diff --git a/.mailmap b/.mailmap index 2d93232ed72b80bd7a6995122fc177c8f599b0e1..3e2bff9137e918255231b3729a81c63251d5c62a 100644 --- a/.mailmap +++ b/.mailmap @@ -25,8 +25,9 @@ Alexandre Belloni Alexei Starovoitov Alexei Starovoitov -Alex Shi -Alex Shi +Alex Shi +Alex Shi +Alex Shi Al Viro Al Viro Andi Kleen @@ -265,6 +266,8 @@ Nicholas Piggin Nicolas Ferre Nicolas Pitre Nicolas Pitre +Nicolas Saenz Julienne +Nicolas Saenz Julienne Oleksij Rempel Oleksij Rempel Oleksij Rempel diff --git a/CREDITS b/CREDITS index cef83b958cbeb79c965e04c0163fd420b194b132..b8f964198ddab91f32d907b8fd58f39f7f5c5e58 100644 --- a/CREDITS +++ b/CREDITS @@ -550,7 +550,7 @@ D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few D: device drivers. His encouragement also helped many engineers get D: started working on the Linux kernel. David passed away in early D: 2011, and will be greatly missed. -W: https://lkml.org/lkml/2011/4/5/36 +W: https://lore.kernel.org/lkml/20110405034819.GA7872@kroah.com N: Gary Brubaker E: xavyer@ix.netcom.com @@ -2536,6 +2536,14 @@ D: Linux/PARISC hacker D: AD1889 sound driver S: Ottawa, Canada +N: Peter Meerwald-Stadler +E: pmeerw@pmeerw.net +W: https://pmeerw.net +D: IIO reviewing, drivers +S: Schießstandstr. 3a +S: A-5061 Elsbethen +S: Austria + N: Dirk Melchers E: dirk@merlin.nbg.sub.org D: 8 bit XT hard disk driver for OMTI5520 diff --git a/Documentation/ABI/stable/procfs-audit_loginuid b/Documentation/ABI/stable/procfs-audit_loginuid new file mode 100644 index 0000000000000000000000000000000000000000..cda4051783914e8ca716bf9518c08bd885dc91d9 --- /dev/null +++ b/Documentation/ABI/stable/procfs-audit_loginuid @@ -0,0 +1,27 @@ +What: Audit Login UID +Date: 2005-02-01 +KernelVersion: 2.6.11-rc2 1e2d1492e178 ("[PATCH] audit: handle loginuid through proc") +Contact: linux-audit@redhat.com +Users: audit and login applications +Description: + The /proc/$pid/loginuid pseudofile is written to set and + read to get the audit login UID of process $pid as a + decimal unsigned int (%u, u32). If it is unset, + permissions are not needed to set it. The accessor must + have CAP_AUDIT_CONTROL in the initial user namespace to + write it if it has been set. It cannot be written again + if AUDIT_FEATURE_LOGINUID_IMMUTABLE is enabled. It + cannot be unset if AUDIT_FEATURE_ONLY_UNSET_LOGINUID is + enabled. + +What: Audit Login Session ID +Date: 2008-03-13 +KernelVersion: 2.6.25-rc7 1e0bd7550ea9 ("[PATCH] export sessionid alongside the loginuid in procfs") +Contact: linux-audit@redhat.com +Users: audit and login applications +Description: + The /proc/$pid/sessionid pseudofile is read to get the + audit login session ID of process $pid as a decimal + unsigned int (%u, u32). It is set automatically, + serially assigned with each new login. + diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index d447a611c41b7707f00ec9c8e925c52013d25f75..c78fc9282876f3d12e01cf7dca56330cc75cf850 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -82,6 +82,24 @@ Description: Allows the root user to read or write 64 bit data directly If the IOMMU is disabled, it also allows the root user to read or write from the host a device VA of a host mapped memory +What: /sys/kernel/debug/habanalabs/hl/data_dma +Date: Apr 2021 +KernelVersion: 5.13 +Contact: ogabbay@kernel.org +Description: Allows the root user to read from the device's internal + memory (DRAM/SRAM) through a DMA engine. + This property is a binary blob that contains the result of the + DMA transfer. + This custom interface is needed (instead of using the generic + Linux user-space PCI mapping) because the amount of internal + memory is huge (>32GB) and reading it via the PCI bar will take + a very long time. + This interface doesn't support concurrency in the same device. + In GAUDI and GOYA, this action can cause undefined behavior + in case the it is done while the device is executing user + workloads. + Only supported on GAUDI at this stage. + What: /sys/kernel/debug/habanalabs/hl/device Date: Jan 2019 KernelVersion: 5.1 @@ -90,6 +108,24 @@ Description: Enables the root user to set the device to specific state. Valid values are "disable", "enable", "suspend", "resume". User can read this property to see the valid values +What: /sys/kernel/debug/habanalabs/hl/dma_size +Date: Apr 2021 +KernelVersion: 5.13 +Contact: ogabbay@kernel.org +Description: Specify the size of the DMA transaction when using DMA to read + from the device's internal memory. The value can not be larger + than 128MB. Writing to this value initiates the DMA transfer. + When the write is finished, the user can read the "data_dma" + blob + +What: /sys/kernel/debug/habanalabs/hl/dump_security_violations +Date: Jan 2021 +KernelVersion: 5.12 +Contact: ogabbay@kernel.org +Description: Dumps all security violations to dmesg. This will also ack + all security violations meanings those violations will not be + dumped next time user calls this API + What: /sys/kernel/debug/habanalabs/hl/engines Date: Jul 2019 KernelVersion: 5.3 @@ -154,6 +190,16 @@ Description: Displays the hop values and physical address for a given ASID e.g. to display info about VA 0x1000 for ASID 1 you need to do: echo "1 0x1000" > /sys/kernel/debug/habanalabs/hl0/mmu +What: /sys/kernel/debug/habanalabs/hl/mmu_error +Date: Mar 2021 +KernelVersion: 5.12 +Contact: fkassabri@habana.ai +Description: Check and display page fault or access violation mmu errors for + all MMUs specified in mmu_cap_mask. + e.g. to display error info for MMU hw cap bit 9, you need to do: + echo "0x200" > /sys/kernel/debug/habanalabs/hl0/mmu_error + cat /sys/kernel/debug/habanalabs/hl0/mmu_error + What: /sys/kernel/debug/habanalabs/hl/set_power_state Date: Jan 2019 KernelVersion: 5.1 @@ -161,6 +207,13 @@ Contact: ogabbay@kernel.org Description: Sets the PCI power state. Valid values are "1" for D0 and "2" for D3Hot +What: /sys/kernel/debug/habanalabs/hl/stop_on_err +Date: Mar 2020 +KernelVersion: 5.6 +Contact: ogabbay@kernel.org +Description: Sets the stop-on_error option for the device engines. Value of + "0" is for disable, otherwise enable. + What: /sys/kernel/debug/habanalabs/hl/userptr Date: Jan 2019 KernelVersion: 5.1 @@ -174,19 +227,4 @@ Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays a list with information about all the active virtual - address mappings per ASID - -What: /sys/kernel/debug/habanalabs/hl/stop_on_err -Date: Mar 2020 -KernelVersion: 5.6 -Contact: ogabbay@kernel.org -Description: Sets the stop-on_error option for the device engines. Value of - "0" is for disable, otherwise enable. - -What: /sys/kernel/debug/habanalabs/hl/dump_security_violations -Date: Jan 2021 -KernelVersion: 5.12 -Contact: ogabbay@kernel.org -Description: Dumps all security violations to dmesg. This will also ack - all security violations meanings those violations will not be - dumped next time user calls this API + address mappings per ASID and all user mappings of HW blocks diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index d957f5da5c046b2b07f0b096e693e51022c39c3a..267973541e721a9ef3fc43400fa2943ff5dba3c9 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -33,6 +33,52 @@ Description: Description of the physical chip / device for device X. Typically a part number. +What: /sys/bus/iio/devices/iio:deviceX/label +KernelVersion: 5.8 +Contact: linux-iio@vger.kernel.org +Description: + Optional symbolic label for a device. + This is useful for userspace to be able to better identify an + individual device. + + The contents of the label are free-form, but there are some + standardized uses: + + For proximity sensors which give the proximity (of a person) to + a certain wlan or wwan antenna the following standardized labels + are used: + + * "proximity-wifi" + * "proximity-lte" + * "proximity-wifi-lte" + * "proximity-wifi-left" + * "proximity-wifi-right" + + These are used to indicate to userspace that these proximity + sensors may be used to tune transmit power to ensure that + Specific Absorption Rate (SAR) limits are honored. + The "-left" and "-right" labels are for devices with multiple + antennas. + + In some laptops/tablets the standardized proximity sensor labels + instead indicate proximity to a specific part of the device: + + * "proximity-palmrest" indicates proximity to the keyboard's palmrest + * "proximity-palmrest-left" indicates proximity to the left part of the palmrest + * "proximity-palmrest-right" indicates proximity to the right part of the palmrest + * "proximity-lap" indicates the device is being used on someone's lap + + Note "proximity-lap" is special in that its value may be + calculated by firmware from other sensor readings, rather then + being a raw sensor reading. + + For accelerometers used in 2-in-1s with 360° (yoga-style) hinges, + which have an accelerometer in both their base and their display, + the following standardized labels are used: + + * "accel-base" + * "accel-display" + What: /sys/bus/iio/devices/iio:deviceX/current_timestamp_clock KernelVersion: 4.5 Contact: linux-iio@vger.kernel.org @@ -325,6 +371,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset +What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceX_offset KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -656,6 +703,8 @@ What: /sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en What: /sys/.../iio:deviceX/events/in_voltageY_thresh_either_en What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en +What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_rising_en +What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_falling_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -733,6 +782,32 @@ Description: a given event type is enabled a future point (and not those for whatever event was previously enabled). +What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en +What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en +KernelVersion: 5.13 +Contact: linux-iio@vger.kernel.org +Descrption: + Adaptive thresholds are similar to normal fixed thresholds + but the value is expressed as an offset from a value which + provides a low frequency approximation of the channel itself. + Thus these detect if a rapid change occurs in the specified + direction which crosses tracking value + offset. + Tracking value calculation is devices specific. + +What: /sys/.../in_capacitanceY_adaptive_thresh_rising_timeout +What: /sys/.../in_capacitanceY_adaptive_thresh_falling_timeout +KernelVersion: 5.11 +Contact: linux-iio@vger.kernel.org +Descrption: + When adaptive thresholds are used, the tracking signal + may adjust too slowly to step changes in the raw signal. + *_timeout (in seconds) specifies a time for which the + difference between the slow tracking signal and the raw + signal is allowed to remain out-of-range before a reset + event occurs in which the tracking signal is made equal + to the raw signal, allowing slow tracking to resume and the + adaptive threshold event detection to function as expected. + What: /sys/.../events/in_accel_thresh_rising_value What: /sys/.../events/in_accel_thresh_falling_value What: /sys/.../events/in_accel_x_raw_thresh_rising_value @@ -773,6 +848,10 @@ What: /sys/.../events/in_proximity0_thresh_falling_value What: /sys/.../events/in_proximity0_thresh_rising_value What: /sys/.../events/in_illuminance_thresh_rising_value What: /sys/.../events/in_illuminance_thresh_falling_value +What: /sys/.../events/in_capacitanceY_thresh_rising_value +What: /sys/.../events/in_capacitanceY_thresh_falling_value +What: /sys/.../events/in_capacitanceY_thresh_adaptive_rising_value +What: /sys/.../events/in_capacitanceY_thresh_falling_rising_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -1118,12 +1197,16 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/buffer/length KernelVersion: 2.6.35 +What: /sys/bus/iio/devices/iio:deviceX/bufferY/length +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: Number of scans contained by the buffer. What: /sys/bus/iio/devices/iio:deviceX/buffer/enable KernelVersion: 2.6.35 +What: /sys/bus/iio/devices/iio:deviceX/bufferY/enable +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: Actually start the buffer capture up. Will start trigger @@ -1131,11 +1214,16 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/scan_elements KernelVersion: 2.6.37 +What: /sys/bus/iio/devices/iio:deviceX/bufferY +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: Directory containing interfaces for elements that will be captured for a single triggered sample set in the buffer. + Since kernel 5.11 the scan_elements attributes are merged into + the bufferY directory, to be configurable per buffer. + What: /sys/.../iio:deviceX/scan_elements/in_accel_x_en What: /sys/.../iio:deviceX/scan_elements/in_accel_y_en What: /sys/.../iio:deviceX/scan_elements/in_accel_z_en @@ -1164,6 +1252,34 @@ What: /sys/.../iio:deviceX/scan_elements/in_pressure_en What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en What: /sys/.../iio:deviceX/scan_elements/in_proximity_en KernelVersion: 2.6.37 +What: /sys/.../iio:deviceX/bufferY/in_accel_x_en +What: /sys/.../iio:deviceX/bufferY/in_accel_y_en +What: /sys/.../iio:deviceX/bufferY/in_accel_z_en +What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_en +What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_en +What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_en +What: /sys/.../iio:deviceX/bufferY/in_magn_x_en +What: /sys/.../iio:deviceX/bufferY/in_magn_y_en +What: /sys/.../iio:deviceX/bufferY/in_magn_z_en +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_en +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_en +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_tilt_comp_en +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_tilt_comp_en +What: /sys/.../iio:deviceX/bufferY/in_timestamp_en +What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_en +What: /sys/.../iio:deviceX/bufferY/in_voltageY_en +What: /sys/.../iio:deviceX/bufferY/in_voltageY-voltageZ_en +What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_en +What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_en +What: /sys/.../iio:deviceX/bufferY/in_voltage_i_en +What: /sys/.../iio:deviceX/bufferY/in_voltage_q_en +What: /sys/.../iio:deviceX/bufferY/in_incli_x_en +What: /sys/.../iio:deviceX/bufferY/in_incli_y_en +What: /sys/.../iio:deviceX/bufferY/in_pressureY_en +What: /sys/.../iio:deviceX/bufferY/in_pressure_en +What: /sys/.../iio:deviceX/bufferY/in_rot_quaternion_en +What: /sys/.../iio:deviceX/bufferY/in_proximity_en +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: Scan element control for triggered data capture. @@ -1185,6 +1301,23 @@ What: /sys/.../iio:deviceX/scan_elements/in_pressure_type What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type What: /sys/.../iio:deviceX/scan_elements/in_proximity_type KernelVersion: 2.6.37 +What: /sys/.../iio:deviceX/bufferY/in_accel_type +What: /sys/.../iio:deviceX/bufferY/in_anglvel_type +What: /sys/.../iio:deviceX/bufferY/in_magn_type +What: /sys/.../iio:deviceX/bufferY/in_incli_type +What: /sys/.../iio:deviceX/bufferY/in_voltageY_type +What: /sys/.../iio:deviceX/bufferY/in_voltage_type +What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_type +What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_type +What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_type +What: /sys/.../iio:deviceX/bufferY/in_voltage_i_type +What: /sys/.../iio:deviceX/bufferY/in_voltage_q_type +What: /sys/.../iio:deviceX/bufferY/in_timestamp_type +What: /sys/.../iio:deviceX/bufferY/in_pressureY_type +What: /sys/.../iio:deviceX/bufferY/in_pressure_type +What: /sys/.../iio:deviceX/bufferY/in_rot_quaternion_type +What: /sys/.../iio:deviceX/bufferY/in_proximity_type +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: Description of the scan element data storage within the buffer @@ -1241,6 +1374,33 @@ What: /sys/.../iio:deviceX/scan_elements/in_pressure_index What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index What: /sys/.../iio:deviceX/scan_elements/in_proximity_index KernelVersion: 2.6.37 +What: /sys/.../iio:deviceX/bufferY/in_voltageY_index +What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_index +What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_index +What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_index +What: /sys/.../iio:deviceX/bufferY/in_voltage_i_index +What: /sys/.../iio:deviceX/bufferY/in_voltage_q_index +What: /sys/.../iio:deviceX/bufferY/in_accel_x_index +What: /sys/.../iio:deviceX/bufferY/in_accel_y_index +What: /sys/.../iio:deviceX/bufferY/in_accel_z_index +What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_index +What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_index +What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_index +What: /sys/.../iio:deviceX/bufferY/in_magn_x_index +What: /sys/.../iio:deviceX/bufferY/in_magn_y_index +What: /sys/.../iio:deviceX/bufferY/in_magn_z_index +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_index +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_index +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_tilt_comp_index +What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_tilt_comp_index +What: /sys/.../iio:deviceX/bufferY/in_incli_x_index +What: /sys/.../iio:deviceX/bufferY/in_incli_y_index +What: /sys/.../iio:deviceX/bufferY/in_timestamp_index +What: /sys/.../iio:deviceX/bufferY/in_pressureY_index +What: /sys/.../iio:deviceX/bufferY/in_pressure_index +What: /sys/.../iio:deviceX/bufferY/in_rot_quaternion_index +What: /sys/.../iio:deviceX/bufferY/in_proximity_index +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: A single positive integer specifying the position of this @@ -1455,6 +1615,8 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/buffer/watermark KernelVersion: 4.2 +What: /sys/bus/iio/devices/iio:deviceX/bufferY/watermark +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: A single positive integer specifying the maximum number of scan @@ -1473,6 +1635,8 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/buffer/data_available KernelVersion: 4.16 +What: /sys/bus/iio/devices/iio:deviceX/bufferY/data_available +KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org Description: A read-only value indicating the bytes of data available in the @@ -1823,3 +1987,12 @@ Description: hinge, keyboard, screen. It means the three channels each correspond respectively to hinge angle, keyboard angle, and screen angle. + +What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_hysteresis_relative +What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hysteresis_relative +KernelVersion: 5.12 +Contact: linux-iio@vger.kernel.org +Description: + Specify the percent for light sensor relative to the channel + absolute value that a data field should change before an event + is generated. Units are a percentage of the prior reading. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 deleted file mode 100644 index bac3d0d48b7b9c656f71604bb8080f40480e0c5f..0000000000000000000000000000000000000000 --- a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 +++ /dev/null @@ -1,133 +0,0 @@ -What: /sys/bus/iio/devices/iio:deviceX/in_count_count_mode_available -What: /sys/bus/iio/devices/iio:deviceX/in_count_noise_error_available -What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available -What: /sys/bus/iio/devices/iio:deviceX/in_index_index_polarity_available -What: /sys/bus/iio/devices/iio:deviceX/in_index_synchronous_mode_available -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Discrete set of available values for the respective counter - configuration are listed in this file. - -What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_mode -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Count mode for channel Y. Four count modes are available: - normal, range limit, non-recycle, and modulo-n. The preset value - for channel Y is used by the count mode where required. - - Normal: - Counting is continuous in either direction. - - Range Limit: - An upper or lower limit is set, mimicking limit switches - in the mechanical counterpart. The upper limit is set to - the preset value, while the lower limit is set to 0. The - counter freezes at count = preset when counting up, and - at count = 0 when counting down. At either of these - limits, the counting is resumed only when the count - direction is reversed. - - Non-recycle: - Counter is disabled whenever a 24-bit count overflow or - underflow takes place. The counter is re-enabled when a - new count value is loaded to the counter via a preset - operation or write to raw. - - Modulo-N: - A count boundary is set between 0 and the preset value. - The counter is reset to 0 at count = preset when - counting up, while the counter is set to the preset - value at count = 0 when counting down; the counter does - not freeze at the bundary points, but counts - continuously throughout. - -What: /sys/bus/iio/devices/iio:deviceX/in_countY_noise_error -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Read-only attribute that indicates whether excessive noise is - present at the channel Y count inputs in quadrature clock mode; - irrelevant in non-quadrature clock mode. - -What: /sys/bus/iio/devices/iio:deviceX/in_countY_preset -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - If the counter device supports preset registers, the preset - count for channel Y is provided by this attribute. - -What: /sys/bus/iio/devices/iio:deviceX/in_countY_quadrature_mode -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Configure channel Y counter for non-quadrature or quadrature - clock mode. Selecting non-quadrature clock mode will disable - synchronous load mode. In quadrature clock mode, the channel Y - scale attribute selects the encoder phase division (scale of 1 - selects full-cycle, scale of 0.5 selects half-cycle, scale of - 0.25 selects quarter-cycle) processed by the channel Y counter. - - Non-quadrature: - The filter and decoder circuit are bypassed. Encoder A - input serves as the count input and B as the UP/DOWN - direction control input, with B = 1 selecting UP Count - mode and B = 0 selecting Down Count mode. - - Quadrature: - Encoder A and B inputs are digitally filtered and - decoded for UP/DN clock. - -What: /sys/bus/iio/devices/iio:deviceX/in_countY_set_to_preset_on_index -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Whether to set channel Y counter with channel Y preset value - when channel Y index input is active, or continuously count. - Valid attribute values are boolean. - -What: /sys/bus/iio/devices/iio:deviceX/in_indexY_index_polarity -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Active level of channel Y index input; irrelevant in - non-synchronous load mode. - -What: /sys/bus/iio/devices/iio:deviceX/in_indexY_synchronous_mode -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - This interface is deprecated; please use the Counter subsystem. - - Configure channel Y counter for non-synchronous or synchronous - load mode. Synchronous load mode cannot be selected in - non-quadrature clock mode. - - Non-synchronous: - A logic low level is the active level at this index - input. The index function (as enabled via - set_to_preset_on_index) is performed directly on the - active level of the index input. - - Synchronous: - Intended for interfacing with encoder Index output in - quadrature clock mode. The active level is configured - via index_polarity. The index function (as enabled via - set_to_preset_on_index) is performed synchronously with - the quadrature clock on the active level of the index - input. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 b/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 index 40df5c9fef996efa5956222c23ca1cb3c0f53a11..9dae94aa880b8f1a98c02aae22d201a5f5227244 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 +++ b/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 @@ -1,11 +1,3 @@ -What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity -Date: January 2017 -KernelVersion: 4.11 -Contact: linux-iio@vger.kernel.org -Description: - Show or set the gain boost of the amp, from 0-31 range. - default 31 - What: /sys/bus/iio/devices/iio:deviceX/sensor_max_range Date: January 2017 KernelVersion: 4.11 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010 b/Documentation/ABI/testing/sysfs-bus-iio-humidity similarity index 79% rename from Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010 rename to Documentation/ABI/testing/sysfs-bus-iio-humidity index 5b78af5f341d2467f9f2dea89017caa78801ac75..cb0d7e75d297e3dffa7fac6e2ec5c0dd0ee6f9f5 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010 +++ b/Documentation/ABI/testing/sysfs-bus-iio-humidity @@ -6,4 +6,5 @@ Description: Controls the heater device within the humidity sensor to get rid of excess condensation. - Valid control values are 0 = OFF, and 1 = ON. + In some devices, this is just a switch in which case 0 = OFF, + and 1 = ON. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x b/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x deleted file mode 100644 index b72bb62552cf174b3162191035dafb789b88acf4..0000000000000000000000000000000000000000 --- a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x +++ /dev/null @@ -1,9 +0,0 @@ -What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw -What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available -KernelVersion: 4.3 -Contact: linux-iio@vger.kernel.org -Description: - Controls the heater device within the humidity sensor to get - rid of excess condensation. - - Valid control values are 0 = OFF, and 1 = ON. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 deleted file mode 100644 index 73498ff666bd74a92269bf5e1006d34571869233..0000000000000000000000000000000000000000 --- a/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 +++ /dev/null @@ -1,62 +0,0 @@ -What: /sys/bus/iio/devices/iio:deviceX/in_count0_preset -KernelVersion: 4.13 -Contact: fabrice.gasnier@st.com -Description: - Reading returns the current preset value. Writing sets the - preset value. Encoder counts continuously from 0 to preset - value, depending on direction (up/down). - -What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available -KernelVersion: 4.13 -Contact: fabrice.gasnier@st.com -Description: - Reading returns the list possible quadrature modes. - -What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode -KernelVersion: 4.13 -Contact: fabrice.gasnier@st.com -Description: - Configure the device counter quadrature modes: - - - non-quadrature: - Encoder IN1 input servers as the count input (up - direction). - - - quadrature: - Encoder IN1 and IN2 inputs are mixed to get direction - and count. - -What: /sys/bus/iio/devices/iio:deviceX/in_count_polarity_available -KernelVersion: 4.13 -Contact: fabrice.gasnier@st.com -Description: - Reading returns the list possible active edges. - -What: /sys/bus/iio/devices/iio:deviceX/in_count0_polarity -KernelVersion: 4.13 -Contact: fabrice.gasnier@st.com -Description: - Configure the device encoder/counter active edge: - - - rising-edge - - falling-edge - - both-edges - - In non-quadrature mode, device counts up on active edge. - - In quadrature mode, encoder counting scenarios are as follows: - - +---------+----------+--------------------+--------------------+ - | Active | Level on | IN1 signal | IN2 signal | - | edge | opposite +----------+---------+----------+---------+ - | | signal | Rising | Falling | Rising | Falling | - +---------+----------+----------+---------+----------+---------+ - | Rising | High -> | Down | - | Up | - | - | edge | Low -> | Up | - | Down | - | - +---------+----------+----------+---------+----------+---------+ - | Falling | High -> | - | Up | - | Down | - | edge | Low -> | - | Down | - | Up | - +---------+----------+----------+---------+----------+---------+ - | Both | High -> | Down | Up | Up | Down | - | edges | Low -> | Up | Down | Down | Up | - +---------+----------+----------+---------+----------+---------+ diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity b/Documentation/ABI/testing/sysfs-bus-iio-proximity index 2172f3bb9c64256ab9b0b524c257cc4410be897d..3aac6dab8775d7715b9d7b33e2ee96d4e21b2b1b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-proximity +++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity @@ -8,3 +8,17 @@ Description: considered close to the device. If the value read from the sensor is above or equal to the value in this file an object should typically be considered near. + +What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity +Date: March 2014 +KernelVersion: 3.15 +Contact: linux-iio@vger.kernel.org +Description: + Proximity sensors sometimes have a controllable amplifier + on the signal from which time of flight measurements are + taken. + The appropriate values to take is dependent on both the + sensor and it's operating environment: + * as3935 (0-31 range) + 18 = indoors (default) + 14 = outdoors diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 index c59d953463417bb1a6705416deadb5cd19a21ab3..1e5c40775a6c40717b358b4c1b532fbda552f77b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 +++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 @@ -6,15 +6,6 @@ Description: Get the current distance in meters of storm (1km steps) 1000-40000 = distance in meters -What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity -Date: March 2014 -KernelVersion: 3.15 -Contact: Matt Ranostay -Description: - Show or set the gain boost of the amp, from 0-31 range. - 18 = indoors (default) - 14 = outdoors - What /sys/bus/iio/devices/iio:deviceX/noise_level_tripped Date: May 2017 KernelVersion: 4.13 diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic b/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic index 1936f732415571326a24ca147833451917cabdc1..4ec03cd363579c176e971fd55602c2ef6ae74a6d 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic @@ -1,4 +1,5 @@ -What: /sys/devices/pci0000:00/*/QEMU0001:00/capability +What: /sys/devices/pci0000:00/*/QEMU0001:00/capability for MMIO + /sys/bus/pci/drivers/pvpanic-pci/0000:00:0*.0/capability for PCI Date: Jan 2021 Contact: zhenwei pi Description: @@ -12,6 +13,7 @@ Description: https://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/specs/pvpanic.txt What: /sys/devices/pci0000:00/*/QEMU0001:00/events + /sys/bus/pci/drivers/pvpanic-pci/0000:00:0*.0/events for PCI Date: Jan 2021 Contact: zhenwei pi Description: diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index d7f09d011b6d29bc693f42ea527abc8697913ae0..c41c68f6469378f2a381cb06b245caa559d3b1f5 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -1,31 +1,3 @@ -What: /sys/bus/thunderbolt/devices//rx_speed -Date: Feb 2021 -KernelVersion: 5.11 -Contact: Isaac Hazan -Description: This attribute reports the XDomain RX speed per lane. - All RX lanes run at the same speed. - -What: /sys/bus/thunderbolt/devices//rx_lanes -Date: Feb 2021 -KernelVersion: 5.11 -Contact: Isaac Hazan -Description: This attribute reports the number of RX lanes the XDomain - is using simultaneously through its upstream port. - -What: /sys/bus/thunderbolt/devices//tx_speed -Date: Feb 2021 -KernelVersion: 5.11 -Contact: Isaac Hazan -Description: This attribute reports the XDomain TX speed per lane. - All TX lanes run at the same speed. - -What: /sys/bus/thunderbolt/devices//tx_lanes -Date: Feb 2021 -KernelVersion: 5.11 -Contact: Isaac Hazan -Description: This attribute reports number of TX lanes the XDomain - is using simultaneously through its upstream port. - What: /sys/bus/thunderbolt/devices/.../domainX/boot_acl Date: Jun 2018 KernelVersion: 4.17 @@ -162,6 +134,13 @@ Contact: thunderbolt-software@lists.01.org Description: This attribute contains name of this device extracted from the device DROM. +What: /sys/bus/thunderbolt/devices/.../maxhopid +Date: Jul 2021 +KernelVersion: 5.13 +Contact: Mika Westerberg +Description: Only set for XDomains. The maximum HopID the other host + supports as its input HopID. + What: /sys/bus/thunderbolt/devices/.../rx_speed Date: Jan 2020 KernelVersion: 5.5 diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index 386bc230a33d82519cf8e4fbc5bf060223cccf54..5e6b74f304062a4a5b59edbf448bb195441e0398 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -97,10 +97,7 @@ Description: object. The values are represented in ms. If the value is less than 1 jiffy, it is considered to be 0, which means no polling. This value is meaningless if the governor is - not polling; thus. If the governor is not using - devfreq-provided central polling - (/sys/class/devfreq/.../central_polling is 0), this value - may be useless. + not polling. A list of governors that support the node: - simple_ondmenad diff --git a/Documentation/ABI/testing/sysfs-driver-xdata b/Documentation/ABI/testing/sysfs-driver-xdata new file mode 100644 index 0000000000000000000000000000000000000000..f574e8e6dca21d5e387f6fbcaf8c630abef20249 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-xdata @@ -0,0 +1,49 @@ +What: /sys/class/misc/drivers/dw-xdata-pcie./write +Date: April 2021 +KernelVersion: 5.13 +Contact: Gustavo Pimentel +Description: Allows the user to enable the PCIe traffic generator which + will create write TLPs frames - from the Root Complex to the + Endpoint direction or to disable the PCIe traffic generator + in all directions. + + Write y/1/on to enable, n/0/off to disable + + Usage e.g. + echo 1 > /sys/class/misc/dw-xdata-pcie./write + or + echo 0 > /sys/class/misc/dw-xdata-pcie./write + + The user can read the current PCIe link throughput generated + through this generator in MB/s. + + Usage e.g. + cat /sys/class/misc/dw-xdata-pcie./write + 204 + + The file is read and write. + +What: /sys/class/misc/dw-xdata-pcie./read +Date: April 2021 +KernelVersion: 5.13 +Contact: Gustavo Pimentel +Description: Allows the user to enable the PCIe traffic generator which + will create read TLPs frames - from the Endpoint to the Root + Complex direction or to disable the PCIe traffic generator + in all directions. + + Write y/1/on to enable, n/0/off to disable + + Usage e.g. + echo 1 > /sys/class/misc/dw-xdata-pcie./read + or + echo 0 > /sys/class/misc/dw-xdata-pcie./read + + The user can read the current PCIe link throughput generated + through this generator in MB/s. + + Usage e.g. + cat /sys/class/misc/dw-xdata-pcie./read + 199 + + The file is read and write. diff --git a/Documentation/ABI/testing/sysfs-firmware-sgi_uv b/Documentation/ABI/testing/sysfs-firmware-sgi_uv index 637c668cbe45c24e02b8c7725bcfb5d676869521..12ed843e1d3e0a8826f2e189d2bfd1287e5ede8a 100644 --- a/Documentation/ABI/testing/sysfs-firmware-sgi_uv +++ b/Documentation/ABI/testing/sysfs-firmware-sgi_uv @@ -39,8 +39,8 @@ Description: The uv_type entry contains the hub revision number. This value can be used to identify the UV system version:: - "0.*" = Hubless UV ('*' is subtype) + "0.*" = Hubless UV ('*' is subtype) "3.0" = UV2 "5.0" = UV3 "7.0" = UV4 diff --git a/Documentation/ABI/testing/sysfs-platform-intel-pmc b/Documentation/ABI/testing/sysfs-platform-intel-pmc new file mode 100644 index 0000000000000000000000000000000000000000..ef199af75ab0dec7d62489aadaca6dfb434c3e98 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-intel-pmc @@ -0,0 +1,20 @@ +What: /sys/devices/platform//etr3 +Date: Apr 2021 +KernelVersion: 5.13 +Contact: "Tomas Winkler" +Description: + The file exposes "Extended Test Mode Register 3" global + reset bits. The bits are used during an Intel platform + manufacturing process to indicate that consequent reset + of the platform is a "global reset". This type of reset + is required in order for manufacturing configurations + to take effect. + + Display global reset setting bits for PMC. + * bit 31 - global reset is locked + * bit 20 - global reset is set + Writing bit 20 value to the etr3 will induce + a platform "global reset" upon consequent platform reset, + in case the register is not locked. + The "global reset bit" should be locked on a production + system and the file is in read-only mode. diff --git a/Documentation/admin-guide/LSM/LoadPin.rst b/Documentation/admin-guide/LSM/LoadPin.rst index 716ad9b23c9aa73115c21ee86538cf99cd7ec173..dd3ca68b5df188315710c8115761f8cb4da93141 100644 --- a/Documentation/admin-guide/LSM/LoadPin.rst +++ b/Documentation/admin-guide/LSM/LoadPin.rst @@ -11,8 +11,8 @@ restrictions without needing to sign the files individually. The LSM is selectable at build-time with ``CONFIG_SECURITY_LOADPIN``, and can be controlled at boot-time with the kernel command line option -"``loadpin.enabled``". By default, it is enabled, but can be disabled at -boot ("``loadpin.enabled=0``"). +"``loadpin.enforce``". By default, it is enabled, but can be disabled at +boot ("``loadpin.enforce=0``"). LoadPin starts pinning when it sees the first file loaded. If the block device backing the filesystem is not read-only, a sysctl is @@ -28,4 +28,4 @@ different mechanisms such as ``CONFIG_MODULE_SIG`` and ``CONFIG_KEXEC_VERIFY_SIG`` to verify kernel module and kernel image while still use LoadPin to protect the integrity of other files kernel loads. The full list of valid file types can be found in ``kernel_read_file_str`` -defined in ``include/linux/fs.h``. +defined in ``include/linux/kernel_read_file.h``. diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst index 0936412e044eed0b1a1af5231441f5841cac61b5..41191b5fb69d9cc0663d20789aad230d3a82b24d 100644 --- a/Documentation/admin-guide/cgroup-v1/memory.rst +++ b/Documentation/admin-guide/cgroup-v1/memory.rst @@ -360,8 +360,8 @@ U != 0, K = unlimited: U != 0, K < U: Kernel memory is a subset of the user memory. This setup is useful in - deployments where the total amount of memory per-cgroup is overcommited. - Overcommiting kernel memory limits is definitely not recommended, since the + deployments where the total amount of memory per-cgroup is overcommitted. + Overcommitting kernel memory limits is definitely not recommended, since the box can still run out of non-reclaimable memory. In this case, the admin could set up K so that the sum of all groups is never greater than the total memory, and freely set U at the cost of his @@ -851,6 +851,9 @@ At reading, current status of OOM is shown. (if 1, oom-killer is disabled) - under_oom 0 or 1 (if 1, the memory cgroup is under OOM, tasks may be stopped.) + - oom_kill integer counter + The number of processes belonging to this cgroup killed by any + kind of OOM killer. 11. Memory Pressure =================== diff --git a/Documentation/admin-guide/cifs/usage.rst b/Documentation/admin-guide/cifs/usage.rst index 13783dc68ab78bb7d09ee3ba1a5060a74589dbcf..f170d88202588b222233bfdc55596b32d3bd32e3 100644 --- a/Documentation/admin-guide/cifs/usage.rst +++ b/Documentation/admin-guide/cifs/usage.rst @@ -714,6 +714,7 @@ DebugData Displays information about active CIFS sessions and version. Stats Lists summary resource usage information as well as per share statistics. +open_files List all the open file handles on all active SMB sessions. ======================= ======================================================= Configuration pseudo-files: @@ -794,6 +795,8 @@ LinuxExtensionsEnabled If set to one then the client will attempt to support and want to map the uid and gid fields to values supplied at mount (rather than the actual values, then set this to zero. (default 1) +dfscache List the content of the DFS cache. + If set to 0, the client will clear the cache. ======================= ======================================================= These experimental features and tracing can be enabled by changing flags in diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index 63fd4e6a014bcce2c161288fed6eb90a64b2b4d6..ef41f77cb9799b1b9808068622db57062ac4095f 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -289,7 +289,7 @@ 152 = /dev/kpoll Kernel Poll Driver 153 = /dev/mergemem Memory merge device 154 = /dev/pmu Macintosh PowerBook power manager - 155 = /dev/isictl MultiTech ISICom serial control + 155 = 156 = /dev/lcd Front panel LCD display 157 = /dev/ac Applicom Intl Profibus card 158 = /dev/nwbutton Netwinder external button @@ -477,11 +477,6 @@ 18 block Sanyo CD-ROM 0 = /dev/sjcd Sanyo CD-ROM - 19 char Cyclades serial card - 0 = /dev/ttyC0 First Cyclades port - ... - 31 = /dev/ttyC31 32nd Cyclades port - 19 block "Double" compressed disk 0 = /dev/double0 First compressed disk ... @@ -493,11 +488,6 @@ See the Double documentation for the meaning of the mirror devices. - 20 char Cyclades serial card - alternate devices - 0 = /dev/cub0 Callout device for ttyC0 - ... - 31 = /dev/cub31 Callout device for ttyC31 - 20 block Hitachi CD-ROM (under development) 0 = /dev/hitcd Hitachi CD-ROM diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 6c04aea8f4cd83652fc8de70cb104f2348a1d456..b119b8277b3ead734aff49130e26c3b30ee729c5 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -347,7 +347,7 @@ Examples /dynamic_debug/control // enable messages in files of which the paths include string "usb" - nullarbor:~ # echo -n '*usb* +p' > /dynamic_debug/control + nullarbor:~ # echo -n 'file *usb* +p' > /dynamic_debug/control // enable all messages nullarbor:~ # echo -n '+p' > /dynamic_debug/control diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst index 423116c4e7875bfdf825ad7703227592eb8ff010..dc00afcabb95f90da2a7562d9f443c0b4ba6eae6 100644 --- a/Documentation/admin-guide/index.rst +++ b/Documentation/admin-guide/index.rst @@ -35,7 +35,6 @@ problems and bugs in particular. :maxdepth: 1 reporting-issues - Reporting bugs (obsolete) security-bugs bug-hunting bug-bisect diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst index 1132796a8d96e7636fc28f0804519849dec3987f..24302cad174a3e34ed532566c97f414ff9cac89c 100644 --- a/Documentation/admin-guide/kernel-parameters.rst +++ b/Documentation/admin-guide/kernel-parameters.rst @@ -140,6 +140,7 @@ parameter is applicable:: PPT Parallel port support is enabled. PS2 Appropriate PS/2 support is enabled. RAM RAM disk support is enabled. + RISCV RISCV architecture is enabled. RDT Intel Resource Director Technology. S390 S390 architecture is enabled. SCSI Appropriate SCSI support is enabled. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index d468f3b9954138fba727aa97d29aa1c5326e2ea5..7ae8a47bfc941d3ba8c4328303463dcfa116bace 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -50,7 +50,7 @@ CONFIG_ACPI_DEBUG must be enabled to produce any ACPI debug output. Bits in debug_layer correspond to a _COMPONENT in an ACPI source file, e.g., - #define _COMPONENT ACPI_PCI_COMPONENT + #define _COMPONENT ACPI_EVENTS Bits in debug_level correspond to a level in ACPI_DEBUG_PRINT statements, e.g., ACPI_DEBUG_PRINT((ACPI_DB_INFO, ... @@ -60,8 +60,6 @@ Enable processor driver info messages: acpi.debug_layer=0x20000000 - Enable PCI/PCI interrupt routing info messages: - acpi.debug_layer=0x400000 Enable AML "Debug" output, i.e., stores to the Debug object while interpreting AML: acpi.debug_layer=0xffffffff acpi.debug_level=0x2 @@ -2283,8 +2281,7 @@ state is kept private from the host. Not valid if the kernel is running in EL2. - Defaults to VHE/nVHE based on hardware support and - the value of CONFIG_ARM64_VHE. + Defaults to VHE/nVHE based on hardware support. kvm-arm.vgic_v3_group0_trap= [KVM,ARM] Trap guest accesses to GICv3 group-0 @@ -3476,7 +3473,8 @@ nr_uarts= [SERIAL] maximum number of UARTs to be registered. - numa_balancing= [KNL,X86] Enable or disable automatic NUMA balancing. + numa_balancing= [KNL,ARM64,PPC,RISCV,S390,X86] Enable or disable automatic + NUMA balancing. Allowed values are enable and disable numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA. @@ -4065,6 +4063,17 @@ fully seed the kernel's CRNG. Default is controlled by CONFIG_RANDOM_TRUST_CPU. + randomize_kstack_offset= + [KNL] Enable or disable kernel stack offset + randomization, which provides roughly 5 bits of + entropy, frustrating memory corruption attacks + that depend on stack address determinism or + cross-syscall address exposures. This is only + available on architectures that have defined + CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET. + Format: (1/Y/y=enable, 0/N/n=disable) + Default is CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT. + ras=option[,option,...] [KNL] RAS-specific options cec_disable [X86] @@ -5104,27 +5113,37 @@ spia_peddr= split_lock_detect= - [X86] Enable split lock detection + [X86] Enable split lock detection or bus lock detection When enabled (and if hardware support is present), atomic instructions that access data across cache line - boundaries will result in an alignment check exception. + boundaries will result in an alignment check exception + for split lock detection or a debug exception for + bus lock detection. off - not enabled - warn - the kernel will emit rate limited warnings + warn - the kernel will emit rate-limited warnings about applications triggering the #AC - exception. This mode is the default on CPUs - that supports split lock detection. + exception or the #DB exception. This mode is + the default on CPUs that support split lock + detection or bus lock detection. Default + behavior is by #AC if both features are + enabled in hardware. fatal - the kernel will send SIGBUS to applications - that trigger the #AC exception. + that trigger the #AC exception or the #DB + exception. Default behavior is by #AC if + both features are enabled in hardware. If an #AC exception is hit in the kernel or in firmware (i.e. not while executing in user mode) the kernel will oops in either "warn" or "fatal" mode. + #DB exception for bus lock is triggered only when + CPL > 0. + srbds= [X86,INTEL] Control the Special Register Buffer Data Sampling (SRBDS) mitigation. @@ -5466,6 +5485,18 @@ See Documentation/admin-guide/mm/transhuge.rst for more details. + trusted.source= [KEYS] + Format: + This parameter identifies the trust source as a backend + for trusted keys implementation. Supported trust + sources: + - "tpm" + - "tee" + If not specified then it defaults to iterating through + the trust source list starting with TPM and assigns the + first trust source as a backend which is initialized + successfully during iteration. + tsc= Disable clocksource stability checks for TSC. Format: [x86] reliable: mark tsc clocksource as reliable, this diff --git a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst index 531f689311f24745531a6d835a4bee920014bbfe..5e51ee5b03589fc9b538daaeb2289fd85f5ce609 100644 --- a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst +++ b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst @@ -332,23 +332,3 @@ To reduce its OS jitter, do at least one of the following: kthreads from being created in the first place. However, please note that this will not eliminate OS jitter, but will instead shift it to RCU_SOFTIRQ. - -Name: - watchdog/%u - -Purpose: - Detect software lockups on each CPU. - -To reduce its OS jitter, do at least one of the following: - -1. Build with CONFIG_LOCKUP_DETECTOR=n, which will prevent these - kthreads from being created in the first place. -2. Boot with "nosoftlockup=0", which will also prevent these kthreads - from being created. Other related watchdog and softlockup boot - parameters may be found in Documentation/admin-guide/kernel-parameters.rst - and Documentation/watchdog/watchdog-parameters.rst. -3. Echo a zero to /proc/sys/kernel/watchdog to disable the - watchdog timer. -4. Echo a large number of /proc/sys/kernel/watchdog_thresh in - order to reduce the frequency of OS jitter due to the watchdog - timer down to a level that is acceptable for your workload. diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst index 91fd6846ce17ca032309d376d58f8f0a9e39e412..6721a80a2d4fbfd48328a4fe2ca18d892a311808 100644 --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst @@ -52,6 +52,7 @@ detailed description): - LCD Shadow (PrivacyGuard) enable and disable - Lap mode sensor - Setting keyboard language + - WWAN Antenna type A compatibility table by model and feature is maintained on the web site, http://ibm-acpi.sf.net/. I appreciate any success or failure @@ -1490,6 +1491,25 @@ fr(French), fr-ch(French(Switzerland)), hu(Hungarian), it(Italy), jp (Japan), nl(Dutch), nn(Norway), pl(Polish), pt(portugese), sl(Slovenian), sv(Sweden), tr(Turkey) +WWAN Antenna type +----------------- + +sysfs: wwan_antenna_type + +On some newer Thinkpads we need to set SAR value based on the antenna +type. This interface will be used by userspace to get the antenna type +and set the corresponding SAR value, as is required for FCC certification. + +The available commands are:: + + cat /sys/devices/platform/thinkpad_acpi/wwan_antenna_type + +Currently 2 antenna types are supported as mentioned below: +- type a +- type b + +The property is read-only. If the platform doesn't have support the sysfs +class is not created. Adaptive keyboard ----------------- diff --git a/Documentation/admin-guide/mm/numaperf.rst b/Documentation/admin-guide/mm/numaperf.rst index c2f826409bf076bb42608f3c69837c2935f7e38c..1666973259479b0b945c18a3eec901c78db2d61d 100644 --- a/Documentation/admin-guide/mm/numaperf.rst +++ b/Documentation/admin-guide/mm/numaperf.rst @@ -151,7 +151,7 @@ Each cache level's directory provides its attributes. For example, the following shows a single cache level and the attributes available for software to query:: - # tree sys/devices/system/node/node0/memory_side_cache/ + # tree /sys/devices/system/node/node0/memory_side_cache/ /sys/devices/system/node/node0/memory_side_cache/ |-- index1 | |-- indexing diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst index 404a5c3d9d00d782b98ea0d76cea01acd85700a7..546979360513154824e221ae2739f25c59bbc4d1 100644 --- a/Documentation/admin-guide/perf/hisi-pmu.rst +++ b/Documentation/admin-guide/perf/hisi-pmu.rst @@ -53,6 +53,60 @@ Example usage of perf:: $# perf stat -a -e hisi_sccl3_l3c0/rd_hit_cpipe/ sleep 5 $# perf stat -a -e hisi_sccl3_l3c0/config=0x02/ sleep 5 +For HiSilicon uncore PMU v2 whose identifier is 0x30, the topology is the same +as PMU v1, but some new functions are added to the hardware. + +(a) L3C PMU supports filtering by core/thread within the cluster which can be +specified as a bitmap:: + + $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0x3/ sleep 5 + +This will only count the operations from core/thread 0 and 1 in this cluster. + +(b) Tracetag allow the user to chose to count only read, write or atomic +operations via the tt_req parameeter in perf. The default value counts all +operations. tt_req is 3bits, 3'b100 represents read operations, 3'b101 +represents write operations, 3'b110 represents atomic store operations and +3'b111 represents atomic non-store operations, other values are reserved:: + + $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5 + +This will only count the read operations in this cluster. + +(c) Datasrc allows the user to check where the data comes from. It is 5 bits. +Some important codes are as follows: +5'b00001: comes from L3C in this die; +5'b01000: comes from L3C in the cross-die; +5'b01001: comes from L3C which is in another socket; +5'b01110: comes from the local DDR; +5'b01111: comes from the cross-die DDR; +5'b10000: comes from cross-socket DDR; +etc, it is mainly helpful to find that the data source is nearest from the CPU +cores. If datasrc_cfg is used in the multi-chips, the datasrc_skt shall be +configured in perf command:: + + $# perf stat -a -e hisi_sccl3_l3c0/config=0xb9,datasrc_cfg=0xE/, + hisi_sccl3_l3c0/config=0xb9,datasrc_cfg=0xF/ sleep 5 + +(d)Some HiSilicon SoCs encapsulate multiple CPU and IO dies. Each CPU die +contains several Compute Clusters (CCLs). The I/O dies are called Super I/O +clusters (SICL) containing multiple I/O clusters (ICLs). Each CCL/ICL in the +SoC has a unique ID. Each ID is 11bits, include a 6-bit SCCL-ID and 5-bit +CCL/ICL-ID. For I/O die, the ICL-ID is followed by: +5'b00000: I/O_MGMT_ICL; +5'b00001: Network_ICL; +5'b00011: HAC_ICL; +5'b10000: PCIe_ICL; + +Users could configure IDs to count data come from specific CCL/ICL, by setting +srcid_cmd & srcid_msk, and data desitined for specific CCL/ICL by setting +tgtid_cmd & tgtid_msk. A set bit in srcid_msk/tgtid_msk means the PMU will not +check the bit when matching against the srcid_cmd/tgtid_cmd. + +If all of these options are disabled, it can works by the default value that +doesn't distinguish the filter condition and ID information and will return +the total counter values in the PMU counters. + The current driver does not support sampling. So "perf record" is unsupported. Also attach to a task is unsupported as the events are all uncore. diff --git a/Documentation/admin-guide/ramoops.rst b/Documentation/admin-guide/ramoops.rst index b0a1ae7df13b8be18cfbed36f5ca6eefc6dd90e7..8f107d8c926136ba1edef53a53c10290104dc566 100644 --- a/Documentation/admin-guide/ramoops.rst +++ b/Documentation/admin-guide/ramoops.rst @@ -3,7 +3,7 @@ Ramoops oops/panic logger Sergiu Iordache -Updated: 17 November 2011 +Updated: 10 Feb 2021 Introduction ------------ @@ -30,6 +30,8 @@ mapping to pgprot_writecombine. Setting ``mem_type=1`` attempts to use depends on atomic operations. At least on ARM, pgprot_noncached causes the memory to be mapped strongly ordered, and atomic operations on strongly ordered memory are implementation defined, and won't work on many ARMs such as omaps. +Setting ``mem_type=2`` attempts to treat the memory region as normal memory, +which enables full cache on it. This can improve the performance. The memory area is divided into ``record_size`` chunks (also rounded down to power of two) and each kmesg dump writes a ``record_size`` chunk of diff --git a/Documentation/admin-guide/reporting-bugs.rst b/Documentation/admin-guide/reporting-bugs.rst deleted file mode 100644 index 409fa91d7495e3e3db32ac96447ede34069d6540..0000000000000000000000000000000000000000 --- a/Documentation/admin-guide/reporting-bugs.rst +++ /dev/null @@ -1,187 +0,0 @@ -.. _reportingbugs: - -.. note:: - - This document is obsolete, and will be replaced by - 'Documentation/admin-guide/reporting-issues.rst' in the near future. - -Reporting bugs -++++++++++++++ - -Background -========== - -The upstream Linux kernel maintainers only fix bugs for specific kernel -versions. Those versions include the current "release candidate" (or -rc) -kernel, any "stable" kernel versions, and any "long term" kernels. - -Please see https://www.kernel.org/ for a list of supported kernels. Any -kernel marked with [EOL] is "end of life" and will not have any fixes -backported to it. - -If you've found a bug on a kernel version that isn't listed on kernel.org, -contact your Linux distribution or embedded vendor for support. -Alternatively, you can attempt to run one of the supported stable or -rc -kernels, and see if you can reproduce the bug on that. It's preferable -to reproduce the bug on the latest -rc kernel. - - -How to report Linux kernel bugs -=============================== - - -Identify the problematic subsystem ----------------------------------- - -Identifying which part of the Linux kernel might be causing your issue -increases your chances of getting your bug fixed. Simply posting to the -generic linux-kernel mailing list (LKML) may cause your bug report to be -lost in the noise of a mailing list that gets 1000+ emails a day. - -Instead, try to figure out which kernel subsystem is causing the issue, -and email that subsystem's maintainer and mailing list. If the subsystem -maintainer doesn't answer, then expand your scope to mailing lists like -LKML. - - -Identify who to notify ----------------------- - -Once you know the subsystem that is causing the issue, you should send a -bug report. Some maintainers prefer bugs to be reported via bugzilla -(https://bugzilla.kernel.org), while others prefer that bugs be reported -via the subsystem mailing list. - -To find out where to send an emailed bug report, find your subsystem or -device driver in the MAINTAINERS file. Search in the file for relevant -entries, and send your bug report to the person(s) listed in the "M:" -lines, making sure to Cc the mailing list(s) in the "L:" lines. When the -maintainer replies to you, make sure to 'Reply-all' in order to keep the -public mailing list(s) in the email thread. - -If you know which driver is causing issues, you can pass one of the driver -files to the get_maintainer.pl script:: - - perl scripts/get_maintainer.pl -f - -If it is a security bug, please copy the Security Contact listed in the -MAINTAINERS file. They can help coordinate bugfix and disclosure. See -:ref:`Documentation/admin-guide/security-bugs.rst ` for more information. - -If you can't figure out which subsystem caused the issue, you should file -a bug in kernel.org bugzilla and send email to -linux-kernel@vger.kernel.org, referencing the bugzilla URL. (For more -information on the linux-kernel mailing list see -http://vger.kernel.org/lkml/). - - -Tips for reporting bugs ------------------------ - -If you haven't reported a bug before, please read: - - https://www.chiark.greenend.org.uk/~sgtatham/bugs.html - - http://www.catb.org/esr/faqs/smart-questions.html - -It's REALLY important to report bugs that seem unrelated as separate email -threads or separate bugzilla entries. If you report several unrelated -bugs at once, it's difficult for maintainers to tease apart the relevant -data. - - -Gather information ------------------- - -The most important information in a bug report is how to reproduce the -bug. This includes system information, and (most importantly) -step-by-step instructions for how a user can trigger the bug. - -If the failure includes an "OOPS:", take a picture of the screen, capture -a netconsole trace, or type the message from your screen into the bug -report. Please read "Documentation/admin-guide/bug-hunting.rst" before posting your -bug report. This explains what you should do with the "Oops" information -to make it useful to the recipient. - -This is a suggested format for a bug report sent via email or bugzilla. -Having a standardized bug report form makes it easier for you not to -overlook things, and easier for the developers to find the pieces of -information they're really interested in. If some information is not -relevant to your bug, feel free to exclude it. - -First run the ver_linux script included as scripts/ver_linux, which -reports the version of some important subsystems. Run this script with -the command ``awk -f scripts/ver_linux``. - -Use that information to fill in all fields of the bug report form, and -post it to the mailing list with a subject of "PROBLEM: " for easy identification by the developers:: - - [1.] One line summary of the problem: - [2.] Full description of the problem/report: - [3.] Keywords (i.e., modules, networking, kernel): - [4.] Kernel information - [4.1.] Kernel version (from /proc/version): - [4.2.] Kernel .config file: - [5.] Most recent kernel version which did not have the bug: - [6.] Output of Oops.. message (if applicable) with symbolic information - resolved (see Documentation/admin-guide/bug-hunting.rst) - [7.] A small shell script or example program which triggers the - problem (if possible) - [8.] Environment - [8.1.] Software (add the output of the ver_linux script here) - [8.2.] Processor information (from /proc/cpuinfo): - [8.3.] Module information (from /proc/modules): - [8.4.] Loaded driver and hardware information (/proc/ioports, /proc/iomem) - [8.5.] PCI information ('lspci -vvv' as root) - [8.6.] SCSI information (from /proc/scsi/scsi) - [8.7.] Other information that might be relevant to the problem - (please look in /proc and include all information that you - think to be relevant): - [X.] Other notes, patches, fixes, workarounds: - - -Follow up -========= - -Expectations for bug reporters ------------------------------- - -Linux kernel maintainers expect bug reporters to be able to follow up on -bug reports. That may include running new tests, applying patches, -recompiling your kernel, and/or re-triggering your bug. The most -frustrating thing for maintainers is for someone to report a bug, and then -never follow up on a request to try out a fix. - -That said, it's still useful for a kernel maintainer to know a bug exists -on a supported kernel, even if you can't follow up with retests. Follow -up reports, such as replying to the email thread with "I tried the latest -kernel and I can't reproduce my bug anymore" are also helpful, because -maintainers have to assume silence means things are still broken. - -Expectations for kernel maintainers ------------------------------------ - -Linux kernel maintainers are busy, overworked human beings. Some times -they may not be able to address your bug in a day, a week, or two weeks. -If they don't answer your email, they may be on vacation, or at a Linux -conference. Check the conference schedule at https://LWN.net for more info: - - https://lwn.net/Calendar/ - -In general, kernel maintainers take 1 to 5 business days to respond to -bugs. The majority of kernel maintainers are employed to work on the -kernel, and they may not work on the weekends. Maintainers are scattered -around the world, and they may not work in your time zone. Unless you -have a high priority bug, please wait at least a week after the first bug -report before sending the maintainer a reminder email. - -The exceptions to this rule are regressions, kernel crashes, security holes, -or userspace breakage caused by new kernel behavior. Those bugs should be -addressed by the maintainers ASAP. If you suspect a maintainer is not -responding to these types of bugs in a timely manner (especially during a -merge window), escalate the bug to LKML and Linus Torvalds. - -Thank you! - -[Some of this is taken from Frohwalt Egerer's original linux-kernel FAQ] diff --git a/Documentation/admin-guide/reporting-issues.rst b/Documentation/admin-guide/reporting-issues.rst index 07879d01fe6854f953adfb3abfcb0ad29e009cf8..48b4d0ef2b09cd5d9770d2d323b37f3cbd8a4854 100644 --- a/Documentation/admin-guide/reporting-issues.rst +++ b/Documentation/admin-guide/reporting-issues.rst @@ -9,25 +9,6 @@ (for example by the kernel's build system) might contain content taken from files which use a more restrictive license. -.. important:: - - This document is being prepared to replace - 'Documentation/admin-guide/reporting-bugs.rst'. The main work is done and - you are already free to follow its instructions when reporting issues to the - Linux kernel developers. But keep in mind, below text still needs a few - finishing touches and review. It was merged to the Linux kernel sources at - this stage to make this process easier and increase the text's visibility. - - Any improvements for the text or other feedback is thus very much welcome. - Please send it to 'Thorsten Leemhuis ' and 'Jonathan - Corbet ', ideally with 'Linux kernel mailing list (LKML) - ' and the 'Linux Kernel Documentation List - ' in CC. - - Areas in the text that still need work or discussion contain a hint like this - which point out the remaining issues; all of them start with the word "FIXME" - to make them easy to find. - Reporting issues ++++++++++++++++ @@ -36,46 +17,43 @@ Reporting issues The short guide (aka TL;DR) =========================== -If you're facing multiple issues with the Linux kernel at once, report each -separately to its developers. Try your best guess which kernel part might be -causing the issue. Check the :ref:`MAINTAINERS ` file for how its -developers expect to be told about issues. Note, it's rarely -`bugzilla.kernel.org `_, as in almost all cases -the report needs to be sent by email! - -Check the destination thoroughly for existing reports; also search the LKML -archives and the web. Join existing discussion if you find matches. If you -don't find any, install `the latest Linux mainline kernel -`_. Make sure it's vanilla, thus is not patched or using -add-on kernel modules. Also ensure the kernel is running in a healthy -environment and is not already tainted before the issue occurs. - -If you can reproduce your issue with the mainline kernel, send a report to the -destination you determined earlier. Make sure it includes all relevant -information, which in case of a regression should mention the change that's -causing it which can often can be found with a bisection. Also ensure the -report reaches all people that need to know about it, for example the security -team, the stable maintainers or the developers of the patch that causes a -regression. Once the report is out, answer any questions that might be raised -and help where you can. That includes keeping the ball rolling: every time a -new rc1 mainline kernel is released, check if the issue is still happening -there and attach a status update to your initial report. - -If you can not reproduce the issue with the mainline kernel, consider sticking -with it; if you'd like to use an older version line and want to see it fixed -there, first make sure it's still supported. Install its latest release as -vanilla kernel. If you cannot reproduce the issue there, try to find the commit -that fixed it in mainline or any discussion preceding it: those will often -mention if backporting is planed or considered too complex. If backporting was -not discussed, ask if it's in the cards. In case you don't find any commits or -a preceding discussion, see the Linux-stable mailing list archives for existing -reports, as it might be a regression specific to the version line. If it is, -report it like you would report a problem in mainline (including the -bisection). - -If you reached this point without a solution, ask for advice one the -subsystem's mailing list. - +Are you facing a regression with vanilla kernels from the same stable or +longterm series? One still supported? Then search the `LKML +`_ and the `Linux stable mailing list +`_ archives for matching reports to join. If +you don't find any, install `the latest release from that series +`_. If it still shows the issue, report it to the stable +mailing list (stable@vger.kernel.org) and CC the regressions list +(regressions@lists.linux.dev). + +In all other cases try your best guess which kernel part might be causing the +issue. Check the :ref:`MAINTAINERS ` file for how its developers +expect to be told about problems, which most of the time will be by email with a +mailing list in CC. Check the destination's archives for matching reports; +search the `LKML `_ and the web, too. If you +don't find any to join, install `the latest mainline kernel +`_. If the issue is present there, send a report. + +The issue was fixed there, but you would like to see it resolved in a still +supported stable or longterm series as well? Then install its latest release. +If it shows the problem, search for the change that fixed it in mainline and +check if backporting is in the works or was discarded; if it's neither, ask +those who handled the change for it. + +**General remarks**: When installing and testing a kernel as outlined above, +ensure it's vanilla (IOW: not patched and not using add-on modules). Also make +sure it's built and running in a healthy environment and not already tainted +before the issue occurs. + +If you are facing multiple issues with the Linux kernel at once, report each +separately. While writing your report, include all information relevant to the +issue, like the kernel and the distro used. In case of a regression, CC the +regressions mailing list (regressions@lists.linux.dev) to your report; also try +to include the commit-id of the change causing it, which a bisection can find. + +Once the report is out, answer any questions that come up and help where you +can. That includes keeping the ball rolling by occasionally retesting with newer +releases and sending a status update afterwards. Step-by-step guide how to report issues to the kernel maintainers ================================================================= @@ -94,28 +72,23 @@ early if an issue that looks like a Linux kernel problem is actually caused by something else. These steps thus help to ensure the time you invest in this process won't feel wasted in the end: - * Stop reading this document and report the problem to your vendor instead, - unless you are running the latest mainline kernel already or are willing to - install it. This kernel must not be modified or enhanced in any way, and - thus be considered 'vanilla'. + * Are you facing an issue with a Linux kernel a hardware or software vendor + provided? Then in almost all cases you are better off to stop reading this + document and reporting the issue to your vendor instead, unless you are + willing to install the latest Linux version yourself. Be aware the latter + will often be needed anyway to hunt down and fix issues. + + * Perform a rough search for existing reports with your favorite internet + search engine; additionally, check the archives of the `Linux Kernel Mailing + List (LKML) `_. If you find matching reports, + join the discussion instead of sending a new one. * See if the issue you are dealing with qualifies as regression, security issue, or a really severe problem: those are 'issues of high priority' that need special handling in some steps that are about to follow. - * Check if your kernel was 'tainted' when the issue occurred, as the event - that made the kernel set this flag might be causing the issue you face. - - * Locate the driver or kernel subsystem that seems to be causing the issue. - Find out how and where its developers expect reports. Note: most of the - time this won't be bugzilla.kernel.org, as issues typically need to be sent - by mail to a maintainer and a public mailing list. - - * Search the archives of the bug tracker or mailing list in question - thoroughly for reports that might match your issue. Also check if you find - something with your favorite internet search engine or in the Linux Kernel - Mailing List (LKML) archives. If you find anything, join the discussion - instead of sending a new report. + * Make sure it's not the kernel's surroundings that are causing the issue + you face. * Create a fresh backup and put system repair and restore tools at hand. @@ -123,8 +96,8 @@ process won't feel wasted in the end: kernel modules on-the-fly, which solutions like DKMS might be doing locally without your knowledge. - * Make sure it's not the kernel's surroundings that are causing the issue - you face. + * Check if your kernel was 'tainted' when the issue occurred, as the event + that made the kernel set this flag might be causing the issue you face. * Write down coarsely how to reproduce the issue. If you deal with multiple issues at once, create separate notes for each of them and make sure they @@ -132,20 +105,35 @@ process won't feel wasted in the end: needs to get reported to the kernel developers separately, unless they are strongly entangled. + * If you are facing a regression within a stable or longterm version line + (say something broke when updating from 5.10.4 to 5.10.5), scroll down to + 'Dealing with regressions within a stable and longterm kernel line'. + + * Locate the driver or kernel subsystem that seems to be causing the issue. + Find out how and where its developers expect reports. Note: most of the + time this won't be bugzilla.kernel.org, as issues typically need to be sent + by mail to a maintainer and a public mailing list. + + * Search the archives of the bug tracker or mailing list in question + thoroughly for reports that might match your issue. If you find anything, + join the discussion instead of sending a new report. + After these preparations you'll now enter the main part: - * Install the latest Linux mainline kernel: that's where all issues get - fixed first, because it's the version line the kernel developers mainly - care about. Testing and reporting with the latest Linux stable kernel can - be an acceptable alternative in some situations, for example during the - merge window; but during that period you might want to suspend your efforts - till its end anyway. + * Unless you are already running the latest 'mainline' Linux kernel, better + go and install it for the reporting process. Testing and reporting with + the latest 'stable' Linux can be an acceptable alternative in some + situations; during the merge window that actually might be even the best + approach, but in that development phase it can be an even better idea to + suspend your efforts for a few days anyway. Whatever version you choose, + ideally use a 'vanilla' build. Ignoring these advices will dramatically + increase the risk your report will be rejected or ignored. * Ensure the kernel you just installed does not 'taint' itself when running. * Reproduce the issue with the kernel you just installed. If it doesn't show - up there, head over to the instructions for issues only happening with + up there, scroll down to the instructions for issues only happening with stable and longterm kernels. * Optimize your notes: try to find and write the most straightforward way to @@ -154,8 +142,8 @@ After these preparations you'll now enter the main part: that hear about it for the first time. And if you learned something in this process, consider searching again for existing reports about the issue. - * If the failure includes a stack dump, like an Oops does, consider decoding - it to find the offending line of code. + * If your failure involves a 'panic', 'Oops', 'warning', or 'BUG', consider + decoding the kernel log to find the line of code that triggered the error. * If your problem is a regression, try to narrow down when the issue was introduced as much as possible. @@ -184,28 +172,54 @@ After these preparations you'll now enter the main part: help yourself, if you don't get any help or if it's unsatisfying. +Reporting regressions within a stable and longterm kernel line +-------------------------------------------------------------- + +This subsection is for you, if you followed above process and got sent here at +the point about regression within a stable or longterm kernel version line. You +face one of those if something breaks when updating from 5.10.4 to 5.10.5 (a +switch from 5.9.15 to 5.10.5 does not qualify). The developers want to fix such +regressions as quickly as possible, hence there is a streamlined process to +report them: + + * Check if the kernel developers still maintain the Linux kernel version + line you care about: go to the `front page of kernel.org + `_ and make sure it mentions + the latest release of the particular version line without an '[EOL]' tag. + + * Check the archives of the `Linux stable mailing list + `_ for existing reports. + + * Install the latest release from the particular version line as a vanilla + kernel. Ensure this kernel is not tainted and still shows the problem, as + the issue might have already been fixed there. If you first noticed the + problem with a vendor kernel, check a vanilla build of the last version + known to work performs fine as well. + + * Send a short problem report to the Linux stable mailing list + (stable@vger.kernel.org) and CC the Linux regressions mailing list + (regressions@lists.linux.dev). Roughly describe the issue and ideally + explain how to reproduce it. Mention the first version that shows the + problem and the last version that's working fine. Then wait for further + instructions. + +The reference section below explains each of these steps in more detail. + + Reporting issues only occurring in older kernel version lines ------------------------------------------------------------- -This section is for you, if you tried the latest mainline kernel as outlined +This subsection is for you, if you tried the latest mainline kernel as outlined above, but failed to reproduce your issue there; at the same time you want to -see the issue fixed in older version lines or a vendor kernel that's regularly -rebased on new stable or longterm releases. If that case follow these steps: +see the issue fixed in a still supported stable or longterm series or vendor +kernels regularly rebased on those. If that the case, follow these steps: * Prepare yourself for the possibility that going through the next few steps might not get the issue solved in older releases: the fix might be too big or risky to get backported there. - * Check if the kernel developers still maintain the Linux kernel version - line you care about: go to the front page of kernel.org and make sure it - mentions the latest release of the particular version line without an - '[EOL]' tag. - - * Check the archives of the Linux stable mailing list for existing reports. - - * Install the latest release from the particular version line as a vanilla - kernel. Ensure this kernel is not tainted and still shows the problem, as - the issue might have already been fixed there. + * Perform the first three steps in the section "Dealing with regressions + within a stable and longterm kernel line" above. * Search the Linux kernel version control system for the change that fixed the issue in mainline, as its commit message might tell you if the fix is @@ -215,22 +229,13 @@ rebased on new stable or longterm releases. If that case follow these steps: deemed unsuitable for backporting. If backporting was not considered at all, join the newest discussion, asking if it's in the cards. - * Check if you're dealing with a regression that was never present in - mainline by installing the first release of the version line you care - about. If the issue doesn't show up with it, you basically need to report - the issue with this version like you would report a problem with mainline - (see above). This ideally includes a bisection followed by a search for - existing reports on the net; with the help of the subject and the two - relevant commit-ids. If that doesn't turn up anything, write the report; CC - or forward the report to the stable maintainers, the stable mailing list, - and those who authored the change. Include the shortened commit-id if you - found the change that causes it. - * One of the former steps should lead to a solution. If that doesn't work out, ask the maintainers for the subsystem that seems to be causing the issue for advice; CC the mailing list for the particular subsystem as well as the stable mailing list. +The reference section below explains each of these steps in more detail. + Reference section: Reporting issues to the kernel maintainers ============================================================= @@ -276,54 +281,103 @@ issues to the Linux kernel developers. Make sure you're using the upstream Linux kernel ------------------------------------------------ - *Stop reading this document and report the problem to your vendor instead, - unless you are running the latest mainline kernel already or are willing to - install it. This kernel must not be modified or enhanced in any way, and - thus be considered 'vanilla'.* + *Are you facing an issue with a Linux kernel a hardware or software vendor + provided? Then in almost all cases you are better off to stop reading this + document and reporting the issue to your vendor instead, unless you are + willing to install the latest Linux version yourself. Be aware the latter + will often be needed anyway to hunt down and fix issues.* Like most programmers, Linux kernel developers don't like to spend time dealing -with reports for issues that don't even happen with the source code they -maintain: it's just a waste everybody's time, yours included. That's why you -later will have to test your issue with the latest 'vanilla' kernel: a kernel -that was build using the Linux sources taken straight from `kernel.org -`_ and not modified or enhanced in any way. - -Almost all kernels used in devices (Computers, Laptops, Smartphones, Routers, -…) and most kernels shipped by Linux distributors are ancient from the point of -kernel development and heavily modified. They thus do not qualify for reporting -an issue to the Linux kernel developers: the issue you face with such a kernel -might be fixed already or caused by the changes or additions, even if they look -small or totally unrelated. That's why issues with such kernels need to be -reported to the vendor that distributed it. Its developers should look into the +with reports for issues that don't even happen with their current code. It's +just a waste everybody's time, especially yours. Unfortunately such situations +easily happen when it comes to the kernel and often leads to frustration on both +sides. That's because almost all Linux-based kernels pre-installed on devices +(Computers, Laptops, Smartphones, Routers, …) and most shipped by Linux +distributors are quite distant from the official Linux kernel as distributed by +kernel.org: these kernels from these vendors are often ancient from the point of +Linux development or heavily modified, often both. + +Most of these vendor kernels are quite unsuitable for reporting issues to the +Linux kernel developers: an issue you face with one of them might have been +fixed by the Linux kernel developers months or years ago already; additionally, +the modifications and enhancements by the vendor might be causing the issue you +face, even if they look small or totally unrelated. That's why you should report +issues with these kernels to the vendor. Its developers should look into the report and, in case it turns out to be an upstream issue, fix it directly -upstream or report it there. In practice that sometimes does not work out. If -that the case, you might want to circumvent the vendor by installing the latest -mainline kernel yourself and reporting the issue as outlined in this document; -just make sure to use really fresh kernel (see below). - - -.. note:: - - FIXME: Should we accept reports for issues with kernel images that are pretty - close to vanilla? But when are they close enough and how to put that line in - words? Maybe something like this? +upstream or forward the report there. In practice that often does not work out +or might not what you want. You thus might want to consider circumventing the +vendor by installing the very latest Linux kernel core yourself. If that's an +option for you move ahead in this process, as a later step in this guide will +explain how to do that once it rules out other potential causes for your issue. + +Note, the previous paragraph is starting with the word 'most', as sometimes +developers in fact are willing to handle reports about issues occurring with +vendor kernels. If they do in the end highly depends on the developers and the +issue in question. Your chances are quite good if the distributor applied only +small modifications to a kernel based on a recent Linux version; that for +example often holds true for the mainline kernels shipped by Debian GNU/Linux +Sid or Fedora Rawhide. Some developers will also accept reports about issues +with kernels from distributions shipping the latest stable kernel, as long as +its only slightly modified; that for example is often the case for Arch Linux, +regular Fedora releases, and openSUSE Tumbleweed. But keep in mind, you better +want to use a mainline Linux and avoid using a stable kernel for this +process, as outlined in the section 'Install a fresh kernel for testing' in more +detail. + +Obviously you are free to ignore all this advice and report problems with an old +or heavily modified vendor kernel to the upstream Linux developers. But note, +those often get rejected or ignored, so consider yourself warned. But it's still +better than not reporting the issue at all: sometimes such reports directly or +indirectly will help to get the issue fixed over time. + + +Search for existing reports, first run +-------------------------------------- + + *Perform a rough search for existing reports with your favorite internet + search engine; additionally, check the archives of the Linux Kernel Mailing + List (LKML). If you find matching reports, join the discussion instead of + sending a new one.* + +Reporting an issue that someone else already brought forward is often a waste of +time for everyone involved, especially you as the reporter. So it's in your own +interest to thoroughly check if somebody reported the issue already. At this +step of the process it's okay to just perform a rough search: a later step will +tell you to perform a more detailed search once you know where your issue needs +to be reported to. Nevertheless, do not hurry with this step of the reporting +process, it can save you time and trouble. + +Simply search the internet with your favorite search engine first. Afterwards, +search the `Linux Kernel Mailing List (LKML) archives +`_. - *Note: Some Linux kernel developers accept reports from vendor kernels that - are known to be close to upstream. That for example is often the case for - the kernels that Debian GNU/Linux Sid or Fedora Rawhide ship, which are - normally following mainline closely and carry only a few patches. So a - report with one of these might be accepted by the developers that need to - handle it. But if they do, depends heavily on the individual developers and - the issue at hand. That's why installing a mainline vanilla kernel is the - safe bet.* +If you get flooded with results consider telling your search engine to limit +search timeframe to the past month or year. And wherever you search, make sure +to use good search terms; vary them a few times, too. While doing so try to +look at the issue from the perspective of someone else: that will help you to +come up with other words to use as search terms. Also make sure not to use too +many search terms at once. Remember to search with and without information like +the name of the kernel driver or the name of the affected hardware component. +But its exact brand name (say 'ASUS Red Devil Radeon RX 5700 XT Gaming OC') +often is not much helpful, as it is too specific. Instead try search terms like +the model line (Radeon 5700 or Radeon 5000) and the code name of the main chip +('Navi' or 'Navi10') with and without its manufacturer ('AMD'). - *Arch Linux, other Fedora releases, and openSUSE Tumbleweed often use quite - recent stable kernels that are pretty close to upstream, too. Some - developers accept bugs from them as well. But note that you normally should - avoid stable kernels for reporting issues and use a mainline kernel instead - (see below).* +In case you find an existing report about your issue, join the discussion, as +you might be able to provide valuable additional information. That can be +important even when a fix is prepared or in its final stages already, as +developers might look for people that can provide additional information or +test a proposed fix. Jump to the section 'Duties after the report went out' for +details on how to get properly involved. - Are there any other major Linux distributions that should be mentioned here? +Note, searching `bugzilla.kernel.org `_ might also +be a good idea, as that might provide valuable insights or turn up matching +reports. If you find the latter, just keep in mind: most subsystems expect +reports in different places, as described below in the section "Check where you +need to report your issue". The developers that should take care of the issue +thus might not even be aware of the bugzilla ticket. Hence, check the ticket if +the issue already got reported as outlined in this document and if not consider +doing so. Issue of high priority? @@ -365,6 +419,75 @@ fatal error where the kernel stop itself) with a 'Oops' (a recoverable error), as the kernel remains running after the latter. +Ensure a healthy environment +---------------------------- + + *Make sure it's not the kernel's surroundings that are causing the issue + you face.* + +Problems that look a lot like a kernel issue are sometimes caused by build or +runtime environment. It's hard to rule out that problem completely, but you +should minimize it: + + * Use proven tools when building your kernel, as bugs in the compiler or the + binutils can cause the resulting kernel to misbehave. + + * Ensure your computer components run within their design specifications; + that's especially important for the main processor, the main memory, and the + motherboard. Therefore, stop undervolting or overclocking when facing a + potential kernel issue. + + * Try to make sure it's not faulty hardware that is causing your issue. Bad + main memory for example can result in a multitude of issues that will + manifest itself in problems looking like kernel issues. + + * If you're dealing with a filesystem issue, you might want to check the file + system in question with ``fsck``, as it might be damaged in a way that leads + to unexpected kernel behavior. + + * When dealing with a regression, make sure it's not something else that + changed in parallel to updating the kernel. The problem for example might be + caused by other software that was updated at the same time. It can also + happen that a hardware component coincidentally just broke when you rebooted + into a new kernel for the first time. Updating the systems BIOS or changing + something in the BIOS Setup can also lead to problems that on look a lot + like a kernel regression. + + +Prepare for emergencies +----------------------- + + *Create a fresh backup and put system repair and restore tools at hand.* + +Reminder, you are dealing with computers, which sometimes do unexpected things, +especially if you fiddle with crucial parts like the kernel of its operating +system. That's what you are about to do in this process. Thus, make sure to +create a fresh backup; also ensure you have all tools at hand to repair or +reinstall the operating system as well as everything you need to restore the +backup. + + +Make sure your kernel doesn't get enhanced +------------------------------------------ + + *Ensure your system does not enhance its kernels by building additional + kernel modules on-the-fly, which solutions like DKMS might be doing locally + without your knowledge.* + +The risk your issue report gets ignored or rejected dramatically increases if +your kernel gets enhanced in any way. That's why you should remove or disable +mechanisms like akmods and DKMS: those build add-on kernel modules +automatically, for example when you install a new Linux kernel or boot it for +the first time. Also remove any modules they might have installed. Then reboot +before proceeding. + +Note, you might not be aware that your system is using one of these solutions: +they often get set up silently when you install Nvidia's proprietary graphics +driver, VirtualBox, or other software that requires a some support from a +module not part of the Linux kernel. That why your might need to uninstall the +packages with such software to get rid of any 3rd party kernel module. + + Check 'taint' flag ------------------ @@ -433,9 +556,52 @@ three things: the name of the module in question). -Locate kernel area that causes the issue +Document how to reproduce issue +------------------------------- + + *Write down coarsely how to reproduce the issue. If you deal with multiple + issues at once, create separate notes for each of them and make sure they + work independently on a freshly booted system. That's needed, as each issue + needs to get reported to the kernel developers separately, unless they are + strongly entangled.* + +If you deal with multiple issues at once, you'll have to report each of them +separately, as they might be handled by different developers. Describing +various issues in one report also makes it quite difficult for others to tear +it apart. Hence, only combine issues in one report if they are very strongly +entangled. + +Additionally, during the reporting process you will have to test if the issue +happens with other kernel versions. Therefore, it will make your work easier if +you know exactly how to reproduce an issue quickly on a freshly booted system. + +Note: it's often fruitless to report issues that only happened once, as they +might be caused by a bit flip due to cosmic radiation. That's why you should +try to rule that out by reproducing the issue before going further. Feel free +to ignore this advice if you are experienced enough to tell a one-time error +due to faulty hardware apart from a kernel issue that rarely happens and thus +is hard to reproduce. + + +Regression in stable or longterm kernel? ---------------------------------------- + *If you are facing a regression within a stable or longterm version line + (say something broke when updating from 5.10.4 to 5.10.5), scroll down to + 'Dealing with regressions within a stable and longterm kernel line'.* + +Regression within a stable and longterm kernel version line are something the +Linux developers want to fix badly, as such issues are even more unwanted than +regression in the main development branch, as they can quickly affect a lot of +people. The developers thus want to learn about such issues as quickly as +possible, hence there is a streamlined process to report them. Note, +regressions with newer kernel version line (say something broke when switching +from 5.9.15 to 5.10.5) do not qualify. + + +Check where you need to report your issue +----------------------------------------- + *Locate the driver or kernel subsystem that seems to be causing the issue. Find out how and where its developers expect reports. Note: most of the time this won't be bugzilla.kernel.org, as issues typically need to be sent @@ -526,26 +692,6 @@ example above does not have such a line. That is the case for most sections, as Linux kernel development is completely driven by mail. Very few subsystems use a bug tracker, and only some of those rely on bugzilla.kernel.org. - -.. note:: - - FIXME: The old text took a totally different approach to bugzilla.kernel.org, - as it mentions it as the place to file issue for people that don't known how - to contact the appropriate people. The new one mentions it rarely; and when - it does like here, it warns users that it's often the wrong place to go. - - This approach was chosen as the main author of this document noticed quite a - few users (or even a lot?) get no reply to the bugs they file in bugzilla. - That's kind of expected, as quite a few (many? most?) of the maintainers - don't even get notified when reports for their subsystem get filed there. And - not getting a single reply to report is something that is just annoying for - users and might make them angry. Improving bugzilla.k.o would be an option, - but on the kernel and maintainers summit 2017 it was agreed on to first go - this route (sorry it took so long): it's easier to achieve and less - controversial, as putting additional burden on already overworked maintainers - is unlikely to get well received. - - In this and many other cases you thus have to look for lines starting with 'Mail:' instead. Those mention the name and the email addresses for the maintainers of the particular code. Also look for a line starting with 'Mailing @@ -558,21 +704,6 @@ and might leave some work for other developers on the subsystem specific list; and LKML is important to have one place where all issue reports can be found. -.. note:: - - FIXME: Above section tells users to always CC LKML. These days it's a kind of - "catch-all" list anyway, which nearly nobody seems to follow closely. So it - seems appropriate to go "all in" and make people send their reports here, - too, as everything (reports, fixes, ...) then can be found in one place (at - least for all reports sent by mail and all subsystems that CC LKML). - - Related: Should we create mailing list like 'linux-issues@vger.kernel.org' - and tell users above to always CC it when reporting issues? Then there would - be one central place reporters could search for existing reports (at least - for issues reported by mail) without getting regular LKML traffic mixed into - the results. - - Finding the maintainers with the help of a script ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -611,205 +742,87 @@ modified during tree-wide cleanups by developers that do not care about the particular driver at all. -Search for existing reports ---------------------------- +Search for existing reports, second run +--------------------------------------- *Search the archives of the bug tracker or mailing list in question - thoroughly for reports that might match your issue. Also check if you find - something with your favorite internet search engine or in the Linux Kernel - Mailing List (LKML) archives. If you find anything, join the discussion - instead of sending a new report.* - -Reporting an issue that someone else already brought forward is often a waste -of time for everyone involved, especially you as the reporter. So it's in your -own interest to thoroughly check if somebody reported the issue already. Thus -do not hurry with this step of the reporting process. Spending 30 to 60 minutes -or even more time can save you and others quite a lot of time and trouble. - -The best place to search is the bug tracker or the mailing list where your -report needs to be filed. You'll find quite a few of those lists on -`lore.kernel.org `_, but some are hosted in -different places. That for example is the case for the ath10k WiFi driver used -as example in the previous step. But you'll often find the archives for these -lists easily on the net. Searching for 'archive ath10k@lists.infradead.org' for -example will quickly lead you to the `Info page for the ath10k mailing list -`_, which at the top links -to its `list archives `_. - -Sadly this and quite a few other lists miss a way to search the archives. In -those cases use a regular internet search engine and add something like + thoroughly for reports that might match your issue. If you find anything, + join the discussion instead of sending a new report.* + +As mentioned earlier already: reporting an issue that someone else already +brought forward is often a waste of time for everyone involved, especially you +as the reporter. That's why you should search for existing report again, now +that you know where they need to be reported to. If it's mailing list, you will +often find its archives on `lore.kernel.org `_. + +But some list are hosted in different places. That for example is the case for +the ath10k WiFi driver used as example in the previous step. But you'll often +find the archives for these lists easily on the net. Searching for 'archive +ath10k@lists.infradead.org' for example will lead you to the `Info page for the +ath10k mailing list `_, +which at the top links to its +`list archives `_. Sadly this and +quite a few other lists miss a way to search the archives. In those cases use a +regular internet search engine and add something like 'site:lists.infradead.org/pipermail/ath10k/' to your search terms, which limits the results to the archives at that URL. -Additionally, search the internet and the `Linux Kernel Mailing List (LKML) -archives `_, as maybe the real culprit might be -in some other subsystem. Searching in `bugzilla.kernel.org -`_ might also be a good idea, but if you find -anything there keep in mind: most subsystems expect reports in different -places, hence those you find there might have not even reached the people -responsible for the subsystem in question. Nevertheless, the data there might -provide valuable insights. - -If you get flooded with results consider telling your search engine to limit -search timeframe to the past month or year. And wherever you search, make sure -to use good search terms; vary them a few times, too. While doing so try to -look at the issue from the perspective of someone else: that will help you to -come up with other words to use as search terms. Also make sure not to use too -many search terms at once. Remember to search with and without information like -the name of the kernel driver or the name of the affected hardware component. -But its exact brand name (say 'ASUS Red Devil Radeon RX 5700 XT Gaming OC') -often is not much helpful, as it is too specific. Instead try search terms like -the model line (Radeon 5700 or Radeon 5000) and the code name of the main chip -('Navi' or 'Navi10') with and without its manufacturer ('AMD'). - -In case you find an existing report about your issue, join the discussion, as -you might be able to provide valuable additional information. That can be -important even when a fix is prepared or in its final stages already, as -developers might look for people that can provide additional information or -test a proposed fix. Jump to the section 'Duties after the report went out' for -details on how to get properly involved. - - -Prepare for emergencies ------------------------ - - *Create a fresh backup and put system repair and restore tools at hand.* - -Reminder, you are dealing with computers, which sometimes do unexpected things, -especially if you fiddle with crucial parts like the kernel of its operating -system. That's what you are about to do in this process. Thus, make sure to -create a fresh backup; also ensure you have all tools at hand to repair or -reinstall the operating system as well as everything you need to restore the -backup. - - -Make sure your kernel doesn't get enhanced ------------------------------------------- - - *Ensure your system does not enhance its kernels by building additional - kernel modules on-the-fly, which solutions like DKMS might be doing locally - without your knowledge.* - -Your kernel must be 'vanilla' when reporting an issue, but stops being pure as -soon as it loads a kernel module not built from the sources used to compile the -kernel image itself. That's why you need to ensure your Linux kernel stays -vanilla by removing or disabling mechanisms like akmods and DKMS: those might -build additional kernel modules automatically, for example when your boot into -a newly installed Linux kernel the first time. Reboot after removing them and -any modules they installed. - -Note, you might not be aware that your system is using one of these solutions: -they often get set up silently when you install Nvidia's proprietary graphics -driver, VirtualBox, or other software that requires a some support from a -module not part of the Linux kernel. That why your might need to uninstall the -packages with such software to get rid of any 3rd party kernel module. - - -Ensure a healthy environment ----------------------------- - - *Make sure it's not the kernel's surroundings that are causing the issue - you face.* - -Problems that look a lot like a kernel issue are sometimes caused by build or -runtime environment. It's hard to rule out that problem completely, but you -should minimize it: - - * Use proven tools when building your kernel, as bugs in the compiler or the - binutils can cause the resulting kernel to misbehave. - - * Ensure your computer components run within their design specifications; - that's especially important for the main processor, the main memory, and the - motherboard. Therefore, stop undervolting or overclocking when facing a - potential kernel issue. - - * Try to make sure it's not faulty hardware that is causing your issue. Bad - main memory for example can result in a multitude of issues that will - manifest itself in problems looking like kernel issues. - - * If you're dealing with a filesystem issue, you might want to check the file - system in question with ``fsck``, as it might be damaged in a way that leads - to unexpected kernel behavior. - - * When dealing with a regression, make sure it's not something else that - changed in parallel to updating the kernel. The problem for example might be - caused by other software that was updated at the same time. It can also - happen that a hardware component coincidentally just broke when you rebooted - into a new kernel for the first time. Updating the systems BIOS or changing - something in the BIOS Setup can also lead to problems that on look a lot - like a kernel regression. - +It's also wise to check the internet, LKML and maybe bugzilla.kernel.org again +at this point. -Document how to reproduce issue -------------------------------- +For details how to search and what to do if you find matching reports see +"Search for existing reports, first run" above. - *Write down coarsely how to reproduce the issue. If you deal with multiple - issues at once, create separate notes for each of them and make sure they - work independently on a freshly booted system. That's needed, as each issue - needs to get reported to the kernel developers separately, unless they are - strongly entangled.* - -If you deal with multiple issues at once, you'll have to report each of them -separately, as they might be handled by different developers. Describing -various issues in one report also makes it quite difficult for others to tear -it apart. Hence, only combine issues in one report if they are very strongly -entangled. - -Additionally, during the reporting process you will have to test if the issue -happens with other kernel versions. Therefore, it will make your work easier if -you know exactly how to reproduce an issue quickly on a freshly booted system. - -Note: it's often fruitless to report issues that only happened once, as they -might be caused by a bit flip due to cosmic radiation. That's why you should -try to rule that out by reproducing the issue before going further. Feel free -to ignore this advice if you are experienced enough to tell a one-time error -due to faulty hardware apart from a kernel issue that rarely happens and thus -is hard to reproduce. +Do not hurry with this step of the reporting process: spending 30 to 60 minutes +or even more time can save you and others quite a lot of time and trouble. Install a fresh kernel for testing ---------------------------------- - *Install the latest Linux mainline kernel: that's where all issues get - fixed first, because it's the version line the kernel developers mainly - care about. Testing and reporting with the latest Linux stable kernel can - be an acceptable alternative in some situations, for example during the - merge window; but during that period you might want to suspend your efforts - till its end anyway.* - -Reporting an issue to the Linux kernel developers they fixed weeks or months -ago is annoying for them and wasting their and your time. That's why it's in -everybody's interest to check if the issue occurs with the latest codebase -before reporting it. - -In the scope of the Linux kernel the term 'latest' means: a kernel version -recently created from the main line of development, as this 'mainline' tree is -where developers first apply fixes; only after that are they are allowed to get -backported to older, still supported version lines called 'stable' and -'longterm' kernels. That's why you should check a recent mainline kernel, even -if you deal with an issue you only want to see fixed in an older version line. -Another reason: some fixes are only applied to mainline or recent version -lines, as it's too hard or risky to backport them to older versions. If that -the case, reporting the issue again is unlikely to change anything. - -Longterm kernels (sometimes called "LTS kernels") are therefore unsuitable for -testing; they simply are too distant from current development. Even the latest -Linux 'stable' kernel is a significant bit behind and thus better avoided. At -least most of the time, as sometimes a stable kernel can the best choice; but -in those situations you might want to wait a few days anyway: - -Choosing between mainline, stable and waiting -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Head over to `kernel.org `_ to decide which version to -use. Ignore the big yellow button that says 'Latest release' and look a little -lower for a table. At its top you'll see a line starting with 'mainline', which -most of the time will point to a pre-release with a version number like -'5.8-rc2'. If that's the case, you'll want to use this mainline kernel for -testing. Do not let that 'rc' scare you, these 'development kernels' are pretty -reliable — and you made a backup, as you were instructed above, didn't you? - -In about two out of every nine to ten weeks, 'mainline' might point you to a + *Unless you are already running the latest 'mainline' Linux kernel, better + go and install it for the reporting process. Testing and reporting with + the latest 'stable' Linux can be an acceptable alternative in some + situations; during the merge window that actually might be even the best + approach, but in that development phase it can be an even better idea to + suspend your efforts for a few days anyway. Whatever version you choose, + ideally use a 'vanilla' built. Ignoring these advices will dramatically + increase the risk your report will be rejected or ignored.* + +As mentioned in the detailed explanation for the first step already: Like most +programmers, Linux kernel developers don't like to spend time dealing with +reports for issues that don't even happen with the current code. It's just a +waste everybody's time, especially yours. That's why it's in everybody's +interest that you confirm the issue still exists with the latest upstream code +before reporting it. You are free to ignore this advice, but as outlined +earlier: doing so dramatically increases the risk that your issue report might +get rejected or simply ignored. + +In the scope of the kernel "latest upstream" normally means: + + * Install a mainline kernel; the latest stable kernel can be an option, but + most of the time is better avoided. Longterm kernels (sometimes called 'LTS + kernels') are unsuitable at this point of the process. The next subsection + explains all of this in more detail. + + * The over next subsection describes way to obtain and install such a kernel. + It also outlines that using a pre-compiled kernel are fine, but better are + vanilla, which means: it was built using Linux sources taken straight `from + kernel.org `_ and not modified or enhanced in any way. + +Choosing the right version for testing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Head over to `kernel.org `_ to find out which version you +want to use for testing. Ignore the big yellow button that says 'Latest release' +and look a little lower at the table. At its top you'll see a line starting with +mainline, which most of the time will point to a pre-release with a version +number like '5.8-rc2'. If that's the case, you'll want to use this mainline +kernel for testing, as that where all fixes have to be applied first. Do not let +that 'rc' scare you, these 'development kernels' are pretty reliable — and you +made a backup, as you were instructed above, didn't you? + +In about two out of every nine to ten weeks, mainline might point you to a proper release with a version number like '5.7'. If that happens, consider suspending the reporting process until the first pre-release of the next version (5.8-rc1) shows up on kernel.org. That's because the Linux development @@ -830,45 +843,79 @@ case mainline for some reason does currently not work for you. An in general: using it for reproducing the issue is also better than not reporting it issue at all. +Better avoid using the latest stable kernel outside merge windows, as all fixes +must be applied to mainline first. That's why checking the latest mainline +kernel is so important: any issue you want to see fixed in older version lines +needs to be fixed in mainline first before it can get backported, which can +take a few days or weeks. Another reason: the fix you hope for might be too +hard or risky for backporting; reporting the issue again hence is unlikely to +change anything. + +These aspects are also why longterm kernels (sometimes called "LTS kernels") +are unsuitable for this part of the reporting process: they are to distant from +the current code. Hence go and test mainline first and follow the process +further: if the issue doesn't occur with mainline it will guide you how to get +it fixed in older version lines, if that's in the cards for the fix in question. + How to obtain a fresh Linux kernel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can use pre-built or self-compiled kernel for testing; if you choose the -latter approach, you can either obtain the source code using git or download it -as tar archive. - -Using a pre-compiled kernel for testing is often the quickest, easiest, and -safest way – especially is you are unfamiliar with the Linux kernel. But it -needs to be a vanilla kernel, which can be hard to come buy. You are in luck if -you are using a popular Linux distribution: for quite a few of them you'll find -repositories on the net that contain packages with the latest mainline or -stable kernels in vanilla fashion. It's totally okay to use these, just make -sure from the repository's documentation they are really vanilla. And ensure -the packages contain the latest versions as offered on kernel.org; they are -likely unsuitable if the package is older than a week, as new mainline and -stable kernels typically get released at least once a week. And be aware that -you might need to get build your own kernel later anyway when it comes to -helping test fixes, as described later in this document. - -Developers and experienced Linux users familiar with git are often best served -by obtaining the latest Linux kernel sources straight from the `official -development repository on kernel.org +**Using a pre-compiled kernel**: This is often the quickest, easiest, and safest +way for testing — especially is you are unfamiliar with the Linux kernel. The +problem: most of those shipped by distributors or add-on repositories are build +from modified Linux sources. They are thus not vanilla and therefore often +unsuitable for testing and issue reporting: the changes might cause the issue +you face or influence it somehow. + +But you are in luck if you are using a popular Linux distribution: for quite a +few of them you'll find repositories on the net that contain packages with the +latest mainline or stable Linux built as vanilla kernel. It's totally okay to +use these, just make sure from the repository's description they are vanilla or +at least close to it. Additionally ensure the packages contain the latest +versions as offered on kernel.org. The packages are likely unsuitable if they +are older than a week, as new mainline and stable kernels typically get released +at least once a week. + +Please note that you might need to build your own kernel manually later: that's +sometimes needed for debugging or testing fixes, as described later in this +document. Also be aware that pre-compiled kernels might lack debug symbols that +are needed to decode messages the kernel prints when a panic, Oops, warning, or +BUG occurs; if you plan to decode those, you might be better off compiling a +kernel yourself (see the end of this subsection and the section titled 'Decode +failure messages' for details). + +**Using git**: Developers and experienced Linux users familiar with git are +often best served by obtaining the latest Linux kernel sources straight from the +`official development repository on kernel.org `_. Those are likely a bit ahead of the latest mainline pre-release. Don't worry about it: they are as reliable as a proper pre-release, unless the kernel's development cycle is currently in the middle of a merge window. But even then they are quite reliable. -People unfamiliar with git are often best served by downloading the sources as -tarball from `kernel.org `_. +**Conventional**: People unfamiliar with git are often best served by +downloading the sources as tarball from `kernel.org `_. -How to actually build a kernel isnot described here, as many websites explain +How to actually build a kernel is not described here, as many websites explain the necessary steps already. If you are new to it, consider following one of those how-to's that suggest to use ``make localmodconfig``, as that tries to pick up the configuration of your current kernel and then tries to adjust it somewhat for your system. That does not make the resulting kernel any better, but quicker to compile. +Note: If you are dealing with a panic, Oops, warning, or BUG from the kernel, +please try to enable CONFIG_KALLSYMS when configuring your kernel. +Additionally, enable CONFIG_DEBUG_KERNEL and CONFIG_DEBUG_INFO, too; the +latter is the relevant one of those two, but can only be reached if you enable +the former. Be aware CONFIG_DEBUG_INFO increases the storage space required to +build a kernel by quite a bit. But that's worth it, as these options will allow +you later to pinpoint the exact line of code that triggers your issue. The +section 'Decode failure messages' below explains this in more detail. + +But keep in mind: Always keep a record of the issue encountered in case it is +hard to reproduce. Sending an undecoded report is better than not reporting +the issue at all. + Check 'taint' flag ------------------ @@ -888,7 +935,7 @@ Reproduce issue with the fresh kernel ------------------------------------- *Reproduce the issue with the kernel you just installed. If it doesn't show - up there, head over to the instructions for issues only happening with + up there, scroll down to the instructions for issues only happening with stable and longterm kernels.* Check if the issue occurs with the fresh Linux kernel version you just @@ -923,31 +970,55 @@ instead you can join. Decode failure messages ----------------------- -.. note:: + *If your failure involves a 'panic', 'Oops', 'warning', or 'BUG', consider + decoding the kernel log to find the line of code that triggered the error.* - FIXME: The text in this section is a placeholder for now and quite similar to - the old text found in 'Documentation/admin-guide/reporting-bugs.rst' - currently. It and the document it references are known to be outdated and - thus need to be revisited. Thus consider this note a request for help: if you - are familiar with this topic, please write a few lines that would fit here. - Alternatively, simply outline the current situation roughly to the main - authors of this document (see intro), as they might be able to write - something then. +When the kernel detects an internal problem, it will log some information about +the executed code. This makes it possible to pinpoint the exact line in the +source code that triggered the issue and shows how it was called. But that only +works if you enabled CONFIG_DEBUG_INFO and CONFIG_KALLSYMS when configuring +your kernel. If you did so, consider to decode the information from the +kernel's log. That will make it a lot easier to understand what lead to the +'panic', 'Oops', 'warning', or 'BUG', which increases the chances that someone +can provide a fix. - This section in the end should answer questions like "when is this actually - needed", "what .config options to ideally set earlier to make this step easy - or unnecessary?" (likely CONFIG_UNWINDER_ORC when it's available, otherwise - CONFIG_UNWINDER_FRAME_POINTER; but is there anything else needed?). +Decoding can be done with a script you find in the Linux source tree. If you +are running a kernel you compiled yourself earlier, call it like this:: -.. + [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh ./linux-5.10.5/vmlinux + +If you are running a packaged vanilla kernel, you will likely have to install +the corresponding packages with debug symbols. Then call the script (which you +might need to get from the Linux sources if your distro does not package it) +like this:: + + [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh \ + /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/ + +The script will work on log lines like the following, which show the address of +the code the kernel was executing when the error occurred:: + + [ 68.387301] RIP: 0010:test_module_init+0x5/0xffa [test_module] + +Once decoded, these lines will look like this:: - *If the failure includes a stack dump, like an Oops does, consider decoding - it to find the offending line of code.* + [ 68.387301] RIP: 0010:test_module_init (/home/username/linux-5.10.5/test-module/test-module.c:16) test_module -When the kernel detects an error, it will print a stack dump that allows to -identify the exact line of code where the issue happens. But that information -sometimes needs to get decoded to be readable, which is explained in -admin-guide/bug-hunting.rst. +In this case the executed code was built from the file +'~/linux-5.10.5/test-module/test-module.c' and the error occurred by the +instructions found in line '16'. + +The script will similarly decode the addresses mentioned in the section +starting with 'Call trace', which show the path to the function where the +problem occurred. Additionally, the script will show the assembler output for +the code section the kernel was executing. + +Note, if you can't get this to work, simply skip this step and mention the +reason for it in the report. If you're lucky, it might not be needed. And if it +is, someone might help you to get things going. Also be aware this is just one +of several ways to decode kernel stack traces. Sometimes different steps will +be required to retrieve the relevant details. Don't worry about that, if that's +needed in your case, developers will tell you what to do. Special care for regressions @@ -1000,8 +1071,7 @@ In the whole process keep in mind: an issue only qualifies as regression if the older and the newer kernel got built with a similar configuration. The best way to archive this: copy the configuration file (``.config``) from the old working kernel freshly to each newer kernel version you try. Afterwards run ``make -oldnoconfig`` to adjust it for the needs of the new version without enabling -any new feature, as those are allowed to cause regressions. +olddefconfig`` to adjust it for the needs of the new version. Write and send the report @@ -1166,17 +1236,26 @@ Special handling for high priority issues Reports for high priority issues need special handling. -**Severe bugs**: make sure the subject or ticket title as well as the first +**Severe issues**: make sure the subject or ticket title as well as the first paragraph makes the severeness obvious. -**Regressions**: If the issue is a regression add [REGRESSION] to the mail's -subject or the title in the bug-tracker. If you did not perform a bisection -mention at least the latest mainline version you tested that worked fine (say -5.7) and the oldest where the issue occurs (say 5.8). If you did a successful -bisection mention the commit id and subject of the change that causes the -regression. Also make sure to add the author of that change to your report; if -you need to file your bug in a bug-tracker forward the report to him in a -private mail and mention where your filed it. +**Regressions**: make the report's subject start with '[REGRESSION]'. + +In case you performed a successful bisection, use the title of the change that +introduced the regression as the second part of your subject. Make the report +also mention the commit id of the culprit. In case of an unsuccessful bisection, +make your report mention the latest tested version that's working fine (say 5.7) +and the oldest where the issue occurs (say 5.8-rc1). + +When sending the report by mail, CC the Linux regressions mailing list +(regressions@lists.linux.dev). In case the report needs to be filed to some web +tracker, proceed to do so; once filed, forward the report by mail to the +regressions list. Make sure to inline the forwarded report, hence do not attach +it. Also add a short note at the top where you mention the URL to the ticket. + +When mailing or forwarding the report, in case of a successful bisection add the +author of the culprit to the recipients; also CC everyone in the signed-off-by +chain, which you find at the end of its commit message. **Security issues**: for these issues your will have to evaluate if a short-term risk to other users would arise if details were publicly disclosed. @@ -1255,7 +1334,7 @@ you never have heard of yet; or you might be asked to apply a patch to the Linux kernel sources to test if it helps. In some cases it will be fine sending a reply asking for instructions how to do that. But before going that route try to find the answer own your own by searching the internet; alternatively -consider asking in other places for advice. For example ask a fried or post +consider asking in other places for advice. For example ask a friend or post about it to a chatroom or forum you normally hang out. **Be patient**: If you are really lucky you might get a reply to your report @@ -1390,32 +1469,11 @@ easier. And with a bit of luck there might be someone in the team that knows a bit about programming and might be able to write a fix. -Details about reporting issues only occurring in older kernel version lines ---------------------------------------------------------------------------- +Reference for "Reporting regressions within a stable and longterm kernel line" +------------------------------------------------------------------------------ -This subsection provides details for steps you need to take if you could not -reproduce your issue with a mainline kernel, but want to see it fixed in older -version lines (aka stable and longterm kernels). - -Some fixes are too complex -~~~~~~~~~~~~~~~~~~~~~~~~~~ - - *Prepare yourself for the possibility that going through the next few steps - might not get the issue solved in older releases: the fix might be too big - or risky to get backported there.* - -Even small and seemingly obvious code-changes sometimes introduce new and -totally unexpected problems. The maintainers of the stable and longterm kernels -are very aware of that and thus only apply changes to these kernels that are -within rules outlined in 'Documentation/process/stable-kernel-rules.rst'. - -Complex or risky changes for example do not qualify and thus only get applied -to mainline. Other fixes are easy to get backported to the newest stable and -longterm kernels, but too risky to integrate into older ones. So be aware the -fix you are hoping for might be one of those that won't be backported to the -version line your care about. In that case you'll have no other choice then to -live with the issue or switch to a newer Linux version, unless you want to -patch the fix into your kernels yourself. +This subsection provides details for the steps you need to perform if you face +a regression within a stable and longterm kernel line. Make sure the particular version line still gets support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1431,7 +1489,7 @@ chosen and gets supported for at least two years (often six). That's why you need to check if the kernel developers still support the version line you care for. -Note, if kernel.org lists two 'stable' version lines on the front page, you +Note, if kernel.org lists two stable version lines on the front page, you should consider switching to the newer one and forget about the older one: support for it is likely to be abandoned soon. Then it will get a "end-of-life" (EOL) stamp. Version lines that reached that point still get mentioned on the @@ -1454,12 +1512,103 @@ Reproduce issue with the newest release *Install the latest release from the particular version line as a vanilla kernel. Ensure this kernel is not tainted and still shows the problem, as - the issue might have already been fixed there.* + the issue might have already been fixed there. If you first noticed the + problem with a vendor kernel, check a vanilla build of the last version + known to work performs fine as well.* Before investing any more time in this process you want to check if the issue was already fixed in the latest release of version line you're interested in. This kernel needs to be vanilla and shouldn't be tainted before the issue -happens, as detailed outlined already above in the process of testing mainline. +happens, as detailed outlined already above in the section "Install a fresh +kernel for testing". + +Did you first notice the regression with a vendor kernel? Then changes the +vendor applied might be interfering. You need to rule that out by performing +a recheck. Say something broke when you updated from 5.10.4-vendor.42 to +5.10.5-vendor.43. Then after testing the latest 5.10 release as outlined in +the previous paragraph check if a vanilla build of Linux 5.10.4 works fine as +well. If things are broken there, the issue does not qualify as upstream +regression and you need switch back to the main step-by-step guide to report +the issue. + +Report the regression +~~~~~~~~~~~~~~~~~~~~~ + + *Send a short problem report to the Linux stable mailing list + (stable@vger.kernel.org) and CC the Linux regressions mailing list + (regressions@lists.linux.dev). Roughly describe the issue and ideally + explain how to reproduce it. Mention the first version that shows the + problem and the last version that's working fine. Then wait for further + instructions.* + +When reporting a regression that happens within a stable or longterm kernel +line (say when updating from 5.10.4 to 5.10.5) a brief report is enough for +the start to get the issue reported quickly. Hence a rough description is all +it takes. + +But note, it helps developers a great deal if you can specify the exact version +that introduced the problem. Hence if possible within a reasonable time frame, +try to find that version using vanilla kernels. Lets assume something broke when +your distributor released a update from Linux kernel 5.10.5 to 5.10.8. Then as +instructed above go and check the latest kernel from that version line, say +5.10.9. If it shows the problem, try a vanilla 5.10.5 to ensure that no patches +the distributor applied interfere. If the issue doesn't manifest itself there, +try 5.10.7 and then (depending on the outcome) 5.10.8 or 5.10.6 to find the +first version where things broke. Mention it in the report and state that 5.10.9 +is still broken. + +What the previous paragraph outlines is basically a rough manual 'bisection'. +Once your report is out your might get asked to do a proper one, as it allows to +pinpoint the exact change that causes the issue (which then can easily get +reverted to fix the issue quickly). Hence consider to do a proper bisection +right away if time permits. See the section 'Special care for regressions' and +the document 'Documentation/admin-guide/bug-bisect.rst' for details how to +perform one. + + +Reference for "Reporting issues only occurring in older kernel version lines" +----------------------------------------------------------------------------- + +This section provides details for the steps you need to take if you could not +reproduce your issue with a mainline kernel, but want to see it fixed in older +version lines (aka stable and longterm kernels). + +Some fixes are too complex +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + *Prepare yourself for the possibility that going through the next few steps + might not get the issue solved in older releases: the fix might be too big + or risky to get backported there.* + +Even small and seemingly obvious code-changes sometimes introduce new and +totally unexpected problems. The maintainers of the stable and longterm kernels +are very aware of that and thus only apply changes to these kernels that are +within rules outlined in 'Documentation/process/stable-kernel-rules.rst'. + +Complex or risky changes for example do not qualify and thus only get applied +to mainline. Other fixes are easy to get backported to the newest stable and +longterm kernels, but too risky to integrate into older ones. So be aware the +fix you are hoping for might be one of those that won't be backported to the +version line your care about. In that case you'll have no other choice then to +live with the issue or switch to a newer Linux version, unless you want to +patch the fix into your kernels yourself. + +Common preparations +~~~~~~~~~~~~~~~~~~~ + + *Perform the first three steps in the section "Reporting issues only + occurring in older kernel version lines" above.* + +You need to carry out a few steps already described in another section of this +guide. Those steps will let you: + + * Check if the kernel developers still maintain the Linux kernel version line + you care about. + + * Search the Linux stable mailing list for exiting reports. + + * Check with the latest release. + Check code history and search for existing discussions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1513,41 +1662,6 @@ discussions abound it. join the discussion: mention the version where you face the issue and that you would like to see it fixed, if suitable. -Check if it's a regression specific to stable or longterm kernels -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - *Check if you're dealing with a regression that was never present in - mainline by installing the first release of the version line you care - about. If the issue doesn't show up with it, you basically need to report - the issue with this version like you would report a problem with mainline - (see above). This ideally includes a bisection followed by a search for - existing reports on the net; with the help of the subject and the two - relevant commit-ids. If that doesn't turn up anything, write the report; CC - or forward the report to the stable maintainers, the stable mailing list, - and those who authored the change. Include the shortened commit-id if you - found the change that causes it.* - -Sometimes you won't find anything in the previous step: the issue you face -might have never occurred in mainline, as it is caused by some change that is -incomplete or not correctly applied. To check this, install the first release -from version line you care about, e.g., if you care about 5.4.x, install 5.4. - -If the issue doesn't show itself there, it's a regression specific to the -particular version line. In that case you need to report it like an issue -happening in mainline, like the last few steps in the main section in the above -outline. - -One of them suggests doing a bisection, which you are strongly advised to do in -this case. After finding the culprit, search the net for existing reports -again: not only search for the exact subject and the commit-id (proper and -shortened to twelve characters) of the change, but also for the commit-id -(proper and shortened) mentioned as 'Upstream commit' in the commit message. - -Write the report; just keep a few specialties in mind: CC or forward the report -to the stable maintainers, the stable mailing list, which the :ref:`MAINTAINERS -` file mentions in the section "STABLE BRANCH". If you performed a -successful bisection, CC the author of the change and include its subject and -the shortened commit-id. Ask for advice ~~~~~~~~~~~~~~ @@ -1560,8 +1674,7 @@ Ask for advice If the previous three steps didn't get you closer to a solution there is only one option left: ask for advice. Do that in a mail you sent to the maintainers for the subsystem where the issue seems to have its roots; CC the mailing list -for the subsystem as well as the stable mailing list the :ref:`MAINTAINERS -` file mention in the section "STABLE BRANCH". +for the subsystem as well as the stable mailing list (stable@vger.kernel.org). Why some issues won't get any reaction or remain unfixed after being reported @@ -1629,3 +1742,13 @@ issues to the Linux kernel developers: the length and complexity of this document and the implications between the lines illustrate that. But that's how it is for now. The main author of this text hopes documenting the state of the art will lay some groundwork to improve the situation over time. + + +.. + This text is maintained by Thorsten Leemhuis . If you + spot a typo or small mistake, feel free to let him know directly and he'll + fix it. You are free to do the same in a mostly informal way if you want + to contribute changes to the text, but for copyright reasons please CC + linux-doc@vger.kernel.org and "sign-off" your contribution as + Documentation/process/submitting-patches.rst outlines in the section "Sign + your work - the Developer's Certificate of Origin". diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst index 67dfa4c290935bb3f15df294770704cf91c3b1a9..60ce5f5ebab6948de2856bcbd8b246f9c0ad2fcf 100644 --- a/Documentation/admin-guide/sysrq.rst +++ b/Documentation/admin-guide/sysrq.rst @@ -90,8 +90,8 @@ Command Function ``b`` Will immediately reboot the system without syncing or unmounting your disks. -``c`` Will perform a system crash by a NULL pointer dereference. - A crashdump will be taken if configured. +``c`` Will perform a system crash and a crashdump will be taken + if configured. ``d`` Shows all locks that are held. diff --git a/Documentation/arch.rst b/Documentation/arch.rst new file mode 100644 index 0000000000000000000000000000000000000000..f10bd32a5972e244ccaa354a0c24788043d71d3f --- /dev/null +++ b/Documentation/arch.rst @@ -0,0 +1,26 @@ +.. SPDX-License-Identifier: GPL-2.0 + +CPU Architectures +================= + +These books provide programming details about architecture-specific +implementation. + +.. toctree:: + :maxdepth: 2 + + arm/index + arm64/index + ia64/index + m68k/index + mips/index + nios2/index + openrisc/index + parisc/index + powerpc/index + riscv/index + s390/index + sh/index + sparc/index + x86/index + xtensa/index diff --git a/Documentation/arm/index.rst b/Documentation/arm/index.rst index b4bea32472b662a1eaf339350f6ac8a96a0a9102..d4f34ae9e6f4d6b925dee2d73f2599a4c6d8294b 100644 --- a/Documentation/arm/index.rst +++ b/Documentation/arm/index.rst @@ -52,6 +52,7 @@ SoC-specific documents stm32/stm32f746-overview stm32/overview stm32/stm32h743-overview + stm32/stm32h750-overview stm32/stm32f769-overview stm32/stm32f429-overview stm32/stm32mp157-overview diff --git a/Documentation/arm/marvell.rst b/Documentation/arm/marvell.rst index 94cd7338359428b515616ec55052b03ccfda8477..c50be711ec728d270ac68dfdb25d53456b42b05e 100644 --- a/Documentation/arm/marvell.rst +++ b/Documentation/arm/marvell.rst @@ -18,12 +18,12 @@ Orion family - 88F5181L - 88F5182 - - Datasheet: http://www.embeddedarm.com/documentation/third-party/MV88F5182-datasheet.pdf - - Programmer's User Guide: http://www.embeddedarm.com/documentation/third-party/MV88F5182-opensource-manual.pdf - - User Manual: http://www.embeddedarm.com/documentation/third-party/MV88F5182-usermanual.pdf + - Datasheet: https://web.archive.org/web/20210124231420/http://csclub.uwaterloo.ca/~board/ts7800/MV88F5182-datasheet.pdf + - Programmer's User Guide: https://web.archive.org/web/20210124231536/http://csclub.uwaterloo.ca/~board/ts7800/MV88F5182-opensource-manual.pdf + - User Manual: https://web.archive.org/web/20210124231631/http://csclub.uwaterloo.ca/~board/ts7800/MV88F5182-usermanual.pdf - 88F5281 - - Datasheet: http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf + - Datasheet: https://web.archive.org/web/20131028144728/http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf - 88F6183 Core: Feroceon 88fr331 (88f51xx) or 88fr531-vd (88f52xx) ARMv5 compatible @@ -38,33 +38,33 @@ Kirkwood family Flavors: - 88F6282 a.k.a Armada 300 - - Product Brief : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf + - Product Brief : https://web.archive.org/web/20111027032509/http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf - 88F6283 a.k.a Armada 310 - - Product Brief : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf + - Product Brief : https://web.archive.org/web/20111027032509/http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf - 88F6190 - - Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf - - Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + - Product Brief : https://web.archive.org/web/20130730072715/http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf + - Hardware Spec : https://web.archive.org/web/20121021182835/http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf + - Functional Spec: https://web.archive.org/web/20130730091033/http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf - 88F6192 - - Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf - - Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + - Product Brief : https://web.archive.org/web/20131113121446/http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf + - Hardware Spec : https://web.archive.org/web/20121021182835/http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf + - Functional Spec: https://web.archive.org/web/20130730091033/http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf - 88F6182 - 88F6180 - - Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf - - Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + - Product Brief : https://web.archive.org/web/20120616201621/http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf + - Hardware Spec : https://web.archive.org/web/20130730091654/http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf + - Functional Spec: https://web.archive.org/web/20130730091033/http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf - 88F6281 - - Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf - - Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + - Product Brief : https://web.archive.org/web/20120131133709/http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf + - Hardware Spec : https://web.archive.org/web/20120620073511/http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf + - Functional Spec: https://web.archive.org/web/20130730091033/http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf Homepage: - http://www.marvell.com/embedded-processors/kirkwood/ + https://web.archive.org/web/20160513194943/http://www.marvell.com/embedded-processors/kirkwood/ Core: Feroceon 88fr131 ARMv5 compatible Linux kernel mach directory: @@ -78,14 +78,15 @@ Discovery family Flavors: - MV78100 - - Product Brief : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf - - Hardware Spec : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf + - Product Brief : https://web.archive.org/web/20120616194711/http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf + - Hardware Spec : https://web.archive.org/web/20141005120451/http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf + - Functional Spec: https://web.archive.org/web/20111110081125/http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf - MV78200 - - Product Brief : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf - - Hardware Spec : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf + - Product Brief : https://web.archive.org/web/20140801121623/http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf + - Hardware Spec : https://web.archive.org/web/20141005120458/http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf + - Functional Spec: https://web.archive.org/web/20111110081125/http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf + - MV76100 Not supported by the Linux kernel. @@ -106,9 +107,9 @@ EBU Armada family - 88F6707 - 88F6W11 - - Product Brief: http://www.marvell.com/embedded-processors/armada-300/assets/Marvell_ARMADA_370_SoC.pdf - - Hardware Spec: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-datasheet.pdf - - Functional Spec: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf + - Product Brief: https://web.archive.org/web/20121115063038/http://www.marvell.com/embedded-processors/armada-300/assets/Marvell_ARMADA_370_SoC.pdf + - Hardware Spec: https://web.archive.org/web/20140617183747/http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-datasheet.pdf + - Functional Spec: https://web.archive.org/web/20140617183701/http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf Core: Sheeva ARMv7 compatible PJ4B @@ -116,7 +117,7 @@ EBU Armada family Armada 375 Flavors: - 88F6720 - - Product Brief: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA_375_SoC-01_product_brief.pdf + - Product Brief: https://web.archive.org/web/20131216023516/http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA_375_SoC-01_product_brief.pdf Core: ARM Cortex-A9 @@ -126,8 +127,8 @@ EBU Armada family - 88F6820 Armada 385 - 88F6828 Armada 388 - - Product infos: http://www.marvell.com/embedded-processors/armada-38x/ - - Functional Spec: http://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-38x-functional-specifications-2015-11.pdf + - Product infos: https://web.archive.org/web/20181006144616/http://www.marvell.com/embedded-processors/armada-38x/ + - Functional Spec: https://web.archive.org/web/20200420191927/https://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-38x-functional-specifications-2015-11.pdf Core: ARM Cortex-A9 @@ -136,7 +137,7 @@ EBU Armada family - 88F6920 Armada 390 - 88F6928 Armada 398 - - Product infos: http://www.marvell.com/embedded-processors/armada-39x/ + - Product infos: https://web.archive.org/web/20181020222559/http://www.marvell.com/embedded-processors/armada-39x/ Core: ARM Cortex-A9 @@ -150,16 +151,16 @@ EBU Armada family not to be confused with the non-SMP 78xx0 SoCs Product Brief: - http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf + https://web.archive.org/web/20121021173528/http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf Functional Spec: - http://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf + https://web.archive.org/web/20180829171131/http://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf - Hardware Specs: - - http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78230_OS.PDF - - http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78260_OS.PDF - - http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78460_OS.PDF + - https://web.archive.org/web/20141127013651/http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78230_OS.PDF + - https://web.archive.org/web/20141222000224/http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78260_OS.PDF + - https://web.archive.org/web/20141222000230/http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78460_OS.PDF Core: Sheeva ARMv7 compatible Dual-core or Quad-core PJ4B-MP @@ -180,13 +181,13 @@ EBU Armada family ARMv8 ARM Cortex A53 (ARMv8) Homepage: - http://www.marvell.com/embedded-processors/armada-3700/ + https://web.archive.org/web/20181103003602/http://www.marvell.com/embedded-processors/armada-3700/ Product Brief: - http://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-37xx-product-brief-2016-01.pdf + https://web.archive.org/web/20210121194810/https://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-37xx-product-brief-2016-01.pdf Hardware Spec: - http://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-37xx-hardware-specifications-2019-09.pdf + https://web.archive.org/web/20210202162011/http://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-37xx-hardware-specifications-2019-09.pdf Device tree files: arch/arm64/boot/dts/marvell/armada-37* @@ -198,11 +199,11 @@ EBU Armada family ARMv8 Core: ARM Cortex A72 Homepage: - http://www.marvell.com/embedded-processors/armada-70xx/ + https://web.archive.org/web/20181020222606/http://www.marvell.com/embedded-processors/armada-70xx/ Product Brief: - - http://www.marvell.com/embedded-processors/assets/Armada7020PB-Jan2016.pdf - - http://www.marvell.com/embedded-processors/assets/Armada7040PB-Jan2016.pdf + - https://web.archive.org/web/20161010105541/http://www.marvell.com/embedded-processors/assets/Armada7020PB-Jan2016.pdf + - https://web.archive.org/web/20160928154533/http://www.marvell.com/embedded-processors/assets/Armada7040PB-Jan2016.pdf Device tree files: arch/arm64/boot/dts/marvell/armada-70* @@ -214,11 +215,11 @@ EBU Armada family ARMv8 ARM Cortex A72 Homepage: - http://www.marvell.com/embedded-processors/armada-80xx/ + https://web.archive.org/web/20181022004830/http://www.marvell.com/embedded-processors/armada-80xx/ Product Brief: - - http://www.marvell.com/embedded-processors/assets/Armada8020PB-Jan2016.pdf - - http://www.marvell.com/embedded-processors/assets/Armada8040PB-Jan2016.pdf + - https://web.archive.org/web/20210124233728/https://www.marvell.com/content/dam/marvell/en/public-collateral/embedded-processors/marvell-embedded-processors-armada-8020-product-brief-2017-12.pdf + - https://web.archive.org/web/20161010105532/http://www.marvell.com/embedded-processors/assets/Armada8040PB-Jan2016.pdf Device tree files: arch/arm64/boot/dts/marvell/armada-80* @@ -233,10 +234,10 @@ Avanta family - 88F6560 Homepage: - http://www.marvell.com/broadband/ + https://web.archive.org/web/20181005145041/http://www.marvell.com/broadband/ Product Brief: - http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf + https://web.archive.org/web/20180829171057/http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf No public datasheet available. @@ -255,7 +256,7 @@ Storage family - 88RC1580 Product infos: - http://www.marvell.com/storage/armada-sp/ + https://web.archive.org/web/20191129073953/http://www.marvell.com/storage/armada-sp/ Core: Sheeva ARMv7 comatible Quad-core PJ4C @@ -269,16 +270,16 @@ Dove family (application processor) - 88AP510 a.k.a Armada 510 Product Brief: - http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf + https://web.archive.org/web/20111102020643/http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf Hardware Spec: - http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf + https://web.archive.org/web/20160428160231/http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf Functional Spec: - http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf + https://web.archive.org/web/20120130172443/http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf Homepage: - http://www.marvell.com/application-processors/armada-500/ + https://web.archive.org/web/20160822232651/http://www.marvell.com/application-processors/armada-500/ Core: ARMv7 compatible @@ -295,22 +296,22 @@ PXA 2xx/3xx/93x/95x family - Application processor only - Core: ARMv5 XScale1 core - PXA270, PXA271, PXA272 - - Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf - - Design guide : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf - - Developers manual : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf - - Specification : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf - - Specification update : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf + - Product Brief : https://web.archive.org/web/20150927135510/http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf + - Design guide : https://web.archive.org/web/20120111181937/http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf + - Developers manual : https://web.archive.org/web/20150927164805/http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf + - Specification : https://web.archive.org/web/20140211221535/http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf + - Specification update : https://web.archive.org/web/20120111104906/http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf - Application processor only - Core: ARMv5 XScale2 core - PXA300, PXA310, PXA320 - - PXA 300 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf - - PXA 310 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf - - PXA 320 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf - - Design guide : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf - - Developers manual : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip - - Specifications : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf - - Specification Update : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip - - Reference Manual : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf + - PXA 300 Product Brief : https://web.archive.org/web/20120111121203/http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf + - PXA 310 Product Brief : https://web.archive.org/web/20120111104515/http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf + - PXA 320 Product Brief : https://web.archive.org/web/20121021182826/http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf + - Design guide : https://web.archive.org/web/20130727144625/http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf + - Developers manual : https://web.archive.org/web/20130727144605/http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip + - Specifications : https://web.archive.org/web/20130727144559/http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf + - Specification Update : https://web.archive.org/web/20150927183411/http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip + - Reference Manual : https://web.archive.org/web/20120111103844/http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf - Application processor only - Core: ARMv5 XScale3 core - PXA930, PXA935 @@ -341,26 +342,26 @@ MMP/MMP2/MMP3 family (communication processor) Flavors: - PXA168, a.k.a Armada 168 - - Homepage : http://www.marvell.com/application-processors/armada-100/armada-168.jsp - - Product brief : http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf - - Hardware manual : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf - - Software manual : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf - - Specification update : http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf - - Boot ROM manual : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf - - App node package : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf + - Homepage : https://web.archive.org/web/20110926014256/http://www.marvell.com/application-processors/armada-100/armada-168.jsp + - Product brief : https://web.archive.org/web/20111102030100/http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf + - Hardware manual : https://web.archive.org/web/20160428165359/http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf + - Software manual : https://web.archive.org/web/20160428154454/http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf + - Specification update : https://web.archive.org/web/20150927160338/http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf + - Boot ROM manual : https://web.archive.org/web/20130727205559/http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf + - App node package : https://web.archive.org/web/20141005090706/http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf - Application processor only - Core: ARMv5 compatible Marvell PJ1 88sv331 (Mohawk) - PXA910/PXA920 - - Homepage : http://www.marvell.com/communication-processors/pxa910/ - - Product Brief : http://www.marvell.com/communication-processors/pxa910/assets/Marvell_PXA910_Platform-001_PB_final.pdf + - Homepage : https://web.archive.org/web/20150928121236/http://www.marvell.com/communication-processors/pxa910/ + - Product Brief : https://archive.org/download/marvell-pxa910-pb/Marvell_PXA910_Platform-001_PB.pdf - Application processor with Communication processor - Core: ARMv5 compatible Marvell PJ1 88sv331 (Mohawk) - - PXA688, a.k.a. MMP2, a.k.a Armada 610 - - Product Brief : http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf + - PXA688, a.k.a. MMP2, a.k.a Armada 610 (OLPC XO-1.75) + - Product Brief : https://web.archive.org/web/20111102023255/http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf - Application processor only - Core: ARMv7 compatible Sheeva PJ4 88sv581x core - - PXA2128, a.k.a. MMP3 (OLPC XO4, Linux support not upstream) - - Product Brief : http://www.marvell.com/application-processors/armada/pxa2128/assets/Marvell-ARMADA-PXA2128-SoC-PB.pdf + - PXA2128, a.k.a. MMP3, a.k.a Armada 620 (OLPC XO-4) + - Product Brief : https://web.archive.org/web/20120824055155/http://www.marvell.com/application-processors/armada/pxa2128/assets/Marvell-ARMADA-PXA2128-SoC-PB.pdf - Application processor only - Core: Dual-core ARMv7 compatible Sheeva PJ4C core - PXA960/PXA968/PXA978 (Linux support not upstream) diff --git a/Documentation/arm/stm32/stm32h750-overview.rst b/Documentation/arm/stm32/stm32h750-overview.rst new file mode 100644 index 0000000000000000000000000000000000000000..0e51235c95477b85f46cdf9c1e2e254a02a7dd73 --- /dev/null +++ b/Documentation/arm/stm32/stm32h750-overview.rst @@ -0,0 +1,34 @@ +================== +STM32H750 Overview +================== + +Introduction +------------ + +The STM32H750 is a Cortex-M7 MCU aimed at various applications. +It features: + +- Cortex-M7 core running up to @480MHz +- 128K internal flash, 1MBytes internal RAM +- FMC controller to connect SDRAM, NOR and NAND memories +- Dual mode QSPI +- SD/MMC/SDIO support +- Ethernet controller +- USB OTFG FS & HS controllers +- I2C, SPI, CAN busses support +- Several 16 & 32 bits general purpose timers +- Serial Audio interface +- LCD controller +- HDMI-CEC +- SPDIFRX +- DFSDM + +Resources +--------- + +Datasheet and reference manual are publicly available on ST website (STM32H750_). + +.. _STM32H750: https://www.st.com/en/microcontrollers-microprocessors/stm32h750-value-line.html + +:Authors: Dillon Min + diff --git a/Documentation/arm/uefi.rst b/Documentation/arm/uefi.rst index f732f957421ff93da91815ab409b71dad4cd7a73..9b0b5e458a1e609ea2083c76137d850e31fe5f8d 100644 --- a/Documentation/arm/uefi.rst +++ b/Documentation/arm/uefi.rst @@ -64,4 +64,11 @@ linux,uefi-mmap-desc-size 32-bit Size in bytes of each entry in the UEFI memory map. linux,uefi-mmap-desc-ver 32-bit Version of the mmap descriptor format. + +linux,initrd-start 64-bit Physical start address of an initrd + +linux,initrd-end 64-bit Physical end address of an initrd + +kaslr-seed 64-bit Entropy used to randomize the kernel image + base address location. ========================== ====== =========================================== diff --git a/Documentation/arm64/booting.rst b/Documentation/arm64/booting.rst index 7552dbc1cc54c76d9b6ea3b6983d9ee800453d84..4fcc00add117bc55ad958728db2af1407b8fe084 100644 --- a/Documentation/arm64/booting.rst +++ b/Documentation/arm64/booting.rst @@ -202,9 +202,10 @@ Before jumping into the kernel, the following conditions must be met: - System registers - All writable architected system registers at the exception level where - the kernel image will be entered must be initialised by software at a - higher exception level to prevent execution in an UNKNOWN state. + All writable architected system registers at or below the exception + level where the kernel image will be entered must be initialised by + software at a higher exception level to prevent execution in an UNKNOWN + state. - SCR_EL3.FIQ must have the same value across all CPUs the kernel is executing on. @@ -270,6 +271,12 @@ Before jumping into the kernel, the following conditions must be met: having 0b1 set for the corresponding bit for each of the auxiliary counters present. + For CPUs with the Fine Grained Traps (FEAT_FGT) extension present: + + - If EL3 is present and the kernel is entered at EL2: + + - SCR_EL3.FGTEn (bit 27) 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. diff --git a/Documentation/arm64/pointer-authentication.rst b/Documentation/arm64/pointer-authentication.rst index 30b2ab06526b27bdd5f6f59922db85cf8b2939bf..f127666ea3a81659daf3bba59c4c64c38bb6ff20 100644 --- a/Documentation/arm64/pointer-authentication.rst +++ b/Documentation/arm64/pointer-authentication.rst @@ -107,3 +107,37 @@ filter out the Pointer Authentication system key registers from KVM_GET/SET_REG_* ioctls and mask those features from cpufeature ID register. Any attempt to use the Pointer Authentication instructions will result in an UNDEFINED exception being injected into the guest. + + +Enabling and disabling keys +--------------------------- + +The prctl PR_PAC_SET_ENABLED_KEYS allows the user program to control which +PAC keys are enabled in a particular task. It takes two arguments, the +first being a bitmask of PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY +and PR_PAC_APDBKEY specifying which keys shall be affected by this prctl, +and the second being a bitmask of the same bits specifying whether the key +should be enabled or disabled. For example:: + + prctl(PR_PAC_SET_ENABLED_KEYS, + PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY, + PR_PAC_APIBKEY, 0, 0); + +disables all keys except the IB key. + +The main reason why this is useful is to enable a userspace ABI that uses PAC +instructions to sign and authenticate function pointers and other pointers +exposed outside of the function, while still allowing binaries conforming to +the ABI to interoperate with legacy binaries that do not sign or authenticate +pointers. + +The idea is that a dynamic loader or early startup code would issue this +prctl very early after establishing that a process may load legacy binaries, +but before executing any PAC instructions. + +For compatibility with previous kernel versions, processes start up with IA, +IB, DA and DB enabled, and are reset to this state on exec(). Processes created +via fork() and clone() inherit the key enabled state from the calling process. + +It is recommended to avoid disabling the IA key, as this has higher performance +overhead than disabling any of the other keys. diff --git a/Documentation/arm64/tagged-address-abi.rst b/Documentation/arm64/tagged-address-abi.rst index 4a9d9c794ee5d889638d1a3af008dec06d11feaf..cbc4d4500241852d43d1f9fe4bea7729021b49ba 100644 --- a/Documentation/arm64/tagged-address-abi.rst +++ b/Documentation/arm64/tagged-address-abi.rst @@ -40,7 +40,7 @@ space obtained in one of the following ways: during creation and with the same restrictions as for ``mmap()`` above (e.g. data, bss, stack). -The AArch64 Tagged Address ABI has two stages of relaxation depending +The AArch64 Tagged Address ABI has two stages of relaxation depending on how the user addresses are used by the kernel: 1. User addresses not accessed by the kernel but used for address space diff --git a/Documentation/conf.py b/Documentation/conf.py index fd65168c10f84f67d62848f3d420dfa4ca5e6ee1..879e86dbea6679498cf738f28fd0b4f474b18a1e 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -331,27 +331,34 @@ htmlhelp_basename = 'TheLinuxKerneldoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -'papersize': 'a4paper', + # The paper size ('letterpaper' or 'a4paper'). + 'papersize': 'a4paper', -# The font size ('10pt', '11pt' or '12pt'). -'pointsize': '11pt', + # The font size ('10pt', '11pt' or '12pt'). + 'pointsize': '11pt', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + #'figure_align': 'htbp', -# Don't mangle with UTF-8 chars -'inputenc': '', -'utf8extra': '', + # Don't mangle with UTF-8 chars + 'inputenc': '', + 'utf8extra': '', -# Additional stuff for the LaTeX preamble. + # Set document margins + 'sphinxsetup': ''' + hmargin=0.5in, vmargin=1in, + parsedliteralwraps=true, + verbatimhintsturnover=false, + ''', + + # Additional stuff for the LaTeX preamble. 'preamble': ''' - % Use some font with UTF-8 support with XeLaTeX + % Use some font with UTF-8 support with XeLaTeX \\usepackage{fontspec} \\setsansfont{DejaVu Sans} \\setromanfont{DejaVu Serif} \\setmonofont{DejaVu Sans Mono} - ''' + ''', } # At least one book (translations) may have Asian characters diff --git a/Documentation/core-api/rbtree.rst b/Documentation/core-api/rbtree.rst index 6b88837fbf824d0cf327cfc971ca462fc3b94581..ed1a9fbc779e1b9de88e878035abc8e6c9a02078 100644 --- a/Documentation/core-api/rbtree.rst +++ b/Documentation/core-api/rbtree.rst @@ -201,7 +201,7 @@ search trees, such as for traversals or users relying on a the particular order for their own logic. To this end, users can use 'struct rb_root_cached' to optimize O(logN) rb_first() calls to a simple pointer fetch avoiding potentially expensive tree iterations. This is done at negligible runtime -overhead for maintanence; albeit larger memory footprint. +overhead for maintenance; albeit larger memory footprint. Similar to the rb_root structure, cached rbtrees are initialized to be empty via:: diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst new file mode 100644 index 0000000000000000000000000000000000000000..51fed1bd72ec46f3d3ef9501fe4e128f90de627a --- /dev/null +++ b/Documentation/dev-tools/checkpatch.rst @@ -0,0 +1,755 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +========== +Checkpatch +========== + +Checkpatch (scripts/checkpatch.pl) is a perl script which checks for trivial +style violations in patches and optionally corrects them. Checkpatch can +also be run on file contexts and without the kernel tree. + +Checkpatch is not always right. Your judgement takes precedence over checkpatch +messages. If your code looks better with the violations, then its probably +best left alone. + + +Options +======= + +This section will describe the options checkpatch can be run with. + +Usage:: + + ./scripts/checkpatch.pl [OPTION]... [FILE]... + +Available options: + + - -q, --quiet + + Enable quiet mode. + + - -v, --verbose + Enable verbose mode. Additional verbose test descriptions are output + so as to provide information on why that particular message is shown. + + - --no-tree + + Run checkpatch without the kernel tree. + + - --no-signoff + + Disable the 'Signed-off-by' line check. The sign-off is a simple line at + the end of the explanation for the patch, which certifies that you wrote it + or otherwise have the right to pass it on as an open-source patch. + + Example:: + + Signed-off-by: Random J Developer + + Setting this flag effectively stops a message for a missing signed-off-by + line in a patch context. + + - --patch + + Treat FILE as a patch. This is the default option and need not be + explicitly specified. + + - --emacs + + Set output to emacs compile window format. This allows emacs users to jump + from the error in the compile window directly to the offending line in the + patch. + + - --terse + + Output only one line per report. + + - --showfile + + Show the diffed file position instead of the input file position. + + - -g, --git + + Treat FILE as a single commit or a git revision range. + + Single commit with: + + - + - ^ + - ~n + + Multiple commits with: + + - .. + - ... + - - + + - -f, --file + + Treat FILE as a regular source file. This option must be used when running + checkpatch on source files in the kernel. + + - --subjective, --strict + + Enable stricter tests in checkpatch. By default the tests emitted as CHECK + do not activate by default. Use this flag to activate the CHECK tests. + + - --list-types + + Every message emitted by checkpatch has an associated TYPE. Add this flag + to display all the types in checkpatch. + + Note that when this flag is active, checkpatch does not read the input FILE, + and no message is emitted. Only a list of types in checkpatch is output. + + - --types TYPE(,TYPE2...) + + Only display messages with the given types. + + Example:: + + ./scripts/checkpatch.pl mypatch.patch --types EMAIL_SUBJECT,BRACES + + - --ignore TYPE(,TYPE2...) + + Checkpatch will not emit messages for the specified types. + + Example:: + + ./scripts/checkpatch.pl mypatch.patch --ignore EMAIL_SUBJECT,BRACES + + - --show-types + + By default checkpatch doesn't display the type associated with the messages. + Set this flag to show the message type in the output. + + - --max-line-length=n + + Set the max line length (default 100). If a line exceeds the specified + length, a LONG_LINE message is emitted. + + + The message level is different for patch and file contexts. For patches, + a WARNING is emitted. While a milder CHECK is emitted for files. So for + file contexts, the --strict flag must also be enabled. + + - --min-conf-desc-length=n + + Set the Kconfig entry minimum description length, if shorter, warn. + + - --tab-size=n + + Set the number of spaces for tab (default 8). + + - --root=PATH + + PATH to the kernel tree root. + + This option must be specified when invoking checkpatch from outside + the kernel root. + + - --no-summary + + Suppress the per file summary. + + - --mailback + + Only produce a report in case of Warnings or Errors. Milder Checks are + excluded from this. + + - --summary-file + + Include the filename in summary. + + - --debug KEY=[0|1] + + Turn on/off debugging of KEY, where KEY is one of 'values', 'possible', + 'type', and 'attr' (default is all off). + + - --fix + + This is an EXPERIMENTAL feature. If correctable errors exists, a file + .EXPERIMENTAL-checkpatch-fixes is created which has the + automatically fixable errors corrected. + + - --fix-inplace + + EXPERIMENTAL - Similar to --fix but input file is overwritten with fixes. + + DO NOT USE this flag unless you are absolutely sure and you have a backup + in place. + + - --ignore-perl-version + + Override checking of perl version. Runtime errors maybe encountered after + enabling this flag if the perl version does not meet the minimum specified. + + - --codespell + + Use the codespell dictionary for checking spelling errors. + + - --codespellfile + + Use the specified codespell file. + Default is '/usr/share/codespell/dictionary.txt'. + + - --typedefsfile + + Read additional types from this file. + + - --color[=WHEN] + + Use colors 'always', 'never', or only when output is a terminal ('auto'). + Default is 'auto'. + + - --kconfig-prefix=WORD + + Use WORD as a prefix for Kconfig symbols (default is `CONFIG_`). + + - -h, --help, --version + + Display the help text. + +Message Levels +============== + +Messages in checkpatch are divided into three levels. The levels of messages +in checkpatch denote the severity of the error. They are: + + - ERROR + + This is the most strict level. Messages of type ERROR must be taken + seriously as they denote things that are very likely to be wrong. + + - WARNING + + This is the next stricter level. Messages of type WARNING requires a + more careful review. But it is milder than an ERROR. + + - CHECK + + This is the mildest level. These are things which may require some thought. + +Type Descriptions +================= + +This section contains a description of all the message types in checkpatch. + +.. Types in this section are also parsed by checkpatch. +.. The types are grouped into subsections based on use. + + +Allocation style +---------------- + + **ALLOC_ARRAY_ARGS** + The first argument for kcalloc or kmalloc_array should be the + number of elements. sizeof() as the first argument is generally + wrong. + See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html + + **ALLOC_SIZEOF_STRUCT** + The allocation style is bad. In general for family of + allocation functions using sizeof() to get memory size, + constructs like:: + + p = alloc(sizeof(struct foo), ...) + + should be:: + + p = alloc(sizeof(*p), ...) + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#allocating-memory + + **ALLOC_WITH_MULTIPLY** + Prefer kmalloc_array/kcalloc over kmalloc/kzalloc with a + sizeof multiply. + See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html + + +API usage +--------- + + **ARCH_DEFINES** + Architecture specific defines should be avoided wherever + possible. + + **ARCH_INCLUDE_LINUX** + Whenever asm/file.h is included and linux/file.h exists, a + conversion can be made when linux/file.h includes asm/file.h. + However this is not always the case (See signal.h). + This message type is emitted only for includes from arch/. + + **AVOID_BUG** + BUG() or BUG_ON() should be avoided totally. + Use WARN() and WARN_ON() instead, and handle the "impossible" + error condition as gracefully as possible. + See: https://www.kernel.org/doc/html/latest/process/deprecated.html#bug-and-bug-on + + **CONSIDER_KSTRTO** + The simple_strtol(), simple_strtoll(), simple_strtoul(), and + simple_strtoull() functions explicitly ignore overflows, which + may lead to unexpected results in callers. The respective kstrtol(), + kstrtoll(), kstrtoul(), and kstrtoull() functions tend to be the + correct replacements. + See: https://www.kernel.org/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull + + **LOCKDEP** + The lockdep_no_validate class was added as a temporary measure to + prevent warnings on conversion of device->sem to device->mutex. + It should not be used for any other purpose. + See: https://lore.kernel.org/lkml/1268959062.9440.467.camel@laptop/ + + **MALFORMED_INCLUDE** + The #include statement has a malformed path. This has happened + because the author has included a double slash "//" in the pathname + accidentally. + + **USE_LOCKDEP** + lockdep_assert_held() annotations should be preferred over + assertions based on spin_is_locked() + See: https://www.kernel.org/doc/html/latest/locking/lockdep-design.html#annotations + + **UAPI_INCLUDE** + No #include statements in include/uapi should use a uapi/ path. + + +Comment style +------------- + + **BLOCK_COMMENT_STYLE** + The comment style is incorrect. The preferred style for multi- + line comments is:: + + /* + * This is the preferred style + * for multi line comments. + */ + + The networking comment style is a bit different, with the first line + not empty like the former:: + + /* This is the preferred comment style + * for files in net/ and drivers/net/ + */ + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting + + **C99_COMMENTS** + C99 style single line comments (//) should not be used. + Prefer the block comment style instead. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting + + +Commit message +-------------- + + **BAD_SIGN_OFF** + The signed-off-by line does not fall in line with the standards + specified by the community. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1 + + **BAD_STABLE_ADDRESS_STYLE** + The email format for stable is incorrect. + Some valid options for stable address are:: + + 1. stable@vger.kernel.org + 2. stable@kernel.org + + For adding version info, the following comment style should be used:: + + stable@vger.kernel.org # version info + + **COMMIT_COMMENT_SYMBOL** + Commit log lines starting with a '#' are ignored by git as + comments. To solve this problem addition of a single space + infront of the log line is enough. + + **COMMIT_MESSAGE** + The patch is missing a commit description. A brief + description of the changes made by the patch should be added. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + + **MISSING_SIGN_OFF** + The patch is missing a Signed-off-by line. A signed-off-by + line should be added according to Developer's certificate of + Origin. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin + + **NO_AUTHOR_SIGN_OFF** + The author of the patch has not signed off the patch. It is + required that a simple sign off line should be present at the + end of explanation of the patch to denote that the author has + written it or otherwise has the rights to pass it on as an open + source patch. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin + + **DIFF_IN_COMMIT_MSG** + Avoid having diff content in commit message. + This causes problems when one tries to apply a file containing both + the changelog and the diff because patch(1) tries to apply the diff + which it found in the changelog. + See: https://lore.kernel.org/lkml/20150611134006.9df79a893e3636019ad2759e@linux-foundation.org/ + + **GERRIT_CHANGE_ID** + To be picked up by gerrit, the footer of the commit message might + have a Change-Id like:: + + Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b + Signed-off-by: A. U. Thor + + The Change-Id line must be removed before submitting. + + **GIT_COMMIT_ID** + The proper way to reference a commit id is: + commit <12+ chars of sha1> ("") + + An example may be:: + + Commit e21d2170f36602ae2708 ("video: remove unnecessary + platform_set_drvdata()") removed the unnecessary + platform_set_drvdata(), but left the variable "dev" unused, + delete it. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + + +Comparison style +---------------- + + **ASSIGN_IN_IF** + Do not use assignments in if condition. + Example:: + + if ((foo = bar(...)) < BAZ) { + + should be written as:: + + foo = bar(...); + if (foo < BAZ) { + + **BOOL_COMPARISON** + Comparisons of A to true and false are better written + as A and !A. + See: https://lore.kernel.org/lkml/1365563834.27174.12.camel@joe-AO722/ + + **COMPARISON_TO_NULL** + Comparisons to NULL in the form (foo == NULL) or (foo != NULL) + are better written as (!foo) and (foo). + + **CONSTANT_COMPARISON** + Comparisons with a constant or upper case identifier on the left + side of the test should be avoided. + + +Macros, Attributes and Symbols +------------------------------ + + **ARRAY_SIZE** + The ARRAY_SIZE(foo) macro should be preferred over + sizeof(foo)/sizeof(foo[0]) for finding number of elements in an + array. + + The macro is defined in include/linux/kernel.h:: + + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + **AVOID_EXTERNS** + Function prototypes don't need to be declared extern in .h + files. It's assumed by the compiler and is unnecessary. + + **AVOID_L_PREFIX** + Local symbol names that are prefixed with `.L` should be avoided, + as this has special meaning for the assembler; a symbol entry will + not be emitted into the symbol table. This can prevent `objtool` + from generating correct unwind info. + + Symbols with STB_LOCAL binding may still be used, and `.L` prefixed + local symbol names are still generally usable within a function, + but `.L` prefixed local symbol names should not be used to denote + the beginning or end of code regions via + `SYM_CODE_START_LOCAL`/`SYM_CODE_END` + + **BIT_MACRO** + Defines like: 1 << <digit> could be BIT(digit). + The BIT() macro is defined in include/linux/bitops.h:: + + #define BIT(nr) (1UL << (nr)) + + **CONST_READ_MOSTLY** + When a variable is tagged with the __read_mostly annotation, it is a + signal to the compiler that accesses to the variable will be mostly + reads and rarely(but NOT never) a write. + + const __read_mostly does not make any sense as const data is already + read-only. The __read_mostly annotation thus should be removed. + + **DATE_TIME** + It is generally desirable that building the same source code with + the same set of tools is reproducible, i.e. the output is always + exactly the same. + + The kernel does *not* use the ``__DATE__`` and ``__TIME__`` macros, + and enables warnings if they are used as they can lead to + non-deterministic builds. + See: https://www.kernel.org/doc/html/latest/kbuild/reproducible-builds.html#timestamps + + **DEFINE_ARCH_HAS** + The ARCH_HAS_xyz and ARCH_HAVE_xyz patterns are wrong. + + For big conceptual features use Kconfig symbols instead. And for + smaller things where we have compatibility fallback functions but + want architectures able to override them with optimized ones, we + should either use weak functions (appropriate for some cases), or + the symbol that protects them should be the same symbol we use. + See: https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/ + + **INIT_ATTRIBUTE** + Const init definitions should use __initconst instead of + __initdata. + + Similarly init definitions without const require a separate + use of const. + + **INLINE_LOCATION** + The inline keyword should sit between storage class and type. + + For example, the following segment:: + + inline static int example_function(void) + { + ... + } + + should be:: + + static inline int example_function(void) + { + ... + } + + **MULTISTATEMENT_MACRO_USE_DO_WHILE** + Macros with multiple statements should be enclosed in a + do - while block. Same should also be the case for macros + starting with `if` to avoid logic defects:: + + #define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + do_this(b, c); \ + } while (0) + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl + + **WEAK_DECLARATION** + Using weak declarations like __attribute__((weak)) or __weak + can have unintended link defects. Avoid using them. + + +Functions and Variables +----------------------- + + **CAMELCASE** + Avoid CamelCase Identifiers. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#naming + + **FUNCTION_WITHOUT_ARGS** + Function declarations without arguments like:: + + int foo() + + should be:: + + int foo(void) + + **GLOBAL_INITIALISERS** + Global variables should not be initialized explicitly to + 0 (or NULL, false, etc.). Your compiler (or rather your + loader, which is responsible for zeroing out the relevant + sections) automatically does it for you. + + **INITIALISED_STATIC** + Static variables should not be initialized explicitly to zero. + Your compiler (or rather your loader) automatically does + it for you. + + **RETURN_PARENTHESES** + return is not a function and as such doesn't need parentheses:: + + return (bar); + + can simply be:: + + return bar; + + +Spacing and Brackets +-------------------- + + **ASSIGNMENT_CONTINUATIONS** + Assignment operators should not be written at the start of a + line but should follow the operand at the previous line. + + **BRACES** + The placement of braces is stylistically incorrect. + The preferred way is to put the opening brace last on the line, + and put the closing brace first:: + + if (x is true) { + we do y + } + + This applies for all non-functional blocks. + However, there is one special case, namely functions: they have the + opening brace at the beginning of the next line, thus:: + + int function(int x) + { + body of function + } + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + **BRACKET_SPACE** + Whitespace before opening bracket '[' is prohibited. + There are some exceptions: + + 1. With a type on the left:: + + ;int [] a; + + 2. At the beginning of a line for slice initialisers:: + + [0...10] = 5, + + 3. Inside a curly brace:: + + = { [0...10] = 5 } + + **CODE_INDENT** + Code indent should use tabs instead of spaces. + Outside of comments, documentation and Kconfig, + spaces are never used for indentation. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation + + **CONCATENATED_STRING** + Concatenated elements should have a space in between. + Example:: + + printk(KERN_INFO"bar"); + + should be:: + + printk(KERN_INFO "bar"); + + **ELSE_AFTER_BRACE** + `else {` should follow the closing block `}` on the same line. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + **LINE_SPACING** + Vertical space is wasted given the limited number of lines an + editor window can display when multiple blank lines are used. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **OPEN_BRACE** + The opening brace should be following the function definitions on the + next line. For any non-functional block it should be on the same line + as the last construct. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + **POINTER_LOCATION** + When using pointer data or a function that returns a pointer type, + the preferred use of * is adjacent to the data name or function name + and not adjacent to the type name. + Examples:: + + char *linux_banner; + unsigned long long memparse(char *ptr, char **retptr); + char *match_strdup(substring_t *s); + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **SPACING** + Whitespace style used in the kernel sources is described in kernel docs. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **SWITCH_CASE_INDENT_LEVEL** + switch should be at the same indent as case. + Example:: + + switch (suffix) { + case 'G': + case 'g': + mem <<= 30; + break; + case 'M': + case 'm': + mem <<= 20; + break; + case 'K': + case 'k': + mem <<= 10; + /* fall through */ + default: + break; + } + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation + + **TRAILING_WHITESPACE** + Trailing whitespace should always be removed. + Some editors highlight the trailing whitespace and cause visual + distractions when editing files. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **WHILE_AFTER_BRACE** + while should follow the closing bracket on the same line:: + + do { + ... + } while(something); + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + +Others +------ + + **CONFIG_DESCRIPTION** + Kconfig symbols should have a help text which fully describes + it. + + **CORRUPTED_PATCH** + The patch seems to be corrupted or lines are wrapped. + Please regenerate the patch file before sending it to the maintainer. + + **DOS_LINE_ENDINGS** + For DOS-formatted patches, there are extra ^M symbols at the end of + the line. These should be removed. + + **EXECUTE_PERMISSIONS** + There is no reason for source files to be executable. The executable + bit can be removed safely. + + **NON_OCTAL_PERMISSIONS** + Permission bits should use 4 digit octal permissions (like 0700 or 0444). + Avoid using any other base like decimal. + + **NOT_UNIFIED_DIFF** + The patch file does not appear to be in unified-diff format. Please + regenerate the patch file before sending it to the maintainer. + + **PRINTF_0XDECIMAL** + Prefixing 0x with decimal output is defective and should be corrected. + + **TRAILING_STATEMENTS** + Trailing statements (for example after any conditional) should be + on the next line. + Like:: + + if (x == y) break; + + should be:: + + if (x == y) + break; diff --git a/Documentation/dev-tools/gcov.rst b/Documentation/dev-tools/gcov.rst index 9e989baae1547ad51a09796fe28c6ad35e77b372..5fce2b06f22954c3ac6e7d7118064f015624c4a9 100644 --- a/Documentation/dev-tools/gcov.rst +++ b/Documentation/dev-tools/gcov.rst @@ -124,6 +124,8 @@ box for setups where kernels are built and run on the same machine. In cases where the kernel runs on a separate machine, special preparations must be made, depending on where the gcov tool is used: +.. _gcov-test: + a) gcov is run on the TEST machine The gcov tool version on the test machine must be compatible with the @@ -143,6 +145,8 @@ a) gcov is run on the TEST machine machine. If any of the path components is symbolic link, the actual directory needs to be used instead (due to make's CURDIR handling). +.. _gcov-build: + b) gcov is run on the BUILD machine The following files need to be copied after each test case from test @@ -211,7 +215,7 @@ Appendix A: gather_on_build.sh ------------------------------ Sample script to gather coverage meta files on the build machine -(see 6a): +(see :ref:`Separated build and test machines a. <gcov-test>`): .. code-block:: sh @@ -244,7 +248,7 @@ Appendix B: gather_on_test.sh ----------------------------- Sample script to gather coverage data files on the test machine -(see 6b): +(see :ref:`Separated build and test machines b. <gcov-build>`): .. code-block:: sh diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index 1b1cf4f5c9d9038efca1243a78fe47035864f1b1..010a2af1e7d9ebffa59f39481ff620bff6552746 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -7,6 +7,9 @@ be used to work on the kernel. For now, the documents have been pulled together without any significant effort to integrate them into a coherent whole; patches welcome! +A brief overview of testing-specific tools can be found in +Documentation/dev-tools/testing-overview.rst + .. class:: toc-title Table of contents @@ -14,6 +17,8 @@ whole; patches welcome! .. toctree:: :maxdepth: 2 + testing-overview + checkpatch coccinelle sparse kcov diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index ddfe053afda6a41e34f25251460ecdcea1c5cbac..d248668d9a85afe9e4741aa4333c0339bc16f8b7 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -161,6 +161,15 @@ particular KASAN features. - ``kasan=off`` or ``=on`` controls whether KASAN is enabled (default: ``on``). +- ``kasan.mode=sync`` or ``=async`` controls whether KASAN is configured in + synchronous or asynchronous mode of execution (default: ``sync``). + Synchronous mode: a bad access is detected immediately when a tag + check fault occurs. + Asynchronous mode: a bad access detection is delayed. When a tag check + fault occurs, the information is stored in hardware (in the TFSR_EL1 + register for arm64). The kernel periodically checks the hardware and + only reports tag faults during these checks. + - ``kasan.stacktrace=off`` or ``=on`` disables or enables alloc and free stack traces collection (default: ``on``). diff --git a/Documentation/dev-tools/testing-overview.rst b/Documentation/dev-tools/testing-overview.rst new file mode 100644 index 0000000000000000000000000000000000000000..b5b46709969ce97611c905a98c96c7c724725a50 --- /dev/null +++ b/Documentation/dev-tools/testing-overview.rst @@ -0,0 +1,117 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================== +Kernel Testing Guide +==================== + + +There are a number of different tools for testing the Linux kernel, so knowing +when to use each of them can be a challenge. This document provides a rough +overview of their differences, and how they fit together. + + +Writing and Running Tests +========================= + +The bulk of kernel tests are written using either the kselftest or KUnit +frameworks. These both provide infrastructure to help make running tests and +groups of tests easier, as well as providing helpers to aid in writing new +tests. + +If you're looking to verify the behaviour of the Kernel — particularly specific +parts of the kernel — then you'll want to use KUnit or kselftest. + + +The Difference Between KUnit and kselftest +------------------------------------------ + +KUnit (Documentation/dev-tools/kunit/index.rst) is an entirely in-kernel system +for "white box" testing: because test code is part of the kernel, it can access +internal structures and functions which aren't exposed to userspace. + +KUnit tests therefore are best written against small, self-contained parts +of the kernel, which can be tested in isolation. This aligns well with the +concept of 'unit' testing. + +For example, a KUnit test might test an individual kernel function (or even a +single codepath through a function, such as an error handling case), rather +than a feature as a whole. + +This also makes KUnit tests very fast to build and run, allowing them to be +run frequently as part of the development process. + +There is a KUnit test style guide which may give further pointers in +Documentation/dev-tools/kunit/style.rst + + +kselftest (Documentation/dev-tools/kselftest.rst), on the other hand, is +largely implemented in userspace, and tests are normal userspace scripts or +programs. + +This makes it easier to write more complicated tests, or tests which need to +manipulate the overall system state more (e.g., spawning processes, etc.). +However, it's not possible to call kernel functions directly from kselftest. +This means that only kernel functionality which is exposed to userspace somehow +(e.g. by a syscall, device, filesystem, etc.) can be tested with kselftest. To +work around this, some tests include a companion kernel module which exposes +more information or functionality. If a test runs mostly or entirely within the +kernel, however, KUnit may be the more appropriate tool. + +kselftest is therefore suited well to tests of whole features, as these will +expose an interface to userspace, which can be tested, but not implementation +details. This aligns well with 'system' or 'end-to-end' testing. + +For example, all new system calls should be accompanied by kselftest tests. + +Code Coverage Tools +=================== + +The Linux Kernel supports two different code coverage measurement tools. These +can be used to verify that a test is executing particular functions or lines +of code. This is useful for determining how much of the kernel is being tested, +and for finding corner-cases which are not covered by the appropriate test. + +:doc:`gcov` is GCC's coverage testing tool, which can be used with the kernel +to get global or per-module coverage. Unlike KCOV, it does not record per-task +coverage. Coverage data can be read from debugfs, and interpreted using the +usual gcov tooling. + +:doc:`kcov` is a feature which can be built in to the kernel to allow +capturing coverage on a per-task level. It's therefore useful for fuzzing and +other situations where information about code executed during, for example, a +single syscall is useful. + + +Dynamic Analysis Tools +====================== + +The kernel also supports a number of dynamic analysis tools, which attempt to +detect classes of issues when they occur in a running kernel. These typically +each look for a different class of bugs, such as invalid memory accesses, +concurrency issues such as data races, or other undefined behaviour like +integer overflows. + +Some of these tools are listed below: + +* kmemleak detects possible memory leaks. See + Documentation/dev-tools/kmemleak.rst +* KASAN detects invalid memory accesses such as out-of-bounds and + use-after-free errors. See Documentation/dev-tools/kasan.rst +* UBSAN detects behaviour that is undefined by the C standard, like integer + overflows. See Documentation/dev-tools/ubsan.rst +* KCSAN detects data races. See Documentation/dev-tools/kcsan.rst +* KFENCE is a low-overhead detector of memory issues, which is much faster than + KASAN and can be used in production. See Documentation/dev-tools/kfence.rst +* lockdep is a locking correctness validator. See + Documentation/locking/lockdep-design.rst +* There are several other pieces of debug instrumentation in the kernel, many + of which can be found in lib/Kconfig.debug + +These tools tend to test the kernel as a whole, and do not "pass" like +kselftest or KUnit tests. They can be combined with KUnit or kselftest by +running tests on a kernel with these tools enabled: you can then be sure +that none of these errors are occurring during the test. + +Some of these tools integrate with KUnit or kselftest and will +automatically fail tests if an issue is detected. + diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index 5f6769bf45bd9f31723b997d45b1806f2f69a18a..97fb9626634435d73314d91b285e6ebba66a4da1 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -109,6 +109,7 @@ properties: - libretech,aml-s905d-pc - phicomm,n1 - smartlabs,sml5442tw + - videostrong,gxl-kii-pro - const: amlogic,s905d - const: amlogic,meson-gxl @@ -120,8 +121,10 @@ properties: - khadas,vim2 - kingnovel,r-box-pro - libretech,aml-s912-pc + - minix,neo-u9h - nexbox,a1 - tronsmart,vega-s96 + - videostrong,gxm-kiii-pro - wetek,core2 - const: amlogic,s912 - const: amlogic,meson-gxm diff --git a/Documentation/devicetree/bindings/arm/apple.yaml b/Documentation/devicetree/bindings/arm/apple.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1e772c85206c01347a2be88568587abbbd2c881b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/apple.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/apple.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple ARM Machine Device Tree Bindings + +maintainers: + - Hector Martin <marcan@marcan.st> + +description: | + ARM platforms using SoCs designed by Apple Inc., branded "Apple Silicon". + + This currently includes devices based on the "M1" SoC, starting with the + three Mac models released in late 2020: + + - Mac mini (M1, 2020) + - MacBook Pro (13-inch, M1, 2020) + - MacBook Air (M1, 2020) + + The compatible property should follow this format: + + compatible = "apple,<targettype>", "apple,<socid>", "apple,arm-platform"; + + <targettype> represents the board/device and comes from the `target-type` + property of the root node of the Apple Device Tree, lowercased. It can be + queried on macOS using the following command: + + $ ioreg -d2 -l | grep target-type + + <socid> is the lowercased SoC ID. Apple uses at least *five* different + names for their SoCs: + + - Marketing name ("M1") + - Internal name ("H13G") + - Codename ("Tonga") + - SoC ID ("T8103") + - Package/IC part number ("APL1102") + + Devicetrees should use the lowercased SoC ID, to avoid confusion if + multiple SoCs share the same marketing name. This can be obtained from + the `compatible` property of the arm-io node of the Apple Device Tree, + which can be queried as follows on macOS: + + $ ioreg -n arm-io | grep compatible + +properties: + $nodename: + const: "/" + compatible: + oneOf: + - description: Apple M1 SoC based platforms + items: + - enum: + - apple,j274 # Mac mini (M1, 2020) + - apple,j293 # MacBook Pro (13-inch, M1, 2020) + - apple,j313 # MacBook Air (M1, 2020) + - const: apple,t8103 + - const: apple,arm-platform + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4908.yaml b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4908.yaml index e55731f43c845c347fbab538b8b788819ef3b8ae..2cd4e4a32278b6dd3f34e4b2dcc7f5c17e019970 100644 --- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4908.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4908.yaml @@ -21,6 +21,7 @@ properties: items: - enum: - netgear,r8000p + - tplink,archer-c2300-v1 - const: brcm,bcm4906 - const: brcm,bcm4908 diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index a2c63c8b1d10bfea6bff9e3dd4d1bcb1c7e2e7e5..e3664eab0f6a9b87a7729175f38ce04a55eae876 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -64,6 +64,21 @@ properties: - compatible - "#reset-cells" + pwm: + type: object + + properties: + compatible: + const: raspberrypi,firmware-poe-pwm + + "#pwm-cells": + # See pwm.yaml in this directory for a description of the cells format. + const: 2 + + required: + - compatible + - "#pwm-cells" + additionalProperties: false required: @@ -87,5 +102,10 @@ examples: compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + pwm: pwm { + compatible = "raspberrypi,firmware-poe-pwm"; + #pwm-cells = <2>; + }; }; ... diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 26b886b20b27bb394cf3e489f1990a2ed7b0d7c3..c299423dc7cb9f9e78f699a84cc92eac67b07e79 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -85,6 +85,8 @@ properties: compatible: enum: + - apple,icestorm + - apple,firestorm - arm,arm710t - arm,arm720t - arm,arm740t diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index 297c87f45db845cc13d144d0f864bffb618d7377..e3c50f231d71c00e4221ce6164ef84234290f6a2 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -617,6 +617,7 @@ properties: - kam,imx7d-flex-concentrator # Kamstrup OMNIA Flex Concentrator - kam,imx7d-flex-concentrator-mfg # Kamstrup OMNIA Flex Concentrator in manufacturing mode - novtech,imx7d-meerkat96 # i.MX7 Meerkat96 Board + - remarkable,imx7d-remarkable2 # i.MX7D ReMarkable 2 E-Ink Tablet - technexion,imx7d-pico-dwarf # TechNexion i.MX7D Pico-Dwarf - technexion,imx7d-pico-hobbit # TechNexion i.MX7D Pico-Hobbit - technexion,imx7d-pico-nymph # TechNexion i.MX7D Pico-Nymph @@ -688,6 +689,14 @@ properties: - variscite,var-som-mx8mm # i.MX8MM Variscite VAR-SOM-MX8MM module - const: fsl,imx8mm + - description: Engicam i.Core MX8M Mini SoM based boards + items: + - enum: + - engicam,icore-mx8mm-ctouch2 # i.MX8MM Engicam i.Core MX8M Mini C.TOUCH 2.0 + - engicam,icore-mx8mm-edimm2.2 # i.MX8MM Engicam i.Core MX8M Mini EDIMM2.2 Starter Kit + - const: engicam,icore-mx8mm # i.MX8MM Engicam i.Core MX8M Mini SoM + - const: fsl,imx8mm + - description: Kontron BL i.MX8MM (N801X S) Board items: - const: kontron,imx8mm-n801x-s @@ -733,6 +742,7 @@ properties: - einfochips,imx8mq-thor96 # i.MX8MQ Thor96 Board - fsl,imx8mq-evk # i.MX8MQ EVK Board - google,imx8mq-phanbell # Google Coral Edge TPU + - kontron,pitx-imx8m # Kontron pITX-imx8m Board - purism,librem5-devkit # Purism Librem5 devkit - solidrun,hummingboard-pulse # SolidRun Hummingboard Pulse - technexion,pico-pi-imx8m # TechNexion PICO-PI-8M evk @@ -755,6 +765,12 @@ properties: - const: zii,imx8mq-ultra - const: fsl,imx8mq + - description: i.MX8QM based Boards + items: + - enum: + - fsl,imx8qm-mek # i.MX8QM MEK Board + - const: fsl,imx8qm + - description: i.MX8QXP based Boards items: - enum: diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml index 93b3bdf6eaeb7539ba94e228afec7a90c5140b44..aff57a8c8c30bfbe291b8d199f0a9186ced197c2 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek.yaml @@ -118,6 +118,10 @@ properties: - enum: - mediatek,mt8183-evb - const: mediatek,mt8183 + - items: + - enum: + - mediatek,mt8195-evb + - const: mediatek,mt8195 - description: Google Krane (Lenovo IdeaPad Duet, 10e,...) items: - enum: @@ -125,6 +129,38 @@ properties: - google,krane-sku176 - const: google,krane - const: mediatek,mt8183 + - description: Google Damu (ASUS Chromebook Flip CM3) + items: + - const: google,damu + - const: mediatek,mt8183 + - description: Google Juniper (Acer Chromebook Spin 311) + items: + - const: google,juniper-sku16 + - const: google,juniper + - const: mediatek,mt8183 + - description: Google Kakadu (ASUS Chromebook Detachable CM3) + items: + - const: google,kakadu-rev3 + - const: google,kakadu-rev2 + - const: google,kakadu + - const: mediatek,mt8183 + - description: Google Kodama (Lenovo 10e Chromebook Tablet) + items: + - enum: + - google,kodama-sku16 + - google,kodama-sku272 + - google,kodama-sku288 + - google,kodama-sku32 + - const: google,kodama + - const: mediatek,mt8183 + - items: + - enum: + - mediatek,mt8183-pumpkin + - const: mediatek,mt8183 + - items: + - enum: + - mediatek,mt8516-pumpkin + - const: mediatek,mt8516 additionalProperties: true diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt index d8c9108c3b4a44915362a92784c196c7c95ffd1e..78c50733985c1613116e48fa897a14e9e1a29725 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt @@ -13,6 +13,7 @@ Required Properties: - "mediatek,mt6779-mmsys", "syscon" - "mediatek,mt6797-mmsys", "syscon" - "mediatek,mt7623-mmsys", "mediatek,mt2701-mmsys", "syscon" + - "mediatek,mt8167-mmsys", "syscon" - "mediatek,mt8173-mmsys", "syscon" - "mediatek,mt8183-mmsys", "syscon" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml index c299dc907f6c132365c8bdab1f710c5a1f67bc03..62fcbd88339232139b6c1aaeefd35bc309d18f17 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml @@ -22,6 +22,7 @@ properties: compatible: enum: - qcom,sc7180-llcc + - qcom,sc7280-llcc - qcom,sdm845-llcc - qcom,sm8150-llcc - qcom,sm8250-llcc diff --git a/Documentation/devicetree/bindings/arm/mstar/mstar.yaml b/Documentation/devicetree/bindings/arm/mstar/mstar.yaml index 61d08c473eb858794bb9b754e8117dd6bd292b2b..a316eef1b72826d20ac0d6ca72ff5c3988576b69 100644 --- a/Documentation/devicetree/bindings/arm/mstar/mstar.yaml +++ b/Documentation/devicetree/bindings/arm/mstar/mstar.yaml @@ -24,6 +24,7 @@ properties: items: - enum: - honestar,ssd201htv2 # Honestar SSD201_HT_V2 devkit + - m5stack,unitv2 # M5Stack UnitV2 - const: mstar,infinity2m - description: infinity3 boards diff --git a/Documentation/devicetree/bindings/arm/npcm/npcm.txt b/Documentation/devicetree/bindings/arm/npcm/npcm.txt deleted file mode 100644 index 2d87d9ecea85b67f10f1665f1355fe6cf85d4a2c..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/arm/npcm/npcm.txt +++ /dev/null @@ -1,6 +0,0 @@ -NPCM Platforms Device Tree Bindings ------------------------------------ -NPCM750 SoC -Required root node properties: - - compatible = "nuvoton,npcm750"; - diff --git a/Documentation/devicetree/bindings/arm/npcm/npcm.yaml b/Documentation/devicetree/bindings/arm/npcm/npcm.yaml new file mode 100644 index 0000000000000000000000000000000000000000..95e51378089c9d48cf1a1b70116e07d370786501 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/npcm/npcm.yaml @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/npcm/npcm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NPCM Platforms Device Tree Bindings + +maintainers: + - Jonathan Neuschäfer <j.neuschaefer@gmx.net> + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - description: WPCM450 based boards + items: + - enum: + - supermicro,x9sci-ln4f-bmc # Supermicro X9SCI-LN4F server's BMC + - const: nuvoton,wpcm450 + + - description: NPCM750 based boards + items: + - enum: + - nuvoton,npcm750-evb # NPCM750 evaluation board + - const: nuvoton,npcm750 + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 174134f920e1de97b1c71186a9296a13de1d47ab..9b27e991bddcef70b00c613c57563df67f642b3c 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -37,6 +37,7 @@ description: | msm8994 msm8996 sc7180 + sc7280 sdm630 sdm660 sdm845 @@ -136,6 +137,16 @@ properties: - samsung,a5u-eur - const: qcom,msm8916 + - items: + - enum: + - sony,karin_windy + - sony,karin-row + - sony,satsuki-row + - sony,sumire-row + - sony,suzuran-row + - qcom,msm8994 + - const: qcom,apq8094 + - items: - const: qcom,msm8996-mtp @@ -164,6 +175,11 @@ properties: - qcom,sc7180-idp - const: qcom,sc7180 + - items: + - enum: + - qcom,sc7280-idp + - const: qcom,sc7280 + - items: - enum: - xiaomi,lavender @@ -172,10 +188,13 @@ properties: - items: - enum: - qcom,sdx55-mtp + - qcom,sdx55-telit-fn980-tlb + - qcom,sdx55-t55 - const: qcom,sdx55 - items: - enum: + - qcom,ipq6018-cp01 - qcom,ipq6018-cp01-c1 - const: qcom,ipq6018 @@ -187,6 +206,7 @@ properties: - items: - enum: + - qcom,sm8350-hdk - qcom,sm8350-mtp - const: qcom,sm8350 diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index c3036f95c7bcee1b5d2c9f08a33fe08a0fb81b59..4a6f772c1043855d660d0ba7c4ce306a42148b99 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -134,6 +134,7 @@ properties: - friendlyarm,nanopi-m4 - friendlyarm,nanopi-m4b - friendlyarm,nanopi-neo4 + - friendlyarm,nanopi-r4s - const: rockchip,rk3399 - description: GeekBuying GeekBox diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml index e7525a3395e547f9a1065b0cb6eabe8c9b4c355b..9a77ab74be99a4ae05e590a2de333d8360685d68 100644 --- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml +++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml @@ -51,6 +51,10 @@ properties: - st,stm32h743i-disco - st,stm32h743i-eval - const: st,stm32h743 + - items: + - enum: + - st,stm32h750i-art-pi + - const: st,stm32h750 - items: - enum: - shiratech,stm32mp157a-iot-box # IoT Box @@ -64,6 +68,23 @@ properties: - const: st,stm32mp157c-ev1 - const: st,stm32mp157c-ed1 - const: st,stm32mp157 + + - description: Engicam i.Core STM32MP1 SoM based Boards + items: + - enum: + - engicam,icore-stm32mp1-ctouch2 # STM32MP1 Engicam i.Core STM32MP1 C.TOUCH 2.0 + - engicam,icore-stm32mp1-edimm2.2 # STM32MP1 Engicam i.Core STM32MP1 EDIMM2.2 Starter Kit + - const: engicam,icore-stm32mp1 # STM32MP1 Engicam i.Core STM32MP1 SoM + - const: st,stm32mp157 + + - description: Engicam MicroGEA STM32MP1 SoM based Boards + items: + - enum: + - engicam,microgea-stm32mp1-microdev2.0 + - engicam,microgea-stm32mp1-microdev2.0-of7 + - const: engicam,microgea-stm32mp1 + - const: st,stm32mp157 + - description: Octavo OSD32MP15x System-in-Package based boards items: - enum: diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index 08607c7ec1bfaebe604ee631d376677c8a0a970a..ac750025a2eba1e20478ebc3427a0c47117d6389 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -802,6 +802,11 @@ properties: - const: tbs-biometrics,a711 - const: allwinner,sun8i-a83t + - description: Topwise A721 Tablet + items: + - const: topwise,a721 + - const: allwinner,sun4i-a10 + - description: Utoo P66 items: - const: utoo,p66 diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml index c6e1c1e63e432365ec7e043c37a568a416169aa3..c5aa362e4026647a06f60a10a6a0d3d69d1f9a99 100644 --- a/Documentation/devicetree/bindings/arm/ti/k3.yaml +++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml @@ -23,6 +23,8 @@ properties: items: - enum: - ti,am654-evm + - siemens,iot2050-basic + - siemens,iot2050-advanced - const: ti,am654 - description: K3 J721E SoC @@ -33,6 +35,13 @@ properties: items: - const: ti,j7200 + - description: K3 AM642 SoC + items: + - enum: + - ti,am642-evm + - ti,am642-sk + - const: ti,am642 + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.yaml b/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.yaml index 940486ef1051d10fbbf6c0c70f3aebaa2f5e0ec1..0f6fe365ebf3068f38f59967d8b9a4957b688c86 100644 --- a/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.yaml +++ b/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.yaml @@ -107,8 +107,8 @@ examples: interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>; reg = <0x5b010000 0x10000>; clocks = <&sdhc0_lpcg IMX_LPCG_CLK_4>, - <&sdhc0_lpcg IMX_LPCG_CLK_0>, - <&sdhc0_lpcg IMX_LPCG_CLK_5>; - clock-names = "ipg", "per", "ahb"; + <&sdhc0_lpcg IMX_LPCG_CLK_5>, + <&sdhc0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "ahb", "per"; power-domains = <&pd IMX_SC_R_SDHC_0>; }; diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index b6daedd6251633624ac4676eedefa73d18a385d7..32509b98142e98654f9c4b2eda761696b6fe281d 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -197,6 +197,16 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [1, 2, 3] + slow-charger-loop: + description: Allows PMIC charger loops which are slow(i.e. cannot meet the 15ms deadline) to + still comply to pSnkStby i.e Maximum power that can be consumed by sink while in Sink Standby + state as defined in 7.4.2 Sink Electrical Parameters of USB Power Delivery Specification + Revision 3.0, Version 1.2. When the property is set, the port requests pSnkStby(2.5W - + 5V@500mA) upon entering SNK_DISCOVERY(instead of 3A or the 1.5A, Rp current advertised, during + SNK_DISCOVERY) and the actual currrent limit after reception of PS_Ready for PD link or during + SNK_READY for non-pd link. + type: boolean + required: - compatible diff --git a/Documentation/devicetree/bindings/counter/interrupt-counter.yaml b/Documentation/devicetree/bindings/counter/interrupt-counter.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fd075d104631015dc54da18ff0f59836e7366b40 --- /dev/null +++ b/Documentation/devicetree/bindings/counter/interrupt-counter.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/counter/interrupt-counter.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Interrupt counter + +maintainers: + - Oleksij Rempel <o.rempel@pengutronix.de> + +description: | + A generic interrupt counter to measure interrupt frequency. It was developed + and used for agricultural devices to measure rotation speed of wheels or + other tools. Since the direction of rotation is not important, only one + signal line is needed. + Interrupts or gpios are required. If both are defined, the interrupt will + take precedence for counting interrupts. + +properties: + compatible: + const: interrupt-counter + + interrupts: + maxItems: 1 + + gpios: + maxItems: 1 + +required: + - compatible + +anyOf: + - required: [ interrupts-extended ] + - required: [ interrupts ] + - required: [ gpios ] + +additionalProperties: false + +examples: + - | + + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/gpio/gpio.h> + + counter-0 { + compatible = "interrupt-counter"; + interrupts-extended = <&gpio 0 IRQ_TYPE_EDGE_RISING>; + }; + + counter-1 { + compatible = "interrupt-counter"; + gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; + }; + + counter-2 { + compatible = "interrupt-counter"; + interrupts-extended = <&gpio 2 IRQ_TYPE_EDGE_RISING>; + gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; + }; + +... diff --git a/Documentation/devicetree/bindings/crypto/ti,sa2ul.yaml b/Documentation/devicetree/bindings/crypto/ti,sa2ul.yaml index 1d48ac712b23c0268db1ad961802fc0a37deb6a2..a410d2cedde6317216fa6aa188af8730fc9c66e2 100644 --- a/Documentation/devicetree/bindings/crypto/ti,sa2ul.yaml +++ b/Documentation/devicetree/bindings/crypto/ti,sa2ul.yaml @@ -14,6 +14,7 @@ properties: enum: - ti,j721e-sa2ul - ti,am654-sa2ul + - ti,am64-sa2ul reg: maxItems: 1 @@ -45,6 +46,18 @@ properties: description: Address translation for the possible RNG child node for SA2UL + clocks: + items: + - description: Clock used by PKA + - description: Main Input Clock + - description: Clock used by rng + + clock-names: + items: + - const: pka_in_clk + - const: x1_clk + - const: x2_clk + patternProperties: "^rng@[a-f0-9]+$": type: object @@ -57,7 +70,16 @@ required: - power-domains - dmas - dma-names - - dma-coherent + +if: + properties: + compatible: + enum: + - ti,j721e-sa2ul + - ti,am654-sa2ul +then: + required: + - dma-coherent additionalProperties: false diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt index a10d1f6d85c64ef5443aca1b64ec88425b0e8eff..ac189dd82b08d9a4ab357e1c768320abbeeb1fb8 100644 --- a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt @@ -12,6 +12,8 @@ Required properties: for details. - center-supply: DMC supply node. - status: Marks the node enabled/disabled. +- rockchip,pmu: Phandle to the syscon managing the "PMU general register + files". Optional properties: - interrupts: The CPU interrupt number. The interrupt specifier @@ -77,24 +79,23 @@ Following properties relate to DDR timing: - rockchip,ddr3_drv : When the DRAM type is DDR3, this parameter defines the DRAM side driver strength in ohms. Default - value is DDR3_DS_40ohm. + value is 40. - rockchip,ddr3_odt : When the DRAM type is DDR3, this parameter defines the DRAM side ODT strength in ohms. Default value - is DDR3_ODT_120ohm. + is 120. - rockchip,phy_ddr3_ca_drv : When the DRAM type is DDR3, this parameter defines the phy side CA line (incluing command line, address line and clock line) driver strength. - Default value is PHY_DRV_ODT_40. + Default value is 40. - rockchip,phy_ddr3_dq_drv : When the DRAM type is DDR3, this parameter defines the PHY side DQ line (including DQS/DQ/DM line) - driver strength. Default value is PHY_DRV_ODT_40. + driver strength. Default value is 40. - rockchip,phy_ddr3_odt : When the DRAM type is DDR3, this parameter defines - the PHY side ODT strength. Default value is - PHY_DRV_ODT_240. + the PHY side ODT strength. Default value is 240. - rockchip,lpddr3_odt_dis_freq : When the DRAM type is LPDDR3, this parameter defines then ODT disable frequency in MHz (Mega Hz). @@ -104,25 +105,23 @@ Following properties relate to DDR timing: - rockchip,lpddr3_drv : When the DRAM type is LPDDR3, this parameter defines the DRAM side driver strength in ohms. Default - value is LP3_DS_34ohm. + value is 34. - rockchip,lpddr3_odt : When the DRAM type is LPDDR3, this parameter defines the DRAM side ODT strength in ohms. Default value - is LP3_ODT_240ohm. + is 240. - rockchip,phy_lpddr3_ca_drv : When the DRAM type is LPDDR3, this parameter defines the PHY side CA line (including command line, address line and clock line) driver strength. - Default value is PHY_DRV_ODT_40. + Default value is 40. - rockchip,phy_lpddr3_dq_drv : When the DRAM type is LPDDR3, this parameter defines the PHY side DQ line (including DQS/DQ/DM line) - driver strength. Default value is - PHY_DRV_ODT_40. + driver strength. Default value is 40. - rockchip,phy_lpddr3_odt : When dram type is LPDDR3, this parameter define - the phy side odt strength, default value is - PHY_DRV_ODT_240. + the phy side odt strength, default value is 240. - rockchip,lpddr4_odt_dis_freq : When the DRAM type is LPDDR4, this parameter defines the ODT disable frequency in @@ -132,32 +131,30 @@ Following properties relate to DDR timing: - rockchip,lpddr4_drv : When the DRAM type is LPDDR4, this parameter defines the DRAM side driver strength in ohms. Default - value is LP4_PDDS_60ohm. + value is 60. - rockchip,lpddr4_dq_odt : When the DRAM type is LPDDR4, this parameter defines the DRAM side ODT on DQS/DQ line strength in ohms. - Default value is LP4_DQ_ODT_40ohm. + Default value is 40. - rockchip,lpddr4_ca_odt : When the DRAM type is LPDDR4, this parameter defines the DRAM side ODT on CA line strength in ohms. - Default value is LP4_CA_ODT_40ohm. + Default value is 40. - rockchip,phy_lpddr4_ca_drv : When the DRAM type is LPDDR4, this parameter defines the PHY side CA line (including command address - line) driver strength. Default value is - PHY_DRV_ODT_40. + line) driver strength. Default value is 40. - rockchip,phy_lpddr4_ck_cs_drv : When the DRAM type is LPDDR4, this parameter defines the PHY side clock line and CS line driver - strength. Default value is PHY_DRV_ODT_80. + strength. Default value is 80. - rockchip,phy_lpddr4_dq_drv : When the DRAM type is LPDDR4, this parameter defines the PHY side DQ line (including DQS/DQ/DM line) - driver strength. Default value is PHY_DRV_ODT_80. + driver strength. Default value is 80. - rockchip,phy_lpddr4_odt : When the DRAM type is LPDDR4, this parameter defines - the PHY side ODT strength. Default value is - PHY_DRV_ODT_60. + the PHY side ODT strength. Default value is 60. Example: dmc_opp_table: dmc_opp_table { @@ -193,23 +190,23 @@ Example: rockchip,phy_dll_dis_freq = <125>; rockchip,auto_pd_dis_freq = <666>; rockchip,ddr3_odt_dis_freq = <333>; - rockchip,ddr3_drv = <DDR3_DS_40ohm>; - rockchip,ddr3_odt = <DDR3_ODT_120ohm>; - rockchip,phy_ddr3_ca_drv = <PHY_DRV_ODT_40>; - rockchip,phy_ddr3_dq_drv = <PHY_DRV_ODT_40>; - rockchip,phy_ddr3_odt = <PHY_DRV_ODT_240>; + rockchip,ddr3_drv = <40>; + rockchip,ddr3_odt = <120>; + rockchip,phy_ddr3_ca_drv = <40>; + rockchip,phy_ddr3_dq_drv = <40>; + rockchip,phy_ddr3_odt = <240>; rockchip,lpddr3_odt_dis_freq = <333>; - rockchip,lpddr3_drv = <LP3_DS_34ohm>; - rockchip,lpddr3_odt = <LP3_ODT_240ohm>; - rockchip,phy_lpddr3_ca_drv = <PHY_DRV_ODT_40>; - rockchip,phy_lpddr3_dq_drv = <PHY_DRV_ODT_40>; - rockchip,phy_lpddr3_odt = <PHY_DRV_ODT_240>; + rockchip,lpddr3_drv = <34>; + rockchip,lpddr3_odt = <240>; + rockchip,phy_lpddr3_ca_drv = <40>; + rockchip,phy_lpddr3_dq_drv = <40>; + rockchip,phy_lpddr3_odt = <240>; rockchip,lpddr4_odt_dis_freq = <333>; - rockchip,lpddr4_drv = <LP4_PDDS_60ohm>; - rockchip,lpddr4_dq_odt = <LP4_DQ_ODT_40ohm>; - rockchip,lpddr4_ca_odt = <LP4_CA_ODT_40ohm>; - rockchip,phy_lpddr4_ca_drv = <PHY_DRV_ODT_40>; - rockchip,phy_lpddr4_ck_cs_drv = <PHY_DRV_ODT_80>; - rockchip,phy_lpddr4_dq_drv = <PHY_DRV_ODT_80>; - rockchip,phy_lpddr4_odt = <PHY_DRV_ODT_60>; + rockchip,lpddr4_drv = <60>; + rockchip,lpddr4_dq_odt = <40>; + rockchip,lpddr4_ca_odt = <40>; + rockchip,phy_lpddr4_ca_drv = <40>; + rockchip,phy_lpddr4_ck_cs_drv = <80>; + rockchip,phy_lpddr4_dq_drv = <80>; + rockchip,phy_lpddr4_odt = <60>; }; diff --git a/Documentation/devicetree/bindings/display/simple-framebuffer.yaml b/Documentation/devicetree/bindings/display/simple-framebuffer.yaml index eaf8c54fcf506442e6ee90539b86981d448563fe..c2499a7906f5bc23b399ce8fe70977c53beb94c6 100644 --- a/Documentation/devicetree/bindings/display/simple-framebuffer.yaml +++ b/Documentation/devicetree/bindings/display/simple-framebuffer.yaml @@ -54,6 +54,7 @@ properties: compatible: items: - enum: + - apple,simple-framebuffer - allwinner,simple-framebuffer - amlogic,simple-framebuffer - const: simple-framebuffer @@ -84,9 +85,13 @@ properties: Format of the framebuffer: * `a8b8g8r8` - 32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r * `r5g6b5` - 16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b + * `x2r10g10b10` - 32-bit pixels, d[29:20]=r, d[19:10]=g, d[9:0]=b + * `x8r8g8b8` - 32-bit pixels, d[23:16]=r, d[15:8]=g, d[7:0]=b enum: - a8b8g8r8 - r5g6b5 + - x2r10g10b10 + - x8r8g8b8 display: $ref: /schemas/types.yaml#/definitions/phandle diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt deleted file mode 100644 index 35383adb10f16abd054c2e599fea2fd40b69764f..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt +++ /dev/null @@ -1,41 +0,0 @@ -Qualcomm's PM8941 USB ID Extcon device - -Some Qualcomm PMICs have a "misc" module that can be used to detect when -the USB ID pin has been pulled low or high. - -PROPERTIES - -- compatible: - Usage: required - Value type: <string> - Definition: Should contain "qcom,pm8941-misc"; - -- reg: - Usage: required - Value type: <u32> - Definition: Should contain the offset to the misc address space - -- interrupts: - Usage: required - Value type: <prop-encoded-array> - Definition: Should contain the usb id interrupt - -- interrupt-names: - Usage: required - Value type: <stringlist> - Definition: Should contain the string "usb_id" for the usb id interrupt - -Example: - - pmic { - usb_id: misc@900 { - compatible = "qcom,pm8941-misc"; - reg = <0x900>; - interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "usb_id"; - }; - } - - usb-controller { - extcon = <&usb_id>; - }; diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6a9c96f0352ac3b781a56eefa6c2d282a0483a4a --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/extcon/qcom,pm8941-misc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. PM8941 USB ID Extcon device + +maintainers: + - Guru Das Srinagesh <gurus@codeaurora.org> + +description: | + Some Qualcomm PMICs have a "misc" module that can be used to detect when + the USB ID pin has been pulled low or high. + +properties: + compatible: + items: + - const: qcom,pm8941-misc + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + items: + - const: usb_id + - const: usb_vbus + +required: + - compatible + - reg + - interrupts + - interrupt-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + pmic { + #address-cells = <1>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + usb_id: misc@900 { + compatible = "qcom,pm8941-misc"; + reg = <0x900>; + interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "usb_id"; + }; + }; + + usb-controller { + extcon = <&usb_id>; + }; diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index a884955f861ecf905c57a204be14fc78a46947d9..e747d73687cbe67099b5debba2794ba02e60c9df 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -20,7 +20,9 @@ Required properties: * "qcom,scm-msm8996" * "qcom,scm-msm8998" * "qcom,scm-sc7180" + * "qcom,scm-sc7280" * "qcom,scm-sdm845" + * "qcom,scm-sdx55" * "qcom,scm-sm8150" * "qcom,scm-sm8250" * "qcom,scm-sm8350" diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt b/Documentation/devicetree/bindings/fpga/fpga-region.txt index e811cf8250199b14205787cfdedf8cd6e4aa4df2..d787d57491a1c537786a9d537a9a976c85624e77 100644 --- a/Documentation/devicetree/bindings/fpga/fpga-region.txt +++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt @@ -245,36 +245,31 @@ Base tree contains: Overlay contains: -/dts-v1/ /plugin/; -/ { - fragment@0 { - target = <&fpga_region0>; - #address-cells = <1>; - #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "soc_system.rbf"; - fpga-bridges = <&fpga_bridge1>; - ranges = <0x20000 0xff200000 0x100000>, - <0x0 0xc0000000 0x20000000>; - - gpio@10040 { - compatible = "altr,pio-1.0"; - reg = <0x10040 0x20>; - altr,ngpio = <4>; - #gpio-cells = <2>; - clocks = <2>; - gpio-controller; - }; - - onchip-memory { - device_type = "memory"; - compatible = "altr,onchipmem-15.1"; - reg = <0x0 0x10000>; - }; - }; +/dts-v1/; +/plugin/; + +&fpga_region0 { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "soc_system.rbf"; + fpga-bridges = <&fpga_bridge1>; + ranges = <0x20000 0xff200000 0x100000>, + <0x0 0xc0000000 0x20000000>; + + gpio@10040 { + compatible = "altr,pio-1.0"; + reg = <0x10040 0x20>; + altr,ngpio = <4>; + #gpio-cells = <2>; + clocks = <2>; + gpio-controller; + }; + + onchip-memory { + device_type = "memory"; + compatible = "altr,onchipmem-15.1"; + reg = <0x0 0x10000>; }; }; @@ -371,25 +366,22 @@ Live Device Tree contains: }; DT Overlay contains: -/dts-v1/ /plugin/; -/ { -fragment@0 { - target = <&fpga_region0>; + +/dts-v1/; +/plugin/; + +&fpga_region0 { #address-cells = <1>; #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - firmware-name = "zynq-gpio.bin"; + firmware-name = "zynq-gpio.bin"; - gpio1: gpio@40000000 { - compatible = "xlnx,xps-gpio-1.00.a"; - reg = <0x40000000 0x10000>; - gpio-controller; - #gpio-cells = <0x2>; - xlnx,gpio-width= <0x6>; - }; + gpio1: gpio@40000000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0x40000000 0x10000>; + gpio-controller; + #gpio-cells = <0x2>; + xlnx,gpio-width= <0x6>; }; }; @@ -402,41 +394,37 @@ This example programs the FPGA to have two regions that can later be partially configured. Each region has its own bridge in the FPGA fabric. DT Overlay contains: -/dts-v1/ /plugin/; -/ { - fragment@0 { - target = <&fpga_region0>; - #address-cells = <1>; - #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "base.rbf"; - - fpga-bridge@4400 { - compatible = "altr,freeze-bridge-controller"; - reg = <0x4400 0x10>; - - fpga_region1: fpga-region1 { - compatible = "fpga-region"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - }; - - fpga-bridge@4420 { - compatible = "altr,freeze-bridge-controller"; - reg = <0x4420 0x10>; - - fpga_region2: fpga-region2 { - compatible = "fpga-region"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - }; + +/dts-v1/; +/plugin/; + +&fpga_region0 { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "base.rbf"; + + fpga-bridge@4400 { + compatible = "altr,freeze-bridge-controller"; + reg = <0x4400 0x10>; + + fpga_region1: fpga-region1 { + compatible = "fpga-region"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + }; + }; + + fpga-bridge@4420 { + compatible = "altr,freeze-bridge-controller"; + reg = <0x4420 0x10>; + + fpga_region2: fpga-region2 { + compatible = "fpga-region"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; }; }; }; @@ -451,28 +439,23 @@ differences are that the FPGA is partially reconfigured due to the "partial-fpga-config" boolean and the only bridge that is controlled during programming is the FPGA based bridge of fpga_region1. -/dts-v1/ /plugin/; -/ { - fragment@0 { - target = <&fpga_region1>; - #address-cells = <1>; - #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "soc_image2.rbf"; - partial-fpga-config; - - gpio@10040 { - compatible = "altr,pio-1.0"; - reg = <0x10040 0x20>; - clocks = <0x2>; - altr,ngpio = <0x4>; - #gpio-cells = <0x2>; - gpio-controller; - }; - }; +/dts-v1/; +/plugin/; + +&fpga_region1 { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "soc_image2.rbf"; + partial-fpga-config; + + gpio@10040 { + compatible = "altr,pio-1.0"; + reg = <0x10040 0x20>; + clocks = <0x2>; + altr,ngpio = <0x4>; + #gpio-cells = <0x2>; + gpio-controller; }; }; diff --git a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt index 4284d293fa6135bf757d53f2bc8faeb29b86e8e2..0acdfa6d62a4d026d2ff49d4123723f6580d68b5 100644 --- a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt +++ b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt @@ -7,13 +7,24 @@ changes from passing through the bridge. The controller can also couple / enable the bridges which allows traffic to pass through the bridge normally. +Xilinx LogiCORE Dynamic Function eXchange(DFX) AXI shutdown manager +Softcore is compatible with the Xilinx LogiCORE pr-decoupler. + +The Dynamic Function eXchange AXI shutdown manager prevents AXI traffic +from passing through the bridge. The controller safely handles AXI4MM +and AXI4-Lite interfaces on a Reconfigurable Partition when it is +undergoing dynamic reconfiguration, preventing the system deadlock +that can occur if AXI transactions are interrupted by DFX + The Driver supports only MMIO handling. A PR region can have multiple PR Decouplers which can be handled independently or chained via decouple/ decouple_status signals. Required properties: - compatible : Should contain "xlnx,pr-decoupler-1.00" followed by - "xlnx,pr-decoupler" + "xlnx,pr-decoupler" or + "xlnx,dfx-axi-shutdown-manager-1.00" followed by + "xlnx,dfx-axi-shutdown-manager" - regs : base address and size for decoupler module - clocks : input clock to IP - clock-names : should contain "aclk" @@ -22,6 +33,7 @@ See Documentation/devicetree/bindings/fpga/fpga-region.txt and Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: +Partial Reconfig Decoupler: fpga-bridge@100000450 { compatible = "xlnx,pr-decoupler-1.00", "xlnx-pr-decoupler"; @@ -30,3 +42,13 @@ Example: clock-names = "aclk"; bridge-enable = <0>; }; + +Dynamic Function eXchange AXI shutdown manager: + fpga-bridge@100000450 { + compatible = "xlnx,dfx-axi-shutdown-manager-1.00", + "xlnx,dfx-axi-shutdown-manager"; + regs = <0x10000045 0x10>; + clocks = <&clkc 15>; + clock-names = "aclk"; + bridge-enable = <0>; + }; diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml index 184492162e7eb9148c6457155362d100dc67765c..894ba217ab329b8d6f2a4098a7ec04843e5392da 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml @@ -69,6 +69,8 @@ properties: where voltage is in V, frequency is in MHz. + dma-coherent: true + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml new file mode 100644 index 0000000000000000000000000000000000000000..911a1ae9c83f425d922ee5230b66e0d3c5034b00 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bosch BMI088 IMU accelerometer part + +maintainers: + - Mike Looijmans <mike.looijmans@topic.nl> + +description: | + Acceleration part of the IMU sensor with an SPI interface + Specifications about the sensor can be found at: + https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf + +properties: + compatible: + enum: + - bosch,bmi088-accel + + reg: + maxItems: 1 + + spi-max-frequency: true + + vdd-supply: true + + vddio-supply: true + + interrupts: + minItems: 1 + maxItems: 2 + description: | + Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW. + Two configurable interrupt lines exist. + + interrupt-names: + description: Specify which interrupt line is in use. + items: + enum: + - INT1 + - INT2 + minItems: 1 + maxItems: 2 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + bmi088-accel@1 { + compatible = "bosch,bmi088-accel"; + reg = <1>; + spi-max-frequency = <10000000>; + interrupt-parent = <&gpio6>; + interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "INT2"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml index 5b21a9fba5ddebdf6f7ee3dce84dd08b5b3f8a59..b939f9652e3a0f4d1db386d99e9c99c23a19c770 100644 --- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml @@ -34,6 +34,7 @@ properties: - items: - enum: - mediatek,mt8183-auxadc + - mediatek,mt8195-auxadc - mediatek,mt8516-auxadc - const: mediatek,mt8173-auxadc diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e0670e3fbb726095eeef8dd1e25ce4fc9fa9fc89 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads131e08.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments ADS131E0x 4-, 6- and 8-Channel ADCs + +maintainers: + - Tomislav Denis <tomislav.denis@avl.com> + +description: | + The ADS131E0x are a family of multichannel, simultaneous sampling, + 24-bit, delta-sigma, analog-to-digital converters (ADCs) with a + built-in programmable gain amplifier (PGA), internal reference + and an onboard oscillator. + The communication with ADC chip is via the SPI bus (mode 1). + + https://www.ti.com/lit/ds/symlink/ads131e08.pdf + +properties: + compatible: + enum: + - ti,ads131e04 + - ti,ads131e06 + - ti,ads131e08 + + reg: + maxItems: 1 + + spi-max-frequency: true + + spi-cpha: true + + clocks: + description: | + Device tree identifier to the clock source (2.048 MHz). + Note: clock source is selected using CLKSEL pin. + maxItems: 1 + + clock-names: + items: + - const: adc-clk + + interrupts: + description: | + IRQ line for the ADC data ready. + maxItems: 1 + + vref-supply: + description: | + Optional external voltage reference. If not supplied, internal voltage + reference is used. + + ti,vref-internal: + description: | + Select the internal voltage reference value. + 0: 2.4V + 1: 4.0V + If this field is left empty, 2.4V is selected. + Note: internal voltage reference is used only if vref-supply is not supplied. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + default: 0 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +required: + - compatible + - reg + - spi-cpha + - clocks + - clock-names + - interrupts + +patternProperties: + "^channel@([0-7])$": + $ref: "adc.yaml" + type: object + description: | + Represents the external channels which are connected to the ADC. + + properties: + reg: + description: | + The channel number. + Up to 4 channels, numbered from 0 to 3 for ti,ads131e04. + Up to 6 channels, numbered from 0 to 5 for ti,ads131e06. + Up to 8 channels, numbered from 0 to 7 for ti,ads131e08. + items: + minimum: 0 + maximum: 7 + + ti,gain: + description: | + The PGA gain value for the channel. + If this field is left empty, PGA gain 1 is used. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4, 8, 12] + default: 1 + + ti,mux: + description: | + Channel input selection(muliplexer). + 0: Normal input. + 1: Input shorted to (VREFP + VREFN) / 2 (for offset or noise measurements). + 3: MVDD (for supply measurement) + 4: Temperature sensor + If this field is left empty, normal input is selected. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 3, 4] + default: 0 + + required: + - reg + + additionalProperties: false + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "ti,ads131e08"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpha; + clocks = <&clk2048k>; + clock-names = "adc-clk"; + interrupt-parent = <&gpio5>; + interrupts = <28 IRQ_TYPE_EDGE_FALLING>; + vref-supply = <&adc_vref>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + }; + + channel@1 { + reg = <1>; + }; + + channel@2 { + reg = <2>; + ti,gain = <2>; + }; + + channel@3 { + reg = <3>; + }; + + channel@4 { + reg = <4>; + }; + + channel@5 { + reg = <5>; + }; + + channel@6 { + reg = <6>; + }; + + channel@7 { + reg = <7>; + ti,mux = <4>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml b/Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2155d3f5666c650197a08630dbc4f6da24e4ea8a --- /dev/null +++ b/Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/cdc/adi,ad7150.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog device AD7150 and similar capacitance to digital convertors. + +maintainers: + - Jonathan Cameron <jic23@kernel.org> + +properties: + compatible: + enum: + - adi,ad7150 + - adi,ad7151 + - adi,ad7156 + + reg: + maxItems: 1 + + vdd-supply: true + + interrupts: true + +allOf: + - if: + properties: + compatible: + contains: + enum: + - adi,ad7150 + - adi,ad7156 + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: adi,ad7151 + then: + properties: + interrupts: + minItems: 1 + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + cdc@48 { + compatible = "adi,ad7150"; + reg = <0x48>; + interrupts = <25 2>, <26 2>; + interrupt-parent = <&gpio>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml index 79fba1508e89c63f2a9543f438f6bb265d6f0026..a7574210175a9fbfea974213574e9b434e617f46 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml @@ -71,15 +71,6 @@ properties: minimum: 0 maximum: 3 - adi,scaled-output-hz: - description: - This property must be present if the clock mode is scaled-sync through - clock-names property. In this mode, the input clock can have a range - of 1Hz to 128HZ which must be scaled to originate an allowable sample - rate. This property specifies that rate. - minimum: 1900 - maximum: 2100 - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml b/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml new file mode 100644 index 0000000000000000000000000000000000000000..099b4be927d4ebeb370f5ebc32446bbbba39c14b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ChromeOS EC MKBP Proximity Sensor + +maintainers: + - Stephen Boyd <swboyd@chromium.org> + - Benson Leung <bleung@chromium.org> + - Enric Balletbo i Serra <enric.balletbo@collabora.com> + +description: | + Google's ChromeOS EC sometimes has the ability to detect user proximity. + This is implemented on the EC as near/far logic and exposed to the OS + via an MKBP switch bit. + +properties: + compatible: + const: google,cros-ec-mkbp-proximity + + label: + description: Name for proximity sensor + +required: + - compatible + +additionalProperties: false + +examples: + - | + proximity { + compatible = "google,cros-ec-mkbp-proximity"; + label = "proximity-wifi-lte"; + }; diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml index db291a9390b7fb74cc8334789f0f5706f112db57..7e98f47987dc68ae5e12e430b249718ad08d187e 100644 --- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml +++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml @@ -66,6 +66,7 @@ properties: - st,lis3mdl-magn - st,lis2mdl - st,lsm9ds1-magn + - st,iis2mdc # Pressure sensors - st,lps001wp-press - st,lps25h-press diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml index 799e73cdb90b494af79c98a8dac61ecaf61b74fd..cb6498108b78a67832fc44a8c13530d066ed2f39 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml @@ -71,6 +71,16 @@ properties: - qcom,sm8250-mmss-noc - qcom,sm8250-npu-noc - qcom,sm8250-system-noc + - qcom,sm8350-aggre1-noc + - qcom,sm8350-aggre2-noc + - qcom,sm8350-config-noc + - qcom,sm8350-dc-noc + - qcom,sm8350-gem-noc + - qcom,sm8350-lpass-ag-noc + - qcom,sm8350-mc-virt + - qcom,sm8350-mmss-noc + - qcom,sm8350-compute-noc + - qcom,sm8350-system-noc '#interconnect-cells': enum: [ 1, 2 ] diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml new file mode 100644 index 0000000000000000000000000000000000000000..29de7807df54ec4713d48d972e2e0035d8a416b0 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sdm660.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM660 Network-On-Chip interconnect + +maintainers: + - AngeloGioacchino Del Regno <kholk11@gmail.com> + +description: | + The Qualcomm SDM660 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +properties: + reg: + maxItems: 1 + + compatible: + enum: + - qcom,sdm660-a2noc + - qcom,sdm660-bimc + - qcom,sdm660-cnoc + - qcom,sdm660-gnoc + - qcom,sdm660-mnoc + - qcom,sdm660-snoc + + '#interconnect-cells': + const: 1 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + +required: + - compatible + - reg + - '#interconnect-cells' + - clock-names + - clocks + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm660-mnoc + then: + properties: + clocks: + items: + - description: Bus Clock. + - description: Bus A Clock. + - description: CPU-NoC High-performance Bus Clock. + clock-names: + items: + - const: bus + - const: bus_a + - const: iface + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm660-a2noc + - qcom,sdm660-bimc + - qcom,sdm660-cnoc + - qcom,sdm660-gnoc + - qcom,sdm660-snoc + then: + properties: + clocks: + items: + - description: Bus Clock. + - description: Bus A Clock. + clock-names: + items: + - const: bus + - const: bus_a + +examples: + - | + #include <dt-bindings/clock/qcom,rpmcc.h> + #include <dt-bindings/clock/qcom,mmcc-sdm660.h> + + bimc: interconnect@1008000 { + compatible = "qcom,sdm660-bimc"; + reg = <0x01008000 0x78000>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_BIMC_CLK>, + <&rpmcc RPM_SMD_BIMC_A_CLK>; + }; + + cnoc: interconnect@1500000 { + compatible = "qcom,sdm660-cnoc"; + reg = <0x01500000 0x10000>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_CNOC_CLK>, + <&rpmcc RPM_SMD_CNOC_A_CLK>; + }; + + snoc: interconnect@1626000 { + compatible = "qcom,sdm660-snoc"; + reg = <0x01626000 0x7090>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_SNOC_CLK>, + <&rpmcc RPM_SMD_SNOC_A_CLK>; + }; + + a2noc: interconnect@1704000 { + compatible = "qcom,sdm660-a2noc"; + reg = <0x01704000 0xc100>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, + <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>; + }; + + mnoc: interconnect@1745000 { + compatible = "qcom,sdm660-mnoc"; + reg = <0x01745000 0xa010>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a", "iface"; + clocks = <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK_A>, + <&mmcc AHB_CLK_SRC>; + }; + + gnoc: interconnect@17900000 { + compatible = "qcom,sdm660-gnoc"; + reg = <0x17900000 0xe000>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&xo_board>, <&xo_board>; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml b/Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cf6c091a07b14f18329158868823b5cc8962c5f8 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/apple,aic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple Interrupt Controller + +maintainers: + - Hector Martin <marcan@marcan.st> + +description: | + The Apple Interrupt Controller is a simple interrupt controller present on + Apple ARM SoC platforms, including various iPhone and iPad devices and the + "Apple Silicon" Macs. + + It provides the following features: + + - Level-triggered hardware IRQs wired to SoC blocks + - Single mask bit per IRQ + - Per-IRQ affinity setting + - Automatic masking on event delivery (auto-ack) + - Software triggering (ORed with hw line) + - 2 per-CPU IPIs (meant as "self" and "other", but they are interchangeable + if not symmetric) + - Automatic prioritization (single event/ack register per CPU, lower IRQs = + higher priority) + - Automatic masking on ack + - Default "this CPU" register view and explicit per-CPU views + + This device also represents the FIQ interrupt sources on platforms using AIC, + which do not go through a discrete interrupt controller. + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +properties: + compatible: + items: + - const: apple,t8103-aic + - const: apple,aic + + interrupt-controller: true + + '#interrupt-cells': + const: 3 + description: | + The 1st cell contains the interrupt type: + - 0: Hardware IRQ + - 1: FIQ + + The 2nd cell contains the interrupt number. + - HW IRQs: interrupt number + - FIQs: + - 0: physical HV timer + - 1: virtual HV timer + - 2: physical guest timer + - 3: virtual guest timer + + The 3rd cell contains the interrupt flags. This is normally + IRQ_TYPE_LEVEL_HIGH (4). + + reg: + description: | + Specifies base physical address and size of the AIC registers. + maxItems: 1 + +required: + - compatible + - '#interrupt-cells' + - interrupt-controller + - reg + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + aic: interrupt-controller@23b100000 { + compatible = "apple,t8103-aic", "apple,aic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x2 0x3b100000 0x0 0x8000>; + }; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/idt,32434-pic.yaml b/Documentation/devicetree/bindings/interrupt-controller/idt,32434-pic.yaml new file mode 100644 index 0000000000000000000000000000000000000000..df5d8d1ead70719298d19cc75f28e43fb27470f4 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/idt,32434-pic.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/idt,32434-pic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: IDT 79RC32434 Interrupt Controller Device Tree Bindings + +maintainers: + - Thomas Bogendoerfer <tsbogend@alpha.franken.de> + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +properties: + "#interrupt-cells": + const: 1 + + compatible: + const: idt,32434-pic + + reg: + maxItems: 1 + + interrupt-controller: true + +required: + - "#interrupt-cells" + - compatible + - reg + - interrupt-controller + +additionalProperties: false + +examples: + - | + idtpic3: interrupt-controller@3800c { + compatible = "idt,32434-pic"; + reg = <0x3800c 0x0c>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <3>; + }; + +... diff --git a/Documentation/devicetree/bindings/interrupt-controller/nuvoton,wpcm450-aic.yaml b/Documentation/devicetree/bindings/interrupt-controller/nuvoton,wpcm450-aic.yaml new file mode 100644 index 0000000000000000000000000000000000000000..9ce6804bdb9996f915fd914f804a798a197e0c7f --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/nuvoton,wpcm450-aic.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/nuvoton,wpcm450-aic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton WPCM450 Advanced Interrupt Controller bindings + +maintainers: + - Jonathan Neuschäfer <j.neuschaefer@gmx.net> + +properties: + '#interrupt-cells': + const: 2 + + compatible: + const: nuvoton,wpcm450-aic + + interrupt-controller: true + + reg: + maxItems: 1 + +additionalProperties: false + +required: + - '#interrupt-cells' + - compatible + - reg + - interrupt-controller + +examples: + - | + aic: interrupt-controller@b8002000 { + compatible = "nuvoton,wpcm450-aic"; + reg = <0xb8002000 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt index 4d28f1dd84ac3a9d86cd7548cb517d1204b13444..16d497e0cd336bbf9ad34faf12971b91a3062868 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt @@ -19,6 +19,7 @@ Properties: Value type: <string> Definition: Should contain "qcom,<soc>-pdc" and "qcom,pdc" - "qcom,sc7180-pdc": For SC7180 + - "qcom,sc7280-pdc": For SC7280 - "qcom,sdm845-pdc": For SDM845 - "qcom,sdm8250-pdc": For SM8250 - "qcom,sdm8350-pdc": For SM8350 diff --git a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml index 15cef82cd356d128d1d18f285768b6b9d80d2c6d..1a3dff277e2bb6da50f3e25283db867c440c14af 100644 --- a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml +++ b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml @@ -34,12 +34,15 @@ properties: - fsl,imx8mm-mu - fsl,imx8mn-mu - fsl,imx8mp-mu + - fsl,imx8qm-mu - fsl,imx8qxp-mu - const: fsl,imx6sx-mu - description: To communicate with i.MX8 SCU with fast IPC items: - const: fsl,imx8-mu-scu - - const: fsl,imx8qxp-mu + - enum: + - fsl,imx8qm-mu + - fsl,imx8qxp-mu - const: fsl,imx6sx-mu reg: diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index 946441b4e1a5d3153e472780d155cbbd146bcd36..c4a0886691124b50538aafeba38e8bbae862ebdd 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -90,9 +90,12 @@ properties: - rc-leadtek-y04g0051 - rc-lme2510 - rc-manli + - rc-mecool-kii-pro + - rc-mecool-kiii-pro - rc-medion-x10 - rc-medion-x10-digitainer - rc-medion-x10-or2x + - rc-minix-neo - rc-msi-digivox-ii - rc-msi-digivox-iii - rc-msi-tvanywhere @@ -145,6 +148,7 @@ properties: - rc-videomate-s350 - rc-videomate-tv-pvr - rc-videostrong-kii-pro + - rc-vega-s9x - rc-wetek-hub - rc-wetek-play2 - rc-winfast diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-emc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-emc.yaml index 09bde65e195571bf7df80dc1a69e75f674f0c625..9163c3f12a853b147626f42dd514fcbd45e888c7 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-emc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-emc.yaml @@ -37,9 +37,10 @@ properties: description: phandle of the memory controller node - core-supply: + power-domains: + maxItems: 1 description: - Phandle of voltage regulator of the SoC "core" power domain. + Phandle of the SoC "core" power domain. operating-points-v2: description: @@ -370,7 +371,7 @@ examples: nvidia,memory-controller = <&mc>; operating-points-v2 = <&dvfs_opp_table>; - core-supply = <&vdd_core>; + power-domains = <&domain>; #interconnect-cells = <0>; diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt index cc443fcf4bec86c2495389703733e9882547b9b9..d2250498c36d39b80a4dd5fa4d1ba749b5379bab 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt @@ -23,7 +23,7 @@ For each opp entry in 'operating-points-v2' table: matches, the OPP gets enabled. Optional properties: -- core-supply: Phandle of voltage regulator of the SoC "core" power domain. +- power-domains: Phandle of the SoC "core" power domain. Child device nodes describe the memory settings for different configurations and clock rates. @@ -48,7 +48,7 @@ Example: interrupts = <0 78 0x04>; clocks = <&tegra_car TEGRA20_CLK_EMC>; nvidia,memory-controller = <&mc>; - core-supply = <&core_vdd_reg>; + power-domains = <&domain>; operating-points-v2 = <&opp_table>; } diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt deleted file mode 100644 index 739b7c6f2e2673b26f879f17b67a11553ce1e3f0..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt +++ /dev/null @@ -1,40 +0,0 @@ -NVIDIA Tegra20 MC(Memory Controller) - -Required properties: -- compatible : "nvidia,tegra20-mc-gart" -- reg : Should contain 2 register ranges: physical base address and length of - the controller's registers and the GART aperture respectively. -- clocks: Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names: Must include the following entries: - - mc: the module's clock input -- interrupts : Should contain MC General interrupt. -- #reset-cells : Should be 1. This cell represents memory client module ID. - The assignments may be found in header file <dt-bindings/memory/tegra20-mc.h> - or in the TRM documentation. -- #iommu-cells: Should be 0. This cell represents the number of cells in an - IOMMU specifier needed to encode an address. GART supports only a single - address space that is shared by all devices, therefore no additional - information needed for the address encoding. -- #interconnect-cells : Should be 1. This cell represents memory client. - The assignments may be found in header file <dt-bindings/memory/tegra20-mc.h>. - -Example: - mc: memory-controller@7000f000 { - compatible = "nvidia,tegra20-mc-gart"; - reg = <0x7000f000 0x400 /* controller registers */ - 0x58000000 0x02000000>; /* GART aperture */ - clocks = <&tegra_car TEGRA20_CLK_MC>; - clock-names = "mc"; - interrupts = <GIC_SPI 77 0x04>; - #reset-cells = <1>; - #iommu-cells = <0>; - #interconnect-cells = <1>; - }; - - video-codec@6001a000 { - compatible = "nvidia,tegra20-vde"; - ... - resets = <&mc TEGRA20_MC_RESET_VDE>; - iommus = <&mc>; - }; diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..55caf69053995fa0346483f3f95346968f63ee56 --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/memory-controllers/nvidia,tegra20-mc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra20 SoC Memory Controller + +maintainers: + - Dmitry Osipenko <digetx@gmail.com> + - Jon Hunter <jonathanh@nvidia.com> + - Thierry Reding <thierry.reding@gmail.com> + +description: | + The Tegra20 Memory Controller merges request streams from various client + interfaces into request stream(s) for the various memory target devices, + and returns response data to the various clients. The Memory Controller + has a configurable arbitration algorithm to allow the user to fine-tune + performance among the various clients. + + Tegra20 Memory Controller includes the GART (Graphics Address Relocation + Table) which allows Memory Controller to provide a linear view of a + fragmented memory pages. + +properties: + compatible: + const: nvidia,tegra20-mc-gart + + reg: + items: + - description: controller registers + - description: GART registers + + clocks: + maxItems: 1 + + clock-names: + items: + - const: mc + + interrupts: + maxItems: 1 + + "#reset-cells": + const: 1 + + "#iommu-cells": + const: 0 + + "#interconnect-cells": + const: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - "#reset-cells" + - "#iommu-cells" + - "#interconnect-cells" + +additionalProperties: false + +examples: + - | + memory-controller@7000f000 { + compatible = "nvidia,tegra20-mc-gart"; + reg = <0x7000f000 0x400>, /* Controller registers */ + <0x58000000 0x02000000>; /* GART aperture */ + clocks = <&clock_controller 32>; + clock-names = "mc"; + + interrupts = <0 77 4>; + + #iommu-cells = <0>; + #reset-cells = <1>; + #interconnect-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml index 0a2e2c0d0fdda56765b918f9dfde87868b77674c..fb6af14cb49c5ff419e9107c71e2a6ecf47be824 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml @@ -39,9 +39,10 @@ properties: description: Phandle of the Memory Controller node. - core-supply: + power-domains: + maxItems: 1 description: - Phandle of voltage regulator of the SoC "core" power domain. + Phandle of the SoC "core" power domain. operating-points-v2: description: @@ -241,7 +242,7 @@ examples: nvidia,memory-controller = <&mc>; operating-points-v2 = <&dvfs_opp_table>; - core-supply = <&vdd_core>; + power-domains = <&domain>; #interconnect-cells = <0>; diff --git a/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt b/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt index d0a38ba8b9ce95ec8bb75f0330e3559dd2fdba4e..936aa108eab4d8ff95ca1b1d1c8a7377728b0356 100644 --- a/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt +++ b/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt @@ -9,13 +9,7 @@ primary use case of the Aspeed LPC controller is as a slave on the bus conditions it can also take the role of bus master. The LPC controller is represented as a multi-function device to account for the -mix of functionality it provides. The principle split is between the register -layout at the start of the I/O space which is, to quote the Aspeed datasheet, -"basically compatible with the [LPC registers from the] popular BMC controller -H8S/2168[1]", and everything else, where everything else is an eclectic -collection of functions with a esoteric register layout. "Everything else", -here labeled the "host" portion of the controller, includes, but is not limited -to: +mix of functionality, which includes, but is not limited to: * An IPMI Block Transfer[2] Controller @@ -44,80 +38,36 @@ Required properties =================== - compatible: One of: - "aspeed,ast2400-lpc", "simple-mfd" - "aspeed,ast2500-lpc", "simple-mfd" - "aspeed,ast2600-lpc", "simple-mfd" + "aspeed,ast2400-lpc-v2", "simple-mfd", "syscon" + "aspeed,ast2500-lpc-v2", "simple-mfd", "syscon" + "aspeed,ast2600-lpc-v2", "simple-mfd", "syscon" - reg: contains the physical address and length values of the Aspeed LPC memory region. - #address-cells: <1> - #size-cells: <1> -- ranges: Maps 0 to the physical address and length of the LPC memory - region - -Required LPC Child nodes -======================== - -BMC Node --------- - -- compatible: One of: - "aspeed,ast2400-lpc-bmc" - "aspeed,ast2500-lpc-bmc" - "aspeed,ast2600-lpc-bmc" - -- reg: contains the physical address and length values of the - H8S/2168-compatible LPC controller memory region - -Host Node ---------- - -- compatible: One of: - "aspeed,ast2400-lpc-host", "simple-mfd", "syscon" - "aspeed,ast2500-lpc-host", "simple-mfd", "syscon" - "aspeed,ast2600-lpc-host", "simple-mfd", "syscon" - -- reg: contains the address and length values of the host-related - register space for the Aspeed LPC controller - -- #address-cells: <1> -- #size-cells: <1> -- ranges: Maps 0 to the address and length of the host-related LPC memory +- ranges: Maps 0 to the physical address and length of the LPC memory region Example: lpc: lpc@1e789000 { - compatible = "aspeed,ast2500-lpc", "simple-mfd"; + compatible = "aspeed,ast2500-lpc-v2", "simple-mfd", "syscon"; reg = <0x1e789000 0x1000>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x1e789000 0x1000>; - lpc_bmc: lpc-bmc@0 { - compatible = "aspeed,ast2500-lpc-bmc"; + lpc_snoop: lpc-snoop@0 { + compatible = "aspeed,ast2600-lpc-snoop"; reg = <0x0 0x80>; - }; - - lpc_host: lpc-host@80 { - compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon"; - reg = <0x80 0x1e0>; - reg-io-width = <4>; - - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x80 0x1e0>; + interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; + snoop-ports = <0x80>; }; }; -BMC Node Children -================== - - -Host Node Children -================== LPC Host Interface Controller ------------------- @@ -149,14 +99,12 @@ Optional properties: Example: -lpc-host@80 { - lpc_ctrl: lpc-ctrl@0 { - compatible = "aspeed,ast2500-lpc-ctrl"; - reg = <0x0 0x80>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - memory-region = <&flash_memory>; - flash = <&spi>; - }; +lpc_ctrl: lpc-ctrl@80 { + compatible = "aspeed,ast2500-lpc-ctrl"; + reg = <0x80 0x80>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + memory-region = <&flash_memory>; + flash = <&spi>; }; LPC Host Controller @@ -179,9 +127,9 @@ Required properties: Example: -lhc: lhc@20 { +lhc: lhc@a0 { compatible = "aspeed,ast2500-lhc"; - reg = <0x20 0x24 0x48 0x8>; + reg = <0xa0 0x24 0xc8 0x8>; }; LPC reset control @@ -192,16 +140,18 @@ state of the LPC bus. Some systems may chose to modify this configuration. Required properties: - - compatible: "aspeed,ast2600-lpc-reset" or - "aspeed,ast2500-lpc-reset" - "aspeed,ast2400-lpc-reset" + - compatible: One of: + "aspeed,ast2600-lpc-reset"; + "aspeed,ast2500-lpc-reset"; + "aspeed,ast2400-lpc-reset"; + - reg: offset and length of the IP in the LHC memory region - #reset-controller indicates the number of reset cells expected Example: -lpc_reset: reset-controller@18 { +lpc_reset: reset-controller@98 { compatible = "aspeed,ast2500-lpc-reset"; - reg = <0x18 0x4>; + reg = <0x98 0x4>; #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index 76bf16ee27ec746fdb2b49f4b73efeb3a3301008..4dfa70a013ae68b55c3f7a30b34c60ba78c9f9cf 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -94,6 +94,9 @@ properties: keyboard-controller: $ref: "/schemas/input/google,cros-ec-keyb.yaml#" + proximity: + $ref: "/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml#" + codecs: type: object additionalProperties: false @@ -180,6 +183,10 @@ examples: interrupts = <99 0>; interrupt-parent = <&gpio7>; spi-max-frequency = <5000000>; + + proximity { + compatible = "google,cros-ec-mkbp-proximity"; + }; }; }; diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index d0e422f4b3e005f7f306e2d19087d2b86e54fcfa..678b3995250264895b99c9b9ea3065c4b91e844d 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -143,6 +143,13 @@ patternProperties: Ready/Busy pins. Active state refers to the NAND ready state and should be set to GPIOD_ACTIVE_HIGH unless the signal is inverted. + secure-regions: + $ref: /schemas/types.yaml#/definitions/uint64-matrix + description: + Regions in the NAND chip which are protected using a secure element + like Trustzone. This property contains the start address and size of + the secure regions present. + required: - reg diff --git a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml new file mode 100644 index 0000000000000000000000000000000000000000..99249cdfbfb31c49b7ed9c0d692a251bc303bf23 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/linksys,ns-partitions.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Linksys Northstar partitioning + +description: | + Linksys devices based on Broadcom Northstar architecture often use two + firmware partitions. One is used for regular booting, the other is treated as + fallback. + + This binding allows defining all fixed partitions and marking those containing + firmware. System can use that information e.g. for booting or flashing + purposes. + +maintainers: + - Rafał Miłecki <rafal@milecki.pl> + +properties: + compatible: + const: linksys,ns-partitions + + "#address-cells": + enum: [ 1, 2 ] + + "#size-cells": + enum: [ 1, 2 ] + +patternProperties: + "^partition@[0-9a-f]+$": + $ref: "partition.yaml#" + properties: + compatible: + items: + - const: linksys,ns-firmware + - const: brcm,trx + unevaluatedProperties: false + +required: + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + partitions { + compatible = "linksys,ns-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot"; + reg = <0x0 0x100000>; + read-only; + }; + + partition@100000 { + label = "nvram"; + reg = <0x100000 0x100000>; + }; + + partition@200000 { + compatible = "linksys,ns-firmware", "brcm,trx"; + reg = <0x200000 0xf00000>; + }; + + partition@1100000 { + compatible = "linksys,ns-firmware", "brcm,trx"; + reg = <0x1100000 0xf00000>; + }; + }; diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5cdd2efa9132d3d1b5ff2db5dbeb1ef21fe4de06 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nvmem cells + +description: | + Any partition containing the compatible "nvmem-cells" will register as a + nvmem provider. + Each direct subnodes represents a nvmem cell following the nvmem binding. + Nvmem binding to declare nvmem-cells can be found in: + Documentation/devicetree/bindings/nvmem/nvmem.yaml + +maintainers: + - Ansuel Smith <ansuelsmth@gmail.com> + +allOf: + - $ref: /schemas/nvmem/nvmem.yaml# + +properties: + compatible: + const: nvmem-cells + +required: + - compatible + +additionalProperties: true + +examples: + - | + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* ... */ + + }; + art: art@1200000 { + compatible = "nvmem-cells"; + reg = <0x1200000 0x0140000>; + label = "art"; + read-only; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_gmac1: macaddr_gmac1@0 { + reg = <0x0 0x6>; + }; + + macaddr_gmac2: macaddr_gmac2@6 { + reg = <0x6 0x6>; + }; + + pre_cal_24g: pre_cal_24g@1000 { + reg = <0x1000 0x2f20>; + }; + + pre_cal_5g: pre_cal_5g@5000{ + reg = <0x5000 0x2f20>; + }; + }; + - | + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x000000 0x100000>; + read-only; + }; + + firmware@100000 { + compatible = "brcm,trx"; + label = "firmware"; + reg = <0x100000 0xe00000>; + }; + + calibration@f00000 { + compatible = "nvmem-cells"; + label = "calibration"; + reg = <0xf00000 0x100000>; + ranges = <0 0xf00000 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + + wifi0@0 { + reg = <0x000000 0x080000>; + }; + + wifi1@80000 { + reg = <0x080000 0x080000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..84ad7ff30121281a131d87bca51bb455c51a1ede --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/qcom,nandc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm NAND controller + +maintainers: + - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +properties: + compatible: + enum: + - qcom,ipq806x-nand + - qcom,ipq4019-nand + - qcom,ipq6018-nand + - qcom,ipq8074-nand + - qcom,sdx55-nand + + reg: + maxItems: 1 + + clocks: + items: + - description: Core Clock + - description: Always ON Clock + + clock-names: + items: + - const: core + - const: aon + + "#address-cells": true + "#size-cells": true + +patternProperties: + "^nand@[a-f0-9]$": + type: object + properties: + nand-bus-width: + const: 8 + + nand-ecc-strength: + enum: [1, 4, 8] + + nand-ecc-step-size: + enum: + - 512 + +allOf: + - $ref: "nand-controller.yaml#" + + - if: + properties: + compatible: + contains: + const: qcom,ipq806x-nand + then: + properties: + dmas: + items: + - description: rxtx DMA channel + + dma-names: + items: + - const: rxtx + + qcom,cmd-crci: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Must contain the ADM command type CRCI block instance number + specified for the NAND controller on the given platform + + qcom,data-crci: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Must contain the ADM data type CRCI block instance number + specified for the NAND controller on the given platform + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq4019-nand + - qcom,ipq6018-nand + - qcom,ipq8074-nand + - qcom,sdx55-nand + + then: + properties: + dmas: + items: + - description: tx DMA channel + - description: rx DMA channel + - description: cmd DMA channel + + dma-names: + items: + - const: tx + - const: rx + - const: cmd + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/qcom,gcc-ipq806x.h> + nand-controller@1ac00000 { + compatible = "qcom,ipq806x-nand"; + reg = <0x1ac00000 0x800>; + + clocks = <&gcc EBI2_CLK>, + <&gcc EBI2_AON_CLK>; + clock-names = "core", "aon"; + + dmas = <&adm_dma 3>; + dma-names = "rxtx"; + qcom,cmd-crci = <15>; + qcom,data-crci = <3>; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; + + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; + }; + }; + + #include <dt-bindings/clock/qcom,gcc-ipq4019.h> + nand-controller@79b0000 { + compatible = "qcom,ipq4019-nand"; + reg = <0x79b0000 0x1000>; + + clocks = <&gcc GCC_QPIC_CLK>, + <&gcc GCC_QPIC_AHB_CLK>; + clock-names = "core", "aon"; + + dmas = <&qpicbam 0>, + <&qpicbam 1>, + <&qpicbam 2>; + dma-names = "tx", "rx", "cmd"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; + + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt deleted file mode 100644 index 5647913d8837ef36df3af41e1aac09b8389d2466..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +++ /dev/null @@ -1,142 +0,0 @@ -* Qualcomm NAND controller - -Required properties: -- compatible: must be one of the following: - * "qcom,ipq806x-nand" - for EBI2 NAND controller being used in IPQ806x - SoC and it uses ADM DMA - * "qcom,ipq4019-nand" - for QPIC NAND controller v1.4.0 being used in - IPQ4019 SoC and it uses BAM DMA - * "qcom,ipq6018-nand" - for QPIC NAND controller v1.5.0 being used in - IPQ6018 SoC and it uses BAM DMA - * "qcom,ipq8074-nand" - for QPIC NAND controller v1.5.0 being used in - IPQ8074 SoC and it uses BAM DMA - * "qcom,sdx55-nand" - for QPIC NAND controller v2.0.0 being used in - SDX55 SoC and it uses BAM DMA - -- reg: MMIO address range -- clocks: must contain core clock and always on clock -- clock-names: must contain "core" for the core clock and "aon" for the - always on clock - -EBI2 specific properties: -- dmas: DMA specifier, consisting of a phandle to the ADM DMA - controller node and the channel number to be used for - NAND. Refer to dma.txt and qcom_adm.txt for more details -- dma-names: must be "rxtx" -- qcom,cmd-crci: must contain the ADM command type CRCI block instance - number specified for the NAND controller on the given - platform -- qcom,data-crci: must contain the ADM data type CRCI block instance - number specified for the NAND controller on the given - platform - -QPIC specific properties: -- dmas: DMA specifier, consisting of a phandle to the BAM DMA - and the channel number to be used for NAND. Refer to - dma.txt, qcom_bam_dma.txt for more details -- dma-names: must contain all 3 channel names : "tx", "rx", "cmd" -- #address-cells: <1> - subnodes give the chip-select number -- #size-cells: <0> - -* NAND chip-select - -Each controller may contain one or more subnodes to represent enabled -chip-selects which (may) contain NAND flash chips. Their properties are as -follows. - -Required properties: -- reg: a single integer representing the chip-select - number (e.g., 0, 1, 2, etc.) -- #address-cells: see partition.txt -- #size-cells: see partition.txt - -Optional properties: -- nand-bus-width: see nand-controller.yaml -- nand-ecc-strength: see nand-controller.yaml. If not specified, then ECC strength will - be used according to chip requirement and available - OOB size. - -Each nandcs device node may optionally contain a 'partitions' sub-node, which -further contains sub-nodes describing the flash partition mapping. See -partition.txt for more detail. - -Example: - -nand-controller@1ac00000 { - compatible = "qcom,ipq806x-nand"; - reg = <0x1ac00000 0x800>; - - clocks = <&gcc EBI2_CLK>, - <&gcc EBI2_AON_CLK>; - clock-names = "core", "aon"; - - dmas = <&adm_dma 3>; - dma-names = "rxtx"; - qcom,cmd-crci = <15>; - qcom,data-crci = <3>; - - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - - nand-ecc-strength = <4>; - nand-bus-width = <8>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "boot-nand"; - reg = <0 0x58a0000>; - }; - - partition@58a0000 { - label = "fs-nand"; - reg = <0x58a0000 0x4000000>; - }; - }; - }; -}; - -nand-controller@79b0000 { - compatible = "qcom,ipq4019-nand"; - reg = <0x79b0000 0x1000>; - - clocks = <&gcc GCC_QPIC_CLK>, - <&gcc GCC_QPIC_AHB_CLK>; - clock-names = "core", "aon"; - - dmas = <&qpicbam 0>, - <&qpicbam 1>, - <&qpicbam 2>; - dma-names = "tx", "rx", "cmd"; - - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - nand-ecc-strength = <4>; - nand-bus-width = <8>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "boot-nand"; - reg = <0 0x58a0000>; - }; - - partition@58a0000 { - label = "fs-nand"; - reg = <0x58a0000 0x4000000>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml new file mode 100644 index 0000000000000000000000000000000000000000..58ff6b0bdb1af397f2958c6875616c04af0a4d9a --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/brcm,nvram.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom's NVRAM + +description: | + Broadcom's NVRAM is a structure containing device specific environment + variables. It is used for storing device configuration, booting parameters + and calibration data. + + NVRAM can be accessed on Broadcom BCM47xx MIPS and Northstar ARM Cortex-A9 + devices usiong I/O mapped memory. + +maintainers: + - Rafał Miłecki <rafal@milecki.pl> + +allOf: + - $ref: "nvmem.yaml#" + +properties: + compatible: + const: brcm,nvram + +unevaluatedProperties: false + +examples: + - | + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; + }; diff --git a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt index ef93c3b95424d911b64f99d1ecdc14d37097ff16..d479ad977e24fb6b7ee1bdc1c818e3af24080e2d 100644 --- a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt +++ b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt @@ -7,7 +7,9 @@ Required properties: "mediatek,mt7622-efuse", "mediatek,efuse": for MT7622 "mediatek,mt7623-efuse", "mediatek,efuse": for MT7623 "mediatek,mt8173-efuse" or "mediatek,efuse": for MT8173 + "mediatek,mt8192-efuse", "mediatek,efuse": for MT8192 "mediatek,mt8516-efuse", "mediatek,efuse": for MT8516 + "mediatek,mt8192-efuse", "mediatek,efuse": for MT8192 - reg: Should contain registers location and length = Data cells = diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml b/Documentation/devicetree/bindings/nvmem/nvmem.yaml index 7481a9e48f1969d67f63755b5c62a0623286e168..b8dc3d2b6e92cc2cccfb4e52808d2611587bc0ca 100644 --- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml +++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml @@ -20,9 +20,6 @@ description: | storage device. properties: - $nodename: - pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$" - "#address-cells": const: 1 diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 992777c90a0bf3803ed7fb2edfe0c4a065353a2f..861b205016b184743c0f55e07972ed70fe46ae61 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -24,6 +24,7 @@ properties: - qcom,msm8998-qfprom - qcom,qcs404-qfprom - qcom,sc7180-qfprom + - qcom,sc7280-qfprom - qcom,sdm845-qfprom - const: qcom,qfprom diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt deleted file mode 100644 index a7aee9ea8926c409add88e6992b50b32261ce358..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt +++ /dev/null @@ -1,21 +0,0 @@ -Driver for Broadcom Northstar USB 2.0 PHY - -Required properties: -- compatible: brcm,ns-usb2-phy -- reg: iomem address range of DMU (Device Management Unit) -- reg-names: "dmu", the only needed & supported reg right now -- clocks: USB PHY reference clock -- clock-names: "phy-ref-clk", the only needed & supported clock right now - -To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it -requires passing phandle to the USB PHY reference clock. - -Example: - usb2-phy { - compatible = "brcm,ns-usb2-phy"; - reg = <0x1800c000 0x1000>; - reg-names = "dmu"; - #phy-cells = <0>; - clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>; - clock-names = "phy-ref-clk"; - }; diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..05b4dcd8001991c6c874ce8bbfee13c49b80436b --- /dev/null +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/bcm-ns-usb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Northstar USB 2.0 PHY + +description: > + To initialize USB 2.0 PHY driver needs to setup PLL correctly. + To do this it requires passing phandle to the USB PHY reference clock. + +maintainers: + - Rafał Miłecki <rafal@milecki.pl> + +properties: + compatible: + const: brcm,ns-usb2-phy + + reg: + items: + - description: iomem address range of DMU (Device Management Unit) + + reg-names: + items: + - const: dmu + + clocks: + items: + - description: USB PHY reference clock + + clock-names: + items: + - const: phy-ref-clk + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/bcm-nsp.h> + phy@1800c000 { + compatible = "brcm,ns-usb2-phy"; + reg = <0x1800c000 0x1000>; + reg-names = "dmu"; + clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>; + clock-names = "phy-ref-clk"; + #phy-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt deleted file mode 100644 index 32f05726035194b30ac01a5a34dfb6c2336146a3..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt +++ /dev/null @@ -1,34 +0,0 @@ -Driver for Broadcom Northstar USB 3.0 PHY - -Required properties: - -- compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy". -- reg: address of MDIO bus device -- usb3-dmp-syscon: phandle to syscon with DMP (Device Management Plugin) - registers -- #phy-cells: must be 0 - -Initialization of USB 3.0 PHY depends on Northstar version. There are currently -three known series: Ax, Bx and Cx. -Known A0: BCM4707 rev 0 -Known B0: BCM4707 rev 4, BCM53573 rev 2 -Known B1: BCM4707 rev 6 -Known C0: BCM47094 rev 0 - -Example: - mdio: mdio@0 { - reg = <0x0>; - #size-cells = <1>; - #address-cells = <0>; - - usb3-phy@10 { - compatible = "brcm,ns-ax-usb3-phy"; - reg = <0x10>; - usb3-dmp-syscon = <&usb3_dmp>; - #phy-cells = <0>; - }; - }; - - usb3_dmp: syscon@18105000 { - reg = <0x18105000 0x1000>; - }; diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7fd419db45d002118fa0037f3640640f2642fd33 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/bcm-ns-usb3-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Northstar USB 3.0 PHY + +description: | + Initialization of USB 3.0 PHY depends on Northstar version. There are currently + three known series: Ax, Bx and Cx. + Known A0: BCM4707 rev 0 + Known B0: BCM4707 rev 4, BCM53573 rev 2 + Known B1: BCM4707 rev 6 + Known C0: BCM47094 rev 0 + +maintainers: + - Rafał Miłecki <rafal@milecki.pl> + +properties: + compatible: + enum: + - brcm,ns-ax-usb3-phy + - brcm,ns-bx-usb3-phy + + reg: + description: address of MDIO bus device + maxItems: 1 + + usb3-dmp-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the DMP (Device Management Plugin) syscon + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - usb3-dmp-syscon + - "#phy-cells" + +additionalProperties: false + +examples: + - | + mdio { + #address-cells = <1>; + #size-cells = <0>; + + usb3-phy@10 { + compatible = "brcm,ns-ax-usb3-phy"; + reg = <0x10>; + usb3-dmp-syscon = <&usb3_dmp>; + #phy-cells = <0>; + }; + }; + + usb3_dmp: syscon@18105000 { + reg = <0x18105000 0x1000>; + }; diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml index 0497368d1fcafb1f0a903de8da1f38466347ea31..5f9e91bfb5ff4383fe15fb8d519ac93e9bfb2d94 100644 --- a/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml @@ -42,6 +42,9 @@ properties: - const: usb_mdio - const: bdc_ec + power-domains: + maxItems: 1 + clocks: minItems: 1 maxItems: 2 diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2437c3683326f7e0965e9c4f8a78101afc72d616 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Marvell Armada UTMI/UTMI+ PHY + +maintainers: + - Miquel Raynal <miquel.raynal@bootlin.com> + +description: + On Armada 3700, there are two USB controllers, one is compatible with + the USB2 and USB3 specifications and supports OTG. The other one is USB2 + compliant and only supports host mode. Both of these controllers come with + a slightly different UTMI PHY. + +properties: + compatible: + enum: + - marvell,a3700-utmi-host-phy + - marvell,a3700-utmi-otg-phy + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + marvell,usb-misc-reg: + description: + Phandle on the "USB miscellaneous registers" shared region + covering registers related to both the host controller and + the PHY. + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - reg + - "#phy-cells" + - marvell,usb-misc-reg + +additionalProperties: false + +examples: + - | + usb2_utmi_host_phy: phy@5f000 { + compatible = "marvell,armada-3700-utmi-host-phy"; + reg = <0x5f000 0x800>; + marvell,usb-misc-reg = <&usb2_syscon>; + #phy-cells = <0>; + }; + + usb2_syscon: system-controller@5f800 { + compatible = "marvell,armada-3700-usb2-host-misc", "syscon"; + reg = <0x5f800 0x800>; + }; diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..30f3b5f32a95aa0a9bc8ce2725858bebcf88c4c6 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Marvell Armada CP110/CP115 UTMI PHY + +maintainers: + - Konstantin Porotchkin <kostap@marvell.com> + +description: + On Armada 7k/8k and CN913x, there are two host and one device USB controllers. + Each of two exiting UTMI PHYs could be connected to either USB host or USB device + controller. + The USB device controller can only be connected to a single UTMI PHY port + 0.H----- USB HOST0 + UTMI PHY0 --------/ + 0.D-----0 + \------ USB DEVICE + 1.D-----1 + UTMI PHY1 --------\ + 1.H----- USB HOST1 + +properties: + compatible: + const: marvell,cp110-utmi-phy + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + marvell,system-controller: + description: + Phandle to the system controller node + $ref: /schemas/types.yaml#/definitions/phandle + +#Required child nodes: + +patternProperties: + "^usb-phy@[0|1]$": + type: object + description: + Each UTMI PHY port must be represented as a sub-node. + + properties: + reg: + description: phy port index. + maxItems: 1 + + "#phy-cells": + const: 0 + + required: + - reg + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - marvell,system-controller + +additionalProperties: false + +examples: + - | + cp0_utmi: utmi@580000 { + compatible = "marvell,cp110-utmi-phy"; + reg = <0x580000 0x2000>; + marvell,system-controller = <&cp0_syscon0>; + #address-cells = <1>; + #size-cells = <0>; + + cp0_utmi0: usb-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + cp0_utmi1: usb-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; + + cp0_usb3_0 { + usb-phy = <&cp0_usb3_0_phy0>; + phys = <&cp0_utmi0>; + phy-names = "utmi"; + /* UTMI0 is connected to USB host controller (default mode) */ + dr_mode = "host"; + }; + + cp0_usb3_1 { + usb-phy = <&cp0_usb3_0_phy1>; + phys = <&cp0_utmi1>; + phy-names = "utmi"; + /* UTMI1 is connected to USB device controller */ + dr_mode = "peripheral"; + }; diff --git a/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml index 71d4acea1f669a7d01a6cde25e67ea1ed4ea2093..6e4d795f9b02aeab819ce7d0a649e8ea08a27b6a 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml @@ -19,11 +19,14 @@ properties: pattern: "^dsi-phy@[0-9a-f]+$" compatible: - enum: - - mediatek,mt2701-mipi-tx - - mediatek,mt7623-mipi-tx - - mediatek,mt8173-mipi-tx - - mediatek,mt8183-mipi-tx + oneOf: + - items: + - enum: + - mediatek,mt7623-mipi-tx + - const: mediatek,mt2701-mipi-tx + - const: mediatek,mt2701-mipi-tx + - const: mediatek,mt8173-mipi-tx + - const: mediatek,mt8183-mipi-tx reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml index 4752517a144604cadcbd761d861f9e8d07645f45..0d94950b84ca3fc3b2ed9755d6bbf2e2ff558ca4 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml @@ -21,10 +21,13 @@ properties: pattern: "^hdmi-phy@[0-9a-f]+$" compatible: - enum: - - mediatek,mt2701-hdmi-phy - - mediatek,mt7623-hdmi-phy - - mediatek,mt8173-hdmi-phy + oneOf: + - items: + - enum: + - mediatek,mt7623-hdmi-phy + - const: mediatek,mt2701-hdmi-phy + - const: mediatek,mt2701-hdmi-phy + - const: mediatek,mt8173-hdmi-phy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index 602e6ff45785e8f2e6797155263e0a1d5f8a30ec..b8a7651a3d9aea654b4552bb1df6e4f2fd679acc 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -79,6 +79,7 @@ properties: - mediatek,mt2712-tphy - mediatek,mt7629-tphy - mediatek,mt8183-tphy + - mediatek,mt8195-tphy - const: mediatek,generic-tphy-v2 - const: mediatek,mt2701-u3phy deprecated: true @@ -117,7 +118,7 @@ properties: # Required child node: patternProperties: - "^usb-phy@[0-9a-f]+$": + "^(usb|pcie|sata)-phy@[0-9a-f]+$": type: object description: A sub-node is required for each port the controller provides. diff --git a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml index 3a9be82e7f13f7775d7b6dc233d1aa6dbd982332..74cc32c1d2e85cac5e18090de2dbb1d2ccdd87be 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml @@ -22,7 +22,12 @@ properties: pattern: "^ufs-phy@[0-9a-f]+$" compatible: - const: mediatek,mt8183-ufsphy + oneOf: + - items: + - enum: + - mediatek,mt8195-ufsphy + - const: mediatek,mt8183-ufsphy + - const: mediatek,mt8183-ufsphy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml b/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bdbdb3bbddbea57a8f66bc51924c07c04f1bbf7f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/microchip,sparx5-serdes.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip Sparx5 Serdes controller + +maintainers: + - Steen Hegelund <steen.hegelund@microchip.com> + +description: | + The Sparx5 SERDES interfaces share the same basic functionality, but + support different operating modes and line rates. + + The following list lists the SERDES features: + + * RX Adaptive Decision Feedback Equalizer (DFE) + * Programmable continuous time linear equalizer (CTLE) + * Rx variable gain control + * Rx built-in fault detector (loss-of-lock/loss-of-signal) + * Adjustable tx de-emphasis (FFE) + * Tx output amplitude control + * Supports rx eye monitor + * Multiple loopback modes + * Prbs generator and checker + * Polarity inversion control + + SERDES6G: + + The SERDES6G is a high-speed SERDES interface, which can operate at + the following data rates: + + * 100 Mbps (100BASE-FX) + * 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX) + * 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX) + * 5.15625 Gbps (5GBASE-KR/5G-USXGMII) + + SERDES10G + + The SERDES10G is a high-speed SERDES interface, which can operate at + the following data rates: + + * 100 Mbps (100BASE-FX) + * 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX) + * 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX) + * 5 Gbps (QSGMII/USGMII) + * 5.15625 Gbps (5GBASE-KR/5G-USXGMII) + * 10 Gbps (10G-USGMII) + * 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII) + + SERDES25G + + The SERDES25G is a high-speed SERDES interface, which can operate at + the following data rates: + + * 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX) + * 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX) + * 5 Gbps (QSGMII/USGMII) + * 5.15625 Gbps (5GBASE-KR/5G-USXGMII) + * 10 Gbps (10G-USGMII) + * 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII) + * 25.78125 Gbps (25GBASE-KR/25GBASE-CR/25GBASE-SR/25GBASE-LR/25GBASE-ER) + +properties: + $nodename: + pattern: "^serdes@[0-9a-f]+$" + + compatible: + const: microchip,sparx5-serdes + + reg: + minItems: 1 + + '#phy-cells': + const: 1 + description: | + - The main serdes input port + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - '#phy-cells' + - clocks + +additionalProperties: false + +examples: + - | + serdes: serdes@10808000 { + compatible = "microchip,sparx5-serdes"; + #phy-cells = <1>; + clocks = <&sys_clk>; + reg = <0x10808000 0x5d0000>; + }; + +... diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt index 38c5fa21f435f1f237028abb0c90ffb5f19c5c29..b62397d2bb0c6c3bec82108bbae26504976cb1d8 100644 --- a/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt +++ b/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt @@ -54,6 +54,7 @@ For Tegra210: - avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. - dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. - hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V. +- nvidia,pmc: phandle and specifier referring to the Tegra210 PMC node. For Tegra186: - avdd-pll-erefeut-supply: UPHY brick and reference clock as well as UTMI PHY diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml index d210843863df084b646b5f07224117c7086562fd..84383e2e0b34d254fe2406a9cb35900d991280a8 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml @@ -26,6 +26,9 @@ properties: '#size-cells': const: 0 + '#clock-cells': + const: 1 + resets: minItems: 1 maxItems: 2 @@ -49,12 +52,24 @@ properties: const: serdes clocks: - maxItems: 2 + minItems: 2 + maxItems: 4 clock-names: + minItems: 2 items: - const: cmn_refclk_dig_div - const: cmn_refclk1_dig_div + - const: pll0_refclk + - const: pll1_refclk + + assigned-clocks: + minItems: 1 + maxItems: 2 + + assigned-clock-parents: + minItems: 1 + maxItems: 2 cdns,autoconf: type: boolean diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index e266ade53d87aef686221606ad54d72aeafc6b55..01dcd14e7b2ad21248efdd588efcaf279d1fa54e 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -28,13 +28,27 @@ properties: '#size-cells': const: 0 + '#clock-cells': + const: 1 + clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 description: - PHY reference clock. Must contain an entry in clock-names. + PHY reference clock for 1 item. Must contain an entry in clock-names. + Optional Parent to enable output reference clock. clock-names: - const: refclk + minItems: 1 + items: + - const: refclk + - const: phy_en_refclk + + assigned-clocks: + maxItems: 3 + + assigned-clock-parents: + maxItems: 3 reg: minItems: 1 @@ -170,7 +184,7 @@ examples: }; - | #include <dt-bindings/phy/phy.h> - #include <dt-bindings/phy/phy-cadence-torrent.h> + #include <dt-bindings/phy/phy-cadence.h> bus { #address-cells = <2>; diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt b/Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt deleted file mode 100644 index aa99ceec73b036892cceab32eeaa10825bdaa3ef..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt +++ /dev/null @@ -1,38 +0,0 @@ -MVEBU A3700 UTMI PHY --------------------- - -USB2 UTMI+ PHY controllers can be found on the following Marvell MVEBU SoCs: -* Armada 3700 - -On Armada 3700, there are two USB controllers, one is compatible with the USB2 -and USB3 specifications and supports OTG. The other one is USB2 compliant and -only supports host mode. Both of these controllers come with a slightly -different UTMI PHY. - -Required Properties: - -- compatible: Should be one of: - * "marvell,a3700-utmi-host-phy" for the PHY connected to - the USB2 host-only controller. - * "marvell,a3700-utmi-otg-phy" for the PHY connected to - the USB3 and USB2 OTG capable controller. -- reg: PHY IP register range. -- marvell,usb-misc-reg: handle on the "USB miscellaneous registers" shared - region covering registers related to both the host - controller and the PHY. -- #phy-cells: Standard property (Documentation: phy-bindings.txt) Should be 0. - - -Example: - - usb2_utmi_host_phy: phy@5f000 { - compatible = "marvell,armada-3700-utmi-host-phy"; - reg = <0x5f000 0x800>; - marvell,usb-misc-reg = <&usb2_syscon>; - #phy-cells = <0>; - }; - - usb2_syscon: system-controller@5f800 { - compatible = "marvell,armada-3700-usb2-host-misc", "syscon"; - reg = <0x5f800 0x800>; - }; diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml index 46df6786727a6b40343ddb454469a5c51246b4fb..018cc1246ee1917ac8a8510a16752708e886386f 100644 --- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml +++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml @@ -51,6 +51,10 @@ properties: vdda1v8-supply: description: regulator providing 1V8 power supply to the PLL block + '#clock-cells': + description: number of clock cells for ck_usbo_48m consumer + const: 0 + #Required child nodes: patternProperties: @@ -120,6 +124,7 @@ examples: vdda1v8-supply = <®18>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <0>; usbphyc_port0: usb-phy@0 { reg = <0>; diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml index 626447fee09252d179e40b5192edc757159245c3..7808ec8bc7128032366a6582aab043a3e2a2e1b5 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml @@ -25,11 +25,13 @@ properties: - qcom,msm8998-qmp-pcie-phy - qcom,msm8998-qmp-ufs-phy - qcom,msm8998-qmp-usb3-phy + - qcom,sc7180-qmp-usb3-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8180x-qmp-usb3-phy - qcom,sdm845-qhp-pcie-phy - qcom,sdm845-qmp-pcie-phy - qcom,sdm845-qmp-ufs-phy + - qcom,sdm845-qmp-usb3-phy - qcom,sdm845-qmp-usb3-uni-phy - qcom,sm8150-qmp-ufs-phy - qcom,sm8150-qmp-usb3-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml index 33974ad10afe4749a5cc961fe6cca8778fbc5090..217aa6c91893d250991d407d8fdb6037b0c643f8 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml @@ -14,9 +14,8 @@ properties: compatible: enum: - qcom,sc7180-qmp-usb3-dp-phy - - qcom,sc7180-qmp-usb3-phy - qcom,sdm845-qmp-usb3-dp-phy - - qcom,sdm845-qmp-usb3-phy + - qcom,sm8250-qmp-usb3-dp-phy reg: items: - description: Address and length of PHY's USB serdes block. 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 ee77c645832667d70ed150d634a66215dce48cb1..20203a8a9e41a76a37e3f345d353d1b20bdc7bac 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml @@ -16,6 +16,7 @@ properties: compatible: enum: - qcom,usb-snps-hs-7nm-phy + - qcom,sc7280-usb-hs-phy - qcom,sm8150-usb-hs-phy - qcom,sm8250-usb-hs-phy - qcom,sm8350-usb-hs-phy diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml index bbbd85501ada84565dd648da6057917f8b9192e8..57e1d013a5028badeaf05f5ed88c68d946c9e73c 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml @@ -15,6 +15,7 @@ properties: enum: - ti,j721e-wiz-16g - ti,j721e-wiz-10g + - ti,am64-wiz-10g power-domains: maxItems: 1 @@ -42,6 +43,9 @@ properties: "#reset-cells": const: 1 + "#clock-cells": + const: 1 + ranges: true assigned-clocks: diff --git a/Documentation/devicetree/bindings/power/brcm,bcm-pmb.yaml b/Documentation/devicetree/bindings/power/brcm,bcm-pmb.yaml index 40b08d83c80bf57c9cb9b032726648d11acb1d69..f8e7ddbd270595c0f4a0948316e2071e4487d589 100644 --- a/Documentation/devicetree/bindings/power/brcm,bcm-pmb.yaml +++ b/Documentation/devicetree/bindings/power/brcm,bcm-pmb.yaml @@ -16,6 +16,7 @@ properties: compatible: enum: - brcm,bcm4908-pmb + - brcm,bcm63138-pmb reg: description: register space of one or more buses diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 1ea21acbbd55480bfb46868f81f826038d58b57a..ff21bfef8204a745dc226523ec9a7bba514d17ef 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -25,10 +25,12 @@ properties: - qcom,qcs404-rpmpd - qcom,sdm660-rpmpd - qcom,sc7180-rpmhpd + - qcom,sc7280-rpmhpd - qcom,sdm845-rpmhpd - qcom,sdx55-rpmhpd - qcom,sm8150-rpmhpd - qcom,sm8250-rpmhpd + - qcom,sm8350-rpmhpd '#power-domain-cells': const: 1 diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt index e7fc045281d10c05213b0abeca47477d336512be..013f096ac0aafe4c3aecb5ee7e343658663b07f2 100644 --- a/Documentation/devicetree/bindings/regulator/fan53555.txt +++ b/Documentation/devicetree/bindings/regulator/fan53555.txt @@ -1,8 +1,8 @@ Binding for Fairchild FAN53555 regulators Required properties: - - compatible: one of "fcs,fan53555", "fcs,fan53526", "silergy,syr827" or - "silergy,syr828" + - compatible: one of "fcs,fan53555", "fcs,fan53526", "silergy,syr827", + "silergy,syr828" or "tcs,tcs4525". - reg: I2C address Optional properties: diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt deleted file mode 100644 index ce1e04354006db449946b5b73254487d3a6ef174..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt +++ /dev/null @@ -1,180 +0,0 @@ -Qualcomm Technologies, Inc. RPMh Regulators - -rpmh-regulator devices support PMIC regulator management via the Voltage -Regulator Manager (VRM) and Oscillator Buffer (XOB) RPMh accelerators. The APPS -processor communicates with these hardware blocks via a Resource State -Coordinator (RSC) using command packets. The VRM allows changing three -parameters for a given regulator: enable state, output voltage, and operating -mode. The XOB allows changing only a single parameter for a given regulator: -its enable state. Despite its name, the XOB is capable of controlling the -enable state of any PMIC peripheral. It is used for clock buffers, low-voltage -switches, and LDO/SMPS regulators which have a fixed voltage and mode. - -======================= -Required Node Structure -======================= - -RPMh regulators must be described in two levels of device nodes. The first -level describes the PMIC containing the regulators and must reside within an -RPMh device node. The second level describes each regulator within the PMIC -which is to be used on the board. Each of these regulators maps to a single -RPMh resource. - -The names used for regulator nodes must match those supported by a given PMIC. -Supported regulator node names: - PM8005: smps1 - smps4 - PM8009: smps1 - smps2, ldo1 - ldo7 - PM8150: smps1 - smps10, ldo1 - ldo18 - PM8150L: smps1 - smps8, ldo1 - ldo11, bob, flash, rgb - PM8350: smps1 - smps12, ldo1 - ldo10, - PM8350C: smps1 - smps10, ldo1 - ldo13, bob - PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 - PMI8998: bob - PM6150: smps1 - smps5, ldo1 - ldo19 - PM6150L: smps1 - smps8, ldo1 - ldo11, bob - PMX55: smps1 - smps7, ldo1 - ldo16 - -======================== -First Level Nodes - PMIC -======================== - -- compatible - Usage: required - Value type: <string> - Definition: Must be one of below: - "qcom,pm8005-rpmh-regulators" - "qcom,pm8009-rpmh-regulators" - "qcom,pm8009-1-rpmh-regulators" - "qcom,pm8150-rpmh-regulators" - "qcom,pm8150l-rpmh-regulators" - "qcom,pm8350-rpmh-regulators" - "qcom,pm8350c-rpmh-regulators" - "qcom,pm8998-rpmh-regulators" - "qcom,pmc8180-rpmh-regulators" - "qcom,pmc8180c-rpmh-regulators" - "qcom,pmi8998-rpmh-regulators" - "qcom,pm6150-rpmh-regulators" - "qcom,pm6150l-rpmh-regulators" - "qcom,pmx55-rpmh-regulators" - -- qcom,pmic-id - Usage: required - Value type: <string> - Definition: RPMh resource name suffix used for the regulators found on - this PMIC. Typical values: "a", "b", "c", "d", "e", "f". - -- vdd-s1-supply -- vdd-s2-supply -- vdd-s3-supply -- vdd-s4-supply - Usage: optional (PM8998 and PM8005 only) - Value type: <phandle> - Definition: phandle of the parent supply regulator of one or more of the - regulators for this PMIC. - -- vdd-s5-supply -- vdd-s6-supply -- vdd-s7-supply -- vdd-s8-supply -- vdd-s9-supply -- vdd-s10-supply -- vdd-s11-supply -- vdd-s12-supply -- vdd-s13-supply -- vdd-l1-l27-supply -- vdd-l2-l8-l17-supply -- vdd-l3-l11-supply -- vdd-l4-l5-supply -- vdd-l6-supply -- vdd-l7-l12-l14-l15-supply -- vdd-l9-supply -- vdd-l10-l23-l25-supply -- vdd-l13-l19-l21-supply -- vdd-l16-l28-supply -- vdd-l18-l22-supply -- vdd-l20-l24-supply -- vdd-l26-supply -- vin-lvs-1-2-supply - Usage: optional (PM8998 only) - Value type: <phandle> - Definition: phandle of the parent supply regulator of one or more of the - regulators for this PMIC. - -- vdd-bob-supply - Usage: optional (PMI8998 only) - Value type: <phandle> - Definition: BOB regulator parent supply phandle - -=============================== -Second Level Nodes - Regulators -=============================== - -- qcom,always-wait-for-ack - Usage: optional - Value type: <empty> - Definition: Boolean flag which indicates that the application processor - must wait for an ACK or a NACK from RPMh for every request - sent for this regulator including those which are for a - strictly lower power state. - -Other properties defined in Documentation/devicetree/bindings/regulator/regulator.txt -may also be used. regulator-initial-mode and regulator-allowed-modes may be -specified for VRM regulators using mode values from -include/dt-bindings/regulator/qcom,rpmh-regulator.h. regulator-allow-bypass -may be specified for BOB type regulators managed via VRM. -regulator-allow-set-load may be specified for LDO type regulators managed via -VRM. - -======== -Examples -======== - -#include <dt-bindings/regulator/qcom,rpmh-regulator.h> - -&apps_rsc { - pm8998-rpmh-regulators { - compatible = "qcom,pm8998-rpmh-regulators"; - qcom,pmic-id = "a"; - - vdd-l7-l12-l14-l15-supply = <&pm8998_s5>; - - smps2 { - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1100000>; - }; - - pm8998_s5: smps5 { - regulator-min-microvolt = <1904000>; - regulator-max-microvolt = <2040000>; - }; - - ldo7 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; - regulator-allowed-modes = - <RPMH_REGULATOR_MODE_LPM - RPMH_REGULATOR_MODE_HPM>; - regulator-allow-set-load; - }; - - lvs1 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - }; - - pmi8998-rpmh-regulators { - compatible = "qcom,pmi8998-rpmh-regulators"; - qcom,pmic-id = "b"; - - bob { - regulator-min-microvolt = <3312000>; - regulator-max-microvolt = <3600000>; - regulator-allowed-modes = - <RPMH_REGULATOR_MODE_AUTO - RPMH_REGULATOR_MODE_HPM>; - regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e561a5b941e46a12bdc1616c56263e75dbe08f16 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -0,0 +1,162 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/qcom,rpmh-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. RPMh Regulators + +maintainers: + - David Collins <collinsd@codeaurora.org> + +description: | + rpmh-regulator devices support PMIC regulator management via the Voltage + Regulator Manager (VRM) and Oscillator Buffer (XOB) RPMh accelerators. + The APPS processor communicates with these hardware blocks via a + Resource State Coordinator (RSC) using command packets. The VRM allows + changing three parameters for a given regulator, enable state, output + voltage, and operating mode. The XOB allows changing only a single + parameter for a given regulator, its enable state. Despite its name, + the XOB is capable of controlling the enable state of any PMIC peripheral. + It is used for clock buffers, low-voltage switches, and LDO/SMPS regulators + which have a fixed voltage and mode. + + ======================= + Required Node Structure + ======================= + + RPMh regulators must be described in two levels of device nodes. The first + level describes the PMIC containing the regulators and must reside within an + RPMh device node. The second level describes each regulator within the PMIC + which is to be used on the board. Each of these regulators maps to a single + RPMh resource. + + The names used for regulator nodes must match those supported by a given + PMIC. Supported regulator node names are + For PM8005, smps1 - smps4 + For PM8009, smps1 - smps2, ldo1 - ldo7 + For PM8150, smps1 - smps10, ldo1 - ldo18 + For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb + For PM8350, smps1 - smps12, ldo1 - ldo10 + For PM8350C, smps1 - smps10, ldo1 - ldo13, bob + For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 + For PMI8998, bob + For PM6150, smps1 - smps5, ldo1 - ldo19 + For PM6150L, smps1 - smps8, ldo1 - ldo11, bob + For PMX55, smps1 - smps7, ldo1 - ldo16 + For PM7325, smps1 - smps8, ldo1 - ldo19 + For PMR735A, smps1 - smps3, ldo1 - ldo7 + +properties: + compatible: + enum: + - qcom,pm8005-rpmh-regulators + - qcom,pm8009-rpmh-regulators + - qcom,pm8009-1-rpmh-regulators + - qcom,pm8150-rpmh-regulators + - qcom,pm8150l-rpmh-regulators + - qcom,pm8350-rpmh-regulators + - qcom,pm8350c-rpmh-regulators + - qcom,pm8998-rpmh-regulators + - qcom,pmi8998-rpmh-regulators + - qcom,pm6150-rpmh-regulators + - qcom,pm6150l-rpmh-regulators + - qcom,pmx55-rpmh-regulators + - qcom,pm7325-rpmh-regulators + - qcom,pmr735a-rpmh-regulators + + qcom,pmic-id: + description: | + RPMh resource name suffix used for the regulators found + on this PMIC. + $ref: /schemas/types.yaml#/definitions/string + enum: [a, b, c, d, e, f] + + qcom,always-wait-for-ack: + description: | + Boolean flag which indicates that the application processor + must wait for an ACK or a NACK from RPMh for every request + sent for this regulator including those which are for a + strictly lower power state. + $ref: /schemas/types.yaml#/definitions/flag + + vdd-flash-supply: + description: Input supply phandle of flash. + + vdd-rgb-supply: + description: Input supply phandle of rgb. + + vin-lvs-1-2-supply: + description: Input supply phandle of one or more regulators. + + vdd-bob-supply: + description: BOB regulator parent supply phandle. + + bob: + type: object + $ref: "regulator.yaml#" + description: BOB regulator node. + +patternProperties: + "^vdd-s([0-9]+)-supply$": + description: Input supply phandle(s) of one or more regulators. + + "^vdd-(l[0-9]+[-]){1,5}supply$": + description: Input supply phandle(s) of one or more regulators. + + "^(smps|ldo|lvs)[0-9]+$": + type: object + $ref: "regulator.yaml#" + description: smps/ldo regulator nodes(s). + +additionalProperties: false + +required: + - compatible + - qcom,pmic-id + +examples: + - | + #include <dt-bindings/regulator/qcom,rpmh-regulator.h> + + pm8998-rpmh-regulators { + compatible = "qcom,pm8998-rpmh-regulators"; + qcom,pmic-id = "a"; + + vdd-l7-l12-l14-l15-supply = <&pm8998_s5>; + + smps2 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + ldo7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-allowed-modes = + <RPMH_REGULATOR_MODE_LPM + RPMH_REGULATOR_MODE_HPM>; + regulator-allow-set-load; + }; + + lvs1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + + pmi8998-rpmh-regulators { + compatible = "qcom,pmi8998-rpmh-regulators"; + qcom,pmic-id = "b"; + + bob { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3600000>; + regulator-allowed-modes = + <RPMH_REGULATOR_MODE_AUTO + RPMH_REGULATOR_MODE_HPM>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/reserved-memory/ramoops.txt b/Documentation/devicetree/bindings/reserved-memory/ramoops.txt index b7886fea368ce107c0b007f4792cfc400ee248a1..b571ef6dab0fc179a3a9fe49a6d4ddac240ac7f3 100644 --- a/Documentation/devicetree/bindings/reserved-memory/ramoops.txt +++ b/Documentation/devicetree/bindings/reserved-memory/ramoops.txt @@ -42,8 +42,14 @@ Optional properties: - pmsg-size: size in bytes of log buffer reserved for userspace messages (defaults to 0: disabled) -- unbuffered: if present, use unbuffered mappings to map the reserved region - (defaults to buffered mappings) +- mem-type: if present, sets the type of mapping is to be used to map the + reserved region. mem-type: 0 = write-combined (default), 1 = unbuffered, + 2 = cached. + +- unbuffered: deprecated, use mem_type instead. If present, and mem_type is + not specified, it is equivalent to mem_type = 1 and uses unbuffered mappings + to map the reserved region (defaults to buffered mappings mem_type = 0). If + both are specified -- "mem_type" overrides "unbuffered". - max-reason: if present, sets maximum type of kmsg dump reasons to store (defaults to 2: log Oopses and Panics). This can be set to INT_MAX to diff --git a/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml b/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml index c147900f9041ab93ed9ba0031551456fa8ee9ed6..6da674666d45610390e4819b8f26005df79a0326 100644 --- a/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml +++ b/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml @@ -28,6 +28,12 @@ properties: clock-names: const: ipsec + resets: + maxItems: 1 + + reset-names: + const: ipsec + interrupts: maxItems: 1 @@ -35,6 +41,18 @@ required: - compatible - reg +if: + properties: + compatible: + enum: + - brcm,bcm6368-rng +then: + required: + - clocks + - clock-names + - resets + - reset-names + additionalProperties: false examples: @@ -58,4 +76,7 @@ examples: clocks = <&periph_clk 18>; clock-names = "ipsec"; + + resets = <&periph_rst 4>; + reset-names = "ipsec"; }; diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml index f54cae9ff7b2865022c3d29dd81a9039b4bf7fa8..f0506a917793ddeb56153312ea5cdb565a5cd9cb 100644 --- a/Documentation/devicetree/bindings/serial/8250.yaml +++ b/Documentation/devicetree/bindings/serial/8250.yaml @@ -12,8 +12,13 @@ maintainers: allOf: - $ref: /schemas/serial.yaml# - if: - required: - - aspeed,sirq-polarity-sense + anyOf: + - required: + - aspeed,lpc-io-reg + - required: + - aspeed,lpc-interrupts + - required: + - aspeed,sirq-polarity-sense then: properties: compatible: @@ -55,6 +60,7 @@ properties: - const: aspeed,ast2500-vuart - const: intel,xscale-uart - const: mrvl,pxa-uart + - const: nuvoton,wpcm450-uart - const: nuvoton,npcm750-uart - const: nvidia,tegra20-uart - const: nxp,lpc3220-uart @@ -165,7 +171,6 @@ properties: property. tx-threshold: - $ref: /schemas/types.yaml#/definitions/uint32 description: | Specify the TX FIFO low water indication for parts with programmable TX FIFO thresholds. @@ -188,6 +193,21 @@ properties: offset and bit number to identify how the SIRQ polarity should be configured. One possible data source is the LPC/eSPI mode bit. Only applicable to aspeed,ast2500-vuart. + deprecated: true + + aspeed,lpc-io-reg: + $ref: '/schemas/types.yaml#/definitions/uint32' + description: | + The VUART LPC address. Only applicable to aspeed,ast2500-vuart. + + aspeed,lpc-interrupts: + $ref: "/schemas/types.yaml#/definitions/uint32-array" + minItems: 2 + maxItems: 2 + description: | + A 2-cell property describing the VUART SIRQ number and SIRQ + polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH). Only + applicable to aspeed,ast2500-vuart. required: - reg @@ -220,6 +240,7 @@ examples: }; - | #include <dt-bindings/clock/aspeed-clock.h> + #include <dt-bindings/interrupt-controller/irq.h> serial@1e787000 { compatible = "aspeed,ast2500-vuart"; reg = <0x1e787000 0x40>; @@ -227,7 +248,8 @@ examples: interrupts = <8>; clocks = <&syscon ASPEED_CLK_APB>; no-loopback-test; - aspeed,sirq-polarity-sense = <&syscon 0x70 25>; + aspeed,lpc-io-reg = <0x3f8>; + aspeed,lpc-interrupts = <4 IRQ_TYPE_LEVEL_LOW>; }; ... diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml b/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..46c62745f901e2fb0c2352500d25f681bd6c98d9 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/brcm,bcm7271-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom 8250 based serial port devicetree bindings + +maintainers: + - Al Cooper <alcooperx@gmail.com> + +allOf: + - $ref: /schemas/serial.yaml# + +description: |+ + The Broadcom UART is based on the basic 8250 UART but with + enhancements for more accurate high speed baud rates and support + for DMA. + +properties: + compatible: + items: + - enum: + - brcm,bcm7271-uart + - brcm,bcm7278-uart + + reg: + minItems: 1 + maxItems: 5 + + reg-names: + description: The UART register block and optionally the DMA register blocks. + oneOf: + - items: + - const: uart + - items: + - const: uart + - const: dma_arb + - const: dma_rx + - const: dma_tx + - const: dma_intr2 + + clocks: + minItems: 1 + + clock-names: + const: sw_baud + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + description: The UART interrupt and optionally the DMA interrupt. + minItems: 1 + items: + - const: uart + - const: dma + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + - interrupt-names + +unevaluatedProperties: false + +examples: + - | + serial@840d000 { + compatible = "brcm,bcm7271-uart"; + reg = <0x840d000 0x20>; + reg-names = "uart"; + interrupts = <0x0 0x62 0x4>; + interrupt-names = "uart"; + clocks = <&scmi_clk 190>; + clock-names = "sw_baud"; + }; + + serial@840e000 { + compatible = "brcm,bcm7271-uart"; + reg = <0x840e000 0x20>, + <0x840e080 0x8>, + <0x840e100 0xa8>, + <0x840e200 0x4c>, + <0x840e300 0x30>; + reg-names = "uart", "dma_arb", "dma_rx", "dma_tx", "dma_intr2"; + interrupts = <0x0 0x62 0x4>, <0x0 0x75 0x4>; + interrupt-names = "uart", "dma"; + clocks = <&scmi_clk 190>; + clock-names = "sw_baud"; + }; diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt index 647b5aee86f31015461d257826a6f6dada570575..64c4fb59acd1e6411668e4bcbc907d93a1ba4b06 100644 --- a/Documentation/devicetree/bindings/serial/mtk-uart.txt +++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt @@ -20,6 +20,7 @@ Required properties: * "mediatek,mt8173-uart" for MT8173 compatible UARTS * "mediatek,mt8183-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS * "mediatek,mt8192-uart", "mediatek,mt6577-uart" for MT8192 compatible UARTS + * "mediatek,mt8195-uart", "mediatek,mt6577-uart" for MT8195 compatible UARTS * "mediatek,mt8516-uart" for MT8516 compatible UARTS * "mediatek,mt6577-uart" for MT6577 and all of the above diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 21ee627b2cedf47779879b89734ee35cb6dd4362..97ec8a093bf303ee1fd1e13d4e864d45b6e394dd 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/serial/samsung_uart.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Samsung S3C, S5P and Exynos SoC UART Controller +title: Samsung S3C, S5P, Exynos, and S5L (Apple SoC) SoC UART Controller maintainers: - Krzysztof Kozlowski <krzk@kernel.org> @@ -19,6 +19,7 @@ properties: compatible: items: - enum: + - apple,s5l-uart - samsung,s3c2410-uart - samsung,s3c2412-uart - samsung,s3c2440-uart @@ -51,6 +52,16 @@ properties: - pattern: '^clk_uart_baud[0-3]$' - pattern: '^clk_uart_baud[0-3]$' + dmas: + items: + - description: DMA controller phandle and request line for RX + - description: DMA controller phandle and request line for TX + + dma-names: + items: + - const: rx + - const: tx + interrupts: description: RX interrupt and optionally TX interrupt. minItems: 1 @@ -68,9 +79,11 @@ required: - interrupts - reg -additionalProperties: false +unevaluatedProperties: false allOf: + - $ref: /schemas/serial.yaml# + - if: properties: compatible: @@ -96,6 +109,7 @@ allOf: compatible: contains: enum: + - apple,s5l-uart - samsung,exynos4210-uart then: properties: diff --git a/Documentation/devicetree/bindings/serial/serial.yaml b/Documentation/devicetree/bindings/serial/serial.yaml index 65e75d04052178372be31517057a1e42f43b132b..f368d58e808608baa8a572b806480a29ec6aeff9 100644 --- a/Documentation/devicetree/bindings/serial/serial.yaml +++ b/Documentation/devicetree/bindings/serial/serial.yaml @@ -75,6 +75,16 @@ properties: type: boolean description: CTS and RTS pins are swapped. + rx-threshold: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + RX FIFO threshold configuration (in bytes). + + tx-threshold: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + TX FIFO threshold configuration (in bytes). + if: required: - uart-has-rtscts diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml index 8631678283f9aaf2db31085722780dc1eecfee63..71a6426bc558a1cbca2fd764acb931d08333410f 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml +++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml @@ -9,9 +9,6 @@ maintainers: title: STMicroelectronics STM32 USART bindings -allOf: - - $ref: rs485.yaml - properties: compatible: enum: @@ -40,6 +37,8 @@ properties: uart-has-rtscts: true + rx-tx-swap: true + dmas: minItems: 1 maxItems: 2 @@ -66,13 +65,46 @@ properties: linux,rs485-enabled-at-boot-time: true rs485-rx-during-tx: true -if: - required: - - st,hw-flow-ctrl -then: - properties: - cts-gpios: false - rts-gpios: false + rx-threshold: + description: + If value is set to 1, RX FIFO threshold is disabled. + enum: [1, 2, 4, 8, 12, 14, 16] + default: 8 + + tx-threshold: + description: + If value is set to 1, TX FIFO threshold is disabled. + enum: [1, 2, 4, 8, 12, 14, 16] + default: 8 + +allOf: + - $ref: rs485.yaml# + - $ref: serial.yaml# + - if: + required: + - st,hw-flow-ctrl + then: + properties: + cts-gpios: false + rts-gpios: false + - if: + properties: + compatible: + const: st,stm32-uart + then: + properties: + rx-tx-swap: false + - if: + properties: + compatible: + contains: + enum: + - st,stm32-uart + - st,stm32f7-uart + then: + properties: + rx-threshold: false + tx-threshold: false required: - compatible @@ -80,19 +112,22 @@ required: - interrupts - clocks -additionalProperties: false +additionalProperties: + type: object examples: - | #include <dt-bindings/clock/stm32mp1-clks.h> usart1: serial@40011000 { - compatible = "st,stm32-uart"; + compatible = "st,stm32h7-uart"; reg = <0x40011000 0x400>; interrupts = <37>; clocks = <&rcc 0 164>; dmas = <&dma2 2 4 0x414 0x0>, <&dma2 7 4 0x414 0x0>; dma-names = "rx", "tx"; + rx-threshold = <4>; + tx-threshold = <4>; rs485-rts-active-low; }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt index ecac2bbeae4592dafa5cad6de97bc0d8092d27c1..8051c17e640ef49f5f1b7880e2aaa771b45200b7 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt +++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt @@ -22,6 +22,7 @@ Required properties in pwrap device node. "mediatek,mt6765-pwrap" for MT6765 SoCs "mediatek,mt6779-pwrap" for MT6779 SoCs "mediatek,mt6797-pwrap" for MT6797 SoCs + "mediatek,mt6873-pwrap" for MT6873/8192 SoCs "mediatek,mt7622-pwrap" for MT7622 SoCs "mediatek,mt8135-pwrap" for MT8135 SoCs "mediatek,mt8173-pwrap" for MT8173 SoCs diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt index 19c059e44681cc3e52fe9e6ba00e51bd8378aafd..783dc81b0f26965df2d22443df23057cfb4650a8 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt @@ -17,6 +17,7 @@ power-domains. Value type: <string> Definition: must be one of: "qcom,sc7180-aoss-qmp" + "qcom,sc7280-aoss-qmp" "qcom,sdm845-aoss-qmp" "qcom,sm8150-aoss-qmp" "qcom,sm8250-aoss-qmp" diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.txt index 042a2e4159bd64db798a2efaa878ee3e7fd6efa5..1382b64e1381c14e113585f949c0cd8c995d7401 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.txt @@ -24,6 +24,13 @@ block and a BT, WiFi and FM radio block, all using SMD as command channels. "qcom,riva", "qcom,pronto" +- firmware-name: + Usage: optional + Value type: <string> + Definition: specifies the relative firmware image path for the WLAN NV + blob. Defaults to "wlan/prima/WCNSS_qcom_wlan_nv.bin" if + not specified. + = SUBNODES The subnodes of the wcnss node are optional and describe the individual blocks in the WCNSS. diff --git a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt index b104be131235db792adb10d428583edde0b8b724..b93a2b3e029d952c4bd76d4b3a98876dbdf0cb25 100644 --- a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt +++ b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt @@ -54,6 +54,8 @@ board specific bus parameters. Value type: <prop-encoded-array> Definition: should specify payload transport window offset1 of each data port. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-offset2: @@ -61,6 +63,8 @@ board specific bus parameters. Value type: <prop-encoded-array> Definition: should specify payload transport window offset2 of each data port. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-sinterval-low: @@ -69,12 +73,16 @@ board specific bus parameters. Definition: should be sample interval low of each data port. Out ports followed by In ports. Used for Sample Interval calculation. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-word-length: Usage: optional Value type: <prop-encoded-array> Definition: should be size of payload channel sample. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-block-pack-mode: @@ -84,6 +92,8 @@ board specific bus parameters. 0 to indicate Blocks are per Channel 1 to indicate Blocks are per Port. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-block-group-count: @@ -92,6 +102,8 @@ board specific bus parameters. Definition: should be in range 1 to 4 to indicate how many sample intervals are combined into a payload. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-lane-control: @@ -100,6 +112,8 @@ board specific bus parameters. Definition: should be in range 0 to 7 to identify which data lane the data port uses. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-hstart: @@ -109,6 +123,8 @@ board specific bus parameters. SoundWire Frame, i.e. left edge of the Transport sub-frame for each port. Values between 0 and 15 are valid. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-hstop: @@ -118,6 +134,8 @@ board specific bus parameters. SoundWire Frame, i.e. the right edge of the Transport sub-frame for each port. Values between 0 and 15 are valid. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,dports-type: @@ -128,6 +146,8 @@ board specific bus parameters. 1 for simple ports 2 for full port Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. Note: diff --git a/Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt b/Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt deleted file mode 100644 index d99a9cf3336b6e5d30ab1d2ceb5f604acd86d927..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt +++ /dev/null @@ -1,245 +0,0 @@ -Broadcom SPI controller - -The Broadcom SPI controller is a SPI master found on various SOCs, including -BRCMSTB (BCM7XXX), Cygnus, NSP and NS2. The Broadcom Master SPI hw IP consits -of : - MSPI : SPI master controller can read and write to a SPI slave device - BSPI : Broadcom SPI in combination with the MSPI hw IP provides acceleration - for flash reads and be configured to do single, double, quad lane - io with 3-byte and 4-byte addressing support. - - Supported Broadcom SoCs have one instance of MSPI+BSPI controller IP. - MSPI master can be used wihout BSPI. BRCMSTB SoCs have an additional instance - of a MSPI master without the BSPI to use with non flash slave devices that - use SPI protocol. - -Required properties: - -- #address-cells: - Must be <1>, as required by generic SPI binding. - -- #size-cells: - Must be <0>, also as required by generic SPI binding. - -- compatible: - Must be one of : - "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi" : MSPI+BSPI on BRCMSTB SoCs - "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-bcm7425-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-bcm7429-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-bcm7435-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-bcm7445-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-bcm7216-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-bcm7278-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI - BRCMSTB SoCs - "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi" : MSPI+BSPI on Cygnus, NSP - "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi" : NS2 SoCs - -- reg: - Define the bases and ranges of the associated I/O address spaces. - The required range is MSPI controller registers. - -- reg-names: - First name does not matter, but must be reserved for the MSPI controller - register range as mentioned in 'reg' above, and will typically contain - - "bspi_regs": BSPI register range, not required with compatible - "spi-brcmstb-mspi" - - "mspi_regs": MSPI register range is required for compatible strings - - "intr_regs", "intr_status_reg" : Interrupt and status register for - NSP, NS2, Cygnus SoC - -- interrupts - The interrupts used by the MSPI and/or BSPI controller. - -- interrupt-names: - Names of interrupts associated with MSPI - - "mspi_halted" : - - "mspi_done": Indicates that the requested SPI operation is complete. - - "spi_lr_fullness_reached" : Linear read BSPI pipe full - - "spi_lr_session_aborted" : Linear read BSPI pipe aborted - - "spi_lr_impatient" : Linear read BSPI requested when pipe empty - - "spi_lr_session_done" : Linear read BSPI session done - -- clocks: - A phandle to the reference clock for this block. - -Optional properties: - - -- native-endian - Defined when using BE SoC and device uses BE register read/write - -Recommended optional m25p80 properties: -- spi-rx-bus-width: Definition as per - Documentation/devicetree/bindings/spi/spi-bus.txt - -Examples: - -BRCMSTB SoC Example: - - SPI Master (MSPI+BSPI) for SPI-NOR access: - - spi@f03e3400 { - #address-cells = <0x1>; - #size-cells = <0x0>; - compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi"; - reg = <0xf03e0920 0x4 0xf03e3400 0x188 0xf03e3200 0x50>; - reg-names = "cs_reg", "mspi", "bspi"; - interrupts = <0x6 0x5 0x4 0x3 0x2 0x1 0x0>; - interrupt-parent = <0x1c>; - interrupt-names = "mspi_halted", - "mspi_done", - "spi_lr_overread", - "spi_lr_session_done", - "spi_lr_impatient", - "spi_lr_session_aborted", - "spi_lr_fullness_reached"; - - clocks = <&hif_spi>; - clock-names = "sw_spi"; - - m25p80@0 { - #size-cells = <0x2>; - #address-cells = <0x2>; - compatible = "m25p80"; - reg = <0x0>; - spi-max-frequency = <0x2625a00>; - spi-cpol; - spi-cpha; - m25p,fast-read; - - flash0.bolt@0 { - reg = <0x0 0x0 0x0 0x100000>; - }; - - flash0.macadr@100000 { - reg = <0x0 0x100000 0x0 0x10000>; - }; - - flash0.nvram@110000 { - reg = <0x0 0x110000 0x0 0x10000>; - }; - - flash0.kernel@120000 { - reg = <0x0 0x120000 0x0 0x400000>; - }; - - flash0.devtree@520000 { - reg = <0x0 0x520000 0x0 0x10000>; - }; - - flash0.splash@530000 { - reg = <0x0 0x530000 0x0 0x80000>; - }; - - flash0@0 { - reg = <0x0 0x0 0x0 0x4000000>; - }; - }; - }; - - - MSPI master for any SPI device : - - spi@f0416000 { - #address-cells = <1>; - #size-cells = <0>; - clocks = <&upg_fixed>; - compatible = "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi"; - reg = <0xf0416000 0x180>; - reg-names = "mspi"; - interrupts = <0x14>; - interrupt-parent = <&irq0_aon_intc>; - interrupt-names = "mspi_done"; - }; - -iProc SoC Example: - - qspi: spi@18027200 { - compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi"; - reg = <0x18027200 0x184>, - <0x18027000 0x124>, - <0x1811c408 0x004>, - <0x180273a0 0x01c>; - reg-names = "mspi_regs", "bspi_regs", "intr_regs", "intr_status_reg"; - interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = - "spi_lr_fullness_reached", - "spi_lr_session_aborted", - "spi_lr_impatient", - "spi_lr_session_done", - "mspi_done", - "mspi_halted"; - clocks = <&iprocmed>; - clock-names = "iprocmed"; - num-cs = <2>; - #address-cells = <1>; - #size-cells = <0>; - }; - - - NS2 SoC Example: - - qspi: spi@66470200 { - compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi"; - reg = <0x66470200 0x184>, - <0x66470000 0x124>, - <0x67017408 0x004>, - <0x664703a0 0x01c>; - reg-names = "mspi", "bspi", "intr_regs", - "intr_status_reg"; - interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "spi_l1_intr"; - clocks = <&iprocmed>; - clock-names = "iprocmed"; - num-cs = <2>; - #address-cells = <1>; - #size-cells = <0>; - }; - - - m25p80 node for NSP, NS2 - - &qspi { - flash: m25p80@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "m25p80"; - reg = <0x0>; - spi-max-frequency = <12500000>; - m25p,fast-read; - spi-cpol; - spi-cpha; - - partition@0 { - label = "boot"; - reg = <0x00000000 0x000a0000>; - }; - - partition@a0000 { - label = "env"; - reg = <0x000a0000 0x00060000>; - }; - - partition@100000 { - label = "system"; - reg = <0x00100000 0x00600000>; - }; - - partition@700000 { - label = "rootfs"; - reg = <0x00700000 0x01900000>; - }; - }; diff --git a/Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.yaml b/Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6ee19d49fd3ccefd300b180be7a1cc0975aa0c1e --- /dev/null +++ b/Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.yaml @@ -0,0 +1,198 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/brcm,spi-bcm-qspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom SPI controller + +maintainers: + - Kamal Dasu <kdasu.kdev@gmail.com> + - Rafał Miłecki <rafal@milecki.pl> + +description: | + The Broadcom SPI controller is a SPI master found on various SOCs, including + BRCMSTB (BCM7XXX), Cygnus, NSP and NS2. The Broadcom Master SPI hw IP consits + of: + MSPI : SPI master controller can read and write to a SPI slave device + BSPI : Broadcom SPI in combination with the MSPI hw IP provides acceleration + for flash reads and be configured to do single, double, quad lane + io with 3-byte and 4-byte addressing support. + + Supported Broadcom SoCs have one instance of MSPI+BSPI controller IP. + MSPI master can be used wihout BSPI. BRCMSTB SoCs have an additional instance + of a MSPI master without the BSPI to use with non flash slave devices that + use SPI protocol. + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + oneOf: + - description: Second Instance of MSPI BRCMSTB SoCs + items: + - enum: + - brcm,spi-bcm7425-qspi + - brcm,spi-bcm7429-qspi + - brcm,spi-bcm7435-qspi + - brcm,spi-bcm7445-qspi + - brcm,spi-bcm7216-qspi + - brcm,spi-bcm7278-qspi + - const: brcm,spi-bcm-qspi + - const: brcm,spi-brcmstb-mspi + - description: Second Instance of MSPI BRCMSTB SoCs + items: + - enum: + - brcm,spi-brcmstb-qspi + - brcm,spi-brcmstb-mspi + - brcm,spi-nsp-qspi + - brcm,spi-ns2-qspi + - const: brcm,spi-bcm-qspi + + reg: + minItems: 1 + maxItems: 5 + + reg-names: + minItems: 1 + maxItems: 5 + items: + - const: mspi + - const: bspi + - enum: [ intr_regs, intr_status_reg, cs_reg ] + - enum: [ intr_regs, intr_status_reg, cs_reg ] + - enum: [ intr_regs, intr_status_reg, cs_reg ] + + interrupts: + minItems: 1 + maxItems: 7 + + interrupt-names: + oneOf: + - minItems: 1 + maxItems: 7 + items: + - const: mspi_done + - const: mspi_halted + - const: spi_lr_fullness_reached + - const: spi_lr_session_aborted + - const: spi_lr_impatient + - const: spi_lr_session_done + - const: spi_lr_overread + - const: spi_l1_intr + + clocks: + maxItems: 1 + description: reference clock for this block + + native-endian: + $ref: /schemas/types.yaml#/definitions/flag + description: Defined when using BE SoC and device uses BE register read/write + +unevaluatedProperties: false + +required: + - reg + - reg-names + - interrupts + - interrupt-names + +examples: + - | # BRCMSTB SoC: SPI Master (MSPI+BSPI) for SPI-NOR access + spi@f03e3400 { + compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi"; + reg = <0xf03e3400 0x188>, <0xf03e3200 0x50>, <0xf03e0920 0x4>; + reg-names = "mspi", "bspi", "cs_reg"; + interrupts = <0x5>, <0x6>, <0x1>, <0x2>, <0x3>, <0x4>, <0x0>; + interrupt-parent = <&gic>; + interrupt-names = "mspi_done", + "mspi_halted", + "spi_lr_fullness_reached", + "spi_lr_session_aborted", + "spi_lr_impatient", + "spi_lr_session_done", + "spi_lr_overread"; + clocks = <&hif_spi>; + #address-cells = <0x1>; + #size-cells = <0x0>; + + flash@0 { + #size-cells = <0x2>; + #address-cells = <0x2>; + compatible = "m25p80"; + reg = <0x0>; + spi-max-frequency = <0x2625a00>; + spi-cpol; + spi-cpha; + }; + }; + - | # BRCMSTB SoC: MSPI master for any SPI device + spi@f0416000 { + clocks = <&upg_fixed>; + compatible = "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi"; + reg = <0xf0416000 0x180>; + reg-names = "mspi"; + interrupts = <0x14>; + interrupt-parent = <&irq0_aon_intc>; + interrupt-names = "mspi_done"; + #address-cells = <1>; + #size-cells = <0>; + }; + - | # iProc SoC + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + spi@18027200 { + compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi"; + reg = <0x18027200 0x184>, + <0x18027000 0x124>, + <0x1811c408 0x004>, + <0x180273a0 0x01c>; + reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg"; + interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "mspi_done", + "mspi_halted", + "spi_lr_fullness_reached", + "spi_lr_session_aborted", + "spi_lr_impatient", + "spi_lr_session_done"; + clocks = <&iprocmed>; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + - | # NS2 SoC + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + spi@66470200 { + compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi"; + reg = <0x66470200 0x184>, + <0x66470000 0x124>, + <0x67017408 0x004>, + <0x664703a0 0x01c>; + reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg"; + interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "spi_l1_intr"; + clocks = <&iprocmed>; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "m25p80"; + reg = <0x0>; + spi-max-frequency = <12500000>; + spi-cpol; + spi-cpha; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/cadence-quadspi.txt b/Documentation/devicetree/bindings/spi/cadence-quadspi.txt deleted file mode 100644 index 8ace832a2d80ced376f28ed96f9a310b19209bbb..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/spi/cadence-quadspi.txt +++ /dev/null @@ -1,68 +0,0 @@ -* Cadence Quad SPI controller - -Required properties: -- compatible : should be one of the following: - Generic default - "cdns,qspi-nor". - For TI 66AK2G SoC - "ti,k2g-qspi", "cdns,qspi-nor". - For TI AM654 SoC - "ti,am654-ospi", "cdns,qspi-nor". - For Intel LGM SoC - "intel,lgm-qspi", "cdns,qspi-nor". -- reg : Contains two entries, each of which is a tuple consisting of a - physical address and length. The first entry is the address and - length of the controller register set. The second entry is the - address and length of the QSPI Controller data area. -- interrupts : Unit interrupt specifier for the controller interrupt. -- clocks : phandle to the Quad SPI clock. -- cdns,fifo-depth : Size of the data FIFO in words. -- cdns,fifo-width : Bus width of the data FIFO in bytes. -- cdns,trigger-address : 32-bit indirect AHB trigger address. - -Optional properties: -- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not. -- cdns,rclk-en : Flag to indicate that QSPI return clock is used to latch - the read data rather than the QSPI clock. Make sure that QSPI return - clock is populated on the board before using this property. - -Optional subnodes: -Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional -custom properties: -- cdns,read-delay : Delay for read capture logic, in clock cycles -- cdns,tshsl-ns : Delay in nanoseconds for the length that the master - mode chip select outputs are de-asserted between - transactions. -- cdns,tsd2d-ns : Delay in nanoseconds between one chip select being - de-activated and the activation of another. -- cdns,tchsh-ns : Delay in nanoseconds between last bit of current - transaction and deasserting the device chip select - (qspi_n_ss_out). -- cdns,tslch-ns : Delay in nanoseconds between setting qspi_n_ss_out low - and first bit transfer. -- resets : Must contain an entry for each entry in reset-names. - See ../reset/reset.txt for details. -- reset-names : Must include either "qspi" and/or "qspi-ocp". - -Example: - - qspi: spi@ff705000 { - compatible = "cdns,qspi-nor"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0xff705000 0x1000>, - <0xffa00000 0x1000>; - interrupts = <0 151 4>; - clocks = <&qspi_clk>; - cdns,is-decoded-cs; - cdns,fifo-depth = <128>; - cdns,fifo-width = <4>; - cdns,trigger-address = <0x00000000>; - resets = <&rst QSPI_RESET>, <&rst QSPI_OCP_RESET>; - reset-names = "qspi", "qspi-ocp"; - - flash0: n25q00@0 { - ... - cdns,read-delay = <4>; - cdns,tshsl-ns = <50>; - cdns,tsd2d-ns = <50>; - cdns,tchsh-ns = <4>; - cdns,tslch-ns = <4>; - }; - }; diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0e7087cc8bf95ea10fe40bf5364a0412b610ece7 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/cdns,qspi-nor.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cadence Quad SPI controller + +maintainers: + - Pratyush Yadav <p.yadav@ti.com> + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - ti,k2g-qspi + - ti,am654-ospi + - intel,lgm-qspi + - const: cdns,qspi-nor + - const: cdns,qspi-nor + + reg: + items: + - description: the controller register set + - description: the controller data area + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + cdns,fifo-depth: + description: + Size of the data FIFO in words. + $ref: "/schemas/types.yaml#/definitions/uint32" + enum: [ 128, 256 ] + default: 128 + + cdns,fifo-width: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Bus width of the data FIFO in bytes. + default: 4 + + cdns,trigger-address: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + 32-bit indirect AHB trigger address. + + cdns,is-decoded-cs: + type: boolean + description: + Flag to indicate whether decoder is used to select different chip select + for different memory regions. + + cdns,rclk-en: + type: boolean + description: + Flag to indicate that QSPI return clock is used to latch the read + data rather than the QSPI clock. Make sure that QSPI return clock + is populated on the board before using this property. + + resets: + maxItems: 2 + + reset-names: + minItems: 1 + maxItems: 2 + items: + enum: [ qspi, qspi-ocp ] + +# subnode's properties +patternProperties: + "@[0-9a-f]+$": + type: object + description: + Flash device uses the below defined properties in the subnode. + + properties: + cdns,read-delay: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Delay for read capture logic, in clock cycles. + + cdns,tshsl-ns: + description: + Delay in nanoseconds for the length that the master mode chip select + outputs are de-asserted between transactions. + + cdns,tsd2d-ns: + description: + Delay in nanoseconds between one chip select being de-activated + and the activation of another. + + cdns,tchsh-ns: + description: + Delay in nanoseconds between last bit of current transaction and + deasserting the device chip select (qspi_n_ss_out). + + cdns,tslch-ns: + description: + Delay in nanoseconds between setting qspi_n_ss_out low and + first bit transfer. + +required: + - compatible + - reg + - interrupts + - clocks + - cdns,fifo-depth + - cdns,fifo-width + - cdns,trigger-address + - '#address-cells' + - '#size-cells' + +unevaluatedProperties: false + +examples: + - | + qspi: spi@ff705000 { + compatible = "cdns,qspi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xff705000 0x1000>, + <0xffa00000 0x1000>; + interrupts = <0 151 4>; + clocks = <&qspi_clk>; + cdns,fifo-depth = <128>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x00000000>; + resets = <&rst 0x1>, <&rst 0x2>; + reset-names = "qspi", "qspi-ocp"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml b/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e586445584124bf0afdff8cdb6b89e6752cb3a72 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/fsl,spi-fsl-qspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale Quad Serial Peripheral Interface (QuadSPI) + +maintainers: + - Han Xu <han.xu@nxp.com> + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + oneOf: + - enum: + - fsl,vf610-qspi + - fsl,imx6sx-qspi + - fsl,imx7d-qspi + - fsl,imx6ul-qspi + - fsl,ls1021a-qspi + - fsl,ls2080a-qspi + - items: + - enum: + - fsl,ls1043a-qspi + - const: fsl,ls1021a-qspi + - items: + - enum: + - fsl,imx8mq-qspi + - const: fsl,imx7d-qspi + + reg: + items: + - description: registers + - description: memory mapping + + reg-names: + items: + - const: QuadSPI + - const: QuadSPI-memory + + interrupts: + maxItems: 1 + + clocks: + items: + - description: SoC SPI qspi_en clock + - description: SoC SPI qspi clock + + clock-names: + items: + - const: qspi_en + - const: qspi + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/fsl,qoriq-clockgen.h> + + soc { + #address-cells = <2>; + #size-cells = <2>; + + spi@1550000 { + compatible = "fsl,ls1021a-qspi"; + reg = <0x0 0x1550000 0x0 0x100000>, + <0x0 0x40000000 0x0 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL QORIQ_CLK_PLL_DIV(2)>, + <&clockgen QORIQ_CLK_PLATFORM_PLL QORIQ_CLK_PLL_DIV(2)>; + clock-names = "qspi_en", "qspi"; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml index 55c239446a5be86474f9eb824a01220437bcadba..7393f30535df5bd9d6831921718d02617c288fff 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml @@ -31,6 +31,7 @@ properties: - mediatek,mt7623-nor - mediatek,mt7629-nor - mediatek,mt8192-nor + - mediatek,mt8195-nor - enum: - mediatek,mt8173-nor - items: diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt deleted file mode 100644 index 69dc5d57b1efbe73324b6e17df474317e1ef684a..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt +++ /dev/null @@ -1,66 +0,0 @@ -* Freescale Quad Serial Peripheral Interface(QuadSPI) - -Required properties: - - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", - "fsl,imx7d-qspi", "fsl,imx6ul-qspi", - "fsl,ls1021a-qspi", "fsl,ls2080a-qspi" - or - "fsl,ls1043a-qspi" followed by "fsl,ls1021a-qspi" - - reg : the first contains the register location and length, - the second contains the memory mapping address and length - - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" - - interrupts : Should contain the interrupt for the device - - clocks : The clocks needed by the QuadSPI controller - - clock-names : Should contain the name of the clocks: "qspi_en" and "qspi". - -Required SPI slave node properties: - - reg: There are two buses (A and B) with two chip selects each. - This encodes to which bus and CS the flash is connected: - <0>: Bus A, CS 0 - <1>: Bus A, CS 1 - <2>: Bus B, CS 0 - <3>: Bus B, CS 1 - -Example: - -qspi0: quadspi@40044000 { - compatible = "fsl,vf610-qspi"; - reg = <0x40044000 0x1000>, <0x20000000 0x10000000>; - reg-names = "QuadSPI", "QuadSPI-memory"; - interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks VF610_CLK_QSPI0_EN>, - <&clks VF610_CLK_QSPI0>; - clock-names = "qspi_en", "qspi"; - - flash0: s25fl128s@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,s25fl128s", "jedec,spi-nor"; - spi-max-frequency = <50000000>; - reg = <0>; - }; -}; - -Example showing the usage of two SPI NOR devices on bus A: - -&qspi2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_qspi2>; - status = "okay"; - - flash0: n25q256a@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "micron,n25q256a", "jedec,spi-nor"; - spi-max-frequency = <29000000>; - reg = <0>; - }; - - flash1: n25q256a@1 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "micron,n25q256a", "jedec,spi-nor"; - spi-max-frequency = <29000000>; - reg = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt index 9e43721fa7d65c2620163c4d9d2e79df9fffa7d3..4d0e4c15c4ea79a2ec83fa04f19a560df6a47988 100644 --- a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt +++ b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt @@ -12,7 +12,9 @@ Required properties: - mediatek,mt8173-spi: for mt8173 platforms - mediatek,mt8183-spi: for mt8183 platforms - "mediatek,mt8192-spi", "mediatek,mt6765-spi": for mt8192 platforms + - "mediatek,mt8195-spi", "mediatek,mt6765-spi": for mt8195 platforms - "mediatek,mt8516-spi", "mediatek,mt2712-spi": for mt8516 platforms + - "mediatek,mt6779-spi", "mediatek,mt6765-spi": for mt6779 platforms - #address-cells: should be 1. diff --git a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt index 7ac60d9fe3571f617329b703ff5d8b3d05c2657b..8f34a7c7d8b843489dbf1e2323ab7ab0f5b2d294 100644 --- a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt @@ -4,6 +4,8 @@ Required properties: - compatible : Should be "nxp,lx2160a-fspi" "nxp,imx8qxp-fspi" "nxp,imx8mm-fspi" + "nxp,imx8mp-fspi" + "nxp,imx8dxl-fspi" - reg : First contains the register location and length, Second contains the memory mapping address and length diff --git a/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt b/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt index c37e5a179b21ecbd77de86799c1890bc0541384f..9192724540fd9ac0990ace30130af84019959edd 100644 --- a/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt +++ b/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt @@ -3,6 +3,7 @@ Binding for MTK SPI Slave controller Required properties: - compatible: should be one of the following. - mediatek,mt2712-spi-slave: for mt2712 platforms + - mediatek,mt8195-spi-slave: for mt8195 platforms - reg: Address and length of the register set for the device. - interrupts: Should contain spi interrupt. - clocks: phandles to input clocks. diff --git a/Documentation/devicetree/bindings/submitting-patches.rst b/Documentation/devicetree/bindings/submitting-patches.rst index 68129ff09967d5d76010494bb094506ca5420f3d..1d11c25249ff546513864f32bb2dfef769923b96 100644 --- a/Documentation/devicetree/bindings/submitting-patches.rst +++ b/Documentation/devicetree/bindings/submitting-patches.rst @@ -75,8 +75,8 @@ II. For kernel maintainers binding, and it hasn't received an Acked-by from the devicetree maintainers after a few weeks, go ahead and take it. - Subsystem bindings (anything affecting more than a single device) - then getting a devicetree maintainer to review it is required. + For subsystem bindings (anything affecting more than a single device), + getting a devicetree maintainer to review it is required. 3) For a series going though multiple trees, the binding patch should be kept with the driver using the binding. diff --git a/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml b/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml index 2c75105c13987efd9236aa0357ab7e39318d5734..7f5e3af5825554d141c0061a61e2227efba431b2 100644 --- a/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml +++ b/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml @@ -34,11 +34,30 @@ properties: - arm,armv8-timer interrupts: + minItems: 1 + maxItems: 5 items: - description: secure timer irq - description: non-secure timer irq - description: virtual timer irq - description: hypervisor timer irq + - description: hypervisor virtual timer irq + + interrupt-names: + oneOf: + - minItems: 2 + items: + - const: phys + - const: virt + - const: hyp-phys + - const: hyp-virt + - minItems: 3 + items: + - const: sec-phys + - const: phys + - const: virt + - const: hyp-phys + - const: hyp-virt clock-frequency: description: The frequency of the main counter, in Hz. Should be present diff --git a/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml b/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml index 024bcad75101f112c3a26cf879513a39818ef9af..8165df4599cf5338be1de82119d8adc98ea294cd 100644 --- a/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml +++ b/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml @@ -20,6 +20,8 @@ select: enum: - ingenic,jz4740-tcu - ingenic,jz4725b-tcu + - ingenic,jz4760-tcu + - ingenic,jz4760b-tcu - ingenic,jz4770-tcu - ingenic,jz4780-tcu - ingenic,x1000-tcu @@ -52,12 +54,15 @@ properties: - enum: - ingenic,jz4740-tcu - ingenic,jz4725b-tcu - - ingenic,jz4770-tcu + - ingenic,jz4760-tcu - ingenic,x1000-tcu - const: simple-mfd - items: - - const: ingenic,jz4780-tcu - - const: ingenic,jz4770-tcu + - enum: + - ingenic,jz4780-tcu + - ingenic,jz4770-tcu + - ingenic,jz4760b-tcu + - const: ingenic,jz4760-tcu - const: simple-mfd reg: @@ -118,6 +123,8 @@ patternProperties: - items: - enum: - ingenic,jz4770-watchdog + - ingenic,jz4760b-watchdog + - ingenic,jz4760-watchdog - ingenic,jz4725b-watchdog - const: ingenic,jz4740-watchdog @@ -147,6 +154,8 @@ patternProperties: - ingenic,jz4725b-pwm - items: - enum: + - ingenic,jz4760-pwm + - ingenic,jz4760b-pwm - ingenic,jz4770-pwm - ingenic,jz4780-pwm - const: ingenic,jz4740-pwm @@ -183,10 +192,15 @@ patternProperties: oneOf: - enum: - ingenic,jz4725b-ost - - ingenic,jz4770-ost + - ingenic,jz4760b-ost - items: - - const: ingenic,jz4780-ost - - const: ingenic,jz4770-ost + - const: ingenic,jz4760-ost + - const: ingenic,jz4725b-ost + - items: + - enum: + - ingenic,jz4780-ost + - ingenic,jz4770-ost + - const: ingenic,jz4760b-ost reg: maxItems: 1 @@ -226,7 +240,7 @@ examples: #include <dt-bindings/clock/jz4770-cgu.h> #include <dt-bindings/clock/ingenic,tcu.h> tcu: timer@10002000 { - compatible = "ingenic,jz4770-tcu", "simple-mfd"; + compatible = "ingenic,jz4770-tcu", "ingenic,jz4760-tcu", "simple-mfd"; reg = <0x10002000 0x1000>; #address-cells = <1>; #size-cells = <1>; @@ -272,7 +286,7 @@ examples: }; ost: timer@e0 { - compatible = "ingenic,jz4770-ost"; + compatible = "ingenic,jz4770-ost", "ingenic,jz4760b-ost"; reg = <0xe0 0x20>; clocks = <&tcu TCU_CLK_OST>; diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt index 690a9c0966aca5246715487bffa5b2d8b1642374..e5c57d6e018634c204d9823bd992680fc30d728b 100644 --- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt +++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt @@ -23,6 +23,7 @@ Required properties: For those SoCs that use SYST * "mediatek,mt8183-timer" for MT8183 compatible timers (SYST) * "mediatek,mt8192-timer" for MT8192 compatible timers (SYST) + * "mediatek,mt8195-timer" for MT8195 compatible timers (SYST) * "mediatek,mt7629-timer" for MT7629 compatible timers (SYST) * "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST) diff --git a/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.txt b/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.txt index 97258f1a1505bf504fdda399945187e20c59b287..ac3a5e887455d69eacdd2ce34790605ee72107b8 100644 --- a/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.txt +++ b/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.txt @@ -4,7 +4,8 @@ Nuvoton NPCM7xx have three timer modules, each timer module provides five 24-bit timer counters. Required properties: -- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750. +- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750, or + "nuvoton,wpcm450-timer" for Hermon WPCM450. - reg : Offset and length of the register set for the device. - interrupts : Contain the timer interrupt of timer 0. - clocks : phandle of timer reference clock (usually a 25 MHz clock). diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.yaml b/Documentation/devicetree/bindings/timer/renesas,cmt.yaml index 428db3a21bb9c38419a61e77c9e88710afe23a63..53dd6d9f518f96f2ff9bff65f08da01ef9767dbc 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.yaml +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.yaml @@ -74,11 +74,13 @@ properties: - renesas,r8a774e1-cmt0 # 32-bit CMT0 on RZ/G2H - renesas,r8a7795-cmt0 # 32-bit CMT0 on R-Car H3 - renesas,r8a7796-cmt0 # 32-bit CMT0 on R-Car M3-W + - renesas,r8a77961-cmt0 # 32-bit CMT0 on R-Car M3-W+ - renesas,r8a77965-cmt0 # 32-bit CMT0 on R-Car M3-N - renesas,r8a77970-cmt0 # 32-bit CMT0 on R-Car V3M - renesas,r8a77980-cmt0 # 32-bit CMT0 on R-Car V3H - renesas,r8a77990-cmt0 # 32-bit CMT0 on R-Car E3 - renesas,r8a77995-cmt0 # 32-bit CMT0 on R-Car D3 + - renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U - const: renesas,rcar-gen3-cmt0 # 32-bit CMT0 on R-Car Gen3 and RZ/G2 - items: @@ -89,11 +91,13 @@ properties: - renesas,r8a774e1-cmt1 # 48-bit CMT on RZ/G2H - renesas,r8a7795-cmt1 # 48-bit CMT on R-Car H3 - renesas,r8a7796-cmt1 # 48-bit CMT on R-Car M3-W + - renesas,r8a77961-cmt1 # 48-bit CMT on R-Car M3-W+ - renesas,r8a77965-cmt1 # 48-bit CMT on R-Car M3-N - renesas,r8a77970-cmt1 # 48-bit CMT on R-Car V3M - renesas,r8a77980-cmt1 # 48-bit CMT on R-Car V3H - renesas,r8a77990-cmt1 # 48-bit CMT on R-Car E3 - renesas,r8a77995-cmt1 # 48-bit CMT on R-Car D3 + - renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U - const: renesas,rcar-gen3-cmt1 # 48-bit CMT on R-Car Gen3 and RZ/G2 reg: diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml index c54188731a1bd7c11d1efbf5de56e27b25e93290..f0f0f121c355b159b25826d59514f3dcdaf98169 100644 --- a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml @@ -28,8 +28,14 @@ properties: - renesas,tmu-r8a774e1 # RZ/G2H - renesas,tmu-r8a7778 # R-Car M1A - renesas,tmu-r8a7779 # R-Car H1 + - renesas,tmu-r8a7795 # R-Car H3 + - renesas,tmu-r8a7796 # R-Car M3-W + - renesas,tmu-r8a77961 # R-Car M3-W+ + - renesas,tmu-r8a77965 # R-Car M3-N - renesas,tmu-r8a77970 # R-Car V3M - renesas,tmu-r8a77980 # R-Car V3H + - renesas,tmu-r8a77990 # R-Car E3 + - renesas,tmu-r8a77995 # R-Car D3 - const: renesas,tmu reg: diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index a327130d1faa5b33d400b6168019b6812528f51d..08e417e2236cf98259a84dd9610ec49e80c8a756 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -50,6 +50,8 @@ properties: - atmel,atsha204a # i2c h/w elliptic curve crypto module - atmel,atecc508a + # BPA-RS600: Power Supply + - blutek,bpa-rs600 # Bosch Sensortec pressure, temperature, humididty and VOC sensor - bosch,bme680 # CM32181: Ambient Light Sensor @@ -102,6 +104,8 @@ properties: - mps,mp2975 # G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface - gmt,g751 + # Infineon IR36021 digital POL buck controller + - infineon,ir36021 # Infineon IR38064 Voltage Regulator - infineon,ir38064 # Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) @@ -288,6 +292,8 @@ properties: - ti,tmp103 # Digital Temperature Sensor - ti,tmp275 + # TI Dual channel DCAP+ multiphase controller TPS53676 with AVSBus + - ti,tps53676 # TI Dual channel DCAP+ multiphase controller TPS53679 - ti,tps53679 # TI Dual channel DCAP+ multiphase controller TPS53688 diff --git a/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt b/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt index a668f43bedf549b9ddb7d4a0ce56b942e324fd6b..04813a46e5d0994b15edcebc2795542031d6cc17 100644 --- a/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt +++ b/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt @@ -1,32 +1,56 @@ Xilinx SuperSpeed DWC3 USB SoC controller Required properties: -- compatible: Should contain "xlnx,zynqmp-dwc3" +- compatible: May contain "xlnx,zynqmp-dwc3" or "xlnx,versal-dwc3" +- reg: Base address and length of the register control block - clocks: A list of phandles for the clocks listed in clock-names - clock-names: Should contain the following: "bus_clk" Master/Core clock, have to be >= 125 MHz for SS operation and >= 60MHz for HS operation "ref_clk" Clock source to core during PHY power down +- resets: A list of phandles for resets listed in reset-names +- reset-names: + "usb_crst" USB core reset + "usb_hibrst" USB hibernation reset + "usb_apbrst" USB APB reset Required child node: A child node must exist to represent the core DWC3 IP block. The name of the node is not important. The content of the node is defined in dwc3.txt. +Optional properties for snps,dwc3: +- dma-coherent: Enable this flag if CCI is enabled in design. Adding this + flag configures Global SoC bus Configuration Register and + Xilinx USB 3.0 IP - USB coherency register to enable CCI. +- interrupt-names: Should contain the following: + "dwc_usb3" USB gadget mode interrupts + "otg" USB OTG mode interrupts + "hiber" USB hibernation interrupts + Example device node: usb@0 { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "xlnx,zynqmp-dwc3"; + reg = <0x0 0xff9d0000 0x0 0x100>; clock-names = "bus_clk", "ref_clk"; clocks = <&clk125>, <&clk125>; + resets = <&zynqmp_reset ZYNQMP_RESET_USB1_CORERESET>, + <&zynqmp_reset ZYNQMP_RESET_USB1_HIBERRESET>, + <&zynqmp_reset ZYNQMP_RESET_USB1_APB>; + reset-names = "usb_crst", "usb_hibrst", "usb_apbrst"; ranges; dwc3@fe200000 { compatible = "snps,dwc3"; reg = <0x0 0xfe200000 0x40000>; - interrupts = <0x0 0x41 0x4>; + interrupt-names = "dwc_usb3", "otg", "hiber"; + interrupts = <0 65 4>, <0 69 4>, <0 75 4>; + phys = <&psgtr 2 PHY_TYPE_USB3 0 2>; + phy-names = "usb3-phy"; dr_mode = "host"; + dma-coherent; }; }; diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml index cb4c6f6d3a33a3f50753b763f230475e0726f169..974032b1fda04fbfd85fbf0844672baf6bcded41 100644 --- a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml @@ -52,11 +52,8 @@ properties: # Required child node: patternProperties: - "^dwc3@[0-9a-f]+$": - type: object - description: - A child node must exist to represent the core DWC3 IP block - The content of the node is defined in dwc3.txt. + "^usb@[0-9a-f]+$": + $ref: snps,dwc3.yaml# required: - compatible @@ -87,7 +84,7 @@ examples: dma-ranges = <0x40000000 0x40000000 0xc0000000>; ranges; - dwc3@38100000 { + usb@38100000 { compatible = "snps,dwc3"; reg = <0x38100000 0x10000>; clocks = <&clk IMX8MP_CLK_HSIO_AXI>, diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml index cf83f2d9afacbcbc64f9bbc9df5de4607f39de94..8089dc956ba32bc9609f4dcee87de6b38fd0c70c 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -122,6 +122,12 @@ properties: description: Set this flag to force EHCI reset after resume. + spurious-oc: + $ref: /schemas/types.yaml#/definitions/flag + description: + Set this flag to indicate that the hardware sometimes turns on + the OC bit when an over-current isn't actually present. + companion: $ref: /schemas/types.yaml#/definitions/phandle description: diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 14f40efb3b22c2a060c9e649b78184b4386b1207..240882b12565d927519767b076950c0c1168eb6b 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -30,6 +30,7 @@ properties: - mediatek,mt7629-xhci - mediatek,mt8173-xhci - mediatek,mt8183-xhci + - mediatek,mt8192-xhci - const: mediatek,mtk-xhci reg: @@ -45,7 +46,18 @@ properties: - const: ippc # optional, only needed for case 1. interrupts: - maxItems: 1 + description: + use "interrupts-extended" when the interrupts are connected to the + separate interrupt controllers + minItems: 1 + items: + - description: xHCI host controller interrupt + - description: optional, wakeup interrupt used to support runtime PM + + interrupt-names: + items: + - const: host + - const: wakeup power-domains: description: A phandle to USB power domain node to control USB's MTCMOS @@ -99,9 +111,9 @@ properties: vbus-supply: description: Regulator of USB VBUS5v - usb3-lpm-capable: - description: supports USB3.0 LPM - type: boolean + usb3-lpm-capable: true + + usb2-lpm-disable: true imod-interval-ns: description: @@ -127,10 +139,13 @@ properties: - description: The second cell represents the register base address of the glue layer in syscon - - description: + - description: | The third cell represents the hardware version of the glue layer, - 1 is used by mt8173 etc, 2 is used by mt2712 etc - enum: [1, 2] + 1 - used by mt8173 etc, revision 1 without following IPM rule; + 2 - used by mt2712 etc, revision 2 following IPM rule; + 101 - used by mt8183, specific 1.01; + 102 - used by mt8192, specific 1.02; + enum: [1, 2, 101, 102] mediatek,u3p-dis-msk: $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml index f5c04b9d2de966ba30ef013912073a79ce053e2c..dbc7876e0a0b474c6558c9919e25325a00e1462a 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml @@ -24,6 +24,7 @@ properties: - mediatek,mt2712-mtu3 - mediatek,mt8173-mtu3 - mediatek,mt8183-mtu3 + - mediatek,mt8192-mtu3 - const: mediatek,mtu3 reg: @@ -126,7 +127,7 @@ properties: Any connector to the data bus of this controller should be modelled using the OF graph bindings specified, if the "usb-role-switch" property is used. See graph.txt - type: object + $ref: /schemas/graph.yaml#/properties/port enable-manual-drd: $ref: /schemas/types.yaml#/definitions/flag @@ -152,10 +153,13 @@ properties: - description: The second cell represents the register base address of the glue layer in syscon - - description: + - description: | The third cell represents the hardware version of the glue layer, - 1 is used by mt8173 etc, 2 is used by mt2712 etc - enum: [1, 2] + 1 - used by mt8173 etc, revision 1 without following IPM rule; + 2 - used by mt2712 etc, revision 2 with following IPM rule; + 101 - used by mt8183, specific 1.01; + 102 - used by mt8192, specific 1.02; + enum: [1, 2, 101, 102] mediatek,u3p-dis-msk: $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index c3cbd1fa994490f8073e81a0c4db3bb352da426a..413299b5fe2b4041654d4128c66369137d59d526 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -16,6 +16,7 @@ properties: - qcom,msm8996-dwc3 - qcom,msm8998-dwc3 - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 - qcom,sm8150-dwc3 diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index 2247da77eac1b66b8462965556c04ded59e44dc2..41416fbd92aa1c384cf74390ba7179c056aa7555 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -87,13 +87,19 @@ properties: minItems: 1 snps,usb2-lpm-disable: - description: Indicate if we don't want to enable USB2 HW LPM + description: Indicate if we don't want to enable USB2 HW LPM for host + mode. type: boolean snps,usb3_lpm_capable: description: Determines if platform is USB3 LPM capable type: boolean + snps,usb2-gadget-lpm-disable: + description: Indicate if we don't want to enable USB2 HW LPM for gadget + mode. + type: boolean + snps,dis-start-transfer-quirk: description: When set, disable isoc START TRANSFER command failure SW work-around diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml index d4c99809ee9a4ef7ff2eb7dac5065f722d9a4d96..b77960a7a37ba9cfd2e27627d8ba5d5cea6708d4 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.yaml +++ b/Documentation/devicetree/bindings/usb/usb-device.yaml @@ -82,9 +82,9 @@ required: additionalProperties: true examples: - #hub connected to port 1 - #device connected to port 2 - #device connected to port 3 + # hub connected to port 1 + # device connected to port 2 + # device connected to port 3 # interface 0 of configuration 1 # interface 0 of configuration 2 - | diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt deleted file mode 100644 index 4dc6a8ee307156ea1f09083900e49536e0a94b6a..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt +++ /dev/null @@ -1,43 +0,0 @@ -USB NOP PHY - -Required properties: -- compatible: should be usb-nop-xceiv -- #phy-cells: Must be 0 - -Optional properties: -- clocks: phandle to the PHY clock. Use as per Documentation/devicetree - /bindings/clock/clock-bindings.txt - This property is required if clock-frequency is specified. - -- clock-names: Should be "main_clk" - -- clock-frequency: the clock frequency (in Hz) that the PHY clock must - be configured to. - -- vcc-supply: phandle to the regulator that provides power to the PHY. - -- reset-gpios: Should specify the GPIO for reset. - -- vbus-detect-gpio: should specify the GPIO detecting a VBus insertion - (see Documentation/devicetree/bindings/gpio/gpio.txt) -- vbus-regulator : should specifiy the regulator supplying current drawn from - the VBus line (see Documentation/devicetree/bindings/regulator/regulator.txt). - -Example: - - hsusb1_phy { - compatible = "usb-nop-xceiv"; - clock-frequency = <19200000>; - clocks = <&osc 0>; - clock-names = "main_clk"; - vcc-supply = <&hsusb1_vcc_regulator>; - reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; - vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; - vbus-regulator = <&vbus_regulator>; - #phy-cells = <0>; - }; - -hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator -and expects that clock to be configured to 19.2MHz by the NOP PHY driver. -hsusb1_vcc_regulator provides power to the PHY and GPIO 7 controls RESET. -GPIO 13 detects VBus insertion, and accordingly notifies the vbus-regulator. diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2824c17285eeafc8dd3ceafc46e20d13105f914c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb-nop-xceiv.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: USB NOP PHY + +maintainers: + - Rob Herring <robh@kernel.org> + +properties: + compatible: + const: usb-nop-xceiv + + clocks: + maxItems: 1 + + clock-names: + const: main_clk + + clock-frequency: true + + '#phy-cells': + const: 0 + + vcc-supply: + description: phandle to the regulator that provides power to the PHY. + + reset-gpios: + maxItems: 1 + + vbus-detect-gpio: + description: Should specify the GPIO detecting a VBus insertion + maxItems: 1 + + vbus-regulator: + description: Should specifiy the regulator supplying current drawn from + the VBus line. + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - '#phy-cells' + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + hsusb1_phy { + compatible = "usb-nop-xceiv"; + clock-frequency = <19200000>; + clocks = <&osc 0>; + clock-names = "main_clk"; + vcc-supply = <&hsusb1_vcc_regulator>; + reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + vbus-regulator = <&vbus_regulator>; + #phy-cells = <0>; + }; + +... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index f6064d84a424de4db2bc3bf6dc149569d8b35f17..c88b1cfb52cb62b8199ce3504cd41a729881aea6 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -103,6 +103,8 @@ patternProperties: description: Anvo-Systems Dresden GmbH "^apm,.*": description: Applied Micro Circuits Corporation (APM) + "^apple,.*": + description: Apple Inc. "^aptina,.*": description: Aptina Imaging "^arasan,.*": @@ -169,6 +171,8 @@ patternProperties: description: Beckhoff Automation GmbH & Co. KG "^bitmain,.*": description: Bitmain Technologies + "^blutek,.*": + description: BluTek Power "^boe,.*": description: BOE Technology Group Co., Ltd. "^bosch,.*": @@ -651,6 +655,8 @@ patternProperties: description: Liebherr-Werk Nenzing GmbH "^lxa,.*": description: Linux Automation GmbH + "^m5stack,.*": + description: M5Stack "^macnica,.*": description: Macnica Americas "^mantix,.*": @@ -932,6 +938,8 @@ patternProperties: description: Unisoc Communications, Inc. "^realtek,.*": description: Realtek Semiconductor Corp. + "^remarkable,.*": + description: reMarkable AS "^renesas,.*": description: Renesas Electronics Corporation "^rex,.*": @@ -1024,6 +1032,8 @@ patternProperties: description: Silex Insight "^siliconmitus,.*": description: Silicon Mitus, Inc. + "^siemens,.*": + description: Siemens AG "^simtek,.*": description: Cypress Semiconductor Corporation (Simtek Corporation) "^sinlinx,.*": @@ -1085,6 +1095,8 @@ patternProperties: description: Shenzhen Sunchip Technology Co., Ltd "^SUNW,.*": description: Sun Microsystems, Inc + "^supermicro,.*": + description: Super Micro Computer, Inc. "^silvaco,.*": description: Silvaco, Inc. "^swir,.*": @@ -1101,6 +1113,8 @@ patternProperties: description: Trusted Computing Group "^tcl,.*": description: Toby Churchill Ltd. + "^tcs,.*": + description: Shenzhen City Tang Cheng Technology Co., Ltd. "^tdo,.*": description: Shangai Top Display Optoelectronics Co., Ltd "^technexion,.*": diff --git a/Documentation/devicetree/bindings/watchdog/nuvoton,npcm-wdt.txt b/Documentation/devicetree/bindings/watchdog/nuvoton,npcm-wdt.txt index 6d593003c933bedddafb80ef685eeec8bb7facf0..9059f54dc023df58cdde319c2bef389e0b895f83 100644 --- a/Documentation/devicetree/bindings/watchdog/nuvoton,npcm-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/nuvoton,npcm-wdt.txt @@ -5,7 +5,8 @@ The watchdog supports a pre-timeout interrupt that fires 10ms before the expiry. Required properties: -- compatible : "nuvoton,npcm750-wdt" for NPCM750 (Poleg). +- compatible : "nuvoton,npcm750-wdt" for NPCM750 (Poleg), or + "nuvoton,wpcm450-wdt" for WPCM450 (Hermon). - reg : Offset and length of the register set for the device. - interrupts : Contain the timer interrupt with flags for falling edge. diff --git a/Documentation/driver-api/device-io.rst b/Documentation/driver-api/device-io.rst index 764963876d089b23b9e7712918f501156ac4856c..e9f04b1815d147ef0ce7956f7c59e558f7735bff 100644 --- a/Documentation/driver-api/device-io.rst +++ b/Documentation/driver-api/device-io.rst @@ -146,6 +146,362 @@ There are also equivalents to memcpy. The ins() and outs() functions copy bytes, words or longs to the given port. +__iomem pointer tokens +====================== + +The data type for an MMIO address is an ``__iomem`` qualified pointer, such as +``void __iomem *reg``. On most architectures it is a regular pointer that +points to a virtual memory address and can be offset or dereferenced, but in +portable code, it must only be passed from and to functions that explicitly +operated on an ``__iomem`` token, in particular the ioremap() and +readl()/writel() functions. The 'sparse' semantic code checker can be used to +verify that this is done correctly. + +While on most architectures, ioremap() creates a page table entry for an +uncached virtual address pointing to the physical MMIO address, some +architectures require special instructions for MMIO, and the ``__iomem`` pointer +just encodes the physical address or an offsettable cookie that is interpreted +by readl()/writel(). + +Differences between I/O access functions +======================================== + +readq(), readl(), readw(), readb(), writeq(), writel(), writew(), writeb() + + These are the most generic accessors, providing serialization against other + MMIO accesses and DMA accesses as well as fixed endianness for accessing + little-endian PCI devices and on-chip peripherals. Portable device drivers + should generally use these for any access to ``__iomem`` pointers. + + Note that posted writes are not strictly ordered against a spinlock, see + Documentation/driver-api/io_ordering.rst. + +readq_relaxed(), readl_relaxed(), readw_relaxed(), readb_relaxed(), +writeq_relaxed(), writel_relaxed(), writew_relaxed(), writeb_relaxed() + + On architectures that require an expensive barrier for serializing against + DMA, these "relaxed" versions of the MMIO accessors only serialize against + each other, but contain a less expensive barrier operation. A device driver + might use these in a particularly performance sensitive fast path, with a + comment that explains why the usage in a specific location is safe without + the extra barriers. + + See memory-barriers.txt for a more detailed discussion on the precise ordering + guarantees of the non-relaxed and relaxed versions. + +ioread64(), ioread32(), ioread16(), ioread8(), +iowrite64(), iowrite32(), iowrite16(), iowrite8() + + These are an alternative to the normal readl()/writel() functions, with almost + identical behavior, but they can also operate on ``__iomem`` tokens returned + for mapping PCI I/O space with pci_iomap() or ioport_map(). On architectures + that require special instructions for I/O port access, this adds a small + overhead for an indirect function call implemented in lib/iomap.c, while on + other architectures, these are simply aliases. + +ioread64be(), ioread32be(), ioread16be() +iowrite64be(), iowrite32be(), iowrite16be() + + These behave in the same way as the ioread32()/iowrite32() family, but with + reversed byte order, for accessing devices with big-endian MMIO registers. + Device drivers that can operate on either big-endian or little-endian + registers may have to implement a custom wrapper function that picks one or + the other depending on which device was found. + + Note: On some architectures, the normal readl()/writel() functions + traditionally assume that devices are the same endianness as the CPU, while + using a hardware byte-reverse on the PCI bus when running a big-endian kernel. + Drivers that use readl()/writel() this way are generally not portable, but + tend to be limited to a particular SoC. + +hi_lo_readq(), lo_hi_readq(), hi_lo_readq_relaxed(), lo_hi_readq_relaxed(), +ioread64_lo_hi(), ioread64_hi_lo(), ioread64be_lo_hi(), ioread64be_hi_lo(), +hi_lo_writeq(), lo_hi_writeq(), hi_lo_writeq_relaxed(), lo_hi_writeq_relaxed(), +iowrite64_lo_hi(), iowrite64_hi_lo(), iowrite64be_lo_hi(), iowrite64be_hi_lo() + + Some device drivers have 64-bit registers that cannot be accessed atomically + on 32-bit architectures but allow two consecutive 32-bit accesses instead. + Since it depends on the particular device which of the two halves has to be + accessed first, a helper is provided for each combination of 64-bit accessors + with either low/high or high/low word ordering. A device driver must include + either <linux/io-64-nonatomic-lo-hi.h> or <linux/io-64-nonatomic-hi-lo.h> to + get the function definitions along with helpers that redirect the normal + readq()/writeq() to them on architectures that do not provide 64-bit access + natively. + +__raw_readq(), __raw_readl(), __raw_readw(), __raw_readb(), +__raw_writeq(), __raw_writel(), __raw_writew(), __raw_writeb() + + These are low-level MMIO accessors without barriers or byteorder changes and + architecture specific behavior. Accesses are usually atomic in the sense that + a four-byte __raw_readl() does not get split into individual byte loads, but + multiple consecutive accesses can be combined on the bus. In portable code, it + is only safe to use these to access memory behind a device bus but not MMIO + registers, as there are no ordering guarantees with regard to other MMIO + accesses or even spinlocks. The byte order is generally the same as for normal + memory, so unlike the other functions, these can be used to copy data between + kernel memory and device memory. + +inl(), inw(), inb(), outl(), outw(), outb() + + PCI I/O port resources traditionally require separate helpers as they are + implemented using special instructions on the x86 architecture. On most other + architectures, these are mapped to readl()/writel() style accessors + internally, usually pointing to a fixed area in virtual memory. Instead of an + ``__iomem`` pointer, the address is a 32-bit integer token to identify a port + number. PCI requires I/O port access to be non-posted, meaning that an outb() + must complete before the following code executes, while a normal writeb() may + still be in progress. On architectures that correctly implement this, I/O port + access is therefore ordered against spinlocks. Many non-x86 PCI host bridge + implementations and CPU architectures however fail to implement non-posted I/O + space on PCI, so they can end up being posted on such hardware. + + In some architectures, the I/O port number space has a 1:1 mapping to + ``__iomem`` pointers, but this is not recommended and device drivers should + not rely on that for portability. Similarly, an I/O port number as described + in a PCI base address register may not correspond to the port number as seen + by a device driver. Portable drivers need to read the port number for the + resource provided by the kernel. + + There are no direct 64-bit I/O port accessors, but pci_iomap() in combination + with ioread64/iowrite64 can be used instead. + +inl_p(), inw_p(), inb_p(), outl_p(), outw_p(), outb_p() + + On ISA devices that require specific timing, the _p versions of the I/O + accessors add a small delay. On architectures that do not have ISA buses, + these are aliases to the normal inb/outb helpers. + +readsq, readsl, readsw, readsb +writesq, writesl, writesw, writesb +ioread64_rep, ioread32_rep, ioread16_rep, ioread8_rep +iowrite64_rep, iowrite32_rep, iowrite16_rep, iowrite8_rep +insl, insw, insb, outsl, outsw, outsb + + These are helpers that access the same address multiple times, usually to copy + data between kernel memory byte stream and a FIFO buffer. Unlike the normal + MMIO accessors, these do not perform a byteswap on big-endian kernels, so the + first byte in the FIFO register corresponds to the first byte in the memory + buffer regardless of the architecture. + +Device memory mapping modes +=========================== + +Some architectures support multiple modes for mapping device memory. +ioremap_*() variants provide a common abstraction around these +architecture-specific modes, with a shared set of semantics. + +ioremap() is the most common mapping type, and is applicable to typical device +memory (e.g. I/O registers). Other modes can offer weaker or stronger +guarantees, if supported by the architecture. From most to least common, they +are as follows: + +ioremap() +--------- + +The default mode, suitable for most memory-mapped devices, e.g. control +registers. Memory mapped using ioremap() has the following characteristics: + +* Uncached - CPU-side caches are bypassed, and all reads and writes are handled + directly by the device +* No speculative operations - the CPU may not issue a read or write to this + memory, unless the instruction that does so has been reached in committed + program flow. +* No reordering - The CPU may not reorder accesses to this memory mapping with + respect to each other. On some architectures, this relies on barriers in + readl_relaxed()/writel_relaxed(). +* No repetition - The CPU may not issue multiple reads or writes for a single + program instruction. +* No write-combining - Each I/O operation results in one discrete read or write + being issued to the device, and multiple writes are not combined into larger + writes. This may or may not be enforced when using __raw I/O accessors or + pointer dereferences. +* Non-executable - The CPU is not allowed to speculate instruction execution + from this memory (it probably goes without saying, but you're also not + allowed to jump into device memory). + +On many platforms and buses (e.g. PCI), writes issued through ioremap() +mappings are posted, which means that the CPU does not wait for the write to +actually reach the target device before retiring the write instruction. + +On many platforms, I/O accesses must be aligned with respect to the access +size; failure to do so will result in an exception or unpredictable results. + +ioremap_wc() +------------ + +Maps I/O memory as normal memory with write combining. Unlike ioremap(), + +* The CPU may speculatively issue reads from the device that the program + didn't actually execute, and may choose to basically read whatever it wants. +* The CPU may reorder operations as long as the result is consistent from the + program's point of view. +* The CPU may write to the same location multiple times, even when the program + issued a single write. +* The CPU may combine several writes into a single larger write. + +This mode is typically used for video framebuffers, where it can increase +performance of writes. It can also be used for other blocks of memory in +devices (e.g. buffers or shared memory), but care must be taken as accesses are +not guaranteed to be ordered with respect to normal ioremap() MMIO register +accesses without explicit barriers. + +On a PCI bus, it is usually safe to use ioremap_wc() on MMIO areas marked as +``IORESOURCE_PREFETCH``, but it may not be used on those without the flag. +For on-chip devices, there is no corresponding flag, but a driver can use +ioremap_wc() on a device that is known to be safe. + +ioremap_wt() +------------ + +Maps I/O memory as normal memory with write-through caching. Like ioremap_wc(), +but also, + +* The CPU may cache writes issued to and reads from the device, and serve reads + from that cache. + +This mode is sometimes used for video framebuffers, where drivers still expect +writes to reach the device in a timely manner (and not be stuck in the CPU +cache), but reads may be served from the cache for efficiency. However, it is +rarely useful these days, as framebuffer drivers usually perform writes only, +for which ioremap_wc() is more efficient (as it doesn't needlessly trash the +cache). Most drivers should not use this. + +ioremap_np() +------------ + +Like ioremap(), but explicitly requests non-posted write semantics. On some +architectures and buses, ioremap() mappings have posted write semantics, which +means that writes can appear to "complete" from the point of view of the +CPU before the written data actually arrives at the target device. Writes are +still ordered with respect to other writes and reads from the same device, but +due to the posted write semantics, this is not the case with respect to other +devices. ioremap_np() explicitly requests non-posted semantics, which means +that the write instruction will not appear to complete until the device has +received (and to some platform-specific extent acknowledged) the written data. + +This mapping mode primarily exists to cater for platforms with bus fabrics that +require this particular mapping mode to work correctly. These platforms set the +``IORESOURCE_MEM_NONPOSTED`` flag for a resource that requires ioremap_np() +semantics and portable drivers should use an abstraction that automatically +selects it where appropriate (see the `Higher-level ioremap abstractions`_ +section below). + +The bare ioremap_np() is only available on some architectures; on others, it +always returns NULL. Drivers should not normally use it, unless they are +platform-specific or they derive benefit from non-posted writes where +supported, and can fall back to ioremap() otherwise. The normal approach to +ensure posted write completion is to do a dummy read after a write as +explained in `Accessing the device`_, which works with ioremap() on all +platforms. + +ioremap_np() should never be used for PCI drivers. PCI memory space writes are +always posted, even on architectures that otherwise implement ioremap_np(). +Using ioremap_np() for PCI BARs will at best result in posted write semantics, +and at worst result in complete breakage. + +Note that non-posted write semantics are orthogonal to CPU-side ordering +guarantees. A CPU may still choose to issue other reads or writes before a +non-posted write instruction retires. See the previous section on MMIO access +functions for details on the CPU side of things. + +ioremap_uc() +------------ + +ioremap_uc() behaves like ioremap() except that on the x86 architecture without +'PAT' mode, it marks memory as uncached even when the MTRR has designated +it as cacheable, see Documentation/x86/pat.rst. + +Portable drivers should avoid the use of ioremap_uc(). + +ioremap_cache() +--------------- + +ioremap_cache() effectively maps I/O memory as normal RAM. CPU write-back +caches can be used, and the CPU is free to treat the device as if it were a +block of RAM. This should never be used for device memory which has side +effects of any kind, or which does not return the data previously written on +read. + +It should also not be used for actual RAM, as the returned pointer is an +``__iomem`` token. memremap() can be used for mapping normal RAM that is outside +of the linear kernel memory area to a regular pointer. + +Portable drivers should avoid the use of ioremap_cache(). + +Architecture example +-------------------- + +Here is how the above modes map to memory attribute settings on the ARM64 +architecture: + ++------------------------+--------------------------------------------+ +| API | Memory region type and cacheability | ++------------------------+--------------------------------------------+ +| ioremap_np() | Device-nGnRnE | ++------------------------+--------------------------------------------+ +| ioremap() | Device-nGnRE | ++------------------------+--------------------------------------------+ +| ioremap_uc() | (not implemented) | ++------------------------+--------------------------------------------+ +| ioremap_wc() | Normal-Non Cacheable | ++------------------------+--------------------------------------------+ +| ioremap_wt() | (not implemented; fallback to ioremap) | ++------------------------+--------------------------------------------+ +| ioremap_cache() | Normal-Write-Back Cacheable | ++------------------------+--------------------------------------------+ + +Higher-level ioremap abstractions +================================= + +Instead of using the above raw ioremap() modes, drivers are encouraged to use +higher-level APIs. These APIs may implement platform-specific logic to +automatically choose an appropriate ioremap mode on any given bus, allowing for +a platform-agnostic driver to work on those platforms without any special +cases. At the time of this writing, the following ioremap() wrappers have such +logic: + +devm_ioremap_resource() + + Can automatically select ioremap_np() over ioremap() according to platform + requirements, if the ``IORESOURCE_MEM_NONPOSTED`` flag is set on the struct + resource. Uses devres to automatically unmap the resource when the driver + probe() function fails or a device in unbound from its driver. + + Documented in Documentation/driver-api/driver-model/devres.rst. + +of_address_to_resource() + + Automatically sets the ``IORESOURCE_MEM_NONPOSTED`` flag for platforms that + require non-posted writes for certain buses (see the nonposted-mmio and + posted-mmio device tree properties). + +of_iomap() + + Maps the resource described in a ``reg`` property in the device tree, doing + all required translations. Automatically selects ioremap_np() according to + platform requirements, as above. + +pci_ioremap_bar(), pci_ioremap_wc_bar() + + Maps the resource described in a PCI base address without having to extract + the physical address first. + +pci_iomap(), pci_iomap_wc() + + Like pci_ioremap_bar()/pci_ioremap_bar(), but also works on I/O space when + used together with ioread32()/iowrite32() and similar accessors + +pcim_iomap() + + Like pci_iomap(), but uses devres to automatically unmap the resource when + the driver probe() function fails or a device in unbound from its driver + + Documented in Documentation/driver-api/driver-model/devres.rst. + +Not using these wrappers may make drivers unusable on certain platforms with +stricter rules for mapping I/O memory. + Public Functions Provided ========================= diff --git a/Documentation/driver-api/driver-model/class.rst b/Documentation/driver-api/driver-model/class.rst deleted file mode 100644 index fff55b80e86a54a452ea8e191f55de29c7731903..0000000000000000000000000000000000000000 --- a/Documentation/driver-api/driver-model/class.rst +++ /dev/null @@ -1,149 +0,0 @@ -============== -Device Classes -============== - -Introduction -~~~~~~~~~~~~ -A device class describes a type of device, like an audio or network -device. The following device classes have been identified: - -<Insert List of Device Classes Here> - - -Each device class defines a set of semantics and a programming interface -that devices of that class adhere to. Device drivers are the -implementation of that programming interface for a particular device on -a particular bus. - -Device classes are agnostic with respect to what bus a device resides -on. - - -Programming Interface -~~~~~~~~~~~~~~~~~~~~~ -The device class structure looks like:: - - - typedef int (*devclass_add)(struct device *); - typedef void (*devclass_remove)(struct device *); - -See the kerneldoc for the struct class. - -A typical device class definition would look like:: - - struct device_class input_devclass = { - .name = "input", - .add_device = input_add_device, - .remove_device = input_remove_device, - }; - -Each device class structure should be exported in a header file so it -can be used by drivers, extensions and interfaces. - -Device classes are registered and unregistered with the core using:: - - int devclass_register(struct device_class * cls); - void devclass_unregister(struct device_class * cls); - - -Devices -~~~~~~~ -As devices are bound to drivers, they are added to the device class -that the driver belongs to. Before the driver model core, this would -typically happen during the driver's probe() callback, once the device -has been initialized. It now happens after the probe() callback -finishes from the core. - -The device is enumerated in the class. Each time a device is added to -the class, the class's devnum field is incremented and assigned to the -device. The field is never decremented, so if the device is removed -from the class and re-added, it will receive a different enumerated -value. - -The class is allowed to create a class-specific structure for the -device and store it in the device's class_data pointer. - -There is no list of devices in the device class. Each driver has a -list of devices that it supports. The device class has a list of -drivers of that particular class. To access all of the devices in the -class, iterate over the device lists of each driver in the class. - - -Device Drivers -~~~~~~~~~~~~~~ -Device drivers are added to device classes when they are registered -with the core. A driver specifies the class it belongs to by setting -the struct device_driver::devclass field. - - -sysfs directory structure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There is a top-level sysfs directory named 'class'. - -Each class gets a directory in the class directory, along with two -default subdirectories:: - - class/ - `-- input - |-- devices - `-- drivers - - -Drivers registered with the class get a symlink in the drivers/ directory -that points to the driver's directory (under its bus directory):: - - class/ - `-- input - |-- devices - `-- drivers - `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ - - -Each device gets a symlink in the devices/ directory that points to the -device's directory in the physical hierarchy:: - - class/ - `-- input - |-- devices - | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - `-- drivers - - -Exporting Attributes -~~~~~~~~~~~~~~~~~~~~ - -:: - - struct devclass_attribute { - struct attribute attr; - ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off); - }; - -Class drivers can export attributes using the DEVCLASS_ATTR macro that works -similarly to the DEVICE_ATTR macro for devices. For example, a definition -like this:: - - static DEVCLASS_ATTR(debug,0644,show_debug,store_debug); - -is equivalent to declaring:: - - static devclass_attribute devclass_attr_debug; - -The bus driver can add and remove the attribute from the class's -sysfs directory using:: - - int devclass_create_file(struct device_class *, struct devclass_attribute *); - void devclass_remove_file(struct device_class *, struct devclass_attribute *); - -In the example above, the file will be named 'debug' in placed in the -class's directory in sysfs. - - -Interfaces -~~~~~~~~~~ -There may exist multiple mechanisms for accessing the same device of a -particular class type. Device interfaces describe these mechanisms. - -When a device is added to a device class, the core attempts to add it -to every interface that is registered with the device class. diff --git a/Documentation/driver-api/driver-model/device.rst b/Documentation/driver-api/driver-model/device.rst index b9b022371e856e831a4c080cbea63e104b97cb01..0833be568b06cacefbeb39e200103946d6f68b2b 100644 --- a/Documentation/driver-api/driver-model/device.rst +++ b/Documentation/driver-api/driver-model/device.rst @@ -63,8 +63,14 @@ Attributes are declared using a macro called DEVICE_ATTR:: Example::: - static DEVICE_ATTR(type, 0444, show_type, NULL); - static DEVICE_ATTR(power, 0644, show_power, store_power); + static DEVICE_ATTR(type, 0444, type_show, NULL); + static DEVICE_ATTR(power, 0644, power_show, power_store); + +Helper macros are available for common values of mode, so the above examples +can be simplified to::: + + static DEVICE_ATTR_RO(type); + static DEVICE_ATTR_RW(power); This declares two structures of type struct device_attribute with respective names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be @@ -76,19 +82,24 @@ organized as follows into a group:: NULL, }; - static struct attribute_group dev_attr_group = { + static struct attribute_group dev_group = { .attrs = dev_attrs, }; - static const struct attribute_group *dev_attr_groups[] = { - &dev_attr_group, + static const struct attribute_group *dev_groups[] = { + &dev_group, NULL, }; +A helper macro is available for the common case of a single group, so the +above two structures can be declared using::: + + ATTRIBUTE_GROUPS(dev); + This array of groups can then be associated with a device by setting the group pointer in struct device before device_register() is invoked:: - dev->groups = dev_attr_groups; + dev->groups = dev_groups; device_register(dev); The device_register() function will use the 'groups' pointer to create the diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index cd8b6e657b94f1da63e88237b1a6690a9fbbb272..e0814d21404847a51f645c42229bdb44fc56b990 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -285,7 +285,8 @@ I2C IIO devm_iio_device_alloc() devm_iio_device_register() - devm_iio_kfifo_allocate() + devm_iio_dmaengine_buffer_setup() + devm_iio_kfifo_buffer_setup() devm_iio_triggered_buffer_setup() devm_iio_trigger_alloc() devm_iio_trigger_register() @@ -309,6 +310,7 @@ IOMAP devm_ioremap() devm_ioremap_uc() devm_ioremap_wc() + devm_ioremap_np() devm_ioremap_resource() : checks resource, requests memory region, ioremaps devm_ioremap_resource_wc() devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device diff --git a/Documentation/driver-api/driver-model/index.rst b/Documentation/driver-api/driver-model/index.rst index 755016422269fb6e01ec3896d622b6f2949c6ffc..4831bdd92e5cd42affef81e5d13af14b10e2f39b 100644 --- a/Documentation/driver-api/driver-model/index.rst +++ b/Documentation/driver-api/driver-model/index.rst @@ -7,7 +7,6 @@ Driver Model binding bus - class design-patterns device devres diff --git a/Documentation/driver-api/gpio/intro.rst b/Documentation/driver-api/gpio/intro.rst index 94dd7185e76eb5df0051f0cd04bf52586f9e2b33..2e924fb5b3d536d5543ac4a92e01e2b5dd11e808 100644 --- a/Documentation/driver-api/gpio/intro.rst +++ b/Documentation/driver-api/gpio/intro.rst @@ -27,7 +27,7 @@ What is a GPIO? =============== A "General Purpose Input/Output" (GPIO) is a flexible software-controlled -digital signal. They are provided from many kinds of chip, and are familiar +digital signal. They are provided from many kinds of chips, and are familiar to Linux developers working with embedded and custom hardware. Each GPIO represents a bit connected to a particular pin, or "ball" on Ball Grid Array (BGA) packages. Board schematics show which external hardware connects to diff --git a/Documentation/driver-api/iio/buffers.rst b/Documentation/driver-api/iio/buffers.rst index 3ddebddc02ca29bb85a42d8fa4156af3fb2a552b..e83026aebe9758f51b2e4464c5062012167b074a 100644 --- a/Documentation/driver-api/iio/buffers.rst +++ b/Documentation/driver-api/iio/buffers.rst @@ -28,24 +28,26 @@ IIO buffer setup The meta information associated with a channel reading placed in a buffer is called a scan element. The important bits configuring scan elements are exposed to userspace applications via the -:file:`/sys/bus/iio/iio:device{X}/scan_elements/*` directory. This file contains +:file:`/sys/bus/iio/iio:device{X}/scan_elements/` directory. This directory contains attributes of the following form: * :file:`enable`, used for enabling a channel. If and only if its attribute is non *zero*, then a triggered capture will contain data samples for this channel. +* :file:`index`, the scan_index of the channel. * :file:`type`, description of the scan element data storage within the buffer and hence the form in which it is read from user space. - Format is [be|le]:[s|u]bits/storagebitsXrepeat[>>shift] . + Format is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift] . + * *be* or *le*, specifies big or little endian. * *s* or *u*, specifies if signed (2's complement) or unsigned. * *bits*, is the number of valid data bits. * *storagebits*, is the number of bits (after padding) that it occupies in the - buffer. - * *shift*, if specified, is the shift that needs to be applied prior to - masking out unused bits. + buffer. * *repeat*, specifies the number of bits/storagebits repetitions. When the - repeat element is 0 or 1, then the repeat value is omitted. + repeat element is 0 or 1, then the repeat value is omitted. + * *shift*, if specified, is the shift that needs to be applied prior to + masking out unused bits. For example, a driver for a 3-axis accelerometer with 12 bit resolution where data is stored in two 8-bits registers as follows:: @@ -122,4 +124,3 @@ More details .. kernel-doc:: include/linux/iio/buffer.h .. kernel-doc:: drivers/iio/industrialio-buffer.c :export: - diff --git a/Documentation/driver-api/serial/cyclades_z.rst b/Documentation/driver-api/serial/cyclades_z.rst deleted file mode 100644 index 532ff67e2f1c5c6cd4318e43c3ec21bd7fdcc16f..0000000000000000000000000000000000000000 --- a/Documentation/driver-api/serial/cyclades_z.rst +++ /dev/null @@ -1,11 +0,0 @@ -================ -Cyclades-Z notes -================ - -The Cyclades-Z must have firmware loaded onto the card before it will -operate. This operation should be performed during system startup, - -The firmware, loader program and the latest device driver code are -available from Cyclades at - - ftp://ftp.cyclades.com/pub/cyclades/cyclades-z/linux/ diff --git a/Documentation/driver-api/serial/index.rst b/Documentation/driver-api/serial/index.rst index 33ad10d05b26501828c8f520e8ea43dbf606cca5..21351b8c95a4d4f8db43f7d40cace9e7affeb9db 100644 --- a/Documentation/driver-api/serial/index.rst +++ b/Documentation/driver-api/serial/index.rst @@ -17,7 +17,6 @@ Serial drivers .. toctree:: :maxdepth: 1 - cyclades_z moxa-smartio n_gsm rocket diff --git a/Documentation/driver-api/serial/rocket.rst b/Documentation/driver-api/serial/rocket.rst deleted file mode 100644 index 23761eae42829eb521d2db9620f98f16f8498147..0000000000000000000000000000000000000000 --- a/Documentation/driver-api/serial/rocket.rst +++ /dev/null @@ -1,185 +0,0 @@ -================================================ -Comtrol(tm) RocketPort(R)/RocketModem(TM) Series -================================================ - -Device Driver for the Linux Operating System -============================================ - -Product overview ----------------- - -This driver provides a loadable kernel driver for the Comtrol RocketPort -and RocketModem PCI boards. These boards provide, 2, 4, 8, 16, or 32 -high-speed serial ports or modems. This driver supports up to a combination -of four RocketPort or RocketModems boards in one machine simultaneously. -This file assumes that you are using the RocketPort driver which is -integrated into the kernel sources. - -The driver can also be installed as an external module using the usual -"make;make install" routine. This external module driver, obtainable -from the Comtrol website listed below, is useful for updating the driver -or installing it into kernels which do not have the driver configured -into them. Installations instructions for the external module -are in the included README and HW_INSTALL files. - -RocketPort ISA and RocketModem II PCI boards currently are only supported by -this driver in module form. - -The RocketPort ISA board requires I/O ports to be configured by the DIP -switches on the board. See the section "ISA Rocketport Boards" below for -information on how to set the DIP switches. - -You pass the I/O port to the driver using the following module parameters: - -board1: - I/O port for the first ISA board -board2: - I/O port for the second ISA board -board3: - I/O port for the third ISA board -board4: - I/O port for the fourth ISA board - -There is a set of utilities and scripts provided with the external driver -(downloadable from http://www.comtrol.com) that ease the configuration and -setup of the ISA cards. - -The RocketModem II PCI boards require firmware to be loaded into the card -before it will function. The driver has only been tested as a module for this -board. - -Installation Procedures ------------------------ - -RocketPort/RocketModem PCI cards require no driver configuration, they are -automatically detected and configured. - -The RocketPort driver can be installed as a module (recommended) or built -into the kernel. This is selected, as for other drivers, through the `make config` -command from the root of the Linux source tree during the kernel build process. - -The RocketPort/RocketModem serial ports installed by this driver are assigned -device major number 46, and will be named /dev/ttyRx, where x is the port number -starting at zero (ex. /dev/ttyR0, /devttyR1, ...). If you have multiple cards -installed in the system, the mapping of port names to serial ports is displayed -in the system log at /var/log/messages. - -If installed as a module, the module must be loaded. This can be done -manually by entering "modprobe rocket". To have the module loaded automatically -upon system boot, edit a `/etc/modprobe.d/*.conf` file and add the line -"alias char-major-46 rocket". - -In order to use the ports, their device names (nodes) must be created with mknod. -This is only required once, the system will retain the names once created. To -create the RocketPort/RocketModem device names, use the command -"mknod /dev/ttyRx c 46 x" where x is the port number starting at zero. - -For example:: - - > mknod /dev/ttyR0 c 46 0 - > mknod /dev/ttyR1 c 46 1 - > mknod /dev/ttyR2 c 46 2 - -The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes) -for you:: - - >/dev/MAKEDEV ttyR - -ISA Rocketport Boards ---------------------- - -You must assign and configure the I/O addresses used by the ISA Rocketport -card before installing and using it. This is done by setting a set of DIP -switches on the Rocketport board. - - -Setting the I/O address ------------------------ - -Before installing RocketPort(R) or RocketPort RA boards, you must find -a range of I/O addresses for it to use. The first RocketPort card -requires a 68-byte contiguous block of I/O addresses, starting at one -of the following: 0x100h, 0x140h, 0x180h, 0x200h, 0x240h, 0x280h, -0x300h, 0x340h, 0x380h. This I/O address must be reflected in the DIP -switches of *all* of the Rocketport cards. - -The second, third, and fourth RocketPort cards require a 64-byte -contiguous block of I/O addresses, starting at one of the following -I/O addresses: 0x100h, 0x140h, 0x180h, 0x1C0h, 0x200h, 0x240h, 0x280h, -0x2C0h, 0x300h, 0x340h, 0x380h, 0x3C0h. The I/O address used by the -second, third, and fourth Rocketport cards (if present) are set via -software control. The DIP switch settings for the I/O address must be -set to the value of the first Rocketport cards. - -In order to distinguish each of the card from the others, each card -must have a unique board ID set on the dip switches. The first -Rocketport board must be set with the DIP switches corresponding to -the first board, the second board must be set with the DIP switches -corresponding to the second board, etc. IMPORTANT: The board ID is -the only place where the DIP switch settings should differ between the -various Rocketport boards in a system. - -The I/O address range used by any of the RocketPort cards must not -conflict with any other cards in the system, including other -RocketPort cards. Below, you will find a list of commonly used I/O -address ranges which may be in use by other devices in your system. -On a Linux system, "cat /proc/ioports" will also be helpful in -identifying what I/O addresses are being used by devices on your -system. - -Remember, the FIRST RocketPort uses 68 I/O addresses. So, if you set it -for 0x100, it will occupy 0x100 to 0x143. This would mean that you -CAN NOT set the second, third or fourth board for address 0x140 since -the first 4 bytes of that range are used by the first board. You would -need to set the second, third, or fourth board to one of the next available -blocks such as 0x180. - -RocketPort and RocketPort RA SW1 Settings:: - - +-------------------------------+ - | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - +-------+-------+---------------+ - | Unused| Card | I/O Port Block| - +-------------------------------+ - - DIP Switches DIP Switches - 7 8 6 5 - =================== =================== - On On UNUSED, MUST BE ON. On On First Card <==== Default - On Off Second Card - Off On Third Card - Off Off Fourth Card - - DIP Switches I/O Address Range - 4 3 2 1 Used by the First Card - ===================================== - On Off On Off 100-143 - On Off Off On 140-183 - On Off Off Off 180-1C3 <==== Default - Off On On Off 200-243 - Off On Off On 240-283 - Off On Off Off 280-2C3 - Off Off On Off 300-343 - Off Off Off On 340-383 - Off Off Off Off 380-3C3 - -Reporting Bugs --------------- - -For technical support, please provide the following -information: Driver version, kernel release, distribution of -kernel, and type of board you are using. Error messages and log -printouts port configuration details are especially helpful. - -USA: - :Phone: (612) 494-4100 - :FAX: (612) 494-4199 - :email: support@comtrol.com - -Comtrol Europe: - :Phone: +44 (0) 1 869 323-220 - :FAX: +44 (0) 1 869 323-211 - :email: support@comtrol.co.uk - -Web: http://www.comtrol.com -FTP: ftp.comtrol.com diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst index 26d13085a11754aaed8d31d20574d10b796fabe3..e519d374c378912c0f09b327a2459cd7170ea2bc 100644 --- a/Documentation/driver-api/surface_aggregator/client.rst +++ b/Documentation/driver-api/surface_aggregator/client.rst @@ -248,7 +248,7 @@ This example defines a function .. code-block:: c - int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg); + static int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg); executing the specified request, with the controller passed in when calling said function. In this example, the argument is provided via the ``arg`` @@ -296,7 +296,7 @@ This invocation of the macro defines a function .. code-block:: c - int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret); + static int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret); executing the specified request, using the device IDs and controller given in the client device. The full list of such macros for client devices is: diff --git a/Documentation/driver-api/surface_aggregator/clients/dtx.rst b/Documentation/driver-api/surface_aggregator/clients/dtx.rst new file mode 100644 index 0000000000000000000000000000000000000000..e7e7c20007f0e092f7588691b8e44dcd5e583c02 --- /dev/null +++ b/Documentation/driver-api/surface_aggregator/clients/dtx.rst @@ -0,0 +1,718 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +.. |__u16| replace:: :c:type:`__u16 <__u16>` +.. |sdtx_event| replace:: :c:type:`struct sdtx_event <sdtx_event>` +.. |sdtx_event_code| replace:: :c:type:`enum sdtx_event_code <sdtx_event_code>` +.. |sdtx_base_info| replace:: :c:type:`struct sdtx_base_info <sdtx_base_info>` +.. |sdtx_device_mode| replace:: :c:type:`struct sdtx_device_mode <sdtx_device_mode>` + +====================================================== +User-Space DTX (Clipboard Detachment System) Interface +====================================================== + +The ``surface_dtx`` driver is responsible for proper clipboard detachment +and re-attachment handling. To this end, it provides the ``/dev/surface/dtx`` +device file, through which it can interface with a user-space daemon. This +daemon is then ultimately responsible for determining and taking necessary +actions, such as unmounting devices attached to the base, +unloading/reloading the graphics-driver, user-notifications, etc. + +There are two basic communication principles used in this driver: Commands +(in other parts of the documentation also referred to as requests) and +events. Commands are sent to the EC and may have a different implications in +different contexts. Events are sent by the EC upon some internal state +change. Commands are always driver-initiated, whereas events are always +initiated by the EC. + +.. contents:: + +Nomenclature +============ + +* **Clipboard:** + The detachable upper part of the Surface Book, housing the screen and CPU. + +* **Base:** + The lower part of the Surface Book from which the clipboard can be + detached, optionally (model dependent) housing the discrete GPU (dGPU). + +* **Latch:** + The mechanism keeping the clipboard attached to the base in normal + operation and allowing it to be detached when requested. + +* **Silently ignored commands:** + The command is accepted by the EC as a valid command and acknowledged + (following the standard communication protocol), but the EC does not act + upon it, i.e. ignores it.e upper part of the + + +Detachment Process +================== + +Warning: This part of the documentation is based on reverse engineering and +testing and thus may contain errors or be incomplete. + +Latch States +------------ + +The latch mechanism has two major states: *open* and *closed*. In the +*closed* state (default), the clipboard is secured to the base, whereas in +the *open* state, the clipboard can be removed by a user. + +The latch can additionally be locked and, correspondingly, unlocked, which +can influence the detachment procedure. Specifically, this locking mechanism +is intended to prevent the dGPU, positioned in the base of the device, from +being hot-unplugged while in use. More details can be found in the +documentation for the detachment procedure below. By default, the latch is +unlocked. + +Detachment Procedure +-------------------- + +Note that the detachment process is governed fully by the EC. The +``surface_dtx`` driver only relays events from the EC to user-space and +commands from user-space to the EC, i.e. it does not influence this process. + +The detachment process is started with the user pressing the *detach* button +on the base of the device or executing the ``SDTX_IOCTL_LATCH_REQUEST`` IOCTL. +Following that: + +1. The EC turns on the indicator led on the detach-button, sends a + *detach-request* event (``SDTX_EVENT_REQUEST``), and awaits further + instructions/commands. In case the latch is unlocked, the led will flash + green. If the latch has been locked, the led will be solid red + +2. The event is, via the ``surface_dtx`` driver, relayed to user-space, where + an appropriate user-space daemon can handle it and send instructions back + to the EC via IOCTLs provided by this driver. + +3. The EC waits for instructions from user-space and acts according to them. + If the EC does not receive any instructions in a given period, it will + time out and continue as follows: + + - If the latch is unlocked, the EC will open the latch and the clipboard + can be detached from the base. This is the exact behavior as without + this driver or any user-space daemon. See the ``SDTX_IOCTL_LATCH_CONFIRM`` + description below for more details on the follow-up behavior of the EC. + + - If the latch is locked, the EC will *not* open the latch, meaning the + clipboard cannot be detached from the base. Furthermore, the EC sends + an cancel event (``SDTX_EVENT_CANCEL``) detailing this with the cancel + reason ``SDTX_DETACH_TIMEDOUT`` (see :ref:`events` for details). + +Valid responses by a user-space daemon to a detachment request event are: + +- Execute ``SDTX_IOCTL_LATCH_REQUEST``. This will immediately abort the + detachment process. Furthermore, the EC will send a detach-request event, + similar to the user pressing the detach-button to cancel said process (see + below). + +- Execute ``SDTX_IOCTL_LATCH_CONFIRM``. This will cause the EC to open the + latch, after which the user can separate clipboard and base. + + As this changes the latch state, a *latch-status* event + (``SDTX_EVENT_LATCH_STATUS``) will be sent once the latch has been opened + successfully. If the EC fails to open the latch, e.g. due to hardware + error or low battery, a latch-cancel event (``SDTX_EVENT_CANCEL``) will be + sent with the cancel reason indicating the specific failure. + + If the latch is currently locked, the latch will automatically be + unlocked before it is opened. + +- Execute ``SDTX_IOCTL_LATCH_HEARTBEAT``. This will reset the internal timeout. + No other actions will be performed, i.e. the detachment process will neither + be completed nor canceled, and the EC will still be waiting for further + responses. + +- Execute ``SDTX_IOCTL_LATCH_CANCEL``. This will abort the detachment process, + similar to ``SDTX_IOCTL_LATCH_REQUEST``, described above, or the button + press, described below. A *generic request* event (``SDTX_EVENT_REQUEST``) + is send in response to this. In contrast to those, however, this command + does not trigger a new detachment process if none is currently in + progress. + +- Do nothing. The detachment process eventually times out as described in + point 3. + +See :ref:`ioctls` for more details on these responses. + +It is important to note that, if the user presses the detach button at any +point when a detachment operation is in progress (i.e. after the EC has sent +the initial *detach-request* event (``SDTX_EVENT_REQUEST``) and before it +received the corresponding response concluding the process), the detachment +process is canceled on the EC-level and an identical event is being sent. +Thus a *detach-request* event, by itself, does not signal the start of the +detachment process. + +The detachment process may further be canceled by the EC due to hardware +failures or a low clipboard battery. This is done via a cancel event +(``SDTX_EVENT_CANCEL``) with the corresponding cancel reason. + + +User-Space Interface Documentation +================================== + +Error Codes and Status Values +----------------------------- + +Error and status codes are divided into different categories, which can be +used to determine if the status code is an error, and, if it is, the +severity and type of that error. The current categories are: + +.. flat-table:: Overview of Status/Error Categories. + :widths: 2 1 3 + :header-rows: 1 + + * - Name + - Value + - Short Description + + * - ``STATUS`` + - ``0x0000`` + - Non-error status codes. + + * - ``RUNTIME_ERROR`` + - ``0x1000`` + - Non-critical runtime errors. + + * - ``HARDWARE_ERROR`` + - ``0x2000`` + - Critical hardware failures. + + * - ``UNKNOWN`` + - ``0xF000`` + - Unknown error codes. + +Other categories are reserved for future use. The ``SDTX_CATEGORY()`` macro +can be used to determine the category of any status value. The +``SDTX_SUCCESS()`` macro can be used to check if the status value is a +success value (``SDTX_CATEGORY_STATUS``) or if it indicates a failure. + +Unknown status or error codes sent by the EC are assigned to the ``UNKNOWN`` +category by the driver and may be implemented via their own code in the +future. + +Currently used error codes are: + +.. flat-table:: Overview of Error Codes. + :widths: 2 1 1 3 + :header-rows: 1 + + * - Name + - Category + - Value + - Short Description + + * - ``SDTX_DETACH_NOT_FEASIBLE`` + - ``RUNTIME`` + - ``0x1001`` + - Detachment not feasible due to low clipboard battery. + + * - ``SDTX_DETACH_TIMEDOUT`` + - ``RUNTIME`` + - ``0x1002`` + - Detachment process timed out while the latch was locked. + + * - ``SDTX_ERR_FAILED_TO_OPEN`` + - ``HARDWARE`` + - ``0x2001`` + - Failed to open latch. + + * - ``SDTX_ERR_FAILED_TO_REMAIN_OPEN`` + - ``HARDWARE`` + - ``0x2002`` + - Failed to keep latch open. + + * - ``SDTX_ERR_FAILED_TO_CLOSE`` + - ``HARDWARE`` + - ``0x2003`` + - Failed to close latch. + +Other error codes are reserved for future use. Non-error status codes may +overlap and are generally only unique within their use-case: + +.. flat-table:: Latch Status Codes. + :widths: 2 1 1 3 + :header-rows: 1 + + * - Name + - Category + - Value + - Short Description + + * - ``SDTX_LATCH_CLOSED`` + - ``STATUS`` + - ``0x0000`` + - Latch is closed/has been closed. + + * - ``SDTX_LATCH_OPENED`` + - ``STATUS`` + - ``0x0001`` + - Latch is open/has been opened. + +.. flat-table:: Base State Codes. + :widths: 2 1 1 3 + :header-rows: 1 + + * - Name + - Category + - Value + - Short Description + + * - ``SDTX_BASE_DETACHED`` + - ``STATUS`` + - ``0x0000`` + - Base has been detached/is not present. + + * - ``SDTX_BASE_ATTACHED`` + - ``STATUS`` + - ``0x0001`` + - Base has been attached/is present. + +Again, other codes are reserved for future use. + +.. _events: + +Events +------ + +Events can be received by reading from the device file. They are disabled by +default and have to be enabled by executing ``SDTX_IOCTL_EVENTS_ENABLE`` +first. All events follow the layout prescribed by |sdtx_event|. Specific +event types can be identified by their event code, described in +|sdtx_event_code|. Note that other event codes are reserved for future use, +thus an event parser must be able to handle any unknown/unsupported event +types gracefully, by relying on the payload length given in the event header. + +Currently provided event types are: + +.. flat-table:: Overview of DTX events. + :widths: 2 1 1 3 + :header-rows: 1 + + * - Name + - Code + - Payload + - Short Description + + * - ``SDTX_EVENT_REQUEST`` + - ``1`` + - ``0`` bytes + - Detachment process initiated/aborted. + + * - ``SDTX_EVENT_CANCEL`` + - ``2`` + - ``2`` bytes + - EC canceled detachment process. + + * - ``SDTX_EVENT_BASE_CONNECTION`` + - ``3`` + - ``4`` bytes + - Base connection state changed. + + * - ``SDTX_EVENT_LATCH_STATUS`` + - ``4`` + - ``2`` bytes + - Latch status changed. + + * - ``SDTX_EVENT_DEVICE_MODE`` + - ``5`` + - ``2`` bytes + - Device mode changed. + +Individual events in more detail: + +``SDTX_EVENT_REQUEST`` +^^^^^^^^^^^^^^^^^^^^^^ + +Sent when a detachment process is started or, if in progress, aborted by the +user, either via a detach button press or a detach request +(``SDTX_IOCTL_LATCH_REQUEST``) being sent from user-space. + +Does not have any payload. + +``SDTX_EVENT_CANCEL`` +^^^^^^^^^^^^^^^^^^^^^ + +Sent when a detachment process is canceled by the EC due to unfulfilled +preconditions (e.g. clipboard battery too low to detach) or hardware +failure. The reason for cancellation is given in the event payload detailed +below and can be one of + +* ``SDTX_DETACH_TIMEDOUT``: Detachment timed out while the latch was locked. + The latch has neither been opened nor unlocked. + +* ``SDTX_DETACH_NOT_FEASIBLE``: Detachment not feasible due to low clipboard + battery. + +* ``SDTX_ERR_FAILED_TO_OPEN``: Could not open the latch (hardware failure). + +* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``: Could not keep the latch open (hardware + failure). + +* ``SDTX_ERR_FAILED_TO_CLOSE``: Could not close the latch (hardware failure). + +Other error codes in this context are reserved for future use. + +These codes can be classified via the ``SDTX_CATEGORY()`` macro to discern +between critical hardware errors (``SDTX_CATEGORY_HARDWARE_ERROR``) or +runtime errors (``SDTX_CATEGORY_RUNTIME_ERROR``), the latter of which may +happen during normal operation if certain preconditions for detachment are +not given. + +.. flat-table:: Detachment Cancel Event Payload + :widths: 1 1 4 + :header-rows: 1 + + * - Field + - Type + - Description + + * - ``reason`` + - |__u16| + - Reason for cancellation. + +``SDTX_EVENT_BASE_CONNECTION`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sent when the base connection state has changed, i.e. when the base has been +attached, detached, or detachment has become infeasible due to low clipboard +battery. The new state and, if a base is connected, ID of the base is +provided as payload of type |sdtx_base_info| with its layout presented +below: + +.. flat-table:: Base-Connection-Change Event Payload + :widths: 1 1 4 + :header-rows: 1 + + * - Field + - Type + - Description + + * - ``state`` + - |__u16| + - Base connection state. + + * - ``base_id`` + - |__u16| + - Type of base connected (zero if none). + +Possible values for ``state`` are: + +* ``SDTX_BASE_DETACHED``, +* ``SDTX_BASE_ATTACHED``, and +* ``SDTX_DETACH_NOT_FEASIBLE``. + +Other values are reserved for future use. + +``SDTX_EVENT_LATCH_STATUS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sent when the latch status has changed, i.e. when the latch has been opened, +closed, or an error occurred. The current status is provided as payload: + +.. flat-table:: Latch-Status-Change Event Payload + :widths: 1 1 4 + :header-rows: 1 + + * - Field + - Type + - Description + + * - ``status`` + - |__u16| + - Latch status. + +Possible values for ``status`` are: + +* ``SDTX_LATCH_CLOSED``, +* ``SDTX_LATCH_OPENED``, +* ``SDTX_ERR_FAILED_TO_OPEN``, +* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``, and +* ``SDTX_ERR_FAILED_TO_CLOSE``. + +Other values are reserved for future use. + +``SDTX_EVENT_DEVICE_MODE`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sent when the device mode has changed. The new device mode is provided as +payload: + +.. flat-table:: Device-Mode-Change Event Payload + :widths: 1 1 4 + :header-rows: 1 + + * - Field + - Type + - Description + + * - ``mode`` + - |__u16| + - Device operation mode. + +Possible values for ``mode`` are: + +* ``SDTX_DEVICE_MODE_TABLET``, +* ``SDTX_DEVICE_MODE_LAPTOP``, and +* ``SDTX_DEVICE_MODE_STUDIO``. + +Other values are reserved for future use. + +.. _ioctls: + +IOCTLs +------ + +The following IOCTLs are provided: + +.. flat-table:: Overview of DTX IOCTLs + :widths: 1 1 1 1 4 + :header-rows: 1 + + * - Type + - Number + - Direction + - Name + - Description + + * - ``0xA5`` + - ``0x21`` + - ``-`` + - ``EVENTS_ENABLE`` + - Enable events for the current file descriptor. + + * - ``0xA5`` + - ``0x22`` + - ``-`` + - ``EVENTS_DISABLE`` + - Disable events for the current file descriptor. + + * - ``0xA5`` + - ``0x23`` + - ``-`` + - ``LATCH_LOCK`` + - Lock the latch. + + * - ``0xA5`` + - ``0x24`` + - ``-`` + - ``LATCH_UNLOCK`` + - Unlock the latch. + + * - ``0xA5`` + - ``0x25`` + - ``-`` + - ``LATCH_REQUEST`` + - Request clipboard detachment. + + * - ``0xA5`` + - ``0x26`` + - ``-`` + - ``LATCH_CONFIRM`` + - Confirm clipboard detachment request. + + * - ``0xA5`` + - ``0x27`` + - ``-`` + - ``LATCH_HEARTBEAT`` + - Send heartbeat signal to EC. + + * - ``0xA5`` + - ``0x28`` + - ``-`` + - ``LATCH_CANCEL`` + - Cancel detachment process. + + * - ``0xA5`` + - ``0x29`` + - ``R`` + - ``GET_BASE_INFO`` + - Get current base/connection information. + + * - ``0xA5`` + - ``0x2A`` + - ``R`` + - ``GET_DEVICE_MODE`` + - Get current device operation mode. + + * - ``0xA5`` + - ``0x2B`` + - ``R`` + - ``GET_LATCH_STATUS`` + - Get current device latch status. + +``SDTX_IOCTL_EVENTS_ENABLE`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x22)``. + +Enable events for the current file descriptor. Events can be obtained by +reading from the device, if enabled. Events are disabled by default. + +``SDTX_IOCTL_EVENTS_DISABLE`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x22)``. + +Disable events for the current file descriptor. Events can be obtained by +reading from the device, if enabled. Events are disabled by default. + +``SDTX_IOCTL_LATCH_LOCK`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x23)``. + +Locks the latch, causing the detachment procedure to abort without opening +the latch on timeout. The latch is unlocked by default. This command will be +silently ignored if the latch is already locked. + +``SDTX_IOCTL_LATCH_UNLOCK`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x24)``. + +Unlocks the latch, causing the detachment procedure to open the latch on +timeout. The latch is unlocked by default. This command will not open the +latch when sent during an ongoing detachment process. It will be silently +ignored if the latch is already unlocked. + +``SDTX_IOCTL_LATCH_REQUEST`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x25)``. + +Generic latch request. Behavior depends on the context: If no +detachment-process is active, detachment is requested. Otherwise the +currently active detachment-process will be aborted. + +If a detachment process is canceled by this operation, a generic detachment +request event (``SDTX_EVENT_REQUEST``) will be sent. + +This essentially behaves the same as a detachment button press. + +``SDTX_IOCTL_LATCH_CONFIRM`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x26)``. + +Acknowledges and confirms a latch request. If sent during an ongoing +detachment process, this command causes the latch to be opened immediately. +The latch will also be opened if it has been locked. In this case, the latch +lock is reset to the unlocked state. + +This command will be silently ignored if there is currently no detachment +procedure in progress. + +``SDTX_IOCTL_LATCH_HEARTBEAT`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x27)``. + +Sends a heartbeat, essentially resetting the detachment timeout. This +command can be used to keep the detachment process alive while work required +for the detachment to succeed is still in progress. + +This command will be silently ignored if there is currently no detachment +procedure in progress. + +``SDTX_IOCTL_LATCH_CANCEL`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IO(0xA5, 0x28)``. + +Cancels detachment in progress (if any). If a detachment process is canceled +by this operation, a generic detachment request event +(``SDTX_EVENT_REQUEST``) will be sent. + +This command will be silently ignored if there is currently no detachment +procedure in progress. + +``SDTX_IOCTL_GET_BASE_INFO`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IOR(0xA5, 0x29, struct sdtx_base_info)``. + +Get the current base connection state (i.e. attached/detached) and the type +of the base connected to the clipboard. This is command essentially provides +a way to query the information provided by the base connection change event +(``SDTX_EVENT_BASE_CONNECTION``). + +Possible values for ``struct sdtx_base_info.state`` are: + +* ``SDTX_BASE_DETACHED``, +* ``SDTX_BASE_ATTACHED``, and +* ``SDTX_DETACH_NOT_FEASIBLE``. + +Other values are reserved for future use. + +``SDTX_IOCTL_GET_DEVICE_MODE`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IOR(0xA5, 0x2A, __u16)``. + +Returns the device operation mode, indicating if and how the base is +attached to the clipboard. This is command essentially provides a way to +query the information provided by the device mode change event +(``SDTX_EVENT_DEVICE_MODE``). + +Returned values are: + +* ``SDTX_DEVICE_MODE_LAPTOP`` +* ``SDTX_DEVICE_MODE_TABLET`` +* ``SDTX_DEVICE_MODE_STUDIO`` + +See |sdtx_device_mode| for details. Other values are reserved for future +use. + + +``SDTX_IOCTL_GET_LATCH_STATUS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Defined as ``_IOR(0xA5, 0x2B, __u16)``. + +Get the current latch status or (presumably) the last error encountered when +trying to open/close the latch. This is command essentially provides a way +to query the information provided by the latch status change event +(``SDTX_EVENT_LATCH_STATUS``). + +Returned values are: + +* ``SDTX_LATCH_CLOSED``, +* ``SDTX_LATCH_OPENED``, +* ``SDTX_ERR_FAILED_TO_OPEN``, +* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``, and +* ``SDTX_ERR_FAILED_TO_CLOSE``. + +Other values are reserved for future use. + +A Note on Base IDs +------------------ + +Base types/IDs provided via ``SDTX_EVENT_BASE_CONNECTION`` or +``SDTX_IOCTL_GET_BASE_INFO`` are directly forwarded from the EC in the lower +byte of the combined |__u16| value, with the driver storing the EC type from +which this ID comes in the high byte (without this, base IDs over different +types of ECs may be overlapping). + +The ``SDTX_DEVICE_TYPE()`` macro can be used to determine the EC device +type. This can be one of + +* ``SDTX_DEVICE_TYPE_HID``, for Surface Aggregator Module over HID, and + +* ``SDTX_DEVICE_TYPE_SSH``, for Surface Aggregator Module over Surface Serial + Hub. + +Note that currently only the ``SSH`` type EC is supported, however ``HID`` +type is reserved for future use. + +Structures and Enums +-------------------- + +.. kernel-doc:: include/uapi/linux/surface_aggregator/dtx.h + +API Users +========= + +A user-space daemon utilizing this API can be found at +https://github.com/linux-surface/surface-dtx-daemon. diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst index 3ccabce2327150c67bf83258be46ddf231e7c63e..98ea9946b8a2e8f42db4914b6bab52dc60aa194b 100644 --- a/Documentation/driver-api/surface_aggregator/clients/index.rst +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst @@ -11,6 +11,7 @@ This is the documentation for client drivers themselves. Refer to :maxdepth: 1 cdev + dtx san .. only:: subproject and html diff --git a/Documentation/driver-api/usb/usb.rst b/Documentation/driver-api/usb/usb.rst index 078e981e2b161f387f7703032f19265e437fea1b..543e70434da2273a0cc7da6fc3e4441217228a1f 100644 --- a/Documentation/driver-api/usb/usb.rst +++ b/Documentation/driver-api/usb/usb.rst @@ -109,15 +109,16 @@ well as to make sure they aren't relying on some HCD-specific behavior. USB-Standard Types ================== -In ``<linux/usb/ch9.h>`` you will find the USB data types defined in -chapter 9 of the USB specification. These data types are used throughout -USB, and in APIs including this host side API, gadget APIs, usb character -devices and debugfs interfaces. +In ``drivers/usb/common/common.c`` and ``drivers/usb/common/debug.c`` you +will find the USB data types defined in chapter 9 of the USB specification. +These data types are used throughout USB, and in APIs including this host +side API, gadget APIs, usb character devices and debugfs interfaces. -.. kernel-doc:: include/linux/usb/ch9.h - :internal: +.. kernel-doc:: drivers/usb/common/common.c + :export: -.. _usb_header: +.. kernel-doc:: drivers/usb/common/debug.c + :export: Host-Side Data Types and Macros =============================== diff --git a/Documentation/driver-api/xilinx/eemi.rst b/Documentation/driver-api/xilinx/eemi.rst index 9dcbc6f18d75df1d21124cff5757782e68c7eab0..c1bc47b9000dce12cfd804de30a45f68ec3336bb 100644 --- a/Documentation/driver-api/xilinx/eemi.rst +++ b/Documentation/driver-api/xilinx/eemi.rst @@ -16,35 +16,8 @@ components running across different processing clusters on a chip or device to communicate with a power management controller (PMC) on a device to issue or respond to power management requests. -EEMI ops is a structure containing all eemi APIs supported by Zynq MPSoC. -The zynqmp-firmware driver maintain all EEMI APIs in zynqmp_eemi_ops -structure. Any driver who want to communicate with PMC using EEMI APIs -can call zynqmp_pm_get_eemi_ops(). - -Example of EEMI ops:: - - /* zynqmp-firmware driver maintain all EEMI APIs */ - struct zynqmp_eemi_ops { - int (*get_api_version)(u32 *version); - int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); - }; - - static const struct zynqmp_eemi_ops eemi_ops = { - .get_api_version = zynqmp_pm_get_api_version, - .query_data = zynqmp_pm_query_data, - }; - -Example of EEMI ops usage:: - - static const struct zynqmp_eemi_ops *eemi_ops; - u32 ret_payload[PAYLOAD_ARG_CNT]; - int ret; - - eemi_ops = zynqmp_pm_get_eemi_ops(); - if (IS_ERR(eemi_ops)) - return PTR_ERR(eemi_ops); - - ret = eemi_ops->query_data(qdata, ret_payload); +Any driver who wants to communicate with PMC using EEMI APIs use the +functions provided for each function. IOCTL ------ diff --git a/Documentation/fb/fbcon.rst b/Documentation/fb/fbcon.rst index 57f66de2f7e167666267d23ac6a327f3ed91c2d4..212f7003cfbab2683174ea4181416532e85be0c7 100644 --- a/Documentation/fb/fbcon.rst +++ b/Documentation/fb/fbcon.rst @@ -207,9 +207,9 @@ Documentation/driver-api/console.rst. To summarize: Echo a value to the bind file that represents the framebuffer console driver. So assuming vtcon1 represents fbcon, then:: - echo 1 > sys/class/vtconsole/vtcon1/bind - attach framebuffer console to + echo 1 > /sys/class/vtconsole/vtcon1/bind - attach framebuffer console to console layer - echo 0 > sys/class/vtconsole/vtcon1/bind - detach framebuffer console from + echo 0 > /sys/class/vtconsole/vtcon1/bind - detach framebuffer console from console layer If fbcon is detached from the console layer, your boot console driver (which is diff --git a/Documentation/features/arch-support.txt b/Documentation/features/arch-support.txt index d22a1095e661c0578c76fd94131e5fe50855a691..118ae031840b7e5a9a42d920cbe1dcaae0defb29 100644 --- a/Documentation/features/arch-support.txt +++ b/Documentation/features/arch-support.txt @@ -8,4 +8,5 @@ The meaning of entries in the tables is: | ok | # feature supported by the architecture |TODO| # feature not yet supported by the architecture | .. | # feature cannot be supported by the hardware + | N/A| # feature doesn't apply to the architecture diff --git a/Documentation/features/vm/TLB/arch-support.txt b/Documentation/features/vm/TLB/arch-support.txt index 48a5ca54839935e4f7721824de4358491cf738e2..e1c3a4c4d107a8afa4c2318d7a3be02ffbad826f 100644 --- a/Documentation/features/vm/TLB/arch-support.txt +++ b/Documentation/features/vm/TLB/arch-support.txt @@ -9,7 +9,7 @@ | alpha: | TODO | | arc: | TODO | | arm: | TODO | - | arm64: | TODO | + | arm64: | N/A | | csky: | TODO | | h8300: | .. | | hexagon: | TODO | diff --git a/Documentation/filesystems/api-summary.rst b/Documentation/filesystems/api-summary.rst index a94f17d9b8365fddc44eb32df1fc50507e908577..7e5c04c9861984dd022edda99e2ef142e60c2cdc 100644 --- a/Documentation/filesystems/api-summary.rst +++ b/Documentation/filesystems/api-summary.rst @@ -101,6 +101,9 @@ Other Functions .. kernel-doc:: fs/xattr.c :export: +.. kernel-doc:: fs/namespace.c + :export: + The proc filesystem =================== @@ -122,6 +125,12 @@ Events based on file descriptors .. kernel-doc:: fs/eventfd.c :export: +eventpoll (epoll) interfaces +============================ + +.. kernel-doc:: fs/eventpoll.c + :internal: + The Filesystem for Exporting Kernel Objects =========================================== diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index 1f76b1cb33484361625c4460b6356906a88bc73e..d4853cb919d2979b9765e68c47b1a00d20ae2e59 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -53,6 +53,7 @@ filesystem implementations. journalling fscrypt fsverity + netfs_library Filesystems =========== diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index b7dcc86c92a45f5ed47cd17cbc5a8b82855927c2..729ce492b6620257af50dc54ad46d704510ce949 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -80,13 +80,16 @@ prototypes:: struct file *, unsigned open_flag, umode_t create_mode); int (*tmpfile) (struct inode *, struct dentry *, umode_t); + int (*fileattr_set)(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); + int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); locking rules: all may block -============ ============================================= +============= ============================================= ops i_rwsem(inode) -============ ============================================= +============= ============================================= lookup: shared create: exclusive link: exclusive (both) @@ -107,7 +110,9 @@ fiemap: no update_time: no atomic_open: shared (exclusive if O_CREAT is set in open flags) tmpfile: no -============ ============================================= +fileattr_get: no or exclusive +fileattr_set: exclusive +============= ============================================= Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem diff --git a/Documentation/filesystems/netfs_library.rst b/Documentation/filesystems/netfs_library.rst new file mode 100644 index 0000000000000000000000000000000000000000..57a64184781863f422ca0c0a02abdd9ae4c2d531 --- /dev/null +++ b/Documentation/filesystems/netfs_library.rst @@ -0,0 +1,526 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================= +NETWORK FILESYSTEM HELPER LIBRARY +================================= + +.. Contents: + + - Overview. + - Buffered read helpers. + - Read helper functions. + - Read helper structures. + - Read helper operations. + - Read helper procedure. + - Read helper cache API. + + +Overview +======== + +The network filesystem helper library is a set of functions designed to aid a +network filesystem in implementing VM/VFS operations. For the moment, that +just includes turning various VM buffered read operations into requests to read +from the server. The helper library, however, can also interpose other +services, such as local caching or local data encryption. + +Note that the library module doesn't link against local caching directly, so +access must be provided by the netfs. + + +Buffered Read Helpers +===================== + +The library provides a set of read helpers that handle the ->readpage(), +->readahead() and much of the ->write_begin() VM operations and translate them +into a common call framework. + +The following services are provided: + + * Handles transparent huge pages (THPs). + + * Insulates the netfs from VM interface changes. + + * Allows the netfs to arbitrarily split reads up into pieces, even ones that + don't match page sizes or page alignments and that may cross pages. + + * Allows the netfs to expand a readahead request in both directions to meet + its needs. + + * Allows the netfs to partially fulfil a read, which will then be resubmitted. + + * Handles local caching, allowing cached data and server-read data to be + interleaved for a single request. + + * Handles clearing of bufferage that aren't on the server. + + * Handle retrying of reads that failed, switching reads from the cache to the + server as necessary. + + * In the future, this is a place that other services can be performed, such as + local encryption of data to be stored remotely or in the cache. + +From the network filesystem, the helpers require a table of operations. This +includes a mandatory method to issue a read operation along with a number of +optional methods. + + +Read Helper Functions +--------------------- + +Three read helpers are provided:: + + * void netfs_readahead(struct readahead_control *ractl, + const struct netfs_read_request_ops *ops, + void *netfs_priv);`` + * int netfs_readpage(struct file *file, + struct page *page, + const struct netfs_read_request_ops *ops, + void *netfs_priv); + * int netfs_write_begin(struct file *file, + struct address_space *mapping, + loff_t pos, + unsigned int len, + unsigned int flags, + struct page **_page, + void **_fsdata, + const struct netfs_read_request_ops *ops, + void *netfs_priv); + +Each corresponds to a VM operation, with the addition of a couple of parameters +for the use of the read helpers: + + * ``ops`` + + A table of operations through which the helpers can talk to the filesystem. + + * ``netfs_priv`` + + Filesystem private data (can be NULL). + +Both of these values will be stored into the read request structure. + +For ->readahead() and ->readpage(), the network filesystem should just jump +into the corresponding read helper; whereas for ->write_begin(), it may be a +little more complicated as the network filesystem might want to flush +conflicting writes or track dirty data and needs to put the acquired page if an +error occurs after calling the helper. + +The helpers manage the read request, calling back into the network filesystem +through the suppplied table of operations. Waits will be performed as +necessary before returning for helpers that are meant to be synchronous. + +If an error occurs and netfs_priv is non-NULL, ops->cleanup() will be called to +deal with it. If some parts of the request are in progress when an error +occurs, the request will get partially completed if sufficient data is read. + +Additionally, there is:: + + * void netfs_subreq_terminated(struct netfs_read_subrequest *subreq, + ssize_t transferred_or_error, + bool was_async); + +which should be called to complete a read subrequest. This is given the number +of bytes transferred or a negative error code, plus a flag indicating whether +the operation was asynchronous (ie. whether the follow-on processing can be +done in the current context, given this may involve sleeping). + + +Read Helper Structures +---------------------- + +The read helpers make use of a couple of structures to maintain the state of +the read. The first is a structure that manages a read request as a whole:: + + struct netfs_read_request { + struct inode *inode; + struct address_space *mapping; + struct netfs_cache_resources cache_resources; + void *netfs_priv; + loff_t start; + size_t len; + loff_t i_size; + const struct netfs_read_request_ops *netfs_ops; + unsigned int debug_id; + ... + }; + +The above fields are the ones the netfs can use. They are: + + * ``inode`` + * ``mapping`` + + The inode and the address space of the file being read from. The mapping + may or may not point to inode->i_data. + + * ``cache_resources`` + + Resources for the local cache to use, if present. + + * ``netfs_priv`` + + The network filesystem's private data. The value for this can be passed in + to the helper functions or set during the request. The ->cleanup() op will + be called if this is non-NULL at the end. + + * ``start`` + * ``len`` + + The file position of the start of the read request and the length. These + may be altered by the ->expand_readahead() op. + + * ``i_size`` + + The size of the file at the start of the request. + + * ``netfs_ops`` + + A pointer to the operation table. The value for this is passed into the + helper functions. + + * ``debug_id`` + + A number allocated to this operation that can be displayed in trace lines + for reference. + + +The second structure is used to manage individual slices of the overall read +request:: + + struct netfs_read_subrequest { + struct netfs_read_request *rreq; + loff_t start; + size_t len; + size_t transferred; + unsigned long flags; + unsigned short debug_index; + ... + }; + +Each subrequest is expected to access a single source, though the helpers will +handle falling back from one source type to another. The members are: + + * ``rreq`` + + A pointer to the read request. + + * ``start`` + * ``len`` + + The file position of the start of this slice of the read request and the + length. + + * ``transferred`` + + The amount of data transferred so far of the length of this slice. The + network filesystem or cache should start the operation this far into the + slice. If a short read occurs, the helpers will call again, having updated + this to reflect the amount read so far. + + * ``flags`` + + Flags pertaining to the read. There are two of interest to the filesystem + or cache: + + * ``NETFS_SREQ_CLEAR_TAIL`` + + This can be set to indicate that the remainder of the slice, from + transferred to len, should be cleared. + + * ``NETFS_SREQ_SEEK_DATA_READ`` + + This is a hint to the cache that it might want to try skipping ahead to + the next data (ie. using SEEK_DATA). + + * ``debug_index`` + + A number allocated to this slice that can be displayed in trace lines for + reference. + + +Read Helper Operations +---------------------- + +The network filesystem must provide the read helpers with a table of operations +through which it can issue requests and negotiate:: + + struct netfs_read_request_ops { + void (*init_rreq)(struct netfs_read_request *rreq, struct file *file); + bool (*is_cache_enabled)(struct inode *inode); + int (*begin_cache_operation)(struct netfs_read_request *rreq); + void (*expand_readahead)(struct netfs_read_request *rreq); + bool (*clamp_length)(struct netfs_read_subrequest *subreq); + void (*issue_op)(struct netfs_read_subrequest *subreq); + bool (*is_still_valid)(struct netfs_read_request *rreq); + int (*check_write_begin)(struct file *file, loff_t pos, unsigned len, + struct page *page, void **_fsdata); + void (*done)(struct netfs_read_request *rreq); + void (*cleanup)(struct address_space *mapping, void *netfs_priv); + }; + +The operations are as follows: + + * ``init_rreq()`` + + [Optional] This is called to initialise the request structure. It is given + the file for reference and can modify the ->netfs_priv value. + + * ``is_cache_enabled()`` + + [Required] This is called by netfs_write_begin() to ask if the file is being + cached. It should return true if it is being cached and false otherwise. + + * ``begin_cache_operation()`` + + [Optional] This is called to ask the network filesystem to call into the + cache (if present) to initialise the caching state for this read. The netfs + library module cannot access the cache directly, so the cache should call + something like fscache_begin_read_operation() to do this. + + The cache gets to store its state in ->cache_resources and must set a table + of operations of its own there (though of a different type). + + This should return 0 on success and an error code otherwise. If an error is + reported, the operation may proceed anyway, just without local caching (only + out of memory and interruption errors cause failure here). + + * ``expand_readahead()`` + + [Optional] This is called to allow the filesystem to expand the size of a + readahead read request. The filesystem gets to expand the request in both + directions, though it's not permitted to reduce it as the numbers may + represent an allocation already made. If local caching is enabled, it gets + to expand the request first. + + Expansion is communicated by changing ->start and ->len in the request + structure. Note that if any change is made, ->len must be increased by at + least as much as ->start is reduced. + + * ``clamp_length()`` + + [Optional] This is called to allow the filesystem to reduce the size of a + subrequest. The filesystem can use this, for example, to chop up a request + that has to be split across multiple servers or to put multiple reads in + flight. + + This should return 0 on success and an error code on error. + + * ``issue_op()`` + + [Required] The helpers use this to dispatch a subrequest to the server for + reading. In the subrequest, ->start, ->len and ->transferred indicate what + data should be read from the server. + + There is no return value; the netfs_subreq_terminated() function should be + called to indicate whether or not the operation succeeded and how much data + it transferred. The filesystem also should not deal with setting pages + uptodate, unlocking them or dropping their refs - the helpers need to deal + with this as they have to coordinate with copying to the local cache. + + Note that the helpers have the pages locked, but not pinned. It is possible + to use the ITER_XARRAY iov iterator to refer to the range of the inode that + is being operated upon without the need to allocate large bvec tables. + + * ``is_still_valid()`` + + [Optional] This is called to find out if the data just read from the local + cache is still valid. It should return true if it is still valid and false + if not. If it's not still valid, it will be reread from the server. + + * ``check_write_begin()`` + + [Optional] This is called from the netfs_write_begin() helper once it has + allocated/grabbed the page to be modified to allow the filesystem to flush + conflicting state before allowing it to be modified. + + It should return 0 if everything is now fine, -EAGAIN if the page should be + regrabbed and any other error code to abort the operation. + + * ``done`` + + [Optional] This is called after the pages in the request have all been + unlocked (and marked uptodate if applicable). + + * ``cleanup`` + + [Optional] This is called as the request is being deallocated so that the + filesystem can clean up ->netfs_priv. + + + +Read Helper Procedure +--------------------- + +The read helpers work by the following general procedure: + + * Set up the request. + + * For readahead, allow the local cache and then the network filesystem to + propose expansions to the read request. This is then proposed to the VM. + If the VM cannot fully perform the expansion, a partially expanded read will + be performed, though this may not get written to the cache in its entirety. + + * Loop around slicing chunks off of the request to form subrequests: + + * If a local cache is present, it gets to do the slicing, otherwise the + helpers just try to generate maximal slices. + + * The network filesystem gets to clamp the size of each slice if it is to be + the source. This allows rsize and chunking to be implemented. + + * The helpers issue a read from the cache or a read from the server or just + clears the slice as appropriate. + + * The next slice begins at the end of the last one. + + * As slices finish being read, they terminate. + + * When all the subrequests have terminated, the subrequests are assessed and + any that are short or have failed are reissued: + + * Failed cache requests are issued against the server instead. + + * Failed server requests just fail. + + * Short reads against either source will be reissued against that source + provided they have transferred some more data: + + * The cache may need to skip holes that it can't do DIO from. + + * If NETFS_SREQ_CLEAR_TAIL was set, a short read will be cleared to the + end of the slice instead of reissuing. + + * Once the data is read, the pages that have been fully read/cleared: + + * Will be marked uptodate. + + * If a cache is present, will be marked with PG_fscache. + + * Unlocked + + * Any pages that need writing to the cache will then have DIO writes issued. + + * Synchronous operations will wait for reading to be complete. + + * Writes to the cache will proceed asynchronously and the pages will have the + PG_fscache mark removed when that completes. + + * The request structures will be cleaned up when everything has completed. + + +Read Helper Cache API +--------------------- + +When implementing a local cache to be used by the read helpers, two things are +required: some way for the network filesystem to initialise the caching for a +read request and a table of operations for the helpers to call. + +The network filesystem's ->begin_cache_operation() method is called to set up a +cache and this must call into the cache to do the work. If using fscache, for +example, the cache would call:: + + int fscache_begin_read_operation(struct netfs_read_request *rreq, + struct fscache_cookie *cookie); + +passing in the request pointer and the cookie corresponding to the file. + +The netfs_read_request object contains a place for the cache to hang its +state:: + + struct netfs_cache_resources { + const struct netfs_cache_ops *ops; + void *cache_priv; + void *cache_priv2; + }; + +This contains an operations table pointer and two private pointers. The +operation table looks like the following:: + + struct netfs_cache_ops { + void (*end_operation)(struct netfs_cache_resources *cres); + + void (*expand_readahead)(struct netfs_cache_resources *cres, + loff_t *_start, size_t *_len, loff_t i_size); + + enum netfs_read_source (*prepare_read)(struct netfs_read_subrequest *subreq, + loff_t i_size); + + int (*read)(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + bool seek_data, + netfs_io_terminated_t term_func, + void *term_func_priv); + + int (*write)(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + netfs_io_terminated_t term_func, + void *term_func_priv); + }; + +With a termination handler function pointer:: + + typedef void (*netfs_io_terminated_t)(void *priv, + ssize_t transferred_or_error, + bool was_async); + +The methods defined in the table are: + + * ``end_operation()`` + + [Required] Called to clean up the resources at the end of the read request. + + * ``expand_readahead()`` + + [Optional] Called at the beginning of a netfs_readahead() operation to allow + the cache to expand a request in either direction. This allows the cache to + size the request appropriately for the cache granularity. + + The function is passed poiners to the start and length in its parameters, + plus the size of the file for reference, and adjusts the start and length + appropriately. It should return one of: + + * ``NETFS_FILL_WITH_ZEROES`` + * ``NETFS_DOWNLOAD_FROM_SERVER`` + * ``NETFS_READ_FROM_CACHE`` + * ``NETFS_INVALID_READ`` + + to indicate whether the slice should just be cleared or whether it should be + downloaded from the server or read from the cache - or whether slicing + should be given up at the current point. + + * ``prepare_read()`` + + [Required] Called to configure the next slice of a request. ->start and + ->len in the subrequest indicate where and how big the next slice can be; + the cache gets to reduce the length to match its granularity requirements. + + * ``read()`` + + [Required] Called to read from the cache. The start file offset is given + along with an iterator to read to, which gives the length also. It can be + given a hint requesting that it seek forward from that start position for + data. + + Also provided is a pointer to a termination handler function and private + data to pass to that function. The termination function should be called + with the number of bytes transferred or an error code, plus a flag + indicating whether the termination is definitely happening in the caller's + context. + + * ``write()`` + + [Required] Called to write to the cache. The start file offset is given + along with an iterator to write from, which gives the length also. + + Also provided is a pointer to a termination handler function and private + data to pass to that function. The termination function should be called + with the number of bytes transferred or an error code, plus a flag + indicating whether the termination is definitely happening in the caller's + context. + +Note that these methods are passed a pointer to the cache resource structure, +not the read request structure as they could be used in other situations where +there isn't a read request structure as well, such as writing dirty data to the +cache. diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index 544c6382a691c38eb09e4bc0dd1ee16f47497873..c1e5efa60f765d8c1219d1421f01327fa20e857c 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -543,7 +543,9 @@ encoded manner. The codes are the following: ac area is accountable nr swap space is not reserved for the area ht area uses huge tlb pages + sf synchronous page fault ar architecture specific flag + wf wipe on fork dd do not include area into core dump sd soft dirty flag mm mixed map area @@ -552,6 +554,8 @@ encoded manner. The codes are the following: mg mergable advise flag bt arm64 BTI guarded page mt arm64 MTE allocation tags are enabled + um userfaultfd missing tracking + uw userfaultfd wr-protect tracking == ======================================= Note that there is no guarantee that every flag and associated mnemonic will diff --git a/Documentation/filesystems/vfat.rst b/Documentation/filesystems/vfat.rst index e85d74e912956f25a9fe7ddc55f3b165311c4574..760a4d83fdf9273fe3702d4ff1c181bd8cf1137a 100644 --- a/Documentation/filesystems/vfat.rst +++ b/Documentation/filesystems/vfat.rst @@ -189,7 +189,7 @@ VFAT MOUNT OPTIONS **discard** If set, issues discard/TRIM commands to the block device when blocks are freed. This is useful for SSD devices - and sparse/thinly-provisoned LUNs. + and sparse/thinly-provisioned LUNs. **nfs=stale_rw|nostale_ro** Enable this only if you want to export the FAT filesystem diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 2049bbf5e3885a32b533e8e70c14103f2b09f2e4..14c31eced416a16d9649f41706994f5fa94d59b5 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -441,6 +441,9 @@ As of kernel 2.6.22, the following members are defined: unsigned open_flag, umode_t create_mode); int (*tmpfile) (struct user_namespace *, struct inode *, struct dentry *, umode_t); int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int); + int (*fileattr_set)(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); + int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); }; Again, all methods are called without any locks being held, unless @@ -588,6 +591,18 @@ otherwise noted. atomically creating, opening and unlinking a file in given directory. +``fileattr_get`` + called on ioctl(FS_IOC_GETFLAGS) and ioctl(FS_IOC_FSGETXATTR) to + retrieve miscellaneous file flags and attributes. Also called + before the relevant SET operation to check what is being changed + (in this case with i_rwsem locked exclusive). If unset, then + fall back to f_op->ioctl(). + +``fileattr_set`` + called on ioctl(FS_IOC_SETFLAGS) and ioctl(FS_IOC_FSSETXATTR) to + change miscellaneous file flags and attributes. Callers hold + i_rwsem exclusive. If unset, then fall back to f_op->ioctl(). + The Address Space Object ======================== diff --git a/Documentation/firmware-guide/acpi/debug.rst b/Documentation/firmware-guide/acpi/debug.rst index 03cd4e25fc451edfb61720a20ae882033baa9aec..0639c9de07f91e82883385acd2bb2edcba82250e 100644 --- a/Documentation/firmware-guide/acpi/debug.rst +++ b/Documentation/firmware-guide/acpi/debug.rst @@ -1,18 +1,17 @@ .. SPDX-License-Identifier: GPL-2.0 -================= -ACPI Debug Output -================= +==================== +ACPI CA Debug Output +==================== -The ACPI CA, the Linux ACPI core, and some ACPI drivers can generate debug -output. This document describes how to use this facility. +The ACPI CA can generate debug output. This document describes how to use this +facility. Compile-time configuration ========================== -ACPI debug output is globally enabled by CONFIG_ACPI_DEBUG. If this config -option is turned off, the debug messages are not even built into the -kernel. +The ACPI CA debug output is globally enabled by CONFIG_ACPI_DEBUG. If this +config option is not set, the debug messages are not even built into the kernel. Boot- and run-time configuration ================================ @@ -27,16 +26,16 @@ debug_layer (component) ======================= The "debug_layer" is a mask that selects components of interest, e.g., a -specific driver or part of the ACPI interpreter. To build the debug_layer -bitmask, look for the "#define _COMPONENT" in an ACPI source file. +specific part of the ACPI interpreter. To build the debug_layer bitmask, look +for the "#define _COMPONENT" in an ACPI source file. You can set the debug_layer mask at boot-time using the acpi.debug_layer command line argument, and you can change it after boot by writing values to /sys/module/acpi/parameters/debug_layer. -The possible components are defined in include/acpi/acoutput.h and -include/acpi/acpi_drivers.h. Reading /sys/module/acpi/parameters/debug_layer -shows the supported mask values, currently these:: +The possible components are defined in include/acpi/acoutput.h. + +Reading /sys/module/acpi/parameters/debug_layer shows the supported mask values:: ACPI_UTILITIES 0x00000001 ACPI_HARDWARE 0x00000002 @@ -52,13 +51,6 @@ shows the supported mask values, currently these:: ACPI_CA_DISASSEMBLER 0x00000800 ACPI_COMPILER 0x00001000 ACPI_TOOLS 0x00002000 - ACPI_SBS_COMPONENT 0x00100000 - ACPI_FAN_COMPONENT 0x00200000 - ACPI_PCI_COMPONENT 0x00400000 - ACPI_CONTAINER_COMPONENT 0x01000000 - ACPI_SYSTEM_COMPONENT 0x02000000 - ACPI_MEMORY_DEVICE_COMPONENT 0x08000000 - ACPI_PROCESSOR_COMPONENT 0x20000000 debug_level =========== @@ -127,10 +119,6 @@ AML) during boot:: acpi.debug_layer=0xffffffff acpi.debug_level=0x2 -Enable PCI and PCI interrupt routing debug messages:: - - acpi.debug_layer=0x400000 acpi.debug_level=0x4 - Enable all ACPI hardware-related messages:: acpi.debug_layer=0x2 acpi.debug_level=0xffffffff diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst index c41ac76ffaae110368ab7126d7fe9d01320eaf55..f3a1223f2517e9d01f905a94a874f51c54ca0604 100644 --- a/Documentation/fpga/dfl.rst +++ b/Documentation/fpga/dfl.rst @@ -7,6 +7,7 @@ Authors: - Enno Luebbers <enno.luebbers@intel.com> - Xiao Guangrong <guangrong.xiao@linux.intel.com> - Wu Hao <hao.wu@intel.com> +- Xu Yilun <yilun.xu@intel.com> The Device Feature List (DFL) FPGA framework (and drivers according to this framework) hides the very details of low layer hardwares and provides @@ -530,6 +531,31 @@ Being able to specify more than one DFL per BAR has been considered, but it was determined the use case did not provide value. Specifying a single DFL per BAR simplifies the implementation and allows for extra error checking. + +Userspace driver support for DFL devices +======================================== +The purpose of an FPGA is to be reprogrammed with newly developed hardware +components. New hardware can instantiate a new private feature in the DFL, and +then present a DFL device in the system. In some cases users may need a +userspace driver for the DFL device: + +* Users may need to run some diagnostic test for their hardware. +* Users may prototype the kernel driver in user space. +* Some hardware is designed for specific purposes and does not fit into one of + the standard kernel subsystems. + +This requires direct access to MMIO space and interrupt handling from +userspace. The uio_dfl module exposes the UIO device interfaces for this +purpose. + +Currently the uio_dfl driver only supports the Ether Group sub feature, which +has no irq in hardware. So the interrupt handling is not added in this driver. + +UIO_DFL should be selected to enable the uio_dfl module driver. To support a +new DFL feature via UIO direct access, its feature id should be added to the +driver's id_table. + + Open discussion =============== FME driver exports one ioctl (DFL_FPGA_FME_PORT_PR) for partial reconfiguration diff --git a/Documentation/hid/intel-ish-hid.rst b/Documentation/hid/intel-ish-hid.rst index f6ce44ff611df775f0ae0ac33f78a7b0159201b7..7a851252267ae75f252c166fe2c27ab7dfb565fb 100644 --- a/Documentation/hid/intel-ish-hid.rst +++ b/Documentation/hid/intel-ish-hid.rst @@ -345,7 +345,7 @@ Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space. To debug ISH, event tracing mechanism is used. To enable debug logs:: echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable - cat sys/kernel/debug/tracing/trace + cat /sys/kernel/debug/tracing/trace 3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260 ----------------------------------------------------- diff --git a/Documentation/hwmon/amd_energy.rst b/Documentation/hwmon/amd_energy.rst deleted file mode 100644 index 9d58cd5ee3da92664943a16887d510fa8b4318b0..0000000000000000000000000000000000000000 --- a/Documentation/hwmon/amd_energy.rst +++ /dev/null @@ -1,119 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -Kernel driver amd_energy -========================== - -Supported chips: - -* AMD Family 17h Processors: Model 30h - -* AMD Family 19h Processors: Model 01h - - Prefix: 'amd_energy' - - Addresses used: RAPL MSRs - - Datasheets: - - - Processor Programming Reference (PPR) for AMD Family 17h Model 01h, Revision B1 Processors - - https://developer.amd.com/wp-content/resources/55570-B1_PUB.zip - - - Preliminary Processor Programming Reference (PPR) for AMD Family 17h Model 31h, Revision B0 Processors - - https://developer.amd.com/wp-content/resources/56176_ppr_Family_17h_Model_71h_B0_pub_Rev_3.06.zip - -Author: Naveen Krishna Chatradhi <nchatrad@amd.com> - -Description ------------ - -The Energy driver exposes the energy counters that are -reported via the Running Average Power Limit (RAPL) -Model-specific Registers (MSRs) via the hardware monitor -(HWMON) sysfs interface. - -1. Power, Energy and Time Units - MSR_RAPL_POWER_UNIT/ C001_0299: - shared with all cores in the socket - -2. Energy consumed by each Core - MSR_CORE_ENERGY_STATUS/ C001_029A: - 32-bitRO, Accumulator, core-level power reporting - -3. Energy consumed by Socket - MSR_PACKAGE_ENERGY_STATUS/ C001_029B: - 32-bitRO, Accumulator, socket-level power reporting, - shared with all cores in socket - -These registers are updated every 1ms and cleared on -reset of the system. - -Note: If SMT is enabled, Linux enumerates all threads as cpus. -Since, the energy status registers are accessed at core level, -reading those registers from the sibling threads would result -in duplicate values. Hence, energy counter entries are not -populated for the siblings. - -Energy Caluclation ------------------- - -Energy information (in Joules) is based on the multiplier, -1/2^ESU; where ESU is an unsigned integer read from -MSR_RAPL_POWER_UNIT register. Default value is 10000b, -indicating energy status unit is 15.3 micro-Joules increment. - -Reported values are scaled as per the formula - -scaled value = ((1/2^ESU) * (Raw value) * 1000000UL) in uJoules - -Users calculate power for a given domain by calculating - dEnergy/dTime for that domain. - -Energy accumulation --------------------------- - -Current, Socket energy status register is 32bit, assuming a 240W -2P system, the register would wrap around in - - 2^32*15.3 e-6/240 * 2 = 547.60833024 secs to wrap(~9 mins) - -The Core energy register may wrap around after several days. - -To improve the wrap around time, a kernel thread is implemented -to accumulate the socket energy counters and one core energy counter -per run to a respective 64-bit counter. The kernel thread starts -running during probe, wakes up every 100secs and stops running -when driver is removed. - -Frequency of the accumulator thread is set during the probe -based on the chosen energy unit resolution. For example -A. fine grain (1.625 micro J) -B. course grain (0.125 milli J) - -A socket and core energy read would return the current register -value added to the respective energy accumulator. - -Sysfs attributes ----------------- - -=============== ======== ===================================== -Attribute Label Description -=============== ======== ===================================== - -* For index N between [1] and [nr_cpus] - -=============== ======== ====================================== -energy[N]_input EcoreX Core Energy X = [0] to [nr_cpus - 1] - Measured input core energy -=============== ======== ====================================== - -* For N between [nr_cpus] and [nr_cpus + nr_socks] - -=============== ======== ====================================== -energy[N]_input EsocketX Socket Energy X = [0] to [nr_socks -1] - Measured input socket energy -=============== ======== ====================================== - -Note: To address CVE-2020-12912, the visibility of the energy[N]_input -attributes is restricted to owner and groups only. diff --git a/Documentation/hwmon/bpa-rs600.rst b/Documentation/hwmon/bpa-rs600.rst new file mode 100644 index 0000000000000000000000000000000000000000..28313995d4ae8892153da3cc56681980a0055000 --- /dev/null +++ b/Documentation/hwmon/bpa-rs600.rst @@ -0,0 +1,74 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver bpa-rs600 +======================= + +Supported chips: + + * BPA-RS600-120 + + Datasheet: Publicly available at the BluTek website + http://blutekpower.com/wp-content/uploads/2019/01/BPA-RS600-120-07-19-2018.pdf + +Authors: + - Chris Packham <chris.packham@alliedtelesis.co.nz> + +Description +----------- + +The BPA-RS600 is a compact 600W removable power supply module. + +Usage Notes +----------- + +This driver does not probe for PMBus devices. You will have to instantiate +devices explicitly. + +Sysfs attributes +---------------- + +======================= ============================================ +curr1_label "iin" +curr1_input Measured input current +curr1_max Maximum input current +curr1_max_alarm Input current high alarm + +curr2_label "iout1" +curr2_input Measured output current +curr2_max Maximum output current +curr2_max_alarm Output current high alarm + +fan1_input Measured fan speed +fan1_alarm Fan warning +fan1_fault Fan fault + +in1_label "vin" +in1_input Measured input voltage +in1_max Maximum input voltage +in1_max_alarm Input voltage high alarm +in1_min Minimum input voltage +in1_min_alarm Input voltage low alarm + +in2_label "vout1" +in2_input Measured output voltage +in2_max Maximum output voltage +in2_max_alarm Output voltage high alarm +in2_min Maximum output voltage +in2_min_alarm Output voltage low alarm + +power1_label "pin" +power1_input Measured input power +power1_alarm Input power alarm +power1_max Maximum input power + +power2_label "pout1" +power2_input Measured output power +power2_max Maximum output power +power2_max_alarm Output power high alarm + +temp1_input Measured temperature around input connector +temp1_alarm Temperature alarm + +temp2_input Measured temperature around output connector +temp2_alarm Temperature alarm +======================= ============================================ diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index 396b95c9a76a2d14e52f6119ffe60c89a86a8e71..e8378e7a1d8c089c5dc311e6743fc5511ce9889b 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -47,19 +47,30 @@ Sysfs entries ======================= ======================================================== curr1_input Total current usage curr2_input Current on the 12v psu rail +curr2_crit Current max critical value on the 12v psu rail curr3_input Current on the 5v psu rail +curr3_crit Current max critical value on the 5v psu rail curr4_input Current on the 3.3v psu rail +curr4_crit Current max critical value on the 3.3v psu rail fan1_input RPM of psu fan in0_input Voltage of the psu ac input in1_input Voltage of the 12v psu rail +in1_crit Voltage max critical value on the 12v psu rail +in1_lcrit Voltage min critical value on the 12v psu rail in2_input Voltage of the 5v psu rail -in3_input Voltage of the 3.3 psu rail +in2_crit Voltage max critical value on the 5v psu rail +in2_lcrit Voltage min critical value on the 5v psu rail +in3_input Voltage of the 3.3v psu rail +in3_crit Voltage max critical value on the 3.3v psu rail +in3_lcrit Voltage min critical value on the 3.3v psu rail power1_input Total power usage power2_input Power usage of the 12v psu rail power3_input Power usage of the 5v psu rail power4_input Power usage of the 3.3v psu rail temp1_input Temperature of the psu vrm component +temp1_crit Temperature max cirtical value of the psu vrm component temp2_input Temperature of the psu case +temp2_crit Temperature max critical value of psu case ======================= ======================================================== Usage Notes diff --git a/Documentation/hwmon/fsp-3y.rst b/Documentation/hwmon/fsp-3y.rst new file mode 100644 index 0000000000000000000000000000000000000000..5693d83a20358cf46d526282c2a998ad066cc8a0 --- /dev/null +++ b/Documentation/hwmon/fsp-3y.rst @@ -0,0 +1,28 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver fsp3y +====================== +Supported devices: + * 3Y POWER YH-5151E + * 3Y POWER YM-2151E + +Author: Václav Kubernát <kubernat@cesnet.cz> + +Description +----------- +This driver implements limited support for two 3Y POWER devices. + +Sysfs entries +------------- + * in1_input input voltage + * in2_input 12V output voltage + * in3_input 5V output voltage + * curr1_input input current + * curr2_input 12V output current + * curr3_input 5V output current + * fan1_input fan rpm + * temp1_input temperature 1 + * temp2_input temperature 2 + * temp3_input temperature 3 + * power1_input input power + * power2_input output power diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 8d5a2df1ecb642b31345b07e3caee8f13db6efcf..9ed60fa84cbec6dd6e585743183eab6e80dfc7ce 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -39,12 +39,12 @@ Hardware Monitoring Kernel Drivers adt7475 aht10 amc6821 - amd_energy asb100 asc7621 aspeed-pwm-tacho bcm54140 bel-pfe + bpa-rs600 bt1-pvt coretemp corsair-cpro @@ -62,6 +62,7 @@ Hardware Monitoring Kernel Drivers f71805f f71882fg fam15h_power + fsp-3y ftsteutates g760a g762 @@ -77,6 +78,7 @@ Hardware Monitoring Kernel Drivers intel-m10-bmc-hwmon ir35221 ir38064 + ir36021 isl68137 it87 jc42 @@ -112,6 +114,7 @@ Hardware Monitoring Kernel Drivers ltc4260 ltc4261 max127 + max15301 max16064 max16065 max1619 @@ -142,6 +145,7 @@ Hardware Monitoring Kernel Drivers npcm750-pwm-fan nsa320 ntc_thermistor + nzxt-kraken2 occ pc87360 pc87427 @@ -168,6 +172,7 @@ Hardware Monitoring Kernel Drivers smsc47m192 smsc47m1 sparx5-temp + stpddc60 tc654 tc74 thmc50 diff --git a/Documentation/hwmon/ir36021.rst b/Documentation/hwmon/ir36021.rst new file mode 100644 index 0000000000000000000000000000000000000000..ca3436b04e2028cefbd1c4c37ad247b1d4fd7ddf --- /dev/null +++ b/Documentation/hwmon/ir36021.rst @@ -0,0 +1,63 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver ir36021 +===================== + +Supported chips: + + * Infineon IR36021 + + Prefix: ir36021 + Addresses scanned: - + + Datasheet: Publicly available at the Infineon website + https://www.infineon.com/dgdl/ir36021.pdf?fileId=5546d462533600a4015355d0aa2d1775 + +Authors: + - Chris Packham <chris.packham@alliedtelesis.co.nz> + +Description +----------- + +The IR36021 is a dual‐loop digital multi‐phase buck controller designed for +point of load applications. + +Usage Notes +----------- + +This driver does not probe for PMBus devices. You will have to instantiate +devices explicitly. + +Sysfs attributes +---------------- + +======================= =========================== +curr1_label "iin" +curr1_input Measured input current +curr1_alarm Input fault alarm + +curr2_label "iout1" +curr2_input Measured output current +curr2_alarm Output over-current alarm + +in1_label "vin" +in1_input Measured input voltage +in1_alarm Input under-voltage alarm + +in2_label "vout1" +in2_input Measured output voltage +in2_alarm Output over-voltage alarm + +power1_label "pin" +power1_input Measured input power +power1_alarm Input under-voltage alarm + +power2_label "pout1" +power2_input Measured output power + +temp1_input Measured temperature +temp1_alarm Temperature alarm + +temp2_input Measured other loop temperature +temp2_alarm Temperature alarm +======================= =========================== diff --git a/Documentation/hwmon/max15301.rst b/Documentation/hwmon/max15301.rst new file mode 100644 index 0000000000000000000000000000000000000000..e3dc22fe1c6d0035593e59481a610452eec8abf9 --- /dev/null +++ b/Documentation/hwmon/max15301.rst @@ -0,0 +1,87 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver max15301 +====================== + +Supported chips: + + * Maxim MAX15301 + + Prefix: 'max15301', 'bmr461' + + Addresses scanned: - + + Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX15301.pdf + +Author: Erik Rosen <erik.rosen@metormote.com> + + +Description +----------- + +This driver supports hardware monitoring for Maxim MAX15301 controller chip and +compatible modules. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details +on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Module parameters +----------------- + +delay +----- + +The controller requires a minimum interval between I2C bus accesses. +The default interval is set to 100 us. For manual override, the driver +provides a writeable module parameter, 'delay', which can be used to +set the interval to a value between 0 and 65,535 microseconds. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +======================= ======================================================== +in1_label "vin" +in1_input Measured input voltage. +in1_lcrit Critical minimum input voltage. +in1_crit Critical maximum input voltage. +in1_lcrit_alarm Input voltage critical low alarm. +in1_crit_alarm Input voltage critical high alarm. + +in2_label "vout1" +in2_input Measured output voltage. +in2_lcrit Critical minimum output Voltage. +in2_crit Critical maximum output voltage. +in2_lcrit_alarm Critical output voltage critical low alarm. +in2_crit_alarm Critical output voltage critical high alarm. + +curr1_label "iout1" +curr1_input Measured output current. +curr1_crit Critical maximum output current. +curr1_crit_alarm Output current critical high alarm. + +temp1_input Measured maximum temperature of all phases. +temp1_max Maximum temperature limit. +temp1_max_alarm High temperature alarm. +temp1_crit Critical maximum temperature limit. +temp1_crit_alarm Critical maximum temperature alarm. +======================= ======================================================== diff --git a/Documentation/hwmon/nzxt-kraken2.rst b/Documentation/hwmon/nzxt-kraken2.rst new file mode 100644 index 0000000000000000000000000000000000000000..94025de65a818ff196f3de0954b0b168d559cf90 --- /dev/null +++ b/Documentation/hwmon/nzxt-kraken2.rst @@ -0,0 +1,42 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver nzxt-kraken2 +========================== + +Supported devices: + +* NZXT Kraken X42 +* NZXT Kraken X52 +* NZXT Kraken X62 +* NZXT Kraken X72 + +Author: Jonas Malaco + +Description +----------- + +This driver enables hardware monitoring support for NZXT Kraken X42/X52/X62/X72 +all-in-one CPU liquid coolers. Three sensors are available: fan speed, pump +speed and coolant temperature. + +Fan and pump control, while supported by the firmware, are not currently +exposed. The addressable RGB LEDs, present in the integrated CPU water block +and pump head, are not supported either. But both features can be found in +existing user-space tools (e.g. `liquidctl`_). + +.. _liquidctl: https://github.com/liquidctl/liquidctl + +Usage Notes +----------- + +As these are USB HIDs, the driver can be loaded automatically by the kernel and +supports hot swapping. + +Sysfs entries +------------- + +======================= ======================================================== +fan1_input Fan speed (in rpm) +fan2_input Pump speed (in rpm) +temp1_input Coolant temperature (in millidegrees Celsius) +======================= ======================================================== diff --git a/Documentation/hwmon/stpddc60.rst b/Documentation/hwmon/stpddc60.rst new file mode 100644 index 0000000000000000000000000000000000000000..7f7ce7f7871b21c119a6f43bb3cc77af4fc081c1 --- /dev/null +++ b/Documentation/hwmon/stpddc60.rst @@ -0,0 +1,90 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver stpddc60 +====================== + +Supported chips: + + * ST STPDDC60 + + Prefix: 'stpddc60', 'bmr481' + + Addresses scanned: - + + Datasheet: https://flexpowermodules.com/documents/fpm-techspec-bmr481 + +Author: Erik Rosen <erik.rosen@metormote.com> + + +Description +----------- + +This driver supports hardware monitoring for ST STPDDC60 controller chip and +compatible modules. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details +on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + +The vout under- and over-voltage limits are set in relation to the commanded +output voltage as a positive or negative offset in the interval 50mV to 400mV +in 50mV steps. This means that the absolute values of the limits will change +when the commanded output voltage changes. Also, care should be taken when +writing to those limits since in the worst case the commanded output voltage +could change at the same time as the limit is written to, wich will lead to +unpredictable results. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Vin, iout, pout and temp limits +are read-write; all other attributes are read-only. + +======================= ======================================================== +in1_label "vin" +in1_input Measured input voltage. +in1_lcrit Critical minimum input voltage. +in1_crit Critical maximum input voltage. +in1_lcrit_alarm Input voltage critical low alarm. +in1_crit_alarm Input voltage critical high alarm. + +in2_label "vout1" +in2_input Measured output voltage. +in2_lcrit Critical minimum output voltage. +in2_crit Critical maximum output voltage. +in2_lcrit_alarm Critical output voltage critical low alarm. +in2_crit_alarm Critical output voltage critical high alarm. + +curr1_label "iout1" +curr1_input Measured output current. +curr1_max Maximum output current. +curr1_max_alarm Output current high alarm. +curr1_crit Critical maximum output current. +curr1_crit_alarm Output current critical high alarm. + +power1_label "pout1" +power1_input Measured output power. +power1_crit Critical maximum output power. +power1_crit_alarm Output power critical high alarm. + +temp1_input Measured maximum temperature of all phases. +temp1_max Maximum temperature limit. +temp1_max_alarm High temperature alarm. +temp1_crit Critical maximum temperature limit. +temp1_crit_alarm Critical maximum temperature alarm. +======================= ======================================================== diff --git a/Documentation/hwmon/sysfs-interface.rst b/Documentation/hwmon/sysfs-interface.rst index 678c9c60b5a3743c0ab8d1f8ead3f789c2d3ab3b..13c5acb72d63fe0b55e602f1fcc1b591c65b1e31 100644 --- a/Documentation/hwmon/sysfs-interface.rst +++ b/Documentation/hwmon/sysfs-interface.rst @@ -65,6 +65,14 @@ the desired value must be written, note that strings which are not a number are interpreted as 0! For more on how written strings are interpreted see the "sysfs attribute writes interpretation" section at the end of this file. +Attribute access +---------------- + +Hardware monitoring sysfs attributes are displayed by unrestricted userspace +applications. For this reason, all standard ABI attributes shall be world +readable. Writeable standard ABI attributes shall be writeable only for +privileged users. + ------------------------------------------------------------------------- ======= =========================================== diff --git a/Documentation/hwmon/tps53679.rst b/Documentation/hwmon/tps53679.rst index c7c589e4978918ef8cfa555d6293001422e1cb28..3b9561648c24f508fb65c47e939c68c2c379b79e 100644 --- a/Documentation/hwmon/tps53679.rst +++ b/Documentation/hwmon/tps53679.rst @@ -19,6 +19,14 @@ Supported chips: Datasheet: https://www.ti.com/lit/gpn/TPS53667 + * Texas Instruments TPS53676 + + Prefix: 'tps53676' + + Addresses scanned: - + + Datasheet: https://www.ti.com/lit/gpn/TPS53676 + * Texas Instruments TPS53679 Prefix: 'tps53679' @@ -136,7 +144,7 @@ power1_input Measured input power. power[N]_label "pout[1-2]". - TPS53647, TPS53667: N=2 - - TPS53679, TPS53681, TPS53588: N=2,3 + - TPS53676, TPS53679, TPS53681, TPS53588: N=2,3 power[N]_input Measured output power. @@ -156,10 +164,11 @@ curr[N]_label "iout[1-2]" or "iout1.[0-5]". The first digit is the output channel, the second digit is the phase within the channel. Per-phase - telemetry supported on TPS53681 only. + telemetry supported on TPS53676 and TPS53681 only. - TPS53647, TPS53667: N=2 - TPS53679, TPS53588: N=2,3 + - TPS53676: N=2-8 - TPS53681: N=2-9 curr[N]_input Measured output current. diff --git a/Documentation/iio/iio_configfs.rst b/Documentation/iio/iio_configfs.rst index 3a5d76f9e2b97421faf2de81ae5d1061a28a7c52..b276397af797e3cb2f3ca27bbc580a2bb0ddfcc3 100644 --- a/Documentation/iio/iio_configfs.rst +++ b/Documentation/iio/iio_configfs.rst @@ -71,7 +71,7 @@ kernel module following the interface in include/linux/iio/sw_trigger.h:: .ops = &iio_trig_sample_ops, }; -module_iio_sw_trigger_driver(iio_trig_sample); + module_iio_sw_trigger_driver(iio_trig_sample); Each trigger type has its own directory under /config/iio/triggers. Loading iio-trig-sample module will create 'trig-sample' trigger type directory @@ -99,3 +99,4 @@ Each trigger can have one or more attributes specific to the trigger type. "hrtimer" trigger type doesn't have any configurable attribute from /config dir. It does introduce the sampling_frequency attribute to trigger directory. +That attribute sets the polling frequency in Hz, with mHz precision. diff --git a/Documentation/index.rst b/Documentation/index.rst index 31f2adc8542dcef0a76995a3fad2ddf473919b71..54ce34fd6fbdaf863ad87588d1fb86c3d0a8ce19 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -149,27 +149,11 @@ Architecture-agnostic documentation Architecture-specific documentation ----------------------------------- -These books provide programming details about architecture-specific -implementation. - .. toctree:: :maxdepth: 2 - arm/index - arm64/index - ia64/index - m68k/index - mips/index - nios2/index - openrisc/index - parisc/index - powerpc/index - riscv/index - s390/index - sh/index - sparc/index - x86/index - xtensa/index + arch + Other documentation ------------------- diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index 3118fc1c1e26bc50640ec478d65f3ca1c9e39868..b24ae7d292cc191f8da0103c9de6fa56fcea4ce2 100644 --- a/Documentation/input/event-codes.rst +++ b/Documentation/input/event-codes.rst @@ -246,9 +246,9 @@ A few EV_ABS codes have special meanings: A device should set the resolution of the axis to indicate whether the pressure is in measurable units. If the resolution is zero, the - pressure data is in arbitrary units. If the resolution is nonzero, the + pressure data is in arbitrary units. If the resolution is non-zero, the pressure data is in units/gram. For example, a value of 10 with a - resolution of 1 represents 10 gram, a value of 10 with a resolution on + resolution of 1 represents 10 gram, a value of 10 with a resolution of 1000 represents 10 microgram. EV_SW @@ -344,7 +344,7 @@ INPUT_PROP_BUTTONPAD For touchpads where the button is placed beneath the surface, such that pressing down on the pad causes a button click, this property should be -set. Common in clickpad notebooks and macbooks from 2009 and onwards. +set. Common in Clickpad notebooks and Macbooks from 2009 and onwards. Originally, the buttonpad property was coded into the bcm5974 driver version field under the name integrated button. For backwards @@ -356,7 +356,7 @@ INPUT_PROP_SEMI_MT Some touchpads, most common between 2008 and 2011, can detect the presence of multiple contacts without resolving the individual positions; only the number of contacts and a rectangular shape is known. For such -touchpads, the semi-mt property should be set. +touchpads, the SEMI_MT property should be set. Depending on the device, the rectangle may enclose all touches, like a bounding box, or just some of them, for instance the two most recent @@ -394,7 +394,7 @@ Guidelines ========== The guidelines below ensure proper single-touch and multi-finger functionality. -For multi-touch functionality, see the multi-touch-protocol.txt document for +For multi-touch functionality, see the multi-touch-protocol.rst document for more information. Mice diff --git a/Documentation/input/ff.rst b/Documentation/input/ff.rst index 0c02e87ee86d517a8bcba9d196cbf2e877e47fcb..5a1da42c33b3106e0f1a37e83b1d8e9274d4e87d 100644 --- a/Documentation/input/ff.rst +++ b/Documentation/input/ff.rst @@ -16,8 +16,8 @@ goal is not to support these devices as if they were simple input-only devices (as it is already the case), but to really enable the rendering of force effects. This document only describes the force feedback part of the Linux input -interface. Please read joystick.txt and input.txt before reading further this -document. +interface. Please read joydev/joystick.rst and input.rst before reading further +this document. Instructions to the user ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -36,7 +36,7 @@ should keep a hand on your device, in order to avoid it to break down if something goes wrong. If you have a serial iforce device, you need to start inputattach. See -joystick.txt for details. +joydev/joystick.rst for details. Does it work ? -------------- diff --git a/Documentation/input/gameport-programming.rst b/Documentation/input/gameport-programming.rst index c96911df1c54afbdc97780becb7be50f4c752c1b..7d7063ad0f9fd69beb94a195998d8187798a8ab7 100644 --- a/Documentation/input/gameport-programming.rst +++ b/Documentation/input/gameport-programming.rst @@ -21,7 +21,7 @@ choose which one to program the hardware to, starting from the more exotic addresses is preferred, because the likelihood of clashing with the standard 0x201 address is smaller. -Eg. if your driver supports addresses 0x200, 0x208, 0x210 and 0x218, then +E.g. if your driver supports addresses 0x200, 0x208, 0x210 and 0x218, then 0x218 would be the address of first choice. If your hardware supports a gameport address that is not mapped to ISA io @@ -78,7 +78,7 @@ the gameport. To register a cooked gameport:: for (i = 0; i < 4; i++) axes[i] = my_mmio[i]; - buttons[i] = my_mmio[4]; + buttons[0] = my_mmio[4]; } int my_open(struct gameport *gameport, int mode) @@ -117,25 +117,28 @@ Simple:: The gameport structure ~~~~~~~~~~~~~~~~~~~~~~ -.. note:: - - This section is outdated. There are several fields here that don't - match what's there at include/linux/gameport.h. - :: struct gameport { - void *private; + void *port_data; A private pointer for free use in the gameport driver. (Not the joystick driver!) :: - int number; + char name[32]; + +Driver's name as set by driver calling gameport_set_name(). Informational +purpose only. + +:: + + char phys[32]; -Number assigned to the gameport when registered. Informational purpose only. +gameport's physical name/description as set by driver calling gameport_set_phys(). +Informational purpose only. :: @@ -210,8 +213,16 @@ gameport. :: - struct gameport_dev *dev; - struct gameport *next; + struct timer_list poll_timer; + unsigned int poll_interval; /* in msecs */ + spinlock_t timer_lock; + unsigned int poll_cnt; + void (*poll_handler)(struct gameport *); + struct gameport *parent, *child; + struct gameport_driver *drv; + struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ + struct device dev; + struct list_head node; For internal use by the gameport layer. diff --git a/Documentation/input/input-programming.rst b/Documentation/input/input-programming.rst index 5938145b0e35d7707b7cfc6ceaf30d0ff5c302cf..2638dce69764cff9495204f3d0b536bfc46b71eb 100644 --- a/Documentation/input/input-programming.rst +++ b/Documentation/input/input-programming.rst @@ -120,7 +120,7 @@ Then there is the:: call to tell those who receive the events that we've sent a complete report. This doesn't seem important in the one button case, but is quite important -for for example mouse movement, where you don't want the X and Y values +for example for mouse movement, where you don't want the X and Y values to be interpreted separately, because that'd result in a different movement. dev->open() and dev->close() @@ -128,7 +128,7 @@ dev->open() and dev->close() In case the driver has to repeatedly poll the device, because it doesn't have an interrupt coming from it and the polling is too expensive to be done -all the time, or if the device uses a valuable resource (eg. interrupt), it +all the time, or if the device uses a valuable resource (e.g. interrupt), it can use the open and close callback to know when it can stop polling or release the interrupt and when it must resume polling or grab the interrupt again. To do that, we would add this to our example driver:: @@ -161,7 +161,7 @@ makes sure that dev->open() is called only when the first user connects to the device and that dev->close() is called when the very last user disconnects. Calls to both callbacks are serialized. -The open() callback should return a 0 in case of success or any nonzero value +The open() callback should return a 0 in case of success or any non-zero value in case of failure. The close() callback (which is void) must always succeed. Inhibiting input devices @@ -182,8 +182,8 @@ providing events to the input core. Calling the device's close() method on inhibit (if there are users) allows the driver to save power. Either by directly powering down the device or by -releasing the runtime-pm reference it got in open() when the driver is using -runtime-pm. +releasing the runtime-PM reference it got in open() when the driver is using +runtime-PM. Inhibiting and uninhibiting are orthogonal to opening and closing the device by input handlers. Userspace might want to inhibit a device in anticipation before @@ -219,8 +219,8 @@ It's reported to the input system via:: input_report_key(struct input_dev *dev, int code, int value) See uapi/linux/input-event-codes.h for the allowable values of code (from 0 to -KEY_MAX). Value is interpreted as a truth value, ie any nonzero value means key -pressed, zero value means key released. The input code generates events only +KEY_MAX). Value is interpreted as a truth value, i.e. any non-zero value means +key pressed, zero value means key released. The input code generates events only in case the value is different from before. In addition to EV_KEY, there are two more basic event types: EV_REL and @@ -231,12 +231,12 @@ because it doesn't have any absolute coordinate system to work in. Absolute events are namely for joysticks and digitizers - devices that do work in an absolute coordinate systems. -Having the device report EV_REL buttons is as simple as with EV_KEY, simply +Having the device report EV_REL buttons is as simple as with EV_KEY; simply set the corresponding bits and call the:: input_report_rel(struct input_dev *dev, int code, int value) -function. Events are generated only for nonzero value. +function. Events are generated only for non-zero values. However EV_ABS requires a little special care. Before calling input_register_device, you have to fill additional fields in the input_dev @@ -280,7 +280,7 @@ device driver. It's a string like 'Generic button device' containing a user friendly name of the device. The id* fields contain the bus ID (PCI, USB, ...), vendor ID and device ID -of the device. The bus IDs are defined in input.h. The vendor and device ids +of the device. The bus IDs are defined in input.h. The vendor and device IDs are defined in pci_ids.h, usb_ids.h and similar include files. These fields should be set by the input device driver before registering it. diff --git a/Documentation/input/input.rst b/Documentation/input/input.rst index 0eb61e67a7b784b0ccb31f17f464363dbaed4f82..2c67fa904adcf902cebf8e7137c0a1609d879a50 100644 --- a/Documentation/input/input.rst +++ b/Documentation/input/input.rst @@ -9,7 +9,7 @@ Introduction Architecture ============ -Input subsystem a collection of drivers that is designed to support +Input subsystem is a collection of drivers that is designed to support all input devices under Linux. Most of the drivers reside in drivers/input, although quite a few live in drivers/hid and drivers/platform. @@ -50,7 +50,7 @@ will be available as a character device on major 13, minor 63:: crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice -This device usually created automatically by the system. The commands +This device is usually created automatically by the system. The commands to create it by hand are:: cd /dev @@ -180,7 +180,7 @@ whole suite. It handles all HID devices, and because there is a very wide variety of them, and because the USB HID specification isn't simple, it needs to be this big. -Currently, it handles USB mice, joysticks, gamepads, steering wheels +Currently, it handles USB mice, joysticks, gamepads, steering wheels, keyboards, trackballs and digitizers. However, USB uses HID also for monitor controls, speaker controls, UPSs, @@ -268,7 +268,7 @@ events on a read. Their layout is:: }; ``time`` is the timestamp, it returns the time at which the event happened. -Type is for example EV_REL for relative moment, EV_KEY for a keypress or +Type is for example EV_REL for relative movement, EV_KEY for a keypress or release. More types are defined in include/uapi/linux/input-event-codes.h. ``code`` is event code, for example REL_X or KEY_BACKSPACE, again a complete diff --git a/Documentation/input/multi-touch-protocol.rst b/Documentation/input/multi-touch-protocol.rst index 21c1e6a228886136e4f126e88dedc844420c3a90..1085cbee4ee720bf465b804b0ccdafc177b8ff43 100644 --- a/Documentation/input/multi-touch-protocol.rst +++ b/Documentation/input/multi-touch-protocol.rst @@ -261,7 +261,7 @@ ABS_MT_PRESSURE signal intensity distribution. If the resolution is zero, the pressure data is in arbitrary units. - If the resolution is nonzero, the pressure data is in units/gram. See + If the resolution is non-zero, the pressure data is in units/gram. See :ref:`input-event-codes` for details. ABS_MT_DISTANCE @@ -279,14 +279,14 @@ ABS_MT_ORIENTATION max should be returned; when aligned with the X axis in the negative direction, the range -max should be returned. - Touch ellipsis are symmetrical by default. For devices capable of true 360 + Touch ellipses are symmetrical by default. For devices capable of true 360 degree orientation, the reported orientation must exceed the range max to indicate more than a quarter of a revolution. For an upside-down finger, range max * 2 should be returned. Orientation can be omitted if the touch area is circular, or if the information is not available in the kernel driver. Partial orientation - support is possible if the device can distinguish between the two axis, but + support is possible if the device can distinguish between the two axes, but not (uniquely) any values in between. In such cases, the range of ABS_MT_ORIENTATION should be [0, 1] [#f4]_. @@ -356,7 +356,7 @@ The range of ABS_MT_ORIENTATION should be set to [0, 1], to indicate that the device can distinguish between a finger along the Y axis (0) and a finger along the X axis (1). -For win8 devices with both T and C coordinates, the position mapping is:: +For Win8 devices with both T and C coordinates, the position mapping is:: ABS_MT_POSITION_X := T_X ABS_MT_POSITION_Y := T_Y diff --git a/Documentation/input/notifier.rst b/Documentation/input/notifier.rst index 161350cb865ebc78eaf1a94b898c962b047da6d8..824379399e611e46cd5d5ca93922efa974c0094b 100644 --- a/Documentation/input/notifier.rst +++ b/Documentation/input/notifier.rst @@ -4,11 +4,12 @@ Keyboard notifier One can use register_keyboard_notifier to get called back on keyboard events (see kbd_keycode() function for details). The passed structure is -keyboard_notifier_param: +keyboard_notifier_param (see <linux/keyboard.h>): - 'vc' always provide the VC for which the keyboard event applies; - 'down' is 1 for a key press event, 0 for a key release; - 'shift' is the current modifier state, mask bit indexes are KG_*; +- 'ledstate' is the current LED state; - 'value' depends on the type of event. - KBD_KEYCODE events are always sent before other events, value is the keycode. diff --git a/Documentation/input/uinput.rst b/Documentation/input/uinput.rst index 10c62e62a0a62d984c4a7abe554e8d5c1afe3a5e..30fe80e325a5d1ef00932d624306a08180250107 100644 --- a/Documentation/input/uinput.rst +++ b/Documentation/input/uinput.rst @@ -179,7 +179,7 @@ uinput old interface -------------------- Before uinput version 5, there wasn't a dedicated ioctl to set up a virtual -device. Programs supportinf older versions of uinput interface need to fill +device. Programs supporting older versions of uinput interface need to fill a uinput_user_dev structure and write it to the uinput file descriptor to configure the new uinput device. New code should not use the old interface but interact with uinput via ioctl calls, or use libevdev. diff --git a/Documentation/leds/leds-lm3556.rst b/Documentation/leds/leds-lm3556.rst index 1ef17d7d800e0da8c0094c03f4851b6106b99cd3..32e3983473ba472388cf086a5e9a4ff36f7dc138 100644 --- a/Documentation/leds/leds-lm3556.rst +++ b/Documentation/leds/leds-lm3556.rst @@ -23,7 +23,7 @@ from 93.75 mA to 1500 mA.The Flash currents are adjusted via the CURRENT CONTROL REGISTER(0x09).Flash mode is activated by the ENABLE REGISTER(0x0A), or by pulling the STROBE pin HIGH. -LM3556 Flash can be controlled through sys/class/leds/flash/brightness file +LM3556 Flash can be controlled through /sys/class/leds/flash/brightness file * if STROBE pin is enabled, below example control brightness only, and ON / OFF will be controlled by STROBE pin. @@ -32,17 +32,17 @@ Flash Example: OFF:: - #echo 0 > sys/class/leds/flash/brightness + #echo 0 > /sys/class/leds/flash/brightness 93.75 mA:: - #echo 1 > sys/class/leds/flash/brightness + #echo 1 > /sys/class/leds/flash/brightness ... 1500 mA:: - #echo 16 > sys/class/leds/flash/brightness + #echo 16 > /sys/class/leds/flash/brightness Torch Mode ^^^^^^^^^^ @@ -51,7 +51,7 @@ In Torch Mode, the current source(LED) is programmed via the CURRENT CONTROL REGISTER(0x09).Torch Mode is activated by the ENABLE REGISTER(0x0A) or by the hardware TORCH input. -LM3556 torch can be controlled through sys/class/leds/torch/brightness file. +LM3556 torch can be controlled through /sys/class/leds/torch/brightness file. * if TORCH pin is enabled, below example control brightness only, and ON / OFF will be controlled by TORCH pin. @@ -59,22 +59,22 @@ Torch Example: OFF:: - #echo 0 > sys/class/leds/torch/brightness + #echo 0 > /sys/class/leds/torch/brightness 46.88 mA:: - #echo 1 > sys/class/leds/torch/brightness + #echo 1 > /sys/class/leds/torch/brightness ... 375 mA:: - #echo 8 > sys/class/leds/torch/brightness + #echo 8 > /sys/class/leds/torch/brightness Indicator Mode ^^^^^^^^^^^^^^ -Indicator pattern can be set through sys/class/leds/indicator/pattern file, +Indicator pattern can be set through /sys/class/leds/indicator/pattern file, and 4 patterns are pre-defined in indicator_pattern array. According to N-lank, Pulse time and N Period values, different pattern wiill @@ -87,13 +87,13 @@ Indicator pattern example: pattern 0:: - #echo 0 > sys/class/leds/indicator/pattern + #echo 0 > /sys/class/leds/indicator/pattern ... pattern 3:: - #echo 3 > sys/class/leds/indicator/pattern + #echo 3 > /sys/class/leds/indicator/pattern Indicator brightness can be controlled through sys/class/leds/indicator/brightness file. @@ -102,17 +102,17 @@ Example: OFF:: - #echo 0 > sys/class/leds/indicator/brightness + #echo 0 > /sys/class/leds/indicator/brightness 5.86 mA:: - #echo 1 > sys/class/leds/indicator/brightness + #echo 1 > /sys/class/leds/indicator/brightness ... 46.875mA:: - #echo 8 > sys/class/leds/indicator/brightness + #echo 8 > /sys/class/leds/indicator/brightness Notes ----- diff --git a/Documentation/livepatch/shadow-vars.rst b/Documentation/livepatch/shadow-vars.rst index c05715aeafa4e9c844917a8d8a1f2439d34a9c8b..6a7d43a8787d88025ad9fbf759da0505ba4121fa 100644 --- a/Documentation/livepatch/shadow-vars.rst +++ b/Documentation/livepatch/shadow-vars.rst @@ -165,8 +165,8 @@ In-flight parent objects Sometimes it may not be convenient or possible to allocate shadow variables alongside their parent objects. Or a livepatch fix may -require shadow varibles to only a subset of parent object instances. In -these cases, the klp_shadow_get_or_alloc() call can be used to attach +require shadow variables for only a subset of parent object instances. +In these cases, the klp_shadow_get_or_alloc() call can be used to attach shadow variables to parents already in-flight. For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is diff --git a/Documentation/misc-devices/dw-xdata-pcie.rst b/Documentation/misc-devices/dw-xdata-pcie.rst new file mode 100644 index 0000000000000000000000000000000000000000..781c6794a50664fad7870773f4557cefa7775f83 --- /dev/null +++ b/Documentation/misc-devices/dw-xdata-pcie.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================================================================== +Driver for Synopsys DesignWare PCIe traffic generator (also known as xData) +=========================================================================== + +Supported chips: +Synopsys DesignWare PCIe prototype solution + +Datasheet: +Not freely available + +Author: +Gustavo Pimentel <gustavo.pimentel@synopsys.com> + +Description +----------- + +This driver should be used as a host-side (Root Complex) driver and Synopsys +DesignWare prototype that includes this IP. + +The dw-xdata-pcie driver can be used to enable/disable PCIe traffic +generator in either direction (mutual exclusion) besides allowing the +PCIe link performance analysis. + +The interaction with this driver is done through the module parameter and +can be changed in runtime. The driver outputs the requested command state +information to ``/var/log/kern.log`` or dmesg. + +Example +------- + +Write TLPs traffic generation - Root Complex to Endpoint direction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate traffic:: + + # echo 1 > /sys/class/misc/dw-xdata-pcie.0/write + +Get link throughput in MB/s:: + + # cat /sys/class/misc/dw-xdata-pcie.0/write + 204 + +Stop traffic in any direction:: + + # echo 0 > /sys/class/misc/dw-xdata-pcie.0/write + +Read TLPs traffic generation - Endpoint to Root Complex direction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate traffic:: + + # echo 1 > /sys/class/misc/dw-xdata-pcie.0/read + +Get link throughput in MB/s:: + + # cat /sys/class/misc/dw-xdata-pcie.0/read + 199 + +Stop traffic in any direction:: + + # echo 0 > /sys/class/misc/dw-xdata-pcie.0/read + diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index 64420b3314feb4bb1399edbbeb541f0a09030b0e..30ac58f8190132c1781e4d99fc84700df0bbef4d 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -19,6 +19,7 @@ fit into other categories. bh1770glc eeprom c2port + dw-xdata-pcie ibmvmc ics932s401 isl29003 diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst index d9c777b18f7a126c15ba954a20db1440a52d5768..18ae21bf7f925987b70523fab7f06c3809e12513 100644 --- a/Documentation/power/runtime_pm.rst +++ b/Documentation/power/runtime_pm.rst @@ -339,6 +339,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: checked additionally, and -EACCES means that 'power.disable_depth' is different from 0 + `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 + `int pm_request_idle(struct device *dev);` - submit a request to execute the subsystem-level idle callback for the device (the request is represented by a work item in pm_wq); returns 0 on diff --git a/Documentation/powerpc/booting.rst b/Documentation/powerpc/booting.rst index 2d0ec2ff2b579e1fd743b9ed98912c8863c197d7..11aa440f98cc9cf91f44ef540b94eb8b5f062fb7 100644 --- a/Documentation/powerpc/booting.rst +++ b/Documentation/powerpc/booting.rst @@ -94,7 +94,7 @@ 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 later is probably a good + PPC_PMAC and PPC_MAPLE. 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/powerpc/dawr-power9.rst b/Documentation/powerpc/dawr-power9.rst index c96ab6befd9c1123dbb6b946e433d2f488587019..e55ac6a24b97f944119fc54b7667152392e212c6 100644 --- a/Documentation/powerpc/dawr-power9.rst +++ b/Documentation/powerpc/dawr-power9.rst @@ -4,7 +4,7 @@ DAWR issues on POWER9 On POWER9 the Data Address Watchpoint Register (DAWR) can cause a checkstop if it points to cache inhibited (CI) memory. Currently Linux has no way to -disinguish CI memory when configuring the DAWR, so (for now) the DAWR is +distinguish CI memory when configuring the DAWR, so (for now) the DAWR is disabled by this commit:: commit 9654153158d3e0684a1bdb76dbababdb7111d5a0 diff --git a/Documentation/powerpc/eeh-pci-error-recovery.rst b/Documentation/powerpc/eeh-pci-error-recovery.rst index 438a87ebc09521ea393ba499bba2e1ae8d8990dc..d6643a91bdf8717b4cc5cb175512c515ed5a2ab3 100644 --- a/Documentation/powerpc/eeh-pci-error-recovery.rst +++ b/Documentation/powerpc/eeh-pci-error-recovery.rst @@ -73,7 +73,7 @@ return all-ff's (0xff, 0xffff, 0xffffffff for 8/16/32-bit reads). This value was chosen because it is the same value you would get if the device was physically unplugged from the slot. This includes access to PCI memory, I/O space, and PCI config -space. Interrupts; however, will continued to be delivered. +space. Interrupts; however, will continue to be delivered. Detection and recovery are performed with the aid of ppc64 firmware. The programming interfaces in the Linux kernel diff --git a/Documentation/powerpc/elfnote.rst b/Documentation/powerpc/elfnote.rst index 06602248621cb180467ec9309080e300b913d38f..3ec8d61e9a33fb0cfcf3ba8cb746f4c9ae29fb69 100644 --- a/Documentation/powerpc/elfnote.rst +++ b/Documentation/powerpc/elfnote.rst @@ -8,7 +8,7 @@ capabilities and information which can be used by a bootloader or userland. Types and Descriptors --------------------- -The types to be used with the "PowerPC" namesapce are defined in [#f1]_. +The types to be used with the "PowerPC" namespace are defined in [#f1]_. 1) PPC_ELFNOTE_CAPABILITIES diff --git a/Documentation/powerpc/firmware-assisted-dump.rst b/Documentation/powerpc/firmware-assisted-dump.rst index 20ea8cdee0aa168175bc26e4c9d3dae83eb391e6..e363fc48529a0a7f71dccdc25efa03de29ae438f 100644 --- a/Documentation/powerpc/firmware-assisted-dump.rst +++ b/Documentation/powerpc/firmware-assisted-dump.rst @@ -171,7 +171,7 @@ that were present in CMA region:: (meta area) | | | - Metadata: This area holds a metadata struture whose + Metadata: This area holds a metadata structure whose address is registered with f/w and retrieved in the second kernel after crash, on platforms that support tags (OPAL). Having such structure with info needed @@ -207,7 +207,7 @@ Currently the dump will be copied from /proc/vmcore to a new file upon user intervention. The dump data available through /proc/vmcore will be in ELF format. Hence the existing kdump infrastructure (kdump scripts) to save the dump works fine with minor modifications. KDump scripts on -major Distro releases have already been modified to work seemlessly (no +major Distro releases have already been modified to work seamlessly (no user intervention in saving the dump) when FADump is used, instead of KDump, as dump mechanism. diff --git a/Documentation/powerpc/kaslr-booke32.rst b/Documentation/powerpc/kaslr-booke32.rst index 8b259fdfdf03bbfe6e530249e1ad7c93bd4ebe93..5681c1d1b65b5de80ecc3b9b12e0d6cd8c78e448 100644 --- a/Documentation/powerpc/kaslr-booke32.rst +++ b/Documentation/powerpc/kaslr-booke32.rst @@ -38,5 +38,5 @@ bit of the entropy to decide the index of the 64M zone. Then we chose a kernstart_virt_addr -To enable KASLR, set CONFIG_RANDOMIZE_BASE = y. If KASLR is enable and you +To enable KASLR, set CONFIG_RANDOMIZE_BASE = y. If KASLR is enabled and you want to disable it at runtime, add "nokaslr" to the kernel cmdline. diff --git a/Documentation/powerpc/mpc52xx.rst b/Documentation/powerpc/mpc52xx.rst index 30260707c3fe85db252fcbda7356d21aab4321f7..5243b1763fad0b377508368679a1c8082ffd386d 100644 --- a/Documentation/powerpc/mpc52xx.rst +++ b/Documentation/powerpc/mpc52xx.rst @@ -34,7 +34,7 @@ To compile/use : Some remarks: - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100 - is not supported, and I'm not sure anyone is interesting in working on it + is not supported, and I'm not sure anyone is interested in working on it so. I didn't took 5xxx because there's apparently a lot of 5xxx that have nothing to do with the MPC5200. I also included the 'MPC' for the same reason. diff --git a/Documentation/powerpc/papr_hcalls.rst b/Documentation/powerpc/papr_hcalls.rst index 48fcf1255a338a2a3a09d18bbe9204bf0ac13292..3d553e8a29374aa79f176356c7200efa40996187 100644 --- a/Documentation/powerpc/papr_hcalls.rst +++ b/Documentation/powerpc/papr_hcalls.rst @@ -40,7 +40,7 @@ and any in-arguments for the hcall are provided in registers *r4-r12*. If values have to be passed through a memory buffer, the data stored in that buffer should be in Big-endian byte order. -Once control is returns back to the guest after hypervisor has serviced the +Once control returns back to the guest after hypervisor has serviced the 'HVCS' instruction the return value of the hcall is available in *r3* and any out values are returned in registers *r4-r12*. Again like in case of in-arguments, any out values stored in a memory buffer will be in Big-endian byte order. @@ -147,7 +147,7 @@ corresponding opcode values please look into the arch specific header [4]_: | Out: *numBytesRead* | Return Value: *H_Success, H_Parameter, H_P2, H_P3, H_Hardware* -Given a DRC Index of an NVDIMM, read N-bytes from the the metadata area +Given a DRC Index of an NVDIMM, read N-bytes from the metadata area associated with it, at a specified offset and copy it to provided buffer. The metadata area stores configuration information such as label information, bad-blocks etc. The metadata area is located out-of-band of NVDIMM storage diff --git a/Documentation/powerpc/transactional_memory.rst b/Documentation/powerpc/transactional_memory.rst index b5b09bf00966f189b9e26c304370d166d984ab3e..040a20675fd14d56f24b92797f85b8a014e5dee0 100644 --- a/Documentation/powerpc/transactional_memory.rst +++ b/Documentation/powerpc/transactional_memory.rst @@ -189,7 +189,7 @@ kernel aborted a transaction: ====================== ================================ These can be checked by the user program's abort handler as TEXASR[0:7]. If -bit 7 is set, it indicates that the error is consider persistent. For example +bit 7 is set, it indicates that the error is considered persistent. For example a TM_CAUSE_ALIGNMENT will be persistent while a TM_CAUSE_RESCHED will not. GDB @@ -271,4 +271,4 @@ with these lines: hrfid and mtmsrd have the same quirk. -The Linux kernel uses this quirk in it's early exception handling. +The Linux kernel uses this quirk in its early exception handling. diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index fa5a62f4150cc8e9cfd90fb0b9aef059d9a66458..f5ba36e964617dd68cf120f3c831f9658f6add84 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -73,12 +73,10 @@ CMAGIC 0x0111 user ``include/linux/ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h`` DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h`` PTY_MAGIC 0x5001 ``drivers/char/pty.c`` PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` @@ -90,14 +88,12 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h`` LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index 91de63b201c126ed19551cb2a35c9c29f9d55fe4..c66a19201deb5080ede9af90403acd1f7d239a29 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -341,6 +341,16 @@ that you have sent your patches to the right place. Wait for a minimum of one week before resubmitting or pinging reviewers - possibly longer during busy times like merge windows. +It's also ok to resend the patch or the patch series after a couple of +weeks with the word "RESEND" added to the subject line:: + + [PATCH Vx RESEND] sub/sys: Condensed patch summary + +Don't add "RESEND" when you are submitting a modified version of your +patch or patch series - "RESEND" only applies to resubmission of a +patch or patch series which have not been modified in any way from the +previous submission. + Include PATCH in the subject ----------------------------- @@ -625,16 +635,19 @@ not considered part of the summary phrase, but describe how the patch should be treated. Common tags might include a version descriptor if the multiple versions of the patch have been sent out in response to comments (i.e., "v1, v2, v3"), or "RFC" to indicate a request for -comments. If there are four patches in a patch series the individual -patches may be numbered like this: 1/4, 2/4, 3/4, 4/4. This assures -that developers understand the order in which the patches should be -applied and that they have reviewed or applied all of the patches in -the patch series. +comments. -A couple of example Subjects:: +If there are four patches in a patch series the individual patches may +be numbered like this: 1/4, 2/4, 3/4, 4/4. This assures that developers +understand the order in which the patches should be applied and that +they have reviewed or applied all of the patches in the patch series. + +Here are some good example Subjects:: Subject: [PATCH 2/5] ext2: improve scalability of bitmap searching Subject: [PATCH v2 01/27] x86: fix eflags tracking + Subject: [PATCH v2] sub/sys: Condensed patch summary + Subject: [PATCH v2 M/N] sub/sys: Condensed patch summary The ``from`` line must be the very first line in the message body, and has the form: @@ -647,34 +660,54 @@ then the ``From:`` line from the email header will be used to determine the patch author in the changelog. The explanation body will be committed to the permanent source -changelog, so should make sense to a competent reader who has long -since forgotten the immediate details of the discussion that might -have led to this patch. Including symptoms of the failure which the -patch addresses (kernel log messages, oops messages, etc.) is -especially useful for people who might be searching the commit logs -looking for the applicable patch. If a patch fixes a compile failure, -it may not be necessary to include _all_ of the compile failures; just -enough that it is likely that someone searching for the patch can find -it. As in the ``summary phrase``, it is important to be both succinct as -well as descriptive. - -The ``---`` marker line serves the essential purpose of marking for patch -handling tools where the changelog message ends. - -One good use for the additional comments after the ``---`` marker is for -a ``diffstat``, to show what files have changed, and the number of -inserted and deleted lines per file. A ``diffstat`` is especially useful -on bigger patches. Other comments relevant only to the moment or the -maintainer, not suitable for the permanent changelog, should also go -here. A good example of such comments might be ``patch changelogs`` -which describe what has changed between the v1 and v2 version of the -patch. - -If you are going to include a ``diffstat`` after the ``---`` marker, please -use ``diffstat`` options ``-p 1 -w 70`` so that filenames are listed from -the top of the kernel source tree and don't use too much horizontal -space (easily fit in 80 columns, maybe with some indentation). (``git`` -generates appropriate diffstats by default.) +changelog, so should make sense to a competent reader who has long since +forgotten the immediate details of the discussion that might have led to +this patch. Including symptoms of the failure which the patch addresses +(kernel log messages, oops messages, etc.) are especially useful for +people who might be searching the commit logs looking for the applicable +patch. The text should be written in such detail so that when read +weeks, months or even years later, it can give the reader the needed +details to grasp the reasoning for **why** the patch was created. + +If a patch fixes a compile failure, it may not be necessary to include +_all_ of the compile failures; just enough that it is likely that +someone searching for the patch can find it. As in the ``summary +phrase``, it is important to be both succinct as well as descriptive. + +The ``---`` marker line serves the essential purpose of marking for +patch handling tools where the changelog message ends. + +One good use for the additional comments after the ``---`` marker is +for a ``diffstat``, to show what files have changed, and the number of +inserted and deleted lines per file. A ``diffstat`` is especially useful +on bigger patches. If you are going to include a ``diffstat`` after the +``---`` marker, please use ``diffstat`` options ``-p 1 -w 70`` so that +filenames are listed from the top of the kernel source tree and don't +use too much horizontal space (easily fit in 80 columns, maybe with some +indentation). (``git`` generates appropriate diffstats by default.) + +Other comments relevant only to the moment or the maintainer, not +suitable for the permanent changelog, should also go here. A good +example of such comments might be ``patch changelogs`` which describe +what has changed between the v1 and v2 version of the patch. + +Please put this information **after** the ``---`` line which separates +the changelog from the rest of the patch. The version information is +not part of the changelog which gets committed to the git tree. It is +additional information for the reviewers. If it's placed above the +commit tags, it needs manual interaction to remove it. If it is below +the separator line, it gets automatically stripped off when applying the +patch:: + + <commit message> + ... + Signed-off-by: Author <author@mail> + --- + V2 -> V3: Removed redundant helper function + V1 -> V2: Cleaned up coding style and addressed review comments + + path/to/file | 5+++-- + ... See more details on the proper patch format in the following references. diff --git a/Documentation/scsi/ChangeLog.megaraid b/Documentation/scsi/ChangeLog.megaraid index d2052fdbedd236d0325f86c2f6df57721fd1322e..cbb329956897cb7470139fc9f05506c2b0516dcb 100644 --- a/Documentation/scsi/ChangeLog.megaraid +++ b/Documentation/scsi/ChangeLog.megaraid @@ -220,7 +220,7 @@ Older Version : 2.20.4.5 (scsi module), 2.20.2.5 (cmm module) 4. Use the pre defined DMA mask constants from dma-mapping.h Use the DMA_{64,32}BIT_MASK constants from dma-mapping.h when calling - pci_set_dma_mask() or pci_set_consistend_dma_mask(). See + pci_set_dma_mask() or pci_set_consistent_dma_mask(). See http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for more details. Signed-off-by: Tobias Klauser <tklauser@nuerscht.ch> diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst index 1da879a68640bdac88a558fa830586070cfa49f5..80d5a5af62a1de0a571ab749319958e7c9912e75 100644 --- a/Documentation/security/keys/trusted-encrypted.rst +++ b/Documentation/security/keys/trusted-encrypted.rst @@ -6,30 +6,127 @@ Trusted and Encrypted Keys are two new key types added to the existing kernel key ring service. Both of these new types are variable length symmetric keys, and in both cases all keys are created in the kernel, and user space sees, stores, and loads only encrypted blobs. Trusted Keys require the availability -of a Trusted Platform Module (TPM) chip for greater security, while Encrypted -Keys can be used on any system. All user level blobs, are displayed and loaded -in hex ascii for convenience, and are integrity verified. +of a Trust Source for greater security, while Encrypted Keys can be used on any +system. All user level blobs, are displayed and loaded in hex ASCII for +convenience, and are integrity verified. -Trusted Keys use a TPM both to generate and to seal the keys. Keys are sealed -under a 2048 bit RSA key in the TPM, and optionally sealed to specified PCR -(integrity measurement) values, and only unsealed by the TPM, if PCRs and blob -integrity verifications match. A loaded Trusted Key can be updated with new -(future) PCR values, so keys are easily migrated to new pcr values, such as -when the kernel and initramfs are updated. The same key can have many saved -blobs under different PCR values, so multiple boots are easily supported. -TPM 1.2 -------- +Trust Source +============ -By default, trusted keys are sealed under the SRK, which has the default -authorization value (20 zeros). This can be set at takeownership time with the -trouser's utility: "tpm_takeownership -u -z". +A trust source provides the source of security for Trusted Keys. This +section lists currently supported trust sources, along with their security +considerations. Whether or not a trust source is sufficiently safe depends +on the strength and correctness of its implementation, as well as the threat +environment for a specific use case. Since the kernel doesn't know what the +environment is, and there is no metric of trust, it is dependent on the +consumer of the Trusted Keys to determine if the trust source is sufficiently +safe. -TPM 2.0 -------- + * Root of trust for storage -The user must first create a storage key and make it persistent, so the key is -available after reboot. This can be done using the following commands. + (1) TPM (Trusted Platform Module: hardware device) + + Rooted to Storage Root Key (SRK) which never leaves the TPM that + provides crypto operation to establish root of trust for storage. + + (2) TEE (Trusted Execution Environment: OP-TEE based on Arm TrustZone) + + Rooted to Hardware Unique Key (HUK) which is generally burnt in on-chip + fuses and is accessible to TEE only. + + * Execution isolation + + (1) TPM + + Fixed set of operations running in isolated execution environment. + + (2) TEE + + Customizable set of operations running in isolated execution + environment verified via Secure/Trusted boot process. + + * Optional binding to platform integrity state + + (1) TPM + + Keys can be optionally sealed to specified PCR (integrity measurement) + values, and only unsealed by the TPM, if PCRs and blob integrity + verifications match. A loaded Trusted Key can be updated with new + (future) PCR values, so keys are easily migrated to new PCR values, + such as when the kernel and initramfs are updated. The same key can + have many saved blobs under different PCR values, so multiple boots are + easily supported. + + (2) TEE + + Relies on Secure/Trusted boot process for platform integrity. It can + be extended with TEE based measured boot process. + + * Interfaces and APIs + + (1) TPM + + TPMs have well-documented, standardized interfaces and APIs. + + (2) TEE + + TEEs have well-documented, standardized client interface and APIs. For + more details refer to ``Documentation/staging/tee.rst``. + + + * Threat model + + The strength and appropriateness of a particular TPM or TEE for a given + purpose must be assessed when using them to protect security-relevant data. + + +Key Generation +============== + +Trusted Keys +------------ + +New keys are created from random numbers generated in the trust source. They +are encrypted/decrypted using a child key in the storage key hierarchy. +Encryption and decryption of the child key must be protected by a strong +access control policy within the trust source. + + * TPM (hardware device) based RNG + + Strength of random numbers may vary from one device manufacturer to + another. + + * TEE (OP-TEE based on Arm TrustZone) based RNG + + RNG is customizable as per platform needs. It can either be direct output + from platform specific hardware RNG or a software based Fortuna CSPRNG + which can be seeded via multiple entropy sources. + +Encrypted Keys +-------------- + +Encrypted keys do not depend on a trust source, and are faster, as they use AES +for encryption/decryption. New keys are created from kernel-generated random +numbers, and are encrypted/decrypted using a specified ‘master’ key. The +‘master’ key can either be a trusted-key or user-key type. The main disadvantage +of encrypted keys is that if they are not rooted in a trusted key, they are only +as secure as the user key encrypting them. The master user key should therefore +be loaded in as secure a way as possible, preferably early in boot. + + +Usage +===== + +Trusted Keys usage: TPM +----------------------- + +TPM 1.2: By default, trusted keys are sealed under the SRK, which has the +default authorization value (20 bytes of 0s). This can be set at takeownership +time with the TrouSerS utility: "tpm_takeownership -u -z". + +TPM 2.0: The user must first create a storage key and make it persistent, so the +key is available after reboot. This can be done using the following commands. With the IBM TSS 2 stack:: @@ -78,14 +175,21 @@ TPM_STORED_DATA format. The key length for new keys are always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits), the upper limit is to fit within the 2048 bit SRK (RSA) keylength, with all necessary structure/padding. -Encrypted keys do not depend on a TPM, and are faster, as they use AES for -encryption/decryption. New keys are created from kernel generated random -numbers, and are encrypted/decrypted using a specified 'master' key. The -'master' key can either be a trusted-key or user-key type. The main -disadvantage of encrypted keys is that if they are not rooted in a trusted key, -they are only as secure as the user key encrypting them. The master user key -should therefore be loaded in as secure a way as possible, preferably early in -boot. +Trusted Keys usage: TEE +----------------------- + +Usage:: + + keyctl add trusted name "new keylen" ring + keyctl add trusted name "load hex_blob" ring + keyctl print keyid + +"keyctl print" returns an ASCII hex copy of the sealed key, which is in format +specific to TEE device implementation. The key length for new keys is always +in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits). + +Encrypted Keys usage +-------------------- The decrypted portion of encrypted keys can contain either a simple symmetric key or a more complex structure. The format of the more complex structure is @@ -103,8 +207,8 @@ Where:: format:= 'default | ecryptfs | enc32' key-type:= 'trusted' | 'user' - -Examples of trusted and encrypted key usage: +Examples of trusted and encrypted key usage +------------------------------------------- Create and save a trusted key named "kmk" of length 32 bytes. @@ -150,7 +254,7 @@ Load a trusted key from the saved blob:: f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b e4a8aea2b607ec96931e6f4d4fe563ba -Reseal a trusted key under new pcr values:: +Reseal (TPM specific) a trusted key under new PCR values:: $ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`" $ keyctl print 268728824 @@ -164,11 +268,12 @@ Reseal a trusted key under new pcr values:: 7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8 + The initial consumer of trusted keys is EVM, which at boot time needs a high -quality symmetric key for HMAC protection of file metadata. The use of a +quality symmetric key for HMAC protection of file metadata. The use of a trusted key provides strong guarantees that the EVM key has not been -compromised by a user level problem, and when sealed to specific boot PCR -values, protects against boot and offline attacks. Create and save an +compromised by a user level problem, and when sealed to a platform integrity +state, protects against boot and offline attacks. Create and save an encrypted key "evm" using the above trusted key "kmk": option 1: omitting 'format':: @@ -207,3 +312,61 @@ about the usage can be found in the file Another new format 'enc32' has been defined in order to support encrypted keys with payload size of 32 bytes. This will initially be used for nvdimm security but may expand to other usages that require 32 bytes payload. + + +TPM 2.0 ASN.1 Key Format +------------------------ + +The TPM 2.0 ASN.1 key format is designed to be easily recognisable, +even in binary form (fixing a problem we had with the TPM 1.2 ASN.1 +format) and to be extensible for additions like importable keys and +policy:: + + TPMKey ::= SEQUENCE { + type OBJECT IDENTIFIER + emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL + parent INTEGER + pubkey OCTET STRING + privkey OCTET STRING + } + +type is what distinguishes the key even in binary form since the OID +is provided by the TCG to be unique and thus forms a recognizable +binary pattern at offset 3 in the key. The OIDs currently made +available are:: + + 2.23.133.10.1.3 TPM Loadable key. This is an asymmetric key (Usually + RSA2048 or Elliptic Curve) which can be imported by a + TPM2_Load() operation. + + 2.23.133.10.1.4 TPM Importable Key. This is an asymmetric key (Usually + RSA2048 or Elliptic Curve) which can be imported by a + TPM2_Import() operation. + + 2.23.133.10.1.5 TPM Sealed Data. This is a set of data (up to 128 + bytes) which is sealed by the TPM. It usually + represents a symmetric key and must be unsealed before + use. + +The trusted key code only uses the TPM Sealed Data OID. + +emptyAuth is true if the key has well known authorization "". If it +is false or not present, the key requires an explicit authorization +phrase. This is used by most user space consumers to decide whether +to prompt for a password. + +parent represents the parent key handle, either in the 0x81 MSO space, +like 0x81000001 for the RSA primary storage key. Userspace programmes +also support specifying the primary handle in the 0x40 MSO space. If +this happens the Elliptic Curve variant of the primary key using the +TCG defined template will be generated on the fly into a volatile +object and used as the parent. The current kernel code only supports +the 0x81 MSO form. + +pubkey is the binary representation of TPM2B_PRIVATE excluding the +initial TPM2B header, which can be reconstructed from the ASN.1 octet +string length. + +privkey is the binary representation of TPM2B_PUBLIC excluding the +initial TPM2B header which can be reconstructed from the ASN.1 octed +string length. diff --git a/Documentation/sphinx/rstFlatTable.py b/Documentation/sphinx/rstFlatTable.py index a3eea0bbe6ba6dc8ead548a6ad20c4a14f25cc43..16bea0632555fcf69c605c8ac07fdc5b048761d5 100755 --- a/Documentation/sphinx/rstFlatTable.py +++ b/Documentation/sphinx/rstFlatTable.py @@ -22,7 +22,7 @@ u""" * *auto span* rightmost cell of a table row over the missing cells on the right side of that table-row. With Option ``:fill-cells:`` this behavior - can changed from *auto span* to *auto fill*, which automaticly inserts + can be changed from *auto span* to *auto fill*, which automatically inserts (empty) cells instead of spanning the last cell. Options: @@ -161,7 +161,7 @@ class ListTableBuilder(object): for colwidth in colwidths: colspec = nodes.colspec(colwidth=colwidth) # FIXME: It seems, that the stub method only works well in the - # absence of rowspan (observed by the html buidler, the docutils-xml + # absence of rowspan (observed by the html builder, the docutils-xml # build seems OK). This is not extraordinary, because there exists # no table directive (except *this* flat-table) which allows to # define coexistent of rowspan and stubs (there was no use-case diff --git a/Documentation/spi/butterfly.rst b/Documentation/spi/butterfly.rst index e614a589547cf7ed7731c294ad6528e2186eb9d5..56088fb090c7302bd88999c6aacee18aadd8978d 100644 --- a/Documentation/spi/butterfly.rst +++ b/Documentation/spi/butterfly.rst @@ -11,7 +11,7 @@ develop firmware for this, and flash it using this adapter cable. You can make this adapter from an old printer cable and solder things directly to the Butterfly. Or (if you have the parts and skills) you -can come up with something fancier, providing ciruit protection to the +can come up with something fancier, providing circuit protection to the Butterfly and the printer port, or with a better power supply than two signal pins from the printer port. Or for that matter, you can use similar cables to talk to many AVR boards, even a breadboard. diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst index f1daffe10d782086a1a7a4db0e1991a29edf930a..d4239025461ded55cf2998ff0bdf56eee0888d36 100644 --- a/Documentation/spi/spi-summary.rst +++ b/Documentation/spi/spi-summary.rst @@ -411,8 +411,11 @@ any more such messages. duplex (one pointer is NULL) transfers; + optionally defining short delays after transfers ... using - the spi_transfer.delay_usecs setting (this delay can be the - only protocol effect, if the buffer length is zero); + the spi_transfer.delay.value setting (this delay can be the + only protocol effect, if the buffer length is zero) ... + when specifying this delay the default spi_transfer.delay.unit + is microseconds, however this can be adjusted to clock cycles + or nanoseconds if needed; + whether the chipselect becomes inactive after a transfer and any delay ... by using the spi_transfer.cs_change flag; diff --git a/Documentation/translations/it_IT/doc-guide/sphinx.rst b/Documentation/translations/it_IT/doc-guide/sphinx.rst index 090d2949d345c74f904391f1e3dcb3aac96aab63..0046d75d9a706de49ee54f131d0565c05087bef9 100644 --- a/Documentation/translations/it_IT/doc-guide/sphinx.rst +++ b/Documentation/translations/it_IT/doc-guide/sphinx.rst @@ -330,17 +330,17 @@ la lista di celle che compongono la *riga* stessa. Fanno eccezione i *commenti* - head col 3 - head col 4 - * - column 1 + * - row 1 - field 1.1 - field 1.2 with autospan - * - column 2 + * - row 2 - field 2.1 - :rspan:`1` :cspan:`1` field 2.2 - 3.3 * .. _`it last row`: - - column 3 + - row 3 Che verrà rappresentata nel seguente modo: @@ -352,37 +352,46 @@ Che verrà rappresentata nel seguente modo: - head col 3 - head col 4 - * - column 1 + * - row 1 - field 1.1 - field 1.2 with autospan - * - column 2 + * - row 2 - field 2.1 - :rspan:`1` :cspan:`1` field 2.2 - 3.3 * .. _`it last row`: - - column 3 + - row 3 Riferimenti incrociati ---------------------- -Per fare dei riferimenti incrociati da una pagina ad un'altra -specificando il percorso a partire dalla cartella *Documentation*. -Per esempio, se volete aggiungere un riferimento a questa pagina -(l'estensione .rst è opzionale):: +Aggiungere un riferimento incrociato da una pagina della +documentazione ad un'altra può essere fatto scrivendo il percorso al +file corrispondende, non serve alcuna sintassi speciale. Si possono +usare sia percorsi assoluti che relativi. Quelli assoluti iniziano con +"documentation/". Per esempio, potete fare riferimento a questo +documento in uno dei seguenti modi (da notare che l'estensione +``.rst`` è necessaria):: - See Documentation/translations/it_IT/doc-guide/sphinx.rst. + Vedere Documentation/doc-guide/sphinx.rst. Questo funziona sempre + Guardate pshinx.rst, che si trova nella stessa cartella. + Leggete ../sphinx.rst, che si trova nella cartella precedente. -Se preferite usare un percorso relative allora vi serve la direttiva -Sphinx ``doc``. Per esempio, se volete aggiungere un riferimento a -questa pagina dalla stessa cartella:: +Se volete che il collegamento abbia un testo diverso rispetto al +titolo del documento, allora dovrete usare la direttiva Sphinx +``doc``. Per esempio:: - See :doc:`sphinx`. + Vedere :doc:`il mio testo per il collegamento <sphinx>`. -Per maggiori informazioni su come aggiungere riferimenti incrociati a -commenti kernel-doc di funzioni o tipi, leggete -Documentation/translations/it_IT/doc-guide/sphinx.rst. +Nella maggioranza dei casi si consiglia il primo metodo perché è più +pulito ed adatto a chi legge dai sorgenti. Se incontrare un ``:doc:`` +che non da alcun valore, sentitevi liberi di convertirlo in un +percorso al documento. + +Per informazioni riguardo ai riferimenti incrociati ai commenti +kernel-doc per funzioni o tipi, consultate .. _it_sphinx_kfigure: @@ -391,7 +400,7 @@ Figure ed immagini Se volete aggiungere un'immagine, utilizzate le direttive ``kernel-figure`` e ``kernel-image``. Per esempio, per inserire una figura di un'immagine in -formato SVG:: +formato SVG (:ref:`it_svg_image_example`):: .. kernel-figure:: ../../../doc-guide/svg_image.svg :alt: una semplice immagine SVG diff --git a/Documentation/translations/it_IT/kernel-hacking/hacking.rst b/Documentation/translations/it_IT/kernel-hacking/hacking.rst index 3d30b69f1ec10d1af1f420a8cd6c4b710b445a3a..f6beb385b4acfccd66ff6744a1a988ec51534481 100644 --- a/Documentation/translations/it_IT/kernel-hacking/hacking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/hacking.rst @@ -369,7 +369,7 @@ all'inizio dell'avvio del sistema è attraverso la procedura Prima di inventare la vostra cache per gli oggetti più usati, considerate l'uso di una cache slab disponibile in ``include/linux/slab.h``. -:c:func:`current()` +:c:macro:`current` ------------------- Definita in ``include/asm/current.h`` diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst index bf1acd6204efab7fdde5e265803094180ec29b1a..1e7c84def369239782866f328fa33e89582da6e1 100644 --- a/Documentation/translations/it_IT/kernel-hacking/locking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst @@ -127,11 +127,11 @@ il vostro processo si auto-sospenderà; verrà riattivato quando il mutex verrà rilasciato. Questo significa che il processore potrà occuparsi d'altro mentre il vostro processo è in attesa. Esistono molti casi in cui non potete permettervi di sospendere un processo (vedere -:ref:`Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni? <it_sleeping-things>`) +`Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni?`_) e quindi dovrete utilizzare gli spinlock. Nessuno di questi *lock* è ricorsivo: vedere -:ref:`Stallo: semplice ed avanzato <it_deadlock>` +`Stallo: semplice ed avanzato`_ I *lock* e i kernel per sistemi monoprocessore ---------------------------------------------- @@ -190,7 +190,7 @@ perfetto questa funzione si chiamerebbe 'spin_lock_softirq()'). Da notare che in questo caso potete utilizzare anche spin_lock_irq() o spin_lock_irqsave(), queste fermano anche le interruzioni hardware: -vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`. +vedere `Contesto di interruzione hardware`_. Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock svaniscono e questa macro diventa semplicemente local_bh_disable() @@ -241,7 +241,7 @@ Lo stesso softirq Lo stesso softirq può essere eseguito su un diverso processore: allo scopo di migliorare le prestazioni potete utilizzare dati riservati ad ogni -processore (vedere :ref:`Dati per processore <it_per-cpu>`). Se siete arrivati +processore (vedere `Dati per processore`_). Se siete arrivati fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità delle prestazioni abbastanza da giustificarne la complessità aggiuntiva. @@ -896,8 +896,6 @@ leggendo solamente il codice. E come dice Alan Cox: “Lock data, not code”. Problemi comuni =============== -.. _`it_deadlock`: - Stallo: semplice ed avanzato ---------------------------- @@ -1282,7 +1280,6 @@ Il beneficio qui sta nel fatto che il contatore di riferimenti no viene scritto: l'oggetto non viene alterato in alcun modo e quindi diventa molto più veloce su sistemi molti-processore grazie alla loro memoria cache. -.. _`it_per-cpu`: Dati per processore ------------------- @@ -1333,7 +1330,6 @@ Naturalmente, questo è più lento della semplice chiamata spin_lock_irq(), quindi ha senso solo se questo genere di accesso è estremamente raro. -.. _`it_sleeping-things`: Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni? ========================================================================= diff --git a/Documentation/translations/it_IT/process/4.Coding.rst b/Documentation/translations/it_IT/process/4.Coding.rst index 8012fe9497aea50b94978a8d9a7678f7684d608f..54fd255b77d02c61a26350b681607823bf0dfc4a 100644 --- a/Documentation/translations/it_IT/process/4.Coding.rst +++ b/Documentation/translations/it_IT/process/4.Coding.rst @@ -264,11 +264,10 @@ La maggior parte di queste opzioni possono essere attivate per qualsiasi kernel utilizzato per lo sviluppo o a scopo di test. In particolare dovreste attivare: - - ENABLE_MUST_CHECK e FRAME_WARN per ottenere degli - avvertimenti dedicati a problemi come l'uso di interfacce deprecate o - l'ignorare un importante valore di ritorno di una funzione. Il risultato - generato da questi avvertimenti può risultare verboso, ma non bisogna - preoccuparsi per gli avvertimenti provenienti da altre parti del kernel. + - FRAME_WARN per ottenere degli avvertimenti su stack frame più + grandi di un dato valore. Il risultato generato da questi + avvertimenti può risultare verboso, ma non bisogna preoccuparsi per + gli avvertimenti provenienti da altre parti del kernel. - DEBUG_OBJECTS aggiungerà un codice per tracciare il ciclo di vita di diversi oggetti creati dal kernel e avvisa quando qualcosa viene eseguito diff --git a/Documentation/translations/it_IT/process/adding-syscalls.rst b/Documentation/translations/it_IT/process/adding-syscalls.rst index c478b6e8c292228cec1e13d9cbcf137391c682af..df8c652d004b1a1a418483ff4c0cee6da028189d 100644 --- a/Documentation/translations/it_IT/process/adding-syscalls.rst +++ b/Documentation/translations/it_IT/process/adding-syscalls.rst @@ -562,7 +562,7 @@ kernel. Se la nuova funzionalità è utile all'interno del kernel, per esempio dev'essere condivisa fra una vecchia e una nuova chiamata di sistema o dev'essere utilizzata da una chiamata di sistema e la sua variante compatibile, allora dev'essere implementata come una funzione di supporto -(*helper function*) (per esempio ``kern_xyzzy()``). Questa funzione potrà +(*helper function*) (per esempio ``ksys_xyzzy()``). Questa funzione potrà essere chiamata dallo *stub* (``sys_xyzzy()``), dalla variante compatibile (``compat_sys_xyzzy()``), e/o da altri parti del kernel. diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst index c86c4543f2491a439232287a7bde9c0f4ad18618..95f2e7c985e2d29839e3bd159c621187ef26ac3d 100644 --- a/Documentation/translations/it_IT/process/coding-style.rst +++ b/Documentation/translations/it_IT/process/coding-style.rst @@ -75,9 +75,26 @@ stessa riga: if (condition) do_this; do_something_everytime; -né mettete più assegnamenti sulla stessa riga. Lo stile del kernel +Non usate le virgole per evitare le parentesi: + +.. code-block:: c + + if (condition) + do_this(), do_that(); + +Invece, usate sempre le parentesi per racchiudere più istruzioni. + +.. code-block:: c + + if (condition) { + do_this(); + do_that(); + } + +Non mettete nemmeno più assegnamenti sulla stessa riga. Lo stile del kernel è ultrasemplice. Evitate espressioni intricate. + Al di fuori dei commenti, della documentazione ed escludendo i Kconfig, gli spazi non vengono mai usati per l'indentazione, e l'esempio qui sopra è volutamente errato. @@ -320,8 +337,7 @@ qualcosa di simile, **non** dovreste chiamarla ``cntusr()``. Codificare il tipo di funzione nel suo nome (quella cosa chiamata notazione ungherese) è stupido - il compilatore conosce comunque il tipo e -può verificarli, e inoltre confonde i programmatori. Non c'è da -sorprendersi che MicroSoft faccia programmi bacati. +può verificarli, e inoltre confonde i programmatori. Le variabili LOCALI dovrebbero avere nomi corti, e significativi. Se avete un qualsiasi contatore di ciclo, probabilmente sarà chiamato ``i``. diff --git a/Documentation/translations/it_IT/process/howto.rst b/Documentation/translations/it_IT/process/howto.rst index 1db5a1082389752b2e20163b4f25c9d1810f3892..9554368a2ae26671beb4048d56aa2e2d2e6da210 100644 --- a/Documentation/translations/it_IT/process/howto.rst +++ b/Documentation/translations/it_IT/process/howto.rst @@ -357,17 +357,10 @@ benvenuti. Riportare Bug ------------- -https://bugzilla.kernel.org è dove gli sviluppatori del kernel Linux tracciano -i bachi del kernel. Gli utenti sono incoraggiati nel riportare tutti i bachi -che trovano utilizzando questo strumento. -Per maggiori dettagli su come usare il bugzilla del kernel, guardare: - - https://bugzilla.kernel.org/page.cgi?id=faq.html - -Il file admin-guide/reporting-bugs.rst nella cartella principale del kernel -fornisce un buon modello sul come segnalare un baco nel kernel, e spiega quali -informazioni sono necessarie agli sviluppatori per poter aiutare il -rintracciamento del problema. +Il file 'Documentation/admin-guide/reporting-issues.rst' nella +cartella principale del kernel spiega come segnalare un baco nel +kernel, e fornisce dettagli su quali informazioni sono necessarie agli +sviluppatori del kernel per poter studiare il problema. Gestire i rapporti sui bug -------------------------- @@ -380,8 +373,14 @@ al corrente della vostra presenza. Riparare bachi è una delle migliori vie per acquisire meriti tra gli altri sviluppatori, perchè non a molte persone piace perdere tempo a sistemare i bachi di altri. -Per lavorare sui rapporti di bachi già riportati, andate su -https://bugzilla.kernel.org. +Per lavorare sui bachi già segnalati, per prima cosa cercate il +sottosistema che vi interessa. Poi, verificate nel file MAINTAINERS +dove vengono collezionati solitamente i bachi per quel sottosistema; +spesso sarà una lista di discussione, raramente un bugtracker. Cercate +bachi nell'archivio e aiutate dove credete di poterlo fare. Potete +anche consultare https://bugzilla.kernel.org; però, solo una manciata di +sottosistemi lo usano attivamente, ciò nonostante i bachi che +coinvolgono l'intero kernel sono sempre riportati lì. Liste di discussione -------------------- diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 1af30f4228f249dc696c10d9a2f331d6f7a5f273..f452fafb1e84cce85fe65664dab168c9f9090872 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -79,12 +79,10 @@ CMAGIC 0x0111 user ``include/linux/ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h`` DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h`` PTY_MAGIC 0x5001 ``drivers/char/pty.c`` PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` @@ -96,16 +94,13 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h`` LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` -GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h`` RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c`` @@ -148,7 +143,6 @@ PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/me NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h`` ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.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`` diff --git a/Documentation/translations/it_IT/process/submit-checklist.rst b/Documentation/translations/it_IT/process/submit-checklist.rst index 614fc17d90869a87aa3443841fc9937eea66a6ec..2fc09cc1f0be51afa916b561b0b2fada33a7eb57 100644 --- a/Documentation/translations/it_IT/process/submit-checklist.rst +++ b/Documentation/translations/it_IT/process/submit-checklist.rst @@ -28,6 +28,10 @@ sottomissione delle patch, in particolare 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. @@ -54,8 +58,7 @@ sottomissione delle patch, in particolare 9) Verificare con sparse. -10) Usare ``make checkstack`` e ``make namespacecheck`` e correggere tutti i - problemi rilevati. +10) Usare ``make checkstack`` e correggere tutti i problemi rilevati. .. note:: @@ -95,31 +98,29 @@ sottomissione delle patch, in particolare informazioni. Le patch che modificano le interfacce utente dovrebbero essere inviate in copia anche a linux-api@vger.kernel.org. -20) Verifica che il kernel passi con successo ``make headers_check`` - -21) La patch è stata verificata con l'iniezione di fallimenti in slab e +20) 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. -22) Il nuovo codice è stato compilato con ``gcc -W`` (usate +21) 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". -23) La patch è stata verificata dopo essere stata inclusa nella serie di patch +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. -24) Tutte le barriere di sincronizzazione {per esempio, ``barrier()``, +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é. -25) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate +24) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate ``Documentation/userspace-api/ioctl/ioctl-number.rst``. -26) Se il codice che avete modificato dipende o usa una qualsiasi interfaccia o +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 diff --git a/Documentation/translations/it_IT/process/submitting-patches.rst b/Documentation/translations/it_IT/process/submitting-patches.rst index ae00352346edd76dcb2117308528895e89a45e06..ded95048b9a85e718e74b1f59a159501fa1360f1 100644 --- a/Documentation/translations/it_IT/process/submitting-patches.rst +++ b/Documentation/translations/it_IT/process/submitting-patches.rst @@ -433,6 +433,14 @@ Alcune persone aggiungono delle etichette alla fine. Per ora queste verranno ignorate, ma potete farlo per meglio identificare procedure aziendali interne o per aggiungere dettagli circa la firma. +In seguito al SoB (Signed-off-by:) dell'autore ve ne sono altri da +parte di tutte quelle persone che si sono occupate della gestione e +del trasporto della patch. Queste però non sono state coinvolte nello +sviluppo, ma la loro sequenza d'apparizione ci racconta il percorso +**reale** che una patch a intrapreso dallo sviluppatore, fino al +manutentore, per poi giungere a Linus. + + Quando utilizzare Acked-by:, Cc:, e Co-developed-by: ---------------------------------------------------- @@ -574,6 +582,10 @@ kernel stabili al fine di capire quale kernel deve ricevere la correzione. Questo è il modo suggerito per indicare che un baco è stato corretto nella patch. Per maggiori dettagli leggete :ref:`it_describe_changes` +Da notare che aggiungere un tag "Fixes:" non esime dalle regole +previste per i kernel stabili, e nemmeno dalla necessità di aggiungere +in copia conoscenza stable@vger.kernel.org su tutte le patch per +suddetti kernel. Il formato canonico delle patch ------------------------------- @@ -642,16 +654,20 @@ Le etichette non verranno considerate come parte della frase riassuntiva, ma indicano come la patch dovrebbe essere trattata. Fra le etichette più comuni ci sono quelle di versione che vengono usate quando una patch è stata inviata più volte (per esempio, "v1, v2, v3"); oppure "RFC" per indicare che si -attendono dei commenti (*Request For Comments*). Se ci sono quattro patch -nella serie, queste dovrebbero essere enumerate così: 1/4, 2/4, 3/4, 4/4. -Questo assicura che gli sviluppatori capiranno l'ordine in cui le patch -dovrebbero essere applicate, e per tracciare quelle che hanno revisionate o -che hanno applicato. +attendono dei commenti (*Request For Comments*). + +Se ci sono quattro patch nella serie, queste dovrebbero essere +enumerate così: 1/4, 2/4, 3/4, 4/4. Questo assicura che gli +sviluppatori capiranno l'ordine in cui le patch dovrebbero essere +applicate, e per tracciare quelle che hanno revisionate o che hanno +applicato. Un paio di esempi di oggetti:: Subject: [PATCH 2/5] ext2: improve scalability of bitmap searching Subject: [PATCH v2 01/27] x86: fix eflags tracking + Subject: [PATCH v2] sub/sys: Condensed patch summary + Subject: [PATCH v2 M/N] sub/sys: Condensed patch summary La riga ``from`` dev'essere la prima nel corpo del messaggio ed è nel formato: @@ -668,30 +684,76 @@ deve aver senso per un lettore esperto che è ha dimenticato i dettagli della discussione che hanno portato alla patch. L'inclusione di informazioni sui problemi oggetto dalla patch (messaggi del kernel, messaggi di oops, eccetera) è particolarmente utile per le persone che potrebbero cercare fra -i messaggi di log per la patch che li tratta. Se la patch corregge un errore -di compilazione, non sarà necessario includere proprio _tutto_ quello che -è uscito dal compilatore; aggiungete solo quello che è necessario per far si -che la vostra patch venga trovata. Come nella ``summary phrase``, è importante -essere sia brevi che descrittivi. +i messaggi di log per la patch che li tratta. Il testo dovrebbe essere scritto +con abbastanza dettagli da far capire al lettore **perché** quella +patch fu creata, e questo a distanza di settimane, mesi, o addirittura +anni. + +Se la patch corregge un errore di compilazione, non sarà necessario +includere proprio _tutto_ quello che è uscito dal compilatore; +aggiungete solo quello che è necessario per far si che la vostra patch +venga trovata. Come nella ``summary phrase``, è importante essere sia +brevi che descrittivi. La linea di demarcazione ``---`` serve essenzialmente a segnare dove finisce il messaggio di changelog. Aggiungere il ``diffstat`` dopo ``---`` è un buon uso di questo spazio, per mostrare i file che sono cambiati, e il numero di file aggiunto o rimossi. -Un ``diffstat`` è particolarmente utile per le patch grandi. Altri commenti -che sono importanti solo per i manutentori, quindi inadatti al changelog -permanente, dovrebbero essere messi qui. Un buon esempio per questo tipo -di commenti potrebbe essere quello di descrivere le differenze fra le versioni +Un ``diffstat`` è particolarmente utile per le patch grandi. Se +includete un ``diffstat`` dopo ``---``, usate le opzioni ``-p 1 -w70`` +cosicché i nomi dei file elencati non occupino troppo spazio +(facilmente rientreranno negli 80 caratteri, magari con qualche +indentazione). (``git`` genera di base dei diffstat adatti). + +I commenti che sono importanti solo per i manutentori, quindi +inadatti al changelog permanente, dovrebbero essere messi qui. Un +buon esempio per questo tipo di commenti potrebbe essere il cosiddetto +``patch changelogs`` che descrivere le differenze fra le versioni della patch. -Se includete un ``diffstat`` dopo ``---``, usate le opzioni ``-p 1 -w70`` -cosicché i nomi dei file elencati non occupino troppo spazio (facilmente -rientreranno negli 80 caratteri, magari con qualche indentazione). -(``git`` genera di base dei diffstat adatti). +Queste informazioni devono andare **dopo** la linea ``---`` che separa +il *changelog* dal resto della patch. Le informazioni riguardanti la +versione di una patch non sono parte del *chagelog* che viene incluso +in git. Queste sono informazioni utili solo ai revisori. Se venissero +messe sopra la riga, qualcuno dovrà fare del lavoro manuale per +rimuoverle; cosa che invece viene fatta automaticamente quando vengono +messe correttamente oltre la riga.:: + + <commit message> + ... + Signed-off-by: Author <author@mail> + --- + V2 -> V3: Removed redundant helper function + V1 -> V2: Cleaned up coding style and addressed review comments + + path/to/file | 5+++-- + ... Maggiori dettagli sul formato delle patch nei riferimenti qui di seguito. +Aggiungere i *backtrace* nei messaggi di commit +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +I *backtrace* aiutano a documentare la sequenza di chiamate a funzione +che portano ad un problema. Tuttavia, non tutti i *backtrace* sono +davvero utili. Per esempio, le sequenze iniziali di avvio sono uniche +e ovvie. Copiare integralmente l'output di ``dmesg`` aggiunge tante +informazioni che distraggono dal vero problema (per esempio, i +marcatori temporali, la lista dei moduli, la lista dei registri, lo +stato dello stack). + +Quindi, per rendere utile un *backtrace* dovreste eliminare le +informazioni inutili, cosicché ci si possa focalizzare sul +problema. Ecco un esempio di un *backtrace* essenziale:: + + unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064) + at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20) + Call Trace: + mba_wrmsr + update_domains + rdtgroup_mkdir + .. _it_explicit_in_reply_to: Usare esplicitamente In-Reply-To nell'intestazione diff --git a/Documentation/translations/ja_JP/SubmitChecklist b/Documentation/translations/ja_JP/SubmitChecklist index b42220d3d46c89b3d89b26fee53119dd26e2c1ab..4429447b096558f3d3519990d9804482dc1c4610 100644 --- a/Documentation/translations/ja_JP/SubmitChecklist +++ b/Documentation/translations/ja_JP/SubmitChecklist @@ -88,20 +88,18 @@ Linux カーネルパッチ投稿者向けチェックリスト 18: 新しいuserspaceインタフェースを作成した場合には、Documentation/ABI/ に Documentation/ABI/README を参考にして必ずドキュメントを追加してください。 -19: 'make headers_check'を実行して全く問題がないことを確認してください。 - -20: 少なくともslabアロケーションとpageアロケーションに失敗した場合の +19: 少なくともslabアロケーションとpageアロケーションに失敗した場合の 挙動について、fault-injectionを利用して確認してください。 Documentation/fault-injection/ を参照してください。 追加したコードがかなりの量であったならば、サブシステム特有の fault-injectionを追加したほうが良いかもしれません。 -21: 新たに追加したコードは、`gcc -W'でコンパイルしてください。 +20: 新たに追加したコードは、`gcc -W'でコンパイルしてください。 このオプションは大量の不要なメッセージを出力しますが、 "warning: comparison between signed and unsigned" のようなメッセージは、 バグを見つけるのに役に立ちます。 -22: 投稿したパッチが -mm パッチセットにマージされた後、全ての既存のパッチや +21: 投稿したパッチが -mm パッチセットにマージされた後、全ての既存のパッチや VM, VFS およびその他のサブシステムに関する様々な変更と、現時点でも共存 できることを確認するテストを行ってください。 diff --git a/Documentation/translations/ko_KR/howto.rst b/Documentation/translations/ko_KR/howto.rst index 787f1e85f8a079eaab1c2d803b3624bb2d37e4a9..a2bdd564c907a090a251addb862592691c3002f0 100644 --- a/Documentation/translations/ko_KR/howto.rst +++ b/Documentation/translations/ko_KR/howto.rst @@ -339,14 +339,8 @@ Andrew Morton의 글이 있다. 버그 보고 --------- -https://bugzilla.kernel.org 는 리눅스 커널 개발자들이 커널의 버그를 추적하는 -곳이다. 사용자들은 발견한 모든 버그들을 보고하기 위하여 이 툴을 사용할 것을 -권장한다. kernel bugzilla를 사용하는 자세한 방법은 다음을 참조하라. - - https://bugzilla.kernel.org/page.cgi?id=faq.html - 메인 커널 소스 디렉토리에 있는 'Documentation/admin-guide/reporting-issues.rst' -파일은 커널 버그라고 생각되는 것을 보고하는 방법에 관한 좋은 템플릿이며 문제를 +파일은 커널 버그라고 생각되는 것을 어떻게 보고하면 되는지, 그리고 문제를 추적하기 위해서 커널 개발자들이 필요로 하는 정보가 무엇들인지를 상세히 설명하고 있다. @@ -362,8 +356,14 @@ https://bugzilla.kernel.org 는 리눅스 커널 개발자들이 커널의 버 점수를 얻을 수 있는 가장 좋은 방법중의 하나이다. 왜냐하면 많은 사람들은 다른 사람들의 버그들을 수정하기 위하여 시간을 낭비하지 않기 때문이다. -이미 보고된 버그 리포트들을 가지고 작업하기 위해서 https://bugzilla.kernel.org -를 참조하라. +이미 보고된 버그 리포트들을 가지고 작업하기 위해서는 여러분이 관심있는 +서브시스템을 찾아라. 해당 서브시스템의 버그들이 어디로 리포트 되는지 +MAINTAINERS 파일을 체크하라; 그건 대부분 메일링 리스트이고, 가끔은 버그 추적 +시스템이다. 그 장소에 있는 최근 버그 리포트 기록들을 검색하고 여러분이 보기에 +적합하다 싶은 것을 도와라. 여러분은 버그 리포트를 위해 +https://bugzilla.kernel.org 를 체크하고자 할 수도 있다; 소수의 커널 +서브시스템들만이 버그 신고와 추적을 위해 해당 시스템을 실제로 사용하고 있지만, +전체 커널의 버그들이 그곳에 정리된다. 메일링 리스트들 diff --git a/Documentation/translations/zh_CN/admin-guide/README.rst b/Documentation/translations/zh_CN/admin-guide/README.rst new file mode 100644 index 0000000000000000000000000000000000000000..669a022f68175e93a462ccb256e12bbae7d182a5 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/README.rst @@ -0,0 +1,347 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/admin-guide/README.rst + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +Linux内核5.x版本 <http://kernel.org/> +========================================= + +以下是Linux版本5的发行注记。仔细阅读它们, +它们会告诉你这些都是什么,解释如何安装内核,以及遇到问题时该如何做。 + +什么是Linux? +--------------- + + Linux是Unix操作系统的克隆版本,由Linus Torvalds在一个松散的网络黑客 + (Hacker,无贬义)团队的帮助下从头开始编写。它旨在实现兼容POSIX和 + 单一UNIX规范。 + + 它具有在现代成熟的Unix中应当具有的所有功能,包括真正的多任务处理、虚拟内存、 + 共享库、按需加载、共享的写时拷贝(COW)可执行文件、恰当的内存管理以及包括 + IPv4和IPv6在内的复合网络栈。 + + Linux在GNU通用公共许可证,版本2(GNU GPLv2)下分发,详见随附的COPYING文件。 + +它能在什么样的硬件上运行? +----------------------------- + + 虽然Linux最初是为32位的x86 PC机(386或更高版本)开发的,但今天它也能运行在 + (至少)Compaq Alpha AXP、Sun SPARC与UltraSPARC、Motorola 68000、PowerPC、 + PowerPC64、ARM、Hitachi SuperH、Cell、IBM S/390、MIPS、HP PA-RISC、Intel + IA-64、DEC VAX、AMD x86-64 Xtensa和ARC架构上。 + + Linux很容易移植到大多数通用的32位或64位体系架构,只要它们有一个分页内存管理 + 单元(PMMU)和一个移植的GNU C编译器(gcc;GNU Compiler Collection,GCC的一 + 部分)。Linux也被移植到许多没有PMMU的体系架构中,尽管功能显然受到了一定的 + 限制。 + Linux也被移植到了其自己上。现在可以将内核作为用户空间应用程序运行——这被 + 称为用户模式Linux(UML)。 + +文档 +----- +因特网上和书籍上都有大量的电子文档,既有Linux专属文档,也有与一般UNIX问题相关 +的文档。我建议在任何Linux FTP站点上查找LDP(Linux文档项目)书籍的文档子目录。 +本自述文件并不是关于系统的文档:有更好的可用资源。 + + - 因特网上和书籍上都有大量的(电子)文档,既有Linux专属文档,也有与普通 + UNIX问题相关的文档。我建议在任何有LDP(Linux文档项目)书籍的Linux FTP + 站点上查找文档子目录。本自述文件并不是关于系统的文档:有更好的可用资源。 + + - 文档/子目录中有各种自述文件:例如,这些文件通常包含一些特定驱动程序的 + 内核安装说明。请阅读 + :ref:`Documentation/process/changes.rst <changes>` 文件,它包含了升级内核 + 可能会导致的问题的相关信息。 + +安装内核源代码 +--------------- + + - 如果您要安装完整的源代码,请把内核tar档案包放在您有权限的目录中(例如您 + 的主目录)并将其解包:: + + xz -cd linux-5.x.tar.xz | tar xvf - + + 将“X”替换成最新内核的版本号。 + + 【不要】使用 /usr/src/linux 目录!这里有一组库头文件使用的内核头文件 + (通常是不完整的)。它们应该与库匹配,而不是被内核的变化搞得一团糟。 + + - 您还可以通过打补丁在5.x版本之间升级。补丁以xz格式分发。要通过打补丁进行 + 安装,请获取所有较新的补丁文件,进入内核源代码(linux-5.x)的目录并 + 执行:: + + xz -cd ../patch-5.x.xz | patch -p1 + + 请【按顺序】替换所有大于当前源代码树版本的“x”,这样就可以了。您可能想要 + 删除备份文件(文件名类似xxx~ 或 xxx.orig),并确保没有失败的补丁(文件名 + 类似xxx# 或 xxx.rej)。如果有,不是你就是我犯了错误。 + + 与5.x内核的补丁不同,5.x.y内核(也称为稳定版内核)的补丁不是增量的,而是 + 直接应用于基本的5.x内核。例如,如果您的基本内核是5.0,并且希望应用5.0.3 + 补丁,则不应先应用5.0.1和5.0.2的补丁。类似地,如果您运行的是5.0.2内核, + 并且希望跳转到5.0.3,那么在应用5.0.3补丁之前,必须首先撤销5.0.2补丁 + (即patch -R)。更多关于这方面的内容,请阅读 + :ref:`Documentation/process/applying-patches.rst <applying_patches>` 。 + + 或者,脚本 patch-kernel 可以用来自动化这个过程。它能确定当前内核版本并 + 应用找到的所有补丁:: + + linux/scripts/patch-kernel linux + + 上面命令中的第一个参数是内核源代码的位置。补丁是在当前目录应用的,但是 + 可以将另一个目录指定为第二个参数。 + + - 确保没有过时的 .o 文件和依赖项:: + + cd linux + make mrproper + + 现在您应该已经正确安装了源代码。 + +软件要求 +--------- + + 编译和运行5.x内核需要各种软件包的最新版本。请参考 + :ref:`Documentation/process/changes.rst <changes>` + 来了解最低版本要求以及如何升级软件包。请注意,使用过旧版本的这些包可能会 + 导致很难追踪的间接错误,因此不要以为在生成或操作过程中出现明显问题时可以 + 只更新包。 + +为内核建立目录 +--------------- + + 编译内核时,默认情况下所有输出文件都将与内核源代码放在一起。使用 + ``make O=output/dir`` 选项可以为输出文件(包括 .config)指定备用位置。 + 例如:: + + kernel source code: /usr/src/linux-5.x + build directory: /home/name/build/kernel + + 要配置和构建内核,请使用:: + + cd /usr/src/linux-5.x + make O=/home/name/build/kernel menuconfig + make O=/home/name/build/kernel + sudo make O=/home/name/build/kernel modules_install install + + 请注意:如果使用了 ``O=output/dir`` 选项,那么它必须用于make的所有调用。 + +配置内核 +--------- + + 即使只升级一个小版本,也不要跳过此步骤。每个版本中都会添加新的配置选项, + 如果配置文件没有按预定设置,就会出现奇怪的问题。如果您想以最少的工作量 + 将现有配置升级到新版本,请使用 ``makeoldconfig`` ,它只会询问您新配置 + 选项的答案。 + + - 其他配置命令包括:: + + "make config" 纯文本界面。 + + "make menuconfig" 基于文本的彩色菜单、选项列表和对话框。 + + "make nconfig" 增强的基于文本的彩色菜单。 + + "make xconfig" 基于Qt的配置工具。 + + "make gconfig" 基于GTK+的配置工具。 + + "make oldconfig" 基于现有的 ./.config 文件选择所有选项,并询问 + 新配置选项。 + + "make olddefconfig" + 类似上一个,但不询问直接将新选项设置为默认值。 + + "make defconfig" 根据体系架构,使用arch/$arch/defconfig或 + arch/$arch/configs/${PLATFORM}_defconfig中的 + 默认选项值创建./.config文件。 + + "make ${PLATFORM}_defconfig" + 使用arch/$arch/configs/${PLATFORM}_defconfig中 + 的默认选项值创建一个./.config文件。 + 用“makehelp”来获取您体系架构中所有可用平台的列表。 + + "make allyesconfig" + 通过尽可能将选项值设置为“y”,创建一个 + ./.config文件。 + + "make allmodconfig" + 通过尽可能将选项值设置为“m”,创建一个 + ./.config文件。 + + "make allnoconfig" 通过尽可能将选项值设置为“n”,创建一个 + ./.config文件。 + + "make randconfig" 通过随机设置选项值来创建./.config文件。 + + "make localmodconfig" 基于当前配置和加载的模块(lsmod)创建配置。禁用 + 已加载的模块不需要的任何模块选项。 + + 要为另一台计算机创建localmodconfig,请将该计算机 + 的lsmod存储到一个文件中,并将其作为lsmod参数传入。 + + 此外,通过在参数LMC_KEEP中指定模块的路径,可以将 + 模块保留在某些文件夹或kconfig文件中。 + + target$ lsmod > /tmp/mylsmod + target$ scp /tmp/mylsmod host:/tmp + + host$ make LSMOD=/tmp/mylsmod \ + LMC_KEEP="drivers/usb:drivers/gpu:fs" \ + localmodconfig + + 上述方法在交叉编译时也适用。 + + "make localyesconfig" 与localmodconfig类似,只是它会将所有模块选项转换 + 为内置(=y)。你可以同时通过LMC_KEEP保留模块。 + + "make kvmconfig" 为kvm客体内核支持启用其他选项。 + + "make xenconfig" 为xen dom0客体内核支持启用其他选项。 + + "make tinyconfig" 配置尽可能小的内核。 + + 更多关于使用Linux内核配置工具的信息,见文档 + Documentation/kbuild/kconfig.rst。 + + - ``make config`` 注意事项: + + - 包含不必要的驱动程序会使内核变大,并且在某些情况下会导致问题: + 探测不存在的控制器卡可能会混淆其他控制器。 + + - 如果存在协处理器,则编译了数学仿真的内核仍将使用协处理器:在 + 这种情况下,数学仿真永远不会被使用。内核会稍微大一点,但不管 + 是否有数学协处理器,都可以在不同的机器上工作。 + + - “kernel hacking”配置细节通常会导致更大或更慢的内核(或两者 + 兼而有之),甚至可以通过配置一些例程来主动尝试破坏坏代码以发现 + 内核问题,从而降低内核的稳定性(kmalloc())。因此,您可能应该 + 用于研究“开发”、“实验”或“调试”特性相关问题。 + +编译内核 +--------- + + - 确保您至少有gcc 4.9可用。 + 有关更多信息,请参阅 :ref:`Documentation/process/changes.rst <changes>` 。 + + 请注意,您仍然可以使用此内核运行a.out用户程序。 + + - 执行 ``make`` 来创建压缩内核映像。如果您安装了lilo以适配内核makefile, + 那么也可以进行 ``makeinstall`` ,但是您可能需要先检查特定的lilo设置。 + + 实际安装必须以root身份执行,但任何正常构建都不需要。 + 无须徒然使用root身份。 + + - 如果您将内核的任何部分配置为模块,那么还必须执行 ``make modules_install`` 。 + + - 详细的内核编译/生成输出: + + 通常,内核构建系统在相当安静的模式下运行(但不是完全安静)。但是有时您或 + 其他内核开发人员需要看到编译、链接或其他命令的执行过程。为此,可使用 + “verbose(详细)”构建模式。 + 向 ``make`` 命令传递 ``V=1`` 来实现,例如:: + + make V=1 all + + 如需构建系统也给出内个目标重建的愿意,请使用 ``V=2`` 。默认为 ``V=0`` 。 + + - 准备一个备份内核以防出错。对于开发版本尤其如此,因为每个新版本都包含 + 尚未调试的新代码。也要确保保留与该内核对应的模块的备份。如果要安装 + 与工作内核版本号相同的新内核,请在进行 ``make modules_install`` 安装 + 之前备份modules目录。 + + 或者,在编译之前,使用内核配置选项“LOCALVERSION”向常规内核版本附加 + 一个唯一的后缀。LOCALVERSION可以在“General Setup”菜单中设置。 + + - 为了引导新内核,您需要将内核映像(例如编译后的 + .../linux/arch/x86/boot/bzImage)复制到常规可引导内核的位置。 + + - 不再支持在没有LILO等启动装载程序帮助的情况下直接从软盘引导内核。 + + 如果从硬盘引导Linux,很可能使用LILO,它使用/etc/lilo.conf文件中 + 指定的内核映像文件。内核映像文件通常是/vmlinuz、/boot/vmlinuz、 + /bzImage或/boot/bzImage。使用新内核前,请保存旧映像的副本,并复制 + 新映像覆盖旧映像。然后您【必须重新运行LILO】来更新加载映射!否则, + 将无法启动新的内核映像。 + + 重新安装LILO通常需要运行/sbin/LILO。您可能希望编辑/etc/lilo.conf + 文件为旧内核映像指定一个条目(例如/vmlinux.old)防止新的不能正常 + 工作。有关更多信息,请参阅LILO文档。 + + 重新安装LILO之后,您应该就已经准备好了。关闭系统,重新启动,尽情 + 享受吧! + + 如果需要更改内核映像中的默认根设备、视频模式等,请在适当的地方使用 + 启动装载程序的引导选项。无需重新编译内核即可更改这些参数。 + + - 使用新内核重新启动并享受它吧。 + +若遇到问题 +----------- + + - 如果您发现了一些可能由于内核缺陷所导致的问题,请检查MAINTAINERS(维护者) + 文件看看是否有人与令您遇到麻烦的内核部分相关。如果无人在此列出,那么第二 + 个最好的方案就是把它们发给我(torvalds@linux-foundation.org),也可能发送 + 到任何其他相关的邮件列表或新闻组。 + + - 在所有的缺陷报告中,【请】告诉我们您在说什么内核,如何复现问题,以及您的 + 设置是什么的(使用您的常识)。如果问题是新的,请告诉我;如果问题是旧的, + 请尝试告诉我您什么时候首次注意到它。 + + - 如果缺陷导致如下消息:: + + unable to handle kernel paging request at address C0000010 + Oops: 0002 + EIP: 0010:XXXXXXXX + eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx + esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx + ds: xxxx es: xxxx fs: xxxx gs: xxxx + Pid: xx, process nr: xx + xx xx xx xx xx xx xx xx xx xx + + 或者类似的内核调试信息显示在屏幕上或在系统日志里,请【如实】复制它。 + 可能对你来说转储(dump)看起来不可理解,但它确实包含可能有助于调试问题的 + 信息。转储上方的文本也很重要:它说明了内核转储代码的原因(在上面的示例中, + 是由于内核指针错误)。更多关于如何理解转储的信息,请参见 + Documentation/admin-guide/bug-hunting.rst。 + + - 如果使用 CONFIG_KALLSYMS 编译内核,则可以按原样发送转储,否则必须使用 + ``ksymoops`` 程序来理解转储(但通常首选使用CONFIG_KALLSYMS编译)。 + 此实用程序可从 + https://www.kernel.org/pub/linux/utils/kernel/ksymoops/ 下载。 + 或者,您可以手动执行转储查找: + + - 在调试像上面这样的转储时,如果您可以查找EIP值的含义,这将非常有帮助。 + 十六进制值本身对我或其他任何人都没有太大帮助:它会取决于特定的内核设置。 + 您应该做的是从EIP行获取十六进制值(忽略 ``0010:`` ),然后在内核名字列表 + 中查找它,以查看哪个内核函数包含有问题的地址。 + + 要找到内核函数名,您需要找到与显示症状的内核相关联的系统二进制文件。就是 + 文件“linux/vmlinux”。要提取名字列表并将其与内核崩溃中的EIP进行匹配, + 请执行:: + + nm vmlinux | sort | less + + 这将为您提供一个按升序排序的内核地址列表,从中很容易找到包含有问题的地址 + 的函数。请注意,内核调试消息提供的地址不一定与函数地址完全匹配(事实上, + 这是不可能的),因此您不能只“grep”列表:不过列表将为您提供每个内核函数 + 的起点,因此通过查找起始地址低于你正在搜索的地址,但后一个函数的高于的 + 函数,你会找到您想要的。实际上,在您的问题报告中加入一些“上下文”可能是 + 一个好主意,给出相关的上下几行。 + + 如果您由于某些原因无法完成上述操作(如您使用预编译的内核映像或类似的映像), + 请尽可能多地告诉我您的相关设置信息,这会有所帮助。有关详细信息请阅读 + ‘Documentation/admin-guide/reporting-issues.rst’。 + + - 或者,您可以在正在运行的内核上使用gdb(只读的;即不能更改值或设置断点)。 + 为此,请首先使用-g编译内核;适当地编辑arch/x86/Makefile,然后执行 ``make + clean`` 。您还需要启用CONFIG_PROC_FS(通过 ``make config`` )。 + + 使用新内核重新启动后,执行 ``gdb vmlinux /proc/kcore`` 。现在可以使用所有 + 普通的gdb命令。查找系统崩溃点的命令是 ``l *0xXXXXXXXX`` (将xxx替换为EIP + 值)。 + + 用gdb无法调试一个当前未运行的内核是由于gdb(错误地)忽略了编译内核的起始 + 偏移量。 diff --git a/Documentation/translations/zh_CN/admin-guide/bug-bisect.rst b/Documentation/translations/zh_CN/admin-guide/bug-bisect.rst new file mode 100644 index 0000000000000000000000000000000000000000..662eb5b46e84ec2190c4ee388936621ef43f644b --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/bug-bisect.rst @@ -0,0 +1,81 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../admin-guide/bug-bisect` + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +二分(bisect)缺陷 ++++++++++++++++++++ + +(英文版)最后更新:2016年10月28日 + +引言 +===== + +始终尝试由来自kernel.org的源代码构建的最新内核。如果您没有信心这样做,请将 +错误报告给您的发行版供应商,而不是内核开发人员。 + +找到缺陷(bug)并不总是那么容易,不过仍然得去找。如果你找不到它,不要放弃。 +尽可能多的向相关维护人员报告您发现的信息。请参阅MAINTAINERS文件以了解您所 +关注的子系统的维护人员。 + +在提交错误报告之前,请阅读“Documentation/admin-guide/reporting-issues.rst”。 + +设备未出现(Devices not appearing) +==================================== + +这通常是由udev/systemd引起的。在将其归咎于内核之前先检查一下。 + +查找导致缺陷的补丁 +=================== + +使用 ``git`` 提供的工具可以很容易地找到缺陷,只要缺陷是可复现的。 + +操作步骤: + +- 从git源代码构建内核 +- 以此开始二分 [#f1]_:: + + $ git bisect start + +- 标记损坏的变更集:: + + $ git bisect bad [commit] + +- 标记正常工作的变更集:: + + $ git bisect good [commit] + +- 重新构建内核并测试 +- 使用以下任一与git bisect进行交互:: + + $ git bisect good + + 或:: + + $ git bisect bad + + 这取决于您测试的变更集上是否有缺陷 +- 在一些交互之后,git bisect将给出可能导致缺陷的变更集。 + +- 例如,如果您知道当前版本有问题,而4.8版本是正常的,则可以执行以下操作:: + + $ git bisect start + $ git bisect bad # Current version is bad + $ git bisect good v4.8 + + +.. [#f1] 您可以(可选地)在开始git bisect的时候提供good或bad参数 + ``git bisect start [BAD] [GOOD]`` + +如需进一步参考,请阅读: + +- ``git-bisect`` 的手册页 +- `Fighting regressions with git bisect(用git bisect解决回归) + <https://www.kernel.org/pub/software/scm/git/docs/git-bisect-lk2009.html>`_ +- `Fully automated bisecting with "git bisect run"(使用git bisect run + 来全自动二分) <https://lwn.net/Articles/317154>`_ +- `Using Git bisect to figure out when brokenness was introduced + (使用Git二分来找出何时引入了错误) <http://webchick.net/node/99>`_ diff --git a/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst b/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst new file mode 100644 index 0000000000000000000000000000000000000000..decb9b26d2f1ae701d23129f1bb9e87f7e45a4b0 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst @@ -0,0 +1,340 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../admin-guide/bug-hunting` + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +追踪缺陷 +========= + +内核错误报告通常附带如下堆栈转储:: + + ------------[ cut here ]------------ + WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70 + Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core] + CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1 + Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009 + 00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6 + c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10 + f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617 + Call Trace: + [<c12ba080>] ? dump_stack+0x44/0x64 + [<c103ed6a>] ? __warn+0xfa/0x120 + [<c109e8a7>] ? module_put+0x57/0x70 + [<c109e8a7>] ? module_put+0x57/0x70 + [<c103ee33>] ? warn_slowpath_null+0x23/0x30 + [<c109e8a7>] ? module_put+0x57/0x70 + [<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk] + [<c109f617>] ? symbol_put_addr+0x27/0x50 + [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb] + [<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb] + [<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0 + [<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb] + [<c13d2882>] ? usb_unbind_interface+0x62/0x250 + [<c136b514>] ? __pm_runtime_idle+0x44/0x70 + [<c13620d8>] ? __device_release_driver+0x78/0x120 + [<c1362907>] ? driver_detach+0x87/0x90 + [<c1361c48>] ? bus_remove_driver+0x38/0x90 + [<c13d1c18>] ? usb_deregister+0x58/0xb0 + [<c109fbb0>] ? SyS_delete_module+0x130/0x1f0 + [<c1055654>] ? task_work_run+0x64/0x80 + [<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90 + [<c10013f0>] ? do_fast_syscall_32+0x80/0x130 + [<c1549f43>] ? sysenter_past_esp+0x40/0x6a + ---[ end trace 6ebc60ef3981792f ]--- + +这样的堆栈跟踪提供了足够的信息来识别内核源代码中发生错误的那一行。根据问题的 +严重性,它还可能包含 **“Oops”** 一词,比如:: + + BUG: unable to handle kernel NULL pointer dereference at (null) + IP: [<c06969d4>] iret_exc+0x7d0/0xa59 + *pdpt = 000000002258a001 *pde = 0000000000000000 + Oops: 0002 [#1] PREEMPT SMP + ... + +尽管有 **Oops** 或其他类型的堆栈跟踪,但通常需要找到出问题的行来识别和处理缺 +陷。在本章中,我们将参考“Oops”来了解需要分析的各种堆栈跟踪。 + +如果内核是用 ``CONFIG_DEBUG_INFO`` 编译的,那么可以使用文件: +`scripts/decode_stacktrace.sh` 。 + +链接的模块 +----------- + +受到污染或正在加载/卸载的模块用“(…)”标记,污染标志在 +`Documentation/admin-guide/tainted-kernels.rst` 文件中进行了描述,“正在被加 +载”用“+”标注,“正在被卸载”用“-”标注。 + + +Oops消息在哪? +--------------- + +通常,Oops文本由klogd从内核缓冲区读取,然后交给 ``syslogd`` ,后者将其写入 +syslog文件,通常是 ``/var/log/messages`` (取决于 ``/etc/syslog.conf`` )。 +在使用systemd的系统上,它也可以由 ``journald`` 守护进程存储,并通过运行 +``journalctl`` 命令进行访问。 + +有时 ``klogd`` 会挂掉,这种情况下您可以运行 ``dmesg > file`` 从内核缓冲区 +读取数据并保存它。或者您可以 ``cat /proc/kmsg > file`` ,但是您必须适时 +中断以停止传输,因为 ``kmsg`` 是一个“永无止境的文件”。 + +如果机器严重崩溃,无法输入命令或磁盘不可用,那还有三个选项: + +(1) 手动复制屏幕上的文本,并在机器重新启动后输入。很难受,但这是突然崩溃下 + 唯一的选择。或者你可以用数码相机拍下屏幕——虽然不那么好,但总比什么都没 + 有好。如果消息滚动超出控制台顶部,使用更高分辨率(例如 ``vga=791`` ) + 引导启动将允许您阅读更多文本。(警告:这需要 ``vesafb`` ,因此对“早期” + 的Oppses没有帮助) + +(2) 从串口终端启动(参见 + :ref:`Documentation/admin-guide/serial-console.rst <serial_console>` ), + 在另一台机器上运行调制解调器然后用你喜欢的通信程序捕获输出。 + Minicom运行良好。 + +(3) 使用Kdump(参阅 Documentation/admin-guide/kdump/kdump.rst ),使用 + Documentation/admin-guide/kdump/gdbmacros.txt 中的dmesg gdbmacro从旧内存 + 中提取内核环形缓冲区。 + +找到缺陷位置 +------------- + +如果你能指出缺陷在内核源代码中的位置,则报告缺陷的效果会非常好。这有两种方法。 +通常来说使用 ``gdb`` 会比较容易,不过内核需要用调试信息来预编译。 + +gdb +^^^^ + +GNU 调试器(GNU debugger, ``gdb`` )是从 ``vmlinux`` 文件中找出OOPS的确切 +文件和行号的最佳方法。 + +在使用 ``CONFIG_DEBUG_INFO`` 编译的内核上使用gdb效果最好。可通过运行以下命令 +进行设置:: + + $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO + +在用 ``CONFIG_DEBUG_INFO`` 编译的内核上,你可以直接从OOPS复制EIP值:: + + EIP: 0060:[<c021e50e>] Not tainted VLI + +并使用GDB来将其翻译成可读形式:: + + $ gdb vmlinux + (gdb) l *0xc021e50e + +如果没有启用 ``CONFIG_DEBUG_INFO`` ,则使用OOPS的函数偏移:: + + EIP is at vt_ioctl+0xda8/0x1482 + +并在启用 ``CONFIG_DEBUG_INFO`` 的情况下重新编译内核:: + + $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO + $ make vmlinux + $ gdb vmlinux + (gdb) l *vt_ioctl+0xda8 + 0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293). + 288 { + 289 struct vc_data *vc = NULL; + 290 int ret = 0; + 291 + 292 console_lock(); + 293 if (VT_BUSY(vc_num)) + 294 ret = -EBUSY; + 295 else if (vc_num) + 296 vc = vc_deallocate(vc_num); + 297 console_unlock(); + +或者若您想要更详细的显示:: + + (gdb) p vt_ioctl + $1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl> + (gdb) l *0xae0+0xda8 + +您也可以使用对象文件作为替代:: + + $ make drivers/tty/ + $ gdb drivers/tty/vt/vt_ioctl.o + (gdb) l *vt_ioctl+0xda8 + +如果你有调用跟踪,类似:: + + Call Trace: + [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5 + [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e + [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee + ... + +这表明问题可能在 :jbd: 模块中。您可以在gdb中加载该模块并列出相关代码:: + + $ gdb fs/jbd/jbd.ko + (gdb) l *log_wait_commit+0xa3 + +.. note:: + + 您还可以对堆栈跟踪处的任何函数调用执行相同的操作,例如:: + + [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb] + + 上述调用发生的位置可以通过以下方式看到:: + + $ gdb drivers/media/usb/dvb-usb/dvb-usb.o + (gdb) l *dvb_usb_adapter_frontend_exit+0x3a + +objdump +^^^^^^^^ + +要调试内核,请使用objdump并从崩溃输出中查找十六进制偏移,以找到有效的代码/汇 +编行。如果没有调试符号,您将看到所示例程的汇编程序代码,但是如果内核有调试 +符号,C代码也将可见(调试符号可以在内核配置菜单的hacking项中启用)。例如:: + + $ objdump -r -S -l --disassemble net/dccp/ipv4.o + +.. note:: + + 您需要处于内核树的顶层以便此获得您的C文件。 + +如果您无法访问源代码,仍然可以使用以下方法调试一些崩溃转储(如Dave Miller的 +示例崩溃转储输出所示):: + + EIP is at +0x14/0x4c0 + ... + Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00 + 00 00 55 57 56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08 + <8b> 83 3c 01 00 00 89 44 24 14 8b 45 28 85 c0 89 44 24 18 0f 85 + + Put the bytes into a "foo.s" file like this: + + .text + .globl foo + foo: + .byte .... /* bytes from Code: part of OOPS dump */ + + Compile it with "gcc -c -o foo.o foo.s" then look at the output of + "objdump --disassemble foo.o". + + Output: + + ip_queue_xmit: + push %ebp + push %edi + push %esi + push %ebx + sub $0xbc, %esp + mov 0xd0(%esp), %ebp ! %ebp = arg0 (skb) + mov 0x8(%ebp), %ebx ! %ebx = skb->sk + mov 0x13c(%ebx), %eax ! %eax = inet_sk(sk)->opt + +`scripts/decodecode` 文件可以用来自动完成大部分工作,这取决于正在调试的CPU +体系结构。 + +报告缺陷 +--------- + +一旦你通过定位缺陷找到了其发生的地方,你可以尝试自己修复它或者向上游报告它。 + +为了向上游报告,您应该找出用于开发受影响代码的邮件列表。这可以使用 ``get_maintainer.pl`` 。 + + +例如,您在gspca的sonixj.c文件中发现一个缺陷,则可以通过以下方法找到它的维护者:: + + $ ./scripts/get_maintainer.pl -f drivers/media/usb/gspca/sonixj.c + Hans Verkuil <hverkuil@xs4all.nl> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%) + Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%) + Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%) + Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%) + linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER) + linux-kernel@vger.kernel.org (open list) + +请注意它将指出: + +- 最后接触源代码的开发人员(如果这是在git树中完成的)。在上面的例子中是Tejun + 和Bhaktipriya(在这个特定的案例中,没有人真正参与这个文件的开发); +- 驱动维护人员(Hans Verkuil); +- 子系统维护人员(Mauro Carvalho Chehab); +- 驱动程序和/或子系统邮件列表(linux-media@vger.kernel.org); +- Linux内核邮件列表(linux-kernel@vger.kernel.org)。 + +通常,修复缺陷的最快方法是将它报告给用于开发相关代码的邮件列表(linux-media +ML),抄送驱动程序维护者(Hans)。 + +如果你完全不知道该把报告寄给谁,且 ``get_maintainer.pl`` 也没有提供任何有用 +的信息,请发送到linux-kernel@vger.kernel.org。 + +感谢您的帮助,这使Linux尽可能稳定:-) + +修复缺陷 +--------- + +如果你懂得编程,你不仅可以通过报告错误来帮助我们,还可以提供一个解决方案。 +毕竟,开源就是分享你的工作,你不想因为你的天才而被认可吗? + +如果你决定这样做,请在制定解决方案后将其提交到上游。 + +请务必阅读 +:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` , +以帮助您的代码被接受。 + + +--------------------------------------------------------------------------- + +用 ``klogd`` 进行Oops跟踪的注意事项 +------------------------------------ + +为了帮助Linus和其他内核开发人员, ``klogd`` 对保护故障的处理提供了大量支持。 +为了完整支持地址解析,至少应该使用 ``sysklogd`` 包的1.3-pl3版本。 + +当发生保护故障时, ``klogd`` 守护进程会自动将内核日志消息中的重要地址转换为 +它们的等效符号。然后通过 ``klogd`` 使用的任何报告机制来转发这个已翻译的内核 +消息。保护错误消息可以直接从消息文件中剪切出来并转发给内核开发人员。 + +``klogd`` 执行两种类型的地址解析,静态翻译和动态翻译。静态翻译使用System.map +文件。为了进行静态转换, ``klogd`` 守护进程必须能够在守护进程初始化时找到系 +统映射文件。有关 ``klogd`` 如何搜索映射文件的信息,请参见klogd手册页。 + +当使用内核可加载模块时,动态地址转换非常重要。由于内核模块的内存是从内核的 +动态内存池中分配的,因此无论是模块的开头还是模块中的函数和符号都没有固定的 +位置。 + +内核支持系统调用,允许程序确定加载哪些模块及其在内存中的位置。klogd守护进程 +使用这些系统调用构建了一个符号表,可用于调试可加载内核模块中发生的保护错误。 + +klogd至少会提供产生保护故障的模块的名称。如果可加载模块的开发人员选择从模块 +导出符号信息,则可能会有其他可用的符号信息。 + +由于内核模块环境可以是动态的,因此当模块环境发生变化时,必须有一种通知 +``klogd`` 守护进程的机制。有一些可用的命令行选项允许klogd向当前正在执行的守 +护进程发出信号示意应该刷新符号信息。有关更多信息,请参阅 ``klogd`` 手册页。 + +sysklogd发行版附带了一个补丁,它修改了 ``modules-2.0.0`` 包,以便在加载或 +卸载模块时自动向klogd发送信号。应用此补丁基本上可无缝支持调试内核可加载模块 +发生的保护故障。 + +以下是 ``klogd`` 处理的可加载模块中的保护故障示例:: + + Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc + Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000 + Aug 29 09:51:01 blizard kernel: *pde = 00000000 + Aug 29 09:51:01 blizard kernel: Oops: 0002 + Aug 29 09:51:01 blizard kernel: CPU: 0 + Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868] + Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212 + Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c + Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c + Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018 + Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000) + Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001 + Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00 + Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036 + Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128] + Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3 + +--------------------------------------------------------------------------- + +:: + + Dr. G.W. Wettstein Oncology Research Div. Computing Facility + Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com + 820 4th St. N. + Fargo, ND 58122 + Phone: 701-234-7556 diff --git a/Documentation/translations/zh_CN/admin-guide/index.rst b/Documentation/translations/zh_CN/admin-guide/index.rst index 48bbd3ebad484fa15d68283ac796f1370f1de926..be835ec8e632a4115cc2f77ef2bab809625a5e0d 100644 --- a/Documentation/translations/zh_CN/admin-guide/index.rst +++ b/Documentation/translations/zh_CN/admin-guide/index.rst @@ -13,9 +13,13 @@ Linux 内核用户和管理员指南 这个初始部分包含总体信息,包括描述内核的README, 关于内核参数的文档等。 -Todolist: +.. toctree:: + :maxdepth: 1 README + +Todolist: + kernel-parameters devices sysctl/index @@ -28,16 +32,21 @@ Todolist: 下面的一组文档,针对的是试图跟踪问题和bug的用户。 -Todolist: +.. toctree:: + :maxdepth: 1 - reporting-bugs + reporting-issues security-bugs bug-hunting bug-bisect tainted-kernels + init + +Todolist: + + reporting-bugs ramoops dynamic-debug-howto - init kdump/index perf/index @@ -56,6 +65,7 @@ Todolist: clearing-warn-once cpu-load + unicode Todolist: @@ -111,7 +121,6 @@ Todolist: sysrq thunderbolt ufs - unicode vga-softcursor video-output xfs diff --git a/Documentation/translations/zh_CN/admin-guide/init.rst b/Documentation/translations/zh_CN/admin-guide/init.rst new file mode 100644 index 0000000000000000000000000000000000000000..fbaf6d97f86c9931950657ede64c7b0b75b21931 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/init.rst @@ -0,0 +1,54 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../admin-guide/init` + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +解释“No working init found.”启动挂起消息 +========================================= + +:作者: + + Andreas Mohr <andi at lisas period de> + + Cristian Souza <cristianmsbr at gmail period com> + +本文档提供了加载初始化二进制(init binary)失败的一些高层级原因(大致按执行 +顺序列出)。 + +1) **无法挂载根文件系统Unable to mount root FS** :请设置“debug”内核参数(在 + 引导加载程序bootloader配置文件或CONFIG_CMDLINE)以获取更详细的内核消息。 + +2) **初始化二进制不存在于根文件系统上init binary doesn't exist on rootfs** : + 确保您的根文件系统类型正确(并且 ``root=`` 内核参数指向正确的分区);拥有 + 所需的驱动程序,例如SCSI或USB等存储硬件;文件系统(ext3、jffs2等)是内建的 + (或者作为模块由initrd预加载)。 + +3) **控制台设备损坏Broken console device** : ``console= setup`` 中可能存在 + 冲突 --> 初始控制台不可用(initial console unavailable)。例如,由于串行 + IRQ问题(如缺少基于中断的配置)导致的某些串行控制台不可靠。尝试使用不同的 + ``console= device`` 或像 ``netconsole=`` 。 + +4) **二进制存在但依赖项不可用Binary exists but dependencies not available** : + 例如初始化二进制的必需库依赖项,像 ``/lib/ld-linux.so.2`` 丢失或损坏。使用 + ``readelf -d <INIT>|grep NEEDED`` 找出需要哪些库。 + +5) **无法加载二进制Binary cannot be loaded** :请确保二进制的体系结构与您的 + 硬件匹配。例如i386不匹配x86_64,或者尝试在ARM硬件上加载x86。如果您尝试在 + 此处加载非二进制文件(shell脚本?),您应该确保脚本在其工作头(shebang + header)行 ``#!/...`` 中指定能正常工作的解释器(包括其库依赖项)。在处理 + 脚本之前,最好先测试一个简单的非脚本二进制文件,比如 ``/bin/sh`` ,并确认 + 它能成功执行。要了解更多信息,请将代码添加到 ``init/main.c`` 以显示 + kernel_execve()的返回值。 + +当您发现新的失败原因时,请扩展本解释(毕竟加载初始化二进制是一个 **关键** 且 +艰难的过渡步骤,需要尽可能无痛地进行),然后向LKML提交一个补丁。 + +待办事项: + +- 通过一个可以存储 ``kernel_execve()`` 结果值的结构体数组实现各种 + ``run_init_process()`` 调用,并在失败时通过迭代 **所有** 结果来记录一切 + (非常重要的可用性修复)。 +- 试着使实现本身在一般情况下更有帮助,例如在受影响的地方提供额外的错误消息。 diff --git a/Documentation/translations/zh_CN/admin-guide/reporting-issues.rst b/Documentation/translations/zh_CN/admin-guide/reporting-issues.rst new file mode 100644 index 0000000000000000000000000000000000000000..6b4988da2c5a8cc50a81d88956dbb340e2fc7a97 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/reporting-issues.rst @@ -0,0 +1,1335 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0) +.. + If you want to distribute this text under CC-BY-4.0 only, please use 'The + Linux kernel developers' for author attribution and link this as source: + https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/admin-guide/reporting-issues.rst +.. + Note: Only the content of this RST file as found in the Linux kernel sources + is available under CC-BY-4.0, as versions of this text that were processed + (for example by the kernel's build system) might contain content taken from + files which use a more restrictive license. + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/admin-guide/reporting-issues.rst + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + + +报告问题 ++++++++++ + + +简明指南(亦即 太长不看) +========================== + +您面临的是否为同系列稳定版或长期支持内核的普通内核的回归?是否仍然受支持? +请搜索 `LKML内核邮件列表 <https://lore.kernel.org/lkml/>`_ 和 +`Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 存档中匹配的报告并 +加入讨论。如果找不到匹配的报告,请安装该系列的最新版本。如果它仍然出现问题, +报告给稳定版邮件列表(stable@vger.kernel.org)。 + +在所有其他情况下,请尽可能猜测是哪个内核部分导致了问题。查看MAINTAINERS文件, +了解开发人员希望如何得知问题,大多数情况下,报告问题都是通过电子邮件和抄送 +相关邮件列表进行的。检查报告目的地的存档中是否已有匹配的报告;也请搜索 +`LKML <https://lore.kernel.org/lkml/>`_ 和网络。如果找不到可加入的讨论,请 +安装 `最新的主线内核 <https://kernel.org/>`_ 。如果仍存在问题,请发送报告。 + +问题已经解决了,但是您希望看到它在一个仍然支持的稳定版或长期支持系列中得到 +解决?请安装其最新版本。如果它出现了问题,那么在主线中搜索修复它的更改,并 +检查是否正在回传(backporting)或者已放弃;如果两者都没有,那么可询问处理 +更改的人员。 + +**通用提醒** :当安装和测试上述内核时,请确保它是普通的(即:没有补丁,也没 +有使用附加模块)。还要确保它是在一个正常的环境中构建和运行,并且在问题发生 +之前没有被污染(tainted)。 + +在编写报告时,要涵盖与问题相关的所有信息,如使用的内核和发行版。在碰见回归时, +尝试给出引入它的更改的提交ID,二分可以找到它。如果您同时面临Linux内核的多个 +问题,请分别报告每个问题。 + +一旦报告发出,请回答任何出现的问题,并尽可能地提供帮助。这包括通过不时重新 +测试新版本并发送状态更新来推动进展。 + + +如何向内核维护人员报告问题的逐步指南 +===================================== + +上面的简明指南概述了如何向Linux内核开发人员报告问题。对于已经熟悉向自由和开 +源软件(FLOSS)项目报告问题的人来说,这可能是他们所需要的全部内容。对于其他 +人,本部分更为详细,并一步一步地描述。为了便于阅读,它仍然尽量简洁,并省略 +了许多细节;这些在逐步指南后的参考章节中进行了描述,该章节更详细地解释了每 +个步骤。 + +注意:本节涉及的方面比简明指南多,顺序也稍有不同。这符合你的利益,以确保您 +尽早意识到看起来像Linux内核毛病的问题可能实际上是由其他原因引起的。这些步骤 +可以确保你最终不会觉得在这一过程中投入的时间是浪费: + + * 您是否面临硬件或软件供应商提供的Linux内核的问题?那么基本上您最好停止阅读 + 本文档,转而向您的供应商报告问题,除非您愿意自己安装最新的Linux版本。寻找 + 和解决问题往往需要后者。 + + * 使用您喜爱的网络搜索引擎对现有报告进行粗略搜索;此外,请检查 + `Linux内核邮件列表(LKML) <https://lore.kernel.org/lkml/>`_ 的存档。如果 + 找到匹配的报告,请加入讨论而不是发送新报告。 + + * 看看你正在处理的问题是否为回归问题、安全问题或非常严重的问题:这些都是需 + 要在接下来的一些步骤中特别处理的“高优先级问题”。 + + * 确保不是内核环境导致了您面临的问题。 + + * 创建一个新的备份,并将系统修复和恢复工具放在手边。 + + * 确保您的系统不会通过动态构建额外的内核模块来增强其内核,像DKMS这样的解决 + 方案可能在您不知情的情况下就在本地进行了这样的工作。 + + * 当问题发生时,检查您的内核是否被“污染”,因为使内核设置这个标志的事件可能 + 会导致您面临的问题。 + + * 粗略地写下如何重现这个问题。如果您同时处理多个问题,请为每个问题单独写注 + 释,并确保它们在新启动的系统上独立出现。这是必要的,因为每个问题都需要分 + 别报告给内核开发人员,除非它们严重纠缠在一起。 + + * 如果您正面临稳定版或长期支持版本线的回归(例如从5.10.4更新到5.10.5时出现 + 故障),请查看后文“报告稳定版和长期支持内核线的回归”小节。 + + * 定位可能引起问题的驱动程序或内核子系统。找出其开发人员期望的报告的方式和 + 位置。注意:大多数情况下不会是 bugzilla.kernel.org,因为问题通常需要通 + 过邮件发送给维护人员和公共邮件列表。 + + * 在缺陷追踪器或问题相关邮件列表的存档中彻底搜索可能与您的问题匹配的报告。 + 如果你发现了一些相关讨论,请加入讨论而不是发送新的报告。 + +在完成这些准备之后,你将进入主要部分: + + * 除非您已经在运行最新的“主线”Linux内核,否则最好在报告流程前安装它。在某些 + 情况下,使用最新的“稳定版”Linux进行测试和报告也是可以接受的替代方案;在 + 合并窗口期间,这实际上可能是最好的方法,但在开发阶段最好还是暂停几天。无论 + 你选择什么版本,最好使用“普通”构建。忽略这些建议会大大增加您的报告被拒绝 + 或忽略的风险。 + + * 确保您刚刚安装的内核在运行时不会“污染”自己。 + + * 在您刚刚安装的内核中复现这个问题。如果它没有出现,请查看下方只发生在 + 稳定版和长期支持内核的问题的说明。 + + * 优化你的笔记:试着找到并写出最直接的复现问题的方法。确保最终结果包含所有 + 重要的细节,同时让第一次听说的人容易阅读和理解。如果您在此过程中学到了一 + 些东西,请考虑再次搜索关于该问题的现有报告。 + + * 如果失败涉及“panic”、“Oops”、“warning”或“BUG”,请考虑解码内核日志以查找触 + 发错误的代码行。 + + * 如果您的问题是回归问题,请尽可能缩小引入问题时的范围。 + + * 通过详细描述问题来开始编写报告。记得包括以下条目:您为复现而安装的最新内 + 核版本、使用的Linux发行版以及关于如何复现该问题的说明。如果可能,将内核 + 构建配置(.config)和 ``dmesg`` 的输出放在网上的某个地方,并链接到它。包 + 含或上传所有其他可能相关的信息,如Oops的输出/截图或来自 ``lspci`` 的输出 + 。一旦你写完了这个主要部分,请在上方插入一个正常长度的段落快速概述问题和 + 影响。再在此之上添加一个简单描述问题的句子,以得到人们的阅读。现在给出一 + 个更短的描述性标题或主题。然后就可以像MAINTAINERS文件告诉你的那样发送或 + 提交报告了,除非你在处理一个“高优先级问题”:它们需要按照下面“高优先级问 + 题的特殊处理”所述特别关照。 + + * 等待别人的反应,继续推进事情,直到你能够接受这样或那样的结果。因此,请公 + 开和及时地回应任何询问。测试提出的修复。积极地测试:至少重新测试每个新主 + 线版本的首个候选版本(RC),并报告你的结果。如果出现拖延,就友好地提醒一 + 下。如果你没有得到任何帮助或者未能满意,请试着自己帮助自己。 + + +报告稳定版和长期支持内核线的回归 +---------------------------------- + +如果您发现了稳定版或长期支持内核版本线中的回归问题并按上述流程跳到这里,那么 +请阅读本小节。即例如您在从5.10.4更新到5.10.5时出现了问题(从5.9.15到5.10.5则 +不是)。开发人员希望尽快修复此类回归,因此有一个简化流程来报告它们: + + * 检查内核开发人员是否仍然维护你关心的Linux内核版本线:去 `kernel.org 的首页 + <https://kernel.org/>`_ ,确保此特定版本线的最新版没有“[EOL]”标记。 + + * 检查 `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 中的现有报告。 + + * 从特定的版本线安装最新版本作为纯净内核。确保这个内核没有被污染,并且仍然 + 存在问题,因为问题可能已经在那里被修复了。如果您第一次发现供应商内核的问题, + 请检查已知最新版本的普通构建是否可以正常运行。 + + * 向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)。大致 + 描述问题,并解释如何复现。讲清楚首个出现问题的版本和最后一个工作正常的版本。 + 然后等待进一步的指示。 + +下面的参考章节部分详细解释了这些步骤中的每一步。 + + +报告只发生在较旧内核版本线的问题 +---------------------------------- + +若您尝试了上述的最新主线内核,但未能在那里复现问题,那么本小节适用于您;以下 +流程有助于使问题在仍然支持的稳定版或长期支持版本线,或者定期基于最新稳定版或 +长期支持内核的供应商内核中得到修复。如果是这种情况,请执行以下步骤: + + * 请做好准备,接下来的几个步骤可能无法在旧版本中解决问题:修复可能太大或太 + 冒险,无法移植到那里。 + + * 执行前节“报告稳定版和长期支持内核线的回归”中的前三个步骤。 + + * 在Linux内核版本控制系统中搜索修复主线问题的更改,因为它的提交消息可能会 + 告诉你修复是否已经计划好了支持。如果你没有找到,搜索适当的邮件列表,寻找 + 讨论此类问题或同行评议可能修复的帖子;然后检查讨论是否认为修复不适合支持。 + 如果支持根本不被考虑,加入最新的讨论,询问是否有可能。 + + * 前面的步骤之一应该会给出一个解决方案。如果仍未能成功,请向可能引起问题的 + 子系统的维护人员询问建议;抄送特定子系统的邮件列表以及稳定版邮件列表 + +下面的参考章节部分详细解释了这些步骤中的每一步。 + + +参考章节:向内核维护者报告问题 +=============================== + +上面的详细指南简要地列出了所有主要步骤,这对大多数人来说应该足够了。但有时, +即使是有经验的用户也可能想知道如何实际执行这些步骤之一。这就是本节的目的, +因为它将提供关于上述每个步骤的更多细节。请将此作为参考文档:可以从头到尾 +阅读它。但它主要是为了浏览和查找如何实际执行这些步骤的详细信息。 + +在深入挖掘细节之前,我想先给你一些一般性建议: + + * Linux内核开发人员很清楚这个过程很复杂,比其他的FLOSS项目要求更多。我们很 + 希望让它更简单。但这需要在不同的地方以及一些基础设施上付诸努力,这些基础 + 设施需要持续的维护;尚未有人站出来做这些工作,所以目前情况就是这样。 + + * 与某些供应商签订的保证或支持合同并不能使您有权要求上游Linux内核社区的开 + 发人员进行修复:这样的合同完全在Linux内核、其开发社区和本文档的范围之外。 + 这就是为什么在这种情况下,你不能要求任何契约保证,即使开发人员处理的问 + 题对供应商有效。如果您想主张您的权利,使用供应商的支持渠道代替。当这样做 + 的时候,你可能想提出你希望看到这个问题在上游Linux内核中修复;可以这是确 + 保最终修复将被纳入所有Linux发行版的唯一方法来鼓励他们。 + + * 如果您从未向FLOSS项目报告过任何问题,那么您应该考虑阅读 `如何有效地报告 + 缺陷 <https://www.chiark.greenend.org.uk/~sgtatham/bugs.html>`_ , `如何 + 以明智的方式提问 <http://www.catb.org/esr/faqs/smart-questions.html>`_ , + 和 `如何提出好问题 <https://jvns.ca/blog/good-questions/>`_ 。 + +解决这些问题之后,可以在下面找到如何正确地向Linux内核报告问题的详细信息。 + + +确保您使用的是上游Linux内核 +---------------------------- + + *您是否面临硬件或软件供应商提供的Linux内核的问题?那么基本上您最好停止阅 + 读本文档,转而向您的供应商报告问题,除非您愿意自己安装最新的Linux版本。 + 寻找和解决问题往往需要后者。* + +与大多数程序员一样,Linux内核开发人员不喜欢花时间处理他们维护的源代码中根本 +不会发生的问题的报告。这只会浪费每个人的时间,尤其是你的时间。不幸的是,当 +涉及到内核时,这样的情况很容易发生,并且常常导致双方气馁。这是因为几乎所有预 +装在设备(台式机、笔记本电脑、智能手机、路由器等)上的Linux内核,以及大多数 +由Linux发行商提供的内核,都与由kernel.org发行的官方Linux内核相距甚远:从Linux +开发的角度来看,这些供应商提供的内核通常是古老的或者经过了大量修改,通常两点 +兼具。 + +大多数供应商内核都不适合用来向Linux内核开发人员报告问题:您在其中遇到的问题 +可能已经由Linux内核开发人员在数月或数年前修复;此外,供应商的修改和增强可能 +会导致您面临的问题,即使它们看起来很小或者完全不相关。这就是为什么您应该向 +供应商报告这些内核的问题。它的开发者应该查看报告,如果它是一个上游问题,直接 +于上游修复或将报告转发到那里。在实践中,这有时行不通。因此,您可能需要考虑 +通过自己安装最新的Linux内核内核来绕过供应商。如果如果您选择此方法,那么本指 +南后面的步骤将解释如何在排除了其他可能导致您的问题的原因后执行此操作。 + +注意前段使用的词语是“大多数”,因为有时候开发人员实际上愿意处理供应商内核出现 +的问题报告。他们是否这么做很大程度上取决于开发人员和相关问题。如果发行版只 +根据最近的Linux版本对内核进行了较小修改,那么机会就比较大;例如对于Debian +GNU/Linux Sid或Fedora Rawhide所提供的主线内核。一些开发人员还将接受基于最新 +稳定内核的发行版内核问题报告,只要它改动不大;例如Arch Linux、常规Fedora版本 +和openSUSE Turboweed。但是请记住,您最好使用主线Linux,并避免在此流程中使用 +稳定版内核,如“安装一个新的内核进行测试”一节中所详述。 + +当然,您可以忽略所有这些建议,并向上游Linux开发人员报告旧的或经过大量修改的 +供应商内核的问题。但是注意,这样的报告经常被拒绝或忽视,所以自行小心考虑一下。 +不过这还是比根本不报告问题要好:有时候这样的报告会直接或间接地帮助解决之后的 +问题。 + + +搜索现有报告(第一部分) +------------------------- + + *使用您喜爱的网络搜索引擎对现有报告进行粗略搜索;此外,请检查Linux内核 + 邮件列表(LKML)的存档。如果找到匹配的报告,请加入讨论而不是发送新报告。* + +报告一个别人已经提出的问题,对每个人来说都是浪费时间,尤其是作为报告人的你。 +所以彻底检查是否有人已经报告了这个问题,这对你自己是有利的。在流程中的这一步, +可以只执行一个粗略的搜索:一旦您知道您的问题需要报告到哪里,稍后的步骤将告诉 +您如何详细搜索。尽管如此,不要仓促完成这一步,它可以节省您的时间和减少麻烦。 + +只需先用你最喜欢的搜索引擎在互联网上搜索。然后再搜索Linux内核邮件列表(LKML) +存档。 + +如果搜索结果实在太多,可以考虑让你的搜索引擎将搜索时间范围限制在过去的一个 +月或一年。而且无论你在哪里搜索,一定要用恰当的搜索关键词;也要变化几次关键 +词。同时,试着从别人的角度看问题:这将帮助你想出其他的关键词。另外,一定不 +要同时使用过多的关键词。记住搜索时要同时尝试包含和不包含内核驱动程序的名称 +或受影响的硬件组件的名称等信息。但其确切的品牌名称(比如说“华硕红魔 Radeon +RX 5700 XT Gaming OC”)往往帮助不大,因为它太具体了。相反,尝试搜索术语,如 +型号(Radeon 5700 或 Radeon 5000)和核心代号(“Navi”或“Navi10”),以及包含 +和不包含其制造商(“AMD”)。 + +如果你发现了关于你的问题的现有报告,请加入讨论,因为你可能会提供有价值的额 +外信息。这一点很重要,即使是在修复程序已经准备好或处于最后阶段,因为开发人 +员可能会寻找能够提供额外信息或测试建议修复程序的人。跳到“发布报告后的责任” +一节,了解有关如何正确参与的细节。 + +注意,搜索 `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 网站可能 +也是一个好主意,因为这可能会提供有价值的见解或找到匹配的报告。如果您发现后者, +请记住:大多数子系统都希望在不同的位置报告,如下面“你需要将问题报告到何处” +一节中所述。因此本应处理这个问题的开发人员甚至可能不知道bugzilla的工单。所以 +请检查工单中的问题是否已经按照本文档所述得到报告,如果没有,请考虑这样做。 + +高优先级的问题? +----------------- + + *看看你正在处理的问题是否是回归问题、安全问题或非常严重的问题:这些都是 + 需要在接下来的一些步骤中特别处理的“高优先级问题”。* + +Linus Torvalds和主要的Linux内核开发人员希望看到一些问题尽快得到解决,因此在 +报告过程中有一些“高优先级问题”的处理略有不同。有三种情况符合条件:回归、安全 +问题和非常严重的问题。 + +如果在旧版本的Linux内核中工作的东西不能在新版本的Linux内核中工作,或者某种 +程度上在新版本的Linux内核中工作得更差,那么你就需要处理“回归”。因此,当一个 +在Linux 5.7中表现良好的WiFi驱动程序在5.8中表现不佳或根本不能工作时,这是一 +种回归。如果应用程序在新的内核中出现不稳定的现象,这也是一种回归,这可能是 +由于内核和用户空间之间的接口(如procfs和sysfs)发生不兼容的更改造成的。显著 +的性能降低或功耗增加也可以称为回归。但是请记住:新内核需要使用与旧内核相似的 +配置来构建(参见下面如何实现这一点)。这是因为内核开发人员在实现新特性时有 +时无法避免不兼容性;但是为了避免回归,这些特性必须在构建配置期间显式地启用。 + +什么是安全问题留给您自己判断。在继续之前,请考虑阅读 +“Documentation/translations/zh_CN/admin-guide/security-bugs.rst”, +因为它提供了如何最恰当地处理安全问题的额外细节。 + +当发生了完全无法接受的糟糕事情时,此问题就是一个“非常严重的问题”。例如, +Linux内核破坏了它处理的数据或损坏了它运行的硬件。当内核突然显示错误消息 +(“kernel panic”)并停止工作,或者根本没有任何停止信息时,您也在处理一个严重 +的问题。注意:不要混淆“panic”(内核停止自身的致命错误)和“Oops”(可恢复错误), +因为显示后者之后内核仍然在运行。 + + +确保环境健康 +-------------- + + *确保不是内核所处环境导致了你所面临的问题。* + +看起来很像内核问题的问题有时是由构建或运行时环境引起的。很难完全排除这种问 +题,但你应该尽量减少这种问题: + + * 构建内核时,请使用经过验证的工具,因为编译器或二进制文件中的错误可能会导 + 致内核出现错误行为。 + + * 确保您的计算机组件在其设计规范内运行;这对处理器、内存和主板尤为重要。因 + 此,当面临潜在的内核问题时,停止低电压或超频。 + + * 尽量确保不是硬件故障导致了你的问题。例如,内存损坏会导致大量的问题,这些 + 问题会表现为看起来像内核问题。 + + * 如果你正在处理一个文件系统问题,你可能需要用 ``fsck`` 检查一下文件系统, + 因为它可能会以某种方式被损坏,从而导致无法预期的内核行为。 + + * 在处理回归问题时,要确保没有在更新内核的同时发生了其他变化。例如,这个问 + 题可能是由同时更新的其他软件引起的。也有可能是在你第一次重启进入新内核时, + 某个硬件巧合地坏了。更新系统 BIOS 或改变 BIOS 设置中的某些内容也会导致 + 一些看起来很像内核回归的问题。 + + +为紧急情况做好准备 +------------------- + + *创建一个全新的备份,并将系统修复和还原工具放在手边* + +我得提醒您,您正在和计算机打交道,计算机有时会出现意想不到的事情,尤其是当 +您折腾其操作系统的内核等关键部件时。而这就是你在这个过程中要做的事情。因此, +一定要创建一个全新的备份;还要确保你手头有修复或重装操作系统的所有工具, +以及恢复备份所需的一切。 + + +确保你的内核不会被增强 +------------------------ + + *确保您的系统不会通过动态构建额外的内核模块来增强其内核,像DKMS这样的解 + 决方案可能在您不知情的情况下就在本地进行了这样的工作。* + +如果内核以任何方式得到增强,那么问题报告被忽略或拒绝的风险就会急剧增加。这就 +是为什么您应该删除或禁用像akmods和DKMS这样的机制:这些机制会自动构建额外内核 +模块,例如当您安装新的Linux内核或第一次引导它时。也要记得同时删除他们可能安装 +的任何模块。然后重新启动再继续。 + +注意,你可能不知道你的系统正在使用这些解决方案之一:当你安装 Nvidia 专有图 +形驱动程序、VirtualBox 或其他需要 Linux 内核以外的模块支持的软件时,它们通 +常会静默设置。这就是为什么你可能需要卸载这些软件的软件包,以摆脱任何第三方 +内核模块。 + + +检查“污染”标志 +---------------- + + *当问题发生时,检查您的内核是否被“污染”,因为使内核设置这个标志的事件可 + 能会导致您面临的问题。* + +当某些可能会导致看起来完全不相关的后续错误的事情发生时,内核会用“污染 +(taint)”标志标记自己。如果您的内核受到污染,那么您面临的可能是这样的错误。 +因此在投入更多时间到这个过程中之前,尽早排除此情况可能对你有好处。这是这个 +步骤出现在这里的唯一原因,因为这个过程稍后会告诉您安装最新的主线内核;然后 +您将需要再次检查污染标志,因为当它出问题的时候内核报告会关注它。 + +在正在运行的系统上检查内核是否污染非常容易:如果 ``cat /proc/sys/kernel/tainted`` +返回“0”,那么内核没有被污染,一切正常。在某些情况下无法检查该文件;这就是 +为什么当内核报告内部问题(“kernel bug”)、可恢复错误(“kernel Oops”)或停止 +操作前不可恢复的错误(“kernel panic”)时,它也会提到污染状态。当其中一个错 +误发生时,查看打印的错误消息的顶部,搜索以“CPU:”开头的行。如果发现问题时内 +核未被污染,那么它应该以“Not infected”结束;如果你看到“Tainted:”且后跟一些 +空格和字母,那就被污染了。 + +如果你的内核被污染了,请阅读“Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst” +以找出原因。设法消除污染因素。通常是由以下三种因素之一引起的: + + 1. 发生了一个可恢复的错误(“kernel Oops”),内核污染了自己,因为内核知道在 + 此之后它可能会出现奇怪的行为错乱。在这种情况下,检查您的内核或系统日志, + 并寻找以下列文字开头的部分:: + + Oops: 0000 [#1] SMP + + 如方括号中的“#1”所示,这是自启动以来的第一次Oops。每个Oops和此后发生的 + 任何其他问题都可能是首个Oops的后续问题,即使这两个问题看起来完全不相关。 + 通过消除首个Oops的原因并在之后复现该问题,可以排除这种情况。有时仅仅 + 重新启动就足够了,有时更改配置后重新启动可以消除Oops。但是在这个流程中 + 不要花费太多时间在这一点上,因为引起Oops的原因可能已经在您稍后将按流程 + 安装的新Linux内核版本中修复了。 + + 2. 您的系统使用的软件安装了自己的内核模块,例如Nvidia的专有图形驱动程序或 + VirtualBox。当内核从外部源(即使它们是开源的)加载此类模块时,它会污染 + 自己:它们有时会在不相关的内核区域导致错误,从而可能导致您面临的问题。 + 因此,当您想要向Linux内核开发人员报告问题时,您必须阻止这些模块加载。 + 大多数情况下最简单的方法是:临时卸载这些软件,包括它们可能已经安装的任 + 何模块。之后重新启动。 + + 3. 当内核加载驻留在Linux内核源代码staging树中的模块时,它也会污染自身。这 + 是一个特殊的区域,代码(主要是驱动程序)还没有达到正常Linux内核的质量 + 标准。当您报告此种模块的问题时,内核受到污染显然是没有问题的;只需确保 + 问题模块是造成污染的唯一原因。如果问题发生在一个不相关的区域,重新启动 + 并通过指定 ``foo.blacklist=1`` 作为内核参数临时阻止该模块被加载(用有 + 问题的模块名替换“foo”)。 + + +记录如何重现问题 +------------------ + + *粗略地写下如何重现这个问题。如果您同时处理多个问题,请为每个问题单独写 + 注释,并确保它们在新启动的系统上独立出现。这是必要的,因为每个问题都需 + 要分别报告给内核开发人员,除非它们严重纠缠在一起。* + +如果你同时处理多个问题,必须分别报告每个问题,因为它们可能由不同的开发人员 +处理。在一份报告中描述多种问题,也会让其他人难以将其分开。因此只有在问题严 +重纠缠的情况下,才能将问题合并在一份报告中。 + +此外,在报告过程中,你必须测试该问题是否发生在其他内核版本上。因此,如果您 +知道如何在一个新启动的系统上快速重现问题,将使您的工作更加轻松。 + +注意:报告只发生过一次的问题往往是没有结果的,因为它们可能是由于宇宙辐射导 +致的位翻转。所以你应该尝试通过重现问题来排除这种情况,然后再继续。如果你有 +足够的经验来区分由于硬件故障引起的一次性错误和难以重现的罕见内核问题,可以 +忽略这个建议。 + + +稳定版或长期支持内核的回归? +----------------------------- + + *如果您正面临稳定版或长期支持版本线的回归(例如从5.10.4更新到5.10.5时出现 + 故障),请查看后文“报告稳定版和长期支持内核线的回归”小节。* + +稳定版和长期支持内核版本线中的回归是Linux开发人员非常希望解决的问题,这样的 +问题甚至比主线开发分支中的回归更不应出现,因为它们会很快影响到很多人。开发人员 +希望尽快了解此类问题,因此有一个简化流程来报告这些问题。注意,使用更新内核版 +本线的回归(比如从5.9.15切换到5.10.5时出现故障)不符合条件。 + + +你需要将问题报告到何处 +------------------------ + + *定位可能引起问题的驱动程序或内核子系统。找出其开发人员期望的报告的方式 + 和位置。注意:大多数情况下不会是bugzilla.kernel.org,因为问题通常需要通 + 过邮件发送给维护人员和公共邮件列表。* + +将报告发送给合适的人是至关重要的,因为Linux内核是一个大项目,大多数开发人员 +只熟悉其中的一小部分。例如,相当多的程序员只关心一个驱动程序,比如一个WiFi +芯片驱动程序;它的开发人员可能对疏远的或不相关的“子系统”(如TCP堆栈、 +PCIe/PCI子系统、内存管理或文件系统)的内部知识了解很少或完全不了解。 + +问题在于:Linux内核缺少一个,可以简单地将问题归档并让需要了解它的开发人员了 +解它的,中心化缺陷跟踪器。这就是为什么你必须找到正确的途径来自己报告问题。 +您可以在脚本的帮助下做到这一点(见下文),但它主要针对的是内核开发人员和专 +家。对于其他人来说,MAINTAINERS(维护人员)文件是更好的选择。 + +如何阅读MAINTAINERS维护者文件 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +为了说明如何使用 :ref:`MAINTAINERS <maintainers>` 文件,让我们假设您的笔记 +本电脑中的WiFi在更新内核后突然出现了错误行为。这种情况下可能是WiFi驱动的问 +题。显然,它也可能由于驱动基于的某些代码,但除非你怀疑有这样的东西会附着在 +驱动程序上。如果真的是其他的问题,驱动程序的开发人员会让合适的人参与进来。 + +遗憾的是,没有通用且简单的办法来检查哪个代码驱动了特定硬件组件。 + +在WiFi驱动出现问题的情况下,你可能想查看 ``lspci -k`` 的输出,因为它列出了 +PCI/PCIe总线上的设备和驱动它的内核模块:: + + [user@something ~]$ lspci -k + [...] + 3a:00.0 Network controller: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter (rev 32) + Subsystem: Bigfoot Networks, Inc. Device 1535 + Kernel driver in use: ath10k_pci + Kernel modules: ath10k_pci + [...] + +但如果你的WiFi芯片通过USB或其他内部总线连接,这种方法就行不通了。在这种情况 +下,您可能需要检查您的WiFi管理器或 ``ip link`` 的输出。寻找有问题的网络接口 +的名称,它可能类似于“wlp58s0”。此名称可以用来找到驱动它的模块:: + + [user@something ~]$ realpath --relative-to=/sys/module//sys/class/net/wlp58s0/device/driver/module + ath10k_pci + +如果这些技巧不能进一步帮助您,请尝试在网上搜索如何缩小相关驱动程序或子系统 +的范围。如果你不确定是哪一个:试着猜一下,即使你猜得不好,也会有人会帮助你 +的。 + +一旦您知道了相应的驱动程序或子系统,您就希望在MAINTAINERS文件中搜索它。如果 +是“ath10k_pci”,您不会找到任何东西,因为名称太具体了。有时你需要在网上寻找 +帮助;但在此之前,请尝试使用一个稍短或修改过的名称来搜索MAINTAINERS文件,因 +为这样你可能会发现类似这样的东西:: + + QUALCOMM ATHEROS ATH10K WIRELESS DRIVER + Mail: A. Some Human <shuman@example.com> + Mailing list: ath10k@lists.infradead.org + Status: Supported + Web-page: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k + SCM: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git + Files: drivers/net/wireless/ath/ath10k/ + +注意:如果您阅读在Linux源代码树的根目录中找到的原始维护者文件,则行描述将是 +缩写。例如,“Mail:(邮件)”将是“M:”,“Mailing list:(邮件列表)”将是“L”, +“Status:(状态)”将是“S:”。此文件顶部有一段解释了这些和其他缩写。 + +首先查看“Status”状态行。理想情况下,它应该得到“Supported(支持)”或 +“Maintained(维护)”。如果状态为“Obsolete(过时的)”,那么你在使用一些过时的 +方法,需要转换到新的解决方案上。有时候,只有在感到有动力时,才会有人为代码 +提供“Odd Fixes”。如果碰见“Orphan”,你就完全不走运了,因为再也没有人关心代码 +了,只剩下这些选项:准备好与问题共存,自己修复它,或者找一个愿意修复它的程序员。 + +检查状态后,寻找以“bug:”开头的一行:它将告诉你在哪里可以找到子系统特定的缺 +陷跟踪器来提交你的问题。上面的例子没有此行。大多数部分都是这样,因为 Linux +内核的开发完全是由邮件驱动的。很少有子系统使用缺陷跟踪器,且其中只有一部分 +依赖于 bugzilla.kernel.org。 + +在这种以及其他很多情况下,你必须寻找以“Mail:”开头的行。这些行提到了特定代码 +的维护者的名字和电子邮件地址。也可以查找以“Mailing list:”开头的行,它告诉你 +开发代码的公共邮件列表。你的报告之后需要通过邮件发到这些地址。另外,对于所有 +通过电子邮件发送的问题报告,一定要抄送 Linux Kernel Mailing List(LKML) +<linux-kernel@vger.kernel.org>。在以后通过邮件发送问题报告时,不要遗漏任何 +一个邮件列表!维护者都是大忙人,可能会把一些工作留给子系统特定列表上的其他开 +发者;而 LKML 很重要,因为需要一个可以找到所有问题报告的地方。 + + +借助脚本找到维护者 +~~~~~~~~~~~~~~~~~~~~ + +对于手头有Linux源码的人来说,有第二个可以找到合适的报告地点的选择:脚本 +“scripts/get_maintainer.pl”,它尝试找到所有要联系的人。它会查询MAINTAINERS +文件,并需要用相关源代码的路径来调用。对于编译成模块的驱动程序,经常可以用 +这样的命令找到:: + + $ modinfo ath10k_pci | grep filename | sed 's!/lib/modules/.*/kernel/!!; s!filename:!!; s!\.ko\(\|\.xz\)!!' + drivers/net/wireless/ath/ath10k/ath10k_pci.ko + +将其中的部分内容传递给脚本:: + + $ ./scripts/get_maintainer.pl -f drivers/net/wireless/ath/ath10k* + Some Human <shuman@example.com> (supporter:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER) + Another S. Human <asomehuman@example.com> (maintainer:NETWORKING DRIVERS) + ath10k@lists.infradead.org (open list:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER) + linux-wireless@vger.kernel.org (open list:NETWORKING DRIVERS (WIRELESS)) + netdev@vger.kernel.org (open list:NETWORKING DRIVERS) + linux-kernel@vger.kernel.org (open list) + +不要把你的报告发给所有的人。发送给维护者,脚本称之为“supporter:”;另外抄送 +代码最相关的邮件列表,以及 Linux 内核邮件列表(LKML)。在此例中,你需要将报 +告发送给 “Some Human <shuman@example.com>” ,并抄送 +“ath10k@lists.infradead.org”和“linux-kernel@vger.kernel.org”。 + +注意:如果你用 git 克隆了 Linux 源代码,你可能需要用--git 再次调用 +get_maintainer.pl。脚本会查看提交历史,以找到最近哪些人参与了相关代码的编写, +因为他们可能会提供帮助。但要小心使用这些结果,因为它很容易让你误入歧途。 +例如,这种情况常常会发生在很少被修改的地方(比如老旧的或未维护的驱动程序): +有时这样的代码会在树级清理期间被根本不关心此驱动程序的开发者修改。 + + +搜索现有报告(第二部分) +-------------------------- + + *在缺陷追踪器或问题相关邮件列表的存档中彻底搜索可能与您的问题匹配的报告。 + 如果找到匹配的报告,请加入讨论而不是发送新报告。* + +如前所述:报告一个别人已经提出的问题,对每个人来说都是浪费时间,尤其是作为报告 +人的你。这就是为什么你应该再次搜索现有的报告。现在你已经知道问题需要报告到哪里。 +如果是邮件列表,那么一般在 `lore.kernel.org <https://lore.kernel.org/>`_ 可以 +找到相应存档。 + +但有些列表运行在其他地方。例如前面步骤中当例子的ath10k WiFi驱动程序就是这种 +情况。但是你通常可以在网上很容易地找到这些列表的档案。例如搜索“archive +ath10k@lists.infradead.org”,将引导您到ath10k邮件列表的信息页,该页面顶部链接 +到其 `列表存档 <https://lists.infradead.org/pipermail/ath10k/>`_ 。遗憾的是, +这个列表和其他一些列表缺乏搜索其存档的功能。在这种情况下可以使用常规的互联网 +搜索引擎,并添加类似“site:lists.infadead.org/pipermail/ath10k/”这 +样的搜索条件,这会把结果限制在该链接中的档案。 + +也请进一步搜索网络、LKML和bugzilla.kernel.org网站。 + +有关如何搜索以及在找到匹配报告时如何操作的详细信息,请参阅上面的“搜索现有报告 +(第一部分)”。 + +不要急着完成报告过程的这一步:花30到60分钟甚至更多的时间可以为你和其他人节省 / +减少相当多的时间和麻烦。 + + +安装一个新的内核进行测试 +-------------------------- + + *除非您已经在运行最新的“主线”Linux内核,否则最好在报告流程前安装它。在 + 某些情况下,使用最新的“稳定版”Linux进行测试和报告也是可以接受的替代方案; + 在合并窗口期间,这实际上可能是最好的方法,但在开发阶段最好还是暂停几天。 + 无论你选择什么版本,最好使用“普通”构建。忽略这些建议会大大增加您的报告 + 被拒绝或忽略的风险。* + +正如第一步的详细解释中所提到的:与大多数程序员一样,与大多数程序员一样,Linux +内核开发人员不喜欢花时间处理他们维护的源代码中根本不会发生的问题的报告。这只 +会浪费每个人的时间,尤其是你的时间。这就是为什么在报告问题之前,您必须先确认 +问题仍然存在于最新的上游代码中,这符合每个人的利益。您可以忽略此建议,但如前 +所述:这样做会极大地增加问题报告被拒绝或被忽略的风险。 + +内核“最新上游”的范围通常指: + + * 安装一个主线内核;最新的稳定版内核也可以是一个选择,但大多数时候都最好避免。 + 长期支持内核(有时称为“LTS内核”)不适合此流程。下一小节将更详细地解释所有 + 这些。 + + * 下一小节描述获取和安装这样一个内核的方法。它还指出了使用预编译内核是可以的, + 但普通的内核更好,这意味着:它是直接使用从 `kernel.org <https://kernel.org/>`_ + 获得的Linux源代码构建并且没有任何方式修改或增强。 + + +选择适合测试的版本 +~~~~~~~~~~~~~~~~~~~~ + +前往 `kernel.org <https://kernel.org/>`_ 来决定使用哪个版本。忽略那个写着 +“Latest release最新版本”的巨大黄色按钮,往下看有一个表格。在表格的顶部,你会 +看到一行以“mainline”开头的字样,大多数情况下它会指向一个版本号类似“5.8-rc2” +的预发布版本。如果是这样的话,你将需要使用这个主线内核进行测试。不要让“rc” +吓到你,这些“开发版内核”实际上非常可靠——而且你已经按照上面的指示做了备份, +不是吗? + +大概每九到十周,“mainline”可能会给你指出一个版本号类似“5.7”的正式版本。如果 +碰见这种情况,请考虑暂停报告过程,直到下一个版本的第一个预发布(5.8-rc1)出 +现在 `kernel.org <https://kernel.org/>`_ 上。这是因为 Linux 的开发周期正在 +两周的“合并窗口”内。大部分的改动和所有干扰性的改动都会在这段时间内被合并到 +下一个版本中。在此期间使用主线是比较危险的。内核开发者通常也很忙,可能没有 +多余的时间来处理问题报告。这也是很有可能在合并窗口中应用了许多修改来修复你 +所面临的问题;这就是为什么你很快就得用一个新的内核版本重新测试,就像下面“发 +布报告后的责任”一节中所述的那样。 + +这就是为什么要等到合并窗口结束后才去做。但是如果你处理的是一些不应该等待的 +东西,则无需这样做。在这种情况下,可以考虑通过 git 获取最新的主线内核(见下 +文),或者使用 kernel.org 上提供的最新稳定版本。如果 mainline 因为某些原因 +不无法正常工作,那么使用它也是可以接受的。总的来说:用它来重现问题也比完全 +不报告问题要好。 + +最好避免在合并窗口外使用最新的稳定版内核,因为所有修复都必须首先应用于主线。 +这就是为什么检查最新的主线内核是如此重要:你希望看到在旧版本线修复的任何问题 +需要先在主线修复,然后才能得到回传,这可能需要几天或几周。另一个原因是:您 +希望的修复对于回传来说可能太难或太冒险;因此再次报告问题不太可能改变任何事情。 + +这些方面也部分表明了为什么长期支持内核(有时称为“LTS内核”)不适合报告流程: +它们与当前代码的距离太远。因此,先去测试主线,然后再按流程走:如果主线没有 +出现问题,流程将指导您如何在旧版本线中修复它。 + +如何获得新的 Linux 内核 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +你可以使用预编译或自编译的内核进行测试;如果你选择后者,可以使用 git 获取源 +代码,或者下载其 tar 存档包。 + +**使用预编译的内核** :这往往是最快速、最简单、最安全的方法——尤其是在你不熟 +悉 Linux 内核的情况下。问题是:发行商或附加存储库提供的大多数版本都是从修改 +过的Linux源代码构建的。因此它们不是普通的,通常不适合于测试和问题报告:这些 +更改可能会导致您面临的问题或以某种方式影响问题。 + +但是如果您使用的是流行的Linux发行版,那么您就很幸运了:对于大部分的发行版, +您可以在网上找到包含最新主线或稳定版本Linux内核包的存储库。使用这些是完全可 +以的,只要从存储库的描述中确认它们是普通的或者至少接近普通。此外,请确保软件 +包包含kernel.org上提供的最新版本内核。如果这些软件包的时间超过一周,那么它们 +可能就不合适了,因为新的主线和稳定版内核通常至少每周发布一次。 + +请注意,您以后可能需要手动构建自己的内核:有时这是调试或测试修复程序所必需的, +如后文所述。还要注意,预编译的内核可能缺少在出现panic、Oops、warning或BUG时 +解码内核打印的消息所需的调试符号;如果您计划解码这些消息,最好自己编译内核 +(有关详细信息,请参阅本小节结尾和“解码失败信息”小节)。 + +**使用git** :熟悉 git 的开发者和有经验的 Linux 用户通常最好直接从 +`kernel.org 上的官方开发仓库 +<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_ +中获取最新的 Linux 内核源代码。这些很可能比最新的主线预发布版本更新一些。不 +用担心:它们和正式的预发布版本一样可靠,除非内核的开发周期目前正处于合并窗 +口中。不过即便如此,它们也是相当可靠的。 + +**常规方法** :不熟悉 git 的人通常最好从 `kernel.org <https://kernel.org/>`_ +下载源码的tar 存档包。 + +如何实际构建一个内核并不在这里描述,因为许多网站已经解释了必要的步骤。如果 +你是新手,可以考虑按照那些建议使用 ``make localmodconfig`` 来做,它将尝试获 +取你当前内核的配置,然后根据你的系统进行一些调整。这样做并不能使编译出来的 +内核更好,但可以更快地编译。 + +注意:如果您正在处理来自内核的pannc、Oops、warning或BUG,请在配置内核时尝试 +启用 CONFIG_KALLSYMS 选项。此外,还可以启用 CONFIG_DEBUG_KERNEL 和 +CONFIG_DEBUG_INFO;后者是相关选项,但只有启用前者才能开启。请注意, +CONFIG_DEBUG_INFO 会需要更多储存空间来构建内核。但这是值得的,因为这些选项将 +允许您稍后精确定位触发问题的确切代码行。下面的“解码失败信息”一节对此进行了更 +详细的解释。 + +但请记住:始终记录遇到的问题,以防难以重现。发送未解码的报告总比不报告要好。 + + +检查“污染”标志 +---------------- + + *确保您刚刚安装的内核在运行时不会“污染”自己。* + +正如上面已经详细介绍过的:当发生一些可能会导致一些看起来完全不相关的后续错 +误的事情时,内核会设置一个“污染”标志。这就是为什么你需要检查你刚刚安装的内 +核是否有设置此标志。如果有的话,几乎在任何情况下你都需要在报告问题之前先消 +除它。详细的操作方法请看上面的章节。 + + +用新内核重现问题 +------------------ + + *在您刚刚安装的内核中复现这个问题。如果它没有出现,请查看下方只发生在 + 稳定版和长期支持内核的问题的说明。* + +检查这个问题是否发生在你刚刚安装的新 Linux 内核版本上。如果新内核已经修复了, +可以考虑使用此版本线,放弃报告问题。但是请记住,只要它没有在 `kernel.org +<https://kernel.org/>`_ 的稳定版和长期版(以及由这些版本衍生出来的厂商内核) +中得到修复,其他用户可能仍然会受到它的困扰。如果你喜欢使用其中的一个,或 +者只是想帮助它们的用户,请前往下面的“报告只发生在较旧内核版本线的问题”一节。 + + +优化复现问题的描述 +-------------------- + + *优化你的笔记:试着找到并写出最直接的复现问题的方法。确保最终结果包含所 + 有重要的细节,同时让第一次听说的人容易阅读和理解。如果您在此过程中学到 + 了一些东西,请考虑再次搜索关于该问题的现有报告。* + +过于复杂的报告会让别人很难理解。因此请尽量找到一个可以直接描述、易于以书面 +形式理解的再现方法。包含所有重要的细节,但同时也要尽量保持简短。 + +在这在前面的步骤中,你很可能已经了解了一些关于你所面临的问题的点。利用这些 +知识,再次搜索可以转而加入的现有报告。 + + +解码失败信息 +------------- + + *如果失败涉及“panic”、“Oops”、“warning”或“BUG”,请考虑解码内核日志以查找 + 触发错误的代码行。* + +当内核检测到内部问题时,它会记录一些有关已执行代码的信息。这使得在源代码中精 +确定位触发问题的行并显示如何调用它成为可能。但只有在配置内核时启用了 +CONFIG_DEBUG_INFO 和 CONFIG_KALLSYMS选项时,这种方法才起效。如果已启用此选项, +请考虑解码内核日志中的信息。这将使我们更容易理解是什么导致了“panic”、“Oops”、 +“warning”或“BUG”,从而增加了有人提供修复的几率。 + +解码可以通过Linux源代码树中的脚本来完成。如果您运行的内核是之前自己编译的, +这样这样调用它:: + + [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh ./linux-5.10.5/vmlinux + /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/ + +如果您运行的是打包好的普通内核,则可能需要安装带有调试符号的相应包。然后按以下 +方式调用脚本(如果发行版未打包,则可能需要从Linux源代码获取):: + + [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh \ + /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/ + +脚本将解码如下的日志行,这些日志行显示内核在发生错误时正在执行的代码的地址:: + + [ 68.387301] RIP: 0010:test_module_init+0x5/0xffa [test_module] + +解码之后,这些行将变成这样:: + + [ 68.387301] RIP: 0010:test_module_init (/home/username/linux-5.10.5/test-module/test-module.c:16) test_module + +在本例中,执行的代码是从文件“~/linux-5.10.5/test-module/test-module.c”构建的, +错误出现在第16行的指令中。 + +该脚本也会如此解码以“Call trace”开头的部分中提到的地址,该部分显示出现问题的 +函数的路径。此外,脚本还会显示内核正在执行的代码部分的汇编输出。 + +注意,如果你没法做到这一点,只需跳过这一步,并在报告中说明原因。如果你幸运的 +话,可能无需解码。如果需要的话,也许有人会帮你做这件事情。还要注意,这只是解 +码内核堆栈跟踪的几种方法之一。有时需要采取不同的步骤来检索相关的详细信息。 +别担心,如果您碰到的情况需要这样做,开发人员会告诉您该怎么做。 + + +对回归的特别关照 +----------------- + + *如果您的问题是回归问题,请尽可能缩小引入问题时的范围。* + +Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化,这就是为什么他 +认为回归是不可接受的,并希望看到它们被迅速修复。这就是为什么引入了回归的改 +动导致的问题若无法通过其他方式快速解决,通常会被迅速撤销。因此,报告回归有 +点像“王炸”,会迅速得到修复。但要做到这一点,需要知道导致回归的变化。通常情 +况下,要由报告者来追查罪魁祸首,因为维护者往往没有时间或手头设置不便来自行 +重现它。 + +有一个叫做“二分”的过程可以来寻找变化,这在 +“Documentation/translations/zh_CN/admin-guide/bug-bisect.rst”文档中进行了详细 +的描述,这个过程通常需要你构建十到二十个内核镜像,每次都尝试在构建下一个镜像 +之前重现问题。是的,这需要花费一些时间,但不用担心,它比大多数人想象的要快得多。 +多亏了“binary search二进制搜索”,这将引导你在源代码管理系统中找到导致回归的提交。 +一旦你找到它,就在网上搜索其主题、提交ID和缩短的提交ID(提交ID的前12个字符)。 +如果有的话,这将引导您找到关于它的现有报告。 + +需要注意的是,二分法需要一点窍门,不是每个人都懂得诀窍,也需要相当多的努力, +不是每个人都愿意投入。尽管如此,还是强烈建议自己进行一次二分。如果你真的 +不能或者不想走这条路,至少要找出是哪个主线内核引入的回归。比如说从 5.5.15 +切换到 5.8.4 的时候出现了一些问题,那么至少可以尝试一下相近的所有的主线版本 +(5.6、5.7 和 5.8)来检查它是什么时候出现的。除非你想在一个稳定版或长期支持 +内核中找到一个回归,否则要避免测试那些编号有三段的版本(5.6.12、5.7.8),因 +为那会使结果难以解释,可能会让你的测试变得无用。一旦你找到了引入回归的主要 +版本,就可以放心地继续报告了。但请记住:在不知道罪魁祸首的情况下,开发人员 +是否能够提供帮助取决于手头的问题。有时他们可能会从报告中确认是什么出现了问 +题,并能修复它;有时他们可能无法提供帮助,除非你进行二分。 + +当处理回归问题时,请确保你所面临的问题真的是由内核引起的,而不是由其他东西 +引起的,如上文所述。 + +在整个过程中,请记住:只有当旧内核和新内核的配置相似时,问题才算回归。最好 +的方法是:把配置文件(``.config``)从旧的工作内核直接复制到你尝试的每个新内 +核版本。之后运行 ``make oldnoconfig`` 来调整它以适应新版本的需要,而不启用 +任何新的功能,因为那些功能也可能导致回归。 + + +撰写并发送报告 +--------------- + + *通过详细描述问题来开始编写报告。记得包括以下条目:您为复现而安装的最新 + 内核版本、使用的Linux发行版以及关于如何复现该问题的说明。如果可能,将内 + 核构建配置(.config)和 ``dmesg`` 的输出放在网上的某个地方,并链接到它。 + 包含或上传所有其他可能相关的信息,如Oops的输出/截图或来自 ``lspci`` + 的输出。一旦你写完了这个主要部分,请在上方插入一个正常长度的段落快速概 + 述问题和影响。再在此之上添加一个简单描述问题的句子,以得到人们的阅读。 + 现在给出一个更短的描述性标题或主题。然后就可以像MAINTAINERS文件告诉你的 + 那样发送或提交报告了,除非你在处理一个“高优先级问题”:它们需要按照下面 + “高优先级问题的特殊处理”所述特别关照。* + +现在你已经准备好了一切,是时候写你的报告了。上文前言中链接的三篇文档对如何 +写报告做了部分解释。这就是为什么本文将只提到一些基本的内容以及 Linux 内核特 +有的东西。 + +有一点是符合这两类的:你的报告中最关键的部分是标题/主题、第一句话和第一段。 +开发者经常会收到许多邮件。因此,他们往往只是花几秒钟的时间浏览一下邮件,然 +后再决定继续下一封或仔细查看。因此,你报告的开头越好,有人研究并帮助你的机 +会就越大。这就是为什么你应该暂时忽略他们,先写出详细的报告。;-) + +每份报告都应提及的事项 +~~~~~~~~~~~~~~~~~~~~~~~~ + +详细描述你的问题是如何发生在你安装的新纯净内核上的。试着包含你之前写的和优 +化过的分步说明,概述你和其他人如何重现这个问题;在极少数无法重现的情况下, +尽量描述你做了什么来触发它。 + +还应包括其他人为了解该问题及其环境而可能需要的所有相关信息。实际需要的东西 +在很大程度上取决于具体问题,但有些事项你总是应该包括在内: + + * ``cat /proc/version`` 的输出,其中包含 Linux 内核版本号和构建时的编译器。 + + * 机器正在运行的 Linux 发行版( ``hostnamectl | grep “Operating System“`` ) + + * CPU 和操作系统的架构( ``uname -mi`` ) + + * 如果您正在处理回归,并进行了二分,请提及导致回归的变更的主题和提交ID。 + +许多情况下,让读你报告的人多了解两件事也是明智之举: + + * 用于构建 Linux 内核的配置(“.config”文件) + + * 内核的信息,你从 ``dmesg`` 得到的信息写到一个文件里。确保它以像“Linux + version 5.8-1 (foobar@example.com) (gcc (GCC) 10.2.1, GNU ld version + 2.34) #1 SMP Mon Aug 3 14:54:37 UTC 2020”这样的行开始,如果没有,那么第 + 一次启动阶段的重要信息已经被丢弃了。在这种情况下,可以考虑使用 + ``journalctl -b 0 -k`` ;或者你也可以重启,重现这个问题,然后调用 + ``dmesg`` 。 + +这两个文件很大,所以直接把它们放到你的报告中是个坏主意。如果你是在缺陷跟踪 +器中提交问题,那么将它们附加到工单中。如果你通过邮件报告问题,不要用附件附 +上它们,因为那会使邮件变得太大,可以按下列之一做: + + * 将文件上传到某个公开的地方(你的网站,公共文件粘贴服务,在 + `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 上创建的工单……), + 并在你的报告中放上链接。理想情况下请使用允许这些文件保存很多年的地方,因 + 为它们可能在很多年后对别人有用;例如 5 年或 10 年后,一个开发者正在修改 + 一些代码,而这些代码正是为了修复你的问题。 + + * 把文件放在一边,然后说明你会在他人回复时再单独发送。只要记得报告发出去后, + 真正做到这一点就可以了。;-) + +提供这些东西可能是明智的 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +根据问题的不同,你可能需要提供更多的背景数据。这里有一些关于提供什么比较好 +的建议: + + * 如果你处理的是内核的“warning”、“OOPS”或“panic”,请包含它。如果你不能复制 + 粘贴它,试着用netconsole网络终端远程跟踪或者至少拍一张屏幕的照片。 + + * 如果问题可能与你的电脑硬件有关,请说明你使用的是什么系统。例如,如果你的 + 显卡有问题,请提及它的制造商,显卡的型号,以及使用的芯片。如果是笔记本电 + 脑,请提及它的型号名称,但尽量确保意义明确。例如“戴尔 XPS 13”就不很明确, + 因为它可能是 2012 年的那款,那款除了看起来和现在销售的没有什么不同之外, + 两者没有任何共同之处。因此,在这种情况下,要加上准确的型号,例如 2019 + 年内推出的 XPS 13 型号为“9380”或“7390”。像“联想 Thinkpad T590”这样的名字 + 也有些含糊不清:这款笔记本有带独立显卡和不带的子型号,所以要尽量找到准确 + 的型号名称或注明主要部件。 + + * 说明正在使用的相关软件。如果你在加载模块时遇到了问题,你要说明正在使用的 + kmod、systemd 和 udev 的版本。如果其中一个 DRM 驱动出现问题,你要说明 + libdrm 和 Mesa 的版本;还要说明你的 Wayland 合成器或 X-Server 及其驱动。 + 如果你有文件系统问题,请注明相应的文件系统实用程序的版本(e2fsprogs, + btrfs-progs, xfsprogs……)。 + + * 从内核中收集可能有用的额外信息。例如, ``lspci -nn`` 的输出可以帮助别人 + 识别你使用的硬件。如果你的硬件有问题,你甚至可以给出 ``sudo lspci -vvv`` + 的结果,因为它提供了组件是如何配置的信息。对于一些问题,可能最好包含 + ``/proc/cpuinfo`` , ``/proc/ioports`` , ``/proc/iomem`` , + ``/proc/modules`` 或 ``/proc/scsi/scsi`` 等文件的内容。一些子系统还提 + 供了收集相关信息的工具。 ``alsa-info.sh`` `就是这样一个工具,它是音频/声 + 音子系统开发者提供的 <https://www.alsa-project.org/wiki/AlsaInfo>`_ 。 + +这些例子应该会给你一些知识点,让你知道附上什么数据可能是明智的,但你自己也 +要想一想,哪些数据对别人会有帮助。不要太担心忘记一些东西,因为开发人员会要 +求提供他们需要的额外细节。但从一开始就把所有重要的东西都提供出来,会增加别 +人仔细查看的机会。 + + +重要部分:报告的开头 +~~~~~~~~~~~~~~~~~~~~~~ + +现在你已经准备好了报告的详细部分,让我们进入最重要的部分:开头几句。现在到 +报告的最前面,在你刚才写的部分之前加上类似“The detailed description:”(详细 +描述)这样的内容,并在最前面插入两个新行。现在写一个正常长度的段落,大致概 +述这个问题。去掉所有枯燥的细节,把重点放在读者需要知道的关键部分,以让人了 +解这是怎么回事;如果你认为这个缺陷影响了很多用户,就提一下这点来吸引大家关 +注。 + +做好这一点后,在顶部再插入两行,写一句话的摘要,快速解释报告的内容。之后你 +要更加抽象,为报告写一个更短的主题/标题。 + +现在你已经写好了这部分,请花点时间来优化它,因为它是你的报告中最重要的部分: +很多人会先读这部分,然后才会决定是否值得花时间阅读其他部分。 + +现在就像 :ref:`MAINTAINERS <maintainers>` 维护者文件告诉你的那样发送或提交 +报告,除非它是前面概述的那些“高优先级问题”之一:在这种情况下,请先阅读下一 +小节,然后再发送报告。 + +高优先级问题的特殊处理 +~~~~~~~~~~~~~~~~~~~~~~~~ + +高优先级问题的报告需要特殊处理。 + +**非常严重的缺陷** :确保在主题或工单标题以及第一段中明显标出 severeness +(非常严重的)。 + +**回归** :如果问题是一个回归,请在邮件的主题或缺陷跟踪器的标题中添加 +[REGRESSION]。如果您没有进行二分,请至少注明您测试的最新主线版本(比如 5.7) +和出现问题的最新版本(比如 5.8)。如果您成功地进行了二分,请注明导致回归 +的提交ID和主题。也请添加该变更的作者到你的报告中;如果您需要将您的缺陷提交 +到缺陷跟踪器中,请将报告以私人邮件的形式转发给他,并注明报告提交地点。 + +**安全问题** :对于这种问题,你将必须评估:如果细节被公开披露,是否会对其他 +用户产生短期风险。如果不会,只需按照所述继续报告问题。如果有此风险,你需要 +稍微调整一下报告流程。 + + * 如果 MAINTAINERS 文件指示您通过邮件报告问题,请不要抄送任何公共邮件列表。 + + * 如果你应该在缺陷跟踪器中提交问题,请确保将工单标记为“私有”或“安全问题”。 + 如果缺陷跟踪器没有提供保持报告私密性的方法,那就别想了,把你的报告以私人 + 邮件的形式发送给维护者吧。 + +在这两种情况下,都一定要将报告发到 MAINTAINERS 文件中“安全联络”部分列出的 +地址。理想的情况是在发送报告的时候直接抄送他们。如果您在缺陷跟踪器中提交了 +报告,请将报告的文本转发到这些地址;但请在报告的顶部加上注释,表明您提交了 +报告,并附上工单链接。 + +更多信息请参见“Documentation/translations/zh_CN/admin-guide/security-bugs.rst”。 + + +发布报告后的责任 +------------------ + + *等待别人的反应,继续推进事情,直到你能够接受这样或那样的结果。因此,请 + 公开和及时地回应任何询问。测试提出的修复。积极地测试:至少重新测试每个 + 新主线版本的首个候选版本(RC),并报告你的结果。如果出现拖延,就友好地 + 提醒一下。如果你没有得到任何帮助或者未能满意,请试着自己帮助自己。* + +如果你的报告非常优秀,而且你真的很幸运,那么某个开发者可能会立即发现导致问 +题的原因;然后他们可能会写一个补丁来修复、测试它,并直接发送给主线集成,同 +时标记它以便以后回溯到需要它的稳定版和长期支持内核。那么你需要做的就是回复 +一句“Thank you very much”(非常感谢),然后在发布后换上修复好的版本。 + +但这种理想状况很少发生。这就是为什么你把报告拿出来之后工作才开始。你要做的 +事情要视情况而定,但通常会是下面列出的事情。但在深入研究细节之前,这里有几 +件重要的事情,你需要记住这部分的过程。 + + +关于进一步互动的一般建议 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**总是公开回复** :当你在缺陷跟踪器中提交问题时,一定要在那里回复,不要私下 +联系任何开发者。对于邮件报告,在回复您收到的任何邮件时,总是使用“全部回复” +功能。这包括带有任何你可能想要添加到你的报告中的额外数据的邮件:进入邮件应 +用程序“已发送”文件夹,并在邮件上使用“全部回复”来回复报告。这种方法可以确保 +公共邮件列表和其他所有参与者都能及时了解情况;它还能保持邮件线程的完整性, +这对于邮件列表将所有相关邮件归为一类是非常重要的。 + +只有两种情况不适合在缺陷跟踪器或“全部回复”中发表评论: + + * 有人让你私下发东西。 + + * 你被告知要发送一些东西,但注意到其中包含需要保密的敏感信息。在这种情况下, + 可以私下发送给要求发送的开发者。但要在工单或邮件中注明你是这么做的,这 + 样其他人就知道你尊重了这个要求。 + +**在请求解释或帮助之前先研究一下** :在这部分过程中,有人可能会告诉你用尚未 +掌握的技能做一些事情。例如你可能会被要求使用一些你从未听说过的测试工具;或 +者你可能会被要求在 Linux 内核源代码上应用一个补丁来测试它是否有帮助。在某些 +情况下,发个回复询问如何做就可以了。但在走这条路之前,尽量通过在互联网上搜 +索自行找到答案;或者考虑在其他地方询问建议。比如询问朋友,或者到你平时常去 +的聊天室或论坛发帖咨询。 + +**要有耐心** :如果你真的很幸运,你可能会在几个小时内收到对你的报告的答复。 +但大多数情况下会花费更多的时间,因为维护者分散在全球各地,因此可能在不同的 +时区——在那里他们已经享受着远离键盘的夜晚。 + +一般来说,内核开发者需要一到五个工作日来回复报告。有时会花费更长的时间,因 +为他们可能正忙于合并窗口、其他工作、参加开发者会议,或者只是在享受一个漫长 +的暑假。 + +“高优先级的问题”(见上面的解释)例外:维护者应该尽快解决这些问题;这就是为 +什么你应该最多等待一个星期(如果是紧急的事情,则只需两天),然后再发送友好 +的提醒。 + +有时维护者可能没有及时回复;有时候可能会出现分歧,例如一个问题是否符合回归 +的条件。在这种情况下,在邮件列表上提出你的顾虑,并请求其他人公开或私下回复 +如何继续推进。如果失败了,可能应该让更高级别的维护者介入。如果是 WiFi 驱动, +那就是无线维护者;如果没有更高级别的维护者,或者其他一切努力都失败了,那 +这可能是一种罕见的、可以让 Linus Torvalds 参与进来的情况。 + +**主动测试** :每当一个新的主线内核版本的第一个预发布版本(rc1)发布的时候, +去检查一下这个问题是否得到了解决,或者是否有什么重要的变化。在工单中或在 +回复报告的邮件中提及结果(确保所有参与讨论的人都被抄送)。这将表明你的承诺 +和你愿意帮忙。如果问题持续存在,它也会提醒开发者确保他们不会忘记它。其他一 +些不定期的重新测试(例如用rc3、rc5 和最终版本)也是一个好主意,但只有在相关 +的东西发生变化或者你正在写什么东西的时候才报告你的结果。 + +这些些常规的事情就不说了,我们来谈谈报告后如何帮助解决问题的细节。 + +查询和测试请求 +~~~~~~~~~~~~~~~ + +如果你的报告得到了回复则需履行以下责任: + +**检查与你打交道的人** :大多数情况下,会是维护者或特定代码区域的开发人员对 +你的报告做出回应。但由于问题通常是公开报告的,所以回复的可能是任何人——包括 +那些想要帮忙的人,但最后可能会用他们的问题或请求引导你完全偏离轨道。这很少 +发生,但这是快速上网搜搜看你正在与谁互动是明智之举的许多原因之一。通过这样 +做,你也可以知道你的报告是否被正确的人听到,因为如果讨论没有导致满意的问题 +解决方案而淡出,之后可能需要提醒维护者(见下文)。 + +**查询数据** :通常你会被要求测试一些东西或提供更多细节。尽快提供所要求的信 +息,因为你已经得到了可能会帮助你的人的注意,你等待的时间越长就有越可能失去 +关注;如果你不在数个工作日内提供信息,甚至可能出现这种结果。 + +**测试请求** :当你被要求测试一个诊断补丁或可能的修复时,也要尽量及时测试。 +但要做得恰当,一定不要急于求成:混淆事情很容易发生,这会给所有人带来许多困 +惑。例如一个常见的错误是以为应用了一个带修复的建议补丁,但事实上并没有。即 +使是有经验的测试人员也会偶尔发生这样的事情,但当有修复的内核和没有修复的内 +核表现得一样时,他们大多时候会注意到。 + +当没有任何实质性进展时该怎么办 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +有些报告不会得到负有相关责任的 Linux 内核开发者的任何反应;或者围绕这个问题 +的讨论有所发展,但渐渐淡出,没有任何实质内容产出。 + +在这种情况下,要等两个星期(最好是三个星期)后再发出友好的提醒:也许当你的 +报告到达时,维护者刚刚离开键盘一段时间,或者有更重要的事情要处理。在写提醒 +信的时候,要善意地问一下,是否还需要你这边提供什么来让事情推进下去。如果报 +告是通过邮件发出来的,那就在邮件的第一行回复你的初始邮件(见上文),其中包 +括下方的原始报告的完整引用:这是少数几种情况下,这样的“TOFU”(Text Over, +Fullquote Under文字在上,完整引用在下)是正确的做法,因为这样所有的收件人都 +会以适当的顺序立即让细节到手头上来。 + +在提醒之后,再等三周的回复。如果你仍然没有得到适当的反馈,你首先应该重新考 +虑你的方法。你是否可能尝试接触了错误的人?是不是报告也许令人反感或者太混乱, +以至于人们决定完全远离它?排除这些因素的最好方法是:把报告给一两个熟悉 +FLOSS 问题报告的人看,询问他们的意见。同时征求他们关于如何继续推进的建议。 +这可能意味着:准备一份更好的报告,让这些人在你发出去之前对它进行审查。这样 +的方法完全可以;只需说明这是关于这个问题的第二份改进的报告,并附上第一份报 +告的链接。 + +如果报告是恰当的,你可以发送第二封提醒信;在其中询问为什么报告没有得到任何 +回复。第二封提醒邮件的好时机是在新 Linux 内核版本的首个预发布版本('rc1') +发布后不久,因为无论如何你都应该在那个时候重新测试并提供状态更新(见上文)。 + +如果第二次提醒的结果又在一周内没有任何反应,可以尝试联系上级维护者询问意见: +即使再忙的维护者在这时候也至少应该发过某种确认。 + +记住要做好失望的准备:理想状况下维护者最好对每一个问题报告做出回应,但他们 +只有义务解决之前列出的“高优先级问题”。所以,如果你得到的回复是“谢谢你的报告, +我目前有更重要的问题要处理,在可预见的未来没有时间去研究这个问题”,那请不 +要太沮丧。 + +也有可能在缺陷跟踪器或列表中进行了一些讨论之后,什么都没有发生,提醒也无助 +于激励大家进行修复。这种情况可能是毁灭性的,但在 Linux 内核开发中确实会发生。 +这些和其他得不到帮助的原因在本文结尾处的“为什么有些问题在被报告后没有得到 +任何回应或者仍然没有修复”中进行了解释。 + +如果你没有得到任何帮助或问题最终没有得到解决,不要沮丧:Linux 内核是 FLOSS, +因此你仍然可以自己帮助自己。例如,你可以试着找到其他受影响的人,和他们一 +起合作来解决这个问题。这样的团队可以一起准备一份新的报告,提到团队有多少人, +为什么你们认为这是应该得到解决的事情。也许你们还可以一起缩小确切原因或引 +入回归的变化,这往往会使修复更容易。而且如果运气好的话,团队中可能会有懂点 +编程的人,也许能写出一个修复方案。 + + + +“报告稳定版和长期支持内核线的回归”的参考 +------------------------------------------ + +本小节提供了在稳定版和长期支持内核线中面对回归时需要执行的步骤的详细信息。 + +确保特定版本线仍然受支持 +~~~~~~~~~~~~~~~~~~~~~~~~~ + + *检查内核开发人员是否仍然维护你关心的Linux内核版本线:去 kernel.org 的 + 首页,确保此特定版本线的最新版没有“[EOL]”标记。* + +大多数内核版本线只支持三个月左右,因为延长维护时间会带来相当多的工作。因此, +每年只会选择一个版本来支持至少两年(通常是六年)。这就是为什么你需要检查 +内核开发者是否还支持你关心的版本线。 + +注意,如果 `kernel.org <https://kernel.org/>`_ 在首页上列出了两个“稳定”版本, +你应该考虑切换到较新的版本,而忘掉较旧的版本:对它的支持可能很快就会结束。 +然后,它将被标记为“生命周期结束”(EOL)。达到这个程度的版本线仍然会在 +`kernel.org <https://kernel.org/>`_ 首页上被显示一两周,但不适合用于测试和 +报告。 + +搜索稳定版邮件列表 +~~~~~~~~~~~~~~~~~~~ + + *检查Linux稳定版邮件列表中的现有报告。* + +也许你所面临的问题已经被发现,并且已经或即将被修复。因此,请在 `Linux 稳定 +版邮件列表的档案 <https://lore.kernel.org/stable/>`_ 中搜索类似问题的报告。 +如果你找到任何匹配的问题,可以考虑加入讨论,除非修复工作已经完成并计划很快 +得到应用。 + +用最新版本复现问题 +~~~~~~~~~~~~~~~~~~~ + + *从特定的版本线安装最新版本作为纯净内核。确保这个内核没有被污染,并且仍 + 然存在问题,因为问题可能已经在那里被修复了。* + +在投入更多时间到这个过程中之前,你要检查这个问题是否在你关注的版本线的最新 +版本中已经得到了修复。这个内核需要是纯净的,在问题发生之前不应该被污染,正 +如上面已经在测试主线的过程中详细介绍过的一样。 + +您是否是第一次注意到供应商内核的回归?供应商的更改可能会发生变化。你需要重新 +检查排除来这个问题。当您从5.10.4-vendor.42更新到5.10.5-vendor.43时,记录损坏 +的信息。然后在测试了前一段中所述的最新5.10版本之后,检查Linux 5.10.4的普通版本 +是否也可以正常工作。如果问题在那里出现,那就不符合上游回归的条件,您需要切换 +回主逐步指南来报告问题。 + +报告回归 +~~~~~~~~~~ + + *向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)。 + 大致描述问题,并解释如何复现。讲清楚首个出现问题的版本和最后一个工作正常 + 的版本。然后等待进一步的指示。* + +当报告在稳定版或长期支持内核线内发生的回归(例如在从5.10.4更新到5.10.5时), +一份简短的报告足以快速报告问题。因此只需要粗略的描述。 + +但是请注意,如果您能够指明引入问题的确切版本,这将对开发人员有很大帮助。因此 +如果有时间的话,请尝试使用普通内核找到该版本。让我们假设发行版发布Linux内核 +5.10.5到5.10.8的更新时发生了故障。那么按照上面的指示,去检查该版本线中的最新 +内核,比如5.10.9。如果问题出现,请尝试普通5.10.5,以确保供应商应用的补丁不会 +干扰。如果问题没有出现,那么尝试5.10.7,然后直到5.10.8或5.10.6(取决于结果) +找到第一个引入问题的版本。在报告中写明这一点,并指出5.10.9仍然存在故障。 + +前一段基本粗略地概述了“二分”方法。一旦报告出来,您可能会被要求做一个正确的 +报告,因为它允许精确地定位导致问题的确切更改(然后很容易被恢复以快速修复问题)。 +因此如果时间允许,考虑立即进行适当的二分。有关如何详细信息,请参阅“对回归的 +特别关照”部分和文档“Documentation/translations/zh_CN/admin-guide/bug-bisect.rst”。 + + +“报告仅在旧内核版本线中发生的问题”的参考 +---------------------------------------- + +本节详细介绍了如果无法用主线内核重现问题,但希望在旧版本线(又称稳定版内核和 +长期支持内核)中修复问题时需要采取的步骤。 + +有些修复太复杂 +~~~~~~~~~~~~~~~ + + *请做好准备,接下来的几个步骤可能无法在旧版本中解决问题:修复可能太大或 + 太冒险,无法移植到那里。* + +即使是微小的、看似明显的代码变化,有时也会带来新的、完全意想不到的问题。稳 +定版和长期支持内核的维护者非常清楚这一点,因此他们只对这些内核进行符合 +“Documentation/translations/zh_CN/process/stable-kernel-rules.rst”中所列出的 +规则的修改。 + +复杂或有风险的修改不符合条件,因此只能应用于主线。其他的修复很容易被回溯到 +最新的稳定版和长期支持内核,但是风险太大,无法集成到旧版内核中。所以要注意 +你所希望的修复可能是那些不会被回溯到你所关心的版本线的修复之一。在这种情况 +下,你将别无选择,要么忍受这个问题,要么切换到一个较新的 Linux 版本,除非你 +想自己把修复补丁应用到你的内核中。 + +通用准备 +~~~~~~~~~~ + + *执行上面“报告仅在旧内核版本线中发生的问题”一节中的前三个步骤。* + +您需要执行本指南另一节中已经描述的几个步骤。这些步骤将让您: + + * 检查内核开发人员是否仍然维护您关心的Linux内核版本行。 + + * 在Linux稳定邮件列表中搜索退出的报告。 + + * 检查最新版本。 + + +检查代码历史和搜索现有的讨论 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + *在Linux内核版本控制系统中搜索修复主线问题的更改,因为它的提交消息可能 + 会告诉你修复是否已经计划好了支持。如果你没有找到,搜索适当的邮件列表, + 寻找讨论此类问题或同行评议可能修复的帖子;然后检查讨论是否认为修复不适 + 合支持。如果支持根本不被考虑,加入最新的讨论,询问是否有可能。* + +在许多情况下,你所处理的问题会发生在主线上,但已在主线上得到了解决。修正它 +的提交也需要被回溯才能解决这个问题。这就是为什么你要搜索它或任何相关讨论。 + + * 首先尝试在存放 Linux 内核源代码的 Git 仓库中找到修复。你可以通过 + `kernel.org 上的网页 + <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_ + 或 `GitHub 上的镜像 <https://github.com/torvalds/linux>`_ 来实现;如果你 + 有一个本地克隆,你也可以在命令行用 ``git log --grep=<pattern>`` 来搜索。 + + 如果你找到了修复,请查看提交消息的尾部是否包含了类似这样的“稳定版标签”: + + Cc: <stable@vger.kernel.org> # 5.4+ + + 像上面这行,开发者标记了安全修复可以回传到 5.4 及以后的版本。大多数情况 + 下,它会在两周内被应用到那里,但有时需要更长的时间。 + + * 如果提交没有告诉你任何东西,或者你找不到修复,请再找找关于这个问题的讨论。 + 用你最喜欢的搜索引擎搜索网络,以及 `Linux kernel developers mailing + list 内核开发者邮件列表 <https://lore.kernel.org/lkml/>`_ 的档案。也可以 + 阅读上面的 `定位导致问题的内核区域` 一节,然后按照说明找到导致问题的子系 + 统:它的缺陷跟踪器或邮件列表存档中可能有你要找的答案。 + + * 如果你看到了一个计划的修复,请按上所述在版本控制系统中搜索它,因为提交可 + 能会告诉你是否可以进行回溯。 + + * 检查讨论中是否有任何迹象表明,该修复程序可能风险太大,无法回溯到你关心 + 的版本线。如果是这样的话,你必须忍受这个问题,或者切换到应用了修复的内 + 核版本线。 + + * 如果修复的问题未包含稳定版标签,并且没有讨论过回溯问题,请加入讨论:如 + 果合适的话,请提及你所面对的问题的版本,以及你希望看到它被修复。 + + +请求建议 +~~~~~~~~~ + + *前面的步骤之一应该会给出一个解决方案。如果仍未能成功,请向可能引起问题 + 的子系统的维护人员询问建议;抄送特定子系统的邮件列表以及稳定版邮件列表。* + +如果前面的三个步骤都没有让你更接近解决方案,那么只剩下一个选择:请求建议。 +在你发给可能是问题根源的子系统的维护者的邮件中这样做;抄送子系统的邮件列表 +以及稳定版邮件列表(stable@vger.kernel.org)。 + + +为什么有些问题在报告后没有任何回应或仍未解决? +=============================================== + +当向 Linux 开发者报告问题时,要注意只有“高优先级的问题”(回归、安全问题、严 +重问题)才一定会得到解决。如果维护者或其他人都失败了,Linus Torvalds 他自己 +会确保这一点。他们和其他内核开发者也会解决很多其他问题。但是要知道,有时他 +们也会不能或不愿帮忙;有时甚至没有人发报告给他们。 + +最好的解释就是那些内核开发者常常是在业余时间为 Linux 内核做出贡献。内核中的 +不少驱动程序都是由这样的程序员编写的,往往只是因为他们想让自己的硬件可以在 +自己喜欢的操作系统上使用。 + +这些程序员大多数时候会很乐意修复别人报告的问题。但是没有人可以强迫他们这样 +做,因为他们是自愿贡献的。 + +还有一些情况下,这些开发者真的很想解决一个问题,但却不能解决:有时他们缺乏 +硬件编程文档来解决问题。这种情况往往由于公开的文档太简陋,或者驱动程序是通 +过逆向工程编写的。 + +业余开发者迟早也会不再关心某驱动。也许他们的测试硬件坏了,被更高级的玩意取 +代了,或者是太老了以至于只能在计算机博物馆里找到。有时开发者根本就不关心他 +们的代码和 Linux 了,因为在他们的生活中一些不同的东西变得更重要了。在某些情 +况下,没有人愿意接手维护者的工作——也没有人可以被强迫,因为对 Linux 内核的贡 +献是自愿的。然而被遗弃的驱动程序仍然存在于内核中:它们对人们仍然有用,删除 +它们可能导致回归。 + +对于那些为 Linux 内核工作而获得报酬的开发者来说,情况并没有什么不同。这些人 +现在贡献了大部分的变更。但是他们的雇主迟早也会停止关注他们的代码或者让程序 +员专注于其他事情。例如,硬件厂商主要通过销售新硬件来赚钱;因此,他们中的不 +少人并没有投入太多时间和精力来维护他们多年前就停止销售的东西的 Linux 内核驱 +动。企业级 Linux 发行商往往持续维护的时间比较长,但在新版本中往往会把对老旧 +和稀有硬件的支持放在一边,以限制范围。一旦公司抛弃了一些代码,往往由业余贡 +献者接手,但正如上面提到的:他们迟早也会放下代码。 + +优先级是一些问题没有被修复的另一个原因,因为维护者相当多的时候是被迫设置这 +些优先级的,因为在 Linux 上工作的时间是有限的。对于业余时间或者雇主给予他们 +的开发人员用于上游内核维护工作的时间也是如此。有时维护人员也会被报告淹没, +即使一个驱动程序几乎完美地工作。为了不被完全缠住,程序员可能别无选择,只能 +对问题报告进行优先级排序而拒绝其中的一些报告。 + +不过这些都不用太过担心,很多驱动都有积极的维护者,他们对尽可能多的解决问题 +相当感兴趣。 + + +结束语 +======= + +与其他免费/自由&开源软件(Free/Libre & Open Source Software,FLOSS)相比, +向 Linux 内核开发者报告问题是很难的:这个文档的长度和复杂性以及字里行间的内 +涵都说明了这一点。但目前就是这样了。这篇文字的主要作者希望通过记录现状来为 +以后改善这种状况打下一些基础。 diff --git a/Documentation/translations/zh_CN/admin-guide/security-bugs.rst b/Documentation/translations/zh_CN/admin-guide/security-bugs.rst new file mode 100644 index 0000000000000000000000000000000000000000..b8120391755d46a4198181ddf53d02f6d3f3ff76 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/security-bugs.rst @@ -0,0 +1,74 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../admin-guide/security-bugs` + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +安全缺陷 +========= + +Linux内核开发人员非常重视安全性。因此我们想知道何时发现了安全漏洞,以便尽快 +修复和披露。请向Linux内核安全团队报告安全漏洞。 + +联络 +----- + +可以通过电子邮件<security@kernel.org>联系Linux内核安全团队。这是一个安全人员 +的私有列表,他们将帮助验证错误报告并开发和发布修复程序。如果您已经有了一个 +修复,请将其包含在您的报告中,这样可以大大加快进程。安全团队可能会从区域维护 +人员那里获得额外的帮助,以理解和修复安全漏洞。 + +与任何缺陷一样,提供的信息越多,诊断和修复就越容易。如果您不清楚哪些信息有用, +请查看“Documentation/translations/zh_CN/admin-guide/reporting-issues.rst”中 +概述的步骤。任何利用漏洞的攻击代码都非常有用,未经报告者同意不会对外发布,除 +非已经公开。 + +请尽可能发送无附件的纯文本电子邮件。如果所有的细节都藏在附件里,那么就很难对 +一个复杂的问题进行上下文引用的讨论。把它想象成一个 +:doc:`常规的补丁提交 <../process/submitting-patches>` (即使你还没有补丁): +描述问题和影响,列出复现步骤,然后给出一个建议的解决方案,所有这些都是纯文本的。 + +披露和限制信息 +--------------- + +安全列表不是公开渠道。为此,请参见下面的协作。 + +一旦开发出了健壮的补丁,发布过程就开始了。对公开的缺陷的修复会立即发布。 + +尽管我们倾向于在未公开缺陷的修复可用时即发布补丁,但应报告者或受影响方的请求, +这可能会被推迟到发布过程开始后的7日内,如果根据缺陷的严重性需要更多的时间, +则可额外延长到14天。推迟发布修复的唯一有效原因是为了适应QA的逻辑和需要发布 +协调的大规模部署。 + +虽然可能与受信任的个人共享受限信息以开发修复,但未经报告者许可,此类信息不会 +与修复程序一起发布或发布在任何其他披露渠道上。这包括但不限于原始错误报告和 +后续讨论(如有)、漏洞、CVE信息或报告者的身份。 + +换句话说,我们唯一感兴趣的是修复缺陷。提交给安全列表的所有其他资料以及对报告 +的任何后续讨论,即使在解除限制之后,也将永久保密。 + +协调 +------ + +对敏感缺陷(例如那些可能导致权限提升的缺陷)的修复可能需要与私有邮件列表 +<linux-distros@vs.openwall.org>进行协调,以便分发供应商做好准备,在公开披露 +上游补丁时发布一个已修复的内核。发行版将需要一些时间来测试建议的补丁,通常 +会要求至少几天的限制,而供应商更新发布更倾向于周二至周四。若合适,安全团队 +可以协助这种协调,或者报告者可以从一开始就包括linux发行版。在这种情况下,请 +记住在电子邮件主题行前面加上“[vs]”,如linux发行版wiki中所述: +<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists>。 + +CVE分配 +-------- + +安全团队通常不分配CVE,我们也不需要它们来进行报告或修复,因为这会使过程不必 +要的复杂化,并可能耽误缺陷处理。如果报告者希望在公开披露之前分配一个CVE编号, +他们需要联系上述的私有linux-distros列表。当在提供补丁之前已有这样的CVE编号时, +如报告者愿意,最好在提交消息中提及它。 + +保密协议 +--------- + +Linux内核安全团队不是一个正式的机构实体,因此无法签订任何保密协议。 diff --git a/Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst b/Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst new file mode 100644 index 0000000000000000000000000000000000000000..bc51d7cff9b09d7294b8679271b4c273afbf81f1 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst @@ -0,0 +1,157 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../admin-guide/tainted-kernels` + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +受污染的内核 +------------- + +当发生一些在稍后调查问题时可能相关的事件时,内核会将自己标记为“受污染 +(tainted)”的。不用太过担心,大多数情况下运行受污染的内核没有问题;这些信息 +主要在有人想调查某个问题时才有意义的,因为问题的真正原因可能是导致内核受污染 +的事件。这就是为什么来自受污染内核的缺陷报告常常被开发人员忽略,因此请尝试用 +未受污染的内核重现问题。 + +请注意,即使在您消除导致污染的原因(亦即卸载专有内核模块)之后,内核仍将保持 +污染状态,以表示内核仍然不可信。这也是为什么内核在注意到内部问题(“kernel +bug”)、可恢复错误(“kernel oops”)或不可恢复错误(“kernel panic”)时会打印 +受污染状态,并将有关此的调试信息写入日志 ``dmesg`` 输出。也可以通过 +``/proc/`` 中的文件在运行时检查受污染的状态。 + + +BUG、Oops或Panics消息中的污染标志 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +在顶部以“CPU:”开头的一行中可以找到受污染的状态;内核是否受到污染和原因会显示 +在进程ID(“PID:”)和触发事件命令的缩写名称(“Comm:”)之后:: + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 + Oops: 0002 [#1] SMP PTI + CPU: 0 PID: 4424 Comm: insmod Tainted: P W O 4.20.0-0.rc6.fc30 #1 + Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 + RIP: 0010:my_oops_init+0x13/0x1000 [kpanic] + [...] + +如果内核在事件发生时没有被污染,您将在那里看到“Not-tainted:”;如果被污染,那 +么它将是“Tainted:”以及字母或空格。在上面的例子中,它看起来是这样的:: + + Tainted: P W O + +下表解释了这些字符的含义。在本例中,由于加载了专有模块( ``P`` ),出现了 +警告( ``W`` ),并且加载了外部构建的模块( ``O`` ),所以内核早些时候受到 +了污染。要解码其他字符,请使用下表。 + + +解码运行时的污染状态 +~~~~~~~~~~~~~~~~~~~~~ + +在运行时,您可以通过读取 ``cat /proc/sys/kernel/tainted`` 来查询受污染状态。 +如果返回 ``0`` ,则内核没有受到污染;任何其他数字都表示受到污染的原因。解码 +这个数字的最简单方法是使用脚本 ``tools/debugging/kernel-chktaint`` ,您的 +发行版可能会将其作为名为 ``linux-tools`` 或 ``kernel-tools`` 的包的一部分提 +供;如果没有,您可以从 +`git.kernel.org <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/debugging/kernel-chktaint>`_ +网站下载此脚本并用 ``sh kernel-chktaint`` 执行,它会在上面引用的日志中有类似 +语句的机器上打印这样的内容:: + + Kernel is Tainted for following reasons: + * Proprietary module was loaded (#0) + * Kernel issued warning (#9) + * Externally-built ('out-of-tree') module was loaded (#12) + See Documentation/admin-guide/tainted-kernels.rst in the Linux kernel or + https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html for + a more details explanation of the various taint flags. + Raw taint value as int/string: 4609/'P W O ' + +你也可以试着自己解码这个数字。如果内核被污染的原因只有一个,那么这很简单, +在本例中您可以通过下表找到数字。如果你需要解码有多个原因的数字,因为它是一 +个位域(bitfield),其中每个位表示一个特定类型的污染的存在或不存在,最好让 +前面提到的脚本来处理。但是如果您需要快速看一下,可以使用这个shell命令来检查 +设置了哪些位:: + + $ for i in $(seq 18); do echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));done + +污染状态代码表 +~~~~~~~~~~~~~~~ + +=== ===== ====== ======================================================== + 位 日志 数字 内核被污染的原因 +=== ===== ====== ======================================================== + 0 G/P 1 已加载专用模块 + 1 _/F 2 模块被强制加载 + 2 _/S 4 内核运行在不合规范的系统上 + 3 _/R 8 模块被强制卸载 + 4 _/M 16 处理器报告了机器检测异常(MCE) + 5 _/B 32 引用了错误的页或某些意外的页标志 + 6 _/U 64 用户空间应用程序请求的污染 + 7 _/D 128 内核最近死机了,即曾出现OOPS或BUG + 8 _/A 256 ACPI表被用户覆盖 + 9 _/W 512 内核发出警告 + 10 _/C 1024 已加载staging驱动程序 + 11 _/I 2048 已应用平台固件缺陷的解决方案 + 12 _/O 4096 已加载外部构建(“树外”)模块 + 13 _/E 8192 已加载未签名的模块 + 14 _/L 16384 发生软锁定 + 15 _/K 32768 内核已实时打补丁 + 16 _/X 65536 备用污染,为发行版定义并使用 + 17 _/T 131072 内核是用结构随机化插件构建的 +=== ===== ====== ======================================================== + +注:字符 ``_`` 表示空白,以便于阅读表。 + +污染的更详细解释 +~~~~~~~~~~~~~~~~~ + + 0) ``G`` 加载的所有模块都有GPL或兼容许可证, ``P`` 加载了任何专有模块。 + 没有MODULE_LICENSE(模块许可证)或MODULE_LICENSE未被insmod认可为GPL + 兼容的模块被认为是专有的。 + + + 1) ``F`` 任何模块被 ``insmod -f`` 强制加载, ``' '`` 所有模块正常加载。 + + 2) ``S`` 内核运行在不合规范的处理器或系统上:硬件已运行在不受支持的配置中, + 因此无法保证正确执行。内核将被污染,例如: + + - 在x86上:PAE是通过intel CPU(如Pentium M)上的forcepae强制执行的,这些 + CPU不报告PAE,但可能有功能实现,SMP内核在非官方支持的SMP Athlon CPU上 + 运行,MSR被暴露到用户空间中。 + - 在arm上:在某些CPU(如Keystone 2)上运行的内核,没有启用某些内核特性。 + - 在arm64上:CPU之间存在不匹配的硬件特性,引导加载程序以不同的模式引导CPU。 + - 某些驱动程序正在被用在不受支持的体系结构上(例如x86_64以外的其他系统 + 上的scsi/snic,非x86/x86_64/itanium上的scsi/ips,已经损坏了arm64上 + irqchip/irq-gic的固件设置…)。 + + 3) ``R`` 模块被 ``rmmod -f`` 强制卸载, ``' '`` 所有模块都正常卸载。 + + 4) ``M`` 任何处理器报告了机器检测异常, ``' '`` 未发生机器检测异常。 + + 5) ``B`` 页面释放函数发现错误的页面引用或某些意外的页面标志。这表示硬件问题 + 或内核错误;日志中应该有其他信息指示发生此污染的原因。 + + 6) ``U`` 用户或用户应用程序特意请求设置受污染标志,否则应为 ``' '`` 。 + + 7) ``D`` 内核最近死机了,即出现了OOPS或BUG。 + + 8) ``A`` ACPI表被重写。 + + 9) ``W`` 内核之前已发出过警告(尽管有些警告可能会设置更具体的污染标志)。 + + 10) ``C`` 已加载staging驱动程序。 + + 11) ``I`` 内核正在处理平台固件(BIOS或类似软件)中的严重错误。 + + 12) ``O`` 已加载外部构建(“树外”)模块。 + + 13) ``E`` 在支持模块签名的内核中加载了未签名的模块。 + + 14) ``L`` 系统上先前发生过软锁定。 + + 15) ``K`` 内核已经实时打了补丁。 + + 16) ``X`` 备用污染,由Linux发行版定义和使用。 + + 17) ``T`` 内核构建时使用了randstruct插件,它可以有意生成非常不寻常的内核结构 + 布局(甚至是性能病态的布局),这在调试时非常有用。于构建时设置。 diff --git a/Documentation/translations/zh_CN/admin-guide/unicode.rst b/Documentation/translations/zh_CN/admin-guide/unicode.rst new file mode 100644 index 0000000000000000000000000000000000000000..b0b08d2b6eb794be3f28be226b3a6fbb0841b532 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/unicode.rst @@ -0,0 +1,170 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/admin-guide/unicode.rst + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +Unicode(统一码)支持 +====================== + + (英文版)上次更新:2005-01-17,版本号 1.4 + +此文档由H. Peter Anvin <unicode@lanana.org>管理,是Linux注册名称与编号管理局 +(Linux Assigned Names And Numbers Authority,LANANA)项目的一部分。 +现行版本请见: + + http://www.lanana.org/docs/unicode/admin-guide/unicode.rst + +简介 +----- + +Linux内核代码已被重写以使用Unicode来将字符映射到字体。下载一个Unicode到字体 +(Unicode-to-font)表,八位字符集与UTF-8模式都将改用此字体来显示。 + +这微妙地改变了八位字符表的语义。现在的四个字符表是: + +=============== =============================== ================ +映射代号 映射名称 Escape代码 (G0) +=============== =============================== ================ +LAT1_MAP Latin-1 (ISO 8859-1) ESC ( B +GRAF_MAP DEC VT100 pseudographics ESC ( 0 +IBMPC_MAP IBM code page 437 ESC ( U +USER_MAP User defined ESC ( K +=============== =============================== ================ + +特别是 ESC ( U 不再是“直通字体”,因为字体可能与IBM字符集完全不同。 +例如,即使加载了一个Latin-1字体,也允许使用块图形(block graphics)。 + +请注意,尽管这些代码与ISO 2022类似,但这些代码及其用途都与ISO 2022不匹配; +Linux有两个八位代码(G0和G1),而ISO 2022有四个七位代码(G0-G3)。 + +根据Unicode标准/ISO 10646,U+F000到U+F8FF被保留用于操作系统范围内的分配 +(Unicode标准将其称为“团体区域(Corporate Zone)”,因为这对于Linux是不准确 +的,所以我们称之为“Linux区域”)。选择U+F000作为起点,因为它允许直接映射 +区域以2的大倍数开始(以防需要1024或2048个字符的字体)。这就留下U+E000到 +U+EFFF作为最终用户区。 + +[v1.2]:Unicodes范围从U+F000到U+F7FF已经被硬编码为直接映射到加载的字体, +绕过了翻译表。用户定义的映射现在默认为U+F000到U+F0FF,模拟前述行为。实际上, +此范围可能较短;例如,vgacon只能处理256字符(U+F000..U+F0FF)或512字符 +(U+F000..U+F1FF)字体。 + +Linux 区域中定义的实际字符 +--------------------------- + +此外,还定义了Unicode 1.1.4中不存在的以下字符;这些字符由DEC VT图形映射使用。 +[v1.2]此用法已过时,不应再使用;请参见下文。 + +====== ====================================== +U+F800 DEC VT GRAPHICS HORIZONTAL LINE SCAN 1 +U+F801 DEC VT GRAPHICS HORIZONTAL LINE SCAN 3 +U+F803 DEC VT GRAPHICS HORIZONTAL LINE SCAN 7 +U+F804 DEC VT GRAPHICS HORIZONTAL LINE SCAN 9 +====== ====================================== + +DEC VT220使用6x10字符矩阵,这些字符在DEC VT图形字符集中形成一个平滑的过渡。 +我省略了扫描5行,因为它也被用作块图形字符,因此被编码为U+2500 FORMS LIGHT +HORIZONTAL。 + +[v1.3]:这些字符已正式添加到Unicode 3.2.0中;它们在U+23BA、U+23BB、U+23BC、 +U+23BD处添加。Linux现在使用新值。 + +[v1.2]:添加了以下字符来表示常见的键盘符号,这些符号不太可能被添加到Unicode +中,因为它们非常讨厌地取决于特定供应商。当然,这是糟糕设计的一个好例子。 + +====== ====================================== +U+F810 KEYBOARD SYMBOL FLYING FLAG +U+F811 KEYBOARD SYMBOL PULLDOWN MENU +U+F812 KEYBOARD SYMBOL OPEN APPLE +U+F813 KEYBOARD SYMBOL SOLID APPLE +====== ====================================== + +克林贡(Klingon)语支持 +------------------------ + +1996年,Linux是世界上第一个添加对人工语言克林贡支持的操作系统,克林贡是由 +Marc Okrand为《星际迷航》电视连续剧创造的。这种编码后来被征募Unicode注册表 +(ConScript Unicode Registry,CSUR)采用,并建议(但最终被拒绝)纳入Unicode +平面一。不过,它仍然是Linux区域中的Linux/CSUR私有分配。 + +这种编码已经得到克林贡语言研究所(Klingon Language Institute)的认可。 +有关更多信息,请联系他们: + + http://www.kli.org/ + +由于Linux CZ开头部分的字符大多是dingbats/symbols/forms类型,而且这是一种 +语言,因此根据标准Unicode惯例,我将它放置在16单元的边界上。 + +.. note:: + + 这个范围现在由征募Unicode注册表正式管理。规范性引用文件为: + + https://www.evertype.com/standards/csur/klingon.html + +克林贡语有一个26个字符的字母表,一个10位数的位置数字书写系统,从左到右 +,从上到下书写。 + +克林贡字母的几种字形已经被提出。但是由于这组符号看起来始终是一致的,只有实际 +的形状不同,因此按照标准Unicode惯例,这些差异被认为是字体变体。 + +====== ======================================================= +U+F8D0 KLINGON LETTER A +U+F8D1 KLINGON LETTER B +U+F8D2 KLINGON LETTER CH +U+F8D3 KLINGON LETTER D +U+F8D4 KLINGON LETTER E +U+F8D5 KLINGON LETTER GH +U+F8D6 KLINGON LETTER H +U+F8D7 KLINGON LETTER I +U+F8D8 KLINGON LETTER J +U+F8D9 KLINGON LETTER L +U+F8DA KLINGON LETTER M +U+F8DB KLINGON LETTER N +U+F8DC KLINGON LETTER NG +U+F8DD KLINGON LETTER O +U+F8DE KLINGON LETTER P +U+F8DF KLINGON LETTER Q + - Written <q> in standard Okrand Latin transliteration +U+F8E0 KLINGON LETTER QH + - Written <Q> in standard Okrand Latin transliteration +U+F8E1 KLINGON LETTER R +U+F8E2 KLINGON LETTER S +U+F8E3 KLINGON LETTER T +U+F8E4 KLINGON LETTER TLH +U+F8E5 KLINGON LETTER U +U+F8E6 KLINGON LETTER V +U+F8E7 KLINGON LETTER W +U+F8E8 KLINGON LETTER Y +U+F8E9 KLINGON LETTER GLOTTAL STOP + +U+F8F0 KLINGON DIGIT ZERO +U+F8F1 KLINGON DIGIT ONE +U+F8F2 KLINGON DIGIT TWO +U+F8F3 KLINGON DIGIT THREE +U+F8F4 KLINGON DIGIT FOUR +U+F8F5 KLINGON DIGIT FIVE +U+F8F6 KLINGON DIGIT SIX +U+F8F7 KLINGON DIGIT SEVEN +U+F8F8 KLINGON DIGIT EIGHT +U+F8F9 KLINGON DIGIT NINE + +U+F8FD KLINGON COMMA +U+F8FE KLINGON FULL STOP +U+F8FF KLINGON SYMBOL FOR EMPIRE +====== ======================================================= + +其他虚构和人工字母 +------------------- + +自从分配了克林贡Linux Unicode块之后,John Cowan <jcowan@reutershealth.com> +和 Michael Everson <everson@evertype.com> 建立了一个虚构和人工字母的注册表。 +征募Unicode注册表请访问: + + https://www.evertype.com/standards/csur/ + +所使用的范围位于最终用户区域的低端,因此无法进行规范化分配,但建议希望对虚构 +字母进行编码的人员使用这些代码,以实现互操作性。对于克林贡语,CSUR采用了Linux +编码。CSUR的人正在推动将Tengwar和Cirth添加到Unicode平面一;将克林贡添加到 +Unicode平面一被拒绝,因此上述编码仍然是官方的。 diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..f1fa71e45c7721180984d19b05787f48b06b25dc --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -0,0 +1,126 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../core-api/irq/index` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_core-api_index.rst: + + +=========== +核心API文档 +=========== + +这是核心内核API手册的首页。 非常感谢为本手册转换(和编写!)的文档! + +核心实用程序 +============ + +本节包含通用的和“核心中的核心”文档。 第一部分是 docbook 时期遗留下 +来的大量 kerneldoc 信息;有朝一日,若有人有动力的话,应当把它们拆分 +出来。 + +Todolist: + + kernel-api + workqueue + printk-basics + printk-formats + symbol-namespaces + +数据结构和低级实用程序 +====================== + +在整个内核中使用的函数库。 + +Todolist: + + kobject + kref + assoc_array + xarray + idr + circular-buffers + rbtree + generic-radix-tree + packing + bus-virt-phys-mapping + this_cpu_ops + timekeeping + errseq + +并发原语 +======== + +Linux如何让一切同时发生。 详情请参阅 +:doc:`/locking/index` + +.. toctree:: + :maxdepth: 1 + + irq/index + +Todolist: + + refcount-vs-atomic + local_ops + padata + ../RCU/index + +低级硬件管理 +============ + +缓存管理,CPU热插拔管理等。 + +Todolist: + + cachetlb + cpu_hotplug + memory-hotplug + genericirq + protection-keys + + +内存管理 +======== + +如何在内核中分配和使用内存。请注意,在 +:doc:`/vm/index` 中有更多的内存管理文档。 + +Todolist: + + memory-allocation + unaligned-memory-access + dma-api + dma-api-howto + dma-attributes + dma-isa-lpc + mm-api + genalloc + pin_user_pages + boot-time-mm + gfp_mask-from-fs-io + +内核调试的接口 +============== + +Todolist: + + debug-objects + tracepoint + debugging-via-ohci1394 + +其它文档 +======== + +不适合放在其它地方或尚未归类的文件; + +Todolist: + + librs + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/translations/zh_CN/core-api/irq/concepts.rst b/Documentation/translations/zh_CN/core-api/irq/concepts.rst new file mode 100644 index 0000000000000000000000000000000000000000..41455bf0f783c5b80aaeb8df631e824c5f17e90f --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/irq/concepts.rst @@ -0,0 +1,24 @@ +.. include:: ../../disclaimer-zh_CN.rst + +:Original: :doc:`../../../../core-api/irq/concepts` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_concepts.rst: + + +=========== +什么是IRQ? +=========== + +IRQ (Interrupt ReQuest) 指来自设备的中断请求。 +目前,它们可以通过一个引脚或通过一个数据包进入。 +多个设备可以连接到同一个引脚,从而共享一个IRQ。 + +IRQ编号是用来描述硬件中断源的内核标识符。通常它是一个到全局irq_desc数组的索引, +但是除了在linux/interrupt.h中实现的之外,其它细节是体系结构特征相关的。 + +IRQ编号是对机器上可能的中断源的枚举。通常枚举的是系统中所有中断控制器的输入引脚 +编号。在ISA(工业标准体系结构)的情况下所枚举的是两个i8259中断控制器的16个输入引脚。 + +体系结构可以给IRQ号赋予额外的含义,在涉及到硬件手动配置的情况下,我们鼓励这样做。 +ISA IRQ是赋予这种额外含义的一个典型例子。 diff --git a/Documentation/translations/zh_CN/core-api/irq/index.rst b/Documentation/translations/zh_CN/core-api/irq/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..910ccabf041f3140e2c9950ab15d00d4519d29ce --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/irq/index.rst @@ -0,0 +1,19 @@ +.. include:: ../../disclaimer-zh_CN.rst + +:Original: :doc:`../../../../core-api/irq/index` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_irq_index.rst: + + +==== +IRQs +==== + +.. toctree:: + :maxdepth: 1 + + concepts + irq-affinity + irq-domain + irqflags-tracing diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst b/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst new file mode 100644 index 0000000000000000000000000000000000000000..82a4428f22fdf883a27cedc94fa397f808c22535 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst @@ -0,0 +1,76 @@ +.. include:: ../../disclaimer-zh_CN.rst + +:Original: :doc:`../../../../core-api/irq/irq-affinity` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_irq-affinity.rst: + + +============== +SMP IRQ 亲和性 +============== + +变更记录: + - 作者:最初由Ingo Molnar <mingo@redhat.com>开始撰写 + - 后期更新维护: Max Krasnyansky <maxk@qualcomm.com> + + +/proc/irq/IRQ#/smp_affinity和/proc/irq/IRQ#/smp_affinity_list指定了哪些CPU能 +够关联到一个给定的IRQ源,这两个文件包含了这些指定cpu的cpu位掩码(smp_affinity)和cpu列 +表(smp_affinity_list)。它不允许关闭所有CPU, 同时如果IRQ控制器不支持中断请求亲和 +(IRQ affinity),那么所有cpu的默认值将保持不变(即关联到所有CPU). + +/proc/irq/default_smp_affinity指明了适用于所有非激活IRQ的默认亲和性掩码。一旦IRQ被 +分配/激活,它的亲和位掩码将被设置为默认掩码。然后可以如上所述改变它。默认掩码是0xffffffff。 + +下面是一个先将IRQ44(eth1)限制在CPU0-3上,然后限制在CPU4-7上的例子(这是一个8CPU的SMP box) + +:: + + [root@moon 44]# cd /proc/irq/44 + [root@moon 44]# cat smp_affinity + ffffffff + + [root@moon 44]# echo 0f > smp_affinity + [root@moon 44]# cat smp_affinity + 0000000f + [root@moon 44]# ping -f h + PING hell (195.4.7.3): 56 data bytes + ... + --- hell ping statistics --- + 6029 packets transmitted, 6027 packets received, 0% packet loss + round-trip min/avg/max = 0.1/0.1/0.4 ms + [root@moon 44]# cat /proc/interrupts | grep 'CPU\|44:' + CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 + 44: 1068 1785 1785 1783 0 0 0 0 IO-APIC-level eth1 + +从上面一行可以看出,IRQ44只传递给前四个处理器(0-3)。 +现在让我们把这个IRQ限制在CPU(4-7)。 + +:: + + [root@moon 44]# echo f0 > smp_affinity + [root@moon 44]# cat smp_affinity + 000000f0 + [root@moon 44]# ping -f h + PING hell (195.4.7.3): 56 data bytes + .. + --- hell ping statistics --- + 2779 packets transmitted, 2777 packets received, 0% packet loss + round-trip min/avg/max = 0.1/0.5/585.4 ms + [root@moon 44]# cat /proc/interrupts | 'CPU\|44:' + CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 + 44: 1068 1785 1785 1783 1784 1069 1070 1069 IO-APIC-level eth1 + +这次IRQ44只传递给最后四个处理器。 +即CPU0-3的计数器没有变化。 + +下面是一个将相同的irq(44)限制在cpus 1024到1031的例子 + +:: + + [root@moon 44]# echo 1024-1031 > smp_affinity_list + [root@moon 44]# cat smp_affinity_list + 1024-1031 + +需要注意的是,如果要用位掩码来做这件事,就需要32个为0的位掩码来追踪其相关的一个。 diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst new file mode 100644 index 0000000000000000000000000000000000000000..3c82dd307a46cafa35364c5d161b4305ee960e3f --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst @@ -0,0 +1,227 @@ +.. include:: ../../disclaimer-zh_CN.rst + +:Original: :doc:`../../../../core-api/irq/irq-domain` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_irq-domain.rst: + + +======================= +irq_domain 中断号映射库 +======================= + +目前Linux内核的设计使用了一个巨大的数字空间,每个独立的IRQ源都被分配了一个不 +同的数字。 +当只有一个中断控制器时,这很简单,但在有多个中断控制器的系统中,内核必须确保每 +个中断控制器都能得到非重复的Linux IRQ号(数字)分配。 + +注册为唯一的irqchips的中断控制器编号呈现出上升的趋势:例如GPIO控制器等不同 +种类的子驱动程序通过将其中断处理程序建模为irqchips,即实际上是级联中断控制器, +避免了重新实现与IRQ核心系统相同的回调机制。 + +在这里,中断号与硬件中断号离散了所有种类的对应关系:而在过去,IRQ号可以选择, +使它们与硬件IRQ线进入根中断控制器(即实际向CPU发射中断线的组件)相匹配,现 +在这个编号仅仅是一个数字。 + +出于这个原因,我们需要一种机制将控制器本地中断号(即硬件irq编号)与Linux IRQ +号分开。 + +irq_alloc_desc*() 和 irq_free_desc*() API 提供了对irq号的分配,但它们不 +提供任何对控制器本地IRQ(hwirq)号到Linux IRQ号空间的反向映射的支持。 + +irq_domain 库在 irq_alloc_desc*() API 的基础上增加了 hwirq 和 IRQ 号码 +之间的映射。 相比于中断控制器驱动开放编码自己的反向映射方案,我们更喜欢用 +irq_domain来管理映射。 + +irq_domain还实现了从抽象的irq_fwspec结构体到hwirq号的转换(到目前为止是 +Device Tree和ACPI GSI),并且可以很容易地扩展以支持其它IRQ拓扑数据源。 + +irq_domain的用法 +================ + +中断控制器驱动程序通过以下方式创建并注册一个irq_domain。调用 +irq_domain_add_*() 或 irq_domain_create_*()函数之一(每个映射方法都有不 +同的分配器函数,后面会详细介绍)。 函数成功后会返回一个指向irq_domain的指针。 +调用者必须向分配器函数提供一个irq_domain_ops结构体。 + +在大多数情况下,irq_domain在开始时是空的,没有任何hwirq和IRQ号之间的映射。 +通过调用irq_create_mapping()将映射添加到irq_domain中,该函数接受 +irq_domain和一个hwirq号作为参数。 如果hwirq的映射还不存在,那么它将分配 +一个新的Linux irq_desc,将其与hwirq关联起来,并调用.map()回调,这样驱动 +程序就可以执行任何必要的硬件设置。 + +当接收到一个中断时,应该使用irq_find_mapping()函数从hwirq号中找到 +Linux IRQ号。 + +在调用irq_find_mapping()之前,至少要调用一次irq_create_mapping()函数, +以免描述符不能被分配。 + +如果驱动程序有Linux的IRQ号或irq_data指针,并且需要知道相关的hwirq号(比 +如在irq_chip回调中),那么可以直接从irq_data->hwirq中获得。 + +irq_domain映射的类型 +==================== + +从hwirq到Linux irq的反向映射有几种机制,每种机制使用不同的分配函数。应该 +使用哪种反向映射类型取决于用例。 下面介绍每一种反向映射类型: + +线性映射 +-------- + +:: + + irq_domain_add_linear() + irq_domain_create_linear() + +线性反向映射维护了一个固定大小的表,该表以hwirq号为索引。 当一个hwirq被映射 +时,会给hwirq分配一个irq_desc,并将irq号存储在表中。 + +当最大的hwirq号固定且数量相对较少时,线性图是一个很好的选择(~<256)。 这种 +映射的优点是固定时间查找IRQ号,而且irq_descs只分配给在用的IRQ。 缺点是该表 +必须尽可能大的hwirq号。 + +irq_domain_add_linear()和irq_domain_create_linear()在功能上是等价的, +除了第一个参数不同--前者接受一个Open Firmware特定的 'struct device_node' 而 +后者接受一个更通用的抽象 'struct fwnode_handle' 。 + +大多数驱动应该使用线性映射 + +树状映射 +-------- + +:: + + irq_domain_add_tree() + irq_domain_create_tree() + +irq_domain维护着从hwirq号到Linux IRQ的radix的树状映射。 当一个hwirq被映射时, +一个irq_desc被分配,hwirq被用作radix树的查找键。 + +如果hwirq号可以非常大,树状映射是一个很好的选择,因为它不需要分配一个和最大hwirq +号一样大的表。 缺点是,hwirq到IRQ号的查找取决于表中有多少条目。 + +irq_domain_add_tree()和irq_domain_create_tree()在功能上是等价的,除了第一 +个参数不同——前者接受一个Open Firmware特定的 'struct device_node' ,而后者接受 +一个更通用的抽象 'struct fwnode_handle' 。 + +很少有驱动应该需要这个映射。 + +无映射 +------ + +:: + + irq_domain_add_nomap() + +当硬件中的hwirq号是可编程的时候,就可以采用无映射类型。 在这种情况下,最好将 +Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create_direct_mapping() +会分配一个Linux IRQ号,并调用.map()回调,这样驱动就可以将Linux IRQ号编入硬件中。 + +大多数驱动程序不能使用这个映射。 + +传统映射类型 +------------ + +:: + + irq_domain_add_simple() + irq_domain_add_legacy() + irq_domain_add_legacy_isa() + irq_domain_create_simple() + irq_domain_create_legacy() + +传统映射是已经为 hwirqs 分配了一系列 irq_descs 的驱动程序的特殊情况。 当驱动程 +序不能立即转换为使用线性映射时,就会使用它。 例如,许多嵌入式系统板卡支持文件使用 +一组用于IRQ号的定义(#define),这些定义被传递给struct设备注册。 在这种情况下, +不能动态分配Linux IRQ号,应该使用传统映射。 + +传统映射假设已经为控制器分配了一个连续的IRQ号范围,并且可以通过向hwirq号添加一 +个固定的偏移来计算IRQ号,反之亦然。 缺点是需要中断控制器管理IRQ分配,并且需要为每 +个hwirq分配一个irq_desc,即使它没有被使用。 + +只有在必须支持固定的IRQ映射时,才应使用传统映射。 例如,ISA控制器将使用传统映射来 +映射Linux IRQ 0-15,这样现有的ISA驱动程序就能得到正确的IRQ号。 + +大多数使用传统映射的用户应该使用irq_domain_add_simple()或 +irq_domain_create_simple(),只有在系统提供IRQ范围时才会使用传统域,否则将使用 +线性域映射。这个调用的语义是这样的:如果指定了一个IRQ范围,那么 描述符将被即时分配 +给它,如果没有范围被分配,它将不会执行 irq_domain_add_linear() 或 +irq_domain_create_linear(),这意味着 *no* irq 描述符将被分配。 + +一个简单域的典型用例是,irqchip供应商同时支持动态和静态IRQ分配。 + +为了避免最终出现使用线性域而没有描述符被分配的情况,确保使用简单域的驱动程序在任何 +irq_find_mapping()之前调用irq_create_mapping()是非常重要的,因为后者实际上 +将用于静态IRQ分配情况。 + +irq_domain_add_simple()和irq_domain_create_simple()以及 +irq_domain_add_legacy()和irq_domain_create_legacy()在功能上是等价的,只 +是第一个参数不同--前者接受Open Firmware特定的 'struct device_node' ,而后者 +接受一个更通用的抽象 'struct fwnode_handle' 。 + +IRQ域层级结构 +------------- + +在某些架构上,可能有多个中断控制器参与将一个中断从设备传送到目标CPU。 +让我们来看看x86平台上典型的中断传递路径吧 +:: + + Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU + +涉及到的中断控制器有三个: + +1) IOAPIC 控制器 +2) 中断重映射控制器 +3) Local APIC 控制器 + +为了支持这样的硬件拓扑结构,使软件架构与硬件架构相匹配,为每个中断控制器建立一 +个irq_domain数据结构,并将这些irq_domain组织成层次结构。 + +在建立irq_domain层次结构时,靠近设备的irq_domain为子域,靠近CPU的 +irq_domain为父域。所以在上面的例子中,将建立如下的层次结构。 +:: + + CPU Vector irq_domain (root irq_domain to manage CPU vectors) + ^ + | + Interrupt Remapping irq_domain (manage irq_remapping entries) + ^ + | + IOAPIC irq_domain (manage IOAPIC delivery entries/pins) + +使用irq_domain层次结构的主要接口有四个: + +1) irq_domain_alloc_irqs(): 分配IRQ描述符和与中断控制器相关的资源来传递这些中断。 +2) irq_domain_free_irqs(): 释放IRQ描述符和与这些中断相关的中断控制器资源。 +3) irq_domain_activate_irq(): 激活中断控制器硬件以传递中断。 +4) irq_domain_deactivate_irq(): 停用中断控制器硬件,停止传递中断。 + +为了支持irq_domain层次结构,需要做如下修改: + +1) 一个新的字段 'parent' 被添加到irq_domain结构中;它用于维护irq_domain的层次信息。 +2) 一个新的字段 'parent_data' 被添加到irq_data结构中;它用于建立层次结构irq_data以 + 匹配irq_domain层次结构。irq_data用于存储irq_domain指针和硬件irq号。 +3) 新的回调被添加到irq_domain_ops结构中,以支持层次结构的irq_domain操作。 + +在支持分层irq_domain和分层irq_data准备就绪后,为每个中断控制器建立一个irq_domain结 +构,并为每个与IRQ相关联的irq_domain分配一个irq_data结构。现在我们可以再进一步支持堆 +栈式(层次结构)的irq_chip。也就是说,一个irq_chip与层次结构中的每个irq_data相关联。 +一个子irq_chip可以自己或通过与它的父irq_chip合作来实现一个所需的操作。 + +通过堆栈式的irq_chip,中断控制器驱动只需要处理自己管理的硬件,在需要的时候可以向其父 +irq_chip请求服务。所以我们可以实现更简洁的软件架构。 + +为了让中断控制器驱动程序支持irq_domain层次结构,它需要做到以下几点: + +1) 实现 irq_domain_ops.alloc 和 irq_domain_ops.free +2) 可选择地实现 irq_domain_ops.activate 和 irq_domain_ops.deactivate. +3) 可选择地实现一个irq_chip来管理中断控制器硬件。 +4) 不需要实现irq_domain_ops.map和irq_domain_ops.unmap,它们在层次结构 + irq_domain中是不用的。 + +irq_domain层次结构绝不是x86特有的,大量用于支持其他架构,如ARM、ARM64等。 + +调试功能 +======== + +打开CONFIG_GENERIC_IRQ_DEBUGFS,可让IRQ子系统的大部分内部结构都在debugfs中暴露出来。 diff --git a/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst b/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst new file mode 100644 index 0000000000000000000000000000000000000000..c889bd0f65d948d9054c2fc9cbc2f524faaf4582 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst @@ -0,0 +1,45 @@ +.. include:: ../../disclaimer-zh_CN.rst + +:Original: :doc:`../../../../core-api/irq/irqflags-tracing` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_irqflags-tracing.rst: + + +================= +IRQ-flags状态追踪 +================= + +:Author: 最初由Ingo Molnar <mingo@redhat.com>开始撰写 + +“irq-flags tracing”(中断标志追踪)功能可以 “追踪” hardirq和softirq的状态,它让 +感兴趣的子系统有机会了解到到内核中发生的每一个 +hardirqs-off/hardirqs-on、softirqs-off/softirqs-on事件。 + +CONFIG_TRACE_IRQFLAGS_SUPPORT是通用锁调试代码提供的CONFIG_PROVE_SPIN_LOCKING +和CONFIG_PROVE_RW_LOCKING所需要的。否则将只有CONFIG_PROVE_MUTEX_LOCKING和 +CONFIG_PROVE_RWSEM_LOCKING在一个架构上被提供--这些都是不在IRQ上下文中使用的 +锁API。(rwsems的一个异常是可以解决的) + +架构对这一点的支持当然不属于“微不足道”的范畴,因为很多低级的汇编代码都要处理irq-flags +的状态变化。但是一个架构可以以一种相当直接且无风险的方式启用irq-flags-tracing。 + +架构如果想支持这个,需要先做一些代码组织上的改变: + +- 在他们的arch级Kconfig文件中添加并启用TRACE_IRQFLAGS_SUPPORT。 + +然后还需要做一些功能上的改变来实现对irq-flags-tracing的支持: + +- 在低级入口代码中增加(构建条件)对trace_hardirqs_off()/trace_hardirqs_on() + 函数的调用。锁验证器会密切关注 “real”的irq-flags是否与 “virtual”的irq-flags + 状态相匹配,如果两者不匹配,则会发出警告(并关闭自己)。通常维护arch中 + irq-flags-track的大部分时间都是在这种状态下度过的:看看lockdep的警告,试着 + 找出我们还没有搞定的汇编代码。修复并重复。一旦系统启动,并且在irq-flags跟踪功 + 能中没有出现lockdep警告的情况下,arch支持就完成了。 + +- 如果该架构有不可屏蔽的中断,那么需要通过lockdep_off()/lockdep_on()将这些中 + 断从irq跟踪[和锁验证]机制中排除。 + + 一般来说,在一个架构中,不完整的irq-flags-tracing实现是没有风险的:lockdep + 会检测到这一点,并将自己关闭。即锁验证器仍然可靠。应该不会因为irq-tracing的错 + 误而崩溃。(除非通过修改不该修改的条件来更改汇编或寄存器而破坏其他代码) diff --git a/Documentation/translations/zh_CN/cpu-freq/core.rst b/Documentation/translations/zh_CN/cpu-freq/core.rst new file mode 100644 index 0000000000000000000000000000000000000000..19fb9c029cfea60db973046dd704da70a9a098db --- /dev/null +++ b/Documentation/translations/zh_CN/cpu-freq/core.rst @@ -0,0 +1,105 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../cpu-freq/core` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_core.rst: + + +==================================== +CPUFreq核心和CPUFreq通知器的通用说明 +==================================== + +作者: + - Dominik Brodowski <linux@brodo.de> + - David Kimdon <dwhedon@debian.org> + - Rafael J. Wysocki <rafael.j.wysocki@intel.com> + - Viresh Kumar <viresh.kumar@linaro.org> + +.. 目录: + + 1. CPUFreq核心和接口 + 2. CPUFreq通知器 + 3. 含有Operating Performance Point (OPP)的CPUFreq表的生成 + +1. CPUFreq核心和接口 +====================== + +cpufreq核心代码位于drivers/cpufreq/cpufreq.c中。这些cpufreq代码为CPUFreq架构的驱 +动程序(那些操作硬件切换频率的代码)以及 "通知器 "提供了一个标准化的接口。 +这些是设备驱动程序或需要了解策略变化的其它内核部分(如 ACPI 热量管理)或所有频率更改(除 +计时代码外),甚至需要强制确定速度限制的通知器(如 ARM 架构上的 LCD 驱动程序)。 +此外, 内核 "常数" loops_per_jiffy会根据频率变化而更新。 + +cpufreq策略的引用计数由 cpufreq_cpu_get 和 cpufreq_cpu_put 来完成,以确保 cpufreq 驱 +动程序被正确地注册到核心中,并且驱动程序在 cpufreq_put_cpu 被调用之前不会被卸载。这也保证 +了每个CPU核的cpufreq 策略在使用期间不会被释放。 + +2. CPUFreq 通知器 +==================== + +CPUFreq通知器符合标准的内核通知器接口。 +关于通知器的细节请参阅 linux/include/linux/notifier.h。 + +这里有两个不同的CPUfreq通知器 - 策略通知器和转换通知器。 + + +2.1 CPUFreq策略通知器 +---------------------------- + +当创建或移除策略时,这些都会被通知。 + +阶段是在通知器的第二个参数中指定的。当第一次创建策略时,阶段是CPUFREQ_CREATE_POLICY,当 +策略被移除时,阶段是CPUFREQ_REMOVE_POLICY。 + +第三个参数 ``void *pointer`` 指向一个结构体cpufreq_policy,其包括min,max(新策略的下限和 +上限(单位为kHz))这几个值。 + + +2.2 CPUFreq转换通知器 +-------------------------------- + +当CPUfreq驱动切换CPU核心频率时,策略中的每个在线CPU都会收到两次通知,这些变化没有任何外部干 +预。 + +第二个参数指定阶段 - CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE. + +第三个参数是一个包含如下值的结构体cpufreq_freqs: + +===== ==================== +cpu 受影响cpu的编号 +old 旧频率 +new 新频率 +flags cpufreq驱动的标志 +===== ==================== + +3. 含有Operating Performance Point (OPP)的CPUFreq表的生成 +================================================================== +关于OPP的细节请参阅 Documentation/power/opp.rst + +dev_pm_opp_init_cpufreq_table - + 这个功能提供了一个随时可用的转换程序,用来将OPP层关于可用频率的内部信息翻译成一种容易提供给 + cpufreq的格式。 + + .. Warning:: + + 不要在中断上下文中使用此函数。 + + 例如:: + + soc_pm_init() + { + /* Do things */ + r = dev_pm_opp_init_cpufreq_table(dev, &freq_table); + if (!r) + policy->freq_table = freq_table; + /* Do other things */ + } + + .. note:: + + 该函数只有在CONFIG_PM_OPP之外还启用了CONFIG_CPU_FREQ时才可用。 + +dev_pm_opp_free_cpufreq_table + 释放dev_pm_opp_init_cpufreq_table分配的表。 diff --git a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst new file mode 100644 index 0000000000000000000000000000000000000000..0ca2cb64666609f534e5c5d932d2c2b3f7b5a0f6 --- /dev/null +++ b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst @@ -0,0 +1,259 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../cpu-freq/cpu-drivers` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_cpu-drivers.rst: + + +======================================= +如何实现一个新的CPUFreq处理器驱动程序? +======================================= + +作者: + + + - Dominik Brodowski <linux@brodo.de> + - Rafael J. Wysocki <rafael.j.wysocki@intel.com> + - Viresh Kumar <viresh.kumar@linaro.org> + +.. Contents + + 1. 怎么做? + 1.1 初始化 + 1.2 Per-CPU 初始化 + 1.3 验证 + 1.4 target/target_index 或 setpolicy? + 1.5 target/target_index + 1.6 setpolicy + 1.7 get_intermediate 与 target_intermediate + 2. 频率表助手 + + + +1. 怎么做? +=========== + +如此,你刚刚得到了一个全新的CPU/芯片组及其数据手册,并希望为这个CPU/芯片组添加cpufreq +支持?很好,这里有一些至关重要的提示: + + +1.1 初始化 +---------- + +首先,在__initcall_level_7 (module_init())或更靠后的函数中检查这个内核是否 +运行在正确的CPU和正确的芯片组上。如果是,则使用cpufreq_register_driver()向 +CPUfreq核心层注册一个cpufreq_driver结构体。 + +结构体cpufreq_driver应该包含什么成员? + + .name - 驱动的名字。 + + .init - 一个指向per-policy初始化函数的指针。 + + .verify - 一个指向"verification"函数的指针。 + + .setpolicy 或 .fast_switch 或 .target 或 .target_index - 差异见 + 下文。 + +并且可选择 + + .flags - cpufreq核的提示。 + + .driver_data - cpufreq驱动程序的特定数据。 + + .resolve_freq - 返回最适合目标频率的频率。不过并不能改变频率。 + + .get_intermediate 和 target_intermediate - 用于在改变CPU频率时切换到稳定 + 的频率。 + + .get - 返回CPU的当前频率。 + + .bios_limit - 返回HW/BIOS对CPU的最大频率限制值。 + + .exit - 一个指向per-policy清理函数的指针,该函数在cpu热插拔过程的CPU_POST_DEAD + 阶段被调用。 + + .stop_cpu - 一个指向per-policy停止函数的指针,该函数在cpu热插拔过程的CPU_DOWN_PREPARE + 阶段被调用。 + + .suspend - 一个指向per-policy暂停函数的指针,该函数在关中断且在该策略的调节器停止 + 后被调用。 + + .resume - 一个指向per-policy恢复函数的指针,该函数在关中断且在调节器再一次开始前被 + 调用。 + + .ready - 一个指向per-policy准备函数的指针,该函数在策略完全初始化之后被调用。 + + .attr - 一个指向NULL结尾的"struct freq_attr"列表的指针,该函数允许导出值到 + sysfs。 + + .boost_enabled - 如果设置,则启用提升(boost)频率。 + + .set_boost - 一个指向per-policy函数的指针,该函数用来开启/关闭提升(boost)频率功能。 + + +1.2 Per-CPU 初始化 +------------------ + +每当一个新的CPU被注册到设备模型中,或者在cpufreq驱动注册自己之后,如果此CPU的cpufreq策 +略不存在,则会调用per-policy的初始化函数cpufreq_driver.init。请注意,.init()和.exit()程序 +只对策略调用一次,而不是对策略管理的每个CPU调用一次。它需要一个 ``struct cpufreq_policy +*policy`` 作为参数。现在该怎么做呢? + +如果有必要,请在你的CPU上激活CPUfreq功能支持。 + +然后,驱动程序必须填写以下数值: + ++-----------------------------------+--------------------------------------+ +|policy->cpuinfo.min_freq 和 | | +|policy->cpuinfo.max_freq | 该CPU支持的最低和最高频率(kHz) | +| | | +| | | ++-----------------------------------+--------------------------------------+ +|policy->cpuinfo.transition_latency | | +| | CPU在两个频率之间切换所需的时间,以 | +| | 纳秒为单位(如适用,否则指定 | +| | CPUFREQ_ETERNAL) | ++-----------------------------------+--------------------------------------+ +|policy->cur | 该CPU当前的工作频率(如适用) | +| | | ++-----------------------------------+--------------------------------------+ +|policy->min, | | +|policy->max, | | +|policy->policy and, if necessary, | | +|policy->governor | 必须包含该cpu的 “默认策略”。稍后 | +| | 会用这些值调用 | +| | cpufreq_driver.verify and either | +| | cpufreq_driver.setpolicy or | +| | cpufreq_driver.target/target_index | +| | | ++-----------------------------------+--------------------------------------+ +|policy->cpus | 用与这个CPU一起做DVFS的(在线+离线) | +| | CPU(即与它共享时钟/电压轨)的掩码更新 | +| | 这个 | +| | | ++-----------------------------------+--------------------------------------+ + +对于设置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),频率表助手可能会有帮 +助。关于它们的更多信息,请参见第2节。 + + +1.3 验证 +-------- + +当用户决定设置一个新的策略(由 “policy,governor,min,max组成”)时,必须对这个策略进行验证, +以便纠正不兼容的值。为了验证这些值,cpufreq_verify_within_limits(``struct cpufreq_policy +*policy``, ``unsigned int min_freq``, ``unsigned int max_freq``)函数可能会有帮助。 +关于频率表助手的详细内容请参见第2节。 + +您需要确保至少有一个有效频率(或工作范围)在 policy->min 和 policy->max 范围内。如果有必 +要,先增加policy->max,只有在没有办法的情况下,才减少policy->min。 + + +1.4 target 或 target_index 或 setpolicy 或 fast_switch? +------------------------------------------------------- + +大多数cpufreq驱动甚至大多数cpu频率升降算法只允许将CPU频率设置为预定义的固定值。对于这些,你 +可以使用->target(),->target_index()或->fast_switch()回调。 + +有些cpufreq功能的处理器可以自己在某些限制之间切换频率。这些应使用->setpolicy()回调。 + + +1.5. target/target_index +------------------------ + +target_index调用有两个参数:``struct cpufreq_policy * policy``和``unsigned int`` +索引(于列出的频率表)。 + +当调用这里时,CPUfreq驱动必须设置新的频率。实际频率必须由freq_table[index].frequency决定。 + +它应该总是在错误的情况下恢复到之前的频率(即policy->restore_freq),即使我们之前切换到中间频率。 + +已弃用 +---------- +目标调用有三个参数。``struct cpufreq_policy * policy``, unsigned int target_frequency, +unsigned int relation. + +CPUfreq驱动在调用这里时必须设置新的频率。实际的频率必须使用以下规则来确定。 + +- 紧跟 "目标频率"。 +- policy->min <= new_freq <= policy->max (这必须是有效的!!!) +- 如果 relation==CPUFREQ_REL_L,尝试选择一个高于或等于 target_freq 的 new_freq。("L代表 + 最低,但不能低于") +- 如果 relation==CPUFREQ_REL_H,尝试选择一个低于或等于 target_freq 的 new_freq。("H代表 + 最高,但不能高于") + +这里,频率表助手可能会帮助你--详见第2节。 + +1.6. fast_switch +---------------- + +这个函数用于从调度器的上下文进行频率切换。并非所有的驱动都要实现它,因为不允许在这个回调中睡眠。这 +个回调必须经过高度优化,以尽可能快地进行切换。 + +这个函数有两个参数: ``struct cpufreq_policy *policy`` 和 ``unsigned int target_frequency``。 + + +1.7 setpolicy +------------- + +setpolicy调用只需要一个``struct cpufreq_policy * policy``作为参数。需要将处理器内或芯片组内动态频 +率切换的下限设置为policy->min,上限设置为policy->max,如果支持的话,当policy->policy为 +CPUFREQ_POLICY_PERFORMANCE时选择面向性能的设置,当CPUFREQ_POLICY_POWERSAVE时选择面向省电的设置。 +也可以查看drivers/cpufreq/longrun.c中的参考实现。 + +1.8 get_intermediate 和 target_intermediate +-------------------------------------------- + +仅适用于 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 未设置的驱动。 + +get_intermediate应该返回一个平台想要切换到的稳定的中间频率,target_intermediate()应该将CPU设置为 +该频率,然后再跳转到'index'对应的频率。核心会负责发送通知,驱动不必在target_intermediate()或 +target_index()中处理。 + +在驱动程序不想因为某个目标频率切换到中间频率的情况下,它们可以从get_intermediate()中返回'0'。在这种情况 +下,核心将直接调用->target_index()。 + +注意:->target_index()应该在失败的情况下恢复到policy->restore_freq,因为core会为此发送通知。 + + +2. 频率表助手 +============= + +由于大多数cpufreq处理器只允许被设置为几个特定的频率,因此,一个带有一些函数的 “频率表”可能会辅助处理器驱动 +程序的一些工作。这样的 "频率表" 由一个cpufreq_frequency_table条目构成的数组组成,"driver_data" 中包 +含了驱动程序的具体数值,"frequency" 中包含了相应的频率,并设置了标志。在表的最后,需要添加一个 +cpufreq_frequency_table条目,频率设置为CPUFREQ_TABLE_END。而如果想跳过表中的一个条目,则将频率设置为 +CPUFREQ_ENTRY_INVALID。这些条目不需要按照任何特定的顺序排序,但如果它们是cpufreq 核心会对它们进行快速的DVFS, +因为搜索最佳匹配会更快。 + +如果策略在其policy->freq_table字段中包含一个有效的指针,cpufreq表就会被核心自动验证。 + +cpufreq_frequency_table_verify()保证至少有一个有效的频率在policy->min和policy->max范围内,并且所有其他 +标准都被满足。这对->verify调用很有帮助。 + +cpufreq_frequency_table_target()是对应于->target阶段的频率表助手。只要把数值传递给这个函数,这个函数就会返 +回包含CPU要设置的频率的频率表条目。 + +以下宏可以作为cpufreq_frequency_table的迭代器。 + +cpufreq_for_each_entry(pos, table) - 遍历频率表的所有条目。 + +cpufreq_for_each_valid_entry(pos, table) - 该函数遍历所有条目,不包括CPUFREQ_ENTRY_INVALID频率。 +使用参数 "pos"-一个``cpufreq_frequency_table * `` 作为循环变量,使用参数 "table"-作为你想迭代 +的``cpufreq_frequency_table * `` 。 + +例如:: + + struct cpufreq_frequency_table *pos, *driver_freq_table; + + cpufreq_for_each_entry(pos, driver_freq_table) { + /* Do something with pos */ + pos->frequency = ... + } + +如果你需要在driver_freq_table中处理pos的位置,不要减去指针,因为它的代价相当高。相反,使用宏 +cpufreq_for_each_entry_idx() 和 cpufreq_for_each_valid_entry_idx() 。 diff --git a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst new file mode 100644 index 0000000000000000000000000000000000000000..c90d1d8353ed23af62424b413bf289b3c561b9ef --- /dev/null +++ b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst @@ -0,0 +1,130 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../cpu-freq/cpufreq-stats` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_cpufreq-stats.rst: + + +========================================== +sysfs CPUFreq Stats的一般说明 +========================================== + +用户信息 + + +作者: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> + +.. Contents + + 1. 简介 + 2. 提供的统计数据(举例说明) + 3. 配置cpufreq-stats + + +1. 简介 +=============== + +cpufreq-stats是一个为每个CPU提供CPU频率统计的驱动。 +这些统计数据在/sysfs中以一堆只读接口的形式提供。这个接口(在配置好后)将出现在 +/sysfs(<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq下的一个单 +独的目录中,提供给每个CPU。 +各种统计数据将在此目录下形成只读文件。 + +此驱动是独立于任何可能运行在你所用CPU上的特定cpufreq_driver而设计的。因此,它将与所有 +cpufreq_driver一起工作。 + + +2. 提供的统计数据(举例说明) +===================================== + +cpufreq stats提供了以下统计数据(在下面详细解释)。 + +- time_in_state +- total_trans +- trans_table + +所有的统计数据将从统计驱动被载入的时间(或统计被重置的时间)开始,到某一统计数据被读取的时间为止。 +显然,统计驱动不会有任何关于统计驱动载入之前的频率转换信息。 + +:: + + <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l + total 0 + drwxr-xr-x 2 root root 0 May 14 16:06 . + drwxr-xr-x 3 root root 0 May 14 15:58 .. + --w------- 1 root root 4096 May 14 16:06 reset + -r--r--r-- 1 root root 4096 May 14 16:06 time_in_state + -r--r--r-- 1 root root 4096 May 14 16:06 total_trans + -r--r--r-- 1 root root 4096 May 14 16:06 trans_table + +- **reset** + +只写属性,可用于重置统计计数器。这对于评估不同调节器下的系统行为非常有用,且无需重启。 + + +- **time_in_state** + +此项给出了这个CPU所支持的每个频率所花费的时间。cat输出的每一行都会有"<frequency> +<time>"对,表示这个CPU在<frequency>上花费了<time>个usertime单位的时间。这里的 +usertime单位是10mS(类似于/proc中输出的其他时间)。 + +:: + + <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state + 3600000 2089 + 3400000 136 + 3200000 34 + 3000000 67 + 2800000 172488 + + +- **total_trans** + +给出了这个CPU上频率转换的总次数。cat的输出将有一个单一的计数,这就是频率转换的总数。 + +:: + + <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans + 20 + +- **trans_table** + +这将提供所有CPU频率转换的细粒度信息。这里的cat输出是一个二维矩阵,其中一个条目<i, j>(第 +i行,第j列)代表从Freq_i到Freq_j的转换次数。Freq_i行和Freq_j列遵循驱动最初提供给cpufreq +核的频率表的排序顺序,因此可以排序(升序或降序)或不排序。 这里的输出也包含了每行每列的实际 +频率值,以便更好地阅读。 + +如果转换表大于PAGE_SIZE,读取时将返回一个-EFBIG错误。 + +:: + + <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table + From : To + : 3600000 3400000 3200000 3000000 2800000 + 3600000: 0 5 0 0 0 + 3400000: 4 0 2 0 0 + 3200000: 0 1 0 2 0 + 3000000: 0 0 1 0 3 + 2800000: 0 0 0 2 0 + +3. 配置cpufreq-stats +============================ + +要在你的内核中配置cpufreq-stats:: + + Config Main Menu + Power management options (ACPI, APM) ---> + CPU Frequency scaling ---> + [*] CPU Frequency scaling + [*] CPU frequency translation statistics + + +"CPU Frequency scaling" (CONFIG_CPU_FREQ) 应该被启用以配置cpufreq-stats。 + +"CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT)提供了包括 +time_in_state、total_trans和trans_table的统计数据。 + +一旦启用了这个选项,并且你的CPU支持cpufrequency,你就可以在/sysfs中看到CPU频率统计。 diff --git a/Documentation/translations/zh_CN/cpu-freq/index.rst b/Documentation/translations/zh_CN/cpu-freq/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..65074e2119403c1a44ee881e48cbcfbfdd23e533 --- /dev/null +++ b/Documentation/translations/zh_CN/cpu-freq/index.rst @@ -0,0 +1,45 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../cpu-freq/index` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_index.rst: + + +======================================================= +Linux CPUFreq - Linux(TM)内核中的CPU频率和电压升降代码 +======================================================= + +Author: Dominik Brodowski <linux@brodo.de> + + 时钟升降允许你在运行中改变CPU的时钟速度。这是一个很好的节省电池电量的方法,因为时 + 钟速度越低,CPU消耗的电量越少。 + + +.. toctree:: + :maxdepth: 1 + + core + cpu-drivers + cpufreq-stats + +邮件列表 +------------ +这里有一个 CPU 频率变化的 CVS 提交和通用列表,您可以在这里报告bug、问题或提交补丁。要发 +布消息,请发送电子邮件到 linux-pm@vger.kernel.org。 + +链接 +----- +FTP档案: +* ftp://ftp.linux.org.uk/pub/linux/cpufreq/ + +如何访问CVS仓库: +* http://cvs.arm.linux.org.uk/ + +CPUFreq邮件列表: +* http://vger.kernel.org/vger-lists.html#linux-pm + +SA-1100的时钟和电压标度: +* http://www.lartmaker.nl/projects/scaling diff --git a/Documentation/translations/zh_CN/dev-tools/gcov.rst b/Documentation/translations/zh_CN/dev-tools/gcov.rst new file mode 100644 index 0000000000000000000000000000000000000000..3158c9da13185a8af67f26f310fece231524418b --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/gcov.rst @@ -0,0 +1,264 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/gcov.rst +:Translator: 赵军奎 Bernard Zhao <bernard@vivo.com> + +在Linux内核里使用gcov做代码覆盖率检查 +===================================== + +gcov分析核心支持在Linux内核中启用GCC的覆盖率测试工具 gcov_ ,Linux内核 +运行时的代码覆盖率数据会以gcov兼容的格式导出到“gcov”debugfs目录中,可 +以通过gcov的 ``-o`` 选项(如下示例)获得指定文件的代码运行覆盖率统计数据 +(需要跳转到内核编译路径下并且要有root权限):: + + # cd /tmp/linux-out + # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c + +这将在当前目录中创建带有执行计数注释的源代码文件。 +在获得这些统计文件后,可以使用图形化的gcov前端工具(比如 lcov_ ),来实现 +自动化处理Linux内核的覆盖率运行数据,同时生成易于阅读的HTML格式文件。 + +可能的用途: + +* 调试(用来判断每一行的代码是否已经运行过) +* 测试改进(如何修改测试代码,尽可能地覆盖到没有运行过的代码) +* 内核最小化配置(对于某一个选项配置,如果关联的代码从来没有运行过, + 是否还需要这个配置) + +.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html +.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php + + +准备 +---- + +内核打开如下配置:: + + CONFIG_DEBUG_FS=y + CONFIG_GCOV_KERNEL=y + +获取整个内核的覆盖率数据,还需要打开:: + + CONFIG_GCOV_PROFILE_ALL=y + +需要注意的是,整个内核开启覆盖率统计会造成内核镜像文件尺寸的增大, +同时内核运行也会变慢一些。 +另外,并不是所有的架构都支持整个内核开启覆盖率统计。 + +代码运行覆盖率数据只在debugfs挂载完成后才可以访问:: + + mount -t debugfs none /sys/kernel/debug + + +定制化 +------ + +如果要单独针对某一个路径或者文件进行代码覆盖率统计,可以在内核相应路 +径的Makefile中增加如下的配置: + +- 单独统计单个文件(例如main.o):: + + GCOV_PROFILE_main.o := y + +- 单独统计某一个路径:: + + GCOV_PROFILE := y + +如果要在整个内核的覆盖率统计(开启CONFIG_GCOV_PROFILE_ALL)中单独排除 +某一个文件或者路径,可以使用如下的方法:: + + GCOV_PROFILE_main.o := n + +和:: + + GCOV_PROFILE := n + +此机制仅支持链接到内核镜像或编译为内核模块的文件。 + + +相关文件 +-------- + +gcov功能需要在debugfs中创建如下文件: + +``/sys/kernel/debug/gcov`` + gcov相关功能的根路径 + +``/sys/kernel/debug/gcov/reset`` + 全局复位文件:向该文件写入数据后会将所有的gcov统计数据清0 + +``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda`` + gcov工具可以识别的覆盖率统计数据文件,向该文件写入数据后 + 会将本文件的gcov统计数据清0 + +``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno`` + gcov工具需要的软连接文件(指向编译时生成的信息统计文件),这个文件是 + 在gcc编译时如果配置了选项 ``-ftest-coverage`` 时生成的。 + + +针对模块的统计 +-------------- + +内核中的模块会动态的加载和卸载,模块卸载时对应的数据会被清除掉。 +gcov提供了一种机制,通过保留相关数据的副本来收集这部分卸载模块的覆盖率数据。 +模块卸载后这些备份数据在debugfs中会继续存在。 +一旦这个模块重新加载,模块关联的运行统计会被初始化成debugfs中备份的数据。 + +可以通过对内核参数gcov_persist的修改来停用gcov对模块的备份机制:: + + gcov_persist = 0 + +在运行时,用户还可以通过写入模块的数据文件或者写入gcov复位文件来丢弃已卸 +载模块的数据。 + + +编译机和测试机分离 +------------------ + +gcov的内核分析插桩支持内核的编译和运行是在同一台机器上,也可以编译和运 +行是在不同的机器上。 +如果内核编译和运行是不同的机器,那么需要额外的准备工作,这取决于gcov工具 +是在哪里使用的: + +.. _gcov-test_zh: + +a) 若gcov运行在测试机上 + + 测试机上面gcov工具的版本必须要跟内核编译机器使用的gcc版本相兼容, + 同时下面的文件要从编译机拷贝到测试机上: + + 从源代码中: + - 所有的C文件和头文件 + + 从编译目录中: + - 所有的C文件和头文件 + - 所有的.gcda文件和.gcno文件 + - 所有目录的链接 + + 特别需要注意,测试机器上面的目录结构跟编译机器上面的目录机构必须 + 完全一致。 + 如果文件是软链接,需要替换成真正的目录文件(这是由make的当前工作 + 目录变量CURDIR引起的)。 + +.. _gcov-build_zh: + +b) 若gcov运行在编译机上 + + 测试用例运行结束后,如下的文件需要从测试机中拷贝到编译机上: + + 从sysfs中的gcov目录中: + - 所有的.gcda文件 + - 所有的.gcno文件软链接 + + 这些文件可以拷贝到编译机的任意目录下,gcov使用-o选项指定拷贝的 + 目录。 + + 比如一个是示例的目录结构如下:: + + /tmp/linux: 内核源码目录 + /tmp/out: 内核编译文件路径(make O=指定) + /tmp/coverage: 从测试机器上面拷贝的数据文件路径 + + [user@build] cd /tmp/out + [user@build] gcov -o /tmp/coverage/tmp/out/init main.c + + +关于编译器的注意事项 +-------------------- + +GCC和LLVM gcov工具不一定兼容。 +如果编译器是GCC,使用 gcov_ 来处理.gcno和.gcda文件,如果是Clang编译器, +则使用 llvm-cov_ 。 + +.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html +.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html + +GCC和Clang gcov之间的版本差异由Kconfig处理的。 +kconfig会根据编译工具链的检查自动选择合适的gcov格式。 + +问题定位 +-------- + +可能出现的问题1 + 编译到链接阶段报错终止 + +问题原因 + 分析标志指定在了源文件但是没有链接到主内核,或者客制化了链接程序 + +解决方法 + 通过在相应的Makefile中使用 ``GCOV_PROFILE := n`` + 或者 ``GCOV_PROFILE_basename.o := n`` 来将链接报错的文件排除掉 + +可能出现的问题2 + 从sysfs复制的文件显示为空或不完整 + +问题原因 + 由于seq_file的工作方式,某些工具(例如cp或tar)可能无法正确地从 + sysfs复制文件。 + +解决方法 + 使用 ``cat`` 读取 ``.gcda`` 文件,使用 ``cp -d`` 复制链接,或者使用附录B + 中所示的机制。 + + +附录A:collect_on_build.sh +-------------------------- + +用于在编译机上收集覆盖率元文件的示例脚本 +(见 :ref:`编译机和测试机分离 a. <gcov-test_zh>` ) + +.. code-block:: sh + + #!/bin/bash + + KSRC=$1 + KOBJ=$2 + DEST=$3 + + if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then + echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2 + exit 1 + fi + + KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) + KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) + + find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \ + -perm /u+r,g+r | tar cfz $DEST -P -T - + + if [ $? -eq 0 ] ; then + echo "$DEST successfully created, copy to test system and unpack with:" + echo " tar xfz $DEST -P" + else + echo "Could not create file $DEST" + fi + + +附录B:collect_on_test.sh +------------------------- + +用于在测试机上收集覆盖率数据文件的示例脚本 +(见 :ref:`编译机和测试机分离 b. <gcov-build_zh>` ) + +.. code-block:: sh + + #!/bin/bash -e + + DEST=$1 + GCDA=/sys/kernel/debug/gcov + + if [ -z "$DEST" ] ; then + echo "Usage: $0 <output.tar.gz>" >&2 + exit 1 + fi + + TEMPDIR=$(mktemp -d) + echo Collecting data.. + find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \; + find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \; + find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \; + tar czf $DEST -C $TEMPDIR sys + rm -rf $TEMPDIR + + echo "$DEST successfully created, copy to build system and unpack with:" + echo " tar xfz $DEST" diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..fd73c479917b259a198697baaa7b6fcbead91701 --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -0,0 +1,35 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/index.rst +:Translator: 赵军奎 Bernard Zhao <bernard@vivo.com> + +============ +内核开发工具 +============ + +本文档是有关内核开发工具文档的合集。 +目前这些文档已经整理在一起,不需要再花费额外的精力。 +欢迎任何补丁。 + +.. class:: toc-title + + 目录 + +.. toctree:: + :maxdepth: 2 + + gcov + +Todolist: + + - coccinelle + - sparse + - kcov + - kasan + - ubsan + - kmemleak + - kcsan + - gdb-kernel-debugging + - kgdb + - kselftest + - kunit/index diff --git a/Documentation/translations/zh_CN/disclaimer-zh_CN.rst b/Documentation/translations/zh_CN/disclaimer-zh_CN.rst index dcf803ede85a180511761c8866f9dcc7c43377fa..3c6db094a63ca2f33406066058685dd75e589a20 100644 --- a/Documentation/translations/zh_CN/disclaimer-zh_CN.rst +++ b/Documentation/translations/zh_CN/disclaimer-zh_CN.rst @@ -6,4 +6,4 @@ .. note:: 如果您发现本文档与原始文件有任何不同或者有翻译问题,请联系该文件的译者, - 或者请求时奎亮的帮助:<alex.shi@linux.alibaba.com>。 + 或者请求时奎亮的帮助:<alexs@kernel.org>。 diff --git a/Documentation/translations/zh_CN/doc-guide/contributing.rst b/Documentation/translations/zh_CN/doc-guide/contributing.rst new file mode 100644 index 0000000000000000000000000000000000000000..394a13b438b0f907f0d1a4c6f293f2295bae51a4 --- /dev/null +++ b/Documentation/translations/zh_CN/doc-guide/contributing.rst @@ -0,0 +1,238 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/doc-guide/contributing.rst + +:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> + +如何帮助改进内核文档 +==================== + +在任何软件开发项目中,文档都是重要组成部分。好的文档有助于引入新的开发人员, +并帮助已有的开发人员更有效地工作。如果缺少高质量的文档,大量的时间就会浪费在 +代码的逆向工程和犯本可避免的错误上。 + +不幸的是,内核的文档目前远远不能满足支持如此规模和重要性的项目的需要。 + +本指南适用于希望帮助改善这种状况的贡献者。内核文档的改进可以由开发者在不同的 +技能层级上进行;这也是一条相对简单可以帮助您了解内核过程并在社区中找到一席之 +地的路径。下面的大部分内容是文档维护人员列出的最迫切需要完成的任务。 + +文档待办事项列表 +---------------- + +为了使我们的文档达到应有的水平,需要完成的任务数不胜数。此列表包含许多重要的 +项目,但还远远不够详尽;如果您知道改进文档的其他方法,请不要羞于启齿。 + +消除警告(WARNING) +~~~~~~~~~~~~~~~~~~~ + +文档构建目前出现了数量惊人的警告。虱子多了不痒,债多了不愁;大伙儿忽略了它们, +他们永远不会注意到他们的工作增加了新的警告。因此,消除警告是文档待办事项列表 +中优先级最高的任务之一。这项任务本身相当简单,但必须以正确的方式进行,才能取 +得成功。 + +C代码编译器发出的警告常常会被视为误报,从而导致出现了旨在让编译器闭嘴的补丁。 +文档构建中的警告几乎总是指向真正的问题;要消除这些警告,需要理解问题并从源头上 +解决问题。因此,修复文档警告的补丁不应在标题中直接写“修复警告”;它们应该指明 +真正修复的问题。 + +另一个重点是,文档警告常常由C代码里kernel-doc注释中的问题引起。虽然文档维护 +人员对收到这些修复补丁的副本表示感谢,但是文档树实际上通常并不适合接受这些 +补丁;它们应该被交给相关子系统的维护人员。 + +例如,在一次文档构建中,我几乎是随意选取了一对警告:: + + ./drivers/devfreq/devfreq.c:1818: warning: bad line: + - Resource-managed devfreq_register_notifier() + ./drivers/devfreq/devfreq.c:1854: warning: bad line: + - Resource-managed devfreq_unregister_notifier() + +(作了断行以便于阅读) + +简单看一下上面给出的源文件,会发现几个kernel-doc注释,如下所示:: + + /** + * devm_devfreq_register_notifier() + - Resource-managed devfreq_register_notifier() + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. + * @nb: The notifier block to be unregistered. + * @list: DEVFREQ_TRANSITION_NOTIFIER. + */ + +问题在于缺了一个“*”,这不符合构建系统对C注释块的格式要求。此问题自2016年注释 +被添加以来一直存在——整整四年之久。修复它只需要添加丢失的星号。看一眼该文件的 +历史记录以了解主题行的常规格式是什么样,再使用 ``scripts/get_maintainer.pl`` +来搞清谁应当收到此补丁。生成的补丁如下所示:: + + [PATCH] PM / devfreq: Fix two malformed kerneldoc comments + + Two kerneldoc comments in devfreq.c fail to adhere to the required format, + resulting in these doc-build warnings: + + ./drivers/devfreq/devfreq.c:1818: warning: bad line: + - Resource-managed devfreq_register_notifier() + ./drivers/devfreq/devfreq.c:1854: warning: bad line: + - Resource-managed devfreq_unregister_notifier() + + Add a couple of missing asterisks and make kerneldoc a little happier. + + Signed-off-by: Jonathan Corbet <corbet@lwn.net> + --- + drivers/devfreq/devfreq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + + diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c + index 57f6944d65a6..00c9b80b3d33 100644 + --- a/drivers/devfreq/devfreq.c + +++ b/drivers/devfreq/devfreq.c + @@ -1814,7 +1814,7 @@ static void devm_devfreq_notifier_release(struct device *dev, void *res) + + /** + * devm_devfreq_register_notifier() + - - Resource-managed devfreq_register_notifier() + + * - Resource-managed devfreq_register_notifier() + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. + * @nb: The notifier block to be unregistered. + @@ -1850,7 +1850,7 @@ EXPORT_SYMBOL(devm_devfreq_register_notifier); + + /** + * devm_devfreq_unregister_notifier() + - - Resource-managed devfreq_unregister_notifier() + + * - Resource-managed devfreq_unregister_notifier() + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. + * @nb: The notifier block to be unregistered. + -- + 2.24.1 + +整个过程只花了几分钟。当然,我后来发现有人在另一个树中修复了它,这亮出了另一 +个教训:在深入研究问题之前,一定要检查linux-next树,看看问题是否已经修复。 + +其他修复可能需要更长的时间,尤其是那些与缺少文档的结构体成员或函数参数相关的 +修复。这种情况下,需要找出这些成员或参数的作用,并正确描述它们。总之,这种 +任务有时会有点乏味,但它非常重要。如果我们真的可以从文档构建中消除警告,那么 +我们就可以开始期望开发人员开始注意避免添加新的警告了。 + +“迷失的”kernel-doc注释 +~~~~~~~~~~~~~~~~~~~~~~ + +开发者被鼓励去为他们的代码写kernel-doc注释,但是许多注释从未被引入文档构建。 +这使得这些信息更难找到,例如使Sphinx无法生成指向该文档的链接。将 ``kernel-doc`` +指令添加到文档中以引入这些注释可以帮助社区获得为编写注释所做工作的全部价值。 + +``scripts/find-unused-docs.sh`` 工具可以用来找到这些被忽略的评论。 + +请注意,将导出的函数和数据结构引入文档是最有价值的。许多子系统还具有供内部 +使用的kernel-doc注释;除非这些注释放在专门针对相关子系统开发人员的文档中, +否则不应将其引入文档构建中。 + + +修正错字 +~~~~~~~~ + + +修复文档中的排版或格式错误是一种快速学习如何创建和发送修补程序的方法,也是 +一项有用的服务。我总是愿意接受这样的补丁。这也意味着,一旦你修复了一些这种 +错误,请考虑转移到更高级的任务,留下一些拼写错误给下一个初学者解决。 + +请注意,有些并 **不是** 拼写错误,不应该被“修复”: + + - 内核文档中用美式和英式英语拼写皆可,没有必要互相倒换。 + + - 在内核文档中,没必要讨论句点后面应该跟一个还是两个空格的问题。其他一些有 + 合理分歧的地方,比如“牛津逗号”,在这也是跑题的。 + +与对任何项目的任何补丁一样,请考虑您的更改是否真的让事情变得更好。 + +“上古”文档 +~~~~~~~~~~ + +一些内核文档是最新的、被维护的,并且非常有用,有些文件确并非如此。尘封、陈旧 +和不准确的文档可能会误导读者,并对我们的整个文档产生怀疑。任何解决这些问题的 +事情都是非常受欢迎的。 + +无论何时处理文档,请考虑它是否是最新的,是否需要更新,或者是否应该完全删除。 +您可以注意以下几个警告标志: + + - 对2.x内核的引用 + - 指向SourceForge存储库 + - 历史记录除了拼写错误啥也没有持续几年 + - 讨论Git之前时代的工作流 + +当然,最好的办法是更新文档,添加所需的任何信息。这样的工作通常需要与熟悉相关 +子系统的开发人员合作。当有人善意地询问开发人员,并听取他们的回答然后采取 +行动时,开发人员通常更愿意与这些致力于改进文档的人员合作。 + +有些文档已经没希望了;例如,我们偶尔会发现引用了很久以前从内核中删除的代码的 +文档。删除过时的文档会碰见令人惊讶的阻力,但我们无论如何都应该这样做。文档中 +多余的粗枝大叶对任何人都没有帮助。 + +如果一个严重过时的文档中可能有一些有用的信息,而您又无法更新它,那么最好在 +开头添加一个警告。建议使用以下文本:: + + .. warning :: + This document is outdated and in need of attention. Please use + this information with caution, and please consider sending patches + to update it. + +这样的话,至少我们长期受苦的读者会得到文件可能会把他们引入歧途的警告。 + +文档一致性 +~~~~~~~~~~ + +这里的老前辈们会记得上世纪90年代出现在书架上的Linux书籍,它们只是从网上不同 +位置搜来的文档文件的集合。在此之后,(大部分)这些书都得到了改进,但是内核的 +文档仍然主要是建立在这种模型上。它有数千个文件,几乎每个文件都是与其他文件相 +独立编写的。我们没有一个连贯的内核文档;只有数千个独立的文档。 + +我们一直试图通过编篡一套“书籍”来改善这种情况,以为特定读者提供成套文档。这 +包括: + + - Documentation/translations/zh_CN/admin-guide/index.rst + - Documentation/core-api/index.rst + - Documentation/driver-api/index.rst + - Documentation/userspace-api/index.rst + +以及文档本身这本“书”。 + +将文档移到适当的书中是一项重要的任务,需要继续进行。不过这项工作还是有一些 +挑战性。移动文档会给处理这些文档的人带来短期的痛苦;他们对这些更改无甚热情 +也是可以理解的。通常情况下,可以将一个文档移动一下;不过我们真的不想一直移动 +它们。 + +即使所有文件都在正确的位置,我们也只是把一大堆文件变成一群小堆文件。试图将 +所有这些文件组合成一个整体的工作尚未开始。如果你对如何在这方面取得进展有好的 +想法,我们将很高兴了解。 + +样式表(Stylesheet)改进 +~~~~~~~~~~~~~~~~~~~~~~~~ + +随着Sphinx的采用,我们得到了比以前更好的HTML输出。但它仍然需要很大的改进; +Donald Knuth和Edward Tufte可能是映像平平的。这需要调整我们的样式表,以创建 +更具排版效果、可访问性和可读性的输出。 + +请注意:如果你承担这个任务,你将进入经典的两难领域。即使是相对明显的变化, +也会有很多意见和讨论。唉,这就是我们生活的世界的本质。 + +无LaTeX的PDF构建 +~~~~~~~~~~~~~~~~ + +对于拥有大量时间和Python技能的人来说,这绝对是一项不平凡的任务。Sphinx工具链 +相对较小且包含良好;很容易添加到开发系统中。但是构建PDF或EPUB输出需要安装 +LaTeX,它绝对称不上小或包含良好的。消除Latex将是一件很好的事情。 + +最初是希望使用 `rst2pdf <https://rst2pdf.org/>`_ 工具来生成PDF,但结果发现 +无法胜任这项任务。不过rst2pdf的开发工作最近似乎又有了起色,这是个充满希望的 +迹象。如果有开发人员愿意与该项目合作,使rst2pdf可与内核文档构建一起工作, +大家会非常感激。 + +编写更多文档 +~~~~~~~~~~~~ + +当然,内核中许多部分的文档严重不足。如果您有编写一个特定内核子系统文档的相应 +知识并愿意这样做,请不要犹豫,编写并向内核贡献结果吧!数不清的内核开发人员和 +用户会感谢你。 diff --git a/Documentation/translations/zh_CN/doc-guide/index.rst b/Documentation/translations/zh_CN/doc-guide/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..5151953c196f888b69b9caf625ad739034352993 --- /dev/null +++ b/Documentation/translations/zh_CN/doc-guide/index.rst @@ -0,0 +1,27 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/doc-guide/index.rst + +:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> + +.. _doc_guide_zh: + +================ +如何编写内核文档 +================ + +.. toctree:: + :maxdepth: 1 + + sphinx + kernel-doc + parse-headers + contributing + maintainer-profile + +.. only:: 子项目与HTML + + 目录 + ==== + + * :ref:`genindex` diff --git a/Documentation/translations/zh_CN/doc-guide/kernel-doc.rst b/Documentation/translations/zh_CN/doc-guide/kernel-doc.rst new file mode 100644 index 0000000000000000000000000000000000000000..82ec84470c0b873f09b43966c396cfd88b2f9059 --- /dev/null +++ b/Documentation/translations/zh_CN/doc-guide/kernel-doc.rst @@ -0,0 +1,499 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/doc-guide/kernel-doc.rst + +:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> + +编写kernel-doc注释 +================== + +Linux内核源文件可以包含kernel-doc格式的结构化文档注释,用以描述代码的函数、 +类型和设计。将文档嵌入源文件更容易保持文档最新。 + +.. note:: 内核文档格式与javadoc、gtk-doc或Doxygen看似很相似,但由于历史原因, + 实际有着明显的不同。内核源包含成千上万个kernel-doc注释。请坚持遵循 + 此处描述的风格。 + +.. note:: kernel-doc无法包含Rust代码:请参考 Documentation/rust/docs.rst 。 + +从注释中提取kernel-doc结构,并从中生成适当的 `Sphinx C 域`_ 函数和带有锚点的 +类型描述。这些注释将被过滤以生成特殊kernel-doc高亮和交叉引用。详见下文。 + +.. _Sphinx C 域: http://www.sphinx-doc.org/en/stable/domains.html + +使用 ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出到可加载模块的每个函数都 +应该有一个kernel-doc注释。模块使用的头文件中的函数和数据结构也应该有 +kernel-doc注释。 + +对于其他内核文件(未标记为 ``static`` )中外部可见的函数,提供kernel-doc格式 +的文档是一个很好的实践。我们也建议为私有(文件 ``static`` )程序提供kernel-doc +格式的文档,以确保内核源代码布局的一致性。此建议优先级较低,由内核源文件的 +维护者自行决定。 + +如何格式化kernel-doc注释 +------------------------ + +kernel-doc注释用 ``/**`` 作为开始标记。 ``kernel-doc`` 工具将提取以这种方式 +标记的注释。注释其余部分的格式类似于一个普通的多行注释,左侧有一列星号,以 +``*/`` 行结束。 + +函数和类型的kernel-doc注释应该放在所描述的函数或类型之前,以便最大限度地提高 +更改代码的人同时更改文档的可能性。概述kernel-doc注释可以放在最顶部的任何地方。 + +用详细模式和不生成实际输出来运行 ``kernel-doc`` 工具,可以验证文档注释的格式 +是否正确。例如:: + + scripts/kernel-doc -v -none drivers/foo/bar.c + +当请求执行额外的gcc检查时,内核构建将验证文档格式:: + + make W=n + +函数文档 +-------- + +函数和函数式宏的kernel-doc注释的一般格式是:: + + /** + * 函数名() - 函数简要说明. + * @参数1: 描述第一个参数. + * @参数2: 描述第二个参数. + * 可以为参数提供一段 + * 多行描述. + * + * 更详细的描述,进一步讨论函数 函数名(), 这可能对使用或修改它的人有用. + * 以空注释行开始, 内部可以包含空注释行. + * + * 详细描述可以有多个段落. + * + * Context: 描述函数是否可以休眠, 它需要、释放或期望持有什么锁. + * 可以写多行. + * Return: 描述函数返回值. + * + * 返回值描述也可以有多个段落, + * 并且应该放在注释块的末尾. + */ + +函数名后面的简短描述可以跨多行,并以参数描述、空注释行或注释块结尾结束。 + +函数参数 +~~~~~~~~ + +每个函数参数都应该按照顺序描述,紧跟在函数简要说明之后。不要在函数描述和参数 +之间,也不要在参数之间留空。 + +每个 ``@参数:`` 描述可以跨多行。 + +.. note:: + + 如果 ``@参数`` 描述有多行,则说明的续行应该从上一行的同一列开始:: + + * @参数: 较长说明 + * 的续行 + + 或:: + + * @参数: + * 较长说明 + * 的续行 + +如果函数的参数数目可变,则需用kernel-doc格式对其进行描述:: + + * @...: 描述 + +函数上下文 +~~~~~~~~~~ + +可调用函数的上下文应该在 ``Context`` 节中描述。此节应该包括函数是休眠的还是 +可以从中断上下文调用的,以及它需要什么锁、释放什么锁和期望它的调用者持有什么 +锁。 + +例如:: + + * Context: Any context. + * Context: Any context. Takes and releases the RCU lock. + * Context: Any context. Expects <lock> to be held by caller. + * Context: Process context. May sleep if @gfp flags permit. + * Context: Process context. Takes and releases <mutex>. + * Context: Softirq or process context. Takes and releases <lock>, BH-safe. + * Context: Interrupt context. + +返回值 +~~~~~~ + +如有返回值,应在 ``Return`` 节中描述。 + +.. note:: + + #) 您提供的多行描述文本 *不会* 识别换行符,因此如果您想将某些文本预格式化, + 如:: + + * Return: + * 0 - OK + * -EINVAL - invalid argument + * -ENOMEM - out of memory + + 它们在最终文档中变成一行:: + + Return: 0 - OK -EINVAL - invalid argument -ENOMEM - out of memory + + 因此,为了在需要的地方换行,您需要使用ReST列表,例如:: + + * Return: + * * 0 - OK to runtime suspend the device + * * -EBUSY - Device should not be runtime suspended + + #) 如果您提供的描述性文本中的行以某个后跟冒号的短语开头,则每一个这种短语 + 都将被视为新的节标题,可能会产生意料不到的效果。 + +结构体、共用体、枚举类型文档 +---------------------------- + +结构体(struct)、共用体(union)、枚举(enum)类型kernel-doc注释的一般格式为:: + + /** + * struct 结构体名 - 简要描述. + * @成员1: 成员1描述. + * @成员2: 成员2描述. + * 可以为成员提供 + * 多行描述. + * + * 结构体的描述. + */ + +可以用 ``union`` 或 ``enum`` 替换上面示例中的 ``struct`` ,以描述共用体或枚举。 +``成员`` 用于表示枚举中的元素或共用体成员。 + +结构体名称后面的简要说明可以跨多行,并以成员说明、空白注释行或注释块结尾结束。 + +成员 +~~~~ + +结构体、共用体和枚举的成员应以与函数参数相同的方式记录;它们后紧跟简短的描述, +并且为多行。 + +在结构体或共用体描述中,可以使用 ``private:`` 和 ``public:`` 注释标签。 +``private:`` 域内的字段不会列在生成的文档中。 + +``private:`` 和 ``public:`` 标签必须紧跟在 ``/*`` 注释标记之后。可以选择是否 +在 ``:`` 和 ``*/`` 结束标记之间包含注释。 + +例子:: + + /** + * struct 张三 - 简短描述 + * @a: 第一个成员 + * @b: 第二个成员 + * @d: 第三个成员 + * + * 详细描述 + */ + struct 张三 { + int a; + int b; + /* private: 仅内部使用 */ + int c; + /* public: 下一个是公有的 */ + int d; + }; + +嵌套的结构体/共用体 +~~~~~~~~~~~~~~~~~~~ + +嵌套的结构体/共用体可像这样记录:: + + /** + * struct nested_foobar - a struct with nested unions and structs + * @memb1: first member of anonymous union/anonymous struct + * @memb2: second member of anonymous union/anonymous struct + * @memb3: third member of anonymous union/anonymous struct + * @memb4: fourth member of anonymous union/anonymous struct + * @bar: non-anonymous union + * @bar.st1: struct st1 inside @bar + * @bar.st2: struct st2 inside @bar + * @bar.st1.memb1: first member of struct st1 on union bar + * @bar.st1.memb2: second member of struct st1 on union bar + * @bar.st2.memb1: first member of struct st2 on union bar + * @bar.st2.memb2: second member of struct st2 on union bar + */ + struct nested_foobar { + /* Anonymous union/struct*/ + union { + struct { + int memb1; + int memb2; + }; + struct { + void *memb3; + int memb4; + }; + }; + union { + struct { + int memb1; + int memb2; + } st1; + struct { + void *memb1; + int memb2; + } st2; + } bar; + }; + +.. note:: + + #) 在记录嵌套结构体或共用体时,如果结构体/共用体 ``张三`` 已命名,则其中 + 的成员 ``李四`` 应记录为 ``@张三.李四:`` + + #) 当嵌套结构体/共用体是匿名的时,其中的成员 ``李四`` 应记录为 ``@李四:`` + +行间注释文档 +~~~~~~~~~~~~ + +结构成员也可在定义时以行间注释形式记录。有两种样式,一种是单行注释,其中开始 +``/**`` 和结束 ``*/`` 位于同一行;另一种是多行注释,开头结尾各自位于一行,就 +像所有其他核心文档注释一样:: + + /** + * struct 张三 - 简短描述. + * @张三: 成员张三. + */ + struct 张三 { + int 张三; + /** + * @李四: 成员李四. + */ + int 李四; + /** + * @王五: 成员王五. + * + * 此处,成员描述可以为好几段. + */ + int 王五; + union { + /** @儿子: 单行描述. */ + int 儿子; + }; + /** @赵六: 描述@张三里面的结构体@赵六 */ + struct { + /** + * @赵六.女儿: 描述@张三.赵六里面的@女儿 + */ + int 女儿; + } 赵六; + }; + +Typedef文档 +----------- + +Typedef的kernel-doc文档注释的一般格式为:: + + /** + * typedef 类型名称 - 简短描述. + * + * 类型描述. + */ + +还可以记录带有函数原型的typedef:: + + /** + * typedef 类型名称 - 简短描述. + * @参数1: 参数1的描述 + * @参数2: 参数2的描述 + * + * 类型描述. + * + * Context: 锁(Locking)上下文. + * Return: 返回值的意义. + */ + typedef void (*类型名称)(struct v4l2_ctrl *参数1, void *参数2); + +高亮与交叉引用 +-------------- + +在kernel-doc注释的描述文本中可以识别以下特殊模式,并将其转换为正确的 +reStructuredText标记和 `Sphinx C 域`_ 引用。 + +.. attention:: 以下内容 **仅** 在kernel-doc注释中识别, **不会** 在普通的 + reStructuredText文档中识别。 + +``funcname()`` + 函数引用。 + +``@parameter`` + 函数参数的名称(未交叉引用,仅格式化)。 + +``%CONST`` + 常量的名称(未交叉引用,仅格式化)。 + +````literal```` + 预格式化文本块。输出将使用等距字体。 + + 若你需要使用在kernel-doc脚本或reStructuredText中有特殊含义的字符,则此功能 + 非常有用。 + + 若你需要在函数描述中使用类似于 ``%ph`` 的东西,这特别有用。 + +``$ENVVAR`` + 环境变量名称(未交叉引用,仅格式化)。 + +``&struct name`` + 结构体引用。 + +``&enum name`` + 枚举引用。 + +``&typedef name`` + Typedef引用。 + +``&struct_name->member`` or ``&struct_name.member`` + 结构体或共用体成员引用。交叉引用将链接到结构体或共用体定义,而不是直接到成员。 + +``&name`` + 泛类型引用。请首选上面描述的完整引用方式。此法主要是为了可能未描述的注释。 + +从reStructuredText交叉引用 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +无需额外的语法来从reStructuredText文档交叉引用kernel-do注释中定义的函数和类型。 +只需以 ``()`` 结束函数名,并在类型之前写上 ``struct`` , ``union`` , ``enum`` +或 ``typedef`` 。 +例如:: + + See foo(). + See struct foo. + See union bar. + See enum baz. + See typedef meh. + +若要在交叉引用链接中使用自定义文本,可以通过以下语法进行:: + + See :c:func:`my custom link text for function foo <foo>`. + See :c:type:`my custom link text for struct bar <bar>`. + +有关更多详细信息,请参阅 `Sphinx C 域`_ 文档。 + +总述性文档注释 +-------------- + +为了促进源代码和注释紧密联合,可以将kernel-doc文档块作为自由形式的注释,而 +不是函数、结构、联合、枚举或typedef的绑定kernel-doc。例如,这可以用于解释 +驱动程序或库代码的操作理论。 + +这是通过使用带有节标题的 ``DOC:`` 节关键字来实现的。 + +总述或高层级文档注释的一般格式为:: + + /** + * DOC: Theory of Operation + * + * The whizbang foobar is a dilly of a gizmo. It can do whatever you + * want it to do, at any time. It reads your mind. Here's how it works. + * + * foo bar splat + * + * The only drawback to this gizmo is that is can sometimes damage + * hardware, software, or its subject(s). + */ + +``DOC:`` 后面的标题用作源文件中的标题,但也用作提取文档注释的标识符。因此, +文件中的标题必须是唯一的。 + +包含kernel-doc注释 +================== + +文档注释可以被包含在任何使用专用kernel-doc Sphinx指令扩展的reStructuredText +文档中。 + +kernel-doc指令的格式如下:: + + .. kernel-doc:: source + :option: + +*source* 是相对于内核源代码树的源文件路径。 +支持以下指令选项: + +export: *[source-pattern ...]* + 包括 *source* 中使用 ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出的所有 + 函数的文档,无论是在 *source* 中还是在 *source-pattern* 指定的任何文件中。 + + 当kernel-doc注释被放置在头文件中,而 ``EXPORT_SYMBOL`` 和 ``EXPORT_SYMBOL_GPL`` + 位于函数定义旁边时, *source-pattern* 非常有用。 + + 例子:: + + .. kernel-doc:: lib/bitmap.c + :export: + + .. kernel-doc:: include/net/mac80211.h + :export: net/mac80211/*.c + +internal: *[source-pattern ...]* + 包括 *source* 中所有在 *source* 或 *source-pattern* 的任何文件中都没有使用 + ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出的函数和类型的文档。 + + 例子:: + + .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c + :internal: + +identifiers: *[ function/type ...]* + 在 *source* 中包含每个 *function* 和 *type* 的文档。如果没有指定 *function* , + 则 *source* 中所有函数和类型的文档都将包含在内。 + + 例子:: + + .. kernel-doc:: lib/bitmap.c + :identifiers: bitmap_parselist bitmap_parselist_user + + .. kernel-doc:: lib/idr.c + :identifiers: + +no-identifiers: *[ function/type ...]* + 排除 *source* 中所有 *function* 和 *type* 的文档。 + + 例子:: + + .. kernel-doc:: lib/bitmap.c + :no-identifiers: bitmap_parselist + +functions: *[ function/type ...]* + 这是“identifiers”指令的别名,已弃用。 + +doc: *title* + 包含 *source* 中由 *title* 标题标识的 ``DOC:`` 文档段落。 *title* 中允许 + 空格;不要在 *title* 上加引号。 *title* 仅用作段落的标识符,不包含在输出中。 + 请确保在所附的reStructuredText文档中有适当的标题。 + + 例子:: + + .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c + :doc: High Definition Audio over HDMI and Display Port + +如果没有选项,kernel-doc指令将包含源文件中的所有文档注释。 + +kernel-doc扩展包含在内核源代码树中,位于 ``Documentation/sphinx/kerneldoc.py`` 。 +在内部,它使用 ``scripts/kernel-doc`` 脚本从源代码中提取文档注释。 + +.. _kernel_doc_zh: + +如何使用kernel-doc生成手册(man)页 +----------------------------------- + +如果您只想使用kernel-doc生成手册页,可以从内核git树这样做:: + + $ scripts/kernel-doc -man \ + $(git grep -l '/\*\*' -- :^Documentation :^tools) \ + | scripts/split-man.pl /tmp/man + +一些旧版本的git不支持路径排除语法的某些变体。 +以下命令之一可能适用于这些版本:: + + $ scripts/kernel-doc -man \ + $(git grep -l '/\*\*' -- . ':!Documentation' ':!tools') \ + | scripts/split-man.pl /tmp/man + + $ scripts/kernel-doc -man \ + $(git grep -l '/\*\*' -- . ":(exclude)Documentation" ":(exclude)tools") \ + | scripts/split-man.pl /tmp/man + diff --git a/Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst b/Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst new file mode 100644 index 0000000000000000000000000000000000000000..35c88e5b3d830bf82c9b12a0392188c8f4a3b2b1 --- /dev/null +++ b/Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/doc-guide/maintainer-profile.rst + +:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> + +文档子系统维护人员条目概述 +========================== + +文档“子系统”是内核文档和相关基础设施的中心协调点。它涵盖了 Documentation/ 下 +的文件层级(Documentation/devicetree 除外)、scripts/ 下的各种实用程序,并且 +在某些情况下的也包括 LICENSES/ 。 + +不过值得注意的是,这个子系统的边界比通常更加模糊。许多其他子系统维护人员需要 +保持对 Documentation/ 某些部分的控制,以便于可以更自由地做更改。除此之外, +许多内核文档都以kernel-doc注释的形式出现在源代码中;这些注释通常(但不总是) +由相关的子系统维护人员维护。 + +文档子系统的邮件列表是<linux-doc@vger.kernel.org>。 +补丁应尽量针对docs-next树。 + +提交检查单补遗 +-------------- + +在进行文档更改时,您应当构建文档以测试,并确保没有引入新的错误或警告。生成 +HTML文档并查看结果将有助于避免对文档渲染结果的不必要争执。 + +开发周期的关键节点 +------------------ + +补丁可以随时发送,但在合并窗口期间,响应将比通常慢。文档树往往在合并窗口打开 +之前关闭得比较晚,因为文档补丁导致回归的风险很小。 + +审阅节奏 +-------- + +我(译注:指Jonathan Corbet <corbet@lwn.net>)是文档子系统的唯一维护者,我在 +自己的时间里完成这项工作,所以对补丁的响应有时会很慢。当补丁被合并时(或当我 +决定拒绝合并补丁时),我都会发送通知。如果您在发送补丁后一周内没有收到回复, +请不要犹豫,发送提醒就好。 + diff --git a/Documentation/translations/zh_CN/doc-guide/parse-headers.rst b/Documentation/translations/zh_CN/doc-guide/parse-headers.rst new file mode 100644 index 0000000000000000000000000000000000000000..a08819e904ed7871d8eac046653cf53cd6c9df4a --- /dev/null +++ b/Documentation/translations/zh_CN/doc-guide/parse-headers.rst @@ -0,0 +1,187 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/doc-guide/parse-headers.rst + +:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> + +===================== +包含用户空间API头文件 +===================== + +有时,为了描述用户空间API并在代码和文档之间生成交叉引用,需要包含头文件和示例 +C代码。为用户空间API文件添加交叉引用还有一个好处:如果在文档中找不到相应符号, +Sphinx将生成警告。这有助于保持用户空间API文档与内核更改同步。 +:ref:`parse_headers.pl <parse_headers_zh>` 提供了生成此类交叉引用的一种方法。 +在构建文档时,必须通过Makefile调用它。有关如何在内核树中使用它的示例,请参阅 +``Documentation/userspace-api/media/Makefile`` 。 + +.. _parse_headers_zh: + +parse_headers.pl +---------------- + +脚本名称 +~~~~~~~~ + + +parse_headers.pl——解析一个C文件,识别函数、结构体、枚举、定义并对Sphinx文档 +创建交叉引用。 + + +用法概要 +~~~~~~~~ + + +\ **parse_headers.pl**\ [<选项>] <C文件> <输出文件> [<例外文件>] + +<选项> 可以是: --debug, --help 或 --usage 。 + + +选项 +~~~~ + + + +\ **--debug**\ + + 开启脚本详细模式,在调试时很有用。 + + +\ **--usage**\ + + 打印简短的帮助信息并退出。 + + + +\ **--help**\ + + 打印更详细的帮助信息并退出。 + + +说明 +~~~~ + +通过C头文件或源文件(<C文件>)中为描述API的文档编写的带交叉引用的 ..预格式化 +文本 块将文件转换成重构文本(RST)。它接受一个可选的<例外文件>,其中描述了 +哪些元素将被忽略或指向非默认引用。 + +输出被写入到<输出文件>。 + +它能够识别定义、函数、结构体、typedef、枚举和枚举符号,并为它们创建交叉引用。 +它还能够区分用于指定Linux ioctl的 ``#define`` 。 + +<例外文件> 包含两种类型的语句: \ **ignore**\ 或 \ **replace**\ . + +ignore标记的语法为: + + +ignore \ **type**\ \ **name**\ + +The \ **ignore**\ 意味着它不会为类型为 \ **type**\ 的 \ **name**\ 符号生成 +交叉引用。 + + +replace标记的语法为: + + +replace \ **type**\ \ **name**\ \ **new_value**\ + +The \ **replace**\ 味着它将为 \ **type**\ 类型的 \ **name**\ 符号生成交叉引 +用,但是它将使用 \ **new_value**\ 来取代默认的替换规则。 + + +这两种语句中, \ **type**\ 可以是以下任一项: + + +\ **ioctl**\ + + ignore 或 replace 语句应用于ioctl定义,如: + + #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) + + + +\ **define**\ + + ignore 或 replace 语句应用于在<C文件>中找到的任何其他 ``#define`` 。 + + + +\ **typedef**\ + + ignore 和 replace 语句应用于<C文件>中的typedef语句。 + + + +\ **struct**\ + + ignore 和 replace 语句应用于<C文件>中的结构体名称语句。 + + + +\ **enum**\ + + ignore 和 replace 语句应用于<C文件>中的枚举名称语句。 + + + +\ **symbol**\ + + ignore 和 replace 语句应用于<C文件>中的枚举值名称语句。 + + replace语句中, \ **new_value**\ 会自动使用 \ **typedef**\ , \ **enum**\ + 和 \ **struct**\ 类型的 :c:type: 引用;以及 \ **ioctl**\ , \ **define**\ 和 + \ **symbol**\ 类型的 :ref: 。引用的类型也可以在replace语句中显式定义。 + + +示例 +~~~~ + + +ignore define _VIDEODEV2_H + + +忽略<C文件>中的 #define _VIDEODEV2_H 。 + +ignore symbol PRIVATE + + +如下结构体: + +enum foo { BAR1, BAR2, PRIVATE }; + +不会为 \ **PRIVATE**\ 生成交叉引用。 + +replace symbol BAR1 :c:type:\`foo\` +replace symbol BAR2 :c:type:\`foo\` + + +如下结构体: + +enum foo { BAR1, BAR2, PRIVATE }; + +它会让BAR1和BAR2枚举符号交叉引用C域中的foo符号。 + + + +缺陷 +~~~~ + + +请向Mauro Carvalho Chehab <mchehab@kernel.org>报告有关缺陷。 + +中文翻译问题请找中文翻译维护者。 + + +版权 +~~~~ + + +版权所有 (c) 2016 Mauro Carvalho Chehab <mchehab+samsung@kernel.org> + +许可证 GPLv2:GNU GPL version 2 <https://gnu.org/licenses/gpl.html> + +这是自由软件:你可以自由地修改和重新发布它。 +在法律允许的范围内,**不提供任何保证**。 diff --git a/Documentation/translations/zh_CN/doc-guide/sphinx.rst b/Documentation/translations/zh_CN/doc-guide/sphinx.rst new file mode 100644 index 0000000000000000000000000000000000000000..951595c7d599b8b4f63144895bb21e67ec09cba0 --- /dev/null +++ b/Documentation/translations/zh_CN/doc-guide/sphinx.rst @@ -0,0 +1,415 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/doc-guide/sphinx.rst + +:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> + +.. _sphinxdoc_zh: + +简介 +==== + +Linux内核使用 `Sphinx <http://www.sphinx-doc.org/>`_ 来把 ``Documentation`` +下的 `reStructuredText <http://docutils.sourceforge.net/rst.html>`_ 文件转 +换成漂亮的文档。使用 ``make htmldocs`` 或 ``make pdfdocs`` 命令即可构建HTML +或PDF格式的文档。生成的文档放在 ``Documentation/output`` 文件夹中。 + +reStructuredText文件可能包含包含来自源文件的结构化文档注释或kernel-doc注释。 +通常它们用于描述代码的功能、类型和设计。kernel-doc注释有一些特殊的结构和 +格式,但除此之外,它们还被作为reStructuredText处理。 + +最后,有成千上万的纯文本文档文件散布在 ``Documentation`` 里。随着时间推移, +其中一些可能会转换为reStructuredText,但其中大部分仍保持纯文本。 + +.. _sphinx_install_zh: + +安装Sphinx +========== + +Documentation/ 下的ReST文件现在使用sphinx1.3或更高版本构建。 + +这有一个脚本可以检查Sphinx的依赖项。更多详细信息见 +:ref:`sphinx-pre-install_zh` 。 + +大多数发行版都附带了Sphinx,但是它的工具链比较脆弱,而且在您的机器上升级它 +或其他一些Python包导致文档构建中断的情况并不少见。 + +避免此情况的一种方法是使用与发行版附带的不同的版本。因此,建议使用 +``virtualenv-3`` 或 ``virtualenv`` 在虚拟环境中安装Sphinx,具体取决于发行版 +如何打包Python3。 + +.. note:: + + #) 低于1.5版本的Sphinx无法与Python的0.13.1或更高版本docutils一起正常工作。 + 如果您想使用这些版本,那么应该运行 ``pip install 'docutils==0.12'`` 。 + + #) html输出建议使用RTD主题。根据Sphinx版本的不同,它应该用 + ``pip install sphinx_rtd_theme`` 单独安装。 + + #) 一些ReST页面包含数学表达式。由于Sphinx的工作方式,这些表达式是使用 LaTeX + 编写的。它需要安装amsfonts和amsmath宏包,以便显示。 + +总之,如您要安装Sphinx 1.7.9版本,应执行:: + + $ virtualenv sphinx_1.7.9 + $ . sphinx_1.7.9/bin/activate + (sphinx_1.7.9) $ pip install -r Documentation/sphinx/requirements.txt + +在运行 ``. sphinx_1.7.9/bin/activate`` 之后,提示符将变化,以指示您正在使用新 +环境。如果您打开了一个新的shell,那么在构建文档之前,您需要重新运行此命令以再 +次进入虚拟环境中。 + +图片输出 +-------- + +内核文档构建系统包含一个扩展,可以处理GraphViz和SVG格式的图像(参见 +:ref:`sphinx_kfigure_zh` )。 + +为了让它工作,您需要同时安装GraphViz和ImageMagick包。如果没有安装这些软件包, +构建系统仍将构建文档,但不会在输出中包含任何图像。 + +PDF和LaTeX构建 +-------------- + +目前只有Sphinx 1.4及更高版本才支持这种构建。 + +对于PDF和LaTeX输出,还需要 ``XeLaTeX`` 3.14159265版本。(译注:此版本号真实 +存在) + +根据发行版的不同,您可能还需要安装一系列 ``texlive`` 软件包,这些软件包提供了 +``XeLaTeX`` 工作所需的最小功能集。 + +.. _sphinx-pre-install_zh: + +检查Sphinx依赖项 +---------------- + +这有一个脚本可以自动检查Sphinx依赖项。如果它认得您的发行版,还会提示您所用发行 +版的安装命令:: + + $ ./scripts/sphinx-pre-install + Checking if the needed tools for Fedora release 26 (Twenty Six) are available + Warning: better to also install "texlive-luatex85". + You should run: + + sudo dnf install -y texlive-luatex85 + /usr/bin/virtualenv sphinx_1.7.9 + . sphinx_1.7.9/bin/activate + pip install -r Documentation/sphinx/requirements.txt + + Can't build as 1 mandatory dependency is missing at ./scripts/sphinx-pre-install line 468. + +默认情况下,它会检查html和PDF的所有依赖项,包括图像、数学表达式和LaTeX构建的 +需求,并假设将使用虚拟Python环境。html构建所需的依赖项被认为是必需的,其他依 +赖项则是可选的。 + +它支持两个可选参数: + +``--no-pdf`` + + 禁用PDF检查; + +``--no-virtualenv`` + + 使用Sphinx的系统打包,而不是Python虚拟环境。 + +Sphinx构建 +========== + +生成文档的常用方法是运行 ``make htmldocs`` 或 ``make pdfdocs`` 。还有其它可用 +的格式:请参阅 ``make help`` 的文档部分。生成的文档放在 ``Documentation/output`` +下相应格式的子目录中。 + +要生成文档,显然必须安装Sphinx( ``sphinx-build`` )。要让HTML输出更漂亮,可以 +使用Read the Docs Sphinx主题( ``sphinx_rtd_theme`` )。对于PDF输出,您还需要 +``XeLaTeX`` 和来自ImageMagick(https://www.imagemagick.org)的 ``convert(1)`` 。 +所有这些软件在大多发行版中都可用或已打包。 + +要传递额外的选项给Sphinx,可以使用make变量 ``SPHINXOPTS`` 。例如,使用 +``make SPHINXOPTS=-v htmldocs`` 获得更详细的输出。 + + +要删除生成的文档,请运行 ``make cleandocs`` 。 + +编写文档 +======== + +添加新文档很容易,只需: + +1. 在 ``Documentation`` 下某处添加一个新的 ``.rst`` 文件。 +2. 从 ``Documentation/index.rst`` 中的Sphinx `主目录树`_ 链接到它。 + +.. _主目录树: http://www.sphinx-doc.org/en/stable/markup/toctree.html + +对于简单的文档(比如您现在正在阅读的文档),这通常已经足够好了,但是对于较大 +的文档,最好创建一个子目录(或者使用现有的子目录)。例如,图形子系统文档位于 +``Documentation/gpu`` 下,拆分为多个 ``.rst`` 文件,并具有从主目录链接来的单 +独索引 ``index.rst`` (有自己的目录树 ``toctree`` )。 + +请参阅 `Sphinx <http://www.sphinx-doc.org/>`_ 和 `reStructuredText +<http://docutils.sourceforge.net/rst.html>`_ 的文档,以了解如何使用它们。 +特别是Sphinx `reStructuredText 基础`_ 这是开始学习使用reStructuredText的 +好地方。还有一些 `Sphinx 特殊标记结构`_ 。 + +.. _reStructuredText 基础: http://www.sphinx-doc.org/en/stable/rest.html +.. _Sphinx 特殊标记结构: http://www.sphinx-doc.org/en/stable/markup/index.html + +内核文档的具体指南 +------------------ + +这是一些内核文档的具体指南: + +* 请不要过于痴迷转换格式到reStructuredText。保持简单。在大多数情况下,文档 + 应该是纯文本,格式应足够一致,以便可以转换为其他格式。 + +* 将现有文档转换为reStructuredText时,请尽量减少格式更改。 + +* 在转换文档时,还要更新内容,而不仅仅是格式。 + +* 请遵循标题修饰符的顺序: + + 1. ``=`` 文档标题,要有上线:: + + ======== + 文档标题 + ======== + + 2. ``=`` 章:: + + 章标题 + ====== + + 3. ``-`` 节:: + + 节标题 + ------ + + 4. ``~`` 小节:: + + 小节标题 + ~~~~~~~~ + + 尽管RST没有规定具体的顺序(“没有强加一个固定数量和顺序的节标题装饰风格,最终 + 按照的顺序将是实际遇到的顺序。”),但是拥有一个通用级别的文档更容易遵循。 + +* 对于插入固定宽度的文本块(用于代码样例、用例等): ``::`` 用于语法高亮意义不 + 大的内容,尤其是短代码段; ``.. code-block:: <language>`` 用于需要语法高亮的 + 较长代码块。对于嵌入到文本中的简短代码片段,请使用 \`\` 。 + + +C域 +--- + +**Sphinx C域(Domain)** (name c)适用于C API文档。例如,函数原型: + +.. code-block:: rst + + .. c:function:: int ioctl( int fd, int request ) + +内核文档的C域有一些附加特性。例如,您可以使用诸如 ``open`` 或 ``ioctl`` 这样的 +通用名称重命名函数的引用名称: + +.. code-block:: rst + + .. c:function:: int ioctl( int fd, int request ) + :name: VIDIOC_LOG_STATUS + +函数名称(例如ioctl)仍保留在输出中,但引用名称从 ``ioctl`` 变为 +``VIDIOC_LOG_STATUS`` 。此函数的索引项也变为 ``VIDIOC_LOG_STATUS`` 。 + +请注意,不需要使用 ``c:func:`` 生成函数文档的交叉引用。由于一些Sphinx扩展的 +神奇力量,如果给定函数名的索引项存在,文档构建系统会自动将对 ``function()`` +的引用转换为交叉引用。如果在内核文档中看到 ``c:func:`` 的用法,请删除它。 + + +列表 +---- + +我们建议使用 *列式表* 格式。 *列式表* 格式是二级列表。与ASCII艺术相比,它们对 +文本文件的读者来说可能没有那么舒适。但其优点是易于创建或修改,而且修改的差异 +(diff)更有意义,因为差异仅限于修改的内容。 + +*平铺表* 也是一个二级列表,类似于 *列式表* ,但具有一些额外特性: + +* 列范围:使用 ``cspan`` 修饰,可以通过其他列扩展单元格 + +* 行范围:使用 ``rspan`` 修饰,可以通过其他行扩展单元格 + +* 自动将表格行最右边的单元格扩展到该行右侧空缺的单元格上。若使用 + ``:fill-cells:`` 选项,此行为可以从 *自动合并* 更改为 *自动插入* ,自动 + 插入(空)单元格,而不是扩展合并到最后一个单元格。 + +选项: + +* ``:header-rows:`` [int] 标题行计数 +* ``:stub-columns:`` [int] 标题列计数 +* ``:widths:`` [[int] [int] ... ] 列宽 +* ``:fill-cells:`` 插入缺少的单元格,而不是自动合并缺少的单元格 + +修饰: + +* ``:cspan:`` [int] 扩展列 +* ``:rspan:`` [int] 扩展行 + +下面的例子演示了如何使用这些标记。分级列表的第一级是 *表格行* 。 *表格行* 中 +只允许一个标记,即该 *表格行* 中的单元格列表。 *comments* ( ``..`` )和 +*targets* 例外(例如引用 ``:ref:`最后一行 <last row_zh>``` / :ref:`最后一行 +<last row_zh>` )。 + +.. code-block:: rst + + .. flat-table:: 表格标题 + :widths: 2 1 1 3 + + * - 表头 列1 + - 表头 列2 + - 表头 列3 + - 表头 列4 + + * - 行1 + - 字段1.1 + - 字段1.2(自动扩展) + + * - 行2 + - 字段2.1 + - :rspan:`1` :cspan:`1` 字段2.2~3.3 + + * .. _`last row_zh`: + + - 行3 + +渲染效果: + + .. flat-table:: 表格标题 + :widths: 2 1 1 3 + + * - 表头 列1 + - 表头 列2 + - 表头 列3 + - 表头 列4 + + * - 行1 + - 字段1.1 + - 字段1.2(自动扩展) + + * - 行2 + - 字段2.1 + - :rspan:`1` :cspan:`1` 字段2.2~3.3 + + * .. _`last row_zh`: + + - 行3 + +交叉引用 +-------- + +从一页文档到另一页文档的交叉引用可以通过简单地写出文件路径来完成,无特殊格式 +要求。路径可以是绝对路径或相对路径。绝对路径从“Documentation/”开始。例如,要 +交叉引用此页,以下写法皆可,取决于具体的文档目录(注意 ``.rst`` 扩展名是可选 +的):: + + 参见 Documentation/doc-guide/sphinx.rst 。此法始终可用。 + 请查看 sphinx.rst ,仅在同级目录中有效。 + 请阅读 ../sphinx.rst ,上级目录中的文件。 + +如果要使用相对路径,则需要使用Sphinx的 ``doc`` 修饰。例如,从同一目录引用此页 +的操作如下:: + + 参见 :doc:`sphinx文档的自定义链接文本 <sphinx>`. + +对于大多数用例,前者是首选,因为它更干净,更适合阅读源文件的人。如果您遇到一 +个没有任何特殊作用的 ``:doc:`` 用法,请将其转换为文档路径。 + +有关交叉引用kernel-doc函数或类型的信息,请参阅 +Documentation/doc-guide/kernel-doc.rst 。 + +.. _sphinx_kfigure_zh: + +图形图片 +======== + +如果要添加图片,应该使用 ``kernel-figure`` 和 ``kernel-image`` 指令。例如, +要插入具有可缩放图像格式的图形,请使用SVG(:ref:`svg_image_example_zh` ):: + + .. kernel-figure:: ../../../doc-guide/svg_image.svg + :alt: 简易 SVG 图片 + + SVG 图片示例 + +.. _svg_image_example_zh: + +.. kernel-figure:: ../../../doc-guide/svg_image.svg + :alt: 简易 SVG 图片 + + SVG 图片示例 + +内核figure(和image)指令支持 DOT 格式文件,请参阅 + +* DOT:http://graphviz.org/pdf/dotguide.pdf +* Graphviz:http://www.graphviz.org/content/dot-language + +一个简单的例子(:ref:`hello_dot_file_zh` ):: + + .. kernel-figure:: ../../../doc-guide/hello.dot + :alt: 你好,世界 + + DOT 示例 + +.. _hello_dot_file_zh: + +.. kernel-figure:: ../../../doc-guide/hello.dot + :alt: 你好,世界 + + DOT 示例 + +嵌入的渲染标记(或语言),如Graphviz的 **DOT** 由 ``kernel-render`` 指令提供:: + + .. kernel-render:: DOT + :alt: 有向图 + :caption: 嵌入式 **DOT** (Graphviz) 代码 + + digraph foo { + "五棵松" -> "国贸"; + } + +如何渲染取决于安装的工具。如果安装了Graphviz,您将看到一个矢量图像。否则,原始 +标记将作为 *文字块* 插入(:ref:`hello_dot_render_zh` )。 + +.. _hello_dot_render_zh: + +.. kernel-render:: DOT + :alt: 有向图 + :caption: 嵌入式 **DOT** (Graphviz) 代码 + + digraph foo { + "五棵松" -> "国贸"; + } + +*render* 指令包含 *figure* 指令中已知的所有选项,以及选项 ``caption`` 。如果 +``caption`` 有值,则插入一个 *figure* 节点,若无,则插入一个 *image* 节点。 +如果您想引用它,还需要一个 ``caption`` (:ref:`hello_svg_render_zh` )。 + +嵌入式 **SVG**:: + + .. kernel-render:: SVG + :caption: 嵌入式 **SVG** 标记 + :alt: 右上箭头 + + <?xml version="1.0" encoding="UTF-8"?> + <svg xmlns="http://www.w3.org/2000/svg" version="1.1" ...> + ... + </svg> + +.. _hello_svg_render_zh: + +.. kernel-render:: SVG + :caption: 嵌入式 **SVG** 标记 + :alt: 右上箭头 + + <?xml version="1.0" encoding="UTF-8"?> + <svg xmlns="http://www.w3.org/2000/svg" + version="1.1" baseProfile="full" width="70px" height="40px" viewBox="0 0 700 400"> + <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/> + <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/> + </svg> + diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index be6f11176200f67050f3225193c3fe02cd5cc177..ee6b20ca90803e0556e2f2bb49c917aeaa9c9897 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -18,8 +18,18 @@ admin-guide/index process/index + dev-tools/index + doc-guide/index + kernel-hacking/index filesystems/index arm64/index + sound/index + cpu-freq/index + mips/index + iio/index + riscv/index + core-api/index + openrisc/index 目录和表格 ---------- diff --git a/Documentation/translations/zh_CN/kernel-hacking/hacking.rst b/Documentation/translations/zh_CN/kernel-hacking/hacking.rst new file mode 100644 index 0000000000000000000000000000000000000000..ab974faddecf18f47bd1edf66e9b4e4383664a26 --- /dev/null +++ b/Documentation/translations/zh_CN/kernel-hacking/hacking.rst @@ -0,0 +1,708 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/kernel-hacking/hacking.rst + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +============== +内核骇客指北 +============== + +:作者: Rusty Russell + +引言 +===== + +欢迎咱优雅的读者们来阅读Rusty的非常不靠谱的Linux内核骇客(Hacking)指南。本文 +描述了内核代码的常见例程和一般要求:其目标是引导有经验的C程序员入门Linux内核 +开发。我回避了实现细节:这是代码要做的,也忽略了很多有用的例程。 + +在你读这篇文章之前,请理解我从来没有想过要写这篇文章,因为我的资历太低了; +但我一直想读这样的文章,自己写是唯一的方法。我希望它能成长为一个最佳实践、 +通用起点和其他信息的汇编。 + +玩家 +======= + +在任何时候,系统中的每个CPU都可以: + +- 与任何进程无关,服务于硬件中断; + +- 与任何进程无关,服务于软件中断(softirq)或子任务(tasklet); + +- 运行于内核空间中,与进程(用户上下文)相关联; + +- 在用户空间中运行进程。 + +它们之间有优先级顺序。最下面的两个可以互相抢占,但上面为严格的层次结构: +每个层级只能被上方的抢占。例如,当一个软中断在CPU上运行时,没有其他软中断 +会抢占它,但是硬件中断可以抢占它。不过,系统中的任何其他CPU都是独立执行的。 + +我们将会看到许多方法,用户上下文可以阻止中断,从而成为真正的不可抢占。 + +用户上下文 +------------ + +用户上下文是指当您从系统调用或其他陷阱进入时:就像用户空间一样,您可以被更 +重要的任务和中断抢占。您可以通过调用 :c:func:`schedule()` 进行睡眠。 + +.. note:: + + 在模块加载和卸载以及块设备层上的操作时,你始终处于用户上下文中。 + +在用户上下文中,当前 ``current`` 指针(指示我们当前正在执行的任务)是有效的, +且 :c:func:`in_interrupt()` ( ``include/linux/preempt.h`` )值为非(false)。 + +.. warning:: + + 请注意,如果您禁用了抢占或软中断(见下文),:c:func:`in_interrupt()` 会 + 返回假阳性。 + +硬件中断(Hard IRQs) +---------------------- + +像定时器、网卡和键盘等都是可能在任意时刻产生中断的真实硬件。内核运行中断 +处理程序,为硬件提供服务。内核确保处理程序永远不会重入:如果相同的中断到达, +它将被排队(或丢弃)。因为它会关闭中断,所以处理程序必须很快:通常它只是 +确认中断,标记一个“软件中断”以执行并退出。 + +您可以通过 :c:func:`in_irq()` 返回真来判断您处于硬件中断状态。 + +.. warning:: + + 请注意,如果中断被禁用,这将返回假阳性(见下文)。 + +软件中断上下文:软中断(Softirqs)与子任务(Tasklets) +------------------------------------------------------- + +当系统调用即将返回用户空间或硬件中断处理程序退出时,任何标记为挂起(通常通 +过硬件中断)的“软件中断”将运行( ``kernel/softirq.c`` )。 + +此处完成了许多真正的中断处理工作。在向SMP过渡的早期,只有“bottom halves下半 +部”(BHs)机制,无法利用多个CPU的优势。在从那些一团糟的就电脑切换过来后不久, +我们放弃了这个限制,转而使用“软中断”。 + +``include/linux/interrupt.h`` 列出了不同的软中断。定时器软中断是一个非常重要 +的软中断( ``include/linux/timer.h`` ):您可以注册它以在给定时间后为您调用 +函数。 + +软中断通常是一个很难处理的问题,因为同一个软中断将同时在多个CPU上运行。因此, +子任务( ``include/linux/interrupt.h`` )更常用:它们是动态可注册的(意味着 +您可以拥有任意数量),并且它们还保证任何子任务都只能在一个CPU上运行,不同的 +子任务也可以同时运行。 + +.. warning:: + + “tasklet”这个名字是误导性的:它们与“任务”无关,可能更多与当时 + 阿列克谢·库兹涅佐夫享用的糟糕伏特加有关。 + +你可以使用 :c:func:`in_softirq()` 宏( ``include/linux/preempt.h`` )来确认 +是否处于软中断(或子任务)中。 + +.. warning:: + + 注意,如果持有 :ref:`bottom half lock <local_bh_disable_zh>` 锁,这将返回 + 假阳性。 + +一些基本规则 +================ + +缺少内存保护 + 如果你损坏了内存,无论是在用户上下文还是中断上下文中,整个机器都会崩溃。 + 你确定你不能在用户空间里做你想做的事吗? + +缺少浮点或MMX + FPU上下文不会被保存;即使在用户上下文中,FPU状态也可能与当前进程不一致: + 您会弄乱某些用户进程的FPU状态。如果真的要这样做,就必须显式地保存/恢复 + 完整的FPU状态(并避免上下文切换)。这通常不是个好主意;请优先用定点算法。 + +严格的堆栈限制 + 对于大多数32位体系结构,根据配置选项的不同内核堆栈大约为3K到6K;对于大 + 多数64位机器,内核堆栈大约为14K,并且经常与中断共享,因此你无法使用全部。 + 应避免深度递归和栈上的巨型本地数组(用动态分配它们来代替)。 + +Linux内核是可移植的 + 就这样吧。您的代码应该是纯64位的,并且不依赖于字节序(endian)。您还应该 + 尽量减少CPU特定的东西,例如内联汇编(inline assembly)应该被干净地封装和 + 最小化以便于移植。一般来说,它应该局限于内核树中有体系结构依赖的部分。 + +输入输出控制(ioctls):避免编写新的系统调用 +============================================== + +系统调用(system call)通常看起来像这样:: + + asmlinkage long sys_mycall(int arg) + { + return 0; + } + + +首先,在大多数情况下,您无需创建新的系统调用。创建一个字符设备并为其实现适当 +的输入输出控制(ioctls)。这比系统调用灵活得多,不必写进每个体系结构的 +``include/asm/unistd.h`` 和 ``arch/kernel/entry.S`` 文件里,而且更容易被Linus +接受。 + +如果您的程序所做的只是读取或写入一些参数,请考虑实现 :c:func:`sysfs()` 接口。 + +在输入输出控制中,您处于进程的用户上下文。出现错误时,返回一个负的错误参数 +(errno,请参阅 ``include/uapi/asm-generic/errno-base.h`` 、 +``include/uapi/asm-generic/errno.h`` 和 ``include/linux/errno.h`` ),否则返 +回0。 + +在睡眠之后,您应该检查是否出现了信号:Unix/Linux处理信号的方法是暂时退出系统 +调用,并返回 ``-ERESTARTSYS`` 错误。系统调用入口代码将切换回用户上下文,处理 +信号处理程序,然后系统调用将重新启动(除非用户禁用了该功能)。因此,您应该准 +备好处理重新启动,例如若您处理某些数据结构到一半。 + +:: + + if (signal_pending(current)) + return -ERESTARTSYS; + + +如果你要做更长时间的计算:优先考虑用户空间。如果你真的想在内核中做这件事,你 +应该定期检查你是否需要让出CPU(请记得每个CPU都有协作多任务)。 +习惯用法:: + + cond_resched(); /* Will sleep */ + + +接口设计的小注释:UNIX系统调用的格言是“提供机制而不是策略 +Provide mechanism not policy”。 + +死锁的“配方” +==================== + +您不能调用任何可能睡眠的程序,除非: + +- 您处于用户上下文中。 + +- 你未拥有任何自旋锁。 + +- 您已经启用中断(实际上,Andi Kleen说调度代码将为您启用它们,但这可能不是 + 您想要的)。 + +注意,有些函数可能隐式地睡眠:常见的是用户空间访问函数(\*_user)和没有 +``GFP_ATOMIC`` 的内存分配函数。 + +您应该始终打开 ``CONFIG_DEBUG_ATOMIC_SLEEP`` 项来编译内核,如果您违反这些 +规则,它将警告您。如果你 **真的** 违反了规则,你最终会锁住你的电脑。 + +真的会这样。 + + +常用函数/程序 +=============== + +:c:func:`printk()` +------------------ + +定义于 ``include/linux/printk.h`` + +:c:func:`printk()` 将内核消息提供给控制台、dmesg和syslog守护进程。它对于调 +试和报告错误很有用,并且可以在中断上下文中使用,但是使用时要小心:如果机器 +的控制台中充斥着printk消息则会无法使用。它使用与ANSI C printf基本兼容的格式 +字符串,并通过C字符串串联为其提供第一个“优先”参数:: + + printk(KERN_INFO "i = %u\n", i); + + +参见 ``include/linux/kern_levels.h`` ;了解其他 ``KERN_`` 值;syslog将这些值 +解释为级别。特殊用法:打印IP地址使用:: + + __be32 ipaddress; + printk(KERN_INFO "my ip: %pI4\n", &ipaddress); + + +:c:func:`printk()` 内部使用的1K缓冲区,不捕获溢出。请确保足够使用。 + +.. note:: + + 当您开始在用户程序中将printf打成printk时,就知道自己是真正的内核程序员了 + :) + +.. note:: + + 另一个注释:最初的unix第六版源代码在其printf函数的顶部有一个注释:“printf + 不应该用于叽叽喳喳”。你也应该遵循此建议。 + +:c:func:`copy_to_user()` / :c:func:`copy_from_user()` / :c:func:`get_user()` / :c:func:`put_user()` +--------------------------------------------------------------------------------------------------- + +定义于 ``include/linux/uaccess.h`` / ``asm/uaccess.h`` + +**[睡眠]** + +:c:func:`put_user()` 和 :c:func:`get_user()` 用于从用户空间中获取和向用户空 +间中传出单个值(如int、char或long)。指向用户空间的指针永远不应该直接取消 +引用:应该使用这些程序复制数据。两者都返回 ``-EFAULT`` 或 0。 + +:c:func:`copy_to_user()` 和 :c:func:`copy_from_user()` 更通用:它们从/向用户 +空间复制任意数量的数据。 + +.. warning:: + + 与 :c:func:`put_user()` 和 :c:func:`get_user()` 不同,它们返回未复制的 + 数据量(即0仍然意味着成功)。 + +【是的,这个愚蠢的接口真心让我尴尬。火爆的口水仗大概每年都会发生。 +—— Rusty Russell】 + +这些函数可以隐式睡眠。它不应该在用户上下文之外调用(没有意义)、调用时禁用中断 +或获得自旋锁。 + +:c:func:`kmalloc()`/:c:func:`kfree()` +------------------------------------- + +定义于 ``include/linux/slab.h`` + +**[可能睡眠:见下]** + +这些函数用于动态请求指针对齐的内存块,类似用户空间中的malloc和free,但 +:c:func:`kmalloc()` 需要额外的标志词。重要的值: + +``GFP_KERNEL`` + 可以睡眠和交换以释放内存。只允许在用户上下文中使用,但这是分配内存最可靠 + 的方法。 + +``GFP_ATOMIC`` + 不会睡眠。较 ``GFP_KERNEL`` 更不可靠,但可以从中断上下文调用。你 **应该** + 有一个很好的内存不足错误处理策略。 + +``GFP_DMA`` + 分配低于16MB的ISA DMA。如果你不知道那是什么,那你就不需要了。非常不可靠。 + +如果您看到一个从无效上下文警告消息调用的睡眠的函数,那么您可能在没有 +``GFP_ATOMIC`` 的情况下从中断上下文调用了一个睡眠的分配函数。你必须立即修复, +快点! + +如果你要分配至少 ``PAGE_SIZE`` ( ``asm/page.h`` 或 ``asm/page_types.h`` ) +字节,请考虑使用 :c:func:`__get_free_pages()` ( ``include/linux/gfp.h`` )。 +它采用顺序参数(0表示页面大小,1表示双页,2表示四页……)和与上述相同的内存 +优先级标志字。 + +如果分配的字节数超过一页,可以使用 :c:func:`vmalloc()` 。它将在内核映射中分 +配虚拟内存。此块在物理内存中不是连续的,但是MMU(内存管理单元)使它看起来像 +是为您准备好的连续空间(因此它只是看起来对cpu连续,对外部设备驱动程序则不然)。 +如果您真的需要为一些奇怪的设备提供大量物理上连续的内存,那么您就会遇到问题: +Linux对此支持很差,因为正在运行的内核中的内存碎片化会使它变得很困难。最好的 +方法是在引导过程的早期通过 :c:func:`alloc_bootmem()` 函数分配。 + +在创建自己的常用对象缓存之前,请考虑使用 ``include/linux/slab.h`` 中的slab +缓存。 + +:c:macro:`current` +------------------ + +定义于 ``include/asm/current.h`` + +此全局变量(其实是宏)包含指向当前任务结构(task structure)的指针,因此仅在 +用户上下文中有效。例如,当进程进行系统调用时,这将指向调用进程的任务结构。 +在中断上下文中不为空(**not NULL**)。 + +:c:func:`mdelay()`/:c:func:`udelay()` +------------------------------------- + +定义于 ``include/asm/delay.h`` / ``include/linux/delay.h`` + +:c:func:`udelay()` 和 :c:func:`ndelay()` 函数可被用于小暂停。不要对它们使用 +大的值,因为这样会导致溢出——帮助函数 :c:func:`mdelay()` 在这里很有用,或者 +考虑 :c:func:`msleep()`。 + +:c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()`/:c:func:`cpu_to_le32()`/:c:func:`le32_to_cpu()` +----------------------------------------------------------------------------------------------- + +定义于 ``include/asm/byteorder.h`` + +:c:func:`cpu_to_be32()` 系列函数(其中“32”可以替换为64或16,“be”可以替换为 +“le”)是在内核中进行字节序转换的常用方法:它们返回转换后的值。所有的变体也 +提供反向转换函数: +:c:func:`be32_to_cpu()` 等。 + +这些函数有两个主要的变体:指针变体,例如 :c:func:`cpu_to_be32p()` ,它获取 +指向给定类型的指针,并返回转换后的值。另一个变体是“in-situ”系列,例如 +:c:func:`cpu_to_be32s()` ,它转换指针引用的值,并返回void。 + +:c:func:`local_irq_save()`/:c:func:`local_irq_restore()` +-------------------------------------------------------- + +定义于 ``include/linux/irqflags.h`` + + +这些程序禁用本地CPU上的硬中断,并还原它们。它们是可重入的;在其一个 +``unsigned long flags`` 参数中保存以前的状态。如果您知道中断已启用,那么可 +直接使用 :c:func:`local_irq_disable()` 和 :c:func:`local_irq_enable()`。 + +.. _local_bh_disable_zh: + +:c:func:`local_bh_disable()`/:c:func:`local_bh_enable()` +-------------------------------------------------------- + +定义于 ``include/linux/bottom_half.h`` + + +这些程序禁用本地CPU上的软中断,并还原它们。它们是可重入的;如果之前禁用了 +软中断,那么在调用这对函数之后仍然会禁用它们。它们阻止软中断和子任务在当前 +CPU上运行。 + +:c:func:`smp_processor_id()` +---------------------------- + +定义于 ``include/linux/smp.h`` + +:c:func:`get_cpu()` 禁用抢占(这样您就不会突然移动到另一个cpu)并返回当前 +处理器号,介于0和 ``NR_CPUS`` 之间。请注意,CPU编号不一定是连续的。完成后, +使用 :c:func:`put_cpu()` 再次返回。 + +如果您知道您不能被另一个任务抢占(即您处于中断上下文中,或已禁用抢占),您 +可以使用 :c:func:`smp_processor_id()`。 + +``__init``/``__exit``/``__initdata`` +------------------------------------ + +定义于 ``include/linux/init.h`` + +引导之后,内核释放一个特殊的部分;用 ``__init`` 标记的函数和用 ``__initdata`` +标记的数据结构在引导完成后被丢弃:同样地,模块在初始化后丢弃此内存。 +``__exit`` 用于声明只在退出时需要的函数:如果此文件未编译为模块,则该函数将 +被删除。请参阅头文件以使用。请注意,使用 :c:func:`EXPORT_SYMBOL()` 或 +:c:func:`EXPORT_SYMBOL_GPL()` 将标记为 ``__init`` 的函数导出到模块是没有意义 +的——这将出问题。 + + +:c:func:`__initcall()`/:c:func:`module_init()` +---------------------------------------------- + +定义于 ``include/linux/init.h`` / ``include/linux/module.h`` + +内核的许多部分都作为模块(内核的可动态加载部分)良好服务。使用 +:c:func:`module_init()` 和 :c:func:`module_exit()` 宏可以简化代码编写,无需 +``#ifdef`` ,即可以作为模块运行或内置在内核中。 + +:c:func:`module_init()` 宏定义在模块插入时(如果文件编译为模块)或在引导时 +调用哪个函数:如果文件未编译为模块,:c:func:`module_init()` 宏将等效于 +:c:func:`__initcall()` ,它通过链接器的魔力确保在引导时调用该函数。 + +该函数可以返回一个错误值,以导致模块加载失败(不幸的是,如果将模块编译到内核 +中,则此操作无效)。此函数在启用中断的用户上下文中调用,因此可以睡眠。 + +:c:func:`module_exit()` +----------------------- + + +定义于 ``include/linux/module.h`` + +这个宏定义了在模块删除时要调用的函数(如果是编译到内核中的文件,则无用武之地)。 +只有在模块使用计数到零时才会调用它。这个函数也可以睡眠,但不能失败:当它返回 +时,所有的东西都必须清理干净。 + +注意,这个宏是可选的:如果它不存在,您的模块将不可移除(除非 ``rmmod -f`` )。 + +:c:func:`try_module_get()`/:c:func:`module_put()` +------------------------------------------------- + +定义于 ``include/linux/module.h`` + +这些函数会操作模块使用计数,以防止删除(如果另一个模块使用其导出的符号之一, +则无法删除模块,参见下文)。在调用模块代码之前,您应该在该模块上调用 +:c:func:`try_module_get()` :若失败,那么该模块将被删除,您应该将其视为不存在。 +若成功,您就可以安全地进入模块,并在完成后调用模块 :c:func:`module_put()` 。 + +大多数可注册结构体都有所有者字段,例如在 +:c:type:`struct file_operations <file_operations>` 结构体中,此字段应设置为 +宏 ``THIS_MODULE`` 。 + +等待队列 ``include/linux/wait.h`` +==================================== + +**[睡眠]** + +等待队列用于等待某程序在条件为真时唤醒另一程序。必须小心使用,以确保没有竞争 +条件。先声明一个 :c:type:`wait_queue_head_t` ,然后对希望等待该条件的进程声明 +一个关于它们自己的 :c:type:`wait_queue_entry_t` ,并将其放入队列中。 + +声明 +----- + +使用 :c:func:`DECLARE_WAIT_QUEUE_HEAD()` 宏声明一个 ``wait_queue_head_t`` , +或者在初始化代码中使用 :c:func:`init_waitqueue_head()` 程序。 + +排队 +----- + +将自己放在等待队列中相当复杂,因为你必须在检查条件之前将自己放入队列中。有一 +个宏可以来执行此操作: :c:func:`wait_event_interruptible()` +( ``include/linux/wait.h`` )第一个参数是等待队列头,第二个参数是计算的表达 +式;当该表达式为true时宏返回0,或者在接收到信号时返回 ``-ERESTARTSYS`` 。 +:c:func:`wait_event()` 版本会忽略信号。 + +唤醒排队任务 +------------- + +调用 :c:func:`wake_up()` ( ``include/linux/wait.h`` ),它将唤醒队列中的所有 +进程。例外情况:如果有一个进程设置了 ``TASK_EXCLUSIVE`` ,队列的其余部分将不 +会被唤醒。这个基本函数的其他变体也可以在同一个头文件中使用。 + +原子操作 +========= + +某些操作在所有平台上都有保证。第一类为操作 :c:type:`atomic_t` +( ``include/asm/atomic.h`` )的函数;它包含一个有符号整数(至少32位长), +您必须使用这些函数来操作或读取 :c:type:`atomic_t` 变量。 +:c:func:`atomic_read()` 和 :c:func:`atomic_set()` 获取并设置计数器,还有 +:c:func:`atomic_add()` ,:c:func:`atomic_sub()` ,:c:func:`atomic_inc()` , +:c:func:`atomic_dec()` 和 :c:func:`atomic_dec_and_test()` (如果递减为零, +则返回true)。 + +是的。它在原子变量为零时返回true(即!=0)。 + +请注意,这些函数比普通的算术运算速度慢,因此不应过度使用。 + +第二类原子操作是在 ``unsigned long`` ( ``include/linux/bitops.h`` )上的 +原子位操作。这些操作通常采用指向位模式(bit pattern)的指针,第0位是最低有效 +位。:c:func:`set_bit()`,:c:func:`clear_bit()` 和 :c:func:`change_bit()` 设置、 +清除和更改给定位。:c:func:`test_and_set_bit()` ,:c:func:`test_and_clear_bit()` +和 :c:func:`test_and_change_bit()` 执行相同的操作,但如果之前设置了位,则返回 +true;这些对于原子设置标志特别有用。 + +可以使用大于 ``BITS_PER_LONG`` 位的位索引调用这些操作。但结果在大端序平台上 +不太正常,所以最好不要这样做。 + +符号 +===== + +在内核内部,正常的链接规则仍然适用(即除非用static关键字将符号声明为文件范围, +否则它可以在内核中的任何位置使用)。但是对于模块,会保留一个特殊可导出符号表, +该表将入口点限制为内核内部。模块也可以导出符号。 + +:c:func:`EXPORT_SYMBOL()` +------------------------- + +定义于 ``include/linux/export.h`` + +这是导出符号的经典方法:动态加载的模块将能够正常使用符号。 + +:c:func:`EXPORT_SYMBOL_GPL()` +----------------------------- + +定义于 ``include/linux/export.h`` + + +类似于 :c:func:`EXPORT_SYMBOL()`,只是 :c:func:`EXPORT_SYMBOL_GPL()` 导出的 +符号只能由具有由 :c:func:`MODULE_LICENSE()` 指定GPL兼容许可证的模块看到。这 +意味着此函数被认为是一个内部实现问题,而不是一个真正的接口。一些维护人员和 +开发人员在添加一些新的API或功能时可能却需要导出 EXPORT_SYMBOL_GPL()。 + +:c:func:`EXPORT_SYMBOL_NS()` +---------------------------- + +定义于 ``include/linux/export.h`` + +这是 ``EXPORT_SYMBOL()`` 的变体,允许指定符号命名空间。符号名称空间记录于 +Documentation/core-api/symbol-namespaces.rst 。 + +:c:func:`EXPORT_SYMBOL_NS_GPL()` +-------------------------------- + +定义于 ``include/linux/export.h`` + +这是 ``EXPORT_SYMBOL_GPL()`` 的变体,允许指定符号命名空间。符号名称空间记录于 +Documentation/core-api/symbol-namespaces.rst 。 + +程序与惯例 +=========== + +双向链表 ``include/linux/list.h`` +----------------------------------- + +内核头文件中曾经有三组链表程序,但这一组是赢家。如果你对一个单链表没有特别迫切的 +需求,那么这是一个不错的选择。 + +通常 :c:func:`list_for_each_entry()` 很有用。 + +返回值惯例 +------------ + +对于在用户上下文中调用的代码,违背C语言惯例是很常见的,即返回0表示成功,返回 +负错误值(例如 ``-EFAULT`` )表示失败。这在一开始可能是不直观的,但在内核中 +相当普遍。 + +使用 :c:func:`ERR_PTR()` ( ``include/linux/err.h`` )将负错误值编码到指针中, +然后使用 :c:func:`IS_ERR()` 和 :c:func:`PTR_ERR()` 将其再取出:避免为错误值 +使用单独的指针参数。挺讨厌的,但的确是个好方式。 + +破坏编译 +---------- + +Linus和其他开发人员有时会更改开发内核中的函数或结构体名称;这样做不仅是为了 +让每个人都保持警惕,还反映了一个重大的更改(例如,不能再在打开中断的情况下 +调用,或者执行额外的检查,或者不执行以前捕获的检查)。通常这会附带一个linux +内核邮件列表中相当全面的注释;请搜索存档以查看。简单地对文件进行全局替换通常 +会让事情变得 **更糟** 。 + +初始化结构体成员 +------------------ + +初始化结构体的首选方法是使用指定的初始化器,如ISO C99所述。 +例如:: + + static struct block_device_operations opt_fops = { + .open = opt_open, + .release = opt_release, + .ioctl = opt_ioctl, + .check_media_change = opt_media_change, + }; + + +这使得很容易查找(grep),并且可以清楚地看到设置了哪些结构字段。你应该这样做, +因为它看起来很酷。 + +GNU 扩展 +---------- + +Linux内核中明确允许GNU扩展。请注意,由于缺乏通用性,一些更复杂的版本并没有 +得到很好的支持,但以下内容被认为是标准的(有关更多详细信息,请参阅GCC info页 +的“C 扩展”部分——是的,实际上是info页,手册页只是info中内容的简短摘要)。 + +- 内联函数 + +- 语句表达式(Statement expressions)(即({ 和 })结构)。 + + +- 声明函数/变量/类型的属性(__attribute__) + +- typeof + +- 零长度数组 + +- 宏变量 + +- 空指针运算 + +- 非常量(Non-Constant)初始化程序 + +- 汇编程序指令(在 arch/ 和 include/asm/ 之内) + +- 字符串函数名(__func__)。 + +- __builtin_constant_p() + +在内核中使用long long时要小心,gcc为其生成的代码非常糟糕:除法和乘法在i386上 +不能工作,因为内核环境中缺少用于它的gcc运行时函数。 + +C++ +--- + +在内核中使用C++通常是个坏主意,因为内核不提供必要的运行时环境,并且不为其 +测试包含文件。不过这仍然是可能的,但不建议。如果你真的想这么做,至少别用 +异常处理(exceptions)。 + +#if +--- + +通常认为,在头文件(或.c文件顶部)中使用宏来抽象函数比在源代码中使用“if”预 +处理器语句更干净。 + +把你的东西放进内核里 +====================== + +为了让你的东西更正式、补丁更整洁,还有一些工作要做: + +- 搞清楚你在谁的地界儿上干活。查看源文件的顶部、 ``MAINTAINERS`` 文件以及 + ``CREDITS`` 文件的最后一部分。你应该和此人协调,确保你没有重新发明轮子, + 或者尝试一些已经被拒绝的东西。 + + 确保你把你的名字和电子邮件地址放在你创建或修改的任何文件的顶部。当人们发 + 现一个缺陷,或者想要做出修改时,这是他们首先会看的地方。 + +- 通常你需要一个配置选项来支持你的内核编程。在适当的目录中编辑 ``Kconfig`` 。 + 配置语言很容易通过剪切和粘贴来使用,在 + Documentation/kbuild/kconfig-language.rst 中有完整的文档。 + + 在您对选项的描述中,请确保同时照顾到了专家用户和对此功能一无所知的用户。 + 在此说明任何不兼容和问题。结尾一定要写上“如有疑问,就选N”(或者是“Y”); + 这是针对那些看不懂你在说什么的人的。 + +- 编辑 ``Makefile`` :配置变量在这里导出,因此通常你只需添加一行 + “obj-$(CONFIG_xxx) += xxx.o”。语法记录在 + Documentation/kbuild/makefiles.rst 。 + +- 如果你做了一些有意义的事情,那可以把自己放进 ``CREDITS`` ,通常不止一个 + 文件(无论如何你的名字都应该在源文件的顶部)。维护人员意味着您希望在对 + 子系统进行更改时得到询问,并了解缺陷;这意味着对某部分代码做出更多承诺。 + +- 最后,别忘记去阅读 Documentation/process/submitting-patches.rst , + 也许还有 Documentation/process/submitting-drivers.rst 。 + +Kernel 仙女棒 +=============== + +浏览源代码时的一些收藏。请随意添加到此列表。 + +``arch/x86/include/asm/delay.h``:: + + #define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) + + +``include/linux/fs.h``:: + + /* + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a dentry + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + */ + #define ERR_PTR(err) ((void *)((long)(err))) + #define PTR_ERR(ptr) ((long)(ptr)) + #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) + +``arch/x86/include/asm/uaccess_32.h:``:: + + #define copy_to_user(to,from,n) \ + (__builtin_constant_p(n) ? \ + __constant_copy_to_user((to),(from),(n)) : \ + __generic_copy_to_user((to),(from),(n))) + + +``arch/sparc/kernel/head.S:``:: + + /* + * Sun people can't spell worth damn. "compatibility" indeed. + * At least we *know* we can't spell, and use a spell-checker. + */ + + /* Uh, actually Linus it is I who cannot spell. Too much murky + * Sparc assembly will do this to ya. + */ + C_LABEL(cputypvar): + .asciz "compatibility" + + /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */ + .align 4 + C_LABEL(cputypvar_sun4m): + .asciz "compatible" + + +``arch/sparc/lib/checksum.S:``:: + + /* Sun, you just can't beat me, you just can't. Stop trying, + * give up. I'm serious, I am going to kick the living shit + * out of you, game over, lights out. + */ + + +致谢 +===== + +感谢Andi Kleen提出点子,回答我的问题,纠正我的错误,充实内容等帮助。 +感谢Philipp Rumpf做了许多拼写和清晰度修复,以及一些优秀的不明显的点。 +感谢Werner Almesberger对 :c:func:`disable_irq()` 做了一个很好的总结, +Jes Sorensen和Andrea Arcangeli补充了一些注意事项。 +感谢Michael Elizabeth Chastain检查并补充了配置部分。 +感谢Telsa Gwynne教我DocBook。 diff --git a/Documentation/translations/zh_CN/kernel-hacking/index.rst b/Documentation/translations/zh_CN/kernel-hacking/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..df530de2278d519638f70d8f0702d40e00588d1e --- /dev/null +++ b/Documentation/translations/zh_CN/kernel-hacking/index.rst @@ -0,0 +1,22 @@ +.. _kernel_hacking_zh: + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/kernel-hacking/index.rst + +:译者: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> + +============= +内核骇客指南 +============= + +.. toctree:: + :maxdepth: 2 + + hacking + +TODO + +- locking diff --git a/Documentation/translations/zh_CN/openrisc/index.rst b/Documentation/translations/zh_CN/openrisc/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..d722642796c80134364a915fbfeebb669aed94bd --- /dev/null +++ b/Documentation/translations/zh_CN/openrisc/index.rst @@ -0,0 +1,30 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../openrisc/index` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_openrisc_index: + + +================= +OpenRISC 体系架构 +================= + +.. toctree:: + :maxdepth: 2 + + openrisc_port + todo + +Todolist: + features + + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/translations/zh_CN/openrisc/openrisc_port.rst b/Documentation/translations/zh_CN/openrisc/openrisc_port.rst new file mode 100644 index 0000000000000000000000000000000000000000..e87d0eec281d56ec3c554a12b81cd66b4636125c --- /dev/null +++ b/Documentation/translations/zh_CN/openrisc/openrisc_port.rst @@ -0,0 +1,124 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../openrisc/openrisc_port` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_openrisc_port: + +============== +OpenRISC Linux +============== + +这是Linux对OpenRISC类微处理器的移植;具体来说,最早移植目标是32位 +OpenRISC 1000系列(或1k)。 + +关于OpenRISC处理器和正在进行中的开发的信息: + + ======= ============================= + 网站 https://openrisc.io + 邮箱 openrisc@lists.librecores.org + ======= ============================= + +--------------------------------------------------------------------- + +OpenRISC工具链和Linux的构建指南 +=============================== + +为了构建和运行Linux for OpenRISC,你至少需要一个基本的工具链,或许 +还需要架构模拟器。 这里概述了准备就位这些部分的步骤。 + +1) 工具链 + +工具链二进制文件可以从openrisc.io或我们的github发布页面获得。不同 +工具链的构建指南可以在openrisc.io或Stafford的工具链构建和发布脚本 +中找到。 + + ====== ================================================= + 二进制 https://github.com/openrisc/or1k-gcc/releases + 工具链 https://openrisc.io/software + 构建 https://github.com/stffrdhrn/or1k-toolchain-build + ====== ================================================= + +2) 构建 + +像往常一样构建Linux内核:: + + make ARCH=openrisc CROSS_COMPILE="or1k-linux-" defconfig + make ARCH=openrisc CROSS_COMPILE="or1k-linux-" + +3) 在FPGA上运行(可选) + +OpenRISC社区通常使用FuseSoC来管理构建和编程SoC到FPGA中。 下面是用 +OpenRISC SoC对De0 Nano开发板进行编程的一个例子。 在构建过程中, +FPGA RTL是从FuseSoC IP核库中下载的代码,并使用FPGA供应商工具构建。 +二进制文件用openocd加载到电路板上。 + +:: + + git clone https://github.com/olofk/fusesoc + cd fusesoc + sudo pip install -e . + + fusesoc init + fusesoc build de0_nano + fusesoc pgm de0_nano + + openocd -f interface/altera-usb-blaster.cfg \ + -f board/or1k_generic.cfg + + telnet localhost 4444 + > init + > halt; load_image vmlinux ; reset + +4) 在模拟器上运行(可选) + +QEMU是一个处理器仿真器,我们推荐它来模拟OpenRISC平台。 请按照QEMU网 +站上的OpenRISC说明,让Linux在QEMU上运行。 你可以自己构建QEMU,但你的 +Linux发行版可能提供了支持OpenRISC的二进制包。 + + ============= ====================================================== + qemu openrisc https://wiki.qemu.org/Documentation/Platforms/OpenRISC + ============= ====================================================== + +--------------------------------------------------------------------- + +术语表 +====== + +代码中使用了以下符号约定以将范围限制在几个特定处理器实现上: + +========= ======================= +openrisc: OpenRISC类型处理器 +or1k: OpenRISC 1000系列处理器 +or1200: OpenRISC 1200处理器 +========= ======================= + +--------------------------------------------------------------------- + +历史 +==== + +2003-11-18 Matjaz Breskvar (phoenix@bsemi.com) + 将linux初步移植到OpenRISC或32架构。 + 所有的核心功能都实现了,并且可以使用。 + +2003-12-08 Matjaz Breskvar (phoenix@bsemi.com) + 彻底改变TLB失误处理。 + 重写异常处理。 + 在默认的initrd中实现了sash-3.6的所有功能。 + 大幅改进的版本。 + +2004-04-10 Matjaz Breskvar (phoenix@bsemi.com) + 大量的bug修复。 + 支持以太网,http和telnet服务器功能。 + 可以运行许多标准的linux应用程序。 + +2004-06-26 Matjaz Breskvar (phoenix@bsemi.com) + 移植到2.6.x。 + +2004-11-30 Matjaz Breskvar (phoenix@bsemi.com) + 大量的bug修复和增强功能。 + 增加了opencores framebuffer驱动。 + +2010-10-09 Jonas Bonn (jonas@southpole.se) + 重大重写,使其与上游的Linux 2.6.36看齐。 diff --git a/Documentation/translations/zh_CN/openrisc/todo.rst b/Documentation/translations/zh_CN/openrisc/todo.rst new file mode 100644 index 0000000000000000000000000000000000000000..9944ad05473b7bb59e4134ec1a1dc52f8f1f880c --- /dev/null +++ b/Documentation/translations/zh_CN/openrisc/todo.rst @@ -0,0 +1,20 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../openrisc/todo` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_openrisc_todo.rst: + +======== +待办事项 +======== + +OpenRISC Linux的移植已经完全投入使用,并且从 2.6.35 开始就一直在上游同步。 +然而,还有一些剩余的项目需要在未来几个月内完成。 下面是一个即将进行调查的已知 +不尽完美的项目列表,即我们的待办事项列表。 + +- 实现其余的DMA API……dma_map_sg等。 + +- 完成重命名清理工作……代码中提到了or32,这是架构的一个老名字。 我们 + 已经确定的名字是or1k,这个改变正在以缓慢积累的方式进行。 目前,or32相当 + 于or1k。 diff --git a/Documentation/translations/zh_CN/process/1.Intro.rst b/Documentation/translations/zh_CN/process/1.Intro.rst index 10a15f3dc28203cc24fe9e511c31ee3ffe604d53..4f9284cbe33b6de8a0776dc03ad4dd7966494c01 100644 --- a/Documentation/translations/zh_CN/process/1.Intro.rst +++ b/Documentation/translations/zh_CN/process/1.Intro.rst @@ -1,162 +1,170 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/1.Intro.rst <development_process_intro>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_process_intro: -介绍 +引言 ==== -执行摘要 +内容提要 -------- -本节的其余部分涵盖了内核开发过程的范围,以及开发人员及其雇主在这方面可能遇 -到的各种挫折。内核代码应该合并到正式的(“主线”)内核中有很多原因,包括对用 -户的自动可用性、多种形式的社区支持以及影响内核开发方向的能力。提供给Linux -内核的代码必须在与GPL兼容的许可证下可用。 +本节的其余部分涵盖了内核开发的过程,以及开发人员及其雇主在这方面可能遇到的 +各种问题。有很多原因使内核代码应被合并到正式的(“主线”)内核中,包括对用户 +的自动可用性、多种形式的社区支持以及影响内核开发方向的能力。提供给Linux内核 +的代码必须在与GPL兼容的许可证下可用。 :ref:`cn_development_process` 介绍了开发过程、内核发布周期和合并窗口的机制。 -涵盖了补丁开发、审查和合并周期中的各个阶段。有一些关于工具和邮件列表的讨论。 -鼓励希望开始内核开发的开发人员作为初始练习跟踪并修复bug。 +涵盖了补丁开发、审查和合并周期中的各个阶段。还有一些关于工具和邮件列表的讨论? +鼓励希望开始内核开发的开发人员跟踪并修复缺陷以作为初步练习。 -:ref:`cn_development_early_stage` 包括早期项目规划,重点是尽快让开发社区参与 +:ref:`cn_development_early_stage` 包括项目的早期规划,重点是尽快让开发社区 +参与进来。 -:ref:`cn_development_coding` 是关于编码过程的;讨论了其他开发人员遇到的几个 -陷阱。对补丁的一些要求已经涵盖,并且介绍了一些工具,这些工具有助于确保内核 +:ref:`cn_development_coding` 是关于编程过程的;介绍了其他开发人员遇到的几个 +陷阱。也涵盖了对补丁的一些要求,并且介绍了一些工具,这些工具有助于确保内核 补丁是正确的。 -:ref:`cn_development_posting` 讨论发布补丁以供评审的过程。为了让开发社区 -认真对待,补丁必须正确格式化和描述,并且必须发送到正确的地方。遵循本节中的 -建议有助于确保为您的工作提供最好的接纳。 +:ref:`cn_development_posting` 描述发布补丁以供评审的过程。为了让开发社区能 +认真对待,补丁必须被正确格式化和描述,并且必须发送到正确的地方。遵循本节中的 +建议有助于确保您的工作能被较好地接纳。 -:ref:`cn_development_followthrough` 介绍了发布补丁之后发生的事情;该工作 -在这一点上还远远没有完成。与审阅者一起工作是开发过程中的一个重要部分;本节 -提供了一些关于如何在这个重要阶段避免问题的提示。当补丁被合并到主线中时, -开发人员要注意不要假定任务已经完成。 +:ref:`cn_development_followthrough` 介绍了发布补丁之后发生的事情;工作在这时 +还远远没有完成。与审阅者一起工作是开发过程中的一个重要部分;本节提供了一些 +关于如何在这个重要阶段避免问题的提示。当补丁被合并到主线中时,开发人员要注意 +不要假定任务已经完成。 -:ref:`cn_development_advancedtopics` 介绍了两个“高级”主题: -使用Git管理补丁和查看其他人发布的补丁。 +:ref:`cn_development_advancedtopics` 介绍了两个“高级”主题:使用Git管理补丁 +和查看其他人发布的补丁。 -:ref:`cn_development_conclusion` 总结了有关内核开发的更多信息,附带有带有 -指向资源的链接. +:ref:`cn_development_conclusion` 总结了有关内核开发的更多信息,附带有相关资源 +链接。 -这个文件是关于什么的 +这个文档是关于什么的 -------------------- -Linux内核有超过800万行代码,每个版本的贡献者超过1000人,是现存最大、最活跃 -的免费软件项目之一。从1991年开始,这个内核已经发展成为一个最好的操作系统 -组件,运行在袖珍数字音乐播放器、台式PC、现存最大的超级计算机以及所有类型的 -系统上。它是一种适用于几乎任何情况的健壮、高效和可扩展的解决方案。 +Linux内核有超过800万行代码,每个版本的贡献者超过1000人,是现存最大、最活跃的 +免费软件项目之一。从1991年开始,这个内核已经发展成为一个最好的操作系统组件, +运行在袖珍数字音乐播放器、台式电脑、现存最大的超级计算机以及所有类型的系统上。 +它是一种适用于几乎任何情况的健壮、高效和可扩展的解决方案。 随着Linux的发展,希望参与其开发的开发人员(和公司)的数量也在增加。硬件供应商 希望确保Linux能够很好地支持他们的产品,使这些产品对Linux用户具有吸引力。嵌入 式系统供应商使用Linux作为集成产品的组件,希望Linux能够尽可能地胜任手头的任务。 -分销商和其他基于Linux的软件供应商对Linux内核的功能、性能和可靠性有着明确的 -兴趣。最终用户也常常希望修改Linux,使之更好地满足他们的需求。 +分销商和其他基于Linux的软件供应商切实关心Linux内核的功能、性能和可靠性。最终 +用户也常常希望修改Linux,使之能更好地满足他们的需求。 Linux最引人注目的特性之一是这些开发人员可以访问它;任何具备必要技能的人都可以 改进Linux并影响其开发方向。专有产品不能提供这种开放性,这是自由软件的一个特点。 -但是,如果有什么不同的话,内核比大多数其他自由软件项目更开放。一个典型的三个月 -内核开发周期可以涉及1000多个开发人员,他们为100多个不同的公司 -(或者根本没有公司)工作。 +如果有什么不同的话,那就是内核比大多数其他自由软件项目更开放。一个典型的三个 +月内核开发周期可以涉及1000多个开发人员,他们为100多个不同的公司(或者根本不 +隶属公司)工作。 -与内核开发社区合作并不是特别困难。但是,尽管如此,许多潜在的贡献者在尝试做 -内核工作时遇到了困难。内核社区已经发展了自己独特的操作方式,使其能够在每天 +与内核开发社区合作并不是特别困难。但尽管如此,仍有许多潜在的贡献者在尝试做 +内核工作时遇到了困难。内核社区已经发展出自己独特的操作方式,使其能够在每天 都要更改数千行代码的环境中顺利运行(并生成高质量的产品)。因此,Linux内核开发 -过程与专有的开发方法有很大的不同也就不足为奇了。 +过程与专有的开发模式有很大的不同也就不足为奇了。 -对于新开发人员来说,内核的开发过程可能会让人感到奇怪和恐惧,但这个背后有充分的 -理由和坚实的经验。一个不了解内核社区的方式的开发人员(或者更糟的是,他们试图 -抛弃或规避内核社区的方式)会有一个令人沮丧的体验。开发社区, 在帮助那些试图学习 -的人的同时,没有时间帮助那些不愿意倾听或不关心开发过程的人。 +对于新开发人员来说,内核的开发过程可能会让人感到奇怪和恐惧,但这背后有充分的 +理由和坚实的经验。一个不了解内核社区工作方式的开发人员(或者更糟的是,他们 +试图抛弃或规避之)会得到令人沮丧的体验。开发社区在帮助那些试图学习的人的同时, +没有时间帮助那些不愿意倾听或不关心开发过程的人。 -希望阅读本文的人能够避免这种令人沮丧的经历。这里有很多材料,但阅读时所做的 +希望阅读本文的人能够避免这种令人沮丧的经历。这些材料很长,但阅读它们时所做的 努力会在短时间内得到回报。开发社区总是需要能让内核变更好的开发人员;下面的 -文本应该帮助您或为您工作的人员加入我们的社区。 +文字应该帮助您或为您工作的人员加入我们的社区。 致谢 ---- -本文件由Jonathan Corbet撰写,corbet@lwn.net。以下人员的建议使之更为完善: +本文档由Jonathan Corbet <corbet@lwn.net> 撰写。以下人员的建议使之更为完善: Johannes Berg, James Berry, Alex Chiang, Roland Dreier, Randy Dunlap, Jake Edge, Jiri Kosina, Matt Mackall, Arthur Marsh, Amanda McPherson, -Andrew Morton, Andrew Price, Tsugikazu Shibata, 和 Jochen Voß. +Andrew Morton, Andrew Price, Tsugikazu Shibata 和 Jochen Voß 。 这项工作得到了Linux基金会的支持,特别感谢Amanda McPherson,他看到了这项工作 -的价值并把它变成现实。 +的价值并将其变成现实。 代码进入主线的重要性 -------------------- 有些公司和开发人员偶尔会想,为什么他们要费心学习如何与内核社区合作,并将代码 放入主线内核(“主线”是由Linus Torvalds维护的内核,Linux发行商将其用作基础)。 -在短期内,贡献代码看起来像是一种可以避免的开销;仅仅将代码分开并直接支持用户 +在短期内,贡献代码看起来像是一种可以避免的开销;维护独立代码并直接支持用户 似乎更容易。事实上,保持代码独立(“树外”)是在经济上是错误的。 -作为说明树外代码成本的一种方法,下面是内核开发过程的一些相关方面;本文稍后将 -更详细地讨论其中的大部分内容。考虑: +为了说明树外代码成本,下面给出内核开发过程的一些相关方面;本文稍后将更详细地 +讨论其中的大部分内容。请考虑: - 所有Linux用户都可以使用合并到主线内核中的代码。它将自动出现在所有启用它的 - 发行版上。不需要驱动程序磁盘、下载,也不需要为多个发行版的多个版本提供支持; - 对于开发人员和用户来说,这一切都是可行的。并入主线解决了大量的分布和支持问题 + 发行版上。无需驱动程序磁盘、额外下载,也不需要为多个发行版的多个版本提供 + 支持;这一切将方便所有开发人员和用户。并入主线解决了大量的分发和支持问题。 -- 当内核开发人员努力维护一个稳定的用户空间接口时,内部内核API处于不断变化之中. - 缺乏一个稳定的内部接口是一个深思熟虑的设计决策;它允许在任何时候进行基本的改 - 进,并产生更高质量的代码。但该策略的一个结果是,如果要使用新的内核,任何树外 - 代码都需要持续的维护。维护树外代码需要大量的工作才能使代码保持工作状态。 +- 当内核开发人员努力维护一个稳定的用户空间接口时,内核内部API处于不断变化之中。 + 不维持稳定的内部接口是一个慎重的设计决策;它允许在任何时候进行基本的改进, + 并产出更高质量的代码。但该策略导致结果是,若要使用新的内核,任何树外代码都 + 需要持续的维护。维护树外代码会需要大量的工作才能使代码保持正常运行。 - 相反,位于主线中的代码不需要这样做,因为一个简单的规则要求进行API更改的任何 - 开发人员也必须修复由于该更改而破坏的任何代码。因此,合并到主线中的代码大大 - 降低了维护成本。 + 相反,位于主线中的代码不需要这样做,因为基本规则要求进行API更改的任何开发 + 人员也必须修复由于该更改而破坏的任何代码。因此,合并到主线中的代码大大降低 + 了维护成本。 -- 除此之外,内核中的代码通常会被其他开发人员改进。令人惊讶的结果可能来自授权 - 您的用户社区和客户改进您的产品。 +- 除此之外,内核中的代码通常会被其他开发人员改进。您授权的用户社区和客户对您 + 产品的改进可能会令人惊喜。 -- 内核代码在合并到主线之前和之后都要经过审查。不管原始开发人员的技能有多强, +- 内核代码在合并到主线之前和之后都要经过审查。无论原始开发人员的技能有多强, 这个审查过程总是能找到改进代码的方法。审查经常发现严重的错误和安全问题。 - 这对于在封闭环境中开发的代码尤其如此;这种代码从外部开发人员的审查中获益 - 匪浅。树外代码是低质量代码。 + 对于在封闭环境中开发的代码尤其如此;这种代码从外部开发人员的审查中获益匪浅。 + 树外代码是低质量代码。 - 参与开发过程是您影响内核开发方向的方式。旁观者的抱怨会被听到,但是活跃的 开发人员有更强的声音——并且能够实现使内核更好地满足其需求的更改。 - 当单独维护代码时,总是存在第三方为类似功能提供不同实现的可能性。如果发生 - 这种情况,合并代码将变得更加困难——甚至到了不可能的地步。然后,您将面临以下 - 令人不快的选择:(1)无限期地维护树外的非标准特性,或(2)放弃代码并将用户 - 迁移到树内版本。 + 这种情况,合并代码将变得更加困难——甚至成为不可能。之后,您将面临以下令人 + 不快的选择:(1)无限期地维护树外的非标准特性,或(2)放弃代码并将用户迁移 + 到树内版本。 -- 代码的贡献是使整个过程工作的根本。通过贡献代码,您可以向内核添加新功能,并 - 提供其他内核开发人员使用的功能和示例。如果您已经为Linux开发了代码(或者 - 正在考虑这样做),那么您显然对这个平台的持续成功感兴趣;贡献代码是确保成功 - 的最好方法之一。 +- 代码的贡献是使整个流程工作的根本。通过贡献代码,您可以向内核添加新功能,并 + 提供其他内核开发人员使用的功能和示例。如果您已经为Linux开发了代码(或者正在 + 考虑这样做),那么您显然对这个平台的持续成功感兴趣;贡献代码是确保成功的 + 最好方法之一。 上述所有理由都适用于任何树外内核代码,包括以专有的、仅二进制形式分发的代码。 -然而,在考虑任何类型的纯二进制内核代码分布之前,还需要考虑其他因素。这些包括: +然而,在考虑任何类型的纯二进制内核代码分布之前,还需要考虑其他因素。包括: -- 围绕专有内核模块分发的法律问题充其量是模糊的;相当多的内核版权所有者认为, - 大多数仅限二进制的模块是内核的派生产品,因此,它们的分发违反了GNU通用公共 - 许可证(下面将详细介绍)。您的作者不是律师,本文档中的任何内容都不可能被 +- 围绕专有内核模块分发的法律问题其实较为模糊;相当多的内核版权所有者认为, + 大多数仅二进制的模块是内核的派生产品,因此,它们的分发违反了GNU通用公共 + 许可证(下面将详细介绍)。本文作者不是律师,本文档中的任何内容都不可能被 视为法律建议。封闭源代码模块的真实法律地位只能由法院决定。但不管怎样,困扰 这些模块的不确定性仍然存在。 - 二进制模块大大增加了调试内核问题的难度,以至于大多数内核开发人员甚至都不会 尝试。因此,只分发二进制模块将使您的用户更难从社区获得支持。 -- 对于只支持二进制的模块的发行者来说,支持也更加困难,他们必须为他们希望支持 - 的每个发行版和每个内核版本提供一个版本的模块。为了提供相当全面的覆盖范围, +- 对于仅二进制的模块的发行者来说,支持也更加困难,他们必须为他们希望支持的 + 每个发行版和每个内核版本提供不同版本的模块。为了提供较为全面的覆盖范围, 可能需要一个模块的几十个构建,并且每次升级内核时,您的用户都必须单独升级 - 您的模块。 + 这些模块。 -- 上面提到的关于代码评审的所有问题都更加存在于封闭源代码。由于该代码根本不可 - 用,因此社区无法对其进行审查,毫无疑问,它将存在严重问题。 +- 上面提到的关于代码评审的所有问题都更加存在于封闭源代码中。由于该代码根本 + 不可得,因此社区无法对其进行审查,毫无疑问,它将存在严重问题。 -尤其是嵌入式系统的制造商,可能会倾向于忽视本节中所说的大部分内容,因为他们 +尤其是嵌入式系统的制造商,可能会倾向于忽视本节中所说的大部分内容;因为他们 相信自己正在商用一种使用冻结内核版本的独立产品,在发布后不需要再进行开发。 这个论点忽略了广泛的代码审查的价值以及允许用户向产品添加功能的价值。但这些 -产品也有有限的商业寿命,之后必须发布新版本的产品。在这一点上,代码在主线上 -并得到良好维护的供应商将能够更好地占位,以使新产品快速上市。 +产品的商业寿命有限,之后必须发布新版本的产品。在这一点上,代码在主线上并得到 +良好维护的供应商将能够更好地占位,以使新产品快速上市。 许可 ---- @@ -164,23 +172,24 @@ Andrew Morton, Andrew Price, Tsugikazu Shibata, 和 Jochen Voß. 代码是根据一些许可证提供给Linux内核的,但是所有代码都必须与GNU通用公共许可 证(GPLV2)的版本2兼容,该版本是覆盖整个内核分发的许可证。在实践中,这意味 着所有代码贡献都由GPLv2(可选地,语言允许在更高版本的GPL下分发)或3子句BSD -许可(New BSD License, 译者注)覆盖。任何不包含在兼容许可证中的贡献都不会 +许可(New BSD License,译者注)覆盖。任何不包含在兼容许可证中的贡献都不会 被接受到内核中。 贡献给内核的代码不需要(或请求)版权分配。合并到主线内核中的所有代码都保留 其原始所有权;因此,内核现在拥有数千个所有者。 -这种所有权结构的一个暗示是,任何改变内核许可的尝试都注定会失败。很少有实际 -的场景可以获得所有版权所有者的同意(或者从内核中删除他们的代码)。因此,特 -别是,在可预见的将来,不可能迁移到GPL的版本3。 +这种所有权结构也暗示着,任何改变内核许可的尝试都注定会失败。很少有实际情况 +可以获得所有版权所有者的同意(或者从内核中删除他们的代码)。因此,尤其是在 +可预见的将来,许可证不大可能迁移到GPL的版本3。 -所有贡献给内核的代码都必须是合法的免费软件。因此,不接受匿名(或匿名)贡献 -者的代码。所有贡献者都需要在他们的代码上“sign off”,声明代码可以在GPL下与内 -核一起分发。无法提供未被其所有者许可为免费软件的代码,或可能为内核造成版权 -相关问题的代码(例如,由缺乏适当保护的反向工程工作派生的代码)不能被接受。 +所有贡献给内核的代码都必须是合法的免费软件。因此,不接受匿名(或化名)贡献 +者的代码。所有贡献者都需要在他们的代码上“sign off(签发)”,声明代码可以 +在GPL下与内核一起分发。无法提供未被其所有者许可为免费软件的代码,或可能为 +内核造成版权相关问题的代码(例如,由缺乏适当保护的反向工程工作派生的代码) +不能被接受。 -有关版权相关问题的问题在Linux开发邮件列表中很常见。这样的问题通常会得到不少 -答案,但要记住,回答这些问题的人不是律师,不能提供法律咨询。如果您有关于 -Linux源代码的法律问题,那么与了解该领域的律师交流是无法替代的。依靠从技术 -邮件列表中获得的答案是一件冒险的事情。 +有关版权问题的提问在Linux开发邮件列表中很常见。这样的问题通常会得到不少答案, +但请记住,回答这些问题的人不是律师,不能提供法律咨询。如果您有关于Linux源代码 +的法律问题,没有什么可以代替咨询了解这一领域的律师。依赖从技术邮件列表中获得 +的答案是一件冒险的事情。 diff --git a/Documentation/translations/zh_CN/process/2.Process.rst b/Documentation/translations/zh_CN/process/2.Process.rst index ebe2e0254b3ebcc85acf94e2768d13ecb46185d9..229629e305ca9b05f67d875a6a6b62296c4386ad 100644 --- a/Documentation/translations/zh_CN/process/2.Process.rst +++ b/Documentation/translations/zh_CN/process/2.Process.rst @@ -1,17 +1,24 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/2.Process.rst <development_process>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_process: -开发流程如何工作 +开发流程如何进行 ================ -90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较 -少。由于拥有数以百万计的用户群,并且在一年的时间里有大约2000名开发人员参与 -进来,内核因此必须发展许多流程来保持开发的顺利进行。要成为流程的有效组成 -部分,需要对流程的工作方式有一个扎实的理解。 +90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较少。 +由于拥有数以百万计的用户群,且每年有大约2000名开发人员参与进来,内核因此必须 +发展出许多既定流程来保证开发的顺利进行。要参与到流程中来,需要对此流程的进行 +方式有一个扎实的理解。 总览 ---- @@ -20,112 +27,113 @@ 内核版本。最近的发布历史记录如下: ====== ================= - 4.11 四月 30, 2017 - 4.12 七月 2, 2017 - 4.13 九月 3, 2017 - 4.14 十一月 12, 2017 - 4.15 一月 28, 2018 - 4.16 四月 1, 2018 + 5.0 2019年3月3日 + 5.1 2019年5月5日 + 5.2 2019年7月7日 + 5.3 2019年9月15日 + 5.4 2019年11月24日 + 5.5 2020年1月6日 ====== ================= -每4.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的4.x -版本包含大约13000个变更集,变更了几十万行代码。因此,4.x是Linux内核开发的前 +每个5.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的5.x +版本包含大约13000个变更集,变更了几十万行代码。因此,5.x是Linux内核开发的前 沿;内核使用滚动开发模型,不断集成重大变化。 -对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开始,“合并 -窗口”被打开。当时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内 +对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开头,“合并 +窗口”被打开。这时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内 核中。在这段时间内,新开发周期的大部分变更(以及所有主要变更)将以接近每天 1000次变更(“补丁”或“变更集”)的速度合并。 -(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是 -提前收集、测试和分级的。稍后将详细描述该过程的工作方式)。 +(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是经 +提前收集、测试和分级的。稍后将详细描述该过程的工作方式。) 合并窗口持续大约两周。在这段时间结束时,LinusTorvalds将声明窗口已关闭,并 -释放第一个“rc”内核。例如,对于目标为4.14的内核,在合并窗口结束时发生的释放 -将被称为4.14-rc1。RC1版本是一个信号,表示合并新特性的时间已经过去,稳定下一 -个内核的时间已经开始。 +释放第一个“rc”内核。例如,对于目标为5.6的内核,在合并窗口结束时发生的释放 +将被称为5.6-rc1。-rc1 版本是一个信号,表示合并新特性的时间已经过去,稳定下一 +个内核的时间已经到来。 在接下来的6到10周内,只有修复问题的补丁才应该提交给主线。有时会允许更大的 -更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往会受到不 +更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往受不到 友好的接待。一般来说,如果您错过了给定特性的合并窗口,最好的做法是等待下一 -个开发周期。(对于以前不支持的硬件,偶尔会对驱动程序进行例外;如果它们不 -改变已有代码,则不会导致回归,并且应该可以随时安全地添加)。 +个开发周期。(偶尔会对未支持硬件的驱动程序进行例外;如果它们不改变已有代码, +则不会导致回归,应该可以随时被安全地加入)。 随着修复程序进入主线,补丁速度将随着时间的推移而变慢。Linus大约每周发布一次 -新的-rc内核;一个正常的系列将在-rc6和-rc9之间,内核被认为足够稳定并最终发布。 +新的-rc内核;在内核被认为足够稳定并最终发布前,一般会达到-rc6到-rc9之间。 然后,整个过程又重新开始了。 -例如,这里是4.16的开发周期进行情况(2018年的所有日期): +例如,这里是5.4的开发周期进行情况(2019年): ============== ============================== - 一月 28 4.15 稳定版发布 - 二月 11 4.16-rc1, 合并窗口关闭 - 二月 18 4.16-rc2 - 二月 25 4.16-rc3 - 三月 4 4.16-rc4 - 三月 11 4.16-rc5 - 三月 18 4.16-rc6 - 三月 25 4.16-rc7 - 四月 1 4.16 稳定版发布 + 九月 15 5.3 稳定版发布 + 九月 30 5.4-rc1 合并窗口关闭 + 十月 6 5.4-rc2 + 十月 13 5.4-rc3 + 十月 20 5.4-rc4 + 十月 27 5.4-rc5 + 十一月 3 5.4-rc6 + 十一月 10 5.4-rc7 + 十一月 17 5.4-rc8 + 十一月 24 5.4 稳定版发布 ============== ============================== -开发人员如何决定何时结束开发周期并创建稳定的版本?使用的最重要的指标是以前 -版本的回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被 -认为是特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。 +开发人员如何决定何时结束开发周期并创建稳定版本?最重要的指标是以前版本的 +回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被认为是 +特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。 开发人员的目标是在稳定发布之前修复所有已知的回归。在现实世界中,这种完美是 -很难实现的;在这种规模的项目中,变量太多了。有一点,延迟最终版本只会使问题 -变得更糟;等待下一个合并窗口的一堆更改将变大,从而在下次创建更多的回归错误。 -因此,大多数4.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。 +很难实现的;在这种规模的项目中,变数太多了。需要说明的是,延迟最终版本只会 +使问题变得更糟;等待下一个合并窗口的更改将变多,导致下次出现更多的回归错误。 +因此,大多数5.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。 -一旦一个稳定的版本发布,它正在进行的维护工作就被移交给“稳定团队”,目前由 -Greg Kroah-Hartman组成。稳定团队将使用4.x.y编号方案不定期的发布稳定版本的更 -新。要加入更新版本,补丁程序必须(1)修复一个重要的bug,(2)已经合并到 -下一个开发主线中。内核通常会在超过其初始版本的一个以上的开发周期内接收稳定 -的更新。例如,4.13内核的历史如下 +一旦一个稳定的版本发布,它的持续维护工作就被移交给“稳定团队”,目前由 +Greg Kroah-Hartman领导。稳定团队将使用5.x.y编号方案不定期地发布稳定版本的 +更新。要合入更新版本,补丁必须(1)修复一个重要的缺陷,且(2)已经合并到 +下一个开发版本主线中。内核通常会在其初始版本后的一个以上的开发周期内收到 +稳定版更新。例如,5.2内核的历史如下(2019年): ============== =============================== - 九月 3 4.13 稳定版发布 - 九月 13 4.13.1 - 九月 20 4.13.2 - 九月 27 4.13.3 - 十月 5 4.13.4 - 十月 12 4.13.5 + 七月 7 5.2 稳定版发布 + 七月 13 5.2.1 + 七月 21 5.2.2 + 七月 26 5.2.3 + 七月 28 5.2.4 + 七月 31 5.2.5 ... ... - 十一月 24 4.13.16 + 十月 11 5.2.21 ============== =============================== -4.13.16是4.13版本的最终稳定更新。 +5.2.21是5.2版本的最终稳定更新。 有些内核被指定为“长期”内核;它们将得到更长时间的支持。在本文中,当前的长期 内核及其维护者是: - ====== ====================== ============================== - 3.16 Ben Hutchings (长期稳定内核) - 4.1 Sasha Levin - 4.4 Greg Kroah-Hartman (长期稳定内核) - 4.9 Greg Kroah-Hartman - 4.14 Greg Kroah-Hartman - ====== ====================== ============================== + ====== ================================ ================ + 3.16 Ben Hutchings (长期稳定内核) + 4.4 Greg Kroah-Hartman & Sasha Levin (长期稳定内核) + 4.9 Greg Kroah-Hartman & Sasha Levin + 4.14 Greg Kroah-Hartman & Sasha Levin + 4.19 Greg Kroah-Hartman & Sasha Levin + 5.4 Greg Kroah-Hartman & Sasha Levin + ====== ================================ ================ -为长期支持选择内核纯粹是维护人员有必要和时间来维护该版本的问题。目前还没有 -为即将发布的任何特定版本提供长期支持的已知计划。 +长期支持内核的选择纯粹是维护人员是否有需求和时间来维护该版本的问题。 +目前还没有为即将发布的任何特定版本提供长期支持的已知计划。 补丁的生命周期 -------------- 补丁不会直接从开发人员的键盘进入主线内核。相反,有一个稍微复杂(如果有些非 正式)的过程,旨在确保对每个补丁进行质量审查,并确保每个补丁实现了一个在主线 -中需要的更改。对于小的修复,这个过程可能会很快发生,或者,在大的和有争议的 -变更的情况下,会持续数年。许多开发人员的挫折来自于对这个过程缺乏理解或者 -试图绕过它。 +中需要的更改。对于小的修复,这个过程可能会很快完成,,而对于较大或有争议的 +变更,可能会持续数年。许多开发人员的沮丧来自于对这个过程缺乏理解或者试图绕过它。 -为了减少这种挫折感,本文将描述补丁如何进入内核。下面是一个介绍,它以某种 -理想化的方式描述了这个过程。更详细的过程将在后面的章节中介绍。 +为了减少这种挫败,本文将描述补丁如何进入内核。下面的介绍以一种较为理想化的 +方式描述了这个过程。更详细的过程将在后面的章节中介绍。 -补丁程序经历的阶段通常是: +补丁通常要经历以下阶段: -- 设计。这就是补丁的真正需求——以及满足这些需求的方式——的所在。设计工作通常 +- 设计。这就是补丁的真正需求——以及满足这些需求的方式——所在。设计工作通常 是在不涉及社区的情况下完成的,但是如果可能的话,最好是在公开的情况下完成 这项工作;这样可以节省很多稍后再重新设计的时间。 @@ -134,53 +142,51 @@ Greg Kroah-Hartman组成。稳定团队将使用4.x.y编号方案不定期的发 - 更广泛的评审。当补丁接近准备好纳入主线时,它应该被相关的子系统维护人员 接受——尽管这种接受并不能保证补丁会一直延伸到主线。补丁将出现在维护人员的 - 子系统树中,并进入 -next 树(如下所述)。当流程工作时,此步骤将导致对补丁 - 进行更广泛的审查,并发现由于将此补丁与其他人所做的工作集成而导致的任何 + 子系统树中,并进入 -next 树(如下所述)。当流程进行时,此步骤将会对补丁 + 进行更广泛的审查,并发现由于将此补丁与其他人所做的工作合并而导致的任何 问题。 -- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最高优先级。 - 如果您的补丁程序得到了关于所需更改的反馈,那么您应该进行这些更改,或者为 - 不应该进行这些更改的原因辩护。如果您的补丁没有评审意见,但没有被其相应的 - 子系统或驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核,使 - 其干净地应用,并不断地将其发送以供审查和合并。 +- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最优先工作。 + 如果您的补丁得到了需要更改的反馈,那么您应该进行这些更改,或者解释为何 + 不应该进行这些更改。如果您的补丁没有评审意见,也没有被其相应的子系统或 + 驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核使其可被正常 + 应用,并不断地发送它以供审查和合并。 - 合并到主线。最终,一个成功的补丁将被合并到由LinusTorvalds管理的主线存储库 - 中。此时可能会出现更多的评论和/或问题;开发人员应对这些问题并解决出现的 - 任何问题很重要。 + 中。此时可能会出现更多的评论和/或问题;对开发人员来说应对这些问题并解决 + 出现的任何问题仍很重要。 -- 稳定版发布。可能受补丁影响的用户数量现在很大,因此可能再次出现新的问题。 +- 稳定版发布。大量用户可能受此补丁影响,因此可能再次出现新的问题。 - 长期维护。虽然开发人员在合并代码后可能会忘记代码,但这种行为往往会给开发 - 社区留下不良印象。合并代码消除了一些维护负担,因为其他代码将修复由API - 更改引起的问题。但是,如果代码要长期保持有用,原始开发人员应该继续为 - 代码负责。 + 社区留下不良印象。合并代码消除了一些维护负担,因为其他人将修复由API更改 + 引起的问题。但是,如果代码要长期保持可用,原始开发人员应该继续为代码负责。 -内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个 -“合并到主线”步骤。这种方法总是会让所有相关人员感到沮丧。 +内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个“合并到 +主线”步骤。这种方法总是会让所有相关人员感到沮丧。 补丁如何进入内核 ---------------- 只有一个人可以将补丁合并到主线内核存储库中:LinusTorvalds。但是,在进入 2.6.38内核的9500多个补丁中,只有112个(大约1.3%)是由Linus自己直接选择的。 -内核项目已经发展到一个规模,没有一个开发人员可以在没有支持的情况下检查和 -选择每个补丁。内核开发人员处理这种增长的方式是通过使用围绕信任链构建的 -助理系统。 +内核项目已经发展到一个没有一个开发人员可以在没有支持的情况下检查和选择每个 +补丁的规模。内核开发人员处理这种增长的方式是使用围绕信任链构建的助理系统。 -内核代码库在逻辑上被分解为一组子系统:网络、特定的体系结构支持、内存管理、 -视频设备等。大多数子系统都有一个指定的维护人员,开发人员对该子系统中的代码 -负有全部责任。这些子系统维护者(松散地)是他们所管理的内核部分的守护者; -他们(通常)会接受一个补丁以包含到主线内核中。 +内核代码库在逻辑上被分解为一组子系统:网络、特定体系结构支持、内存管理、视 +频设备等。大多数子系统都有一个指定的维护人员,其总体负责该子系统中的代码。 +这些子系统维护者(松散地)是他们所管理的内核部分的“守门员”;他们(通常) +会接受一个补丁以包含到主线内核中。 -子系统维护人员每个人都使用git源代码管理工具管理自己版本的内核源代码树。Git -等工具(以及Quilt或Mercurial等相关工具)允许维护人员跟踪补丁列表,包括作者 +子系统维护人员每个人都管理着自己版本的内核源代码树,通常(并非总是)使用Git。 +Git等工具(以及Quilt或Mercurial等相关工具)允许维护人员跟踪补丁列表,包括作者 信息和其他元数据。在任何给定的时间,维护人员都可以确定他或她的存储库中的哪 些补丁在主线中找不到。 -当合并窗口打开时,顶级维护人员将要求Linus从其存储库中“拉出”他们为合并选择 +当合并窗口打开时,顶级维护人员将要求Linus从存储库中“拉出”他们为合并选择 的补丁。如果Linus同意,补丁流将流向他的存储库,成为主线内核的一部分。 -Linus对拉操作中接收到的特定补丁的关注程度各不相同。很明显,有时他看起来很 -关注。但是,作为一般规则,Linus相信子系统维护人员不会向上游发送坏补丁。 +Linus对拉取中接收到的特定补丁的关注程度各不相同。很明显,有时他看起来很 +关注。但是一般来说,Linus相信子系统维护人员不会向上游发送坏补丁。 子系统维护人员反过来也可以从其他维护人员那里获取补丁。例如,网络树是由首先 在专用于网络设备驱动程序、无线网络等的树中积累的补丁构建的。此存储链可以 @@ -195,26 +201,26 @@ Next 树 子系统树链引导补丁流到内核,但它也提出了一个有趣的问题:如果有人想查看为 下一个合并窗口准备的所有补丁怎么办?开发人员将感兴趣的是,还有什么其他的 -更改有待解决,以查看是否存在需要担心的冲突;例如,更改核心内核函数原型的 +更改有待解决,以了解是否存在需要担心的冲突;例如,更改核心内核函数原型的 修补程序将与使用该函数旧形式的任何其他修补程序冲突。审查人员和测试人员希望 -在所有这些变更到达主线内核之前,能够访问它们的集成形式中的变更。您可以从所有 -有趣的子系统树中提取更改,但这将是一项大型且容易出错的工作。 +在所有这些变更到达主线内核之前,能够访问它们的集成形式的变更。您可以从所有 +相关的子系统树中提取更改,但这将是一项复杂且容易出错的工作。 -答案以-next树的形式出现,在这里子系统树被收集以供测试和审查。Andrew Morton -维护的这些旧树被称为“-mm”(用于内存管理,这就是它的启动名字)。-mm 树集成了 -一长串子系统树中的补丁;它还包含一些旨在帮助调试的补丁。 +解决方案以-next树的形式出现,在这里子系统树被收集以供测试和审查。这些树中 +由Andrew Morton维护的较老的一个,被称为“-mm”(用于内存管理,创建时为此)。 +-mm 树集成了一长串子系统树中的补丁;它还包含一些旨在帮助调试的补丁。 除此之外,-mm 还包含大量由Andrew直接选择的补丁。这些补丁可能已经发布在邮件 -列表上,或者它们可能应用于内核中没有指定子系统树的部分。结果,-mm 作为一种 -最后手段的子系统树运行;如果没有其他明显的路径可以让补丁进入主线,那么它很 -可能以-mm 结束。累积在-mm 中的各种补丁最终将被转发到适当的子系统树,或者直接 +列表上,或者它们可能应用于内核中未指定子系统树的部分。同时,-mm 作为最后 +手段的子系统树;如果没有其他明显的路径可以让补丁进入主线,那么它很可能最 +终选择-mm 树。累积在-mm 中的各种补丁最终将被转发到适当的子系统树,或者直接 发送到Linus。在典型的开发周期中,大约5-10%的补丁通过-mm 进入主线。 -当前-mm 补丁可在“mmotm”(-mm of the moment)目录中找到,地址: +当前-mm 补丁可在“mmotm”(-mm of the moment)目录中找到: https://www.ozlabs.org/~akpm/mmotm/ -然而,使用mmotm树可能是一种令人沮丧的体验;它甚至可能无法编译。 +然而,使用MMOTM树可能会十分令人头疼;它甚至可能无法编译。 下一个周期补丁合并的主要树是linux-next,由Stephen Rothwell 维护。根据设计 linux-next 是下一个合并窗口关闭后主线的快照。linux-next树在Linux-kernel 和 @@ -228,49 +234,48 @@ Linux-next 已经成为内核开发过程中不可或缺的一部分;在一个 Staging 树 ---------- -内核源代码树包含drivers/staging/directory,其中有许多驱动程序或文件系统的 -子目录正在被添加到内核树中。它们然需要更多的工作的时候可以保留在 -driver/staging目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合 -Linux内核编码或质量标准的驱动程序的方法,但人们可能希望使用它们并跟踪开发。 +内核源代码树包含drivers/staging/目录,其中有许多驱动程序或文件系统的子目录 +正在被添加到内核树中。它们在仍然需要更多的修正的时候可以保留在driver/staging/ +目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合Linux内核编码或 +质量标准的驱动程序的方法,人们可能希望使用它们并跟踪开发。 -Greg Kroah Hartman 目前负责维护staging 树。仍需要工作的驱动程序将发送给他, +Greg Kroah Hartman 目前负责维护staging 树。仍需要修正的驱动程序将发送给他, 每个驱动程序在drivers/staging/中都有自己的子目录。除了驱动程序源文件之外, -目录中还应该有一个TODO文件。todo文件列出了驱动程序需要接受的挂起的工作, +目录中还应该有一个TODO文件。TODO文件列出了驱动程序需要接受的暂停的工作, 以及驱动程序的任何补丁都应该抄送的人员列表。当前的规则要求,staging的驱动 程序必须至少正确编译。 -Staging 是一种相对容易的方法,可以让新的驱动程序进入主线,幸运的是,他们会 -引起其他开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾; -staging中没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用 -staging驱动程序。因此,在成为一名合适的主线驱动的路上,staging 充其量只是 -一个停留。 +Staging 是一种让新的驱动程序进入主线的相对容易的方法,它们会幸运地引起其他 +开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾;staging中 +没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用staging驱动 +程序。因此,在成为一个合适的主线驱动的路上,staging 仅是一个中转站。 工具 ---- 从上面的文本可以看出,内核开发过程在很大程度上依赖于在不同方向上聚集补丁的 能力。如果没有适当强大的工具,整个系统将无法在任何地方正常工作。关于如何使用 -这些工具的教程远远超出了本文档的范围,但是还是有一些指南的空间。 +这些工具的教程远远超出了本文档的范围,但还是用一点篇幅介绍一些关键点。 到目前为止,内核社区使用的主要源代码管理系统是git。Git是在自由软件社区中开发 的许多分布式版本控制系统之一。它非常适合内核开发,因为它在处理大型存储库和 -大量补丁时性能非常好。它还有一个难以学习和使用的名声,尽管随着时间的推移它 -变得更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不 -将它用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。 +大量补丁时性能非常好。它也以难以学习和使用而著称,尽管随着时间的推移它变得 +更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不将它 +用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。 -现在几乎所有的Linux发行版都打包了Git。主页位于: +现在几乎所有的Linux发行版都打包了Git。Git主页位于: https://git-scm.com/ -那个页面有指向文档和教程的指针。 +此页面包含了文档和教程的链接。 -在不使用git的内核开发人员中,最流行的选择几乎肯定是mercurial: +在不使用git的内核开发人员中,最流行的选择几乎肯定是Mercurial: http://www.seleric.com/mercurial/ Mercurial与Git共享许多特性,但它提供了一个界面,许多人觉得它更易于使用。 -另一个值得了解的工具是quilt: +另一个值得了解的工具是Quilt: https://savannah.nongnu.org/projects/quilt @@ -282,79 +287,79 @@ Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会 邮件列表 -------- -大量的Linux内核开发工作是通过邮件列表完成的。如果不在某个地方加入至少一个列表, -就很难成为社区中一个功能完备的成员。但是,Linux邮件列表对开发人员来说也是一个 -潜在的危险,他们可能会被一堆电子邮件淹没,违反Linux列表上使用的约定,或者 -两者兼而有之。 +大量的Linux内核开发工作是通过邮件列表完成的。如果不加入至少一个某个列表, +就很难成为社区中的一个“全功能”成员。但是,Linux邮件列表对开发人员来说也是 +一个潜在的危险,他们可能会被一堆电子邮件淹没、违反Linux列表上使用的约定, +或者两者兼而有之。 大多数内核邮件列表都在vger.kernel.org上运行;主列表位于: http://vger.kernel.org/vger-lists.html -不过,也有一些列表托管在别处;其中一些列表位于lists.redhat.com。 +不过,也有一些列表托管在别处;其中一些列表位于 +redhat.com/mailman/listinfo。 -当然,内核开发的核心邮件列表是linux-kernel。这个名单是一个令人生畏的地方; -每天的信息量可以达到500条,噪音很高,谈话技术性很强,参与者并不总是表现出 +当然,内核开发的核心邮件列表是linux-kernel。这个列表是一个令人生畏的地方: +每天的信息量可以达到500条,噪音很高,谈话技术性很强,且参与者并不总是表现出 高度的礼貌。但是,没有其他地方可以让内核开发社区作为一个整体聚集在一起; -避免使用此列表的开发人员将错过重要信息。 +不使用此列表的开发人员将错过重要信息。 -有一些提示可以帮助在linux-kernel生存: +以下一些提示可以帮助在linux-kernel生存: -- 将邮件转移到单独的文件夹,而不是主邮箱。我们必须能够持续地忽略洪流。 +- 将邮件转移到单独的文件夹,而不是主邮箱文件夹。我们必须能够持续地忽略洪流。 -- 不要试图跟踪每一次谈话-其他人都不会。重要的是要对感兴趣的主题(尽管请 - 注意,长时间的对话可以在不更改电子邮件主题行的情况下偏离原始主题)和参与 - 的人进行筛选。 +- 不要试图跟上每一次谈话——没人会这样。重要的是要筛选感兴趣的主题(但请注意 + 长时间的对话可能会偏离原来的主题,尽管未改变电子邮件的主题)和参与的人。 -- 不要挑事。如果有人试图激起愤怒的反应,忽略他们。 +- 不要回复挑事的人。如果有人试图激起愤怒,请忽略他们。 -- 当响应Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留 - cc:header。如果没有强有力的理由(如明确的请求),则不应删除收件人。一定要 - 确保你要回复的人在cc:list中。这个惯例也使你不必在回复邮件时明确要求被抄送。 +- 当回复Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留 + Cc: 抄送头。如果没有确实的理由(如明确的请求),则不应删除收件人。一定要 + 确保你要回复的人在抄送列表中。这个惯例也使你不必在回复邮件时明确要求被抄送。 -- 在提出问题之前,搜索列表档案(和整个网络)。有些开发人员可能会对那些显然 +- 在提出问题之前,搜索列表存档(和整个网络)。有些开发人员可能会对那些显然 没有完成家庭作业的人感到不耐烦。 -- 避免贴顶帖(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难 +- 避免顶部回复(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难 理解,印象也很差。 -- 询问正确的邮件列表。linux-kernel 可能是通用的讨论点,但它不是从所有子系统 - 中寻找开发人员的最佳场所。 +- 在正确的邮件列表发问。linux-kernel 可能是通用的讨论场所,但它不是寻找所有 + 子系统开发人员的最佳场所。 -最后一点——找到正确的邮件列表——是开发人员出错的常见地方。在Linux内核上提出与 -网络相关的问题的人几乎肯定会收到一个礼貌的建议,转而在netdev列表上提出, -因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、 -video4linux、ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码 -一起打包的MAINTAINERS文件。 +最后一点——找到正确的邮件列表——是开发人员常出错的地方。在linux-kernel上 +提出与网络相关的问题的人几乎肯定会收到一个礼貌的建议,转到netdev列表上提出, +因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、video4linux、 +ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码一起打包的 +MAINTAINERS文件。 开始内核开发 ------------ -关于如何开始内核开发过程的问题很常见——来自个人和公司。同样常见的是错误,这 -使得关系的开始比必须的更困难。 +关于如何开始内核开发过程的问题很常见——个人和公司皆然。同样常见的是失误,这 +使得关系的开始比本应的更困难。 公司通常希望聘请知名的开发人员来启动开发团队。实际上,这是一种有效的技术。 -但它也往往是昂贵的,而且没有增长经验丰富的内核开发人员储备。考虑到时间的 -投入,可以让内部开发人员加快Linux内核的开发速度。花这个时间可以让雇主拥有 -一批了解内核和公司的开发人员,他们也可以帮助培训其他人。从中期来看,这往往 -是更有利可图的方法。 +但它也往往是昂贵的,而且对增加有经验的内核开发人员的数量没有多大帮助。考 +虑到时间投入,可以让内部开发人员加快Linux内核的开发速度。利用这段时间可以 +让雇主拥有一批既了解内核又了解公司的开发人员,还可以帮助培训其他人。从中期 +来看,这通常是更有利可图的方法。 可以理解的是,单个开发人员往往对起步感到茫然。从一个大型项目开始可能会很 -吓人;人们往往想先用一些较小的东西来测试水域。这是一些开发人员开始创建修补 -拼写错误或轻微编码风格问题的补丁的地方。不幸的是,这样的补丁会产生一定程度 -的噪音,这会分散整个开发社区的注意力,因此,越来越多的人看不起它们。希望向 -社区介绍自己的新开发人员将无法通过这些方式获得他们想要的那种接待。 +吓人;人们往往想先用一些较小的东西来试试水。由此,一些开发人员开始创建修补 +拼写错误或轻微编码风格问题的补丁。不幸的是,这样的补丁会产生一定程度的噪音, +这会分散整个开发社区的注意力,因此,它们越来越被人不看重。希望向社区介绍 +自己的新开发人员将无法通过这些方式获得他们期待的反响。 -Andrew Morton 为有抱负的内核开发人员提供了这个建议 +Andrew Morton 为有抱负的内核开发人员提供了如下建议 :: - 所有内核初学者的No.1项目肯定是“确保内核在所有的机器上,你可以触摸 - 到的,始终运行良好" 通常这样做的方法是与其他人一起解决问题(这 - 可能需要坚持!)但这很好——这是内核开发的一部分 + 所有内核开发者的第一个项目肯定应该是“确保内核在您可以操作的所有 + 机器上始终完美运行”。通常的方法是和其他人一起解决问题(这可能需 + 要坚持!),但就是如此——这是内核开发的一部分。 (http://lwn.net/articles/283982/) -在没有明显问题需要解决的情况下,建议开发人员查看当前的回归和开放式错误列表. -解决需要修复的问题没有任何缺点;通过解决这些问题,开发人员将获得处理过程的 -经验,同时与开发社区的其他人建立尊重。 +在没有明显问题需要解决的情况下,通常建议开发人员查看当前的回归和开放缺陷 +列表。从来都不缺少需要解决的问题;通过解决这些问题,开发人员将从该过程获得 +经验,同时与开发社区的其他成员建立相互尊重。 diff --git a/Documentation/translations/zh_CN/process/3.Early-stage.rst b/Documentation/translations/zh_CN/process/3.Early-stage.rst index b8676aec60050b4dea792c36130b5cf4a171637d..de53dd12e91183d700b4a3c752af05e73134444a 100644 --- a/Documentation/translations/zh_CN/process/3.Early-stage.rst +++ b/Documentation/translations/zh_CN/process/3.Early-stage.rst @@ -1,7 +1,14 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/3.Early-stage.rst <development_early_stage>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_early_stage: @@ -9,45 +16,45 @@ ======== 当考虑一个Linux内核开发项目时,很可能会直接跳进去开始编码。然而,与任何重要 -的项目一样,成功的许多基础最好是在第一行代码编写之前就做好了。在早期计划和 -沟通中花费一些时间可以节省更多的时间。 +的项目一样,许多成功的基础最好是在第一行代码编写之前就打下。在早期计划和 +沟通中花费一些时间可以在之后节省更多的时间。 -详述问题 +搞清问题 -------- -与任何工程项目一样,成功的内核增强从要解决的问题的清晰描述开始。在某些情况 -下,这个步骤很容易:例如,当某个特定硬件需要驱动程序时。不过,在其他方面, -将实际问题与建议的解决方案混淆是很有诱惑力的,这可能会导致困难。 +与任何工程项目一样,成功的内核改善从清晰描述要解决的问题开始。在某些情况 +下,这个步骤很容易:例如当某个特定硬件需要驱动程序时。不过,在其他情况下, +很容易将实际问题与建议的解决方案混在一起,这可能会导致麻烦。 -举个例子:几年前,使用Linux音频的开发人员寻求一种方法来运行应用程序,而不因 -系统延迟过大而导致退出或其他工件。他们得到的解决方案是一个内核模块,旨在连 -接到Linux安全模块(LSM)框架中;这个模块可以配置为允许特定的应用程序访问 -实时调度程序。这个模块被实现并发送到Linux内核邮件列表,在那里它立即遇到问题。 +举个例子:几年前,Linux音频的开发人员寻求一种方法来运行应用程序,而不会因 +系统延迟过大而导致退出或其他问题。他们得到的解决方案是一个连接到Linux安全 +模块(LSM)框架中的内核模块;这个模块可以配置为允许特定的应用程序访问实时 +调度程序。这个模块被实现并发到linux-kernel邮件列表,在那里它立即遇到了麻烦。 对于音频开发人员来说,这个安全模块足以解决他们当前的问题。但是,对于更广泛的 内核社区来说,这被视为对LSM框架的滥用(LSM框架并不打算授予他们原本不具备的 进程特权),并对系统稳定性造成风险。他们首选的解决方案包括短期的通过rlimit 机制进行实时调度访问,以及长期的减少延迟的工作。 -然而,音频社区看不到他们实施的特定解决方案的过去;他们不愿意接受替代方案。 +然而,音频社区无法超越他们实施的特定解决方案来看问题;他们不愿意接受替代方案。 由此产生的分歧使这些开发人员对整个内核开发过程感到失望;其中一个开发人员返回 -到音频列表并发布了以下内容: +到audio列表并发布了以下内容: - 有很多非常好的Linux内核开发人员,但他们往往会被一群傲慢的傻瓜所压倒。 - 试图向这些人传达用户需求是浪费时间。他们太“聪明”了,根本听不到少数人 - 的话。 + 有很多非常好的Linux内核开发人员,但他们往往会被一群傲慢的傻瓜所压倒。 + 试图向这些人传达用户需求是浪费时间。他们太“聪明”了,根本听不到少数 + 人的话。 (http://lwn.net/articles/131776/) -实际情况不同;与特定模块相比,内核开发人员更关心系统稳定性、长期维护以及找到 -正确的问题解决方案。这个故事的寓意是把重点放在问题上——而不是具体的解决方案 -上——并在投入创建代码之前与开发社区讨论这个问题。 +实际情况却是不同的;与特定模块相比,内核开发人员更关心系统稳定性、长期维护 +以及找到问题的正确解决方案。这个故事的寓意是把重点放在问题上——而不是具体的 +解决方案上——并在开始编写代码之前与开发社区讨论这个问题。 因此,在考虑一个内核开发项目时,我们应该得到一组简短问题的答案: - - 究竟需要解决的问题是什么? + - 需要解决的问题究竟是什么? - - 受此问题影响的用户是谁?解决方案应该解决哪些用例? + - 受此问题影响的用户有哪些?解决方案应该解决哪些使用案例? - 内核现在为何没能解决这个问题? @@ -62,100 +69,100 @@ - 很可能问题是由内核以您不理解的方式解决的。Linux内核很大,具有许多不明显 的特性和功能。并不是所有的内核功能都像人们所希望的那样有文档记录,而且很 - 容易遗漏一些东西。你的作者发出了一个完整的驱动程序,复制了一个新作者不 - 知道的现有驱动程序。重新设计现有轮子的代码不仅浪费,而且不会被接受到主线 + 容易遗漏一些东西。某作者发布了一个完整的驱动程序,重复了一个其不 + 知道的现有驱动程序。重新发明现有轮子的代码不仅浪费,而且不会被接受到主线 内核中。 - - 建议的解决方案中可能有一些元素不适用于主线合并。在编写代码之前,最好先 - 了解这样的问题。 + - 建议的解决方案中可能有一些要素不适合并入主线。在编写代码之前,最好先了解 + 这样的问题。 - 其他开发人员完全有可能考虑过这个问题;他们可能有更好的解决方案的想法,并且 可能愿意帮助创建这个解决方案。 在内核开发社区的多年经验给了我们一个明确的教训:闭门设计和开发的内核代码总是 有一些问题,这些问题只有在代码发布到社区中时才会被发现。有时这些问题很严重, -需要数月或数年的努力才能使代码达到内核社区的标准。一些例子包括: +需要数月或数年的努力才能使代码达到内核社区的标准。例如: - 设计并实现了单处理器系统的DeviceScape网络栈。只有使其适合于多处理器系统, - 才能将其合并到主线中。在代码中改装锁等等是一项困难的任务;因此,这段代码 + 才能将其合并到主线中。在代码中修改锁等等是一项困难的任务;因此,这段代码 (现在称为mac80211)的合并被推迟了一年多。 - Reiser4文件系统包含许多功能,核心内核开发人员认为这些功能应该在虚拟文件 系统层中实现。它还包括一些特性,这些特性在不将系统暴露于用户引起的死锁的 - 情况下是不容易实现的。这些问题的最新发现——以及对其中一些问题的拒绝——已经 - 导致Reiser4远离了主线内核。 + 情况下是不容易实现的。这些问题过迟发现——以及拒绝处理其中一些问题——已经 + 导致Reiser4置身主线内核之外。 - Apparmor安全模块以被认为不安全和不可靠的方式使用内部虚拟文件系统数据结构。 - 这种担心(包括其他)使Apparmor多年不在主线上。 + 这种担心(包括其他)使Apparmor多年来无法进入主线。 -在每一种情况下,通过与内核开发人员的早期讨论,可以避免大量的痛苦和额外的工作。 +在这些情况下,与内核开发人员的早期讨论,可以避免大量的痛苦和额外的工作。 -找谁交流 --------- +找谁交流? +---------- 当开发人员决定公开他们的计划时,下一个问题是:我们从哪里开始?答案是找到正确 的邮件列表和正确的维护者。对于邮件列表,最好的方法是在维护者(MAINTAINERS)文件 -中查找要发布的相关位置。如果有一个合适的子系统列表,那么发布它通常比在Linux -内核上发布更可取;您更有可能接触到在相关子系统中具有专业知识的开发人员,并且 -环境可能具支持性。 +中查找要发布的相关位置。如果有一个合适的子系统列表,那么其上发布通常比在 +linux-kernel上发布更可取;您更有可能接触到在相关子系统中具有专业知识的开发 +人员,并且环境可能具支持性。 -找到维护人员可能会有点困难。同样,维护者文件是开始的地方。但是,该文件往往不总 -是最新的,并且并非所有子系统都在那里表示。实际上,维护者文件中列出的人员可能 +找到维护人员可能会有点困难。同样,维护者文件是开始的地方。但是,该文件往往不 +是最新的,并且并非所有子系统都在那里显示。实际上,维护者文件中列出的人员可能 不是当前实际担任该角色的人员。因此,当对联系谁有疑问时,一个有用的技巧是使用 -git(尤其是“git-log”)查看感兴趣的子系统中当前活动的用户。看看谁在写补丁, -如果有人的话,谁会在这些补丁上加上用线签名的。这些人将是帮助新开发项目的最佳 -人选。 +git(尤其是“git-log”)查看感兴趣的子系统中当前活动的用户。看看谁在写补丁、 +谁会在这些补丁上加上Signed-off-by行签名(如有)。这些人将是帮助新开发项目的 +最佳人选。 -找到合适的维护者的任务有时是非常具有挑战性的,以至于内核开发人员添加了一个 -脚本来简化过程: +找到合适的维护者有时是非常具有挑战性的,以至于内核开发人员添加了一个脚本来 +简化这个过程: :: .../scripts/get_maintainer.pl -当给定“-f”选项时,此脚本将返回给定文件或目录的当前维护者。如果在命令行上传递 -了一个补丁,它将列出可能接收补丁副本的维护人员。有许多选项可以调节 -get_maintainer.pl搜索维护者的难易程度;请小心使用更具攻击性的选项,因为最终 +当给定“-f”选项时,此脚本将返回指定文件或目录的当前维护者。如果在命令行上 +给出了一个补丁,它将列出可能接收补丁副本的维护人员。有许多选项可以调节 +get_maintainer.pl搜索维护者的严格程度;请小心使用更激进的选项,因为最终结果 可能会包括对您正在修改的代码没有真正兴趣的开发人员。 -如果所有其他方法都失败了,那么与Andrew Morton交谈可以成为一种有效的方法来跟踪 -特定代码段的维护人员。 +如果所有其他方法都失败了,那么与Andrew Morton交流是跟踪特定代码段维护人员 +的一种有效方法。 何时邮寄? ---------- -如果可能的话,在早期阶段发布你的计划只会有帮助。描述正在解决的问题以及已经 +如果可能的话,在早期阶段发布你的计划只会更有帮助。描述正在解决的问题以及已经 制定的关于如何实施的任何计划。您可以提供的任何信息都可以帮助开发社区为项目 提供有用的输入。 -在这个阶段可能发生的一件令人沮丧的事情不是敌对的反应,而是很少或根本没有 -反应。可悲的事实是:(1)内核开发人员往往很忙;(2)不缺少有宏伟计划和很少 -代码(甚至代码前景)支持他们的人;(3)没有人有义务审查或评论别人发表的 -想法。除此之外,高级设计常常隐藏一些问题,这些问题只有在有人真正尝试实现 -这些设计时才会被发现;因此,内核开发人员宁愿看到代码。 +在这个阶段可能发生的一件令人沮丧的事情不是得到反对意见,而是很少或根本没有 +反馈。令人伤心的事实是:(1)内核开发人员往往很忙;(2)不缺少有宏伟计划但 +代码(甚至代码设想)很少的人去支持他们;(3)没有人有义务审查或评论别人发表 +的想法。除此之外,高层级的设计常常隐藏着一些问题,这些问题只有在有人真正尝试 +实现这些设计时才会被发现;因此,内核开发人员宁愿看到代码。 -如果发表评论的请求在评论的方式上没有什么效果,不要假设这意味着对项目没有 -兴趣。不幸的是,你也不能假设你的想法没有问题。在这种情况下,最好的做法是 -继续进行,把你的进展随时通知社区。 +如果发布请求评论(RFC)并没得到什么有用的评论,不要以为这意味着无人对此项目 +有兴趣,同时你也不能假设你的想法没有问题。在这种情况下,最好的做法是继续进 +行,把你的进展随时通知社区。 获得官方认可 ----------------------- -如果您的工作是在公司环境中完成的,就像大多数Linux内核工作一样,显然,在您将 -公司的计划或代码发布到公共邮件列表之前,必须获得适当授权的经理的许可。发布 -不确定是否兼容GPL的代码可能是有特别问题的;公司的管理层和法律人员越早能够就 -发布内核开发项目达成一致,对参与的每个人都越好。 +如果您的工作是在公司环境中完成的,就像大多数Linux内核工作一样;显然,在您将 +公司的计划或代码发布到公共邮件列表之前,必须获得有适当权利经理的许可。发布 +不确定是否兼容GPL的代码尤其会带来问题;公司的管理层和法律人员越早能够就发布 +内核开发项目达成一致,对参与的每个人都越好。 一些读者可能会认为他们的核心工作是为了支持还没有正式承认存在的产品。将雇主 的计划公布在公共邮件列表上可能不是一个可行的选择。在这种情况下,有必要考虑 保密是否真的是必要的;通常不需要把开发计划关在门内。 -也就是说,有些情况下,一家公司在开发过程的早期就不能合法地披露其计划。拥有 -经验丰富的内核开发人员的公司可以选择以开环的方式进行,前提是他们以后能够避免 +的确,有些情况下一家公司在开发过程的早期无法合法地披露其计划。拥有经验丰富 +的内核开发人员的公司可能选择以开环的方式进行开发,前提是他们以后能够避免 严重的集成问题。对于没有这种内部专业知识的公司,最好的选择往往是聘请外部 -开发商根据保密协议审查计划。Linux基金会运行了一个NDA程序,旨在帮助解决这种 -情况; +开发者根据保密协议审查计划。Linux基金会运行了一个NDA程序,旨在帮助解决这种 +情况;更多信息参见: - http://www.linuxfoundation.org/en/NDA_program + http://www.linuxfoundation.org/nda/ 这种审查通常足以避免以后出现严重问题,而无需公开披露项目。 diff --git a/Documentation/translations/zh_CN/process/4.Coding.rst b/Documentation/translations/zh_CN/process/4.Coding.rst index 66cd8ee076062b8d0e94db86ce915ebab6550b56..94f7f866f10397913a5a62f5faf820a5fd5f1fa8 100644 --- a/Documentation/translations/zh_CN/process/4.Coding.rst +++ b/Documentation/translations/zh_CN/process/4.Coding.rst @@ -1,155 +1,160 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/4.Coding.rst <development_coding>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_coding: 使代码正确 ====================== -虽然对于一个坚实的、面向社区的设计过程有很多话要说,但是任何内核开发项目的 -证明都在生成的代码中。它是将由其他开发人员检查并合并(或不合并)到主线树中 +虽然一个坚实的、面向社区的设计过程有很多值得说道的,但是任何内核开发项目工作 +的证明都反映在代码中。它是将由其他开发人员检查并合并(或不合并)到主线树中 的代码。所以这段代码的质量决定了项目的最终成功。 -本节将检查编码过程。我们将从内核开发人员出错的几种方式开始。然后重点将转移 -到正确的事情和可以帮助这个任务的工具上。 +本节将检查编码过程。我们将从内核开发人员常犯的几种错误开始。然后重点将转移 +到正确的做法和相关有用的工具上。 陷阱 ---- -编码风格 +代码风格 ******** -内核长期以来都有一种标准的编码风格,如 +内核长期以来都有其标准的代码风格,如 :ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>` -中所述。在大部分时间里,该文件中描述的政策被认为至多是建议性的。因此,内核 -中存在大量不符合编码风格准则的代码。代码的存在会给内核开发人员带来两个独立 -的危害。 - -首先,要相信内核编码标准并不重要,也不强制执行。事实上,如果没有按照标准对代 -码进行编码,那么向内核添加新代码是非常困难的;许多开发人员甚至会在审查代码之 -前要求对代码进行重新格式化。一个与内核一样大的代码库需要一些统一的代码,以使 -开发人员能够快速理解其中的任何部分。所以已经没有空间来存放奇怪的格式化代码了。 - -偶尔,内核的编码风格会与雇主的强制风格发生冲突。在这种情况下,内核的风格必须 -在代码合并之前获胜。将代码放入内核意味着以多种方式放弃一定程度的控制权——包括 -控制代码的格式化方式。 - -另一个陷阱是假定已经在内核中的代码迫切需要编码样式的修复。开发人员可能会开始 -生成重新格式化补丁,作为熟悉过程的一种方式,或者作为将其名称写入内核变更日志 -的一种方式,或者两者兼而有之。但是纯编码风格的修复被开发社区视为噪音;它们往 -往受到冷遇。因此,最好避免使用这种类型的补丁。由于其他原因,在处理一段代码的 -同时修复它的样式是很自然的,但是编码样式的更改不应该仅为了更改而进行。 - -编码风格的文档也不应该被视为绝对的法律,这是永远不会被违反的。如果有一个很好 -的理由反对这种样式(例如,如果拆分为适合80列限制的行,那么它的可读性就会大大 -降低),那么就这样做。 - -请注意,您还可以使用 ``clang-format`` 工具来帮助您处理这些规则,自动重新格式 -化部分代码,并查看完整的文件,以发现编码样式错误、拼写错误和可能的改进。它还 -可以方便地进行排序,包括对齐变量/宏、回流文本和其他类似任务。有关详细信息,请 -参阅文件 :ref:`Documentation/process/clang-format.rst <clangformat>` +中所述。在多数时候,该文档中描述的准则至多被认为是建议性的。因此,内核中存在 +大量不符合代码风格准则的代码。这种代码的存在会给内核开发人员带来两方面的危害。 + +首先,相信内核代码标准并不重要,也不强制执行。但事实上,如果没有按照标准 +编写代码,那么新代码将很难加入到内核中;许多开发人员甚至会在审查代码之前要求 +对代码进行重新格式化。一个像内核这么大的代码库需要一些统一格式的代码,以使 +开发人员能够快速理解其中的任何部分。所以再也经不起奇怪格式的代码的折腾了。 + +内核的代码风格偶尔会与雇主的强制风格发生冲突。在这种情况下,必须在代码合并 +之前遵从内核代码风格。将代码放入内核意味着以多种方式放弃一定程度的控制权—— +包括控制代码样式。 + +另一个危害是认为已经在内核中的代码迫切需要修复代码样式。开发者可能会开始编写 +重新格式化补丁,作为熟悉开发过程的一种方式,或者作为将其名字写入内核变更日志 +的一种方式,或者两者兼而有之。但是纯代码风格的修复被开发社区视为噪音,它们往 +往受到冷遇。因此,最好避免编写这种类型的补丁。在由于其他原因处理一段代码的 +同时顺带修复其样式是很自然的,但是不应该仅为了更改代码样式而更改之。 + +代码风格文档也不应该被视为绝对不可违反的规则。如果有一个足够的理由反对这种 +样式(例如为了80列限制拆分行会导致可读性大大降低),那么就这样做吧。 + +注意您还可以使用 ``clang-format`` 工具来帮助您处理这些规则,快速自动重新格式 +化部分代码,和审阅完整的文件以发现代码样式错误、拼写错误和可能的改进。它还 +可以方便地排序 ``#includes`` 、对齐变量/宏、重排文本和其他类似任务。有关详细 +信息,请参阅文档 :ref:`Documentation/process/clang-format.rst <clangformat>` 抽象层 ****** 计算机科学教授教学生以灵活性和信息隐藏的名义广泛使用抽象层。当然,内核广泛 -地使用了抽象;任何涉及数百万行代码的项目都不能做到这一点并存活下来。但经验 -表明,过度或过早的抽象可能和过早的优化一样有害。抽象应用于所需的级别, +地使用了抽象;任何涉及数百万行代码的项目都必须做到这一点以存续下来。但经验 +表明,过度或过早的抽象可能和过早的优化一样有害。抽象应用在适当层级, 不要过度。 -在一个简单的级别上,考虑一个函数的参数,该参数总是由所有调用方作为零传递。 -我们可以保留这个论点: 以防有人最终需要使用它提供的额外灵活性。不过,到那时, -实现这个额外参数的代码很有可能以某种从未被注意到的微妙方式被破坏——因为它从 -未被使用过。或者,当需要额外的灵活性时,它不会以符合程序员早期期望的方式来 -这样做。内核开发人员通常会提交补丁来删除未使用的参数;一般来说,首先不应该 -添加这些参数。 +简单点,先考虑一个调用时始终只有一个参数且总为零的函数。我们可以保留这个参数, +以在需要使用它时提供的额外灵活性。不过,在那时实现了这个额外参数的代码很有 +可能以某种从未被注意到的微妙方式被破坏——因为它从未被使用过。或者当需要额外 +的灵活性时,它并未以符合程序员当初期望的方式来实现。内核开发人员通常会提交 +补丁来删除未使用的参数;一般来说,一开始就不应该添加这些参数。 -隐藏硬件访问的抽象层——通常允许大量的驱动程序在多个操作系统中使用——尤其不受 +隐藏硬件访问的抽象层——通常为了允许大量的驱动程序兼容多个操作系统——尤其不受 欢迎。这样的层使代码变得模糊,可能会造成性能损失;它们不属于Linux内核。 -另一方面,如果您发现自己从另一个内核子系统复制了大量的代码,那么现在是时候 -问一下,事实上,将这些代码中的一些提取到单独的库中,或者在更高的层次上实现 -这些功能是否有意义。在整个内核中复制相同的代码没有价值。 +另一方面,如果您发现自己从另一个内核子系统复制了大量的代码,那么是时候 +了解一下:是否需要将这些代码中的部分提取到单独的库中,或者在更高的层次上 +实现这些功能。在整个内核中复制相同的代码没有价值。 #ifdef 和预处理 *************** -C预处理器似乎给一些C程序员带来了强大的诱惑,他们认为它是一种有效地将大量灵 -活性编码到源文件中的方法。但是预处理器不是C,大量使用它会导致代码对其他人来 -说更难读取,对编译器来说更难检查正确性。大量的预处理器几乎总是代码需要一些 +C预处理器似乎给一些C程序员带来了强大的诱惑,他们认为它是一种将大量灵活性加入 +源代码中的方法。但是预处理器不是C,大量使用它会导致代码对其他人来说更难阅读, +对编译器来说更难检查正确性。使用了大量预处理器几乎总是代码需要一些 清理工作的标志。 -使用ifdef的条件编译实际上是一个强大的功能,它在内核中使用。但是很少有人希望 -看到代码被大量地撒上ifdef块。作为一般规则,ifdef的使用应尽可能限制在头文件 -中。有条件编译的代码可以限制函数,如果代码不存在,这些函数就会变成空的。然后 -编译器将悄悄地优化对空函数的调用。结果是代码更加清晰,更容易理解。 +使用#ifdef的条件编译实际上是一个强大的功能,它在内核中使用。但是很少有人希望 +看到代码被铺满#ifdef块。一般规定,ifdef的使用应尽可能限制在头文件中。条件 +编译代码可以限制函数,如果代码不存在,这些函数就直接变成空的。然后编译器将 +悄悄地优化对空函数的调用。使得代码更加清晰,更容易理解。 -C预处理器宏存在许多危险,包括可能对具有副作用且没有类型安全性的表达式进行多 -重评估。如果您试图定义宏,请考虑创建一个内联函数。结果相同的代码,但是内联 -函数更容易读取,不会多次计算其参数,并且允许编译器对参数和返回值执行类型检查。 +C预处理器宏存在许多危险性,包括可能对具有副作用且没有类型安全的表达式进行多 +重评估。如果您试图定义宏,请考虑创建一个内联函数替代。结果相同的代码,内联 +函数更容易阅读,不会多次计算其参数,并且允许编译器对参数和返回值执行类型检查。 内联函数 ******** 不过,内联函数本身也存在风险。程序员可以倾心于避免函数调用和用内联函数填充源 文件所固有的效率。然而,这些功能实际上会降低性能。因为它们的代码在每个调用站 -点都被复制,所以它们最终会增加编译内核的大小。反过来,这会对处理器的内存缓存 -造成压力,从而大大降低执行速度。通常,内联函数应该非常小,而且相对较少。毕竟, -函数调用的成本并不高;大量内联函数的创建是过早优化的典型例子。 +点都被复制一遍,所以最终会增加编译内核的大小。此外,这也对处理器的内存缓存 +造成压力,从而大大降低执行速度。通常内联函数应该非常小,而且相对较少。毕竟 +函数调用的成本并不高;大量创建内联函数是过早优化的典型例子。 -一般来说,内核程序员会忽略缓存效果,这会带来危险。在开始的数据结构课程中,经 -典的时间/空间权衡通常不适用于当代硬件。空间就是时间,因为一个大的程序比一个 +一般来说,内核程序员会自冒风险忽略缓存效果。在数据结构课程开头中的经典 +时间/空间权衡通常不适用于当代硬件。空间 *就是* 时间,因为一个大的程序比一个 更紧凑的程序运行得慢。 -最近的编译器在决定一个给定函数是否应该被内联方面扮演着越来越积极的角色。 -因此,“inline”关键字的自由放置可能不仅仅是过度的,它也可能是无关的。 +较新的编译器越来越激进地决定一个给定函数是否应该内联。因此,随意放置使用 +“inline”关键字可能不仅仅是过度的,也可能是无用的。 锁 ** -2006年5月,“deviceescape”网络堆栈在GPL下发布,并被纳入主线内核。这是一个受 -欢迎的消息;对Linux中无线网络的支持充其量被认为是不合格的,而deviceescape -堆栈提供了修复这种情况的承诺。然而,直到2007年6月(2.6.22),这段代码才真 +2006年5月,“deviceescape”网络堆栈在前呼后拥下以GPL发布,并被纳入主线内核。 +这是一个受欢迎的消息;Linux中对无线网络的支持充其量被认为是不合格的,而 +Deviceescape堆栈承诺修复这种情况。然而直到2007年6月(2.6.22),这段代码才真 正进入主线。发生了什么? -这段代码显示了许多闭门造车的迹象。但一个特别大的问题是,它并不是设计用于多 -处理器系统。在合并这个网络堆栈(现在称为mac80211)之前,需要对其进行一个锁 -方案的改造。 +这段代码出现了许多闭门造车的迹象。但一个大麻烦是,它并不是为多处理器系统而 +设计。在合并这个网络堆栈(现在称为mac80211)之前,需要对其进行一个锁方案的 +改造。 曾经,Linux内核代码可以在不考虑多处理器系统所带来的并发性问题的情况下进行 -开发。然而,现在,这个文件是写在双核笔记本电脑上的。即使在单处理器系统上, +开发。然而现在,这个文档就是在双核笔记本电脑上写的。即使在单处理器系统上, 为提高响应能力所做的工作也会提高内核内的并发性水平。编写内核代码而不考虑锁 -的日子已经过去很长了。 +的日子早已远去。 可以由多个线程并发访问的任何资源(数据结构、硬件寄存器等)必须由锁保护。新 -的代码应该记住这一要求;事后改装锁是一项相当困难的任务。内核开发人员应该花 -时间充分了解可用的锁原语,以便为作业选择正确的工具。显示对并发性缺乏关注的 -代码进入主线将很困难。 +的代码应该谨记这一要求;事后修改锁是一项相当困难的任务。内核开发人员应该花 +时间充分了解可用的锁原语,以便为工作选择正确的工具。对并发性缺乏关注的代码 +很难进入主线。 回归 **** -最后一个值得一提的危险是:它可能会引起改变(这可能会带来很大的改进),从而 -导致现有用户的某些东西中断。这种变化被称为“回归”,回归已经成为主线内核最不 -受欢迎的。除少数例外情况外,如果回归不能及时修正,会导致回归的变化将被取消。 -最好首先避免回归。 +最后一个值得一提的危险是回归:它可能会引起导致现有用户的某些东西中断的改变 +(这也可能会带来很大的改进)。这种变化被称为“回归”,回归已经成为主线内核 +最不受欢迎的问题。除了少数例外情况,如果回归不能及时修正,会导致回归的修改 +将被取消。最好首先避免回归发生。 -人们常常争论,如果回归让更多人可以工作,远超过产生问题,那么回归是合理的。 -如果它破坏的一个系统却为十个系统带来新的功能,为什么不进行更改呢?2007年7月, +人们常常争论,如果回归带来的功能远超过产生的问题,那么回归是否为可接受的。 +如果它破坏了一个系统却为十个系统带来新的功能,为何不改改态度呢?2007年7月, Linus对这个问题给出了最佳答案: :: - 所以我们不会通过引入新问题来修复错误。那样的谎言很疯狂,没有人知道 - 你是否真的有进展。是前进两步,后退一步,还是向前一步,向后两步? + + 所以我们不会通过引入新问题来修复错误。这种方式是靠不住的,没人知道 + 是否真的有进展。是前进两步、后退一步,还是前进一步、后退两步? (http://lwn.net/articles/243460/) -一种特别不受欢迎的回归类型是用户空间ABI的任何变化。一旦接口被导出到用户空间, +特别不受欢迎的一种回归类型是用户空间ABI的任何变化。一旦接口被导出到用户空间, 就必须无限期地支持它。这一事实使得用户空间接口的创建特别具有挑战性:因为它们 -不能以不兼容的方式进行更改,所以必须第一次正确地进行更改。因此,用户空间界面 -总是需要大量的思考、清晰的文档和广泛的审查。 +不能以不兼容的方式进行更改,所以必须一次就对。因此,用户空间接口总是需要大量 +的思考、清晰的文档和广泛的审查。 代码检查工具 @@ -157,13 +162,13 @@ Linus对这个问题给出了最佳答案: 至少目前,编写无错误代码仍然是我们中很少人能达到的理想状态。不过,我们希望做 的是,在代码进入主线内核之前,尽可能多地捕获并修复这些错误。为此,内核开发人 -员已经组装了一系列令人印象深刻的工具,可以自动捕获各种各样的模糊问题。计算机 +员已经提供了一系列令人印象深刻的工具,可以自动捕获各种各样的隐藏问题。计算机 发现的任何问题都是一个以后不会困扰用户的问题,因此,只要有可能,就应该使用 自动化工具。 -第一步只是注意编译器产生的警告。当代版本的GCC可以检测(并警告)大量潜在错误。 -通常,这些警告都指向真正的问题。提交以供审阅的代码通常不会产生任何编译器警告。 -在消除警告时,注意了解真正的原因,并尽量避免“修复”,使警告消失而不解决其原因。 +第一步是注意编译器产生的警告。当前版本的GCC可以检测(并警告)大量潜在错误。 +通常,这些警告都指向真正的问题。提交以供审阅的代码一般不会产生任何编译器警告。 +在消除警告时,注意了解真正的原因,并尽量避免仅“修复”使警告消失而不解决其原因。 请注意,并非所有编译器警告都默认启用。使用“make KCFLAGS=-W”构建内核以 获得完整集合。 @@ -172,45 +177,43 @@ Linus对这个问题给出了最佳答案: 子菜单中。对于任何用于开发或测试目的的内核,都应该启用其中几个选项。特别是, 您应该打开: - - 启用 ENABLE_MUST_CHECK and FRAME_WARN 以获得一组额外的警告,以解决使用不 - 推荐使用的接口或忽略函数的重要返回值等问题。这些警告生成的输出可能是冗长 - 的,但您不必担心来自内核其他部分的警告。 + - FRAME_WARN 获取大于给定数量的堆栈帧的警告。 + 这些警告生成的输出可能比较冗长,但您不必担心来自内核其他部分的警告。 - - DEBUG_OBJECTS 将添加代码,以跟踪内核创建的各种对象的生存期,并在出现问题时 - 发出警告。如果要添加创建(和导出)自己的复杂对象的子系统,请考虑添加对对象 - 调试基础结构的支持。 + - DEBUG_OBJECTS 将添加代码以跟踪内核创建的各种对象的生命周期,并在出现问题 + 时发出警告。如果你要添加创建(和导出)关于其自己的复杂对象的子系统,请 + 考虑打开对象调试基础结构的支持。 - DEBUG_SLAB 可以发现各种内存分配和使用错误;它应该用于大多数开发内核。 - - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP and DEBUG_MUTEXES 会发现许多常见的 - 锁定错误. + - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP 和 DEBUG_MUTEXES 会发现许多常见的 + 锁错误。 -还有很多其他调试选项,其中一些将在下面讨论。其中一些具有显著的性能影响,不应 -一直使用。但是,在学习可用选项上花费的一些时间可能会在短期内得到多次回报。 +还有很多其他调试选项,其中一些将在下面讨论。其中一些有显著的性能影响,不应 +一直使用。在学习可用选项上花费一些时间,可能会在短期内得到许多回报。 -其中一个较重的调试工具是锁定检查器或“lockdep”。该工具将跟踪系统中每个锁 +其中一个较重的调试工具是锁检查器或“lockdep”。该工具将跟踪系统中每个锁 (spinlock或mutex)的获取和释放、获取锁的相对顺序、当前中断环境等等。然后, -它可以确保总是以相同的顺序获取锁,相同的中断假设适用于所有情况,等等。换句话 -说,lockdep可以找到许多场景,在这些场景中,系统很少会死锁。在部署的系统中, -这种问题可能会很痛苦(对于开发人员和用户而言);LockDep允许提前以自动方式 -发现问题。具有任何类型的非普通锁定的代码在提交包含前应在启用lockdep的情况 -下运行。 +它可以确保总是以相同的顺序获取锁,相同的中断假设适用于所有情况等等。换句话 +说,lockdep可以找到许多导致系统死锁的场景。在部署的系统中,这种问题可能会 +很痛苦(对于开发人员和用户而言);LockDep允许提前以自动方式发现问题。具有 +任何类型的非普通锁的代码在提交合并前应在启用lockdep的情况下运行测试。 作为一个勤奋的内核程序员,毫无疑问,您将检查任何可能失败的操作(如内存分配) -的返回状态。然而,事实上,最终的故障恢复路径可能完全没有经过测试。未测试的 -代码往往会被破坏;如果所有这些错误处理路径都被执行了几次,那么您可能对代码 +的返回状态。然而,事实上,最终的故障复现路径可能完全没有经过测试。未测试的 +代码往往会出问题;如果所有这些错误处理路径都被执行了几次,那么您可能对代码 更有信心。 内核提供了一个可以做到这一点的错误注入框架,特别是在涉及内存分配的情况下。 -启用故障注入后,内存分配的可配置百分比将失败;这些失败可以限制在特定的代码 +启用故障注入后,内存分配的可配置失败的百分比;这些失败可以限定在特定的代码 范围内。在启用了故障注入的情况下运行,程序员可以看到当情况恶化时代码如何响 应。有关如何使用此工具的详细信息,请参阅 Documentation/fault-injection/fault-injection.rst。 -使用“sparse”静态分析工具可以发现其他类型的错误。对于sparse,可以警告程序员 -用户空间和内核空间地址之间的混淆、big endian和small endian数量的混合、在需 -要一组位标志的地方传递整数值等等。sparse必须单独安装(如果您的分发服务器没 -有将其打包,可以在 https://sparse.wiki.kernel.org/index.php/Main_page)找到, +“sparse”静态分析工具可以发现其他类型的错误。sparse可以警告程序员用户空间 +和内核空间地址之间的混淆、大端序与小端序的混淆、在需要一组位标志的地方传递 +整数值等等。sparse必须单独安装(如果您的分发服务器没有将其打包, +可以在 https://sparse.wiki.kernel.org/index.php/Main_page 找到), 然后可以通过在make命令中添加“C=1”在代码上运行它。 “Coccinelle”工具 :ref:`http://coccinelle.lip6.fr/ <devtools_coccinelle>` @@ -221,8 +224,8 @@ scripts/coccinelle目录下已经打包了相当多的内核“语义补丁” 其他类型的可移植性错误最好通过为其他体系结构编译代码来发现。如果没有S/390系统 -或Blackfin开发板,您仍然可以执行编译步骤。可以在以下位置找到一组用于x86系统的 -大型交叉编译器: +或Blackfin开发板,您仍然可以执行编译步骤。可以在以下位置找到一大堆用于x86系统的 +交叉编译器: https://www.kernel.org/pub/tools/crosstool/ @@ -233,22 +236,22 @@ scripts/coccinelle目录下已经打包了相当多的内核“语义补丁” 文档通常比内核开发规则更为例外。即便如此,足够的文档将有助于简化将新代码合并 到内核中的过程,使其他开发人员的生活更轻松,并对您的用户有所帮助。在许多情况 -下,文件的添加已基本上成为强制性的。 +下,添加文档已基本上是强制性的。 任何补丁的第一个文档是其关联的变更日志。日志条目应该描述正在解决的问题、解决 方案的形式、处理补丁的人员、对性能的任何相关影响,以及理解补丁可能需要的任何 -其他内容。确保changelog说明了为什么补丁值得应用;大量开发人员未能提供这些信息。 +其他内容。确保变更日志说明了*为什么*补丁值得应用;大量开发者未能提供这些信息。 -任何添加新用户空间界面的代码(包括新的sysfs或/proc文件)都应该包含该界面的 -文档,该文档使用户空间开发人员能够知道他们在使用什么。请参阅 -Documentation/ABI/README,了解如何格式化此文档以及需要提供哪些信息。 +任何添加新用户空间接口的代码——包括新的sysfs或/proc文件——都应该包含该接口 +的文档,该文档使用户空间开发人员能够知道他们在使用什么。请参阅 +Documentation/ABI/README,了解如何此文档格式以及需要提供哪些信息。 -文件 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>` -描述了内核的所有引导时间参数。任何添加新参数的补丁都应该向该文件添加适当的 +文档 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>` +描述了内核的所有引导时间参数。任何添加新参数的补丁都应该向该文档添加适当的 条目。 -任何新的配置选项都必须附有帮助文本,帮助文本清楚地解释了这些选项以及用户可能 -希望何时选择它们。 +任何新的配置选项都必须附有帮助文本,帮助文本需清楚地解释这些选项以及用户可能 +希望何时使用它们。 许多子系统的内部API信息通过专门格式化的注释进行记录;这些注释可以通过 “kernel-doc”脚本以多种方式提取和格式化。如果您在具有kerneldoc注释的子系统中 @@ -257,31 +260,31 @@ Documentation/ABI/README,了解如何格式化此文档以及需要提供哪 来说是一个有用的活动。这些注释的格式以及如何创建kerneldoc模板的一些信息可以在 :ref:`Documentation/doc-guide/ <doc_guide>` 上找到。 -任何阅读大量现有内核代码的人都会注意到,注释的缺失往往是最值得注意的。再一次, -对新代码的期望比过去更高;合并未注释的代码将更加困难。这就是说,人们几乎不希望 -用语言注释代码。代码本身应该是可读的,注释解释了更微妙的方面。 +任何阅读大量现有内核代码的人都会注意到,注释的缺失往往是最值得注意的。同时, +对新代码的要求比过去更高;合并未注释的代码将更加困难。这就是说,人们并不期望 +详细注释的代码。代码本身应该是自解释的,注释阐释了更微妙的方面。 某些事情应该总是被注释。使用内存屏障时,应附上一行文字,解释为什么需要设置内存 -屏障。数据结构的锁定规则通常需要在某个地方解释。一般来说,主要数据结构需要全面 -的文档。应该指出单独代码位之间不明显的依赖性。任何可能诱使代码看门人进行错误的 -“清理”的事情都需要一个注释来说明为什么要这样做。等等。 +屏障。数据结构的锁规则通常需要在某个地方解释。一般来说,主要数据结构需要全面 +的文档。应该指出代码中分立的位之间不明显的依赖性。任何可能诱使代码管理人进行 +错误的“清理”的事情都需要一个注释来说明为什么要这样做。等等。 内部API更改 ----------- -内核提供给用户空间的二进制接口不能被破坏,除非在最严重的情况下。相反,内核的 -内部编程接口是高度流动的,当需要时可以更改。如果你发现自己不得不处理一个内核 -API,或者仅仅因为它不满足你的需求而不使用特定的功能,这可能是API需要改变的一 -个标志。作为内核开发人员,您有权进行此类更改。 +内核提供给用户空间的二进制接口不能被破坏,除非逼不得已。而内核的内部编程接口 +是高度流动的,当需要时可以更改。如果你发现自己不得不处理一个内核API,或者仅 +仅因为它不满足你的需求导致无法使用特定的功能,这可能是API需要改变的一个标志。 +作为内核开发人员,您有权进行此类更改。 -当然, 可以进行API更改,但它们必须是合理的。因此,任何进行内部API更改的补丁都 -应该附带一个关于更改内容和必要原因的描述。这种变化也应该分解成一个单独的补丁, -而不是埋在一个更大的补丁中。 +的确可以进行API更改,但更改必须是合理的。因此任何进行内部API更改的补丁都应该 +附带关于更改内容和必要原因的描述。这种变化也应该拆分成一个单独的补丁,而不是 +埋在一个更大的补丁中。 另一个要点是,更改内部API的开发人员通常要负责修复内核树中被更改破坏的任何代码。 -对于一个广泛使用的函数,这个职责可以导致成百上千的变化,其中许多变化可能与其他 -开发人员正在做的工作相冲突。不用说,这可能是一项大工作,所以最好确保理由是 +对于一个广泛使用的函数,这个责任可以导致成百上千的变化,其中许多变化可能与其他 +开发人员正在做的工作相冲突。不用说,这可能是一项大工程,所以最好确保理由是 可靠的。请注意,coccinelle工具可以帮助进行广泛的API更改。 在进行不兼容的API更改时,应尽可能确保编译器捕获未更新的代码。这将帮助您确保找 diff --git a/Documentation/translations/zh_CN/process/5.Posting.rst b/Documentation/translations/zh_CN/process/5.Posting.rst index 9ff9945f918c7ebfaf19fa6a6ff4490e9ccf02a0..b0c65614844d8fdc98b65d8d4f1ac529463d561b 100644 --- a/Documentation/translations/zh_CN/process/5.Posting.rst +++ b/Documentation/translations/zh_CN/process/5.Posting.rst @@ -1,150 +1,157 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/5.Posting.rst <development_posting>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_posting: 发布补丁 ======== -迟早,当您的工作准备好提交给社区进行审查,并最终包含到主线内核中时。不出所料, +您的工作迟早会准备好提交给社区进行审查,并最终包含到主线内核中。毫不稀奇, 内核开发社区已经发展出一套用于发布补丁的约定和过程;遵循这些约定和过程将使 -参与其中的每个人的生活更加轻松。本文件将试图合理详细地涵盖这些期望;更多信息 -也可在以下文件中找到 -:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`, -:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>` -和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`. +参与其中的每个人的生活更加轻松。本文档试图描述这些约定的部分细节;更多信息 +也可在以下文档中找到 +:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`, +:ref:`Documentation/translations/zh_CN/process/submitting-drivers.rst <cn_submittingdrivers>` +和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`。 何时邮寄 -------- -在补丁完全“准备好”之前,有一个不断的诱惑来避免发布补丁。对于简单的补丁, -这不是问题。但是,如果正在完成的工作很复杂,那么在工作完成之前从社区获得 -反馈就可以获得很多好处。因此,您应该考虑发布正在进行的工作,甚至使Git树 -可用,以便感兴趣的开发人员可以随时赶上您的工作。 +在补丁完全“准备好”之前,避免发布补丁是一种持续的诱惑。对于简单的补丁,这 +不是问题。但是如果正在完成的工作很复杂,那么在工作完成之前从社区获得反馈就 +可以获得很多好处。因此,您应该考虑发布正在进行的工作,甚至维护一个可用的Git +树,以便感兴趣的开发人员可以随时赶上您的工作。 -当发布还没有准备好包含的代码时,最好在发布本身中这样说。还应提及任何有待完成 -的主要工作和任何已知问题。很少有人会看到那些被认为是半生不熟的补丁,但是那些 -人会想到他们可以帮助你把工作推向正确的方向。 +当发布中有尚未准备好被包含的代码,最好在发布中说明。还应提及任何有待完成的 +主要工作和任何已知问题。很少有人会愿意看那些被认为是半生不熟的补丁,但是 +那些愿意的人会带着他们的点子来一起帮助你把工作推向正确的方向。 创建补丁之前 ------------ -在考虑将补丁发送到开发社区之前,有许多事情应该做。这些包括: +在考虑将补丁发送到开发社区之前,有许多事情应该做。包括: - - 尽可能地测试代码。利用内核的调试工具,确保内核使用所有合理的配置选项组合 - 进行构建,使用跨编译器为不同的体系结构进行构建等。 + - 尽可能地测试代码。利用内核的调试工具,确保内核使用了所有可能的配置选项组合 + 进行构建,使用交叉编译器为不同的体系结构进行构建等。 - - 确保您的代码符合内核编码风格指南。 + - 确保您的代码符合内核代码风格指南。 - 您的更改是否具有性能影响?如果是这样,您应该运行基准测试来显示您的变更的 影响(或好处);结果的摘要应该包含在补丁中。 - 确保您有权发布代码。如果这项工作是为雇主完成的,雇主对这项工作具有所有权, - 并且必须同意根据GPL对其进行放行。 + 并且必须同意根据GPL对其进行发布。 一般来说,在发布代码之前进行一些额外的思考,几乎总是能在短时间内得到回报。 补丁准备 -------- -准备发布补丁可能是一个惊人的工作量,但再次尝试节省时间在这里通常是不明智的, -即使在短期内。 +准备补丁发布的工作量可能很惊人,但在此尝试节省时间通常是不明智的,即使在短期 +内亦然。 -必须针对内核的特定版本准备补丁。作为一般规则,补丁程序应该基于Linus的Git树中 -的当前主线。当以主线为基础时,从一个众所周知的发布点开始——一个稳定的或RC的 -发布——而不是在一个主线分支任意点。 +必须针对内核的特定版本准备补丁。一般来说,补丁应该基于Linus的Git树中的当前 +主线。当以主线为基础时,请从一个众所周知的发布点开始——如稳定版本或 -rc +版本发布点——而不是在一个任意的主线分支点。 -但是,可能需要针对-mm、linux-next或子系统树生成版本,以便于更广泛的测试和审查。 -根据补丁的区域以及其他地方的情况,针对这些其他树建立补丁可能需要大量的工作来 +也可能需要针对-mm、linux-next或子系统树生成版本,以便于更广泛的测试和审查。 +根据补丁的区域以及其他地方的情况,针对其他树建立的补丁可能需要大量的工作来 解决冲突和处理API更改。 只有最简单的更改才应格式化为单个补丁;其他所有更改都应作为一系列逻辑更改进行。 分割补丁是一门艺术;一些开发人员花了很长时间来弄清楚如何按照社区期望的方式来 -做。然而,有一些经验法则可以大大帮助: +分割。不过,这些经验法则也许有帮助: - - 您发布的补丁程序系列几乎肯定不会是工作系统中的一系列更改。相反,您所做的 - 更改需要在最终形式中加以考虑,然后以有意义的方式进行拆分。开发人员对离散的、 - 自包含的更改感兴趣,而不是您获取这些更改的路径。 + - 您发布的补丁系列几乎肯定不会是开发过程中版本控制系统中的一系列更改。相反, + 需要对您所做更改的最终形式加以考虑,然后以有意义的方式进行拆分。开发人员对 + 离散的、自包含的更改感兴趣,而不是您创造这些更改的原始路径。 - - 每个逻辑上独立的变更都应该格式化为单独的补丁。这些更改可以是小的(“向此 - 结构添加字段”)或大的(例如,添加一个重要的新驱动程序),但它们在概念上 - 应该是小的,并且可以接受一行描述。每个补丁都应该做一个特定的更改,可以单独 - 检查并验证它所做的事情。 + - 每个逻辑上独立的变更都应该格式化为单独的补丁。这些更改可以是小的(如“向 + 此结构体添加字段”)或大的(如添加一个重要的新驱动程序),但它们在概念上 + 应该是小的,并且可以在一行内简述。每个补丁都应该做一个特定的、可以单独 + 检查并验证它所做的事情的更改。 - - 作为重申上述准则的一种方法:不要在同一补丁中混合不同类型的更改。如果一个 - 补丁修复了一个关键的安全漏洞,重新排列了一些结构,并重新格式化了代码,那么 - 很有可能它会被忽略,而重要的修复将丢失。 + - 换种方式重申上述准则,也就是说:不要在同一补丁中混合不同类型的更改。如果 + 一个补丁修复了一个关键的安全漏洞,又重新排列了一些结构,还重新格式化了代 + 码,那么它很有可能会被忽略,从而导致重要的修复丢失。 - - 每个补丁都应该产生一个内核,它可以正确地构建和运行;如果补丁系列在中间被 - 中断,那么结果应该仍然是一个工作的内核。补丁系列的部分应用是使用 - “git bisct”工具查找回归的一个常见场景;如果结果是一个损坏的内核,那么对于 - 那些从事追踪问题的高尚工作的开发人员和用户来说,将使他们的生活更加艰难。 + - 每个补丁都应该能创建一个可以正确地构建和运行的内核;如果补丁系列在中间被 + 断开,那么结果仍应是一个正常工作的内核。部分应用一系列补丁是使用 + “git bisct”工具查找回归的一个常见场景;如果结果是一个损坏的内核,那么将使 + 那些从事追踪问题的高尚工作的开发人员和用户的生活更加艰难。 - - 不过,不要过分。一位开发人员曾经将一组编辑内容作为500个单独的补丁发布到一个 - 文件中,这并没有使他成为内核邮件列表中最受欢迎的人。一个补丁可以相当大, - 只要它仍然包含一个单一的逻辑变更。 + - 不要过分分割。一位开发人员曾经将一组针对单个文件的编辑分成500个单独的补丁 + 发布,这并没有使他成为内核邮件列表中最受欢迎的人。一个补丁可以相当大, + 只要它仍然包含一个单一的 *逻辑* 变更。 - - 用一系列补丁添加一个全新的基础设施是很有诱惑力的,但是在系列中的最后一个 - 补丁启用整个补丁之前,该基础设施是不使用的。如果可能的话,应该避免这种 - 诱惑;如果这个系列增加了回归,那么二分法将指出最后一个补丁是导致问题的 - 补丁,即使真正的bug在其他地方。只要有可能,添加新代码的补丁程序应该立即 - 激活该代码。 + - 用一系列补丁添加一个全新的基础设施,但是该设施在系列中的最后一个补丁启用 + 整个变更之前不能使用,这看起来很诱人。如果可能的话,应该避免这种诱惑; + 如果这个系列增加了回归,那么二分法将指出最后一个补丁是导致问题的补丁, + 即使真正的bug在其他地方。只要有可能,添加新代码的补丁程序应该立即激活该 + 代码。 -创建完美补丁系列的工作可能是一个令人沮丧的过程,在完成“真正的工作”之后需要花费 -大量的时间和思考。但是,如果做得好,这是一段很好的时间。 +创建完美补丁系列的工作可能是一个令人沮丧的过程,在完成“真正的工作”之后需要 +花费大量的时间和思考。但是如果做得好,花费的时间就是值得的。 补丁格式和更改日志 ------------------ 所以现在你有了一系列完美的补丁可以发布,但是这项工作还没有完成。每个补丁都 -需要被格式化成一条消息,它可以快速而清晰地将其目的传达给世界其他地方。为此, +需要被格式化成一条消息,以快速而清晰地将其目的传达到世界其他地方。为此, 每个补丁将由以下部分组成: - - 命名补丁作者的可选“from”行。只有当你通过电子邮件传递别人的补丁时,这一行 - 才是必要的,但是如果有疑问,添加它不会有任何伤害。 + - 可选的“From”行,表明补丁作者。只有当你通过电子邮件发送别人的补丁时,这一行 + 才是必须的,但是为防止疑问加上它也不会有什么坏处。 - - 一行描述补丁的作用。对于没有其他上下文的读者来说,此消息应该足够了解补丁 - 的范围;这是将在“短格式”变更日志中显示的行。此消息通常首先用相关的子系统 - 名称格式化,然后是补丁的目的。例如: + - 一行描述,说明补丁的作用。对于在没有其他上下文的情况下看到该消息的读者来说, + 该消息应足以确定修补程序的范围;此行将显示在“short form(简短格式)”变更 + 日志中。此消息通常需要先加上子系统名称前缀,然后是补丁的目的。例如: - :: + :: - gpio: fix build on CONFIG_GPIO_SYSFS=n + gpio: fix build on CONFIG_GPIO_SYSFS=n - - 一个空白行,后面是补丁内容的详细描述。这个描述可以是必需的;它应该说明补丁 + - 一行空白,后接补丁内容的详细描述。此描述可以是任意需要的长度;它应该说明补丁 的作用以及为什么它应该应用于内核。 - - 一个或多个标记行,至少有一个由补丁作者的:signed-off-by 签名。签名将在下面 - 更详细地描述。 + - 一个或多个标记行,至少有一个由补丁作者的 Signed-off-by 签名。标记将在下面 + 详细描述。 -上面的项目一起构成补丁的变更日志。写一篇好的变更日志是一门至关重要但常常被 -忽视的艺术;值得花一点时间来讨论这个问题。当你写一个变更日志时,你应该记住 -有很多不同的人会读你的话。其中包括子系统维护人员和审查人员,他们需要决定是否 -应该包括补丁,分销商和其他维护人员试图决定是否应该将补丁反向移植到其他内核, -bug搜寻人员想知道补丁是否负责他们正在追查的问题,想知道内核如何变化的用户。 -等等。一个好的变更日志以最直接和最简洁的方式向所有这些人传达所需的信息。 +上面的项目一起构成补丁的变更日志。写一则好的变更日志是一门至关重要但常常被 +忽视的艺术;值得花一点时间来讨论这个问题。当你编写变更日志时,你应该记住有 +很多不同的人会读你的话。其中包括子系统维护人员和审查人员,他们需要决定是否 +应该合并补丁,分销商和其他维护人员试图决定是否应该将补丁反向移植到其他内核, +缺陷搜寻人员想知道补丁是否导致他们正在追查的问题,以及想知道内核如何变化的 +用户等等。一个好的变更日志以最直接和最简洁的方式向所有这些人传达所需的信息。 -为此,总结行应该描述变更的影响和动机,以及在一行约束条件下可能发生的变化。 +在结尾,总结行应该描述变更的影响和动机,以及在一行约束条件下可能发生的变化。 然后,详细的描述可以详述这些主题,并提供任何需要的附加信息。如果补丁修复了 -一个bug,请引用引入该bug的commit(如果可能,请在引用commits时同时提供commit id -和标题)。如果某个问题与特定的日志或编译器输出相关联,请包含该输出以帮助其他 -人搜索同一问题的解决方案。如果更改是为了支持以后补丁中的其他更改,那么就这么 -说。如果更改了内部API,请详细说明这些更改以及其他开发人员应该如何响应。一般 -来说,你越能把自己放在每个阅读你的changelog的人的位置上,changelog(和内核 +一个缺陷,请引用引入该缺陷的提交(如果可能,请在引用提交时同时提供其 id 和 +标题)。如果某个问题与特定的日志或编译器输出相关联,请包含该输出以帮助其他 +人搜索同一问题的解决方案。如果更改是为了支持以后补丁中的其他更改,那么应当 +说明。如果更改了内部API,请详细说明这些更改以及其他开发人员应该如何响应。 +一般来说,你越把自己放在每个阅读你变更日志的人的位置上,变更日志(和内核 作为一个整体)就越好。 -不用说,变更日志应该是将变更提交到修订控制系统时使用的文本。接下来是: +不消说,变更日志是将变更提交到版本控制系统时使用的文本。接下来将是: - - 补丁本身,采用统一的(“-u”)补丁格式。将“-p”选项用于diff将使函数名与更改 - 相关联,从而使结果补丁更容易被其他人读取。 + - 补丁本身,采用统一的(“-u”)补丁格式。使用“-p”选项来diff将使函数名与 + 更改相关联,从而使结果补丁更容易被其他人读取。 -您应该避免在补丁中包括对不相关文件(例如,由构建过程生成的文件或编辑器 -备份文件)的更改。文档目录中的文件“dontdiff”在这方面有帮助;使用“-X”选项将 +您应该避免在补丁中包括与更改不相关文件(例如,构建过程生成的文件或编辑器 +备份文件)。文档目录中的“dontdiff”文件在这方面有帮助;使用“-X”选项将 其传递给diff。 -上面提到的标签用于描述各种开发人员如何与这个补丁的开发相关联。 +上面提到的标签(tag)用于描述各种开发人员如何与这个补丁的开发相关联。 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>` 文档中对它们进行了详细描述;下面是一个简短的总结。每一行的格式如下: @@ -154,87 +161,87 @@ bug搜寻人员想知道补丁是否负责他们正在追查的问题,想知 常用的标签有: - - Signed-off-by: 这是一个开发人员的证明,他或她有权提交补丁以包含到内核中。 - 这是开发来源认证协议,其全文可在 + - Signed-off-by: 这是一个开发人员的证明,证明他或她有权提交补丁以包含到内核 + 中。这表明同意开发者来源认证协议,其全文见 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>` - 中找到,如果没有适当的签字,则不能合并到主线中。 + 如果没有合适的签字,则不能合并到主线中。 - Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上 - 工作时,它用于将属性赋予共同作者(除了 From: 所赋予的作者之外)。因为 - Co-developed-by: 表示作者身份,所以每个共同开发人, 必须紧跟在相关合作作者 - 的签名之后。具体内容和示例可以在以下文件中找到 + 工作时,它用于给出共同作者(除了 From: 所给出的作者之外)。由于 + Co-developed-by: 表示作者身份,所以每个共同开发人,必须紧跟在相关合作作者 + 的Signed-off-by之后。具体内容和示例见以下文件 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>` - Acked-by: 表示另一个开发人员(通常是相关代码的维护人员)同意补丁适合包含 在内核中。 - - Tested-by: 声明指定的人已经测试了补丁并发现它可以工作。 + - Tested-by: 声明某人已经测试了补丁并确认它可以工作。 - - Reviewed-by: 指定的开发人员已经审查了补丁的正确性;有关详细信息,请参阅 + - Reviewed-by: 表示某开发人员已经审查了补丁的正确性;有关详细信息,请参阅 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>` - - Reported-by: 指定报告此补丁修复的问题的用户;此标记用于提供感谢。 + - Reported-by: 指定报告此补丁修复的问题的用户;此标记用于表示感谢。 - - Cc:指定的人收到了补丁的副本,并有机会对此发表评论。 + - Cc:指定某人收到了补丁的副本,并有机会对此发表评论。 -在补丁中添加标签时要小心:只有cc:才适合在没有指定人员明确许可的情况下添加。 +在补丁中添加标签时要小心:只有Cc:才适合在没有指定人员明确许可的情况下添加。 发送补丁 -------- -在邮寄补丁之前,您还需要注意以下几点: +在寄出补丁之前,您还需要注意以下几点: - - 您确定您的邮件发送程序不会损坏补丁吗?有免费的空白更改或由邮件客户端 - 执行的行包装的补丁不会在另一端复原,并且通常不会进行任何详细检查。如果有 - 任何疑问,把补丁寄给你自己,让你自己相信它是完好无损的。 + - 您确定您的邮件发送程序不会损坏补丁吗?被邮件客户端更改空白或修饰了行的补丁 + 无法被另一端接受,并且通常不会进行任何详细检查。如果有任何疑问,先把补丁寄 + 给你自己,让你自己确定它是完好无损的。 :ref:`Documentation/translations/zh_CN/process/email-clients.rst <cn_email_clients>` - 提供了一些有用的提示,可以让特定的邮件客户机工作以发送补丁。 + 提供了一些有用的提示,可以让特定的邮件客户端正常发送补丁。 - - 你确定你的补丁没有愚蠢的错误吗?您应该始终通过scripts/checkpatch.pl运行 - 补丁程序,并解决它提出的投诉。请记住,checkpatch.pl虽然是大量思考内核 - 补丁应该是什么样子的体现,但它并不比您聪明。如果修复checkpatch.pl投诉会 + - 你确定你的补丁没有荒唐的错误吗?您应该始终通过scripts/checkpatch.pl检查 + 补丁程序,并解决它提出的问题。请记住,checkpatch.pl,虽然体现了对内核补丁 + 应该是什么样的大量思考,但它并不比您聪明。如果修复checkpatch.pl给的问题会 使代码变得更糟,请不要这样做。 补丁应始终以纯文本形式发送。请不要将它们作为附件发送;这使得审阅者在答复中更难 引用补丁的部分。相反,只需将补丁直接放到您的消息中。 -邮寄补丁时,重要的是将副本发送给任何可能感兴趣的人。与其他一些项目不同,内核 -鼓励人们错误地发送过多的副本;不要假定相关人员会看到您在邮件列表中的发布。 +寄出补丁时,重要的是将副本发送给任何可能感兴趣的人。与其他一些项目不同,内核 +鼓励人们甚至错误地发送过多的副本;不要假定相关人员会看到您在邮件列表中的发布。 尤其是,副本应发送至: - - 受影响子系统的维护人员。如前所述,维护人员文件是查找这些人员的第一个地方。 + - 受影响子系统的维护人员。如前所述,维护人员文件是查找这些人员的首选地方。 - 其他在同一领域工作的开发人员,尤其是那些现在可能在那里工作的开发人员。使用 git查看还有谁修改了您正在处理的文件,这很有帮助。 - - 如果您对错误报告或功能请求做出响应,也可以抄送原始发送人。 + - 如果您对某错误报告或功能请求做出响应,也可以抄送原始发送人。 - - 将副本发送到相关邮件列表,或者,如果没有其他应用,则发送到Linux内核列表。 + - 将副本发送到相关邮件列表,或者若无相关列表,则发送到linux-kernel列表。 - - 如果您正在修复一个bug,请考虑该修复是否应进入下一个稳定更新。如果是这样, - stable@vger.kernel.org 应该得到补丁的副本。另外,在补丁本身的标签中添加 - 一个“cc:stable@vger.kernel.org”;这将使稳定团队在修复进入主线时收到通知。 + - 如果您正在修复一个缺陷,请考虑该修复是否应进入下一个稳定更新。如果是这样, + 补丁副本也应发到stable@vger.kernel.org 。另外,在补丁本身的标签中添加一个 + “Cc: stable@vger.kernel.org”;这将使稳定版团队在修复进入主线时收到通知。 -当为一个补丁选择接收者时,最好知道你认为谁最终会接受这个补丁并将其合并。虽然 -可以将补丁直接发送给LinusTorvalds并让他合并,但通常情况下不会这样做。Linus -很忙,并且有子系统维护人员负责监视内核的特定部分。通常您会希望维护人员合并您 -的补丁。如果没有明显的维护人员,Andrew Morton通常是最后的补丁目标。 +当为一个补丁选择接收者时,最好清楚你认为谁最终会接受这个补丁并将其合并。虽然 +可以将补丁直接发给Linus Torvalds并让他合并,但通常情况下不会这样做。Linus很 +忙,并且有子系统维护人员负责监视内核的特定部分。通常您会希望维护人员合并您的 +补丁。如果没有明显的维护人员,Andrew Morton通常是最后的补丁接收者。 -补丁需要好的主题行。补丁程序行的规范格式如下: +补丁需要好的主题行。补丁主题行的规范格式如下: :: [PATCH nn/mm] subsys: one-line description of the patch -其中“nn”是补丁的序号,“mm”是系列中补丁的总数,“subsys”是受影响子系统的名称。 -显然,一个单独的补丁可以省略nn/mm。 +其中“nn”是补丁的序号,“mm”是系列中补丁的总数,“subsys”是受影响子系统的 +名称。当然,一个单独的补丁可以省略nn/mm。 -如果您有一系列重要的补丁,那么通常将介绍性描述作为零部分发送。不过,这种约定 -并没有得到普遍遵循;如果您使用它,请记住简介中的信息不会使它进入内核变更日志。 +如果您有一系列重要的补丁,那么通常发送一个简介作为第〇部分。不过,这个约定 +并没有得到普遍遵循;如果您使用它,请记住简介中的信息不会进入内核变更日志。 因此,请确保补丁本身具有完整的变更日志信息。 一般来说,多部分补丁的第二部分和后续部分应作为对第一部分的回复发送,以便它们 在接收端都连接在一起。像git和coilt这样的工具有命令,可以通过适当的线程发送 -一组补丁。但是,如果您有一个长系列,并且正在使用git,请远离–chain reply-to -选项,以避免创建异常深的嵌套。 +一组补丁。但是,如果您有一长串补丁,并正使用git,请不要使用–-chain-reply-to +选项,以避免创建过深的嵌套。 diff --git a/Documentation/translations/zh_CN/process/6.Followthrough.rst b/Documentation/translations/zh_CN/process/6.Followthrough.rst index f509e077e1cb08ebd549632499dc16c4a752c9e1..2a127e737b6a585b0a031e2c4fceb2a4e936eead 100644 --- a/Documentation/translations/zh_CN/process/6.Followthrough.rst +++ b/Documentation/translations/zh_CN/process/6.Followthrough.rst @@ -1,145 +1,152 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/6.Followthrough.rst <development_followthrough>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_followthrough: 跟进 ==== -在这一点上,您已经遵循了到目前为止给出的指导方针,并且,随着您自己的工程技能 -的增加,已经发布了一系列完美的补丁。即使是经验丰富的内核开发人员也能犯的最大 -错误之一是,认为他们的工作现在已经完成了。事实上,发布补丁意味着进入流程的下 -一个阶段,可能还需要做很多工作。 +此时,您已经遵循了到目前为止给出的指导方针,并且,随着您自己的工程技能的增加, +已经发布了一系列完美的补丁。即使是经验丰富的内核开发人员也能犯的最大错误之一 +是,认为他们的工作现在已经完成了。事实上,发布补丁意味着进入流程的下一个阶段, +可能还需要做很多工作。 -一个补丁在第一次发布时就非常出色,没有改进的余地,这是很罕见的。内核开发流程 -认识到这一事实,因此,它非常注重对已发布代码的改进。作为代码的作者,您应该与 +一个补丁在首次发布时就非常出色、没有改进的余地,这是很罕见的。内核开发流程已 +认识到这一事实,因此它非常注重对已发布代码的改进。作为代码的作者,您应该与 内核社区合作,以确保您的代码符合内核的质量标准。如果不参与这个过程,很可能会 -阻止将补丁包含到主线中。 +无法将补丁合并到主线中。 与审阅者合作 ------------ 任何意义上的补丁都会导致其他开发人员在审查代码时发表大量评论。对于许多开发 -人员来说,与审查人员合作可能是内核开发过程中最令人生畏的部分。但是,如果你 +人员来说,与审阅人员合作可能是内核开发过程中最令人生畏的部分。但是如果你 记住一些事情,生活会变得容易得多: - - 如果你已经很好地解释了你的补丁,评论人员会理解它的价值,以及为什么你会 - 费尽心思去写它。但是这个并不能阻止他们提出一个基本的问题:五年或十年后 - 用这个代码维护一个内核会是什么感觉?你可能被要求做出的许多改变——从编码风格 - 的调整到大量的重写——都来自于对Linux的理解,即从现在起十年后,Linux仍将在 - 开发中。 + - 如果你已经很好地解释了你的补丁,审阅人员会理解它的价值,以及为什么你会 + 费尽心思去写它。但是这个并不能阻止他们提出一个基本的问题:在五年或十年后 + 维护含有此代码的内核会怎么样?你可能被要求做出的许多改变——从编码风格的 + 调整到大量的重写——都来自于对Linux的理解,即从现在起十年后,Linux仍将 + 在开发中。 - 代码审查是一项艰苦的工作,这是一项相对吃力不讨好的工作;人们记得谁编写了 - 内核代码,但对于那些审查它的人来说,几乎没有什么持久的名声。因此,评论 + 内核代码,但对于那些审查它的人来说,几乎没有什么长久的名声。因此,审阅 人员可能会变得暴躁,尤其是当他们看到同样的错误被一遍又一遍地犯下时。如果 - 你得到了一个看起来愤怒、侮辱或完全冒犯你的评论,抵制以同样方式回应的冲动。 - 代码审查是关于代码的,而不是关于人的,代码审查人员不会亲自攻击您。 + 你得到了一个看起来愤怒、侮辱或完全冒犯你的评论,请抑制以同样方式回应的冲动。 + 代码审查是关于代码的,而不是关于人的,代码审阅人员不会亲自攻击您。 - - 同样,代码审查人员也不想以牺牲你雇主的利益为代价来宣传他们雇主的议程。 + - 同样,代码审阅人员也不想以牺牲你雇主的利益为代价来宣传他们雇主的议程。 内核开发人员通常希望今后几年能在内核上工作,但他们明白他们的雇主可能会改 变。他们真的,几乎毫无例外地,致力于创造他们所能做到的最好的内核;他们并 没有试图给雇主的竞争对手造成不适。 -所有这些归根结底都是,当审阅者向您发送评论时,您需要注意他们正在进行的技术 -观察。不要让他们的表达方式或你自己的骄傲阻止这种事情的发生。当你在一个补丁 -上得到评论时,花点时间去理解评论人想说什么。如果可能的话,请修复审阅者要求 -您修复的内容。然后回复审稿人:谢谢他们,并描述你将如何回答他们的问题。 +所有这些归根结底就是,当审阅者向您发送评论时,您需要注意他们正在进行的技术 +评论。不要让他们的表达方式或你自己的骄傲阻止此事。当你在一个补丁上得到评论 +时,花点时间去理解评论人想说什么。如果可能的话,请修复审阅者要求您修复的内 +容。然后回复审阅者:谢谢他们,并描述你将如何回答他们的问题。 请注意,您不必同意审阅者建议的每个更改。如果您认为审阅者误解了您的代码,请 解释到底发生了什么。如果您对建议的更改有技术上的异议,请描述它并证明您对该 -问题的解决方案是正确的。如果你的解释有道理,审稿人会接受的。不过,如果你的 -解释不能证明是有说服力的,尤其是当其他人开始同意审稿人的观点时,请花些时间 -重新考虑一下。你很容易对自己解决问题的方法视而不见,以至于你没有意识到某个 -问题根本是错误的,或者你甚至没有解决正确的问题。 +问题的解决方案是正确的。如果你的解释有道理,审阅者会接受的。不过,如果你的 +解释证明缺乏说服力,尤其是当其他人开始同意审稿人的观点时,请花些时间重新考虑 +一下。你很容易对自己解决问题的方法视而不见,以至于你没有意识到某些东西完全 +是错误的,或者你甚至没有解决正确的问题。 -Andrew Morton建议,每一条不会导致代码更改的评论都应该导致额外的代码注释; -这可以帮助未来的评论人员避免出现第一次出现的问题。 +Andrew Morton建议,每一个不会导致代码更改的审阅评论都应该产生一个额外的代码 +注释;这可以帮助未来的审阅人员避免第一次出现的问题。 -一个致命的错误是忽视评论,希望它们会消失。他们不会走的。如果您在没有对之前 -收到的注释做出响应的情况下重新发布代码,那么很可能会发现补丁毫无用处。 +一个致命的错误是忽视评论,希望它们会消失。它们不会走的。如果您在没有对之前 +收到的评论做出响应的情况下重新发布代码,那么很可能会发现补丁毫无用处。 说到重新发布代码:请记住,审阅者不会记住您上次发布的代码的所有细节。因此, -提醒审查人员以前提出的问题以及您如何处理这些问题总是一个好主意;补丁变更 +提醒审阅人员以前提出的问题以及您如何处理这些问题总是一个好主意;补丁变更 日志是提供此类信息的好地方。审阅者不必搜索列表档案来熟悉上次所说的内容; -如果您帮助他们开始运行,当他们重新访问您的代码时,他们的心情会更好。 +如果您帮助他们直接开始,当他们重新查看您的代码时,心情会更好。 如果你已经试着做正确的事情,但事情仍然没有进展呢?大多数技术上的分歧都可以 -通过讨论来解决,但有时人们只需要做出决定。如果你真的认为这个决定对你不利, -你可以试着向更高的权力上诉。在这篇文章中,更高的权力倾向于Andrew Morton。 -Andrew在内核开发社区中受i很大的尊重;他经常为似乎被绝望地阻塞事情清障。 -尽管如此,对Andrew的呼吁不应轻而易举,也不应在所有其他替代方案都被探索之前 -使用。当然,记住,他也可能不同意你的意见。 +通过讨论来解决,但有时人们仍需要做出决定。如果你真的认为这个决定对你不利, +你可以试着向有更高权力的人上诉。对于本文,更高权力的人是 Andrew Morton 。 +Andrew 在内核开发社区中非常受尊敬;他经常为似乎被绝望阻塞的事情清障。尽管 +如此,不应轻易就直接找 Andrew ,也不应在所有其他替代方案都被尝试之前找他。 +当然,记住,他也可能不同意你的意见。 接下来会发生什么 ---------------- -如果一个补丁被认为是添加到内核中的一件好事,并且一旦大多数审查问题得到解决, -下一步通常是进入子系统维护人员的树中。工作方式因子系统而异;每个维护人员都 -有自己的工作方式。特别是,可能有不止一棵树——一棵树,也许,专门用于计划下一 -个合并窗口的补丁,另一棵树用于长期工作。 +如果一个补丁被认为适合添加到内核中,并且大多数审查问题得到解决,下一步通常 +是进入子系统维护人员的树中。工作方式因子系统而异;每个维护人员都有自己的 +工作方式。特别是可能有不止一棵树——也许一棵树专门用于计划下一个合并窗口的 +补丁,另一棵树用于长期工作。 -对于应用于没有明显子系统树(例如内存管理修补程序)的区域的修补程序,默认树 -通常以-mm结尾。影响多个子系统的补丁也可以最终通过-mm树。 +对于应用到不属于明显子系统树(例如内存管理修补程序)的区域的修补程序,默认树 +通常上溯到-mm。影响多个子系统的补丁也可以最终进入-mm树。 包含在子系统树中可以提高补丁的可见性。现在,使用该树的其他开发人员将默认获 得补丁。子系统树通常也为Linux提供支持,使其内容对整个开发社区可见。在这一点 上,您很可能会从一组新的审阅者那里得到更多的评论;这些评论需要像上一轮那样 -得到回答。 +得到回应。 -在这一点上也会发生什么,这取决于你的补丁的性质,是与其他人正在做的工作发生 +在这时也会发生点什么,这取决于你的补丁的性质,是否与其他人正在做的工作发生 冲突。在最坏的情况下,严重的补丁冲突可能会导致一些工作被搁置,以便剩余的补丁 可以成形并合并。另一些时候,冲突解决将涉及到与其他开发人员合作,可能还会 在树之间移动一些补丁,以确保所有的应用都是干净的。这项工作可能是一件痛苦的 -事情,但要计算您的福祉:在Linux下一棵树出现之前,这些冲突通常只在合并窗口 -中出现,必须迅速解决。现在可以在合并窗口打开之前,在空闲时解决这些问题。 +事情,但也需庆幸现在的幸福:在linux-next树出现之前,这些冲突通常只在合并窗口 +中出现,必须迅速解决。现在可以在合并窗口打开之前的空闲时间解决这些问题。 有朝一日,如果一切顺利,您将登录并看到您的补丁已经合并到主线内核中。祝贺你! -然而,一旦庆祝活动完成(并且您已经将自己添加到维护人员文件中),就值得记住 -一个重要的小事实:工作仍然没有完成。并入主线带来了自身的挑战。 +然而,一旦庆祝完了(并且您已经将自己添加到维护人员文件中),就一定要记住 +一个重要的小事实:工作仍然没有完成。并入主线也带来了它的挑战。 -首先,补丁的可见性再次提高。可能会有新一轮的开发者评论,他们以前不知道这 -个补丁。忽略它们可能很有诱惑力,因为您的代码不再存在任何被合并的问题。但是, -要抵制这种诱惑,您仍然需要对有问题或建议的开发人员作出响应。 +首先,补丁的可见性再次提高。可能会有以前不知道这个补丁的开发者的新一轮评论。 +忽略它们可能很有诱惑力,因为您的代码不再存在任何被合并的问题。但是,要抵制 +这种诱惑,您仍然需要对有问题或建议的开发人员作出响应。 -不过,更重要的是:将代码包含在主线中会将代码交给更大的一组测试人员。即使您 -为尚未提供的硬件提供了驱动程序,您也会惊讶于有多少人会将您的代码构建到内核 -中。当然,如果有测试人员,也会有错误报告。 +不过,更重要的是:将代码包含在主线中会将代码交给更多的一些测试人员。即使您 +为尚未可用的硬件提供了驱动程序,您也会惊讶于有多少人会将您的代码构建到内核 +中。当然,如果有测试人员,也可能会有错误报告。 -最糟糕的错误报告是回归。如果你的补丁导致回归,你会发现很多不舒服的眼睛盯着 -你;回归需要尽快修复。如果您不愿意或无法修复回归(其他人都不会为您修复), +最糟糕的错误报告是回归。如果你的补丁导致回归,你会发现多到让你不舒服的眼睛盯 +着你;回归需要尽快修复。如果您不愿意或无法修复回归(其他人都不会为您修复), 那么在稳定期内,您的补丁几乎肯定会被移除。除了否定您为使补丁进入主线所做的 -所有工作之外,如果由于未能修复回归而取消补丁,很可能会使将来的工作更难合并。 +所有工作之外,如果由于未能修复回归而取消补丁,很可能会使将来的工作更难被合并。 -在处理完任何回归之后,可能还有其他普通的bug需要处理。稳定期是修复这些错误并 -确保代码在主线内核版本中的首次发布尽可能可靠的最好机会。所以,请回答错误 +在处理完任何回归之后,可能还有其他普通缺陷需要处理。稳定期是修复这些错误并 +确保代码在主线内核版本中的首次发布尽可能可靠的最好机会。所以,请回应错误 报告,并尽可能解决问题。这就是稳定期的目的;一旦解决了旧补丁的任何问题,就 -可以开始创建酷的新补丁。 +可以开始尽情创建新补丁。 -别忘了,还有其他里程碑也可能会创建bug报告:下一个主线稳定版本,当著名的发行 -商选择包含补丁的内核版本时,等等。继续响应这些报告是您工作的基本骄傲。但是, -如果这不是足够的动机,那么也值得考虑的是,开发社区会记住那些在合并后对代码 -失去兴趣的开发人员。下一次你发布补丁时,他们会以你以后不会在身边维护它为假 -设来评估它。 +别忘了,还有其他节点也可能会创建缺陷报告:下一个主线稳定版本,当著名的发行 +商选择包含您补丁的内核版本时等等。继续响应这些报告是您工作的基本素养。但是 +如果这不能提供足够的动机,那么也需要考虑:开发社区会记住那些在合并后对代码 +失去兴趣的开发人员。下一次你发布补丁时,他们会以你以后不会持续维护它为前提 +来评估它。 其他可能发生的事情 ------------------ -有一天,你可以打开你的邮件客户端,看到有人给你寄了一个代码补丁。毕竟,这是 +某天,当你打开你的邮件客户端时,看到有人给你寄了一个代码补丁。毕竟,这是 让您的代码公开存在的好处之一。如果您同意这个补丁,您可以将它转发给子系统 -维护人员(确保包含一个正确的From:行,这样属性是正确的,并添加一个您自己 -的签准),或者回复一个Acked-by,让原始发送者向上发送它。 +维护人员(确保包含一个正确的From:行,这样属性是正确的,并添加一个您自己的 +signoff ),或者回复一个 Acked-by: 让原始发送者向上发送它。 -如果您不同意补丁,请发送一个礼貌的回复,解释原因。如果可能的话,告诉作者需要 -做哪些更改才能让您接受补丁。对于代码的编写者和维护者所反对的合并补丁,存在着 -一定的阻力,但仅此而已。如果你被认为不必要的阻碍了好的工作,那么这些补丁最 -终会经过你身边并进入主线。在Linux内核中,没有人对任何代码拥有绝对的否决权。 -除了Linus。 +如果您不同意补丁,请礼貌地回复,解释原因。如果可能的话,告诉作者需要做哪些 +更改才能让您接受补丁。合并代码的编写者和维护者所反对的补丁的确存在着一定的 +阻力,但仅此而已。如果你被认为不必要的阻碍了好的工作,那么这些补丁最终会 +绕过你并进入主线。在Linux内核中,没有人对任何代码拥有绝对的否决权。可能除 +了Linus。 在非常罕见的情况下,您可能会看到完全不同的东西:另一个开发人员发布了针对您 -的问题的不同解决方案。在这一点上,两个补丁中的一个可能不会合并,“我的在这里 -是第一个”不被认为是一个令人信服的技术论据。如果有人的补丁取代了你的补丁而进 -入了主线,那么只有一种方法可以回应你:高兴你的问题得到解决,继续你的工作。 -以这种方式把一个人的工作推到一边可能会伤害和气馁,但是在他们忘记了谁的补丁 -真正被合并很久之后,社区会记住你的反应。 +的问题的不同解决方案。在这时,两个补丁之一可能不会被合并,“我的补丁首先 +发布”不被认为是一个令人信服的技术论据。如果有别人的补丁取代了你的补丁而进 +入了主线,那么只有一种方法可以回应你:很高兴你的问题解决了,请继续工作吧。 +以这种方式把某人的工作推到一边可能导致伤心和气馁,但是社区会记住你的反应, +即使很久以后他们已经忘记了谁的补丁真正被合并。 diff --git a/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst b/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst index 2f0ef750746f385f6022620a9c8b9e57e9ef62b0..6d0dadae13b12ad1fa3313e5de468b202db480a3 100644 --- a/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst +++ b/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst @@ -1,7 +1,14 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/7.AdvancedTopics.rst <development_advancedtopics>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> + +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_advancedtopics: @@ -15,110 +22,112 @@ --------------- 内核使用分布式版本控制始于2002年初,当时Linus首次开始使用专有的Bitkeeper应用 -程序。虽然bitkeeper存在争议,但它所体现的软件版本管理方法却肯定不是。分布式 -版本控制可以立即加速内核开发项目。在当前的时代,有几种免费的比特保持器替代品。 -无论好坏,内核项目都将Git作为其选择的工具。 +程序。虽然BitKeeper存在争议,但它所体现的软件版本管理方法却肯定不是。分布式 +版本控制可以立即加速内核开发项目。现在有好几种免费的BitKeeper替代品。 +但无论好坏,内核项目都已经选择了Git作为其工具。 -使用Git管理补丁可以使开发人员的生活更加轻松,尤其是随着补丁数量的增加。Git -也有其粗糙的边缘和一定的危险,它是一个年轻和强大的工具,仍然在其开发人员完善 +使用Git管理补丁可以使开发人员的生活更加轻松,尤其是随着补丁数量的增长。Git也 +有其粗糙的边角和一定的危险性,它是一个年轻和强大的工具,仍然在其开发人员完善 中。本文档不会试图教会读者如何使用git;这会是个巨长的文档。相反,这里的重点 -将是Git如何特别适合内核开发过程。想要加快Git的开发人员可以在以下网站上找到 -更多信息: +将是Git如何特别适合内核开发过程。想要加快用Git速度的开发人员可以在以下网站上 +找到更多信息: https://git-scm.com/ https://www.kernel.org/pub/software/scm/git/docs/user-manual.html -在尝试使用它使补丁可供其他人使用之前,第一要务是阅读上述站点,对Git的工作 -方式有一个扎实的了解。使用Git的开发人员应该能够获得主线存储库的副本,探索 -修订历史,提交对树的更改,使用分支等。了解Git用于重写历史的工具(如Rebase) -也很有用。Git有自己的术语和概念;Git的新用户应该了解refs、远程分支、索引、 -快进合并、推拉、分离头等。一开始可能有点吓人,但这些概念不难通过一点学习来 +同时网上也能找到各种各样的教程。 + +在尝试使用它生成补丁供他人使用之前,第一要务是阅读上述网页,对Git的工作方式 +有一个扎实的了解。使用Git的开发人员应能进行拉取主线存储库的副本,查询修订 +历史,提交对树的更改,使用分支等操作。了解Git用于重写历史的工具(如rebase) +也很有用。Git有自己的术语和概念;Git的新用户应该了解引用、远程分支、索引、 +快进合并、推拉、游离头等。一开始可能有点吓人,但这些概念不难通过一点学习来 理解。 使用git生成通过电子邮件提交的补丁是提高速度的一个很好的练习。 -当您准备好开始安装Git树供其他人查看时,您当然需要一个可以从中提取的服务器。 -如果您有一个可以访问Internet的系统,那么使用git守护进程设置这样的服务器相 -对简单。否则,免费的公共托管网站(例如github)开始出现在网络上。成熟的开发 -人员可以在kernel.org上获得一个帐户,但这些帐户并不容易找到;有关更多信息, -请参阅 https://kernel.org/faq/ +当您准备好开始建立Git树供其他人查看时,无疑需要一个可以从中拉取的服务器。 +如果您有一个可以访问因特网的系统,那么使用git-daemon设置这样的服务器相对 +简单。同时,免费的公共托管网站(例如github)也开始出现在网络上。成熟的开发 +人员可以在kernel.org上获得一个帐户,但这些帐户并不容易得到;更多有关信息, +请参阅 https://kernel.org/faq/ 。 正常的Git工作流程涉及到许多分支的使用。每一条开发线都可以分为单独的“主题 -分支”,并独立维护。Git的分支机构很便宜,没有理由不免费使用它们。而且,在 -任何情况下,您都不应该在任何您打算让其他人从中受益的分支中进行开发。应该 -小心地创建公开可用的分支;当它们处于完整的形式并准备好运行时(而不是之前), -合并开发分支的补丁。 +分支”,并独立维护。Git的分支很容易使用,没有理由不使用它们。而且,在任何 +情况下,您都不应该在任何您打算让其他人从中拉取的分支中进行开发。应该小心地 +创建公开可用的分支;当开发分支处于完整状态并已准备好时(而不是之前)才合并 +开发分支的补丁。 Git提供了一些强大的工具,可以让您重写开发历史。一个不方便的补丁(比如说, 一个打破二分法的补丁,或者有其他一些明显的缺陷)可以在适当的位置修复,或者 -完全从历史中消失。一个补丁系列可以被重写,就好像它是在今天的主线之上写的 -一样,即使你已经花了几个月的时间在写它。可以透明地将更改从一个分支转移到另 -一个分支。等等。明智地使用git修改历史的能力可以帮助创建问题更少的干净补丁集。 +完全从历史中消失。一个补丁系列可以被重写,就好像它是在今天的主线上写的一样, +即使你已经花了几个月的时间在写它。可以透明地将更改从一个分支转移到另一个 +分支。等等。明智地使用git修改历史的能力可以帮助创建问题更少的干净补丁集。 -然而,过度使用这种能力可能会导致其他问题,而不仅仅是对创建完美项目历史的 -简单痴迷。重写历史将重写该历史中包含的更改,将经过测试(希望)的内核树变 -为未经测试的内核树。但是,除此之外,如果开发人员没有对项目历史的共享视图, -他们就无法轻松地协作;如果您重写了其他开发人员拉入他们存储库的历史,您将 -使这些开发人员的生活更加困难。因此,这里有一个简单的经验法则:被导出到其他 -人的历史在此后通常被认为是不可变的。 +然而,过度使用这种功能可能会导致其他问题,而不仅仅是对创建完美项目历史的 +简单痴迷。重写历史将重写该历史中包含的更改,将经过测试(希望如此)的内核树 +变为未经测试的内核树。除此之外,如果开发人员没有共享项目历史,他们就无法 +轻松地协作;如果您重写了其他开发人员拉入他们存储库的历史,您将使这些开发 +人员的生活更加困难。因此,这里有一个简单的经验法则:被导出到其他地方的历史 +在此后通常被认为是不可变的。 因此,一旦将一组更改推送到公开可用的服务器上,就不应该重写这些更改。如果您 -尝试强制进行不会导致快进合并(即不共享同一历史记录的更改)的更改,Git将尝 -试强制执行此规则。可以重写此检查,有时可能需要重写导出的树。在树之间移动变 -更集以避免Linux-next中的冲突就是一个例子。但这种行为应该是罕见的。这就是为 -什么开发应该在私有分支中进行(必要时可以重写)并且只有在公共分支处于合理的 -高级状态时才转移到公共分支中的原因之一。 +尝试强制进行无法快进合并的更改(即不共享同一历史记录的更改),Git将尝试强制 +执行此规则。这可能覆盖检查,有时甚至需要重写导出的树。在树之间移动变更集以 +避免linux-next中的冲突就是一个例子。但这种行为应该是罕见的。这就是为什么 +开发应该在私有分支中进行(必要时可以重写)并且只有在公共分支处于合理的较新 +状态时才转移到公共分支中的原因之一。 当主线(或其他一组变更所基于的树)前进时,很容易与该树合并以保持领先地位。 对于一个私有的分支,rebasing 可能是一个很容易跟上另一棵树的方法,但是一旦 -一棵树被导出到全世界,rebasing就不是一个选项。一旦发生这种情况,就必须进行 -完全合并(merge)。合并有时是很有意义的,但是过于频繁的合并会不必要地扰乱 -历史。在这种情况下,建议的技术是不经常合并,通常只在特定的发布点(如主线-rc -发布)合并。如果您对特定的更改感到紧张,则可以始终在私有分支中执行测试合并。 -在这种情况下,git rerere 工具很有用;它记住合并冲突是如何解决的,这样您就 -不必重复相同的工作。 +一棵树被导出到外界,rebasing就不可取了。一旦发生这种情况,就必须进行完全 +合并(merge)。合并有时是很有意义的,但是过于频繁的合并会不必要地扰乱历史。 +在这种情况下建议的做法是不要频繁合并,通常只在特定的发布点(如主线-rc发布) +合并。如果您对特定的更改感到紧张,则可以始终在私有分支中执行测试合并。在 +这种情况下,git“rerere”工具很有用;它能记住合并冲突是如何解决的,这样您 +就不必重复相同的工作。 关于Git这样的工具的一个最大的反复抱怨是:补丁从一个存储库到另一个存储库的 大量移动使得很容易陷入错误建议的变更中,这些变更避开审查雷达进入主线。当内 -核开发人员看到这种情况发生时,他们往往会感到不高兴;在Git树上放置未查看或 -主题外的补丁可能会影响您将来获取树的能力。引用Linus: +核开发人员看到这种情况发生时,他们往往会感到不高兴;在Git树上放置未审阅或 +主题外的补丁可能会影响您将来让树被拉取的能力。引用Linus的话: :: - 你可以给我发补丁,但要我从你哪里取一个Git补丁,我需要知道你知道 - 你在做什么,我需要能够相信事情而不去检查每个个人改变。 + 你可以给我发补丁,但当我从你那里拉取一个Git补丁时,我需要知道你清楚 + 自己在做什么,我需要能够相信事情而 *无需* 手动检查每个单独的更改。 (http://lwn.net/articles/224135/)。 为了避免这种情况,请确保给定分支中的所有补丁都与相关主题紧密相关;“驱动程序 修复”分支不应更改核心内存管理代码。而且,最重要的是,不要使用Git树来绕过 -审查过程。不时的将树的摘要发布到相关的列表中,当时间合适时,请求 -Linux-next 中包含该树。 +审查过程。不时的将树的摘要发布到相关的列表中,在合适时候请求linux-next中 +包含该树。 -如果其他人开始发送补丁以包含到您的树中,不要忘记查看它们。还要确保您维护正确 -的作者信息; ``git am`` 工具在这方面做得最好,但是如果它通过第三方转发给您, -您可能需要在补丁中添加“From:”行。 +如果其他人开始发送补丁以包含到您的树中,不要忘记审阅它们。还要确保您维护正确 +的作者信息; git “am”工具在这方面做得最好,但是如果补丁通过第三方转发给您, +您可能需要在补丁中添加“From:”行。 -请求pull操作时,请务必提供所有相关信息:树的位置、要拉的分支以及拉操作将导致 -的更改。在这方面,git request pull 命令非常有用;它将按照其他开发人员的预期 -格式化请求,并检查以确保您记住了将这些更改推送到公共服务器。 +请求拉取时,请务必提供所有相关信息:树的位置、要拉取的分支以及拉取将导致的 +更改。在这方面 git request-pull 命令非常有用;它将按照其他开发人员所期望的 +格式化请求,并检查以确保您已记得将这些更改推送到公共服务器。 -审查补丁 +审阅补丁 -------- -一些读者当然会反对将本节与“高级主题”放在一起,因为即使是刚开始的内核开发人员 -也应该检查补丁。当然,学习如何在内核环境中编程没有比查看其他人发布的代码更好 -的方法了。此外,审阅者永远供不应求;通过查看代码,您可以对整个流程做出重大贡献。 +一些读者显然会反对将本节与“高级主题”放在一起,因为即使是刚开始的内核开发人员 +也应该审阅补丁。当然,没有比查看其他人发布的代码更好的方法来学习如何在内核环境 +中编程了。此外,审阅者永远供不应求;通过审阅代码,您可以对整个流程做出重大贡献。 -审查代码可能是一个令人生畏的前景,特别是对于一个新的内核开发人员来说,他们 +审查代码可能是一副令人生畏的图景,特别是对一个新的内核开发人员来说,他们 可能会对公开询问代码感到紧张,而这些代码是由那些有更多经验的人发布的。不过, -即使是最有经验的开发人员编写的代码也可以得到改进。也许对评审员(所有评审员) -最好的建议是:把评审评论当成问题而不是批评。询问“在这条路径中如何释放锁?” +即使是最有经验的开发人员编写的代码也可以得到改进。也许对(所有)审阅者最好 +的建议是:把审阅评论当成问题而不是批评。询问“在这条路径中如何释放锁?” 总是比说“这里的锁是错误的”更好。 -不同的开发人员将从不同的角度审查代码。一些主要关注的是编码样式以及代码行是 -否有尾随空格。其他人将主要关注补丁作为一个整体实现的变更是否对内核有好处。 -然而,其他人会检查是否存在锁定问题、堆栈使用过度、可能的安全问题、在其他 -地方发现的代码重复、足够的文档、对性能的不利影响、用户空间ABI更改等。所有 -类型的检查,如果它们导致更好的代码进入内核,都是受欢迎和值得的。 +不同的开发人员将从不同的角度审查代码。部分人会主要关注代码风格以及代码行是 +否有尾随空格。其他人会主要关注补丁作为一个整体实现的变更是否对内核有好处。 +同时也有人会检查是否存在锁问题、堆栈使用过度、可能的安全问题、在其他地方 +发现的代码重复、足够的文档、对性能的不利影响、用户空间ABI更改等。所有类型 +的检查,只要它们能引导更好的代码进入内核,都是受欢迎和值得的。 diff --git a/Documentation/translations/zh_CN/process/8.Conclusion.rst b/Documentation/translations/zh_CN/process/8.Conclusion.rst index 90cec3de610673cff765f42ee9f0f8b5004eaeac..71c3e30efc6f8a5d9420ba506ae26580247d4ce6 100644 --- a/Documentation/translations/zh_CN/process/8.Conclusion.rst +++ b/Documentation/translations/zh_CN/process/8.Conclusion.rst @@ -1,7 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: :ref:`Documentation/process/8.Conclusion.rst <development_conclusion>` -:Translator: Alex Shi <alex.shi@linux.alibaba.com> +:Translator: + + 时奎亮 Alex Shi <alex.shi@linux.alibaba.com> + +:校译: + + 吴想成 Wu XiangCheng <bobwxc@email.cn> .. _cn_development_conclusion: @@ -9,56 +15,56 @@ ======== 关于Linux内核开发和相关主题的信息来源很多。首先是在内核源代码分发中找到的 -文档目录。顶级 :ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>` -文件是一个重要的起点 +文档目录。顶级 +:ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>` +文件是一个重要的起点; :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>` -和 :ref:`process/submitting-drivers.rst <submittingdrivers>` +和 :ref:`Documentation/transaltions/zh_CN/process/submitting-drivers.rst <cn_submittingdrivers>` 也是所有内核开发人员都应该阅读的内容。许多内部内核API都是使用kerneldoc机制 -记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档( -尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。 +记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档 +(尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。 -不同的网站在各个细节层次上讨论内核开发。您的作者想谦虚地建议用 https://lwn.net/ -作为来源;有关许多特定内核主题的信息可以通过以下网址的lwn内核索引找到: +不同的网站在各个细节层次上讨论内核开发。本文作者想谦虚地建议用 https://lwn.net/ +作为来源;有关许多特定内核主题的信息可以通过以下网址的 LWN 内核索引找到: - http://lwn.net/kernel/index/ + http://lwn.net/kernel/index/ 除此之外,内核开发人员的一个宝贵资源是: - https://kernelnewbies.org/ + https://kernelnewbies.org/ -当然,我们不应该忘记 https://kernel.org/ 这是内核发布信息的最终位置。 +当然,也不应该忘记 https://kernel.org/ ,这是内核发布信息的最终位置。 关于内核开发有很多书: - Linux设备驱动程序,第三版(Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman)。 - 在线:http://lwn.net/kernel/ldd3/ + 《Linux设备驱动程序》第三版(Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman) + 线上版本在 http://lwn.net/kernel/ldd3/ - Linux内核开发(Robert Love)。 + 《Linux内核设计与实现》(Robert Love) - 了解Linux内核(Daniel Bovet和Marco Cesati)。 + 《深入理解Linux内核》(Daniel Bovet和Marco Cesati) -然而,所有这些书都有一个共同的缺点:当它们上架时,它们往往有些过时,而且它们 -已经上架一段时间了。不过,在那里还可以找到相当多的好信息。 +然而,所有这些书都有一个共同的缺点:它们上架时就往往有些过时,而且已经上架 +一段时间了。不过,在那里还是可以找到相当多的好信息。 有关git的文档,请访问: - https://www.kernel.org/pub/software/scm/git/docs/ + https://www.kernel.org/pub/software/scm/git/docs/ - https://www.kernel.org/pub/software/scm/git/docs/user-manual.html + https://www.kernel.org/pub/software/scm/git/docs/user-manual.html 结论 ==== -祝贺所有通过这篇冗长的文件的人。希望它能够帮助您理解Linux内核是如何开发的, +祝贺所有通过这篇冗长的文档的人。希望它能够帮助您理解Linux内核是如何开发的, 以及您如何参与这个过程。 -最后,重要的是参与。任何开源软件项目都不超过其贡献者投入其中的总和。Linux内核 -的发展速度和以前一样快,因为它得到了大量开发人员的帮助,他们都在努力使它变得 -更好。内核是一个主要的例子,说明当成千上万的人为了一个共同的目标一起工作时, -可以做些什么。 +最后,重要的是参与。任何开源软件项目都不会超过其贡献者投入其中的总和。Linux +内核的发展速度和以前一样快,因为它得到了大量开发人员的帮助,他们都在努力使它 +变得更好。内核是一个最成功的例子,说明了当成千上万的人为了一个共同的目标一起 +工作时,可以做出什么。 -不过,内核总是可以从更大的开发人员基础中获益。总有更多的工作要做。但是,同样 +不过,内核总是可以从更大的开发人员基础中获益。总有更多的工作要做。但是同样 重要的是,Linux生态系统中的大多数其他参与者可以通过为内核做出贡献而受益。使 代码进入主线是提高代码质量、降低维护和分发成本、提高对内核开发方向的影响程度 -等的关键。这是一种人人都赢的局面。踢开你的编辑,来加入我们吧,你会非常受 -欢迎的。 +等的关键。这是一种共赢的局面。启动你的编辑器,来加入我们吧;你会非常受欢迎的。 diff --git a/Documentation/translations/zh_CN/process/index.rst b/Documentation/translations/zh_CN/process/index.rst index 8051a7b322c53256bbefd2ea7185567c33046868..39e9c88fbaa602f6a81395d21cada78802df69c1 100644 --- a/Documentation/translations/zh_CN/process/index.rst +++ b/Documentation/translations/zh_CN/process/index.rst @@ -13,11 +13,11 @@ 与Linux 内核社区一起工作 ======================== -那么你想成为Linux内核开发人员? 欢迎! 不但从技术意义上讲有很多关于内核的知识 -需要学,而且了解我们社区的工作方式也很重要。 阅读这些文章可以让您以更轻松地, -麻烦最少的方式将更改合并到内核。 +你想成为Linux内核开发人员吗?欢迎之至!在学习许多关于内核的技术知识的同时, +了解我们社区的工作方式也很重要。阅读这些文档可以让您以更轻松的、麻烦更少的 +方式将更改合并到内核。 -以下是每位开发人员应阅读的基本指南。 +以下是每位开发人员都应阅读的基本指南: .. toctree:: :maxdepth: 1 @@ -47,7 +47,7 @@ management-style embargoed-hardware-issues -这些是一些总体技术指南,由于缺乏更好的地方,现在已经放在这里 +这些是一些总体性技术指南,由于不大好分类而放在这里: .. toctree:: :maxdepth: 1 diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 7bb9d4165ed3e4a5996fc6b135d8eb6e6bcd09c7..42f0635ca70a54ba803cdd2a15b1e5847c000b18 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -62,12 +62,10 @@ CMAGIC 0x0111 user ``include/linux/ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h`` DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h`` PTY_MAGIC 0x5001 ``drivers/char/pty.c`` PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` @@ -79,14 +77,12 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h`` LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h`` RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` diff --git a/Documentation/translations/zh_CN/process/submit-checklist.rst b/Documentation/translations/zh_CN/process/submit-checklist.rst index 50386e0e42e7fd6a629e612c5743771efa2de24c..a64858d321fcdc6ce9496ffc441e2777d3567201 100644 --- a/Documentation/translations/zh_CN/process/submit-checklist.rst +++ b/Documentation/translations/zh_CN/process/submit-checklist.rst @@ -82,24 +82,22 @@ Linux内核补丁提交清单 请参阅 ``Documentation/ABI/README`` 。更改用户空间接口的补丁应该抄送 linux-api@vger.kernel.org。 -20) 检查是否全部通过 ``make headers_check`` 。 - -21) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/`` +20) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/`` 如果新代码是实质性的,那么添加子系统特定的故障注入可能是合适的。 -22) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这 +21) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这 将产生大量噪声,但对于查找诸如“警告:有符号和无符号之间的比较”之类的错误 很有用。 -23) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以 +22) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以 及VM、VFS和其他子系统中的各种更改一起工作。 -24) 所有内存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要源代码中的注 +23) 所有内存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要源代码中的注 释来解释它们正在执行的操作及其原因的逻辑。 -25) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/userspace-api/ioctl/ioctl-number.rst`` +24) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/userspace-api/ioctl/ioctl-number.rst`` -26) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或 +25) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或 功能,则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` (如果该选项可用)的情况 下测试以下多个构建[并非所有这些都同时存在,只是它们的各种/随机组合]: diff --git a/Documentation/translations/zh_CN/riscv/boot-image-header.rst b/Documentation/translations/zh_CN/riscv/boot-image-header.rst new file mode 100644 index 0000000000000000000000000000000000000000..241bf9c1bcbe7d881434afdc4cb64210cdb653d2 --- /dev/null +++ b/Documentation/translations/zh_CN/riscv/boot-image-header.rst @@ -0,0 +1,67 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../riscv/boot-image-header` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_boot-image-header.rst: + + +========================== +RISC-V Linux启动镜像文件头 +========================== + +:Author: Atish Patra <atish.patra@wdc.com> +:Date: 20 May 2019 + +此文档仅描述RISC-V Linux 启动文件头的详情。 + +TODO: + 写一个完整的启动指南。 + +在解压后的Linux内核镜像中存在以下64字节的文件头:: + + u32 code0; /* Executable code */ + u32 code1; /* Executable code */ + u64 text_offset; /* Image load offset, little endian */ + u64 image_size; /* Effective Image size, little endian */ + u64 flags; /* kernel flags, little endian */ + u32 version; /* Version of this header */ + u32 res1 = 0; /* Reserved */ + u64 res2 = 0; /* Reserved */ + u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */ + u32 magic2 = 0x05435352; /* Magic number 2, little endian, "RSC\x05" */ + u32 res3; /* Reserved for PE COFF offset */ + +这种头格式与PE/COFF文件头兼容,并在很大程度上受到ARM64文件头的启发。因此,ARM64 +和RISC-V文件头可以在未来合并为一个共同的头。 + +注意 +==== + +- 将来也可以复用这个文件头,用来对RISC-V的EFI桩提供支持。为了使内核镜像如同一个 + EFI应用程序一样加载,EFI规范中规定在内核镜像的开始需要PE/COFF镜像文件头。为了 + 支持EFI桩,应该用“MZ”魔术字符替换掉code0,并且res3(偏移量未0x3c)应指向PE/COFF + 文件头的其余部分. + +- 表示文件头版本号的Drop-bit位域 + + ========== ========== + Bits 0:15 次要 版本 + Bits 16:31 主要 版本 + ========== ========== + + 这保持了新旧版本之间的兼容性。 + 当前版本被定义为0.2。 + +- 从版本0.2开始,结构体成员“magic”就已经被弃用,在之后的版本中,可能会移除掉它。 + 最初,该成员应该与ARM64头的“magic”成员匹配,但遗憾的是并没有。 + “magic2”成员代替“magic”成员与ARM64头相匹配。 + +- 在当前的文件头,标志位域只剩下了一个位。 + + ===== ============================== + Bit 0 内核字节序。1 if BE, 0 if LE. + ===== ============================== + +- 对于引导加载程序加载内核映像来说,image_size成员对引导加载程序而言是必须的,否 + 则将引导失败。 diff --git a/Documentation/translations/zh_CN/riscv/index.rst b/Documentation/translations/zh_CN/riscv/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..db13b1101490cf54aa0864cd902d065263027c20 --- /dev/null +++ b/Documentation/translations/zh_CN/riscv/index.rst @@ -0,0 +1,28 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../riscv/index` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_riscv_index: + + +=============== +RISC-V 体系结构 +=============== + +.. toctree:: + :maxdepth: 1 + + boot-image-header + pmu + patch-acceptance + + +.. only:: subproject and html + + 目录 + ==== + + * :ref:`genindex` diff --git a/Documentation/translations/zh_CN/riscv/patch-acceptance.rst b/Documentation/translations/zh_CN/riscv/patch-acceptance.rst new file mode 100644 index 0000000000000000000000000000000000000000..9fd1c8216763f148e169706075f39ec4f625bed3 --- /dev/null +++ b/Documentation/translations/zh_CN/riscv/patch-acceptance.rst @@ -0,0 +1,31 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../riscv/patch-acceptance` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_riscv_patch-acceptance: + + +arch/riscv 开发者维护指南 +========================= + +概述 +---- +RISC-V指令集体系结构是公开开发的: +正在进行的草案可供所有人查看和测试实现。新模块或者扩展草案可能会在开发过程中发 +生更改---有时以不兼容的方式对以前的草案进行更改。这种灵活性可能会给RISC-V Linux +维护者带来挑战。Linux开发过程更喜欢经过良好检查和测试的代码,而不是试验代码。我 +们希望推广同样的规则到即将被内核合并的RISC-V相关代码。 + +附加的提交检查单 +---------------- +我们仅接受相关标准已经被RISC-V基金会标准为“已批准”或“已冻结”的扩展或模块的补丁。 +(开发者当然可以维护自己的Linux内核树,其中包含所需代码扩展草案的代码。) + +此外,RISC-V规范允许爱好者创建自己的自定义扩展。这些自定义拓展不需要通过RISC-V +基金会的任何审核或批准。为了避免将爱好者一些特别的RISC-V拓展添加进内核代码带来 +的维护复杂性和对性能的潜在影响,我们将只接受RISC-V基金会正式冻结或批准的的扩展 +补丁。(开发者当然可以维护自己的Linux内核树,其中包含他们想要的任何自定义扩展 +的代码。) diff --git a/Documentation/translations/zh_CN/riscv/pmu.rst b/Documentation/translations/zh_CN/riscv/pmu.rst new file mode 100644 index 0000000000000000000000000000000000000000..22dcf3a9ca6eec76aa76d5aa42af721263bcc1d4 --- /dev/null +++ b/Documentation/translations/zh_CN/riscv/pmu.rst @@ -0,0 +1,233 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../riscv/pmu` +:Translator: Yanteng Si <siyanteng@loongson.cn> + +.. _cn_riscv_pmu: + + +======================== +RISC-V平台上对PMUs的支持 +======================== + +Alan Kao <alankao@andestech.com>, Mar 2018 + +简介 +------------ + +截止本文撰写时,在The RISC-V ISA Privileged Version 1.10中提到的 perf_event +相关特性如下: +(详情请查阅手册) + +* [m|s]counteren +* mcycle[h], cycle[h] +* minstret[h], instret[h] +* mhpeventx, mhpcounterx[h] + +仅有以上这些功能,移植perf需要做很多工作,究其原因是缺少以下通用架构的性能 +监测特性: + +* 启用/停用计数器 + 在我们这里,计数器一直在自由运行。 +* 计数器溢出引起的中断 + 规范中没有这种功能。 +* 中断指示器 + 不可能所有的计数器都有很多的中断端口,所以需要一个中断指示器让软件来判断 + 哪个计数器刚好溢出。 +* 写入计数器 + 由于内核不能修改计数器,所以会有一个SBI来支持这个功能[1]。 另外,一些厂商 + 考虑实现M-S-U型号机器的硬件扩展来直接写入计数器。 + +这篇文档旨在为开发者提供一个在内核中支持PMU的简要指南。下面的章节简要解释了 +perf' 机制和待办事项。 + +你可以在这里查看以前的讨论[1][2]。 另外,查看附录中的相关内核结构体可能会有 +帮助。 + + +1. 初始化 +--------- + +*riscv_pmu* 是一个类型为 *struct riscv_pmu* 的全局指针,它包含了根据perf内部 +约定的各种方法和PMU-specific参数。人们应该声明这样的实例来代表PMU。 默认情况 +下, *riscv_pmu* 指向一个常量结构体 *riscv_base_pmu* ,它对基准QEMU模型有非常 +基础的支持。 + + +然后他/她可以将实例的指针分配给 *riscv_pmu* ,这样就可以利用已经实现的最小逻 +辑,或者创建他/她自己的 *riscv_init_platform_pmu* 实现。 + +换句话说,现有的 *riscv_base_pmu* 源只是提供了一个参考实现。 开发者可以灵活地 +决定多少部分可用,在最极端的情况下,他们可以根据自己的需要定制每一个函数。 + + +2. Event Initialization +----------------------- + +当用户启动perf命令来监控一些事件时,首先会被用户空间的perf工具解释为多个 +*perf_event_open* 系统调用,然后进一步调用上一步分配的 *event_init* 成员函数 +的主体。 在 *riscv_base_pmu* 的情况下,就是 *riscv_event_init* 。 + +该功能的主要目的是将用户提供的事件翻译成映射图,从而可以直接对HW-related的控 +制寄存器或计数器进行操作。该翻译基于 *riscv_pmu* 中提供的映射和方法。 + +注意,有些功能也可以在这个阶段完成: + +(1) 中断设置,这个在下一节说; +(2) 特限级设置(仅用户空间、仅内核空间、两者都有); +(3) 析构函数设置。 通常应用 *riscv_destroy_event* 即可; +(4) 对非采样事件的调整,这将被函数应用,如 *perf_adjust_period* ,通常如下:: + + if (!is_sampling_event(event)) { + hwc->sample_period = x86_pmu.max_period; + hwc->last_period = hwc->sample_period; + local64_set(&hwc->period_left, hwc->sample_period); + } + + +在 *riscv_base_pmu* 的情况下,目前只提供了(3)。 + + +3. 中断 +------- + +3.1. 中断初始化 + +这种情况经常出现在 *event_init* 方案的开头。通常情况下,这应该是一个代码段,如:: + + int x86_reserve_hardware(void) + { + int err = 0; + + if (!atomic_inc_not_zero(&pmc_refcount)) { + mutex_lock(&pmc_reserve_mutex); + if (atomic_read(&pmc_refcount) == 0) { + if (!reserve_pmc_hardware()) + err = -EBUSY; + else + reserve_ds_buffers(); + } + if (!err) + atomic_inc(&pmc_refcount); + mutex_unlock(&pmc_reserve_mutex); + } + + return err; + } + +而神奇的是 *reserve_pmc_hardware* ,它通常做原子操作,使实现的IRQ可以从某个全局函 +数指针访问。 而 *release_pmc_hardware* 的作用正好相反,它用在上一节提到的事件分配 +器中。 + + (注:从所有架构的实现来看,*reserve/release* 对总是IRQ设置,所以 *pmc_hardware* + 似乎有些误导。 它并不处理事件和物理计数器之间的绑定,这一点将在下一节介绍。) + +3.2. IRQ结构体 + +基本上,一个IRQ运行以下伪代码:: + + for each hardware counter that triggered this overflow + + get the event of this counter + + // following two steps are defined as *read()*, + // check the section Reading/Writing Counters for details. + count the delta value since previous interrupt + update the event->count (# event occurs) by adding delta, and + event->hw.period_left by subtracting delta + + if the event overflows + sample data + set the counter appropriately for the next overflow + + if the event overflows again + too frequently, throttle this event + fi + fi + + end for + + 然而截至目前,没有一个RISC-V的实现为perf设计了中断,所以具体的实现要在未来完成。 + +4. Reading/Writing 计数 +----------------------- + +它们看似差不多,但perf对待它们的态度却截然不同。 对于读,在 *struct pmu* 中有一个 +*read* 接口,但它的作用不仅仅是读。 根据上下文,*read* 函数不仅要读取计数器的内容 +(event->count),还要更新左周期到下一个中断(event->hw.period_left)。 + + 但 perf 的核心不需要直接写计数器。 写计数器隐藏在以下两点的抽象化之后, + 1) *pmu->start* ,从字面上看就是开始计数,所以必须把计数器设置成一个合适的值,以 + 便下一次中断; + 2)在IRQ里面,应该把计数器设置成同样的合理值。 + +在RISC-V中,读操作不是问题,但写操作就需要费些力气了,因为S模式不允许写计数器。 + + +5. add()/del()/start()/stop() +----------------------------- + +基本思想: add()/del() 向PMU添加/删除事件,start()/stop() 启动/停止PMU中某个事件 +的计数器。 所有这些函数都使用相同的参数: *struct perf_event *event* 和 *int flag* 。 + +把 perf 看作一个状态机,那么你会发现这些函数作为这些状态之间的状态转换过程。 +定义了三种状态(event->hw.state): + +* PERF_HES_STOPPED: 计数停止 +* PERF_HES_UPTODATE: event->count是最新的 +* PERF_HES_ARCH: 依赖于体系结构的用法,。。。我们现在并不需要它。 + +这些状态转换的正常流程如下: + +* 用户启动一个 perf 事件,导致调用 *event_init* 。 +* 当被上下文切换进来的时候,*add* 会被 perf core 调用,并带有一个标志 PERF_EF_START, + 也就是说事件被添加后应该被启动。 在这个阶段,如果有的话,一般事件会被绑定到一个物 + 理计数器上。当状态变为PERF_HES_STOPPED和PERF_HES_UPTODATE,因为现在已经停止了, + (软件)事件计数不需要更新。 + + - 然后调用 *start* ,并启用计数器。 + 通过PERF_EF_RELOAD标志,它向计数器写入一个适当的值(详细情况请参考上一节)。 + 如果标志不包含PERF_EF_RELOAD,则不会写入任何内容。 + 现在状态被重置为none,因为它既没有停止也没有更新(计数已经开始)。 + +*当被上下文切换出来时被调用。 然后,它检查出PMU中的所有事件,并调用 *stop* 来更新它们 + 的计数。 + + - *stop* 被 *del* 和perf核心调用,标志为PERF_EF_UPDATE,它经常以相同的逻辑和 *read* + 共用同一个子程序。 + 状态又一次变为PERF_HES_STOPPED和PERF_HES_UPTODATE。 + + - 这两对程序的生命周期: *add* 和 *del* 在任务切换时被反复调用;*start* 和 *stop* 在 + perf核心需要快速停止和启动时也会被调用,比如在调整中断周期时。 + +目前的实现已经足够了,将来可以很容易地扩展到功能。 + +A. 相关结构体 +------------- + +* struct pmu: include/linux/perf_event.h +* struct riscv_pmu: arch/riscv/include/asm/perf_event.h + + 两个结构体都被设计为只读。 + + *struct pmu* 定义了一些函数指针接口,它们大多以 *struct perf_event* 作为主参数,根据 + perf的内部状态机处理perf事件(详情请查看kernel/events/core.c)。 + + *struct riscv_pmu* 定义了PMU的具体参数。 命名遵循所有其它架构的惯例。 + +* struct perf_event: include/linux/perf_event.h +* struct hw_perf_event + + 表示 perf 事件的通用结构体,以及硬件相关的细节。 + +* struct riscv_hw_events: arch/riscv/include/asm/perf_event.h + + 保存事件状态的结构有两个固定成员。 + 事件的数量和事件的数组。 + +参考文献 +-------- + +[1] https://github.com/riscv/riscv-linux/pull/124 + +[2] https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/f19TmCNP6yA diff --git a/Documentation/translations/zh_CN/sound/hd-audio/controls.rst b/Documentation/translations/zh_CN/sound/hd-audio/controls.rst new file mode 100644 index 0000000000000000000000000000000000000000..54c028ab9a4076c8dadc5b5dfa9da70c8ad0ba3c --- /dev/null +++ b/Documentation/translations/zh_CN/sound/hd-audio/controls.rst @@ -0,0 +1,102 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Chinese translator: Huang Jianghui <huangjianghui@uniontech.com> +--------------------------------------------------------------------- +.. include:: ../../disclaimer-zh_CN.rst +以下为正文 +--------------------------------------------------------------------- +====================================== +高清音频编解码器特定混音器控件 +====================================== + + +此文件解释特定于编解码器的混音器控件. + +瑞昱编解码器 +------------ + +声道模式 + 这是一个用于更改环绕声道设置的枚举控件,仅在环绕声道打开时显示出现。 + 它给出要使用的通道数:"2ch","4ch","6ch",和"8ch"。根据配置,这还控 + 制多I/O插孔的插孔重分配。 + +自动静音模式 + 这是一个枚举控件,用于更改耳机和线路输出插孔的自动静音行为。如果内 + 置扬声器、耳机和/或线路输出插孔在机器上可用,则显示该控件。当只有 + 耳机或者线路输出的时候,它给出”禁用“和”启用“状态。当启用后,插孔插 + 入后扬声器会自动静音。 + + 当耳机和线路输出插孔都存在时,它给出”禁用“、”仅扬声器“和”线路输出+扬 + 声器“。当”仅扬声器“被选择,插入耳机或者线路输出插孔可使扬声器静音, + 但不会使线路输出静音。当线路输出+扬声器被选择,插入耳机插孔会同时使扬 + 声器和线路输出静音。 + + +矽玛特编解码器 +-------------- + +模拟环回 + 此控件启用/禁用模拟环回电路。只有在编解码器提示中将”lookback“设置为真 + 时才会出现(见HD-Audio.txt)。请注意,在某些编解码器上,模拟环回和正常 + PCM播放是独占的,即当此选项打开时,您将听不到任何PCM流。 + +交换中置/低频 + 交换中置和低频通道顺序,通常情况下,左侧对应中置,右侧对应低频,启动此 + 项后,左边低频,右边中置。 + +耳机作为线路输出 + 当此控制开启时,将耳机视为线路输出插孔。也就是说,耳机不会自动静音其他 + 线路输出,没有耳机放大器被设置到引脚上。 + +麦克风插口模式、线路插孔模式等 + 这些枚举控制输入插孔引脚的方向和偏置。根据插孔类型,它可以设置为”麦克风 + 输入“和”线路输入“以确定输入偏置,或者当引脚是环绕声道的多I/O插孔时,它 + 可以设置为”线路输出“。 + + +威盛编解码器 +------------ + +智能5.1 + 一个枚举控件,用于为环绕输出重新分配多个I/O插孔的任务。当它打开时,相应 + 的输入插孔(通常是线路输入和麦克风输入)被切换为环绕和中央低频输出插孔。 + +独立耳机 + 启用此枚举控制时,耳机输出从单个流(第三个PCM,如hw:0,2)而不是主流路由。 + 如果耳机DAC与侧边或中央低频通道DAC共享,则DAC将自动切换到耳机。 + +环回混合 + 一个用于确定是否启动了模拟环回路由的枚举控件。当它启用后,模拟环回路由到 + 前置通道。同样,耳机与扬声器输出也采用相同的路径。作为一个副作用,当设置 + 此模式后,单个音量控制将不再适用于耳机和扬声器,因为只有一个DAC连接到混 + 音器小部件。 + +动态电源控制 + 此控件决定是否启动每个插孔的动态电源控制检测。启用时,根据插孔的插入情况 + 动态更改组件的电源状态(D0/D3)以节省电量消耗。但是,如果您的系统没有提 + 供正确的插孔检测,这将无法工作;在这种情况下,请关闭此控件。 + +插孔检测 + 此控件仅为VT1708编解码器提供,它不会为每个插孔插拔提供适当的未请求事件。 + 当此控件打开,驱动将轮询插孔检测,以便耳机自动静音可以工作,而关闭此控 + 件将降低功耗。 + + +科胜讯编解码器 +-------------- + +自动静音模式 + 见瑞昱解码器 + + + +模拟编解码器 +------------ + +通道模式 + 这是一个用于更改环绕声道设置的枚举控件,仅在环绕声道可用时显示。它提供了能 + 被使用的通道数:”2ch“、”4ch“和”6ch“。根据配置,这还控制多I/O插孔的插孔重 + 分配。 + +独立耳机 + 启动此枚举控制后,耳机输出从单个流(第三个PCM,如hw:0,2)而不是主流路由。 diff --git a/Documentation/translations/zh_CN/sound/hd-audio/index.rst b/Documentation/translations/zh_CN/sound/hd-audio/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..d9885d53b069f4417842dabfed445104b049e5ae --- /dev/null +++ b/Documentation/translations/zh_CN/sound/hd-audio/index.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../../disclaimer-zh_CN.rst + +:Original: :doc:`../../../../sound/hd-audio/index` +:Translator: Huang Jianghui <huangjianghui@uniontech.com> + + +高清音频 +======== + +.. toctree:: + :maxdepth: 2 + + controls diff --git a/Documentation/translations/zh_CN/sound/index.rst b/Documentation/translations/zh_CN/sound/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..28d5dca34a636692963a1cd4ad512617ce59c9a7 --- /dev/null +++ b/Documentation/translations/zh_CN/sound/index.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: :doc:`../../../sound/index` +:Translator: Huang Jianghui <huangjianghui@uniontech.com> + + +==================== +Linux 声音子系统文档 +==================== + +.. toctree:: + :maxdepth: 2 + + hd-audio/index + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/usb/usbip_protocol.rst b/Documentation/usb/usbip_protocol.rst index 988c832166cd60a9e08d477eca9f7152152dc32a..0b8541fda4d8476e7686b6f569e3345ef5d64a76 100644 --- a/Documentation/usb/usbip_protocol.rst +++ b/Documentation/usb/usbip_protocol.rst @@ -2,15 +2,15 @@ USB/IP protocol =============== -PRELIMINARY DRAFT, MAY CONTAIN MISTAKES! -28 Jun 2011 +Architecture +============ The USB/IP protocol follows a server/client architecture. The server exports the -USB devices and the clients imports them. The device driver for the exported +USB devices and the clients import them. The device driver for the exported USB device runs on the client machine. The client may ask for the list of the exported USB devices. To get the list the -client opens a TCP/IP connection towards the server, and sends an OP_REQ_DEVLIST +client opens a TCP/IP connection to the server, and sends an OP_REQ_DEVLIST packet on top of the TCP/IP connection (so the actual OP_REQ_DEVLIST may be sent in one or more pieces at the low level transport layer). The server sends back the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the @@ -30,7 +30,7 @@ TCP/IP connection is closed. | | Once the client knows the list of exported USB devices it may decide to use one -of them. First the client opens a TCP/IP connection towards the server and +of them. First the client opens a TCP/IP connection to the server and sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the import was successful the TCP/IP connection remains open and will be used to transfer the URB traffic between the client and the server. The client may @@ -84,17 +84,61 @@ server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively. | <---------------------------------------------- | | . | | : | + +For UNLINK, note that after a successful USBIP_RET_UNLINK, the unlinked URB +submission would not have a corresponding USBIP_RET_SUBMIT (this is explained in +function stub_recv_cmd_unlink of drivers/usb/usbip/stub_rx.c). + +:: + + virtual host controller usb host + "client" "server" + (imports USB devices) (exports USB devices) + | | + | USBIP_CMD_SUBMIT(seqnum = p) | + | ----------------------------------------------> | | | | USBIP_CMD_UNLINK | + | (seqnum = p+1, unlink_seqnum = p) | | ----------------------------------------------> | | | | USBIP_RET_UNLINK | + | (seqnum = p+1, status = -ECONNRESET) | + | <---------------------------------------------- | + | | + | Note: No USBIP_RET_SUBMIT(seqnum = p) | + | <--X---X---X---X---X---X---X---X---X---X---X--- | + | . | + | : | + | | + | USBIP_CMD_SUBMIT(seqnum = q) | + | ----------------------------------------------> | + | | + | USBIP_RET_SUBMIT(seqnum = q) | + | <---------------------------------------------- | + | | + | USBIP_CMD_UNLINK | + | (seqnum = q+1, unlink_seqnum = q) | + | ----------------------------------------------> | + | | + | USBIP_RET_UNLINK | + | (seqnum = q+1, status = 0) | | <---------------------------------------------- | | | The fields are in network (big endian) byte order meaning that the most significant byte (MSB) is stored at the lowest address. +Protocol Version +================ + +The documented USBIP version is v1.1.1. The binary representation of this +version in message headers is 0x0111. + +This is defined in tools/usb/usbip/configure.ac + +Message Format +============== OP_REQ_DEVLIST: Retrieve the list of exported USB devices. @@ -102,7 +146,7 @@ OP_REQ_DEVLIST: +-----------+--------+------------+---------------------------------------------------+ | Offset | Length | Value | Description | +===========+========+============+===================================================+ -| 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | +| 0 | 2 | | USBIP version | +-----------+--------+------------+---------------------------------------------------+ | 2 | 2 | 0x8005 | Command code: Retrieve the list of exported USB | | | | | devices. | @@ -116,7 +160,7 @@ OP_REP_DEVLIST: +-----------+--------+------------+---------------------------------------------------+ | Offset | Length | Value | Description | +===========+========+============+===================================================+ -| 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0.| +| 0 | 2 | | USBIP version | +-----------+--------+------------+---------------------------------------------------+ | 2 | 2 | 0x0005 | Reply code: The list of exported USB devices. | +-----------+--------+------------+---------------------------------------------------+ @@ -165,8 +209,8 @@ OP_REP_DEVLIST: | 0x143 | 1 | | bNumInterfaces | +-----------+--------+------------+---------------------------------------------------+ | 0x144 | | m_0 | From now on each interface is described, all | -| | | | together bNumInterfaces times, with the | -| | | | the following 4 fields: | +| | | | together bNumInterfaces times, with the following | +| | | | 4 fields: | +-----------+--------+------------+---------------------------------------------------+ | | 1 | | bInterfaceClass | +-----------+--------+------------+---------------------------------------------------+ @@ -177,7 +221,7 @@ OP_REP_DEVLIST: | 0x147 | 1 | | padding byte for alignment, shall be set to zero | +-----------+--------+------------+---------------------------------------------------+ | 0xC + | | | The second exported USB device starts at i=1 | -| i*0x138 + | | | with the busid field. | +| i*0x138 + | | | with the path field. | | m_(i-1)*4 | | | | +-----------+--------+------------+---------------------------------------------------+ @@ -187,7 +231,7 @@ OP_REQ_IMPORT: +-----------+--------+------------+---------------------------------------------------+ | Offset | Length | Value | Description | +===========+========+============+===================================================+ -| 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | +| 0 | 2 | | USBIP version | +-----------+--------+------------+---------------------------------------------------+ | 2 | 2 | 0x8003 | Command code: import a remote USB device. | +-----------+--------+------------+---------------------------------------------------+ @@ -206,7 +250,7 @@ OP_REP_IMPORT: +-----------+--------+------------+---------------------------------------------------+ | Offset | Length | Value | Description | +===========+========+============+===================================================+ -| 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | +| 0 | 2 | | USBIP version | +-----------+--------+------------+---------------------------------------------------+ | 2 | 2 | 0x0003 | Reply code: Reply to import. | +-----------+--------+------------+---------------------------------------------------+ @@ -254,158 +298,156 @@ OP_REP_IMPORT: | 0x13E | 1 | | bNumInterfaces | +-----------+--------+------------+---------------------------------------------------+ -USBIP_CMD_SUBMIT: - Submit an URB +The following four commands have a common basic header called +'usbip_header_basic', and their headers, called 'usbip_header' (before +transfer_buffer payload), have the same length, therefore paddings are needed. -+-----------+--------+------------+---------------------------------------------------+ -| Offset | Length | Value | Description | -+===========+========+============+===================================================+ -| 0 | 4 | 0x00000001 | command: Submit an URB | -+-----------+--------+------------+---------------------------------------------------+ -| 4 | 4 | | seqnum: the sequence number of the URB to submit | -+-----------+--------+------------+---------------------------------------------------+ -| 8 | 4 | | devid | -+-----------+--------+------------+---------------------------------------------------+ -| 0xC | 4 | | direction: | -| | | | | -| | | | - 0: USBIP_DIR_OUT | -| | | | - 1: USBIP_DIR_IN | -+-----------+--------+------------+---------------------------------------------------+ -| 0x10 | 4 | | ep: endpoint number, possible values are: 0...15 | -+-----------+--------+------------+---------------------------------------------------+ -| 0x14 | 4 | | transfer_flags: possible values depend on the | -| | | | URB transfer type, see below | -+-----------+--------+------------+---------------------------------------------------+ -| 0x18 | 4 | | transfer_buffer_length | -+-----------+--------+------------+---------------------------------------------------+ -| 0x1C | 4 | | start_frame: specify the selected frame to | -| | | | transmit an ISO frame, ignored if URB_ISO_ASAP | -| | | | is specified at transfer_flags | -+-----------+--------+------------+---------------------------------------------------+ -| 0x20 | 4 | | number_of_packets: number of ISO packets | -+-----------+--------+------------+---------------------------------------------------+ -| 0x24 | 4 | | interval: maximum time for the request on the | -| | | | server-side host controller | -+-----------+--------+------------+---------------------------------------------------+ -| 0x28 | 8 | | setup: data bytes for USB setup, filled with | -| | | | zeros if not used | -+-----------+--------+------------+---------------------------------------------------+ -| 0x30 | | | URB data. For ISO transfers the padding between | -| | | | each ISO packets is not transmitted. | -+-----------+--------+------------+---------------------------------------------------+ +usbip_header_basic: ++-----------+--------+---------------------------------------------------+ +| Offset | Length | Description | ++===========+========+===================================================+ +| 0 | 4 | command | ++-----------+--------+---------------------------------------------------+ +| 4 | 4 | seqnum: sequential number that identifies requests| +| | | and corresponding responses; | +| | | incremented per connection | ++-----------+--------+---------------------------------------------------+ +| 8 | 4 | devid: specifies a remote USB device uniquely | +| | | instead of busnum and devnum; | +| | | for client (request), this value is | +| | | ((busnum << 16) | devnum); | +| | | for server (response), this shall be set to 0 | ++-----------+--------+---------------------------------------------------+ +| 0xC | 4 | direction: | +| | | | +| | | - 0: USBIP_DIR_OUT | +| | | - 1: USBIP_DIR_IN | +| | | | +| | | only used by client, for server this shall be 0 | ++-----------+--------+---------------------------------------------------+ +| 0x10 | 4 | ep: endpoint number | +| | | only used by client, for server this shall be 0; | +| | | for UNLINK, this shall be 0 | ++-----------+--------+---------------------------------------------------+ - +-------------------------+------------+---------+-----------+----------+-------------+ - | Allowed transfer_flags | value | control | interrupt | bulk | isochronous | - +=========================+============+=========+===========+==========+=============+ - | URB_SHORT_NOT_OK | 0x00000001 | only in | only in | only in | no | - +-------------------------+------------+---------+-----------+----------+-------------+ - | URB_ISO_ASAP | 0x00000002 | no | no | no | yes | - +-------------------------+------------+---------+-----------+----------+-------------+ - | URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes | yes | yes | yes | - +-------------------------+------------+---------+-----------+----------+-------------+ - | URB_ZERO_PACKET | 0x00000040 | no | no | only out | no | - +-------------------------+------------+---------+-----------+----------+-------------+ - | URB_NO_INTERRUPT | 0x00000080 | yes | yes | yes | yes | - +-------------------------+------------+---------+-----------+----------+-------------+ - | URB_FREE_BUFFER | 0x00000100 | yes | yes | yes | yes | - +-------------------------+------------+---------+-----------+----------+-------------+ - | URB_DIR_MASK | 0x00000200 | yes | yes | yes | yes | - +-------------------------+------------+---------+-----------+----------+-------------+ +USBIP_CMD_SUBMIT: + Submit an URB ++-----------+--------+---------------------------------------------------+ +| Offset | Length | Description | ++===========+========+===================================================+ +| 0 | 20 | usbip_header_basic, 'command' shall be 0x00000001 | ++-----------+--------+---------------------------------------------------+ +| 0x14 | 4 | transfer_flags: possible values depend on the | +| | | URB transfer_flags (refer to URB doc in | +| | | Documentation/driver-api/usb/URB.rst) | +| | | but with URB_NO_TRANSFER_DMA_MAP masked. Refer to | +| | | function usbip_pack_cmd_submit and function | +| | | tweak_transfer_flags in drivers/usb/usbip/ | +| | | usbip_common.c. The following fields may also ref | +| | | to function usbip_pack_cmd_submit and URB doc | ++-----------+--------+---------------------------------------------------+ +| 0x18 | 4 | transfer_buffer_length: | +| | | use URB transfer_buffer_length | ++-----------+--------+---------------------------------------------------+ +| 0x1C | 4 | start_frame: use URB start_frame; | +| | | initial frame for ISO transfer; | +| | | shall be set to 0 if not ISO transfer | ++-----------+--------+---------------------------------------------------+ +| 0x20 | 4 | number_of_packets: number of ISO packets; | +| | | shall be set to 0xffffffff if not ISO transfer | ++-----------+--------+---------------------------------------------------+ +| 0x24 | 4 | interval: maximum time for the request on the | +| | | server-side host controller | ++-----------+--------+---------------------------------------------------+ +| 0x28 | 8 | setup: data bytes for USB setup, filled with | +| | | zeros if not used. | ++-----------+--------+---------------------------------------------------+ +| 0x30 | n | transfer_buffer. | +| | | If direction is USBIP_DIR_OUT then n equals | +| | | transfer_buffer_length; otherwise n equals 0. | +| | | For ISO transfers the padding between each ISO | +| | | packets is not transmitted. | ++-----------+--------+---------------------------------------------------+ +| 0x30+n | m | iso_packet_descriptor | ++-----------+--------+---------------------------------------------------+ USBIP_RET_SUBMIT: Reply for submitting an URB -+-----------+--------+------------+---------------------------------------------------+ -| Offset | Length | Value | Description | -+===========+========+============+===================================================+ -| 0 | 4 | 0x00000003 | command | -+-----------+--------+------------+---------------------------------------------------+ -| 4 | 4 | | seqnum: URB sequence number | -+-----------+--------+------------+---------------------------------------------------+ -| 8 | 4 | | devid | -+-----------+--------+------------+---------------------------------------------------+ -| 0xC | 4 | | direction: | -| | | | | -| | | | - 0: USBIP_DIR_OUT | -| | | | - 1: USBIP_DIR_IN | -+-----------+--------+------------+---------------------------------------------------+ -| 0x10 | 4 | | ep: endpoint number | -+-----------+--------+------------+---------------------------------------------------+ -| 0x14 | 4 | | status: zero for successful URB transaction, | -| | | | otherwise some kind of error happened. | -+-----------+--------+------------+---------------------------------------------------+ -| 0x18 | 4 | n | actual_length: number of URB data bytes | -+-----------+--------+------------+---------------------------------------------------+ -| 0x1C | 4 | | start_frame: for an ISO frame the actually | -| | | | selected frame for transmit. | -+-----------+--------+------------+---------------------------------------------------+ -| 0x20 | 4 | | number_of_packets | -+-----------+--------+------------+---------------------------------------------------+ -| 0x24 | 4 | | error_count | -+-----------+--------+------------+---------------------------------------------------+ -| 0x28 | 8 | | setup: data bytes for USB setup, filled with | -| | | | zeros if not used | -+-----------+--------+------------+---------------------------------------------------+ -| 0x30 | n | | URB data bytes. For ISO transfers the padding | -| | | | between each ISO packets is not transmitted. | -+-----------+--------+------------+---------------------------------------------------+ ++-----------+--------+---------------------------------------------------+ +| Offset | Length | Description | ++===========+========+===================================================+ +| 0 | 20 | usbip_header_basic, 'command' shall be 0x00000003 | ++-----------+--------+---------------------------------------------------+ +| 0x14 | 4 | status: zero for successful URB transaction, | +| | | otherwise some kind of error happened. | ++-----------+--------+---------------------------------------------------+ +| 0x18 | 4 | actual_length: number of URB data bytes; | +| | | use URB actual_length | ++-----------+--------+---------------------------------------------------+ +| 0x1C | 4 | start_frame: use URB start_frame; | +| | | initial frame for ISO transfer; | +| | | shall be set to 0 if not ISO transfer | ++-----------+--------+---------------------------------------------------+ +| 0x20 | 4 | number_of_packets: number of ISO packets; | +| | | shall be set to 0xffffffff if not ISO transfer | ++-----------+--------+---------------------------------------------------+ +| 0x24 | 4 | error_count | ++-----------+--------+---------------------------------------------------+ +| 0x28 | 8 | padding, shall be set to 0 | ++-----------+--------+---------------------------------------------------+ +| 0x30 | n | transfer_buffer. | +| | | If direction is USBIP_DIR_IN then n equals | +| | | actual_length; otherwise n equals 0. | +| | | For ISO transfers the padding between each ISO | +| | | packets is not transmitted. | ++-----------+--------+---------------------------------------------------+ +| 0x30+n | m | iso_packet_descriptor | ++-----------+--------+---------------------------------------------------+ USBIP_CMD_UNLINK: Unlink an URB -+-----------+--------+------------+---------------------------------------------------+ -| Offset | Length | Value | Description | -+===========+========+============+===================================================+ -| 0 | 4 | 0x00000002 | command: URB unlink command | -+-----------+--------+------------+---------------------------------------------------+ -| 4 | 4 | | seqnum: URB sequence number to unlink: | -| | | | | -| | | | FIXME: | -| | | | is this so? | -+-----------+--------+------------+---------------------------------------------------+ -| 8 | 4 | | devid | -+-----------+--------+------------+---------------------------------------------------+ -| 0xC | 4 | | direction: | -| | | | | -| | | | - 0: USBIP_DIR_OUT | -| | | | - 1: USBIP_DIR_IN | -+-----------+--------+------------+---------------------------------------------------+ -| 0x10 | 4 | | ep: endpoint number: zero | -+-----------+--------+------------+---------------------------------------------------+ -| 0x14 | 4 | | seqnum: the URB sequence number given previously | -| | | | at USBIP_CMD_SUBMIT.seqnum field | -+-----------+--------+------------+---------------------------------------------------+ -| 0x30 | n | | URB data bytes. For ISO transfers the padding | -| | | | between each ISO packets is not transmitted. | -+-----------+--------+------------+---------------------------------------------------+ ++-----------+--------+---------------------------------------------------+ +| Offset | Length | Description | ++===========+========+===================================================+ +| 0 | 20 | usbip_header_basic, 'command' shall be 0x00000002 | ++-----------+--------+---------------------------------------------------+ +| 0x14 | 4 | unlink_seqnum, of the SUBMIT request to unlink | ++-----------+--------+---------------------------------------------------+ +| 0x18 | 24 | padding, shall be set to 0 | ++-----------+--------+---------------------------------------------------+ USBIP_RET_UNLINK: Reply for URB unlink -+-----------+--------+------------+---------------------------------------------------+ -| Offset | Length | Value | Description | -+===========+========+============+===================================================+ -| 0 | 4 | 0x00000004 | command: reply for the URB unlink command | -+-----------+--------+------------+---------------------------------------------------+ -| 4 | 4 | | seqnum: the unlinked URB sequence number | -+-----------+--------+------------+---------------------------------------------------+ -| 8 | 4 | | devid | -+-----------+--------+------------+---------------------------------------------------+ -| 0xC | 4 | | direction: | -| | | | | -| | | | - 0: USBIP_DIR_OUT | -| | | | - 1: USBIP_DIR_IN | -+-----------+--------+------------+---------------------------------------------------+ -| 0x10 | 4 | | ep: endpoint number | -+-----------+--------+------------+---------------------------------------------------+ -| 0x14 | 4 | | status: This is the value contained in the | -| | | | urb->status in the URB completition handler. | -| | | | | -| | | | FIXME: | -| | | | a better explanation needed. | -+-----------+--------+------------+---------------------------------------------------+ -| 0x30 | n | | URB data bytes. For ISO transfers the padding | -| | | | between each ISO packets is not transmitted. | -+-----------+--------+------------+---------------------------------------------------+ ++-----------+--------+---------------------------------------------------+ +| Offset | Length | Description | ++===========+========+===================================================+ +| 0 | 20 | usbip_header_basic, 'command' shall be 0x00000004 | ++-----------+--------+---------------------------------------------------+ +| 0x14 | 4 | status: This is similar to the status of | +| | | USBIP_RET_SUBMIT (share the same memory offset). | +| | | When UNLINK is successful, status is -ECONNRESET; | +| | | when USBIP_CMD_UNLINK is after USBIP_RET_SUBMIT | +| | | status is 0 | ++-----------+--------+---------------------------------------------------+ +| 0x18 | 24 | padding, shall be set to 0 | ++-----------+--------+---------------------------------------------------+ + +EXAMPLE +======= + + The following data is captured from wire with Human Interface Devices (HID) + payload + +:: + + CmdIntrIN: 00000001 00000d05 0001000f 00000001 00000001 00000200 00000040 ffffffff 00000000 00000004 00000000 00000000 + CmdIntrOUT: 00000001 00000d06 0001000f 00000000 00000001 00000000 00000040 ffffffff 00000000 00000004 00000000 00000000 + ffffffff860008a784ce5ae212376300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + RetIntrOut: 00000003 00000d06 00000000 00000000 00000000 00000000 00000040 ffffffff 00000000 00000000 00000000 00000000 + RetIntrIn: 00000003 00000d05 00000000 00000000 00000000 00000000 00000040 ffffffff 00000000 00000000 00000000 00000000 + ffffffff860011a784ce5ae2123763612891b1020100000400000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 599bd449394441611e726ef6f2b6c3b1b4b96481..9bfc2b510c6484bd752a266374adb6b78a6431c4 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -209,7 +209,6 @@ Code Seq# Include File Comments linux/fs.h, 'X' all fs/ocfs2/ocfs_fs.h conflict! 'X' 01 linux/pktcdvd.h conflict! -'Y' all linux/cyclades.h 'Z' 14-15 drivers/message/fusion/mptctl.h '[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices <mailto:gregkh@linuxfoundation.org> @@ -245,6 +244,7 @@ Code Seq# Include File Comments 'i' 00-3F linux/i2o-dev.h conflict! 'i' 0B-1F linux/ipmi.h conflict! 'i' 80-8F linux/i8k.h +'i' 90-9F `linux/iio/*.h` IIO 'j' 00-3F linux/joystick.h 'k' 00-0F linux/spi/spidev.h conflict! 'k' 00-05 video/kyro.h conflict! @@ -327,6 +327,8 @@ Code Seq# Include File Comments 0xA4 00-1F uapi/asm/sgx.h <mailto:linux-sgx@vger.kernel.org> 0xA5 01 linux/surface_aggregator/cdev.h Microsoft Surface Platform System Aggregator <mailto:luzmaximilian@gmail.com> +0xA5 20-2F linux/surface_aggregator/dtx.h Microsoft Surface DTX driver + <mailto:luzmaximilian@gmail.com> 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h @@ -347,6 +349,7 @@ Code Seq# Include File Comments 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org> 0xB6 all linux/fpga-dfl.h 0xB7 all uapi/linux/remoteproc_cdev.h <mailto:linux-remoteproc@vger.kernel.org> +0xB7 all uapi/linux/nsfs.h <mailto:Andrei Vagin <avagin@openvz.org>> 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h 0xCA 10-2F uapi/misc/ocxl.h diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 307f2fcf1b021239c505eed0f066bc69a1b983c3..245d80581f159580318215708d624166124a630a 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -55,7 +55,7 @@ not cause harm to the host, their actual behavior is not guaranteed by the API. See "General description" for details on the ioctl usage model that is supported by KVM. -It is important to note that althought VM ioctls may only be issued from +It is important to note that although VM ioctls may only be issued from the process that created the VM, a VM's lifecycle is associated with its file descriptor, not its creator (process). In other words, the VM and its resources, *including the associated address space*, are not freed diff --git a/Documentation/watchdog/pcwd-watchdog.rst b/Documentation/watchdog/pcwd-watchdog.rst index 405e2a3700828eb43592817002078067f0f47e5e..151505c856f63c8dbfa9ef4a3de8a0c0ae26afad 100644 --- a/Documentation/watchdog/pcwd-watchdog.rst +++ b/Documentation/watchdog/pcwd-watchdog.rst @@ -47,7 +47,7 @@ Documentation and Driver by Ken Hollis <kenji@bitgate.com> WDIOC_GETSTATUS This returns the status of the card, with the bits of WDIOF_* bitwise-anded into the value. (The comments - are in linux/pcwd.h) + are in include/uapi/linux/watchdog.h) WDIOC_GETBOOTSTATUS This returns the status of the card that was reported diff --git a/Documentation/x86/sgx.rst b/Documentation/x86/sgx.rst index eaee1368b4fd8b838afba5d69d626fad1ec9e39d..dd0ac96ff9efba9021b0398a8c0323618e1c33b1 100644 --- a/Documentation/x86/sgx.rst +++ b/Documentation/x86/sgx.rst @@ -209,3 +209,44 @@ An application may be loaded into a container enclave which is specially configured with a library OS and run-time which permits the application to run. The enclave run-time and library OS work together to execute the application when a thread enters the enclave. + +Impact of Potential Kernel SGX Bugs +=================================== + +EPC leaks +--------- + +When EPC page leaks happen, a WARNING like this is shown in dmesg: + +"EREMOVE returned ... and an EPC page was leaked. SGX may become unusable..." + +This is effectively a kernel use-after-free of an EPC page, and due +to the way SGX works, the bug is detected at freeing. Rather than +adding the page back to the pool of available EPC pages, the kernel +intentionally leaks the page to avoid additional errors in the future. + +When this happens, the kernel will likely soon leak more EPC pages, and +SGX will likely become unusable because the memory available to SGX is +limited. However, while this may be fatal to SGX, the rest of the kernel +is unlikely to be impacted and should continue to work. + +As a result, when this happpens, user should stop running any new +SGX workloads, (or just any new workloads), and migrate all valuable +workloads. Although a machine reboot can recover all EPC memory, the bug +should be reported to Linux developers. + + +Virtual EPC +=========== + +The implementation has also a virtual EPC driver to support SGX enclaves +in guests. Unlike the SGX driver, an EPC page allocated by the virtual +EPC driver doesn't have a specific enclave associated with it. This is +because KVM doesn't track how a guest uses EPC pages. + +As a result, the SGX core page reclaimer doesn't support reclaiming EPC +pages allocated to KVM guests through the virtual EPC driver. If the +user wants to deploy SGX applications both on the host and in guests +on the same machine, the user should reserve enough EPC (by taking out +total virtual EPC size of all SGX VMs from the physical EPC size) for +host SGX applications so they can run with acceptable performance. diff --git a/MAINTAINERS b/MAINTAINERS index 54987de38a608827e1664e0e1303474407828837..1f9341c2b6c7312d411b274a00935d150704da5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -300,7 +300,6 @@ M: Syed Nayyar Waris <syednwaris@gmail.com> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-bus-counter-104-quad-8 -F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 F: drivers/counter/104-quad-8.c ACCES PCI-IDIO-16 GPIO DRIVER @@ -573,6 +572,12 @@ S: Maintained F: Documentation/scsi/advansys.rst F: drivers/scsi/advansys.c +ADVANTECH SWBTN DRIVER +M: Andrea Ho <Andrea.Ho@advantech.com.tw> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/adv_swbutton.c + ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346) M: Michael Hennerich <michael.hennerich@analog.com> S: Supported @@ -697,6 +702,11 @@ S: Maintained F: Documentation/i2c/busses/i2c-ali1563.rst F: drivers/i2c/busses/i2c-ali1563.c +ALIENWARE WMI DRIVER +L: Dell.Client.Kernel@dell.com +S: Maintained +F: drivers/platform/x86/dell/alienware-wmi.c + ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER M: Tomislav Denis <tomislav.denis@avl.com> L: linux-iio@vger.kernel.org @@ -870,13 +880,6 @@ S: Supported T: git git://people.freedesktop.org/~agd5f/linux F: drivers/gpu/drm/amd/display/ -AMD ENERGY DRIVER -M: Naveen Krishna Chatradhi <nchatrad@amd.com> -L: linux-hwmon@vger.kernel.org -S: Maintained -F: Documentation/hwmon/amd_energy.rst -F: drivers/hwmon/amd_energy.c - AMD FAM15H PROCESSOR POWER MONITORING DRIVER M: Huang Rui <ray.huang@amd.com> L: linux-hwmon@vger.kernel.org @@ -1142,7 +1145,7 @@ W: http://ez.analog.com/community/linux-device-drivers F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523 F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 F: Documentation/devicetree/bindings/iio/*/adi,* -F: Documentation/devicetree/bindings/iio/dac/ad5758.txt +F: Documentation/devicetree/bindings/iio/dac/adi,ad5758.yaml F: drivers/iio/*/ad* F: drivers/iio/adc/ltc249* F: drivers/iio/amplifiers/hmc425a.c @@ -1639,6 +1642,20 @@ F: arch/arm/mach-alpine/ F: arch/arm64/boot/dts/amazon/ F: drivers/*/*alpine* +ARM/APPLE MACHINE SUPPORT +M: Hector Martin <marcan@marcan.st> +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +W: https://asahilinux.org +B: https://github.com/AsahiLinux/linux/issues +C: irc://chat.freenode.net/asahi-dev +T: git https://github.com/AsahiLinux/linux.git +F: Documentation/devicetree/bindings/arm/apple.yaml +F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml +F: arch/arm64/boot/dts/apple/ +F: drivers/irqchip/irq-apple-aic.c +F: include/dt-bindings/interrupt-controller/apple-aic.h + ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson <jesper.nilsson@axis.com> M: Lars Persson <lars.persson@axis.com> @@ -1766,6 +1783,7 @@ F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/trace/coresight/* F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h +F: include/linux/coresight* F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h @@ -2203,6 +2221,15 @@ F: drivers/*/*npcm* F: drivers/*/*/*npcm* F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h +ARM/NUVOTON WPCM450 ARCHITECTURE +M: Jonathan Neuschäfer <j.neuschaefer@gmx.net> +L: openbmc@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/*/*wpcm* +F: arch/arm/boot/dts/nuvoton-wpcm450* +F: arch/arm/mach-npcm/wpcm450.c +F: drivers/*/*wpcm* + ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT L: openmoko-kernel@lists.openmoko.org (subscribers-only) S: Orphan @@ -2305,6 +2332,7 @@ F: drivers/tty/serial/msm_serial.c F: drivers/usb/dwc3/dwc3-qcom.c F: include/dt-bindings/*/qcom* F: include/linux/*/qcom* +F: include/linux/soc/qcom/ ARM/RADISYS ENP2611 MACHINE SUPPORT M: Lennert Buytenhek <kernel@wantstofly.org> @@ -2384,7 +2412,7 @@ F: sound/soc/rockchip/ N: rockchip ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org S: Maintained @@ -2640,8 +2668,10 @@ F: drivers/watchdog/visconti_wdt.c N: visconti ARM/UNIPHIER ARCHITECTURE +M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> +M: Masami Hiramatsu <mhiramat@kernel.org> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Orphan +S: Maintained F: Documentation/devicetree/bindings/arm/socionext/uniphier.yaml F: Documentation/devicetree/bindings/gpio/socionext,uniphier-gpio.yaml F: Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml @@ -2988,9 +3018,11 @@ L: linux-audit@redhat.com (moderated for non-subscribers) S: Supported W: https://github.com/linux-audit T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git +F: include/asm-generic/audit_*.h F: include/linux/audit.h F: include/uapi/linux/audit.h F: kernel/audit* +F: lib/*audit.c AUXILIARY DISPLAY DRIVERS M: Miguel Ojeda <ojeda@kernel.org> @@ -3378,7 +3410,7 @@ F: include/linux/dsa/brcm.h F: include/linux/platform_data/b53.h BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE -M: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> +M: Nicolas Saenz Julienne <nsaenz@kernel.org> L: bcm-kernel-feedback-list@broadcom.com L: linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -3567,6 +3599,14 @@ S: Supported F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml F: drivers/i2c/busses/i2c-brcmstb.c +BROADCOM BRCMSTB UART DRIVER +M: Al Cooper <alcooperx@gmail.com> +L: linux-serial@vger.kernel.org +L: bcm-kernel-feedback-list@broadcom.com +S: Maintained +F: Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml +F: drivers/tty/serial/8250/8250_bcm7271.c + BROADCOM BRCMSTB USB EHCI DRIVER M: Al Cooper <alcooperx@gmail.com> L: linux-usb@vger.kernel.org @@ -3698,7 +3738,7 @@ BROADCOM SPI DRIVER M: Kamal Dasu <kdasu.kdev@gmail.com> M: bcm-kernel-feedback-list@broadcom.com S: Maintained -F: Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt +F: Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.yaml F: drivers/spi/spi-bcm-qspi.* F: drivers/spi/spi-brcmstb-qspi.c F: drivers/spi/spi-iproc-qspi.c @@ -4190,13 +4230,20 @@ X: drivers/char/tpm/ CHECKPATCH M: Andy Whitcroft <apw@canonical.com> M: Joe Perches <joe@perches.com> +R: Dwaipayan Ray <dwaipayanray1@gmail.com> +R: Lukas Bulwahn <lukas.bulwahn@gmail.com> S: Maintained F: scripts/checkpatch.pl +CHECKPATCH DOCUMENTATION +M: Dwaipayan Ray <dwaipayanray1@gmail.com> +M: Lukas Bulwahn <lukas.bulwahn@gmail.com> +R: Joe Perches <joe@perches.com> +S: Maintained +F: Documentation/dev-tools/checkpatch.rst + CHINESE DOCUMENTATION -M: Harry Wei <harryxiyou@gmail.com> -M: Alex Shi <alex.shi@linux.alibaba.com> -L: xiyoulinuxkernelgroup@googlegroups.com (subscribers-only) +M: Alex Shi <alexs@kernel.org> S: Maintained F: Documentation/translations/zh_CN/ @@ -4429,6 +4476,12 @@ S: Supported F: Documentation/process/code-of-conduct-interpretation.rst F: Documentation/process/code-of-conduct.rst +COMEDI DRIVERS +M: Ian Abbott <abbotti@mev.co.uk> +M: H Hartley Sweeten <hsweeten@visionengravers.com> +S: Odd Fixes +F: drivers/comedi/ + COMMON CLK FRAMEWORK M: Michael Turquette <mturquette@baylibre.com> M: Stephen Boyd <sboyd@kernel.org> @@ -4885,16 +4938,8 @@ S: Maintained W: http://www.armlinux.org.uk/ F: drivers/video/fbdev/cyber2000fb.* -CYCLADES ASYNC MUX DRIVER -S: Orphan -W: http://www.cyclades.com/ -F: drivers/tty/cyclades.c -F: include/linux/cyclades.h -F: include/uapi/linux/cyclades.h - CYCLADES PC300 DRIVER S: Orphan -W: http://www.cyclades.com/ F: drivers/net/wan/pc300* CYPRESS_FIRMWARE MEDIA DRIVER @@ -5043,19 +5088,19 @@ F: drivers/platform/x86/dell/dell_rbu.c DELL SMBIOS DRIVER M: Pali Rohár <pali@kernel.org> -M: Mario Limonciello <mario.limonciello@dell.com> +L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-smbios.* DELL SMBIOS SMM DRIVER -M: Mario Limonciello <mario.limonciello@dell.com> +L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-smbios-smm.c DELL SMBIOS WMI DRIVER -M: Mario Limonciello <mario.limonciello@dell.com> +L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-smbios-wmi.c @@ -5069,14 +5114,14 @@ F: Documentation/driver-api/dcdbas.rst F: drivers/platform/x86/dell/dcdbas.* DELL WMI DESCRIPTOR DRIVER -M: Mario Limonciello <mario.limonciello@dell.com> +L: Dell.Client.Kernel@dell.com S: Maintained F: drivers/platform/x86/dell/dell-wmi-descriptor.c DELL WMI SYSMAN DRIVER M: Divya Bharathi <divya.bharathi@dell.com> -M: Mario Limonciello <mario.limonciello@dell.com> M: Prasanth Ksr <prasanth.ksr@dell.com> +L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -5108,6 +5153,13 @@ S: Maintained F: drivers/dma/dw-edma/ F: include/linux/dma/edma.h +DESIGNWARE XDATA IP DRIVER +M: Gustavo Pimentel <gustavo.pimentel@synopsys.com> +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/misc-devices/dw-xdata-pcie.rst +F: drivers/misc/dw-xdata-pcie.c + DESIGNWARE USB2 DRD IP DRIVER M: Minas Harutyunyan <hminas@synopsys.com> L: linux-usb@vger.kernel.org @@ -5178,6 +5230,12 @@ M: Torben Mathiasen <device@lanana.org> S: Maintained W: http://lanana.org/docs/device-list/index.html +DEVICE RESOURCE MANAGEMENT HELPERS +M: Hans de Goede <hdegoede@redhat.com> +R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> +S: Maintained +F: include/linux/devm-helpers.h + DEVICE-MAPPER (LVM) M: Alasdair Kergon <agk@redhat.com> M: Mike Snitzer <snitzer@redhat.com> @@ -5387,7 +5445,7 @@ F: drivers/hwmon/dme1737.c DMI/SMBIOS SUPPORT M: Jean Delvare <jdelvare@suse.com> S: Maintained -T: quilt http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging.git dmi-for-next F: Documentation/ABI/testing/sysfs-firmware-dmi-tables F: drivers/firmware/dmi-id.c F: drivers/firmware/dmi_scan.c @@ -5413,6 +5471,12 @@ X: Documentation/power/ X: Documentation/spi/ X: Documentation/userspace-api/media/ +DOCUMENTATION REPORTING ISSUES +M: Thorsten Leemhuis <linux@leemhuis.info> +L: linux-doc@vger.kernel.org +S: Maintained +F: Documentation/admin-guide/reporting-issues.rst + DOCUMENTATION SCRIPTS M: Mauro Carvalho Chehab <mchehab@kernel.org> L: linux-doc@vger.kernel.org @@ -6999,6 +7063,7 @@ S: Maintained F: Documentation/ABI/testing/sysfs-bus-dfl* F: Documentation/fpga/dfl.rst F: drivers/fpga/dfl* +F: drivers/uio/uio_dfl.c F: include/linux/dfl.h F: include/uapi/linux/fpga-dfl.h @@ -7168,6 +7233,7 @@ FREESCALE QUAD SPI DRIVER M: Han Xu <han.xu@nxp.com> L: linux-spi@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml F: drivers/spi/spi-fsl-qspi.c FREESCALE QUICC ENGINE LIBRARY @@ -7392,14 +7458,6 @@ F: Documentation/hwmon/gsc-hwmon.rst F: drivers/hwmon/gsc-hwmon.c F: include/linux/platform_data/gsc_hwmon.h -GASKET DRIVER FRAMEWORK -M: Rob Springer <rspringer@google.com> -M: Todd Poynor <toddpoynor@google.com> -M: Ben Chan <benchan@chromium.org> -M: Richard Yeh <rcy@google.com> -S: Maintained -F: drivers/staging/gasket/ - GCC PLUGINS M: Kees Cook <keescook@chromium.org> L: linux-hardening@vger.kernel.org @@ -7551,6 +7609,12 @@ F: Documentation/filesystems/gfs2* F: fs/gfs2/ F: include/uapi/linux/gfs2_ondisk.h +GIGABYTE WMI DRIVER +M: Thomas Weißschuh <thomas@weissschuh.net> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/gigabyte-wmi.c + GNSS SUBSYSTEM M: Johan Hovold <johan@kernel.org> S: Maintained @@ -7859,6 +7923,7 @@ F: Documentation/hwmon/ F: drivers/hwmon/ F: include/linux/hwmon*.h F: include/trace/events/hwmon*.h +K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info) HARDWARE RANDOM NUMBER GENERATOR CORE M: Matt Mackall <mpm@selenic.com> @@ -7900,6 +7965,11 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/usb/hdpvr/ +HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER +M: Matt Hsiao <matt.hsiao@hpe.com> +S: Supported +F: drivers/misc/hpilo.[ch] + HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER M: Jerry Hoemann <jerry.hoemann@hpe.com> S: Supported @@ -8122,6 +8192,13 @@ F: drivers/crypto/hisilicon/sec2/sec_crypto.c F: drivers/crypto/hisilicon/sec2/sec_crypto.h F: drivers/crypto/hisilicon/sec2/sec_main.c +HISILICON SPI Controller DRIVER FOR KUNPENG SOCS +M: Jay Fang <f.fangjian@huawei.com> +L: linux-spi@vger.kernel.org +S: Maintained +W: http://www.hisilicon.com +F: drivers/spi/spi-hisi-kunpeng.c + HISILICON STAGING DRIVERS FOR HIKEY 960/970 M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> S: Maintained @@ -8216,7 +8293,7 @@ M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> L: linux-iio@vger.kernel.org S: Maintained W: http://www.st.com/ -F: Documentation/devicetree/bindings/iio/humidity/hts221.txt +F: Documentation/devicetree/bindings/iio/humidity/st,hts221.yaml F: drivers/iio/humidity/hts221* HUAWEI ETHERNET DRIVER @@ -8554,7 +8631,8 @@ S: Supported F: drivers/scsi/ibmvscsi/ibmvfc* IBM Power Virtual Management Channel Driver -M: Steven Royer <seroyer@linux.ibm.com> +M: Brad Warrum <bwarrum@linux.ibm.com> +M: Ritu Agarwal <rituagar@linux.ibm.com> S: Supported F: drivers/misc/ibmvmc.* @@ -8612,9 +8690,8 @@ F: drivers/ide/ F: include/linux/ide.h IDE/ATAPI DRIVERS -M: Borislav Petkov <bp@alien8.de> L: linux-ide@vger.kernel.org -S: Maintained +S: Orphan F: Documentation/cdrom/ide-cd.rst F: drivers/ide/ide-cd* @@ -8682,7 +8759,7 @@ M: Peter Rosin <peda@axentia.se> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac -F: Documentation/devicetree/bindings/iio/dac/dpot-dac.txt +F: Documentation/devicetree/bindings/iio/dac/dpot-dac.yaml F: drivers/iio/dac/dpot-dac.c IIO ENVELOPE DETECTOR @@ -8690,7 +8767,7 @@ M: Peter Rosin <peda@axentia.se> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector -F: Documentation/devicetree/bindings/iio/adc/envelope-detector.txt +F: Documentation/devicetree/bindings/iio/adc/envelope-detector.yaml F: drivers/iio/adc/envelope-detector.c IIO MULTIPLEXER @@ -8700,10 +8777,15 @@ S: Maintained F: Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt F: drivers/iio/multiplexer/iio-mux.c +IIO SCMI BASED DRIVER +M: Jyoti Bhayana <jbhayana@google.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/common/scmi_sensors/scmi_iio.c + IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron <jic23@kernel.org> R: Lars-Peter Clausen <lars@metafoo.de> -R: Peter Meerwald-Stadler <pmeerw@pmeerw.net> L: linux-iio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git @@ -8719,9 +8801,9 @@ IIO UNIT CONVERTER M: Peter Rosin <peda@axentia.se> L: linux-iio@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt -F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt -F: Documentation/devicetree/bindings/iio/afe/voltage-divider.txt +F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.yaml +F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.yaml +F: Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml F: drivers/iio/afe/iio-rescale.c IKANOS/ADI EAGLE ADSL USB DRIVER @@ -9149,6 +9231,7 @@ M: Rajneesh Bhardwaj <irenic.rajneesh@gmail.com> M: David E Box <david.e.box@intel.com> L: platform-driver-x86@vger.kernel.org S: Maintained +F: Documentation/ABI/testing/sysfs-platform-intel-pmc F: drivers/platform/x86/intel_pmc_core* INTEL PMIC GPIO DRIVERS @@ -9259,7 +9342,7 @@ W: https://slimbootloader.github.io/security/firmware-update.html F: drivers/platform/x86/intel-wmi-sbl-fw-update.c INTEL WMI THUNDERBOLT FORCE POWER DRIVER -M: Mario Limonciello <mario.limonciello@dell.com> +L: Dell.Client.Kernel@dell.com S: Maintained F: drivers/platform/x86/intel-wmi-thunderbolt.c @@ -9289,6 +9372,7 @@ Q: https://patchwork.kernel.org/project/intel-sgx/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx F: Documentation/x86/sgx.rst F: arch/x86/entry/vdso/vsgx.S +F: arch/x86/include/asm/sgx.h F: arch/x86/include/uapi/asm/sgx.h F: arch/x86/kernel/cpu/sgx/* F: tools/testing/selftests/sgx/* @@ -9298,6 +9382,7 @@ INTERCONNECT API M: Georgi Djakov <djakov@kernel.org> L: linux-pm@vger.kernel.org S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc.git F: Documentation/devicetree/bindings/interconnect/ F: Documentation/driver-api/interconnect.rst F: drivers/interconnect/ @@ -9305,6 +9390,13 @@ F: include/dt-bindings/interconnect/ F: include/linux/interconnect-provider.h F: include/linux/interconnect.h +INTERRUPT COUNTER DRIVER +M: Oleksij Rempel <o.rempel@pengutronix.de> +R: Pengutronix Kernel Team <kernel@pengutronix.de> +L: linux-iio@vger.kernel.org +F: Documentation/devicetree/bindings/counter/interrupt-counter.yaml +F: drivers/counter/interrupt-cnt.c + INVENSENSE ICM-426xx IMU DRIVER M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com> L: linux-iio@vger.kernel.org @@ -9732,6 +9824,11 @@ F: include/uapi/linux/sunrpc/ F: net/sunrpc/ F: Documentation/filesystems/nfs/ +KERNEL REGRESSIONS +M: Thorsten Leemhuis <linux@leemhuis.info> +L: regressions@lists.linux.dev +S: Supported + KERNEL SELFTEST FRAMEWORK M: Shuah Khan <shuah@kernel.org> M: Shuah Khan <skhan@linuxfoundation.org> @@ -9894,6 +9991,14 @@ F: include/keys/trusted-type.h F: include/keys/trusted_tpm.h F: security/keys/trusted-keys/ +KEYS-TRUSTED-TEE +M: Sumit Garg <sumit.garg@linaro.org> +L: linux-integrity@vger.kernel.org +L: keyrings@vger.kernel.org +S: Supported +F: include/keys/trusted_tee.h +F: security/keys/trusted-keys/trusted_tee.c + KEYS/KEYRINGS M: David Howells <dhowells@redhat.com> M: Jarkko Sakkinen <jarkko@kernel.org> @@ -10804,6 +10909,13 @@ S: Orphan F: drivers/video/fbdev/matrox/matroxfb_* F: include/uapi/linux/matroxfb.h +MAX15301 DRIVER +M: Daniel Nilsson <daniel.nilsson@flex.com> +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/max15301.rst +F: drivers/hwmon/pmbus/max15301.c + MAX16065 HARDWARE MONITOR DRIVER M: Guenter Roeck <linux@roeck-us.net> L: linux-hwmon@vger.kernel.org @@ -10883,7 +10995,7 @@ F: drivers/regulator/max77802-regulator.c F: include/dt-bindings/*/*max77802.h MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> L: linux-pm@vger.kernel.org S: Supported @@ -10892,7 +11004,7 @@ F: drivers/power/supply/max77693_charger.c MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS M: Chanwoo Choi <cw00.choi@samsung.com> -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> L: linux-kernel@vger.kernel.org S: Supported @@ -11451,8 +11563,8 @@ Q: https://patchwork.kernel.org/project/netdevbpf/list/ F: drivers/net/ethernet/mellanox/mlxfw/ MELLANOX HARDWARE PLATFORM SUPPORT -M: Andy Shevchenko <andy@infradead.org> -M: Darren Hart <dvhart@infradead.org> +M: Hans de Goede <hdegoede@redhat.com> +M: Mark Gross <mgross@linux.intel.com> M: Vadim Pasternak <vadimp@nvidia.com> L: platform-driver-x86@vger.kernel.org S: Supported @@ -11543,7 +11655,7 @@ F: include/linux/memblock.h F: mm/memblock.c MEMORY CONTROLLER DRIVERS -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git @@ -11811,7 +11923,7 @@ MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER M: Eugen Hristev <eugen.hristev@microchip.com> L: linux-iio@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt +F: Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml F: drivers/iio/adc/at91-sama5d2_adc.c F: include/dt-bindings/iio/adc/at91-sama5d2_adc.h @@ -11875,6 +11987,14 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch] F: include/linux/cciss*.h F: include/uapi/linux/cciss*.h +MICROSOFT SURFACE DTX DRIVER +M: Maximilian Luz <luzmaximilian@gmail.com> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: Documentation/driver-api/surface_aggregator/clients/dtx.rst +F: drivers/platform/surface/surface_dtx.c +F: include/uapi/linux/surface_aggregator/dtx.h + MICROSOFT SURFACE GPE LID SUPPORT DRIVER M: Maximilian Luz <luzmaximilian@gmail.com> L: platform-driver-x86@vger.kernel.org @@ -11896,6 +12016,12 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/surface/surface_hotplug.c +MICROSOFT SURFACE PLATFORM PROFILE DRIVER +M: Maximilian Luz <luzmaximilian@gmail.com> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/surface/surface_platform_profile.c + MICROSOFT SURFACE PRO 3 BUTTON DRIVER M: Chen Yu <yu.c.chen@intel.com> L: platform-driver-x86@vger.kernel.org @@ -11911,6 +12037,7 @@ F: Documentation/driver-api/surface_aggregator/ F: drivers/platform/surface/aggregator/ F: drivers/platform/surface/surface_acpi_notify.c F: drivers/platform/surface/surface_aggregator_cdev.c +F: drivers/platform/surface/surface_aggregator_registry.c F: include/linux/surface_acpi_notify.h F: include/linux/surface_aggregator/ F: include/uapi/linux/surface_aggregator/ @@ -12102,8 +12229,7 @@ F: drivers/media/pci/meye/ F: include/uapi/linux/meye.h MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD -M: Jiri Slaby <jirislaby@kernel.org> -S: Maintained +S: Orphan F: Documentation/driver-api/serial/moxa-smartio.rst F: drivers/tty/mxser.* @@ -12247,11 +12373,6 @@ F: drivers/mux/ F: include/dt-bindings/mux/ F: include/linux/mux/ -MULTITECH MULTIPORT CARD (ISICOM) -S: Orphan -F: drivers/tty/isicom.c -F: include/linux/isicom.h - MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER M: Bin Liu <b-liu@ti.com> L: linux-usb@vger.kernel.org @@ -12887,7 +13008,7 @@ F: Documentation/devicetree/bindings/regulator/nxp,pf8x00-regulator.yaml F: drivers/regulator/pf8x00-regulator.c NXP PTN5150A CC LOGIC AND EXTCON DRIVER -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml @@ -12930,6 +13051,13 @@ L: linux-nfc@lists.01.org (moderated for non-subscribers) S: Supported F: drivers/nfc/nxp-nci +NZXT-KRAKEN2 HARDWARE MONITORING DRIVER +M: Jonas Malaco <jonas@protocubo.io> +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/nzxt-kraken2.rst +F: drivers/hwmon/nzxt-kraken2.c + OBJAGG M: Jiri Pirko <jiri@nvidia.com> L: netdev@vger.kernel.org @@ -14178,7 +14306,7 @@ F: drivers/pinctrl/renesas/ PIN CONTROLLER - SAMSUNG M: Tomasz Figa <tomasz.figa@gmail.com> -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Sylwester Nawrocki <s.nawrocki@samsung.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org @@ -14299,7 +14427,7 @@ PNI RM3100 IIO DRIVER M: Song Qiang <songqiang1304521@gmail.com> L: linux-iio@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt +F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.yaml F: drivers/iio/magnetometer/rm3100* PNP SUPPORT @@ -14334,6 +14462,15 @@ F: include/linux/pm_* F: include/linux/powercap.h F: kernel/configs/nopm.config +DYNAMIC THERMAL POWER MANAGEMENT (DTPM) +M: Daniel Lezcano <daniel.lezcano@kernel.org> +L: linux-pm@vger.kernel.org +S: Supported +B: https://bugzilla.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm +F: drivers/powercap/dtpm* +F: include/linux/dtpm.h + POWER STATE COORDINATION INTERFACE (PSCI) M: Mark Rutland <mark.rutland@arm.com> M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> @@ -15281,7 +15418,7 @@ RENESAS R-CAR GYROADC DRIVER M: Marek Vasut <marek.vasut@gmail.com> L: linux-iio@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt +F: Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml F: drivers/iio/adc/rcar-gyroadc.c RENESAS R-CAR I2C DRIVERS @@ -15434,12 +15571,6 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/rocker/ -ROCKETPORT DRIVER -S: Maintained -W: http://www.comtrol.com -F: Documentation/driver-api/serial/rocket.rst -F: drivers/tty/rocket* - ROCKETPORT EXPRESS/INFINITY DRIVER M: Kevin Cernekee <cernekee@gmail.com> L: linux-serial@vger.kernel.org @@ -15745,7 +15876,7 @@ F: Documentation/admin-guide/LSM/SafeSetID.rst F: security/safesetid/ SAMSUNG AUDIO (ASoC) DRIVERS -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Sylwester Nawrocki <s.nawrocki@samsung.com> L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported @@ -15753,7 +15884,7 @@ F: Documentation/devicetree/bindings/sound/samsung* F: sound/soc/samsung/ SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> L: linux-crypto@vger.kernel.org L: linux-samsung-soc@vger.kernel.org S: Maintained @@ -15788,7 +15919,7 @@ S: Maintained F: drivers/platform/x86/samsung-laptop.c SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> L: linux-kernel@vger.kernel.org L: linux-samsung-soc@vger.kernel.org @@ -15813,7 +15944,7 @@ F: drivers/media/platform/s3c-camif/ F: include/media/drv-intf/s3c_camif.h SAMSUNG S3FWRN5 NFC DRIVER -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Krzysztof Opasiak <k.opasiak@samsung.com> L: linux-nfc@lists.01.org (moderated for non-subscribers) S: Maintained @@ -15833,7 +15964,7 @@ S: Supported F: drivers/media/i2c/s5k5baf.c SAMSUNG S5P Security SubSystem (SSS) DRIVER -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Vladimir Zapolskiy <vz@mleia.com> L: linux-crypto@vger.kernel.org L: linux-samsung-soc@vger.kernel.org @@ -15865,7 +15996,7 @@ F: include/linux/clk/samsung.h F: include/linux/platform_data/clk-s3c2410.h SAMSUNG SPI DRIVERS -M: Krzysztof Kozlowski <krzk@kernel.org> +M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> M: Andi Shyti <andi@etezian.org> L: linux-spi@vger.kernel.org L: linux-samsung-soc@vger.kernel.org @@ -16628,6 +16759,13 @@ F: drivers/firmware/arm_sdei.c F: include/linux/arm_sdei.h F: include/uapi/linux/arm_sdei.h +SOFTWARE NODES +R: Andy Shevchenko <andriy.shevchenko@linux.intel.com> +R: Heikki Krogerus <heikki.krogerus@linux.intel.com> +L: linux-acpi@vger.kernel.org +S: Maintained +F: drivers/base/swnode.c + SOFTWARE RAID (Multiple Disks) SUPPORT M: Song Liu <song@kernel.org> L: linux-raid@vger.kernel.org @@ -16890,6 +17028,8 @@ F: arch/arm/mach-spear/ SPI NOR SUBSYSTEM M: Tudor Ambarus <tudor.ambarus@microchip.com> +R: Michael Walle <michael@walle.cc> +R: Pratyush Yadav <p.yadav@ti.com> L: linux-mtd@lists.infradead.org S: Maintained W: http://www.linux-mtd.infradead.org/ @@ -16959,7 +17099,7 @@ M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> L: linux-iio@vger.kernel.org S: Maintained W: http://www.st.com/ -F: Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +F: Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml F: drivers/iio/imu/st_lsm6dsx/ ST MIPID02 CSI-2 TO PARALLEL BRIDGE DRIVER @@ -16977,11 +17117,18 @@ L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-stm32* +ST STPDDC60 DRIVER +M: Daniel Nilsson <daniel.nilsson@flex.com> +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/stpddc60.rst +F: drivers/hwmon/pmbus/stpddc60.c + ST VL53L0X ToF RANGER(I2C) IIO DRIVER M: Song Qiang <songqiang1304521@gmail.com> L: linux-iio@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/iio/proximity/vl53l0x.txt +F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml F: drivers/iio/proximity/vl53l0x-i2c.c STABLE BRANCH @@ -16998,12 +17145,6 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/staging/media/atomisp/ -STAGING - COMEDI -M: Ian Abbott <abbotti@mev.co.uk> -M: H Hartley Sweeten <hsweeten@visionengravers.com> -S: Odd Fixes -F: drivers/staging/comedi/ - STAGING - FIELDBUS SUBSYSTEM M: Sven Van Asbroeck <TheSven73@gmail.com> S: Maintained @@ -17717,7 +17858,7 @@ TEXAS INSTRUMENTS' DAC7612 DAC DRIVER M: Ricardo Ribalda <ribalda@kernel.org> L: linux-iio@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt +F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml F: drivers/iio/dac/ti-dac7612.c TEXAS INSTRUMENTS DMA DRIVERS @@ -17859,6 +18000,13 @@ M: Robert Richter <rric@kernel.org> S: Odd Fixes F: drivers/gpio/gpio-thunderx.c +TI ADS131E0X ADC SERIES DRIVER +M: Tomislav Denis <tomislav.denis@avl.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml +F: drivers/iio/adc/ti-ads131e08.c + TI AM437X VPFE DRIVER M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com> L: linux-media@vger.kernel.org diff --git a/Makefile b/Makefile index 9abf24c09d284a2a017abc717398297d91ee6487..225b8e433ccef66a6e4c5c81a379835323397dbd 100644 --- a/Makefile +++ b/Makefile @@ -830,6 +830,10 @@ KBUILD_CFLAGS += -ftrivial-auto-var-init=zero KBUILD_CFLAGS += -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang endif +# While VLAs have been removed, GCC produces unreachable stack probes +# for the randomize_kstack_offset feature. Disable it for all compilers. +KBUILD_CFLAGS += $(call cc-option, -fno-stack-clash-protection) + DEBUG_CFLAGS := # Workaround for GCC versions < 5.0 @@ -937,6 +941,23 @@ KBUILD_AFLAGS += -fno-lto export CC_FLAGS_LTO endif +ifdef CONFIG_CFI_CLANG +CC_FLAGS_CFI := -fsanitize=cfi \ + -fsanitize-cfi-cross-dso \ + -fno-sanitize-cfi-canonical-jump-tables \ + -fno-sanitize-trap=cfi \ + -fno-sanitize-blacklist + +ifdef CONFIG_CFI_PERMISSIVE +CC_FLAGS_CFI += -fsanitize-recover=cfi +endif + +# If LTO flags are filtered out, we must also filter out CFI. +CC_FLAGS_LTO += $(CC_FLAGS_CFI) +KBUILD_CFLAGS += $(CC_FLAGS_CFI) +export CC_FLAGS_CFI +endif + ifdef CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B KBUILD_CFLAGS += -falign-functions=32 endif diff --git a/arch/Kconfig b/arch/Kconfig index ecfd3520b676b014ee9d1dbddd181b4fd37e73bb..5bc98d28a6e01059c958c813e1953ba72fb2af93 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -692,6 +692,51 @@ config LTO_CLANG_THIN If unsure, say Y. endchoice +config ARCH_SUPPORTS_CFI_CLANG + bool + help + An architecture should select this option if it can support Clang's + Control-Flow Integrity (CFI) checking. + +config CFI_CLANG + bool "Use Clang's Control Flow Integrity (CFI)" + depends on LTO_CLANG && ARCH_SUPPORTS_CFI_CLANG + # Clang >= 12: + # - https://bugs.llvm.org/show_bug.cgi?id=46258 + # - https://bugs.llvm.org/show_bug.cgi?id=47479 + depends on CLANG_VERSION >= 120000 + select KALLSYMS + help + This option enables Clang’s forward-edge Control Flow Integrity + (CFI) checking, where the compiler injects a runtime check to each + indirect function call to ensure the target is a valid function with + the correct static type. This restricts possible call targets and + makes it more difficult for an attacker to exploit bugs that allow + the modification of stored function pointers. More information can be + found from Clang's documentation: + + https://clang.llvm.org/docs/ControlFlowIntegrity.html + +config CFI_CLANG_SHADOW + bool "Use CFI shadow to speed up cross-module checks" + default y + depends on CFI_CLANG && MODULES + help + If you select this option, the kernel builds a fast look-up table of + CFI check functions in loaded modules to reduce performance overhead. + + If unsure, say Y. + +config CFI_PERMISSIVE + bool "Use CFI in permissive mode" + depends on CFI_CLANG + help + When selected, Control Flow Integrity (CFI) violations result in a + warning instead of a kernel panic. This option should only be used + for finding indirect call type mismatches during development. + + If unsure, say N. + config HAVE_ARCH_WITHIN_STACK_FRAMES bool help @@ -1054,6 +1099,29 @@ config VMAP_STACK backing virtual mappings with real shadow memory, and KASAN_VMALLOC must be enabled. +config HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET + def_bool n + help + An arch should select this symbol if it can support kernel stack + offset randomization with calls to add_random_kstack_offset() + during syscall entry and choose_random_kstack_offset() during + syscall exit. Careful removal of -fstack-protector-strong and + -fstack-protector should also be applied to the entry code and + closely examined, as the artificial stack bump looks like an array + to the compiler, so it will attempt to add canary checks regardless + of the static branch state. + +config RANDOMIZE_KSTACK_OFFSET_DEFAULT + bool "Randomize kernel stack offset on syscall entry" + depends on HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET + help + The kernel stack offset can be randomized (after pt_regs) by + roughly 5 bits of entropy, frustrating memory corruption + attacks that depend on stack address determinism or + cross-syscall address exposures. This feature is controlled + by kernel boot param "randomize_kstack_offset=on/off", and this + config chooses the default boot state. + config ARCH_OPTIONAL_KERNEL_RWX def_bool n diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a680c78cf7edbe6f15d3fc98d65056daa128fb25..b1d991051d068e2bc44a31a1ed9897e7ff37452d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1326,7 +1326,7 @@ config ARM_PSCI # selected platforms. config ARCH_NR_GPIO int - default 2048 if ARCH_SOCFPGA + default 2048 if ARCH_INTEL_SOCFPGA default 1024 if ARCH_BRCMSTB || ARCH_RENESAS || ARCH_TEGRA || \ ARCH_ZYNQ || ARCH_ASPEED default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \ diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 9e0b5e7f12af69dca9c9dd32ce6c750574e71ccd..36016497b1b3fcdca10bee2d43016c4c908be12f 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1087,7 +1087,7 @@ choice on SD5203 UART. config DEBUG_SOCFPGA_UART0 - depends on ARCH_SOCFPGA + depends on ARCH_INTEL_SOCFPGA bool "Use SOCFPGA UART0 for low-level debug" select DEBUG_UART_8250 help @@ -1095,7 +1095,7 @@ choice on SOCFPGA(Cyclone 5 and Arria 5) based platforms. config DEBUG_SOCFPGA_ARRIA10_UART1 - depends on ARCH_SOCFPGA + depends on ARCH_INTEL_SOCFPGA bool "Use SOCFPGA Arria10 UART1 for low-level debug" select DEBUG_UART_8250 help @@ -1103,7 +1103,7 @@ choice on SOCFPGA(Arria 10) based platforms. config DEBUG_SOCFPGA_CYCLONE5_UART1 - depends on ARCH_SOCFPGA + depends on ARCH_INTEL_SOCFPGA bool "Use SOCFPGA Cyclone 5 UART1 for low-level debug" select DEBUG_UART_8250 help diff --git a/arch/arm/Makefile b/arch/arm/Makefile index dad5502ecc28c5b48039c2d238d0d173b0858502..415c3514573ac9c7158a4a01b0f53d5e4d77b7b4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -209,7 +209,7 @@ machine-$(CONFIG_PLAT_SAMSUNG) += s3c machine-$(CONFIG_ARCH_S5PV210) += s5pv210 machine-$(CONFIG_ARCH_SA1100) += sa1100 machine-$(CONFIG_ARCH_RENESAS) += shmobile -machine-$(CONFIG_ARCH_SOCFPGA) += socfpga +machine-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga machine-$(CONFIG_ARCH_STI) += sti machine-$(CONFIG_ARCH_STM32) += stm32 machine-$(CONFIG_ARCH_SUNXI) += sunxi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 8e5d4ab4e75e6e027309e6dd6583d7ea5ac25b86..f8f09c5066e7509948d4b0cf351b953141ef435e 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -333,8 +333,11 @@ dtb-$(CONFIG_ARCH_LPC18XX) += \ dtb-$(CONFIG_ARCH_LPC32XX) += \ lpc3250-ea3250.dtb \ lpc3250-phy3250.dtb +dtb-$(CONFIG_ARCH_WPCM450) += \ + nuvoton-wpcm450-supermicro-x9sci-ln4f.dtb dtb-$(CONFIG_ARCH_NPCM7XX) += \ nuvoton-npcm730-gsj.dtb \ + nuvoton-npcm730-gbs.dtb \ nuvoton-npcm730-kudo.dtb \ nuvoton-npcm750-evb.dtb \ nuvoton-npcm750-runbmc-olympus.dtb @@ -660,6 +663,7 @@ dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-pico-hobbit.dtb \ imx7d-pico-nymph.dtb \ imx7d-pico-pi.dtb \ + imx7d-remarkable2.dtb \ imx7d-sbc-imx7.dtb \ imx7d-sdb.dtb \ imx7d-sdb-reva.dtb \ @@ -929,7 +933,9 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8974-sony-xperia-castor.dtb \ qcom-msm8974-sony-xperia-honami.dtb \ qcom-mdm9615-wp8548-mangoh-green.dtb \ - qcom-sdx55-mtp.dtb + qcom-sdx55-mtp.dtb \ + qcom-sdx55-t55.dtb \ + qcom-sdx55-telit-fn980-tlb.dtb dtb-$(CONFIG_ARCH_RDA) += \ rda8810pl-orangepi-2g-iot.dtb \ rda8810pl-orangepi-i96.dtb @@ -1033,7 +1039,7 @@ dtb-$(CONFIG_ARCH_S5PV210) += \ s5pv210-smdkc110.dtb \ s5pv210-smdkv210.dtb \ s5pv210-torbreck.dtb -dtb-$(CONFIG_ARCH_SOCFPGA) += \ +dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += \ socfpga_arria5_socdk.dtb \ socfpga_arria10_socdk_nand.dtb \ socfpga_arria10_socdk_qspi.dtb \ @@ -1071,11 +1077,16 @@ dtb-$(CONFIG_ARCH_STM32) += \ stm32746g-eval.dtb \ stm32h743i-eval.dtb \ stm32h743i-disco.dtb \ + stm32h750i-art-pi.dtb \ stm32mp153c-dhcom-drc02.dtb \ stm32mp157a-avenger96.dtb \ stm32mp157a-dhcor-avenger96.dtb \ stm32mp157a-dk1.dtb \ stm32mp157a-iot-box.dtb \ + stm32mp157a-microgea-stm32mp1-microdev2.0.dtb \ + stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dtb \ + stm32mp157a-icore-stm32mp1-ctouch2.dtb \ + stm32mp157a-icore-stm32mp1-edimm2.2.dtb \ stm32mp157a-stinger96.dtb \ stm32mp157c-dhcom-pdk2.dtb \ stm32mp157c-dhcom-picoitx.dtb \ @@ -1105,7 +1116,8 @@ dtb-$(CONFIG_MACH_SUN4I) += \ sun4i-a10-olinuxino-lime.dtb \ sun4i-a10-pcduino.dtb \ sun4i-a10-pcduino2.dtb \ - sun4i-a10-pov-protab2-ips9.dtb + sun4i-a10-pov-protab2-ips9.dtb \ + sun4i-a10-topwise-a721.dtb dtb-$(CONFIG_MACH_SUN5I) += \ sun5i-a10s-auxtek-t003.dtb \ sun5i-a10s-auxtek-t004.dtb \ @@ -1337,6 +1349,7 @@ dtb-$(CONFIG_MACH_ARMADA_375) += \ armada-375-db.dtb dtb-$(CONFIG_MACH_ARMADA_38X) += \ armada-382-rd-ac3x-48g4x2xl.dtb \ + armada-385-atl-x530.dtb\ armada-385-clearfog-gtr-s4.dtb \ armada-385-clearfog-gtr-l8.dtb \ armada-385-db-88f6820-amc.dtb \ @@ -1397,6 +1410,7 @@ dtb-$(CONFIG_ARCH_MILBEAUT) += milbeaut-m10v-evb.dtb dtb-$(CONFIG_ARCH_MSTARV7) += \ mstar-infinity-msc313-breadbee_crust.dtb \ mstar-infinity2m-ssd202d-ssd201htv2.dtb \ + mstar-infinity2m-ssd202d-unitv2.dtb \ mstar-infinity3-msc313e-breadbee.dtb \ mstar-mercury5-ssc8336n-midrived08.dtb dtb-$(CONFIG_ARCH_ASPEED) += \ @@ -1406,6 +1420,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-ampere-mtjade.dtb \ aspeed-bmc-arm-centriq2400-rep.dtb \ aspeed-bmc-arm-stardragon4800-rep2.dtb \ + aspeed-bmc-asrock-e3c246d4i.dtb \ aspeed-bmc-bytedance-g220a.dtb \ aspeed-bmc-facebook-cmm.dtb \ aspeed-bmc-facebook-galaxy100.dtb \ @@ -1418,6 +1433,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-facebook-yosemitev2.dtb \ aspeed-bmc-ibm-everest.dtb \ aspeed-bmc-ibm-rainier.dtb \ + aspeed-bmc-ibm-rainier-1s4u.dtb \ aspeed-bmc-ibm-rainier-4u.dtb \ aspeed-bmc-intel-s2600wf.dtb \ aspeed-bmc-inspur-fp5280g2.dtb \ diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index b4feb85e171adc994a1be2b42c09eb6752126608..e2ee8b8c07bc5ebe41791e39fccf4daab3e1e579 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -26,54 +26,54 @@ &gpio0 { gpio-line-names = - "[ethernet]", - "[ethernet]", + "[mdio_data]", + "[mdio_clk]", "P9_22 [spi0_sclk]", "P9_21 [spi0_d0]", "P9_18 [spi0_d1]", "P9_17 [spi0_cs0]", - "[sd card]", - "P9_42A [ecappwm0]", - "P8_35 [hdmi]", - "P8_33 [hdmi]", - "P8_31 [hdmi]", - "P8_32 [hdmi]", + "[mmc0_cd]", + "P8_42A [ecappwm0]", + "P8_35 [lcd d12]", + "P8_33 [lcd d13]", + "P8_31 [lcd d14]", + "P8_32 [lcd d15]", "P9_20 [i2c2_sda]", "P9_19 [i2c2_scl]", "P9_26 [uart1_rxd]", "P9_24 [uart1_txd]", - "[ethernet]", - "[ethernet]", - "[usb]", - "[hdmi]", + "[rmii1_txd3]", + "[rmii1_txd2]", + "[usb0_drvvbus]", + "[hdmi cec]", "P9_41B", - "[ethernet]", + "[rmii1_txd1]", "P8_19 [ehrpwm2a]", "P8_13 [ehrpwm2b]", - "[NC]", - "[NC]", + "NC", + "NC", "P8_14", "P8_17", - "[ethernet]", - "[ethernet]", + "[rmii1_txd0]", + "[rmii1_refclk]", "P9_11 [uart4_rxd]", "P9_13 [uart4_txd]"; }; &gpio1 { gpio-line-names = - "P8_25 [emmc]", - "[emmc]", - "P8_5 [emmc]", - "P8_6 [emmc]", - "P8_23 [emmc]", - "P8_22 [emmc]", - "P8_3 [emmc]", - "P8_4 [emmc]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", + "P8_25 [mmc1_dat0]", + "[mmc1_dat1]", + "P8_5 [mmc1_dat2]", + "P8_6 [mmc1_dat3]", + "P8_23 [mmc1_dat4]", + "P8_22 [mmc1_dat5]", + "P8_3 [mmc1_dat6]", + "P8_4 [mmc1_dat7]", + "NC", + "NC", + "NC", + "NC", "P8_12", "P8_11", "P8_16", @@ -82,13 +82,13 @@ "P9_23", "P9_14 [ehrpwm1a]", "P9_16 [ehrpwm1b]", - "[emmc]", + "[emmc rst]", "[usr0 led]", "[usr1 led]", "[usr2 led]", "[usr3 led]", - "[hdmi]", - "[usb]", + "[hdmi irq]", + "[usb vbus oc]", "[hdmi audio]", "P9_12", "P8_26", @@ -116,38 +116,38 @@ "P8_38 [hdmi]", "P8_36 [hdmi]", "P8_34 [hdmi]", - "[ethernet]", - "[ethernet]", - "[ethernet]", - "[ethernet]", + "[rmii1_rxd3]", + "[rmii1_rxd2]", + "[rmii1_rxd1]", + "[rmii1_rxd0]", "P8_27 [hdmi]", "P8_29 [hdmi]", "P8_28 [hdmi]", "P8_30 [hdmi]", - "[emmc]", - "[emmc]", - "[emmc]", - "[emmc]", - "[emmc]", - "[emmc]"; + "[mmc0_dat3]", + "[mmc0_dat2]", + "[mmc0_dat1]", + "[mmc0_dat0]", + "[mmc0_clk]", + "[mmc0_cmd]"; }; &gpio3 { gpio-line-names = - "[ethernet]", - "[ethernet]", - "[ethernet]", - "[ethernet]", - "[ethernet]", - "[i2c0]", - "[i2c0]", - "[emu]", - "[emu]", - "[ethernet]", - "[ethernet]", - "[NC]", - "[NC]", - "[usb]", + "[mii col]", + "[mii crs]", + "[mii rx err]", + "[mii tx en]", + "[mii rx dv]", + "[i2c0 sda]", + "[i2c0 scl]", + "[jtag emu0]", + "[jtag emu1]", + "[mii tx clk]", + "[mii rx clk]", + "NC", + "NC", + "[usb vbus en]", "P9_31 [spi1_sclk]", "P9_29 [spi1_d0]", "P9_30 [spi1_d1]", @@ -156,14 +156,14 @@ "P9_27", "P9_41A", "P9_25", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]"; + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC"; }; diff --git a/arch/arm/boot/dts/am335x-pocketbeagle.dts b/arch/arm/boot/dts/am335x-pocketbeagle.dts index d526c5941c9b1730eff4d8ee1d4a3287d0841239..209cdd17dc1e9878b65df105829b94f03d2a9887 100644 --- a/arch/arm/boot/dts/am335x-pocketbeagle.dts +++ b/arch/arm/boot/dts/am335x-pocketbeagle.dts @@ -61,51 +61,51 @@ &gpio0 { gpio-line-names = - "[NC]", - "[NC]", + "NC", + "NC", "P1.08 [SPI0_CLK]", "P1.10 [SPI0_MISO]", "P1.12 [SPI0_MOSI]", "P1.06 [SPI0_CS]", "[MMC0_CD]", "P2.29 [SPI1_CLK]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", + "[SYSBOOT 12]", + "[SYSBOOT 13]", + "[SYSBOOT 14]", + "[SYSBOOT 15]", "P1.26 [I2C2_SDA]", "P1.28 [I2C2_SCL]", "P2.11 [I2C1_SDA]", "P2.09 [I2C1_SCL]", - "[NC]", - "[NC]", - "[NC]", + "NC", + "NC", + "NC", "P2.31 [SPI1_CS]", "P1.20 [PRU0.16]", - "[NC]", - "[NC]", + "NC", + "NC", "P2.03", - "[NC]", - "[NC]", + "NC", + "NC", "P1.34", "P2.19", - "[NC]", - "[NC]", + "NC", + "NC", "P2.05 [UART4_RX]", "P2.07 [UART4_TX]"; }; &gpio1 { gpio-line-names = - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", "P2.25 [SPI1_MOSI]", "P1.32 [UART0_RX]", "P1.30 [UART0_TX]", @@ -113,10 +113,10 @@ "P2.33", "P2.22", "P2.18", - "[NC]", - "[NC]", + "NC", + "NC", "P2.01 [PWM1A]", - "[NC]", + "NC", "P2.10", "[USR LED 0]", "[USR LED 1]", @@ -126,35 +126,35 @@ "P2.04", "P2.02", "P2.08", - "[NC]", - "[NC]", - "[NC]"; + "NC", + "NC", + "NC"; }; &gpio2 { gpio-line-names = "P2.20", "P2.17", - "[NC]", - "[NC]", - "[NC]", + "NC", + "NC", + "NC", "[EEPROM_WP]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[SYSBOOT]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", + "[SYSBOOT 0]", + "[SYSBOOT 1]", + "[SYSBOOT 2]", + "[SYSBOOT 3]", + "[SYSBOOT 4]", + "[SYSBOOT 5]", + "[SYSBOOT 6]", + "[SYSBOOT 7]", + "[SYSBOOT 8]", + "[SYSBOOT 9]", + "[SYSBOOT 10]", + "[SYSBOOT 11]", + "NC", + "NC", + "NC", + "NC", "P2.35 [AIN5]", "P1.02 [AIN6]", "P1.35 [PRU1.10]", @@ -169,19 +169,19 @@ &gpio3 { gpio-line-names = - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", + "NC", + "NC", + "NC", + "NC", + "NC", "[I2C0_SDA]", "[I2C0_SCL]", - "[JTAG]", - "[JTAG]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", + "[JTAG EMU0]", + "[JTAG EMU1]", + "NC", + "NC", + "NC", + "NC", "P1.03 [USB1]", "P1.36 [PWM0A]", "P1.33 [PRU0.1]", @@ -191,16 +191,16 @@ "P2.34 [PRU0.5]", "P2.28 [PRU0.6]", "P1.29 [PRU0.7]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]", - "[NC]"; + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC"; }; &am33xx_pinmux { diff --git a/arch/arm/boot/dts/am33xx-l4.dtsi b/arch/arm/boot/dts/am33xx-l4.dtsi index 1fb22088caebbc1eb5925752d726061ce88aa5f1..039a9ab4c7eaaab8f9b1126f6558fbbbd761cb66 100644 --- a/arch/arm/boot/dts/am33xx-l4.dtsi +++ b/arch/arm/boot/dts/am33xx-l4.dtsi @@ -259,22 +259,22 @@ ranges = <0x00000000 0x0000d000 0x00001000>, <0x00001000 0x0000e000 0x00001000>; - tscadc: tscadc@0 { - compatible = "ti,am3359-tscadc"; - reg = <0x0 0x1000>; - interrupts = <16>; - status = "disabled"; - dmas = <&edma 53 0>, <&edma 57 0>; - dma-names = "fifo0", "fifo1"; + tscadc: tscadc@0 { + compatible = "ti,am3359-tscadc"; + reg = <0x0 0x1000>; + interrupts = <16>; + status = "disabled"; + dmas = <&edma 53 0>, <&edma 57 0>; + dma-names = "fifo0", "fifo1"; - tsc { - compatible = "ti,am3359-tsc"; - }; - am335x_adc: adc { - #io-channel-cells = <1>; - compatible = "ti,am3359-adc"; - }; + tsc { + compatible = "ti,am3359-tsc"; + }; + am335x_adc: adc { + #io-channel-cells = <1>; + compatible = "ti,am3359-adc"; }; + }; }; target-module@10000 { /* 0x44e10000, ap 22 0c.0 */ diff --git a/arch/arm/boot/dts/armada-385-atl-x530.dts b/arch/arm/boot/dts/armada-385-atl-x530.dts new file mode 100644 index 0000000000000000000000000000000000000000..ed3f41c7df7152d4c949a510fa3ae73af1de1dda --- /dev/null +++ b/arch/arm/boot/dts/armada-385-atl-x530.dts @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Device Tree file for Armada 385 Allied Telesis x530/GS980MX Board. + (x530/AT-GS980MX) + * + Copyright (C) 2020 Allied Telesis Labs + */ + +/dts-v1/; +#include "armada-385.dtsi" + +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "x530/AT-GS980MX"; + compatible = "alliedtelesis,gs980mx", "alliedtelesis,x530", "marvell,armada385", "marvell,armada380"; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; /* 1GB */ + }; + + soc { + ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000 + MBUS_ID(0x01, 0x3d) 0 0xf4800000 0x80000 + MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>; + + internal-regs { + i2c0: i2c@11000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + }; + + uart0: serial@12000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; + }; + }; + }; +}; + +&pciec { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + reset-gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; + reset-delay-us = <400000>; +}; + +&pcie2 { + status = "okay"; +}; + +&devbus_cs1 { + compatible = "marvell,mvebu-devbus"; + status = "okay"; + + devbus,bus-width = <8>; + devbus,turn-off-ps = <60000>; + devbus,badr-skew-ps = <0>; + devbus,acc-first-ps = <124000>; + devbus,acc-next-ps = <248000>; + devbus,rd-setup-ps = <0>; + devbus,rd-hold-ps = <0>; + + /* Write parameters */ + devbus,sync-enable = <0>; + devbus,wr-high-ps = <60000>; + devbus,wr-low-ps = <60000>; + devbus,ale-wr-ps = <60000>; + + nvs@0 { + status = "okay"; + + compatible = "mtd-ram"; + reg = <0 0x00080000>; + bank-width = <1>; + label = "nvs"; + }; +}; + +&pinctrl { + i2c0_gpio_pins: i2c-gpio-pins-0 { + marvell,pins = "mpp2", "mpp3"; + marvell,function = "gpio"; + }; +}; + +&i2c0 { + clock-frequency = <100000>; + status = "okay"; + + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&i2c0_pins>; + pinctrl-1 = <&i2c0_gpio_pins>; + scl-gpio = <&gpio0 2 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + sda-gpio = <&gpio0 3 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + i2c0mux: mux@71 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9544"; + reg = <0x71>; + i2c-mux-idle-disconnect; + + i2c@0 { /* POE devices MUX */ + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + adt7476_2e: hwmon@2e { + compatible = "adi,adt7476"; + reg = <0x2e>; + }; + + adt7476_2d: hwmon@2d { + compatible = "adi,adt7476"; + reg = <0x2d>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + rtc@68 { + compatible = "dallas,ds1340"; + reg = <0x68>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + gpio@20 { + compatible = "nxp,pca9554"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; +}; + +&usb0 { + status = "okay"; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; + status = "okay"; + + spi-flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <1>; /* Chip select 1 */ + spi-max-frequency = <54000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + partition@u-boot { + reg = <0x00000000 0x00100000>; + label = "u-boot"; + }; + partition@u-boot-env { + reg = <0x00100000 0x00040000>; + label = "u-boot-env"; + }; + partition@unused { + reg = <0x00140000 0x00e80000>; + label = "unused"; + }; + partition@idprom { + reg = <0x00fc0000 0x00040000>; + label = "idprom"; + }; + }; + }; +}; + +&nand_controller { + status = "okay"; + + nand@0 { + reg = <0>; + label = "pxa3xx_nand-0"; + nand-rb = <0>; + nand-on-flash-bbt; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + + marvell,nand-enable-arbiter; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + partition@user { + reg = <0x00000000 0x0f000000>; + label = "user"; + }; + partition@errlog { + /* Maximum mtdoops size is 8MB, so set to that. */ + reg = <0x0f000000 0x00800000>; + label = "errlog"; + }; + partition@nand-bbt { + reg = <0x0f800000 0x00800000>; + label = "nand-bbt"; + }; + }; + }; +}; + diff --git a/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts b/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts index ac2d04cfaf2f3ab88161c2426a85b87f903145c4..6aeb47c44eba27b06b9680d7e608c2e2409b2788 100644 --- a/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts +++ b/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts @@ -151,6 +151,31 @@ status = "okay"; }; +//FPGA +&i2c2 { + status = "okay"; +}; + +//24LC128 EEPROM +&i2c3 { + status = "okay"; +}; + +//P0 Power regulators +&i2c4 { + status = "okay"; +}; + +//P1 Power regulators +&i2c5 { + status = "okay"; +}; + +//P0/P1 Thermal diode +&i2c6 { + status = "okay"; +}; + // Thermal Sensors &i2c7 { status = "okay"; @@ -196,6 +221,11 @@ }; }; +//BMC I2C +&i2c8 { + status = "okay"; +}; + &kcs1 { status = "okay"; aspeed,lpc-io-reg = <0x60>; diff --git a/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts b/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts new file mode 100644 index 0000000000000000000000000000000000000000..dcab6e78dfa4107e0eb0633163ef8dfc5174a58c --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +#include "aspeed-g5.dtsi" +#include <dt-bindings/gpio/aspeed-gpio.h> +#include <dt-bindings/i2c/i2c.h> + +/{ + model = "ASRock E3C246D4I BMC"; + compatible = "asrock,e3c246d4i-bmc", "aspeed,ast2500"; + + aliases { + serial4 = &uart5; + }; + + chosen { + stdout-path = &uart5; + bootargs = "console=tty0 console=ttyS4,115200 earlyprintk"; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; + + leds { + compatible = "gpio-leds"; + + heartbeat { + /* BMC_HB_LED_N */ + gpios = <&gpio ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>; + linux,default-trigger = "timer"; + }; + + system-fault { + /* SYSTEM_FAULT_LED_N */ + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>; + panic-indicator; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + uid-button { + label = "uid-button"; + gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>; + linux,code = <ASPEED_GPIO(F, 1)>; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>, + <&adc 5>, <&adc 6>, <&adc 7>, <&adc 8>, <&adc 9>, + <&adc 10>, <&adc 11>, <&adc 12>; + }; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <100000000>; /* 100 MHz */ +#include "openbmc-flash-layout.dtsi" + }; +}; + +&uart5 { + status = "okay"; +}; + +&vuart { + status = "okay"; + aspeed,sirq-active-high; +}; + +&mac0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>; +}; + +&i2c1 { + status = "okay"; + + /* thermal sensor, one diode run to a disconnected header */ + w83773g@4c { + compatible = "nuvoton,w83773g"; + reg = <0x4c>; + }; +}; + +&i2c3 { + status = "okay"; + + /* FRU EEPROM */ + eeprom@57 { + compatible = "st,24c128", "atmel,24c128"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +&video { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; + +&lpc_ctrl { + status = "okay"; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&gpio { + status = "okay"; + gpio-line-names = + /* A */ "BMC_MAC1_INTB", "BMC_MAC2_INTB", "NMI_BTN_N", "BMC_NMI", + "", "", "", "", + /* B */ "", "", "", "", "", "IRQ_BMC_PCH_SMI_LPC_N", "", "", + /* C */ "", "", "", "", "", "", "", "", + /* D */ "BMC_PSIN", "BMC_PSOUT", "BMC_RESETCON", "RESETCON", + "", "", "", "", + /* E */ "", "", "", "", "", "", "", "", + /* F */ "LOCATORLED_STATUS_N", "LOCATORBTN", "", "", + "", "", "BMC_PCH_SCI_LPC", "BMC_NCSI_MUX_CTL", + /* G */ "HWM_BAT_EN", "CHASSIS_ID0", "CHASSIS_ID1", "CHASSIS_ID2", + "BMC_ALERT1_N_R", "BMC_ALERT2_N_R", "BMC_ALERT3_N", "SML0ALERT", + /* H */ "FM_ME_RCVR_N", "O_PWROK", "SKL_CNL_R", "D4_DIMM_EVENT_3V_N", + "MFG_MODE_N", "BMC_RTCRST", "BMC_HB_LED_N", "BMC_CASEOPEN", + /* I */ "", "", "", "", "", "", "", "", + /* J */ "BMC_READY", "BMC_PCH_BIOS_CS_N", "BMC_SMI", "", + "", "", "", "", + /* K */ "", "", "", "", "", "", "", "", + /* L */ "BMC_CTS1", "BMC_DCD1", "BMC_DSR1", "BMC_RI1", + "BMC_DTR1", "BMC_RTS1", "BMC_TXD1", "BMC_RXD1", + /* M */ "BMC_LAN0_DIS_N", "BMC_LAN1_DIS_N", "", "", + "", "", "", "", + /* N */ "", "", "", "", "", "", "", "", + /* O */ "", "", "", "", "", "", "", "", + /* P */ "", "", "", "", "", "", "", "", + /* Q */ "", "", "", "", + "BMC_SBM_PRESENT_1_N", "BMC_SBM_PRESENT_2_N", + "BMC_SBM_PRESENT_3_N", "BMC_PCIE_WAKE_N", + /* R */ "", "", "", "", "", "", "", "", + /* S */ "PCHHOT_BMC_N", "", "RSMRST", + "", "", "", "", "", + /* T */ "", "", "", "", "", "", "", "", + /* U */ "", "", "", "", "", "", "", "", + /* V */ "", "", "", "", "", "", "", "", + /* W */ "PS_PWROK", /* dummy always-high signal */ + "", "", "", "", "", "", "", + /* X */ "", "", "", "", "", "", "", "", + /* Y */ "SLP_S3", "SLP_S5", "", "", "", "", "", "", + /* Z */ "CPU_CATERR_BMC_PCH_N", "", "SYSTEM_FAULT_LED_N", "BMC_THROTTLE_N", + "", "", "", "", + /* AA */ "CPU1_THERMTRIP_LATCH_N", "", "CPU1_PROCHOT_N", "", + "", "", "IRQ_SMI_ACTIVE_N", "FM_BIOS_POST_CMPLT_N", + /* AB */ "", "", "ME_OVERRIDE", "BMC_DMI_MODIFY", + "", "", "", "", + /* AC */ "LAD0", "LAD1", "LAD2", "LAD3", + "CK_33M_BMC", "LFRAME", "SERIRQ", "S_PLTRST"; + + /* Assert BMC_READY so BIOS doesn't sit around waiting for it */ + bmc-ready { + gpio-hog; + gpios = <ASPEED_GPIO(J, 0) GPIO_ACTIVE_LOW>; + output-high; + }; +}; + +&adc { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc0_default + &pinctrl_adc1_default + &pinctrl_adc2_default + &pinctrl_adc3_default + &pinctrl_adc4_default + &pinctrl_adc5_default + &pinctrl_adc6_default + &pinctrl_adc7_default + &pinctrl_adc8_default + &pinctrl_adc9_default + &pinctrl_adc10_default + &pinctrl_adc11_default + &pinctrl_adc12_default>; +}; + +&kcs3 { + status = "okay"; + aspeed,lpc-io-reg = <0xca2>; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts index cd18641d5c236e0d3e14e151775742a5357d65e7..7b4b2b126ad849c483c1b67eac368a3847250081 100644 --- a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts @@ -507,6 +507,11 @@ &i2c7 { status = "okay"; //HSC, AirMax Conn A + adm1278@45 { + compatible = "adm1275"; + reg = <0x45>; + shunt-resistor-micro-ohms = <250>; + }; }; &i2c8 { diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts index 6bd876657bb8e39bb676c0cf795e613290a2045d..3295c8c7c05c8cf6c3a2852e5811988b8f25453f 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts @@ -44,6 +44,58 @@ i2c415 = &cfam3_i2c15; i2c416 = &cfam3_i2c16; i2c417 = &cfam3_i2c17; + i2c500 = &cfam4_i2c0; + i2c501 = &cfam4_i2c1; + i2c510 = &cfam4_i2c10; + i2c511 = &cfam4_i2c11; + i2c512 = &cfam4_i2c12; + i2c513 = &cfam4_i2c13; + i2c514 = &cfam4_i2c14; + i2c515 = &cfam4_i2c15; + i2c602 = &cfam5_i2c2; + i2c603 = &cfam5_i2c3; + i2c610 = &cfam5_i2c10; + i2c611 = &cfam5_i2c11; + i2c614 = &cfam5_i2c14; + i2c615 = &cfam5_i2c15; + i2c616 = &cfam5_i2c16; + i2c617 = &cfam5_i2c17; + i2c700 = &cfam6_i2c0; + i2c701 = &cfam6_i2c1; + i2c710 = &cfam6_i2c10; + i2c711 = &cfam6_i2c11; + i2c712 = &cfam6_i2c12; + i2c713 = &cfam6_i2c13; + i2c714 = &cfam6_i2c14; + i2c715 = &cfam6_i2c15; + i2c802 = &cfam7_i2c2; + i2c803 = &cfam7_i2c3; + i2c810 = &cfam7_i2c10; + i2c811 = &cfam7_i2c11; + i2c814 = &cfam7_i2c14; + i2c815 = &cfam7_i2c15; + i2c816 = &cfam7_i2c16; + i2c817 = &cfam7_i2c17; + + i2c16 = &i2c4mux0chn0; + i2c17 = &i2c4mux0chn1; + i2c18 = &i2c4mux0chn2; + i2c19 = &i2c5mux0chn0; + i2c20 = &i2c5mux0chn1; + i2c21 = &i2c5mux0chn2; + i2c22 = &i2c5mux0chn3; + i2c23 = &i2c6mux0chn0; + i2c24 = &i2c6mux0chn1; + i2c25 = &i2c6mux0chn2; + i2c26 = &i2c6mux0chn3; + i2c27 = &i2c14mux0chn0; + i2c28 = &i2c14mux0chn1; + i2c29 = &i2c14mux0chn2; + i2c30 = &i2c14mux0chn3; + i2c31 = &i2c14mux1chn0; + i2c32 = &i2c14mux1chn1; + i2c33 = &i2c14mux1chn2; + i2c34 = &i2c14mux1chn3; serial4 = &uart5; @@ -63,6 +115,22 @@ spi41 = &cfam3_spi1; spi42 = &cfam3_spi2; spi43 = &cfam3_spi3; + spi50 = &cfam4_spi0; + spi51 = &cfam4_spi1; + spi52 = &cfam4_spi2; + spi53 = &cfam4_spi3; + spi60 = &cfam5_spi0; + spi61 = &cfam5_spi1; + spi62 = &cfam5_spi2; + spi63 = &cfam5_spi3; + spi70 = &cfam6_spi0; + spi71 = &cfam6_spi1; + spi72 = &cfam6_spi2; + spi73 = &cfam6_spi3; + spi80 = &cfam7_spi0; + spi81 = &cfam7_spi1; + spi82 = &cfam7_spi2; + spi83 = &cfam7_spi3; }; chosen { @@ -103,41 +171,1500 @@ reg = <0xbf000000 0x01000000>; /* 16M */ }; }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <1000>; + + fan0-presence { + label = "fan0-presence"; + gpios = <&pca0 15 GPIO_ACTIVE_LOW>; + linux,code = <15>; + }; + + fan1-presence { + label = "fan1-presence"; + gpios = <&pca0 14 GPIO_ACTIVE_LOW>; + linux,code = <14>; + }; + + fan2-presence { + label = "fan2-presence"; + gpios = <&pca0 13 GPIO_ACTIVE_LOW>; + linux,code = <13>; + }; + + fan3-presence { + label = "fan3-presence"; + gpios = <&pca0 12 GPIO_ACTIVE_LOW>; + linux,code = <12>; + }; + }; +}; + +&gpio0 { + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "USERSPACE_RSTIND_BUFF","","","","","","","", + /*C0-C7*/ "","","","","","","","", + /*D0-D7*/ "","","","","","","","", + /*E0-E7*/ "","","","","","","","", + /*F0-F7*/ "PIN_HOLE_RESET_IN_N","","", + "PIN_HOLE_RESET_OUT_N","","","","", + /*G0-G7*/ "","","","","","","","", + /*H0-H7*/ "","","","","","","","", + /*I0-I7*/ "","","","","","","","", + /*J0-J7*/ "","","","","","","","", + /*K0-K7*/ "","","","","","","","", + /*L0-L7*/ "","","","","","","","", + /*M0-M7*/ "","","","","","","","", + /*N0-N7*/ "","","","","","","","", + /*O0-O7*/ "","","","","","","","", + /*P0-P7*/ "","","","","","","","", + /*Q0-Q7*/ "","","","","","","","", + /*R0-R7*/ "","","","","","I2C_FLASH_MICRO_N","","", + /*S0-S7*/ "","","","","","","","", + /*T0-T7*/ "","","","","","","","", + /*U0-U7*/ "","","","","","","","", + /*V0-V7*/ "","BMC_3RESTART_ATTEMPT_P","","","","","","", + /*W0-W7*/ "","","","","","","","", + /*X0-X7*/ "","","","","","","","", + /*Y0-Y7*/ "","","","","","","","", + /*Z0-Z7*/ "","","","","","","",""; +}; + +&i2c0 { + status = "okay"; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + + pca1: pca9552@62 { + compatible = "nxp,pca9552"; + reg = <0x62>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "presence-ps0", + "presence-ps1", + "presence-ps2", + "presence-ps3", + "presence-pdb", + "presence-tpm", + "", "", + "presence-cp0", + "presence-cp1", + "presence-cp2", + "presence-cp3", + "presence-dasd", + "presence-lcd-op", + "presence-base-op", + ""; + + gpio@0 { + reg = <0>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@01 { + reg = <1>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@2 { + reg = <2>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@3 { + reg = <3>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@4 { + reg = <4>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@5 { + reg = <5>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@6 { + reg = <6>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@7 { + reg = <7>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@8 { + reg = <8>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@9 { + reg = <9>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@10 { + reg = <10>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@11 { + reg = <11>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@12 { + reg = <12>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@13 { + reg = <13>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@14 { + reg = <14>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@15 { + reg = <15>; + type = <PCA955X_TYPE_GPIO>; + }; + }; +}; + +&i2c1 { + status = "okay"; + + pca2: pca9552@61 { + compatible = "nxp,pca9552"; + reg = <0x61>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "presence-cable-card1", + "presence-cable-card2", + "presence-cable-card3", + "presence-cable-card4", + "presence-cable-card5", + "expander-cable-card1", + "expander-cable-card2", + "expander-cable-card3", + "expander-cable-card4", + "expander-cable-card5"; + + gpio@0 { + reg = <0>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@1 { + reg = <1>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@2 { + reg = <2>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@3 { + reg = <3>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@4 { + reg = <4>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@5 { + reg = <5>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@6 { + reg = <6>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@7 { + reg = <7>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@8 { + reg = <8>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@9 { + reg = <9>; + type = <PCA955X_TYPE_GPIO>; + }; + + }; + + pca3: pca9552@62 { + compatible = "nxp,pca9552"; + reg = <0x62>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "presence-cable-card6", + "presence-cable-card7", + "presence-cable-card8", + "presence-cable-card9", + "presence-cable-card10", + "presence-cable-card11", + "expander-cable-card6", + "expander-cable-card7", + "expander-cable-card8", + "expander-cable-card9", + "expander-cable-card10", + "expander-cable-card11"; + + gpio@0 { + reg = <0>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@1 { + reg = <1>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@2 { + reg = <2>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@3 { + reg = <3>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@4 { + reg = <4>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@5 { + reg = <5>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@6 { + reg = <6>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@7 { + reg = <7>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@8 { + reg = <8>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@9 { + reg = <9>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@10 { + reg = <10>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@11 { + reg = <11>; + type = <PCA955X_TYPE_GPIO>; + }; + + }; + +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; + + eeprom@54 { + compatible = "atmel,24c128"; + reg = <0x54>; + }; + + power-supply@68 { + compatible = "ibm,cffps"; + reg = <0x68>; + }; + + power-supply@69 { + compatible = "ibm,cffps"; + reg = <0x69>; + }; + + power-supply@6a { + compatible = "ibm,cffps"; + reg = <0x6a>; + }; + + power-supply@6b { + compatible = "ibm,cffps"; + reg = <0x6b>; + }; +}; + +&i2c4 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; + + i2c4mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + }; + + i2c4mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c4mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; + }; +}; + +&i2c5 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; + + i2c5mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c5mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; + + i2c5mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + }; + + i2c5mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + eeprom@53 { + compatible = "atmel,24c64"; + reg = <0x53>; + }; + }; + }; +}; + +&i2c6 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; + + i2c6mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c6mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + }; + + i2c6mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@53 { + compatible = "atmel,24c64"; + reg = <0x53>; + }; + }; + + i2c6mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; + }; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; + + ucd90320@11 { + compatible = "ti,ucd90320"; + reg = <0x11>; + }; + + rtc@32 { + compatible = "epson,rx8900"; + reg = <0x32>; + }; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; +}; + +&i2c9 { + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + + eeprom@51 { + compatible = "atmel,24c128"; + reg = <0x51>; + }; + + eeprom@53 { + compatible = "atmel,24c128"; + reg = <0x53>; + }; + + eeprom@52 { + compatible = "atmel,24c128"; + reg = <0x52>; + }; +}; + +&i2c10 { + status = "okay"; + + eeprom@51 { + compatible = "atmel,24c128"; + reg = <0x51>; + }; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + + eeprom@53 { + compatible = "atmel,24c128"; + reg = <0x53>; + }; + + eeprom@52 { + compatible = "atmel,24c128"; + reg = <0x52>; + }; +}; + +&i2c11 { + status = "okay"; + + eeprom@51 { + compatible = "atmel,24c128"; + reg = <0x51>; + }; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + + eeprom@53 { + compatible = "atmel,24c128"; + reg = <0x53>; + }; + + eeprom@52 { + compatible = "atmel,24c128"; + reg = <0x52>; + }; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; + + eeprom@51 { + compatible = "atmel,24c128"; + reg = <0x51>; + }; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + + eeprom@53 { + compatible = "atmel,24c128"; + reg = <0x53>; + }; + + eeprom@52 { + compatible = "atmel,24c128"; + reg = <0x52>; + }; }; -&ehci1 { - status = "okay"; -}; +&i2c14 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; + + i2c14mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c14mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + }; + }; + + i2c14mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + }; + + i2c14mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + max31785@52 { + compatible = "maxim,max31785a"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x52>; + + fan@0 { + compatible = "pmbus-fan"; + reg = <0>; + tach-pulses = <2>; + }; + + fan@1 { + compatible = "pmbus-fan"; + reg = <1>; + tach-pulses = <2>; + }; + + fan@2 { + compatible = "pmbus-fan"; + reg = <2>; + tach-pulses = <2>; + }; + + fan@3 { + compatible = "pmbus-fan"; + reg = <3>; + tach-pulses = <2>; + }; + }; + + pca0: pca9552@61 { + compatible = "nxp,pca9552"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x61>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "","","","", + "","","","", + "","","","", + "presence-fan3", + "presence-fan2", + "presence-fan1", + "presence-fan0"; + + gpio@0 { + reg = <0>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@1 { + reg = <1>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@2 { + reg = <2>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@3 { + reg = <3>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@4 { + reg = <4>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@5 { + reg = <5>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@6 { + reg = <6>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@7 { + reg = <7>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@8 { + reg = <8>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@9 { + reg = <9>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@10 { + reg = <10>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@11 { + reg = <11>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@12 { + reg = <12>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@13 { + reg = <13>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@14 { + reg = <14>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@15 { + reg = <15>; + type = <PCA955X_TYPE_GPIO>; + }; + }; + }; + }; + + i2c-switch@71 { + compatible = "nxp,pca9546"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; + + i2c14mux1chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + }; + + i2c14mux1chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + }; + + i2c14mux1chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + }; + + i2c14mux1chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + }; + }; +}; + +&i2c15 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&emmc_controller { + status = "okay"; +}; + +&pinctrl_emmc_default { + bias-disable; +}; + +&emmc { + status = "okay"; +}; + +&fsim0 { + status = "okay"; + + #address-cells = <2>; + #size-cells = <0>; + + /* + * CFAM Reset is supposed to be active low but pass1 hardware is wired + * active high. + */ + cfam-reset-gpios = <&gpio0 ASPEED_GPIO(Q, 0) GPIO_ACTIVE_HIGH>; + + cfam@0,0 { /* DCM0_C0 */ + reg = <0 0>; + #address-cells = <1>; + #size-cells = <1>; + chip-id = <0>; + + scom@1000 { + compatible = "ibm,fsi2pib"; + reg = <0x1000 0x400>; + }; + + i2c@1800 { + compatible = "ibm,fsi-i2c-master"; + reg = <0x1800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam0_i2c0: i2c-bus@0 { + reg = <0>; /* OMI01 */ + }; + + cfam0_i2c1: i2c-bus@1 { + reg = <1>; /* OMI23 */ + }; + + cfam0_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam0_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam0_i2c12: i2c-bus@c { + reg = <12>; /* OP4A */ + }; + + cfam0_i2c13: i2c-bus@d { + reg = <13>; /* OP4B */ + }; + + cfam0_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam0_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; + }; + + fsi2spi@1c00 { + compatible = "ibm,fsi2spi"; + reg = <0x1c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam0_spi0: spi@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam0_spi1: spi@20 { + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam0_spi2: spi@40 { + reg = <0x40>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam0_spi3: spi@60 { + reg = <0x60>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + }; + + sbefifo@2400 { + compatible = "ibm,p9-sbefifo"; + reg = <0x2400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + fsi_occ0: occ { + compatible = "ibm,p10-occ"; + }; + }; + + fsi_hub0: hub@3400 { + compatible = "fsi-master-hub"; + reg = <0x3400 0x400>; + #address-cells = <2>; + #size-cells = <0>; + }; + }; +}; + +&fsi_hub0 { + cfam@1,0 { /* DCM0_C1 */ + reg = <1 0>; + #address-cells = <1>; + #size-cells = <1>; + chip-id = <1>; + + scom@1000 { + compatible = "ibm,fsi2pib"; + reg = <0x1000 0x400>; + }; + + i2c@1800 { + compatible = "ibm,fsi-i2c-master"; + reg = <0x1800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam1_i2c2: i2c-bus@2 { + reg = <2>; /* OMI45 */ + }; + + cfam1_i2c3: i2c-bus@3 { + reg = <3>; /* OMI67 */ + }; + + cfam1_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam1_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam1_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam1_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; + + cfam1_i2c16: i2c-bus@10 { + reg = <16>; /* OP6A */ + }; + + cfam1_i2c17: i2c-bus@11 { + reg = <17>; /* OP6B */ + }; + }; + + fsi2spi@1c00 { + compatible = "ibm,fsi2spi"; + reg = <0x1c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam1_spi0: spi@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam1_spi1: spi@20 { + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam1_spi2: spi@40 { + reg = <0x40>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam1_spi3: spi@60 { + reg = <0x60>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + }; + + sbefifo@2400 { + compatible = "ibm,p9-sbefifo"; + reg = <0x2400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + fsi_occ1: occ { + compatible = "ibm,p10-occ"; + }; + }; + + fsi_hub1: hub@3400 { + compatible = "fsi-master-hub"; + reg = <0x3400 0x400>; + #address-cells = <2>; + #size-cells = <0>; + + no-scan-on-init; + }; + }; + + cfam@2,0 { /* DCM1_C0 */ + reg = <2 0>; + #address-cells = <1>; + #size-cells = <1>; + chip-id = <2>; + + scom@1000 { + compatible = "ibm,fsi2pib"; + reg = <0x1000 0x400>; + }; + + i2c@1800 { + compatible = "ibm,fsi-i2c-master"; + reg = <0x1800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam2_i2c0: i2c-bus@0 { + reg = <0>; /* OM01 */ + }; + + cfam2_i2c1: i2c-bus@1 { + reg = <1>; /* OM23 */ + }; + + cfam2_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam2_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam2_i2c12: i2c-bus@c { + reg = <12>; /* OP4A */ + }; + + cfam2_i2c13: i2c-bus@d { + reg = <13>; /* OP4B */ + }; + + cfam2_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam2_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; + }; + + fsi2spi@1c00 { + compatible = "ibm,fsi2spi"; + reg = <0x1c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam2_spi0: spi@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam2_spi1: spi@20 { + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam2_spi2: spi@40 { + reg = <0x40>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam2_spi3: spi@60 { + reg = <0x60>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + }; + + sbefifo@2400 { + compatible = "ibm,p9-sbefifo"; + reg = <0x2400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + fsi_occ2: occ { + compatible = "ibm,p10-occ"; + }; + }; + + fsi_hub2: hub@3400 { + compatible = "fsi-master-hub"; + reg = <0x3400 0x400>; + #address-cells = <2>; + #size-cells = <0>; + + no-scan-on-init; + }; + }; -&emmc_controller { - status = "okay"; -}; + cfam@3,0 { /* DCM1_C1 */ + reg = <3 0>; + #address-cells = <1>; + #size-cells = <1>; + chip-id = <3>; -&pinctrl_emmc_default { - bias-disable; -}; + scom@1000 { + compatible = "ibm,fsi2pib"; + reg = <0x1000 0x400>; + }; -&emmc { - status = "okay"; -}; + i2c@1800 { + compatible = "ibm,fsi-i2c-master"; + reg = <0x1800 0x400>; + #address-cells = <1>; + #size-cells = <0>; -&fsim0 { - status = "okay"; + cfam3_i2c2: i2c-bus@2 { + reg = <2>; /* OM45 */ + }; - #address-cells = <2>; - #size-cells = <0>; + cfam3_i2c3: i2c-bus@3 { + reg = <3>; /* OM67 */ + }; - /* - * CFAM Reset is supposed to be active low but pass1 hardware is wired - * active high. - */ - cfam-reset-gpios = <&gpio0 ASPEED_GPIO(Q, 0) GPIO_ACTIVE_HIGH>; + cfam3_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; - cfam@0,0 { - reg = <0 0>; + cfam3_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam3_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam3_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; + + cfam3_i2c16: i2c-bus@10 { + reg = <16>; /* OP6A */ + }; + + cfam3_i2c17: i2c-bus@11 { + reg = <17>; /* OP6B */ + }; + }; + + fsi2spi@1c00 { + compatible = "ibm,fsi2spi"; + reg = <0x1c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam3_spi0: spi@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam3_spi1: spi@20 { + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam3_spi2: spi@40 { + reg = <0x40>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam3_spi3: spi@60 { + reg = <0x60>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + }; + + sbefifo@2400 { + compatible = "ibm,p9-sbefifo"; + reg = <0x2400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + fsi_occ3: occ { + compatible = "ibm,p10-occ"; + }; + }; + + fsi_hub3: hub@3400 { + compatible = "fsi-master-hub"; + reg = <0x3400 0x400>; + #address-cells = <2>; + #size-cells = <0>; + + no-scan-on-init; + }; + }; + + cfam@4,0 { /* DCM2_C0 */ + reg = <4 0>; #address-cells = <1>; #size-cells = <1>; - chip-id = <0>; + chip-id = <4>; scom@1000 { compatible = "ibm,fsi2pib"; @@ -150,35 +1677,35 @@ #address-cells = <1>; #size-cells = <0>; - cfam0_i2c0: i2c-bus@0 { - reg = <0>; /* OMI01 */ + cfam4_i2c0: i2c-bus@0 { + reg = <0>; /* OM01 */ }; - cfam0_i2c1: i2c-bus@1 { - reg = <1>; /* OMI23 */ + cfam4_i2c1: i2c-bus@1 { + reg = <1>; /* OM23 */ }; - cfam0_i2c10: i2c-bus@a { + cfam4_i2c10: i2c-bus@a { reg = <10>; /* OP3A */ }; - cfam0_i2c11: i2c-bus@b { + cfam4_i2c11: i2c-bus@b { reg = <11>; /* OP3B */ }; - cfam0_i2c12: i2c-bus@c { + cfam4_i2c12: i2c-bus@c { reg = <12>; /* OP4A */ }; - cfam0_i2c13: i2c-bus@d { + cfam4_i2c13: i2c-bus@d { reg = <13>; /* OP4B */ }; - cfam0_i2c14: i2c-bus@e { + cfam4_i2c14: i2c-bus@e { reg = <14>; /* OP5A */ }; - cfam0_i2c15: i2c-bus@f { + cfam4_i2c15: i2c-bus@f { reg = <15>; /* OP5B */ }; }; @@ -189,7 +1716,7 @@ #address-cells = <1>; #size-cells = <0>; - cfam0_spi0: spi@0 { + cfam4_spi0: spi@0 { reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -205,7 +1732,7 @@ }; }; - cfam0_spi1: spi@20 { + cfam4_spi1: spi@20 { reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -221,7 +1748,7 @@ }; }; - cfam0_spi2: spi@40 { + cfam4_spi2: spi@40 { reg = <0x40>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -238,7 +1765,7 @@ }; }; - cfam0_spi3: spi@60 { + cfam4_spi3: spi@60 { reg = <0x60>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -262,26 +1789,26 @@ #address-cells = <1>; #size-cells = <0>; - fsi_occ0: occ { + fsi_occ4: occ { compatible = "ibm,p10-occ"; }; }; - fsi_hub0: hub@3400 { + fsi_hub4: hub@3400 { compatible = "fsi-master-hub"; reg = <0x3400 0x400>; #address-cells = <2>; #size-cells = <0>; + + no-scan-on-init; }; }; -}; -&fsi_hub0 { - cfam@1,0 { - reg = <1 0>; + cfam@5,0 { /* DCM2_C1 */ + reg = <5 0>; #address-cells = <1>; #size-cells = <1>; - chip-id = <1>; + chip-id = <5>; scom@1000 { compatible = "ibm,fsi2pib"; @@ -294,35 +1821,35 @@ #address-cells = <1>; #size-cells = <0>; - cfam1_i2c2: i2c-bus@2 { - reg = <2>; /* OMI45 */ + cfam5_i2c2: i2c-bus@2 { + reg = <2>; /* OM45 */ }; - cfam1_i2c3: i2c-bus@3 { - reg = <3>; /* OMI67 */ + cfam5_i2c3: i2c-bus@3 { + reg = <3>; /* OM67 */ }; - cfam1_i2c10: i2c-bus@a { + cfam5_i2c10: i2c-bus@a { reg = <10>; /* OP3A */ }; - cfam1_i2c11: i2c-bus@b { + cfam5_i2c11: i2c-bus@b { reg = <11>; /* OP3B */ }; - cfam1_i2c14: i2c-bus@e { + cfam5_i2c14: i2c-bus@e { reg = <14>; /* OP5A */ }; - cfam1_i2c15: i2c-bus@f { + cfam5_i2c15: i2c-bus@f { reg = <15>; /* OP5B */ }; - cfam1_i2c16: i2c-bus@10 { + cfam5_i2c16: i2c-bus@10 { reg = <16>; /* OP6A */ }; - cfam1_i2c17: i2c-bus@11 { + cfam5_i2c17: i2c-bus@11 { reg = <17>; /* OP6B */ }; }; @@ -333,7 +1860,7 @@ #address-cells = <1>; #size-cells = <0>; - cfam1_spi0: spi@0 { + cfam5_spi0: spi@0 { reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -349,7 +1876,7 @@ }; }; - cfam1_spi1: spi@20 { + cfam5_spi1: spi@20 { reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -365,7 +1892,7 @@ }; }; - cfam1_spi2: spi@40 { + cfam5_spi2: spi@40 { reg = <0x40>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -382,7 +1909,7 @@ }; }; - cfam1_spi3: spi@60 { + cfam5_spi3: spi@60 { reg = <0x60>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -406,12 +1933,12 @@ #address-cells = <1>; #size-cells = <0>; - fsi_occ1: occ { + fsi_occ5: occ { compatible = "ibm,p10-occ"; }; }; - fsi_hub1: hub@3400 { + fsi_hub5: hub@3400 { compatible = "fsi-master-hub"; reg = <0x3400 0x400>; #address-cells = <2>; @@ -421,11 +1948,11 @@ }; }; - cfam@2,0 { - reg = <2 0>; + cfam@6,0 { /* DCM3_C0 */ + reg = <6 0>; #address-cells = <1>; #size-cells = <1>; - chip-id = <2>; + chip-id = <6>; scom@1000 { compatible = "ibm,fsi2pib"; @@ -438,35 +1965,35 @@ #address-cells = <1>; #size-cells = <0>; - cfam2_i2c0: i2c-bus@0 { + cfam6_i2c0: i2c-bus@0 { reg = <0>; /* OM01 */ }; - cfam2_i2c1: i2c-bus@1 { + cfam6_i2c1: i2c-bus@1 { reg = <1>; /* OM23 */ }; - cfam2_i2c10: i2c-bus@a { + cfam6_i2c10: i2c-bus@a { reg = <10>; /* OP3A */ }; - cfam2_i2c11: i2c-bus@b { + cfam6_i2c11: i2c-bus@b { reg = <11>; /* OP3B */ }; - cfam2_i2c12: i2c-bus@c { + cfam6_i2c12: i2c-bus@c { reg = <12>; /* OP4A */ }; - cfam2_i2c13: i2c-bus@d { + cfam6_i2c13: i2c-bus@d { reg = <13>; /* OP4B */ }; - cfam2_i2c14: i2c-bus@e { + cfam6_i2c14: i2c-bus@e { reg = <14>; /* OP5A */ }; - cfam2_i2c15: i2c-bus@f { + cfam6_i2c15: i2c-bus@f { reg = <15>; /* OP5B */ }; }; @@ -477,7 +2004,7 @@ #address-cells = <1>; #size-cells = <0>; - cfam2_spi0: spi@0 { + cfam6_spi0: spi@0 { reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -493,7 +2020,7 @@ }; }; - cfam2_spi1: spi@20 { + cfam6_spi1: spi@20 { reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -509,7 +2036,7 @@ }; }; - cfam2_spi2: spi@40 { + cfam6_spi2: spi@40 { reg = <0x40>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -526,7 +2053,7 @@ }; }; - cfam2_spi3: spi@60 { + cfam6_spi3: spi@60 { reg = <0x60>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -550,12 +2077,12 @@ #address-cells = <1>; #size-cells = <0>; - fsi_occ2: occ { + fsi_occ6: occ { compatible = "ibm,p10-occ"; }; }; - fsi_hub2: hub@3400 { + fsi_hub6: hub@3400 { compatible = "fsi-master-hub"; reg = <0x3400 0x400>; #address-cells = <2>; @@ -565,11 +2092,11 @@ }; }; - cfam@3,0 { - reg = <3 0>; + cfam@7,0 { /* DCM3_C1 */ + reg = <7 0>; #address-cells = <1>; #size-cells = <1>; - chip-id = <3>; + chip-id = <7>; scom@1000 { compatible = "ibm,fsi2pib"; @@ -582,35 +2109,35 @@ #address-cells = <1>; #size-cells = <0>; - cfam3_i2c2: i2c-bus@2 { + cfam7_i2c2: i2c-bus@2 { reg = <2>; /* OM45 */ }; - cfam3_i2c3: i2c-bus@3 { + cfam7_i2c3: i2c-bus@3 { reg = <3>; /* OM67 */ }; - cfam3_i2c10: i2c-bus@a { + cfam7_i2c10: i2c-bus@a { reg = <10>; /* OP3A */ }; - cfam3_i2c11: i2c-bus@b { + cfam7_i2c11: i2c-bus@b { reg = <11>; /* OP3B */ }; - cfam3_i2c14: i2c-bus@e { + cfam7_i2c14: i2c-bus@e { reg = <14>; /* OP5A */ }; - cfam3_i2c15: i2c-bus@f { + cfam7_i2c15: i2c-bus@f { reg = <15>; /* OP5B */ }; - cfam3_i2c16: i2c-bus@10 { + cfam7_i2c16: i2c-bus@10 { reg = <16>; /* OP6A */ }; - cfam3_i2c17: i2c-bus@11 { + cfam7_i2c17: i2c-bus@11 { reg = <17>; /* OP6B */ }; }; @@ -621,7 +2148,7 @@ #address-cells = <1>; #size-cells = <0>; - cfam3_spi0: spi@0 { + cfam7_spi0: spi@0 { reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -637,7 +2164,7 @@ }; }; - cfam3_spi1: spi@20 { + cfam7_spi1: spi@20 { reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -653,7 +2180,7 @@ }; }; - cfam3_spi2: spi@40 { + cfam7_spi2: spi@40 { reg = <0x40>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -670,7 +2197,7 @@ }; }; - cfam3_spi3: spi@60 { + cfam7_spi3: spi@60 { reg = <0x60>; compatible = "ibm,fsi2spi-restricted"; #address-cells = <1>; @@ -694,12 +2221,12 @@ #address-cells = <1>; #size-cells = <0>; - fsi_occ3: occ { + fsi_occ7: occ { compatible = "ibm,p10-occ"; }; }; - fsi_hub3: hub@3400 { + fsi_hub7: hub@3400 { compatible = "fsi-master-hub"; reg = <0x3400 0x400>; #address-cells = <2>; @@ -727,6 +2254,22 @@ reg = <4>; }; +&fsi_occ4 { + reg = <5>; +}; + +&fsi_occ5 { + reg = <6>; +}; + +&fsi_occ6 { + reg = <7>; +}; + +&fsi_occ7 { + reg = <8>; +}; + &ibt { status = "okay"; }; @@ -769,6 +2312,20 @@ use-ncsi; }; +&wdt1 { + aspeed,reset-type = "none"; + aspeed,external-signal; + aspeed,ext-push-pull; + aspeed,ext-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdtrst1_default>; +}; + +&wdt2 { + status = "okay"; +}; + &xdma { status = "okay"; memory-region = <&vga_memory>; diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-1s4u.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-1s4u.dts new file mode 100644 index 0000000000000000000000000000000000000000..f5f5b18c113a82064f0381741c1855cddf231ec7 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-1s4u.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2021 IBM Corp. +/dts-v1/; + +#include "aspeed-bmc-ibm-rainier-4u.dts" + +/ { + model = "Rainier 1S4U"; +}; + +&max { + /delete-node/ fan3; + /delete-node/ fan5; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts index 291f7d6c9979cc391fb77494e57c4099a8065e98..f7fd3b3c90d08b8883dd8e00d5acb9a8b184d8d8 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts @@ -22,16 +22,30 @@ &fan0 { tach-pulses = <4>; + /delete-property/ maxim,fan-dual-tach; }; &fan1 { tach-pulses = <4>; + /delete-property/ maxim,fan-dual-tach; }; &fan2 { tach-pulses = <4>; + /delete-property/ maxim,fan-dual-tach; }; &fan3 { tach-pulses = <4>; + /delete-property/ maxim,fan-dual-tach; +}; + +&fan4 { + tach-pulses = <4>; + /delete-property/ maxim,fan-dual-tach; +}; + +&fan5 { + tach-pulses = <4>; + /delete-property/ maxim,fan-dual-tach; }; diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts index 6c9804d2f3b4f5a744d1a3d72360c9c4e7edc397..941c0489479ac3402230739bc61d70ae589261a4 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts @@ -12,11 +12,55 @@ compatible = "ibm,rainier-bmc", "aspeed,ast2600"; aliases { + i2c100 = &cfam0_i2c0; + i2c101 = &cfam0_i2c1; + i2c110 = &cfam0_i2c10; + i2c111 = &cfam0_i2c11; + i2c112 = &cfam0_i2c12; + i2c113 = &cfam0_i2c13; + i2c114 = &cfam0_i2c14; + i2c115 = &cfam0_i2c15; + i2c202 = &cfam1_i2c2; + i2c203 = &cfam1_i2c3; + i2c210 = &cfam1_i2c10; + i2c211 = &cfam1_i2c11; + i2c214 = &cfam1_i2c14; + i2c215 = &cfam1_i2c15; + i2c216 = &cfam1_i2c16; + i2c217 = &cfam1_i2c17; + i2c300 = &cfam2_i2c0; + i2c301 = &cfam2_i2c1; + i2c310 = &cfam2_i2c10; + i2c311 = &cfam2_i2c11; + i2c312 = &cfam2_i2c12; + i2c313 = &cfam2_i2c13; + i2c314 = &cfam2_i2c14; + i2c315 = &cfam2_i2c15; + i2c402 = &cfam3_i2c2; + i2c403 = &cfam3_i2c3; + i2c410 = &cfam3_i2c10; + i2c411 = &cfam3_i2c11; + i2c414 = &cfam3_i2c14; + i2c415 = &cfam3_i2c15; + i2c416 = &cfam3_i2c16; + i2c417 = &cfam3_i2c17; + serial4 = &uart5; i2c16 = &i2c2mux0; i2c17 = &i2c2mux1; i2c18 = &i2c2mux2; i2c19 = &i2c2mux3; + i2c20 = &i2c4mux0chn0; + i2c21 = &i2c4mux0chn1; + i2c22 = &i2c4mux0chn2; + i2c23 = &i2c5mux0chn0; + i2c24 = &i2c5mux0chn1; + i2c25 = &i2c6mux0chn0; + i2c26 = &i2c6mux0chn1; + i2c27 = &i2c6mux0chn2; + i2c28 = &i2c6mux0chn3; + i2c29 = &i2c11mux0chn0; + i2c30 = &i2c11mux0chn1; spi10 = &cfam0_spi0; spi11 = &cfam0_spi1; @@ -30,6 +74,10 @@ spi31 = &cfam2_spi1; spi32 = &cfam2_spi2; spi33 = &cfam2_spi3; + spi40 = &cfam3_spi0; + spi41 = &cfam3_spi1; + spi42 = &cfam3_spi2; + spi43 = &cfam3_spi3; }; chosen { @@ -131,6 +179,73 @@ reg = <3>; }; }; + + leds { + compatible = "gpio-leds"; + + /* BMC Card fault LED at the back */ + bmc-ingraham0 { + gpios = <&gpio0 ASPEED_GPIO(H, 1) GPIO_ACTIVE_LOW>; + }; + + /* Enclosure ID LED at the back */ + rear-enc-id0 { + gpios = <&gpio0 ASPEED_GPIO(H, 2) GPIO_ACTIVE_LOW>; + }; + + /* Enclosure fault LED at the back */ + rear-enc-fault0 { + gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>; + }; + + /* PCIE slot power LED */ + pcieslot-power { + gpios = <&gpio0 ASPEED_GPIO(P, 4) GPIO_ACTIVE_LOW>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <1000>; + + fan0-presence { + label = "fan0-presence"; + gpios = <&pca0 6 GPIO_ACTIVE_LOW>; + linux,code = <6>; + }; + + fan1-presence { + label = "fan1-presence"; + gpios = <&pca0 7 GPIO_ACTIVE_LOW>; + linux,code = <7>; + }; + + fan2-presence { + label = "fan2-presence"; + gpios = <&pca0 8 GPIO_ACTIVE_LOW>; + linux,code = <8>; + }; + + fan3-presence { + label = "fan3-presence"; + gpios = <&pca0 9 GPIO_ACTIVE_LOW>; + linux,code = <9>; + }; + + fan4-presence { + label = "fan4-presence"; + gpios = <&pca0 10 GPIO_ACTIVE_LOW>; + linux,code = <10>; + }; + + fan5-presence { + label = "fan5-presence"; + gpios = <&pca0 11 GPIO_ACTIVE_LOW>; + linux,code = <11>; + }; + }; }; &ehci1 { @@ -146,7 +261,7 @@ /*E0-E7*/ "","","","","","","","", /*F0-F7*/ "","","","","","","","", /*G0-G7*/ "","","","","","","","", - /*H0-H7*/ "","","","","","","","", + /*H0-H7*/ "","bmc-ingraham0","rear-enc-id0","rear-enc-fault0","","","","", /*I0-I7*/ "","","","","","","","", /*J0-J7*/ "","","","","","","","", /*K0-K7*/ "","","","","","","","", @@ -154,7 +269,7 @@ /*M0-M7*/ "","","","","","","","", /*N0-N7*/ "","","","","","","","", /*O0-O7*/ "","","","usb-power","","","","", - /*P0-P7*/ "","","","","","","","", + /*P0-P7*/ "","","","","pcieslot-power","","","", /*Q0-Q7*/ "cfam-reset","","","","","","","", /*R0-R7*/ "","","","","","","","", /*S0-S7*/ "presence-ps0","presence-ps1","presence-ps2","presence-ps3", @@ -226,6 +341,38 @@ reg = <0x1800 0x400>; #address-cells = <1>; #size-cells = <0>; + + cfam0_i2c0: i2c-bus@0 { + reg = <0>; /* OMI01 */ + }; + + cfam0_i2c1: i2c-bus@1 { + reg = <1>; /* OMI23 */ + }; + + cfam0_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam0_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam0_i2c12: i2c-bus@c { + reg = <12>; /* OP4A */ + }; + + cfam0_i2c13: i2c-bus@d { + reg = <13>; /* OP4B */ + }; + + cfam0_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam0_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; }; fsi2spi@1c00 { @@ -317,8 +464,6 @@ reg = <0x3400 0x400>; #address-cells = <2>; #size-cells = <0>; - - no-scan-on-init; }; }; }; @@ -340,6 +485,38 @@ reg = <0x1800 0x400>; #address-cells = <1>; #size-cells = <0>; + + cfam1_i2c2: i2c-bus@2 { + reg = <2>; /* OMI45 */ + }; + + cfam1_i2c3: i2c-bus@3 { + reg = <3>; /* OMI67 */ + }; + + cfam1_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam1_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam1_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam1_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; + + cfam1_i2c16: i2c-bus@10 { + reg = <16>; /* OP6A */ + }; + + cfam1_i2c17: i2c-bus@11 { + reg = <17>; /* OP6B */ + }; }; fsi2spi@1c00 { @@ -452,6 +629,38 @@ reg = <0x1800 0x400>; #address-cells = <1>; #size-cells = <0>; + + cfam2_i2c0: i2c-bus@0 { + reg = <0>; /* OM01 */ + }; + + cfam2_i2c1: i2c-bus@1 { + reg = <1>; /* OM23 */ + }; + + cfam2_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam2_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam2_i2c12: i2c-bus@c { + reg = <12>; /* OP4A */ + }; + + cfam2_i2c13: i2c-bus@d { + reg = <13>; /* OP4B */ + }; + + cfam2_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam2_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; }; fsi2spi@1c00 { @@ -547,6 +756,150 @@ no-scan-on-init; }; }; + + cfam@3,0 { + reg = <3 0>; + #address-cells = <1>; + #size-cells = <1>; + chip-id = <3>; + + scom@1000 { + compatible = "ibm,fsi2pib"; + reg = <0x1000 0x400>; + }; + + i2c@1800 { + compatible = "ibm,fsi-i2c-master"; + reg = <0x1800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam3_i2c2: i2c-bus@2 { + reg = <2>; /* OM45 */ + }; + + cfam3_i2c3: i2c-bus@3 { + reg = <3>; /* OM67 */ + }; + + cfam3_i2c10: i2c-bus@a { + reg = <10>; /* OP3A */ + }; + + cfam3_i2c11: i2c-bus@b { + reg = <11>; /* OP3B */ + }; + + cfam3_i2c14: i2c-bus@e { + reg = <14>; /* OP5A */ + }; + + cfam3_i2c15: i2c-bus@f { + reg = <15>; /* OP5B */ + }; + + cfam3_i2c16: i2c-bus@10 { + reg = <16>; /* OP6A */ + }; + + cfam3_i2c17: i2c-bus@11 { + reg = <17>; /* OP6B */ + }; + }; + + fsi2spi@1c00 { + compatible = "ibm,fsi2spi"; + reg = <0x1c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + cfam3_spi0: spi@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam3_spi1: spi@20 { + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam3_spi2: spi@40 { + reg = <0x40>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + + cfam3_spi3: spi@60 { + reg = <0x60>; + compatible = "ibm,fsi2spi-restricted"; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + at25,byte-len = <0x80000>; + at25,addr-mode = <4>; + at25,page-size = <256>; + + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + }; + + sbefifo@2400 { + compatible = "ibm,p9-sbefifo"; + reg = <0x2400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + fsi_occ3: occ { + compatible = "ibm,p10-occ"; + }; + }; + + fsi_hub3: hub@3400 { + compatible = "fsi-master-hub"; + reg = <0x3400 0x400>; + #address-cells = <2>; + #size-cells = <0>; + + no-scan-on-init; + }; + }; }; /* Legacy OCC numbering (to get rid of when userspace is fixed) */ @@ -562,6 +915,10 @@ reg = <3>; }; +&fsi_occ3 { + reg = <4>; +}; + &ibt { status = "okay"; }; @@ -574,20 +931,64 @@ reg = <0x51>; }; - tca9554@40 { + tca_pres1: tca9554@20{ compatible = "ti,tca9554"; - reg = <0x40>; + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + gpio-controller; #gpio-cells = <2>; - smbus0-hog { - gpio-hog; - gpios = <4 GPIO_ACTIVE_HIGH>; - output-high; - line-name = "smbus0"; + gpio-line-names = "", + "RUSSEL_FW_I2C_ENABLE_N", + "RUSSEL_OPPANEL_PRESENCE_N", + "BLYTH_OPPANEL_PRESENCE_N", + "CPU_TPM_CARD_PRESENT_N", + "DASD_BP2_PRESENT_N", + "DASD_BP1_PRESENT_N", + "DASD_BP0_PRESENT_N"; + + gpio@0 { + reg = <0>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@1 { + reg = <1>; + type = <PCA955X_TYPE_GPIO>; }; - }; + gpio@2 { + reg = <2>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@3 { + reg = <3>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@4 { + reg = <4>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@5 { + reg = <5>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@6 { + reg = <6>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@7 { + reg = <7>; + type = <PCA955X_TYPE_GPIO>; + }; + }; }; &i2c1 { @@ -610,6 +1011,104 @@ compatible = "ibm,cffps"; reg = <0x69>; }; + + pca_pres1: pca9552@61 { + compatible = "nxp,pca9552"; + reg = <0x61>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLOT0_PRSNT_EN_RSVD", "SLOT1_PRSNT_EN_RSVD", + "SLOT2_PRSNT_EN_RSVD", "SLOT3_PRSNT_EN_RSVD", + "SLOT4_PRSNT_EN_RSVD", "SLOT0_EXPANDER_PRSNT_N", + "SLOT1_EXPANDER_PRSNT_N", "SLOT2_EXPANDER_PRSNT_N", + "SLOT3_EXPANDER_PRSNT_N", "SLOT4_EXPANDER_PRSNT_N", + "", "", "", "", "", ""; + + gpio@0 { + reg = <0>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@1 { + reg = <1>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@2 { + reg = <2>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@3 { + reg = <3>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@4 { + reg = <4>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@5 { + reg = <5>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@6 { + reg = <6>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@7 { + reg = <7>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@8 { + reg = <8>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@9 { + reg = <9>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@10 { + reg = <10>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@11 { + reg = <11>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@12 { + reg = <12>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@13 { + reg = <13>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@14 { + reg = <14>; + type = <PCA955X_TYPE_GPIO>; + }; + + gpio@15 { + reg = <15>; + type = <PCA955X_TYPE_GPIO>; + }; + }; }; &i2c4 { @@ -630,19 +1129,46 @@ reg = <0x4a>; }; - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; + pca9546@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; - eeprom@51 { - compatible = "atmel,24c64"; - reg = <0x51>; - }; + i2c4mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; - eeprom@52 { - compatible = "atmel,24c64"; - reg = <0x52>; + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c4mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; + + i2c4mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + }; }; }; @@ -659,14 +1185,35 @@ reg = <0x49>; }; - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; + pca9546@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; - eeprom@51 { - compatible = "atmel,24c64"; - reg = <0x51>; + i2c5mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c5mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; }; }; @@ -688,24 +1235,57 @@ reg = <0x4b>; }; - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; + pca9546@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; - eeprom@51 { - compatible = "atmel,24c64"; - reg = <0x51>; - }; + i2c6mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; - eeprom@52 { - compatible = "atmel,24c64"; - reg = <0x52>; - }; + eeprom@53 { + compatible = "atmel,24c64"; + reg = <0x53>; + }; + }; - eeprom@53 { - compatible = "atmel,24c64"; - reg = <0x53>; + i2c6mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + }; + + i2c6mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c6mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; }; }; @@ -713,9 +1293,9 @@ multi-master; status = "okay"; - si7021-a20@20 { + si7021-a20@40 { compatible = "silabs,si7020"; - reg = <0x20>; + reg = <0x40>; }; tmp275@48 { @@ -723,7 +1303,7 @@ reg = <0x48>; }; - max31785@52 { + max: max31785@52 { compatible = "maxim,max31785a"; reg = <0x52>; #address-cells = <1>; @@ -752,6 +1332,18 @@ reg = <3>; tach-pulses = <2>; }; + + fan4: fan@4 { + compatible = "pmbus-fan"; + reg = <4>; + tach-pulses = <2>; + }; + + fan5: fan@5 { + compatible = "pmbus-fan"; + reg = <5>; + tach-pulses = <2>; + }; }; pca0: pca9552@61 { @@ -899,7 +1491,7 @@ reg = <0x51>; }; - pca1: pca9552@61 { + pca_pres2: pca9552@61 { compatible = "nxp,pca9552"; reg = <0x61>; #address-cells = <1>; @@ -907,6 +1499,15 @@ gpio-controller; #gpio-cells = <2>; + gpio-line-names = + "SLOT6_PRSNT_EN_RSVD", "SLOT7_PRSNT_EN_RSVD", + "SLOT8_PRSNT_EN_RSVD", "SLOT9_PRSNT_EN_RSVD", + "SLOT10_PRSNT_EN_RSVD", "SLOT11_PRSNT_EN_RSVD", + "SLOT6_EXPANDER_PRSNT_N", "SLOT7_EXPANDER_PRSNT_N", + "SLOT8_EXPANDER_PRSNT_N", "SLOT9_EXPANDER_PRSNT_N", + "SLOT10_EXPANDER_PRSNT_N", "SLOT11_EXPANDER_PRSNT_N", + "", "", "", ""; + gpio@0 { reg = <0>; type = <PCA955X_TYPE_GPIO>; @@ -1041,14 +1642,35 @@ reg = <0x49>; }; - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; + pca9546@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; - eeprom@51 { - compatible = "atmel,24c64"; - reg = <0x51>; + i2c11mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c11mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; }; }; @@ -1140,6 +1762,20 @@ }; }; +&wdt1 { + aspeed,reset-type = "none"; + aspeed,external-signal; + aspeed,ext-push-pull; + aspeed,ext-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdtrst1_default>; +}; + +&wdt2 { + status = "okay"; +}; + &xdma { status = "okay"; memory-region = <&vga_memory>; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts index 577c211c469eae9c1e478d39ffd9ba635083b69d..15c1f0ac81dcd8267e4791c1fc6bd2e7fa12283e 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts @@ -383,6 +383,39 @@ }; }; +&gpio { + gpio-line-names = + /*A0-A7*/ "","cfam-reset","","","","","","", + /*B0-B7*/ "","","","","","","","", + /*C0-C7*/ "","","","","","","","", + /*D0-D7*/ "fsi-enable","","","","","","","", + /*E0-E7*/ "","","","","","fsi-mux","fsi-clock","fsi-data", + /*F0-F7*/ "","id-button","","","","","air-water","", + /*G0-G7*/ "","","","","","","","", + /*H0-H7*/ "","","","","","","","", + /*I0-I7*/ "","","","","","","","", + /*J0-J7*/ "","","checkstop","","","","","", + /*K0-K7*/ "","","","","","","","", + /*L0-L7*/ "","","","","","","","", + /*M0-M7*/ "","","","","","","","", + /*N0-N7*/ "","","","","","","","", + /*O0-O7*/ "","","","","","","","", + /*P0-P7*/ "","","","","","","","", + /*Q0-Q7*/ "","","","","","","","", + /*R0-R7*/ "","","fsi-trans","","","","","", + /*S0-S7*/ "","","","","","","","", + /*T0-T7*/ "","","","","","","","", + /*U0-U7*/ "","","","","","","","", + /*V0-V7*/ "","","","","","","","", + /*W0-W7*/ "","","","","","","","", + /*X0-X7*/ "","","","","","","","", + /*Y0-Y7*/ "","","","","","","","", + /*Z0-Z7*/ "presence-ps1","","presence-ps0","","","","","", + /*AA0-AA7*/ "led-front-fault","power-button","led-front-id","","","","","", + /*AB0-AB7*/ "","","","","","","","", + /*AC0-AC7*/ "","","","","","","",""; +}; + &fmc { status = "okay"; flash@0 { diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index e7a45ba18fc9c7e17887223ec3abbe2e79afb02e..c5aeb3cf3a0961b6760a0fd6d59e0e6705be33bd 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -343,59 +343,45 @@ }; lpc: lpc@1e789000 { - compatible = "aspeed,ast2400-lpc", "simple-mfd"; + compatible = "aspeed,ast2400-lpc-v2", "simple-mfd", "syscon"; reg = <0x1e789000 0x1000>; + reg-io-width = <4>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x1e789000 0x1000>; - lpc_bmc: lpc-bmc@0 { - compatible = "aspeed,ast2400-lpc-bmc"; - reg = <0x0 0x80>; + lpc_ctrl: lpc-ctrl@80 { + compatible = "aspeed,ast2400-lpc-ctrl"; + reg = <0x80 0x10>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; }; - lpc_host: lpc-host@80 { - compatible = "aspeed,ast2400-lpc-host", "simple-mfd", "syscon"; - reg = <0x80 0x1e0>; - reg-io-width = <4>; - - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x80 0x1e0>; - - lpc_ctrl: lpc-ctrl@0 { - compatible = "aspeed,ast2400-lpc-ctrl"; - reg = <0x0 0x10>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - status = "disabled"; - }; - - lpc_snoop: lpc-snoop@10 { - compatible = "aspeed,ast2400-lpc-snoop"; - reg = <0x10 0x8>; - interrupts = <8>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - status = "disabled"; - }; - - lhc: lhc@20 { - compatible = "aspeed,ast2400-lhc"; - reg = <0x20 0x24 0x48 0x8>; - }; - - lpc_reset: reset-controller@18 { - compatible = "aspeed,ast2400-lpc-reset"; - reg = <0x18 0x4>; - #reset-cells = <1>; - }; - - ibt: ibt@c0 { - compatible = "aspeed,ast2400-ibt-bmc"; - reg = <0xc0 0x18>; - interrupts = <8>; - status = "disabled"; - }; + lpc_snoop: lpc-snoop@90 { + compatible = "aspeed,ast2400-lpc-snoop"; + reg = <0x90 0x8>; + interrupts = <8>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + + lhc: lhc@a0 { + compatible = "aspeed,ast2400-lhc"; + reg = <0xa0 0x24 0xc8 0x8>; + }; + + lpc_reset: reset-controller@98 { + compatible = "aspeed,ast2400-lpc-reset"; + reg = <0x98 0x4>; + #reset-cells = <1>; + }; + + ibt: ibt@140 { + compatible = "aspeed,ast2400-ibt-bmc"; + reg = <0x140 0x18>; + interrupts = <8>; + status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 21930521a986a7a4d13af15f14de483f12430729..d733c1f161c1b998ca98f20e072a63b3b5af6eb7 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -434,91 +434,74 @@ }; lpc: lpc@1e789000 { - compatible = "aspeed,ast2500-lpc", "simple-mfd"; + compatible = "aspeed,ast2500-lpc-v2", "simple-mfd", "syscon"; reg = <0x1e789000 0x1000>; + reg-io-width = <4>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x1e789000 0x1000>; - lpc_bmc: lpc-bmc@0 { - compatible = "aspeed,ast2500-lpc-bmc", "simple-mfd", "syscon"; - reg = <0x0 0x80>; - reg-io-width = <4>; - - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x80>; - - kcs1: kcs@24 { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>; - interrupts = <8>; - status = "disabled"; - }; - kcs2: kcs@28 { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>; - interrupts = <8>; - status = "disabled"; - }; - kcs3: kcs@2c { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>; - interrupts = <8>; - status = "disabled"; - }; + kcs1: kcs@24 { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>; + interrupts = <8>; + status = "disabled"; + }; + + kcs2: kcs@28 { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>; + interrupts = <8>; + status = "disabled"; + }; + + kcs3: kcs@2c { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>; + interrupts = <8>; + status = "disabled"; + }; + + kcs4: kcs@114 { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x114 0x1>, <0x118 0x1>, <0x11c 0x1>; + interrupts = <8>; + status = "disabled"; }; - lpc_host: lpc-host@80 { - compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon"; - reg = <0x80 0x1e0>; - reg-io-width = <4>; - - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x80 0x1e0>; - - kcs4: kcs@94 { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x94 0x1>, <0x98 0x1>, <0x9c 0x1>; - interrupts = <8>; - status = "disabled"; - }; - - lpc_ctrl: lpc-ctrl@0 { - compatible = "aspeed,ast2500-lpc-ctrl"; - reg = <0x0 0x10>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - status = "disabled"; - }; - - lpc_snoop: lpc-snoop@10 { - compatible = "aspeed,ast2500-lpc-snoop"; - reg = <0x10 0x8>; - interrupts = <8>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - status = "disabled"; - }; - - lpc_reset: reset-controller@18 { - compatible = "aspeed,ast2500-lpc-reset"; - reg = <0x18 0x4>; - #reset-cells = <1>; - }; - - lhc: lhc@20 { - compatible = "aspeed,ast2500-lhc"; - reg = <0x20 0x24 0x48 0x8>; - }; - - - ibt: ibt@c0 { - compatible = "aspeed,ast2500-ibt-bmc"; - reg = <0xc0 0x18>; - interrupts = <8>; - status = "disabled"; - }; + lpc_ctrl: lpc-ctrl@80 { + compatible = "aspeed,ast2500-lpc-ctrl"; + reg = <0x80 0x10>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + + lpc_snoop: lpc-snoop@90 { + compatible = "aspeed,ast2500-lpc-snoop"; + reg = <0x90 0x8>; + interrupts = <8>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + + lpc_reset: reset-controller@98 { + compatible = "aspeed,ast2500-lpc-reset"; + reg = <0x98 0x4>; + #reset-cells = <1>; + }; + + lhc: lhc@a0 { + compatible = "aspeed,ast2500-lhc"; + reg = <0xa0 0x24 0xc8 0x8>; + }; + + + ibt: ibt@140 { + compatible = "aspeed,ast2500-ibt-bmc"; + reg = <0x140 0x18>; + interrupts = <8>; + status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 3ee470c2b7b5625f06fa58b0a046075e6cf9fdf4..f96607b7b4e2a8ec0ed4f12affd7f91236782807 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -460,91 +460,74 @@ }; lpc: lpc@1e789000 { - compatible = "aspeed,ast2600-lpc", "simple-mfd"; + compatible = "aspeed,ast2600-lpc-v2", "simple-mfd", "syscon"; reg = <0x1e789000 0x1000>; + reg-io-width = <4>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x1e789000 0x1000>; - lpc_bmc: lpc-bmc@0 { - compatible = "aspeed,ast2600-lpc-bmc", "simple-mfd", "syscon"; - reg = <0x0 0x80>; - reg-io-width = <4>; - - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x80>; - - kcs1: kcs@24 { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>; - interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; - kcs_chan = <1>; - status = "disabled"; - }; - kcs2: kcs@28 { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>; - interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; - kcs3: kcs@2c { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>; - interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; + kcs1: kcs@24 { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>; + interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; + kcs_chan = <1>; + status = "disabled"; + }; + + kcs2: kcs@28 { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>; + interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + kcs3: kcs@2c { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>; + interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + kcs4: kcs@114 { + compatible = "aspeed,ast2500-kcs-bmc-v2"; + reg = <0x114 0x1>, <0x118 0x1>, <0x11c 0x1>; + interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + lpc_ctrl: lpc-ctrl@80 { + compatible = "aspeed,ast2600-lpc-ctrl"; + reg = <0x80 0x80>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + + lpc_snoop: lpc-snoop@80 { + compatible = "aspeed,ast2600-lpc-snoop"; + reg = <0x80 0x80>; + interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; }; - lpc_host: lpc-host@80 { - compatible = "aspeed,ast2600-lpc-host", "simple-mfd", "syscon"; - reg = <0x80 0x1e0>; - reg-io-width = <4>; - - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x80 0x1e0>; - - kcs4: kcs@94 { - compatible = "aspeed,ast2500-kcs-bmc-v2"; - reg = <0x94 0x1>, <0x98 0x1>, <0x9c 0x1>; - interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; - - lpc_ctrl: lpc-ctrl@0 { - compatible = "aspeed,ast2600-lpc-ctrl"; - reg = <0x0 0x80>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - status = "disabled"; - }; - - lpc_snoop: lpc-snoop@0 { - compatible = "aspeed,ast2600-lpc-snoop"; - reg = <0x0 0x80>; - interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&syscon ASPEED_CLK_GATE_LCLK>; - status = "disabled"; - }; - - lhc: lhc@20 { - compatible = "aspeed,ast2600-lhc"; - reg = <0x20 0x24 0x48 0x8>; - }; - - lpc_reset: reset-controller@18 { - compatible = "aspeed,ast2600-lpc-reset"; - reg = <0x18 0x4>; - #reset-cells = <1>; - }; - - ibt: ibt@c0 { - compatible = "aspeed,ast2600-ibt-bmc"; - reg = <0xc0 0x18>; - interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; + lhc: lhc@a0 { + compatible = "aspeed,ast2600-lhc"; + reg = <0xa0 0x24 0xc8 0x8>; + }; + + lpc_reset: reset-controller@98 { + compatible = "aspeed,ast2600-lpc-reset"; + reg = <0x98 0x4>; + #reset-cells = <1>; + }; + + ibt: ibt@140 { + compatible = "aspeed,ast2600-ibt-bmc"; + reg = <0x140 0x18>; + interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/at91-sam9x60ek.dts b/arch/arm/boot/dts/at91-sam9x60ek.dts index 775ceb3acb6c01074b8277f8ce1fcb2cdecbe65f..edca66c232c154e0c3f1275fdf2c73faa797d04a 100644 --- a/arch/arm/boot/dts/at91-sam9x60ek.dts +++ b/arch/arm/boot/dts/at91-sam9x60ek.dts @@ -8,6 +8,7 @@ */ /dts-v1/; #include "sam9x60.dtsi" +#include <dt-bindings/input/input.h> / { model = "Microchip SAM9X60-EK"; @@ -84,7 +85,7 @@ sw1 { label = "SW1"; gpios = <&pioD 18 GPIO_ACTIVE_LOW>; - linux,code=<0x104>; + linux,code=<KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts b/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts index 84e1180f3e89d2ece9bbf96b6a56b907a6ff79b8..a9e6fee55a2a8f76338891d5d988619108d96e26 100644 --- a/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts +++ b/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts @@ -11,6 +11,7 @@ #include "at91-sama5d27_som1.dtsi" #include <dt-bindings/mfd/atmel-flexcom.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> / { model = "Atmel SAMA5D27 SOM1 EK"; @@ -466,7 +467,7 @@ pb4 { label = "USER"; gpios = <&pioA PIN_PA29 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d27_wlsom1_ek.dts b/arch/arm/boot/dts/at91-sama5d27_wlsom1_ek.dts index 180a08765cb8523393730b746fc2b7e9be4134d0..ff83967fd0082fcd7cda85a0a6d22ecf4a76808d 100644 --- a/arch/arm/boot/dts/at91-sama5d27_wlsom1_ek.dts +++ b/arch/arm/boot/dts/at91-sama5d27_wlsom1_ek.dts @@ -8,6 +8,7 @@ */ /dts-v1/; #include "at91-sama5d27_wlsom1.dtsi" +#include <dt-bindings/input/input.h> / { model = "Microchip SAMA5D27 WLSOM1 EK"; @@ -35,7 +36,7 @@ sw4 { label = "USER BUTTON"; gpios = <&pioA PIN_PB2 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_icp.dts b/arch/arm/boot/dts/at91-sama5d2_icp.dts index 46722a163184ec29a75068913a48aecf1a71b4e6..bd64721fa23caa546249af579bd8df64c98fb9c9 100644 --- a/arch/arm/boot/dts/at91-sama5d2_icp.dts +++ b/arch/arm/boot/dts/at91-sama5d2_icp.dts @@ -12,6 +12,7 @@ #include "sama5d2.dtsi" #include "sama5d2-pinfunc.h" #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> #include <dt-bindings/mfd/atmel-flexcom.h> / { @@ -51,7 +52,7 @@ sw4 { label = "USER_PB1"; gpios = <&pioA PIN_PD0 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts index 8de57d164acd3a1b1699e8138a0e0907045eb5fe..dfd150eb0fd86972fdbf0248ca88aebeeb6f0ec5 100644 --- a/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts +++ b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts @@ -11,6 +11,7 @@ #include "sama5d2-pinfunc.h" #include <dt-bindings/mfd/atmel-flexcom.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> #include <dt-bindings/pinctrl/at91.h> / { @@ -402,7 +403,7 @@ bp1 { label = "PB_USER"; gpios = <&pioA PIN_PA10 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 4e7cf21f124c010af9ab8a27ba9ff076f22fb3a2..509c732a0d8b48acb519e3473d14026ceab4a3f2 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -10,6 +10,7 @@ #include "sama5d2-pinfunc.h" #include <dt-bindings/mfd/atmel-flexcom.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> #include <dt-bindings/regulator/active-semi,8945a-regulator.h> / { @@ -712,7 +713,7 @@ bp1 { label = "PB_USER"; gpios = <&pioA PIN_PB9 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index 5179258f92470aebb2fa31e7ff45b81c9cf44f97..9c55a921263bdd062a29f29b49ed12525bdcf570 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -7,6 +7,7 @@ */ /dts-v1/; #include "sama5d36.dtsi" +#include <dt-bindings/input/input.h> / { model = "SAMA5D3 Xplained"; @@ -354,7 +355,7 @@ bp3 { label = "PB_USER"; gpios = <&pioE 29 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91sam9260ek.dts b/arch/arm/boot/dts/at91sam9260ek.dts index d3446e42b5983a515eabaef01ebcac4ba257f557..ce96345d28a396e6fb2a76ed1a39e6b5d1e03387 100644 --- a/arch/arm/boot/dts/at91sam9260ek.dts +++ b/arch/arm/boot/dts/at91sam9260ek.dts @@ -7,6 +7,7 @@ */ /dts-v1/; #include "at91sam9260.dtsi" +#include <dt-bindings/input/input.h> / { model = "Atmel at91sam9260ek"; @@ -156,7 +157,7 @@ btn4 { label = "Button 4"; gpios = <&pioA 31 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi index 6e6e672c0b86df1d91e57d92a41b8e59caa13146..87bb39060e8becd02c140e5d5effde8fef8295f0 100644 --- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -5,6 +5,7 @@ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> */ #include "at91sam9g20.dtsi" +#include <dt-bindings/input/input.h> / { @@ -234,7 +235,7 @@ btn4 { label = "Button 4"; gpios = <&pioA 31 GPIO_ACTIVE_LOW>; - linux,code = <0x104>; + linux,code = <KEY_PROG1>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts index 6a96655d86260920093d6489ecb02f93064fa1c1..8ed403767540e2fa6b859aca0d9dfcb9498e9d27 100644 --- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts +++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts index 3b0029e61b4c65b2ff95584df8554ffe7b7ef3be..667b118ba4ee1a35b2170414c689433cd200f243 100644 --- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts +++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts index 90f57bad6b24395fd59f89ae274beea11318155a..ff31ce45831a7b8bb8d224fae444559de9f0ff14 100644 --- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts +++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; }; spi { diff --git a/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts index 41548d6d479a54e3d40290783a00714cd7a2fe7e..5bac1e15775a346f9f27995a234ad39c9cc8ace3 100644 --- a/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts +++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts @@ -21,6 +21,11 @@ reg = <0x00000000 0x08000000>; }; + nvram@1c080000 { + compatible = "brcm,nvram"; + reg = <0x1c080000 0x180000>; + }; + gpio-keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts index fed75e6ab58ca8b2df9cec515784330f064a2726..61c7b137607e5d31d73c6eef76b7960636038585 100644 --- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts +++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts @@ -22,8 +22,8 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts index 79542e18915c5d964520e6e0b2212d6cb15129ed..4c60eda296d9737f7a0269da39952c401bf60d92 100644 --- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts +++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts index 51c64f0b25603d43e167deea65e01f591b67c2b5..9ca6d1b2590d4b59f9f5f75c6aaf6a12a247218a 100644 --- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts +++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts index c29950b43a95392b957271ab571bcd87982a6f58..0e273c598732f288915379e2c5e043c544a8e6a6 100644 --- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts +++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts index 2f2d2b0a6893c53df158924d22087c11d01b89d0..d857751ec5076422e68bdf80feaa6088d55aacbc 100644 --- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts +++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; spi { diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts index 0e349e39f6081e01430688aff0db5f2715ebf06b..8b1a05a0f1a115fcebe10fd9171c6f6cf0f7543b 100644 --- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts +++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; spi { diff --git a/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts b/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts index 432254383769a03d97dbc60f6b934a812df04cdb..9316a36434f7fed658bbbbaec45d1d3968f6e546 100644 --- a/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts +++ b/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts @@ -21,6 +21,11 @@ reg = <0x00000000 0x08000000>; }; + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; + }; + leds { compatible = "gpio-leds"; diff --git a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts index 8f1e565c3db45b709ba1a4be968d99aa174098ef..6c6bb7b17d27ab0ded09f7dbdca4ba8b5fc719c8 100644 --- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts +++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts @@ -21,8 +21,8 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts index ce888b1835d1f7e9a177067d8cd72372bd2eacc3..d29e7f80ea6aa144e9dfee27fbdfe867a6befd06 100644 --- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts +++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts @@ -21,8 +21,8 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts b/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts index ed8619b54d692e7d52026d44a03aebdd6e7b6fb3..9b6887d477d8610de811431b64cb5de6e5d30d83 100644 --- a/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts +++ b/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts @@ -18,8 +18,13 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; + }; + + nvram@1c080000 { + compatible = "brcm,nvram"; + reg = <0x1c080000 0x180000>; }; gpio-keys { diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts index 1f87993eae1d1a8407dd3e07256888806c1b882e..7989a53597d4fdd73f495b1d21d2aaa6377e16e2 100644 --- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts +++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts @@ -21,8 +21,8 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts index 6c6199a53d0918d707c362aae413dd7fde837545..87b655be674c540d9d288082eef71c072568c8e4 100644 --- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts @@ -32,8 +32,8 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts index 911c65fbf2510cddb06d1c5dc227f044d1ed6658..e635a15041dd8c133ec773f9c5b99f2f135c4b35 100644 --- a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts +++ b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts @@ -21,8 +21,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; }; nand: nand@18028000 { diff --git a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts index 3725f2b0d60bd2ca037158e28757decbb835ceea..05d4f2931772b405f6b9e6cab6a1bce9544b9bba 100644 --- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts +++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts @@ -18,8 +18,13 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; + }; + + nvram@1c080000 { + compatible = "brcm,nvram"; + reg = <0x1c080000 0x100000>; }; gpio-keys { @@ -70,6 +75,7 @@ power { label = "bcm53xx:white:power"; gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; }; wifi-disabled { @@ -274,7 +280,7 @@ &nandcs { partitions { - compatible = "fixed-partitions"; + compatible = "linksys,ns-partitions"; #address-cells = <1>; #size-cells = <1>; @@ -295,20 +301,18 @@ }; partition@200000 { - label = "firmware"; - reg = <0x0200000 0x01D00000>; - compatible = "brcm,trx"; + reg = <0x0200000 0x01d00000>; + compatible = "linksys,ns-firmware", "brcm,trx"; }; - partition@1F00000 { - label = "failsafe"; - reg = <0x01F00000 0x01D00000>; - read-only; + partition@1f00000 { + reg = <0x01f00000 0x01d00000>; + compatible = "linksys,ns-firmware", "brcm,trx"; }; partition@5200000 { label = "system"; - reg = <0x05200000 0x02E00000>; + reg = <0x05200000 0x02e00000>; }; }; }; diff --git a/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts b/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts index 50f7cd08cfbbc41e6d76211f0510cb977e2dbc7f..4b8117f32d2627549eca1b3772093d42cf1048a1 100644 --- a/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts +++ b/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts @@ -18,8 +18,13 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; + }; + + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts b/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts index bcc420f85b566fe73e93e62a09f1f6f31702cc62..5fecce0422c79b3104ec6cf62d1dc3819065abd6 100644 --- a/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts +++ b/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts @@ -18,8 +18,13 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; + }; + + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts index 4f8d777ae18de35a18d933b0b6def73071a7d44c..452b8d0ab180ef613e11d31f06dfcaf0d7163129 100644 --- a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts +++ b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts @@ -18,8 +18,8 @@ memory { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts index e17e9a17fb0088720bceaa25d03cd442cfc4f384..cbe8c8e4a301271cb546aab25f268893935f76c3 100644 --- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts +++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts @@ -18,8 +18,13 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x08000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x08000000>; + }; + + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts index 60cc87ecc7ece4bc71970eac6da3aeed78de1102..24ae3c8a3e09679f1c0a0d29c9445248bb8cd4b1 100644 --- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts +++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts @@ -18,8 +18,13 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; + }; + + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts index f42a1703f4ab1a90cc728c45f2e1a544ef1b71df..42097a4c2659f926afa4089fb30cda7e657ef389 100644 --- a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts +++ b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts @@ -18,8 +18,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; }; leds { diff --git a/arch/arm/boot/dts/bcm47094-phicomm-k3.dts b/arch/arm/boot/dts/bcm47094-phicomm-k3.dts index ac3a4483dcb3f870c77751bfc0c5a4d536a374ca..a2566ad4619c48bc0c61fe45de68d99333e85120 100644 --- a/arch/arm/boot/dts/bcm47094-phicomm-k3.dts +++ b/arch/arm/boot/dts/bcm47094-phicomm-k3.dts @@ -15,8 +15,8 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x08000000 - 0x88000000 0x18000000>; + reg = <0x00000000 0x08000000>, + <0x88000000 0x18000000>; }; gpio-keys { diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi index 3bf90d9e33353b366d826b876d0b40101ad01e36..149144cdff35a9cd0fe82317fe52cd5bcff3f2e1 100644 --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -1,5 +1,8 @@ &l4_cfg { /* 0x4a000000 */ - compatible = "ti,dra7-l4-cfg", "simple-bus"; + compatible = "ti,dra7-l4-cfg", "simple-pm-bus"; + power-domains = <&prm_coreaon>; + clocks = <&l4cfg_clkctrl DRA7_L4CFG_L4_CFG_CLKCTRL 0>; + clock-names = "fck"; reg = <0x4a000000 0x800>, <0x4a000800 0x800>, <0x4a001000 0x1000>; @@ -11,7 +14,7 @@ <0x00200000 0x4a200000 0x100000>; /* segment 2 */ segment@0 { /* 0x4a000000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -493,7 +496,7 @@ }; segment@100000 { /* 0x4a100000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00002000 0x00102000 0x001000>, /* ap 27 */ @@ -572,11 +575,33 @@ }; target-module@40000 { /* 0x4a140000, ap 31 06.0 */ - compatible = "ti,sysc"; - status = "disabled"; - #address-cells = <1>; + compatible = "ti,sysc-omap4", "ti,sysc"; + reg = <0x400fc 4>, + <0x41100 4>; + reg-names = "rev", "sysc"; + ti,sysc-midle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>, + <SYSC_IDLE_SMART_WKUP>; + power-domains = <&prm_l3init>; + clocks = <&l3init_clkctrl DRA7_L3INIT_SATA_CLKCTRL 0>; + clock-names = "fck"; #size-cells = <1>; + #address-cells = <1>; ranges = <0x0 0x40000 0x10000>; + + sata: sata@0 { + compatible = "snps,dwc-ahci"; + reg = <0 0x1100>, <0x1100 0x8>; + interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; + phys = <&sata_phy>; + phy-names = "sata-phy"; + clocks = <&l3init_clkctrl DRA7_L3INIT_SATA_CLKCTRL 8>; + ports-implemented = <0x1>; + }; }; target-module@51000 { /* 0x4a151000, ap 33 50.0 */ @@ -789,7 +814,7 @@ }; segment@200000 { /* 0x4a200000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00018000 0x00218000 0x001000>, /* ap 43 */ @@ -1006,7 +1031,10 @@ }; &l4_per1 { /* 0x48000000 */ - compatible = "ti,dra7-l4-per1", "simple-bus"; + compatible = "ti,dra7-l4-per1", "simple-pm-bus"; + power-domains = <&prm_l4per>; + clocks = <&l4per_clkctrl DRA7_L4PER_L4_PER1_CLKCTRL 0>; + clock-names = "fck"; reg = <0x48000000 0x800>, <0x48000800 0x800>, <0x48001000 0x400>, @@ -1020,7 +1048,7 @@ <0x00200000 0x48200000 0x200000>; /* segment 1 */ segment@0 { /* 0x48000000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -1168,7 +1196,7 @@ }; }; - target-module@34000 { /* 0x48034000, ap 7 46.0 */ + timer3_target: target-module@34000 { /* 0x48034000, ap 7 46.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; reg = <0x34000 0x4>, <0x34010 0x4>; @@ -1195,7 +1223,7 @@ }; }; - target-module@36000 { /* 0x48036000, ap 9 4e.0 */ + timer4_target: target-module@36000 { /* 0x48036000, ap 9 4e.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; reg = <0x36000 0x4>, <0x36010 0x4>; @@ -2269,14 +2297,17 @@ }; segment@200000 { /* 0x48200000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; }; &l4_per2 { /* 0x48400000 */ - compatible = "ti,dra7-l4-per2", "simple-bus"; + compatible = "ti,dra7-l4-per2", "simple-pm-bus"; + power-domains = <&prm_l4per>; + clocks = <&l4per2_clkctrl DRA7_L4PER2_L4_PER2_CLKCTRL 0>; + clock-names = "fck"; reg = <0x48400000 0x800>, <0x48400800 0x800>, <0x48401000 0x400>, @@ -2296,7 +2327,7 @@ <0x48454000 0x48454000 0x400000>; /* L3 data port */ segment@0 { /* 0x48400000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -3094,7 +3125,10 @@ }; &l4_per3 { /* 0x48800000 */ - compatible = "ti,dra7-l4-per3", "simple-bus"; + compatible = "ti,dra7-l4-per3", "simple-pm-bus"; + power-domains = <&prm_l4per>; + clocks = <&l4per3_clkctrl DRA7_L4PER3_L4_PER3_CLKCTRL 0>; + clock-names = "fck"; reg = <0x48800000 0x800>, <0x48800800 0x800>, <0x48801000 0x400>, @@ -3106,7 +3140,7 @@ ranges = <0x00000000 0x48800000 0x200000>; /* segment 0 */ segment@0 { /* 0x48800000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -4205,7 +4239,10 @@ }; &l4_wkup { /* 0x4ae00000 */ - compatible = "ti,dra7-l4-wkup", "simple-bus"; + compatible = "ti,dra7-l4-wkup", "simple-pm-bus"; + power-domains = <&prm_wkupaon>; + clocks = <&wkupaon_clkctrl DRA7_WKUPAON_L4_WKUP_CLKCTRL 0>; + clock-names = "fck"; reg = <0x4ae00000 0x800>, <0x4ae00800 0x800>, <0x4ae01000 0x1000>; @@ -4218,7 +4255,7 @@ <0x00030000 0x4ae30000 0x010000>; /* segment 3 */ segment@0 { /* 0x4ae00000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -4295,7 +4332,7 @@ }; segment@10000 { /* 0x4ae10000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00010000 0x001000>, /* ap 5 */ @@ -4405,7 +4442,7 @@ }; segment@20000 { /* 0x4ae20000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00006000 0x00026000 0x001000>, /* ap 13 */ @@ -4511,7 +4548,7 @@ }; segment@30000 { /* 0x4ae30000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x0000c000 0x0003c000 0x002000>, /* ap 30 */ diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index ce1194744f84025210f5c706e412e10b1267abd0..dfc1ef8ef6aea16941c4cc75f53d45d767611309 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -46,6 +46,7 @@ timer { compatible = "arm,armv7-timer"; + status = "disabled"; /* See ARM architected timer wrap erratum i940 */ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, @@ -124,18 +125,6 @@ }; }; - /* - * The soc node represents the soc top level view. It is used for IPs - * that are not memory mapped in the MPU view or for the MPU itself. - */ - soc { - compatible = "ti,omap-infra"; - mpu { - compatible = "ti,omap5-mpu"; - ti,hwmods = "mpu"; - }; - }; - /* * XXX: Use a flat representation of the SOC interconnect. * The real OMAP interconnect network is quite complex. @@ -144,16 +133,22 @@ * hierarchy. */ ocp: ocp { - compatible = "ti,dra7-l3-noc", "simple-bus"; + compatible = "simple-pm-bus"; + power-domains = <&prm_core>; + clocks = <&l3main1_clkctrl DRA7_L3MAIN1_L3_MAIN_1_CLKCTRL 0>, + <&l3instr_clkctrl DRA7_L3INSTR_L3_MAIN_2_CLKCTRL 0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x0 0x0 0xc0000000>; dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>; - ti,hwmods = "l3_main_1", "l3_main_2"; - reg = <0x0 0x44000000 0x0 0x1000000>, - <0x0 0x45000000 0x0 0x1000>; - interrupts-extended = <&crossbar_mpu GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, - <&wakeupgen GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + + l3-noc@44000000 { + compatible = "ti,dra7-l3-noc"; + reg = <0x44000000 0x1000>, + <0x45000000 0x1000>; + interrupts-extended = <&crossbar_mpu GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, + <&wakeupgen GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + }; l4_cfg: interconnect@4a000000 { }; @@ -161,36 +156,65 @@ }; l4_per1: interconnect@48000000 { }; + + target-module@48210000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + power-domains = <&prm_mpu>; + clocks = <&mpu_clkctrl DRA7_MPU_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x48210000 0x1f0000>; + + mpu { + compatible = "ti,omap5-mpu"; + }; + }; + l4_per2: interconnect@48400000 { }; l4_per3: interconnect@48800000 { }; - axi@0 { - compatible = "simple-bus"; + /* + * Register access seems to have complex dependencies and also + * seems to need an enabled phy. See the TRM chapter for "Table + * 26-678. Main Sequence PCIe Controller Global Initialization" + * and also dra7xx_pcie_probe(). + */ + axi0: target-module@51000000 { + compatible = "ti,sysc-omap4", "ti,sysc"; + power-domains = <&prm_l3init>; + resets = <&prm_l3init 0>; + reset-names = "rstctrl"; + clocks = <&pcie_clkctrl DRA7_PCIE_PCIE1_CLKCTRL 0>, + <&pcie_clkctrl DRA7_PCIE_PCIE1_CLKCTRL 9>, + <&pcie_clkctrl DRA7_PCIE_PCIE1_CLKCTRL 10>; + clock-names = "fck", "phy-clk", "phy-clk-div"; #size-cells = <1>; #address-cells = <1>; - ranges = <0x51000000 0x51000000 0x3000 - 0x0 0x20000000 0x10000000>; + ranges = <0x51000000 0x51000000 0x3000>, + <0x20000000 0x20000000 0x10000000>; dma-ranges; /** * To enable PCI endpoint mode, disable the pcie1_rc * node and enable pcie1_ep mode. */ pcie1_rc: pcie@51000000 { - reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>; + reg = <0x51000000 0x2000>, + <0x51002000 0x14c>, + <0x20001000 0x2000>; reg-names = "rc_dbics", "ti_conf", "config"; interrupts = <0 232 0x4>, <0 233 0x4>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; - ranges = <0x81000000 0 0 0x03000 0 0x00010000 - 0x82000000 0 0x20013000 0x13000 0 0xffed000>; + ranges = <0x81000000 0 0x00000000 0x20003000 0 0x00010000>, + <0x82000000 0 0x20013000 0x20013000 0 0x0ffed000>; bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; linux,pci-domain = <0>; - ti,hwmods = "pcie1"; phys = <&pcie1_phy>; phy-names = "pcie-phy0"; ti,syscon-lane-sel = <&scm_conf_pcie 0x18>; @@ -209,13 +233,15 @@ }; pcie1_ep: pcie_ep@51000000 { - reg = <0x51000000 0x28>, <0x51002000 0x14c>, <0x51001000 0x28>, <0x1000 0x10000000>; + reg = <0x51000000 0x28>, + <0x51002000 0x14c>, + <0x51001000 0x28>, + <0x20001000 0x10000000>; reg-names = "ep_dbics", "ti_conf", "ep_dbics2", "addr_space"; interrupts = <0 232 0x4>; num-lanes = <1>; num-ib-windows = <4>; num-ob-windows = <16>; - ti,hwmods = "pcie1"; phys = <&pcie1_phy>; phy-names = "pcie-phy0"; ti,syscon-unaligned-access = <&scm_conf1 0x14 1>; @@ -224,28 +250,42 @@ }; }; - axi@1 { - compatible = "simple-bus"; + /* + * Register access seems to have complex dependencies and also + * seems to need an enabled phy. See the TRM chapter for "Table + * 26-678. Main Sequence PCIe Controller Global Initialization" + * and also dra7xx_pcie_probe(). + */ + axi1: target-module@51800000 { + compatible = "ti,sysc-omap4", "ti,sysc"; + clocks = <&pcie_clkctrl DRA7_PCIE_PCIE2_CLKCTRL 0>, + <&pcie_clkctrl DRA7_PCIE_PCIE2_CLKCTRL 9>, + <&pcie_clkctrl DRA7_PCIE_PCIE2_CLKCTRL 10>; + clock-names = "fck", "phy-clk", "phy-clk-div"; + power-domains = <&prm_l3init>; + resets = <&prm_l3init 1>; + reset-names = "rstctrl"; #size-cells = <1>; #address-cells = <1>; - ranges = <0x51800000 0x51800000 0x3000 - 0x0 0x30000000 0x10000000>; + ranges = <0x51800000 0x51800000 0x3000>, + <0x30000000 0x30000000 0x10000000>; dma-ranges; status = "disabled"; pcie2_rc: pcie@51800000 { - reg = <0x51800000 0x2000>, <0x51802000 0x14c>, <0x1000 0x2000>; + reg = <0x51800000 0x2000>, + <0x51802000 0x14c>, + <0x30001000 0x2000>; reg-names = "rc_dbics", "ti_conf", "config"; interrupts = <0 355 0x4>, <0 356 0x4>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; - ranges = <0x81000000 0 0 0x03000 0 0x00010000 - 0x82000000 0 0x30013000 0x13000 0 0xffed000>; + ranges = <0x81000000 0 0x00000000 0x30003000 0 0x00010000>, + <0x82000000 0 0x30013000 0x30013000 0 0x0ffed000>; bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; linux,pci-domain = <1>; - ti,hwmods = "pcie2"; phys = <&pcie2_phy>; phy-names = "pcie-phy0"; interrupt-map-mask = <0 0 0 7>; @@ -336,8 +376,15 @@ target-module@43300000 { compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x43300000 0x4>; - reg-names = "rev"; + reg = <0x43300000 0x4>, + <0x43300010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-midle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; clocks = <&l3main1_clkctrl DRA7_L3MAIN1_TPCC_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; @@ -369,8 +416,15 @@ target-module@43400000 { compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x43400000 0x4>; - reg-names = "rev"; + reg = <0x43400000 0x4>, + <0x43400010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-midle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; clocks = <&l3main1_clkctrl DRA7_L3MAIN1_TPTC0_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; @@ -387,8 +441,15 @@ target-module@43500000 { compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x43500000 0x4>; - reg-names = "rev"; + reg = <0x43500000 0x4>, + <0x43500010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-midle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; clocks = <&l3main1_clkctrl DRA7_L3MAIN1_TPTC1_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; @@ -403,11 +464,23 @@ }; }; - dmm@4e000000 { - compatible = "ti,omap5-dmm"; - reg = <0x4e000000 0x800>; - interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; - ti,hwmods = "dmm"; + target-module@4e000000 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0x4e000000 0x4>, + <0x4e000010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ranges = <0x0 0x4e000000 0x2000000>; + #size-cells = <1>; + #address-cells = <1>; + + dmm@0 { + compatible = "ti,omap5-dmm"; + reg = <0 0x800>; + interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; + }; }; ipu1: ipu@58820000 { @@ -694,32 +767,36 @@ >; }; - qspi: spi@4b300000 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4b300000 0x100>, - <0x5c000000 0x4000000>; - reg-names = "qspi_base", "qspi_mmap"; - syscon-chipselects = <&scm_conf 0x558>; - #address-cells = <1>; - #size-cells = <0>; - ti,hwmods = "qspi"; - clocks = <&l4per2_clkctrl DRA7_L4PER2_QSPI_CLKCTRL 25>; + target-module@4b300000 { + compatible = "ti,sysc-omap4", "ti,sysc"; + reg = <0x4b300000 0x4>, + <0x4b300010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>, + <SYSC_IDLE_SMART_WKUP>; + clocks = <&l4per2_clkctrl DRA7_L4PER2_QSPI_CLKCTRL 0>; clock-names = "fck"; - num-cs = <4>; - interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; - - /* OCP2SCP3 */ - sata: sata@4a141100 { - compatible = "snps,dwc-ahci"; - reg = <0x4a140000 0x1100>, <0x4a141100 0x7>; - interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; - phys = <&sata_phy>; - phy-names = "sata-phy"; - clocks = <&l3init_clkctrl DRA7_L3INIT_SATA_CLKCTRL 8>; - ti,hwmods = "sata"; - ports-implemented = <0x1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4b300000 0x1000>, + <0x5c000000 0x5c000000 0x4000000>; + + qspi: spi@0 { + compatible = "ti,dra7xxx-qspi"; + reg = <0 0x100>, + <0x5c000000 0x4000000>; + reg-names = "qspi_base", "qspi_mmap"; + syscon-chipselects = <&scm_conf 0x558>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&l4per2_clkctrl DRA7_L4PER2_QSPI_CLKCTRL 25>; + clock-names = "fck"; + num-cs = <4>; + interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; }; /* OCP2SCP1 */ @@ -1241,3 +1318,22 @@ assigned-clock-parents = <&sys_32k_ck>; }; }; + +/* Local timers, see ARM architected timer wrap erratum i940 */ +&timer3_target { + ti,no-reset-on-init; + ti,no-idle; + timer@0 { + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>; + assigned-clock-parents = <&timer_sys_clk_div>; + }; +}; + +&timer4_target { + ti,no-reset-on-init; + ti,no-idle; + timer@0 { + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>; + assigned-clock-parents = <&timer_sys_clk_div>; + }; +}; diff --git a/arch/arm/boot/dts/ep7209.dtsi b/arch/arm/boot/dts/ep7209.dtsi index 365931f8b48d19ced278fccdf14c2ba517a9ac68..57bdad2c199478d63bcfd38bab80d81f4bb196d7 100644 --- a/arch/arm/boot/dts/ep7209.dtsi +++ b/arch/arm/boot/dts/ep7209.dtsi @@ -10,6 +10,8 @@ model = "Cirrus Logic EP7209"; compatible = "cirrus,ep7209"; + chosen { }; + aliases { gpio0 = &porta; gpio1 = &portb; @@ -108,6 +110,7 @@ compatible = "cirrus,ep7209-fb"; reg = <0x800002c0 0xd44>, <0x60000000 0xc000>; clocks = <&clks CLPS711X_CLK_BUS>; + syscon = <&syscon1>; status = "disabled"; }; @@ -132,7 +135,7 @@ #pwm-cells = <1>; }; - uart1: uart@80000480 { + uart1: serial@80000480 { compatible = "cirrus,ep7209-uart"; reg = <0x80000480 0x80>; interrupts = <12 13>; @@ -147,6 +150,7 @@ reg = <0x80000500 0x4>; interrupts = <15>; clocks = <&clks CLPS711X_CLK_SPI>; + syscon = <&syscon3>; status = "disabled"; }; @@ -155,7 +159,7 @@ reg = <0x80001100 0x80>; }; - uart2: uart@80001480 { + uart2: serial@80001480 { compatible = "cirrus,ep7209-uart"; reg = <0x80001480 0x80>; interrupts = <28 29>; @@ -170,6 +174,7 @@ clocks = <&clks CLPS711X_CLK_PLL>; clock-names = "pll"; interrupts = <32>; + syscon = <&syscon3>; status = "disabled"; }; @@ -179,8 +184,17 @@ }; }; + keypad: keypad { + compatible = "cirrus,ep7209-keypad"; + interrupt-parent = <&intc>; + interrupts = <16>; + syscon = <&syscon1>; + status = "disabled"; + }; + mctrl: mctrl { compatible = "cirrus,ep7209-mctrl-gpio"; + gpio,syscon-dev = <&syscon1 0 0>; gpio-controller; #gpio-cells = <2>; }; diff --git a/arch/arm/boot/dts/ep7211-edb7211.dts b/arch/arm/boot/dts/ep7211-edb7211.dts index da076479c8e2cb487a22fbf28715ac5af82a350d..7fb532f227afb6c7b687ceee4561c1e65a481c31 100644 --- a/arch/arm/boot/dts/ep7211-edb7211.dts +++ b/arch/arm/boot/dts/ep7211-edb7211.dts @@ -7,7 +7,7 @@ model = "Cirrus Logic EP7211 Development Board"; compatible = "cirrus,edb7211", "cirrus,ep7211", "cirrus,ep7209"; - memory { + memory@c0000000 { device_type = "memory"; reg = <0xc0000000 0x02000000>; }; diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts index fae046e08a5dd359c6bb0e624e6b6f56ee2ed18a..8b41a9d5e2db989eea1a291433815d8478957c2c 100644 --- a/arch/arm/boot/dts/exynos3250-monk.dts +++ b/arch/arm/boot/dts/exynos3250-monk.dts @@ -142,7 +142,7 @@ assigned-clock-rates = <6000000>; thermistor-ap { - compatible = "ntc,ncp15wb473"; + compatible = "murata,ncp15wb473"; pullup-uv = <1800000>; pullup-ohm = <100000>; pulldown-ohm = <100000>; @@ -150,7 +150,7 @@ }; thermistor-battery { - compatible = "ntc,ncp15wb473"; + compatible = "murata,ncp15wb473"; pullup-uv = <1800000>; pullup-ohm = <100000>; pulldown-ohm = <100000>; diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts index d64ccf4b7d3240a841c22371d82ab2a6eac74891..c52b9cf4f74c2b9d43f2fd92ae4a9de77f359b3d 100644 --- a/arch/arm/boot/dts/exynos3250-rinato.dts +++ b/arch/arm/boot/dts/exynos3250-rinato.dts @@ -142,7 +142,7 @@ assigned-clock-rates = <6000000>; thermistor-ap { - compatible = "ntc,ncp15wb473"; + compatible = "murata,ncp15wb473"; pullup-uv = <1800000>; pullup-ohm = <100000>; pulldown-ohm = <100000>; @@ -150,7 +150,7 @@ }; thermistor-battery { - compatible = "ntc,ncp15wb473"; + compatible = "murata,ncp15wb473"; pullup-uv = <1800000>; pullup-ohm = <100000>; pulldown-ohm = <100000>; diff --git a/arch/arm/boot/dts/exynos4210-i9100.dts b/arch/arm/boot/dts/exynos4210-i9100.dts index 304a8ee2364c59c495637bcfaa45831efa845246..525ff3d2fac342f6472b45243eefd7c9272b322f 100644 --- a/arch/arm/boot/dts/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/exynos4210-i9100.dts @@ -136,7 +136,7 @@ compatible = "maxim,max17042"; interrupt-parent = <&gpx2>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&max17042_fuel_irq>; pinctrl-names = "default"; @@ -147,6 +147,36 @@ }; }; + i2c_s5k5baf: i2c-gpio-1 { + compatible = "i2c-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + sda-gpios = <&gpc1 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpc1 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <2>; + + image-sensor@2d { + compatible = "samsung,s5k5baf"; + reg = <0x2d>; + vdda-supply = <&cam_io_en_reg>; + vddreg-supply = <&vt_core_15v_reg>; + vddio-supply = <&vtcam_reg>; + clocks = <&camera 0>; + clock-names = "mclk"; + stbyn-gpios = <&gpl2 0 GPIO_ACTIVE_LOW>; + rstn-gpios = <&gpl2 1 GPIO_ACTIVE_LOW>; + clock-frequency = <24000000>; + + port { + s5k5bafx_ep: endpoint { + remote-endpoint = <&csis1_ep>; + data-lanes = <1>; + }; + }; + }; + }; + spi-3 { compatible = "spi-gpio"; #address-cells = <1>; @@ -220,7 +250,29 @@ }; &camera { + pinctrl-0 = <&cam_port_a_clk_active>; + pinctrl-names = "default"; status = "okay"; + assigned-clocks = <&clock CLK_MOUT_CAM0>, <&clock CLK_MOUT_CAM1>; + assigned-clock-parents = <&clock CLK_XUSBXTI>, <&clock CLK_XUSBXTI>; +}; + +&csis_1 { + status = "okay"; + vddcore-supply = <&vusb_reg>; + vddio-supply = <&vmipi_reg>; + clock-frequency = <160000000>; + #address-cells = <1>; + #size-cells = <0>; + + port@4 { + reg = <4>; + csis1_ep: endpoint { + remote-endpoint = <&s5k5bafx_ep>; + data-lanes = <1>; + samsung,csis-hs-settle = <6>; + }; + }; }; &cpu0 { @@ -384,6 +436,8 @@ pinctrl-0 = <&max8997_irq>, <&otg_gp>, <&usb_sel>; pinctrl-names = "default"; + charger-supply = <&charger_reg>; + regulators { vadc_reg: LDO1 { regulator-name = "VADC_3.3V_C210"; diff --git a/arch/arm/boot/dts/exynos4412-midas.dtsi b/arch/arm/boot/dts/exynos4412-midas.dtsi index 111c32bae02c04c71872b7835f2d2dab20e8e203..fc77c1bfd844e654c25a160d84c651c9c508437f 100644 --- a/arch/arm/boot/dts/exynos4412-midas.dtsi +++ b/arch/arm/boot/dts/exynos4412-midas.dtsi @@ -173,7 +173,7 @@ pmic@66 { compatible = "maxim,max77693"; interrupt-parent = <&gpx1>; - interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&max77693_irq>; reg = <0x66>; @@ -221,7 +221,7 @@ fuel-gauge@36 { compatible = "maxim,max17047"; interrupt-parent = <&gpx2>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&max77693_fuel_irq>; reg = <0x36>; @@ -665,7 +665,7 @@ max77686: pmic@9 { compatible = "maxim,max77686"; interrupt-parent = <&gpx0>; - interrupts = <7 IRQ_TYPE_NONE>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&max77686_irq>; pinctrl-names = "default"; reg = <0x09>; diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 2b20d9095d9f2dd737ee535a7e5e9d921d6ef1b8..5bd05866d7a34853bcf68570458fd3950b44f316 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -2,7 +2,7 @@ /* * Common definition for Hardkernel's Exynos4412 based ODROID-X/X2/U2/U3 boards * device tree source -*/ + */ #include <dt-bindings/sound/samsung-i2s.h> #include <dt-bindings/input/input.h> @@ -122,6 +122,7 @@ }; &clock { + clocks = <&clock CLK_XUSBXTI>; assigned-clocks = <&clock CLK_FOUT_EPLL>; assigned-clock-rates = <45158401>; }; @@ -278,7 +279,7 @@ max77686: pmic@9 { compatible = "maxim,max77686"; interrupt-parent = <&gpx3>; - interrupts = <2 IRQ_TYPE_NONE>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&max77686_irq>; reg = <0x09>; diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts index 0e9d626e740a3abd738ed7662852e6b0dfa39b2b..440135d0ff2ab3ffe5df1b5a88b2b8a471559359 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts @@ -84,7 +84,8 @@ ethernet: usbether@1 { compatible = "usb0424,ec00"; reg = <1>; - local-mac-address = [00 00 00 00 00 00]; /* Filled in by a bootloader */ + /* Filled in by a bootloader */ + local-mac-address = [00 00 00 00 00 00]; }; }; }; diff --git a/arch/arm/boot/dts/exynos4412-p4note.dtsi b/arch/arm/boot/dts/exynos4412-p4note.dtsi index b2f9d5448a188ae9c82557d7d8993273da902cc7..9e750890edb87b5391eb85866f2cb9e4ff3065fb 100644 --- a/arch/arm/boot/dts/exynos4412-p4note.dtsi +++ b/arch/arm/boot/dts/exynos4412-p4note.dtsi @@ -146,7 +146,7 @@ pinctrl-0 = <&fuel_alert_irq>; pinctrl-names = "default"; interrupt-parent = <&gpx2>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; maxim,rsns-microohm = <10000>; maxim,over-heat-temp = <600>; maxim,over-volt = <4300>; @@ -322,7 +322,7 @@ max77686: pmic@9 { compatible = "maxim,max77686"; interrupt-parent = <&gpx0>; - interrupts = <7 IRQ_TYPE_NONE>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&max77686_irq>; pinctrl-names = "default"; reg = <0x09>; diff --git a/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi b/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi index 3a3b2fafefddcccac8ce3c20b9a88d122a94543a..7f187a3dedccbf31b3a7693839547792517c7f1c 100644 --- a/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi @@ -7,41 +7,41 @@ */ &ppmu_dmc0 { - status = "okay"; + status = "okay"; - events { - ppmu_dmc0_3: ppmu-event3-dmc0 { - event-name = "ppmu-event3-dmc0"; - }; - }; + events { + ppmu_dmc0_3: ppmu-event3-dmc0 { + event-name = "ppmu-event3-dmc0"; + }; + }; }; &ppmu_dmc1 { - status = "okay"; + status = "okay"; - events { - ppmu_dmc1_3: ppmu-event3-dmc1 { - event-name = "ppmu-event3-dmc1"; - }; - }; + events { + ppmu_dmc1_3: ppmu-event3-dmc1 { + event-name = "ppmu-event3-dmc1"; + }; + }; }; &ppmu_leftbus { - status = "okay"; + status = "okay"; - events { - ppmu_leftbus_3: ppmu-event3-leftbus { - event-name = "ppmu-event3-leftbus"; - }; - }; + events { + ppmu_leftbus_3: ppmu-event3-leftbus { + event-name = "ppmu-event3-leftbus"; + }; + }; }; &ppmu_rightbus { - status = "okay"; + status = "okay"; - events { - ppmu_rightbus_3: ppmu-event3-rightbus { - event-name = "ppmu-event3-rightbus"; - }; - }; + events { + ppmu_rightbus_3: ppmu-event3-rightbus { + event-name = "ppmu-event3-rightbus"; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 8b5a79a8720c67382e9f416932fefafcb6b8a0f6..39bbe18145cf242bf3864a4e07e805e70b6ac4db 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -134,7 +134,7 @@ compatible = "maxim,max77686"; reg = <0x09>; interrupt-parent = <&gpx3>; - interrupts = <2 IRQ_TYPE_NONE>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&max77686_irq>; #clock-cells = <1>; diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi index 6635f6184051e593d74dfdea7c30408f35a1841f..2335c46873494d19bc9db14698a4b66ff10672bd 100644 --- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi +++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi @@ -292,7 +292,7 @@ max77686: pmic@9 { compatible = "maxim,max77686"; interrupt-parent = <&gpx3>; - interrupts = <2 IRQ_TYPE_NONE>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&max77686_irq>; wakeup-source; diff --git a/arch/arm/boot/dts/exynos5410-pinctrl.dtsi b/arch/arm/boot/dts/exynos5410-pinctrl.dtsi index d0aa18443a69b4e8474ed4df18f7af161257e60d..9599ba8ba7988505f9262c3092872b68930af67f 100644 --- a/arch/arm/boot/dts/exynos5410-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5410-pinctrl.dtsi @@ -235,13 +235,13 @@ interrupt-parent = <&combiner>; #interrupt-cells = <2>; interrupts = <23 0>, - <24 0>, - <25 0>, - <25 1>, - <26 0>, - <26 1>, - <27 0>, - <27 1>; + <24 0>, + <25 0>, + <25 1>, + <26 0>, + <26 1>, + <27 0>, + <27 1>; }; gpx1: gpx1 { @@ -252,13 +252,13 @@ interrupt-parent = <&combiner>; #interrupt-cells = <2>; interrupts = <28 0>, - <28 1>, - <29 0>, - <29 1>, - <30 0>, - <30 1>, - <31 0>, - <31 1>; + <28 1>, + <29 0>, + <29 1>, + <30 0>, + <30 1>, + <31 0>, + <31 1>; }; gpx2: gpx2 { diff --git a/arch/arm/boot/dts/imx50-kobo-aura.dts b/arch/arm/boot/dts/imx50-kobo-aura.dts index 97cfd970fe742528938b01434109ba710ad0f6e4..82ce8c43be867efac9f21dd3c73b6960896e099d 100644 --- a/arch/arm/boot/dts/imx50-kobo-aura.dts +++ b/arch/arm/boot/dts/imx50-kobo-aura.dts @@ -143,10 +143,24 @@ pinctrl-0 = <&pinctrl_i2c3>; status = "okay"; - /* TODO: embedded controller at 0x43 */ + embedded-controller@43 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ec>; + compatible = "netronix,ntxec"; + reg = <0x43>; + system-power-controller; + interrupts-extended = <&gpio4 11 IRQ_TYPE_EDGE_FALLING>; + #pwm-cells = <2>; + }; }; &iomuxc { + pinctrl_ec: ecgrp { + fsl,pins = < + MX50_PAD_CSPI_SS0__GPIO4_11 0x0 /* INT */ + >; + }; + pinctrl_gpiokeys: gpiokeysgrp { fsl,pins = < MX50_PAD_CSPI_MISO__GPIO4_10 0x0 diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 7ebb46ce9e362cb0dcab01f817686b621086a6a4..01cfcbe5928e83a1c7514d8cbd94c461ef85e761 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -467,7 +467,7 @@ }; iim: efuse@83f98000 { - compatible = "fsl,imx51-iim", "fsl,imx27-iim"; + compatible = "fsl,imx51-iim", "fsl,imx27-iim", "syscon"; reg = <0x83f98000 0x4000>; interrupts = <69>; clocks = <&clks IMX5_CLK_IIM_GATE>; diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi b/arch/arm/boot/dts/imx53-qsb-common.dtsi index 9b4efcd82636d354c59825386b723ca6f76326c0..fe4244044a0f3be8b10e4bb7d0d4f077a194d92c 100644 --- a/arch/arm/boot/dts/imx53-qsb-common.dtsi +++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi @@ -142,6 +142,7 @@ &esdhc1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_esdhc1>; + cd-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; status = "okay"; }; @@ -209,6 +210,7 @@ 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 >; }; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 000050aeeabe071d0523741322dc95a3be292644..2cf3909cca2f871a4936d8f927d57c8b7377cf25 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -668,7 +668,7 @@ }; iim: efuse@63f98000 { - compatible = "fsl,imx53-iim", "fsl,imx27-iim"; + compatible = "fsl,imx53-iim", "fsl,imx27-iim", "syscon"; reg = <0x63f98000 0x4000>; interrupts = <69>; clocks = <&clks IMX5_CLK_IIM_GATE>; diff --git a/arch/arm/boot/dts/imx6dl-plybas.dts b/arch/arm/boot/dts/imx6dl-plybas.dts index 333c306aa946313da745cb3064990f4e974533d3..bf72a67a9c7618793d8c649aa2ee92d10199a65b 100644 --- a/arch/arm/boot/dts/imx6dl-plybas.dts +++ b/arch/arm/boot/dts/imx6dl-plybas.dts @@ -19,17 +19,15 @@ gpio_keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; autorepeat; - button@20 { + button-start { label = "START"; linux,code = <31>; gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; }; - button@21 { + button-clean { label = "CLEAN"; linux,code = <46>; gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/imx6q-b450v3.dts b/arch/arm/boot/dts/imx6q-b450v3.dts index 604f2420370fb3db1a86ecffb41d707540b1c9de..d994b32ad825c9e667da08eb36655ed267468b53 100644 --- a/arch/arm/boot/dts/imx6q-b450v3.dts +++ b/arch/arm/boot/dts/imx6q-b450v3.dts @@ -84,6 +84,11 @@ }; &pca9539 { + gpio-line-names = "AMB_P_INT1#", "AMB_P_INT2#", "BT_EN", "WLAN_EN", + "", "SM_D_ACT", "DP1_RST#", "", + "WD15S_EN", "WD15S_DIS#", "", "", + "", "", "", ""; + P04-hog { gpio-hog; gpios = <4 0>; diff --git a/arch/arm/boot/dts/imx6q-b650v3.dts b/arch/arm/boot/dts/imx6q-b650v3.dts index 56d2aeb1900c5250465bcb557539f93c6f56ae9f..fa1a1df37cde1cb59aee4a1224e4428fb2ed563c 100644 --- a/arch/arm/boot/dts/imx6q-b650v3.dts +++ b/arch/arm/boot/dts/imx6q-b650v3.dts @@ -84,6 +84,11 @@ }; &pca9539 { + gpio-line-names = "AMB_P_INT1#", "AMB_P_INT2#", "BT_EN", "WLAN_EN", + "", "SM_D_ACT", "DP1_RST#", "", + "WD15S_EN", "WD15S_DIS#", "", "", + "", "", "", ""; + P07-hog { gpio-hog; gpios = <7 0>; diff --git a/arch/arm/boot/dts/imx6q-b850v3.dts b/arch/arm/boot/dts/imx6q-b850v3.dts index 3d6b757bf325df6497f7f0e8f51e98edd5416e04..db8c332df6a1d53f1b3eff6572a9f080ac10fe0a 100644 --- a/arch/arm/boot/dts/imx6q-b850v3.dts +++ b/arch/arm/boot/dts/imx6q-b850v3.dts @@ -199,6 +199,11 @@ }; &pca9539 { + gpio-line-names = "AMB_P_INT1#", "AMB_P_INT2#", "BT_EN", "WLAN_EN", + "REMOTE_ON_PML#", "SM_D_ACT", "DP1_RST#", "DP2_RST#", + "", "", "", "", + "", "", "", ""; + P10-hog { gpio-hog; gpios = <8 0>; diff --git a/arch/arm/boot/dts/imx6q-ba16.dtsi b/arch/arm/boot/dts/imx6q-ba16.dtsi index e4578ed3371ef27dcf2b9f0cecadb024b6aae92e..6330d75f8f39082f08b4c11c527a03314a008858 100644 --- a/arch/arm/boot/dts/imx6q-ba16.dtsi +++ b/arch/arm/boot/dts/imx6q-ba16.dtsi @@ -124,6 +124,9 @@ regulator-name = "usb_otg_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; + pinctrl-0 = <&pinctrl_usbotg_vbus>; + gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; + enable-active-high; }; }; @@ -172,7 +175,19 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii-id"; + phy-supply = <®_3p3v>; + phy-handle = <&phy0>; status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@4 { + reg = <4>; + qca,clk-out-frequency = <125000000>; + }; + }; }; &hdmi { @@ -575,6 +590,12 @@ >; }; + pinctrl_usbotg_vbus: usbotgvbusgrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x000b0 + >; + }; + pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 diff --git a/arch/arm/boot/dts/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/imx6q-bx50v3.dtsi index 2a98cc657595f705cc48ee6c6fc06e5303f94636..10922375c51e122be1a77e16aeb81d57f6e9e4bc 100644 --- a/arch/arm/boot/dts/imx6q-bx50v3.dtsi +++ b/arch/arm/boot/dts/imx6q-bx50v3.dtsi @@ -173,8 +173,8 @@ &i2c1 { pinctrl-names = "default", "gpio"; pinctrl-1 = <&pinctrl_i2c1_gpio>; - sda-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>; - scl-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio5 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio5 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; pca9547: mux@70 { compatible = "nxp,pca9547"; @@ -315,15 +315,15 @@ &i2c2 { pinctrl-names = "default", "gpio"; pinctrl-1 = <&pinctrl_i2c2_gpio>; - sda-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>; - scl-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; }; &i2c3 { pinctrl-names = "default", "gpio"; pinctrl-1 = <&pinctrl_i2c3_gpio>; - sda-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; - scl-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; }; &iomuxc { diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi index 959d8ac2e393bfa9afca68f71c4d7c1d8c360edb..8e587e17e75df9eccf4d1cca4e6de20526ae4363 100644 --- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi @@ -32,8 +32,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi index 8072ed47c6bb21250fe50249f0449c6809c6e405..a0710d562766e18d97f46e7245d80a97eb18e071 100644 --- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi @@ -32,8 +32,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi index 8c9bcdd39830b2d1e160257044d10be03aa9d944..29ba24c273e9031fa8527205021e0bf710d55227 100644 --- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi @@ -33,8 +33,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi index e5d803d023c81292f096f9210a7cffad9886d80f..435dec6338fe68f9d17aad3115c20eb099240bec 100644 --- a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi @@ -67,8 +67,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi index 290a607fede967f24c1841e556a66163b9946e22..2e61102ae6946593315767bda7b7ed1ae85f734c 100644 --- a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi @@ -24,8 +24,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw560x.dtsi b/arch/arm/boot/dts/imx6qdl-gw560x.dtsi index 093a219a77ae188fa300cd81311d8b9ecc30a650..4bc4371e6bae56e02ee910b98f0f03656a3b4441 100644 --- a/arch/arm/boot/dts/imx6qdl-gw560x.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw560x.dtsi @@ -91,8 +91,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw5903.dtsi b/arch/arm/boot/dts/imx6qdl-gw5903.dtsi index e1c8dd233cab3cb5b2984fe123a0b9271cb407bf..1fdb7ba630f1be20b4025d0ce802f52dd9274447 100644 --- a/arch/arm/boot/dts/imx6qdl-gw5903.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw5903.dtsi @@ -75,8 +75,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw5904.dtsi b/arch/arm/boot/dts/imx6qdl-gw5904.dtsi index 3cd2e717c1daaaf8fe9b8f927b3718be6d4b47b7..304f3fb88fabff91685206913510277eb8813530 100644 --- a/arch/arm/boot/dts/imx6qdl-gw5904.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw5904.dtsi @@ -72,8 +72,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw5907.dtsi b/arch/arm/boot/dts/imx6qdl-gw5907.dtsi index 21c68a55bcb994b13e1f79066e442daeefadae42..fcd3bdfd6182724b2d081f56ca82e61f5586a6b8 100644 --- a/arch/arm/boot/dts/imx6qdl-gw5907.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw5907.dtsi @@ -23,8 +23,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw5910.dtsi b/arch/arm/boot/dts/imx6qdl-gw5910.dtsi index ed4e2225995941194983e532bc9e0847ef4b2a47..68e5ab2e27e2218f3f5ec8c89d2f0a8af848c26d 100644 --- a/arch/arm/boot/dts/imx6qdl-gw5910.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw5910.dtsi @@ -26,8 +26,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw5912.dtsi b/arch/arm/boot/dts/imx6qdl-gw5912.dtsi index 797f160249f787d02f0295820846dafbc4df5261..0415bcb416400d9e81b6cbd788fcd22c4a3072a4 100644 --- a/arch/arm/boot/dts/imx6qdl-gw5912.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw5912.dtsi @@ -24,8 +24,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-gw5913.dtsi b/arch/arm/boot/dts/imx6qdl-gw5913.dtsi index 4cd7d290f5b28f6240411b3b690fa8ad33c988c7..8e23cec7149e5338d8569b3f14516b4e37bc4ff2 100644 --- a/arch/arm/boot/dts/imx6qdl-gw5913.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw5913.dtsi @@ -23,8 +23,6 @@ gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; user-pb { label = "user_pb"; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi index d434868e870a98f26a9361df2d6c23a33b069000..51d28e275aa649ba878dc972b281b55ab0d07176 100644 --- a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi +++ b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi @@ -78,7 +78,8 @@ ssi2 { fsl,audmux-port = <1>; fsl,port-config = < - (IMX_AUDMUX_V2_PTCR_TFSDIR | + (IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_TFSEL(4) | IMX_AUDMUX_V2_PTCR_TCLKDIR | IMX_AUDMUX_V2_PTCR_TCSEL(4)) @@ -89,7 +90,7 @@ pins5 { fsl,audmux-port = <4>; fsl,port-config = < - 0x00000000 + IMX_AUDMUX_V2_PTCR_SYN IMX_AUDMUX_V2_PDCR_RXDSEL(1) >; }; @@ -164,6 +165,7 @@ &usbotg { status = "okay"; + dr_mode = "peripheral"; }; &usdhc2 { diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi index f28a96fcf23e8fec54e0b2885dfa281a15141d22..7bd658b7bdda0f9561ee001577948b9a24f62699 100644 --- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi @@ -31,6 +31,8 @@ reg_usb_h1_vbus: regulator@1 { compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1_vbus>; reg = <1>; regulator-name = "usb_h1_vbus"; regulator-min-microvolt = <5000000>; @@ -41,6 +43,8 @@ }; gpio_leds: leds { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds>; compatible = "gpio-leds"; green { @@ -122,6 +126,8 @@ }; pmic@58 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; compatible = "dlg,da9063"; reg = <0x58>; interrupt-parent = <&gpio2>; @@ -215,25 +221,13 @@ }; &iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - imx6q-phytec-pfla02 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 - MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ - MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x80000000 /* PMIC interrupt */ - MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */ - MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */ - >; - }; - 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 */ >; }; @@ -255,6 +249,7 @@ 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 */ >; }; @@ -308,10 +303,21 @@ >; }; + 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 = <MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000>; }; + pinctrl_pmic: pmicgrp { + fsl,pins = <MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x80000000>; /* PMIC interrupt */ + }; + pinctrl_uart3: uart3grp { fsl,pins = < MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 @@ -328,9 +334,9 @@ >; }; - pinctrl_usbh1: usbh1grp { + pinctrl_usbh1_vbus: usbh1vbusgrp { fsl,pins = < - MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x80000000 + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 >; }; @@ -415,8 +421,6 @@ &usbh1 { vbus-supply = <®_usb_h1_vbus>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbh1>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6qdl-ts7970.dtsi b/arch/arm/boot/dts/imx6qdl-ts7970.dtsi index e6aa0c33754de834732aaa2d49018a16caf20476..fded07f370b390b292466ec67477819ccaaba7cb 100644 --- a/arch/arm/boot/dts/imx6qdl-ts7970.dtsi +++ b/arch/arm/boot/dts/imx6qdl-ts7970.dtsi @@ -506,7 +506,6 @@ }; &ssi1 { - fsl,mode = "i2s-slave"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index c070893c509ee2dbbab43adbcdb417028c3776b0..b62a0dbb033ff19487bdd0083e033c01d6d05c43 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -97,15 +97,21 @@ &i2c1 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio3 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio3 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; }; &i2c2 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; codec: sgtl5000@a { @@ -185,6 +191,13 @@ >; }; + 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 @@ -192,6 +205,13 @@ >; }; + 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 diff --git a/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts b/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts index 6ea5f918d0593d6902b7c29b466952654f994a3c..a17b8bbbdb9560cae9de75aded4c6082c77c1e7c 100644 --- a/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts +++ b/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts @@ -97,8 +97,11 @@ pinctrl-1 = <&pinctrl_i2c1_sleep>; status = "okay"; - /* TODO: embedded controller at 0x43 (driver missing) */ - + ec: embedded-controller@43 { + compatible = "netronix,ntxec"; + reg = <0x43>; + #pwm-cells = <2>; + }; }; &i2c2 { diff --git a/arch/arm/boot/dts/imx6ull-colibri.dtsi b/arch/arm/boot/dts/imx6ull-colibri.dtsi index 4436556624d6713c48b438f14b52a6d67bd95c45..0cdbf7b6e7285643e7e86196b45537e0d5977488 100644 --- a/arch/arm/boot/dts/imx6ull-colibri.dtsi +++ b/arch/arm/boot/dts/imx6ull-colibri.dtsi @@ -522,12 +522,12 @@ pinctrl_usdhc2: usdhc2-grp { fsl,pins = < - MX6UL_PAD_CSI_DATA00__USDHC2_DATA0 0x17059 - MX6UL_PAD_CSI_DATA01__USDHC2_DATA1 0x17059 - MX6UL_PAD_CSI_DATA02__USDHC2_DATA2 0x17059 - MX6UL_PAD_CSI_DATA03__USDHC2_DATA3 0x17059 - MX6UL_PAD_CSI_HSYNC__USDHC2_CMD 0x17059 - MX6UL_PAD_CSI_VSYNC__USDHC2_CLK 0x17059 + MX6UL_PAD_CSI_DATA00__USDHC2_DATA0 0x17069 + MX6UL_PAD_CSI_DATA01__USDHC2_DATA1 0x17069 + MX6UL_PAD_CSI_DATA02__USDHC2_DATA2 0x17069 + MX6UL_PAD_CSI_DATA03__USDHC2_DATA3 0x17069 + MX6UL_PAD_CSI_HSYNC__USDHC2_CMD 0x17069 + MX6UL_PAD_CSI_VSYNC__USDHC2_CLK 0x17069 MX6UL_PAD_GPIO1_IO03__OSC32K_32K_OUT 0x10 >; diff --git a/arch/arm/boot/dts/imx7d-mba7.dts b/arch/arm/boot/dts/imx7d-mba7.dts index 5ef86de530131bd4e99a0ce2b8239f73893e459d..23856a8d4b8c2222973937dedd93b1cd32efc14c 100644 --- a/arch/arm/boot/dts/imx7d-mba7.dts +++ b/arch/arm/boot/dts/imx7d-mba7.dts @@ -99,8 +99,6 @@ /* probe deferral not supported */ /* pcie-bus-supply = <®_mpcie_1v5>; */ reset-gpio = <&gpio5 12 GPIO_ACTIVE_LOW>; - disable-gpio = <&gpio2 29 GPIO_ACTIVE_LOW>; - power-on-gpio = <&gpio2 30 GPIO_ACTIVE_LOW>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx7d-remarkable2.dts b/arch/arm/boot/dts/imx7d-remarkable2.dts new file mode 100644 index 0000000000000000000000000000000000000000..8cbae656395c1f4e53f9ed0660881b69f2f8cfda --- /dev/null +++ b/arch/arm/boot/dts/imx7d-remarkable2.dts @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/ + * + */ + +/dts-v1/; + +#include "imx7d.dtsi" + +/ { + model = "reMarkable 2.0"; + compatible = "remarkable,imx7d-remarkable2", "fsl,imx7d"; + + chosen { + stdout-path = &uart6; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; +}; + +&clks { + assigned-clocks = <&clks IMX7D_CLKO2_ROOT_SRC>, + <&clks IMX7D_CLKO2_ROOT_DIV>; + assigned-clock-parents = <&clks IMX7D_CKIL>; + assigned-clock-rates = <0>, <32768>; +}; + +&snvs_pwrkey { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>; + status = "okay"; +}; + +&uart6 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart6>; + assigned-clocks = <&clks IMX7D_UART6_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>; + status = "okay"; +}; + +&usbotg2 { + srp-disable; + hnp-disable; + 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>; + assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>; + assigned-clock-rates = <400000000>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; + +&iomuxc { + pinctrl_uart1: uart1grp { + fsl,pins = < + MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 + MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x79 + >; + }; + + pinctrl_uart6: uart6grp { + fsl,pins = < + MX7D_PAD_EPDC_DATA09__UART6_DCE_TX 0x79 + MX7D_PAD_EPDC_DATA08__UART6_DCE_RX 0x79 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x59 + MX7D_PAD_SD3_CLK__SD3_CLK 0x19 + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x59 + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x59 + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x59 + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x59 + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x59 + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x59 + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x59 + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x59 + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x19 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp_100mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5a + MX7D_PAD_SD3_CLK__SD3_CLK 0x1a + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5a + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5a + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5a + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5a + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5a + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5a + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5a + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5a + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1a + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp_200mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5b + MX7D_PAD_SD3_CLK__SD3_CLK 0x1b + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5b + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5b + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5b + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5b + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5b + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5b + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5b + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5b + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1b + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX7D_PAD_ENET1_COL__WDOG1_WDOG_ANY 0x74 + >; + }; +}; diff --git a/arch/arm/boot/dts/iwg20d-q7-common.dtsi b/arch/arm/boot/dts/iwg20d-q7-common.dtsi index 63cafd220dba1d04ccdaa92042ea82ede5dad0c6..bc857676d19104a1c9f4c7e5f739961a22c48803 100644 --- a/arch/arm/boot/dts/iwg20d-q7-common.dtsi +++ b/arch/arm/boot/dts/iwg20d-q7-common.dtsi @@ -325,8 +325,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi1 &src3 &dvc1>; - capture = <&ssi0 &src2 &dvc0>; + playback = <&ssi1>, <&src3>, <&dvc1>; + capture = <&ssi0>, <&src2>, <&dvc0>; }; }; }; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 007dd2bd05951124031c2716641c07e844203a26..4fce81422943be89b9a7701ae314188b450c6aa8 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -246,6 +246,7 @@ reg = <0x0 0x1700000 0x0 0x100000>; ranges = <0x0 0x0 0x1700000 0x100000>; interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; + dma-coherent; sec_jr0: jr@10000 { compatible = "fsl,sec-v5.0-job-ring", @@ -871,7 +872,7 @@ phy_type = "ulpi"; }; - usb3: usb3@3100000 { + usb3: usb@3100000 { compatible = "snps,dwc3"; reg = <0x0 0x3100000 0x0 0x10000>; interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi index 08a7d3ce383f2ac133a7900549776f880fdd50ff..ea02fd403a9b49edfe8e554e97d30d2a75cbd8b4 100644 --- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi +++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi @@ -27,16 +27,14 @@ cpcap_battery: battery { compatible = "motorola,cpcap-battery"; - interrupts-extended = < - &cpcap 6 0 &cpcap 5 0 &cpcap 3 0 - &cpcap 20 0 &cpcap 54 0 &cpcap 57 0 - >; + interrupts-extended = + <&cpcap 6 0>, <&cpcap 5 0>, <&cpcap 3 0>, + <&cpcap 20 0>, <&cpcap 54 0>, <&cpcap 57 0>; interrupt-names = "eol", "lowbph", "lowbpl", - "chrgcurr1", "battdetb", - "cccal"; - io-channels = <&cpcap_adc 0 &cpcap_adc 1 - &cpcap_adc 5 &cpcap_adc 6>; + "chrgcurr1", "battdetb", "cccal"; + io-channels = <&cpcap_adc 0>, <&cpcap_adc 1>, + <&cpcap_adc 5>, <&cpcap_adc 6>; io-channel-names = "battdetb", "battp", "chg_isense", "batti"; power-supplies = <&cpcap_charger>; @@ -44,20 +42,19 @@ cpcap_charger: charger { compatible = "motorola,mapphone-cpcap-charger"; - interrupts-extended = < - &cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0 - &cpcap 22 0 &cpcap 21 0 &cpcap 20 0 &cpcap 19 0 - &cpcap 54 0 - >; + interrupts-extended = + <&cpcap 13 0>, <&cpcap 12 0>, <&cpcap 29 0>, + <&cpcap 28 0>, <&cpcap 22 0>, <&cpcap 21 0>, + <&cpcap 20 0>, <&cpcap 19 0>, <&cpcap 54 0>; interrupt-names = - "chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", - "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld", - "battdetb"; - mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW - &gpio3 23 GPIO_ACTIVE_LOW>; - io-channels = <&cpcap_adc 0 &cpcap_adc 1 - &cpcap_adc 2 &cpcap_adc 5 - &cpcap_adc 6>; + "chrg_det", "rvrs_chrg", "chrg_se1b", + "se0conn", "rvrs_mode", "chrgcurr2", + "chrgcurr1", "vbusvld", "battdetb"; + mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW>, + <&gpio3 23 GPIO_ACTIVE_LOW>; + io-channels = <&cpcap_adc 0>, <&cpcap_adc 1>, + <&cpcap_adc 2>, <&cpcap_adc 5>, + <&cpcap_adc 6>; io-channel-names = "battdetb", "battp", "vbus", "chg_isense", "batti"; @@ -98,22 +95,22 @@ cpcap_usb2_phy: phy { compatible = "motorola,mapphone-cpcap-usb-phy"; - pinctrl-0 = <&usb_gpio_mux_sel1 &usb_gpio_mux_sel2>; + pinctrl-0 = <&usb_gpio_mux_sel1>, <&usb_gpio_mux_sel2>; pinctrl-1 = <&usb_ulpi_pins>; pinctrl-2 = <&usb_utmi_pins>; pinctrl-3 = <&uart3_pins>; pinctrl-names = "default", "ulpi", "utmi", "uart"; #phy-cells = <0>; - interrupts-extended = < - &cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0 - &cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0 - &cpcap 48 0 - >; + interrupts-extended = + <&cpcap 15 0>, <&cpcap 14 0>, <&cpcap 28 0>, + <&cpcap 19 0>, <&cpcap 18 0>, <&cpcap 17 0>, + <&cpcap 16 0>, <&cpcap 49 0>, <&cpcap 48 0>; interrupt-names = - "id_ground", "id_float", "se0conn", "vbusvld", - "sessvld", "sessend", "se1", "dm", "dp"; - mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH - &gpio1 0 GPIO_ACTIVE_HIGH>; + "id_ground", "id_float", "se0conn", + "vbusvld", "sessvld", "sessend", + "se1", "dm", "dp"; + mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, + <&gpio1 0 GPIO_ACTIVE_HIGH>; io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>; io-channel-names = "vbus", "id"; vusb-supply = <&vusb>; diff --git a/arch/arm/boot/dts/mstar-infinity2m-ssd202d-unitv2.dts b/arch/arm/boot/dts/mstar-infinity2m-ssd202d-unitv2.dts new file mode 100644 index 0000000000000000000000000000000000000000..a81684002e45d8f897bce8908e7fdbc8c11e4a6d --- /dev/null +++ b/arch/arm/boot/dts/mstar-infinity2m-ssd202d-unitv2.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 thingy.jp. + * Author: Daniel Palmer <daniel@thingy.jp> + */ + +/dts-v1/; +#include "mstar-infinity2m-ssd202d.dtsi" + +/ { + model = "UnitV2"; + compatible = "m5stack,unitv2", "mstar,infinity2m"; + + aliases { + serial0 = &pm_uart; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&pm_uart { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/mstar-v7.dtsi b/arch/arm/boot/dts/mstar-v7.dtsi index b0a21b0b731f06053fd6272c4a612b40e2936d7c..075d583d6f40c5063389a8305afdc1478d70cf16 100644 --- a/arch/arm/boot/dts/mstar-v7.dtsi +++ b/arch/arm/boot/dts/mstar-v7.dtsi @@ -6,6 +6,7 @@ #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/clock/mstar-msc313-mpll.h> / { #address-cells = <1>; @@ -46,6 +47,21 @@ interrupt-affinity = <&cpu0>; }; + clocks: clocks { + xtal: xtal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + rtc_xtal: rtc_xtal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + status = "disabled"; + }; + }; + soc: soc { compatible = "simple-bus"; #address-cells = <1>; @@ -109,6 +125,13 @@ reg = <0x204400 0x200>; }; + mpll: mpll@206000 { + compatible = "mstar,msc313-mpll"; + #clock-cells = <1>; + reg = <0x206000 0x200>; + clocks = <&xtal>; + }; + gpio: gpio@207800 { #gpio-cells = <2>; reg = <0x207800 0x200>; diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi index fade142840176b90ffb48e9ccbf5182c14374cec..4776f85d6d5b81346cb006a737319297439f7d27 100644 --- a/arch/arm/boot/dts/mt2701.dtsi +++ b/arch/arm/boot/dts/mt2701.dtsi @@ -607,7 +607,7 @@ }; usb0: usb@1a1c0000 { - compatible = "mediatek,mt8173-xhci"; + compatible = "mediatek,mt2701-xhci", "mediatek,mtk-xhci"; reg = <0 0x1a1c0000 0 0x1000>, <0 0x1a1c4700 0 0x0100>; reg-names = "mac", "ippc"; @@ -620,8 +620,9 @@ status = "disabled"; }; - u3phy0: usb-phy@1a1c4000 { - compatible = "mediatek,mt2701-u3phy"; + u3phy0: t-phy@1a1c4000 { + compatible = "mediatek,mt2701-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x1a1c4000 0 0x0700>; #address-cells = <2>; #size-cells = <2>; @@ -646,7 +647,7 @@ }; usb1: usb@1a240000 { - compatible = "mediatek,mt8173-xhci"; + compatible = "mediatek,mt2701-xhci", "mediatek,mtk-xhci"; reg = <0 0x1a240000 0 0x1000>, <0 0x1a244700 0 0x0100>; reg-names = "mac", "ippc"; @@ -659,8 +660,9 @@ status = "disabled"; }; - u3phy1: usb-phy@1a244000 { - compatible = "mediatek,mt2701-u3phy"; + u3phy1: t-phy@1a244000 { + compatible = "mediatek,mt2701-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x1a244000 0 0x0700>; #address-cells = <2>; #size-cells = <2>; @@ -700,8 +702,9 @@ status = "disabled"; }; - u2phy0: usb-phy@11210000 { - compatible = "mediatek,generic-tphy-v1"; + u2phy0: t-phy@11210000 { + compatible = "mediatek,mt2701-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x11210000 0 0x0800>; #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/mt6589.dtsi b/arch/arm/boot/dts/mt6589.dtsi index f3ccb70c0779c66d42d553572e6c7d90270ab0db..70df00a7bb26701dc2cdeb21272e45c7298af5ea 100644 --- a/arch/arm/boot/dts/mt6589.dtsi +++ b/arch/arm/boot/dts/mt6589.dtsi @@ -17,6 +17,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "mediatek,mt6589-smp"; cpu@0 { device_type = "cpu"; diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi index aea6809500d7484c3d9daf8c90f9fd9320c8c36c..3c11f7cfcc4013d6439c2fef6c5bdfc76bb8efb7 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi @@ -787,8 +787,9 @@ }; }; - pcie0_phy: pcie-phy@1a149000 { - compatible = "mediatek,generic-tphy-v1"; + pcie0_phy: t-phy@1a149000 { + compatible = "mediatek,mt7623-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x1a149000 0 0x0700>; #address-cells = <2>; #size-cells = <2>; @@ -804,8 +805,9 @@ }; }; - pcie1_phy: pcie-phy@1a14a000 { - compatible = "mediatek,generic-tphy-v1"; + pcie1_phy: t-phy@1a14a000 { + compatible = "mediatek,mt7623-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x1a14a000 0 0x0700>; #address-cells = <2>; #size-cells = <2>; @@ -823,7 +825,7 @@ usb1: usb@1a1c0000 { compatible = "mediatek,mt7623-xhci", - "mediatek,mt8173-xhci"; + "mediatek,mtk-xhci"; reg = <0 0x1a1c0000 0 0x1000>, <0 0x1a1c4700 0 0x0100>; reg-names = "mac", "ippc"; @@ -836,9 +838,9 @@ status = "disabled"; }; - u3phy1: usb-phy@1a1c4000 { - compatible = "mediatek,mt7623-u3phy", - "mediatek,mt2701-u3phy"; + u3phy1: t-phy@1a1c4000 { + compatible = "mediatek,mt7623-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x1a1c4000 0 0x0700>; #address-cells = <2>; #size-cells = <2>; @@ -864,7 +866,7 @@ usb2: usb@1a240000 { compatible = "mediatek,mt7623-xhci", - "mediatek,mt8173-xhci"; + "mediatek,mtk-xhci"; reg = <0 0x1a240000 0 0x1000>, <0 0x1a244700 0 0x0100>; reg-names = "mac", "ippc"; @@ -877,9 +879,9 @@ status = "disabled"; }; - u3phy2: usb-phy@1a244000 { - compatible = "mediatek,mt7623-u3phy", - "mediatek,mt2701-u3phy"; + u3phy2: t-phy@1a244000 { + compatible = "mediatek,mt7623-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x1a244000 0 0x0700>; #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/mt7623n.dtsi b/arch/arm/boot/dts/mt7623n.dtsi index 1880ac9e32cf73b5a9d00616af50e8049ab9ceb7..bcb0846e29fd67846bca4b8af43fec97935248ae 100644 --- a/arch/arm/boot/dts/mt7623n.dtsi +++ b/arch/arm/boot/dts/mt7623n.dtsi @@ -246,7 +246,7 @@ status = "disabled"; }; - mipi_tx0: mipi-dphy@10010000 { + mipi_tx0: dsi-phy@10010000 { compatible = "mediatek,mt7623-mipi-tx", "mediatek,mt2701-mipi-tx"; reg = <0 0x10010000 0 0x90>; @@ -265,7 +265,7 @@ status = "disabled"; }; - hdmi_phy: phy@10209100 { + hdmi_phy: hdmi-phy@10209100 { compatible = "mediatek,mt7623-hdmi-phy", "mediatek,mt2701-hdmi-phy"; reg = <0 0x10209100 0 0x24>; diff --git a/arch/arm/boot/dts/mt7629.dtsi b/arch/arm/boot/dts/mt7629.dtsi index 5cbb3d244c7504a978e0535ba251c475ada842d0..874043f0490d3f9578e6ed7afec6676ccae48616 100644 --- a/arch/arm/boot/dts/mt7629.dtsi +++ b/arch/arm/boot/dts/mt7629.dtsi @@ -329,8 +329,9 @@ status = "disabled"; }; - u3phy0: usb-phy@1a0c4000 { - compatible = "mediatek,generic-tphy-v2"; + u3phy0: t-phy@1a0c4000 { + compatible = "mediatek,mt7629-tphy", + "mediatek,generic-tphy-v2"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x1a0c4000 0xe00>; @@ -413,14 +414,15 @@ }; }; - pciephy1: pcie-phy@1a14a000 { - compatible = "mediatek,generic-tphy-v2"; + pciephy1: t-phy@1a14a000 { + compatible = "mediatek,mt7629-tphy", + "mediatek,generic-tphy-v2"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x1a14a000 0x1000>; status = "disabled"; - pcieport1: port1phy@0 { + pcieport1: pcie-phy@0 { reg = <0 0x1000>; clocks = <&clk20m>; clock-names = "ref"; diff --git a/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts b/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts new file mode 100644 index 0000000000000000000000000000000000000000..eb6eb21cb2a44539a73913e6d55b4bd35f10e248 --- /dev/null +++ b/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts @@ -0,0 +1,1135 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Quanta Computer Inc. George.Hung@quantatw.com + +/dts-v1/; +#include "nuvoton-npcm730.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Quanta GBS Board (Device Tree)"; + compatible = "quanta,gbs-bmc","nuvoton,npcm730"; + + aliases { + ethernet1 = &gmac0; + serial0 = &serial0; + serial1 = &serial1; + serial2 = &serial2; + serial3 = &serial3; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + i2c7 = &i2c7; + i2c8 = &i2c8; + i2c9 = &i2c9; + i2c10 = &i2c10; + i2c11 = &i2c11; + i2c12 = &i2c12; + i2c13 = &i2c13; + i2c14 = &i2c14; + i2c15 = &i2c15; + i2c16 = &i2c0_slotPE0_0; + i2c17 = &i2c0_slotPE1_1; + i2c18 = &i2c0_slotUSB_2; + i2c19 = &i2c0_3; + i2c20 = &i2c5_i2cool_0; + i2c21 = &i2c5_i2cool_1; + i2c22 = &i2c5_i2cool_2; + i2c23 = &i2c5_hsbp_fru_3; + i2c24 = &i2c6_u2_15_0; + i2c25 = &i2c6_u2_14_1; + i2c26 = &i2c6_u2_13_2; + i2c27 = &i2c6_u2_12_3; + i2c28 = &i2c7_u2_11_0; + i2c29 = &i2c7_u2_10_1; + i2c30 = &i2c7_u2_9_2; + i2c31 = &i2c7_u2_8_3; + i2c32 = &i2c9_vddcr_cpu; + i2c33 = &i2c9_vddcr_soc; + i2c34 = &i2c9_vddio_efgh; + i2c35 = &i2c9_vddio_abcd; + i2c36 = &i2c10_u2_7_0; + i2c37 = &i2c10_u2_6_1; + i2c38 = &i2c10_u2_5_2; + i2c39 = &i2c10_u2_4_3; + i2c40 = &i2c11_clk_buf0_0; + i2c41 = &i2c11_clk_buf1_1; + i2c42 = &i2c11_clk_buf2_2; + i2c43 = &i2c11_clk_buf3_3; + i2c44 = &i2c14_u2_3_0; + i2c45 = &i2c14_u2_2_1; + i2c46 = &i2c14_u2_1_2; + i2c47 = &i2c14_u2_0_3; + fiu0 = &fiu0; + fiu1 = &fiu3; + }; + + chosen { + stdout-path = &serial0; + }; + + memory { + reg = <0 0x40000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + sas-cable0 { + label = "sas-cable0"; + gpios = <&gpio2 9 GPIO_ACTIVE_LOW>; + linux,code = <73>; + }; + + sas-cable1 { + label = "sas-cable1"; + gpios = <&gpio2 8 GPIO_ACTIVE_LOW>; + linux,code = <72>; + }; + + sas-cable2 { + label = "sas-cable2"; + gpios = <&gpio2 7 GPIO_ACTIVE_LOW>; + linux,code = <71>; + }; + + sas-cable3 { + label = "sas-cable3"; + gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; + linux,code = <70>; + }; + + sata0 { + label = "sata0"; + gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + linux,code = <5>; + }; + + hsbp-cable { + label = "hsbp-cable"; + gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; + linux,code = <57>; + }; + + fanbd-cable { + label = "fanbd-cable"; + gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>; + linux,code = <58>; + }; + + bp12v-cable { + label = "bp12v-cable"; + gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>; + linux,code = <69>; + }; + + pe-slot0 { + label = "pe-slot0"; + gpios = <&gpio3 24 GPIO_ACTIVE_LOW>; + linux,code = <120>; + }; + + pe-slot1 { + label = "pe-slot1"; + gpios = <&gpio3 25 GPIO_ACTIVE_LOW>; + linux,code = <121>; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 1>, <&adc 2>; + }; + + iio-hwmon-battery { + compatible = "iio-hwmon"; + io-channels = <&adc 0>; + }; + + leds { + compatible = "gpio-leds"; + + heartbeat { /* gpio153 */ + gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + attention { /* gpio215 */ + gpios = <&gpio6 23 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + sys_boot_status { /* gpio216 */ + gpios = <&gpio6 24 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + retain-state-shutdown; + }; + + bmc_fault { /* gpio217 */ + gpios = <&gpio6 25 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "panic"; + panic-indicator; + }; + + led_u2_0_locate { + gpios = <&pca9535_ledlocate 3 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_1_locate { + gpios = <&pca9535_ledlocate 2 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_2_locate { + gpios = <&pca9535_ledlocate 1 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_3_locate { + gpios = <&pca9535_ledlocate 0 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_4_locate { + gpios = <&pca9535_ledlocate 7 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_5_locate { + gpios = <&pca9535_ledlocate 6 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_6_locate { + gpios = <&pca9535_ledlocate 5 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_7_locate { + gpios = <&pca9535_ledlocate 4 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_8_locate { + gpios = <&pca9535_ledlocate 11 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_9_locate { + gpios = <&pca9535_ledlocate 10 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_10_locate { + gpios = <&pca9535_ledlocate 9 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_11_locate { + gpios = <&pca9535_ledlocate 8 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_12_locate { + gpios = <&pca9535_ledlocate 15 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_13_locate { + gpios = <&pca9535_ledlocate 14 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_14_locate { + gpios = <&pca9535_ledlocate 13 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_15_locate { + gpios = <&pca9535_ledlocate 12 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_0_fault { + gpios = <&pca9535_ledfault 3 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_1_fault { + gpios = <&pca9535_ledfault 2 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_2_fault { + gpios = <&pca9535_ledfault 1 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_3_fault { + gpios = <&pca9535_ledfault 0 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_4_fault { + gpios = <&pca9535_ledfault 7 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_5_fault { + gpios = <&pca9535_ledfault 6 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_6_fault { + gpios = <&pca9535_ledfault 5 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_7_fault { + gpios = <&pca9535_ledfault 4 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_8_fault { + gpios = <&pca9535_ledfault 11 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_9_fault { + gpios = <&pca9535_ledfault 10 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_10_fault { + gpios = <&pca9535_ledfault 9 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_11_fault { + gpios = <&pca9535_ledfault 8 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_12_fault { + gpios = <&pca9535_ledfault 15 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_13_fault { + gpios = <&pca9535_ledfault 14 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_14_fault { + gpios = <&pca9535_ledfault 13 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_u2_15_fault { + gpios = <&pca9535_ledfault 12 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + }; + + seven-seg-disp { + compatible = "seven-seg-gpio-dev"; + refresh-interval-ms = /bits/ 16 <600>; + clock-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + data-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + clear-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + }; + + pcie-slot { + pcie1: pcie-slot@1 { + label = "PE0"; + }; + pcie2: pcie-slot@2 { + label = "PE1"; + }; + }; +}; + +&fiu0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0cs1_pins>; + status = "okay"; + spi-nor@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + spi-max-frequency = <20000000>; + spi-rx-bus-width = <2>; + label = "bmc"; + partitions@80000000 { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + u-boot@0 { + label = "u-boot"; + reg = <0x0000000 0xf0000>; + }; + image-descriptor@f0000 { + label = "image-descriptor"; + reg = <0xf0000 0x10000>; + }; + hoth-update@100000 { + label = "hoth-update"; + reg = <0x100000 0x100000>; + }; + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x500000>; + }; + rofs@700000 { + label = "rofs"; + reg = <0x700000 0x35f0000>; + }; + rwfs@3cf0000 { + label = "rwfs"; + reg = <0x3cf0000 0x300000>; + }; + hoth-mailbox@3ff0000 { + label = "hoth-mailbox"; + reg = <0x3ff0000 0x10000>; + }; + }; + }; +}; + +&fiu3 { + pinctrl-0 = <&spi3_pins>, <&spi3cs1_pins>; + status = "okay"; + + spi-nor@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; + m25p,fast-read; + label = "pnor"; + }; + spi-nor@1 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + reg = <1>; + spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; + m25p,fast-read; + }; +}; + +&gcr { + serial_port_mux: uart-mux-controller { + compatible = "mmio-mux"; + #mux-control-cells = <1>; + mux-reg-masks = <0x38 0x07>; + idle-states = <2>; /* Serial port mode 3 (takeover) */ + }; + + uart1_mode_mux: uart1-mode-mux-controller { + compatible = "mmio-mux"; + #mux-control-cells = <1>; + mux-reg-masks = <0x64 0x01000000>; + idle-states = <0>; /* Set UART1 mode to normal (follow SPMOD) */ + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii-id"; + snps,eee-force-disable; +}; + +&ehci1 { + status = "okay"; +}; + +&watchdog1 { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&serial0 { + status = "okay"; +}; + +&serial1 { + status = "okay"; +}; + +&serial2 { + status = "okay"; +}; + +&serial3 { + status = "okay"; +}; + +&adc { + #io-channel-cells = <1>; + status = "okay"; +}; + +&lpc_kcs { + kcs1: kcs1@0 { + status = "okay"; + }; + + kcs2: kcs2@0 { + status = "okay"; + }; + + kcs3: kcs3@0 { + status = "okay"; + }; +}; + +&spi1 { + cs-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; /* dummy - gpio147 */ + pinctrl-names = "default"; + pinctrl-0 = <&gpio224ol_pins &gpio227o_pins + &gpio228_pins>; + status = "okay"; + + jtag_master@0 { + compatible = "nuvoton,npcm750-jtag-master"; + spi-max-frequency = <25000000>; + reg = <0>; + status = "okay"; + + pinctrl-names = "pspi", "gpio"; + pinctrl-0 = <&pspi2_pins>; + pinctrl-1 = <&gpio224ol_pins &gpio227o_pins + &gpio228_pins>; + + tck-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>; + tdi-gpios = <&gpio7 3 GPIO_ACTIVE_HIGH>; + tdo-gpios = <&gpio7 4 GPIO_ACTIVE_HIGH>; + tms-gpios = <&gpio7 6 GPIO_ACTIVE_HIGH>; + }; +}; + +&i2c0 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + i2c-mux-idle-disconnect; + reset-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>; + + i2c0_slotPE0_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + pcie-slot = &pcie1; + }; + + i2c0_slotPE1_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + pcie-slot = &pcie2; + }; + + i2c0_slotUSB_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c0_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + status = "okay"; + + pca9535_ifdet: pca9535-ifdet@24 { + compatible = "nxp,pca9535"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9535_pwren: pca9535-pwren@20 { + compatible = "nxp,pca9535"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "pwr_u2_3_en","pwr_u2_2_en", + "pwr_u2_1_en","pwr_u2_0_en", + "pwr_u2_7_en","pwr_u2_6_en", + "pwr_u2_5_en","pwr_u2_4_en", + "pwr_u2_11_en","pwr_u2_10_en", + "pwr_u2_9_en","pwr_u2_8_en", + "pwr_u2_15_en","pwr_u2_14_en", + "pwr_u2_13_en","pwr_u2_12_en"; + }; + + pca9535_pwrgd: pca9535-pwrgd@21 { + compatible = "nxp,pca9535"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9535_ledlocate: pca9535-ledlocate@22 { + compatible = "nxp,pca9535"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + + }; + + pca9535_ledfault: pca9535-ledfault@23 { + compatible = "nxp,pca9535"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + + }; + + pca9535_pwrdisable: pca9535-pwrdisable@25 { + compatible = "nxp,pca9535"; + reg = <0x25>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "u2_3_pwr_dis","u2_2_pwr_dis", + "u2_1_pwr_dis","u2_0_pwr_dis", + "u2_7_pwr_dis","u2_6_pwr_dis", + "u2_5_pwr_dis","u2_4_pwr_dis", + "u2_11_pwr_dis","u2_10_pwr_dis", + "u2_9_pwr_dis","u2_8_pwr_dis", + "u2_15_pwr_dis","u2_14_pwr_dis", + "u2_13_pwr_dis","u2_12_pwr_dis"; + }; + + pca9535_perst: pca9535-perst@26 { + compatible = "nxp,pca9535"; + reg = <0x26>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "u2_15_perst","u2_14_perst", + "u2_13_perst","u2_12_perst", + "u2_11_perst","u2_10_perst", + "u2_9_perst","u2_8_perst", + "u2_7_perst","u2_6_perst", + "u2_5_perst","u2_4_perst", + "u2_3_perst","u2_2_perst", + "u2_1_perst","u2_0_perst"; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + status = "okay"; + + sbtsi@4c { + compatible = "amd,sbtsi"; + reg = <0x4c>; + }; +}; + +&i2c5 { + clock-frequency = <100000>; + status = "okay"; + + mb_fru@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + i2c-switch@71 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + i2c-mux-idle-disconnect; + + i2c5_i2cool_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + max31725@54 { + compatible = "maxim,max31725"; + reg = <0x54>; + status = "okay"; + }; + }; + + i2c5_i2cool_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + max31725@55 { + compatible = "maxim,max31725"; + reg = <0x55>; + status = "okay"; + }; + }; + + i2c5_i2cool_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + max31725@5d { + compatible = "maxim,max31725"; + reg = <0x5d>; + status = "okay"; + }; + fan_fru@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + }; + + i2c5_hsbp_fru_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + hsbp_fru@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + status = "okay"; + }; + }; + }; +}; + +&i2c6 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@73 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x73>; + i2c-mux-idle-disconnect; + + i2c6_u2_15_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c6_u2_14_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + i2c6_u2_13_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c6_u2_12_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c7 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@72 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x72>; + i2c-mux-idle-disconnect; + + i2c7_u2_11_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c7_u2_10_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + i2c7_u2_9_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c7_u2_8_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c8 { + clock-frequency = <100000>; + status = "okay"; + + i2c8_adm1272: adm1272@10 { + compatible = "adi,adm1272"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10>; + shunt-resistor-micro-ohms = <300>; + }; +}; + +&i2c9 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + i2c-mux-idle-disconnect; + reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; + + i2c9_vddcr_cpu: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + vrm@60 { + compatible = "isil,isl68137"; + reg = <0x60>; + }; + }; + + i2c9_vddcr_soc: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + vrm@61 { + compatible = "isil,isl68137"; + reg = <0x61>; + }; + }; + + i2c9_vddio_efgh: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + vrm@63 { + compatible = "isil,isl68137"; + reg = <0x63>; + }; + }; + + i2c9_vddio_abcd: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + vrm@45 { + compatible = "isil,isl68137"; + reg = <0x45>; + }; + }; + }; +}; + +&i2c10 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + i2c-mux-idle-disconnect; + + i2c10_u2_7_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c10_u2_6_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + i2c10_u2_5_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c10_u2_4_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c11 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@76 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + i2c11_clk_buf0_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c11_clk_buf1_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + i2c11_clk_buf2_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c11_clk_buf3_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c12 { + clock-frequency = <100000>; + status = "okay"; + + max34451@4e { + compatible = "maxim,max34451"; + reg = <0x4e>; + }; + vrm@5d { + compatible = "isil,isl68137"; + reg = <0x5d>; + }; + vrm@5e { + compatible = "isil,isl68137"; + reg = <0x5e>; + }; +}; + +&i2c13 { + clock-frequency = <100000>; + status = "okay"; +}; + +&i2c14 { + clock-frequency = <100000>; + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + i2c-mux-idle-disconnect; + + i2c14_u2_3_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c14_u2_2_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c14_u2_1_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c14_u2_0_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&pwm_fan { + pinctrl-names = "default"; + pinctrl-0 = < + &pwm0_pins &pwm1_pins + &pwm2_pins &pwm3_pins + &pwm4_pins + &fanin0_pins &fanin1_pins + &fanin2_pins &fanin3_pins + &fanin4_pins + >; + status = "okay"; + + fan@0 { + reg = <0x00>; + fan-tach-ch = /bits/ 8 <0x00>; + }; + fan@1 { + reg = <0x01>; + fan-tach-ch = /bits/ 8 <0x01>; + }; + fan@2 { + reg = <0x02>; + fan-tach-ch = /bits/ 8 <0x02>; + }; + fan@3 { + reg = <0x04>; + fan-tach-ch = /bits/ 8 <0x04>; + }; + fan@4 { + reg = <0x03>; + fan-tach-ch = /bits/ 8 <0x03>; + }; +}; + +&pinctrl { + pinctrl-names = "default"; + + gpio0: gpio@f0010000 { + /* POWER_OUT=gpio07, RESET_OUT=gpio06, PS_PWROK=gpio13 */ + gpio-line-names = + /*0-31*/ + "","","","","","","RESET_OUT","POWER_OUT", + "","","","","","PS_PWROK","","", + "","","","","","","","", + "","","","","","","",""; + }; + gpio1: gpio@f0011000 { + /* SIO_POWER_GOOD=gpio59 */ + gpio-line-names = + /*32-63*/ + "","","","","","","","", + "","","","","","","","", + "","","","","","","","", + "","","","SIO_POWER_GOOD","","","",""; + }; + gpio2: gpio@f0012000 { + bmc_usb_mux_oe_n { + gpio-hog; + gpios = <25 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "bmc-usb-mux-oe-n"; + }; + bmc_usb_mux_sel { + gpio-hog; + gpios = <26 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "bmc-usb-mux-sel"; + }; + bmc_usb2517_reset_n { + gpio-hog; + gpios = <27 GPIO_ACTIVE_LOW>; + output-low; + line-name = "bmc-usb2517-reset-n"; + }; + }; + gpio3: gpio@f0013000 { + assert_cpu0_reset { + gpio-hog; + gpios = <14 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "assert-cpu0-reset"; + }; + assert_pwrok_cpu0_n { + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "assert-pwrok-cpu0-n"; + }; + assert_cpu0_prochot { + gpio-hog; + gpios = <16 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "assert-cpu0-prochot"; + }; + }; + gpio4: gpio@f0014000 { + /* POST_COMPLETE=gpio143 */ + gpio-line-names = + /*128-159*/ + "","","","","","","","", + "","","","","","","","POST_COMPLETE", + "","","","","","","","", + "","","","","","","",""; + }; + gpio5: gpio@f0015000 { + /* POWER_BUTTON=gpio177 */ + gpio-line-names = + /*160-191*/ + "","","","","","","","", + "","","","","","","","", + "","POWER_BUTTON","","","","","","", + "","","","","","","",""; + }; + gpio6: gpio@f0016000 { + /* SIO_S5=gpio199, RESET_BUTTON=gpio203 */ + gpio-line-names = + /*192-223*/ + "","","","","","","","SIO_S5", + "","","","RESET_BUTTON","","","","", + "","","","","","","","", + "","","","","","","",""; + }; + + gpio224ol_pins: gpio224ol-pins { + pins = "GPIO224/SPIXCK"; + bias-disable; + output-low; + }; + gpio227o_pins: gpio227o-pins { + pins = "GPIO227/nSPIXCS0"; + bias-disable; + output-high; + }; + gpio228_pins: gpio228-pins { + pins = "GPIO228/nSPIXCS1"; + bias-disable; + input-enable; + }; +}; diff --git a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts index 9f13d08f5804ecd3b40e80687f60377f931b0860..dea3dbc4a6a5248c11eeaf9bebf77598df781a71 100644 --- a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts +++ b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts @@ -9,7 +9,7 @@ / { model = "Nuvoton npcm750 Development Board (Device Tree)"; - compatible = "nuvoton,npcm750"; + compatible = "nuvoton,npcm750-evb", "nuvoton,npcm750"; aliases { ethernet2 = &gmac0; diff --git a/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts b/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts new file mode 100644 index 0000000000000000000000000000000000000000..83f27fbf4e93993cdbe4f7410c07e08ca6db8c82 --- /dev/null +++ b/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +// Copyright 2021 Jonathan Neuschäfer + +/dts-v1/; + +/* The last 16 MiB are dedicated to the GPU */ +/memreserve/ 0x07000000 0x01000000; + +#include "nuvoton-wpcm450.dtsi" + +/ { + model = "Supermicro X9SCi-LN4F BMC"; + compatible = "supermicro,x9sci-ln4f-bmc", "nuvoton,wpcm450"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0 0x08000000>; /* 128 MiB */ + }; +}; + +&serial0 { + /* + * Debug serial port. TX is exposed on the right pad of unpopulated + * resistor R1247, RX on the right pad of R1162. + */ + status = "okay"; +}; + +&serial1 { + /* "Serial over LAN" port. Connected to ttyS2 of the host system. */ + status = "okay"; +}; + +&watchdog0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/nuvoton-wpcm450.dtsi b/arch/arm/boot/dts/nuvoton-wpcm450.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d7cbeb187484074bc5983975ef11b53e07acf80c --- /dev/null +++ b/arch/arm/boot/dts/nuvoton-wpcm450.dtsi @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +// Copyright 2021 Jonathan Neuschäfer + +#include <dt-bindings/interrupt-controller/irq.h> + +/ { + compatible = "nuvoton,wpcm450"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,arm926ej-s"; + device_type = "cpu"; + reg = <0>; + }; + }; + + clk24m: clock-24mhz { + /* 24 MHz dummy clock */ + compatible = "fixed-clock"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&aic>; + ranges; + + serial0: serial@b8000000 { + compatible = "nuvoton,wpcm450-uart"; + reg = <0xb8000000 0x20>; + reg-shift = <2>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk24m>; + status = "disabled"; + }; + + serial1: serial@b8000100 { + compatible = "nuvoton,wpcm450-uart"; + reg = <0xb8000100 0x20>; + reg-shift = <2>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk24m>; + status = "disabled"; + }; + + timer0: timer@b8001000 { + compatible = "nuvoton,wpcm450-timer"; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + reg = <0xb8001000 0x1c>; + clocks = <&clk24m>; + }; + + watchdog0: watchdog@b800101c { + compatible = "nuvoton,wpcm450-wdt"; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + reg = <0xb800101c 0x4>; + clocks = <&clk24m>; + status = "disabled"; + }; + + aic: interrupt-controller@b8002000 { + compatible = "nuvoton,wpcm450-aic"; + reg = <0xb8002000 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap3-echo.dts b/arch/arm/boot/dts/omap3-echo.dts index b9fd113979f25e875966bea0077c7b3d0cab2fed..8f02ff5e7da691829c69f70c58ff9c494a5c870b 100644 --- a/arch/arm/boot/dts/omap3-echo.dts +++ b/arch/arm/boot/dts/omap3-echo.dts @@ -7,6 +7,7 @@ #include "dm3725.dtsi" #include <dt-bindings/input/input.h> +#include <dt-bindings/leds/common.h> / { model = "Amazon Echo (first generation)"; @@ -139,179 +140,367 @@ clock-frequency = <400000>; lp5523A: lp5523A@32 { + #address-cells = <1>; + #size-cells = <0>; compatible = "national,lp5523"; label = "q1"; reg = <0x32>; clock-mode = /bits/ 8 <0>; /* LP55XX_CLOCK_AUTO */ enable-gpio = <&gpio4 13 GPIO_ACTIVE_HIGH>; /* GPIO_109 */ - chan0 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan1 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan2 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan3 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan4 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan5 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan6 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan7 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan8 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; + multi-led@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0>; + color = <LED_COLOR_ID_RGB>; + + led@0 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x0>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@1 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x1>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@6 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x6>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; + color = <LED_COLOR_ID_RGB>; + + led@2 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x2>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@3 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x3>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@7 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x7>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + color = <LED_COLOR_ID_RGB>; + + led@4 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x4>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@5 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x5>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@8 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x8>; + color = <LED_COLOR_ID_RED>; + }; }; }; lp5523B: lp5523B@33 { + #address-cells = <1>; + #size-cells = <0>; compatible = "national,lp5523"; label = "q3"; reg = <0x33>; clock-mode = /bits/ 8 <0>; /* LP55XX_CLOCK_AUTO */ - chan0 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan1 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan2 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan3 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan4 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan5 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan6 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan7 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan8 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; + multi-led@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0>; + color = <LED_COLOR_ID_RGB>; + + led@0 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x0>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@1 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x1>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@6 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x6>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; + color = <LED_COLOR_ID_RGB>; + + led@2 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x2>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@3 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x3>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@7 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x7>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + color = <LED_COLOR_ID_RGB>; + + led@4 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x4>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@5 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x5>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@8 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x8>; + color = <LED_COLOR_ID_RED>; + }; }; }; lp5523C: lp5523C@34 { + #address-cells = <1>; + #size-cells = <0>; compatible = "national,lp5523"; label = "q4"; reg = <0x34>; clock-mode = /bits/ 8 <0>; /* LP55XX_CLOCK_AUTO */ - chan0 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan1 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan2 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan3 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan4 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan5 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan6 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan7 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan8 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; + multi-led@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0>; + color = <LED_COLOR_ID_RGB>; + + led@0 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x0>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@1 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x1>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@6 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x6>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; + color = <LED_COLOR_ID_RGB>; + + led@2 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x2>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@3 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x3>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@7 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x7>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + color = <LED_COLOR_ID_RGB>; + + led@4 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x4>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@5 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x5>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@8 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x8>; + color = <LED_COLOR_ID_RED>; + }; }; }; lp5523D: lp552D@35 { + #address-cells = <1>; + #size-cells = <0>; compatible = "national,lp5523"; label = "q2"; reg = <0x35>; clock-mode = /bits/ 8 <0>; /* LP55XX_CLOCK_AUTO */ - chan0 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan1 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan2 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan3 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan4 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan5 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan6 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan7 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; - }; - chan8 { - led-cur = /bits/ 8 <12>; - max-cur = /bits/ 8 <15>; + multi-led@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0>; + color = <LED_COLOR_ID_RGB>; + + led@0 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x0>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@1 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x1>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@6 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x6>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; + color = <LED_COLOR_ID_RGB>; + + led@2 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x2>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@3 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x3>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@7 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x7>; + color = <LED_COLOR_ID_RED>; + }; + }; + multi-led@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + color = <LED_COLOR_ID_RGB>; + + led@4 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x4>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@5 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x5>; + color = <LED_COLOR_ID_BLUE>; + }; + + led@8 { + led-cur = /bits/ 8 <12>; + max-cur = /bits/ 8 <15>; + reg = <0x8>; + color = <LED_COLOR_ID_RED>; + }; }; }; }; @@ -417,6 +606,8 @@ }; &mmc3 { + #address-cells = <1>; + #size-cells = <0>; status = "okay"; bus-width = <4>; pinctrl-names = "default"; @@ -426,6 +617,11 @@ mmc-pwrseq = <&sdio_pwrseq>; vmmc-supply = <&vcc3v3>; vqmmc-supply = <&vcc1v8>; + atheros@0 { + compatible = "atheros,ath6kl"; + reg = <0>; + bus-width = <4>; + }; }; &tps { diff --git a/arch/arm/boot/dts/omap4-l4.dtsi b/arch/arm/boot/dts/omap4-l4.dtsi index e0bb60a3077959b9127e0844d9d9eab5e2001c52..99721673d7afdd13e30c946f1fd24e141f8887a5 100644 --- a/arch/arm/boot/dts/omap4-l4.dtsi +++ b/arch/arm/boot/dts/omap4-l4.dtsi @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 &l4_cfg { /* 0x4a000000 */ - compatible = "ti,omap4-l4-cfg", "simple-bus"; + compatible = "ti,omap4-l4-cfg", "simple-pm-bus"; + power-domains = <&prm_core>; + clocks = <&l4_cfg_clkctrl OMAP4_L4_CFG_CLKCTRL 0>; + clock-names = "fck"; reg = <0x4a000000 0x800>, <0x4a000800 0x800>, <0x4a001000 0x1000>; @@ -16,7 +19,7 @@ <0x00300000 0x4a300000 0x080000>; /* segment 6 */ segment@0 { /* 0x4a000000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -43,7 +46,6 @@ target-module@2000 { /* 0x4a002000, ap 3 06.0 */ compatible = "ti,sysc-omap4", "ti,sysc"; - ti,hwmods = "ctrl_module_core"; reg = <0x2000 0x4>, <0x2010 0x4>; reg-names = "rev", "sysc"; @@ -347,7 +349,7 @@ }; segment@80000 { /* 0x4a080000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00059000 0x000d9000 0x001000>, /* ap 13 */ @@ -639,7 +641,7 @@ }; segment@100000 { /* 0x4a100000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00100000 0x001000>, /* ap 21 */ @@ -653,7 +655,6 @@ target-module@0 { /* 0x4a100000, ap 21 2a.0 */ compatible = "ti,sysc-omap4", "ti,sysc"; - ti,hwmods = "ctrl_module_pad_core"; reg = <0x0 0x4>, <0x10 0x4>; reg-names = "rev", "sysc"; @@ -741,13 +742,13 @@ }; segment@180000 { /* 0x4a180000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; segment@200000 { /* 0x4a200000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x0001e000 0x0021e000 0x001000>, /* ap 31 */ @@ -903,13 +904,13 @@ }; segment@280000 { /* 0x4a280000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; l4_cfg_segment_300000: segment@300000 { /* 0x4a300000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00300000 0x020000>, /* ap 67 */ @@ -944,7 +945,10 @@ }; &l4_wkup { /* 0x4a300000 */ - compatible = "ti,omap4-l4-wkup", "simple-bus"; + compatible = "ti,omap4-l4-wkup", "simple-pm-bus"; + power-domains = <&prm_wkup>; + clocks = <&l4_wkup_clkctrl OMAP4_L4_WKUP_CLKCTRL 0>; + clock-names = "fck"; reg = <0x4a300000 0x800>, <0x4a300800 0x800>, <0x4a301000 0x1000>; @@ -956,7 +960,7 @@ <0x00020000 0x4a320000 0x010000>; /* segment 2 */ segment@0 { /* 0x4a300000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -1041,7 +1045,6 @@ target-module@c000 { /* 0x4a30c000, ap 19 2c.0 */ compatible = "ti,sysc-omap4", "ti,sysc"; - ti,hwmods = "ctrl_module_wkup"; reg = <0xc000 0x4>, <0xc010 0x4>; reg-names = "rev", "sysc"; @@ -1062,7 +1065,7 @@ }; segment@10000 { /* 0x4a310000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00010000 0x001000>, /* ap 5 */ @@ -1202,7 +1205,6 @@ target-module@e000 { /* 0x4a31e000, ap 21 30.0 */ compatible = "ti,sysc-omap4", "ti,sysc"; - ti,hwmods = "ctrl_module_pad_wkup"; reg = <0xe000 0x4>, <0xe010 0x4>; reg-names = "rev", "sysc"; @@ -1231,7 +1233,7 @@ }; segment@20000 { /* 0x4a320000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00006000 0x00026000 0x001000>, /* ap 13 */ @@ -1284,7 +1286,10 @@ }; &l4_per { /* 0x48000000 */ - compatible = "ti,omap4-l4-per", "simple-bus"; + compatible = "ti,omap4-l4-per", "simple-pm-bus"; + power-domains = <&prm_l4per>; + clocks = <&l4_per_clkctrl OMAP4_L4_PER_CLKCTRL 0>; + clock-names = "fck"; reg = <0x48000000 0x800>, <0x48000800 0x800>, <0x48001000 0x400>, @@ -1298,7 +1303,7 @@ <0x00200000 0x48200000 0x200000>; /* segment 1 */ segment@0 { /* 0x48000000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -2437,7 +2442,7 @@ }; segment@200000 { /* 0x48200000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00150000 0x00350000 0x001000>, /* ap 77 */ diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 4a9f9496a8677777fa167aed82ef91eb9067b69a..2bbff9032be3ed6faefd4c1dc98106d5d21cbc1b 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -59,14 +59,12 @@ }; /* - * Note that 4430 needs cross trigger interface (CTI) supported - * before we can configure the interrupts. This means sampling - * events are not supported for pmu. Note that 4460 does not use - * CTI, see also 4460.dtsi. + * Needed early by omap4_sram_init() for barrier, do not move to l3 + * interconnect as simple-pm-bus probes at module_init() time. */ - pmu { - compatible = "arm,cortex-a9-pmu"; - ti,hwmods = "debugss"; + ocmcram: sram@40304000 { + compatible = "mmio-sram"; + reg = <0x40304000 0xa000>; /* 40k */ }; gic: interrupt-controller@48241000 { @@ -101,19 +99,6 @@ interrupt-parent = <&gic>; }; - /* - * The soc node represents the soc top level view. It is used for IPs - * that are not memory mapped in the MPU view or for the MPU itself. - */ - soc { - compatible = "ti,omap-infra"; - mpu { - compatible = "ti,omap4-mpu"; - ti,hwmods = "mpu"; - sram = <&ocmcram>; - }; - }; - /* * XXX: Use a flat representation of the OMAP4 interconnect. * The real OMAP interconnect network is quite complex. @@ -122,16 +107,23 @@ * hierarchy. */ ocp { - compatible = "ti,omap4-l3-noc", "simple-bus"; + compatible = "simple-pm-bus"; + power-domains = <&prm_l4per>; + clocks = <&l3_1_clkctrl OMAP4_L3_MAIN_1_CLKCTRL 0>, + <&l3_2_clkctrl OMAP4_L3_MAIN_2_CLKCTRL 0>, + <&l3_instr_clkctrl OMAP4_L3_MAIN_3_CLKCTRL 0>; #address-cells = <1>; #size-cells = <1>; ranges; - ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; - reg = <0x44000000 0x1000>, - <0x44800000 0x2000>, - <0x45000000 0x1000>; - interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + + l3-noc@44000000 { + compatible = "ti,omap4-l3-noc"; + reg = <0x44000000 0x1000>, + <0x44800000 0x2000>, + <0x45000000 0x1000>; + interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + }; l4_wkup: interconnect@4a300000 { }; @@ -142,12 +134,22 @@ l4_per: interconnect@48000000 { }; - l4_abe: interconnect@40100000 { + target-module@48210000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + power-domains = <&prm_mpu>; + clocks = <&mpuss_clkctrl OMAP4_MPU_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x48210000 0x1f0000>; + + mpu { + compatible = "ti,omap4-mpu"; + sram = <&ocmcram>; + }; }; - ocmcram: sram@40304000 { - compatible = "mmio-sram"; - reg = <0x40304000 0xa000>; /* 40k */ + l4_abe: interconnect@40100000 { }; target-module@50000000 { @@ -189,7 +191,6 @@ target-module@52000000 { compatible = "ti,sysc-omap4", "ti,sysc"; - ti,hwmods = "iss"; reg = <0x52000000 0x4>, <0x52000010 0x4>; reg-names = "rev", "sysc"; @@ -203,6 +204,7 @@ <SYSC_IDLE_SMART>, <SYSC_IDLE_SMART_WKUP>; ti,sysc-delay-us = <2>; + power-domains = <&prm_cam>; clocks = <&iss_clkctrl OMAP4_ISS_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; @@ -212,6 +214,26 @@ /* No child device binding, driver in staging */ }; + /* + * Note that 4430 needs cross trigger interface (CTI) supported + * before we can configure the interrupts. This means sampling + * events are not supported for pmu. Note that 4460 does not use + * CTI, see also 4460.dtsi. + */ + target-module@54000000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + power-domains = <&prm_emu>; + clocks = <&emu_sys_clkctrl OMAP4_DEBUGSS_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x54000000 0x1000000>; + + pmu: pmu { + compatible = "arm,cortex-a9-pmu"; + }; + }; + target-module@55082000 { compatible = "ti,sysc-omap2", "ti,sysc"; reg = <0x55082000 0x4>, @@ -261,35 +283,67 @@ /* No child device binding or driver in mainline */ }; - dmm@4e000000 { - compatible = "ti,omap4-dmm"; - reg = <0x4e000000 0x800>; - interrupts = <0 113 0x4>; - ti,hwmods = "dmm"; + target-module@4e000000 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0x4e000000 0x4>, + <0x4e000010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ranges = <0x0 0x4e000000 0x2000000>; + #size-cells = <1>; + #address-cells = <1>; + + dmm@0 { + compatible = "ti,omap4-dmm"; + reg = <0 0x800>; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + }; }; - emif1: emif@4c000000 { - compatible = "ti,emif-4d"; - reg = <0x4c000000 0x100>; - interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; - ti,hwmods = "emif1"; - ti,no-idle-on-init; - phy-type = <1>; - hw-caps-read-idle-ctrl; - hw-caps-ll-interface; - hw-caps-temp-alert; + target-module@4c000000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + reg = <0x4c000000 0x4>; + reg-names = "rev"; + clocks = <&l3_emif_clkctrl OMAP4_EMIF1_CLKCTRL 0>; + clock-names = "fck"; + ti,no-idle; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4c000000 0x1000000>; + + emif1: emif@0 { + compatible = "ti,emif-4d"; + reg = <0 0x100>; + interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + phy-type = <1>; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; + }; }; - emif2: emif@4d000000 { - compatible = "ti,emif-4d"; - reg = <0x4d000000 0x100>; - interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; - ti,hwmods = "emif2"; - ti,no-idle-on-init; - phy-type = <1>; - hw-caps-read-idle-ctrl; - hw-caps-ll-interface; - hw-caps-temp-alert; + target-module@4d000000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + reg = <0x4d000000 0x4>; + reg-names = "rev"; + clocks = <&l3_emif_clkctrl OMAP4_EMIF2_CLKCTRL 0>; + clock-names = "fck"; + ti,no-idle; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4d000000 0x1000000>; + + emif2: emif@0 { + compatible = "ti,emif-4d"; + reg = <0 0x100>; + interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; + phy-type = <1>; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; + }; }; dsp: dsp { @@ -440,6 +494,7 @@ <SYSC_IDLE_NO>, <SYSC_IDLE_SMART>, <SYSC_IDLE_SMART_WKUP>; + power-domains = <&prm_gfx>; clocks = <&l3_gfx_clkctrl OMAP4_GPU_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi index 2d3e54901b6ea4f20b2afcc38ec2665afd8ca776..3d6db1db94e04aa100fdc474536c3a3a750a7483 100644 --- a/arch/arm/boot/dts/omap4460.dtsi +++ b/arch/arm/boot/dts/omap4460.dtsi @@ -26,13 +26,6 @@ }; }; - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; - ti,hwmods = "debugss"; - }; - thermal-zones { #include "omap4-cpu-thermal.dtsi" }; @@ -128,4 +121,10 @@ <0x00030000 0x00030000 0x00010000>; }; +&pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; +}; + /include/ "omap446x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap5-l4.dtsi b/arch/arm/boot/dts/omap5-l4.dtsi index 887b3359dd5a111a953f22539e138bc164ca42f5..b148b289e83015ffafa86909b3ca3a2dde47988a 100644 --- a/arch/arm/boot/dts/omap5-l4.dtsi +++ b/arch/arm/boot/dts/omap5-l4.dtsi @@ -1,5 +1,8 @@ &l4_cfg { /* 0x4a000000 */ - compatible = "ti,omap5-l4-cfg", "simple-bus"; + compatible = "ti,omap5-l4-cfg", "simple-pm-bus"; + power-domains = <&prm_core>; + clocks = <&l4cfg_clkctrl OMAP5_L4_CFG_CLKCTRL 0>; + clock-names = "fck"; reg = <0x4a000000 0x800>, <0x4a000800 0x800>, <0x4a001000 0x1000>; @@ -15,7 +18,7 @@ <0x00300000 0x4a300000 0x080000>; /* segment 6 */ segment@0 { /* 0x4a000000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -391,7 +394,7 @@ }; segment@80000 { /* 0x4a080000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00059000 0x000d9000 0x001000>, /* ap 13 */ @@ -654,7 +657,7 @@ }; segment@100000 { /* 0x4a100000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00002000 0x00102000 0x001000>, /* ap 59 */ @@ -691,22 +694,44 @@ }; target-module@40000 { /* 0x4a140000, ap 101 16.0 */ - compatible = "ti,sysc"; - status = "disabled"; - #address-cells = <1>; + compatible = "ti,sysc-omap4", "ti,sysc"; + reg = <0x400fc 4>, + <0x41100 4>; + reg-names = "rev", "sysc"; + ti,sysc-midle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>, + <SYSC_IDLE_SMART_WKUP>; + power-domains = <&prm_l3init>; + clocks = <&l3init_clkctrl OMAP5_SATA_CLKCTRL 0>; + clock-names = "fck"; #size-cells = <1>; + #address-cells = <1>; ranges = <0x0 0x40000 0x10000>; + + sata: sata@0 { + compatible = "snps,dwc-ahci"; + reg = <0 0x1100>, <0x1100 0x8>; + interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; + phys = <&sata_phy>; + phy-names = "sata-phy"; + clocks = <&l3init_clkctrl OMAP5_SATA_CLKCTRL 8>; + ports-implemented = <0x1>; + }; }; }; segment@180000 { /* 0x4a180000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; segment@200000 { /* 0x4a200000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x0001e000 0x0021e000 0x001000>, /* ap 29 */ @@ -912,20 +937,23 @@ }; segment@280000 { /* 0x4a280000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; segment@300000 { /* 0x4a300000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; }; &l4_per { /* 0x48000000 */ - compatible = "ti,omap5-l4-per", "simple-bus"; + compatible = "ti,omap5-l4-per", "simple-pm-bus"; + power-domains = <&prm_core>; + clocks = <&l4per_clkctrl OMAP5_L4_PER_CLKCTRL 0>; + clock-names = "fck"; reg = <0x48000000 0x800>, <0x48000800 0x800>, <0x48001000 0x400>, @@ -939,7 +967,7 @@ <0x00200000 0x48200000 0x200000>; /* segment 1 */ segment@0 { /* 0x48000000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -2148,14 +2176,17 @@ }; segment@200000 { /* 0x48200000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; }; }; &l4_wkup { /* 0x4ae00000 */ - compatible = "ti,omap5-l4-wkup", "simple-bus"; + compatible = "ti,omap5-l4-wkup", "simple-pm-bus"; + power-domains = <&prm_wkupaon>; + clocks = <&wkupaon_clkctrl OMAP5_L4_WKUP_CLKCTRL 0>; + clock-names = "fck"; reg = <0x4ae00000 0x800>, <0x4ae00800 0x800>, <0x4ae01000 0x1000>; @@ -2167,7 +2198,7 @@ <0x00020000 0x4ae20000 0x010000>; /* segment 2 */ segment@0 { /* 0x4ae00000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00000000 0x000800>, /* ap 0 */ @@ -2296,7 +2327,7 @@ }; segment@10000 { /* 0x4ae10000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x00010000 0x001000>, /* ap 5 */ @@ -2423,7 +2454,7 @@ }; segment@20000 { /* 0x4ae20000 */ - compatible = "simple-bus"; + compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00006000 0x00026000 0x001000>, /* ap 13 */ diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index ee821d0ab3648ade7c90f2a5a8e57b4f44ff8a6e..bac6fa83879368b447d9e0146d2c998ba6d81fe3 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -106,6 +106,15 @@ <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>; }; + /* + * Needed early by omap4_sram_init() for barrier, do not move to l3 + * interconnect as simple-pm-bus probes at module_init() time. + */ + ocmcram: sram@40300000 { + compatible = "mmio-sram"; + reg = <0 0x40300000 0 0x20000>; /* 128k */ + }; + gic: interrupt-controller@48211000 { compatible = "arm,cortex-a15-gic"; interrupt-controller; @@ -125,19 +134,6 @@ interrupt-parent = <&gic>; }; - /* - * The soc node represents the soc top level view. It is used for IPs - * that are not memory mapped in the MPU view or for the MPU itself. - */ - soc { - compatible = "ti,omap-infra"; - mpu { - compatible = "ti,omap4-mpu"; - ti,hwmods = "mpu"; - sram = <&ocmcram>; - }; - }; - /* * XXX: Use a flat representation of the OMAP3 interconnect. * The real OMAP interconnect network is quite complex. @@ -146,17 +142,24 @@ * hierarchy. */ ocp { - compatible = "ti,omap5-l3-noc", "simple-bus"; + compatible = "simple-pm-bus"; + power-domains = <&prm_core>; + clocks = <&l3main1_clkctrl OMAP5_L3_MAIN_1_CLKCTRL 0>, + <&l3main2_clkctrl OMAP5_L3_MAIN_2_CLKCTRL 0>, + <&l3instr_clkctrl OMAP5_L3_MAIN_3_CLKCTRL 0>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0 0 0xc0000000>; dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>; - ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; - reg = <0 0x44000000 0 0x2000>, - <0 0x44800000 0 0x3000>, - <0 0x45000000 0 0x4000>; - interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + + l3-noc@44000000 { + compatible = "ti,omap5-l3-noc"; + reg = <0x44000000 0x2000>, + <0x44800000 0x3000>, + <0x45000000 0x4000>; + interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + }; l4_wkup: interconnect@4ae00000 { }; @@ -167,31 +170,58 @@ l4_per: interconnect@48000000 { }; - l4_abe: interconnect@40100000 { + target-module@48210000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + power-domains = <&prm_mpu>; + clocks = <&mpu_clkctrl OMAP5_MPU_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x48210000 0x1f0000>; + + mpu { + compatible = "ti,omap4-mpu"; + sram = <&ocmcram>; + }; }; - ocmcram: sram@40300000 { - compatible = "mmio-sram"; - reg = <0x40300000 0x20000>; /* 128k */ + l4_abe: interconnect@40100000 { }; - gpmc: gpmc@50000000 { - compatible = "ti,omap4430-gpmc"; - reg = <0x50000000 0x1000>; - #address-cells = <2>; - #size-cells = <1>; - interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; - dmas = <&sdma 4>; - dma-names = "rxtx"; - gpmc,num-cs = <8>; - gpmc,num-waitpins = <4>; - ti,hwmods = "gpmc"; - clocks = <&l3_iclk_div>; + target-module@50000000 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0x50000000 4>, + <0x50000010 4>, + <0x50000014 4>; + reg-names = "rev", "sysc", "syss"; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ti,syss-mask = <1>; + ti,no-idle-on-init; + clocks = <&l3main2_clkctrl OMAP5_L3_MAIN_2_GPMC_CLKCTRL 0>; clock-names = "fck"; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x50000000 0x50000000 0x00001000>, /* regs */ + <0x00000000 0x00000000 0x40000000>; /* data */ + + gpmc: gpmc@50000000 { + compatible = "ti,omap4430-gpmc"; + reg = <0x50000000 0x1000>; + #address-cells = <2>; + #size-cells = <1>; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&sdma 4>; + dma-names = "rxtx"; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <4>; + clock-names = "fck"; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; }; target-module@55082000 { @@ -246,35 +276,67 @@ status = "disabled"; }; - dmm@4e000000 { - compatible = "ti,omap5-dmm"; - reg = <0x4e000000 0x800>; - interrupts = <0 113 0x4>; - ti,hwmods = "dmm"; + target-module@4e000000 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0x4e000000 0x4>, + <0x4e000010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>; + ranges = <0x0 0x4e000000 0x2000000>; + #size-cells = <1>; + #address-cells = <1>; + + dmm@0 { + compatible = "ti,omap5-dmm"; + reg = <0 0x800>; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + }; }; - emif1: emif@4c000000 { - compatible = "ti,emif-4d5"; - ti,hwmods = "emif1"; - ti,no-idle-on-init; - phy-type = <2>; /* DDR PHY type: Intelli PHY */ - reg = <0x4c000000 0x400>; - interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; - hw-caps-read-idle-ctrl; - hw-caps-ll-interface; - hw-caps-temp-alert; + target-module@4c000000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + reg = <0x4c000000 0x4>; + reg-names = "rev"; + clocks = <&emif_clkctrl OMAP5_EMIF1_CLKCTRL 0>; + clock-names = "fck"; + ti,no-idle; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4c000000 0x1000000>; + + emif1: emif@0 { + compatible = "ti,emif-4d5"; + reg = <0 0x400>; + interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + phy-type = <2>; /* DDR PHY type: Intelli PHY */ + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; + }; }; - emif2: emif@4d000000 { - compatible = "ti,emif-4d5"; - ti,hwmods = "emif2"; - ti,no-idle-on-init; - phy-type = <2>; /* DDR PHY type: Intelli PHY */ - reg = <0x4d000000 0x400>; - interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; - hw-caps-read-idle-ctrl; - hw-caps-ll-interface; - hw-caps-temp-alert; + target-module@4d000000 { + compatible = "ti,sysc-omap4-simple", "ti,sysc"; + reg = <0x4d000000 0x4>; + reg-names = "rev"; + clocks = <&emif_clkctrl OMAP5_EMIF2_CLKCTRL 0>; + clock-names = "fck"; + ti,no-idle; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4d000000 0x1000000>; + + emif2: emif@0 { + compatible = "ti,emif-4d5"; + reg = <0 0x400>; + interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; + phy-type = <2>; /* DDR PHY type: Intelli PHY */ + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; + }; }; aes1_target: target-module@4b501000 { @@ -374,18 +436,6 @@ #thermal-sensor-cells = <1>; }; - /* OCP2SCP3 */ - sata: sata@4a141100 { - compatible = "snps,dwc-ahci"; - reg = <0x4a140000 0x1100>, <0x4a141100 0x7>; - interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; - phys = <&sata_phy>; - phy-names = "sata-phy"; - clocks = <&l3init_clkctrl OMAP5_SATA_CLKCTRL 8>; - ti,hwmods = "sata"; - ports-implemented = <0x1>; - }; - target-module@56000000 { compatible = "ti,sysc-omap4", "ti,sysc"; reg = <0x5600fe00 0x4>, diff --git a/arch/arm/boot/dts/owl-s500-roseapplepi.dts b/arch/arm/boot/dts/owl-s500-roseapplepi.dts index ff91561ca99c8ee01bea4dc3f11390ff704085cc..b8c5db2344aa0c344dfb49b7af2dbf87b44d61be 100644 --- a/arch/arm/boot/dts/owl-s500-roseapplepi.dts +++ b/arch/arm/boot/dts/owl-s500-roseapplepi.dts @@ -2,7 +2,7 @@ /* * Roseapple Pi * - * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> + * Copyright (C) 2020-2021 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> */ /dts-v1/; @@ -27,20 +27,140 @@ reg = <0x0 0x80000000>; /* 2GB */ }; - /* Fixed regulator used in the absence of PMIC */ - sd_vcc: sd-vcc { + syspwr: regulator-5v0 { compatible = "regulator-fixed"; - regulator-name = "fixed-3.1V"; - regulator-min-microvolt = <3100000>; - regulator-max-microvolt = <3100000>; + regulator-name = "SYSPWR"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; regulator-always-on; }; }; +&cpu0 { + cpu0-supply = <&vdd_cpu>; +}; + &i2c0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; + + atc260x: pmic@65 { + compatible = "actions,atc2603c"; + reg = <0x65>; + interrupt-parent = <&sirq>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + + reset-time-sec = <6>; + + regulators { + compatible = "actions,atc2603c-regulator"; + + dcdc1-supply = <&syspwr>; + dcdc2-supply = <&syspwr>; + dcdc3-supply = <&syspwr>; + ldo1-supply = <&syspwr>; + ldo2-supply = <&syspwr>; + ldo3-supply = <&syspwr>; + ldo5-supply = <&syspwr>; + ldo6-supply = <&syspwr>; + ldo7-supply = <&syspwr>; + ldo8-supply = <&syspwr>; + ldo11-supply = <&syspwr>; + ldo12-supply = <&syspwr>; + switchldo1-supply = <&vcc>; + + vdd_cpu: dcdc1 { + regulator-name = "VDD_CPU"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + }; + + vddq: dcdc2 { + regulator-name = "VDDQ"; + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <2150000>; + regulator-always-on; + regulator-boot-on; + }; + + vcc: dcdc3 { + regulator-name = "VCC"; + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vcc_3v3: ldo1 { + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + avcc: ldo2 { + regulator-name = "AVCC"; + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_1v8: ldo3 { + regulator-name = "VDD_1V8"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2000000>; + regulator-always-on; + }; + + vcc_3v1: ldo5 { + regulator-name = "VCC_3V1"; + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3300000>; + }; + + avdd: ldo6 { + regulator-name = "AVDD"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + }; + + sens_1v8: ldo7 { + regulator-name = "SENS_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo8: ldo8 { + regulator-name = "LDO8"; + regulator-min-microvolt = <2300000>; + regulator-max-microvolt = <3300000>; + }; + + svcc: ldo11 { + regulator-name = "SVCC"; + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + rtc_vdd: ldo12 { + regulator-name = "RTC_VDD"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + sd_vcc: switchldo1 { + regulator-name = "SD_VCC"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; }; &i2c1 { diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi index 7bf1da916f256a9a03985b51705016a219a8e810..ff1bdb10ad198f9d0740555a0b701acbb00b3597 100644 --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi @@ -480,7 +480,7 @@ status = "disabled"; }; - nand: qpic-nand@79b0000 { + nand: nand-controller@79b0000 { compatible = "qcom,ipq4019-nand"; reg = <0x79b0000 0x1000>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts index 0cda654371ae78e007659e4223c1d8a6dad6b316..30ee913faae6a325a9a2cc45bdcdd786d0c38a2b 100644 --- a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts +++ b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts @@ -529,6 +529,10 @@ pinctrl-names = "default"; pinctrl-0 = <&mpu6515_pin>; + mount-matrix = "0", "-1", "0", + "-1", "0", "0", + "0", "0", "1"; + i2c-gate { #address-cells = <1>; #size-cells = <0>; @@ -575,7 +579,7 @@ maxim,rcomp = /bits/ 8 <0x4d>; interrupt-parent = <&msmgpio>; - interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&fuelgauge_pin>; diff --git a/arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts b/arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts index a0f7f461f48c864e2f56b5d462d28ccf6f293c0d..d737de7173cffcde1005d4cb6a4eabccc1e25d92 100644 --- a/arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts +++ b/arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts @@ -322,6 +322,27 @@ status = "okay"; }; + /* blsp2_uart8 */ + serial@f995e000 { + status = "okay"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&blsp2_uart8_pins_active>; + pinctrl-1 = <&blsp2_uart8_pins_sleep>; + + bluetooth { + compatible = "brcm,bcm43540-bt"; + max-speed = <3000000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_pins>; + device-wakeup-gpios = <&msmgpio 91 GPIO_ACTIVE_HIGH>; + shutdown-gpios = <&gpio_expander 9 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&msmgpio>; + interrupts = <75 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host-wakeup"; + }; + }; + gpio-keys { compatible = "gpio-keys"; input-name = "gpio-keys"; @@ -356,6 +377,35 @@ }; pinctrl@fd510000 { + blsp2_uart8_pins_active: blsp2-uart8-pins-active { + pins = "gpio45", "gpio46", "gpio47", "gpio48"; + function = "blsp_uart8"; + drive-strength = <8>; + bias-disable; + }; + + blsp2_uart8_pins_sleep: blsp2-uart8-pins-sleep { + pins = "gpio45", "gpio46", "gpio47", "gpio48"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + bt_pins: bt-pins { + hostwake { + pins = "gpio75"; + function = "gpio"; + drive-strength = <16>; + input-enable; + }; + + devwake { + pins = "gpio91"; + function = "gpio"; + drive-strength = <2>; + }; + }; + sdhc1_pin_a: sdhc1-pin-active { clk { pins = "sdc1_clk"; @@ -717,7 +767,7 @@ maxim,rcomp = /bits/ 8 <0x56>; interrupt-parent = <&pma8084_gpios>; - interrupts = <21 IRQ_TYPE_EDGE_FALLING>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&fuelgauge_pin>; diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index c65d33591efaa3171cd04695d0abbab265d7e69c..db4c06bf7888bf529e5494cc63bf43d44750b5e2 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -715,6 +715,15 @@ status = "disabled"; }; + blsp2_uart8: serial@f995e000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xf995e000 0x1000>; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + blsp2_uart10: serial@f9960000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xf9960000 0x1000>; diff --git a/arch/arm/boot/dts/qcom-sdx55-t55.dts b/arch/arm/boot/dts/qcom-sdx55-t55.dts new file mode 100644 index 0000000000000000000000000000000000000000..ddcd53aa533db64f74e2e4b9b279246b2e2bd2b4 --- /dev/null +++ b/arch/arm/boot/dts/qcom-sdx55-t55.dts @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Ltd. + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/regulator/qcom,rpmh-regulator.h> +#include "qcom-sdx55.dtsi" +#include "qcom-pmx55.dtsi" + +/ { + model = "Thundercomm T55 Development Kit"; + compatible = "qcom,sdx55-t55", "qcom,sdx55"; + qcom,board-id = <0xb010008 0x4>; + + aliases { + serial0 = &blsp1_uart3; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mpss_debug_mem: memory@8ef00000 { + no-map; + reg = <0x8ef00000 0x800000>; + }; + + ipa_fw_mem: memory@8fced000 { + no-map; + reg = <0x8fced000 0x10000>; + }; + + mpss_adsp_mem: memory@90800000 { + no-map; + reg = <0x90800000 0xf800000>; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + vreg_bob_3p3: pmx55-bob { + compatible = "regulator-fixed"; + regulator-name = "vreg_bob_3p3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; + + vreg_s7e_mx_0p752: pmx55-s7e { + compatible = "regulator-fixed"; + regulator-name = "vreg_s7e_mx_0p752"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + + vin-supply = <&vph_pwr>; + }; + + vreg_sd_vdd: sd-vdd { + compatible = "regulator-fixed"; + regulator-name = "vreg_sd_vdd"; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + + vin-supply = <&vreg_vddpx_2>; + }; + + vreg_vddpx_2: vddpx-2 { + compatible = "regulator-gpio"; + regulator-name = "vreg_vddpx_2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2850000>; + enable-gpios = <&tlmm 98 GPIO_ACTIVE_HIGH>; + gpios = <&tlmm 100 GPIO_ACTIVE_HIGH>; + states = <1800000 0>, <2850000 1>; + startup-delay-us = <200000>; + enable-active-high; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; +}; + +&apps_rsc { + pmx55-rpmh-regulators { + compatible = "qcom,pmx55-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-l1-l2-supply = <&vreg_s2e_1p224>; + vdd-l3-l9-supply = <&vreg_s3e_0p824>; + vdd-l4-l12-supply = <&vreg_s4e_1p904>; + vdd-l5-l6-supply = <&vreg_s4e_1p904>; + vdd-l7-l8-supply = <&vreg_s3e_0p824>; + vdd-l10-l11-l13-supply = <&vreg_bob_3p3>; + vdd-l14-supply = <&vreg_s7e_mx_0p752>; + vdd-l15-supply = <&vreg_s2e_1p224>; + vdd-l16-supply = <&vreg_s4e_1p904>; + + vreg_s2e_1p224: smps2 { + regulator-min-microvolt = <1280000>; + regulator-max-microvolt = <1400000>; + }; + + vreg_s3e_0p824: smps3 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1000000>; + }; + + vreg_s4e_1p904: smps4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1960000>; + }; + + vreg_l1e_bb_1p2: ldo1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo2 { + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo3 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + vreg_l4e_bb_0p875: ldo4 { + regulator-min-microvolt = <872000>; + regulator-max-microvolt = <872000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + vreg_l5e_bb_1p7: ldo5 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo7 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo8 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo9 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + vreg_l10e_3p1: ldo10 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo11 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo12 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo13 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo14 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo15 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo16 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + }; +}; + +&blsp1_uart3 { + status = "ok"; +}; + +&qpic_bam { + status = "ok"; +}; + +&qpic_nand { + status = "ok"; + + nand@0 { + reg = <0>; + + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; + nand-bus-width = <8>; + /* efs2 partition is secured */ + secure-regions = <0x500000 0xb00000>; + }; +}; + +&remoteproc_mpss { + status = "okay"; + memory-region = <&mpss_adsp_mem>; +}; + +&usb_hsphy { + status = "okay"; + vdda-pll-supply = <&vreg_l4e_bb_0p875>; + vdda33-supply = <&vreg_l10e_3p1>; + vdda18-supply = <&vreg_l5e_bb_1p7>; +}; + +&usb_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l4e_bb_0p875>; + vdda-pll-supply = <&vreg_l1e_bb_1p2>; +}; + +&usb { + status = "okay"; +}; + +&usb_dwc3 { + dr_mode = "peripheral"; +}; diff --git a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts new file mode 100644 index 0000000000000000000000000000000000000000..3065f84634b800d95d5af62c0585c7940c6d73a0 --- /dev/null +++ b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Ltd. + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/regulator/qcom,rpmh-regulator.h> +#include "qcom-sdx55.dtsi" +#include "qcom-pmx55.dtsi" + +/ { + model = "Telit FN980 TLB"; + compatible = "qcom,sdx55-telit-fn980-tlb", "qcom,sdx55"; + qcom,board-id = <0xb010008 0x0>; + + aliases { + serial0 = &blsp1_uart3; + }; + + chosen { + stdout-path = "serial0:921600n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mpss_debug_mem: memory@8ef00000 { + no-map; + reg = <0x8ef00000 0x800000>; + }; + + ipa_fw_mem: memory@8fced000 { + no-map; + reg = <0x8fced000 0x10000>; + }; + + mpss_adsp_mem: memory@90800000 { + no-map; + reg = <0x90800000 0xf800000>; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + vreg_bob_3p3: pmx55-bob { + compatible = "regulator-fixed"; + regulator-name = "vreg_bob_3p3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; + + vreg_s7e_mx_0p752: pmx55-s7e { + compatible = "regulator-fixed"; + regulator-name = "vreg_s7e_mx_0p752"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + + vin-supply = <&vph_pwr>; + }; + + vreg_sd_vdd: sd-vdd { + compatible = "regulator-fixed"; + regulator-name = "vreg_sd_vdd"; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + + vin-supply = <&vreg_vddpx_2>; + }; + + vreg_vddpx_2: vddpx-2 { + compatible = "regulator-gpio"; + regulator-name = "vreg_vddpx_2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2850000>; + enable-gpios = <&tlmm 98 GPIO_ACTIVE_HIGH>; + gpios = <&tlmm 100 GPIO_ACTIVE_HIGH>; + states = <1800000 0>, <2850000 1>; + startup-delay-us = <200000>; + enable-active-high; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; +}; + +&apps_rsc { + pmx55-rpmh-regulators { + compatible = "qcom,pmx55-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-l1-l2-supply = <&vreg_s2e_1p224>; + vdd-l3-l9-supply = <&vreg_s3e_0p824>; + vdd-l4-l12-supply = <&vreg_s4e_1p904>; + vdd-l5-l6-supply = <&vreg_s4e_1p904>; + vdd-l7-l8-supply = <&vreg_s3e_0p824>; + vdd-l10-l11-l13-supply = <&vreg_bob_3p3>; + vdd-l14-supply = <&vreg_s7e_mx_0p752>; + vdd-l15-supply = <&vreg_s2e_1p224>; + vdd-l16-supply = <&vreg_s4e_1p904>; + + vreg_s2e_1p224: smps2 { + regulator-min-microvolt = <1280000>; + regulator-max-microvolt = <1400000>; + }; + + vreg_s3e_0p824: smps3 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1000000>; + }; + + vreg_s4e_1p904: smps4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1960000>; + }; + + vreg_l1e_bb_1p2: ldo1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo2 { + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo3 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + vreg_l4e_bb_0p875: ldo4 { + regulator-min-microvolt = <872000>; + regulator-max-microvolt = <872000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + vreg_l5e_bb_1p7: ldo5 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo7 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo8 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo9 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + vreg_l10e_3p1: ldo10 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo11 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo12 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo13 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo14 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo15 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + + ldo16 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>; + }; + }; +}; + +&blsp1_uart3 { + status = "ok"; +}; + +&qpic_bam { + status = "ok"; +}; + +&qpic_nand { + status = "ok"; + + nand@0 { + reg = <0>; + + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; + nand-bus-width = <8>; + /* ico and efs2 partitions are secured */ + secure-regions = <0x500000 0x500000 + 0xa00000 0xb00000>; + }; +}; + +&remoteproc_mpss { + status = "okay"; + memory-region = <&mpss_adsp_mem>; +}; + +&usb_hsphy { + status = "okay"; + vdda-pll-supply = <&vreg_l4e_bb_0p875>; + vdda33-supply = <&vreg_l10e_3p1>; + vdda18-supply = <&vreg_l5e_bb_1p7>; +}; + +&usb_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l4e_bb_0p875>; + vdda-pll-supply = <&vreg_l1e_bb_1p2>; +}; + +&usb { + status = "okay"; +}; + +&usb_dwc3 { + dr_mode = "peripheral"; +}; diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi index e4180bbc46555417ca82b10de69195458902959d..0057c7c04d31a83312f011751bce51bfcf280c6c 100644 --- a/arch/arm/boot/dts/qcom-sdx55.dtsi +++ b/arch/arm/boot/dts/qcom-sdx55.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/clock/qcom,gcc-sdx55.h> #include <dt-bindings/clock/qcom,rpmh.h> +#include <dt-bindings/interconnect/qcom,sdx55.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/power/qcom-rpmpd.h> #include <dt-bindings/soc/qcom,rpmh-rsc.h> @@ -53,6 +54,41 @@ compatible = "arm,cortex-a7"; reg = <0x0>; enable-method = "psci"; + clocks = <&apcs>; + power-domains = <&rpmhpd SDX55_CX>; + power-domain-names = "rpmhpd"; + operating-points-v2 = <&cpu_opp_table>; + }; + }; + + cpu_opp_table: cpu-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-345600000 { + opp-hz = /bits/ 64 <345600000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-576000000 { + opp-hz = /bits/ 64 <576000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-1094400000 { + opp-hz = /bits/ 64 <1094400000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-1555200000 { + opp-hz = /bits/ 64 <1555200000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + + firmware { + scm { + compatible = "qcom,scm-sdx55", "qcom,scm"; }; }; @@ -119,6 +155,37 @@ hwlocks = <&tcsr_mutex 3>; }; + smp2p-mpss { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = <GIC_SPI 113 IRQ_TYPE_EDGE_RISING>; + mboxes = <&apcs 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + ipa_smp2p_out: ipa-ap-to-modem { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + ipa_smp2p_in: ipa-modem-to-ap { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + soc: soc { #address-cells = <1>; #size-cells = <1>; @@ -187,6 +254,34 @@ }; }; + mc_virt: interconnect@1100000 { + compatible = "qcom,sdx55-mc-virt"; + reg = <0x01100000 0x400000>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mem_noc: interconnect@9680000 { + compatible = "qcom,sdx55-mem-noc"; + reg = <0x09680000 0x40000>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + system_noc: interconnect@162c000 { + compatible = "qcom,sdx55-system-noc"; + reg = <0x0162c000 0x31200>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + ipa_virt: interconnect@1e00000 { + compatible = "qcom,sdx55-ipa-virt"; + reg = <0x01e00000 0x100000>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + qpic_bam: dma-controller@1b04000 { compatible = "qcom,bam-v1.7.0"; reg = <0x01b04000 0x1c000>; @@ -199,7 +294,7 @@ status = "disabled"; }; - qpic_nand: nand@1b30000 { + qpic_nand: nand-controller@1b30000 { compatible = "qcom,sdx55-nand"; reg = <0x01b30000 0x10000>; #address-cells = <1>; @@ -215,6 +310,47 @@ status = "disabled"; }; + ipa: ipa@1e40000 { + compatible = "qcom,sdx55-ipa"; + + iommus = <&apps_smmu 0x5e0 0x0>, + <&apps_smmu 0x5e2 0x0>; + reg = <0x1e40000 0x7000>, + <0x1e50000 0x4b20>, + <0x1e04000 0x2c000>; + reg-names = "ipa-reg", + "ipa-shared", + "gsi"; + + interrupts-extended = <&intc GIC_SPI 241 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>, + <&ipa_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&ipa_smp2p_in 1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ipa", + "gsi", + "ipa-clock-query", + "ipa-setup-ready"; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + clock-names = "core"; + + interconnects = <&system_noc MASTER_IPA &system_noc SLAVE_SNOC_MEM_NOC_GC>, + <&mem_noc MASTER_SNOC_GC_MEM_NOC &mc_virt SLAVE_EBI_CH0>, + <&system_noc MASTER_IPA &system_noc SLAVE_OCIMEM>, + <&mem_noc MASTER_AMPSS_M0 &system_noc SLAVE_IPA_CFG>; + interconnect-names = "memory-a", + "memory-b", + "imem", + "config"; + + qcom,smem-states = <&ipa_smp2p_out 0>, + <&ipa_smp2p_out 1>; + qcom,smem-state-names = "ipa-clock-enabled-valid", + "ipa-clock-enabled"; + + status = "disabled"; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x01f40000 0x40000>; @@ -233,6 +369,39 @@ status = "disabled"; }; + remoteproc_mpss: remoteproc@4080000 { + compatible = "qcom,sdx55-mpss-pas"; + reg = <0x04080000 0x4040>; + + interrupts-extended = <&intc GIC_SPI 250 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd SDX55_CX>, + <&rpmhpd SDX55_MSS>; + power-domain-names = "cx", "mss"; + + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts = <GIC_SPI 114 IRQ_TYPE_EDGE_RISING>; + label = "mpss"; + qcom,remote-pid = <1>; + mboxes = <&apcs 15>; + }; + }; + usb: usb@a6f8800 { compatible = "qcom,sdx55-dwc3", "qcom,dwc3"; reg = <0x0a6f8800 0x400>; @@ -319,6 +488,21 @@ #interrupt-cells = <2>; }; + imem@1468f000 { + compatible = "simple-mfd"; + reg = <0x1468f000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x0 0x1468f000 0x1000>; + + pil-reloc@94c { + compatible = "qcom,pil-reloc-info"; + reg = <0x94c 0x200>; + }; + }; + apps_smmu: iommu@15000000 { compatible = "qcom,sdx55-smmu-500", "arm,mmu-500"; reg = <0x15000000 0x20000>; @@ -352,6 +536,23 @@ <0x17802000 0x1000>; }; + a7pll: clock@17808000 { + compatible = "qcom,sdx55-a7pll"; + reg = <0x17808000 0x1000>; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "bi_tcxo"; + #clock-cells = <0>; + }; + + apcs: mailbox@17810000 { + compatible = "qcom,sdx55-apcs-gcc", "syscon"; + reg = <0x17810000 0x2000>; + #mbox-cells = <1>; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&a7pll>, <&gcc GPLL0>; + clock-names = "ref", "pll", "aux"; + #clock-cells = <0>; + }; + watchdog@17817000 { compatible = "qcom,apss-wdt-sdx55", "qcom,kpss-wdt"; reg = <0x17817000 0x1000>; @@ -491,6 +692,10 @@ }; }; }; + + apps_bcm_voter: bcm_voter { + compatible = "qcom,bcm-voter"; + }; }; }; diff --git a/arch/arm/boot/dts/r7s9210-rza2mevb.dts b/arch/arm/boot/dts/r7s9210-rza2mevb.dts index d062d02865e7dfbb34a7ad6ebf76ee1ffd3b25e5..68498ce2aec0ebd9688ed9cf4dc4bb76e6f51077 100644 --- a/arch/arm/boot/dts/r7s9210-rza2mevb.dts +++ b/arch/arm/boot/dts/r7s9210-rza2mevb.dts @@ -4,6 +4,28 @@ * * Copyright (C) 2018 Renesas Electronics * + * As upstream Linux does not support XIP, it cannot run in 8 MiB of HyperRAM. + * Hence the 64 MiB of SDRAM on the sub-board needs to be enabled, which has + * the following ramifications: + * - SCIF4 connected to the on-board USB-serial can no longer be used as the + * serial console, + * - Instead, SCIF2 is used as the serial console, by connecting a 3.3V TTL + * USB-to-Serial adapter to the CMOS camera connector: + * - RXD = CN17-9, + * - TXD = CN17-10, + * - GND = CN17-2 or CN17-17, + * - The first Ethernet channel can no longer be used, + * - USB Channel 1 loses the overcurrent input signal. + * + * Please make sure your sub-board matches the following switch settings: + * + * SW6 SW6-1 set to SDRAM + * ON SW6-2 set to Audio + * +---------------------+ SW6-3 set to DRP + * | = = = = = | SW6-4 set to CEU + * | = = | SW6-5 set to Ether2 + * | 1 2 3 4 5 6 7 8 9 0 | SW6-6 set to VDC6 + * +---------------------+ SW6-7 set to VDC6 */ /dts-v1/; @@ -17,9 +39,8 @@ compatible = "renesas,rza2mevb", "renesas,r7s9210"; aliases { - serial0 = &scif4; - ethernet0 = ðer0; - ethernet1 = ðer1; + serial0 = &scif2; + ethernet0 = ðer1; }; chosen { @@ -58,9 +79,9 @@ }; }; - memory@40000000 { + memory@c000000 { device_type = "memory"; - reg = <0x40000000 0x00800000>; /* HyperRAM */ + reg = <0x0c000000 0x04000000>; /* SDRAM */ }; }; @@ -72,17 +93,6 @@ status = "okay"; }; -ðer0 { - pinctrl-names = "default"; - pinctrl-0 = <ð0_pins>; - status = "okay"; - renesas,no-ether-link; - phy-handle = <&phy0>; - phy0: ethernet-phy@0 { - reg = <0>; - }; -}; - ðer1 { pinctrl-names = "default"; pinctrl-0 = <ð1_pins>; @@ -142,9 +152,9 @@ }; /* Serial Console */ - scif4_pins: serial4 { - pinmux = <RZA2_PINMUX(PORT9, 0, 4)>, /* TxD4 */ - <RZA2_PINMUX(PORT9, 1, 4)>; /* RxD4 */ + scif2_pins: serial2 { + pinmux = <RZA2_PINMUX(PORTE, 2, 3)>, /* TxD2 */ + <RZA2_PINMUX(PORTE, 1, 3)>; /* RxD2 */ }; sdhi0_pins: sdhi0 { @@ -165,8 +175,7 @@ usb1_pins: usb1 { pinmux = <RZA2_PINMUX(PORTC, 0, 1)>, /* VBUSIN1 */ - <RZA2_PINMUX(PORTC, 5, 1)>, /* VBUSEN1 */ - <RZA2_PINMUX(PORT7, 5, 5)>; /* OVRCUR1 */ + <RZA2_PINMUX(PORTC, 5, 1)>; /* VBUSEN1 */ }; }; @@ -176,9 +185,9 @@ }; /* Serial Console */ -&scif4 { +&scif2 { pinctrl-names = "default"; - pinctrl-0 = <&scif4_pins>; + pinctrl-0 = <&scif2_pins>; status = "okay"; }; diff --git a/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ca.dts b/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ca.dts index 98c3fbd89fa6c5c79c248bf011958fdb46a85872..2bcb229844abc5c2f2af2b390a8d511c4b9e0469 100644 --- a/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ca.dts +++ b/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ca.dts @@ -91,92 +91,20 @@ status = "okay"; }; -&i2c0 { - ov5640@3c { - compatible = "ovti,ov5640"; - reg = <0x3c>; - clocks = <&mclk_cam1>; - clock-names = "xclk"; - - port { - ov5640_0: endpoint { - bus-width = <8>; - data-shift = <2>; - bus-type = <6>; - pclk-sample = <1>; - remote-endpoint = <&vin0ep>; - }; - }; - }; -}; - &i2c1 { pinctrl-0 = <&i2c1_pins>; pinctrl-names = "default"; - status = "okay"; + /* status set to "okay" when needed by camera configuration below */ clock-frequency = <400000>; - - ov5640@3c { - compatible = "ovti,ov5640"; - reg = <0x3c>; - clocks = <&mclk_cam2>; - clock-names = "xclk"; - - port { - ov5640_1: endpoint { - bus-width = <8>; - data-shift = <2>; - bus-type = <6>; - pclk-sample = <1>; - remote-endpoint = <&vin1ep>; - }; - }; - }; -}; - -&i2c2 { - ov5640@3c { - compatible = "ovti,ov5640"; - reg = <0x3c>; - clocks = <&mclk_cam3>; - clock-names = "xclk"; - - port { - ov5640_2: endpoint { - bus-width = <8>; - data-shift = <2>; - bus-type = <6>; - pclk-sample = <1>; - remote-endpoint = <&vin2ep>; - }; - }; - }; }; &i2c3 { pinctrl-0 = <&i2c3_pins>; pinctrl-names = "default"; - status = "okay"; + /* status set to "okay" when needed by camera configuration below */ clock-frequency = <400000>; - - ov5640@3c { - compatible = "ovti,ov5640"; - reg = <0x3c>; - clocks = <&mclk_cam4>; - clock-names = "xclk"; - - port { - ov5640_3: endpoint { - bus-width = <8>; - data-shift = <2>; - bus-type = <6>; - pclk-sample = <1>; - remote-endpoint = <&vin3ep>; - }; - }; - }; }; &pfc { @@ -267,6 +195,22 @@ cts-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; }; +/* + * Below configuration ties VINx endpoints to ov5640/ov7725 camera endpoints + * + * (un)comment the #include statements to change configuration + */ + +/* 8bit CMOS Camera 1 (J13) */ +#define CAM_PARENT_I2C i2c0 +#define MCLK_CAM mclk_cam1 +#define CAM_EP cam0ep +#define VIN_EP vin0ep +#undef CAM_ENABLED +#include "r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi" +//#include "r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi" + +#ifdef CAM_ENABLED &vin0 { /* * Set SW2 switch on the SOM to 'ON' @@ -278,13 +222,29 @@ port { vin0ep: endpoint { - remote-endpoint = <&ov5640_0>; + remote-endpoint = <&cam0ep>; bus-width = <8>; bus-type = <6>; }; }; }; - +#endif /* CAM_ENABLED */ + +#undef CAM_PARENT_I2C +#undef MCLK_CAM +#undef CAM_EP +#undef VIN_EP + +/* 8bit CMOS Camera 2 (J14) */ +#define CAM_PARENT_I2C i2c1 +#define MCLK_CAM mclk_cam2 +#define CAM_EP cam1ep +#define VIN_EP vin1ep +#undef CAM_ENABLED +#include "r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi" +//#include "r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi" + +#ifdef CAM_ENABLED &vin1 { /* Set SW1 switch on the SOM to 'ON' */ status = "okay"; @@ -293,13 +253,30 @@ port { vin1ep: endpoint { - remote-endpoint = <&ov5640_1>; + remote-endpoint = <&cam1ep>; bus-width = <8>; bus-type = <6>; }; }; }; +#endif /* CAM_ENABLED */ + +#undef CAM_PARENT_I2C +#undef MCLK_CAM +#undef CAM_EP +#undef VIN_EP + +/* 8bit CMOS Camera 3 (J12) */ +#define CAM_PARENT_I2C i2c2 +#define MCLK_CAM mclk_cam3 +#define CAM_EP cam2ep +#define VIN_EP vin2ep +#undef CAM_ENABLED +#include "r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi" +//#include "r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi" + +#ifdef CAM_ENABLED &vin2 { status = "okay"; pinctrl-0 = <&vin2_pins>; @@ -307,14 +284,30 @@ port { vin2ep: endpoint { - remote-endpoint = <&ov5640_2>; + remote-endpoint = <&cam2ep>; bus-width = <8>; data-shift = <8>; bus-type = <6>; }; }; }; - +#endif /* CAM_ENABLED */ + +#undef CAM_PARENT_I2C +#undef MCLK_CAM +#undef CAM_EP +#undef VIN_EP + +/* 8bit CMOS Camera 4 (J11) */ +#define CAM_PARENT_I2C i2c3 +#define MCLK_CAM mclk_cam4 +#define CAM_EP cam3ep +#define VIN_EP vin3ep +#undef CAM_ENABLED +#include "r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi" +//#include "r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi" + +#ifdef CAM_ENABLED &vin3 { status = "okay"; pinctrl-0 = <&vin3_pins>; @@ -322,9 +315,15 @@ port { vin3ep: endpoint { - remote-endpoint = <&ov5640_3>; + remote-endpoint = <&cam3ep>; bus-width = <8>; bus-type = <6>; }; }; }; +#endif /* CAM_ENABLED */ + +#undef CAM_PARENT_I2C +#undef MCLK_CAM +#undef CAM_EP +#undef VIN_EP diff --git a/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi b/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..70c72ba4fe724a70eb308603b0d51849d0595f1a --- /dev/null +++ b/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ov5640-single.dtsi @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This include file ties a VIN interface with a single ov5640 sensor on + * the iWave-RZ/G1H Qseven board development platform connected with the + * camera daughter board. + * + * Copyright (C) 2020 Renesas Electronics Corp. + */ + +#define CAM_ENABLED 1 + +&CAM_PARENT_I2C { + status = "okay"; + + ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&MCLK_CAM>; + clock-names = "xclk"; + status = "okay"; + + port { + CAM_EP: endpoint { + bus-width = <8>; + data-shift = <2>; + bus-type = <6>; + pclk-sample = <1>; + remote-endpoint = <&VIN_EP>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi b/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f5e77f02425167205d7366f6af33c71556c1b56d --- /dev/null +++ b/arch/arm/boot/dts/r8a7742-iwg21d-q7-dbcm-ov7725-single.dtsi @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This include file ties a VIN interface with a single ov7725 sensor on + * the iWave-RZ/G1H Qseven board development platform connected with the + * camera daughter board. + * + * Copyright (C) 2020 Renesas Electronics Corp. + */ + +#define CAM_ENABLED 1 + +&CAM_PARENT_I2C { + status = "okay"; + + ov7725@21 { + compatible = "ovti,ov7725"; + reg = <0x21>; + clocks = <&MCLK_CAM>; + status = "okay"; + + port { + CAM_EP: endpoint { + bus-width = <8>; + bus-type = <6>; + remote-endpoint = <&VIN_EP>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/r8a7742-iwg21d-q7.dts b/arch/arm/boot/dts/r8a7742-iwg21d-q7.dts index 0063ef92f50e35f1fe5bf1385bffa6dbea9b634a..94bf8a116b5242a94d6635494bbf4c66769c048d 100644 --- a/arch/arm/boot/dts/r8a7742-iwg21d-q7.dts +++ b/arch/arm/boot/dts/r8a7742-iwg21d-q7.dts @@ -387,8 +387,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi4 &src4 &dvc1>; - capture = <&ssi3 &src3 &dvc0>; + playback = <&ssi4>, <&src4>, <&dvc1>; + capture = <&ssi3>, <&src3>, <&dvc0>; }; }; }; diff --git a/arch/arm/boot/dts/r8a7742.dtsi b/arch/arm/boot/dts/r8a7742.dtsi index 6a78c813057b610f9717e0cc651166cc85cdc0e7..dd1b976d2a6c81c7c712aa08024afec96d5a1668 100644 --- a/arch/arm/boot/dts/r8a7742.dtsi +++ b/arch/arm/boot/dts/r8a7742.dtsi @@ -367,13 +367,13 @@ apmu@e6151000 { compatible = "renesas,r8a7742-apmu", "renesas,apmu"; reg = <0 0xe6151000 0 0x188>; - cpus = <&cpu4 &cpu5 &cpu6 &cpu7>; + cpus = <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>; }; apmu@e6152000 { compatible = "renesas,r8a7742-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1 &cpu2 &cpu3>; + cpus = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts b/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts index 807e7d0d6b620c83a3e9c3116c82e7bfb501ce64..4ace117470e800f8e8956d92cf49e8a329184658 100644 --- a/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts +++ b/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts @@ -61,7 +61,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; diff --git a/arch/arm/boot/dts/r8a7743.dtsi b/arch/arm/boot/dts/r8a7743.dtsi index f444e418f4085a26ccd8e32ba2df1ece5691a1bf..6e37b8da278b91705a7619567f3d9b869cc84c5d 100644 --- a/arch/arm/boot/dts/r8a7743.dtsi +++ b/arch/arm/boot/dts/r8a7743.dtsi @@ -293,7 +293,7 @@ apmu@e6152000 { compatible = "renesas,r8a7743-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7744.dtsi b/arch/arm/boot/dts/r8a7744.dtsi index 0442aad4f9dba0245f1264e65b741e5581f276ae..ace20861c0c496cbe541ef128e59c03cab212307 100644 --- a/arch/arm/boot/dts/r8a7744.dtsi +++ b/arch/arm/boot/dts/r8a7744.dtsi @@ -293,7 +293,7 @@ apmu@e6152000 { compatible = "renesas,r8a7744-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts b/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts index 1c7b37a01f0ab9239b761e0cb4ac38450a9b9faa..73bd62d8a929e5da26dfe8d39d6ca148824c7827 100644 --- a/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts +++ b/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts @@ -289,8 +289,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi3 &src3 &dvc0>; - capture = <&ssi4 &src4 &dvc1>; + playback = <&ssi3>, <&src3>, <&dvc0>; + capture = <&ssi4>, <&src4>, <&dvc1>; }; }; }; diff --git a/arch/arm/boot/dts/r8a7745-sk-rzg1e.dts b/arch/arm/boot/dts/r8a7745-sk-rzg1e.dts index db72a801abe548fe9e767098ac6c3f18bae5ec79..59d1a9bfab05a27eeb1401f2c4fe8073c24e8a4e 100644 --- a/arch/arm/boot/dts/r8a7745-sk-rzg1e.dts +++ b/arch/arm/boot/dts/r8a7745-sk-rzg1e.dts @@ -56,7 +56,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; diff --git a/arch/arm/boot/dts/r8a7745.dtsi b/arch/arm/boot/dts/r8a7745.dtsi index 0f14ac22921de7d4d94f06c7c8fed6a8d82232e9..be33bdabe45281e8cdf3742bb4b5ee042dc1327f 100644 --- a/arch/arm/boot/dts/r8a7745.dtsi +++ b/arch/arm/boot/dts/r8a7745.dtsi @@ -258,7 +258,7 @@ apmu@e6151000 { compatible = "renesas,r8a7745-apmu", "renesas,apmu"; reg = <0 0xe6151000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a77470.dtsi b/arch/arm/boot/dts/r8a77470.dtsi index 691b1a131c870df377da47885d128e28507d3af9..a1d7f6e7a2e34bff2897814507773468e779f3b0 100644 --- a/arch/arm/boot/dts/r8a77470.dtsi +++ b/arch/arm/boot/dts/r8a77470.dtsi @@ -205,7 +205,7 @@ apmu@e6151000 { compatible = "renesas,r8a77470-apmu", "renesas,apmu"; reg = <0 0xe6151000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index 09a152b9155754ac5ab7bbc95429a88582e62cf3..2dad0742d2ba159bec8f38181d8c66d2235441ba 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -53,6 +53,9 @@ i2c11 = &i2cexio1; i2c12 = &i2chdmi; i2c13 = &i2cpwr; + mmc0 = &mmcif1; + mmc1 = &sdhi0; + mmc2 = &sdhi2; }; chosen { @@ -659,7 +662,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; @@ -908,7 +911,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -918,8 +921,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi0 &src2 &dvc0>; - capture = <&ssi1 &src3 &dvc1>; + playback = <&ssi0>, <&src2>, <&dvc0>; + capture = <&ssi1>, <&src3>, <&dvc1>; }; }; }; diff --git a/arch/arm/boot/dts/r8a7790-stout.dts b/arch/arm/boot/dts/r8a7790-stout.dts index 6a457bc9280a4949fe750c9aab566a06ca9e0915..d51f23572d7fc7273afb7556565bfbf3644a01b0 100644 --- a/arch/arm/boot/dts/r8a7790-stout.dts +++ b/arch/arm/boot/dts/r8a7790-stout.dts @@ -191,7 +191,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; @@ -321,7 +321,7 @@ &iic3 { pinctrl-names = "default"; - pinctrl-0 = <&iic3_pins &pmic_irq_pins>; + pinctrl-0 = <&iic3_pins>, <&pmic_irq_pins>; status = "okay"; pmic@58 { diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index b0569b4ea5c8ae96b6b4416d68f251e4a44078b0..de29394eed63605e26258c7ba2ebf5fb0d0028b6 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -381,13 +381,13 @@ apmu@e6151000 { compatible = "renesas,r8a7790-apmu", "renesas,apmu"; reg = <0 0xe6151000 0 0x188>; - cpus = <&cpu4 &cpu5 &cpu6 &cpu7>; + cpus = <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>; }; apmu@e6152000 { compatible = "renesas,r8a7790-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1 &cpu2 &cpu3>; + cpus = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index f603cba5441fcb9e03e0fc6984ee9d1ca44c5d2e..61e881bbbf6ee5aa7d512252fb4985abbf5cdb83 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -53,6 +53,9 @@ i2c12 = &i2cexio1; i2c13 = &i2chdmi; i2c14 = &i2cexio4; + mmc0 = &sdhi0; + mmc1 = &sdhi1; + mmc2 = &sdhi2; }; chosen { @@ -78,6 +81,9 @@ keyboard { compatible = "gpio-keys"; + pinctrl-0 = <&sw2_pins>; + pinctrl-names = "default"; + key-1 { gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; linux,code = <KEY_1>; @@ -615,10 +621,15 @@ groups = "audio_clk_a"; function = "audio_clk"; }; + + sw2_pins: sw2 { + pins = "GP_5_0", "GP_5_1", "GP_5_2", "GP_5_3"; + bias-pull-up; + }; }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; @@ -878,7 +889,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -888,8 +899,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi0 &src2 &dvc0>; - capture = <&ssi1 &src3 &dvc1>; + playback = <&ssi0>, <&src2>, <&dvc0>; + capture = <&ssi1>, <&src3>, <&dvc1>; }; }; }; diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts index c6d563fb7ec7c17ff41afcfde07b963c16ebddd7..c6ef636965c16f39b9290e9051c9ecf5165f11fa 100644 --- a/arch/arm/boot/dts/r8a7791-porter.dts +++ b/arch/arm/boot/dts/r8a7791-porter.dts @@ -28,6 +28,8 @@ serial0 = &scif0; i2c9 = &gpioi2c2; i2c10 = &i2chdmi; + mmc0 = &sdhi0; + mmc1 = &sdhi2; }; chosen { @@ -292,7 +294,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; @@ -494,7 +496,7 @@ }; &rcar_sound { - pinctrl-0 = <&ssi_pins &audio_clk_pins>; + pinctrl-0 = <&ssi_pins>, <&audio_clk_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 87f0d6dc3e5ac38eb88b9f8ac49420a81d39b865..9d8320f71a6a83809545191581f82f2529944876 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -315,7 +315,7 @@ apmu@e6152000 { compatible = "renesas,r8a7791-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7792-blanche.dts b/arch/arm/boot/dts/r8a7792-blanche.dts index 9368ac2cf5082ff99d692c5c79ee1b44f6e7787e..c100ae903a46bb1c00f241d9efe729cbcc3e394c 100644 --- a/arch/arm/boot/dts/r8a7792-blanche.dts +++ b/arch/arm/boot/dts/r8a7792-blanche.dts @@ -334,7 +334,7 @@ }; &du { - pinctrl-0 = <&du0_pins &du1_pins>; + pinctrl-0 = <&du0_pins>, <&du1_pins>; pinctrl-names = "default"; clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&x1_clk>, <&x2_clk>; diff --git a/arch/arm/boot/dts/r8a7792-wheat.dts b/arch/arm/boot/dts/r8a7792-wheat.dts index ba2d2a58901261f6bf29f8eaf48324046be103de..434e4655be9daff78265280b8da0fef79c67bdcc 100644 --- a/arch/arm/boot/dts/r8a7792-wheat.dts +++ b/arch/arm/boot/dts/r8a7792-wheat.dts @@ -307,7 +307,7 @@ }; &du { - pinctrl-0 = <&du0_pins &du1_pins>; + pinctrl-0 = <&du0_pins>, <&du1_pins>; pinctrl-names = "default"; clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&osc2_clk>; diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi index f5b299bfcb23796cccc0f108ca888a0ece5eb95e..253e8bf643d1821d0caa67ab4dd684c14b48642b 100644 --- a/arch/arm/boot/dts/r8a7792.dtsi +++ b/arch/arm/boot/dts/r8a7792.dtsi @@ -314,7 +314,7 @@ apmu@e6152000 { compatible = "renesas,r8a7792-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts index abf487e8fe0f366fed09b3b4778a3afed6ebf19d..87fa57a99399b73d575103cfe670f2240a760a78 100644 --- a/arch/arm/boot/dts/r8a7793-gose.dts +++ b/arch/arm/boot/dts/r8a7793-gose.dts @@ -49,6 +49,9 @@ i2c10 = &gpioi2c4; i2c11 = &i2chdmi; i2c12 = &i2cexio4; + mmc0 = &sdhi0; + mmc1 = &sdhi1; + mmc2 = &sdhi2; }; chosen { @@ -576,7 +579,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; @@ -751,7 +754,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -761,8 +764,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi0 &src2 &dvc0>; - capture = <&ssi1 &src3 &dvc1>; + playback = <&ssi0>, <&src2>, <&dvc0>; + capture = <&ssi1>, <&src3>, <&dvc1>; }; }; }; diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi index f930f69f7bcce43abdcc6a8adeabb18f3cb1c901..6d74475030edfeb63e0666ec75d25afe68178282 100644 --- a/arch/arm/boot/dts/r8a7793.dtsi +++ b/arch/arm/boot/dts/r8a7793.dtsi @@ -290,7 +290,7 @@ apmu@e6152000 { compatible = "renesas,r8a7793-apmu", "renesas,apmu"; reg = <0 0xe6152000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts index 3f1cc5bbf32979e84dc4d5b2f8df8b258478c789..f9dba5688d3ffd18b623c3be04a7485e4ecc07f3 100644 --- a/arch/arm/boot/dts/r8a7794-alt.dts +++ b/arch/arm/boot/dts/r8a7794-alt.dts @@ -19,6 +19,9 @@ i2c10 = &gpioi2c4; i2c11 = &i2chdmi; i2c12 = &i2cexio4; + mmc0 = &mmcif0; + mmc1 = &sdhi0; + mmc2 = &sdhi1; }; chosen { @@ -330,7 +333,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts index 677596f6c9c9a7d9da31eb75254aed51e0baba04..eb89a27a6ed0c9aa1002d66c79dd4fa2b4dd35cc 100644 --- a/arch/arm/boot/dts/r8a7794-silk.dts +++ b/arch/arm/boot/dts/r8a7794-silk.dts @@ -31,6 +31,8 @@ serial0 = &scif2; i2c9 = &gpioi2c1; i2c10 = &i2chdmi; + mmc0 = &mmcif0; + mmc1 = &sdhi1; }; chosen { @@ -379,7 +381,7 @@ }; ðer { - pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-0 = <ðer_pins>, <&phy1_pins>; pinctrl-names = "default"; phy-handle = <&phy1>; @@ -518,7 +520,7 @@ }; &du { - pinctrl-0 = <&du0_pins &du1_pins>; + pinctrl-0 = <&du0_pins>, <&du1_pins>; pinctrl-names = "default"; status = "okay"; @@ -541,7 +543,7 @@ }; &rcar_sound { - pinctrl-0 = <&ssi_pins &audio_clk_pins>; + pinctrl-0 = <&ssi_pins>, <&audio_clk_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index cd5e2904068abd69321cdaf9e1c2f355ae7816f6..330dc516ecd151509d48548132c0583c207a91d3 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -256,7 +256,7 @@ apmu@e6151000 { compatible = "renesas,r8a7794-apmu", "renesas,apmu"; reg = <0 0xe6151000 0 0x188>; - cpus = <&cpu0 &cpu1>; + cpus = <&cpu0>, <&cpu1>; }; rst: reset-controller@e6160000 { diff --git a/arch/arm/boot/dts/rk3228-evb.dts b/arch/arm/boot/dts/rk3228-evb.dts index aed879db6c15211f9d5e0a420533b7b0ce87c852..69a5e239ed1ab165fb145ea9558bb8e7d79bb1c6 100644 --- a/arch/arm/boot/dts/rk3228-evb.dts +++ b/arch/arm/boot/dts/rk3228-evb.dts @@ -8,6 +8,10 @@ model = "Rockchip RK3228 Evaluation board"; compatible = "rockchip,rk3228-evb", "rockchip,rk3228"; + aliases { + mmc0 = &emmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x40000000>; diff --git a/arch/arm/boot/dts/rk3229-evb.dts b/arch/arm/boot/dts/rk3229-evb.dts index 350497a3ca8623d51252577c38994d40bf11851e..797476e8bef145009be06b43efea8cbe05abf3b7 100644 --- a/arch/arm/boot/dts/rk3229-evb.dts +++ b/arch/arm/boot/dts/rk3229-evb.dts @@ -9,6 +9,10 @@ model = "Rockchip RK3229 Evaluation board"; compatible = "rockchip,rk3229-evb", "rockchip,rk3229"; + aliases { + mmc0 = &emmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x40000000>; diff --git a/arch/arm/boot/dts/rk3229-xms6.dts b/arch/arm/boot/dts/rk3229-xms6.dts index 263393ac4fa635d5a950429263b2d457fe5ab07f..7bfbfd11fb55fd1a2bf012d61defe5ff7540b079 100644 --- a/arch/arm/boot/dts/rk3229-xms6.dts +++ b/arch/arm/boot/dts/rk3229-xms6.dts @@ -9,6 +9,12 @@ model = "Mecer Xtreme Mini S6"; compatible = "mecer,xms6", "rockchip,rk3229"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdio; + mmc2 = &emmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x40000000>; diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index a4dd50aaf3fc6423a526177c62cc11936ef46741..208f2124509536e14aabb15932f5b262f48b55ba 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -14,9 +14,6 @@ interrupt-parent = <&gic>; aliases { - mmc0 = &sdmmc; - mmc1 = &sdio; - mmc2 = &emmc; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -370,7 +367,7 @@ }; wdt: watchdog@110a0000 { - compatible = "snps,dw-wdt"; + compatible = "rockchip,rk3228-wdt", "snps,dw-wdt"; reg = <0x110a0000 0x100>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru PCLK_CPU>; diff --git a/arch/arm/boot/dts/rv1108-elgin-r1.dts b/arch/arm/boot/dts/rv1108-elgin-r1.dts index b1db924710c80e1dcdd1d20f33fc5fcb0f0e1d8d..f62c9f7af79db923324bcfedce1acebca8f994c9 100644 --- a/arch/arm/boot/dts/rv1108-elgin-r1.dts +++ b/arch/arm/boot/dts/rv1108-elgin-r1.dts @@ -12,6 +12,10 @@ model = "Elgin RV1108 R1 board"; compatible = "elgin,rv1108-r1", "rockchip,rv1108"; + aliases { + mmc0 = &emmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x08000000>; diff --git a/arch/arm/boot/dts/rv1108-evb.dts b/arch/arm/boot/dts/rv1108-evb.dts index 30f3d0470ad9805e6a3b61082cfcc1be83edfc2b..fe5fc9bf75c9980d769806a8ed2f3b0d3f0507de 100644 --- a/arch/arm/boot/dts/rv1108-evb.dts +++ b/arch/arm/boot/dts/rv1108-evb.dts @@ -8,6 +8,10 @@ model = "Rockchip RV1108 Evaluation board"; compatible = "rockchip,rv1108-evb", "rockchip,rv1108"; + aliases { + mmc0 = &sdmmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x08000000>; diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi index 7319a2473b80f05da89e2576be1373e05d11c68b..884872ca5207f8e974e3bebe851c355c8f467314 100644 --- a/arch/arm/boot/dts/rv1108.dtsi +++ b/arch/arm/boot/dts/rv1108.dtsi @@ -19,9 +19,6 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; - mmc0 = &emmc; - mmc1 = &sdio; - mmc2 = &sdmmc; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -303,11 +300,10 @@ }; watchdog: watchdog@10360000 { - compatible = "snps,dw-wdt"; + compatible = "rockchip,rv1108-wdt", "snps,dw-wdt"; reg = <0x10360000 0x100>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru PCLK_WDT>; - clock-names = "pclk_wdt"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/s5pv210-fascinate4g.dts b/arch/arm/boot/dts/s5pv210-fascinate4g.dts index ca064359dd308d778c522c98c68c9b22b68bb8b4..b47d8300e536ed047551ff972b52ee4e64eae5bb 100644 --- a/arch/arm/boot/dts/s5pv210-fascinate4g.dts +++ b/arch/arm/boot/dts/s5pv210-fascinate4g.dts @@ -115,7 +115,7 @@ compatible = "maxim,max77836-battery"; interrupt-parent = <&gph3>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&fg_irq>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 2c4952427296efc6ba96428096a6cf71b59e455b..801969c113d64e13f5ad3a347e3b64dadaf656ba 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -40,7 +40,7 @@ interrupts = <2 IRQ_TYPE_LEVEL_HIGH 0>; }; - etb { + etb@740000 { compatible = "arm,coresight-etb10", "arm,primecell"; reg = <0x740000 0x1000>; @@ -56,9 +56,9 @@ }; }; - etm { + etm@73c000 { compatible = "arm,coresight-etm3x", "arm,primecell"; - reg = <0x73C000 0x1000>; + reg = <0x73c000 0x1000>; clocks = <&pmc PMC_TYPE_CORE PMC_MCK>; clock-names = "apb_pclk"; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 7c979652f330d2ed7733007058b77f8df70ebdf1..d1841bffe3c576a495fbaf9df6399b5a946129af 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -709,7 +709,7 @@ atmel,pins = <AT91_PIOD 5 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* PD5 periph A MCI0_DA4 with pullup, conflicts with TIOA0, PWMH2 */ AT91_PIOD 6 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* PD6 periph A MCI0_DA5 with pullup, conflicts with TIOB0, PWML2 */ - AT91_PIOD 7 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* PD7 periph A MCI0_DA6 with pullup, conlicts with TCLK0, PWMH3 */ + AT91_PIOD 7 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* PD7 periph A MCI0_DA6 with pullup, conflicts with TCLK0, PWMH3 */ AT91_PIOD 8 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>; /* PD8 periph A MCI0_DA7 with pullup, conflicts with PWML3 */ }; }; diff --git a/arch/arm/boot/dts/ste-ab8500.dtsi b/arch/arm/boot/dts/ste-ab8500.dtsi index 4fd09997a2b91674a4a92873882f7e62caa3d231..a16a00fb5fa5d86f4935d65319fa9af4cfa452fc 100644 --- a/arch/arm/boot/dts/ste-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-ab8500.dtsi @@ -317,8 +317,8 @@ // supplies to the display/camera ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2900000>; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; /* BUG: If turned off MMC will be affected. */ regulator-always-on; diff --git a/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi index e024520f4d476df5077bf38e83aa2b4074dcde12..8d59202cebd6fa799423d52e33336d56e1d86471 100644 --- a/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi +++ b/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi @@ -1,14 +1,89 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Device Tree for the TVK1281618 R2 UIB + * Device Tree for the TVK1281618 R2 user interface board (UIB) */ -#include "ste-href-tvk1281618.dtsi" +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/input/input.h> / { + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&prox_tvk_mode>, <&hall_tvk_mode>; + + button@139 { + /* Proximity sensor */ + gpios = <&gpio6 25 GPIO_ACTIVE_HIGH>; + linux,code = <11>; /* SW_FRONT_PROXIMITY */ + label = "SFH7741 Proximity Sensor"; + }; + button@145 { + /* Hall sensor */ + gpios = <&gpio4 17 GPIO_ACTIVE_HIGH>; + linux,code = <0>; /* SW_LID */ + label = "HED54XXU11 Hall Effect Sensor"; + }; + }; + soc { + i2c@80004000 { + tc35893@44 { + compatible = "toshiba,tc35893"; + reg = <0x44>; + interrupt-parent = <&gpio6>; + interrupts = <26 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&tc35893_tvk_mode>; + + interrupt-controller; + #interrupt-cells = <1>; + status = "disabled"; + + tc3589x_gpio { + compatible = "toshiba,tc3589x-gpio"; + interrupts = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + tc3589x_keypad { + compatible = "toshiba,tc3589x-keypad"; + interrupts = <6>; + debounce-delay-ms = <4>; + keypad,num-columns = <8>; + keypad,num-rows = <8>; + linux,no-autorepeat; + wakeup-source; + linux,keymap = <MATRIX_KEY(3, 1, KEY_END)>, + <MATRIX_KEY(4, 1, KEY_HOME)>, + <MATRIX_KEY(6, 4, KEY_VOLUMEDOWN)>, + <MATRIX_KEY(4, 2, KEY_EMAIL)>, + <MATRIX_KEY(3, 3, KEY_RIGHT)>, + <MATRIX_KEY(2, 5, KEY_BACKSPACE)>, + <MATRIX_KEY(6, 7, KEY_MENU)>, + <MATRIX_KEY(5, 0, KEY_ENTER)>, + <MATRIX_KEY(4, 3, KEY_0)>, + <MATRIX_KEY(3, 4, KEY_DOT)>, + <MATRIX_KEY(5, 2, KEY_UP)>, + <MATRIX_KEY(3, 5, KEY_DOWN)>, + <MATRIX_KEY(4, 5, KEY_SEND)>, + <MATRIX_KEY(0, 5, KEY_BACK)>, + <MATRIX_KEY(6, 2, KEY_VOLUMEUP)>, + <MATRIX_KEY(1, 3, KEY_SPACE)>, + <MATRIX_KEY(7, 6, KEY_LEFT)>, + <MATRIX_KEY(5, 5, KEY_SEARCH)>; + }; + }; + }; + i2c@80128000 { - lsm303dlh@18 { + accelerometer@18 { /* Accelerometer */ compatible = "st,lsm303dlh-accel"; st,drdy-int-pin = <1>; @@ -30,7 +105,7 @@ * <&gpio2 19 IRQ_TYPE_EDGE_FALLING>; */ }; - lsm303dlh@1e { + magnetometer@1e { /* Magnetometer */ compatible = "st,lsm303dlh-magn"; reg = <0x1e>; @@ -48,7 +123,7 @@ * <&gpio2 19 IRQ_TYPE_EDGE_FALLING>; */ }; - lis331dl@1c { + accelerometer@1c { /* Accelerometer */ compatible = "st,lis331dl-accel"; st,drdy-int-pin = <1>; @@ -62,6 +137,72 @@ interrupts = <18 IRQ_TYPE_EDGE_RISING>, <19 IRQ_TYPE_EDGE_RISING>; }; + magnetometer@f { + /* Magnetometer */ + compatible = "asahi-kasei,ak8974"; + reg = <0x0f>; + avdd-supply = <&ab8500_ldo_aux1_reg>; + dvdd-supply = <&db8500_vsmps2_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&gyro_magn_tvk_mode>; + /* + * These interrupts cannot be used: the other component + * ST-Micro L3D4200D gyro that is connected to the same lines + * cannot set its DRDY line to open drain, so it cannot be + * shared with other peripherals. The should be defined for + * the falling edge if they could be wired together. + * + * interrupts-extended = + * <&gpio1 0 IRQ_TYPE_EDGE_FALLING>, + * <&gpio0 31 IRQ_TYPE_EDGE_FALLING>; + */ + }; + gyroscope@68 { + /* Gyroscope */ + compatible = "st,l3g4200d-gyro"; + st,drdy-int-pin = <2>; + reg = <0x68>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + vddio-supply = <&db8500_vsmps2_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&gyro_magn_tvk_mode>; + interrupts-extended = + <&gpio1 0 IRQ_TYPE_EDGE_RISING>, + <&gpio0 31 IRQ_TYPE_EDGE_RISING>; + }; + pressure@5c { + /* Barometer/pressure sensor */ + compatible = "st,lps001wp-press"; + reg = <0x5c>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + vddio-supply = <&db8500_vsmps2_reg>; + }; + }; + i2c@80110000 { + synaptics@4b { + /* Synaptics RMI4 TM1217 touchscreen */ + compatible = "syna,rmi4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4b>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + vddio-supply = <&db8500_vsmps2_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&synaptics_tvk_mode>; + interrupt-parent = <&gpio2>; + interrupts = <20 IRQ_TYPE_EDGE_FALLING>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep = <1>; + }; + rmi4-f11@11 { + reg = <0x11>; + syna,sensor-type = <1>; + /* This is a landscape display */ + touchscreen-swapped-x-y; + }; + }; }; mcde@a0350000 { status = "okay"; @@ -75,5 +216,68 @@ }; }; }; + pinctrl { + prox { + prox_tvk_mode: prox_tvk { + tvk_cfg { + pins = "GPIO217_AH12"; + ste,config = <&gpio_in_pu>; + }; + }; + }; + hall { + hall_tvk_mode: hall_tvk { + tvk_cfg { + pins = "GPIO145_C13"; + ste,config = <&gpio_in_pu>; + }; + }; + }; + tc35893 { + /* IRQ from the TC35893 */ + tc35893_tvk_mode: tc35893_tvk { + tvk_cfg { + pins = "GPIO218_AH11"; + ste,config = <&gpio_in_pu>; + }; + }; + }; + accelerometer { + accel_tvk_mode: accel_tvk { + /* Accelerometer interrupt lines 1 & 2 */ + tvk_cfg { + pins = "GPIO82_C1", "GPIO83_D3"; + ste,config = <&gpio_in_pd>; + }; + }; + }; + gyroscope { + /* + * These lines are shared between Gyroscope l3g400dh + * and AK8974 magnetometer. + */ + gyro_magn_tvk_mode: gyro_magn_tvk { + /* GPIO 31 used for INT pull down the line */ + tvk_cfg1 { + pins = "GPIO31_V3"; + ste,config = <&gpio_in_pd>; + }; + /* GPIO 32 used for DRDY, pull this down */ + tvk_cfg2 { + pins = "GPIO32_V2"; + ste,config = <&gpio_in_pd>; + }; + }; + }; + synaptics { + synaptics_tvk_mode: synaptics_tvk { + /* Touchscreen uses GPIO 84 */ + tvk_cfg1 { + pins = "GPIO84_C2"; + ste,config = <&gpio_in_pu>; + }; + }; + }; + }; }; }; diff --git a/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi index cb3677f0a1cbb65bab8af0d51d8b3b824d5c7972..70f058352efcae16ee359d604e7c0748404d8bfd 100644 --- a/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi +++ b/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi @@ -1,44 +1,152 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Device Tree for the TVK1281618 R2 UIB + * Device Tree for the TVK1281618 R3 user interface board (UIB) + * also known as the "CYTTSP board" */ -#include "ste-href-tvk1281618.dtsi" +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/input/input.h> / { + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&hall_tvk_mode>; + + button@145 { + /* Hall sensor */ + gpios = <&gpio4 17 GPIO_ACTIVE_HIGH>; + linux,code = <0>; /* SW_LID */ + label = "HED54XXU11 Hall Effect Sensor"; + }; + }; + soc { - i2c@80128000 { - /* Marked: - * 129 - * M35 - * L3GD20 - */ - l3gd20@6a { - /* Gyroscope */ - compatible = "st,l3gd20"; + i2c@80004000 { + tc35893@44 { + compatible = "toshiba,tc35893"; + reg = <0x44>; + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&tc35893_tvk_mode>; + + interrupt-controller; + #interrupt-cells = <1>; status = "disabled"; + + tc3589x_gpio { + compatible = "toshiba,tc3589x-gpio"; + interrupts = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + tc3589x_keypad { + compatible = "toshiba,tc3589x-keypad"; + interrupts = <6>; + debounce-delay-ms = <4>; + keypad,num-columns = <8>; + keypad,num-rows = <8>; + linux,no-autorepeat; + wakeup-source; + linux,keymap = <MATRIX_KEY(3, 1, KEY_END)>, + <MATRIX_KEY(4, 1, KEY_HOME)>, + <MATRIX_KEY(6, 4, KEY_VOLUMEDOWN)>, + <MATRIX_KEY(4, 2, KEY_EMAIL)>, + <MATRIX_KEY(3, 3, KEY_RIGHT)>, + <MATRIX_KEY(2, 5, KEY_BACKSPACE)>, + <MATRIX_KEY(6, 7, KEY_MENU)>, + <MATRIX_KEY(5, 0, KEY_ENTER)>, + <MATRIX_KEY(4, 3, KEY_0)>, + <MATRIX_KEY(3, 4, KEY_DOT)>, + <MATRIX_KEY(5, 2, KEY_UP)>, + <MATRIX_KEY(3, 5, KEY_DOWN)>, + <MATRIX_KEY(4, 5, KEY_SEND)>, + <MATRIX_KEY(0, 5, KEY_BACK)>, + <MATRIX_KEY(6, 2, KEY_VOLUMEUP)>, + <MATRIX_KEY(1, 3, KEY_SPACE)>, + <MATRIX_KEY(7, 6, KEY_LEFT)>, + <MATRIX_KEY(5, 5, KEY_SEARCH)>; + }; + }; + }; + + i2c@80128000 { + accelerometer@19 { + compatible = "st,lsm303dlhc-accel"; st,drdy-int-pin = <1>; - drive-open-drain; - reg = <0x6a>; // 0x6a or 0x6b + reg = <0x19>; vdd-supply = <&ab8500_ldo_aux1_reg>; vddio-supply = <&db8500_vsmps2_reg>; + interrupt-parent = <&gpio2>; + interrupts = <18 IRQ_TYPE_EDGE_RISING>, + <19 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&accel_tvk_mode>; }; - /* - * Marked: - * 2122 - * C3H - * DQEEE - * LIS3DH? - */ - lis3dh@18 { - /* Accelerometer */ - compatible = "st,lis3dh-accel"; + magnetometer@1e { + compatible = "st,lsm303dlm-magn"; st,drdy-int-pin = <1>; - reg = <0x18>; + reg = <0x1e>; vdd-supply = <&ab8500_ldo_aux1_reg>; vddio-supply = <&db8500_vsmps2_reg>; + // This interrupt is not properly working with the driver + // interrupt-parent = <&gpio1>; + // interrupts = <0 IRQ_TYPE_EDGE_RISING>; pinctrl-names = "default"; - pinctrl-0 = <&accel_tvk_mode>; + pinctrl-0 = <&magn_tvk_mode>; + }; + gyroscope@68 { + /* Gyroscope */ + compatible = "st,l3g4200d-gyro"; + reg = <0x68>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + vddio-supply = <&db8500_vsmps2_reg>; + }; + pressure@5c { + /* Barometer/pressure sensor */ + compatible = "st,lps001wp-press"; + reg = <0x5c>; + vdd-supply = <&ab8500_ldo_aux1_reg>; + vddio-supply = <&db8500_vsmps2_reg>; + }; + }; + + spi@80111000 { + num-cs = <1>; + cs-gpios = <&gpio6 24 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2_default_mode>; + status = "okay"; + + touchscreen@0 { + compatible = "cypress,cy8ctma340"; + /* + * Actually the max frequency is 6 MHz, but over 2 MHz the + * data rate needs to be restricted to max 2Mbps which the + * SPI framework cannot handle. + */ + spi-max-frequency = <2000000>; + reg = <0>; + interrupt-parent = <&gpio2>; + interrupts = <20 IRQ_TYPE_EDGE_FALLING>; + vcpin-supply = <&ab8500_ldo_aux1_reg>; + vdd-supply = <&db8500_vsmps2_reg>; + reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <480>; + touchscreen-size-y = <854>; + active-interval-ms = <0>; + touch-timeout-ms = <255>; + lowpower-interval-ms = <10>; + bootloader-key = /bits/ 8 <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07>; + pinctrl-names = "default"; + pinctrl-0 = <&cyttsp_tvk_mode>; }; }; @@ -54,5 +162,57 @@ }; }; }; + + pinctrl { + hall { + hall_tvk_mode: hall_tvk { + tvk_cfg { + pins = "GPIO145_C13"; + ste,config = <&gpio_in_pu>; + }; + }; + }; + tc35893 { + /* IRQ from the TC35893 */ + tc35893_tvk_mode: tc35893_tvk { + tvk_cfg { + pins = "GPIO64_F3"; + ste,config = <&gpio_in_pu>; + }; + }; + }; + accelerometer { + accel_tvk_mode: accel_tvk { + /* Accelerometer interrupt lines 1 & 2 */ + tvk_cfg { + pins = "GPIO82_C1", "GPIO83_D3"; + ste,config = <&gpio_in_pd>; + }; + }; + }; + magnetometer { + magn_tvk_mode: magn_tvk { + /* GPIO 32 used for DRDY, pull this down */ + tvk_cfg { + pins = "GPIO32_V2"; + ste,config = <&gpio_in_pd>; + }; + }; + }; + cyttsp { + cyttsp_tvk_mode: cyttsp_tvk { + /* Touchscreen uses GPIO84 for IRQ */ + tvk_cfg1 { + pins = "GPIO84_C2"; + ste,config = <&gpio_in_pu>; + }; + /* GPIO143 is reset */ + tvk_cfg2 { + pins = "GPIO143_D12"; + ste,config = <&gpio_out_hi>; + }; + }; + }; + }; }; }; diff --git a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi deleted file mode 100644 index e1dbfae225956220f2a5bd896e37f42f7f0f90b8..0000000000000000000000000000000000000000 --- a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi +++ /dev/null @@ -1,218 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2012 ST-Ericsson AB - * - * Device Tree for the TVK1281618 family of UIBs - */ - -#include <dt-bindings/interrupt-controller/irq.h> - -/ { - gpio_keys { - compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; - vdd-supply = <&ab8500_ldo_aux1_reg>; - pinctrl-names = "default"; - pinctrl-0 = <&prox_tvk_mode>, <&hall_tvk_mode>; - - button@139 { - /* Proximity sensor */ - gpios = <&gpio6 25 GPIO_ACTIVE_HIGH>; - linux,code = <11>; /* SW_FRONT_PROXIMITY */ - label = "SFH7741 Proximity Sensor"; - }; - button@145 { - /* Hall sensor */ - gpios = <&gpio4 17 GPIO_ACTIVE_HIGH>; - linux,code = <0>; /* SW_LID */ - label = "HED54XXU11 Hall Effect Sensor"; - }; - }; - - soc { - i2c@80004000 { - tc35893@44 { - compatible = "toshiba,tc35893"; - reg = <0x44>; - interrupt-parent = <&gpio6>; - interrupts = <26 IRQ_TYPE_EDGE_RISING>; - pinctrl-names = "default"; - pinctrl-0 = <&tc35893_tvk_mode>; - - interrupt-controller; - #interrupt-cells = <1>; - - tc3589x_gpio { - compatible = "toshiba,tc3589x-gpio"; - interrupts = <0>; - - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - #gpio-cells = <2>; - }; - tc3589x_keypad { - compatible = "toshiba,tc3589x-keypad"; - interrupts = <6>; - debounce-delay-ms = <4>; - keypad,num-columns = <8>; - keypad,num-rows = <8>; - linux,no-autorepeat; - wakeup-source; - linux,keymap = <0x0301006b - 0x04010066 - 0x06040072 - 0x040200d7 - 0x0303006a - 0x0205000e - 0x0607008b - 0x0500001c - 0x0403000b - 0x03040034 - 0x05020067 - 0x0305006c - 0x040500e7 - 0x0005009e - 0x06020073 - 0x01030039 - 0x07060069 - 0x050500d9>; - }; - }; - }; - /* Sensors mounted on all board variants */ - i2c@80128000 { - ak8974@f { - /* Magnetometer */ - compatible = "asahi-kasei,ak8974"; - reg = <0x0f>; - avdd-supply = <&ab8500_ldo_aux1_reg>; - dvdd-supply = <&db8500_vsmps2_reg>; - pinctrl-names = "default"; - pinctrl-0 = <&gyro_magn_tvk_mode>; - /* - * These interrupts cannot be used: the other component - * ST-Micro L3D4200D gyro that is connected to the same lines - * cannot set its DRDY line to open drain, so it cannot be - * shared with other peripherals. The should be defined for - * the falling edge if they could be wired together. - * - * interrupts-extended = - * <&gpio1 0 IRQ_TYPE_EDGE_FALLING>, - * <&gpio0 31 IRQ_TYPE_EDGE_FALLING>; - */ - }; - l3g4200d@68 { - /* Gyroscope */ - compatible = "st,l3g4200d-gyro"; - st,drdy-int-pin = <2>; - reg = <0x68>; - vdd-supply = <&ab8500_ldo_aux1_reg>; - vddio-supply = <&db8500_vsmps2_reg>; - pinctrl-names = "default"; - pinctrl-0 = <&gyro_magn_tvk_mode>; - interrupts-extended = - <&gpio1 0 IRQ_TYPE_EDGE_RISING>, - <&gpio0 31 IRQ_TYPE_EDGE_RISING>; - }; - lsp001wm@5c { - /* Barometer/pressure sensor */ - compatible = "st,lps001wp-press"; - reg = <0x5c>; - vdd-supply = <&ab8500_ldo_aux1_reg>; - vddio-supply = <&db8500_vsmps2_reg>; - }; - }; - - i2c@80110000 { - synaptics@4b { - /* Synaptics RMI4 TM1217 touchscreen */ - compatible = "syna,rmi4-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x4b>; - vdd-supply = <&ab8500_ldo_aux1_reg>; - vddio-supply = <&db8500_vsmps2_reg>; - pinctrl-names = "default"; - pinctrl-0 = <&synaptics_tvk_mode>; - interrupt-parent = <&gpio2>; - interrupts = <20 IRQ_TYPE_EDGE_FALLING>; - - rmi-f01@1 { - reg = <0x1>; - syna,nosleep = <1>; - }; - rmi-f11@11 { - reg = <0x11>; - touchscreen-inverted-x; - syna,sensor-type = <1>; - }; - }; - }; - - pinctrl { - /* Pull up this GPIO pin */ - tc35893 { - tc35893_tvk_mode: tc35893_tvk { - tvk_cfg { - pins = "GPIO218_AH11"; - ste,config = <&gpio_in_pu>; - }; - }; - }; - prox { - prox_tvk_mode: prox_tvk { - tvk_cfg { - pins = "GPIO217_AH12"; - ste,config = <&gpio_in_pu>; - }; - }; - }; - hall { - hall_tvk_mode: hall_tvk { - tvk_cfg { - pins = "GPIO145_C13"; - ste,config = <&gpio_in_pu>; - }; - }; - }; - accelerometer { - accel_tvk_mode: accel_tvk { - /* Accelerometer interrupt lines 1 & 2 */ - tvk_cfg { - pins = "GPIO82_C1", "GPIO83_D3"; - ste,config = <&gpio_in_pd>; - }; - }; - }; - gyroscope { - /* - * These lines are shared between Gyroscope l3g400dh - * and AK8974 magnetometer. - */ - gyro_magn_tvk_mode: gyro_magn_tvk { - /* GPIO 31 used for INT pull down the line */ - tvk_cfg1 { - pins = "GPIO31_V3"; - ste,config = <&gpio_in_pd>; - }; - /* GPIO 32 used for DRDY, pull this down */ - tvk_cfg2 { - pins = "GPIO32_V2"; - ste,config = <&gpio_in_pd>; - }; - }; - }; - synaptics { - synaptics_tvk_mode: synaptics_tvk { - /* Touchscreen uses GPIO 84 */ - tvk_cfg1 { - pins = "GPIO84_C2"; - ste,config = <&gpio_in_pu>; - }; - }; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/ste-href520-tvk.dts b/arch/arm/boot/dts/ste-href520-tvk.dts index a036a03f67187eabf8318acd53de12b7cd529127..4201547c598893be3e84ddbb7bfffdb5ac316ad3 100644 --- a/arch/arm/boot/dts/ste-href520-tvk.dts +++ b/arch/arm/boot/dts/ste-href520-tvk.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Device Tree for the HREF520 version with the TVK1281618 UIB + * Device Tree for the HREF520 version with the TVK1281618 R3 UIB */ /dts-v1/; @@ -9,7 +9,7 @@ #include "ste-href-tvk1281618-r3.dtsi" / { - model = "ST-Ericsson HREF520 and TVK1281618 UIB"; + model = "ST-Ericsson HREF520 and TVK1281618 R3 UIB"; compatible = "st-ericsson,href520", "st-ericsson,u8500"; diff --git a/arch/arm/boot/dts/ste-hrefprev60-tvk.dts b/arch/arm/boot/dts/ste-hrefprev60-tvk.dts index 4e6e4439dcffc26920464b417db16a2ec49cde91..75506339a93cd8dca073fad8603b8b8c429636fb 100644 --- a/arch/arm/boot/dts/ste-hrefprev60-tvk.dts +++ b/arch/arm/boot/dts/ste-hrefprev60-tvk.dts @@ -9,7 +9,7 @@ #include "ste-href-tvk1281618-r2.dtsi" / { - model = "ST-Ericsson HREF (pre-v60) and TVK1281618 UIB"; + model = "ST-Ericsson HREF (pre-v60) and TVK1281618 R2 UIB"; compatible = "st-ericsson,mop500", "st-ericsson,u8500"; /* ST6G3244ME level translator for 1.8/2.9 V */ diff --git a/arch/arm/boot/dts/ste-hrefv60plus-tvk.dts b/arch/arm/boot/dts/ste-hrefv60plus-tvk.dts index 9c2d2ee6d6d8d3699d91fd745b184a25153ab79b..2db2f8be8b036531396142353821a093b51a0e67 100644 --- a/arch/arm/boot/dts/ste-hrefv60plus-tvk.dts +++ b/arch/arm/boot/dts/ste-hrefv60plus-tvk.dts @@ -2,7 +2,7 @@ /* * Copyright 2012 ST-Ericsson AB * - * Device Tree for the HREF version 60 or later with the TVK1281618 UIB + * Device Tree for the HREF version 60 or later with the TVK1281618 R2 UIB */ /dts-v1/; @@ -11,7 +11,7 @@ #include "ste-href-tvk1281618-r2.dtsi" / { - model = "ST-Ericsson HREF (v60+) and TVK1281618 UIB"; + model = "ST-Ericsson HREF (v60+) and TVK1281618 R2 UIB"; compatible = "st-ericsson,hrefv60+", "st-ericsson,u8500"; /* ST6G3244ME level translator for 1.8/2.9 V */ diff --git a/arch/arm/boot/dts/ste-ux500-samsung-janice.dts b/arch/arm/boot/dts/ste-ux500-samsung-janice.dts index 7411bfeda285d0eedcc3c3ebccc7cab4894294e0..f24369873ce2cee0e3fb3cc110118f6674bfe0d5 100644 --- a/arch/arm/boot/dts/ste-ux500-samsung-janice.dts +++ b/arch/arm/boot/dts/ste-ux500-samsung-janice.dts @@ -135,21 +135,22 @@ /* * This regulator is a GPIO line that drives the Broadcom WLAN - * line BT_VREG_EN high and enables the internal regulators - * inside the chip. + * line WL_REG_ON high and enables the internal regulators + * inside the chip. Unfortunatley it is erroneously named + * WLAN_RST_N on the schematic but it is not a reset line. * * The voltage specified here is only used to determine the OCR mask, * the for the SDIO connector, the chip is actually connected * directly to VBAT. */ - wl_bt_reg: regulator-gpio-wlan { + wl_reg: regulator-gpio-wlan { compatible = "regulator-fixed"; - regulator-name = "BT_VREG_EN"; + regulator-name = "WL_REG_ON"; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; startup-delay-us = <100000>; - /* GPIO222 (BT_VREG_EN) */ - gpio = <&gpio6 30 GPIO_ACTIVE_HIGH>; + /* GPIO215 (WLAN_RST_N to WL_REG_ON) */ + gpio = <&gpio6 23 GPIO_ACTIVE_HIGH>; enable-active-high; pinctrl-names = "default"; pinctrl-0 = <&wlan_ldo_en_default>; @@ -390,11 +391,10 @@ pinctrl-1 = <&mc1_a_2_sleep>; /* * GPIO-controlled voltage enablement: this drives - * the BT_VREG_EN line high when we use this device. - * Represented as regulator to fill OCR mask and to - * be usable in parallel with the Bluetooth chip. + * the WL_REG_ON line high when we use this device. + * Represented as regulator to fill OCR mask. */ - vmmc-supply = <&wl_bt_reg>; + vmmc-supply = <&wl_reg>; #address-cells = <1>; #size-cells = <0>; @@ -408,9 +408,6 @@ interrupt-parent = <&gpio6>; interrupts = <24 IRQ_TYPE_EDGE_FALLING>; interrupt-names = "host-wake"; - /* GPIO215 WLAN_RST_N */ - /* FIXME: kernel does not use this assert/deassert */ - reset-gpios = <&gpio6 23 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&wlan_default_mode>; }; @@ -440,15 +437,8 @@ bluetooth { compatible = "brcm,bcm4330-bt"; - /* - * We actually have shutdown-gpios, BT_VREG_EN on GPIO222, - * but since this GPIO is shared with the WLAN chip, we need - * to reference the regulator instead. The regulator - * framework will reference count the GPIO usage and - * make sure we can use the same GPIO for several supplies. - */ - // shutdown-gpios = <&gpio6 30 GPIO_ACTIVE_HIGH>; - vbat-supply = <&wl_bt_reg>; + /* GPIO222 rail BT_VREG_EN to BT_REG_ON */ + shutdown-gpios = <&gpio6 30 GPIO_ACTIVE_HIGH>; /* BT_WAKE on GPIO199 */ device-wakeup-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>; /* BT_HOST_WAKE on GPIO97 */ @@ -759,9 +749,9 @@ /* GPIO that enables the WLAN internal LDO regulators */ wlan-ldo { wlan_ldo_en_default: wlan_ldo_default { - /* GPIO222 BT_VREG_ON */ + /* GPIO215 named WLAN_RST_N */ janice_cfg1 { - pins = "GPIO222_AJ9"; + pins = "GPIO215_AH13"; ste,config = <&gpio_out_lo>; }; }; @@ -875,11 +865,6 @@ }; wlan { wlan_default_mode: wlan_default { - /* GPIO215 used for RESET_N */ - janice_cfg1 { - pins = "GPIO215_AH13"; - ste,config = <&gpio_out_lo>; - }; /* GPIO216 for WL_HOST_WAKE */ janice_cfg2 { pins = "GPIO216_AG12"; @@ -889,14 +874,17 @@ }; bluetooth { bluetooth_default_mode: bluetooth_default { + /* GPIO199 BT_WAKE and GPIO222 BT_VREG_ON */ janice_cfg1 { - pins = "GPIO199_AH23"; + pins = "GPIO199_AH23", "GPIO222_AJ9"; ste,config = <&gpio_out_lo>; }; + /* GPIO97 BT_HOST_WAKE */ janice_cfg2 { pins = "GPIO97_D9"; ste,config = <&gpio_in_nopull>; }; + /* GPIO209 BT_RST_N */ janice_cfg3 { pins = "GPIO209_AG15"; ste,config = <&gpio_out_hi>; diff --git a/arch/arm/boot/dts/stm32h7-pinctrl.dtsi b/arch/arm/boot/dts/stm32h7-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..aa1bc3e10a49deaeb688d4705a3b2c67ba3f49fb --- /dev/null +++ b/arch/arm/boot/dts/stm32h7-pinctrl.dtsi @@ -0,0 +1,275 @@ +/* + * Copyright 2017 - Alexandre Torgue <alexandre.torgue@st.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) 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 AUTHORS OR COPYRIGHT + * HOLDERS 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 <dt-bindings/pinctrl/stm32-pinfunc.h> + +&pinctrl { + + i2c1_pins_a: i2c1-0 { + pins { + pinmux = <STM32_PINMUX('B', 6, AF4)>, /* I2C1_SCL */ + <STM32_PINMUX('B', 7, AF4)>; /* I2C1_SDA */ + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + + ethernet_rmii: rmii-0 { + pins { + pinmux = <STM32_PINMUX('G', 11, AF11)>, + <STM32_PINMUX('G', 13, AF11)>, + <STM32_PINMUX('G', 12, AF11)>, + <STM32_PINMUX('C', 4, AF11)>, + <STM32_PINMUX('C', 5, AF11)>, + <STM32_PINMUX('A', 7, AF11)>, + <STM32_PINMUX('C', 1, AF11)>, + <STM32_PINMUX('A', 2, AF11)>, + <STM32_PINMUX('A', 1, AF11)>; + slew-rate = <2>; + }; + }; + + sdmmc1_b4_pins_a: sdmmc1-b4-0 { + pins { + pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */ + <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */ + <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */ + <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */ + <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */ + <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */ + slew-rate = <3>; + drive-push-pull; + bias-disable; + }; + }; + + sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 { + pins1 { + pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */ + <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */ + <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */ + <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */ + <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */ + slew-rate = <3>; + drive-push-pull; + bias-disable; + }; + pins2{ + pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */ + slew-rate = <3>; + drive-open-drain; + bias-disable; + }; + }; + + sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { + pins { + pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */ + <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */ + <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */ + <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */ + <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */ + <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */ + }; + }; + + sdmmc1_dir_pins_a: sdmmc1-dir-0 { + pins1 { + pinmux = <STM32_PINMUX('C', 6, AF8)>, /* SDMMC1_D0DIR */ + <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */ + <STM32_PINMUX('B', 9, AF7)>; /* SDMMC1_CDIR */ + slew-rate = <3>; + drive-push-pull; + bias-pull-up; + }; + pins2{ + pinmux = <STM32_PINMUX('B', 8, AF7)>; /* SDMMC1_CKIN */ + bias-pull-up; + }; + }; + + sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 { + pins { + pinmux = <STM32_PINMUX('C', 6, ANALOG)>, /* SDMMC1_D0DIR */ + <STM32_PINMUX('C', 7, ANALOG)>, /* SDMMC1_D123DIR */ + <STM32_PINMUX('B', 9, ANALOG)>, /* SDMMC1_CDIR */ + <STM32_PINMUX('B', 8, ANALOG)>; /* SDMMC1_CKIN */ + }; + }; + + sdmmc2_b4_pins_a: sdmmc2-b4-0 { + pins { + pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC1_D0 */ + <STM32_PINMUX('B', 15, AF9)>, /* SDMMC1_D1 */ + <STM32_PINMUX('B', 3, AF9)>, /* SDMMC1_D2 */ + <STM32_PINMUX('B', 4, AF9)>, /* SDMMC1_D3 */ + <STM32_PINMUX('D', 6, AF11)>, /* SDMMC1_CK */ + <STM32_PINMUX('D', 7, AF11)>; /* SDMMC1_CMD */ + slew-rate = <3>; + drive-push-pull; + bias-disable; + }; + }; + + sdmmc2_b4_od_pins_a: sdmmc2-b4-od-0 { + pins1 { + pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */ + <STM32_PINMUX('B', 15, AF9)>, /* SDMMC1_D1 */ + <STM32_PINMUX('B', 3, AF9)>, /* SDMMC1_D2 */ + <STM32_PINMUX('B', 4, AF9)>, /* SDMMC1_D3 */ + <STM32_PINMUX('D', 6, AF11)>; /* SDMMC1_CK */ + slew-rate = <3>; + drive-push-pull; + bias-disable; + }; + pins2{ + pinmux = <STM32_PINMUX('D', 7, AF11)>; /* SDMMC1_CMD */ + slew-rate = <3>; + drive-open-drain; + bias-disable; + }; + }; + + sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 { + pins { + pinmux = <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC1_D0 */ + <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC1_D1 */ + <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC1_D2 */ + <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC1_D3 */ + <STM32_PINMUX('D', 6, ANALOG)>, /* SDMMC1_CK */ + <STM32_PINMUX('D', 7, ANALOG)>; /* SDMMC1_CMD */ + }; + }; + + spi1_pins: spi1-0 { + pins1 { + pinmux = <STM32_PINMUX('A', 5, AF5)>, + /* SPI1_CLK */ + <STM32_PINMUX('B', 5, AF5)>; + /* SPI1_MOSI */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + pins2 { + pinmux = <STM32_PINMUX('G', 9, AF5)>; + /* SPI1_MISO */ + bias-disable; + }; + }; + + uart4_pins: uart4-0 { + pins1 { + pinmux = <STM32_PINMUX('A', 0, AF8)>; /* UART4_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = <STM32_PINMUX('I', 9, AF8)>; /* UART4_RX */ + bias-disable; + }; + }; + + usart1_pins: usart1-0 { + pins1 { + pinmux = <STM32_PINMUX('B', 14, AF4)>; /* USART1_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = <STM32_PINMUX('B', 15, AF4)>; /* USART1_RX */ + bias-disable; + }; + }; + + usart2_pins: usart2-0 { + pins1 { + pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */ + bias-disable; + }; + }; + + usart3_pins: usart3-0 { + pins1 { + pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */ + <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS_DE */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = <STM32_PINMUX('B', 11, AF7)>, /* USART3_RX */ + <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS_NSS */ + bias-disable; + }; + }; + + usbotg_hs_pins_a: usbotg-hs-0 { + pins { + pinmux = <STM32_PINMUX('H', 4, AF10)>, /* ULPI_NXT */ + <STM32_PINMUX('I', 11, AF10)>, /* ULPI_DIR> */ + <STM32_PINMUX('C', 0, AF10)>, /* ULPI_STP> */ + <STM32_PINMUX('A', 5, AF10)>, /* ULPI_CK> */ + <STM32_PINMUX('A', 3, AF10)>, /* ULPI_D0> */ + <STM32_PINMUX('B', 0, AF10)>, /* ULPI_D1> */ + <STM32_PINMUX('B', 1, AF10)>, /* ULPI_D2> */ + <STM32_PINMUX('B', 10, AF10)>, /* ULPI_D3> */ + <STM32_PINMUX('B', 11, AF10)>, /* ULPI_D4> */ + <STM32_PINMUX('B', 12, AF10)>, /* ULPI_D5> */ + <STM32_PINMUX('B', 13, AF10)>, /* ULPI_D6> */ + <STM32_PINMUX('B', 5, AF10)>; /* ULPI_D7> */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; +}; + diff --git a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi deleted file mode 100644 index fa5dcb6a5fddfc5edeb59ad817b9f2c203c58bee..0000000000000000000000000000000000000000 --- a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2017 - Alexandre Torgue <alexandre.torgue@st.com> - * - * This file is dual-licensed: you can use it either under the terms - * of the GPL or the X11 license, at your option. Note that this dual - * licensing only applies to this file, and not this project as a - * whole. - * - * a) This file 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 file 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. - * - * Or, alternatively, - * - * b) 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 AUTHORS OR COPYRIGHT - * HOLDERS 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 <dt-bindings/pinctrl/stm32-pinfunc.h> - -/ { - soc { - pin-controller { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,stm32h743-pinctrl"; - ranges = <0 0x58020000 0x3000>; - interrupt-parent = <&exti>; - st,syscfg = <&syscfg 0x8>; - pins-are-numbered; - - gpioa: gpio@58020000 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x0 0x400>; - clocks = <&rcc GPIOA_CK>; - st,bank-name = "GPIOA"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpiob: gpio@58020400 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x400 0x400>; - clocks = <&rcc GPIOB_CK>; - st,bank-name = "GPIOB"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpioc: gpio@58020800 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x800 0x400>; - clocks = <&rcc GPIOC_CK>; - st,bank-name = "GPIOC"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpiod: gpio@58020c00 { - gpio-controller; - #gpio-cells = <2>; - reg = <0xc00 0x400>; - clocks = <&rcc GPIOD_CK>; - st,bank-name = "GPIOD"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpioe: gpio@58021000 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x1000 0x400>; - clocks = <&rcc GPIOE_CK>; - st,bank-name = "GPIOE"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpiof: gpio@58021400 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x1400 0x400>; - clocks = <&rcc GPIOF_CK>; - st,bank-name = "GPIOF"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpiog: gpio@58021800 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x1800 0x400>; - clocks = <&rcc GPIOG_CK>; - st,bank-name = "GPIOG"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpioh: gpio@58021c00 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x1c00 0x400>; - clocks = <&rcc GPIOH_CK>; - st,bank-name = "GPIOH"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpioi: gpio@58022000 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x2000 0x400>; - clocks = <&rcc GPIOI_CK>; - st,bank-name = "GPIOI"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpioj: gpio@58022400 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x2400 0x400>; - clocks = <&rcc GPIOJ_CK>; - st,bank-name = "GPIOJ"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpiok: gpio@58022800 { - gpio-controller; - #gpio-cells = <2>; - reg = <0x2800 0x400>; - clocks = <&rcc GPIOK_CK>; - st,bank-name = "GPIOK"; - interrupt-controller; - #interrupt-cells = <2>; - }; - - i2c1_pins_a: i2c1-0 { - pins { - pinmux = <STM32_PINMUX('B', 6, AF4)>, /* I2C1_SCL */ - <STM32_PINMUX('B', 7, AF4)>; /* I2C1_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - ethernet_rmii: rmii-0 { - pins { - pinmux = <STM32_PINMUX('G', 11, AF11)>, - <STM32_PINMUX('G', 13, AF11)>, - <STM32_PINMUX('G', 12, AF11)>, - <STM32_PINMUX('C', 4, AF11)>, - <STM32_PINMUX('C', 5, AF11)>, - <STM32_PINMUX('A', 7, AF11)>, - <STM32_PINMUX('C', 1, AF11)>, - <STM32_PINMUX('A', 2, AF11)>, - <STM32_PINMUX('A', 1, AF11)>; - slew-rate = <2>; - }; - }; - - sdmmc1_b4_pins_a: sdmmc1-b4-0 { - pins { - pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */ - <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */ - <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */ - <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */ - <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */ - <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */ - slew-rate = <3>; - drive-push-pull; - bias-disable; - }; - }; - - sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 { - pins1 { - pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */ - <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */ - <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */ - <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */ - <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */ - slew-rate = <3>; - drive-push-pull; - bias-disable; - }; - pins2{ - pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */ - slew-rate = <3>; - drive-open-drain; - bias-disable; - }; - }; - - sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { - pins { - pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */ - <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */ - <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */ - <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */ - <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */ - <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */ - }; - }; - - sdmmc1_dir_pins_a: sdmmc1-dir-0 { - pins1 { - pinmux = <STM32_PINMUX('C', 6, AF8)>, /* SDMMC1_D0DIR */ - <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */ - <STM32_PINMUX('B', 9, AF7)>; /* SDMMC1_CDIR */ - slew-rate = <3>; - drive-push-pull; - bias-pull-up; - }; - pins2{ - pinmux = <STM32_PINMUX('B', 8, AF7)>; /* SDMMC1_CKIN */ - bias-pull-up; - }; - }; - - sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 { - pins { - pinmux = <STM32_PINMUX('C', 6, ANALOG)>, /* SDMMC1_D0DIR */ - <STM32_PINMUX('C', 7, ANALOG)>, /* SDMMC1_D123DIR */ - <STM32_PINMUX('B', 9, ANALOG)>, /* SDMMC1_CDIR */ - <STM32_PINMUX('B', 8, ANALOG)>; /* SDMMC1_CKIN */ - }; - }; - - usart1_pins: usart1-0 { - pins1 { - pinmux = <STM32_PINMUX('B', 14, AF4)>; /* USART1_TX */ - bias-disable; - drive-push-pull; - slew-rate = <0>; - }; - pins2 { - pinmux = <STM32_PINMUX('B', 15, AF4)>; /* USART1_RX */ - bias-disable; - }; - }; - - usart2_pins: usart2-0 { - pins1 { - pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */ - bias-disable; - drive-push-pull; - slew-rate = <0>; - }; - pins2 { - pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */ - bias-disable; - }; - }; - - usbotg_hs_pins_a: usbotg-hs-0 { - pins { - pinmux = <STM32_PINMUX('H', 4, AF10)>, /* ULPI_NXT */ - <STM32_PINMUX('I', 11, AF10)>, /* ULPI_DIR> */ - <STM32_PINMUX('C', 0, AF10)>, /* ULPI_STP> */ - <STM32_PINMUX('A', 5, AF10)>, /* ULPI_CK> */ - <STM32_PINMUX('A', 3, AF10)>, /* ULPI_D0> */ - <STM32_PINMUX('B', 0, AF10)>, /* ULPI_D1> */ - <STM32_PINMUX('B', 1, AF10)>, /* ULPI_D2> */ - <STM32_PINMUX('B', 10, AF10)>, /* ULPI_D3> */ - <STM32_PINMUX('B', 11, AF10)>, /* ULPI_D4> */ - <STM32_PINMUX('B', 12, AF10)>, /* ULPI_D5> */ - <STM32_PINMUX('B', 13, AF10)>, /* ULPI_D6> */ - <STM32_PINMUX('B', 5, AF10)>; /* ULPI_D7> */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi index 4ebffb0a45a3b43e83385c6ff51362290f7008b1..05ecdf9ff03a44732cb5039918d66f717100b8cc 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -135,6 +135,22 @@ clocks = <&rcc USART2_CK>; }; + usart3: serial@40004800 { + compatible = "st,stm32h7-uart"; + reg = <0x40004800 0x400>; + interrupts = <39>; + status = "disabled"; + clocks = <&rcc USART3_CK>; + }; + + uart4: serial@40004c00 { + compatible = "st,stm32h7-uart"; + reg = <0x40004c00 0x400>; + interrupts = <52>; + status = "disabled"; + clocks = <&rcc UART4_CK>; + }; + i2c1: i2c@40005400 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; @@ -159,7 +175,7 @@ status = "disabled"; }; - i2c3: i2c@40005C00 { + i2c3: i2c@40005c00 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; @@ -368,6 +384,21 @@ max-frequency = <120000000>; }; + sdmmc2: mmc@48022400 { + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x10153180>; + reg = <0x48022400 0x400>; + interrupts = <124>; + interrupt-names = "cmd_irq"; + clocks = <&rcc SDMMC2_CK>; + clock-names = "apb_pclk"; + resets = <&rcc STM32H7_AHB2_RESET(SDMMC2)>; + cap-sd-highspeed; + cap-mmc-highspeed; + max-frequency = <120000000>; + status = "disabled"; + }; + exti: interrupt-controller@58000000 { compatible = "st,stm32h7-exti"; interrupt-controller; @@ -392,7 +423,7 @@ status = "disabled"; }; - i2c4: i2c@58001C00 { + i2c4: i2c@58001c00 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; @@ -555,6 +586,148 @@ snps,pbl = <8>; status = "disabled"; }; + + pinctrl: pin-controller@58020000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32h743-pinctrl"; + ranges = <0 0x58020000 0x3000>; + interrupt-parent = <&exti>; + st,syscfg = <&syscfg 0x8>; + pins-are-numbered; + + gpioa: gpio@58020000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + clocks = <&rcc GPIOA_CK>; + st,bank-name = "GPIOA"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@58020400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x400 0x400>; + clocks = <&rcc GPIOB_CK>; + st,bank-name = "GPIOB"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@58020800 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x800 0x400>; + clocks = <&rcc GPIOC_CK>; + st,bank-name = "GPIOC"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@58020c00 { + gpio-controller; + #gpio-cells = <2>; + reg = <0xc00 0x400>; + clocks = <&rcc GPIOD_CK>; + st,bank-name = "GPIOD"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@58021000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1000 0x400>; + clocks = <&rcc GPIOE_CK>; + st,bank-name = "GPIOE"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@58021400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1400 0x400>; + clocks = <&rcc GPIOF_CK>; + st,bank-name = "GPIOF"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 80 16>; + }; + + gpiog: gpio@58021800 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1800 0x400>; + clocks = <&rcc GPIOG_CK>; + st,bank-name = "GPIOG"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 96 16>; + }; + + gpioh: gpio@58021c00 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1c00 0x400>; + clocks = <&rcc GPIOH_CK>; + st,bank-name = "GPIOH"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 112 16>; + }; + + gpioi: gpio@58022000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x2000 0x400>; + clocks = <&rcc GPIOI_CK>; + st,bank-name = "GPIOI"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 128 16>; + }; + + gpioj: gpio@58022400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x2400 0x400>; + clocks = <&rcc GPIOJ_CK>; + st,bank-name = "GPIOJ"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 144 16>; + }; + + gpiok: gpio@58022800 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x2800 0x400>; + clocks = <&rcc GPIOK_CK>; + st,bank-name = "GPIOK"; + interrupt-controller; + #interrupt-cells = <2>; + ngpios = <8>; + gpio-ranges = <&pinctrl 0 160 8>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/stm32h743i-disco.dts b/arch/arm/boot/dts/stm32h743i-disco.dts index e446d311c5200cb35b8c5bcb1d2de6a0bddcb0bc..59e01ce10318412528d8813edcb6994e099a96a7 100644 --- a/arch/arm/boot/dts/stm32h743i-disco.dts +++ b/arch/arm/boot/dts/stm32h743i-disco.dts @@ -42,7 +42,7 @@ /dts-v1/; #include "stm32h743.dtsi" -#include "stm32h743-pinctrl.dtsi" +#include "stm32h7-pinctrl.dtsi" / { model = "STMicroelectronics STM32H743i-Discovery board"; diff --git a/arch/arm/boot/dts/stm32h743i-eval.dts b/arch/arm/boot/dts/stm32h743i-eval.dts index 8f398178f5e5c7a7b7a129dfa138b82afdca291f..38cc7faf68841294c5fe18214aaa86f02bd06b70 100644 --- a/arch/arm/boot/dts/stm32h743i-eval.dts +++ b/arch/arm/boot/dts/stm32h743i-eval.dts @@ -42,7 +42,7 @@ /dts-v1/; #include "stm32h743.dtsi" -#include "stm32h743-pinctrl.dtsi" +#include "stm32h7-pinctrl.dtsi" / { model = "STMicroelectronics STM32H743i-EVAL board"; diff --git a/arch/arm/boot/dts/stm32h750.dtsi b/arch/arm/boot/dts/stm32h750.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..41e3b1e3a874b4c9f4ae13ce48a8b17a5008c5c4 --- /dev/null +++ b/arch/arm/boot/dts/stm32h750.dtsi @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright (C) STMicroelectronics 2021 - All Rights Reserved */ + +#include "stm32h743.dtsi" + + diff --git a/arch/arm/boot/dts/stm32h750i-art-pi.dts b/arch/arm/boot/dts/stm32h750i-art-pi.dts new file mode 100644 index 0000000000000000000000000000000000000000..9bb73bb6190126394694a332794fa259c11f40e3 --- /dev/null +++ b/arch/arm/boot/dts/stm32h750i-art-pi.dts @@ -0,0 +1,229 @@ +/* + * Copyright 2021 - Dillon Min <dillon.minfei@gmail.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) 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 AUTHORS OR COPYRIGHT + * HOLDERS 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. + * + * For art-pi board resources, you can refer to link: + * https://art-pi.gitee.io/website/ + */ + +/dts-v1/; +#include "stm32h750.dtsi" +#include "stm32h7-pinctrl.dtsi" +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "RT-Thread STM32H750i-ART-PI board"; + compatible = "st,stm32h750i-art-pi", "st,stm32h750"; + + chosen { + bootargs = "root=/dev/ram"; + stdout-path = "serial0:2000000n8"; + }; + + memory@c0000000 { + device_type = "memory"; + reg = <0xc0000000 0x2000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + no-map; + size = <0x100000>; + linux,dma-default; + }; + }; + + aliases { + serial0 = &uart4; + serial1 = &usart3; + }; + + leds { + compatible = "gpio-leds"; + led-red { + gpios = <&gpioi 8 0>; + }; + led-green { + gpios = <&gpioc 15 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + v3v3: regulator-v3v3 { + compatible = "regulator-fixed"; + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + wlan_pwr: regulator-wlan { + compatible = "regulator-fixed"; + + regulator-name = "wl-reg"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&clk_hse { + clock-frequency = <25000000>; +}; + +&dma1 { + status = "okay"; +}; + +&dma2 { + status = "okay"; +}; + +&mac { + status = "disabled"; + pinctrl-0 = <ðernet_rmii>; + pinctrl-names = "default"; + phy-mode = "rmii"; + phy-handle = <&phy0>; + + mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; +}; + +&sdmmc1 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; + broken-cd; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + status = "okay"; +}; + +&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>; + broken-cd; + non-removable; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&wlan_pwr>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&spi1 { + status = "okay"; + pinctrl-0 = <&spi1_pins>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 4 GPIO_ACTIVE_LOW>; + dmas = <&dmamux1 37 0x400 0x05>, + <&dmamux1 38 0x400 0x05>; + dma-names = "rx", "tx"; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <80000000>; + + partition@0 { + label = "root filesystem"; + reg = <0 0x1000000>; + }; + }; +}; + +&usart2 { + pinctrl-0 = <&usart2_pins>; + pinctrl-names = "default"; + status = "disabled"; +}; + +&usart3 { + pinctrl-names = "default"; + pinctrl-0 = <&usart3_pins>; + dmas = <&dmamux1 45 0x400 0x05>, + <&dmamux1 46 0x400 0x05>; + dma-names = "rx", "tx"; + st,hw-flow-ctrl; + status = "okay"; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + host-wakeup-gpios = <&gpioc 0 GPIO_ACTIVE_HIGH>; + device-wakeup-gpios = <&gpioi 10 GPIO_ACTIVE_HIGH>; + shutdown-gpios = <&gpioi 11 GPIO_ACTIVE_HIGH>; + max-speed = <115200>; + }; +}; + +&uart4 { + pinctrl-0 = <&uart4_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + + diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi index 7b4249ed198330ad01a6dd128020874b8866fedd..060baa8b7e9d4daadc97c9f8545307d60eb2e2c8 100644 --- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi @@ -1891,10 +1891,15 @@ usart2_idle_pins_c: usart2-idle-2 { pins1 { pinmux = <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */ - <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */ <STM32_PINMUX('D', 3, ANALOG)>; /* USART2_CTS_NSS */ }; pins2 { + pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */ + bias-disable; + drive-push-pull; + slew-rate = <3>; + }; + pins3 { pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */ bias-disable; }; @@ -1940,10 +1945,15 @@ usart3_idle_pins_b: usart3-idle-1 { pins1 { pinmux = <STM32_PINMUX('B', 10, ANALOG)>, /* USART3_TX */ - <STM32_PINMUX('G', 8, ANALOG)>, /* USART3_RTS */ <STM32_PINMUX('I', 10, ANALOG)>; /* USART3_CTS_NSS */ }; pins2 { + pinmux = <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins3 { pinmux = <STM32_PINMUX('B', 12, AF8)>; /* USART3_RX */ bias-disable; }; @@ -1976,10 +1986,15 @@ usart3_idle_pins_c: usart3-idle-2 { pins1 { pinmux = <STM32_PINMUX('B', 10, ANALOG)>, /* USART3_TX */ - <STM32_PINMUX('G', 8, ANALOG)>, /* USART3_RTS */ <STM32_PINMUX('B', 13, ANALOG)>; /* USART3_CTS_NSS */ }; pins2 { + pinmux = <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins3 { pinmux = <STM32_PINMUX('B', 12, AF8)>; /* USART3_RX */ bias-disable; }; diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi index 4b8031782555cc0d39383aff2aa67824c9dcc3e6..fcd3230c469b7e41dea4aaeabfb441b235666103 100644 --- a/arch/arm/boot/dts/stm32mp151.dtsi +++ b/arch/arm/boot/dts/stm32mp151.dtsi @@ -452,32 +452,36 @@ usart2: serial@4000e000 { compatible = "st,stm32h7-uart"; reg = <0x4000e000 0x400>; - interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 27 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART2_K>; + wakeup-source; status = "disabled"; }; usart3: serial@4000f000 { compatible = "st,stm32h7-uart"; reg = <0x4000f000 0x400>; - interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 28 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART3_K>; + wakeup-source; status = "disabled"; }; uart4: serial@40010000 { compatible = "st,stm32h7-uart"; reg = <0x40010000 0x400>; - interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 30 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART4_K>; + wakeup-source; status = "disabled"; }; uart5: serial@40011000 { compatible = "st,stm32h7-uart"; reg = <0x40011000 0x400>; - interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART5_K>; + wakeup-source; status = "disabled"; }; @@ -493,6 +497,7 @@ #size-cells = <0>; st,syscfg-fmp = <&syscfg 0x4 0x1>; wakeup-source; + i2c-analog-filter; status = "disabled"; }; @@ -508,6 +513,7 @@ #size-cells = <0>; st,syscfg-fmp = <&syscfg 0x4 0x2>; wakeup-source; + i2c-analog-filter; status = "disabled"; }; @@ -523,6 +529,7 @@ #size-cells = <0>; st,syscfg-fmp = <&syscfg 0x4 0x4>; wakeup-source; + i2c-analog-filter; status = "disabled"; }; @@ -538,6 +545,7 @@ #size-cells = <0>; st,syscfg-fmp = <&syscfg 0x4 0x10>; wakeup-source; + i2c-analog-filter; status = "disabled"; }; @@ -577,16 +585,18 @@ uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; - interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 32 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART7_K>; + wakeup-source; status = "disabled"; }; uart8: serial@40019000 { compatible = "st,stm32h7-uart"; reg = <0x40019000 0x400>; - interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 33 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART8_K>; + wakeup-source; status = "disabled"; }; @@ -665,8 +675,9 @@ usart6: serial@44003000 { compatible = "st,stm32h7-uart"; reg = <0x44003000 0x400>; - interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART6_K>; + wakeup-source; status = "disabled"; }; @@ -1421,11 +1432,13 @@ "mac-clk-tx", "mac-clk-rx", "eth-ck", + "ptp_ref", "ethstp"; clocks = <&rcc ETHMAC>, <&rcc ETHTX>, <&rcc ETHRX>, <&rcc ETHCK_K>, + <&rcc ETHPTP_K>, <&rcc ETHSTP>; st,syscon = <&syscfg 0x4>; snps,mixed-burst; @@ -1505,8 +1518,9 @@ usart1: serial@5c000000 { compatible = "st,stm32h7-uart"; reg = <0x5c000000 0x400>; - interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&exti 26 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART1_K>; + wakeup-source; status = "disabled"; }; @@ -1536,6 +1550,7 @@ #size-cells = <0>; st,syscfg-fmp = <&syscfg 0x4 0x8>; wakeup-source; + i2c-analog-filter; status = "disabled"; }; @@ -1573,6 +1588,7 @@ #size-cells = <0>; st,syscfg-fmp = <&syscfg 0x4 0x20>; wakeup-source; + i2c-analog-filter; status = "disabled"; }; diff --git a/arch/arm/boot/dts/stm32mp153c-dhcom-drc02.dts b/arch/arm/boot/dts/stm32mp153c-dhcom-drc02.dts index 02a39132958ea957ebd2fcfbe5224421242e0e1e..b4e504f026ce73794df91994bad3256f36887a55 100644 --- a/arch/arm/boot/dts/stm32mp153c-dhcom-drc02.dts +++ b/arch/arm/boot/dts/stm32mp153c-dhcom-drc02.dts @@ -20,6 +20,10 @@ "st,stm32mp153"; }; +&cryp1 { + status = "okay"; +}; + &m_can1 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&m_can1_pins_a>; diff --git a/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1-ctouch2.dts b/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1-ctouch2.dts new file mode 100644 index 0000000000000000000000000000000000000000..d3058a036c749f62fcc7f1aae882b637a06ffa0c --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1-ctouch2.dts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (c) STMicroelectronics 2019 - All Rights Reserved + * Copyright (c) 2020 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/dts-v1/; +#include "stm32mp157.dtsi" +#include "stm32mp157a-icore-stm32mp1.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Engicam i.Core STM32MP1 C.TOUCH 2.0"; + compatible = "engicam,icore-stm32mp1-ctouch2", + "engicam,icore-stm32mp1", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&sdmmc1 { + bus-width = <4>; + disable-wp; + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; + st,neg-edge; + vmmc-supply = <&v3v3>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1-edimm2.2.dts b/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1-edimm2.2.dts new file mode 100644 index 0000000000000000000000000000000000000000..ec9f1d1cd50fb456615e92913393a49898d155fc --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1-edimm2.2.dts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (c) STMicroelectronics 2019 - All Rights Reserved + * Copyright (c) 2020 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/dts-v1/; +#include "stm32mp157.dtsi" +#include "stm32mp157a-icore-stm32mp1.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Engicam i.Core STM32MP1 EDIMM2.2 Starter Kit"; + compatible = "engicam,icore-stm32mp1-edimm2.2", + "engicam,icore-stm32mp1", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&sdmmc1 { + bus-width = <4>; + disable-wp; + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; + st,neg-edge; + vmmc-supply = <&v3v3>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1.dtsi b/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..01166ccacf2b0b1298d6466dd90a2a6e5f4ca46e --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-icore-stm32mp1.dtsi @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (c) STMicroelectronics 2019 - All Rights Reserved + * Copyright (c) 2020 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/ { + compatible = "engicam,icore-stm32mp1", "st,stm32mp157"; + + memory@c0000000 { + device_type = "memory"; + reg = <0xc0000000 0x20000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mcuram2: mcuram2@10000000 { + compatible = "shared-dma-pool"; + reg = <0x10000000 0x40000>; + no-map; + }; + + vdev0vring0: vdev0vring0@10040000 { + compatible = "shared-dma-pool"; + reg = <0x10040000 0x1000>; + no-map; + }; + + vdev0vring1: vdev0vring1@10041000 { + compatible = "shared-dma-pool"; + reg = <0x10041000 0x1000>; + no-map; + }; + + vdev0buffer: vdev0buffer@10042000 { + compatible = "shared-dma-pool"; + reg = <0x10042000 0x4000>; + no-map; + }; + + mcuram: mcuram@30000000 { + compatible = "shared-dma-pool"; + reg = <0x30000000 0x40000>; + no-map; + }; + + retram: retram@38000000 { + compatible = "shared-dma-pool"; + reg = <0x38000000 0x10000>; + no-map; + }; + }; + + vddcore: regulator-vddcore { + compatible = "regulator-fixed"; + regulator-name = "vddcore"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vdd: regulator-vdd { + compatible = "regulator-fixed"; + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_usb: regulator-vdd-usb { + compatible = "regulator-fixed"; + regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdda: regulator-vdda { + compatible = "regulator-fixed"; + regulator-name = "vdda"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_ddr: regulator-vdd-ddr { + compatible = "regulator-fixed"; + regulator-name = "vdd_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + vtt_ddr: regulator-vtt-ddr { + compatible = "regulator-fixed"; + regulator-name = "vtt_ddr"; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <675000>; + regulator-always-on; + vin-supply = <&vdd>; + }; + + vref_ddr: regulator-vref-ddr { + compatible = "regulator-fixed"; + regulator-name = "vref_ddr"; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <675000>; + regulator-always-on; + vin-supply = <&vdd>; + }; + + vdd_sd: regulator-vdd-sd { + compatible = "regulator-fixed"; + regulator-name = "vdd_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + v3v3: regulator-v3v3 { + compatible = "regulator-fixed"; + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + v2v8: regulator-v2v8 { + compatible = "regulator-fixed"; + regulator-name = "v2v8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + vin-supply = <&v3v3>; + }; + + v1v8: regulator-v1v8 { + compatible = "regulator-fixed"; + regulator-name = "v1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + vin-supply = <&v3v3>; + }; +}; + +&dts { + status = "okay"; +}; + +&i2c2 { + i2c-scl-falling-time-ns = <20>; + i2c-scl-rising-time-ns = <185>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&i2c2_pins_a>; + pinctrl-1 = <&i2c2_sleep_pins_a>; + status = "okay"; +}; + +&ipcc { + status = "okay"; +}; + +&iwdg2{ + timeout-sec = <32>; + status = "okay"; +}; + +&m4_rproc{ + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; + mbox-names = "vq0", "vq1", "shutdown"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + status = "okay"; +}; + +&rng1 { + status = "okay"; +}; + +&rtc{ + status = "okay"; +}; + +&vrefbuf { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + vdda-supply = <&vdd>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts new file mode 100644 index 0000000000000000000000000000000000000000..674b2d330dc41f327304a02b3a78161db09ee5f9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (c) STMicroelectronics 2019 - All Rights Reserved + * Copyright (c) 2020 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/dts-v1/; +#include "stm32mp157.dtsi" +#include "stm32mp157a-microgea-stm32mp1.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Engicam MicroGEA STM32MP1 MicroDev 2.0 7\" Open Frame"; + compatible = "engicam,microgea-stm32mp1-microdev2.0-of7", + "engicam,microgea-stm32mp1", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + serial1 = &uart8; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + backlight: backlight { + compatible = "gpio-backlight"; + gpios = <&gpiod 13 GPIO_ACTIVE_HIGH>; + default-on; + }; + + lcd_3v3: regulator-lcd-3v3 { + compatible = "regulator-fixed"; + regulator-name = "lcd_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpiof 10 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + power-supply = <&panel_pwr>; + }; + + panel_pwr: regulator-panel-pwr { + compatible = "regulator-fixed"; + regulator-name = "panel_pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpiob 10 GPIO_ACTIVE_HIGH>; + regulator-always-on; + }; + + panel { + compatible = "auo,b101aw03"; + backlight = <&backlight>; + enable-gpios = <&gpiof 2 GPIO_ACTIVE_HIGH>; + power-supply = <&lcd_3v3>; + + port { + panel_in: endpoint { + remote-endpoint = <<dc_ep0_out>; + }; + }; + }; +}; + +&i2c2 { + i2c-scl-falling-time-ns = <20>; + i2c-scl-rising-time-ns = <185>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&i2c2_pins_a>; + pinctrl-1 = <&i2c2_sleep_pins_a>; + status = "okay"; +}; + +<dc { + pinctrl-names = "default"; + pinctrl-0 = <<dc_pins>; + status = "okay"; + + port { + ltdc_ep0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_in>; + }; + }; +}; + +&pinctrl { + ltdc_pins: ltdc { + pins { + pinmux = <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */ + <STM32_PINMUX('H', 12, AF14)>, /* LTDC_R6 */ + <STM32_PINMUX('H', 11, AF14)>, /* LTDC_R5 */ + <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */ + <STM32_PINMUX('D', 9, AF14)>, /* LTDC_B0 */ + <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */ + <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */ + <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */ + <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */ + <STM32_PINMUX('G', 7, AF14)>, /* LTDC_CLK */ + <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */ + <STM32_PINMUX('H', 2, AF14)>, /* LTDC_R0 */ + <STM32_PINMUX('H', 3, AF14)>, /* LTDC_R1 */ + <STM32_PINMUX('H', 8, AF14)>, /* LTDC_R2 */ + <STM32_PINMUX('H', 9, AF14)>, /* LTDC_R3 */ + <STM32_PINMUX('H', 10, AF14)>, /* LTDC_R4 */ + <STM32_PINMUX('H', 13, AF14)>, /* LTDC_G2 */ + <STM32_PINMUX('H', 14, AF14)>, /* LTDC_G3 */ + <STM32_PINMUX('H', 15, AF14)>, /* LTDC_G4 */ + <STM32_PINMUX('I', 0, AF14)>, /* LTDC_G5 */ + <STM32_PINMUX('I', 1, AF14)>, /* LTDC_G6 */ + <STM32_PINMUX('I', 2, AF14)>, /* LTDC_G7 */ + <STM32_PINMUX('I', 4, AF14)>, /* LTDC_B4 */ + <STM32_PINMUX('I', 5, AF14)>, /* LTDC_B5 */ + <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */ + <STM32_PINMUX('I', 7, AF14)>, /* LTDC_B7 */ + <STM32_PINMUX('I', 9, AF14)>, /* LTDC_VSYNC */ + <STM32_PINMUX('I', 10, AF14)>; /* LTDC_HSYNC */ + bias-disable; + drive-push-pull; + slew-rate = <3>; + }; + }; +}; + +&sdmmc1 { + bus-width = <4>; + disable-wp; + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; + st,neg-edge; + vmmc-supply = <&vdd>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + status = "okay"; +}; + +/* J31: RS323 */ +&uart8 { + pinctrl-names = "default"; + pinctrl-0 = <&uart8_pins_a>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0.dts b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0.dts new file mode 100644 index 0000000000000000000000000000000000000000..7a75868164dc065825f1a96cb53e91a9a858b56f --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0.dts @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (c) STMicroelectronics 2019 - All Rights Reserved + * Copyright (c) 2020 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/dts-v1/; +#include "stm32mp157.dtsi" +#include "stm32mp157a-microgea-stm32mp1.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Engicam MicroGEA STM32MP1 MicroDev 2.0 Carrier Board"; + compatible = "engicam,microgea-stm32mp1-microdev2.0", + "engicam,microgea-stm32mp1", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + serial1 = &uart8; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&sdmmc1 { + bus-width = <4>; + disable-wp; + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; + st,neg-edge; + vmmc-supply = <&vdd>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + status = "okay"; +}; + +/* J31: RS323 */ +&uart8 { + pinctrl-names = "default"; + pinctrl-0 = <&uart8_pins_a>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1.dtsi b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0b85175f151e4e3e4e389db552f3843e738ae9b5 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1.dtsi @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (c) STMicroelectronics 2019 - All Rights Reserved + * Copyright (c) 2020 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/ { + compatible = "engicam,microgea-stm32mp1", "st,stm32mp157"; + + memory@c0000000 { + device_type = "memory"; + reg = <0xc0000000 0x10000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mcuram2: mcuram2@10000000 { + compatible = "shared-dma-pool"; + reg = <0x10000000 0x40000>; + no-map; + }; + + vdev0vring0: vdev0vring0@10040000 { + compatible = "shared-dma-pool"; + reg = <0x10040000 0x1000>; + no-map; + }; + + vdev0vring1: vdev0vring1@10041000 { + compatible = "shared-dma-pool"; + reg = <0x10041000 0x1000>; + no-map; + }; + + vdev0buffer: vdev0buffer@10042000 { + compatible = "shared-dma-pool"; + reg = <0x10042000 0x4000>; + no-map; + }; + + mcuram: mcuram@30000000 { + compatible = "shared-dma-pool"; + reg = <0x30000000 0x40000>; + no-map; + }; + + retram: retram@38000000 { + compatible = "shared-dma-pool"; + reg = <0x38000000 0x10000>; + no-map; + }; + }; + + vin: regulator-vin { + compatible = "regulator-fixed"; + regulator-name = "vin"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + vddcore: regulator-vddcore { + compatible = "regulator-fixed"; + regulator-name = "vddcore"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + vin-supply = <&vin>; + }; + + vdd: regulator-vdd { + compatible = "regulator-fixed"; + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + vin-supply = <&vin>; + }; + + vddq_ddr: regulator-vddq-ddr { + compatible = "regulator-fixed"; + regulator-name = "vddq_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + vin-supply = <&vin>; + }; +}; + +&dts { + status = "okay"; +}; + +&fmc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&fmc_pins_a>; + pinctrl-1 = <&fmc_sleep_pins_a>; + status = "okay"; + + nand-controller@4,0 { + status = "okay"; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; + }; +}; + +&ipcc { + status = "okay"; +}; + +&iwdg2{ + timeout-sec = <32>; + status = "okay"; +}; + +&m4_rproc{ + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; + mbox-names = "vq0", "vq1", "shutdown"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + status = "okay"; +}; + +&rng1 { + status = "okay"; +}; + +&rtc{ + status = "okay"; +}; + +&vrefbuf { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + vdda-supply = <&vdd>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dhcom-pdk2.dts b/arch/arm/boot/dts/stm32mp157c-dhcom-pdk2.dts index d3b81382f97c3e2d8d330edef8e2a614d9bcae63..6dd8216c235eb574b516acdaaabb5c6d77bc1296 100644 --- a/arch/arm/boot/dts/stm32mp157c-dhcom-pdk2.dts +++ b/arch/arm/boot/dts/stm32mp157c-dhcom-pdk2.dts @@ -20,6 +20,10 @@ "st,stm32mp157"; }; +&cryp1 { + status = "okay"; +}; + &m_can1 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&m_can1_pins_a>; diff --git a/arch/arm/boot/dts/stm32mp157c-dhcom-picoitx.dts b/arch/arm/boot/dts/stm32mp157c-dhcom-picoitx.dts index cfb8f8a0c82d7770b79e51b3eccf7d73423b3e33..7067a860aaff8c751b523797c71549dc31d57fcf 100644 --- a/arch/arm/boot/dts/stm32mp157c-dhcom-picoitx.dts +++ b/arch/arm/boot/dts/stm32mp157c-dhcom-picoitx.dts @@ -20,6 +20,10 @@ "st,stm32mp157"; }; +&cryp1 { + status = "okay"; +}; + &m_can1 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&m_can1_pins_a>; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-drc02.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-drc02.dtsi index fad23d6f69b8f4dd50da42f46c643bd04ccd7bda..fb45c5aa878da43c8fa5d6fefe81ffa3ac0d1157 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcom-drc02.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-drc02.dtsi @@ -43,15 +43,15 @@ &gpiod { gpio-line-names = "", "", "", "", - "", "", "", "", - "", "", "", "Out1", - "Out2", "", "", ""; + "", "", "DHCOM-B", "", + "", "", "", "DRC02-Out1", + "DRC02-Out2", "", "", ""; }; &gpioi { - gpio-line-names = "In1", "", "", "", - "", "", "", "", - "In2", "", "", "", + gpio-line-names = "DRC02-In1", "DHCOM-O", "DHCOM-H", "DHCOM-I", + "DHCOM-R", "DHCOM-M", "", "", + "DRC02-In2", "", "", "", "", "", "", ""; /* diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-picoitx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-picoitx.dtsi index cd3a1798ca6815db1c6a248b0ea7bf1be579c0dc..ba816ef8b9b25586e13aee1bbeba5d905262e35e 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcom-picoitx.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-picoitx.dtsi @@ -57,22 +57,22 @@ &gpioc { gpio-line-names = "", "", "", "", - "", "", "In1", "", + "", "", "PicoITX-In1", "", "", "", "", "", "", "", "", ""; }; &gpiod { gpio-line-names = "", "", "", "", - "", "", "", "", - "", "", "", "Out1", - "Out2", "", "", ""; + "", "", "DHCOM-B", "", + "", "", "", "PicoITX-Out1", + "PicoITX-Out2", "", "", ""; }; &gpiog { - gpio-line-names = "In2", "", "", "", - "", "", "", "", + gpio-line-names = "PicoITX-In2", "", "", "", "", "", "", "", + "DHCOM-L", "", "", "", "", "", "", ""; }; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi index 2617815e42a6454abf636cf547f57cc22e4742c9..272a1a67a9adc15adffacf85918ad319781b2421 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi @@ -92,6 +92,10 @@ }; }; +&crc1 { + status = "okay"; +}; + &dac { pinctrl-names = "default"; pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; @@ -164,10 +168,70 @@ }; }; +&gpioa { + gpio-line-names = "", "", "", "", + "", "", "DHCOM-K", "", + "", "", "", "", + "", "", "", ""; +}; + +&gpiob { + gpio-line-names = "", "", "", "", + "", "", "", "", + "DHCOM-Q", "", "", "", + "", "", "", ""; +}; + &gpioc { + gpio-line-names = "", "", "", "", + "", "", "DHCOM-E", "", + "", "", "", "", + "", "", "", ""; status = "okay"; }; +&gpiod { + gpio-line-names = "", "", "", "", + "", "", "DHCOM-B", "", + "", "", "", "DHCOM-F", + "DHCOM-D", "", "", ""; +}; + +&gpioe { + gpio-line-names = "", "", "", "", + "", "", "DHCOM-P", "", + "", "", "", "", + "", "", "", ""; +}; + +&gpiof { + gpio-line-names = "", "", "", "DHCOM-A", + "", "", "", "", + "", "", "", "", + "", "", "", ""; +}; + +&gpiog { + gpio-line-names = "DHCOM-C", "", "", "", + "", "", "", "", + "DHCOM-L", "", "", "", + "", "", "", ""; +}; + +&gpioh { + gpio-line-names = "", "", "", "", + "", "", "", "DHCOM-N", + "DHCOM-J", "DHCOM-W", "DHCOM-V", "DHCOM-U", + "DHCOM-T", "", "DHCOM-S", ""; +}; + +&gpioi { + gpio-line-names = "DHCOM-G", "DHCOM-O", "DHCOM-H", "DHCOM-I", + "DHCOM-R", "DHCOM-M", "", "", + "", "", "", "", + "", "", "", ""; +}; + &i2c4 { pinctrl-names = "default"; pinctrl-0 = <&i2c4_pins_a>; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi index b09e87fe901a6122485f4637235774c9263b05d1..64dca5b7f748d8bc3b9b3120b4f1ba387a5d3003 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi @@ -162,6 +162,41 @@ }; }; +&gpioa { + gpio-line-names = "", "", "", "", + "", "", "", "", + "", "", "", "AV96-K", + "AV96-I", "", "AV96-A", ""; +}; + +&gpiob { + gpio-line-names = "", "", "", "", + "", "AV96-J", "", "", + "", "", "", "AV96-B", + "", "AV96-L", "", ""; +}; + +&gpioc { + gpio-line-names = "", "", "", "AV96-C", + "", "", "", "", + "", "", "", "", + "", "", "", ""; +}; + +&gpiod { + gpio-line-names = "", "", "", "", + "", "", "", "", + "AV96-D", "", "", "", + "", "", "AV96-E", "AV96-F"; +}; + +&gpiof { + gpio-line-names = "", "", "", "", + "", "", "", "", + "", "", "", "", + "AV96-G", "AV96-H", "", ""; +}; + &i2c1 { /* X6 I2C1 */ pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins_b>; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi index 803eb8bc9c85c819d296ca6f59d98411cb151229..013ae369791d761c53e8fd58f3bc3b09e1ce62c5 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi @@ -21,6 +21,10 @@ }; }; +&crc1 { + status = "okay"; +}; + &dts { status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-topwise-a721.dts b/arch/arm/boot/dts/sun4i-a10-topwise-a721.dts new file mode 100644 index 0000000000000000000000000000000000000000..3628f12d2521ed8b925d4b0f6d9a1dcdbe7ef393 --- /dev/null +++ b/arch/arm/boot/dts/sun4i-a10-topwise-a721.dts @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Pascal Roeleven <dev@pascalroeleven.nl> + */ + +/dts-v1/; +#include "sun4i-a10.dtsi" +#include "sunxi-common-regulators.dtsi" + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/pwm/pwm.h> + +/ { + model = "Topwise A721"; + compatible = "topwise,a721", "allwinner,sun4i-a10"; + + aliases { + serial0 = &uart0; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 100000 PWM_POLARITY_INVERTED>; + power-supply = <®_vbat>; + enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */ + brightness-levels = <0 30 40 50 60 70 80 90 100>; + default-brightness-level = <8>; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + panel { + compatible = "starry,kr070pe2t"; + backlight = <&backlight>; + power-supply = <®_lcd_power>; + + port { + panel_input: endpoint { + remote-endpoint = <&tcon0_out_panel>; + }; + }; + }; + + reg_lcd_power: reg-lcd-power { + compatible = "regulator-fixed"; + regulator-name = "reg-lcd-power"; + gpio = <&pio 7 8 GPIO_ACTIVE_HIGH>; /* PH8 */ + enable-active-high; + }; + + reg_vbat: reg-vbat { + compatible = "regulator-fixed"; + regulator-name = "vbat"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + +}; + +&codec { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <®_dcdc2>; +}; + +&de { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + axp209: pmic@34 { + reg = <0x34>; + interrupts = <0>; + }; +}; + +#include "axp209.dtsi" + +&ac_power_supply { + status = "okay"; +}; + +&battery_power_supply { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + accelerometer@4c { + compatible = "fsl,mma7660"; + reg = <0x4c>; + }; +}; + +&i2c2 { + status = "okay"; + + touchscreen@38 { + compatible = "edt,edt-ft5406"; + reg = <0x38>; + interrupt-parent = <&pio>; + interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>; + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + vcc-supply = <®_vcc3v3>; + }; +}; + +&lradc { + vref-supply = <®_ldo2>; + status = "okay"; + + button-571 { + label = "Volume Up"; + linux,code = <KEY_VOLUMEUP>; + channel = <0>; + voltage = <571428>; + }; + + button-761 { + label = "Volume Down"; + linux,code = <KEY_VOLUMEDOWN>; + channel = <0>; + voltage = <761904>; + }; +}; + +&mmc0 { + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH01 */ + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&otg_sram { + status = "okay"; +}; + +&pio { + vcc-pb-supply = <®_vcc3v3>; + vcc-pf-supply = <®_vcc3v3>; + vcc-ph-supply = <®_vcc3v3>; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pin>; + status = "okay"; +}; + +®_dcdc2 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-cpu"; +}; + +®_dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; + regulator-name = "vdd-int-dll"; +}; + +®_ldo1 { + regulator-name = "vdd-rtc"; +}; + +®_ldo2 { + regulator-always-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "avcc"; +}; + +®_usb0_vbus { + status = "okay"; +}; + +®_usb1_vbus { + status = "okay"; +}; + +®_usb2_vbus { + status = "okay"; +}; + +&tcon0_out { + tcon0_out_panel: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&usb_otg { + dr_mode = "otg"; + status = "okay"; +}; + +&usb_power_supply { + status = "okay"; +}; + +&usbphy { + usb0_id_det-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */ + usb0_vbus_det-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */ + usb0_vbus-supply = <®_usb0_vbus>; + usb1_vbus-supply = <®_usb1_vbus>; + usb2_vbus-supply = <®_usb2_vbus>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts index 486cec6f71e0954b1f7ec976f7a6cb4301333723..236ebfc061924bf694b6c897f872beb8c5d75d20 100644 --- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts +++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts @@ -227,7 +227,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; }; }; diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts index e4f3415e6108c910ac222d24ca3ae9fdb1acbd27..7d2eaaf5c33e39a24369bf986eb4d4faa20ac445 100644 --- a/arch/arm/boot/dts/sun6i-a31-m9.dts +++ b/arch/arm/boot/dts/sun6i-a31-m9.dts @@ -116,7 +116,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts index 7bd4bdd66a76cadd64fe0b64c8c95d155a106c79..83611434270cbc0d9b7c003b4b682e70af7fa97d 100644 --- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts +++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts @@ -116,7 +116,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index a75033e85fcb69d3a09c091ae08edb2a08604d69..a31f9072bf79da6f3a13e82b49f1ded7c2fc684a 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -611,6 +611,7 @@ pio: pinctrl@1c20800 { compatible = "allwinner,sun6i-a31-pinctrl"; reg = <0x01c20800 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>, @@ -802,6 +803,7 @@ lradc: lradc@1c22800 { compatible = "allwinner,sun4i-a10-lradc-keys"; reg = <0x01c22800 0x100>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; @@ -1299,6 +1301,7 @@ #clock-cells = <1>; compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; clocks = <&osc32k>; @@ -1308,7 +1311,7 @@ r_intc: interrupt-controller@1f00c00 { compatible = "allwinner,sun6i-a31-r-intc"; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>; reg = <0x01f00c00 0x400>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; }; @@ -1383,6 +1386,7 @@ r_pio: pinctrl@1f02c00 { compatible = "allwinner,sun6i-a31-r-pinctrl"; reg = <0x01f02c00 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>; diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts index 66bc6ca77afbac3756b11a02136294af4eb788b0..b32b70ada7fd0ee433b066bf6f04179f37322a87 100644 --- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts +++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts @@ -159,7 +159,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; }; }; diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi index 7455c0db4a8ae8a40f3a55fab0ffd7cf34bfe642..227ad489731c331404471c15e572617d0a38ce5f 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi +++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi @@ -79,7 +79,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts index efb25b949f30345beb87dae2a7994232851c4a01..96554ab4f6d3373eac165bb72f6ddc215fe3d5fd 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts @@ -149,7 +149,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; x-powers,drive-vbus-en; }; diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts index cadc45255d7b9f8adc832a9837aba3f3879e10c4..0b61f5368d449294450acdead0f575bb5534d3ec 100644 --- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts @@ -99,7 +99,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi index 6bf3fbdd738f9c84fcd06886891e80af118cadc0..f38d19c6be8cb480d0e0a42329496bdaf1c2ddb4 100644 --- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi +++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi @@ -80,7 +80,7 @@ compatible = "x-powers,axp221"; reg = <0x68>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; drivevbus-supply = <®_vcc5v0>; x-powers,drive-vbus-en; }; diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi index a42fac676b3119af04a533ade4b22b1ff591db99..4461d5098b20b7c423a67af3519c6733bfcd3e86 100644 --- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi @@ -338,6 +338,7 @@ pio: pinctrl@1c20800 { /* compatible gets set in SoC specific dtsi file */ reg = <0x01c20800 0x400>; + interrupt-parent = <&r_intc>; /* interrupts get set in SoC specific dtsi file */ clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>; clock-names = "apb", "hosc", "losc"; @@ -473,6 +474,7 @@ lradc: lradc@1c22800 { compatible = "allwinner,sun4i-a10-lradc-keys"; reg = <0x01c22800 0x100>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; @@ -709,6 +711,7 @@ rtc: rtc@1f00000 { compatible = "allwinner,sun8i-a23-rtc"; reg = <0x01f00000 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; clock-output-names = "osc32k", "osc32k-out"; @@ -719,7 +722,7 @@ r_intc: interrupt-controller@1f00c00 { compatible = "allwinner,sun6i-a31-r-intc"; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>; reg = <0x01f00c00 0x400>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; }; @@ -805,6 +808,7 @@ r_pio: pinctrl@1f02c00 { compatible = "allwinner,sun8i-a23-r-pinctrl"; reg = <0x01f02c00 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>; clock-names = "apb", "hosc", "losc"; diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts index 8538514c85886da9968acd7e7b6f4ccb9b3b6df3..6fee8f13350820a0c73dde13cc83b44e1b765336 100644 --- a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts +++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts @@ -99,7 +99,7 @@ compatible = "x-powers,axp223"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; x-powers,drive-vbus-en; }; diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts index d54a067fc76e85e1fa880f50722c5a5d980defaf..0c82ff3c7cb485f21d908985ce2f8dbf7a70f50a 100644 --- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts +++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts @@ -166,7 +166,7 @@ compatible = "x-powers,axp223"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; }; }; diff --git a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts index 9c006fc188217e608a2356885ed6a0293e7f1b99..c31c97d16024ca118c00c038bee141f194c1e341 100644 --- a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts +++ b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts @@ -122,7 +122,7 @@ compatible = "x-powers,axp818", "x-powers,axp813"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; swin-supply = <®_dcdc1>; }; @@ -142,7 +142,7 @@ ac100_rtc: rtc { compatible = "x-powers,ac100-rtc"; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; clocks = <&ac100_codec>; #clock-cells = <1>; clock-output-names = "cko1_rtc", diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts index b60016a4429c54ea9c69ac02be7c5b853a442c0b..5a7e1bd5f8258bf90816e577fe4940a0f3887b8a 100644 --- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts +++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts @@ -203,7 +203,7 @@ compatible = "x-powers,axp813"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; fldoin-supply = <®_dcdc5>; swin-supply = <®_dcdc1>; @@ -225,7 +225,7 @@ ac100_rtc: rtc { compatible = "x-powers,ac100-rtc"; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; clocks = <&ac100_codec>; #clock-cells = <1>; clock-output-names = "cko1_rtc", diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts index e26af7cf10e0ce20c94990bb73767ceff09428f2..870993393fc2439953297003869052b28f6b4b5a 100644 --- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts +++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts @@ -239,7 +239,7 @@ compatible = "x-powers,axp818", "x-powers,axp813"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; swin-supply = <®_dcdc1>; x-powers,drive-vbus-en; @@ -260,7 +260,7 @@ ac100_rtc: rtc { compatible = "x-powers,ac100-rtc"; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; clocks = <&ac100_codec>; #clock-cells = <1>; clock-output-names = "cko1_rtc", diff --git a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts index 83b01b03e08ebf0b027906993104cec2b3c2622d..7fe2a584ddf97722d00e203a4e5f76702fbeecec 100644 --- a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts +++ b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts @@ -263,7 +263,7 @@ compatible = "x-powers,axp813"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; swin-supply = <®_dcdc1>; x-powers,drive-vbus-en; }; @@ -283,7 +283,7 @@ ac100_rtc: rtc { compatible = "x-powers,ac100-rtc"; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; clocks = <&ac100_codec>; #clock-cells = <1>; clock-output-names = "cko1_rtc", diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index bd898b250e7405a9fbfae2ef292b526b07d873e3..ac97eac91349b93a2c7a190d8ccf7eeb05100ac3 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -708,6 +708,7 @@ pio: pinctrl@1c20800 { compatible = "allwinner,sun8i-a83t-pinctrl"; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; @@ -1111,7 +1112,7 @@ compatible = "allwinner,sun8i-a83t-r-intc", "allwinner,sun6i-a31-r-intc"; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>; reg = <0x01f00c00 0x400>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; }; @@ -1147,6 +1148,7 @@ r_lradc: lradc@1f03c00 { compatible = "allwinner,sun8i-a83t-r-lradc"; reg = <0x01f03c00 0x100>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; @@ -1154,6 +1156,7 @@ r_pio: pinctrl@1f02c00 { compatible = "allwinner,sun8i-a83t-r-pinctrl"; reg = <0x01f02c00 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&osc16Md512>; diff --git a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts index f3f7a2c912abed2afd0fc3e50f678675f1dc93ca..8e8634ff2f9d3b64fa2b6e64547819b58e5465c1 100644 --- a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts +++ b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts @@ -26,6 +26,17 @@ stdout-path = "serial0:115200n8"; }; + connector { + compatible = "hdmi-connector"; + type = "c"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; @@ -103,10 +114,24 @@ cpu-supply = <®_vdd_cpux>; }; +&de { + status = "okay"; +}; + &ehci0 { status = "okay"; }; +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts index 62b5280ec093568ddb482718b1b60e06f9e65b61..f0e591e1c77173d6c82093259fd79279b6d25f98 100644 --- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts @@ -111,6 +111,17 @@ #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; }; + + r-gpio-keys { + compatible = "gpio-keys"; + + power { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; }; &de { diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts index 293016d081cd882a985971633ae9f17a0ff352ce..bf5b5e2f6168beefaef40d67e25c9befae73ce85 100644 --- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts +++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts @@ -164,7 +164,7 @@ compatible = "x-powers,axp223"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; x-powers,drive-vbus-en; }; diff --git a/arch/arm/boot/dts/sun8i-r16-parrot.dts b/arch/arm/boot/dts/sun8i-r16-parrot.dts index 2be1b76fe2f67719cbfb738ab015f1e751a4e6e4..95543a9c21182fd74b02c9cb746563edb29855d2 100644 --- a/arch/arm/boot/dts/sun8i-r16-parrot.dts +++ b/arch/arm/boot/dts/sun8i-r16-parrot.dts @@ -165,7 +165,7 @@ compatible = "x-powers,axp223"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; drivevbus-supply = <®_vcc5v0>; x-powers,drive-vbus-en; }; diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi index 797d61cff11e3ab933fd9646e62a2d757da721d8..872d56caa9ce7f91ccaeb4460835583fe4d0f4f8 100644 --- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi +++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi @@ -94,7 +94,7 @@ compatible = "x-powers,axp223"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; eldoin-supply = <®_dcdc1>; drivevbus-supply = <®_vcc5v0>; x-powers,drive-vbus-en; diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi index 9be13378d4df58b8fc54e4b4eec697a942a7400f..c7428df9469e65fa3d4662ef9736fcf1cf32f0a6 100644 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -395,6 +395,7 @@ pio: pinctrl@1c20800 { /* compatible is in per SoC .dtsi file */ reg = <0x01c20800 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>; @@ -852,6 +853,7 @@ rtc: rtc@1f00000 { /* compatible is in per SoC .dtsi file */ reg = <0x01f00000 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; clock-output-names = "osc32k", "osc32k-out", "iosc"; @@ -859,6 +861,15 @@ #clock-cells = <1>; }; + r_intc: interrupt-controller@1f00c00 { + compatible = "allwinner,sun8i-h3-r-intc", + "allwinner,sun6i-a31-r-intc"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x01f00c00 0x400>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + }; + r_ccu: clock@1f01400 { compatible = "allwinner,sun8i-h3-r-ccu"; reg = <0x01f01400 0x100>; @@ -900,6 +911,7 @@ r_pio: pinctrl@1f02c00 { compatible = "allwinner,sun8i-h3-r-pinctrl"; reg = <0x01f02c00 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&rtc 0>; clock-names = "apb", "hosc", "losc"; diff --git a/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi index 49d9420a328983bdff304fe7b8ff1dc4df3765ed..781ac86010302e3e3a1705e0c415723278f845c4 100644 --- a/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi @@ -128,24 +128,28 @@ opp-microvolt = <800000 800000 1150000>; opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x0003>; + opp-suspend; }; opp@204000000,950 { opp-microvolt = <950000 950000 1150000>; opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x0008>; + opp-suspend; }; opp@204000000,1050 { opp-microvolt = <1050000 1050000 1150000>; opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x0010>; + opp-suspend; }; opp@204000000,1110 { opp-microvolt = <1110000 1110000 1150000>; opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x0004>; + opp-suspend; }; opp@264000000,800 { @@ -360,6 +364,7 @@ opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x001F>; opp-peak-kBps = <3264000>; + opp-suspend; }; opp@264000000 { diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts index d3b99535d755ef47167994d5efb48556e7d52add..2298fc034183b65260cb3a09710d2055b0216ded 100644 --- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts @@ -448,8 +448,10 @@ reset-gpios = <&gpio TEGRA_GPIO(Q, 7) GPIO_ACTIVE_LOW>; - avdd-supply = <&vdd_3v3_sys>; + vdda-supply = <&vdd_3v3_sys>; vdd-supply = <&vdd_3v3_sys>; + + atmel,wakeup-method = <1>; }; gyroscope@68 { @@ -575,7 +577,7 @@ vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; regulator-coupled-with = <&rtc_vdd &vdd_cpu>; regulator-coupled-max-spread = <170000 550000>; @@ -616,7 +618,7 @@ rtc_vdd: ldo2 { regulator-name = "vdd_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; regulator-coupled-with = <&vdd_core &vdd_cpu>; regulator-coupled-max-spread = <170000 550000>; @@ -838,9 +840,10 @@ #cooling-cells = <2>; }; - cpu@1 { + cpu1: cpu@1 { cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; }; @@ -1055,7 +1058,7 @@ trip0: cpu-alert0 { /* start throttling at 50C */ temperature = <50000>; - hysteresis = <3000>; + hysteresis = <200>; type = "passive"; }; @@ -1070,7 +1073,8 @@ cooling-maps { map0 { trip = <&trip0>; - cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm/boot/dts/tegra20-cpu-opp.dtsi b/arch/arm/boot/dts/tegra20-cpu-opp.dtsi index 702a635e88e7aeb2352da5612637804eb34c9949..135de316383b533dff14ca00211d8831539d75dc 100644 --- a/arch/arm/boot/dts/tegra20-cpu-opp.dtsi +++ b/arch/arm/boot/dts/tegra20-cpu-opp.dtsi @@ -9,12 +9,14 @@ clock-latency-ns = <400000>; opp-supported-hw = <0x0F 0x0003>; opp-hz = /bits/ 64 <216000000>; + opp-suspend; }; opp@216000000,800 { clock-latency-ns = <400000>; opp-supported-hw = <0x0F 0x0004>; opp-hz = /bits/ 64 <216000000>; + opp-suspend; }; opp@312000000,750 { diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 7e49112cd9a15c30fed60b83bc57372021737226..940a9f31cd86406a436b5fd9e5954d93ea769150 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -387,10 +387,10 @@ core_vdd_reg: sm0 { regulator-name = "+1.2vs_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1225000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; regulator-coupled-with = <&rtc_vdd_reg &cpu_vdd_reg>; - regulator-coupled-max-spread = <170000 450000>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; nvidia,tegra-core-regulator; @@ -401,7 +401,7 @@ regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; regulator-coupled-with = <&core_vdd_reg &rtc_vdd_reg>; - regulator-coupled-max-spread = <450000 450000>; + regulator-coupled-max-spread = <550000 550000>; regulator-always-on; nvidia,tegra-cpu-regulator; @@ -425,10 +425,10 @@ rtc_vdd_reg: ldo2 { regulator-name = "+1.2vs_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1225000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; regulator-coupled-with = <&core_vdd_reg &cpu_vdd_reg>; - regulator-coupled-max-spread = <170000 450000>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; nvidia,tegra-rtc-regulator; diff --git a/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi index b84afecea154bb9a58f25ddfff32fc65531c154e..ef3ad2e5f2701cae907da2abb7dbebff8e6dbaea 100644 --- a/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi @@ -68,6 +68,7 @@ opp-microvolt = <1000000 1000000 1300000>; opp-hz = /bits/ 64 <216000000>; opp-supported-hw = <0x000F>; + opp-suspend; }; opp@300000000 { diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index 055334ae3d2889ceb5a84a7da8723b5564027ee6..99a356c1ccec34eae144f98f7e2e6ec91d5bf09b 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts @@ -2,8 +2,10 @@ /dts-v1/; #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra20.dtsi" #include "tegra20-cpu-opp.dtsi" +#include "tegra20-cpu-opp-microvolt.dtsi" / { model = "NVIDIA Tegra20 Ventana evaluation board"; @@ -420,18 +422,28 @@ regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-coupled-with = <&rtc_vdd &vdd_cpu>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; + regulator-boot-on; + + nvidia,tegra-core-regulator; }; - sm1 { + vdd_cpu: sm1 { regulator-name = "vdd_sm1,vdd_cpu"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1125000>; + regulator-coupled-with = <&vdd_core &rtc_vdd>; + regulator-coupled-max-spread = <550000 550000>; regulator-always-on; + regulator-boot-on; + + nvidia,tegra-cpu-regulator; }; sm2_reg: sm2 { @@ -450,10 +462,16 @@ regulator-always-on; }; - ldo2 { + rtc_vdd: ldo2 { regulator-name = "vdd_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-coupled-with = <&vdd_core &vdd_cpu>; + regulator-coupled-max-spread = <170000 550000>; + regulator-always-on; + regulator-boot-on; + + nvidia,tegra-rtc-regulator; }; ldo3 { @@ -511,9 +529,10 @@ }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; + #thermal-sensor-cells = <1>; }; }; @@ -595,11 +614,15 @@ cpus { cpu0: cpu@0 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; - cpu@1 { + cpu1: cpu@1 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; }; @@ -697,4 +720,37 @@ <&tegra_car TEGRA20_CLK_CDEV1>; clock-names = "pll_a", "pll_a_out0", "mclk"; }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>; + + trips { + trip0: cpu-alert0 { + /* start throttling at 50C */ + temperature = <50000>; + hysteresis = <200>; + type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra30-apalis.dtsi b/arch/arm/boot/dts/tegra30-apalis.dtsi index 6544ce70b46f8c76a885dd759d1f13f1ef44f2e1..b2ac51fb15b140745eaa812845cafabc66212f64 100644 --- a/arch/arm/boot/dts/tegra30-apalis.dtsi +++ b/arch/arm/boot/dts/tegra30-apalis.dtsi @@ -860,6 +860,7 @@ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; interrupt-controller; + wakeup-source; ti,system-power-controller; diff --git a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi index ac1c1a63eb0e4152f51077fa535eccc92b99252c..dc773b1bf8ee8166750ce79a0b0cd4810fc16198 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi @@ -1056,19 +1056,22 @@ #cooling-cells = <2>; }; - cpu@1 { + cpu1: cpu@1 { cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; - cpu@2 { + cpu2: cpu@2 { cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; - cpu@3 { + cpu3: cpu@3 { cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; }; @@ -1281,7 +1284,10 @@ cooling-maps { map0 { trip = <&trip0>; - cooling-device = <&cpu0 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/tegra30-asus-nexus7-grouper-ti-pmic.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi index bfc06b988781d1b85addf5b19b13017a45a58527..b97da45ebdb48bdf2f05a53546f2f8046758216f 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi @@ -12,6 +12,7 @@ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; interrupt-controller; + wakeup-source; ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>; ti,system-power-controller; diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index e0624b74fb5030d59691145b028cf54ee2eb7d29..e159feeedef7262270b2a42c44d9daf74ff4203e 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts @@ -1776,6 +1776,7 @@ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; interrupt-controller; + wakeup-source; ti,system-power-controller; diff --git a/arch/arm/boot/dts/tegra30-cardhu-a04.dts b/arch/arm/boot/dts/tegra30-cardhu-a04.dts index c1c0ca628af1fec80ac2ed26f10eb11a09fdcf90..a11028b8b67bc154a26693440a3a8336415953e4 100644 --- a/arch/arm/boot/dts/tegra30-cardhu-a04.dts +++ b/arch/arm/boot/dts/tegra30-cardhu-a04.dts @@ -2,8 +2,6 @@ /dts-v1/; #include "tegra30-cardhu.dtsi" -#include "tegra30-cpu-opp.dtsi" -#include "tegra30-cpu-opp-microvolt.dtsi" /* This dts file support the cardhu A04 and later versions of board */ @@ -92,50 +90,4 @@ enable-active-high; gpio = <&gpio TEGRA_GPIO(DD, 0) GPIO_ACTIVE_HIGH>; }; - - i2c@7000d000 { - pmic: tps65911@2d { - regulators { - vddctrl_reg: vddctrl { - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1125000>; - regulator-coupled-with = <&vddcore_reg>; - regulator-coupled-max-spread = <300000>; - regulator-max-step-microvolt = <100000>; - - nvidia,tegra-cpu-regulator; - }; - }; - }; - - vddcore_reg: tps62361@60 { - regulator-coupled-with = <&vddctrl_reg>; - regulator-coupled-max-spread = <300000>; - regulator-max-step-microvolt = <100000>; - - nvidia,tegra-core-regulator; - }; - }; - - cpus { - cpu0: cpu@0 { - cpu-supply = <&vddctrl_reg>; - operating-points-v2 = <&cpu0_opp_table>; - }; - - cpu@1 { - cpu-supply = <&vddctrl_reg>; - operating-points-v2 = <&cpu0_opp_table>; - }; - - cpu@2 { - cpu-supply = <&vddctrl_reg>; - operating-points-v2 = <&cpu0_opp_table>; - }; - - cpu@3 { - cpu-supply = <&vddctrl_reg>; - operating-points-v2 = <&cpu0_opp_table>; - }; - }; }; diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index dab9989fa76051ffe1725ccc7fcce2c4d4456efb..2dff14b87f3e61019bf6ea567f843ae0ecf54b17 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra30.dtsi" +#include "tegra30-cpu-opp.dtsi" +#include "tegra30-cpu-opp-microvolt.dtsi" /** * This file contains common DT entry for all fab version of Cardhu. @@ -240,6 +243,7 @@ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; interrupt-controller; + wakeup-source; ti,system-power-controller; @@ -272,9 +276,14 @@ vddctrl_reg: vddctrl { regulator-name = "vdd_cpu,vdd_sys"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1250000>; + regulator-coupled-with = <&vdd_core>; + regulator-coupled-max-spread = <300000>; + regulator-max-step-microvolt = <100000>; regulator-always-on; + + nvidia,tegra-cpu-regulator; }; vio_reg: vio { @@ -334,25 +343,31 @@ }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; vcc-supply = <&sys_3v3_reg>; interrupt-parent = <&gpio>; interrupts = <TEGRA_GPIO(CC, 2) IRQ_TYPE_LEVEL_LOW>; + #thermal-sensor-cells = <1>; }; - tps62361@60 { + vdd_core: tps62361@60 { compatible = "ti,tps62361"; reg = <0x60>; regulator-name = "tps62361-vout"; regulator-min-microvolt = <500000>; regulator-max-microvolt = <1500000>; + regulator-coupled-with = <&vddctrl_reg>; + regulator-coupled-max-spread = <300000>; + regulator-max-step-microvolt = <100000>; regulator-boot-on; regulator-always-on; ti,vsel0-state-high; ti,vsel1-state-high; + + nvidia,tegra-core-regulator; }; }; @@ -424,6 +439,32 @@ #clock-cells = <0>; }; + cpus { + cpu0: cpu@0 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + + cpu1: cpu@1 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + + cpu2: cpu@2 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + + cpu3: cpu@3 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + }; + panel: panel { compatible = "chunghwa,claa101wb01"; ddc-i2c-bus = <&panelddc>; @@ -603,6 +644,41 @@ <&tegra_car TEGRA30_CLK_EXTERN1>; }; + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>; + + trips { + trip0: cpu-alert0 { + /* throttle at 57C until temperature drops to 56.8C */ + temperature = <57000>; + hysteresis = <200>; + type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + 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>; + }; + }; + }; + }; + gpio-keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/tegra30-colibri.dtsi b/arch/arm/boot/dts/tegra30-colibri.dtsi index e36aa3ce6c3d36a0f97aa37f6646caacf3b6a99a..413e35215804bee3360ca80191b33cc1d0d0860e 100644 --- a/arch/arm/boot/dts/tegra30-colibri.dtsi +++ b/arch/arm/boot/dts/tegra30-colibri.dtsi @@ -737,6 +737,7 @@ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; interrupt-controller; + wakeup-source; ti,system-power-controller; diff --git a/arch/arm/boot/dts/tegra30-cpu-opp.dtsi b/arch/arm/boot/dts/tegra30-cpu-opp.dtsi index 0f7135006d197c5cb5f092bea52f43776a1e603b..72f2fe26cc0e9ef39d90e04e57393bbc0362820c 100644 --- a/arch/arm/boot/dts/tegra30-cpu-opp.dtsi +++ b/arch/arm/boot/dts/tegra30-cpu-opp.dtsi @@ -45,18 +45,21 @@ clock-latency-ns = <100000>; opp-supported-hw = <0x1F 0x31FE>; opp-hz = /bits/ 64 <204000000>; + opp-suspend; }; opp@204000000,850 { clock-latency-ns = <100000>; opp-supported-hw = <0x1F 0x0C01>; opp-hz = /bits/ 64 <204000000>; + opp-suspend; }; opp@204000000,912 { clock-latency-ns = <100000>; opp-supported-hw = <0x1F 0x0200>; opp-hz = /bits/ 64 <204000000>; + opp-suspend; }; opp@312000000,850 { diff --git a/arch/arm/boot/dts/tegra30-ouya.dts b/arch/arm/boot/dts/tegra30-ouya.dts index 0368b3b816ef2941a9d9b76a32012d20d67a6e33..9a10e0d697626664538ed478f6a4356c3fd06fd4 100644 --- a/arch/arm/boot/dts/tegra30-ouya.dts +++ b/arch/arm/boot/dts/tegra30-ouya.dts @@ -139,6 +139,7 @@ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; interrupt-controller; + wakeup-source; ti,en-gpio-sleep = <0 1 1 1 1 1 0 0 1>; ti,system-power-controller; @@ -391,19 +392,23 @@ cpu-supply = <&vdd_cpu>; #cooling-cells = <2>; }; - cpu@1 { + + cpu1: cpu@1 { operating-points-v2 = <&cpu0_opp_table>; cpu-supply = <&vdd_cpu>; + #cooling-cells = <2>; }; - cpu@2 { + cpu2: cpu@2 { operating-points-v2 = <&cpu0_opp_table>; cpu-supply = <&vdd_cpu>; + #cooling-cells = <2>; }; - cpu@3 { + cpu3: cpu@3 { operating-points-v2 = <&cpu0_opp_table>; cpu-supply = <&vdd_cpu>; + #cooling-cells = <2>; }; }; @@ -455,7 +460,10 @@ }; map1 { trip = <&cpu_alert1>; - cooling-device = <&cpu0 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/tegra30-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi index cbe84d25e7263fe6b0181c25671a74e2f876dd92..2c97803197257b409320d822cc85e23fa1b3b99f 100644 --- a/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi @@ -128,12 +128,14 @@ opp-microvolt = <1000000 1000000 1350000>; opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x0007>; + opp-suspend; }; opp@204000000,1250 { opp-microvolt = <1250000 1250000 1350000>; opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x0008>; + opp-suspend; }; opp@333500000,1000 { @@ -312,6 +314,7 @@ opp-hz = /bits/ 64 <204000000>; opp-supported-hw = <0x000F>; opp-peak-kBps = <1632000>; + opp-suspend; }; opp@333500000 { diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 6403b064e8dcf9f94f1a442e096791a52b8d96ff..06c888a45eb39332169df8603764d634c501b031 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -46,6 +46,7 @@ CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y +CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y @@ -53,7 +54,7 @@ CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ATMEL=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_FASTMAP=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 @@ -131,6 +132,8 @@ CONFIG_MEDIA_SUPPORT_FILTER=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_PLATFORM_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_ATMEL_ISI=y CONFIG_VIDEO_OV2640=m diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig index 81665b7abf8307efdb996bd6795e77b1dcab36e9..a49e699e52de363e77749f0045a35a0c08641cf9 100644 --- a/arch/arm/configs/ezx_defconfig +++ b/arch/arm/configs/ezx_defconfig @@ -213,7 +213,6 @@ CONFIG_POWER_SUPPLY=y CONFIG_EZX_PCAP=y CONFIG_REGULATOR=y CONFIG_REGULATOR_DEBUG=y -CONFIG_REGULATOR_USERSPACE_CONSUMER=y CONFIG_REGULATOR_PCAP=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig index ae15a2a33802ab48a23c3b34fde3951cc73c48bb..118c4c927f2640f243c8c2787f83adecc9ad56ca 100644 --- a/arch/arm/configs/imote2_defconfig +++ b/arch/arm/configs/imote2_defconfig @@ -194,7 +194,6 @@ CONFIG_POWER_SUPPLY=y CONFIG_PMIC_DA903X=y CONFIG_REGULATOR=y CONFIG_REGULATOR_DEBUG=y -CONFIG_REGULATOR_USERSPACE_CONSUMER=y CONFIG_REGULATOR_DA903X=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 9f862b21b40abfd2936f8437e73f258b71179666..80a3ae02d7594472e5c8e451f5c9a20d9767b610 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -33,6 +33,8 @@ CONFIG_SOC_IMX25=y CONFIG_SOC_IMX27=y CONFIG_ARCH_MVEBU=y CONFIG_MACH_KIRKWOOD=y +CONFIG_ARCH_NPCM=y +CONFIG_ARCH_WPCM450=y CONFIG_ARCH_ORION5X=y CONFIG_MACH_DB88F5281=y CONFIG_MACH_RD88F5182=y @@ -178,6 +180,7 @@ CONFIG_THERMAL=y CONFIG_KIRKWOOD_THERMAL=y CONFIG_AT91SAM9X_WATCHDOG=y CONFIG_ORION_WATCHDOG=y +CONFIG_NPCM7XX_WATCHDOG=y CONFIG_IMX2_WDT=y CONFIG_MFD_ATMEL_HLCDC=y # CONFIG_ABX500_CORE is not set diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 3823da605430d675b52dacd6502dfcc8c0db57e3..52a0400fdd926edbefeccf8acc019dcb88c31c97 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -79,7 +79,7 @@ CONFIG_ARCH_MSM8960=y CONFIG_ARCH_MSM8974=y CONFIG_ARCH_ROCKCHIP=y CONFIG_ARCH_RENESAS=y -CONFIG_ARCH_SOCFPGA=y +CONFIG_ARCH_INTEL_SOCFPGA=y CONFIG_PLAT_SPEAR=y CONFIG_ARCH_SPEAR13XX=y CONFIG_MACH_SPEAR1310=y @@ -791,7 +791,6 @@ CONFIG_USB_XHCI_MVEBU=y CONFIG_USB_XHCI_TEGRA=m CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_STI=y -CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_EHCI_EXYNOS=m CONFIG_USB_EHCI_MV=m CONFIG_USB_OHCI_HCD=y @@ -817,6 +816,7 @@ CONFIG_USB_DWC2=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_TEGRA=y CONFIG_USB_ISP1760=y CONFIG_USB_HSIC_USB3503=y CONFIG_AB8500_USB=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index f250bf1cc022c90d5b5875b47c6dd8721be409aa..77b4bea12feb8c014b0930402d8b886037352bf6 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -87,6 +87,155 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_NETDEV=m +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_COUNTER=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_OBJREF=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB_INET=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NFT_REJECT_NETDEV=m +CONFIG_NF_FLOW_TABLE_INET=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_FLOW_TABLE_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_NF_FLOW_TABLE_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=m CONFIG_BRIDGE=m CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_VLAN_8021Q=m @@ -137,7 +286,6 @@ CONFIG_PCI_EPF_TEST=m CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_OMAP_OCP2SCP=y -CONFIG_SIMPLE_PM_BUS=y CONFIG_CONNECTOR=m CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y @@ -165,6 +313,7 @@ CONFIG_SENSORS_TSL2550=m CONFIG_SRAM=y CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m CONFIG_BLK_DEV_SD=y CONFIG_SCSI_SCAN_ASYNC=y CONFIG_ATA=y diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index bd7dd81c9c54414e50f34ef2138c0533172e4327..875a3c28a267db70d3cb61a40e7b6de14fe22601 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -415,7 +415,6 @@ CONFIG_MFD_TC6393XB=y CONFIG_REGULATOR=y CONFIG_REGULATOR_DEBUG=y CONFIG_REGULATOR_FIXED_VOLTAGE=m -CONFIG_REGULATOR_USERSPACE_CONSUMER=m CONFIG_REGULATOR_ACT8865=m CONFIG_REGULATOR_AS3711=m CONFIG_REGULATOR_AXP20X=m diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig index 3f36887e833307942aefc9a135bc993449493421..26353cbfa968003a44fe9dc7ad7683ef938ead84 100644 --- a/arch/arm/configs/qcom_defconfig +++ b/arch/arm/configs/qcom_defconfig @@ -215,6 +215,8 @@ CONFIG_DMADEVICES=y CONFIG_QCOM_BAM_DMA=y CONFIG_STAGING=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_A7PLL=y +CONFIG_QCOM_CLK_APCS_SDX55=y CONFIG_QCOM_CLK_RPM=y CONFIG_QCOM_CLK_RPMH=y CONFIG_QCOM_CLK_SMD_RPM=y @@ -232,11 +234,14 @@ CONFIG_ARM_SMMU=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y CONFIG_REMOTEPROC=y CONFIG_QCOM_ADSP_PIL=y +CONFIG_QCOM_Q6V5_PAS=y CONFIG_QCOM_Q6V5_PIL=y CONFIG_QCOM_WCNSS_PIL=y CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_GSBI=y @@ -273,6 +278,7 @@ CONFIG_QCOM_QFPROM=y CONFIG_INTERCONNECT=y CONFIG_INTERCONNECT_QCOM=y CONFIG_INTERCONNECT_QCOM_MSM8974=m +CONFIG_INTERCONNECT_QCOM_SDX55=m CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y @@ -290,7 +296,7 @@ CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y CONFIG_DMA_CMA=y -CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CMA_SIZE_MBYTES=64 CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y @@ -299,3 +305,5 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WATCHDOG=y CONFIG_QCOM_WDT=y CONFIG_ARM_PSCI=y +CONFIG_CPU_FREQ=y +CONFIG_CPUFREQ_DT=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index f4c3c0652432a2c146d3ac00b9b3e2de3a7d2a77..17db3b3e2dd37238480f13280c73483978749d48 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -8,11 +8,6 @@ CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_AT91=y CONFIG_SOC_SAMA5D2=y CONFIG_SOC_SAMA5D3=y @@ -25,9 +20,14 @@ CONFIG_KEXEC=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_DEBUG=y CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -55,6 +55,7 @@ CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y +CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y @@ -62,7 +63,7 @@ CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ATMEL=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_FASTMAP=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 @@ -75,8 +76,8 @@ CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y CONFIG_NET_DSA_MICROCHIP_KSZ9477=m CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI=m -CONFIG_MACB=y # CONFIG_NET_VENDOR_BROADCOM is not set +CONFIG_MACB=y # CONFIG_NET_VENDOR_CIRRUS is not set # CONFIG_NET_VENDOR_FARADAY is not set # CONFIG_NET_VENDOR_INTEL is not set @@ -89,9 +90,12 @@ CONFIG_MACB=y # CONFIG_NET_VENDOR_STMICRO is not set # CONFIG_NET_VENDOR_WIZNET is not set CONFIG_MICREL_PHY=y +CONFIG_USB_LAN78XX=m CONFIG_LIBERTAS_THINFIRM=m CONFIG_LIBERTAS_THINFIRM_USB=m -CONFIG_RTL8187=m +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_USB=m CONFIG_RT2X00=m CONFIG_RT2500USB=m CONFIG_RT73USB=m @@ -99,10 +103,7 @@ CONFIG_RT2800USB=m CONFIG_RT2800USB_RT53XX=y CONFIG_RT2800USB_RT55XX=y CONFIG_RT2800USB_UNKNOWN=y -CONFIG_MWIFIEX=m -CONFIG_MWIFIEX_SDIO=m -CONFIG_MWIFIEX_USB=m -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_RTL8187=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_QT1070=y @@ -124,10 +125,10 @@ CONFIG_SPI_ATMEL=y CONFIG_SPI_ATMEL_QUADSPI=y CONFIG_SPI_GPIO=y CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_SAMA5D2_PIOBU=m +CONFIG_GPIO_SAMA5D2_PIOBU=y +CONFIG_POWER_RESET=y CONFIG_POWER_SUPPLY=y CONFIG_BATTERY_ACT8945A=y -CONFIG_POWER_RESET=y CONFIG_SENSORS_JC42=m CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y @@ -139,13 +140,15 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_ACT8865=y CONFIG_REGULATOR_ACT8945A=y -CONFIG_REGULATOR_MCP16502=m +CONFIG_REGULATOR_MCP16502=y CONFIG_REGULATOR_PWM=m CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_SUPPORT_FILTER=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_PLATFORM_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_ATMEL_ISC=y CONFIG_VIDEO_ATMEL_ISI=y @@ -166,11 +169,12 @@ CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_ATMEL_SOC=y CONFIG_SND_ATMEL_SOC_WM8904=y -# CONFIG_HID_GENERIC is not set CONFIG_SND_ATMEL_SOC_CLASSD=y CONFIG_SND_ATMEL_SOC_PDMIC=y CONFIG_SND_ATMEL_SOC_TSE850_PCM5142=m CONFIG_SND_ATMEL_SOC_I2S=y +CONFIG_SND_SOC_MIKROE_PROTO=m +# CONFIG_HID_GENERIC is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y @@ -201,6 +205,9 @@ CONFIG_RTC_DRV_AT91RM9200=y CONFIG_DMADEVICES=y CONFIG_AT_HDMAC=y CONFIG_AT_XDMAC=y +CONFIG_STAGING=y +CONFIG_STAGING_MEDIA=y +CONFIG_VIDEO_HANTRO=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_IIO=y CONFIG_AT91_ADC=y @@ -224,14 +231,14 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_DEV_ATMEL_AES=y +CONFIG_CRYPTO_DEV_ATMEL_TDES=y +CONFIG_CRYPTO_DEV_ATMEL_SHA=y CONFIG_STRIP_ASM_SYMS=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set CONFIG_DEBUG_USER=y -CONFIG_CRYPTO_USER_API_HASH=m -CONFIG_CRYPTO_USER_API_SKCIPHER=m -CONFIG_CRYPTO_DEV_ATMEL_AES=y -CONFIG_CRYPTO_DEV_ATMEL_TDES=y -CONFIG_CRYPTO_DEV_ATMEL_SHA=y diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index 01a6ebdf033a6482c753f3dc34ea0a1932d50f6f..f25b09efb81640e3723c9d339027df25777bd903 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -220,6 +220,5 @@ CONFIG_NLS_ISO8859_1=y CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=64 CONFIG_PRINTK_TIME=y -# CONFIG_ENABLE_MUST_CHECK is not set CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 0c60eb382c806af9fb7df3e509864a65f009e36c..2d9404ea52c6d25459124e5ad86b84d40eaaafad 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -9,7 +9,7 @@ CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y -CONFIG_ARCH_SOCFPGA=y +CONFIG_ARCH_INTEL_SOCFPGA=y CONFIG_ARM_THUMBEE=y CONFIG_SMP=y CONFIG_NR_CPUS=2 diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index bcedfe1422aafa7ddef232a0e47a736d42046407..dbb1ef601762141e5ddde41f1dcebdefda4f7982 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -55,6 +55,7 @@ CONFIG_KEYBOARD_GPIO=y CONFIG_KEYBOARD_NOMADIK=y CONFIG_KEYBOARD_STMPE=y CONFIG_KEYBOARD_TC3589X=y +CONFIG_KEYBOARD_TM2_TOUCHKEY=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ATMEL_MXT=y @@ -74,10 +75,12 @@ CONFIG_SERIAL_DEV_BUS=y CONFIG_HW_RANDOM=y CONFIG_I2C_GPIO=y CONFIG_SPI=y +CONFIG_SPI_GPIO=y CONFIG_SPI_PL022=y CONFIG_GPIO_STMPE=y CONFIG_GPIO_TC3589X=y CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_NTC_THERMISTOR=y CONFIG_THERMAL=y CONFIG_CPU_THERMAL=y CONFIG_WATCHDOG=y @@ -85,6 +88,10 @@ CONFIG_MFD_STMPE=y CONFIG_MFD_TC3589X=y CONFIG_REGULATOR_AB8500=y CONFIG_REGULATOR_GPIO=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L2_FLASH_LED_CLASS=y CONFIG_DRM=y CONFIG_DRM_PANEL_NOVATEK_NT35510=y CONFIG_DRM_PANEL_SAMSUNG_S6D16D0=y @@ -112,10 +119,12 @@ CONFIG_MMC=y CONFIG_MMC_ARMMMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=y CONFIG_LEDS_LM3530=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_LP55XX_COMMON=y CONFIG_LEDS_LP5521=y +CONFIG_LEDS_RT8515=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AB8500=y @@ -124,16 +133,21 @@ CONFIG_DMADEVICES=y CONFIG_STE_DMA40=y CONFIG_HWSPINLOCK=y CONFIG_HSEM_U8500=y +CONFIG_EXTCON_FSA9480=y CONFIG_IIO=y CONFIG_IIO_SW_TRIGGER=y CONFIG_BMA180=y +CONFIG_BMC150_ACCEL=y CONFIG_IIO_ST_ACCEL_3AXIS=y +CONFIG_IIO_RESCALE=y +CONFIG_MPU3050_I2C=y CONFIG_IIO_ST_GYRO_3AXIS=y CONFIG_INV_MPU6050_I2C=y CONFIG_BH1780=y CONFIG_GP2AP002=y CONFIG_AK8974=y CONFIG_IIO_ST_MAGN_3AXIS=y +CONFIG_YAMAHA_YAS530=y CONFIG_IIO_HRTIMER_TRIGGER=y CONFIG_IIO_ST_PRESS=y CONFIG_EXT2_FS=y diff --git a/arch/arm/crypto/aes-cipher-core.S b/arch/arm/crypto/aes-cipher-core.S index 472e56d09eeae6d4f4fd4211960c49750bd4c649..1da3f41359aa86cc808471077dc1ee9a273fd089 100644 --- a/arch/arm/crypto/aes-cipher-core.S +++ b/arch/arm/crypto/aes-cipher-core.S @@ -99,28 +99,6 @@ __hround \out2, \out3, \in2, \in1, \in0, \in3, \in1, \in0, 0, \sz, \op, \oldcpsr .endm - .macro __rev, out, in - .if __LINUX_ARM_ARCH__ < 6 - lsl t0, \in, #24 - and t1, \in, #0xff00 - and t2, \in, #0xff0000 - orr \out, t0, \in, lsr #24 - orr \out, \out, t1, lsl #8 - orr \out, \out, t2, lsr #8 - .else - rev \out, \in - .endif - .endm - - .macro __adrl, out, sym, c - .if __LINUX_ARM_ARCH__ < 7 - ldr\c \out, =\sym - .else - movw\c \out, #:lower16:\sym - movt\c \out, #:upper16:\sym - .endif - .endm - .macro do_crypt, round, ttab, ltab, bsz push {r3-r11, lr} @@ -133,10 +111,10 @@ ldr r7, [in, #12] #ifdef CONFIG_CPU_BIG_ENDIAN - __rev r4, r4 - __rev r5, r5 - __rev r6, r6 - __rev r7, r7 + rev_l r4, t0 + rev_l r5, t0 + rev_l r6, t0 + rev_l r7, t0 #endif eor r4, r4, r8 @@ -144,7 +122,7 @@ eor r6, r6, r10 eor r7, r7, r11 - __adrl ttab, \ttab + mov_l ttab, \ttab /* * Disable interrupts and prefetch the 1024-byte 'ft' or 'it' table into * L1 cache, assuming cacheline size >= 32. This is a hardening measure @@ -180,7 +158,7 @@ 2: .ifb \ltab add ttab, ttab, #1 .else - __adrl ttab, \ltab + mov_l ttab, \ltab // Prefetch inverse S-box for final round; see explanation above .set i, 0 .rept 256 / 64 @@ -194,10 +172,10 @@ \round r4, r5, r6, r7, r8, r9, r10, r11, \bsz, b, rounds #ifdef CONFIG_CPU_BIG_ENDIAN - __rev r4, r4 - __rev r5, r5 - __rev r6, r6 - __rev r7, r7 + rev_l r4, t0 + rev_l r5, t0 + rev_l r6, t0 + rev_l r7, t0 #endif ldr out, [sp] diff --git a/arch/arm/crypto/blake2b-neon-glue.c b/arch/arm/crypto/blake2b-neon-glue.c index 34d73200e7fa6eff750bb2ae5fe9a9017c24af0f..4b59d027ba4acde262603caecda9d11bd2a952f1 100644 --- a/arch/arm/crypto/blake2b-neon-glue.c +++ b/arch/arm/crypto/blake2b-neon-glue.c @@ -85,8 +85,8 @@ static int __init blake2b_neon_mod_init(void) static void __exit blake2b_neon_mod_exit(void) { - return crypto_unregister_shashes(blake2b_neon_algs, - ARRAY_SIZE(blake2b_neon_algs)); + crypto_unregister_shashes(blake2b_neon_algs, + ARRAY_SIZE(blake2b_neon_algs)); } module_init(blake2b_neon_mod_init); diff --git a/arch/arm/crypto/blake2s-core.S b/arch/arm/crypto/blake2s-core.S index bed897e9a181a1ae0c7104fdd7b73e34e4f74975..86345751bbf3a3d8a7e3af72684985833cf6734b 100644 --- a/arch/arm/crypto/blake2s-core.S +++ b/arch/arm/crypto/blake2s-core.S @@ -8,6 +8,7 @@ */ #include <linux/linkage.h> +#include <asm/assembler.h> // Registers used to hold message words temporarily. There aren't // enough ARM registers to hold the whole message block, so we have to @@ -38,6 +39,23 @@ #endif .endm +.macro _le32_bswap a, tmp +#ifdef __ARMEB__ + rev_l \a, \tmp +#endif +.endm + +.macro _le32_bswap_8x a, b, c, d, e, f, g, h, tmp + _le32_bswap \a, \tmp + _le32_bswap \b, \tmp + _le32_bswap \c, \tmp + _le32_bswap \d, \tmp + _le32_bswap \e, \tmp + _le32_bswap \f, \tmp + _le32_bswap \g, \tmp + _le32_bswap \h, \tmp +.endm + // Execute a quarter-round of BLAKE2s by mixing two columns or two diagonals. // (a0, b0, c0, d0) and (a1, b1, c1, d1) give the registers containing the two // columns/diagonals. s0-s1 are the word offsets to the message words the first @@ -180,8 +198,10 @@ ENTRY(blake2s_compress_arch) tst r1, #3 bne .Lcopy_block_misaligned ldmia r1!, {r2-r9} + _le32_bswap_8x r2, r3, r4, r5, r6, r7, r8, r9, r14 stmia r12!, {r2-r9} ldmia r1!, {r2-r9} + _le32_bswap_8x r2, r3, r4, r5, r6, r7, r8, r9, r14 stmia r12, {r2-r9} .Lcopy_block_done: str r1, [sp, #68] // Update message pointer @@ -268,6 +288,7 @@ ENTRY(blake2s_compress_arch) 1: #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ldr r3, [r1], #4 + _le32_bswap r3, r4 #else ldrb r3, [r1, #0] ldrb r4, [r1, #1] diff --git a/arch/arm/crypto/chacha-scalar-core.S b/arch/arm/crypto/chacha-scalar-core.S index 2985b80a45b57032b91785732df8a139616d6e4c..083fe1ab96d03fdce3de83e58381e557c96dfcf5 100644 --- a/arch/arm/crypto/chacha-scalar-core.S +++ b/arch/arm/crypto/chacha-scalar-core.S @@ -41,32 +41,15 @@ X14 .req r12 X15 .req r14 -.macro __rev out, in, t0, t1, t2 -.if __LINUX_ARM_ARCH__ >= 6 - rev \out, \in -.else - lsl \t0, \in, #24 - and \t1, \in, #0xff00 - and \t2, \in, #0xff0000 - orr \out, \t0, \in, lsr #24 - orr \out, \out, \t1, lsl #8 - orr \out, \out, \t2, lsr #8 -.endif -.endm - -.macro _le32_bswap x, t0, t1, t2 +.macro _le32_bswap_4x a, b, c, d, tmp #ifdef __ARMEB__ - __rev \x, \x, \t0, \t1, \t2 + rev_l \a, \tmp + rev_l \b, \tmp + rev_l \c, \tmp + rev_l \d, \tmp #endif .endm -.macro _le32_bswap_4x a, b, c, d, t0, t1, t2 - _le32_bswap \a, \t0, \t1, \t2 - _le32_bswap \b, \t0, \t1, \t2 - _le32_bswap \c, \t0, \t1, \t2 - _le32_bswap \d, \t0, \t1, \t2 -.endm - .macro __ldrd a, b, src, offset #if __LINUX_ARM_ARCH__ >= 6 ldrd \a, \b, [\src, #\offset] @@ -200,7 +183,7 @@ add X1, X1, r9 add X2, X2, r10 add X3, X3, r11 - _le32_bswap_4x X0, X1, X2, X3, r8, r9, r10 + _le32_bswap_4x X0, X1, X2, X3, r8 ldmia r12!, {r8-r11} eor X0, X0, r8 eor X1, X1, r9 @@ -216,7 +199,7 @@ ldmia r12!, {X0-X3} add X6, r10, X6, ror #brot add X7, r11, X7, ror #brot - _le32_bswap_4x X4, X5, X6, X7, r8, r9, r10 + _le32_bswap_4x X4, X5, X6, X7, r8 eor X4, X4, X0 eor X5, X5, X1 eor X6, X6, X2 @@ -231,7 +214,7 @@ add r1, r1, r9 // x9 add r6, r6, r10 // x10 add r7, r7, r11 // x11 - _le32_bswap_4x r0, r1, r6, r7, r8, r9, r10 + _le32_bswap_4x r0, r1, r6, r7, r8 ldmia r12!, {r8-r11} eor r0, r0, r8 // x8 eor r1, r1, r9 // x9 @@ -245,7 +228,7 @@ add r3, r9, r3, ror #drot // x13 add r4, r10, r4, ror #drot // x14 add r5, r11, r5, ror #drot // x15 - _le32_bswap_4x r2, r3, r4, r5, r9, r10, r11 + _le32_bswap_4x r2, r3, r4, r5, r9 ldr r9, [sp, #72] // load LEN eor r2, r2, r0 // x12 eor r3, r3, r1 // x13 @@ -301,7 +284,7 @@ add X1, X1, r9 add X2, X2, r10 add X3, X3, r11 - _le32_bswap_4x X0, X1, X2, X3, r8, r9, r10 + _le32_bswap_4x X0, X1, X2, X3, r8 stmia r14!, {X0-X3} // Save keystream for x4-x7 @@ -311,7 +294,7 @@ add X5, r9, X5, ror #brot add X6, r10, X6, ror #brot add X7, r11, X7, ror #brot - _le32_bswap_4x X4, X5, X6, X7, r8, r9, r10 + _le32_bswap_4x X4, X5, X6, X7, r8 add r8, sp, #64 stmia r14!, {X4-X7} @@ -323,7 +306,7 @@ add r1, r1, r9 // x9 add r6, r6, r10 // x10 add r7, r7, r11 // x11 - _le32_bswap_4x r0, r1, r6, r7, r8, r9, r10 + _le32_bswap_4x r0, r1, r6, r7, r8 stmia r14!, {r0,r1,r6,r7} __ldrd r8, r9, sp, 144 __ldrd r10, r11, sp, 152 @@ -331,7 +314,7 @@ add r3, r9, r3, ror #drot // x13 add r4, r10, r4, ror #drot // x14 add r5, r11, r5, ror #drot // x15 - _le32_bswap_4x r2, r3, r4, r5, r9, r10, r11 + _le32_bswap_4x r2, r3, r4, r5, r9 stmia r14, {r2-r5} // Stack: ks0-ks15 unused0-unused7 x0-x15 OUT IN LEN diff --git a/arch/arm/crypto/curve25519-core.S b/arch/arm/crypto/curve25519-core.S index be18af52e7dc9a5657af1a9a3acb50f56f66d8d3..b697fa5d059a2389b32b58ee1e7abff876da99c7 100644 --- a/arch/arm/crypto/curve25519-core.S +++ b/arch/arm/crypto/curve25519-core.S @@ -10,8 +10,8 @@ #include <linux/linkage.h> .text -.fpu neon .arch armv7-a +.fpu neon .align 4 ENTRY(curve25519_neon) diff --git a/arch/arm/crypto/poly1305-glue.c b/arch/arm/crypto/poly1305-glue.c index 3023c1acfa19475e2972ff47342ba958cb8b7ef3..c31bd8f7c0927e5226984b6573c3d4d76a1d445c 100644 --- a/arch/arm/crypto/poly1305-glue.c +++ b/arch/arm/crypto/poly1305-glue.c @@ -29,7 +29,7 @@ void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit) static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); -void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) +void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) { poly1305_init_arm(&dctx->h, key); dctx->s[0] = get_unaligned_le32(key + 16); diff --git a/arch/arm/include/asm/paravirt.h b/arch/arm/include/asm/paravirt.h index cdbf02d9c1d45ce0ea2c83d7d1ee2d1f2d05565f..95d5b0d625cd35ecf127180534098bfa6c5e3b40 100644 --- a/arch/arm/include/asm/paravirt.h +++ b/arch/arm/include/asm/paravirt.h @@ -3,23 +3,19 @@ #define _ASM_ARM_PARAVIRT_H #ifdef CONFIG_PARAVIRT +#include <linux/static_call_types.h> + struct static_key; extern struct static_key paravirt_steal_enabled; extern struct static_key paravirt_steal_rq_enabled; -struct pv_time_ops { - unsigned long long (*steal_clock)(int cpu); -}; - -struct paravirt_patch_template { - struct pv_time_ops time; -}; +u64 dummy_steal_clock(int cpu); -extern struct paravirt_patch_template pv_ops; +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); static inline u64 paravirt_steal_clock(int cpu) { - return pv_ops.time.steal_clock(cpu); + return static_call(pv_steal_clock)(cpu); } #endif diff --git a/arch/arm/include/asm/xen/swiotlb-xen.h b/arch/arm/include/asm/xen/swiotlb-xen.h new file mode 100644 index 0000000000000000000000000000000000000000..455ade5d53205465cc3b94888713f222c66213d0 --- /dev/null +++ b/arch/arm/include/asm/xen/swiotlb-xen.h @@ -0,0 +1 @@ +#include <xen/arm/swiotlb-xen.h> diff --git a/arch/arm/kernel/paravirt.c b/arch/arm/kernel/paravirt.c index 4cfed91fe256e5c94f6d6386f6673918ee593398..7dd9806369fb08217eeb4ef905ec15f134202cbf 100644 --- a/arch/arm/kernel/paravirt.c +++ b/arch/arm/kernel/paravirt.c @@ -9,10 +9,15 @@ #include <linux/export.h> #include <linux/jump_label.h> #include <linux/types.h> +#include <linux/static_call.h> #include <asm/paravirt.h> struct static_key paravirt_steal_enabled; struct static_key paravirt_steal_rq_enabled; -struct paravirt_patch_template pv_ops; -EXPORT_SYMBOL_GPL(pv_ops); +static u64 native_steal_clock(int cpu) +{ + return 0; +} + +DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 120f9aa6fff32578d439c4880d950ded86cd43a6..90dcdfe3b3d0d225a83b170ab4247e3872891e71 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -17,6 +17,8 @@ #include <linux/clk/at91_pmc.h> #include <linux/platform_data/atmel.h> +#include <soc/at91/pm.h> + #include <asm/cacheflush.h> #include <asm/fncpy.h> #include <asm/system_misc.h> @@ -25,17 +27,6 @@ #include "generic.h" #include "pm.h" -/* - * FIXME: this is needed to communicate between the pinctrl driver and - * the PM implementation in the machine. Possibly part of the PM - * implementation should be moved down into the pinctrl driver and get - * called as part of the generic suspend/resume path. - */ -#ifdef CONFIG_PINCTRL_AT91 -extern void at91_pinctrl_gpio_suspend(void); -extern void at91_pinctrl_gpio_resume(void); -#endif - struct at91_soc_pm { int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity); int (*config_pmc_ws)(void __iomem *pmc, u32 mode, u32 polarity); @@ -326,6 +317,12 @@ static void at91_pm_suspend(suspend_state_t state) static int at91_pm_enter(suspend_state_t state) { #ifdef CONFIG_PINCTRL_AT91 + /* + * FIXME: this is needed to communicate between the pinctrl driver and + * the PM implementation in the machine. Possibly part of the PM + * implementation should be moved down into the pinctrl driver and get + * called as part of the generic suspend/resume path. + */ at91_pinctrl_gpio_suspend(); #endif diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index ea0be59f469aefa9c80b68455500f0f5dd8f1ff2..fb4a394ece3a04b22bd02c63ef23fc0c15c7dcff 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -78,12 +78,11 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) #endif /* CONFIG_HOTPLUG_CPU */ /** - * exynos_core_power_down : power down the specified cpu - * @cpu : the cpu to power down + * exynos_cpu_power_down() - power down the specified cpu + * @cpu: the cpu to power down * * Power down the specified cpu. The sequence must be finished by a * call to cpu_do_idle() - * */ void exynos_cpu_power_down(int cpu) { @@ -107,8 +106,8 @@ void exynos_cpu_power_down(int cpu) } /** - * exynos_cpu_power_up : power up the specified cpu - * @cpu : the cpu to power up + * exynos_cpu_power_up() - power up the specified cpu + * @cpu: the cpu to power up * * Power up the specified cpu */ @@ -124,9 +123,8 @@ void exynos_cpu_power_up(int cpu) } /** - * exynos_cpu_power_state : returns the power state of the cpu - * @cpu : the cpu to retrieve the power state from - * + * exynos_cpu_power_state() - returns the power state of the cpu + * @cpu: the cpu to retrieve the power state from */ int exynos_cpu_power_state(int cpu) { @@ -135,8 +133,8 @@ int exynos_cpu_power_state(int cpu) } /** - * exynos_cluster_power_down : power down the specified cluster - * @cluster : the cluster to power down + * exynos_cluster_power_down() - power down the specified cluster + * @cluster: the cluster to power down */ void exynos_cluster_power_down(int cluster) { @@ -144,8 +142,8 @@ void exynos_cluster_power_down(int cluster) } /** - * exynos_cluster_power_up : power up the specified cluster - * @cluster : the cluster to power up + * exynos_cluster_power_up() - power up the specified cluster + * @cluster: the cluster to power up */ void exynos_cluster_power_up(int cluster) { @@ -154,8 +152,8 @@ void exynos_cluster_power_up(int cluster) } /** - * exynos_cluster_power_state : returns the power state of the cluster - * @cluster : the cluster to retrieve the power state from + * exynos_cluster_power_state() - returns the power state of the cluster + * @cluster: the cluster to retrieve the power state from * */ int exynos_cluster_power_state(int cluster) @@ -165,7 +163,7 @@ int exynos_cluster_power_state(int cluster) } /** - * exynos_scu_enable : enables SCU for Cortex-A9 based system + * exynos_scu_enable() - enables SCU for Cortex-A9 based system */ void exynos_scu_enable(void) { diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c index 07ea28b99cd0ce431e258f9ed588e2100003b7f8..b8d14b369cc9fa41c1a248e1ed9fb76208fc707c 100644 --- a/arch/arm/mach-hisi/hisilicon.c +++ b/arch/arm/mach-hisi/hisilicon.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * (Hisilicon's SoC based) flattened device tree enabled machine + * (HiSilicon's SoC based) flattened device tree enabled machine * - * Copyright (c) 2012-2013 Hisilicon Ltd. + * Copyright (c) 2012-2013 HiSilicon Ltd. * Copyright (c) 2012-2013 Linaro Ltd. * * Author: Haojian Zhuang <haojian.zhuang@linaro.org> diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c index 5c5f255abc3adde8d9bdc4208d227e98ceb29cbf..c517941416f19ad12ad97ff02d07eb9fd54a903f 100644 --- a/arch/arm/mach-hisi/hotplug.c +++ b/arch/arm/mach-hisi/hotplug.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Linaro Ltd. - * Copyright (c) 2013 Hisilicon Limited. + * Copyright (c) 2013 HiSilicon Limited. */ #include <linux/cpu.h> diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c index f155e32f8420e2a777b37b77543ccd839e953cc3..96a484095194db4e24a68eabdaf1bd928a1f9c37 100644 --- a/arch/arm/mach-hisi/platmcpm.c +++ b/arch/arm/mach-hisi/platmcpm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2014 Linaro Ltd. - * Copyright (c) 2013-2014 Hisilicon Limited. + * Copyright (c) 2013-2014 HiSilicon Limited. */ #include <linux/init.h> #include <linux/smp.h> diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c index da7a09c1dae56f34c79720819fed22a9de3fe9d6..a56cc64deeb8ff8a8bd5267f5d6fbc74c58f2b1e 100644 --- a/arch/arm/mach-hisi/platsmp.c +++ b/arch/arm/mach-hisi/platsmp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Linaro Ltd. - * Copyright (c) 2013 Hisilicon Limited. + * Copyright (c) 2013 HiSilicon Limited. * Based on arch/arm/mach-vexpress/platsmp.c, Copyright (C) 2002 ARM Ltd. */ #include <linux/smp.h> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 52902782cc5f40111395b9bb918968bc7a429713..b407b024dde34b0846ff48081f8637c7a2980c59 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -63,7 +63,7 @@ config SOC_IMX35 select MXC_AVIC select PINCTRL_IMX35 help - This enables support for Freescale i.MX31 processor + This enables support for Freescale i.MX35 processor endif diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index e9962b48e30cbd2db797cf9bb452b452ca93dfe3..2e3af2bc7758e0eb3a4597e35e2e0e7c1704c0c5 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -45,7 +45,7 @@ * This is also the lowest power state possible without affecting * non-cpu parts of the system. For these reasons, imx5 should default * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also - * uses this state and needs to take no action when registers remain confgiured + * uses this state and needs to take no action when registers remain configured * for this state. */ #define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF diff --git a/arch/arm/mach-mstar/Kconfig b/arch/arm/mach-mstar/Kconfig index 576d1ab293c8734c587d2dd2d918c21358fbf874..cd300eeedc2067f06e5652e10cb50aecc1cb0f97 100644 --- a/arch/arm/mach-mstar/Kconfig +++ b/arch/arm/mach-mstar/Kconfig @@ -4,6 +4,7 @@ menuconfig ARCH_MSTARV7 select ARM_GIC select ARM_HEAVY_MB select MST_IRQ + select MSTAR_MSC313_MPLL help Support for newer MStar/Sigmastar SoC families that are based on Armv7 cores like the Cortex A7 and share the same diff --git a/arch/arm/mach-npcm/Kconfig b/arch/arm/mach-npcm/Kconfig index 7f7002dc2b21fec89afd25529c87d7ca16630cf2..658c8efb4ca1445891c370aad48ff924658537d5 100644 --- a/arch/arm/mach-npcm/Kconfig +++ b/arch/arm/mach-npcm/Kconfig @@ -1,11 +1,21 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig ARCH_NPCM bool "Nuvoton NPCM Architecture" - depends on ARCH_MULTI_V7 + depends on ARCH_MULTI_V5 || ARCH_MULTI_V7 select PINCTRL if ARCH_NPCM +config ARCH_WPCM450 + bool "Support for WPCM450 BMC (Hermon)" + depends on ARCH_MULTI_V5 + select CPU_ARM926T + select NPCM7XX_TIMER + help + General support for WPCM450 BMC (Hermon). + + Winbond/Nuvoton WPCM450 BMC based on the ARM926EJ-S. + config ARCH_NPCM7XX bool "Support for NPCM7xx BMC (Poleg)" depends on ARCH_MULTI_V7 diff --git a/arch/arm/mach-npcm/Makefile b/arch/arm/mach-npcm/Makefile index 1bc3a70bfab8b79b78f34529a8a9645f9acb3336..8d61fcd42fb1988c5fb9d0dcbdba2d9d99bdbe97 100644 --- a/arch/arm/mach-npcm/Makefile +++ b/arch/arm/mach-npcm/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only AFLAGS_headsmp.o += -march=armv7-a +obj-$(CONFIG_ARCH_WPCM450) += wpcm450.o obj-$(CONFIG_ARCH_NPCM7XX) += npcm7xx.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/arch/arm/mach-npcm/wpcm450.c b/arch/arm/mach-npcm/wpcm450.c new file mode 100644 index 0000000000000000000000000000000000000000..f17b3dab45af323221beba8445444acaca77cb65 --- /dev/null +++ b/arch/arm/mach-npcm/wpcm450.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2021 Jonathan Neuschäfer + +#include <asm/mach/arch.h> + +static const char *const wpcm450_dt_match[] = { + "nuvoton,wpcm450", + NULL +}; + +DT_MACHINE_START(WPCM450_DT, "WPCM450 chip") + .dt_compat = wpcm450_dt_match, +MACHINE_END diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c index 97fc2096b9709104cdb4a539cd6bfdca10563543..0411d5508d63709ad42f87b92e8767f644435967 100644 --- a/arch/arm/mach-omap1/timer.c +++ b/arch/arm/mach-omap1/timer.c @@ -1,4 +1,4 @@ -/** +/* * OMAP1 Dual-Mode Timers - platform device registration * * Contains first level initialization routines which internally diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 4178c0ee46eba5a63ee33f8923ea431268a76ced..7df8f5276ddf5fddaa86cb7b69d51951e6d8a6f2 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -34,7 +34,6 @@ config ARCH_OMAP4 select ARM_GIC select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP - select OMAP_HWMOD select OMAP_INTERCONNECT select OMAP_INTERCONNECT_BARRIER select PL310_ERRATA_588369 if CACHE_L2X0 @@ -54,7 +53,6 @@ config SOC_OMAP5 select HAVE_ARM_SCU if SMP select HAVE_ARM_ARCH_TIMER select ARM_ERRATA_798181 if SMP - select OMAP_HWMOD select OMAP_INTERCONNECT select OMAP_INTERCONNECT_BARRIER select PM_OPP @@ -90,7 +88,6 @@ config SOC_DRA7XX select HAVE_ARM_ARCH_TIMER select IRQ_CROSSBAR select ARM_ERRATA_798181 if SMP - select OMAP_HWMOD select OMAP_INTERCONNECT select OMAP_INTERCONNECT_BARRIER select PM_OPP diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 9bcfb34a22064752372ad241b09f734733152fde..8306ad686bc8ed6b135148883d7566f7863afdfc 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -20,14 +20,14 @@ secure-common = omap-smc.o omap-secure.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common) -obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common) $(secure-common) +obj-$(CONFIG_ARCH_OMAP4) += $(secure-common) obj-$(CONFIG_SOC_AM33XX) += $(secure-common) -obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common) +obj-$(CONFIG_SOC_OMAP5) += $(secure-common) obj-$(CONFIG_SOC_AM43XX) += $(secure-common) -obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common) +obj-$(CONFIG_SOC_DRA7XX) += $(secure-common) ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),) -obj-y += mcbsp.o +obj-$(CONFIG_OMAP_HWMOD) += mcbsp.o endif obj-$(CONFIG_TWL4030_CORE) += omap_twl.o @@ -207,9 +207,6 @@ obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2430_data.o obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_ipblock_data.o obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_3xxx_data.o obj-$(CONFIG_SOC_TI81XX) += omap_hwmod_81xx_data.o -obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o -obj-$(CONFIG_SOC_OMAP5) += omap_hwmod_54xx_data.o -obj-$(CONFIG_SOC_DRA7XX) += omap_hwmod_7xx_data.o # OMAP2420 MSDI controller integration support ("MMC") obj-$(CONFIG_SOC_OMAP2420) += msdi.o diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 49926eced5f1aca0cc6f1a318ae08900abfb1e39..db446f271f5d858d4e6cf8b1bb9454fa9a58489a 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -343,15 +343,6 @@ static inline void omap5_secondary_hyp_startup(void) } #endif -#ifdef CONFIG_SOC_DRA7XX -extern int dra7xx_pciess_reset(struct omap_hwmod *oh); -#else -static inline int dra7xx_pciess_reset(struct omap_hwmod *oh) -{ - return 0; -} -#endif - struct omap_system_dma_plat_info; void pdata_quirks_init(const struct of_device_id *); diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 060ba6957b7c838cea5c3030c3f220b2cab08a1e..fba0c7aa398cc5e96646f2f79ac9aba544f92378 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -402,6 +402,7 @@ static int __init _omap2_init_reprogram_sdrc(void) return v; } +#ifdef CONFIG_OMAP_HWMOD static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data) { return omap_hwmod_set_postsetup_state(oh, *(u8 *)data); @@ -414,6 +415,11 @@ static void __init __maybe_unused omap_hwmod_init_postsetup(void) /* Set the default postsetup state for all hwmods */ omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state); } +#else +static inline void omap_hwmod_init_postsetup(void) +{ +} +#endif #ifdef CONFIG_SOC_OMAP2420 void __init omap2420_init_early(void) @@ -615,8 +621,6 @@ void __init omap4430_init_early(void) omap44xx_voltagedomains_init(); omap44xx_powerdomains_init(); omap44xx_clockdomains_init(); - omap44xx_hwmod_init(); - omap_hwmod_init_postsetup(); omap_l2_cache_init(); omap_clk_soc_init = omap4xxx_dt_clk_init; omap_secure_init(); @@ -643,8 +647,6 @@ void __init omap5_init_early(void) omap54xx_voltagedomains_init(); omap54xx_powerdomains_init(); omap54xx_clockdomains_init(); - omap54xx_hwmod_init(); - omap_hwmod_init_postsetup(); omap_clk_soc_init = omap5xxx_dt_clk_init; omap_secure_init(); } @@ -667,8 +669,6 @@ void __init dra7xx_init_early(void) dra7xxx_check_revision(); dra7xx_powerdomains_init(); dra7xx_clockdomains_init(); - dra7xx_hwmod_init(); - omap_hwmod_init_postsetup(); omap_clk_soc_init = dra7xx_dt_clk_init; omap_secure_init(); } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 2310cd56e99b55247b2d9ec2d491a4d411a5d355..65934b2924fb5115dc91d5299e017b66279df808 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2137,6 +2137,7 @@ static int of_dev_hwmod_lookup(struct device_node *np, if (res == 0) { *found = fc; *index = i; + of_node_put(np0); return 0; } } @@ -3495,10 +3496,6 @@ static const struct omap_hwmod_reset omap24xx_reset_quirks[] = { { .match = "msdi", .len = 4, .reset = omap_msdi_reset, }, }; -static const struct omap_hwmod_reset dra7_reset_quirks[] = { - { .match = "pcie", .len = 4, .reset = dra7xx_pciess_reset, }, -}; - static const struct omap_hwmod_reset omap_reset_quirks[] = { { .match = "dss_core", .len = 8, .reset = omap_dss_reset, }, { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, }, @@ -3534,10 +3531,6 @@ omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh, omap24xx_reset_quirks, ARRAY_SIZE(omap24xx_reset_quirks)); - if (soc_is_dra7xx()) - omap_hwmod_init_reset_quirk(dev, oh, data, dra7_reset_quirks, - ARRAY_SIZE(dra7_reset_quirks)); - omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks, ARRAY_SIZE(omap_reset_quirks)); } diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index eebf2fdf434cde54b738ef6aa70e1fac14be4e37..6962a8d267e7c210d32a2ac1f64a3d7209b174f0 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -607,6 +607,8 @@ struct omap_hwmod { struct omap_hwmod *parent_hwmod; }; +#ifdef CONFIG_OMAP_HWMOD + struct device_node; struct omap_hwmod *omap_hwmod_lookup(const char *name); @@ -656,6 +658,17 @@ extern void __init omap_hwmod_init(void); const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh); +#else /* CONFIG_OMAP_HWMOD */ + +static inline int +omap_hwmod_for_each_by_class(const char *classname, + int (*fn)(struct omap_hwmod *oh, void *user), + void *user) +{ + return 0; +} +#endif /* CONFIG_OMAP_HWMOD */ + /* * */ @@ -671,7 +684,6 @@ extern int omap2420_hwmod_init(void); extern int omap2430_hwmod_init(void); extern int omap3xxx_hwmod_init(void); extern int omap44xx_hwmod_init(void); -extern int omap54xx_hwmod_init(void); extern int am33xx_hwmod_init(void); extern int dm814x_hwmod_init(void); extern int dm816x_hwmod_init(void); diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c deleted file mode 100644 index 6aa3b8e81a0cfe4a459a6952f832723d1573baba..0000000000000000000000000000000000000000 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ /dev/null @@ -1,877 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Hardware modules present on the OMAP44xx chips - * - * Copyright (C) 2009-2012 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Paul Walmsley - * Benoit Cousson - * - * This file is automatically generated from the OMAP hardware databases. - * We respectfully ask that any modifications to this file be coordinated - * with the public linux-omap@vger.kernel.org mailing list and the - * authors above to ensure that the autogeneration scripts are kept - * up-to-date with the file contents. - * Note that this file is currently not in sync with autogeneration scripts. - * The above note to be removed, once it is synced up. - */ - -#include <linux/io.h> - -#include "omap_hwmod.h" -#include "omap_hwmod_common_data.h" -#include "cm1_44xx.h" -#include "cm2_44xx.h" -#include "prm44xx.h" -#include "prm-regbits-44xx.h" - -/* Base offset for all OMAP4 interrupts external to MPUSS */ -#define OMAP44XX_IRQ_GIC_START 32 - -/* - * IP blocks - */ - -/* - * 'dmm' class - * instance(s): dmm - */ -static struct omap_hwmod_class omap44xx_dmm_hwmod_class = { - .name = "dmm", -}; - -/* dmm */ -static struct omap_hwmod omap44xx_dmm_hwmod = { - .name = "dmm", - .class = &omap44xx_dmm_hwmod_class, - .clkdm_name = "l3_emif_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_MEMIF_DMM_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'l3' class - * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3 - */ -static struct omap_hwmod_class omap44xx_l3_hwmod_class = { - .name = "l3", -}; - -/* l3_instr */ -static struct omap_hwmod omap44xx_l3_instr_hwmod = { - .name = "l3_instr", - .class = &omap44xx_l3_hwmod_class, - .clkdm_name = "l3_instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* l3_main_1 */ -static struct omap_hwmod omap44xx_l3_main_1_hwmod = { - .name = "l3_main_1", - .class = &omap44xx_l3_hwmod_class, - .clkdm_name = "l3_1_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET, - }, - }, -}; - -/* l3_main_2 */ -static struct omap_hwmod omap44xx_l3_main_2_hwmod = { - .name = "l3_main_2", - .class = &omap44xx_l3_hwmod_class, - .clkdm_name = "l3_2_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L3_2_L3_2_CONTEXT_OFFSET, - }, - }, -}; - -/* l3_main_3 */ -static struct omap_hwmod omap44xx_l3_main_3_hwmod = { - .name = "l3_main_3", - .class = &omap44xx_l3_hwmod_class, - .clkdm_name = "l3_instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L3INSTR_L3_3_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* - * 'l4' class - * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup - */ -static struct omap_hwmod_class omap44xx_l4_hwmod_class = { - .name = "l4", -}; - -/* l4_cfg */ -static struct omap_hwmod omap44xx_l4_cfg_hwmod = { - .name = "l4_cfg", - .class = &omap44xx_l4_hwmod_class, - .clkdm_name = "l4_cfg_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L4CFG_L4_CFG_CONTEXT_OFFSET, - }, - }, -}; - -/* l4_per */ -static struct omap_hwmod omap44xx_l4_per_hwmod = { - .name = "l4_per", - .class = &omap44xx_l4_hwmod_class, - .clkdm_name = "l4_per_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L4PER_L4_PER_CONTEXT_OFFSET, - }, - }, -}; - -/* l4_wkup */ -static struct omap_hwmod omap44xx_l4_wkup_hwmod = { - .name = "l4_wkup", - .class = &omap44xx_l4_hwmod_class, - .clkdm_name = "l4_wkup_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_WKUP_L4WKUP_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_WKUP_L4WKUP_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'mpu_bus' class - * instance(s): mpu_private - */ -static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = { - .name = "mpu_bus", -}; - -/* mpu_private */ -static struct omap_hwmod omap44xx_mpu_private_hwmod = { - .name = "mpu_private", - .class = &omap44xx_mpu_bus_hwmod_class, - .clkdm_name = "mpuss_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* - * 'ocp_wp_noc' class - * instance(s): ocp_wp_noc - */ -static struct omap_hwmod_class omap44xx_ocp_wp_noc_hwmod_class = { - .name = "ocp_wp_noc", -}; - -/* ocp_wp_noc */ -static struct omap_hwmod omap44xx_ocp_wp_noc_hwmod = { - .name = "ocp_wp_noc", - .class = &omap44xx_ocp_wp_noc_hwmod_class, - .clkdm_name = "l3_instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L3INSTR_OCP_WP1_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* - * Modules omap_hwmod structures - * - * The following IPs are excluded for the moment because: - * - They do not need an explicit SW control using omap_hwmod API. - * - They still need to be validated with the driver - * properly adapted to omap_hwmod / omap_device - * - * usim - */ - -/* - * 'ctrl_module' class - * attila core control module + core pad control module + wkup pad control - * module + attila wkup control module - */ - -static struct omap_hwmod_class_sysconfig omap44xx_ctrl_module_sysc = { - .rev_offs = 0x0000, - .sysc_offs = 0x0010, - .sysc_flags = SYSC_HAS_SIDLEMODE, - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP), - .sysc_fields = &omap_hwmod_sysc_type2, -}; - -static struct omap_hwmod_class omap44xx_ctrl_module_hwmod_class = { - .name = "ctrl_module", - .sysc = &omap44xx_ctrl_module_sysc, -}; - -/* ctrl_module_core */ -static struct omap_hwmod omap44xx_ctrl_module_core_hwmod = { - .name = "ctrl_module_core", - .class = &omap44xx_ctrl_module_hwmod_class, - .clkdm_name = "l4_cfg_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* ctrl_module_pad_core */ -static struct omap_hwmod omap44xx_ctrl_module_pad_core_hwmod = { - .name = "ctrl_module_pad_core", - .class = &omap44xx_ctrl_module_hwmod_class, - .clkdm_name = "l4_cfg_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* ctrl_module_wkup */ -static struct omap_hwmod omap44xx_ctrl_module_wkup_hwmod = { - .name = "ctrl_module_wkup", - .class = &omap44xx_ctrl_module_hwmod_class, - .clkdm_name = "l4_wkup_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* ctrl_module_pad_wkup */ -static struct omap_hwmod omap44xx_ctrl_module_pad_wkup_hwmod = { - .name = "ctrl_module_pad_wkup", - .class = &omap44xx_ctrl_module_hwmod_class, - .clkdm_name = "l4_wkup_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* - * 'debugss' class - * debug and emulation sub system - */ - -static struct omap_hwmod_class omap44xx_debugss_hwmod_class = { - .name = "debugss", -}; - -/* debugss */ -static struct omap_hwmod omap44xx_debugss_hwmod = { - .name = "debugss", - .class = &omap44xx_debugss_hwmod_class, - .clkdm_name = "emu_sys_clkdm", - .main_clk = "trace_clk_div_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_EMU_DEBUGSS_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_EMU_DEBUGSS_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'emif' class - * external memory interface no1 - */ - -static struct omap_hwmod_class_sysconfig omap44xx_emif_sysc = { - .rev_offs = 0x0000, -}; - -static struct omap_hwmod_class omap44xx_emif_hwmod_class = { - .name = "emif", - .sysc = &omap44xx_emif_sysc, -}; - -/* emif1 */ -static struct omap_hwmod omap44xx_emif1_hwmod = { - .name = "emif1", - .class = &omap44xx_emif_hwmod_class, - .clkdm_name = "l3_emif_clkdm", - .flags = HWMOD_INIT_NO_IDLE, - .main_clk = "ddrphy_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_MEMIF_EMIF_1_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_MEMIF_EMIF_1_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* emif2 */ -static struct omap_hwmod omap44xx_emif2_hwmod = { - .name = "emif2", - .class = &omap44xx_emif_hwmod_class, - .clkdm_name = "l3_emif_clkdm", - .flags = HWMOD_INIT_NO_IDLE, - .main_clk = "ddrphy_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_MEMIF_EMIF_2_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_MEMIF_EMIF_2_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* - * 'iss' class - * external images sensor pixel data processor - */ - -static struct omap_hwmod_class_sysconfig omap44xx_iss_sysc = { - .rev_offs = 0x0000, - .sysc_offs = 0x0010, - /* - * ISS needs 100 OCP clk cycles delay after a softreset before - * accessing sysconfig again. - * The lowest frequency at the moment for L3 bus is 100 MHz, so - * 1usec delay is needed. Add an x2 margin to be safe (2 usecs). - * - * TODO: Indicate errata when available. - */ - .srst_udelay = 2, - .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS | - SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET), - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO | - MSTANDBY_SMART | MSTANDBY_SMART_WKUP), - .sysc_fields = &omap_hwmod_sysc_type2, -}; - -static struct omap_hwmod_class omap44xx_iss_hwmod_class = { - .name = "iss", - .sysc = &omap44xx_iss_sysc, -}; - -/* iss */ -static struct omap_hwmod_opt_clk iss_opt_clks[] = { - { .role = "ctrlclk", .clk = "iss_ctrlclk" }, -}; - -static struct omap_hwmod omap44xx_iss_hwmod = { - .name = "iss", - .class = &omap44xx_iss_hwmod_class, - .clkdm_name = "iss_clkdm", - .main_clk = "ducati_clk_mux_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_CAM_ISS_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, - .opt_clks = iss_opt_clks, - .opt_clks_cnt = ARRAY_SIZE(iss_opt_clks), -}; - -/* - * 'mpu' class - * mpu sub-system - */ - -static struct omap_hwmod_class omap44xx_mpu_hwmod_class = { - .name = "mpu", -}; - -/* mpu */ -static struct omap_hwmod omap44xx_mpu_hwmod = { - .name = "mpu", - .class = &omap44xx_mpu_hwmod_class, - .clkdm_name = "mpuss_clkdm", - .flags = HWMOD_INIT_NO_IDLE, - .main_clk = "dpll_mpu_m2_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'ocmc_ram' class - * top-level core on-chip ram - */ - -static struct omap_hwmod_class omap44xx_ocmc_ram_hwmod_class = { - .name = "ocmc_ram", -}; - -/* ocmc_ram */ -static struct omap_hwmod omap44xx_ocmc_ram_hwmod = { - .name = "ocmc_ram", - .class = &omap44xx_ocmc_ram_hwmod_class, - .clkdm_name = "l3_2_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_L3_2_OCMC_RAM_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_L3_2_OCMC_RAM_CONTEXT_OFFSET, - }, - }, -}; - - -/* - * 'prcm' class - * power and reset manager (part of the prcm infrastructure) + clock manager 2 - * + clock manager 1 (in always on power domain) + local prm in mpu - */ - -static struct omap_hwmod_class omap44xx_prcm_hwmod_class = { - .name = "prcm", -}; - -/* prcm_mpu */ -static struct omap_hwmod omap44xx_prcm_mpu_hwmod = { - .name = "prcm_mpu", - .class = &omap44xx_prcm_hwmod_class, - .clkdm_name = "l4_wkup_clkdm", - .flags = HWMOD_NO_IDLEST, - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* cm_core_aon */ -static struct omap_hwmod omap44xx_cm_core_aon_hwmod = { - .name = "cm_core_aon", - .class = &omap44xx_prcm_hwmod_class, - .flags = HWMOD_NO_IDLEST, - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* cm_core */ -static struct omap_hwmod omap44xx_cm_core_hwmod = { - .name = "cm_core", - .class = &omap44xx_prcm_hwmod_class, - .flags = HWMOD_NO_IDLEST, - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* prm */ -static struct omap_hwmod_rst_info omap44xx_prm_resets[] = { - { .name = "rst_global_warm_sw", .rst_shift = 0 }, - { .name = "rst_global_cold_sw", .rst_shift = 1 }, -}; - -static struct omap_hwmod omap44xx_prm_hwmod = { - .name = "prm", - .class = &omap44xx_prcm_hwmod_class, - .rst_lines = omap44xx_prm_resets, - .rst_lines_cnt = ARRAY_SIZE(omap44xx_prm_resets), -}; - -/* - * 'scrm' class - * system clock and reset manager - */ - -static struct omap_hwmod_class omap44xx_scrm_hwmod_class = { - .name = "scrm", -}; - -/* scrm */ -static struct omap_hwmod omap44xx_scrm_hwmod = { - .name = "scrm", - .class = &omap44xx_scrm_hwmod_class, - .clkdm_name = "l4_wkup_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* - * 'sl2if' class - * shared level 2 memory interface - */ - -static struct omap_hwmod_class omap44xx_sl2if_hwmod_class = { - .name = "sl2if", -}; - -/* sl2if */ -static struct omap_hwmod omap44xx_sl2if_hwmod = { - .name = "sl2if", - .class = &omap44xx_sl2if_hwmod_class, - .clkdm_name = "ivahd_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET, - .context_offs = OMAP4_RM_IVAHD_SL2_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* - * interfaces - */ - -/* l3_main_1 -> dmm */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = { - .master = &omap44xx_l3_main_1_hwmod, - .slave = &omap44xx_dmm_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_SDMA, -}; - -/* mpu -> dmm */ -static struct omap_hwmod_ocp_if omap44xx_mpu__dmm = { - .master = &omap44xx_mpu_hwmod, - .slave = &omap44xx_dmm_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU, -}; - -/* l3_main_3 -> l3_instr */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_3__l3_instr = { - .master = &omap44xx_l3_main_3_hwmod, - .slave = &omap44xx_l3_instr_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* ocp_wp_noc -> l3_instr */ -static struct omap_hwmod_ocp_if omap44xx_ocp_wp_noc__l3_instr = { - .master = &omap44xx_ocp_wp_noc_hwmod, - .slave = &omap44xx_l3_instr_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> l3_main_1 */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = { - .master = &omap44xx_l3_main_2_hwmod, - .slave = &omap44xx_l3_main_1_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> l3_main_1 */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_l3_main_1_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> l3_main_1 */ -static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = { - .master = &omap44xx_mpu_hwmod, - .slave = &omap44xx_l3_main_1_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU, -}; - -/* debugss -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap44xx_debugss__l3_main_2 = { - .master = &omap44xx_debugss_hwmod, - .slave = &omap44xx_l3_main_2_hwmod, - .clk = "dbgclk_mux_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* iss -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = { - .master = &omap44xx_iss_hwmod, - .slave = &omap44xx_l3_main_2_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = { - .master = &omap44xx_l3_main_1_hwmod, - .slave = &omap44xx_l3_main_2_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU, -}; - -/* l4_cfg -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_l3_main_2_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l3_main_3 */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = { - .master = &omap44xx_l3_main_1_hwmod, - .slave = &omap44xx_l3_main_3_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU, -}; - -/* l3_main_2 -> l3_main_3 */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_3 = { - .master = &omap44xx_l3_main_2_hwmod, - .slave = &omap44xx_l3_main_3_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> l3_main_3 */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_l3_main_3_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_cfg */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = { - .master = &omap44xx_l3_main_1_hwmod, - .slave = &omap44xx_l4_cfg_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> l4_per */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = { - .master = &omap44xx_l3_main_2_hwmod, - .slave = &omap44xx_l4_per_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> l4_wkup */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_l4_wkup_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> mpu_private */ -static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = { - .master = &omap44xx_mpu_hwmod, - .slave = &omap44xx_mpu_private_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> ocp_wp_noc */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ocp_wp_noc = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_ocp_wp_noc_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> ctrl_module_core */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_core = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_ctrl_module_core_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> ctrl_module_pad_core */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_pad_core = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_ctrl_module_pad_core_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_wkup -> ctrl_module_wkup */ -static struct omap_hwmod_ocp_if omap44xx_l4_wkup__ctrl_module_wkup = { - .master = &omap44xx_l4_wkup_hwmod, - .slave = &omap44xx_ctrl_module_wkup_hwmod, - .clk = "l4_wkup_clk_mux_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_wkup -> ctrl_module_pad_wkup */ -static struct omap_hwmod_ocp_if omap44xx_l4_wkup__ctrl_module_pad_wkup = { - .master = &omap44xx_l4_wkup_hwmod, - .slave = &omap44xx_ctrl_module_pad_wkup_hwmod, - .clk = "l4_wkup_clk_mux_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_instr -> debugss */ -static struct omap_hwmod_ocp_if omap44xx_l3_instr__debugss = { - .master = &omap44xx_l3_instr_hwmod, - .slave = &omap44xx_debugss_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> iss */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iss = { - .master = &omap44xx_l3_main_2_hwmod, - .slave = &omap44xx_iss_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> ocmc_ram */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ocmc_ram = { - .master = &omap44xx_l3_main_2_hwmod, - .slave = &omap44xx_ocmc_ram_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu_private -> prcm_mpu */ -static struct omap_hwmod_ocp_if omap44xx_mpu_private__prcm_mpu = { - .master = &omap44xx_mpu_private_hwmod, - .slave = &omap44xx_prcm_mpu_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_wkup -> cm_core_aon */ -static struct omap_hwmod_ocp_if omap44xx_l4_wkup__cm_core_aon = { - .master = &omap44xx_l4_wkup_hwmod, - .slave = &omap44xx_cm_core_aon_hwmod, - .clk = "l4_wkup_clk_mux_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> cm_core */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__cm_core = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_cm_core_hwmod, - .clk = "l4_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_wkup -> prm */ -static struct omap_hwmod_ocp_if omap44xx_l4_wkup__prm = { - .master = &omap44xx_l4_wkup_hwmod, - .slave = &omap44xx_prm_hwmod, - .clk = "l4_wkup_clk_mux_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_wkup -> scrm */ -static struct omap_hwmod_ocp_if omap44xx_l4_wkup__scrm = { - .master = &omap44xx_l4_wkup_hwmod, - .slave = &omap44xx_scrm_hwmod, - .clk = "l4_wkup_clk_mux_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> sl2if */ -static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l3_main_2__sl2if = { - .master = &omap44xx_l3_main_2_hwmod, - .slave = &omap44xx_sl2if_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> emif1 */ -static struct omap_hwmod_ocp_if omap44xx_mpu__emif1 = { - .master = &omap44xx_mpu_hwmod, - .slave = &omap44xx_emif1_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> emif2 */ -static struct omap_hwmod_ocp_if omap44xx_mpu__emif2 = { - .master = &omap44xx_mpu_hwmod, - .slave = &omap44xx_emif2_hwmod, - .clk = "l3_div_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = { - &omap44xx_l3_main_1__dmm, - &omap44xx_mpu__dmm, - &omap44xx_l3_main_3__l3_instr, - &omap44xx_ocp_wp_noc__l3_instr, - &omap44xx_l3_main_2__l3_main_1, - &omap44xx_l4_cfg__l3_main_1, - &omap44xx_mpu__l3_main_1, - &omap44xx_debugss__l3_main_2, - &omap44xx_iss__l3_main_2, - &omap44xx_l3_main_1__l3_main_2, - &omap44xx_l4_cfg__l3_main_2, - &omap44xx_l3_main_1__l3_main_3, - &omap44xx_l3_main_2__l3_main_3, - &omap44xx_l4_cfg__l3_main_3, - &omap44xx_l3_main_1__l4_cfg, - &omap44xx_l3_main_2__l4_per, - &omap44xx_l4_cfg__l4_wkup, - &omap44xx_mpu__mpu_private, - &omap44xx_l4_cfg__ocp_wp_noc, - &omap44xx_l4_cfg__ctrl_module_core, - &omap44xx_l4_cfg__ctrl_module_pad_core, - &omap44xx_l4_wkup__ctrl_module_wkup, - &omap44xx_l4_wkup__ctrl_module_pad_wkup, - &omap44xx_l3_instr__debugss, - &omap44xx_l3_main_2__iss, - &omap44xx_l3_main_2__ocmc_ram, - &omap44xx_mpu_private__prcm_mpu, - &omap44xx_l4_wkup__cm_core_aon, - &omap44xx_l4_cfg__cm_core, - &omap44xx_l4_wkup__prm, - &omap44xx_l4_wkup__scrm, - /* &omap44xx_l3_main_2__sl2if, */ - &omap44xx_mpu__emif1, - &omap44xx_mpu__emif2, - NULL, -}; - -int __init omap44xx_hwmod_init(void) -{ - omap_hwmod_init(); - return omap_hwmod_register_links(omap44xx_hwmod_ocp_ifs); -} - diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c deleted file mode 100644 index 85b9ab4756eda0a3492e451e79ebe124139e991c..0000000000000000000000000000000000000000 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ /dev/null @@ -1,467 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Hardware modules present on the OMAP54xx chips - * - * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com - * - * Paul Walmsley - * Benoit Cousson - * - * This file is automatically generated from the OMAP hardware databases. - * We respectfully ask that any modifications to this file be coordinated - * with the public linux-omap@vger.kernel.org mailing list and the - * authors above to ensure that the autogeneration scripts are kept - * up-to-date with the file contents. - */ - -#include <linux/io.h> -#include <linux/power/smartreflex.h> - -#include "omap_hwmod.h" -#include "omap_hwmod_common_data.h" -#include "cm1_54xx.h" -#include "cm2_54xx.h" -#include "prm54xx.h" - -/* Base offset for all OMAP5 interrupts external to MPUSS */ -#define OMAP54XX_IRQ_GIC_START 32 - -/* - * IP blocks - */ - -/* - * 'dmm' class - * instance(s): dmm - */ -static struct omap_hwmod_class omap54xx_dmm_hwmod_class = { - .name = "dmm", -}; - -/* dmm */ -static struct omap_hwmod omap54xx_dmm_hwmod = { - .name = "dmm", - .class = &omap54xx_dmm_hwmod_class, - .clkdm_name = "emif_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_EMIF_DMM_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_EMIF_DMM_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'l3' class - * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3 - */ -static struct omap_hwmod_class omap54xx_l3_hwmod_class = { - .name = "l3", -}; - -/* l3_instr */ -static struct omap_hwmod omap54xx_l3_instr_hwmod = { - .name = "l3_instr", - .class = &omap54xx_l3_hwmod_class, - .clkdm_name = "l3instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* l3_main_1 */ -static struct omap_hwmod omap54xx_l3_main_1_hwmod = { - .name = "l3_main_1", - .class = &omap54xx_l3_hwmod_class, - .clkdm_name = "l3main1_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L3MAIN1_L3_MAIN_1_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L3MAIN1_L3_MAIN_1_CONTEXT_OFFSET, - }, - }, -}; - -/* l3_main_2 */ -static struct omap_hwmod omap54xx_l3_main_2_hwmod = { - .name = "l3_main_2", - .class = &omap54xx_l3_hwmod_class, - .clkdm_name = "l3main2_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L3MAIN2_L3_MAIN_2_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L3MAIN2_L3_MAIN_2_CONTEXT_OFFSET, - }, - }, -}; - -/* l3_main_3 */ -static struct omap_hwmod omap54xx_l3_main_3_hwmod = { - .name = "l3_main_3", - .class = &omap54xx_l3_hwmod_class, - .clkdm_name = "l3instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L3INSTR_L3_MAIN_3_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L3INSTR_L3_MAIN_3_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* - * 'l4' class - * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup - */ -static struct omap_hwmod_class omap54xx_l4_hwmod_class = { - .name = "l4", -}; - -/* l4_cfg */ -static struct omap_hwmod omap54xx_l4_cfg_hwmod = { - .name = "l4_cfg", - .class = &omap54xx_l4_hwmod_class, - .clkdm_name = "l4cfg_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L4CFG_L4_CFG_CONTEXT_OFFSET, - }, - }, -}; - -/* l4_per */ -static struct omap_hwmod omap54xx_l4_per_hwmod = { - .name = "l4_per", - .class = &omap54xx_l4_hwmod_class, - .clkdm_name = "l4per_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L4PER_L4_PER_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L4PER_L4_PER_CONTEXT_OFFSET, - }, - }, -}; - -/* l4_wkup */ -static struct omap_hwmod omap54xx_l4_wkup_hwmod = { - .name = "l4_wkup", - .class = &omap54xx_l4_hwmod_class, - .clkdm_name = "wkupaon_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_WKUPAON_L4_WKUP_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_WKUPAON_L4_WKUP_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'mpu_bus' class - * instance(s): mpu_private - */ -static struct omap_hwmod_class omap54xx_mpu_bus_hwmod_class = { - .name = "mpu_bus", -}; - -/* mpu_private */ -static struct omap_hwmod omap54xx_mpu_private_hwmod = { - .name = "mpu_private", - .class = &omap54xx_mpu_bus_hwmod_class, - .clkdm_name = "mpu_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* - * 'emif' class - * external memory interface no1 (wrapper) - */ - -static struct omap_hwmod_class_sysconfig omap54xx_emif_sysc = { - .rev_offs = 0x0000, -}; - -static struct omap_hwmod_class omap54xx_emif_hwmod_class = { - .name = "emif", - .sysc = &omap54xx_emif_sysc, -}; - -/* emif1 */ -static struct omap_hwmod omap54xx_emif1_hwmod = { - .name = "emif1", - .class = &omap54xx_emif_hwmod_class, - .clkdm_name = "emif_clkdm", - .flags = HWMOD_INIT_NO_IDLE, - .main_clk = "dpll_core_h11x2_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_EMIF_EMIF1_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_EMIF_EMIF1_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* emif2 */ -static struct omap_hwmod omap54xx_emif2_hwmod = { - .name = "emif2", - .class = &omap54xx_emif_hwmod_class, - .clkdm_name = "emif_clkdm", - .flags = HWMOD_INIT_NO_IDLE, - .main_clk = "dpll_core_h11x2_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_EMIF_EMIF2_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_EMIF_EMIF2_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - - - - -/* - * 'mpu' class - * mpu sub-system - */ - -static struct omap_hwmod_class omap54xx_mpu_hwmod_class = { - .name = "mpu", -}; - -/* mpu */ -static struct omap_hwmod omap54xx_mpu_hwmod = { - .name = "mpu", - .class = &omap54xx_mpu_hwmod_class, - .clkdm_name = "mpu_clkdm", - .flags = HWMOD_INIT_NO_IDLE, - .main_clk = "dpll_mpu_m2_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_MPU_MPU_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_MPU_MPU_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'sata' class - * sata: serial ata interface gen2 compliant ( 1 rx/ 1 tx) - */ - -static struct omap_hwmod_class_sysconfig omap54xx_sata_sysc = { - .rev_offs = 0x00fc, - .sysc_offs = 0x0000, - .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO | - MSTANDBY_SMART | MSTANDBY_SMART_WKUP), - .sysc_fields = &omap_hwmod_sysc_type2, -}; - -static struct omap_hwmod_class omap54xx_sata_hwmod_class = { - .name = "sata", - .sysc = &omap54xx_sata_sysc, -}; - -/* sata */ -static struct omap_hwmod omap54xx_sata_hwmod = { - .name = "sata", - .class = &omap54xx_sata_hwmod_class, - .clkdm_name = "l3init_clkdm", - .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY, - .main_clk = "func_48m_fclk", - .mpu_rt_idx = 1, - .prcm = { - .omap4 = { - .clkctrl_offs = OMAP54XX_CM_L3INIT_SATA_CLKCTRL_OFFSET, - .context_offs = OMAP54XX_RM_L3INIT_SATA_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* l4_cfg -> sata */ -static struct omap_hwmod_ocp_if omap54xx_l4_cfg__sata = { - .master = &omap54xx_l4_cfg_hwmod, - .slave = &omap54xx_sata_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* - * Interfaces - */ - -/* l3_main_1 -> dmm */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_1__dmm = { - .master = &omap54xx_l3_main_1_hwmod, - .slave = &omap54xx_dmm_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_SDMA, -}; - -/* l3_main_3 -> l3_instr */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_3__l3_instr = { - .master = &omap54xx_l3_main_3_hwmod, - .slave = &omap54xx_l3_instr_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> l3_main_1 */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_2__l3_main_1 = { - .master = &omap54xx_l3_main_2_hwmod, - .slave = &omap54xx_l3_main_1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> l3_main_1 */ -static struct omap_hwmod_ocp_if omap54xx_l4_cfg__l3_main_1 = { - .master = &omap54xx_l4_cfg_hwmod, - .slave = &omap54xx_l3_main_1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> l3_main_1 */ -static struct omap_hwmod_ocp_if omap54xx_mpu__l3_main_1 = { - .master = &omap54xx_mpu_hwmod, - .slave = &omap54xx_l3_main_1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU, -}; - -/* l3_main_1 -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l3_main_2 = { - .master = &omap54xx_l3_main_1_hwmod, - .slave = &omap54xx_l3_main_2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU, -}; - -/* l4_cfg -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap54xx_l4_cfg__l3_main_2 = { - .master = &omap54xx_l4_cfg_hwmod, - .slave = &omap54xx_l3_main_2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l3_main_3 */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l3_main_3 = { - .master = &omap54xx_l3_main_1_hwmod, - .slave = &omap54xx_l3_main_3_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU, -}; - -/* l3_main_2 -> l3_main_3 */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_2__l3_main_3 = { - .master = &omap54xx_l3_main_2_hwmod, - .slave = &omap54xx_l3_main_3_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> l3_main_3 */ -static struct omap_hwmod_ocp_if omap54xx_l4_cfg__l3_main_3 = { - .master = &omap54xx_l4_cfg_hwmod, - .slave = &omap54xx_l3_main_3_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_cfg */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l4_cfg = { - .master = &omap54xx_l3_main_1_hwmod, - .slave = &omap54xx_l4_cfg_hwmod, - .clk = "l4_root_clk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_2 -> l4_per */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_2__l4_per = { - .master = &omap54xx_l3_main_2_hwmod, - .slave = &omap54xx_l4_per_hwmod, - .clk = "l4_root_clk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_wkup */ -static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l4_wkup = { - .master = &omap54xx_l3_main_1_hwmod, - .slave = &omap54xx_l4_wkup_hwmod, - .clk = "wkupaon_iclk_mux", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> mpu_private */ -static struct omap_hwmod_ocp_if omap54xx_mpu__mpu_private = { - .master = &omap54xx_mpu_hwmod, - .slave = &omap54xx_mpu_private_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> emif1 */ -static struct omap_hwmod_ocp_if omap54xx_mpu__emif1 = { - .master = &omap54xx_mpu_hwmod, - .slave = &omap54xx_emif1_hwmod, - .clk = "dpll_core_h11x2_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> emif2 */ -static struct omap_hwmod_ocp_if omap54xx_mpu__emif2 = { - .master = &omap54xx_mpu_hwmod, - .slave = &omap54xx_emif2_hwmod, - .clk = "dpll_core_h11x2_ck", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> mpu */ -static struct omap_hwmod_ocp_if omap54xx_l4_cfg__mpu = { - .master = &omap54xx_l4_cfg_hwmod, - .slave = &omap54xx_mpu_hwmod, - .clk = "l4_root_clk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = { - &omap54xx_l3_main_1__dmm, - &omap54xx_l3_main_3__l3_instr, - &omap54xx_l3_main_2__l3_main_1, - &omap54xx_l4_cfg__l3_main_1, - &omap54xx_mpu__l3_main_1, - &omap54xx_l3_main_1__l3_main_2, - &omap54xx_l4_cfg__l3_main_2, - &omap54xx_l3_main_1__l3_main_3, - &omap54xx_l3_main_2__l3_main_3, - &omap54xx_l4_cfg__l3_main_3, - &omap54xx_l3_main_1__l4_cfg, - &omap54xx_l3_main_2__l4_per, - &omap54xx_l3_main_1__l4_wkup, - &omap54xx_mpu__mpu_private, - &omap54xx_mpu__emif1, - &omap54xx_mpu__emif2, - &omap54xx_l4_cfg__mpu, - &omap54xx_l4_cfg__sata, - NULL, -}; - -int __init omap54xx_hwmod_init(void) -{ - omap_hwmod_init(); - return omap_hwmod_register_links(omap54xx_hwmod_ocp_ifs); -} diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c deleted file mode 100644 index 48c2a808bd4673a422abf6f79a147dc5d47fbc46..0000000000000000000000000000000000000000 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ /dev/null @@ -1,719 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Hardware modules present on the DRA7xx chips - * - * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com - * - * Paul Walmsley - * Benoit Cousson - * - * This file is automatically generated from the OMAP hardware databases. - * We respectfully ask that any modifications to this file be coordinated - * with the public linux-omap@vger.kernel.org mailing list and the - * authors above to ensure that the autogeneration scripts are kept - * up-to-date with the file contents. - */ - -#include <linux/io.h> - -#include "omap_hwmod.h" -#include "omap_hwmod_common_data.h" -#include "cm1_7xx.h" -#include "cm2_7xx.h" -#include "prm7xx.h" -#include "soc.h" - -/* Base offset for all DRA7XX interrupts external to MPUSS */ -#define DRA7XX_IRQ_GIC_START 32 - -/* - * IP blocks - */ - -/* - * 'dmm' class - * instance(s): dmm - */ -static struct omap_hwmod_class dra7xx_dmm_hwmod_class = { - .name = "dmm", -}; - -/* dmm */ -static struct omap_hwmod dra7xx_dmm_hwmod = { - .name = "dmm", - .class = &dra7xx_dmm_hwmod_class, - .clkdm_name = "emif_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_EMIF_DMM_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_EMIF_DMM_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'l3' class - * instance(s): l3_instr, l3_main_1, l3_main_2 - */ -static struct omap_hwmod_class dra7xx_l3_hwmod_class = { - .name = "l3", -}; - -/* l3_instr */ -static struct omap_hwmod dra7xx_l3_instr_hwmod = { - .name = "l3_instr", - .class = &dra7xx_l3_hwmod_class, - .clkdm_name = "l3instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* l3_main_1 */ -static struct omap_hwmod dra7xx_l3_main_1_hwmod = { - .name = "l3_main_1", - .class = &dra7xx_l3_hwmod_class, - .clkdm_name = "l3main1_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3MAIN1_L3_MAIN_1_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3MAIN1_L3_MAIN_1_CONTEXT_OFFSET, - }, - }, -}; - -/* l3_main_2 */ -static struct omap_hwmod dra7xx_l3_main_2_hwmod = { - .name = "l3_main_2", - .class = &dra7xx_l3_hwmod_class, - .clkdm_name = "l3instr_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3INSTR_L3_MAIN_2_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3INSTR_L3_MAIN_2_CONTEXT_OFFSET, - .modulemode = MODULEMODE_HWCTRL, - }, - }, -}; - -/* - * 'l4' class - * instance(s): l4_cfg, l4_per1, l4_per2, l4_per3, l4_wkup - */ -static struct omap_hwmod_class dra7xx_l4_hwmod_class = { - .name = "l4", -}; - -/* l4_cfg */ -static struct omap_hwmod dra7xx_l4_cfg_hwmod = { - .name = "l4_cfg", - .class = &dra7xx_l4_hwmod_class, - .clkdm_name = "l4cfg_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L4CFG_L4_CFG_CONTEXT_OFFSET, - }, - }, -}; - -/* l4_per1 */ -static struct omap_hwmod dra7xx_l4_per1_hwmod = { - .name = "l4_per1", - .class = &dra7xx_l4_hwmod_class, - .clkdm_name = "l4per_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L4PER_L4_PER1_CLKCTRL_OFFSET, - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* l4_per2 */ -static struct omap_hwmod dra7xx_l4_per2_hwmod = { - .name = "l4_per2", - .class = &dra7xx_l4_hwmod_class, - .clkdm_name = "l4per2_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L4PER2_L4_PER2_CLKCTRL_OFFSET, - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* l4_per3 */ -static struct omap_hwmod dra7xx_l4_per3_hwmod = { - .name = "l4_per3", - .class = &dra7xx_l4_hwmod_class, - .clkdm_name = "l4per3_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L4PER3_L4_PER3_CLKCTRL_OFFSET, - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* l4_wkup */ -static struct omap_hwmod dra7xx_l4_wkup_hwmod = { - .name = "l4_wkup", - .class = &dra7xx_l4_hwmod_class, - .clkdm_name = "wkupaon_clkdm", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_WKUPAON_L4_WKUP_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_WKUPAON_L4_WKUP_CONTEXT_OFFSET, - }, - }, -}; - -/* - * 'atl' class - * - */ - -static struct omap_hwmod_class dra7xx_atl_hwmod_class = { - .name = "atl", -}; - -/* atl */ -static struct omap_hwmod dra7xx_atl_hwmod = { - .name = "atl", - .class = &dra7xx_atl_hwmod_class, - .clkdm_name = "atl_clkdm", - .main_clk = "atl_gfclk_mux", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_ATL_ATL_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_ATL_ATL_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* - * 'bb2d' class - * - */ - -static struct omap_hwmod_class dra7xx_bb2d_hwmod_class = { - .name = "bb2d", -}; - -/* bb2d */ -static struct omap_hwmod dra7xx_bb2d_hwmod = { - .name = "bb2d", - .class = &dra7xx_bb2d_hwmod_class, - .clkdm_name = "dss_clkdm", - .main_clk = "dpll_core_h24x2_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_DSS_BB2D_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_DSS_BB2D_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* - * 'ctrl_module' class - * - */ - -static struct omap_hwmod_class dra7xx_ctrl_module_hwmod_class = { - .name = "ctrl_module", -}; - -/* ctrl_module_wkup */ -static struct omap_hwmod dra7xx_ctrl_module_wkup_hwmod = { - .name = "ctrl_module_wkup", - .class = &dra7xx_ctrl_module_hwmod_class, - .clkdm_name = "wkupaon_clkdm", - .prcm = { - .omap4 = { - .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT, - }, - }, -}; - -/* - * 'mpu' class - * - */ - -static struct omap_hwmod_class dra7xx_mpu_hwmod_class = { - .name = "mpu", -}; - -/* mpu */ -static struct omap_hwmod dra7xx_mpu_hwmod = { - .name = "mpu", - .class = &dra7xx_mpu_hwmod_class, - .clkdm_name = "mpu_clkdm", - .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET, - .main_clk = "dpll_mpu_m2_ck", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_MPU_MPU_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_MPU_MPU_CONTEXT_OFFSET, - }, - }, -}; - - -/* - * 'PCIE' class - * - */ - -/* - * As noted in documentation for _reset() in omap_hwmod.c, the stock reset - * functionality of OMAP HWMOD layer does not deassert the hardreset lines - * associated with an IP automatically leaving the driver to handle that - * by itself. This does not work for PCIeSS which needs the reset lines - * deasserted for the driver to start accessing registers. - * - * We use a PCIeSS HWMOD class specific reset handler to deassert the hardreset - * lines after asserting them. - */ -int dra7xx_pciess_reset(struct omap_hwmod *oh) -{ - int i; - - for (i = 0; i < oh->rst_lines_cnt; i++) { - omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name); - omap_hwmod_deassert_hardreset(oh, oh->rst_lines[i].name); - } - - return 0; -} - -static struct omap_hwmod_class dra7xx_pciess_hwmod_class = { - .name = "pcie", - .reset = dra7xx_pciess_reset, -}; - -/* pcie1 */ -static struct omap_hwmod_rst_info dra7xx_pciess1_resets[] = { - { .name = "pcie", .rst_shift = 0 }, -}; - -static struct omap_hwmod dra7xx_pciess1_hwmod = { - .name = "pcie1", - .class = &dra7xx_pciess_hwmod_class, - .clkdm_name = "pcie_clkdm", - .rst_lines = dra7xx_pciess1_resets, - .rst_lines_cnt = ARRAY_SIZE(dra7xx_pciess1_resets), - .main_clk = "l4_root_clk_div", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3INIT_PCIESS1_CLKCTRL_OFFSET, - .rstctrl_offs = DRA7XX_RM_L3INIT_PCIESS_RSTCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3INIT_PCIESS1_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* pcie2 */ -static struct omap_hwmod_rst_info dra7xx_pciess2_resets[] = { - { .name = "pcie", .rst_shift = 1 }, -}; - -/* pcie2 */ -static struct omap_hwmod dra7xx_pciess2_hwmod = { - .name = "pcie2", - .class = &dra7xx_pciess_hwmod_class, - .clkdm_name = "pcie_clkdm", - .rst_lines = dra7xx_pciess2_resets, - .rst_lines_cnt = ARRAY_SIZE(dra7xx_pciess2_resets), - .main_clk = "l4_root_clk_div", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3INIT_PCIESS2_CLKCTRL_OFFSET, - .rstctrl_offs = DRA7XX_RM_L3INIT_PCIESS_RSTCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3INIT_PCIESS2_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* - * 'qspi' class - * - */ - -static struct omap_hwmod_class_sysconfig dra7xx_qspi_sysc = { - .rev_offs = 0, - .sysc_offs = 0x0010, - .sysc_flags = SYSC_HAS_SIDLEMODE, - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP), - .sysc_fields = &omap_hwmod_sysc_type2, -}; - -static struct omap_hwmod_class dra7xx_qspi_hwmod_class = { - .name = "qspi", - .sysc = &dra7xx_qspi_sysc, -}; - -/* qspi */ -static struct omap_hwmod dra7xx_qspi_hwmod = { - .name = "qspi", - .class = &dra7xx_qspi_hwmod_class, - .clkdm_name = "l4per2_clkdm", - .main_clk = "qspi_gfclk_div", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L4PER2_QSPI_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L4PER2_QSPI_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* - * 'sata' class - * - */ - -static struct omap_hwmod_class_sysconfig dra7xx_sata_sysc = { - .rev_offs = 0x00fc, - .sysc_offs = 0x0000, - .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO | - MSTANDBY_SMART | MSTANDBY_SMART_WKUP), - .sysc_fields = &omap_hwmod_sysc_type2, -}; - -static struct omap_hwmod_class dra7xx_sata_hwmod_class = { - .name = "sata", - .sysc = &dra7xx_sata_sysc, -}; - -/* sata */ - -static struct omap_hwmod dra7xx_sata_hwmod = { - .name = "sata", - .class = &dra7xx_sata_hwmod_class, - .clkdm_name = "l3init_clkdm", - .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY, - .main_clk = "func_48m_fclk", - .mpu_rt_idx = 1, - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3INIT_SATA_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3INIT_SATA_CONTEXT_OFFSET, - .modulemode = MODULEMODE_SWCTRL, - }, - }, -}; - -/* - * 'vcp' class - * - */ - -static struct omap_hwmod_class dra7xx_vcp_hwmod_class = { - .name = "vcp", -}; - -/* vcp1 */ -static struct omap_hwmod dra7xx_vcp1_hwmod = { - .name = "vcp1", - .class = &dra7xx_vcp_hwmod_class, - .clkdm_name = "l3main1_clkdm", - .main_clk = "l3_iclk_div", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3MAIN1_VCP1_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3MAIN1_VCP1_CONTEXT_OFFSET, - }, - }, -}; - -/* vcp2 */ -static struct omap_hwmod dra7xx_vcp2_hwmod = { - .name = "vcp2", - .class = &dra7xx_vcp_hwmod_class, - .clkdm_name = "l3main1_clkdm", - .main_clk = "l3_iclk_div", - .prcm = { - .omap4 = { - .clkctrl_offs = DRA7XX_CM_L3MAIN1_VCP2_CLKCTRL_OFFSET, - .context_offs = DRA7XX_RM_L3MAIN1_VCP2_CONTEXT_OFFSET, - }, - }, -}; - - - -/* - * Interfaces - */ - -/* l3_main_1 -> dmm */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__dmm = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_dmm_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_SDMA, -}; - -/* l3_main_2 -> l3_instr */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_2__l3_instr = { - .master = &dra7xx_l3_main_2_hwmod, - .slave = &dra7xx_l3_instr_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> l3_main_1 */ -static struct omap_hwmod_ocp_if dra7xx_l4_cfg__l3_main_1 = { - .master = &dra7xx_l4_cfg_hwmod, - .slave = &dra7xx_l3_main_1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* mpu -> l3_main_1 */ -static struct omap_hwmod_ocp_if dra7xx_mpu__l3_main_1 = { - .master = &dra7xx_mpu_hwmod, - .slave = &dra7xx_l3_main_1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU, -}; - -/* l3_main_1 -> l3_main_2 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l3_main_2 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_l3_main_2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU, -}; - -/* l4_cfg -> l3_main_2 */ -static struct omap_hwmod_ocp_if dra7xx_l4_cfg__l3_main_2 = { - .master = &dra7xx_l4_cfg_hwmod, - .slave = &dra7xx_l3_main_2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_cfg */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_cfg = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_l4_cfg_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_per1 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_per1 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_l4_per1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_per2 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_per2 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_l4_per2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_per3 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_per3 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_l4_per3_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> l4_wkup */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_wkup = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_l4_wkup_hwmod, - .clk = "wkupaon_iclk_mux", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_per2 -> atl */ -static struct omap_hwmod_ocp_if dra7xx_l4_per2__atl = { - .master = &dra7xx_l4_per2_hwmod, - .slave = &dra7xx_atl_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> bb2d */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__bb2d = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_bb2d_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_wkup -> ctrl_module_wkup */ -static struct omap_hwmod_ocp_if dra7xx_l4_wkup__ctrl_module_wkup = { - .master = &dra7xx_l4_wkup_hwmod, - .slave = &dra7xx_ctrl_module_wkup_hwmod, - .clk = "wkupaon_iclk_mux", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> mpu */ -static struct omap_hwmod_ocp_if dra7xx_l4_cfg__mpu = { - .master = &dra7xx_l4_cfg_hwmod, - .slave = &dra7xx_mpu_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> pciess1 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess1 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_pciess1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> pciess1 */ -static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess1 = { - .master = &dra7xx_l4_cfg_hwmod, - .slave = &dra7xx_pciess1_hwmod, - .clk = "l4_root_clk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> pciess2 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess2 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_pciess2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> pciess2 */ -static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess2 = { - .master = &dra7xx_l4_cfg_hwmod, - .slave = &dra7xx_pciess2_hwmod, - .clk = "l4_root_clk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> qspi */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__qspi = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_qspi_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_cfg -> sata */ -static struct omap_hwmod_ocp_if dra7xx_l4_cfg__sata = { - .master = &dra7xx_l4_cfg_hwmod, - .slave = &dra7xx_sata_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> vcp1 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__vcp1 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_vcp1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_per2 -> vcp1 */ -static struct omap_hwmod_ocp_if dra7xx_l4_per2__vcp1 = { - .master = &dra7xx_l4_per2_hwmod, - .slave = &dra7xx_vcp1_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l3_main_1 -> vcp2 */ -static struct omap_hwmod_ocp_if dra7xx_l3_main_1__vcp2 = { - .master = &dra7xx_l3_main_1_hwmod, - .slave = &dra7xx_vcp2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* l4_per2 -> vcp2 */ -static struct omap_hwmod_ocp_if dra7xx_l4_per2__vcp2 = { - .master = &dra7xx_l4_per2_hwmod, - .slave = &dra7xx_vcp2_hwmod, - .clk = "l3_iclk_div", - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = { - &dra7xx_l3_main_1__dmm, - &dra7xx_l3_main_2__l3_instr, - &dra7xx_l4_cfg__l3_main_1, - &dra7xx_mpu__l3_main_1, - &dra7xx_l3_main_1__l3_main_2, - &dra7xx_l4_cfg__l3_main_2, - &dra7xx_l3_main_1__l4_cfg, - &dra7xx_l3_main_1__l4_per1, - &dra7xx_l3_main_1__l4_per2, - &dra7xx_l3_main_1__l4_per3, - &dra7xx_l3_main_1__l4_wkup, - &dra7xx_l4_per2__atl, - &dra7xx_l3_main_1__bb2d, - &dra7xx_l4_wkup__ctrl_module_wkup, - &dra7xx_l4_cfg__mpu, - &dra7xx_l3_main_1__pciess1, - &dra7xx_l4_cfg__pciess1, - &dra7xx_l3_main_1__pciess2, - &dra7xx_l4_cfg__pciess2, - &dra7xx_l3_main_1__qspi, - &dra7xx_l4_cfg__sata, - &dra7xx_l3_main_1__vcp1, - &dra7xx_l4_per2__vcp1, - &dra7xx_l3_main_1__vcp2, - &dra7xx_l4_per2__vcp2, - NULL, -}; - -/* SoC variant specific hwmod links */ -static struct omap_hwmod_ocp_if *dra72x_hwmod_ocp_ifs[] __initdata = { - NULL, -}; - -static struct omap_hwmod_ocp_if *rtc_hwmod_ocp_ifs[] __initdata = { - NULL, -}; - -int __init dra7xx_hwmod_init(void) -{ - int ret; - - omap_hwmod_init(); - ret = omap_hwmod_register_links(dra7xx_hwmod_ocp_ifs); - - if (!ret && soc_is_dra74x()) { - ret = omap_hwmod_register_links(rtc_hwmod_ocp_ifs); - } else if (!ret && soc_is_dra72x()) { - ret = omap_hwmod_register_links(dra72x_hwmod_ocp_ifs); - if (!ret && !of_machine_is_compatible("ti,dra718")) - ret = omap_hwmod_register_links(rtc_hwmod_ocp_ifs); - } else if (!ret && soc_is_dra76x()) { - if (!ret && soc_is_dra76x_abz()) - ret = omap_hwmod_register_links(rtc_hwmod_ocp_ifs); - } - - return ret; -} diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index a642d3b39e503ec4878ab2364520480e52ca24e6..d4dab041324dc035e5ccc27b51781499c08ee5b5 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * OMAP and TWL PMIC specific initializations. * * Copyright (C) 2010 Texas Instruments Incorporated. diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 2e3a10914c40aaa6cb47d6745c607e78f4dcade4..765809b214e719e7292cca2b26819cd53a72708d 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -443,7 +443,7 @@ void omap_auxdata_legacy_init(struct device *dev) dev->platform_data = &twl_gpio_auxdata; } -#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP) +#if defined(CONFIG_ARCH_OMAP3) && IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP) static struct omap_mcbsp_platform_data mcbsp_pdata; static void __init omap3_mcbsp_init(void) { @@ -569,10 +569,29 @@ static void pdata_quirks_check(struct pdata_init *quirks) } } -void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table) +static const char * const pdata_quirks_init_nodes[] = { + "prcm", + "prm", +}; + +static void __init +pdata_quirks_init_clocks(const struct of_device_id *omap_dt_match_table) { struct device_node *np; + int i; + + for (i = 0; i < ARRAY_SIZE(pdata_quirks_init_nodes); i++) { + np = of_find_node_by_name(NULL, pdata_quirks_init_nodes[i]); + if (!np) + continue; + + of_platform_populate(np, omap_dt_match_table, + omap_auxdata_lookup, NULL); + } +} +void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table) +{ /* * We still need this for omap2420 and omap3 PM to work, others are * using drivers/misc/sram.c already. @@ -585,13 +604,7 @@ void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table) omap3_mcbsp_init(); pdata_quirks_check(auxdata_quirks); - /* Populate always-on PRCM in l4_wkup to probe l4_wkup */ - np = of_find_node_by_name(NULL, "prcm"); - if (!np) - np = of_find_node_by_name(NULL, "prm"); - if (np) - of_platform_populate(np, omap_dt_match_table, - omap_auxdata_lookup, NULL); + pdata_quirks_init_clocks(omap_dt_match_table); of_platform_populate(NULL, omap_dt_match_table, omap_auxdata_lookup, NULL); diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 919d35d5b325ddce3c59d25fa1a4b246bd894186..b43eab9879d3eedf20b44c459bf528d7e592d69d 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -168,8 +168,8 @@ static int pwrdm_suspend_set(void *data, u64 val) return -EINVAL; } -DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, - pwrdm_suspend_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, + pwrdm_suspend_set, "%llu\n"); static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) { diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 1cbac76136d464e173742e7c694dce58abd395d9..0a5b87e2a4b07368bce15b46fb2a997af335cb3c 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1202,26 +1202,26 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm) if (!pwrdm) { pr_debug("powerdomain: %s: invalid powerdomain pointer\n", __func__); - return 1; + return true; } if (pwrdm->pwrsts & PWRSTS_OFF) - return 1; + return true; if (pwrdm->pwrsts & PWRSTS_RET) { if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF) - return 1; + return true; for (i = 0; i < pwrdm->banks; i++) if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF) - return 1; + return true; } for (i = 0; i < pwrdm->banks; i++) if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF) - return 1; + return true; - return 0; + return false; } /** diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index 605925684b0aa4d1015c9d0d3eb4a17d76f28f75..db672cf19a51fb6632f3224654940c62bab0cefd 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -152,6 +152,7 @@ exit: return 0; } +#ifdef CONFIG_OMAP_HWMOD static int __init sr_dev_init(struct omap_hwmod *oh, void *user) { struct omap_smartreflex_dev_attr *sr_dev_attr; @@ -165,6 +166,12 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) return sr_init_by_name(oh->name, sr_dev_attr->sensor_voltdm_name); } +#else +static int __init sr_dev_init(struct omap_hwmod *oh, void *user) +{ + return -EINVAL; +} +#endif /* * API to be called from board files to enable smartreflex diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c index 151e26ec06968334e037d5bf389d7f12e4c1ce71..04a12523cdee0418e764027cb0cbc732fd594c20 100644 --- a/arch/arm/mach-pxa/icontrol.c +++ b/arch/arm/mach-pxa/icontrol.c @@ -74,13 +74,17 @@ static const struct property_entry mcp251x_properties[] = { {} }; +static const struct software_node mcp251x_node = { + .properties = mcp251x_properties, +}; + static struct spi_board_info mcp251x_board_info[] = { { .modalias = "mcp2515", .max_speed_hz = 6500000, .bus_num = 3, .chip_select = 0, - .properties = mcp251x_properties, + .swnode = &mcp251x_node, .controller_data = &mcp251x_chip_info1, .irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ1) }, @@ -89,7 +93,7 @@ static struct spi_board_info mcp251x_board_info[] = { .max_speed_hz = 6500000, .bus_num = 3, .chip_select = 1, - .properties = mcp251x_properties, + .swnode = &mcp251x_node, .controller_data = &mcp251x_chip_info2, .irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ2) }, @@ -98,7 +102,7 @@ static struct spi_board_info mcp251x_board_info[] = { .max_speed_hz = 6500000, .bus_num = 4, .chip_select = 0, - .properties = mcp251x_properties, + .swnode = &mcp251x_node, .controller_data = &mcp251x_chip_info3, .irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ3) }, @@ -107,7 +111,7 @@ static struct spi_board_info mcp251x_board_info[] = { .max_speed_hz = 6500000, .bus_num = 4, .chip_select = 1, - .properties = mcp251x_properties, + .swnode = &mcp251x_node, .controller_data = &mcp251x_chip_info4, .irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ4) } diff --git a/arch/arm/mach-pxa/pxa_cplds_irqs.c b/arch/arm/mach-pxa/pxa_cplds_irqs.c index 45c19ca96f7a650142112c9d9ec8c9deac8122d3..ec0d9b094744db67ae99bb80faababa817c3845e 100644 --- a/arch/arm/mach-pxa/pxa_cplds_irqs.c +++ b/arch/arm/mach-pxa/pxa_cplds_irqs.c @@ -147,22 +147,20 @@ static int cplds_probe(struct platform_device *pdev) } irq_set_irq_wake(fpga->irq, 1); - fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node, - CPLDS_NB_IRQ, - &cplds_irq_domain_ops, fpga); + if (base_irq) + fpga->irqdomain = irq_domain_add_legacy(pdev->dev.of_node, + CPLDS_NB_IRQ, + base_irq, 0, + &cplds_irq_domain_ops, + fpga); + else + fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node, + CPLDS_NB_IRQ, + &cplds_irq_domain_ops, + fpga); if (!fpga->irqdomain) return -ENODEV; - if (base_irq) { - ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0, - CPLDS_NB_IRQ); - if (ret) { - dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n", - base_irq, base_irq + CPLDS_NB_IRQ); - return ret; - } - } - return 0; } diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index b27fc7ac9ceab1ae3543522bd97ae195aacf8df1..97700429633ee6ac0a408f3aefc81d51fb98049f 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -433,10 +433,14 @@ static const struct property_entry mcp251x_properties[] = { {} }; +static const struct software_node mcp251x_node = { + .properties = mcp251x_properties, +}; + static struct spi_board_info zeus_spi_board_info[] = { [0] = { .modalias = "mcp2515", - .properties = mcp251x_properties, + .swnode = &mcp251x_node, .irq = PXA_GPIO_TO_IRQ(ZEUS_CAN_GPIO), .max_speed_hz = 1*1000*1000, .bus_num = 3, diff --git a/arch/arm/mach-s3c/mach-rx1950.c b/arch/arm/mach-s3c/mach-rx1950.c index 6e19add158a987e445925c59346d3c2ca4d3e10a..a3f46aa61c45b5f7347429c4d2d14c19746ef17f 100644 --- a/arch/arm/mach-s3c/mach-rx1950.c +++ b/arch/arm/mach-s3c/mach-rx1950.c @@ -384,6 +384,8 @@ static struct s3c2410fb_mach_info rx1950_lcd_cfg = { static struct pwm_lookup rx1950_pwm_lookup[] = { PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight.0", NULL, 48000, PWM_POLARITY_NORMAL), + PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", "RX1950 LCD", LCD_PWM_PERIOD, + PWM_POLARITY_NORMAL), }; static struct pwm_device *lcd_pwm; @@ -498,19 +500,18 @@ static void rx1950_bl_power(int enable) static int rx1950_backlight_init(struct device *dev) { WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight")); - lcd_pwm = pwm_request(1, "RX1950 LCD"); + lcd_pwm = pwm_get(dev, "RX1950 LCD"); if (IS_ERR(lcd_pwm)) { dev_err(dev, "Unable to request PWM for LCD power!\n"); return PTR_ERR(lcd_pwm); } /* - * This is only required to initialize .polarity; all other values are - * fixed in this driver. + * Call pwm_init_state to initialize .polarity and .period. The other + * values are fixed in this driver. */ pwm_init_state(lcd_pwm, &lcd_pwm_state); - lcd_pwm_state.period = LCD_PWM_PERIOD; lcd_pwm_state.duty_cycle = LCD_PWM_DUTY; rx1950_lcd_power(1); @@ -524,7 +525,7 @@ static void rx1950_backlight_exit(struct device *dev) rx1950_bl_power(0); rx1950_lcd_power(0); - pwm_free(lcd_pwm); + pwm_put(lcd_pwm); gpio_free(S3C2410_GPB(0)); } diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index c3bb68d57cea2e5143a61073744050c23be44233..43ddec677c0b3422390b7700fa1fc21fd6efd764 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menuconfig ARCH_SOCFPGA +menuconfig ARCH_INTEL_SOCFPGA bool "Altera SOCFPGA family" depends on ARCH_MULTI_V7 select ARCH_SUPPORTS_BIG_ENDIAN @@ -19,7 +19,7 @@ menuconfig ARCH_SOCFPGA select PL310_ERRATA_753970 if PL310 select PL310_ERRATA_769419 -if ARCH_SOCFPGA +if ARCH_INTEL_SOCFPGA config SOCFPGA_SUSPEND bool "Suspend to RAM on SOCFPGA" help diff --git a/arch/arm/mach-spear/spear320.c b/arch/arm/mach-spear/spear320.c index 0958f68a21e236566666f13247eb1b5f8555bba2..926d5a243238af92ea5705bc79390db25ee8cb5f 100644 --- a/arch/arm/mach-spear/spear320.c +++ b/arch/arm/mach-spear/spear320.c @@ -195,14 +195,12 @@ static struct pl022_ssp_controller spear320_ssp_data[] = { .dma_filter = pl08x_filter_id, .dma_tx_param = "ssp1_tx", .dma_rx_param = "ssp1_rx", - .num_chipselect = 2, }, { .bus_id = 2, .enable_dma = 1, .dma_filter = pl08x_filter_id, .dma_tx_param = "ssp2_tx", .dma_rx_param = "ssp2_rx", - .num_chipselect = 2, } }; diff --git a/arch/arm/mach-spear/spear3xx.c b/arch/arm/mach-spear/spear3xx.c index 8537fcffe5a86e765df492bcd24275f8369987bd..f83321d5e35383365940d35660277a3ef66de81a 100644 --- a/arch/arm/mach-spear/spear3xx.c +++ b/arch/arm/mach-spear/spear3xx.c @@ -30,16 +30,6 @@ struct pl022_ssp_controller pl022_plat_data = { .dma_filter = pl08x_filter_id, .dma_tx_param = "ssp0_tx", .dma_rx_param = "ssp0_rx", - /* - * This is number of spi devices that can be connected to spi. There are - * two type of chipselects on which slave devices can work. One is chip - * select provided by spi masters other is controlled through external - * gpio's. We can't use chipselect provided from spi master (because as - * soon as FIFO becomes empty, CS is disabled and transfer ends). So - * this number now depends on number of gpios available for spi. each - * slave on each master requires a separate gpio pin. - */ - .num_chipselect = 2, }; /* dmac device registration */ diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c index 011d57b488c2e954dcc350069e79ef0c2228c9ac..a766310d8dca41d6447af6c23898ca18500e9a3b 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -17,6 +17,7 @@ static const char *const stm32_compat[] __initconst = { "st,stm32f746", "st,stm32f769", "st,stm32h743", + "st,stm32h750", "st,stm32mp157", NULL }; diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 0810f3abd810dde81e6bb6880a6d3c01420dd206..415d8ad2a3c1e80f3bb8d0770b301721aef92315 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -86,7 +86,7 @@ static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) } #ifdef CONFIG_HOTPLUG_CPU -void ux500_cpu_die(unsigned int cpu) +static void ux500_cpu_die(unsigned int cpu) { wfi(); } diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 1eb59003bdecdea32408afb842c800d94ca0d072..9f11de46aaa94e452264eb8ec31ceda6a025acc4 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -85,7 +85,7 @@ static int dma_lch_count; static int dma_chan_count; static int omap_dma_reserve_channels; -static spinlock_t dma_chan_lock; +static DEFINE_SPINLOCK(dma_chan_lock); static struct omap_dma_lch *dma_chan; static inline void disable_lnk(int lch); @@ -902,7 +902,6 @@ static int omap_system_dma_probe(struct platform_device *pdev) if (!dma_chan) return -ENOMEM; - spin_lock_init(&dma_chan_lock); for (ch = 0; ch < dma_chan_count; ch++) { omap_clear_dma(ch); diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index 467fa225c3d0ed5c9793107f583c2be74d7a88c9..e1b12b242a3204751c05ea99e620df869eeddc01 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c @@ -135,10 +135,22 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order) return; } +int xen_swiotlb_detect(void) +{ + if (!xen_domain()) + return 0; + if (xen_feature(XENFEAT_direct_mapped)) + return 1; + /* legacy case */ + if (!xen_feature(XENFEAT_not_direct_mapped) && xen_initial_domain()) + return 1; + return 0; +} + static int __init xen_mm_init(void) { struct gnttab_cache_flush cflush; - if (!xen_initial_domain()) + if (!xen_swiotlb_detect()) return 0; xen_swiotlb_init(1, false); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index dfdc3e0af5e1deb55dc19467c69788d749fe5552..ef5c7ffa7f557fd6d6f204694d320a5ae990b7b5 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -75,6 +75,7 @@ config ARM64 select ARCH_SUPPORTS_SHADOW_CALL_STACK if CC_HAVE_SHADOW_CALL_STACK select ARCH_SUPPORTS_LTO_CLANG if CPU_LITTLE_ENDIAN select ARCH_SUPPORTS_LTO_CLANG_THIN + select ARCH_SUPPORTS_CFI_CLANG select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && (GCC_VERSION >= 50000 || CC_IS_CLANG) select ARCH_SUPPORTS_NUMA_BALANCING @@ -108,9 +109,9 @@ config ARM64 select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP + select GENERIC_FIND_FIRST_BIT select GENERIC_IDLE_POLL_SETUP select GENERIC_IRQ_IPI - select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL @@ -138,6 +139,7 @@ config ARM64 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if !(ARM64_16K_PAGES && ARM64_VA_BITS_48) + select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN select HAVE_ARCH_KASAN_SW_TAGS if HAVE_ARCH_KASAN select HAVE_ARCH_KASAN_HW_TAGS if (HAVE_ARCH_KASAN && ARM64_MTE) select HAVE_ARCH_KFENCE @@ -146,6 +148,7 @@ config ARM64 select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT select HAVE_ARCH_PFN_VALID select HAVE_ARCH_PREL32_RELOCATIONS + select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_STACKLEAK select HAVE_ARCH_THREAD_STRUCT_WHITELIST @@ -194,6 +197,7 @@ config ARM64 select IOMMU_DMA if IOMMU_SUPPORT select IRQ_DOMAIN select IRQ_FORCED_THREADING + select KASAN_VMALLOC if KASAN_GENERIC select MODULES_USE_ELF_RELA select NEED_DMA_MAP_STATE select NEED_SG_DMA_LENGTH @@ -1068,6 +1072,9 @@ config SYS_SUPPORTS_HUGETLBFS config ARCH_HAS_CACHE_LINE_SIZE def_bool y +config ARCH_HAS_FILTER_PGPROT + def_bool y + config ARCH_ENABLE_SPLIT_PMD_PTLOCK def_bool y if PGTABLE_LEVELS > 2 @@ -1429,19 +1436,6 @@ config ARM64_USE_LSE_ATOMICS built with binutils >= 2.25 in order for the new instructions to be used. -config ARM64_VHE - bool "Enable support for Virtualization Host Extensions (VHE)" - default y - help - Virtualization Host Extensions (VHE) allow the kernel to run - directly at EL2 (instead of EL1) on processors that support - it. This leads to better performance for KVM, as they reduce - the cost of the world switch. - - Selecting this option allows the VHE feature to be detected - at runtime, and does not affect processors that do not - implement this feature. - endmenu menu "ARMv8.2 architectural features" @@ -1695,10 +1689,23 @@ config ARM64_MTE endmenu +menu "ARMv8.7 architectural features" + +config ARM64_EPAN + bool "Enable support for Enhanced Privileged Access Never (EPAN)" + default y + depends on ARM64_PAN + help + Enhanced Privileged Access Never (EPAN) allows Privileged + Access Never to be used with Execute-only mappings. + + The feature is detected at runtime, and will remain disabled + if the cpu does not implement the feature. +endmenu + config ARM64_SVE bool "ARM Scalable Vector Extension support" default y - depends on !KVM || ARM64_VHE help The Scalable Vector Extension (SVE) is an extension to the AArch64 execution state which complements and extends the SIMD functionality @@ -1727,12 +1734,6 @@ config ARM64_SVE booting the kernel. If unsure and you are not observing these symptoms, you should assume that it is safe to say Y. - CPUs that support SVE are architecturally required to support the - Virtualization Host Extensions (VHE), so the kernel makes no - provision for supporting SVE alongside KVM without VHE enabled. - Thus, you will need to enable CONFIG_ARM64_VHE if you want to support - KVM in the same kernel image. - config ARM64_MODULE_PLTS bool "Use PLTs to allow module memory to spill over into vmalloc area" depends on MODULES diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index d142c0eba87f7022d021b835be569bd142fdc396..ba10cda8ab106961c480c5916a7be2d9ba4c9624 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -8,16 +8,6 @@ config ARCH_ACTIONS help This enables support for the Actions Semiconductor S900 SoC family. -config ARCH_AGILEX - bool "Intel's Agilex SoCFPGA Family" - help - This enables support for Intel's Agilex SoCFPGA Family. - -config ARCH_N5X - bool "Intel's eASIC N5X SoCFPGA Family" - help - This enables support for Intel's eASIC N5X SoCFPGA Family. - config ARCH_SUNXI bool "Allwinner sunxi 64-bit SoC Family" select ARCH_HAS_RESET_CONTROLLER @@ -36,6 +26,13 @@ config ARCH_ALPINE This enables support for the Annapurna Labs Alpine Soc family. +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. + config ARCH_BCM2835 bool "Broadcom BCM2835 family" select TIMER_OF @@ -253,10 +250,11 @@ config ARCH_SEATTLE help This enables support for AMD Seattle SOC Family -config ARCH_STRATIX10 - bool "Altera's Stratix 10 SoCFPGA Family" +config ARCH_INTEL_SOCFPGA + bool "Intel's SoCFPGA ARMv8 Families" help - This enables support for Altera's Stratix 10 SoCFPGA Family. + This enables support for Intel's SoCFPGA ARMv8 families: + Stratix 10 (ex. Altera), Agilex and eASIC N5X. config ARCH_SYNQUACER bool "Socionext SynQuacer SoC Family" diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index f1173cd935945ad5a2a55441cb2c88bbbdc620cb..639e01a4d8553ba5cdb3c37aa69b3dff3bc61496 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -6,6 +6,7 @@ subdir-y += amazon subdir-y += amd subdir-y += amlogic subdir-y += apm +subdir-y += apple subdir-y += arm subdir-y += bitmain subdir-y += broadcom diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts index c7bd73f35ed89e917e2060d61aefd8b1603721c3..f17cc89f472d9479ba69c096877c98061655a74b 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts @@ -173,7 +173,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */ }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts index f7fe9fa50cb39ec1a1018c74e4d46d0f6dc3c669..997a193726836b62ad7204ab989198dafbc5ae69 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts @@ -191,7 +191,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */ }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts index 09b3c7fb82c00917d0040e769f2536dcdfe3fe0f..e47ff06a6fa9990b2d2f0b4de59b2b55de02d20b 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts @@ -152,7 +152,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts index f3f8e177ab610352846905ec7a4edffb8341c2df..ec7e2c0e82c1911ac30cf3e515418e7e31f612e4 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts @@ -185,7 +185,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */ }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts index 70e31743f0bacbcd5cf1b9e384f2a8319bae80a8..097a5511523ad54eff05d8dc8efcb2db84196f97 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts @@ -192,7 +192,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */ }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts index 329cf276561e896bbc193eb26208d4348e03c74d..2accb5ddf783359e3de69d155edb0c4cf479e66a 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts @@ -139,7 +139,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts index 7ae16541d14f5f738901d86c57997c3b72f5f659..34e67f5f829794fde53be977d601f2adf7c108d2 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts @@ -245,7 +245,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi index 9f69d489a81de906f7086e771b6d12b972a80e92..79adea3f8cc16aaf42f64568f164d35d4251b209 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi @@ -296,7 +296,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts index 422a8507f674fc7e1dd1d6365225af76275d1926..7ef96f9ff7aed0ec02bc2b7c2c27b6958e50c307 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts @@ -266,7 +266,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; x-powers,drive-vbus-en; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi index df62044ff7a7a9d404eaded80e1ebf7d4d8a1d25..6d78a1c98f105134e416c221b2a69ec8fb01a04f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi @@ -45,7 +45,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts index f0a16f355e270619b8afb14d1b45f23b3e166a5e..45e1abdf70a05fffd6eeda6a97a3957012cf090d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts @@ -205,7 +205,7 @@ compatible = "x-powers,axp803"; reg = <0x3a3>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; wakeup-source; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 57786fc120c30b884c4509648c7ded86f2cc030c..5b30e6c1fa05d078c682ac7d72ca66c2fda8ac9f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -648,6 +648,7 @@ pio: pinctrl@1c20800 { compatible = "allwinner,sun50i-a64-pinctrl"; reg = <0x01c20800 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; @@ -818,6 +819,7 @@ compatible = "allwinner,sun50i-a64-lradc", "allwinner,sun8i-a83t-r-lradc"; reg = <0x01c21800 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; @@ -1208,6 +1210,7 @@ compatible = "allwinner,sun50i-a64-rtc", "allwinner,sun8i-h3-rtc"; reg = <0x01f00000 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; clock-output-names = "osc32k", "osc32k-out", "iosc"; @@ -1219,7 +1222,7 @@ compatible = "allwinner,sun50i-a64-r-intc", "allwinner,sun6i-a31-r-intc"; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>; reg = <0x01f00c00 0x400>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; }; @@ -1279,6 +1282,7 @@ r_pio: pinctrl@1f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&osc32k>; clock-names = "apb", "hosc", "losc"; 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 b5808047d6e4ac4250a486dd0944c204b4a4b2fb..6249e9e0292863f00684485a1eab0ffcccf8f1b3 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts @@ -150,14 +150,30 @@ vcc-pg-supply = <®_aldo1>; }; -&r_i2c { +&r_ir { + linux,rc-map-name = "rc-beelink-gs1"; + status = "okay"; +}; + +&r_pio { + /* + * FIXME: We can't add that supply for now since it would + * create a circular dependency between pinctrl, the regulator + * and the RSB Bus. + * + * vcc-pl-supply = <®_aldo1>; + */ + vcc-pm-supply = <®_aldo1>; +}; + +&r_rsb { status = "okay"; - axp805: pmic@36 { + axp805: pmic@745 { compatible = "x-powers,axp805", "x-powers,axp806"; - reg = <0x36>; + reg = <0x745>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <1>; x-powers,self-working-mode; @@ -273,22 +289,6 @@ }; }; -&r_ir { - linux,rc-map-name = "rc-beelink-gs1"; - status = "okay"; -}; - -&r_pio { - /* - * PL0 and PL1 are used for PMIC I2C - * don't enable the pl-supply else - * it will fail at boot - * - * vcc-pl-supply = <®_aldo1>; - */ - vcc-pm-supply = <®_aldo1>; -}; - &spdif { 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 7e83f6146f8a589f06fad2d1f5ec215a78217a8a..c45d7b7fb39a8f68d71222b5787c52a5662d567f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts @@ -175,14 +175,18 @@ vcc-pg-supply = <®_vcc_wifi_io>; }; -&r_i2c { +&r_ir { + status = "okay"; +}; + +&r_rsb { status = "okay"; - axp805: pmic@36 { + axp805: pmic@745 { compatible = "x-powers,axp805", "x-powers,axp806"; - reg = <0x36>; + reg = <0x745>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <1>; x-powers,self-working-mode; @@ -291,10 +295,6 @@ }; }; -&r_ir { - status = "okay"; -}; - &rtc { clocks = <&ext_osc32k>; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi index da0875bd38d40e2e5419bf5e8b0c577cc45714b2..92745128fcfebdf6d1f85cb6605ac560e2aaa7ca 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi @@ -112,14 +112,22 @@ vcc-pg-supply = <®_aldo1>; }; -&r_i2c { +&r_ir { + status = "okay"; +}; + +&r_pio { + vcc-pm-supply = <®_bldo3>; +}; + +&r_rsb { status = "okay"; - axp805: pmic@36 { + axp805: pmic@745 { compatible = "x-powers,axp805", "x-powers,axp806"; - reg = <0x36>; + reg = <0x745>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <1>; x-powers,self-working-mode; @@ -232,14 +240,6 @@ }; }; -&r_ir { - status = "okay"; -}; - -&r_pio { - vcc-pm-supply = <®_bldo3>; -}; - &rtc { clocks = <&ext_osc32k>; }; 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 b868ad17af8fdad6563035996b82fb5da7bf7dcd..1ffd68f43f875845f245e60d17e8c02f932ed88d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts @@ -168,7 +168,7 @@ compatible = "x-powers,axp805", "x-powers,axp806"; reg = <0x36>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <1>; x-powers,self-working-mode; @@ -281,7 +281,7 @@ compatible = "nxp,pcf8563"; reg = <0x51>; interrupt-parent = <&r_intc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; #clock-cells = <0>; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi index af8b7d0ef75068040ce7bcc569cdca8e618d30e6..50815867ce7b18de0714bcdb8e2bcc0e7e3a4135 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi @@ -294,6 +294,7 @@ pio: pinctrl@300b000 { compatible = "allwinner,sun50i-h6-pinctrl"; reg = <0x0300b000 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>, @@ -902,6 +903,7 @@ rtc: rtc@7000000 { compatible = "allwinner,sun50i-h6-rtc"; reg = <0x07000000 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; clock-output-names = "osc32k", "osc32k-out", "iosc"; @@ -927,10 +929,9 @@ }; r_intc: interrupt-controller@7021000 { - compatible = "allwinner,sun50i-h6-r-intc", - "allwinner,sun6i-a31-r-intc"; + compatible = "allwinner,sun50i-h6-r-intc"; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>; reg = <0x07021000 0x400>; interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; }; @@ -938,6 +939,7 @@ r_pio: pinctrl@7022000 { compatible = "allwinner,sun50i-h6-r-pinctrl"; reg = <0x07022000 0x400>; + interrupt-parent = <&r_intc>; interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>; diff --git a/arch/arm64/boot/dts/altera/Makefile b/arch/arm64/boot/dts/altera/Makefile index 10119c7ab4374acb3902634b43b1ce14d9d512c4..4db83fbeb115bcd46db381d951edcc19bf183e89 100644 --- a/arch/arm64/boot/dts/altera/Makefile +++ b/arch/arm64/boot/dts/altera/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -dtb-$(CONFIG_ARCH_STRATIX10) += socfpga_stratix10_socdk.dtb \ +dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_stratix10_socdk.dtb \ socfpga_stratix10_socdk_nand.dtb diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 042627ed98c1cfa46990549b92d67ba3baebab3b..43b9eed921fae98a6a435e16c68a3a4b73f25d3c 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -31,6 +31,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-libretech-cc.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-libretech-cc-v2.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-nexbox-a95x.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-mecool-kii-pro.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-phicomm-n1.dtb @@ -40,6 +41,8 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-libretech-pc.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-khadas-vim2.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-gxm-mecool-kiii-pro.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-gxm-minix-neo-u9h.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q201.dtb diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi index 755b4ad1518467247894b7890a25f11f41db3049..b4000cf65a9a0a69940f6a8bc28228636ea0965d 100644 --- a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi @@ -88,13 +88,13 @@ #reset-cells = <1>; }; - periphs_pinctrl: pinctrl@0400 { + periphs_pinctrl: pinctrl@400 { compatible = "amlogic,meson-a1-periphs-pinctrl"; #address-cells = <2>; #size-cells = <2>; ranges; - gpio: bank@0400 { + gpio: bank@400 { reg = <0x0 0x0400 0x0 0x003c>, <0x0 0x0480 0x0 0x0118>; reg-names = "mux", "gpio"; diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi index d945c84ab697ae944df92923d3e6ca18b3ba57aa..895c43c7af9f7e6297f648703daef092e1fec9ee 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi @@ -1731,7 +1731,6 @@ interrupts = <GIC_SPI 150 IRQ_TYPE_EDGE_RISING>; clocks = <&clkc CLKID_VAPB>; resets = <&reset RESET_GE2D>; - reset-names = "core"; }; gic: interrupt-controller@ffc01000 { diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi index b858c5e43cc88fb1e593b28fe5a93a908331b196..793d48f723906415f179901a969b444495376423 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi @@ -17,6 +17,12 @@ #address-cells = <2>; #size-cells = <2>; + aliases { + mmc0 = &sd_emmc_b; /* SD card */ + mmc1 = &sd_emmc_c; /* eMMC */ + mmc2 = &sd_emmc_a; /* SDIO */ + }; + chosen { #address-cells = <2>; #size-cells = <2>; @@ -122,9 +128,9 @@ pcie: pcie@fc000000 { compatible = "amlogic,g12a-pcie", "snps,dw-pcie"; - reg = <0x0 0xfc000000 0x0 0x400000 - 0x0 0xff648000 0x0 0x2000 - 0x0 0xfc400000 0x0 0x200000>; + reg = <0x0 0xfc000000 0x0 0x400000>, + <0x0 0xff648000 0x0 0x2000>, + <0x0 0xfc400000 0x0 0x200000>; reg-names = "elbi", "cfg", "config"; interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <1>; @@ -134,8 +140,8 @@ #address-cells = <3>; #size-cells = <2>; device_type = "pci"; - ranges = <0x81000000 0 0 0x0 0xfc600000 0 0x00100000 - 0x82000000 0 0xfc700000 0x0 0xfc700000 0 0x1900000>; + ranges = <0x81000000 0 0 0x0 0xfc600000 0 0x00100000>, + <0x82000000 0 0xfc700000 0x0 0xfc700000 0 0x1900000>; clocks = <&clkc CLKID_PCIE_PHY &clkc CLKID_PCIE_COMB @@ -2003,7 +2009,7 @@ }; }; - vrtc: rtc@0a8 { + vrtc: rtc@a8 { compatible = "amlogic,meson-vrtc"; reg = <0x0 0x000a8 0x0 0x4>; }; @@ -2181,7 +2187,7 @@ amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; }; - watchdog: wdt@f0d0 { + watchdog: watchdog@f0d0 { compatible = "amlogic,meson-gxbb-wdt"; reg = <0x0 0xf0d0 0x0 0x10>; clocks = <&xtal>; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-gsking-x.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-gsking-x.dts index 211191f66344677d5fabf1d98d791acbd8c0f2aa..6c7bfacbad78ea2f7641666f126592727c9f63e6 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-gsking-x.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-gsking-x.dts @@ -12,7 +12,7 @@ #include <dt-bindings/sound/meson-g12a-tohdmitx.h> / { - compatible = "azw,gsking-x", "amlogic,g12b"; + compatible = "azw,gsking-x", "amlogic,s922x", "amlogic,g12b"; model = "Beelink GS-King X"; aliases { diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-gtking-pro.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-gtking-pro.dts index 0e331aa5a2d7c46da21577de8f489b7134aab7b9..707daf92787bae1c19637bb90dcdb5d92d361ad7 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-gtking-pro.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-gtking-pro.dts @@ -11,7 +11,7 @@ #include <dt-bindings/sound/meson-g12a-tohdmitx.h> / { - compatible = "azw,gtking", "amlogic,g12b"; + compatible = "azw,gtking", "amlogic,s922x", "amlogic,g12b"; model = "Beelink GT-King Pro"; aliases { @@ -35,7 +35,7 @@ leds { compatible = "gpio-leds"; - white { + led-white { label = "power:white"; gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; default-state = "on"; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts index a7db84a500bb6f4c656edbdfac959f2130e18878..5d96c14490504cc79c41a421adbd79338d17e813 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts @@ -11,7 +11,7 @@ #include <dt-bindings/sound/meson-g12a-tohdmitx.h> / { - compatible = "azw,gtking", "amlogic,g12b"; + compatible = "azw,gtking", "amlogic,s922x", "amlogic,g12b"; model = "Beelink GT-King"; aliases { diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi index 58ce569b2ace92d4f6f4eeafa9c21b46b725c740..344573e157a7bf016544ccb94413ef436d563b25 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi @@ -42,7 +42,7 @@ leds { compatible = "gpio-leds"; - blue { + led-blue { label = "n2:blue"; gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; @@ -410,7 +410,7 @@ &ext_mdio { external_phy: ethernet-phy@0 { - /* Realtek RTL8211F (0x001cc916) */ + /* Realtek RTL8211F (0x001cc916) */ reg = <0>; max-speed = <1000>; @@ -446,13 +446,58 @@ }; &gpio { + gpio-line-names = + /* GPIOZ */ + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + /* GPIOH */ + "", "", "", "", "", "", "", "", + "", + /* BOOT */ + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + /* GPIOC */ + "", "", "", "", "", "", "", "", + /* GPIOA */ + "PIN_44", /* GPIOA_0 */ + "PIN_46", /* GPIOA_1 */ + "PIN_45", /* GPIOA_2 */ + "PIN_47", /* GPIOA_3 */ + "PIN_26", /* GPIOA_4 */ + "", "", "", "", "", "", + "PIN_42", /* GPIOA_11 */ + "PIN_32", /* GPIOA_12 */ + "PIN_7", /* GPIOA_13 */ + "PIN_27", /* GPIOA_14 */ + "PIN_28", /* GPIOA_15 */ + /* GPIOX */ + "PIN_16", /* GPIOX_0 */ + "PIN_18", /* GPIOX_1 */ + "PIN_22", /* GPIOX_2 */ + "PIN_11", /* GPIOX_3 */ + "PIN_13", /* GPIOX_4 */ + "PIN_33", /* GPIOX_5 */ + "PIN_35", /* GPIOX_6 */ + "PIN_15", /* GPIOX_7 */ + "PIN_19", /* GPIOX_8 */ + "PIN_21", /* GPIOX_9 */ + "PIN_24", /* GPIOX_10 */ + "PIN_23", /* GPIOX_11 */ + "PIN_8", /* GPIOX_12 */ + "PIN_10", /* GPIOX_13 */ + "PIN_29", /* GPIOX_14 */ + "PIN_31", /* GPIOX_15 */ + "PIN_12", /* GPIOX_16 */ + "PIN_3", /* GPIOX_17 */ + "PIN_5", /* GPIOX_18 */ + "PIN_36"; /* GPIOX_19 */ /* * WARNING: The USB Hub on the Odroid-N2 needs a reset signal * to be turned high in order to be detected by the USB Controller * This signal should be handled by a USB specific power sequence * in order to reset the Hub when USB bus is powered down. */ - usb-hub { + hog-0 { gpio-hog; gpios = <GPIOH_4 GPIO_ACTIVE_HIGH>; output-high; @@ -508,6 +553,11 @@ status = "okay"; }; +&saradc { + status = "okay"; + vref-supply = <&vddao_1v8>; +}; + /* SD card */ &sd_emmc_b { status = "okay"; diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi index 0edd137151f89eb6ba63695d28abdfaf18cf6434..3d00404aae0f4a981731dc8ddcdb60ccccdc0caa 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi @@ -20,6 +20,12 @@ #address-cells = <2>; #size-cells = <2>; + aliases { + mmc0 = &sd_emmc_b; /* SD card */ + mmc1 = &sd_emmc_c; /* eMMC */ + mmc2 = &sd_emmc_a; /* SDIO */ + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts index bfaf7f41a2d6d9d76612d10865cffb1474be38f8..201596247fd93945eea04aa1346187613e584eb9 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -257,7 +257,7 @@ * This signal should be handled by a USB specific power sequence * in order to reset the Hub when USB bus is powered down. */ - usb-hub { + hog-0 { gpio-hog; gpios = <GPIOAO_4 GPIO_ACTIVE_HIGH>; output-high; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-mecool-kii-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-mecool-kii-pro.dts new file mode 100644 index 0000000000000000000000000000000000000000..c529b6c860a4760ee3b8ec0ae8cc888280249878 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-mecool-kii-pro.dts @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/* + * Author: Christian Hewitt <christianshewitt@gmail.com> + */ + +/dts-v1/; + +#include "meson-gxl-s905d.dtsi" +#include "meson-gx-p23x-q20x.dtsi" +#include <dt-bindings/input/input.h> +#include <dt-bindings/leds/common.h> + +/ { + compatible = "videostrong,gxl-kii-pro", "amlogic,s905d", "amlogic,meson-gxl"; + model = "MeCool KII Pro"; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "Update"; + linux,code = <KEY_VENDOR>; + press-threshold-microvolt = <10000>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-blue { + color = <LED_COLOR_ID_BLUE>; + function = LED_FUNCTION_POWER; + gpios = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>; + default-state = "on"; + panic-indicator; + }; + }; +}; + +ðmac { + phy-mode = "rmii"; + phy-handle = <&internal_phy>; +}; + +&ir { + linux,rc-map-name = "rc-mecool-kii-pro"; +}; + +&sd_emmc_a { + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + max-speed = <2000000>; + clocks = <&wifi32k>; + clock-names = "lpo"; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts index ad6d72254150817e28eda6dc586c3a7918da4fa5..b331a013572f3eb0cb56ffbdf87cd4cbb8cc4aca 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts @@ -16,28 +16,28 @@ leds { compatible = "gpio-leds"; - yellow { + led-yellow { color = <LED_COLOR_ID_YELLOW>; function = LED_FUNCTION_STATUS; gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; default-state = "off"; }; - blue { + led-blue { color = <LED_COLOR_ID_BLUE>; function = LED_FUNCTION_STATUS; gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>; default-state = "off"; }; - green { + led-green { color = <LED_COLOR_ID_GREEN>; function = LED_FUNCTION_STATUS; gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; default-state = "on"; }; - red { + led-red { color = <LED_COLOR_ID_RED>; function = LED_FUNCTION_STATUS; gpios = <&gpio GPIODV_27 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts new file mode 100644 index 0000000000000000000000000000000000000000..ebebf344b7153dcfa1a4033fe1ff9d9896c1cb84 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/* + * Author: Christian Hewitt <christianshewitt@gmail.com> + */ + +/dts-v1/; + +#include "meson-gxm.dtsi" +#include "meson-gx-p23x-q20x.dtsi" +#include <dt-bindings/input/input.h> +#include <dt-bindings/leds/common.h> + +/ { + compatible = "videostrong,gxm-kiii-pro", "amlogic,s912", "amlogic,meson-gxm"; + model = "MeCool KIII Pro"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0xC0000000>; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "Update"; + linux,code = <KEY_VENDOR>; + press-threshold-microvolt = <10000>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-blue { + color = <LED_COLOR_ID_BLUE>; + function = LED_FUNCTION_POWER; + gpios = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>; + default-state = "on"; + panic-indicator; + }; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>; + pinctrl-names = "default"; + + phy-handle = <&external_phy>; + + amlogic,tx-delay-ns = <2>; + + phy-mode = "rgmii"; +}; + +&external_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + max-speed = <1000>; + + reset-assert-us = <10000>; + reset-deassert-us = <80000>; + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&ir { + linux,rc-map-name = "rc-mecool-kiii-pro"; +}; + +&sd_emmc_a { + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + max-speed = <2000000>; + clocks = <&wifi32k>; + clock-names = "lpo"; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts new file mode 100644 index 0000000000000000000000000000000000000000..ea9f234d1fc750a0418159392f73f02ec298416f --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) Christian Hewitt <christianshewitt@gmail.com> + */ + +/dts-v1/; + +#include "meson-gxm.dtsi" +#include "meson-gx-p23x-q20x.dtsi" +#include <dt-bindings/input/input.h> +#include <dt-bindings/leds/common.h> + +/ { + compatible = "minix,neo-u9h", "amlogic,s912", "amlogic,meson-gxm"; + model = "Minix Neo U9-H"; + + leds { + compatible = "gpio-leds"; + + led-white { + color = <LED_COLOR_ID_WHITE>; + function = LED_FUNCTION_POWER; + gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; + default-state = "on"; + panic-indicator; + }; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "update"; + linux,code = <KEY_VENDOR>; + press-threshold-microvolt = <10000>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>; + pinctrl-names = "default"; + phy-handle = <&external_phy>; + amlogic,tx-delay-ns = <2>; + phy-mode = "rgmii"; +}; + +&external_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + max-speed = <1000>; + + reset-assert-us = <10000>; + reset-deassert-us = <80000>; + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&ir { + linux,rc-map-name = "rc-minix-neo"; +}; + +&i2c_B { + status = "okay"; + pinctrl-0 = <&i2c_b_pins>; + pinctrl-names = "default"; + + rtc: rtc@51 { + status = "okay"; + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "xin32k"; + wakeup-source; + }; +}; + +&sd_emmc_a { + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + max-speed = <2000000>; + clocks = <&wifi32k>; + clock-names = "lpo"; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-wetek-core2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-wetek-core2.dts index ec794c134c158d9df29d51821d0563ed52335940..1e7f77f9b533d53073129ae804ecd7d0c71d500c 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm-wetek-core2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-wetek-core2.dts @@ -22,7 +22,7 @@ leds { compatible = "gpio-leds"; - blue { + led-blue { color = <LED_COLOR_ID_BLUE>; function = LED_FUNCTION_STATUS; gpios = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi index 877e3b98920398a544506fc8aa89c79f79b4564a..66d67524b031981089c302b3a0286c817d1d1f38 100644 --- a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi @@ -43,14 +43,14 @@ leds { compatible = "gpio-leds"; - white { + led-white { color = <LED_COLOR_ID_WHITE>; function = LED_FUNCTION_STATUS; gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - red { + led-red { color = <LED_COLOR_ID_RED>; function = LED_FUNCTION_STATUS; gpios = <&gpio_expander 5 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts index b2a4e823c1d8b6219a471c32cf6fb6784f7a99a7..8c327c03d84503760e88fe19c7c76cc315302a11 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts @@ -47,7 +47,7 @@ * This signal should be handled by a USB specific power sequence * in order to reset the Hub when USB bus is powered down. */ - usb-hub { + hog-0 { gpio-hog; gpios = <GPIOH_4 GPIO_ACTIVE_HIGH>; output-high; diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cbbd701ebf05bf049ef9bd8eab095cbe9e80ac48 --- /dev/null +++ b/arch/arm64/boot/dts/apple/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_APPLE) += t8103-j274.dtb diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts new file mode 100644 index 0000000000000000000000000000000000000000..e0f6775b98783445f625809fbc2426ab7a6a0f20 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple Mac mini (M1, 2020) + * + * target-type: J274 + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t8103.dtsi" + +/ { + compatible = "apple,j274", "apple,t8103", "apple,arm-platform"; + model = "Apple Mac mini (M1, 2020)"; + + 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 0x2 0>; /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a1e22a2ea2e53cdb2e0af338f2703eb09a1c18fc --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T8103 "M1" SoC + * + * Other names: H13G, "Tonga" + * + * Copyright The Asahi Linux Contributors + */ + +#include <dt-bindings/interrupt-controller/apple-aic.h> +#include <dt-bindings/interrupt-controller/irq.h> + +/ { + compatible = "apple,t8103", "apple,arm-platform"; + + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu1: cpu@1 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu2: cpu@2 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu3: cpu@3 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu4: cpu@10100 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu5: cpu@10101 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu6: cpu@10102 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10102>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + + cpu7: cpu@10103 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10103>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt"; + interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>, + <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>, + <AIC_FIQ AIC_TMR_HV_PHYS IRQ_TYPE_LEVEL_HIGH>, + <AIC_FIQ AIC_TMR_HV_VIRT IRQ_TYPE_LEVEL_HIGH>; + }; + + clk24: clock-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clk24"; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + + ranges; + nonposted-mmio; + + serial0: serial@235200000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x35200000 0x0 0x1000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = <AIC_IRQ 605 IRQ_TYPE_LEVEL_HIGH>; + /* + * TODO: figure out the clocking properly, there may + * be a third selectable clock. + */ + clocks = <&clk24>, <&clk24>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + aic: interrupt-controller@23b100000 { + compatible = "apple,t8103-aic", "apple,aic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x2 0x3b100000 0x0 0x8000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index f6c55877fbd94fd59cdc4832f64fffe5928fb5d5..1cc7fdcec51bccd2dfb74305c65f2f7557980c61 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -544,6 +544,10 @@ ranges = <0x01000000 0x00 0x00000000 0x00 0x5f800000 0x0 0x00800000>, <0x02000000 0x00 0x50000000 0x00 0x50000000 0x0 0x08000000>, <0x42000000 0x40 0x00000000 0x40 0x00000000 0x1 0x00000000>; + /* Standard AXI Translation entries as programmed by EDK2 */ + dma-ranges = <0x02000000 0x0 0x2c1c0000 0x0 0x2c1c0000 0x0 0x00040000>, + <0x02000000 0x0 0x80000000 0x0 0x80000000 0x0 0x80000000>, + <0x43000000 0x8 0x00000000 0x8 0x00000000 0x2 0x00000000>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &gic 0 GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, @@ -640,7 +644,6 @@ #iommu-cells = <1>; #global-interrupts = <1>; dma-coherent; - status = "disabled"; }; smmu_hdlcd1: iommu@7fb10000 { diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts index 5f290090b0cf27852338108aedce111c17e902ce..0e24e29eb9b1bc69b9dae27d5b0e746482c284a4 100644 --- a/arch/arm64/boot/dts/arm/juno-r1.dts +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -230,6 +230,10 @@ status = "okay"; }; +&smmu_pcie { + status = "okay"; +}; + &etm0 { cpu = <&A57_0>; }; diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts index 305300dd521c9d4f6c22b9436cd55bd3e811c768..e609420ce3e4e48263ae905c8c04f647b2e51289 100644 --- a/arch/arm64/boot/dts/arm/juno-r2.dts +++ b/arch/arm64/boot/dts/arm/juno-r2.dts @@ -236,6 +236,10 @@ status = "okay"; }; +&smmu_pcie { + status = "okay"; +}; + &etm0 { cpu = <&A72_0>; }; diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/Makefile b/arch/arm64/boot/dts/broadcom/bcm4908/Makefile index ebebc0cd421f79be4c8e7ae90ef80b9e16604a67..cc75854519ac362dd03417c2d3d60dbeb4a1857c 100644 --- a/arch/arm64/boot/dts/broadcom/bcm4908/Makefile +++ b/arch/arm64/boot/dts/broadcom/bcm4908/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_BCM4908) += bcm4906-netgear-r8000p.dtb +dtb-$(CONFIG_ARCH_BCM4908) += bcm4906-tplink-archer-c2300-v1.dtb dtb-$(CONFIG_ARCH_BCM4908) += bcm4908-asus-gt-ac5300.dtb diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-netgear-r8000p.dts b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-netgear-r8000p.dts index ee3ed612274c7deab140967f6d2eff8bf8110908..2dd028438c22c8482840faad804b50e8a18cd5ae 100644 --- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-netgear-r8000p.dts +++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-netgear-r8000p.dts @@ -18,11 +18,106 @@ leds { compatible = "gpio-leds"; - wps { + led-power-white { + function = LED_FUNCTION_POWER; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + }; + + led-power-amber { + function = LED_FUNCTION_POWER; + color = <LED_COLOR_ID_AMBER>; + gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; + }; + + led-wps { function = LED_FUNCTION_WPS; color = <LED_COLOR_ID_WHITE>; gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; }; + + led-2ghz { + function = "2ghz"; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + }; + + led-5ghz-1 { + function = "5ghz-1"; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + }; + + led-5ghz-2 { + function = "5ghz-2"; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 16 GPIO_ACTIVE_LOW>; + }; + + led-usb2 { + function = "usb2"; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + }; + + led-usb3 { + function = "usb3"; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + }; + + led-wifi { + function = "wifi"; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 56 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&enet { + nvmem-cells = <&base_mac_addr>; + nvmem-cell-names = "mac-address"; +}; + +&usb_phy { + brcm,ioc = <1>; + status = "okay"; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&xhci { + status = "okay"; +}; + +&ports { + port@0 { + label = "lan4"; + }; + + port@1 { + label = "lan3"; + }; + + port@2 { + label = "lan2"; + }; + + port@3 { + label = "lan1"; + }; + + port@7 { + reg = <7>; + phy-mode = "internal"; + phy-handle = <&phy12>; + label = "wan"; }; }; @@ -40,11 +135,21 @@ #size-cells = <1>; partition@0 { + compatible = "nvmem-cells"; label = "cferom"; reg = <0x0 0x100000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x100000>; + + base_mac_addr: mac@106a0 { + reg = <0x106a0 0x6>; + }; }; partition@100000 { + compatible = "brcm,bcm4908-firmware"; label = "firmware"; reg = <0x100000 0x4400000>; }; diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-tplink-archer-c2300-v1.dts b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-tplink-archer-c2300-v1.dts new file mode 100644 index 0000000000000000000000000000000000000000..b63eefab48bd50e7bafd647e55b710a05f99666e --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-tplink-archer-c2300-v1.dts @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> +#include <dt-bindings/leds/common.h> + +#include "bcm4906.dtsi" + +/ { + compatible = "tplink,archer-c2300-v1", "brcm,bcm4906", "brcm,bcm4908"; + model = "TP-Link Archer C2300 V1"; + + memory@0 { + device_type = "memory"; + reg = <0x00 0x00 0x00 0x20000000>; + }; + + leds { + compatible = "gpio-leds"; + + led-power { + function = LED_FUNCTION_POWER; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + }; + + led-2ghz { + function = "2ghz"; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + }; + + led-5ghz { + function = "5ghz"; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + }; + + led-wan-amber { + function = LED_FUNCTION_WAN; + color = <LED_COLOR_ID_AMBER>; + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + }; + + led-wan-blue { + function = LED_FUNCTION_WAN; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + }; + + led-lan { + function = LED_FUNCTION_LAN; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + }; + + led-wps { + function = LED_FUNCTION_WPS; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + }; + + led-usb2 { + function = "usb2"; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + }; + + led-usb3 { + function = "usbd3"; + color = <LED_COLOR_ID_BLUE>; + gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + }; + + led-brightness { + function = LED_FUNCTION_BACKLIGHT; + color = <LED_COLOR_ID_WHITE>; + gpios = <&gpio0 19 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <100>; + + brightness { + label = "LEDs"; + linux,code = <KEY_BRIGHTNESS_ZERO>; + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "WPS"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + }; + + wifi { + label = "WiFi"; + linux,code = <KEY_RFKILL>; + gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; + }; + + restart { + label = "Reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&usb_phy { + brcm,ioc = <1>; + status = "okay"; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&xhci { + status = "okay"; +}; + +&ports { + port@0 { + label = "lan4"; + }; + + port@1 { + label = "lan3"; + }; + + port@2 { + label = "lan2"; + }; + + port@3 { + label = "lan1"; + }; + + port@7 { + reg = <7>; + phy-mode = "internal"; + phy-handle = <&phy12>; + label = "wan"; + }; +}; + +&nandcs { + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + nand-on-flash-bbt; + + #address-cells = <1>; + #size-cells = <0>; + + partitions { + compatible = "brcm,bcm4908-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "cferom"; + reg = <0x0 0x100000>; + }; + + partition@100000 { + compatible = "brcm,bcm4908-firmware"; + reg = <0x100000 0x3900000>; + }; + + partition@5800000 { + compatible = "brcm,bcm4908-firmware"; + reg = <0x3a00000 0x3900000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts index 6e4ad66ff536007c8fa41dcf7c122048fe64f3c7..169fbb7cfd34261d1c3cc95f27d2447dee1da65c 100644 --- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts +++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts @@ -44,6 +44,28 @@ }; }; +&enet { + nvmem-cells = <&base_mac_addr>; + nvmem-cell-names = "mac-address"; +}; + +&usb_phy { + brcm,ioc = <1>; + status = "okay"; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&xhci { + status = "okay"; +}; + &ports { port@0 { label = "lan2"; @@ -65,6 +87,7 @@ port@7 { label = "sw"; reg = <7>; + phy-mode = "rgmii"; fixed-link { speed = <1000>; @@ -105,13 +128,32 @@ #size-cells = <0>; partitions { - compatible = "fixed-partitions"; + compatible = "brcm,bcm4908-partitions"; #address-cells = <1>; #size-cells = <1>; partition@0 { + compatible = "nvmem-cells"; label = "cferom"; reg = <0x0 0x100000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x100000>; + + base_mac_addr: mac@106a0 { + reg = <0x106a0 0x6>; + }; + }; + + partition@100000 { + compatible = "brcm,bcm4908-firmware"; + reg = <0x100000 0x5700000>; + }; + + partition@5800000 { + compatible = "brcm,bcm4908-firmware"; + reg = <0x5800000 0x5700000>; }; }; }; diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi index 9354077f74cd623a119b71014a259d812cf0d174..8060178b365d860c283c6b96d6b75b0fe94398e1 100644 --- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi @@ -2,6 +2,8 @@ #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/phy/phy.h> +#include <dt-bindings/soc/bcm-pmb.h> /dts-v1/; @@ -110,28 +112,52 @@ #size-cells = <1>; ranges = <0x00 0x00 0x80000000 0x281000>; - usb@c300 { + enet: ethernet@2000 { + compatible = "brcm,bcm4908-enet"; + reg = <0x2000 0x1000>; + + interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "rx", "tx"; + }; + + usb_phy: usb-phy@c200 { + compatible = "brcm,bcm4908-usb-phy"; + reg = <0xc200 0x100>; + reg-names = "ctrl"; + power-domains = <&pmb BCM_PMB_HOST_USB>; + dr_mode = "host"; + brcm,has-xhci; + brcm,has-eohci; + #phy-cells = <1>; + status = "disabled"; + }; + + ehci: usb@c300 { compatible = "generic-ehci"; reg = <0xc300 0x100>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + phys = <&usb_phy PHY_TYPE_USB2>; status = "disabled"; }; - usb@c400 { + ohci: usb@c400 { compatible = "generic-ohci"; reg = <0xc400 0x100>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + phys = <&usb_phy PHY_TYPE_USB2>; status = "disabled"; }; - usb@d000 { + xhci: usb@d000 { compatible = "generic-xhci"; reg = <0xd000 0x8c8>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; + phys = <&usb_phy PHY_TYPE_USB3>; status = "disabled"; }; - ethernet-switch@80000 { + bus@80000 { compatible = "simple-bus"; #size-cells = <1>; #address-cells = <1>; @@ -182,6 +208,17 @@ phy-mode = "internal"; phy-handle = <&phy11>; }; + + port@8 { + reg = <8>; + phy-mode = "internal"; + ethernet = <&enet>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; }; }; @@ -222,7 +259,7 @@ #address-cells = <1>; #size-cells = <1>; - power-controller@2800c0 { + pmb: power-controller@2800c0 { compatible = "brcm,bcm4908-pmb"; reg = <0x2800c0 0x40>; #power-domain-cells = <1>; diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi index 413cac63a1cb3a50069721d662fb44f16e277de3..773d9abe3a4491bb438d4e3fd298ec205e787d9a 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi @@ -1002,7 +1002,7 @@ ppmu_event0_d1_general: ppmu-event0-d1-general { event-name = "ppmu-event0-d1-general"; }; - }; + }; }; &pinctrl_alive { diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi index 6433f9ee35e19b4cfd19f6b1f6d191f5a794e5f2..18a912eee36054aec10806a70b8d6e1b5c3167c5 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi @@ -564,9 +564,9 @@ compatible = "samsung,exynos5433-slim-sss"; reg = <0x11140000 0x1000>; interrupts = <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>; - clock-names = "aclk", "pclk"; - clocks = <&cmu_imem CLK_ACLK_SLIMSSS>, - <&cmu_imem CLK_PCLK_SLIMSSS>; + clock-names = "pclk", "aclk"; + clocks = <&cmu_imem CLK_PCLK_SLIMSSS>, + <&cmu_imem CLK_ACLK_SLIMSSS>; }; pd_gscl: power-domain@105c4000 { diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 6438db3822f822380f0af1e0c8334c4203d1daa3..44890d56c194d295410d77b6b5c4ac7866674aed 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -33,6 +33,8 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2162a-qds.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-beacon-kit.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-ddr4-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-kontron-n801x-s.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-nitrogen-r2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-var-som-symphony.dtb @@ -47,6 +49,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-hummingboard-pulse.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mq-kontron-pitx-imx8m.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-devkit.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-r2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-r3.dtb @@ -57,6 +60,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mq-pico-pi.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-thor96.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8qm-mek.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-eval-v3.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts index 0516076087ae33b7b449a7e62612aa71de6f6e7e..a92ecb331cdcb0146ae47fe142cb97cf79c2bf40 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts @@ -25,6 +25,8 @@ spi1 = &dspi2; mmc0 = &esdhc1; mmc1 = &esdhc; + rtc0 = &rtc; + rtc1 = &ftm_alarm0; }; buttons0 { @@ -115,8 +117,6 @@ status = "okay"; flash@0 { - #address-cells = <1>; - #size-cells = <1>; compatible = "jedec,spi-nor"; m25p,fast-read; spi-max-frequency = <133000000>; @@ -125,49 +125,37 @@ spi-rx-bus-width = <2>; /* 2 SPI Rx lines */ spi-tx-bus-width = <1>; /* 1 SPI Tx line */ - partition@0 { - reg = <0x000000 0x010000>; - label = "rcw"; - read-only; - }; - - partition@10000 { - reg = <0x010000 0x0f0000>; - label = "failsafe bootloader"; - read-only; - }; - - partition@100000 { - reg = <0x100000 0x040000>; - label = "failsafe DP firmware"; - read-only; - }; - - partition@140000 { - reg = <0x140000 0x0a0000>; - label = "failsafe trusted firmware"; - read-only; - }; - - partition@1e0000 { - reg = <0x1e0000 0x020000>; - label = "reserved"; - read-only; - }; - - partition@200000 { - reg = <0x200000 0x010000>; - label = "configuration store"; - }; - - partition@210000 { - reg = <0x210000 0x1d0000>; - label = "bootloader"; - }; - - partition@3e0000 { - reg = <0x3e0000 0x020000>; - label = "bootloader environment"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + reg = <0x000000 0x010000>; + label = "rcw"; + read-only; + }; + + partition@10000 { + reg = <0x010000 0x1d0000>; + label = "failsafe bootloader"; + read-only; + }; + + partition@200000 { + reg = <0x200000 0x010000>; + label = "configuration store"; + }; + + partition@210000 { + reg = <0x210000 0x1d0000>; + label = "bootloader"; + }; + + partition@3e0000 { + reg = <0x3e0000 0x020000>; + label = "bootloader environment"; + }; }; }; }; @@ -191,7 +179,7 @@ &i2c0 { status = "okay"; - rtc@32 { + rtc: rtc@32 { compatible = "microcrystal,rv8803"; reg = <0x32>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts index fbcba9cb8503dc06210d01aef5d1443c201ca1b1..bfd14b64567e49469178285d33f35c68f73bf613 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts @@ -25,6 +25,7 @@ serial1 = &duart1; mmc0 = &esdhc; mmc1 = &esdhc1; + rtc1 = &ftm_alarm0; }; chosen { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts index 41ae6e7675ba9558aea580ebb441f2a0942c78f5..9322c6ad8e4aee291720062d55ff23724cbc26e1 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts @@ -21,6 +21,7 @@ serial1 = &duart1; mmc0 = &esdhc; mmc1 = &esdhc1; + rtc1 = &ftm_alarm0; }; chosen { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi index 262fbad8f0ec5ed1ec036948f411328ef25beb89..9506f0669eaddd926dd398a09f07e2075ee20734 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi @@ -18,10 +18,6 @@ #address-cells = <2>; #size-cells = <2>; - aliases { - rtc1 = &ftm_alarm0; - }; - cpus { #address-cells = <1>; #size-cells = <0>; @@ -1027,7 +1023,7 @@ status = "disabled"; fixed-link { - speed = <1000>; + speed = <2500>; full-duplex; }; }; @@ -1114,6 +1110,12 @@ full-duplex; }; }; + + rcec@1f,0 { + reg = <0x00f800 0 0 0 0>; + /* IEP INT_A */ + interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; + }; }; rcpm: power-controller@1e34040 { diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi index 459dccad83269cd08cb9c34d959621fb986b4558..afb455210bd07ed68319890c6fed3549d63f38e7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi @@ -122,6 +122,30 @@ vcc-supply = <&sb_3v3>; }; }; + + sfp0_i2c: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + sfp1_i2c: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + sfp2_i2c: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + sfp3_i2c: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-clearfog-itx.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a-clearfog-itx.dtsi index 2b63235ca627009926b0654de0a187a836e9736b..17f8e733972a3077ecfed361f0dfa15fef851cee 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-clearfog-itx.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-clearfog-itx.dtsi @@ -30,6 +30,54 @@ gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; }; }; + + sfp0: sfp-0 { + compatible = "sff,sfp"; + i2c-bus = <&sfp0_i2c>; + mod-def0-gpio = <&gpio2 0 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <2000>; + }; + + sfp1: sfp-1 { + compatible = "sff,sfp"; + i2c-bus = <&sfp1_i2c>; + mod-def0-gpio = <&gpio2 9 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <2000>; + }; + + sfp2: sfp-2 { + compatible = "sff,sfp"; + i2c-bus = <&sfp2_i2c>; + mod-def0-gpio = <&gpio2 10 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <2000>; + }; + + sfp3: sfp-3 { + compatible = "sff,sfp"; + i2c-bus = <&sfp3_i2c>; + mod-def0-gpio = <&gpio2 11 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <2000>; + }; +}; + +&dpmac7 { + sfp = <&sfp0>; + managed = "in-band-status"; +}; + +&dpmac8 { + sfp = <&sfp1>; + managed = "in-band-status"; +}; + +&dpmac9 { + sfp = <&sfp2>; + managed = "in-band-status"; +}; + +&dpmac10 { + sfp = <&sfp3>; + managed = "in-band-status"; }; &emdio2 { @@ -44,6 +92,22 @@ status = "okay"; }; +&pcs_mdio7 { + status = "okay"; +}; + +&pcs_mdio8 { + status = "okay"; +}; + +&pcs_mdio9 { + status = "okay"; +}; + +&pcs_mdio10 { + status = "okay"; +}; + &sata0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-adma.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-adma.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9386d1a59e82b6e8a8b10e460b6708a32a992b5c --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-adma.dtsi @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include "imx8-ss-audio.dtsi" +#include "imx8-ss-dma.dtsi" diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6c8d75ef92503dbe5e4049be9b59b7e754adcb8a --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/clock/imx8-lpcg.h> +#include <dt-bindings/firmware/imx/rsrc.h> + +audio_subsys: bus@59000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x59000000 0x0 0x59000000 0x1000000>; + + audio_ipg_clk: clock-audio-ipg { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <120000000>; + clock-output-names = "audio_ipg_clk"; + }; + + dsp_lpcg: clock-controller@59580000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x59580000 0x10000>; + #clock-cells = <1>; + clocks = <&audio_ipg_clk>, + <&audio_ipg_clk>, + <&audio_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_7>; + clock-output-names = "dsp_lpcg_adb_clk", + "dsp_lpcg_ipg_clk", + "dsp_lpcg_core_clk"; + power-domains = <&pd IMX_SC_R_DSP>; + }; + + dsp_ram_lpcg: clock-controller@59590000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x59590000 0x10000>; + #clock-cells = <1>; + clocks = <&audio_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_4>; + clock-output-names = "dsp_ram_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_DSP_RAM>; + }; + + dsp: dsp@596e8000 { + compatible = "fsl,imx8qxp-dsp"; + 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>; + memory-region = <&dsp_reserved>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e1e81ca0ca698a0e579bc982aae1dfc4bfb37b60 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/clock/imx8-lpcg.h> +#include <dt-bindings/firmware/imx/rsrc.h> + +conn_subsys: bus@5b000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5b000000 0x0 0x5b000000 0x1000000>; + + conn_axi_clk: clock-conn-axi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <333333333>; + clock-output-names = "conn_axi_clk"; + }; + + conn_ahb_clk: clock-conn-ahb { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <166666666>; + clock-output-names = "conn_ahb_clk"; + }; + + conn_ipg_clk: clock-conn-ipg { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <83333333>; + clock-output-names = "conn_ipg_clk"; + }; + + usdhc1: mmc@5b010000 { + interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x5b010000 0x10000>; + clocks = <&sdhc0_lpcg IMX_LPCG_CLK_4>, + <&sdhc0_lpcg IMX_LPCG_CLK_5>, + <&sdhc0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "per", "ahb"; + power-domains = <&pd IMX_SC_R_SDHC_0>; + status = "disabled"; + }; + + usdhc2: mmc@5b020000 { + interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x5b020000 0x10000>; + clocks = <&sdhc1_lpcg IMX_LPCG_CLK_4>, + <&sdhc1_lpcg IMX_LPCG_CLK_5>, + <&sdhc1_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "per", "ahb"; + power-domains = <&pd IMX_SC_R_SDHC_1>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + status = "disabled"; + }; + + usdhc3: mmc@5b030000 { + interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x5b030000 0x10000>; + clocks = <&sdhc2_lpcg IMX_LPCG_CLK_4>, + <&sdhc2_lpcg IMX_LPCG_CLK_5>, + <&sdhc2_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "per", "ahb"; + power-domains = <&pd IMX_SC_R_SDHC_2>; + status = "disabled"; + }; + + fec1: ethernet@5b040000 { + reg = <0x5b040000 0x10000>; + interrupts = <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&enet0_lpcg IMX_LPCG_CLK_4>, + <&enet0_lpcg IMX_LPCG_CLK_2>, + <&enet0_lpcg IMX_LPCG_CLK_1>, + <&enet0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "ahb", "enet_clk_ref", "ptp"; + fsl,num-tx-queues=<3>; + fsl,num-rx-queues=<3>; + power-domains = <&pd IMX_SC_R_ENET_0>; + status = "disabled"; + }; + + fec2: ethernet@5b050000 { + reg = <0x5b050000 0x10000>; + interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&enet1_lpcg IMX_LPCG_CLK_4>, + <&enet1_lpcg IMX_LPCG_CLK_2>, + <&enet1_lpcg IMX_LPCG_CLK_1>, + <&enet1_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "ahb", "enet_clk_ref", "ptp"; + fsl,num-tx-queues=<3>; + fsl,num-rx-queues=<3>; + power-domains = <&pd IMX_SC_R_ENET_1>; + status = "disabled"; + }; + + /* LPCG clocks */ + sdhc0_lpcg: clock-controller@5b200000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5b200000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_SDHC_0 IMX_SC_PM_CLK_PER>, + <&conn_ipg_clk>, <&conn_axi_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>, + <IMX_LPCG_CLK_5>; + clock-output-names = "sdhc0_lpcg_per_clk", + "sdhc0_lpcg_ipg_clk", + "sdhc0_lpcg_ahb_clk"; + power-domains = <&pd IMX_SC_R_SDHC_0>; + }; + + sdhc1_lpcg: clock-controller@5b210000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5b210000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_SDHC_1 IMX_SC_PM_CLK_PER>, + <&conn_ipg_clk>, <&conn_axi_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>, + <IMX_LPCG_CLK_5>; + clock-output-names = "sdhc1_lpcg_per_clk", + "sdhc1_lpcg_ipg_clk", + "sdhc1_lpcg_ahb_clk"; + power-domains = <&pd IMX_SC_R_SDHC_1>; + }; + + sdhc2_lpcg: clock-controller@5b220000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5b220000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_SDHC_2 IMX_SC_PM_CLK_PER>, + <&conn_ipg_clk>, <&conn_axi_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>, + <IMX_LPCG_CLK_5>; + clock-output-names = "sdhc2_lpcg_per_clk", + "sdhc2_lpcg_ipg_clk", + "sdhc2_lpcg_ahb_clk"; + power-domains = <&pd IMX_SC_R_SDHC_2>; + }; + + enet0_lpcg: clock-controller@5b230000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5b230000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_ENET_0 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_ENET_0 IMX_SC_PM_CLK_PER>, + <&conn_axi_clk>, <&conn_ipg_clk>, <&conn_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_2>, <IMX_LPCG_CLK_4>, + <IMX_LPCG_CLK_5>; + clock-output-names = "enet0_ipg_root_clk", + "enet0_tx_clk", + "enet0_ahb_clk", + "enet0_ipg_clk", + "enet0_ipg_s_clk"; + power-domains = <&pd IMX_SC_R_ENET_0>; + }; + + enet1_lpcg: clock-controller@5b240000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5b240000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_ENET_1 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_ENET_1 IMX_SC_PM_CLK_PER>, + <&conn_axi_clk>, <&conn_ipg_clk>, <&conn_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_2>, <IMX_LPCG_CLK_4>, + <IMX_LPCG_CLK_5>; + clock-output-names = "enet1_ipg_root_clk", + "enet1_tx_clk", + "enet1_ahb_clk", + "enet1_ipg_clk", + "enet1_ipg_s_clk"; + power-domains = <&pd IMX_SC_R_ENET_1>; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-ddr.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-ddr.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8b5cad4e270029883ae03ead30456e2d1ddbb0af --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-ddr.dtsi @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +ddr_subsys: bus@5c000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5c000000 0x0 0x5c000000 0x1000000>; + + ddr-pmu@5c020000 { + compatible = "fsl,imx8-ddr-pmu"; + reg = <0x5c020000 0x10000>; + interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..960a802b8b6eea02635c588197787377867ffd3c --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/clock/imx8-lpcg.h> +#include <dt-bindings/firmware/imx/rsrc.h> + +dma_subsys: bus@5a000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5a000000 0x0 0x5a000000 0x1000000>; + + dma_ipg_clk: clock-dma-ipg { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <120000000>; + clock-output-names = "dma_ipg_clk"; + }; + + lpuart0: serial@5a060000 { + reg = <0x5a060000 0x1000>; + interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart0_lpcg IMX_LPCG_CLK_4>, + <&uart0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "baud"; + power-domains = <&pd IMX_SC_R_UART_0>; + status = "disabled"; + }; + + lpuart1: serial@5a070000 { + reg = <0x5a070000 0x1000>; + interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart1_lpcg IMX_LPCG_CLK_4>, + <&uart1_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "baud"; + power-domains = <&pd IMX_SC_R_UART_1>; + status = "disabled"; + }; + + lpuart2: serial@5a080000 { + reg = <0x5a080000 0x1000>; + interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart2_lpcg IMX_LPCG_CLK_4>, + <&uart2_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "baud"; + power-domains = <&pd IMX_SC_R_UART_2>; + status = "disabled"; + }; + + lpuart3: serial@5a090000 { + reg = <0x5a090000 0x1000>; + interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart3_lpcg IMX_LPCG_CLK_4>, + <&uart3_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "baud"; + power-domains = <&pd IMX_SC_R_UART_3>; + status = "disabled"; + }; + + uart0_lpcg: clock-controller@5a460000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5a460000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "uart0_lpcg_baud_clk", + "uart0_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_UART_0>; + }; + + uart1_lpcg: clock-controller@5a470000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5a470000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_UART_1 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "uart1_lpcg_baud_clk", + "uart1_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_UART_1>; + }; + + uart2_lpcg: clock-controller@5a480000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5a480000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_UART_2 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "uart2_lpcg_baud_clk", + "uart2_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_UART_2>; + }; + + uart3_lpcg: clock-controller@5a490000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5a490000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_UART_3 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "uart3_lpcg_baud_clk", + "uart3_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_UART_3>; + }; + + i2c0: i2c@5a800000 { + reg = <0x5a800000 0x4000>; + interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&i2c0_lpcg IMX_LPCG_CLK_0>; + clock-names = "per"; + assigned-clocks = <&clk IMX_SC_R_I2C_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; + power-domains = <&pd IMX_SC_R_I2C_0>; + status = "disabled"; + }; + + i2c1: i2c@5a810000 { + reg = <0x5a810000 0x4000>; + interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&i2c1_lpcg IMX_LPCG_CLK_0>; + clock-names = "per"; + assigned-clocks = <&clk IMX_SC_R_I2C_1 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; + power-domains = <&pd IMX_SC_R_I2C_1>; + status = "disabled"; + }; + + i2c2: i2c@5a820000 { + reg = <0x5a820000 0x4000>; + interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&i2c2_lpcg IMX_LPCG_CLK_0>; + clock-names = "per"; + assigned-clocks = <&clk IMX_SC_R_I2C_2 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; + power-domains = <&pd IMX_SC_R_I2C_2>; + status = "disabled"; + }; + + i2c3: i2c@5a830000 { + reg = <0x5a830000 0x4000>; + interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&i2c3_lpcg IMX_LPCG_CLK_0>; + clock-names = "per"; + assigned-clocks = <&clk IMX_SC_R_I2C_3 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; + power-domains = <&pd IMX_SC_R_I2C_3>; + status = "disabled"; + }; + + i2c0_lpcg: clock-controller@5ac00000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5ac00000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_I2C_0 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "i2c0_lpcg_clk", + "i2c0_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_I2C_0>; + }; + + i2c1_lpcg: clock-controller@5ac10000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5ac10000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_I2C_1 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "i2c1_lpcg_clk", + "i2c1_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_I2C_1>; + }; + + i2c2_lpcg: clock-controller@5ac20000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5ac20000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_I2C_2 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "i2c2_lpcg_clk", + "i2c2_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_I2C_2>; + }; + + i2c3_lpcg: clock-controller@5ac30000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5ac30000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_I2C_3 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "i2c3_lpcg_clk", + "i2c3_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_I2C_3>; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ee4e585a9c391aff4358d555204258cd70c6e292 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/clock/imx8-lpcg.h> +#include <dt-bindings/firmware/imx/rsrc.h> + +lsio_subsys: bus@5d000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5d000000 0x0 0x5d000000 0x1000000>; + + lsio_mem_clk: clock-lsio-mem { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "lsio_mem_clk"; + }; + + lsio_bus_clk: clock-lsio-bus { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "lsio_bus_clk"; + }; + + lsio_gpio0: gpio@5d080000 { + reg = <0x5d080000 0x10000>; + interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_0>; + }; + + lsio_gpio1: gpio@5d090000 { + reg = <0x5d090000 0x10000>; + interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_1>; + }; + + lsio_gpio2: gpio@5d0a0000 { + reg = <0x5d0a0000 0x10000>; + interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_2>; + }; + + lsio_gpio3: gpio@5d0b0000 { + reg = <0x5d0b0000 0x10000>; + interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_3>; + }; + + lsio_gpio4: gpio@5d0c0000 { + reg = <0x5d0c0000 0x10000>; + interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_4>; + }; + + lsio_gpio5: gpio@5d0d0000 { + reg = <0x5d0d0000 0x10000>; + interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_5>; + }; + + lsio_gpio6: gpio@5d0e0000 { + reg = <0x5d0e0000 0x10000>; + interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_6>; + }; + + lsio_gpio7: gpio@5d0f0000 { + reg = <0x5d0f0000 0x10000>; + interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + power-domains = <&pd IMX_SC_R_GPIO_7>; + }; + + lsio_mu0: mailbox@5d1b0000 { + reg = <0x5d1b0000 0x10000>; + interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + status = "disabled"; + }; + + lsio_mu1: mailbox@5d1c0000 { + reg = <0x5d1c0000 0x10000>; + interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + }; + + lsio_mu2: mailbox@5d1d0000 { + reg = <0x5d1d0000 0x10000>; + interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + status = "disabled"; + }; + + lsio_mu3: mailbox@5d1e0000 { + reg = <0x5d1e0000 0x10000>; + interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + status = "disabled"; + }; + + lsio_mu4: mailbox@5d1f0000 { + reg = <0x5d1f0000 0x10000>; + interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + status = "disabled"; + }; + + lsio_mu13: mailbox@5d280000 { + reg = <0x5d280000 0x10000>; + interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <2>; + power-domains = <&pd IMX_SC_R_MU_13A>; + }; + + /* LPCG clocks */ + pwm0_lpcg: clock-controller@5d400000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d400000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_0 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_0 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_0 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_0 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm0_lpcg_ipg_clk", + "pwm0_lpcg_ipg_hf_clk", + "pwm0_lpcg_ipg_s_clk", + "pwm0_lpcg_ipg_slv_clk", + "pwm0_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_0>; + }; + + pwm1_lpcg: clock-controller@5d410000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d410000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm1_lpcg_ipg_clk", + "pwm1_lpcg_ipg_hf_clk", + "pwm1_lpcg_ipg_s_clk", + "pwm1_lpcg_ipg_slv_clk", + "pwm1_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_1>; + }; + + pwm2_lpcg: clock-controller@5d420000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d420000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm2_lpcg_ipg_clk", + "pwm2_lpcg_ipg_hf_clk", + "pwm2_lpcg_ipg_s_clk", + "pwm2_lpcg_ipg_slv_clk", + "pwm2_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_2>; + }; + + pwm3_lpcg: clock-controller@5d430000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d430000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_3 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_3 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_3 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_3 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm3_lpcg_ipg_clk", + "pwm3_lpcg_ipg_hf_clk", + "pwm3_lpcg_ipg_s_clk", + "pwm3_lpcg_ipg_slv_clk", + "pwm3_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_3>; + }; + + pwm4_lpcg: clock-controller@5d440000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d440000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_4 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_4 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_4 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_4 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm4_lpcg_ipg_clk", + "pwm4_lpcg_ipg_hf_clk", + "pwm4_lpcg_ipg_s_clk", + "pwm4_lpcg_ipg_slv_clk", + "pwm4_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_4>; + }; + + pwm5_lpcg: clock-controller@5d450000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d450000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_5 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_5 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_5 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_5 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm5_lpcg_ipg_clk", + "pwm5_lpcg_ipg_hf_clk", + "pwm5_lpcg_ipg_s_clk", + "pwm5_lpcg_ipg_slv_clk", + "pwm5_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_5>; + }; + + pwm6_lpcg: clock-controller@5d460000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d460000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_6 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_6 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_6 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_6 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm6_lpcg_ipg_clk", + "pwm6_lpcg_ipg_hf_clk", + "pwm6_lpcg_ipg_s_clk", + "pwm6_lpcg_ipg_slv_clk", + "pwm6_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_6>; + }; + + pwm7_lpcg: clock-controller@5d470000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5d470000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_PWM_7 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_7 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_PWM_7 IMX_SC_PM_CLK_PER>, + <&lsio_bus_clk>, + <&clk IMX_SC_R_PWM_7 IMX_SC_PM_CLK_PER>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_1>, + <IMX_LPCG_CLK_4>, <IMX_LPCG_CLK_5>, + <IMX_LPCG_CLK_6>; + clock-output-names = "pwm7_lpcg_ipg_clk", + "pwm7_lpcg_ipg_hf_clk", + "pwm7_lpcg_ipg_s_clk", + "pwm7_lpcg_ipg_slv_clk", + "pwm7_lpcg_ipg_mstr_clk"; + power-domains = <&pd IMX_SC_R_PWM_7>; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm-ctouch2.dts b/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm-ctouch2.dts new file mode 100644 index 0000000000000000000000000000000000000000..5389d6f2beba9d0cff05192ffa6ec207ce0df104 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm-ctouch2.dts @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 NXP + * Copyright (c) 2019 Engicam srl + * Copyright (c) 2020 Amarula Solutions(India) + */ + +/dts-v1/; +#include "imx8mm.dtsi" +#include "imx8mm-icore-mx8mm.dtsi" + +/ { + model = "Engicam i.Core MX8M Mini C.TOUCH 2.0"; + compatible = "engicam,icore-mx8mm-ctouch2", "engicam,icore-mx8mm", + "fsl,imx8mm"; + + chosen { + stdout-path = &uart2; + }; +}; + +&fec1 { + status = "okay"; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; +}; + +&i2c4 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; +}; + +&iomuxc { + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3 + MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 + MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140 + MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX 0x140 + >; + }; + + pinctrl_usdhc1_gpio: usdhc1gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x41 + >; + }; + + 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 + >; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +/* SD */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + cd-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + max-frequency = <50000000>; + bus-width = <4>; + no-1-8-v; + pm-ignore-notify; + keep-power-in-suspend; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm-edimm2.2.dts b/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm-edimm2.2.dts new file mode 100644 index 0000000000000000000000000000000000000000..a4a2ada148353f70450625fdfc03e4d7116870b5 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm-edimm2.2.dts @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 NXP + * Copyright (c) 2019 Engicam srl + * Copyright (c) 2020 Amarula Solutions(India) + */ + +/dts-v1/; +#include "imx8mm.dtsi" +#include "imx8mm-icore-mx8mm.dtsi" + +/ { + model = "Engicam i.Core MX8M Mini EDIMM2.2 Starter Kit"; + compatible = "engicam,icore-mx8mm-edimm2.2", "engicam,icore-mx8mm", + "fsl,imx8mm"; + + chosen { + stdout-path = &uart2; + }; +}; + +&fec1 { + status = "okay"; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; +}; + +&i2c4 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; +}; + +&iomuxc { + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3 + MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 + MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140 + MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX 0x140 + >; + }; + + pinctrl_usdhc1_gpio: usdhc1gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x41 + >; + }; + + 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 + >; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +/* SD */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + cd-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + max-frequency = <50000000>; + bus-width = <4>; + no-1-8-v; + pm-ignore-notify; + keep-power-in-suspend; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b40148d728ea94ade4adcf7e47db1654b4aef8de --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm.dtsi @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2018 NXP + * Copyright (c) 2019 Engicam srl + * Copyright (c) 2020 Amarula Solutons(India) + */ + +/ { + compatible = "engicam,icore-mx8mm", "fsl,imx8mm"; +}; + +&A53_0 { + cpu-supply = <®_buck4>; +}; + +&A53_1 { + cpu-supply = <®_buck4>; +}; + +&A53_2 { + cpu-supply = <®_buck4>; +}; + +&A53_3 { + cpu-supply = <®_buck4>; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + reset-gpios = <&gpio3 7 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@8 { + compatible = "nxp,pf8121a"; + reg = <0x08>; + + regulators { + reg_ldo1: ldo1 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_ldo2: ldo2 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_ldo3: ldo3 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_ldo4: ldo4 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck1: buck1 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck2: buck2 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck3: buck3 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck4: buck4 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck5: buck5 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck6: buck6 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_buck7: buck7 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_vsnvs: vsnvs { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; +}; + +&iomuxc { + pinctrl_fec1: fec1grp { + fsl,pins = < + MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x3 + MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO 0x3 + MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f + MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f + MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f + MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f + MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91 + MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91 + MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91 + MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91 + MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f + MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 + MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 + MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f + MX8MM_IOMUXC_NAND_DATA01_GPIO3_IO7 0x19 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 + MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x190 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d0 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d0 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d0 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d0 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d0 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d0 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d0 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d0 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d0 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d0 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x190 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x194 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d4 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d4 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d4 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d4 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d4 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d4 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d4 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d4 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d4 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x196 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d6 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d6 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d6 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d6 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d6 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d6 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d6 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d6 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d6 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x196 + >; + }; +}; + +/* eMMC */ +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts b/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts index c0c384d7614795277487c44fc5d73a85a36eb6d9..74c09891600f2525928321e13dbae633a9517560 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts @@ -9,6 +9,53 @@ / { model = "Boundary Devices i.MX8MMini Nitrogen8MM Rev2"; compatible = "boundary,imx8mm-nitrogen8mm", "fsl,imx8mm"; + + reg_vref_1v8: regulator-vref-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vref-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + reg_vref_3v3: regulator-vref-3v3 { + compatible = "regulator-fixed"; + regulator-name = "vref-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_wlan_vmmc: regulator-wlan-vmmc { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_wlan_vmmc>; + regulator-name = "reg_wlan_vmmc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio3 20 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + sound-wm8960 { + audio-cpu = <&sai1>; + audio-codec = <&wm8960>; + audio-routing = + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "RINPUT1", "Mic Jack", + "Mic Jack", "MICB"; + compatible = "fsl,imx-audio-wm8960"; + /* JD2: hp detect high for headphone*/ + hp-det-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>; + /* Jack is not stuffed */ + mic-det-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + model = "wm8960-audio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sound_wm8960>; + }; }; &A53_0 { @@ -27,6 +74,17 @@ cpu-supply = <®_buck3>; }; +/* J15 */ +&ecspi2 { + assigned-clocks = <&clk IMX8MM_CLK_ECSPI2>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_40M>; + assigned-clock-rates = <40000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; @@ -47,6 +105,12 @@ }; }; +&flexspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexspi>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -156,7 +220,7 @@ #address-cells = <1>; #size-cells = <0>; - i2c3 { + i2c3@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; @@ -173,12 +237,88 @@ }; }; +&i2c4 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + wm8960: codec@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + clocks = <&clk IMX8MM_CLK_SAI1_ROOT>; + clock-names = "mclk1"; + wlf,shared-lrclk; + #sound-dai-cells = <0>; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&pwm2 { + assigned-clocks = <&clk IMX8MM_CLK_PWM2>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_40M>; + assigned-clock-rates = <40000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm2>; + status = "okay"; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; + status = "okay"; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; + status = "okay"; +}; + +&sai1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai1>; + status = "okay"; +}; + +&sai2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2>; + status = "okay"; +}; + +/* BT */ +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + uart-has-rtscts; + status = "okay"; +}; + /* console */ &uart2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart2>; - assigned-clocks = <&clk IMX8MM_CLK_UART2>; - assigned-clock-parents = <&clk IMX8MM_CLK_24M>; + status = "okay"; +}; + +/* J15 */ +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + uart-has-rtscts; + status = "okay"; +}; + +/* J9 */ +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; status = "okay"; }; @@ -191,6 +331,8 @@ pinctrl-0 = <&pinctrl_usdhc1>; pinctrl-1 = <&pinctrl_usdhc1_100mhz>; pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + vmmc-supply = <®_vref_3v3>; + vqmmc-supply = <®_vref_1v8>; status = "okay"; }; @@ -206,6 +348,48 @@ status = "okay"; }; +/* wlan */ +&usdhc3 { + bus-width = <4>; + sdhci-caps-mask = <0x2 0x0>; + non-removable; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + vmmc-supply = <®_wlan_vmmc>; + vqmmc-supply = <®_vref_1v8>; + status = "okay"; +}; + +/* USB OTG port */ +&usbotg1 { + dr_mode = "otg"; + over-current-active-low; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg1>; + power-active-high; + status = "okay"; +}; + +/* USB Host port */ +&usbotg2 { + dr_mode = "host"; + over-current-active-low; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg2>; + power-active-high; + /* + * FIXME: having USB2 enabled hangs the boot just after: + *[ 1.655941] ci_hdrc ci_hdrc.1: EHCI Host Controller + *[ 1.660880] ci_hdrc ci_hdrc.1: new USB bus registered, assigned bus number 2 + *[ 1.681505] ci_hdrc ci_hdrc.1: USB 2.0 started, EHCI 1.00 + *[ 1.687730] hub 2-0:1.0: USB hub found + *[ 1.691528] hub 2-0:1.0: 1 port detected + */ + status = "disabled"; +}; + &wdog1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_wdog>; @@ -217,6 +401,15 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x140 + MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0x19 + MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0x19 + MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0x19 + >; + }; + pinctrl_fec1: fec1grp { fsl,pins = < MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x3 @@ -237,6 +430,17 @@ >; }; + pinctrl_flexspi: flexspigrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_ALE_QSPI_A_SCLK 0x1c2 + MX8MM_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B 0x82 + MX8MM_IOMUXC_NAND_DATA00_QSPI_A_DATA0 0x82 + MX8MM_IOMUXC_NAND_DATA01_QSPI_A_DATA1 0x82 + MX8MM_IOMUXC_NAND_DATA02_QSPI_A_DATA2 0x82 + MX8MM_IOMUXC_NAND_DATA03_QSPI_A_DATA3 0x82 + >; + }; + pinctrl_hog: hoggrp { fsl,pins = < MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x09 @@ -258,12 +462,86 @@ >; }; + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 + MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 + >; + }; + pinctrl_i2c3a_rv4162: i2c3a-rv4162grp { fsl,pins = < MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22 0x1c0 >; }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT 0x16 + >; + }; + + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT 0x16 + >; + }; + + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX8MM_IOMUXC_SPDIF_TX_PWM3_OUT 0x16 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX8MM_IOMUXC_SAI3_MCLK_PWM4_OUT 0x16 + >; + }; + + pinctrl_reg_wlan_vmmc: reg-wlan-vmmcgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20 0x16 + >; + }; + + pinctrl_sai1: sai1grp { + fsl,pins = < + /* wm8960 */ + MX8MM_IOMUXC_SAI1_MCLK_SAI1_MCLK 0xd6 + MX8MM_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC 0xd6 + MX8MM_IOMUXC_SAI1_TXC_SAI1_TX_BCLK 0xd6 + MX8MM_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0 0xd6 + MX8MM_IOMUXC_SAI1_RXD0_SAI1_RX_DATA0 0xd6 + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + /* Bluetooth PCM */ + MX8MM_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC 0xd6 + MX8MM_IOMUXC_SAI2_TXC_SAI2_TX_BCLK 0xd6 + MX8MM_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0 0xd6 + MX8MM_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0 0xd6 + >; + }; + + pinctrl_sound_wm8960: sound-wm8960grp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x80 + MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x80 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX 0x140 + MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX 0x140 + MX8MM_IOMUXC_UART3_RXD_UART1_DCE_CTS_B 0x140 + MX8MM_IOMUXC_UART3_TXD_UART1_DCE_RTS_B 0x140 + >; + }; + pinctrl_uart2: uart2grp { fsl,pins = < MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140 @@ -271,6 +549,36 @@ >; }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI1_SCLK_UART3_DCE_RX 0x140 + MX8MM_IOMUXC_ECSPI1_MOSI_UART3_DCE_TX 0x140 + MX8MM_IOMUXC_ECSPI1_SS0_UART3_DCE_RTS_B 0x140 + MX8MM_IOMUXC_ECSPI1_MISO_UART3_DCE_CTS_B 0x140 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 + MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140 + >; + }; + + pinctrl_usbotg1: usbotg1grp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO12_USB1_OTG_PWR 0x16 + MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x156 + >; + }; + + pinctrl_usbotg2: usbotg2grp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO14_USB2_OTG_PWR 0x16 + MX8MM_IOMUXC_GPIO1_IO15_USB2_OTG_OC 0x15 + >; + }; + pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x190 diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 6bf1d15ba16a88b1890aa510c815eb637d35f487..a27e02bee6b4797376e213adb3acfabcc7af9df6 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -887,7 +887,7 @@ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk IMX8MM_CLK_QSPI_ROOT>, <&clk IMX8MM_CLK_QSPI_ROOT>; - clock-names = "fspi", "fspi_en"; + clock-names = "fspi_en", "fspi"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi index de2cd0e3201c6dfb48123177082007b773c27089..c35eeaff958f5d205212d883dbba01c7792faf9e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi @@ -262,8 +262,12 @@ &usdhc1 { #address-cells = <1>; #size-cells = <0>; - pinctrl-names = "default"; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + vmmc-supply = <&buck4_reg>; + vqmmc-supply = <&buck5_reg>; bus-width = <4>; non-removable; cap-power-off-card; diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi index 16ea50089567d2639f41e9be4249ff029b0349a8..4dac4da38f4c05122752dd9f5a4bf16a3fa2b5ba 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -898,7 +898,7 @@ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk IMX8MN_CLK_QSPI_ROOT>, <&clk IMX8MN_CLK_QSPI_ROOT>; - clock-names = "fspi", "fspi_en"; + clock-names = "fspi_en", "fspi"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts index 7db4273cc88bc099b4f392ce7a4daa28115173cb..2c28e589677ea1de04c2edd0ebe8f0e5c127192d 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts @@ -98,6 +98,8 @@ reg = <1>; eee-broken-1000t; reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + reset-deassert-us = <80000>; }; }; }; 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 122c95ddad3053b2c28d6a24bcedad354003bf41..984a6b9ded8d7a8c4936f220d099ab2cc755c7c3 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts @@ -16,7 +16,7 @@ "phytec,imx8mp-phycore-som", "fsl,imx8mp"; chosen { - stdout-path = &uart2; + stdout-path = &uart1; }; reg_usdhc2_vmmc: regulator-usdhc2 { @@ -33,6 +33,30 @@ }; }; +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_1_50_NS>; + ti,tx-internal-delay = <DP83867_RGMIIDCTL_1_50_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>; + enet-phy-lane-no-swap; + }; + }; +}; + &i2c2 { clock-frequency = <400000>; pinctrl-names = "default", "gpio"; @@ -71,9 +95,9 @@ }; /* debug console */ -&uart2 { +&uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; @@ -90,6 +114,26 @@ }; &iomuxc { + pinctrl_eqos: eqosgrp { + fsl,pins = < + MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x3 + MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x3 + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x91 + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x91 + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x91 + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x91 + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x91 + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91 + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x1f + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x1f + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x1f + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x1f + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x1f + MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x10 + >; + }; + pinctrl_i2c2: i2c2grp { fsl,pins = < MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c3 @@ -110,10 +154,10 @@ >; }; - pinctrl_uart2: uart2grp { + pinctrl_uart1: uart1grp { fsl,pins = < - MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x49 - MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x49 + MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x49 + MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x49 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index c7523fd4eae9b533bd0960d40383502e3ecfc239..c2d51a46cb3cb294e0378f75015a74dbf19f6fcc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -18,6 +18,7 @@ aliases { ethernet0 = &fec; + ethernet1 = &eqos; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -312,6 +313,22 @@ status = "disabled"; }; + wdog2: watchdog@30290000 { + compatible = "fsl,imx8mp-wdt", "fsl,imx21-wdt"; + reg = <0x30290000 0x10000>; + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk IMX8MP_CLK_WDOG2_ROOT>; + status = "disabled"; + }; + + wdog3: watchdog@302a0000 { + compatible = "fsl,imx8mp-wdt", "fsl,imx21-wdt"; + reg = <0x302a0000 0x10000>; + interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk IMX8MP_CLK_WDOG3_ROOT>; + status = "disabled"; + }; + iomuxc: pinctrl@30330000 { compatible = "fsl,imx8mp-iomuxc"; reg = <0x30330000 0x10000>; @@ -786,6 +803,28 @@ nvmem_macaddr_swap; status = "disabled"; }; + + eqos: ethernet@30bf0000 { + compatible = "nxp,imx8mp-dwmac-eqos", "snps,dwmac-5.10a"; + reg = <0x30bf0000 0x10000>; + interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "eth_wake_irq", "macirq"; + clocks = <&clk IMX8MP_CLK_ENET_QOS_ROOT>, + <&clk IMX8MP_CLK_QOS_ENET_ROOT>, + <&clk IMX8MP_CLK_ENET_QOS_TIMER>, + <&clk IMX8MP_CLK_ENET_QOS>; + clock-names = "stmmaceth", "pclk", "ptp_ref", "tx"; + assigned-clocks = <&clk IMX8MP_CLK_ENET_AXI>, + <&clk IMX8MP_CLK_ENET_QOS_TIMER>, + <&clk IMX8MP_CLK_ENET_QOS>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>, + <&clk IMX8MP_SYS_PLL2_100M>, + <&clk IMX8MP_SYS_PLL2_125M>; + assigned-clock-rates = <0>, <100000000>, <125000000>; + intf_mode = <&gpr 0x4>; + status = "disabled"; + }; }; gic: interrupt-controller@38800000 { @@ -828,7 +867,7 @@ ranges; status = "disabled"; - usb_dwc3_0: dwc3@38100000 { + usb_dwc3_0: usb@38100000 { compatible = "snps,dwc3"; reg = <0x38100000 0x10000>; clocks = <&clk IMX8MP_CLK_HSIO_AXI>, @@ -869,7 +908,7 @@ ranges; status = "disabled"; - usb_dwc3_1: dwc3@38200000 { + usb_dwc3_1: usb@38200000 { compatible = "snps,dwc3"; reg = <0x38200000 0x10000>; clocks = <&clk IMX8MP_CLK_HSIO_AXI>, diff --git a/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts b/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts new file mode 100644 index 0000000000000000000000000000000000000000..f593e4ff62e1c73fb092fdee4c5f59e5afb4e8a5 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts @@ -0,0 +1,613 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree File for the Kontron pitx-imx8m board. + * + * Copyright (C) 2021 Heiko Thiery <heiko.thiery@gmail.com> + */ + +/dts-v1/; + +#include "imx8mq.dtsi" +#include <dt-bindings/net/ti-dp83867.h> + +/ { + model = "Kontron pITX-imx8m"; + compatible = "kontron,pitx-imx8m", "fsl,imx8mq"; + + aliases { + i2c0 = &i2c1; + i2c1 = &i2c2; + i2c2 = &i2c3; + mmc0 = &usdhc1; + mmc1 = &usdhc2; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; + spi0 = &qspi0; + spi1 = &ecspi2; + }; + + chosen { + stdout-path = "serial2:115200n8"; + }; + + pcie0_refclk: pcie0-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + pcie1_refclk: pcie1-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + reg_usdhc2_vmmc: regulator-usdhc2-vmmc { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2>; + regulator-name = "V_3V3_SD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <20000>; + enable-active-high; + }; +}; + +&ecspi2 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@0 { + compatible = "infineon,slb9670"; + reg = <0>; + spi-max-frequency = <43000000>; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>; + ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + reset-assert-us = <10>; + reset-deassert-us = <280>; + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@8 { + compatible = "fsl,pfuze100"; + fsl,pfuze-support-disable-sw; + reg = <0x8>; + + regulators { + sw1a_reg: sw1ab { + regulator-name = "V_0V9_GPU"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <1100000>; + }; + + sw1c_reg: sw1c { + regulator-name = "V_0V9_VPU"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <1100000>; + }; + + sw2_reg: sw2 { + regulator-name = "V_1V1_NVCC_DRAM"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + sw3a_reg: sw3ab { + regulator-name = "V_1V0_DRAM"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-name = "V_1V8_S0"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-name = "NC"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-name = "V_0V9_SNVS"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-name = "V_0V55_VREF_DDR"; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-name = "V_1V5_CSI"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-name = "V_0V9_PHY"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <975000>; + regulator-always-on; + }; + + vgen3_reg: vgen3 { + regulator-name = "V_1V8_PHY"; + regulator-min-microvolt = <1675000>; + regulator-max-microvolt = <1975000>; + regulator-always-on; + }; + + vgen4_reg: vgen4 { + regulator-name = "V_1V8_VDDA"; + regulator-min-microvolt = <1625000>; + regulator-max-microvolt = <1875000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-name = "V_3V3_PHY"; + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3625000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-name = "V_2V8_CAM"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + fan-controller@1b { + compatible = "maxim,max6650"; + reg = <0x1b>; + maxim,fan-microvolt = <5000000>; + }; + + rtc@32 { + compatible = "microcrystal,rv8803"; + reg = <0x32>; + }; + + sensor@4b { + compatible = "national,lm75b"; + reg = <0x4b>; + }; + + eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + pagesize = <32>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; +}; + +/* M.2 B-key slot */ +&pcie0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie0>; + reset-gpio = <&gpio1 9 GPIO_ACTIVE_LOW>; + clocks = <&clk IMX8MQ_CLK_PCIE1_ROOT>, + <&clk IMX8MQ_CLK_PCIE1_AUX>, + <&clk IMX8MQ_CLK_PCIE1_PHY>, + <&pcie0_refclk>; + clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus"; + status = "okay"; +}; + +/* Intel Ethernet Controller I210/I211 */ +&pcie1 { + clocks = <&clk IMX8MQ_CLK_PCIE2_ROOT>, + <&clk IMX8MQ_CLK_PCIE2_AUX>, + <&clk IMX8MQ_CLK_PCIE2_PHY>, + <&pcie1_refclk>; + clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus"; + fsl,max-link-speed = <1>; + status = "okay"; +}; + +&pgc_gpu { + power-supply = <&sw1a_reg>; +}; + +&pgc_vpu { + power-supply = <&sw1c_reg>; +}; + +&qspi0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + m25p,fast-read; + spi-max-frequency = <50000000>; + }; +}; + +&snvs_pwrkey { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + assigned-clocks = <&clk IMX8MQ_CLK_UART1>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + assigned-clocks = <&clk IMX8MQ_CLK_UART2>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + fsl,uart-has-rtscts; + assigned-clocks = <&clk IMX8MQ_CLK_UART3>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>; + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +&usb_dwc3_0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb0>; + dr_mode = "otg"; + hnp-disable; + srp-disable; + adp-disable; + maximum-speed = "high-speed"; + status = "okay"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + status = "okay"; +}; + +&usdhc1 { + assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>; + assigned-clock-rates = <400000000>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + vqmmc-supply = <&sw4_reg>; + bus-width = <8>; + non-removable; + no-sd; + no-sdio; + status = "okay"; +}; + +&usdhc2 { + assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>; + assigned-clock-rates = <200000000>; + 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>; + bus-width = <4>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; + vmmc-supply = <®_usdhc2_vmmc>; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_CE1_B_GPIO3_IO2 0x19 /* TPM Reset */ + MX8MQ_IOMUXC_NAND_CE3_B_GPIO3_IO4 0x19 /* USB2 Hub Reset */ + >; + }; + + pinctrl_gpio: gpiogrp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_CLE_GPIO3_IO5 0x19 /* GPIO0 */ + MX8MQ_IOMUXC_NAND_RE_B_GPIO3_IO15 0x19 /* GPIO1 */ + MX8MQ_IOMUXC_NAND_WE_B_GPIO3_IO17 0x19 /* GPIO2 */ + MX8MQ_IOMUXC_NAND_WP_B_GPIO3_IO18 0x19 /* GPIO3 */ + MX8MQ_IOMUXC_NAND_READY_B_GPIO3_IO16 0x19 /* GPIO4 */ + MX8MQ_IOMUXC_NAND_DATA04_GPIO3_IO10 0x19 /* GPIO5 */ + MX8MQ_IOMUXC_NAND_DATA05_GPIO3_IO11 0x19 /* GPIO6 */ + MX8MQ_IOMUXC_NAND_DATA06_GPIO3_IO12 0x19 /* GPIO7 */ + >; + }; + + pinctrl_pcie0: pcie0grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO09_GPIO1_IO9 0x16 /* PCIE_PERST */ + MX8MQ_IOMUXC_UART4_TXD_GPIO5_IO29 0x16 /* W_DISABLE */ + >; + }; + + pinctrl_reg_usdhc2: regusdhc2gpiogrp { + fsl,pins = < + MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x41 + >; + }; + + pinctrl_fec1: fec1grp { + fsl,pins = < + MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC 0x3 + MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO 0x23 + MX8MQ_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f + MX8MQ_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f + MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f + MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f + MX8MQ_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91 + MX8MQ_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91 + MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91 + MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91 + MX8MQ_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f + MX8MQ_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 + MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 + MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f + MX8MQ_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x16 + MX8MQ_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x16 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL 0x4000007f + MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA 0x4000007f + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C2_SCL_I2C2_SCL 0x4000007f + MX8MQ_IOMUXC_I2C2_SDA_I2C2_SDA 0x4000007f + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C3_SCL_I2C3_SCL 0x4000007f + MX8MQ_IOMUXC_I2C3_SDA_I2C3_SDA 0x4000007f + >; + }; + + pinctrl_qspi: qspigrp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_ALE_QSPI_A_SCLK 0x82 + MX8MQ_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B 0x82 + MX8MQ_IOMUXC_NAND_DATA00_QSPI_A_DATA0 0x82 + MX8MQ_IOMUXC_NAND_DATA01_QSPI_A_DATA1 0x82 + MX8MQ_IOMUXC_NAND_DATA02_QSPI_A_DATA2 0x82 + MX8MQ_IOMUXC_NAND_DATA03_QSPI_A_DATA3 0x82 + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MQ_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0x19 + MX8MQ_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0x19 + MX8MQ_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0x19 + >; + }; + + pinctrl_ecspi2_cs: ecspi2csgrp { + fsl,pins = < + MX8MQ_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x19 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 + MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX 0x49 + MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX 0x49 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX8MQ_IOMUXC_UART3_TXD_UART3_DCE_TX 0x49 + MX8MQ_IOMUXC_UART3_RXD_UART3_DCE_RX 0x49 + MX8MQ_IOMUXC_ECSPI1_SS0_UART3_DCE_RTS_B 0x49 + MX8MQ_IOMUXC_ECSPI1_MISO_UART3_DCE_CTS_B 0x49 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x83 + MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xc3 + MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xc3 + MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xc3 + MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xc3 + MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xc3 + MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xc3 + MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xc3 + MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xc3 + MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xc3 + MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x83 + MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0xc1 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1-100grp { + fsl,pins = < + MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x8d + MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xcd + MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xcd + MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xcd + MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xcd + MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xcd + MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xcd + MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xcd + MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xcd + MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xcd + MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x8d + MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0xc1 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1-200grp { + fsl,pins = < + MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x9f + MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xdf + MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xdf + MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xdf + MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xdf + MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xdf + MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xdf + MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xdf + MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xdf + MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xdf + MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x9f + MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0xc1 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CD_B_GPIO2_IO12 0x41 + MX8MQ_IOMUXC_SD2_WP_GPIO2_IO20 0x19 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x83 + MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xc3 + MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xc3 + MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xc3 + MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xc3 + MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xc3 + MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100grp { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x8d + MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xcd + MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xcd + MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xcd + MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xcd + MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xcd + MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200grp { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x9f + MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xdf + MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xdf + MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xdf + MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xdf + MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xdf + MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usb0: usb0grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO12_USB1_OTG_PWR 0x19 + MX8MQ_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x19 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts index dd217a0760e9b6e9222b8a95066f13576027408c..622f3787a1866b5ff8902b41a22173968e25f3ed 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts @@ -50,13 +50,6 @@ linux,code = <KEY_VOLUMEDOWN>; }; - hp-det { - label = "HP_DET"; - gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; - wakeup-source; - linux,code = <KEY_HP>; - }; - wwan-wake { label = "WWAN_WAKE"; gpios = <&gpio3 8 GPIO_ACTIVE_LOW>; @@ -163,21 +156,35 @@ #sound-dai-cells = <0>; }; + mic_mux: mic-mux { + compatible = "simple-audio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_micsel>; + mux-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>; + sound-name-prefix = "Mic Mux"; + }; + sound { compatible = "simple-audio-card"; - simple-audio-card,name = "sgtl5000"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hpdet>; + simple-audio-card,aux-devs = <&speaker_amp>, <&mic_mux>; + simple-audio-card,name = "Librem 5 Devkit"; simple-audio-card,format = "i2s"; simple-audio-card,widgets = - "Microphone", "Microphone Jack", - "Headphone", "Headphone Jack", - "Speaker", "Speaker Ext", - "Line", "Line In Jack"; + "Microphone", "Builtin Microphone", + "Microphone", "Headset Microphone", + "Headphone", "Headphones", + "Speaker", "Builtin Speaker"; simple-audio-card,routing = - "MIC_IN", "Microphone Jack", - "Microphone Jack", "Mic Bias", - "LINE_IN", "Line In Jack", - "Headphone Jack", "HP_OUT", - "Speaker Ext", "LINE_OUT"; + "MIC_IN", "Mic Mux OUT", + "Mic Mux IN1", "Headset Microphone", + "Mic Mux IN2", "Builtin Microphone", + "Mic Mux OUT", "Mic Bias", + "Headphones", "HP_OUT", + "Builtin Speaker", "Speaker Amp OUTR", + "Speaker Amp INR", "LINE_OUT"; + simple-audio-card,hp-det-gpio = <&gpio3 20 GPIO_ACTIVE_HIGH>; simple-audio-card,cpu { sound-dai = <&sai2>; @@ -207,6 +214,15 @@ }; }; + speaker_amp: speaker-amp { + compatible = "simple-audio-amplifier"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spkamp>; + VCC-supply = <®_3v3_p>; + sound-name-prefix = "Speaker Amp"; + enable-gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>; + }; + vibrator { compatible = "gpio-vibrator"; pinctrl-names = "default"; @@ -315,7 +331,6 @@ regulator-min-microvolt = <700000>; regulator-max-microvolt = <1300000>; regulator-boot-on; - regulator-enable-ramp-delay = <200>; rohm,dvs-run-voltage = <900000>; }; @@ -610,7 +625,6 @@ fsl,pins = < MX8MQ_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x16 MX8MQ_IOMUXC_SAI2_RXC_GPIO4_IO22 0x16 - MX8MQ_IOMUXC_SAI5_RXC_GPIO3_IO20 0x180 /* HP_DET */ MX8MQ_IOMUXC_NAND_DATA02_GPIO3_IO8 0x80 /* nWoWWAN */ >; }; @@ -621,6 +635,12 @@ >; }; + pinctrl_hpdet: hpdetgrp { + fsl,pins = < + MX8MQ_IOMUXC_SAI5_RXC_GPIO3_IO20 0xC0 /* HP_DET */ + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL 0x4000001f @@ -641,6 +661,18 @@ >; }; + pinctrl_micsel: micselgrp { + fsl,pins = < + MX8MQ_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5 0xc6 /* MIC_SEL */ + >; + }; + + pinctrl_spkamp: spkamp { + fsl,pins = < + MX8MQ_IOMUXC_SPDIF_TX_GPIO5_IO3 0x81 /* MUTE */ + >; + }; + pinctrl_pmic: pmicgrp { fsl,pins = < MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x80 /* PMIC intr */ diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r2.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r2.dts index d77fc5df3f06c4a0a34c09946a8c405045d4ddee..73bd431cbd6a8575e5c1470e41568976e44d5fad 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r2.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r2.dts @@ -25,5 +25,5 @@ }; &proximity { - proximity-near-level = <220>; + proximity-near-level = <120>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts index 0d38327043f880aa71dc495e447cc23cb34fe0fc..cd3c3edd48fa310b552f61f39fb2802f4c406ffb 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts @@ -28,6 +28,10 @@ ti,termination-current = <144000>; /* uA */ }; +&buck3_reg { + regulator-always-on; +}; + &proximity { proximity-near-level = <25>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi index 06a4799b6aeb1bacbf7d99dbfd49f713bbd0ef3e..460ef0d86540acce3e7775d89c6cebfb9507fe7f 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi @@ -258,6 +258,25 @@ compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "protected0"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "protected1"; + reg = <0x30000 0x10000>; + read-only; + }; + + partition@40000 { + label = "rw"; + reg = <0x40000 0x1C0000>; + }; }; }; @@ -267,8 +286,9 @@ pmic-5v-hog { gpio-hog; - gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; + gpios = <1 GPIO_ACTIVE_HIGH>; input; + lane-mapping = "pmic-5v"; }; }; @@ -1051,8 +1071,6 @@ assigned-clocks = <&clk IMX8MQ_CLK_SAI2>; assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>; assigned-clock-rates = <24576000>; - assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL2>; - assigned-clock-rates = <786432000>, <722534400>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts new file mode 100644 index 0000000000000000000000000000000000000000..ce9d3f0b98fc0383667fe8ffd60b239eaab348a2 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +/dts-v1/; + +#include "imx8qm.dtsi" + +/ { + model = "Freescale i.MX8QM MEK"; + compatible = "fsl,imx8qm-mek", "fsl,imx8qm"; + + chosen { + stdout-path = &lpuart0; + }; + + cpus { + /delete-node/ cpu-map; + /delete-node/ cpu@100; + /delete-node/ cpu@101; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00000000 0x80000000 0 0x40000000>; + }; + + reg_usdhc2_vmmc: usdhc2-vmmc { + compatible = "regulator-fixed"; + regulator-name = "SD1_SPWR"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&lsio_gpio4 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&lpuart0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpuart0>; + status = "okay"; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; +}; + +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + bus-width = <8>; + no-sd; + no-sdio; + non-removable; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + bus-width = <4>; + vmmc-supply = <®_usdhc2_vmmc>; + cd-gpios = <&lsio_gpio4 22 GPIO_ACTIVE_LOW>; + wp-gpios = <&lsio_gpio4 21 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&iomuxc { + pinctrl_fec1: fec1grp { + fsl,pins = < + IMX8QM_ENET0_MDC_CONN_ENET0_MDC 0x06000020 + IMX8QM_ENET0_MDIO_CONN_ENET0_MDIO 0x06000020 + IMX8QM_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL 0x06000020 + IMX8QM_ENET0_RGMII_TXC_CONN_ENET0_RGMII_TXC 0x06000020 + IMX8QM_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0 0x06000020 + IMX8QM_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1 0x06000020 + IMX8QM_ENET0_RGMII_TXD2_CONN_ENET0_RGMII_TXD2 0x06000020 + IMX8QM_ENET0_RGMII_TXD3_CONN_ENET0_RGMII_TXD3 0x06000020 + IMX8QM_ENET0_RGMII_RXC_CONN_ENET0_RGMII_RXC 0x06000020 + IMX8QM_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL 0x06000020 + IMX8QM_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0 0x06000020 + IMX8QM_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1 0x06000020 + IMX8QM_ENET0_RGMII_RXD2_CONN_ENET0_RGMII_RXD2 0x06000020 + IMX8QM_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3 0x06000020 + >; + }; + + pinctrl_lpuart0: lpuart0grp { + fsl,pins = < + IMX8QM_UART0_RX_DMA_UART0_RX 0x06000020 + IMX8QM_UART0_TX_DMA_UART0_TX 0x06000020 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + IMX8QM_EMMC0_CLK_CONN_EMMC0_CLK 0x06000041 + IMX8QM_EMMC0_CMD_CONN_EMMC0_CMD 0x00000021 + IMX8QM_EMMC0_DATA0_CONN_EMMC0_DATA0 0x00000021 + IMX8QM_EMMC0_DATA1_CONN_EMMC0_DATA1 0x00000021 + IMX8QM_EMMC0_DATA2_CONN_EMMC0_DATA2 0x00000021 + IMX8QM_EMMC0_DATA3_CONN_EMMC0_DATA3 0x00000021 + IMX8QM_EMMC0_DATA4_CONN_EMMC0_DATA4 0x00000021 + IMX8QM_EMMC0_DATA5_CONN_EMMC0_DATA5 0x00000021 + IMX8QM_EMMC0_DATA6_CONN_EMMC0_DATA6 0x00000021 + IMX8QM_EMMC0_DATA7_CONN_EMMC0_DATA7 0x00000021 + IMX8QM_EMMC0_STROBE_CONN_EMMC0_STROBE 0x00000041 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + IMX8QM_USDHC1_CLK_CONN_USDHC1_CLK 0x06000041 + IMX8QM_USDHC1_CMD_CONN_USDHC1_CMD 0x00000021 + IMX8QM_USDHC1_DATA0_CONN_USDHC1_DATA0 0x00000021 + IMX8QM_USDHC1_DATA1_CONN_USDHC1_DATA1 0x00000021 + IMX8QM_USDHC1_DATA2_CONN_USDHC1_DATA2 0x00000021 + IMX8QM_USDHC1_DATA3_CONN_USDHC1_DATA3 0x00000021 + IMX8QM_USDHC1_VSELECT_CONN_USDHC1_VSELECT 0x00000021 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..42637a45701c502b2b418f44307fad024ad063fd --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +&fec1 { + compatible = "fsl,imx8qm-fec", "fsl,imx6sx-fec"; +}; + +&fec2 { + compatible = "fsl,imx8qm-fec", "fsl,imx6sx-fec"; +}; + +&usdhc1 { + compatible = "fsl,imx8qm-usdhc", "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; +}; + +&usdhc2 { + compatible = "fsl,imx8qm-usdhc", "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bbe5f5ecfb9244eafed71d8d4832862c04eb043c --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +&dma_subsys { + uart4_lpcg: clock-controller@5a4a0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5a4a0000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX_SC_R_UART_4 IMX_SC_PM_CLK_PER>, + <&dma_ipg_clk>; + clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>; + clock-output-names = "uart4_lpcg_baud_clk", + "uart4_lpcg_ipg_clk"; + power-domains = <&pd IMX_SC_R_UART_4>; + }; +}; + +&lpuart0 { + compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; +}; + +&lpuart1 { + compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; +}; + +&lpuart2 { + compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; +}; + +&lpuart3 { + compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; +}; + +&i2c0 { + compatible = "fsl,imx8qm-lpi2c", "fsl,imx7ulp-lpi2c"; +}; + +&i2c1 { + compatible = "fsl,imx8qm-lpi2c", "fsl,imx7ulp-lpi2c"; +}; + +&i2c2 { + compatible = "fsl,imx8qm-lpi2c", "fsl,imx7ulp-lpi2c"; +}; + +&i2c3 { + compatible = "fsl,imx8qm-lpi2c", "fsl,imx7ulp-lpi2c"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..30896610c6547d47a2db600df226949a060a627c --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +&lsio_gpio0 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio1 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio2 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio3 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio4 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio5 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio6 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio7 { + compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio"; +}; + +&lsio_mu0 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qm-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu1 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qm-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu2 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qm-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu3 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qm-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu4 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qm-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu13 { + compatible = "fsl,imx8qm-mu", "fsl,imx6sx-mu"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..12cd059b339b7ebd76cbe0fb666b7ba05f349a33 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qm.dtsi @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/clock/imx8-lpcg.h> +#include <dt-bindings/firmware/imx/rsrc.h> +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/pinctrl/pads-imx8qm.h> + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + mmc0 = &usdhc1; + mmc1 = &usdhc2; + mmc2 = &usdhc3; + serial0 = &lpuart0; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&A53_0>; + }; + core1 { + cpu = <&A53_1>; + }; + core2 { + cpu = <&A53_2>; + }; + core3 { + cpu = <&A53_3>; + }; + }; + + cluster1 { + core0 { + cpu = <&A72_0>; + }; + core1 { + cpu = <&A72_1>; + }; + }; + }; + + A53_0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A53_1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A53_2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A53_3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A72_0: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a72", "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&A72_L2>; + }; + + A72_1: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a72", "arm,armv8"; + reg = <0x0 0x101>; + enable-method = "psci"; + next-level-cache = <&A72_L2>; + }; + + A53_L2: l2-cache0 { + compatible = "cache"; + }; + + A72_L2: l2-cache1 { + compatible = "cache"; + }; + }; + + gic: interrupt-controller@51a00000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x51a00000 0 0x10000>, /* GIC Dist */ + <0x0 0x51b00000 0 0xC0000>, /* GICR */ + <0x0 0x52000000 0 0x2000>, /* GICC */ + <0x0 0x52010000 0 0x1000>, /* GICH */ + <0x0 0x52020000 0 0x20000>; /* GICV */ + #interrupt-cells = <3>; + interrupt-controller; + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gic>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Physical Secure */ + <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Physical Non-Secure */ + <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virtual */ + <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hypervisor */ + }; + + scu { + compatible = "fsl,imx-scu"; + mbox-names = "tx0", + "rx0", + "gip3"; + mboxes = <&lsio_mu1 0 0 + &lsio_mu1 1 0 + &lsio_mu1 3 3>; + + pd: imx8qx-pd { + compatible = "fsl,imx8qm-scu-pd", "fsl,scu-pd"; + #power-domain-cells = <1>; + }; + + clk: clock-controller { + compatible = "fsl,imx8qxp-clk", "fsl,scu-clk"; + #clock-cells = <2>; + }; + + iomuxc: pinctrl { + compatible = "fsl,imx8qm-iomuxc"; + }; + + }; + + /* sorted in register address */ + #include "imx8-ss-dma.dtsi" + #include "imx8-ss-conn.dtsi" + #include "imx8-ss-lsio.dtsi" +}; + +#include "imx8qm-ss-dma.dtsi" +#include "imx8qm-ss-conn.dtsi" +#include "imx8qm-ss-lsio.dtsi" diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts b/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts index a3f8cf1959747c8a7efa730f34e86db44a6777e4..47bb68823b240edb307b6924e6b1469803234f1b 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts @@ -13,13 +13,13 @@ compatible = "einfochips,imx8qxp-ai_ml", "fsl,imx8qxp"; aliases { - serial1 = &adma_lpuart1; - serial2 = &adma_lpuart2; - serial3 = &adma_lpuart3; + serial1 = &lpuart1; + serial2 = &lpuart2; + serial3 = &lpuart3; }; chosen { - stdout-path = &adma_lpuart2; + stdout-path = &lpuart2; }; memory@80000000 { @@ -82,7 +82,7 @@ }; /* BT */ -&adma_lpuart0 { +&lpuart0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart0>; uart-has-rtscts; @@ -90,21 +90,21 @@ }; /* LS-UART0 */ -&adma_lpuart1 { +&lpuart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart1>; status = "okay"; }; /* Debug */ -&adma_lpuart2 { +&lpuart2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart2>; status = "okay"; }; /* PCI-E UART */ -&adma_lpuart3 { +&lpuart3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart3>; status = "okay"; @@ -133,7 +133,7 @@ &usdhc1 { #address-cells = <1>; #size-cells = <0>; - assigned-clocks = <&clk IMX_CONN_SDHC0_CLK>; + assigned-clocks = <&clk IMX_SC_R_SDHC_0 IMX_SC_PM_CLK_PER>; assigned-clock-rates = <200000000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc1>; @@ -151,7 +151,7 @@ /* SD */ &usdhc2 { - assigned-clocks = <&clk IMX_CONN_SDHC1_CLK>; + assigned-clocks = <&clk IMX_SC_R_SDHC_1 IMX_SC_PM_CLK_PER>; assigned-clock-rates = <200000000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc2>; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi index c7336f38760546cd8c7e148c1f115b3f70806b7e..144fc9e82da751c62ce047a121e40283ec3c8acf 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi @@ -26,7 +26,7 @@ }; }; -&adma_i2c1 { +&i2c1 { status = "okay"; /* M41T0M6 real time clock on carrier board */ @@ -37,17 +37,17 @@ }; /* Colibri UART_B */ -&adma_lpuart0 { +&lpuart0 { status= "okay"; }; /* Colibri UART_C */ -&adma_lpuart2 { +&lpuart2 { status= "okay"; }; /* Colibri UART_A */ -&adma_lpuart3 { +&lpuart3 { status= "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi index f38acff0d25c6792a5fec0afb1d2ec3357480a75..89d70e0304339b0ba3b78c9e406cc8a95ac74e36 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi @@ -10,7 +10,7 @@ compatible = "toradex,colibri-imx8x", "fsl,imx8qxp"; chosen { - stdout-path = &adma_lpuart3; + stdout-path = &lpuart3; }; reg_module_3v3: regulator-module-3v3 { @@ -22,7 +22,7 @@ }; /* On-module I2C */ -&adma_i2c0 { +&i2c0 { #address-cells = <1>; #size-cells = <0>; clock-frequency = <100000>; @@ -49,7 +49,7 @@ }; /* Colibri I2C */ -&adma_i2c1 { +&i2c1 { #address-cells = <1>; #size-cells = <0>; clock-frequency = <100000>; @@ -58,19 +58,19 @@ }; /* Colibri UART_B */ -&adma_lpuart0 { +&lpuart0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart0>; }; /* Colibri UART_C */ -&adma_lpuart2 { +&lpuart2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart2>; }; /* Colibri UART_A */ -&adma_lpuart3 { +&lpuart3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart3>, <&pinctrl_lpuart3_ctrl>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index 46437d3c7a043b0006230e2bcb01016730c00b2a..863232a47004c380cd4b614cce88d79844ad8085 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -12,7 +12,7 @@ compatible = "fsl,imx8qxp-mek", "fsl,imx8qxp"; chosen { - stdout-path = &adma_lpuart0; + stdout-path = &lpuart0; }; memory@80000000 { @@ -30,11 +30,30 @@ }; }; -&adma_dsp { +&dsp { status = "okay"; }; -&adma_i2c1 { +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; + }; +}; + +&i2c1 { #address-cells = <1>; #size-cells = <0>; clock-frequency = <100000>; @@ -110,31 +129,12 @@ }; }; -&adma_lpuart0 { +&lpuart0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart0>; status = "okay"; }; -&fec1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec1>; - phy-mode = "rgmii-id"; - phy-handle = <ðphy0>; - fsl,magic-packet; - status = "okay"; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - ethphy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <0>; - }; - }; -}; - &scu_key { status = "okay"; }; @@ -173,7 +173,7 @@ }; &usdhc1 { - assigned-clocks = <&clk IMX_CONN_SDHC0_CLK>; + assigned-clocks = <&clk IMX_SC_R_SDHC_0 IMX_SC_PM_CLK_PER>; assigned-clock-rates = <200000000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc1>; @@ -185,7 +185,7 @@ }; &usdhc2 { - assigned-clocks = <&clk IMX_CONN_SDHC1_CLK>; + assigned-clocks = <&clk IMX_SC_R_SDHC_1 IMX_SC_PM_CLK_PER>; assigned-clock-rates = <200000000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc2>; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-adma.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-adma.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..dc1daa8dc72feba760f5be36178acf1bf4b08182 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-adma.dtsi @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +&lpuart0 { + compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; +}; + +&lpuart1 { + compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; +}; + +&lpuart2 { + compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; +}; + +&lpuart3 { + compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; +}; + +&i2c0 { + compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; +}; + +&i2c1 { + compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; +}; + +&i2c2 { + compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; +}; + +&i2c3 { + compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f5f58959f65ceffe0877cce5425656431a07cf2b --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +&usdhc1 { + compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; +}; + +&usdhc2 { + compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; +}; + +&usdhc3 { + compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; +}; + +&fec1 { + compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec"; +}; + +&fec2 { + compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11395479ffc0125ade09f436cf253a9222bbaa55 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2020 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +&lsio_gpio0 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio1 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio2 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio3 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio4 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio5 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio6 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_gpio7 { + compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; +}; + +&lsio_mu0 { + compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu1 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu2 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu3 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu4 { + compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; +}; + +&lsio_mu13 { + compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi index e46faac1fe71fe8c8777110418703285840fd42b..1e6b4995091e0c6567ebf3d23b9b755cbbfa2c6a 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Freescale Semiconductor, Inc. - * Copyright 2017-2018 NXP + * Copyright 2017-2020 NXP * Dong Aisheng <aisheng.dong@nxp.com> */ #include <dt-bindings/clock/imx8-clock.h> +#include <dt-bindings/clock/imx8-lpcg.h> #include <dt-bindings/firmware/imx/rsrc.h> #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> @@ -29,10 +30,10 @@ gpio5 = &lsio_gpio5; gpio6 = &lsio_gpio6; gpio7 = &lsio_gpio7; - i2c0 = &adma_i2c0; - i2c1 = &adma_i2c1; - i2c2 = &adma_i2c2; - i2c3 = &adma_i2c3; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; mmc0 = &usdhc1; mmc1 = &usdhc2; mmc2 = &usdhc3; @@ -41,10 +42,10 @@ mu2 = &lsio_mu2; mu3 = &lsio_mu3; mu4 = &lsio_mu4; - serial0 = &adma_lpuart0; - serial1 = &adma_lpuart1; - serial2 = &adma_lpuart2; - serial3 = &adma_lpuart3; + serial0 = &lpuart0; + serial1 = &lpuart1; + serial2 = &lpuart2; + serial3 = &lpuart3; }; cpus { @@ -58,7 +59,7 @@ reg = <0x0 0x0>; enable-method = "psci"; next-level-cache = <&A35_L2>; - clocks = <&clk IMX_A35_CLK>; + clocks = <&clk IMX_SC_R_A35 IMX_SC_PM_CLK_CPU>; operating-points-v2 = <&a35_opp_table>; #cooling-cells = <2>; }; @@ -69,7 +70,7 @@ reg = <0x0 0x1>; enable-method = "psci"; next-level-cache = <&A35_L2>; - clocks = <&clk IMX_A35_CLK>; + clocks = <&clk IMX_SC_R_A35 IMX_SC_PM_CLK_CPU>; operating-points-v2 = <&a35_opp_table>; #cooling-cells = <2>; }; @@ -80,7 +81,7 @@ reg = <0x0 0x2>; enable-method = "psci"; next-level-cache = <&A35_L2>; - clocks = <&clk IMX_A35_CLK>; + clocks = <&clk IMX_SC_R_A35 IMX_SC_PM_CLK_CPU>; operating-points-v2 = <&a35_opp_table>; #cooling-cells = <2>; }; @@ -91,7 +92,7 @@ reg = <0x0 0x3>; enable-method = "psci"; next-level-cache = <&A35_L2>; - clocks = <&clk IMX_A35_CLK>; + clocks = <&clk IMX_SC_R_A35 IMX_SC_PM_CLK_CPU>; operating-points-v2 = <&a35_opp_table>; #cooling-cells = <2>; }; @@ -158,9 +159,14 @@ &lsio_mu1 1 0 &lsio_mu1 3 3>; + pd: imx8qx-pd { + compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd"; + #power-domain-cells = <1>; + }; + clk: clock-controller { compatible = "fsl,imx8qxp-clk"; - #clock-cells = <1>; + #clock-cells = <2>; clocks = <&xtal32k &xtal24m>; clock-names = "xtal_32KHz", "xtal_24Mhz"; }; @@ -175,11 +181,6 @@ #size-cells = <1>; }; - pd: imx8qx-pd { - compatible = "fsl,imx8qxp-scu-pd"; - #power-domain-cells = <1>; - }; - scu_key: scu-key { compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key"; linux,keycodes = <KEY_POWER>; @@ -223,380 +224,6 @@ clock-output-names = "xtal_24MHz"; }; - adma_subsys: bus@59000000 { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x59000000 0x0 0x59000000 0x2000000>; - - adma_lpcg: clock-controller@59000000 { - compatible = "fsl,imx8qxp-lpcg-adma"; - reg = <0x59000000 0x2000000>; - #clock-cells = <1>; - }; - - adma_dsp: dsp@596e8000 { - compatible = "fsl,imx8qxp-dsp"; - reg = <0x596e8000 0x88000>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_DSP_IPG_CLK>, - <&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>; - 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>; - status = "disabled"; - }; - - adma_lpuart0: serial@5a060000 { - compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; - reg = <0x5a060000 0x1000>; - interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART0_IPG_CLK>, - <&adma_lpcg IMX_ADMA_LPCG_UART0_BAUD_CLK>; - clock-names = "ipg", "baud"; - power-domains = <&pd IMX_SC_R_UART_0>; - status = "disabled"; - }; - - adma_lpuart1: serial@5a070000 { - compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; - reg = <0x5a070000 0x1000>; - interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART1_IPG_CLK>, - <&adma_lpcg IMX_ADMA_LPCG_UART1_BAUD_CLK>; - clock-names = "ipg", "baud"; - power-domains = <&pd IMX_SC_R_UART_1>; - status = "disabled"; - }; - - adma_lpuart2: serial@5a080000 { - compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; - reg = <0x5a080000 0x1000>; - interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART2_IPG_CLK>, - <&adma_lpcg IMX_ADMA_LPCG_UART2_BAUD_CLK>; - clock-names = "ipg", "baud"; - power-domains = <&pd IMX_SC_R_UART_2>; - status = "disabled"; - }; - - adma_lpuart3: serial@5a090000 { - compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; - reg = <0x5a090000 0x1000>; - interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART3_IPG_CLK>, - <&adma_lpcg IMX_ADMA_LPCG_UART3_BAUD_CLK>; - clock-names = "ipg", "baud"; - power-domains = <&pd IMX_SC_R_UART_3>; - status = "disabled"; - }; - - adma_i2c0: i2c@5a800000 { - compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; - reg = <0x5a800000 0x4000>; - interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_I2C0_CLK>; - clock-names = "per"; - assigned-clocks = <&clk IMX_ADMA_I2C0_CLK>; - assigned-clock-rates = <24000000>; - power-domains = <&pd IMX_SC_R_I2C_0>; - status = "disabled"; - }; - - adma_i2c1: i2c@5a810000 { - compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; - reg = <0x5a810000 0x4000>; - interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_I2C1_CLK>; - clock-names = "per"; - assigned-clocks = <&clk IMX_ADMA_I2C1_CLK>; - assigned-clock-rates = <24000000>; - power-domains = <&pd IMX_SC_R_I2C_1>; - status = "disabled"; - }; - - adma_i2c2: i2c@5a820000 { - compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; - reg = <0x5a820000 0x4000>; - interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_I2C2_CLK>; - clock-names = "per"; - assigned-clocks = <&clk IMX_ADMA_I2C2_CLK>; - assigned-clock-rates = <24000000>; - power-domains = <&pd IMX_SC_R_I2C_2>; - status = "disabled"; - }; - - adma_i2c3: i2c@5a830000 { - compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c"; - reg = <0x5a830000 0x4000>; - interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_I2C3_CLK>; - clock-names = "per"; - assigned-clocks = <&clk IMX_ADMA_I2C3_CLK>; - assigned-clock-rates = <24000000>; - power-domains = <&pd IMX_SC_R_I2C_3>; - status = "disabled"; - }; - }; - - conn_subsys: bus@5b000000 { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x5b000000 0x0 0x5b000000 0x1000000>; - - conn_lpcg: clock-controller@5b200000 { - compatible = "fsl,imx8qxp-lpcg-conn"; - reg = <0x5b200000 0xb0000>; - #clock-cells = <1>; - }; - - usdhc1: mmc@5b010000 { - compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; - interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x5b010000 0x10000>; - clocks = <&conn_lpcg IMX_CONN_LPCG_SDHC0_IPG_CLK>, - <&conn_lpcg IMX_CONN_LPCG_SDHC0_PER_CLK>, - <&conn_lpcg IMX_CONN_LPCG_SDHC0_HCLK>; - clock-names = "ipg", "per", "ahb"; - power-domains = <&pd IMX_SC_R_SDHC_0>; - status = "disabled"; - }; - - usdhc2: mmc@5b020000 { - compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; - interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x5b020000 0x10000>; - clocks = <&conn_lpcg IMX_CONN_LPCG_SDHC1_IPG_CLK>, - <&conn_lpcg IMX_CONN_LPCG_SDHC1_PER_CLK>, - <&conn_lpcg IMX_CONN_LPCG_SDHC1_HCLK>; - clock-names = "ipg", "per", "ahb"; - power-domains = <&pd IMX_SC_R_SDHC_1>; - fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; - status = "disabled"; - }; - - usdhc3: mmc@5b030000 { - compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; - interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x5b030000 0x10000>; - clocks = <&conn_lpcg IMX_CONN_LPCG_SDHC2_IPG_CLK>, - <&conn_lpcg IMX_CONN_LPCG_SDHC2_PER_CLK>, - <&conn_lpcg IMX_CONN_LPCG_SDHC2_HCLK>; - clock-names = "ipg", "per", "ahb"; - power-domains = <&pd IMX_SC_R_SDHC_2>; - status = "disabled"; - }; - - fec1: ethernet@5b040000 { - compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec"; - reg = <0x5b040000 0x10000>; - interrupts = <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&conn_lpcg IMX_CONN_LPCG_ENET0_IPG_CLK>, - <&conn_lpcg IMX_CONN_LPCG_ENET0_AHB_CLK>, - <&conn_lpcg IMX_CONN_LPCG_ENET0_TX_CLK>, - <&conn_lpcg IMX_CONN_LPCG_ENET0_ROOT_CLK>; - clock-names = "ipg", "ahb", "enet_clk_ref", "ptp"; - fsl,num-tx-queues=<3>; - fsl,num-rx-queues=<3>; - power-domains = <&pd IMX_SC_R_ENET_0>; - status = "disabled"; - }; - - fec2: ethernet@5b050000 { - compatible = "fsl,imx8qxp-fec", "fsl,imx6sx-fec"; - reg = <0x5b050000 0x10000>; - interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&conn_lpcg IMX_CONN_LPCG_ENET1_IPG_CLK>, - <&conn_lpcg IMX_CONN_LPCG_ENET1_AHB_CLK>, - <&conn_lpcg IMX_CONN_LPCG_ENET1_TX_CLK>, - <&conn_lpcg IMX_CONN_LPCG_ENET1_ROOT_CLK>; - clock-names = "ipg", "ahb", "enet_clk_ref", "ptp"; - fsl,num-tx-queues=<3>; - fsl,num-rx-queues=<3>; - power-domains = <&pd IMX_SC_R_ENET_1>; - status = "disabled"; - }; - }; - - ddr_subsyss: bus@5c000000 { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x5c000000 0x0 0x5c000000 0x1000000>; - - ddr-pmu@5c020000 { - compatible = "fsl,imx8-ddr-pmu"; - reg = <0x5c020000 0x10000>; - interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - - lsio_subsys: bus@5d000000 { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x5d000000 0x0 0x5d000000 0x1000000>; - - lsio_gpio0: gpio@5d080000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d080000 0x10000>; - interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_0>; - }; - - lsio_gpio1: gpio@5d090000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d090000 0x10000>; - interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_1>; - }; - - lsio_gpio2: gpio@5d0a0000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d0a0000 0x10000>; - interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_2>; - }; - - lsio_gpio3: gpio@5d0b0000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d0b0000 0x10000>; - interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_3>; - }; - - lsio_gpio4: gpio@5d0c0000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d0c0000 0x10000>; - interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_4>; - }; - - lsio_gpio5: gpio@5d0d0000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d0d0000 0x10000>; - interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_5>; - }; - - lsio_gpio6: gpio@5d0e0000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d0e0000 0x10000>; - interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_6>; - }; - - lsio_gpio7: gpio@5d0f0000 { - compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio"; - reg = <0x5d0f0000 0x10000>; - interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - power-domains = <&pd IMX_SC_R_GPIO_7>; - }; - - lsio_mu0: mailbox@5d1b0000 { - compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; - reg = <0x5d1b0000 0x10000>; - interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; - #mbox-cells = <2>; - status = "disabled"; - }; - - lsio_mu1: mailbox@5d1c0000 { - compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; - reg = <0x5d1c0000 0x10000>; - interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; - #mbox-cells = <2>; - }; - - lsio_mu2: mailbox@5d1d0000 { - compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; - reg = <0x5d1d0000 0x10000>; - interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; - #mbox-cells = <2>; - status = "disabled"; - }; - - lsio_mu3: mailbox@5d1e0000 { - compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; - reg = <0x5d1e0000 0x10000>; - interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>; - #mbox-cells = <2>; - status = "disabled"; - }; - - lsio_mu4: mailbox@5d1f0000 { - compatible = "fsl,imx8-mu-scu", "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; - reg = <0x5d1f0000 0x10000>; - interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>; - #mbox-cells = <2>; - status = "disabled"; - }; - - lsio_mu13: mailbox@5d280000 { - compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu"; - reg = <0x5d280000 0x10000>; - interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; - #mbox-cells = <2>; - power-domains = <&pd IMX_SC_R_MU_13A>; - }; - - lsio_lpcg: clock-controller@5d400000 { - compatible = "fsl,imx8qxp-lpcg-lsio"; - reg = <0x5d400000 0x400000>; - #clock-cells = <1>; - }; - }; - thermal_zones: thermal-zones { cpu-thermal0 { polling-delay-passive = <250>; @@ -629,4 +256,14 @@ }; }; }; + + /* sorted in register address */ + #include "imx8-ss-adma.dtsi" + #include "imx8-ss-conn.dtsi" + #include "imx8-ss-ddr.dtsi" + #include "imx8-ss-lsio.dtsi" }; + +#include "imx8qxp-ss-adma.dtsi" +#include "imx8qxp-ss-conn.dtsi" +#include "imx8qxp-ss-lsio.dtsi" diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile index 3a052540605b63fc333339107b9dd8416087fd0b..0b5477442263f60c0af9d03ad8d3aed67de751f9 100644 --- a/arch/arm64/boot/dts/intel/Makefile +++ b/arch/arm64/boot/dts/intel/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -dtb-$(CONFIG_ARCH_AGILEX) += socfpga_agilex_socdk.dtb \ - socfpga_agilex_socdk_nand.dtb +dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_socdk.dtb \ + socfpga_agilex_socdk_nand.dtb \ + socfpga_n5x_socdk.dtb dtb-$(CONFIG_ARCH_KEEMBAY) += keembay-evm.dtb -dtb-$(CONFIG_ARCH_N5X) += socfpga_n5x_socdk.dtb diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi index 07c099b4ed5b565f3832c24d4240eef8a9414bf0..163f33b46e4f7e597d0fbbe3f42945868f65eb4d 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi +++ b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi @@ -6,6 +6,7 @@ /dts-v1/; #include <dt-bindings/reset/altr,rst-mgr-s10.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/clock/agilex-clock.h> / { @@ -61,10 +62,10 @@ pmu { compatible = "arm,armv8-pmuv3"; - interrupts = <0 170 4>, - <0 171 4>, - <0 172 4>, - <0 173 4>; + interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>; interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, @@ -77,7 +78,7 @@ method = "smc"; }; - intc: intc@fffc1000 { + intc: interrupt-controller@fffc1000 { compatible = "arm,gic-400", "arm,cortex-a15-gic"; #interrupt-cells = <3>; interrupt-controller; @@ -87,6 +88,48 @@ <0x0 0xfffc6000 0x0 0x2000>; }; + clocks { + cb_intosc_hs_div2_clk: cb-intosc-hs-div2-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + }; + + cb_intosc_ls_clk: cb-intosc-ls-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + }; + + f2s_free_clk: f2s-free-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + }; + + osc1: osc1 { + #clock-cells = <0>; + compatible = "fixed-clock"; + }; + + qspi_clk: qspi-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <200000000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&intc>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + }; + + usbphy0: usbphy { + #phy-cells = <0>; + compatible = "usb-nop-xceiv"; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -108,38 +151,10 @@ #clock-cells = <1>; }; - clocks { - cb_intosc_hs_div2_clk: cb-intosc-hs-div2-clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - }; - - cb_intosc_ls_clk: cb-intosc-ls-clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - }; - - f2s_free_clk: f2s-free-clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - }; - - osc1: osc1 { - #clock-cells = <0>; - compatible = "fixed-clock"; - }; - - qspi_clk: qspi-clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <200000000>; - }; - }; - gmac0: ethernet@ff800000 { compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac"; reg = <0xff800000 0x2000>; - interrupts = <0 90 4>; + interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq"; mac-address = [00 00 00 00 00 00]; resets = <&rst EMAC0_RESET>, <&rst EMAC0_OCP_RESET>; @@ -157,7 +172,7 @@ gmac1: ethernet@ff802000 { compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac"; reg = <0xff802000 0x2000>; - interrupts = <0 91 4>; + interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq"; mac-address = [00 00 00 00 00 00]; resets = <&rst EMAC1_RESET>, <&rst EMAC1_OCP_RESET>; @@ -175,7 +190,7 @@ gmac2: ethernet@ff804000 { compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac"; reg = <0xff804000 0x2000>; - interrupts = <0 92 4>; + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq"; mac-address = [00 00 00 00 00 00]; resets = <&rst EMAC2_RESET>, <&rst EMAC2_OCP_RESET>; @@ -206,7 +221,7 @@ reg = <0>; interrupt-controller; #interrupt-cells = <2>; - interrupts = <0 110 4>; + interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; }; }; @@ -226,7 +241,7 @@ reg = <0>; interrupt-controller; #interrupt-cells = <2>; - interrupts = <0 111 4>; + interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; }; }; @@ -235,7 +250,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc02800 0x100>; - interrupts = <0 103 4>; + interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst I2C0_RESET>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; status = "disabled"; @@ -246,7 +261,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc02900 0x100>; - interrupts = <0 104 4>; + interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst I2C1_RESET>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; status = "disabled"; @@ -257,7 +272,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc02a00 0x100>; - interrupts = <0 105 4>; + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst I2C2_RESET>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; status = "disabled"; @@ -268,7 +283,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc02b00 0x100>; - interrupts = <0 106 4>; + interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst I2C3_RESET>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; status = "disabled"; @@ -279,7 +294,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc02c00 0x100>; - interrupts = <0 107 4>; + interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst I2C4_RESET>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; status = "disabled"; @@ -290,7 +305,7 @@ #size-cells = <0>; compatible = "altr,socfpga-dw-mshc"; reg = <0xff808000 0x1000>; - interrupts = <0 96 4>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; fifo-depth = <0x400>; resets = <&rst SDMMC_RESET>; reset-names = "reset"; @@ -301,14 +316,14 @@ status = "disabled"; }; - nand: nand@ffb90000 { + nand: nand-controller@ffb90000 { #address-cells = <1>; #size-cells = <0>; compatible = "altr,socfpga-denali-nand"; reg = <0xffb90000 0x10000>, <0xffb80000 0x1000>; reg-names = "nand_data", "denali_reg"; - interrupts = <0 97 4>; + interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clkmgr AGILEX_NAND_CLK>, <&clkmgr AGILEX_NAND_X_CLK>, <&clkmgr AGILEX_NAND_ECC_CLK>; @@ -325,15 +340,15 @@ pdma: pdma@ffda0000 { compatible = "arm,pl330", "arm,primecell"; reg = <0xffda0000 0x1000>; - interrupts = <0 81 4>, - <0 82 4>, - <0 83 4>, - <0 84 4>, - <0 85 4>, - <0 86 4>, - <0 87 4>, - <0 88 4>, - <0 89 4>; + interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -355,17 +370,43 @@ #global-interrupts = <2>; #iommu-cells = <1>; interrupt-parent = <&intc>; - interrupts = <0 128 4>, /* Global Secure Fault */ - <0 129 4>, /* Global Non-secure Fault */ + /* Global Secure Fault */ + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, + /* Global Non-secure Fault */ + <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>, /* Non-secure Context Interrupts (32) */ - <0 138 4>, <0 139 4>, <0 140 4>, <0 141 4>, - <0 142 4>, <0 143 4>, <0 144 4>, <0 145 4>, - <0 146 4>, <0 147 4>, <0 148 4>, <0 149 4>, - <0 150 4>, <0 151 4>, <0 152 4>, <0 153 4>, - <0 154 4>, <0 155 4>, <0 156 4>, <0 157 4>, - <0 158 4>, <0 159 4>, <0 160 4>, <0 161 4>, - <0 162 4>, <0 163 4>, <0 164 4>, <0 165 4>, - <0 166 4>, <0 167 4>, <0 168 4>, <0 169 4>; + <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>; stream-match-mask = <0x7ff0>; clocks = <&clkmgr AGILEX_MPU_CCU_CLK>, <&clkmgr AGILEX_L3_MAIN_FREE_CLK>, @@ -378,7 +419,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0xffda4000 0x1000>; - interrupts = <0 99 4>; + interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst SPIM0_RESET>; reset-names = "spi"; reg-io-width = <4>; @@ -392,7 +433,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0xffda5000 0x1000>; - interrupts = <0 100 4>; + interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst SPIM1_RESET>; reset-names = "spi"; reg-io-width = <4>; @@ -406,18 +447,9 @@ reg = <0xffd12000 0x500>; }; - /* Local timer */ - timer { - compatible = "arm,armv8-timer"; - interrupts = <1 13 0xf08>, - <1 14 0xf08>, - <1 11 0xf08>, - <1 10 0xf08>; - }; - timer0: timer0@ffc03000 { compatible = "snps,dw-apb-timer"; - interrupts = <0 113 4>; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; reg = <0xffc03000 0x100>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; clock-names = "timer"; @@ -425,7 +457,7 @@ timer1: timer1@ffc03100 { compatible = "snps,dw-apb-timer"; - interrupts = <0 114 4>; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; reg = <0xffc03100 0x100>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; clock-names = "timer"; @@ -433,7 +465,7 @@ timer2: timer2@ffd00000 { compatible = "snps,dw-apb-timer"; - interrupts = <0 115 4>; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>; reg = <0xffd00000 0x100>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; clock-names = "timer"; @@ -441,16 +473,16 @@ timer3: timer3@ffd00100 { compatible = "snps,dw-apb-timer"; - interrupts = <0 116 4>; + interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; reg = <0xffd00100 0x100>; clocks = <&clkmgr AGILEX_L4_SP_CLK>; clock-names = "timer"; }; - uart0: serial0@ffc02000 { + uart0: serial@ffc02000 { compatible = "snps,dw-apb-uart"; reg = <0xffc02000 0x100>; - interrupts = <0 108 4>; + interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; resets = <&rst UART0_RESET>; @@ -458,10 +490,10 @@ clocks = <&clkmgr AGILEX_L4_SP_CLK>; }; - uart1: serial1@ffc02100 { + uart1: serial@ffc02100 { compatible = "snps,dw-apb-uart"; reg = <0xffc02100 0x100>; - interrupts = <0 109 4>; + interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; resets = <&rst UART1_RESET>; @@ -469,16 +501,10 @@ status = "disabled"; }; - usbphy0: usbphy@0 { - #phy-cells = <0>; - compatible = "usb-nop-xceiv"; - status = "okay"; - }; - usb0: usb@ffb00000 { compatible = "snps,dwc2"; reg = <0xffb00000 0x40000>; - interrupts = <0 93 4>; + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy0>; phy-names = "usb2-phy"; resets = <&rst USB0_RESET>, <&rst USB0_OCP_RESET>; @@ -491,7 +517,7 @@ usb1: usb@ffb40000 { compatible = "snps,dwc2"; reg = <0xffb40000 0x40000>; - interrupts = <0 94 4>; + interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy0>; phy-names = "usb2-phy"; resets = <&rst USB1_RESET>, <&rst USB1_OCP_RESET>; @@ -504,7 +530,7 @@ watchdog0: watchdog@ffd00200 { compatible = "snps,dw-wdt"; reg = <0xffd00200 0x100>; - interrupts = <0 117 4>; + interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst WATCHDOG0_RESET>; clocks = <&clkmgr AGILEX_L4_SYS_FREE_CLK>; status = "disabled"; @@ -513,7 +539,7 @@ watchdog1: watchdog@ffd00300 { compatible = "snps,dw-wdt"; reg = <0xffd00300 0x100>; - interrupts = <0 118 4>; + interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst WATCHDOG1_RESET>; clocks = <&clkmgr AGILEX_L4_SYS_FREE_CLK>; status = "disabled"; @@ -522,7 +548,7 @@ watchdog2: watchdog@ffd00400 { compatible = "snps,dw-wdt"; reg = <0xffd00400 0x100>; - interrupts = <0 125 4>; + interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst WATCHDOG2_RESET>; clocks = <&clkmgr AGILEX_L4_SYS_FREE_CLK>; status = "disabled"; @@ -531,7 +557,7 @@ watchdog3: watchdog@ffd00500 { compatible = "snps,dw-wdt"; reg = <0xffd00500 0x100>; - interrupts = <0 126 4>; + interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; resets = <&rst WATCHDOG3_RESET>; clocks = <&clkmgr AGILEX_L4_SYS_FREE_CLK>; status = "disabled"; @@ -548,7 +574,7 @@ altr,sysmgr-syscon = <&sysmgr>; #address-cells = <1>; #size-cells = <1>; - interrupts = <0 15 4>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; interrupt-controller; #interrupt-cells = <2>; ranges; @@ -607,7 +633,7 @@ #size-cells = <0>; reg = <0xff8d2000 0x100>, <0xff900000 0x100000>; - interrupts = <0 3 4>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; cdns,fifo-depth = <128>; cdns,fifo-width = <4>; cdns,trigger-address = <0x00000000>; diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts index a7a83f29f00bd271d51047ec778fbab1d393eaf4..0f7a0ba344bedc3842eacea74b470c43f763f705 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts +++ b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts @@ -41,14 +41,6 @@ /* We expect the bootloader to fill in the reg */ reg = <0 0 0 0>; }; - - soc { - clocks { - osc1 { - clock-frequency = <25000000>; - }; - }; - }; }; &gpio1 { @@ -92,6 +84,10 @@ bus-width = <4>; }; +&osc1 { + clock-frequency = <25000000>; +}; + &uart0 { status = "okay"; }; @@ -117,7 +113,7 @@ m25p,fast-read; cdns,page-size = <256>; cdns,block-size = <16>; - cdns,read-delay = <1>; + cdns,read-delay = <2>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; cdns,tchsh-ns = <4>; diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk_nand.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk_nand.dts index 979aa59a6bd0bf47bddccf561eaabc584f4992a5..cc2dcabf34e3090d3311ce30cf5fc595d7466cf7 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk_nand.dts +++ b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk_nand.dts @@ -20,17 +20,17 @@ leds { compatible = "gpio-leds"; - hps0 { + led0 { label = "hps_led0"; gpios = <&portb 20 GPIO_ACTIVE_HIGH>; }; - hps1 { + led1 { label = "hps_led1"; gpios = <&portb 19 GPIO_ACTIVE_HIGH>; }; - hps2 { + led2 { label = "hps_led2"; gpios = <&portb 21 GPIO_ACTIVE_HIGH>; }; @@ -41,14 +41,6 @@ /* We expect the bootloader to fill in the reg */ reg = <0 0 0 0>; }; - - soc { - clocks { - osc1 { - clock-frequency = <25000000>; - }; - }; - }; }; &gpio1 { @@ -121,6 +113,10 @@ }; }; +&osc1 { + clock-frequency = <25000000>; +}; + &uart0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts index 5f56e2697feeab401aa230b5a1336070ac78669f..01f1307ce4acba1b37e043e47c77b578bb120d94 100644 --- a/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts +++ b/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts @@ -23,14 +23,6 @@ /* We expect the bootloader to fill in the reg */ reg = <0 0 0 0>; }; - - soc { - clocks { - osc1 { - clock-frequency = <25000000>; - }; - }; - }; }; &clkmgr { @@ -44,6 +36,10 @@ bus-width = <4>; }; +&osc1 { + clock-frequency = <25000000>; +}; + &uart0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi index 7a2df148c6a31aa00e3ef638ff9711d6540eab11..456dcd4a7793f5576eb3ef9ae9e84ce560c44ccf 100644 --- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi @@ -156,7 +156,8 @@ }; nb_periph_clk: nb-periph-clk@13000 { - compatible = "marvell,armada-3700-periph-clock-nb"; + compatible = "marvell,armada-3700-periph-clock-nb", + "syscon"; reg = <0x13000 0x100>; clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts index a7eb4e7697a25a73c8aea1de38de6c851bdcacbf..51f3e2907597fa9880066f94afeafccc7e008cf3 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts @@ -218,6 +218,10 @@ }; }; +&cp0_utmi { + status = "okay"; +}; + &cp0_comphy1 { cp0_usbh0_con: connector { compatible = "usb-a-connector"; @@ -226,8 +230,9 @@ }; &cp0_usb3_0 { - phys = <&cp0_comphy1 0>; - phy-names = "cp0-usb3h0-comphy"; + phys = <&cp0_comphy1 0>, <&cp0_utmi0>; + phy-names = "cp0-usb3h0-comphy", "utmi"; + dr_mode = "host"; status = "okay"; }; @@ -239,8 +244,9 @@ }; &cp0_usb3_1 { - phys = <&cp0_comphy4 1>; - phy-names = "cp0-usb3h1-comphy"; + phys = <&cp0_comphy4 1>, <&cp0_utmi1>; + phy-names = "cp0-usb3h1-comphy", "utmi"; + dr_mode = "host"; status = "okay"; }; 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 eb01cc96ba7a3a47315f8d1c5808b5c0a709979a..0ec0d562581899bdc8490182a9feb42ed6b22f7c 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 @@ -31,6 +31,16 @@ ethernet2 = &cp1_eth2; }; + fan: pwm { + compatible = "pwm-fan"; + /* 20% steps */ + cooling-levels = <0 51 102 153 204 255>; + #cooling-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&cp0_fan_pwm_pins>; + pwms = <&cp0_gpio2 16 40000>; + }; + v_3_3: regulator-3-3v { compatible = "regulator-fixed"; regulator-name = "v_3_3"; @@ -102,6 +112,123 @@ }; }; +&ap_thermal_ic { + polling-delay = <1000>; /* milliseconds */ + trips { + ap_active: trip-active { + temperature = <40000>; /* millicelsius */ + hysteresis = <4000>; /* millicelsius */ + type = "active"; + }; + }; + cooling-maps { + map0 { + trip = <&ap_active>; + cooling-device = <&fan THERMAL_NO_LIMIT 4>; + }; + map1 { + trip = <&ap_crit>; + cooling-device = <&fan 4 5>; + }; + }; +}; + +&cp0_thermal_ic { + polling-delay = <1000>; /* milliseconds */ + trips { + cp0_active0: trip-active0 { + temperature = <40000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + cp0_active1: trip-active1 { + temperature = <45000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + cp0_active2: trip-active2 { + temperature = <50000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + cp0_active3: trip-active3 { + temperature = <60000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + }; + cooling-maps { + map0 { + trip = <&cp0_active0>; + cooling-device = <&fan 0 1>; + }; + map1 { + trip = <&cp0_active1>; + cooling-device = <&fan 1 2>; + }; + map2 { + trip = <&cp0_active2>; + cooling-device = <&fan 2 3>; + }; + map3 { + trip = <&cp0_active3>; + cooling-device = <&fan 3 4>; + }; + map4 { + trip = <&cp0_crit>; + cooling-device = <&fan 4 5>; + }; + }; +}; + +&cp1_thermal_ic { + polling-delay = <1000>; /* milliseconds */ + trips { + cp1_active0: trip-active0 { + temperature = <40000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + cp1_active1: trip-active1 { + temperature = <45000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + cp1_active2: trip-active2 { + temperature = <50000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + cp1_active3: trip-active3 { + temperature = <60000>; /* millicelsius */ + hysteresis = <2500>; /* millicelsius */ + type = "active"; + }; + }; + cooling-maps { + map0 { + trip = <&cp1_active0>; + cooling-device = <&fan 0 1>; + }; + map1 { + trip = <&cp1_active1>; + cooling-device = <&fan 1 2>; + }; + map2 { + trip = <&cp1_active2>; + cooling-device = <&fan 2 3>; + }; + map3 { + trip = <&cp1_active3>; + cooling-device = <&fan 3 4>; + }; + map4 { + trip = <&cp1_crit>; + cooling-device = <&fan 4 5>; + }; + }; +}; + &uart0 { status = "okay"; pinctrl-0 = <&uart0_pins>; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts index 09fb5256f1db12ef8dca938b4d3c82322cb2619e..e39e1efc95b6e74ddd2b4e27e754bc7360868b96 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts @@ -154,8 +154,15 @@ }; /* CON9 on CP0 expansion */ +&cp0_utmi { + status = "okay"; +}; + &cp0_usb3_0 { usb-phy = <&cp0_usb3_0_phy>; + phys = <&cp0_utmi0>; + phy-names = "utmi"; + dr_mode = "host"; status = "okay"; }; @@ -168,8 +175,9 @@ /* CON10 on CP0 expansion */ &cp0_usb3_1 { - phys = <&cp0_comphy4 1>; - phy-names = "cp0-usb3h1-comphy"; + phys = <&cp0_comphy4 1>, <&cp0_utmi1>; + phy-names = "usb", "utmi"; + dr_mode = "host"; status = "okay"; }; @@ -306,14 +314,23 @@ }; }; +&cp1_utmi { + status = "okay"; +}; + /* CON9 on CP1 expansion */ &cp1_usb3_0 { usb-phy = <&cp1_usb3_0_phy>; + phys = <&cp1_utmi0>; + phy-names = "utmi"; + dr_mode = "host"; status = "okay"; }; /* CON10 on CP1 expansion */ &cp1_usb3_1 { + phys = <&cp1_utmi1>; + phy-names = "utmi"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi index cbcb210cb6d8db33ca6b40cf70b3b2fbdcf6f3c3..adbfecc678b5c5d99c432d87bd94304ee10271e4 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi @@ -259,13 +259,23 @@ vqmmc-supply = <&v_3_3>; }; +&cp0_utmi { + status = "okay"; +}; + &cp0_usb3_0 { /* J38? - USB2.0 only */ + phys = <&cp0_utmi0>; + phy-names = "utmi"; + dr_mode = "host"; status = "okay"; }; &cp0_usb3_1 { /* J38? - USB2.0 only */ + phys = <&cp0_utmi1>; + phy-names = "utmi"; + dr_mode = "host"; status = "okay"; }; @@ -364,9 +374,14 @@ }; }; +&cp1_utmi { + status = "okay"; +}; + &cp1_usb3_0 { /* CPS Lane 2 - CON7 */ - phys = <&cp1_comphy2 0>; - phy-names = "cp1-usb3h0-comphy"; + phys = <&cp1_comphy2 0>, <&cp1_utmi0>; + phy-names = "cp1-usb3h0-comphy", "utmi"; + dr_mode = "host"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi index c6f5df2deccfeb87a60456f29199b1da74713419..3bd2182817fb849d9beec3892679ed81f110feee 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi @@ -285,6 +285,25 @@ }; }; + CP11X_LABEL(utmi): utmi@580000 { + compatible = "marvell,cp110-utmi-phy"; + reg = <0x580000 0x2000>; + marvell,system-controller = <&CP11X_LABEL(syscon0)>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + CP11X_LABEL(utmi0): usb-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + CP11X_LABEL(utmi1): usb-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; + CP11X_LABEL(usb3_0): usb@500000 { compatible = "marvell,armada-8k-xhci", "generic-xhci"; diff --git a/arch/arm64/boot/dts/marvell/cn9130-db.dts b/arch/arm64/boot/dts/marvell/cn9130-db.dts index 79020e6d27928914aebfc067c26d2caadaf4e5f5..2c2af001619b0e886bb0a57c5c22f9a8737d38f3 100644 --- a/arch/arm64/boot/dts/marvell/cn9130-db.dts +++ b/arch/arm64/boot/dts/marvell/cn9130-db.dts @@ -392,14 +392,22 @@ }; }; +&cp0_utmi { + status = "okay"; +}; + &cp0_usb3_0 { status = "okay"; usb-phy = <&cp0_usb3_0_phy0>; - phy-names = "usb"; + phys = <&cp0_utmi0>; + phy-names = "utmi"; + dr_mode = "host"; }; &cp0_usb3_1 { status = "okay"; usb-phy = <&cp0_usb3_0_phy1>; - phy-names = "usb"; + phys = <&cp0_utmi1>; + phy-names = "utmi"; + dr_mode = "host"; }; diff --git a/arch/arm64/boot/dts/marvell/cn9131-db.dts b/arch/arm64/boot/dts/marvell/cn9131-db.dts index 3c975f98b2a3d7a98ce71d506b13cd7978bb8689..ba2d4e1da1590676843cc3772c99592ccc9d9362 100644 --- a/arch/arm64/boot/dts/marvell/cn9131-db.dts +++ b/arch/arm64/boot/dts/marvell/cn9131-db.dts @@ -193,10 +193,15 @@ }; /* CON58 */ +&cp1_utmi { + status = "okay"; +}; + &cp1_usb3_1 { status = "okay"; usb-phy = <&cp1_usb3_0_phy0>; /* Generic PHY, providing serdes lanes */ - phys = <&cp1_comphy3 1>; - phy-names = "usb"; + phys = <&cp1_comphy3 1>, <&cp1_utmi1>; + phy-names = "usb", "utmi"; + dr_mode = "host"; }; diff --git a/arch/arm64/boot/dts/marvell/cn9132-db.dts b/arch/arm64/boot/dts/marvell/cn9132-db.dts index 4ef0df3097caedcd606ee88c3b10527262d4fc8c..81fba024b22da93fde77ee15bb5bb5171199f2cb 100644 --- a/arch/arm64/boot/dts/marvell/cn9132-db.dts +++ b/arch/arm64/boot/dts/marvell/cn9132-db.dts @@ -205,17 +205,24 @@ }; }; +&cp2_utmi { + status = "okay"; +}; + &cp2_usb3_0 { status = "okay"; usb-phy = <&cp2_usb3_0_phy0>; + phys = <&cp2_utmi0>; phy-names = "usb"; + dr_mode = "host"; }; /* SLM-1521-V2, CON11 */ &cp2_usb3_1 { status = "okay"; usb-phy = <&cp2_usb3_0_phy1>; - phy-names = "usb"; /* Generic PHY, providing serdes lanes */ - phys = <&cp2_comphy3 1>; + phys = <&cp2_comphy3 1>, <&cp2_utmi1>; + phy-names = "usb", "utmi"; + dr_mode = "host"; }; diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index deba27ab765746761e1a8d930607902b32f49c6c..a1c50adc98fa71b50cd79fbe1eb52be43720a93c 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -13,7 +13,15 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana-rev7.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-damu.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-juniper-sku16.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kakadu.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku16.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku272.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku288.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku32.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-krane-sku0.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-krane-sku176.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-pumpkin.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-evb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi index db17d0a4ed57bb0a776197efd0e136872cf4c57f..a9cca9c146fdc6396e83538fa320fe2e5328b955 100644 --- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi @@ -805,7 +805,7 @@ ranges; status = "disabled"; - usb_host0: xhci@11270000 { + usb_host0: usb@11270000 { compatible = "mediatek,mt2712-xhci", "mediatek,mtk-xhci"; reg = <0 0x11270000 0 0x1000>; @@ -818,7 +818,7 @@ }; }; - u3phy0: usb-phy@11290000 { + u3phy0: t-phy@11290000 { compatible = "mediatek,mt2712-tphy", "mediatek,generic-tphy-v2"; #address-cells = <1>; @@ -869,7 +869,7 @@ ranges; status = "disabled"; - usb_host1: xhci@112c0000 { + usb_host1: usb@112c0000 { compatible = "mediatek,mt2712-xhci", "mediatek,mtk-xhci"; reg = <0 0x112c0000 0 0x1000>; @@ -882,7 +882,7 @@ }; }; - u3phy1: usb-phy@112e0000 { + u3phy1: t-phy@112e0000 { compatible = "mediatek,mt2712-tphy", "mediatek,generic-tphy-v2"; #address-cells = <1>; diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts index 08ad0ffb24df345c53e0bc6eb6f98386db4b0e9c..f2dc850010f10c1e73b48a2897e31ae0aeb6eb7b 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -495,6 +495,16 @@ groups = "watchdog"; }; }; + + wmac_pins: wmac-pins { + mux { + function = "antsel"; + groups = "antsel0", "antsel1", "antsel2", "antsel3", + "antsel4", "antsel5", "antsel6", "antsel7", + "antsel8", "antsel9", "antsel12", "antsel13", + "antsel14", "antsel15", "antsel16", "antsel17"; + }; + }; }; &pwm { @@ -559,5 +569,7 @@ }; &wmac { + pinctrl-names = "default"; + pinctrl-0 = <&wmac_pins>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index 7c6d871538a63bfff476de69fbcda458e2610116..890a942ec60827dc16362c1a83e9958a0f455d48 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -742,8 +742,8 @@ status = "disabled"; }; - u3phy: usb-phy@1a0c4000 { - compatible = "mediatek,mt7622-u3phy", + u3phy: t-phy@1a0c4000 { + compatible = "mediatek,mt7622-tphy", "mediatek,generic-tphy-v1"; reg = <0 0x1a0c4000 0 0x700>; #address-cells = <2>; @@ -877,8 +877,9 @@ status = "disabled"; }; - sata_phy: sata-phy@1a243000 { - compatible = "mediatek,generic-tphy-v1"; + sata_phy: t-phy@1a243000 { + compatible = "mediatek,mt7622-tphy", + "mediatek,generic-tphy-v1"; #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts index 6dffada2e66b4c98cfa31169c30f1e95ddfc2875..f6a1738dfbaa1c46e2322fb57524eef61781e496 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts @@ -294,7 +294,7 @@ &pwrap { /* Only MT8173 E1 needs USB power domain */ - power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + power-domains = <&spm MT8173_POWER_DOMAIN_USB>; pmic: mt6397 { compatible = "mediatek,mt6397"; @@ -516,10 +516,8 @@ extcon = <&extcon_usb>; dr_mode = "otg"; wakeup-source; - pinctrl-names = "default", "id_float", "id_ground"; + pinctrl-names = "default"; pinctrl-0 = <&usb_id_pins_float>; - pinctrl-1 = <&usb_id_pins_float>; - pinctrl-2 = <&usb_id_pins_ground>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi index 7fa870e4386a393acc8cd691ea21961100e11630..003a5653c505d60d776c5b0a0974bcc4cdfe38bd 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi @@ -631,7 +631,7 @@ #mbox-cells = <2>; }; - mipi_tx0: mipi-dphy@10215000 { + mipi_tx0: dsi-phy@10215000 { compatible = "mediatek,mt8173-mipi-tx"; reg = <0 0x10215000 0 0x1000>; clocks = <&clk26m>; @@ -641,7 +641,7 @@ status = "disabled"; }; - mipi_tx1: mipi-dphy@10216000 { + mipi_tx1: dsi-phy@10216000 { compatible = "mediatek,mt8173-mipi-tx"; reg = <0 0x10216000 0 0x1000>; clocks = <&clk26m>; @@ -926,7 +926,7 @@ }; ssusb: usb@11271000 { - compatible = "mediatek,mt8173-mtu3"; + compatible = "mediatek,mt8173-mtu3", "mediatek,mtu3"; reg = <0 0x11271000 0 0x3000>, <0 0x11280700 0 0x0100>; reg-names = "mac", "ippc"; @@ -943,8 +943,9 @@ ranges; status = "disabled"; - usb_host: xhci@11270000 { - compatible = "mediatek,mt8173-xhci"; + usb_host: usb@11270000 { + compatible = "mediatek,mt8173-xhci", + "mediatek,mtk-xhci"; reg = <0 0x11270000 0 0x1000>; reg-names = "mac"; interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; @@ -955,7 +956,7 @@ }; }; - u3phy: usb-phy@11290000 { + u3phy: t-phy@11290000 { compatible = "mediatek,mt8173-u3phy"; reg = <0 0x11290000 0 0x800>; #address-cells = <2>; @@ -1235,7 +1236,7 @@ <&mmsys CLK_MM_DSI1_DIGITAL>, <&mipi_tx1>; clock-names = "engine", "digital", "hs"; - phy = <&mipi_tx1>; + phys = <&mipi_tx1>; phy-names = "dphy"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts index 3249c959f76fc77c4047e4f18731ea7dab4327df..edff1e03e6fee94f5a32e5f1775be0d5d0ae74e3 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts @@ -352,6 +352,10 @@ }; }; +&mfg { + domain-supply = <&mt6358_vgpu_reg>; +}; + &spi0 { pinctrl-names = "default"; pinctrl-0 = <&spi_pins_0>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts new file mode 100644 index 0000000000000000000000000000000000000000..42ba9c00866cd692b82a4c6068ba514d6d97539c --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" + +/ { + model = "Google damu board"; + compatible = "google,damu", "mediatek,mt8183"; +}; + +&touchscreen { + status = "okay"; + + compatible = "hid-over-i2c"; + reg = <0x10>; + interrupt-parent = <&pio>; + interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_DAMU"; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dts new file mode 100644 index 0000000000000000000000000000000000000000..36d2c3b3cadf9abee7520b355c5539d7eeb0f9db --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-juniper.dtsi" + +/ { + model = "Google juniper sku16 board"; + compatible = "google,juniper-sku16", "google,juniper", "mediatek,mt8183"; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..078bc765646f57fd8c55e97325893ab50e4dac51 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper.dtsi @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" + +&i2c2 { + trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_pins>; + + interrupts-extended = <&pio 7 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_JUNIPER"; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4049dff8464bb562d2e37e0916121dcc0f7c15d8 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +#include "mt8183-kukui.dtsi" + +/ { + panel: panel { + compatible = "auo,b116xw03"; + power-supply = <&pp3300_panel>; + ddc-i2c-bus = <&i2c4>; + backlight = <&backlight_lcd0>; + + port { + panel_in: endpoint { + remote-endpoint = <&anx7625_out>; + }; + }; + }; + + pp1200_mipibrdg: pp1200-mipibrdg { + compatible = "regulator-fixed"; + regulator-name = "pp1200_mipibrdg"; + pinctrl-names = "default"; + pinctrl-0 = <&pp1200_mipibrdg_en>; + + enable-active-high; + regulator-boot-on; + + gpio = <&pio 54 GPIO_ACTIVE_HIGH>; + }; + + pp1800_mipibrdg: pp1800-mipibrdg { + compatible = "regulator-fixed"; + regulator-name = "pp1800_mipibrdg"; + pinctrl-names = "default"; + pinctrl-0 = <&pp1800_lcd_en>; + + enable-active-high; + regulator-boot-on; + + gpio = <&pio 36 GPIO_ACTIVE_HIGH>; + }; + + pp3300_panel: pp3300-panel { + compatible = "regulator-fixed"; + regulator-name = "pp3300_panel"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + pinctrl-names = "default"; + pinctrl-0 = <&pp3300_panel_pins>; + + enable-active-high; + regulator-boot-on; + + gpio = <&pio 35 GPIO_ACTIVE_HIGH>; + }; + + vddio_mipibrdg: vddio-mipibrdg { + compatible = "regulator-fixed"; + regulator-name = "vddio_mipibrdg"; + pinctrl-names = "default"; + pinctrl-0 = <&vddio_mipibrdg_en>; + + enable-active-high; + regulator-boot-on; + + gpio = <&pio 37 GPIO_ACTIVE_HIGH>; + }; + + volume_buttons: volume-buttons { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&volume_button_pins>; + + volume_down { + label = "Volume Down"; + linux,code = <KEY_VOLUMEDOWN>; + debounce-interval = <100>; + + gpios = <&pio 6 GPIO_ACTIVE_LOW>; + }; + + volume_up { + label = "Volume Up"; + linux,code = <KEY_VOLUMEUP>; + debounce-interval = <100>; + + gpios = <&pio 5 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&dsi0 { + status = "okay"; + /delete-node/panel@0; + ports { + port { + dsi_out: endpoint { + remote-endpoint = <&anx7625_in>; + }; + }; + }; +}; + +&i2c0 { + status = "okay"; + + touchscreen: touchscreen@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&pio 156 GPIO_ACTIVE_LOW>; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; + clock-frequency = <400000>; + + trackpad@15 { + compatible = "elan,ekth3000"; + reg = <0x15>; + + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_pins>; + + interrupts-extended = <&pio 7 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins>; + status = "okay"; + clock-frequency = <100000>; + + anx_bridge: anx7625@58 { + compatible = "analogix,anx7625"; + reg = <0x58>; + pinctrl-names = "default"; + pinctrl-0 = <&anx7625_pins>; + panel_flags = <1>; + enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>; + reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>; + vdd10-supply = <&pp1200_mipibrdg>; + vdd18-supply = <&pp1800_mipibrdg>; + vdd33-supply = <&vddio_mipibrdg>; + + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + + anx7625_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + anx7625_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&i2c_tunnel { + google,remote-bus = <2>; +}; + +&pio { + /* 192 lines */ + gpio-line-names = + "SPI_AP_EC_CS_L", + "SPI_AP_EC_MOSI", + "SPI_AP_EC_CLK", + "I2S3_DO", + "USB_PD_INT_ODL", + "", + "", + "", + "", + "IT6505_HPD_L", + "I2S3_TDM_D3", + "SOC_I2C6_1V8_SCL", + "SOC_I2C6_1V8_SDA", + "DPI_D0", + "DPI_D1", + "DPI_D2", + "DPI_D3", + "DPI_D4", + "DPI_D5", + "DPI_D6", + "DPI_D7", + "DPI_D8", + "DPI_D9", + "DPI_D10", + "DPI_D11", + "DPI_HSYNC", + "DPI_VSYNC", + "DPI_DE", + "DPI_CK", + "AP_MSDC1_CLK", + "AP_MSDC1_DAT3", + "AP_MSDC1_CMD", + "AP_MSDC1_DAT0", + "AP_MSDC1_DAT2", + "AP_MSDC1_DAT1", + "", + "", + "", + "", + "", + "", + "OTG_EN", + "DRVBUS", + "DISP_PWM", + "DSI_TE", + "LCM_RST_1V8", + "AP_CTS_WIFI_RTS", + "AP_RTS_WIFI_CTS", + "SOC_I2C5_1V8_SCL", + "SOC_I2C5_1V8_SDA", + "SOC_I2C3_1V8_SCL", + "SOC_I2C3_1V8_SDA", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "SOC_I2C1_1V8_SDA", + "SOC_I2C0_1V8_SDA", + "SOC_I2C0_1V8_SCL", + "SOC_I2C1_1V8_SCL", + "AP_SPI_H1_MISO", + "AP_SPI_H1_CS_L", + "AP_SPI_H1_MOSI", + "AP_SPI_H1_CLK", + "I2S5_BCK", + "I2S5_LRCK", + "I2S5_DO", + "BOOTBLOCK_EN_L", + "MT8183_KPCOL0", + "SPI_AP_EC_MISO", + "UART_DBG_TX_AP_RX", + "UART_AP_TX_DBG_RX", + "I2S2_MCK", + "I2S2_BCK", + "CLK_5M_WCAM", + "CLK_2M_UCAM", + "I2S2_LRCK", + "I2S2_DI", + "SOC_I2C2_1V8_SCL", + "SOC_I2C2_1V8_SDA", + "SOC_I2C4_1V8_SCL", + "SOC_I2C4_1V8_SDA", + "", + "SCL8", + "SDA8", + "FCAM_PWDN_L", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "", + "", + "", + "", + "", + "", + /* + * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics + * call it BIOS_FLASH_WP_R_L. + */ + "AP_FLASH_WP_L", + "EC_AP_INT_ODL", + "IT6505_INT_ODL", + "H1_INT_OD_L", + "", + "", + "", + "", + "", + "", + "", + "AP_SPI_FLASH_MISO", + "AP_SPI_FLASH_CS_L", + "AP_SPI_FLASH_MOSI", + "AP_SPI_FLASH_CLK", + "DA7219_IRQ", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ""; + + pp1200_mipibrdg_en: pp1200-mipibrdg-en { + pins1 { + pinmux = <PINMUX_GPIO54__FUNC_GPIO54>; + output-low; + }; + }; + + pp1800_lcd_en: pp1800-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO36__FUNC_GPIO36>; + output-low; + }; + }; + + pp3300_panel_pins: pp3300-panel-pins { + panel_3v3_enable: panel-3v3-enable { + pinmux = <PINMUX_GPIO35__FUNC_GPIO35>; + output-low; + }; + }; + + ppvarp_lcd_en: ppvarp-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO66__FUNC_GPIO66>; + output-low; + }; + }; + + ppvarn_lcd_en: ppvarn-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO166__FUNC_GPIO166>; + output-low; + }; + }; + + anx7625_pins: anx7625-pins { + pins1 { + pinmux = <PINMUX_GPIO45__FUNC_GPIO45>, + <PINMUX_GPIO73__FUNC_GPIO73>; + output-low; + }; + pins2 { + pinmux = <PINMUX_GPIO4__FUNC_GPIO4>; + input-enable; + bias-pull-up; + }; + }; + + touchscreen_pins: touchscreen-pins { + touch_int_odl { + pinmux = <PINMUX_GPIO155__FUNC_GPIO155>; + input-enable; + bias-pull-up; + }; + + touch_rst_l { + pinmux = <PINMUX_GPIO156__FUNC_GPIO156>; + output-high; + }; + }; + + trackpad_pins: trackpad-pins { + trackpad_int { + pinmux = <PINMUX_GPIO7__FUNC_GPIO7>; + input-enable; + bias-disable; /* pulled externally */ + }; + }; + + vddio_mipibrdg_en: vddio-mipibrdg-en { + pins1 { + pinmux = <PINMUX_GPIO37__FUNC_GPIO37>; + output-low; + }; + }; + + volume_button_pins: volume-button-pins { + voldn-btn-odl { + pinmux = <PINMUX_GPIO6__FUNC_GPIO6>; + input-enable; + bias-pull-up; + }; + + volup-btn-odl { + pinmux = <PINMUX_GPIO5__FUNC_GPIO5>; + input-enable; + bias-pull-up; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts new file mode 100644 index 0000000000000000000000000000000000000000..20eb0dc68f094903dc0f59dab3057d2c1565cffa --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2020 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-kakadu.dtsi" + +/ { + model = "MediaTek kakadu board"; + compatible = "google,kakadu-rev3", "google,kakadu-rev2", + "google,kakadu", "mediatek,mt8183"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b442e38a3156dc7a13f6744a63b197c7198672c6 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2020 Google LLC + */ + +#include "mt8183-kukui.dtsi" +#include <dt-bindings/input/gpio-keys.h> + +/ { + ppvarn_lcd: ppvarn-lcd { + compatible = "regulator-fixed"; + regulator-name = "ppvarn_lcd"; + pinctrl-names = "default"; + pinctrl-0 = <&ppvarn_lcd_en>; + + enable-active-high; + + gpio = <&pio 66 GPIO_ACTIVE_HIGH>; + }; + + ppvarp_lcd: ppvarp-lcd { + compatible = "regulator-fixed"; + regulator-name = "ppvarp_lcd"; + pinctrl-names = "default"; + pinctrl-0 = <&ppvarp_lcd_en>; + + enable-active-high; + + gpio = <&pio 166 GPIO_ACTIVE_HIGH>; + }; + + pp1800_lcd: pp1800-lcd { + compatible = "regulator-fixed"; + regulator-name = "pp1800_lcd"; + pinctrl-names = "default"; + pinctrl-0 = <&pp1800_lcd_en>; + + enable-active-high; + + gpio = <&pio 36 GPIO_ACTIVE_HIGH>; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pen_eject>; + + pen-insert { + label = "Pen Insert"; + /* Insert = low, eject = high */ + gpios = <&pio 6 GPIO_ACTIVE_LOW>; + linux,code = <SW_PEN_INSERTED>; + linux,input-type = <EV_SW>; + wakeup-event-action = <EV_ACT_DEASSERTED>; + wakeup-source; + }; + }; +}; + +&bluetooth { + firmware-name = "nvm_00440302_i2s_eu.bin"; +}; + +&i2c0 { + status = "okay"; + + touchscreen: touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + pinctrl-names = "default"; + pinctrl-0 = <&open_touch>; + + interrupt-parent = <&pio>; + interrupts = <155 IRQ_TYPE_EDGE_FALLING>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; + }; +}; + +&mt6358_vcama2_reg { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; + clock-frequency = <400000>; + + eeprom@58 { + compatible = "atmel,24c32"; + reg = <0x58>; + pagesize = <32>; + }; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins>; + status = "okay"; + clock-frequency = <400000>; + + eeprom@54 { + compatible = "atmel,24c32"; + reg = <0x54>; + pagesize = <32>; + }; +}; + +&mipi_tx0 { + drive-strength-microamp = <5800>; +}; + +&pio { + /* 192 lines */ + gpio-line-names = + "SPI_AP_EC_CS_L", + "SPI_AP_EC_MOSI", + "SPI_AP_EC_CLK", + "I2S3_DO", + "USB_PD_INT_ODL", + "", + "", + "", + "", + "IT6505_HPD_L", + "I2S3_TDM_D3", + "SOC_I2C6_1V8_SCL", + "SOC_I2C6_1V8_SDA", + "DPI_D0", + "DPI_D1", + "DPI_D2", + "DPI_D3", + "DPI_D4", + "DPI_D5", + "DPI_D6", + "DPI_D7", + "DPI_D8", + "DPI_D9", + "DPI_D10", + "DPI_D11", + "DPI_HSYNC", + "DPI_VSYNC", + "DPI_DE", + "DPI_CK", + "AP_MSDC1_CLK", + "AP_MSDC1_DAT3", + "AP_MSDC1_CMD", + "AP_MSDC1_DAT0", + "AP_MSDC1_DAT2", + "AP_MSDC1_DAT1", + "", + "", + "", + "", + "", + "", + "OTG_EN", + "DRVBUS", + "DISP_PWM", + "DSI_TE", + "LCM_RST_1V8", + "AP_CTS_WIFI_RTS", + "AP_RTS_WIFI_CTS", + "SOC_I2C5_1V8_SCL", + "SOC_I2C5_1V8_SDA", + "SOC_I2C3_1V8_SCL", + "SOC_I2C3_1V8_SDA", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "SOC_I2C1_1V8_SDA", + "SOC_I2C0_1V8_SDA", + "SOC_I2C0_1V8_SCL", + "SOC_I2C1_1V8_SCL", + "AP_SPI_H1_MISO", + "AP_SPI_H1_CS_L", + "AP_SPI_H1_MOSI", + "AP_SPI_H1_CLK", + "I2S5_BCK", + "I2S5_LRCK", + "I2S5_DO", + "BOOTBLOCK_EN_L", + "MT8183_KPCOL0", + "SPI_AP_EC_MISO", + "UART_DBG_TX_AP_RX", + "UART_AP_TX_DBG_RX", + "I2S2_MCK", + "I2S2_BCK", + "CLK_5M_WCAM", + "CLK_2M_UCAM", + "I2S2_LRCK", + "I2S2_DI", + "SOC_I2C2_1V8_SCL", + "SOC_I2C2_1V8_SDA", + "SOC_I2C4_1V8_SCL", + "SOC_I2C4_1V8_SDA", + "", + "SCL8", + "SDA8", + "FCAM_PWDN_L", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "", + "", + "", + "", + "", + "", + /* + * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics + * call it BIOS_FLASH_WP_R_L. + */ + "AP_FLASH_WP_L", + "EC_AP_INT_ODL", + "IT6505_INT_ODL", + "H1_INT_OD_L", + "", + "", + "", + "", + "", + "", + "", + "AP_SPI_FLASH_MISO", + "AP_SPI_FLASH_CS_L", + "AP_SPI_FLASH_MOSI", + "AP_SPI_FLASH_CLK", + "DA7219_IRQ", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ""; + + ppvarp_lcd_en: ppvarp-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO66__FUNC_GPIO66>; + output-low; + }; + }; + + ppvarn_lcd_en: ppvarn-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO166__FUNC_GPIO166>; + output-low; + }; + }; + + pp1800_lcd_en: pp1800-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO36__FUNC_GPIO36>; + output-low; + }; + }; + + open_touch: open_touch { + irq_pin { + pinmux = <PINMUX_GPIO155__FUNC_GPIO155>; + input-enable; + bias-pull-up; + }; + + rst_pin { + pinmux = <PINMUX_GPIO156__FUNC_GPIO156>; + + /* + * The pen driver doesn't currently support driving + * this reset line. By specifying output-high here + * we're relying on the fact that this pin has a default + * pulldown at boot (which makes sure the pen was in + * reset if it was powered) and then we set it high here + * to take it out of reset. Better would be if the pen + * driver could control this and we could remove + * "output-high" here. + */ + output-high; + }; + }; + + pen_eject: peneject { + pen_eject { + pinmux = <PINMUX_GPIO6__FUNC_GPIO6>; + input-enable; + /* External pull-up. */ + bias-disable; + }; + }; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_KAKADU"; +}; + +&panel { + status = "okay"; + compatible = "boe,tv105wum-nw0"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku16.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku16.dts new file mode 100644 index 0000000000000000000000000000000000000000..e3dd75bdaea4310c86e29a92c52dfb0e2f7781bf --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku16.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + * + * SKU: 0x10 => 16 + * - bit 8: Camera: 0 (OV5695) + * - bits 7..4: Panel ID: 0x1 (AUO) + */ + +/dts-v1/; +#include "mt8183-kukui-kodama.dtsi" + +/ { + model = "MediaTek kodama sku16 board"; + compatible = "google,kodama-sku16", "google,kodama", "mediatek,mt8183"; +}; + +&panel { + status = "okay"; + compatible = "auo,b101uan08.3"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku272.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku272.dts new file mode 100644 index 0000000000000000000000000000000000000000..d81935ae07bc9b8bb6fbc63a3f486e3ac3f6c177 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku272.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2020 Google LLC + * + * SKU: 0x110 => 272 + * - bit 8: Camera: 1 (GC5035) + * - bits 7..4: Panel ID: 0x1 (AUO) + */ + +/dts-v1/; +#include "mt8183-kukui-kodama.dtsi" + +/ { + model = "MediaTek kodama sku272 board"; + compatible = "google,kodama-sku272", "google,kodama", "mediatek,mt8183"; +}; + +&panel { + status = "okay"; + compatible = "auo,b101uan08.3"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku288.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku288.dts new file mode 100644 index 0000000000000000000000000000000000000000..f4082fbe0517a593fcd022cf52a30dc389c5a610 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku288.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2020 Google LLC + * + * SKU: 0x120 => 288 + * - bit 8: Camera: 1 (GC5035) + * - bits 7..4: Panel ID: 0x2 (BOE) + */ + +/dts-v1/; +#include "mt8183-kukui-kodama.dtsi" + +/ { + model = "MediaTek kodama sku288 board"; + compatible = "google,kodama-sku288", "google,kodama", "mediatek,mt8183"; +}; + +&panel { + status = "okay"; + compatible = "boe,tv101wum-n53"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku32.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku32.dts new file mode 100644 index 0000000000000000000000000000000000000000..7739358008ee61443c301c19334b4b4fef1725da --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku32.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + * + * SKU: 0x20 => 32 + * - bit 8: Camera: 0 (OV5695) + * - bits 7..4: Panel ID: 0x2 (BOE) + */ + +/dts-v1/; +#include "mt8183-kukui-kodama.dtsi" + +/ { + model = "MediaTek kodama sku32 board"; + compatible = "google,kodama-sku32", "google,kodama", "mediatek,mt8183"; +}; + +&panel { + status = "okay"; + compatible = "boe,tv101wum-n53"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2f5234a16eadf033b960d399fd969621fcf3f007 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui.dtsi" + +/ { + ppvarn_lcd: ppvarn-lcd { + compatible = "regulator-fixed"; + regulator-name = "ppvarn_lcd"; + pinctrl-names = "default"; + pinctrl-0 = <&ppvarn_lcd_en>; + + enable-active-high; + + gpio = <&pio 66 GPIO_ACTIVE_HIGH>; + }; + + ppvarp_lcd: ppvarp-lcd { + compatible = "regulator-fixed"; + regulator-name = "ppvarp_lcd"; + pinctrl-names = "default"; + pinctrl-0 = <&ppvarp_lcd_en>; + + enable-active-high; + + gpio = <&pio 166 GPIO_ACTIVE_HIGH>; + }; + + pp1800_lcd: pp1800-lcd { + compatible = "regulator-fixed"; + regulator-name = "pp1800_lcd"; + pinctrl-names = "default"; + pinctrl-0 = <&pp1800_lcd_en>; + + enable-active-high; + + gpio = <&pio 36 GPIO_ACTIVE_HIGH>; + }; +}; + +&i2c0 { + status = "okay"; + + touchscreen: touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + interrupt-parent = <&pio>; + interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&touch_default>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; + clock-frequency = <400000>; + + eeprom@58 { + compatible = "atmel,24c64"; + reg = <0x58>; + pagesize = <32>; + }; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins>; + status = "okay"; + clock-frequency = <400000>; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + pagesize = <32>; + }; +}; + +&mt6358_vcama2_reg { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + +&pio { + /* 192 lines */ + gpio-line-names = + "SPI_AP_EC_CS_L", + "SPI_AP_EC_MOSI", + "SPI_AP_EC_CLK", + "I2S3_DO", + "USB_PD_INT_ODL", + "", + "", + "", + "", + "IT6505_HPD_L", + "I2S3_TDM_D3", + "SOC_I2C6_1V8_SCL", + "SOC_I2C6_1V8_SDA", + "DPI_D0", + "DPI_D1", + "DPI_D2", + "DPI_D3", + "DPI_D4", + "DPI_D5", + "DPI_D6", + "DPI_D7", + "DPI_D8", + "DPI_D9", + "DPI_D10", + "DPI_D11", + "DPI_HSYNC", + "DPI_VSYNC", + "DPI_DE", + "DPI_CK", + "AP_MSDC1_CLK", + "AP_MSDC1_DAT3", + "AP_MSDC1_CMD", + "AP_MSDC1_DAT0", + "AP_MSDC1_DAT2", + "AP_MSDC1_DAT1", + "", + "", + "", + "", + "", + "", + "OTG_EN", + "DRVBUS", + "DISP_PWM", + "DSI_TE", + "LCM_RST_1V8", + "AP_CTS_WIFI_RTS", + "AP_RTS_WIFI_CTS", + "SOC_I2C5_1V8_SCL", + "SOC_I2C5_1V8_SDA", + "SOC_I2C3_1V8_SCL", + "SOC_I2C3_1V8_SDA", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "SOC_I2C1_1V8_SDA", + "SOC_I2C0_1V8_SDA", + "SOC_I2C0_1V8_SCL", + "SOC_I2C1_1V8_SCL", + "AP_SPI_H1_MISO", + "AP_SPI_H1_CS_L", + "AP_SPI_H1_MOSI", + "AP_SPI_H1_CLK", + "I2S5_BCK", + "I2S5_LRCK", + "I2S5_DO", + "BOOTBLOCK_EN_L", + "MT8183_KPCOL0", + "SPI_AP_EC_MISO", + "UART_DBG_TX_AP_RX", + "UART_AP_TX_DBG_RX", + "I2S2_MCK", + "I2S2_BCK", + "CLK_5M_WCAM", + "CLK_2M_UCAM", + "I2S2_LRCK", + "I2S2_DI", + "SOC_I2C2_1V8_SCL", + "SOC_I2C2_1V8_SDA", + "SOC_I2C4_1V8_SCL", + "SOC_I2C4_1V8_SDA", + "", + "SCL8", + "SDA8", + "FCAM_PWDN_L", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "I2S_PMIC", + "", + "", + "", + "", + "", + "", + /* + * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics + * call it BIOS_FLASH_WP_R_L. + */ + "AP_FLASH_WP_L", + "EC_AP_INT_ODL", + "IT6505_INT_ODL", + "H1_INT_OD_L", + "", + "", + "", + "", + "", + "", + "", + "AP_SPI_FLASH_MISO", + "AP_SPI_FLASH_CS_L", + "AP_SPI_FLASH_MOSI", + "AP_SPI_FLASH_CLK", + "DA7219_IRQ", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ""; + + ppvarp_lcd_en: ppvarp-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO66__FUNC_GPIO66>; + output-low; + }; + }; + + ppvarn_lcd_en: ppvarn-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO166__FUNC_GPIO166>; + output-low; + }; + }; + + pp1800_lcd_en: pp1800-lcd-en { + pins1 { + pinmux = <PINMUX_GPIO36__FUNC_GPIO36>; + output-low; + }; + }; + + touch_default: touchdefault { + pin_irq { + pinmux = <PINMUX_GPIO155__FUNC_GPIO155>; + input-enable; + bias-pull-up; + }; + + touch_pin_reset: pin_reset { + pinmux = <PINMUX_GPIO156__FUNC_GPIO156>; + + /* + * The touchscreen driver doesn't currently support driving + * this reset line. By specifying output-high here + * we're relying on the fact that this pin has a default + * pulldown at boot (which makes sure the controller was in + * reset if it was powered) and then we set it high here + * to take it out of reset. Better would be if the touchscreen + * driver could control this and we could remove + * "output-high" here. + */ + output-high; + }; + }; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_KODAMA"; +}; + +&i2c_tunnel { + google,remote-bus = <2>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts new file mode 100644 index 0000000000000000000000000000000000000000..0aff5eb52e8876ef8a5f4d9a688a7f9e1ed4b26d --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 BayLibre, SAS. + * Author: Fabien Parent <fparent@baylibre.com> + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include "mt8183.dtsi" +#include "mt6358.dtsi" + +/ { + model = "Pumpkin MT8183"; + compatible = "mediatek,mt8183-pumpkin", "mediatek,mt8183"; + + aliases { + serial0 = &uart0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0 0x40000000 0 0x80000000>; + }; + + chosen { + stdout-path = "serial0:921600n8"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + scp_mem_reserved: scp_mem_region@50000000 { + compatible = "shared-dma-pool"; + reg = <0 0x50000000 0 0x2900000>; + no-map; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-red { + label = "red"; + gpios = <&pio 155 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-green { + label = "green"; + gpios = <&pio 156 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + ntc { + compatible = "murata,ncp03wf104"; + pullup-uv = <1800000>; + pullup-ohm = <390000>; + pulldown-ohm = <0>; + io-channels = <&auxadc 0>; + }; +}; + +&auxadc { + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_0>; + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_1>; + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_2>; + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_3>; + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_4>; + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_5>; + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c6 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_pins>; + status = "okay"; + clock-frequency = <100000>; +}; + +&mmc0 { + status = "okay"; + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_default>; + pinctrl-1 = <&mmc0_pins_uhs>; + bus-width = <8>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + cap-mmc-hw-reset; + no-sdio; + no-sd; + hs400-ds-delay = <0x12814>; + vmmc-supply = <&mt6358_vemc_reg>; + vqmmc-supply = <&mt6358_vio18_reg>; + assigned-clocks = <&topckgen CLK_TOP_MUX_MSDC50_0>; + assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_CK>; + non-removable; +}; + +&mmc1 { + status = "okay"; + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc1_pins_default>; + pinctrl-1 = <&mmc1_pins_uhs>; + bus-width = <4>; + max-frequency = <200000000>; + cap-sd-highspeed; + sd-uhs-sdr50; + sd-uhs-sdr104; + cap-sdio-irq; + no-mmc; + no-sd; + vmmc-supply = <&mt6358_vmch_reg>; + vqmmc-supply = <&mt6358_vmc_reg>; + keep-power-in-suspend; + enable-sdio-wakeup; + non-removable; +}; + +&pio { + i2c_pins_0: i2c0 { + pins_i2c{ + pinmux = <PINMUX_GPIO82__FUNC_SDA0>, + <PINMUX_GPIO83__FUNC_SCL0>; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_1: i2c1 { + pins_i2c{ + pinmux = <PINMUX_GPIO81__FUNC_SDA1>, + <PINMUX_GPIO84__FUNC_SCL1>; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_2: i2c2 { + pins_i2c{ + pinmux = <PINMUX_GPIO103__FUNC_SCL2>, + <PINMUX_GPIO104__FUNC_SDA2>; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_3: i2c3 { + pins_i2c{ + pinmux = <PINMUX_GPIO50__FUNC_SCL3>, + <PINMUX_GPIO51__FUNC_SDA3>; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_4: i2c4 { + pins_i2c{ + pinmux = <PINMUX_GPIO105__FUNC_SCL4>, + <PINMUX_GPIO106__FUNC_SDA4>; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_5: i2c5 { + pins_i2c{ + pinmux = <PINMUX_GPIO48__FUNC_SCL5>, + <PINMUX_GPIO49__FUNC_SDA5>; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c6_pins: i2c6 { + pins_cmd_dat { + pinmux = <PINMUX_GPIO113__FUNC_SCL6>, + <PINMUX_GPIO114__FUNC_SDA6>; + mediatek,pull-up-adv = <3>; + }; + }; + + mmc0_pins_default: mmc0-pins-default { + pins_cmd_dat { + pinmux = <PINMUX_GPIO123__FUNC_MSDC0_DAT0>, + <PINMUX_GPIO128__FUNC_MSDC0_DAT1>, + <PINMUX_GPIO125__FUNC_MSDC0_DAT2>, + <PINMUX_GPIO132__FUNC_MSDC0_DAT3>, + <PINMUX_GPIO126__FUNC_MSDC0_DAT4>, + <PINMUX_GPIO129__FUNC_MSDC0_DAT5>, + <PINMUX_GPIO127__FUNC_MSDC0_DAT6>, + <PINMUX_GPIO130__FUNC_MSDC0_DAT7>, + <PINMUX_GPIO122__FUNC_MSDC0_CMD>; + input-enable; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-up-adv = <01>; + }; + + pins_clk { + pinmux = <PINMUX_GPIO124__FUNC_MSDC0_CLK>; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-down-adv = <10>; + }; + + pins_rst { + pinmux = <PINMUX_GPIO133__FUNC_MSDC0_RSTB>; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-down-adv = <01>; + }; + }; + + mmc0_pins_uhs: mmc0-pins-uhs { + pins_cmd_dat { + pinmux = <PINMUX_GPIO123__FUNC_MSDC0_DAT0>, + <PINMUX_GPIO128__FUNC_MSDC0_DAT1>, + <PINMUX_GPIO125__FUNC_MSDC0_DAT2>, + <PINMUX_GPIO132__FUNC_MSDC0_DAT3>, + <PINMUX_GPIO126__FUNC_MSDC0_DAT4>, + <PINMUX_GPIO129__FUNC_MSDC0_DAT5>, + <PINMUX_GPIO127__FUNC_MSDC0_DAT6>, + <PINMUX_GPIO130__FUNC_MSDC0_DAT7>, + <PINMUX_GPIO122__FUNC_MSDC0_CMD>; + input-enable; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-up-adv = <01>; + }; + + pins_clk { + pinmux = <PINMUX_GPIO124__FUNC_MSDC0_CLK>; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-down-adv = <10>; + }; + + pins_ds { + pinmux = <PINMUX_GPIO131__FUNC_MSDC0_DSL>; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-down-adv = <10>; + }; + + pins_rst { + pinmux = <PINMUX_GPIO133__FUNC_MSDC0_RSTB>; + drive-strength = <MTK_DRIVE_14mA>; + mediatek,pull-up-adv = <01>; + }; + }; + + mmc1_pins_default: mmc1-pins-default { + pins_cmd_dat { + pinmux = <PINMUX_GPIO31__FUNC_MSDC1_CMD>, + <PINMUX_GPIO32__FUNC_MSDC1_DAT0>, + <PINMUX_GPIO34__FUNC_MSDC1_DAT1>, + <PINMUX_GPIO33__FUNC_MSDC1_DAT2>, + <PINMUX_GPIO30__FUNC_MSDC1_DAT3>; + input-enable; + mediatek,pull-up-adv = <10>; + }; + + pins_clk { + pinmux = <PINMUX_GPIO29__FUNC_MSDC1_CLK>; + input-enable; + mediatek,pull-down-adv = <10>; + }; + + pins_pmu { + pinmux = <PINMUX_GPIO178__FUNC_GPIO178>; + output-high; + }; + }; + + mmc1_pins_uhs: mmc1-pins-uhs { + pins_cmd_dat { + pinmux = <PINMUX_GPIO31__FUNC_MSDC1_CMD>, + <PINMUX_GPIO32__FUNC_MSDC1_DAT0>, + <PINMUX_GPIO34__FUNC_MSDC1_DAT1>, + <PINMUX_GPIO33__FUNC_MSDC1_DAT2>, + <PINMUX_GPIO30__FUNC_MSDC1_DAT3>; + drive-strength = <MTK_DRIVE_6mA>; + input-enable; + mediatek,pull-up-adv = <10>; + }; + + pins_clk { + pinmux = <PINMUX_GPIO29__FUNC_MSDC1_CLK>; + drive-strength = <MTK_DRIVE_8mA>; + mediatek,pull-down-adv = <10>; + input-enable; + }; + }; +}; + +&mfg { + domain-supply = <&mt6358_vgpu_reg>; +}; + +&cpu0 { + proc-supply = <&mt6358_vproc12_reg>; +}; + +&cpu1 { + proc-supply = <&mt6358_vproc12_reg>; +}; + +&cpu2 { + proc-supply = <&mt6358_vproc12_reg>; +}; + +&cpu3 { + proc-supply = <&mt6358_vproc12_reg>; +}; + +&cpu4 { + proc-supply = <&mt6358_vproc11_reg>; +}; + +&cpu5 { + proc-supply = <&mt6358_vproc11_reg>; +}; + +&cpu6 { + proc-supply = <&mt6358_vproc11_reg>; +}; + +&cpu7 { + proc-supply = <&mt6358_vproc11_reg>; +}; + +&uart0 { + status = "okay"; +}; + +&scp { + status = "okay"; +}; + +&dsi0 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi index 80519a145f13f9172a674eee604863ad73cda0a4..c5e822b6b77a3fa8856c5411cbc1196ff8d50a73 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi @@ -13,6 +13,7 @@ #include <dt-bindings/power/mt8183-power.h> #include <dt-bindings/reset-controller/mt8183-resets.h> #include <dt-bindings/phy/phy.h> +#include <dt-bindings/thermal/thermal.h> #include "mt8183-pinfunc.h" / { @@ -657,6 +658,142 @@ status = "disabled"; }; + thermal: thermal@1100b000 { + #thermal-sensor-cells = <1>; + compatible = "mediatek,mt8183-thermal"; + reg = <0 0x1100b000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_THERM>, + <&infracfg CLK_INFRA_AUXADC>; + clock-names = "therm", "auxadc"; + resets = <&infracfg MT8183_INFRACFG_AO_THERM_SW_RST>; + interrupts = <0 76 IRQ_TYPE_LEVEL_LOW>; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration>; + nvmem-cell-names = "calibration-data"; + }; + + thermal-zones { + cpu_thermal: cpu_thermal { + polling-delay-passive = <100>; + polling-delay = <500>; + thermal-sensors = <&thermal 0>; + sustainable-power = <5000>; + + trips { + threshold: trip-point0 { + temperature = <68000>; + hysteresis = <2000>; + type = "passive"; + }; + + target: trip-point1 { + temperature = <80000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_crit: cpu-crit { + temperature = <115000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&target>; + 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>; + contribution = <3072>; + }; + map1 { + trip = <&target>; + 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>; + contribution = <1024>; + }; + }; + }; + + /* The tzts1 ~ tzts6 don't need to polling */ + /* The tzts1 ~ tzts6 don't need to thermal throttle */ + + tzts1: tzts1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&thermal 1>; + sustainable-power = <5000>; + trips {}; + cooling-maps {}; + }; + + tzts2: tzts2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&thermal 2>; + sustainable-power = <5000>; + trips {}; + cooling-maps {}; + }; + + tzts3: tzts3 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&thermal 3>; + sustainable-power = <5000>; + trips {}; + cooling-maps {}; + }; + + tzts4: tzts4 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&thermal 4>; + sustainable-power = <5000>; + trips {}; + cooling-maps {}; + }; + + tzts5: tzts5 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&thermal 5>; + sustainable-power = <5000>; + trips {}; + cooling-maps {}; + }; + + tztsABB: tztsABB { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&thermal 6>; + sustainable-power = <5000>; + trips {}; + cooling-maps {}; + }; + }; + pwm0: pwm@1100e000 { compatible = "mediatek,mt8183-disp-pwm"; reg = <0 0x1100e000 0 0x1000>; @@ -874,13 +1011,13 @@ clocks = <&infracfg CLK_INFRA_UNIPRO_SCK>, <&infracfg CLK_INFRA_USB>; clock-names = "sys_ck", "ref_ck"; - mediatek,syscon-wakeup = <&pericfg 0x400 0>; + mediatek,syscon-wakeup = <&pericfg 0x420 101>; #address-cells = <2>; #size-cells = <2>; ranges; status = "disabled"; - usb_host: xhci@11200000 { + usb_host: usb@11200000 { compatible = "mediatek,mt8183-xhci", "mediatek,mtk-xhci"; reg = <0 0x11200000 0 0x1000>; @@ -923,11 +1060,10 @@ status = "disabled"; }; - mipi_tx0: mipi-dphy@11e50000 { + mipi_tx0: dsi-phy@11e50000 { compatible = "mediatek,mt8183-mipi-tx"; reg = <0 0x11e50000 0 0x1000>; clocks = <&apmixedsys CLK_APMIXED_MIPID0_26M>; - clock-names = "ref_clk"; #clock-cells = <0>; #phy-cells = <0>; clock-output-names = "mipi_tx0_pll"; @@ -941,16 +1077,19 @@ reg = <0 0x11f10000 0 0x1000>; #address-cells = <1>; #size-cells = <1>; + thermal_calibration: calib@180 { + reg = <0x180 0xc>; + }; + mipi_tx_calibration: calib@190 { reg = <0x190 0xc>; }; }; - u3phy: usb-phy@11f40000 { + u3phy: t-phy@11f40000 { compatible = "mediatek,mt8183-tphy", "mediatek,generic-tphy-v2"; #address-cells = <1>; - #phy-cells = <1>; #size-cells = <1>; ranges = <0 0 0x11f40000 0x1000>; status = "okay"; @@ -964,7 +1103,7 @@ status = "okay"; }; - u3port0: usb-phy@0700 { + u3port0: usb-phy@700 { reg = <0x0700 0x900>; clocks = <&clk26m>; clock-names = "ref"; @@ -983,6 +1122,9 @@ compatible = "mediatek,mt8183-mmsys", "syscon"; reg = <0 0x14000000 0 0x1000>; #clock-cells = <1>; + mboxes = <&gce 0 CMDQ_THR_PRIO_HIGHEST>, + <&gce 1 CMDQ_THR_PRIO_HIGHEST>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0 0x1000>; }; ovl0: ovl@14008000 { @@ -1058,6 +1200,7 @@ interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_LOW>; power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; clocks = <&mmsys CLK_MM_DISP_CCORR0>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0xf000 0x1000>; }; aal0: aal@14010000 { @@ -1067,6 +1210,7 @@ interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_LOW>; power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; clocks = <&mmsys CLK_MM_DISP_AAL0>; + mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0 0x1000>; }; gamma0: gamma@14011000 { @@ -1075,6 +1219,7 @@ interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_LOW>; power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; clocks = <&mmsys CLK_MM_DISP_GAMMA0>; + mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0x1000 0x1000>; }; dither0: dither@14012000 { @@ -1083,6 +1228,7 @@ interrupts = <GIC_SPI 235 IRQ_TYPE_LEVEL_LOW>; power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; clocks = <&mmsys CLK_MM_DISP_DITHER0>; + mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0x2000 0x1000>; }; dsi0: dsi@14014000 { diff --git a/arch/arm64/boot/dts/mediatek/mt8516.dtsi b/arch/arm64/boot/dts/mediatek/mt8516.dtsi index b80e95574bef8f6b02618b88a789508b79b70d9c..bbe5a1419effcf72872ab2accca76365c60dbb70 100644 --- a/arch/arm64/boot/dts/mediatek/mt8516.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8516.dtsi @@ -480,7 +480,7 @@ }; usb0: usb@11100000 { - compatible = "mediatek,mtk-musb"; + compatible = "mediatek,mt8516-musb", "mediatek,mtk-musb"; reg = <0 0x11100000 0 0x1000>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>; interrupt-names = "mc"; @@ -493,7 +493,7 @@ }; usb1: usb@11190000 { - compatible = "mediatek,mtk-musb"; + compatible = "mediatek,mt8516-musb", "mediatek,mtk-musb"; reg = <0 0x11190000 0 0x1000>; interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_LOW>; interrupt-names = "mc"; @@ -506,8 +506,9 @@ status = "disabled"; }; - usb_phy: usb@11110000 { - compatible = "mediatek,generic-tphy-v1"; + usb_phy: t-phy@11110000 { + compatible = "mediatek,mt8516-tphy", + "mediatek,generic-tphy-v1"; reg = <0 0x11110000 0 0x800>; #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi index 63fd70086bb85ed66b08027a41e0ee8b8fd5ebb6..fcddec14738d83d63d7fd0d629af6b0d0052bcf5 100644 --- a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi +++ b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi @@ -56,7 +56,7 @@ tca6416: gpio@20 { compatible = "ti,tca6416"; reg = <0x20>; - reset-gpios = <&pio 65 GPIO_ACTIVE_HIGH>; + reset-gpios = <&pio 65 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&tca6416_pins>; @@ -188,6 +188,7 @@ &usb0 { status = "okay"; dr_mode = "peripheral"; + usb-role-switch; usb_con: connector { compatible = "usb-c-connector"; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 549a7a2151d455f241f24ba88634a19c59bfbcbe..456502aeee49b69c848208b93b41dd726b567bf9 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -27,10 +27,16 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8998-asus-novago-tp370ql.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-hp-envy-x2.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-lenovo-miix-630.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8998-oneplus-cheeseburger.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8998-oneplus-dumpling.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb5165-rb5.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-idp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r1.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r1-lte.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r2.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r2-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r0.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r1-kb.dtb @@ -38,8 +44,16 @@ dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r1-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r3.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r3-kb.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r3-lte.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-limozeen.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-limozeen-nots.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-limozeen-nots-r4.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r1.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r1-lte.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r2.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r2-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-r1-lte.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7280-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm630-sony-xperia-ganges-kirin.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm630-sony-xperia-nile-discovery.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm630-sony-xperia-nile-pioneer.dtb @@ -59,4 +73,5 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8150-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8150-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8350-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-mtp.dtb diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts index 48bd1c2874dead4e4d0d95f8b9be5f5af8e6353f..f3c0dbfd0a232b20368f65bb74d71bb3a5599794 100644 --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts @@ -9,5 +9,5 @@ / { model = "Qualcomm Technologies, Inc. APQ 8016 SBC"; - compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc"; + compatible = "qcom,apq8016-sbc", "qcom,apq8016"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 5353da521974b5b1ffebf982e339ed19814b2e4a..4f06c0a9c425204485351719779c8c91968d9a73 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -25,10 +25,10 @@ chosen { }; - memory { + memory@80000000 { device_type = "memory"; /* We expect the bootloader to fill in the reg */ - reg = <0 0 0 0>; + reg = <0 0x80000000 0 0>; }; reserved-memory { @@ -1766,7 +1766,9 @@ compatible = "qcom,msm-qgic2"; interrupt-controller; #interrupt-cells = <3>; - reg = <0x0b000000 0x1000>, <0x0b002000 0x1000>; + reg = <0x0b000000 0x1000>, <0x0b002000 0x2000>, + <0x0b001000 0x1000>, <0x0b004000 0x2000>; + interrupts = <GIC_PPI 0 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; }; apcs: mailbox@b011000 { diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi index f49d442d2edf3236c79855d26160d247e82e3226..f9f0b5aa6a266d3694d48b82d9804c9aca0ccc52 100644 --- a/arch/arm64/boot/dts/qcom/msm8994.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi @@ -149,10 +149,10 @@ }; }; - memory { + memory@80000000 { device_type = "memory"; /* We expect the bootloader to fill in the reg */ - reg = <0 0 0 0>; + reg = <0 0x80000000 0 0>; }; tcsr_mutex: hwlock { diff --git a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi index b500f24d47bc3beaba6725bc2b9eeb6b354cccd2..125d7923d713173acafe2a78e03b3257d4d3af8f 100644 --- a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi @@ -281,6 +281,10 @@ }; }; +&remoteproc_mss { + status = "okay"; +}; + &tlmm { gpio-reserved-ranges = <0 4>, <81 4>; diff --git a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi index c1ef0c71d5f59056f0e8be1b4a335c2f064b9f9f..a1d15eab8553eb81d97dd1cd8aeb5a50371d4a92 100644 --- a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi @@ -328,6 +328,10 @@ status = "okay"; }; +&remoteproc_mss { + status = "okay"; +}; + &remoteproc_slpi { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts b/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts new file mode 100644 index 0000000000000000000000000000000000000000..66b9297588ab53aaf79113318631444496ce4c58 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * OnePlus 5 (cheeseburger) device tree + * + * Copyright (c) 2021, Jami Kettunen <jamipkettunen@gmail.com> + */ + +#include <dt-bindings/leds/common.h> +#include "msm8998-oneplus-common.dtsi" + +/ { + model = "OnePlus 5"; + compatible = "oneplus,cheeseburger", "qcom,msm8998"; + /* Required for bootloader to select correct board */ + qcom,board-id = <8 0 16859 23>; + + /* Capacitive keypad button backlight */ + leds { + compatible = "gpio-leds"; + + pinctrl-names = "default"; + pinctrl-0 = <&button_backlight_default>; + + button-backlight { + gpios = <&pmi8998_gpio 5 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_WHITE>; + function = LED_FUNCTION_KBD_BACKLIGHT; + default-state = "off"; + }; + }; +}; + +&pmi8998_gpio { + button_backlight_default: button-backlight-default { + pinconf { + pins = "gpio5"; + function = "normal"; + bias-pull-down; + qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0f5c7828a901d986a96685753ac6ca9982568c5a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * OnePlus 5(T) (cheeseburger / dumpling) common device tree source based on msm8998-mtp.dtsi + * + * Copyright (c) 2021, Jami Kettunen <jamipkettunen@gmail.com> + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/pinctrl/qcom,pmic-gpio.h> +#include "msm8998.dtsi" +#include "pm8998.dtsi" +#include "pmi8998.dtsi" +#include "pm8005.dtsi" + +/ { + /* Required for bootloader to select correct board */ + qcom,msm-id = <292 0x20001>; /* 8998 v2.1 */ + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* Use display framebuffer setup by the UEFI XBL bootloader for simplefb */ + framebuffer0: framebuffer@9d400000 { + compatible = "simple-framebuffer"; + reg = <0x0 0x9d400000 0x0 0x2400000>; + width = <1080>; + height = <1920>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + }; + }; + + reserved-memory { + /* Bootloader display framebuffer region */ + cont_splash_mem: memory@9d400000 { + reg = <0x0 0x9d400000 0x0 0x2400000>; + no-map; + }; + + /* For getting crash logs using Android downstream kernels */ + ramoops@ac000000 { + compatible = "ramoops"; + reg = <0x0 0xac000000 0x0 0x200000>; + console-size = <0x80000>; + pmsg-size = <0x40000>; + record-size = <0x8000>; + ftrace-size = <0x20000>; + }; + + /* + * The following memory regions on downstream are "dynamically allocated" + * but given the same addresses every time. Hard code them as these addresses + * are where the OnePlus signed firmware expects them to be. + */ + ipa_fws_region: ipa@f6800000 { + compatible = "shared-dma-pool"; + reg = <0x0 0xf6800000 0x0 0x5000>; + no-map; + }; + zap_shader_region: gpu@f6900000 { + compatible = "shared-dma-pool"; + reg = <0x0 0xf6900000 0x0 0x2000>; + no-map; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + label = "Volume buttons"; + autorepeat; + + pinctrl-names = "default"; + pinctrl-0 = <&vol_keys_default>; + + vol-down { + label = "Volume down"; + gpios = <&pm8998_gpio 5 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEDOWN>; + debounce-interval = <15>; + wakeup-source; + }; + + vol-up { + label = "Volume up"; + gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + debounce-interval = <15>; + wakeup-source; + }; + }; + + gpio-hall-sensor { + compatible = "gpio-keys"; + label = "Hall effect sensor"; + + pinctrl-names = "default"; + pinctrl-0 = <&hall_sensor_default>; + + hall-sensor { + label = "Hall Effect Sensor"; + gpios = <&tlmm 124 GPIO_ACTIVE_LOW>; + linux,input-type = <EV_SW>; + linux,code = <SW_LID>; + linux,can-disable; + wakeup-source; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-always-on; + regulator-boot-on; + }; +}; + +/* + * OnePlus' ADSP firmware requires 30 MiB in total, so increase the adsp_mem + * region by 4 MiB to account for this while relocating the other now + * conflicting memory nodes accordingly. + */ +&adsp_mem { + reg = <0x0 0x8b200000 0x0 0x1e00000>; +}; +&mpss_mem { + reg = <0x0 0x8d000000 0x0 0x7000000>; +}; +&venus_mem { + reg = <0x0 0x94000000 0x0 0x500000>; +}; +&mba_mem { + reg = <0x0 0x94500000 0x0 0x200000>; +}; +&slpi_mem { + reg = <0x0 0x94700000 0x0 0xf00000>; +}; +&ipa_fw_mem { + reg = <0x0 0x95600000 0x0 0x10000>; +}; +&ipa_gsi_mem { + reg = <0x0 0x95610000 0x0 0x5000>; +}; +&gpu_mem { + reg = <0x0 0x95615000 0x0 0x100000>; +}; +&wlan_msa_mem { + reg = <0x0 0x95715000 0x0 0x100000>; +}; + +&blsp1_i2c5 { + status = "okay"; + + touchscreen@20 { + compatible = "syna,rmi4-i2c"; + reg = <0x20>; + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&tlmm>; + interrupts = <125 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + + vdd-supply = <&vreg_l28_3p0>; + vio-supply = <&vreg_l6a_1p8>; + + syna,reset-delay-ms = <20>; + syna,startup-delay-ms = <20>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4_f12: rmi4-f12@12 { + reg = <0x12>; + syna,rezero-wait-ms = <20>; + syna,sensor-type = <1>; + touchscreen-x-mm = <68>; + touchscreen-y-mm = <122>; + }; + }; +}; + +&blsp1_uart3 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3990-bt"; + + vddio-supply = <&vreg_s4a_1p8>; + vddxo-supply = <&vreg_l7a_1p8>; + vddrf-supply = <&vreg_l17a_1p3>; + vddch0-supply = <&vreg_l25a_3p3>; + max-speed = <3200000>; + }; +}; + +&blsp1_uart3_on { + rx { + /delete-property/ bias-disable; + /* + * Configure a pull-up on 46 (RX). This is needed to + * avoid garbage data when the TX pin of the Bluetooth + * module is in tri-state (module powered off or not + * driving the signal yet). + */ + bias-pull-up; + }; + + cts { + /delete-property/ bias-disable; + /* + * Configure a pull-down on 47 (CTS) to match the pull + * of the Bluetooth module. + */ + bias-pull-down; + }; +}; + +&blsp2_uart1 { + status = "okay"; +}; + +&pm8005_lsid1 { + pm8005-regulators { + compatible = "qcom,pm8005-regulators"; + + vdd_s1-supply = <&vph_pwr>; + + pm8005_s1: s1 { /* VDD_GFX supply */ + regulator-min-microvolt = <524000>; + regulator-max-microvolt = <1100000>; + regulator-enable-ramp-delay = <500>; + + /* hack until we rig up the gpu consumer */ + regulator-always-on; + }; + }; +}; + +&pm8998_gpio { + vol_keys_default: vol-keys-default { + pinconf { + pins = "gpio5", "gpio6"; + function = "normal"; + bias-pull-up; + input-enable; + qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>; + }; + }; +}; + +&qusb2phy { + status = "okay"; + + vdda-pll-supply = <&vreg_l12a_1p8>; + vdda-phy-dpdm-supply = <&vreg_l24a_3p075>; +}; + +&rpm_requests { + pm8998-regulators { + compatible = "qcom,rpm-pm8998-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3-supply = <&vph_pwr>; + vdd_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + vdd_s7-supply = <&vph_pwr>; + vdd_s8-supply = <&vph_pwr>; + vdd_s9-supply = <&vph_pwr>; + vdd_s10-supply = <&vph_pwr>; + vdd_s11-supply = <&vph_pwr>; + vdd_s12-supply = <&vph_pwr>; + vdd_s13-supply = <&vph_pwr>; + vdd_l1_l27-supply = <&vreg_s7a_1p025>; + vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>; + vdd_l3_l11-supply = <&vreg_s7a_1p025>; + vdd_l4_l5-supply = <&vreg_s7a_1p025>; + vdd_l6-supply = <&vreg_s5a_2p04>; + vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>; + vdd_l9-supply = <&vreg_bob>; + vdd_l10_l23_l25-supply = <&vreg_bob>; + vdd_l13_l19_l21-supply = <&vreg_bob>; + vdd_l16_l28-supply = <&vreg_bob>; + vdd_l18_l22-supply = <&vreg_bob>; + vdd_l20_l24-supply = <&vreg_bob>; + vdd_l26-supply = <&vreg_s3a_1p35>; + vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>; + + vreg_s3a_1p35: s3 { + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + }; + vreg_s4a_1p8: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-allow-set-load; + }; + vreg_s5a_2p04: s5 { + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2040000>; + }; + vreg_s7a_1p025: s7 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1028000>; + }; + vreg_l1a_0p875: l1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + }; + vreg_l2a_1p2: l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + vreg_l3a_1p0: l3 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + vreg_l5a_0p8: l5 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + }; + vreg_l6a_1p8: l6 { + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <1808000>; + }; + vreg_l7a_1p8: l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + vreg_l8a_1p2: l8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + vreg_l9a_1p8: l9 { + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <2960000>; + }; + vreg_l10a_1p8: l10 { + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <2960000>; + }; + vreg_l11a_1p0: l11 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + vreg_l12a_1p8: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + vreg_l13a_2p95: l13 { + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <2960000>; + }; + vreg_l14a_1p88: l14 { + regulator-min-microvolt = <1880000>; + regulator-max-microvolt = <1880000>; + }; + vreg_l15a_1p8: l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + vreg_l16a_2p7: l16 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + }; + vreg_l17a_1p3: l17 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + }; + vreg_l18a_2p7: l18 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + }; + vreg_l19a_3p0: l19 { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + }; + vreg_l20a_2p95: l20 { + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-allow-set-load; + }; + vreg_l21a_2p95: l21 { + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-allow-set-load; + regulator-system-load = <800000>; + }; + vreg_l22a_2p85: l22 { + regulator-min-microvolt = <2864000>; + regulator-max-microvolt = <2864000>; + }; + vreg_l23a_3p3: l23 { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; + }; + vreg_l24a_3p075: l24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + }; + vreg_l25a_3p3: l25 { + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3312000>; + }; + vreg_l26a_1p2: l26 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-allow-set-load; + }; + vreg_l28_3p0: l28 { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + }; + vreg_lvs1a_1p8: lvs1 { }; + vreg_lvs2a_1p8: lvs2 { }; + }; + + pmi8998-regulators { + compatible = "qcom,rpm-pmi8998-regulators"; + + vdd_bob-supply = <&vph_pwr>; + + vreg_bob: bob { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3600000>; + }; + }; +}; + +&tlmm { + gpio-reserved-ranges = <0 4>, <81 4>; + + hall_sensor_default: hall-sensor-default { + pins = "gpio124"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + + ts_int_active: ts-int-active { + pins = "gpio125"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; + + ts_reset_active: ts-reset-active { + pins = "gpio89"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; +}; + +&ufshc { + status = "okay"; + + vcc-supply = <&vreg_l20a_2p95>; + vccq-supply = <&vreg_l26a_1p2>; + vccq2-supply = <&vreg_s4a_1p8>; + vcc-max-microamp = <750000>; + vccq-max-microamp = <560000>; + vccq2-max-microamp = <750000>; +}; + +&ufsphy { + status = "okay"; + + vdda-phy-supply = <&vreg_l1a_0p875>; + vdda-pll-supply = <&vreg_l2a_1p2>; + vddp-ref-clk-supply = <&vreg_l26a_1p2>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14600>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; +}; + +&usb3 { + status = "okay"; + + /* Disable USB3 clock requirement as the device only supports USB2 */ + qcom,select-utmi-as-pipe-clk; +}; + +&usb3_dwc3 { + /* Drop the unused USB 3 PHY */ + phys = <&qusb2phy>; + phy-names = "usb2-phy"; + + /* Fastest mode for USB 2 */ + maximum-speed = "high-speed"; + + /* Force to peripheral until we can switch modes */ + dr_mode = "peripheral"; +}; + +&wifi { + /* Leave disabled until MSS is functional */ + vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>; + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998-oneplus-dumpling.dts b/arch/arm64/boot/dts/qcom/msm8998-oneplus-dumpling.dts new file mode 100644 index 0000000000000000000000000000000000000000..544b9b0ae44bb365f99a8a90428860c33e5bf09c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-oneplus-dumpling.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * OnePlus 5T (dumpling) device tree + * + * Copyright (c) 2021, Jami Kettunen <jamipkettunen@gmail.com> + */ + +#include "msm8998-oneplus-common.dtsi" + +/ { + model = "OnePlus 5T"; + compatible = "oneplus,dumpling", "qcom,msm8998"; + /* Required for bootloader to select correct board */ + qcom,board-id = <8 0 17801 43>; +}; + +/* Update the screen height values from 1920 to 2160 on the 5T */ +&framebuffer0 { + height = <2160>; +}; + +/* Adjust digitizer area height to match the 5T's taller panel */ +&rmi4_f12 { + touchscreen-y-mm = <137>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index 1f2e93aa6553c5bbcce6b07df76c14389477a768..e9d3ce29937c4e01189cde089f98892f9b09dc8a 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -1398,6 +1398,8 @@ <&rpmpd MSM8998_VDDMX>; power-domain-names = "cx", "mx"; + status = "disabled"; + mba { memory-region = <&mba_mem>; }; diff --git a/arch/arm64/boot/dts/qcom/pm8150.dtsi b/arch/arm64/boot/dts/qcom/pm8150.dtsi index bdc76d504b78f6c5846500e2e9af941be5f6f49d..fa4ea7ded0ab9de152cbb771c270b351073d1280 100644 --- a/arch/arm64/boot/dts/qcom/pm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150.dtsi @@ -107,13 +107,11 @@ status = "disabled"; }; - pm8150_rtc: rtc@6000 { + rtc@6000 { compatible = "qcom,pm8941-rtc"; reg = <0x6000>; reg-names = "rtc", "alarm"; interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; - - status = "disabled"; }; pm8150_gpios: gpio@c000 { diff --git a/arch/arm64/boot/dts/qcom/pm8350.dtsi b/arch/arm64/boot/dts/qcom/pm8350.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..308f9ca7c744bad092e4c0e1feac1c7da8036605 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8350.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/spmi/spmi.h> + +&spmi_bus { + pm8350: pmic@1 { + compatible = "qcom,pm8350", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm8350_gpios: gpio@8800 { + compatible = "qcom,pm8350-gpio"; + reg = <0x8800>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8350b.dtsi b/arch/arm64/boot/dts/qcom/pm8350b.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b23bb1d49a4d7a499a5620e4df2e920f3960f1a7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8350b.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/spmi/spmi.h> + +&spmi_bus { + pm8350b: pmic@3 { + compatible = "qcom,pm8350b", "qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm8350b_gpios: gpio@8800 { + compatible = "qcom,pm8350b-gpio"; + reg = <0x8800>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8350c.dtsi b/arch/arm64/boot/dts/qcom/pm8350c.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2b9b75ecec600cea767c25edf066f4d34f6e183e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8350c.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/spmi/spmi.h> + +&spmi_bus { + pm8350c: pmic@2 { + compatible = "qcom,pm8350c", "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm8350c_gpios: gpio@8800 { + compatible = "qcom,pm8350c-gpio"; + reg = <0x8800>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/qcom/pmk8350.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1530b8ff270f7a55292b79643fccb8a5dc5f3da0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmk8350.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/spmi/spmi.h> + +&spmi_bus { + pmk8350: pmic@0 { + compatible = "qcom,pmk8350", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmk8350_gpios: gpio@b000 { + compatible = "qcom,pmk8350-gpio"; + reg = <0xb000>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmr735a.dtsi b/arch/arm64/boot/dts/qcom/pmr735a.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1c675af13cbfca62f491663157e7ad4564022c67 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmr735a.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/spmi/spmi.h> + +&spmi_bus { + pmr735a: pmic@4 { + compatible = "qcom,pmr735a", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmr735a_gpios: gpio@8800 { + compatible = "qcom,pmr735a-gpio"; + reg = <0x8800>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmr735b.dtsi b/arch/arm64/boot/dts/qcom/pmr735b.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1144086280f55e1035256508e88c0990ada8193e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmr735b.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/spmi/spmi.h> + +&spmi_bus { + pmr735b: pmic@5 { + compatible = "qcom,pmr735b", "qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmr735b_gpios: gpio@8800 { + compatible = "qcom,pmr735b-gpio"; + reg = <0x8800>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 2f0528d012993571967d5ab9465ab5405321f6f4..5f41de20aa22d6294017abf48686b08a236e9c13 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -811,10 +811,6 @@ }; }; -&pm8150_rtc { - status = "okay"; -}; - &qupv3_id_0 { status = "okay"; }; @@ -952,6 +948,9 @@ /* CAN */ &spi0 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs_gpio>; + cs-gpios = <&tlmm 31 GPIO_ACTIVE_LOW>; can@0 { compatible = "microchip,mcp2518fd"; @@ -1352,3 +1351,14 @@ vdd-micb-supply = <&vreg_s4a_1p8>; qcom,dmic-sample-rate = <600000>; }; + +/* PINCTRL - additions to nodes defined in sm8250.dtsi */ +&qup_spi0_cs_gpio { + drive-strength = <6>; + bias-disable; +}; + +&qup_spi0_data_clk { + drive-strength = <6>; + bias-disable; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts new file mode 100644 index 0000000000000000000000000000000000000000..533c048903ea10fb594ff115e4b2b1818f5578e2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google CoachZ board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180-trogdor-coachz-r1.dts" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google CoachZ (rev1) with LTE"; + compatible = "google,coachz-rev1-sku0", "qcom,sc7180"; +}; + +&cros_ec_proximity { + label = "proximity-wifi-lte"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts new file mode 100644 index 0000000000000000000000000000000000000000..1b1dbdb2a82f2d301888a060cf18c61230ff29ed --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google CoachZ board device tree source + * + * Copyright 2020 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-coachz.dtsi" + +/ { + model = "Google CoachZ (rev1)"; + compatible = "google,coachz-rev1", "qcom,sc7180"; +}; + +&tlmm { + gpio-line-names = "HUB_RST_L", + "AP_RAM_ID0", + "AP_SKU_ID2", + "AP_RAM_ID1", + "FP_TO_AP_IRQ_L", + "AP_RAM_ID2", + "UF_CAM_EN", + "WF_CAM_EN", + "TS_RESET_L", + "TS_INT_L", + "FPMCU_BOOT0", + "EDP_BRIJ_IRQ", + "AP_EDP_BKLTEN", + "UF_CAM_MCLK", + "WF_CAM_CLK", + "EDP_BRIJ_I2C_SDA", + "EDP_BRIJ_I2C_SCL", + "UF_CAM_SDA", + "UF_CAM_SCL", + "WF_CAM_SDA", + "WF_CAM_SCL", + "WLC_IRQ", + "FP_RST_L", + "AMP_EN", + "WLC_NRST", + "AP_SAR_SENSOR_SDA", + "AP_SAR_SENSOR_SCL", + "", + "", + "WF_CAM_RST_L", + "UF_CAM_RST_L", + "AP_BRD_ID2", + "BRIJ_SUSPEND", + "AP_BRD_ID0", + "AP_H1_SPI_MISO", + "AP_H1_SPI_MOSI", + "AP_H1_SPI_CLK", + "AP_H1_SPI_CS_L", + "", + "", + "", + "", + "H1_AP_INT_ODL", + "", + "UART_AP_TX_DBG_RX", + "UART_DBG_TX_AP_RX", + "", + "", + "FORCED_USB_BOOT", + "AMP_BCLK", + "AMP_LRCLK", + "AMP_DIN", + "EN_PP3300_DX_EDP", + "HP_BCLK", + "HP_LRCLK", + "HP_DOUT", + "HP_DIN", + "HP_MCLK", + "AP_SKU_ID0", + "AP_EC_SPI_MISO", + "AP_EC_SPI_MOSI", + "AP_EC_SPI_CLK", + "AP_EC_SPI_CS_L", + "AP_SPI_CLK", + "AP_SPI_MOSI", + "AP_SPI_MISO", + /* + * AP_FLASH_WP_L is crossystem ABI. Schematics + * call it BIOS_FLASH_WP_L. + */ + "AP_FLASH_WP_L", + "", + "AP_SPI_CS0_L", + "SD_CD_ODL", + "", + "", + "", + "", + "FPMCU_SEL", + "UIM2_DATA", + "UIM2_CLK", + "UIM2_RST", + "UIM2_PRESENT_L", + "UIM1_DATA", + "UIM1_CLK", + "UIM1_RST", + "", + "DMIC_CLK_EN", + "HUB_EN", + "", + "AP_SPI_FP_MISO", + "AP_SPI_FP_MOSI", + "AP_SPI_FP_CLK", + "AP_SPI_FP_CS_L", + "AP_SKU_ID1", + "AP_RST_REQ", + "", + "AP_BRD_ID1", + "AP_EC_INT_L", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "EDP_BRIJ_EN", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "AP_TS_PEN_I2C_SDA", + "AP_TS_PEN_I2C_SCL", + "DP_HOT_PLUG_DET", + "EC_IN_RW_ODL"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2-lte.dts new file mode 100644 index 0000000000000000000000000000000000000000..6e7745801faeba6294963c411950f9e581106e69 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2-lte.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google CoachZ board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180-trogdor-coachz-r2.dts" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google CoachZ (rev2+) with LTE"; + compatible = "google,coachz-sku0", "qcom,sc7180"; +}; + +&cros_ec_proximity { + label = "proximity-wifi-lte"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2.dts new file mode 100644 index 0000000000000000000000000000000000000000..4f69b6ba299f1ab751c205a3458997574f82fd3e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google CoachZ board device tree source + * + * Copyright 2020 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-coachz.dtsi" + +/ { + model = "Google CoachZ (rev2+)"; + compatible = "google,coachz", "qcom,sc7180"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4c6e433c8226a3dd7a422eca5fa45d8ee3aa4675 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google CoachZ board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180.dtsi" + +ap_ec_spi: &spi6 {}; +ap_h1_spi: &spi0 {}; + +#include "sc7180-trogdor.dtsi" + +/* Deleted nodes from trogdor.dtsi */ + +/delete-node/ &alc5682; +/delete-node/ &pp3300_codec; + +/ { + /* BOARD-SPECIFIC TOP LEVEL NODES */ + + adau7002: audio-codec-1 { + compatible = "adi,adau7002"; + IOVDD-supply = <&pp1800_l15a>; + #sound-dai-cells = <0>; + }; +}; + +&ap_spi_fp { + status = "okay"; +}; + +&backlight { + pwms = <&cros_ec_pwm 0>; +}; + +&camcc { + status = "okay"; +}; + +&cros_ec { + cros_ec_proximity: proximity { + compatible = "google,cros-ec-mkbp-proximity"; + label = "proximity-wifi"; + }; +}; + +ap_ts_pen_1v8: &i2c4 { + status = "okay"; + clock-frequency = <400000>; + + ap_ts: touchscreen@5d { + compatible = "goodix,gt7375p"; + reg = <0x5d>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_l>, <&ts_reset_l>; + + interrupt-parent = <&tlmm>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>; + + vdd-supply = <&pp3300_ts>; + }; +}; + +&i2c7 { + status = "disabled"; +}; + +&i2c9 { + status = "disabled"; +}; + +&panel { + compatible = "boe,nv110wtm-n61"; +}; + +&pp3300_dx_edp { + gpio = <&tlmm 67 GPIO_ACTIVE_HIGH>; +}; + +&sdhc_2 { + status = "okay"; +}; + +&sn65dsi86_out { + data-lanes = <0 1 2 3>; +}; + +&sound { + compatible = "google,sc7180-coachz"; + model = "sc7180-adau7002-max98357a"; + audio-routing = "PDM_DAT", "DMIC"; + + pinctrl-names = "default"; + pinctrl-0 = <&dmic_clk_en>; +}; + +&sound_multimedia0_codec { + sound-dai = <&adau7002>; +}; + +/* PINCTRL - modifications to sc7180-trogdor.dtsi */ + +&en_pp3300_dx_edp { + pinmux { + pins = "gpio67"; + }; + + pinconf { + pins = "gpio67"; + }; +}; + +&ts_reset_l { + pinconf { + /* + * We want reset state by default and it will be up to the + * driver to disable this when it's ready. + */ + output-low; + }; +}; + +/* PINCTRL - board-specific pinctrl */ + +&tlmm { + gpio-line-names = "HUB_RST_L", + "AP_RAM_ID0", + "AP_SKU_ID2", + "AP_RAM_ID1", + "FP_TO_AP_IRQ_L", + "AP_RAM_ID2", + "UF_CAM_EN", + "WF_CAM_EN", + "TS_RESET_L", + "TS_INT_L", + "FPMCU_BOOT0", + "EDP_BRIJ_IRQ", + "AP_EDP_BKLTEN", + "UF_CAM_MCLK", + "WF_CAM_CLK", + "EDP_BRIJ_I2C_SDA", + "EDP_BRIJ_I2C_SCL", + "UF_CAM_SDA", + "UF_CAM_SCL", + "WF_CAM_SDA", + "WF_CAM_SCL", + "WLC_IRQ", + "FP_RST_L", + "AMP_EN", + "WLC_NRST", + "AP_SAR_SENSOR_SDA", + "AP_SAR_SENSOR_SCL", + "", + "", + "WF_CAM_RST_L", + "UF_CAM_RST_L", + "AP_BRD_ID2", + "BRIJ_SUSPEND", + "AP_BRD_ID0", + "AP_H1_SPI_MISO", + "AP_H1_SPI_MOSI", + "AP_H1_SPI_CLK", + "AP_H1_SPI_CS_L", + "", + "", + "", + "", + "H1_AP_INT_ODL", + "", + "UART_AP_TX_DBG_RX", + "UART_DBG_TX_AP_RX", + "", + "", + "FORCED_USB_BOOT", + "AMP_BCLK", + "AMP_LRCLK", + "AMP_DIN", + "", + "HP_BCLK", + "HP_LRCLK", + "HP_DOUT", + "HP_DIN", + "HP_MCLK", + "AP_SKU_ID0", + "AP_EC_SPI_MISO", + "AP_EC_SPI_MOSI", + "AP_EC_SPI_CLK", + "AP_EC_SPI_CS_L", + "AP_SPI_CLK", + "AP_SPI_MOSI", + "AP_SPI_MISO", + /* + * AP_FLASH_WP_L is crossystem ABI. Schematics + * call it BIOS_FLASH_WP_L. + */ + "AP_FLASH_WP_L", + "EN_PP3300_DX_EDP", + "AP_SPI_CS0_L", + "SD_CD_ODL", + "", + "", + "", + "", + "EN_FP_RAILS", + "UIM2_DATA", + "UIM2_CLK", + "UIM2_RST", + "UIM2_PRESENT_L", + "UIM1_DATA", + "UIM1_CLK", + "UIM1_RST", + "", + "", + "HUB_EN", + "", + "AP_SPI_FP_MISO", + "AP_SPI_FP_MOSI", + "AP_SPI_FP_CLK", + "AP_SPI_FP_CS_L", + "AP_SKU_ID1", + "AP_RST_REQ", + "", + "AP_BRD_ID1", + "AP_EC_INT_L", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "EDP_BRIJ_EN", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "AP_TS_PEN_I2C_SDA", + "AP_TS_PEN_I2C_SCL", + "DP_HOT_PLUG_DET", + "EC_IN_RW_ODL"; + + dmic_clk_en: dmic_clk_en { + pinmux { + pins = "gpio83"; + function = "gpio"; + }; + + pinconf { + pins = "gpio83"; + drive-strength = <8>; + bias-pull-up; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots-r4.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots-r4.dts new file mode 100644 index 0000000000000000000000000000000000000000..6ebde0828550c0705da4d11878a3066286e593f0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots-r4.dts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Lazor Limozeen board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180-trogdor-lazor-limozeen-nots.dts" + +/ { + model = "Google Lazor Limozeen without Touchscreen (rev4)"; + compatible = "google,lazor-rev4-sku5", "qcom,sc7180"; +}; + +/* + * rev4-sku5 was built with a different trackpad. + */ +/delete-node/&trackpad; +&ap_tp_i2c { + trackpad: trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + pinctrl-names = "default"; + pinctrl-0 = <&tp_int_odl>; + + interrupt-parent = <&tlmm>; + interrupts = <58 IRQ_TYPE_EDGE_FALLING>; + + vcc-supply = <&pp3300_fp_tp>; + hid-descr-addr = <0x20>; + + wakeup-source; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots.dts new file mode 100644 index 0000000000000000000000000000000000000000..0456c7e05d0079b70edd2deb754b84c1e45fb1a8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots.dts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Lazor Limozeen board device tree source + * + * Copyright 2020 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-lazor.dtsi" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google Lazor Limozeen without Touchscreen"; + compatible = "google,lazor-sku6", "google,lazor-sku5", "qcom,sc7180"; +}; + +/delete-node/&ap_ts; + +&panel { + compatible = "innolux,n116bca-ea1", "innolux,n116bge"; +}; + +&sdhc_2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen.dts new file mode 100644 index 0000000000000000000000000000000000000000..e6ad6dae4e6039380a61dbec08d1488ed9e2ee1f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Lazor Limozeen board device tree source + * + * Copyright 2020 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-lazor.dtsi" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google Lazor Limozeen"; + compatible = "google,lazor-sku4", "qcom,sc7180"; +}; + +/delete-node/&ap_ts; + +&ap_ts_pen_1v8 { + ap_ts: touchscreen@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_l>, <&ts_reset_l>; + + interrupt-parent = <&tlmm>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + + vcc33-supply = <&pp3300_ts>; + + reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>; + }; +}; + +&panel { + compatible = "auo,b116xa01"; +}; + +&sdhc_2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts index 30e3e769d2b4f7644090da755e7d7a1a6d58dc69..5c997cd9006973bb9555e30df41d405c66ff591a 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts @@ -14,6 +14,15 @@ compatible = "google,lazor-rev0", "qcom,sc7180"; }; +/* + * Lazor is stuffed with a 47k NTC as charger thermistor which currently is + * not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; +}; + &pp3300_hub { /* pp3300_l7c is used to power the USB hub */ /delete-property/regulator-always-on; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts index c2ef06367baf729819cdceb62822ad673c7a7dd6..d9fbcc7bc5bd48db1c10ecab94e318b83f1aa490 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts @@ -14,6 +14,15 @@ compatible = "google,lazor-rev1", "google,lazor-rev2", "qcom,sc7180"; }; +/* + * Lazor is stuffed with a 47k NTC as charger thermistor which currently is + * not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; +}; + &pp3300_hub { /* pp3300_l7c is used to power the USB hub */ /delete-property/regulator-always-on; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-kb.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-kb.dts index 6985beb97e53e89f25db8e917a1919d36d0cb64d..dcb41afdc82a69664832c163b3f6a90db35788f0 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-kb.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-kb.dts @@ -5,7 +5,10 @@ * Copyright 2020 Google LLC. */ -#include "sc7180-trogdor-lazor-r3.dts" +/dts-v1/; + +#include "sc7180-trogdor-lazor.dtsi" +#include "sc7180-lite.dtsi" / { model = "Google Lazor (rev3+) with KB Backlight"; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-lte.dts index 0881f8dd02c95c20b26f913b8012b7ff5a64814b..be44900602d7493a9a92e9dce32058cf4c44ac14 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-lte.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3-lte.dts @@ -5,7 +5,9 @@ * Copyright 2020 Google LLC. */ -#include "sc7180-trogdor-lazor-r3.dts" +/dts-v1/; + +#include "sc7180-trogdor-lazor.dtsi" #include "sc7180-trogdor-lte-sku.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts index 1b9d2f46359e438a897d7cc55e85dfbf7c3f03a1..ea8c2ee097416bd87294a104510495b4c2e388dc 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts @@ -8,8 +8,18 @@ /dts-v1/; #include "sc7180-trogdor-lazor.dtsi" +#include "sc7180-lite.dtsi" / { model = "Google Lazor (rev3+)"; compatible = "google,lazor", "qcom,sc7180"; }; + +/* + * Lazor is stuffed with a 47k NTC as charger thermistor which currently is + * not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi index 89e5cd29ec091bebd3221c445ff156a91759fd88..6b10b96173e8776901e1bcf6cd4539e520264c52 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi @@ -12,23 +12,6 @@ ap_h1_spi: &spi0 {}; #include "sc7180-trogdor.dtsi" -/ { - panel: panel { - compatible = "boe,nv133fhm-n62"; - power-supply = <&pp3300_dx_edp>; - backlight = <&backlight>; - hpd-gpios = <&sn65dsi86_bridge 2 GPIO_ACTIVE_HIGH>; - - ports { - port { - panel_in_edp: endpoint { - remote-endpoint = <&sn65dsi86_out>; - }; - }; - }; - }; -}; - &ap_sar_sensor { semtech,cs0-ground; semtech,combined-sensors = <3>; @@ -58,8 +41,30 @@ ap_ts_pen_1v8: &i2c4 { }; }; +&panel { + compatible = "boe,nv133fhm-n62"; +}; + +&trackpad { + interrupts = <58 IRQ_TYPE_EDGE_FALLING>; +}; + +&wifi { + qcom,ath10k-calibration-variant = "GO_LAZOR"; +}; + /* PINCTRL - modifications to sc7180-trogdor.dtsi */ +&trackpad_int_1v8_odl { + pinmux { + pins = "gpio58"; + }; + + pinconf { + pins = "gpio58"; + }; +}; + &ts_reset_l { pinconf { /* This pin is not connected on -rev0, pull up to park. */ diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1-lte.dts new file mode 100644 index 0000000000000000000000000000000000000000..0202f03eafe6ded3fe4fb5a3cb5cd7636831bad0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1-lte.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180-trogdor-pompom-r1.dts" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google Pompom (rev1) with LTE"; + compatible = "google,pompom-rev1-sku0", "qcom,sc7180"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts new file mode 100644 index 0000000000000000000000000000000000000000..e720e7bd0d70c467a9fee937603fd1748d3d7bbc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2020 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-pompom.dtsi" + +/ { + model = "Google Pompom (rev1)"; + compatible = "google,pompom-rev1", "qcom,sc7180"; +}; + +&pp3300_hub { + /* pp3300_l7c is used to power the USB hub */ + /delete-property/regulator-always-on; + /delete-property/regulator-boot-on; +}; + +&pp3300_l7c { + regulator-always-on; + regulator-boot-on; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts new file mode 100644 index 0000000000000000000000000000000000000000..791d496ad046c1b3f6d677806708f8f1fb97107d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180-trogdor-pompom-r2.dts" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google Pompom (rev2+) with LTE"; + compatible = "google,pompom-sku0", "qcom,sc7180"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts new file mode 100644 index 0000000000000000000000000000000000000000..984d7337da784e487d3427cfb4223dea4d8f6eba --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2020 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-pompom.dtsi" + +/ { + model = "Google Pompom (rev2+)"; + compatible = "google,pompom", "qcom,sc7180"; +}; + +&keyboard_controller { + function-row-physmap = < + MATRIX_KEY(0x00, 0x02, 0) /* T1 */ + MATRIX_KEY(0x03, 0x02, 0) /* T2 */ + MATRIX_KEY(0x02, 0x02, 0) /* T3 */ + MATRIX_KEY(0x01, 0x02, 0) /* T4 */ + MATRIX_KEY(0x03, 0x04, 0) /* T5 */ + MATRIX_KEY(0x02, 0x04, 0) /* T6 */ + MATRIX_KEY(0x01, 0x04, 0) /* T7 */ + MATRIX_KEY(0x02, 0x09, 0) /* T8 */ + MATRIX_KEY(0x01, 0x09, 0) /* T9 */ + MATRIX_KEY(0x00, 0x04, 0) /* T10 */ + >; + linux,keymap = < + MATRIX_KEY(0x00, 0x02, KEY_BACK) + MATRIX_KEY(0x03, 0x02, KEY_REFRESH) + MATRIX_KEY(0x02, 0x02, KEY_ZOOM) + MATRIX_KEY(0x01, 0x02, KEY_SCALE) + MATRIX_KEY(0x03, 0x04, KEY_SYSRQ) + MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSDOWN) + MATRIX_KEY(0x01, 0x04, KEY_BRIGHTNESSUP) + MATRIX_KEY(0x02, 0x09, KEY_MUTE) + MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN) + MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP) + + CROS_STD_MAIN_KEYMAP + >; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..622b5f1b88a2cc1273dbdbc9a5d96d8f3669ed9d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2020 Google LLC. + */ + +#include "sc7180.dtsi" + +ap_ec_spi: &spi6 {}; +ap_h1_spi: &spi0 {}; + +#include "sc7180-trogdor.dtsi" + +/ { + thermal-zones { + 5v-choke-thermal { + polling-delay-passive = <0>; + polling-delay = <250>; + + thermal-sensors = <&pm6150_adc_tm 1>; + + trips { + 5v-choke-crit { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + }; +}; + +&alc5682 { + realtek,dmic-clk-driving-high = "true"; +}; + +&cpu6_alert0 { + temperature = <60000>; +}; + +&cpu6_alert1 { + temperature = <65000>; +}; + +&cpu6_thermal { + sustainable-power = <948>; +}; + +&cpu7_alert0 { + temperature = <60000>; +}; + +&cpu7_alert1 { + temperature = <65000>; +}; + +&cpu7_thermal { + sustainable-power = <948>; +}; + +&cpu8_alert0 { + temperature = <60000>; +}; + +&cpu8_alert1 { + temperature = <65000>; +}; + +&cpu8_thermal { + sustainable-power = <948>; +}; + +&cpu9_alert0 { + temperature = <60000>; +}; + +&cpu9_alert1 { + temperature = <65000>; +}; + +&cpu9_thermal { + sustainable-power = <948>; +}; + +&gpio_keys { + status = "okay"; +}; + +ap_ts_pen_1v8: &i2c4 { + status = "okay"; + clock-frequency = <400000>; + + ap_ts: touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_l>, <&ts_reset_l>; + + interrupt-parent = <&tlmm>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + + post-power-on-delay-ms = <20>; + hid-descr-addr = <0x0001>; + + vdd-supply = <&pp3300_ts>; + }; +}; + +&panel { + compatible = "kingdisplay,kd116n21-30nv-a010"; +}; + +&pen_insert { + /* Insert = high, eject = low */ + gpios = <&tlmm 52 GPIO_ACTIVE_HIGH>; +}; + +&pm6150_adc { + 5v-choke-thermistor@4e { + reg = <ADC5_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm6150_adc_tm { + status = "okay"; + + 5v-choke-thermistor@1 { + reg = <1>; + io-channels = <&pm6150_adc ADC5_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + +&sdhc_2 { + status = "okay"; +}; + +&sound { + model = "sc7180-rt5682-max98357a-2mic"; + pinctrl-names = "default"; + pinctrl-0 = <&dmic_sel>; + dmic-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>; +}; + +&usb_c1 { + status = "disabled"; +}; + +&wifi { + qcom,ath10k-calibration-variant = "GO_POMPOM"; +}; + +/* PINCTRL - board-specific pinctrl */ + +&tlmm { + gpio-line-names = "TP_INT_ODL", + "AP_RAM_ID0", + "AP_SKU_ID2", + "AP_RAM_ID1", + "", + "AP_RAM_ID2", + "AP_TP_I2C_SDA", + "AP_TP_I2C_SCL", + "TS_RESET_L", + "TS_INT_L", + "", + "EDP_BRIJ_IRQ", + "AP_EDP_BKLTEN", + "", + "", + "EDP_BRIJ_I2C_SDA", + "EDP_BRIJ_I2C_SCL", + "HUB_RST_L", + "", + "", + "", + "", + "", + "AMP_EN", + "P_SENSOR_INT_L", + "AP_SAR_SENSOR_SDA", + "AP_SAR_SENSOR_SCL", + "", + "HP_IRQ", + "", + "EN_PP3300_DX_EDP", + "AP_BRD_ID2", + "BRIJ_SUSPEND", + "AP_BRD_ID0", + "AP_H1_SPI_MISO", + "AP_H1_SPI_MOSI", + "AP_H1_SPI_CLK", + "AP_H1_SPI_CS_L", + "", + "", + "", + "", + "H1_AP_INT_ODL", + "", + "UART_AP_TX_DBG_RX", + "UART_DBG_TX_AP_RX", + "HP_I2C_SDA", + "HP_I2C_SCL", + "FORCED_USB_BOOT", + "AMP_BCLK", + "AMP_LRCLK", + "AMP_DIN", + "PEN_PDCT_L", + "HP_BCLK", + "HP_LRCLK", + "HP_DOUT", + "HP_DIN", + "HP_MCLK", + "AP_SKU_ID0", + "AP_EC_SPI_MISO", + "AP_EC_SPI_MOSI", + "AP_EC_SPI_CLK", + "AP_EC_SPI_CS_L", + "AP_SPI_CLK", + "AP_SPI_MOSI", + "AP_SPI_MISO", + /* + * AP_FLASH_WP_L is crossystem ABI. Schematics + * call it BIOS_FLASH_WP_L. + */ + "AP_FLASH_WP_L", + "", + "AP_SPI_CS0_L", + "SD_CD_ODL", + "", + "", + "", + "", + "", + "UIM2_DATA", + "UIM2_CLK", + "UIM2_RST", + "UIM2_PRESENT", + "UIM1_DATA", + "UIM1_CLK", + "UIM1_RST", + "", + "EN_PP3300_CODEC", + "EN_PP3300_HUB", + "", + "DMIC_SEL", + "", + "", + "", + "AP_SKU_ID1", + "AP_RST_REQ", + "", + "AP_BRD_ID1", + "AP_EC_INT_R_L", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "EDP_BRIJ_EN", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "AP_TS_PEN_I2C_SDA", + "AP_TS_PEN_I2C_SCL", + "DP_HOT_PLUG_DET", + "EC_IN_RW_ODL"; + + dmic_sel: dmic-sel { + pinmux { + pins = "gpio86"; + function = "gpio"; + }; + + pinconf { + pins = "gpio86"; + bias-pull-down; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts index 2cb522d6962e5fa3d86975af0d452bdcc0abcaeb..2b522f9e0d8ff07b7758fcb085ebda6f89e5141f 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts @@ -17,21 +17,6 @@ ap_h1_spi: &spi0 {}; / { model = "Google Trogdor (rev1+)"; compatible = "google,trogdor", "qcom,sc7180"; - - panel: panel { - compatible = "auo,b116xa01"; - power-supply = <&pp3300_dx_edp>; - backlight = <&backlight>; - hpd-gpios = <&sn65dsi86_bridge 2 GPIO_ACTIVE_HIGH>; - - ports { - port { - panel_in_edp: endpoint { - remote-endpoint = <&sn65dsi86_out>; - }; - }; - }; - }; }; ap_ts_pen_1v8: &i2c4 { @@ -53,6 +38,10 @@ ap_ts_pen_1v8: &i2c4 { }; }; +&panel { + compatible = "auo,b116xa01"; +}; + &pp3300_hub { /* pp3300_l7c is used to power the USB hub */ /delete-property/regulator-always-on; @@ -68,6 +57,22 @@ ap_ts_pen_1v8: &i2c4 { status = "okay"; }; +&trackpad { + interrupts = <58 IRQ_TYPE_EDGE_FALLING>; +}; + +/* PINCTRL - modifications to sc7180-trogdor.dtsi */ + +&trackpad_int_1v8_odl { + pinmux { + pins = "gpio58"; + }; + + pinconf { + pins = "gpio58"; + }; +}; + /* PINCTRL - board-specific pinctrl */ &tlmm { diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi index 07c8b2c926c0c5020b498631dab962c9f0ef7e56..24d293ef56d7b4b75ed7fac3d5ab471112df1036 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi @@ -6,8 +6,10 @@ */ #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/gpio-keys.h> #include <dt-bindings/input/input.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> +#include <dt-bindings/sound/sc7180-lpass.h> /* PMICs depend on spmi_bus label and so must come after SoC */ #include "pm6150.dtsi" @@ -15,16 +17,18 @@ / { thermal-zones { - charger-thermal { + charger_thermal: charger-thermal { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm6150_adc_tm 1>; + thermal-sensors = <&pm6150_adc_tm 0>; trips { - temperature = <125000>; - hysteresis = <1000>; - type = "critical"; + charger-crit { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; }; }; }; @@ -45,7 +49,7 @@ /* Increase the size from 2MB to 8MB */ &rmtfs_mem { - reg = <0x0 0x84400000 0x0 0x800000>; + reg = <0x0 0x94600000 0x0 0x800000>; }; / { @@ -243,6 +247,7 @@ gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; linux,code = <SW_PEN_INSERTED>; linux,input-type = <EV_SW>; + wakeup-event-action = <EV_ACT_DEASSERTED>; wakeup-source; }; }; @@ -255,6 +260,21 @@ #sound-dai-cells = <0>; }; + panel: panel { + /* Compatible will be filled in per-board */ + power-supply = <&pp3300_dx_edp>; + backlight = <&backlight>; + hpd-gpios = <&sn65dsi86_bridge 2 GPIO_ACTIVE_HIGH>; + + ports { + port { + panel_in_edp: endpoint { + remote-endpoint = <&sn65dsi86_out>; + }; + }; + }; + }; + pwmleds { compatible = "pwm-leds"; keyboard_backlight: keyboard-backlight { @@ -264,6 +284,42 @@ max-brightness = <1023>; }; }; + + sound: sound { + compatible = "google,sc7180-trogdor"; + model = "sc7180-rt5682-max98357a-1mic"; + + audio-routing = + "Headphone Jack", "HPOL", + "Headphone Jack", "HPOR"; + + #address-cells = <1>; + #size-cells = <0>; + + dai-link@0 { + link-name = "MultiMedia0"; + reg = <MI2S_PRIMARY>; + cpu { + sound-dai = <&lpass_cpu MI2S_PRIMARY>; + }; + + sound_multimedia0_codec: codec { + sound-dai = <&alc5682 0 /* aif1 */>; + }; + }; + + dai-link@1 { + link-name = "MultiMedia1"; + reg = <MI2S_SECONDARY>; + cpu { + sound-dai = <&lpass_cpu MI2S_SECONDARY>; + }; + + sound_multimedia1_codec: codec { + sound-dai = <&max98357a>; + }; + }; + }; }; &qfprom { @@ -551,6 +607,10 @@ }; }; +&camcc { + status = "disabled"; +}; + &dsi0 { status = "okay"; vdda-supply = <&vdda_mipi_dsi0_1p2>; @@ -642,14 +702,14 @@ ap_tp_i2c: &i2c7 { status = "okay"; clock-frequency = <400000>; - trackpad@15 { + trackpad: trackpad@15 { compatible = "elan,ekth3000"; reg = <0x15>; pinctrl-names = "default"; - pinctrl-0 = <&trackpad_int_1v8_odl>; + pinctrl-0 = <&tp_int_odl>; interrupt-parent = <&tlmm>; - interrupts = <58 IRQ_TYPE_EDGE_FALLING>; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; vcc-supply = <&pp3300_fp_tp>; @@ -697,6 +757,27 @@ hp_i2c: &i2c9 { modem-init; }; +&lpass_cpu { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&sec_mi2s_active>, <&pri_mi2s_active>, <&pri_mi2s_mclk_active>; + + #address-cells = <1>; + #size-cells = <0>; + + mi2s@0 { + reg = <MI2S_PRIMARY>; + qcom,playback-sd-lines = <1>; + qcom,capture-sd-lines = <0>; + }; + + mi2s@1 { + reg = <MI2S_SECONDARY>; + qcom,playback-sd-lines = <0>; + }; +}; + &mdp { status = "okay"; }; @@ -716,8 +797,8 @@ hp_i2c: &i2c9 { &pm6150_adc_tm { status = "okay"; - charger-thermistor@1 { - reg = <1>; + charger-thermistor@0 { + reg = <0>; io-channels = <&pm6150_adc ADC5_AMUX_THM3_100K_PU>; qcom,ratiometric; qcom,hw-settle-time-us = <200>; @@ -768,17 +849,17 @@ hp_i2c: &i2c9 { }; &spi0 { - pinctrl-0 = <&qup_spi0_cs_gpio>; + pinctrl-0 = <&qup_spi0_cs_gpio_init_high>, <&qup_spi0_cs_gpio>; cs-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>; }; &spi6 { - pinctrl-0 = <&qup_spi6_cs_gpio>; + pinctrl-0 = <&qup_spi6_cs_gpio_init_high>, <&qup_spi6_cs_gpio>; cs-gpios = <&tlmm 62 GPIO_ACTIVE_LOW>; }; ap_spi_fp: &spi10 { - pinctrl-0 = <&qup_spi10_cs_gpio>; + pinctrl-0 = <&qup_spi10_cs_gpio_init_high>, <&qup_spi10_cs_gpio>; cs-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>; cros_ec_fp: ec@0 { @@ -787,7 +868,7 @@ ap_spi_fp: &spi10 { interrupt-parent = <&tlmm>; interrupts = <4 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; - pinctrl-0 = <&fp_to_ap_irq_l>, <&fp_rst_l>, <&fpmcu_boot0>, <&fpmcu_sel>; + pinctrl-0 = <&fp_to_ap_irq_l>; spi-max-frequency = <3000000>; }; }; @@ -812,7 +893,6 @@ ap_spi_fp: &spi10 { vddrf-supply = <&pp1300_l2c>; vddch0-supply = <&pp3300_l10c>; max-speed = <3200000>; - clocks = <&rpmhcc RPMH_RF_CLK2>; }; }; @@ -875,6 +955,22 @@ ap_spi_fp: &spi10 { }; }; +&pri_mi2s_active { + pinconf { + pins = "gpio53", "gpio54", "gpio55", "gpio56"; + drive-strength = <2>; + bias-pull-down; + }; +}; + +&pri_mi2s_mclk_active { + pinconf { + pins = "gpio57"; + drive-strength = <2>; + bias-pull-down; + }; +}; + &qspi_cs0 { pinconf { pins = "gpio68"; @@ -1015,6 +1111,14 @@ ap_spi_fp: &spi10 { }; }; +&sec_mi2s_active { + pinconf { + pins = "gpio49", "gpio50", "gpio51"; + drive-strength = <2>; + bias-pull-down; + }; +}; + /* PINCTRL - board-specific pinctrl */ &pm6150_gpio { @@ -1109,20 +1213,6 @@ ap_spi_fp: &spi10 { }; }; - dp_hot_plug_det: dp-hot-plug-det { - pinmux { - pins = "gpio117"; - function = "dp_hot"; - }; - - config { - pins = "gpio117"; - bias-disable; - input-enable; - drive-strength = <2>; - }; - }; - edp_brij_en: edp-brij-en { pinmux { pins = "gpio104"; @@ -1188,48 +1278,6 @@ ap_spi_fp: &spi10 { }; }; - fpmcu_boot0: fpmcu-boot0 { - pinmux { - pins = "gpio10"; - function = "gpio"; - }; - - pinconf { - pins = "gpio10"; - bias-disable; - drive-strength = <2>; - output-low; - }; - }; - - fpmcu_sel: fpmcu-sel { - pinmux { - pins = "gpio22"; - function = "gpio"; - }; - - pinconf { - pins = "gpio22"; - bias-disable; - drive-strength = <2>; - output-high; - }; - }; - - fp_rst_l: fp-rst-l { - pinmux { - pins = "gpio5"; - function = "gpio"; - }; - - pinconf { - pins = "gpio5"; - bias-disable; - drive-strength = <2>; - output-high; - }; - }; - fp_to_ap_irq_l: fp-to-ap-irq-l { pinmux { pins = "gpio4"; @@ -1245,7 +1293,6 @@ ap_spi_fp: &spi10 { }; }; - h1_ap_int_odl: h1-ap-int-odl { pinmux { pins = "gpio42"; @@ -1339,6 +1386,27 @@ ap_spi_fp: &spi10 { }; }; + qup_spi0_cs_gpio_init_high: qup-spi0-cs-gpio-init-high { + pinconf { + pins = "gpio37"; + output-high; + }; + }; + + qup_spi6_cs_gpio_init_high: qup-spi6-cs-gpio-init-high { + pinconf { + pins = "gpio62"; + output-high; + }; + }; + + qup_spi10_cs_gpio_init_high: qup-spi10-cs-gpio-init-high { + pinconf { + pins = "gpio89"; + output-high; + }; + }; + qup_uart3_sleep: qup-uart3-sleep { pinmux { pins = "gpio38", "gpio39", @@ -1386,14 +1454,16 @@ ap_spi_fp: &spi10 { }; }; - trackpad_int_1v8_odl: trackpad-int-1v8-odl { + /* Named trackpad_int_1v8_odl on earlier revision schematics */ + trackpad_int_1v8_odl: + tp_int_odl: tp-int-odl { pinmux { - pins = "gpio58"; + pins = "gpio0"; function = "gpio"; }; pinconf { - pins = "gpio58"; + pins = "gpio0"; /* Has external pullup */ bias-disable; diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 1ea3344ab62cf3845a1429b870b1dc094519bf49..6228ba2d85132570ac3055f7490f249292c21a96 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -110,9 +110,9 @@ no-map; }; - rmtfs_mem: memory@84400000 { + rmtfs_mem: memory@94600000 { compatible = "qcom,rmtfs-mem"; - reg = <0x0 0x84400000 0x0 0x200000>; + reg = <0x0 0x94600000 0x0 0x200000>; no-map; qcom,client-id = <1>; @@ -1856,12 +1856,6 @@ pins = "gpio49", "gpio50", "gpio51"; function = "mi2s_1"; }; - - pinconf { - pins = "gpio49", "gpio50", "gpio51"; - drive-strength = <8>; - bias-pull-up; - }; }; pri_mi2s_active: pri-mi2s-active { @@ -1869,12 +1863,6 @@ pins = "gpio53", "gpio54", "gpio55", "gpio56"; function = "mi2s_0"; }; - - pinconf { - pins = "gpio53", "gpio54", "gpio55", "gpio56"; - drive-strength = <8>; - bias-pull-up; - }; }; pri_mi2s_mclk_active: pri-mi2s-mclk-active { @@ -1882,12 +1870,6 @@ pins = "gpio57"; function = "lpass_ext"; }; - - pinconf { - pins = "gpio57"; - drive-strength = <8>; - bias-pull-up; - }; }; sdc1_on: sdc1-on { @@ -2770,12 +2752,11 @@ }; usb_1_qmpphy: phy-wrapper@88e9000 { - compatible = "qcom,sc7180-qmp-usb3-phy"; + compatible = "qcom,sc7180-qmp-usb3-dp-phy"; reg = <0 0x088e9000 0 0x18c>, - <0 0x088e8000 0 0x38>; - reg-names = "reg-base", "dp_com"; + <0 0x088e8000 0 0x38>, + <0 0x088ea000 0 0x40>; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -2790,7 +2771,7 @@ <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; reset-names = "phy", "common"; - usb_1_ssphy: phy@88e9200 { + usb_1_ssphy: usb3-phy@88e9200 { reg = <0 0x088e9200 0 0x128>, <0 0x088e9400 0 0x200>, <0 0x088e9c00 0 0x218>, @@ -2803,6 +2784,16 @@ clock-names = "pipe0"; clock-output-names = "usb3_phy_pipe_clk_src"; }; + + dp_phy: dp-phy@88ea200 { + reg = <0 0x088ea200 0 0x200>, + <0 0x088ea400 0 0x200>, + <0 0x088eaa00 0 0x200>, + <0 0x088ea600 0 0x200>, + <0 0x088ea800 0 0x200>; + #clock-cells = <1>; + #phy-cells = <0>; + }; }; dc_noc: interconnect@9160000 { @@ -2854,10 +2845,10 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <150000000>; - interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 488 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 489 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 8 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 9 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -3166,8 +3157,8 @@ <&gcc GCC_DISP_GPLL0_CLK_SRC>, <&dsi_phy 0>, <&dsi_phy 1>, - <0>, - <0>; + <&dp_phy 0>, + <&dp_phy 1>; clock-names = "bi_tcxo", "gcc_disp_gpll0_clk_src", "dsi0_phy_pll_out_byteclk", @@ -3222,7 +3213,7 @@ #reset-cells = <1>; }; - aoss_qmp: qmp@c300000 { + aoss_qmp: power-controller@c300000 { compatible = "qcom,sc7180-aoss-qmp"; reg = <0 0x0c300000 0 0x100000>; interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>; @@ -3575,7 +3566,8 @@ reg = <0 0x62f00000 0 0x29000>; reg-names = "lpass-lpaif"; - iommus = <&apps_smmu 0x1020 0>; + iommus = <&apps_smmu 0x1020 0>, + <&apps_smmu 0x1021 0>; power-domains = <&lpass_hm LPASS_CORE_HM_GDSCR>; diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dts b/arch/arm64/boot/dts/qcom/sc7280-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..54d2cb365b71a07e580e60fa1f4e9913d866db24 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dts @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * sc7280 IDP board device tree source + * + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +/dts-v1/; + +#include "sc7280.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sc7280 IDP platform"; + compatible = "qcom,sc7280-idp", "qcom,sc7280"; + + aliases { + serial0 = &uart5; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&apps_rsc { + pm7325-regulators { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vreg_s1b_1p8: smps1 { + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2040000>; + }; + + vreg_s7b_0p9: smps7 { + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vreg_s8b_1p2: smps8 { + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1500000>; + }; + + vreg_l1b_0p8: ldo1 { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + }; + + vreg_l2b_3p0: ldo2 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + }; + + vreg_l6b_1p2: ldo6 { + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + }; + + vreg_l7b_2p9: ldo7 { + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + }; + + vreg_l8b_0p9: ldo8 { + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + }; + + vreg_l9b_1p2: ldo9 { + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + }; + + vreg_l11b_1p7: ldo11 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_l12b_0p8: ldo12 { + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + }; + + vreg_l13b_0p8: ldo13 { + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + }; + + vreg_l14b_1p2: ldo14 { + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + }; + + vreg_l15b_0p8: ldo15 { + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + }; + + vreg_l16b_1p2: ldo16 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + }; + + vreg_l17b_1p8: ldo17 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + + vreg_l18b_1p8: ldo18 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_l19b_1p8: ldo19 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + + pm8350c-regulators { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vreg_s1c_2p2: smps1 { + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + }; + + vreg_s9c_1p0: smps9 { + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + }; + + vreg_l2c_1p8: ldo2 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + }; + + vreg_l3c_3p0: ldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + }; + + vreg_l4c_1p8: ldo4 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + vreg_l5c_1p8: ldo5 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + vreg_l6c_2p9: ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + }; + + vreg_l8c_1p8: ldo8 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_l9c_2p9: ldo9 { + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + }; + + vreg_l10c_0p8: ldo10 { + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + }; + + vreg_l11c_2p8: ldo11 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + }; + + vreg_l12c_1p8: ldo12 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_l13c_3p0: ldo13 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + }; + + vreg_bob: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + }; + }; + + pmr735a-regulators { + compatible = "qcom,pmr735a-rpmh-regulators"; + qcom,pmic-id = "e"; + + vreg_l2e_1p2: ldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + vreg_l3e_0p9: ldo3 { + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <1020000>; + }; + + vreg_l4e_1p7: ldo4 { + regulator-min-microvolt = <1776000>; + regulator-max-microvolt = <1890000>; + }; + + vreg_l5e_0p8: ldo5 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + }; + + vreg_l6e_0p8: ldo6 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <904000>; + }; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&uart5 { + status = "okay"; +}; + +/* PINCTRL - additions to nodes defined in sc7280.dtsi */ + +&qup_uart5_default { + tx { + pins = "gpio46"; + drive-strength = <2>; + bias-disable; + }; + + rx { + pins = "gpio47"; + drive-strength = <2>; + bias-pull-up; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2cc478553935ca4a9e0918ce1c7f2b78f472eaf6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -0,0 +1,1128 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * sc7280 SoC device tree source + * + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + */ + +#include <dt-bindings/clock/qcom,gcc-sc7280.h> +#include <dt-bindings/clock/qcom,rpmh.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/mailbox/qcom-ipcc.h> +#include <dt-bindings/power/qcom-aoss-qmp.h> +#include <dt-bindings/power/qcom-rpmpd.h> +#include <dt-bindings/soc/qcom,rpmh-rsc.h> + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <76800000>; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + #clock-cells = <0>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + aop_mem: memory@80800000 { + reg = <0x0 0x80800000 0x0 0x60000>; + no-map; + }; + + aop_cmd_db_mem: memory@80860000 { + reg = <0x0 0x80860000 0x0 0x20000>; + compatible = "qcom,cmd-db"; + no-map; + }; + + cpucp_mem: memory@80b00000 { + no-map; + reg = <0x0 0x80b00000 0x0 0x100000>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x0>; + enable-method = "psci"; + cpu-idle-states = <&LITTLE_CPU_SLEEP_0 + &LITTLE_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_0>; + L2_0: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + L3_0: l3-cache { + compatible = "cache"; + }; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x100>; + enable-method = "psci"; + cpu-idle-states = <&LITTLE_CPU_SLEEP_0 + &LITTLE_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_100>; + L2_100: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x200>; + enable-method = "psci"; + cpu-idle-states = <&LITTLE_CPU_SLEEP_0 + &LITTLE_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_200>; + L2_200: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x300>; + enable-method = "psci"; + cpu-idle-states = <&LITTLE_CPU_SLEEP_0 + &LITTLE_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_300>; + L2_300: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x400>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CPU_SLEEP_0 + &BIG_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_400>; + L2_400: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x500>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CPU_SLEEP_0 + &BIG_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_500>; + L2_500: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x600>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CPU_SLEEP_0 + &BIG_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_600>; + L2_600: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,kryo"; + reg = <0x0 0x700>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CPU_SLEEP_0 + &BIG_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + next-level-cache = <&L2_700>; + L2_700: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + idle-states { + entry-method = "psci"; + + LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + compatible = "arm,idle-state"; + idle-state-name = "little-power-down"; + arm,psci-suspend-param = <0x40000003>; + entry-latency-us = <549>; + exit-latency-us = <901>; + min-residency-us = <1774>; + local-timer-stop; + }; + + LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + compatible = "arm,idle-state"; + idle-state-name = "little-rail-power-down"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <702>; + exit-latency-us = <915>; + min-residency-us = <4001>; + local-timer-stop; + }; + + BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + idle-state-name = "big-power-down"; + arm,psci-suspend-param = <0x40000003>; + entry-latency-us = <523>; + exit-latency-us = <1244>; + min-residency-us = <2207>; + local-timer-stop; + }; + + BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + compatible = "arm,idle-state"; + idle-state-name = "big-rail-power-down"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <526>; + exit-latency-us = <1854>; + min-residency-us = <5555>; + local-timer-stop; + }; + + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "cluster-power-down"; + arm,psci-suspend-param = <0x40003444>; + entry-latency-us = <3263>; + exit-latency-us = <6562>; + min-residency-us = <9926>; + local-timer-stop; + }; + }; + }; + + memory@80000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0 0x80000000 0 0>; + }; + + firmware { + scm { + compatible = "qcom,scm-sc7280", "qcom,scm"; + }; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + soc: soc@0 { + #address-cells = <2>; + #size-cells = <2>; + ranges = <0 0 0 0 0x10 0>; + dma-ranges = <0 0 0 0 0x10 0>; + compatible = "simple-bus"; + + gcc: clock-controller@100000 { + compatible = "qcom,gcc-sc7280"; + reg = <0 0x00100000 0 0x1f0000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>, + <0>, <0>, <0>, <0>, <0>, <0>; + clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk", + "pcie_0_pipe_clk", "pcie_1_pipe-clk", + "ufs_phy_rx_symbol_0_clk", "ufs_phy_rx_symbol_1_clk", + "ufs_phy_tx_symbol_0_clk", + "usb3_phy_wrapper_gcc_usb30_pipe_clk"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + ipcc: mailbox@408000 { + compatible = "qcom,sc7280-ipcc", "qcom,ipcc"; + reg = <0 0x00408000 0 0x1000>; + interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + }; + + qupv3_id_0: geniqup@9c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x009c0000 0 0x2000>; + clock-names = "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + uart5: serial@994000 { + compatible = "qcom,geni-debug-uart"; + reg = <0 0x00994000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_uart5_default>; + interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + }; + + stm@6002000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0 0x06002000 0 0x1000>, + <0 0x16280000 0 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + stm_out: endpoint { + remote-endpoint = <&funnel0_in7>; + }; + }; + }; + }; + + funnel@6041000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06041000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + funnel0_out: endpoint { + remote-endpoint = <&merge_funnel_in0>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@7 { + reg = <7>; + funnel0_in7: endpoint { + remote-endpoint = <&stm_out>; + }; + }; + }; + }; + + funnel@6042000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06042000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + funnel1_out: endpoint { + remote-endpoint = <&merge_funnel_in1>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@4 { + reg = <4>; + funnel1_in4: endpoint { + remote-endpoint = <&apss_merge_funnel_out>; + }; + }; + }; + }; + + funnel@6045000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06045000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + merge_funnel_out: endpoint { + remote-endpoint = <&swao_funnel_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + merge_funnel_in0: endpoint { + remote-endpoint = <&funnel0_out>; + }; + }; + + port@1 { + reg = <1>; + merge_funnel_in1: endpoint { + remote-endpoint = <&funnel1_out>; + }; + }; + }; + }; + + replicator@6046000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0 0x06046000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + replicator_out: endpoint { + remote-endpoint = <&etr_in>; + }; + }; + }; + + in-ports { + port { + replicator_in: endpoint { + remote-endpoint = <&swao_replicator_out>; + }; + }; + }; + }; + + etr@6048000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x06048000 0 0x1000>; + iommus = <&apps_smmu 0x04c0 0>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,scatter-gather; + + in-ports { + port { + etr_in: endpoint { + remote-endpoint = <&replicator_out>; + }; + }; + }; + }; + + funnel@6b04000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06b04000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + swao_funnel_out: endpoint { + remote-endpoint = <&etf_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@7 { + reg = <7>; + swao_funnel_in: endpoint { + remote-endpoint = <&merge_funnel_out>; + }; + }; + }; + }; + + etf@6b05000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x06b05000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + etf_out: endpoint { + remote-endpoint = <&swao_replicator_in>; + }; + }; + }; + + in-ports { + port { + etf_in: endpoint { + remote-endpoint = <&swao_funnel_out>; + }; + }; + }; + }; + + replicator@6b06000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0 0x06b06000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + qcom,replicator-loses-context; + + out-ports { + port { + swao_replicator_out: endpoint { + remote-endpoint = <&replicator_in>; + }; + }; + }; + + in-ports { + port { + swao_replicator_in: endpoint { + remote-endpoint = <&etf_out>; + }; + }; + }; + }; + + etm@7040000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07040000 0 0x1000>; + + cpu = <&CPU0>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm0_out: endpoint { + remote-endpoint = <&apss_funnel_in0>; + }; + }; + }; + }; + + etm@7140000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07140000 0 0x1000>; + + cpu = <&CPU1>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm1_out: endpoint { + remote-endpoint = <&apss_funnel_in1>; + }; + }; + }; + }; + + etm@7240000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07240000 0 0x1000>; + + cpu = <&CPU2>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm2_out: endpoint { + remote-endpoint = <&apss_funnel_in2>; + }; + }; + }; + }; + + etm@7340000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07340000 0 0x1000>; + + cpu = <&CPU3>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm3_out: endpoint { + remote-endpoint = <&apss_funnel_in3>; + }; + }; + }; + }; + + etm@7440000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07440000 0 0x1000>; + + cpu = <&CPU4>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm4_out: endpoint { + remote-endpoint = <&apss_funnel_in4>; + }; + }; + }; + }; + + etm@7540000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07540000 0 0x1000>; + + cpu = <&CPU5>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm5_out: endpoint { + remote-endpoint = <&apss_funnel_in5>; + }; + }; + }; + }; + + etm@7640000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07640000 0 0x1000>; + + cpu = <&CPU6>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm6_out: endpoint { + remote-endpoint = <&apss_funnel_in6>; + }; + }; + }; + }; + + etm@7740000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07740000 0 0x1000>; + + cpu = <&CPU7>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + qcom,skip-power-up; + + out-ports { + port { + etm7_out: endpoint { + remote-endpoint = <&apss_funnel_in7>; + }; + }; + }; + }; + + funnel@7800000 { /* APSS Funnel */ + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x07800000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + apss_funnel_out: endpoint { + remote-endpoint = <&apss_merge_funnel_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + apss_funnel_in0: endpoint { + remote-endpoint = <&etm0_out>; + }; + }; + + port@1 { + reg = <1>; + apss_funnel_in1: endpoint { + remote-endpoint = <&etm1_out>; + }; + }; + + port@2 { + reg = <2>; + apss_funnel_in2: endpoint { + remote-endpoint = <&etm2_out>; + }; + }; + + port@3 { + reg = <3>; + apss_funnel_in3: endpoint { + remote-endpoint = <&etm3_out>; + }; + }; + + port@4 { + reg = <4>; + apss_funnel_in4: endpoint { + remote-endpoint = <&etm4_out>; + }; + }; + + port@5 { + reg = <5>; + apss_funnel_in5: endpoint { + remote-endpoint = <&etm5_out>; + }; + }; + + port@6 { + reg = <6>; + apss_funnel_in6: endpoint { + remote-endpoint = <&etm6_out>; + }; + }; + + port@7 { + reg = <7>; + apss_funnel_in7: endpoint { + remote-endpoint = <&etm7_out>; + }; + }; + }; + }; + + funnel@7810000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x07810000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + apss_merge_funnel_out: endpoint { + remote-endpoint = <&funnel1_in4>; + }; + }; + }; + + in-ports { + port { + apss_merge_funnel_in: endpoint { + remote-endpoint = <&apss_funnel_out>; + }; + }; + }; + }; + + system-cache-controller@9200000 { + compatible = "qcom,sc7280-llcc"; + reg = <0 0x09200000 0 0xd0000>, <0 0x09600000 0 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,sc7280-pdc", "qcom,pdc"; + reg = <0 0x0b220000 0 0x30000>; + qcom,pdc-ranges = <0 480 40>, <40 140 14>, <54 263 1>, + <55 306 4>, <59 312 3>, <62 374 2>, + <64 434 2>, <66 438 3>, <69 86 1>, + <70 520 54>, <124 609 31>, <155 63 1>, + <156 716 12>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + aoss_qmp: power-controller@c300000 { + compatible = "qcom,sc7280-aoss-qmp"; + reg = <0 0x0c300000 0 0x100000>; + interrupts-extended = <&ipcc IPCC_CLIENT_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + #clock-cells = <0>; + #power-domain-cells = <1>; + }; + + spmi_bus: spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0 0x0c440000 0 0x1100>, + <0 0x0c600000 0 0x2000000>, + <0 0x0e600000 0 0x100000>, + <0 0x0e700000 0 0xa0000>, + <0 0x0c40a000 0 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + #interrupt-cells = <4>; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,sc7280-pinctrl"; + reg = <0 0x0f100000 0 0x300000>; + interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&tlmm 0 0 175>; + wakeup-parent = <&pdc>; + + qup_uart5_default: qup-uart5-default { + pins = "gpio46", "gpio47"; + function = "qup13"; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,sc7280-smmu-500", "arm,mmu-500"; + reg = <0 0x15000000 0 0x100000>; + #iommu-cells = <2>; + #global-interrupts = <1>; + dma-coherent; + interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>; + }; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0 0x17a00000 0 0x10000>, /* GICD */ + <0 0x17a60000 0 0x100000>; /* GICR * 8 */ + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>; + + gic-its@17a40000 { + compatible = "arm,gic-v3-its"; + msi-controller; + #msi-cells = <1>; + reg = <0 0x17a40000 0 0x20000>; + status = "disabled"; + }; + }; + + watchdog@17c10000 { + compatible = "qcom,apss-wdt-sc7280", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + }; + + timer@17c20000 { + #address-cells = <2>; + #size-cells = <2>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0 0x17c20000 0 0x1000>; + + frame@17c21000 { + frame-number = <0>; + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c21000 0 0x1000>, + <0 0x17c22000 0 0x1000>; + }; + + frame@17c23000 { + frame-number = <1>; + interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c23000 0 0x1000>; + status = "disabled"; + }; + + frame@17c25000 { + frame-number = <2>; + interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c25000 0 0x1000>; + status = "disabled"; + }; + + frame@17c27000 { + frame-number = <3>; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c27000 0 0x1000>; + status = "disabled"; + }; + + frame@17c29000 { + frame-number = <4>; + interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c29000 0 0x1000>; + status = "disabled"; + }; + + frame@17c2b000 { + frame-number = <5>; + interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c2b000 0 0x1000>; + status = "disabled"; + }; + + frame@17c2d000 { + frame-number = <6>; + interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; + reg = <0 0x17c2d000 0 0x1000>; + status = "disabled"; + }; + }; + + apps_rsc: rsc@18200000 { + compatible = "qcom,rpmh-rsc"; + reg = <0 0x18200000 0 0x10000>, + <0 0x18210000 0 0x10000>, + <0 0x18220000 0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = <ACTIVE_TCS 2>, + <SLEEP_TCS 3>, + <WAKE_TCS 3>, + <CONTROL_TCS 1>; + + rpmhpd: power-controller { + compatible = "qcom,sc7280-rpmhpd"; + #power-domain-cells = <1>; + operating-points-v2 = <&rpmhpd_opp_table>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp1 { + opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>; + }; + + rpmhpd_opp_low_svs: opp2 { + opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>; + }; + + rpmhpd_opp_svs: opp3 { + opp-level = <RPMH_REGULATOR_LEVEL_SVS>; + }; + + rpmhpd_opp_svs_l1: opp4 { + opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>; + }; + + rpmhpd_opp_svs_l2: opp5 { + opp-level = <RPMH_REGULATOR_LEVEL_SVS_L2>; + }; + + rpmhpd_opp_nom: opp6 { + opp-level = <RPMH_REGULATOR_LEVEL_NOM>; + }; + + rpmhpd_opp_nom_l1: opp7 { + opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>; + }; + + rpmhpd_opp_turbo: opp8 { + opp-level = <RPMH_REGULATOR_LEVEL_TURBO>; + }; + + rpmhpd_opp_turbo_l1: opp9 { + opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>; + }; + }; + }; + + rpmhcc: clock-controller { + compatible = "qcom,sc7280-rpmh-clk"; + clocks = <&xo_board>; + clock-names = "xo"; + #clock-cells = <1>; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, + <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts index c4ac6f5dc008d4f439259ec21f8a649fcf50f133..2d5533dd4ec2d6ba938c3c7e1b13a2c8c7257703 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -244,7 +244,7 @@ &adsp_pas { status = "okay"; - firmware-name = "qcom/sdm845/adsp.mdt"; + firmware-name = "qcom/sdm845/adsp.mbn"; }; &apps_rsc { @@ -390,7 +390,7 @@ &cdsp_pas { status = "okay"; - firmware-name = "qcom/sdm845/cdsp.mdt"; + firmware-name = "qcom/sdm845/cdsp.mbn"; }; &dsi0 { @@ -1015,7 +1015,7 @@ left_spkr: wsa8810-left{ compatible = "sdw10217201000"; reg = <0 1>; - powerdown-gpios = <&wcdgpio 2 GPIO_ACTIVE_HIGH>; + powerdown-gpios = <&wcdgpio 1 GPIO_ACTIVE_HIGH>; #thermal-sensor-cells = <0>; sound-name-prefix = "SpkrLeft"; #sound-dai-cells = <0>; @@ -1023,7 +1023,7 @@ right_spkr: wsa8810-right{ compatible = "sdw10217201000"; - powerdown-gpios = <&wcdgpio 2 GPIO_ACTIVE_HIGH>; + powerdown-gpios = <&wcdgpio 1 GPIO_ACTIVE_HIGH>; reg = <0 2>; #thermal-sensor-cells = <0>; sound-name-prefix = "SpkrRight"; @@ -1108,6 +1108,25 @@ status = "okay"; }; +&camss { + vdda-supply = <&vreg_l1a_0p875>; + + status = "ok"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + csiphy0_ep: endpoint { + clock-lanes = <7>; + data-lanes = <0 1 2 3>; + remote-endpoint = <&ov8856_ep>; + }; + }; + }; +}; + &cci_i2c0 { camera@10 { compatible = "ovti,ov8856"; @@ -1137,7 +1156,7 @@ avdd-supply = <&cam0_avdd_2v8>; dvdd-supply = <&cam0_dvdd_1v2>; - status = "disable"; + status = "ok"; port { ov8856_ep: endpoint { @@ -1145,7 +1164,7 @@ link-frequencies = /bits/ 64 <360000000 180000000>; data-lanes = <1 2 3 4>; -// remote-endpoint = <&csiphy0_ep>; + remote-endpoint = <&csiphy0_ep>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts index 86cbae63eaf7b92dd2078f755af67558ba1aeabe..7d029425336e40a2784fd14a1b17658095f8646e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts @@ -157,6 +157,14 @@ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; + vreg_l14a_1p8: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-boot-on; + regulator-always-on; + }; + vreg_l17a_1p3: ldo17 { regulator-min-microvolt = <1304000>; regulator-max-microvolt = <1304000>; @@ -191,6 +199,7 @@ regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-boot-on; }; }; }; @@ -200,6 +209,43 @@ firmware-name = "qcom/sdm845/cdsp.mdt"; }; +&dsi0 { + status = "okay"; + vdda-supply = <&vreg_l26a_1p2>; + + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "tianma,fhd-video"; + reg = <0>; + vddi0-supply = <&vreg_l14a_1p8>; + vddpos-supply = <&lab>; + vddneg-supply = <&ibb>; + + #address-cells = <1>; + #size-cells = <0>; + + reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>; + + port { + tianma_nt36672a_in_0: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; +}; + +&dsi0_out { + remote-endpoint = <&tianma_nt36672a_in_0>; + data-lanes = <0 1 2 3>; +}; + +&dsi0_phy { + status = "okay"; + vdds-supply = <&vreg_l1a_0p875>; +}; + &gcc { protected-clocks = <GCC_QSPI_CORE_CLK>, <GCC_QSPI_CORE_CLK_SRC>, @@ -215,6 +261,31 @@ }; }; +&ibb { + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + regulator-over-current-protection; + regulator-pull-down; + regulator-soft-start; + qcom,discharge-resistor-kohms = <300>; +}; + +&lab { + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + regulator-over-current-protection; + regulator-pull-down; + regulator-soft-start; +}; + +&mdss { + status = "okay"; +}; + +&mdss_mdp { + status = "okay"; +}; + &mss_pil { status = "okay"; firmware-name = "qcom/sdm845/mba.mbn", "qcom/sdm845/modem.mdt"; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 454f794af54791eecf4fb36bfe651e5f57c1f4a9..0a86fe71a66d19d4d0e422fef1153527122e99b7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1061,6 +1061,16 @@ gcc: clock-controller@100000 { compatible = "qcom,gcc-sdm845"; reg = <0 0x00100000 0 0x1f0000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&pcie0_lane>, + <&pcie1_lane>; + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "sleep_clk", + "pcie_0_pipe_clk", + "pcie_1_pipe_clk"; #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; @@ -2062,6 +2072,7 @@ clocks = <&gcc GCC_PCIE_0_PIPE_CLK>; clock-names = "pipe0"; + #clock-cells = <0>; #phy-cells = <0>; clock-output-names = "pcie_0_pipe_clk"; }; @@ -2170,6 +2181,7 @@ clocks = <&gcc GCC_PCIE_1_PIPE_CLK>; clock-names = "pipe0"; + #clock-cells = <0>; #phy-cells = <0>; clock-output-names = "pcie_1_pipe_clk"; }; @@ -2382,7 +2394,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - gpio-ranges = <&tlmm 0 0 150>; + gpio-ranges = <&tlmm 0 0 151>; wakeup-parent = <&pdc_intc>; cci0_default: cci0-default { @@ -3673,7 +3685,6 @@ <0 0x088e8000 0 0x10>; reg-names = "reg-base", "dp_com"; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -3695,6 +3706,7 @@ <0 0x088e9600 0 0x128>, <0 0x088e9800 0 0x200>, <0 0x088e9a00 0 0x100>; + #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; clock-names = "pipe0"; @@ -3706,7 +3718,6 @@ compatible = "qcom,sdm845-qmp-usb3-uni-phy"; reg = <0 0x088eb000 0 0x18c>; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -3726,6 +3737,7 @@ <0 0x088eb400 0 0x1fc>, <0 0x088eb800 0 0x218>, <0 0x088eb600 0 0x70>; + #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; clock-names = "pipe0"; @@ -3909,6 +3921,141 @@ #reset-cells = <1>; }; + camss: camss@a00000 { + compatible = "qcom,sdm845-camss"; + + reg = <0 0xacb3000 0 0x1000>, + <0 0xacba000 0 0x1000>, + <0 0xacc8000 0 0x1000>, + <0 0xac65000 0 0x1000>, + <0 0xac66000 0 0x1000>, + <0 0xac67000 0 0x1000>, + <0 0xac68000 0 0x1000>, + <0 0xacaf000 0 0x4000>, + <0 0xacb6000 0 0x4000>, + <0 0xacc4000 0 0x4000>; + reg-names = "csid0", + "csid1", + "csid2", + "csiphy0", + "csiphy1", + "csiphy2", + "csiphy3", + "vfe0", + "vfe1", + "vfe_lite"; + + interrupts = <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csid0", + "csid1", + "csid2", + "csiphy0", + "csiphy1", + "csiphy2", + "csiphy3", + "vfe0", + "vfe1", + "vfe_lite"; + + power-domains = <&clock_camcc IFE_0_GDSC>, + <&clock_camcc IFE_1_GDSC>, + <&clock_camcc TITAN_TOP_GDSC>; + + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY3_CLK>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>; + clock-names = "camnoc_axi", + "cpas_ahb", + "cphy_rx_src", + "csi0", + "csi0_src", + "csi1", + "csi1_src", + "csi2", + "csi2_src", + "csiphy0", + "csiphy0_timer", + "csiphy0_timer_src", + "csiphy1", + "csiphy1_timer", + "csiphy1_timer_src", + "csiphy2", + "csiphy2_timer", + "csiphy2_timer_src", + "csiphy3", + "csiphy3_timer", + "csiphy3_timer_src", + "gcc_camera_ahb", + "gcc_camera_axi", + "slow_ahb_src", + "soc_ahb", + "vfe0_axi", + "vfe0", + "vfe0_cphy_rx", + "vfe0_src", + "vfe1_axi", + "vfe1", + "vfe1_cphy_rx", + "vfe1_src", + "vfe_lite", + "vfe_lite_cphy_rx", + "vfe_lite_src"; + + iommus = <&apps_smmu 0x0808 0x0>, + <&apps_smmu 0x0810 0x8>, + <&apps_smmu 0x0c08 0x0>, + <&apps_smmu 0x0c10 0x8>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + cci: cci@ac4a000 { compatible = "qcom,sdm845-cci"; #address-cells = <1>; @@ -4428,7 +4575,7 @@ #reset-cells = <1>; }; - aoss_qmp: qmp@c300000 { + aoss_qmp: power-controller@c300000 { compatible = "qcom,sdm845-aoss-qmp"; reg = <0 0x0c300000 0 0x100000>; interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index e5bb17bc2f46b6c903a9f2352d90b717afc058e9..51235a9521c24314bc88afb26f909c5c2c949b99 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -577,17 +577,188 @@ <&sleep_clk>; }; + qupv3_id_0: geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x008c0000 0x0 0x6000>; + clock-names = "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + iommus = <&apps_smmu 0xc3 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + i2c0: i2c@880000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00880000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c0_default>; + interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@884000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00884000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c1_default>; + interrupts = <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@888000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00888000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c2_default>; + interrupts = <GIC_SPI 603 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@88c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0088c000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c3_default>; + interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@890000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00890000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c4_default>; + interrupts = <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c5: i2c@894000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00894000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c5_default>; + interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c6: i2c@898000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00898000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c6_default>; + interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c7: i2c@89c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0089c000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c7_default>; + interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + }; + qupv3_id_1: geniqup@ac0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x00ac0000 0x0 0x6000>; clock-names = "m-ahb", "s-ahb"; clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + iommus = <&apps_smmu 0x603 0x0>; #address-cells = <2>; #size-cells = <2>; ranges; status = "disabled"; + i2c8: i2c@a80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a80000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c8_default>; + interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c9: i2c@a84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a84000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c9_default>; + interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c10: i2c@a88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a88000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c10_default>; + interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c11: i2c@a8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a8c000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c11_default>; + interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + uart2: serial@a90000 { compatible = "qcom,geni-debug-uart"; reg = <0x0 0x00a90000 0x0 0x4000>; @@ -596,6 +767,124 @@ interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; + + i2c12: i2c@a90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a90000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c12_default>; + interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c16: i2c@94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0094000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c16_default>; + interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + + qupv3_id_2: geniqup@cc0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x00cc0000 0x0 0x6000>; + + clock-names = "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + iommus = <&apps_smmu 0x7a3 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + i2c17: i2c@c80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00c80000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c17_default>; + interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c18: i2c@c84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00c84000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c18_default>; + interrupts = <GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c19: i2c@c88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00c88000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c19_default>; + interrupts = <GIC_SPI 584 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c13: i2c@c8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00c8c000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c13_default>; + interrupts = <GIC_SPI 585 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c14: i2c@c90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00c90000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c14_default>; + interrupts = <GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c15: i2c@c94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00c94000 0 0x4000>; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c15_default>; + interrupts = <GIC_SPI 587 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; config_noc: interconnect@1500000 { @@ -914,11 +1203,271 @@ <0x0 0x03D00000 0x0 0x300000>; reg-names = "west", "east", "north", "south"; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; - gpio-ranges = <&tlmm 0 0 175>; + gpio-ranges = <&tlmm 0 0 176>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + + qup_i2c0_default: qup-i2c0-default { + mux { + pins = "gpio0", "gpio1"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c1_default: qup-i2c1-default { + mux { + pins = "gpio114", "gpio115"; + function = "qup1"; + }; + + config { + pins = "gpio114", "gpio115"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c2_default: qup-i2c2-default { + mux { + pins = "gpio126", "gpio127"; + function = "qup2"; + }; + + config { + pins = "gpio126", "gpio127"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c3_default: qup-i2c3-default { + mux { + pins = "gpio144", "gpio145"; + function = "qup3"; + }; + + config { + pins = "gpio144", "gpio145"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c4_default: qup-i2c4-default { + mux { + pins = "gpio51", "gpio52"; + function = "qup4"; + }; + + config { + pins = "gpio51", "gpio52"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c5_default: qup-i2c5-default { + mux { + pins = "gpio121", "gpio122"; + function = "qup5"; + }; + + config { + pins = "gpio121", "gpio122"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c6_default: qup-i2c6-default { + mux { + pins = "gpio6", "gpio7"; + function = "qup6"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c7_default: qup-i2c7-default { + mux { + pins = "gpio98", "gpio99"; + function = "qup7"; + }; + + config { + pins = "gpio98", "gpio99"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c8_default: qup-i2c8-default { + mux { + pins = "gpio88", "gpio89"; + function = "qup8"; + }; + + config { + pins = "gpio88", "gpio89"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c9_default: qup-i2c9-default { + mux { + pins = "gpio39", "gpio40"; + function = "qup9"; + }; + + config { + pins = "gpio39", "gpio40"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c10_default: qup-i2c10-default { + mux { + pins = "gpio9", "gpio10"; + function = "qup10"; + }; + + config { + pins = "gpio9", "gpio10"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c11_default: qup-i2c11-default { + mux { + pins = "gpio94", "gpio95"; + function = "qup11"; + }; + + config { + pins = "gpio94", "gpio95"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c12_default: qup-i2c12-default { + mux { + pins = "gpio83", "gpio84"; + function = "qup12"; + }; + + config { + pins = "gpio83", "gpio84"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c13_default: qup-i2c13-default { + mux { + pins = "gpio43", "gpio44"; + function = "qup13"; + }; + + config { + pins = "gpio43", "gpio44"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c14_default: qup-i2c14-default { + mux { + pins = "gpio47", "gpio48"; + function = "qup14"; + }; + + config { + pins = "gpio47", "gpio48"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c15_default: qup-i2c15-default { + mux { + pins = "gpio27", "gpio28"; + function = "qup15"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c16_default: qup-i2c16-default { + mux { + pins = "gpio86", "gpio85"; + function = "qup16"; + }; + + config { + pins = "gpio86", "gpio85"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c17_default: qup-i2c17-default { + mux { + pins = "gpio55", "gpio56"; + function = "qup17"; + }; + + config { + pins = "gpio55", "gpio56"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c18_default: qup-i2c18-default { + mux { + pins = "gpio23", "gpio24"; + function = "qup18"; + }; + + config { + pins = "gpio23", "gpio24"; + drive-strength = <0x02>; + bias-disable; + }; + }; + + qup_i2c19_default: qup-i2c19-default { + mux { + pins = "gpio57", "gpio58"; + function = "qup19"; + }; + + config { + pins = "gpio57", "gpio58"; + drive-strength = <0x02>; + bias-disable; + }; + }; }; remoteproc_mpss: remoteproc@4080000 { @@ -1612,7 +2161,6 @@ <0 0x088e8000 0 0x10>; reg-names = "reg-base", "dp_com"; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -1634,6 +2182,7 @@ <0 0x088e9600 0 0x200>, <0 0x088e9800 0 0x200>, <0 0x088e9a00 0 0x100>; + #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; clock-names = "pipe0"; @@ -1659,7 +2208,6 @@ compatible = "qcom,sm8150-qmp-usb3-uni-phy"; reg = <0 0x088eb000 0 0x200>; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -1679,6 +2227,7 @@ <0 0x088eb400 0 0x200>, <0 0x088eb800 0 0x800>, <0 0x088eb600 0 0x200>; + #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; clock-names = "pipe0"; diff --git a/arch/arm64/boot/dts/qcom/sm8250-mtp.dts b/arch/arm64/boot/dts/qcom/sm8250-mtp.dts index 5b4c5b08434c6b2b57ca7cf88a9afb258a4f4ceb..cfc4d1febe0f9fcc34697c98e134411088e24f4e 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8250-mtp.dts @@ -601,10 +601,6 @@ }; }; -&pm8150_rtc { - status = "okay"; -}; - &qupv3_id_0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 947e1accae3ab8f7a3b70891e77d1e667c218056..4c0de12aaba6f2e3c542384c2ad62356ca09bdbd 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -17,6 +17,7 @@ #include <dt-bindings/soc/qcom,rpmh-rsc.h> #include <dt-bindings/sound/qcom,q6afe.h> #include <dt-bindings/thermal/thermal.h> +#include <dt-bindings/clock/qcom,videocc-sm8250.h> / { interrupt-parent = <&intc>; @@ -279,7 +280,7 @@ pmu { compatible = "arm,armv8-pmuv3"; - interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; }; psci { @@ -548,8 +549,6 @@ reg = <0 0x00880000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi14_default>; interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -576,8 +575,6 @@ reg = <0 0x00884000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi15_default>; interrupts = <GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -604,8 +601,6 @@ reg = <0 0x00888000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi16_default>; interrupts = <GIC_SPI 584 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -632,8 +627,6 @@ reg = <0 0x0088c000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi17_default>; interrupts = <GIC_SPI 585 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -673,8 +666,6 @@ reg = <0 0x00890000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi18_default>; interrupts = <GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -714,8 +705,6 @@ reg = <0 0x00894000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi19_default>; interrupts = <GIC_SPI 587 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -755,8 +744,6 @@ reg = <0 0x00980000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi0_default>; interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -783,8 +770,6 @@ reg = <0 0x00984000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi1_default>; interrupts = <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -811,8 +796,6 @@ reg = <0 0x00988000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi2_default>; interrupts = <GIC_SPI 603 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -852,8 +835,6 @@ reg = <0 0x0098c000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi3_default>; interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -880,8 +861,6 @@ reg = <0 0x00990000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi4_default>; interrupts = <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -908,8 +887,6 @@ reg = <0 0x00994000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi5_default>; interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -936,8 +913,6 @@ reg = <0 0x00998000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi6_default>; interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -977,8 +952,6 @@ reg = <0 0x0099c000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi7_default>; interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -1018,8 +991,6 @@ reg = <0 0x00a80000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi8_default>; interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -1046,8 +1017,6 @@ reg = <0 0x00a84000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi9_default>; interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -1074,8 +1043,6 @@ reg = <0 0x00a88000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi10_default>; interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -1102,8 +1069,6 @@ reg = <0 0x00a8c000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi11_default>; interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -1130,8 +1095,6 @@ reg = <0 0x00a90000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi12_default>; interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -1171,8 +1134,6 @@ reg = <0 0x00a94000 0 0x4000>; clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi13_default>; interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; @@ -2097,12 +2058,11 @@ }; usb_1_qmpphy: phy@88e9000 { - compatible = "qcom,sm8250-qmp-usb3-phy"; + compatible = "qcom,sm8250-qmp-usb3-dp-phy"; reg = <0 0x088e9000 0 0x200>, - <0 0x088e8000 0 0x20>; - reg-names = "reg-base", "dp_com"; + <0 0x088e8000 0 0x40>, + <0 0x088ea000 0 0x200>; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -2116,25 +2076,39 @@ <&gcc GCC_USB3_PHY_PRIM_BCR>; reset-names = "phy", "common"; - usb_1_ssphy: lanes@88e9200 { + usb_1_ssphy: usb3-phy@88e9200 { reg = <0 0x088e9200 0 0x200>, <0 0x088e9400 0 0x200>, <0 0x088e9c00 0 0x400>, <0 0x088e9600 0 0x200>, <0 0x088e9800 0 0x200>, <0 0x088e9a00 0 0x100>; + #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; clock-names = "pipe0"; clock-output-names = "usb3_phy_pipe_clk_src"; }; + + dp_phy: dp-phy@88ea200 { + reg = <0 0x088ea200 0 0x200>, + <0 0x088ea400 0 0x200>, + <0 0x088eac00 0 0x400>, + <0 0x088ea600 0 0x200>, + <0 0x088ea800 0 0x200>, + <0 0x088eaa00 0 0x100>; + #phy-cells = <0>; + #clock-cells = <1>; + clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "pipe0"; + clock-output-names = "usb3_phy_pipe_clk_src"; + }; }; usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8250-qmp-usb3-uni-phy"; reg = <0 0x088eb000 0 0x200>; status = "disabled"; - #clock-cells = <1>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -2153,6 +2127,7 @@ reg = <0 0x088eb200 0 0x200>, <0 0x088eb400 0 0x200>, <0 0x088eb800 0 0x800>; + #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; clock-names = "pipe0"; @@ -2322,15 +2297,86 @@ }; }; + venus: video-codec@aa00000 { + compatible = "qcom,sm8250-venus"; + reg = <0 0x0aa00000 0 0x100000>; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&videocc MVS0C_GDSC>, + <&videocc MVS0_GDSC>, + <&rpmhpd SM8250_MX>; + power-domain-names = "venus", "vcodec0", "mx"; + operating-points-v2 = <&venus_opp_table>; + + clocks = <&gcc GCC_VIDEO_AXI0_CLK>, + <&videocc VIDEO_CC_MVS0C_CLK>, + <&videocc VIDEO_CC_MVS0_CLK>; + clock-names = "iface", "core", "vcodec0_core"; + + interconnects = <&gem_noc MASTER_AMPSS_M0 &config_noc SLAVE_VENUS_CFG>, + <&mmss_noc MASTER_VIDEO_P0 &mc_virt SLAVE_EBI_CH0>; + interconnect-names = "cpu-cfg", "video-mem"; + + iommus = <&apps_smmu 0x2100 0x0400>; + memory-region = <&video_mem>; + + resets = <&gcc GCC_VIDEO_AXI0_CLK_ARES>, + <&videocc VIDEO_CC_MVS0C_CLK_ARES>; + reset-names = "bus", "core"; + + video-decoder { + compatible = "venus-decoder"; + }; + + video-encoder { + compatible = "venus-encoder"; + }; + + venus_opp_table: venus-opp-table { + compatible = "operating-points-v2"; + + opp-720000000 { + opp-hz = /bits/ 64 <720000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-1014000000 { + opp-hz = /bits/ 64 <1014000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-1098000000 { + opp-hz = /bits/ 64 <1098000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-1332000000 { + opp-hz = /bits/ 64 <1332000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + videocc: clock-controller@abf0000 { + compatible = "qcom,sm8250-videocc"; + reg = <0 0x0abf0000 0 0x10000>; + clocks = <&gcc GCC_VIDEO_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>; + mmcx-supply = <&mmcx_reg>; + clock-names = "iface", "bi_tcxo", "bi_tcxo_ao"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + mdss: mdss@ae00000 { compatible = "qcom,sdm845-mdss"; reg = <0 0x0ae00000 0 0x1000>; reg-names = "mdss"; - interconnects = <&gem_noc MASTER_AMPSS_M0 &config_noc SLAVE_DISPLAY_CFG>, - <&mmss_noc MASTER_MDP_PORT0 &mc_virt SLAVE_EBI_CH0>, + interconnects = <&mmss_noc MASTER_MDP_PORT0 &mc_virt SLAVE_EBI_CH0>, <&mmss_noc MASTER_MDP_PORT1 &mc_virt SLAVE_EBI_CH0>; - interconnect-names = "notused", "mdp0-mem", "mdp1-mem"; + interconnect-names = "mdp0-mem", "mdp1-mem"; power-domains = <&dispcc MDSS_GDSC>; @@ -2580,36 +2626,22 @@ dispcc: clock-controller@af00000 { compatible = "qcom,sm8250-dispcc"; - reg = <0 0x0af00000 0 0x20000>; + reg = <0 0x0af00000 0 0x10000>; mmcx-supply = <&mmcx_reg>; clocks = <&rpmhcc RPMH_CXO_CLK>, <&dsi0_phy 0>, <&dsi0_phy 1>, <&dsi1_phy 0>, <&dsi1_phy 1>, - <0>, - <0>, - <0>, - <0>, - <0>, - <0>, - <0>, - <0>, - <&sleep_clk>; + <&dp_phy 0>, + <&dp_phy 1>; clock-names = "bi_tcxo", "dsi0_phy_pll_out_byteclk", "dsi0_phy_pll_out_dsiclk", "dsi1_phy_pll_out_byteclk", "dsi1_phy_pll_out_dsiclk", - "dp_link_clk_divsel_ten", - "dp_vco_divided_clk_src_mux", - "dptx1_phy_pll_link_clk", - "dptx1_phy_pll_vco_div_clk", - "dptx2_phy_pll_link_clk", - "dptx2_phy_pll_vco_div_clk", - "edp_phy_pll_link_clk", - "edp_phy_pll_vco_div_clk", - "sleep_clk"; + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div_clk"; #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; @@ -2647,7 +2679,7 @@ #thermal-sensor-cells = <1>; }; - aoss_qmp: qmp@c300000 { + aoss_qmp: power-controller@c300000 { compatible = "qcom,sm8250-aoss-qmp"; reg = <0 0x0c300000 0 0x100000>; interrupts-extended = <&ipcc IPCC_CLIENT_AOP @@ -2689,7 +2721,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - gpio-ranges = <&tlmm 0 0 180>; + gpio-ranges = <&tlmm 0 0 181>; wakeup-parent = <&pdc>; pri_mi2s_active: pri-mi2s-active { @@ -2983,304 +3015,324 @@ }; }; - qup_spi0_default: qup-spi0-default { - mux { - pins = "gpio28", "gpio29", - "gpio30", "gpio31"; - function = "qup0"; - }; + qup_spi0_cs: qup-spi0-cs { + pins = "gpio31"; + function = "qup0"; + }; - config { - pins = "gpio28", "gpio29", - "gpio30", "gpio31"; - drive-strength = <6>; - bias-disable; - }; + qup_spi0_cs_gpio: qup-spi0-cs-gpio { + pins = "gpio31"; + function = "gpio"; }; - qup_spi1_default: qup-spi1-default { - mux { - pins = "gpio4", "gpio5", - "gpio6", "gpio7"; - function = "qup1"; - }; + qup_spi0_data_clk: qup-spi0-data-clk { + pins = "gpio28", "gpio29", + "gpio30"; + function = "qup0"; + }; - config { - pins = "gpio4", "gpio5", - "gpio6", "gpio7"; - drive-strength = <6>; - bias-disable; - }; + qup_spi1_cs: qup-spi1-cs { + pins = "gpio7"; + function = "qup1"; }; - qup_spi2_default: qup-spi2-default { - mux { - pins = "gpio115", "gpio116", - "gpio117", "gpio118"; - function = "qup2"; - }; + qup_spi1_cs_gpio: qup-spi1-cs-gpio { + pins = "gpio7"; + function = "gpio"; + }; - config { - pins = "gpio115", "gpio116", - "gpio117", "gpio118"; - drive-strength = <6>; - bias-disable; - }; + qup_spi1_data_clk: qup-spi1-data-clk { + pins = "gpio4", "gpio5", + "gpio6"; + function = "qup1"; }; - qup_spi3_default: qup-spi3-default { - mux { - pins = "gpio119", "gpio120", - "gpio121", "gpio122"; - function = "qup3"; - }; + qup_spi2_cs: qup-spi2-cs { + pins = "gpio118"; + function = "qup2"; + }; - config { - pins = "gpio119", "gpio120", - "gpio121", "gpio122"; - drive-strength = <6>; - bias-disable; - }; + qup_spi2_cs_gpio: qup-spi2-cs-gpio { + pins = "gpio118"; + function = "gpio"; }; - qup_spi4_default: qup-spi4-default { - mux { - pins = "gpio8", "gpio9", - "gpio10", "gpio11"; - function = "qup4"; - }; + qup_spi2_data_clk: qup-spi2-data-clk { + pins = "gpio115", "gpio116", + "gpio117"; + function = "qup2"; + }; - config { - pins = "gpio8", "gpio9", - "gpio10", "gpio11"; - drive-strength = <6>; - bias-disable; - }; + qup_spi3_cs: qup-spi3-cs { + pins = "gpio122"; + function = "qup3"; }; - qup_spi5_default: qup-spi5-default { - mux { - pins = "gpio12", "gpio13", - "gpio14", "gpio15"; - function = "qup5"; - }; + qup_spi3_cs_gpio: qup-spi3-cs-gpio { + pins = "gpio122"; + function = "gpio"; + }; - config { - pins = "gpio12", "gpio13", - "gpio14", "gpio15"; - drive-strength = <6>; - bias-disable; - }; + qup_spi3_data_clk: qup-spi3-data-clk { + pins = "gpio119", "gpio120", + "gpio121"; + function = "qup3"; }; - qup_spi6_default: qup-spi6-default { - mux { - pins = "gpio16", "gpio17", - "gpio18", "gpio19"; - function = "qup6"; - }; + qup_spi4_cs: qup-spi4-cs { + pins = "gpio11"; + function = "qup4"; + }; - config { - pins = "gpio16", "gpio17", - "gpio18", "gpio19"; - drive-strength = <6>; - bias-disable; - }; + qup_spi4_cs_gpio: qup-spi4-cs-gpio { + pins = "gpio11"; + function = "gpio"; }; - qup_spi7_default: qup-spi7-default { - mux { - pins = "gpio20", "gpio21", - "gpio22", "gpio23"; - function = "qup7"; - }; + qup_spi4_data_clk: qup-spi4-data-clk { + pins = "gpio8", "gpio9", + "gpio10"; + function = "qup4"; + }; - config { - pins = "gpio20", "gpio21", - "gpio22", "gpio23"; - drive-strength = <6>; - bias-disable; - }; + qup_spi5_cs: qup-spi5-cs { + pins = "gpio15"; + function = "qup5"; }; - qup_spi8_default: qup-spi8-default { - mux { - pins = "gpio24", "gpio25", - "gpio26", "gpio27"; - function = "qup8"; - }; + qup_spi5_cs_gpio: qup-spi5-cs-gpio { + pins = "gpio15"; + function = "gpio"; + }; - config { - pins = "gpio24", "gpio25", - "gpio26", "gpio27"; - drive-strength = <6>; - bias-disable; - }; + qup_spi5_data_clk: qup-spi5-data-clk { + pins = "gpio12", "gpio13", + "gpio14"; + function = "qup5"; }; - qup_spi9_default: qup-spi9-default { - mux { - pins = "gpio125", "gpio126", - "gpio127", "gpio128"; - function = "qup9"; - }; + qup_spi6_cs: qup-spi6-cs { + pins = "gpio19"; + function = "qup6"; + }; - config { - pins = "gpio125", "gpio126", - "gpio127", "gpio128"; - drive-strength = <6>; - bias-disable; - }; + qup_spi6_cs_gpio: qup-spi6-cs-gpio { + pins = "gpio19"; + function = "gpio"; }; - qup_spi10_default: qup-spi10-default { - mux { - pins = "gpio129", "gpio130", - "gpio131", "gpio132"; - function = "qup10"; - }; + qup_spi6_data_clk: qup-spi6-data-clk { + pins = "gpio16", "gpio17", + "gpio18"; + function = "qup6"; + }; - config { - pins = "gpio129", "gpio130", - "gpio131", "gpio132"; - drive-strength = <6>; - bias-disable; - }; + qup_spi7_cs: qup-spi7-cs { + pins = "gpio23"; + function = "qup7"; }; - qup_spi11_default: qup-spi11-default { - mux { - pins = "gpio60", "gpio61", - "gpio62", "gpio63"; - function = "qup11"; - }; + qup_spi7_cs_gpio: qup-spi7-cs-gpio { + pins = "gpio23"; + function = "gpio"; + }; - config { - pins = "gpio60", "gpio61", - "gpio62", "gpio63"; - drive-strength = <6>; - bias-disable; - }; + qup_spi7_data_clk: qup-spi7-data-clk { + pins = "gpio20", "gpio21", + "gpio22"; + function = "qup7"; }; - qup_spi12_default: qup-spi12-default { - mux { - pins = "gpio32", "gpio33", - "gpio34", "gpio35"; - function = "qup12"; - }; + qup_spi8_cs: qup-spi8-cs { + pins = "gpio27"; + function = "qup8"; + }; - config { - pins = "gpio32", "gpio33", - "gpio34", "gpio35"; - drive-strength = <6>; - bias-disable; - }; + qup_spi8_cs_gpio: qup-spi8-cs-gpio { + pins = "gpio27"; + function = "gpio"; }; - qup_spi13_default: qup-spi13-default { - mux { - pins = "gpio36", "gpio37", - "gpio38", "gpio39"; - function = "qup13"; - }; + qup_spi8_data_clk: qup-spi8-data-clk { + pins = "gpio24", "gpio25", + "gpio26"; + function = "qup8"; + }; - config { - pins = "gpio36", "gpio37", - "gpio38", "gpio39"; - drive-strength = <6>; - bias-disable; - }; + qup_spi9_cs: qup-spi9-cs { + pins = "gpio128"; + function = "qup9"; }; - qup_spi14_default: qup-spi14-default { - mux { - pins = "gpio40", "gpio41", - "gpio42", "gpio43"; - function = "qup14"; - }; + qup_spi9_cs_gpio: qup-spi9-cs-gpio { + pins = "gpio128"; + function = "gpio"; + }; - config { - pins = "gpio40", "gpio41", - "gpio42", "gpio43"; - drive-strength = <6>; - bias-disable; - }; + qup_spi9_data_clk: qup-spi9-data-clk { + pins = "gpio125", "gpio126", + "gpio127"; + function = "qup9"; }; - qup_spi15_default: qup-spi15-default { - mux { - pins = "gpio44", "gpio45", - "gpio46", "gpio47"; - function = "qup15"; - }; + qup_spi10_cs: qup-spi10-cs { + pins = "gpio132"; + function = "qup10"; + }; - config { - pins = "gpio44", "gpio45", - "gpio46", "gpio47"; - drive-strength = <6>; - bias-disable; - }; + qup_spi10_cs_gpio: qup-spi10-cs-gpio { + pins = "gpio132"; + function = "gpio"; }; - qup_spi16_default: qup-spi16-default { - mux { - pins = "gpio48", "gpio49", - "gpio50", "gpio51"; - function = "qup16"; - }; + qup_spi10_data_clk: qup-spi10-data-clk { + pins = "gpio129", "gpio130", + "gpio131"; + function = "qup10"; + }; - config { - pins = "gpio48", "gpio49", - "gpio50", "gpio51"; - drive-strength = <6>; - bias-disable; - }; + qup_spi11_cs: qup-spi11-cs { + pins = "gpio63"; + function = "qup11"; }; - qup_spi17_default: qup-spi17-default { - mux { - pins = "gpio52", "gpio53", - "gpio54", "gpio55"; - function = "qup17"; - }; + qup_spi11_cs_gpio: qup-spi11-cs-gpio { + pins = "gpio63"; + function = "gpio"; + }; - config { - pins = "gpio52", "gpio53", - "gpio54", "gpio55"; - drive-strength = <6>; - bias-disable; - }; + qup_spi11_data_clk: qup-spi11-data-clk { + pins = "gpio60", "gpio61", + "gpio62"; + function = "qup11"; }; - qup_spi18_default: qup-spi18-default { - mux { - pins = "gpio56", "gpio57", - "gpio58", "gpio59"; - function = "qup18"; - }; + qup_spi12_cs: qup-spi12-cs { + pins = "gpio35"; + function = "qup12"; + }; - config { - pins = "gpio56", "gpio57", - "gpio58", "gpio59"; - drive-strength = <6>; - bias-disable; - }; + qup_spi12_cs_gpio: qup-spi12-cs-gpio { + pins = "gpio35"; + function = "gpio"; }; - qup_spi19_default: qup-spi19-default { - mux { - pins = "gpio0", "gpio1", - "gpio2", "gpio3"; - function = "qup19"; - }; + qup_spi12_data_clk: qup-spi12-data-clk { + pins = "gpio32", "gpio33", + "gpio34"; + function = "qup12"; + }; - config { - pins = "gpio0", "gpio1", - "gpio2", "gpio3"; - drive-strength = <6>; - bias-disable; - }; + qup_spi13_cs: qup-spi13-cs { + pins = "gpio39"; + function = "qup13"; + }; + + qup_spi13_cs_gpio: qup-spi13-cs-gpio { + pins = "gpio39"; + function = "gpio"; + }; + + qup_spi13_data_clk: qup-spi13-data-clk { + pins = "gpio36", "gpio37", + "gpio38"; + function = "qup13"; + }; + + qup_spi14_cs: qup-spi14-cs { + pins = "gpio43"; + function = "qup14"; + }; + + qup_spi14_cs_gpio: qup-spi14-cs-gpio { + pins = "gpio43"; + function = "gpio"; + }; + + qup_spi14_data_clk: qup-spi14-data-clk { + pins = "gpio40", "gpio41", + "gpio42"; + function = "qup14"; + }; + + qup_spi15_cs: qup-spi15-cs { + pins = "gpio47"; + function = "qup15"; + }; + + qup_spi15_cs_gpio: qup-spi15-cs-gpio { + pins = "gpio47"; + function = "gpio"; + }; + + qup_spi15_data_clk: qup-spi15-data-clk { + pins = "gpio44", "gpio45", + "gpio46"; + function = "qup15"; + }; + + qup_spi16_cs: qup-spi16-cs { + pins = "gpio51"; + function = "qup16"; + }; + + qup_spi16_cs_gpio: qup-spi16-cs-gpio { + pins = "gpio51"; + function = "gpio"; + }; + + qup_spi16_data_clk: qup-spi16-data-clk { + pins = "gpio48", "gpio49", + "gpio50"; + function = "qup16"; + }; + + qup_spi17_cs: qup-spi17-cs { + pins = "gpio55"; + function = "qup17"; + }; + + qup_spi17_cs_gpio: qup-spi17-cs-gpio { + pins = "gpio55"; + function = "gpio"; + }; + + qup_spi17_data_clk: qup-spi17-data-clk { + pins = "gpio52", "gpio53", + "gpio54"; + function = "qup17"; + }; + + qup_spi18_cs: qup-spi18-cs { + pins = "gpio59"; + function = "qup18"; + }; + + qup_spi18_cs_gpio: qup-spi18-cs-gpio { + pins = "gpio59"; + function = "gpio"; + }; + + qup_spi18_data_clk: qup-spi18-data-clk { + pins = "gpio56", "gpio57", + "gpio58"; + function = "qup18"; + }; + + qup_spi19_cs: qup-spi19-cs { + pins = "gpio3"; + function = "qup19"; + }; + + qup_spi19_cs_gpio: qup-spi19-cs-gpio { + pins = "gpio3"; + function = "gpio"; + }; + + qup_spi19_data_clk: qup-spi19-data-clk { + pins = "gpio0", "gpio1", + "gpio2"; + function = "qup19"; }; qup_uart2_default: qup-uart2-default { @@ -3754,7 +3806,7 @@ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>, - <GIC_PPI 12 + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8350-hdk.dts b/arch/arm64/boot/dts/qcom/sm8350-hdk.dts new file mode 100644 index 0000000000000000000000000000000000000000..f23a0cf3f7b754e22d685519b0e1ba89bc7e5e11 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8350-hdk.dts @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2020-2021, Linaro Limited + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/regulator/qcom,rpmh-regulator.h> +#include "sm8350.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8350 HDK"; + compatible = "qcom,sm8350-hdk", "qcom,sm8350"; + + aliases { + serial0 = &uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + 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; + }; +}; + +&adsp { + status = "okay"; + firmware-name = "qcom/sm8350/adsp.mbn"; +}; + +&apps_rsc { + pm8350-rpmh-regulators { + compatible = "qcom,pm8350-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-s11-supply = <&vph_pwr>; + vdd-s12-supply = <&vph_pwr>; + + vdd-l1-l4-supply = <&vreg_s11b_0p95>; + vdd-l2-l7-supply = <&vreg_bob>; + vdd-l3-l5-supply = <&vreg_bob>; + vdd-l6-l9-l10-supply = <&vreg_s11b_0p95>; + + vreg_s10b_1p8: smps10 { + regulator-name = "vreg_s10b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_s11b_0p95: smps11 { + regulator-name = "vreg_s11b_0p95"; + regulator-min-microvolt = <952000>; + regulator-max-microvolt = <952000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_s12b_1p25: smps12 { + regulator-name = "vreg_s12b_1p25"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1256000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l1b_0p88: ldo1 { + regulator-name = "vreg_l1b_0p88"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l2b_3p07: ldo2 { + regulator-name = "vreg_l2b_3p07"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l3b_0p9: ldo3 { + regulator-name = "vreg_l3b_0p9"; + regulator-min-microvolt = <904000>; + regulator-max-microvolt = <904000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l5b_0p88: ldo5 { + regulator-name = "vreg_l5b_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <888000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-allow-set-load; + }; + + vreg_l6b_1p2: ldo6 { + regulator-name = "vreg_l6b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1208000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-allow-set-load; + }; + + vreg_l7b_2p96: ldo7 { + regulator-name = "vreg_l7b_2p96"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-allow-set-load; + }; + + vreg_l9b_1p2: ldo9 { + regulator-name = "vreg_l9b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + regulator-allow-set-load; + }; + }; + + pm8350c-rpmh-regulators { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + + vdd-l1-l12-supply = <&vreg_s1c_1p86>; + vdd-l2-l8-supply = <&vreg_s1c_1p86>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>; + vdd-l6-l9-l11-supply = <&vreg_bob>; + vdd-l10-supply = <&vreg_s12b_1p25>; + + vdd-bob-supply = <&vph_pwr>; + + vreg_s1c_1p86: smps1 { + regulator-name = "vreg_s1c_1p86"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <1880000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-name = "vreg_l1c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l2c_1p8: ldo2 { + regulator-name = "vreg_l2c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l6c_1p8: ldo6 { + regulator-name = "vreg_l6c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l9c_2p96: ldo9 { + regulator-name = "vreg_l9c_2p96"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + + vreg_l10c_1p2: ldo10 { + regulator-name = "vreg_l10c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; + }; + }; +}; + +&cdsp { + status = "okay"; + firmware-name = "qcom/sm8350/cdsp.mbn"; +}; + +&mpss { + status = "okay"; + firmware-name = "qcom/sm8350/modem.mbn"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&slpi { + status = "okay"; + firmware-name = "qcom/sm8350/slpi.mbn"; +}; + +&tlmm { + gpio-reserved-ranges = <52 8>; +}; + +&uart2 { + status = "okay"; +}; + +&ufs_mem_hc { + status = "okay"; + + reset-gpios = <&tlmm 203 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b_2p96>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <900000>; +}; + +&ufs_mem_phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l5b_0p88>; + vdda-max-microamp = <91600>; + vdda-pll-supply = <&vreg_l6b_1p2>; + vdda-pll-max-microamp = <19000>; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + /* TODO: Define USB-C connector properly */ + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + status = "okay"; + + vdda-pll-supply = <&vreg_l5b_0p88>; + vdda18-supply = <&vreg_l1c_1p8>; + vdda33-supply = <&vreg_l2b_3p07>; +}; + +&usb_1_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l1b_0p88>; +}; + +&usb_2 { + status = "okay"; +}; + +&usb_2_dwc3 { + dr_mode = "host"; + + pinctrl-names = "default"; + pinctrl-0 = <&usb_hub_enabled_state>; +}; + +&usb_2_hsphy { + status = "okay"; + + vdda-pll-supply = <&vreg_l5b_0p88>; + vdda18-supply = <&vreg_l1c_1p8>; + vdda33-supply = <&vreg_l2b_3p07>; +}; + +&usb_2_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l5b_0p88>; +}; + +/* PINCTRL - additions to nodes defined in sm8350.dtsi */ + +&tlmm { + usb_hub_enabled_state: usb-hub-enabled-state { + pins = "gpio42"; + function = "gpio"; + + drive-strength = <2>; + output-low; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8350-mtp.dts b/arch/arm64/boot/dts/qcom/sm8350-mtp.dts index 8923657579fbbd927c9b71d40fd22ad17ee07efa..6ca638b4e321318753e14911c1de1d059c030508 100644 --- a/arch/arm64/boot/dts/qcom/sm8350-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8350-mtp.dts @@ -5,8 +5,15 @@ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> #include "sm8350.dtsi" +#include "pm8350.dtsi" +#include "pm8350b.dtsi" +#include "pm8350c.dtsi" +#include "pmk8350.dtsi" +#include "pmr735a.dtsi" +#include "pmr735b.dtsi" / { model = "Qualcomm Technologies, Inc. sm8350 MTP"; @@ -31,6 +38,11 @@ }; }; +&adsp { + status = "okay"; + firmware-name = "qcom/sm8350/adsp.mbn"; +}; + &apps_rsc { pm8350-rpmh-regulators { compatible = "qcom,pm8350-rpmh-regulators"; @@ -56,57 +68,67 @@ vdd-l8-supply = <&vreg_s2c_0p8>; vreg_s10b_1p8: smps10 { + regulator-name = "vreg_s10b_1p8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; vreg_s11b_0p95: smps11 { + regulator-name = "vreg_s11b_0p95"; regulator-min-microvolt = <752000>; regulator-max-microvolt = <1000000>; }; vreg_s12b_1p25: smps12 { + regulator-name = "vreg_s12b_1p25"; regulator-min-microvolt = <1224000>; regulator-max-microvolt = <1360000>; }; vreg_l1b_0p88: ldo1 { + regulator-name = "vreg_l1b_0p88"; regulator-min-microvolt = <912000>; regulator-max-microvolt = <920000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l2b_3p07: ldo2 { + regulator-name = "vreg_l2b_3p07"; regulator-min-microvolt = <3072000>; regulator-max-microvolt = <3072000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l3b_0p9: ldo3 { + regulator-name = "vreg_l3b_0p9"; regulator-min-microvolt = <904000>; regulator-max-microvolt = <904000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l5b_0p88: ldo5 { + regulator-name = "vreg_l3b_0p9"; regulator-min-microvolt = <880000>; regulator-max-microvolt = <888000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l6b_1p2: ldo6 { + regulator-name = "vreg_l6b_1p2"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1208000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l7b_2p96: ldo7 { + regulator-name = "vreg_l7b_2p96"; regulator-min-microvolt = <2400000>; regulator-max-microvolt = <3008000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l9b_1p2: ldo9 { + regulator-name = "vreg_l9b_1p2"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; @@ -137,99 +159,116 @@ vdd-bob-supply = <&vph_pwr>; vreg_s1c_1p86: smps1 { + regulator-name = "vreg_s1c_1p86"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1952000>; }; vreg_s2c_0p8: smps2 { + regulator-name = "vreg_s2c_0p8"; regulator-min-microvolt = <640000>; regulator-max-microvolt = <1000000>; }; vreg_s10c_1p05: smps10 { + regulator-name = "vreg_s10c_1p05"; regulator-min-microvolt = <1048000>; regulator-max-microvolt = <1128000>; }; vreg_bob: bob { + regulator-name = "vreg_bob"; regulator-min-microvolt = <3008000>; regulator-max-microvolt = <3960000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>; }; vreg_l1c_1p8: ldo1 { + regulator-name = "vreg_l1c_1p8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l2c_1p8: ldo2 { + regulator-name = "vreg_l2c_1p8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l3c_3p0: ldo3 { + regulator-name = "vreg_l3c_3p0"; regulator-min-microvolt = <3008000>; regulator-max-microvolt = <3008000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l4c_uim1: ldo4 { + regulator-name = "vreg_l4c_uim1"; regulator-min-microvolt = <1704000>; regulator-max-microvolt = <3000000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l5c_uim2: ldo5 { + regulator-name = "vreg_l5c_uim2"; regulator-min-microvolt = <1704000>; regulator-max-microvolt = <3000000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l6c_1p8: ldo6 { + regulator-name = "vreg_l6c_1p8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2960000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l7c_3p0: ldo7 { + regulator-name = "vreg_l7c_3p0"; regulator-min-microvolt = <3008000>; regulator-max-microvolt = <3008000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l8c_1p8: ldo8 { + regulator-name = "vreg_l8c_1p8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l9c_2p96: ldo9 { + regulator-name = "vreg_l9c_2p96"; regulator-min-microvolt = <2960000>; regulator-max-microvolt = <3008000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l10c_1p2: ldo10 { + regulator-name = "vreg_l10c_1p2"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l11c_2p96: ldo11 { + regulator-name = "vreg_l11c_2p96"; regulator-min-microvolt = <2400000>; regulator-max-microvolt = <3008000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l12c_1p8: ldo12 { + regulator-name = "vreg_l12c_1p8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2000000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; }; vreg_l13c_3p0: ldo13 { + regulator-name = "vreg_l13c_3p0"; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>; @@ -237,10 +276,25 @@ }; }; +&cdsp { + status = "okay"; + firmware-name = "qcom/sm8350/cdsp.mbn"; +}; + +&mpss { + status = "okay"; + firmware-name = "qcom/sm8350/modem.mbn"; +}; + &qupv3_id_1 { status = "okay"; }; +&slpi { + status = "okay"; + firmware-name = "qcom/sm8350/slpi.mbn"; +}; + &tlmm { gpio-reserved-ranges = <52 8>; }; @@ -248,3 +302,65 @@ &uart2 { status = "okay"; }; + +&ufs_mem_hc { + status = "okay"; + + reset-gpios = <&tlmm 203 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b_2p96>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <900000>; +}; + +&ufs_mem_phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l5b_0p88>; + vdda-max-microamp = <91600>; + vdda-pll-supply = <&vreg_l6b_1p2>; + vdda-pll-max-microamp = <19000>; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + status = "okay"; + + vdda-pll-supply = <&vreg_l5b_0p88>; + vdda18-supply = <&vreg_l1c_1p8>; + vdda33-supply = <&vreg_l2b_3p07>; +}; + +&usb_1_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l1b_0p88>; +}; + +&usb_2 { + status = "okay"; +}; + +&usb_2_hsphy { + status = "okay"; + + vdda-pll-supply = <&vreg_l5b_0p88>; + vdda18-supply = <&vreg_l1c_1p8>; + vdda33-supply = <&vreg_l2b_3p07>; +}; + +&usb_2_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l5b_0p88>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index 5ef460458f5c374a2d03733109a7d3c17761e506..ed0b51bc03ea7aa7fe443584e8d3e04ffa9accf6 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -1,14 +1,16 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) 2020, Linaro Limaited + * Copyright (c) 2020, Linaro Limited */ #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/clock/qcom,gcc-sm8350.h> #include <dt-bindings/clock/qcom,rpmh.h> #include <dt-bindings/mailbox/qcom-ipcc.h> #include <dt-bindings/power/qcom-aoss-qmp.h> #include <dt-bindings/power/qcom-rpmpd.h> #include <dt-bindings/soc/qcom,rpmh-rsc.h> +#include <dt-bindings/thermal/thermal.h> / { interrupt-parent = <&intc>; @@ -43,6 +45,8 @@ reg = <0x0 0x0>; enable-method = "psci"; next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_0: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -58,6 +62,8 @@ reg = <0x0 0x100>; enable-method = "psci"; next-level-cache = <&L2_100>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_100: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -70,6 +76,8 @@ reg = <0x0 0x200>; enable-method = "psci"; next-level-cache = <&L2_200>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_200: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -82,6 +90,8 @@ reg = <0x0 0x300>; enable-method = "psci"; next-level-cache = <&L2_300>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_300: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -94,6 +104,8 @@ reg = <0x0 0x400>; enable-method = "psci"; next-level-cache = <&L2_400>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_400: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -106,6 +118,8 @@ reg = <0x0 0x500>; enable-method = "psci"; next-level-cache = <&L2_500>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_500: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -119,6 +133,8 @@ reg = <0x0 0x600>; enable-method = "psci"; next-level-cache = <&L2_600>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_600: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -131,6 +147,8 @@ reg = <0x0 0x700>; enable-method = "psci"; next-level-cache = <&L2_700>; + qcom,freq-domain = <&cpufreq_hw 2>; + #cooling-cells = <2>; L2_700: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -153,7 +171,7 @@ pmu { compatible = "arm,armv8-pmuv3"; - interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; }; psci { @@ -257,6 +275,15 @@ no-map; }; + rmtfs_mem: memory@9b800000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0x9b800000 0x0 0x280000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = <15>; + }; + hyp_reserved_mem: memory@d0000000 { reg = <0x0 0xd0000000 0x0 0x800000>; no-map; @@ -294,6 +321,102 @@ hwlocks = <&tcsr_mutex 3>; }; + smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + smp2p_adsp_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_adsp_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + smp2p_cdsp_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_cdsp_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + smp2p_modem_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_modem_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-slpi { + compatible = "qcom,smp2p"; + qcom,smem = <481>, <430>; + interrupts-extended = <&ipcc IPCC_CLIENT_SLPI + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_SLPI + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <3>; + + smp2p_slpi_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_slpi_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + soc: soc@0 { #address-cells = <2>; #size-cells = <2>; @@ -324,8 +447,8 @@ compatible = "qcom,geni-se-qup"; reg = <0x0 0x009c0000 0x0 0x6000>; clock-names = "m-ahb", "s-ahb"; - clocks = <&gcc 121>, - <&gcc 122>; + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -335,7 +458,7 @@ compatible = "qcom,geni-debug-uart"; reg = <0 0x0098c000 0 0x4000>; clock-names = "se"; - clocks = <&gcc 83>; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; pinctrl-names = "default"; pinctrl-0 = <&qup_uart3_default_state>; interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>; @@ -345,12 +468,215 @@ }; }; + apps_smmu: iommu@15000000 { + compatible = "qcom,sm8350-smmu-500", "arm,mmu-500"; + reg = <0 0x15000000 0 0x100000>; + #iommu-cells = <2>; + #global-interrupts = <2>; + interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 412 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 690 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 691 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 692 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 693 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 694 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 695 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 697 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 707 IRQ_TYPE_LEVEL_HIGH>; + }; + + config_noc: interconnect@1500000 { + compatible = "qcom,sm8350-config-noc"; + reg = <0 0x01500000 0 0xa580>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect@1580000 { + compatible = "qcom,sm8350-mc-virt"; + reg = <0 0x01580000 0 0x1000>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,sm8350-system-noc"; + reg = <0 0x01680000 0 0x1c200>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sm8350-aggre1-noc"; + reg = <0 0x016e0000 0 0x1f180>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre2_noc: interconnect@1700000 { + compatible = "qcom,sm8350-aggre2-noc"; + reg = <0 0x01700000 0 0x33000>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mmss_noc: interconnect@1740000 { + compatible = "qcom,sm8350-mmss-noc"; + reg = <0 0x01740000 0 0x1f080>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + lpass_ag_noc: interconnect@3c40000 { + compatible = "qcom,sm8350-lpass-ag-noc"; + reg = <0 0x03c40000 0 0xf080>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + compute_noc: interconnect@a0c0000{ + compatible = "qcom,sm8350-compute-noc"; + reg = <0 0x0a0c0000 0 0xa180>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; #hwlock-cells = <1>; }; + mpss: remoteproc@4080000 { + compatible = "qcom,sm8350-mpss-pas"; + reg = <0x0 0x04080000 0x0 0x4040>; + + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, + <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 3 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&aoss_qmp AOSS_QMP_LS_MODEM>, + <&rpmhpd 0>, + <&rpmhpd 12>; + power-domain-names = "load_state", "cx", "mss"; + + interconnects = <&mc_virt 0 &mc_virt 1>; + + memory-region = <&pil_modem_mem>; + + qcom,smem-states = <&smp2p_modem_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>; + label = "modem"; + qcom,remote-pid = <1>; + }; + }; + pdc: interrupt-controller@b220000 { compatible = "qcom,sm8350-pdc", "qcom,pdc"; reg = <0 0x0b220000 0 0x30000>, <0 0x17c000f0 0 0x60>; @@ -363,7 +689,29 @@ interrupt-controller; }; - aoss_qmp: qmp@c300000 { + tsens0: thermal-sensor@c222000 { + compatible = "qcom,sm8350-tsens", "qcom,tsens-v2"; + reg = <0 0x0c263000 0 0x1ff>, /* TM */ + <0 0x0c222000 0 0x8>; /* SROT */ + #qcom,sensors = <15>; + interrupts = <&pdc 26 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 28 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c223000 { + compatible = "qcom,sm8350-tsens", "qcom,tsens-v2"; + reg = <0 0x0c265000 0 0x1ff>, /* TM */ + <0 0x0c223000 0 0x8>; /* SROT */ + #qcom,sensors = <14>; + interrupts = <&pdc 27 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 29 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + aoss_qmp: power-controller@c300000 { compatible = "qcom,sm8350-aoss-qmp"; reg = <0 0x0c300000 0 0x100000>; interrupts-extended = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP @@ -374,6 +722,24 @@ #power-domain-cells = <1>; }; + spmi_bus: spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x0 0xc440000 0x0 0x1100>, + <0x0 0xc600000 0x0 0x2000000>, + <0x0 0xe600000 0x0 0x100000>, + <0x0 0xe700000 0x0 0xa0000>, + <0x0 0xc40a000 0x0 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + }; + tlmm: pinctrl@f100000 { compatible = "qcom,sm8350-tlmm"; reg = <0 0x0f100000 0 0x300000>; @@ -382,7 +748,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - gpio-ranges = <&tlmm 0 0 203>; + gpio-ranges = <&tlmm 0 0 204>; qup_uart3_default_state: qup-uart3-default-state { rx { @@ -396,6 +762,13 @@ }; }; + rng: rng@10d3000 { + compatible = "qcom,prng-ee"; + reg = <0 0x010d3000 0 0x1000>; + clocks = <&rpmhcc RPMH_HWKM_CLK>; + clock-names = "core"; + }; + intc: interrupt-controller@17a00000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; @@ -486,6 +859,1256 @@ clocks = <&xo_board>; }; + rpmhpd: power-controller { + compatible = "qcom,sm8350-rpmhpd"; + #power-domain-cells = <1>; + operating-points-v2 = <&rpmhpd_opp_table>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp1 { + opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>; + }; + + rpmhpd_opp_min_svs: opp2 { + opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>; + }; + + rpmhpd_opp_low_svs: opp3 { + opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>; + }; + + rpmhpd_opp_svs: opp4 { + opp-level = <RPMH_REGULATOR_LEVEL_SVS>; + }; + + rpmhpd_opp_svs_l1: opp5 { + opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>; + }; + + rpmhpd_opp_nom: opp6 { + opp-level = <RPMH_REGULATOR_LEVEL_NOM>; + }; + + rpmhpd_opp_nom_l1: opp7 { + opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>; + }; + + rpmhpd_opp_nom_l2: opp8 { + opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>; + }; + + rpmhpd_opp_turbo: opp9 { + opp-level = <RPMH_REGULATOR_LEVEL_TURBO>; + }; + + rpmhpd_opp_turbo_l1: opp10 { + opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>; + }; + }; + }; + + apps_bcm_voter: bcm_voter { + compatible = "qcom,bcm-voter"; + }; + }; + + cpufreq_hw: cpufreq@18591000 { + compatible = "qcom,sm8350-cpufreq-epss", "qcom,cpufreq-epss"; + reg = <0 0x18591000 0 0x1000>, + <0 0x18592000 0 0x1000>, + <0 0x18593000 0 0x1000>; + reg-names = "freq-domain0", "freq-domain1", "freq-domain2"; + + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + + #freq-domain-cells = <1>; + }; + + ufs_mem_hc: ufshc@1d84000 { + compatible = "qcom,sm8350-ufshc", "qcom,ufshc", + "jedec,ufs-2.0"; + reg = <0 0x01d84000 0 0x3000>; + interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>; + phys = <&ufs_mem_phy_lanes>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + #reset-cells = <1>; + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + power-domains = <&gcc UFS_PHY_GDSC>; + + iommus = <&apps_smmu 0xe0 0x0>; + + clock-names = + "ref_clk", + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + clocks = + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + freq-table-hz = + <75000000 300000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <75000000 300000000>, + <0 0>, + <0 0>, + <75000000 300000000>, + <75000000 300000000>; + status = "disabled"; + }; + + ufs_mem_phy: phy@1d87000 { + compatible = "qcom,sm8350-qmp-ufs-phy"; + reg = <0 0x01d87000 0 0xe10>; + #address-cells = <2>; + #size-cells = <2>; + #clock-cells = <1>; + ranges; + clock-names = "ref", + "ref_aux"; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + status = "disabled"; + + ufs_mem_phy_lanes: lanes@1d87400 { + reg = <0 0x01d87400 0 0x108>, + <0 0x01d87600 0 0x1e0>, + <0 0x01d87c00 0 0x1dc>, + <0 0x01d87800 0 0x108>, + <0 0x01d87a00 0 0x1e0>; + #phy-cells = <0>; + #clock-cells = <0>; + }; + }; + + slpi: remoteproc@5c00000 { + compatible = "qcom,sm8350-slpi-pas"; + reg = <0 0x05c00000 0 0x4000>; + + interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + <&smp2p_slpi_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_slpi_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_slpi_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_slpi_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&aoss_qmp AOSS_QMP_LS_SLPI>, + <&rpmhpd 4>, + <&rpmhpd 5>; + power-domain-names = "load_state", "lcx", "lmx"; + + memory-region = <&pil_slpi_mem>; + + qcom,smem-states = <&smp2p_slpi_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_SLPI + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_SLPI + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "slpi"; + qcom,remote-pid = <3>; + + }; + }; + + cdsp: remoteproc@98900000 { + compatible = "qcom,sm8350-cdsp-pas"; + reg = <0 0x098900000 0 0x1400000>; + + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&aoss_qmp AOSS_QMP_LS_CDSP>, + <&rpmhpd 0>, + <&rpmhpd 10>; + power-domain-names = "load_state", "cx", "mxc"; + + interconnects = <&compute_noc 1 &mc_virt 1>; + + memory-region = <&pil_cdsp_mem>; + + qcom,smem-states = <&smp2p_cdsp_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "cdsp"; + qcom,remote-pid = <5>; + }; + }; + + usb_1_hsphy: phy@88e3000 { + compatible = "qcom,sm8350-usb-hs-phy", + "qcom,usb-snps-hs-7nm-phy"; + reg = <0 0x088e3000 0 0x400>; + status = "disabled"; + #phy-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + }; + + usb_2_hsphy: phy@88e4000 { + compatible = "qcom,sm8250-usb-hs-phy", + "qcom,usb-snps-hs-7nm-phy"; + reg = <0 0x088e4000 0 0x400>; + status = "disabled"; + #phy-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_SEC_BCR>; + }; + + usb_1_qmpphy: phy-wrapper@88e9000 { + compatible = "qcom,sm8350-qmp-usb3-phy"; + reg = <0 0x088e9000 0 0x200>, + <0 0x088e8000 0 0x20>; + reg-names = "reg-base", "dp_com"; + status = "disabled"; + #clock-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + clock-names = "aux", "ref_clk_src", "com_aux"; + + resets = <&gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + + usb_1_ssphy: phy@88e9200 { + reg = <0 0x088e9200 0 0x200>, + <0 0x088e9400 0 0x200>, + <0 0x088e9c00 0 0x400>, + <0 0x088e9600 0 0x200>, + <0 0x088e9800 0 0x200>, + <0 0x088e9a00 0 0x100>; + #phy-cells = <0>; + #clock-cells = <1>; + clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "pipe0"; + clock-output-names = "usb3_phy_pipe_clk_src"; + }; + }; + + usb_2_qmpphy: phy-wrapper@88eb000 { + compatible = "qcom,sm8350-qmp-usb3-uni-phy"; + reg = <0 0x088eb000 0 0x200>; + status = "disabled"; + #clock-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_EN>, + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; + clock-names = "aux", "ref_clk_src", "ref", "com_aux"; + + resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, + <&gcc GCC_USB3_PHY_SEC_BCR>; + reset-names = "phy", "common"; + + usb_2_ssphy: phy@88ebe00 { + reg = <0 0x088ebe00 0 0x200>, + <0 0x088ec000 0 0x200>, + <0 0x088eb200 0 0x1100>; + #phy-cells = <0>; + #clock-cells = <1>; + clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "pipe0"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + }; + }; + + dc_noc: interconnect@90e0000 { + compatible = "qcom,sm8350-dc-noc"; + reg = <0 0x090c0000 0 0x4200>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + gem_noc: interconnect@9100000 { + compatible = "qcom,sm8350-gem-noc"; + reg = <0 0x09100000 0 0xb4000>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + usb_1: usb@a6f8800 { + compatible = "qcom,sm8350-dwc3", "qcom,dwc3"; + reg = <0 0x0a6f8800 0 0x400>; + status = "disabled"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>; + clock-names = "cfg_noc", "core", "iface", "mock_utmi", + "sleep"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", + "dm_hs_phy_irq", "ss_phy_irq"; + + power-domains = <&gcc USB30_PRIM_GDSC>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + + usb_1_dwc3: dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0 0x0a600000 0 0xcd00>; + interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; + iommus = <&apps_smmu 0x0 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + phys = <&usb_1_hsphy>, <&usb_1_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; + + usb_2: usb@a8f8800 { + compatible = "qcom,sm8350-dwc3", "qcom,dwc3"; + reg = <0 0x0a8f8800 0 0x400>; + status = "disabled"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, + <&gcc GCC_USB30_SEC_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_SEC_SLEEP_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_EN>; + clock-names = "cfg_noc", "core", "iface", "mock_utmi", + "sleep", "xo"; + + assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_SEC_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 12 IRQ_TYPE_EDGE_BOTH>, + <&pdc 13 IRQ_TYPE_EDGE_BOTH>, + <&pdc 16 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", + "dm_hs_phy_irq", "ss_phy_irq"; + + power-domains = <&gcc USB30_SEC_GDSC>; + + resets = <&gcc GCC_USB30_SEC_BCR>; + + usb_2_dwc3: dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0 0x0a800000 0 0xcd00>; + interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; + iommus = <&apps_smmu 0x20 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; + + adsp: remoteproc@17300000 { + compatible = "qcom,sm8350-adsp-pas"; + reg = <0 0x17300000 0 0x100>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&aoss_qmp AOSS_QMP_LS_LPASS>, + <&rpmhpd 4>, + <&rpmhpd 5>; + power-domain-names = "load_state", "lcx", "lmx"; + + memory-region = <&pil_adsp_mem>; + + qcom,smem-states = <&smp2p_adsp_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "lpass"; + qcom,remote-pid = <2>; + }; + }; + }; + + thermal-zones { + cpu0-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 1>; + + trips { + cpu0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu1-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 2>; + + trips { + cpu1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu2-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 3>; + + trips { + cpu2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu3-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 4>; + + trips { + cpu3_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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-top-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 7>; + + trips { + cpu4_top_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_top_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_top_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu5-top-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 8>; + + trips { + cpu5_top_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_top_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_top_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu6-top-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 9>; + + trips { + cpu6_top_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_top_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_top_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu7-top-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 10>; + + trips { + cpu7_top_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_top_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_top_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu4-bottom-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 11>; + + trips { + cpu4_bottom_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_bottom_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_bottom_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu5-bottom-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 12>; + + trips { + cpu5_bottom_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_bottom_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_bottom_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu6-bottom-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 13>; + + trips { + cpu6_bottom_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_bottom_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_bottom_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + cpu7-bottom-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 14>; + + trips { + cpu7_bottom_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_bottom_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_bottom_crit: cpu_crit { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + 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>; + }; + 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>; + }; + }; + }; + + aoss0-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 0>; + + trips { + aoss0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + cluster0-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 5>; + + trips { + cluster0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + cluster0_crit: cluster0_crit { + temperature = <110000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + cluster1-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens0 6>; + + trips { + cluster1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + cluster1_crit: cluster1_crit { + temperature = <110000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + aoss1-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 0>; + + trips { + aoss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + gpu-thermal-top { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 1>; + + trips { + gpu1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + }; + + gpu-thermal-bottom { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 2>; + + trips { + gpu2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + }; + + nspss1-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 3>; + + trips { + nspss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + }; + + nspss2-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 4>; + + trips { + nspss2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + }; + + nspss3-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 5>; + + trips { + nspss3_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + }; + + video-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 6>; + + trips { + video_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + mem-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 7>; + + trips { + mem_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + modem1-thermal-top { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 8>; + + trips { + modem1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + modem2-thermal-top { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 9>; + + trips { + modem2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + modem3-thermal-top { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 10>; + + trips { + modem3_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + modem4-thermal-top { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 11>; + + trips { + modem4_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + camera-thermal-top { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 12>; + + trips { + camera1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + camera-thermal-bottom { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&tsens1 13>; + + trips { + camera2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi b/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi index 30c169b08536a59d38fbd3df6c29f5d0eee27fab..d8046fedf9c129290010440b168771d4e56cd541 100644 --- a/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi +++ b/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi @@ -615,7 +615,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -639,7 +639,7 @@ bitclock-master = <&rsnd_endpoint0>; frame-master = <&rsnd_endpoint0>; - playback = <&ssi1 &dvc1 &src1>; + playback = <&ssi1>, <&dvc1>, <&src1>; capture = <&ssi0>; }; }; diff --git a/arch/arm64/boot/dts/renesas/hihope-common.dtsi b/arch/arm64/boot/dts/renesas/hihope-common.dtsi index 7a3da9b06f677f0caa52ba604dda4dbfed3eeac1..0c7e6f79059020ff9f49d163c8c68310e0c18f9d 100644 --- a/arch/arm64/boot/dts/renesas/hihope-common.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-common.dtsi @@ -12,6 +12,9 @@ aliases { serial0 = &scif2; serial1 = &hscif0; + mmc0 = &sdhi3; + mmc1 = &sdhi0; + mmc2 = &sdhi2; }; chosen { diff --git a/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi b/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi index 929f4a1d3f9054efcf9751b8525fe17b00a7310d..7fc0339a3ac97896710efabd22d6375bbe869314 100644 --- a/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi @@ -80,7 +80,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/renesas/r8a774a1-beacon-rzg2m-kit.dts b/arch/arm64/boot/dts/renesas/r8a774a1-beacon-rzg2m-kit.dts index 501cb05da228de6c5517a946c06ccf7958bed86e..3cf2e076940f3b5a8740ff9d97b5a362c1f52b0d 100644 --- a/arch/arm64/boot/dts/renesas/r8a774a1-beacon-rzg2m-kit.dts +++ b/arch/arm64/boot/dts/renesas/r8a774a1-beacon-rzg2m-kit.dts @@ -21,6 +21,9 @@ serial4 = &hscif2; serial5 = &scif5; ethernet0 = &avb; + mmc0 = &sdhi3; + mmc1 = &sdhi0; + mmc2 = &sdhi2; }; chosen { diff --git a/arch/arm64/boot/dts/renesas/r8a774b1-beacon-rzg2n-kit.dts b/arch/arm64/boot/dts/renesas/r8a774b1-beacon-rzg2n-kit.dts index 71763f4402a7c575149b1a4dfb7065acb77080c4..3c0d59def8ee534231a5bf5a6d88a8c181b57d26 100644 --- a/arch/arm64/boot/dts/renesas/r8a774b1-beacon-rzg2n-kit.dts +++ b/arch/arm64/boot/dts/renesas/r8a774b1-beacon-rzg2n-kit.dts @@ -22,6 +22,9 @@ serial5 = &scif5; serial6 = &scif4; ethernet0 = &avb; + mmc0 = &sdhi3; + mmc1 = &sdhi0; + mmc2 = &sdhi2; }; chosen { diff --git a/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts b/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts index ea87cb5a459c89b307b0362dd07c70f68905828c..4e72e4f2bab055a5d31f5e5dc1b714f04dcc005f 100644 --- a/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts +++ b/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts @@ -17,6 +17,8 @@ aliases { serial0 = &scif2; serial1 = &hscif2; + mmc0 = &sdhi0; + mmc1 = &sdhi3; }; chosen { @@ -351,7 +353,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -365,7 +367,7 @@ rcar_sound,dai { dai0 { - playback = <&ssi0 &src0 &dvc0>; + playback = <&ssi0>, <&src0>, <&dvc0>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a774e1-beacon-rzg2h-kit.dts b/arch/arm64/boot/dts/renesas/r8a774e1-beacon-rzg2h-kit.dts index 273f062f290932720748cb477f45ddd239656268..7b6649a3ded0299ef242c23420a0053714c4adee 100644 --- a/arch/arm64/boot/dts/renesas/r8a774e1-beacon-rzg2h-kit.dts +++ b/arch/arm64/boot/dts/renesas/r8a774e1-beacon-rzg2h-kit.dts @@ -22,6 +22,9 @@ serial5 = &scif5; serial6 = &scif4; ethernet0 = &avb; + mmc0 = &sdhi3; + mmc1 = &sdhi0; + mmc2 = &sdhi2; }; chosen { diff --git a/arch/arm64/boot/dts/renesas/r8a77950-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77950-salvator-x.dts index 2438825c9b22e26d9f1a5ae8ba5d40706d17ea01..3e3b954a4a9defe83bb9d756332989465ed14658 100644 --- a/arch/arm64/boot/dts/renesas/r8a77950-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a77950-salvator-x.dts @@ -52,29 +52,6 @@ status = "okay"; }; -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - &hdmi1 { status = "okay"; @@ -111,19 +88,7 @@ &rcar_sound { ports { - /* rsnd_port0 is on salvator-common */ - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; + /* rsnd_port0/1 are described in salvator-common.dtsi */ rsnd_port2: port@2 { reg = <2>; rsnd_endpoint2: endpoint { diff --git a/arch/arm64/boot/dts/renesas/r8a77950.dtsi b/arch/arm64/boot/dts/renesas/r8a77950.dtsi index d716c4386ae9f4374d074ed6553865208e9381db..25b87da32eebb6dc2f9abf0f671cfa7410722274 100644 --- a/arch/arm64/boot/dts/renesas/r8a77950.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77950.dtsi @@ -29,6 +29,11 @@ <&ipmmu_mp1 30>, <&ipmmu_mp1 31>; }; +&cluster0_opp { + /delete-node/ opp-1600000000; + /delete-node/ opp-1700000000; +}; + &du { renesas,vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd3 0>; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77951-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77951-salvator-x.dts index a402a2fb6e3c313b550daaa3d74f71e354350a6e..cf2165bdf62511ffa65f16355ad6fe9717fa75f8 100644 --- a/arch/arm64/boot/dts/renesas/r8a77951-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a77951-salvator-x.dts @@ -52,29 +52,6 @@ status = "okay"; }; -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - &hdmi1 { status = "okay"; @@ -111,19 +88,7 @@ &rcar_sound { ports { - /* rsnd_port0 is on salvator-common */ - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; + /* rsnd_port0/1 are described in salvator-common.dtsi */ rsnd_port2: port@2 { reg = <2>; rsnd_endpoint2: endpoint { diff --git a/arch/arm64/boot/dts/renesas/r8a77951-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77951-salvator-xs.dts index e5922329a4b896e4655550b79c9f4deaee2dc1f9..37202fcdc35bc7739e13b17ffad2a7caf11c0b86 100644 --- a/arch/arm64/boot/dts/renesas/r8a77951-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a77951-salvator-xs.dts @@ -57,29 +57,6 @@ status = "okay"; }; -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - &hdmi1 { status = "okay"; @@ -152,19 +129,7 @@ &rcar_sound { ports { - /* rsnd_port0 is on salvator-common */ - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; + /* rsnd_port0/1 are described in salvator-common.dtsi */ rsnd_port2: port@2 { reg = <2>; rsnd_endpoint2: endpoint { diff --git a/arch/arm64/boot/dts/renesas/r8a77960-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77960-salvator-x.dts index ecfbeafeaf367f15ef9c9d0f8d7c582e6a358da5..d5543f26c4720cea6a7d85594102c5eb1a4b4b75 100644 --- a/arch/arm64/boot/dts/renesas/r8a77960-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a77960-salvator-x.dts @@ -35,49 +35,3 @@ clock-names = "du.0", "du.1", "du.2", "dclkin.0", "dclkin.1", "dclkin.2"; }; - -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - -&rcar_sound { - ports { - /* rsnd_port0 is on salvator-common */ - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; - }; -}; - -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; diff --git a/arch/arm64/boot/dts/renesas/r8a77960-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77960-salvator-xs.dts index 249896a38fdcc7a83d24579a8aa664fcf009b252..9ebb47b6bf2dcbc1415c71f43751751dc4ce53c9 100644 --- a/arch/arm64/boot/dts/renesas/r8a77960-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a77960-salvator-xs.dts @@ -35,49 +35,3 @@ clock-names = "du.0", "du.1", "du.2", "dclkin.0", "dclkin.1", "dclkin.2"; }; - -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - -&rcar_sound { - ports { - /* rsnd_port0 is on salvator-common */ - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; - }; -}; - -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; diff --git a/arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts index 1e76033651062c3945212688a267bb807db166fb..c7f14177f7b95b5a714dfe5a67200190980d45b8 100644 --- a/arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts @@ -40,49 +40,3 @@ clock-names = "du.0", "du.1", "du.2", "dclkin.0", "dclkin.1", "dclkin.2"; }; - -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - -&rcar_sound { - ports { - /* rsnd_port0 is on salvator-common */ - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; - }; -}; - -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; diff --git a/arch/arm64/boot/dts/renesas/r8a77961-ulcb.dts b/arch/arm64/boot/dts/renesas/r8a77961-ulcb.dts index 7c6e60f6f32d5c9dead3be1290f12257deff47c4..294a055f117ea72b52b59f6f86d6c08279f66d2a 100644 --- a/arch/arm64/boot/dts/renesas/r8a77961-ulcb.dts +++ b/arch/arm64/boot/dts/renesas/r8a77961-ulcb.dts @@ -30,3 +30,14 @@ reg = <0x6 0x00000000 0x1 0x00000000>; }; }; + +&du { + clocks = <&cpg CPG_MOD 724>, + <&cpg CPG_MOD 723>, + <&cpg CPG_MOD 722>, + <&versaclock5 1>, + <&versaclock5 3>, + <&versaclock5 2>; + clock-names = "du.0", "du.1", "du.2", + "dclkin.0", "dclkin.1", "dclkin.2"; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a77961.dtsi b/arch/arm64/boot/dts/renesas/r8a77961.dtsi index e8c31ebec09730c41591e09b09e39d9f028ea170..ab081f14af9aa0fbf92e7323b0b8cdc5f702f4fd 100644 --- a/arch/arm64/boot/dts/renesas/r8a77961.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77961.dtsi @@ -1155,13 +1155,35 @@ }; can0: can@e6c30000 { + compatible = "renesas,can-r8a77961", + "renesas,rcar-gen3-can"; reg = <0 0xe6c30000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 916>, + <&cpg CPG_CORE R8A77961_CLK_CANFD>, + <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A77961_CLK_CANFD>; + assigned-clock-rates = <40000000>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 916>; + status = "disabled"; }; can1: can@e6c38000 { + compatible = "renesas,can-r8a77961", + "renesas,rcar-gen3-can"; reg = <0 0xe6c38000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 915>, + <&cpg CPG_CORE R8A77961_CLK_CANFD>, + <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A77961_CLK_CANFD>; + assigned-clock-rates = <40000000>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 915>; + status = "disabled"; }; pwm0: pwm@e6e30000 { @@ -1397,43 +1419,259 @@ }; vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef0000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 811>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 811>; + renesas,id = <0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin0csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin0>; + }; + vin0csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin0>; + }; + }; + }; }; vin1: video@e6ef1000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef1000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 810>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 810>; + renesas,id = <1>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin1csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin1>; + }; + vin1csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin1>; + }; + }; + }; }; vin2: video@e6ef2000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef2000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 809>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 809>; + renesas,id = <2>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin2csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin2>; + }; + vin2csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin2>; + }; + }; + }; }; vin3: video@e6ef3000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef3000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 808>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 808>; + renesas,id = <3>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin3csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin3>; + }; + vin3csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin3>; + }; + }; + }; }; vin4: video@e6ef4000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef4000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 807>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 807>; + renesas,id = <4>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin4csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin4>; + }; + vin4csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin4>; + }; + }; + }; }; vin5: video@e6ef5000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef5000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 806>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 806>; + renesas,id = <5>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin5csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin5>; + }; + vin5csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin5>; + }; + }; + }; }; vin6: video@e6ef6000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef6000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 805>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 805>; + renesas,id = <6>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin6csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin6>; + }; + vin6csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin6>; + }; + }; + }; }; vin7: video@e6ef7000 { + compatible = "renesas,vin-r8a77961"; reg = <0 0xe6ef7000 0 0x1000>; - /* placeholder */ + interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 804>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 804>; + renesas,id = <7>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin7csi20: endpoint@0 { + reg = <0>; + remote-endpoint = <&csi20vin7>; + }; + vin7csi40: endpoint@2 { + reg = <2>; + remote-endpoint = <&csi40vin7>; + }; + }; + }; }; rcar_sound: sound@ec500000 { @@ -2249,8 +2487,13 @@ }; csi20: csi2@fea80000 { + compatible = "renesas,r8a77961-csi2"; reg = <0 0xfea80000 0 0x10000>; - /* placeholder */ + interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 714>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 714>; + status = "disabled"; ports { #address-cells = <1>; @@ -2259,14 +2502,53 @@ port@1 { #address-cells = <1>; #size-cells = <0>; + reg = <1>; + + csi20vin0: endpoint@0 { + reg = <0>; + remote-endpoint = <&vin0csi20>; + }; + csi20vin1: endpoint@1 { + reg = <1>; + remote-endpoint = <&vin1csi20>; + }; + csi20vin2: endpoint@2 { + reg = <2>; + remote-endpoint = <&vin2csi20>; + }; + csi20vin3: endpoint@3 { + reg = <3>; + remote-endpoint = <&vin3csi20>; + }; + csi20vin4: endpoint@4 { + reg = <4>; + remote-endpoint = <&vin4csi20>; + }; + csi20vin5: endpoint@5 { + reg = <5>; + remote-endpoint = <&vin5csi20>; + }; + csi20vin6: endpoint@6 { + reg = <6>; + remote-endpoint = <&vin6csi20>; + }; + csi20vin7: endpoint@7 { + reg = <7>; + remote-endpoint = <&vin7csi20>; + }; }; }; }; csi40: csi2@feaa0000 { + compatible = "renesas,r8a77961-csi2"; reg = <0 0xfeaa0000 0 0x10000>; - /* placeholder */ + interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 716>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 716>; + status = "disabled"; ports { #address-cells = <1>; @@ -2277,7 +2559,41 @@ #size-cells = <0>; reg = <1>; + + csi40vin0: endpoint@0 { + reg = <0>; + remote-endpoint = <&vin0csi40>; + }; + csi40vin1: endpoint@1 { + reg = <1>; + remote-endpoint = <&vin1csi40>; + }; + csi40vin2: endpoint@2 { + reg = <2>; + remote-endpoint = <&vin2csi40>; + }; + csi40vin3: endpoint@3 { + reg = <3>; + remote-endpoint = <&vin3csi40>; + }; + csi40vin4: endpoint@4 { + reg = <4>; + remote-endpoint = <&vin4csi40>; + }; + csi40vin5: endpoint@5 { + reg = <5>; + remote-endpoint = <&vin5csi40>; + }; + csi40vin6: endpoint@6 { + reg = <6>; + remote-endpoint = <&vin6csi40>; + }; + csi40vin7: endpoint@7 { + reg = <7>; + remote-endpoint = <&vin7csi40>; + }; }; + }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts index 660a0240eec56268cd6ad661562f496b93cb0c94..f84c64ed4df7b0459fe43bb7f03770a1542eca86 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts @@ -30,48 +30,3 @@ clock-names = "du.0", "du.1", "du.3", "dclkin.0", "dclkin.1", "dclkin.3"; }; - -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - -&rcar_sound { - ports { - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; - }; -}; - -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts index d7e621101af7e6311d83145fe8834286118545bb..729756c24c7479a3474cfac18dccd86d70cf0635 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts @@ -31,29 +31,6 @@ "dclkin.0", "dclkin.1", "dclkin.3"; }; -&hdmi0 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - rcar_dw_hdmi0_out: endpoint { - remote-endpoint = <&hdmi0_con>; - }; - }; - port@2 { - reg = <2>; - dw_hdmi0_snd_in: endpoint { - remote-endpoint = <&rsnd_endpoint1>; - }; - }; - }; -}; - -&hdmi0_con { - remote-endpoint = <&rcar_dw_hdmi0_out>; -}; - &pca9654 { pcie-sata-switch-hog { gpio-hog; @@ -63,29 +40,7 @@ }; }; -&rcar_sound { - ports { - rsnd_port1: port@1 { - reg = <1>; - rsnd_endpoint1: endpoint { - remote-endpoint = <&dw_hdmi0_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint1>; - frame-master = <&rsnd_endpoint1>; - - playback = <&ssi2>; - }; - }; - }; -}; - /* SW12-7 must be set 'Off' (MD12 set to 1) which is not the default! */ &sata { status = "okay"; }; - -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi index ec7ca72399ec4d5464e775daedea5150d7c116fb..1ffa4a995a7ab8ae8fe8fa25d347ef04fd7a5fa4 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi @@ -992,8 +992,8 @@ reg = <1>; - vin4csi41: endpoint@2 { - reg = <2>; + vin4csi41: endpoint@3 { + reg = <3>; remote-endpoint = <&csi41vin4>; }; }; @@ -1020,8 +1020,8 @@ reg = <1>; - vin5csi41: endpoint@2 { - reg = <2>; + vin5csi41: endpoint@3 { + reg = <3>; remote-endpoint = <&csi41vin5>; }; }; @@ -1048,8 +1048,8 @@ reg = <1>; - vin6csi41: endpoint@2 { - reg = <2>; + vin6csi41: endpoint@3 { + reg = <3>; remote-endpoint = <&csi41vin6>; }; }; @@ -1076,8 +1076,8 @@ reg = <1>; - vin7csi41: endpoint@2 { - reg = <2>; + vin7csi41: endpoint@3 { + reg = <3>; remote-endpoint = <&csi41vin7>; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts index f74f8b9993f1d79c6eab2cbda34236bc144944c0..295d34f1d216d963e22e38e60b6f72613e21ba7f 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts +++ b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts @@ -16,6 +16,9 @@ aliases { serial0 = &scif2; ethernet0 = &avb; + mmc0 = &sdhi3; + mmc1 = &sdhi0; + mmc2 = &sdhi1; }; chosen { @@ -621,7 +624,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -653,8 +656,8 @@ rcar_sound,dai { dai0 { - playback = <&ssi0 &src0 &dvc0>; - capture = <&ssi1 &src1 &dvc1>; + playback = <&ssi0>, <&src0>, <&dvc0>; + capture = <&ssi1>, <&src1>, <&dvc1>; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi index fa284a7260d68251c0a786d591a7e59fe44fc413..a0a1a1da0d874f1ac12f6689bd7ac7381bfcf70b 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi @@ -6,12 +6,45 @@ */ #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/leds/common.h> + #include "r8a779a0.dtsi" / { model = "Renesas Falcon CPU board"; compatible = "renesas,falcon-cpu", "renesas,r8a779a0"; + aliases { + serial0 = &scif0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led-1 { + gpios = <&gpio4 18 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <1>; + }; + led-2 { + gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <2>; + }; + led-3 { + gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <3>; + }; + }; + memory@48000000 { device_type = "memory"; /* first 128MB is reserved for secure area. */ @@ -52,22 +85,6 @@ }; }; -&avb0 { - pinctrl-0 = <&avb0_pins>; - pinctrl-names = "default"; - phy-handle = <&phy0>; - tx-internal-delay-ps = <2000>; - status = "okay"; - - phy0: ethernet-phy@0 { - rxc-skew-ps = <1500>; - reg = <0>; - interrupt-parent = <&gpio4>; - interrupts = <16 IRQ_TYPE_LEVEL_LOW>; - reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; - }; -}; - &extal_clk { clock-frequency = <16666666>; }; @@ -82,6 +99,13 @@ status = "okay"; clock-frequency = <400000>; + + eeprom@50 { + compatible = "rohm,br24g01", "atmel,24c01"; + label = "cpu-board"; + reg = <0x50>; + pagesize = <8>; + }; }; &i2c1 { @@ -121,24 +145,6 @@ pinctrl-0 = <&scif_clk_pins>; pinctrl-names = "default"; - avb0_pins: avb0 { - mux { - groups = "avb0_link", "avb0_mdio", "avb0_rgmii", "avb0_txcrefclk"; - function = "avb0"; - }; - - pins_mdio { - groups = "avb0_mdio"; - drive-strength = <21>; - }; - - pins_mii { - groups = "avb0_rgmii"; - drive-strength = <21>; - }; - - }; - i2c0_pins: i2c0 { groups = "i2c0"; function = "i2c0"; @@ -171,6 +177,11 @@ }; }; +&rwdt { + timeout-sec = <60>; + status = "okay"; +}; + &scif0 { pinctrl-0 = <&scif0_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..14d3db5d6c16485d95ff7d50057658cd7e1699eb --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for the Falcon CSI/DSI sub-board + * + * Copyright (C) 2021 Glider bv + */ + +&i2c0 { + eeprom@52 { + compatible = "rohm,br24g01", "atmel,24c01"; + label = "csi-dsi-sub-board-id"; + reg = <0x52>; + pagesize = <8>; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-ethernet.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-ethernet.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e11bf9ace7768d54c6fdb9b34345c744e6351aa0 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-ethernet.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for the Falcon Ethernet sub-board + * + * Copyright (C) 2021 Glider bv + */ + +&i2c0 { + eeprom@53 { + compatible = "rohm,br24g01", "atmel,24c01"; + label = "ethernet-sub-board-id"; + reg = <0x53>; + pagesize = <8>; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts b/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts index 5617b81dd7dc3e8700b1b5105657f1ce4dfbae88..687f019e79f059a1194b758f306cca64101b16f6 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts @@ -7,6 +7,8 @@ /dts-v1/; #include "r8a779a0-falcon-cpu.dtsi" +#include "r8a779a0-falcon-csi-dsi.dtsi" +#include "r8a779a0-falcon-ethernet.dtsi" / { model = "Renesas Falcon CPU and Breakout boards based on r8a779a0"; @@ -14,15 +16,51 @@ aliases { ethernet0 = &avb0; - serial0 = &scif0; }; +}; + +&avb0 { + pinctrl-0 = <&avb0_pins>; + pinctrl-names = "default"; + phy-handle = <&phy0>; + tx-internal-delay-ps = <2000>; + status = "okay"; - chosen { - stdout-path = "serial0:115200n8"; + phy0: ethernet-phy@0 { + rxc-skew-ps = <1500>; + reg = <0>; + interrupt-parent = <&gpio4>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; }; }; -&rwdt { - timeout-sec = <60>; - status = "okay"; +&i2c0 { + eeprom@51 { + compatible = "rohm,br24g01", "atmel,24c01"; + label = "breakout-board"; + reg = <0x51>; + pagesize = <8>; + }; +}; + +&pfc { + avb0_pins: avb0 { + mux { + groups = "avb0_link", "avb0_mdio", "avb0_rgmii", + "avb0_txcrefclk"; + function = "avb0"; + }; + + pins_mdio { + groups = "avb0_mdio"; + drive-strength = <21>; + }; + + pins_mii { + groups = "avb0_rgmii"; + drive-strength = <21>; + }; + + }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi index dfd6ae8b564fb1ba19d591ee7fcec5f0f72dea75..70b3604e56cd7c06a3f6adc1973b383159783a72 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi @@ -60,10 +60,7 @@ pmu_a76 { compatible = "arm,cortex-a76-pmu"; - interrupts-extended = <&gic GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>, - <&gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>, - <&gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, - <&gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&gic GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; }; /* External SCIF clock - to be overridden by boards that provide it */ @@ -239,6 +236,76 @@ #interrupt-cells = <2>; }; + cmt0: timer@e60f0000 { + compatible = "renesas,r8a779a0-cmt0", + "renesas,rcar-gen3-cmt0"; + reg = <0 0xe60f0000 0 0x1004>; + interrupts = <GIC_SPI 500 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 501 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 910>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 910>; + status = "disabled"; + }; + + cmt1: timer@e6130000 { + compatible = "renesas,r8a779a0-cmt1", + "renesas,rcar-gen3-cmt1"; + reg = <0 0xe6130000 0 0x1004>; + interrupts = <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 455 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 911>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 911>; + status = "disabled"; + }; + + cmt2: timer@e6140000 { + compatible = "renesas,r8a779a0-cmt1", + "renesas,rcar-gen3-cmt1"; + reg = <0 0xe6140000 0 0x1004>; + interrupts = <GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 457 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 459 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 463 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 912>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 912>; + status = "disabled"; + }; + + cmt3: timer@e6148000 { + compatible = "renesas,r8a779a0-cmt1", + "renesas,rcar-gen3-cmt1"; + reg = <0 0xe6148000 0 0x1004>; + interrupts = <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 913>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 913>; + status = "disabled"; + }; + cpg: clock-controller@e6150000 { compatible = "renesas,r8a779a0-cpg-mssr"; reg = <0 0xe6150000 0 0x4000>; @@ -260,6 +327,84 @@ #power-domain-cells = <1>; }; + tmu0: timer@e61e0000 { + compatible = "renesas,tmu-r8a779a0", "renesas,tmu"; + reg = <0 0xe61e0000 0 0x30>; + interrupts = <GIC_SPI 512 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 513 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 514 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 713>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 713>; + status = "disabled"; + }; + + tmu1: timer@e6fc0000 { + compatible = "renesas,tmu-r8a779a0", "renesas,tmu"; + reg = <0 0xe6fc0000 0 0x30>; + interrupts = <GIC_SPI 504 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 505 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 714>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 714>; + status = "disabled"; + }; + + tmu2: timer@e6fd0000 { + compatible = "renesas,tmu-r8a779a0", "renesas,tmu"; + reg = <0 0xe6fd0000 0 0x30>; + interrupts = <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 510 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 715>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 715>; + status = "disabled"; + }; + + tmu3: timer@e6fe0000 { + compatible = "renesas,tmu-r8a779a0", "renesas,tmu"; + reg = <0 0xe6fe0000 0 0x30>; + interrupts = <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 716>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 716>; + status = "disabled"; + }; + + tmu4: timer@ffc00000 { + compatible = "renesas,tmu-r8a779a0", "renesas,tmu"; + reg = <0 0xffc00000 0 0x30>; + interrupts = <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 717>; + clock-names = "fck"; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 717>; + status = "disabled"; + }; + + tsc: thermal@e6190000 { + compatible = "renesas,r8a779a0-thermal"; + reg = <0 0xe6190000 0 0x200>, + <0 0xe6198000 0 0x200>, + <0 0xe61a0000 0 0x200>, + <0 0xe61a8000 0 0x200>, + <0 0xe61b0000 0 0x200>; + clocks = <&cpg CPG_MOD 919>; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 919>; + #thermal-sensor-cells = <1>; + }; + i2c0: i2c@e6500000 { compatible = "renesas,i2c-r8a779a0", "renesas,rcar-gen3-i2c"; @@ -954,12 +1099,122 @@ power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; }; + fcpvd0: fcp@fea10000 { + compatible = "renesas,fcpv"; + reg = <0 0xfea10000 0 0x200>; + clocks = <&cpg CPG_MOD 508>; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 508>; + }; + + fcpvd1: fcp@fea11000 { + compatible = "renesas,fcpv"; + reg = <0 0xfea11000 0 0x200>; + clocks = <&cpg CPG_MOD 509>; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 509>; + }; + + vspd0: vsp@fea20000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea20000 0 0x5000>; + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 830>; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 830>; + + renesas,fcp = <&fcpvd0>; + }; + + vspd1: vsp@fea28000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea28000 0 0x5000>; + interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 831>; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 831>; + + renesas,fcp = <&fcpvd1>; + }; + prr: chipid@fff00044 { compatible = "renesas,prr"; reg = <0 0xfff00044 0 4>; }; }; + thermal-zones { + sensor_thermal1: sensor-thermal1 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&tsc 0>; + + trips { + sensor1_crit: sensor1-crit { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + sensor_thermal2: sensor-thermal2 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&tsc 1>; + + trips { + sensor2_crit: sensor2-crit { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + sensor_thermal3: sensor-thermal3 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&tsc 2>; + + trips { + sensor3_crit: sensor3-crit { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + sensor_thermal4: sensor-thermal4 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&tsc 3>; + + trips { + sensor4_crit: sensor4-crit { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + sensor_thermal5: sensor-thermal5 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&tsc 4>; + + trips { + sensor5_crit: sensor5-crit { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi index c22bb38994e805ed0bff16545d338dc7a36931d4..e18747df219f8118ae2f75bbbe3290207d44647e 100644 --- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi @@ -36,6 +36,9 @@ serial0 = &scif2; serial1 = &hscif1; ethernet0 = &avb; + mmc0 = &sdhi2; + mmc1 = &sdhi0; + mmc2 = &sdhi3; }; chosen { @@ -198,7 +201,8 @@ label = "rcar-sound"; - dais = <&rsnd_port0>; + dais = <&rsnd_port0 /* ak4613 */ + &rsnd_port1>; /* HDMI0 */ }; vbus0_usb2: regulator-vbus0-usb2 { @@ -316,6 +320,10 @@ }; }; +&a57_0 { + cpu-supply = <&dvfs>; +}; + &audio_clk_a { clock-frequency = <22579200>; }; @@ -394,6 +402,29 @@ clock-frequency = <32768>; }; +&hdmi0 { + status = "okay"; + + ports { + port@1 { + reg = <1>; + rcar_dw_hdmi0_out: endpoint { + remote-endpoint = <&hdmi0_con>; + }; + }; + port@2 { + reg = <2>; + dw_hdmi0_snd_in: endpoint { + remote-endpoint = <&rsnd_endpoint1>; + }; + }; + }; +}; + +&hdmi0_con { + remote-endpoint = <&rcar_dw_hdmi0_out>; +}; + &hscif1 { pinctrl-0 = <&hscif1_pins>; pinctrl-names = "default"; @@ -730,7 +761,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -773,8 +804,21 @@ bitclock-master = <&rsnd_endpoint0>; frame-master = <&rsnd_endpoint0>; - playback = <&ssi0 &src0 &dvc0>; - capture = <&ssi1 &src1 &dvc1>; + playback = <&ssi0>, <&src0>, <&dvc0>; + capture = <&ssi1>, <&src1>, <&dvc1>; + }; + }; + + rsnd_port1: port@1 { + reg = <1>; + rsnd_endpoint1: endpoint { + remote-endpoint = <&dw_hdmi0_snd_in>; + + dai-format = "i2s"; + bitclock-master = <&rsnd_endpoint1>; + frame-master = <&rsnd_endpoint1>; + + playback = <&ssi2>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi index e9ed2597f1c20621bc562f4d718b1fdda98ea88e..61bd4df09df0da9ab92926c022f8aaa963e54f08 100644 --- a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi +++ b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi @@ -16,6 +16,7 @@ aliases { serial1 = &hscif0; serial2 = &scif1; + mmc2 = &sdhi3; }; clksndsel: clksndsel { diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi index a04eae55dd6c42dc575682b0c247baf319016a8b..1f177af3eb9dfa37fa7e3d08b4e824628c1550dd 100644 --- a/arch/arm64/boot/dts/renesas/ulcb.dtsi +++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi @@ -23,6 +23,8 @@ aliases { serial0 = &scif2; ethernet0 = &avb; + mmc0 = &sdhi2; + mmc1 = &sdhi0; }; chosen { @@ -136,6 +138,10 @@ }; }; +&a57_0 { + cpu-supply = <&dvfs>; +}; + &audio_clk_a { clock-frequency = <22579200>; }; @@ -365,7 +371,7 @@ }; &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-0 = <&sound_pins>, <&sound_clk_pins>; pinctrl-names = "default"; /* Single DAI */ @@ -408,8 +414,8 @@ bitclock-master = <&rsnd_for_ak4613>; frame-master = <&rsnd_for_ak4613>; - playback = <&ssi0 &src0 &dvc0>; - capture = <&ssi1 &src1 &dvc1>; + playback = <&ssi0>, <&src0>, <&dvc0>; + capture = <&ssi1>, <&src1>, <&dvc1>; }; }; rsnd_port1: port@1 { diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 62d3abc17a24670d034a141ea556c56f7cbc3b1e..c3e00c0e2db7e1d7869f023acd9cc2e2579fe43c 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -36,6 +36,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-r4s.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-orangepi.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-pinebook-pro.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou.dtb diff --git a/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi b/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi index 08b0b9fbcbc9a3621e104429a8a42bf4dcad4c35..3429e124d95a2168639ee1713d0ec78bbdd5d0d8 100644 --- a/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi @@ -6,6 +6,11 @@ */ / { + aliases { + mmc1 = &sdmmc; + mmc2 = &sdio; + }; + vcc5v0_sys: vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; /* +5V */ 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 cdacd34836006794b40b158b5d10888df3deee5b..7249871530ab96c778b09a6366a7a8ed817b3a00 100644 --- a/arch/arm64/boot/dts/rockchip/px30-engicam-px30-core.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-engicam-px30-core.dtsi @@ -11,6 +11,10 @@ / { compatible = "engicam,px30-core", "rockchip,px30"; + + aliases { + mmc0 = &emmc; + }; }; &cpu0 { diff --git a/arch/arm64/boot/dts/rockchip/px30-evb.dts b/arch/arm64/boot/dts/rockchip/px30-evb.dts index 5fe905fae9a8f339cd8141bb964b569a7068df54..c1ce9c295e5bb0156b37b379df6c14a642385357 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb.dts @@ -13,6 +13,12 @@ model = "Rockchip PX30 EVB"; compatible = "rockchip,px30-evb", "rockchip,px30"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdio; + mmc2 = &emmc; + }; + chosen { stdout-path = "serial5:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi index c45b0cfcae09c6de8598d499219ece3719d46480..09baa8a167ce65ffc6fa8db6a99df1ee7ac5cf84 100644 --- a/arch/arm64/boot/dts/rockchip/px30.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30.dtsi @@ -25,9 +25,6 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; - mmc0 = &sdmmc; - mmc1 = &sdio; - mmc2 = &emmc; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -603,7 +600,7 @@ }; wdt: watchdog@ff1e0000 { - compatible = "snps,dw-wdt"; + compatible = "rockchip,px30-wdt", "snps,dw-wdt"; reg = <0x0 0xff1e0000 0x0 0x100>; clocks = <&cru PCLK_WDT_NS>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; @@ -984,6 +981,27 @@ status = "disabled"; }; + gpu_opp_table: opp-table2 { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <950000>; + }; + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <975000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <1050000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <1125000>; + }; + }; + gpu: gpu@ff400000 { compatible = "rockchip,px30-mali", "arm,mali-bifrost"; reg = <0x0 0xff400000 0x0 0x4000>; @@ -994,6 +1012,7 @@ clocks = <&cru SCLK_GPU>; #cooling-cells = <2>; power-domains = <&power PX30_PD_GPU>; + operating-points-v2 = <&gpu_opp_table>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts index 7a96be10eaf0d3431f5602bb41edef94af7ca67d..3dddd4742c3a0ea0cdcb1f92738103eb374e5deb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts @@ -9,6 +9,12 @@ / { model = "Firefly ROC-RK3308-CC board"; compatible = "firefly,roc-rk3308-cc", "rockchip,rk3308"; + + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi index 3a035a189450cdf480081c622859efcb54b3214c..0c5fa9801e6fd0299a9e2f9e50f7029af95e17d5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi @@ -24,9 +24,6 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; - mmc0 = &sdmmc; - mmc1 = &emmc; - mmc2 = &sdio; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -247,7 +244,7 @@ }; wdt: watchdog@ff080000 { - compatible = "snps,dw-wdt"; + compatible = "rockchip,rk3308-wdt", "snps,dw-wdt"; reg = <0x0 0xff080000 0x0 0x100>; clocks = <&cru PCLK_WDT>; interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts index 30c73ef25370b0048472517e00f884dbda8c8cac..763cf9b4620eb687786cad50a2f579659e60959f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts @@ -8,6 +8,12 @@ model = "A95X Z2"; compatible = "zkmagic,a95x-z2", "rockchip,rk3318"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdio; + mmc2 = &emmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; @@ -357,6 +363,11 @@ status = "okay"; }; +&usbdrd3 { + dr_mode = "host"; + status = "okay"; +}; + &usb_host0_ehci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts index 97fb93e1cc00fd9aa23ddabd241f4420262b055d..49c97f76df774f7b23f3b97eea3e1ee10462c015 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts @@ -14,6 +14,10 @@ model = "ODROID-GO Advance"; compatible = "hardkernel,rk3326-odroid-go2", "rockchip,rk3326"; + aliases { + mmc0 = &sdmmc; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts index 37f307cfa4cc7bf84e4fabf3ee7e1158119be35f..de2d3e88e27fcb2b401be24704ab99e24eb61e81 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts @@ -8,6 +8,11 @@ model = "Beelink A1"; compatible = "azw,beelink-a1", "rockchip,rk3328"; + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + /* * UART pins, as viewed with bottom of case removed: * diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts index a48767931af6fa074e4cb2a5f39af0fb1714a709..ff6b466e0e07442b10ba97d9ba129f1cc36fbeb8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts @@ -10,6 +10,12 @@ model = "Rockchip RK3328 EVB"; compatible = "rockchip,rk3328-evb", "rockchip,rk3328"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdio; + mmc2 = &emmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts index faf496d789cf860f2b525c3fb87d5084ed0df65c..f807bc066ccb9c085d6be7e085a5bf993c07e0f3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts @@ -13,6 +13,10 @@ model = "FriendlyElec NanoPi R2S"; compatible = "friendlyarm,nanopi-r2s", "rockchip,rk3328"; + aliases { + mmc0 = &sdmmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts index 19959bfba4519bd6aab2ce18c85314abc7032caf..a05732b59f38043049442b59fdc522681255047c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts @@ -10,6 +10,11 @@ model = "Firefly roc-rk3328-cc"; compatible = "firefly,roc-rk3328-cc", "rockchip,rk3328"; + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; 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 2d71ca7e429c1609149fd69225af9fe3473f9e38..c7e31efdd2e112d0da099f05c4580f7399b21ebe 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts @@ -20,6 +20,11 @@ model = "Radxa ROCK Pi E"; compatible = "radxa,rockpi-e", "rockchip,rk3328"; + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index c984662043da81964e108697274dc3709be2d90b..3bef1f39bc6e13e45db0124b7607050685f60e93 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -10,6 +10,11 @@ model = "Pine64 Rock64"; compatible = "pine64,rock64", "rockchip,rk3328"; + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index 063ed0adbec42ed15a125866b133a0421ba21632..5bab617847350250e429c79f37aaef1117920668 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -27,9 +27,6 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; - mmc0 = &sdmmc; - mmc1 = &sdio; - mmc2 = &emmc; ethernet0 = &gmac2io; ethernet1 = &gmac2phy; }; @@ -438,7 +435,7 @@ }; wdt: watchdog@ff1a0000 { - compatible = "snps,dw-wdt"; + compatible = "rockchip,rk3328-wdt", "snps,dw-wdt"; reg = <0x0 0xff1a0000 0x0 0x100>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru PCLK_WDT>; @@ -980,6 +977,25 @@ status = "disabled"; }; + usbdrd3: usb@ff600000 { + compatible = "rockchip,rk3328-dwc3", "snps,dwc3"; + reg = <0x0 0xff600000 0x0 0x100000>; + interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_USB3OTG_REF>, <&cru SCLK_USB3OTG_SUSPEND>, + <&cru ACLK_USB3OTG>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk"; + dr_mode = "otg"; + phy_type = "utmi_wide"; + snps,dis-del-phy-power-chg-quirk; + snps,dis_enblslpm_quirk; + snps,dis-tx-ipgap-linecheck-quirk; + snps,dis-u2-freeclk-exists-quirk; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + status = "disabled"; + }; + gic: interrupt-controller@ff811000 { compatible = "arm,gic-400"; #interrupt-cells = <3>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi index 87fabc64cc399bca0e2589c26359cb50657c8957..15d1fc541c38e8a03c28dec0578061842947c42c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi @@ -8,6 +8,10 @@ #include "rk3368.dtsi" / { + aliases { + mmc0 = &emmc; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts index 46357d1d77cdc84a8a8f85e398a68a60a8d224ff..62aa97a0b8c9f3d1b094d54d9f24d387a7d4700f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts @@ -11,6 +11,10 @@ model = "GeekBox"; compatible = "geekbuying,geekbox", "rockchip,rk3368"; + aliases { + mmc0 = &emmc; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts index 7fcb1eacea8acf29cca7cfe4d937ac79c3a99ebe..cae01d35b93d91818ed82818b50151b90d89dd74 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts @@ -10,6 +10,10 @@ model = "Theobroma Systems RK3368-uQ7 Baseboard"; compatible = "tsd,rk3368-lion-haikou", "rockchip,rk3368"; + aliases { + mmc1 = &sdmmc; + }; + chosen { stdout-path = "serial0:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi index 24d28be4736cf83e2b5251fc0b9d649d84fdd79d..bcd7977fb0f8ec67ae8413d97ffc9fd3e64afc16 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi @@ -7,6 +7,10 @@ #include "rk3368.dtsi" / { + aliases { + mmc0 = &emmc; + }; + chosen { stdout-path = "serial0:115200n8"; }; 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 ecce16ecc9c379d487ed03db96f708baf8ed0e3c..3ebe15e03cf4dea50ccd9bbefcabade5972065a2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts @@ -11,6 +11,11 @@ model = "Rockchip Orion R68"; compatible = "tronsmart,orion-r68-meta", "rockchip,rk3368"; + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts index 5ffd7b4d3036cdab0da3e3af6280824b80b53e78..5ccaa5f7a370b57b6d3d3b9273509cfe0b73103c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts @@ -11,6 +11,11 @@ model = "Rockchip PX5 EVB"; compatible = "rockchip,px5-evb", "rockchip,px5", "rockchip,rk3368"; + aliases { + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial4:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts index 2582fa4b90e2cf75f722cce6fbc54406cee19c3b..959d3cc801f2b16381892c5665bcb88db1d7fa90 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts @@ -11,6 +11,11 @@ model = "Rockchip R88"; compatible = "rockchip,r88", "rockchip,rk3368"; + aliases { + mmc0 = &sdio0; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index 7af68ec3feaec866bf4a816dd76d6399b4b42f61..242f821a90ba9ddf499c4522ef60710bb469af4f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -25,9 +25,6 @@ i2c3 = &i2c3; i2c4 = &i2c4; i2c5 = &i2c5; - mmc0 = &sdmmc; - mmc1 = &sdio0; - mmc2 = &emmc; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -667,7 +664,7 @@ status = "disabled"; }; - timer@ff810000 { + timer0: timer@ff810000 { compatible = "rockchip,rk3368-timer", "rockchip,rk3288-timer"; reg = <0x0 0xff810000 0x0 0x20>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index 694b0d08d644aeee1015d33d30f192d624a2a4a6..7b717ebec8ffa0f5565035e23ec1f8c709a3b916 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts @@ -11,6 +11,10 @@ model = "Rockchip RK3399 Evaluation Board"; compatible = "rockchip,rk3399-evb", "rockchip,rk3399"; + aliases { + mmc0 = &sdhci; + }; + backlight: backlight { compatible = "pwm-backlight"; brightness-levels = < diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts index 6db18808b9c54be1f9c91398b7aa71545c8c446b..45254be1350dec791cfb4f04baf565c96b5fd216 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -13,6 +13,12 @@ model = "Firefly-RK3399 Board"; compatible = "firefly,firefly-rk3399", "rockchip,rk3399"; + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi index 32dcaf210085538c91b0d6f690d64072e9a10ec7..4002742fed4c13401627fccebb4debc7bd249759 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi @@ -10,6 +10,11 @@ #include "rk3399-op1-opp.dtsi" / { + aliases { + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts index 341d074ed9969e4f44136cf87a6c47260219ba02..bee45c17e2caa4da78d200c46c9e2dff3de5921f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts @@ -9,6 +9,12 @@ model = "Hugsun X99 TV BOX"; compatible = "hugsun,x99", "rockchip,rk3399"; + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi index 635afdd99122f6e8883980fbad2045ebc015b793..d5c7648c841dc7d12ca42aae4d0ab85b774caa3f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi @@ -11,6 +11,12 @@ #include "rk3399-opp.dtsi" / { + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts index 66c725a34220719e271b79592c916d60ed7413d3..19485b552bc4b8f0e963a3d3e522f337309dce3f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts @@ -18,6 +18,11 @@ model = "Kobol Helios64"; compatible = "kobol,helios64", "rockchip,rk3399"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + avdd_1v8_s0: avdd-1v8-s0 { compatible = "regulator-fixed"; regulator-name = "avdd_1v8_s0"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts index 1fa80ac15464bd30a90b930b4a8c604d48d54cad..7c93f840bc64f9f2cca0f1bb7fae3eff9a452b23 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts @@ -13,6 +13,12 @@ model = "Leez RK3399 P710"; compatible = "leez,p710", "rockchip,rk3399"; + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts new file mode 100644 index 0000000000000000000000000000000000000000..fa58098876438835b9ce355bab6505e1f250d613 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts @@ -0,0 +1,133 @@ +// 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 <jensenhuang@friendlyarm.com> + * Copyright (c) 2020 Marty Jones <mj8263788@gmail.com> + * Copyright (c) 2021 Tianling Shen <cnsztl@gmail.com> + */ + +/dts-v1/; +#include "rk3399-nanopi4.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:sys"; + 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/ power; + + reset { + debounce-interval = <50>; + gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; + label = "reset"; + linux,code = <KEY_RESTART>; + }; + }; + + 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-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi index 48ed4aaa37f3d33b0572563838d5b183049f6221..16fd58c4a80f3ff5e30e79e391d15a670daed35a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi @@ -17,6 +17,12 @@ #include "rk3399-opp.dtsi" / { + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi index d6f1095abb0409cde225636319bcd340ab861cf5..da41cd81ebb77c76bd50f0a0db90347df2878bde 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi @@ -10,28 +10,28 @@ opp00 { opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <800000>; + opp-microvolt = <825000 825000 1250000>; clock-latency-ns = <40000>; }; opp01 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <800000>; + opp-microvolt = <825000 825000 1250000>; }; opp02 { opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1250000>; }; opp03 { opp-hz = /bits/ 64 <1008000000>; - opp-microvolt = <925000>; + opp-microvolt = <925000 925000 1250000>; }; opp04 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1000000>; + opp-microvolt = <1000000 1000000 1250000>; }; opp05 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <1125000>; + opp-microvolt = <1125000 1125000 1250000>; }; }; @@ -41,36 +41,36 @@ opp00 { opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <800000>; + opp-microvolt = <825000 825000 1250000>; clock-latency-ns = <40000>; }; opp01 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <800000>; + opp-microvolt = <825000 825000 1250000>; }; opp02 { opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <825000>; + opp-microvolt = <825000 825000 1250000>; }; opp03 { opp-hz = /bits/ 64 <1008000000>; - opp-microvolt = <875000>; + opp-microvolt = <875000 875000 1250000>; }; opp04 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1250000>; }; opp05 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <1025000>; + opp-microvolt = <1025000 1025000 1250000>; }; opp06 { opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <1100000>; + opp-microvolt = <1100000 1100000 1250000>; }; opp07 { opp-hz = /bits/ 64 <1800000000>; - opp-microvolt = <1200000>; + opp-microvolt = <1200000 1200000 1250000>; }; }; @@ -79,27 +79,27 @@ opp00 { opp-hz = /bits/ 64 <200000000>; - opp-microvolt = <800000>; + opp-microvolt = <825000 825000 1150000>; }; opp01 { opp-hz = /bits/ 64 <297000000>; - opp-microvolt = <800000>; + opp-microvolt = <825000 825000 1150000>; }; opp02 { opp-hz = /bits/ 64 <400000000>; - opp-microvolt = <825000>; + opp-microvolt = <825000 825000 1150000>; }; opp03 { opp-hz = /bits/ 64 <500000000>; - opp-microvolt = <875000>; + opp-microvolt = <875000 875000 1150000>; }; opp04 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <925000>; + opp-microvolt = <925000 925000 1150000>; }; opp05 { opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <1100000>; + opp-microvolt = <1100000 1100000 1150000>; }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts index ad7c4d00888f69deceb62f2a5b0a52b38ec14299..04b54abea3cc070511fd082e7a2f26e06e97338b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts @@ -15,6 +15,12 @@ model = "Orange Pi RK3399 Board"; compatible = "rockchip,rk3399-orangepi", "rockchip,rk3399"; + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts index 219b7507a10fb7732f1a1cbc56cc52c07ef0893b..2b5f001ff4a61f945456e9fdd7bf5c87a0af7ae8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts @@ -18,6 +18,12 @@ model = "Pine64 Pinebook Pro"; compatible = "pine64,pinebook-pro", "rockchip,rk3399"; + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts index a8d363568fd62a082dc99b00a844dfd75aa8d136..292bb7e80cf35dab9564fb77d4dee224743ec066 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts @@ -10,6 +10,10 @@ model = "Theobroma Systems RK3399-Q7 SoM"; compatible = "tsd,rk3399-puma-haikou", "rockchip,rk3399"; + aliases { + mmc1 = &sdmmc; + }; + chosen { stdout-path = "serial0:115200n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi index 4660416c8f382aa97b485023e8682fb8725b00a3..fb67db4619ea07087d55bef9d711bc8c34aa292b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi @@ -8,6 +8,10 @@ #include "rk3399-opp.dtsi" / { + aliases { + mmc0 = &sdhci; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -21,57 +25,6 @@ }; }; - /* - * Overwrite the opp-table for CPUB as this board uses a different - * regulator (FAN53555) that only allows 10mV steps and therefore - * can't reach the operation point target voltages from rk3399-opp.dtsi - */ - /delete-node/ opp-table1; - cluster1_opp: opp-table1 { - compatible = "operating-points-v2"; - opp-shared; - - opp00 { - opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <800000>; - clock-latency-ns = <40000>; - }; - opp01 { - opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <800000>; - }; - opp02 { - opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <830000>; - opp-suspend; - }; - opp03 { - opp-hz = /bits/ 64 <1008000000>; - opp-microvolt = <880000>; - }; - opp04 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <950000>; - }; - opp05 { - opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <1030000>; - }; - opp06 { - opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <1100000>; - }; - opp07 { - opp-hz = /bits/ 64 <1800000000>; - opp-microvolt = <1200000>; - }; - opp08 { - opp-hz = /bits/ 64 <1992000000>; - opp-microvolt = <1230000>; - turbo-mode; - }; - }; - clkin_gmac: external-gmac-clock { compatible = "fixed-clock"; clock-frequency = <125000000>; 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 754627d971445410f0f07e85f91dd9664797a29b..9447c8724b65a98bafe9ea319814dbb7c077991c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts @@ -11,6 +11,10 @@ model = "Firefly ROC-RK3399-PC Mezzanine Board"; compatible = "firefly,roc-rk3399-pc-mezzanine", "rockchip,rk3399"; + aliases { + mmc2 = &sdio0; + }; + /* MP8009 PoE PD */ poe_12v: poe-12v { compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi index 20309076dbac069acb62bd048dbb555e1d2ec53f..c172f5a803e7b1a3fa254654dee3916c8c46f84a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi @@ -13,6 +13,11 @@ model = "Firefly ROC-RK3399-PC Board"; compatible = "firefly,roc-rk3399-pc", "rockchip,rk3399"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; 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 fb7599f07af4817feb36c216a2d9c1b00dff8d3c..7d0a7c6977039c03fe249f1ee7e710eb2c1886ac 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi @@ -11,6 +11,11 @@ #include "rk3399-opp.dtsi" / { + aliases { + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b.dts index f7cb035c68b2de6fe83cc836b1db27d245267020..9f41a7f83ead8a621cad40d618a453ae90c66ecb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b.dts @@ -10,6 +10,10 @@ / { model = "Radxa ROCK Pi 4B"; compatible = "radxa,rockpi4b", "radxa,rockpi4", "rockchip,rk3399"; + + aliases { + mmc2 = &sdio0; + }; }; &sdio0 { 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 4c7ebb1c5d2db24410610eec53169ede894a379f..99169bcd51c03dabd5576d1a64e226f510128b30 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts @@ -11,6 +11,10 @@ / { model = "Radxa ROCK Pi 4C"; compatible = "radxa,rockpi4c", "radxa,rockpi4", "rockchip,rk3399"; + + aliases { + mmc2 = &sdio0; + }; }; &sdio0 { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi index 5e3ac589bc54a6c27a84fa6e9fae0302166b1349..25dc61c26a9431b7da05180533bba210eff5e059 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi @@ -9,6 +9,12 @@ #include "rk3399-opp.dtsi" / { + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; clocks = <&rk808 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi index 5ab0b9edfc8890aec93f518b9a2033eaa33758f7..6bff8db7d33e8a76aef6d3c3f5b92e09f0e776da 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi @@ -10,6 +10,12 @@ #include "rk3399-opp.dtsi" / { + aliases { + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; @@ -36,6 +42,13 @@ }; }; + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&ir_int>; + pinctrl-names = "default"; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -604,6 +617,12 @@ }; }; + ir { + ir_int: ir-int { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + leds { work_led_pin: work-led-pin { rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts index 73e269a8ae0cc755dea90a2045872c4379161b98..f6b2199a42bdac0c9e810affea66afa76a39ea92 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts @@ -10,6 +10,10 @@ model = "Excavator-RK3399 Board"; compatible = "rockchip,rk3399-sapphire-excavator", "rockchip,rk3399"; + aliases { + mmc2 = &sdio0; + }; + adc-keys { compatible = "adc-keys"; io-channels = <&saradc 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi index 701a567d76382964d1a078e9cf658021c6724e18..46b0f97a0b1c323b9ff2d9f95234c04680abe127 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi @@ -11,6 +11,11 @@ / { compatible = "rockchip,rk3399-sapphire", "rockchip,rk3399"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index edbbf35fe19e620db9137d82dc82788f8a739553..0f2879cc1a6658af4ade49d3e7c1c4f6d0f51bea 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -29,9 +29,6 @@ i2c6 = &i2c6; i2c7 = &i2c7; i2c8 = &i2c8; - mmc0 = &sdio0; - mmc1 = &sdmmc; - mmc2 = &sdhci; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -1531,7 +1528,7 @@ }; watchdog@ff848000 { - compatible = "snps,dw-wdt"; + compatible = "rockchip,rk3399-wdt", "snps,dw-wdt"; reg = <0x0 0xff848000 0x0 0x100>; clocks = <&cru PCLK_WDT>; interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi index 7257494d28318899b93a7b109eb5b15c2a05eeb0..c0074b3ed4af798b246ae9394c41d7883d9ff835 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi @@ -12,6 +12,11 @@ / { compatible = "vamrs,rk3399pro-vmarc-som", "rockchip,rk3399pro"; + aliases { + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + vcc3v3_pcie: vcc-pcie-regulator { compatible = "regulator-fixed"; enable-active-high; diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 65506f21ba30d71dc69a57981a5507b8571b3e82..d56c742f5a1060cfb14914e0cdc6a26173f2b251 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -3,11 +3,17 @@ # Make file to build device tree binaries for boards based on # Texas Instruments Inc processors # -# Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/ +# Copyright (C) 2016-2021 Texas Instruments Incorporated - https://www.ti.com/ # dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced.dtb dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board.dtb dtb-$(CONFIG_ARCH_K3) += k3-j7200-common-proc-board.dtb + +dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb + +dtb-$(CONFIG_ARCH_K3) += k3-am642-sk.dtb diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b2bcbf23eefda88e59ab0968cc8359c0cae526f1 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -0,0 +1,675 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM642 SoC Family Main Domain peripherals + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +&cbass_main { + oc_sram: sram@70000000 { + compatible = "mmio-sram"; + reg = <0x00 0x70000000 0x00 0x200000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x70000000 0x200000>; + + atf-sram@0 { + reg = <0x0 0x1a000>; + }; + }; + + gic500: interrupt-controller@1800000 { + compatible = "arm,gic-v3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ + <0x00 0x01840000 0x00 0xC0000>; /* GICR */ + /* + * vcpumntirq: + * virtual CPU interface maintenance interrupt + */ + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>; + + 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>; + }; + }; + + dmss: dmss { + compatible = "simple-mfd"; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges; + ranges; + + ti,sci-dev-id = <25>; + + secure_proxy_main: mailbox@4d000000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x4d000000 0x00 0x80000>, + <0x00 0x4a600000 0x00 0x80000>, + <0x00 0x4a400000 0x00 0x80000>; + interrupt-names = "rx_012"; + interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; + }; + + inta_main_dmss: interrupt-controller@48000000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x48000000 0x00 0x100000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupt-parent = <&gic500>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <28>; + ti,interrupt-ranges = <4 68 36>; + ti,unmapped-event-sources = <&main_bcdma>, <&main_pktdma>; + }; + + main_bcdma: dma-controller@485c0100 { + compatible = "ti,am64-dmss-bcdma"; + reg = <0x00 0x485c0100 0x00 0x100>, + <0x00 0x4c000000 0x00 0x20000>, + <0x00 0x4a820000 0x00 0x20000>, + <0x00 0x4aa40000 0x00 0x20000>, + <0x00 0x4bc00000 0x00 0x100000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + msi-parent = <&inta_main_dmss>; + #dma-cells = <3>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <26>; + ti,sci-rm-range-bchan = <0x20>; /* BLOCK_COPY_CHAN */ + ti,sci-rm-range-rchan = <0x21>; /* SPLIT_TR_RX_CHAN */ + ti,sci-rm-range-tchan = <0x22>; /* SPLIT_TR_TX_CHAN */ + }; + + main_pktdma: dma-controller@485c0000 { + compatible = "ti,am64-dmss-pktdma"; + reg = <0x00 0x485c0000 0x00 0x100>, + <0x00 0x4a800000 0x00 0x20000>, + <0x00 0x4aa00000 0x00 0x40000>, + <0x00 0x4b800000 0x00 0x400000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + msi-parent = <&inta_main_dmss>; + #dma-cells = <2>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <30>; + ti,sci-rm-range-tchan = <0x23>, /* UNMAPPED_TX_CHAN */ + <0x24>, /* CPSW_TX_CHAN */ + <0x25>, /* SAUL_TX_0_CHAN */ + <0x26>, /* SAUL_TX_1_CHAN */ + <0x27>, /* ICSSG_0_TX_CHAN */ + <0x28>; /* ICSSG_1_TX_CHAN */ + ti,sci-rm-range-tflow = <0x10>, /* RING_UNMAPPED_TX_CHAN */ + <0x11>, /* RING_CPSW_TX_CHAN */ + <0x12>, /* RING_SAUL_TX_0_CHAN */ + <0x13>, /* RING_SAUL_TX_1_CHAN */ + <0x14>, /* RING_ICSSG_0_TX_CHAN */ + <0x15>; /* RING_ICSSG_1_TX_CHAN */ + ti,sci-rm-range-rchan = <0x29>, /* UNMAPPED_RX_CHAN */ + <0x2b>, /* CPSW_RX_CHAN */ + <0x2d>, /* SAUL_RX_0_CHAN */ + <0x2f>, /* SAUL_RX_1_CHAN */ + <0x31>, /* SAUL_RX_2_CHAN */ + <0x33>, /* SAUL_RX_3_CHAN */ + <0x35>, /* ICSSG_0_RX_CHAN */ + <0x37>; /* ICSSG_1_RX_CHAN */ + ti,sci-rm-range-rflow = <0x2a>, /* FLOW_UNMAPPED_RX_CHAN */ + <0x2c>, /* FLOW_CPSW_RX_CHAN */ + <0x2e>, /* FLOW_SAUL_RX_0/1_CHAN */ + <0x32>, /* FLOW_SAUL_RX_2/3_CHAN */ + <0x36>, /* FLOW_ICSSG_0_RX_CHAN */ + <0x38>; /* FLOW_ICSSG_1_RX_CHAN */ + }; + }; + + dmsc: dmsc@44043000 { + compatible = "ti,k2g-sci"; + ti,host-id = <12>; + mbox-names = "rx", "tx"; + mboxes= <&secure_proxy_main 12>, + <&secure_proxy_main 13>; + reg-names = "debug_messages"; + reg = <0x00 0x44043000 0x00 0xfe0>; + + k3_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <2>; + }; + + k3_clks: clocks { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; + + k3_reset: reset-controller { + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; + }; + + main_pmx0: pinctrl@f4000 { + compatible = "pinctrl-single"; + reg = <0x00 0xf4000 0x00 0x2d0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + main_conf: syscon@43000000 { + compatible = "syscon", "simple-mfd"; + reg = <0x00 0x43000000 0x00 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00 0x00 0x43000000 0x20000>; + + chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x00000014 0x4>; + }; + + phy_gmii_sel: phy@4044 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4044 0x8>; + #phy-cells = <1>; + }; + }; + + main_uart0: serial@2800000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02800000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 146 0>; + clock-names = "fclk"; + }; + + main_uart1: serial@2810000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02810000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 152 0>; + clock-names = "fclk"; + }; + + main_uart2: serial@2820000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02820000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 153 0>; + clock-names = "fclk"; + }; + + main_uart3: serial@2830000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02830000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 154 0>; + clock-names = "fclk"; + }; + + main_uart4: serial@2840000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02840000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 155 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 155 0>; + clock-names = "fclk"; + }; + + main_uart5: serial@2850000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02850000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 156 0>; + clock-names = "fclk"; + }; + + main_uart6: serial@2860000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02860000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 158 0>; + clock-names = "fclk"; + }; + + main_i2c0: i2c@20000000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20000000 0x00 0x100>; + interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 102 2>; + clock-names = "fck"; + }; + + main_i2c1: i2c@20010000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20010000 0x00 0x100>; + interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 103 2>; + clock-names = "fck"; + }; + + main_i2c2: i2c@20020000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20020000 0x00 0x100>; + interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 104 2>; + clock-names = "fck"; + }; + + main_i2c3: i2c@20030000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20030000 0x00 0x100>; + interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 105 2>; + clock-names = "fck"; + }; + + main_spi0: spi@20100000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x20100000 0x00 0x400>; + interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 141 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 141 0>; + dmas = <&main_pktdma 0xc300 0>, <&main_pktdma 0x4300 0>; + dma-names = "tx0", "rx0"; + }; + + main_spi1: spi@20110000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x20110000 0x00 0x400>; + interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 142 0>; + }; + + main_spi2: spi@20120000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x20120000 0x00 0x400>; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 143 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 143 0>; + }; + + main_spi3: spi@20130000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x20130000 0x00 0x400>; + interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 144 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 144 0>; + }; + + main_spi4: spi@20140000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x20140000 0x00 0x400>; + interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 145 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 145 0>; + }; + + main_gpio_intr: interrupt-controller0 { + compatible = "ti,sci-intr"; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <3>; + ti,interrupt-ranges = <0 32 16>; + }; + + main_gpio0: gpio@600000 { + compatible = "ti,am64-gpio", "ti,keystone-gpio"; + reg = <0x0 0x00600000 0x0 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <190>, <191>, <192>, + <193>, <194>, <195>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <87>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 77 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 77 0>; + clock-names = "gpio"; + }; + + main_gpio1: gpio@601000 { + compatible = "ti,am64-gpio", "ti,keystone-gpio"; + reg = <0x0 0x00601000 0x0 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <180>, <181>, <182>, + <183>, <184>, <185>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <88>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 78 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 78 0>; + clock-names = "gpio"; + }; + + sdhci0: mmc@fa10000 { + compatible = "ti,am64-sdhci-8bit"; + reg = <0x00 0xfa10000 0x00 0x260>, <0x00 0xfa18000 0x00 0x134>; + interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&k3_pds 57 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 57 0>, <&k3_clks 57 1>; + clock-names = "clk_ahb", "clk_xin"; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + ti,trm-icp = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x6>; + ti,otap-del-sel-hs200 = <0x7>; + ti,otap-del-sel-hs400 = <0x4>; + }; + + sdhci1: mmc@fa00000 { + compatible = "ti,am64-sdhci-4bit"; + reg = <0x00 0xfa00000 0x00 0x260>, <0x00 0xfa08000 0x00 0x134>; + interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 58 3>, <&k3_clks 58 4>; + clock-names = "clk_ahb", "clk_xin"; + ti,trm-icp = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0xf>; + 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,clkbuf-sel = <0x7>; + }; + + cpsw3g: ethernet@8000000 { + compatible = "ti,am642-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0 0x8000000 0x0 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x0 0x0 0x0 0x8000000 0x0 0x200000>; + clocks = <&k3_clks 13 0>; + assigned-clocks = <&k3_clks 13 1>; + assigned-clock-parents = <&k3_clks 13 9>; + clock-names = "fck"; + power-domains = <&k3_pds 13 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&main_pktdma 0xC500 15>, + <&main_pktdma 0xC501 15>, + <&main_pktdma 0xC502 15>, + <&main_pktdma 0xC503 15>, + <&main_pktdma 0xC504 15>, + <&main_pktdma 0xC505 15>, + <&main_pktdma 0xC506 15>, + <&main_pktdma 0xC507 15>, + <&main_pktdma 0x4500 15>; + dma-names = "tx0", "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", + "tx7", "rx"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + label = "port1"; + phys = <&phy_gmii_sel 1>; + mac-address = [00 00 de ad be ef]; + }; + + cpsw_port2: port@2 { + reg = <2>; + ti,mac-only; + label = "port2"; + phys = <&phy_gmii_sel 2>; + mac-address = [00 01 de ad be ef]; + }; + }; + + cpsw3g_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x0 0xf00 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 13 0>; + clock-names = "fck"; + bus_freq = <1000000>; + }; + + cpts@3d000 { + compatible = "ti,j721e-cpts"; + reg = <0x0 0x3d000 0x0 0x400>; + clocks = <&k3_clks 13 1>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + + cpts@39000000 { + compatible = "ti,j721e-cpts"; + reg = <0x0 0x39000000 0x0 0x400>; + reg-names = "cpts"; + power-domains = <&k3_pds 84 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 84 0>; + clock-names = "cpts"; + assigned-clocks = <&k3_clks 84 0>; + assigned-clock-parents = <&k3_clks 84 8>; + interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-periodic-outputs = <6>; + ti,cpts-ext-ts-inputs = <8>; + }; + + usbss0: cdns-usb@f900000{ + compatible = "ti,am64-usb"; + reg = <0x00 0xf900000 0x00 0x100>; + power-domains = <&k3_pds 161 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 161 9>, <&k3_clks 161 1>; + clock-names = "ref", "lpm"; + assigned-clocks = <&k3_clks 161 9>; /* USB2_REFCLK */ + assigned-clock-parents = <&k3_clks 161 10>; /* HF0SC0 */ + #address-cells = <2>; + #size-cells = <2>; + ranges; + usb0: usb@f400000{ + compatible = "cdns,usb3"; + reg = <0x00 0xf400000 0x00 0x10000>, + <0x00 0xf410000 0x00 0x10000>, + <0x00 0xf420000 0x00 0x10000>; + reg-names = "otg", + "xhci", + "dev"; + interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, /* irq.0 */ + <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>, /* irq.6 */ + <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>; /* otgirq */ + interrupt-names = "host", + "peripheral", + "otg"; + maximum-speed = "super-speed"; + dr_mode = "otg"; + }; + }; + + tscadc0: tscadc@28001000 { + compatible = "ti,am654-tscadc", "ti,am3359-tscadc"; + reg = <0x00 0x28001000 0x00 0x1000>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&k3_pds 0 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 0 0>; + assigned-clocks = <&k3_clks 0 0>; + assigned-clock-parents = <&k3_clks 0 3>; + assigned-clock-rates = <60000000>; + clock-names = "adc_tsc_fck"; + + adc { + #io-channel-cells = <1>; + compatible = "ti,am654-adc", "ti,am3359-adc"; + }; + }; + + fss: bus@fc00000 { + compatible = "simple-bus"; + reg = <0x00 0x0fc00000 0x00 0x70000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ospi0: spi@fc40000 { + compatible = "ti,am654-ospi", "cdns,qspi-nor"; + reg = <0x00 0x0fc40000 0x00 0x100>, + <0x05 0x00000000 0x01 0x00000000>; + interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x0>; + #address-cells = <0x1>; + #size-cells = <0x0>; + clocks = <&k3_clks 75 6>; + assigned-clocks = <&k3_clks 75 6>; + assigned-clock-parents = <&k3_clks 75 7>; + assigned-clock-rates = <166666666>; + power-domains = <&k3_pds 75 TI_SCI_PD_EXCLUSIVE>; + }; + }; + + hwspinlock: spinlock@2a000000 { + compatible = "ti,am64-hwspinlock"; + reg = <0x00 0x2a000000 0x00 0x1000>; + #hwlock-cells = <1>; + }; + + mailbox0_cluster2: mailbox@29020000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29020000 0x00 0x200>; + interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster3: mailbox@29030000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29030000 0x00 0x200>; + interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster4: mailbox@29040000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29040000 0x00 0x200>; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster5: mailbox@29050000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29050000 0x00 0x200>; + interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster6: mailbox@29060000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29060000 0x00 0x200>; + interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster7: mailbox@29070000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29070000 0x00 0x200>; + interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..99e94dee1bd45812608f80cfbed7c87c8d725a01 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM64 SoC Family MCU Domain peripherals + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +&cbass_mcu { + mcu_uart0: serial@4a00000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x04a00000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 149 0>; + clock-names = "fclk"; + }; + + mcu_uart1: serial@4a10000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x04a10000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 160 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 160 0>; + clock-names = "fclk"; + }; + + mcu_i2c0: i2c@4900000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x04900000 0x00 0x100>; + interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 106 2>; + clock-names = "fck"; + }; + + mcu_i2c1: i2c@4910000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x04910000 0x00 0x100>; + interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 107 2>; + clock-names = "fck"; + }; + + mcu_spi0: spi@4b00000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x04b00000 0x00 0x400>; + interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 147 0>; + }; + + mcu_spi1: spi@4b10000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x04b10000 0x00 0x400>; + interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 148 0>; + }; + + mcu_gpio_intr: interrupt-controller1 { + compatible = "ti,sci-intr"; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <5>; + ti,interrupt-ranges = <0 104 4>; + }; + + mcu_gpio0: gpio@4201000 { + compatible = "ti,am64-gpio", "keystone-gpio"; + reg = <0x0 0x4201000 0x0 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&mcu_gpio_intr>; + interrupts = <30>, <31>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <23>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 79 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 79 0>; + clock-names = "gpio"; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am64.dtsi b/arch/arm64/boot/dts/ti/k3-am64.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..de6805b0c72c1709e8d2d96ca8e75954912f10f9 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am64.dtsi @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM642 SoC Family + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/pinctrl/k3.h> +#include <dt-bindings/soc/ti,sci_pm_domain.h> + +/ { + model = "Texas Instruments K3 AM642 SoC"; + compatible = "ti,am642"; + interrupt-parent = <&gic500>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &mcu_uart0; + serial1 = &mcu_uart1; + serial2 = &main_uart0; + serial3 = &main_uart1; + serial4 = &main_uart2; + serial5 = &main_uart3; + serial6 = &main_uart4; + serial7 = &main_uart5; + serial8 = &main_uart6; + ethernet0 = &cpsw_port1; + ethernet1 = &cpsw_port2; + }; + + chosen { }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + }; + + a53_timer0: timer-cl0-cpu0 { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* cntpsirq */ + <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* cntpnsirq */ + <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* cntvirq */ + <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* cnthpirq */ + }; + + pmu: pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>; + }; + + cbass_main: bus@f4000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x000f4000 0x00 0x000f4000 0x00 0x000002d0>, /* PINCTRL */ + <0x00 0x00600000 0x00 0x00600000 0x00 0x00001100>, /* GPIO */ + <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* Timesync router */ + <0x00 0x01000000 0x00 0x01000000 0x00 0x02330400>, /* First peripheral window */ + <0x00 0x08000000 0x00 0x08000000 0x00 0x00200000>, /* Main CPSW */ + <0x00 0x0d000000 0x00 0x0d000000 0x00 0x00800000>, /* PCIE_CORE */ + <0x00 0x0f000000 0x00 0x0f000000 0x00 0x00c44200>, /* Second peripheral window */ + <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */ + <0x00 0x30000000 0x00 0x30000000 0x00 0x000bc100>, /* ICSSG0/1 */ + <0x00 0x37000000 0x00 0x37000000 0x00 0x00040000>, /* TIMERMGR0 TIMERS */ + <0x00 0x39000000 0x00 0x39000000 0x00 0x00000400>, /* CPTS0 */ + <0x00 0x3b000000 0x00 0x3b000000 0x00 0x00000400>, /* GPMC0_CFG */ + <0x00 0x3cd00000 0x00 0x3cd00000 0x00 0x00000200>, /* TIMERMGR0_CONFIG */ + <0x00 0x3f004000 0x00 0x3f004000 0x00 0x00000400>, /* GICSS0_REGS */ + <0x00 0x43000000 0x00 0x43000000 0x00 0x00020000>, /* CTRL_MMR0 */ + <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */ + <0x00 0x48000000 0x00 0x48000000 0x00 0x06400000>, /* DMASS */ + <0x00 0x50000000 0x00 0x50000000 0x00 0x08000000>, /* GPMC0 DATA */ + <0x00 0x60000000 0x00 0x60000000 0x00 0x08000000>, /* FSS0 DAT1 */ + <0x00 0x68000000 0x00 0x68000000 0x00 0x08000000>, /* PCIe DAT0 */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00200000>, /* OC SRAM */ + <0x00 0x78000000 0x00 0x78000000 0x00 0x00800000>, /* Main R5FSS */ + <0x06 0x00000000 0x06 0x00000000 0x01 0x00000000>, /* PCIe DAT1 */ + <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS0 DAT3 */ + + /* MCU Domain Range */ + <0x00 0x04000000 0x00 0x04000000 0x00 0x01ff1400>; + + cbass_mcu: bus@4000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x04000000 0x00 0x04000000 0x00 0x01ff1400>; /* Peripheral window */ + }; + }; +}; + +/* Now include the peripherals for each bus segments */ +#include "k3-am64-main.dtsi" +#include "k3-am64-mcu.dtsi" diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts new file mode 100644 index 0000000000000000000000000000000000000000..dad0efa961ed11701f7b7ab94244922956e18843 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; + +#include <dt-bindings/leds/common.h> +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/net/ti-dp83867.h> +#include "k3-am642.dtsi" + +/ { + compatible = "ti,am642-evm", "ti,am642"; + model = "Texas Instruments AM642 EVM"; + + chosen { + stdout-path = "serial2:115200n8"; + bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000"; + }; + + memory@80000000 { + device_type = "memory"; + /* 2G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>; + + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + secure_ddr: optee@9e800000 { + reg = <0x00 0x9e800000 0x00 0x01800000>; /* for OP-TEE */ + alignment = <0x1000>; + no-map; + }; + }; + + evm_12v0: fixedregulator-evm12v0 { + /* main DC jack */ + compatible = "regulator-fixed"; + regulator-name = "evm_12v0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_5v0: fixedregulator-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; + }; + + vsys_3v3: fixedregulator-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; + }; + + vdd_mmc1: fixed-regulator-sd { + /* TPS2051BD */ + 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 = <&exp1 6 GPIO_ACTIVE_HIGH>; + }; + + vddb: fixedregulator-vddb { + compatible = "regulator-fixed"; + regulator-name = "vddb_3v3_display"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vsys_3v3>; + regulator-always-on; + regulator-boot-on; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + label = "am64-evm:red:heartbeat"; + gpios = <&exp1 16 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_HEARTBEAT; + default-state = "off"; + }; + }; + + mdio_mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&exp1 12 GPIO_ACTIVE_HIGH>; + }; + + mdio-mux-1 { + compatible = "mdio-mux-multiplexer"; + mux-controls = <&mdio_mux>; + mdio-parent-bus = <&cpsw3g_mdio>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@1 { + reg = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + + cpsw3g_phy3: ethernet-phy@3 { + reg = <3>; + }; + }; + }; +}; + +&main_pmx0 { + main_mmc1_pins_default: main-mmc1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0294, PIN_INPUT_PULLUP, 0) /* (J19) MMC1_CMD */ + AM64X_IOPAD(0x028c, PIN_INPUT_PULLDOWN, 0) /* (L20) MMC1_CLK */ + AM64X_IOPAD(0x0288, PIN_INPUT_PULLUP, 0) /* (K21) MMC1_DAT0 */ + AM64X_IOPAD(0x0284, PIN_INPUT_PULLUP, 0) /* (L21) MMC1_DAT1 */ + AM64X_IOPAD(0x0280, PIN_INPUT_PULLUP, 0) /* (K19) MMC1_DAT2 */ + AM64X_IOPAD(0x027c, PIN_INPUT_PULLUP, 0) /* (K18) MMC1_DAT3 */ + AM64X_IOPAD(0x0298, PIN_INPUT_PULLUP, 0) /* (D19) MMC1_SDCD */ + AM64X_IOPAD(0x029c, PIN_INPUT, 0) /* (C20) MMC1_SDWP */ + AM64X_IOPAD(0x0290, PIN_INPUT, 0) /* MMC1_CLKLB */ + >; + }; + + main_uart0_pins_default: main-uart0-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0238, PIN_INPUT, 0) /* (B16) UART0_CTSn */ + AM64X_IOPAD(0x023c, PIN_OUTPUT, 0) /* (A16) UART0_RTSn */ + AM64X_IOPAD(0x0230, PIN_INPUT, 0) /* (D15) UART0_RXD */ + AM64X_IOPAD(0x0234, PIN_OUTPUT, 0) /* (C16) UART0_TXD */ + >; + }; + + main_spi0_pins_default: main-spi0-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0210, PIN_INPUT, 0) /* (D13) SPI0_CLK */ + AM64X_IOPAD(0x0208, PIN_OUTPUT, 0) /* (D12) SPI0_CS0 */ + AM64X_IOPAD(0x0214, PIN_OUTPUT, 0) /* (A13) SPI0_D0 */ + AM64X_IOPAD(0x0218, PIN_INPUT, 0) /* (A14) SPI0_D1 */ + >; + }; + + main_i2c1_pins_default: main-i2c1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0268, PIN_INPUT_PULLUP, 0) /* (C18) I2C1_SCL */ + AM64X_IOPAD(0x026c, PIN_INPUT_PULLUP, 0) /* (B19) I2C1_SDA */ + >; + }; + + mdio1_pins_default: mdio1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x01fc, PIN_OUTPUT, 4) /* (R2) PRG0_PRU1_GPO19.MDIO0_MDC */ + AM64X_IOPAD(0x01f8, PIN_INPUT, 4) /* (P5) PRG0_PRU1_GPO18.MDIO0_MDIO */ + >; + }; + + rgmii1_pins_default: rgmii1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x01cc, PIN_INPUT, 4) /* (W5) PRG0_PRU1_GPO7.RGMII1_RD0 */ + AM64X_IOPAD(0x01d4, PIN_INPUT, 4) /* (Y5) PRG0_PRU1_GPO9.RGMII1_RD1 */ + AM64X_IOPAD(0x01d8, PIN_INPUT, 4) /* (V6) PRG0_PRU1_GPO10.RGMII1_RD2 */ + AM64X_IOPAD(0x01f4, PIN_INPUT, 4) /* (V5) PRG0_PRU1_GPO17.RGMII1_RD3 */ + AM64X_IOPAD(0x0188, PIN_INPUT, 4) /* (AA5) PRG0_PRU0_GPO10.RGMII1_RXC */ + AM64X_IOPAD(0x0184, PIN_INPUT, 4) /* (W6) PRG0_PRU0_GPO9.RGMII1_RX_CTL */ + AM64X_IOPAD(0x0124, PIN_OUTPUT, 4) /* (V15) PRG1_PRU1_GPO7.RGMII1_TD0 */ + AM64X_IOPAD(0x012c, PIN_OUTPUT, 4) /* (V14) PRG1_PRU1_GPO9.RGMII1_TD1 */ + AM64X_IOPAD(0x0130, PIN_OUTPUT, 4) /* (W14) PRG1_PRU1_GPO10.RGMII1_TD2 */ + AM64X_IOPAD(0x014c, PIN_OUTPUT, 4) /* (AA14) PRG1_PRU1_GPO17.RGMII1_TD3 */ + AM64X_IOPAD(0x00e0, PIN_OUTPUT, 4) /* (U14) PRG1_PRU0_GPO10.RGMII1_TXC */ + AM64X_IOPAD(0x00dc, PIN_OUTPUT, 4) /* (U15) PRG1_PRU0_GPO9.RGMII1_TX_CTL */ + >; + }; + + rgmii2_pins_default: rgmii2-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0108, PIN_INPUT, 4) /* (W11) PRG1_PRU1_GPO0.RGMII2_RD0 */ + AM64X_IOPAD(0x010c, PIN_INPUT, 4) /* (V11) PRG1_PRU1_GPO1.RGMII2_RD1 */ + AM64X_IOPAD(0x0110, PIN_INPUT, 4) /* (AA12) PRG1_PRU1_GPO2.RGMII2_RD2 */ + AM64X_IOPAD(0x0114, PIN_INPUT, 4) /* (Y12) PRG1_PRU1_GPO3.RGMII2_RD3 */ + AM64X_IOPAD(0x0120, PIN_INPUT, 4) /* (U11) PRG1_PRU1_GPO6.RGMII2_RXC */ + AM64X_IOPAD(0x0118, PIN_INPUT, 4) /* (W12) PRG1_PRU1_GPO4.RGMII2_RX_CTL */ + AM64X_IOPAD(0x0134, PIN_OUTPUT, 4) /* (AA10) PRG1_PRU1_GPO11.RGMII2_TD0 */ + AM64X_IOPAD(0x0138, PIN_OUTPUT, 4) /* (V10) PRG1_PRU1_GPO12.RGMII2_TD1 */ + AM64X_IOPAD(0x013c, PIN_OUTPUT, 4) /* (U10) PRG1_PRU1_GPO13.RGMII2_TD2 */ + AM64X_IOPAD(0x0140, PIN_OUTPUT, 4) /* (AA11) PRG1_PRU1_GPO14.RGMII2_TD3 */ + AM64X_IOPAD(0x0148, PIN_OUTPUT, 4) /* (Y10) PRG1_PRU1_GPO16.RGMII2_TXC */ + AM64X_IOPAD(0x0144, PIN_OUTPUT, 4) /* (Y11) PRG1_PRU1_GPO15.RGMII2_TX_CTL */ + >; + }; + + main_usb0_pins_default: main-usb0-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */ + >; + }; + + ospi0_pins_default: ospi0-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0000, PIN_OUTPUT, 0) /* (N20) OSPI0_CLK */ + AM64X_IOPAD(0x002c, PIN_OUTPUT, 0) /* (L19) OSPI0_CSn0 */ + AM64X_IOPAD(0x000c, PIN_INPUT, 0) /* (M19) OSPI0_D0 */ + AM64X_IOPAD(0x0010, PIN_INPUT, 0) /* (M18) OSPI0_D1 */ + AM64X_IOPAD(0x0014, PIN_INPUT, 0) /* (M20) OSPI0_D2 */ + AM64X_IOPAD(0x0018, PIN_INPUT, 0) /* (M21) OSPI0_D3 */ + AM64X_IOPAD(0x001c, PIN_INPUT, 0) /* (P21) OSPI0_D4 */ + AM64X_IOPAD(0x0020, PIN_INPUT, 0) /* (P20) OSPI0_D5 */ + AM64X_IOPAD(0x0024, PIN_INPUT, 0) /* (N18) OSPI0_D6 */ + AM64X_IOPAD(0x0028, PIN_INPUT, 0) /* (M17) OSPI0_D7 */ + AM64X_IOPAD(0x0008, PIN_INPUT, 0) /* (N19) OSPI0_DQS */ + >; + }; +}; + +&main_uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart0_pins_default>; +}; + +/* main_uart1 is reserved for firmware usage */ +&main_uart1 { + status = "reserved"; +}; + +&main_uart2 { + status = "disabled"; +}; + +&main_uart3 { + status = "disabled"; +}; + +&main_uart4 { + status = "disabled"; +}; + +&main_uart5 { + status = "disabled"; +}; + +&main_uart6 { + status = "disabled"; +}; + +&mcu_uart0 { + status = "disabled"; +}; + +&mcu_uart1 { + status = "disabled"; +}; + +&main_i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <400000>; + + exp1: gpio@22 { + compatible = "ti,tca6424"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "GPIO_eMMC_RSTn", "CAN_MUX_SEL", + "GPIO_CPSW1_RST", "GPIO_RGMII1_RST", + "GPIO_RGMII2_RST", "GPIO_PCIe_RST_OUT", + "MMC1_SD_EN", "FSI_FET_SEL", + "MCAN0_STB_3V3", "MCAN1_STB_3V3", + "CPSW_FET_SEL", "CPSW_FET2_SEL", + "PRG1_RGMII2_FET_SEL", "TEST_GPIO2", + "GPIO_OLED_RESETn", "VPP_LDO_EN", + "TEST_LED1", "TP92", "TP90", "TP88", + "TP87", "TP86", "TP89", "TP91"; + }; + + /* osd9616p0899-10 */ + display@3c { + compatible = "solomon,ssd1306fb-i2c"; + reg = <0x3c>; + reset-gpios = <&exp1 14 GPIO_ACTIVE_LOW>; + vbat-supply = <&vddb>; + solomon,height = <16>; + solomon,width = <96>; + solomon,com-seq; + solomon,com-invdir; + solomon,page-offset = <0>; + solomon,prechargep1 = <2>; + solomon,prechargep2 = <13>; + }; +}; + +/* mcu_gpio0 is reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_i2c0 { + status = "disabled"; +}; + +&mcu_i2c1 { + status = "disabled"; +}; + +&mcu_spi0 { + status = "disabled"; +}; + +&mcu_spi1 { + status = "disabled"; +}; + +&main_spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_spi0_pins_default>; + ti,pindir-d0-out-d1-in = <1>; + eeprom@0 { + compatible = "microchip,93lc46b"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cs-high; + data-size = <16>; + }; +}; + +&sdhci0 { + /* emmc */ + bus-width = <8>; + non-removable; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&sdhci1 { + /* SD/MMC */ + vmmc-supply = <&vdd_mmc1>; + pinctrl-names = "default"; + bus-width = <4>; + pinctrl-0 = <&main_mmc1_pins_default>; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&usbss0 { + ti,vbus-divider; + ti,usb2-only; +}; + +&usb0 { + dr_mode = "otg"; + maximum-speed = "high-speed"; + pinctrl-names = "default"; + pinctrl-0 = <&main_usb0_pins_default>; +}; + +&cpsw3g { + pinctrl-names = "default"; + pinctrl-0 = <&mdio1_pins_default + &rgmii1_pins_default + &rgmii2_pins_default>; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy0>; +}; + +&cpsw_port2 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy3>; +}; + +&cpsw3g_mdio { + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + }; +}; + +&tscadc0 { + /* ADC is reserved for R5 usage */ + status = "reserved"; +}; + +&ospi0 { + pinctrl-names = "default"; + pinctrl-0 = <&ospi0_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>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&mailbox0_cluster2 { + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster3 { + status = "disabled"; +}; + +&mailbox0_cluster4 { + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster5 { + status = "disabled"; +}; + +&mailbox0_cluster6 { + mbox_m4_0: mbox-m4-0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; +}; + +&mailbox0_cluster7 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts new file mode 100644 index 0000000000000000000000000000000000000000..8424cd071955591d862dc9530ff2d99795f39e1d --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/net/ti-dp83867.h> +#include "k3-am642.dtsi" + +/ { + compatible = "ti,am642-sk", "ti,am642"; + model = "Texas Instruments AM642 SK"; + + chosen { + stdout-path = "serial2:115200n8"; + bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000"; + }; + + memory@80000000 { + device_type = "memory"; + /* 2G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>; + + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + secure_ddr: optee@9e800000 { + reg = <0x00 0x9e800000 0x00 0x01800000>; /* for OP-TEE */ + alignment = <0x1000>; + no-map; + }; + }; + + vusb_main: fixed-regulator-vusb-main5v0 { + /* USB MAIN INPUT 5V DC */ + compatible = "regulator-fixed"; + regulator-name = "vusb_main5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_3v3_sys: fixedregulator-vcc-3v3-sys { + /* output of LP8733xx */ + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_sys"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vusb_main>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_mmc1: fixed-regulator-sd { + /* TPS2051BD */ + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + vin-supply = <&vcc_3v3_sys>; + gpio = <&exp1 3 GPIO_ACTIVE_HIGH>; + }; +}; + +&main_pmx0 { + main_mmc1_pins_default: main-mmc1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0294, PIN_INPUT, 0) /* (J19) MMC1_CMD */ + AM64X_IOPAD(0x0290, PIN_INPUT, 0) /* (#N/A) MMC1_CLKLB */ + AM64X_IOPAD(0x028c, PIN_INPUT, 0) /* (L20) MMC1_CLK */ + AM64X_IOPAD(0x0288, PIN_INPUT, 0) /* (K21) MMC1_DAT0 */ + AM64X_IOPAD(0x0284, PIN_INPUT, 0) /* (L21) MMC1_DAT1 */ + AM64X_IOPAD(0x0280, PIN_INPUT, 0) /* (K19) MMC1_DAT2 */ + AM64X_IOPAD(0x027c, PIN_INPUT, 0) /* (K18) MMC1_DAT3 */ + AM64X_IOPAD(0x0298, PIN_INPUT, 0) /* (D19) MMC1_SDCD */ + >; + }; + + main_i2c1_pins_default: main-i2c1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0268, PIN_INPUT_PULLUP, 0) /* (C18) I2C1_SCL */ + AM64X_IOPAD(0x026c, PIN_INPUT_PULLUP, 0) /* (B19) I2C1_SDA */ + >; + }; + + mdio1_pins_default: mdio1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x01fc, PIN_OUTPUT, 4) /* (R2) PRG0_PRU1_GPO19.MDIO0_MDC */ + AM64X_IOPAD(0x01f8, PIN_INPUT, 4) /* (P5) PRG0_PRU1_GPO18.MDIO0_MDIO */ + >; + }; + + rgmii1_pins_default: rgmii1-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x011c, PIN_INPUT, 4) /* (AA13) PRG1_PRU1_GPO5.RGMII1_RD0 */ + AM64X_IOPAD(0x0128, PIN_INPUT, 4) /* (U12) PRG1_PRU1_GPO8.RGMII1_RD1 */ + AM64X_IOPAD(0x0150, PIN_INPUT, 4) /* (Y13) PRG1_PRU1_GPO18.RGMII1_RD2 */ + AM64X_IOPAD(0x0154, PIN_INPUT, 4) /* (V12) PRG1_PRU1_GPO19.RGMII1_RD3 */ + AM64X_IOPAD(0x00d8, PIN_INPUT, 4) /* (W13) PRG1_PRU0_GPO8.RGMII1_RXC */ + AM64X_IOPAD(0x00cc, PIN_INPUT, 4) /* (V13) PRG1_PRU0_GPO5.RGMII1_RX_CTL */ + AM64X_IOPAD(0x0124, PIN_OUTPUT, 4) /* (V15) PRG1_PRU1_GPO7.RGMII1_TD0 */ + AM64X_IOPAD(0x012c, PIN_OUTPUT, 4) /* (V14) PRG1_PRU1_GPO9.RGMII1_TD1 */ + AM64X_IOPAD(0x0130, PIN_OUTPUT, 4) /* (W14) PRG1_PRU1_GPO10.RGMII1_TD2 */ + AM64X_IOPAD(0x014c, PIN_OUTPUT, 4) /* (AA14) PRG1_PRU1_GPO17.RGMII1_TD3 */ + AM64X_IOPAD(0x00e0, PIN_OUTPUT, 4) /* (U14) PRG1_PRU0_GPO10.RGMII1_TXC */ + AM64X_IOPAD(0x00dc, PIN_OUTPUT, 4) /* (U15) PRG1_PRU0_GPO9.RGMII1_TX_CTL */ + >; + }; + + rgmii2_pins_default: rgmii2-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0108, PIN_INPUT, 4) /* (W11) PRG1_PRU1_GPO0.RGMII2_RD0 */ + AM64X_IOPAD(0x010c, PIN_INPUT, 4) /* (V11) PRG1_PRU1_GPO1.RGMII2_RD1 */ + AM64X_IOPAD(0x0110, PIN_INPUT, 4) /* (AA12) PRG1_PRU1_GPO2.RGMII2_RD2 */ + AM64X_IOPAD(0x0114, PIN_INPUT, 4) /* (Y12) PRG1_PRU1_GPO3.RGMII2_RD3 */ + AM64X_IOPAD(0x0120, PIN_INPUT, 4) /* (U11) PRG1_PRU1_GPO6.RGMII2_RXC */ + AM64X_IOPAD(0x0118, PIN_INPUT, 4) /* (W12) PRG1_PRU1_GPO4.RGMII2_RX_CTL */ + AM64X_IOPAD(0x0134, PIN_OUTPUT, 4) /* (AA10) PRG1_PRU1_GPO11.RGMII2_TD0 */ + AM64X_IOPAD(0x0138, PIN_OUTPUT, 4) /* (V10) PRG1_PRU1_GPO12.RGMII2_TD1 */ + AM64X_IOPAD(0x013c, PIN_OUTPUT, 4) /* (U10) PRG1_PRU1_GPO13.RGMII2_TD2 */ + AM64X_IOPAD(0x0140, PIN_OUTPUT, 4) /* (AA11) PRG1_PRU1_GPO14.RGMII2_TD3 */ + AM64X_IOPAD(0x0148, PIN_OUTPUT, 4) /* (Y10) PRG1_PRU1_GPO16.RGMII2_TXC */ + AM64X_IOPAD(0x0144, PIN_OUTPUT, 4) /* (Y11) PRG1_PRU1_GPO15.RGMII2_TX_CTL */ + >; + }; + + ospi0_pins_default: ospi0-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x0000, PIN_OUTPUT, 0) /* (N20) OSPI0_CLK */ + AM64X_IOPAD(0x002c, PIN_OUTPUT, 0) /* (L19) OSPI0_CSn0 */ + AM64X_IOPAD(0x000c, PIN_INPUT, 0) /* (M19) OSPI0_D0 */ + AM64X_IOPAD(0x0010, PIN_INPUT, 0) /* (M18) OSPI0_D1 */ + AM64X_IOPAD(0x0014, PIN_INPUT, 0) /* (M20) OSPI0_D2 */ + AM64X_IOPAD(0x0018, PIN_INPUT, 0) /* (M21) OSPI0_D3 */ + AM64X_IOPAD(0x001c, PIN_INPUT, 0) /* (P21) OSPI0_D4 */ + AM64X_IOPAD(0x0020, PIN_INPUT, 0) /* (P20) OSPI0_D5 */ + AM64X_IOPAD(0x0024, PIN_INPUT, 0) /* (N18) OSPI0_D6 */ + AM64X_IOPAD(0x0028, PIN_INPUT, 0) /* (M17) OSPI0_D7 */ + AM64X_IOPAD(0x0008, PIN_INPUT, 0) /* (N19) OSPI0_DQS */ + >; + }; +}; + +&mcu_uart0 { + status = "disabled"; +}; + +&mcu_uart1 { + status = "disabled"; +}; + +&main_uart1 { + /* main_uart1 is reserved for firmware usage */ + status = "reserved"; +}; + +&main_uart2 { + status = "disabled"; +}; + +&main_uart3 { + status = "disabled"; +}; + +&main_uart4 { + status = "disabled"; +}; + +&main_uart5 { + status = "disabled"; +}; + +&main_uart6 { + status = "disabled"; +}; + +&mcu_i2c0 { + status = "disabled"; +}; + +&mcu_i2c1 { + status = "disabled"; +}; + +&main_i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <400000>; + + exp1: gpio@70 { + compatible = "nxp,pca9538"; + reg = <0x70>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "GPIO_CPSW2_RST", "GPIO_CPSW1_RST", + "PRU_DETECT", "MMC1_SD_EN", + "VPP_LDO_EN", "RPI_PS_3V3_En", + "RPI_PS_5V0_En", "RPI_HAT_DETECT"; + }; +}; + +&main_i2c3 { + status = "disabled"; +}; + +&mcu_spi0 { + status = "disabled"; +}; + +&mcu_spi1 { + status = "disabled"; +}; + +/* mcu_gpio0 is reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&sdhci1 { + /* SD/MMC */ + vmmc-supply = <&vdd_mmc1>; + pinctrl-names = "default"; + bus-width = <4>; + pinctrl-0 = <&main_mmc1_pins_default>; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&cpsw3g { + pinctrl-names = "default"; + pinctrl-0 = <&mdio1_pins_default + &rgmii1_pins_default + &rgmii2_pins_default>; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy0>; +}; + +&cpsw_port2 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy1>; +}; + +&cpsw3g_mdio { + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + }; + + cpsw3g_phy1: ethernet-phy@1 { + reg = <1>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + }; +}; + +&tscadc0 { + status = "disabled"; +}; + +&ospi0 { + pinctrl-names = "default"; + pinctrl-0 = <&ospi0_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>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&mailbox0_cluster2 { + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster3 { + status = "disabled"; +}; + +&mailbox0_cluster4 { + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster5 { + status = "disabled"; +}; + +&mailbox0_cluster6 { + mbox_m4_0: mbox-m4-0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; +}; + +&mailbox0_cluster7 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am642.dtsi b/arch/arm64/boot/dts/ti/k3-am642.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e2b397c88401858594a4de131cdb7d422a2472dc --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am642.dtsi @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM642 SoC family in Dual core configuration + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; + +#include "k3-am64.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0: cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x000>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-size = <0x40000>; + cache-line-size = <64>; + cache-sets = <512>; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..de763ca9251c71f25d6c24caae4be4cc24faf36d --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Siemens AG, 2018-2021 + * + * Authors: + * Le Jin <le.jin@siemens.com> + * Jan Kiszka <jan.kiszk@siemens.com> + * + * Common bits of the IOT2050 Basic and Advanced variants + */ + +/dts-v1/; + +#include "k3-am654.dtsi" +#include <dt-bindings/phy/phy.h> + +/ { + aliases { + spi0 = &mcu_spi0; + }; + + chosen { + stdout-path = "serial3:115200n8"; + bootargs = "earlycon=ns16550a,mmio32,0x02810000"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + secure_ddr: secure-ddr@9e800000 { + reg = <0 0x9e800000 0 0x01800000>; /* for OP-TEE */ + alignment = <0x1000>; + no-map; + }; + + mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0 0xa0000000 0 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0 0xa0100000 0 0xf00000>; + no-map; + }; + + mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0 0xa1000000 0 0x100000>; + no-map; + }; + + mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0 0xa1100000 0 0xf00000>; + no-map; + }; + + rtos_ipc_memory_region: ipc-memories@a2000000 { + reg = <0x00 0xa2000000 0x00 0x00200000>; + alignment = <0x1000>; + no-map; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&leds_pins_default>; + + status-led-red { + gpios = <&wkup_gpio0 32 GPIO_ACTIVE_HIGH>; + panic-indicator; + }; + + status-led-green { + gpios = <&wkup_gpio0 24 GPIO_ACTIVE_HIGH>; + }; + + user-led1-red { + gpios = <&pcal9535_3 14 GPIO_ACTIVE_HIGH>; + }; + + user-led1-green { + gpios = <&pcal9535_2 15 GPIO_ACTIVE_HIGH>; + }; + + user-led2-red { + gpios = <&wkup_gpio0 17 GPIO_ACTIVE_HIGH>; + }; + + user-led2-green { + gpios = <&wkup_gpio0 22 GPIO_ACTIVE_HIGH>; + }; + }; + + dp_refclk: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <19200000>; + }; +}; + +&wkup_pmx0 { + wkup_i2c0_pins_default: wkup-i2c0-pins-default { + pinctrl-single,pins = < + /* (AC7) WKUP_I2C0_SCL */ + AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) + /* (AD6) WKUP_I2C0_SDA */ + AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) + >; + }; + + mcu_i2c0_pins_default: mcu-i2c0-pins-default { + pinctrl-single,pins = < + /* (AD8) MCU_I2C0_SCL */ + AM65X_WKUP_IOPAD(0x00e8, PIN_INPUT, 0) + /* (AD7) MCU_I2C0_SDA */ + AM65X_WKUP_IOPAD(0x00ec, PIN_INPUT, 0) + >; + }; + + arduino_i2c_aio_switch_pins_default: arduino-i2c-aio-switch-pins-default { + pinctrl-single,pins = < + /* (R2) WKUP_GPIO0_21 */ + AM65X_WKUP_IOPAD(0x0024, PIN_OUTPUT, 7) + >; + }; + + push_button_pins_default: push-button-pins-default { + pinctrl-single,pins = < + /* (T1) MCU_OSPI1_CLK.WKUP_GPIO0_25 */ + AM65X_WKUP_IOPAD(0x0034, PIN_INPUT, 7) + >; + }; + + arduino_uart_pins_default: arduino-uart-pins-default { + pinctrl-single,pins = < + /* (P4) MCU_UART0_RXD */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) + /* (P5) MCU_UART0_TXD */ + AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) + >; + }; + + arduino_io_d2_to_d3_pins_default: arduino-io-d2-to-d3-pins-default { + pinctrl-single,pins = < + /* (P1) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_OUTPUT, 7) + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 7) + >; + }; + + arduino_io_oe_pins_default: arduino-io-oe-pins-default { + pinctrl-single,pins = < + /* (N4) WKUP_GPIO0_34 */ + AM65X_WKUP_IOPAD(0x0058, PIN_OUTPUT, 7) + /* (M2) WKUP_GPIO0_36 */ + AM65X_WKUP_IOPAD(0x0060, PIN_OUTPUT, 7) + /* (M3) WKUP_GPIO0_37 */ + AM65X_WKUP_IOPAD(0x0064, PIN_OUTPUT, 7) + /* (M4) WKUP_GPIO0_38 */ + AM65X_WKUP_IOPAD(0x0068, PIN_OUTPUT, 7) + /* (M1) WKUP_GPIO0_41 */ + AM65X_WKUP_IOPAD(0x0074, PIN_OUTPUT, 7) + >; + }; + + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-pins-default { + pinctrl-single,pins = < + /* (V1) MCU_OSPI0_CLK */ + AM65X_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) + /* (U2) MCU_OSPI0_DQS */ + AM65X_WKUP_IOPAD(0x0008, PIN_INPUT, 0) + /* (U4) MCU_OSPI0_D0 */ + AM65X_WKUP_IOPAD(0x000c, PIN_INPUT, 0) + /* (U5) MCU_OSPI0_D1 */ + AM65X_WKUP_IOPAD(0x0010, PIN_INPUT, 0) + /* (R4) MCU_OSPI0_CSn0 */ + AM65X_WKUP_IOPAD(0x002c, PIN_OUTPUT, 0) + >; + }; + + db9_com_mode_pins_default: db9-com-mode-pins-default { + pinctrl-single,pins = < + /* (AD3) WKUP_GPIO0_5, used as uart0 mode 0 */ + AM65X_WKUP_IOPAD(0x00c4, PIN_OUTPUT, 7) + /* (AC3) WKUP_GPIO0_4, used as uart0 mode 1 */ + AM65X_WKUP_IOPAD(0x00c0, PIN_OUTPUT, 7) + /* (AC1) WKUP_GPIO0_7, used as uart0 term */ + AM65X_WKUP_IOPAD(0x00cc, PIN_OUTPUT, 7) + /* (AC2) WKUP_GPIO0_6, used as uart0 en */ + AM65X_WKUP_IOPAD(0x00c8, PIN_OUTPUT, 7) + >; + }; + + leds_pins_default: leds-pins-default { + pinctrl-single,pins = < + /* (T2) WKUP_GPIO0_17, used as user led1 red */ + AM65X_WKUP_IOPAD(0x0014, PIN_OUTPUT, 7) + /* (R3) WKUP_GPIO0_22, used as user led1 green */ + AM65X_WKUP_IOPAD(0x0028, PIN_OUTPUT, 7) + /* (R5) WKUP_GPIO0_24, used as status led red */ + AM65X_WKUP_IOPAD(0x0030, PIN_OUTPUT, 7) + /* (N2) WKUP_GPIO0_32, used as status led green */ + AM65X_WKUP_IOPAD(0x0050, PIN_OUTPUT, 7) + >; + }; + + mcu_spi0_pins_default: mcu-spi0-pins-default { + pinctrl-single,pins = < + /* (Y1) MCU_SPI0_CLK */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0) + /* (Y3) MCU_SPI0_D0 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0) + /* (Y2) MCU_SPI0_D1 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0) + /* (Y4) MCU_SPI0_CS0 */ + AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0) + >; + }; + + minipcie_pins_default: minipcie-pins-default { + pinctrl-single,pins = < + /* (P2) MCU_OSPI1_DQS.WKUP_GPIO0_27 */ + AM65X_WKUP_IOPAD(0x003C, PIN_OUTPUT, 7) + >; + }; +}; + +&main_pmx0 { + main_uart1_pins_default: main-uart1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ + AM65X_IOPAD(0x014c, PIN_OUTPUT, 6) /* (AD23) UART1_TXD */ + AM65X_IOPAD(0x0178, PIN_INPUT, 6) /* (AD22) UART1_CTSn */ + AM65X_IOPAD(0x017c, PIN_OUTPUT, 6) /* (AC21) UART1_RTSn */ + >; + }; + + main_i2c3_pins_default: main-i2c3-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01c0, PIN_INPUT, 2) /* (AF13) I2C3_SCL */ + AM65X_IOPAD(0x01d4, PIN_INPUT, 2) /* (AG12) I2C3_SDA */ + >; + }; + + main_mmc1_pins_default: main-mmc1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x02d4, PIN_INPUT_PULLDOWN, 0) /* (C27) MMC1_CLK */ + AM65X_IOPAD(0x02d8, PIN_INPUT_PULLUP, 0) /* (C28) MMC1_CMD */ + AM65X_IOPAD(0x02d0, PIN_INPUT_PULLUP, 0) /* (D28) MMC1_DAT0 */ + AM65X_IOPAD(0x02cc, PIN_INPUT_PULLUP, 0) /* (E27) MMC1_DAT1 */ + AM65X_IOPAD(0x02c8, PIN_INPUT_PULLUP, 0) /* (D26) MMC1_DAT2 */ + AM65X_IOPAD(0x02c4, PIN_INPUT_PULLUP, 0) /* (D27) MMC1_DAT3 */ + AM65X_IOPAD(0x02dc, PIN_INPUT_PULLUP, 0) /* (B24) MMC1_SDCD */ + AM65X_IOPAD(0x02e0, PIN_INPUT_PULLUP, 0) /* (C24) MMC1_SDWP */ + >; + }; + + usb0_pins_default: usb0-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x02bc, PIN_OUTPUT, 0) /* (AD9) USB0_DRVVBUS */ + >; + }; + + usb1_pins_default: usb1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x02c0, PIN_OUTPUT, 0) /* (AC8) USB1_DRVVBUS */ + >; + }; + + arduino_io_d4_to_d9_pins_default: arduino-io-d4-to-d9-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0084, PIN_OUTPUT, 7) /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x008C, PIN_OUTPUT, 7) /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x0098, PIN_OUTPUT, 7) /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x00AC, PIN_OUTPUT, 7) /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00C0, PIN_OUTPUT, 7) /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00CC, PIN_OUTPUT, 7) /* (AD15) GPIO0_51 */ + >; + }; + + dss_vout1_pins_default: dss-vout1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0000, PIN_OUTPUT, 1) /* VOUT1_DATA0 */ + AM65X_IOPAD(0x0004, PIN_OUTPUT, 1) /* VOUT1_DATA1 */ + AM65X_IOPAD(0x0008, PIN_OUTPUT, 1) /* VOUT1_DATA2 */ + AM65X_IOPAD(0x000c, PIN_OUTPUT, 1) /* VOUT1_DATA3 */ + AM65X_IOPAD(0x0010, PIN_OUTPUT, 1) /* VOUT1_DATA4 */ + AM65X_IOPAD(0x0014, PIN_OUTPUT, 1) /* VOUT1_DATA5 */ + AM65X_IOPAD(0x0018, PIN_OUTPUT, 1) /* VOUT1_DATA6 */ + AM65X_IOPAD(0x001c, PIN_OUTPUT, 1) /* VOUT1_DATA7 */ + AM65X_IOPAD(0x0020, PIN_OUTPUT, 1) /* VOUT1_DATA8 */ + AM65X_IOPAD(0x0024, PIN_OUTPUT, 1) /* VOUT1_DATA9 */ + AM65X_IOPAD(0x0028, PIN_OUTPUT, 1) /* VOUT1_DATA10 */ + AM65X_IOPAD(0x002c, PIN_OUTPUT, 1) /* VOUT1_DATA11 */ + AM65X_IOPAD(0x0030, PIN_OUTPUT, 1) /* VOUT1_DATA12 */ + AM65X_IOPAD(0x0034, PIN_OUTPUT, 1) /* VOUT1_DATA13 */ + AM65X_IOPAD(0x0038, PIN_OUTPUT, 1) /* VOUT1_DATA14 */ + AM65X_IOPAD(0x003c, PIN_OUTPUT, 1) /* VOUT1_DATA15 */ + AM65X_IOPAD(0x0040, PIN_OUTPUT, 1) /* VOUT1_DATA16 */ + AM65X_IOPAD(0x0044, PIN_OUTPUT, 1) /* VOUT1_DATA17 */ + AM65X_IOPAD(0x0048, PIN_OUTPUT, 1) /* VOUT1_DATA18 */ + AM65X_IOPAD(0x004c, PIN_OUTPUT, 1) /* VOUT1_DATA19 */ + AM65X_IOPAD(0x0050, PIN_OUTPUT, 1) /* VOUT1_DATA20 */ + AM65X_IOPAD(0x0054, PIN_OUTPUT, 1) /* VOUT1_DATA21 */ + AM65X_IOPAD(0x0058, PIN_OUTPUT, 1) /* VOUT1_DATA22 */ + AM65X_IOPAD(0x005c, PIN_OUTPUT, 1) /* VOUT1_DATA23 */ + AM65X_IOPAD(0x0060, PIN_OUTPUT, 1) /* VOUT1_VSYNC */ + AM65X_IOPAD(0x0064, PIN_OUTPUT, 1) /* VOUT1_HSYNC */ + AM65X_IOPAD(0x0068, PIN_OUTPUT, 1) /* VOUT1_PCLK */ + AM65X_IOPAD(0x006c, PIN_OUTPUT, 1) /* VOUT1_DE */ + >; + }; + + dp_pins_default: dp-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0078, PIN_OUTPUT, 7) /* (AF18) DP rst_n */ + >; + }; + + main_i2c2_pins_default: main-i2c2-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0074, PIN_INPUT, 5) /* (T27) I2C2_SCL */ + AM65X_IOPAD(0x0070, PIN_INPUT, 5) /* (R25) I2C2_SDA */ + >; + }; +}; + +&main_pmx1 { + main_i2c0_pins_default: main-i2c0-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0000, PIN_INPUT, 0) /* (D20) I2C0_SCL */ + AM65X_IOPAD(0x0004, PIN_INPUT, 0) /* (C21) I2C0_SDA */ + >; + }; + + main_i2c1_pins_default: main-i2c1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0008, PIN_INPUT, 0) /* (B21) I2C1_SCL */ + AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */ + >; + }; + + ecap0_pins_default: ecap0-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0010, PIN_INPUT, 0) /* (D21) ECAP0_IN_APWM_OUT */ + >; + }; +}; + +&wkup_uart0 { + /* Wakeup UART is used by System firmware */ + status = "reserved"; +}; + +&main_uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart1_pins_default>; +}; + +&main_uart2 { + status = "disabled"; +}; + +&mcu_uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&arduino_uart_pins_default>; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&arduino_io_d4_to_d9_pins_default>; + gpio-line-names = + "main_gpio0-base", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "IO4", "", "IO5", "", "", "IO6", "", + "", "", "", "IO7", "", "", "", "", "IO8", "", + "", "IO9"; +}; + +&wkup_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = < + &arduino_io_d2_to_d3_pins_default + &arduino_i2c_aio_switch_pins_default + &arduino_io_oe_pins_default + &push_button_pins_default + &db9_com_mode_pins_default + >; + gpio-line-names = + /* 0..9 */ + "wkup_gpio0-base", "", "", "", "UART0-mode1", "UART0-mode0", + "UART0-enable", "UART0-terminate", "", "WIFI-disable", + /* 10..19 */ + "", "", "", "", "", "", "", "", "", "", + /* 20..29 */ + "", "A4A5-I2C-mux", "", "", "", "USER-button", "", "", "","IO0", + /* 30..39 */ + "IO1", "IO2", "", "IO3", "IO17-direction", "A5", + "IO16-direction", "IO15-direction", "IO14-direction", "A3", + /* 40..49 */ + "", "IO18-direction", "A4", "A2", "A1", "A0", "", "", "IO13", + "IO11", + /* 50..51 */ + "IO12", "IO10"; +}; + +&wkup_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + clock-frequency = <400000>; +}; + +&mcu_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_i2c0_pins_default>; + clock-frequency = <400000>; + + psu: regulator@60 { + compatible = "ti,tps62363"; + reg = <0x60>; + regulator-name = "tps62363-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + ti,vsel0-state-high; + ti,vsel1-state-high; + ti,enable-vout-discharge; + }; + + /* D4200 */ + pcal9535_1: gpio@20 { + compatible = "nxp,pcal9535"; + reg = <0x20>; + #gpio-cells = <2>; + gpio-controller; + gpio-line-names = + "A0-pull", "A1-pull", "A2-pull", "A3-pull", "A4-pull", + "A5-pull", "", "", + "IO14-enable", "IO15-enable", "IO16-enable", + "IO17-enable", "IO18-enable", "IO19-enable"; + }; + + /* D4201 */ + pcal9535_2: gpio@21 { + compatible = "nxp,pcal9535"; + reg = <0x21>; + #gpio-cells = <2>; + gpio-controller; + gpio-line-names = + "IO0-direction", "IO1-direction", "IO2-direction", + "IO3-direction", "IO4-direction", "IO5-direction", + "IO6-direction", "IO7-direction", + "IO8-direction", "IO9-direction", "IO10-direction", + "IO11-direction", "IO12-direction", "IO13-direction", + "IO19-direction"; + }; + + /* D4202 */ + pcal9535_3: gpio@25 { + compatible = "nxp,pcal9535"; + reg = <0x25>; + #gpio-cells = <2>; + gpio-controller; + gpio-line-names = + "IO0-pull", "IO1-pull", "IO2-pull", "IO3-pull", + "IO4-pull", "IO5-pull", "IO6-pull", "IO7-pull", + "IO8-pull", "IO9-pull", "IO10-pull", "IO11-pull", + "IO12-pull", "IO13-pull"; + }; +}; + +&main_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; + clock-frequency = <400000>; + + rtc: rtc8564@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + + eeprom: eeprom@54 { + compatible = "atmel,24c08"; + reg = <0x54>; + pagesize = <16>; + }; +}; + +&main_i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <400000>; +}; + +&main_i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; +}; + +&main_i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c3_pins_default>; + clock-frequency = <400000>; + + #address-cells = <1>; + #size-cells = <0>; + + edp-bridge@f { + compatible = "toshiba,tc358767"; + reg = <0x0f>; + pinctrl-names = "default"; + pinctrl-0 = <&dp_pins_default>; + reset-gpios = <&main_gpio0 30 GPIO_ACTIVE_HIGH>; + + clock-names = "ref"; + clocks = <&dp_refclk>; + + toshiba,hpd-pin = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + bridge_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + }; + }; +}; + +&mcu_cpsw { + status = "disabled"; +}; + +&ecap0 { + pinctrl-names = "default"; + pinctrl-0 = <&ecap0_pins_default>; +}; + +&sdhci1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc1_pins_default>; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&usb0 { + pinctrl-names = "default"; + pinctrl-0 = <&usb0_pins_default>; + dr_mode = "host"; +}; + +&usb1 { + pinctrl-names = "default"; + pinctrl-0 = <&usb1_pins_default>; + dr_mode = "host"; +}; + +&mcu_spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_spi0_pins_default>; + + #address-cells = <1>; + #size-cells= <0>; + ti,pindir-d0-out-d1-in = <1>; +}; + +&tscadc0 { + status = "disabled"; +}; + +&tscadc1 { + adc { + ti,adc-channels = <0 1 2 3 4 5>; + }; +}; + +&ospi0 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_fss0_ospi0_pins_default>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + spi-max-frequency = <50000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <2>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout1_pins_default>; + + assigned-clocks = <&k3_clks 67 2>; + assigned-clock-parents = <&k3_clks 67 5>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + port@1 { + reg = <1>; + + dpi_out: endpoint { + remote-endpoint = <&bridge_in>; + }; + }; +}; + +&serdes0 { + status = "disabled"; +}; + +&pcie0_rc { + status = "disabled"; +}; + +&pcie0_ep { + status = "disabled"; +}; + +&pcie1_rc { + pinctrl-names = "default"; + pinctrl-0 = <&minipcie_pins_default>; + + num-lanes = <1>; + phys = <&serdes1 PHY_TYPE_PCIE 0>; + phy-names = "pcie-phy0"; + reset-gpios = <&wkup_gpio0 27 GPIO_ACTIVE_HIGH>; +}; + +&pcie1_ep { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index ceb579fb427db7181724b0c954e6bd2073543ced..cb340d1b401f3c7938eefc72a646a0b162c49396 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -707,6 +707,7 @@ dma-coherent; interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>; msi-map = <0x0 &gic_its 0x0 0x10000>; + device_type = "pci"; }; pcie0_ep: pcie-ep@5500000 { @@ -739,6 +740,7 @@ dma-coherent; interrupts = <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>; msi-map = <0x0 &gic_its 0x10000 0x10000>; + device_type = "pci"; }; pcie1_ep: pcie-ep@5600000 { @@ -919,4 +921,397 @@ clocks = <&ehrpwm_tbclk 5>, <&k3_clks 45 0>; clock-names = "tbclk", "fck"; }; + + icssg0: icssg@b000000 { + compatible = "ti,am654-icssg"; + reg = <0x00 0xb000000 0x00 0x80000>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0xb000000 0x80000>; + + icssg0_mem: memories@0 { + reg = <0x0 0x2000>, + <0x2000 0x2000>, + <0x10000 0x10000>; + reg-names = "dram0", "dram1", + "shrdram2"; + }; + + icssg0_cfg: cfg@26000 { + compatible = "ti,pruss-cfg", "syscon"; + reg = <0x26000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x26000 0x2000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + icssg0_coreclk_mux: coreclk-mux@3c { + reg = <0x3c>; + #clock-cells = <0>; + clocks = <&k3_clks 62 19>, /* icssg0_core_clk */ + <&k3_clks 62 3>; /* icssg0_iclk */ + assigned-clocks = <&icssg0_coreclk_mux>; + assigned-clock-parents = <&k3_clks 62 3>; + }; + + icssg0_iepclk_mux: iepclk-mux@30 { + reg = <0x30>; + #clock-cells = <0>; + clocks = <&k3_clks 62 10>, /* icssg0_iep_clk */ + <&icssg0_coreclk_mux>; /* core_clk */ + assigned-clocks = <&icssg0_iepclk_mux>; + assigned-clock-parents = <&icssg0_coreclk_mux>; + }; + }; + }; + + icssg0_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; + }; + + icssg0_mii_g_rt: mii-g-rt@33000 { + compatible = "ti,pruss-mii-g", "syscon"; + reg = <0x33000 0x1000>; + }; + + icssg0_intc: interrupt-controller@20000 { + compatible = "ti,icssg-intc"; + reg = <0x20000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host_intr0", "host_intr1", + "host_intr2", "host_intr3", + "host_intr4", "host_intr5", + "host_intr6", "host_intr7"; + }; + + pru0_0: pru@34000 { + compatible = "ti,am654-pru"; + reg = <0x34000 0x4000>, + <0x22000 0x100>, + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru0_0-fw"; + }; + + rtu0_0: rtu@4000 { + compatible = "ti,am654-rtu"; + reg = <0x4000 0x2000>, + <0x23000 0x100>, + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu0_0-fw"; + }; + + tx_pru0_0: txpru@a000 { + compatible = "ti,am654-tx-pru"; + reg = <0xa000 0x1800>, + <0x25000 0x100>, + <0x25400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-txpru0_0-fw"; + }; + + pru0_1: pru@38000 { + compatible = "ti,am654-pru"; + reg = <0x38000 0x4000>, + <0x24000 0x100>, + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru0_1-fw"; + }; + + rtu0_1: rtu@6000 { + compatible = "ti,am654-rtu"; + reg = <0x6000 0x2000>, + <0x23800 0x100>, + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu0_1-fw"; + }; + + tx_pru0_1: txpru@c000 { + compatible = "ti,am654-tx-pru"; + reg = <0xc000 0x1800>, + <0x25800 0x100>, + <0x25c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-txpru0_1-fw"; + }; + }; + + icssg1: icssg@b100000 { + compatible = "ti,am654-icssg"; + reg = <0x00 0xb100000 0x00 0x80000>; + power-domains = <&k3_pds 63 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0xb100000 0x80000>; + + icssg1_mem: memories@0 { + reg = <0x0 0x2000>, + <0x2000 0x2000>, + <0x10000 0x10000>; + reg-names = "dram0", "dram1", + "shrdram2"; + }; + + icssg1_cfg: cfg@26000 { + compatible = "ti,pruss-cfg", "syscon"; + reg = <0x26000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x26000 0x2000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + icssg1_coreclk_mux: coreclk-mux@3c { + reg = <0x3c>; + #clock-cells = <0>; + clocks = <&k3_clks 63 19>, /* icssg1_core_clk */ + <&k3_clks 63 3>; /* icssg1_iclk */ + assigned-clocks = <&icssg1_coreclk_mux>; + assigned-clock-parents = <&k3_clks 63 3>; + }; + + icssg1_iepclk_mux: iepclk-mux@30 { + reg = <0x30>; + #clock-cells = <0>; + clocks = <&k3_clks 63 10>, /* icssg1_iep_clk */ + <&icssg1_coreclk_mux>; /* core_clk */ + assigned-clocks = <&icssg1_iepclk_mux>; + assigned-clock-parents = <&icssg1_coreclk_mux>; + }; + }; + }; + + icssg1_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; + }; + + icssg1_mii_g_rt: mii-g-rt@33000 { + compatible = "ti,pruss-mii-g", "syscon"; + reg = <0x33000 0x1000>; + }; + + icssg1_intc: interrupt-controller@20000 { + compatible = "ti,icssg-intc"; + reg = <0x20000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host_intr0", "host_intr1", + "host_intr2", "host_intr3", + "host_intr4", "host_intr5", + "host_intr6", "host_intr7"; + }; + + pru1_0: pru@34000 { + compatible = "ti,am654-pru"; + reg = <0x34000 0x4000>, + <0x22000 0x100>, + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru1_0-fw"; + }; + + rtu1_0: rtu@4000 { + compatible = "ti,am654-rtu"; + reg = <0x4000 0x2000>, + <0x23000 0x100>, + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu1_0-fw"; + }; + + tx_pru1_0: txpru@a000 { + compatible = "ti,am654-tx-pru"; + reg = <0xa000 0x1800>, + <0x25000 0x100>, + <0x25400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-txpru1_0-fw"; + }; + + pru1_1: pru@38000 { + compatible = "ti,am654-pru"; + reg = <0x38000 0x4000>, + <0x24000 0x100>, + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru1_1-fw"; + }; + + rtu1_1: rtu@6000 { + compatible = "ti,am654-rtu"; + reg = <0x6000 0x2000>, + <0x23800 0x100>, + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu1_1-fw"; + }; + + tx_pru1_1: txpru@c000 { + compatible = "ti,am654-tx-pru"; + reg = <0xc000 0x1800>, + <0x25800 0x100>, + <0x25c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-txpru1_1-fw"; + }; + }; + + icssg2: icssg@b200000 { + compatible = "ti,am654-icssg"; + reg = <0x00 0xb200000 0x00 0x80000>; + power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0xb200000 0x80000>; + + icssg2_mem: memories@0 { + reg = <0x0 0x2000>, + <0x2000 0x2000>, + <0x10000 0x10000>; + reg-names = "dram0", "dram1", + "shrdram2"; + }; + + icssg2_cfg: cfg@26000 { + compatible = "ti,pruss-cfg", "syscon"; + reg = <0x26000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x26000 0x2000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + icssg2_coreclk_mux: coreclk-mux@3c { + reg = <0x3c>; + #clock-cells = <0>; + clocks = <&k3_clks 64 19>, /* icssg1_core_clk */ + <&k3_clks 64 3>; /* icssg1_iclk */ + assigned-clocks = <&icssg2_coreclk_mux>; + assigned-clock-parents = <&k3_clks 64 3>; + }; + + icssg2_iepclk_mux: iepclk-mux@30 { + reg = <0x30>; + #clock-cells = <0>; + clocks = <&k3_clks 64 10>, /* icssg1_iep_clk */ + <&icssg2_coreclk_mux>; /* core_clk */ + assigned-clocks = <&icssg2_iepclk_mux>; + assigned-clock-parents = <&icssg2_coreclk_mux>; + }; + }; + }; + + icssg2_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; + }; + + icssg2_mii_g_rt: mii-g-rt@33000 { + compatible = "ti,pruss-mii-g", "syscon"; + reg = <0x33000 0x1000>; + }; + + icssg2_intc: interrupt-controller@20000 { + compatible = "ti,icssg-intc"; + reg = <0x20000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host_intr0", "host_intr1", + "host_intr2", "host_intr3", + "host_intr4", "host_intr5", + "host_intr6", "host_intr7"; + }; + + pru2_0: pru@34000 { + compatible = "ti,am654-pru"; + reg = <0x34000 0x4000>, + <0x22000 0x100>, + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru2_0-fw"; + }; + + rtu2_0: rtu@4000 { + compatible = "ti,am654-rtu"; + reg = <0x4000 0x2000>, + <0x23000 0x100>, + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu2_0-fw"; + }; + + tx_pru2_0: txpru@a000 { + compatible = "ti,am654-tx-pru"; + reg = <0xa000 0x1800>, + <0x25000 0x100>, + <0x25400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-txpru2_0-fw"; + }; + + pru2_1: pru@38000 { + compatible = "ti,am654-pru"; + reg = <0x38000 0x4000>, + <0x24000 0x100>, + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru2_1-fw"; + }; + + rtu2_1: rtu@6000 { + compatible = "ti,am654-rtu"; + reg = <0x6000 0x2000>, + <0x23800 0x100>, + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu2_1-fw"; + }; + + tx_pru2_1: txpru@c000 { + compatible = "ti,am654-tx-pru"; + reg = <0xc000 0x1800>, + <0x25800 0x100>, + <0x25c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-txpru2_1-fw"; + }; + }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi index 7454c8cec0cc584658deb99b719622a14f4520c2..0388c02c22037317e764e6a180a8bc9b64617d52 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi @@ -308,4 +308,13 @@ ti,loczrama = <1>; }; }; + + mcu_rti1: watchdog@40610000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x0 0x40610000 0x0 0x100>; + clocks = <&k3_clks 135 0>; + power-domains = <&k3_pds 135 TI_SCI_PD_SHARED>; + assigned-clocks = <&k3_clks 135 0>; + assigned-clock-parents = <&k3_clks 135 4>; + }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts new file mode 100644 index 0000000000000000000000000000000000000000..4f7e3f2a626551e3f65f5fbdb79011dd1872e919 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Siemens AG, 2018-2021 + * + * Authors: + * Le Jin <le.jin@siemens.com> + * Jan Kiszka <jan.kiszk@siemens.com> + * + * AM6528-based (dual-core) IOT2050 Basic variant + * 1 GB RAM, no eMMC, main_uart0 on connector X30 + */ + +/dts-v1/; + +#include "k3-am65-iot2050-common.dtsi" + +/ { + compatible = "siemens,iot2050-basic", "ti,am654"; + model = "SIMATIC IOT2050 Basic"; + + memory@80000000 { + device_type = "memory"; + /* 1G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x40000000>; + }; + + cpus { + cpu-map { + /delete-node/ cluster1; + }; + /delete-node/ cpu@100; + /delete-node/ cpu@101; + }; + + /delete-node/ l2-cache1; +}; + +/* eMMC */ +&sdhci0 { + status = "disabled"; +}; + +&main_pmx0 { + main_uart0_pins_default: main-uart0-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01e4, PIN_INPUT, 0) /* (AF11) UART0_RXD */ + AM65X_IOPAD(0x01e8, PIN_OUTPUT, 0) /* (AE11) UART0_TXD */ + AM65X_IOPAD(0x01ec, PIN_INPUT, 0) /* (AG11) UART0_CTSn */ + AM65X_IOPAD(0x01f0, PIN_OUTPUT, 0) /* (AD11) UART0_RTSn */ + AM65X_IOPAD(0x0188, PIN_INPUT, 1) /* (D25) UART0_DCDn */ + AM65X_IOPAD(0x018c, PIN_INPUT, 1) /* (B26) UART0_DSRn */ + AM65X_IOPAD(0x0190, PIN_OUTPUT, 1) /* (A24) UART0_DTRn */ + AM65X_IOPAD(0x0194, PIN_INPUT, 1) /* (E24) UART0_RIN */ + >; + }; +}; + +&main_uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart0_pins_default>; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts index fe304394390619316c6c307eb07601f7d1f0ed71..9e87fb313a541c5d25b40539494de6f6dec02b13 100644 --- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts @@ -483,9 +483,9 @@ flash@0{ compatible = "jedec,spi-nor"; reg = <0x0>; - spi-tx-bus-width = <1>; + spi-tx-bus-width = <8>; spi-rx-bus-width = <8>; - spi-max-frequency = <40000000>; + spi-max-frequency = <25000000>; cdns,tshsl-ns = <60>; cdns,tsd2d-ns = <60>; cdns,tchsh-ns = <60>; diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced.dts new file mode 100644 index 0000000000000000000000000000000000000000..ec9617c13cdb6085407a1167f4510ee118357a4a --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced.dts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Siemens AG, 2018-2021 + * + * Authors: + * Le Jin <le.jin@siemens.com> + * Jan Kiszka <jan.kiszk@siemens.com> + * + * AM6548-based (quad-core) IOT2050 Advanced variant + * 2 GB RAM, 16 GB eMMC, USB-serial converter on connector X30 + */ + +/dts-v1/; + +#include "k3-am65-iot2050-common.dtsi" + +/ { + compatible = "siemens,iot2050-advanced", "ti,am654"; + model = "SIMATIC IOT2050 Advanced"; + + memory@80000000 { + device_type = "memory"; + /* 2G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>; + }; +}; + +&main_pmx0 { + main_mmc0_pins_default: main-mmc0-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */ + AM65X_IOPAD(0x01ac, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */ + AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */ + AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */ + AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */ + AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */ + AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */ + AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */ + AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */ + AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */ + AM65X_IOPAD(0x01b8, PIN_OUTPUT_PULLUP, 7) /* (B23) MMC0_SDWP */ + AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */ + AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */ + >; + }; +}; + +/* eMMC */ +&sdhci0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc0_pins_default>; + bus-width = <8>; + non-removable; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&main_uart0 { + status = "disabled"; +}; 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 4a7182abccf5d050eb1efd8d916c036c529173eb..bedd01b7a32cea39d513031dded83c0b837139f8 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 @@ -16,6 +16,65 @@ stdout-path = "serial2:115200n8"; bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000"; }; + + evm_12v0: fixedregulator-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: fixedregulator-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: fixedregulator-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: fixedregulator-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: gpio-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 55 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; + }; }; &wkup_pmx0 { @@ -45,6 +104,13 @@ }; &main_pmx0 { + main_i2c0_pins_default: main-i2c0-pins-default { + pinctrl-single,pins = < + J721E_IOPAD(0xd4, PIN_INPUT_PULLUP, 0) /* (V3) I2C0_SCL */ + J721E_IOPAD(0xd8, PIN_INPUT_PULLUP, 0) /* (W2) I2C0_SDA */ + >; + }; + main_i2c1_pins_default: main-i2c1-pins-default { pinctrl-single,pins = < J721E_IOPAD(0xdc, PIN_INPUT_PULLUP, 3) /* (U3) ECAP0_IN_APWM_OUT.I2C1_SCL */ @@ -70,6 +136,12 @@ J721E_IOPAD(0x120, PIN_OUTPUT, 0) /* (T4) USB0_DRVVBUS */ >; }; + + vdd_sd_dv_pins_default: vdd-sd-dv-pins-default { + pinctrl-single,pins = < + J721E_IOPAD(0xd0, PIN_OUTPUT, 7) /* (T5) SPI0_D1.GPIO0_55 */ + >; + }; }; &wkup_uart0 { @@ -122,6 +194,22 @@ status = "disabled"; }; +&main_gpio2 { + status = "disabled"; +}; + +&main_gpio4 { + status = "disabled"; +}; + +&main_gpio6 { + status = "disabled"; +}; + +&wkup_gpio1 { + status = "disabled"; +}; + &mcu_cpsw { pinctrl-names = "default"; pinctrl-0 = <&mcu_cpsw_pins_default &mcu_mdio_pins_default>; @@ -141,6 +229,10 @@ }; &main_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; + clock-frequency = <400000>; + exp1: gpio@20 { compatible = "ti,tca6416"; reg = <0x20>; @@ -190,6 +282,8 @@ /* SD card */ pinctrl-0 = <&main_mmc1_pins_default>; pinctrl-names = "default"; + vmmc-supply = <&vdd_mmc1>; + vqmmc-supply = <&vdd_sd_dv>; ti,driver-strength-ohm = <50>; disable-wp; }; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi index 17477ab0fd8e147753f9a2a68001ccae2f872d2d..f86c493a44f1cfa9f3f0b2e211b169943b818020 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -512,11 +512,16 @@ ti,otap-del-sel-mmc-hs = <0x0>; ti,otap-del-sel-ddr52 = <0x6>; ti,otap-del-sel-hs200 = <0x8>; - ti,otap-del-sel-hs400 = <0x0>; + 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>; bus-width = <8>; mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; dma-coherent; }; @@ -534,7 +539,12 @@ ti,otap-del-sel-sdr50 = <0xc>; ti,otap-del-sel-sdr104 = <0x5>; ti,otap-del-sel-ddr50 = <0xc>; - no-1-8-v; + 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,clkbuf-sel = <0x7>; + ti,trm-icp = <0x8>; dma-coherent; }; @@ -672,6 +682,78 @@ }; }; + 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>; + #address-cells = <0>; + ti,ngpio = <69>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 105 0>; + clock-names = "gpio"; + }; + + 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>; + #address-cells = <0>; + ti,ngpio = <69>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 107 0>; + clock-names = "gpio"; + }; + + 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>; + #address-cells = <0>; + ti,ngpio = <69>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 109 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 109 0>; + clock-names = "gpio"; + }; + + 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>; + #address-cells = <0>; + ti,ngpio = <69>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 111 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 111 0>; + clock-names = "gpio"; + }; + main_r5fss0: r5fss@5c00000 { compatible = "ti,j7200-r5fss"; ti,cluster-mode = <1>; 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 359e3e8a8cd0066e5f325a87e539b90df7a1fc2b..5e74e43822c3f6ad250a2a2c960b81445ad7d04d 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi @@ -107,6 +107,40 @@ ti,interrupt-ranges = <16 960 16>; }; + 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>; + #address-cells = <0>; + ti,ngpio = <85>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 113 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 113 0>; + clock-names = "gpio"; + }; + + 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>; + #address-cells = <0>; + ti,ngpio = <85>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 114 0>; + clock-names = "gpio"; + }; + mcu_navss: bus@28380000 { compatible = "simple-mfd"; #address-cells = <2>; @@ -269,6 +303,23 @@ #size-cells = <1>; mux-controls = <&hbmc_mux 0>; }; + + ospi0: spi@47040000 { + compatible = "ti,am654-ospi", "cdns,qspi-nor"; + reg = <0x0 0x47040000 0x0 0x100>, + <0x5 0x00000000 0x1 0x0000000>; + interrupts = <GIC_SPI 840 IRQ_TYPE_LEVEL_HIGH>; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x0>; + clocks = <&k3_clks 103 0>; + assigned-clocks = <&k3_clks 103 0>; + assigned-clock-parents = <&k3_clks 103 2>; + assigned-clock-rates = <166666666>; + power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <0>; + }; }; tscadc0: tscadc@40200000 { 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 a988e2ab2ba1614b873339d52cf06064b6dbcc35..34724440171a6c90ef3d5554d0ee0ba8f9d5a6ce 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi @@ -100,6 +100,22 @@ J721E_WKUP_IOPAD(0x28, PIN_INPUT, 1) /* (A7) MCU_OSPI0_D7.MCU_HYPERBUS0_DQ7 */ >; }; + + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-pins-default { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) /* MCU_OSPI0_CLK */ + J721E_WKUP_IOPAD(0x002c, PIN_OUTPUT, 0) /* MCU_OSPI0_CSn0 */ + J721E_WKUP_IOPAD(0x000c, PIN_INPUT, 0) /* MCU_OSPI0_D0 */ + J721E_WKUP_IOPAD(0x0010, PIN_INPUT, 0) /* MCU_OSPI0_D1 */ + J721E_WKUP_IOPAD(0x0014, PIN_INPUT, 0) /* MCU_OSPI0_D2 */ + J721E_WKUP_IOPAD(0x0018, PIN_INPUT, 0) /* MCU_OSPI0_D3 */ + J721E_WKUP_IOPAD(0x001c, PIN_INPUT, 0) /* MCU_OSPI0_D4 */ + J721E_WKUP_IOPAD(0x0020, PIN_INPUT, 0) /* MCU_OSPI0_D5 */ + 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 */ + >; + }; }; &main_pmx0 { @@ -235,3 +251,23 @@ "GPIO_LIN_EN", "CAN_STB"; }; }; + +&ospi0 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_fss0_ospi0_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>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 8c84dafb7125c8aedaebe51704a52134657795cb..c2aa45a3ac795b57d842f0641cdc771fb81e94fc 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -1042,13 +1042,16 @@ assigned-clocks = <&k3_clks 91 1>; assigned-clock-parents = <&k3_clks 91 2>; bus-width = <8>; - mmc-hs400-1_8v; + mmc-hs200-1_8v; mmc-ddr-1_8v; ti,otap-del-sel-legacy = <0xf>; ti,otap-del-sel-mmc-hs = <0xf>; ti,otap-del-sel-ddr52 = <0x5>; ti,otap-del-sel-hs200 = <0x6>; ti,otap-del-sel-hs400 = <0x0>; + ti,itap-del-sel-legacy = <0x10>; + ti,itap-del-sel-mmc-hs = <0xa>; + ti,itap-del-sel-ddr52 = <0x3>; ti,trm-icp = <0x8>; ti,strobe-sel = <0x77>; dma-coherent; @@ -1069,9 +1072,15 @@ ti,otap-del-sel-sdr25 = <0xf>; ti,otap-del-sel-sdr50 = <0xc>; 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,trm-icp = <0x8>; ti,clkbuf-sel = <0x7>; dma-coherent; + sdhci-caps-mask = <0x2 0x0>; }; main_sdhci2: mmc@4f98000 { @@ -1089,9 +1098,15 @@ ti,otap-del-sel-sdr25 = <0xf>; ti,otap-del-sel-sdr50 = <0xc>; 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,trm-icp = <0x8>; ti,clkbuf-sel = <0x7>; dma-coherent; + sdhci-caps-mask = <0x2 0x0>; }; usbss0: cdns-usb@4104000 { @@ -1647,4 +1662,266 @@ resets = <&k3_reset 15 1>; firmware-name = "j7-c71_0-fw"; }; + + icssg0: icssg@b000000 { + compatible = "ti,j721e-icssg"; + reg = <0x00 0xb000000 0x00 0x80000>; + power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x0b000000 0x100000>; + + icssg0_mem: memories@0 { + reg = <0x0 0x2000>, + <0x2000 0x2000>, + <0x10000 0x10000>; + reg-names = "dram0", "dram1", + "shrdram2"; + }; + + icssg0_cfg: cfg@26000 { + compatible = "ti,pruss-cfg", "syscon"; + reg = <0x26000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x26000 0x2000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + icssg0_coreclk_mux: coreclk-mux@3c { + reg = <0x3c>; + #clock-cells = <0>; + clocks = <&k3_clks 119 24>, /* icssg0_core_clk */ + <&k3_clks 119 1>; /* icssg0_iclk */ + assigned-clocks = <&icssg0_coreclk_mux>; + assigned-clock-parents = <&k3_clks 119 1>; + }; + + icssg0_iepclk_mux: iepclk-mux@30 { + reg = <0x30>; + #clock-cells = <0>; + clocks = <&k3_clks 119 3>, /* icssg0_iep_clk */ + <&icssg0_coreclk_mux>; /* core_clk */ + assigned-clocks = <&icssg0_iepclk_mux>; + assigned-clock-parents = <&icssg0_coreclk_mux>; + }; + }; + }; + + icssg0_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; + }; + + icssg0_mii_g_rt: mii-g-rt@33000 { + compatible = "ti,pruss-mii-g", "syscon"; + reg = <0x33000 0x1000>; + }; + + icssg0_intc: interrupt-controller@20000 { + compatible = "ti,icssg-intc"; + reg = <0x20000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host_intr0", "host_intr1", + "host_intr2", "host_intr3", + "host_intr4", "host_intr5", + "host_intr6", "host_intr7"; + }; + + pru0_0: pru@34000 { + compatible = "ti,j721e-pru"; + reg = <0x34000 0x3000>, + <0x22000 0x100>, + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-pru0_0-fw"; + }; + + rtu0_0: rtu@4000 { + compatible = "ti,j721e-rtu"; + reg = <0x4000 0x2000>, + <0x23000 0x100>, + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-rtu0_0-fw"; + }; + + tx_pru0_0: txpru@a000 { + compatible = "ti,j721e-tx-pru"; + reg = <0xa000 0x1800>, + <0x25000 0x100>, + <0x25400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-txpru0_0-fw"; + }; + + pru0_1: pru@38000 { + compatible = "ti,j721e-pru"; + reg = <0x38000 0x3000>, + <0x24000 0x100>, + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-pru0_1-fw"; + }; + + rtu0_1: rtu@6000 { + compatible = "ti,j721e-rtu"; + reg = <0x6000 0x2000>, + <0x23800 0x100>, + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-rtu0_1-fw"; + }; + + tx_pru0_1: txpru@c000 { + compatible = "ti,j721e-tx-pru"; + reg = <0xc000 0x1800>, + <0x25800 0x100>, + <0x25c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-txpru0_1-fw"; + }; + }; + + icssg1: icssg@b100000 { + compatible = "ti,j721e-icssg"; + reg = <0x00 0xb100000 0x00 0x80000>; + power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x0b100000 0x100000>; + + icssg1_mem: memories@b100000 { + reg = <0x0 0x2000>, + <0x2000 0x2000>, + <0x10000 0x10000>; + reg-names = "dram0", "dram1", + "shrdram2"; + }; + + icssg1_cfg: cfg@26000 { + compatible = "ti,pruss-cfg", "syscon"; + reg = <0x26000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x26000 0x2000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + icssg1_coreclk_mux: coreclk-mux@3c { + reg = <0x3c>; + #clock-cells = <0>; + clocks = <&k3_clks 120 54>, /* icssg1_core_clk */ + <&k3_clks 120 4>; /* icssg1_iclk */ + assigned-clocks = <&icssg1_coreclk_mux>; + assigned-clock-parents = <&k3_clks 120 4>; + }; + + icssg1_iepclk_mux: iepclk-mux@30 { + reg = <0x30>; + #clock-cells = <0>; + clocks = <&k3_clks 120 9>, /* icssg1_iep_clk */ + <&icssg1_coreclk_mux>; /* core_clk */ + assigned-clocks = <&icssg1_iepclk_mux>; + assigned-clock-parents = <&icssg1_coreclk_mux>; + }; + }; + }; + + icssg1_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; + }; + + icssg1_mii_g_rt: mii-g-rt@33000 { + compatible = "ti,pruss-mii-g", "syscon"; + reg = <0x33000 0x1000>; + }; + + icssg1_intc: interrupt-controller@20000 { + compatible = "ti,icssg-intc"; + reg = <0x20000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host_intr0", "host_intr1", + "host_intr2", "host_intr3", + "host_intr4", "host_intr5", + "host_intr6", "host_intr7"; + }; + + pru1_0: pru@34000 { + compatible = "ti,j721e-pru"; + reg = <0x34000 0x4000>, + <0x22000 0x100>, + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-pru1_0-fw"; + }; + + rtu1_0: rtu@4000 { + compatible = "ti,j721e-rtu"; + reg = <0x4000 0x2000>, + <0x23000 0x100>, + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-rtu1_0-fw"; + }; + + tx_pru1_0: txpru@a000 { + compatible = "ti,j721e-tx-pru"; + reg = <0xa000 0x1800>, + <0x25000 0x100>, + <0x25400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-txpru1_0-fw"; + }; + + pru1_1: pru@38000 { + compatible = "ti,j721e-pru"; + reg = <0x38000 0x4000>, + <0x24000 0x100>, + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-pru1_1-fw"; + }; + + rtu1_1: rtu@6000 { + compatible = "ti,j721e-rtu"; + reg = <0x6000 0x2000>, + <0x23800 0x100>, + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-rtu1_1-fw"; + }; + + tx_pru1_1: txpru@c000 { + compatible = "ti,j721e-tx-pru"; + reg = <0xc000 0x1800>, + <0x25800 0x100>, + <0x25c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "j7-txpru1_1-fw"; + }; + }; }; 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 6c44afae9187e9f2919c984cbf03c99e7565be01..d56e3475aee79e59396f1ed767470de43e9cbbcc 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi @@ -180,7 +180,7 @@ ranges; ospi0: spi@47040000 { - compatible = "ti,am654-ospi"; + compatible = "ti,am654-ospi", "cdns,qspi-nor"; reg = <0x0 0x47040000 0x0 0x100>, <0x5 0x00000000 0x1 0x0000000>; interrupts = <GIC_SPI 840 IRQ_TYPE_LEVEL_HIGH>; @@ -197,7 +197,7 @@ }; ospi1: spi@47050000 { - compatible = "ti,am654-ospi"; + compatible = "ti,am654-ospi", "cdns,qspi-nor"; reg = <0x0 0x47050000 0x0 0x100>, <0x7 0x00000000 0x1 0x00000000>; interrupts = <GIC_SPI 841 IRQ_TYPE_LEVEL_HIGH>; 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 57720e6a04c519d77a54dd08c7c3c7d9aaba893b..2fee2906183d10b184f7795fe4332288975577a7 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi @@ -174,9 +174,9 @@ flash@0{ compatible = "jedec,spi-nor"; reg = <0x0>; - spi-tx-bus-width = <1>; + spi-tx-bus-width = <8>; spi-rx-bus-width = <8>; - spi-max-frequency = <40000000>; + spi-max-frequency = <25000000>; cdns,tshsl-ns = <60>; cdns,tsd2d-ns = <60>; cdns,tchsh-ns = <60>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts index 12e8bd48dc8c8029ce226959bebbdd6c1cd78225..eca6c2de84a743c2a88a45a9cd33483994828f8f 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts @@ -580,25 +580,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <4>; - si5328: clock-generator@69 {/* SI5328 - u20 */ - reg = <0x69>; - /* - * Chip has interrupt present connected to PL - * interrupt-parent = <&>; - * interrupts = <>; - */ - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - clocks = <&refhdmi>; - clock-names = "xtal"; - clock-output-names = "si5328"; - - si5328_clk: clk0@0 { - reg = <0>; - clock-frequency = <27000000>; - }; - }; + /* SI5328 - u20 */ }; /* 5 - 7 unconnected */ }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts index 18771e868399ca32e2e94d6b9224c169d8e2b6e3..eff7c64470878c8d87d3104df6d089a674b48120 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts @@ -581,25 +581,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <4>; - si5328: clock-generator@69 {/* SI5328 - u20 */ - reg = <0x69>; - /* - * Chip has interrupt present connected to PL - * interrupt-parent = <&>; - * interrupts = <>; - */ - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - clocks = <&refhdmi>; - clock-names = "xtal"; - clock-output-names = "si5328"; - - si5328_clk: clk0@0 { - reg = <0>; - clock-frequency = <27000000>; - }; - }; + /* SI5328 - u20 */ }; i2c@5 { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a3b391d187872cca0630272d1a59d0cd0b36f84f..28dccb891a5359ec1672b2bd1257ad00f691d21a 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -856,6 +856,7 @@ interrupts = <0 122 4>; interrupt-parent = <&gic>; clock-names = "axi_clk"; + power-domains = <&zynqmp_firmware PD_DP>; #dma-cells = <1>; }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index d612f633b7719e6f79e3c66da4a92331d2c5fdb2..08c6f769df9aeb1f39e04524e05be51ba16f8f99 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -29,8 +29,10 @@ CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y CONFIG_ARCH_ACTIONS=y CONFIG_ARCH_AGILEX=y +CONFIG_ARCH_N5X=y CONFIG_ARCH_SUNXI=y CONFIG_ARCH_ALPINE=y +CONFIG_ARCH_APPLE=y CONFIG_ARCH_BCM2835=y CONFIG_ARCH_BCM4908=y CONFIG_ARCH_BCM_IPROC=y @@ -41,6 +43,7 @@ CONFIG_ARCH_K3=y CONFIG_ARCH_LAYERSCAPE=y CONFIG_ARCH_LG1K=y CONFIG_ARCH_HISI=y +CONFIG_ARCH_KEEMBAY=y CONFIG_ARCH_MEDIATEK=y CONFIG_ARCH_MESON=y CONFIG_ARCH_MVEBU=y @@ -50,7 +53,7 @@ CONFIG_ARCH_RENESAS=y CONFIG_ARCH_ROCKCHIP=y CONFIG_ARCH_S32=y CONFIG_ARCH_SEATTLE=y -CONFIG_ARCH_STRATIX10=y +CONFIG_ARCH_INTEL_SOCFPGA=y CONFIG_ARCH_SYNQUACER=y CONFIG_ARCH_TEGRA=y CONFIG_ARCH_SPRD=y @@ -225,6 +228,7 @@ CONFIG_PCI_HOST_THUNDER_PEM=y CONFIG_PCI_HOST_THUNDER_ECAM=y CONFIG_PCIE_ROCKCHIP_HOST=m CONFIG_PCIE_BRCMSTB=m +CONFIG_PCI_IMX6=y CONFIG_PCI_LAYERSCAPE=y CONFIG_PCIE_LAYERSCAPE_GEN4=y CONFIG_PCI_HISI=y @@ -359,7 +363,7 @@ CONFIG_MESON_GXL_PHY=m CONFIG_MICREL_PHY=y CONFIG_MICROSEMI_PHY=y CONFIG_AT803X_PHY=y -CONFIG_REALTEK_PHY=m +CONFIG_REALTEK_PHY=y CONFIG_ROCKCHIP_PHY=y CONFIG_VITESSE_PHY=y CONFIG_USB_PEGASUS=m @@ -448,6 +452,7 @@ CONFIG_I2C_GPIO=m CONFIG_I2C_IMX=y CONFIG_I2C_IMX_LPI2C=y CONFIG_I2C_MESON=y +CONFIG_I2C_MT65XX=y CONFIG_I2C_MV64XXX=y CONFIG_I2C_OMAP=y CONFIG_I2C_OWL=y @@ -465,6 +470,9 @@ CONFIG_SPI=y CONFIG_SPI_ARMADA_3700=y CONFIG_SPI_BCM2835=m CONFIG_SPI_BCM2835AUX=m +CONFIG_SPI_DESIGNWARE=m +CONFIG_SPI_DW_DMA=y +CONFIG_SPI_DW_MMIO=m CONFIG_SPI_FSL_LPSPI=y CONFIG_SPI_FSL_QUADSPI=y CONFIG_SPI_NXP_FLEXSPI=y @@ -494,6 +502,7 @@ CONFIG_PINCTRL_IMX8MM=y CONFIG_PINCTRL_IMX8MN=y CONFIG_PINCTRL_IMX8MP=y CONFIG_PINCTRL_IMX8MQ=y +CONFIG_PINCTRL_IMX8QM=y CONFIG_PINCTRL_IMX8QXP=y CONFIG_PINCTRL_IMX8DXL=y CONFIG_PINCTRL_MSM=y @@ -510,6 +519,7 @@ CONFIG_PINCTRL_SC7180=y CONFIG_PINCTRL_SDM845=y CONFIG_PINCTRL_SM8150=y CONFIG_PINCTRL_SM8250=y +CONFIG_PINCTRL_SM8350=y CONFIG_PINCTRL_LPASS_LPI=m CONFIG_GPIO_ALTERA=m CONFIG_GPIO_DAVINCI=y @@ -594,6 +604,7 @@ CONFIG_MFD_EXYNOS_LPASS=m CONFIG_MFD_HI6421_PMIC=y CONFIG_MFD_HI655X_PMIC=y CONFIG_MFD_MAX77620=y +CONFIG_MFD_MT6397=y CONFIG_MFD_SPMI_PMIC=y CONFIG_MFD_RK808=y CONFIG_MFD_SEC_CORE=y @@ -611,6 +622,8 @@ CONFIG_REGULATOR_HI655X=y CONFIG_REGULATOR_MAX77620=y CONFIG_REGULATOR_MAX8973=y CONFIG_REGULATOR_MP8859=y +CONFIG_REGULATOR_MT6358=y +CONFIG_REGULATOR_MT6397=y CONFIG_REGULATOR_PCA9450=y CONFIG_REGULATOR_PF8X00=y CONFIG_REGULATOR_PFUZE100=y @@ -682,6 +695,7 @@ CONFIG_DRM_MSM=m CONFIG_DRM_TEGRA=m CONFIG_DRM_PANEL_LVDS=m CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m CONFIG_DRM_PANEL_RAYDIUM_RM67191=m CONFIG_DRM_PANEL_SITRONIX_ST7703=m @@ -689,6 +703,7 @@ CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m CONFIG_DRM_DISPLAY_CONNECTOR=m CONFIG_DRM_NWL_MIPI_DSI=m CONFIG_DRM_LONTIUM_LT9611=m +CONFIG_DRM_PARADE_PS8640=m CONFIG_DRM_SII902X=m CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_THINE_THC63LVD1024=m @@ -703,6 +718,8 @@ CONFIG_DRM_VC4=m CONFIG_DRM_ETNAVIV=m CONFIG_DRM_HISI_HIBMC=m CONFIG_DRM_HISI_KIRIN=m +CONFIG_DRM_MEDIATEK=m +CONFIG_DRM_MEDIATEK_HDMI=m CONFIG_DRM_MXSFB=m CONFIG_DRM_MESON=m CONFIG_DRM_PL111=m @@ -760,9 +777,11 @@ CONFIG_SND_SOC_GTM601=m CONFIG_SND_SOC_PCM3168A_I2C=m CONFIG_SND_SOC_RT5659=m CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m +CONFIG_SND_SOC_SIMPLE_MUX=m CONFIG_SND_SOC_TAS571X=m CONFIG_SND_SOC_WCD934X=m CONFIG_SND_SOC_WM8904=m +CONFIG_SND_SOC_WM8960=m CONFIG_SND_SOC_WM8962=m CONFIG_SND_SOC_WSA881X=m CONFIG_SND_SOC_LPASS_WSA_MACRO=m @@ -787,6 +806,7 @@ CONFIG_USB_RENESAS_USBHS_HCD=m CONFIG_USB_RENESAS_USBHS=m CONFIG_USB_ACM=m CONFIG_USB_STORAGE=y +CONFIG_USB_MTU3=y CONFIG_USB_MUSB_HDRC=y CONFIG_USB_MUSB_SUNXI=y CONFIG_USB_DWC3=y @@ -879,6 +899,7 @@ CONFIG_RTC_DRV_DS3232=y CONFIG_RTC_DRV_PCF2127=m CONFIG_RTC_DRV_EFI=y CONFIG_RTC_DRV_CROS_EC=y +CONFIG_RTC_DRV_FSL_FTM_ALARM=m CONFIG_RTC_DRV_S3C=y CONFIG_RTC_DRV_PL031=y CONFIG_RTC_DRV_SUN6I=y @@ -915,6 +936,9 @@ CONFIG_VIRTIO_MMIO=y CONFIG_XEN_GNTDEV=y CONFIG_XEN_GRANT_DEV_ALLOC=y CONFIG_MFD_CROS_EC_DEV=y +CONFIG_STAGING=y +CONFIG_STAGING_MEDIA=y +CONFIG_VIDEO_HANTRO=m CONFIG_CHROME_PLATFORMS=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y @@ -957,6 +981,7 @@ CONFIG_SDM_VIDEOCC_845=y CONFIG_SDM_DISPCC_845=y CONFIG_SM_GCC_8150=y CONFIG_SM_GCC_8250=y +CONFIG_SM_GCC_8350=y CONFIG_SM_GPUCC_8150=y CONFIG_SM_GPUCC_8250=y CONFIG_SM_DISPCC_8250=y @@ -974,6 +999,7 @@ CONFIG_ROCKCHIP_IOMMU=y CONFIG_TEGRA_IOMMU_SMMU=y CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU_V3=y +CONFIG_MTK_IOMMU=y CONFIG_QCOM_IOMMU=y CONFIG_REMOTEPROC=y CONFIG_QCOM_Q6V5_MSS=m @@ -988,6 +1014,8 @@ CONFIG_OWL_PM_DOMAINS=y CONFIG_RASPBERRYPI_POWER=y CONFIG_FSL_DPAA=y CONFIG_FSL_MC_DPIO=y +CONFIG_FSL_RCPM=y +CONFIG_MTK_PMIC_WRAP=y CONFIG_QCOM_AOSS_QMP=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_GENI_SE=y @@ -1022,6 +1050,8 @@ CONFIG_ARCH_TEGRA_186_SOC=y CONFIG_ARCH_TEGRA_194_SOC=y CONFIG_ARCH_TEGRA_234_SOC=y CONFIG_TI_SCI_PM_DOMAINS=y +CONFIG_ARM_IMX_BUS_DEVFREQ=m +CONFIG_ARM_IMX8M_DDRC_DEVFREQ=m CONFIG_EXTCON_PTN5150=m CONFIG_EXTCON_USB_GPIO=y CONFIG_EXTCON_USBC_CROS_EC=y @@ -1045,6 +1075,8 @@ CONFIG_PWM_BCM2835=m CONFIG_PWM_CROS_EC=m CONFIG_PWM_IMX27=m CONFIG_PWM_MESON=m +CONFIG_PWM_MTK_DISP=m +CONFIG_PWM_MEDIATEK=m CONFIG_PWM_RCAR=m CONFIG_PWM_ROCKCHIP=y CONFIG_PWM_SAMSUNG=y @@ -1064,6 +1096,7 @@ CONFIG_PHY_HI6220_USB=y CONFIG_PHY_HISTB_COMBPHY=y CONFIG_PHY_HISI_INNO_USB2=y CONFIG_PHY_MVEBU_CP110_COMPHY=y +CONFIG_PHY_MTK_TPHY=y CONFIG_PHY_QCOM_QMP=m CONFIG_PHY_QCOM_QUSB2=m CONFIG_PHY_QCOM_USB_HS=y @@ -1088,6 +1121,7 @@ CONFIG_QCOM_L3_PMU=y CONFIG_NVMEM_IMX_OCOTP=y CONFIG_NVMEM_IMX_OCOTP_SCU=y CONFIG_QCOM_QFPROM=y +CONFIG_MTK_EFUSE=y CONFIG_ROCKCHIP_EFUSE=y CONFIG_NVMEM_SUNXI_SID=y CONFIG_UNIPHIER_EFUSE=y @@ -1156,6 +1190,7 @@ CONFIG_CRYPTO_DEV_HISI_TRNG=m CONFIG_CMA_SIZE_MBYTES=32 CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index bbdb54702aa7a45d40fd26b7c2db5e2c98ffbca9..b495de22bb38081e20577798ccb59c0e785d47ac 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -359,6 +359,7 @@ ST5( mov v4.16b, vctr.16b ) ins vctr.d[0], x8 /* apply carry to N counter blocks for N := x12 */ + cbz x12, 2f adr x16, 1f sub x16, x16, x12, lsl #3 br x16 @@ -700,7 +701,7 @@ AES_FUNC_START(aes_mac_update) cbz w5, .Lmacout encrypt_block v0, w2, x1, x7, w8 st1 {v0.16b}, [x4] /* return dg */ - cond_yield .Lmacout, x7 + cond_yield .Lmacout, x7, x8 b .Lmacloop4x .Lmac1x: add w3, w3, #4 diff --git a/arch/arm64/crypto/poly1305-glue.c b/arch/arm64/crypto/poly1305-glue.c index 683de671741a7f0de196a1e9947d6f6a8510c9c0..9c3d86e397bf3a1fd9302c0a3057913f9a6ed9ca 100644 --- a/arch/arm64/crypto/poly1305-glue.c +++ b/arch/arm64/crypto/poly1305-glue.c @@ -25,7 +25,7 @@ asmlinkage void poly1305_emit(void *state, u8 *digest, const u32 *nonce); static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); -void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) +void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) { poly1305_init_arm64(&dctx->h, key); dctx->s[0] = get_unaligned_le32(key + 16); diff --git a/arch/arm64/crypto/sha1-ce-core.S b/arch/arm64/crypto/sha1-ce-core.S index 8c02bbc2684ed7f88428bf3f4b96482a64c202a5..889ca0f8972b3736c044a1f80bdccf5ddc41e4df 100644 --- a/arch/arm64/crypto/sha1-ce-core.S +++ b/arch/arm64/crypto/sha1-ce-core.S @@ -121,7 +121,7 @@ CPU_LE( rev32 v11.16b, v11.16b ) add dgav.4s, dgav.4s, dg0v.4s cbz w2, 2f - cond_yield 3f, x5 + cond_yield 3f, x5, x6 b 0b /* diff --git a/arch/arm64/crypto/sha2-ce-core.S b/arch/arm64/crypto/sha2-ce-core.S index 6cdea7d560593ba90adc0047958823fd8057da7b..491179922f49808f1144a7a313b3eb647067d17e 100644 --- a/arch/arm64/crypto/sha2-ce-core.S +++ b/arch/arm64/crypto/sha2-ce-core.S @@ -129,7 +129,7 @@ CPU_LE( rev32 v19.16b, v19.16b ) /* handled all input blocks? */ cbz w2, 2f - cond_yield 3f, x5 + cond_yield 3f, x5, x6 b 0b /* diff --git a/arch/arm64/crypto/sha3-ce-core.S b/arch/arm64/crypto/sha3-ce-core.S index 6f5208414fe3fdb03c33482a26eda8d0cddc09e4..9c77313f5a60885231e9374b8853a0a3252d3504 100644 --- a/arch/arm64/crypto/sha3-ce-core.S +++ b/arch/arm64/crypto/sha3-ce-core.S @@ -184,11 +184,11 @@ SYM_FUNC_START(sha3_ce_transform) eor v0.16b, v0.16b, v31.16b cbnz w8, 3b - cond_yield 3f, x8 + cond_yield 4f, x8, x9 cbnz w2, 0b /* save state */ -3: st1 { v0.1d- v3.1d}, [x0], #32 +4: st1 { v0.1d- v3.1d}, [x0], #32 st1 { v4.1d- v7.1d}, [x0], #32 st1 { v8.1d-v11.1d}, [x0], #32 st1 {v12.1d-v15.1d}, [x0], #32 diff --git a/arch/arm64/crypto/sha512-ce-core.S b/arch/arm64/crypto/sha512-ce-core.S index d6e7f6c95fa6f26f20471426ca04bc7498178c5b..b6a3a36e15f58cf98c7829bc2ad746349d23a74e 100644 --- a/arch/arm64/crypto/sha512-ce-core.S +++ b/arch/arm64/crypto/sha512-ce-core.S @@ -195,7 +195,7 @@ CPU_LE( rev64 v19.16b, v19.16b ) add v10.2d, v10.2d, v2.2d add v11.2d, v11.2d, v3.2d - cond_yield 3f, x4 + cond_yield 3f, x4, x5 /* handled all input blocks? */ cbnz w2, 0b diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 880b9054d75c9b1e92432cc680d7d111801dc70e..934b9be582d21deb1f7d7d98d036918642e80180 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -173,7 +173,7 @@ static inline void gic_pmr_mask_irqs(void) static inline void gic_arch_enable_irqs(void) { - asm volatile ("msr daifclr, #2" : : : "memory"); + asm volatile ("msr daifclr, #3" : : : "memory"); } #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index 9f0ec21d6327f49b8e06549ebfb2e218733a4638..88d20f04c64a5863c8d4c04c46a7790751cfaf95 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -165,25 +165,6 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl) isb(); } -/* - * Ensure that reads of the counter are treated the same as memory reads - * for the purposes of ordering by subsequent memory barriers. - * - * This insanity brought to you by speculative system register reads, - * out-of-order memory accesses, sequence locks and Thomas Gleixner. - * - * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html - */ -#define arch_counter_enforce_ordering(val) do { \ - u64 tmp, _val = (val); \ - \ - asm volatile( \ - " eor %0, %1, %1\n" \ - " add %0, sp, %0\n" \ - " ldr xzr, [%0]" \ - : "=r" (tmp) : "r" (_val)); \ -} while (0) - static __always_inline u64 __arch_counter_get_cntpct_stable(void) { u64 cnt; @@ -224,8 +205,6 @@ static __always_inline u64 __arch_counter_get_cntvct(void) return cnt; } -#undef arch_counter_enforce_ordering - static inline int arch_timer_arch_init(void) { return 0; diff --git a/arch/arm64/include/asm/asm_pointer_auth.h b/arch/arm64/include/asm/asm_pointer_auth.h index 52dead2a8640d2ef4acf30a0059e2d2c3413e906..8ca2dc0661ee298a503d6f794ec8bfff95932da2 100644 --- a/arch/arm64/include/asm/asm_pointer_auth.h +++ b/arch/arm64/include/asm/asm_pointer_auth.h @@ -13,30 +13,12 @@ * so use the base value of ldp as thread.keys_user and offset as * thread.keys_user.ap*. */ - .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3 + .macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3 mov \tmp1, #THREAD_KEYS_USER add \tmp1, \tsk, \tmp1 -alternative_if_not ARM64_HAS_ADDRESS_AUTH - b .Laddr_auth_skip_\@ -alternative_else_nop_endif ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA] msr_s SYS_APIAKEYLO_EL1, \tmp2 msr_s SYS_APIAKEYHI_EL1, \tmp3 - ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIB] - msr_s SYS_APIBKEYLO_EL1, \tmp2 - msr_s SYS_APIBKEYHI_EL1, \tmp3 - ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDA] - msr_s SYS_APDAKEYLO_EL1, \tmp2 - msr_s SYS_APDAKEYHI_EL1, \tmp3 - ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDB] - msr_s SYS_APDBKEYLO_EL1, \tmp2 - msr_s SYS_APDBKEYHI_EL1, \tmp3 -.Laddr_auth_skip_\@: -alternative_if ARM64_HAS_GENERIC_AUTH - ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APGA] - msr_s SYS_APGAKEYLO_EL1, \tmp2 - msr_s SYS_APGAKEYHI_EL1, \tmp3 -alternative_else_nop_endif .endm .macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3 diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index ca31594d3d6c36cb61809fc016fcff747d7526ec..ab569b0b45fc17381cbeda7f5e16f69e57051f09 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -15,6 +15,7 @@ #include <asm-generic/export.h> #include <asm/asm-offsets.h> +#include <asm/alternative.h> #include <asm/cpufeature.h> #include <asm/cputype.h> #include <asm/debug-monitors.h> @@ -23,6 +24,14 @@ #include <asm/ptrace.h> #include <asm/thread_info.h> + /* + * Provide a wxN alias for each wN register so what we can paste a xN + * reference after a 'w' to obtain the 32-bit version. + */ + .irp n,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 + wx\n .req w\n + .endr + .macro save_and_disable_daif, flags mrs \flags, daif msr daifset, #0xf @@ -40,9 +49,9 @@ msr daif, \flags .endm - /* IRQ is the lowest priority flag, unconditionally unmask the rest. */ - .macro enable_da_f - msr daifclr, #(8 | 4 | 1) + /* IRQ/FIQ are the lowest priority flags, unconditionally unmask the rest. */ + .macro enable_da + msr daifclr, #(8 | 4) .endm /* @@ -50,7 +59,7 @@ */ .macro save_and_disable_irq, flags mrs \flags, daif - msr daifset, #2 + msr daifset, #3 .endm .macro restore_irq, flags @@ -692,90 +701,33 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU isb .endm -/* - * Check whether to yield to another runnable task from kernel mode NEON code - * (which runs with preemption disabled). - * - * if_will_cond_yield_neon - * // pre-yield patchup code - * do_cond_yield_neon - * // post-yield patchup code - * endif_yield_neon <label> - * - * where <label> is optional, and marks the point where execution will resume - * after a yield has been performed. If omitted, execution resumes right after - * the endif_yield_neon invocation. Note that the entire sequence, including - * the provided patchup code, will be omitted from the image if - * CONFIG_PREEMPTION is not defined. - * - * As a convenience, in the case where no patchup code is required, the above - * sequence may be abbreviated to - * - * cond_yield_neon <label> - * - * Note that the patchup code does not support assembler directives that change - * the output section, any use of such directives is undefined. - * - * The yield itself consists of the following: - * - Check whether the preempt count is exactly 1 and a reschedule is also - * needed. If so, calling of preempt_enable() in kernel_neon_end() will - * trigger a reschedule. If it is not the case, yielding is pointless. - * - Disable and re-enable kernel mode NEON, and branch to the yield fixup - * code. - * - * This macro sequence may clobber all CPU state that is not guaranteed by the - * AAPCS to be preserved across an ordinary function call. - */ - - .macro cond_yield_neon, lbl - if_will_cond_yield_neon - do_cond_yield_neon - endif_yield_neon \lbl - .endm - - .macro if_will_cond_yield_neon -#ifdef CONFIG_PREEMPTION - get_current_task x0 - ldr x0, [x0, #TSK_TI_PREEMPT] - sub x0, x0, #PREEMPT_DISABLE_OFFSET - cbz x0, .Lyield_\@ - /* fall through to endif_yield_neon */ - .subsection 1 -.Lyield_\@ : -#else - .section ".discard.cond_yield_neon", "ax" -#endif - .endm - - .macro do_cond_yield_neon - bl kernel_neon_end - bl kernel_neon_begin - .endm - - .macro endif_yield_neon, lbl - .ifnb \lbl - b \lbl - .else - b .Lyield_out_\@ - .endif - .previous -.Lyield_out_\@ : - .endm - /* - * Check whether preempt-disabled code should yield as soon as it - * is able. This is the case if re-enabling preemption a single - * time results in a preempt count of zero, and the TIF_NEED_RESCHED - * flag is set. (Note that the latter is stored negated in the - * top word of the thread_info::preempt_count field) + * Check whether preempt/bh-disabled asm code should yield as soon as + * it is able. This is the case if we are currently running in task + * context, and either a softirq is pending, or the TIF_NEED_RESCHED + * flag is set and re-enabling preemption a single time would result in + * a preempt count of zero. (Note that the TIF_NEED_RESCHED flag is + * stored negated in the top word of the thread_info::preempt_count + * field) */ - .macro cond_yield, lbl:req, tmp:req -#ifdef CONFIG_PREEMPTION + .macro cond_yield, lbl:req, tmp:req, tmp2:req get_current_task \tmp ldr \tmp, [\tmp, #TSK_TI_PREEMPT] + /* + * If we are serving a softirq, there is no point in yielding: the + * softirq will not be preempted no matter what we do, so we should + * run to completion as quickly as we can. + */ + tbnz \tmp, #SOFTIRQ_SHIFT, .Lnoyield_\@ +#ifdef CONFIG_PREEMPTION sub \tmp, \tmp, #PREEMPT_DISABLE_OFFSET cbz \tmp, \lbl #endif + adr_l \tmp, irq_stat + IRQ_CPUSTAT_SOFTIRQ_PENDING + this_cpu_offset \tmp2 + ldr w\tmp, [\tmp, \tmp2] + cbnz w\tmp, \lbl // yield on pending softirq in task context +.Lnoyield_\@: .endm /* diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index c3009b0e52393bfe49f770dae6ee749bca00669c..065ba482daf063c87fdde854ad26c4eabb24ccda 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -25,10 +25,6 @@ #define psb_csync() asm volatile("hint #17" : : : "memory") #define csdb() asm volatile("hint #20" : : : "memory") -#define spec_bar() asm volatile(ALTERNATIVE("dsb nsh\nisb\n", \ - SB_BARRIER_INSN"nop\n", \ - ARM64_HAS_SB)) - #ifdef CONFIG_ARM64_PSEUDO_NMI #define pmr_sync() \ do { \ @@ -70,6 +66,25 @@ static inline unsigned long array_index_mask_nospec(unsigned long idx, return mask; } +/* + * Ensure that reads of the counter are treated the same as memory reads + * for the purposes of ordering by subsequent memory barriers. + * + * This insanity brought to you by speculative system register reads, + * out-of-order memory accesses, sequence locks and Thomas Gleixner. + * + * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html + */ +#define arch_counter_enforce_ordering(val) do { \ + u64 tmp, _val = (val); \ + \ + asm volatile( \ + " eor %0, %1, %1\n" \ + " add %0, sp, %0\n" \ + " ldr xzr, [%0]" \ + : "=r" (tmp) : "r" (_val)); \ +} while (0) + #define __smp_mb() dmb(ish) #define __smp_rmb() dmb(ishld) #define __smp_wmb() dmb(ishst) diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index c40f2490cd7b7ddca4e814681e6a87a63a3813a0..b0c5eda0498f2ab64df582f46bfcbb868410fbd4 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -67,7 +67,8 @@ #define ARM64_HAS_LDAPR 59 #define ARM64_KVM_PROTECTED_MODE 60 #define ARM64_WORKAROUND_NVIDIA_CARMEL_CNP 61 +#define ARM64_HAS_EPAN 62 -#define ARM64_NCAPS 62 +#define ARM64_NCAPS 63 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 61177bac49fa7fe7831c381598708a3946a868fe..338840c00e8ed72f339aa8fd513c2b2729ce14d7 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -63,6 +63,23 @@ struct arm64_ftr_bits { s64 safe_val; /* safe value for FTR_EXACT features */ }; +/* + * Describe the early feature override to the core override code: + * + * @val Values that are to be merged into the final + * sanitised value of the register. Only the bitfields + * set to 1 in @mask are valid + * @mask Mask of the features that are overridden by @val + * + * A @mask field set to full-1 indicates that the corresponding field + * in @val is a valid override. + * + * A @mask field set to full-0 with the corresponding @val field set + * to full-0 denotes that this field has no override + * + * A @mask field set to full-0 with the corresponding @val field set + * to full-1 denotes thath this field has an invalid override. + */ struct arm64_ftr_override { u64 val; u64 mask; diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index ef5b040dee44dff5bd9fd0011e56fa792833f4d9..6231e1f0abe7e3c288512f3bf7fbb2c0cb479b41 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -59,6 +59,7 @@ #define ARM_CPU_IMP_NVIDIA 0x4E #define ARM_CPU_IMP_FUJITSU 0x46 #define ARM_CPU_IMP_HISI 0x48 +#define ARM_CPU_IMP_APPLE 0x61 #define ARM_CPU_PART_AEM_V8 0xD0F #define ARM_CPU_PART_FOUNDATION 0xD00 @@ -99,6 +100,9 @@ #define HISI_CPU_PART_TSV110 0xD01 +#define APPLE_CPU_PART_M1_ICESTORM 0x022 +#define APPLE_CPU_PART_M1_FIRESTORM 0x023 + #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) @@ -127,6 +131,8 @@ #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX) #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110) +#define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) +#define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */ #define MIDR_FUJITSU_ERRATUM_010001 MIDR_FUJITSU_A64FX diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h index 1c26d7baa67f8d1e12a009bd0e22230f511abeea..5eb7af9c455792a55c8c93a70ac8a8b861e288d8 100644 --- a/arch/arm64/include/asm/daifflags.h +++ b/arch/arm64/include/asm/daifflags.h @@ -13,8 +13,8 @@ #include <asm/ptrace.h> #define DAIF_PROCCTX 0 -#define DAIF_PROCCTX_NOIRQ PSR_I_BIT -#define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) +#define DAIF_PROCCTX_NOIRQ (PSR_I_BIT | PSR_F_BIT) +#define DAIF_ERRCTX (PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) #define DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) @@ -47,7 +47,7 @@ static inline unsigned long local_daif_save_flags(void) if (system_uses_irq_prio_masking()) { /* If IRQs are masked with PMR, reflect it in the flags */ if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON) - flags |= PSR_I_BIT; + flags |= PSR_I_BIT | PSR_F_BIT; } return flags; @@ -69,7 +69,7 @@ static inline void local_daif_restore(unsigned long flags) bool irq_disabled = flags & PSR_I_BIT; WARN_ON(system_has_prio_mask_debugging() && - !(read_sysreg(daif) & PSR_I_BIT)); + (read_sysreg(daif) & (PSR_I_BIT | PSR_F_BIT)) != (PSR_I_BIT | PSR_F_BIT)); if (!irq_disabled) { trace_hardirqs_on(); @@ -86,7 +86,7 @@ static inline void local_daif_restore(unsigned long flags) * If interrupts are disabled but we can take * asynchronous errors, we can take NMIs */ - flags &= ~PSR_I_BIT; + flags &= ~(PSR_I_BIT | PSR_F_BIT); pmr = GIC_PRIO_IRQOFF; } else { pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET; diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index d77d358f9395ccf714543a8a4b27ac8cc844bdbf..b3f2d3bb0938cd94c69ba6379200f9a0f6d8f589 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -131,6 +131,26 @@ .Lskip_sve_\@: .endm +/* Disable any fine grained traps */ +.macro __init_el2_fgt + mrs x1, id_aa64mmfr0_el1 + ubfx x1, x1, #ID_AA64MMFR0_FGT_SHIFT, #4 + cbz x1, .Lskip_fgt_\@ + + msr_s SYS_HDFGRTR_EL2, xzr + msr_s SYS_HDFGWTR_EL2, xzr + msr_s SYS_HFGRTR_EL2, xzr + msr_s SYS_HFGWTR_EL2, xzr + msr_s SYS_HFGITR_EL2, xzr + + mrs x1, id_aa64pfr0_el1 // AMU traps UNDEF without AMU + ubfx x1, x1, #ID_AA64PFR0_AMU_SHIFT, #4 + cbz x1, .Lskip_fgt_\@ + + msr_s SYS_HAFGRTR_EL2, xzr +.Lskip_fgt_\@: +.endm + .macro __init_el2_nvhe_prepare_eret mov x0, #INIT_PSTATE_EL1 msr spsr_el2, x0 @@ -155,6 +175,7 @@ __init_el2_nvhe_idregs __init_el2_nvhe_cptr __init_el2_nvhe_sve + __init_el2_fgt __init_el2_nvhe_prepare_eret .endm diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h index bec5f14b622ae2fd50e471803418ca6c91c624f0..ebb263b2d3b19ebec07f68e4fdadb2e684106076 100644 --- a/arch/arm64/include/asm/fpsimd.h +++ b/arch/arm64/include/asm/fpsimd.h @@ -73,6 +73,7 @@ extern void sve_flush_live(void); extern void sve_load_from_fpsimd_state(struct user_fpsimd_state const *state, unsigned long vq_minus_1); extern unsigned int sve_get_vl(void); +extern void sve_set_vq(unsigned long vq_minus_1); struct arm64_cpu_capabilities; extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused); diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 5ea8656a2030bff30e447041029f13106b4c44c3..7fd836bea7eb42853883fae3ea5015867e3dd0b9 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -169,16 +169,7 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size); #define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC)) - -/* - * PCI configuration space mapping function. - * - * The PCI specification disallows posted write configuration transactions. - * Add an arch specific pci_remap_cfgspace() definition that is implemented - * through nGnRnE device memory attribute as recommended by the ARM v8 - * Architecture reference manual Issue A.k B2.8.2 "Device memory". - */ -#define pci_remap_cfgspace(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRnE)) +#define ioremap_np(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRnE)) /* * io{read,write}{16,32,64}be() macros diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index b2b0c6405eb082fea7c99e607e7f2c9d9cca4ee7..fac08e18bcd512eec9bbafe7fa79a38ccea1d48c 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -8,6 +8,10 @@ struct pt_regs; +int set_handle_irq(void (*handle_irq)(struct pt_regs *)); +#define set_handle_irq set_handle_irq +int set_handle_fiq(void (*handle_fiq)(struct pt_regs *)); + static inline int nr_legacy_irqs(void) { return 0; diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h index a1020285ea75045c08006b4e068181fac4338a51..81bbfa3a035bd2152f5239a37607136091ffb156 100644 --- a/arch/arm64/include/asm/irq_work.h +++ b/arch/arm64/include/asm/irq_work.h @@ -2,6 +2,8 @@ #ifndef __ASM_IRQ_WORK_H #define __ASM_IRQ_WORK_H +extern void arch_irq_work_raise(void); + static inline bool arch_irq_work_has_interrupt(void) { return true; diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h index ff328e5bbb75721e93d1df93bf43cf55aae6f492..b57b9b1e434485d5c869f953ce969da70aeca6dd 100644 --- a/arch/arm64/include/asm/irqflags.h +++ b/arch/arm64/include/asm/irqflags.h @@ -12,15 +12,13 @@ /* * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and - * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'dai' + * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif' * order: * Masking debug exceptions causes all other exceptions to be masked too/ - * Masking SError masks irq, but not debug exceptions. Masking irqs has no - * side effects for other flags. Keeping to this order makes it easier for - * entry.S to know which exceptions should be unmasked. - * - * FIQ is never expected, but we mask it when we disable debug exceptions, and - * unmask it at all other times. + * Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are + * always masked and unmasked together, and have no side effects for other + * flags. Keeping to this order makes it easier for entry.S to know which + * exceptions should be unmasked. */ /* @@ -35,7 +33,7 @@ static inline void arch_local_irq_enable(void) } asm volatile(ALTERNATIVE( - "msr daifclr, #2 // arch_local_irq_enable", + "msr daifclr, #3 // arch_local_irq_enable", __msr_s(SYS_ICC_PMR_EL1, "%0"), ARM64_HAS_IRQ_PRIO_MASKING) : @@ -54,7 +52,7 @@ static inline void arch_local_irq_disable(void) } asm volatile(ALTERNATIVE( - "msr daifset, #2 // arch_local_irq_disable", + "msr daifset, #3 // arch_local_irq_disable", __msr_s(SYS_ICC_PMR_EL1, "%0"), ARM64_HAS_IRQ_PRIO_MASKING) : diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 0aabc3be9a75953fe02b48d535198cc9eed7f6bf..e6c7417bfb9290403399c0b0604a73c4e4cc681c 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -243,8 +243,10 @@ static inline const void *__tag_set(const void *addr, u8 tag) } #ifdef CONFIG_KASAN_HW_TAGS -#define arch_enable_tagging() mte_enable_kernel() +#define arch_enable_tagging_sync() mte_enable_kernel_sync() +#define arch_enable_tagging_async() mte_enable_kernel_async() #define arch_set_tagging_report_once(state) mte_set_report_once(state) +#define arch_force_async_tag_fault() mte_check_tfsr_exit() #define arch_init_tags(max_tag) mte_init_tags(max_tag) #define arch_get_random_tag() mte_get_random_tag() #define arch_get_mem_tag(addr) mte_get_mem_tag(addr) @@ -321,6 +323,22 @@ static inline void *phys_to_virt(phys_addr_t x) #define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x))) #define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x)) +#ifdef CONFIG_CFI_CLANG +/* + * With CONFIG_CFI_CLANG, the compiler replaces function address + * references with the address of the function's CFI jump table + * entry. The function_nocfi macro always returns the address of the + * actual function instead. + */ +#define function_nocfi(x) ({ \ + void *addr; \ + asm("adrp %0, " __stringify(x) "\n\t" \ + "add %0, %0, :lo12:" __stringify(x) \ + : "=r" (addr)); \ + addr; \ +}) +#endif + /* * virt_to_page(x) convert a _valid_ virtual address to struct page * * virt_addr_valid(x) indicates whether a virtual address is valid diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index bd02e99b1a4c54972f871ebe4d0c81650b965abb..d3cef91335396c8df517d621250f361cba6fe434 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -119,7 +119,7 @@ static inline void cpu_install_idmap(void) * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD, * avoiding the possibility of conflicting TLB entries being allocated. */ -static inline void cpu_replace_ttbr1(pgd_t *pgdp) +static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp) { typedef void (ttbr_replace_func)(phys_addr_t); extern ttbr_replace_func idmap_cpu_replace_ttbr1; @@ -140,7 +140,7 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp) ttbr1 |= TTBR_CNP_BIT; } - replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1); + replace_phys = (void *)__pa_symbol(function_nocfi(idmap_cpu_replace_ttbr1)); cpu_install_idmap(); replace_phys(ttbr1); diff --git a/arch/arm64/include/asm/mte-kasan.h b/arch/arm64/include/asm/mte-kasan.h index 7ab500e2ad1762c054e4f36f0840a78696ba5985..4acf8bf41cade68d70e48a0a05f95b7fe25f2aea 100644 --- a/arch/arm64/include/asm/mte-kasan.h +++ b/arch/arm64/include/asm/mte-kasan.h @@ -77,7 +77,8 @@ static inline void mte_set_mem_tag_range(void *addr, size_t size, u8 tag) } while (curr != end); } -void mte_enable_kernel(void); +void mte_enable_kernel_sync(void); +void mte_enable_kernel_async(void); void mte_init_tags(u64 max_tag); void mte_set_report_once(bool state); @@ -104,7 +105,11 @@ static inline void mte_set_mem_tag_range(void *addr, size_t size, u8 tag) { } -static inline void mte_enable_kernel(void) +static inline void mte_enable_kernel_sync(void) +{ +} + +static inline void mte_enable_kernel_async(void) { } diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h index 9b557a457f244c7f8f79c129a916fc0fb1c12563..bc88a1ced0d7e588070437f1ac34ba9fa01aec02 100644 --- a/arch/arm64/include/asm/mte.h +++ b/arch/arm64/include/asm/mte.h @@ -39,16 +39,15 @@ void mte_free_tag_storage(char *storage); void mte_sync_tags(pte_t *ptep, pte_t pte); void mte_copy_page_tags(void *kto, const void *kfrom); -void flush_mte_state(void); +void mte_thread_init_user(void); void mte_thread_switch(struct task_struct *next); +void mte_suspend_enter(void); void mte_suspend_exit(void); long set_mte_ctrl(struct task_struct *task, unsigned long arg); long get_mte_ctrl(struct task_struct *task); int mte_ptrace_copy_tags(struct task_struct *child, long request, unsigned long addr, unsigned long data); -void mte_assign_mem_tag_range(void *addr, size_t size); - #else /* CONFIG_ARM64_MTE */ /* unused if !CONFIG_ARM64_MTE, silence the compiler */ @@ -60,12 +59,15 @@ static inline void mte_sync_tags(pte_t *ptep, pte_t pte) static inline void mte_copy_page_tags(void *kto, const void *kfrom) { } -static inline void flush_mte_state(void) +static inline void mte_thread_init_user(void) { } static inline void mte_thread_switch(struct task_struct *next) { } +static inline void mte_suspend_enter(void) +{ +} static inline void mte_suspend_exit(void) { } @@ -84,11 +86,51 @@ static inline int mte_ptrace_copy_tags(struct task_struct *child, return -EIO; } -static inline void mte_assign_mem_tag_range(void *addr, size_t size) +#endif /* CONFIG_ARM64_MTE */ + +#ifdef CONFIG_KASAN_HW_TAGS +/* Whether the MTE asynchronous mode is enabled. */ +DECLARE_STATIC_KEY_FALSE(mte_async_mode); + +static inline bool system_uses_mte_async_mode(void) { + return static_branch_unlikely(&mte_async_mode); } -#endif /* CONFIG_ARM64_MTE */ +void mte_check_tfsr_el1(void); + +static inline void mte_check_tfsr_entry(void) +{ + mte_check_tfsr_el1(); +} + +static inline void mte_check_tfsr_exit(void) +{ + /* + * The asynchronous faults are sync'ed automatically with + * TFSR_EL1 on kernel entry but for exit an explicit dsb() + * is required. + */ + dsb(nsh); + isb(); + + mte_check_tfsr_el1(); +} +#else +static inline bool system_uses_mte_async_mode(void) +{ + return false; +} +static inline void mte_check_tfsr_el1(void) +{ +} +static inline void mte_check_tfsr_entry(void) +{ +} +static inline void mte_check_tfsr_exit(void) +{ +} +#endif /* CONFIG_KASAN_HW_TAGS */ #endif /* __ASSEMBLY__ */ #endif /* __ASM_MTE_H */ diff --git a/arch/arm64/include/asm/paravirt.h b/arch/arm64/include/asm/paravirt.h index cf3a0fd7c1a7e00ef146b4a19aa4abf711a33b6c..9aa193e0e8f28d9309bc18013230e714152f4f93 100644 --- a/arch/arm64/include/asm/paravirt.h +++ b/arch/arm64/include/asm/paravirt.h @@ -3,23 +3,19 @@ #define _ASM_ARM64_PARAVIRT_H #ifdef CONFIG_PARAVIRT +#include <linux/static_call_types.h> + struct static_key; extern struct static_key paravirt_steal_enabled; extern struct static_key paravirt_steal_rq_enabled; -struct pv_time_ops { - unsigned long long (*steal_clock)(int cpu); -}; - -struct paravirt_patch_template { - struct pv_time_ops time; -}; +u64 dummy_steal_clock(int cpu); -extern struct paravirt_patch_template pv_ops; +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); static inline u64 paravirt_steal_clock(int cpu) { - return pv_ops.time.steal_clock(cpu); + return static_call(pv_steal_clock)(cpu); } int __init pv_time_init(void); diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index 3c6a7f5988b127e54b14d422489feda06d03f847..31fbab3d6f99234c301cde17d856dec02f12b17c 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -27,7 +27,10 @@ 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) { - __pud_populate(pudp, __pa(pmdp), PMD_TYPE_TABLE); + pudval_t pudval = PUD_TYPE_TABLE; + + pudval |= (mm == &init_mm) ? PUD_TABLE_UXN : PUD_TABLE_PXN; + __pud_populate(pudp, __pa(pmdp), pudval); } #else static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot) @@ -45,7 +48,10 @@ 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) { - __p4d_populate(p4dp, __pa(pudp), PUD_TYPE_TABLE); + p4dval_t p4dval = P4D_TYPE_TABLE; + + p4dval |= (mm == &init_mm) ? P4D_TABLE_UXN : P4D_TABLE_PXN; + __p4d_populate(p4dp, __pa(pudp), p4dval); } #else static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot) @@ -70,16 +76,15 @@ static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep, static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) { - /* - * The pmd must be loaded with the physical address of the PTE table - */ - __pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE); + VM_BUG_ON(mm != &init_mm); + __pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE | PMD_TABLE_UXN); } static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) { - __pmd_populate(pmdp, page_to_phys(ptep), PMD_TYPE_TABLE); + VM_BUG_ON(mm == &init_mm); + __pmd_populate(pmdp, page_to_phys(ptep), PMD_TYPE_TABLE | PMD_TABLE_PXN); } #define pmd_pgtable(pmd) pmd_page(pmd) diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index 42442a0ae2ab9b3d37afd3f2cc3ae920c37f76db..b82575a33f8b62f638c0f728bfc0681dfa6b0cad 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -94,6 +94,17 @@ /* * Hardware page table definitions. * + * Level 0 descriptor (P4D). + */ +#define P4D_TYPE_TABLE (_AT(p4dval_t, 3) << 0) +#define P4D_TABLE_BIT (_AT(p4dval_t, 1) << 1) +#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_PXN (_AT(p4dval_t, 1) << 59) +#define P4D_TABLE_UXN (_AT(p4dval_t, 1) << 60) + +/* * Level 1 descriptor (PUD). */ #define PUD_TYPE_TABLE (_AT(pudval_t, 3) << 0) @@ -101,6 +112,8 @@ #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_PXN (_AT(pudval_t, 1) << 59) +#define PUD_TABLE_UXN (_AT(pudval_t, 1) << 60) /* * Level 2 descriptor (PMD). @@ -122,6 +135,8 @@ #define PMD_SECT_CONT (_AT(pmdval_t, 1) << 52) #define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53) #define PMD_SECT_UXN (_AT(pmdval_t, 1) << 54) +#define PMD_TABLE_PXN (_AT(pmdval_t, 1) << 59) +#define PMD_TABLE_UXN (_AT(pmdval_t, 1) << 60) /* * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 9a65fb5281100a7e08b29ee380c91b84cd887ca6..fab2f573f7a4fa239710b2e20857403da6929436 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -87,12 +87,13 @@ extern bool arm64_use_ng_mappings; #define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE) #define PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) #define PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN) +#define PAGE_EXECONLY __pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN) #define __P000 PAGE_NONE #define __P001 PAGE_READONLY #define __P010 PAGE_READONLY #define __P011 PAGE_READONLY -#define __P100 PAGE_READONLY_EXEC +#define __P100 PAGE_EXECONLY #define __P101 PAGE_READONLY_EXEC #define __P110 PAGE_READONLY_EXEC #define __P111 PAGE_READONLY_EXEC @@ -101,7 +102,7 @@ extern bool arm64_use_ng_mappings; #define __S001 PAGE_READONLY #define __S010 PAGE_SHARED #define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY_EXEC +#define __S100 PAGE_EXECONLY #define __S101 PAGE_READONLY_EXEC #define __S110 PAGE_SHARED_EXEC #define __S111 PAGE_SHARED_EXEC diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 47027796c2f934a0207013044dcaee2f9e58078c..0b10204e72fcbca2586d0106a610833e9f6b194c 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -113,11 +113,12 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte)) #define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID)) +/* + * Execute-only user mappings do not have the PTE_USER bit set. All valid + * kernel mappings have the PTE_UXN bit set. + */ #define pte_valid_not_user(pte) \ - ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID) -#define pte_valid_user(pte) \ - ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) - + ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN)) /* * Could the pte be present in the TLB? We must check mm_tlb_flush_pending * so that we don't erroneously return false for pages that have been @@ -130,12 +131,14 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte)) /* - * p??_access_permitted() is true for valid user mappings (subject to the - * write permission check). PROT_NONE mappings do not have the PTE_VALID bit - * set. + * p??_access_permitted() is true for valid user mappings (PTE_USER + * bit set, subject to the write permission check). For execute-only + * mappings, like PROT_EXEC with EPAN (both PTE_USER and PTE_UXN bits + * not set) must return false. PROT_NONE mappings do not have the + * PTE_VALID bit set. */ #define pte_access_permitted(pte, write) \ - (pte_valid_user(pte) && (!(write) || pte_write(pte))) + (((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) && (!(write) || pte_write(pte))) #define pmd_access_permitted(pmd, write) \ (pte_access_permitted(pmd_pte(pmd), (write))) #define pud_access_permitted(pud, write) \ @@ -995,6 +998,18 @@ static inline bool arch_wants_old_prefaulted_pte(void) } #define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte +static inline pgprot_t arch_filter_pgprot(pgprot_t prot) +{ + if (cpus_have_const_cap(ARM64_HAS_EPAN)) + return prot; + + if (pgprot_val(prot) != pgprot_val(PAGE_EXECONLY)) + return prot; + + return PAGE_READONLY_EXEC; +} + + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_PGTABLE_H */ diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index b112a11e93024f4cff245b294fdf48637cd01f6d..d50416be99be0bf0d903f0a985b476546bc83d63 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h @@ -3,6 +3,7 @@ #define __ASM_POINTER_AUTH_H #include <linux/bitops.h> +#include <linux/prctl.h> #include <linux/random.h> #include <asm/cpufeature.h> @@ -34,6 +35,25 @@ struct ptrauth_keys_kernel { struct ptrauth_key apia; }; +#define __ptrauth_key_install_nosync(k, v) \ +do { \ + struct ptrauth_key __pki_v = (v); \ + write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1); \ + write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1); \ +} while (0) + +static inline void ptrauth_keys_install_user(struct ptrauth_keys_user *keys) +{ + if (system_supports_address_auth()) { + __ptrauth_key_install_nosync(APIB, keys->apib); + __ptrauth_key_install_nosync(APDA, keys->apda); + __ptrauth_key_install_nosync(APDB, keys->apdb); + } + + if (system_supports_generic_auth()) + __ptrauth_key_install_nosync(APGA, keys->apga); +} + static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys) { if (system_supports_address_auth()) { @@ -45,14 +65,9 @@ static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys) if (system_supports_generic_auth()) get_random_bytes(&keys->apga, sizeof(keys->apga)); -} -#define __ptrauth_key_install_nosync(k, v) \ -do { \ - struct ptrauth_key __pki_v = (v); \ - write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1); \ - write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1); \ -} while (0) + ptrauth_keys_install_user(keys); +} static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys) { @@ -71,6 +86,10 @@ static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kerne extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg); +extern int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys, + unsigned long enabled); +extern int ptrauth_get_enabled_keys(struct task_struct *tsk); + static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr) { return ptrauth_clear_pac(ptr); @@ -85,8 +104,23 @@ static __always_inline void ptrauth_enable(void) isb(); } -#define ptrauth_thread_init_user(tsk) \ - ptrauth_keys_init_user(&(tsk)->thread.keys_user) +#define ptrauth_suspend_exit() \ + ptrauth_keys_install_user(¤t->thread.keys_user) + +#define ptrauth_thread_init_user() \ + do { \ + ptrauth_keys_init_user(¤t->thread.keys_user); \ + \ + /* enable all keys */ \ + if (system_supports_address_auth()) \ + set_task_sctlr_el1(current->thread.sctlr_user | \ + SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \ + SCTLR_ELx_ENDA | SCTLR_ELx_ENDB); \ + } while (0) + +#define ptrauth_thread_switch_user(tsk) \ + ptrauth_keys_install_user(&(tsk)->thread.keys_user) + #define ptrauth_thread_init_kernel(tsk) \ ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel) #define ptrauth_thread_switch_kernel(tsk) \ @@ -95,10 +129,17 @@ static __always_inline void ptrauth_enable(void) #else /* CONFIG_ARM64_PTR_AUTH */ #define ptrauth_enable() #define ptrauth_prctl_reset_keys(tsk, arg) (-EINVAL) +#define ptrauth_set_enabled_keys(tsk, keys, enabled) (-EINVAL) +#define ptrauth_get_enabled_keys(tsk) (-EINVAL) #define ptrauth_strip_insn_pac(lr) (lr) -#define ptrauth_thread_init_user(tsk) +#define ptrauth_suspend_exit() +#define ptrauth_thread_init_user() #define ptrauth_thread_init_kernel(tsk) +#define ptrauth_thread_switch_user(tsk) #define ptrauth_thread_switch_kernel(tsk) #endif /* CONFIG_ARM64_PTR_AUTH */ +#define PR_PAC_ENABLED_KEYS_MASK \ + (PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY) + #endif /* __ASM_POINTER_AUTH_H */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 5bf4c484ab26b3de42b1a18aad3bed6ff0c0744c..35cb45e3d9ff85a2d7493df355ad8169dbec09f7 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -154,11 +154,15 @@ struct thread_struct { struct ptrauth_keys_kernel keys_kernel; #endif #ifdef CONFIG_ARM64_MTE - u64 sctlr_tcf0; u64 gcr_user_excl; #endif + u64 sctlr_user; }; +#define SCTLR_USER_MASK \ + (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB | \ + SCTLR_EL1_TCF0_MASK) + static inline void arch_thread_struct_whitelist(unsigned long *offset, unsigned long *size) { @@ -250,6 +254,8 @@ extern void release_thread(struct task_struct *); unsigned long get_wchan(struct task_struct *p); +void set_task_sctlr_el1(u64 sctlr); + /* Thread switching */ extern struct task_struct *cpu_switch_to(struct task_struct *prev, struct task_struct *next); @@ -306,6 +312,11 @@ extern void __init minsigstksz_setup(void); /* PR_PAC_RESET_KEYS prctl */ #define PAC_RESET_KEYS(tsk, arg) ptrauth_prctl_reset_keys(tsk, arg) +/* PR_PAC_{SET,GET}_ENABLED_KEYS prctl */ +#define PAC_SET_ENABLED_KEYS(tsk, keys, enabled) \ + ptrauth_set_enabled_keys(tsk, keys, enabled) +#define PAC_GET_ENABLED_KEYS(tsk) ptrauth_get_enabled_keys(tsk) + #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI /* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg); diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h index 38187f74e0896525cba3783870dc19fb61bde388..b1dd7ecff7efb4a3b1edcf954bb3368080d9bb48 100644 --- a/arch/arm64/include/asm/ptdump.h +++ b/arch/arm64/include/asm/ptdump.h @@ -23,7 +23,7 @@ struct ptdump_info { void ptdump_walk(struct seq_file *s, struct ptdump_info *info); #ifdef CONFIG_PTDUMP_DEBUGFS -void ptdump_debugfs_register(struct ptdump_info *info, const char *name); +void __init ptdump_debugfs_register(struct ptdump_info *info, const char *name); #else static inline void ptdump_debugfs_register(struct ptdump_info *info, const char *name) { } diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 030eebcaa901a5ebb5cb94ccb54b96b1fb963a56..566e973e38c2c0f91f8f6a07ab25ca85d9ee5f8f 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -147,6 +147,7 @@ bool cpus_are_stuck_in_kernel(void); extern void crash_smp_send_stop(void); extern bool smp_crash_stop_failed(void); +extern void panic_smp_self_stop(void); #endif /* ifndef __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index eb29b1fe8255eb23d0cf2e9e588dd19ddee5061b..4b33ca6206793361fad25b23258c05ccfe06b024 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -148,27 +148,7 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, return false; } -static inline void start_backtrace(struct stackframe *frame, - unsigned long fp, unsigned long pc) -{ - frame->fp = fp; - frame->pc = pc; -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame->graph = 0; -#endif - - /* - * Prime the first unwind. - * - * In unwind_frame() we'll check that the FP points to a valid stack, - * which can't be STACK_TYPE_UNKNOWN, and the first unwind will be - * treated as a transition to whichever stack that happens to be. The - * prev_fp value won't be used, but we set it to 0 such that it is - * definitely not an accessible stack address. - */ - bitmap_zero(frame->stacks_done, __NR_STACK_TYPES); - frame->prev_fp = 0; - frame->prev_type = STACK_TYPE_UNKNOWN; -} +void start_backtrace(struct stackframe *frame, unsigned long fp, + unsigned long pc); #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index d4a5fca984c3e228594e19a80fa68bc37e43e16c..012a0b8c0a27c83394af56c099656f3c0f927a14 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -475,9 +475,15 @@ #define SYS_PMCCFILTR_EL0 sys_reg(3, 3, 14, 15, 7) #define SYS_SCTLR_EL2 sys_reg(3, 4, 1, 0, 0) +#define SYS_HFGRTR_EL2 sys_reg(3, 4, 1, 1, 4) +#define SYS_HFGWTR_EL2 sys_reg(3, 4, 1, 1, 5) +#define SYS_HFGITR_EL2 sys_reg(3, 4, 1, 1, 6) #define SYS_ZCR_EL2 sys_reg(3, 4, 1, 2, 0) #define SYS_TRFCR_EL2 sys_reg(3, 4, 1, 2, 1) #define SYS_DACR32_EL2 sys_reg(3, 4, 3, 0, 0) +#define SYS_HDFGRTR_EL2 sys_reg(3, 4, 3, 1, 4) +#define SYS_HDFGWTR_EL2 sys_reg(3, 4, 3, 1, 5) +#define SYS_HAFGRTR_EL2 sys_reg(3, 4, 3, 1, 6) #define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0) #define SYS_ELR_EL2 sys_reg(3, 4, 4, 0, 1) #define SYS_IFSR32_EL2 sys_reg(3, 4, 5, 0, 1) @@ -565,8 +571,10 @@ #define SCTLR_ELx_TCF_ASYNC (UL(0x2) << SCTLR_ELx_TCF_SHIFT) #define SCTLR_ELx_TCF_MASK (UL(0x3) << SCTLR_ELx_TCF_SHIFT) +#define SCTLR_ELx_ENIA_SHIFT 31 + #define SCTLR_ELx_ITFSB (BIT(37)) -#define SCTLR_ELx_ENIA (BIT(31)) +#define SCTLR_ELx_ENIA (BIT(SCTLR_ELx_ENIA_SHIFT)) #define SCTLR_ELx_ENIB (BIT(30)) #define SCTLR_ELx_ENDA (BIT(27)) #define SCTLR_ELx_EE (BIT(25)) @@ -597,6 +605,7 @@ (SCTLR_EL2_RES1 | ENDIAN_SET_EL2) /* SCTLR_EL1 specific flags. */ +#define SCTLR_EL1_EPAN (BIT(57)) #define SCTLR_EL1_ATA0 (BIT(42)) #define SCTLR_EL1_TCF0_SHIFT 38 @@ -637,7 +646,7 @@ SCTLR_EL1_SED | SCTLR_ELx_I | SCTLR_EL1_DZE | SCTLR_EL1_UCT | \ SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN | SCTLR_ELx_ITFSB | \ SCTLR_ELx_ATA | SCTLR_EL1_ATA0 | ENDIAN_SET_EL1 | SCTLR_EL1_UCI | \ - SCTLR_EL1_RES1) + SCTLR_EL1_EPAN | SCTLR_EL1_RES1) /* MAIR_ELx memory attributes (used by Linux) */ #define MAIR_ATTR_DEVICE_nGnRnE UL(0x00) @@ -1032,6 +1041,66 @@ #define TRFCR_ELx_ExTRE BIT(1) #define TRFCR_ELx_E0TRE BIT(0) + +/* GIC Hypervisor interface registers */ +/* ICH_MISR_EL2 bit definitions */ +#define ICH_MISR_EOI (1 << 0) +#define ICH_MISR_U (1 << 1) + +/* ICH_LR*_EL2 bit definitions */ +#define ICH_LR_VIRTUAL_ID_MASK ((1ULL << 32) - 1) + +#define ICH_LR_EOI (1ULL << 41) +#define ICH_LR_GROUP (1ULL << 60) +#define ICH_LR_HW (1ULL << 61) +#define ICH_LR_STATE (3ULL << 62) +#define ICH_LR_PENDING_BIT (1ULL << 62) +#define ICH_LR_ACTIVE_BIT (1ULL << 63) +#define ICH_LR_PHYS_ID_SHIFT 32 +#define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT) +#define ICH_LR_PRIORITY_SHIFT 48 +#define ICH_LR_PRIORITY_MASK (0xffULL << ICH_LR_PRIORITY_SHIFT) + +/* ICH_HCR_EL2 bit definitions */ +#define ICH_HCR_EN (1 << 0) +#define ICH_HCR_UIE (1 << 1) +#define ICH_HCR_NPIE (1 << 3) +#define ICH_HCR_TC (1 << 10) +#define ICH_HCR_TALL0 (1 << 11) +#define ICH_HCR_TALL1 (1 << 12) +#define ICH_HCR_EOIcount_SHIFT 27 +#define ICH_HCR_EOIcount_MASK (0x1f << ICH_HCR_EOIcount_SHIFT) + +/* ICH_VMCR_EL2 bit definitions */ +#define ICH_VMCR_ACK_CTL_SHIFT 2 +#define ICH_VMCR_ACK_CTL_MASK (1 << ICH_VMCR_ACK_CTL_SHIFT) +#define ICH_VMCR_FIQ_EN_SHIFT 3 +#define ICH_VMCR_FIQ_EN_MASK (1 << ICH_VMCR_FIQ_EN_SHIFT) +#define ICH_VMCR_CBPR_SHIFT 4 +#define ICH_VMCR_CBPR_MASK (1 << ICH_VMCR_CBPR_SHIFT) +#define ICH_VMCR_EOIM_SHIFT 9 +#define ICH_VMCR_EOIM_MASK (1 << ICH_VMCR_EOIM_SHIFT) +#define ICH_VMCR_BPR1_SHIFT 18 +#define ICH_VMCR_BPR1_MASK (7 << ICH_VMCR_BPR1_SHIFT) +#define ICH_VMCR_BPR0_SHIFT 21 +#define ICH_VMCR_BPR0_MASK (7 << ICH_VMCR_BPR0_SHIFT) +#define ICH_VMCR_PMR_SHIFT 24 +#define ICH_VMCR_PMR_MASK (0xffUL << ICH_VMCR_PMR_SHIFT) +#define ICH_VMCR_ENG0_SHIFT 0 +#define ICH_VMCR_ENG0_MASK (1 << ICH_VMCR_ENG0_SHIFT) +#define ICH_VMCR_ENG1_SHIFT 1 +#define ICH_VMCR_ENG1_MASK (1 << ICH_VMCR_ENG1_SHIFT) + +/* ICH_VTR_EL2 bit definitions */ +#define ICH_VTR_PRI_BITS_SHIFT 29 +#define ICH_VTR_PRI_BITS_MASK (7 << ICH_VTR_PRI_BITS_SHIFT) +#define ICH_VTR_ID_BITS_SHIFT 23 +#define ICH_VTR_ID_BITS_MASK (7 << ICH_VTR_ID_BITS_SHIFT) +#define ICH_VTR_SEIS_SHIFT 22 +#define ICH_VTR_SEIS_MASK (1 << ICH_VTR_SEIS_SHIFT) +#define ICH_VTR_A3V_SHIFT 21 +#define ICH_VTR_A3V_MASK (1 << ICH_VTR_A3V_SHIFT) + #ifdef __ASSEMBLY__ .irp num,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 diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 3b8dca4eb08d4138d5301d352178be877511bc29..ec2db3419c4183f82103563372f2f9500f904070 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -17,17 +17,9 @@ int pcibus_to_node(struct pci_bus *bus); #include <linux/arch_topology.h> void update_freq_counters_refs(void); -void topology_scale_freq_tick(void); - -#ifdef CONFIG_ARM64_AMU_EXTN -/* - * Replace task scheduler's default counter-based - * frequency-invariance scale factor setting. - */ -#define arch_scale_freq_tick topology_scale_freq_tick -#endif /* CONFIG_ARM64_AMU_EXTN */ /* Replace task scheduler's default frequency-invariant accounting */ +#define arch_scale_freq_tick topology_scale_freq_tick #define arch_set_freq_scale topology_set_freq_scale #define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_invariant topology_scale_freq_invariant diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 0deb88467111cccb0ec87cae36644834a516041e..b5f08621fa296168968506e0ae545c4c2dfd9406 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -20,6 +20,7 @@ #include <asm/cpufeature.h> #include <asm/mmu.h> +#include <asm/mte.h> #include <asm/ptrace.h> #include <asm/memory.h> #include <asm/extable.h> @@ -188,6 +189,23 @@ static inline void __uaccess_enable_tco(void) ARM64_MTE, CONFIG_KASAN_HW_TAGS)); } +/* + * These functions disable tag checking only if in MTE async mode + * since the sync mode generates exceptions synchronously and the + * nofault or load_unaligned_zeropad can handle them. + */ +static inline void __uaccess_disable_tco_async(void) +{ + if (system_uses_mte_async_mode()) + __uaccess_disable_tco(); +} + +static inline void __uaccess_enable_tco_async(void) +{ + if (system_uses_mte_async_mode()) + __uaccess_enable_tco(); +} + static inline void uaccess_disable_privileged(void) { __uaccess_disable_tco(); @@ -307,8 +325,10 @@ do { \ do { \ int __gkn_err = 0; \ \ + __uaccess_enable_tco_async(); \ __raw_get_mem("ldr", *((type *)(dst)), \ (__force type *)(src), __gkn_err); \ + __uaccess_disable_tco_async(); \ if (unlikely(__gkn_err)) \ goto err_label; \ } while (0) @@ -380,8 +400,10 @@ do { \ do { \ int __pkn_err = 0; \ \ + __uaccess_enable_tco_async(); \ __raw_put_mem("str", *((type *)(src)), \ (__force type *)(dst), __pkn_err); \ + __uaccess_disable_tco_async(); \ if (unlikely(__pkn_err)) \ goto err_label; \ } while(0) diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index 631ab12816335ff0bed9eda6b9eb4ad56c657b72..4b4c0dac0e1494298e821e859c2a32737989109a 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -83,11 +83,7 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, */ isb(); asm volatile("mrs %0, cntvct_el0" : "=r" (res) :: "memory"); - /* - * This isb() is required to prevent that the seq lock is - * speculated.# - */ - isb(); + arch_counter_enforce_ordering(res); return res; } diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h index ea487218db7909765dceeb762339cacfea935b24..2dcb104c645b634134044828a0fd048e11e752c3 100644 --- a/arch/arm64/include/asm/word-at-a-time.h +++ b/arch/arm64/include/asm/word-at-a-time.h @@ -55,6 +55,8 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) { unsigned long ret, tmp; + __uaccess_enable_tco_async(); + /* Load word from unaligned pointer addr */ asm( "1: ldr %0, %3\n" @@ -76,6 +78,8 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) : "=&r" (ret), "=&r" (tmp) : "r" (addr), "Q" (*(unsigned long *)addr)); + __uaccess_disable_tco_async(); + return ret; } diff --git a/arch/arm64/include/asm/xen/swiotlb-xen.h b/arch/arm64/include/asm/xen/swiotlb-xen.h new file mode 100644 index 0000000000000000000000000000000000000000..455ade5d53205465cc3b94888713f222c66213d0 --- /dev/null +++ b/arch/arm64/include/asm/xen/swiotlb-xen.h @@ -0,0 +1 @@ +#include <xen/arm/swiotlb-xen.h> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index ed65576ce710b0277cd52393640f75a78f4fa6a0..6cc97730790e7167a69995aba58c94c40ec40e61 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -9,6 +9,11 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_insn.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE) +# Remove stack protector to avoid triggering unneeded stack canary +# checks due to randomize_kstack_offset. +CFLAGS_REMOVE_syscall.o = -fstack-protector -fstack-protector-strong +CFLAGS_syscall.o += -fno-stack-protector + # Object file lists. obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ entry-common.o entry-fpsimd.o process.o ptrace.o \ diff --git a/arch/arm64/kernel/acpi_parking_protocol.c b/arch/arm64/kernel/acpi_parking_protocol.c index e7c941d8340dcb71eeaf667d99e976be4e6a4d88..bfeeb5319abf9851c5b6fca759e3de03e39c0b41 100644 --- a/arch/arm64/kernel/acpi_parking_protocol.c +++ b/arch/arm64/kernel/acpi_parking_protocol.c @@ -99,7 +99,8 @@ static int acpi_parking_protocol_cpu_boot(unsigned int cpu) * that read this address need to convert this address to the * Boot-Loader's endianness before jumping. */ - writeq_relaxed(__pa_symbol(secondary_entry), &mailbox->entry_point); + writeq_relaxed(__pa_symbol(function_nocfi(secondary_entry)), + &mailbox->entry_point); writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id); arch_send_wakeup_ipi_mask(cpumask_of(cpu)); diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 1184c44ea2c7da0678cd821b839b9b643011c03e..abc84636af0766f54e808fdee1476ae31bf0af9d 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -133,8 +133,8 @@ static void clean_dcache_range_nopatch(u64 start, u64 end) } while (cur += d_size, cur < end); } -static void __apply_alternatives(void *alt_region, bool is_module, - unsigned long *feature_mask) +static void __nocfi __apply_alternatives(void *alt_region, bool is_module, + unsigned long *feature_mask) { struct alt_instr *alt; struct alt_region *region = alt_region; diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index a36e2fc330d430a714f901595ee9efc02bedab99..e797603e55b70ae46d44827aae0891240366cede 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -43,6 +43,7 @@ int main(void) #endif BLANK(); DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context)); + DEFINE(THREAD_SCTLR_USER, offsetof(struct task_struct, thread.sctlr_user)); #ifdef CONFIG_ARM64_PTR_AUTH DEFINE(THREAD_KEYS_USER, offsetof(struct task_struct, thread.keys_user)); DEFINE(THREAD_KEYS_KERNEL, offsetof(struct task_struct, thread.keys_kernel)); @@ -95,6 +96,8 @@ int main(void) DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE); BLANK(); DEFINE(PREEMPT_DISABLE_OFFSET, PREEMPT_DISABLE_OFFSET); + DEFINE(SOFTIRQ_SHIFT, SOFTIRQ_SHIFT); + DEFINE(IRQ_CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); BLANK(); DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack)); DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); @@ -147,10 +150,6 @@ int main(void) #endif #ifdef CONFIG_ARM64_PTR_AUTH DEFINE(PTRAUTH_USER_KEY_APIA, offsetof(struct ptrauth_keys_user, apia)); - DEFINE(PTRAUTH_USER_KEY_APIB, offsetof(struct ptrauth_keys_user, apib)); - DEFINE(PTRAUTH_USER_KEY_APDA, offsetof(struct ptrauth_keys_user, apda)); - DEFINE(PTRAUTH_USER_KEY_APDB, offsetof(struct ptrauth_keys_user, apdb)); - DEFINE(PTRAUTH_USER_KEY_APGA, offsetof(struct ptrauth_keys_user, apga)); DEFINE(PTRAUTH_KERNEL_KEY_APIA, offsetof(struct ptrauth_keys_kernel, apia)); BLANK(); #endif diff --git a/arch/arm64/kernel/cpu-reset.h b/arch/arm64/kernel/cpu-reset.h index ed50e9587ad813ceb82bafbae46c07891cc3c6f3..9a7b1262ef17a3a6462ffc31d2974f199f5a31c1 100644 --- a/arch/arm64/kernel/cpu-reset.h +++ b/arch/arm64/kernel/cpu-reset.h @@ -13,16 +13,16 @@ void __cpu_soft_restart(unsigned long el2_switch, unsigned long entry, unsigned long arg0, unsigned long arg1, unsigned long arg2); -static inline void __noreturn cpu_soft_restart(unsigned long entry, - unsigned long arg0, - unsigned long arg1, - unsigned long arg2) +static inline void __noreturn __nocfi cpu_soft_restart(unsigned long entry, + unsigned long arg0, + unsigned long arg1, + unsigned long arg2) { typeof(__cpu_soft_restart) *restart; unsigned long el2_switch = !is_kernel_in_hyp_mode() && is_hyp_mode_available(); - restart = (void *)__pa_symbol(__cpu_soft_restart); + restart = (void *)__pa_symbol(function_nocfi(__cpu_soft_restart)); cpu_install_idmap(); restart(el2_switch, entry, arg0, arg1, arg2); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index e5281e1c8f1d291020790d0319922ee8c1b3a4ea..30c82d38c189e2be6d35a377a953d79a0757eccd 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -808,6 +808,12 @@ static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new) reg->name, ftrp->shift + ftrp->width - 1, ftrp->shift, str, tmp); + } else if ((ftr_mask & reg->override->val) == ftr_mask) { + reg->override->val &= ~ftr_mask; + pr_warn("%s[%d:%d]: impossible override, ignored\n", + reg->name, + ftrp->shift + ftrp->width - 1, + ftrp->shift); } val = arm64_ftr_set_value(ftrp, val, ftr_new); @@ -1445,7 +1451,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, } #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -static void +static void __nocfi kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) { typedef void (kpti_remap_fn)(int, int, phys_addr_t); @@ -1462,7 +1468,7 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) if (arm64_use_ng_mappings) return; - remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); + remap_fn = (void *)__pa_symbol(function_nocfi(idmap_kpti_install_ng_mappings)); cpu_install_idmap(); remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir)); @@ -1619,7 +1625,6 @@ int get_cpu_with_amu_feat(void) } #endif -#ifdef CONFIG_ARM64_VHE static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused) { return is_kernel_in_hyp_mode(); @@ -1638,7 +1643,6 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused) if (!alternative_is_applied(ARM64_HAS_VIRT_HOST_EXTN)) write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); } -#endif static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused) { @@ -1823,6 +1827,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .cpu_enable = cpu_enable_pan, }, #endif /* CONFIG_ARM64_PAN */ +#ifdef CONFIG_ARM64_EPAN + { + .desc = "Enhanced Privileged Access Never", + .capability = ARM64_HAS_EPAN, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, + .sys_reg = SYS_ID_AA64MMFR1_EL1, + .field_pos = ID_AA64MMFR1_PAN_SHIFT, + .sign = FTR_UNSIGNED, + .min_field_value = 3, + }, +#endif /* CONFIG_ARM64_EPAN */ #ifdef CONFIG_ARM64_LSE_ATOMICS { .desc = "LSE atomic instructions", @@ -1841,7 +1857,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE, .matches = has_no_hw_prefetch, }, -#ifdef CONFIG_ARM64_VHE { .desc = "Virtualization Host Extensions", .capability = ARM64_HAS_VIRT_HOST_EXTN, @@ -1849,7 +1864,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = runs_at_el2, .cpu_enable = cpu_copy_el2regs, }, -#endif /* CONFIG_ARM64_VHE */ { .desc = "32-bit EL0 Support", .capability = ARM64_HAS_32BIT_EL0, diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c index 9d35884504737173efb02d6c127946ba42cfe932..a1ec351c36bd8aa6085eebd98c9f5cf2084a92d0 100644 --- a/arch/arm64/kernel/entry-common.c +++ b/arch/arm64/kernel/entry-common.c @@ -37,6 +37,8 @@ static void noinstr enter_from_kernel_mode(struct pt_regs *regs) lockdep_hardirqs_off(CALLER_ADDR0); rcu_irq_enter_check_tick(); trace_hardirqs_off_finish(); + + mte_check_tfsr_entry(); } /* @@ -47,6 +49,8 @@ static void noinstr exit_to_kernel_mode(struct pt_regs *regs) { lockdep_assert_irqs_disabled(); + mte_check_tfsr_exit(); + if (interrupts_enabled(regs)) { if (regs->exit_rcu) { trace_hardirqs_on_prepare(); @@ -293,6 +297,8 @@ asmlinkage void noinstr enter_from_user_mode(void) asmlinkage void noinstr exit_to_user_mode(void) { + mte_check_tfsr_exit(); + trace_hardirqs_on_prepare(); lockdep_hardirqs_on_prepare(CALLER_ADDR0); user_enter_irqoff(); diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S index 2ca395c25448f45f29e55ca67992d3ebd491aeb4..3ecec60d3295832b8c7a5917767c638e3866d92e 100644 --- a/arch/arm64/kernel/entry-fpsimd.S +++ b/arch/arm64/kernel/entry-fpsimd.S @@ -48,6 +48,11 @@ SYM_FUNC_START(sve_get_vl) ret SYM_FUNC_END(sve_get_vl) +SYM_FUNC_START(sve_set_vq) + sve_load_vq x0, x1, x2 + ret +SYM_FUNC_END(sve_set_vq) + /* * Load SVE state from FPSIMD state. * diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 6acfc5e6b5e05d926a291aea9c3ca07cfd49e888..4ac5455c0eaddef032d49ae06fd8b470e354f27d 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -249,7 +249,29 @@ alternative_else_nop_endif check_mte_async_tcf x22, x23 apply_ssbd 1, x22, x23 - ptrauth_keys_install_kernel tsk, x20, x22, x23 +#ifdef CONFIG_ARM64_PTR_AUTH +alternative_if ARM64_HAS_ADDRESS_AUTH + /* + * Enable IA for in-kernel PAC if the task had it disabled. Although + * this could be implemented with an unconditional MRS which would avoid + * a load, this was measured to be slower on Cortex-A75 and Cortex-A76. + * + * Install the kernel IA key only if IA was enabled in the task. If IA + * was disabled on kernel exit then we would have left the kernel IA + * installed so there is no need to install it again. + */ + ldr x0, [tsk, THREAD_SCTLR_USER] + tbz x0, SCTLR_ELx_ENIA_SHIFT, 1f + __ptrauth_keys_install_kernel_nosync tsk, x20, x22, x23 + b 2f +1: + mrs x0, sctlr_el1 + orr x0, x0, SCTLR_ELx_ENIA + msr sctlr_el1, x0 +2: + isb +alternative_else_nop_endif +#endif mte_set_kernel_gcr x22, x23 @@ -353,8 +375,26 @@ alternative_else_nop_endif 3: scs_save tsk, x0 - /* No kernel C function calls after this as user keys are set. */ - ptrauth_keys_install_user tsk, x0, x1, x2 +#ifdef CONFIG_ARM64_PTR_AUTH +alternative_if ARM64_HAS_ADDRESS_AUTH + /* + * IA was enabled for in-kernel PAC. Disable it now if needed, or + * alternatively install the user's IA. All other per-task keys and + * SCTLR bits were updated on task switch. + * + * No kernel C function calls after this. + */ + ldr x0, [tsk, THREAD_SCTLR_USER] + tbz x0, SCTLR_ELx_ENIA_SHIFT, 1f + __ptrauth_keys_install_user tsk, x0, x1, x2 + b 2f +1: + mrs x0, sctlr_el1 + bic x0, x0, SCTLR_ELx_ENIA + msr sctlr_el1, x0 +2: +alternative_else_nop_endif +#endif mte_set_user_gcr tsk, x0, x1 @@ -493,28 +533,14 @@ tsk .req x28 // current thread_info /* * Interrupt handling. */ - .macro irq_handler - ldr_l x1, handle_arch_irq + .macro irq_handler, handler:req + ldr_l x1, \handler mov x0, sp irq_stack_entry blr x1 irq_stack_exit .endm -#ifdef CONFIG_ARM64_PSEUDO_NMI - /* - * Set res to 0 if irqs were unmasked in interrupted context. - * Otherwise set res to non-0 value. - */ - .macro test_irqs_unmasked res:req, pmr:req -alternative_if ARM64_HAS_IRQ_PRIO_MASKING - sub \res, \pmr, #GIC_PRIO_IRQON -alternative_else - mov \res, xzr -alternative_endif - .endm -#endif - .macro gic_prio_kentry_setup, tmp:req #ifdef CONFIG_ARM64_PSEUDO_NMI alternative_if ARM64_HAS_IRQ_PRIO_MASKING @@ -533,6 +559,47 @@ alternative_endif #endif .endm + .macro el1_interrupt_handler, handler:req + gic_prio_irq_setup pmr=x20, tmp=x1 + enable_da + + mov x0, sp + bl enter_el1_irq_or_nmi + + irq_handler \handler + +#ifdef CONFIG_PREEMPTION + ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count +alternative_if ARM64_HAS_IRQ_PRIO_MASKING + /* + * DA were cleared at start of handling, and IF are cleared by + * the GIC irqchip driver using gic_arch_enable_irqs() for + * normal IRQs. If anything is set, it means we come back from + * an NMI instead of a normal IRQ, so skip preemption + */ + mrs x0, daif + orr x24, x24, x0 +alternative_else_nop_endif + cbnz x24, 1f // preempt count != 0 || NMI return path + bl arm64_preempt_schedule_irq // irq en/disable is done inside +1: +#endif + + mov x0, sp + bl exit_el1_irq_or_nmi + .endm + + .macro el0_interrupt_handler, handler:req + gic_prio_irq_setup pmr=x20, tmp=x0 + user_exit_irqoff + enable_da + + tbz x22, #55, 1f + bl do_el0_irq_bp_hardening +1: + irq_handler \handler + .endm + .text /* @@ -549,18 +616,18 @@ SYM_CODE_START(vectors) kernel_ventry 1, sync // Synchronous EL1h kernel_ventry 1, irq // IRQ EL1h - kernel_ventry 1, fiq_invalid // FIQ EL1h + kernel_ventry 1, fiq // FIQ EL1h kernel_ventry 1, error // Error EL1h kernel_ventry 0, sync // Synchronous 64-bit EL0 kernel_ventry 0, irq // IRQ 64-bit EL0 - kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 + kernel_ventry 0, fiq // FIQ 64-bit EL0 kernel_ventry 0, error // Error 64-bit EL0 #ifdef CONFIG_COMPAT kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 - kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 + kernel_ventry 0, fiq_compat, 32 // FIQ 32-bit EL0 kernel_ventry 0, error_compat, 32 // Error 32-bit EL0 #else kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 @@ -626,12 +693,6 @@ SYM_CODE_START_LOCAL(el0_error_invalid) inv_entry 0, BAD_ERROR SYM_CODE_END(el0_error_invalid) -#ifdef CONFIG_COMPAT -SYM_CODE_START_LOCAL(el0_fiq_invalid_compat) - inv_entry 0, BAD_FIQ, 32 -SYM_CODE_END(el0_fiq_invalid_compat) -#endif - SYM_CODE_START_LOCAL(el1_sync_invalid) inv_entry 1, BAD_SYNC SYM_CODE_END(el1_sync_invalid) @@ -662,35 +723,16 @@ SYM_CODE_END(el1_sync) .align 6 SYM_CODE_START_LOCAL_NOALIGN(el1_irq) kernel_entry 1 - gic_prio_irq_setup pmr=x20, tmp=x1 - enable_da_f - - mov x0, sp - bl enter_el1_irq_or_nmi - - irq_handler - -#ifdef CONFIG_PREEMPTION - ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count -alternative_if ARM64_HAS_IRQ_PRIO_MASKING - /* - * DA_F were cleared at start of handling. If anything is set in DAIF, - * we come back from an NMI, so skip preemption - */ - mrs x0, daif - orr x24, x24, x0 -alternative_else_nop_endif - cbnz x24, 1f // preempt count != 0 || NMI return path - bl arm64_preempt_schedule_irq // irq en/disable is done inside -1: -#endif - - mov x0, sp - bl exit_el1_irq_or_nmi - + el1_interrupt_handler handle_arch_irq kernel_exit 1 SYM_CODE_END(el1_irq) +SYM_CODE_START_LOCAL_NOALIGN(el1_fiq) + kernel_entry 1 + el1_interrupt_handler handle_arch_fiq + kernel_exit 1 +SYM_CODE_END(el1_fiq) + /* * EL0 mode handlers. */ @@ -717,6 +759,11 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat) b el0_irq_naked SYM_CODE_END(el0_irq_compat) +SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat) + kernel_entry 0, 32 + b el0_fiq_naked +SYM_CODE_END(el0_fiq_compat) + SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat) kernel_entry 0, 32 b el0_error_naked @@ -727,18 +774,17 @@ SYM_CODE_END(el0_error_compat) SYM_CODE_START_LOCAL_NOALIGN(el0_irq) kernel_entry 0 el0_irq_naked: - gic_prio_irq_setup pmr=x20, tmp=x0 - user_exit_irqoff - enable_da_f - - tbz x22, #55, 1f - bl do_el0_irq_bp_hardening -1: - irq_handler - + el0_interrupt_handler handle_arch_irq b ret_to_user SYM_CODE_END(el0_irq) +SYM_CODE_START_LOCAL_NOALIGN(el0_fiq) + kernel_entry 0 +el0_fiq_naked: + el0_interrupt_handler handle_arch_fiq + b ret_to_user +SYM_CODE_END(el0_fiq) + SYM_CODE_START_LOCAL(el1_error) kernel_entry 1 mrs x1, esr_el1 @@ -759,7 +805,7 @@ el0_error_naked: mov x0, sp mov x1, x25 bl do_serror - enable_da_f + enable_da b ret_to_user SYM_CODE_END(el0_error) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 062b21f30f9422aa03d6cf0eb8cc56e2ba8032d9..ad3dd34a83cf98db4593c4a406728aecd75bc96e 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -180,7 +180,7 @@ static void __get_cpu_fpsimd_context(void) */ static void get_cpu_fpsimd_context(void) { - preempt_disable(); + local_bh_disable(); __get_cpu_fpsimd_context(); } @@ -201,7 +201,7 @@ static void __put_cpu_fpsimd_context(void) static void put_cpu_fpsimd_context(void) { __put_cpu_fpsimd_context(); - preempt_enable(); + local_bh_enable(); } static bool have_cpu_fpsimd_context(void) @@ -285,7 +285,7 @@ static void task_fpsimd_load(void) WARN_ON(!system_supports_fpsimd()); WARN_ON(!have_cpu_fpsimd_context()); - if (system_supports_sve() && test_thread_flag(TIF_SVE)) + if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) sve_load_state(sve_pffr(¤t->thread), ¤t->thread.uw.fpsimd_state.fpsr, sve_vq_from_vl(current->thread.sve_vl) - 1); @@ -307,7 +307,8 @@ static void fpsimd_save(void) WARN_ON(!have_cpu_fpsimd_context()); if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) { - if (system_supports_sve() && test_thread_flag(TIF_SVE)) { + if (IS_ENABLED(CONFIG_ARM64_SVE) && + test_thread_flag(TIF_SVE)) { if (WARN_ON(sve_get_vl() != last->sve_vl)) { /* * Can't save the user regs, so current would @@ -926,9 +927,8 @@ void fpsimd_release_task(struct task_struct *dead_task) * Trapped SVE access * * Storage is allocated for the full SVE state, the current FPSIMD - * register contents are migrated across, and TIF_SVE is set so that - * the SVE access trap will be disabled the next time this task - * reaches ret_to_user. + * register contents are migrated across, and the access trap is + * disabled. * * TIF_SVE should be clear on entry: otherwise, fpsimd_restore_current_state() * would have disabled the SVE access trap for userspace during @@ -946,15 +946,24 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs) get_cpu_fpsimd_context(); - fpsimd_save(); - - /* Force ret_to_user to reload the registers: */ - fpsimd_flush_task_state(current); - - fpsimd_to_sve(current); if (test_and_set_thread_flag(TIF_SVE)) WARN_ON(1); /* SVE access shouldn't have trapped */ + /* + * Convert the FPSIMD state to SVE, zeroing all the state that + * is not shared with FPSIMD. If (as is likely) the current + * state is live in the registers then do this there and + * update our metadata for the current task including + * disabling the trap, otherwise update our in-memory copy. + */ + if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) { + sve_set_vq(sve_vq_from_vl(current->thread.sve_vl) - 1); + sve_flush_live(); + fpsimd_bind_task_to_cpu(); + } else { + fpsimd_to_sve(current); + } + put_cpu_fpsimd_context(); } @@ -1092,7 +1101,7 @@ void fpsimd_preserve_current_state(void) void fpsimd_signal_preserve_current_state(void) { fpsimd_preserve_current_state(); - if (system_supports_sve() && test_thread_flag(TIF_SVE)) + if (test_thread_flag(TIF_SVE)) sve_to_fpsimd(current); } @@ -1181,7 +1190,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state) get_cpu_fpsimd_context(); current->thread.uw.fpsimd_state = *state; - if (system_supports_sve() && test_thread_flag(TIF_SVE)) + if (test_thread_flag(TIF_SVE)) fpsimd_to_sve(current); task_fpsimd_load(); diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c index 86a5cf9bc19a1e8ac7d47f529fc2492d072857bc..b5d3ddaf69d9e9b0c58c5ae1bf21fdb80b364b99 100644 --- a/arch/arm64/kernel/ftrace.c +++ b/arch/arm64/kernel/ftrace.c @@ -55,7 +55,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) unsigned long pc; u32 new; - pc = (unsigned long)&ftrace_call; + pc = (unsigned long)function_nocfi(ftrace_call); new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func, AARCH64_INSN_BRANCH_LINK); diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 840bda1869e9ccb0d88b2e6bb0cb63ea1eb1f0c6..96873dfa67fd5214dca48d68a98483b6b1bf9d2c 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -477,14 +477,13 @@ EXPORT_SYMBOL(kimage_vaddr) * booted in EL1 or EL2 respectively. */ SYM_FUNC_START(init_kernel_el) - mov_q x0, INIT_SCTLR_EL1_MMU_OFF - msr sctlr_el1, x0 - mrs x0, CurrentEL cmp x0, #CurrentEL_EL2 b.eq init_el2 SYM_INNER_LABEL(init_el1, SYM_L_LOCAL) + mov_q x0, INIT_SCTLR_EL1_MMU_OFF + msr sctlr_el1, x0 isb mov_q x0, INIT_PSTATE_EL1 msr spsr_el1, x0 @@ -504,9 +503,43 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) msr vbar_el2, x0 isb + /* + * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, + * making it impossible to start in nVHE mode. Is that + * compliant with the architecture? Absolutely not! + */ + mrs x0, hcr_el2 + and x0, x0, #HCR_E2H + cbz x0, 1f + + /* Switching to VHE requires a sane SCTLR_EL1 as a start */ + mov_q x0, INIT_SCTLR_EL1_MMU_OFF + msr_s SYS_SCTLR_EL12, x0 + + /* + * Force an eret into a helper "function", and let it return + * to our original caller... This makes sure that we have + * initialised the basic PSTATE state. + */ + mov x0, #INIT_PSTATE_EL2 + msr spsr_el1, x0 + adr x0, __cpu_stick_to_vhe + msr elr_el1, x0 + eret + +1: + mov_q x0, INIT_SCTLR_EL1_MMU_OFF + msr sctlr_el1, x0 + msr elr_el2, lr mov w0, #BOOT_CPU_MODE_EL2 eret + +__cpu_stick_to_vhe: + mov x0, #HVC_VHE_RESTART + hvc #0 + mov x0, #BOOT_CPU_MODE_EL2 + ret SYM_FUNC_END(init_kernel_el) /* diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S index 5eccbd62fec8a84fd35dc715a2f81e907847ea3b..74ad3db061d13c7377bc55f7e3789629c98ccfec 100644 --- a/arch/arm64/kernel/hyp-stub.S +++ b/arch/arm64/kernel/hyp-stub.S @@ -27,12 +27,12 @@ SYM_CODE_START(__hyp_stub_vectors) ventry el2_fiq_invalid // FIQ EL2t ventry el2_error_invalid // Error EL2t - ventry el2_sync_invalid // Synchronous EL2h + ventry elx_sync // Synchronous EL2h ventry el2_irq_invalid // IRQ EL2h ventry el2_fiq_invalid // FIQ EL2h ventry el2_error_invalid // Error EL2h - ventry el1_sync // Synchronous 64-bit EL1 + ventry elx_sync // Synchronous 64-bit EL1 ventry el1_irq_invalid // IRQ 64-bit EL1 ventry el1_fiq_invalid // FIQ 64-bit EL1 ventry el1_error_invalid // Error 64-bit EL1 @@ -45,7 +45,7 @@ SYM_CODE_END(__hyp_stub_vectors) .align 11 -SYM_CODE_START_LOCAL(el1_sync) +SYM_CODE_START_LOCAL(elx_sync) cmp x0, #HVC_SET_VECTORS b.ne 1f msr vbar_el2, x1 @@ -71,7 +71,7 @@ SYM_CODE_START_LOCAL(el1_sync) 9: mov x0, xzr eret -SYM_CODE_END(el1_sync) +SYM_CODE_END(elx_sync) // nVHE? No way! Give me the real thing! SYM_CODE_START_LOCAL(mutate_to_vhe) @@ -224,7 +224,6 @@ SYM_FUNC_END(__hyp_reset_vectors) * Entry point to switch to VHE if deemed capable */ SYM_FUNC_START(switch_to_vhe) -#ifdef CONFIG_ARM64_VHE // Need to have booted at EL2 adr_l x1, __boot_cpu_mode ldr w0, [x1] @@ -240,6 +239,5 @@ SYM_FUNC_START(switch_to_vhe) mov x0, #HVC_VHE_RESTART hvc #0 1: -#endif ret SYM_FUNC_END(switch_to_vhe) diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c index 83f1c4b92095e9a6acf0c2eac454f965228bf040..e628c8ce1ffe2f6976fd20233f75632d73ce42c4 100644 --- a/arch/arm64/kernel/idreg-override.c +++ b/arch/arm64/kernel/idreg-override.c @@ -25,14 +25,26 @@ struct ftr_set_desc { struct { char name[FTR_DESC_FIELD_LEN]; u8 shift; + bool (*filter)(u64 val); } fields[]; }; +static bool __init mmfr1_vh_filter(u64 val) +{ + /* + * If we ever reach this point while running VHE, we're + * guaranteed to be on one of these funky, VHE-stuck CPUs. If + * the user was trying to force nVHE on us, proceed with + * attitude adjustment. + */ + return !(is_kernel_in_hyp_mode() && val == 0); +} + static const struct ftr_set_desc mmfr1 __initconst = { .name = "id_aa64mmfr1", .override = &id_aa64mmfr1_override, .fields = { - { "vh", ID_AA64MMFR1_VHE_SHIFT }, + { "vh", ID_AA64MMFR1_VHE_SHIFT, mmfr1_vh_filter }, {} }, }; @@ -124,6 +136,18 @@ static void __init match_options(const char *cmdline) if (find_field(cmdline, regs[i], f, &v)) continue; + /* + * If an override gets filtered out, advertise + * it by setting the value to 0xf, but + * clearing the mask... Yes, this is fragile. + */ + if (regs[i]->fields[f].filter && + !regs[i]->fields[f].filter(v)) { + regs[i]->override->val |= mask; + regs[i]->override->mask &= ~mask; + continue; + } + regs[i]->override->val &= ~mask; regs[i]->override->val |= (v << shift) & mask; regs[i]->override->mask |= mask; diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index dfb1feab867d43b7fd5ea029b3f69d9bbf873907..bda49430c9ea3c9beb0669689e760bc6bd26c3ce 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -71,13 +71,44 @@ static void init_irq_stacks(void) } #endif +static void default_handle_irq(struct pt_regs *regs) +{ + panic("IRQ taken without a root IRQ handler\n"); +} + +static void default_handle_fiq(struct pt_regs *regs) +{ + panic("FIQ taken without a root FIQ handler\n"); +} + +void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq; +void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq; + +int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) +{ + if (handle_arch_irq != default_handle_irq) + return -EBUSY; + + handle_arch_irq = handle_irq; + pr_info("Root IRQ handler: %ps\n", handle_irq); + return 0; +} + +int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *)) +{ + if (handle_arch_fiq != default_handle_fiq) + return -EBUSY; + + handle_arch_fiq = handle_fiq; + pr_info("Root FIQ handler: %ps\n", handle_fiq); + return 0; +} + void __init init_IRQ(void) { init_irq_stacks(); init_irq_scs(); irqchip_init(); - if (!handle_arch_irq) - panic("No interrupt controller found."); if (system_uses_irq_prio_masking()) { /* diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c index 27f8939deb1b322839e9b09195adcdfd3b5ce7e1..341342b207f63286db6db7c48b72fe7629c12b9e 100644 --- a/arch/arm64/kernel/kaslr.c +++ b/arch/arm64/kernel/kaslr.c @@ -128,15 +128,17 @@ u64 __init kaslr_early_init(void) /* use the top 16 bits to randomize the linear region */ memstart_offset_seed = seed >> 48; - if (IS_ENABLED(CONFIG_KASAN_GENERIC) || - IS_ENABLED(CONFIG_KASAN_SW_TAGS)) + if (!IS_ENABLED(CONFIG_KASAN_VMALLOC) && + (IS_ENABLED(CONFIG_KASAN_GENERIC) || + IS_ENABLED(CONFIG_KASAN_SW_TAGS))) /* - * KASAN does not expect the module region to intersect the - * vmalloc region, since shadow memory is allocated for each - * module at load time, whereas the vmalloc region is shadowed - * by KASAN zero pages. So keep modules out of the vmalloc - * region if KASAN is enabled, and put the kernel well within - * 4 GB of the module region. + * KASAN without KASAN_VMALLOC does not expect the module region + * to intersect the vmalloc region, since shadow memory is + * allocated for each module at load time, whereas the vmalloc + * region is shadowed by KASAN zero pages. So keep modules + * out of the vmalloc region if KASAN is enabled without + * KASAN_VMALLOC, and put the kernel well within 4 GB of the + * module region. */ return offset % SZ_2G; diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index fe21e0f06492ee5e4328288b191e25d08ef28d08..b5ec010c481f37c87c5d977a870a955ca86377af 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -40,14 +40,16 @@ void *module_alloc(unsigned long size) NUMA_NO_NODE, __builtin_return_address(0)); if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && - !IS_ENABLED(CONFIG_KASAN_GENERIC) && - !IS_ENABLED(CONFIG_KASAN_SW_TAGS)) + (IS_ENABLED(CONFIG_KASAN_VMALLOC) || + (!IS_ENABLED(CONFIG_KASAN_GENERIC) && + !IS_ENABLED(CONFIG_KASAN_SW_TAGS)))) /* - * KASAN can only deal with module allocations being served - * from the reserved module region, since the remainder of - * the vmalloc region is already backed by zero shadow pages, - * and punching holes into it is non-trivial. Since the module - * region is not randomized when KASAN is enabled, it is even + * KASAN without KASAN_VMALLOC can only deal with module + * allocations being served from the reserved module region, + * since the remainder of the vmalloc region is already + * backed by zero shadow pages, and punching holes into it + * is non-trivial. Since the module region is not randomized + * when KASAN is enabled without KASAN_VMALLOC, it is even * less likely that the module region gets exhausted, so we * can simply omit this fallback in that case. */ diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c index b3c70a612c7a93324b735559853069320519dd94..125a10e413e9f2967b7cbc56fb355924020d66e0 100644 --- a/arch/arm64/kernel/mte.c +++ b/arch/arm64/kernel/mte.c @@ -26,6 +26,12 @@ u64 gcr_kernel_excl __ro_after_init; static bool report_fault_once = true; +#ifdef CONFIG_KASAN_HW_TAGS +/* Whether the MTE asynchronous mode is enabled. */ +DEFINE_STATIC_KEY_FALSE(mte_async_mode); +EXPORT_SYMBOL_GPL(mte_async_mode); +#endif + static void mte_sync_page_tags(struct page *page, pte_t *ptep, bool check_swap) { pte_t old_pte = READ_ONCE(*ptep); @@ -107,13 +113,45 @@ void mte_init_tags(u64 max_tag) write_sysreg_s(SYS_GCR_EL1_RRND | gcr_kernel_excl, SYS_GCR_EL1); } -void mte_enable_kernel(void) +static inline void __mte_enable_kernel(const char *mode, unsigned long tcf) { /* Enable MTE Sync Mode for EL1. */ - sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC); + sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, tcf); isb(); + + pr_info_once("MTE: enabled in %s mode at EL1\n", mode); +} + +#ifdef CONFIG_KASAN_HW_TAGS +void mte_enable_kernel_sync(void) +{ + /* + * Make sure we enter this function when no PE has set + * async mode previously. + */ + WARN_ONCE(system_uses_mte_async_mode(), + "MTE async mode enabled system wide!"); + + __mte_enable_kernel("synchronous", SCTLR_ELx_TCF_SYNC); } +void mte_enable_kernel_async(void) +{ + __mte_enable_kernel("asynchronous", SCTLR_ELx_TCF_ASYNC); + + /* + * MTE async mode is set system wide by the first PE that + * executes this function. + * + * Note: If in future KASAN acquires a runtime switching + * mode in between sync and async, this strategy needs + * to be reviewed. + */ + if (!system_uses_mte_async_mode()) + static_branch_enable(&mte_async_mode); +} +#endif + void mte_set_report_once(bool state) { WRITE_ONCE(report_fault_once, state); @@ -124,25 +162,28 @@ bool mte_report_once(void) return READ_ONCE(report_fault_once); } -static void update_sctlr_el1_tcf0(u64 tcf0) +#ifdef CONFIG_KASAN_HW_TAGS +void mte_check_tfsr_el1(void) { - /* ISB required for the kernel uaccess routines */ - sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF0_MASK, tcf0); - isb(); -} + u64 tfsr_el1; -static void set_sctlr_el1_tcf0(u64 tcf0) -{ - /* - * mte_thread_switch() checks current->thread.sctlr_tcf0 as an - * optimisation. Disable preemption so that it does not see - * the variable update before the SCTLR_EL1.TCF0 one. - */ - preempt_disable(); - current->thread.sctlr_tcf0 = tcf0; - update_sctlr_el1_tcf0(tcf0); - preempt_enable(); + if (!system_supports_mte()) + return; + + tfsr_el1 = read_sysreg_s(SYS_TFSR_EL1); + + if (unlikely(tfsr_el1 & SYS_TFSR_EL1_TF1)) { + /* + * Note: isb() is not required after this direct write + * because there is no indirect read subsequent to it + * (per ARM DDI 0487F.c table D13-1). + */ + write_sysreg_s(0, SYS_TFSR_EL1); + + kasan_report_async(); + } } +#endif static void update_gcr_el1_excl(u64 excl) { @@ -166,7 +207,7 @@ static void set_gcr_el1_excl(u64 excl) */ } -void flush_mte_state(void) +void mte_thread_init_user(void) { if (!system_supports_mte()) return; @@ -176,19 +217,39 @@ void flush_mte_state(void) write_sysreg_s(0, SYS_TFSRE0_EL1); clear_thread_flag(TIF_MTE_ASYNC_FAULT); /* disable tag checking */ - set_sctlr_el1_tcf0(SCTLR_EL1_TCF0_NONE); + set_task_sctlr_el1((current->thread.sctlr_user & ~SCTLR_EL1_TCF0_MASK) | + SCTLR_EL1_TCF0_NONE); /* reset tag generation mask */ set_gcr_el1_excl(SYS_GCR_EL1_EXCL_MASK); } void mte_thread_switch(struct task_struct *next) +{ + /* + * Check if an async tag exception occurred at EL1. + * + * Note: On the context switch path we rely on the dsb() present + * in __switch_to() to guarantee that the indirect writes to TFSR_EL1 + * are synchronized before this point. + */ + isb(); + mte_check_tfsr_el1(); +} + +void mte_suspend_enter(void) { if (!system_supports_mte()) return; - /* avoid expensive SCTLR_EL1 accesses if no change */ - if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0) - update_sctlr_el1_tcf0(next->thread.sctlr_tcf0); + /* + * The barriers are required to guarantee that the indirect writes + * to TFSR_EL1 are synchronized before we report the state. + */ + dsb(nsh); + isb(); + + /* Report SYS_TFSR_EL1 before suspend entry */ + mte_check_tfsr_el1(); } void mte_suspend_exit(void) @@ -201,7 +262,7 @@ void mte_suspend_exit(void) long set_mte_ctrl(struct task_struct *task, unsigned long arg) { - u64 tcf0; + u64 sctlr = task->thread.sctlr_user & ~SCTLR_EL1_TCF0_MASK; u64 gcr_excl = ~((arg & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT) & SYS_GCR_EL1_EXCL_MASK; @@ -210,23 +271,23 @@ long set_mte_ctrl(struct task_struct *task, unsigned long arg) switch (arg & PR_MTE_TCF_MASK) { case PR_MTE_TCF_NONE: - tcf0 = SCTLR_EL1_TCF0_NONE; + sctlr |= SCTLR_EL1_TCF0_NONE; break; case PR_MTE_TCF_SYNC: - tcf0 = SCTLR_EL1_TCF0_SYNC; + sctlr |= SCTLR_EL1_TCF0_SYNC; break; case PR_MTE_TCF_ASYNC: - tcf0 = SCTLR_EL1_TCF0_ASYNC; + sctlr |= SCTLR_EL1_TCF0_ASYNC; break; default: return -EINVAL; } if (task != current) { - task->thread.sctlr_tcf0 = tcf0; + task->thread.sctlr_user = sctlr; task->thread.gcr_user_excl = gcr_excl; } else { - set_sctlr_el1_tcf0(tcf0); + set_task_sctlr_el1(sctlr); set_gcr_el1_excl(gcr_excl); } @@ -243,7 +304,7 @@ long get_mte_ctrl(struct task_struct *task) ret = incl << PR_MTE_TAG_SHIFT; - switch (task->thread.sctlr_tcf0) { + switch (task->thread.sctlr_user & SCTLR_EL1_TCF0_MASK) { case SCTLR_EL1_TCF0_NONE: ret |= PR_MTE_TCF_NONE; break; diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c index c07d7a03494108a9a75fea9e9bb6b98830b3d0fa..75fed4460407dee05914177a86c234423a6efe54 100644 --- a/arch/arm64/kernel/paravirt.c +++ b/arch/arm64/kernel/paravirt.c @@ -18,6 +18,7 @@ #include <linux/reboot.h> #include <linux/slab.h> #include <linux/types.h> +#include <linux/static_call.h> #include <asm/paravirt.h> #include <asm/pvclock-abi.h> @@ -26,8 +27,12 @@ struct static_key paravirt_steal_enabled; struct static_key paravirt_steal_rq_enabled; -struct paravirt_patch_template pv_ops; -EXPORT_SYMBOL_GPL(pv_ops); +static u64 native_steal_clock(int cpu) +{ + return 0; +} + +DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); struct pv_time_stolen_time_region { struct pvclock_vcpu_stolen_time *kaddr; @@ -45,7 +50,7 @@ static int __init parse_no_stealacc(char *arg) early_param("no-steal-acc", parse_no_stealacc); /* return stolen time in ns by asking the hypervisor */ -static u64 pv_steal_clock(int cpu) +static u64 para_steal_clock(int cpu) { struct pv_time_stolen_time_region *reg; @@ -150,7 +155,7 @@ int __init pv_time_init(void) if (ret) return ret; - pv_ops.time.steal_clock = pv_steal_clock; + static_call_update(pv_steal_clock, para_steal_clock); static_key_slow_inc(¶virt_steal_enabled); if (steal_acc) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 4658fcf88c2b4ddff069e3f47858c6443eac0198..f594957e29bd1253fdfae7fdd8df6742033c122b 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -470,9 +470,8 @@ static inline u64 armv8pmu_read_evcntr(int idx) static inline u64 armv8pmu_read_hw_counter(struct perf_event *event) { int idx = event->hw.idx; - u64 val = 0; + u64 val = armv8pmu_read_evcntr(idx); - val = armv8pmu_read_evcntr(idx); if (armv8pmu_event_is_chained(event)) val = (val << 32) | armv8pmu_read_evcntr(idx - 1); return val; @@ -520,7 +519,7 @@ static u64 armv8pmu_read_counter(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - u64 value = 0; + u64 value; if (idx == ARMV8_IDX_CYCLE_COUNTER) value = read_sysreg(pmccntr_el0); diff --git a/arch/arm64/kernel/pointer_auth.c b/arch/arm64/kernel/pointer_auth.c index adb955fd9bdd9812e1ab29ac2735d8ea2b836997..60901ab0a7fe54f74dbe4eca272ef189390c9245 100644 --- a/arch/arm64/kernel/pointer_auth.c +++ b/arch/arm64/kernel/pointer_auth.c @@ -43,6 +43,69 @@ int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg) get_random_bytes(&keys->apdb, sizeof(keys->apdb)); if (arg & PR_PAC_APGAKEY) get_random_bytes(&keys->apga, sizeof(keys->apga)); + ptrauth_keys_install_user(keys); return 0; } + +static u64 arg_to_enxx_mask(unsigned long arg) +{ + u64 sctlr_enxx_mask = 0; + + WARN_ON(arg & ~PR_PAC_ENABLED_KEYS_MASK); + if (arg & PR_PAC_APIAKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENIA; + if (arg & PR_PAC_APIBKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENIB; + if (arg & PR_PAC_APDAKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENDA; + if (arg & PR_PAC_APDBKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENDB; + return sctlr_enxx_mask; +} + +int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys, + unsigned long enabled) +{ + u64 sctlr = tsk->thread.sctlr_user; + + if (!system_supports_address_auth()) + return -EINVAL; + + if (is_compat_thread(task_thread_info(tsk))) + return -EINVAL; + + if ((keys & ~PR_PAC_ENABLED_KEYS_MASK) || (enabled & ~keys)) + return -EINVAL; + + sctlr &= ~arg_to_enxx_mask(keys); + sctlr |= arg_to_enxx_mask(enabled); + if (tsk == current) + set_task_sctlr_el1(sctlr); + else + tsk->thread.sctlr_user = sctlr; + + return 0; +} + +int ptrauth_get_enabled_keys(struct task_struct *tsk) +{ + int retval = 0; + + if (!system_supports_address_auth()) + return -EINVAL; + + if (is_compat_thread(task_thread_info(tsk))) + return -EINVAL; + + if (tsk->thread.sctlr_user & SCTLR_ELx_ENIA) + retval |= PR_PAC_APIAKEY; + if (tsk->thread.sctlr_user & SCTLR_ELx_ENIB) + retval |= PR_PAC_APIBKEY; + if (tsk->thread.sctlr_user & SCTLR_ELx_ENDA) + retval |= PR_PAC_APDAKEY; + if (tsk->thread.sctlr_user & SCTLR_ELx_ENDB) + retval |= PR_PAC_APDBKEY; + + return retval; +} diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index 85645b2b0c7ab5ff4161039037c5d787d5db8b5e..d607c9912025219469d1946b1ea6ac56128d8cc3 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -264,8 +264,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr) * normal page fault. */ instruction_pointer_set(regs, (unsigned long) cur->addr); - if (!instruction_pointer(regs)) - BUG(); + BUG_ON(!instruction_pointer(regs)); if (kcb->kprobe_status == KPROBE_REENTER) { restore_previous_kprobe(kcb); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index a6798da5427b400fefc17888140a9ed872c19001..8293d81cf73b8d7774e0501f27887df4bbb19f4a 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -86,7 +86,7 @@ static void noinstr __cpu_do_idle_irqprio(void) unsigned long daif_bits; daif_bits = read_sysreg(daif); - write_sysreg(daif_bits | PSR_I_BIT, daif); + write_sysreg(daif_bits | PSR_I_BIT | PSR_F_BIT, daif); /* * Unmask PMR before going idle to make sure interrupts can @@ -339,7 +339,6 @@ void flush_thread(void) tls_thread_flush(); flush_ptrace_hw_breakpoint(current); flush_tagged_addr_state(); - flush_mte_state(); } void release_thread(struct task_struct *dead_task) @@ -529,6 +528,31 @@ static void erratum_1418040_thread_switch(struct task_struct *prev, write_sysreg(val, cntkctl_el1); } +static void update_sctlr_el1(u64 sctlr) +{ + /* + * EnIA must not be cleared while in the kernel as this is necessary for + * in-kernel PAC. It will be cleared on kernel exit if needed. + */ + sysreg_clear_set(sctlr_el1, SCTLR_USER_MASK & ~SCTLR_ELx_ENIA, sctlr); + + /* ISB required for the kernel uaccess routines when setting TCF0. */ + isb(); +} + +void set_task_sctlr_el1(u64 sctlr) +{ + /* + * __switch_to() checks current->thread.sctlr as an + * optimisation. Disable preemption so that it does not see + * the variable update before the SCTLR_EL1 one. + */ + preempt_disable(); + current->thread.sctlr_user = sctlr; + update_sctlr_el1(sctlr); + preempt_enable(); +} + /* * Thread switching. */ @@ -544,6 +568,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev, entry_task_switch(next); ssbs_thread_switch(next); erratum_1418040_thread_switch(prev, next); + ptrauth_thread_switch_user(next); /* * vendor hook is needed before the dsb(), * because MPAM is related to cache maintenance. @@ -564,6 +589,9 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev, * registers. */ mte_thread_switch(next); + /* avoid expensive SCTLR_EL1 accesses if no change */ + if (prev->thread.sctlr_user != next->thread.sctlr_user) + update_sctlr_el1(next->thread.sctlr_user); trace_android_vh_is_fpsimd_save(prev, next); @@ -615,7 +643,8 @@ void arch_setup_new_exec(void) { current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0; - ptrauth_thread_init_user(current); + ptrauth_thread_init_user(); + mte_thread_init_user(); if (task_spec_ssb_noexec(current)) { arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS, diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 62d2bda7adb807010439282fc956e63a5d269095..ab7f4c4761046a38adfaec8dcfe38db5db405210 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -38,7 +38,8 @@ static int __init cpu_psci_cpu_prepare(unsigned int cpu) static int cpu_psci_cpu_boot(unsigned int cpu) { - int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry)); + phys_addr_t pa_secondary_entry = __pa_symbol(function_nocfi(secondary_entry)); + int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry); if (err) pr_err("failed to boot CPU%d (%d)\n", cpu, err); diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 170f42fd6101a8cb9e9781064bfe7ded6c2a0ce2..eb2f73939b7bbbaf7feb4a5cb98dd127ad3c7a9b 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -909,6 +909,38 @@ static int pac_mask_get(struct task_struct *target, return membuf_write(&to, &uregs, sizeof(uregs)); } +static int pac_enabled_keys_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + long enabled_keys = ptrauth_get_enabled_keys(target); + + if (IS_ERR_VALUE(enabled_keys)) + return enabled_keys; + + return membuf_write(&to, &enabled_keys, sizeof(enabled_keys)); +} + +static int pac_enabled_keys_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 enabled_keys = ptrauth_get_enabled_keys(target); + + if (IS_ERR_VALUE(enabled_keys)) + return enabled_keys; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &enabled_keys, 0, + sizeof(long)); + if (ret) + return ret; + + return ptrauth_set_enabled_keys(target, PR_PAC_ENABLED_KEYS_MASK, + enabled_keys); +} + #ifdef CONFIG_CHECKPOINT_RESTORE static __uint128_t pac_key_to_user(const struct ptrauth_key *key) { @@ -1074,6 +1106,7 @@ enum aarch64_regset { #endif #ifdef CONFIG_ARM64_PTR_AUTH REGSET_PAC_MASK, + REGSET_PAC_ENABLED_KEYS, #ifdef CONFIG_CHECKPOINT_RESTORE REGSET_PACA_KEYS, REGSET_PACG_KEYS, @@ -1160,6 +1193,14 @@ static const struct user_regset aarch64_regsets[] = { .regset_get = pac_mask_get, /* this cannot be set dynamically */ }, + [REGSET_PAC_ENABLED_KEYS] = { + .core_note_type = NT_ARM_PAC_ENABLED_KEYS, + .n = 1, + .size = sizeof(long), + .align = sizeof(long), + .regset_get = pac_enabled_keys_get, + .set = pac_enabled_keys_set, + }, #ifdef CONFIG_CHECKPOINT_RESTORE [REGSET_PACA_KEYS] = { .core_note_type = NT_ARM_PACA_KEYS, diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 327188ab29075ce6c3ec071a292a15a58dbddca8..696e4b1a91bfb902e57721b1da512a380cd5faf0 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -193,6 +193,7 @@ static void init_gic_priority_masking(void) cpuflags = read_sysreg(daif); WARN_ON(!(cpuflags & PSR_I_BIT)); + WARN_ON(!(cpuflags & PSR_F_BIT)); gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); } diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c index 056772c2609851bf7ec93cdb0db0292f9c5904a3..c45a835128057ac6f904e9770138005c08efdfbb 100644 --- a/arch/arm64/kernel/smp_spin_table.c +++ b/arch/arm64/kernel/smp_spin_table.c @@ -66,6 +66,7 @@ static int smp_spin_table_cpu_init(unsigned int cpu) static int smp_spin_table_cpu_prepare(unsigned int cpu) { __le64 __iomem *release_addr; + phys_addr_t pa_holding_pen = __pa_symbol(function_nocfi(secondary_holding_pen)); if (!cpu_release_addr[cpu]) return -ENODEV; @@ -88,7 +89,7 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu) * boot-loader's endianness before jumping. This is mandated by * the boot protocol. */ - writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr); + writeq_relaxed(pa_holding_pen, release_addr); __flush_dcache_area((__force void *)release_addr, sizeof(*release_addr)); diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 7dfe6e81773a20b85a8c054e9fa8bfdafe7f9f36..6eb701bfc57eed6ded17ac8b3d84efc376aee888 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -32,6 +32,30 @@ * add sp, sp, #0x10 */ + +void start_backtrace(struct stackframe *frame, unsigned long fp, + unsigned long pc) +{ + frame->fp = fp; + frame->pc = pc; +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + frame->graph = 0; +#endif + + /* + * Prime the first unwind. + * + * In unwind_frame() we'll check that the FP points to a valid stack, + * which can't be STACK_TYPE_UNKNOWN, and the first unwind will be + * treated as a transition to whichever stack that happens to be. The + * prev_fp value won't be used, but we set it to 0 such that it is + * definitely not an accessible stack address. + */ + bitmap_zero(frame->stacks_done, __NR_STACK_TYPES); + frame->prev_fp = 0; + frame->prev_type = STACK_TYPE_UNKNOWN; +} + /* * Unwind from one frame record (A) to the next frame record (B). * diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index d7564891ffe12f656d80f76363821870886c7ad6..e3f72df9509d72e18b192aa106dec182ace45293 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -74,8 +74,9 @@ void notrace __cpu_suspend_exit(void) */ spectre_v4_enable_mitigation(NULL); - /* Restore additional MTE-specific configuration */ + /* Restore additional feature-specific configuration */ mte_suspend_exit(); + ptrauth_suspend_exit(); } /* @@ -91,6 +92,9 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) unsigned long flags; struct sleep_stack_data state; + /* Report any MTE async fault before going to suspend */ + mte_suspend_enter(); + /* * From this point debug exceptions are disabled to prevent * updates to mdscr register (saved and restored along with diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c index b9cf12b271d79a8fc8896960f2581a16d139adf4..263d6c1a525f3d6d06c944917454d4178fc3515c 100644 --- a/arch/arm64/kernel/syscall.c +++ b/arch/arm64/kernel/syscall.c @@ -5,6 +5,7 @@ #include <linux/errno.h> #include <linux/nospec.h> #include <linux/ptrace.h> +#include <linux/randomize_kstack.h> #include <linux/syscalls.h> #include <asm/daifflags.h> @@ -43,6 +44,8 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno, { long ret; + add_random_kstack_offset(); + if (scno < sc_nr) { syscall_fn_t syscall_fn; syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)]; @@ -55,6 +58,19 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno, ret = lower_32_bits(ret); regs->regs[0] = ret; + + /* + * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(), + * but not enough for arm64 stack utilization comfort. To keep + * reasonable stack head room, reduce the maximum offset to 9 bits. + * + * The actual entropy will be further reduced by the compiler when + * applying stack alignment constraints: the AAPCS mandates a + * 16-byte (i.e. 4-bit) aligned SP at function boundaries. + * + * The resulting 5 bits of entropy is seen in SP[8:4]. + */ + choose_random_kstack_offset(get_random_int() & 0x1FF); } static inline bool has_syscall_work(unsigned long flags) diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index e08a4126453a2ce50f150d0ec95ce0d868fb26dd..4dd14a6620c176e969962f6854d63538ae265394 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -199,12 +199,47 @@ static int freq_inv_set_max_ratio(int cpu, u64 max_rate, u64 ref_rate) return 0; } -static DEFINE_STATIC_KEY_FALSE(amu_fie_key); -#define amu_freq_invariant() static_branch_unlikely(&amu_fie_key) +static void amu_scale_freq_tick(void) +{ + u64 prev_core_cnt, prev_const_cnt; + u64 core_cnt, const_cnt, scale; + + prev_const_cnt = this_cpu_read(arch_const_cycles_prev); + prev_core_cnt = this_cpu_read(arch_core_cycles_prev); + + update_freq_counters_refs(); + + const_cnt = this_cpu_read(arch_const_cycles_prev); + core_cnt = this_cpu_read(arch_core_cycles_prev); + + if (unlikely(core_cnt <= prev_core_cnt || + const_cnt <= prev_const_cnt)) + return; + + /* + * /\core arch_max_freq_scale + * scale = ------- * -------------------- + * /\const SCHED_CAPACITY_SCALE + * + * See validate_cpu_freq_invariance_counters() for details on + * arch_max_freq_scale and the use of SCHED_CAPACITY_SHIFT. + */ + scale = core_cnt - prev_core_cnt; + scale *= this_cpu_read(arch_max_freq_scale); + scale = div64_u64(scale >> SCHED_CAPACITY_SHIFT, + const_cnt - prev_const_cnt); + + scale = min_t(unsigned long, scale, SCHED_CAPACITY_SCALE); + this_cpu_write(arch_freq_scale, (unsigned long)scale); +} + +static struct scale_freq_data amu_sfd = { + .source = SCALE_FREQ_SOURCE_ARCH, + .set_freq_scale = amu_scale_freq_tick, +}; static void amu_fie_setup(const struct cpumask *cpus) { - bool invariant; int cpu; /* We are already set since the last insmod of cpufreq driver */ @@ -221,25 +256,10 @@ static void amu_fie_setup(const struct cpumask *cpus) cpumask_or(amu_fie_cpus, amu_fie_cpus, cpus); - invariant = topology_scale_freq_invariant(); - - /* We aren't fully invariant yet */ - if (!invariant && !cpumask_equal(amu_fie_cpus, cpu_present_mask)) - return; - - static_branch_enable(&amu_fie_key); + topology_set_scale_freq_source(&amu_sfd, amu_fie_cpus); pr_debug("CPUs[%*pbl]: counters will be used for FIE.", cpumask_pr_args(cpus)); - - /* - * Task scheduler behavior depends on frequency invariance support, - * either cpufreq or counter driven. If the support status changes as - * a result of counter initialisation and use, retrigger the build of - * scheduling domains to ensure the information is propagated properly. - */ - if (!invariant) - rebuild_sched_domains_energy(); } static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val, @@ -256,8 +276,8 @@ static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val, * initialized AMU support and enabled invariance. The AMU counters will * keep on working just fine in the absence of the cpufreq driver, and * for the CPUs for which there are no counters available, the last set - * value of freq_scale will remain valid as that is the frequency those - * CPUs are running at. + * value of arch_freq_scale will remain valid as that is the frequency + * those CPUs are running at. */ return 0; @@ -283,53 +303,6 @@ static int __init init_amu_fie(void) } core_initcall(init_amu_fie); -bool arch_freq_counters_available(const struct cpumask *cpus) -{ - return amu_freq_invariant() && - cpumask_subset(cpus, amu_fie_cpus); -} - -void topology_scale_freq_tick(void) -{ - u64 prev_core_cnt, prev_const_cnt; - u64 core_cnt, const_cnt, scale; - int cpu = smp_processor_id(); - - if (!amu_freq_invariant()) - return; - - if (!cpumask_test_cpu(cpu, amu_fie_cpus)) - return; - - prev_const_cnt = this_cpu_read(arch_const_cycles_prev); - prev_core_cnt = this_cpu_read(arch_core_cycles_prev); - - update_freq_counters_refs(); - - const_cnt = this_cpu_read(arch_const_cycles_prev); - core_cnt = this_cpu_read(arch_core_cycles_prev); - - if (unlikely(core_cnt <= prev_core_cnt || - const_cnt <= prev_const_cnt)) - return; - - /* - * /\core arch_max_freq_scale - * scale = ------- * -------------------- - * /\const SCHED_CAPACITY_SCALE - * - * See validate_cpu_freq_invariance_counters() for details on - * arch_max_freq_scale and the use of SCHED_CAPACITY_SHIFT. - */ - scale = core_cnt - prev_core_cnt; - scale *= this_cpu_read(arch_max_freq_scale); - scale = div64_u64(scale >> SCHED_CAPACITY_SHIFT, - const_cnt - prev_const_cnt); - - scale = min_t(unsigned long, scale, SCHED_CAPACITY_SCALE); - this_cpu_write(freq_scale, (unsigned long)scale); -} - #ifdef CONFIG_ACPI_CPPC_LIB #include <acpi/cppc_acpi.h> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index cee5d04ea9ad1a6e5f39ddbf393819aefe193a89..a61fc4f989b37bfe57f05931926edb03146ab89e 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -86,7 +86,7 @@ static int vdso_mremap(const struct vm_special_mapping *sm, return 0; } -static int __vdso_init(enum vdso_abi abi) +static int __init __vdso_init(enum vdso_abi abi) { int i; struct page **vdso_pagelist; @@ -271,6 +271,14 @@ enum aarch32_map { static struct page *aarch32_vectors_page __ro_after_init; static struct page *aarch32_sig_page __ro_after_init; +static int aarch32_sigpage_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + current->mm->context.sigpage = (void *)new_vma->vm_start; + + return 0; +} + static struct vm_special_mapping aarch32_vdso_maps[] = { [AA32_MAP_VECTORS] = { .name = "[vectors]", /* ABI */ @@ -279,6 +287,7 @@ static struct vm_special_mapping aarch32_vdso_maps[] = { [AA32_MAP_SIGPAGE] = { .name = "[sigpage]", /* ABI */ .pages = &aarch32_sig_page, + .mremap = aarch32_sigpage_mremap, }, [AA32_MAP_VVAR] = { .name = "[vvar]", @@ -299,34 +308,35 @@ static int aarch32_alloc_kuser_vdso_page(void) if (!IS_ENABLED(CONFIG_KUSER_HELPERS)) return 0; - vdso_page = get_zeroed_page(GFP_ATOMIC); + vdso_page = get_zeroed_page(GFP_KERNEL); if (!vdso_page) return -ENOMEM; memcpy((void *)(vdso_page + 0x1000 - kuser_sz), __kuser_helper_start, kuser_sz); aarch32_vectors_page = virt_to_page(vdso_page); - flush_dcache_page(aarch32_vectors_page); return 0; } +#define COMPAT_SIGPAGE_POISON_WORD 0xe7fddef1 static int aarch32_alloc_sigpage(void) { extern char __aarch32_sigret_code_start[], __aarch32_sigret_code_end[]; int sigret_sz = __aarch32_sigret_code_end - __aarch32_sigret_code_start; - unsigned long sigpage; + __le32 poison = cpu_to_le32(COMPAT_SIGPAGE_POISON_WORD); + void *sigpage; - sigpage = get_zeroed_page(GFP_ATOMIC); + sigpage = (void *)__get_free_page(GFP_KERNEL); if (!sigpage) return -ENOMEM; - memcpy((void *)sigpage, __aarch32_sigret_code_start, sigret_sz); + memset32(sigpage, (__force u32)poison, PAGE_SIZE / sizeof(poison)); + memcpy(sigpage, __aarch32_sigret_code_start, sigret_sz); aarch32_sig_page = virt_to_page(sigpage); - flush_dcache_page(aarch32_sig_page); return 0; } -static int __aarch32_alloc_vdso_pages(void) +static int __init __aarch32_alloc_vdso_pages(void) { if (!IS_ENABLED(CONFIG_COMPAT_VDSO)) diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index a6707df4f6c0fc017c796e770d9ff5f05ded1f54..fb24a0f022adde354d65febd5de80828680e49a3 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -75,9 +75,9 @@ quiet_cmd_hyprel = HYPREL $@ quiet_cmd_hypcopy = HYPCOPY $@ cmd_hypcopy = $(OBJCOPY) --prefix-symbols=__kvm_nvhe_ $< $@ -# Remove ftrace and Shadow Call Stack CFLAGS. -# This is equivalent to the 'notrace' and '__noscs' annotations. -KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS), $(KBUILD_CFLAGS)) +# Remove ftrace, Shadow Call Stack, and CFI CFLAGS. +# This is equivalent to the 'notrace', '__noscs', and '__nocfi' annotations. +KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_CFI), $(KBUILD_CFLAGS)) # KVM nVHE code is run at a different exception code with a different map, so # compiler instrumentation that inserts callbacks or checks into the code may diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 40cbaca81333439f5d873056da432306e9f2ddaa..b9518f94bd43557f6545d2064ac605bfaeabeedc 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -2190,8 +2190,8 @@ static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id, return offset; } -static int vgic_its_ite_cmp(void *priv, struct list_head *a, - struct list_head *b) +static int vgic_its_ite_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct its_ite *itea = container_of(a, struct its_ite, ite_list); struct its_ite *iteb = container_of(b, struct its_ite, ite_list); @@ -2329,8 +2329,8 @@ static int vgic_its_restore_dte(struct vgic_its *its, u32 id, return offset; } -static int vgic_its_device_cmp(void *priv, struct list_head *a, - struct list_head *b) +static int vgic_its_device_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct its_device *deva = container_of(a, struct its_device, dev_list); struct its_device *devb = container_of(b, struct its_device, dev_list); diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 15a6c98ee92f05cdf35f19c5ed5cbd7a6738f699..2f1b156021a6042e9a7a224c684e7b4bdf4db7be 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -86,7 +86,7 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, } break; case GICD_TYPER2: - if (kvm_vgic_global_state.has_gicv4_1) + if (kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi()) value = GICD_TYPER2_nASSGIcap; break; case GICD_IIDR: @@ -119,7 +119,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu, dist->enabled = val & GICD_CTLR_ENABLE_SS_G1; /* Not a GICv4.1? No HW SGIs */ - if (!kvm_vgic_global_state.has_gicv4_1) + if (!kvm_vgic_global_state.has_gicv4_1 || !gic_cpuif_has_vsgi()) val &= ~GICD_CTLR_nASSGIreq; /* Dist stays enabled? nASSGIreq is RO */ diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index 1c597c9885fa7a115824df4ad66a1fbada87f129..15b666200f0b4be8a70f10952f77ce6d1e1eff40 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -255,7 +255,8 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq) * Return negative if "a" sorts before "b", 0 to preserve order, and positive * to sort "b" before "a". */ -static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b) +static int vgic_irq_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list); struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list); diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 93e87b2875567e09427b4d5e60a947a0e33be77c..4bf1dd3eb041912f8cad240fa606eb9efb5df2a1 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -53,7 +53,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, iommu_setup_dma_ops(dev, dma_base, size); #ifdef CONFIG_XEN - if (xen_initial_domain()) + if (xen_swiotlb_detect()) dev->dma_ops = &xen_swiotlb_dma_ops; #endif } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index f37d4e3830b79a9459f1de8c4349afda05e1c347..871c82ab0a309550c3a140dc969afcc876525ef8 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -527,7 +527,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr, const struct fault_info *inf; struct mm_struct *mm = current->mm; vm_fault_t fault; - unsigned long vm_flags = VM_ACCESS_FLAGS; + unsigned long vm_flags; unsigned int mm_flags = FAULT_FLAG_DEFAULT; unsigned long addr = untagged_addr(far); @@ -544,12 +544,28 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr, if (user_mode(regs)) mm_flags |= FAULT_FLAG_USER; + /* + * vm_flags tells us what bits we must have in vma->vm_flags + * for the fault to be benign, __do_page_fault() would check + * vma->vm_flags & vm_flags and returns an error if the + * intersection is empty + */ if (is_el0_instruction_abort(esr)) { + /* It was exec fault */ vm_flags = VM_EXEC; mm_flags |= FAULT_FLAG_INSTRUCTION; } else if (is_write_abort(esr)) { + /* It was write fault */ vm_flags = VM_WRITE; mm_flags |= FAULT_FLAG_WRITE; + } else { + /* It was read fault */ + vm_flags = VM_READ; + /* Write implies read */ + vm_flags |= VM_WRITE; + /* If EPAN is absent then exec implies read */ + if (!cpus_have_const_cap(ARM64_HAS_EPAN)) + vm_flags |= VM_EXEC; } if (is_ttbr0_addr(addr) && is_el1_permission_fault(addr, esr, regs)) { diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c index d8e66c78440ec38a9a8d2e9304a0f01dfc3cbd00..61b52a92b8b68b0d6a9d72bd816f6483bcb7c175 100644 --- a/arch/arm64/mm/kasan_init.c +++ b/arch/arm64/mm/kasan_init.c @@ -79,7 +79,7 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node, phys_addr_t pmd_phys = early ? __pa_symbol(kasan_early_shadow_pmd) : kasan_alloc_zeroed_page(node); - __pud_populate(pudp, pmd_phys, PMD_TYPE_TABLE); + __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE); } return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr); @@ -92,7 +92,7 @@ static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node, phys_addr_t pud_phys = early ? __pa_symbol(kasan_early_shadow_pud) : kasan_alloc_zeroed_page(node); - __p4d_populate(p4dp, pud_phys, PMD_TYPE_TABLE); + __p4d_populate(p4dp, pud_phys, P4D_TYPE_TABLE); } return early ? pud_offset_kimg(p4dp, addr) : pud_offset(p4dp, addr); @@ -214,15 +214,18 @@ static void __init kasan_init_shadow(void) { u64 kimg_shadow_start, kimg_shadow_end; u64 mod_shadow_start, mod_shadow_end; + u64 vmalloc_shadow_end; phys_addr_t pa_start, pa_end; u64 i; - kimg_shadow_start = (u64)kasan_mem_to_shadow(_text) & PAGE_MASK; - kimg_shadow_end = PAGE_ALIGN((u64)kasan_mem_to_shadow(_end)); + kimg_shadow_start = (u64)kasan_mem_to_shadow(KERNEL_START) & PAGE_MASK; + kimg_shadow_end = PAGE_ALIGN((u64)kasan_mem_to_shadow(KERNEL_END)); mod_shadow_start = (u64)kasan_mem_to_shadow((void *)MODULES_VADDR); mod_shadow_end = (u64)kasan_mem_to_shadow((void *)MODULES_END); + vmalloc_shadow_end = (u64)kasan_mem_to_shadow((void *)VMALLOC_END); + /* * We are going to perform proper setup of shadow memory. * At first we should unmap early shadow (clear_pgds() call below). @@ -237,16 +240,22 @@ static void __init kasan_init_shadow(void) clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); kasan_map_populate(kimg_shadow_start, kimg_shadow_end, - early_pfn_to_nid(virt_to_pfn(lm_alias(_text)))); + early_pfn_to_nid(virt_to_pfn(lm_alias(KERNEL_START)))); kasan_populate_early_shadow(kasan_mem_to_shadow((void *)PAGE_END), (void *)mod_shadow_start); - kasan_populate_early_shadow((void *)kimg_shadow_end, - (void *)KASAN_SHADOW_END); - if (kimg_shadow_start > mod_shadow_end) - kasan_populate_early_shadow((void *)mod_shadow_end, - (void *)kimg_shadow_start); + if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { + BUILD_BUG_ON(VMALLOC_START != MODULES_END); + kasan_populate_early_shadow((void *)vmalloc_shadow_end, + (void *)KASAN_SHADOW_END); + } else { + kasan_populate_early_shadow((void *)kimg_shadow_end, + (void *)KASAN_SHADOW_END); + if (kimg_shadow_start > mod_shadow_end) + kasan_populate_early_shadow((void *)mod_shadow_end, + (void *)kimg_shadow_start); + } for_each_mem_range(i, &pa_start, &pa_end) { void *start = (void *)__phys_to_virt(pa_start); diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 5d9550fdb9cf8d14871069d2c229db3245688756..d563335ad43f5ef21d3ac6579a4989ac770687d3 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -39,6 +39,7 @@ #define NO_BLOCK_MAPPINGS BIT(0) #define NO_CONT_MAPPINGS BIT(1) +#define NO_EXEC_MAPPINGS BIT(2) /* assumes FEAT_HPDS is not used */ u64 idmap_t0sz = TCR_T0SZ(VA_BITS_MIN); u64 idmap_ptrs_per_pgd = PTRS_PER_PGD; @@ -185,10 +186,14 @@ 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; phys_addr_t pte_phys; + + if (flags & NO_EXEC_MAPPINGS) + pmdval |= PMD_TABLE_PXN; BUG_ON(!pgtable_alloc); pte_phys = pgtable_alloc(PAGE_SHIFT); - __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE); + __pmd_populate(pmdp, pte_phys, pmdval); pmd = READ_ONCE(*pmdp); } BUG_ON(pmd_bad(pmd)); @@ -259,10 +264,14 @@ 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; phys_addr_t pmd_phys; + + if (flags & NO_EXEC_MAPPINGS) + pudval |= PUD_TABLE_PXN; BUG_ON(!pgtable_alloc); pmd_phys = pgtable_alloc(PMD_SHIFT); - __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE); + __pud_populate(pudp, pmd_phys, pudval); pud = READ_ONCE(*pudp); } BUG_ON(pud_bad(pud)); @@ -306,10 +315,14 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, p4d_t p4d = READ_ONCE(*p4dp); if (p4d_none(p4d)) { + p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN; phys_addr_t pud_phys; + + if (flags & NO_EXEC_MAPPINGS) + p4dval |= P4D_TABLE_PXN; BUG_ON(!pgtable_alloc); pud_phys = pgtable_alloc(PUD_SHIFT); - __p4d_populate(p4dp, pud_phys, PUD_TYPE_TABLE); + __p4d_populate(p4dp, pud_phys, p4dval); p4d = READ_ONCE(*p4dp); } BUG_ON(p4d_bad(p4d)); @@ -486,14 +499,24 @@ early_param("crashkernel", enable_crash_mem_map); static void __init map_mem(pgd_t *pgdp) { + static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN); phys_addr_t kernel_start = __pa_symbol(_stext); phys_addr_t kernel_end = __pa_symbol(__init_begin); phys_addr_t start, end; - int flags = 0; + int flags = NO_EXEC_MAPPINGS; u64 i; + /* + * Setting hierarchical PXNTable attributes on table entries covering + * the linear region is only possible if it is guaranteed that no table + * entries at any level are being shared between the linear region and + * the vmalloc region. Check whether this is true for the PGD level, in + * which case it is guaranteed to be true for all other levels as well. + */ + BUILD_BUG_ON(pgd_index(direct_map_end - 1) == pgd_index(direct_map_end)); + if (rodata_full || crash_mem_map || debug_pagealloc_enabled()) - flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; + flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; /* * Take care not to create a writable alias for the @@ -1210,11 +1233,11 @@ void __init early_fixmap_init(void) pudp = pud_offset_kimg(p4dp, addr); } else { if (p4d_none(p4d)) - __p4d_populate(p4dp, __pa_symbol(bm_pud), PUD_TYPE_TABLE); + __p4d_populate(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE); pudp = fixmap_pud(addr); } if (pud_none(READ_ONCE(*pudp))) - __pud_populate(pudp, __pa_symbol(bm_pmd), PMD_TYPE_TABLE); + __pud_populate(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE); pmdp = fixmap_pmd(addr); __pmd_populate(pmdp, __pa_symbol(bm_pte), PMD_TYPE_TABLE); @@ -1480,7 +1503,7 @@ struct range arch_get_mappable_range(void) int arch_add_memory(int nid, u64 start, u64 size, struct mhp_params *params) { - int ret, flags = 0; + int ret, flags = NO_EXEC_MAPPINGS; VM_BUG_ON(!mhp_range_allowed(start, size, true)); @@ -1490,7 +1513,7 @@ int arch_add_memory(int nid, u64 start, u64 size, */ if (rodata_full || debug_pagealloc_enabled() || IS_ENABLED(CONFIG_KFENCE)) - flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; + flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), size, params->pgprot, __pgd_pgtable_alloc, diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index c967bfd30d2b545f9836dad23cec8a83bdad764d..0a48191534ff6360787b17c428b017a79190ed7e 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -419,14 +419,17 @@ SYM_FUNC_START(__cpu_setup) reset_amuserenr_el0 x1 // Disable AMU access from EL0 /* - * Memory region attributes + * Default values for VMSA control registers. These will be adjusted + * below depending on detected CPU features. */ - mov_q x5, MAIR_EL1_SET -#ifdef CONFIG_ARM64_MTE - mte_tcr .req x20 - - mov mte_tcr, #0 + mair .req x17 + tcr .req x16 + mov_q mair, MAIR_EL1_SET + mov_q tcr, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ + TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ + TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS +#ifdef CONFIG_ARM64_MTE /* * Update MAIR_EL1, GCR_EL1 and TFSR*_EL1 if MTE is supported * (ID_AA64PFR1_EL1[11:8] > 1). @@ -438,7 +441,7 @@ SYM_FUNC_START(__cpu_setup) /* Normal Tagged memory type at the corresponding MAIR index */ mov x10, #MAIR_ATTR_NORMAL_TAGGED - bfi x5, x10, #(8 * MT_NORMAL_TAGGED), #8 + bfi mair, x10, #(8 * MT_NORMAL_TAGGED), #8 /* initialize GCR_EL1: all non-zero tags excluded by default */ mov x10, #(SYS_GCR_EL1_RRND | SYS_GCR_EL1_EXCL_MASK) @@ -449,37 +452,26 @@ SYM_FUNC_START(__cpu_setup) msr_s SYS_TFSRE0_EL1, xzr /* set the TCR_EL1 bits */ - mov_q mte_tcr, TCR_KASAN_HW_FLAGS + mov_q x10, TCR_KASAN_HW_FLAGS + orr tcr, tcr, x10 1: #endif - msr mair_el1, x5 - /* - * Set/prepare TCR and TTBR. TCR_EL1.T1SZ gets further - * adjusted if the kernel is compiled with 52bit VA support. - */ - mov_q x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ - TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ - TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS -#ifdef CONFIG_ARM64_MTE - orr x10, x10, mte_tcr - .unreq mte_tcr -#endif - tcr_clear_errata_bits x10, x9, x5 + tcr_clear_errata_bits tcr, x9, x5 #ifdef CONFIG_ARM64_VA_BITS_52 ldr_l x9, vabits_actual sub x9, xzr, x9 add x9, x9, #64 - tcr_set_t1sz x10, x9 + tcr_set_t1sz tcr, x9 #else ldr_l x9, idmap_t0sz #endif - tcr_set_t0sz x10, x9 + tcr_set_t0sz tcr, x9 /* * Set the IPS bits in TCR_EL1. */ - tcr_compute_pa_size x10, #TCR_IPS_SHIFT, x5, x6 + tcr_compute_pa_size tcr, #TCR_IPS_SHIFT, x5, x6 #ifdef CONFIG_ARM64_HW_AFDBM /* * Enable hardware update of the Access Flags bit. @@ -489,13 +481,17 @@ SYM_FUNC_START(__cpu_setup) mrs x9, ID_AA64MMFR1_EL1 and x9, x9, #0xf cbz x9, 1f - orr x10, x10, #TCR_HA // hardware Access flag update + orr tcr, tcr, #TCR_HA // hardware Access flag update 1: #endif /* CONFIG_ARM64_HW_AFDBM */ - msr tcr_el1, x10 + msr mair_el1, mair + msr tcr_el1, tcr /* * Prepare SCTLR */ mov_q x0, INIT_SCTLR_EL1_MMU_ON ret // return to head.S + + .unreq mair + .unreq tcr SYM_FUNC_END(__cpu_setup) diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c index 0e050d76b83aab01bf39493fb8c31829bc48c767..a50e92ea1878e0e787771333e736cc1000d104df 100644 --- a/arch/arm64/mm/ptdump.c +++ b/arch/arm64/mm/ptdump.c @@ -337,7 +337,7 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info) ptdump_walk_pgd(&st.ptdump, info->mm, NULL); } -static void ptdump_initialize(void) +static void __init ptdump_initialize(void) { unsigned i, j; @@ -381,7 +381,7 @@ void ptdump_check_wx(void) pr_info("Checked W+X mappings: passed, no W+X pages found\n"); } -static int ptdump_init(void) +static int __init ptdump_init(void) { address_markers[PAGE_END_NR].start_address = PAGE_END; #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) diff --git a/arch/arm64/mm/ptdump_debugfs.c b/arch/arm64/mm/ptdump_debugfs.c index d29d722ec3ec6e58f1ca795913a4515ae639365f..68bf1a125502dab30fb60903a33d65bb20eb93e6 100644 --- a/arch/arm64/mm/ptdump_debugfs.c +++ b/arch/arm64/mm/ptdump_debugfs.c @@ -16,7 +16,7 @@ static int ptdump_show(struct seq_file *m, void *v) } DEFINE_SHOW_ATTRIBUTE(ptdump); -void ptdump_debugfs_register(struct ptdump_info *info, const char *name) +void __init ptdump_debugfs_register(struct ptdump_info *info, const char *name) { debugfs_create_file(name, 0400, NULL, info, &ptdump_fops); } diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 786656090c502956f71902a3770968a6b69f61af..59b727b693575eb32d0b9567d3866ef03e150f6f 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -580,12 +580,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -598,7 +594,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 9bb12be4a38e8a36be22de9f827765eca9b8a305..8d4ddcebe7b8d2e54c1f425a4e782ebe050be4ba 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -536,12 +536,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -554,7 +550,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 413232626d9d573072c0dbd03fcdf27007cf9257..9cc9f1a06516434e96f24acfbb10ba9c9d9602f7 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -558,12 +558,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -576,7 +572,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index 819cc70b06d8663dde5136da36529c19f66a0e05..c3f3f462e6ce6fa5456cd58284890389b03734e7 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -529,12 +529,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -547,7 +543,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 8f8d5968713bfe2d1dd77b29b143adf70c19d265..8c908fc5c1910aa07739c03d009ba44c82381b71 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -538,12 +538,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -556,7 +552,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index bf15e6c1c939bb3097bd7baa0566f9e186a1dbcd..4e68b72d9c50f15b2ad936dd078d11abb7715095 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -561,12 +561,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -579,7 +575,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 5466d48fcd9d51c9479ae4b5fcfdcce04f9f61c4..d31896293c394c21f98276a81f75c77d49740b58 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -647,12 +647,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -665,7 +661,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 93c3059188389742a1b1ebfefe0c01b29ddbf2ba..c7442f9dd469a19e65f47fd0032f7fbb9a09f90d 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -528,12 +528,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -546,7 +542,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index cacd6c617f6951ee3d15cad78aab0b8ab0cced4a..233b82ea103a448b47a3dede20f4103619579ddd 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -529,12 +529,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -547,7 +543,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index 3ae421cb24a43986826b2e8153d1f383117939cd..664025a0f6a4173eb40e9b061a65cd1d12072978 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -547,12 +547,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -565,7 +561,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 6da97e28c48ef66e133b3850c3dee61ab95664ab..73293a0b3dc86e58c7c393aec4fb788e7a7127df 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -531,12 +531,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -549,7 +545,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index f54481bb789aecb853a673e209d6814996e67fc5..bca8a6f3e92f55a87de8ca339d17ed655e764984 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -530,12 +530,8 @@ CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_BLAKE2S=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA3=m -CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m @@ -548,7 +544,6 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m diff --git a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile index aab04d372ae7d5abf38fa115602d5c668d6cb5bd..834ae9471b8810bff20b2057b266dbf67fa5218f 100644 --- a/arch/m68k/fpsp040/Makefile +++ b/arch/m68k/fpsp040/Makefile @@ -10,7 +10,3 @@ obj-y := bindec.o binstr.o decbin.o do_func.o gen_except.o get_op.o \ ssin.o ssinh.o stan.o stanh.o sto_res.o stwotox.o tbldo.o util.o \ x_bsun.o x_fline.o x_operr.o x_ovfl.o x_snan.o x_store.o \ x_unfl.o x_unimp.o x_unsupp.o bugfix.o skeleton.o - -EXTRA_LDFLAGS := -x - -$(OS_OBJS): fpsp.h diff --git a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile index 43b435049452b1daafd360d3ed33192c99cd4df7..56b530a96c2f33b5a71d3d67a6dffdf6e8136a5c 100644 --- a/arch/m68k/ifpsp060/Makefile +++ b/arch/m68k/ifpsp060/Makefile @@ -5,5 +5,3 @@ # for more details. obj-y := fskeleton.o iskeleton.o os.o - -EXTRA_LDFLAGS := -x diff --git a/arch/m68k/include/asm/mvme147hw.h b/arch/m68k/include/asm/mvme147hw.h index 257b29184af913f8613b3cbcacb91a08e14ef924..e28eb1c0e0bfb37986e520102214fd6e5e1cd5b3 100644 --- a/arch/m68k/include/asm/mvme147hw.h +++ b/arch/m68k/include/asm/mvme147hw.h @@ -66,6 +66,9 @@ struct pcc_regs { #define PCC_INT_ENAB 0x08 #define PCC_TIMER_INT_CLR 0x80 + +#define PCC_TIMER_TIC_EN 0x01 +#define PCC_TIMER_COC_EN 0x02 #define PCC_TIMER_CLR_OVF 0x04 #define PCC_LEVEL_ABORT 0x07 diff --git a/arch/m68k/include/asm/sun3xflop.h b/arch/m68k/include/asm/sun3xflop.h index 93f2a8431c0e90797c00a835f35c3c43480859e3..bce8aabb5380d80bacc47ee04d27521c8d34b069 100644 --- a/arch/m68k/include/asm/sun3xflop.h +++ b/arch/m68k/include/asm/sun3xflop.h @@ -106,7 +106,7 @@ static void sun3x_82072_fd_outb(unsigned char value, int port) case 4: /* FD_STATUS */ *(sun3x_fdc.status_r) = value; break; - }; + } return; } diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 1c235d8f53f36dbb5669e15be107de1a7abe3920..f55bdcb8e4f15723d1cc4333ea04a05e9835a08b 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -388,6 +388,8 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) ret = -EPERM; if (!capable(CAP_SYS_ADMIN)) goto out; + + mmap_read_lock(current->mm); } else { struct vm_area_struct *vma; diff --git a/arch/m68k/kernel/syscalls/Makefile b/arch/m68k/kernel/syscalls/Makefile index 285aaba832d93936c3f2b7edb2938dbfe13fc21f..6713c65a25e15cfe96824cbcdba6bb8f222ef274 100644 --- a/arch/m68k/kernel/syscalls/Makefile +++ b/arch/m68k/kernel/syscalls/Makefile @@ -6,20 +6,14 @@ _dummy := $(shell [ -d '$(uapi)' ] || mkdir -p '$(uapi)') \ $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)') syscall := $(src)/syscall.tbl -syshdr := $(srctree)/$(src)/syscallhdr.sh -systbl := $(srctree)/$(src)/syscalltbl.sh +syshdr := $(srctree)/scripts/syscallhdr.sh +systbl := $(srctree)/scripts/syscalltbl.sh quiet_cmd_syshdr = SYSHDR $@ - cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' '$<' '$@' \ - '$(syshdr_abis_$(basetarget))' \ - '$(syshdr_pfx_$(basetarget))' \ - '$(syshdr_offset_$(basetarget))' + cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --emit-nr $< $@ quiet_cmd_systbl = SYSTBL $@ - cmd_systbl = $(CONFIG_SHELL) '$(systbl)' '$<' '$@' \ - '$(systbl_abis_$(basetarget))' \ - '$(systbl_abi_$(basetarget))' \ - '$(systbl_offset_$(basetarget))' + cmd_systbl = $(CONFIG_SHELL) $(systbl) $< $@ $(uapi)/unistd_32.h: $(syscall) $(syshdr) FORCE $(call if_changed,syshdr) diff --git a/arch/m68k/kernel/syscalls/syscallhdr.sh b/arch/m68k/kernel/syscalls/syscallhdr.sh deleted file mode 100644 index 6f357d68ef4498fe6da8770e0943944c64833285..0000000000000000000000000000000000000000 --- a/arch/m68k/kernel/syscalls/syscallhdr.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -in="$1" -out="$2" -my_abis=`echo "($3)" | tr ',' '|'` -prefix="$4" -offset="$5" - -fileguard=_UAPI_ASM_M68K_`basename "$out" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ - -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` -grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( - printf "#ifndef %s\n" "${fileguard}" - printf "#define %s\n" "${fileguard}" - printf "\n" - - nxt=0 - while read nr abi name entry ; do - if [ -z "$offset" ]; then - printf "#define __NR_%s%s\t%s\n" \ - "${prefix}" "${name}" "${nr}" - else - printf "#define __NR_%s%s\t(%s + %s)\n" \ - "${prefix}" "${name}" "${offset}" "${nr}" - fi - nxt=$((nr+1)) - done - - printf "\n" - printf "#ifdef __KERNEL__\n" - printf "#define __NR_syscalls\t%s\n" "${nxt}" - printf "#endif\n" - printf "\n" - printf "#endif /* %s */\n" "${fileguard}" -) > "$out" diff --git a/arch/m68k/kernel/syscalls/syscalltbl.sh b/arch/m68k/kernel/syscalls/syscalltbl.sh deleted file mode 100644 index 85d78d9309adc4ab2199a4a9fafdce0997da5f87..0000000000000000000000000000000000000000 --- a/arch/m68k/kernel/syscalls/syscalltbl.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -in="$1" -out="$2" -my_abis=`echo "($3)" | tr ',' '|'` -my_abi="$4" -offset="$5" - -emit() { - t_nxt="$1" - t_nr="$2" - t_entry="$3" - - while [ $t_nxt -lt $t_nr ]; do - printf "__SYSCALL(%s, sys_ni_syscall, )\n" "${t_nxt}" - t_nxt=$((t_nxt+1)) - done - printf "__SYSCALL(%s, %s, )\n" "${t_nxt}" "${t_entry}" -} - -grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( - nxt=0 - if [ -z "$offset" ]; then - offset=0 - fi - - while read nr abi name entry ; do - emit $((nxt+offset)) $((nr+offset)) $entry - nxt=$((nr+1)) - done -) > "$out" diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index d329cc7b481cd1a4b3a72f05b766f4f684ab443e..e25ef4a9df3027dc07bd0205f615aaefa9fdd760 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -18,9 +18,8 @@ #define sys_mmap2 sys_mmap_pgoff #endif -#define __SYSCALL(nr, entry, nargs) .long entry +#define __SYSCALL(nr, entry) .long entry .section .rodata ALIGN ENTRY(sys_call_table) #include <asm/syscall_table.h> -#undef __SYSCALL diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index cfdc7f912e14ed20a98c0843e373a56a76db4d12..e1e90c49a49624ccf2cc81f427723de0c89dd28f 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -114,8 +114,10 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id) unsigned long flags; local_irq_save(flags); - m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; - m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF; + m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF | PCC_TIMER_COC_EN | + PCC_TIMER_TIC_EN; + m147_pcc->t1_int_cntrl = PCC_INT_ENAB | PCC_TIMER_INT_CLR | + PCC_LEVEL_TIMER1; clk_total += PCC_TIMER_CYCLES; legacy_timer_tick(1); local_irq_restore(flags); @@ -133,10 +135,10 @@ void mvme147_sched_init (void) /* Init the clock with a value */ /* The clock counter increments until 0xFFFF then reloads */ m147_pcc->t1_preload = PCC_TIMER_PRELOAD; - m147_pcc->t1_cntrl = 0x0; /* clear timer */ - m147_pcc->t1_cntrl = 0x3; /* start timer */ - m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; /* clear pending ints */ - m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; + m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF | PCC_TIMER_COC_EN | + PCC_TIMER_TIC_EN; + m147_pcc->t1_int_cntrl = PCC_INT_ENAB | PCC_TIMER_INT_CLR | + PCC_LEVEL_TIMER1; clocksource_register_hz(&mvme147_clk, PCC_TIMER_CLOCK_FREQ); } diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index 30357fe4ba6c8b6eea7c99896a19b10756829782..b59593c7cfb9dfbfd9073b18166bca1cdd5c0515 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -366,6 +366,7 @@ static u32 clk_total; #define PCCTOVR1_COC_EN 0x02 #define PCCTOVR1_OVR_CLR 0x04 +#define PCCTIC1_INT_LEVEL 6 #define PCCTIC1_INT_CLR 0x08 #define PCCTIC1_INT_EN 0x10 @@ -374,8 +375,8 @@ static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) unsigned long flags; local_irq_save(flags); - out_8(PCCTIC1, in_8(PCCTIC1) | PCCTIC1_INT_CLR); - out_8(PCCTOVR1, PCCTOVR1_OVR_CLR); + out_8(PCCTOVR1, PCCTOVR1_OVR_CLR | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN); + out_8(PCCTIC1, PCCTIC1_INT_EN | PCCTIC1_INT_CLR | PCCTIC1_INT_LEVEL); clk_total += PCC_TIMER_CYCLES; legacy_timer_tick(1); local_irq_restore(flags); @@ -389,14 +390,15 @@ void mvme16x_sched_init(void) int irq; /* Using PCCchip2 or MC2 chip tick timer 1 */ - out_be32(PCCTCNT1, 0); - out_be32(PCCTCMP1, PCC_TIMER_CYCLES); - out_8(PCCTOVR1, in_8(PCCTOVR1) | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN); - out_8(PCCTIC1, PCCTIC1_INT_EN | 6); if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, IRQF_TIMER, "timer", NULL)) panic ("Couldn't register timer int"); + out_be32(PCCTCNT1, 0); + out_be32(PCCTCMP1, PCC_TIMER_CYCLES); + out_8(PCCTOVR1, PCCTOVR1_OVR_CLR | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN); + out_8(PCCTIC1, PCCTIC1_INT_EN | PCCTIC1_INT_CLR | PCCTIC1_INT_LEVEL); + clocksource_register_hz(&mvme16x_clk, PCC_TIMER_CLOCK_FREQ); if (brdno == 0x0162 || brdno == 0x172) diff --git a/arch/mips/crypto/poly1305-glue.c b/arch/mips/crypto/poly1305-glue.c index fc881b46d9111572842cae886d267511922ffbc0..bc6110fb98e0ab6540e0008bec541972c8406a4c 100644 --- a/arch/mips/crypto/poly1305-glue.c +++ b/arch/mips/crypto/poly1305-glue.c @@ -17,7 +17,7 @@ asmlinkage void poly1305_init_mips(void *state, const u8 *key); asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit); asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce); -void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) +void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) { poly1305_init_mips(&dctx->h, key); dctx->s[0] = get_unaligned_le32(key + 16); diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index cf33dd8a487ee8c401f418b789b8345b92173b15..c25a2ce5e29f516661c544dcc4b99e93210f3598 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -276,10 +276,6 @@ asmlinkage void plat_irq_dispatch(void) } #ifdef CONFIG_CPU_XLP -static const struct irq_domain_ops xlp_pic_irq_domain_ops = { - .xlate = irq_domain_xlate_onetwocell, -}; - static int __init xlp_of_pic_init(struct device_node *node, struct device_node *parent) { @@ -324,7 +320,7 @@ static int __init xlp_of_pic_init(struct device_node *node, xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs, nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE, - &xlp_pic_irq_domain_ops, NULL); + &irq_domain_simple_ops, NULL); if (xlp_pic_domain == NULL) { pr_err("PIC %pOFn: Creating legacy domain failed!\n", node); return -EINVAL; diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 6677ac0da45a5ec036c19a5f0418e0448a0fcd4a..1fd9d1260f9e996e0a760f66acade1256c79618d 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -595,7 +595,6 @@ CONFIG_GAMEPORT_FM801=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y CONFIG_ROCKETPORT=m -CONFIG_CYCLADES=m CONFIG_SYNCLINK_GT=m CONFIG_NOZOMI=m CONFIG_N_HDLC=m diff --git a/arch/powerpc/crypto/sha1-spe-glue.c b/arch/powerpc/crypto/sha1-spe-glue.c index b1e577cbf00ca73c4460818722f8ab5f54c928f6..88e8ea73bfa714d22a3790b64f42b55b57ced936 100644 --- a/arch/powerpc/crypto/sha1-spe-glue.c +++ b/arch/powerpc/crypto/sha1-spe-glue.c @@ -107,7 +107,7 @@ static int ppc_spe_sha1_update(struct shash_desc *desc, const u8 *data, src += bytes; len -= bytes; - }; + } memcpy((char *)sctx->buffer, src, len); return 0; diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 60b5583e9eafccba2788c477652985397935bdb9..1a587618015c2e198e6cf50dfee7731484a9dea5 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -149,8 +149,7 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i, return -EIO; } - if (!dump_skip(cprm, roundup(cprm->pos - ret + sz, 4) - cprm->pos)) - return -EIO; + dump_skip_to(cprm, roundup(cprm->pos - ret + sz, 4)); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index b83a3670bd74e5c0c1295bf28b147a0e9a05caba..bed05b644c2c548693dc43a43260450fe699d4cd 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -236,10 +236,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, if (!inode) return -ENOSPC; - if (dir->i_mode & S_ISGID) { - inode->i_gid = dir->i_gid; - inode->i_mode &= S_ISGID; - } + inode_init_owner(&init_user_ns, inode, dir, mode | S_IFDIR); ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */ SPUFS_I(inode)->i_ctx = ctx; if (!ctx) { @@ -470,10 +467,7 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode) goto out; ret = 0; - if (dir->i_mode & S_ISGID) { - inode->i_gid = dir->i_gid; - inode->i_mode &= S_ISGID; - } + inode_init_owner(&init_user_ns, inode, dir, mode | S_IFDIR); gang = alloc_spu_gang(); SPUFS_I(inode)->i_ctx = NULL; SPUFS_I(inode)->i_gang = gang; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 7f1266c24f6bc1af2a4351b8f1210ec5f8b05128..101477b3e26339d59428330da708fc06b03c1c4b 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -24,12 +24,6 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, } } -/* - * This function returns an error if it detects any unreliable features of the - * stack. Otherwise it guarantees that the stack trace is reliable. - * - * If the task is not 'current', the caller *must* ensure the task is inactive. - */ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, void *cookie, struct task_struct *task) { diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index 9bb27e5c22f159c97fed8410d59dd92c91084e0e..9fbfc9574432aadace3149cd6fafea8eeaedd5a8 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -409,6 +409,10 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size) #define ioremap_uc(X,Y) ioremap((X),(Y)) #define ioremap_wc(X,Y) ioremap((X),(Y)) #define ioremap_wt(X,Y) ioremap((X),(Y)) +static inline void __iomem *ioremap_np(unsigned long offset, unsigned long size) +{ + return NULL; +} static inline void iounmap(volatile void __iomem *addr) { diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2792879d398ee41fa0d4858815b33e18664297ae..f3db131be563f2235e7dd77f3c68d4c75fffc920 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -165,6 +165,7 @@ config X86 select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64 select HAVE_ARCH_USERFAULTFD_WP if X86_64 && USERFAULTFD select HAVE_ARCH_VMAP_STACK if X86_64 + select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET select HAVE_ARCH_WITHIN_STACK_FRAMES select HAVE_ASM_MODVERSIONS select HAVE_CMPXCHG_DOUBLE @@ -571,6 +572,7 @@ config X86_UV depends on X86_EXTENDED_PLATFORM depends on NUMA depends on EFI + depends on KEXEC_CORE depends on X86_X2APIC depends on PCI help @@ -777,6 +779,7 @@ if HYPERVISOR_GUEST config PARAVIRT bool "Enable paravirtualization code" + depends on HAVE_STATIC_CALL help This changes the kernel so it can modify itself when it is run under a hypervisor, potentially improving performance significantly @@ -1406,7 +1409,7 @@ config HIGHMEM4G config HIGHMEM64G bool "64GB" - depends on !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !WINCHIP3D && !MK6 + depends on !M486SX && !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !WINCHIP3D && !MK6 select X86_PAE help Select this if you have a 32-bit processor and more than 4 @@ -1518,6 +1521,7 @@ config AMD_MEM_ENCRYPT select ARCH_USE_MEMREMAP_PROT select ARCH_HAS_FORCE_DMA_UNENCRYPTED select INSTRUCTION_DECODER + select ARCH_HAS_RESTRICTED_VIRTIO_MEMORY_ACCESS help Say yes to enable support for the encryption of system memory. This requires an AMD processor that supports Secure Memory @@ -1931,6 +1935,7 @@ config X86_SGX depends on CRYPTO_SHA256=y select SRCU select MMU_NOTIFIER + select NUMA_KEEP_MEMINFO if NUMA help Intel(R) Software Guard eXtensions (SGX) is a set of CPU instructions that can be used by applications to set aside private regions of code diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 9a85eae37b17357e8d1b9ee5058b44e6bad2c09d..78faf9c7e3aed4825c4efcc00dce87495dde8fcc 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -33,6 +33,7 @@ REALMODE_CFLAGS += -ffreestanding REALMODE_CFLAGS += -fno-stack-protector REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -Wno-address-of-packed-member) REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), $(cc_stack_align4)) +REALMODE_CFLAGS += $(CLANG_FLAGS) export REALMODE_CFLAGS # BITS is used as extension for files which are available in a 32 bit diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index e0bc3988c3faa823e5d4be99abe327044035b8ef..6e5522aebbbd467e17df99a91513caff232056ad 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -46,6 +46,7 @@ KBUILD_CFLAGS += -D__DISABLE_EXPORTS # Disable relocation relaxation in case the link is not PIE. KBUILD_CFLAGS += $(call as-option,-Wa$(comma)-mrelax-relocations=no) KBUILD_CFLAGS += -include $(srctree)/include/linux/hidden.h +KBUILD_CFLAGS += $(CLANG_FLAGS) # sev-es.c indirectly inludes inat-table.h which is generated during # compilation and stored in $(objtree). Add the directory to the includes so diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S index c4bb0f9363f5ee6494f86780d2a93ff82cc40fb3..95a223b3e56a2b6b6b113867e6d9bbe49c90e419 100644 --- a/arch/x86/boot/compressed/efi_thunk_64.S +++ b/arch/x86/boot/compressed/efi_thunk_64.S @@ -5,7 +5,7 @@ * Early support for invoking 32-bit EFI services from a 64-bit kernel. * * Because this thunking occurs before ExitBootServices() we have to - * restore the firmware's 32-bit GDT before we make EFI serivce calls, + * restore the firmware's 32-bit GDT before we make EFI service calls, * since the firmware's 32-bit IDT is still currently installed and it * needs to be able to service interrupts. * diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index e94874f4bbc1d2e563ba76fd74145a8e137b2fc7..a2347ded77ea25fce37f80b32eb743254a7a480e 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -34,6 +34,7 @@ #include <asm/asm-offsets.h> #include <asm/bootparam.h> #include <asm/desc_defs.h> +#include <asm/trapnr.h> #include "pgtable.h" /* @@ -107,9 +108,19 @@ SYM_FUNC_START(startup_32) movl %eax, %gs movl %eax, %ss -/* setup a stack and make sure cpu supports long mode. */ + /* Setup a stack and load CS from current GDT */ leal rva(boot_stack_end)(%ebp), %esp + pushl $__KERNEL32_CS + leal rva(1f)(%ebp), %eax + pushl %eax + lretl +1: + + /* Setup Exception handling for SEV-ES */ + call startup32_load_idt + + /* Make sure cpu supports long mode. */ call verify_cpu testl %eax, %eax jnz .Lno_longmode @@ -172,11 +183,21 @@ SYM_FUNC_START(startup_32) */ call get_sev_encryption_bit xorl %edx, %edx +#ifdef CONFIG_AMD_MEM_ENCRYPT testl %eax, %eax jz 1f subl $32, %eax /* Encryption bit is always above bit 31 */ bts %eax, %edx /* Set encryption mask for page tables */ + /* + * Mark SEV as active in sev_status so that startup32_check_sev_cbit() + * will do a check. The sev_status memory will be fully initialized + * with the contents of MSR_AMD_SEV_STATUS later in + * set_sev_encryption_mask(). For now it is sufficient to know that SEV + * is active. + */ + movl $1, rva(sev_status)(%ebp) 1: +#endif /* Initialize Page tables to 0 */ leal rva(pgtable)(%ebx), %edi @@ -231,7 +252,7 @@ SYM_FUNC_START(startup_32) /* * Setup for the jump to 64bit mode * - * When the jump is performend we will be in long mode but + * When the jump is performed we will be in long mode but * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 * (and in turn EFER.LMA = 1). To jump into 64bit mode we use * the new gdt/idt that has __KERNEL_CS with CS.L = 1. @@ -261,6 +282,9 @@ SYM_FUNC_START(startup_32) movl %esi, %edx 1: #endif + /* Check if the C-bit position is correct when SEV is active */ + call startup32_check_sev_cbit + pushl $__KERNEL_CS pushl %eax @@ -694,6 +718,19 @@ SYM_DATA_START(boot_idt) .endr SYM_DATA_END_LABEL(boot_idt, SYM_L_GLOBAL, boot_idt_end) +#ifdef CONFIG_AMD_MEM_ENCRYPT +SYM_DATA_START(boot32_idt_desc) + .word boot32_idt_end - boot32_idt - 1 + .long 0 +SYM_DATA_END(boot32_idt_desc) + .balign 8 +SYM_DATA_START(boot32_idt) + .rept 32 + .quad 0 + .endr +SYM_DATA_END_LABEL(boot32_idt, SYM_L_GLOBAL, boot32_idt_end) +#endif + #ifdef CONFIG_EFI_STUB SYM_DATA(image_offset, .long 0) #endif @@ -786,6 +823,137 @@ SYM_DATA_START_LOCAL(loaded_image_proto) SYM_DATA_END(loaded_image_proto) #endif +#ifdef CONFIG_AMD_MEM_ENCRYPT + __HEAD + .code32 +/* + * Write an IDT entry into boot32_idt + * + * Parameters: + * + * %eax: Handler address + * %edx: Vector number + * + * Physical offset is expected in %ebp + */ +SYM_FUNC_START(startup32_set_idt_entry) + push %ebx + push %ecx + + /* IDT entry address to %ebx */ + leal rva(boot32_idt)(%ebp), %ebx + shl $3, %edx + addl %edx, %ebx + + /* Build IDT entry, lower 4 bytes */ + movl %eax, %edx + andl $0x0000ffff, %edx # Target code segment offset [15:0] + movl $__KERNEL32_CS, %ecx # Target code segment selector + shl $16, %ecx + orl %ecx, %edx + + /* Store lower 4 bytes to IDT */ + movl %edx, (%ebx) + + /* Build IDT entry, upper 4 bytes */ + movl %eax, %edx + andl $0xffff0000, %edx # Target code segment offset [31:16] + orl $0x00008e00, %edx # Present, Type 32-bit Interrupt Gate + + /* Store upper 4 bytes to IDT */ + movl %edx, 4(%ebx) + + pop %ecx + pop %ebx + ret +SYM_FUNC_END(startup32_set_idt_entry) +#endif + +SYM_FUNC_START(startup32_load_idt) +#ifdef CONFIG_AMD_MEM_ENCRYPT + /* #VC handler */ + leal rva(startup32_vc_handler)(%ebp), %eax + movl $X86_TRAP_VC, %edx + call startup32_set_idt_entry + + /* Load IDT */ + leal rva(boot32_idt)(%ebp), %eax + movl %eax, rva(boot32_idt_desc+2)(%ebp) + lidt rva(boot32_idt_desc)(%ebp) +#endif + ret +SYM_FUNC_END(startup32_load_idt) + +/* + * Check for the correct C-bit position when the startup_32 boot-path is used. + * + * The check makes use of the fact that all memory is encrypted when paging is + * disabled. The function creates 64 bits of random data using the RDRAND + * instruction. RDRAND is mandatory for SEV guests, so always available. If the + * hypervisor violates that the kernel will crash right here. + * + * The 64 bits of random data are stored to a memory location and at the same + * time kept in the %eax and %ebx registers. Since encryption is always active + * when paging is off the random data will be stored encrypted in main memory. + * + * Then paging is enabled. When the C-bit position is correct all memory is + * still mapped encrypted and comparing the register values with memory will + * succeed. An incorrect C-bit position will map all memory unencrypted, so that + * the compare will use the encrypted random data and fail. + */ +SYM_FUNC_START(startup32_check_sev_cbit) +#ifdef CONFIG_AMD_MEM_ENCRYPT + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + + /* Check for non-zero sev_status */ + movl rva(sev_status)(%ebp), %eax + testl %eax, %eax + jz 4f + + /* + * Get two 32-bit random values - Don't bail out if RDRAND fails + * because it is better to prevent forward progress if no random value + * can be gathered. + */ +1: rdrand %eax + jnc 1b +2: rdrand %ebx + jnc 2b + + /* Store to memory and keep it in the registers */ + movl %eax, rva(sev_check_data)(%ebp) + movl %ebx, rva(sev_check_data+4)(%ebp) + + /* Enable paging to see if encryption is active */ + movl %cr0, %edx /* Backup %cr0 in %edx */ + movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */ + movl %ecx, %cr0 + + cmpl %eax, rva(sev_check_data)(%ebp) + jne 3f + cmpl %ebx, rva(sev_check_data+4)(%ebp) + jne 3f + + movl %edx, %cr0 /* Restore previous %cr0 */ + + jmp 4f + +3: /* Check failed - hlt the machine */ + hlt + jmp 3b + +4: + popl %edx + popl %ecx + popl %ebx + popl %eax +#endif + ret +SYM_FUNC_END(startup32_check_sev_cbit) + /* * Stack and heap for uncompression */ diff --git a/arch/x86/boot/compressed/idt_64.c b/arch/x86/boot/compressed/idt_64.c index 804a502ee0d28bae40d754a00d282a5aa8ffeb51..9b93567d663a9003d25a8d3f9a3ff6029da28458 100644 --- a/arch/x86/boot/compressed/idt_64.c +++ b/arch/x86/boot/compressed/idt_64.c @@ -52,3 +52,17 @@ void load_stage2_idt(void) load_boot_idt(&boot_idt_desc); } + +void cleanup_exception_handling(void) +{ + /* + * Flush GHCB from cache and map it encrypted again when running as + * SEV-ES guest. + */ + sev_es_shutdown_ghcb(); + + /* Set a null-idt, disabling #PF and #VC handling */ + boot_idt_desc.size = 0; + boot_idt_desc.address = 0; + load_boot_idt(&boot_idt_desc); +} diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index b92fffbe761fd5d38c86f68770bb71152c62d8c3..e36690778497f3ac02e4c7b0b3a1f3bcb7d4ec21 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -639,9 +639,9 @@ static bool process_mem_region(struct mem_vector *region, if (slot_area_index == MAX_SLOT_AREA) { debug_putstr("Aborted e820/efi memmap scan (slot_areas full)!\n"); - return 1; + return true; } - return 0; + return false; } #if defined(CONFIG_MEMORY_HOTREMOVE) && defined(CONFIG_ACPI) diff --git a/arch/x86/boot/compressed/mem_encrypt.S b/arch/x86/boot/compressed/mem_encrypt.S index aa561795efd16182fa185964045ec40571d0b71b..c1e81a848b2a50b7f1f1635e96119c312affab37 100644 --- a/arch/x86/boot/compressed/mem_encrypt.S +++ b/arch/x86/boot/compressed/mem_encrypt.S @@ -23,12 +23,6 @@ SYM_FUNC_START(get_sev_encryption_bit) push %ecx push %edx - /* Check if running under a hypervisor */ - movl $1, %eax - cpuid - bt $31, %ecx /* Check the hypervisor bit */ - jnc .Lno_sev - movl $0x80000000, %eax /* CPUID to check the highest leaf */ cpuid cmpl $0x8000001f, %eax /* See if 0x8000001f is available */ @@ -67,10 +61,132 @@ SYM_FUNC_START(get_sev_encryption_bit) ret SYM_FUNC_END(get_sev_encryption_bit) +/** + * sev_es_req_cpuid - Request a CPUID value from the Hypervisor using + * the GHCB MSR protocol + * + * @%eax: Register to request (0=EAX, 1=EBX, 2=ECX, 3=EDX) + * @%edx: CPUID Function + * + * Returns 0 in %eax on success, non-zero on failure + * %edx returns CPUID value on success + */ +SYM_CODE_START_LOCAL(sev_es_req_cpuid) + shll $30, %eax + orl $0x00000004, %eax + movl $MSR_AMD64_SEV_ES_GHCB, %ecx + wrmsr + rep; vmmcall # VMGEXIT + rdmsr + + /* Check response */ + movl %eax, %ecx + andl $0x3ffff000, %ecx # Bits [12-29] MBZ + jnz 2f + + /* Check return code */ + andl $0xfff, %eax + cmpl $5, %eax + jne 2f + + /* All good - return success */ + xorl %eax, %eax +1: + ret +2: + movl $-1, %eax + jmp 1b +SYM_CODE_END(sev_es_req_cpuid) + +SYM_CODE_START(startup32_vc_handler) + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + + /* Keep CPUID function in %ebx */ + movl %eax, %ebx + + /* Check if error-code == SVM_EXIT_CPUID */ + cmpl $0x72, 16(%esp) + jne .Lfail + + movl $0, %eax # Request CPUID[fn].EAX + movl %ebx, %edx # CPUID fn + call sev_es_req_cpuid # Call helper + testl %eax, %eax # Check return code + jnz .Lfail + movl %edx, 12(%esp) # Store result + + movl $1, %eax # Request CPUID[fn].EBX + movl %ebx, %edx # CPUID fn + call sev_es_req_cpuid # Call helper + testl %eax, %eax # Check return code + jnz .Lfail + movl %edx, 8(%esp) # Store result + + movl $2, %eax # Request CPUID[fn].ECX + movl %ebx, %edx # CPUID fn + call sev_es_req_cpuid # Call helper + testl %eax, %eax # Check return code + jnz .Lfail + movl %edx, 4(%esp) # Store result + + movl $3, %eax # Request CPUID[fn].EDX + movl %ebx, %edx # CPUID fn + call sev_es_req_cpuid # Call helper + testl %eax, %eax # Check return code + jnz .Lfail + movl %edx, 0(%esp) # Store result + + /* + * Sanity check CPUID results from the Hypervisor. See comment in + * do_vc_no_ghcb() for more details on why this is necessary. + */ + + /* Fail if SEV leaf not available in CPUID[0x80000000].EAX */ + cmpl $0x80000000, %ebx + jne .Lcheck_sev + cmpl $0x8000001f, 12(%esp) + jb .Lfail + jmp .Ldone + +.Lcheck_sev: + /* Fail if SEV bit not set in CPUID[0x8000001f].EAX[1] */ + cmpl $0x8000001f, %ebx + jne .Ldone + btl $1, 12(%esp) + jnc .Lfail + +.Ldone: + popl %edx + popl %ecx + popl %ebx + popl %eax + + /* Remove error code */ + addl $4, %esp + + /* Jump over CPUID instruction */ + addl $2, (%esp) + + iret +.Lfail: + /* Send terminate request to Hypervisor */ + movl $0x100, %eax + xorl %edx, %edx + movl $MSR_AMD64_SEV_ES_GHCB, %ecx + wrmsr + rep; vmmcall + + /* If request fails, go to hlt loop */ + hlt + jmp .Lfail +SYM_CODE_END(startup32_vc_handler) + .code64 #include "../../kernel/sev_verify_cbit.S" - SYM_FUNC_START(set_sev_encryption_mask) #ifdef CONFIG_AMD_MEM_ENCRYPT push %rbp diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 267e7f93050ef322cec5e29a742d685c6661b75c..dde042f64ccaa4b41fe983d4d6ad20416392a731 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -430,8 +430,6 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, error("Destination address too large"); #endif #ifndef CONFIG_RELOCATABLE - if ((unsigned long)output != LOAD_PHYSICAL_ADDR) - error("Destination address does not match LOAD_PHYSICAL_ADDR"); if (virt_addr != LOAD_PHYSICAL_ADDR) error("Destination virtual address changed when not relocatable"); #endif @@ -443,11 +441,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, handle_relocations(output, output_len, virt_addr); debug_putstr("done.\nBooting the kernel.\n"); - /* - * Flush GHCB from cache and map it encrypted again when running as - * SEV-ES guest. - */ - sev_es_shutdown_ghcb(); + /* Disable exception handling before booting the kernel */ + cleanup_exception_handling(); return output; } diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 901ea5ebec22a7b9e599b2e2fee990447993544e..e5612f035498c15d2762911807ad4c518638e390 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -155,6 +155,12 @@ extern pteval_t __default_kernel_pte_mask; extern gate_desc boot_idt[BOOT_IDT_ENTRIES]; extern struct desc_ptr boot_idt_desc; +#ifdef CONFIG_X86_64 +void cleanup_exception_handling(void); +#else +static inline void cleanup_exception_handling(void) { } +#endif + /* IDT Entry Points */ void boot_page_fault(void); void boot_stage1_vc(void); diff --git a/arch/x86/boot/compressed/sev-es.c b/arch/x86/boot/compressed/sev-es.c index 27826c265aab484770a3b82b7cde24116cb66d7b..d904bd56b3e33778c92b445c3fed12e148fc4ae5 100644 --- a/arch/x86/boot/compressed/sev-es.c +++ b/arch/x86/boot/compressed/sev-es.c @@ -200,14 +200,8 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code) } finish: - if (result == ES_OK) { + if (result == ES_OK) vc_finish_insn(&ctxt); - } else if (result != ES_RETRY) { - /* - * For now, just halt the machine. That makes debugging easier, - * later we just call sev_es_terminate() here. - */ - while (true) - asm volatile("hlt\n"); - } + else if (result != ES_RETRY) + sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST); } diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c index 7c4c7b2fbf0599ce3dd85c497946f7c13489adfd..98cf3b4e4c9fecfe8b2a479640f9f84a8215a046 100644 --- a/arch/x86/crypto/crc32-pclmul_glue.c +++ b/arch/x86/crypto/crc32-pclmul_glue.c @@ -24,7 +24,7 @@ /* * Copyright 2012 Xyratex Technology Limited * - * Wrappers for kernel crypto shash api to pclmulqdq crc32 imlementation. + * Wrappers for kernel crypto shash api to pclmulqdq crc32 implementation. */ #include <linux/init.h> #include <linux/module.h> diff --git a/arch/x86/crypto/curve25519-x86_64.c b/arch/x86/crypto/curve25519-x86_64.c index 5af8021b98cea4e8d10b7b1ebc5a264c89ab7bd4..6706b6cb1d0fc133c614431a0ff8cea4b83b836a 100644 --- a/arch/x86/crypto/curve25519-x86_64.c +++ b/arch/x86/crypto/curve25519-x86_64.c @@ -114,11 +114,11 @@ static inline void fadd(u64 *out, const u64 *f1, const u64 *f2) ); } -/* Computes the field substraction of two field elements */ +/* Computes the field subtraction of two field elements */ static inline void fsub(u64 *out, const u64 *f1, const u64 *f2) { asm volatile( - /* Compute the raw substraction of f1-f2 */ + /* Compute the raw subtraction of f1-f2 */ " movq 0(%1), %%r8;" " subq 0(%2), %%r8;" " movq 8(%1), %%r9;" @@ -135,7 +135,7 @@ static inline void fsub(u64 *out, const u64 *f1, const u64 *f2) " mov $38, %%rcx;" " cmovc %%rcx, %%rax;" - /* Step 2: Substract carry*38 from the original difference */ + /* Step 2: Subtract carry*38 from the original difference */ " sub %%rax, %%r8;" " sbb $0, %%r9;" " sbb $0, %%r10;" diff --git a/arch/x86/crypto/poly1305_glue.c b/arch/x86/crypto/poly1305_glue.c index 646da46e8d1042c2ee426185bbc346b5a328cd27..1dfb8af48a3caa7ae7a406b8dbf30ccabc840a20 100644 --- a/arch/x86/crypto/poly1305_glue.c +++ b/arch/x86/crypto/poly1305_glue.c @@ -16,7 +16,7 @@ #include <asm/simd.h> asmlinkage void poly1305_init_x86_64(void *ctx, - const u8 key[POLY1305_KEY_SIZE]); + const u8 key[POLY1305_BLOCK_SIZE]); asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp, const size_t len, const u32 padbit); asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], @@ -81,7 +81,7 @@ static void convert_to_base2_64(void *ctx) state->is_base2_26 = 0; } -static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_KEY_SIZE]) +static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_BLOCK_SIZE]) { poly1305_init_x86_64(ctx, key); } @@ -129,7 +129,7 @@ static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], poly1305_emit_avx(ctx, mac, nonce); } -void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) +void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) { poly1305_simd_init(&dctx->h, key); dctx->s[0] = get_unaligned_le32(&key[16]); diff --git a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S index fc23552afe37d767ba484155bf99dd843ed7e9b1..bca4cea757ce245b7044a86924263c90c50206f4 100644 --- a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S +++ b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S @@ -88,7 +88,7 @@ /* * Combined G1 & G2 function. Reordered with help of rotates to have moves - * at begining. + * at beginning. */ #define g1g2_3(ab, cd, Tx0, Tx1, Tx2, Tx3, Ty0, Ty1, Ty2, Ty3, x, y) \ /* G1,1 && G2,1 */ \ diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 03725696397c8e32b80f4735900c5a0355a5bb21..3507cf2064f107bd2363aabe56c17210db41d9eb 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -117,7 +117,7 @@ static bool is_blacklisted_cpu(void) * storing blocks in 64bit registers to allow three blocks to * be processed parallel. Parallel operation then allows gaining * more performance than was trade off, on out-of-order CPUs. - * However Atom does not benefit from this parallellism and + * However Atom does not benefit from this parallelism and * should be blacklisted. */ return true; diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 4efd39aacb9f28366f3bbafb17f59a3ec181cbed..7b2542b13ebd9683748677df37604adb911c4b40 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -38,6 +38,7 @@ #ifdef CONFIG_X86_64 __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs) { + add_random_kstack_offset(); nr = syscall_enter_from_user_mode(regs, nr); instrumentation_begin(); @@ -83,6 +84,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs) { unsigned int nr = syscall_32_enter(regs); + add_random_kstack_offset(); /* * Subtlety here: if ptrace pokes something larger than 2^32-1 into * orig_ax, the unsigned int return value truncates it. This may @@ -102,6 +104,7 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs) unsigned int nr = syscall_32_enter(regs); int res; + add_random_kstack_offset(); /* * This cannot use syscall_enter_from_user_mode() as it has to * fetch EBP before invoking any of the syscall entry work diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index df8c017e616119850d7df71a72a7021bdf715241..ff00347409007193d6b11590ae210dfa43dbcdaf 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -40,7 +40,7 @@ #include <asm/processor-flags.h> #include <asm/irq_vectors.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/asm.h> #include <asm/smap.h> #include <asm/frame.h> @@ -209,7 +209,7 @@ * * Lets build a 5 entry IRET frame after that, such that struct pt_regs * is complete and in particular regs->sp is correct. This gives us - * the original 6 enties as gap: + * the original 6 entries as gap: * * 14*4(%esp) - <previous context> * 13*4(%esp) - gap / flags @@ -430,7 +430,7 @@ * will soon execute iret and the tracer was already set to * the irqstate after the IRET: */ - DISABLE_INTERRUPTS(CLBR_ANY) + cli lss (%esp), %esp /* switch to espfix segment */ .Lend_\@: #endif /* CONFIG_X86_ESPFIX32 */ @@ -1077,7 +1077,7 @@ restore_all_switch_stack: * when returning from IPI handler and when returning from * scheduler to user-space. */ - INTERRUPT_RETURN + iret .section .fixup, "ax" SYM_CODE_START(asm_iret_error) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 400908dff42ebfebf0f0dda3063b9b41ff7ffd2c..a16a5294d55f655a70566a1dc4f92b1fa2574798 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -305,7 +305,7 @@ SYM_CODE_END(ret_from_fork) .macro DEBUG_ENTRY_ASSERT_IRQS_OFF #ifdef CONFIG_DEBUG_ENTRY pushq %rax - SAVE_FLAGS(CLBR_RAX) + SAVE_FLAGS testl $X86_EFLAGS_IF, %eax jz .Lokay_\@ ud2 @@ -511,7 +511,7 @@ SYM_CODE_START(\asmsym) /* * No need to switch back to the IST stack. The current stack is either * identical to the stack in the IRET frame or the VC fall-back stack, - * so it is definitly mapped even with PTI enabled. + * so it is definitely mapped even with PTI enabled. */ jmp paranoid_exit diff --git a/arch/x86/entry/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c index 2d0f3d8bcc257cc421a4df652e6909d6f2f44c11..edfe9780f6d1962b0d57c91475b025d0cc024936 100644 --- a/arch/x86/entry/vdso/vdso2c.c +++ b/arch/x86/entry/vdso/vdso2c.c @@ -218,7 +218,7 @@ int main(int argc, char **argv) /* * Figure out the struct name. If we're writing to a .so file, - * generate raw output insted. + * generate raw output instead. */ name = strdup(argv[3]); namelen = strlen(name); diff --git a/arch/x86/entry/vdso/vdso2c.h b/arch/x86/entry/vdso/vdso2c.h index 1c7cfac7e64ace62a4db3fb148baec1ee9e0a592..5264daa8859f5be103a8ad61d4f675631c9ae791 100644 --- a/arch/x86/entry/vdso/vdso2c.h +++ b/arch/x86/entry/vdso/vdso2c.h @@ -35,7 +35,7 @@ static void BITSFUNC(extract)(const unsigned char *data, size_t data_len, if (offset + len > data_len) fail("section to extract overruns input data"); - fprintf(outfile, "static const unsigned char %s[%lu] = {", name, len); + fprintf(outfile, "static const unsigned char %s[%zu] = {", name, len); BITSFUNC(copy)(outfile, data + offset, len); fprintf(outfile, "\n};\n\n"); } diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S index de1fff7188aad1a5074f0823372ac97fb9f54b14..6ddd7a937b3e3001c0d7c3736736dcb90d5c610d 100644 --- a/arch/x86/entry/vdso/vdso32/system_call.S +++ b/arch/x86/entry/vdso/vdso32/system_call.S @@ -6,7 +6,7 @@ #include <linux/linkage.h> #include <asm/dwarf2.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> .text .globl __kernel_vsyscall @@ -29,7 +29,7 @@ __kernel_vsyscall: * anyone with an AMD CPU, for example). Nonetheless, we try to keep * it working approximately as well as it ever worked. * - * This link may eludicate some of the history: + * This link may elucidate some of the history: * https://android-review.googlesource.com/#/q/Iac3295376d61ef83e713ac9b528f3b50aa780cd7 * personally, I find it hard to understand what's going on there. * diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index 825e829ffff19e245adde1855af2ffc675a12219..235a5794296acbef611d65d2de8cbec7de9f4ed3 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -358,7 +358,7 @@ int map_vdso_once(const struct vdso_image *image, unsigned long addr) mmap_write_lock(mm); /* * Check if we have already mapped vdso blob - fail to prevent - * abusing from userspace install_speciall_mapping, which may + * abusing from userspace install_special_mapping, which may * not do accounting and rlimit right. * We could search vma near context.vdso, but it's a slowpath, * so let's explicitly check all VMAs to be completely sure. diff --git a/arch/x86/entry/vdso/vsgx.S b/arch/x86/entry/vdso/vsgx.S index 86a0e94f68dff84f3bbe139300fa0d55df350e75..99dafac992e2cecc3a9cb9c311e012afc971ffd5 100644 --- a/arch/x86/entry/vdso/vsgx.S +++ b/arch/x86/entry/vdso/vsgx.S @@ -137,7 +137,7 @@ SYM_FUNC_START(__vdso_sgx_enter_enclave) /* * If the return from callback is zero or negative, return immediately, - * else re-execute ENCLU with the postive return value interpreted as + * else re-execute ENCLU with the positive return value interpreted as * the requested ENCLU function. */ cmp $0, %eax diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index 2c1791c4a518f2ad70bec87d1000445ff7e08cf1..9687a8aef01c5d48533d020aba872fe58f6b41f8 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -623,7 +623,7 @@ static void amd_pmu_disable_all(void) /* * Check each counter for overflow and wait for it to be reset by the * NMI if it has overflowed. This relies on the fact that all active - * counters are always enabled when this function is caled and + * counters are always enabled when this function is called and * ARCH_PERFMON_EVENTSEL_INT is always set. */ for (idx = 0; idx < x86_pmu.num_counters; idx++) { diff --git a/arch/x86/events/amd/iommu.h b/arch/x86/events/amd/iommu.h index 0e5c036fd7bea1b2b0801b7bcc7122670095463f..e6493a67f1c6b3615c775c9a706955e81cf4b11b 100644 --- a/arch/x86/events/amd/iommu.h +++ b/arch/x86/events/amd/iommu.h @@ -17,7 +17,7 @@ #define IOMMU_PC_DEVID_MATCH_REG 0x20 #define IOMMU_PC_COUNTER_REPORT_REG 0x28 -/* maximun specified bank/counters */ +/* maximum specified bank/counters */ #define PC_MAX_SPEC_BNKS 64 #define PC_MAX_SPEC_CNTRS 16 diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 18df1712969554ce3d58b6e65c311cfc283bfa00..4c31cae4707ee6c0bf8519fee7d8b1048d473a9f 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -765,7 +765,7 @@ struct perf_sched { }; /* - * Initialize interator that runs through all events and counters. + * Initialize iterator that runs through all events and counters. */ static void perf_sched_init(struct perf_sched *sched, struct event_constraint **constraints, int num, int wmin, int wmax, int gpmax) diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index 731dd8d0dbb11cc538899b181e32c92aa916900e..6320d2cfd9d3e12617babf3b2fa06906166df87a 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -594,7 +594,7 @@ static __init int bts_init(void) * we cannot use the user mapping since it will not be available * if we're not running the owning process. * - * With PTI we can't use the kernal map either, because its not + * With PTI we can't use the kernel map either, because its not * there when we run userspace. * * For now, disable this driver when using PTI. diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index c57ec8e2790783c09377cf290ebd1551ccf13b80..3fd69bd5fa6ea00040335397a572c71a55772688 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -137,7 +137,7 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly = FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ INTEL_UEVENT_CONSTRAINT(0x0148, 0x4), /* L1D_PEND_MISS.PENDING */ - INTEL_UEVENT_CONSTRAINT(0x0279, 0xf), /* IDQ.EMTPY */ + INTEL_UEVENT_CONSTRAINT(0x0279, 0xf), /* IDQ.EMPTY */ INTEL_UEVENT_CONSTRAINT(0x019c, 0xf), /* IDQ_UOPS_NOT_DELIVERED.CORE */ INTEL_UEVENT_CONSTRAINT(0x02a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_LDM_PENDING */ INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */ @@ -2186,7 +2186,7 @@ static void intel_pmu_enable_all(int added) * magic three (non-counting) events 0x4300B5, 0x4300D2, and 0x4300B1 either * in sequence on the same PMC or on different PMCs. * - * In practise it appears some of these events do in fact count, and + * In practice it appears some of these events do in fact count, and * we need to program all 4 events. */ static void intel_pmu_nhm_workaround(void) @@ -2435,7 +2435,7 @@ static inline u64 icl_get_metrics_event_value(u64 metric, u64 slots, int idx) /* * The metric is reported as an 8bit integer fraction - * suming up to 0xff. + * summing up to 0xff. * slots-in-metric = (Metric / 0xff) * slots */ val = (metric >> ((idx - INTEL_PMC_IDX_METRIC_BASE) * 8)) & 0xff; @@ -2776,7 +2776,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) * processing loop coming after that the function, otherwise * phony regular samples may be generated in the sampling buffer * not marked with the EXACT tag. Another possibility is to have - * one PEBS event and at least one non-PEBS event whic hoverflows + * one PEBS event and at least one non-PEBS event which overflows * while PEBS has armed. In this case, bit 62 of GLOBAL_STATUS will * not be set, yet the overflow status bit for the PEBS counter will * be on Skylake. @@ -2824,7 +2824,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) } /* - * Intel Perf mertrics + * Intel Perf metrics */ if (__test_and_clear_bit(GLOBAL_STATUS_PERF_METRICS_OVF_BIT, (unsigned long *)&status)) { handled++; @@ -4594,7 +4594,7 @@ static bool check_msr(unsigned long msr, u64 mask) /* * Disable the check for real HW, so we don't - * mess with potentionaly enabled registers: + * mess with potentially enabled registers: */ if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) return true; @@ -4659,7 +4659,7 @@ static __init void intel_arch_events_quirk(void) { int bit; - /* disable event that reported as not presend by cpuid */ + /* disable event that reported as not present by cpuid */ for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) { intel_perfmon_event_map[intel_arch_events_map[bit].id] = 0; pr_warn("CPUID marked event: \'%s\' unavailable\n", diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index d32b302719fe56dc7302fa49049bca7b2e06ae6e..5aabb0e2964a87a9794616ea0342d6682463656e 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -1805,7 +1805,7 @@ intel_pmu_save_and_restart_reload(struct perf_event *event, int count) * * [-period, 0] * - * the difference between two consequtive reads is: + * the difference between two consecutive reads is: * * A) value2 - value1; * when no overflows have happened in between, diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 21890dacfcfee5f7406e5ac5b72980188ccb3997..acb04ef3da3f12cc12c47eed65bf8e2db9c45a7e 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -1198,7 +1198,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort) /* * The LBR logs any address in the IP, even if the IP just * faulted. This means userspace can control the from address. - * Ensure we don't blindy read any address by validating it is + * Ensure we don't blindly read any address by validating it is * a known text address. */ if (kernel_text_address(from)) { diff --git a/arch/x86/events/intel/p4.c b/arch/x86/events/intel/p4.c index a4cc66005ce85004174f076150b7d7aa34ae5b62..971dffe0b77d475511f8416d607c86b6d4ae5be5 100644 --- a/arch/x86/events/intel/p4.c +++ b/arch/x86/events/intel/p4.c @@ -24,7 +24,7 @@ struct p4_event_bind { unsigned int escr_msr[2]; /* ESCR MSR for this event */ unsigned int escr_emask; /* valid ESCR EventMask bits */ unsigned int shared; /* event is shared across threads */ - char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on abscence */ + char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on absence */ }; struct p4_pebs_bind { @@ -45,7 +45,7 @@ struct p4_pebs_bind { * it's needed for mapping P4_PEBS_CONFIG_METRIC_MASK bits of * event configuration to find out which values are to be * written into MSR_IA32_PEBS_ENABLE and MSR_P4_PEBS_MATRIX_VERT - * resgisters + * registers */ static struct p4_pebs_bind p4_pebs_bind_map[] = { P4_GEN_PEBS_BIND(1stl_cache_load_miss_retired, 0x0000001, 0x0000001), @@ -1313,7 +1313,7 @@ static __initconst const struct x86_pmu p4_pmu = { .get_event_constraints = x86_get_event_constraints, /* * IF HT disabled we may need to use all - * ARCH_P4_MAX_CCCR counters simulaneously + * ARCH_P4_MAX_CCCR counters simultaneously * though leave it restricted at moment assuming * HT is on */ diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index e94af4a54d0d89fb385a61472d3c91708101fd1f..915847655c0652820ef9083faae49d63e85007d1 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -362,7 +362,7 @@ static bool pt_event_valid(struct perf_event *event) /* * Setting bit 0 (TraceEn in RTIT_CTL MSR) in the attr.config - * clears the assomption that BranchEn must always be enabled, + * clears the assumption that BranchEn must always be enabled, * as was the case with the first implementation of PT. * If this bit is not set, the legacy behavior is preserved * for compatibility with the older userspace. diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index 9b89376318388e043e9dfc5918fd8aaf80731862..4bba0491068c869059ac234fb709599789d4cbe8 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -280,17 +280,17 @@ * | [63] | 00h | VALID - When set, indicates the CPU bus * numbers have been initialized. (RO) * |[62:48]| --- | Reserved - * |[47:40]| 00h | BUS_NUM_5 — Return the bus number BIOS assigned + * |[47:40]| 00h | BUS_NUM_5 - Return the bus number BIOS assigned * CPUBUSNO(5). (RO) - * |[39:32]| 00h | BUS_NUM_4 — Return the bus number BIOS assigned + * |[39:32]| 00h | BUS_NUM_4 - Return the bus number BIOS assigned * CPUBUSNO(4). (RO) - * |[31:24]| 00h | BUS_NUM_3 — Return the bus number BIOS assigned + * |[31:24]| 00h | BUS_NUM_3 - Return the bus number BIOS assigned * CPUBUSNO(3). (RO) - * |[23:16]| 00h | BUS_NUM_2 — Return the bus number BIOS assigned + * |[23:16]| 00h | BUS_NUM_2 - Return the bus number BIOS assigned * CPUBUSNO(2). (RO) - * |[15:8] | 00h | BUS_NUM_1 — Return the bus number BIOS assigned + * |[15:8] | 00h | BUS_NUM_1 - Return the bus number BIOS assigned * CPUBUSNO(1). (RO) - * | [7:0] | 00h | BUS_NUM_0 — Return the bus number BIOS assigned + * | [7:0] | 00h | BUS_NUM_0 - Return the bus number BIOS assigned * CPUBUSNO(0). (RO) */ #define SKX_MSR_CPU_BUS_NUMBER 0x300 diff --git a/arch/x86/events/zhaoxin/core.c b/arch/x86/events/zhaoxin/core.c index e68827e604ad1bb82af185e2e8db6e8ce77024c4..949d845c922b48282d0414462b47159fca57206d 100644 --- a/arch/x86/events/zhaoxin/core.c +++ b/arch/x86/events/zhaoxin/core.c @@ -494,7 +494,7 @@ static __init void zhaoxin_arch_events_quirk(void) { int bit; - /* disable event that reported as not presend by cpuid */ + /* disable event that reported as not present by cpuid */ for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(zx_arch_events_map)) { zx_pmon_event_map[zx_arch_events_map[bit].id] = 0; pr_warn("CPUID marked event: \'%s\' unavailable\n", diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index 284e73661a18bde5d17ba6b03efd78d9be1cd309..90e682a92820dea099bc5cbb75a703581d828c0e 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -60,9 +60,11 @@ static u32 hv_apic_read(u32 reg) switch (reg) { case APIC_EOI: rdmsr(HV_X64_MSR_EOI, reg_val, hi); + (void)hi; return reg_val; case APIC_TASKPRI: rdmsr(HV_X64_MSR_TPR, reg_val, hi); + (void)hi; return reg_val; default: @@ -103,7 +105,7 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector) struct hv_send_ipi_ex *ipi_arg; unsigned long flags; int nr_bank = 0; - int ret = 1; + u64 status = HV_STATUS_INVALID_PARAMETER; if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) return false; @@ -128,19 +130,19 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector) if (!nr_bank) ipi_arg->vp_set.format = HV_GENERIC_SET_ALL; - ret = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank, + status = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank, ipi_arg, NULL); ipi_mask_ex_done: local_irq_restore(flags); - return ((ret == 0) ? true : false); + return hv_result_success(status); } static bool __send_ipi_mask(const struct cpumask *mask, int vector) { int cur_cpu, vcpu; struct hv_send_ipi ipi_arg; - int ret = 1; + u64 status; trace_hyperv_send_ipi_mask(mask, vector); @@ -184,9 +186,9 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector) __set_bit(vcpu, (unsigned long *)&ipi_arg.cpu_mask); } - ret = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector, + status = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector, ipi_arg.cpu_mask); - return ((ret == 0) ? true : false); + return hv_result_success(status); do_ex_hypercall: return __send_ipi_mask_ex(mask, vector); @@ -195,6 +197,7 @@ do_ex_hypercall: static bool __send_ipi_one(int cpu, int vector) { int vp = hv_cpu_number_to_vp_number(cpu); + u64 status; trace_hyperv_send_ipi_one(cpu, vector); @@ -207,7 +210,8 @@ static bool __send_ipi_one(int cpu, int vector) if (vp >= 64) return __send_ipi_mask_ex(cpumask_of(cpu), vector); - return !hv_do_fast_hypercall16(HVCALL_SEND_IPI, vector, BIT_ULL(vp)); + status = hv_do_fast_hypercall16(HVCALL_SEND_IPI, vector, BIT_ULL(vp)); + return hv_result_success(status); } static void hv_send_ipi(int cpu, int vector) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index b81047dec1da323860eb3fc70cb935335d3d7939..bb0ae4b5c00f1bf6654142ddbb69f870610a240c 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -54,28 +54,6 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg); u32 hv_max_vp_index; EXPORT_SYMBOL_GPL(hv_max_vp_index); -void *hv_alloc_hyperv_page(void) -{ - BUILD_BUG_ON(PAGE_SIZE != HV_HYP_PAGE_SIZE); - - return (void *)__get_free_page(GFP_KERNEL); -} -EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page); - -void *hv_alloc_hyperv_zeroed_page(void) -{ - BUILD_BUG_ON(PAGE_SIZE != HV_HYP_PAGE_SIZE); - - return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); -} -EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page); - -void hv_free_hyperv_page(unsigned long addr) -{ - free_page(addr); -} -EXPORT_SYMBOL_GPL(hv_free_hyperv_page); - static int hv_cpu_init(unsigned int cpu) { u64 msr_vp_index; @@ -97,7 +75,7 @@ static int hv_cpu_init(unsigned int cpu) *output_arg = page_address(pg + 1); } - hv_get_vp_index(msr_vp_index); + msr_vp_index = hv_get_register(HV_REGISTER_VP_INDEX); hv_vp_index[smp_processor_id()] = msr_vp_index; @@ -162,7 +140,7 @@ EXPORT_SYMBOL_GPL(hyperv_stop_tsc_emulation); static inline bool hv_reenlightenment_available(void) { /* - * Check for required features and priviliges to make TSC frequency + * Check for required features and privileges to make TSC frequency * change notifications work. */ return ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS && @@ -292,7 +270,7 @@ static int hv_suspend(void) /* * Reset the hypercall page as it is going to be invalidated - * accross hibernation. Setting hv_hypercall_pg to NULL ensures + * across hibernation. Setting hv_hypercall_pg to NULL ensures * that any subsequent hypercall operation fails safely instead of * crashing due to an access of an invalid page. The hypercall page * pointer is restored on resume. @@ -349,7 +327,7 @@ static void __init hv_stimer_setup_percpu_clockev(void) * Ignore any errors in setting up stimer clockevents * as we can run with the LAPIC timer as a fallback. */ - (void)hv_stimer_alloc(); + (void)hv_stimer_alloc(false); /* * Still register the LAPIC timer, because the direct-mode STIMER is @@ -369,7 +347,7 @@ static void __init hv_get_partition_id(void) local_irq_save(flags); output_page = *this_cpu_ptr(hyperv_pcpu_output_arg); status = hv_do_hypercall(HVCALL_GET_PARTITION_ID, NULL, output_page); - if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) { + if (!hv_result_success(status)) { /* No point in proceeding if this failed */ pr_err("Failed to get partition ID: %lld\n", status); BUG(); @@ -520,6 +498,8 @@ void __init hyperv_init(void) x86_init.irqs.create_pci_msi_domain = hv_create_pci_msi_domain; #endif + /* Query the VMs extended capability once, so that it can be cached. */ + hv_query_ext_cap(0); return; remove_cpuhp_state: @@ -593,33 +573,6 @@ void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die) } EXPORT_SYMBOL_GPL(hyperv_report_panic); -/** - * hyperv_report_panic_msg - report panic message to Hyper-V - * @pa: physical address of the panic page containing the message - * @size: size of the message in the page - */ -void hyperv_report_panic_msg(phys_addr_t pa, size_t size) -{ - /* - * P3 to contain the physical address of the panic page & P4 to - * contain the size of the panic data in that page. Rest of the - * registers are no-op when the NOTIFY_MSG flag is set. - */ - wrmsrl(HV_X64_MSR_CRASH_P0, 0); - wrmsrl(HV_X64_MSR_CRASH_P1, 0); - wrmsrl(HV_X64_MSR_CRASH_P2, 0); - wrmsrl(HV_X64_MSR_CRASH_P3, pa); - wrmsrl(HV_X64_MSR_CRASH_P4, size); - - /* - * Let Hyper-V know there is crash data available along with - * the panic message. - */ - wrmsrl(HV_X64_MSR_CRASH_CTL, - (HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG)); -} -EXPORT_SYMBOL_GPL(hyperv_report_panic_msg); - bool hv_is_hyperv_initialized(void) { union hv_x64_msr_hypercall_contents hypercall_msr; @@ -650,7 +603,7 @@ EXPORT_SYMBOL_GPL(hv_is_hibernation_supported); enum hv_isolation_type hv_get_isolation_type(void) { - if (!(ms_hyperv.features_b & HV_ISOLATION)) + if (!(ms_hyperv.priv_high & HV_ISOLATION)) return HV_ISOLATION_TYPE_NONE; return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); } @@ -661,3 +614,50 @@ bool hv_is_isolation_supported(void) return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; } EXPORT_SYMBOL_GPL(hv_is_isolation_supported); + +/* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */ +bool hv_query_ext_cap(u64 cap_query) +{ + /* + * The address of the 'hv_extended_cap' variable will be used as an + * output parameter to the hypercall below and so it should be + * compatible with 'virt_to_phys'. Which means, it's address should be + * directly mapped. Use 'static' to keep it compatible; stack variables + * can be virtually mapped, making them imcompatible with + * 'virt_to_phys'. + * Hypercall input/output addresses should also be 8-byte aligned. + */ + static u64 hv_extended_cap __aligned(8); + static bool hv_extended_cap_queried; + u64 status; + + /* + * Querying extended capabilities is an extended hypercall. Check if the + * partition supports extended hypercall, first. + */ + if (!(ms_hyperv.priv_high & HV_ENABLE_EXTENDED_HYPERCALLS)) + return false; + + /* Extended capabilities do not change at runtime. */ + if (hv_extended_cap_queried) + return hv_extended_cap & cap_query; + + status = hv_do_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, NULL, + &hv_extended_cap); + + /* + * The query extended capabilities hypercall should not fail under + * any normal circumstances. Avoid repeatedly making the hypercall, on + * error. + */ + hv_extended_cap_queried = true; + status &= HV_HYPERCALL_RESULT_MASK; + if (status != HV_STATUS_SUCCESS) { + pr_err("Hyper-V: Extended query capabilities hypercall failed 0x%llx\n", + status); + return false; + } + + return hv_extended_cap & cap_query; +} +EXPORT_SYMBOL_GPL(hv_query_ext_cap); diff --git a/arch/x86/hyperv/hv_proc.c b/arch/x86/hyperv/hv_proc.c index 60461e598239127f85dcb4bfb77868e5692437d3..68a0843d4750f765b50dd303c82bc445f442646e 100644 --- a/arch/x86/hyperv/hv_proc.c +++ b/arch/x86/hyperv/hv_proc.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/types.h> -#include <linux/version.h> #include <linux/vmalloc.h> #include <linux/mm.h> #include <linux/clockchips.h> @@ -93,10 +92,9 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages) status = hv_do_rep_hypercall(HVCALL_DEPOSIT_MEMORY, page_count, 0, input_page, NULL); local_irq_restore(flags); - - if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) { + if (!hv_result_success(status)) { pr_err("Failed to deposit pages: %lld\n", status); - ret = status; + ret = hv_result(status); goto err_free_allocations; } @@ -122,7 +120,7 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id) struct hv_add_logical_processor_out *output; u64 status; unsigned long flags; - int ret = 0; + int ret = HV_STATUS_SUCCESS; int pxm = node_to_pxm(node); /* @@ -148,13 +146,11 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id) input, output); local_irq_restore(flags); - status &= HV_HYPERCALL_RESULT_MASK; - - if (status != HV_STATUS_INSUFFICIENT_MEMORY) { - if (status != HV_STATUS_SUCCESS) { + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { + if (!hv_result_success(status)) { pr_err("%s: cpu %u apic ID %u, %lld\n", __func__, lp_index, apic_id, status); - ret = status; + ret = hv_result(status); } break; } @@ -169,7 +165,7 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags) struct hv_create_vp *input; u64 status; unsigned long irq_flags; - int ret = 0; + int ret = HV_STATUS_SUCCESS; int pxm = node_to_pxm(node); /* Root VPs don't seem to need pages deposited */ @@ -200,13 +196,11 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags) status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL); local_irq_restore(irq_flags); - status &= HV_HYPERCALL_RESULT_MASK; - - if (status != HV_STATUS_INSUFFICIENT_MEMORY) { - if (status != HV_STATUS_SUCCESS) { + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { + if (!hv_result_success(status)) { pr_err("%s: vcpu %u, lp %u, %lld\n", __func__, vp_index, flags, status); - ret = status; + ret = hv_result(status); } break; } diff --git a/arch/x86/hyperv/hv_spinlock.c b/arch/x86/hyperv/hv_spinlock.c index f3270c1fc48c1dba158a8af7cac7a4ad30405e45..91cfe698bde0c531a388df586c00f65c35d34aa5 100644 --- a/arch/x86/hyperv/hv_spinlock.c +++ b/arch/x86/hyperv/hv_spinlock.c @@ -25,7 +25,6 @@ static void hv_qlock_kick(int cpu) static void hv_qlock_wait(u8 *byte, u8 val) { - unsigned long msr_val; unsigned long flags; if (in_nmi()) @@ -48,8 +47,13 @@ static void hv_qlock_wait(u8 *byte, u8 val) /* * Only issue the rdmsrl() when the lock state has not changed. */ - if (READ_ONCE(*byte) == val) + if (READ_ONCE(*byte) == val) { + unsigned long msr_val; + rdmsrl(HV_X64_MSR_GUEST_IDLE, msr_val); + + (void)msr_val; + } local_irq_restore(flags); } diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c index 4421a8d92e2307a7021261a5ac3aca5d68c071d8..514fc64e23d5b49964fed6c690ae30c6876b826f 100644 --- a/arch/x86/hyperv/irqdomain.c +++ b/arch/x86/hyperv/irqdomain.c @@ -63,10 +63,10 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level, local_irq_restore(flags); - if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) + if (!hv_result_success(status)) pr_err("%s: hypercall failed, status %lld\n", __func__, status); - return status & HV_HYPERCALL_RESULT_MASK; + return hv_result(status); } static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *old_entry) @@ -88,7 +88,7 @@ static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *old_entry) status = hv_do_hypercall(HVCALL_UNMAP_DEVICE_INTERRUPT, input, NULL); local_irq_restore(flags); - return status & HV_HYPERCALL_RESULT_MASK; + return hv_result(status); } #ifdef CONFIG_PCI_MSI diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c index 2c87350c1fb095149a06709cbc0b11f2427f7acc..c0ba8874d9cb833d4f25d5b0395e386e386270af 100644 --- a/arch/x86/hyperv/mmu.c +++ b/arch/x86/hyperv/mmu.c @@ -58,7 +58,7 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus, int cpu, vcpu, gva_n, max_gvas; struct hv_tlb_flush **flush_pcpu; struct hv_tlb_flush *flush; - u64 status = U64_MAX; + u64 status; unsigned long flags; trace_hyperv_mmu_flush_tlb_others(cpus, info); @@ -161,7 +161,7 @@ do_ex_hypercall: check_status: local_irq_restore(flags); - if (!(status & HV_HYPERCALL_RESULT_MASK)) + if (hv_result_success(status)) return; do_native: native_flush_tlb_others(cpus, info); @@ -176,7 +176,7 @@ static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus, u64 status; if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) - return U64_MAX; + return HV_STATUS_INVALID_PARAMETER; flush_pcpu = (struct hv_tlb_flush_ex **) this_cpu_ptr(hyperv_pcpu_input_arg); @@ -201,7 +201,7 @@ static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus, flush->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K; nr_bank = cpumask_to_vpset(&(flush->hv_vp_set), cpus); if (nr_bank < 0) - return U64_MAX; + return HV_STATUS_INVALID_PARAMETER; /* * We can flush not more than max_gvas with one hypercall. Flush the diff --git a/arch/x86/hyperv/nested.c b/arch/x86/hyperv/nested.c index dd0a843f766d2ae2d3792613a7cdcb84ab5b64df..5d70968c85382560f6d7112b778a935d7a3466fa 100644 --- a/arch/x86/hyperv/nested.c +++ b/arch/x86/hyperv/nested.c @@ -47,7 +47,7 @@ int hyperv_flush_guest_mapping(u64 as) flush, NULL); local_irq_restore(flags); - if (!(status & HV_HYPERCALL_RESULT_MASK)) + if (hv_result_success(status)) ret = 0; fault: @@ -92,7 +92,7 @@ int hyperv_flush_guest_mapping_range(u64 as, { struct hv_guest_mapping_flush_list **flush_pcpu; struct hv_guest_mapping_flush_list *flush; - u64 status = 0; + u64 status; unsigned long flags; int ret = -ENOTSUPP; int gpa_n = 0; @@ -125,10 +125,10 @@ int hyperv_flush_guest_mapping_range(u64 as, local_irq_restore(flags); - if (!(status & HV_HYPERCALL_RESULT_MASK)) + if (hv_result_success(status)) ret = 0; else - ret = status; + ret = hv_result(status); fault: trace_hyperv_nested_flush_guest_mapping_range(as, ret); return ret; diff --git a/arch/x86/include/asm/agp.h b/arch/x86/include/asm/agp.h index 62da760d6d5a6cb177df16f75a3e0e5975db1e1c..cd7b14322035ebbf2853c312164f7aef869f5b33 100644 --- a/arch/x86/include/asm/agp.h +++ b/arch/x86/include/asm/agp.h @@ -9,7 +9,7 @@ * Functions to keep the agpgart mappings coherent with the MMU. The * GART gives the CPU a physical alias of pages in memory. The alias * region is mapped uncacheable. Make sure there are no conflicting - * mappings with different cachability attributes for the same + * mappings with different cacheability attributes for the same * page. This avoids data corruption on some CPUs. */ diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h deleted file mode 100644 index 464034db299f781104da5f05a6a3604320f8d4d7..0000000000000000000000000000000000000000 --- a/arch/x86/include/asm/alternative-asm.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_X86_ALTERNATIVE_ASM_H -#define _ASM_X86_ALTERNATIVE_ASM_H - -#ifdef __ASSEMBLY__ - -#include <asm/asm.h> - -#ifdef CONFIG_SMP - .macro LOCK_PREFIX -672: lock - .pushsection .smp_locks,"a" - .balign 4 - .long 672b - . - .popsection - .endm -#else - .macro LOCK_PREFIX - .endm -#endif - -/* - * objtool annotation to ignore the alternatives and only consider the original - * instruction(s). - */ -.macro ANNOTATE_IGNORE_ALTERNATIVE - .Lannotate_\@: - .pushsection .discard.ignore_alts - .long .Lannotate_\@ - . - .popsection -.endm - -/* - * Issue one struct alt_instr descriptor entry (need to put it into - * the section .altinstructions, see below). This entry contains - * enough information for the alternatives patching code to patch an - * instruction. See apply_alternatives(). - */ -.macro altinstruction_entry orig alt feature orig_len alt_len pad_len - .long \orig - . - .long \alt - . - .word \feature - .byte \orig_len - .byte \alt_len - .byte \pad_len -.endm - -/* - * Define an alternative between two instructions. If @feature is - * present, early code in apply_alternatives() replaces @oldinstr with - * @newinstr. ".skip" directive takes care of proper instruction padding - * in case @newinstr is longer than @oldinstr. - */ -.macro ALTERNATIVE oldinstr, newinstr, feature -140: - \oldinstr -141: - .skip -(((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)),0x90 -142: - - .pushsection .altinstructions,"a" - altinstruction_entry 140b,143f,\feature,142b-140b,144f-143f,142b-141b - .popsection - - .pushsection .altinstr_replacement,"ax" -143: - \newinstr -144: - .popsection -.endm - -#define old_len 141b-140b -#define new_len1 144f-143f -#define new_len2 145f-144f - -/* - * gas compatible max based on the idea from: - * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax - * - * The additional "-" is needed because gas uses a "true" value of -1. - */ -#define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b))))) - - -/* - * Same as ALTERNATIVE macro above but for two alternatives. If CPU - * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has - * @feature2, it replaces @oldinstr with @feature2. - */ -.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 -140: - \oldinstr -141: - .skip -((alt_max_short(new_len1, new_len2) - (old_len)) > 0) * \ - (alt_max_short(new_len1, new_len2) - (old_len)),0x90 -142: - - .pushsection .altinstructions,"a" - altinstruction_entry 140b,143f,\feature1,142b-140b,144f-143f,142b-141b - altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f,142b-141b - .popsection - - .pushsection .altinstr_replacement,"ax" -143: - \newinstr1 -144: - \newinstr2 -145: - .popsection -.endm - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_X86_ALTERNATIVE_ASM_H */ diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 13adca37c99a36a3a8282e22283b130b4a5dd0ad..17b36090d448500634bf41f1bae46160651ae29d 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -2,13 +2,17 @@ #ifndef _ASM_X86_ALTERNATIVE_H #define _ASM_X86_ALTERNATIVE_H -#ifndef __ASSEMBLY__ - #include <linux/types.h> -#include <linux/stddef.h> #include <linux/stringify.h> #include <asm/asm.h> +#define ALTINSTR_FLAG_INV (1 << 15) +#define ALT_NOT(feat) ((feat) | ALTINSTR_FLAG_INV) + +#ifndef __ASSEMBLY__ + +#include <linux/stddef.h> + /* * Alternative inline assembly for SMP. * @@ -150,7 +154,7 @@ static inline int alternatives_text_reserved(void *start, void *end) " .byte " alt_rlen(num) "\n" /* replacement len */ \ " .byte " alt_pad_len "\n" /* pad len */ -#define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \ +#define ALTINSTR_REPLACEMENT(newinstr, num) /* replacement */ \ "# ALT: replacement " #num "\n" \ b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n" @@ -161,7 +165,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ALTINSTR_ENTRY(feature, 1) \ ".popsection\n" \ ".pushsection .altinstr_replacement, \"ax\"\n" \ - ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ + ALTINSTR_REPLACEMENT(newinstr, 1) \ ".popsection\n" #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ @@ -171,10 +175,15 @@ static inline int alternatives_text_reserved(void *start, void *end) ALTINSTR_ENTRY(feature2, 2) \ ".popsection\n" \ ".pushsection .altinstr_replacement, \"ax\"\n" \ - ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ - ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ + ALTINSTR_REPLACEMENT(newinstr1, 1) \ + ALTINSTR_REPLACEMENT(newinstr2, 2) \ ".popsection\n" +/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */ +#define ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) \ + ALTERNATIVE_2(oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \ + newinstr_yes, feature) + #define ALTERNATIVE_3(oldinsn, newinsn1, feat1, newinsn2, feat2, newinsn3, feat3) \ OLDINSTR_3(oldinsn, 1, 2, 3) \ ".pushsection .altinstructions,\"a\"\n" \ @@ -183,9 +192,9 @@ static inline int alternatives_text_reserved(void *start, void *end) ALTINSTR_ENTRY(feat3, 3) \ ".popsection\n" \ ".pushsection .altinstr_replacement, \"ax\"\n" \ - ALTINSTR_REPLACEMENT(newinsn1, feat1, 1) \ - ALTINSTR_REPLACEMENT(newinsn2, feat2, 2) \ - ALTINSTR_REPLACEMENT(newinsn3, feat3, 3) \ + ALTINSTR_REPLACEMENT(newinsn1, 1) \ + ALTINSTR_REPLACEMENT(newinsn2, 2) \ + ALTINSTR_REPLACEMENT(newinsn3, 3) \ ".popsection\n" /* @@ -206,6 +215,9 @@ static inline int alternatives_text_reserved(void *start, void *end) #define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \ asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory") +#define alternative_ternary(oldinstr, feature, newinstr_yes, newinstr_no) \ + asm_inline volatile(ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) ::: "memory") + /* * Alternative inline assembly with input. * @@ -271,6 +283,116 @@ static inline int alternatives_text_reserved(void *start, void *end) */ #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr +#else /* __ASSEMBLY__ */ + +#ifdef CONFIG_SMP + .macro LOCK_PREFIX +672: lock + .pushsection .smp_locks,"a" + .balign 4 + .long 672b - . + .popsection + .endm +#else + .macro LOCK_PREFIX + .endm +#endif + +/* + * objtool annotation to ignore the alternatives and only consider the original + * instruction(s). + */ +.macro ANNOTATE_IGNORE_ALTERNATIVE + .Lannotate_\@: + .pushsection .discard.ignore_alts + .long .Lannotate_\@ - . + .popsection +.endm + +/* + * Issue one struct alt_instr descriptor entry (need to put it into + * the section .altinstructions, see below). This entry contains + * enough information for the alternatives patching code to patch an + * instruction. See apply_alternatives(). + */ +.macro altinstruction_entry orig alt feature orig_len alt_len pad_len + .long \orig - . + .long \alt - . + .word \feature + .byte \orig_len + .byte \alt_len + .byte \pad_len +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE oldinstr, newinstr, feature +140: + \oldinstr +141: + .skip -(((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)),0x90 +142: + + .pushsection .altinstructions,"a" + altinstruction_entry 140b,143f,\feature,142b-140b,144f-143f,142b-141b + .popsection + + .pushsection .altinstr_replacement,"ax" +143: + \newinstr +144: + .popsection +.endm + +#define old_len 141b-140b +#define new_len1 144f-143f +#define new_len2 145f-144f + +/* + * gas compatible max based on the idea from: + * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax + * + * The additional "-" is needed because gas uses a "true" value of -1. + */ +#define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b))))) + + +/* + * Same as ALTERNATIVE macro above but for two alternatives. If CPU + * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has + * @feature2, it replaces @oldinstr with @feature2. + */ +.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 +140: + \oldinstr +141: + .skip -((alt_max_short(new_len1, new_len2) - (old_len)) > 0) * \ + (alt_max_short(new_len1, new_len2) - (old_len)),0x90 +142: + + .pushsection .altinstructions,"a" + altinstruction_entry 140b,143f,\feature1,142b-140b,144f-143f,142b-141b + altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f,142b-141b + .popsection + + .pushsection .altinstr_replacement,"ax" +143: + \newinstr1 +144: + \newinstr2 +145: + .popsection +.endm + +/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */ +#define ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) \ + ALTERNATIVE_2 oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \ + newinstr_yes, feature + #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_ALTERNATIVE_H */ diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index 4d4ec5cbdc51c3a6e75de4d37a1ea44ddfb9a8a3..94fbe6ae74313d397429a0992ba729aedb0ee2ba 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -22,7 +22,7 @@ extern void __add_wrong_size(void) /* * Constants for operation sizes. On 32-bit, the 64-bit size it set to * -1 because sizeof will never return -1, thereby making those switch - * case statements guaranteeed dead code which the compiler will + * case statements guaranteed dead code which the compiler will * eliminate, and allowing the "missing symbol in the default case" to * indicate a usage error. */ diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index da78ccbd493b77e30c0b56a2fa8c7267835ffdfb..0d7fc0e2bfc9e6403f87436faa421bfdfec97e0a 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -41,12 +41,13 @@ 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 -extern void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c); +extern void __init sld_setup(struct cpuinfo_x86 *c); extern void switch_to_sld(unsigned long tifn); 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); #else -static inline void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) {} +static inline void __init sld_setup(struct cpuinfo_x86 *c) {} static inline void switch_to_sld(unsigned long tifn) {} static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code) { @@ -57,6 +58,8 @@ static inline bool handle_guest_split_lock(unsigned long ip) { return false; } + +static inline void handle_bus_lock(struct pt_regs *regs) {} #endif #ifdef CONFIG_IA32_FEAT_CTL void init_ia32_feat_ctl(struct cpuinfo_x86 *c); diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 1728d4ce5730b64fa475db780d9c483418d1aa43..16a51e7288d581805701cbd21aebb08c4c63441c 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -8,6 +8,7 @@ #include <asm/asm.h> #include <linux/bitops.h> +#include <asm/alternative.h> enum cpuid_leafs { @@ -175,39 +176,15 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit); */ static __always_inline bool _static_cpu_has(u16 bit) { - asm_volatile_goto("1: jmp 6f\n" - "2:\n" - ".skip -(((5f-4f) - (2b-1b)) > 0) * " - "((5f-4f) - (2b-1b)),0x90\n" - "3:\n" - ".section .altinstructions,\"a\"\n" - " .long 1b - .\n" /* src offset */ - " .long 4f - .\n" /* repl offset */ - " .word %P[always]\n" /* always replace */ - " .byte 3b - 1b\n" /* src len */ - " .byte 5f - 4f\n" /* repl len */ - " .byte 3b - 2b\n" /* pad len */ - ".previous\n" - ".section .altinstr_replacement,\"ax\"\n" - "4: jmp %l[t_no]\n" - "5:\n" - ".previous\n" - ".section .altinstructions,\"a\"\n" - " .long 1b - .\n" /* src offset */ - " .long 0\n" /* no replacement */ - " .word %P[feature]\n" /* feature bit */ - " .byte 3b - 1b\n" /* src len */ - " .byte 0\n" /* repl len */ - " .byte 0\n" /* pad len */ - ".previous\n" - ".section .altinstr_aux,\"ax\"\n" - "6:\n" - " testb %[bitnum],%[cap_byte]\n" - " jnz %l[t_yes]\n" - " jmp %l[t_no]\n" - ".previous\n" + asm_volatile_goto( + ALTERNATIVE_TERNARY("jmp 6f", %P[feature], "", "jmp %l[t_no]") + ".section .altinstr_aux,\"ax\"\n" + "6:\n" + " testb %[bitnum],%[cap_byte]\n" + " jnz %l[t_yes]\n" + " jmp %l[t_no]\n" + ".previous\n" : : [feature] "i" (bit), - [always] "i" (X86_FEATURE_ALWAYS), [bitnum] "i" (1 << (bit & 7)), [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3]) : : t_yes, t_no); diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index cc96e26d69f7ae9fa04ccdbc35d1f72f93d735a2..6241165620867e11e755b73e24ffd4a83976d5d2 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -236,6 +236,8 @@ #define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */ #define X86_FEATURE_VMCALL ( 8*32+18) /* "" Hypervisor supports the VMCALL instruction */ #define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */ +#define X86_FEATURE_PVUNLOCK ( 8*32+20) /* "" PV unlock function */ +#define X86_FEATURE_VCPUPREEMPT ( 8*32+21) /* "" PV vcpu_is_preempted function */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ @@ -290,6 +292,8 @@ #define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */ #define X86_FEATURE_SPLIT_LOCK_DETECT (11*32+ 6) /* #AC for split lock */ #define X86_FEATURE_PER_THREAD_MBA (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */ +#define X86_FEATURE_SGX1 (11*32+ 8) /* "" Basic SGX */ +#define X86_FEATURE_SGX2 (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ @@ -354,6 +358,7 @@ #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ +#define X86_FEATURE_BUS_LOCK_DETECT (16*32+24) /* Bus Lock detect */ #define X86_FEATURE_CLDEMOTE (16*32+25) /* CLDEMOTE instruction */ #define X86_FEATURE_MOVDIRI (16*32+27) /* MOVDIRI instruction */ #define X86_FEATURE_MOVDIR64B (16*32+28) /* MOVDIR64B instruction */ diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 9224d40cdefee7f60f8dde09b42b71c0f5a9f4fd..7d7500806af8a900694e5a5fe5b8440b70a5c522 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -283,12 +283,12 @@ extern u32 elf_hwcap2; * * The decision process for determining the results are: * - *              CPU: | lacks NX*  | has NX, ia32     | has NX, x86_64 | - * ELF:              |            |                  |                | + * CPU: | lacks NX* | has NX, ia32 | has NX, x86_64 | + * ELF: | | | | * ---------------------|------------|------------------|----------------| - * missing PT_GNU_STACK | exec-all   | exec-all         | exec-none      | - * PT_GNU_STACK == RWX  | exec-stack | exec-stack       | exec-stack     | - * PT_GNU_STACK == RW   | exec-none  | exec-none        | exec-none      | + * missing PT_GNU_STACK | exec-all | exec-all | exec-none | + * PT_GNU_STACK == RWX | exec-stack | exec-stack | exec-stack | + * PT_GNU_STACK == RW | exec-none | exec-none | exec-none | * * exec-all : all PROT_READ user mappings are executable, except when * backed by files on a noexec-filesystem. diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h index 2b87b191b3b8470cf80ad8d5004a7baf4ab4d6da..14ebd21965691d17ea763e5f62494cf780946cae 100644 --- a/arch/x86/include/asm/entry-common.h +++ b/arch/x86/include/asm/entry-common.h @@ -2,6 +2,7 @@ #ifndef _ASM_X86_ENTRY_COMMON_H #define _ASM_X86_ENTRY_COMMON_H +#include <linux/randomize_kstack.h> #include <linux/user-return-notifier.h> #include <asm/nospec-branch.h> @@ -70,6 +71,21 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, */ current_thread_info()->status &= ~(TS_COMPAT | TS_I386_REGS_POKED); #endif + + /* + * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(), + * but not enough for x86 stack utilization comfort. To keep + * reasonable stack head room, reduce the maximum offset to 8 bits. + * + * The actual entropy will be further reduced by the compiler when + * applying stack alignment constraints (see cc_stack_align4/8 in + * arch/x86/Makefile), which will remove the 3 (x86_64) or 2 (ia32) + * low bits from any entropy chosen here. + * + * Therefore, final stack offset entropy will be 5 (x86_64) or + * 6 (ia32) bits. + */ + choose_random_kstack_offset(rdtsc() & 0xFF); } #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index e6cd3fee562bff1704b2c4fcfeec9a8f156e509e..606f5cc579b2bd52f678b57e06409b108c1fd803 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -156,7 +156,7 @@ enum hv_isolation_type { #define HV_X64_MSR_HYPERCALL 0x40000001 /* MSR used to provide vcpu index */ -#define HV_X64_MSR_VP_INDEX 0x40000002 +#define HV_REGISTER_VP_INDEX 0x40000002 /* MSR used to reset the guest OS. */ #define HV_X64_MSR_RESET 0x40000003 @@ -165,10 +165,10 @@ enum hv_isolation_type { #define HV_X64_MSR_VP_RUNTIME 0x40000010 /* MSR used to read the per-partition time reference counter */ -#define HV_X64_MSR_TIME_REF_COUNT 0x40000020 +#define HV_REGISTER_TIME_REF_COUNT 0x40000020 /* A partition's reference time stamp counter (TSC) page */ -#define HV_X64_MSR_REFERENCE_TSC 0x40000021 +#define HV_REGISTER_REFERENCE_TSC 0x40000021 /* MSR used to retrieve the TSC frequency */ #define HV_X64_MSR_TSC_FREQUENCY 0x40000022 @@ -183,50 +183,50 @@ enum hv_isolation_type { #define HV_X64_MSR_VP_ASSIST_PAGE 0x40000073 /* Define synthetic interrupt controller model specific registers. */ -#define HV_X64_MSR_SCONTROL 0x40000080 -#define HV_X64_MSR_SVERSION 0x40000081 -#define HV_X64_MSR_SIEFP 0x40000082 -#define HV_X64_MSR_SIMP 0x40000083 -#define HV_X64_MSR_EOM 0x40000084 -#define HV_X64_MSR_SINT0 0x40000090 -#define HV_X64_MSR_SINT1 0x40000091 -#define HV_X64_MSR_SINT2 0x40000092 -#define HV_X64_MSR_SINT3 0x40000093 -#define HV_X64_MSR_SINT4 0x40000094 -#define HV_X64_MSR_SINT5 0x40000095 -#define HV_X64_MSR_SINT6 0x40000096 -#define HV_X64_MSR_SINT7 0x40000097 -#define HV_X64_MSR_SINT8 0x40000098 -#define HV_X64_MSR_SINT9 0x40000099 -#define HV_X64_MSR_SINT10 0x4000009A -#define HV_X64_MSR_SINT11 0x4000009B -#define HV_X64_MSR_SINT12 0x4000009C -#define HV_X64_MSR_SINT13 0x4000009D -#define HV_X64_MSR_SINT14 0x4000009E -#define HV_X64_MSR_SINT15 0x4000009F +#define HV_REGISTER_SCONTROL 0x40000080 +#define HV_REGISTER_SVERSION 0x40000081 +#define HV_REGISTER_SIEFP 0x40000082 +#define HV_REGISTER_SIMP 0x40000083 +#define HV_REGISTER_EOM 0x40000084 +#define HV_REGISTER_SINT0 0x40000090 +#define HV_REGISTER_SINT1 0x40000091 +#define HV_REGISTER_SINT2 0x40000092 +#define HV_REGISTER_SINT3 0x40000093 +#define HV_REGISTER_SINT4 0x40000094 +#define HV_REGISTER_SINT5 0x40000095 +#define HV_REGISTER_SINT6 0x40000096 +#define HV_REGISTER_SINT7 0x40000097 +#define HV_REGISTER_SINT8 0x40000098 +#define HV_REGISTER_SINT9 0x40000099 +#define HV_REGISTER_SINT10 0x4000009A +#define HV_REGISTER_SINT11 0x4000009B +#define HV_REGISTER_SINT12 0x4000009C +#define HV_REGISTER_SINT13 0x4000009D +#define HV_REGISTER_SINT14 0x4000009E +#define HV_REGISTER_SINT15 0x4000009F /* * Synthetic Timer MSRs. Four timers per vcpu. */ -#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0 -#define HV_X64_MSR_STIMER0_COUNT 0x400000B1 -#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2 -#define HV_X64_MSR_STIMER1_COUNT 0x400000B3 -#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4 -#define HV_X64_MSR_STIMER2_COUNT 0x400000B5 -#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6 -#define HV_X64_MSR_STIMER3_COUNT 0x400000B7 +#define HV_REGISTER_STIMER0_CONFIG 0x400000B0 +#define HV_REGISTER_STIMER0_COUNT 0x400000B1 +#define HV_REGISTER_STIMER1_CONFIG 0x400000B2 +#define HV_REGISTER_STIMER1_COUNT 0x400000B3 +#define HV_REGISTER_STIMER2_CONFIG 0x400000B4 +#define HV_REGISTER_STIMER2_COUNT 0x400000B5 +#define HV_REGISTER_STIMER3_CONFIG 0x400000B6 +#define HV_REGISTER_STIMER3_COUNT 0x400000B7 /* Hyper-V guest idle MSR */ #define HV_X64_MSR_GUEST_IDLE 0x400000F0 /* Hyper-V guest crash notification MSR's */ -#define HV_X64_MSR_CRASH_P0 0x40000100 -#define HV_X64_MSR_CRASH_P1 0x40000101 -#define HV_X64_MSR_CRASH_P2 0x40000102 -#define HV_X64_MSR_CRASH_P3 0x40000103 -#define HV_X64_MSR_CRASH_P4 0x40000104 -#define HV_X64_MSR_CRASH_CTL 0x40000105 +#define HV_REGISTER_CRASH_P0 0x40000100 +#define HV_REGISTER_CRASH_P1 0x40000101 +#define HV_REGISTER_CRASH_P2 0x40000102 +#define HV_REGISTER_CRASH_P3 0x40000103 +#define HV_REGISTER_CRASH_P4 0x40000104 +#define HV_REGISTER_CRASH_CTL 0x40000105 /* TSC emulation after migration */ #define HV_X64_MSR_REENLIGHTENMENT_CONTROL 0x40000106 @@ -236,6 +236,32 @@ enum hv_isolation_type { /* TSC invariant control */ #define HV_X64_MSR_TSC_INVARIANT_CONTROL 0x40000118 +/* Register name aliases for temporary compatibility */ +#define HV_X64_MSR_STIMER0_COUNT HV_REGISTER_STIMER0_COUNT +#define HV_X64_MSR_STIMER0_CONFIG HV_REGISTER_STIMER0_CONFIG +#define HV_X64_MSR_STIMER1_COUNT HV_REGISTER_STIMER1_COUNT +#define HV_X64_MSR_STIMER1_CONFIG HV_REGISTER_STIMER1_CONFIG +#define HV_X64_MSR_STIMER2_COUNT HV_REGISTER_STIMER2_COUNT +#define HV_X64_MSR_STIMER2_CONFIG HV_REGISTER_STIMER2_CONFIG +#define HV_X64_MSR_STIMER3_COUNT HV_REGISTER_STIMER3_COUNT +#define HV_X64_MSR_STIMER3_CONFIG HV_REGISTER_STIMER3_CONFIG +#define HV_X64_MSR_SCONTROL HV_REGISTER_SCONTROL +#define HV_X64_MSR_SVERSION HV_REGISTER_SVERSION +#define HV_X64_MSR_SIMP HV_REGISTER_SIMP +#define HV_X64_MSR_SIEFP HV_REGISTER_SIEFP +#define HV_X64_MSR_VP_INDEX HV_REGISTER_VP_INDEX +#define HV_X64_MSR_EOM HV_REGISTER_EOM +#define HV_X64_MSR_SINT0 HV_REGISTER_SINT0 +#define HV_X64_MSR_SINT15 HV_REGISTER_SINT15 +#define HV_X64_MSR_CRASH_P0 HV_REGISTER_CRASH_P0 +#define HV_X64_MSR_CRASH_P1 HV_REGISTER_CRASH_P1 +#define HV_X64_MSR_CRASH_P2 HV_REGISTER_CRASH_P2 +#define HV_X64_MSR_CRASH_P3 HV_REGISTER_CRASH_P3 +#define HV_X64_MSR_CRASH_P4 HV_REGISTER_CRASH_P4 +#define HV_X64_MSR_CRASH_CTL HV_REGISTER_CRASH_CTL +#define HV_X64_MSR_TIME_REF_COUNT HV_REGISTER_TIME_REF_COUNT +#define HV_X64_MSR_REFERENCE_TSC HV_REGISTER_REFERENCE_TSC + /* * Declare the MSR used to setup pages used to communicate with the hypervisor. */ @@ -288,35 +314,6 @@ struct hv_tsc_emulation_status { #define HV_X64_MSR_TSC_REFERENCE_ENABLE 0x00000001 #define HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT 12 - -/* Define hypervisor message types. */ -enum hv_message_type { - HVMSG_NONE = 0x00000000, - - /* Memory access messages. */ - HVMSG_UNMAPPED_GPA = 0x80000000, - HVMSG_GPA_INTERCEPT = 0x80000001, - - /* Timer notification messages. */ - HVMSG_TIMER_EXPIRED = 0x80000010, - - /* Error messages. */ - HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020, - HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021, - HVMSG_UNSUPPORTED_FEATURE = 0x80000022, - - /* Trace buffer complete messages. */ - HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040, - - /* Platform-specific processor intercept messages. */ - HVMSG_X64_IOPORT_INTERCEPT = 0x80010000, - HVMSG_X64_MSR_INTERCEPT = 0x80010001, - HVMSG_X64_CPUID_INTERCEPT = 0x80010002, - HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, - HVMSG_X64_APIC_EOI = 0x80010004, - HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 -}; - struct hv_nested_enlightenments_control { struct { __u32 directhypercall:1; diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 5eb3bdf36a41984811cd4da8c3f1c9370912b2c6..e35e342673c72675cfbdd2b4a6acfac999b058a8 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -547,7 +547,7 @@ SYM_CODE_END(spurious_entries_start) /* * Dummy trap number so the low level ASM macro vector number checks do not * match which results in emitting plain IDTENTRY stubs without bells and - * whistels. + * whistles. */ #define X86_TRAP_OTHER 0xFFFF diff --git a/arch/x86/include/asm/intel_pconfig.h b/arch/x86/include/asm/intel_pconfig.h index 3cb002b1d0f930b3751d9a34b9e6720db5780415..994638ef171bec62782bdee78fe01061fa2acba6 100644 --- a/arch/x86/include/asm/intel_pconfig.h +++ b/arch/x86/include/asm/intel_pconfig.h @@ -38,7 +38,7 @@ enum pconfig_leaf { #define MKTME_INVALID_ENC_ALG 4 #define MKTME_DEVICE_BUSY 5 -/* Hardware requires the structure to be 256 byte alinged. Otherwise #GP(0). */ +/* Hardware requires the structure to be 256 byte aligned. Otherwise #GP(0). */ struct mktme_key_program { u16 keyid; u32 keyid_ctrl; diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h index 423b788f495e92ce8b059509c84feedbb66d9e37..ebe8d2ea44fe0973076f369273bf94394fcabf09 100644 --- a/arch/x86/include/asm/intel_pt.h +++ b/arch/x86/include/asm/intel_pt.h @@ -3,7 +3,7 @@ #define _ASM_X86_INTEL_PT_H #define PT_CPUID_LEAVES 2 -#define PT_CPUID_REGS_NUM 4 /* number of regsters (eax, ebx, ecx, edx) */ +#define PT_CPUID_REGS_NUM 4 /* number of registers (eax, ebx, ecx, edx) */ enum pt_capabilities { PT_CAP_max_subleaf = 0, diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index d726459d08e5a1f8eecb83bd0857e9fef793355f..841a5d104afaaca1ff4b3151b459c2f74ccef70d 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -159,7 +159,7 @@ static inline void *phys_to_virt(phys_addr_t address) /* * ISA I/O bus memory addresses are 1:1 with the physical address. * However, we truncate the address to unsigned int to avoid undesirable - * promitions in legacy drivers. + * promotions in legacy drivers. */ static inline unsigned int isa_virt_to_bus(volatile void *address) { diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h index 9b2a0ff76c73e215ca788300835f74462ded371e..562854c60808263798413e3b61b2cbaf230dfd11 100644 --- a/arch/x86/include/asm/irq_stack.h +++ b/arch/x86/include/asm/irq_stack.h @@ -190,7 +190,7 @@ /* * Macro to invoke __do_softirq on the irq stack. This is only called from - * task context when bottom halfs are about to be reenabled and soft + * task context when bottom halves are about to be reenabled and soft * interrupts are pending to be processed. The interrupt stack cannot be in * use here. */ diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 144d70ea43936b226787148b3c1fb7c917b30f6d..c5ce9845c999841797b0b479d3c5b85aa8638963 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -109,18 +109,13 @@ static __always_inline unsigned long arch_local_irq_save(void) } #else -#define ENABLE_INTERRUPTS(x) sti -#define DISABLE_INTERRUPTS(x) cli - #ifdef CONFIG_X86_64 #ifdef CONFIG_DEBUG_ENTRY -#define SAVE_FLAGS(x) pushfq; popq %rax +#define SAVE_FLAGS pushfq; popq %rax #endif #define INTERRUPT_RETURN jmp native_iret -#else -#define INTERRUPT_RETURN iret #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3768819693e5c8a59da539b8f2907c1c75c729db..10eca9e8f7f668e4457e8c95cf22fd0c068550fb 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1488,7 +1488,7 @@ extern u64 kvm_mce_cap_supported; /* * EMULTYPE_NO_DECODE - Set when re-emulating an instruction (after completing * userspace I/O) to indicate that the emulation context - * should be resued as is, i.e. skip initialization of + * should be reused as is, i.e. skip initialization of * emulation context, instruction fetch and decode. * * EMULTYPE_TRAP_UD - Set when emulating an intercepted #UD from hardware. @@ -1513,7 +1513,7 @@ extern u64 kvm_mce_cap_supported; * * EMULTYPE_VMWARE_GP - Set when emulating an intercepted #GP for VMware * backdoor emulation, which is opt in via module param. - * VMware backoor emulation handles select instructions + * VMware backdoor emulation handles select instructions * and reinjects the #GP for all other cases. * * EMULTYPE_PF - Set when emulating MMIO by way of an intercepted #PF, in which diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index ccf60a809a17957c744aeaac25cbd69570b6a666..67ff0d637e554129454977d71ca03fc98badbd27 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -9,70 +9,29 @@ #include <asm/hyperv-tlfs.h> #include <asm/nospec-branch.h> #include <asm/paravirt.h> +#include <asm/mshyperv.h> typedef int (*hyperv_fill_flush_list_func)( struct hv_guest_mapping_flush_list *flush, void *data); -#define hv_init_timer(timer, tick) \ - wrmsrl(HV_X64_MSR_STIMER0_COUNT + (2*timer), tick) -#define hv_init_timer_config(timer, val) \ - wrmsrl(HV_X64_MSR_STIMER0_CONFIG + (2*timer), val) - -#define hv_get_simp(val) rdmsrl(HV_X64_MSR_SIMP, val) -#define hv_set_simp(val) wrmsrl(HV_X64_MSR_SIMP, val) - -#define hv_get_siefp(val) rdmsrl(HV_X64_MSR_SIEFP, val) -#define hv_set_siefp(val) wrmsrl(HV_X64_MSR_SIEFP, val) - -#define hv_get_synic_state(val) rdmsrl(HV_X64_MSR_SCONTROL, val) -#define hv_set_synic_state(val) wrmsrl(HV_X64_MSR_SCONTROL, val) - -#define hv_get_vp_index(index) rdmsrl(HV_X64_MSR_VP_INDEX, index) - -#define hv_signal_eom() wrmsrl(HV_X64_MSR_EOM, 0) - -#define hv_get_synint_state(int_num, val) \ - rdmsrl(HV_X64_MSR_SINT0 + int_num, val) -#define hv_set_synint_state(int_num, val) \ - wrmsrl(HV_X64_MSR_SINT0 + int_num, val) -#define hv_recommend_using_aeoi() \ - (!(ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED)) +static inline void hv_set_register(unsigned int reg, u64 value) +{ + wrmsrl(reg, value); +} -#define hv_get_crash_ctl(val) \ - rdmsrl(HV_X64_MSR_CRASH_CTL, val) +static inline u64 hv_get_register(unsigned int reg) +{ + u64 value; -#define hv_get_time_ref_count(val) \ - rdmsrl(HV_X64_MSR_TIME_REF_COUNT, val) + rdmsrl(reg, value); + return value; +} -#define hv_get_reference_tsc(val) \ - rdmsrl(HV_X64_MSR_REFERENCE_TSC, val) -#define hv_set_reference_tsc(val) \ - wrmsrl(HV_X64_MSR_REFERENCE_TSC, val) -#define hv_set_clocksource_vdso(val) \ - ((val).vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK) -#define hv_enable_vdso_clocksource() \ - vclocks_set_used(VDSO_CLOCKMODE_HVCLOCK); #define hv_get_raw_timer() rdtsc_ordered() -#define hv_get_vector() HYPERVISOR_CALLBACK_VECTOR - -/* - * Reference to pv_ops must be inline so objtool - * detection of noinstr violations can work correctly. - */ -static __always_inline void hv_setup_sched_clock(void *sched_clock) -{ -#ifdef CONFIG_PARAVIRT - pv_ops.time.sched_clock = sched_clock; -#endif -} void hyperv_vector_handler(struct pt_regs *regs); -static inline void hv_enable_stimer0_percpu_irq(int irq) {} -static inline void hv_disable_stimer0_percpu_irq(int irq) {} - - #if IS_ENABLED(CONFIG_HYPERV) extern int hyperv_init_cpuhp; @@ -189,38 +148,6 @@ static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2) return hv_status; } -/* - * Rep hypercalls. Callers of this functions are supposed to ensure that - * rep_count and varhead_size comply with Hyper-V hypercall definition. - */ -static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, - void *input, void *output) -{ - u64 control = code; - u64 status; - u16 rep_comp; - - control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; - control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; - - do { - status = hv_do_hypercall(control, input, output); - if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) - return status; - - /* Bits 32-43 of status have 'Reps completed' data. */ - rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >> - HV_HYPERCALL_REP_COMP_OFFSET; - - control &= ~HV_HYPERCALL_REP_START_MASK; - control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; - - touch_nmi_watchdog(); - } while (rep_comp < rep_count); - - return status; -} - extern struct hv_vp_assist_page **hv_vp_assist_page; static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu) @@ -233,9 +160,6 @@ static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu) void __init hyperv_init(void); void hyperv_setup_mmu_ops(void); -void *hv_alloc_hyperv_page(void); -void *hv_alloc_hyperv_zeroed_page(void); -void hv_free_hyperv_page(unsigned long addr); void set_hv_tscchange_cb(void (*cb)(void)); void clear_hv_tscchange_cb(void); void hyperv_stop_tsc_emulation(void); @@ -272,8 +196,6 @@ int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); #else /* CONFIG_HYPERV */ static inline void hyperv_init(void) {} static inline void hyperv_setup_mmu_ops(void) {} -static inline void *hv_alloc_hyperv_page(void) { return NULL; } -static inline void hv_free_hyperv_page(unsigned long addr) {} static inline void set_hv_tscchange_cb(void (*cb)(void)) {} static inline void clear_hv_tscchange_cb(void) {} static inline void hyperv_stop_tsc_emulation(void) {}; diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 546d6ecf0a35b52a58196f07676058e59c301b62..fe335d8c1676fdc3e09e56d333d5da40cfe3c3ac 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -265,6 +265,7 @@ #define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ #define DEBUGCTLMSR_BTF_SHIFT 1 #define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ +#define DEBUGCTLMSR_BUS_LOCK_DETECT (1UL << 2) #define DEBUGCTLMSR_TR (1UL << 6) #define DEBUGCTLMSR_BTS (1UL << 7) #define DEBUGCTLMSR_BTINT (1UL << 8) @@ -628,8 +629,6 @@ #define MSR_IA32_APICBASE_ENABLE (1<<11) #define MSR_IA32_APICBASE_BASE (0xfffff<<12) -#define MSR_IA32_TSCDEADLINE 0x000006e0 - #define MSR_IA32_UCODE_WRITE 0x00000079 #define MSR_IA32_UCODE_REV 0x0000008b diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index cb9ad6b739737e4e36f47f3e93e0604f5a4c7713..c14fb80b9a07a47db41883ad37acef172ede8787 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -7,7 +7,6 @@ #include <linux/objtool.h> #include <asm/alternative.h> -#include <asm/alternative-asm.h> #include <asm/cpufeatures.h> #include <asm/msr-index.h> #include <asm/unwind_hints.h> @@ -33,7 +32,7 @@ /* * Google experimented with loop-unrolling and this turned out to be - * the optimal version — two calls, each with their own speculation + * the optimal version - two calls, each with their own speculation * trap should their return address end up getting used, in a loop. */ #define __FILL_RETURN_BUFFER(reg, nr, sp) \ diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 4abf110e224380b2514626c8753eedabb7e4d905..43992e5c52c243d8d400c471d0808887fcba9a8b 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -15,11 +15,20 @@ #include <linux/bug.h> #include <linux/types.h> #include <linux/cpumask.h> +#include <linux/static_call_types.h> #include <asm/frame.h> -static inline unsigned long long paravirt_sched_clock(void) +u64 dummy_steal_clock(int cpu); +u64 dummy_sched_clock(void); + +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); +DECLARE_STATIC_CALL(pv_sched_clock, dummy_sched_clock); + +void paravirt_set_sched_clock(u64 (*func)(void)); + +static inline u64 paravirt_sched_clock(void) { - return PVOP_CALL0(unsigned long long, time.sched_clock); + return static_call(pv_sched_clock)(); } struct static_key; @@ -33,9 +42,13 @@ bool pv_is_native_vcpu_is_preempted(void); static inline u64 paravirt_steal_clock(int cpu) { - return PVOP_CALL1(u64, time.steal_clock, cpu); + return static_call(pv_steal_clock)(cpu); } +#ifdef CONFIG_PARAVIRT_SPINLOCKS +void __init paravirt_set_cap(void); +#endif + /* The paravirtualized I/O functions */ static inline void slow_down_io(void) { @@ -122,7 +135,9 @@ static inline void write_cr0(unsigned long x) static inline unsigned long read_cr2(void) { - return PVOP_CALLEE0(unsigned long, mmu.read_cr2); + return PVOP_ALT_CALLEE0(unsigned long, mmu.read_cr2, + "mov %%cr2, %%rax;", + ALT_NOT(X86_FEATURE_XENPV)); } static inline void write_cr2(unsigned long x) @@ -132,12 +147,14 @@ static inline void write_cr2(unsigned long x) static inline unsigned long __read_cr3(void) { - return PVOP_CALL0(unsigned long, mmu.read_cr3); + return PVOP_ALT_CALL0(unsigned long, mmu.read_cr3, + "mov %%cr3, %%rax;", ALT_NOT(X86_FEATURE_XENPV)); } static inline void write_cr3(unsigned long x) { - PVOP_VCALL1(mmu.write_cr3, x); + PVOP_ALT_VCALL1(mmu.write_cr3, x, + "mov %%rdi, %%cr3", ALT_NOT(X86_FEATURE_XENPV)); } static inline void __write_cr4(unsigned long x) @@ -157,7 +174,7 @@ static inline void halt(void) static inline void wbinvd(void) { - PVOP_VCALL0(cpu.wbinvd); + PVOP_ALT_VCALL0(cpu.wbinvd, "wbinvd", ALT_NOT(X86_FEATURE_XENPV)); } static inline u64 paravirt_read_msr(unsigned msr) @@ -371,22 +388,28 @@ static inline void paravirt_release_p4d(unsigned long pfn) static inline pte_t __pte(pteval_t val) { - return (pte_t) { PVOP_CALLEE1(pteval_t, mmu.make_pte, val) }; + return (pte_t) { PVOP_ALT_CALLEE1(pteval_t, mmu.make_pte, val, + "mov %%rdi, %%rax", + ALT_NOT(X86_FEATURE_XENPV)) }; } static inline pteval_t pte_val(pte_t pte) { - return PVOP_CALLEE1(pteval_t, mmu.pte_val, pte.pte); + return PVOP_ALT_CALLEE1(pteval_t, mmu.pte_val, pte.pte, + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); } static inline pgd_t __pgd(pgdval_t val) { - return (pgd_t) { PVOP_CALLEE1(pgdval_t, mmu.make_pgd, val) }; + return (pgd_t) { PVOP_ALT_CALLEE1(pgdval_t, mmu.make_pgd, val, + "mov %%rdi, %%rax", + ALT_NOT(X86_FEATURE_XENPV)) }; } static inline pgdval_t pgd_val(pgd_t pgd) { - return PVOP_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd); + return PVOP_ALT_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd, + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); } #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION @@ -419,12 +442,15 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) static inline pmd_t __pmd(pmdval_t val) { - return (pmd_t) { PVOP_CALLEE1(pmdval_t, mmu.make_pmd, val) }; + return (pmd_t) { PVOP_ALT_CALLEE1(pmdval_t, mmu.make_pmd, val, + "mov %%rdi, %%rax", + ALT_NOT(X86_FEATURE_XENPV)) }; } static inline pmdval_t pmd_val(pmd_t pmd) { - return PVOP_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd); + return PVOP_ALT_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd, + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); } static inline void set_pud(pud_t *pudp, pud_t pud) @@ -436,14 +462,16 @@ static inline pud_t __pud(pudval_t val) { pudval_t ret; - ret = PVOP_CALLEE1(pudval_t, mmu.make_pud, val); + ret = PVOP_ALT_CALLEE1(pudval_t, mmu.make_pud, val, + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); return (pud_t) { ret }; } static inline pudval_t pud_val(pud_t pud) { - return PVOP_CALLEE1(pudval_t, mmu.pud_val, pud.pud); + return PVOP_ALT_CALLEE1(pudval_t, mmu.pud_val, pud.pud, + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); } static inline void pud_clear(pud_t *pudp) @@ -462,14 +490,17 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) static inline p4d_t __p4d(p4dval_t val) { - p4dval_t ret = PVOP_CALLEE1(p4dval_t, mmu.make_p4d, val); + p4dval_t ret = PVOP_ALT_CALLEE1(p4dval_t, mmu.make_p4d, val, + "mov %%rdi, %%rax", + ALT_NOT(X86_FEATURE_XENPV)); return (p4d_t) { ret }; } static inline p4dval_t p4d_val(p4d_t p4d) { - return PVOP_CALLEE1(p4dval_t, mmu.p4d_val, p4d.p4d); + return PVOP_ALT_CALLEE1(p4dval_t, mmu.p4d_val, p4d.p4d, + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); } static inline void __set_pgd(pgd_t *pgdp, pgd_t pgd) @@ -556,7 +587,9 @@ static __always_inline void pv_queued_spin_lock_slowpath(struct qspinlock *lock, static __always_inline void pv_queued_spin_unlock(struct qspinlock *lock) { - PVOP_VCALLEE1(lock.queued_spin_unlock, lock); + PVOP_ALT_VCALLEE1(lock.queued_spin_unlock, lock, + "movb $0, (%%" _ASM_ARG1 ");", + ALT_NOT(X86_FEATURE_PVUNLOCK)); } static __always_inline void pv_wait(u8 *ptr, u8 val) @@ -571,7 +604,9 @@ static __always_inline void pv_kick(int cpu) static __always_inline bool pv_vcpu_is_preempted(long cpu) { - return PVOP_CALLEE1(bool, lock.vcpu_is_preempted, cpu); + return PVOP_ALT_CALLEE1(bool, lock.vcpu_is_preempted, cpu, + "xor %%" _ASM_AX ", %%" _ASM_AX ";", + ALT_NOT(X86_FEATURE_VCPUPREEMPT)); } void __raw_callee_save___native_queued_spin_unlock(struct qspinlock *lock); @@ -645,17 +680,18 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu); #ifdef CONFIG_PARAVIRT_XXL static inline notrace unsigned long arch_local_save_flags(void) { - return PVOP_CALLEE0(unsigned long, irq.save_fl); + return PVOP_ALT_CALLEE0(unsigned long, irq.save_fl, "pushf; pop %%rax;", + ALT_NOT(X86_FEATURE_XENPV)); } static inline notrace void arch_local_irq_disable(void) { - PVOP_VCALLEE0(irq.irq_disable); + PVOP_ALT_VCALLEE0(irq.irq_disable, "cli;", ALT_NOT(X86_FEATURE_XENPV)); } static inline notrace void arch_local_irq_enable(void) { - PVOP_VCALLEE0(irq.irq_enable); + PVOP_ALT_VCALLEE0(irq.irq_enable, "sti;", ALT_NOT(X86_FEATURE_XENPV)); } static inline notrace unsigned long arch_local_irq_save(void) @@ -700,84 +736,27 @@ extern void default_banner(void); .popsection -#define COND_PUSH(set, mask, reg) \ - .if ((~(set)) & mask); push %reg; .endif -#define COND_POP(set, mask, reg) \ - .if ((~(set)) & mask); pop %reg; .endif - #ifdef CONFIG_X86_64 - -#define PV_SAVE_REGS(set) \ - COND_PUSH(set, CLBR_RAX, rax); \ - COND_PUSH(set, CLBR_RCX, rcx); \ - COND_PUSH(set, CLBR_RDX, rdx); \ - COND_PUSH(set, CLBR_RSI, rsi); \ - COND_PUSH(set, CLBR_RDI, rdi); \ - COND_PUSH(set, CLBR_R8, r8); \ - COND_PUSH(set, CLBR_R9, r9); \ - COND_PUSH(set, CLBR_R10, r10); \ - COND_PUSH(set, CLBR_R11, r11) -#define PV_RESTORE_REGS(set) \ - COND_POP(set, CLBR_R11, r11); \ - COND_POP(set, CLBR_R10, r10); \ - COND_POP(set, CLBR_R9, r9); \ - COND_POP(set, CLBR_R8, r8); \ - COND_POP(set, CLBR_RDI, rdi); \ - COND_POP(set, CLBR_RSI, rsi); \ - COND_POP(set, CLBR_RDX, rdx); \ - COND_POP(set, CLBR_RCX, rcx); \ - COND_POP(set, CLBR_RAX, rax) +#ifdef CONFIG_PARAVIRT_XXL #define PARA_PATCH(off) ((off) / 8) #define PARA_SITE(ptype, ops) _PVSITE(ptype, ops, .quad, 8) #define PARA_INDIRECT(addr) *addr(%rip) -#else -#define PV_SAVE_REGS(set) \ - COND_PUSH(set, CLBR_EAX, eax); \ - COND_PUSH(set, CLBR_EDI, edi); \ - COND_PUSH(set, CLBR_ECX, ecx); \ - COND_PUSH(set, CLBR_EDX, edx) -#define PV_RESTORE_REGS(set) \ - COND_POP(set, CLBR_EDX, edx); \ - COND_POP(set, CLBR_ECX, ecx); \ - COND_POP(set, CLBR_EDI, edi); \ - COND_POP(set, CLBR_EAX, eax) - -#define PARA_PATCH(off) ((off) / 4) -#define PARA_SITE(ptype, ops) _PVSITE(ptype, ops, .long, 4) -#define PARA_INDIRECT(addr) *%cs:addr -#endif -#ifdef CONFIG_PARAVIRT_XXL #define INTERRUPT_RETURN \ - PARA_SITE(PARA_PATCH(PV_CPU_iret), \ - ANNOTATE_RETPOLINE_SAFE; \ - jmp PARA_INDIRECT(pv_ops+PV_CPU_iret);) - -#define DISABLE_INTERRUPTS(clobbers) \ - PARA_SITE(PARA_PATCH(PV_IRQ_irq_disable), \ - PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ - ANNOTATE_RETPOLINE_SAFE; \ - call PARA_INDIRECT(pv_ops+PV_IRQ_irq_disable); \ - PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) - -#define ENABLE_INTERRUPTS(clobbers) \ - PARA_SITE(PARA_PATCH(PV_IRQ_irq_enable), \ - PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ - ANNOTATE_RETPOLINE_SAFE; \ - call PARA_INDIRECT(pv_ops+PV_IRQ_irq_enable); \ - PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) -#endif + ANNOTATE_RETPOLINE_SAFE; \ + ALTERNATIVE_TERNARY("jmp *paravirt_iret(%rip);", \ + X86_FEATURE_XENPV, "jmp xen_iret;", "jmp native_iret;") -#ifdef CONFIG_X86_64 -#ifdef CONFIG_PARAVIRT_XXL #ifdef CONFIG_DEBUG_ENTRY -#define SAVE_FLAGS(clobbers) \ - PARA_SITE(PARA_PATCH(PV_IRQ_save_fl), \ - PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ - ANNOTATE_RETPOLINE_SAFE; \ - call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl); \ - PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) +.macro PARA_IRQ_save_fl + PARA_SITE(PARA_PATCH(PV_IRQ_save_fl), + ANNOTATE_RETPOLINE_SAFE; + call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl);) +.endm + +#define SAVE_FLAGS ALTERNATIVE "PARA_IRQ_save_fl;", "pushf; pop %rax;", \ + ALT_NOT(X86_FEATURE_XENPV) #endif #endif /* CONFIG_PARAVIRT_XXL */ #endif /* CONFIG_X86_64 */ @@ -800,5 +779,11 @@ static inline void paravirt_arch_exit_mmap(struct mm_struct *mm) { } #endif + +#ifndef CONFIG_PARAVIRT_SPINLOCKS +static inline void paravirt_set_cap(void) +{ +} +#endif #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_PARAVIRT_H */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index de87087d3bde16ac6a062536ebad122541acc7ad..ae692c3194e9e5e9758d171649a2ee5496f6a7cb 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -3,7 +3,6 @@ #define _ASM_X86_PARAVIRT_TYPES_H /* Bitmask of what can be clobbered: usually at least eax. */ -#define CLBR_NONE 0 #define CLBR_EAX (1 << 0) #define CLBR_ECX (1 << 1) #define CLBR_EDX (1 << 2) @@ -15,7 +14,6 @@ #define CLBR_ARG_REGS (CLBR_EAX | CLBR_EDX | CLBR_ECX) #define CLBR_RET_REG (CLBR_EAX | CLBR_EDX) -#define CLBR_SCRATCH (0) #else #define CLBR_RAX CLBR_EAX #define CLBR_RCX CLBR_ECX @@ -32,12 +30,9 @@ #define CLBR_ARG_REGS (CLBR_RDI | CLBR_RSI | CLBR_RDX | \ CLBR_RCX | CLBR_R8 | CLBR_R9) #define CLBR_RET_REG (CLBR_RAX) -#define CLBR_SCRATCH (CLBR_R10 | CLBR_R11) #endif /* X86_64 */ -#define CLBR_CALLEE_SAVE ((CLBR_ARG_REGS | CLBR_SCRATCH) & ~CLBR_RET_REG) - #ifndef __ASSEMBLY__ #include <asm/desc_defs.h> @@ -73,19 +68,6 @@ struct pv_info { const char *name; }; -struct pv_init_ops { - /* - * Patch may replace one of the defined code sequences with - * arbitrary code, subject to the same register constraints. - * This generally means the code is not free to clobber any - * registers other than EAX. The patch function should return - * the number of bytes of code generated, as we nop pad the - * rest in generic code. - */ - unsigned (*patch)(u8 type, void *insn_buff, - unsigned long addr, unsigned len); -} __no_randomize_layout; - #ifdef CONFIG_PARAVIRT_XXL struct pv_lazy_ops { /* Set deferred update mode, used for batching operations. */ @@ -95,11 +77,6 @@ struct pv_lazy_ops { } __no_randomize_layout; #endif -struct pv_time_ops { - unsigned long long (*sched_clock)(void); - unsigned long long (*steal_clock)(int cpu); -} __no_randomize_layout; - struct pv_cpu_ops { /* hooks for various privileged instructions */ void (*io_delay)(void); @@ -156,10 +133,6 @@ struct pv_cpu_ops { u64 (*read_pmc)(int counter); - /* Normal iret. Jump to this with the standard iret stack - frame set up. */ - void (*iret)(void); - void (*start_context_switch)(struct task_struct *prev); void (*end_context_switch)(struct task_struct *next); #endif @@ -290,8 +263,6 @@ struct pv_lock_ops { * number for each function using the offset which we use to indicate * what to patch. */ struct paravirt_patch_template { - struct pv_init_ops init; - struct pv_time_ops time; struct pv_cpu_ops cpu; struct pv_irq_ops irq; struct pv_mmu_ops mmu; @@ -300,6 +271,7 @@ struct paravirt_patch_template { extern struct pv_info pv_info; extern struct paravirt_patch_template pv_ops; +extern void (*paravirt_iret)(void); #define PARAVIRT_PATCH(x) \ (offsetof(struct paravirt_patch_template, x) / sizeof(void *)) @@ -331,11 +303,7 @@ extern struct paravirt_patch_template pv_ops; /* Simple instruction patching code. */ #define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t" -unsigned paravirt_patch_ident_64(void *insn_buff, unsigned len); -unsigned paravirt_patch_default(u8 type, void *insn_buff, unsigned long addr, unsigned len); -unsigned paravirt_patch_insns(void *insn_buff, unsigned len, const char *start, const char *end); - -unsigned native_patch(u8 type, void *insn_buff, unsigned long addr, unsigned len); +unsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr, unsigned int len); int paravirt_disable_iospace(void); @@ -371,7 +339,7 @@ int paravirt_disable_iospace(void); * on the stack. All caller-save registers (eax,edx,ecx) are expected * to be modified (either clobbered or used for return values). * X86_64, on the other hand, already specifies a register-based calling - * conventions, returning at %rax, with parameteres going on %rdi, %rsi, + * conventions, returning at %rax, with parameters going on %rdi, %rsi, * %rdx, and %rcx. Note that for this reason, x86_64 does not need any * special handling for dealing with 4 arguments, unlike i386. * However, x86_64 also have to clobber all caller saved registers, which @@ -414,11 +382,9 @@ int paravirt_disable_iospace(void); * makes sure the incoming and outgoing types are always correct. */ #ifdef CONFIG_X86_32 -#define PVOP_VCALL_ARGS \ +#define PVOP_CALL_ARGS \ unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx; -#define PVOP_CALL_ARGS PVOP_VCALL_ARGS - #define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x)) #define PVOP_CALL_ARG2(x) "d" ((unsigned long)(x)) #define PVOP_CALL_ARG3(x) "c" ((unsigned long)(x)) @@ -434,12 +400,10 @@ int paravirt_disable_iospace(void); #define VEXTRA_CLOBBERS #else /* CONFIG_X86_64 */ /* [re]ax isn't an arg, but the return val */ -#define PVOP_VCALL_ARGS \ +#define PVOP_CALL_ARGS \ unsigned long __edi = __edi, __esi = __esi, \ __edx = __edx, __ecx = __ecx, __eax = __eax; -#define PVOP_CALL_ARGS PVOP_VCALL_ARGS - #define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x)) #define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x)) #define PVOP_CALL_ARG3(x) "d" ((unsigned long)(x)) @@ -464,152 +428,138 @@ int paravirt_disable_iospace(void); #define PVOP_TEST_NULL(op) ((void)pv_ops.op) #endif -#define PVOP_RETMASK(rettype) \ +#define PVOP_RETVAL(rettype) \ ({ unsigned long __mask = ~0UL; \ + BUILD_BUG_ON(sizeof(rettype) > sizeof(unsigned long)); \ switch (sizeof(rettype)) { \ case 1: __mask = 0xffUL; break; \ case 2: __mask = 0xffffUL; break; \ case 4: __mask = 0xffffffffUL; break; \ default: break; \ } \ - __mask; \ + __mask & __eax; \ }) -#define ____PVOP_CALL(rettype, op, clbr, call_clbr, extra_clbr, \ - pre, post, ...) \ +#define ____PVOP_CALL(ret, op, clbr, call_clbr, extra_clbr, ...) \ ({ \ - rettype __ret; \ PVOP_CALL_ARGS; \ PVOP_TEST_NULL(op); \ - /* This is 32-bit specific, but is okay in 64-bit */ \ - /* since this condition will never hold */ \ - if (sizeof(rettype) > sizeof(unsigned long)) { \ - asm volatile(pre \ - paravirt_alt(PARAVIRT_CALL) \ - post \ - : call_clbr, ASM_CALL_CONSTRAINT \ - : paravirt_type(op), \ - paravirt_clobber(clbr), \ - ##__VA_ARGS__ \ - : "memory", "cc" extra_clbr); \ - __ret = (rettype)((((u64)__edx) << 32) | __eax); \ - } else { \ - asm volatile(pre \ - paravirt_alt(PARAVIRT_CALL) \ - post \ - : call_clbr, ASM_CALL_CONSTRAINT \ - : paravirt_type(op), \ - paravirt_clobber(clbr), \ - ##__VA_ARGS__ \ - : "memory", "cc" extra_clbr); \ - __ret = (rettype)(__eax & PVOP_RETMASK(rettype)); \ - } \ - __ret; \ + asm volatile(paravirt_alt(PARAVIRT_CALL) \ + : call_clbr, ASM_CALL_CONSTRAINT \ + : paravirt_type(op), \ + paravirt_clobber(clbr), \ + ##__VA_ARGS__ \ + : "memory", "cc" extra_clbr); \ + ret; \ }) -#define __PVOP_CALL(rettype, op, pre, post, ...) \ - ____PVOP_CALL(rettype, op, CLBR_ANY, PVOP_CALL_CLOBBERS, \ - EXTRA_CLOBBERS, pre, post, ##__VA_ARGS__) - -#define __PVOP_CALLEESAVE(rettype, op, pre, post, ...) \ - ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \ - PVOP_CALLEE_CLOBBERS, , \ - pre, post, ##__VA_ARGS__) - - -#define ____PVOP_VCALL(op, clbr, call_clbr, extra_clbr, pre, post, ...) \ +#define ____PVOP_ALT_CALL(ret, op, alt, cond, clbr, call_clbr, \ + extra_clbr, ...) \ ({ \ - PVOP_VCALL_ARGS; \ + PVOP_CALL_ARGS; \ PVOP_TEST_NULL(op); \ - asm volatile(pre \ - paravirt_alt(PARAVIRT_CALL) \ - post \ + asm volatile(ALTERNATIVE(paravirt_alt(PARAVIRT_CALL), \ + alt, cond) \ : call_clbr, ASM_CALL_CONSTRAINT \ : paravirt_type(op), \ paravirt_clobber(clbr), \ ##__VA_ARGS__ \ : "memory", "cc" extra_clbr); \ + ret; \ }) -#define __PVOP_VCALL(op, pre, post, ...) \ - ____PVOP_VCALL(op, CLBR_ANY, PVOP_VCALL_CLOBBERS, \ - VEXTRA_CLOBBERS, \ - pre, post, ##__VA_ARGS__) +#define __PVOP_CALL(rettype, op, ...) \ + ____PVOP_CALL(PVOP_RETVAL(rettype), op, CLBR_ANY, \ + PVOP_CALL_CLOBBERS, EXTRA_CLOBBERS, ##__VA_ARGS__) + +#define __PVOP_ALT_CALL(rettype, op, alt, cond, ...) \ + ____PVOP_ALT_CALL(PVOP_RETVAL(rettype), op, alt, cond, CLBR_ANY,\ + PVOP_CALL_CLOBBERS, EXTRA_CLOBBERS, \ + ##__VA_ARGS__) + +#define __PVOP_CALLEESAVE(rettype, op, ...) \ + ____PVOP_CALL(PVOP_RETVAL(rettype), op.func, CLBR_RET_REG, \ + PVOP_CALLEE_CLOBBERS, , ##__VA_ARGS__) + +#define __PVOP_ALT_CALLEESAVE(rettype, op, alt, cond, ...) \ + ____PVOP_ALT_CALL(PVOP_RETVAL(rettype), op.func, alt, cond, \ + CLBR_RET_REG, PVOP_CALLEE_CLOBBERS, , ##__VA_ARGS__) + + +#define __PVOP_VCALL(op, ...) \ + (void)____PVOP_CALL(, op, CLBR_ANY, PVOP_VCALL_CLOBBERS, \ + VEXTRA_CLOBBERS, ##__VA_ARGS__) + +#define __PVOP_ALT_VCALL(op, alt, cond, ...) \ + (void)____PVOP_ALT_CALL(, op, alt, cond, CLBR_ANY, \ + PVOP_VCALL_CLOBBERS, VEXTRA_CLOBBERS, \ + ##__VA_ARGS__) -#define __PVOP_VCALLEESAVE(op, pre, post, ...) \ - ____PVOP_VCALL(op.func, CLBR_RET_REG, \ - PVOP_VCALLEE_CLOBBERS, , \ - pre, post, ##__VA_ARGS__) +#define __PVOP_VCALLEESAVE(op, ...) \ + (void)____PVOP_CALL(, op.func, CLBR_RET_REG, \ + PVOP_VCALLEE_CLOBBERS, , ##__VA_ARGS__) +#define __PVOP_ALT_VCALLEESAVE(op, alt, cond, ...) \ + (void)____PVOP_ALT_CALL(, op.func, alt, cond, CLBR_RET_REG, \ + PVOP_VCALLEE_CLOBBERS, , ##__VA_ARGS__) #define PVOP_CALL0(rettype, op) \ - __PVOP_CALL(rettype, op, "", "") + __PVOP_CALL(rettype, op) #define PVOP_VCALL0(op) \ - __PVOP_VCALL(op, "", "") + __PVOP_VCALL(op) +#define PVOP_ALT_CALL0(rettype, op, alt, cond) \ + __PVOP_ALT_CALL(rettype, op, alt, cond) +#define PVOP_ALT_VCALL0(op, alt, cond) \ + __PVOP_ALT_VCALL(op, alt, cond) #define PVOP_CALLEE0(rettype, op) \ - __PVOP_CALLEESAVE(rettype, op, "", "") + __PVOP_CALLEESAVE(rettype, op) #define PVOP_VCALLEE0(op) \ - __PVOP_VCALLEESAVE(op, "", "") + __PVOP_VCALLEESAVE(op) +#define PVOP_ALT_CALLEE0(rettype, op, alt, cond) \ + __PVOP_ALT_CALLEESAVE(rettype, op, alt, cond) +#define PVOP_ALT_VCALLEE0(op, alt, cond) \ + __PVOP_ALT_VCALLEESAVE(op, alt, cond) #define PVOP_CALL1(rettype, op, arg1) \ - __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1)) + __PVOP_CALL(rettype, op, PVOP_CALL_ARG1(arg1)) #define PVOP_VCALL1(op, arg1) \ - __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1)) + __PVOP_VCALL(op, PVOP_CALL_ARG1(arg1)) +#define PVOP_ALT_VCALL1(op, arg1, alt, cond) \ + __PVOP_ALT_VCALL(op, alt, cond, PVOP_CALL_ARG1(arg1)) #define PVOP_CALLEE1(rettype, op, arg1) \ - __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1)) + __PVOP_CALLEESAVE(rettype, op, PVOP_CALL_ARG1(arg1)) #define PVOP_VCALLEE1(op, arg1) \ - __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1)) + __PVOP_VCALLEESAVE(op, PVOP_CALL_ARG1(arg1)) +#define PVOP_ALT_CALLEE1(rettype, op, arg1, alt, cond) \ + __PVOP_ALT_CALLEESAVE(rettype, op, alt, cond, PVOP_CALL_ARG1(arg1)) +#define PVOP_ALT_VCALLEE1(op, arg1, alt, cond) \ + __PVOP_ALT_VCALLEESAVE(op, alt, cond, PVOP_CALL_ARG1(arg1)) #define PVOP_CALL2(rettype, op, arg1, arg2) \ - __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) + __PVOP_CALL(rettype, op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2)) #define PVOP_VCALL2(op, arg1, arg2) \ - __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) - -#define PVOP_CALLEE2(rettype, op, arg1, arg2) \ - __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) -#define PVOP_VCALLEE2(op, arg1, arg2) \ - __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) - + __PVOP_VCALL(op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2)) #define PVOP_CALL3(rettype, op, arg1, arg2, arg3) \ - __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ + __PVOP_CALL(rettype, op, PVOP_CALL_ARG1(arg1), \ PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3)) #define PVOP_VCALL3(op, arg1, arg2, arg3) \ - __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \ + __PVOP_VCALL(op, PVOP_CALL_ARG1(arg1), \ PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3)) -/* This is the only difference in x86_64. We can make it much simpler */ -#ifdef CONFIG_X86_32 #define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \ __PVOP_CALL(rettype, op, \ - "push %[_arg4];", "lea 4(%%esp),%%esp;", \ - PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ - PVOP_CALL_ARG3(arg3), [_arg4] "mr" ((u32)(arg4))) -#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \ - __PVOP_VCALL(op, \ - "push %[_arg4];", "lea 4(%%esp),%%esp;", \ - "0" ((u32)(arg1)), "1" ((u32)(arg2)), \ - "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4))) -#else -#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \ - __PVOP_CALL(rettype, op, "", "", \ PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) #define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \ - __PVOP_VCALL(op, "", "", \ - PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ + __PVOP_VCALL(op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) -#endif /* Lazy mode for batching updates / context switch */ enum paravirt_lazy_mode { diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index a02c67291cfcbdf69048030323e1c4d4f2aee907..b1099f2d9800c7e2fe7873bbda7172fd72fdde90 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -1244,7 +1244,7 @@ static inline p4d_t *user_to_kernel_p4dp(p4d_t *p4dp) /* * clone_pgd_range(pgd_t *dst, pgd_t *src, int count); * - * dst - pointer to pgd range anwhere on a pgd page + * dst - pointer to pgd range anywhere on a pgd page * src - "" * count - the number of pgds to copy. * diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index f1b9ed5efaa9016275cbd520e310a8f74e1801d9..185142b84ebe8fa96d289aa794d0509c1cc3c4ce 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -314,11 +314,6 @@ struct x86_hw_tss { struct x86_hw_tss { u32 reserved1; u64 sp0; - - /* - * We store cpu_current_top_of_stack in sp1 so it's always accessible. - * Linux does not use ring 1, so sp1 is not otherwise needed. - */ u64 sp1; /* @@ -426,12 +421,7 @@ struct irq_stack { char stack[IRQ_STACK_SIZE]; } __aligned(IRQ_STACK_SIZE); -#ifdef CONFIG_X86_32 DECLARE_PER_CPU(unsigned long, cpu_current_top_of_stack); -#else -/* The RO copy can't be accessed with this_cpu_xyz(), so use the RW copy. */ -#define cpu_current_top_of_stack cpu_tss_rw.x86_tss.sp1 -#endif #ifdef CONFIG_X86_64 struct fixed_percpu_data { @@ -527,7 +517,7 @@ struct thread_struct { struct io_bitmap *io_bitmap; /* - * IOPL. Priviledge level dependent I/O permission which is + * IOPL. Privilege level dependent I/O permission which is * emulated via the I/O bitmap to prevent user space from disabling * interrupts. */ diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h index b6a9d51d1d7911894fa6b831b2f01a05f1daf57f..8c5d1910a848f25091711eb675f400dc6f8270f7 100644 --- a/arch/x86/include/asm/proto.h +++ b/arch/x86/include/asm/proto.h @@ -4,6 +4,8 @@ #include <asm/ldt.h> +struct task_struct; + /* misc architecture specific prototypes */ void syscall_init(void); diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h index 4352f08bfbb54b405a0c18d945362211b94cda15..43fa081a1adb236daf9c2f4de4e89616285ed40f 100644 --- a/arch/x86/include/asm/set_memory.h +++ b/arch/x86/include/asm/set_memory.h @@ -8,8 +8,8 @@ /* * The set_memory_* API can be used to change various attributes of a virtual * address range. The attributes include: - * Cachability : UnCached, WriteCombining, WriteThrough, WriteBack - * Executability : eXeutable, NoteXecutable + * Cacheability : UnCached, WriteCombining, WriteThrough, WriteBack + * Executability : eXecutable, NoteXecutable * Read/Write : ReadOnly, ReadWrite * Presence : NotPresent * Encryption : Encrypted, Decrypted diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 389d851a02c4fd55cab18a10b4d277bb12b093ab..a12458a7a8d4af15b9380a0d4cc336a6d1c80723 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -130,11 +130,6 @@ void *extend_brk(size_t size, size_t align); : : "i" (sz)); \ } -/* Helper for reserving space for arrays of things */ -#define RESERVE_BRK_ARRAY(type, name, entries) \ - type *name; \ - RESERVE_BRK(name, sizeof(type) * entries) - extern void probe_roms(void); #ifdef __i386__ diff --git a/arch/x86/kernel/cpu/sgx/arch.h b/arch/x86/include/asm/sgx.h similarity index 89% rename from arch/x86/kernel/cpu/sgx/arch.h rename to arch/x86/include/asm/sgx.h index dd7602c44c72636a2787b4ec52df500b5d81d57d..9c31e0ebc55b14ed0ecce56f17e42636d5f2a7eb 100644 --- a/arch/x86/kernel/cpu/sgx/arch.h +++ b/arch/x86/include/asm/sgx.h @@ -2,15 +2,20 @@ /** * Copyright(c) 2016-20 Intel Corporation. * - * Contains data structures defined by the SGX architecture. Data structures - * defined by the Linux software stack should not be placed here. + * Intel Software Guard Extensions (SGX) support. */ -#ifndef _ASM_X86_SGX_ARCH_H -#define _ASM_X86_SGX_ARCH_H +#ifndef _ASM_X86_SGX_H +#define _ASM_X86_SGX_H #include <linux/bits.h> #include <linux/types.h> +/* + * This file contains both data structures defined by SGX architecture and Linux + * defined software data structures and functions. The two should not be mixed + * together for better readibility. The architectural definitions come first. + */ + /* The SGX specific CPUID function. */ #define SGX_CPUID 0x12 /* EPC enumeration. */ @@ -22,16 +27,36 @@ /* The bitmask for the EPC section type. */ #define SGX_CPUID_EPC_MASK GENMASK(3, 0) +enum sgx_encls_function { + ECREATE = 0x00, + EADD = 0x01, + EINIT = 0x02, + EREMOVE = 0x03, + EDGBRD = 0x04, + EDGBWR = 0x05, + EEXTEND = 0x06, + ELDU = 0x08, + EBLOCK = 0x09, + EPA = 0x0A, + EWB = 0x0B, + ETRACK = 0x0C, + EAUG = 0x0D, + EMODPR = 0x0E, + EMODT = 0x0F, +}; + /** * enum sgx_return_code - The return code type for ENCLS, ENCLU and ENCLV * %SGX_NOT_TRACKED: Previous ETRACK's shootdown sequence has not * been completed yet. + * %SGX_CHILD_PRESENT SECS has child pages present in the EPC. * %SGX_INVALID_EINITTOKEN: EINITTOKEN is invalid and enclave signer's * public key does not match IA32_SGXLEPUBKEYHASH. * %SGX_UNMASKED_EVENT: An unmasked event, e.g. INTR, was received */ enum sgx_return_code { SGX_NOT_TRACKED = 11, + SGX_CHILD_PRESENT = 13, SGX_INVALID_EINITTOKEN = 16, SGX_UNMASKED_EVENT = 128, }; @@ -271,7 +296,7 @@ struct sgx_pcmd { * @header1: constant byte string * @vendor: must be either 0x0000 or 0x8086 * @date: YYYYMMDD in BCD - * @header2: costant byte string + * @header2: constant byte string * @swdefined: software defined value */ struct sgx_sigstruct_header { @@ -335,4 +360,19 @@ struct sgx_sigstruct { #define SGX_LAUNCH_TOKEN_SIZE 304 -#endif /* _ASM_X86_SGX_ARCH_H */ +/* + * Do not put any hardware-defined SGX structure representations below this + * comment! + */ + +#ifdef CONFIG_X86_SGX_KVM +int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs, + int *trapnr); +int sgx_virt_einit(void __user *sigstruct, void __user *token, + void __user *secs, u64 *lepubkeyhash, int *trapnr); +#endif + +int sgx_set_attribute(unsigned long *allowed_attributes, + unsigned int attribute_fd); + +#endif /* _ASM_X86_SGX_H */ diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h index 0bc9b0895f33e5a65c9f4304ae6d92fafade2394..d17b39893b7973073f21814e41d841aed5fec11a 100644 --- a/arch/x86/include/asm/smap.h +++ b/arch/x86/include/asm/smap.h @@ -11,6 +11,7 @@ #include <asm/nops.h> #include <asm/cpufeatures.h> +#include <asm/alternative.h> /* "Raw" instruction opcodes */ #define __ASM_CLAC ".byte 0x0f,0x01,0xca" @@ -18,8 +19,6 @@ #ifdef __ASSEMBLY__ -#include <asm/alternative-asm.h> - #ifdef CONFIG_X86_SMAP #define ASM_CLAC \ @@ -37,8 +36,6 @@ #else /* __ASSEMBLY__ */ -#include <asm/alternative.h> - #ifdef CONFIG_X86_SMAP static __always_inline void clac(void) diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index 9f69cc497f4b68f3f49029f5b2b7a3209d8d890e..b5f0d2ff47e47366d0df6f0987cd1e4e2ea82adf 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -71,12 +71,7 @@ static inline void update_task_stack(struct task_struct *task) else this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0); #else - /* - * x86-64 updates x86_tss.sp1 via cpu_current_top_of_stack. That - * doesn't work on x86-32 because sp1 and - * cpu_current_top_of_stack have different values (because of - * the non-zero stack-padding on 32bit). - */ + /* Xen PV enters the kernel on the thread stack. */ if (static_cpu_has(X86_FEATURE_XENPV)) load_sp0(task_top_of_stack(task)); #endif diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h index a84333adeef232aa4d38f10d8ec1af7c1155ddb7..80c08c7d5e72e44d850cfa206598287e28df8150 100644 --- a/arch/x86/include/asm/syscall_wrapper.h +++ b/arch/x86/include/asm/syscall_wrapper.h @@ -80,6 +80,7 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); } #define __COND_SYSCALL(abi, name) \ + __weak long __##abi##_##name(const struct pt_regs *__unused); \ __weak long __##abi##_##name(const struct pt_regs *__unused) \ { \ return sys_ni_syscall(); \ diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 06b740bae431d2a0b4a163553e548dc5d64d7c0d..de406d93b515dbc7b93f31f17ece2334ea3b4443 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -197,13 +197,7 @@ static inline int arch_within_stack_frames(const void * const stack, #endif } -#else /* !__ASSEMBLY__ */ - -#ifdef CONFIG_X86_64 -# define cpu_current_top_of_stack (cpu_tss_rw + TSS_sp1) -#endif - -#endif +#endif /* !__ASSEMBLY__ */ /* * Thread-synchronous status. diff --git a/arch/x86/include/asm/uv/uv_geo.h b/arch/x86/include/asm/uv/uv_geo.h index f241451035fb2b4c9a721198312255dafe3139be..027a9258dbca482ae69ce099274c097734648149 100644 --- a/arch/x86/include/asm/uv/uv_geo.h +++ b/arch/x86/include/asm/uv/uv_geo.h @@ -10,7 +10,7 @@ #ifndef _ASM_UV_GEO_H #define _ASM_UV_GEO_H -/* Type declaractions */ +/* Type declarations */ /* Size of a geoid_s structure (must be before decl. of geoid_u) */ #define GEOID_SIZE 8 diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 5002f52be3328418a429bb3217ade8a5cfce5808..d3e3197917be89f9bb7d9d488bf5a9772ccb9090 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -353,7 +353,7 @@ union uvh_apicid { * * Note there are NO leds on a UV system. This register is only * used by the system controller to monitor system-wide operation. - * There are 64 regs per node. With Nahelem cpus (2 cores per node, + * There are 64 regs per node. With Nehalem cpus (2 cores per node, * 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on * a node. * diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index 600a141c88050ffe05ed716d767e5b4eae84e53b..b25d3f82c2f36a9a210863d0540f2adc5744238a 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h @@ -234,7 +234,7 @@ struct boot_params { * handling of page tables. * * These enums should only ever be used by x86 code, and the code that uses - * it should be well contained and compartamentalized. + * it should be well contained and compartmentalized. * * KVM and Xen HVM do not have a subarch as these are expected to follow * standard x86 boot entries. If there is a genuine need for "hypervisor" type @@ -252,7 +252,7 @@ struct boot_params { * @X86_SUBARCH_XEN: Used for Xen guest types which follow the PV boot path, * which start at asm startup_xen() entry point and later jump to the C * xen_start_kernel() entry point. Both domU and dom0 type of guests are - * currently supportd through this PV boot path. + * currently supported through this PV boot path. * @X86_SUBARCH_INTEL_MID: Used for Intel MID (Mobile Internet Device) platform * systems which do not have the PCI legacy interfaces. * @X86_SUBARCH_CE4100: Used for Intel CE media processor (CE4100) SoC diff --git a/arch/x86/include/uapi/asm/debugreg.h b/arch/x86/include/uapi/asm/debugreg.h index d95d080b30e3ea833a5ddbe47f95e1195c6870a1..0007ba077c0c2beac746d7d51e9e00809cfb4fed 100644 --- a/arch/x86/include/uapi/asm/debugreg.h +++ b/arch/x86/include/uapi/asm/debugreg.h @@ -24,6 +24,7 @@ #define DR_TRAP3 (0x8) /* db3 */ #define DR_TRAP_BITS (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3) +#define DR_BUS_LOCK (0x800) /* bus_lock */ #define DR_STEP (0x4000) /* single-step */ #define DR_SWITCH (0x8000) /* task switch */ diff --git a/arch/x86/include/uapi/asm/msgbuf.h b/arch/x86/include/uapi/asm/msgbuf.h index b3d0664fadc9cc8055f1f84e5978341491d0b4ee..ac83e25bbf37b5c17a1bb79485aa57b9e0a8d1eb 100644 --- a/arch/x86/include/uapi/asm/msgbuf.h +++ b/arch/x86/include/uapi/asm/msgbuf.h @@ -12,7 +12,7 @@ * The msqid64_ds structure for x86 architecture with x32 ABI. * * On x86-32 and x86-64 we can just use the generic definition, but - * x32 uses the same binary layout as x86_64, which is differnet + * x32 uses the same binary layout as x86_64, which is different * from other 32-bit architectures. */ diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h index 9034f3007c4efc2e59aa9e0df97c9d34d0e29223..9690d6899ad98093fda3ab6909de8eac3093af77 100644 --- a/arch/x86/include/uapi/asm/sgx.h +++ b/arch/x86/include/uapi/asm/sgx.h @@ -152,7 +152,7 @@ struct sgx_enclave_run { * Most exceptions reported on ENCLU, including those that occur within the * enclave, are fixed up and reported synchronously instead of being delivered * via a standard signal. Debug Exceptions (#DB) and Breakpoints (#BP) are - * never fixed up and are always delivered via standard signals. On synchrously + * never fixed up and are always delivered via standard signals. On synchronously * reported exceptions, -EFAULT is returned and details about the exception are * recorded in @run.exception, the optional sgx_enclave_exception struct. * diff --git a/arch/x86/include/uapi/asm/shmbuf.h b/arch/x86/include/uapi/asm/shmbuf.h index f0305dc660c9a92338272dbfe40712519b123682..fce18eaa070c1b39b2293a8acb747d41f79519c0 100644 --- a/arch/x86/include/uapi/asm/shmbuf.h +++ b/arch/x86/include/uapi/asm/shmbuf.h @@ -9,7 +9,7 @@ * The shmid64_ds structure for x86 architecture with x32 ABI. * * On x86-32 and x86-64 we can just use the generic definition, but - * x32 uses the same binary layout as x86_64, which is differnet + * x32 uses the same binary layout as x86_64, which is different * from other 32-bit architectures. */ diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi/asm/sigcontext.h index 844d60eb1882755f3653ddfdf3a130285a4fbe3a..d0d9b331d3a13864a886e9c7ecfac285454fe5c0 100644 --- a/arch/x86/include/uapi/asm/sigcontext.h +++ b/arch/x86/include/uapi/asm/sigcontext.h @@ -139,7 +139,7 @@ struct _fpstate_32 { * The 64-bit FPU frame. (FXSAVE format and later) * * Note1: If sw_reserved.magic1 == FP_XSTATE_MAGIC1 then the structure is - * larger: 'struct _xstate'. Note that 'struct _xstate' embedds + * larger: 'struct _xstate'. Note that 'struct _xstate' embeds * 'struct _fpstate' so that you can always assume the _fpstate portion * exists so that you can check the magic value. * diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 2ddf08351f0bca0b5f3911a1855e7fa91d748ef0..0704c2a94272c0b30b052441eb5070cb53b39430 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -35,7 +35,6 @@ KASAN_SANITIZE_sev-es.o := n KCSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD_test_nx.o := y -OBJECT_FILES_NON_STANDARD_paravirt_patch.o := y ifdef CONFIG_FRAME_POINTER OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o := y @@ -121,7 +120,7 @@ obj-$(CONFIG_AMD_NB) += amd_nb.o obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o -obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch.o +obj-$(CONFIG_PARAVIRT) += paravirt.o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o obj-$(CONFIG_X86_PMEM_LEGACY_DEVICE) += pmem.o diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 14cd3186dc77dc7a929a47026bfa8c3152f89308..e90310cbe73ac2fac72f21ab469e139130703544 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -830,7 +830,7 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base) EXPORT_SYMBOL(acpi_unregister_ioapic); /** - * acpi_ioapic_registered - Check whether IOAPIC assoicatied with @gsi_base + * acpi_ioapic_registered - Check whether IOAPIC associated with @gsi_base * has been registered * @handle: ACPI handle of the IOAPIC device * @gsi_base: GSI base associated with the IOAPIC @@ -1656,7 +1656,7 @@ static int __init parse_acpi(char *arg) else if (strcmp(arg, "noirq") == 0) { acpi_noirq_set(); } - /* "acpi=copy_dsdt" copys DSDT */ + /* "acpi=copy_dsdt" copies DSDT */ else if (strcmp(arg, "copy_dsdt") == 0) { acpi_gbl_copy_dsdt_locally = 1; } diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index cc1fea76aab05dfabb69ca59e3bff20f0643914d..3f85fcae450ce2fb89b8c466d6872815491f493f 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -41,7 +41,7 @@ unsigned long acpi_get_wakeup_address(void) * x86_acpi_enter_sleep_state - enter sleep state * @state: Sleep state to enter. * - * Wrapper around acpi_enter_sleep_state() to be called by assmebly. + * Wrapper around acpi_enter_sleep_state() to be called by assembly. */ asmlinkage acpi_status __visible x86_acpi_enter_sleep_state(u8 state) { diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 8d778e46725d293ed0659742b636e70c81985d73..f810e6fececd1fedeec621d7f7883975410e614e 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -28,6 +28,7 @@ #include <asm/insn.h> #include <asm/io.h> #include <asm/fixmap.h> +#include <asm/paravirt.h> int __read_mostly alternatives_patched; @@ -388,21 +389,31 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, */ for (a = start; a < end; a++) { int insn_buff_sz = 0; + /* Mask away "NOT" flag bit for feature to test. */ + u16 feature = a->cpuid & ~ALTINSTR_FLAG_INV; instr = (u8 *)&a->instr_offset + a->instr_offset; replacement = (u8 *)&a->repl_offset + a->repl_offset; BUG_ON(a->instrlen > sizeof(insn_buff)); - BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32); - if (!boot_cpu_has(a->cpuid)) { + BUG_ON(feature >= (NCAPINTS + NBUGINTS) * 32); + + /* + * Patch if either: + * - feature is present + * - feature not present but ALTINSTR_FLAG_INV is set to mean, + * patch if feature is *NOT* present. + */ + if (!boot_cpu_has(feature) == !(a->cpuid & ALTINSTR_FLAG_INV)) { if (a->padlen > 1) optimize_nops(a, instr); continue; } - DPRINTK("feat: %d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d), pad: %d", - a->cpuid >> 5, - a->cpuid & 0x1f, + DPRINTK("feat: %s%d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d), pad: %d", + (a->cpuid & ALTINSTR_FLAG_INV) ? "!" : "", + feature >> 5, + feature & 0x1f, instr, instr, a->instrlen, replacement, a->replacementlen, a->padlen); @@ -605,7 +616,7 @@ void __init_or_module apply_paravirt(struct paravirt_patch_site *start, BUG_ON(p->len > MAX_PATCH_LEN); /* prep the buffer with the original instructions */ memcpy(insn_buff, p->instr, p->len); - used = pv_ops.init.patch(p->type, insn_buff, (unsigned long)p->instr, p->len); + used = paravirt_patch(p->type, insn_buff, (unsigned long)p->instr, p->len); BUG_ON(used > p->len); @@ -723,6 +734,33 @@ void __init alternative_instructions(void) * patching. */ + /* + * Paravirt patching and alternative patching can be combined to + * replace a function call with a short direct code sequence (e.g. + * by setting a constant return value instead of doing that in an + * external function). + * In order to make this work the following sequence is required: + * 1. set (artificial) features depending on used paravirt + * functions which can later influence alternative patching + * 2. apply paravirt patching (generally replacing an indirect + * function call with a direct one) + * 3. apply alternative patching (e.g. replacing a direct function + * call with a custom code sequence) + * Doing paravirt patching after alternative patching would clobber + * the optimization of the custom code with a function call again. + */ + paravirt_set_cap(); + + /* + * First patch paravirt functions, such that we overwrite the indirect + * call with the direct call. + */ + apply_paravirt(__parainstructions, __parainstructions_end); + + /* + * Then patch alternatives, such that those paravirt calls that are in + * alternatives can be overwritten by their immediate fragments. + */ apply_alternatives(__alt_instructions, __alt_instructions_end); #ifdef CONFIG_SMP @@ -741,8 +779,6 @@ void __init alternative_instructions(void) } #endif - apply_paravirt(__parainstructions, __parainstructions_end); - restart_nmi(); alternatives_patched = 1; } diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index b4396952c9a6ce287a4d8e0587b62a617a484f92..09083094eb575c656beceaa5298f53c9d6ffb206 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Shared support code for AMD K8 northbridges and derivates. + * Shared support code for AMD K8 northbridges and derivatives. * Copyright 2006 Andi Kleen, SUSE Labs. */ diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 4f26700f314d9ad48c4c57af17831b7f4fdb9d9b..4a39fb429f15b427f796b95f97ce60db56d0f029 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -619,7 +619,7 @@ static void setup_APIC_timer(void) if (this_cpu_has(X86_FEATURE_ARAT)) { lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; - /* Make LAPIC timer preferrable over percpu HPET */ + /* Make LAPIC timer preferable over percpu HPET */ lapic_clockevent.rating = 150; } @@ -666,7 +666,7 @@ void lapic_update_tsc_freq(void) * In this functions we calibrate APIC bus clocks to the external timer. * * We want to do the calibration only once since we want to have local timer - * irqs syncron. CPUs connected by the same APIC bus have the very same bus + * irqs synchronous. CPUs connected by the same APIC bus have the very same bus * frequency. * * This was previously done by reading the PIT/HPET and waiting for a wrap @@ -1532,7 +1532,7 @@ static bool apic_check_and_ack(union apic_ir *irr, union apic_ir *isr) * Most probably by now the CPU has serviced that pending interrupt and it * might not have done the ack_APIC_irq() because it thought, interrupt * came from i8259 as ExtInt. LAPIC did not get EOI so it does not clear - * the ISR bit and cpu thinks it has already serivced the interrupt. Hence + * the ISR bit and cpu thinks it has already serviced the interrupt. Hence * a vector might get locked. It was noticed for timer irq (vector * 0x31). Issue an extra EOI to clear ISR. * @@ -1657,7 +1657,7 @@ static void setup_local_APIC(void) */ /* * Actually disabling the focus CPU check just makes the hang less - * frequent as it makes the interrupt distributon model be more + * frequent as it makes the interrupt distribution model be more * like LRU than MRU (the short-term load is more even across CPUs). */ @@ -1875,7 +1875,7 @@ static __init void try_to_enable_x2apic(int remap_mode) /* * Without IR, all CPUs can be addressed by IOAPIC/MSI only - * in physical mode, and CPUs with an APIC ID that cannnot + * in physical mode, and CPUs with an APIC ID that cannot * be addressed must not be brought online. */ x2apic_set_max_apicid(apic_limit); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 73ff4dd426a8341bcd38654c2856b5d465bed6ba..d5c691a3208b69d7aba5b2321074d6175dab2dd4 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -928,7 +928,7 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info) /* * setup_IO_APIC_irqs() programs all legacy IRQs with default trigger - * and polarity attirbutes. So allow the first user to reprogram the + * and polarity attributes. So allow the first user to reprogram the * pin with real trigger and polarity attributes. */ if (irq < nr_legacy_irqs() && data->count == 1) { @@ -994,7 +994,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, /* * Legacy ISA IRQ has already been allocated, just add pin to - * the pin list assoicated with this IRQ and program the IOAPIC + * the pin list associated with this IRQ and program the IOAPIC * entry. The IOAPIC entry */ if (irq_data && irq_data->parent_data) { @@ -1752,7 +1752,7 @@ static inline void ioapic_finish_move(struct irq_data *data, bool moveit) * with masking the ioapic entry and then polling until * Remote IRR was clear before reprogramming the * ioapic I don't trust the Remote IRR bit to be - * completey accurate. + * completely accurate. * * However there appears to be no other way to plug * this race, so if the Remote IRR bit is not @@ -1830,7 +1830,7 @@ static void ioapic_ack_level(struct irq_data *irq_data) /* * Tail end of clearing remote IRR bit (either by delivering the EOI * message via io-apic EOI register write or simulating it using - * mask+edge followed by unnask+level logic) manually when the + * mask+edge followed by unmask+level logic) manually when the * level triggered interrupt is seen as the edge triggered interrupt * at the cpu. */ diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 3c9c7492252f827207a8638e53318835f79b48dc..6dbdc7c22bb751126cb70f9ea5766e120235f4eb 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -543,6 +543,14 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1) return -ENOSYS; + /* + * Catch any attempt to touch the cascade interrupt on a PIC + * equipped system. + */ + if (WARN_ON_ONCE(info->flags & X86_IRQ_ALLOC_LEGACY && + virq == PIC_CASCADE_IR)) + return -EINVAL; + for (i = 0; i < nr_irqs; i++) { irqd = irq_domain_get_irq_data(domain, virq + i); BUG_ON(!irqd); @@ -745,6 +753,11 @@ void __init lapic_assign_system_vectors(void) /* Mark the preallocated legacy interrupts */ for (i = 0; i < nr_legacy_irqs(); i++) { + /* + * Don't touch the cascade interrupt. It's unusable + * on PIC equipped machines. See the large comment + * in the IO/APIC code. + */ if (i != PIC_CASCADE_IR) irq_matrix_assign(vector_matrix, ISA_IRQ_VECTOR(i)); } @@ -1045,7 +1058,7 @@ void irq_force_complete_move(struct irq_desc *desc) * * But in case of cpu hotplug this should be a non issue * because if the affinity update happens right before all - * cpus rendevouz in stop machine, there is no way that the + * cpus rendezvous in stop machine, there is no way that the * interrupt can be blocked on the target cpu because all cpus * loops first with interrupts enabled in stop machine, so the * old vector is not yet cleaned up when the interrupt fires. @@ -1054,7 +1067,7 @@ void irq_force_complete_move(struct irq_desc *desc) * of the interrupt on the apic/system bus would be delayed * beyond the point where the target cpu disables interrupts * in stop machine. I doubt that it can happen, but at least - * there is a theroretical chance. Virtualization might be + * there is a theoretical chance. Virtualization might be * able to expose this, but AFAICT the IOAPIC emulation is not * as stupid as the real hardware. * diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 52bc217ca8c32a805947071ae28884cebe560ad6..f5a48e66e4f5462f83c4a76e89554377372964c6 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -369,6 +369,15 @@ static int __init early_get_arch_type(void) return ret; } +/* UV system found, check which APIC MODE BIOS already selected */ +static void __init early_set_apic_mode(void) +{ + if (x2apic_enabled()) + uv_system_type = UV_X2APIC; + else + uv_system_type = UV_LEGACY_APIC; +} + static int __init uv_set_system_type(char *_oem_id, char *_oem_table_id) { /* Save OEM_ID passed from ACPI MADT */ @@ -404,11 +413,12 @@ static int __init uv_set_system_type(char *_oem_id, char *_oem_table_id) else uv_hubless_system |= 0x8; - /* Copy APIC type */ + /* Copy OEM Table ID */ uv_stringify(sizeof(oem_table_id), oem_table_id, _oem_table_id); pr_info("UV: OEM IDs %s/%s, SystemType %d, HUBLESS ID %x\n", oem_id, oem_table_id, uv_system_type, uv_hubless_system); + return 0; } @@ -453,6 +463,7 @@ static int __init uv_set_system_type(char *_oem_id, char *_oem_table_id) early_set_hub_type(); /* Other UV setup functions */ + early_set_apic_mode(); early_get_pnodeid(); early_get_apic_socketid_shift(); x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range; @@ -472,29 +483,14 @@ static int __init uv_acpi_madt_oem_check(char *_oem_id, char *_oem_table_id) if (uv_set_system_type(_oem_id, _oem_table_id) == 0) return 0; - /* Save and Decode OEM Table ID */ + /* Save for display of the OEM Table ID */ uv_stringify(sizeof(oem_table_id), oem_table_id, _oem_table_id); - /* This is the most common hardware variant, x2apic mode */ - if (!strcmp(oem_table_id, "UVX")) - uv_system_type = UV_X2APIC; - - /* Only used for very small systems, usually 1 chassis, legacy mode */ - else if (!strcmp(oem_table_id, "UVL")) - uv_system_type = UV_LEGACY_APIC; - - else - goto badbios; - pr_info("UV: OEM IDs %s/%s, System/UVType %d/0x%x, HUB RevID %d\n", oem_id, oem_table_id, uv_system_type, is_uv(UV_ANY), uv_min_hub_revision_id); return 0; - -badbios: - pr_err("UV: UVarchtype:%s not supported\n", uv_archtype); - BUG(); } enum uv_system_type get_uv_system_type(void) @@ -1671,6 +1667,9 @@ static __init int uv_system_init_hubless(void) if (rc < 0) return rc; + /* Set section block size for current node memory */ + set_block_size(); + /* Create user access node */ if (rc >= 0) uv_setup_proc_files(1); diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 660270359d39355f0e37d17a718c1d62ab6a4e2d..241dda687eb9f684e933efffee5f9228323f4e37 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -94,7 +94,7 @@ * Remove APM dependencies in arch/i386/kernel/process.c * Remove APM dependencies in drivers/char/sysrq.c * Reset time across standby. - * Allow more inititialisation on SMP. + * Allow more initialisation on SMP. * Remove CONFIG_APM_POWER_OFF and make it boot time * configurable (default on). * Make debug only a boot time parameter (remove APM_DEBUG). @@ -766,7 +766,7 @@ static int apm_driver_version(u_short *val) * not cleared until it is acknowledged. * * Additional information is returned in the info pointer, providing - * that APM 1.2 is in use. If no messges are pending the value 0x80 + * that APM 1.2 is in use. If no messages are pending the value 0x80 * is returned (No power management events pending). */ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) @@ -1025,7 +1025,7 @@ static int apm_enable_power_management(int enable) * status which gives the rough battery status, and current power * source. The bat value returned give an estimate as a percentage * of life and a status value for the battery. The estimated life - * if reported is a lifetime in secodnds/minutes at current powwer + * if reported is a lifetime in seconds/minutes at current power * consumption. */ diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 60b9f42ce3c152720425961eb52ca3983b53868f..ecd3fd6993d1a5e4f257405681c70eef77532bb6 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -61,13 +61,6 @@ static void __used common(void) OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext); #endif -#ifdef CONFIG_PARAVIRT_XXL - BLANK(); - OFFSET(PV_IRQ_irq_disable, paravirt_patch_template, irq.irq_disable); - OFFSET(PV_IRQ_irq_enable, paravirt_patch_template, irq.irq_enable); - OFFSET(PV_CPU_iret, paravirt_patch_template, cpu.iret); -#endif - #ifdef CONFIG_XEN BLANK(); OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c index 3ca9be482a9e83b4c6545d6ccbe00e83cb131da7..d66af2950e06e7ccfecc8e0c549a572ef8db2b93 100644 --- a/arch/x86/kernel/cpu/cacheinfo.c +++ b/arch/x86/kernel/cpu/cacheinfo.c @@ -877,7 +877,7 @@ void init_intel_cacheinfo(struct cpuinfo_x86 *c) static int __cache_amd_cpumap_setup(unsigned int cpu, int index, struct _cpuid4_info_regs *base) { - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cpu_cacheinfo *this_cpu_ci; struct cacheinfo *this_leaf; int i, sibling; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ab640abe26b686a57e89f95dafa6b7a158db1fd9..99e1656b326eb853bf8d06fee9bb9da9c7faf970 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -482,7 +482,7 @@ static __always_inline void setup_pku(struct cpuinfo_x86 *c) if (pk) pk->pkru = init_pkru_value; /* - * Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE + * Setting X86_CR4_PKE will cause the X86_FEATURE_OSPKE * cpuid bit to be set. We need to ensure that we * update that bit in this CPU's "cpu_info". */ @@ -1330,7 +1330,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) cpu_set_bug_bits(c); - cpu_set_core_cap_bits(c); + sld_setup(c); fpu__init_system(c); @@ -1404,7 +1404,7 @@ static void detect_null_seg_behavior(struct cpuinfo_x86 *c) * where GS is unused by the prev and next threads. * * Since neither vendor documents this anywhere that I can see, - * detect it directly instead of hardcoding the choice by + * detect it directly instead of hard-coding the choice by * vendor. * * I've designated AMD's behavior as the "bug" because it's @@ -1748,6 +1748,8 @@ DEFINE_PER_CPU(bool, hardirq_stack_inuse); DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT; EXPORT_PER_CPU_SYMBOL(__preempt_count); +DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) = TOP_OF_INIT_STACK; + /* May not be marked __init: used by software suspend */ void syscall_init(void) { diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c index 42af31b64c2ceb3f96cebd2bb54827b0f084b445..defda61f372df532dadf52dd452949135ee0881b 100644 --- a/arch/x86/kernel/cpu/cpuid-deps.c +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -72,6 +72,9 @@ static const struct cpuid_dep cpuid_deps[] = { { X86_FEATURE_AVX512_FP16, X86_FEATURE_AVX512BW }, { X86_FEATURE_ENQCMD, X86_FEATURE_XSAVES }, { X86_FEATURE_PER_THREAD_MBA, X86_FEATURE_MBA }, + { X86_FEATURE_SGX_LC, X86_FEATURE_SGX }, + { X86_FEATURE_SGX1, X86_FEATURE_SGX }, + { X86_FEATURE_SGX2, X86_FEATURE_SGX1 }, {} }; diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c index 1d9b8aaea06c8c9c7d14b0c30d51ded3bac83d7d..7227c15299d0b8a50ce44459e7b5d8889704db5e 100644 --- a/arch/x86/kernel/cpu/cyrix.c +++ b/arch/x86/kernel/cpu/cyrix.c @@ -291,7 +291,7 @@ static void init_cyrix(struct cpuinfo_x86 *c) mark_tsc_unstable("cyrix 5510/5520 detected"); } #endif - c->x86_cache_size = 16; /* Yep 16K integrated cache thats it */ + c->x86_cache_size = 16; /* Yep 16K integrated cache that's it */ /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { diff --git a/arch/x86/kernel/cpu/feat_ctl.c b/arch/x86/kernel/cpu/feat_ctl.c index 3b1b01f2b248a57cd0dee06fbd35077e42ed1a76..da696eb4821a0b159e14ea0246beea0bcaf22cfc 100644 --- a/arch/x86/kernel/cpu/feat_ctl.c +++ b/arch/x86/kernel/cpu/feat_ctl.c @@ -93,15 +93,9 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c) } #endif /* CONFIG_X86_VMX_FEATURE_NAMES */ -static void clear_sgx_caps(void) -{ - setup_clear_cpu_cap(X86_FEATURE_SGX); - setup_clear_cpu_cap(X86_FEATURE_SGX_LC); -} - static int __init nosgx(char *str) { - clear_sgx_caps(); + setup_clear_cpu_cap(X86_FEATURE_SGX); return 0; } @@ -110,23 +104,30 @@ early_param("nosgx", nosgx); void init_ia32_feat_ctl(struct cpuinfo_x86 *c) { + bool enable_sgx_kvm = false, enable_sgx_driver = false; bool tboot = tboot_enabled(); - bool enable_sgx; + bool enable_vmx; u64 msr; if (rdmsrl_safe(MSR_IA32_FEAT_CTL, &msr)) { clear_cpu_cap(c, X86_FEATURE_VMX); - clear_sgx_caps(); + clear_cpu_cap(c, X86_FEATURE_SGX); return; } - /* - * Enable SGX if and only if the kernel supports SGX and Launch Control - * is supported, i.e. disable SGX if the LE hash MSRs can't be written. - */ - enable_sgx = cpu_has(c, X86_FEATURE_SGX) && - cpu_has(c, X86_FEATURE_SGX_LC) && - IS_ENABLED(CONFIG_X86_SGX); + enable_vmx = cpu_has(c, X86_FEATURE_VMX) && + IS_ENABLED(CONFIG_KVM_INTEL); + + if (cpu_has(c, X86_FEATURE_SGX) && IS_ENABLED(CONFIG_X86_SGX)) { + /* + * Separate out SGX driver enabling from KVM. This allows KVM + * guests to use SGX even if the kernel SGX driver refuses to + * use it. This happens if flexible Launch Control is not + * available. + */ + enable_sgx_driver = cpu_has(c, X86_FEATURE_SGX_LC); + enable_sgx_kvm = enable_vmx && IS_ENABLED(CONFIG_X86_SGX_KVM); + } if (msr & FEAT_CTL_LOCKED) goto update_caps; @@ -142,15 +143,18 @@ void init_ia32_feat_ctl(struct cpuinfo_x86 *c) * i.e. KVM is enabled, to avoid unnecessarily adding an attack vector * for the kernel, e.g. using VMX to hide malicious code. */ - if (cpu_has(c, X86_FEATURE_VMX) && IS_ENABLED(CONFIG_KVM_INTEL)) { + if (enable_vmx) { msr |= FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX; if (tboot) msr |= FEAT_CTL_VMX_ENABLED_INSIDE_SMX; } - if (enable_sgx) - msr |= FEAT_CTL_SGX_ENABLED | FEAT_CTL_SGX_LC_ENABLED; + if (enable_sgx_kvm || enable_sgx_driver) { + msr |= FEAT_CTL_SGX_ENABLED; + if (enable_sgx_driver) + msr |= FEAT_CTL_SGX_LC_ENABLED; + } wrmsrl(MSR_IA32_FEAT_CTL, msr); @@ -173,10 +177,29 @@ update_caps: } update_sgx: - if (!(msr & FEAT_CTL_SGX_ENABLED) || - !(msr & FEAT_CTL_SGX_LC_ENABLED) || !enable_sgx) { - if (enable_sgx) - pr_err_once("SGX disabled by BIOS\n"); - clear_sgx_caps(); + if (!(msr & FEAT_CTL_SGX_ENABLED)) { + if (enable_sgx_kvm || enable_sgx_driver) + pr_err_once("SGX disabled by BIOS.\n"); + clear_cpu_cap(c, X86_FEATURE_SGX); + return; + } + + /* + * VMX feature bit may be cleared due to being disabled in BIOS, + * in which case SGX virtualization cannot be supported either. + */ + if (!cpu_has(c, X86_FEATURE_VMX) && enable_sgx_kvm) { + pr_err_once("SGX virtualization disabled due to lack of VMX.\n"); + enable_sgx_kvm = 0; + } + + if (!(msr & FEAT_CTL_SGX_LC_ENABLED) && enable_sgx_driver) { + if (!enable_sgx_kvm) { + pr_err_once("SGX Launch Control is locked. Disable SGX.\n"); + clear_cpu_cap(c, X86_FEATURE_SGX); + } else { + pr_err_once("SGX Launch Control is locked. Support SGX virtualization only.\n"); + clear_cpu_cap(c, X86_FEATURE_SGX_LC); + } } } diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 0e422a5448351c6d418a3bc40f40b39e5d7c2e1d..fe0bec14d7ece81f8cc9f5430d21ffdba6cc5a5f 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -44,9 +44,9 @@ enum split_lock_detect_state { }; /* - * Default to sld_off because most systems do not support split lock detection - * split_lock_setup() will switch this to sld_warn on systems that support - * split lock detect, unless there is a command line override. + * 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; @@ -301,7 +301,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) * The operating system must reload CR3 to cause the TLB to be flushed" * * As a result, boot_cpu_has(X86_FEATURE_PGE) in arch/x86/include/asm/tlbflush.h - * should be false so that __flush_tlb_all() causes CR3 insted of CR4.PGE + * should be false so that __flush_tlb_all() causes CR3 instead of CR4.PGE * to be modified. */ if (c->x86 == 5 && c->x86_model == 9) { @@ -603,6 +603,7 @@ static void init_intel_misc_features(struct cpuinfo_x86 *c) } static void split_lock_init(void); +static void bus_lock_init(void); static void init_intel(struct cpuinfo_x86 *c) { @@ -720,6 +721,7 @@ static void init_intel(struct cpuinfo_x86 *c) tsx_disable(); split_lock_init(); + bus_lock_init(); intel_init_thermal(c); } @@ -1020,16 +1022,15 @@ static bool split_lock_verify_msr(bool on) return ctrl == tmp; } -static void __init split_lock_setup(void) +static void __init sld_state_setup(void) { enum split_lock_detect_state state = sld_warn; char arg[20]; int i, ret; - if (!split_lock_verify_msr(false)) { - pr_info("MSR access failed: Disabled\n"); + 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)); @@ -1041,17 +1042,14 @@ static void __init split_lock_setup(void) } } } + sld_state = state; +} - switch (state) { - case sld_off: - pr_info("disabled\n"); +static void __init __split_lock_setup(void) +{ + if (!split_lock_verify_msr(false)) { + pr_info("MSR access failed: Disabled\n"); return; - case sld_warn: - pr_info("warning about user-space split_locks\n"); - break; - case sld_fatal: - pr_info("sending SIGBUS on user-space split_locks\n"); - break; } rdmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); @@ -1061,7 +1059,9 @@ static void __init split_lock_setup(void) return; } - sld_state = state; + /* Restore the MSR to its cached value. */ + wrmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); + setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT); } @@ -1118,6 +1118,29 @@ bool handle_guest_split_lock(unsigned long ip) } EXPORT_SYMBOL_GPL(handle_guest_split_lock); +static void bus_lock_init(void) +{ + u64 val; + + /* + * Warn and fatal are handled by #AC for split lock if #AC for + * split lock is supported. + */ + if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT) || + (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) && + (sld_state == sld_warn || sld_state == sld_fatal)) || + sld_state == sld_off) + return; + + /* + * Enable #DB for bus lock. All bus locks are handled in #DB except + * split locks are handled in #AC in the fatal case. + */ + rdmsrl(MSR_IA32_DEBUGCTLMSR, val); + 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) @@ -1126,6 +1149,21 @@ bool handle_user_split_lock(struct pt_regs *regs, long error_code) return true; } +void handle_bus_lock(struct pt_regs *regs) +{ + switch (sld_state) { + case sld_off: + break; + 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; + } +} + /* * This function is called only when switching between tasks with * different split-lock detection modes. It sets the MSR for the @@ -1166,7 +1204,7 @@ static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = { {} }; -void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) +static void __init split_lock_setup(struct cpuinfo_x86 *c) { const struct x86_cpu_id *m; u64 ia32_core_caps; @@ -1193,5 +1231,40 @@ void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) } cpu_model_supports_sld = true; - split_lock_setup(); + __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"); + 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; + } +} + +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/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index 7962355436dacf3f74eea63f74e8e8d66df5d07f..bf7fe87a7e884d3006f20f76a113e8289618ebe9 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -529,7 +529,7 @@ static void mce_irq_work_cb(struct irq_work *entry) * Check if the address reported by the CPU is in a format we can parse. * It would be possible to add code for most other cases, but all would * be somewhat complicated (e.g. segment offset would require an instruction - * parser). So only support physical addresses up to page granuality for now. + * parser). So only support physical addresses up to page granularity for now. */ int mce_usable_address(struct mce *m) { diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c index 7b360731fc2d058480f059cbd92cffd1213a7615..4e86d97f96530a92f1f7f6b8a889757559097f66 100644 --- a/arch/x86/kernel/cpu/mce/inject.c +++ b/arch/x86/kernel/cpu/mce/inject.c @@ -74,6 +74,7 @@ MCE_INJECT_SET(status); MCE_INJECT_SET(misc); MCE_INJECT_SET(addr); MCE_INJECT_SET(synd); +MCE_INJECT_SET(ipid); #define MCE_INJECT_GET(reg) \ static int inj_##reg##_get(void *data, u64 *val) \ @@ -88,11 +89,13 @@ MCE_INJECT_GET(status); MCE_INJECT_GET(misc); MCE_INJECT_GET(addr); MCE_INJECT_GET(synd); +MCE_INJECT_GET(ipid); DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n"); DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n"); DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n"); DEFINE_SIMPLE_ATTRIBUTE(synd_fops, inj_synd_get, inj_synd_set, "%llx\n"); +DEFINE_SIMPLE_ATTRIBUTE(ipid_fops, inj_ipid_get, inj_ipid_set, "%llx\n"); static void setup_inj_struct(struct mce *m) { @@ -629,6 +632,8 @@ static const char readme_msg[] = "\t is present in hardware. \n" "\t - \"th\": Trigger APIC interrupt for Threshold errors. Causes threshold \n" "\t APIC interrupt handler to handle the error. \n" +"\n" +"ipid:\t IPID (AMD-specific)\n" "\n"; static ssize_t @@ -652,6 +657,7 @@ static struct dfs_node { { .name = "misc", .fops = &misc_fops, .perm = S_IRUSR | S_IWUSR }, { .name = "addr", .fops = &addr_fops, .perm = S_IRUSR | S_IWUSR }, { .name = "synd", .fops = &synd_fops, .perm = S_IRUSR | S_IWUSR }, + { .name = "ipid", .fops = &ipid_fops, .perm = S_IRUSR | S_IWUSR }, { .name = "bank", .fops = &bank_fops, .perm = S_IRUSR | S_IWUSR }, { .name = "flags", .fops = &flags_fops, .perm = S_IRUSR | S_IWUSR }, { .name = "cpu", .fops = &extcpu_fops, .perm = S_IRUSR | S_IWUSR }, diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c index 83df991314c531bea4c1b90b98d2f8f61fab66ab..55ffa84d30d6949e4cf260afaac23a9219ebfcb1 100644 --- a/arch/x86/kernel/cpu/mce/severity.c +++ b/arch/x86/kernel/cpu/mce/severity.c @@ -142,7 +142,7 @@ static struct severity { MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR) ), MCESEV( - KEEP, "Non signalled machine check", + KEEP, "Non signaled machine check", SER, BITCLR(MCI_STATUS_S) ), diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index b935e1b5f115e797de342b9d73a9346aacdaa3b0..6a6318e9590c89f0903be4c304238329e5895ac3 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -629,16 +629,16 @@ static ssize_t reload_store(struct device *dev, if (val != 1) return size; - tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); - if (tmp_ret != UCODE_NEW) - return size; - get_online_cpus(); ret = check_online_cpus(); if (ret) goto put; + tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); + if (tmp_ret != UCODE_NEW) + goto put; + mutex_lock(µcode_mutex); ret = microcode_reload_late(); mutex_unlock(µcode_mutex); diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index e88bc296afca0ba9f513b37ceb336396b0431a92..22f13343b5da808f5045195a93522130dc8165d0 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -60,23 +60,18 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback) set_irq_regs(old_regs); } -int hv_setup_vmbus_irq(int irq, void (*handler)(void)) +void hv_setup_vmbus_handler(void (*handler)(void)) { - /* - * The 'irq' argument is ignored on x86/x64 because a hard-coded - * interrupt vector is used for Hyper-V interrupts. - */ vmbus_handler = handler; - return 0; } +EXPORT_SYMBOL_GPL(hv_setup_vmbus_handler); -void hv_remove_vmbus_irq(void) +void hv_remove_vmbus_handler(void) { /* We have no way to deallocate the interrupt gate */ vmbus_handler = NULL; } -EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq); -EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq); +EXPORT_SYMBOL_GPL(hv_remove_vmbus_handler); /* * Routines to do per-architecture handling of stimer0 @@ -95,21 +90,17 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_stimer0) set_irq_regs(old_regs); } -int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void)) +/* For x86/x64, override weak placeholders in hyperv_timer.c */ +void hv_setup_stimer0_handler(void (*handler)(void)) { - *vector = HYPERV_STIMER0_VECTOR; - *irq = -1; /* Unused on x86/x64 */ hv_stimer0_handler = handler; - return 0; } -EXPORT_SYMBOL_GPL(hv_setup_stimer0_irq); -void hv_remove_stimer0_irq(int irq) +void hv_remove_stimer0_handler(void) { /* We have no way to deallocate the interrupt gate */ hv_stimer0_handler = NULL; } -EXPORT_SYMBOL_GPL(hv_remove_stimer0_irq); void hv_setup_kexec_handler(void (*handler)(void)) { @@ -197,7 +188,7 @@ static unsigned char hv_get_nmi_reason(void) #ifdef CONFIG_X86_LOCAL_APIC /* * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes - * it dificult to process CHANNELMSG_UNLOAD in case of crash. Handle + * it difficult to process CHANNELMSG_UNLOAD in case of crash. Handle * unknown NMI on the first CPU which gets it. */ static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs) @@ -274,12 +265,13 @@ static void __init ms_hyperv_init_platform(void) * Extract the features and hints */ ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES); - ms_hyperv.features_b = cpuid_ebx(HYPERV_CPUID_FEATURES); + ms_hyperv.priv_high = cpuid_ebx(HYPERV_CPUID_FEATURES); ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES); ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); - pr_info("Hyper-V: features 0x%x, hints 0x%x, misc 0x%x\n", - ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features); + pr_info("Hyper-V: privilege flags low 0x%x, high 0x%x, hints 0x%x, misc 0x%x\n", + ms_hyperv.features, ms_hyperv.priv_high, ms_hyperv.hints, + ms_hyperv.misc_features); ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS); ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS); @@ -325,7 +317,7 @@ static void __init ms_hyperv_init_platform(void) x86_platform.calibrate_cpu = hv_get_tsc_khz; } - if (ms_hyperv.features_b & HV_ISOLATION) { + if (ms_hyperv.priv_high & HV_ISOLATION) { ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG); ms_hyperv.isolation_config_b = cpuid_ebx(HYPERV_CPUID_ISOLATION_CONFIG); @@ -428,7 +420,7 @@ static void __init ms_hyperv_init_platform(void) /* * Hyper-V doesn't provide irq remapping for IO-APIC. To enable x2apic, - * set x2apic destination mode to physcial mode when x2apic is available + * set x2apic destination mode to physical mode when x2apic is available * and Hyper-V IOMMU driver makes sure cpus assigned with IO-APIC irqs * have 8-bit APIC id. */ diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index 9231640782fa23fdb4974e72ec4699b4b5491029..0c3b372318b70776dc915279c005130a0454e7ff 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -434,7 +434,7 @@ set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn, state->range_sizek = sizek - second_sizek; } -/* Mininum size of mtrr block that can take hole: */ +/* Minimum size of mtrr block that can take hole: */ static u64 mtrr_chunk_size __initdata = (256ULL<<20); static int __init parse_mtrr_chunk_size_opt(char *p) diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.c b/arch/x86/kernel/cpu/mtrr/mtrr.c index 28c8a23aa42ee9b0fc253f6f34e883a334f4d8ba..a76694bffe86a43c60e92079f41e1134049d04ed 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.c +++ b/arch/x86/kernel/cpu/mtrr/mtrr.c @@ -799,7 +799,7 @@ void mtrr_ap_init(void) * * This routine is called in two cases: * - * 1. very earily time of software resume, when there absolutely + * 1. very early time of software resume, when there absolutely * isn't mtrr entry changes; * * 2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 698bb26aeb6e95ed06599b11bcf3f72f105fc842..23001ae03e82b924d66ed56e70194d533bbff5a0 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -192,7 +192,7 @@ static unsigned int cbm_idx(struct rdt_resource *r, unsigned int closid) * Intel(R) Xeon(R) CPU E5-2608L v3 @ 2.00GHz * Intel(R) Xeon(R) CPU E5-2658A v3 @ 2.20GHz * - * Probe by trying to write the first of the L3 cach mask registers + * Probe by trying to write the first of the L3 cache mask registers * and checking that the bits stick. Max CLOSids is always 4 and max cbm length * is always 20 on hsw server parts. The minimum cache bitmask length * allowed for HSW server is always 2 bits. Hardcode all of them. diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 7ac31210e452abfa4d4e8af9ff2daba6039c2a9b..dbeaa8409313492396bbe9a1dbf0f67c0b4de4d0 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -387,7 +387,7 @@ void mon_event_count(void *info) * adjust the bandwidth percentage values via the IA32_MBA_THRTL_MSRs so * that: * - * current bandwdith(cur_bw) < user specified bandwidth(user_bw) + * current bandwidth(cur_bw) < user specified bandwidth(user_bw) * * This uses the MBM counters to measure the bandwidth and MBA throttle * MSRs to control the bandwidth for a particular rdtgrp. It builds on the @@ -397,7 +397,7 @@ void mon_event_count(void *info) * timer. Having 1s interval makes the calculation of bandwidth simpler. * * Although MBA's goal is to restrict the bandwidth to a maximum, there may - * be a need to increase the bandwidth to avoid uncecessarily restricting + * be a need to increase the bandwidth to avoid unnecessarily restricting * the L2 <-> L3 traffic. * * Since MBA controls the L2 external bandwidth where as MBM measures the @@ -480,7 +480,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) /* * Delta values are updated dynamically package wise for each - * rdtgrp everytime the throttle MSR changes value. + * rdtgrp every time the throttle MSR changes value. * * This is because (1)the increase in bandwidth is not perfectly * linear and only "approximately" linear even when the hardware diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c index e916646adc69f8f5293b5ca1ed4ca1b34b7f8a00..935af2ac6b1af15c677d6d9fffb75b0e0eec830e 100644 --- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c +++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c @@ -1307,7 +1307,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) * If the thread does not get on the CPU for whatever * reason and the process which sets up the region is * interrupted then this will leave the thread in runnable - * state and once it gets on the CPU it will derefence + * state and once it gets on the CPU it will dereference * the cleared, but not freed, plr struct resulting in an * empty pseudo-locking loop. */ @@ -1391,7 +1391,7 @@ out: * group is removed from user space via a "rmdir" from userspace or the * unmount of the resctrl filesystem. On removal the resource group does * not go back to pseudo-locksetup mode before it is removed, instead it is - * removed directly. There is thus assymmetry with the creation where the + * removed directly. There is thus asymmetry with the creation where the * &struct pseudo_lock_region is removed here while it was not created in * rdtgroup_pseudo_lock_create(). * diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index f9190adc52cb9beda0db99c07e805dc0f7c26d21..01fd30e7829dcf8accb31891e734ea770dd68b8b 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * User interface for Resource Alloction in Resource Director Technology(RDT) + * User interface for Resource Allocation in Resource Director Technology(RDT) * * Copyright (C) 2016 Intel Corporation * @@ -294,7 +294,7 @@ static int rdtgroup_cpus_show(struct kernfs_open_file *of, /* * This is safe against resctrl_sched_in() called from __switch_to() * because __switch_to() is executed with interrupts disabled. A local call - * from update_closid_rmid() is proteced against __switch_to() because + * from update_closid_rmid() is protected against __switch_to() because * preemption is disabled. */ static void update_cpu_closid_rmid(void *info) @@ -2555,7 +2555,7 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn, /* * This creates a directory mon_data which contains the monitored data. * - * mon_data has one directory for each domain whic are named + * mon_data has one directory for each domain which are named * in the format mon_<domain_name>_<domain_id>. For ex: A mon_data * with L3 domain looks as below: * ./mon_data: diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 972ec3bfa9c0cfc0a743d30f3fc01df7150b9b87..21d1f062895a8dfdf4c66ecbec8d91da3feadb5c 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -36,6 +36,8 @@ static const struct cpuid_bit cpuid_bits[] = { { 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_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, { X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 }, diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile index 91d3dc784a2925ec39d8a2251822df36d41ec017..9c1656779b2a058ff6f15d30bbac00ca557fd148 100644 --- a/arch/x86/kernel/cpu/sgx/Makefile +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -3,3 +3,4 @@ obj-y += \ encl.o \ ioctl.o \ main.o +obj-$(CONFIG_X86_SGX_KVM) += virt.o diff --git a/arch/x86/kernel/cpu/sgx/driver.c b/arch/x86/kernel/cpu/sgx/driver.c index 8ce6d8371cfbf74eba9a4eba624220350d43f1c9..aa9b8b8688676fc66ebc6fdd605fe4467991af13 100644 --- a/arch/x86/kernel/cpu/sgx/driver.c +++ b/arch/x86/kernel/cpu/sgx/driver.c @@ -136,10 +136,6 @@ static const struct file_operations sgx_encl_fops = { .get_unmapped_area = sgx_get_unmapped_area, }; -const struct file_operations sgx_provision_fops = { - .owner = THIS_MODULE, -}; - static struct miscdevice sgx_dev_enclave = { .minor = MISC_DYNAMIC_MINOR, .name = "sgx_enclave", @@ -147,13 +143,6 @@ static struct miscdevice sgx_dev_enclave = { .fops = &sgx_encl_fops, }; -static struct miscdevice sgx_dev_provision = { - .minor = MISC_DYNAMIC_MINOR, - .name = "sgx_provision", - .nodename = "sgx_provision", - .fops = &sgx_provision_fops, -}; - int __init sgx_drv_init(void) { unsigned int eax, ebx, ecx, edx; @@ -187,11 +176,5 @@ int __init sgx_drv_init(void) if (ret) return ret; - ret = misc_register(&sgx_dev_provision); - if (ret) { - misc_deregister(&sgx_dev_enclave); - return ret; - } - return 0; } diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c index 7449ef33f0819db43aae1283ac07dddd35ffc636..3be203297988f09e627388f2f69d4fb8263eaf46 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c @@ -7,7 +7,7 @@ #include <linux/shmem_fs.h> #include <linux/suspend.h> #include <linux/sched/mm.h> -#include "arch.h" +#include <asm/sgx.h> #include "encl.h" #include "encls.h" #include "sgx.h" @@ -78,7 +78,7 @@ static struct sgx_epc_page *sgx_encl_eldu(struct sgx_encl_page *encl_page, ret = __sgx_encl_eldu(encl_page, epc_page, secs_page); if (ret) { - sgx_free_epc_page(epc_page); + sgx_encl_free_epc_page(epc_page); return ERR_PTR(ret); } @@ -404,7 +404,7 @@ void sgx_encl_release(struct kref *ref) if (sgx_unmark_page_reclaimable(entry->epc_page)) continue; - sgx_free_epc_page(entry->epc_page); + sgx_encl_free_epc_page(entry->epc_page); encl->secs_child_cnt--; entry->epc_page = NULL; } @@ -415,7 +415,7 @@ void sgx_encl_release(struct kref *ref) xa_destroy(&encl->page_array); if (!encl->secs_child_cnt && encl->secs.epc_page) { - sgx_free_epc_page(encl->secs.epc_page); + sgx_encl_free_epc_page(encl->secs.epc_page); encl->secs.epc_page = NULL; } @@ -423,7 +423,7 @@ void sgx_encl_release(struct kref *ref) va_page = list_first_entry(&encl->va_pages, struct sgx_va_page, list); list_del(&va_page->list); - sgx_free_epc_page(va_page->epc_page); + sgx_encl_free_epc_page(va_page->epc_page); kfree(va_page); } @@ -686,7 +686,7 @@ struct sgx_epc_page *sgx_alloc_va_page(void) ret = __epa(sgx_get_epc_virt_addr(epc_page)); if (ret) { WARN_ONCE(1, "EPA returned %d (0x%x)", ret, ret); - sgx_free_epc_page(epc_page); + sgx_encl_free_epc_page(epc_page); return ERR_PTR(-EFAULT); } @@ -735,3 +735,24 @@ bool sgx_va_page_full(struct sgx_va_page *va_page) return slot == SGX_VA_SLOT_COUNT; } + +/** + * sgx_encl_free_epc_page - free an EPC page assigned to an enclave + * @page: EPC page to be freed + * + * Free an EPC page assigned to an enclave. It does EREMOVE for the page, and + * only upon success, it puts the page back to free page list. Otherwise, it + * gives a WARNING to indicate page is leaked. + */ +void sgx_encl_free_epc_page(struct sgx_epc_page *page) +{ + int ret; + + WARN_ON_ONCE(page->flags & SGX_EPC_PAGE_RECLAIMER_TRACKED); + + ret = __eremove(sgx_get_epc_virt_addr(page)); + if (WARN_ONCE(ret, EREMOVE_ERROR_MESSAGE, ret, ret)) + return; + + sgx_free_epc_page(page); +} diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h index d8d30ccbef4c95017bec5926f1fab6d04fb12185..6e74f85b626451752b0ec8a0b02f64bd77e232c4 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -115,5 +115,6 @@ struct sgx_epc_page *sgx_alloc_va_page(void); unsigned int sgx_alloc_va_slot(struct sgx_va_page *va_page); void sgx_free_va_slot(struct sgx_va_page *va_page, unsigned int offset); bool sgx_va_page_full(struct sgx_va_page *va_page); +void sgx_encl_free_epc_page(struct sgx_epc_page *page); #endif /* _X86_ENCL_H */ diff --git a/arch/x86/kernel/cpu/sgx/encls.h b/arch/x86/kernel/cpu/sgx/encls.h index 443188fe7e7057bb0dba10bda49acfdbf42757e4..9b204843b78d3ec7ff3903548358d39c4665dee8 100644 --- a/arch/x86/kernel/cpu/sgx/encls.h +++ b/arch/x86/kernel/cpu/sgx/encls.h @@ -11,21 +11,6 @@ #include <asm/traps.h> #include "sgx.h" -enum sgx_encls_function { - ECREATE = 0x00, - EADD = 0x01, - EINIT = 0x02, - EREMOVE = 0x03, - EDGBRD = 0x04, - EDGBWR = 0x05, - EEXTEND = 0x06, - ELDU = 0x08, - EBLOCK = 0x09, - EPA = 0x0A, - EWB = 0x0B, - ETRACK = 0x0C, -}; - /** * ENCLS_FAULT_FLAG - flag signifying an ENCLS return code is a trapnr * @@ -55,6 +40,19 @@ enum sgx_encls_function { } while (0); \ } +/* + * encls_faulted() - Check if an ENCLS leaf faulted given an error code + * @ret: the return value of an ENCLS leaf function call + * + * Return: + * - true: ENCLS leaf faulted. + * - false: Otherwise. + */ +static inline bool encls_faulted(int ret) +{ + return ret & ENCLS_FAULT_FLAG; +} + /** * encls_failed() - Check if an ENCLS function failed * @ret: the return value of an ENCLS function call @@ -65,7 +63,7 @@ enum sgx_encls_function { */ static inline bool encls_failed(int ret) { - if (ret & ENCLS_FAULT_FLAG) + if (encls_faulted(ret)) return ENCLS_TRAPNR(ret) != X86_TRAP_PF; return !!ret; diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c index 90a5caf76939a7bc71423ea98b5bc7254c1c1261..83df20e3e633353ca0b707cda6cae51cb6f09714 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c @@ -2,6 +2,7 @@ /* Copyright(c) 2016-20 Intel Corporation. */ #include <asm/mman.h> +#include <asm/sgx.h> #include <linux/mman.h> #include <linux/delay.h> #include <linux/file.h> @@ -47,7 +48,7 @@ static void sgx_encl_shrink(struct sgx_encl *encl, struct sgx_va_page *va_page) encl->page_cnt--; if (va_page) { - sgx_free_epc_page(va_page->epc_page); + sgx_encl_free_epc_page(va_page->epc_page); list_del(&va_page->list); kfree(va_page); } @@ -117,7 +118,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) return 0; err_out: - sgx_free_epc_page(encl->secs.epc_page); + sgx_encl_free_epc_page(encl->secs.epc_page); encl->secs.epc_page = NULL; err_out_backing: @@ -365,7 +366,7 @@ err_out_unlock: mmap_read_unlock(current->mm); err_out_free: - sgx_free_epc_page(epc_page); + sgx_encl_free_epc_page(epc_page); kfree(encl_page); return ret; @@ -495,7 +496,7 @@ static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, void *token) { u64 mrsigner[4]; - int i, j, k; + int i, j; void *addr; int ret; @@ -544,8 +545,7 @@ static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, preempt_disable(); - for (k = 0; k < 4; k++) - wrmsrl(MSR_IA32_SGXLEPUBKEYHASH0 + k, mrsigner[k]); + sgx_update_lepubkeyhash(mrsigner); ret = __einit(sigstruct, token, addr); @@ -568,7 +568,7 @@ static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, } } - if (ret & ENCLS_FAULT_FLAG) { + if (encls_faulted(ret)) { if (encls_failed(ret)) ENCLS_WARN(ret, "EINIT"); @@ -604,7 +604,6 @@ static long sgx_ioc_enclave_init(struct sgx_encl *encl, void __user *arg) { struct sgx_sigstruct *sigstruct; struct sgx_enclave_init init_arg; - struct page *initp_page; void *token; int ret; @@ -615,11 +614,15 @@ static long sgx_ioc_enclave_init(struct sgx_encl *encl, void __user *arg) if (copy_from_user(&init_arg, arg, sizeof(init_arg))) return -EFAULT; - initp_page = alloc_page(GFP_KERNEL); - if (!initp_page) + /* + * 'sigstruct' must be on a page boundary and 'token' on a 512 byte + * boundary. kmalloc() will give this alignment when allocating + * PAGE_SIZE bytes. + */ + sigstruct = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!sigstruct) return -ENOMEM; - sigstruct = kmap(initp_page); token = (void *)((unsigned long)sigstruct + PAGE_SIZE / 2); memset(token, 0, SGX_LAUNCH_TOKEN_SIZE); @@ -645,8 +648,7 @@ static long sgx_ioc_enclave_init(struct sgx_encl *encl, void __user *arg) ret = sgx_encl_init(encl, sigstruct, token); out: - kunmap(initp_page); - __free_page(initp_page); + kfree(sigstruct); return ret; } @@ -665,24 +667,11 @@ out: static long sgx_ioc_enclave_provision(struct sgx_encl *encl, void __user *arg) { struct sgx_enclave_provision params; - struct file *file; if (copy_from_user(¶ms, arg, sizeof(params))) return -EFAULT; - file = fget(params.fd); - if (!file) - return -EINVAL; - - if (file->f_op != &sgx_provision_fops) { - fput(file); - return -EINVAL; - } - - encl->attributes_mask |= SGX_ATTR_PROVISIONKEY; - - fput(file); - return 0; + return sgx_set_attribute(&encl->attributes_mask, params.fd); } long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index 8df81a3ed945738e5da7440ade5424bf53f17a11..63d3de02bbccb50ba7ab015227ac4cc680954877 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -1,14 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2016-20 Intel Corporation. */ +#include <linux/file.h> #include <linux/freezer.h> #include <linux/highmem.h> #include <linux/kthread.h> +#include <linux/miscdevice.h> #include <linux/pagemap.h> #include <linux/ratelimit.h> #include <linux/sched/mm.h> #include <linux/sched/signal.h> #include <linux/slab.h> +#include <asm/sgx.h> #include "driver.h" #include "encl.h" #include "encls.h" @@ -23,42 +26,58 @@ static DECLARE_WAIT_QUEUE_HEAD(ksgxd_waitq); * with sgx_reclaimer_lock acquired. */ static LIST_HEAD(sgx_active_page_list); - static DEFINE_SPINLOCK(sgx_reclaimer_lock); +/* The free page list lock protected variables prepend the lock. */ +static unsigned long sgx_nr_free_pages; + +/* Nodes with one or more EPC sections. */ +static nodemask_t sgx_numa_mask; + +/* + * Array with one list_head for each possible NUMA node. Each + * list contains all the sgx_epc_section's which are on that + * node. + */ +static struct sgx_numa_node *sgx_numa_nodes; + +static LIST_HEAD(sgx_dirty_page_list); + /* - * Reset dirty EPC pages to uninitialized state. Laundry can be left with SECS - * pages whose child pages blocked EREMOVE. + * Reset post-kexec EPC pages to the uninitialized state. The pages are removed + * from the input list, and made available for the page allocator. SECS pages + * prepending their children in the input list are left intact. */ -static void sgx_sanitize_section(struct sgx_epc_section *section) +static void __sgx_sanitize_pages(struct list_head *dirty_page_list) { struct sgx_epc_page *page; LIST_HEAD(dirty); int ret; - /* init_laundry_list is thread-local, no need for a lock: */ - while (!list_empty(§ion->init_laundry_list)) { + /* dirty_page_list is thread-local, no need for a lock: */ + while (!list_empty(dirty_page_list)) { if (kthread_should_stop()) return; - /* needed for access to ->page_list: */ - spin_lock(§ion->lock); - - page = list_first_entry(§ion->init_laundry_list, - struct sgx_epc_page, list); + page = list_first_entry(dirty_page_list, struct sgx_epc_page, list); ret = __eremove(sgx_get_epc_virt_addr(page)); - if (!ret) - list_move(&page->list, §ion->page_list); - else + if (!ret) { + /* + * page is now sanitized. Make it available via the SGX + * page allocator: + */ + list_del(&page->list); + sgx_free_epc_page(page); + } else { + /* The page is not yet clean - move to the dirty list. */ list_move_tail(&page->list, &dirty); - - spin_unlock(§ion->lock); + } cond_resched(); } - list_splice(&dirty, §ion->init_laundry_list); + list_splice(&dirty, dirty_page_list); } static bool sgx_reclaimer_age(struct sgx_epc_page *epc_page) @@ -195,10 +214,10 @@ static const cpumask_t *sgx_encl_ewb_cpumask(struct sgx_encl *encl) /* * Swap page to the regular memory transformed to the blocked state by using - * EBLOCK, which means that it can no loger be referenced (no new TLB entries). + * EBLOCK, which means that it can no longer be referenced (no new TLB entries). * * The first trial just tries to write the page assuming that some other thread - * has reset the count for threads inside the enlave by using ETRACK, and + * has reset the count for threads inside the enclave by using ETRACK, and * previous thread count has been zeroed out. The second trial calls ETRACK * before EWB. If that fails we kick all the HW threads out, and then do EWB, * which should be guaranteed the succeed. @@ -278,7 +297,7 @@ static void sgx_reclaimer_write(struct sgx_epc_page *epc_page, sgx_encl_ewb(encl->secs.epc_page, &secs_backing); - sgx_free_epc_page(encl->secs.epc_page); + sgx_encl_free_epc_page(encl->secs.epc_page); encl->secs.epc_page = NULL; sgx_encl_put_backing(&secs_backing, true); @@ -308,6 +327,7 @@ static void sgx_reclaim_pages(void) struct sgx_epc_section *section; struct sgx_encl_page *encl_page; struct sgx_epc_page *epc_page; + struct sgx_numa_node *node; pgoff_t page_index; int cnt = 0; int ret; @@ -379,50 +399,33 @@ skip: epc_page->flags &= ~SGX_EPC_PAGE_RECLAIMER_TRACKED; section = &sgx_epc_sections[epc_page->section]; - spin_lock(§ion->lock); - list_add_tail(&epc_page->list, §ion->page_list); - section->free_cnt++; - spin_unlock(§ion->lock); - } -} - -static unsigned long sgx_nr_free_pages(void) -{ - unsigned long cnt = 0; - int i; - - for (i = 0; i < sgx_nr_epc_sections; i++) - cnt += sgx_epc_sections[i].free_cnt; + node = section->node; - return cnt; + spin_lock(&node->lock); + list_add_tail(&epc_page->list, &node->free_page_list); + sgx_nr_free_pages++; + spin_unlock(&node->lock); + } } static bool sgx_should_reclaim(unsigned long watermark) { - return sgx_nr_free_pages() < watermark && - !list_empty(&sgx_active_page_list); + return sgx_nr_free_pages < watermark && !list_empty(&sgx_active_page_list); } static int ksgxd(void *p) { - int i; - set_freezable(); /* * Sanitize pages in order to recover from kexec(). The 2nd pass is * required for SECS pages, whose child pages blocked EREMOVE. */ - for (i = 0; i < sgx_nr_epc_sections; i++) - sgx_sanitize_section(&sgx_epc_sections[i]); - - for (i = 0; i < sgx_nr_epc_sections; i++) { - sgx_sanitize_section(&sgx_epc_sections[i]); + __sgx_sanitize_pages(&sgx_dirty_page_list); + __sgx_sanitize_pages(&sgx_dirty_page_list); - /* Should never happen. */ - if (!list_empty(&sgx_epc_sections[i].init_laundry_list)) - WARN(1, "EPC section %d has unsanitized pages.\n", i); - } + /* sanity check: */ + WARN_ON(!list_empty(&sgx_dirty_page_list)); while (!kthread_should_stop()) { if (try_to_freeze()) @@ -454,45 +457,56 @@ static bool __init sgx_page_reclaimer_init(void) return true; } -static struct sgx_epc_page *__sgx_alloc_epc_page_from_section(struct sgx_epc_section *section) +static struct sgx_epc_page *__sgx_alloc_epc_page_from_node(int nid) { - struct sgx_epc_page *page; + struct sgx_numa_node *node = &sgx_numa_nodes[nid]; + struct sgx_epc_page *page = NULL; - spin_lock(§ion->lock); + spin_lock(&node->lock); - if (list_empty(§ion->page_list)) { - spin_unlock(§ion->lock); + if (list_empty(&node->free_page_list)) { + spin_unlock(&node->lock); return NULL; } - page = list_first_entry(§ion->page_list, struct sgx_epc_page, list); + page = list_first_entry(&node->free_page_list, struct sgx_epc_page, list); list_del_init(&page->list); - section->free_cnt--; + sgx_nr_free_pages--; + + spin_unlock(&node->lock); - spin_unlock(§ion->lock); return page; } /** * __sgx_alloc_epc_page() - Allocate an EPC page * - * Iterate through EPC sections and borrow a free EPC page to the caller. When a - * page is no longer needed it must be released with sgx_free_epc_page(). + * Iterate through NUMA nodes and reserve ia free EPC page to the caller. Start + * from the NUMA node, where the caller is executing. * * Return: - * an EPC page, - * -errno on error + * - an EPC page: A borrowed EPC pages were available. + * - NULL: Out of EPC pages. */ struct sgx_epc_page *__sgx_alloc_epc_page(void) { - struct sgx_epc_section *section; struct sgx_epc_page *page; - int i; + int nid_of_current = numa_node_id(); + int nid = nid_of_current; - for (i = 0; i < sgx_nr_epc_sections; i++) { - section = &sgx_epc_sections[i]; + if (node_isset(nid_of_current, sgx_numa_mask)) { + page = __sgx_alloc_epc_page_from_node(nid_of_current); + if (page) + return page; + } + + /* Fall back to the non-local NUMA nodes: */ + while (true) { + nid = next_node_in(nid, sgx_numa_mask); + if (nid == nid_of_current) + break; - page = __sgx_alloc_epc_page_from_section(section); + page = __sgx_alloc_epc_page_from_node(nid); if (page) return page; } @@ -598,23 +612,22 @@ struct sgx_epc_page *sgx_alloc_epc_page(void *owner, bool reclaim) * sgx_free_epc_page() - Free an EPC page * @page: an EPC page * - * Call EREMOVE for an EPC page and insert it back to the list of free pages. + * Put the EPC page back to the list of free pages. It's the caller's + * responsibility to make sure that the page is in uninitialized state. In other + * words, do EREMOVE, EWB or whatever operation is necessary before calling + * this function. */ void sgx_free_epc_page(struct sgx_epc_page *page) { struct sgx_epc_section *section = &sgx_epc_sections[page->section]; - int ret; + struct sgx_numa_node *node = section->node; - WARN_ON_ONCE(page->flags & SGX_EPC_PAGE_RECLAIMER_TRACKED); + spin_lock(&node->lock); - ret = __eremove(sgx_get_epc_virt_addr(page)); - if (WARN_ONCE(ret, "EREMOVE returned %d (0x%x)", ret, ret)) - return; + list_add_tail(&page->list, &node->free_page_list); + sgx_nr_free_pages++; - spin_lock(§ion->lock); - list_add_tail(&page->list, §ion->page_list); - section->free_cnt++; - spin_unlock(§ion->lock); + spin_unlock(&node->lock); } static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size, @@ -635,18 +648,14 @@ static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size, } section->phys_addr = phys_addr; - spin_lock_init(§ion->lock); - INIT_LIST_HEAD(§ion->page_list); - INIT_LIST_HEAD(§ion->init_laundry_list); for (i = 0; i < nr_pages; i++) { section->pages[i].section = index; section->pages[i].flags = 0; section->pages[i].owner = NULL; - list_add_tail(§ion->pages[i].list, §ion->init_laundry_list); + list_add_tail(§ion->pages[i].list, &sgx_dirty_page_list); } - section->free_cnt = nr_pages; return true; } @@ -665,8 +674,13 @@ static bool __init sgx_page_cache_init(void) { u32 eax, ebx, ecx, edx, type; u64 pa, size; + int nid; int i; + sgx_numa_nodes = kmalloc_array(num_possible_nodes(), sizeof(*sgx_numa_nodes), GFP_KERNEL); + if (!sgx_numa_nodes) + return false; + for (i = 0; i < ARRAY_SIZE(sgx_epc_sections); i++) { cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC, &eax, &ebx, &ecx, &edx); @@ -689,6 +703,21 @@ static bool __init sgx_page_cache_init(void) break; } + nid = numa_map_to_online_node(phys_to_target_node(pa)); + if (nid == NUMA_NO_NODE) { + /* The physical address is already printed above. */ + pr_warn(FW_BUG "Unable to map EPC section to online node. Fallback to the NUMA node 0.\n"); + nid = 0; + } + + if (!node_isset(nid, sgx_numa_mask)) { + spin_lock_init(&sgx_numa_nodes[nid].lock); + INIT_LIST_HEAD(&sgx_numa_nodes[nid].free_page_list); + node_set(nid, sgx_numa_mask); + } + + sgx_epc_sections[i].node = &sgx_numa_nodes[nid]; + sgx_nr_epc_sections++; } @@ -700,6 +729,67 @@ static bool __init sgx_page_cache_init(void) return true; } +/* + * Update the SGX_LEPUBKEYHASH MSRs to the values specified by caller. + * Bare-metal driver requires to update them to hash of enclave's signer + * before EINIT. KVM needs to update them to guest's virtual MSR values + * before doing EINIT from guest. + */ +void sgx_update_lepubkeyhash(u64 *lepubkeyhash) +{ + int i; + + WARN_ON_ONCE(preemptible()); + + for (i = 0; i < 4; i++) + wrmsrl(MSR_IA32_SGXLEPUBKEYHASH0 + i, lepubkeyhash[i]); +} + +const struct file_operations sgx_provision_fops = { + .owner = THIS_MODULE, +}; + +static struct miscdevice sgx_dev_provision = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sgx_provision", + .nodename = "sgx_provision", + .fops = &sgx_provision_fops, +}; + +/** + * sgx_set_attribute() - Update allowed attributes given file descriptor + * @allowed_attributes: Pointer to allowed enclave attributes + * @attribute_fd: File descriptor for specific attribute + * + * Append enclave attribute indicated by file descriptor to allowed + * attributes. Currently only SGX_ATTR_PROVISIONKEY indicated by + * /dev/sgx_provision is supported. + * + * Return: + * -0: SGX_ATTR_PROVISIONKEY is appended to allowed_attributes + * -EINVAL: Invalid, or not supported file descriptor + */ +int sgx_set_attribute(unsigned long *allowed_attributes, + unsigned int attribute_fd) +{ + struct file *file; + + file = fget(attribute_fd); + if (!file) + return -EINVAL; + + if (file->f_op != &sgx_provision_fops) { + fput(file); + return -EINVAL; + } + + *allowed_attributes |= SGX_ATTR_PROVISIONKEY; + + fput(file); + return 0; +} +EXPORT_SYMBOL_GPL(sgx_set_attribute); + static int __init sgx_init(void) { int ret; @@ -716,12 +806,28 @@ static int __init sgx_init(void) goto err_page_cache; } - ret = sgx_drv_init(); + ret = misc_register(&sgx_dev_provision); if (ret) goto err_kthread; + /* + * Always try to initialize the native *and* KVM drivers. + * The KVM driver is less picky than the native one and + * can function if the native one is not supported on the + * current system or fails to initialize. + * + * Error out only if both fail to initialize. + */ + ret = sgx_drv_init(); + + if (sgx_vepc_init() && ret) + goto err_provision; + return 0; +err_provision: + misc_deregister(&sgx_dev_provision); + err_kthread: kthread_stop(ksgxd_tsk); diff --git a/arch/x86/kernel/cpu/sgx/sgx.h b/arch/x86/kernel/cpu/sgx/sgx.h index 5fa42d143feb869a1443ede7f5eb990bac184e0f..4628acec000915e2d2b41895088c3edbe5033c14 100644 --- a/arch/x86/kernel/cpu/sgx/sgx.h +++ b/arch/x86/kernel/cpu/sgx/sgx.h @@ -8,11 +8,15 @@ #include <linux/rwsem.h> #include <linux/types.h> #include <asm/asm.h> -#include "arch.h" +#include <asm/sgx.h> #undef pr_fmt #define pr_fmt(fmt) "sgx: " fmt +#define EREMOVE_ERROR_MESSAGE \ + "EREMOVE returned %d (0x%x) and an EPC page was leaked. SGX may become unusable. " \ + "Refer to Documentation/x86/sgx.rst for more information." + #define SGX_MAX_EPC_SECTIONS 8 #define SGX_EEXTEND_BLOCK_SIZE 256 #define SGX_NR_TO_SCAN 16 @@ -29,29 +33,26 @@ struct sgx_epc_page { struct list_head list; }; +/* + * Contains the tracking data for NUMA nodes having EPC pages. Most importantly, + * the free page list local to the node is stored here. + */ +struct sgx_numa_node { + struct list_head free_page_list; + spinlock_t lock; +}; + /* * The firmware can define multiple chunks of EPC to the different areas of the * physical memory e.g. for memory areas of the each node. This structure is * used to store EPC pages for one EPC section and virtual memory area where * the pages have been mapped. - * - * 'lock' must be held before accessing 'page_list' or 'free_cnt'. */ struct sgx_epc_section { unsigned long phys_addr; void *virt_addr; struct sgx_epc_page *pages; - - spinlock_t lock; - struct list_head page_list; - unsigned long free_cnt; - - /* - * Pages which need EREMOVE run on them before they can be - * used. Only safe to be accessed in ksgxd and init code. - * Not protected by locks. - */ - struct list_head init_laundry_list; + struct sgx_numa_node *node; }; extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; @@ -83,4 +84,15 @@ void sgx_mark_page_reclaimable(struct sgx_epc_page *page); int sgx_unmark_page_reclaimable(struct sgx_epc_page *page); struct sgx_epc_page *sgx_alloc_epc_page(void *owner, bool reclaim); +#ifdef CONFIG_X86_SGX_KVM +int __init sgx_vepc_init(void); +#else +static inline int __init sgx_vepc_init(void) +{ + return -ENODEV; +} +#endif + +void sgx_update_lepubkeyhash(u64 *lepubkeyhash); + #endif /* _X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/virt.c b/arch/x86/kernel/cpu/sgx/virt.c new file mode 100644 index 0000000000000000000000000000000000000000..6ad165a5c0cc57abbaf7e73fc9dfc5b42dd2c766 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/virt.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device driver to expose SGX enclave memory to KVM guests. + * + * Copyright(c) 2021 Intel Corporation. + */ + +#include <linux/miscdevice.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/sched/mm.h> +#include <linux/sched/signal.h> +#include <linux/slab.h> +#include <linux/xarray.h> +#include <asm/sgx.h> +#include <uapi/asm/sgx.h> + +#include "encls.h" +#include "sgx.h" + +struct sgx_vepc { + struct xarray page_array; + struct mutex lock; +}; + +/* + * Temporary SECS pages that cannot be EREMOVE'd due to having child in other + * virtual EPC instances, and the lock to protect it. + */ +static struct mutex zombie_secs_pages_lock; +static struct list_head zombie_secs_pages; + +static int __sgx_vepc_fault(struct sgx_vepc *vepc, + struct vm_area_struct *vma, unsigned long addr) +{ + struct sgx_epc_page *epc_page; + unsigned long index, pfn; + int ret; + + WARN_ON(!mutex_is_locked(&vepc->lock)); + + /* Calculate index of EPC page in virtual EPC's page_array */ + index = vma->vm_pgoff + PFN_DOWN(addr - vma->vm_start); + + epc_page = xa_load(&vepc->page_array, index); + if (epc_page) + return 0; + + epc_page = sgx_alloc_epc_page(vepc, false); + if (IS_ERR(epc_page)) + return PTR_ERR(epc_page); + + ret = xa_err(xa_store(&vepc->page_array, index, epc_page, GFP_KERNEL)); + if (ret) + goto err_free; + + pfn = PFN_DOWN(sgx_get_epc_phys_addr(epc_page)); + + ret = vmf_insert_pfn(vma, addr, pfn); + if (ret != VM_FAULT_NOPAGE) { + ret = -EFAULT; + goto err_delete; + } + + return 0; + +err_delete: + xa_erase(&vepc->page_array, index); +err_free: + sgx_free_epc_page(epc_page); + return ret; +} + +static vm_fault_t sgx_vepc_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct sgx_vepc *vepc = vma->vm_private_data; + int ret; + + mutex_lock(&vepc->lock); + ret = __sgx_vepc_fault(vepc, vma, vmf->address); + mutex_unlock(&vepc->lock); + + if (!ret) + return VM_FAULT_NOPAGE; + + if (ret == -EBUSY && (vmf->flags & FAULT_FLAG_ALLOW_RETRY)) { + mmap_read_unlock(vma->vm_mm); + return VM_FAULT_RETRY; + } + + return VM_FAULT_SIGBUS; +} + +static const struct vm_operations_struct sgx_vepc_vm_ops = { + .fault = sgx_vepc_fault, +}; + +static int sgx_vepc_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct sgx_vepc *vepc = file->private_data; + + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vma->vm_ops = &sgx_vepc_vm_ops; + /* Don't copy VMA in fork() */ + vma->vm_flags |= VM_PFNMAP | VM_IO | VM_DONTDUMP | VM_DONTCOPY; + vma->vm_private_data = vepc; + + return 0; +} + +static int sgx_vepc_free_page(struct sgx_epc_page *epc_page) +{ + int ret; + + /* + * Take a previously guest-owned EPC page and return it to the + * general EPC page pool. + * + * Guests can not be trusted to have left this page in a good + * state, so run EREMOVE on the page unconditionally. In the + * case that a guest properly EREMOVE'd this page, a superfluous + * EREMOVE is harmless. + */ + ret = __eremove(sgx_get_epc_virt_addr(epc_page)); + if (ret) { + /* + * Only SGX_CHILD_PRESENT is expected, which is because of + * EREMOVE'ing an SECS still with child, in which case it can + * be handled by EREMOVE'ing the SECS again after all pages in + * virtual EPC have been EREMOVE'd. See comments in below in + * sgx_vepc_release(). + * + * The user of virtual EPC (KVM) needs to guarantee there's no + * logical processor is still running in the enclave in guest, + * otherwise EREMOVE will get SGX_ENCLAVE_ACT which cannot be + * handled here. + */ + WARN_ONCE(ret != SGX_CHILD_PRESENT, EREMOVE_ERROR_MESSAGE, + ret, ret); + return ret; + } + + sgx_free_epc_page(epc_page); + + return 0; +} + +static int sgx_vepc_release(struct inode *inode, struct file *file) +{ + struct sgx_vepc *vepc = file->private_data; + struct sgx_epc_page *epc_page, *tmp, *entry; + unsigned long index; + + LIST_HEAD(secs_pages); + + xa_for_each(&vepc->page_array, index, entry) { + /* + * Remove all normal, child pages. sgx_vepc_free_page() + * will fail if EREMOVE fails, but this is OK and expected on + * SECS pages. Those can only be EREMOVE'd *after* all their + * child pages. Retries below will clean them up. + */ + if (sgx_vepc_free_page(entry)) + continue; + + xa_erase(&vepc->page_array, index); + } + + /* + * Retry EREMOVE'ing pages. This will clean up any SECS pages that + * only had children in this 'epc' area. + */ + xa_for_each(&vepc->page_array, index, entry) { + epc_page = entry; + /* + * An EREMOVE failure here means that the SECS page still + * has children. But, since all children in this 'sgx_vepc' + * have been removed, the SECS page must have a child on + * another instance. + */ + if (sgx_vepc_free_page(epc_page)) + list_add_tail(&epc_page->list, &secs_pages); + + xa_erase(&vepc->page_array, index); + } + + /* + * SECS pages are "pinned" by child pages, and "unpinned" once all + * children have been EREMOVE'd. A child page in this instance + * may have pinned an SECS page encountered in an earlier release(), + * creating a zombie. Since some children were EREMOVE'd above, + * try to EREMOVE all zombies in the hopes that one was unpinned. + */ + mutex_lock(&zombie_secs_pages_lock); + list_for_each_entry_safe(epc_page, tmp, &zombie_secs_pages, list) { + /* + * Speculatively remove the page from the list of zombies, + * if the page is successfully EREMOVE'd it will be added to + * the list of free pages. If EREMOVE fails, throw the page + * on the local list, which will be spliced on at the end. + */ + list_del(&epc_page->list); + + if (sgx_vepc_free_page(epc_page)) + list_add_tail(&epc_page->list, &secs_pages); + } + + if (!list_empty(&secs_pages)) + list_splice_tail(&secs_pages, &zombie_secs_pages); + mutex_unlock(&zombie_secs_pages_lock); + + kfree(vepc); + + return 0; +} + +static int sgx_vepc_open(struct inode *inode, struct file *file) +{ + struct sgx_vepc *vepc; + + vepc = kzalloc(sizeof(struct sgx_vepc), GFP_KERNEL); + if (!vepc) + return -ENOMEM; + mutex_init(&vepc->lock); + xa_init(&vepc->page_array); + + file->private_data = vepc; + + return 0; +} + +static const struct file_operations sgx_vepc_fops = { + .owner = THIS_MODULE, + .open = sgx_vepc_open, + .release = sgx_vepc_release, + .mmap = sgx_vepc_mmap, +}; + +static struct miscdevice sgx_vepc_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sgx_vepc", + .nodename = "sgx_vepc", + .fops = &sgx_vepc_fops, +}; + +int __init sgx_vepc_init(void) +{ + /* SGX virtualization requires KVM to work */ + if (!cpu_feature_enabled(X86_FEATURE_VMX)) + return -ENODEV; + + INIT_LIST_HEAD(&zombie_secs_pages); + mutex_init(&zombie_secs_pages_lock); + + return misc_register(&sgx_vepc_dev); +} + +/** + * sgx_virt_ecreate() - Run ECREATE on behalf of guest + * @pageinfo: Pointer to PAGEINFO structure + * @secs: Userspace pointer to SECS page + * @trapnr: trap number injected to guest in case of ECREATE error + * + * Run ECREATE on behalf of guest after KVM traps ECREATE for the purpose + * of enforcing policies of guest's enclaves, and return the trap number + * which should be injected to guest in case of any ECREATE error. + * + * Return: + * - 0: ECREATE was successful. + * - <0: on error. + */ +int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs, + int *trapnr) +{ + int ret; + + /* + * @secs is an untrusted, userspace-provided address. It comes from + * KVM and is assumed to be a valid pointer which points somewhere in + * userspace. This can fault and call SGX or other fault handlers when + * userspace mapping @secs doesn't exist. + * + * Add a WARN() to make sure @secs is already valid userspace pointer + * from caller (KVM), who should already have handled invalid pointer + * case (for instance, made by malicious guest). All other checks, + * such as alignment of @secs, are deferred to ENCLS itself. + */ + if (WARN_ON_ONCE(!access_ok(secs, PAGE_SIZE))) + return -EINVAL; + + __uaccess_begin(); + ret = __ecreate(pageinfo, (void *)secs); + __uaccess_end(); + + if (encls_faulted(ret)) { + *trapnr = ENCLS_TRAPNR(ret); + return -EFAULT; + } + + /* ECREATE doesn't return an error code, it faults or succeeds. */ + WARN_ON_ONCE(ret); + return 0; +} +EXPORT_SYMBOL_GPL(sgx_virt_ecreate); + +static int __sgx_virt_einit(void __user *sigstruct, void __user *token, + void __user *secs) +{ + int ret; + + /* + * Make sure all userspace pointers from caller (KVM) are valid. + * All other checks deferred to ENCLS itself. Also see comment + * for @secs in sgx_virt_ecreate(). + */ +#define SGX_EINITTOKEN_SIZE 304 + if (WARN_ON_ONCE(!access_ok(sigstruct, sizeof(struct sgx_sigstruct)) || + !access_ok(token, SGX_EINITTOKEN_SIZE) || + !access_ok(secs, PAGE_SIZE))) + return -EINVAL; + + __uaccess_begin(); + ret = __einit((void *)sigstruct, (void *)token, (void *)secs); + __uaccess_end(); + + return ret; +} + +/** + * sgx_virt_einit() - Run EINIT on behalf of guest + * @sigstruct: Userspace pointer to SIGSTRUCT structure + * @token: Userspace pointer to EINITTOKEN structure + * @secs: Userspace pointer to SECS page + * @lepubkeyhash: Pointer to guest's *virtual* SGX_LEPUBKEYHASH MSR values + * @trapnr: trap number injected to guest in case of EINIT error + * + * Run EINIT on behalf of guest after KVM traps EINIT. If SGX_LC is available + * in host, SGX driver may rewrite the hardware values at wish, therefore KVM + * needs to update hardware values to guest's virtual MSR values in order to + * ensure EINIT is executed with expected hardware values. + * + * Return: + * - 0: EINIT was successful. + * - <0: on error. + */ +int sgx_virt_einit(void __user *sigstruct, void __user *token, + void __user *secs, u64 *lepubkeyhash, int *trapnr) +{ + int ret; + + if (!cpu_feature_enabled(X86_FEATURE_SGX_LC)) { + ret = __sgx_virt_einit(sigstruct, token, secs); + } else { + preempt_disable(); + + sgx_update_lepubkeyhash(lepubkeyhash); + + ret = __sgx_virt_einit(sigstruct, token, secs); + preempt_enable(); + } + + /* Propagate up the error from the WARN_ON_ONCE in __sgx_virt_einit() */ + if (ret == -EINVAL) + return ret; + + if (encls_faulted(ret)) { + *trapnr = ENCLS_TRAPNR(ret); + return -EFAULT; + } + + return ret; +} +EXPORT_SYMBOL_GPL(sgx_virt_einit); diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c index 8678864ce7123c35cbb5d0ab09e9ffcd91095e16..132a2de44d2fe4d6906516d0c0b776d42a0ed74b 100644 --- a/arch/x86/kernel/cpu/topology.c +++ b/arch/x86/kernel/cpu/topology.c @@ -30,7 +30,7 @@ EXPORT_SYMBOL(__max_die_per_package); #ifdef CONFIG_SMP /* - * Check if given CPUID extended toplogy "leaf" is implemented + * Check if given CPUID extended topology "leaf" is implemented */ static int check_extended_topology_leaf(int leaf) { @@ -44,7 +44,7 @@ static int check_extended_topology_leaf(int leaf) return 0; } /* - * Return best CPUID Extended Toplogy Leaf supported + * Return best CPUID Extended Topology Leaf supported */ static int detect_extended_topology_leaf(struct cpuinfo_x86 *c) { diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index c6ede3b3d302d3fb28222f0f398e5afb6a3ca336..c04b933f48d38257e1ca241875a10581b1c92121 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -27,6 +27,7 @@ #include <linux/clocksource.h> #include <linux/cpu.h> #include <linux/reboot.h> +#include <linux/static_call.h> #include <asm/div64.h> #include <asm/x86_init.h> #include <asm/hypervisor.h> @@ -336,11 +337,11 @@ static void __init vmware_paravirt_ops_setup(void) vmware_cyc2ns_setup(); if (vmw_sched_clock) - pv_ops.time.sched_clock = vmware_sched_clock; + paravirt_set_sched_clock(vmware_sched_clock); if (vmware_is_stealclock_available()) { has_steal_clock = true; - pv_ops.time.steal_clock = vmware_steal_clock; + static_call_update(pv_steal_clock, vmware_steal_clock); /* We use reboot notifier only to disable steal clock */ register_reboot_notifier(&vmware_pv_reboot_nb); @@ -378,6 +379,8 @@ static void __init vmware_set_capabilities(void) { setup_force_cpu_cap(X86_FEATURE_CONSTANT_TSC); setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE); + if (vmware_tsc_khz) + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMCALL) setup_force_cpu_cap(X86_FEATURE_VMCALL); else if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMMCALL) diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 22aad412f965e60d0c41265cd2a544eb412d1b5b..bc0657f0deedf2b13641088b9b8ea9173262f70b 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -31,8 +31,8 @@ * - inform the user about the firmware's notion of memory layout * via /sys/firmware/memmap * - * - the hibernation code uses it to generate a kernel-independent MD5 - * fingerprint of the physical memory layout of a system. + * - the hibernation code uses it to generate a kernel-independent CRC32 + * checksum of the physical memory layout of a system. * * - 'e820_table_kexec': a slightly modified (by the kernel) firmware version * passed to us by the bootloader - the major difference between @@ -793,7 +793,7 @@ core_initcall(e820__register_nvs_regions); #endif /* - * Allocate the requested number of bytes with the requsted alignment + * Allocate the requested number of bytes with the requested alignment * and return (the physical address) to the caller. Also register this * range in the 'kexec' E820 table as a reserved range. * diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 683749b80ae2829c0a3f56734c4e0da0bc3e4e0e..a85c64000218968bc30854ccb583845b6790175d 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -253,7 +253,7 @@ static bool xfeature_enabled(enum xfeature xfeature) static void __init setup_xstate_features(void) { u32 eax, ebx, ecx, edx, i; - /* start at the beginnning of the "extended state" */ + /* start at the beginning of the "extended state" */ unsigned int last_good_offset = offsetof(struct xregs_state, extended_state_area); /* diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 5e9beb77cafd43895794295824135ecb3dea3b4e..18be44163a50fb4ec9d06f3094fad3b4a0bdb732 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -104,7 +104,7 @@ static unsigned int __head *fixup_int(void *ptr, unsigned long physaddr) static bool __head check_la57_support(unsigned long physaddr) { /* - * 5-level paging is detected and enabled at kernel decomression + * 5-level paging is detected and enabled at kernel decompression * stage. Only check if it has been enabled there. */ if (!(native_read_cr4() & X86_CR4_LA57)) diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index ee1a283f8e966655d76ab52b0b3ac8d61b78e8ef..d552f177eca0e927c7a56efcff2c7fcbe7af21e3 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -245,7 +245,7 @@ static const __initconst struct idt_data ist_idts[] = { * after that. * * Note, that X86_64 cannot install the real #PF handler in - * idt_setup_early_traps() because the memory intialization needs the #PF + * idt_setup_early_traps() because the memory initialization needs the #PF * handler from the early_idt_handler_array to initialize the early page * tables. */ diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 58aa712973ac80608652378785a3255c9a88dfb7..e28f6a5d14f1b2d14ca4c4e9aaae2ec2b0f4a3dd 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -338,7 +338,7 @@ void fixup_irqs(void) irq_migrate_all_off_this_cpu(); /* - * We can remove mdelay() and then send spuriuous interrupts to + * We can remove mdelay() and then send spurious interrupts to * new cpu targets for all the irqs that were handled previously by * this cpu. While it works, I have seen spurious interrupt messages * (nothing wrong but still...). diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index ff7878df96b4606cc307c95902d7ebcbb046d806..3a43a2dee658189764c440240c0621225e75c4fb 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -17,7 +17,7 @@ * Updated by: Tom Rini <trini@kernel.crashing.org> * Updated by: Jason Wessel <jason.wessel@windriver.com> * Modified for 386 by Jim Kingdon, Cygnus Support. - * Origianl kgdb, compatibility with 2.1.xx kernel by + * Original kgdb, compatibility with 2.1.xx kernel by * David Grothe <dave@gcom.com> * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com> * X86_64 changes from Andi Kleen's patch merged by Jim Houston @@ -642,7 +642,7 @@ void kgdb_arch_late(void) struct perf_event **pevent; /* - * Pre-allocate the hw breakpoint structions in the non-atomic + * Pre-allocate the hw breakpoint instructions in the non-atomic * portion of kgdb because this operation requires mutexs to * complete. */ diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c index 51c7f5271aee47abf14b83733fa0e0d34c9a9926..596de2f6d3a57f522f1fa30496a5ec75977e63a7 100644 --- a/arch/x86/kernel/kprobes/ftrace.c +++ b/arch/x86/kernel/kprobes/ftrace.c @@ -12,7 +12,7 @@ #include "common.h" -/* Ftrace callback handler for kprobes -- called under preepmt disabled */ +/* Ftrace callback handler for kprobes -- called under preempt disabled */ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct ftrace_regs *fregs) { diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 78bb0fae39826cff94ac2081f327c91e7d87d8c4..172c947240b991ff40eb78a2faf8529679ae6264 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -650,7 +650,7 @@ static void __init kvm_guest_init(void) if (kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { has_steal_clock = 1; - pv_ops.time.steal_clock = kvm_steal_clock; + static_call_update(pv_steal_clock, kvm_steal_clock); } if (pv_tlb_flush_supported()) { diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 1fc0962c89c082b5b638a79efc040e4940de9991..d37ed4e1d0338c8b21ad461f5d2672cead15629a 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -106,7 +106,7 @@ static inline void kvm_sched_clock_init(bool stable) if (!stable) clear_sched_clock_stable(); kvm_sched_clock_offset = kvm_clock_read(); - pv_ops.time.sched_clock = kvm_sched_clock_read; + paravirt_set_sched_clock(kvm_sched_clock_read); pr_info("kvm-clock: using sched offset of %llu cycles", kvm_sched_clock_offset); diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index a29a44a98e5bef10751af769bd198d783e23b9fd..f01cd9a08155795e62e0a550817ca6e9ca5c1fdf 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -260,7 +260,7 @@ static void set_idt(void *newidt, u16 limit) { struct desc_ptr curidt; - /* x86-64 supports unaliged loads & stores */ + /* x86-64 supports unaligned loads & stores */ curidt.size = limit; curidt.address = (unsigned long)newidt; diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c index 4f75d0cf6305f04221bb9df16ac40e843193707b..9e1ea99ad9df4beca4771705b32b46444e7c925e 100644 --- a/arch/x86/kernel/paravirt-spinlocks.c +++ b/arch/x86/kernel/paravirt-spinlocks.c @@ -32,3 +32,12 @@ bool pv_is_native_vcpu_is_preempted(void) return pv_ops.lock.vcpu_is_preempted.func == __raw_callee_save___native_vcpu_is_preempted; } + +void __init paravirt_set_cap(void) +{ + if (!pv_is_native_spin_unlock()) + setup_force_cpu_cap(X86_FEATURE_PVUNLOCK); + + if (!pv_is_native_vcpu_is_preempted()) + setup_force_cpu_cap(X86_FEATURE_VCPUPREEMPT); +} diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index c60222ab8ab9b8ae2dded7687609b3165020c544..d0730264786b2175e409cc1396edc8668afe8ecf 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -14,6 +14,7 @@ #include <linux/highmem.h> #include <linux/kprobes.h> #include <linux/pgtable.h> +#include <linux/static_call.h> #include <asm/bug.h> #include <asm/paravirt.h> @@ -52,7 +53,10 @@ void __init default_banner(void) } /* Undefined instruction for dealing with missing ops pointers. */ -static const unsigned char ud2a[] = { 0x0f, 0x0b }; +static void paravirt_BUG(void) +{ + BUG(); +} struct branch { unsigned char opcode; @@ -85,25 +89,6 @@ u64 notrace _paravirt_ident_64(u64 x) { return x; } - -static unsigned paravirt_patch_jmp(void *insn_buff, const void *target, - unsigned long addr, unsigned len) -{ - struct branch *b = insn_buff; - unsigned long delta = (unsigned long)target - (addr+5); - - if (len < 5) { -#ifdef CONFIG_RETPOLINE - WARN_ONCE(1, "Failing to patch indirect JMP in %ps\n", (void *)addr); -#endif - return len; /* call too long for patch site */ - } - - b->opcode = 0xe9; /* jmp */ - b->delta = delta; - - return 5; -} #endif DEFINE_STATIC_KEY_TRUE(virt_spin_lock_key); @@ -114,8 +99,8 @@ void __init native_pv_lock_init(void) static_branch_disable(&virt_spin_lock_key); } -unsigned paravirt_patch_default(u8 type, void *insn_buff, - unsigned long addr, unsigned len) +unsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr, + unsigned int len) { /* * Neat trick to map patch type back to the call within the @@ -125,20 +110,10 @@ unsigned paravirt_patch_default(u8 type, void *insn_buff, unsigned ret; if (opfunc == NULL) - /* If there's no function, patch it with a ud2a (BUG) */ - ret = paravirt_patch_insns(insn_buff, len, ud2a, ud2a+sizeof(ud2a)); + /* If there's no function, patch it with paravirt_BUG() */ + ret = paravirt_patch_call(insn_buff, paravirt_BUG, addr, len); else if (opfunc == _paravirt_nop) ret = 0; - -#ifdef CONFIG_PARAVIRT_XXL - /* identity functions just return their single argument */ - else if (opfunc == _paravirt_ident_64) - ret = paravirt_patch_ident_64(insn_buff, len); - - else if (type == PARAVIRT_PATCH(cpu.iret)) - /* If operation requires a jmp, then jmp */ - ret = paravirt_patch_jmp(insn_buff, opfunc, addr, len); -#endif else /* Otherwise call the function. */ ret = paravirt_patch_call(insn_buff, opfunc, addr, len); @@ -146,19 +121,6 @@ unsigned paravirt_patch_default(u8 type, void *insn_buff, return ret; } -unsigned paravirt_patch_insns(void *insn_buff, unsigned len, - const char *start, const char *end) -{ - unsigned insn_len = end - start; - - /* Alternative instruction is too large for the patch site and we cannot continue: */ - BUG_ON(insn_len > len || start == NULL); - - memcpy(insn_buff, start, insn_len); - - return insn_len; -} - struct static_key paravirt_steal_enabled; struct static_key paravirt_steal_rq_enabled; @@ -167,6 +129,14 @@ static u64 native_steal_clock(int cpu) return 0; } +DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); +DEFINE_STATIC_CALL(pv_sched_clock, native_sched_clock); + +void paravirt_set_sched_clock(u64 (*func)(void)) +{ + static_call_update(pv_sched_clock, func); +} + /* These are in entry.S */ extern void native_iret(void); @@ -269,13 +239,6 @@ struct pv_info pv_info = { #define PTE_IDENT __PV_IS_CALLEE_SAVE(_paravirt_ident_64) struct paravirt_patch_template pv_ops = { - /* Init ops. */ - .init.patch = native_patch, - - /* Time ops. */ - .time.sched_clock = native_sched_clock, - .time.steal_clock = native_steal_clock, - /* Cpu ops. */ .cpu.io_delay = native_io_delay, @@ -308,8 +271,6 @@ struct paravirt_patch_template pv_ops = { .cpu.load_sp0 = native_load_sp0, - .cpu.iret = native_iret, - #ifdef CONFIG_X86_IOPL_IOPERM .cpu.invalidate_io_bitmap = native_tss_invalidate_io_bitmap, .cpu.update_io_bitmap = native_tss_update_io_bitmap, @@ -414,6 +375,8 @@ struct paravirt_patch_template pv_ops = { NOKPROBE_SYMBOL(native_get_debugreg); NOKPROBE_SYMBOL(native_set_debugreg); NOKPROBE_SYMBOL(native_load_idt); + +void (*paravirt_iret)(void) = native_iret; #endif EXPORT_SYMBOL(pv_ops); diff --git a/arch/x86/kernel/paravirt_patch.c b/arch/x86/kernel/paravirt_patch.c deleted file mode 100644 index abd27ec67397c3e4d7e97d529d169408f76948f1..0000000000000000000000000000000000000000 --- a/arch/x86/kernel/paravirt_patch.c +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/stringify.h> - -#include <asm/paravirt.h> -#include <asm/asm-offsets.h> - -#define PSTART(d, m) \ - patch_data_##d.m - -#define PEND(d, m) \ - (PSTART(d, m) + sizeof(patch_data_##d.m)) - -#define PATCH(d, m, insn_buff, len) \ - paravirt_patch_insns(insn_buff, len, PSTART(d, m), PEND(d, m)) - -#define PATCH_CASE(ops, m, data, insn_buff, len) \ - case PARAVIRT_PATCH(ops.m): \ - return PATCH(data, ops##_##m, insn_buff, len) - -#ifdef CONFIG_PARAVIRT_XXL -struct patch_xxl { - const unsigned char irq_irq_disable[1]; - const unsigned char irq_irq_enable[1]; - const unsigned char irq_save_fl[2]; - const unsigned char mmu_read_cr2[3]; - const unsigned char mmu_read_cr3[3]; - const unsigned char mmu_write_cr3[3]; - const unsigned char cpu_wbinvd[2]; - const unsigned char mov64[3]; -}; - -static const struct patch_xxl patch_data_xxl = { - .irq_irq_disable = { 0xfa }, // cli - .irq_irq_enable = { 0xfb }, // sti - .irq_save_fl = { 0x9c, 0x58 }, // pushf; pop %[re]ax - .mmu_read_cr2 = { 0x0f, 0x20, 0xd0 }, // mov %cr2, %[re]ax - .mmu_read_cr3 = { 0x0f, 0x20, 0xd8 }, // mov %cr3, %[re]ax - .mmu_write_cr3 = { 0x0f, 0x22, 0xdf }, // mov %rdi, %cr3 - .cpu_wbinvd = { 0x0f, 0x09 }, // wbinvd - .mov64 = { 0x48, 0x89, 0xf8 }, // mov %rdi, %rax -}; - -unsigned int paravirt_patch_ident_64(void *insn_buff, unsigned int len) -{ - return PATCH(xxl, mov64, insn_buff, len); -} -# endif /* CONFIG_PARAVIRT_XXL */ - -#ifdef CONFIG_PARAVIRT_SPINLOCKS -struct patch_lock { - unsigned char queued_spin_unlock[3]; - unsigned char vcpu_is_preempted[2]; -}; - -static const struct patch_lock patch_data_lock = { - .vcpu_is_preempted = { 0x31, 0xc0 }, // xor %eax, %eax - -# ifdef CONFIG_X86_64 - .queued_spin_unlock = { 0xc6, 0x07, 0x00 }, // movb $0, (%rdi) -# else - .queued_spin_unlock = { 0xc6, 0x00, 0x00 }, // movb $0, (%eax) -# endif -}; -#endif /* CONFIG_PARAVIRT_SPINLOCKS */ - -unsigned int native_patch(u8 type, void *insn_buff, unsigned long addr, - unsigned int len) -{ - switch (type) { - -#ifdef CONFIG_PARAVIRT_XXL - PATCH_CASE(irq, save_fl, xxl, insn_buff, len); - PATCH_CASE(irq, irq_enable, xxl, insn_buff, len); - PATCH_CASE(irq, irq_disable, xxl, insn_buff, len); - - PATCH_CASE(mmu, read_cr2, xxl, insn_buff, len); - PATCH_CASE(mmu, read_cr3, xxl, insn_buff, len); - PATCH_CASE(mmu, write_cr3, xxl, insn_buff, len); - - PATCH_CASE(cpu, wbinvd, xxl, insn_buff, len); -#endif - -#ifdef CONFIG_PARAVIRT_SPINLOCKS - case PARAVIRT_PATCH(lock.queued_spin_unlock): - if (pv_is_native_spin_unlock()) - return PATCH(lock, queued_spin_unlock, insn_buff, len); - break; - - case PARAVIRT_PATCH(lock.vcpu_is_preempted): - if (pv_is_native_vcpu_is_preempted()) - return PATCH(lock, vcpu_is_preempted, insn_buff, len); - break; -#endif - default: - break; - } - - return paravirt_patch_default(type, insn_buff, addr, len); -} diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 9c214d7085a489a2c18c093619e6ef6b1210b01d..43cbfc84153ae2c6ba4bcff93fe719e3902a0d1b 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -63,14 +63,9 @@ __visible DEFINE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss_rw) = { */ .sp0 = (1UL << (BITS_PER_LONG-1)) + 1, - /* - * .sp1 is cpu_current_top_of_stack. The init task never - * runs user code, but cpu_current_top_of_stack should still - * be well defined before the first context switch. - */ +#ifdef CONFIG_X86_32 .sp1 = TOP_OF_INIT_STACK, -#ifdef CONFIG_X86_32 .ss0 = __KERNEL_DS, .ss1 = __KERNEL_CS, #endif @@ -451,7 +446,7 @@ void speculative_store_bypass_ht_init(void) * First HT sibling to come up on the core. Link shared state of * the first HT sibling to itself. The siblings on the same core * which come up later will see the shared state pointer and link - * themself to the state of this CPU. + * themselves to the state of this CPU. */ st->shared_state = st; } diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index 11065dc03f5bc83c5eda66309047ccff34620507..eda37df016f02905e4ca6e2155efbbbb4180d744 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -89,7 +89,7 @@ u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) /* * Assumption here is that last_value, a global accumulator, always goes * forward. If we are less than that, we should not be much smaller. - * We assume there is an error marging we're inside, and then the correction + * We assume there is an error margin we're inside, and then the correction * does not sacrifice accuracy. * * For reads: global may have changed between test and return, diff --git a/arch/x86/kernel/relocate_kernel_32.S b/arch/x86/kernel/relocate_kernel_32.S index 94b33885f8d20463c3038392a36373e266357a9d..f469153eca8ab305a873d4ac667b031a64e453ee 100644 --- a/arch/x86/kernel/relocate_kernel_32.S +++ b/arch/x86/kernel/relocate_kernel_32.S @@ -107,7 +107,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) * - Write protect disabled * - No task switch * - Don't do FP software emulation. - * - Proctected mode enabled + * - Protected mode enabled */ movl %cr0, %eax andl $~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %eax diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index a4d9a261425b0f48da767884068112a053823fdb..c53271aebb64d9b6298f034206a9a130bc067c92 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -121,7 +121,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) * - Write protect disabled * - No task switch * - Don't do FP software emulation. - * - Proctected mode enabled + * - Protected mode enabled */ movq %cr0, %rax andq $~(X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %rax diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index ccab6cf91283d75c1fd6a06db437e6a2526dc70a..69757fac7462a9d48ac6cbc39fd1eea6e51083a3 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -65,7 +65,7 @@ RESERVE_BRK(dmi_alloc, 65536); /* * Range of the BSS area. The size of the BSS area is determined - * at link time, with RESERVE_BRK*() facility reserving additional + * at link time, with RESERVE_BRK() facility reserving additional * chunks. */ unsigned long _brk_start = (unsigned long)__brk_base; @@ -633,11 +633,16 @@ static void __init trim_snb_memory(void) printk(KERN_DEBUG "reserving inaccessible SNB gfx pages\n"); /* - * Reserve all memory below the 1 MB mark that has not - * already been reserved. + * SandyBridge integrated graphics devices have a bug that prevents + * them from accessing certain memory ranges, namely anything below + * 1M and in the pages listed in bad_pages[] above. + * + * To avoid these pages being ever accessed by SNB gfx devices + * reserve all memory below the 1 MB mark and bad_pages that have + * not already been reserved at boot time. */ memblock_reserve(0, 1<<20); - + for (i = 0; i < ARRAY_SIZE(bad_pages); i++) { if (memblock_reserve(bad_pages[i], PAGE_SIZE)) printk(KERN_WARNING "failed to reserve 0x%08lx\n", @@ -645,18 +650,6 @@ static void __init trim_snb_memory(void) } } -/* - * Here we put platform-specific memory range workarounds, i.e. - * memory known to be corrupt or otherwise in need to be reserved on - * specific platforms. - * - * If this gets used more widely it could use a real dispatch mechanism. - */ -static void __init trim_platform_memory_ranges(void) -{ - trim_snb_memory(); -} - static void __init trim_bios_range(void) { /* @@ -725,11 +718,41 @@ static int __init parse_reservelow(char *p) early_param("reservelow", parse_reservelow); -static void __init trim_low_memory_range(void) +static void __init early_reserve_memory(void) { + /* + * Reserve the memory occupied by the kernel between _text and + * __end_of_kernel_reserve symbols. Any kernel sections after the + * __end_of_kernel_reserve symbol must be explicitly reserved with a + * separate memblock_reserve() or they will be discarded. + */ + memblock_reserve(__pa_symbol(_text), + (unsigned long)__end_of_kernel_reserve - (unsigned long)_text); + + /* + * The first 4Kb of memory is a BIOS owned area, but generally it is + * not listed as such in the E820 table. + * + * Reserve the first memory page and typically some additional + * memory (64KiB by default) since some BIOSes are known to corrupt + * low memory. See the Kconfig help text for X86_RESERVE_LOW. + * + * In addition, make sure page 0 is always reserved because on + * systems with L1TF its contents can be leaked to user processes. + */ memblock_reserve(0, ALIGN(reserve_low, PAGE_SIZE)); + + early_reserve_initrd(); + + if (efi_enabled(EFI_BOOT)) + efi_memblock_x86_reserve_range(); + + memblock_x86_reserve_range_setup_data(); + + reserve_ibft_region(); + reserve_bios_regions(); } - + /* * Dump out kernel offset information on panic. */ @@ -764,29 +787,6 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p) void __init setup_arch(char **cmdline_p) { - /* - * Reserve the memory occupied by the kernel between _text and - * __end_of_kernel_reserve symbols. Any kernel sections after the - * __end_of_kernel_reserve symbol must be explicitly reserved with a - * separate memblock_reserve() or they will be discarded. - */ - memblock_reserve(__pa_symbol(_text), - (unsigned long)__end_of_kernel_reserve - (unsigned long)_text); - - /* - * Make sure page 0 is always reserved because on systems with - * L1TF its contents can be leaked to user processes. - */ - memblock_reserve(0, PAGE_SIZE); - - early_reserve_initrd(); - - /* - * At this point everything still needed from the boot loader - * or BIOS or kernel text should be early reserved or marked not - * RAM in e820. All other memory is free game. - */ - #ifdef CONFIG_X86_32 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); @@ -910,8 +910,18 @@ void __init setup_arch(char **cmdline_p) parse_early_param(); - if (efi_enabled(EFI_BOOT)) - efi_memblock_x86_reserve_range(); + /* + * Do some memory reservations *before* memory is added to + * memblock, so memblock allocations won't overwrite it. + * Do it after early param, so we could get (unlikely) panic from + * serial. + * + * After this point everything still needed from the boot loader or + * firmware or kernel text should be early reserved or marked not + * RAM in e820. All other memory is free game. + */ + early_reserve_memory(); + #ifdef CONFIG_MEMORY_HOTPLUG /* * Memory used by the kernel cannot be hot-removed because Linux @@ -938,9 +948,6 @@ void __init setup_arch(char **cmdline_p) x86_report_nx(); - /* after early param, so could get panic from serial */ - memblock_x86_reserve_range_setup_data(); - if (acpi_mps_check()) { #ifdef CONFIG_X86_LOCAL_APIC disable_apic = 1; @@ -1032,14 +1039,12 @@ void __init setup_arch(char **cmdline_p) */ find_smp_config(); - reserve_ibft_region(); - early_alloc_pgt_buf(); /* * Need to conclude brk, before e820__memblock_setup() - * it could use memblock_find_in_range, could overlap with - * brk area. + * it could use memblock_find_in_range, could overlap with + * brk area. */ reserve_brk(); @@ -1054,8 +1059,6 @@ void __init setup_arch(char **cmdline_p) */ sev_setup_arch(); - reserve_bios_regions(); - efi_fake_memmap(); efi_find_mirror(); efi_esrt_init(); @@ -1081,8 +1084,12 @@ void __init setup_arch(char **cmdline_p) reserve_real_mode(); - trim_platform_memory_ranges(); - trim_low_memory_range(); + /* + * Reserving memory causing GPU hangs on Sandy Bridge integrated + * graphics devices should be done after we allocated memory under + * 1M for the real mode trampoline. + */ + trim_snb_memory(); init_mem_mapping(); diff --git a/arch/x86/kernel/sev-es-shared.c b/arch/x86/kernel/sev-es-shared.c index cdc04d09124233d0c90c3def9a2dc6fcaadaade9..0aa9f13efd57230b4690059878cd0253ed8c2e01 100644 --- a/arch/x86/kernel/sev-es-shared.c +++ b/arch/x86/kernel/sev-es-shared.c @@ -24,7 +24,7 @@ static bool __init sev_es_check_cpu_features(void) return true; } -static void sev_es_terminate(unsigned int reason) +static void __noreturn sev_es_terminate(unsigned int reason) { u64 val = GHCB_SEV_TERMINATE; @@ -186,7 +186,6 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) * make it accessible to the hypervisor. * * In particular, check for: - * - Hypervisor CPUID bit * - Availability of CPUID leaf 0x8000001f * - SEV CPUID bit. * @@ -194,10 +193,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) * can't be checked here. */ - if ((fn == 1 && !(regs->cx & BIT(31)))) - /* Hypervisor bit */ - goto fail; - else if (fn == 0x80000000 && (regs->ax < 0x8000001f)) + if (fn == 0x80000000 && (regs->ax < 0x8000001f)) /* SEV leaf check */ goto fail; else if ((fn == 0x8000001f && !(regs->ax & BIT(1)))) @@ -210,12 +206,8 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) return; fail: - sev_es_wr_ghcb_msr(GHCB_SEV_TERMINATE); - VMGEXIT(); - - /* Shouldn't get here - if we do halt the machine */ - while (true) - asm volatile("hlt\n"); + /* Terminate the guest */ + sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST); } static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt, diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c index 04a780abb512d01eb246067eff2b27f6e8501c51..26f5479a97a8bbab1d55eedcc689c8186aed57cc 100644 --- a/arch/x86/kernel/sev-es.c +++ b/arch/x86/kernel/sev-es.c @@ -137,29 +137,41 @@ static __always_inline bool on_vc_stack(struct pt_regs *regs) } /* - * This function handles the case when an NMI is raised in the #VC exception - * handler entry code. In this case, the IST entry for #VC must be adjusted, so - * that any subsequent #VC exception will not overwrite the stack contents of the - * interrupted #VC handler. + * This function handles the case when an NMI is raised in the #VC + * exception handler entry code, before the #VC handler has switched off + * its IST stack. In this case, the IST entry for #VC must be adjusted, + * so that any nested #VC exception will not overwrite the stack + * contents of the interrupted #VC handler. * * The IST entry is adjusted unconditionally so that it can be also be - * unconditionally adjusted back in sev_es_ist_exit(). Otherwise a nested - * sev_es_ist_exit() call may adjust back the IST entry too early. + * unconditionally adjusted back in __sev_es_ist_exit(). Otherwise a + * nested sev_es_ist_exit() call may adjust back the IST entry too + * early. + * + * The __sev_es_ist_enter() and __sev_es_ist_exit() functions always run + * on the NMI IST stack, as they are only called from NMI handling code + * right now. */ void noinstr __sev_es_ist_enter(struct pt_regs *regs) { unsigned long old_ist, new_ist; /* Read old IST entry */ - old_ist = __this_cpu_read(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC]); + new_ist = old_ist = __this_cpu_read(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC]); - /* Make room on the IST stack */ + /* + * If NMI happened while on the #VC IST stack, set the new IST + * value below regs->sp, so that the interrupted stack frame is + * not overwritten by subsequent #VC exceptions. + */ if (on_vc_stack(regs)) - new_ist = ALIGN_DOWN(regs->sp, 8) - sizeof(old_ist); - else - new_ist = old_ist - sizeof(old_ist); + new_ist = regs->sp; - /* Store old IST entry */ + /* + * Reserve additional 8 bytes and store old IST value so this + * adjustment can be unrolled in __sev_es_ist_exit(). + */ + new_ist -= sizeof(old_ist); *(unsigned long *)new_ist = old_ist; /* Set new IST entry */ @@ -277,7 +289,7 @@ static enum es_result vc_decode_insn(struct es_em_ctxt *ctxt) return ES_EXCEPTION; } - insn_init(&ctxt->insn, buffer, MAX_INSN_SIZE - res, 1); + insn_init(&ctxt->insn, buffer, MAX_INSN_SIZE, 1); insn_get_length(&ctxt->insn); } diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index f306e85a08a641883dc98fb6156df4857480205e..a06cb107c0e88e8621cd514d3dd1546979f4bfb7 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -492,7 +492,7 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, * SS descriptor, but we do need SS to be valid. It's possible * that the old SS is entirely bogus -- this can happen if the * signal we're trying to deliver is #GP or #SS caused by a bad - * SS value. We also have a compatbility issue here: DOSEMU + * SS value. We also have a compatibility issue here: DOSEMU * relies on the contents of the SS register indicating the * SS value at the time of the signal, even though that code in * DOSEMU predates sigreturn's ability to restore SS. (DOSEMU diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index eff4ce3b10da7185cb770e35b6006516e72830db..06db901fabe8e0e9d61403b754080fe2f9b46ac3 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -67,7 +67,7 @@ * 5AP. symmetric IO mode (normal Linux operation) not affected. * 'noapic' mode has vector 0xf filled out properly. * 6AP. 'noapic' mode might be affected - fixed in later steppings - * 7AP. We do not assume writes to the LVT deassering IRQs + * 7AP. We do not assume writes to the LVT deasserting IRQs * 8AP. We do not enable low power mode (deep sleep) during MP bootup * 9AP. We do not use mixed mode * @@ -204,7 +204,7 @@ static void native_stop_other_cpus(int wait) } /* * Don't wait longer than 10 ms if the caller didn't - * reqeust it. If wait is true, the machine hangs here if + * request it. If wait is true, the machine hangs here if * one or more CPUs do not reach shutdown state. */ timeout = USEC_PER_MSEC * 10; diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 16703c35a944f1ffdff2ca95d68a073cdfc4d782..1e2050c4f94a6eb7213308bb79f318d647be8c1d 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1407,7 +1407,7 @@ void __init calculate_max_logical_packages(void) int ncpus; /* - * Today neither Intel nor AMD support heterogenous systems so + * Today neither Intel nor AMD support heterogeneous systems so * extrapolate the boot cpu's data to all packages. */ ncpus = cpu_data(0).booted_cores * topology_max_smt_threads(); diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index 8627fda8d9930dd553d8fef0576f01b581109fdf..15b058eefc4e7f9758982ed39c30822680e59d7d 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -29,12 +29,6 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, } } -/* - * This function returns an error if it detects any unreliable features of the - * stack. Otherwise it guarantees that the stack trace is reliable. - * - * If the task is not 'current', the caller *must* ensure the task is inactive. - */ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, void *cookie, struct task_struct *task) { diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c index 653b7f617b61bfce19ccf0e0254462c00e18c5e5..8a56a6d80098b26a87ac3fc3f13d8d986a6db1d5 100644 --- a/arch/x86/kernel/sysfb_efi.c +++ b/arch/x86/kernel/sysfb_efi.c @@ -10,7 +10,7 @@ * EFI Quirks * Several EFI systems do not correctly advertise their boot framebuffers. * Hence, we use this static table of known broken machines and fix up the - * information so framebuffer drivers can load corectly. + * information so framebuffer drivers can load correctly. */ #include <linux/dmi.h> diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index 4c09ba1102047c66db21e340c6a3f4bcf528c7b1..f9af561c3cd4fef9ff3b3bbeb53cb8ba03a1524b 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -49,6 +49,30 @@ bool tboot_enabled(void) return tboot != NULL; } +/* noinline to prevent gcc from warning about dereferencing constant fixaddr */ +static noinline __init bool check_tboot_version(void) +{ + if (memcmp(&tboot_uuid, &tboot->uuid, sizeof(tboot->uuid))) { + pr_warn("tboot at 0x%llx is invalid\n", boot_params.tboot_addr); + return false; + } + + if (tboot->version < 5) { + pr_warn("tboot version is invalid: %u\n", tboot->version); + return false; + } + + pr_info("found shared page at phys addr 0x%llx:\n", + boot_params.tboot_addr); + pr_debug("version: %d\n", tboot->version); + pr_debug("log_addr: 0x%08x\n", tboot->log_addr); + pr_debug("shutdown_entry: 0x%x\n", tboot->shutdown_entry); + pr_debug("tboot_base: 0x%08x\n", tboot->tboot_base); + pr_debug("tboot_size: 0x%x\n", tboot->tboot_size); + + return true; +} + void __init tboot_probe(void) { /* Look for valid page-aligned address for shared page. */ @@ -66,25 +90,9 @@ void __init tboot_probe(void) /* Map and check for tboot UUID. */ set_fixmap(FIX_TBOOT_BASE, boot_params.tboot_addr); - tboot = (struct tboot *)fix_to_virt(FIX_TBOOT_BASE); - if (memcmp(&tboot_uuid, &tboot->uuid, sizeof(tboot->uuid))) { - pr_warn("tboot at 0x%llx is invalid\n", boot_params.tboot_addr); + tboot = (void *)fix_to_virt(FIX_TBOOT_BASE); + if (!check_tboot_version()) tboot = NULL; - return; - } - if (tboot->version < 5) { - pr_warn("tboot version is invalid: %u\n", tboot->version); - tboot = NULL; - return; - } - - pr_info("found shared page at phys addr 0x%llx:\n", - boot_params.tboot_addr); - pr_debug("version: %d\n", tboot->version); - pr_debug("log_addr: 0x%08x\n", tboot->log_addr); - pr_debug("shutdown_entry: 0x%x\n", tboot->shutdown_entry); - pr_debug("tboot_base: 0x%08x\n", tboot->tboot_base); - pr_debug("tboot_size: 0x%x\n", tboot->tboot_size); } static pgd_t *tboot_pg_dir; diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index f5477eab5692b3e308db251fd71fb0de1ef5c34d..bd83748e2bde3a7f1b95b94a90db5c0577f99b66 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -113,7 +113,7 @@ int arch_register_cpu(int num) * Two known BSP/CPU0 dependencies: Resume from suspend/hibernate * depends on BSP. PIC interrupts depend on BSP. * - * If the BSP depencies are under control, one can tell kernel to + * If the BSP dependencies are under control, one can tell kernel to * enable BSP hotplug. This basically adds a control file and * one can attempt to offline BSP. */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 651e3e5089593a273894fb0340ee97c2b9251aa9..f577d07fbd43a0bac91b0ec7fc8f1d7299fbf22c 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -395,7 +395,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault) /* * Adjust our frame so that we return straight to the #GP * vector with the expected RSP value. This is safe because - * we won't enable interupts or schedule before we invoke + * we won't enable interrupts or schedule before we invoke * general_protection, so nothing will clobber the stack * frame we just set up. * @@ -978,6 +978,10 @@ static __always_inline void exc_debug_user(struct pt_regs *regs, goto out_irq; } + /* #DB for bus lock can only be triggered from userspace. */ + if (dr6 & DR_BUS_LOCK) + handle_bus_lock(regs); + /* Add the virtual_dr6 bits for signals. */ dr6 |= current->thread.virtual_dr6; if (dr6 & (DR_STEP | DR_TRAP_BITS) || icebp) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index f70dffc2771f53d5f2b924126150d244463c09ee..57ec01192180534964b60e11090313b749f250d8 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -14,6 +14,7 @@ #include <linux/percpu.h> #include <linux/timex.h> #include <linux/static_key.h> +#include <linux/static_call.h> #include <asm/hpet.h> #include <asm/timer.h> @@ -254,7 +255,7 @@ unsigned long long sched_clock(void) bool using_native_sched_clock(void) { - return pv_ops.time.sched_clock == native_sched_clock; + return static_call_query(pv_sched_clock) == native_sched_clock; } #else unsigned long long @@ -739,7 +740,7 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void) * 2) Reference counter. If available we use the HPET or the * PMTIMER as a reference to check the sanity of that value. * We use separate TSC readouts and check inside of the - * reference read for any possible disturbance. We dicard + * reference read for any possible disturbance. We discard * disturbed values here as well. We do that around the PIT * calibration delay loop as we have to wait for a certain * amount of time anyway. @@ -1079,7 +1080,7 @@ static void tsc_resume(struct clocksource *cs) * very small window right after one CPU updated cycle_last under * xtime/vsyscall_gtod lock and the other CPU reads a TSC value which * is smaller than the cycle_last reference value due to a TSC which - * is slighty behind. This delta is nowhere else observable, but in + * is slightly behind. This delta is nowhere else observable, but in * that case it results in a forward time jump in the range of hours * due to the unsigned delta calculation of the time keeping core * code, which is necessary to support wrapping clocksources like pm @@ -1264,7 +1265,7 @@ EXPORT_SYMBOL(convert_art_to_tsc); * corresponding clocksource * @cycles: System counter value * @cs: Clocksource corresponding to system counter value. Used - * by timekeeping code to verify comparibility of two cycle + * by timekeeping code to verify comparability of two cycle * values. */ diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index 3d3c761eb74a64a535f0d0c516d275e48a0a36b8..50a4515fe0ad15ec241c257735022287094a4514 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c @@ -472,7 +472,7 @@ retry: /* * Add the result to the previous adjustment value. * - * The adjustement value is slightly off by the overhead of the + * The adjustment value is slightly off by the overhead of the * sync mechanism (observed values are ~200 TSC cycles), but this * really depends on CPU, node distance and frequency. So * compensating for this is hard to get right. Experiments show diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c index f6225bf22c02f60b66fb25abe9b068030a1f3c70..fac1daae7994a6d751f89d041d5c643231ce8f2c 100644 --- a/arch/x86/kernel/umip.c +++ b/arch/x86/kernel/umip.c @@ -272,7 +272,7 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst, * by whether the operand is a register or a memory location. * If operand is a register, return as many bytes as the operand * size. If operand is memory, return only the two least - * siginificant bytes. + * significant bytes. */ if (X86_MODRM_MOD(insn->modrm.value) == 3) *data_size = insn->opnd_bytes; diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index a788d5120d4d94abe25f9199709ae99fd0929e49..f6b93a35ce1455c7252d2fa491167ba187d32e7b 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -84,6 +84,18 @@ config KVM_INTEL To compile this as a module, choose M here: the module will be called kvm-intel. +config X86_SGX_KVM + bool "Software Guard eXtensions (SGX) Virtualization" + depends on X86_SGX && KVM_INTEL + help + + Enables KVM guests to create SGX enclaves. + + This includes support to expose "raw" unreclaimable enclave memory to + guests via a device node, e.g. /dev/sgx_vepc. + + If unsure, say N. + config KVM_AMD tristate "KVM for AMD processors support" depends on KVM diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 6bd2f8b830e49ff115ea9058bb6a2c51ebcdfaf5..c02466a1410b7588e9d261245433f0b4ce1edb64 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1033,7 +1033,7 @@ EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry); * - Centaur: 0xc0000000 - 0xcfffffff * * The Hypervisor class is further subdivided into sub-classes that each act as - * their own indepdent class associated with a 0x100 byte range. E.g. if Qemu + * their own independent class associated with a 0x100 byte range. E.g. if Qemu * is advertising support for both HyperV and KVM, the resulting Hypervisor * CPUID sub-classes are: * diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index f7970ba6219fc52887a4b6b3757ef6de8686ce8d..cdd2a2b6550e71b488fe6a1e3ef5f7ad142daf40 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -3222,7 +3222,7 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, } /* - * Now load segment descriptors. If fault happenes at this stage + * Now load segment descriptors. If fault happens at this stage * it is handled in a context of new task */ ret = __load_segment_descriptor(ctxt, tss->ldt_selector, VCPU_SREG_LDTR, diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 8a4de3f12820d5f6afe34c2eb62753525896aa71..d5b72a08e566ca9faeff77d672d228669b47b452 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -269,7 +269,7 @@ int kvm_set_routing_entry(struct kvm *kvm, const struct kvm_irq_routing_entry *ue) { /* We can't check irqchip_in_kernel() here as some callers are - * currently inititalizing the irqchip. Other callers should therefore + * currently initializing the irqchip. Other callers should therefore * check kvm_arch_can_set_irq_routing() before calling this function. */ switch (ue->type) { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 951dae4e71751cddbef1bb733c2dc82d7eb31cb0..62b1729277ef582dd596cc498516d83224b2e2b7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4961,7 +4961,7 @@ static void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, /* * No need to care whether allocation memory is successful - * or not since pte prefetch is skiped if it does not have + * or not since pte prefetch is skipped if it does not have * enough objects in the cache. */ mmu_topup_memory_caches(vcpu, true); diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index 1f6f98c76bdf10a064dbe41cbe5638af49554d93..360983865398925cec503e4a4c2648bf6da57d2c 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -59,7 +59,7 @@ struct kvm_mmu_page { #ifdef CONFIG_X86_64 bool tdp_mmu_page; - /* Used for freeing the page asyncronously if it is a TDP MMU page. */ + /* Used for freeing the page asynchronously if it is a TDP MMU page. */ struct rcu_head rcu_head; #endif }; diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 018d82e73e3117d14b05adaa104f46569402b222..34207b8748861e188053c203945cb97b440166a1 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -404,7 +404,7 @@ static void __handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, * If this warning were to trigger it would indicate that there was a * missing MMU notifier or a race with some notifier handler. * A present, leaf SPTE should never be directly replaced with another - * present leaf SPTE pointing to a differnt PFN. A notifier handler + * present leaf SPTE pointing to a different PFN. A notifier handler * should be zapping the SPTE before the main MM's page table is * changed, or the SPTE should be zeroed, and the TLBs flushed by the * thread before replacement. @@ -418,7 +418,7 @@ static void __handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, /* * Crash the host to prevent error propagation and guest data - * courruption. + * corruption. */ BUG(); } @@ -529,7 +529,7 @@ static inline bool tdp_mmu_zap_spte_atomic(struct kvm *kvm, /* * No other thread can overwrite the removed SPTE as they * must either wait on the MMU lock or use - * tdp_mmu_set_spte_atomic which will not overrite the + * tdp_mmu_set_spte_atomic which will not overwrite the * special removed SPTE value. No bookkeeping is needed * here since the SPTE is going from non-present * to non-present. diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 7b30bc967af38c2da2781cba6dbb0d1fb906ff15..67e753edfa225bafdd2a728e5c2d9939b0bc2db6 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -103,7 +103,7 @@ static inline bool kvm_valid_perf_global_ctrl(struct kvm_pmu *pmu, /* returns general purpose PMC with the specified MSR. Note that it can be * used for both PERFCTRn and EVNTSELn; that is why it accepts base as a - * paramenter to tell them apart. + * parameter to tell them apart. */ static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr, u32 base) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 78bdcfac4e400ac31647329e1d5b609278be4b02..3e55674098be08c7f983f2d1810d2908961da1b2 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -727,7 +727,7 @@ static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) struct amd_svm_iommu_ir *ir; /** - * In some cases, the existing irte is updaed and re-set, + * In some cases, the existing irte is updated and re-set, * so we need to check here if it's already been * added * to the ir_list. */ @@ -838,7 +838,7 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, * Here, we setup with legacy mode in the following cases: * 1. When cannot target interrupt to a specific vcpu. * 2. Unsetting posted interrupt. - * 3. APIC virtialization is disabled for the vcpu. + * 3. APIC virtualization is disabled for the vcpu. * 4. IRQ has incompatible delivery mode (SMI, INIT, etc) */ if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set && diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 874ea309279f5f9e02698854099c54f0aab95f56..2b27a94524033d7dd4606c37668f60f48233d1a2 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2082,7 +2082,7 @@ void sev_es_prepare_guest_switch(struct vcpu_svm *svm, unsigned int cpu) hostsa = (struct vmcb_save_area *)(page_address(sd->save_area) + 0x400); hostsa->xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); - /* PKRU is restored on VMEXIT, save the curent host value */ + /* PKRU is restored on VMEXIT, save the current host value */ hostsa->pkru = read_pkru(); /* MSR_IA32_XSS is restored on VMEXIT, save the currnet host value */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 58a45bb139f88ab78c4a01e370693379968f0984..6dad89248312192421e7542e5f6f70ae54125217 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4400,7 +4400,7 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int i * * This happens because CPU microcode reading instruction bytes * uses a special opcode which attempts to read data using CPL=0 - * priviledges. The microcode reads CS:RIP and if it hits a SMAP + * privileges. The microcode reads CS:RIP and if it hits a SMAP * fault, it gives up and returns no instruction bytes. * * Detection: diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index bcca0b80e0d040be4ce9a4f9a2ee05d77e0c8257..1e069aac741004f1fbea664f813eaad430a997c3 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3537,7 +3537,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) * snapshot restore (migration). * * In this flow, it is assumed that vmcs12 cache was - * trasferred as part of captured nVMX state and should + * transferred as part of captured nVMX state and should * therefore not be read from guest memory (which may not * exist on destination host yet). */ diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c index 4831bc44ce66fc0e4773f74f4a213a7e48b8be01..459748680daf2b93e40a67c56e7306a85a65121b 100644 --- a/arch/x86/kvm/vmx/posted_intr.c +++ b/arch/x86/kvm/vmx/posted_intr.c @@ -10,7 +10,7 @@ #include "vmx.h" /* - * We maintian a per-CPU linked-list of vCPU, so in wakeup_handler() we + * We maintain a per-CPU linked-list of vCPU, so in wakeup_handler() we * can find which vCPU should be waken up. */ static DEFINE_PER_CPU(struct list_head, blocked_vcpu_on_cpu); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 29b40e092d13db4dfc8664f001b9ce422f90b3e3..bcbf0d2139e9a527e04901ee17e351aad4cf9af0 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1529,7 +1529,7 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data) /* * MTCFreq, CycThresh and PSBFreq encodings check, any MSR write that - * utilize encodings marked reserved will casue a #GP fault. + * utilize encodings marked reserved will cause a #GP fault. */ value = intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_mtc_periods); if (intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_mtc) && @@ -2761,7 +2761,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); /* - * Update real mode segment cache. It may be not up-to-date if sement + * Update real mode segment cache. It may be not up-to-date if segment * register was written while vcpu was in a guest mode. */ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES); @@ -7252,7 +7252,7 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) if (intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_topa_output)) vmx->pt_desc.ctl_bitmask &= ~RTIT_CTL_TOPA; - /* If CPUID.(EAX=14H,ECX=0):ECX[3]=1 FabircEn can be set */ + /* If CPUID.(EAX=14H,ECX=0):ECX[3]=1 FabricEn can be set */ if (intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_output_subsys)) vmx->pt_desc.ctl_bitmask &= ~RTIT_CTL_FABRIC_EN; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ee0dc58ac3a51cb6b8a273b5e28b26395f8f85d8..efc7a82ab14015d64fc65c2f4ffdb6588ddd6024 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -156,9 +156,9 @@ module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR); /* * lapic timer advance (tscdeadline mode only) in nanoseconds. '-1' enables - * adaptive tuning starting from default advancment of 1000ns. '0' disables + * adaptive tuning starting from default advancement of 1000ns. '0' disables * advancement entirely. Any other value is used as-is and disables adaptive - * tuning, i.e. allows priveleged userspace to set an exact advancement time. + * tuning, i.e. allows privileged userspace to set an exact advancement time. */ static int __read_mostly lapic_timer_advance_ns = -1; module_param(lapic_timer_advance_ns, int, S_IRUGO | S_IWUSR); @@ -1287,7 +1287,7 @@ static const u32 emulated_msrs_all[] = { MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK, MSR_IA32_TSC_ADJUST, - MSR_IA32_TSCDEADLINE, + MSR_IA32_TSC_DEADLINE, MSR_IA32_ARCH_CAPABILITIES, MSR_IA32_PERF_CAPABILITIES, MSR_IA32_MISC_ENABLE, @@ -1372,7 +1372,7 @@ static u64 kvm_get_arch_capabilities(void) /* * If nx_huge_pages is enabled, KVM's shadow paging will ensure that * the nested hypervisor runs with NX huge pages. If it is not, - * L1 is anyway vulnerable to ITLB_MULTIHIT explots from other + * L1 is anyway vulnerable to ITLB_MULTIHIT exploits from other * L1 guests, so it need not worry about its own (L2) guests. */ data |= ARCH_CAP_PSCHANGE_MC_NO; @@ -1849,7 +1849,7 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) ret = EXIT_FASTPATH_EXIT_HANDLED; } break; - case MSR_IA32_TSCDEADLINE: + case MSR_IA32_TSC_DEADLINE: data = kvm_read_edx_eax(vcpu); if (!handle_fastpath_set_tscdeadline(vcpu, data)) { kvm_skip_emulated_instruction(vcpu); @@ -3087,7 +3087,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return kvm_set_apic_base(vcpu, msr_info); case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: return kvm_x2apic_msr_write(vcpu, msr, data); - case MSR_IA32_TSCDEADLINE: + case MSR_IA32_TSC_DEADLINE: kvm_set_lapic_tscdeadline_msr(vcpu, data); break; case MSR_IA32_TSC_ADJUST: @@ -3449,7 +3449,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: return kvm_x2apic_msr_read(vcpu, msr_info->index, &msr_info->data); - case MSR_IA32_TSCDEADLINE: + case MSR_IA32_TSC_DEADLINE: msr_info->data = kvm_get_lapic_tscdeadline_msr(vcpu); break; case MSR_IA32_TSC_ADJUST: diff --git a/arch/x86/lib/atomic64_386_32.S b/arch/x86/lib/atomic64_386_32.S index 3b6544111ac92dc310f23e4919b699e541ea3c56..16bc9130e7a5e81192ed7a0ee9999a3276c0d8e7 100644 --- a/arch/x86/lib/atomic64_386_32.S +++ b/arch/x86/lib/atomic64_386_32.S @@ -6,7 +6,7 @@ */ #include <linux/linkage.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> /* if you want SMP support, implement these with real spinlocks */ .macro LOCK reg diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S index 1c5c81c16b0668f17ae3cc11b05f95f52a153637..ce6935690766f41a6ac4262c966de4c9fcbcdcc1 100644 --- a/arch/x86/lib/atomic64_cx8_32.S +++ b/arch/x86/lib/atomic64_cx8_32.S @@ -6,7 +6,7 @@ */ #include <linux/linkage.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> .macro read64 reg movl %ebx, %eax diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S index 2402d4c489d298cf05e368ef4cb40d457ed5e574..db4b4f9197c7d99d6b945b6586da9274fdd6ce2a 100644 --- a/arch/x86/lib/copy_page_64.S +++ b/arch/x86/lib/copy_page_64.S @@ -3,7 +3,7 @@ #include <linux/linkage.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/export.h> /* diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 77b9b2a3b5c84dbf8418d7816e84412297fbc12b..57b79c577496d7700c8df7fe5c3a5c1b24370674 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -11,7 +11,7 @@ #include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/asm.h> #include <asm/smap.h> #include <asm/export.h> diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c index bb0b3fe1e0a0251c716ec2568576d8e0ceb13900..2bf07e18e38cb3ffef9a0d0c476f000c46501ff5 100644 --- a/arch/x86/lib/insn-eval.c +++ b/arch/x86/lib/insn-eval.c @@ -232,7 +232,7 @@ static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) * resolve_seg_reg() - obtain segment register index * @insn: Instruction with operands * @regs: Register values as seen when entering kernel mode - * @regoff: Operand offset, in pt_regs, used to deterimine segment register + * @regoff: Operand offset, in pt_regs, used to determine segment register * * Determine the segment register associated with the operands and, if * applicable, prefixes and the instruction pointed by @insn. @@ -517,7 +517,7 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, * @insn: Instruction containing ModRM byte * @regs: Register values as seen when entering kernel mode * @offs1: Offset of the first operand register - * @offs2: Offset of the second opeand register, if applicable + * @offs2: Offset of the second operand register, if applicable * * Obtain the offset, in pt_regs, of the registers indicated by the ModRM byte * in @insn. This function is to be used with 16-bit address encodings. The @@ -576,7 +576,7 @@ static int get_reg_offset_16(struct insn *insn, struct pt_regs *regs, * If ModRM.mod is 0 and ModRM.rm is 110b, then we use displacement- * only addressing. This means that no registers are involved in * computing the effective address. Thus, ensure that the first - * register offset is invalild. The second register offset is already + * register offset is invalid. The second register offset is already * invalid under the aforementioned conditions. */ if ((X86_MODRM_MOD(insn->modrm.value) == 0) && diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index 1e299ac73c8698622c7e631a4571b5b88e8b32f7..1cc9da6e29c7926be24bea853952f115c4fa5a3f 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -4,7 +4,7 @@ #include <linux/linkage.h> #include <asm/errno.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/export.h> .pushsection .noinstr.text, "ax" diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S index 41902fe8b85982e10409c1a68e86cf01ee1519fd..64801010d312d92820b3c3e86738ae99b5be9ec3 100644 --- a/arch/x86/lib/memmove_64.S +++ b/arch/x86/lib/memmove_64.S @@ -8,7 +8,7 @@ */ #include <linux/linkage.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/export.h> #undef memmove diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 0bfd26e4ca9e938af774c5b1e4fea753d47d156c..9827ae267f96e00660870f775fb8d2d297c20445 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -3,7 +3,7 @@ #include <linux/linkage.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/export.h> /* diff --git a/arch/x86/lib/mmx_32.c b/arch/x86/lib/mmx_32.c index 419365c48b2ada2b40094552affd0e4cd4ba433c..cc5f4ea943d37ff4b87bde9a5baa7888db827c42 100644 --- a/arch/x86/lib/mmx_32.c +++ b/arch/x86/lib/mmx_32.c @@ -14,7 +14,7 @@ * tested so far for any MMX solution figured. * * 22/09/2000 - Arjan van de Ven - * Improved for non-egineering-sample Athlons + * Improved for non-engineering-sample Athlons * */ #include <linux/hardirq.h> diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c index 75a0915b0d01d769a98484463be321c8585e5e20..40bbe56bde3256eadea3d68a01b6af713b943552 100644 --- a/arch/x86/lib/msr-smp.c +++ b/arch/x86/lib/msr-smp.c @@ -252,7 +252,7 @@ static void __wrmsr_safe_regs_on_cpu(void *info) rv->err = wrmsr_safe_regs(rv->regs); } -int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) +int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]) { int err; struct msr_regs_info rv; @@ -265,7 +265,7 @@ int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) } EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu); -int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) +int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]) { int err; struct msr_regs_info rv; diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index 3bd905e10ee21bd532338740c5294ea75a8284ba..b09cd2ad426ccde84865b1d974f3dd35d5109c54 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c @@ -36,7 +36,7 @@ EXPORT_SYMBOL(msrs_free); * argument @m. * */ -int msr_read(u32 msr, struct msr *m) +static int msr_read(u32 msr, struct msr *m) { int err; u64 val; @@ -54,7 +54,7 @@ int msr_read(u32 msr, struct msr *m) * @msr: MSR to write * @m: value to write */ -int msr_write(u32 msr, struct msr *m) +static int msr_write(u32 msr, struct msr *m) { return wrmsrl_safe(msr, m->q); } diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index f6fb1d218dccf7fe84de55591c6ed22f5ddc528f..6bb74b5c238c61db1c23b8ec33152561bf1deaba 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -4,7 +4,7 @@ #include <linux/linkage.h> #include <asm/dwarf2.h> #include <asm/cpufeatures.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/export.h> #include <asm/nospec-branch.h> #include <asm/unwind_hints.h> diff --git a/arch/x86/math-emu/fpu_trig.c b/arch/x86/math-emu/fpu_trig.c index 4a9887851ad8ab05e11fb427df846721bd66ff43..990d847ae902c6e032462e55914dbc680a3959bd 100644 --- a/arch/x86/math-emu/fpu_trig.c +++ b/arch/x86/math-emu/fpu_trig.c @@ -547,7 +547,7 @@ static void frndint_(FPU_REG *st0_ptr, u_char st0_tag) single_arg_error(st0_ptr, st0_tag); } -static int fsin(FPU_REG *st0_ptr, u_char tag) +static int f_sin(FPU_REG *st0_ptr, u_char tag) { u_char arg_sign = getsign(st0_ptr); @@ -608,6 +608,11 @@ static int fsin(FPU_REG *st0_ptr, u_char tag) } } +static void fsin(FPU_REG *st0_ptr, u_char tag) +{ + f_sin(st0_ptr, tag); +} + static int f_cos(FPU_REG *st0_ptr, u_char tag) { u_char st0_sign; @@ -724,7 +729,7 @@ static void fsincos(FPU_REG *st0_ptr, u_char st0_tag) } reg_copy(st0_ptr, &arg); - if (!fsin(st0_ptr, st0_tag)) { + if (!f_sin(st0_ptr, st0_tag)) { push(); FPU_copy_to_reg0(&arg, st0_tag); f_cos(&st(0), st0_tag); @@ -1635,7 +1640,7 @@ void FPU_triga(void) } static FUNC_ST0 const trig_table_b[] = { - fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0) fsin, fcos + fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos }; void FPU_trigb(void) diff --git a/arch/x86/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c index fe6246ff98870580ce11a2b2178b68b731c4036c..7ca6417c0c8d1727f78d4bb6df8f5d08f0197788 100644 --- a/arch/x86/math-emu/reg_ld_str.c +++ b/arch/x86/math-emu/reg_ld_str.c @@ -964,7 +964,7 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d) /* The return value (in eax) is zero if the result is exact, if bits are changed due to rounding, truncation, etc, then a non-zero value is returned */ -/* Overflow is signalled by a non-zero return value (in eax). +/* Overflow is signaled by a non-zero return value (in eax). In the case of overflow, the returned significand always has the largest possible value */ int FPU_round_to_int(FPU_REG *r, u_char tag) diff --git a/arch/x86/math-emu/reg_round.S b/arch/x86/math-emu/reg_round.S index 11a1f798451bd153822dbcc7babd41ffb6f174cd..4a9fc3cc5a4d4266adfd2ccc5911c4fa8a066476 100644 --- a/arch/x86/math-emu/reg_round.S +++ b/arch/x86/math-emu/reg_round.S @@ -575,7 +575,7 @@ Normalise_result: #ifdef PECULIAR_486 /* * This implements a special feature of 80486 behaviour. - * Underflow will be signalled even if the number is + * Underflow will be signaled even if the number is * not a denormal after rounding. * This difference occurs only for masked underflow, and not * in the unmasked case. diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index a73347e2cdfc569e7ef2dbd6a3b12ea1af5f6702..1c548ad0075204e3d129913be2767b64d1edb2fc 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1497,7 +1497,7 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) * userspace task is trying to access some valid (from guest's point of * view) memory which is not currently mapped by the host (e.g. the * memory is swapped out). Note, the corresponding "page ready" event - * which is injected when the memory becomes available, is delived via + * which is injected when the memory becomes available, is delivered via * an interrupt mechanism and not a #PF exception * (see arch/x86/kernel/kvm.c: sysvec_kvm_asyncpf_interrupt()). * @@ -1523,7 +1523,7 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) * * In case the fault hit a RCU idle region the conditional entry * code reenabled RCU to avoid subsequent wreckage which helps - * debugability. + * debuggability. */ state = irqentry_enter(regs); diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index dd694fb9391696e8cecfce2c5a8185786af423ba..fbf41dd142ca11f02b4fe2f524942f9dd08bcee0 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -29,7 +29,7 @@ /* * We need to define the tracepoints somewhere, and tlb.c - * is only compied when SMP=y. + * is only compiled when SMP=y. */ #define CREATE_TRACE_POINTS #include <trace/events/tlb.h> @@ -756,7 +756,7 @@ void __init init_mem_mapping(void) #ifdef CONFIG_X86_64 if (max_pfn > max_low_pfn) { - /* can we preseve max_low_pfn ?*/ + /* can we preserve max_low_pfn ?*/ max_low_pfn = max_pfn; } #else @@ -939,7 +939,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end) { /* * end could be not aligned, and We can not align that, - * decompresser could be confused by aligned initrd_end + * decompressor could be confused by aligned initrd_end * We already reserve the end partial page before in * - i386_start_kernel() * - x86_64_start_kernel() diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index b5a3fa4033d38bf00fd4766683459892c9554ec8..55247451ba85bdc4b01ac6fd96395d0203ce8462 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -172,7 +172,7 @@ static void sync_global_pgds_l4(unsigned long start, unsigned long end) /* * With folded p4d, pgd_none() is always false, we need to - * handle synchonization on p4d level. + * handle synchronization on p4d level. */ MAYBE_BUILD_BUG_ON(pgd_none(*pgd_ref)); p4d_ref = p4d_offset(pgd_ref, addr); @@ -986,7 +986,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end, if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) { /* * Do not free direct mapping pages since they were - * freed when offlining, or simplely not in use. + * freed when offlining, or simply not in use. */ if (!direct) free_pagetable(pte_page(*pte), 0); @@ -1004,7 +1004,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end, * * If we are not removing the whole page, it means * other page structs in this page are being used and - * we canot remove them. So fill the unused page_structs + * we cannot remove them. So fill the unused page_structs * with 0xFD, and remove the page when it is wholly * filled with 0xFD. */ diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index 6e6b39710e5fa561d1aec5c7005b79b0a1290da8..557f0fe25dff47641f03a86e5166a03f19627901 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -96,7 +96,7 @@ void __init kernel_randomize_memory(void) memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) + CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING; - /* Adapt phyiscal memory region size based on available memory */ + /* Adapt physical memory region size based on available memory */ if (memory_tb < kaslr_regions[0].size_tb) kaslr_regions[0].size_tb = memory_tb; diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index be020a7bc41474d54fcd1619f81e244509cb2be5..d3efbc5b344982658393b4bca3c744d5977318ec 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* Support for MMIO probes. - * Benfit many code from kprobes + * Benefit many code from kprobes * (C) 2002 Louis Zhuang <louis.zhuang@intel.com>. * 2007 Alexander Eichner * 2008 Pekka Paalanen <pq@iki.fi> diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index ae78cef7998023e7d7520dab74e0153b543af8f4..f633f9e23b8fcc897b990a3c96aeccee34f0c10d 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/bitops.h> #include <linux/dma-mapping.h> +#include <linux/virtio_config.h> #include <asm/tlbflush.h> #include <asm/fixmap.h> @@ -484,3 +485,8 @@ void __init mem_encrypt_init(void) print_mem_encrypt_feature_info(); } +int arch_has_restricted_virtio_memory_access(void) +{ + return sev_active(); +} +EXPORT_SYMBOL_GPL(arch_has_restricted_virtio_memory_access); diff --git a/arch/x86/mm/mem_encrypt_boot.S b/arch/x86/mm/mem_encrypt_boot.S index 7a84fc8bc5c36f476ba0561eed47e7cb08014ef9..17d292b7072f1e6cce6d2f951f566f2727820d82 100644 --- a/arch/x86/mm/mem_encrypt_boot.S +++ b/arch/x86/mm/mem_encrypt_boot.S @@ -27,7 +27,7 @@ SYM_FUNC_START(sme_encrypt_execute) * - stack page (PAGE_SIZE) * - encryption routine page (PAGE_SIZE) * - intermediate copy buffer (PMD_PAGE_SIZE) - * R8 - physcial address of the pagetables to use for encryption + * R8 - physical address of the pagetables to use for encryption */ push %rbp diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c index 6c5eb6f3f14f40f9002e2afde0ebbccee1237e75..a19374d2610132ee94d78ee5f675d7004236aaa0 100644 --- a/arch/x86/mm/mem_encrypt_identity.c +++ b/arch/x86/mm/mem_encrypt_identity.c @@ -503,14 +503,10 @@ void __init sme_enable(struct boot_params *bp) #define AMD_SME_BIT BIT(0) #define AMD_SEV_BIT BIT(1) - /* - * Set the feature mask (SME or SEV) based on whether we are - * running under a hypervisor. - */ - eax = 1; - ecx = 0; - native_cpuid(&eax, &ebx, &ecx, &edx); - feature_mask = (ecx & BIT(31)) ? AMD_SEV_BIT : AMD_SME_BIT; + + /* Check the SEV MSR whether SEV or SME is enabled */ + sev_status = __rdmsr(MSR_AMD64_SEV); + feature_mask = (sev_status & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT; /* * Check for the SME/SEV feature: @@ -530,19 +526,26 @@ void __init sme_enable(struct boot_params *bp) /* Check if memory encryption is enabled */ if (feature_mask == AMD_SME_BIT) { + /* + * No SME if Hypervisor bit is set. This check is here to + * prevent a guest from trying to enable SME. For running as a + * KVM guest the MSR_K8_SYSCFG will be sufficient, but there + * might be other hypervisors which emulate that MSR as non-zero + * or even pass it through to the guest. + * A malicious hypervisor can still trick a guest into this + * path, but there is no way to protect against that. + */ + eax = 1; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + if (ecx & BIT(31)) + return; + /* For SME, check the SYSCFG MSR */ msr = __rdmsr(MSR_K8_SYSCFG); if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT)) return; } else { - /* For SEV, check the SEV MSR */ - msr = __rdmsr(MSR_AMD64_SEV); - if (!(msr & MSR_AMD64_SEV_ENABLED)) - return; - - /* Save SEV_STATUS to avoid reading MSR again */ - sev_status = msr; - /* SEV state cannot be controlled by a command line option */ sme_me_mask = me_mask; sev_enabled = true; diff --git a/arch/x86/mm/pat/memtype.c b/arch/x86/mm/pat/memtype.c index ca311aaa67b889b6985eeefdad379569432b76c8..3112ca7786ed1462686fb8fbae96b621d3334195 100644 --- a/arch/x86/mm/pat/memtype.c +++ b/arch/x86/mm/pat/memtype.c @@ -695,7 +695,7 @@ int memtype_free(u64 start, u64 end) /** - * lookup_memtype - Looksup the memory type for a physical address + * lookup_memtype - Looks up the memory type for a physical address * @paddr: physical address of which memory type needs to be looked up * * Only to be called when PAT is enabled @@ -800,6 +800,7 @@ void memtype_free_io(resource_size_t start, resource_size_t end) memtype_free(start, end); } +#ifdef CONFIG_X86_PAT int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size) { enum page_cache_mode type = _PAGE_CACHE_MODE_WC; @@ -813,6 +814,7 @@ void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size) memtype_free_io(start, start + size); } EXPORT_SYMBOL(arch_io_free_memtype_wc); +#endif pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 16f878c26667933c5641069bb5b40c8f97221cc7..427980617557c173b533fe6f8b258f5dab29c014 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -680,7 +680,7 @@ pmd_t *lookup_pmd_address(unsigned long address) * end up in this kind of memory, for instance. * * This could be optimized, but it is only intended to be - * used at inititalization time, and keeping it + * used at initialization time, and keeping it * unoptimized should increase the testing coverage for * the more obscure platforms. */ diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c index 8873ed1438a978ec9b7e959556bbc1450161c5ba..a2332eef66e9f8532e9e52a56925a2a04f95a53d 100644 --- a/arch/x86/mm/pkeys.c +++ b/arch/x86/mm/pkeys.c @@ -128,7 +128,7 @@ u32 init_pkru_value = PKRU_AD_KEY( 1) | PKRU_AD_KEY( 2) | PKRU_AD_KEY( 3) | /* * Called from the FPU code when creating a fresh set of FPU * registers. This is called from a very specific context where - * we know the FPU regstiers are safe for use and we can use PKRU + * we know the FPU registers are safe for use and we can use PKRU * directly. */ void copy_init_pkru_to_fpregs(void) diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 1aab92930569af4542db384dabd46a56a6890662..5d5c7bb50ce9e2e9646f783d26adb1e33ea094aa 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -361,7 +361,7 @@ pti_clone_pgtable(unsigned long start, unsigned long end, * global, so set it as global in both copies. Note: * the X86_FEATURE_PGE check is not _required_ because * the CPU ignores _PAGE_GLOBAL when PGE is not - * supported. The check keeps consistentency with + * supported. The check keeps consistency with * code that only set this bit when supported. */ if (boot_cpu_has(X86_FEATURE_PGE)) @@ -440,10 +440,9 @@ static void __init pti_clone_user_shared(void) for_each_possible_cpu(cpu) { /* - * The SYSCALL64 entry code needs to be able to find the - * thread stack and needs one word of scratch space in which - * to spill a register. All of this lives in the TSS, in - * the sp1 and sp2 slots. + * The SYSCALL64 entry code needs one word of scratch space + * in which to spill a register. It lives in the sp2 slot + * of the CPU's TSS. * * This is done for all possible CPUs during boot to ensure * that it's propagated to all mms. @@ -512,7 +511,7 @@ static void pti_clone_entry_text(void) static inline bool pti_kernel_image_global_ok(void) { /* - * Systems with PCIDs get litlle benefit from global + * Systems with PCIDs get little benefit from global * kernel text and are not worth the downsides. */ if (cpu_feature_enabled(X86_FEATURE_PCID)) diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 569ac1d57f55a318b6f7a7daf5cfee55be15e4c4..98f269560d4060fb1f93ecfc968bccbe6a2574de 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -106,7 +106,7 @@ static inline u16 kern_pcid(u16 asid) #ifdef CONFIG_PAGE_TABLE_ISOLATION /* - * Make sure that the dynamic ASID space does not confict with the + * Make sure that the dynamic ASID space does not conflict with the * bit we are using to switch between user and kernel ASIDs. */ BUILD_BUG_ON(TLB_NR_DYN_ASIDS >= (1 << X86_CR3_PTI_PCID_USER_BIT)); @@ -736,7 +736,7 @@ static void flush_tlb_func_common(const struct flush_tlb_info *f, * 3, we'd be break the invariant: we'd update local_tlb_gen above * 1 without the full flush that's needed for tlb_gen 2. * - * 2. f->new_tlb_gen == mm_tlb_gen. This is purely an optimiation. + * 2. f->new_tlb_gen == mm_tlb_gen. This is purely an optimization. * Partial TLB flushes are not all that much cheaper than full TLB * flushes, so it seems unlikely that it would be a performance win * to do a partial flush if that won't bring our TLB fully up to @@ -876,7 +876,7 @@ static inline struct flush_tlb_info *get_flush_tlb_info(struct mm_struct *mm, static inline void put_flush_tlb_info(void) { #ifdef CONFIG_DEBUG_VM - /* Complete reentrency prevention checks */ + /* Complete reentrancy prevention checks */ barrier(); this_cpu_dec(flush_tlb_info_idx); #endif diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7f1b3a862e1418835b2285110c8ced2e1a74e9d1..220e72434f3c0d3b920f787a387f371c63ef2ac1 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1556,7 +1556,7 @@ emit_cond_jmp: /* Convert BPF opcode to x86 */ if (is_imm8(jmp_offset)) { if (jmp_padding) { /* To keep the jmp_offset valid, the extra bytes are - * padded before the jump insn, so we substract the + * padded before the jump insn, so we subtract the * 2 bytes of jmp_cond insn from INSN_SZ_DIFF. * * If the previous pass already emits an imm8 @@ -1631,7 +1631,7 @@ emit_jmp: if (jmp_padding) { /* To avoid breaking jmp_offset, the extra bytes * are padded before the actual jmp insn, so - * 2 bytes is substracted from INSN_SZ_DIFF. + * 2 bytes is subtracted from INSN_SZ_DIFF. * * If the previous pass already emits an imm8 * jmp, there is nothing to pad (0 byte). diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 0a0e168be1cbec0da9bad7cf2266d11118eae977..02dc64625e64d2e599504d264afb605d5cff5ae4 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -375,7 +375,7 @@ static const struct dmi_system_id msi_k8t_dmi_table[] = { * The BIOS only gives options "DISABLED" and "AUTO". This code sets * the corresponding register-value to enable the soundcard. * - * The soundcard is only enabled, if the mainborad is identified + * The soundcard is only enabled, if the mainboard is identified * via DMI-tables and the soundcard is detected to be off. */ static void pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev) diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 1b82d77019b17502edc7a5696543137cff23bc76..df7b5477fc4f2a0306a8103de7510e9affe4f4e3 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -195,7 +195,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) } /* - * Certain firmware versions are way too sentimential and still believe + * Certain firmware versions are way too sentimental and still believe * they are exclusive and unquestionable owners of the first physical page, * even though they explicitly mark it as EFI_CONVENTIONAL_MEMORY * (but then write-access it later during SetVirtualAddressMap()). @@ -457,7 +457,7 @@ void __init efi_dump_pagetable(void) * in a kernel thread and user context. Preemption needs to remain disabled * while the EFI-mm is borrowed. mmgrab()/mmdrop() is not used because the mm * can not change under us. - * It should be ensured that there are no concurent calls to this function. + * It should be ensured that there are no concurrent calls to this function. */ void efi_enter_mm(void) { diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 67d93a243c353c5aad59a65910f529928d10c5d8..7850111008a8b87e4c5a63ea984fcfec18af8184 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -441,7 +441,7 @@ void __init efi_free_boot_services(void) * 1.4.4 with SGX enabled booting Linux via Fedora 24's * grub2-efi on a hard disk. (And no, I don't know why * this happened, but Linux should still try to boot rather - * panicing early.) + * panicking early.) */ rm_size = real_mode_size_needed(); if (rm_size && (start + rm_size) < (1<<20) && size >= rm_size) { @@ -726,7 +726,7 @@ void efi_crash_gracefully_on_page_fault(unsigned long phys_addr) * Buggy efi_reset_system() is handled differently from other EFI * Runtime Services as it doesn't use efi_rts_wq. Although, * native_machine_emergency_restart() says that machine_real_restart() - * could fail, it's better not to compilcate this fault handler + * could fail, it's better not to complicate this fault handler * because this case occurs *very* rarely and hence could be improved * on a need by basis. */ diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c index 0286fe1b14b5cb57ca09f83ceb8a74d4f3b9f716..d3d456925b2a9388d245a940a4097a57360e59a6 100644 --- a/arch/x86/platform/intel-quark/imr.c +++ b/arch/x86/platform/intel-quark/imr.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * imr.c -- Intel Isolated Memory Region driver * * Copyright(c) 2013 Intel Corporation. @@ -551,7 +551,7 @@ static void __init imr_fixup_memmap(struct imr_device *idev) /* * Setup an unlocked IMR around the physical extent of the kernel - * from the beginning of the .text secton to the end of the + * from the beginning of the .text section to the end of the * .rodata section as one physically contiguous block. * * We don't round up @size since it is already PAGE_SIZE aligned. diff --git a/arch/x86/platform/intel-quark/imr_selftest.c b/arch/x86/platform/intel-quark/imr_selftest.c index 570e3062faac267df713fa8d8b2a3ba74461c579..761f3689f60a6b4d8002bd312686ce9b5e26b553 100644 --- a/arch/x86/platform/intel-quark/imr_selftest.c +++ b/arch/x86/platform/intel-quark/imr_selftest.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * imr_selftest.c -- Intel Isolated Memory Region self-test driver * * Copyright(c) 2013 Intel Corporation. diff --git a/arch/x86/platform/intel/iosf_mbi.c b/arch/x86/platform/intel/iosf_mbi.c index 526f70f27c1c3571e96e91b27d1dc869cb97ef73..fdd49d70b43738be371da7efb5476339ca315ef7 100644 --- a/arch/x86/platform/intel/iosf_mbi.c +++ b/arch/x86/platform/intel/iosf_mbi.c @@ -187,7 +187,7 @@ bool iosf_mbi_available(void) EXPORT_SYMBOL(iosf_mbi_available); /* - **************** P-Unit/kernel shared I2C bus arbritration **************** + **************** P-Unit/kernel shared I2C bus arbitration **************** * * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel) * share a single I2C bus to the PMIC. Below are helpers to arbitrate the @@ -493,7 +493,7 @@ static void iosf_sideband_debug_init(void) /* mcrx */ debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx); - /* mcr - initiates mailbox tranaction */ + /* mcr - initiates mailbox transaction */ debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops); } diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c index 85f4638764d69b87d310702cd3453518f1bc547e..994a229cb79fe190fe6836dfb0c4aa7bc51fbd45 100644 --- a/arch/x86/platform/olpc/olpc-xo15-sci.c +++ b/arch/x86/platform/olpc/olpc-xo15-sci.c @@ -27,7 +27,7 @@ static bool lid_wake_on_close; * wake-on-close. This is implemented as standard by the XO-1.5 DSDT. * * We provide here a sysfs attribute that will additionally enable - * wake-on-close behavior. This is useful (e.g.) when we oportunistically + * wake-on-close behavior. This is useful (e.g.) when we opportunistically * suspend with the display running; if the lid is then closed, we want to * wake up to turn the display off. * diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c index 26d1f66937892eb9e4d3d78af9b3c1fa3993291b..75e3319e8bee5b22986473c5690cc4da8bc56e9c 100644 --- a/arch/x86/platform/olpc/olpc_dt.c +++ b/arch/x86/platform/olpc/olpc_dt.c @@ -131,7 +131,7 @@ void * __init prom_early_alloc(unsigned long size) const size_t chunk_size = max(PAGE_SIZE, size); /* - * To mimimize the number of allocations, grab at least + * To minimize the number of allocations, grab at least * PAGE_SIZE of memory (that's an arbitrary choice that's * fast enough on the platforms we care about while minimizing * wasted bootmem) and hand off chunks of it to callers. diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S index d2ccadc247e6f9a51abcf09184eafc2c8b59346a..66b317398b8a625be4bb2924bb04a967b89c7492 100644 --- a/arch/x86/platform/pvh/head.S +++ b/arch/x86/platform/pvh/head.S @@ -30,10 +30,10 @@ * the boot start info structure. * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared. * - `cr4`: all bits are cleared. - * - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’ - * and a limit of ‘0xFFFFFFFF’. The selector value is unspecified. + * - `cs `: must be a 32-bit read/execute code segment with a base of `0` + * and a limit of `0xFFFFFFFF`. The selector value is unspecified. * - `ds`, `es`: must be a 32-bit read/write data segment with a base of - * ‘0’ and a limit of ‘0xFFFFFFFF’. The selector values are all + * `0` and a limit of `0xFFFFFFFF`. The selector values are all * unspecified. * - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit * of '0x67'. diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c index eafc530c8767c4075377403fa89c88416b52a8a5..1e9ff28bc2e04c270ab594fa82f11dbc3590bc0d 100644 --- a/arch/x86/platform/uv/uv_nmi.c +++ b/arch/x86/platform/uv/uv_nmi.c @@ -24,6 +24,7 @@ #include <asm/kdebug.h> #include <asm/local64.h> #include <asm/nmi.h> +#include <asm/reboot.h> #include <asm/traps.h> #include <asm/uv/uv.h> #include <asm/uv/uv_hub.h> @@ -91,6 +92,8 @@ static atomic_t uv_nmi_cpus_in_nmi = ATOMIC_INIT(-1); static atomic_t uv_nmi_slave_continue; static cpumask_var_t uv_nmi_cpu_mask; +static atomic_t uv_nmi_kexec_failed; + /* Values for uv_nmi_slave_continue */ #define SLAVE_CLEAR 0 #define SLAVE_CONTINUE 1 @@ -834,38 +837,35 @@ static void uv_nmi_touch_watchdogs(void) touch_nmi_watchdog(); } -static atomic_t uv_nmi_kexec_failed; - -#if defined(CONFIG_KEXEC_CORE) -static void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) +static void uv_nmi_kdump(int cpu, int main, struct pt_regs *regs) { + /* Check if kdump kernel loaded for both main and secondary CPUs */ + if (!kexec_crash_image) { + if (main) + pr_err("UV: NMI error: kdump kernel not loaded\n"); + return; + } + /* Call crash to dump system state */ - if (master) { + if (main) { pr_emerg("UV: NMI executing crash_kexec on CPU%d\n", cpu); crash_kexec(regs); - pr_emerg("UV: crash_kexec unexpectedly returned, "); + pr_emerg("UV: crash_kexec unexpectedly returned\n"); atomic_set(&uv_nmi_kexec_failed, 1); - if (!kexec_crash_image) { - pr_cont("crash kernel not loaded\n"); - return; - } - pr_cont("kexec busy, stalling cpus while waiting\n"); - } - /* If crash exec fails the slaves should return, otherwise stall */ - while (atomic_read(&uv_nmi_kexec_failed) == 0) - mdelay(10); -} + } else { /* secondary */ -#else /* !CONFIG_KEXEC_CORE */ -static inline void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) -{ - if (master) - pr_err("UV: NMI kdump: KEXEC not supported in this kernel\n"); - atomic_set(&uv_nmi_kexec_failed, 1); + /* If kdump kernel fails, secondaries will exit this loop */ + while (atomic_read(&uv_nmi_kexec_failed) == 0) { + + /* Once shootdown cpus starts, they do not return */ + run_crash_ipi_callback(regs); + + mdelay(10); + } + } } -#endif /* !CONFIG_KEXEC_CORE */ #ifdef CONFIG_KGDB #ifdef CONFIG_KGDB_KDB @@ -889,7 +889,7 @@ static inline int uv_nmi_kdb_reason(void) * Call KGDB/KDB from NMI handler * * Note that if both KGDB and KDB are configured, then the action of 'kgdb' or - * 'kdb' has no affect on which is used. See the KGDB documention for further + * 'kdb' has no affect on which is used. See the KGDB documentation for further * information. */ static void uv_call_kgdb_kdb(int cpu, struct pt_regs *regs, int master) diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index 7e4bafaedd7fab45936eb859e93380da931c0ff6..20263fcf16dbe32b6461030956fb71eb8c5bc5e7 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -334,7 +334,7 @@ int hibernate_resume_nonboot_cpu_disable(void) /* * When bsp_check() is called in hibernate and suspend, cpu hotplug - * is disabled already. So it's unnessary to handle race condition between + * is disabled already. So it's unnecessary to handle race condition between * cpumask query and cpu hotplug. */ static int bsp_check(void) diff --git a/arch/x86/power/hibernate.c b/arch/x86/power/hibernate.c index cd3914fc9f3d474d6c7b517ca670f9d30cde906b..e94e0050a583a8fe7d865093e9995a84c2fcdf32 100644 --- a/arch/x86/power/hibernate.c +++ b/arch/x86/power/hibernate.c @@ -13,8 +13,8 @@ #include <linux/kdebug.h> #include <linux/cpu.h> #include <linux/pgtable.h> - -#include <crypto/hash.h> +#include <linux/types.h> +#include <linux/crc32.h> #include <asm/e820/api.h> #include <asm/init.h> @@ -54,95 +54,33 @@ int pfn_is_nosave(unsigned long pfn) return pfn >= nosave_begin_pfn && pfn < nosave_end_pfn; } - -#define MD5_DIGEST_SIZE 16 - struct restore_data_record { unsigned long jump_address; unsigned long jump_address_phys; unsigned long cr3; unsigned long magic; - u8 e820_digest[MD5_DIGEST_SIZE]; + unsigned long e820_checksum; }; -#if IS_BUILTIN(CONFIG_CRYPTO_MD5) /** - * get_e820_md5 - calculate md5 according to given e820 table + * compute_e820_crc32 - calculate crc32 of a given e820 table * * @table: the e820 table to be calculated - * @buf: the md5 result to be stored to + * + * Return: the resulting checksum */ -static int get_e820_md5(struct e820_table *table, void *buf) +static inline u32 compute_e820_crc32(struct e820_table *table) { - struct crypto_shash *tfm; - struct shash_desc *desc; - int size; - int ret = 0; - - tfm = crypto_alloc_shash("md5", 0, 0); - if (IS_ERR(tfm)) - return -ENOMEM; - - desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm), - GFP_KERNEL); - if (!desc) { - ret = -ENOMEM; - goto free_tfm; - } - - desc->tfm = tfm; - - size = offsetof(struct e820_table, entries) + + int size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry) * table->nr_entries; - if (crypto_shash_digest(desc, (u8 *)table, size, buf)) - ret = -EINVAL; - - kfree_sensitive(desc); - -free_tfm: - crypto_free_shash(tfm); - return ret; -} - -static int hibernation_e820_save(void *buf) -{ - return get_e820_md5(e820_table_firmware, buf); -} - -static bool hibernation_e820_mismatch(void *buf) -{ - int ret; - u8 result[MD5_DIGEST_SIZE]; - - memset(result, 0, MD5_DIGEST_SIZE); - /* If there is no digest in suspend kernel, let it go. */ - if (!memcmp(result, buf, MD5_DIGEST_SIZE)) - return false; - - ret = get_e820_md5(e820_table_firmware, result); - if (ret) - return true; - - return memcmp(result, buf, MD5_DIGEST_SIZE) ? true : false; -} -#else -static int hibernation_e820_save(void *buf) -{ - return 0; -} - -static bool hibernation_e820_mismatch(void *buf) -{ - /* If md5 is not builtin for restore kernel, let it go. */ - return false; + return ~crc32_le(~0, (unsigned char const *)table, size); } -#endif #ifdef CONFIG_X86_64 -#define RESTORE_MAGIC 0x23456789ABCDEF01UL +#define RESTORE_MAGIC 0x23456789ABCDEF02UL #else -#define RESTORE_MAGIC 0x12345678UL +#define RESTORE_MAGIC 0x12345679UL #endif /** @@ -179,7 +117,8 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) */ rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK; - return hibernation_e820_save(rdr->e820_digest); + rdr->e820_checksum = compute_e820_crc32(e820_table_firmware); + return 0; } /** @@ -200,7 +139,7 @@ int arch_hibernation_header_restore(void *addr) jump_address_phys = rdr->jump_address_phys; restore_cr3 = rdr->cr3; - if (hibernation_e820_mismatch(rdr->e820_digest)) { + if (rdr->e820_checksum != compute_e820_crc32(e820_table_firmware)) { pr_crit("Hibernate inconsistent memory map detected!\n"); return -ENODEV; } diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 22fda7d991590504f956f943d4d4d7bfdcea67ee..1be71ef5e4c4ed52ed074a90bf7d6d55efc901fb 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -103,7 +103,7 @@ static void __init setup_real_mode(void) *ptr += phys_base; } - /* Must be perfomed *after* relocation. */ + /* Must be performed *after* relocation. */ trampoline_header = (struct trampoline_header *) __va(real_mode_header->trampoline_header); diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index dc0a337f985b66151efd295b1aeb3973086cb1a0..4f18cd9eacd8ecc60ad58a05d61fa92def7e63e8 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -1070,8 +1070,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_pmc = xen_read_pmc, - .iret = xen_iret, - .load_tr_desc = paravirt_nop, .set_ldt = xen_set_ldt, .load_gdt = xen_load_gdt, @@ -1233,8 +1231,8 @@ asmlinkage __visible void __init xen_start_kernel(void) /* Install Xen paravirt ops */ pv_info = xen_info; - pv_ops.init.patch = paravirt_patch_default; pv_ops.cpu = xen_cpu_ops; + paravirt_iret = xen_iret; xen_init_irq_ops(); /* diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c index cf2ade864c3020be11927d71b67b636c75a0a3da..1e28c880f64262e4806cb134474939acf2f0a3b3 100644 --- a/arch/x86/xen/mmu_pv.c +++ b/arch/x86/xen/mmu_pv.c @@ -2410,7 +2410,7 @@ int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr, rmd.prot = prot; /* * We use the err_ptr to indicate if there we are doing a contiguous - * mapping or a discontigious mapping. + * mapping or a discontiguous mapping. */ rmd.contiguous = !err_ptr; rmd.no_translate = no_translate; diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 91f5b330dcc6db596b5ef19bb1c7f03d3abeeb3c..d9c945ee1100847bd04173efdb1aedf33b49e610 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -379,11 +379,6 @@ void xen_timer_resume(void) } } -static const struct pv_time_ops xen_time_ops __initconst = { - .sched_clock = xen_sched_clock, - .steal_clock = xen_steal_clock, -}; - static struct pvclock_vsyscall_time_info *xen_clock __read_mostly; static u64 xen_clock_value_saved; @@ -525,17 +520,24 @@ static void __init xen_time_init(void) pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); } -void __init xen_init_time_ops(void) +static void __init xen_init_time_common(void) { xen_sched_clock_offset = xen_clocksource_read(); - pv_ops.time = xen_time_ops; + static_call_update(pv_steal_clock, xen_steal_clock); + paravirt_set_sched_clock(xen_sched_clock); + + x86_platform.calibrate_tsc = xen_tsc_khz; + x86_platform.get_wallclock = xen_get_wallclock; +} + +void __init xen_init_time_ops(void) +{ + xen_init_time_common(); x86_init.timers.timer_init = xen_time_init; x86_init.timers.setup_percpu_clockev = x86_init_noop; x86_cpuinit.setup_percpu_clockev = x86_init_noop; - x86_platform.calibrate_tsc = xen_tsc_khz; - x86_platform.get_wallclock = xen_get_wallclock; /* Dom0 uses the native method to set the hardware RTC. */ if (!xen_initial_domain()) x86_platform.set_wallclock = xen_set_wallclock; @@ -569,13 +571,11 @@ void __init xen_hvm_init_time_ops(void) return; } - xen_sched_clock_offset = xen_clocksource_read(); - pv_ops.time = xen_time_ops; + xen_init_time_common(); + x86_init.timers.setup_percpu_clockev = xen_time_init; x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents; - x86_platform.calibrate_tsc = xen_tsc_khz; - x86_platform.get_wallclock = xen_get_wallclock; x86_platform.set_wallclock = xen_set_wallclock; } #endif diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index af81a62faba64204015bc7279899a7d05b891929..a3dda25a4e45ee9f9e4a993aa279db68e06118d2 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -31,48 +31,23 @@ #define SERIAL_MAX_NUM_LINES 1 #define SERIAL_TIMER_VALUE (HZ / 10) +static void rs_poll(struct timer_list *); + static struct tty_driver *serial_driver; static struct tty_port serial_port; -static struct timer_list serial_timer; - +static DEFINE_TIMER(serial_timer, rs_poll); static DEFINE_SPINLOCK(timer_lock); -static char *serial_version = "0.1"; -static char *serial_name = "ISS serial driver"; - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ - -static void rs_poll(struct timer_list *); - static int rs_open(struct tty_struct *tty, struct file * filp) { - tty->port = &serial_port; spin_lock_bh(&timer_lock); - if (tty->count == 1) { - timer_setup(&serial_timer, rs_poll, 0); + if (tty->count == 1) mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); - } spin_unlock_bh(&timer_lock); return 0; } - -/* - * ------------------------------------------------------------ - * iss_serial_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ static void rs_close(struct tty_struct *tty, struct file * filp) { spin_lock_bh(&timer_lock); @@ -149,7 +124,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) static int rs_proc_show(struct seq_file *m, void *v) { - seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); + seq_printf(m, "serinfo:1.0 driver:0.1\n"); return 0; } @@ -166,14 +141,12 @@ static const struct tty_operations serial_ops = { .proc_show = rs_proc_show, }; -int __init rs_init(void) +static int __init rs_init(void) { tty_port_init(&serial_port); serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); - pr_info("%s %s\n", serial_name, serial_version); - /* Initialize the tty_driver structure */ serial_driver->driver_name = "iss_serial"; @@ -198,11 +171,7 @@ int __init rs_init(void) static __exit void rs_exit(void) { - int error; - - if ((error = tty_unregister_driver(serial_driver))) - pr_err("ISS_SERIAL: failed to unregister serial driver (%d)\n", - error); + tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); tty_port_destroy(&serial_port); } diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index e1e997af89a0d6f664d103b275a752e85fd7e3a2..3ebd6f10f728e9be433cd5e63147a84b40774029 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -75,7 +75,8 @@ void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx) blk_mq_run_hw_queue(hctx, true); } -static int sched_rq_cmp(void *priv, struct list_head *a, struct list_head *b) +static int sched_rq_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct request *rqa = container_of(a, struct request, queuelist); struct request *rqb = container_of(b, struct request, queuelist); diff --git a/block/blk-mq.c b/block/blk-mq.c index d4d7c1caa439666f212c63df86a2a61a81a68ca9..4e3a70ab5be19b7f2645d50263007be69e449d78 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1895,7 +1895,8 @@ void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx, spin_unlock(&ctx->lock); } -static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b) +static int plug_rq_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct request *rqa = container_of(a, struct request, queuelist); struct request *rqb = container_of(b, struct request, queuelist); diff --git a/certs/.gitignore b/certs/.gitignore index 2a248399068635ff51a8c66f4081f1816e3e25ff..6cbd1f1a5837b2b61552a5084e08873abab5cb34 100644 --- a/certs/.gitignore +++ b/certs/.gitignore @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only x509_certificate_list +x509_revocation_list diff --git a/certs/Kconfig b/certs/Kconfig index c94e93d8bccf038f4684c4cce93d558d9e7269ff..ab88d2a7f3c7fb38526b334562cd7b283ca5ea62 100644 --- a/certs/Kconfig +++ b/certs/Kconfig @@ -83,4 +83,21 @@ config SYSTEM_BLACKLIST_HASH_LIST wrapper to incorporate the list into the kernel. Each <hash> should be a string of hex digits. +config SYSTEM_REVOCATION_LIST + bool "Provide system-wide ring of revocation certificates" + depends on SYSTEM_BLACKLIST_KEYRING + depends on PKCS7_MESSAGE_PARSER=y + help + If set, this allows revocation certificates to be stored in the + blacklist keyring and implements a hook whereby a PKCS#7 message can + be checked to see if it matches such a certificate. + +config SYSTEM_REVOCATION_KEYS + string "X.509 certificates to be preloaded into the system blacklist keyring" + depends on SYSTEM_REVOCATION_LIST + help + If set, this option should be the filename of a PEM-formatted file + containing X.509 certificates to be included in the default blacklist + keyring. + endmenu diff --git a/certs/Makefile b/certs/Makefile index f4c25b67aad90b5833f1e390e2cf0ae303412fbd..b6db52ebf0beb166f290899519515fccc72e4786 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -3,8 +3,9 @@ # Makefile for the linux kernel signature checking certificates. # -obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o -obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o +obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o common.o +obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o common.o +obj-$(CONFIG_SYSTEM_REVOCATION_LIST) += revocation_certificates.o ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"") obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o else @@ -29,7 +30,7 @@ $(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREF $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS)) endif # CONFIG_SYSTEM_TRUSTED_KEYRING -clean-files := x509_certificate_list .x509.list +clean-files := x509_certificate_list .x509.list x509_revocation_list ifeq ($(CONFIG_MODULE_SIG),y) ############################################################################### @@ -104,3 +105,17 @@ targets += signing_key.x509 $(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) endif # CONFIG_MODULE_SIG + +ifeq ($(CONFIG_SYSTEM_REVOCATION_LIST),y) + +$(eval $(call config_filename,SYSTEM_REVOCATION_KEYS)) + +$(obj)/revocation_certificates.o: $(obj)/x509_revocation_list + +quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2)) + cmd_extract_certs = scripts/extract-cert $(2) $@ + +targets += x509_revocation_list +$(obj)/x509_revocation_list: scripts/extract-cert $(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(SYSTEM_REVOCATION_KEYS_FILENAME) FORCE + $(call if_changed,extract_certs,$(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_REVOCATION_KEYS)) +endif diff --git a/certs/blacklist.c b/certs/blacklist.c index bffe4c6f4a9e204d215119278d419bb491d2d7c8..c9a435b15af40679513d596ad845e31359a7c4df 100644 --- a/certs/blacklist.c +++ b/certs/blacklist.c @@ -17,9 +17,15 @@ #include <linux/uidgid.h> #include <keys/system_keyring.h> #include "blacklist.h" +#include "common.h" static struct key *blacklist_keyring; +#ifdef CONFIG_SYSTEM_REVOCATION_LIST +extern __initconst const u8 revocation_certificate_list[]; +extern __initconst const unsigned long revocation_certificate_list_size; +#endif + /* * The description must be a type prefix, a colon and then an even number of * hex digits. The hash is kept in the description. @@ -145,6 +151,49 @@ int is_binary_blacklisted(const u8 *hash, size_t hash_len) } EXPORT_SYMBOL_GPL(is_binary_blacklisted); +#ifdef CONFIG_SYSTEM_REVOCATION_LIST +/** + * add_key_to_revocation_list - Add a revocation certificate to the blacklist + * @data: The data blob containing the certificate + * @size: The size of data blob + */ +int add_key_to_revocation_list(const char *data, size_t size) +{ + key_ref_t key; + + key = key_create_or_update(make_key_ref(blacklist_keyring, true), + "asymmetric", + NULL, + data, + size, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW), + KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN); + + if (IS_ERR(key)) { + pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key)); + return PTR_ERR(key); + } + + return 0; +} + +/** + * is_key_on_revocation_list - Determine if the key for a PKCS#7 message is revoked + * @pkcs7: The PKCS#7 message to check + */ +int is_key_on_revocation_list(struct pkcs7_message *pkcs7) +{ + int ret; + + ret = pkcs7_validate_trust(pkcs7, blacklist_keyring); + + if (ret == 0) + return -EKEYREJECTED; + + return -ENOKEY; +} +#endif + /* * Initialise the blacklist */ @@ -177,3 +226,18 @@ static int __init blacklist_init(void) * Must be initialised before we try and load the keys into the keyring. */ device_initcall(blacklist_init); + +#ifdef CONFIG_SYSTEM_REVOCATION_LIST +/* + * Load the compiled-in list of revocation X.509 certificates. + */ +static __init int load_revocation_certificate_list(void) +{ + if (revocation_certificate_list_size) + pr_notice("Loading compiled-in revocation X.509 certificates\n"); + + return load_certificate_list(revocation_certificate_list, revocation_certificate_list_size, + blacklist_keyring); +} +late_initcall(load_revocation_certificate_list); +#endif diff --git a/certs/blacklist.h b/certs/blacklist.h index 1efd6fa0dc608c2a3d598b56c798f3e772a2bdbc..51b320cf85749e7a82788ed54a301b8a63243f1e 100644 --- a/certs/blacklist.h +++ b/certs/blacklist.h @@ -1,3 +1,5 @@ #include <linux/kernel.h> +#include <linux/errno.h> +#include <crypto/pkcs7.h> extern const char __initconst *const blacklist_hashes[]; diff --git a/certs/common.c b/certs/common.c new file mode 100644 index 0000000000000000000000000000000000000000..16a220887a53e8d74cb80c4e9f534a013e313c14 --- /dev/null +++ b/certs/common.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/kernel.h> +#include <linux/key.h> +#include "common.h" + +int load_certificate_list(const u8 cert_list[], + const unsigned long list_size, + const struct key *keyring) +{ + key_ref_t key; + const u8 *p, *end; + size_t plen; + + p = cert_list; + end = p + list_size; + while (p < end) { + /* Each cert begins with an ASN.1 SEQUENCE tag and must be more + * than 256 bytes in size. + */ + if (end - p < 4) + goto dodgy_cert; + if (p[0] != 0x30 && + p[1] != 0x82) + goto dodgy_cert; + plen = (p[2] << 8) | p[3]; + plen += 4; + if (plen > end - p) + goto dodgy_cert; + + key = key_create_or_update(make_key_ref(keyring, 1), + "asymmetric", + NULL, + p, + plen, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ), + KEY_ALLOC_NOT_IN_QUOTA | + KEY_ALLOC_BUILT_IN | + KEY_ALLOC_BYPASS_RESTRICTION); + if (IS_ERR(key)) { + pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", + PTR_ERR(key)); + } else { + pr_notice("Loaded X.509 cert '%s'\n", + key_ref_to_ptr(key)->description); + key_ref_put(key); + } + p += plen; + } + + return 0; + +dodgy_cert: + pr_err("Problem parsing in-kernel X.509 certificate list\n"); + return 0; +} diff --git a/certs/common.h b/certs/common.h new file mode 100644 index 0000000000000000000000000000000000000000..abdb5795936b76f6ed5f958eec9b0918a7cac0d6 --- /dev/null +++ b/certs/common.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _CERT_COMMON_H +#define _CERT_COMMON_H + +int load_certificate_list(const u8 cert_list[], const unsigned long list_size, + const struct key *keyring); + +#endif diff --git a/certs/revocation_certificates.S b/certs/revocation_certificates.S new file mode 100644 index 0000000000000000000000000000000000000000..f21aae8a8f0ef76fd79f3276e40a6a591b49357a --- /dev/null +++ b/certs/revocation_certificates.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/export.h> +#include <linux/init.h> + + __INITRODATA + + .align 8 + .globl revocation_certificate_list +revocation_certificate_list: +__revocation_list_start: + .incbin "certs/x509_revocation_list" +__revocation_list_end: + + .align 8 + .globl revocation_certificate_list_size +revocation_certificate_list_size: +#ifdef CONFIG_64BIT + .quad __revocation_list_end - __revocation_list_start +#else + .long __revocation_list_end - __revocation_list_start +#endif diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 4b693da488f14bcc66b452789f2eab92da959f9f..0c9a4795e847b5b43d68ef6786d53895d1502e64 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -16,6 +16,7 @@ #include <keys/asymmetric-type.h> #include <keys/system_keyring.h> #include <crypto/pkcs7.h> +#include "common.h" static struct key *builtin_trusted_keys; #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING @@ -137,54 +138,10 @@ device_initcall(system_trusted_keyring_init); */ static __init int load_system_certificate_list(void) { - key_ref_t key; - const u8 *p, *end; - size_t plen; - pr_notice("Loading compiled-in X.509 certificates\n"); - p = system_certificate_list; - end = p + system_certificate_list_size; - while (p < end) { - /* Each cert begins with an ASN.1 SEQUENCE tag and must be more - * than 256 bytes in size. - */ - if (end - p < 4) - goto dodgy_cert; - if (p[0] != 0x30 && - p[1] != 0x82) - goto dodgy_cert; - plen = (p[2] << 8) | p[3]; - plen += 4; - if (plen > end - p) - goto dodgy_cert; - - key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1), - "asymmetric", - NULL, - p, - plen, - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ), - KEY_ALLOC_NOT_IN_QUOTA | - KEY_ALLOC_BUILT_IN | - KEY_ALLOC_BYPASS_RESTRICTION); - if (IS_ERR(key)) { - pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", - PTR_ERR(key)); - } else { - pr_notice("Loaded X.509 cert '%s'\n", - key_ref_to_ptr(key)->description); - key_ref_put(key); - } - p += plen; - } - - return 0; - -dodgy_cert: - pr_err("Problem parsing in-kernel X.509 certificate list\n"); - return 0; + return load_certificate_list(system_certificate_list, system_certificate_list_size, + builtin_trusted_keys); } late_initcall(load_system_certificate_list); @@ -242,6 +199,12 @@ int verify_pkcs7_message_sig(const void *data, size_t len, pr_devel("PKCS#7 platform keyring is not available\n"); goto error; } + + ret = is_key_on_revocation_list(pkcs7); + if (ret != -ENOKEY) { + pr_devel("PKCS#7 platform key is on revocation list\n"); + goto error; + } } ret = pkcs7_validate_trust(pkcs7, trusted_keys); if (ret < 0) { diff --git a/crypto/Kconfig b/crypto/Kconfig index 5809cc198fa7c35dcc087447e8e7c244a41a885a..ca3b02dcbbfac7ecb5daf3c4035205ffc733372f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -242,6 +242,16 @@ config CRYPTO_ECDH help Generic implementation of the ECDH algorithm +config CRYPTO_ECDSA + tristate "ECDSA (NIST P192, P256 etc.) algorithm" + select CRYPTO_ECC + select CRYPTO_AKCIPHER + select ASN1 + help + Elliptic Curve Digital Signature Algorithm (NIST P192, P256 etc.) + is A NIST cryptographic standard algorithm. Only signature verification + is implemented. + config CRYPTO_ECRDSA tristate "EC-RDSA (GOST 34.10) algorithm" select CRYPTO_ECC @@ -1213,7 +1223,6 @@ config CRYPTO_BLOWFISH_X86_64 config CRYPTO_CAMELLIA tristate "Camellia cipher algorithms" - depends on CRYPTO select CRYPTO_ALGAPI help Camellia cipher algorithms module. @@ -1229,7 +1238,6 @@ config CRYPTO_CAMELLIA config CRYPTO_CAMELLIA_X86_64 tristate "Camellia cipher algorithm (x86_64)" depends on X86 && 64BIT - depends on CRYPTO select CRYPTO_SKCIPHER imply CRYPTO_CTR help @@ -1246,7 +1254,6 @@ config CRYPTO_CAMELLIA_X86_64 config CRYPTO_CAMELLIA_AESNI_AVX_X86_64 tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX)" depends on X86 && 64BIT - depends on CRYPTO select CRYPTO_SKCIPHER select CRYPTO_CAMELLIA_X86_64 select CRYPTO_SIMD @@ -1265,7 +1272,6 @@ config CRYPTO_CAMELLIA_AESNI_AVX_X86_64 config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX2)" depends on X86 && 64BIT - depends on CRYPTO select CRYPTO_CAMELLIA_AESNI_AVX_X86_64 help Camellia cipher algorithm module (x86_64/AES-NI/AVX2). @@ -1281,7 +1287,6 @@ config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 config CRYPTO_CAMELLIA_SPARC64 tristate "Camellia cipher algorithm (SPARC64)" depends on SPARC64 - depends on CRYPTO select CRYPTO_ALGAPI select CRYPTO_SKCIPHER help diff --git a/crypto/Makefile b/crypto/Makefile index cf23affb16780686a83dea9684095bad03ac9539..10526d4559b802b27224215ba1ac32b3cacc9abe 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -50,6 +50,12 @@ sm2_generic-y += sm2.o obj-$(CONFIG_CRYPTO_SM2) += sm2_generic.o +$(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h +$(obj)/ecdsa.o: $(obj)/ecdsasignature.asn1.h +ecdsa_generic-y += ecdsa.o +ecdsa_generic-y += ecdsasignature.asn1.o +obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o + crypto_acompress-y := acompress.o crypto_acompress-y += scompress.o obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o diff --git a/crypto/aegis.h b/crypto/aegis.h index 6920ebe7767953c53261960f5e203aa8422c9359..6ef9c174c973d1eb50f8e47dd016bce5722f6b59 100644 --- a/crypto/aegis.h +++ b/crypto/aegis.h @@ -21,9 +21,28 @@ union aegis_block { u8 bytes[AEGIS_BLOCK_SIZE]; }; +struct aegis_state; + +extern int aegis128_have_aes_insn; + #define AEGIS_BLOCK_ALIGN (__alignof__(union aegis_block)) #define AEGIS_ALIGNED(p) IS_ALIGNED((uintptr_t)p, AEGIS_BLOCK_ALIGN) +bool crypto_aegis128_have_simd(void); +void crypto_aegis128_update_simd(struct aegis_state *state, const void *msg); +void crypto_aegis128_init_simd(struct aegis_state *state, + const union aegis_block *key, + const u8 *iv); +void crypto_aegis128_encrypt_chunk_simd(struct aegis_state *state, u8 *dst, + const u8 *src, unsigned int size); +void crypto_aegis128_decrypt_chunk_simd(struct aegis_state *state, u8 *dst, + const u8 *src, unsigned int size); +int crypto_aegis128_final_simd(struct aegis_state *state, + union aegis_block *tag_xor, + unsigned int assoclen, + unsigned int cryptlen, + unsigned int authsize); + static __always_inline void crypto_aegis_block_xor(union aegis_block *dst, const union aegis_block *src) { diff --git a/crypto/aegis128-core.c b/crypto/aegis128-core.c index 89dc1c5596890d7e6822dbc33caec72441de8bdc..c4f1bfa1d04fa9eb00fc55cfaa89ed0690a45607 100644 --- a/crypto/aegis128-core.c +++ b/crypto/aegis128-core.c @@ -58,21 +58,6 @@ static bool aegis128_do_simd(void) return false; } -bool crypto_aegis128_have_simd(void); -void crypto_aegis128_update_simd(struct aegis_state *state, const void *msg); -void crypto_aegis128_init_simd(struct aegis_state *state, - const union aegis_block *key, - const u8 *iv); -void crypto_aegis128_encrypt_chunk_simd(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size); -void crypto_aegis128_decrypt_chunk_simd(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size); -int crypto_aegis128_final_simd(struct aegis_state *state, - union aegis_block *tag_xor, - unsigned int assoclen, - unsigned int cryptlen, - unsigned int authsize); - static void crypto_aegis128_update(struct aegis_state *state) { union aegis_block tmp; diff --git a/crypto/aegis128-neon.c b/crypto/aegis128-neon.c index 94d591a002a4737cd73369d9100e2fea5b15b11e..a7856915ec85b4172eceff31442f024d7d00809f 100644 --- a/crypto/aegis128-neon.c +++ b/crypto/aegis128-neon.c @@ -30,7 +30,7 @@ bool crypto_aegis128_have_simd(void) return IS_ENABLED(CONFIG_ARM64); } -void crypto_aegis128_init_simd(union aegis_block *state, +void crypto_aegis128_init_simd(struct aegis_state *state, const union aegis_block *key, const u8 *iv) { @@ -39,14 +39,14 @@ void crypto_aegis128_init_simd(union aegis_block *state, kernel_neon_end(); } -void crypto_aegis128_update_simd(union aegis_block *state, const void *msg) +void crypto_aegis128_update_simd(struct aegis_state *state, const void *msg) { kernel_neon_begin(); crypto_aegis128_update_neon(state, msg); kernel_neon_end(); } -void crypto_aegis128_encrypt_chunk_simd(union aegis_block *state, u8 *dst, +void crypto_aegis128_encrypt_chunk_simd(struct aegis_state *state, u8 *dst, const u8 *src, unsigned int size) { kernel_neon_begin(); @@ -54,7 +54,7 @@ void crypto_aegis128_encrypt_chunk_simd(union aegis_block *state, u8 *dst, kernel_neon_end(); } -void crypto_aegis128_decrypt_chunk_simd(union aegis_block *state, u8 *dst, +void crypto_aegis128_decrypt_chunk_simd(struct aegis_state *state, u8 *dst, const u8 *src, unsigned int size) { kernel_neon_begin(); @@ -62,7 +62,7 @@ void crypto_aegis128_decrypt_chunk_simd(union aegis_block *state, u8 *dst, kernel_neon_end(); } -int crypto_aegis128_final_simd(union aegis_block *state, +int crypto_aegis128_final_simd(struct aegis_state *state, union aegis_block *tag_xor, unsigned int assoclen, unsigned int cryptlen, diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 9acb9d2c4bcf9368142cbbfc556ebfdc72aa051d..18cc82dc4a42f0804e9439ee7b36ece1bd9406b5 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -491,8 +491,8 @@ static int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) /** * af_alg_alloc_tsgl - allocate the TX SGL * - * @sk socket of connection to user space - * @return: 0 upon success, < 0 upon error + * @sk: socket of connection to user space + * Return: 0 upon success, < 0 upon error */ static int af_alg_alloc_tsgl(struct sock *sk) { @@ -525,15 +525,15 @@ static int af_alg_alloc_tsgl(struct sock *sk) } /** - * aead_count_tsgl - Count number of TX SG entries + * af_alg_count_tsgl - Count number of TX SG entries * * The counting starts from the beginning of the SGL to @bytes. If - * an offset is provided, the counting of the SG entries starts at the offset. + * an @offset is provided, the counting of the SG entries starts at the @offset. * - * @sk socket of connection to user space - * @bytes Count the number of SG entries holding given number of bytes. - * @offset Start the counting of SG entries from the given offset. - * @return Number of TX SG entries found given the constraints + * @sk: socket of connection to user space + * @bytes: Count the number of SG entries holding given number of bytes. + * @offset: Start the counting of SG entries from the given offset. + * Return: Number of TX SG entries found given the constraints */ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) { @@ -577,19 +577,19 @@ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) EXPORT_SYMBOL_GPL(af_alg_count_tsgl); /** - * aead_pull_tsgl - Release the specified buffers from TX SGL + * af_alg_pull_tsgl - Release the specified buffers from TX SGL * - * If @dst is non-null, reassign the pages to dst. The caller must release + * If @dst is non-null, reassign the pages to @dst. The caller must release * the pages. If @dst_offset is given only reassign the pages to @dst starting * at the @dst_offset (byte). The caller must ensure that @dst is large * enough (e.g. by using af_alg_count_tsgl with the same offset). * - * @sk socket of connection to user space - * @used Number of bytes to pull from TX SGL - * @dst If non-NULL, buffer is reassigned to dst SGL instead of releasing. The - * caller must release the buffers in dst. - * @dst_offset Reassign the TX SGL from given offset. All buffers before - * reaching the offset is released. + * @sk: socket of connection to user space + * @used: Number of bytes to pull from TX SGL + * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The + * caller must release the buffers in dst. + * @dst_offset: Reassign the TX SGL from given offset. All buffers before + * reaching the offset is released. */ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, size_t dst_offset) @@ -657,7 +657,7 @@ EXPORT_SYMBOL_GPL(af_alg_pull_tsgl); /** * af_alg_free_areq_sgls - Release TX and RX SGLs of the request * - * @areq Request holding the TX and RX SGL + * @areq: Request holding the TX and RX SGL */ static void af_alg_free_areq_sgls(struct af_alg_async_req *areq) { @@ -692,9 +692,9 @@ static void af_alg_free_areq_sgls(struct af_alg_async_req *areq) /** * af_alg_wait_for_wmem - wait for availability of writable memory * - * @sk socket of connection to user space - * @flags If MSG_DONTWAIT is set, then only report if function would sleep - * @return 0 when writable memory is available, < 0 upon error + * @sk: socket of connection to user space + * @flags: If MSG_DONTWAIT is set, then only report if function would sleep + * Return: 0 when writable memory is available, < 0 upon error */ static int af_alg_wait_for_wmem(struct sock *sk, unsigned int flags) { @@ -725,7 +725,7 @@ static int af_alg_wait_for_wmem(struct sock *sk, unsigned int flags) /** * af_alg_wmem_wakeup - wakeup caller when writable memory is available * - * @sk socket of connection to user space + * @sk: socket of connection to user space */ void af_alg_wmem_wakeup(struct sock *sk) { @@ -748,10 +748,10 @@ EXPORT_SYMBOL_GPL(af_alg_wmem_wakeup); /** * af_alg_wait_for_data - wait for availability of TX data * - * @sk socket of connection to user space - * @flags If MSG_DONTWAIT is set, then only report if function would sleep - * @min Set to minimum request size if partial requests are allowed. - * @return 0 when writable memory is available, < 0 upon error + * @sk: socket of connection to user space + * @flags: If MSG_DONTWAIT is set, then only report if function would sleep + * @min: Set to minimum request size if partial requests are allowed. + * Return: 0 when writable memory is available, < 0 upon error */ int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min) { @@ -790,7 +790,7 @@ EXPORT_SYMBOL_GPL(af_alg_wait_for_data); /** * af_alg_data_wakeup - wakeup caller when new data can be sent to kernel * - * @sk socket of connection to user space + * @sk: socket of connection to user space */ static void af_alg_data_wakeup(struct sock *sk) { @@ -820,12 +820,12 @@ static void af_alg_data_wakeup(struct sock *sk) * * In addition, the ctx is filled with the information sent via CMSG. * - * @sock socket of connection to user space - * @msg message from user space - * @size size of message from user space - * @ivsize the size of the IV for the cipher operation to verify that the + * @sock: socket of connection to user space + * @msg: message from user space + * @size: size of message from user space + * @ivsize: the size of the IV for the cipher operation to verify that the * user-space-provided IV has the right size - * @return the number of copied data upon success, < 0 upon error + * Return: the number of copied data upon success, < 0 upon error */ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, unsigned int ivsize) @@ -977,6 +977,11 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg); /** * af_alg_sendpage - sendpage system call handler + * @sock: socket of connection to user space to write to + * @page: data to send + * @offset: offset into page to begin sending + * @size: length of data + * @flags: message send/receive flags * * This is a generic implementation of sendpage to fill ctx->tsgl_list. */ @@ -1035,6 +1040,7 @@ EXPORT_SYMBOL_GPL(af_alg_sendpage); /** * af_alg_free_resources - release resources required for crypto request + * @areq: Request holding the TX and RX SGL */ void af_alg_free_resources(struct af_alg_async_req *areq) { @@ -1047,6 +1053,9 @@ EXPORT_SYMBOL_GPL(af_alg_free_resources); /** * af_alg_async_cb - AIO callback handler + * @_req: async request info + * @err: if non-zero, error result to be returned via ki_complete(); + * otherwise return the AIO output length via ki_complete(). * * This handler cleans up the struct af_alg_async_req upon completion of the * AIO operation. @@ -1073,6 +1082,9 @@ EXPORT_SYMBOL_GPL(af_alg_async_cb); /** * af_alg_poll - poll system call handler + * @file: file pointer + * @sock: socket to poll + * @wait: poll_table */ __poll_t af_alg_poll(struct file *file, struct socket *sock, poll_table *wait) @@ -1098,9 +1110,9 @@ EXPORT_SYMBOL_GPL(af_alg_poll); /** * af_alg_alloc_areq - allocate struct af_alg_async_req * - * @sk socket of connection to user space - * @areqlen size of struct af_alg_async_req + crypto_*_reqsize - * @return allocated data structure or ERR_PTR upon error + * @sk: socket of connection to user space + * @areqlen: size of struct af_alg_async_req + crypto_*_reqsize + * Return: allocated data structure or ERR_PTR upon error */ struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, unsigned int areqlen) @@ -1125,13 +1137,13 @@ EXPORT_SYMBOL_GPL(af_alg_alloc_areq); * af_alg_get_rsgl - create the RX SGL for the output data from the crypto * operation * - * @sk socket of connection to user space - * @msg user space message - * @flags flags used to invoke recvmsg with - * @areq instance of the cryptographic request that will hold the RX SGL - * @maxsize maximum number of bytes to be pulled from user space - * @outlen number of bytes in the RX SGL - * @return 0 on success, < 0 upon error + * @sk: socket of connection to user space + * @msg: user space message + * @flags: flags used to invoke recvmsg with + * @areq: instance of the cryptographic request that will hold the RX SGL + * @maxsize: maximum number of bytes to be pulled from user space + * @outlen: number of bytes in the RX SGL + * Return: 0 on success, < 0 upon error */ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, struct af_alg_async_req *areq, size_t maxsize, diff --git a/crypto/api.c b/crypto/api.c index ed08cbd5b9d3f41e70509bd1c00d346cd5d55c86..c4eda56cff8917e08c2de3b0ada13df291c785ab 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -562,7 +562,7 @@ void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) { struct crypto_alg *alg; - if (unlikely(!mem)) + if (IS_ERR_OR_NULL(mem)) return; alg = tfm->__crt_alg; diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 788a4ba1e2e747de90b600b56a5b610ba4eb935b..4fefb219bfdc86318f33b822eef7bc8214a2a106 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/seq_file.h> #include <linux/scatterlist.h> +#include <linux/asn1.h> #include <keys/asymmetric-subtype.h> #include <crypto/public_key.h> #include <crypto/akcipher.h> @@ -85,7 +86,8 @@ int software_key_determine_akcipher(const char *encoding, return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; } - if (strcmp(encoding, "raw") == 0) { + if (strcmp(encoding, "raw") == 0 || + strcmp(encoding, "x962") == 0) { strcpy(alg_name, pkey->pkey_algo); return 0; } diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 52c9b455fc7df56845516edc94526b585358a87b..6d003096b5bca4dcaeb13158d88f8907e1a2b51a 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -227,6 +227,26 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, ctx->cert->sig->hash_algo = "sha224"; goto rsa_pkcs1; + case OID_id_ecdsa_with_sha1: + ctx->cert->sig->hash_algo = "sha1"; + goto ecdsa; + + case OID_id_ecdsa_with_sha224: + ctx->cert->sig->hash_algo = "sha224"; + goto ecdsa; + + case OID_id_ecdsa_with_sha256: + ctx->cert->sig->hash_algo = "sha256"; + goto ecdsa; + + case OID_id_ecdsa_with_sha384: + ctx->cert->sig->hash_algo = "sha384"; + goto ecdsa; + + case OID_id_ecdsa_with_sha512: + ctx->cert->sig->hash_algo = "sha512"; + goto ecdsa; + case OID_gost2012Signature256: ctx->cert->sig->hash_algo = "streebog256"; goto ecrdsa; @@ -255,6 +275,11 @@ sm2: ctx->cert->sig->encoding = "raw"; ctx->algo_oid = ctx->last_oid; return 0; +ecdsa: + ctx->cert->sig->pkey_algo = "ecdsa"; + ctx->cert->sig->encoding = "x962"; + ctx->algo_oid = ctx->last_oid; + return 0; } /* @@ -276,7 +301,8 @@ int x509_note_signature(void *context, size_t hdrlen, if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 || strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 || - strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0) { + strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0 || + strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) { /* Discard the BIT STRING metadata */ if (vlen < 1 || *(const u8 *)value != 0) return -EBADMSG; @@ -459,6 +485,7 @@ int x509_extract_key_data(void *context, size_t hdrlen, const void *value, size_t vlen) { struct x509_parse_context *ctx = context; + enum OID oid; ctx->key_algo = ctx->last_oid; switch (ctx->last_oid) { @@ -470,7 +497,25 @@ int x509_extract_key_data(void *context, size_t hdrlen, ctx->cert->pub->pkey_algo = "ecrdsa"; break; case OID_id_ecPublicKey: - ctx->cert->pub->pkey_algo = "sm2"; + if (parse_OID(ctx->params, ctx->params_size, &oid) != 0) + return -EBADMSG; + + switch (oid) { + case OID_sm2: + ctx->cert->pub->pkey_algo = "sm2"; + break; + case OID_id_prime192v1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p192"; + break; + case OID_id_prime256v1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p256"; + break; + case OID_id_ansip384r1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p384"; + break; + default: + return -ENOPKG; + } break; default: return -ENOPKG; diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index ae450eb8be144fbe41596d75d04f811ff6864521..3d45161b271a48f4a508a0dd3d9a981e6f7f15dd 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -129,7 +129,9 @@ int x509_check_for_self_signed(struct x509_certificate *cert) } ret = -EKEYREJECTED; - if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0) + if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0 && + (strncmp(cert->pub->pkey_algo, "ecdsa-", 6) != 0 || + strcmp(cert->sig->pkey_algo, "ecdsa") != 0)) goto out; ret = public_key_verify_signature(cert->pub, cert->sig); diff --git a/crypto/crc32_generic.c b/crypto/crc32_generic.c index 0e103fb5dd777c625d554114fe32a574674dae42..a989cb44fd16081c01966071ac8203108f259236 100644 --- a/crypto/crc32_generic.c +++ b/crypto/crc32_generic.c @@ -1,26 +1,4 @@ -/* GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see http://www.gnu.org/licenses - * - * Please visit http://www.xyratex.com/contact if you need additional - * information or have any questions. - * - * GPL HEADER END - */ - +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012 Xyratex Technology Limited */ diff --git a/crypto/ecc.c b/crypto/ecc.c index c80aa25994a0c3e4b87cefba958862d5a657b2f3..afc6cefdc1d9ef0fa6e683c5047afd18c323230e 100644 --- a/crypto/ecc.c +++ b/crypto/ecc.c @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <crypto/ecc_curve.h> #include <linux/module.h> #include <linux/random.h> #include <linux/slab.h> @@ -42,7 +43,14 @@ typedef struct { u64 m_high; } uint128_t; -static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id) +/* Returns curv25519 curve param */ +const struct ecc_curve *ecc_get_curve25519(void) +{ + return &ecc_25519; +} +EXPORT_SYMBOL(ecc_get_curve25519); + +const struct ecc_curve *ecc_get_curve(unsigned int curve_id) { switch (curve_id) { /* In FIPS mode only allow P256 and higher */ @@ -50,10 +58,13 @@ static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id) return fips_enabled ? NULL : &nist_p192; case ECC_CURVE_NIST_P256: return &nist_p256; + case ECC_CURVE_NIST_P384: + return &nist_p384; default: return NULL; } } +EXPORT_SYMBOL(ecc_get_curve); static u64 *ecc_alloc_digits_space(unsigned int ndigits) { @@ -128,7 +139,7 @@ bool vli_is_zero(const u64 *vli, unsigned int ndigits) } EXPORT_SYMBOL(vli_is_zero); -/* Returns nonzero if bit bit of vli is set. */ +/* Returns nonzero if bit of vli is set. */ static u64 vli_test_bit(const u64 *vli, unsigned int bit) { return (vli[bit / 64] & ((u64)1 << (bit % 64))); @@ -775,18 +786,133 @@ static void vli_mmod_fast_256(u64 *result, const u64 *product, } } +#define SL32OR32(x32, y32) (((u64)x32 << 32) | y32) +#define AND64H(x64) (x64 & 0xffFFffFF00000000ull) +#define AND64L(x64) (x64 & 0x00000000ffFFffFFull) + +/* Computes result = product % curve_prime + * from "Mathematical routines for the NIST prime elliptic curves" + */ +static void vli_mmod_fast_384(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + int carry; + const unsigned int ndigits = 6; + + /* t */ + vli_set(result, product, ndigits); + + /* s1 */ + tmp[0] = 0; // 0 || 0 + tmp[1] = 0; // 0 || 0 + tmp[2] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[3] = product[11]>>32; // 0 ||a23 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry = vli_lshift(tmp, tmp, 1, ndigits); + carry += vli_add(result, result, tmp, ndigits); + + /* s2 */ + tmp[0] = product[6]; //a13||a12 + tmp[1] = product[7]; //a15||a14 + tmp[2] = product[8]; //a17||a16 + tmp[3] = product[9]; //a19||a18 + tmp[4] = product[10]; //a21||a20 + tmp[5] = product[11]; //a23||a22 + carry += vli_add(result, result, tmp, ndigits); + + /* s3 */ + tmp[0] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[1] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 + tmp[2] = SL32OR32(product[7], (product[6])>>32); //a14||a13 + tmp[3] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 + tmp[4] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 + tmp[5] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 + carry += vli_add(result, result, tmp, ndigits); + + /* s4 */ + tmp[0] = AND64H(product[11]); //a23|| 0 + tmp[1] = (product[10]<<32); //a20|| 0 + tmp[2] = product[6]; //a13||a12 + tmp[3] = product[7]; //a15||a14 + tmp[4] = product[8]; //a17||a16 + tmp[5] = product[9]; //a19||a18 + carry += vli_add(result, result, tmp, ndigits); + + /* s5 */ + tmp[0] = 0; // 0|| 0 + tmp[1] = 0; // 0|| 0 + tmp[2] = product[10]; //a21||a20 + tmp[3] = product[11]; //a23||a22 + tmp[4] = 0; // 0|| 0 + tmp[5] = 0; // 0|| 0 + carry += vli_add(result, result, tmp, ndigits); + + /* s6 */ + tmp[0] = AND64L(product[10]); // 0 ||a20 + tmp[1] = AND64H(product[10]); //a21|| 0 + tmp[2] = product[11]; //a23||a22 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry += vli_add(result, result, tmp, ndigits); + + /* d1 */ + tmp[0] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 + tmp[1] = SL32OR32(product[7], (product[6]>>32)); //a14||a13 + tmp[2] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 + tmp[3] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 + tmp[4] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 + tmp[5] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + carry -= vli_sub(result, result, tmp, ndigits); + + /* d2 */ + tmp[0] = (product[10]<<32); //a20|| 0 + tmp[1] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[2] = (product[11]>>32); // 0 ||a23 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry -= vli_sub(result, result, tmp, ndigits); + + /* d3 */ + tmp[0] = 0; // 0 || 0 + tmp[1] = AND64H(product[11]); //a23|| 0 + tmp[2] = product[11]>>32; // 0 ||a23 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry -= vli_sub(result, result, tmp, ndigits); + + if (carry < 0) { + do { + carry += vli_add(result, result, curve_prime, ndigits); + } while (carry < 0); + } else { + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) + carry -= vli_sub(result, result, curve_prime, ndigits); + } + +} + +#undef SL32OR32 +#undef AND64H +#undef AND64L + /* Computes result = product % curve_prime for different curve_primes. * * Note that curve_primes are distinguished just by heuristic check and * not by complete conformance check. */ static bool vli_mmod_fast(u64 *result, u64 *product, - const u64 *curve_prime, unsigned int ndigits) + const struct ecc_curve *curve) { u64 tmp[2 * ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; - /* Currently, both NIST primes have -1 in lowest qword. */ - if (curve_prime[0] != -1ull) { + /* All NIST curves have name prefix 'nist_' */ + if (strncmp(curve->name, "nist_", 5) != 0) { /* Try to handle Pseudo-Marsenne primes. */ if (curve_prime[ndigits - 1] == -1ull) { vli_mmod_special(result, product, curve_prime, @@ -809,6 +935,9 @@ static bool vli_mmod_fast(u64 *result, u64 *product, case 4: vli_mmod_fast_256(result, product, curve_prime, tmp); break; + case 6: + vli_mmod_fast_384(result, product, curve_prime, tmp); + break; default: pr_err_ratelimited("ecc: unsupported digits size!\n"); return false; @@ -832,22 +961,22 @@ EXPORT_SYMBOL(vli_mod_mult_slow); /* Computes result = (left * right) % curve_prime. */ static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right, - const u64 *curve_prime, unsigned int ndigits) + const struct ecc_curve *curve) { u64 product[2 * ECC_MAX_DIGITS]; - vli_mult(product, left, right, ndigits); - vli_mmod_fast(result, product, curve_prime, ndigits); + vli_mult(product, left, right, curve->g.ndigits); + vli_mmod_fast(result, product, curve); } /* Computes result = left^2 % curve_prime. */ static void vli_mod_square_fast(u64 *result, const u64 *left, - const u64 *curve_prime, unsigned int ndigits) + const struct ecc_curve *curve) { u64 product[2 * ECC_MAX_DIGITS]; - vli_square(product, left, ndigits); - vli_mmod_fast(result, product, curve_prime, ndigits); + vli_square(product, left, curve->g.ndigits); + vli_mmod_fast(result, product, curve); } #define EVEN(vli) (!(vli[0] & 1)) @@ -945,25 +1074,27 @@ static bool ecc_point_is_zero(const struct ecc_point *point) /* Double in place */ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, - u64 *curve_prime, unsigned int ndigits) + const struct ecc_curve *curve) { /* t1 = x, t2 = y, t3 = z */ u64 t4[ECC_MAX_DIGITS]; u64 t5[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; if (vli_is_zero(z1, ndigits)) return; /* t4 = y1^2 */ - vli_mod_square_fast(t4, y1, curve_prime, ndigits); + vli_mod_square_fast(t4, y1, curve); /* t5 = x1*y1^2 = A */ - vli_mod_mult_fast(t5, x1, t4, curve_prime, ndigits); + vli_mod_mult_fast(t5, x1, t4, curve); /* t4 = y1^4 */ - vli_mod_square_fast(t4, t4, curve_prime, ndigits); + vli_mod_square_fast(t4, t4, curve); /* t2 = y1*z1 = z3 */ - vli_mod_mult_fast(y1, y1, z1, curve_prime, ndigits); + vli_mod_mult_fast(y1, y1, z1, curve); /* t3 = z1^2 */ - vli_mod_square_fast(z1, z1, curve_prime, ndigits); + vli_mod_square_fast(z1, z1, curve); /* t1 = x1 + z1^2 */ vli_mod_add(x1, x1, z1, curve_prime, ndigits); @@ -972,7 +1103,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, /* t3 = x1 - z1^2 */ vli_mod_sub(z1, x1, z1, curve_prime, ndigits); /* t1 = x1^2 - z1^4 */ - vli_mod_mult_fast(x1, x1, z1, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, z1, curve); /* t3 = 2*(x1^2 - z1^4) */ vli_mod_add(z1, x1, x1, curve_prime, ndigits); @@ -989,7 +1120,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, /* t1 = 3/2*(x1^2 - z1^4) = B */ /* t3 = B^2 */ - vli_mod_square_fast(z1, x1, curve_prime, ndigits); + vli_mod_square_fast(z1, x1, curve); /* t3 = B^2 - A */ vli_mod_sub(z1, z1, t5, curve_prime, ndigits); /* t3 = B^2 - 2A = x3 */ @@ -997,7 +1128,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, /* t5 = A - x3 */ vli_mod_sub(t5, t5, z1, curve_prime, ndigits); /* t1 = B * (A - x3) */ - vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, t5, curve); /* t4 = B * (A - x3) - y1^4 = y3 */ vli_mod_sub(t4, x1, t4, curve_prime, ndigits); @@ -1007,23 +1138,22 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, } /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ -static void apply_z(u64 *x1, u64 *y1, u64 *z, u64 *curve_prime, - unsigned int ndigits) +static void apply_z(u64 *x1, u64 *y1, u64 *z, const struct ecc_curve *curve) { u64 t1[ECC_MAX_DIGITS]; - vli_mod_square_fast(t1, z, curve_prime, ndigits); /* z^2 */ - vli_mod_mult_fast(x1, x1, t1, curve_prime, ndigits); /* x1 * z^2 */ - vli_mod_mult_fast(t1, t1, z, curve_prime, ndigits); /* z^3 */ - vli_mod_mult_fast(y1, y1, t1, curve_prime, ndigits); /* y1 * z^3 */ + vli_mod_square_fast(t1, z, curve); /* z^2 */ + vli_mod_mult_fast(x1, x1, t1, curve); /* x1 * z^2 */ + vli_mod_mult_fast(t1, t1, z, curve); /* z^3 */ + vli_mod_mult_fast(y1, y1, t1, curve); /* y1 * z^3 */ } /* P = (x1, y1) => 2P, (x2, y2) => P' */ static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2, - u64 *p_initial_z, u64 *curve_prime, - unsigned int ndigits) + u64 *p_initial_z, const struct ecc_curve *curve) { u64 z[ECC_MAX_DIGITS]; + const unsigned int ndigits = curve->g.ndigits; vli_set(x2, x1, ndigits); vli_set(y2, y1, ndigits); @@ -1034,35 +1164,37 @@ static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2, if (p_initial_z) vli_set(z, p_initial_z, ndigits); - apply_z(x1, y1, z, curve_prime, ndigits); + apply_z(x1, y1, z, curve); - ecc_point_double_jacobian(x1, y1, z, curve_prime, ndigits); + ecc_point_double_jacobian(x1, y1, z, curve); - apply_z(x2, y2, z, curve_prime, ndigits); + apply_z(x2, y2, z, curve); } /* Input P = (x1, y1, Z), Q = (x2, y2, Z) * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) * or P => P', Q => P + Q */ -static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, - unsigned int ndigits) +static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + const struct ecc_curve *curve) { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ u64 t5[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; /* t5 = x2 - x1 */ vli_mod_sub(t5, x2, x1, curve_prime, ndigits); /* t5 = (x2 - x1)^2 = A */ - vli_mod_square_fast(t5, t5, curve_prime, ndigits); + vli_mod_square_fast(t5, t5, curve); /* t1 = x1*A = B */ - vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, t5, curve); /* t3 = x2*A = C */ - vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); + vli_mod_mult_fast(x2, x2, t5, curve); /* t4 = y2 - y1 */ vli_mod_sub(y2, y2, y1, curve_prime, ndigits); /* t5 = (y2 - y1)^2 = D */ - vli_mod_square_fast(t5, y2, curve_prime, ndigits); + vli_mod_square_fast(t5, y2, curve); /* t5 = D - B */ vli_mod_sub(t5, t5, x1, curve_prime, ndigits); @@ -1071,11 +1203,11 @@ static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, /* t3 = C - B */ vli_mod_sub(x2, x2, x1, curve_prime, ndigits); /* t2 = y1*(C - B) */ - vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits); + vli_mod_mult_fast(y1, y1, x2, curve); /* t3 = B - x3 */ vli_mod_sub(x2, x1, t5, curve_prime, ndigits); /* t4 = (y2 - y1)*(B - x3) */ - vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits); + vli_mod_mult_fast(y2, y2, x2, curve); /* t4 = y3 */ vli_mod_sub(y2, y2, y1, curve_prime, ndigits); @@ -1086,22 +1218,24 @@ static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) * or P => P - Q, Q => P + Q */ -static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, - unsigned int ndigits) +static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + const struct ecc_curve *curve) { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ u64 t5[ECC_MAX_DIGITS]; u64 t6[ECC_MAX_DIGITS]; u64 t7[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; /* t5 = x2 - x1 */ vli_mod_sub(t5, x2, x1, curve_prime, ndigits); /* t5 = (x2 - x1)^2 = A */ - vli_mod_square_fast(t5, t5, curve_prime, ndigits); + vli_mod_square_fast(t5, t5, curve); /* t1 = x1*A = B */ - vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, t5, curve); /* t3 = x2*A = C */ - vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); + vli_mod_mult_fast(x2, x2, t5, curve); /* t4 = y2 + y1 */ vli_mod_add(t5, y2, y1, curve_prime, ndigits); /* t4 = y2 - y1 */ @@ -1110,29 +1244,29 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, /* t6 = C - B */ vli_mod_sub(t6, x2, x1, curve_prime, ndigits); /* t2 = y1 * (C - B) */ - vli_mod_mult_fast(y1, y1, t6, curve_prime, ndigits); + vli_mod_mult_fast(y1, y1, t6, curve); /* t6 = B + C */ vli_mod_add(t6, x1, x2, curve_prime, ndigits); /* t3 = (y2 - y1)^2 */ - vli_mod_square_fast(x2, y2, curve_prime, ndigits); + vli_mod_square_fast(x2, y2, curve); /* t3 = x3 */ vli_mod_sub(x2, x2, t6, curve_prime, ndigits); /* t7 = B - x3 */ vli_mod_sub(t7, x1, x2, curve_prime, ndigits); /* t4 = (y2 - y1)*(B - x3) */ - vli_mod_mult_fast(y2, y2, t7, curve_prime, ndigits); + vli_mod_mult_fast(y2, y2, t7, curve); /* t4 = y3 */ vli_mod_sub(y2, y2, y1, curve_prime, ndigits); /* t7 = (y2 + y1)^2 = F */ - vli_mod_square_fast(t7, t5, curve_prime, ndigits); + vli_mod_square_fast(t7, t5, curve); /* t7 = x3' */ vli_mod_sub(t7, t7, t6, curve_prime, ndigits); /* t6 = x3' - B */ vli_mod_sub(t6, t7, x1, curve_prime, ndigits); /* t6 = (y2 + y1)*(x3' - B) */ - vli_mod_mult_fast(t6, t6, t5, curve_prime, ndigits); + vli_mod_mult_fast(t6, t6, t5, curve); /* t2 = y3' */ vli_mod_sub(y1, t6, y1, curve_prime, ndigits); @@ -1162,41 +1296,37 @@ static void ecc_point_mult(struct ecc_point *result, vli_set(rx[1], point->x, ndigits); vli_set(ry[1], point->y, ndigits); - xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve_prime, - ndigits); + xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve); for (i = num_bits - 2; i > 0; i--) { nb = !vli_test_bit(scalar, i); - xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, - ndigits); - xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, - ndigits); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); } nb = !vli_test_bit(scalar, 0); - xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, - ndigits); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); /* Find final 1/Z value. */ /* X1 - X0 */ vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits); /* Yb * (X1 - X0) */ - vli_mod_mult_fast(z, z, ry[1 - nb], curve_prime, ndigits); + vli_mod_mult_fast(z, z, ry[1 - nb], curve); /* xP * Yb * (X1 - X0) */ - vli_mod_mult_fast(z, z, point->x, curve_prime, ndigits); + vli_mod_mult_fast(z, z, point->x, curve); /* 1 / (xP * Yb * (X1 - X0)) */ vli_mod_inv(z, z, curve_prime, point->ndigits); /* yP / (xP * Yb * (X1 - X0)) */ - vli_mod_mult_fast(z, z, point->y, curve_prime, ndigits); + vli_mod_mult_fast(z, z, point->y, curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ - vli_mod_mult_fast(z, z, rx[1 - nb], curve_prime, ndigits); + vli_mod_mult_fast(z, z, rx[1 - nb], curve); /* End 1/Z calculation */ - xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, ndigits); + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); - apply_z(rx[0], ry[0], z, curve_prime, ndigits); + apply_z(rx[0], ry[0], z, curve); vli_set(result->x, rx[0], ndigits); vli_set(result->y, ry[0], ndigits); @@ -1217,9 +1347,9 @@ static void ecc_point_add(const struct ecc_point *result, vli_mod_sub(z, result->x, p->x, curve->p, ndigits); vli_set(px, p->x, ndigits); vli_set(py, p->y, ndigits); - xycz_add(px, py, result->x, result->y, curve->p, ndigits); + xycz_add(px, py, result->x, result->y, curve); vli_mod_inv(z, z, curve->p, ndigits); - apply_z(result->x, result->y, z, curve->p, ndigits); + apply_z(result->x, result->y, z, curve); } /* Computes R = u1P + u2Q mod p using Shamir's trick. @@ -1248,8 +1378,7 @@ void ecc_point_mult_shamir(const struct ecc_point *result, points[2] = q; points[3] = ∑ - num_bits = max(vli_num_bits(u1, ndigits), - vli_num_bits(u2, ndigits)); + num_bits = max(vli_num_bits(u1, ndigits), vli_num_bits(u2, ndigits)); i = num_bits - 1; idx = (!!vli_test_bit(u1, i)) | ((!!vli_test_bit(u2, i)) << 1); point = points[idx]; @@ -1260,7 +1389,7 @@ void ecc_point_mult_shamir(const struct ecc_point *result, z[0] = 1; for (--i; i >= 0; i--) { - ecc_point_double_jacobian(rx, ry, z, curve->p, ndigits); + ecc_point_double_jacobian(rx, ry, z, curve); idx = (!!vli_test_bit(u1, i)) | ((!!vli_test_bit(u2, i)) << 1); point = points[idx]; if (point) { @@ -1270,27 +1399,17 @@ void ecc_point_mult_shamir(const struct ecc_point *result, vli_set(tx, point->x, ndigits); vli_set(ty, point->y, ndigits); - apply_z(tx, ty, z, curve->p, ndigits); + apply_z(tx, ty, z, curve); vli_mod_sub(tz, rx, tx, curve->p, ndigits); - xycz_add(tx, ty, rx, ry, curve->p, ndigits); - vli_mod_mult_fast(z, z, tz, curve->p, ndigits); + xycz_add(tx, ty, rx, ry, curve); + vli_mod_mult_fast(z, z, tz, curve); } } vli_mod_inv(z, z, curve->p, ndigits); - apply_z(rx, ry, z, curve->p, ndigits); + apply_z(rx, ry, z, curve); } EXPORT_SYMBOL(ecc_point_mult_shamir); -static inline void ecc_swap_digits(const u64 *in, u64 *out, - unsigned int ndigits) -{ - const __be64 *src = (__force __be64 *)in; - int i; - - for (i = 0; i < ndigits; i++) - out[i] = be64_to_cpu(src[ndigits - 1 - i]); -} - static int __ecc_is_key_valid(const struct ecc_curve *curve, const u64 *private_key, unsigned int ndigits) { @@ -1441,10 +1560,10 @@ int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, return -EINVAL; /* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */ - vli_mod_square_fast(yy, pk->y, curve->p, pk->ndigits); /* y^2 */ - vli_mod_square_fast(xxx, pk->x, curve->p, pk->ndigits); /* x^2 */ - vli_mod_mult_fast(xxx, xxx, pk->x, curve->p, pk->ndigits); /* x^3 */ - vli_mod_mult_fast(w, curve->a, pk->x, curve->p, pk->ndigits); /* a·x */ + vli_mod_square_fast(yy, pk->y, curve); /* y^2 */ + vli_mod_square_fast(xxx, pk->x, curve); /* x^2 */ + vli_mod_mult_fast(xxx, xxx, pk->x, curve); /* x^3 */ + vli_mod_mult_fast(w, curve->a, pk->x, curve); /* a·x */ vli_mod_add(w, w, curve->b, curve->p, pk->ndigits); /* a·x + b */ vli_mod_add(w, w, xxx, curve->p, pk->ndigits); /* x^3 + a·x + b */ if (vli_cmp(yy, w, pk->ndigits) != 0) /* Equation */ diff --git a/crypto/ecc.h b/crypto/ecc.h index d4e546b9ad79ea72d9dc0122cc7457e7f4feac84..a006132646a4389e74bdadb1a27ac998cea97993 100644 --- a/crypto/ecc.h +++ b/crypto/ecc.h @@ -26,49 +26,34 @@ #ifndef _CRYPTO_ECC_H #define _CRYPTO_ECC_H +#include <crypto/ecc_curve.h> + /* One digit is u64 qword. */ #define ECC_CURVE_NIST_P192_DIGITS 3 #define ECC_CURVE_NIST_P256_DIGITS 4 -#define ECC_MAX_DIGITS (512 / 64) +#define ECC_CURVE_NIST_P384_DIGITS 6 +#define ECC_MAX_DIGITS (512 / 64) /* due to ecrdsa */ #define ECC_DIGITS_TO_BYTES_SHIFT 3 -/** - * struct ecc_point - elliptic curve point in affine coordinates - * - * @x: X coordinate in vli form. - * @y: Y coordinate in vli form. - * @ndigits: Length of vlis in u64 qwords. - */ -struct ecc_point { - u64 *x; - u64 *y; - u8 ndigits; -}; +#define ECC_MAX_BYTES (ECC_MAX_DIGITS << ECC_DIGITS_TO_BYTES_SHIFT) #define ECC_POINT_INIT(x, y, ndigits) (struct ecc_point) { x, y, ndigits } /** - * struct ecc_curve - definition of elliptic curve - * - * @name: Short name of the curve. - * @g: Generator point of the curve. - * @p: Prime number, if Barrett's reduction is used for this curve - * pre-calculated value 'mu' is appended to the @p after ndigits. - * Use of Barrett's reduction is heuristically determined in - * vli_mmod_fast(). - * @n: Order of the curve group. - * @a: Curve parameter a. - * @b: Curve parameter b. + * ecc_swap_digits() - Copy ndigits from big endian array to native array + * @in: Input array + * @out: Output array + * @ndigits: Number of digits to copy */ -struct ecc_curve { - char *name; - struct ecc_point g; - u64 *p; - u64 *n; - u64 *a; - u64 *b; -}; +static inline void ecc_swap_digits(const u64 *in, u64 *out, unsigned int ndigits) +{ + const __be64 *src = (__force __be64 *)in; + int i; + + for (i = 0; i < ndigits; i++) + out[i] = be64_to_cpu(src[ndigits - 1 - i]); +} /** * ecc_is_key_valid() - Validate a given ECDH private key diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h index 69be6c7d228f2ed3513c7f6810942606873bf13e..9719934c9428ef68325fd36e2653c337774b50ea 100644 --- a/crypto/ecc_curve_defs.h +++ b/crypto/ecc_curve_defs.h @@ -54,4 +54,53 @@ static struct ecc_curve nist_p256 = { .b = nist_p256_b }; +/* NIST P-384 */ +static u64 nist_p384_g_x[] = { 0x3A545E3872760AB7ull, 0x5502F25DBF55296Cull, + 0x59F741E082542A38ull, 0x6E1D3B628BA79B98ull, + 0x8Eb1C71EF320AD74ull, 0xAA87CA22BE8B0537ull }; +static u64 nist_p384_g_y[] = { 0x7A431D7C90EA0E5Full, 0x0A60B1CE1D7E819Dull, + 0xE9DA3113B5F0B8C0ull, 0xF8F41DBD289A147Cull, + 0x5D9E98BF9292DC29ull, 0x3617DE4A96262C6Full }; +static u64 nist_p384_p[] = { 0x00000000FFFFFFFFull, 0xFFFFFFFF00000000ull, + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_n[] = { 0xECEC196ACCC52973ull, 0x581A0DB248B0A77Aull, + 0xC7634D81F4372DDFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_a[] = { 0x00000000FFFFFFFCull, 0xFFFFFFFF00000000ull, + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_b[] = { 0x2a85c8edd3ec2aefull, 0xc656398d8a2ed19dull, + 0x0314088f5013875aull, 0x181d9c6efe814112ull, + 0x988e056be3f82d19ull, 0xb3312fa7e23ee7e4ull }; +static struct ecc_curve nist_p384 = { + .name = "nist_384", + .g = { + .x = nist_p384_g_x, + .y = nist_p384_g_y, + .ndigits = 6, + }, + .p = nist_p384_p, + .n = nist_p384_n, + .a = nist_p384_a, + .b = nist_p384_b +}; + +/* curve25519 */ +static u64 curve25519_g_x[] = { 0x0000000000000009, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000 }; +static u64 curve25519_p[] = { 0xffffffffffffffed, 0xffffffffffffffff, + 0xffffffffffffffff, 0x7fffffffffffffff }; +static u64 curve25519_a[] = { 0x000000000001DB41, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000 }; +static const struct ecc_curve ecc_25519 = { + .name = "curve25519", + .g = { + .x = curve25519_g_x, + .ndigits = 4, + }, + .p = curve25519_p, + .a = curve25519_a, +}; + #endif diff --git a/crypto/ecdh.c b/crypto/ecdh.c index 96f80c8f8e30484c2c1b656d91d12a0e82eeee9f..04a427b8c956477deb435c5b9d68ec7a6f20f174 100644 --- a/crypto/ecdh.c +++ b/crypto/ecdh.c @@ -23,33 +23,16 @@ static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm) return kpp_tfm_ctx(tfm); } -static unsigned int ecdh_supported_curve(unsigned int curve_id) -{ - switch (curve_id) { - case ECC_CURVE_NIST_P192: return ECC_CURVE_NIST_P192_DIGITS; - case ECC_CURVE_NIST_P256: return ECC_CURVE_NIST_P256_DIGITS; - default: return 0; - } -} - static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, unsigned int len) { struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); struct ecdh params; - unsigned int ndigits; if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0 || - params.key_size > sizeof(ctx->private_key)) + params.key_size > sizeof(u64) * ctx->ndigits) return -EINVAL; - ndigits = ecdh_supported_curve(params.curve_id); - if (!ndigits) - return -EINVAL; - - ctx->curve_id = params.curve_id; - ctx->ndigits = ndigits; - if (!params.key || !params.key_size) return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, ctx->private_key); @@ -140,13 +123,24 @@ static unsigned int ecdh_max_size(struct crypto_kpp *tfm) return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1); } -static struct kpp_alg ecdh = { +static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P192; + ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS; + + return 0; +} + +static struct kpp_alg ecdh_nist_p192 = { .set_secret = ecdh_set_secret, .generate_public_key = ecdh_compute_value, .compute_shared_secret = ecdh_compute_value, .max_size = ecdh_max_size, + .init = ecdh_nist_p192_init_tfm, .base = { - .cra_name = "ecdh", + .cra_name = "ecdh-nist-p192", .cra_driver_name = "ecdh-generic", .cra_priority = 100, .cra_module = THIS_MODULE, @@ -154,14 +148,48 @@ static struct kpp_alg ecdh = { }, }; +static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P256; + ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS; + + return 0; +} + +static struct kpp_alg ecdh_nist_p256 = { + .set_secret = ecdh_set_secret, + .generate_public_key = ecdh_compute_value, + .compute_shared_secret = ecdh_compute_value, + .max_size = ecdh_max_size, + .init = ecdh_nist_p256_init_tfm, + .base = { + .cra_name = "ecdh-nist-p256", + .cra_driver_name = "ecdh-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdh_ctx), + }, +}; + +static bool ecdh_nist_p192_registered; + static int ecdh_init(void) { - return crypto_register_kpp(&ecdh); + int ret; + + ret = crypto_register_kpp(&ecdh_nist_p192); + ecdh_nist_p192_registered = ret == 0; + + return crypto_register_kpp(&ecdh_nist_p256); } static void ecdh_exit(void) { - crypto_unregister_kpp(&ecdh); + if (ecdh_nist_p192_registered) + crypto_unregister_kpp(&ecdh_nist_p192); + crypto_unregister_kpp(&ecdh_nist_p256); } subsys_initcall(ecdh_init); diff --git a/crypto/ecdh_helper.c b/crypto/ecdh_helper.c index fca63b559f655266fab1ff432dda85b21225c906..f18f9028f9121d66b6d1210c3408f6bcfdb7be14 100644 --- a/crypto/ecdh_helper.c +++ b/crypto/ecdh_helper.c @@ -10,7 +10,7 @@ #include <crypto/ecdh.h> #include <crypto/kpp.h> -#define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 2 * sizeof(short)) +#define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + sizeof(short)) static inline u8 *ecdh_pack_data(void *dst, const void *src, size_t sz) { @@ -46,7 +46,6 @@ int crypto_ecdh_encode_key(char *buf, unsigned int len, return -EINVAL; ptr = ecdh_pack_data(ptr, &secret, sizeof(secret)); - ptr = ecdh_pack_data(ptr, ¶ms->curve_id, sizeof(params->curve_id)); ptr = ecdh_pack_data(ptr, ¶ms->key_size, sizeof(params->key_size)); ecdh_pack_data(ptr, params->key, params->key_size); @@ -70,7 +69,6 @@ int crypto_ecdh_decode_key(const char *buf, unsigned int len, if (unlikely(len < secret.len)) return -EINVAL; - ptr = ecdh_unpack_data(¶ms->curve_id, ptr, sizeof(params->curve_id)); ptr = ecdh_unpack_data(¶ms->key_size, ptr, sizeof(params->key_size)); if (secret.len != crypto_ecdh_key_len(params)) return -EINVAL; diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c new file mode 100644 index 0000000000000000000000000000000000000000..1e7b15009bf6314d1cff33adb34c193682e6f757 --- /dev/null +++ b/crypto/ecdsa.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 IBM Corporation + */ + +#include <linux/module.h> +#include <crypto/internal/akcipher.h> +#include <crypto/akcipher.h> +#include <crypto/ecdh.h> +#include <linux/asn1_decoder.h> +#include <linux/scatterlist.h> + +#include "ecc.h" +#include "ecdsasignature.asn1.h" + +struct ecc_ctx { + unsigned int curve_id; + const struct ecc_curve *curve; + + bool pub_key_set; + u64 x[ECC_MAX_DIGITS]; /* pub key x and y coordinates */ + u64 y[ECC_MAX_DIGITS]; + 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 keylen = ndigits * sizeof(u64); + ssize_t diff = vlen - keylen; + const char *d = value; + u8 rs[ECC_MAX_BYTES]; + + 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, which we add + */ + 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 >= keylen) + return -EINVAL; + + if (diff) { + /* leading zeros not given in 'value' */ + memset(rs, 0, -diff); + } + + memcpy(&rs[-diff], d, vlen); + + ecc_swap_digits((u64 *)rs, 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; + unsigned int ndigits = curve->g.ndigits; + u64 s1[ECC_MAX_DIGITS]; + u64 u1[ECC_MAX_DIGITS]; + u64 u2[ECC_MAX_DIGITS]; + u64 x1[ECC_MAX_DIGITS]; + u64 y1[ECC_MAX_DIGITS]; + struct ecc_point res = ECC_POINT_INIT(x1, y1, ndigits); + + /* 0 < r < n and 0 < s < n */ + if (vli_is_zero(r, ndigits) || vli_cmp(r, curve->n, ndigits) >= 0 || + vli_is_zero(s, ndigits) || vli_cmp(s, curve->n, ndigits) >= 0) + return -EBADMSG; + + /* hash is given */ + pr_devel("hash : %016llx %016llx ... %016llx\n", + hash[ndigits - 1], hash[ndigits - 2], hash[0]); + + /* s1 = (s^-1) mod n */ + vli_mod_inv(s1, s, curve->n, ndigits); + /* u1 = (hash * s1) mod n */ + vli_mod_mult_slow(u1, hash, s1, curve->n, ndigits); + /* u2 = (r * s1) mod n */ + vli_mod_mult_slow(u2, r, s1, curve->n, ndigits); + /* res = u1*G + u2 * pub_key */ + ecc_point_mult_shamir(&res, u1, &curve->g, u2, &ctx->pub_key, curve); + + /* res.x = res.x mod n (if res.x > order) */ + if (unlikely(vli_cmp(res.x, curve->n, ndigits) == 1)) + /* faster alternative for NIST p384, p256 & p192 */ + vli_sub(res.x, res.x, curve->n, ndigits); + + if (!vli_cmp(res.x, r, ndigits)) + return 0; + + return -EKEYREJECTED; +} + +/* + * Verify an ECDSA signature. + */ +static int ecdsa_verify(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + size_t keylen = ctx->curve->g.ndigits * sizeof(u64); + struct ecdsa_signature_ctx sig_ctx = { + .curve = ctx->curve, + }; + u8 rawhash[ECC_MAX_BYTES]; + u64 hash[ECC_MAX_DIGITS]; + unsigned char *buffer; + ssize_t diff; + 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 the hash is shorter then we will add leading zeros to fit to ndigits */ + diff = keylen - req->dst_len; + if (diff >= 0) { + if (diff) + memset(rawhash, 0, diff); + memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); + } else if (diff < 0) { + /* given hash is longer, we take the left-most bytes */ + memcpy(&rawhash, buffer + req->src_len, keylen); + } + + ecc_swap_digits((u64 *)rawhash, hash, ctx->curve->g.ndigits); + + ret = _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); + +error: + kfree(buffer); + + return ret; +} + +static int ecdsa_ecc_ctx_init(struct ecc_ctx *ctx, unsigned int curve_id) +{ + ctx->curve_id = curve_id; + ctx->curve = ecc_get_curve(curve_id); + if (!ctx->curve) + return -EINVAL; + + return 0; +} + + +static void ecdsa_ecc_ctx_deinit(struct ecc_ctx *ctx) +{ + ctx->pub_key_set = false; +} + +static int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx) +{ + unsigned int curve_id = ctx->curve_id; + int ret; + + ecdsa_ecc_ctx_deinit(ctx); + ret = ecdsa_ecc_ctx_init(ctx, curve_id); + if (ret == 0) + ctx->pub_key = ECC_POINT_INIT(ctx->x, ctx->y, + ctx->curve->g.ndigits); + return ret; +} + +/* + * Set the public key given the raw uncompressed key data from an X509 + * certificate. The key data contain the concatenated X and Y coordinates of + * the public key. + */ +static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) +{ + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + const unsigned char *d = key; + const u64 *digits = (const u64 *)&d[1]; + unsigned int ndigits; + int ret; + + ret = ecdsa_ecc_ctx_reset(ctx); + if (ret < 0) + return ret; + + if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u64)) != 0) + return -EINVAL; + /* we only accept uncompressed format indicated by '4' */ + if (d[0] != 4) + return -EINVAL; + + keylen--; + ndigits = (keylen >> 1) / sizeof(u64); + if (ndigits != ctx->curve->g.ndigits) + return -EINVAL; + + ecc_swap_digits(digits, ctx->pub_key.x, ndigits); + ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits); + ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key); + + ctx->pub_key_set = ret == 0; + + return ret; +} + +static void ecdsa_exit_tfm(struct crypto_akcipher *tfm) +{ + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + + ecdsa_ecc_ctx_deinit(ctx); +} + +static unsigned int ecdsa_max_size(struct crypto_akcipher *tfm) +{ + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + + return ctx->pub_key.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; +} + +static int ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) +{ + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + + return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); +} + +static struct akcipher_alg ecdsa_nist_p384 = { + .verify = ecdsa_verify, + .set_pub_key = ecdsa_set_pub_key, + .max_size = ecdsa_max_size, + .init = ecdsa_nist_p384_init_tfm, + .exit = ecdsa_exit_tfm, + .base = { + .cra_name = "ecdsa-nist-p384", + .cra_driver_name = "ecdsa-nist-p384-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecc_ctx), + }, +}; + +static int ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) +{ + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + + return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); +} + +static struct akcipher_alg ecdsa_nist_p256 = { + .verify = ecdsa_verify, + .set_pub_key = ecdsa_set_pub_key, + .max_size = ecdsa_max_size, + .init = ecdsa_nist_p256_init_tfm, + .exit = ecdsa_exit_tfm, + .base = { + .cra_name = "ecdsa-nist-p256", + .cra_driver_name = "ecdsa-nist-p256-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecc_ctx), + }, +}; + +static int ecdsa_nist_p192_init_tfm(struct crypto_akcipher *tfm) +{ + struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + + return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P192); +} + +static struct akcipher_alg ecdsa_nist_p192 = { + .verify = ecdsa_verify, + .set_pub_key = ecdsa_set_pub_key, + .max_size = ecdsa_max_size, + .init = ecdsa_nist_p192_init_tfm, + .exit = ecdsa_exit_tfm, + .base = { + .cra_name = "ecdsa-nist-p192", + .cra_driver_name = "ecdsa-nist-p192-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecc_ctx), + }, +}; +static bool ecdsa_nist_p192_registered; + +static int ecdsa_init(void) +{ + int ret; + + /* NIST p192 may not be available in FIPS mode */ + ret = crypto_register_akcipher(&ecdsa_nist_p192); + ecdsa_nist_p192_registered = ret == 0; + + ret = crypto_register_akcipher(&ecdsa_nist_p256); + if (ret) + goto nist_p256_error; + + ret = crypto_register_akcipher(&ecdsa_nist_p384); + if (ret) + goto nist_p384_error; + + return 0; + +nist_p384_error: + crypto_unregister_akcipher(&ecdsa_nist_p256); + +nist_p256_error: + if (ecdsa_nist_p192_registered) + crypto_unregister_akcipher(&ecdsa_nist_p192); + return ret; +} + +static void ecdsa_exit(void) +{ + if (ecdsa_nist_p192_registered) + crypto_unregister_akcipher(&ecdsa_nist_p192); + crypto_unregister_akcipher(&ecdsa_nist_p256); + crypto_unregister_akcipher(&ecdsa_nist_p384); +} + +subsys_initcall(ecdsa_init); +module_exit(ecdsa_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stefan Berger <stefanb@linux.ibm.com>"); +MODULE_DESCRIPTION("ECDSA generic algorithm"); +MODULE_ALIAS_CRYPTO("ecdsa-generic"); diff --git a/crypto/ecdsasignature.asn1 b/crypto/ecdsasignature.asn1 new file mode 100644 index 0000000000000000000000000000000000000000..621ab754fb9f9769d0fe67bb7f79072db6ab8c2b --- /dev/null +++ b/crypto/ecdsasignature.asn1 @@ -0,0 +1,4 @@ +ECDSASignature ::= SEQUENCE { + r INTEGER ({ ecdsa_get_signature_r }), + s INTEGER ({ ecdsa_get_signature_s }) +} diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c index c36ea0c8be984bb1c305bb234aedaa9ea68080c9..76a04d000c0d3fd55c1521862208c04def6ce7bd 100644 --- a/crypto/fcrypt.c +++ b/crypto/fcrypt.c @@ -63,10 +63,7 @@ do { \ } while (0) /* Rotate right one 64 bit number as a 56 bit number */ -#define ror56_64(k, n) \ -do { \ - k = (k >> n) | ((k & ((1 << n) - 1)) << (56 - n)); \ -} while (0) +#define ror56_64(k, n) (k = (k >> n) | ((k & ((1 << n) - 1)) << (56 - n))) /* * Sboxes for Feistel network derived from diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c index 6e147c43fc186c2c540c6a23c8b995c1da413c2d..a11b3208760f35d508ed31a3eff46b9c15eb8bc8 100644 --- a/crypto/jitterentropy.c +++ b/crypto/jitterentropy.c @@ -597,7 +597,7 @@ int jent_read_entropy(struct rand_data *ec, unsigned char *data, if (!ec) return -1; - while (0 < len) { + while (len > 0) { unsigned int tocopy; jent_gen_entropy(ec); @@ -678,7 +678,7 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr, } /* verify and set the oversampling rate */ - if (0 == osr) + if (osr == 0) osr = 1; /* minimum sampling rate is 1 */ entropy_collector->osr = osr; @@ -769,7 +769,7 @@ int jent_entropy_init(void) * etc. with the goal to clear it to get the worst case * measurements. */ - if (CLEARCACHE > i) + if (i < CLEARCACHE) continue; if (stuck) @@ -826,7 +826,7 @@ int jent_entropy_init(void) * should not fail. The value of 3 should cover the NTP case being * performed during our test run. */ - if (3 < time_backwards) + if (time_backwards > 3) return JENT_ENOMONOTONIC; /* diff --git a/crypto/keywrap.c b/crypto/keywrap.c index 3517773bc7f732b06f947c238744d75ae70c7e80..054d9a216fc9f3dbabeecbdd12a28954b1e0fa5e 100644 --- a/crypto/keywrap.c +++ b/crypto/keywrap.c @@ -114,9 +114,9 @@ static void crypto_kw_scatterlist_ff(struct scatter_walk *walk, scatterwalk_start(walk, sg); scatterwalk_advance(walk, skip); break; - } else - skip -= sg->length; + } + skip -= sg->length; sg = sg_next(sg); } } diff --git a/crypto/rng.c b/crypto/rng.c index a888d84b524a4805dcb83ada16d92e0f05bd84ad..fea082b25fe4b6636ce184acdb907bb571f23603 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -34,22 +34,18 @@ int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) u8 *buf = NULL; int err; - crypto_stats_get(alg); if (!seed && slen) { buf = kmalloc(slen, GFP_KERNEL); - if (!buf) { - crypto_alg_put(alg); + if (!buf) return -ENOMEM; - } err = get_random_bytes_wait(buf, slen); - if (err) { - crypto_alg_put(alg); + if (err) goto out; - } seed = buf; } + crypto_stats_get(alg); err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); crypto_stats_rng_seed(alg, err); out: diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c index 236c87547a174edda55c952f21d3ca6664d42349..45f98b750053e72d7bc4ca9aa069f965291a5c18 100644 --- a/crypto/serpent_generic.c +++ b/crypto/serpent_generic.c @@ -272,6 +272,7 @@ int __serpent_setkey(struct serpent_ctx *ctx, const u8 *key, u32 *k = ctx->expkey; u8 *k8 = (u8 *)k; u32 r0, r1, r2, r3, r4; + __le32 *lk; int i; /* Copy key, add padding */ @@ -283,22 +284,32 @@ int __serpent_setkey(struct serpent_ctx *ctx, const u8 *key, while (i < SERPENT_MAX_KEY_SIZE) k8[i++] = 0; + lk = (__le32 *)k; + k[0] = le32_to_cpu(lk[0]); + k[1] = le32_to_cpu(lk[1]); + k[2] = le32_to_cpu(lk[2]); + k[3] = le32_to_cpu(lk[3]); + k[4] = le32_to_cpu(lk[4]); + k[5] = le32_to_cpu(lk[5]); + k[6] = le32_to_cpu(lk[6]); + k[7] = le32_to_cpu(lk[7]); + /* Expand key using polynomial */ - r0 = le32_to_cpu(k[3]); - r1 = le32_to_cpu(k[4]); - r2 = le32_to_cpu(k[5]); - r3 = le32_to_cpu(k[6]); - r4 = le32_to_cpu(k[7]); - - keyiter(le32_to_cpu(k[0]), r0, r4, r2, 0, 0); - keyiter(le32_to_cpu(k[1]), r1, r0, r3, 1, 1); - keyiter(le32_to_cpu(k[2]), r2, r1, r4, 2, 2); - keyiter(le32_to_cpu(k[3]), r3, r2, r0, 3, 3); - keyiter(le32_to_cpu(k[4]), r4, r3, r1, 4, 4); - keyiter(le32_to_cpu(k[5]), r0, r4, r2, 5, 5); - keyiter(le32_to_cpu(k[6]), r1, r0, r3, 6, 6); - keyiter(le32_to_cpu(k[7]), r2, r1, r4, 7, 7); + r0 = k[3]; + r1 = k[4]; + r2 = k[5]; + r3 = k[6]; + r4 = k[7]; + + keyiter(k[0], r0, r4, r2, 0, 0); + keyiter(k[1], r1, r0, r3, 1, 1); + keyiter(k[2], r2, r1, r4, 2, 2); + keyiter(k[3], r3, r2, r0, 3, 3); + keyiter(k[4], r4, r3, r1, 4, 4); + keyiter(k[5], r0, r4, r2, 5, 5); + keyiter(k[6], r1, r0, r3, 6, 6); + keyiter(k[7], r2, r1, r4, 7, 7); keyiter(k[0], r3, r2, r0, 8, 8); keyiter(k[1], r4, r3, r1, 9, 9); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 93359999c94bd48f198b5bc0bb1de1e9ac7d18e6..10c5b3b01ec47c2e45a044f3ad8c4180004f8c5a 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1168,11 +1168,6 @@ static inline int check_shash_op(const char *op, int err, return err; } -static inline const void *sg_data(struct scatterlist *sg) -{ - return page_address(sg_page(sg)) + sg->offset; -} - /* Test one hash test vector in one configuration, using the shash API */ static int test_shash_vec_cfg(const struct hash_testvec *vec, const char *vec_name, @@ -1230,7 +1225,7 @@ static int test_shash_vec_cfg(const struct hash_testvec *vec, return 0; if (cfg->nosimd) crypto_disable_simd_for_test(); - err = crypto_shash_digest(desc, sg_data(&tsgl->sgl[0]), + err = crypto_shash_digest(desc, sg_virt(&tsgl->sgl[0]), tsgl->sgl[0].length, result); if (cfg->nosimd) crypto_reenable_simd_for_test(); @@ -1266,7 +1261,7 @@ static int test_shash_vec_cfg(const struct hash_testvec *vec, cfg->finalization_type == FINALIZATION_TYPE_FINUP) { if (divs[i]->nosimd) crypto_disable_simd_for_test(); - err = crypto_shash_finup(desc, sg_data(&tsgl->sgl[i]), + err = crypto_shash_finup(desc, sg_virt(&tsgl->sgl[i]), tsgl->sgl[i].length, result); if (divs[i]->nosimd) crypto_reenable_simd_for_test(); @@ -1278,7 +1273,7 @@ static int test_shash_vec_cfg(const struct hash_testvec *vec, } if (divs[i]->nosimd) crypto_disable_simd_for_test(); - err = crypto_shash_update(desc, sg_data(&tsgl->sgl[i]), + err = crypto_shash_update(desc, sg_virt(&tsgl->sgl[i]), tsgl->sgl[i].length); if (divs[i]->nosimd) crypto_reenable_simd_for_test(); @@ -4904,11 +4899,38 @@ static const struct alg_test_desc alg_test_descs[] = { } }, { #endif - .alg = "ecdh", +#ifndef CONFIG_CRYPTO_FIPS + .alg = "ecdh-nist-p192", .test = alg_test_kpp, .fips_allowed = 1, .suite = { - .kpp = __VECS(ecdh_tv_template) + .kpp = __VECS(ecdh_p192_tv_template) + } + }, { +#endif + .alg = "ecdh-nist-p256", + .test = alg_test_kpp, + .fips_allowed = 1, + .suite = { + .kpp = __VECS(ecdh_p256_tv_template) + } + }, { + .alg = "ecdsa-nist-p192", + .test = alg_test_akcipher, + .suite = { + .akcipher = __VECS(ecdsa_nist_p192_tv_template) + } + }, { + .alg = "ecdsa-nist-p256", + .test = alg_test_akcipher, + .suite = { + .akcipher = __VECS(ecdsa_nist_p256_tv_template) + } + }, { + .alg = "ecdsa-nist-p384", + .test = alg_test_akcipher, + .suite = { + .akcipher = __VECS(ecdsa_nist_p384_tv_template) } }, { .alg = "ecrdsa", diff --git a/crypto/testmgr.h b/crypto/testmgr.h index ced56ea0c9b43b2be118bfdee7759eb10c9b6631..34e4a3db39917eab258e58336c84da806e0b518d 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -566,6 +566,430 @@ static const struct akcipher_testvec rsa_tv_template[] = { } }; +/* + * ECDSA test vectors. + */ +static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { + { + .key = + "\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" + "\x68\x01\x9d\xba\xce\x83\x08\xef\x95\x52\x7b\xa0\x0f\xe4\x18\x86" + "\x80\x6f\xa5\x79\x77\xda\xd0", + .c_size = 55, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\x4f\x53\x75\xc8\x02\x48\xeb\xc3\x92\x0f\x1e\x72\xee\xc4\xa3\xe3" + "\x5c\x99\xdb\x92\x5b\x36", + .c_size = 54, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\x69\x43\xfd\x48\x19\x86\xcf\x32\xdd\x41\x74\x6a\x51\xc7\xd9\x7d" + "\x3a\x97\xd9\xcd\x1a\x6a\x49", + .c_size = 55, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\xbc\x5a\x1f\x82\x96\x61\xd7\xd1\x01\x77\x44\x5d\x53\xa4\x7c\x93" + "\x12\x3b\x3b\x28\xfb\x6d\xe1", + .c_size = 55, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\xb4\x22\x9a\x98\x73\x3c\x83\xa9\x14\x2a\x5e\xf5\xe5\xfb\x72\x28" + "\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[] = { + { + .key = + "\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" + "\x52\x0e\x48\x4d\xcc\x02\x21\x00\xd7\xe4\xef\x52\x66\xd3\x5b\x9d" + "\x8a\xfa\x54\x93\x29\xa7\x70\x86\xf1\x03\x03\xf3\x3b\xe2\x73\xf7" + "\xfb\x9d\x8b\xde\xd4\x8d\x6f\xad", + .c_size = 72, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\xf5\x81\xd2\x1e\x02\x20\x5f\xf8\x74\xf8\x57\xd0\x5e\x54\x76\x20" + "\x4a\x77\x22\xec\xc8\x66\xbf\x50\x05\x58\x39\x0e\x26\x92\xce\xd5" + "\x2e\x8b\xde\x5a\x04\x0e", + .c_size = 70, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\xdc\x0c\xd0\x82\x02\x21\x00\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 = 71, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\xc7\x94\xb1\xd5\xfe\x02\x21\x00\xeb\xa7\x80\x26\xdc\xf9\x3a\x44" + "\x19\xfb\x5f\x92\xf4\xc9\x23\x37\x69\xf4\x3b\x4f\x47\xcf\x9b\x16" + "\xc0\x60\x11\x92\xdc\x17\x89\x12", + .c_size = 72, + .public_key_vec = true, + .siggen_sigver_test = true, + }, { + .key = + "\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" + "\x99\x09\x37\x4d\xfa\x02\x20\x1e\xb9\x75\x31\xf6\x04\xa5\x4d\xf8" + "\x00\xdd\xab\xd4\xc0\x2b\xe6\x5c\xad\xc3\x78\x1c\xc2\xc1\x19\x76" + "\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[] = { + { + .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, + .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" + "\x32\x3c\xce\x70\x2b\x78\xf1\x4c\x26\xe6\x5b\x86\xcf\xec\x7c\x7e" + "\xd0\x87\xd7\xd7\x6e\x02\x31\x00\xcd\xbb\x7e\x81\x5d\x8f\x63\xc0" + "\x5f\x63\xb1\xbe\x5e\x4c\x0e\xa1\xdf\x28\x8c\x1b\xfa\xf9\x95\x88" + "\x74\xa0\x0f\xbf\xaf\xc3\x36\x76\x4a\xa1\x59\xf1\x1c\xa4\x58\x26" + "\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" + "\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, + .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" + "\xe3\x93\x07\xe0\x99\xc9\x9c\x11\xb8\x10\x01\xc5\x41\x3f\xdd\x15" + "\x1b\x68\x2b\x9d\x8b\x02\x31\x00\x8b\x03\x2c\xfc\x1f\xd1\xa9\xa4" + "\x4b\x00\x08\x31\x6c\xf5\xd5\xf6\xdf\xd8\x68\xa2\x64\x42\x65\xf3" + "\x4d\xd0\xc6\x6e\xb0\xe9\xfc\x14\x9f\x19\xd0\x42\x8b\x93\xc2\x11" + "\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" + "\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, + .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" + "\x04\xe2\xf9\x67\xb6\xc6\xfc\x70\x2e\x66\x3c\x77\xc8\x8d\x2c\x79" + "\x3a\x8e\x32\xc4\x02\x30\x40\x34\xb8\x90\xa9\x80\xab\x47\x26\xa2" + "\xb0\x89\x42\x0a\xda\xd9\xdd\xce\xbc\xb2\x97\xf4\x9c\xf3\x15\x68" + "\xc0\x75\x3e\x23\x5e\x36\x4f\x8d\xde\x1e\x93\x8d\x95\xbb\x10\x0e" + "\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" + "\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, + .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" + "\xca\x8c\xd6\xb6\xb4\x3b\x1f\x07\x8f\x15\x02\xfe\x1d\xa2\xa4\xc8" + "\xf2\xea\x9d\x11\x1f\x02\x31\x00\xfc\x50\xf6\x43\xbd\x50\x82\x0e" + "\xbf\xe3\x75\x24\x49\xac\xfb\xc8\x71\xcd\x8f\x18\x99\xf0\x0f\x13" + "\x44\x92\x8c\x86\x99\x65\xb3\x97\x96\x17\x04\xc9\x05\x77\xf1\x8e" + "\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" + "\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, + .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" + "\xaf\xb3\xd9\xdc\x2b\x43\x0e\x6a\xb3\x53\x6f\x3e\xb3\xc7\xa8\xb3" + "\x17\x77\xd1\x02\x30\x63\xf6\xf0\x3d\x5f\x5f\x99\x3f\xde\x3a\x3d" + "\x16\xaf\xb4\x52\x6a\xec\x63\xe3\x0c\xec\x50\xdc\xcc\xc4\x6a\x03" + "\x5f\x8d\x7a\xf9\xfb\x34\xe4\x8b\x80\xa5\xb6\xda\x2c\x4e\x45\xcf" + "\x3c\x93\xff\x50\x5d", + .c_size = 101, + .public_key_vec = true, + .siggen_sigver_test = true, + }, +}; + /* * EC-RDSA test vectors are generated by gost-engine. */ @@ -2261,19 +2685,17 @@ static const struct kpp_testvec curve25519_tv_template[] = { } }; -static const struct kpp_testvec ecdh_tv_template[] = { - { #ifndef CONFIG_CRYPTO_FIPS +static const struct kpp_testvec ecdh_p192_tv_template[] = { + { .secret = #ifdef __LITTLE_ENDIAN "\x02\x00" /* type */ - "\x20\x00" /* len */ - "\x01\x00" /* curve_id */ + "\x1e\x00" /* len */ "\x18\x00" /* key_size */ #else "\x00\x02" /* type */ - "\x00\x20" /* len */ - "\x00\x01" /* curve_id */ + "\x00\x1e" /* len */ "\x00\x18" /* key_size */ #endif "\xb5\x05\xb1\x71\x1e\xbf\x8c\xda" @@ -2301,18 +2723,20 @@ static const struct kpp_testvec ecdh_tv_template[] = { .b_public_size = 48, .expected_a_public_size = 48, .expected_ss_size = 24 - }, { + } +}; #endif + +static const struct kpp_testvec ecdh_p256_tv_template[] = { + { .secret = #ifdef __LITTLE_ENDIAN "\x02\x00" /* type */ - "\x28\x00" /* len */ - "\x02\x00" /* curve_id */ + "\x26\x00" /* len */ "\x20\x00" /* key_size */ #else "\x00\x02" /* type */ - "\x00\x28" /* len */ - "\x00\x02" /* curve_id */ + "\x00\x26" /* len */ "\x00\x20" /* key_size */ #endif "\x24\xd1\x21\xeb\xe5\xcf\x2d\x83" @@ -2350,25 +2774,21 @@ static const struct kpp_testvec ecdh_tv_template[] = { .secret = #ifdef __LITTLE_ENDIAN "\x02\x00" /* type */ - "\x08\x00" /* len */ - "\x02\x00" /* curve_id */ + "\x06\x00" /* len */ "\x00\x00", /* key_size */ #else "\x00\x02" /* type */ - "\x00\x08" /* len */ - "\x00\x02" /* curve_id */ + "\x00\x06" /* len */ "\x00\x00", /* key_size */ #endif .b_secret = #ifdef __LITTLE_ENDIAN "\x02\x00" /* type */ - "\x28\x00" /* len */ - "\x02\x00" /* curve_id */ + "\x26\x00" /* len */ "\x20\x00" /* key_size */ #else "\x00\x02" /* type */ - "\x00\x28" /* len */ - "\x00\x02" /* curve_id */ + "\x00\x26" /* len */ "\x00\x20" /* key_size */ #endif "\x24\xd1\x21\xeb\xe5\xcf\x2d\x83" diff --git a/drivers/Kconfig b/drivers/Kconfig index 62c753a73651ffba3ebe876a4049132c22590011..47980c6b1945d1ba73e1e2dd8dd4d33fdc4e37a0 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -149,6 +149,8 @@ source "drivers/xen/Kconfig" source "drivers/greybus/Kconfig" +source "drivers/comedi/Kconfig" + source "drivers/staging/Kconfig" source "drivers/platform/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 6fba7daba59194dcc785d05f64e3c0296db9a2b7..8f3fee8281ade69a1393bf3be4c44c954516a4c5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -148,6 +148,7 @@ obj-$(CONFIG_VHOST_IOTLB) += vhost/ obj-$(CONFIG_VHOST) += vhost/ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_GREYBUS) += greybus/ +obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ diff --git a/drivers/accessibility/speakup/i18n.c b/drivers/accessibility/speakup/i18n.c index ee240d36f947c997afd84ca585ecd07a8ad91f71..46bd50f3c3a42c119e1523cb7f1f6cb64fb8cbe6 100644 --- a/drivers/accessibility/speakup/i18n.c +++ b/drivers/accessibility/speakup/i18n.c @@ -548,12 +548,10 @@ ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length) if ((index < MSG_FIRST_INDEX) || (index >= MSG_LAST_INDEX)) return -EINVAL; - newstr = kmalloc(length + 1, GFP_KERNEL); + newstr = kmemdup_nul(text, length, GFP_KERNEL); if (!newstr) return -ENOMEM; - memcpy(newstr, text, length); - newstr[length] = '\0'; if (index >= MSG_FORMATTED_START && index <= MSG_FORMATTED_END && !fmt_validate(speakup_default_msgs[index], newstr)) { diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c index 9af1d4c124d378d312e943c260c43afd426c8156..2e39fcf492d8bd8d1b0e09a5887714ba38645b15 100644 --- a/drivers/accessibility/speakup/spk_ttyio.c +++ b/drivers/accessibility/speakup/spk_ttyio.c @@ -104,7 +104,6 @@ static int spk_ttyio_receive_buf2(struct tty_struct *tty, static struct tty_ldisc_ops spk_ttyio_ldisc_ops = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "speakup_ldisc", .open = spk_ttyio_ldisc_open, .close = spk_ttyio_ldisc_close, diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index b41180330cc11e280f2c8ab2cbc9f24e2f457bc1..b0cb662233f1a19151659e4c57875e2a062aad1b 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 27 $) + * acpi_ac.c - ACPI AC Adapter Driver (Revision: 27) * * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> @@ -78,17 +78,14 @@ static struct acpi_driver acpi_ac_driver = { struct acpi_ac { struct power_supply *charger; struct power_supply_desc charger_desc; - struct acpi_device * device; + struct acpi_device *device; unsigned long long state; struct notifier_block battery_nb; }; #define to_acpi_ac(x) power_supply_get_drvdata(x) -/* -------------------------------------------------------------------------- - AC Adapter Management - -------------------------------------------------------------------------- */ - +/* AC Adapter Management */ static int acpi_ac_get_state(struct acpi_ac *ac) { acpi_status status = AE_OK; @@ -109,9 +106,7 @@ static int acpi_ac_get_state(struct acpi_ac *ac) return 0; } -/* -------------------------------------------------------------------------- - sysfs I/F - -------------------------------------------------------------------------- */ +/* sysfs I/F */ static int get_ac_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -138,10 +133,7 @@ static enum power_supply_property ac_props[] = { POWER_SUPPLY_PROP_ONLINE, }; -/* -------------------------------------------------------------------------- - Driver Model - -------------------------------------------------------------------------- */ - +/* Driver Model */ static void acpi_ac_notify(struct acpi_device *device, u32 event) { struct acpi_ac *ac = acpi_driver_data(device); @@ -174,8 +166,6 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event) acpi_notifier_call_chain(device, event, (u32) ac->state); kobject_uevent(&ac->charger->dev.kobj, KOBJ_CHANGE); } - - return; } static int acpi_ac_battery_notify(struct notifier_block *nb, @@ -187,7 +177,7 @@ static int acpi_ac_battery_notify(struct notifier_block *nb, /* * On HP Pavilion dv6-6179er AC status notifications aren't triggered * when adapter is plugged/unplugged. However, battery status - * notifcations are triggered when battery starts charging or + * notifications are triggered when battery starts charging or * discharging. Re-reading AC status triggers lost AC notifications, * if AC status has changed. */ @@ -282,9 +272,8 @@ static int acpi_ac_add(struct acpi_device *device) ac->battery_nb.notifier_call = acpi_ac_battery_notify; register_acpi_notifier(&ac->battery_nb); end: - if (result) { + if (result) kfree(ac); - } return result; } @@ -293,7 +282,7 @@ end: static int acpi_ac_resume(struct device *dev) { struct acpi_ac *ac; - unsigned old_state; + unsigned int old_state; if (!dev) return -EINVAL; @@ -352,9 +341,8 @@ static int __init acpi_ac_init(void) } result = acpi_bus_register_driver(&acpi_ac_driver); - if (result < 0) { + if (result < 0) return -ENODEV; - } return 0; } diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 39359ce0eb2c057ebdfd22f3252bb4e8018c7baa..0ec5b3f69112774f176ee1b12a185d4e5350e755 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -176,10 +176,10 @@ static const struct apd_device_desc hip08_spi_desc = { #endif -/** -* Create platform device during acpi scan attach handle. -* Return value > 0 on success of creating device. -*/ +/* + * Create platform device during acpi scan attach handle. + * Return value > 0 on success of creating device. + */ static int acpi_apd_create_device(struct acpi_device *adev, const struct acpi_device_id *id) { diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index 9d6c0fc120d77d31e152b38f087b648b22a6cad8..bbd00d96b7a8dca8bd5613e457cb0546a0e0d1af 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c @@ -478,7 +478,6 @@ err_lock: ipmi_dev_release(ipmi_device); err_ref: put_device(smi_data.dev); - return; } static void ipmi_bmc_gone(int iface) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index be73974ce449acaecd88bfe31973d2d930e9efb0..ca742f16a507a4d4b8634b813b52ff6156a111af 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -377,6 +377,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { static int is_memory(struct acpi_resource *res, void *not_used) { struct resource r; + return !acpi_dev_resource_memory(res, &r); } @@ -1200,6 +1201,7 @@ static int acpi_lpss_poweroff_noirq(struct device *dev) if (pdata->dev_desc->resume_from_noirq) { /* This is analogous to the acpi_lpss_suspend_noirq() case. */ int ret = acpi_lpss_do_poweroff_late(dev); + if (ret) return ret; } diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index b84ab722feb444a9fecca65f76ae3a7e7cc67a89..df4adeb335b246da9ee32bc4f6181d264c1cd841 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -128,6 +128,7 @@ static void round_robin_cpu(unsigned int tsk_index) static void exit_round_robin(unsigned int tsk_index) { struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); + cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); tsk_in_cpu[tsk_index] = -1; } @@ -265,6 +266,7 @@ static ssize_t rrtime_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; + if (kstrtoul(buf, 0, &num)) return -EINVAL; if (num < 1 || num >= 100) @@ -286,6 +288,7 @@ static ssize_t idlepct_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; + if (kstrtoul(buf, 0, &num)) return -EINVAL; if (num < 1 || num >= 100) @@ -307,6 +310,7 @@ static ssize_t idlecpus_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; + if (kstrtoul(buf, 0, &num)) return -EINVAL; mutex_lock(&isolated_cpus_lock); diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 2ee5e05a0d69e881d6a28f02f7e05028037da9b9..2d5bd2a6ddcefd2760babc6f7f946480d0c588d7 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -22,17 +22,10 @@ #include "internal.h" -#define _COMPONENT ACPI_PROCESSOR_COMPONENT - -ACPI_MODULE_NAME("processor"); - DEFINE_PER_CPU(struct acpi_processor *, processors); EXPORT_PER_CPU_SYMBOL(processors); -/* -------------------------------------------------------------------------- - Errata Handling - -------------------------------------------------------------------------- */ - +/* Errata Handling */ struct acpi_processor_errata errata __read_mostly; EXPORT_SYMBOL_GPL(errata); @@ -51,19 +44,19 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev) switch (dev->revision) { case 0: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n")); + dev_dbg(&dev->dev, "Found PIIX4 A-step\n"); break; case 1: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n")); + dev_dbg(&dev->dev, "Found PIIX4 B-step\n"); break; case 2: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n")); + dev_dbg(&dev->dev, "Found PIIX4E\n"); break; case 3: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n")); + dev_dbg(&dev->dev, "Found PIIX4M\n"); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n")); + dev_dbg(&dev->dev, "Found unknown PIIX4\n"); break; } @@ -129,11 +122,9 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev) } if (errata.piix4.bmisx) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Bus master activity detection (BM-IDE) erratum enabled\n")); + dev_dbg(&dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n"); if (errata.piix4.fdma) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Type-F DMA livelock erratum (C3 disabled)\n")); + dev_dbg(&dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n"); return 0; } @@ -157,10 +148,7 @@ static int acpi_processor_errata(void) return result; } -/* -------------------------------------------------------------------------- - Initialization - -------------------------------------------------------------------------- */ - +/* Initialization */ #ifdef CONFIG_ACPI_HOTPLUG_CPU int __weak acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu) @@ -244,11 +232,9 @@ static int acpi_processor_get_info(struct acpi_device *device) */ if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { pr->flags.bm_control = 1; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Bus mastering arbitration control present\n")); + dev_dbg(&device->dev, "Bus mastering arbitration control present\n"); } else - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "No bus mastering arbitration control\n")); + dev_dbg(&device->dev, "No bus mastering arbitration control\n"); if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { /* Declared with "Processor" statement; match ProcessorID */ @@ -291,7 +277,7 @@ static int acpi_processor_get_info(struct acpi_device *device) pr->phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id); if (invalid_phys_cpuid(pr->phys_id)) - acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n"); + dev_dbg(&device->dev, "Failed to get CPU physical ID.\n"); pr->id = acpi_map_cpuid(pr->phys_id, pr->acpi_id); if (!cpu0_initialized && !acpi_has_cpu_in_madt()) { @@ -314,6 +300,7 @@ static int acpi_processor_get_info(struct acpi_device *device) */ if (invalid_logical_cpuid(pr->id) || !cpu_present(pr->id)) { int ret = acpi_processor_hotadd_init(pr); + if (ret) return ret; } @@ -328,11 +315,10 @@ static int acpi_processor_get_info(struct acpi_device *device) * CPU+CPU ID. */ sprintf(acpi_device_bid(device), "CPU%X", pr->id); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, - pr->acpi_id)); + dev_dbg(&device->dev, "Processor [%d:%d]\n", pr->id, pr->acpi_id); if (!object.processor.pblk_address) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); + dev_dbg(&device->dev, "No PBLK (NULL address)\n"); else if (object.processor.pblk_length != 6) dev_err(&device->dev, "Invalid PBLK length [%d]\n", object.processor.pblk_length); @@ -440,10 +426,7 @@ static int acpi_processor_add(struct acpi_device *device, } #ifdef CONFIG_ACPI_HOTPLUG_CPU -/* -------------------------------------------------------------------------- - Removal - -------------------------------------------------------------------------- */ - +/* Removal */ static void acpi_processor_remove(struct acpi_device *device) { struct acpi_processor *pr; @@ -901,7 +884,7 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, info->count = last_index; - end: +end: kfree(buffer.pointer); return ret; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 2ea1781290ccf7697293749ae8c963e7767e0cee..0c884020f74b4759ef1a1cfeded4104b7bbaf7ad 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1392,7 +1392,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, break; } } - /* Ajust level_current to closest available level */ + /* Adjust level_current to closest available level */ level_current += delta; for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { l = device->brightness->levels[i]; @@ -1555,7 +1555,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video, /* * Win8 requires setting bit2 of _DOS to let firmware know it shouldn't - * preform any automatic brightness change on receiving a notification. + * perform any automatic brightness change on receiving a notification. */ static int acpi_video_bus_start_devices(struct acpi_video_bus *video) { @@ -2182,6 +2182,30 @@ static bool dmi_is_desktop(void) return false; } +/* + * We're seeing a lot of bogus backlight interfaces on newer machines + * without a LCD such as desktops, servers and HDMI sticks. Checking the + * lcd flag fixes this, enable this by default on any machines which are: + * 1. Win8 ready (where we also prefer the native backlight driver, so + * normally the acpi_video code should not register there anyways); *and* + * 2.1 Report a desktop/server DMI chassis-type, or + * 2.2 Are an ACPI-reduced-hardware platform (and thus won't use the EC for + backlight control) + */ +static bool should_check_lcd_flag(void) +{ + if (!acpi_osi_is_win8()) + return false; + + if (dmi_is_desktop()) + return true; + + if (acpi_reduced_hardware()) + return true; + + return false; +} + int acpi_video_register(void) { int ret = 0; @@ -2195,19 +2219,8 @@ int acpi_video_register(void) goto leave; } - /* - * We're seeing a lot of bogus backlight interfaces on newer machines - * without a LCD such as desktops, servers and HDMI sticks. Checking - * the lcd flag fixes this, so enable this on any machines which are - * win8 ready (where we also prefer the native backlight driver, so - * normally the acpi_video code should not register there anyways). - */ - if (only_lcd == -1) { - if (dmi_is_desktop() && acpi_osi_is_win8()) - only_lcd = true; - else - only_lcd = false; - } + if (only_lcd == -1) + only_lcd = should_check_lcd_flag(); dmi_check_system(video_dmi_table); diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 15cf904f075190a2470a54e162264b87b9147acb..5951b433c30434bdd7c746b605af2a30028ed67b 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -328,6 +328,17 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_BMS", METHOD_1ARGS(ACPI_TYPE_INTEGER), METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_BPC", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0), + + {{"_BPS", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (5 Int) */ + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0), + + {{"_BPT", METHOD_1ARGS(ACPI_TYPE_PACKAGE), + METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_BQC", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, @@ -347,6 +358,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_CBA", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See PCI firmware spec 3.0 */ + {{"_CBR", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0), + {{"_CCA", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* ACPI 5.1 */ diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index 0cb975a3e01ddc3a10da93c8cfbdb9a1f675b94f..37c47e185fd47ccbceca873daf8fd7f3fade5763 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -46,6 +46,7 @@ typedef enum { ACPI_RSC_1BITFLAG, ACPI_RSC_2BITFLAG, ACPI_RSC_3BITFLAG, + ACPI_RSC_6BITFLAG, ACPI_RSC_ADDRESS, ACPI_RSC_BITMASK, ACPI_RSC_BITMASK16, @@ -102,6 +103,7 @@ typedef enum { ACPI_RSD_1BITFLAG, ACPI_RSD_2BITFLAG, ACPI_RSD_3BITFLAG, + ACPI_RSD_6BITFLAG, ACPI_RSD_ADDRESS, ACPI_RSD_DWORDLIST, ACPI_RSD_LITERAL, @@ -295,6 +297,7 @@ extern struct acpi_rsconvert_info acpi_rs_convert_address64[]; extern struct acpi_rsconvert_info acpi_rs_convert_ext_address64[]; extern struct acpi_rsconvert_info acpi_rs_convert_gpio[]; extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[]; +extern struct acpi_rsconvert_info acpi_rs_convert_csi2_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[]; @@ -349,6 +352,7 @@ extern struct acpi_rsdump_info acpi_rs_dump_gpio[]; extern struct acpi_rsdump_info acpi_rs_dump_pin_function[]; extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[]; extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_csi2_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[]; diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index be6de7149e670aa5bc2f9ff4f329745fd2b579f4..bccae0d3db752b70513dbef510df5855ad95f779 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -28,6 +28,7 @@ extern const char *acpi_gbl_max_decode[]; extern const char *acpi_gbl_mem_decode[]; extern const char *acpi_gbl_min_decode[]; extern const char *acpi_gbl_mtp_decode[]; +extern const char *acpi_gbl_phy_decode[]; extern const char *acpi_gbl_rng_decode[]; extern const char *acpi_gbl_rw_decode[]; extern const char *acpi_gbl_shr_decode[]; diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index a9d91a3c29947691f9bfbb820e38c01d115ed938..b98123210281e6c00f209b138d919babb8803dc0 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -40,6 +40,7 @@ #define ACPI_RESTAG_IORESTRICTION "_IOR" #define ACPI_RESTAG_LENGTH "_LEN" #define ACPI_RESTAG_LINE "_LIN" +#define ACPI_RESTAG_LOCALPORT "_PRT" #define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ #define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ #define ACPI_RESTAG_MAXADDR "_MAX" @@ -49,6 +50,7 @@ #define ACPI_RESTAG_MODE "_MOD" #define ACPI_RESTAG_PARITY "_PAR" #define ACPI_RESTAG_PHASE "_PHA" +#define ACPI_RESTAG_PHYTYPE "_PHY" #define ACPI_RESTAG_PIN "_PIN" #define ACPI_RESTAG_PINCONFIG "_PPI" #define ACPI_RESTAG_PINCONFIG_TYPE "_TYP" @@ -316,12 +318,26 @@ struct aml_resource_gpio { #define AML_RESOURCE_I2C_SERIALBUSTYPE 1 #define AML_RESOURCE_SPI_SERIALBUSTYPE 2 #define AML_RESOURCE_UART_SERIALBUSTYPE 3 -#define AML_RESOURCE_MAX_SERIALBUSTYPE 3 +#define AML_RESOURCE_CSI2_SERIALBUSTYPE 4 +#define AML_RESOURCE_MAX_SERIALBUSTYPE 4 #define AML_RESOURCE_VENDOR_SERIALBUSTYPE 192 /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */ struct aml_resource_common_serialbus { AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON}; +struct aml_resource_csi2_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_CSI2_REVISION 1 /* ACPI 6.4 */ +#define AML_RESOURCE_CSI2_TYPE_REVISION 1 /* ACPI 6.4 */ +#define AML_RESOURCE_CSI2_MIN_DATA_LEN 0 /* ACPI 6.4 */ + struct aml_resource_i2c_serialbus { AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON u32 connection_speed; @@ -510,6 +526,7 @@ union aml_resource { struct aml_resource_i2c_serialbus i2c_serial_bus; struct aml_resource_spi_serialbus spi_serial_bus; struct aml_resource_uart_serialbus uart_serial_bus; + struct aml_resource_csi2_serialbus csi2_serial_bus; struct aml_resource_common_serialbus common_serial_bus; struct aml_resource_pin_function pin_function; struct aml_resource_pin_config pin_config; diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index fcf129d27baa517d0c4099009d8c391f8bcf7647..90583db459a20a0de2ae7df717529ca500cc9075 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -677,10 +677,10 @@ acpi_rs_get_list_length(u8 *aml_buffer, *size_needed += buffer_size; ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Type %.2X, AmlLength %.2X InternalLength %.2X\n", + "Type %.2X, AmlLength %.2X InternalLength %.2X%8X\n", acpi_ut_get_resource_type(aml_buffer), acpi_ut_get_descriptor_length(aml_buffer), - buffer_size)); + ACPI_FORMAT_UINT64(*size_needed))); /* * Point to the next resource within the AML stream using the length diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 6601e71b45e332aa0591218353de7bab43292637..611bc71c193f97c93a3776bd021d3b79f87e3411 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -87,6 +87,9 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list) ("Invalid descriptor type (%X) in resource list\n", resource_list->type); return; + } else if (!resource_list->type) { + ACPI_ERROR((AE_INFO, "Invalid Zero Resource Type")); + return; } /* Sanity check the length. It must not be zero, or we loop forever */ @@ -258,6 +261,11 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) table->pointer[*target & 0x07]); break; + case ACPI_RSD_6BITFLAG: + + acpi_rs_out_integer8(name, (ACPI_GET8(target) & 0x3F)); + break; + case ACPI_RSD_SHORTLIST: /* * Short byte list (single line output) for DMA and IRQ resources diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index cafa8134b4c6f25970c395887749b0fbbcbea5ac..b8b37449011bbcec792d8fbd57bf26b243d1f7a7 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -421,6 +421,32 @@ struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[11] = { ACPI_RS_DUMP_COMMON_SERIAL_BUS }; +struct acpi_rsdump_info acpi_rs_dump_csi2_serial_bus[11] = { + { ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_csi2_serial_bus), + "Camera Serial Bus", NULL }, + { ACPI_RSD_UINT8, ACPI_RSD_OFFSET(csi2_serial_bus.revision_id), + "RevisionId", NULL }, + { ACPI_RSD_UINT8, ACPI_RSD_OFFSET(csi2_serial_bus.type), "Type", + acpi_gbl_sbt_decode }, + { ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(csi2_serial_bus.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode }, + { ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(csi2_serial_bus.slave_mode), + "SlaveMode", acpi_gbl_sm_decode }, + { ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(csi2_serial_bus.phy_type), + "PhyType", acpi_gbl_phy_decode }, + { ACPI_RSD_6BITFLAG, + ACPI_RSD_OFFSET(csi2_serial_bus.local_port_instance), + "LocalPortInstance", NULL }, + { ACPI_RSD_UINT8, ACPI_RSD_OFFSET(csi2_serial_bus.type_revision_id), + "TypeRevisionId", NULL }, + { ACPI_RSD_UINT16, ACPI_RSD_OFFSET(csi2_serial_bus.vendor_length), + "VendorLength", NULL }, + { ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(csi2_serial_bus.vendor_data), + "VendorData", NULL }, + { ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(csi2_serial_bus.resource_source), + "ResourceSource", NULL }, +}; + struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[14] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus), "I2C Serial Bus", NULL}, diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 6e2e596902eb3250d19e1f70d2f2ffad3796cc26..eaeb7ab58c2add6c0b75bc5ffba485d22bafd064 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -96,13 +96,14 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_pin_group_config, /* 0x12, ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG */ }; -/* Subtype table for serial_bus -- I2C, SPI, and UART */ +/* Subtype table for serial_bus -- I2C, SPI, UART, and CSI2 */ struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = { NULL, acpi_rs_convert_i2c_serial_bus, acpi_rs_convert_spi_serial_bus, acpi_rs_convert_uart_serial_bus, + acpi_rs_convert_csi2_serial_bus }; #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER) @@ -142,6 +143,7 @@ struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = { acpi_rs_dump_i2c_serial_bus, /* AML_RESOURCE_I2C_BUS_TYPE */ acpi_rs_dump_spi_serial_bus, /* AML_RESOURCE_SPI_BUS_TYPE */ acpi_rs_dump_uart_serial_bus, /* AML_RESOURCE_UART_BUS_TYPE */ + acpi_rs_dump_csi2_serial_bus, /* AML_RESOURCE_CSI2_BUS_TYPE */ }; #endif @@ -226,6 +228,7 @@ const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = { sizeof(struct aml_resource_i2c_serialbus), sizeof(struct aml_resource_spi_serialbus), sizeof(struct aml_resource_uart_serialbus), + sizeof(struct aml_resource_csi2_serialbus), }; const u8 acpi_gbl_resource_struct_serial_bus_sizes[] = { @@ -233,4 +236,5 @@ const u8 acpi_gbl_resource_struct_serial_bus_sizes[] = { ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), + ACPI_RS_SIZE(struct acpi_resource_csi2_serialbus), }; diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 0307675d37beb8c5ecf7fee11a496450fd69e05f..e46efaa889cdd7c4afa0126bc1feaa5d9f264db7 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -59,7 +59,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, AML_RESOURCE_MAX_SERIALBUSTYPE) { conversion_table = NULL; } else { - /* This is an I2C, SPI, or UART serial_bus descriptor */ + /* This is an I2C, SPI, UART, or CSI2 serial_bus descriptor */ conversion_table = acpi_gbl_convert_resource_serial_bus_dispatch @@ -89,6 +89,11 @@ acpi_rs_convert_aml_to_resources(u8 * aml, return_ACPI_STATUS(status); } + if (!resource->length) { + ACPI_EXCEPTION((AE_INFO, status, + "Zero-length resource returned from RsConvertAmlToResource")); + } + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Type %.2X, AmlLength %.2X InternalLength %.2X\n", acpi_ut_get_resource_type(aml), length, @@ -158,7 +163,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, AML_RESOURCE_MAX_SERIALBUSTYPE) { conversion_table = NULL; } else { - /* This is an I2C, SPI, or UART serial_bus descriptor */ + /* This is an I2C, SPI, UART or CSI2 serial_bus descriptor */ conversion_table = acpi_gbl_convert_resource_serial_bus_dispatch diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 1763a3dbc9b15497cb60c3b210320ed9ed50bb9d..c2dd9aae474591bcc4401c843086be59704ae493 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -70,6 +70,8 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, */ count = INIT_TABLE_LENGTH(info); while (count) { + target = NULL; + /* * Source is the external AML byte stream buffer, * destination is the internal resource descriptor @@ -120,6 +122,14 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, ((ACPI_GET8(source) >> info->value) & 0x07)); break; + case ACPI_RSC_6BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8(destination, + ((ACPI_GET8(source) >> info->value) & 0x3F)); + break; + case ACPI_RSC_COUNT: item_count = ACPI_GET8(source); @@ -509,6 +519,15 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, value)); break; + case ACPI_RSC_6BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) + ((ACPI_GET8(source) & 0x3F) << info-> + value)); + break; + case ACPI_RSC_COUNT: item_count = ACPI_GET8(source); diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index 1b937d88980f3bd92bebdccd5a7ef272b26f867b..f9267956535c3cba43d01bfd14b87eaeefdd7228 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -185,6 +185,81 @@ struct acpi_rsconvert_info acpi_rs_convert_pin_function[13] = { 0}, }; +/******************************************************************************* + * + * acpi_rs_convert_csi2_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_csi2_serial_bus[14] = { + { ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_csi2_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_csi2_serial_bus) }, + + { ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_csi2_serialbus), + 0 }, + + { ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1 }, + + { ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.csi2_serial_bus.type), + AML_OFFSET(csi2_serial_bus.type), + 1 }, + + { ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.csi2_serial_bus.producer_consumer), + AML_OFFSET(csi2_serial_bus.flags), + 1 }, + + { ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.csi2_serial_bus.slave_mode), + AML_OFFSET(csi2_serial_bus.flags), + 0 }, + + { ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.csi2_serial_bus.phy_type), + AML_OFFSET(csi2_serial_bus.type_specific_flags), + 0 }, + + { ACPI_RSC_6BITFLAG, + ACPI_RS_OFFSET(data.csi2_serial_bus.local_port_instance), + AML_OFFSET(csi2_serial_bus.type_specific_flags), + 2 }, + + { ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.csi2_serial_bus.type_revision_id), + AML_OFFSET(csi2_serial_bus.type_revision_id), + 1 }, + + /* Vendor data */ + + { ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.csi2_serial_bus.vendor_length), + AML_OFFSET(csi2_serial_bus.type_data_length), + AML_RESOURCE_CSI2_MIN_DATA_LEN }, + + { ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.csi2_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_csi2_serialbus) }, + + /* Resource Source */ + + { ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.csi2_serial_bus.resource_source.index), + AML_OFFSET(csi2_serial_bus.res_source_index), + 1 }, + + { ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.csi2_serial_bus.resource_source.string_length), + AML_OFFSET(csi2_serial_bus.type_data_length), + sizeof(struct aml_resource_csi2_serialbus) }, + + { ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.csi2_serial_bus.resource_source.string_ptr), + AML_OFFSET(csi2_serial_bus.type_data_length), + sizeof(struct aml_resource_csi2_serialbus) }, +}; + /******************************************************************************* * * acpi_rs_convert_i2c_serial_bus diff --git a/drivers/acpi/acpica/utresdecode.c b/drivers/acpi/acpica/utresdecode.c index 0a9c337346e8b8e50f9e226207b84fa88069d864..85730fcd7d006b31dc41457b1852f749577cb4c3 100644 --- a/drivers/acpi/acpica/utresdecode.c +++ b/drivers/acpi/acpica/utresdecode.c @@ -82,6 +82,13 @@ const char *acpi_gbl_mtp_decode[] = { "AddressRangeNVS" }; +const char *acpi_gbl_phy_decode[] = { + "Type C", + "Type D", + "Unknown Type", + "Unknown Type" +}; + const char *acpi_gbl_rng_decode[] = { "InvalidRanges", "NonISAOnlyRanges", @@ -161,7 +168,8 @@ const char *acpi_gbl_sbt_decode[] = { "/* UNKNOWN serial bus type */", "I2C", "SPI", - "UART" + "UART", + "CSI2" }; /* I2C serial bus access mode */ diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index cba5505171dac30730bf26e8c80a31f3af0d73a5..16f9a7035b39c68d38087df3ee3927785f817c62 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -64,6 +64,7 @@ const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus), ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus), ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_csi2_serialbus), }; /* diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 1331567595512f7ddc6b880a0d1e7ffd499677e1..328e8aeece6c5509cd6f7789591b15c2621dba73 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -725,7 +725,6 @@ static int __init einj_init(void) goto err_release; } - rc = -ENOMEM; einj_param = einj_get_parameter_address(); if ((param_extension || acpi5) && einj_param) { debugfs_create_x32("flags", S_IRUSR | S_IWUSR, einj_debug_dir, diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index b9597216d0211e803cdde18468f2e4065064676c..242f3c2d553309a214abb69aca2d460b9c470853 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(erst_disable); static struct acpi_table_erst *erst_tab; -/* ERST Error Log Address Range atrributes */ +/* ERST Error Log Address Range attributes */ #define ERST_RANGE_RESERVED 0x0001 #define ERST_RANGE_NVRAM 0x0002 #define ERST_RANGE_SLOW 0x0004 diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index f220bb00e91b6200dbd69c2bd29915d9cafb6e2b..277f00b288d143cfffabfa2faefec9968073058c 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * APEI Hardware Error Souce Table support + * APEI Hardware Error Source Table support * * HEST describes error sources in detail; communicates operational * parameters (i.e. severity levels, masking bits, and threshold diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b822f77afba602b9f9cac3bf2511b75497213d1c..dae91f906cea97059790ea8c23f63e8d5372cd7d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -74,16 +74,17 @@ enum { ACPI_BATTERY_XINFO_PRESENT, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, /* On Lenovo Thinkpad models from 2010 and 2011, the power unit - switches between mWh and mAh depending on whether the system - is running on battery or not. When mAh is the unit, most - reported values are incorrect and need to be adjusted by - 10000/design_voltage. Verified on x201, t410, t410s, and x220. - Pre-2010 and 2012 models appear to always report in mWh and - are thus unaffected (tested with t42, t61, t500, x200, x300, - and x230). Also, in mid-2012 Lenovo issued a BIOS update for - the 2011 models that fixes the issue (tested on x220 with a - post-1.29 BIOS), but as of Nov. 2012, no such update is - available for the 2010 models. */ + * switches between mWh and mAh depending on whether the system + * is running on battery or not. When mAh is the unit, most + * reported values are incorrect and need to be adjusted by + * 10000/design_voltage. Verified on x201, t410, t410s, and x220. + * Pre-2010 and 2012 models appear to always report in mWh and + * are thus unaffected (tested with t42, t61, t500, x200, x300, + * and x230). Also, in mid-2012 Lenovo issued a BIOS update for + * the 2011 models that fixes the issue (tested on x220 with a + * post-1.29 BIOS), but as of Nov. 2012, no such update is + * available for the 2010 models. + */ ACPI_BATTERY_QUIRK_THINKPAD_MAH, /* for batteries reporting current capacity with design capacity * on a full charge, but showing degradation in full charge cap. @@ -371,9 +372,7 @@ static enum power_supply_property energy_battery_full_cap_broken_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; -/* -------------------------------------------------------------------------- - Battery Management - -------------------------------------------------------------------------- */ +/* Battery Management */ struct acpi_offsets { size_t offset; /* offset inside struct acpi_sbs_battery */ u8 mode; /* int or string? */ @@ -431,6 +430,7 @@ static int extract_package(struct acpi_battery *battery, { int i; union acpi_object *element; + if (package->type != ACPI_TYPE_PACKAGE) return -EFAULT; for (i = 0; i < num; ++i) { @@ -439,6 +439,7 @@ static int extract_package(struct acpi_battery *battery, element = &package->package.elements[i]; if (offsets[i].mode) { u8 *ptr = (u8 *)battery + offsets[i].offset; + if (element->type == ACPI_TYPE_STRING || element->type == ACPI_TYPE_BUFFER) strncpy(ptr, element->string.pointer, 32); @@ -497,10 +498,12 @@ static int extract_battery_info(const int use_bix, battery->design_capacity_warning * 10000 / battery->design_voltage; /* Curiously, design_capacity_low, unlike the rest of them, - is correct. */ + * is correct. + */ /* capacity_granularity_* equal 1 on the systems tested, so - it's impossible to tell if they would need an adjustment - or not if their values were higher. */ + * it's impossible to tell if they would need an adjustment + * or not if their values were higher. + */ } if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags) && battery->capacity_now > battery->full_charge_capacity) @@ -532,8 +535,8 @@ static int acpi_battery_get_info(struct acpi_battery *battery) if (ACPI_FAILURE(status)) { acpi_handle_info(battery->device->handle, "%s evaluation failed: %s\n", - use_bix ?"_BIX":"_BIF", - acpi_format_exception(status)); + use_bix ? "_BIX":"_BIF", + acpi_format_exception(status)); } else { result = extract_battery_info(use_bix, battery, @@ -648,6 +651,7 @@ static ssize_t acpi_battery_alarm_show(struct device *dev, char *buf) { struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + return sprintf(buf, "%d\n", battery->alarm * 1000); } @@ -657,6 +661,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm = x/1000; if (acpi_battery_present(battery)) @@ -743,7 +748,7 @@ EXPORT_SYMBOL_GPL(battery_hook_register); * This function gets called right after the battery sysfs * attributes have been added, so that the drivers that * define custom sysfs attributes can add their own. -*/ + */ static void battery_hook_add_battery(struct acpi_battery *battery) { struct acpi_battery_hook *hook_node, *tmp; @@ -872,10 +877,12 @@ static void find_battery(const struct dmi_header *dm, void *private) { struct acpi_battery *battery = (struct acpi_battery *)private; /* Note: the hardcoded offsets below have been extracted from - the source code of dmidecode. */ + * the source code of dmidecode. + */ if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) { const u8 *dmi_data = (const u8 *)(dm + 1); int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6)); + if (dm->length >= 18) dmi_capacity *= dmi_data[17]; if (battery->design_capacity * battery->design_voltage / 1000 @@ -917,6 +924,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery) if (battery->power_unit && dmi_name_in_vendors("LENOVO")) { const char *s; + s = dmi_get_system_info(DMI_PRODUCT_VERSION); if (s && !strncasecmp(s, "ThinkPad", 8)) { dmi_walk(find_battery, battery); @@ -1013,10 +1021,7 @@ static void acpi_battery_refresh(struct acpi_battery *battery) sysfs_add_battery(battery); } -/* -------------------------------------------------------------------------- - Driver Interface - -------------------------------------------------------------------------- */ - +/* Driver Interface */ static void acpi_battery_notify(struct acpi_device *device, u32 event) { struct acpi_battery *battery = acpi_driver_data(device); @@ -1026,11 +1031,11 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) return; old = battery->bat; /* - * On Acer Aspire V5-573G notifications are sometimes triggered too - * early. For example, when AC is unplugged and notification is - * triggered, battery state is still reported as "Full", and changes to - * "Discharging" only after short delay, without any notification. - */ + * On Acer Aspire V5-573G notifications are sometimes triggered too + * early. For example, when AC is unplugged and notification is + * triggered, battery state is still reported as "Full", and changes to + * "Discharging" only after short delay, without any notification. + */ if (battery_notification_delay_ms > 0) msleep(battery_notification_delay_ms); if (event == ACPI_BATTERY_NOTIFY_INFO) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 85e5e0328a2e4beaa74896cbae077325e0b13f5d..f25bd336113bd6f3676cd9f2be849cbd15821316 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -156,10 +156,7 @@ static unsigned long lid_report_interval __read_mostly = 500; module_param(lid_report_interval, ulong, 0644); MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events"); -/* -------------------------------------------------------------------------- - FS Interface (/proc) - -------------------------------------------------------------------------- */ - +/* FS Interface (/proc) */ static struct proc_dir_entry *acpi_button_dir; static struct proc_dir_entry *acpi_lid_dir; @@ -348,9 +345,7 @@ static int acpi_button_remove_fs(struct acpi_device *device) return 0; } -/* -------------------------------------------------------------------------- - Driver Interface - -------------------------------------------------------------------------- */ +/* Driver Interface */ int acpi_lid_open(void) { if (!lid_device) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 69057fcd2c047fa50e6c5c93f8564bd2f5a5c875..a4d4eebba1da422b2ef0c0236f424da4fa0ad783 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -33,7 +33,6 @@ #define pr_fmt(fmt) "ACPI CPPC: " fmt -#include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/iopoll.h> #include <linux/ktime.h> @@ -101,14 +100,14 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); (cpc)->cpc_entry.reg.space_id == \ ACPI_ADR_SPACE_PLATFORM_COMM) -/* Evalutes to True if reg is a NULL register descriptor */ +/* Evaluates to True if reg is a NULL register descriptor */ #define IS_NULL_REG(reg) ((reg)->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY && \ (reg)->address == 0 && \ (reg)->bit_width == 0 && \ (reg)->bit_offset == 0 && \ (reg)->access_width == 0) -/* Evalutes to True if an optional cpc field is supported */ +/* Evaluates to True if an optional cpc field is supported */ #define CPC_SUPPORTED(cpc) ((cpc)->type == ACPI_TYPE_INTEGER ? \ !!(cpc)->cpc_entry.int_value : \ !IS_NULL_REG(&(cpc)->cpc_entry.reg)) @@ -119,23 +118,15 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); */ #define NUM_RETRIES 500ULL -struct cppc_attr { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, - struct attribute *attr, char *buf); - ssize_t (*store)(struct kobject *kobj, - struct attribute *attr, const char *c, ssize_t count); -}; - #define define_one_cppc_ro(_name) \ -static struct cppc_attr _name = \ +static struct kobj_attribute _name = \ __ATTR(_name, 0444, show_##_name, NULL) #define to_cpc_desc(a) container_of(a, struct cpc_desc, kobj) #define show_cppc_data(access_fn, struct_name, member_name) \ static ssize_t show_##member_name(struct kobject *kobj, \ - struct attribute *attr, char *buf) \ + struct kobj_attribute *attr, char *buf) \ { \ struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); \ struct struct_name st_name = {0}; \ @@ -161,7 +152,7 @@ show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); static ssize_t show_feedback_ctrs(struct kobject *kobj, - struct attribute *attr, char *buf) + struct kobj_attribute *attr, char *buf) { struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); struct cppc_perf_fb_ctrs fb_ctrs = {0}; @@ -327,6 +318,7 @@ end: if (unlikely(ret)) { for_each_possible_cpu(i) { struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i); + if (!desc) continue; @@ -778,7 +770,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER; memcpy(&cpc_ptr->cpc_regs[i-2].cpc_entry.reg, gas_t, sizeof(*gas_t)); } else { - pr_debug("Err in entry:%d in CPC table of CPU:%d \n", i, pr->id); + pr_debug("Err in entry:%d in CPC table of CPU:%d\n", i, pr->id); goto out_free; } } @@ -868,7 +860,7 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr) void __iomem *addr; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, pr->id); - if (pcc_ss_id >=0 && pcc_data[pcc_ss_id]) { + if (pcc_ss_id >= 0 && pcc_data[pcc_ss_id]) { if (pcc_data[pcc_ss_id]->pcc_channel_acquired) { pcc_data[pcc_ss_id]->refcount--; if (!pcc_data[pcc_ss_id]->refcount) { @@ -955,22 +947,22 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) val, reg->bit_width); switch (reg->bit_width) { - case 8: - *val = readb_relaxed(vaddr); - break; - case 16: - *val = readw_relaxed(vaddr); - break; - case 32: - *val = readl_relaxed(vaddr); - break; - case 64: - *val = readq_relaxed(vaddr); - break; - default: - pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n", - reg->bit_width, pcc_ss_id); - ret_val = -EFAULT; + case 8: + *val = readb_relaxed(vaddr); + break; + case 16: + *val = readw_relaxed(vaddr); + break; + case 32: + *val = readl_relaxed(vaddr); + break; + case 64: + *val = readq_relaxed(vaddr); + break; + default: + pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n", + reg->bit_width, pcc_ss_id); + ret_val = -EFAULT; } return ret_val; @@ -994,23 +986,23 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) val, reg->bit_width); switch (reg->bit_width) { - case 8: - writeb_relaxed(val, vaddr); - break; - case 16: - writew_relaxed(val, vaddr); - break; - case 32: - writel_relaxed(val, vaddr); - break; - case 64: - writeq_relaxed(val, vaddr); - break; - default: - pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n", - reg->bit_width, pcc_ss_id); - ret_val = -EFAULT; - break; + case 8: + writeb_relaxed(val, vaddr); + break; + case 16: + writew_relaxed(val, vaddr); + break; + case 32: + writel_relaxed(val, vaddr); + break; + case 64: + writeq_relaxed(val, vaddr); + break; + default: + pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n", + reg->bit_width, pcc_ss_id); + ret_val = -EFAULT; + break; } return ret_val; @@ -1330,7 +1322,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * is still with OSPM. * pending_pcc_write_cmd can also be cleared by a different CPU, if * there was a pcc CMD_READ waiting on down_write and it steals the lock - * before the pcc CMD_WRITE is completed. pcc_send_cmd checks for this + * before the pcc CMD_WRITE is completed. send_pcc_cmd checks for this * case during a CMD_READ and if there are pending writes it delivers * the write command before servicing the read command */ @@ -1355,8 +1347,8 @@ EXPORT_SYMBOL_GPL(cppc_set_perf); /** * cppc_get_transition_latency - returns frequency transition latency in ns * - * ACPI CPPC does not explicitly specifiy how a platform can specify the - * transition latency for perfromance change requests. The closest we have + * ACPI CPPC does not explicitly specify how a platform can specify the + * transition latency for performance change requests. The closest we have * is the timing information from the PCCT tables which provides the info * on the number and frequency of PCC commands the platform can handle. */ diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index 7b54dc95d36b3171035ed6642d42c8605ce67869..443fdf62dd227034a2eb0159314fff31fdd6c2a0 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -19,7 +19,7 @@ static struct dentry *cm_dentry; /* /sys/kernel/debug/acpi/custom_method */ -static ssize_t cm_write(struct file *file, const char __user * user_buf, +static ssize_t cm_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { static char *buf; diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 096153761ebc35d01c565a4b7aa71d909a274612..16c0fe8a72a7ffa788d733d969141634d8102c3b 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -966,6 +966,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume); int acpi_subsys_runtime_suspend(struct device *dev) { int ret = pm_generic_runtime_suspend(dev); + return ret ? ret : acpi_dev_suspend(dev, true); } EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend); @@ -980,6 +981,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend); int acpi_subsys_runtime_resume(struct device *dev) { int ret = acpi_dev_resume(dev); + return ret ? ret : pm_generic_runtime_resume(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); @@ -1171,6 +1173,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze); int acpi_subsys_restore_early(struct device *dev) { int ret = acpi_dev_resume(dev); + return ret ? ret : pm_generic_restore_early(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_restore_early); diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index da4ff2a8b06a00f99478766bface964fbb4fe06e..fa2c1c93072cf44b292512c53926d49659ad08c3 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -73,6 +73,7 @@ static const struct sysfs_ops acpi_data_node_sysfs_ops = { static void acpi_data_node_release(struct kobject *kobj) { struct acpi_data_node *dn = to_data_node(kobj); + complete(&dn->kobj_done); } @@ -130,7 +131,7 @@ static void acpi_hide_nondev_subnodes(struct acpi_device_data *data) * Return: 0: no _HID and no _CID * -EINVAL: output error * -ENOMEM: output is truncated -*/ + */ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, int size) { @@ -376,12 +377,12 @@ eject_store(struct device *d, struct device_attribute *attr, if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) return -ENODEV; - get_device(&acpi_device->dev); + acpi_dev_get(acpi_device); status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT); if (ACPI_SUCCESS(status)) return count; - put_device(&acpi_device->dev); + acpi_dev_put(acpi_device); acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; @@ -431,7 +432,8 @@ static DEVICE_ATTR_RO(path); /* sysfs file that shows description text from the ACPI _STR method */ static ssize_t description_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct acpi_device *acpi_dev = to_acpi_device(dev); int result; @@ -456,7 +458,8 @@ static DEVICE_ATTR_RO(description); static ssize_t sun_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct acpi_device *acpi_dev = to_acpi_device(dev); acpi_status status; unsigned long long sun; @@ -471,7 +474,8 @@ static DEVICE_ATTR_RO(sun); static ssize_t hrv_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct acpi_device *acpi_dev = to_acpi_device(dev); acpi_status status; unsigned long long hrv; @@ -485,7 +489,8 @@ hrv_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(hrv); static ssize_t status_show(struct device *dev, struct device_attribute *attr, - char *buf) { + char *buf) +{ struct acpi_device *acpi_dev = to_acpi_device(dev); acpi_status status; unsigned long long sta; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 0937ceab052e89f90009c519339354f6a8a7d0ae..7cf92158008fa687296f807c7c6695ba25c96457 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -271,6 +271,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) if (!acpi_device_enumerated(adev)) { int ret = acpi_bus_scan(adev->handle); + if (ret) dev_dbg(&adev->dev, "scan error %d\n", -ret); } @@ -502,6 +503,7 @@ static ssize_t flags_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dock_station *dock_station = dev->platform_data; + return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); } @@ -523,7 +525,7 @@ static ssize_t undock_store(struct device *dev, struct device_attribute *attr, begin_undock(dock_station); ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); acpi_scan_lock_release(); - return ret ? ret: count; + return ret ? ret : count; } static DEVICE_ATTR_WO(undock); @@ -535,10 +537,11 @@ static ssize_t uid_show(struct device *dev, { unsigned long long lbuf; struct dock_station *dock_station = dev->platform_data; + acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); if (ACPI_FAILURE(status)) - return 0; + return 0; return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf); } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 36b24b0658cb789ba2471298bb16bb55352845a5..0715e3be99a0be9b16a937d4bd98d3ec6cd646f7 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -190,7 +190,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) if (!acpi_dev) return -EINVAL; - get_device(&acpi_dev->dev); + acpi_dev_get(acpi_dev); get_device(dev); physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL); if (!physical_node) { @@ -217,7 +217,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) goto err; put_device(dev); - put_device(&acpi_dev->dev); + acpi_dev_put(acpi_dev); return 0; } if (pn->node_id == node_id) { @@ -257,7 +257,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) err: ACPI_COMPANION_SET(dev, NULL); put_device(dev); - put_device(&acpi_dev->dev); + acpi_dev_put(acpi_dev); return retval; } EXPORT_SYMBOL_GPL(acpi_bind_one); @@ -285,7 +285,7 @@ int acpi_unbind_one(struct device *dev) ACPI_COMPANION_SET(dev, NULL); /* Drop references taken by acpi_bind_one(). */ put_device(dev); - put_device(&acpi_dev->dev); + acpi_dev_put(acpi_dev); kfree(entry); break; } diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index cf148287e2baf542f6d65546193e7728989119c6..60a2939cde6c500d9946f20be336a635e6979f51 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -74,7 +74,6 @@ static struct acpi_driver acpi_hed_driver = { }; module_acpi_driver(acpi_hed_driver); -ACPI_MODULE_NAME("hed"); MODULE_AUTHOR("Huang Ying"); MODULE_DESCRIPTION("ACPI Hardware Error Device Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index cb8f70842249e3cb9da68e0fe9de903a91203498..f973bbe90e5eeea7e3a195d8803bdfa0ed99a813 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -109,8 +109,7 @@ struct acpi_device_bus_id { int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, - int type, unsigned long long sta, - struct acpi_device_info *info); + int type); int acpi_device_setup_files(struct acpi_device *dev); void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_add_finalize(struct acpi_device *device); @@ -143,6 +142,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev, int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +void acpi_turn_off_unused_power_resources(void); /* -------------------------------------------------------------------------- Device Power Management diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 8c5dde628405a8b6900daaaa03bb070b3685804c..958aaac869e8d2f9440f33f12a8bf4d68053608f 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1195,7 +1195,8 @@ static int __nfit_mem_init(struct acpi_nfit_desc *acpi_desc, return 0; } -static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b) +static int nfit_mem_cmp(void *priv, const struct list_head *_a, + const struct list_head *_b) { struct nfit_mem *a = container_of(_a, typeof(*a), list); struct nfit_mem *b = container_of(_b, typeof(*b), list); @@ -3831,7 +3832,7 @@ static __init int nfit_init(void) int ret; BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40); - BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56); + BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 64); BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48); BUILD_BUG_ON(sizeof(struct acpi_nfit_interleave) != 20); BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9); diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index cb73a5d6ea76da0b0790b7ba6d81c7bcd7626704..c3d783aca196ff5aec773b1c8734b54ef55f6429 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -558,7 +558,8 @@ static bool hmat_update_best(u8 type, u32 value, u32 *best) return updated; } -static int initiator_cmp(void *priv, struct list_head *a, struct list_head *b) +static int initiator_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct memory_initiator *ia; struct memory_initiator *ib; @@ -722,7 +723,7 @@ static void hmat_register_target(struct memory_target *target) /* * Skip offline nodes. This can happen when memory * marked EFI_MEMORY_SP, "specific purpose", is applied - * to all the memory in a promixity domain leading to + * to all the memory in a proximity domain leading to * the node being marked offline / unplugged, or if * memory-only "hotplug" node is offline. */ diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 14ee631cb7cf121b673829120bb221ee369d8b6f..08e15774fb9f99703c32502affbb151cc76f2e18 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -9,6 +9,7 @@ * Bjorn Helgaas <bjorn.helgaas@hp.com> */ +#define pr_fmt(fmt) "ACPI: PCI: " fmt #include <linux/dmi.h> #include <linux/kernel.h> @@ -22,11 +23,6 @@ #include <linux/slab.h> #include <linux/interrupt.h> -#define PREFIX "ACPI: " - -#define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_irq"); - struct acpi_prt_entry { struct acpi_pci_id id; u8 pin; @@ -126,7 +122,7 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, entry->pin == quirk->pin && !strcmp(prt->source, quirk->source) && strlen(prt->source) >= strlen(quirk->actual_source)) { - printk(KERN_WARNING PREFIX "firmware reports " + pr_warn("Firmware reports " "%04x:%02x:%02x PCI INT %c connected to %s; " "changing to %s\n", entry->id.segment, entry->id.bus, @@ -191,12 +187,9 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev, * the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ - - ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, - " %04x:%02x:%02x[%c] -> %s[%d]\n", - entry->id.segment, entry->id.bus, - entry->id.device, pin_name(entry->pin), - prt->source, entry->index)); + pr_debug("%04x:%02x:%02x[%c] -> %s[%d]\n", + entry->id.segment, entry->id.bus, entry->id.device, + pin_name(entry->pin), prt->source, entry->index); *entry_ptr = entry; @@ -307,8 +300,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) #ifdef CONFIG_X86_IO_APIC acpi_reroute_boot_interrupt(dev, entry); #endif /* CONFIG_X86_IO_APIC */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", - pci_name(dev), pin_name(pin))); + dev_dbg(&dev->dev, "Found [%c] _PRT entry\n", pin_name(pin)); return entry; } @@ -324,9 +316,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) /* PC card has the same IRQ as its cardbridge */ bridge_pin = bridge->pin; if (!bridge_pin) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "No interrupt pin configured for device %s\n", - pci_name(bridge))); + dev_dbg(&bridge->dev, "No interrupt pin configured\n"); return NULL; } pin = bridge_pin; @@ -334,10 +324,8 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry); if (!ret && entry) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Derived GSI for %s INT %c from %s\n", - pci_name(dev), pin_name(orig_pin), - pci_name(bridge))); + dev_dbg(&dev->dev, "Derived GSI INT %c from %s\n", + pin_name(orig_pin), pci_name(bridge)); return entry; } @@ -413,9 +401,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pin = dev->pin; if (!pin) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "No interrupt pin configured for device %s\n", - pci_name(dev))); + dev_dbg(&dev->dev, "No interrupt pin configured\n"); return 0; } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index fb4c5632a232bf6a2c1d60a4639c5f9842ef3d2e..cb7b900d9466c84fa01b7d680936f0233a4fde7e 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -12,6 +12,8 @@ * for IRQ management (e.g. start()->_SRS). */ +#define pr_fmt(fmt) "ACPI: PCI: " fmt + #include <linux/syscore_ops.h> #include <linux/kernel.h> #include <linux/module.h> @@ -27,8 +29,6 @@ #include "internal.h" -#define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" #define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" #define ACPI_PCI_LINK_MAX_POSSIBLE 16 @@ -85,6 +85,7 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, void *context) { struct acpi_pci_link *link = context; + acpi_handle handle = link->device->handle; u32 i; switch (resource->type) { @@ -95,17 +96,17 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, { struct acpi_resource_irq *p = &resource->data.irq; if (!p || !p->interrupt_count) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Blank _PRS IRQ resource\n")); + acpi_handle_debug(handle, + "Blank _PRS IRQ resource\n"); return AE_OK; } for (i = 0; (i < p->interrupt_count && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { if (!p->interrupts[i]) { - printk(KERN_WARNING PREFIX - "Invalid _PRS IRQ %d\n", - p->interrupts[i]); + acpi_handle_debug(handle, + "Invalid _PRS IRQ %d\n", + p->interrupts[i]); continue; } link->irq.possible[i] = p->interrupts[i]; @@ -121,17 +122,17 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, struct acpi_resource_extended_irq *p = &resource->data.extended_irq; if (!p || !p->interrupt_count) { - printk(KERN_WARNING PREFIX - "Blank _PRS EXT IRQ resource\n"); + acpi_handle_debug(handle, + "Blank _PRS EXT IRQ resource\n"); return AE_OK; } for (i = 0; (i < p->interrupt_count && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { if (!p->interrupts[i]) { - printk(KERN_WARNING PREFIX - "Invalid _PRS IRQ %d\n", - p->interrupts[i]); + acpi_handle_debug(handle, + "Invalid _PRS IRQ %d\n", + p->interrupts[i]); continue; } link->irq.possible[i] = p->interrupts[i]; @@ -143,8 +144,8 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, break; } default: - printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n", - resource->type); + acpi_handle_debug(handle, "_PRS resource type 0x%x is not IRQ\n", + resource->type); return AE_OK; } @@ -153,18 +154,18 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, static int acpi_pci_link_get_possible(struct acpi_pci_link *link) { + acpi_handle handle = link->device->handle; acpi_status status; - status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS, + status = acpi_walk_resources(handle, METHOD_NAME__PRS, acpi_pci_link_check_possible, link); if (ACPI_FAILURE(status)) { - acpi_handle_debug(link->device->handle, "_PRS not present or invalid"); + acpi_handle_debug(handle, "_PRS not present or invalid"); return 0; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found %d possible IRQs\n", - link->irq.possible_count)); + acpi_handle_debug(handle, "Found %d possible IRQs\n", + link->irq.possible_count); return 0; } @@ -186,8 +187,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource, * IRQ descriptors may have no IRQ# bits set, * particularly those those w/ _STA disabled */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Blank _CRS IRQ resource\n")); + pr_debug("Blank _CRS IRQ resource\n"); return AE_OK; } *irq = p->interrupts[0]; @@ -202,8 +202,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource, * extended IRQ descriptors must * return at least 1 IRQ */ - printk(KERN_WARNING PREFIX - "Blank _CRS EXT IRQ resource\n"); + pr_debug("Blank _CRS EXT IRQ resource\n"); return AE_OK; } *irq = p->interrupts[0]; @@ -211,8 +210,8 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource, } break; default: - printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n", - resource->type); + pr_debug("_CRS resource type 0x%x is not IRQ\n", + resource->type); return AE_OK; } @@ -228,8 +227,9 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource, */ static int acpi_pci_link_get_current(struct acpi_pci_link *link) { - int result = 0; + acpi_handle handle = link->device->handle; acpi_status status; + int result = 0; int irq = 0; link->irq.active = 0; @@ -239,12 +239,12 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link) /* Query _STA, set link->device->status */ result = acpi_bus_get_status(link->device); if (result) { - printk(KERN_ERR PREFIX "Unable to read status\n"); + acpi_handle_err(handle, "Unable to read status\n"); goto end; } if (!link->device->status.enabled) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); + acpi_handle_debug(handle, "Link disabled\n"); return 0; } } @@ -253,22 +253,22 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link) * Query and parse _CRS to get the current IRQ assignment. */ - status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS, + status = acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_pci_link_check_current, &irq); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS")); + acpi_evaluation_failure_warn(handle, "_CRS", status); result = -ENODEV; goto end; } if (acpi_strict && !irq) { - printk(KERN_ERR PREFIX "_CRS returned 0\n"); + acpi_handle_err(handle, "_CRS returned 0\n"); result = -ENODEV; } link->irq.active = irq; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); + acpi_handle_debug(handle, "Link at IRQ %d \n", link->irq.active); end: return result; @@ -276,13 +276,14 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link) static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) { - int result; - acpi_status status; struct { struct acpi_resource res; struct acpi_resource end; } *resource; struct acpi_buffer buffer = { 0, NULL }; + acpi_handle handle = link->device->handle; + acpi_status status; + int result; if (!irq) return -EINVAL; @@ -329,7 +330,8 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) /* ignore resource_source, it's optional */ break; default: - printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type); + acpi_handle_err(handle, "Invalid resource type %d\n", + link->irq.resource_type); result = -EINVAL; goto end; @@ -342,7 +344,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) /* check for total failure */ if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS")); + acpi_evaluation_failure_warn(handle, "_SRS", status); result = -ENODEV; goto end; } @@ -350,15 +352,11 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) /* Query _STA, set device->status */ result = acpi_bus_get_status(link->device); if (result) { - printk(KERN_ERR PREFIX "Unable to read status\n"); + acpi_handle_err(handle, "Unable to read status\n"); goto end; } - if (!link->device->status.enabled) { - printk(KERN_WARNING PREFIX - "%s [%s] disabled and referenced, BIOS bug\n", - acpi_device_name(link->device), - acpi_device_bid(link->device)); - } + if (!link->device->status.enabled) + acpi_handle_warn(handle, "Disabled and referenced, BIOS bug\n"); /* Query _CRS, set link->irq.active */ result = acpi_pci_link_get_current(link); @@ -375,14 +373,12 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) * policy: when _CRS doesn't return what we just _SRS * assume _SRS worked and override _CRS value. */ - printk(KERN_WARNING PREFIX - "%s [%s] BIOS reported IRQ %d, using IRQ %d\n", - acpi_device_name(link->device), - acpi_device_bid(link->device), link->irq.active, irq); + acpi_handle_warn(handle, "BIOS reported IRQ %d, using IRQ %d\n", + link->irq.active, irq); link->irq.active = irq; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); + acpi_handle_debug(handle, "Set IRQ %d\n", link->irq.active); end: kfree(resource); @@ -531,6 +527,7 @@ static int acpi_irq_balance = -1; /* 0: static, 1: balance */ static int acpi_pci_link_allocate(struct acpi_pci_link *link) { + acpi_handle handle = link->device->handle; int irq; int i; @@ -553,8 +550,8 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) */ if (i == link->irq.possible_count) { if (acpi_strict) - printk(KERN_WARNING PREFIX "_CRS %d not found" - " in _PRS\n", link->irq.active); + acpi_handle_warn(handle, "_CRS %d not found in _PRS\n", + link->irq.active); link->irq.active = 0; } @@ -578,28 +575,23 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) } } if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) { - printk(KERN_ERR PREFIX "No IRQ available for %s [%s]. " - "Try pci=noacpi or acpi=off\n", - acpi_device_name(link->device), - acpi_device_bid(link->device)); + acpi_handle_err(handle, + "No IRQ available. Try pci=noacpi or acpi=off\n"); return -ENODEV; } /* Attempt to enable the link device at this IRQ. */ if (acpi_pci_link_set(link, irq)) { - printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. " - "Try pci=noacpi or acpi=off\n", - acpi_device_name(link->device), - acpi_device_bid(link->device)); + acpi_handle_err(handle, + "Unable to set IRQ. Try pci=noacpi or acpi=off\n"); return -ENODEV; } else { if (link->irq.active < ACPI_MAX_ISA_IRQS) acpi_isa_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; - pr_info("%s [%s] enabled at IRQ %d\n", - acpi_device_name(link->device), - acpi_device_bid(link->device), link->irq.active); + acpi_handle_info(handle, "Enabled at IRQ %d\n", + link->irq.active); } link->irq.initialized = 1; @@ -620,19 +612,19 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, result = acpi_bus_get_device(handle, &device); if (result) { - printk(KERN_ERR PREFIX "Invalid link device\n"); + acpi_handle_err(handle, "Invalid link device\n"); return -1; } link = acpi_driver_data(device); if (!link) { - printk(KERN_ERR PREFIX "Invalid link context\n"); + acpi_handle_err(handle, "Invalid link context\n"); return -1; } /* TBD: Support multiple index (IRQ) entries per Link Device */ if (index) { - printk(KERN_ERR PREFIX "Invalid index %d\n", index); + acpi_handle_err(handle, "Invalid index %d\n", index); return -1; } @@ -644,7 +636,7 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, if (!link->irq.active) { mutex_unlock(&acpi_link_lock); - printk(KERN_ERR PREFIX "Link active IRQ is 0!\n"); + acpi_handle_err(handle, "Link active IRQ is 0!\n"); return -1; } link->refcnt++; @@ -656,9 +648,7 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, *polarity = link->irq.polarity; if (name) *name = acpi_device_bid(link->device); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Link %s is referenced\n", - acpi_device_bid(link->device))); + acpi_handle_debug(handle, "Link is referenced\n"); return link->irq.active; } @@ -674,20 +664,20 @@ int acpi_pci_link_free_irq(acpi_handle handle) result = acpi_bus_get_device(handle, &device); if (result) { - printk(KERN_ERR PREFIX "Invalid link device\n"); + acpi_handle_err(handle, "Invalid link device\n"); return -1; } link = acpi_driver_data(device); if (!link) { - printk(KERN_ERR PREFIX "Invalid link context\n"); + acpi_handle_err(handle, "Invalid link context\n"); return -1; } mutex_lock(&acpi_link_lock); if (!link->irq.initialized) { mutex_unlock(&acpi_link_lock); - printk(KERN_ERR PREFIX "Link isn't initialized\n"); + acpi_handle_err(handle, "Link isn't initialized\n"); return -1; } #ifdef FUTURE_USE @@ -702,9 +692,7 @@ int acpi_pci_link_free_irq(acpi_handle handle) */ link->refcnt--; #endif - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Link %s is dereferenced\n", - acpi_device_bid(link->device))); + acpi_handle_debug(handle, "Link is dereferenced\n"); if (link->refcnt == 0) acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL); @@ -720,10 +708,10 @@ int acpi_pci_link_free_irq(acpi_handle handle) static int acpi_pci_link_add(struct acpi_device *device, const struct acpi_device_id *not_used) { - int result; + acpi_handle handle = device->handle; struct acpi_pci_link *link; + int result; int i; - int found = 0; link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); if (!link) @@ -742,31 +730,23 @@ static int acpi_pci_link_add(struct acpi_device *device, /* query and set link->irq.active */ acpi_pci_link_get_current(link); - printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device), - acpi_device_bid(device)); + pr_info("Interrupt link %s configured for IRQ %d\n", + acpi_device_bid(device), link->irq.active); + for (i = 0; i < link->irq.possible_count; i++) { - if (link->irq.active == link->irq.possible[i]) { - printk(KERN_CONT " *%d", link->irq.possible[i]); - found = 1; - } else - printk(KERN_CONT " %d", link->irq.possible[i]); + if (link->irq.active != link->irq.possible[i]) + acpi_handle_debug(handle, "Possible IRQ %d\n", + link->irq.possible[i]); } - printk(KERN_CONT ")"); - - if (!found) - printk(KERN_CONT " *%d", link->irq.active); - if (!link->device->status.enabled) - printk(KERN_CONT ", disabled."); - - printk(KERN_CONT "\n"); + pr_info("Interrupt link %s disabled\n", acpi_device_bid(device)); list_add_tail(&link->list, &acpi_link_list); end: /* disable all links -- to be activated on use */ - acpi_evaluate_object(device->handle, "_DIS", NULL, NULL); + acpi_evaluate_object(handle, "_DIS", NULL, NULL); mutex_unlock(&acpi_link_lock); if (result) diff --git a/drivers/acpi/pmic/intel_pmic_chtcrc.c b/drivers/acpi/pmic/intel_pmic_chtcrc.c index ebf8d3187df1f516bea541ca3a86d82c15bf78c3..2900dc3074d2c5be0cc919f9f226ac6b377236c5 100644 --- a/drivers/acpi/pmic/intel_pmic_chtcrc.c +++ b/drivers/acpi/pmic/intel_pmic_chtcrc.c @@ -15,7 +15,7 @@ /* * We have no docs for the CHT Crystal Cove PMIC. The Asus Zenfone-2 kernel * code has 2 Crystal Cove regulator drivers, one calls the PMIC a "Crystal - * Cove Plus" PMIC and talks about Cherry Trail, so presuambly that one + * Cove Plus" PMIC and talks about Cherry Trail, so presumably that one * could be used to get register info for the regulators if we need to * implement regulator support in the future. * diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 9b608b55d2b29545ccd32965bbdc5636af49252b..56102eaaa2da852ac91831b8ebd1fbc78e8235df 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -925,8 +925,7 @@ int acpi_add_power_resource(acpi_handle handle) return -ENOMEM; device = &resource->device; - acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER, - ACPI_STA_DEFAULT, NULL); + acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER); mutex_init(&resource->resource_lock); INIT_LIST_HEAD(&resource->list_node); INIT_LIST_HEAD(&resource->dependents); @@ -935,7 +934,7 @@ int acpi_add_power_resource(acpi_handle handle) strcpy(acpi_device_class(device), ACPI_POWER_CLASS); device->power.state = ACPI_STATE_UNKNOWN; - /* Evalute the object to get the system level and resource order. */ + /* Evaluate the object to get the system level and resource order. */ status = acpi_evaluate_object(handle, NULL, NULL, &buffer); if (ACPI_FAILURE(status)) goto err; @@ -996,6 +995,7 @@ void acpi_resume_power_resources(void) mutex_unlock(&power_resource_list_lock); } +#endif void acpi_turn_off_unused_power_resources(void) { @@ -1004,18 +1004,9 @@ void acpi_turn_off_unused_power_resources(void) mutex_lock(&power_resource_list_lock); list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) { - int result, state; - mutex_lock(&resource->resource_lock); - result = acpi_power_get_state(resource->device.handle, &state); - if (result) { - mutex_unlock(&resource->resource_lock); - continue; - } - - if (state == ACPI_POWER_RESOURCE_STATE_ON - && !resource->ref_count) { + if (!resource->ref_count) { dev_info(&resource->device.dev, "Turning OFF\n"); __acpi_power_off(resource); } @@ -1025,4 +1016,3 @@ void acpi_turn_off_unused_power_resources(void) mutex_unlock(&power_resource_list_lock); } -#endif diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 62114a03a51aa134dbf5254f105392c60c27a550..77541f939be3e464838409ec7d18d4a43736cf63 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -28,9 +28,6 @@ #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 -#define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("processor_driver"); - MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI Processor Driver"); MODULE_LICENSE("GPL"); @@ -87,8 +84,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) dev_name(&device->dev), event, 0); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); + acpi_handle_debug(handle, "Unsupported event [0x%x]\n", event); break; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 4e2d76b8b697ecb7f7f14d4dfaab4a9a3e64909f..45a019619e4a5657d51e238f6af01d9ec3ad739c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -32,9 +32,6 @@ #include <asm/cpu.h> #endif -#define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("processor_idle"); - #define ACPI_IDLE_STATE_START (IS_ENABLED(CONFIG_ARCH_HAS_CPU_RELAX) ? 1 : 0) static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER; @@ -240,8 +237,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) * 100 microseconds. */ if (acpi_gbl_FADT.c2_latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C2 latency too large [%d]\n", acpi_gbl_FADT.c2_latency)); + acpi_handle_debug(pr->handle, "C2 latency too large [%d]\n", + acpi_gbl_FADT.c2_latency); /* invalidate C2 */ pr->power.states[ACPI_STATE_C2].address = 0; } @@ -251,16 +248,15 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) * 1000 microseconds. */ if (acpi_gbl_FADT.c3_latency > ACPI_PROCESSOR_MAX_C3_LATENCY) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 latency too large [%d]\n", acpi_gbl_FADT.c3_latency)); + acpi_handle_debug(pr->handle, "C3 latency too large [%d]\n", + acpi_gbl_FADT.c3_latency); /* invalidate C3 */ pr->power.states[ACPI_STATE_C3].address = 0; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "lvl2[0x%08x] lvl3[0x%08x]\n", + acpi_handle_debug(pr->handle, "lvl2[0x%08x] lvl3[0x%08x]\n", pr->power.states[ACPI_STATE_C2].address, - pr->power.states[ACPI_STATE_C3].address)); + pr->power.states[ACPI_STATE_C3].address); snprintf(pr->power.states[ACPI_STATE_C2].desc, ACPI_CX_DESC_LEN, "ACPI P_LVL2 IOPORT 0x%x", @@ -325,8 +321,8 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, * devices thus we take the conservative approach. */ else if (errata.piix4.fdma) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 not supported on PIIX4 with Type-F DMA\n")); + acpi_handle_debug(pr->handle, + "C3 not supported on PIIX4 with Type-F DMA\n"); return; } @@ -345,13 +341,13 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, if (!pr->flags.bm_control) { if (pr->flags.has_cst != 1) { /* bus mastering control is necessary */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 support requires BM control\n")); + acpi_handle_debug(pr->handle, + "C3 support requires BM control\n"); return; } else { /* Here we enter C3 without bus mastering */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 support without BM control\n")); + acpi_handle_debug(pr->handle, + "C3 support without BM control\n"); } } } else { @@ -360,9 +356,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, * supported on when bm_check is not required. */ if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + acpi_handle_debug(pr->handle, "Cache invalidation should work properly" - " for C3 to be enabled on SMP systems\n")); + " for C3 to be enabled on SMP systems\n"); return; } } @@ -789,8 +785,8 @@ static inline void acpi_processor_cstate_first_run_checks(void) dmi_check_system(processor_power_dmi_table); max_cstate = acpi_processor_cstate_check(max_cstate); if (max_cstate < ACPI_C_STATES_MAX) - pr_notice("ACPI: processor limited to max C-state %d\n", - max_cstate); + pr_notice("processor limited to max C-state %d\n", max_cstate); + first_run++; if (nocst) @@ -848,7 +844,7 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle, status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _LPI, giving up\n")); + acpi_handle_debug(handle, "No _LPI, giving up\n"); return -ENODEV; } diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 813f1b78c16a91bf294cc191960e58a33c63e493..8c3f82c9fff353a924c68f39aea6f2a4d104db22 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -16,9 +16,6 @@ #include "internal.h" -#define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("processor_pdc"); - static bool __init processor_physically_present(acpi_handle handle) { int cpuid, type; @@ -132,8 +129,8 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); if (ACPI_FAILURE(status)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Could not evaluate _PDC, using legacy perf. control.\n")); + acpi_handle_debug(handle, + "Could not evaluate _PDC, using legacy perf control\n"); return status; } diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 32f0f554ccaed36addf840b24849f990b20c0a88..d088a0089ee9bb3ead1c913138624b7a33127b5c 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -23,8 +23,6 @@ #define PREFIX "ACPI: " #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" -#define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); @@ -65,13 +63,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) * (e.g. 0 = states 0..n; 1 = states 1..n; etc. */ status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc); - - if (status != AE_NOT_FOUND) + if (status != AE_NOT_FOUND) { acpi_processor_ppc_in_use = true; - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC")); - return -ENODEV; + if (ACPI_FAILURE(status)) { + acpi_evaluation_failure_warn(pr->handle, "_PPC", status); + return -ENODEV; + } } pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, @@ -98,7 +96,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status * @handle: ACPI processor handle * @status: the status code of _PPC evaluation - * 0: success. OSPM is now using the performance state specificed. + * 0: success. OSPM is now using the performance state specified. * 1: failure. OSPM has not changed the number of P-states in use */ static void acpi_processor_ppc_ost(acpi_handle handle, int status) @@ -199,7 +197,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr) status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT")); + acpi_evaluation_failure_warn(pr->handle, "_PCT", status); return -ENODEV; } @@ -299,7 +297,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS")); + acpi_evaluation_failure_warn(pr->handle, "_PSS", status); return -ENODEV; } @@ -310,8 +308,8 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) goto end; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", - pss->package.count)); + acpi_handle_debug(pr->handle, "Found %d performance states\n", + pss->package.count); pr->performance->state_count = pss->package.count; pr->performance->states = @@ -330,12 +328,13 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) state.length = sizeof(struct acpi_processor_px); state.pointer = px; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); + acpi_handle_debug(pr->handle, "Extracting state %d\n", i); status = acpi_extract_package(&(pss->package.elements[i]), &format, &state); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data")); + acpi_handle_warn(pr->handle, "Invalid _PSS data: %s\n", + acpi_format_exception(status)); result = -EFAULT; kfree(pr->performance->states); goto end; @@ -343,14 +342,14 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) amd_fixup_frequency(px, i); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + acpi_handle_debug(pr->handle, "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", i, (u32) px->core_frequency, (u32) px->power, (u32) px->transition_latency, (u32) px->bus_master_latency, - (u32) px->control, (u32) px->status)); + (u32) px->control, (u32) px->status); /* * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq @@ -400,8 +399,8 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr) return -EINVAL; if (!acpi_has_method(pr->handle, "_PCT")) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "ACPI-based processor performance control unavailable\n")); + acpi_handle_debug(pr->handle, + "ACPI-based processor performance control unavailable\n"); return -ENODEV; } @@ -442,24 +441,23 @@ int acpi_processor_pstate_control(void) if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control) return 0; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Writing pstate_control [0x%x] to smi_command [0x%x]\n", - acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command)); + pr_debug("Writing pstate_control [0x%x] to smi_command [0x%x]\n", + acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command); status = acpi_os_write_port(acpi_gbl_FADT.smi_command, (u32)acpi_gbl_FADT.pstate_control, 8); if (ACPI_SUCCESS(status)) return 1; - ACPI_EXCEPTION((AE_INFO, status, - "Failed to write pstate_control [0x%x] to smi_command [0x%x]", - acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command)); + pr_warn("Failed to write pstate_control [0x%x] to smi_command [0x%x]: %s\n", + acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command, + acpi_format_exception(status)); return -EIO; } int acpi_processor_notify_smm(struct module *calling_module) { - static int is_done = 0; + static int is_done; int result; if (!acpi_processor_cpufreq_init) @@ -485,7 +483,7 @@ int acpi_processor_notify_smm(struct module *calling_module) result = acpi_processor_pstate_control(); if (!result) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n")); + pr_debug("No SMI port or pstate_control\n"); module_put(calling_module); return 0; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index b1876534324b56954ced8f23a46161f1f67246ee..e61b8f038364bb5c0414c5ef4c09480479db02f2 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -22,9 +22,6 @@ #define PREFIX "ACPI: " -#define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("processor_throttling"); - /* ignore_tpc: * 0 -> acpi processor driver doesn't ignore _TPC values * 1 -> acpi processor driver ignores _TPC values @@ -196,10 +193,8 @@ err_ret: */ void acpi_processor_throttling_init(void) { - if (acpi_processor_update_tsd_coord()) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Assume no T-state coordination\n")); - } + if (acpi_processor_update_tsd_coord()) + pr_debug("Assume no T-state coordination\n"); return; } @@ -216,12 +211,13 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data) cpu = p_tstate->cpu; pr = per_cpu(processors, cpu); if (!pr) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid pr pointer\n")); + pr_debug("Invalid pr pointer\n"); return 0; } if (!pr->flags.throttling) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling control is " - "unsupported on CPU %d\n", cpu)); + acpi_handle_debug(pr->handle, + "Throttling control unsupported on CPU %d\n", + cpu); return 0; } target_state = p_tstate->target_state; @@ -245,9 +241,9 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data) target_state = p_throttling->state_count - 1; } p_tstate->target_state = target_state; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PreChange Event:" - "target T-state of CPU %d is T%d\n", - cpu, target_state)); + acpi_handle_debug(pr->handle, + "PreChange Event: target T-state of CPU %d is T%d\n", + cpu, target_state); break; case THROTTLING_POSTCHANGE: /* @@ -255,9 +251,9 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data) * T-state flag of acpi_processor_throttling. */ p_throttling->state = target_state; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PostChange Event:" - "CPU %d is switched to T%d\n", - cpu, target_state)); + acpi_handle_debug(pr->handle, + "PostChange Event: CPU %d is switched to T%d\n", + cpu, target_state); break; default: printk(KERN_WARNING @@ -284,9 +280,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc); if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC")); - } + if (status != AE_NOT_FOUND) + acpi_evaluation_failure_warn(pr->handle, "_TPC", status); + return -ENODEV; } @@ -417,9 +413,9 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr) status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC")); - } + if (status != AE_NOT_FOUND) + acpi_evaluation_failure_warn(pr->handle, "_PTC", status); + return -ENODEV; } @@ -502,9 +498,9 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr) status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer); if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS")); - } + if (status != AE_NOT_FOUND) + acpi_evaluation_failure_warn(pr->handle, "_TSS", status); + return -ENODEV; } @@ -515,8 +511,8 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr) goto end; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", - tss->package.count)); + acpi_handle_debug(pr->handle, "Found %d throttling states\n", + tss->package.count); pr->throttling.state_count = tss->package.count; pr->throttling.states_tss = @@ -537,12 +533,13 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr) state.length = sizeof(struct acpi_processor_tx_tss); state.pointer = tx; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); + acpi_handle_debug(pr->handle, "Extracting state %d\n", i); status = acpi_extract_package(&(tss->package.elements[i]), &format, &state); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data")); + acpi_handle_warn(pr->handle, "Invalid _TSS data: %s\n", + acpi_format_exception(status)); result = -EFAULT; kfree(pr->throttling.states_tss); goto end; @@ -582,9 +579,9 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr) status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer); if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSD")); - } + if (status != AE_NOT_FOUND) + acpi_evaluation_failure_warn(pr->handle, "_TSD", status); + return -ENODEV; } @@ -698,9 +695,9 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) local_irq_enable(); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + acpi_handle_debug(pr->handle, "Throttling state is T%d (%d%% throttling applied)\n", - state, pr->throttling.states[state].performance)); + state, pr->throttling.states[state].performance); return 0; } @@ -875,8 +872,8 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) if (ret >= 0) { state = acpi_get_throttling_state(pr, value); if (state == -1) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Invalid throttling state, reset\n")); + acpi_handle_debug(pr->handle, + "Invalid throttling state, reset\n"); state = 0; ret = __acpi_processor_set_throttling(pr, state, true, true); @@ -921,10 +918,10 @@ static int acpi_processor_get_fadt_info(struct acpi_processor *pr) int i, step; if (!pr->throttling.address) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n")); + acpi_handle_debug(pr->handle, "No throttling register\n"); return -EINVAL; } else if (!pr->throttling.duty_width) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n")); + acpi_handle_debug(pr->handle, "No throttling states\n"); return -EINVAL; } /* TBD: Support duty_cycle values that span bit 4. */ @@ -1015,10 +1012,10 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr, local_irq_enable(); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + acpi_handle_debug(pr->handle, "Throttling state set to T%d (%d%%)\n", state, (pr->throttling.states[state].performance ? pr-> - throttling.states[state].performance / 10 : 0))); + throttling.states[state].performance / 10 : 0)); return 0; } @@ -1129,8 +1126,8 @@ static int __acpi_processor_set_throttling(struct acpi_processor *pr, * error message and continue. */ if (!match_pr) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Invalid Pointer for CPU %d\n", i)); + acpi_handle_debug(pr->handle, + "Invalid Pointer for CPU %d\n", i); continue; } /* @@ -1138,9 +1135,8 @@ static int __acpi_processor_set_throttling(struct acpi_processor *pr, * we will report the error message and continue. */ if (!match_pr->flags.throttling) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Throttling Control is unsupported " - "on CPU %d\n", i)); + acpi_handle_debug(pr->handle, + "Throttling Control unsupported on CPU %d\n", i); continue; } @@ -1177,11 +1173,11 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) int result = 0; struct acpi_processor_throttling *pthrottling; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + acpi_handle_debug(pr->handle, "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", pr->throttling.address, pr->throttling.duty_offset, - pr->throttling.duty_width)); + pr->throttling.duty_width); /* * Evaluate _PTC, _TSS and _TPC @@ -1221,13 +1217,13 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) * used this part. */ if (errata.piix4.throttle) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Throttling not supported on PIIX4 A- or B-step\n")); + acpi_handle_debug(pr->handle, + "Throttling not supported on PIIX4 A- or B-step\n"); return 0; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", - pr->throttling.state_count)); + acpi_handle_debug(pr->handle, "Found %d throttling states\n", + pr->throttling.state_count); pr->flags.throttling = 1; @@ -1242,9 +1238,9 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) goto end; if (pr->throttling.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + acpi_handle_debug(pr->handle, "Disabling throttling (was T%d)\n", - pr->throttling.state)); + pr->throttling.state); result = acpi_processor_set_throttling(pr, 0, false); if (result) goto end; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 20a7892c6d3fd86f998b44929d4ff02054d1e39b..ee78a210c6068645574b8a5954e14578efd7e564 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -596,7 +596,7 @@ static int __acpi_dev_get_resources(struct acpi_device *adev, * @preproc_data: Pointer passed to the caller's preprocessing routine. * * Evaluate the _CRS method for the given device node and process its output by - * (1) executing the @preproc() rountine provided by the caller, passing the + * (1) executing the @preproc() routine provided by the caller, passing the * resource pointer and @preproc_data to it as arguments, for each ACPI resource * returned and (2) converting all of the returned ACPI resources into struct * resource objects if possible. If the return value of @preproc() in step (1) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 6efe7edd7b1eadbf3c6b66c88c56b0fbe72fe2f8..bc973fbd70b2a3f03231c76737a530048b838e24 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -530,7 +530,7 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used) * used by the device. */ acpi_power_transition(adev, ACPI_STATE_D3_COLD); - put_device(&adev->dev); + acpi_dev_put(adev); } } @@ -560,7 +560,7 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context) * prevents attempts to register device objects identical to those being * deleted from happening concurrently (such attempts result from * hotplug events handled via the ACPI hotplug workqueue). It also will - * run after all of the work items submitted previosuly, which helps + * run after all of the work items submitted previously, which helps * those work items to ensure that they are not accessing stale device * objects. */ @@ -604,8 +604,7 @@ EXPORT_SYMBOL(acpi_bus_get_device); static void get_acpi_device(void *dev) { - if (dev) - get_device(&((struct acpi_device *)dev)->dev); + acpi_dev_get(dev); } struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle) @@ -615,7 +614,7 @@ struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle) void acpi_bus_put_acpi_device(struct acpi_device *adev) { - put_device(&adev->dev); + acpi_dev_put(adev); } static struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id) @@ -757,27 +756,25 @@ static bool acpi_info_matches_ids(struct acpi_device_info *info, const char * const ids[]) { struct acpi_pnp_device_id_list *cid_list = NULL; - int i; + int i, index; if (!(info->valid & ACPI_VALID_HID)) return false; + index = match_string(ids, -1, info->hardware_id.string); + if (index >= 0) + return true; + if (info->valid & ACPI_VALID_CID) cid_list = &info->compatible_id_list; - for (i = 0; ids[i]; i++) { - int j; + if (!cid_list) + return false; - if (!strcmp(info->hardware_id.string, ids[i])) + for (i = 0; i < cid_list->count; i++) { + index = match_string(ids, -1, cid_list->ids[i].string); + if (index >= 0) return true; - - if (!cid_list) - continue; - - for (j = 0; j < cid_list->count; j++) { - if (!strcmp(cid_list->ids[j].string, ids[i])) - return true; - } } return false; @@ -1307,8 +1304,9 @@ static bool acpi_object_is_system_bus(acpi_handle handle) } static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, - int device_type, struct acpi_device_info *info) + int device_type) { + struct acpi_device_info *info = NULL; struct acpi_pnp_device_id_list *cid_list; int i; @@ -1319,6 +1317,7 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, break; } + acpi_get_object_info(handle, &info); if (!info) { pr_err(PREFIX "%s: Error reading device info\n", __func__); @@ -1344,6 +1343,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, if (info->valid & ACPI_VALID_CLS) acpi_add_id(pnp, info->class_code.string); + kfree(info); + /* * Some devices don't reliably have _HIDs & _CIDs, so add * synthetic HIDs to make sure drivers can find them. @@ -1649,17 +1650,16 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) } void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, - int type, unsigned long long sta, - struct acpi_device_info *info) + int type) { INIT_LIST_HEAD(&device->pnp.ids); device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); fwnode_init(&device->fwnode, &acpi_device_fwnode_ops); - acpi_set_device_status(device, sta); + acpi_set_device_status(device, ACPI_STA_DEFAULT); acpi_device_get_busid(device); - acpi_set_pnp_ids(handle, &device->pnp, type, info); + acpi_set_pnp_ids(handle, &device->pnp, type); acpi_init_properties(device); acpi_bus_get_flags(device); device->flags.match_driver = false; @@ -1680,33 +1680,30 @@ void acpi_device_add_finalize(struct acpi_device *device) kobject_uevent(&device->dev.kobj, KOBJ_ADD); } +static void acpi_scan_init_status(struct acpi_device *adev) +{ + if (acpi_bus_get_status(adev)) + acpi_set_device_status(adev, 0); +} + static int acpi_add_single_object(struct acpi_device **child, - acpi_handle handle, int type, - unsigned long long sta) + acpi_handle handle, int type) { - struct acpi_device_info *info = NULL; struct acpi_device *device; int result; - if (handle != ACPI_ROOT_OBJECT && type == ACPI_BUS_TYPE_DEVICE) - acpi_get_object_info(handle, &info); - device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); - if (!device) { - kfree(info); + if (!device) return -ENOMEM; - } - acpi_init_device_object(device, handle, type, sta, info); - kfree(info); + acpi_init_device_object(device, handle, type); /* - * For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so - * that we can call acpi_bus_get_status() and use its quirk handling. - * Note this must be done before the get power-/wakeup_dev-flags calls. + * Getting the status is delayed till here so that we can call + * acpi_bus_get_status() and use its quirk handling. Note that + * this must be done before the get power-/wakeup_dev-flags calls. */ - if (type == ACPI_BUS_TYPE_DEVICE) - if (acpi_bus_get_status(device) < 0) - acpi_set_device_status(device, 0); + if (type == ACPI_BUS_TYPE_DEVICE || type == ACPI_BUS_TYPE_PROCESSOR) + acpi_scan_init_status(device); acpi_bus_get_power_flags(device); acpi_bus_get_wakeup_device_flags(device); @@ -1763,50 +1760,6 @@ static bool acpi_device_should_be_hidden(acpi_handle handle) return true; } -static int acpi_bus_type_and_status(acpi_handle handle, int *type, - unsigned long long *sta) -{ - acpi_status status; - acpi_object_type acpi_type; - - status = acpi_get_type(handle, &acpi_type); - if (ACPI_FAILURE(status)) - return -ENODEV; - - switch (acpi_type) { - case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ - case ACPI_TYPE_DEVICE: - if (acpi_device_should_be_hidden(handle)) - return -ENODEV; - - *type = ACPI_BUS_TYPE_DEVICE; - /* - * acpi_add_single_object updates this once we've an acpi_device - * so that acpi_bus_get_status' quirk handling can be used. - */ - *sta = ACPI_STA_DEFAULT; - break; - case ACPI_TYPE_PROCESSOR: - *type = ACPI_BUS_TYPE_PROCESSOR; - status = acpi_bus_get_status_handle(handle, sta); - if (ACPI_FAILURE(status)) - return -ENODEV; - break; - case ACPI_TYPE_THERMAL: - *type = ACPI_BUS_TYPE_THERMAL; - *sta = ACPI_STA_DEFAULT; - break; - case ACPI_TYPE_POWER: - *type = ACPI_BUS_TYPE_POWER; - *sta = ACPI_STA_DEFAULT; - break; - default: - return -ENODEV; - } - - return 0; -} - bool acpi_device_is_present(const struct acpi_device *adev) { return adev->status.present || adev->status.functional; @@ -1875,7 +1828,7 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) } } -static u32 acpi_scan_check_dep(acpi_handle handle) +static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) { struct acpi_handle_list dep_devices; acpi_status status; @@ -1888,7 +1841,8 @@ static u32 acpi_scan_check_dep(acpi_handle handle) * 2. ACPI nodes describing USB ports. * Still, checking for _HID catches more then just these cases ... */ - if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID")) + if (!check_dep || !acpi_has_method(handle, "_DEP") || + !acpi_has_method(handle, "_HID")) return 0; status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices); @@ -1953,33 +1907,48 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, struct acpi_device **adev_p) { struct acpi_device *device = NULL; - unsigned long long sta; + acpi_object_type acpi_type; int type; - int result; acpi_bus_get_device(handle, &device); if (device) goto out; - result = acpi_bus_type_and_status(handle, &type, &sta); - if (result) + if (ACPI_FAILURE(acpi_get_type(handle, &acpi_type))) return AE_OK; - if (type == ACPI_BUS_TYPE_POWER) { - acpi_add_power_resource(handle); - return AE_OK; - } + switch (acpi_type) { + case ACPI_TYPE_DEVICE: + if (acpi_device_should_be_hidden(handle)) + return AE_OK; - if (type == ACPI_BUS_TYPE_DEVICE && check_dep) { - u32 count = acpi_scan_check_dep(handle); - /* Bail out if the number of recorded dependencies is not 0. */ - if (count > 0) { + /* Bail out if there are dependencies. */ + if (acpi_scan_check_dep(handle, check_dep) > 0) { acpi_bus_scan_second_pass = true; return AE_CTRL_DEPTH; } + + fallthrough; + case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ + type = ACPI_BUS_TYPE_DEVICE; + break; + + case ACPI_TYPE_PROCESSOR: + type = ACPI_BUS_TYPE_PROCESSOR; + break; + + case ACPI_TYPE_THERMAL: + type = ACPI_BUS_TYPE_THERMAL; + break; + + case ACPI_TYPE_POWER: + acpi_add_power_resource(handle); + fallthrough; + default: + return AE_OK; } - acpi_add_single_object(&device, handle, type, sta); + acpi_add_single_object(&device, handle, type); if (!device) return AE_CTRL_DEPTH; @@ -2253,8 +2222,7 @@ int acpi_bus_register_early_device(int type) struct acpi_device *device = NULL; int result; - result = acpi_add_single_object(&device, NULL, - type, ACPI_STA_DEFAULT); + result = acpi_add_single_object(&device, NULL, type); if (result) return result; @@ -2274,8 +2242,7 @@ static int acpi_bus_scan_fixed(void) struct acpi_device *device = NULL; result = acpi_add_single_object(&device, NULL, - ACPI_BUS_TYPE_POWER_BUTTON, - ACPI_STA_DEFAULT); + ACPI_BUS_TYPE_POWER_BUTTON); if (result) return result; @@ -2291,8 +2258,7 @@ static int acpi_bus_scan_fixed(void) struct acpi_device *device = NULL; result = acpi_add_single_object(&device, NULL, - ACPI_BUS_TYPE_SLEEP_BUTTON, - ACPI_STA_DEFAULT); + ACPI_BUS_TYPE_SLEEP_BUTTON); if (result) return result; @@ -2388,11 +2354,13 @@ int __init acpi_scan_init(void) acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); acpi_device_del(acpi_root); - put_device(&acpi_root->dev); + acpi_bus_put_acpi_device(acpi_root); goto out; } } + acpi_turn_off_unused_power_resources(); + acpi_scan_initialized = true; out: diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h index 1856f76ac83f73451715af33f5488f2420b7fca9..7fe41ee489d6123c2fec04a6672ef25f1c04cbce 100644 --- a/drivers/acpi/sleep.h +++ b/drivers/acpi/sleep.h @@ -8,7 +8,6 @@ extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; extern void acpi_resume_power_resources(void); -extern void acpi_turn_off_unused_power_resources(void); static inline acpi_status acpi_set_waking_vector(u32 wakeup_address) { diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 8baf7644a0d08254c0f42d289ce7dbc25244539c..d25927195d6d8ef099fb1fd4e7a2aa301f0f5d51 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -12,9 +12,6 @@ #include "internal.h" -#define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("sysfs"); - #ifdef CONFIG_ACPI_DEBUG /* * ACPI debug sysfs I/F, including: @@ -51,14 +48,6 @@ static const struct acpi_dlayer acpi_debug_layers[] = { ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), ACPI_DEBUG_INIT(ACPI_COMPILER), ACPI_DEBUG_INIT(ACPI_TOOLS), - - ACPI_DEBUG_INIT(ACPI_SBS_COMPONENT), - ACPI_DEBUG_INIT(ACPI_FAN_COMPONENT), - ACPI_DEBUG_INIT(ACPI_PCI_COMPONENT), - ACPI_DEBUG_INIT(ACPI_CONTAINER_COMPONENT), - ACPI_DEBUG_INIT(ACPI_SYSTEM_COMPONENT), - ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT), - ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT), }; static const struct acpi_dlevel acpi_debug_levels[] = { @@ -652,8 +641,7 @@ static int get_status(u32 index, acpi_event_status *ret, if (index < num_gpes) { status = acpi_get_gpe_device(index, handle); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, - "Invalid GPE 0x%x", index)); + pr_warn("Invalid GPE 0x%x", index); return -ENXIO; } status = acpi_get_gpe_status(*handle, index, ret); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 682edd913b3b103d8d58182e7351cb9ce760eb96..3b54b8fd739699925bf7ca9bc243101657b682d3 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -511,6 +511,20 @@ __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, EXPORT_SYMBOL(__acpi_handle_debug); #endif +/** + * acpi_evaluation_failure_warn - Log evaluation failure warning. + * @handle: Parent object handle. + * @name: Name of the object whose evaluation has failed. + * @status: Status value returned by the failing object evaluation. + */ +void acpi_evaluation_failure_warn(acpi_handle handle, const char *name, + acpi_status status) +{ + acpi_handle_warn(handle, "%s evaluation failed: %s\n", name, + acpi_format_exception(status)); +} +EXPORT_SYMBOL_GPL(acpi_evaluation_failure_warn); + /** * acpi_has_method: Check whether @handle has a method named @name * @handle: ACPI device handle @@ -797,7 +811,7 @@ static int acpi_dev_match_cb(struct device *dev, const void *data) * Note that if the device is pluggable, it may since have disappeared. * * Note that unlike acpi_dev_found() this function checks the status - * of the device. So for devices which are present in the dsdt, but + * of the device. So for devices which are present in the DSDT, but * which are disabled (their _STA callback returns 0) this function * will return false. * @@ -824,7 +838,7 @@ EXPORT_SYMBOL(acpi_dev_present); /** * acpi_dev_get_next_match_dev - Return the next match of ACPI device - * @adev: Pointer to the previous acpi_device matching this @hid, @uid and @hrv + * @adev: Pointer to the previous ACPI device matching this @hid, @uid and @hrv * @hid: Hardware ID of the device. * @uid: Unique ID of the device, pass NULL to not check _UID * @hrv: Hardware Revision of the device, pass -1 to not check _HRV @@ -832,7 +846,11 @@ EXPORT_SYMBOL(acpi_dev_present); * Return the next match of ACPI device if another matching device was present * at the moment of invocation, or NULL otherwise. * - * The caller is responsible to call put_device() on the returned device. + * FIXME: The function does not tolerate the sudden disappearance of @adev, e.g. + * in the case of a hotplug event. That said, the caller should ensure that + * this will never happen. + * + * The caller is responsible for invoking acpi_dev_put() on the returned device. * * See additional information in acpi_dev_present() as well. */ @@ -861,7 +879,7 @@ EXPORT_SYMBOL(acpi_dev_get_next_match_dev); * Return the first match of ACPI device if a matching device was present * at the moment of invocation, or NULL otherwise. * - * The caller is responsible to call put_device() on the returned device. + * The caller is responsible for invoking acpi_dev_put() on the returned device. * * See additional information in acpi_dev_present() as well. */ @@ -872,6 +890,17 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) } EXPORT_SYMBOL(acpi_dev_get_first_match_dev); +/** + * acpi_reduced_hardware - Return if this is an ACPI-reduced-hw machine + * + * Return true when running on an ACPI-reduced-hw machine, false otherwise. + */ +bool acpi_reduced_hardware(void) +{ + return acpi_gbl_reduced_hardware; +} +EXPORT_SYMBOL_GPL(acpi_reduced_hardware); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 83cd4c95faf0da8acec49d1104542c61cd218f5e..33474fd969913c513d1acfd1577a0135f1c8a8d9 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -385,6 +385,30 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"), }, }, + { + .callback = video_detect_force_native, + .ident = "ASUSTeK COMPUTER INC. GA401", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA401"), + }, + }, + { + .callback = video_detect_force_native, + .ident = "ASUSTeK COMPUTER INC. GA502", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA502"), + }, + }, + { + .callback = video_detect_force_native, + .ident = "ASUSTeK COMPUTER INC. GA503", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), + }, + }, /* * Desktops which falsely report a backlight and which our heuristics diff --git a/drivers/android/binder.c b/drivers/android/binder.c index eb080e3b09c0b6bf961950fa61c30d17c606c5fd..7cc878b068f1cbf86e09aab6f141725416cd6a4f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1640,6 +1640,12 @@ static void binder_free_transaction(struct binder_transaction *t) if (target_proc) { binder_inner_proc_lock(target_proc); + target_proc->outstanding_txns--; + if (target_proc->outstanding_txns < 0) + pr_warn("%s: Unexpected outstanding_txns %d\n", + __func__, target_proc->outstanding_txns); + if (!target_proc->outstanding_txns && target_proc->is_frozen) + wake_up_interruptible_all(&target_proc->freeze_wait); if (t->buffer) t->buffer->transaction = NULL; binder_inner_proc_unlock(target_proc); @@ -2465,10 +2471,11 @@ static int binder_fixup_parent(struct binder_transaction *t, * If the @thread parameter is not NULL, the transaction is always queued * to the waitlist of that specific thread. * - * Return: true if the transactions was successfully queued - * false if the target process or thread is dead + * Return: 0 if the transaction was successfully queued + * BR_DEAD_REPLY if the target process or thread is dead + * BR_FROZEN_REPLY if the target process or thread is frozen */ -static bool binder_proc_transaction(struct binder_transaction *t, +static int binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) { @@ -2491,11 +2498,16 @@ static bool binder_proc_transaction(struct binder_transaction *t, } binder_inner_proc_lock(proc); + if (proc->is_frozen) { + proc->sync_recv |= !oneway; + proc->async_recv |= oneway; + } - if (proc->is_dead || (thread && thread->is_dead)) { + if ((proc->is_frozen && !oneway) || proc->is_dead || + (thread && thread->is_dead)) { binder_inner_proc_unlock(proc); binder_node_unlock(node); - return false; + return proc->is_frozen ? BR_FROZEN_REPLY : BR_DEAD_REPLY; } if (!thread && !pending_async) @@ -2514,10 +2526,11 @@ static bool binder_proc_transaction(struct binder_transaction *t, if (!pending_async) binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + proc->outstanding_txns++; binder_inner_proc_unlock(proc); binder_node_unlock(node); - return true; + return 0; } /** @@ -2843,7 +2856,16 @@ static void binder_transaction(struct binder_proc *proc, u32 secid; size_t added_size; - security_task_getsecid(proc->tsk, &secid); + /* + * Arguably this should be the task's subjective LSM secid but + * we can't reliably access the subjective creds of a task + * other than our own so we must use the objective creds, which + * are safe to access. The downside is that if a task is + * temporarily overriding it's creds it will not be reflected + * here; however, it isn't clear that binder would handle that + * case well anyway. + */ + security_task_getsecid_obj(proc->tsk, &secid); ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); if (ret) { return_error = BR_FAILED_REPLY; @@ -3150,19 +3172,25 @@ static void binder_transaction(struct binder_proc *proc, goto err_bad_object_type; } } - tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + if (t->buffer->oneway_spam_suspect) + tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT; + else + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; t->work.type = BINDER_WORK_TRANSACTION; if (reply) { binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); - if (target_thread->is_dead) { + if (target_thread->is_dead || target_proc->is_frozen) { + return_error = target_thread->is_dead ? + BR_DEAD_REPLY : BR_FROZEN_REPLY; binder_inner_proc_unlock(target_proc); goto err_dead_proc_or_thread; } BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction_ilocked(target_thread, in_reply_to); binder_enqueue_thread_work_ilocked(target_thread, &t->work); + target_proc->outstanding_txns++; binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); trace_android_vh_binder_restore_priority(in_reply_to, current); @@ -3183,7 +3211,9 @@ static void binder_transaction(struct binder_proc *proc, t->from_parent = thread->transaction_stack; thread->transaction_stack = t; binder_inner_proc_unlock(proc); - if (!binder_proc_transaction(t, target_proc, target_thread)) { + return_error = binder_proc_transaction(t, + target_proc, target_thread); + if (return_error) { binder_inner_proc_lock(proc); binder_pop_transaction_ilocked(thread, t); binder_inner_proc_unlock(proc); @@ -3193,7 +3223,8 @@ static void binder_transaction(struct binder_proc *proc, BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); binder_enqueue_thread_work(thread, tcomplete); - if (!binder_proc_transaction(t, target_proc, NULL)) + return_error = binder_proc_transaction(t, target_proc, NULL); + if (return_error) goto err_dead_proc_or_thread; } if (target_thread) @@ -3210,7 +3241,6 @@ static void binder_transaction(struct binder_proc *proc, return; err_dead_proc_or_thread: - return_error = BR_DEAD_REPLY; return_error_line = __LINE__; binder_dequeue_work(proc, tcomplete); err_translate_failed: @@ -3836,7 +3866,7 @@ static int binder_wait_for_work(struct binder_thread *thread, binder_inner_proc_lock(proc); list_del_init(&thread->waiting_thread_node); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; break; } } @@ -4016,9 +4046,14 @@ retry: binder_stat_br(proc, thread, cmd); } break; - case BINDER_WORK_TRANSACTION_COMPLETE: { + case BINDER_WORK_TRANSACTION_COMPLETE: + case BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT: { + if (proc->oneway_spam_detection_enabled && + w->type == BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT) + cmd = BR_ONEWAY_SPAM_SUSPECT; + else + cmd = BR_TRANSACTION_COMPLETE; binder_inner_proc_unlock(proc); - cmd = BR_TRANSACTION_COMPLETE; kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); if (put_user(cmd, (uint32_t __user *)ptr)) @@ -4439,6 +4474,9 @@ static void binder_free_proc(struct binder_proc *proc) BUG_ON(!list_empty(&proc->todo)); BUG_ON(!list_empty(&proc->delivered_death)); + if (proc->outstanding_txns) + pr_warn("%s: Unexpected outstanding_txns %d\n", + __func__, proc->outstanding_txns); device = container_of(proc->context, struct binder_device, context); if (refcount_dec_and_test(&device->ref)) { kfree(proc->context->name); @@ -4501,6 +4539,7 @@ static int binder_thread_release(struct binder_proc *proc, (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { + thread->proc->outstanding_txns--; t->to_proc = NULL; t->to_thread = NULL; if (t->buffer) { @@ -4751,6 +4790,76 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, return 0; } +static int binder_ioctl_freeze(struct binder_freeze_info *info, + struct binder_proc *target_proc) +{ + int ret = 0; + + if (!info->enable) { + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + return 0; + } + + /* + * Freezing the target. Prevent new transactions by + * setting frozen state. If timeout specified, wait + * for transactions to drain. + */ + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = true; + binder_inner_proc_unlock(target_proc); + + if (info->timeout_ms > 0) + ret = wait_event_interruptible_timeout( + target_proc->freeze_wait, + (!target_proc->outstanding_txns), + msecs_to_jiffies(info->timeout_ms)); + + if (!ret && target_proc->outstanding_txns) + ret = -EAGAIN; + + if (ret < 0) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + } + + return ret; +} + +static int binder_ioctl_get_freezer_info( + struct binder_frozen_status_info *info) +{ + struct binder_proc *target_proc; + bool found = false; + + info->sync_recv = 0; + info->async_recv = 0; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info->pid) { + found = true; + binder_inner_proc_lock(target_proc); + info->sync_recv |= target_proc->sync_recv; + info->async_recv |= target_proc->async_recv; + binder_inner_proc_unlock(target_proc); + } + } + mutex_unlock(&binder_procs_lock); + + if (!found) + return -EINVAL; + + return 0; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; @@ -4869,6 +4978,96 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_FREEZE: { + struct binder_freeze_info info; + struct binder_proc **target_procs = NULL, *target_proc; + int target_procs_count = 0, i = 0; + + ret = 0; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info.pid) + target_procs_count++; + } + + if (target_procs_count == 0) { + mutex_unlock(&binder_procs_lock); + ret = -EINVAL; + goto err; + } + + target_procs = kcalloc(target_procs_count, + sizeof(struct binder_proc *), + GFP_KERNEL); + + if (!target_procs) { + mutex_unlock(&binder_procs_lock); + ret = -ENOMEM; + goto err; + } + + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid != info.pid) + continue; + + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + + target_procs[i++] = target_proc; + } + mutex_unlock(&binder_procs_lock); + + for (i = 0; i < target_procs_count; i++) { + if (ret >= 0) + ret = binder_ioctl_freeze(&info, + target_procs[i]); + + binder_proc_dec_tmpref(target_procs[i]); + } + + kfree(target_procs); + + if (ret < 0) + goto err; + break; + } + case BINDER_GET_FROZEN_INFO: { + struct binder_frozen_status_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_freezer_info(&info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + break; + } + case BINDER_ENABLE_ONEWAY_SPAM_DETECTION: { + uint32_t enable; + + if (copy_from_user(&enable, ubuf, sizeof(enable))) { + ret = -EINVAL; + goto err; + } + binder_inner_proc_lock(proc); + proc->oneway_spam_detection_enabled = (bool)enable; + binder_inner_proc_unlock(proc); + break; + } default: ret = -EINVAL; goto err; @@ -4878,7 +5077,7 @@ err: if (thread) thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret && ret != -ERESTARTSYS) + if (ret && ret != -EINTR) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); err_unlocked: trace_binder_ioctl_done(ret); @@ -4965,6 +5164,7 @@ static int binder_open(struct inode *nodp, struct file *filp) get_task_struct(current->group_leader); proc->tsk = current->group_leader; INIT_LIST_HEAD(&proc->todo); + init_waitqueue_head(&proc->freeze_wait); if (binder_supported_policy(current->policy)) { proc->default_priority.sched_policy = current->policy; proc->default_priority.prio = current->normal_prio; @@ -5184,6 +5384,9 @@ static void binder_deferred_release(struct binder_proc *proc) proc->tmp_ref++; proc->is_dead = true; + proc->is_frozen = false; + proc->sync_recv = false; + proc->async_recv = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { @@ -5536,7 +5739,9 @@ static const char * const binder_return_strings[] = { "BR_FINISHED", "BR_DEAD_BINDER", "BR_CLEAR_DEATH_NOTIFICATION_DONE", - "BR_FAILED_REPLY" + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", + "BR_ONEWAY_SPAM_SUSPECT", }; static const char * const binder_command_strings[] = { diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 7caf74ad24053a49327e07eeb902feb527376d90..340515f54498ce885be926afc35364e9412ae37a 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -338,7 +338,7 @@ static inline struct vm_area_struct *binder_alloc_get_vma( return vma; } -static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) +static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) { /* * Find the amount and size of buffers allocated by the current caller; @@ -366,13 +366,19 @@ static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) /* * Warn if this pid has more than 50 transactions, or more than 50% of - * async space (which is 25% of total buffer size). + * async space (which is 25% of total buffer size). Oneway spam is only + * detected when the threshold is exceeded. */ if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) { binder_alloc_debug(BINDER_DEBUG_USER_ERROR, "%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n", alloc->pid, pid, num_buffers, total_alloc_size); + if (!alloc->oneway_spam_detected) { + alloc->oneway_spam_detected = true; + return true; + } } + return false; } static struct binder_buffer *binder_alloc_new_buf_locked( @@ -525,6 +531,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked( buffer->async_transaction = is_async; buffer->extra_buffers_size = extra_buffers_size; buffer->pid = pid; + buffer->oneway_spam_suspect = false; if (is_async) { alloc->free_async_space -= size + sizeof(struct binder_buffer); binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, @@ -536,7 +543,9 @@ static struct binder_buffer *binder_alloc_new_buf_locked( * of async space left (which is less than 10% of total * buffer size). */ - debug_low_async_space_locked(alloc, pid); + buffer->oneway_spam_suspect = debug_low_async_space_locked(alloc, pid); + } else { + alloc->oneway_spam_detected = false; } } return buffer; diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 6e8e001381af4ba2c2f73a2ab7bbca1feff5397f..7dea57a84c79b1eb2d77df14a14f9b7d272711bf 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -26,6 +26,8 @@ struct binder_transaction; * @clear_on_free: %true if buffer must be zeroed after use * @allow_user_free: %true if user is allowed to free buffer * @async_transaction: %true if buffer is in use for an async txn + * @oneway_spam_suspect: %true if total async allocate size just exceed + * spamming detect threshold * @debug_id: unique ID for debugging * @transaction: pointer to associated struct binder_transaction * @target_node: struct binder_node associated with this buffer @@ -45,7 +47,8 @@ struct binder_buffer { unsigned clear_on_free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned debug_id:28; + unsigned oneway_spam_suspect:1; + unsigned debug_id:27; struct binder_transaction *transaction; @@ -87,6 +90,8 @@ struct binder_lru_page { * @buffer_size: size of address space specified via mmap * @pid: pid for associated binder_proc (invariant after init) * @pages_high: high watermark of offset in @pages + * @oneway_spam_detected: %true if oneway spam detection fired, clear that + * flag once the async buffer has returned to a healthy state * * Bookkeeping structure for per-proc address space management for binder * buffers. It is normally initialized during binder_init() and binder_mmap() @@ -107,6 +112,7 @@ struct binder_alloc { uint32_t buffer_free; int pid; size_t pages_high; + bool oneway_spam_detected; }; #ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 78a4efd827ece6bc394ab3315500a7ff49245d07..7e2e2ffd74e6cb48a4aa8f7f489986d5ccc4560f 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -155,7 +155,7 @@ enum binder_stat_types { }; struct binder_stats { - atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t br[_IOC_NR(BR_ONEWAY_SPAM_SUSPECT) + 1]; atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; @@ -174,6 +174,7 @@ struct binder_work { enum binder_work_type { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT, BINDER_WORK_RETURN_ERROR, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, @@ -388,9 +389,22 @@ struct binder_priority { * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform * (protected by binder_deferred_lock) + * @outstanding_txns: number of transactions to be transmitted before + * processes in freeze_wait are woken up + * (protected by @inner_lock) * @is_dead: process is dead and awaiting free * when outstanding transactions are cleaned up * (protected by @inner_lock) + * @is_frozen: process is frozen and unable to service + * binder transactions + * (protected by @inner_lock) + * @sync_recv: process received sync transactions since last frozen + * (protected by @inner_lock) + * @async_recv: process received async transactions since last frozen + * (protected by @inner_lock) + * @freeze_wait: waitqueue of processes waiting for all outstanding + * transactions to be processed + * (protected by @inner_lock) * @todo: list of work for this process * (protected by @inner_lock) * @stats: per-process binder statistics @@ -417,6 +431,8 @@ struct binder_priority { * @outer_lock: no nesting under innor or node lock * Lock order: 1) outer, 2) node, 3) inner * @binderfs_entry: process-specific binderfs log file + * @oneway_spam_detection_enabled: process enabled oneway spam detection + * or not * * Bookkeeping structure for binder processes */ @@ -431,7 +447,12 @@ struct binder_proc { struct task_struct *tsk; struct hlist_node deferred_work_node; int deferred_work; + int outstanding_txns; bool is_dead; + bool is_frozen; + bool sync_recv; + bool async_recv; + wait_queue_head_t freeze_wait; struct list_head todo; struct binder_stats stats; @@ -447,6 +468,7 @@ struct binder_proc { spinlock_t inner_lock; spinlock_t outer_lock; struct dentry *binderfs_entry; + bool oneway_spam_detection_enabled; }; /** diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index b574cce98dc3686ce473b1f2cc132b4de8616ed2..422753d52244bd446664e2b68f427f9a3a6ff32b 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2054,7 +2054,7 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) } submitted++; ATM_SKB(skb)->vcc = vcc; - tasklet_disable(&ENI_DEV(vcc->dev)->task); + tasklet_disable_in_atomic(&ENI_DEV(vcc->dev)->task); res = do_tx(skb); tasklet_enable(&ENI_DEV(vcc->dev)->task); if (res == enq_ok) return 0; diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 56f317fb7ee29ce6438d427c1107191beae37a61..e74219436fbb4e832cecd3d9e135ce0200f0b5b9 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -22,18 +22,94 @@ #include <linux/smp.h> #include <trace/hooks/topology.h> +static DEFINE_PER_CPU(struct scale_freq_data *, sft_data); +static struct cpumask scale_freq_counters_mask; +static bool scale_freq_invariant; + +static bool supports_scale_freq_counters(const struct cpumask *cpus) +{ + return cpumask_subset(cpus, &scale_freq_counters_mask); +} + bool topology_scale_freq_invariant(void) { return cpufreq_supports_freq_invariance() || - arch_freq_counters_available(cpu_online_mask); + supports_scale_freq_counters(cpu_online_mask); } -__weak bool arch_freq_counters_available(const struct cpumask *cpus) +static void update_scale_freq_invariant(bool status) { - return false; + if (scale_freq_invariant == status) + return; + + /* + * Task scheduler behavior depends on frequency invariance support, + * either cpufreq or counter driven. If the support status changes as + * a result of counter initialisation and use, retrigger the build of + * scheduling domains to ensure the information is propagated properly. + */ + if (topology_scale_freq_invariant() == status) { + scale_freq_invariant = status; + rebuild_sched_domains_energy(); + } } -DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; -EXPORT_PER_CPU_SYMBOL_GPL(freq_scale); + +void topology_set_scale_freq_source(struct scale_freq_data *data, + const struct cpumask *cpus) +{ + struct scale_freq_data *sfd; + int cpu; + + /* + * Avoid calling rebuild_sched_domains() unnecessarily if FIE is + * supported by cpufreq. + */ + if (cpumask_empty(&scale_freq_counters_mask)) + scale_freq_invariant = topology_scale_freq_invariant(); + + for_each_cpu(cpu, cpus) { + sfd = per_cpu(sft_data, cpu); + + /* Use ARCH provided counters whenever possible */ + if (!sfd || sfd->source != SCALE_FREQ_SOURCE_ARCH) { + per_cpu(sft_data, cpu) = data; + cpumask_set_cpu(cpu, &scale_freq_counters_mask); + } + } + + update_scale_freq_invariant(true); +} +EXPORT_SYMBOL_GPL(topology_set_scale_freq_source); + +void topology_clear_scale_freq_source(enum scale_freq_source source, + const struct cpumask *cpus) +{ + struct scale_freq_data *sfd; + int cpu; + + for_each_cpu(cpu, cpus) { + sfd = per_cpu(sft_data, cpu); + + if (sfd && sfd->source == source) { + per_cpu(sft_data, cpu) = NULL; + cpumask_clear_cpu(cpu, &scale_freq_counters_mask); + } + } + + update_scale_freq_invariant(false); +} +EXPORT_SYMBOL_GPL(topology_clear_scale_freq_source); + +void topology_scale_freq_tick(void) +{ + struct scale_freq_data *sfd = *this_cpu_ptr(&sft_data); + + if (sfd) + sfd->set_freq_scale(); +} + +DEFINE_PER_CPU(unsigned long, arch_freq_scale) = SCHED_CAPACITY_SCALE; +EXPORT_PER_CPU_SYMBOL_GPL(arch_freq_scale); void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq, unsigned long max_freq) @@ -49,7 +125,7 @@ void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq, * want to update the scale factor with information from CPUFREQ. * Instead the scale factor will be updated from arch_scale_freq_tick. */ - if (arch_freq_counters_available(cpus)) + if (supports_scale_freq_counters(cpus)) return; scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq; @@ -57,7 +133,7 @@ void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq, trace_android_vh_arch_set_freq_scale(cpus, cur_freq, max_freq, &scale); for_each_cpu(i, cpus) - per_cpu(freq_scale, i) = scale; + per_cpu(arch_freq_scale, i) = scale; } DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE; diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index f7bd0f4db13d832788e839d965c7f0bd7c8efb4e..9c00d203d61e3d1444011e7c7a83728813a70aea 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -461,6 +461,10 @@ attribute_container_add_class_device(struct device *classdev) /** * attribute_container_add_class_device_adapter - simple adapter for triggers * + * @cont: the container to register. + * @dev: the generic device to activate the trigger for + * @classdev: the class device to add + * * This function is identical to attribute_container_add_class_device except * that it is designed to be called from the triggers */ diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index d8b314e7d0fdc88cfa33f37f2ccefdd329cb286e..adc199dfba3cb3ff3e03ea3c98ae4645799fa442 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -265,8 +265,3 @@ void __init auxiliary_bus_init(void) { WARN_ON(bus_register(&auxiliary_bus_type)); } - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Auxiliary Bus"); -MODULE_AUTHOR("David Ertman <david.m.ertman@intel.com>"); -MODULE_AUTHOR("Kiran Patil <kiran.patil@intel.com>"); diff --git a/drivers/base/base.h b/drivers/base/base.h index 52b3d7b75c2750e85c0b5f1b238964dd42cb5fa9..e5f9b7e656c34b385ef2aa2a309a702c587b6388 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -185,11 +185,13 @@ extern int device_links_read_lock(void); extern void device_links_read_unlock(int idx); extern int device_links_read_lock_held(void); extern int device_links_check_suppliers(struct device *dev); +extern void device_links_force_bind(struct device *dev); extern void device_links_driver_bound(struct device *dev); extern void device_links_driver_cleanup(struct device *dev); extern void device_links_no_driver(struct device *dev); extern bool device_links_busy(struct device *dev); extern void device_links_unbind_consumers(struct device *dev); +extern void fw_devlink_drivers_done(void); /* device pm support */ void device_pm_move_to_tail(struct device *dev); diff --git a/drivers/base/component.c b/drivers/base/component.c index dcfbe7251dc43b86edd347c371c306d70d32e39d..272ba42392f0c0d953ea593dd26421f9f2f1e5a6 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -65,7 +65,6 @@ struct master { const struct component_master_ops *ops; struct device *dev; struct component_match *match; - struct dentry *dentry; }; struct component { @@ -125,15 +124,13 @@ core_initcall(component_debug_init); static void component_master_debugfs_add(struct master *m) { - m->dentry = debugfs_create_file(dev_name(m->dev), 0444, - component_debugfs_dir, - m, &component_devices_fops); + debugfs_create_file(dev_name(m->dev), 0444, component_debugfs_dir, m, + &component_devices_fops); } static void component_master_debugfs_del(struct master *m) { - debugfs_remove(m->dentry); - m->dentry = NULL; + debugfs_remove(debugfs_lookup(dev_name(m->dev), component_debugfs_dir)); } #else diff --git a/drivers/base/core.c b/drivers/base/core.c index d9b26f5b1d94780cb5942e081e6e778abf9de901..4a8bf8cda52bc77243fcffb8af554309aeed01bb 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -51,6 +51,7 @@ static LIST_HEAD(deferred_sync); static unsigned int defer_sync_state_count = 1; static DEFINE_MUTEX(fwnode_link_lock); static bool fw_devlink_is_permissive(void); +static bool fw_devlink_drv_reg_done; /** * fwnode_link_add - Create a link between two fwnode_handles. @@ -1153,6 +1154,41 @@ static ssize_t waiting_for_supplier_show(struct device *dev, } static DEVICE_ATTR_RO(waiting_for_supplier); +/** + * device_links_force_bind - Prepares device to be force bound + * @dev: Consumer device. + * + * device_bind_driver() force binds a device to a driver without calling any + * driver probe functions. So the consumer really isn't going to wait for any + * supplier before it's bound to the driver. We still want the device link + * states to be sensible when this happens. + * + * In preparation for device_bind_driver(), this function goes through each + * supplier device links and checks if the supplier is bound. If it is, then + * the device link status is set to CONSUMER_PROBE. Otherwise, the device link + * is dropped. Links without the DL_FLAG_MANAGED flag set are ignored. + */ +void device_links_force_bind(struct device *dev) +{ + struct device_link *link, *ln; + + device_links_write_lock(); + + list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) { + if (!(link->flags & DL_FLAG_MANAGED)) + continue; + + if (link->status != DL_STATE_AVAILABLE) { + device_link_drop_managed(link); + continue; + } + WRITE_ONCE(link->status, DL_STATE_CONSUMER_PROBE); + } + dev->links.status = DL_DEV_PROBING; + + device_links_write_unlock(); +} + /** * device_links_driver_bound - Update device links after probing its driver. * @dev: Device to update the links for. @@ -1563,6 +1599,52 @@ static void fw_devlink_parse_fwtree(struct fwnode_handle *fwnode) fw_devlink_parse_fwtree(child); } +static void fw_devlink_relax_link(struct device_link *link) +{ + if (!(link->flags & DL_FLAG_INFERRED)) + return; + + if (link->flags == (DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE)) + return; + + pm_runtime_drop_link(link); + link->flags = DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE; + dev_dbg(link->consumer, "Relaxing link with %s\n", + dev_name(link->supplier)); +} + +static int fw_devlink_no_driver(struct device *dev, void *data) +{ + struct device_link *link = to_devlink(dev); + + if (!link->supplier->can_match) + fw_devlink_relax_link(link); + + return 0; +} + +void fw_devlink_drivers_done(void) +{ + fw_devlink_drv_reg_done = true; + device_links_write_lock(); + class_for_each_device(&devlink_class, NULL, NULL, + fw_devlink_no_driver); + device_links_write_unlock(); +} + +static void fw_devlink_unblock_consumers(struct device *dev) +{ + struct device_link *link; + + if (!fw_devlink_flags || fw_devlink_is_permissive()) + return; + + device_links_write_lock(); + list_for_each_entry(link, &dev->links.consumers, s_node) + fw_devlink_relax_link(link); + device_links_write_unlock(); +} + /** * fw_devlink_relax_cycle - Convert cyclic links to SYNC_STATE_ONLY links * @con: Device to check dependencies for. @@ -1599,21 +1681,16 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup) ret = 1; - if (!(link->flags & DL_FLAG_INFERRED)) - continue; - - pm_runtime_drop_link(link); - link->flags = DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE; - dev_dbg(link->consumer, "Relaxing link with %s\n", - dev_name(link->supplier)); + fw_devlink_relax_link(link); } return ret; } /** * fw_devlink_create_devlink - Create a device link from a consumer to fwnode - * @con - Consumer device for the device link - * @sup_handle - fwnode handle of supplier + * @con: consumer device for the device link + * @sup_handle: fwnode handle of supplier + * @flags: devlink flags * * This function will try to create a device link between the consumer device * @con and the supplier device represented by @sup_handle. @@ -1709,7 +1786,7 @@ out: /** * __fw_devlink_link_to_consumers - Create device links to consumers of a device - * @dev - Device that needs to be linked to its consumers + * @dev: Device that needs to be linked to its consumers * * This function looks at all the consumer fwnodes of @dev and creates device * links between the consumer device and @dev (supplier). @@ -1779,8 +1856,8 @@ static void __fw_devlink_link_to_consumers(struct device *dev) /** * __fw_devlink_link_to_suppliers - Create device links to suppliers of a device - * @dev - The consumer device that needs to be linked to its suppliers - * @fwnode - Root of the fwnode tree that is used to create device links + * @dev: The consumer device that needs to be linked to its suppliers + * @fwnode: Root of the fwnode tree that is used to create device links * * This function looks at all the supplier fwnodes of fwnode tree rooted at * @fwnode and creates device links between @dev (consumer) and all the @@ -3240,6 +3317,15 @@ int device_add(struct device *dev) } bus_probe_device(dev); + + /* + * If all driver registration is done and a newly added device doesn't + * match with any driver, don't block its consumers from probing in + * case the consumer device is able to operate without this supplier. + */ + if (dev->fwnode && fw_devlink_drv_reg_done && !dev->can_match) + fw_devlink_unblock_consumers(dev); + if (parent) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 8f1d6569564c4099deea31b1ebfd2371481ee36a..2b9e41377a0705a5743775ba6d8837b3a190da13 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -409,13 +409,11 @@ __cpu_device_create(struct device *parent, void *drvdata, const char *fmt, va_list args) { struct device *dev = NULL; - int retval = -ENODEV; + int retval = -ENOMEM; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - retval = -ENOMEM; + if (!dev) goto error; - } device_initialize(dev); dev->parent = parent; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 37a5e5f8b2219e3a50d7d587a6d94c9d8da35971..ecd7cf848daff7ea3522cb18f568f2203c5a522b 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -55,7 +55,6 @@ static DEFINE_MUTEX(deferred_probe_mutex); static LIST_HEAD(deferred_probe_pending_list); static LIST_HEAD(deferred_probe_active_list); static atomic_t deferred_trigger_count = ATOMIC_INIT(0); -static struct dentry *deferred_devices; static bool initcalls_done; /* Save the async probe drivers' name from kernel cmdline */ @@ -69,6 +68,12 @@ static char async_probe_drv_names[ASYNC_DRV_NAMES_MAX_LEN]; */ static bool defer_all_probes; +static void __device_set_deferred_probe_reason(const struct device *dev, char *reason) +{ + kfree(dev->p->deferred_probe_reason); + dev->p->deferred_probe_reason = reason; +} + /* * deferred_probe_work_func() - Retry probing devices in the active list. */ @@ -97,8 +102,7 @@ static void deferred_probe_work_func(struct work_struct *work) get_device(dev); - kfree(dev->p->deferred_probe_reason); - dev->p->deferred_probe_reason = NULL; + __device_set_deferred_probe_reason(dev, NULL); /* * Drop the mutex while probing each device; the probe path may @@ -126,6 +130,9 @@ static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func); void driver_deferred_probe_add(struct device *dev) { + if (!dev->can_match) + return; + mutex_lock(&deferred_probe_mutex); if (list_empty(&dev->p->deferred_probe)) { dev_dbg(dev, "Added to deferred list\n"); @@ -140,8 +147,7 @@ void driver_deferred_probe_del(struct device *dev) if (!list_empty(&dev->p->deferred_probe)) { dev_dbg(dev, "Removed from deferred list\n"); list_del_init(&dev->p->deferred_probe); - kfree(dev->p->deferred_probe_reason); - dev->p->deferred_probe_reason = NULL; + __device_set_deferred_probe_reason(dev, NULL); } mutex_unlock(&deferred_probe_mutex); } @@ -185,7 +191,7 @@ static void driver_deferred_probe_trigger(void) * Kick the re-probe thread. It may already be scheduled, but it is * safe to kick it again. */ - schedule_work(&deferred_probe_work); + queue_work(system_unbound_wq, &deferred_probe_work); } /** @@ -220,11 +226,12 @@ void device_unblock_probing(void) void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf) { const char *drv = dev_driver_string(dev); + char *reason; mutex_lock(&deferred_probe_mutex); - kfree(dev->p->deferred_probe_reason); - dev->p->deferred_probe_reason = kasprintf(GFP_KERNEL, "%s: %pV", drv, vaf); + reason = kasprintf(GFP_KERNEL, "%s: %pV", drv, vaf); + __device_set_deferred_probe_reason(dev, reason); mutex_unlock(&deferred_probe_mutex); } @@ -294,6 +301,8 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) { struct device_private *p; + fw_devlink_drivers_done(); + driver_deferred_probe_timeout = 0; driver_deferred_probe_trigger(); flush_work(&deferred_probe_work); @@ -315,8 +324,8 @@ static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_ */ static int deferred_probe_initcall(void) { - deferred_devices = debugfs_create_file("devices_deferred", 0444, NULL, - NULL, &deferred_devs_fops); + debugfs_create_file("devices_deferred", 0444, NULL, NULL, + &deferred_devs_fops); driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); @@ -324,6 +333,9 @@ static int deferred_probe_initcall(void) flush_work(&deferred_probe_work); initcalls_done = true; + if (!IS_ENABLED(CONFIG_MODULES)) + fw_devlink_drivers_done(); + /* * Trigger deferred probe again, this time we won't defer anything * that is optional @@ -341,7 +353,7 @@ late_initcall(deferred_probe_initcall); static void __exit deferred_probe_exit(void) { - debugfs_remove_recursive(deferred_devices); + debugfs_remove_recursive(debugfs_lookup("devices_deferred", NULL)); } __exitcall(deferred_probe_exit); @@ -418,8 +430,11 @@ static int driver_sysfs_add(struct device *dev) if (ret) goto rm_dev; - if (!IS_ENABLED(CONFIG_DEV_COREDUMP) || !dev->driver->coredump || - !device_create_file(dev, &dev_attr_coredump)) + if (!IS_ENABLED(CONFIG_DEV_COREDUMP) || !dev->driver->coredump) + return 0; + + ret = device_create_file(dev, &dev_attr_coredump); + if (!ret) return 0; sysfs_remove_link(&dev->kobj, "driver"); @@ -462,8 +477,10 @@ int device_bind_driver(struct device *dev) int ret; ret = driver_sysfs_add(dev); - if (!ret) + if (!ret) { + device_links_force_bind(dev); driver_bound(dev); + } else if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DRIVER_NOT_BOUND, dev); @@ -731,6 +748,7 @@ static int driver_probe_device(struct device_driver *drv, struct device *dev) if (!device_is_registered(dev)) return -ENODEV; + dev->can_match = true; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); @@ -834,6 +852,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); + dev->can_match = true; driver_deferred_probe_add(dev); } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d\n", ret); @@ -1069,6 +1088,7 @@ static int __driver_attach(struct device *dev, void *data) return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); + dev->can_match = true; driver_deferred_probe_add(dev); } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d\n", ret); diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 9243468e2c99fd7b28541fe34d860eb0b0c4da23..8eec0e0ddff7b1ec40b585daed4977bf13914425 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -202,7 +202,7 @@ static int devcd_match_failing(struct device *dev, const void *failing) * NOTE: if two tables allocated with devcd_alloc_sgtable and then chained * using the sg_chain function then that function should be called only once * on the chained table - * @table: pointer to sg_table to free + * @data: pointer to sg_table to free */ static void devcd_free_sgtable(void *data) { @@ -210,7 +210,7 @@ static void devcd_free_sgtable(void *data) } /** - * devcd_read_from_table - copy data from sg_table to a given buffer + * devcd_read_from_sgtable - copy data from sg_table to a given buffer * and return the number of bytes read * @buffer: the buffer to copy the data to it * @buf_len: the length of the buffer @@ -292,13 +292,16 @@ void dev_coredumpm(struct device *dev, struct module *owner, if (device_add(&devcd->devcd_dev)) goto put_device; + /* + * These should normally not fail, but there is no problem + * continuing without the links, so just warn instead of + * failing. + */ if (sysfs_create_link(&devcd->devcd_dev.kobj, &dev->kobj, - "failing_device")) - /* nothing - symlink will be missing */; - - if (sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj, - "devcoredump")) - /* nothing - symlink will be missing */; + "failing_device") || + sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj, + "devcoredump")) + dev_warn(dev, "devcoredump create_link failed\n"); INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT); diff --git a/drivers/base/devres.c b/drivers/base/devres.c index fb9d5289a620338e42cf14e9f40046794c9f2d7c..8746f2212781b5153afa2307aee5dc6493248250 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -58,8 +58,8 @@ static void devres_log(struct device *dev, struct devres_node *node, const char *op) { if (unlikely(log_devres)) - dev_err(dev, "DEVRES %3s %p %s (%lu bytes)\n", - op, node, node->name, (unsigned long)node->size); + dev_err(dev, "DEVRES %3s %p %s (%zu bytes)\n", + op, node, node->name, node->size); } #else /* CONFIG_DEBUG_DEVRES */ #define set_node_dbginfo(node, n, s) do {} while (0) @@ -1228,6 +1228,6 @@ EXPORT_SYMBOL_GPL(__devm_alloc_percpu); void devm_free_percpu(struct device *dev, void __percpu *pdata) { WARN_ON(devres_destroy(dev, devm_percpu_release, devm_percpu_match, - (void *)pdata)); + (__force void *)pdata)); } EXPORT_SYMBOL_GPL(devm_free_percpu); diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 653c8c6ac7a73a2137598065b79a078fdaaf1841..8be352ab4ddbfdcfdda4885dde97c39b5477cf32 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -371,7 +371,7 @@ int __init devtmpfs_mount(void) return err; } -static DECLARE_COMPLETION(setup_done); +static __initdata DECLARE_COMPLETION(setup_done); static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid, struct device *dev) @@ -405,7 +405,7 @@ static void __noreturn devtmpfs_work_loop(void) } } -static int __init devtmpfs_setup(void *p) +static noinline int __init devtmpfs_setup(void *p) { int err; @@ -419,7 +419,6 @@ static int __init devtmpfs_setup(void *p) init_chroot("."); out: *(int *)p = err; - complete(&setup_done); return err; } @@ -432,6 +431,7 @@ static int __ref devtmpfsd(void *p) { int err = devtmpfs_setup(p); + complete(&setup_done); if (err) return err; devtmpfs_work_loop(); diff --git a/drivers/base/node.c b/drivers/base/node.c index f449dbb2c74666a83caabb55b39e8c9de31a622c..2c36f61d30bcb0d7c6b315c6dfcd8e1ee492722e 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -268,21 +268,20 @@ static void node_init_cache_dev(struct node *node) if (!dev) return; + device_initialize(dev); dev->parent = &node->dev; dev->release = node_cache_release; if (dev_set_name(dev, "memory_side_cache")) - goto free_dev; + goto put_device; - if (device_register(dev)) - goto free_name; + if (device_add(dev)) + goto put_device; pm_runtime_no_callbacks(dev); node->cache_dev = dev; return; -free_name: - kfree_const(dev->kobj.name); -free_dev: - kfree(dev); +put_device: + put_device(dev); } /** @@ -319,25 +318,24 @@ void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs) return; dev = &info->dev; + device_initialize(dev); dev->parent = node->cache_dev; dev->release = node_cacheinfo_release; dev->groups = cache_groups; if (dev_set_name(dev, "index%d", cache_attrs->level)) - goto free_cache; + goto put_device; info->cache_attrs = *cache_attrs; - if (device_register(dev)) { + if (device_add(dev)) { dev_warn(&node->dev, "failed to add cache level:%d\n", cache_attrs->level); - goto free_name; + goto put_device; } pm_runtime_no_callbacks(dev); list_add_tail(&info->node, &node->cache_attrs); return; -free_name: - kfree_const(dev->kobj.name); -free_cache: - kfree(info); +put_device: + put_device(dev); } static void node_remove_caches(struct node *node) diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 2c1e2e0c1a59cc5f037f57aec963c8fcfa04a8e2..0b72b134a3048971345c96f0aedbe1fdbac5f671 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -316,10 +316,11 @@ void *platform_msi_get_host_data(struct irq_domain *domain) } /** - * platform_msi_create_device_domain - Create a platform-msi domain + * __platform_msi_create_device_domain - Create a platform-msi domain * * @dev: The device generating the MSIs * @nvec: The number of MSIs that need to be allocated + * @is_tree: flag to indicate tree hierarchy * @write_msi_msg: Callback to write an interrupt message for @dev * @ops: The hierarchy domain operations to use * @host_data: Private data associated to this domain diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 6e1f8e0b661cef101dc6d4a01ad56beea41345d5..9cd34def2237b8a27eb827863826dbe51cca6709 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -192,7 +192,7 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num) #ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ if (!dev || num >= dev->archdata.num_irqs) - return -ENXIO; + goto out_not_found; ret = dev->archdata.irqs[num]; goto out; #else @@ -223,10 +223,8 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num) struct irq_data *irqd; irqd = irq_get_irq_data(r->start); - if (!irqd) { - ret = -ENXIO; - goto out; - } + if (!irqd) + goto out_not_found; irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); } @@ -249,8 +247,9 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num) goto out; } - ret = -ENXIO; #endif +out_not_found: + ret = -ENXIO; out: WARN(ret == 0, "0 is an invalid IRQ number\n"); return ret; diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 84d5acb6301b751152ae6f28af5a76f0b1df16c0..0251f3e6e61d5036418b03fd258b98520408463d 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -140,7 +140,7 @@ static void pm_clk_op_unlock(struct pm_subsys_data *psd, unsigned long *flags) } /** - * pm_clk_enable - Enable a clock, reporting any errors + * __pm_clk_enable - Enable a clock, reporting any errors * @dev: The device for the given clock * @ce: PM clock entry corresponding to the clock. */ diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 78c310d3179d36b67c59a62e6ceda8d2f0f774d4..b6a782c3161387db4f1582231249398ac54a4cab 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1087,34 +1087,6 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, genpd->status = GENPD_STATE_ON; } -/** - * resume_needed - Check whether to resume a device before system suspend. - * @dev: Device to check. - * @genpd: PM domain the device belongs to. - * - * There are two cases in which a device that can wake up the system from sleep - * states should be resumed by genpd_prepare(): (1) if the device is enabled - * to wake up the system and it has to remain active for this purpose while the - * system is in the sleep state and (2) if the device is not enabled to wake up - * the system from sleep states and it generally doesn't generate wakeup signals - * by itself (those signals are generated on its behalf by other parts of the - * system). In the latter case it may be necessary to reconfigure the device's - * wakeup settings during system suspend, because it may have been set up to - * signal remote wakeup from the system's working state as needed by runtime PM. - * Return 'true' in either of the above cases. - */ -static bool resume_needed(struct device *dev, - const struct generic_pm_domain *genpd) -{ - bool active_wakeup; - - if (!device_can_wakeup(dev)) - return false; - - active_wakeup = genpd_is_active_wakeup(genpd); - return device_may_wakeup(dev) ? active_wakeup : !active_wakeup; -} - /** * genpd_prepare - Start power transition of a device in a PM domain. * @dev: Device to start the transition of. @@ -1135,14 +1107,6 @@ static int genpd_prepare(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - /* - * If a wakeup request is pending for the device, it should be woken up - * at this point and a system wakeup event should be reported if it's - * set up to wake up the system from sleep states. - */ - if (resume_needed(dev, genpd)) - pm_runtime_resume(dev); - genpd_lock(genpd); if (genpd->prepared_count++ == 0) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index fe1dad68aee4dd61537f66ff42afa69d4a870607..1fc1a992f90caa07fd607ebbb4a2d0a1a80b26a2 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -951,7 +951,7 @@ static void pm_runtime_work(struct work_struct *work) /** * pm_suspend_timer_fn - Timer function for pm_schedule_suspend(). - * @data: Device pointer passed by pm_schedule_suspend(). + * @timer: hrtimer used by pm_schedule_suspend(). * * Check if the time is right and queue a suspend request. */ diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 01057f640233075f61844f9c5b2b0efe29690b2c..ed00775f531e9fca451fdac39f1994e2fe201c02 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -403,9 +403,9 @@ void device_wakeup_detach_irq(struct device *dev) } /** - * device_wakeup_arm_wake_irqs(void) + * device_wakeup_arm_wake_irqs - * - * Itereates over the list of device wakeirqs to arm them. + * Iterates over the list of device wakeirqs to arm them. */ void device_wakeup_arm_wake_irqs(void) { @@ -419,9 +419,9 @@ void device_wakeup_arm_wake_irqs(void) } /** - * device_wakeup_disarm_wake_irqs(void) + * device_wakeup_disarm_wake_irqs - * - * Itereates over the list of device wakeirqs to disarm them. + * Iterates over the list of device wakeirqs to disarm them. */ void device_wakeup_disarm_wake_irqs(void) { @@ -535,6 +535,7 @@ EXPORT_SYMBOL_GPL(device_init_wakeup); /** * device_set_wakeup_enable - Enable or disable a device to wake up the system. * @dev: Device to handle. + * @enable: enable/disable flag */ int device_set_wakeup_enable(struct device *dev, bool enable) { @@ -584,7 +585,7 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws) */ /** - * wakup_source_activate - Mark given wakeup source as active. + * wakeup_source_activate - Mark given wakeup source as active. * @ws: Wakeup source to handle. * * Update the @ws' statistics and, if @ws has just been activated, notify the PM @@ -689,7 +690,7 @@ static inline void update_prevent_sleep_time(struct wakeup_source *ws, #endif /** - * wakup_source_deactivate - Mark given wakeup source as inactive. + * wakeup_source_deactivate - Mark given wakeup source as inactive. * @ws: Wakeup source to handle. * * Update the @ws' statistics and notify the PM core that the wakeup source has @@ -788,7 +789,7 @@ EXPORT_SYMBOL_GPL(pm_relax); /** * pm_wakeup_timer_fn - Delayed finalization of a wakeup event. - * @data: Address of the wakeup source object associated with the event source. + * @t: timer list * * Call wakeup_source_deactivate() for the wakeup source whose address is stored * in @data if it is currently active and its timer has not been canceled and @@ -1072,7 +1073,7 @@ bool pm_save_wakeup_count(unsigned int count) #ifdef CONFIG_PM_AUTOSLEEP /** * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources. - * @enabled: Whether to set or to clear the autosleep_enabled flags. + * @set: Whether to set or to clear the autosleep_enabled flags. */ void pm_wakep_autosleep_enabled(bool set) { diff --git a/drivers/base/power/wakeup_stats.c b/drivers/base/power/wakeup_stats.c index d638259b829a5ef24303f874cbe2405722fbeae6..924fac493c4f24840bef4932707253bc0805c57a 100644 --- a/drivers/base/power/wakeup_stats.c +++ b/drivers/base/power/wakeup_stats.c @@ -137,7 +137,7 @@ static struct device *wakeup_source_device_create(struct device *parent, struct wakeup_source *ws) { struct device *dev = NULL; - int retval = -ENODEV; + int retval; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { @@ -154,7 +154,7 @@ static struct device *wakeup_source_device_create(struct device *parent, dev_set_drvdata(dev, ws); device_set_pm_not_required(dev); - retval = kobject_set_name(&dev->kobj, "wakeup%d", ws->id); + retval = dev_set_name(dev, "wakeup%d", ws->id); if (retval) goto error; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index ff2ee87987c7e6b194588713f19a38fbcacd0308..211a335a608d7acc7cda755a45302b5544c25464 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -660,6 +660,7 @@ void regmap_debugfs_exit(struct regmap *map) regmap_debugfs_free_dump_cache(map); mutex_unlock(&map->cache_lock); kfree(map->debugfs_name); + map->debugfs_name = NULL; } else { struct regmap_debugfs_node *node, *tmp; diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 19db764ffa4ab21de2043565416e70ed1df7faea..760296a4b6062ab7ebb25d874a4ad23130b23eeb 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -38,6 +38,7 @@ struct regmap_irq_chip_data { unsigned int *wake_buf; unsigned int *type_buf; unsigned int *type_buf_def; + unsigned int **virt_buf; unsigned int irq_reg_stride; unsigned int type_reg_stride; @@ -45,6 +46,27 @@ struct regmap_irq_chip_data { bool clear_status:1; }; +static int sub_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base_reg, int i) +{ + const struct regmap_irq_chip *chip = data->chip; + struct regmap *map = data->map; + struct regmap_irq_sub_irq_map *subreg; + unsigned int offset; + int reg = 0; + + if (!chip->sub_reg_offsets || !chip->not_fixed_stride) { + /* Assume linear mapping */ + reg = base_reg + (i * map->reg_stride * data->irq_reg_stride); + } else { + subreg = &chip->sub_reg_offsets[i]; + offset = subreg->offset[0]; + reg = base_reg + offset; + } + + return reg; +} + static inline const struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data, int irq) @@ -73,7 +95,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) { struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); struct regmap *map = d->map; - int i, ret; + int i, j, ret; u32 reg; u32 unmask_offset; u32 val; @@ -87,8 +109,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) if (d->clear_status) { for (i = 0; i < d->chip->num_regs; i++) { - reg = d->chip->status_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->status_base, i); ret = regmap_read(map, reg, &val); if (ret) @@ -108,8 +129,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) if (!d->chip->mask_base) continue; - reg = d->chip->mask_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->mask_base, i); if (d->chip->mask_invert) { ret = regmap_irq_update_bits(d, reg, d->mask_buf_def[i], ~d->mask_buf[i]); @@ -136,8 +156,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) dev_err(d->map->dev, "Failed to sync masks in %x\n", reg); - reg = d->chip->wake_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->wake_base, i); if (d->wake_buf) { if (d->chip->wake_invert) ret = regmap_irq_update_bits(d, reg, @@ -161,8 +180,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data) * it'll be ignored in irq handler, then may introduce irq storm */ if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) { - reg = d->chip->ack_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->ack_base, i); + /* some chips ack by write 0 */ if (d->chip->ack_invert) ret = regmap_write(map, reg, ~d->mask_buf[i]); @@ -187,8 +206,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) for (i = 0; i < d->chip->num_type_reg; i++) { if (!d->type_buf_def[i]) continue; - reg = d->chip->type_base + - (i * map->reg_stride * d->type_reg_stride); + reg = sub_irq_reg(d, d->chip->type_base, i); if (d->chip->type_invert) ret = regmap_irq_update_bits(d, reg, d->type_buf_def[i], ~d->type_buf[i]); @@ -201,6 +219,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data) } } + if (d->chip->num_virt_regs) { + for (i = 0; i < d->chip->num_virt_regs; i++) { + for (j = 0; j < d->chip->num_regs; j++) { + reg = sub_irq_reg(d, d->chip->virt_reg_base[i], + j); + ret = regmap_write(map, reg, d->virt_buf[i][j]); + if (ret != 0) + dev_err(d->map->dev, + "Failed to write virt 0x%x: %d\n", + reg, ret); + } + } + } + if (d->chip->runtime_pm) pm_runtime_put(map->dev); @@ -301,6 +333,11 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type) default: return -EINVAL; } + + if (d->chip->set_type_virt) + return d->chip->set_type_virt(d->virt_buf, type, data->hwirq, + reg); + return 0; } @@ -352,8 +389,15 @@ static inline int read_sub_irq_data(struct regmap_irq_chip_data *data, for (i = 0; i < subreg->num_regs; i++) { unsigned int offset = subreg->offset[i]; - ret = regmap_read(map, chip->status_base + offset, - &data->status_buf[offset]); + if (chip->not_fixed_stride) + ret = regmap_read(map, + chip->status_base + offset, + &data->status_buf[b]); + else + ret = regmap_read(map, + chip->status_base + offset, + &data->status_buf[offset]); + if (ret) break; } @@ -474,10 +518,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) } else { for (i = 0; i < data->chip->num_regs; i++) { - ret = regmap_read(map, chip->status_base + - (i * map->reg_stride - * data->irq_reg_stride), - &data->status_buf[i]); + unsigned int reg = sub_irq_reg(data, + data->chip->status_base, i); + ret = regmap_read(map, reg, &data->status_buf[i]); if (ret != 0) { dev_err(map->dev, @@ -499,8 +542,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) data->status_buf[i] &= ~data->mask_buf[i]; if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) { - reg = chip->ack_base + - (i * map->reg_stride * data->irq_reg_stride); + reg = sub_irq_reg(data, data->chip->ack_base, i); + if (chip->ack_invert) ret = regmap_write(map, reg, ~data->status_buf[i]); @@ -605,6 +648,12 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, return -EINVAL; } + if (chip->not_fixed_stride) { + for (i = 0; i < chip->num_regs; i++) + if (chip->sub_reg_offsets[i].num_regs != 1) + return -EINVAL; + } + if (irq_base) { irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0); if (irq_base < 0) { @@ -662,6 +711,24 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, goto err_alloc; } + if (chip->num_virt_regs) { + /* + * Create virt_buf[chip->num_extra_config_regs][chip->num_regs] + */ + d->virt_buf = kcalloc(chip->num_virt_regs, sizeof(*d->virt_buf), + GFP_KERNEL); + if (!d->virt_buf) + goto err_alloc; + + for (i = 0; i < chip->num_virt_regs; i++) { + d->virt_buf[i] = kcalloc(chip->num_regs, + sizeof(unsigned int), + GFP_KERNEL); + if (!d->virt_buf[i]) + goto err_alloc; + } + } + d->irq_chip = regmap_irq_chip; d->irq_chip.name = chip->name; d->irq = irq; @@ -700,8 +767,8 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, if (!chip->mask_base) continue; - reg = chip->mask_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->mask_base, i); + if (chip->mask_invert) ret = regmap_irq_update_bits(d, reg, d->mask_buf[i], ~d->mask_buf[i]); @@ -725,8 +792,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, continue; /* Ack masked but set interrupts */ - reg = chip->status_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->status_base, i); ret = regmap_read(map, reg, &d->status_buf[i]); if (ret != 0) { dev_err(map->dev, "Failed to read IRQ status: %d\n", @@ -735,8 +801,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, } if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) { - reg = chip->ack_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->ack_base, i); if (chip->ack_invert) ret = regmap_write(map, reg, ~(d->status_buf[i] & d->mask_buf[i])); @@ -765,8 +830,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, if (d->wake_buf) { for (i = 0; i < chip->num_regs; i++) { d->wake_buf[i] = d->mask_buf_def[i]; - reg = chip->wake_base + - (i * map->reg_stride * d->irq_reg_stride); + reg = sub_irq_reg(d, d->chip->wake_base, i); if (chip->wake_invert) ret = regmap_irq_update_bits(d, reg, @@ -786,8 +850,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, if (chip->num_type_reg && !chip->type_in_mask) { for (i = 0; i < chip->num_type_reg; ++i) { - reg = chip->type_base + - (i * map->reg_stride * d->type_reg_stride); + reg = sub_irq_reg(d, d->chip->type_base, i); ret = regmap_read(map, reg, &d->type_buf_def[i]); @@ -838,6 +901,11 @@ err_alloc: kfree(d->mask_buf); kfree(d->status_buf); kfree(d->status_reg_buf); + if (d->virt_buf) { + for (i = 0; i < chip->num_virt_regs; i++) + kfree(d->virt_buf[i]); + kfree(d->virt_buf); + } kfree(d); return ret; } diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index fa3719ef80e4d12b93655189ed4cec22075a04e0..3cc11b813f28ca8ff6cb508b83cd3d1d2c996cce 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -12,10 +12,10 @@ #include <linux/slab.h> struct swnode { - int id; struct kobject kobj; struct fwnode_handle fwnode; const struct software_node *node; + int id; /* hierarchy */ struct ida child_ids; @@ -720,19 +720,30 @@ software_node_find_by_name(const struct software_node *parent, const char *name) } EXPORT_SYMBOL_GPL(software_node_find_by_name); -static int -software_node_register_properties(struct software_node *node, - const struct property_entry *properties) +static struct software_node *software_node_alloc(const struct property_entry *properties) { struct property_entry *props; + struct software_node *node; props = property_entries_dup(properties); if (IS_ERR(props)) - return PTR_ERR(props); + return ERR_CAST(props); + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + property_entries_free(props); + return ERR_PTR(-ENOMEM); + } node->properties = props; - return 0; + return node; +} + +static void software_node_free(const struct software_node *node) +{ + property_entries_free(node->properties); + kfree(node); } static void software_node_release(struct kobject *kobj) @@ -746,10 +757,9 @@ static void software_node_release(struct kobject *kobj) ida_simple_remove(&swnode_root_ids, swnode->id); } - if (swnode->allocated) { - property_entries_free(swnode->node->properties); - kfree(swnode->node); - } + if (swnode->allocated) + software_node_free(swnode->node); + ida_destroy(&swnode->child_ids); kfree(swnode); } @@ -767,22 +777,19 @@ swnode_register(const struct software_node *node, struct swnode *parent, int ret; swnode = kzalloc(sizeof(*swnode), GFP_KERNEL); - if (!swnode) { - ret = -ENOMEM; - goto out_err; - } + if (!swnode) + return ERR_PTR(-ENOMEM); ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids, 0, 0, GFP_KERNEL); if (ret < 0) { kfree(swnode); - goto out_err; + return ERR_PTR(ret); } swnode->id = ret; swnode->node = node; swnode->parent = parent; - swnode->allocated = allocated; swnode->kobj.kset = swnode_kset; fwnode_init(&swnode->fwnode, &software_node_ops); @@ -803,16 +810,17 @@ swnode_register(const struct software_node *node, struct swnode *parent, return ERR_PTR(ret); } + /* + * Assign the flag only in the successful case, so + * the above kobject_put() won't mess up with properties. + */ + swnode->allocated = allocated; + if (parent) list_add_tail(&swnode->entry, &parent->children); kobject_uevent(&swnode->kobj, KOBJ_ADD); return &swnode->fwnode; - -out_err: - if (allocated) - property_entries_free(node->properties); - return ERR_PTR(ret); } /** @@ -880,7 +888,11 @@ EXPORT_SYMBOL_GPL(software_node_unregister_nodes); * software_node_register_node_group - Register a group of software nodes * @node_group: NULL terminated array of software node pointers to be registered * - * Register multiple software nodes at once. + * Register multiple software nodes at once. If any node in the array + * has its .parent pointer set (which can only be to another software_node), + * then its parent **must** have been registered before it is; either outside + * of this function or by ordering the array such that parent comes before + * child. */ int software_node_register_node_group(const struct software_node **node_group) { @@ -906,10 +918,14 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group); * software_node_unregister_node_group - Unregister a group of software nodes * @node_group: NULL terminated array of software node pointers to be unregistered * - * Unregister multiple software nodes at once. The array will be unwound in - * reverse order (i.e. last entry first) and thus if any members of the array are - * children of another member then the children must appear later in the list such - * that they are unregistered first. + * Unregister multiple software nodes at once. If parent pointers are set up + * in any of the software nodes then the array **must** be ordered such that + * parents come before their children. + * + * NOTE: If you are uncertain whether the array is ordered such that + * parents will be unregistered before their children, it is wiser to + * remove the nodes individually, in the correct order (child before + * parent). */ void software_node_unregister_node_group( const struct software_node **node_group) @@ -963,31 +979,28 @@ struct fwnode_handle * fwnode_create_software_node(const struct property_entry *properties, const struct fwnode_handle *parent) { + struct fwnode_handle *fwnode; struct software_node *node; - struct swnode *p = NULL; - int ret; + struct swnode *p; - if (parent) { - if (IS_ERR(parent)) - return ERR_CAST(parent); - if (!is_software_node(parent)) - return ERR_PTR(-EINVAL); - p = to_swnode(parent); - } + if (IS_ERR(parent)) + return ERR_CAST(parent); - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - return ERR_PTR(-ENOMEM); + p = to_swnode(parent); + if (parent && !p) + return ERR_PTR(-EINVAL); - ret = software_node_register_properties(node, properties); - if (ret) { - kfree(node); - return ERR_PTR(ret); - } + node = software_node_alloc(properties); + if (IS_ERR(node)) + return ERR_CAST(node); node->parent = p ? p->node : NULL; - return swnode_register(node, p, 1); + fwnode = swnode_register(node, p, 1); + if (IS_ERR(fwnode)) + software_node_free(node); + + return fwnode; } EXPORT_SYMBOL_GPL(fwnode_create_software_node); @@ -1032,6 +1045,7 @@ int device_add_software_node(struct device *dev, const struct software_node *nod } set_secondary_fwnode(dev, &swnode->fwnode); + software_node_notify(dev, KOBJ_ADD); return 0; } @@ -1105,8 +1119,8 @@ int software_node_notify(struct device *dev, unsigned long action) switch (action) { case KOBJ_ADD: - ret = sysfs_create_link(&dev->kobj, &swnode->kobj, - "software_node"); + ret = sysfs_create_link_nowarn(&dev->kobj, &swnode->kobj, + "software_node"); if (ret) break; diff --git a/drivers/base/test/Kconfig b/drivers/base/test/Kconfig index ba225eb1b7615fb6a56996acd3c18cbba773afe8..2f3fa31a948e2e86f6e9753a304443110a29fcc6 100644 --- a/drivers/base/test/Kconfig +++ b/drivers/base/test/Kconfig @@ -8,7 +8,7 @@ config TEST_ASYNC_DRIVER_PROBE The module name will be test_async_driver_probe.ko If unsure say N. -config KUNIT_DRIVER_PE_TEST +config DRIVER_PE_KUNIT_TEST bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS depends on KUNIT=y default KUNIT_ALL_TESTS diff --git a/drivers/base/test/Makefile b/drivers/base/test/Makefile index 2f15fae8625f191d42fd80f594d86fcb5a8fe4c5..64b2f3d744d51aa91d98d64012adb8fce6bae54b 100644 --- a/drivers/base/test/Makefile +++ b/drivers/base/test/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o -obj-$(CONFIG_KUNIT_DRIVER_PE_TEST) += property-entry-test.o +obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o CFLAGS_REMOVE_property-entry-test.o += -fplugin-arg-structleak_plugin-byref -fplugin-arg-structleak_plugin-byref-all diff --git a/drivers/base/test/property-entry-test.c b/drivers/base/test/property-entry-test.c index abe03315180ff9a2d77c25b541a6b08e07d498bb..1106fedcceed88aad2e6fdb83eeff7c846b5a577 100644 --- a/drivers/base/test/property-entry-test.c +++ b/drivers/base/test/property-entry-test.c @@ -27,6 +27,9 @@ static void pe_test_uints(struct kunit *test) node = fwnode_create_software_node(entries, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); + error = fwnode_property_count_u8(node, "prop-u8"); + KUNIT_EXPECT_EQ(test, error, 1); + error = fwnode_property_read_u8(node, "prop-u8", &val_u8); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u8, 8); @@ -48,6 +51,9 @@ static void pe_test_uints(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u16, 16); + error = fwnode_property_count_u16(node, "prop-u16"); + KUNIT_EXPECT_EQ(test, error, 1); + error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16); @@ -65,6 +71,9 @@ static void pe_test_uints(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u32, 32); + error = fwnode_property_count_u32(node, "prop-u32"); + KUNIT_EXPECT_EQ(test, error, 1); + error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32); @@ -82,6 +91,9 @@ static void pe_test_uints(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u64, 64); + error = fwnode_property_count_u64(node, "prop-u64"); + KUNIT_EXPECT_EQ(test, error, 1); + error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64); @@ -95,15 +107,19 @@ static void pe_test_uints(struct kunit *test) error = fwnode_property_read_u64_array(node, "no-prop-u64", array_u64, 1); KUNIT_EXPECT_NE(test, error, 0); + /* Count 64-bit values as 16-bit */ + error = fwnode_property_count_u16(node, "prop-u64"); + KUNIT_EXPECT_EQ(test, error, 4); + fwnode_remove_software_node(node); } static void pe_test_uint_arrays(struct kunit *test) { - static const u8 a_u8[16] = { 8, 9 }; - static const u16 a_u16[16] = { 16, 17 }; - static const u32 a_u32[16] = { 32, 33 }; - static const u64 a_u64[16] = { 64, 65 }; + static const u8 a_u8[10] = { 8, 9 }; + static const u16 a_u16[10] = { 16, 17 }; + static const u32 a_u32[10] = { 32, 33 }; + static const u64 a_u64[10] = { 64, 65 }; static const struct property_entry entries[] = { PROPERTY_ENTRY_U8_ARRAY("prop-u8", a_u8), PROPERTY_ENTRY_U16_ARRAY("prop-u16", a_u16), @@ -126,6 +142,9 @@ static void pe_test_uint_arrays(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u8, 8); + error = fwnode_property_count_u8(node, "prop-u8"); + KUNIT_EXPECT_EQ(test, error, 10); + error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8); @@ -148,6 +167,9 @@ static void pe_test_uint_arrays(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u16, 16); + error = fwnode_property_count_u16(node, "prop-u16"); + KUNIT_EXPECT_EQ(test, error, 10); + error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16); @@ -170,6 +192,9 @@ static void pe_test_uint_arrays(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u32, 32); + error = fwnode_property_count_u32(node, "prop-u32"); + KUNIT_EXPECT_EQ(test, error, 10); + error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32); @@ -192,6 +217,9 @@ static void pe_test_uint_arrays(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)val_u64, 64); + error = fwnode_property_count_u64(node, "prop-u64"); + KUNIT_EXPECT_EQ(test, error, 10); + error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 1); KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64); @@ -210,6 +238,14 @@ static void pe_test_uint_arrays(struct kunit *test) error = fwnode_property_read_u64_array(node, "no-prop-u64", array_u64, 1); KUNIT_EXPECT_NE(test, error, 0); + /* Count 64-bit values as 16-bit */ + error = fwnode_property_count_u16(node, "prop-u64"); + KUNIT_EXPECT_EQ(test, error, 40); + + /* Other way around */ + error = fwnode_property_count_u64(node, "prop-u16"); + KUNIT_EXPECT_EQ(test, error, 2); + fwnode_remove_software_node(node); } @@ -239,6 +275,9 @@ static void pe_test_strings(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_STREQ(test, str, "single"); + error = fwnode_property_string_array_count(node, "str"); + KUNIT_EXPECT_EQ(test, error, 1); + error = fwnode_property_read_string_array(node, "str", strs, 1); KUNIT_EXPECT_EQ(test, error, 1); KUNIT_EXPECT_STREQ(test, strs[0], "single"); @@ -258,6 +297,9 @@ static void pe_test_strings(struct kunit *test) KUNIT_EXPECT_EQ(test, error, 0); KUNIT_EXPECT_STREQ(test, str, ""); + error = fwnode_property_string_array_count(node, "strs"); + KUNIT_EXPECT_EQ(test, error, 2); + error = fwnode_property_read_string_array(node, "strs", strs, 3); KUNIT_EXPECT_EQ(test, error, 2); KUNIT_EXPECT_STREQ(test, strs[0], "string-a"); @@ -370,15 +412,8 @@ static void pe_test_reference(struct kunit *test) }; static const struct software_node_ref_args refs[] = { - { - .node = &nodes[0], - .nargs = 0, - }, - { - .node = &nodes[1], - .nargs = 2, - .args = { 3, 4 }, - }, + SOFTWARE_NODE_REFERENCE(&nodes[0]), + SOFTWARE_NODE_REFERENCE(&nodes[1], 3, 4), }; const struct property_entry entries[] = { diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index b0c71d3a81a024375c6b789affb97728ea6b2ac2..bda5c815e44156da9a2ba660cf5150156d171721 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -313,6 +313,7 @@ struct xen_blkif { struct work_struct free_work; unsigned int nr_ring_pages; + bool multi_ref; /* All rings for this device. */ struct xen_blkif_ring *rings; unsigned int nr_rings; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index c2aaf690352c7aee1229bcdeb0169ef6db6610e2..125b22205d3836220cf7f8c2f23d77cfa310430f 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -998,14 +998,17 @@ static int read_per_ring_refs(struct xen_blkif_ring *ring, const char *dir) for (i = 0; i < nr_grefs; i++) { char ring_ref_name[RINGREF_NAME_LEN]; - snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i); + if (blkif->multi_ref) + snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i); + else { + WARN_ON(i != 0); + snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref"); + } + err = xenbus_scanf(XBT_NIL, dir, ring_ref_name, "%u", &ring_ref[i]); if (err != 1) { - if (nr_grefs == 1) - break; - err = -EINVAL; xenbus_dev_fatal(dev, err, "reading %s/%s", dir, ring_ref_name); @@ -1013,18 +1016,6 @@ static int read_per_ring_refs(struct xen_blkif_ring *ring, const char *dir) } } - if (err != 1) { - WARN_ON(nr_grefs != 1); - - err = xenbus_scanf(XBT_NIL, dir, "ring-ref", "%u", - &ring_ref[0]); - if (err != 1) { - err = -EINVAL; - xenbus_dev_fatal(dev, err, "reading %s/ring-ref", dir); - return err; - } - } - err = -ENOMEM; for (i = 0; i < nr_grefs * XEN_BLKIF_REQS_PER_PAGE; i++) { req = kzalloc(sizeof(*req), GFP_KERNEL); @@ -1129,10 +1120,15 @@ static int connect_ring(struct backend_info *be) blkif->nr_rings, blkif->blk_protocol, protocol, blkif->vbd.feature_gnt_persistent ? "persistent grants" : ""); - ring_page_order = xenbus_read_unsigned(dev->otherend, - "ring-page-order", 0); - - if (ring_page_order > xen_blkif_max_ring_order) { + err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-page-order", "%u", + &ring_page_order); + if (err != 1) { + blkif->nr_ring_pages = 1; + blkif->multi_ref = false; + } else if (ring_page_order <= xen_blkif_max_ring_order) { + blkif->nr_ring_pages = 1 << ring_page_order; + blkif->multi_ref = true; + } else { err = -EINVAL; xenbus_dev_fatal(dev, err, "requested ring page order %d exceed max:%d", @@ -1141,8 +1137,6 @@ static int connect_ring(struct backend_info *be) return err; } - blkif->nr_ring_pages = 1 << ring_page_order; - if (blkif->nr_rings == 1) return read_per_ring_refs(&blkif->rings[0], dev->otherend); else { diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index e1c6798889f48afe9e6fc14a8ef5d93f919d365c..06c4efd97780013341ade3232aca246972f08f8b 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2397,7 +2397,7 @@ static void blkfront_connect(struct blkfront_info *info) } /* - * physcial-sector-size is a newer field, so old backends may not + * physical-sector-size is a newer field, so old backends may not * provide this. Assume physical sector size to be the same as * sector_size in that case. */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 637c5b8c2aa1a545c1b07a16df3b196489149144..71a4ca505e09e6b339d56940663ccd892a733ed1 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -821,7 +821,6 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty, static struct tty_ldisc_ops hci_uart_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_hci", .open = hci_uart_tty_open, .close = hci_uart_tty_close, diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index c2546bf229fb362d49d666596715a1dab4291403..8100cf51cd09e7e02dff5282baa0181bc64d168e 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -389,7 +389,6 @@ static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl, void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) { const struct firmware *firmware = NULL; - struct image_info *image_info; struct device *dev = &mhi_cntrl->mhi_dev->dev; const char *fw_name; void *buf; @@ -417,9 +416,9 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) } } - /* If device is in pass through, do reset to ready state transition */ - if (mhi_cntrl->ee == MHI_EE_PTHRU) - goto fw_load_ee_pthru; + /* wait for ready on pass through or any other execution environment */ + if (mhi_cntrl->ee != MHI_EE_EDL && mhi_cntrl->ee != MHI_EE_PBL) + goto fw_load_ready_state; fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ? mhi_cntrl->edl_image : mhi_cntrl->fw_image; @@ -461,9 +460,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) goto error_fw_load; } - if (mhi_cntrl->ee == MHI_EE_EDL) { + /* Wait for ready since EDL image was loaded */ + if (fw_name == mhi_cntrl->edl_image) { release_firmware(firmware); - return; + goto fw_load_ready_state; } write_lock_irq(&mhi_cntrl->pm_lock); @@ -488,47 +488,45 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) release_firmware(firmware); -fw_load_ee_pthru: +fw_load_ready_state: /* Transitioning into MHI RESET->READY state */ ret = mhi_ready_state_transition(mhi_cntrl); - - if (!mhi_cntrl->fbc_download) - return; - if (ret) { dev_err(dev, "MHI did not enter READY state\n"); goto error_ready_state; } - /* Wait for the SBL event */ - ret = wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_SBL || - MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), - msecs_to_jiffies(mhi_cntrl->timeout_ms)); + dev_info(dev, "Wait for device to enter SBL or Mission mode\n"); + return; - if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - dev_err(dev, "MHI did not enter SBL\n"); - goto error_ready_state; +error_ready_state: + if (mhi_cntrl->fbc_download) { + mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); + mhi_cntrl->fbc_image = NULL; } - /* Start full firmware image download */ - image_info = mhi_cntrl->fbc_image; +error_fw_load: + mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; + wake_up_all(&mhi_cntrl->state_event); +} + +int mhi_download_amss_image(struct mhi_controller *mhi_cntrl) +{ + struct image_info *image_info = mhi_cntrl->fbc_image; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + int ret; + + if (!image_info) + return -EIO; + ret = mhi_fw_load_bhie(mhi_cntrl, /* Vector table is the last entry */ &image_info->mhi_buf[image_info->entries - 1]); if (ret) { - dev_err(dev, "MHI did not load image over BHIe, ret: %d\n", - ret); - goto error_fw_load; + dev_err(dev, "MHI did not load AMSS, ret:%d\n", ret); + mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; + wake_up_all(&mhi_cntrl->state_event); } - return; - -error_ready_state: - mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); - mhi_cntrl->fbc_image = NULL; - -error_fw_load: - mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; - wake_up_all(&mhi_cntrl->state_event); + return ret; } diff --git a/drivers/bus/mhi/core/debugfs.c b/drivers/bus/mhi/core/debugfs.c index 7d43138ce66d8408a1f09c91a2a76ec0f8693a15..858d7516410bb75e9aea5692cbc9eed4e9a66400 100644 --- a/drivers/bus/mhi/core/debugfs.c +++ b/drivers/bus/mhi/core/debugfs.c @@ -377,7 +377,7 @@ static struct dentry *mhi_debugfs_root; void mhi_create_debugfs(struct mhi_controller *mhi_cntrl) { mhi_cntrl->debugfs_dentry = - debugfs_create_dir(dev_name(mhi_cntrl->cntrl_dev), + debugfs_create_dir(dev_name(&mhi_cntrl->mhi_dev->dev), mhi_debugfs_root); debugfs_create_file("states", 0444, mhi_cntrl->debugfs_dentry, diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index be4eebb0971bc18270371f9c10dd9071f9b80cbf..c81b377fca8f7e7b0bf6e96c0b9c3f32ca22eb94 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -22,13 +22,14 @@ static DEFINE_IDA(mhi_controller_ida); const char * const mhi_ee_str[MHI_EE_MAX] = { - [MHI_EE_PBL] = "PBL", - [MHI_EE_SBL] = "SBL", - [MHI_EE_AMSS] = "AMSS", - [MHI_EE_RDDM] = "RDDM", - [MHI_EE_WFW] = "WFW", - [MHI_EE_PTHRU] = "PASS THRU", - [MHI_EE_EDL] = "EDL", + [MHI_EE_PBL] = "PRIMARY BOOTLOADER", + [MHI_EE_SBL] = "SECONDARY BOOTLOADER", + [MHI_EE_AMSS] = "MISSION MODE", + [MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE", + [MHI_EE_WFW] = "WLAN FIRMWARE", + [MHI_EE_PTHRU] = "PASS THROUGH", + [MHI_EE_EDL] = "EMERGENCY DOWNLOAD", + [MHI_EE_FP] = "FLASH PROGRAMMER", [MHI_EE_DISABLE_TRANSITION] = "DISABLE", [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED", }; @@ -37,8 +38,9 @@ const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { [DEV_ST_TRANSITION_PBL] = "PBL", [DEV_ST_TRANSITION_READY] = "READY", [DEV_ST_TRANSITION_SBL] = "SBL", - [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION_MODE", - [DEV_ST_TRANSITION_SYS_ERR] = "SYS_ERR", + [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", + [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER", + [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR", [DEV_ST_TRANSITION_DISABLE] = "DISABLE", }; @@ -49,24 +51,30 @@ const char * const mhi_state_str[MHI_STATE_MAX] = { [MHI_STATE_M1] = "M1", [MHI_STATE_M2] = "M2", [MHI_STATE_M3] = "M3", - [MHI_STATE_M3_FAST] = "M3_FAST", + [MHI_STATE_M3_FAST] = "M3 FAST", [MHI_STATE_BHI] = "BHI", - [MHI_STATE_SYS_ERR] = "SYS_ERR", + [MHI_STATE_SYS_ERR] = "SYS ERROR", +}; + +const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { + [MHI_CH_STATE_TYPE_RESET] = "RESET", + [MHI_CH_STATE_TYPE_STOP] = "STOP", + [MHI_CH_STATE_TYPE_START] = "START", }; static const char * const mhi_pm_state_str[] = { [MHI_PM_STATE_DISABLE] = "DISABLE", - [MHI_PM_STATE_POR] = "POR", + [MHI_PM_STATE_POR] = "POWER ON RESET", [MHI_PM_STATE_M0] = "M0", [MHI_PM_STATE_M2] = "M2", [MHI_PM_STATE_M3_ENTER] = "M?->M3", [MHI_PM_STATE_M3] = "M3", [MHI_PM_STATE_M3_EXIT] = "M3->M0", - [MHI_PM_STATE_FW_DL_ERR] = "FW DL Error", - [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS_ERR Detect", - [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS_ERR Process", + [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error", + [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect", + [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process", [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process", - [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "LD or Error Fatal Detect", + [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", }; const char *to_mhi_pm_state_str(enum mhi_pm_state state) @@ -508,8 +516,6 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl) /* Setup wake db */ mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB); - mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 4, 0); - mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0); mhi_cntrl->wake_set = false; /* Setup channel db address for each channel in tre_ring */ @@ -552,6 +558,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, struct mhi_ring *buf_ring; struct mhi_ring *tre_ring; struct mhi_chan_ctxt *chan_ctxt; + u32 tmp; buf_ring = &mhi_chan->buf_ring; tre_ring = &mhi_chan->tre_ring; @@ -565,7 +572,19 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, vfree(buf_ring->base); buf_ring->base = tre_ring->base = NULL; + tre_ring->ctxt_wp = NULL; chan_ctxt->rbase = 0; + chan_ctxt->rlen = 0; + chan_ctxt->rp = 0; + chan_ctxt->wp = 0; + + tmp = chan_ctxt->chcfg; + tmp &= ~CHAN_CTX_CHSTATE_MASK; + tmp |= (MHI_CH_STATE_DISABLED << CHAN_CTX_CHSTATE_SHIFT); + chan_ctxt->chcfg = tmp; + + /* Update to all cores */ + smp_wmb(); } int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, @@ -863,12 +882,10 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, u32 soc_info; int ret, i; - if (!mhi_cntrl) - return -EINVAL; - - if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || + if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || + !mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || !mhi_cntrl->status_cb || !mhi_cntrl->read_reg || - !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs) + !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq) return -EINVAL; ret = parse_config(mhi_cntrl, config); @@ -890,8 +907,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker); init_waitqueue_head(&mhi_cntrl->state_event); - mhi_cntrl->hiprio_wq = alloc_ordered_workqueue - ("mhi_hiprio_wq", WQ_MEM_RECLAIM | WQ_HIGHPRI); + mhi_cntrl->hiprio_wq = alloc_ordered_workqueue("mhi_hiprio_wq", WQ_HIGHPRI); if (!mhi_cntrl->hiprio_wq) { dev_err(mhi_cntrl->cntrl_dev, "Failed to allocate workqueue\n"); ret = -ENOMEM; @@ -1083,8 +1099,6 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image); } - mhi_cntrl->pre_init = true; - mutex_unlock(&mhi_cntrl->pm_mutex); return 0; @@ -1115,7 +1129,6 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl) } mhi_deinit_dev_ctxt(mhi_cntrl); - mhi_cntrl->pre_init = false; } EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down); @@ -1296,7 +1309,8 @@ static int mhi_driver_remove(struct device *dev) mutex_lock(&mhi_chan->mutex); - if (ch_state[dir] == MHI_CH_STATE_ENABLED && + if ((ch_state[dir] == MHI_CH_STATE_ENABLED || + ch_state[dir] == MHI_CH_STATE_STOP) && !mhi_chan->offload_ch) mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 6f80ec30c0cdcc342ad0faa128bda13e13b96473..5b9ea66b92dc32fb7dce14f4a4db5ea7419839af 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -369,6 +369,18 @@ enum mhi_ch_state { MHI_CH_STATE_ERROR = 0x5, }; +enum mhi_ch_state_type { + MHI_CH_STATE_TYPE_RESET, + MHI_CH_STATE_TYPE_STOP, + MHI_CH_STATE_TYPE_START, + MHI_CH_STATE_TYPE_MAX, +}; + +extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; +#define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ + "INVALID_STATE" : \ + mhi_ch_state_type_str[(state)]) + #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ mode != MHI_DB_BRST_ENABLE) @@ -379,13 +391,15 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \ ee == MHI_EE_EDL) -#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW) +#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW || \ + ee == MHI_EE_FP) enum dev_st_transition { DEV_ST_TRANSITION_PBL, DEV_ST_TRANSITION_READY, DEV_ST_TRANSITION_SBL, DEV_ST_TRANSITION_MISSION_MODE, + DEV_ST_TRANSITION_FP, DEV_ST_TRANSITION_SYS_ERR, DEV_ST_TRANSITION_DISABLE, DEV_ST_TRANSITION_MAX, @@ -619,6 +633,7 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl); int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl); int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, enum mhi_cmd_type cmd); +int mhi_download_amss_image(struct mhi_controller *mhi_cntrl); static inline bool mhi_is_active(struct mhi_controller *mhi_cntrl) { return (mhi_cntrl->dev_state >= MHI_STATE_M0 && @@ -643,6 +658,9 @@ int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 mask, u32 shift, u32 *out); +int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, u32 mask, + u32 shift, u32 val, u32 delayus); void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 val); void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 4e0131b94056ba8532f591960fee4e4c527570c2..22acde118bc352560f2d329a074b71959770ae32 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -4,6 +4,7 @@ * */ +#include <linux/delay.h> #include <linux/device.h> #include <linux/dma-direction.h> #include <linux/dma-mapping.h> @@ -37,6 +38,28 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, return 0; } +int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, + u32 mask, u32 shift, u32 val, u32 delayus) +{ + int ret; + u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus; + + while (retry--) { + ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, shift, + &out); + if (ret) + return ret; + + if (out == val) + return 0; + + fsleep(delayus); + } + + return -ETIMEDOUT; +} + void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 val) { @@ -242,10 +265,17 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl, smp_wmb(); } +static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr) +{ + return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len; +} + int mhi_destroy_device(struct device *dev, void *data) { + struct mhi_chan *ul_chan, *dl_chan; struct mhi_device *mhi_dev; struct mhi_controller *mhi_cntrl; + enum mhi_ee_type ee = MHI_EE_MAX; if (dev->bus != &mhi_bus_type) return 0; @@ -257,6 +287,17 @@ int mhi_destroy_device(struct device *dev, void *data) if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER) return 0; + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + + /* + * If execution environment is specified, remove only those devices that + * started in them based on ee_mask for the channels as we move on to a + * different execution environment + */ + if (data) + ee = *(enum mhi_ee_type *)data; + /* * For the suspend and resume case, this function will get called * without mhi_unregister_controller(). Hence, we need to drop the @@ -264,11 +305,19 @@ int mhi_destroy_device(struct device *dev, void *data) * be sure that there will be no instances of mhi_dev left after * this. */ - if (mhi_dev->ul_chan) - put_device(&mhi_dev->ul_chan->mhi_dev->dev); + if (ul_chan) { + if (ee != MHI_EE_MAX && !(ul_chan->ee_mask & BIT(ee))) + return 0; - if (mhi_dev->dl_chan) - put_device(&mhi_dev->dl_chan->mhi_dev->dev); + put_device(&ul_chan->mhi_dev->dev); + } + + if (dl_chan) { + if (ee != MHI_EE_MAX && !(dl_chan->ee_mask & BIT(ee))) + return 0; + + put_device(&dl_chan->mhi_dev->dev); + } dev_dbg(&mhi_cntrl->mhi_dev->dev, "destroy device for chan:%s\n", mhi_dev->name); @@ -383,7 +432,16 @@ irqreturn_t mhi_irq_handler(int irq_number, void *dev) struct mhi_event_ctxt *er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; struct mhi_ring *ev_ring = &mhi_event->ring; - void *dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + dma_addr_t ptr = er_ctxt->rp; + void *dev_rp; + + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return IRQ_HANDLED; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); /* Only proceed if event ring has pending events */ if (ev_ring->rp == dev_rp) @@ -407,9 +465,9 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) { struct mhi_controller *mhi_cntrl = priv; struct device *dev = &mhi_cntrl->mhi_dev->dev; - enum mhi_state state = MHI_STATE_MAX; + enum mhi_state state; enum mhi_pm_state pm_state = 0; - enum mhi_ee_type ee = 0; + enum mhi_ee_type ee; write_lock_irq(&mhi_cntrl->pm_lock); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { @@ -418,11 +476,11 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) } state = mhi_get_mhi_state(mhi_cntrl); - ee = mhi_cntrl->ee; - mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); - dev_dbg(dev, "local ee:%s device ee:%s dev_state:%s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), TO_MHI_EXEC_STR(ee), - TO_MHI_STATE_STR(state)); + ee = mhi_get_exec_env(mhi_cntrl); + dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), + TO_MHI_STATE_STR(mhi_cntrl->dev_state), + TO_MHI_EXEC_STR(ee), TO_MHI_STATE_STR(state)); if (state == MHI_STATE_SYS_ERR) { dev_dbg(dev, "System error detected\n"); @@ -431,27 +489,30 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) } write_unlock_irq(&mhi_cntrl->pm_lock); - /* If device supports RDDM don't bother processing SYS error */ - if (mhi_cntrl->rddm_image) { - /* host may be performing a device power down already */ - if (!mhi_is_active(mhi_cntrl)) - goto exit_intvec; + if (pm_state != MHI_PM_SYS_ERR_DETECT || ee == mhi_cntrl->ee) + goto exit_intvec; - if (mhi_cntrl->ee == MHI_EE_RDDM && mhi_cntrl->ee != ee) { + switch (ee) { + case MHI_EE_RDDM: + /* proceed if power down is not already in progress */ + if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) { mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM); + mhi_cntrl->ee = ee; wake_up_all(&mhi_cntrl->state_event); } - goto exit_intvec; - } - - if (pm_state == MHI_PM_SYS_ERR_DETECT) { + break; + case MHI_EE_PBL: + case MHI_EE_EDL: + case MHI_EE_PTHRU: + mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR); + mhi_cntrl->ee = ee; wake_up_all(&mhi_cntrl->state_event); - - /* For fatal errors, we let controller decide next step */ - if (MHI_IN_PBL(ee)) - mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR); - else - mhi_pm_sys_err_handler(mhi_cntrl); + mhi_pm_sys_err_handler(mhi_cntrl); + break; + default: + wake_up_all(&mhi_cntrl->state_event); + mhi_pm_sys_err_handler(mhi_cntrl); + break; } exit_intvec: @@ -536,6 +597,11 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, struct mhi_buf_info *buf_info; u16 xfer_len; + if (!is_valid_ring_ptr(tre_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event element points outside of the tre ring\n"); + break; + } /* Get the TRB this event points to */ ev_tre = mhi_to_virtual(tre_ring, ptr); @@ -570,8 +636,11 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, /* notify client */ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); - if (mhi_chan->dir == DMA_TO_DEVICE) + if (mhi_chan->dir == DMA_TO_DEVICE) { atomic_dec(&mhi_cntrl->pending_pkts); + /* Release the reference got from mhi_queue() */ + mhi_cntrl->runtime_put(mhi_cntrl); + } /* * Recycle the buffer if buffer is pre-allocated, @@ -595,15 +664,15 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, case MHI_EV_CC_OOB: case MHI_EV_CC_DB_MODE: { - unsigned long flags; + unsigned long pm_lock_flags; mhi_chan->db_cfg.db_mode = 1; - read_lock_irqsave(&mhi_cntrl->pm_lock, flags); + read_lock_irqsave(&mhi_cntrl->pm_lock, pm_lock_flags); if (tre_ring->wp != tre_ring->rp && MHI_DB_ACCESS_VALID(mhi_cntrl)) { mhi_ring_chan_db(mhi_cntrl, mhi_chan); } - read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); + read_unlock_irqrestore(&mhi_cntrl->pm_lock, pm_lock_flags); break; } case MHI_EV_CC_BAD_TRE: @@ -695,6 +764,12 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan; u32 chan; + if (!is_valid_ring_ptr(mhi_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event element points outside of the cmd ring\n"); + return; + } + cmd_pkt = mhi_to_virtual(mhi_ring, ptr); chan = MHI_TRE_GET_CMD_CHID(cmd_pkt); @@ -719,6 +794,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, struct device *dev = &mhi_cntrl->mhi_dev->dev; u32 chan; int count = 0; + dma_addr_t ptr = er_ctxt->rp; /* * This is a quick check to avoid unnecessary event processing @@ -728,7 +804,13 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) return -EIO; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); local_rp = ev_ring->rp; while (dev_rp != local_rp) { @@ -771,14 +853,14 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, break; case MHI_STATE_SYS_ERR: { - enum mhi_pm_state new_state; + enum mhi_pm_state pm_state; dev_dbg(dev, "System error detected\n"); write_lock_irq(&mhi_cntrl->pm_lock); - new_state = mhi_tryset_pm_state(mhi_cntrl, + pm_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_SYS_ERR_DETECT); write_unlock_irq(&mhi_cntrl->pm_lock); - if (new_state == MHI_PM_SYS_ERR_DETECT) + if (pm_state == MHI_PM_SYS_ERR_DETECT) mhi_pm_sys_err_handler(mhi_cntrl); break; } @@ -807,6 +889,9 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, case MHI_EE_AMSS: st = DEV_ST_TRANSITION_MISSION_MODE; break; + case MHI_EE_FP: + st = DEV_ST_TRANSITION_FP; + break; case MHI_EE_RDDM: mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM); write_lock_irq(&mhi_cntrl->pm_lock); @@ -834,6 +919,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, */ if (chan < mhi_cntrl->max_chan) { mhi_chan = &mhi_cntrl->mhi_chan[chan]; + if (!mhi_chan->configured) + break; parse_xfer_event(mhi_cntrl, local_rp, mhi_chan); event_quota--; } @@ -845,7 +932,15 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp = ev_ring->rp; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + + ptr = er_ctxt->rp; + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); count++; } @@ -868,11 +963,18 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, int count = 0; u32 chan; struct mhi_chan *mhi_chan; + dma_addr_t ptr = er_ctxt->rp; if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) return -EIO; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); local_rp = ev_ring->rp; while (dev_rp != local_rp && event_quota > 0) { @@ -886,7 +988,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, * Only process the event ring elements whose channel * ID is within the maximum supported range. */ - if (chan < mhi_cntrl->max_chan) { + if (chan < mhi_cntrl->max_chan && + mhi_cntrl->mhi_chan[chan].configured) { mhi_chan = &mhi_cntrl->mhi_chan[chan]; if (likely(type == MHI_PKT_TYPE_TX_EVENT)) { @@ -900,7 +1003,15 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp = ev_ring->rp; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + + ptr = er_ctxt->rp; + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); count++; } read_lock_bh(&mhi_cntrl->pm_lock); @@ -996,7 +1107,7 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, ret = mhi_is_ring_full(mhi_cntrl, tre_ring); if (unlikely(ret)) { - ret = -ENOMEM; + ret = -EAGAIN; goto exit_unlock; } @@ -1004,9 +1115,11 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (unlikely(ret)) goto exit_unlock; - /* trigger M3 exit if necessary */ - if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state)) - mhi_trigger_resume(mhi_cntrl); + /* Packet is queued, take a usage ref to exit M3 if necessary + * for host->device buffer, balanced put is done on buffer completion + * for device->host buffer, balanced put is after ringing the DB + */ + mhi_cntrl->runtime_get(mhi_cntrl); /* Assert dev_wake (to exit/prevent M1/M2)*/ mhi_cntrl->wake_toggle(mhi_cntrl); @@ -1014,12 +1127,11 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (mhi_chan->dir == DMA_TO_DEVICE) atomic_inc(&mhi_cntrl->pending_pkts); - if (unlikely(!MHI_DB_ACCESS_VALID(mhi_cntrl))) { - ret = -EIO; - goto exit_unlock; - } + if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) + mhi_ring_chan_db(mhi_cntrl, mhi_chan); - mhi_ring_chan_db(mhi_cntrl, mhi_chan); + if (dir == DMA_FROM_DEVICE) + mhi_cntrl->runtime_put(mhi_cntrl); exit_unlock: read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); @@ -1162,6 +1274,11 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl, cmd_tre->dword[0] = MHI_TRE_CMD_RESET_DWORD0; cmd_tre->dword[1] = MHI_TRE_CMD_RESET_DWORD1(chan); break; + case MHI_CMD_STOP_CHAN: + cmd_tre->ptr = MHI_TRE_CMD_STOP_PTR; + cmd_tre->dword[0] = MHI_TRE_CMD_STOP_DWORD0; + cmd_tre->dword[1] = MHI_TRE_CMD_STOP_DWORD1(chan); + break; case MHI_CMD_START_CHAN: cmd_tre->ptr = MHI_TRE_CMD_START_PTR; cmd_tre->dword[0] = MHI_TRE_CMD_START_DWORD0; @@ -1183,56 +1300,125 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl, return 0; } -static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan) +static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, + struct mhi_chan *mhi_chan, + enum mhi_ch_state_type to_state) { + struct device *dev = &mhi_chan->mhi_dev->dev; + enum mhi_cmd_type cmd = MHI_CMD_NOP; int ret; - struct device *dev = &mhi_cntrl->mhi_dev->dev; - - dev_dbg(dev, "Entered: unprepare channel:%d\n", mhi_chan->chan); - /* no more processing events for this channel */ - mutex_lock(&mhi_chan->mutex); - write_lock_irq(&mhi_chan->lock); - if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED && - mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) { + dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan, + TO_CH_STATE_TYPE_STR(to_state)); + + switch (to_state) { + case MHI_CH_STATE_TYPE_RESET: + write_lock_irq(&mhi_chan->lock); + if (mhi_chan->ch_state != MHI_CH_STATE_STOP && + mhi_chan->ch_state != MHI_CH_STATE_ENABLED && + mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) { + write_unlock_irq(&mhi_chan->lock); + return -EINVAL; + } + mhi_chan->ch_state = MHI_CH_STATE_DISABLED; write_unlock_irq(&mhi_chan->lock); - mutex_unlock(&mhi_chan->mutex); - return; + + cmd = MHI_CMD_RESET_CHAN; + break; + case MHI_CH_STATE_TYPE_STOP: + if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) + return -EINVAL; + + cmd = MHI_CMD_STOP_CHAN; + break; + case MHI_CH_STATE_TYPE_START: + if (mhi_chan->ch_state != MHI_CH_STATE_STOP && + mhi_chan->ch_state != MHI_CH_STATE_DISABLED) + return -EINVAL; + + cmd = MHI_CMD_START_CHAN; + break; + default: + dev_err(dev, "%d: Channel state update to %s not allowed\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + return -EINVAL; } - mhi_chan->ch_state = MHI_CH_STATE_DISABLED; - write_unlock_irq(&mhi_chan->lock); + /* bring host and device out of suspended states */ + ret = mhi_device_get_sync(mhi_cntrl->mhi_dev); + if (ret) + return ret; + mhi_cntrl->runtime_get(mhi_cntrl); reinit_completion(&mhi_chan->completion); - read_lock_bh(&mhi_cntrl->pm_lock); - if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - read_unlock_bh(&mhi_cntrl->pm_lock); - goto error_invalid_state; + ret = mhi_send_cmd(mhi_cntrl, mhi_chan, cmd); + if (ret) { + dev_err(dev, "%d: Failed to send %s channel command\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + goto exit_channel_update; } - mhi_cntrl->wake_toggle(mhi_cntrl); - read_unlock_bh(&mhi_cntrl->pm_lock); + ret = wait_for_completion_timeout(&mhi_chan->completion, + msecs_to_jiffies(mhi_cntrl->timeout_ms)); + if (!ret || mhi_chan->ccs != MHI_EV_CC_SUCCESS) { + dev_err(dev, + "%d: Failed to receive %s channel command completion\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + ret = -EIO; + goto exit_channel_update; + } - mhi_cntrl->runtime_get(mhi_cntrl); + ret = 0; + + if (to_state != MHI_CH_STATE_TYPE_RESET) { + write_lock_irq(&mhi_chan->lock); + mhi_chan->ch_state = (to_state == MHI_CH_STATE_TYPE_START) ? + MHI_CH_STATE_ENABLED : MHI_CH_STATE_STOP; + write_unlock_irq(&mhi_chan->lock); + } + + dev_dbg(dev, "%d: Channel state change to %s successful\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + +exit_channel_update: mhi_cntrl->runtime_put(mhi_cntrl); - ret = mhi_send_cmd(mhi_cntrl, mhi_chan, MHI_CMD_RESET_CHAN); + mhi_device_put(mhi_cntrl->mhi_dev); + + return ret; +} + +static void mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, + struct mhi_chan *mhi_chan) +{ + int ret; + struct device *dev = &mhi_chan->mhi_dev->dev; + + mutex_lock(&mhi_chan->mutex); + + if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { + dev_dbg(dev, "Current EE: %s Required EE Mask: 0x%x\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask); + goto exit_unprepare_channel; + } + + /* no more processing events for this channel */ + ret = mhi_update_channel_state(mhi_cntrl, mhi_chan, + MHI_CH_STATE_TYPE_RESET); if (ret) - goto error_invalid_state; + dev_err(dev, "%d: Failed to reset channel, still resetting\n", + mhi_chan->chan); - /* even if it fails we will still reset */ - ret = wait_for_completion_timeout(&mhi_chan->completion, - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (!ret || mhi_chan->ccs != MHI_EV_CC_SUCCESS) - dev_err(dev, - "Failed to receive cmd completion, still resetting\n"); +exit_unprepare_channel: + write_lock_irq(&mhi_chan->lock); + mhi_chan->ch_state = MHI_CH_STATE_DISABLED; + write_unlock_irq(&mhi_chan->lock); -error_invalid_state: if (!mhi_chan->offload_ch) { mhi_reset_chan(mhi_cntrl, mhi_chan); mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); } - dev_dbg(dev, "chan:%d successfully resetted\n", mhi_chan->chan); + dev_dbg(dev, "%d: successfully reset\n", mhi_chan->chan); + mutex_unlock(&mhi_chan->mutex); } @@ -1240,28 +1426,16 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) { int ret = 0; - struct device *dev = &mhi_cntrl->mhi_dev->dev; - - dev_dbg(dev, "Preparing channel: %d\n", mhi_chan->chan); + struct device *dev = &mhi_chan->mhi_dev->dev; if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { - dev_err(dev, - "Current EE: %s Required EE Mask: 0x%x for chan: %s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask, - mhi_chan->name); + dev_err(dev, "Current EE: %s Required EE Mask: 0x%x\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask); return -ENOTCONN; } mutex_lock(&mhi_chan->mutex); - /* If channel is not in disable state, do not allow it to start */ - if (mhi_chan->ch_state != MHI_CH_STATE_DISABLED) { - ret = -EIO; - dev_dbg(dev, "channel: %d is not in disabled state\n", - mhi_chan->chan); - goto error_init_chan; - } - /* Check of client manages channel context for offload channels */ if (!mhi_chan->offload_ch) { ret = mhi_init_chan_ctxt(mhi_cntrl, mhi_chan); @@ -1269,34 +1443,11 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, goto error_init_chan; } - reinit_completion(&mhi_chan->completion); - read_lock_bh(&mhi_cntrl->pm_lock); - if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - read_unlock_bh(&mhi_cntrl->pm_lock); - ret = -EIO; - goto error_pm_state; - } - - mhi_cntrl->wake_toggle(mhi_cntrl); - read_unlock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->runtime_get(mhi_cntrl); - mhi_cntrl->runtime_put(mhi_cntrl); - - ret = mhi_send_cmd(mhi_cntrl, mhi_chan, MHI_CMD_START_CHAN); + ret = mhi_update_channel_state(mhi_cntrl, mhi_chan, + MHI_CH_STATE_TYPE_START); if (ret) goto error_pm_state; - ret = wait_for_completion_timeout(&mhi_chan->completion, - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (!ret || mhi_chan->ccs != MHI_EV_CC_SUCCESS) { - ret = -EIO; - goto error_pm_state; - } - - write_lock_irq(&mhi_chan->lock); - mhi_chan->ch_state = MHI_CH_STATE_ENABLED; - write_unlock_irq(&mhi_chan->lock); - /* Pre-allocate buffer for xfer ring */ if (mhi_chan->pre_alloc) { int nr_el = get_nr_avail_ring_elements(mhi_cntrl, @@ -1334,9 +1485,6 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, mutex_unlock(&mhi_chan->mutex); - dev_dbg(dev, "Chan: %d successfully moved to start state\n", - mhi_chan->chan); - return 0; error_pm_state: @@ -1350,7 +1498,7 @@ error_init_chan: error_pre_alloc: mutex_unlock(&mhi_chan->mutex); - __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + mhi_unprepare_channel(mhi_cntrl, mhi_chan); return ret; } @@ -1365,6 +1513,7 @@ static void mhi_mark_stale_events(struct mhi_controller *mhi_cntrl, struct mhi_ring *ev_ring; struct device *dev = &mhi_cntrl->mhi_dev->dev; unsigned long flags; + dma_addr_t ptr; dev_dbg(dev, "Marking all events for chan: %d as stale\n", chan); @@ -1372,7 +1521,15 @@ static void mhi_mark_stale_events(struct mhi_controller *mhi_cntrl, /* mark all stale events related to channel as STALE event */ spin_lock_irqsave(&mhi_event->lock, flags); - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + + ptr = er_ctxt->rp; + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + dev_rp = ev_ring->rp; + } else { + dev_rp = mhi_to_virtual(ev_ring, ptr); + } local_rp = ev_ring->rp; while (dev_rp != local_rp) { @@ -1403,8 +1560,11 @@ static void mhi_reset_data_chan(struct mhi_controller *mhi_cntrl, while (tre_ring->rp != tre_ring->wp) { struct mhi_buf_info *buf_info = buf_ring->rp; - if (mhi_chan->dir == DMA_TO_DEVICE) + if (mhi_chan->dir == DMA_TO_DEVICE) { atomic_dec(&mhi_cntrl->pending_pkts); + /* Release the reference got from mhi_queue() */ + mhi_cntrl->runtime_put(mhi_cntrl); + } if (!buf_info->pre_mapped) mhi_cntrl->unmap_single(mhi_cntrl, buf_info); @@ -1467,7 +1627,7 @@ error_open_chan: if (!mhi_chan) continue; - __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + mhi_unprepare_channel(mhi_cntrl, mhi_chan); } return ret; @@ -1485,7 +1645,7 @@ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev) if (!mhi_chan) continue; - __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + mhi_unprepare_channel(mhi_cntrl, mhi_chan); } } EXPORT_SYMBOL_GPL(mhi_unprepare_from_transfer); diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index 681960c72d2a8629560b7d7c65c48a22cd0eec80..e2e59a341fef64ee707a72dc4fbf38ca17aef08d 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -153,35 +153,33 @@ static void mhi_toggle_dev_wake(struct mhi_controller *mhi_cntrl) /* Handle device ready state transition */ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl) { - void __iomem *base = mhi_cntrl->regs; struct mhi_event *mhi_event; enum mhi_pm_state cur_state; struct device *dev = &mhi_cntrl->mhi_dev->dev; - u32 reset = 1, ready = 0; + u32 interval_us = 25000; /* poll register field every 25 milliseconds */ int ret, i; - /* Wait for RESET to be cleared and READY bit to be set by the device */ - wait_event_timeout(mhi_cntrl->state_event, - MHI_PM_IN_FATAL_STATE(mhi_cntrl->pm_state) || - mhi_read_reg_field(mhi_cntrl, base, MHICTRL, - MHICTRL_RESET_MASK, - MHICTRL_RESET_SHIFT, &reset) || - mhi_read_reg_field(mhi_cntrl, base, MHISTATUS, - MHISTATUS_READY_MASK, - MHISTATUS_READY_SHIFT, &ready) || - (!reset && ready), - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - /* Check if device entered error state */ if (MHI_PM_IN_FATAL_STATE(mhi_cntrl->pm_state)) { dev_err(dev, "Device link is not accessible\n"); return -EIO; } - /* Timeout if device did not transition to ready state */ - if (reset || !ready) { - dev_err(dev, "Device Ready timeout\n"); - return -ETIMEDOUT; + /* Wait for RESET to be cleared and READY bit to be set by the device */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, + MHICTRL_RESET_MASK, MHICTRL_RESET_SHIFT, 0, + interval_us); + if (ret) { + dev_err(dev, "Device failed to clear MHI Reset\n"); + return ret; + } + + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, + MHISTATUS_READY_MASK, MHISTATUS_READY_SHIFT, 1, + interval_us); + if (ret) { + dev_err(dev, "Device failed to enter MHI Ready\n"); + return ret; } dev_dbg(dev, "Device in READY State\n"); @@ -377,24 +375,28 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) { struct mhi_event *mhi_event; struct device *dev = &mhi_cntrl->mhi_dev->dev; + enum mhi_ee_type ee = MHI_EE_MAX, current_ee = mhi_cntrl->ee; int i, ret; dev_dbg(dev, "Processing Mission Mode transition\n"); write_lock_irq(&mhi_cntrl->pm_lock); if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) - mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); + ee = mhi_get_exec_env(mhi_cntrl); - if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) { + if (!MHI_IN_MISSION_MODE(ee)) { mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT; write_unlock_irq(&mhi_cntrl->pm_lock); wake_up_all(&mhi_cntrl->state_event); return -EIO; } + mhi_cntrl->ee = ee; write_unlock_irq(&mhi_cntrl->pm_lock); wake_up_all(&mhi_cntrl->state_event); + device_for_each_child(&mhi_cntrl->mhi_dev->dev, ¤t_ee, + mhi_destroy_device); mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_MISSION_MODE); /* Force MHI to be in M0 state before continuing */ @@ -560,6 +562,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl) static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) { enum mhi_pm_state cur_state, prev_state; + enum dev_st_transition next_state; struct mhi_event *mhi_event; struct mhi_cmd_ctxt *cmd_ctxt; struct mhi_cmd *mhi_cmd; @@ -673,7 +676,23 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) er_ctxt->wp = er_ctxt->rbase; } - mhi_ready_state_transition(mhi_cntrl); + /* Transition to next state */ + if (MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) { + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_POR); + write_unlock_irq(&mhi_cntrl->pm_lock); + if (cur_state != MHI_PM_POR) { + dev_err(dev, "Error moving to state %s from %s\n", + to_mhi_pm_state_str(MHI_PM_POR), + to_mhi_pm_state_str(cur_state)); + goto exit_sys_error_transition; + } + next_state = DEV_ST_TRANSITION_PBL; + } else { + next_state = DEV_ST_TRANSITION_READY; + } + + mhi_queue_state_transition(mhi_cntrl, next_state); exit_sys_error_transition: dev_dbg(dev, "Exiting with PM state: %s, MHI state: %s\n", @@ -742,8 +761,7 @@ void mhi_pm_st_worker(struct work_struct *work) if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); - if (MHI_IN_PBL(mhi_cntrl->ee)) - mhi_fw_load_handler(mhi_cntrl); + mhi_fw_load_handler(mhi_cntrl); break; case DEV_ST_TRANSITION_SBL: write_lock_irq(&mhi_cntrl->pm_lock); @@ -755,10 +773,18 @@ void mhi_pm_st_worker(struct work_struct *work) * either SBL or AMSS states */ mhi_create_devices(mhi_cntrl); + if (mhi_cntrl->fbc_download) + mhi_download_amss_image(mhi_cntrl); break; case DEV_ST_TRANSITION_MISSION_MODE: mhi_pm_mission_mode_transition(mhi_cntrl); break; + case DEV_ST_TRANSITION_FP: + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_cntrl->ee = MHI_EE_FP; + write_unlock_irq(&mhi_cntrl->pm_lock); + mhi_create_devices(mhi_cntrl); + break; case DEV_ST_TRANSITION_READY: mhi_ready_state_transition(mhi_cntrl); break; @@ -822,7 +848,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) return -EBUSY; } - dev_info(dev, "Allowing M3 transition\n"); + dev_dbg(dev, "Allowing M3 transition\n"); new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M3_ENTER); if (new_state != MHI_PM_M3_ENTER) { write_unlock_irq(&mhi_cntrl->pm_lock); @@ -836,7 +862,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) /* Set MHI to M3 and wait for completion */ mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M3); write_unlock_irq(&mhi_cntrl->pm_lock); - dev_info(dev, "Wait for M3 completion\n"); + dev_dbg(dev, "Waiting for M3 completion\n"); ret = wait_event_timeout(mhi_cntrl->state_event, mhi_cntrl->dev_state == MHI_STATE_M3 || @@ -870,9 +896,9 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl) enum mhi_pm_state cur_state; int ret; - dev_info(dev, "Entered with PM state: %s, MHI state: %s\n", - to_mhi_pm_state_str(mhi_cntrl->pm_state), - TO_MHI_STATE_STR(mhi_cntrl->dev_state)); + dev_dbg(dev, "Entered with PM state: %s, MHI state: %s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); if (mhi_cntrl->pm_state == MHI_PM_DISABLE) return 0; @@ -880,6 +906,9 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl) if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) return -EIO; + if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) + return -EINVAL; + /* Notify clients about exiting LPM */ list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, node) { mutex_lock(&itr->mutex); @@ -1033,13 +1062,6 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) mutex_lock(&mhi_cntrl->pm_mutex); mhi_cntrl->pm_state = MHI_PM_DISABLE; - if (!mhi_cntrl->pre_init) { - /* Setup device context */ - ret = mhi_init_dev_ctxt(mhi_cntrl); - if (ret) - goto error_dev_ctxt; - } - ret = mhi_init_irq_setup(mhi_cntrl); if (ret) goto error_setup_irq; @@ -1092,7 +1114,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) &val) || !val, msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (ret) { + if (!ret) { ret = -EIO; dev_info(dev, "Failed to reset MHI due to syserr state\n"); goto error_bhi_offset; @@ -1121,10 +1143,7 @@ error_bhi_offset: mhi_deinit_free_irq(mhi_cntrl); error_setup_irq: - if (!mhi_cntrl->pre_init) - mhi_deinit_dev_ctxt(mhi_cntrl); - -error_dev_ctxt: + mhi_cntrl->pm_state = MHI_PM_DISABLE; mutex_unlock(&mhi_cntrl->pm_mutex); return ret; @@ -1136,12 +1155,19 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) enum mhi_pm_state cur_state, transition_state; struct device *dev = &mhi_cntrl->mhi_dev->dev; + mutex_lock(&mhi_cntrl->pm_mutex); + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_cntrl->pm_state; + if (cur_state == MHI_PM_DISABLE) { + write_unlock_irq(&mhi_cntrl->pm_lock); + mutex_unlock(&mhi_cntrl->pm_mutex); + return; /* Already powered down */ + } + /* If it's not a graceful shutdown, force MHI to linkdown state */ transition_state = (graceful) ? MHI_PM_SHUTDOWN_PROCESS : MHI_PM_LD_ERR_FATAL_DETECT; - mutex_lock(&mhi_cntrl->pm_mutex); - write_lock_irq(&mhi_cntrl->pm_lock); cur_state = mhi_tryset_pm_state(mhi_cntrl, transition_state); if (cur_state != transition_state) { dev_err(dev, "Failed to move to state: %s from: %s\n", @@ -1166,15 +1192,6 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) flush_work(&mhi_cntrl->st_worker); free_irq(mhi_cntrl->irq[0], mhi_cntrl); - - if (!mhi_cntrl->pre_init) { - /* Free all allocated resources */ - if (mhi_cntrl->fbc_image) { - mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); - mhi_cntrl->fbc_image = NULL; - } - mhi_deinit_dev_ctxt(mhi_cntrl); - } } EXPORT_SYMBOL_GPL(mhi_power_down); diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 20673a4b4a3c657ed97d59cbc2bac29af35ce962..7c810f02a2ef4d164f959e3a02a7aa6684bfe32b 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -14,6 +14,7 @@ #include <linux/mhi.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_runtime.h> #include <linux/timer.h> #include <linux/workqueue.h> @@ -71,9 +72,9 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = false, \ } -#define MHI_EVENT_CONFIG_CTRL(ev_ring) \ +#define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \ { \ - .num_elements = 64, \ + .num_elements = el_count, \ .irq_moderation_ms = 0, \ .irq = (ev_ring) + 1, \ .priority = 1, \ @@ -114,9 +115,69 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = true, \ } -#define MHI_EVENT_CONFIG_DATA(ev_ring) \ +#define MHI_CHANNEL_CONFIG_UL_SBL(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_TO_DEVICE, \ + .ee_mask = BIT(MHI_EE_SBL), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } \ + +#define MHI_CHANNEL_CONFIG_DL_SBL(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_FROM_DEVICE, \ + .ee_mask = BIT(MHI_EE_SBL), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } + +#define MHI_CHANNEL_CONFIG_UL_FP(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_TO_DEVICE, \ + .ee_mask = BIT(MHI_EE_FP), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } \ + +#define MHI_CHANNEL_CONFIG_DL_FP(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_FROM_DEVICE, \ + .ee_mask = BIT(MHI_EE_FP), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } + +#define MHI_EVENT_CONFIG_DATA(ev_ring, el_count) \ { \ - .num_elements = 128, \ + .num_elements = el_count, \ .irq_moderation_ms = 5, \ .irq = (ev_ring) + 1, \ .priority = 1, \ @@ -127,9 +188,9 @@ struct mhi_pci_dev_info { .offload_channel = false, \ } -#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, ch_num) \ +#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, el_count, ch_num) \ { \ - .num_elements = 2048, \ + .num_elements = el_count, \ .irq_moderation_ms = 1, \ .irq = (ev_ring) + 1, \ .priority = 1, \ @@ -150,21 +211,23 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = { MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0), MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0), MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0), + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2), MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3), }; static struct mhi_event_config modem_qcom_v1_mhi_events[] = { /* first ring is control+data ring */ - MHI_EVENT_CONFIG_CTRL(0), + MHI_EVENT_CONFIG_CTRL(0, 64), /* DIAG dedicated event ring */ - MHI_EVENT_CONFIG_DATA(1), + MHI_EVENT_CONFIG_DATA(1, 128), /* Hardware channels request dedicated hardware event rings */ - MHI_EVENT_CONFIG_HW_DATA(2, 100), - MHI_EVENT_CONFIG_HW_DATA(3, 101) + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101) }; -static struct mhi_controller_config modem_qcom_v1_mhiv_config = { +static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { .max_channels = 128, .timeout_ms = 8000, .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels), @@ -173,6 +236,15 @@ static struct mhi_controller_config modem_qcom_v1_mhiv_config = { .event_cfg = modem_qcom_v1_mhi_events, }; +static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { + .name = "qcom-sdx65m", + .fw = "qcom/sdx65m/xbl.elf", + .edl = "qcom/sdx65m/edl.mbn", + .config = &modem_qcom_v1_mhiv_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .name = "qcom-sdx55m", .fw = "qcom/sdx55m/sbl1.mbn", @@ -182,15 +254,121 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .dma_data_width = 32 }; +static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { + .name = "qcom-sdx24", + .edl = "qcom/prog_firehose_sdx24.mbn", + .config = &modem_qcom_v1_mhiv_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + +static const struct mhi_channel_config mhi_quectel_em1xx_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "NMEA", 32, 0), + MHI_CHANNEL_CONFIG_DL(1, "NMEA", 32, 0), + MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), + MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), + /* The EDL firmware is a flash-programmer exposing firehose protocol */ + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), +}; + +static struct mhi_event_config mhi_quectel_em1xx_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 128), + MHI_EVENT_CONFIG_DATA(1, 128), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101) +}; + +static const struct mhi_controller_config modem_quectel_em1xx_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_quectel_em1xx_channels), + .ch_cfg = mhi_quectel_em1xx_channels, + .num_events = ARRAY_SIZE(mhi_quectel_em1xx_events), + .event_cfg = mhi_quectel_em1xx_events, +}; + +static const struct mhi_pci_dev_info mhi_quectel_em1xx_info = { + .name = "quectel-em1xx", + .edl = "qcom/prog_firehose_sdx24.mbn", + .config = &modem_quectel_em1xx_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + +static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 0), + MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 0), + MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_UL(32, "AT", 32, 0), + MHI_CHANNEL_CONFIG_DL(33, "AT", 32, 0), + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), +}; + +static struct mhi_event_config mhi_foxconn_sdx55_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 128), + MHI_EVENT_CONFIG_DATA(1, 128), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101) +}; + +static const struct mhi_controller_config modem_foxconn_sdx55_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_foxconn_sdx55_channels), + .ch_cfg = mhi_foxconn_sdx55_channels, + .num_events = ARRAY_SIZE(mhi_foxconn_sdx55_events), + .event_cfg = mhi_foxconn_sdx55_events, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { + .name = "foxconn-sdx55", + .fw = "qcom/sdx55m/sbl1.mbn", + .edl = "qcom/sdx55m/edl.mbn", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + static const struct pci_device_id mhi_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, + { PCI_DEVICE(0x1eac, 0x1001), /* EM120R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, + /* T99W175 (sdx55), Both for eSIM and Non-eSIM */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0ab), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* DW5930e (sdx55), With eSIM, It's also T99W175 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b0), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* DW5930e (sdx55), Non-eSIM, It's also T99W175 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); enum mhi_pci_device_status { MHI_PCI_DEV_STARTED, + MHI_PCI_DEV_SUSPENDED, }; struct mhi_pci_device { @@ -224,12 +402,31 @@ static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl, case MHI_CB_FATAL_ERROR: case MHI_CB_SYS_ERROR: dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb); + pm_runtime_forbid(&pdev->dev); + break; + case MHI_CB_EE_MISSION_MODE: + pm_runtime_allow(&pdev->dev); break; default: break; } } +static void mhi_pci_wake_get_nop(struct mhi_controller *mhi_cntrl, bool force) +{ + /* no-op */ +} + +static void mhi_pci_wake_put_nop(struct mhi_controller *mhi_cntrl, bool override) +{ + /* no-op */ +} + +static void mhi_pci_wake_toggle_nop(struct mhi_controller *mhi_cntrl) +{ + /* no-op */ +} + static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl) { struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev); @@ -330,13 +527,19 @@ static int mhi_pci_get_irqs(struct mhi_controller *mhi_cntrl, static int mhi_pci_runtime_get(struct mhi_controller *mhi_cntrl) { - /* no PM for now */ - return 0; + /* The runtime_get() MHI callback means: + * Do whatever is requested to leave M3. + */ + return pm_runtime_get(mhi_cntrl->cntrl_dev); } static void mhi_pci_runtime_put(struct mhi_controller *mhi_cntrl) { - /* no PM for now */ + /* The runtime_put() MHI callback means: + * Device can be moved in M3 state. + */ + pm_runtime_mark_last_busy(mhi_cntrl->cntrl_dev); + pm_runtime_put(mhi_cntrl->cntrl_dev); } static void mhi_pci_recovery_work(struct work_struct *work) @@ -350,6 +553,7 @@ static void mhi_pci_recovery_work(struct work_struct *work) dev_warn(&pdev->dev, "device recovery started\n"); del_timer(&mhi_pdev->health_check_timer); + pm_runtime_forbid(&pdev->dev); /* Clean up MHI state */ if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) { @@ -357,7 +561,6 @@ static void mhi_pci_recovery_work(struct work_struct *work) mhi_unprepare_after_power_down(mhi_cntrl); } - /* Check if we can recover without full reset */ pci_set_power_state(pdev, PCI_D0); pci_load_saved_state(pdev, mhi_pdev->pci_state); pci_restore_state(pdev); @@ -391,6 +594,10 @@ static void health_check(struct timer_list *t) struct mhi_pci_device *mhi_pdev = from_timer(mhi_pdev, t, health_check_timer); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; + if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || + test_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return; + if (!mhi_pci_is_alive(mhi_cntrl)) { dev_err(mhi_cntrl->cntrl_dev, "Device died\n"); queue_work(system_long_wq, &mhi_pdev->recovery_work); @@ -433,6 +640,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->status_cb = mhi_pci_status_cb; mhi_cntrl->runtime_get = mhi_pci_runtime_get; mhi_cntrl->runtime_put = mhi_pci_runtime_put; + mhi_cntrl->wake_get = mhi_pci_wake_get_nop; + mhi_cntrl->wake_put = mhi_pci_wake_put_nop; + mhi_cntrl->wake_toggle = mhi_pci_wake_toggle_nop; err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width)); if (err) @@ -444,9 +654,12 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, mhi_pdev); - /* Have stored pci confspace at hand for restore in sudden PCI error */ + /* Have stored pci confspace at hand for restore in sudden PCI error. + * cache the state locally and discard the PCI core one. + */ pci_save_state(pdev); mhi_pdev->pci_state = pci_store_saved_state(pdev); + pci_load_saved_state(pdev, NULL); pci_enable_pcie_error_reporting(pdev); @@ -472,6 +685,14 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* start health check */ mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + /* Only allow runtime-suspend if PME capable (for wakeup) */ + if (pci_pme_capable(pdev, PCI_D3hot)) { + pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + } + return 0; err_unprepare: @@ -495,9 +716,19 @@ static void mhi_pci_remove(struct pci_dev *pdev) mhi_unprepare_after_power_down(mhi_cntrl); } + /* balancing probe put_noidle */ + if (pci_pme_capable(pdev, PCI_D3hot)) + pm_runtime_get_noresume(&pdev->dev); + mhi_unregister_controller(mhi_cntrl); } +static void mhi_pci_shutdown(struct pci_dev *pdev) +{ + mhi_pci_remove(pdev); + pci_set_power_state(pdev, PCI_D3hot); +} + static void mhi_pci_reset_prepare(struct pci_dev *pdev) { struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev); @@ -605,41 +836,59 @@ static const struct pci_error_handlers mhi_pci_err_handler = { .reset_done = mhi_pci_reset_done, }; -static int __maybe_unused mhi_pci_suspend(struct device *dev) +static int __maybe_unused mhi_pci_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; + int err; + + if (test_and_set_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return 0; del_timer(&mhi_pdev->health_check_timer); cancel_work_sync(&mhi_pdev->recovery_work); + if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || + mhi_cntrl->ee != MHI_EE_AMSS) + goto pci_suspend; /* Nothing to do at MHI level */ + /* Transition to M3 state */ - mhi_pm_suspend(mhi_cntrl); + err = mhi_pm_suspend(mhi_cntrl); + if (err) { + dev_err(&pdev->dev, "failed to suspend device: %d\n", err); + clear_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status); + return -EBUSY; + } - pci_save_state(pdev); +pci_suspend: pci_disable_device(pdev); pci_wake_from_d3(pdev, true); - pci_set_power_state(pdev, PCI_D3hot); return 0; } -static int __maybe_unused mhi_pci_resume(struct device *dev) +static int __maybe_unused mhi_pci_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; int err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_set_master(pdev); + if (!test_and_clear_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return 0; err = pci_enable_device(pdev); if (err) goto err_recovery; + pci_set_master(pdev); + pci_wake_from_d3(pdev, false); + + if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || + mhi_cntrl->ee != MHI_EE_AMSS) + return 0; /* Nothing to do at MHI level */ + /* Exit M3, transition to M0 state */ err = mhi_pm_resume(mhi_cntrl); if (err) { @@ -650,16 +899,44 @@ static int __maybe_unused mhi_pci_resume(struct device *dev) /* Resume health check */ mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + /* It can be a remote wakeup (no mhi runtime_get), update access time */ + pm_runtime_mark_last_busy(dev); + return 0; err_recovery: - /* The device may have loose power or crashed, try recovering it */ + /* Do not fail to not mess up our PCI device state, the device likely + * lost power (d3cold) and we simply need to reset it from the recovery + * procedure, trigger the recovery asynchronously to prevent system + * suspend exit delaying. + */ queue_work(system_long_wq, &mhi_pdev->recovery_work); + pm_runtime_mark_last_busy(dev); - return err; + return 0; +} + +static int __maybe_unused mhi_pci_suspend(struct device *dev) +{ + pm_runtime_disable(dev); + return mhi_pci_runtime_suspend(dev); +} + +static int __maybe_unused mhi_pci_resume(struct device *dev) +{ + int ret; + + /* Depending the platform, device may have lost power (d3cold), we need + * to resume it now to check its state and recover when necessary. + */ + ret = mhi_pci_runtime_resume(dev); + pm_runtime_enable(dev); + + return ret; } static const struct dev_pm_ops mhi_pci_pm_ops = { + SET_RUNTIME_PM_OPS(mhi_pci_runtime_suspend, mhi_pci_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(mhi_pci_suspend, mhi_pci_resume) }; @@ -668,6 +945,7 @@ static struct pci_driver mhi_pci_driver = { .id_table = mhi_pci_id_table, .probe = mhi_pci_probe, .remove = mhi_pci_remove, + .shutdown = mhi_pci_shutdown, .err_handler = &mhi_pci_err_handler, .driver.pm = &mhi_pci_pm_ops }; diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c index 03ddcf426887b445ef4bb0e4caacf9cc76d3c44b..0b8f53a688b8a472a793a5f21545fa17b0442704 100644 --- a/drivers/bus/qcom-ebi2.c +++ b/drivers/bus/qcom-ebi2.c @@ -353,8 +353,10 @@ static int qcom_ebi2_probe(struct platform_device *pdev) /* Figure out the chipselect */ ret = of_property_read_u32(child, "reg", &csindex); - if (ret) + if (ret) { + of_node_put(child); return ret; + } if (csindex > 5) { dev_err(dev, diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 3d74f237f005bb3358e8040b9a63e16c2de4c4d0..5fae60f8c1355519c0c4825fae8888e4990f7ef0 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -288,7 +288,7 @@ static int sysc_add_named_clock_from_child(struct sysc *ddata, * limit for clk_get(). If cl ever needs to be freed, it should be done * with clkdev_drop(). */ - cl = kcalloc(1, sizeof(*cl), GFP_KERNEL); + cl = kzalloc(sizeof(*cl), GFP_KERNEL); if (!cl) return -ENOMEM; @@ -635,6 +635,51 @@ static int sysc_parse_and_check_child_range(struct sysc *ddata) return 0; } +/* Interconnect instances to probe before l4_per instances */ +static struct resource early_bus_ranges[] = { + /* am3/4 l4_wkup */ + { .start = 0x44c00000, .end = 0x44c00000 + 0x300000, }, + /* omap4/5 and dra7 l4_cfg */ + { .start = 0x4a000000, .end = 0x4a000000 + 0x300000, }, + /* omap4 l4_wkup */ + { .start = 0x4a300000, .end = 0x4a300000 + 0x30000, }, + /* omap5 and dra7 l4_wkup without dra7 dcan segment */ + { .start = 0x4ae00000, .end = 0x4ae00000 + 0x30000, }, +}; + +static atomic_t sysc_defer = ATOMIC_INIT(10); + +/** + * sysc_defer_non_critical - defer non_critical interconnect probing + * @ddata: device driver data + * + * We want to probe l4_cfg and l4_wkup interconnect instances before any + * l4_per instances as l4_per instances depend on resources on l4_cfg and + * l4_wkup interconnects. + */ +static int sysc_defer_non_critical(struct sysc *ddata) +{ + struct resource *res; + int i; + + if (!atomic_read(&sysc_defer)) + return 0; + + for (i = 0; i < ARRAY_SIZE(early_bus_ranges); i++) { + res = &early_bus_ranges[i]; + if (ddata->module_pa >= res->start && + ddata->module_pa <= res->end) { + atomic_set(&sysc_defer, 0); + + return 0; + } + } + + atomic_dec_if_positive(&sysc_defer); + + return -EPROBE_DEFER; +} + static struct device_node *stdout_path; static void sysc_init_stdout_path(struct sysc *ddata) @@ -856,15 +901,19 @@ static int sysc_map_and_check_registers(struct sysc *ddata) struct device_node *np = ddata->dev->of_node; int error; - if (!of_get_property(np, "reg", NULL)) - return 0; - error = sysc_parse_and_check_child_range(ddata); if (error) return error; + error = sysc_defer_non_critical(ddata); + if (error) + return error; + sysc_check_children(ddata); + if (!of_get_property(np, "reg", NULL)) + return 0; + error = sysc_parse_registers(ddata); if (error) return error; @@ -1447,12 +1496,16 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("dwc3", 0, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 0), SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), + SYSC_QUIRK("elm", 0x48080000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 0), + SYSC_QUIRK("emif", 0, 0, -ENODEV, -ENODEV, 0x40441403, 0xffff0fff, 0), + SYSC_QUIRK("emif", 0, 0, -ENODEV, -ENODEV, 0x50440500, 0xffffffff, 0), SYSC_QUIRK("epwmss", 0, 0, 0x4, -ENODEV, 0x47400001, 0xffffffff, 0), SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -ENODEV, 0, 0, 0), SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 0), SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50031d00, 0xffffffff, 0), SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0), + SYSC_QUIRK("keypad", 0x4a31c000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 0), SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0), SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0), SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0), @@ -1464,11 +1517,14 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("ocp2scp", 0, 0, -ENODEV, -ENODEV, 0x50060007, 0xffffffff, 0), SYSC_QUIRK("padconf", 0, 0, 0x10, -ENODEV, 0x4fff0800, 0xffffffff, 0), SYSC_QUIRK("padconf", 0, 0, -ENODEV, -ENODEV, 0x40001100, 0xffffffff, 0), + SYSC_QUIRK("pcie", 0x51000000, -ENODEV, -ENODEV, -ENODEV, 0, 0, 0), + SYSC_QUIRK("pcie", 0x51800000, -ENODEV, -ENODEV, -ENODEV, 0, 0, 0), SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000100, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x00004102, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0), SYSC_QUIRK("rfbi", 0x4832a800, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), SYSC_QUIRK("rfbi", 0x58002000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), + SYSC_QUIRK("sata", 0, 0xfc, 0x1100, -ENODEV, 0x5e412000, 0xffffffff, 0), SYSC_QUIRK("scm", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0), SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4e8b0100, 0xffffffff, 0), SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4f000100, 0xffffffff, 0), @@ -1592,7 +1648,7 @@ static u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset, case SOC_UNKNOWN: default: return 0; - }; + } /* Remap the whole module range to be able to reset dispc outputs */ devm_iounmap(ddata->dev, ddata->module_va); @@ -2802,6 +2858,7 @@ static int sysc_init_soc(struct sysc *ddata) const struct soc_device_attribute *match; struct ti_sysc_platform_data *pdata; unsigned long features = 0; + struct device_node *np; if (sysc_soc) return 0; @@ -2822,6 +2879,24 @@ static int sysc_init_soc(struct sysc *ddata) if (match && match->data) sysc_soc->soc = (int)match->data; + /* + * Check and warn about possible old incomplete dtb. We now want to see + * simple-pm-bus instead of simple-bus in the dtb for genpd using SoCs. + */ + switch (sysc_soc->soc) { + case SOC_AM3: + case SOC_AM4: + case SOC_4430 ... SOC_4470: + case SOC_5430: + case SOC_DRA7: + np = of_find_node_by_path("/ocp"); + WARN_ONCE(np && of_device_is_compatible(np, "simple-bus"), + "ti-sysc: Incomplete old dtb, please update\n"); + break; + default: + break; + } + /* Ignore devices that are not available on HS and EMU SoCs */ if (!sysc_soc->general_purpose) { switch (sysc_soc->soc) { @@ -2830,7 +2905,7 @@ static int sysc_init_soc(struct sysc *ddata) break; default: break; - }; + } } match = soc_device_match(sysc_soc_feat_match); diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 45ac7ab003ce30cb1b2f454c28948643366bb865..deb85a334c937506f68c80ecd235b42fdb567b44 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -836,7 +836,7 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) Dummy = readb(apbs[IndexCard].RamIO + VERS); kfree(adgl); mutex_unlock(&ac_mutex); - return 0; + return ret; err: if (warncount) { diff --git a/drivers/char/hw_random/ba431-rng.c b/drivers/char/hw_random/ba431-rng.c index 410b50b05e2104a95cd46e0dfc8c45e5ef486946..5b7ca0416490a27b78557b9939ebd80e3cd4706b 100644 --- a/drivers/char/hw_random/ba431-rng.c +++ b/drivers/char/hw_random/ba431-rng.c @@ -170,7 +170,6 @@ static int ba431_trng_init(struct hwrng *rng) static int ba431_trng_probe(struct platform_device *pdev) { struct ba431_trng *ba431; - struct resource *res; int ret; ba431 = devm_kzalloc(&pdev->dev, sizeof(*ba431), GFP_KERNEL); @@ -179,8 +178,7 @@ static int ba431_trng_probe(struct platform_device *pdev) ba431->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ba431->base = devm_ioremap_resource(&pdev->dev, res); + ba431->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ba431->base)) return PTR_ERR(ba431->base); @@ -193,7 +191,7 @@ static int ba431_trng_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ba431); - ret = hwrng_register(&ba431->rng); + ret = devm_hwrng_register(&pdev->dev, &ba431->rng); if (ret) { dev_err(&pdev->dev, "BA431 registration failed (%d)\n", ret); return ret; @@ -204,15 +202,6 @@ static int ba431_trng_probe(struct platform_device *pdev) return 0; } -static int ba431_trng_remove(struct platform_device *pdev) -{ - struct ba431_trng *ba431 = platform_get_drvdata(pdev); - - hwrng_unregister(&ba431->rng); - - return 0; -} - static const struct of_device_id ba431_trng_dt_ids[] = { { .compatible = "silex-insight,ba431-rng", .data = NULL }, { /* sentinel */ } @@ -225,7 +214,6 @@ static struct platform_driver ba431_trng_driver = { .of_match_table = ba431_trng_dt_ids, }, .probe = ba431_trng_probe, - .remove = ba431_trng_remove, }; module_platform_driver(ba431_trng_driver); diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c index 1a7c43b43c6b093837184b3b4a6183982dfa3436..e7dd457e9b22bde15bb896762ac170b95aa662f1 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/printk.h> #include <linux/clk.h> +#include <linux/reset.h> #define RNG_CTRL 0x0 #define RNG_STATUS 0x4 @@ -32,6 +33,7 @@ struct bcm2835_rng_priv { void __iomem *base; bool mask_interrupts; struct clk *clk; + struct reset_control *reset; }; static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng) @@ -88,11 +90,13 @@ static int bcm2835_rng_init(struct hwrng *rng) int ret = 0; u32 val; - if (!IS_ERR(priv->clk)) { - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + ret = reset_control_reset(priv->reset); + if (ret) + return ret; if (priv->mask_interrupts) { /* mask the interrupt */ @@ -115,8 +119,7 @@ static void bcm2835_rng_cleanup(struct hwrng *rng) /* disable rng hardware */ rng_writel(priv, 0, RNG_CTRL); - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); } struct bcm2835_rng_of_data { @@ -155,9 +158,13 @@ static int bcm2835_rng_probe(struct platform_device *pdev) return PTR_ERR(priv->base); /* Clock is optional on most platforms */ - priv->clk = devm_clk_get(dev, NULL); - if (PTR_ERR(priv->clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + priv->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->reset = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(priv->reset)) + return PTR_ERR(priv->reset); priv->rng.name = pdev->name; priv->rng.init = bcm2835_rng_init; diff --git a/drivers/char/hw_random/cctrng.c b/drivers/char/hw_random/cctrng.c index 7a293f2147a00c7586a068297c4b50160dd1a02f..302ffa354c2fda6cf59432b0af2650f55f9606a6 100644 --- a/drivers/char/hw_random/cctrng.c +++ b/drivers/char/hw_random/cctrng.c @@ -486,7 +486,6 @@ static void cc_trng_clk_fini(struct cctrng_drvdata *drvdata) static int cctrng_probe(struct platform_device *pdev) { - struct resource *req_mem_cc_regs = NULL; struct cctrng_drvdata *drvdata; struct device *dev = &pdev->dev; int rc = 0; @@ -510,27 +509,16 @@ static int cctrng_probe(struct platform_device *pdev) drvdata->circ.buf = (char *)drvdata->data_buf; - /* Get device resources */ - /* First CC registers space */ - req_mem_cc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - /* Map registers space */ - drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs); + drvdata->cc_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(drvdata->cc_base)) { dev_err(dev, "Failed to ioremap registers"); return PTR_ERR(drvdata->cc_base); } - dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name, - req_mem_cc_regs); - dev_dbg(dev, "CC registers mapped from %pa to 0x%p\n", - &req_mem_cc_regs->start, drvdata->cc_base); - /* Then IRQ */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "Failed getting IRQ resource\n"); + if (irq < 0) return irq; - } /* parse sampling rate from device tree */ rc = cc_trng_parse_sampling_ratio(drvdata); @@ -585,7 +573,7 @@ static int cctrng_probe(struct platform_device *pdev) atomic_set(&drvdata->pending_hw, 1); /* registration of the hwrng device */ - rc = hwrng_register(&drvdata->rng); + rc = devm_hwrng_register(dev, &drvdata->rng); if (rc) { dev_err(dev, "Could not register hwrng device.\n"); goto post_pm_err; @@ -618,8 +606,6 @@ static int cctrng_remove(struct platform_device *pdev) dev_dbg(dev, "Releasing cctrng resources...\n"); - hwrng_unregister(&drvdata->rng); - cc_trng_pm_fini(drvdata); cc_trng_clk_fini(drvdata); diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 8c1c47dd9f4644d84af5f519c107fa29450651a3..adb3c2bd7783e8d6907c5a62da73466730b54204 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -396,7 +396,7 @@ static ssize_t hwrng_attr_selected_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", cur_rng_set_by_user); + return sysfs_emit(buf, "%d\n", cur_rng_set_by_user); } static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index eb7db27f9f196624c6ae857ffabb8bea950ff806..d740b8814bf3fe1ea02c8bc4747920e51ec60a22 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -25,13 +25,13 @@ */ #include <linux/hw_random.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/stop_machine.h> #include <linux/delay.h> #include <linux/slab.h> -#include <asm/io.h> #define PFX KBUILD_MODNAME ": " diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 5cc5fc504968267b0d17251477477f41ea7a3fee..cede9f15910293752281e34df0dbc35b186bfe05 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -30,8 +30,7 @@ #include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/clk.h> - -#include <asm/io.h> +#include <linux/io.h> #define RNG_REG_STATUS_RDY (1 << 0) @@ -378,16 +377,13 @@ MODULE_DEVICE_TABLE(of, omap_rng_of_match); static int of_get_omap_rng_device_details(struct omap_rng_dev *priv, struct platform_device *pdev) { - const struct of_device_id *match; struct device *dev = &pdev->dev; int irq, err; - match = of_match_device(of_match_ptr(omap_rng_of_match), dev); - if (!match) { - dev_err(dev, "no compatible OF match\n"); - return -EINVAL; - } - priv->pdata = match->data; + priv->pdata = of_device_get_match_data(dev); + if (!priv->pdata) + return -ENODEV; + if (of_device_is_compatible(dev->of_node, "ti,omap4-rng") || of_device_is_compatible(dev->of_node, "inside-secure,safexcel-eip76")) { diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c index e8210c1715cfd50aefff9c561b30b3fa389a873b..99c8bd0859a1487cfe933e9e9309d82cafc07b90 100644 --- a/drivers/char/hw_random/pic32-rng.c +++ b/drivers/char/hw_random/pic32-rng.c @@ -96,7 +96,7 @@ static int pic32_rng_probe(struct platform_device *pdev) priv->rng.name = pdev->name; priv->rng.read = pic32_rng_read; - ret = hwrng_register(&priv->rng); + ret = devm_hwrng_register(&pdev->dev, &priv->rng); if (ret) goto err_register; @@ -113,7 +113,6 @@ static int pic32_rng_remove(struct platform_device *pdev) { struct pic32_rng *rng = platform_get_drvdata(pdev); - hwrng_unregister(&rng->rng); writel(0, rng->base + RNGCON); clk_disable_unprepare(rng->clk); return 0; diff --git a/drivers/char/hw_random/xiphera-trng.c b/drivers/char/hw_random/xiphera-trng.c index 7bdab8c8a6a8f40b719574750e552a82a95b7cd4..2a9fea72b2e0d0bc7426b0a5831fff0ffc078614 100644 --- a/drivers/char/hw_random/xiphera-trng.c +++ b/drivers/char/hw_random/xiphera-trng.c @@ -63,14 +63,12 @@ static int xiphera_trng_probe(struct platform_device *pdev) int ret; struct xiphera_trng *trng; struct device *dev = &pdev->dev; - struct resource *res; trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); if (!trng) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - trng->mem = devm_ioremap_resource(dev, res); + trng->mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(trng->mem)) return PTR_ERR(trng->mem); diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c index a140203c079bad7cbd52358985daf4963b7eabc1..eefe362f65f0780923074cd592b09764133782de 100644 --- a/drivers/char/ipmi/kcs_bmc_aspeed.c +++ b/drivers/char/ipmi/kcs_bmc_aspeed.c @@ -27,7 +27,6 @@ #define KCS_CHANNEL_MAX 4 -/* mapped to lpc-bmc@0 IO space */ #define LPC_HICR0 0x000 #define LPC_HICR0_LPC3E BIT(7) #define LPC_HICR0_LPC2E BIT(6) @@ -52,15 +51,13 @@ #define LPC_STR1 0x03C #define LPC_STR2 0x040 #define LPC_STR3 0x044 - -/* mapped to lpc-host@80 IO space */ -#define LPC_HICRB 0x080 +#define LPC_HICRB 0x100 #define LPC_HICRB_IBFIF4 BIT(1) #define LPC_HICRB_LPC4E BIT(0) -#define LPC_LADR4 0x090 -#define LPC_IDR4 0x094 -#define LPC_ODR4 0x098 -#define LPC_STR4 0x09C +#define LPC_LADR4 0x110 +#define LPC_IDR4 0x114 +#define LPC_ODR4 0x118 +#define LPC_STR4 0x11C struct aspeed_kcs_bmc { struct regmap *map; @@ -348,12 +345,20 @@ static int aspeed_kcs_probe(struct platform_device *pdev) struct device_node *np; int rc; - np = pdev->dev.of_node; + np = dev->of_node->parent; + if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && + !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && + !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { + dev_err(dev, "unsupported LPC device binding\n"); + return -ENODEV; + } + + np = dev->of_node; if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc") || - of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc")) + of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc")) kcs_bmc = aspeed_kcs_probe_of_v1(pdev); else if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc-v2") || - of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc-v2")) + of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc-v2")) kcs_bmc = aspeed_kcs_probe_of_v2(pdev); else return -EINVAL; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 862c2fd933c7beace6e01d6e573d5f510ee01cb4..0e22e3b0a04e7f621f67f919b3c00ce500f62dd6 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -546,7 +546,7 @@ static int lp_open(struct inode *inode, struct file *file) } /* Determine if the peripheral supports ECP mode */ lp_claim_parport_or_block(&lp_table[minor]); - if ( (lp_table[minor].dev->port->modes & PARPORT_MODE_ECP) && + if ((lp_table[minor].dev->port->modes & PARPORT_MODE_ECP) && !parport_negotiate(lp_table[minor].dev->port, IEEE1284_MODE_ECP)) { printk(KERN_INFO "lp%d: ECP mode\n", minor); @@ -590,7 +590,7 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd, return -ENODEV; if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; - switch ( cmd ) { + switch (cmd) { case LPTIME: if (arg > UINT_MAX / HZ) return -EINVAL; diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index 5e1618a76b2a31df845d9b9c16787b20207a8a02..8588b51202e53a32d50fc9aedb16883d0df5d7ad 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -177,14 +177,10 @@ int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData) return retval; } -int tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData) +void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData) { - int retval = 0; - PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_Cleanup entry and exit pBDData %p\n", pBDData); - - return retval; } int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData) diff --git a/drivers/char/mwave/tp3780i.h b/drivers/char/mwave/tp3780i.h index 07685b68538f79a0443c5dd65154731b18f2c1c7..8bd976d42faefc291078463ec8e726c0b39b8a7c 100644 --- a/drivers/char/mwave/tp3780i.h +++ b/drivers/char/mwave/tp3780i.h @@ -91,7 +91,7 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData); int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData); int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData); int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities); -int tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData); +void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData); int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode, void __user *pvBuffer, unsigned int uCount, unsigned long ulDSPAddr); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 2be8d9a8eec5d578d6e06b89d3dfe926b1c8bc64..3287a7627ed00c08df7aa20edbecc5c2dc813db7 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -530,8 +530,6 @@ static int mgslpc_probe(struct pcmcia_device *link) info->port.ops = &mgslpc_port_ops; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; - info->port.close_delay = 5*HZ/10; - info->port.closing_wait = 30*HZ; init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->lock); diff --git a/drivers/char/random.c b/drivers/char/random.c index 0fe9e200e4c8401681954e7f59cd785205b2924b..605969ed0f965c224b3d562ce9dd976a56aab717 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -500,7 +500,6 @@ struct entropy_store { unsigned short add_ptr; unsigned short input_rotate; int entropy_count; - unsigned int initialized:1; unsigned int last_data_init:1; __u8 last_data[EXTRACT_SIZE]; }; @@ -660,7 +659,7 @@ static void process_random_ready_list(void) */ static void credit_entropy_bits(struct entropy_store *r, int nbits) { - int entropy_count, orig, has_initialized = 0; + int entropy_count, orig; const int pool_size = r->poolinfo->poolfracbits; int nfrac = nbits << ENTROPY_SHIFT; @@ -717,23 +716,14 @@ retry: if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; - if (has_initialized) { - r->initialized = 1; - kill_fasync(&fasync, SIGIO, POLL_IN); - } - trace_credit_entropy_bits(r->name, nbits, entropy_count >> ENTROPY_SHIFT, _RET_IP_); if (r == &input_pool) { int entropy_bits = entropy_count >> ENTROPY_SHIFT; - if (crng_init < 2) { - if (entropy_bits < 128) - return; + if (crng_init < 2 && entropy_bits >= 128) crng_reseed(&primary_crng, r); - entropy_bits = ENTROPY_BITS(r); - } } } @@ -819,7 +809,7 @@ static bool __init crng_init_try_arch_early(struct crng_state *crng) static void __maybe_unused crng_initialize_secondary(struct crng_state *crng) { - memcpy(&crng->state[0], "expand 32-byte k", 16); + chacha_init_consts(crng->state); _get_random_bytes(&crng->state[4], sizeof(__u32) * 12); crng_init_try_arch(crng); crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; @@ -827,7 +817,7 @@ static void __maybe_unused crng_initialize_secondary(struct crng_state *crng) static void __init crng_initialize_primary(struct crng_state *crng) { - memcpy(&crng->state[0], "expand 32-byte k", 16); + chacha_init_consts(crng->state); _extract_entropy(&input_pool, &crng->state[4], sizeof(__u32) * 12, 0); if (crng_init_try_arch_early(crng) && trust_cpu) { invalidate_batched_entropy(); @@ -1372,8 +1362,7 @@ retry: } /* - * This function does the actual extraction for extract_entropy and - * extract_entropy_user. + * This function does the actual extraction for extract_entropy. * * Note: we assume that .poolwords is a multiple of 16 words. */ diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c index 3633ed70f48fa71ad2d4e2c264788bb2f75e3a21..1b18ce5ebab1ef4c49348d48a52f7de2fec48627 100644 --- a/drivers/char/tpm/eventlog/acpi.c +++ b/drivers/char/tpm/eventlog/acpi.c @@ -41,6 +41,27 @@ struct acpi_tcpa { }; }; +/* Check that the given log is indeed a TPM2 log. */ +static bool tpm_is_tpm2_log(void *bios_event_log, u64 len) +{ + struct tcg_efi_specid_event_head *efispecid; + struct tcg_pcr_event *event_header; + int n; + + if (len < sizeof(*event_header)) + return false; + len -= sizeof(*event_header); + event_header = bios_event_log; + + if (len < sizeof(*efispecid)) + return false; + efispecid = (struct tcg_efi_specid_event_head *)event_header->event; + + n = memcmp(efispecid->signature, TCG_SPECID_SIG, + sizeof(TCG_SPECID_SIG)); + return n == 0; +} + /* read binary bios log */ int tpm_read_log_acpi(struct tpm_chip *chip) { @@ -52,6 +73,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip) struct acpi_table_tpm2 *tbl; struct acpi_tpm2_phy *tpm2_phy; int format; + int ret; log = &chip->log; @@ -112,6 +134,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip) log->bios_event_log_end = log->bios_event_log + len; + ret = -EIO; virt = acpi_os_map_iomem(start, len); if (!virt) goto err; @@ -119,11 +142,19 @@ int tpm_read_log_acpi(struct tpm_chip *chip) memcpy_fromio(log->bios_event_log, virt, len); acpi_os_unmap_iomem(virt, len); + + if (chip->flags & TPM_CHIP_FLAG_TPM2 && + !tpm_is_tpm2_log(log->bios_event_log, len)) { + /* try EFI log next */ + ret = -ENODEV; + goto err; + } + return format; err: kfree(log->bios_event_log); log->bios_event_log = NULL; - return -EIO; + return ret; } diff --git a/drivers/char/tpm/eventlog/common.c b/drivers/char/tpm/eventlog/common.c index 7460f230bae4c6dbc8ed68acfbb42200a0c5a9b0..8512ec76d5260d6788686b33bd3dc79db34fa937 100644 --- a/drivers/char/tpm/eventlog/common.c +++ b/drivers/char/tpm/eventlog/common.c @@ -107,6 +107,9 @@ void tpm_bios_log_setup(struct tpm_chip *chip) int log_version; int rc = 0; + if (chip->flags & TPM_CHIP_FLAG_VIRTUAL) + return; + rc = tpm_read_log(chip); if (rc < 0) return; diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c index 35229e5143cacde3771a460f2e1c820579eca025..e6cb9d525e30ca6457873ddc582baa21bd384264 100644 --- a/drivers/char/tpm/eventlog/efi.c +++ b/drivers/char/tpm/eventlog/efi.c @@ -17,6 +17,7 @@ int tpm_read_log_efi(struct tpm_chip *chip) { struct efi_tcg2_final_events_table *final_tbl = NULL; + int final_events_log_size = efi_tpm_final_log_size; struct linux_efi_tpm_eventlog *log_tbl; struct tpm_bios_log *log; u32 log_size; @@ -66,12 +67,12 @@ int tpm_read_log_efi(struct tpm_chip *chip) ret = tpm_log_version; if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || - efi_tpm_final_log_size == 0 || + final_events_log_size == 0 || tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) goto out; final_tbl = memremap(efi.tpm_final_log, - sizeof(*final_tbl) + efi_tpm_final_log_size, + sizeof(*final_tbl) + final_events_log_size, MEMREMAP_WB); if (!final_tbl) { pr_err("Could not map UEFI TPM final log\n"); @@ -80,10 +81,18 @@ int tpm_read_log_efi(struct tpm_chip *chip) goto out; } - efi_tpm_final_log_size -= log_tbl->final_events_preboot_size; + /* + * The 'final events log' size excludes the 'final events preboot log' + * at its beginning. + */ + final_events_log_size -= log_tbl->final_events_preboot_size; + /* + * Allocate memory for the 'combined log' where we will append the + * 'final events log' to. + */ tmp = krealloc(log->bios_event_log, - log_size + efi_tpm_final_log_size, + log_size + final_events_log_size, GFP_KERNEL); if (!tmp) { kfree(log->bios_event_log); @@ -94,15 +103,19 @@ int tpm_read_log_efi(struct tpm_chip *chip) log->bios_event_log = tmp; /* - * Copy any of the final events log that didn't also end up in the - * main log. Events can be logged in both if events are generated + * Append any of the 'final events log' that didn't also end up in the + * 'main log'. Events can be logged in both if events are generated * between GetEventLog() and ExitBootServices(). */ memcpy((void *)log->bios_event_log + log_size, final_tbl->events + log_tbl->final_events_preboot_size, - efi_tpm_final_log_size); + final_events_log_size); + /* + * The size of the 'combined log' is the size of the 'main log' plus + * the size of the 'final events log'. + */ log->bios_event_log_end = log->bios_event_log + - log_size + efi_tpm_final_log_size; + log_size + final_events_log_size; out: memunmap(final_tbl); diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index ec9a65e7887dd5d49ef789e1e27f19374a8d07cd..f19c227d20f485f4151c5b8f7e6cf926eb5474b6 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -483,6 +483,7 @@ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) expected = be32_to_cpup((__be32 *)(buf + 2)); if (expected > buf_len) { dev_err(&chip->dev, "Buffer too small to receive i2c data\n"); + rc = -E2BIG; goto out_err; } diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 6a0059e508e3861e062afb33feb7f4ceac089cdb..93f5d11c830b792425b6fc45e7e269091719d942 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -158,12 +158,23 @@ static int tpk_ioctl(struct tty_struct *tty, return 0; } +/* + * TTY operations hangup function. + */ +static void tpk_hangup(struct tty_struct *tty) +{ + struct ttyprintk_port *tpkp = tty->driver_data; + + tty_port_hangup(&tpkp->port); +} + static const struct tty_operations ttyprintk_ops = { .open = tpk_open, .close = tpk_close, .write = tpk_write, .write_room = tpk_write_room, .ioctl = tpk_ioctl, + .hangup = tpk_hangup, }; static const struct tty_port_operations null_ops = { }; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 1836cc56e357b7b428808e5a0d32163e68f2e491..59dfd9c421a1eabff55dc721639349216c699fed 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1456,18 +1456,15 @@ static int add_port(struct ports_device *portdev, u32 id) */ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); - if (pdrvdata.debugfs_dir) { - /* - * Finally, create the debugfs file that we can use to - * inspect a port's state at any time - */ - snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", - port->portdev->vdev->index, id); - port->debugfs_file = debugfs_create_file(debugfs_name, 0444, - pdrvdata.debugfs_dir, - port, - &port_debugfs_fops); - } + /* + * Finally, create the debugfs file that we can use to + * inspect a port's state at any time + */ + snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", + port->portdev->vdev->index, id); + port->debugfs_file = debugfs_create_file(debugfs_name, 0444, + pdrvdata.debugfs_dir, + port, &port_debugfs_fops); return 0; free_inbufs: @@ -2244,8 +2241,6 @@ static int __init init(void) } pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); - if (!pdrvdata.debugfs_dir) - pr_warn("Error creating debugfs dir for virtio-ports\n"); INIT_LIST_HEAD(&pdrvdata.consoles); INIT_LIST_HEAD(&pdrvdata.portdevs); diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a588d56502d40a07ae65654752161fbf58dc33ab..1d1891b9cad20a078c674ff635d0382837cbdecd 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -394,6 +394,7 @@ source "drivers/clk/renesas/Kconfig" source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" source "drivers/clk/sifive/Kconfig" +source "drivers/clk/socfpga/Kconfig" source "drivers/clk/sprd/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index b22ae4f81e0b33c375e1c28f9caa8247b662512a..9b582b3fca34f2683048cb0fe6cae4ef0148dcd3 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -104,9 +104,7 @@ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ obj-$(CONFIG_CLK_SIFIVE) += sifive/ -obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ -obj-$(CONFIG_ARCH_AGILEX) += socfpga/ -obj-$(CONFIG_ARCH_STRATIX10) += socfpga/ +obj-y += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_ARCH_STI) += st/ diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index f89b9cfc43099992b920940bb633ca2fb270fe3c..dd3b71eafabf3031a1de61ab4902fc44863c6c42 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -314,7 +314,7 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) return -ENOENT; } - firmware = rpi_firmware_get(firmware_node); + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); of_node_put(firmware_node); if (!firmware) return -EPROBE_DEFER; diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index c754dfbb73fd42837b3f772e41d599577df05d41..1e357d364ca26d3d0e2c18508b161eae013c21d6 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -2,7 +2,7 @@ /* * System Control and Power Interface (SCMI) Protocol based clock driver * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #include <linux/clk-provider.h> @@ -13,11 +13,13 @@ #include <linux/scmi_protocol.h> #include <asm/div64.h> +static const struct scmi_clk_proto_ops *scmi_proto_clk_ops; + struct scmi_clk { u32 id; struct clk_hw hw; const struct scmi_clock_info *info; - const struct scmi_handle *handle; + const struct scmi_protocol_handle *ph; }; #define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw) @@ -29,7 +31,7 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw, u64 rate; struct scmi_clk *clk = to_scmi_clk(hw); - ret = clk->handle->clk_ops->rate_get(clk->handle, clk->id, &rate); + ret = scmi_proto_clk_ops->rate_get(clk->ph, clk->id, &rate); if (ret) return 0; return rate; @@ -69,21 +71,21 @@ static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, { struct scmi_clk *clk = to_scmi_clk(hw); - return clk->handle->clk_ops->rate_set(clk->handle, clk->id, rate); + return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate); } static int scmi_clk_enable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); - return clk->handle->clk_ops->enable(clk->handle, clk->id); + return scmi_proto_clk_ops->enable(clk->ph, clk->id); } static void scmi_clk_disable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); - clk->handle->clk_ops->disable(clk->handle, clk->id); + scmi_proto_clk_ops->disable(clk->ph, clk->id); } static const struct clk_ops scmi_clk_ops = { @@ -142,11 +144,17 @@ static int scmi_clocks_probe(struct scmi_device *sdev) struct device *dev = &sdev->dev; struct device_node *np = dev->of_node; const struct scmi_handle *handle = sdev->handle; + struct scmi_protocol_handle *ph; - if (!handle || !handle->clk_ops) + if (!handle) return -ENODEV; - count = handle->clk_ops->count_get(handle); + scmi_proto_clk_ops = + handle->devm_protocol_get(sdev, SCMI_PROTOCOL_CLOCK, &ph); + if (IS_ERR(scmi_proto_clk_ops)) + return PTR_ERR(scmi_proto_clk_ops); + + count = scmi_proto_clk_ops->count_get(ph); if (count < 0) { dev_err(dev, "%pOFn: invalid clock output count\n", np); return -EINVAL; @@ -167,14 +175,14 @@ static int scmi_clocks_probe(struct scmi_device *sdev) if (!sclk) return -ENOMEM; - sclk->info = handle->clk_ops->info_get(handle, idx); + sclk->info = scmi_proto_clk_ops->info_get(ph, idx); if (!sclk->info) { dev_dbg(dev, "invalid clock info for idx %d\n", idx); continue; } sclk->id = idx; - sclk->handle = handle; + sclk->ph = ph; err = scmi_clk_ops_init(dev, sclk); if (err) { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ab745e73f52d19c1adf752ee44b0c1f11b62ad15..419b2046fdfbee95af7e3d2fa1d50f39d265d558 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4693,6 +4693,8 @@ int of_clk_add_hw_provider(struct device_node *np, if (ret < 0) of_clk_del_provider(np); + fwnode_dev_initialized(&np->fwnode, true); + return ret; } EXPORT_SYMBOL_GPL(of_clk_add_hw_provider); diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index aaf31abe1c8ff38e8fcb131f7725e2c30095a870..7e1b136e71ae0f6daf048c73a452439b1dcb7725 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -503,8 +503,8 @@ static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider) #else -static int _cmp_sci_clk_list(void *priv, struct list_head *a, - struct list_head *b) +static int _cmp_sci_clk_list(void *priv, const struct list_head *a, + const struct list_head *b) { struct sci_clk *ca = container_of(a, struct sci_clk, node); struct sci_clk *cb = container_of(b, struct sci_clk, node); diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index f5746f9ea929fddef2ddfb234930d67e8ec7914d..32ac6b6b75306258cabcaed8f57fedbafdb6ba23 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -84,6 +84,7 @@ struct clk_pm_cpu { void __iomem *reg_div; u8 shift_div; struct regmap *nb_pm_base; + unsigned long l1_expiration; }; #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) @@ -440,33 +441,6 @@ static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) return val; } -static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); - struct regmap *base = pm_cpu->nb_pm_base; - int load_level; - - /* - * We set the clock parent only if the DVFS is available but - * not enabled. - */ - if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base)) - return -EINVAL; - - /* Set the parent clock for all the load level */ - for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { - unsigned int reg, mask, val, - offset = ARMADA_37XX_NB_TBG_SEL_OFF; - - armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); - - val = index << offset; - mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset; - regmap_update_bits(base, reg, mask, val); - } - return 0; -} - static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -514,8 +488,10 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, } /* - * Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz - * respectively) to L0 frequency (1.2 Ghz) requires a significant + * Workaround when base CPU frequnecy is 1000 or 1200 MHz + * + * Switching the CPU from the L2 or L3 frequencies (250/300 or 200 MHz + * respectively) to L0 frequency (1/1.2 GHz) requires a significant * amount of time to let VDD stabilize to the appropriate * voltage. This amount of time is large enough that it cannot be * covered by the hardware countdown register. Due to this, the CPU @@ -525,26 +501,56 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, * To work around this problem, we prevent switching directly from the * L2/L3 frequencies to the L0 frequency, and instead switch to the L1 * frequency in-between. The sequence therefore becomes: - * 1. First switch from L2/L3(200/300MHz) to L1(600MHZ) + * 1. First switch from L2/L3 (200/250/300 MHz) to L1 (500/600 MHz) * 2. Sleep 20ms for stabling VDD voltage - * 3. Then switch from L1(600MHZ) to L0(1200Mhz). + * 3. Then switch from L1 (500/600 MHz) to L0 (1000/1200 MHz). */ -static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base) +static void clk_pm_cpu_set_rate_wa(struct clk_pm_cpu *pm_cpu, + unsigned int new_level, unsigned long rate, + struct regmap *base) { unsigned int cur_level; - if (rate != 1200 * 1000 * 1000) - return; - regmap_read(base, ARMADA_37XX_NB_CPU_LOAD, &cur_level); cur_level &= ARMADA_37XX_NB_CPU_LOAD_MASK; - if (cur_level <= ARMADA_37XX_DVFS_LOAD_1) + + if (cur_level == new_level) + return; + + /* + * System wants to go to L1 on its own. If we are going from L2/L3, + * remember when 20ms will expire. If from L0, set the value so that + * next switch to L0 won't have to wait. + */ + if (new_level == ARMADA_37XX_DVFS_LOAD_1) { + if (cur_level == ARMADA_37XX_DVFS_LOAD_0) + pm_cpu->l1_expiration = jiffies; + else + pm_cpu->l1_expiration = jiffies + msecs_to_jiffies(20); return; + } + + /* + * If we are setting to L2/L3, just invalidate L1 expiration time, + * sleeping is not needed. + */ + if (rate < 1000*1000*1000) + goto invalidate_l1_exp; + + /* + * We are going to L0 with rate >= 1GHz. Check whether we have been at + * L1 for long enough time. If not, go to L1 for 20ms. + */ + if (pm_cpu->l1_expiration && jiffies >= pm_cpu->l1_expiration) + goto invalidate_l1_exp; regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD, ARMADA_37XX_NB_CPU_LOAD_MASK, ARMADA_37XX_DVFS_LOAD_1); msleep(20); + +invalidate_l1_exp: + pm_cpu->l1_expiration = 0; } static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, @@ -578,7 +584,9 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, reg = ARMADA_37XX_NB_CPU_LOAD; mask = ARMADA_37XX_NB_CPU_LOAD_MASK; - clk_pm_cpu_set_rate_wa(rate, base); + /* Apply workaround when base CPU frequency is 1000 or 1200 MHz */ + if (parent_rate >= 1000*1000*1000) + clk_pm_cpu_set_rate_wa(pm_cpu, load_level, rate, base); regmap_update_bits(base, reg, mask, load_level); @@ -592,7 +600,6 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops clk_pm_cpu_ops = { .get_parent = clk_pm_cpu_get_parent, - .set_parent = clk_pm_cpu_set_parent, .round_rate = clk_pm_cpu_round_rate, .set_rate = clk_pm_cpu_set_rate, .recalc_rate = clk_pm_cpu_recalc_rate, diff --git a/drivers/clk/socfpga/Kconfig b/drivers/clk/socfpga/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..0cf16b894efb3a210cb0431c2ac89da22476281d --- /dev/null +++ b/drivers/clk/socfpga/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 +config CLK_INTEL_SOCFPGA + bool "Intel SoCFPGA family clock support" if COMPILE_TEST && !ARCH_INTEL_SOCFPGA + default ARCH_INTEL_SOCFPGA + help + Support for the clock controllers present on Intel SoCFPGA and eASIC + devices like Aria, Cyclone, Stratix 10, Agilex and N5X eASIC. + +if CLK_INTEL_SOCFPGA + +config CLK_INTEL_SOCFPGA32 + bool "Intel Aria / Cyclone clock controller support" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA) + default ARM && ARCH_INTEL_SOCFPGA + +config CLK_INTEL_SOCFPGA64 + bool "Intel Stratix / Agilex / N5X clock controller support" if COMPILE_TEST && (!ARM64 || !ARCH_INTEL_SOCFPGA) + default ARM64 && ARCH_INTEL_SOCFPGA + +endif # CLK_INTEL_SOCFPGA diff --git a/drivers/clk/socfpga/Makefile b/drivers/clk/socfpga/Makefile index bf736f8d201abf2bc65904567fdd738bbb6aafda..e8dfce339c915e4ddf5e31205bc813378649d8c6 100644 --- a/drivers/clk/socfpga/Makefile +++ b/drivers/clk/socfpga/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_ARCH_SOCFPGA) += clk.o clk-gate.o clk-pll.o clk-periph.o -obj-$(CONFIG_ARCH_SOCFPGA) += clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o -obj-$(CONFIG_ARCH_STRATIX10) += clk-s10.o -obj-$(CONFIG_ARCH_STRATIX10) += clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o -obj-$(CONFIG_ARCH_AGILEX) += clk-agilex.o -obj-$(CONFIG_ARCH_AGILEX) += clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o +obj-$(CONFIG_CLK_INTEL_SOCFPGA32) += clk.o clk-gate.o clk-pll.o clk-periph.o \ + clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o +obj-$(CONFIG_CLK_INTEL_SOCFPGA64) += clk-s10.o \ + clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o \ + clk-agilex.o diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index c5cc0a2dac6ff880de18824553701c9d06c5ee5e..0193cebe8c5a3e21abe35032ace7314e10e7b103 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -2515,18 +2515,6 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw) pll_writel(val, PLLE_SS_CTRL, pll); udelay(1); - val = pll_readl_misc(pll); - val &= ~PLLE_MISC_IDDQ_SW_CTRL; - pll_writel_misc(val, pll); - - val = pll_readl(pll->params->aux_reg, pll); - val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE); - val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL); - pll_writel(val, pll->params->aux_reg, pll); - udelay(1); - val |= PLLE_AUX_SEQ_ENABLE; - pll_writel(val, pll->params->aux_reg, pll); - out: if (pll->lock) spin_unlock_irqrestore(pll->lock, flags); diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 68cbb98af567dd53e0429dbbbe91198d7f74c291..b9099012dc7b1d3d24accd2d1a65881fb2938103 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2020 NVIDIA CORPORATION. All rights reserved. */ #include <linux/io.h> @@ -403,6 +403,14 @@ static unsigned long tegra210_input_freq[] = { #define PLLRE_BASE_DEFAULT_MASK 0x1c000000 #define PLLRE_MISC0_WRITE_MASK 0x67ffffff +/* PLLE */ +#define PLLE_MISC_IDDQ_SW_CTRL (1 << 14) +#define PLLE_AUX_USE_LOCKDET (1 << 3) +#define PLLE_AUX_SS_SEQ_INCLUDE (1 << 31) +#define PLLE_AUX_ENABLE_SWCTL (1 << 4) +#define PLLE_AUX_SS_SWCTL (1 << 6) +#define PLLE_AUX_SEQ_ENABLE (1 << 24) + /* PLLX */ #define PLLX_USE_DYN_RAMP 1 #define PLLX_BASE_LOCK (1 << 27) @@ -489,6 +497,49 @@ static unsigned long tegra210_input_freq[] = { #define PLLU_MISC0_WRITE_MASK 0xbfffffff #define PLLU_MISC1_WRITE_MASK 0x00000007 +bool tegra210_plle_hw_sequence_is_enabled(void) +{ + u32 value; + + value = readl_relaxed(clk_base + PLLE_AUX); + if (value & PLLE_AUX_SEQ_ENABLE) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_is_enabled); + +int tegra210_plle_hw_sequence_start(void) +{ + u32 value; + + if (tegra210_plle_hw_sequence_is_enabled()) + return 0; + + /* skip if PLLE is not enabled yet */ + value = readl_relaxed(clk_base + PLLE_MISC0); + if (!(value & PLLE_MISC_LOCK)) + return -EIO; + + value &= ~PLLE_MISC_IDDQ_SW_CTRL; + writel_relaxed(value, clk_base + PLLE_MISC0); + + value = readl_relaxed(clk_base + PLLE_AUX); + value |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE); + value &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL); + writel_relaxed(value, clk_base + PLLE_AUX); + + fence_udelay(1, clk_base); + + value |= PLLE_AUX_SEQ_ENABLE; + writel_relaxed(value, clk_base + PLLE_AUX); + + fence_udelay(1, clk_base); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_start); + void tegra210_xusb_pll_hw_control_enable(void) { u32 val; diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index f0542391ca4bd3ca3ecca43f2dd968033db76827..90e0a9ea635155604ad2ba4090718d006aa3ccc7 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -156,6 +156,8 @@ static const struct omap_clkctrl_reg_data omap5_l3main1_clkctrl_regs[] __initcon static const struct omap_clkctrl_reg_data omap5_l3main2_clkctrl_regs[] __initconst = { { OMAP5_L3_MAIN_2_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { OMAP5_L3_MAIN_2_GPMC_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { OMAP5_L3_MAIN_2_OCMC_RAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, { 0 }, }; diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d0177824c518b88daa749d2f8d3d4b9ac183b8d0..4fb1f4da27ec0997bd3cdfc3474c696952aec819 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -51,7 +51,7 @@ static unsigned arch_timers_present __initdata; -static void __iomem *arch_counter_base; +static void __iomem *arch_counter_base __ro_after_init; struct arch_timer { void __iomem *base; @@ -60,15 +60,24 @@ struct arch_timer { #define to_arch_timer(e) container_of(e, struct arch_timer, evt) -static u32 arch_timer_rate; -static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI]; +static u32 arch_timer_rate __ro_after_init; +u32 arch_timer_rate1 __ro_after_init; +static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init; + +static const char *arch_timer_ppi_names[ARCH_TIMER_MAX_TIMER_PPI] = { + [ARCH_TIMER_PHYS_SECURE_PPI] = "sec-phys", + [ARCH_TIMER_PHYS_NONSECURE_PPI] = "phys", + [ARCH_TIMER_VIRT_PPI] = "virt", + [ARCH_TIMER_HYP_PPI] = "hyp-phys", + [ARCH_TIMER_HYP_VIRT_PPI] = "hyp-virt", +}; static struct clock_event_device __percpu *arch_timer_evt; -static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI; -static bool arch_timer_c3stop; -static bool arch_timer_mem_use_virtual; -static bool arch_counter_suspend_stop; +static enum arch_timer_ppi_nr arch_timer_uses_ppi __ro_after_init = ARCH_TIMER_VIRT_PPI; +static bool arch_timer_c3stop __ro_after_init; +static bool arch_timer_mem_use_virtual __ro_after_init; +static bool arch_counter_suspend_stop __ro_after_init; #ifdef CONFIG_GENERIC_GETTIMEOFDAY static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER; #else @@ -76,7 +85,7 @@ static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_NONE; #endif /* CONFIG_GENERIC_GETTIMEOFDAY */ static cpumask_t evtstrm_available = CPU_MASK_NONE; -static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); +static bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); static int __init early_evtstrm_cfg(char *buf) { @@ -176,7 +185,7 @@ static notrace u64 arch_counter_get_cntvct(void) * to exist on arm64. arm doesn't use this before DT is probed so even * if we don't have the cp15 accessors we won't have a problem. */ -u64 (*arch_timer_read_counter)(void) = arch_counter_get_cntvct; +u64 (*arch_timer_read_counter)(void) __ro_after_init = arch_counter_get_cntvct; EXPORT_SYMBOL_GPL(arch_timer_read_counter); static u64 arch_counter_read(struct clocksource *cs) @@ -925,7 +934,7 @@ static int validate_timer_rate(void) * rate was probed first, and don't verify that others match. If the first node * probed has a clock-frequency property, this overrides the HW register. */ -static void arch_timer_of_configure_rate(u32 rate, struct device_node *np) +static void __init arch_timer_of_configure_rate(u32 rate, struct device_node *np) { /* Who has more than one independent system counter? */ if (arch_timer_rate) @@ -939,7 +948,7 @@ static void arch_timer_of_configure_rate(u32 rate, struct device_node *np) pr_warn("frequency not available\n"); } -static void arch_timer_banner(unsigned type) +static void __init arch_timer_banner(unsigned type) { pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n", type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "", @@ -1280,8 +1289,9 @@ static void __init arch_timer_populate_kvm_info(void) static int __init arch_timer_of_init(struct device_node *np) { - int i, ret; + int i, irq, ret; u32 rate; + bool has_names; if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("multiple nodes in dt, skipping\n"); @@ -1289,8 +1299,17 @@ static int __init arch_timer_of_init(struct device_node *np) } arch_timers_present |= ARCH_TIMER_TYPE_CP15; - for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++) - arch_timer_ppi[i] = irq_of_parse_and_map(np, i); + + has_names = of_property_read_bool(np, "interrupt-names"); + + for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++) { + if (has_names) + irq = of_irq_get_byname(np, arch_timer_ppi_names[i]); + else + irq = of_irq_get(np, i); + if (irq > 0) + arch_timer_ppi[i] = irq; + } arch_timer_populate_kvm_info(); diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index 996900d017c61e41bbe734f5124e44d9e99f46c8..2fc93e46cea38e2c0d0fe2d69e0ae109bd8a979d 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -18,7 +18,7 @@ #define RATE_32K 32768 -#define TIMER_MODE_CONTINOUS 0x1 +#define TIMER_MODE_CONTINUOUS 0x1 #define TIMER_DOWNCOUNT_VAL 0xffffffff #define PRCMU_TIMER_REF 0 @@ -55,13 +55,13 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node) /* * The A9 sub system expects the timer to be configured as - * a continous looping timer. + * a continuous looping timer. * The PRCMU should configure it but if it for some reason * don't we do it here. */ if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) != - TIMER_MODE_CONTINOUS) { - writel(TIMER_MODE_CONTINOUS, + TIMER_MODE_CONTINUOUS) { + writel(TIMER_MODE_CONTINUOUS, clksrc_dbx500_timer_base + PRCMU_TIMER_MODE); writel(TIMER_DOWNCOUNT_VAL, clksrc_dbx500_timer_base + PRCMU_TIMER_REF); diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 42e7e43b8fcd9e82c7f740c934b9a1edd69e8d64..3819ef5b709894621d4f18c7ecd7145595d4d46b 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -38,7 +38,7 @@ static int __init timer_get_base_and_rate(struct device_node *np, } /* - * Not all implementations use a periphal clock, so don't panic + * Not all implementations use a peripheral clock, so don't panic * if it's not present */ pclk = of_clk_get_by_name(np, "pclk"); @@ -52,18 +52,34 @@ static int __init timer_get_base_and_rate(struct device_node *np, return 0; timer_clk = of_clk_get_by_name(np, "timer"); - if (IS_ERR(timer_clk)) - return PTR_ERR(timer_clk); + if (IS_ERR(timer_clk)) { + ret = PTR_ERR(timer_clk); + goto out_pclk_disable; + } ret = clk_prepare_enable(timer_clk); if (ret) - return ret; + goto out_timer_clk_put; *rate = clk_get_rate(timer_clk); - if (!(*rate)) - return -EINVAL; + if (!(*rate)) { + ret = -EINVAL; + goto out_timer_clk_disable; + } return 0; + +out_timer_clk_disable: + clk_disable_unprepare(timer_clk); +out_timer_clk_put: + clk_put(timer_clk); +out_pclk_disable: + if (!IS_ERR(pclk)) { + clk_disable_unprepare(pclk); + clk_put(pclk); + } + iounmap(*base); + return ret; } static int __init add_clockevent(struct device_node *event_timer) diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 269a691bd2c4502485261a59baa7a73a718692bb..977fd05ac35f62e1db380a8f289f475b52109355 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -18,6 +18,9 @@ #include <linux/sched_clock.h> #include <linux/mm.h> #include <linux/cpuhotplug.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/acpi.h> #include <clocksource/hyperv_timer.h> #include <asm/hyperv-tlfs.h> #include <asm/mshyperv.h> @@ -43,14 +46,13 @@ static u64 hv_sched_clock_offset __ro_after_init; */ static bool direct_mode_enabled; -static int stimer0_irq; -static int stimer0_vector; +static int stimer0_irq = -1; static int stimer0_message_sint; +static DEFINE_PER_CPU(long, stimer0_evt); /* - * ISR for when stimer0 is operating in Direct Mode. Direct Mode - * does not use VMbus or any VMbus messages, so process here and not - * in the VMbus driver code. + * Common code for stimer0 interrupts coming via Direct Mode or + * as a VMbus message. */ void hv_stimer0_isr(void) { @@ -61,6 +63,16 @@ void hv_stimer0_isr(void) } EXPORT_SYMBOL_GPL(hv_stimer0_isr); +/* + * stimer0 interrupt handler for architectures that support + * per-cpu interrupts, which also implies Direct Mode. + */ +static irqreturn_t hv_stimer0_percpu_isr(int irq, void *dev_id) +{ + hv_stimer0_isr(); + return IRQ_HANDLED; +} + static int hv_ce_set_next_event(unsigned long delta, struct clock_event_device *evt) { @@ -68,16 +80,16 @@ static int hv_ce_set_next_event(unsigned long delta, current_tick = hv_read_reference_counter(); current_tick += delta; - hv_init_timer(0, current_tick); + hv_set_register(HV_REGISTER_STIMER0_COUNT, current_tick); return 0; } static int hv_ce_shutdown(struct clock_event_device *evt) { - hv_init_timer(0, 0); - hv_init_timer_config(0, 0); - if (direct_mode_enabled) - hv_disable_stimer0_percpu_irq(stimer0_irq); + hv_set_register(HV_REGISTER_STIMER0_COUNT, 0); + hv_set_register(HV_REGISTER_STIMER0_CONFIG, 0); + if (direct_mode_enabled && stimer0_irq >= 0) + disable_percpu_irq(stimer0_irq); return 0; } @@ -95,8 +107,9 @@ static int hv_ce_set_oneshot(struct clock_event_device *evt) * on the specified hardware vector/IRQ. */ timer_cfg.direct_mode = 1; - timer_cfg.apic_vector = stimer0_vector; - hv_enable_stimer0_percpu_irq(stimer0_irq); + timer_cfg.apic_vector = HYPERV_STIMER0_VECTOR; + if (stimer0_irq >= 0) + enable_percpu_irq(stimer0_irq, IRQ_TYPE_NONE); } else { /* * When it expires, the timer will generate a VMbus message, @@ -105,7 +118,7 @@ static int hv_ce_set_oneshot(struct clock_event_device *evt) timer_cfg.direct_mode = 0; timer_cfg.sintx = stimer0_message_sint; } - hv_init_timer_config(0, timer_cfg.as_uint64); + hv_set_register(HV_REGISTER_STIMER0_CONFIG, timer_cfg.as_uint64); return 0; } @@ -169,10 +182,58 @@ int hv_stimer_cleanup(unsigned int cpu) } EXPORT_SYMBOL_GPL(hv_stimer_cleanup); +/* + * These placeholders are overridden by arch specific code on + * architectures that need special setup of the stimer0 IRQ because + * they don't support per-cpu IRQs (such as x86/x64). + */ +void __weak hv_setup_stimer0_handler(void (*handler)(void)) +{ +}; + +void __weak hv_remove_stimer0_handler(void) +{ +}; + +/* Called only on architectures with per-cpu IRQs (i.e., not x86/x64) */ +static int hv_setup_stimer0_irq(void) +{ + int ret; + + ret = acpi_register_gsi(NULL, HYPERV_STIMER0_VECTOR, + ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH); + if (ret < 0) { + pr_err("Can't register Hyper-V stimer0 GSI. Error %d", ret); + return ret; + } + stimer0_irq = ret; + + ret = request_percpu_irq(stimer0_irq, hv_stimer0_percpu_isr, + "Hyper-V stimer0", &stimer0_evt); + if (ret) { + pr_err("Can't request Hyper-V stimer0 IRQ %d. Error %d", + stimer0_irq, ret); + acpi_unregister_gsi(stimer0_irq); + stimer0_irq = -1; + } + return ret; +} + +static void hv_remove_stimer0_irq(void) +{ + if (stimer0_irq == -1) { + hv_remove_stimer0_handler(); + } else { + free_percpu_irq(stimer0_irq, &stimer0_evt); + acpi_unregister_gsi(stimer0_irq); + stimer0_irq = -1; + } +} + /* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */ -int hv_stimer_alloc(void) +int hv_stimer_alloc(bool have_percpu_irqs) { - int ret = 0; + int ret; /* * Synthetic timers are always available except on old versions of @@ -188,29 +249,37 @@ int hv_stimer_alloc(void) direct_mode_enabled = ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE; - if (direct_mode_enabled) { - ret = hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector, - hv_stimer0_isr); + + /* + * If Direct Mode isn't enabled, the remainder of the initialization + * is done later by hv_stimer_legacy_init() + */ + if (!direct_mode_enabled) + return 0; + + if (have_percpu_irqs) { + ret = hv_setup_stimer0_irq(); if (ret) - goto free_percpu; + goto free_clock_event; + } else { + hv_setup_stimer0_handler(hv_stimer0_isr); + } - /* - * Since we are in Direct Mode, stimer initialization - * can be done now with a CPUHP value in the same range - * as other clockevent devices. - */ - ret = cpuhp_setup_state(CPUHP_AP_HYPERV_TIMER_STARTING, - "clockevents/hyperv/stimer:starting", - hv_stimer_init, hv_stimer_cleanup); - if (ret < 0) - goto free_stimer0_irq; + /* + * Since we are in Direct Mode, stimer initialization + * can be done now with a CPUHP value in the same range + * as other clockevent devices. + */ + ret = cpuhp_setup_state(CPUHP_AP_HYPERV_TIMER_STARTING, + "clockevents/hyperv/stimer:starting", + hv_stimer_init, hv_stimer_cleanup); + if (ret < 0) { + hv_remove_stimer0_irq(); + goto free_clock_event; } return ret; -free_stimer0_irq: - hv_remove_stimer0_irq(stimer0_irq); - stimer0_irq = 0; -free_percpu: +free_clock_event: free_percpu(hv_clock_event); hv_clock_event = NULL; return ret; @@ -254,23 +323,6 @@ void hv_stimer_legacy_cleanup(unsigned int cpu) } EXPORT_SYMBOL_GPL(hv_stimer_legacy_cleanup); - -/* hv_stimer_free - Free global resources allocated by hv_stimer_alloc() */ -void hv_stimer_free(void) -{ - if (!hv_clock_event) - return; - - if (direct_mode_enabled) { - cpuhp_remove_state(CPUHP_AP_HYPERV_TIMER_STARTING); - hv_remove_stimer0_irq(stimer0_irq); - stimer0_irq = 0; - } - free_percpu(hv_clock_event); - hv_clock_event = NULL; -} -EXPORT_SYMBOL_GPL(hv_stimer_free); - /* * Do a global cleanup of clockevents for the cases of kexec and * vmbus exit @@ -287,12 +339,17 @@ void hv_stimer_global_cleanup(void) hv_stimer_legacy_cleanup(cpu); } - /* - * If Direct Mode is enabled, the cpuhp teardown callback - * (hv_stimer_cleanup) will be run on all CPUs to stop the - * stimers. - */ - hv_stimer_free(); + if (!hv_clock_event) + return; + + if (direct_mode_enabled) { + cpuhp_remove_state(CPUHP_AP_HYPERV_TIMER_STARTING); + hv_remove_stimer0_irq(); + stimer0_irq = -1; + } + free_percpu(hv_clock_event); + hv_clock_event = NULL; + } EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); @@ -302,14 +359,6 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); * the other that uses the TSC reference page feature as defined in the * TLFS. The MSR version is for compatibility with old versions of * Hyper-V and 32-bit x86. The TSC reference page version is preferred. - * - * The Hyper-V clocksource ratings of 250 are chosen to be below the - * TSC clocksource rating of 300. In configurations where Hyper-V offers - * an InvariantTSC, the TSC is not marked "unstable", so the TSC clocksource - * is available and preferred. With the higher rating, it will be the - * default. On older hardware and Hyper-V versions, the TSC is marked - * "unstable", so no TSC clocksource is created and the selected Hyper-V - * clocksource will be the default. */ u64 (*hv_read_reference_counter)(void); @@ -331,7 +380,7 @@ static u64 notrace read_hv_clock_tsc(void) u64 current_tick = hv_read_tsc_page(hv_get_tsc_page()); if (current_tick == U64_MAX) - hv_get_time_ref_count(current_tick); + current_tick = hv_get_register(HV_REGISTER_TIME_REF_COUNT); return current_tick; } @@ -352,9 +401,9 @@ static void suspend_hv_clock_tsc(struct clocksource *arg) u64 tsc_msr; /* Disable the TSC page */ - hv_get_reference_tsc(tsc_msr); + tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC); tsc_msr &= ~BIT_ULL(0); - hv_set_reference_tsc(tsc_msr); + hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr); } @@ -364,39 +413,44 @@ static void resume_hv_clock_tsc(struct clocksource *arg) u64 tsc_msr; /* Re-enable the TSC page */ - hv_get_reference_tsc(tsc_msr); + tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC); tsc_msr &= GENMASK_ULL(11, 0); tsc_msr |= BIT_ULL(0) | (u64)phys_addr; - hv_set_reference_tsc(tsc_msr); + hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr); } +#ifdef VDSO_CLOCKMODE_HVCLOCK static int hv_cs_enable(struct clocksource *cs) { - hv_enable_vdso_clocksource(); + vclocks_set_used(VDSO_CLOCKMODE_HVCLOCK); return 0; } +#endif static struct clocksource hyperv_cs_tsc = { .name = "hyperv_clocksource_tsc_page", - .rating = 250, + .rating = 500, .read = read_hv_clock_tsc_cs, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, .suspend= suspend_hv_clock_tsc, .resume = resume_hv_clock_tsc, +#ifdef VDSO_CLOCKMODE_HVCLOCK .enable = hv_cs_enable, + .vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK, +#else + .vdso_clock_mode = VDSO_CLOCKMODE_NONE, +#endif }; static u64 notrace read_hv_clock_msr(void) { - u64 current_tick; /* * Read the partition counter to get the current tick count. This count * is set to 0 when the partition is created and is incremented in * 100 nanosecond units. */ - hv_get_time_ref_count(current_tick); - return current_tick; + return hv_get_register(HV_REGISTER_TIME_REF_COUNT); } static u64 notrace read_hv_clock_msr_cs(struct clocksource *arg) @@ -412,12 +466,36 @@ static u64 notrace read_hv_sched_clock_msr(void) static struct clocksource hyperv_cs_msr = { .name = "hyperv_clocksource_msr", - .rating = 250, + .rating = 500, .read = read_hv_clock_msr_cs, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +/* + * Reference to pv_ops must be inline so objtool + * detection of noinstr violations can work correctly. + */ +#ifdef CONFIG_GENERIC_SCHED_CLOCK +static __always_inline void hv_setup_sched_clock(void *sched_clock) +{ + /* + * We're on an architecture with generic sched clock (not x86/x64). + * The Hyper-V sched clock read function returns nanoseconds, not + * the normal 100ns units of the Hyper-V synthetic clock. + */ + sched_clock_register(sched_clock, 64, NSEC_PER_SEC); +} +#elif defined CONFIG_PARAVIRT +static __always_inline void hv_setup_sched_clock(void *sched_clock) +{ + /* We're on x86/x64 *and* using PV ops */ + paravirt_set_sched_clock(sched_clock); +} +#else /* !CONFIG_GENERIC_SCHED_CLOCK && !CONFIG_PARAVIRT */ +static __always_inline void hv_setup_sched_clock(void *sched_clock) {} +#endif /* CONFIG_GENERIC_SCHED_CLOCK */ + static bool __init hv_init_tsc_clocksource(void) { u64 tsc_msr; @@ -429,6 +507,22 @@ static bool __init hv_init_tsc_clocksource(void) if (hv_root_partition) return false; + /* + * If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly + * handles frequency and offset changes due to live migration, + * pause/resume, and other VM management operations. So lower the + * Hyper-V Reference TSC rating, causing the generic TSC to be used. + * TSC_INVARIANT is not offered on ARM64, so the Hyper-V Reference + * TSC will be preferred over the virtualized ARM64 arch counter. + * While the Hyper-V MSR clocksource won't be used since the + * Reference TSC clocksource is present, change its rating as + * well for consistency. + */ + if (ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) { + hyperv_cs_tsc.rating = 250; + hyperv_cs_msr.rating = 250; + } + hv_read_reference_counter = read_hv_clock_tsc; phys_addr = virt_to_phys(hv_get_tsc_page()); @@ -439,12 +533,11 @@ static bool __init hv_init_tsc_clocksource(void) * (which already has at least the low 12 bits set to zero since * it is page aligned). Also set the "enable" bit, which is bit 0. */ - hv_get_reference_tsc(tsc_msr); + tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC); tsc_msr &= GENMASK_ULL(11, 0); tsc_msr = tsc_msr | 0x1 | (u64)phys_addr; - hv_set_reference_tsc(tsc_msr); + hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr); - hv_set_clocksource_vdso(hyperv_cs_tsc); clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); hv_sched_clock_offset = hv_read_reference_counter(); @@ -457,7 +550,7 @@ void __init hv_init_clocksource(void) { /* * Try to set up the TSC page clocksource. If it succeeds, we're - * done. Otherwise, set up the MSR clocksoruce. At least one of + * done. Otherwise, set up the MSR clocksource. At least one of * these will always be available except on very old versions of * Hyper-V on x86. In that case we won't have a Hyper-V * clocksource, but Linux will still run with a clocksource based diff --git a/drivers/clocksource/ingenic-ost.c b/drivers/clocksource/ingenic-ost.c index 029efc2731b49f35b89f3b3c07011a2152f8d40b..06d25754e606cb7cc9f2efbb8c0e673cebd34e76 100644 --- a/drivers/clocksource/ingenic-ost.c +++ b/drivers/clocksource/ingenic-ost.c @@ -88,9 +88,9 @@ static int __init ingenic_ost_probe(struct platform_device *pdev) return PTR_ERR(ost->regs); map = device_node_to_regmap(dev->parent->of_node); - if (!map) { + if (IS_ERR(map)) { dev_err(dev, "regmap not found"); - return -EINVAL; + return PTR_ERR(map); } ost->clk = devm_clk_get(dev, "ost"); @@ -167,13 +167,14 @@ static const struct ingenic_ost_soc_info jz4725b_ost_soc_info = { .is64bit = false, }; -static const struct ingenic_ost_soc_info jz4770_ost_soc_info = { +static const struct ingenic_ost_soc_info jz4760b_ost_soc_info = { .is64bit = true, }; static const struct of_device_id ingenic_ost_of_match[] = { { .compatible = "ingenic,jz4725b-ost", .data = &jz4725b_ost_soc_info, }, - { .compatible = "ingenic,jz4770-ost", .data = &jz4770_ost_soc_info, }, + { .compatible = "ingenic,jz4760b-ost", .data = &jz4760b_ost_soc_info, }, + { .compatible = "ingenic,jz4770-ost", .data = &jz4760b_ost_soc_info, }, { } }; diff --git a/drivers/clocksource/ingenic-timer.c b/drivers/clocksource/ingenic-timer.c index 905fd6b163a8190bf2bad79a7e33c6620c0a312a..24ed0f1f089b8dca48e684a7caf888fb8c920b3d 100644 --- a/drivers/clocksource/ingenic-timer.c +++ b/drivers/clocksource/ingenic-timer.c @@ -264,6 +264,7 @@ static const struct ingenic_soc_info jz4725b_soc_info = { static const struct of_device_id ingenic_tcu_of_match[] = { { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, }, { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, }, + { .compatible = "ingenic,jz4760-tcu", .data = &jz4740_soc_info, }, { .compatible = "ingenic,jz4770-tcu", .data = &jz4740_soc_info, }, { .compatible = "ingenic,x1000-tcu", .data = &jz4740_soc_info, }, { /* sentinel */ } @@ -358,6 +359,7 @@ err_free_ingenic_tcu: TIMER_OF_DECLARE(jz4740_tcu_intc, "ingenic,jz4740-tcu", ingenic_tcu_init); TIMER_OF_DECLARE(jz4725b_tcu_intc, "ingenic,jz4725b-tcu", ingenic_tcu_init); +TIMER_OF_DECLARE(jz4760_tcu_intc, "ingenic,jz4760-tcu", ingenic_tcu_init); TIMER_OF_DECLARE(jz4770_tcu_intc, "ingenic,jz4770-tcu", ingenic_tcu_init); TIMER_OF_DECLARE(x1000_tcu_intc, "ingenic,x1000-tcu", ingenic_tcu_init); diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index c98f8851fd6804540bfb8e40d96703df7c736407..d7ed99f0001f890d85a7d8ea95575f284cf0d90d 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -339,8 +339,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch) sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE | SH_CMT16_CMCSR_CKS512); } else { - sh_cmt_write_cmcsr(ch, SH_CMT32_CMCSR_CMM | - SH_CMT32_CMCSR_CMTOUT_IE | + u32 cmtout = ch->cmt->info->model <= SH_CMT_48BIT ? + SH_CMT32_CMCSR_CMTOUT_IE : 0; + sh_cmt_write_cmcsr(ch, cmtout | SH_CMT32_CMCSR_CMM | SH_CMT32_CMCSR_CMR_IRQ | SH_CMT32_CMCSR_CKS_RCLK8); } diff --git a/drivers/clocksource/timer-atmel-tcb.c b/drivers/clocksource/timer-atmel-tcb.c index 787dbebbb4324469dbdabc4e588a7b4c53672b1e..27af17c995900477fd3c0037bff9476364c5ecf0 100644 --- a/drivers/clocksource/timer-atmel-tcb.c +++ b/drivers/clocksource/timer-atmel-tcb.c @@ -455,9 +455,9 @@ static int __init tcb_clksrc_init(struct device_node *node) tcaddr = tc.regs; if (bits == 32) { - /* use apropriate function to read 32 bit counter */ + /* use appropriate function to read 32 bit counter */ clksrc.read = tc_get_cycles32; - /* setup ony channel 0 */ + /* setup only channel 0 */ tcb_setup_single_chan(&tc, best_divisor_idx); tc_sched_clock = tc_sched_clock_read32; tc_delay_timer.read_current_timer = tc_delay_timer_read32; diff --git a/drivers/clocksource/timer-fsl-ftm.c b/drivers/clocksource/timer-fsl-ftm.c index 12a2ed7cfaff9eeb2d32ed2be641322f1b17be72..93f336ec875a221544d5fc31a54e4bd7e499764a 100644 --- a/drivers/clocksource/timer-fsl-ftm.c +++ b/drivers/clocksource/timer-fsl-ftm.c @@ -116,7 +116,7 @@ static int ftm_set_next_event(unsigned long delta, * to the MOD register latches the value into a buffer. The MOD * register is updated with the value of its write buffer with * the following scenario: - * a, the counter source clock is diabled. + * a, the counter source clock is disabled. */ ftm_counter_disable(priv->clkevt_base); diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index ab623b25a47b7682f5ec904e1a31c99feb79281f..cfa4ec7ef396814ccd3ea592c87b675835408a55 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -237,7 +237,7 @@ static void __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate, break; } - /* Use the bigest prescaler if we didn't match one. */ + /* Use the biggest prescaler if we didn't match one. */ if (*pres == MCHP_PIT64B_PRES_MAX) *pres = MCHP_PIT64B_PRES_MAX - 1; } diff --git a/drivers/clocksource/timer-npcm7xx.c b/drivers/clocksource/timer-npcm7xx.c index 9780ffd8010e686697a57eded89aa2d1d02d826c..a00520cbb660a1c8ee2e14e3cee30043390356f4 100644 --- a/drivers/clocksource/timer-npcm7xx.c +++ b/drivers/clocksource/timer-npcm7xx.c @@ -208,5 +208,6 @@ static int __init npcm7xx_timer_init(struct device_node *np) return 0; } +TIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init); TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init); diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index 572da477c6d35c5edc64f16b5d8562cde5311d53..529cc6a51cdb3bf842d30ba693ae20ca9df5ec65 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -211,10 +211,10 @@ out_fail: } /** - * timer_of_cleanup - release timer_of ressources + * timer_of_cleanup - release timer_of resources * @to: timer_of structure * - * Release the ressources that has been used in timer_of_init(). + * Release the resources that has been used in timer_of_init(). * This function should be called in init error cases */ void __init timer_of_cleanup(struct timer_of *to) diff --git a/drivers/clocksource/timer-pistachio.c b/drivers/clocksource/timer-pistachio.c index a2dd85d0c1d75471b4061c95c93d30bdeb1e068a..6f37181a8c6330f65fa34d883eb0810b07e25da7 100644 --- a/drivers/clocksource/timer-pistachio.c +++ b/drivers/clocksource/timer-pistachio.c @@ -71,7 +71,7 @@ static u64 notrace pistachio_clocksource_read_cycles(struct clocksource *cs) { struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); - u32 counter, overflw; + u32 counter, overflow; unsigned long flags; /* @@ -80,7 +80,7 @@ pistachio_clocksource_read_cycles(struct clocksource *cs) */ raw_spin_lock_irqsave(&pcs->lock, flags); - overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); + overflow = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); raw_spin_unlock_irqrestore(&pcs->lock, flags); diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c index 33b3e8aa2cc50c66eaea9906e593a9ce0259268c..b6f97960d8ee020f908dbd260b6c04c188c0b4d8 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -2,6 +2,7 @@ #include <linux/clk.h> #include <linux/clocksource.h> #include <linux/clockchips.h> +#include <linux/cpuhotplug.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -449,13 +450,13 @@ static int dmtimer_set_next_event(unsigned long cycles, struct dmtimer_systimer *t = &clkevt->t; void __iomem *pend = t->base + t->pend; - writel_relaxed(0xffffffff - cycles, t->base + t->counter); while (readl_relaxed(pend) & WP_TCRR) cpu_relax(); + writel_relaxed(0xffffffff - cycles, t->base + t->counter); - writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl); while (readl_relaxed(pend) & WP_TCLR) cpu_relax(); + writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl); return 0; } @@ -490,18 +491,18 @@ static int dmtimer_set_periodic(struct clock_event_device *evt) dmtimer_clockevent_shutdown(evt); /* Looks like we need to first set the load value separately */ - writel_relaxed(clkevt->period, t->base + t->load); while (readl_relaxed(pend) & WP_TLDR) cpu_relax(); + writel_relaxed(clkevt->period, t->base + t->load); - writel_relaxed(clkevt->period, t->base + t->counter); while (readl_relaxed(pend) & WP_TCRR) cpu_relax(); + writel_relaxed(clkevt->period, t->base + t->counter); - writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, - t->base + t->ctrl); while (readl_relaxed(pend) & WP_TCLR) cpu_relax(); + writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, + t->base + t->ctrl); return 0; } @@ -530,17 +531,17 @@ static void omap_clockevent_unidle(struct clock_event_device *evt) writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); } -static int __init dmtimer_clockevent_init(struct device_node *np) +static int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, + struct device_node *np, + unsigned int features, + const struct cpumask *cpumask, + const char *name, + int rating) { - struct dmtimer_clockevent *clkevt; struct clock_event_device *dev; struct dmtimer_systimer *t; int error; - clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); - if (!clkevt) - return -ENOMEM; - t = &clkevt->t; dev = &clkevt->dev; @@ -548,24 +549,23 @@ static int __init dmtimer_clockevent_init(struct device_node *np) * We mostly use cpuidle_coupled with ARM local timers for runtime, * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here. */ - dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - dev->rating = 300; + dev->features = features; + dev->rating = rating; dev->set_next_event = dmtimer_set_next_event; dev->set_state_shutdown = dmtimer_clockevent_shutdown; dev->set_state_periodic = dmtimer_set_periodic; dev->set_state_oneshot = dmtimer_clockevent_shutdown; + dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown; dev->tick_resume = dmtimer_clockevent_shutdown; - dev->cpumask = cpu_possible_mask; + dev->cpumask = cpumask; dev->irq = irq_of_parse_and_map(np, 0); - if (!dev->irq) { - error = -ENXIO; - goto err_out_free; - } + if (!dev->irq) + return -ENXIO; error = dmtimer_systimer_setup(np, &clkevt->t); if (error) - goto err_out_free; + return error; clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ); @@ -577,38 +577,132 @@ static int __init dmtimer_clockevent_init(struct device_node *np) writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl); error = request_irq(dev->irq, dmtimer_clockevent_interrupt, - IRQF_TIMER, "clockevent", clkevt); + IRQF_TIMER, name, clkevt); if (error) goto err_out_unmap; writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); - pr_info("TI gptimer clockevent: %s%lu Hz at %pOF\n", - of_find_property(np, "ti,timer-alwon", NULL) ? + pr_info("TI gptimer %s: %s%lu Hz at %pOF\n", + name, of_find_property(np, "ti,timer-alwon", NULL) ? "always-on " : "", t->rate, np->parent); - clockevents_config_and_register(dev, t->rate, - 3, /* Timer internal resynch latency */ + return 0; + +err_out_unmap: + iounmap(t->base); + + return error; +} + +static int __init dmtimer_clockevent_init(struct device_node *np) +{ + struct dmtimer_clockevent *clkevt; + int error; + + clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); + if (!clkevt) + return -ENOMEM; + + error = dmtimer_clkevt_init_common(clkevt, np, + CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + cpu_possible_mask, "clockevent", + 300); + if (error) + goto err_out_free; + + clockevents_config_and_register(&clkevt->dev, clkevt->t.rate, + 3, /* Timer internal resync latency */ 0xffffffff); if (of_machine_is_compatible("ti,am33xx") || of_machine_is_compatible("ti,am43")) { - dev->suspend = omap_clockevent_idle; - dev->resume = omap_clockevent_unidle; + clkevt->dev.suspend = omap_clockevent_idle; + clkevt->dev.resume = omap_clockevent_unidle; } return 0; -err_out_unmap: - iounmap(t->base); - err_out_free: kfree(clkevt); return error; } +/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */ +static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer); + +static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu) +{ + struct dmtimer_clockevent *clkevt; + int error; + + if (!cpu_possible(cpu)) + return -EINVAL; + + if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") || + !of_property_read_bool(np->parent, "ti,no-idle")) + pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent); + + clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); + + error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT, + cpumask_of(cpu), "percpu-dmtimer", + 500); + if (error) + return error; + + return 0; +} + +/* See TRM for timer internal resynch latency */ +static int omap_dmtimer_starting_cpu(unsigned int cpu) +{ + struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); + struct clock_event_device *dev = &clkevt->dev; + struct dmtimer_systimer *t = &clkevt->t; + + clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX); + irq_force_affinity(dev->irq, cpumask_of(cpu)); + + return 0; +} + +static int __init dmtimer_percpu_timer_startup(void) +{ + struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0); + struct dmtimer_systimer *t = &clkevt->t; + + if (t->sysc) { + cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING, + "clockevents/omap/gptimer:starting", + omap_dmtimer_starting_cpu, NULL); + } + + return 0; +} +subsys_initcall(dmtimer_percpu_timer_startup); + +static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) +{ + struct device_node *arm_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; + } + + if (pa == 0x48034000) /* dra7 dmtimer3 */ + return dmtimer_percpu_timer_init(np, 0); + else if (pa == 0x48036000) /* dra7 dmtimer4 */ + return dmtimer_percpu_timer_init(np, 1); + + return 0; +} + /* Clocksource */ static struct dmtimer_clocksource * to_dmtimer_clocksource(struct clocksource *cs) @@ -742,6 +836,9 @@ static int __init dmtimer_systimer_init(struct device_node *np) if (clockevent == pa) return dmtimer_clockevent_init(np); + if (of_machine_is_compatible("ti,dra7")) + return dmtimer_percpu_quirk_init(np, pa); + return 0; } diff --git a/drivers/clocksource/timer-vf-pit.c b/drivers/clocksource/timer-vf-pit.c index 1a86a4e7e344303fc25d6df100753e984eca8992..911c92146eca6d4db3cd87deeafd1e7df04d8324 100644 --- a/drivers/clocksource/timer-vf-pit.c +++ b/drivers/clocksource/timer-vf-pit.c @@ -136,7 +136,7 @@ static int __init pit_clockevent_init(unsigned long rate, int irq) /* * The value for the LDVAL register trigger is calculated as: * LDVAL trigger = (period / clock period) - 1 - * The pit is a 32-bit down count timer, when the conter value + * The pit is a 32-bit down count timer, when the counter value * reaches 0, it will generate an interrupt, thus the minimal * LDVAL trigger value is 1. And then the min_delta is * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. diff --git a/drivers/staging/comedi/Kconfig b/drivers/comedi/Kconfig similarity index 97% rename from drivers/staging/comedi/Kconfig rename to drivers/comedi/Kconfig index 049b659fa6ad82d012c57913932cbc346377902e..3cb61fa2c5c3b2fb8a994ebaec65d10821508863 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/comedi/Kconfig @@ -1319,4 +1319,37 @@ config COMEDI_NI_TIO config COMEDI_NI_ROUTING tristate +config COMEDI_TESTS + tristate "Comedi unit tests" + help + Enable comedi unit-test modules to be built. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about comedi unit-test modules. + +if COMEDI_TESTS + +config COMEDI_TESTS_EXAMPLE + tristate "Comedi example unit-test module" + help + Enable support for an example unit-test module. This is just a + silly example to be used as a basis for writing other unit-test + modules. + + To compile this as a module, choose M here: the module will be called + comedi_example_test. + +config COMEDI_TESTS_NI_ROUTES + tristate "NI routing unit-test module" + select COMEDI_NI_ROUTING + help + Enable support for a unit-test module to test the signal routing + code used by comedi drivers for various National Instruments cards. + + To compile this as a module, choose M here: the module will be called + ni_routes_test. + +endif # COMEDI_TESTS + endif # COMEDI diff --git a/drivers/staging/comedi/Makefile b/drivers/comedi/Makefile similarity index 100% rename from drivers/staging/comedi/Makefile rename to drivers/comedi/Makefile diff --git a/drivers/staging/comedi/TODO b/drivers/comedi/TODO similarity index 100% rename from drivers/staging/comedi/TODO rename to drivers/comedi/TODO diff --git a/drivers/staging/comedi/comedi.h b/drivers/comedi/comedi.h similarity index 100% rename from drivers/staging/comedi/comedi.h rename to drivers/comedi/comedi.h diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/comedi/comedi_buf.c similarity index 95% rename from drivers/staging/comedi/comedi_buf.c rename to drivers/comedi/comedi_buf.c index 3ef3ddabf139444d8b49259c62d2fd45c19a46e8..06bfc859ab314d3670276b6512eefd01f91178a6 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/comedi/comedi_buf.c @@ -371,35 +371,35 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s, if (!s->munge || (async->cmd.flags & CMDF_RAWDATA)) { async->munge_count += num_bytes; - count = num_bytes; - } else { - /* don't munge partial samples */ - num_bytes -= num_bytes % num_sample_bytes; - while (count < num_bytes) { - int block_size = num_bytes - count; - unsigned int buf_end; + return num_bytes; + } - buf_end = async->prealloc_bufsz - async->munge_ptr; - if (block_size > buf_end) - block_size = buf_end; + /* don't munge partial samples */ + num_bytes -= num_bytes % num_sample_bytes; + while (count < num_bytes) { + int block_size = num_bytes - count; + unsigned int buf_end; - s->munge(s->device, s, - async->prealloc_buf + async->munge_ptr, - block_size, async->munge_chan); + buf_end = async->prealloc_bufsz - async->munge_ptr; + if (block_size > buf_end) + block_size = buf_end; - /* - * ensure data is munged in buffer before the - * async buffer munge_count is incremented - */ - smp_wmb(); - - async->munge_chan += block_size / num_sample_bytes; - async->munge_chan %= async->cmd.chanlist_len; - async->munge_count += block_size; - async->munge_ptr += block_size; - async->munge_ptr %= async->prealloc_bufsz; - count += block_size; - } + s->munge(s->device, s, + async->prealloc_buf + async->munge_ptr, + block_size, async->munge_chan); + + /* + * ensure data is munged in buffer before the + * async buffer munge_count is incremented + */ + smp_wmb(); + + async->munge_chan += block_size / num_sample_bytes; + async->munge_chan %= async->cmd.chanlist_len; + async->munge_count += block_size; + async->munge_ptr += block_size; + async->munge_ptr %= async->prealloc_bufsz; + count += block_size; } return count; diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c similarity index 100% rename from drivers/staging/comedi/comedi_fops.c rename to drivers/comedi/comedi_fops.c diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/comedi/comedi_internal.h similarity index 100% rename from drivers/staging/comedi/comedi_internal.h rename to drivers/comedi/comedi_internal.h diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/comedi/comedi_pci.c similarity index 100% rename from drivers/staging/comedi/comedi_pci.c rename to drivers/comedi/comedi_pci.c diff --git a/drivers/staging/comedi/comedi_pci.h b/drivers/comedi/comedi_pci.h similarity index 100% rename from drivers/staging/comedi/comedi_pci.h rename to drivers/comedi/comedi_pci.h diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/comedi/comedi_pcmcia.c similarity index 100% rename from drivers/staging/comedi/comedi_pcmcia.c rename to drivers/comedi/comedi_pcmcia.c diff --git a/drivers/staging/comedi/comedi_pcmcia.h b/drivers/comedi/comedi_pcmcia.h similarity index 100% rename from drivers/staging/comedi/comedi_pcmcia.h rename to drivers/comedi/comedi_pcmcia.h diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/comedi/comedi_usb.c similarity index 100% rename from drivers/staging/comedi/comedi_usb.c rename to drivers/comedi/comedi_usb.c diff --git a/drivers/staging/comedi/comedi_usb.h b/drivers/comedi/comedi_usb.h similarity index 100% rename from drivers/staging/comedi/comedi_usb.h rename to drivers/comedi/comedi_usb.h diff --git a/drivers/staging/comedi/comedidev.h b/drivers/comedi/comedidev.h similarity index 100% rename from drivers/staging/comedi/comedidev.h rename to drivers/comedi/comedidev.h diff --git a/drivers/staging/comedi/comedilib.h b/drivers/comedi/comedilib.h similarity index 100% rename from drivers/staging/comedi/comedilib.h rename to drivers/comedi/comedilib.h diff --git a/drivers/staging/comedi/drivers.c b/drivers/comedi/drivers.c similarity index 100% rename from drivers/staging/comedi/drivers.c rename to drivers/comedi/drivers.c diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/comedi/drivers/8255.c similarity index 100% rename from drivers/staging/comedi/drivers/8255.c rename to drivers/comedi/drivers/8255.c diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/comedi/drivers/8255.h similarity index 100% rename from drivers/staging/comedi/drivers/8255.h rename to drivers/comedi/drivers/8255.h diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/comedi/drivers/8255_pci.c similarity index 100% rename from drivers/staging/comedi/drivers/8255_pci.c rename to drivers/comedi/drivers/8255_pci.c diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/comedi/drivers/Makefile similarity index 100% rename from drivers/staging/comedi/drivers/Makefile rename to drivers/comedi/drivers/Makefile diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/comedi/drivers/addi_apci_1032.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_1032.c rename to drivers/comedi/drivers/addi_apci_1032.c diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/comedi/drivers/addi_apci_1500.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_1500.c rename to drivers/comedi/drivers/addi_apci_1500.c diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/comedi/drivers/addi_apci_1516.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_1516.c rename to drivers/comedi/drivers/addi_apci_1516.c diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/comedi/drivers/addi_apci_1564.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_1564.c rename to drivers/comedi/drivers/addi_apci_1564.c diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/comedi/drivers/addi_apci_16xx.c similarity index 98% rename from drivers/staging/comedi/drivers/addi_apci_16xx.c rename to drivers/comedi/drivers/addi_apci_16xx.c index 9bbef3b15f3fce465adb55acfc9ab8324990d2cd..c306aa41df97510f8d93525b3feba6eb2ab825a5 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/comedi/drivers/addi_apci_16xx.c @@ -110,7 +110,7 @@ static int apci16xx_auto_attach(struct comedi_device *dev, dev->iobase = pci_resource_start(pcidev, 0); /* - * Work out the nubmer of subdevices needed to support all the + * Work out the number of subdevices needed to support all the * digital i/o channels on the board. Each subdevice supports * up to 32 channels. */ diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/comedi/drivers/addi_apci_2032.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_2032.c rename to drivers/comedi/drivers/addi_apci_2032.c diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/comedi/drivers/addi_apci_2200.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_2200.c rename to drivers/comedi/drivers/addi_apci_2200.c diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/comedi/drivers/addi_apci_3120.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_3120.c rename to drivers/comedi/drivers/addi_apci_3120.c diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/comedi/drivers/addi_apci_3501.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_3501.c rename to drivers/comedi/drivers/addi_apci_3501.c diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/comedi/drivers/addi_apci_3xxx.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_apci_3xxx.c rename to drivers/comedi/drivers/addi_apci_3xxx.c diff --git a/drivers/staging/comedi/drivers/addi_tcw.h b/drivers/comedi/drivers/addi_tcw.h similarity index 100% rename from drivers/staging/comedi/drivers/addi_tcw.h rename to drivers/comedi/drivers/addi_tcw.h diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/comedi/drivers/addi_watchdog.c similarity index 100% rename from drivers/staging/comedi/drivers/addi_watchdog.c rename to drivers/comedi/drivers/addi_watchdog.c diff --git a/drivers/staging/comedi/drivers/addi_watchdog.h b/drivers/comedi/drivers/addi_watchdog.h similarity index 100% rename from drivers/staging/comedi/drivers/addi_watchdog.h rename to drivers/comedi/drivers/addi_watchdog.h diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/comedi/drivers/adl_pci6208.c similarity index 100% rename from drivers/staging/comedi/drivers/adl_pci6208.c rename to drivers/comedi/drivers/adl_pci6208.c diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/comedi/drivers/adl_pci7x3x.c similarity index 100% rename from drivers/staging/comedi/drivers/adl_pci7x3x.c rename to drivers/comedi/drivers/adl_pci7x3x.c diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/comedi/drivers/adl_pci8164.c similarity index 100% rename from drivers/staging/comedi/drivers/adl_pci8164.c rename to drivers/comedi/drivers/adl_pci8164.c diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/comedi/drivers/adl_pci9111.c similarity index 100% rename from drivers/staging/comedi/drivers/adl_pci9111.c rename to drivers/comedi/drivers/adl_pci9111.c diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/comedi/drivers/adl_pci9118.c similarity index 100% rename from drivers/staging/comedi/drivers/adl_pci9118.c rename to drivers/comedi/drivers/adl_pci9118.c diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/comedi/drivers/adq12b.c similarity index 100% rename from drivers/staging/comedi/drivers/adq12b.c rename to drivers/comedi/drivers/adq12b.c diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/comedi/drivers/adv_pci1710.c similarity index 100% rename from drivers/staging/comedi/drivers/adv_pci1710.c rename to drivers/comedi/drivers/adv_pci1710.c diff --git a/drivers/staging/comedi/drivers/adv_pci1720.c b/drivers/comedi/drivers/adv_pci1720.c similarity index 100% rename from drivers/staging/comedi/drivers/adv_pci1720.c rename to drivers/comedi/drivers/adv_pci1720.c diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/comedi/drivers/adv_pci1723.c similarity index 100% rename from drivers/staging/comedi/drivers/adv_pci1723.c rename to drivers/comedi/drivers/adv_pci1723.c diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/comedi/drivers/adv_pci1724.c similarity index 100% rename from drivers/staging/comedi/drivers/adv_pci1724.c rename to drivers/comedi/drivers/adv_pci1724.c diff --git a/drivers/staging/comedi/drivers/adv_pci1760.c b/drivers/comedi/drivers/adv_pci1760.c similarity index 100% rename from drivers/staging/comedi/drivers/adv_pci1760.c rename to drivers/comedi/drivers/adv_pci1760.c diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/comedi/drivers/adv_pci_dio.c similarity index 99% rename from drivers/staging/comedi/drivers/adv_pci_dio.c rename to drivers/comedi/drivers/adv_pci_dio.c index 8e222b6ff2b4c388b79dd5532be8a579f64a8c45..54c7419c8ca61d3883ac675aeb16744099d69060 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/comedi/drivers/adv_pci_dio.c @@ -604,7 +604,6 @@ static int pci_dio_auto_attach(struct comedi_device *dev, ? pci_dio_insn_bits_di_w : pci_dio_insn_bits_di_b; s->private = (void *)d->addr; - } } diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/comedi/drivers/aio_aio12_8.c similarity index 100% rename from drivers/staging/comedi/drivers/aio_aio12_8.c rename to drivers/comedi/drivers/aio_aio12_8.c diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/comedi/drivers/aio_iiro_16.c similarity index 100% rename from drivers/staging/comedi/drivers/aio_iiro_16.c rename to drivers/comedi/drivers/aio_iiro_16.c diff --git a/drivers/staging/comedi/drivers/amcc_s5933.h b/drivers/comedi/drivers/amcc_s5933.h similarity index 100% rename from drivers/staging/comedi/drivers/amcc_s5933.h rename to drivers/comedi/drivers/amcc_s5933.h diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/comedi/drivers/amplc_dio200.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_dio200.c rename to drivers/comedi/drivers/amplc_dio200.c diff --git a/drivers/staging/comedi/drivers/amplc_dio200.h b/drivers/comedi/drivers/amplc_dio200.h similarity index 100% rename from drivers/staging/comedi/drivers/amplc_dio200.h rename to drivers/comedi/drivers/amplc_dio200.h diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/comedi/drivers/amplc_dio200_common.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_dio200_common.c rename to drivers/comedi/drivers/amplc_dio200_common.c diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/comedi/drivers/amplc_dio200_pci.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_dio200_pci.c rename to drivers/comedi/drivers/amplc_dio200_pci.c diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/comedi/drivers/amplc_pc236.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pc236.c rename to drivers/comedi/drivers/amplc_pc236.c diff --git a/drivers/staging/comedi/drivers/amplc_pc236.h b/drivers/comedi/drivers/amplc_pc236.h similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pc236.h rename to drivers/comedi/drivers/amplc_pc236.h diff --git a/drivers/staging/comedi/drivers/amplc_pc236_common.c b/drivers/comedi/drivers/amplc_pc236_common.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pc236_common.c rename to drivers/comedi/drivers/amplc_pc236_common.c diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/comedi/drivers/amplc_pc263.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pc263.c rename to drivers/comedi/drivers/amplc_pc263.c diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/comedi/drivers/amplc_pci224.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pci224.c rename to drivers/comedi/drivers/amplc_pci224.c diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/comedi/drivers/amplc_pci230.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pci230.c rename to drivers/comedi/drivers/amplc_pci230.c diff --git a/drivers/staging/comedi/drivers/amplc_pci236.c b/drivers/comedi/drivers/amplc_pci236.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pci236.c rename to drivers/comedi/drivers/amplc_pci236.c diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/comedi/drivers/amplc_pci263.c similarity index 100% rename from drivers/staging/comedi/drivers/amplc_pci263.c rename to drivers/comedi/drivers/amplc_pci263.c diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/comedi/drivers/c6xdigio.c similarity index 100% rename from drivers/staging/comedi/drivers/c6xdigio.c rename to drivers/comedi/drivers/c6xdigio.c diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/comedi/drivers/cb_das16_cs.c similarity index 100% rename from drivers/staging/comedi/drivers/cb_das16_cs.c rename to drivers/comedi/drivers/cb_das16_cs.c diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/comedi/drivers/cb_pcidas.c similarity index 100% rename from drivers/staging/comedi/drivers/cb_pcidas.c rename to drivers/comedi/drivers/cb_pcidas.c diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/comedi/drivers/cb_pcidas64.c similarity index 99% rename from drivers/staging/comedi/drivers/cb_pcidas64.c rename to drivers/comedi/drivers/cb_pcidas64.c index 6d3ba399a7f0bb4e5dc84a4299cee080b6d93d6f..41a8fea7f48a5d91c476c4be7c8a7477100fba76 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/comedi/drivers/cb_pcidas64.c @@ -229,11 +229,6 @@ enum daq_atrig_low_4020_contents { EXT_START_TRIG_BNC_BIT = 0x2000, }; -static inline u16 analog_trig_low_threshold_bits(u16 threshold) -{ - return threshold & 0xfff; -} - enum adc_control0_contents { ADC_GATE_SRC_MASK = 0x3, /* bits that select gate */ ADC_SOFT_GATE_BITS = 0x1, /* software gate */ diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/comedi/drivers/cb_pcidda.c similarity index 100% rename from drivers/staging/comedi/drivers/cb_pcidda.c rename to drivers/comedi/drivers/cb_pcidda.c diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/comedi/drivers/cb_pcimdas.c similarity index 100% rename from drivers/staging/comedi/drivers/cb_pcimdas.c rename to drivers/comedi/drivers/cb_pcimdas.c diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/comedi/drivers/cb_pcimdda.c similarity index 100% rename from drivers/staging/comedi/drivers/cb_pcimdda.c rename to drivers/comedi/drivers/cb_pcimdda.c diff --git a/drivers/staging/comedi/drivers/comedi_8254.c b/drivers/comedi/drivers/comedi_8254.c similarity index 100% rename from drivers/staging/comedi/drivers/comedi_8254.c rename to drivers/comedi/drivers/comedi_8254.c diff --git a/drivers/staging/comedi/drivers/comedi_8254.h b/drivers/comedi/drivers/comedi_8254.h similarity index 100% rename from drivers/staging/comedi/drivers/comedi_8254.h rename to drivers/comedi/drivers/comedi_8254.h diff --git a/drivers/staging/comedi/drivers/comedi_8255.c b/drivers/comedi/drivers/comedi_8255.c similarity index 100% rename from drivers/staging/comedi/drivers/comedi_8255.c rename to drivers/comedi/drivers/comedi_8255.c diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/comedi/drivers/comedi_bond.c similarity index 100% rename from drivers/staging/comedi/drivers/comedi_bond.c rename to drivers/comedi/drivers/comedi_bond.c diff --git a/drivers/staging/comedi/drivers/comedi_isadma.c b/drivers/comedi/drivers/comedi_isadma.c similarity index 100% rename from drivers/staging/comedi/drivers/comedi_isadma.c rename to drivers/comedi/drivers/comedi_isadma.c diff --git a/drivers/staging/comedi/drivers/comedi_isadma.h b/drivers/comedi/drivers/comedi_isadma.h similarity index 100% rename from drivers/staging/comedi/drivers/comedi_isadma.h rename to drivers/comedi/drivers/comedi_isadma.h diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/comedi/drivers/comedi_parport.c similarity index 100% rename from drivers/staging/comedi/drivers/comedi_parport.c rename to drivers/comedi/drivers/comedi_parport.c diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/comedi/drivers/comedi_test.c similarity index 100% rename from drivers/staging/comedi/drivers/comedi_test.c rename to drivers/comedi/drivers/comedi_test.c diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/comedi/drivers/contec_pci_dio.c similarity index 100% rename from drivers/staging/comedi/drivers/contec_pci_dio.c rename to drivers/comedi/drivers/contec_pci_dio.c diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/comedi/drivers/dac02.c similarity index 100% rename from drivers/staging/comedi/drivers/dac02.c rename to drivers/comedi/drivers/dac02.c diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/comedi/drivers/daqboard2000.c similarity index 100% rename from drivers/staging/comedi/drivers/daqboard2000.c rename to drivers/comedi/drivers/daqboard2000.c diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/comedi/drivers/das08.c similarity index 100% rename from drivers/staging/comedi/drivers/das08.c rename to drivers/comedi/drivers/das08.c diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/comedi/drivers/das08.h similarity index 100% rename from drivers/staging/comedi/drivers/das08.h rename to drivers/comedi/drivers/das08.h diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/comedi/drivers/das08_cs.c similarity index 100% rename from drivers/staging/comedi/drivers/das08_cs.c rename to drivers/comedi/drivers/das08_cs.c diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/comedi/drivers/das08_isa.c similarity index 100% rename from drivers/staging/comedi/drivers/das08_isa.c rename to drivers/comedi/drivers/das08_isa.c diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/comedi/drivers/das08_pci.c similarity index 100% rename from drivers/staging/comedi/drivers/das08_pci.c rename to drivers/comedi/drivers/das08_pci.c diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/comedi/drivers/das16.c similarity index 100% rename from drivers/staging/comedi/drivers/das16.c rename to drivers/comedi/drivers/das16.c diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/comedi/drivers/das16m1.c similarity index 100% rename from drivers/staging/comedi/drivers/das16m1.c rename to drivers/comedi/drivers/das16m1.c diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/comedi/drivers/das1800.c similarity index 100% rename from drivers/staging/comedi/drivers/das1800.c rename to drivers/comedi/drivers/das1800.c diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/comedi/drivers/das6402.c similarity index 100% rename from drivers/staging/comedi/drivers/das6402.c rename to drivers/comedi/drivers/das6402.c diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/comedi/drivers/das800.c similarity index 99% rename from drivers/staging/comedi/drivers/das800.c rename to drivers/comedi/drivers/das800.c index 2881808d6606c2833ada99de22428aa4265a8d5a..bc08324f422faf3f1df19c44dbf043e9ed871c12 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/comedi/drivers/das800.c @@ -668,7 +668,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = board->name; if (irq > 1 && irq <= 7) { - ret = request_irq(irq, das800_interrupt, 0, dev->board_name, + ret = request_irq(irq, das800_interrupt, 0, "das800", dev); if (ret == 0) dev->irq = irq; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/comedi/drivers/dmm32at.c similarity index 100% rename from drivers/staging/comedi/drivers/dmm32at.c rename to drivers/comedi/drivers/dmm32at.c diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/comedi/drivers/dt2801.c similarity index 100% rename from drivers/staging/comedi/drivers/dt2801.c rename to drivers/comedi/drivers/dt2801.c diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/comedi/drivers/dt2811.c similarity index 100% rename from drivers/staging/comedi/drivers/dt2811.c rename to drivers/comedi/drivers/dt2811.c diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/comedi/drivers/dt2814.c similarity index 66% rename from drivers/staging/comedi/drivers/dt2814.c rename to drivers/comedi/drivers/dt2814.c index bcf4d5444fafa74a0b832f47160d5ecd7f118062..ed44ce0d151b080fb6f14fb828d8fda00e391f8d 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/comedi/drivers/dt2814.c @@ -44,14 +44,46 @@ #define DT2814_ENB 0x10 #define DT2814_CHANMASK 0x0f -struct dt2814_private { - int ntrig; - int curadchan; -}; - #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ +static int dt2814_ai_notbusy(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2814_CSR); + if (context) + *(unsigned int *)context = status; + if (status & DT2814_BUSY) + return -EBUSY; + return 0; +} + +static int dt2814_ai_clear(struct comedi_device *dev) +{ + unsigned int status = 0; + int ret; + + /* Wait until not busy and get status register value. */ + ret = comedi_timeout(dev, NULL, NULL, dt2814_ai_notbusy, + (unsigned long)&status); + if (ret) + return ret; + + if (status & (DT2814_FINISH | DT2814_ERR)) { + /* + * There unread data, or the error flag is set. + * Read the data register twice to clear the condition. + */ + inb(dev->iobase + DT2814_DATA); + inb(dev->iobase + DT2814_DATA); + } + return 0; +} + static int dt2814_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -73,6 +105,7 @@ static int dt2814_ai_insn_read(struct comedi_device *dev, int chan; int ret; + dt2814_ai_clear(dev); /* clear stale data or error */ for (n = 0; n < insn->n; n++) { chan = CR_CHAN(insn->chanspec); @@ -169,80 +202,119 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev, static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct dt2814_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int chan; int trigvar; + dt2814_ai_clear(dev); /* clear stale data or error */ trigvar = dt2814_ns_to_timer(&cmd->scan_begin_arg, cmd->flags); chan = CR_CHAN(cmd->chanlist[0]); - devpriv->ntrig = cmd->stop_arg; outb(chan | DT2814_ENB | (trigvar << 5), dev->iobase + DT2814_CSR); return 0; } +static int dt2814_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int status; + unsigned long flags; + + spin_lock_irqsave(&dev->spinlock, flags); + status = inb(dev->iobase + DT2814_CSR); + if (status & DT2814_ENB) { + /* + * Clear the timed trigger enable bit. + * + * Note: turning off timed mode triggers another + * sample. This will be mopped up by the calls to + * dt2814_ai_clear(). + */ + outb(status & DT2814_CHANMASK, dev->iobase + DT2814_CSR); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + return 0; +} + static irqreturn_t dt2814_interrupt(int irq, void *d) { - int lo, hi; struct comedi_device *dev = d; - struct dt2814_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - int data; + struct comedi_async *async; + unsigned int lo, hi; + unsigned short data; + unsigned int status; if (!dev->attached) { dev_err(dev->class_dev, "spurious interrupt\n"); return IRQ_HANDLED; } + async = s->async; + + spin_lock(&dev->spinlock); + + status = inb(dev->iobase + DT2814_CSR); + if (!(status & DT2814_ENB)) { + /* Timed acquisition not enabled. Nothing to do. */ + spin_unlock(&dev->spinlock); + return IRQ_HANDLED; + } + + if (!(status & (DT2814_FINISH | DT2814_ERR))) { + /* Spurious interrupt? */ + spin_unlock(&dev->spinlock); + return IRQ_HANDLED; + } + + /* Read data or clear error. */ hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); data = (hi << 4) | (lo >> 4); - if (!(--devpriv->ntrig)) { - int i; - - outb(0, dev->iobase + DT2814_CSR); + if (status & DT2814_ERR) { + async->events |= COMEDI_CB_ERROR; + } else { + comedi_buf_write_samples(s, &data, 1); + if (async->cmd.stop_src == TRIG_COUNT && + async->scans_done >= async->cmd.stop_arg) { + async->events |= COMEDI_CB_EOA; + } + } + if (async->events & COMEDI_CB_CANCEL_MASK) { /* - * note: turning off timed mode triggers another - * sample. + * Disable timed mode. + * + * Note: turning off timed mode triggers another + * sample. This will be mopped up by the calls to + * dt2814_ai_clear(). */ + outb(status & DT2814_CHANMASK, dev->iobase + DT2814_CSR); + } - for (i = 0; i < DT2814_TIMEOUT; i++) { - if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH) - break; - } - inb(dev->iobase + DT2814_DATA); - inb(dev->iobase + DT2814_DATA); + spin_unlock(&dev->spinlock); - s->async->events |= COMEDI_CB_EOA; - } comedi_handle_events(dev, s); return IRQ_HANDLED; } static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct dt2814_private *devpriv; struct comedi_subdevice *s; int ret; - int i; ret = comedi_request_region(dev, it->options[0], 0x2); if (ret) return ret; outb(0, dev->iobase + DT2814_CSR); - usleep_range(100, 200); - if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) { + if (dt2814_ai_clear(dev)) { dev_err(dev->class_dev, "reset error (fatal)\n"); return -EIO; } - i = inb(dev->iobase + DT2814_DATA); - i = inb(dev->iobase + DT2814_DATA); if (it->options[1]) { ret = request_irq(it->options[1], dt2814_interrupt, 0, @@ -255,10 +327,6 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -272,16 +340,30 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->do_cmd = dt2814_ai_cmd; s->do_cmdtest = dt2814_ai_cmdtest; + s->cancel = dt2814_ai_cancel; } return 0; } +static void dt2814_detach(struct comedi_device *dev) +{ + if (dev->irq) { + /* + * An extra conversion triggered on termination of an + * asynchronous command may still be in progress. Wait for + * it to finish and clear the data or error status. + */ + dt2814_ai_clear(dev); + } + comedi_legacy_detach(dev); +} + static struct comedi_driver dt2814_driver = { .driver_name = "dt2814", .module = THIS_MODULE, .attach = dt2814_attach, - .detach = comedi_legacy_detach, + .detach = dt2814_detach, }; module_comedi_driver(dt2814_driver); diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/comedi/drivers/dt2815.c similarity index 100% rename from drivers/staging/comedi/drivers/dt2815.c rename to drivers/comedi/drivers/dt2815.c diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/comedi/drivers/dt2817.c similarity index 100% rename from drivers/staging/comedi/drivers/dt2817.c rename to drivers/comedi/drivers/dt2817.c diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/comedi/drivers/dt282x.c similarity index 100% rename from drivers/staging/comedi/drivers/dt282x.c rename to drivers/comedi/drivers/dt282x.c diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/comedi/drivers/dt3000.c similarity index 100% rename from drivers/staging/comedi/drivers/dt3000.c rename to drivers/comedi/drivers/dt3000.c diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/comedi/drivers/dt9812.c similarity index 100% rename from drivers/staging/comedi/drivers/dt9812.c rename to drivers/comedi/drivers/dt9812.c diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/comedi/drivers/dyna_pci10xx.c similarity index 100% rename from drivers/staging/comedi/drivers/dyna_pci10xx.c rename to drivers/comedi/drivers/dyna_pci10xx.c diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/comedi/drivers/fl512.c similarity index 100% rename from drivers/staging/comedi/drivers/fl512.c rename to drivers/comedi/drivers/fl512.c diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/comedi/drivers/gsc_hpdi.c similarity index 100% rename from drivers/staging/comedi/drivers/gsc_hpdi.c rename to drivers/comedi/drivers/gsc_hpdi.c diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/comedi/drivers/icp_multi.c similarity index 100% rename from drivers/staging/comedi/drivers/icp_multi.c rename to drivers/comedi/drivers/icp_multi.c diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/comedi/drivers/ii_pci20kc.c similarity index 100% rename from drivers/staging/comedi/drivers/ii_pci20kc.c rename to drivers/comedi/drivers/ii_pci20kc.c diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/comedi/drivers/jr3_pci.c similarity index 100% rename from drivers/staging/comedi/drivers/jr3_pci.c rename to drivers/comedi/drivers/jr3_pci.c diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/comedi/drivers/jr3_pci.h similarity index 100% rename from drivers/staging/comedi/drivers/jr3_pci.h rename to drivers/comedi/drivers/jr3_pci.h diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/comedi/drivers/ke_counter.c similarity index 100% rename from drivers/staging/comedi/drivers/ke_counter.c rename to drivers/comedi/drivers/ke_counter.c diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/comedi/drivers/me4000.c similarity index 100% rename from drivers/staging/comedi/drivers/me4000.c rename to drivers/comedi/drivers/me4000.c diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/comedi/drivers/me_daq.c similarity index 100% rename from drivers/staging/comedi/drivers/me_daq.c rename to drivers/comedi/drivers/me_daq.c diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/comedi/drivers/mf6x4.c similarity index 100% rename from drivers/staging/comedi/drivers/mf6x4.c rename to drivers/comedi/drivers/mf6x4.c diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/comedi/drivers/mite.c similarity index 100% rename from drivers/staging/comedi/drivers/mite.c rename to drivers/comedi/drivers/mite.c diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/comedi/drivers/mite.h similarity index 100% rename from drivers/staging/comedi/drivers/mite.h rename to drivers/comedi/drivers/mite.h diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/comedi/drivers/mpc624.c similarity index 100% rename from drivers/staging/comedi/drivers/mpc624.c rename to drivers/comedi/drivers/mpc624.c diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/comedi/drivers/multiq3.c similarity index 100% rename from drivers/staging/comedi/drivers/multiq3.c rename to drivers/comedi/drivers/multiq3.c diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/comedi/drivers/ni_6527.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_6527.c rename to drivers/comedi/drivers/ni_6527.c diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/comedi/drivers/ni_65xx.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_65xx.c rename to drivers/comedi/drivers/ni_65xx.c diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/comedi/drivers/ni_660x.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_660x.c rename to drivers/comedi/drivers/ni_660x.c diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/comedi/drivers/ni_670x.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_670x.c rename to drivers/comedi/drivers/ni_670x.c diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/comedi/drivers/ni_at_a2150.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_at_a2150.c rename to drivers/comedi/drivers/ni_at_a2150.c diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/comedi/drivers/ni_at_ao.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_at_ao.c rename to drivers/comedi/drivers/ni_at_ao.c diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/comedi/drivers/ni_atmio.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_atmio.c rename to drivers/comedi/drivers/ni_atmio.c diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/comedi/drivers/ni_atmio16d.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_atmio16d.c rename to drivers/comedi/drivers/ni_atmio16d.c diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/comedi/drivers/ni_daq_700.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_daq_700.c rename to drivers/comedi/drivers/ni_daq_700.c diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/comedi/drivers/ni_daq_dio24.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_daq_dio24.c rename to drivers/comedi/drivers/ni_daq_dio24.c diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/comedi/drivers/ni_labpc.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc.c rename to drivers/comedi/drivers/ni_labpc.c diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/comedi/drivers/ni_labpc.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc.h rename to drivers/comedi/drivers/ni_labpc.h diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/comedi/drivers/ni_labpc_common.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc_common.c rename to drivers/comedi/drivers/ni_labpc_common.c diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/comedi/drivers/ni_labpc_cs.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc_cs.c rename to drivers/comedi/drivers/ni_labpc_cs.c diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/comedi/drivers/ni_labpc_isadma.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc_isadma.c rename to drivers/comedi/drivers/ni_labpc_isadma.c diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/comedi/drivers/ni_labpc_isadma.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc_isadma.h rename to drivers/comedi/drivers/ni_labpc_isadma.h diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/comedi/drivers/ni_labpc_pci.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc_pci.c rename to drivers/comedi/drivers/ni_labpc_pci.c diff --git a/drivers/staging/comedi/drivers/ni_labpc_regs.h b/drivers/comedi/drivers/ni_labpc_regs.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_labpc_regs.h rename to drivers/comedi/drivers/ni_labpc_regs.h diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/comedi/drivers/ni_mio_common.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_mio_common.c rename to drivers/comedi/drivers/ni_mio_common.c diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/comedi/drivers/ni_mio_cs.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_mio_cs.c rename to drivers/comedi/drivers/ni_mio_cs.c diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/comedi/drivers/ni_pcidio.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_pcidio.c rename to drivers/comedi/drivers/ni_pcidio.c diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/comedi/drivers/ni_pcimio.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_pcimio.c rename to drivers/comedi/drivers/ni_pcimio.c diff --git a/drivers/staging/comedi/drivers/ni_routes.c b/drivers/comedi/drivers/ni_routes.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routes.c rename to drivers/comedi/drivers/ni_routes.c diff --git a/drivers/staging/comedi/drivers/ni_routes.h b/drivers/comedi/drivers/ni_routes.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_routes.h rename to drivers/comedi/drivers/ni_routes.h diff --git a/drivers/staging/comedi/drivers/ni_routing/README b/drivers/comedi/drivers/ni_routing/README similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/README rename to drivers/comedi/drivers/ni_routing/README diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.c b/drivers/comedi/drivers/ni_routing/ni_device_routes.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.h b/drivers/comedi/drivers/ni_routing/ni_device_routes.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes.h rename to drivers/comedi/drivers/ni_routing/ni_device_routes.h diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/all.h b/drivers/comedi/drivers/ni_routing/ni_device_routes/all.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/all.h rename to drivers/comedi/drivers/ni_routing/ni_device_routes/all.h diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c rename to drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values.c b/drivers/comedi/drivers/ni_routing/ni_route_values.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_route_values.c rename to drivers/comedi/drivers/ni_routing/ni_route_values.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values.h b/drivers/comedi/drivers/ni_routing/ni_route_values.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_route_values.h rename to drivers/comedi/drivers/ni_routing/ni_route_values.h diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/all.h b/drivers/comedi/drivers/ni_routing/ni_route_values/all.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_route_values/all.h rename to drivers/comedi/drivers/ni_routing/ni_route_values/all.h diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_660x.c b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_660x.c rename to drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c rename to drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c rename to drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/.gitignore b/drivers/comedi/drivers/ni_routing/tools/.gitignore similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/.gitignore rename to drivers/comedi/drivers/ni_routing/tools/.gitignore diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/Makefile b/drivers/comedi/drivers/ni_routing/tools/Makefile similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/Makefile rename to drivers/comedi/drivers/ni_routing/tools/Makefile diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/convert_c_to_py.c b/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/convert_c_to_py.c rename to drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/convert_csv_to_c.py b/drivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/convert_csv_to_c.py rename to drivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/convert_py_to_csv.py b/drivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/convert_py_to_csv.py rename to drivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/csv_collection.py b/drivers/comedi/drivers/ni_routing/tools/csv_collection.py similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/csv_collection.py rename to drivers/comedi/drivers/ni_routing/tools/csv_collection.py diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/make_blank_csv.py b/drivers/comedi/drivers/ni_routing/tools/make_blank_csv.py similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/make_blank_csv.py rename to drivers/comedi/drivers/ni_routing/tools/make_blank_csv.py diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/ni_names.py b/drivers/comedi/drivers/ni_routing/tools/ni_names.py similarity index 100% rename from drivers/staging/comedi/drivers/ni_routing/tools/ni_names.py rename to drivers/comedi/drivers/ni_routing/tools/ni_names.py diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/comedi/drivers/ni_stc.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_stc.h rename to drivers/comedi/drivers/ni_stc.h diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/comedi/drivers/ni_tio.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_tio.c rename to drivers/comedi/drivers/ni_tio.c diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/comedi/drivers/ni_tio.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_tio.h rename to drivers/comedi/drivers/ni_tio.h diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/comedi/drivers/ni_tio_internal.h similarity index 100% rename from drivers/staging/comedi/drivers/ni_tio_internal.h rename to drivers/comedi/drivers/ni_tio_internal.h diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/comedi/drivers/ni_tiocmd.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_tiocmd.c rename to drivers/comedi/drivers/ni_tiocmd.c diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/comedi/drivers/ni_usb6501.c similarity index 100% rename from drivers/staging/comedi/drivers/ni_usb6501.c rename to drivers/comedi/drivers/ni_usb6501.c diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/comedi/drivers/pcl711.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl711.c rename to drivers/comedi/drivers/pcl711.c diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/comedi/drivers/pcl724.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl724.c rename to drivers/comedi/drivers/pcl724.c diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/comedi/drivers/pcl726.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl726.c rename to drivers/comedi/drivers/pcl726.c diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/comedi/drivers/pcl730.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl730.c rename to drivers/comedi/drivers/pcl730.c diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/comedi/drivers/pcl812.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl812.c rename to drivers/comedi/drivers/pcl812.c diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/comedi/drivers/pcl816.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl816.c rename to drivers/comedi/drivers/pcl816.c diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/comedi/drivers/pcl818.c similarity index 100% rename from drivers/staging/comedi/drivers/pcl818.c rename to drivers/comedi/drivers/pcl818.c diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/comedi/drivers/pcm3724.c similarity index 100% rename from drivers/staging/comedi/drivers/pcm3724.c rename to drivers/comedi/drivers/pcm3724.c diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/comedi/drivers/pcmad.c similarity index 100% rename from drivers/staging/comedi/drivers/pcmad.c rename to drivers/comedi/drivers/pcmad.c diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/comedi/drivers/pcmda12.c similarity index 100% rename from drivers/staging/comedi/drivers/pcmda12.c rename to drivers/comedi/drivers/pcmda12.c diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/comedi/drivers/pcmmio.c similarity index 100% rename from drivers/staging/comedi/drivers/pcmmio.c rename to drivers/comedi/drivers/pcmmio.c diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/comedi/drivers/pcmuio.c similarity index 100% rename from drivers/staging/comedi/drivers/pcmuio.c rename to drivers/comedi/drivers/pcmuio.c diff --git a/drivers/staging/comedi/drivers/plx9052.h b/drivers/comedi/drivers/plx9052.h similarity index 100% rename from drivers/staging/comedi/drivers/plx9052.h rename to drivers/comedi/drivers/plx9052.h diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/comedi/drivers/plx9080.h similarity index 100% rename from drivers/staging/comedi/drivers/plx9080.h rename to drivers/comedi/drivers/plx9080.h diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/comedi/drivers/quatech_daqp_cs.c similarity index 100% rename from drivers/staging/comedi/drivers/quatech_daqp_cs.c rename to drivers/comedi/drivers/quatech_daqp_cs.c diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/comedi/drivers/rtd520.c similarity index 100% rename from drivers/staging/comedi/drivers/rtd520.c rename to drivers/comedi/drivers/rtd520.c diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/comedi/drivers/rti800.c similarity index 100% rename from drivers/staging/comedi/drivers/rti800.c rename to drivers/comedi/drivers/rti800.c diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/comedi/drivers/rti802.c similarity index 100% rename from drivers/staging/comedi/drivers/rti802.c rename to drivers/comedi/drivers/rti802.c diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/comedi/drivers/s526.c similarity index 100% rename from drivers/staging/comedi/drivers/s526.c rename to drivers/comedi/drivers/s526.c diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/comedi/drivers/s626.c similarity index 100% rename from drivers/staging/comedi/drivers/s626.c rename to drivers/comedi/drivers/s626.c diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/comedi/drivers/s626.h similarity index 100% rename from drivers/staging/comedi/drivers/s626.h rename to drivers/comedi/drivers/s626.h diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/comedi/drivers/ssv_dnp.c similarity index 100% rename from drivers/staging/comedi/drivers/ssv_dnp.c rename to drivers/comedi/drivers/ssv_dnp.c diff --git a/drivers/staging/comedi/drivers/tests/Makefile b/drivers/comedi/drivers/tests/Makefile similarity index 57% rename from drivers/staging/comedi/drivers/tests/Makefile rename to drivers/comedi/drivers/tests/Makefile index b5d8e13d4162928a0c6ae9b24058c6a7c2a7cb60..5ff7cdc32a321cf28cf3b633ce344904db3fc82f 100644 --- a/drivers/staging/comedi/drivers/tests/Makefile +++ b/drivers/comedi/drivers/tests/Makefile @@ -3,5 +3,6 @@ # ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG -obj-$(CONFIG_COMEDI_TESTS) += example_test.o ni_routes_test.o +obj-$(CONFIG_COMEDI_TESTS_EXAMPLE) += comedi_example_test.o +obj-$(CONFIG_COMEDI_TESTS_NI_ROUTES) += ni_routes_test.o CFLAGS_ni_routes_test.o := -DDEBUG diff --git a/drivers/staging/comedi/drivers/tests/example_test.c b/drivers/comedi/drivers/tests/comedi_example_test.c similarity index 91% rename from drivers/staging/comedi/drivers/tests/example_test.c rename to drivers/comedi/drivers/tests/comedi_example_test.c index fc65158b8e8ed76780fb921a148e962ba53496fc..e5aaaeab7bdd9a5824f6160bc50c0e6a9a20ac2c 100644 --- a/drivers/staging/comedi/drivers/tests/example_test.c +++ b/drivers/comedi/drivers/tests/comedi_example_test.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* vim: set ts=8 sw=8 noet tw=80 nowrap: */ /* - * comedi/drivers/tests/example_test.c + * comedi/drivers/tests/comedi_example_test.c * Example set of unit tests. * * COMEDI - Linux Control and Measurement Device Interface @@ -35,14 +35,14 @@ static struct comedi_device dev = { /* *** END fake board data *** */ /* *** BEGIN fake data init *** */ -void init_fake(void) +static void init_fake(void) { dev.item = 10; } /* *** END fake data init *** */ -void test0(void) +static void test0(void) { init_fake(); unittest(dev.item != 11, "negative result\n"); @@ -52,8 +52,8 @@ void test0(void) /* **** BEGIN simple module entry/exit functions **** */ static int __init unittest_enter(void) { - const unittest_fptr unit_tests[] = { - (unittest_fptr)test0, + static const unittest_fptr unit_tests[] = { + test0, NULL, }; diff --git a/drivers/staging/comedi/drivers/tests/ni_routes_test.c b/drivers/comedi/drivers/tests/ni_routes_test.c similarity index 88% rename from drivers/staging/comedi/drivers/tests/ni_routes_test.c rename to drivers/comedi/drivers/tests/ni_routes_test.c index 4061b3b5f8e9b446131117a7cabc66c716fb416f..32073850d545be396d8bb08afa4f2eb208b6ef66 100644 --- a/drivers/staging/comedi/drivers/tests/ni_routes_test.c +++ b/drivers/comedi/drivers/tests/ni_routes_test.c @@ -24,7 +24,7 @@ #include "../ni_routes.h" #include "unittest.h" -#define RVi(table, src, dest) ((table)[(dest) * NI_NUM_NAMES + (src)]) +#define RVI(table, src, dest) ((table)[(dest) * NI_NUM_NAMES + (src)]) #define O(x) ((x) + NI_NAMES_BASE) #define B(x) ((x) - NI_NAMES_BASE) #define V(x) ((x) | 0x80) @@ -63,24 +63,24 @@ static const int no_val_dest = O(7), no_val_index = 4; /* I1 and I2 should not call O(...). Mostly here to shut checkpatch.pl up */ #define I1(x1) \ - (int[]){ \ - x1, 0 \ - } + ((int[]){ \ + (x1), 0 \ + }) #define I2(x1, x2) \ - (int[]){ \ + ((int[]){ \ (x1), (x2), 0 \ - } + }) #define I3(x1, x2, x3) \ - (int[]){ \ + ((int[]){ \ (x1), (x2), (x3), 0 \ - } + }) /* O9 is build to call O(...) for each arg */ #define O9(x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - (int[]){ \ + ((int[]){ \ O(x1), O(x2), O(x3), O(x4), O(x5), O(x6), O(x7), O(x8), O(x9), \ 0 \ - } + }) static struct ni_device_routes DR = { .device = "testdev", @@ -194,7 +194,7 @@ static bool route_set_dests_in_order(const struct ni_device_routes *devroutes) } /* Tests that all route_set->src are in order of the signal source. */ -bool route_set_sources_in_order(const struct ni_device_routes *devroutes) +static bool route_set_sources_in_order(const struct ni_device_routes *devroutes) { int i; @@ -211,13 +211,14 @@ bool route_set_sources_in_order(const struct ni_device_routes *devroutes) return true; } -void test_ni_assign_device_routes(void) +static void test_ni_assign_device_routes(void) { - const struct ni_device_routes *devroutes, *olddevroutes; + const struct ni_device_routes *devroutes; const u8 *table, *oldtable; init_pci_6070e(); - ni_assign_device_routes(ni_eseries, pci_6070e, &private.routing_tables); + ni_assign_device_routes(ni_eseries, pci_6070e, NULL, + &private.routing_tables); devroutes = private.routing_tables.valid_routes; table = private.routing_tables.route_values; @@ -242,18 +243,16 @@ void test_ni_assign_device_routes(void) unittest(route_set_sources_in_order(devroutes), "all pci-6070e route_set->src's in order of signal source\n"); - unittest( - RVi(table, B(PXI_Star), B(NI_AI_SampleClock)) == V(17) && - RVi(table, B(NI_10MHzRefClock), B(TRIGGER_LINE(0))) == 0 && - RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(0))) == 0 && - RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(2))) == - V(NI_PFI_OUTPUT_AI_CONVERT), - "pci-6070e finds e-series route_values table\n"); + unittest(RVI(table, B(PXI_Star), B(NI_AI_SampleClock)) == V(17) && + RVI(table, B(NI_10MHzRefClock), B(TRIGGER_LINE(0))) == 0 && + RVI(table, B(NI_AI_ConvertClock), B(NI_PFI(0))) == 0 && + RVI(table, B(NI_AI_ConvertClock), B(NI_PFI(2))) == V(NI_PFI_OUTPUT_AI_CONVERT), + "pci-6070e finds e-series route_values table\n"); - olddevroutes = devroutes; oldtable = table; init_pci_6220(); - ni_assign_device_routes(ni_mseries, pci_6220, &private.routing_tables); + ni_assign_device_routes(ni_mseries, pci_6220, NULL, + &private.routing_tables); devroutes = private.routing_tables.valid_routes; table = private.routing_tables.route_values; @@ -261,15 +260,14 @@ void test_ni_assign_device_routes(void) "find device pci-6220\n"); unittest(oldtable != table, "pci-6220 find other route_values table\n"); - unittest( - RVi(table, B(PXI_Star), B(NI_AI_SampleClock)) == V(20) && - RVi(table, B(NI_10MHzRefClock), B(TRIGGER_LINE(0))) == V(12) && - RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(0))) == V(3) && - RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(2))) == V(3), - "pci-6220 finds m-series route_values table\n"); + unittest(RVI(table, B(PXI_Star), B(NI_AI_SampleClock)) == V(20) && + RVI(table, B(NI_10MHzRefClock), B(TRIGGER_LINE(0))) == V(12) && + RVI(table, B(NI_AI_ConvertClock), B(NI_PFI(0))) == V(3) && + RVI(table, B(NI_AI_ConvertClock), B(NI_PFI(2))) == V(3), + "pci-6220 finds m-series route_values table\n"); } -void test_ni_sort_device_routes(void) +static void test_ni_sort_device_routes(void) { /* We begin by sorting the device routes for use in later tests */ ni_sort_device_routes(&DR); @@ -280,7 +278,7 @@ void test_ni_sort_device_routes(void) "all route_set->src's of fake data in order of sig. source\n"); } -void test_ni_find_route_set(void) +static void test_ni_find_route_set(void) { unittest(!ni_find_route_set(bad_dest, &DR), "check for nonexistent route_set\n"); @@ -296,7 +294,7 @@ void test_ni_find_route_set(void) "find last route_set\n"); } -void test_ni_route_set_has_source(void) +static void test_ni_route_set_has_source(void) { unittest(!ni_route_set_has_source(&DR.routes[0], O(0)), "check for bad source\n"); @@ -308,7 +306,7 @@ void test_ni_route_set_has_source(void) "find last source\n"); } -void test_ni_route_to_register(void) +static void test_ni_route_to_register(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -358,7 +356,7 @@ void test_ni_route_to_register(void) "validate indirect route through brd3 to TRIGGER_LINE(1)\n"); } -void test_ni_lookup_route_register(void) +static void test_ni_lookup_route_register(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -397,7 +395,7 @@ void test_ni_lookup_route_register(void) "brd0_src1: lookup indirect route register\n"); } -void test_route_is_valid(void) +static void test_route_is_valid(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -412,7 +410,7 @@ void test_route_is_valid(void) "validate last destination\n"); } -void test_ni_is_cmd_dest(void) +static void test_ni_is_cmd_dest(void) { init_pci_fake(); unittest(ni_is_cmd_dest(NI_AI_SampleClock), @@ -429,7 +427,7 @@ void test_ni_is_cmd_dest(void) "check that AO/SampleClockTimebase _not_ cmd destination\n"); } -void test_channel_is_pfi(void) +static void test_channel_is_pfi(void) { init_pci_fake(); unittest(channel_is_pfi(NI_PFI(0)), "check First pfi channel\n"); @@ -439,7 +437,7 @@ void test_channel_is_pfi(void) "check first non pfi channel\n"); } -void test_channel_is_rtsi(void) +static void test_channel_is_rtsi(void) { init_pci_fake(); unittest(channel_is_rtsi(TRIGGER_LINE(0)), @@ -452,7 +450,7 @@ void test_channel_is_rtsi(void) "check first non rtsi channel\n"); } -void test_ni_count_valid_routes(void) +static void test_ni_count_valid_routes(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -460,7 +458,7 @@ void test_ni_count_valid_routes(void) unittest(ni_count_valid_routes(T) == 57, "count all valid routes\n"); } -void test_ni_get_valid_routes(void) +static void test_ni_get_valid_routes(void) { const struct ni_route_tables *T = &private.routing_tables; unsigned int pair_data[2]; @@ -477,7 +475,7 @@ void test_ni_get_valid_routes(void) "destination of first valid pair from ni_get_valid_routes\n"); } -void test_ni_find_route_source(void) +static void test_ni_find_route_source(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -494,7 +492,7 @@ void test_ni_find_route_source(void) "find invalid source (without checking device routes)\n"); } -void test_route_register_is_valid(void) +static void test_route_register_is_valid(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -509,7 +507,7 @@ void test_route_register_is_valid(void) "find last source"); } -void test_ni_check_trigger_arg(void) +static void test_ni_check_trigger_arg(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -542,7 +540,7 @@ void test_ni_check_trigger_arg(void) "check trigger arg for last src->dest\n"); } -void test_ni_get_reg_value(void) +static void test_ni_get_reg_value(void) { const struct ni_route_tables *T = &private.routing_tables; @@ -578,23 +576,23 @@ void test_ni_get_reg_value(void) /* **** BEGIN simple module entry/exit functions **** */ static int __init ni_routes_unittest(void) { - const unittest_fptr unit_tests[] = { - (unittest_fptr)test_ni_assign_device_routes, - (unittest_fptr)test_ni_sort_device_routes, - (unittest_fptr)test_ni_find_route_set, - (unittest_fptr)test_ni_route_set_has_source, - (unittest_fptr)test_ni_route_to_register, - (unittest_fptr)test_ni_lookup_route_register, - (unittest_fptr)test_route_is_valid, - (unittest_fptr)test_ni_is_cmd_dest, - (unittest_fptr)test_channel_is_pfi, - (unittest_fptr)test_channel_is_rtsi, - (unittest_fptr)test_ni_count_valid_routes, - (unittest_fptr)test_ni_get_valid_routes, - (unittest_fptr)test_ni_find_route_source, - (unittest_fptr)test_route_register_is_valid, - (unittest_fptr)test_ni_check_trigger_arg, - (unittest_fptr)test_ni_get_reg_value, + static const unittest_fptr unit_tests[] = { + test_ni_assign_device_routes, + test_ni_sort_device_routes, + test_ni_find_route_set, + test_ni_route_set_has_source, + test_ni_route_to_register, + test_ni_lookup_route_register, + test_route_is_valid, + test_ni_is_cmd_dest, + test_channel_is_pfi, + test_channel_is_rtsi, + test_ni_count_valid_routes, + test_ni_get_valid_routes, + test_ni_find_route_source, + test_route_register_is_valid, + test_ni_check_trigger_arg, + test_ni_get_reg_value, NULL, }; diff --git a/drivers/staging/comedi/drivers/tests/unittest.h b/drivers/comedi/drivers/tests/unittest.h similarity index 98% rename from drivers/staging/comedi/drivers/tests/unittest.h rename to drivers/comedi/drivers/tests/unittest.h index b8e622ea1de19ae5c1624518dd2b16a833c7ba7b..2da3beea2479d3c6538eb8331b06be809c291a99 100644 --- a/drivers/staging/comedi/drivers/tests/unittest.h +++ b/drivers/comedi/drivers/tests/unittest.h @@ -27,7 +27,7 @@ static struct unittest_results { int failed; } unittest_results; -typedef void *(*unittest_fptr)(void); +typedef void (*unittest_fptr)(void); #define unittest(result, fmt, ...) ({ \ bool failed = !(result); \ diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/comedi/drivers/usbdux.c similarity index 100% rename from drivers/staging/comedi/drivers/usbdux.c rename to drivers/comedi/drivers/usbdux.c diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/comedi/drivers/usbduxfast.c similarity index 100% rename from drivers/staging/comedi/drivers/usbduxfast.c rename to drivers/comedi/drivers/usbduxfast.c diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/comedi/drivers/usbduxsigma.c similarity index 100% rename from drivers/staging/comedi/drivers/usbduxsigma.c rename to drivers/comedi/drivers/usbduxsigma.c diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/comedi/drivers/vmk80xx.c similarity index 100% rename from drivers/staging/comedi/drivers/vmk80xx.c rename to drivers/comedi/drivers/vmk80xx.c diff --git a/drivers/staging/comedi/drivers/z8536.h b/drivers/comedi/drivers/z8536.h similarity index 100% rename from drivers/staging/comedi/drivers/z8536.h rename to drivers/comedi/drivers/z8536.h diff --git a/drivers/staging/comedi/kcomedilib/Makefile b/drivers/comedi/kcomedilib/Makefile similarity index 100% rename from drivers/staging/comedi/kcomedilib/Makefile rename to drivers/comedi/kcomedilib/Makefile diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/comedi/kcomedilib/kcomedilib_main.c similarity index 100% rename from drivers/staging/comedi/kcomedilib/kcomedilib_main.c rename to drivers/comedi/kcomedilib/kcomedilib_main.c diff --git a/drivers/staging/comedi/proc.c b/drivers/comedi/proc.c similarity index 100% rename from drivers/staging/comedi/proc.c rename to drivers/comedi/proc.c diff --git a/drivers/staging/comedi/range.c b/drivers/comedi/range.c similarity index 100% rename from drivers/staging/comedi/range.c rename to drivers/comedi/range.c diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index 78766b6ec271a3dc191cf1f4582c82c560e6ee73..9691f8612be87ec338e2a7e5f60c439999a5e0c9 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -9,8 +9,6 @@ #include <linux/counter.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/iio/iio.h> -#include <linux/iio/types.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/isa.h> @@ -29,7 +27,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); #define QUAD8_NUM_COUNTERS 8 /** - * struct quad8_iio - IIO device private data structure + * struct quad8 - device private data structure * @counter: instance of the counter_device * @fck_prescaler: array of filter clock prescaler configurations * @preset: array of preset values @@ -41,9 +39,9 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); * @synchronous_mode: array of index function synchronous mode configurations * @index_polarity: array of index function polarity configurations * @cable_fault_enable: differential encoder cable status enable configurations - * @base: base port address of the IIO device + * @base: base port address of the device */ -struct quad8_iio { +struct quad8 { struct mutex lock; struct counter_device counter; unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; @@ -98,532 +96,10 @@ struct quad8_iio { #define QUAD8_CMR_QUADRATURE_X2 0x10 #define QUAD8_CMR_QUADRATURE_X4 0x18 - -static int quad8_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int *val, int *val2, long mask) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; - unsigned int flags; - unsigned int borrow; - unsigned int carry; - int i; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - if (chan->type == IIO_INDEX) { - *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) - & BIT(chan->channel)); - return IIO_VAL_INT; - } - - flags = inb(base_offset + 1); - borrow = flags & QUAD8_FLAG_BT; - carry = !!(flags & QUAD8_FLAG_CT); - - /* Borrow XOR Carry effectively doubles count range */ - *val = (borrow ^ carry) << 24; - - mutex_lock(&priv->lock); - - /* Reset Byte Pointer; transfer Counter to Output Latch */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, - base_offset + 1); - - for (i = 0; i < 3; i++) - *val |= (unsigned int)inb(base_offset) << (8 * i); - - mutex_unlock(&priv->lock); - - return IIO_VAL_INT; - case IIO_CHAN_INFO_ENABLE: - *val = priv->ab_enable[chan->channel]; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 1; - *val2 = priv->quadrature_scale[chan->channel]; - return IIO_VAL_FRACTIONAL_LOG2; - } - - return -EINVAL; -} - -static int quad8_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int val, int val2, long mask) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; - int i; - unsigned int ior_cfg; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - if (chan->type == IIO_INDEX) - return -EINVAL; - - /* Only 24-bit values are supported */ - if ((unsigned int)val > 0xFFFFFF) - return -EINVAL; - - mutex_lock(&priv->lock); - - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - - /* Counter can only be set via Preset Register */ - for (i = 0; i < 3; i++) - outb(val >> (8 * i), base_offset); - - /* Transfer Preset Register to Counter */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); - - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - - /* Set Preset Register back to original value */ - val = priv->preset[chan->channel]; - for (i = 0; i < 3; i++) - outb(val >> (8 * i), base_offset); - - /* Reset Borrow, Carry, Compare, and Sign flags */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); - /* Reset Error flag */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); - - mutex_unlock(&priv->lock); - - return 0; - case IIO_CHAN_INFO_ENABLE: - /* only boolean values accepted */ - if (val < 0 || val > 1) - return -EINVAL; - - mutex_lock(&priv->lock); - - priv->ab_enable[chan->channel] = val; - - ior_cfg = val | priv->preset_enable[chan->channel] << 1; - - /* Load I/O control configuration */ - outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); - - mutex_unlock(&priv->lock); - - return 0; - case IIO_CHAN_INFO_SCALE: - mutex_lock(&priv->lock); - - /* Quadrature scaling only available in quadrature mode */ - if (!priv->quadrature_mode[chan->channel] && - (val2 || val != 1)) { - mutex_unlock(&priv->lock); - return -EINVAL; - } - - /* Only three gain states (1, 0.5, 0.25) */ - if (val == 1 && !val2) - priv->quadrature_scale[chan->channel] = 0; - else if (!val) - switch (val2) { - case 500000: - priv->quadrature_scale[chan->channel] = 1; - break; - case 250000: - priv->quadrature_scale[chan->channel] = 2; - break; - default: - mutex_unlock(&priv->lock); - return -EINVAL; - } - else { - mutex_unlock(&priv->lock); - return -EINVAL; - } - - mutex_unlock(&priv->lock); - return 0; - } - - return -EINVAL; -} - -static const struct iio_info quad8_info = { - .read_raw = quad8_read_raw, - .write_raw = quad8_write_raw -}; - -static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, - const struct iio_chan_spec *chan, char *buf) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); -} - -static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, - const struct iio_chan_spec *chan, const char *buf, size_t len) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; - unsigned int preset; - int ret; - int i; - - ret = kstrtouint(buf, 0, &preset); - if (ret) - return ret; - - /* Only 24-bit values are supported */ - if (preset > 0xFFFFFF) - return -EINVAL; - - mutex_lock(&priv->lock); - - priv->preset[chan->channel] = preset; - - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - - /* Set Preset Register */ - for (i = 0; i < 3; i++) - outb(preset >> (8 * i), base_offset); - - mutex_unlock(&priv->lock); - - return len; -} - -static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, char *buf) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", - !priv->preset_enable[chan->channel]); -} - -static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, const char *buf, - size_t len) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - bool preset_enable; - int ret; - unsigned int ior_cfg; - - ret = kstrtobool(buf, &preset_enable); - if (ret) - return ret; - - /* Preset enable is active low in Input/Output Control register */ - preset_enable = !preset_enable; - - mutex_lock(&priv->lock); - - priv->preset_enable[chan->channel] = preset_enable; - - ior_cfg = priv->ab_enable[chan->channel] | - (unsigned int)preset_enable << 1; - - /* Load I/O control configuration to Input / Output Control Register */ - outb(QUAD8_CTR_IOR | ior_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return len; -} - -static const char *const quad8_noise_error_states[] = { - "No excessive noise is present at the count inputs", - "Excessive noise is present at the count inputs" -}; - -static int quad8_get_noise_error(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - - return !!(inb(base_offset) & QUAD8_FLAG_E); -} - -static const struct iio_enum quad8_noise_error_enum = { - .items = quad8_noise_error_states, - .num_items = ARRAY_SIZE(quad8_noise_error_states), - .get = quad8_get_noise_error -}; - -static const char *const quad8_count_direction_states[] = { - "down", - "up" -}; - -static int quad8_get_count_direction(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - - return !!(inb(base_offset) & QUAD8_FLAG_UD); -} - -static const struct iio_enum quad8_count_direction_enum = { - .items = quad8_count_direction_states, - .num_items = ARRAY_SIZE(quad8_count_direction_states), - .get = quad8_get_count_direction -}; - -static const char *const quad8_count_modes[] = { - "normal", - "range limit", - "non-recycle", - "modulo-n" -}; - -static int quad8_set_count_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int cnt_mode) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - unsigned int mode_cfg = cnt_mode << 1; - const int base_offset = priv->base + 2 * chan->channel + 1; - - mutex_lock(&priv->lock); - - priv->count_mode[chan->channel] = cnt_mode; - - /* Add quadrature mode configuration */ - if (priv->quadrature_mode[chan->channel]) - mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; - - /* Load mode configuration to Counter Mode Register */ - outb(QUAD8_CTR_CMR | mode_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_count_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->count_mode[chan->channel]; -} - -static const struct iio_enum quad8_count_mode_enum = { - .items = quad8_count_modes, - .num_items = ARRAY_SIZE(quad8_count_modes), - .set = quad8_set_count_mode, - .get = quad8_get_count_mode -}; - -static const char *const quad8_synchronous_modes[] = { - "non-synchronous", - "synchronous" -}; - -static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int synchronous_mode) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - unsigned int idr_cfg = synchronous_mode; - - mutex_lock(&priv->lock); - - idr_cfg |= priv->index_polarity[chan->channel] << 1; - - /* Index function must be non-synchronous in non-quadrature mode */ - if (synchronous_mode && !priv->quadrature_mode[chan->channel]) { - mutex_unlock(&priv->lock); - return -EINVAL; - } - - priv->synchronous_mode[chan->channel] = synchronous_mode; - - /* Load Index Control configuration to Index Control Register */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->synchronous_mode[chan->channel]; -} - -static const struct iio_enum quad8_synchronous_mode_enum = { - .items = quad8_synchronous_modes, - .num_items = ARRAY_SIZE(quad8_synchronous_modes), - .set = quad8_set_synchronous_mode, - .get = quad8_get_synchronous_mode -}; - -static const char *const quad8_quadrature_modes[] = { - "non-quadrature", - "quadrature" -}; - -static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int quadrature_mode) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - unsigned int mode_cfg; - - mutex_lock(&priv->lock); - - mode_cfg = priv->count_mode[chan->channel] << 1; - - if (quadrature_mode) - mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; - else { - /* Quadrature scaling only available in quadrature mode */ - priv->quadrature_scale[chan->channel] = 0; - - /* Synchronous function not supported in non-quadrature mode */ - if (priv->synchronous_mode[chan->channel]) - quad8_set_synchronous_mode(indio_dev, chan, 0); - } - - priv->quadrature_mode[chan->channel] = quadrature_mode; - - /* Load mode configuration to Counter Mode Register */ - outb(QUAD8_CTR_CMR | mode_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->quadrature_mode[chan->channel]; -} - -static const struct iio_enum quad8_quadrature_mode_enum = { - .items = quad8_quadrature_modes, - .num_items = ARRAY_SIZE(quad8_quadrature_modes), - .set = quad8_set_quadrature_mode, - .get = quad8_get_quadrature_mode -}; - -static const char *const quad8_index_polarity_modes[] = { - "negative", - "positive" -}; - -static int quad8_set_index_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int index_polarity) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - unsigned int idr_cfg = index_polarity << 1; - - mutex_lock(&priv->lock); - - idr_cfg |= priv->synchronous_mode[chan->channel]; - - priv->index_polarity[chan->channel] = index_polarity; - - /* Load Index Control configuration to Index Control Register */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_index_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->index_polarity[chan->channel]; -} - -static const struct iio_enum quad8_index_polarity_enum = { - .items = quad8_index_polarity_modes, - .num_items = ARRAY_SIZE(quad8_index_polarity_modes), - .set = quad8_set_index_polarity, - .get = quad8_get_index_polarity -}; - -static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { - { - .name = "preset", - .shared = IIO_SEPARATE, - .read = quad8_read_preset, - .write = quad8_write_preset - }, - { - .name = "set_to_preset_on_index", - .shared = IIO_SEPARATE, - .read = quad8_read_set_to_preset_on_index, - .write = quad8_write_set_to_preset_on_index - }, - IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), - IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), - IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), - IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), - IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), - IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), - IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), - IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), - {} -}; - -static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { - IIO_ENUM("synchronous_mode", IIO_SEPARATE, - &quad8_synchronous_mode_enum), - IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), - IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), - IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), - {} -}; - -#define QUAD8_COUNT_CHAN(_chan) { \ - .type = IIO_COUNT, \ - .channel = (_chan), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ - .ext_info = quad8_count_ext_info, \ - .indexed = 1 \ -} - -#define QUAD8_INDEX_CHAN(_chan) { \ - .type = IIO_INDEX, \ - .channel = (_chan), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .ext_info = quad8_index_ext_info, \ - .indexed = 1 \ -} - -static const struct iio_chan_spec quad8_channels[] = { - QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), - QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), - QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), - QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), - QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), - QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), - QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), - QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) -}; - static int quad8_signal_read(struct counter_device *counter, struct counter_signal *signal, enum counter_signal_value *val) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; unsigned int state; /* Only Index signal levels can be read */ @@ -641,7 +117,7 @@ static int quad8_signal_read(struct counter_device *counter, static int quad8_count_read(struct counter_device *counter, struct counter_count *count, unsigned long *val) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; unsigned int flags; unsigned int borrow; @@ -672,7 +148,7 @@ static int quad8_count_read(struct counter_device *counter, static int quad8_count_write(struct counter_device *counter, struct counter_count *count, unsigned long val) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; int i; @@ -727,7 +203,7 @@ static enum counter_count_function quad8_count_functions_list[] = { static int quad8_function_get(struct counter_device *counter, struct counter_count *count, size_t *function) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int id = count->id; mutex_lock(&priv->lock); @@ -755,7 +231,7 @@ static int quad8_function_get(struct counter_device *counter, static int quad8_function_set(struct counter_device *counter, struct counter_count *count, size_t function) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int id = count->id; unsigned int *const quadrature_mode = priv->quadrature_mode + id; unsigned int *const scale = priv->quadrature_scale + id; @@ -811,7 +287,7 @@ static int quad8_function_set(struct counter_device *counter, static void quad8_direction_get(struct counter_device *counter, struct counter_count *count, enum counter_count_direction *direction) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; unsigned int ud_flag; const unsigned int flag_addr = priv->base + 2 * count->id + 1; @@ -845,7 +321,7 @@ static int quad8_action_get(struct counter_device *counter, struct counter_count *count, struct counter_synapse *synapse, size_t *action) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; int err; size_t function = 0; const size_t signal_a_id = count->synapses[0].signal->id; @@ -905,10 +381,15 @@ static const struct counter_ops quad8_ops = { .action_get = quad8_action_get }; +static const char *const quad8_index_polarity_modes[] = { + "negative", + "positive" +}; + static int quad8_index_polarity_get(struct counter_device *counter, struct counter_signal *signal, size_t *index_polarity) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; *index_polarity = priv->index_polarity[channel_id]; @@ -919,7 +400,7 @@ static int quad8_index_polarity_get(struct counter_device *counter, static int quad8_index_polarity_set(struct counter_device *counter, struct counter_signal *signal, size_t index_polarity) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; const int base_offset = priv->base + 2 * channel_id + 1; unsigned int idr_cfg = index_polarity << 1; @@ -945,10 +426,15 @@ static struct counter_signal_enum_ext quad8_index_pol_enum = { .set = quad8_index_polarity_set }; +static const char *const quad8_synchronous_modes[] = { + "non-synchronous", + "synchronous" +}; + static int quad8_synchronous_mode_get(struct counter_device *counter, struct counter_signal *signal, size_t *synchronous_mode) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; *synchronous_mode = priv->synchronous_mode[channel_id]; @@ -959,7 +445,7 @@ static int quad8_synchronous_mode_get(struct counter_device *counter, static int quad8_synchronous_mode_set(struct counter_device *counter, struct counter_signal *signal, size_t synchronous_mode) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; const int base_offset = priv->base + 2 * channel_id + 1; unsigned int idr_cfg = synchronous_mode; @@ -1001,7 +487,7 @@ static ssize_t quad8_count_floor_read(struct counter_device *counter, static int quad8_count_mode_get(struct counter_device *counter, struct counter_count *count, size_t *cnt_mode) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; /* Map 104-QUAD-8 count mode to Generic Counter count mode */ switch (priv->count_mode[count->id]) { @@ -1025,7 +511,7 @@ static int quad8_count_mode_get(struct counter_device *counter, static int quad8_count_mode_set(struct counter_device *counter, struct counter_count *count, size_t cnt_mode) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; unsigned int mode_cfg; const int base_offset = priv->base + 2 * count->id + 1; @@ -1084,7 +570,7 @@ static ssize_t quad8_count_direction_read(struct counter_device *counter, static ssize_t quad8_count_enable_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; return sprintf(buf, "%u\n", priv->ab_enable[count->id]); } @@ -1092,7 +578,7 @@ static ssize_t quad8_count_enable_read(struct counter_device *counter, static ssize_t quad8_count_enable_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; int err; bool ab_enable; @@ -1116,10 +602,15 @@ static ssize_t quad8_count_enable_write(struct counter_device *counter, return len; } +static const char *const quad8_noise_error_states[] = { + "No excessive noise is present at the count inputs", + "Excessive noise is present at the count inputs" +}; + static int quad8_error_noise_get(struct counter_device *counter, struct counter_count *count, size_t *noise_error) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id + 1; *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); @@ -1136,18 +627,18 @@ static struct counter_count_enum_ext quad8_error_noise_enum = { static ssize_t quad8_count_preset_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; return sprintf(buf, "%u\n", priv->preset[count->id]); } -static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id, - unsigned int preset) +static void quad8_preset_register_set(struct quad8 *priv, int id, + unsigned int preset) { - const unsigned int base_offset = quad8iio->base + 2 * id; + const unsigned int base_offset = priv->base + 2 * id; int i; - quad8iio->preset[id] = preset; + priv->preset[id] = preset; /* Reset Byte Pointer */ outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); @@ -1160,7 +651,7 @@ static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id, static ssize_t quad8_count_preset_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; unsigned int preset; int ret; @@ -1184,7 +675,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter, static ssize_t quad8_count_ceiling_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; mutex_lock(&priv->lock); @@ -1205,7 +696,7 @@ static ssize_t quad8_count_ceiling_read(struct counter_device *counter, static ssize_t quad8_count_ceiling_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; unsigned int ceiling; int ret; @@ -1235,7 +726,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter, static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; return sprintf(buf, "%u\n", !priv->preset_enable[count->id]); } @@ -1243,7 +734,7 @@ static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, static ssize_t quad8_count_preset_enable_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id + 1; bool preset_enable; int ret; @@ -1274,7 +765,7 @@ static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter, struct counter_signal *signal, void *private, char *buf) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; bool disabled; unsigned int status; @@ -1304,7 +795,7 @@ static ssize_t quad8_signal_cable_fault_enable_read( struct counter_device *counter, struct counter_signal *signal, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id)); @@ -1315,7 +806,7 @@ static ssize_t quad8_signal_cable_fault_enable_write( struct counter_device *counter, struct counter_signal *signal, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; bool enable; int ret; @@ -1345,7 +836,7 @@ static ssize_t quad8_signal_cable_fault_enable_write( static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter, struct counter_signal *signal, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]); @@ -1355,7 +846,7 @@ static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter, struct counter_signal *signal, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; const int base_offset = priv->base + 2 * channel_id; u8 prescaler; @@ -1531,11 +1022,9 @@ static struct counter_count quad8_counts[] = { static int quad8_probe(struct device *dev, unsigned int id) { - struct iio_dev *indio_dev; - struct quad8_iio *quad8iio; + struct quad8 *priv; int i, j; unsigned int base_offset; - int err; if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -1543,32 +1032,23 @@ static int quad8_probe(struct device *dev, unsigned int id) return -EBUSY; } - /* Allocate IIO device; this also allocates driver data structure */ - indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio)); - if (!indio_dev) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - /* Initialize IIO device */ - indio_dev->info = &quad8_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->num_channels = ARRAY_SIZE(quad8_channels); - indio_dev->channels = quad8_channels; - indio_dev->name = dev_name(dev); - /* Initialize Counter device and driver data */ - quad8iio = iio_priv(indio_dev); - quad8iio->counter.name = dev_name(dev); - quad8iio->counter.parent = dev; - quad8iio->counter.ops = &quad8_ops; - quad8iio->counter.counts = quad8_counts; - quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts); - quad8iio->counter.signals = quad8_signals; - quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals); - quad8iio->counter.priv = quad8iio; - quad8iio->base = base[id]; + priv->counter.name = dev_name(dev); + priv->counter.parent = dev; + priv->counter.ops = &quad8_ops; + priv->counter.counts = quad8_counts; + priv->counter.num_counts = ARRAY_SIZE(quad8_counts); + priv->counter.signals = quad8_signals; + priv->counter.num_signals = ARRAY_SIZE(quad8_signals); + priv->counter.priv = priv; + priv->base = base[id]; /* Initialize mutex */ - mutex_init(&quad8iio->lock); + mutex_init(&priv->lock); /* Reset all counters and disable interrupt function */ outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); @@ -1602,13 +1082,8 @@ static int quad8_probe(struct device *dev, unsigned int id) /* Enable all counters */ outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); - /* Register IIO device */ - err = devm_iio_device_register(dev, indio_dev); - if (err) - return err; - /* Register Counter device */ - return devm_counter_register(dev, &quad8iio->counter); + return devm_counter_register(dev, &priv->counter); } static struct isa_driver quad8_driver = { @@ -1621,5 +1096,5 @@ static struct isa_driver quad8_driver = { module_isa_driver(quad8_driver, num_quad8); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); -MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); +MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 2de53ab0dd252be4bb89f018b0827d3bf1fd6627..5328705aa09c685b3c9a13d97d05e83d27d95d44 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -14,7 +14,7 @@ if COUNTER config 104_QUAD_8 tristate "ACCES 104-QUAD-8 driver" - depends on PC104 && X86 && IIO + depends on PC104 && X86 select ISA_BUS_API help Say yes here to build support for the ACCES 104-QUAD-8 quadrature @@ -29,6 +29,16 @@ config 104_QUAD_8 The base port addresses for the devices may be configured via the base array module parameter. +config INTERRUPT_CNT + tristate "Interrupt counter driver" + depends on GPIOLIB + help + Select this option to enable interrupt counter driver. Any interrupt + source can be used by this driver as the event source. + + To compile this driver as a module, choose M here: the + module will be called interrupt-cnt. + config STM32_TIMER_CNT tristate "STM32 Timer encoder counter driver" depends on MFD_STM32_TIMERS || COMPILE_TEST @@ -41,7 +51,7 @@ config STM32_TIMER_CNT config STM32_LPTIMER_CNT tristate "STM32 LP Timer encoder counter driver" - depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO + depends on MFD_STM32_LPTIMER || COMPILE_TEST help Select this option to enable STM32 Low-Power Timer quadrature encoder and counter driver. diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index 0a393f71e4813a7efabb873d137dd02c45014db6..cb646ed2f0395c6c4d550c1b06032d2f38d06889 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COUNTER) += counter.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o +obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o obj-$(CONFIG_TI_EQEP) += ti-eqep.o diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c new file mode 100644 index 0000000000000000000000000000000000000000..a99ee79969775cc1b0a6a1e89c56c0972dcb4579 --- /dev/null +++ b/drivers/counter/interrupt-cnt.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + */ + +#include <linux/counter.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define INTERRUPT_CNT_NAME "interrupt-cnt" + +struct interrupt_cnt_priv { + atomic_t count; + struct counter_device counter; + struct gpio_desc *gpio; + int irq; + bool enabled; + struct counter_signal signals; + struct counter_synapse synapses; + struct counter_count cnts; +}; + +static irqreturn_t interrupt_cnt_isr(int irq, void *dev_id) +{ + struct interrupt_cnt_priv *priv = dev_id; + + atomic_inc(&priv->count); + + return IRQ_HANDLED; +} + +static ssize_t interrupt_cnt_enable_read(struct counter_device *counter, + struct counter_count *count, + void *private, char *buf) +{ + struct interrupt_cnt_priv *priv = counter->priv; + + return sysfs_emit(buf, "%d\n", priv->enabled); +} + +static ssize_t interrupt_cnt_enable_write(struct counter_device *counter, + struct counter_count *count, + void *private, const char *buf, + size_t len) +{ + struct interrupt_cnt_priv *priv = counter->priv; + bool enable; + ssize_t ret; + + ret = kstrtobool(buf, &enable); + if (ret) + return ret; + + if (priv->enabled == enable) + return len; + + if (enable) { + priv->enabled = true; + enable_irq(priv->irq); + } else { + disable_irq(priv->irq); + priv->enabled = false; + } + + return len; +} + +static const struct counter_count_ext interrupt_cnt_ext[] = { + { + .name = "enable", + .read = interrupt_cnt_enable_read, + .write = interrupt_cnt_enable_write, + }, +}; + +static enum counter_synapse_action interrupt_cnt_synapse_actionss[] = { + COUNTER_SYNAPSE_ACTION_RISING_EDGE, +}; + +static int interrupt_cnt_action_get(struct counter_device *counter, + struct counter_count *count, + struct counter_synapse *synapse, + size_t *action) +{ + *action = 0; + + return 0; +} + +static int interrupt_cnt_read(struct counter_device *counter, + struct counter_count *count, unsigned long *val) +{ + struct interrupt_cnt_priv *priv = counter->priv; + + *val = atomic_read(&priv->count); + + return 0; +} + +static int interrupt_cnt_write(struct counter_device *counter, + struct counter_count *count, + const unsigned long val) +{ + struct interrupt_cnt_priv *priv = counter->priv; + + atomic_set(&priv->count, val); + + return 0; +} + +static enum counter_count_function interrupt_cnt_functions[] = { + COUNTER_COUNT_FUNCTION_INCREASE, +}; + +static int interrupt_cnt_function_get(struct counter_device *counter, + struct counter_count *count, + size_t *function) +{ + *function = 0; + + return 0; +} + +static int interrupt_cnt_signal_read(struct counter_device *counter, + struct counter_signal *signal, + enum counter_signal_value *val) +{ + struct interrupt_cnt_priv *priv = counter->priv; + int ret; + + if (!priv->gpio) + return -EINVAL; + + ret = gpiod_get_value(priv->gpio); + if (ret < 0) + return ret; + + *val = ret ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW; + + return 0; +} + +static const struct counter_ops interrupt_cnt_ops = { + .action_get = interrupt_cnt_action_get, + .count_read = interrupt_cnt_read, + .count_write = interrupt_cnt_write, + .function_get = interrupt_cnt_function_get, + .signal_read = interrupt_cnt_signal_read, +}; + +static int interrupt_cnt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct interrupt_cnt_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->irq = platform_get_irq_optional(pdev, 0); + if (priv->irq == -ENXIO) + priv->irq = 0; + else if (priv->irq < 0) + return dev_err_probe(dev, priv->irq, "failed to get IRQ\n"); + + priv->gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_IN); + if (IS_ERR(priv->gpio)) + return dev_err_probe(dev, PTR_ERR(priv->gpio), "failed to get GPIO\n"); + + if (!priv->irq && !priv->gpio) { + dev_err(dev, "IRQ and GPIO are not found. At least one source should be provided\n"); + return -ENODEV; + } + + if (!priv->irq) { + int irq = gpiod_to_irq(priv->gpio); + + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get IRQ from GPIO\n"); + + priv->irq = irq; + } + + priv->signals.name = devm_kasprintf(dev, GFP_KERNEL, "IRQ %d", + priv->irq); + if (!priv->signals.name) + return -ENOMEM; + + priv->counter.signals = &priv->signals; + priv->counter.num_signals = 1; + + priv->synapses.actions_list = interrupt_cnt_synapse_actionss; + priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actionss); + priv->synapses.signal = &priv->signals; + + priv->cnts.name = "Channel 0 Count"; + priv->cnts.functions_list = interrupt_cnt_functions; + priv->cnts.num_functions = ARRAY_SIZE(interrupt_cnt_functions); + priv->cnts.synapses = &priv->synapses; + priv->cnts.num_synapses = 1; + priv->cnts.ext = interrupt_cnt_ext; + priv->cnts.num_ext = ARRAY_SIZE(interrupt_cnt_ext); + + priv->counter.priv = priv; + priv->counter.name = dev_name(dev); + priv->counter.parent = dev; + priv->counter.ops = &interrupt_cnt_ops; + priv->counter.counts = &priv->cnts; + priv->counter.num_counts = 1; + + irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); + ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr, + IRQF_TRIGGER_RISING | IRQF_NO_THREAD, + dev_name(dev), priv); + if (ret) + return ret; + + return devm_counter_register(dev, &priv->counter); +} + +static const struct of_device_id interrupt_cnt_of_match[] = { + { .compatible = "interrupt-counter", }, + {} +}; +MODULE_DEVICE_TABLE(of, interrupt_cnt_of_match); + +static struct platform_driver interrupt_cnt_driver = { + .probe = interrupt_cnt_probe, + .driver = { + .name = INTERRUPT_CNT_NAME, + .of_match_table = interrupt_cnt_of_match, + }, +}; +module_platform_driver(interrupt_cnt_driver); + +MODULE_ALIAS("platform:interrupt-counter"); +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>"); +MODULE_DESCRIPTION("Interrupt counter driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c index fd6828e2d34f532629217c5167d188c6e4241e2f..937439635d53f4a6fcc0fd334ca70caee19a521d 100644 --- a/drivers/counter/stm32-lptimer-cnt.c +++ b/drivers/counter/stm32-lptimer-cnt.c @@ -12,8 +12,8 @@ #include <linux/bitfield.h> #include <linux/counter.h> -#include <linux/iio/iio.h> #include <linux/mfd/stm32-lptimer.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -107,249 +107,27 @@ static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable) return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val); } -static int stm32_lptim_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_ENABLE: - if (val < 0 || val > 1) - return -EINVAL; - - /* Check nobody uses the timer, or already disabled/enabled */ - ret = stm32_lptim_is_enabled(priv); - if ((ret < 0) || (!ret && !val)) - return ret; - if (val && ret) - return -EBUSY; - - ret = stm32_lptim_setup(priv, val); - if (ret) - return ret; - return stm32_lptim_set_enable_state(priv, val); - - default: - return -EINVAL; - } -} - -static int stm32_lptim_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - u32 dat; - int ret; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat); - if (ret) - return ret; - *val = dat; - return IIO_VAL_INT; - - case IIO_CHAN_INFO_ENABLE: - ret = stm32_lptim_is_enabled(priv); - if (ret < 0) - return ret; - *val = ret; - return IIO_VAL_INT; - - case IIO_CHAN_INFO_SCALE: - /* Non-quadrature mode: scale = 1 */ - *val = 1; - *val2 = 0; - if (priv->quadrature_mode) { - /* - * Quadrature encoder mode: - * - both edges, quarter cycle, scale is 0.25 - * - either rising/falling edge scale is 0.5 - */ - if (priv->polarity > 1) - *val2 = 2; - else - *val2 = 1; - } - return IIO_VAL_FRACTIONAL_LOG2; - - default: - return -EINVAL; - } -} - -static const struct iio_info stm32_lptim_cnt_iio_info = { - .read_raw = stm32_lptim_read_raw, - .write_raw = stm32_lptim_write_raw, -}; - -static const char *const stm32_lptim_quadrature_modes[] = { - "non-quadrature", - "quadrature", -}; - -static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return priv->quadrature_mode; -} - -static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int type) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - if (stm32_lptim_is_enabled(priv)) - return -EBUSY; - - priv->quadrature_mode = type; - - return 0; -} - -static const struct iio_enum stm32_lptim_quadrature_mode_en = { - .items = stm32_lptim_quadrature_modes, - .num_items = ARRAY_SIZE(stm32_lptim_quadrature_modes), - .get = stm32_lptim_get_quadrature_mode, - .set = stm32_lptim_set_quadrature_mode, -}; - -static const char * const stm32_lptim_cnt_polarity[] = { - "rising-edge", "falling-edge", "both-edges", -}; - -static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return priv->polarity; -} - -static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int type) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - if (stm32_lptim_is_enabled(priv)) - return -EBUSY; - - priv->polarity = type; - - return 0; -} - -static const struct iio_enum stm32_lptim_cnt_polarity_en = { - .items = stm32_lptim_cnt_polarity, - .num_items = ARRAY_SIZE(stm32_lptim_cnt_polarity), - .get = stm32_lptim_cnt_get_polarity, - .set = stm32_lptim_cnt_set_polarity, -}; - -static ssize_t stm32_lptim_cnt_get_ceiling(struct stm32_lptim_cnt *priv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling); -} - -static ssize_t stm32_lptim_cnt_set_ceiling(struct stm32_lptim_cnt *priv, - const char *buf, size_t len) -{ - int ret; - - if (stm32_lptim_is_enabled(priv)) - return -EBUSY; - - ret = kstrtouint(buf, 0, &priv->ceiling); - if (ret) - return ret; - - if (priv->ceiling > STM32_LPTIM_MAX_ARR) - return -EINVAL; - - return len; -} - -static ssize_t stm32_lptim_cnt_get_preset_iio(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return stm32_lptim_cnt_get_ceiling(priv, buf); -} - -static ssize_t stm32_lptim_cnt_set_preset_iio(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - const char *buf, size_t len) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return stm32_lptim_cnt_set_ceiling(priv, buf, len); -} - -/* LP timer with encoder */ -static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = { - { - .name = "preset", - .shared = IIO_SEPARATE, - .read = stm32_lptim_cnt_get_preset_iio, - .write = stm32_lptim_cnt_set_preset_iio, - }, - IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), - IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), - IIO_ENUM("quadrature_mode", IIO_SEPARATE, - &stm32_lptim_quadrature_mode_en), - IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en), - {} -}; - -static const struct iio_chan_spec stm32_lptim_enc_channels = { - .type = IIO_COUNT, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_ENABLE) | - BIT(IIO_CHAN_INFO_SCALE), - .ext_info = stm32_lptim_enc_ext_info, - .indexed = 1, -}; - -/* LP timer without encoder (counter only) */ -static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = { - { - .name = "preset", - .shared = IIO_SEPARATE, - .read = stm32_lptim_cnt_get_preset_iio, - .write = stm32_lptim_cnt_set_preset_iio, - }, - IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), - IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), - {} -}; - -static const struct iio_chan_spec stm32_lptim_cnt_channels = { - .type = IIO_COUNT, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_ENABLE) | - BIT(IIO_CHAN_INFO_SCALE), - .ext_info = stm32_lptim_cnt_ext_info, - .indexed = 1, -}; - /** * enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes * @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) + * + * In non-quadrature mode, device counts up on active edge. + * In quadrature mode, encoder counting scenarios are as follows: + * +---------+----------+--------------------+--------------------+ + * | Active | Level on | IN1 signal | IN2 signal | + * | edge | opposite +----------+---------+----------+---------+ + * | | signal | Rising | Falling | Rising | Falling | + * +---------+----------+----------+---------+----------+---------+ + * | Rising | High -> | Down | - | Up | - | + * | edge | Low -> | Up | - | Down | - | + * +---------+----------+----------+---------+----------+---------+ + * | Falling | High -> | - | Up | - | Down | + * | edge | Low -> | - | Down | - | Up | + * +---------+----------+----------+---------+----------+---------+ + * | Both | High -> | Down | Up | Up | Down | + * | edges | Low -> | Up | Down | Down | Up | + * +---------+----------+----------+---------+----------+---------+ */ enum stm32_lptim_cnt_function { STM32_LPTIM_COUNTER_INCREASE, @@ -484,7 +262,7 @@ static ssize_t stm32_lptim_cnt_ceiling_read(struct counter_device *counter, { struct stm32_lptim_cnt *const priv = counter->priv; - return stm32_lptim_cnt_get_ceiling(priv, buf); + return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling); } static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter, @@ -493,8 +271,22 @@ static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter, const char *buf, size_t len) { struct stm32_lptim_cnt *const priv = counter->priv; + unsigned int ceiling; + int ret; + + if (stm32_lptim_is_enabled(priv)) + return -EBUSY; + + ret = kstrtouint(buf, 0, &ceiling); + if (ret) + return ret; + + if (ceiling > STM32_LPTIM_MAX_ARR) + return -EINVAL; + + priv->ceiling = ceiling; - return stm32_lptim_cnt_set_ceiling(priv, buf, len); + return len; } static const struct counter_count_ext stm32_lptim_cnt_ext[] = { @@ -630,32 +422,19 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) { struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); struct stm32_lptim_cnt *priv; - struct iio_dev *indio_dev; - int ret; if (IS_ERR_OR_NULL(ddata)) return -EINVAL; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); - if (!indio_dev) + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - priv = iio_priv(indio_dev); priv->dev = &pdev->dev; priv->regmap = ddata->regmap; priv->clk = ddata->clk; priv->ceiling = STM32_LPTIM_MAX_ARR; - /* Initialize IIO device */ - indio_dev->name = dev_name(&pdev->dev); - indio_dev->dev.of_node = pdev->dev.of_node; - indio_dev->info = &stm32_lptim_cnt_iio_info; - if (ddata->has_encoder) - indio_dev->channels = &stm32_lptim_enc_channels; - else - indio_dev->channels = &stm32_lptim_cnt_channels; - indio_dev->num_channels = 1; - /* Initialize Counter device */ priv->counter.name = dev_name(&pdev->dev); priv->counter.parent = &pdev->dev; @@ -673,10 +452,6 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - ret = devm_iio_device_register(&pdev->dev, indio_dev); - if (ret) - return ret; - return devm_counter_register(&pdev->dev, &priv->counter); } diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index cf79fe19c09460897b1e3dd38e07b52f0448296e..c63de9ed3dc080f72ea8b956661279c4cf6426da 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -13,7 +13,8 @@ config CPU_FREQ clock speed, you need to either enable a dynamic cpufreq governor (see below) after boot, or use a userspace tool. - For details, take a look at <file:Documentation/cpu-freq>. + For details, take a look at + <file:Documentation/admin-guide/pm/cpufreq.rst>. If in doubt, say N. @@ -147,8 +148,6 @@ config CPU_FREQ_GOV_USERSPACE To compile this driver as a module, choose M here: the module will be called cpufreq_userspace. - For details, take a look at <file:Documentation/cpu-freq/>. - If in doubt, say Y. config CPU_FREQ_GOV_ONDEMAND @@ -165,7 +164,8 @@ config CPU_FREQ_GOV_ONDEMAND To compile this driver as a module, choose M here: the module will be called cpufreq_ondemand. - For details, take a look at linux/Documentation/cpu-freq. + For details, take a look at + <file:Documentation/admin-guide/pm/cpufreq.rst>. If in doubt, say N. @@ -189,7 +189,8 @@ config CPU_FREQ_GOV_CONSERVATIVE To compile this driver as a module, choose M here: the module will be called cpufreq_conservative. - For details, take a look at linux/Documentation/cpu-freq. + For details, take a look at + <file:Documentation/admin-guide/pm/cpufreq.rst>. If in doubt, say N. @@ -262,8 +263,6 @@ config IA64_ACPI_CPUFREQ This driver adds a CPUFreq driver which utilizes the ACPI Processor Performance States. - For details, take a look at <file:Documentation/cpu-freq/>. - If in doubt, say N. endif @@ -287,8 +286,6 @@ config LOONGSON2_CPUFREQ Loongson2F and it's successors support this feature. - For details, take a look at <file:Documentation/cpu-freq/>. - If in doubt, say N. config LOONGSON1_CPUFREQ @@ -298,8 +295,6 @@ config LOONGSON1_CPUFREQ This option adds a CPUFreq driver for loongson1 processors which support software configurable cpu frequency. - For details, take a look at <file:Documentation/cpu-freq/>. - If in doubt, say N. endif @@ -309,8 +304,6 @@ config SPARC_US3_CPUFREQ help This adds the CPUFreq driver for UltraSPARC-III processors. - For details, take a look at <file:Documentation/cpu-freq>. - If in doubt, say N. config SPARC_US2E_CPUFREQ @@ -318,8 +311,6 @@ config SPARC_US2E_CPUFREQ help This adds the CPUFreq driver for UltraSPARC-IIe processors. - For details, take a look at <file:Documentation/cpu-freq>. - If in doubt, say N. endif @@ -334,8 +325,6 @@ config SH_CPU_FREQ will also generate a notice in the boot log before disabling itself if the CPU in question is not capable of rate rounding. - For details, take a look at <file:Documentation/cpu-freq>. - If unsure, say N. endif diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index e65e0a43be6449b655e2126ce133a786c1554a02..a5c5f70acfc9ef0f7634736926e77bed75bd1614 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -19,6 +19,16 @@ config ACPI_CPPC_CPUFREQ If in doubt, say N. +config ACPI_CPPC_CPUFREQ_FIE + bool "Frequency Invariance support for CPPC cpufreq driver" + depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY + default y + help + This extends frequency invariance support in the CPPC cpufreq driver, + by using CPPC delivered and reference performance counters. + + If in doubt, say N. + config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM tristate "Allwinner nvmem based SUN50I CPUFreq driver" depends on ARCH_SUNXI diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index b4af4094309b09eaf83733f8aab00d62fd1eb36e..3fc98a3ffd91ec0d084e16276991246f9acb04e2 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -25,6 +25,10 @@ #include "cpufreq-dt.h" +/* Clk register set */ +#define ARMADA_37XX_CLK_TBG_SEL 0 +#define ARMADA_37XX_CLK_TBG_SEL_CPU_OFF 22 + /* Power management in North Bridge register set */ #define ARMADA_37XX_NB_L0L1 0x18 #define ARMADA_37XX_NB_L2L3 0x1C @@ -69,6 +73,8 @@ #define LOAD_LEVEL_NR 4 #define MIN_VOLT_MV 1000 +#define MIN_VOLT_MV_FOR_L1_1000MHZ 1108 +#define MIN_VOLT_MV_FOR_L1_1200MHZ 1155 /* AVS value for the corresponding voltage (in mV) */ static int avs_map[] = { @@ -80,6 +86,8 @@ static int avs_map[] = { }; struct armada37xx_cpufreq_state { + struct platform_device *pdev; + struct device *cpu_dev; struct regmap *regmap; u32 nb_l0l1; u32 nb_l2l3; @@ -120,10 +128,15 @@ static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq) * will be configured then the DVFS will be enabled. */ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, - struct clk *clk, u8 *divider) + struct regmap *clk_base, u8 *divider) { + u32 cpu_tbg_sel; int load_lvl; - struct clk *parent; + + /* Determine to which TBG clock is CPU connected */ + regmap_read(clk_base, ARMADA_37XX_CLK_TBG_SEL, &cpu_tbg_sel); + cpu_tbg_sel >>= ARMADA_37XX_CLK_TBG_SEL_CPU_OFF; + cpu_tbg_sel &= ARMADA_37XX_NB_TBG_SEL_MASK; for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { unsigned int reg, mask, val, offset = 0; @@ -142,6 +155,11 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, mask = (ARMADA_37XX_NB_CLK_SEL_MASK << ARMADA_37XX_NB_CLK_SEL_OFF); + /* Set TBG index, for all levels we use the same TBG */ + val = cpu_tbg_sel << ARMADA_37XX_NB_TBG_SEL_OFF; + mask = (ARMADA_37XX_NB_TBG_SEL_MASK + << ARMADA_37XX_NB_TBG_SEL_OFF); + /* * Set cpu divider based on the pre-computed array in * order to have balanced step. @@ -160,14 +178,6 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, regmap_update_bits(base, reg, mask, val); } - - /* - * Set cpu clock source, for all the level we keep the same - * clock source that the one already configured. For this one - * we need to use the clock framework - */ - parent = clk_get_parent(clk); - clk_set_parent(clk, parent); } /* @@ -202,6 +212,8 @@ static u32 armada_37xx_avs_val_match(int target_vm) * - L2 & L3 voltage should be about 150mv smaller than L0 voltage. * This function calculates L1 & L2 & L3 AVS values dynamically based * on L0 voltage and fill all AVS values to the AVS value table. + * When base CPU frequency is 1000 or 1200 MHz then there is additional + * minimal avs value for load L1. */ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, struct armada_37xx_dvfs *dvfs) @@ -233,6 +245,19 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) dvfs->avs[load_level] = avs_min; + /* + * Set the avs values for load L0 and L1 when base CPU frequency + * is 1000/1200 MHz to its typical initial values according to + * the Armada 3700 Hardware Specifications. + */ + if (dvfs->cpu_freq_max >= 1000*1000*1000) { + if (dvfs->cpu_freq_max >= 1200*1000*1000) + avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ); + else + avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ); + dvfs->avs[0] = dvfs->avs[1] = avs_min; + } + return; } @@ -252,6 +277,26 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, target_vm = avs_map[l0_vdd_min] - 150; target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm); + + /* + * Fix the avs value for load L1 when base CPU frequency is 1000/1200 MHz, + * otherwise the CPU gets stuck when switching from load L1 to load L0. + * Also ensure that avs value for load L1 is not higher than for L0. + */ + if (dvfs->cpu_freq_max >= 1000*1000*1000) { + u32 avs_min_l1; + + if (dvfs->cpu_freq_max >= 1200*1000*1000) + avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ); + else + avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ); + + if (avs_min_l1 > dvfs->avs[0]) + avs_min_l1 = dvfs->avs[0]; + + if (dvfs->avs[1] < avs_min_l1) + dvfs->avs[1] = avs_min_l1; + } } static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, @@ -357,12 +402,17 @@ static int __init armada37xx_cpufreq_driver_init(void) struct armada_37xx_dvfs *dvfs; struct platform_device *pdev; unsigned long freq; - unsigned int cur_frequency, base_frequency; - struct regmap *nb_pm_base, *avs_base; + unsigned int base_frequency; + struct regmap *nb_clk_base, *nb_pm_base, *avs_base; struct device *cpu_dev; int load_lvl, ret; struct clk *clk, *parent; + nb_clk_base = + syscon_regmap_lookup_by_compatible("marvell,armada-3700-periph-clock-nb"); + if (IS_ERR(nb_clk_base)) + return -ENODEV; + nb_pm_base = syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm"); @@ -413,15 +463,7 @@ static int __init armada37xx_cpufreq_driver_init(void) return -EINVAL; } - /* Get nominal (current) CPU frequency */ - cur_frequency = clk_get_rate(clk); - if (!cur_frequency) { - dev_err(cpu_dev, "Failed to get clock rate for CPU\n"); - clk_put(clk); - return -EINVAL; - } - - dvfs = armada_37xx_cpu_freq_info_get(cur_frequency); + dvfs = armada_37xx_cpu_freq_info_get(base_frequency); if (!dvfs) { clk_put(clk); return -EINVAL; @@ -439,7 +481,7 @@ static int __init armada37xx_cpufreq_driver_init(void) armada37xx_cpufreq_avs_configure(avs_base, dvfs); armada37xx_cpufreq_avs_setup(avs_base, dvfs); - armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); + armada37xx_cpufreq_dvfs_setup(nb_pm_base, nb_clk_base, dvfs->divider); clk_put(clk); for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; @@ -466,6 +508,9 @@ static int __init armada37xx_cpufreq_driver_init(void) if (ret) goto disable_dvfs; + armada37xx_cpufreq_state->cpu_dev = cpu_dev; + armada37xx_cpufreq_state->pdev = pdev; + platform_set_drvdata(pdev, dvfs); return 0; disable_dvfs: @@ -473,7 +518,7 @@ disable_dvfs: remove_opp: /* clean-up the already added opp before leaving */ while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) { - freq = cur_frequency / dvfs->divider[load_lvl]; + freq = base_frequency / dvfs->divider[load_lvl]; dev_pm_opp_remove(cpu_dev, freq); } @@ -484,6 +529,26 @@ remove_opp: /* late_initcall, to guarantee the driver is loaded after A37xx clock driver */ late_initcall(armada37xx_cpufreq_driver_init); +static void __exit armada37xx_cpufreq_driver_exit(void) +{ + struct platform_device *pdev = armada37xx_cpufreq_state->pdev; + struct armada_37xx_dvfs *dvfs = platform_get_drvdata(pdev); + unsigned long freq; + int load_lvl; + + platform_device_unregister(pdev); + + armada37xx_cpufreq_disable_dvfs(armada37xx_cpufreq_state->regmap); + + for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { + freq = dvfs->cpu_freq_max / dvfs->divider[load_lvl]; + dev_pm_opp_remove(armada37xx_cpufreq_state->cpu_dev, freq); + } + + kfree(armada37xx_cpufreq_state); +} +module_exit(armada37xx_cpufreq_driver_exit); + static const struct of_device_id __maybe_unused armada37xx_cpufreq_of_match[] = { { .compatible = "marvell,armada-3700-nb-pm" }, { }, diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 8a482c434ea6ae844305ba9b215223400203b1eb..3848b4c222e1332cae44f19503c03c2177c95fa6 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -10,14 +10,18 @@ #define pr_fmt(fmt) "CPPC Cpufreq:" fmt +#include <linux/arch_topology.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/cpu.h> #include <linux/cpufreq.h> #include <linux/dmi.h> +#include <linux/irq_work.h> +#include <linux/kthread.h> #include <linux/time.h> #include <linux/vmalloc.h> +#include <uapi/linux/sched/types.h> #include <asm/unaligned.h> @@ -57,6 +61,204 @@ static struct cppc_workaround_oem_info wa_info[] = { } }; +#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE + +/* Frequency invariance support */ +struct cppc_freq_invariance { + int cpu; + struct irq_work irq_work; + struct kthread_work work; + struct cppc_perf_fb_ctrs prev_perf_fb_ctrs; + struct cppc_cpudata *cpu_data; +}; + +static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv); +static struct kthread_worker *kworker_fie; +static bool fie_disabled; + +static struct cpufreq_driver cppc_cpufreq_driver; +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); + +/** + * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance + * @work: The work item. + * + * The CPPC driver register itself with the topology core to provide its own + * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which + * gets called by the scheduler on every tick. + * + * Note that the arch specific counters have higher priority than CPPC counters, + * if available, though the CPPC driver doesn't need to have any special + * handling for that. + * + * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we + * reach here from hard-irq context), which then schedules a normal work item + * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable + * based on the counter updates since the last tick. + */ +static void cppc_scale_freq_workfn(struct kthread_work *work) +{ + struct cppc_freq_invariance *cppc_fi; + struct cppc_perf_fb_ctrs fb_ctrs = {0}; + struct cppc_cpudata *cpu_data; + unsigned long local_freq_scale; + u64 perf; + + cppc_fi = container_of(work, struct cppc_freq_invariance, work); + cpu_data = cppc_fi->cpu_data; + + if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) { + pr_warn("%s: failed to read perf counters\n", __func__); + return; + } + + cppc_fi->prev_perf_fb_ctrs = fb_ctrs; + perf = cppc_perf_from_fbctrs(cpu_data, cppc_fi->prev_perf_fb_ctrs, + fb_ctrs); + + perf <<= SCHED_CAPACITY_SHIFT; + local_freq_scale = div64_u64(perf, cpu_data->perf_caps.highest_perf); + if (WARN_ON(local_freq_scale > 1024)) + local_freq_scale = 1024; + + per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale; +} + +static void cppc_irq_work(struct irq_work *irq_work) +{ + struct cppc_freq_invariance *cppc_fi; + + cppc_fi = container_of(irq_work, struct cppc_freq_invariance, irq_work); + kthread_queue_work(kworker_fie, &cppc_fi->work); +} + +static void cppc_scale_freq_tick(void) +{ + struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id()); + + /* + * cppc_get_perf_ctrs() can potentially sleep, call that from the right + * context. + */ + irq_work_queue(&cppc_fi->irq_work); +} + +static struct scale_freq_data cppc_sftd = { + .source = SCALE_FREQ_SOURCE_CPPC, + .set_freq_scale = cppc_scale_freq_tick, +}; + +static void cppc_freq_invariance_policy_init(struct cpufreq_policy *policy, + struct cppc_cpudata *cpu_data) +{ + struct cppc_perf_fb_ctrs fb_ctrs = {0}; + struct cppc_freq_invariance *cppc_fi; + int i, ret; + + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + if (fie_disabled) + return; + + for_each_cpu(i, policy->cpus) { + cppc_fi = &per_cpu(cppc_freq_inv, i); + cppc_fi->cpu = i; + cppc_fi->cpu_data = cpu_data; + kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn); + init_irq_work(&cppc_fi->irq_work, cppc_irq_work); + + ret = cppc_get_perf_ctrs(i, &fb_ctrs); + if (ret) { + pr_warn("%s: failed to read perf counters: %d\n", + __func__, ret); + fie_disabled = true; + } else { + cppc_fi->prev_perf_fb_ctrs = fb_ctrs; + } + } +} + +static void __init cppc_freq_invariance_init(void) +{ + struct sched_attr attr = { + .size = sizeof(struct sched_attr), + .sched_policy = SCHED_DEADLINE, + .sched_nice = 0, + .sched_priority = 0, + /* + * Fake (unused) bandwidth; workaround to "fix" + * priority inheritance. + */ + .sched_runtime = 1000000, + .sched_deadline = 10000000, + .sched_period = 10000000, + }; + int ret; + + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + if (fie_disabled) + return; + + kworker_fie = kthread_create_worker(0, "cppc_fie"); + if (IS_ERR(kworker_fie)) + return; + + ret = sched_setattr_nocheck(kworker_fie->task, &attr); + if (ret) { + pr_warn("%s: failed to set SCHED_DEADLINE: %d\n", __func__, + ret); + kthread_destroy_worker(kworker_fie); + return; + } + + /* Register for freq-invariance */ + topology_set_scale_freq_source(&cppc_sftd, cpu_present_mask); +} + +static void cppc_freq_invariance_exit(void) +{ + struct cppc_freq_invariance *cppc_fi; + int i; + + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + if (fie_disabled) + return; + + topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, cpu_present_mask); + + for_each_possible_cpu(i) { + cppc_fi = &per_cpu(cppc_freq_inv, i); + irq_work_sync(&cppc_fi->irq_work); + } + + kthread_destroy_worker(kworker_fie); + kworker_fie = NULL; +} + +#else +static inline void +cppc_freq_invariance_policy_init(struct cpufreq_policy *policy, + struct cppc_cpudata *cpu_data) +{ +} + +static inline void cppc_freq_invariance_init(void) +{ +} + +static inline void cppc_freq_invariance_exit(void) +{ +} +#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */ + /* Callback function used to retrieve the max frequency from DMI */ static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) { @@ -216,26 +418,16 @@ static unsigned int cppc_cpufreq_get_transition_delay_us(unsigned int cpu) { unsigned long implementor = read_cpuid_implementor(); unsigned long part_num = read_cpuid_part_number(); - unsigned int delay_us = 0; switch (implementor) { case ARM_CPU_IMP_QCOM: switch (part_num) { case QCOM_CPU_PART_FALKOR_V1: case QCOM_CPU_PART_FALKOR: - delay_us = 10000; - break; - default: - delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC; - break; + return 10000; } - break; - default: - delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC; - break; } - - return delay_us; + return cppc_get_transition_latency(cpu) / NSEC_PER_USEC; } #else @@ -355,9 +547,12 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) cpu_data->perf_ctrls.desired_perf = caps->highest_perf; ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); - if (ret) + if (ret) { pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", caps->highest_perf, cpu, ret); + } else { + cppc_freq_invariance_policy_init(policy, cpu_data); + } return ret; } @@ -370,12 +565,12 @@ static inline u64 get_delta(u64 t1, u64 t0) return (u32)t1 - (u32)t0; } -static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data, - struct cppc_perf_fb_ctrs fb_ctrs_t0, - struct cppc_perf_fb_ctrs fb_ctrs_t1) +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) { u64 delta_reference, delta_delivered; - u64 reference_perf, delivered_perf; + u64 reference_perf; reference_perf = fb_ctrs_t0.reference_perf; @@ -384,12 +579,21 @@ static int cppc_get_rate_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 */ - if (delta_reference || delta_delivered) - delivered_perf = (reference_perf * delta_delivered) / - delta_reference; - else - delivered_perf = cpu_data->perf_ctrls.desired_perf; + /* Check to avoid divide-by zero and invalid delivered_perf */ + if (!delta_reference || !delta_delivered) + return cpu_data->perf_ctrls.desired_perf; + + return (reference_perf * delta_delivered) / delta_reference; +} + +static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data, + struct cppc_perf_fb_ctrs fb_ctrs_t0, + struct cppc_perf_fb_ctrs fb_ctrs_t1) +{ + u64 delivered_perf; + + delivered_perf = cppc_perf_from_fbctrs(cpu_data, fb_ctrs_t0, + fb_ctrs_t1); return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf); } @@ -514,6 +718,8 @@ static void cppc_check_hisi_workaround(void) static int __init cppc_cpufreq_init(void) { + int ret; + if ((acpi_disabled) || !acpi_cpc_valid()) return -ENODEV; @@ -521,7 +727,11 @@ static int __init cppc_cpufreq_init(void) cppc_check_hisi_workaround(); - return cpufreq_register_driver(&cppc_cpufreq_driver); + ret = cpufreq_register_driver(&cppc_cpufreq_driver); + if (!ret) + cppc_freq_invariance_init(); + + return ret; } static inline void free_cpu_data(void) @@ -538,6 +748,7 @@ static inline void free_cpu_data(void) static void __exit cppc_cpufreq_exit(void) { + cppc_freq_invariance_exit(); cpufreq_unregister_driver(&cppc_cpufreq_driver); free_cpu_data(); diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index b1e1bdc63b01f207c12ba45d26da315d83ec7465..ece52863ba62e66cfd87e335299dbdf5388404c6 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -255,10 +255,15 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu) * before updating priv->cpus. Otherwise, we will end up creating * duplicate OPPs for the CPUs. * - * OPPs might be populated at runtime, don't check for error here. + * OPPs might be populated at runtime, don't fail for error here unless + * it is -EPROBE_DEFER. */ - if (!dev_pm_opp_of_cpumask_add_table(priv->cpus)) + ret = dev_pm_opp_of_cpumask_add_table(priv->cpus); + if (!ret) { priv->have_static_opps = true; + } else if (ret == -EPROBE_DEFER) { + goto out; + } /* * The OPP table must be initialized, statically or dynamically, by this diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7b07066a229fd53176ec4fa52a748325a8d2975a..30bb41f3226596da9ef4c332d62786a95398a072 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -44,9 +44,6 @@ static LIST_HEAD(cpufreq_policy_list); #define for_each_inactive_policy(__policy) \ for_each_suitable_policy(__policy, false) -#define for_each_policy(__policy) \ - list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) - /* Iterate over governors */ static LIST_HEAD(cpufreq_governor_list); #define for_each_governor(__governor) \ diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 2efe7189ccc4273e72cb16417679aba31af43dcd..c6bdc455517f856b8c736e492a6350d5b3c78da8 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -54,7 +54,7 @@ processor_set_pstate ( retval = ia64_pal_set_pstate((u64)value); if (retval) { - pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n", + pr_debug("Failed to set freq to 0x%x, with error 0x%llx\n", value, retval); return -ENODEV; } @@ -77,7 +77,7 @@ processor_get_pstate ( if (retval) pr_debug("Failed to get current freq with " - "error 0x%lx, idx 0x%x\n", retval, *value); + "error 0x%llx, idx 0x%x\n", retval, *value); return (int)retval; } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 5175ae3cac44bff53f05398409815d104763d980..f0401064d7aa5da75b0b15187a88d58d4ee100f7 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -819,19 +819,21 @@ static struct freq_attr *hwp_cpufreq_attrs[] = { NULL, }; -static void intel_pstate_get_hwp_max(struct cpudata *cpu, int *phy_max, - int *current_max) +static void __intel_pstate_get_hwp_cap(struct cpudata *cpu) { u64 cap; rdmsrl_on_cpu(cpu->cpu, MSR_HWP_CAPABILITIES, &cap); WRITE_ONCE(cpu->hwp_cap_cached, cap); - if (global.no_turbo || global.turbo_disabled) - *current_max = HWP_GUARANTEED_PERF(cap); - else - *current_max = HWP_HIGHEST_PERF(cap); + cpu->pstate.max_pstate = HWP_GUARANTEED_PERF(cap); + cpu->pstate.turbo_pstate = HWP_HIGHEST_PERF(cap); +} - *phy_max = HWP_HIGHEST_PERF(cap); +static void intel_pstate_get_hwp_cap(struct cpudata *cpu) +{ + __intel_pstate_get_hwp_cap(cpu); + cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling; + cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling; } static void intel_pstate_hwp_set(unsigned int cpu) @@ -1195,12 +1197,13 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b, static void update_qos_request(enum freq_qos_req_type type) { - int max_state, turbo_max, freq, i, perf_pct; struct freq_qos_request *req; struct cpufreq_policy *policy; + int i; for_each_possible_cpu(i) { struct cpudata *cpu = all_cpu_data[i]; + unsigned int freq, perf_pct; policy = cpufreq_cpu_get(i); if (!policy) @@ -1213,9 +1216,7 @@ static void update_qos_request(enum freq_qos_req_type type) continue; if (hwp_active) - intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state); - else - turbo_max = cpu->pstate.turbo_pstate; + intel_pstate_get_hwp_cap(cpu); if (type == FREQ_QOS_MIN) { perf_pct = global.min_perf_pct; @@ -1224,8 +1225,7 @@ static void update_qos_request(enum freq_qos_req_type type) perf_pct = global.max_perf_pct; } - freq = DIV_ROUND_UP(turbo_max * perf_pct, 100); - freq *= cpu->pstate.scaling; + freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * perf_pct, 100); if (freq_qos_update_request(req, freq) < 0) pr_warn("Failed to update freq constraint: CPU%d\n", i); @@ -1715,21 +1715,17 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) { cpu->pstate.min_pstate = pstate_funcs.get_min(); cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(); - cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); cpu->pstate.scaling = pstate_funcs.get_scaling(); if (hwp_active && !hwp_mode_bdw) { - unsigned int phy_max, current_max; - - intel_pstate_get_hwp_max(cpu, &phy_max, ¤t_max); - cpu->pstate.turbo_freq = phy_max * cpu->pstate.scaling; - cpu->pstate.turbo_pstate = phy_max; - cpu->pstate.max_pstate = HWP_GUARANTEED_PERF(READ_ONCE(cpu->hwp_cap_cached)); + __intel_pstate_get_hwp_cap(cpu); } else { - cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling; cpu->pstate.max_pstate = pstate_funcs.get_max(); + cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); } + cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling; + cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling; if (pstate_funcs.get_aperf_mperf_shift) cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift(); @@ -2199,41 +2195,34 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu, unsigned int policy_min, unsigned int policy_max) { + int scaling = cpu->pstate.scaling; int32_t max_policy_perf, min_policy_perf; - int max_state, turbo_max; - int max_freq; /* - * HWP needs some special consideration, because on BDX the - * HWP_REQUEST uses abstract value to represent performance - * rather than pure ratios. + * HWP needs some special consideration, because HWP_REQUEST uses + * abstract values to represent performance rather than pure ratios. */ - if (hwp_active) { - intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state); - } else { - max_state = global.no_turbo || global.turbo_disabled ? - cpu->pstate.max_pstate : cpu->pstate.turbo_pstate; - turbo_max = cpu->pstate.turbo_pstate; - } - max_freq = max_state * cpu->pstate.scaling; + if (hwp_active) + intel_pstate_get_hwp_cap(cpu); - max_policy_perf = max_state * policy_max / max_freq; + max_policy_perf = policy_max / scaling; if (policy_max == policy_min) { min_policy_perf = max_policy_perf; } else { - min_policy_perf = max_state * policy_min / max_freq; + min_policy_perf = policy_min / scaling; min_policy_perf = clamp_t(int32_t, min_policy_perf, 0, max_policy_perf); } - pr_debug("cpu:%d max_state %d min_policy_perf:%d max_policy_perf:%d\n", - cpu->cpu, max_state, min_policy_perf, max_policy_perf); + pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n", + cpu->cpu, min_policy_perf, max_policy_perf); /* Normalize user input to [min_perf, max_perf] */ if (per_cpu_limits) { cpu->min_perf_ratio = min_policy_perf; cpu->max_perf_ratio = max_policy_perf; } else { + int turbo_max = cpu->pstate.turbo_pstate; int32_t global_min, global_max; /* Global limits are in percent of the maximum turbo P-state. */ @@ -2322,10 +2311,9 @@ static void intel_pstate_verify_cpu_policy(struct cpudata *cpu, update_turbo_state(); if (hwp_active) { - int max_state, turbo_max; - - intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state); - max_freq = max_state * cpu->pstate.scaling; + intel_pstate_get_hwp_cap(cpu); + max_freq = global.no_turbo || global.turbo_disabled ? + cpu->pstate.max_freq : cpu->pstate.turbo_freq; } else { max_freq = intel_pstate_get_max_freq(cpu); } @@ -2416,25 +2404,15 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy) cpu->max_perf_ratio = 0xFF; cpu->min_perf_ratio = 0; - policy->min = cpu->pstate.min_pstate * cpu->pstate.scaling; - policy->max = cpu->pstate.turbo_pstate * cpu->pstate.scaling; - /* cpuinfo and default policy values */ policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling; update_turbo_state(); global.turbo_disabled_mf = global.turbo_disabled; policy->cpuinfo.max_freq = global.turbo_disabled ? - cpu->pstate.max_pstate : cpu->pstate.turbo_pstate; - policy->cpuinfo.max_freq *= cpu->pstate.scaling; - - if (hwp_active) { - unsigned int max_freq; - - max_freq = global.turbo_disabled ? cpu->pstate.max_freq : cpu->pstate.turbo_freq; - if (max_freq < policy->cpuinfo.max_freq) - policy->cpuinfo.max_freq = max_freq; - } + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; intel_pstate_init_acpi_perf_limits(policy); @@ -2683,10 +2661,10 @@ static void intel_cpufreq_adjust_perf(unsigned int cpunum, static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy) { - int max_state, turbo_max, min_freq, max_freq, ret; struct freq_qos_request *req; struct cpudata *cpu; struct device *dev; + int ret, freq; dev = get_cpu_device(policy->cpu); if (!dev) @@ -2711,30 +2689,31 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy) if (hwp_active) { u64 value; - intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state); policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY_HWP; + + intel_pstate_get_hwp_cap(cpu); + rdmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, &value); WRITE_ONCE(cpu->hwp_req_cached, value); + cpu->epp_cached = intel_pstate_get_epp(cpu, value); } else { - turbo_max = cpu->pstate.turbo_pstate; policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY; } - min_freq = DIV_ROUND_UP(turbo_max * global.min_perf_pct, 100); - min_freq *= cpu->pstate.scaling; - max_freq = DIV_ROUND_UP(turbo_max * global.max_perf_pct, 100); - max_freq *= cpu->pstate.scaling; + freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.min_perf_pct, 100); ret = freq_qos_add_request(&policy->constraints, req, FREQ_QOS_MIN, - min_freq); + freq); if (ret < 0) { dev_err(dev, "Failed to add min-freq constraint (%d)\n", ret); goto free_req; } + freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.max_perf_pct, 100); + ret = freq_qos_add_request(&policy->constraints, req + 1, FREQ_QOS_MAX, - max_freq); + freq); if (ret < 0) { dev_err(dev, "Failed to add max-freq constraint (%d)\n", ret); goto remove_min_req; diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 69786e5bbf057dcea234805d6686e1dbf0a9ea89..ad7d4f272ddcb525b8e7abebd8dda1a1bcf2aa39 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -91,7 +91,7 @@ static DEFINE_MUTEX(set_freq_lock); /* Use 800MHz when entering sleep mode */ #define SLEEP_FREQ (800 * 1000) -/* Tracks if cpu freqency can be updated anymore */ +/* Tracks if CPU frequency can be updated anymore */ static bool no_cpufreq_access; /* @@ -190,7 +190,7 @@ static u32 clkdiv_val[5][11] = { /* * This function set DRAM refresh counter - * accoriding to operating frequency of DRAM + * according to operating frequency of DRAM * ch: DMC port number 0 or 1 * freq: Operating frequency of DRAM(KHz) */ @@ -320,7 +320,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) /* * 3. DMC1 refresh count for 133Mhz if (index == L4) is - * true refresh counter is already programed in upper + * true refresh counter is already programmed in upper * code. 0x287@83Mhz */ if (!bus_speed_changing) @@ -378,7 +378,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) /* * 6. Turn on APLL * 6-1. Set PMS values - * 6-2. Wait untile the PLL is locked + * 6-2. Wait until the PLL is locked */ if (index == L0) writel_relaxed(APLL_VAL_1000, S5P_APLL_CON); @@ -390,7 +390,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) } while (!(reg & (0x1 << 29))); /* - * 7. Change souce clock from SCLKMPLL(667Mhz) + * 7. Change source clock from SCLKMPLL(667Mhz) * to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX * (667/4=166)->(200/4=50)Mhz */ @@ -439,8 +439,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) } /* - * L4 level need to change memory bus speed, hence onedram clock divier - * and memory refresh parameter should be changed + * L4 level needs to change memory bus speed, hence ONEDRAM clock + * divider and memory refresh parameter should be changed */ if (bus_speed_changing) { reg = readl_relaxed(S5P_CLK_DIV6); diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 5bd03b59887fb41416e2a343f9314e0c62c79a2e..c8a4364ad3c2637027b9f96c08f0feb3f5bc6d9e 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -2,7 +2,7 @@ /* * System Control and Power Interface (SCMI) based CPUFreq Interface driver * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. * Sudeep Holla <sudeep.holla@arm.com> */ @@ -25,17 +25,17 @@ struct scmi_data { struct device *cpu_dev; }; -static const struct scmi_handle *handle; +static struct scmi_protocol_handle *ph; +static const struct scmi_perf_proto_ops *perf_ops; static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); - const struct scmi_perf_ops *perf_ops = handle->perf_ops; struct scmi_data *priv = policy->driver_data; unsigned long rate; int ret; - ret = perf_ops->freq_get(handle, priv->domain_id, &rate, false); + ret = perf_ops->freq_get(ph, priv->domain_id, &rate, false); if (ret) return 0; return rate / 1000; @@ -50,19 +50,17 @@ static int scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { struct scmi_data *priv = policy->driver_data; - const struct scmi_perf_ops *perf_ops = handle->perf_ops; u64 freq = policy->freq_table[index].frequency; - return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false); + return perf_ops->freq_set(ph, priv->domain_id, freq * 1000, false); } static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { struct scmi_data *priv = policy->driver_data; - const struct scmi_perf_ops *perf_ops = handle->perf_ops; - if (!perf_ops->freq_set(handle, priv->domain_id, + if (!perf_ops->freq_set(ph, priv->domain_id, target_freq * 1000, true)) return target_freq; @@ -75,7 +73,7 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) int cpu, domain, tdomain; struct device *tcpu_dev; - domain = handle->perf_ops->device_domain_id(cpu_dev); + domain = perf_ops->device_domain_id(cpu_dev); if (domain < 0) return domain; @@ -87,7 +85,7 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) if (!tcpu_dev) continue; - tdomain = handle->perf_ops->device_domain_id(tcpu_dev); + tdomain = perf_ops->device_domain_id(tcpu_dev); if (tdomain == domain) cpumask_set_cpu(cpu, cpumask); } @@ -102,13 +100,13 @@ scmi_get_cpu_power(unsigned long *power, unsigned long *KHz, unsigned long Hz; int ret, domain; - domain = handle->perf_ops->device_domain_id(cpu_dev); + domain = perf_ops->device_domain_id(cpu_dev); if (domain < 0) return domain; /* Get the power cost of the performance domain. */ Hz = *KHz * 1000; - ret = handle->perf_ops->est_power_get(handle, domain, &Hz, power); + ret = perf_ops->est_power_get(ph, domain, &Hz, power); if (ret) return ret; @@ -126,6 +124,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) struct scmi_data *priv; struct cpufreq_frequency_table *freq_table; struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power); + cpumask_var_t opp_shared_cpus; bool power_scale_mw; cpu_dev = get_cpu_device(policy->cpu); @@ -134,30 +133,64 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) return -ENODEV; } - ret = handle->perf_ops->device_opps_add(handle, cpu_dev); - if (ret) { - dev_warn(cpu_dev, "failed to add opps to the device\n"); - return ret; - } + if (!zalloc_cpumask_var(&opp_shared_cpus, GFP_KERNEL)) + ret = -ENOMEM; + /* Obtain CPUs that share SCMI performance controls */ ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus); if (ret) { dev_warn(cpu_dev, "failed to get sharing cpumask\n"); - return ret; + goto out_free_cpumask; } - ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); - if (ret) { - dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", - __func__, ret); - return ret; + /* + * Obtain CPUs that share performance levels. + * The OPP 'sharing cpus' info may come from DT through an empty opp + * table and opp-shared. + */ + ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, opp_shared_cpus); + if (ret || !cpumask_weight(opp_shared_cpus)) { + /* + * Either opp-table is not set or no opp-shared was found. + * Use the CPU mask from SCMI to designate CPUs sharing an OPP + * table. + */ + cpumask_copy(opp_shared_cpus, policy->cpus); } + /* + * A previous CPU may have marked OPPs as shared for a few CPUs, based on + * what OPP core provided. If the current CPU is part of those few, then + * there is no need to add OPPs again. + */ nr_opp = dev_pm_opp_get_opp_count(cpu_dev); if (nr_opp <= 0) { - dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); - ret = -EPROBE_DEFER; - goto out_free_opp; + ret = perf_ops->device_opps_add(ph, cpu_dev); + if (ret) { + dev_warn(cpu_dev, "failed to add opps to the device\n"); + goto out_free_cpumask; + } + + nr_opp = dev_pm_opp_get_opp_count(cpu_dev); + if (nr_opp <= 0) { + dev_err(cpu_dev, "%s: No OPPs for this device: %d\n", + __func__, ret); + + ret = -ENODEV; + goto out_free_opp; + } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, opp_shared_cpus); + if (ret) { + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", + __func__, ret); + + goto out_free_opp; + } + + power_scale_mw = perf_ops->power_scale_mw_get(ph); + em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, + opp_shared_cpus, power_scale_mw); } priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -173,7 +206,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) } priv->cpu_dev = cpu_dev; - priv->domain_id = handle->perf_ops->device_domain_id(cpu_dev); + priv->domain_id = perf_ops->device_domain_id(cpu_dev); policy->driver_data = priv; policy->freq_table = freq_table; @@ -181,26 +214,27 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) /* SCMI allows DVFS request for any domain from any CPU */ policy->dvfs_possible_from_any_cpu = true; - latency = handle->perf_ops->transition_latency_get(handle, cpu_dev); + latency = perf_ops->transition_latency_get(ph, cpu_dev); if (!latency) latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = latency; policy->fast_switch_possible = - handle->perf_ops->fast_switch_possible(handle, cpu_dev); - - power_scale_mw = handle->perf_ops->power_scale_mw_get(handle); - em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus, - power_scale_mw); + perf_ops->fast_switch_possible(ph, cpu_dev); + free_cpumask_var(opp_shared_cpus); return 0; out_free_priv: kfree(priv); + out_free_opp: dev_pm_opp_remove_all_dynamic(cpu_dev); +out_free_cpumask: + free_cpumask_var(opp_shared_cpus); + return ret; } @@ -233,12 +267,17 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev) { int ret; struct device *dev = &sdev->dev; + const struct scmi_handle *handle; handle = sdev->handle; - if (!handle || !handle->perf_ops) + if (!handle) return -ENODEV; + perf_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PERF, &ph); + if (IS_ERR(perf_ops)) + return PTR_ERR(perf_ops); + #ifdef CONFIG_COMMON_CLK /* dummy clock provider as needed by OPP if clocks property is used */ if (of_find_property(dev->of_node, "#clock-cells", NULL)) diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 0844fadc4be85b6f1ca5655d0b87b94e9dad33e6..334f83e56120c0022311c9f3f11ecaad5d0e67d7 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -107,7 +107,7 @@ config ARM_TEGRA_CPUIDLE config ARM_QCOM_SPM_CPUIDLE bool "CPU Idle Driver for Qualcomm Subsystem Power Manager (SPM)" - depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64 + depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64 && MMU select ARM_CPU_SUSPEND select CPU_IDLE_MULTIPLE_DRIVERS select DT_IDLE_STATES diff --git a/drivers/cpuidle/cpuidle-tegra.c b/drivers/cpuidle/cpuidle-tegra.c index 191966dc8d023b603c1ef7757e70f08a620b53c0..508bd9f2379294a58c91ba778058268988957cc1 100644 --- a/drivers/cpuidle/cpuidle-tegra.c +++ b/drivers/cpuidle/cpuidle-tegra.c @@ -48,11 +48,6 @@ enum tegra_state { static atomic_t tegra_idle_barrier; static atomic_t tegra_abort_flag; -static inline bool tegra_cpuidle_using_firmware(void) -{ - return firmware_ops->prepare_idle && firmware_ops->do_idle; -} - static void tegra_cpuidle_report_cpus_state(void) { unsigned long cpu, lcpu, csr; @@ -135,13 +130,9 @@ static int tegra_cpuidle_c7_enter(void) { int err; - if (tegra_cpuidle_using_firmware()) { - err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); - if (err) - return err; - - return call_firmware_op(do_idle, 0); - } + err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); + if (err && err != -ENOSYS) + return err; return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); } @@ -356,9 +347,7 @@ static int tegra_cpuidle_probe(struct platform_device *pdev) * is disabled. */ if (!IS_ENABLED(CONFIG_PM_SLEEP)) { - if (!tegra_cpuidle_using_firmware()) - tegra_cpuidle_disable_state(TEGRA_C7); - + tegra_cpuidle_disable_state(TEGRA_C7); tegra_cpuidle_disable_state(TEGRA_CC6); } diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 4070e573bf43a49ee638085448d46e705894e74d..f70aa17e2a8e0e9e9576252f8a33280c3d601115 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -181,9 +181,13 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv) */ if (s->target_residency > 0) s->target_residency_ns = s->target_residency * NSEC_PER_USEC; + else if (s->target_residency_ns < 0) + s->target_residency_ns = 0; if (s->exit_latency > 0) s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC; + else if (s->exit_latency_ns < 0) + s->exit_latency_ns = 0; } } diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index b0a7ad566081a2f3d9b51f3a3d52ae9263064b33..c3aa8d6ccee338870da3e514f36959bb295a160d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -271,7 +271,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, u64 predicted_ns; u64 interactivity_req; unsigned long nr_iowaiters; - ktime_t delta_next; + ktime_t delta, delta_tick; int i, idx; if (data->needs_update) { @@ -280,7 +280,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } /* determine the expected residency time, round up */ - data->next_timer_ns = tick_nohz_get_sleep_length(&delta_next); + delta = tick_nohz_get_sleep_length(&delta_tick); + if (unlikely(delta < 0)) { + delta = 0; + delta_tick = 0; + } + data->next_timer_ns = delta; nr_iowaiters = nr_iowait_cpu(dev->cpu); data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters); @@ -318,7 +323,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * state selection. */ if (predicted_ns < TICK_NSEC) - predicted_ns = delta_next; + predicted_ns = data->next_timer_ns; } else { /* * Use the performance multiplier and the user-configurable @@ -377,7 +382,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * stuck in the shallow one for too long. */ if (drv->states[idx].target_residency_ns < TICK_NSEC && - s->target_residency_ns <= delta_next) + s->target_residency_ns <= delta_tick) idx = i; return idx; @@ -399,7 +404,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, predicted_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) { *stop_tick = false; - if (idx > 0 && drv->states[idx].target_residency_ns > delta_next) { + if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) { /* * The tick is not going to be stopped and the target * residency of the state to be returned is not within @@ -411,7 +416,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, continue; idx = i; - if (drv->states[i].target_residency_ns <= delta_next) + if (drv->states[i].target_residency_ns <= delta_tick) break; } } diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c index 6deaaf5f05b5765598115132492edc4f654df9da..ac4bb27d69b0ed9d2cd7f25d32590f3b7d5c781c 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -100,8 +100,8 @@ struct teo_idle_state { * @intervals: Saved idle duration values. */ struct teo_cpu { - u64 time_span_ns; - u64 sleep_length_ns; + s64 time_span_ns; + s64 sleep_length_ns; struct teo_idle_state states[CPUIDLE_STATE_MAX]; int interval_idx; u64 intervals[INTERVALS]; @@ -117,7 +117,8 @@ static DEFINE_PER_CPU(struct teo_cpu, teo_cpus); static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); - int i, idx_hit = -1, idx_timer = -1; + int i, idx_hit = 0, idx_timer = 0; + unsigned int hits, misses; u64 measured_ns; if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { @@ -174,25 +175,22 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * also increase the "early hits" metric for the state that actually * matches the measured idle duration. */ - if (idx_timer >= 0) { - unsigned int hits = cpu_data->states[idx_timer].hits; - unsigned int misses = cpu_data->states[idx_timer].misses; - - hits -= hits >> DECAY_SHIFT; - misses -= misses >> DECAY_SHIFT; - - if (idx_timer > idx_hit) { - misses += PULSE; - if (idx_hit >= 0) - cpu_data->states[idx_hit].early_hits += PULSE; - } else { - hits += PULSE; - } + hits = cpu_data->states[idx_timer].hits; + hits -= hits >> DECAY_SHIFT; + + misses = cpu_data->states[idx_timer].misses; + misses -= misses >> DECAY_SHIFT; - cpu_data->states[idx_timer].misses = misses; - cpu_data->states[idx_timer].hits = hits; + if (idx_timer == idx_hit) { + hits += PULSE; + } else { + misses += PULSE; + cpu_data->states[idx_hit].early_hits += PULSE; } + cpu_data->states[idx_timer].misses = misses; + cpu_data->states[idx_timer].hits = hits; + /* * Save idle duration values corresponding to non-timer wakeups for * pattern detection. @@ -216,7 +214,7 @@ static bool teo_time_ok(u64 interval_ns) */ static int teo_find_shallower_state(struct cpuidle_driver *drv, struct cpuidle_device *dev, int state_idx, - u64 duration_ns) + s64 duration_ns) { int i; @@ -242,10 +240,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); s64 latency_req = cpuidle_governor_latency_req(dev->cpu); - u64 duration_ns; + int max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i; unsigned int hits, misses, early_hits; - int max_early_idx, prev_max_early_idx, constraint_idx, idx, i; ktime_t delta_tick; + s64 duration_ns; if (dev->last_state_idx >= 0) { teo_update(drv, dev); @@ -264,6 +262,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, prev_max_early_idx = -1; constraint_idx = drv->state_count; idx = -1; + idx0 = idx; for (i = 0; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; @@ -324,6 +323,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, idx = i; /* first enabled state */ hits = cpu_data->states[i].hits; misses = cpu_data->states[i].misses; + idx0 = i; } if (s->target_residency_ns > duration_ns) @@ -376,11 +376,16 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, if (idx < 0) { idx = 0; /* No states enabled. Must use 0. */ - } else if (idx > 0) { + } else if (idx > idx0) { unsigned int count = 0; u64 sum = 0; /* + * The target residencies of at least two different enabled idle + * states are less than or equal to the current expected idle + * duration. Try to refine the selection using the most recent + * measured idle duration values. + * * Count and sum the most recent idle duration values less than * the current expected idle duration value. */ @@ -428,7 +433,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * till the closest timer including the tick, try to correct * that. */ - if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) + if (idx > idx0 && + drv->states[idx].target_residency_ns > delta_tick) idx = teo_find_shallower_state(drv, dev, idx, delta_tick); } diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig index 856fb20456566ab8dc1fbe78b0727c6c6693fd17..b8e75210a0e3150900f2eeed78756f5c282b40b4 100644 --- a/drivers/crypto/allwinner/Kconfig +++ b/drivers/crypto/allwinner/Kconfig @@ -71,10 +71,10 @@ config CRYPTO_DEV_SUN8I_CE_DEBUG config CRYPTO_DEV_SUN8I_CE_HASH bool "Enable support for hash on sun8i-ce" depends on CRYPTO_DEV_SUN8I_CE - select MD5 - select SHA1 - select SHA256 - select SHA512 + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_SHA256 + select CRYPTO_SHA512 help Say y to enable support for hash algorithms. @@ -132,8 +132,8 @@ config CRYPTO_DEV_SUN8I_SS_PRNG config CRYPTO_DEV_SUN8I_SS_HASH bool "Enable support for hash on sun8i-ss" depends on CRYPTO_DEV_SUN8I_SS - select MD5 - select SHA1 - select SHA256 + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_SHA256 help Say y to enable support for hash algorithms. diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-cipher.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-cipher.c index c2e6f5ed1d79744a7bc0b0e4179fdf81c9cd8ec7..dec79fa3ebafb83951901b07044ee1f994639c93 100644 --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-cipher.c @@ -561,7 +561,7 @@ int sun4i_ss_cipher_init(struct crypto_tfm *tfm) sizeof(struct sun4i_cipher_req_ctx) + crypto_skcipher_reqsize(op->fallback_tfm)); - err = pm_runtime_get_sync(op->ss->dev); + err = pm_runtime_resume_and_get(op->ss->dev); if (err < 0) goto error_pm; diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c index 709905ec46806d3303bcd79faa7878bc471c3dd4..44b8fc4b786dc8c724373c415d3e8ecc409e1753 100644 --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c @@ -288,8 +288,7 @@ static int sun4i_ss_pm_suspend(struct device *dev) { struct sun4i_ss_ctx *ss = dev_get_drvdata(dev); - if (ss->reset) - reset_control_assert(ss->reset); + reset_control_assert(ss->reset); clk_disable_unprepare(ss->ssclk); clk_disable_unprepare(ss->busclk); @@ -314,12 +313,10 @@ static int sun4i_ss_pm_resume(struct device *dev) goto err_enable; } - if (ss->reset) { - err = reset_control_deassert(ss->reset); - if (err) { - dev_err(ss->dev, "Cannot deassert reset control\n"); - goto err_enable; - } + err = reset_control_deassert(ss->reset); + if (err) { + dev_err(ss->dev, "Cannot deassert reset control\n"); + goto err_enable; } return err; @@ -401,12 +398,10 @@ static int sun4i_ss_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock ahb_ss acquired\n"); ss->reset = devm_reset_control_get_optional(&pdev->dev, "ahb"); - if (IS_ERR(ss->reset)) { - if (PTR_ERR(ss->reset) == -EPROBE_DEFER) - return PTR_ERR(ss->reset); + if (IS_ERR(ss->reset)) + return PTR_ERR(ss->reset); + if (!ss->reset) dev_info(&pdev->dev, "no reset control found\n"); - ss->reset = NULL; - } /* * Check that clock have the correct rates given in the datasheet @@ -459,7 +454,7 @@ static int sun4i_ss_probe(struct platform_device *pdev) * this info could be useful */ - err = pm_runtime_get_sync(ss->dev); + err = pm_runtime_resume_and_get(ss->dev); if (err < 0) goto error_pm; diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-hash.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-hash.c index c1b4585e9bbc7d459bfb6c47d66adbf145735f9a..d28292762b3247a6c999b6f382d28a25d6c7fabe 100644 --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-hash.c +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-hash.c @@ -27,7 +27,7 @@ int sun4i_hash_crainit(struct crypto_tfm *tfm) algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash); op->ss = algt->ss; - err = pm_runtime_get_sync(op->ss->dev); + err = pm_runtime_resume_and_get(op->ss->dev); if (err < 0) return err; diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c index 443160a114bb031a0d53e78106d82eb01c0e51a5..491fcb7b81b40b6f989bb27d9414804d81bd23cc 100644 --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c @@ -29,7 +29,7 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng); ss = algt->ss; - err = pm_runtime_get_sync(ss->dev); + err = pm_runtime_resume_and_get(ss->dev); if (err < 0) return err; diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 33707a2e55ff0c2dd0e2f16c1487c708038db867..54ae8d16e4931ab8aea18f6a96ccccc38c61df7c 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -240,11 +240,14 @@ static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req theend_sgs: if (areq->src == areq->dst) { - dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL); + dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src), + DMA_BIDIRECTIONAL); } else { if (nr_sgs > 0) - dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_TO_DEVICE); - dma_unmap_sg(ce->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE); + dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src), + DMA_TO_DEVICE); + dma_unmap_sg(ce->dev, areq->dst, sg_nents(areq->dst), + DMA_FROM_DEVICE); } theend_iv: diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index 158422ff5695ce66a625ba0427d0cb386ba63684..00194d1d9ae69b153400505ef4b45474caa8ef5e 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -932,7 +932,7 @@ static int sun8i_ce_probe(struct platform_device *pdev) if (err) goto error_alg; - err = pm_runtime_get_sync(ce->dev); + err = pm_runtime_resume_and_get(ce->dev); if (err < 0) goto error_alg; diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 2f09a37306e28412c81c3f4a7576526c5312af10..88194718a806ce8452dcb1ea06661dd2c9581c17 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -405,7 +405,8 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(areq->base.tfm)); dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE); - dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_TO_DEVICE); + dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src), + DMA_TO_DEVICE); dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c index cfde9ee4356b138260ae51f110a991febb3d4b30..cd1baee424a18a6fd56187f64a399d631e2db3d9 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c @@ -99,6 +99,7 @@ int sun8i_ce_prng_generate(struct crypto_rng *tfm, const u8 *src, dma_iv = dma_map_single(ce->dev, ctx->seed, ctx->slen, DMA_TO_DEVICE); if (dma_mapping_error(ce->dev, dma_iv)) { dev_err(ce->dev, "Cannot DMA MAP IV\n"); + err = -EFAULT; goto err_iv; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c index ed2a69f82e1c189ee382b0692f8e4d3d686e0f7a..9ef1c85c4aaa5590fe9c521db24ad1d4121d2f8f 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c @@ -232,10 +232,13 @@ sgd_next: theend_sgs: if (areq->src == areq->dst) { - dma_unmap_sg(ss->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL); + dma_unmap_sg(ss->dev, areq->src, sg_nents(areq->src), + DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(ss->dev, areq->src, nr_sgs, DMA_TO_DEVICE); - dma_unmap_sg(ss->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE); + dma_unmap_sg(ss->dev, areq->src, sg_nents(areq->src), + DMA_TO_DEVICE); + dma_unmap_sg(ss->dev, areq->dst, sg_nents(areq->dst), + DMA_FROM_DEVICE); } theend_iv: @@ -351,7 +354,7 @@ int sun8i_ss_cipher_init(struct crypto_tfm *tfm) op->enginectx.op.prepare_request = NULL; op->enginectx.op.unprepare_request = NULL; - err = pm_runtime_get_sync(op->ss->dev); + err = pm_runtime_resume_and_get(op->ss->dev); if (err < 0) { dev_err(op->ss->dev, "pm error %d\n", err); goto error_pm; diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c index e0ddc684798dc50e67379943c18cbe3f0179f932..80e89066dbd1ae60f3a646a8a69481267b1d5074 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c @@ -753,7 +753,7 @@ static int sun8i_ss_probe(struct platform_device *pdev) if (err) goto error_alg; - err = pm_runtime_get_sync(ss->dev); + err = pm_runtime_resume_and_get(ss->dev); if (err < 0) goto error_alg; diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c index 11cbcbc83a7b67b7b94d8be58017ba0911f9243a..3c073eb3db038a148b304c73bcae0c1af108f398 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c @@ -348,8 +348,10 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq) bf = (__le32 *)pad; result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA); - if (!result) + if (!result) { + kfree(pad); return -ENOMEM; + } for (i = 0; i < MAX_SG; i++) { rctx->t_dst[i].addr = 0; @@ -432,14 +434,14 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq) err = sun8i_ss_run_hash_task(ss, rctx, crypto_tfm_alg_name(areq->base.tfm)); dma_unmap_single(ss->dev, addr_pad, j * 4, DMA_TO_DEVICE); - dma_unmap_sg(ss->dev, areq->src, nr_sgs, DMA_TO_DEVICE); + dma_unmap_sg(ss->dev, areq->src, sg_nents(areq->src), + DMA_TO_DEVICE); dma_unmap_single(ss->dev, addr_res, digestsize, DMA_FROM_DEVICE); - kfree(pad); - memcpy(areq->result, result, algt->alg.hash.halg.digestsize); - kfree(result); theend: + kfree(pad); + kfree(result); crypto_finalize_hash_request(engine, breq, err); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c index 08a1473b214578543c5531e29b040680244c1c7d..3191527928e4163df5c0017029076413977c8322 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c @@ -103,7 +103,8 @@ int sun8i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, dma_iv = dma_map_single(ss->dev, ctx->seed, ctx->slen, DMA_TO_DEVICE); if (dma_mapping_error(ss->dev, dma_iv)) { dev_err(ss->dev, "Cannot DMA MAP IV\n"); - return -EFAULT; + err = -EFAULT; + goto err_free; } dma_dst = dma_map_single(ss->dev, d, todo, DMA_FROM_DEVICE); @@ -167,6 +168,7 @@ err_iv: memcpy(ctx->seed, d + dlen, ctx->slen); } memzero_explicit(d, todo); +err_free: kfree(d); return err; diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index a3fa849b139ae6af29d6353e5706eadf2e3c995d..ded7322427329596b98c2bba1483106e13eac7dd 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/** +/* * AMCC SoC PPC4xx Crypto Driver * * Copyright (c) 2008 Applied Micro Circuits Corporation. @@ -115,7 +115,7 @@ int crypto4xx_decrypt_iv_block(struct skcipher_request *req) return crypto4xx_crypt(req, AES_IV_SIZE, true, true); } -/** +/* * AES Functions */ static int crypto4xx_setkey_aes(struct crypto_skcipher *cipher, @@ -374,7 +374,7 @@ static int crypto4xx_aead_setup_fallback(struct crypto4xx_ctx *ctx, return crypto_aead_setkey(ctx->sw_cipher.aead, key, keylen); } -/** +/* * AES-CCM Functions */ @@ -489,7 +489,7 @@ int crypto4xx_setauthsize_aead(struct crypto_aead *cipher, return crypto_aead_setauthsize(ctx->sw_cipher.aead, authsize); } -/** +/* * AES-GCM Functions */ @@ -617,7 +617,7 @@ int crypto4xx_decrypt_aes_gcm(struct aead_request *req) return crypto4xx_crypt_aes_gcm(req, true); } -/** +/* * HASH SHA1 Functions */ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm, @@ -711,7 +711,7 @@ int crypto4xx_hash_digest(struct ahash_request *req) ctx->sa_len, 0, NULL); } -/** +/* * SHA1 Algorithm */ int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 8d1b918a05335daed33140973f5b67b4a65ecb60..8278d98074e9ada52f58748a1764d89df73acb6f 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/** +/* * AMCC SoC PPC4xx Crypto Driver * * Copyright (c) 2008 Applied Micro Circuits Corporation. @@ -44,7 +44,7 @@ #define PPC4XX_SEC_VERSION_STR "0.5" -/** +/* * PPC4xx Crypto Engine Initialization Routine */ static void crypto4xx_hw_init(struct crypto4xx_device *dev) @@ -159,7 +159,7 @@ void crypto4xx_free_sa(struct crypto4xx_ctx *ctx) ctx->sa_len = 0; } -/** +/* * alloc memory for the gather ring * no need to alloc buf for the ring * gdr_tail, gdr_head and gdr_count are initialized by this function @@ -268,7 +268,7 @@ static u32 crypto4xx_put_pd_to_pdr(struct crypto4xx_device *dev, u32 idx) return tail; } -/** +/* * alloc memory for the gather ring * no need to alloc buf for the ring * gdr_tail, gdr_head and gdr_count are initialized by this function @@ -346,7 +346,7 @@ static inline struct ce_gd *crypto4xx_get_gdp(struct crypto4xx_device *dev, return &dev->gdr[idx]; } -/** +/* * alloc memory for the scatter ring * need to alloc buf for the ring * sdr_tail, sdr_head and sdr_count are initialized by this function @@ -930,7 +930,7 @@ int crypto4xx_build_pd(struct crypto_async_request *req, return is_busy ? -EBUSY : -EINPROGRESS; } -/** +/* * Algorithm Registration Functions */ static void crypto4xx_ctx_init(struct crypto4xx_alg *amcc_alg, @@ -1097,7 +1097,7 @@ static void crypto4xx_bh_tasklet_cb(unsigned long data) } while (head != tail); } -/** +/* * Top Half of isr. */ static inline irqreturn_t crypto4xx_interrupt_handler(int irq, void *data, @@ -1186,7 +1186,7 @@ static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed, return 0; } -/** +/* * Supported Crypto Algorithms */ static struct crypto4xx_alg_common crypto4xx_alg[] = { @@ -1369,7 +1369,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { } }, }; -/** +/* * Module Initialization Routine */ static int crypto4xx_probe(struct platform_device *ofdev) diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index a4e25b46cd0ab310b5b45020d872e0d8faf695ad..56c10668c0ab0ae514d4be59463ca2be6b0e8a79 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/** +/* * AMCC SoC PPC4xx Crypto Driver * * Copyright (c) 2008 Applied Micro Circuits Corporation. @@ -188,7 +188,7 @@ int crypto4xx_hash_final(struct ahash_request *req); int crypto4xx_hash_update(struct ahash_request *req); int crypto4xx_hash_init(struct ahash_request *req); -/** +/* * Note: Only use this function to copy items that is word aligned. */ static inline void crypto4xx_memcpy_swab32(u32 *dst, const void *buf, diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h index c4c0a1a7594156e7950f23d158b337775c788e41..1038061224da667d47a057df224e6c669c97e4c1 100644 --- a/drivers/crypto/amcc/crypto4xx_reg_def.h +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/** +/* * AMCC SoC PPC4xx Crypto Driver * * Copyright (c) 2008 Applied Micro Circuits Corporation. @@ -104,7 +104,7 @@ #define CRYPTO4XX_PRNG_LFSR_L 0x00070030 #define CRYPTO4XX_PRNG_LFSR_H 0x00070034 -/** +/* * Initialize CRYPTO ENGINE registers, and memory bases. */ #define PPC4XX_PDR_POLL 0x3ff @@ -123,7 +123,7 @@ #define PPC4XX_INT_TIMEOUT_CNT 0 #define PPC4XX_INT_TIMEOUT_CNT_REVB 0x3FF #define PPC4XX_INT_CFG 1 -/** +/* * all follow define are ad hoc */ #define PPC4XX_RING_RETRY 100 @@ -131,7 +131,7 @@ #define PPC4XX_SDR_SIZE PPC4XX_NUM_SD #define PPC4XX_GDR_SIZE PPC4XX_NUM_GD -/** +/* * Generic Security Association (SA) with all possible fields. These will * never likely used except for reference purpose. These structure format * can be not changed as the hardware expects them to be layout as defined. diff --git a/drivers/crypto/amcc/crypto4xx_sa.h b/drivers/crypto/amcc/crypto4xx_sa.h index fe756abfc19f91f398960a1d2ca74fa6f5a21e13..e98e4e7abbad8d9a21fbc05e871ae894e3f0c4f3 100644 --- a/drivers/crypto/amcc/crypto4xx_sa.h +++ b/drivers/crypto/amcc/crypto4xx_sa.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/** +/* * AMCC SoC PPC4xx Crypto Driver * * Copyright (c) 2008 Applied Micro Circuits Corporation. @@ -14,7 +14,7 @@ #define AES_IV_SIZE 16 -/** +/* * Contents of Dynamic Security Association (SA) with all possible fields */ union dynamic_sa_contents { @@ -122,7 +122,7 @@ union sa_command_0 { #define SA_AES_KEY_LEN_256 4 #define SA_REV2 1 -/** +/* * The follow defines bits sa_command_1 * In Basic hash mode this bit define simple hash or hmac. * In IPsec mode, this bit define muting control. @@ -172,7 +172,7 @@ struct dynamic_sa_ctl { union sa_command_1 sa_command_1; } __attribute__((packed)); -/** +/* * State Record for Security Association (SA) */ struct sa_state_record { @@ -184,7 +184,7 @@ struct sa_state_record { }; } __attribute__((packed)); -/** +/* * Security Association (SA) for AES128 * */ @@ -213,7 +213,7 @@ struct dynamic_sa_aes192 { #define SA_AES192_LEN (sizeof(struct dynamic_sa_aes192)/4) #define SA_AES192_CONTENTS 0x3e000062 -/** +/* * Security Association (SA) for AES256 */ struct dynamic_sa_aes256 { @@ -228,7 +228,7 @@ struct dynamic_sa_aes256 { #define SA_AES256_CONTENTS 0x3e000082 #define SA_AES_CONTENTS 0x3e000002 -/** +/* * Security Association (SA) for AES128 CCM */ struct dynamic_sa_aes128_ccm { @@ -242,7 +242,7 @@ struct dynamic_sa_aes128_ccm { #define SA_AES128_CCM_CONTENTS 0x3e000042 #define SA_AES_CCM_CONTENTS 0x3e000002 -/** +/* * Security Association (SA) for AES128_GCM */ struct dynamic_sa_aes128_gcm { @@ -258,7 +258,7 @@ struct dynamic_sa_aes128_gcm { #define SA_AES128_GCM_CONTENTS 0x3e000442 #define SA_AES_GCM_CONTENTS 0x3e000402 -/** +/* * Security Association (SA) for HASH160: HMAC-SHA1 */ struct dynamic_sa_hash160 { diff --git a/drivers/crypto/amcc/crypto4xx_trng.h b/drivers/crypto/amcc/crypto4xx_trng.h index 3af732f25c1c04a5af59f470d5a804c0346db776..7356716274cba030ff257588d16d285dd761250a 100644 --- a/drivers/crypto/amcc/crypto4xx_trng.h +++ b/drivers/crypto/amcc/crypto4xx_trng.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/** +/* * AMCC SoC PPC4xx Crypto Driver * * Copyright (c) 2008 Applied Micro Circuits Corporation. diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/amlogic/amlogic-gxl-cipher.c index 8b5e07316352c3df6ac52ea27bebd11c0897fe72..c6865cbd334b293bec18184dc128bc2863d7546f 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c +++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c @@ -236,10 +236,10 @@ static int meson_cipher(struct skcipher_request *areq) dma_unmap_single(mc->dev, phykeyiv, keyivlen, DMA_TO_DEVICE); if (areq->src == areq->dst) { - dma_unmap_sg(mc->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL); + dma_unmap_sg(mc->dev, areq->src, sg_nents(areq->src), DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(mc->dev, areq->src, nr_sgs, DMA_TO_DEVICE); - dma_unmap_sg(mc->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE); + dma_unmap_sg(mc->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE); + dma_unmap_sg(mc->dev, areq->dst, sg_nents(areq->dst), DMA_FROM_DEVICE); } if (areq->iv && ivsize > 0) { diff --git a/drivers/crypto/amlogic/amlogic-gxl-core.c b/drivers/crypto/amlogic/amlogic-gxl-core.c index 5bbeff433c8c09d03486e2f8956fa11789545ad8..6e7ae896717cd2a21600f4282fc27145c3e18da3 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-core.c +++ b/drivers/crypto/amlogic/amlogic-gxl-core.c @@ -217,9 +217,6 @@ static int meson_crypto_probe(struct platform_device *pdev) struct meson_dev *mc; int err, i; - if (!pdev->dev.of_node) - return -ENODEV; - mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); if (!mc) return -ENOMEM; diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 9bd8e5167be34bfc9ad67381f45853664a580c75..333fbefbbccbd94fda92eba0b6c5e666fd7e10ba 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -26,7 +26,7 @@ static struct atmel_ecc_driver_data driver_data; /** - * atmel_ecdh_ctx - transformation context + * struct atmel_ecdh_ctx - transformation context * @client : pointer to i2c client device * @fallback : used for unsupported curves or when user wants to use its own * private key. @@ -34,7 +34,6 @@ static struct atmel_ecc_driver_data driver_data; * of the user to not call set_secret() while * generate_public_key() or compute_shared_secret() are in flight. * @curve_id : elliptic curve id - * @n_sz : size in bytes of the n prime * @do_fallback: true when the device doesn't support the curve or when the user * wants to use its own private key. */ @@ -43,7 +42,6 @@ struct atmel_ecdh_ctx { struct crypto_kpp *fallback; const u8 *public_key; unsigned int curve_id; - size_t n_sz; bool do_fallback; }; @@ -51,7 +49,6 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, int status) { struct kpp_request *req = areq; - struct atmel_ecdh_ctx *ctx = work_data->ctx; struct atmel_i2c_cmd *cmd = &work_data->cmd; size_t copied, n_sz; @@ -59,7 +56,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, goto free_work_data; /* might want less than we've got */ - n_sz = min_t(size_t, ctx->n_sz, req->dst_len); + n_sz = min_t(size_t, ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len); /* copy the shared secret */ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz), @@ -73,14 +70,6 @@ free_work_data: kpp_request_complete(req, status); } -static unsigned int atmel_ecdh_supported_curve(unsigned int curve_id) -{ - if (curve_id == ECC_CURVE_NIST_P256) - return ATMEL_ECC_NIST_P256_N_SIZE; - - return 0; -} - /* * A random private key is generated and stored in the device. The device * returns the pair public key. @@ -104,8 +93,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, return -EINVAL; } - ctx->n_sz = atmel_ecdh_supported_curve(params.curve_id); - if (!ctx->n_sz || params.key_size) { + if (params.key_size) { /* fallback to ecdh software implementation */ ctx->do_fallback = true; return crypto_kpp_set_secret(ctx->fallback, buf, len); @@ -125,7 +113,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, goto free_cmd; ctx->do_fallback = false; - ctx->curve_id = params.curve_id; atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2); @@ -263,6 +250,7 @@ static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm) struct crypto_kpp *fallback; struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); + ctx->curve_id = ECC_CURVE_NIST_P256; ctx->client = atmel_ecc_i2c_client_alloc(); if (IS_ERR(ctx->client)) { pr_err("tfm - i2c_client binding failed\n"); @@ -306,7 +294,7 @@ static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm) return ATMEL_ECC_PUBKEY_SIZE; } -static struct kpp_alg atmel_ecdh = { +static struct kpp_alg atmel_ecdh_nist_p256 = { .set_secret = atmel_ecdh_set_secret, .generate_public_key = atmel_ecdh_generate_public_key, .compute_shared_secret = atmel_ecdh_compute_shared_secret, @@ -315,7 +303,7 @@ static struct kpp_alg atmel_ecdh = { .max_size = atmel_ecdh_max_size, .base = { .cra_flags = CRYPTO_ALG_NEED_FALLBACK, - .cra_name = "ecdh", + .cra_name = "ecdh-nist-p256", .cra_driver_name = "atmel-ecdh", .cra_priority = ATMEL_ECC_PRIORITY, .cra_module = THIS_MODULE, @@ -340,14 +328,14 @@ static int atmel_ecc_probe(struct i2c_client *client, &driver_data.i2c_client_list); spin_unlock(&driver_data.i2c_list_lock); - ret = crypto_register_kpp(&atmel_ecdh); + ret = crypto_register_kpp(&atmel_ecdh_nist_p256); if (ret) { spin_lock(&driver_data.i2c_list_lock); list_del(&i2c_priv->i2c_client_list_node); spin_unlock(&driver_data.i2c_list_lock); dev_err(&client->dev, "%s alg registration failed\n", - atmel_ecdh.base.cra_driver_name); + atmel_ecdh_nist_p256.base.cra_driver_name); } else { dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n"); } @@ -365,7 +353,7 @@ static int atmel_ecc_remove(struct i2c_client *client) return -EBUSY; } - crypto_unregister_kpp(&atmel_ecdh); + crypto_unregister_kpp(&atmel_ecdh_nist_p256); spin_lock(&driver_data.i2c_list_lock); list_del(&i2c_priv->i2c_client_list_node); diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c index e8e8281e027d9c9d6161325b549aed5eb4d83883..6fd3e969211d7aa7d14fc14fb94b18610d093b62 100644 --- a/drivers/crypto/atmel-i2c.c +++ b/drivers/crypto/atmel-i2c.c @@ -339,7 +339,7 @@ int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) } if (bus_clk_rate > 1000000L) { - dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", + dev_err(dev, "%u exceeds maximum supported clock frequency (1MHz)\n", bus_clk_rate); return -EINVAL; } diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 352d80cb5ae95e755519203460cacf69eeb326f3..1b13f601fd959c372c6913d63bb65734cb4da8cb 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -434,7 +434,7 @@ static int atmel_sha_init(struct ahash_request *req) ctx->flags = 0; - dev_dbg(dd->dev, "init: digest size: %d\n", + dev_dbg(dd->dev, "init: digest size: %u\n", crypto_ahash_digestsize(tfm)); switch (crypto_ahash_digestsize(tfm)) { @@ -1102,7 +1102,7 @@ static int atmel_sha_start(struct atmel_sha_dev *dd) struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); int err; - dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", + dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %u\n", ctx->op, req->nbytes); err = atmel_sha_hw_init(dd); diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 4d63cb13a54f975fc13a652927fce3583ccedcc4..6f01c51e3c37644d903ba9b2b0a94336fa92cb77 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -1217,7 +1217,6 @@ static int atmel_tdes_probe(struct platform_device *pdev) tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res); if (IS_ERR(tdes_dd->io_base)) { - dev_err(dev, "can't ioremap\n"); err = PTR_ERR(tdes_dd->io_base); goto err_tasklet_kill; } diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 851b149f71701d48658138cc23ccbc533b1f5417..053315e260c2267b4a47cf1c15d732fcbec6db30 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -1019,6 +1019,7 @@ static void handle_ahash_resp(struct iproc_reqctx_s *rctx) * a SPU response message for an AEAD request. Includes buffers to catch SPU * message headers and the response data. * @mssg: mailbox message containing the receive sg + * @req: Crypto API request * @rctx: crypto request context * @rx_frag_num: number of scatterlist elements required to hold the * SPU response message @@ -2952,9 +2953,9 @@ static int aead_gcm_esp_setkey(struct crypto_aead *cipher, /** * rfc4543_gcm_esp_setkey() - setkey operation for RFC4543 variant of GCM/GMAC. - * cipher: AEAD structure - * key: Key followed by 4 bytes of salt - * keylen: Length of key plus salt, in bytes + * @cipher: AEAD structure + * @key: Key followed by 4 bytes of salt + * @keylen: Length of key plus salt, in bytes * * Extracts salt from key and stores it to be prepended to IV on each request. * Digest is always 16 bytes diff --git a/drivers/crypto/bcm/spu.c b/drivers/crypto/bcm/spu.c index 007abf92cc05be6541ac11c26676abbb72f7a6ac..6283e8c6d51d3ea4ffb75fd19427a44edf76a145 100644 --- a/drivers/crypto/bcm/spu.c +++ b/drivers/crypto/bcm/spu.c @@ -457,7 +457,7 @@ u16 spum_hash_pad_len(enum hash_alg hash_alg, enum hash_mode hash_mode, * @cipher_mode: Algo type * @data_size: Length of plaintext (bytes) * - * @Return: Length of padding, in bytes + * Return: Length of padding, in bytes */ u32 spum_gcm_ccm_pad_len(enum spu_cipher_mode cipher_mode, unsigned int data_size) @@ -510,10 +510,10 @@ u32 spum_assoc_resp_len(enum spu_cipher_mode cipher_mode, } /** - * spu_aead_ivlen() - Calculate the length of the AEAD IV to be included + * spum_aead_ivlen() - Calculate the length of the AEAD IV to be included * in a SPU request after the AAD and before the payload. * @cipher_mode: cipher mode - * @iv_ctr_len: initialization vector length in bytes + * @iv_len: initialization vector length in bytes * * In Linux ~4.2 and later, the assoc_data sg includes the IV. So no need * to include the IV as a separate field in the SPU request msg. @@ -543,9 +543,9 @@ enum hash_type spum_hash_type(u32 src_sent) /** * spum_digest_size() - Determine the size of a hash digest to expect the SPU to * return. - * alg_digest_size: Number of bytes in the final digest for the given algo - * alg: The hash algorithm - * htype: Type of hash operation (init, update, full, etc) + * @alg_digest_size: Number of bytes in the final digest for the given algo + * @alg: The hash algorithm + * @htype: Type of hash operation (init, update, full, etc) * * When doing incremental hashing for an algorithm with a truncated hash * (e.g., SHA224), the SPU returns the full digest so that it can be fed back as @@ -580,7 +580,7 @@ u32 spum_digest_size(u32 alg_digest_size, enum hash_alg alg, * @aead_parms: Parameters related to AEAD operation * @data_size: Length of data to be encrypted or authenticated. If AEAD, does * not include length of AAD. - + * * Return: the length of the SPU header in bytes. 0 if an error occurs. */ u32 spum_create_request(u8 *spu_hdr, @@ -911,7 +911,7 @@ u16 spum_cipher_req_init(u8 *spu_hdr, struct spu_cipher_parms *cipher_parms) * setkey() time in spu_cipher_req_init(). * @spu_hdr: Start of the request message header (MH field) * @spu_req_hdr_len: Length in bytes of the SPU request header - * @isInbound: 0 encrypt, 1 decrypt + * @is_inbound: 0 encrypt, 1 decrypt * @cipher_parms: Parameters describing cipher operation to be performed * @data_size: Length of the data in the BD field * diff --git a/drivers/crypto/bcm/spu2.c b/drivers/crypto/bcm/spu2.c index 2db35b5ccaa245f59fac09a39daccca394a65b8e..07989bb8c220a4909cd07bb513330ae58cd0c888 100644 --- a/drivers/crypto/bcm/spu2.c +++ b/drivers/crypto/bcm/spu2.c @@ -543,7 +543,8 @@ void spu2_dump_msg_hdr(u8 *buf, unsigned int buf_len) /** * spu2_fmd_init() - At setkey time, initialize the fixed meta data for * subsequent skcipher requests for this context. - * @spu2_cipher_type: Cipher algorithm + * @fmd: Start of FMD field to be written + * @spu2_type: Cipher algorithm * @spu2_mode: Cipher mode * @cipher_key_len: Length of cipher key, in bytes * @cipher_iv_len: Length of cipher initialization vector, in bytes @@ -598,7 +599,7 @@ static int spu2_fmd_init(struct SPU2_FMD *fmd, * SPU request packet. * @fmd: Start of FMD field to be written * @is_inbound: true if decrypting. false if encrypting. - * @authFirst: true if alg authenticates before encrypting + * @auth_first: true if alg authenticates before encrypting * @protocol: protocol selector * @cipher_type: cipher algorithm * @cipher_mode: cipher mode @@ -640,6 +641,7 @@ static void spu2_fmd_ctrl0_write(struct SPU2_FMD *fmd, * spu2_fmd_ctrl1_write() - Write ctrl1 field in fixed metadata (FMD) field of * SPU request packet. * @fmd: Start of FMD field to be written + * @is_inbound: true if decrypting. false if encrypting. * @assoc_size: Length of additional associated data, in bytes * @auth_key_len: Length of authentication key, in bytes * @cipher_key_len: Length of cipher key, in bytes @@ -793,7 +795,7 @@ u32 spu2_ctx_max_payload(enum spu_cipher_alg cipher_alg, } /** - * spu_payload_length() - Given a SPU2 message header, extract the payload + * spu2_payload_length() - Given a SPU2 message header, extract the payload * length. * @spu_hdr: Start of SPU message header (FMD) * @@ -812,10 +814,11 @@ u32 spu2_payload_length(u8 *spu_hdr) } /** - * spu_response_hdr_len() - Determine the expected length of a SPU response + * spu2_response_hdr_len() - Determine the expected length of a SPU response * header. * @auth_key_len: Length of authentication key, in bytes * @enc_key_len: Length of encryption key, in bytes + * @is_hash: Unused * * For SPU2, includes just FMD. OMD is never requested. * @@ -827,7 +830,7 @@ u16 spu2_response_hdr_len(u16 auth_key_len, u16 enc_key_len, bool is_hash) } /** - * spu_hash_pad_len() - Calculate the length of hash padding required to extend + * spu2_hash_pad_len() - Calculate the length of hash padding required to extend * data to a full block size. * @hash_alg: hash algorithm * @hash_mode: hash mode @@ -845,8 +848,10 @@ u16 spu2_hash_pad_len(enum hash_alg hash_alg, enum hash_mode hash_mode, } /** - * spu2_gcm_ccm_padlen() - Determine the length of GCM/CCM padding for either + * spu2_gcm_ccm_pad_len() - Determine the length of GCM/CCM padding for either * the AAD field or the data. + * @cipher_mode: Unused + * @data_size: Unused * * Return: 0. Unlike SPU-M, SPU2 hardware does any GCM/CCM padding required. */ @@ -857,7 +862,7 @@ u32 spu2_gcm_ccm_pad_len(enum spu_cipher_mode cipher_mode, } /** - * spu_assoc_resp_len() - Determine the size of the AAD2 buffer needed to catch + * spu2_assoc_resp_len() - Determine the size of the AAD2 buffer needed to catch * associated data in a SPU2 output packet. * @cipher_mode: cipher mode * @assoc_len: length of additional associated data, in bytes @@ -878,11 +883,11 @@ u32 spu2_assoc_resp_len(enum spu_cipher_mode cipher_mode, return resp_len; } -/* - * spu_aead_ivlen() - Calculate the length of the AEAD IV to be included +/** + * spu2_aead_ivlen() - Calculate the length of the AEAD IV to be included * in a SPU request after the AAD and before the payload. * @cipher_mode: cipher mode - * @iv_ctr_len: initialization vector length in bytes + * @iv_len: initialization vector length in bytes * * For SPU2, AEAD IV is included in OMD and does not need to be repeated * prior to the payload. @@ -909,9 +914,9 @@ enum hash_type spu2_hash_type(u32 src_sent) /** * spu2_digest_size() - Determine the size of a hash digest to expect the SPU to * return. - * alg_digest_size: Number of bytes in the final digest for the given algo - * alg: The hash algorithm - * htype: Type of hash operation (init, update, full, etc) + * @alg_digest_size: Number of bytes in the final digest for the given algo + * @alg: The hash algorithm + * @htype: Type of hash operation (init, update, full, etc) * */ u32 spu2_digest_size(u32 alg_digest_size, enum hash_alg alg, @@ -921,7 +926,7 @@ u32 spu2_digest_size(u32 alg_digest_size, enum hash_alg alg, } /** - * spu_create_request() - Build a SPU2 request message header, includint FMD and + * spu2_create_request() - Build a SPU2 request message header, includint FMD and * OMD. * @spu_hdr: Start of buffer where SPU request header is to be written * @req_opts: SPU request message options @@ -1105,7 +1110,7 @@ u32 spu2_create_request(u8 *spu_hdr, } /** - * spu_cipher_req_init() - Build an skcipher SPU2 request message header, + * spu2_cipher_req_init() - Build an skcipher SPU2 request message header, * including FMD and OMD. * @spu_hdr: Location of start of SPU request (FMD field) * @cipher_parms: Parameters describing cipher request @@ -1162,11 +1167,11 @@ u16 spu2_cipher_req_init(u8 *spu_hdr, struct spu_cipher_parms *cipher_parms) } /** - * spu_cipher_req_finish() - Finish building a SPU request message header for a + * spu2_cipher_req_finish() - Finish building a SPU request message header for a * block cipher request. * @spu_hdr: Start of the request message header (MH field) * @spu_req_hdr_len: Length in bytes of the SPU request header - * @isInbound: 0 encrypt, 1 decrypt + * @is_inbound: 0 encrypt, 1 decrypt * @cipher_parms: Parameters describing cipher operation to be performed * @data_size: Length of the data in the BD field * @@ -1222,7 +1227,7 @@ void spu2_cipher_req_finish(u8 *spu_hdr, } /** - * spu_request_pad() - Create pad bytes at the end of the data. + * spu2_request_pad() - Create pad bytes at the end of the data. * @pad_start: Start of buffer where pad bytes are to be written * @gcm_padding: Length of GCM padding, in bytes * @hash_pad_len: Number of bytes of padding extend data to full block @@ -1311,7 +1316,7 @@ u8 spu2_rx_status_len(void) } /** - * spu_status_process() - Process the status from a SPU response message. + * spu2_status_process() - Process the status from a SPU response message. * @statp: start of STATUS word * * Return: 0 - if status is good and response should be processed diff --git a/drivers/crypto/bcm/util.c b/drivers/crypto/bcm/util.c index c4669a96eaecf1258acdf3b57e9211c9d71c221f..d5d9cabea55aa4d4d621731a6200977e76928ac7 100644 --- a/drivers/crypto/bcm/util.c +++ b/drivers/crypto/bcm/util.c @@ -119,8 +119,8 @@ int spu_sg_count(struct scatterlist *sg_list, unsigned int skip, int nbytes) * @from_skip: number of bytes to skip in from_sg. Non-zero when previous * request included part of the buffer in entry in from_sg. * Assumes from_skip < from_sg->length. - * @from_nents number of entries in from_sg - * @length number of bytes to copy. may reach this limit before exhausting + * @from_nents: number of entries in from_sg + * @length: number of bytes to copy. may reach this limit before exhausting * from_sg. * * Copies the entries themselves, not the data in the entries. Assumes to_sg has diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index a780e627838ae9a3aa41835a32d353c4d4ea00ff..8b8ed77d8715d25595a7f26ed6c9cdf7ab4d5b22 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -71,6 +71,9 @@ struct caam_skcipher_alg { * @adata: authentication algorithm details * @cdata: encryption algorithm details * @authsize: authentication tag (a.k.a. ICV / MAC) size + * @xts_key_fallback: true if fallback tfm needs to be used due + * to unsupported xts key lengths + * @fallback: xts fallback tfm */ struct caam_ctx { struct caam_flc flc[NUM_OP]; diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index dd5f101e43f83ce1a1f358b06a3f3f1686e4a94c..e313233ec6de79e48e25bc88c490a82a4e21991e 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -187,7 +187,8 @@ static void rsa_priv_f_done(struct device *dev, u32 *desc, u32 err, } /** - * Count leading zeros, need it to strip, from a given scatterlist + * caam_rsa_count_leading_zeros - Count leading zeros, need it to strip, + * from a given scatterlist * * @sgl : scatterlist to count zeros from * @nbytes: number of zeros, in bytes, to strip diff --git a/drivers/crypto/cavium/cpt/cptpf_main.c b/drivers/crypto/cavium/cpt/cptpf_main.c index 711b1acdd4e0c269e897d2b82b1b8c9ebaf0bf7d..06ee42e8a24584e68ecc129d5fc4fdc52c7536f9 100644 --- a/drivers/crypto/cavium/cpt/cptpf_main.c +++ b/drivers/crypto/cavium/cpt/cptpf_main.c @@ -10,7 +10,6 @@ #include <linux/moduleparam.h> #include <linux/pci.h> #include <linux/printk.h> -#include <linux/version.h> #include "cptpf.h" diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c index 99b053094f5aff2290e7b23d26c4ae309a03eec0..c288c4b51783da60b2a188b44fe8ef7b4c53ae4e 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_isr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c @@ -10,7 +10,7 @@ #include "nitrox_isr.h" #include "nitrox_mbx.h" -/** +/* * One vector for each type of ring * - NPS packet ring, AQMQ ring and ZQMQ ring */ @@ -216,7 +216,7 @@ static void nps_core_int_tasklet(unsigned long data) } } -/** +/* * nps_core_int_isr - interrupt handler for NITROX errors and * mailbox communication */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index 53ef0679213301b81a79a47a66368952d34cbd93..df95ba26b414150c9b8163323973fd8f98e5e9c2 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -58,14 +58,15 @@ static void softreq_unmap_sgbufs(struct nitrox_softreq *sr) struct device *dev = DEV(ndev); - dma_unmap_sg(dev, sr->in.sg, sr->in.sgmap_cnt, DMA_BIDIRECTIONAL); + dma_unmap_sg(dev, sr->in.sg, sg_nents(sr->in.sg), + DMA_BIDIRECTIONAL); dma_unmap_single(dev, sr->in.sgcomp_dma, sr->in.sgcomp_len, DMA_TO_DEVICE); kfree(sr->in.sgcomp); sr->in.sg = NULL; sr->in.sgmap_cnt = 0; - dma_unmap_sg(dev, sr->out.sg, sr->out.sgmap_cnt, + dma_unmap_sg(dev, sr->out.sg, sg_nents(sr->out.sg), DMA_BIDIRECTIONAL); dma_unmap_single(dev, sr->out.sgcomp_dma, sr->out.sgcomp_len, DMA_TO_DEVICE); @@ -178,7 +179,7 @@ static int dma_map_inbufs(struct nitrox_softreq *sr, return 0; incomp_err: - dma_unmap_sg(dev, req->src, nents, DMA_BIDIRECTIONAL); + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_BIDIRECTIONAL); sr->in.sgmap_cnt = 0; return ret; } @@ -203,7 +204,7 @@ static int dma_map_outbufs(struct nitrox_softreq *sr, return 0; outcomp_map_err: - dma_unmap_sg(dev, req->dst, nents, DMA_BIDIRECTIONAL); + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_BIDIRECTIONAL); sr->out.sgmap_cnt = 0; sr->out.sg = NULL; return ret; diff --git a/drivers/crypto/cavium/zip/common.h b/drivers/crypto/cavium/zip/common.h index 58fb3ed6e64424766ac6907b62f77a934bedcc78..54f6fb054119f0b518e54a73754888a4a07136bc 100644 --- a/drivers/crypto/cavium/zip/common.h +++ b/drivers/crypto/cavium/zip/common.h @@ -56,7 +56,6 @@ #include <linux/seq_file.h> #include <linux/string.h> #include <linux/types.h> -#include <linux/version.h> /* Device specific zlib function definitions */ #include "zip_device.h" diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c index 88275b4867ea36e9a23bb1a7e6e7b10a6c0c522b..5976530c00a8a16e90c420925bc90c2e8b792c5c 100644 --- a/drivers/crypto/ccp/ccp-crypto-main.c +++ b/drivers/crypto/ccp/ccp-crypto-main.c @@ -59,7 +59,7 @@ struct ccp_crypto_queue { #define CCP_CRYPTO_MAX_QLEN 100 static struct ccp_crypto_queue req_queue; -static spinlock_t req_queue_lock; +static DEFINE_SPINLOCK(req_queue_lock); struct ccp_crypto_cmd { struct list_head entry; @@ -410,7 +410,6 @@ static int ccp_crypto_init(void) return ret; } - spin_lock_init(&req_queue_lock); INIT_LIST_HEAD(&req_queue.cmds); req_queue.backlog = &req_queue.cmds; req_queue.cmd_count = 0; diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 0971ee60f840081717646ad2d18a55fbde36a185..6777582aa1ceee3fcb0be1ac641da9b99ac3ab6e 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -548,7 +548,7 @@ bool ccp_queues_suspended(struct ccp_device *ccp) return ccp->cmd_q_count == suspended; } -int ccp_dev_suspend(struct sp_device *sp) +void ccp_dev_suspend(struct sp_device *sp) { struct ccp_device *ccp = sp->ccp_data; unsigned long flags; @@ -556,7 +556,7 @@ int ccp_dev_suspend(struct sp_device *sp) /* If there's no device there's nothing to do */ if (!ccp) - return 0; + return; spin_lock_irqsave(&ccp->cmd_lock, flags); @@ -572,11 +572,9 @@ int ccp_dev_suspend(struct sp_device *sp) while (!ccp_queues_suspended(ccp)) wait_event_interruptible(ccp->suspend_queue, ccp_queues_suspended(ccp)); - - return 0; } -int ccp_dev_resume(struct sp_device *sp) +void ccp_dev_resume(struct sp_device *sp) { struct ccp_device *ccp = sp->ccp_data; unsigned long flags; @@ -584,7 +582,7 @@ int ccp_dev_resume(struct sp_device *sp) /* If there's no device there's nothing to do */ if (!ccp) - return 0; + return; spin_lock_irqsave(&ccp->cmd_lock, flags); @@ -597,8 +595,6 @@ int ccp_dev_resume(struct sp_device *sp) } spin_unlock_irqrestore(&ccp->cmd_lock, flags); - - return 0; } int ccp_dev_init(struct sp_device *sp) diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index d6a8f4e4b14a8099649404ba0a34abadf9c99696..bb88198c874e0ed2b8ed55a03fb93a9d9bef0aa0 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -2418,7 +2418,6 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) dst.address += CCP_ECC_OUTPUT_SIZE; ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.y, 0, CCP_ECC_MODULUS_BYTES); - dst.address += CCP_ECC_OUTPUT_SIZE; /* Restore the workarea address */ dst.address = save; diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index cb9b4c4e371edb43a4d2b593ba39bda330189a0f..da3872c48308e176550bd03becfe584501482294 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -21,6 +21,7 @@ #include <linux/ccp.h> #include <linux/firmware.h> #include <linux/gfp.h> +#include <linux/cpufeature.h> #include <asm/smp.h> @@ -972,6 +973,11 @@ int sev_dev_init(struct psp_device *psp) struct sev_device *sev; int ret = -ENOMEM; + if (!boot_cpu_has(X86_FEATURE_SEV)) { + dev_info_once(dev, "SEV: memory encryption not enabled by BIOS\n"); + return 0; + } + sev = devm_kzalloc(dev, sizeof(*sev), GFP_KERNEL); if (!sev) goto e_err; diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c index 6284a15e50472911071404cd2327d82b20141985..7eb3e46682860c975f74e392beb87995f78d2913 100644 --- a/drivers/crypto/ccp/sp-dev.c +++ b/drivers/crypto/ccp/sp-dev.c @@ -213,12 +213,8 @@ void sp_destroy(struct sp_device *sp) int sp_suspend(struct sp_device *sp) { - int ret; - if (sp->dev_vdata->ccp_vdata) { - ret = ccp_dev_suspend(sp); - if (ret) - return ret; + ccp_dev_suspend(sp); } return 0; @@ -226,12 +222,8 @@ int sp_suspend(struct sp_device *sp) int sp_resume(struct sp_device *sp) { - int ret; - if (sp->dev_vdata->ccp_vdata) { - ret = ccp_dev_resume(sp); - if (ret) - return ret; + ccp_dev_resume(sp); } return 0; diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 0218d0670eeefdf274f0a9a2d45aac0491b1d385..20377e67f65dfd959e4df11d834e913151d87f48 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -134,8 +134,8 @@ struct sp_device *sp_get_psp_master_device(void); int ccp_dev_init(struct sp_device *sp); void ccp_dev_destroy(struct sp_device *sp); -int ccp_dev_suspend(struct sp_device *sp); -int ccp_dev_resume(struct sp_device *sp); +void ccp_dev_suspend(struct sp_device *sp); +void ccp_dev_resume(struct sp_device *sp); #else /* !CONFIG_CRYPTO_DEV_SP_CCP */ @@ -144,15 +144,8 @@ static inline int ccp_dev_init(struct sp_device *sp) return 0; } static inline void ccp_dev_destroy(struct sp_device *sp) { } - -static inline int ccp_dev_suspend(struct sp_device *sp) -{ - return 0; -} -static inline int ccp_dev_resume(struct sp_device *sp) -{ - return 0; -} +static inline void ccp_dev_suspend(struct sp_device *sp) { } +static inline void ccp_dev_resume(struct sp_device *sp) { } #endif /* CONFIG_CRYPTO_DEV_SP_CCP */ #ifdef CONFIG_CRYPTO_DEV_SP_PSP diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index f471dbaef1fbc35e4bd9d40c38b5fdda4c74047e..f468594ef8afaaf2bec250a972db9382fd6bc5fa 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -356,6 +356,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] }, { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] }, { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] }, + { PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[4] }, /* Last entry must be zero */ { 0, } }; diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c index 5e697a90ea7f497082e05d9ac6aac49d1cfec530..5c9d47f3be375093fc31c96f336570555fa04df0 100644 --- a/drivers/crypto/ccp/tee-dev.c +++ b/drivers/crypto/ccp/tee-dev.c @@ -5,7 +5,7 @@ * Author: Rijo Thomas <Rijo-john.Thomas@amd.com> * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com> * - * Copyright 2019 Advanced Micro Devices, Inc. + * Copyright (C) 2019,2021 Advanced Micro Devices, Inc. */ #include <linux/types.h> @@ -36,6 +36,7 @@ static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size) if (!start_addr) return -ENOMEM; + memset(start_addr, 0x0, ring_size); rb_mgr->ring_start = start_addr; rb_mgr->ring_size = ring_size; rb_mgr->ring_pa = __psp_pa(start_addr); @@ -244,41 +245,54 @@ static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id, void *buf, size_t len, struct tee_ring_cmd **resp) { struct tee_ring_cmd *cmd; - u32 rptr, wptr; int nloop = 1000, ret = 0; + u32 rptr; *resp = NULL; mutex_lock(&tee->rb_mgr.mutex); - wptr = tee->rb_mgr.wptr; - - /* Check if ring buffer is full */ + /* Loop until empty entry found in ring buffer */ do { + /* Get pointer to ring buffer command entry */ + cmd = (struct tee_ring_cmd *) + (tee->rb_mgr.ring_start + tee->rb_mgr.wptr); + rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg); - if (!(wptr + sizeof(struct tee_ring_cmd) == rptr)) + /* Check if ring buffer is full or command entry is waiting + * for response from TEE + */ + if (!(tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr || + cmd->flag == CMD_WAITING_FOR_RESPONSE)) break; - dev_info(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", - rptr, wptr); + dev_dbg(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", + rptr, tee->rb_mgr.wptr); - /* Wait if ring buffer is full */ + /* Wait if ring buffer is full or TEE is processing data */ mutex_unlock(&tee->rb_mgr.mutex); schedule_timeout_interruptible(msecs_to_jiffies(10)); mutex_lock(&tee->rb_mgr.mutex); } while (--nloop); - if (!nloop && (wptr + sizeof(struct tee_ring_cmd) == rptr)) { - dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", - rptr, wptr); + if (!nloop && + (tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr || + cmd->flag == CMD_WAITING_FOR_RESPONSE)) { + dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u response flag %u\n", + rptr, tee->rb_mgr.wptr, cmd->flag); ret = -EBUSY; goto unlock; } - /* Pointer to empty data entry in ring buffer */ - cmd = (struct tee_ring_cmd *)(tee->rb_mgr.ring_start + wptr); + /* Do not submit command if PSP got disabled while processing any + * command in another thread + */ + if (psp_dead) { + ret = -EBUSY; + goto unlock; + } /* Write command data into ring buffer */ cmd->cmd_id = cmd_id; @@ -286,6 +300,9 @@ static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id, memset(&cmd->buf[0], 0, sizeof(cmd->buf)); memcpy(&cmd->buf[0], buf, len); + /* Indicate driver is waiting for response */ + cmd->flag = CMD_WAITING_FOR_RESPONSE; + /* Update local copy of write pointer */ tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd); if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size) @@ -309,14 +326,14 @@ static int tee_wait_cmd_completion(struct psp_tee_device *tee, struct tee_ring_cmd *resp, unsigned int timeout) { - /* ~5ms sleep per loop => nloop = timeout * 200 */ - int nloop = timeout * 200; + /* ~1ms sleep per loop => nloop = timeout * 1000 */ + int nloop = timeout * 1000; while (--nloop) { if (resp->cmd_state == TEE_CMD_STATE_COMPLETED) return 0; - usleep_range(5000, 5100); + usleep_range(1000, 1100); } dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n", @@ -353,12 +370,16 @@ int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len, return ret; ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT); - if (ret) + if (ret) { + resp->flag = CMD_RESPONSE_TIMEDOUT; return ret; + } memcpy(buf, &resp->buf[0], len); *status = resp->status; + resp->flag = CMD_RESPONSE_COPIED; + return 0; } EXPORT_SYMBOL(psp_tee_process_cmd); diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h index f099601121150dc7c38e4ef89e22d8a61475f4b1..49d26158b71e31635557d971ad19a148b9859043 100644 --- a/drivers/crypto/ccp/tee-dev.h +++ b/drivers/crypto/ccp/tee-dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT */ /* - * Copyright 2019 Advanced Micro Devices, Inc. + * Copyright (C) 2019,2021 Advanced Micro Devices, Inc. * * Author: Rijo Thomas <Rijo-john.Thomas@amd.com> * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com> @@ -18,7 +18,7 @@ #include <linux/mutex.h> #define TEE_DEFAULT_TIMEOUT 10 -#define MAX_BUFFER_SIZE 992 +#define MAX_BUFFER_SIZE 988 /** * enum tee_ring_cmd_id - TEE interface commands for ring buffer configuration @@ -81,6 +81,20 @@ enum tee_cmd_state { TEE_CMD_STATE_COMPLETED, }; +/** + * enum cmd_resp_state - TEE command's response status maintained by driver + * @CMD_RESPONSE_INVALID: initial state when no command is written to ring + * @CMD_WAITING_FOR_RESPONSE: driver waiting for response from TEE + * @CMD_RESPONSE_TIMEDOUT: failed to get response from TEE + * @CMD_RESPONSE_COPIED: driver has copied response from TEE + */ +enum cmd_resp_state { + CMD_RESPONSE_INVALID, + CMD_WAITING_FOR_RESPONSE, + CMD_RESPONSE_TIMEDOUT, + CMD_RESPONSE_COPIED, +}; + /** * struct tee_ring_cmd - Structure of the command buffer in TEE ring * @cmd_id: refers to &enum tee_cmd_id. Command id for the ring buffer @@ -91,6 +105,7 @@ enum tee_cmd_state { * @pdata: private data (currently unused) * @res1: reserved region * @buf: TEE command specific buffer + * @flag: refers to &enum cmd_resp_state */ struct tee_ring_cmd { u32 cmd_id; @@ -100,6 +115,7 @@ struct tee_ring_cmd { u64 pdata; u32 res1[2]; u8 buf[MAX_BUFFER_SIZE]; + u32 flag; /* Total size: 1024 bytes */ } __packed; diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c index d0e59e942568a0e7837b4c517559eb56a5df829f..e599ac6dc162a26c1246e24b45dddd982aeceb1a 100644 --- a/drivers/crypto/ccree/cc_driver.c +++ b/drivers/crypto/ccree/cc_driver.c @@ -352,10 +352,8 @@ static int init_cc_resources(struct platform_device *plat_dev) req_mem_cc_regs = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); /* Map registers space */ new_drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs); - if (IS_ERR(new_drvdata->cc_base)) { - dev_err(dev, "Failed to ioremap registers"); + if (IS_ERR(new_drvdata->cc_base)) return PTR_ERR(new_drvdata->cc_base); - } dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name, req_mem_cc_regs); diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index f5a336634daa6333ddd5b28d5fb4411a4f37d5bb..6933546f87b1a863e9eecc94470d09168bde5b51 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -126,11 +126,6 @@ static inline struct uld_ctx *ULD_CTX(struct chcr_context *ctx) return container_of(ctx->dev, struct uld_ctx, dev); } -static inline int is_ofld_imm(const struct sk_buff *skb) -{ - return (skb->len <= SGE_MAX_WR_LEN); -} - static inline void chcr_init_hctx_per_wr(struct chcr_ahash_req_ctx *reqctx) { memset(&reqctx->hctx_wr, 0, sizeof(struct chcr_hctx_per_wr)); @@ -769,13 +764,14 @@ static inline void create_wreq(struct chcr_context *ctx, struct uld_ctx *u_ctx = ULD_CTX(ctx); unsigned int tx_channel_id, rx_channel_id; unsigned int txqidx = 0, rxqidx = 0; - unsigned int qid, fid; + unsigned int qid, fid, portno; get_qidxs(req, &txqidx, &rxqidx); qid = u_ctx->lldi.rxq_ids[rxqidx]; fid = u_ctx->lldi.rxq_ids[0]; + portno = rxqidx / ctx->rxq_perchan; tx_channel_id = txqidx / ctx->txq_perchan; - rx_channel_id = rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[portno]); chcr_req->wreq.op_to_cctx_size = FILL_WR_OP_CCTX_SIZE; @@ -797,15 +793,13 @@ static inline void create_wreq(struct chcr_context *ctx, /** * create_cipher_wr - form the WR for cipher operations - * @req: cipher req. - * @ctx: crypto driver context of the request. - * @qid: ingress qid where response of this WR should be received. - * @op_type: encryption or decryption + * @wrparam: Container for create_cipher_wr()'s parameters */ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(wrparam->req); struct chcr_context *ctx = c_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); struct ablk_ctx *ablkctx = ABLK_CTX(ctx); struct sk_buff *skb = NULL; struct chcr_wr *chcr_req; @@ -822,6 +816,7 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam) struct adapter *adap = padap(ctx->dev); unsigned int rx_channel_id = reqctx->rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); nents = sg_nents_xlen(reqctx->dstsg, wrparam->bytes, CHCR_DST_SG_SIZE, reqctx->dst_ofst); dst_size = get_space_for_phys_dsgl(nents); @@ -1559,7 +1554,8 @@ static inline void chcr_free_shash(struct crypto_shash *base_hash) /** * create_hash_wr - Create hash work request - * @req - Cipher req base + * @req: Cipher req base + * @param: Container for create_hash_wr()'s parameters */ static struct sk_buff *create_hash_wr(struct ahash_request *req, struct hash_wr_param *param) @@ -1580,6 +1576,7 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req, int error = 0; unsigned int rx_channel_id = req_ctx->rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); transhdr_len = HASH_TRANSHDR_SIZE(param->kctx_len); req_ctx->hctx_wr.imm = (transhdr_len + param->bfr_len + param->sg_len) <= SGE_MAX_WR_LEN; @@ -2438,6 +2435,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_context *ctx = a_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); struct chcr_authenc_ctx *actx = AUTHENC_CTX(aeadctx); struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); @@ -2457,6 +2455,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, struct adapter *adap = padap(ctx->dev); unsigned int rx_channel_id = reqctx->rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); if (req->cryptlen == 0) return NULL; @@ -2710,9 +2709,11 @@ void chcr_add_aead_dst_ent(struct aead_request *req, struct dsgl_walk dsgl_walk; unsigned int authsize = crypto_aead_authsize(tfm); struct chcr_context *ctx = a_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); u32 temp; unsigned int rx_channel_id = reqctx->rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); dsgl_walk_init(&dsgl_walk, phys_cpl); dsgl_walk_add_page(&dsgl_walk, IV + reqctx->b0_len, reqctx->iv_dma); temp = req->assoclen + req->cryptlen + @@ -2752,9 +2753,11 @@ void chcr_add_cipher_dst_ent(struct skcipher_request *req, struct chcr_skcipher_req_ctx *reqctx = skcipher_request_ctx(req); struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(wrparam->req); struct chcr_context *ctx = c_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); struct dsgl_walk dsgl_walk; unsigned int rx_channel_id = reqctx->rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); dsgl_walk_init(&dsgl_walk, phys_cpl); dsgl_walk_add_sg(&dsgl_walk, reqctx->dstsg, wrparam->bytes, reqctx->dst_ofst); @@ -2958,6 +2961,7 @@ static void fill_sec_cpl_for_aead(struct cpl_tx_sec_pdu *sec_cpl, { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_context *ctx = a_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); unsigned int cipher_mode = CHCR_SCMD_CIPHER_MODE_AES_CCM; @@ -2967,6 +2971,8 @@ static void fill_sec_cpl_for_aead(struct cpl_tx_sec_pdu *sec_cpl, unsigned int tag_offset = 0, auth_offset = 0; unsigned int assoclen; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); + if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) assoclen = req->assoclen - 8; else @@ -3127,6 +3133,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_context *ctx = a_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); struct sk_buff *skb = NULL; @@ -3143,6 +3150,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, struct adapter *adap = padap(ctx->dev); unsigned int rx_channel_id = reqctx->rxqidx / ctx->rxq_perchan; + rx_channel_id = cxgb4_port_e2cchan(u_ctx->lldi.ports[rx_channel_id]); if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) assoclen = req->assoclen - 8; diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c index f91f9d762a45ea1b980914bfdcd9d224f064370e..39c70e6255f9939fe580310ed22a904bbb68862e 100644 --- a/drivers/crypto/chelsio/chcr_core.c +++ b/drivers/crypto/chelsio/chcr_core.c @@ -1,4 +1,4 @@ -/** +/* * This file is part of the Chelsio T4/T5/T6 Ethernet driver for Linux. * * Copyright (C) 2011-2016 Chelsio Communications. All rights reserved. @@ -184,7 +184,7 @@ static void *chcr_uld_add(const struct cxgb4_lld_info *lld) struct uld_ctx *u_ctx; /* Create the device and add it in the device list */ - pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION); + pr_info_once("%s\n", DRV_DESC); if (!(lld->ulp_crypto & ULP_CRYPTO_LOOKASIDE)) return ERR_PTR(-EOPNOTSUPP); @@ -309,4 +309,3 @@ module_exit(chcr_crypto_exit); MODULE_DESCRIPTION("Crypto Co-processor for Chelsio Terminator cards."); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Chelsio Communications"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h index b02f981e7c3234f66d0da99588578e508e7a03bc..f7c8bb95a71b41f63cfa356133b32d8200c9e5d0 100644 --- a/drivers/crypto/chelsio/chcr_core.h +++ b/drivers/crypto/chelsio/chcr_core.h @@ -44,7 +44,6 @@ #include "cxgb4_uld.h" #define DRV_MODULE_NAME "chcr" -#define DRV_VERSION "1.0.0.0-ko" #define DRV_DESC "Chelsio T6 Crypto Co-processor Driver" #define MAX_PENDING_REQ_TO_HW 20 diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 4ee010f399124ae5df0afd14b510f1db4cc7569a..fa5a9f207bc90afb94a26b101e8b018e3f3eb0aa 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -21,7 +21,7 @@ /* Static structures */ static void __iomem *_iobase; -static spinlock_t lock; +static DEFINE_SPINLOCK(lock); /* Write a 128 bit field (either a writable key or IV) */ static inline void @@ -383,8 +383,6 @@ static int geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) goto erequest; } - spin_lock_init(&lock); - /* Clear any pending activity */ iowrite32(AES_INTR_PENDING | AES_INTR_MASK, _iobase + AES_INTR_REG); diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig index 843192666dc38a5ec0c4c385aea7b4ca254fe682..e572f9982d4ef4bbd2e0c177170d31e60436440d 100644 --- a/drivers/crypto/hisilicon/Kconfig +++ b/drivers/crypto/hisilicon/Kconfig @@ -68,6 +68,8 @@ config CRYPTO_DEV_HISI_HPRE select CRYPTO_DEV_HISI_QM select CRYPTO_DH select CRYPTO_RSA + select CRYPTO_CURVE25519 + select CRYPTO_ECDH help Support for HiSilicon HPRE(High Performance RSA Engine) accelerator, which can accelerate RSA and DH algorithms. diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h index 181c109b19f7c4219be4db42739c04b4bd984382..e0b4a1982ee9ef709db645b5e755a2edaaa1605b 100644 --- a/drivers/crypto/hisilicon/hpre/hpre.h +++ b/drivers/crypto/hisilicon/hpre/hpre.h @@ -10,6 +10,14 @@ #define HPRE_PF_DEF_Q_NUM 64 #define HPRE_PF_DEF_Q_BASE 0 +/* + * type used in qm sqc DW6. + * 0 - Algorithm which has been supported in V2, like RSA, DH and so on; + * 1 - ECC algorithm in V3. + */ +#define HPRE_V2_ALG_TYPE 0 +#define HPRE_V3_ECC_ALG_TYPE 1 + enum { HPRE_CLUSTER0, HPRE_CLUSTER1, @@ -18,7 +26,6 @@ enum { }; enum hpre_ctrl_dbgfs_file { - HPRE_CURRENT_QM, HPRE_CLEAR_ENABLE, HPRE_CLUSTER_CTRL, HPRE_DEBUG_FILE_NUM, @@ -75,6 +82,9 @@ enum hpre_alg_type { HPRE_ALG_KG_CRT = 0x3, HPRE_ALG_DH_G2 = 0x4, HPRE_ALG_DH = 0x5, + HPRE_ALG_ECC_MUL = 0xD, + /* shared by x25519 and x448, but x448 is not supported now */ + HPRE_ALG_CURVE25519_MUL = 0x10, }; struct hpre_sqe { @@ -92,8 +102,8 @@ struct hpre_sqe { __le32 rsvd1[_HPRE_SQE_ALIGN_EXT]; }; -struct hisi_qp *hpre_create_qp(void); -int hpre_algs_register(void); -void hpre_algs_unregister(void); +struct hisi_qp *hpre_create_qp(u8 type); +int hpre_algs_register(struct hisi_qm *qm); +void hpre_algs_unregister(struct hisi_qm *qm); #endif diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c index a87f9904087aac2d02481e2b309acc99d4656edd..a380087c83f771ee39b6c2c930768ed2e7d2918a 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c +++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2019 HiSilicon Limited. */ #include <crypto/akcipher.h> +#include <crypto/curve25519.h> #include <crypto/dh.h> +#include <crypto/ecc_curve.h> +#include <crypto/ecdh.h> #include <crypto/internal/akcipher.h> #include <crypto/internal/kpp.h> #include <crypto/internal/rsa.h> @@ -36,6 +39,13 @@ struct hpre_ctx; #define HPRE_DFX_SEC_TO_US 1000000 #define HPRE_DFX_US_TO_NS 1000 +/* size in bytes of the n prime */ +#define HPRE_ECC_NIST_P192_N_SIZE 24 +#define HPRE_ECC_NIST_P256_N_SIZE 32 + +/* size in bytes */ +#define HPRE_ECC_HW256_KSZ_B 32 + typedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe); struct hpre_rsa_ctx { @@ -61,14 +71,35 @@ struct hpre_dh_ctx { * else if base if the counterpart public key we * compute the shared secret * ZZ = yb^xa mod p; [RFC2631 sec 2.1.1] + * low address: d--->n, please refer to Hisilicon HPRE UM */ - char *xa_p; /* low address: d--->n, please refer to Hisilicon HPRE UM */ + char *xa_p; dma_addr_t dma_xa_p; char *g; /* m */ dma_addr_t dma_g; }; +struct hpre_ecdh_ctx { + /* low address: p->a->k->b */ + unsigned char *p; + dma_addr_t dma_p; + + /* low address: x->y */ + unsigned char *g; + dma_addr_t dma_g; +}; + +struct hpre_curve25519_ctx { + /* low address: p->a->k */ + unsigned char *p; + dma_addr_t dma_p; + + /* gx coordinate */ + unsigned char *g; + dma_addr_t dma_g; +}; + struct hpre_ctx { struct hisi_qp *qp; struct hpre_asym_request **req_list; @@ -80,7 +111,11 @@ struct hpre_ctx { union { struct hpre_rsa_ctx rsa; struct hpre_dh_ctx dh; + struct hpre_ecdh_ctx ecdh; + struct hpre_curve25519_ctx curve25519; }; + /* for ecc algorithms */ + unsigned int curve_id; }; struct hpre_asym_request { @@ -91,6 +126,8 @@ struct hpre_asym_request { union { struct akcipher_request *rsa; struct kpp_request *dh; + struct kpp_request *ecdh; + struct kpp_request *curve25519; } areq; int err; int req_id; @@ -152,12 +189,12 @@ static void hpre_rm_req_from_ctx(struct hpre_asym_request *hpre_req) } } -static struct hisi_qp *hpre_get_qp_and_start(void) +static struct hisi_qp *hpre_get_qp_and_start(u8 type) { struct hisi_qp *qp; int ret; - qp = hpre_create_qp(); + qp = hpre_create_qp(type); if (!qp) { pr_err("Can not create hpre qp!\n"); return ERR_PTR(-ENODEV); @@ -261,8 +298,6 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx, dma_addr_t tmp; tmp = le64_to_cpu(sqe->in); - if (unlikely(!tmp)) - return; if (src) { if (req->src) @@ -272,8 +307,6 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx, } tmp = le64_to_cpu(sqe->out); - if (unlikely(!tmp)) - return; if (req->dst) { if (dst) @@ -288,13 +321,16 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx, static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, void **kreq) { + struct device *dev = HPRE_DEV(ctx); struct hpre_asym_request *req; - int err, id, done; + unsigned int err, done, alg; + int id; #define HPRE_NO_HW_ERR 0 #define HPRE_HW_TASK_DONE 3 #define HREE_HW_ERR_MASK 0x7ff #define HREE_SQE_DONE_MASK 0x3 +#define HREE_ALG_TYPE_MASK 0x1f id = (int)le16_to_cpu(sqe->tag); req = ctx->req_list[id]; hpre_rm_req_from_ctx(req); @@ -307,7 +343,11 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, HREE_SQE_DONE_MASK; if (likely(err == HPRE_NO_HW_ERR && done == HPRE_HW_TASK_DONE)) - return 0; + return 0; + + alg = le32_to_cpu(sqe->dw0) & HREE_ALG_TYPE_MASK; + dev_err_ratelimited(dev, "alg[0x%x] error: done[0x%x], etype[0x%x]\n", + alg, done, err); return -EINVAL; } @@ -413,7 +453,6 @@ static void hpre_alg_cb(struct hisi_qp *qp, void *resp) struct hpre_sqe *sqe = resp; struct hpre_asym_request *req = ctx->req_list[le16_to_cpu(sqe->tag)]; - if (unlikely(!req)) { atomic64_inc(&dfx[HPRE_INVALID_REQ_CNT].value); return; @@ -422,18 +461,29 @@ static void hpre_alg_cb(struct hisi_qp *qp, void *resp) req->cb(ctx, resp); } -static int hpre_ctx_init(struct hpre_ctx *ctx) +static void hpre_stop_qp_and_put(struct hisi_qp *qp) +{ + hisi_qm_stop_qp(qp); + hisi_qm_free_qps(&qp, 1); +} + +static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) { struct hisi_qp *qp; + int ret; - qp = hpre_get_qp_and_start(); + qp = hpre_get_qp_and_start(type); if (IS_ERR(qp)) return PTR_ERR(qp); qp->qp_ctx = ctx; qp->req_cb = hpre_alg_cb; - return hpre_ctx_set(ctx, qp, QM_Q_DEPTH); + ret = hpre_ctx_set(ctx, qp, QM_Q_DEPTH); + if (ret) + hpre_stop_qp_and_put(qp); + + return ret; } static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) @@ -510,7 +560,6 @@ static int hpre_send(struct hpre_ctx *ctx, struct hpre_sqe *msg) return ret; } -#ifdef CONFIG_CRYPTO_DH static int hpre_dh_compute_value(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); @@ -674,7 +723,7 @@ static int hpre_dh_init_tfm(struct crypto_kpp *tfm) { struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); - return hpre_ctx_init(ctx); + return hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); } static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) @@ -683,7 +732,6 @@ static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) hpre_dh_clear_ctx(ctx, true); } -#endif static void hpre_rsa_drop_leading_zeros(const char **ptr, size_t *len) { @@ -1100,7 +1148,7 @@ static int hpre_rsa_init_tfm(struct crypto_akcipher *tfm) return PTR_ERR(ctx->rsa.soft_tfm); } - ret = hpre_ctx_init(ctx); + ret = hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); if (ret) crypto_free_akcipher(ctx->rsa.soft_tfm); @@ -1115,6 +1163,734 @@ static void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm) crypto_free_akcipher(ctx->rsa.soft_tfm); } +static void hpre_key_to_big_end(u8 *data, int len) +{ + int i, j; + u8 tmp; + + for (i = 0; i < len / 2; i++) { + j = len - i - 1; + tmp = data[j]; + data[j] = data[i]; + data[i] = tmp; + } +} + +static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all, + bool is_ecdh) +{ + struct device *dev = HPRE_DEV(ctx); + unsigned int sz = ctx->key_sz; + unsigned int shift = sz << 1; + + if (is_clear_all) + hisi_qm_stop_qp(ctx->qp); + + if (is_ecdh && ctx->ecdh.p) { + /* ecdh: p->a->k->b */ + memzero_explicit(ctx->ecdh.p + shift, sz); + dma_free_coherent(dev, sz << 3, ctx->ecdh.p, ctx->ecdh.dma_p); + ctx->ecdh.p = NULL; + } else if (!is_ecdh && ctx->curve25519.p) { + /* curve25519: p->a->k */ + memzero_explicit(ctx->curve25519.p + shift, sz); + dma_free_coherent(dev, sz << 2, ctx->curve25519.p, + ctx->curve25519.dma_p); + ctx->curve25519.p = NULL; + } + + hpre_ctx_clear(ctx, is_clear_all); +} + +static unsigned int hpre_ecdh_supported_curve(unsigned short id) +{ + switch (id) { + case ECC_CURVE_NIST_P192: + case ECC_CURVE_NIST_P256: + return HPRE_ECC_HW256_KSZ_B; + default: + break; + } + + return 0; +} + +static void fill_curve_param(void *addr, u64 *param, unsigned int cur_sz, u8 ndigits) +{ + unsigned int sz = cur_sz - (ndigits - 1) * sizeof(u64); + u8 i = 0; + + while (i < ndigits - 1) { + memcpy(addr + sizeof(u64) * i, ¶m[i], sizeof(u64)); + i++; + } + + memcpy(addr + sizeof(u64) * i, ¶m[ndigits - 1], sz); + hpre_key_to_big_end((u8 *)addr, cur_sz); +} + +static int hpre_ecdh_fill_curve(struct hpre_ctx *ctx, struct ecdh *params, + unsigned int cur_sz) +{ + unsigned int shifta = ctx->key_sz << 1; + unsigned int shiftb = ctx->key_sz << 2; + void *p = ctx->ecdh.p + ctx->key_sz - cur_sz; + void *a = ctx->ecdh.p + shifta - cur_sz; + void *b = ctx->ecdh.p + shiftb - cur_sz; + void *x = ctx->ecdh.g + ctx->key_sz - cur_sz; + void *y = ctx->ecdh.g + shifta - cur_sz; + const struct ecc_curve *curve = ecc_get_curve(ctx->curve_id); + char *n; + + if (unlikely(!curve)) + return -EINVAL; + + n = kzalloc(ctx->key_sz, GFP_KERNEL); + if (!n) + return -ENOMEM; + + fill_curve_param(p, curve->p, cur_sz, curve->g.ndigits); + fill_curve_param(a, curve->a, cur_sz, curve->g.ndigits); + fill_curve_param(b, curve->b, cur_sz, curve->g.ndigits); + fill_curve_param(x, curve->g.x, cur_sz, curve->g.ndigits); + fill_curve_param(y, curve->g.y, cur_sz, curve->g.ndigits); + fill_curve_param(n, curve->n, cur_sz, curve->g.ndigits); + + if (params->key_size == cur_sz && memcmp(params->key, n, cur_sz) >= 0) { + kfree(n); + return -EINVAL; + } + + kfree(n); + return 0; +} + +static unsigned int hpre_ecdh_get_curvesz(unsigned short id) +{ + switch (id) { + case ECC_CURVE_NIST_P192: + return HPRE_ECC_NIST_P192_N_SIZE; + case ECC_CURVE_NIST_P256: + return HPRE_ECC_NIST_P256_N_SIZE; + default: + break; + } + + return 0; +} + +static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params) +{ + struct device *dev = HPRE_DEV(ctx); + unsigned int sz, shift, curve_sz; + int ret; + + ctx->key_sz = hpre_ecdh_supported_curve(ctx->curve_id); + if (!ctx->key_sz) + return -EINVAL; + + curve_sz = hpre_ecdh_get_curvesz(ctx->curve_id); + if (!curve_sz || params->key_size > curve_sz) + return -EINVAL; + + sz = ctx->key_sz; + + if (!ctx->ecdh.p) { + ctx->ecdh.p = dma_alloc_coherent(dev, sz << 3, &ctx->ecdh.dma_p, + GFP_KERNEL); + if (!ctx->ecdh.p) + return -ENOMEM; + } + + shift = sz << 2; + ctx->ecdh.g = ctx->ecdh.p + shift; + ctx->ecdh.dma_g = ctx->ecdh.dma_p + shift; + + ret = hpre_ecdh_fill_curve(ctx, params, curve_sz); + if (ret) { + dev_err(dev, "failed to fill curve_param, ret = %d!\n", ret); + dma_free_coherent(dev, sz << 3, ctx->ecdh.p, ctx->ecdh.dma_p); + ctx->ecdh.p = NULL; + return ret; + } + + return 0; +} + +static bool hpre_key_is_zero(char *key, unsigned short key_sz) +{ + int i; + + for (i = 0; i < key_sz; i++) + if (key[i]) + return false; + + return true; +} + +static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, + unsigned int len) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + struct device *dev = HPRE_DEV(ctx); + unsigned int sz, sz_shift; + struct ecdh params; + int ret; + + if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0) { + dev_err(dev, "failed to decode ecdh key!\n"); + return -EINVAL; + } + + if (hpre_key_is_zero(params.key, params.key_size)) { + dev_err(dev, "Invalid hpre key!\n"); + return -EINVAL; + } + + hpre_ecc_clear_ctx(ctx, false, true); + + ret = hpre_ecdh_set_param(ctx, ¶ms); + if (ret < 0) { + dev_err(dev, "failed to set hpre param, ret = %d!\n", ret); + return ret; + } + + sz = ctx->key_sz; + sz_shift = (sz << 1) + sz - params.key_size; + memcpy(ctx->ecdh.p + sz_shift, params.key, params.key_size); + + return 0; +} + +static void hpre_ecdh_hw_data_clr_all(struct hpre_ctx *ctx, + struct hpre_asym_request *req, + struct scatterlist *dst, + struct scatterlist *src) +{ + struct device *dev = HPRE_DEV(ctx); + struct hpre_sqe *sqe = &req->req; + dma_addr_t dma; + + dma = le64_to_cpu(sqe->in); + + if (src && req->src) + dma_free_coherent(dev, ctx->key_sz << 2, req->src, dma); + + dma = le64_to_cpu(sqe->out); + + if (req->dst) + dma_free_coherent(dev, ctx->key_sz << 1, req->dst, dma); + if (dst) + dma_unmap_single(dev, dma, ctx->key_sz << 1, DMA_FROM_DEVICE); +} + +static void hpre_ecdh_cb(struct hpre_ctx *ctx, void *resp) +{ + unsigned int curve_sz = hpre_ecdh_get_curvesz(ctx->curve_id); + struct hpre_dfx *dfx = ctx->hpre->debug.dfx; + struct hpre_asym_request *req = NULL; + struct kpp_request *areq; + u64 overtime_thrhld; + char *p; + int ret; + + ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req); + areq = req->areq.ecdh; + areq->dst_len = ctx->key_sz << 1; + + overtime_thrhld = atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value); + if (overtime_thrhld && hpre_is_bd_timeout(req, overtime_thrhld)) + atomic64_inc(&dfx[HPRE_OVER_THRHLD_CNT].value); + + p = sg_virt(areq->dst); + memmove(p, p + ctx->key_sz - curve_sz, curve_sz); + memmove(p + curve_sz, p + areq->dst_len - curve_sz, curve_sz); + + hpre_ecdh_hw_data_clr_all(ctx, req, areq->dst, areq->src); + kpp_request_complete(areq, ret); + + atomic64_inc(&dfx[HPRE_RECV_CNT].value); +} + +static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + struct kpp_request *req) +{ + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; + int req_id; + void *tmp; + + if (req->dst_len < ctx->key_sz << 1) { + req->dst_len = ctx->key_sz << 1; + return -EINVAL; + } + + tmp = kpp_request_ctx(req); + h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); + h_req->cb = hpre_ecdh_cb; + h_req->areq.ecdh = req; + msg = &h_req->req; + memset(msg, 0, sizeof(*msg)); + msg->key = cpu_to_le64(ctx->ecdh.dma_p); + + msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT); + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + + req_id = hpre_add_req_to_ctx(h_req); + if (req_id < 0) + return -EBUSY; + + msg->tag = cpu_to_le16((u16)req_id); + return 0; +} + +static int hpre_ecdh_src_data_init(struct hpre_asym_request *hpre_req, + struct scatterlist *data, unsigned int len) +{ + struct hpre_sqe *msg = &hpre_req->req; + struct hpre_ctx *ctx = hpre_req->ctx; + struct device *dev = HPRE_DEV(ctx); + unsigned int tmpshift; + dma_addr_t dma = 0; + void *ptr; + int shift; + + /* Src_data include gx and gy. */ + shift = ctx->key_sz - (len >> 1); + if (unlikely(shift < 0)) + return -EINVAL; + + ptr = dma_alloc_coherent(dev, ctx->key_sz << 2, &dma, GFP_KERNEL); + if (unlikely(!ptr)) + return -ENOMEM; + + tmpshift = ctx->key_sz << 1; + scatterwalk_map_and_copy(ptr + tmpshift, data, 0, len, 0); + memcpy(ptr + shift, ptr + tmpshift, len >> 1); + memcpy(ptr + ctx->key_sz + shift, ptr + tmpshift + (len >> 1), len >> 1); + + hpre_req->src = ptr; + msg->in = cpu_to_le64(dma); + return 0; +} + +static int hpre_ecdh_dst_data_init(struct hpre_asym_request *hpre_req, + struct scatterlist *data, unsigned int len) +{ + struct hpre_sqe *msg = &hpre_req->req; + struct hpre_ctx *ctx = hpre_req->ctx; + struct device *dev = HPRE_DEV(ctx); + dma_addr_t dma = 0; + + if (unlikely(!data || !sg_is_last(data) || len != ctx->key_sz << 1)) { + dev_err(dev, "data or data length is illegal!\n"); + return -EINVAL; + } + + hpre_req->dst = NULL; + dma = dma_map_single(dev, sg_virt(data), len, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, dma))) { + dev_err(dev, "dma map data err!\n"); + return -ENOMEM; + } + + msg->out = cpu_to_le64(dma); + return 0; +} + +static int hpre_ecdh_compute_value(struct kpp_request *req) +{ + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + struct device *dev = HPRE_DEV(ctx); + void *tmp = kpp_request_ctx(req); + struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); + struct hpre_sqe *msg = &hpre_req->req; + int ret; + + ret = hpre_ecdh_msg_request_set(ctx, req); + if (unlikely(ret)) { + dev_err(dev, "failed to set ecdh request, ret = %d!\n", ret); + return ret; + } + + if (req->src) { + ret = hpre_ecdh_src_data_init(hpre_req, req->src, req->src_len); + if (unlikely(ret)) { + dev_err(dev, "failed to init src data, ret = %d!\n", ret); + goto clear_all; + } + } else { + msg->in = cpu_to_le64(ctx->ecdh.dma_g); + } + + ret = hpre_ecdh_dst_data_init(hpre_req, req->dst, req->dst_len); + if (unlikely(ret)) { + dev_err(dev, "failed to init dst data, ret = %d!\n", ret); + goto clear_all; + } + + msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_ECC_MUL); + ret = hpre_send(ctx, msg); + if (likely(!ret)) + return -EINPROGRESS; + +clear_all: + hpre_rm_req_from_ctx(hpre_req); + hpre_ecdh_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + return ret; +} + +static unsigned int hpre_ecdh_max_size(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + /* max size is the pub_key_size, include x and y */ + return ctx->key_sz << 1; +} + +static int hpre_ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P192; + + return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); +} + +static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P256; + + return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); +} + +static void hpre_ecdh_exit_tfm(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + hpre_ecc_clear_ctx(ctx, true, true); +} + +static void hpre_curve25519_fill_curve(struct hpre_ctx *ctx, const void *buf, + unsigned int len) +{ + u8 secret[CURVE25519_KEY_SIZE] = { 0 }; + unsigned int sz = ctx->key_sz; + const struct ecc_curve *curve; + unsigned int shift = sz << 1; + void *p; + + /* + * The key from 'buf' is in little-endian, we should preprocess it as + * the description in rfc7748: "k[0] &= 248, k[31] &= 127, k[31] |= 64", + * then convert it to big endian. Only in this way, the result can be + * the same as the software curve-25519 that exists in crypto. + */ + memcpy(secret, buf, len); + curve25519_clamp_secret(secret); + hpre_key_to_big_end(secret, CURVE25519_KEY_SIZE); + + p = ctx->curve25519.p + sz - len; + + curve = ecc_get_curve25519(); + + /* fill curve parameters */ + fill_curve_param(p, curve->p, len, curve->g.ndigits); + fill_curve_param(p + sz, curve->a, len, curve->g.ndigits); + memcpy(p + shift, secret, len); + fill_curve_param(p + shift + sz, curve->g.x, len, curve->g.ndigits); + memzero_explicit(secret, CURVE25519_KEY_SIZE); +} + +static int hpre_curve25519_set_param(struct hpre_ctx *ctx, const void *buf, + unsigned int len) +{ + struct device *dev = HPRE_DEV(ctx); + unsigned int sz = ctx->key_sz; + unsigned int shift = sz << 1; + + /* p->a->k->gx */ + if (!ctx->curve25519.p) { + ctx->curve25519.p = dma_alloc_coherent(dev, sz << 2, + &ctx->curve25519.dma_p, + GFP_KERNEL); + if (!ctx->curve25519.p) + return -ENOMEM; + } + + ctx->curve25519.g = ctx->curve25519.p + shift + sz; + ctx->curve25519.dma_g = ctx->curve25519.dma_p + shift + sz; + + hpre_curve25519_fill_curve(ctx, buf, len); + + return 0; +} + +static int hpre_curve25519_set_secret(struct crypto_kpp *tfm, const void *buf, + unsigned int len) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + struct device *dev = HPRE_DEV(ctx); + int ret = -EINVAL; + + if (len != CURVE25519_KEY_SIZE || + !crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE)) { + dev_err(dev, "key is null or key len is not 32bytes!\n"); + return ret; + } + + /* Free old secret if any */ + hpre_ecc_clear_ctx(ctx, false, false); + + ctx->key_sz = CURVE25519_KEY_SIZE; + ret = hpre_curve25519_set_param(ctx, buf, CURVE25519_KEY_SIZE); + if (ret) { + dev_err(dev, "failed to set curve25519 param, ret = %d!\n", ret); + hpre_ecc_clear_ctx(ctx, false, false); + return ret; + } + + return 0; +} + +static void hpre_curve25519_hw_data_clr_all(struct hpre_ctx *ctx, + struct hpre_asym_request *req, + struct scatterlist *dst, + struct scatterlist *src) +{ + struct device *dev = HPRE_DEV(ctx); + struct hpre_sqe *sqe = &req->req; + dma_addr_t dma; + + dma = le64_to_cpu(sqe->in); + + if (src && req->src) + dma_free_coherent(dev, ctx->key_sz, req->src, dma); + + dma = le64_to_cpu(sqe->out); + + if (req->dst) + dma_free_coherent(dev, ctx->key_sz, req->dst, dma); + if (dst) + dma_unmap_single(dev, dma, ctx->key_sz, DMA_FROM_DEVICE); +} + +static void hpre_curve25519_cb(struct hpre_ctx *ctx, void *resp) +{ + struct hpre_dfx *dfx = ctx->hpre->debug.dfx; + struct hpre_asym_request *req = NULL; + struct kpp_request *areq; + u64 overtime_thrhld; + int ret; + + ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req); + areq = req->areq.curve25519; + areq->dst_len = ctx->key_sz; + + overtime_thrhld = atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value); + if (overtime_thrhld && hpre_is_bd_timeout(req, overtime_thrhld)) + atomic64_inc(&dfx[HPRE_OVER_THRHLD_CNT].value); + + hpre_key_to_big_end(sg_virt(areq->dst), CURVE25519_KEY_SIZE); + + hpre_curve25519_hw_data_clr_all(ctx, req, areq->dst, areq->src); + kpp_request_complete(areq, ret); + + atomic64_inc(&dfx[HPRE_RECV_CNT].value); +} + +static int hpre_curve25519_msg_request_set(struct hpre_ctx *ctx, + struct kpp_request *req) +{ + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; + int req_id; + void *tmp; + + if (unlikely(req->dst_len < ctx->key_sz)) { + req->dst_len = ctx->key_sz; + return -EINVAL; + } + + tmp = kpp_request_ctx(req); + h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); + h_req->cb = hpre_curve25519_cb; + h_req->areq.curve25519 = req; + msg = &h_req->req; + memset(msg, 0, sizeof(*msg)); + msg->key = cpu_to_le64(ctx->curve25519.dma_p); + + msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT); + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + + req_id = hpre_add_req_to_ctx(h_req); + if (req_id < 0) + return -EBUSY; + + msg->tag = cpu_to_le16((u16)req_id); + return 0; +} + +static void hpre_curve25519_src_modulo_p(u8 *ptr) +{ + int i; + + for (i = 0; i < CURVE25519_KEY_SIZE - 1; i++) + ptr[i] = 0; + + /* The modulus is ptr's last byte minus '0xed'(last byte of p) */ + ptr[i] -= 0xed; +} + +static int hpre_curve25519_src_init(struct hpre_asym_request *hpre_req, + struct scatterlist *data, unsigned int len) +{ + struct hpre_sqe *msg = &hpre_req->req; + struct hpre_ctx *ctx = hpre_req->ctx; + struct device *dev = HPRE_DEV(ctx); + u8 p[CURVE25519_KEY_SIZE] = { 0 }; + const struct ecc_curve *curve; + dma_addr_t dma = 0; + u8 *ptr; + + if (len != CURVE25519_KEY_SIZE) { + dev_err(dev, "sourc_data len is not 32bytes, len = %u!\n", len); + return -EINVAL; + } + + ptr = dma_alloc_coherent(dev, ctx->key_sz, &dma, GFP_KERNEL); + if (unlikely(!ptr)) + return -ENOMEM; + + scatterwalk_map_and_copy(ptr, data, 0, len, 0); + + if (!crypto_memneq(ptr, curve25519_null_point, CURVE25519_KEY_SIZE)) { + dev_err(dev, "gx is null!\n"); + goto err; + } + + /* + * Src_data(gx) is in little-endian order, MSB in the final byte should + * be masked as described in RFC7748, then transform it to big-endian + * form, then hisi_hpre can use the data. + */ + ptr[31] &= 0x7f; + hpre_key_to_big_end(ptr, CURVE25519_KEY_SIZE); + + curve = ecc_get_curve25519(); + + fill_curve_param(p, curve->p, CURVE25519_KEY_SIZE, curve->g.ndigits); + + /* + * When src_data equals (2^255 - 19) ~ (2^255 - 1), it is out of p, + * we get its modulus to p, and then use it. + */ + if (memcmp(ptr, p, ctx->key_sz) >= 0) + hpre_curve25519_src_modulo_p(ptr); + + hpre_req->src = ptr; + msg->in = cpu_to_le64(dma); + return 0; + +err: + dma_free_coherent(dev, ctx->key_sz, ptr, dma); + return -EINVAL; +} + +static int hpre_curve25519_dst_init(struct hpre_asym_request *hpre_req, + struct scatterlist *data, unsigned int len) +{ + struct hpre_sqe *msg = &hpre_req->req; + struct hpre_ctx *ctx = hpre_req->ctx; + struct device *dev = HPRE_DEV(ctx); + dma_addr_t dma = 0; + + if (!data || !sg_is_last(data) || len != ctx->key_sz) { + dev_err(dev, "data or data length is illegal!\n"); + return -EINVAL; + } + + hpre_req->dst = NULL; + dma = dma_map_single(dev, sg_virt(data), len, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, dma))) { + dev_err(dev, "dma map data err!\n"); + return -ENOMEM; + } + + msg->out = cpu_to_le64(dma); + return 0; +} + +static int hpre_curve25519_compute_value(struct kpp_request *req) +{ + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + struct device *dev = HPRE_DEV(ctx); + void *tmp = kpp_request_ctx(req); + struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); + struct hpre_sqe *msg = &hpre_req->req; + int ret; + + ret = hpre_curve25519_msg_request_set(ctx, req); + if (unlikely(ret)) { + dev_err(dev, "failed to set curve25519 request, ret = %d!\n", ret); + return ret; + } + + if (req->src) { + ret = hpre_curve25519_src_init(hpre_req, req->src, req->src_len); + if (unlikely(ret)) { + dev_err(dev, "failed to init src data, ret = %d!\n", + ret); + goto clear_all; + } + } else { + msg->in = cpu_to_le64(ctx->curve25519.dma_g); + } + + ret = hpre_curve25519_dst_init(hpre_req, req->dst, req->dst_len); + if (unlikely(ret)) { + dev_err(dev, "failed to init dst data, ret = %d!\n", ret); + goto clear_all; + } + + msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_CURVE25519_MUL); + ret = hpre_send(ctx, msg); + if (likely(!ret)) + return -EINPROGRESS; + +clear_all: + hpre_rm_req_from_ctx(hpre_req); + hpre_curve25519_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + return ret; +} + +static unsigned int hpre_curve25519_max_size(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + return ctx->key_sz; +} + +static int hpre_curve25519_init_tfm(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); +} + +static void hpre_curve25519_exit_tfm(struct crypto_kpp *tfm) +{ + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + hpre_ecc_clear_ctx(ctx, true, false); +} + static struct akcipher_alg rsa = { .sign = hpre_rsa_dec, .verify = hpre_rsa_enc, @@ -1135,7 +1911,6 @@ static struct akcipher_alg rsa = { }, }; -#ifdef CONFIG_CRYPTO_DH static struct kpp_alg dh = { .set_secret = hpre_dh_set_secret, .generate_public_key = hpre_dh_compute_value, @@ -1152,9 +1927,83 @@ static struct kpp_alg dh = { .cra_module = THIS_MODULE, }, }; -#endif -int hpre_algs_register(void) +static struct kpp_alg ecdh_nist_p192 = { + .set_secret = hpre_ecdh_set_secret, + .generate_public_key = hpre_ecdh_compute_value, + .compute_shared_secret = hpre_ecdh_compute_value, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p192_init_tfm, + .exit = hpre_ecdh_exit_tfm, + .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ, + .base = { + .cra_ctxsize = sizeof(struct hpre_ctx), + .cra_priority = HPRE_CRYPTO_ALG_PRI, + .cra_name = "ecdh-nist-p192", + .cra_driver_name = "hpre-ecdh", + .cra_module = THIS_MODULE, + }, +}; + +static struct kpp_alg ecdh_nist_p256 = { + .set_secret = hpre_ecdh_set_secret, + .generate_public_key = hpre_ecdh_compute_value, + .compute_shared_secret = hpre_ecdh_compute_value, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p256_init_tfm, + .exit = hpre_ecdh_exit_tfm, + .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ, + .base = { + .cra_ctxsize = sizeof(struct hpre_ctx), + .cra_priority = HPRE_CRYPTO_ALG_PRI, + .cra_name = "ecdh-nist-p256", + .cra_driver_name = "hpre-ecdh", + .cra_module = THIS_MODULE, + }, +}; + +static struct kpp_alg curve25519_alg = { + .set_secret = hpre_curve25519_set_secret, + .generate_public_key = hpre_curve25519_compute_value, + .compute_shared_secret = hpre_curve25519_compute_value, + .max_size = hpre_curve25519_max_size, + .init = hpre_curve25519_init_tfm, + .exit = hpre_curve25519_exit_tfm, + .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ, + .base = { + .cra_ctxsize = sizeof(struct hpre_ctx), + .cra_priority = HPRE_CRYPTO_ALG_PRI, + .cra_name = "curve25519", + .cra_driver_name = "hpre-curve25519", + .cra_module = THIS_MODULE, + }, +}; + + +static int hpre_register_ecdh(void) +{ + int ret; + + ret = crypto_register_kpp(&ecdh_nist_p192); + if (ret) + return ret; + + ret = crypto_register_kpp(&ecdh_nist_p256); + if (ret) { + crypto_unregister_kpp(&ecdh_nist_p192); + return ret; + } + + return 0; +} + +static void hpre_unregister_ecdh(void) +{ + crypto_unregister_kpp(&ecdh_nist_p256); + crypto_unregister_kpp(&ecdh_nist_p192); +} + +int hpre_algs_register(struct hisi_qm *qm) { int ret; @@ -1162,19 +2011,37 @@ int hpre_algs_register(void) ret = crypto_register_akcipher(&rsa); if (ret) return ret; -#ifdef CONFIG_CRYPTO_DH + ret = crypto_register_kpp(&dh); if (ret) - crypto_unregister_akcipher(&rsa); -#endif + goto unreg_rsa; + + if (qm->ver >= QM_HW_V3) { + ret = hpre_register_ecdh(); + if (ret) + goto unreg_dh; + ret = crypto_register_kpp(&curve25519_alg); + if (ret) + goto unreg_ecdh; + } + return 0; +unreg_ecdh: + hpre_unregister_ecdh(); +unreg_dh: + crypto_unregister_kpp(&dh); +unreg_rsa: + crypto_unregister_akcipher(&rsa); return ret; } -void hpre_algs_unregister(void) +void hpre_algs_unregister(struct hisi_qm *qm) { - crypto_unregister_akcipher(&rsa); -#ifdef CONFIG_CRYPTO_DH + if (qm->ver >= QM_HW_V3) { + crypto_unregister_kpp(&curve25519_alg); + hpre_unregister_ecdh(); + } + crypto_unregister_kpp(&dh); -#endif + crypto_unregister_akcipher(&rsa); } diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index e7a2c70eb9cf52f3cc70d6389418a781a62037e4..046bc962c8b2dd180f0cf856102a143964559a89 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -13,7 +13,6 @@ #include <linux/uacce.h> #include "hpre.h" -#define HPRE_QUEUE_NUM_V2 1024 #define HPRE_QM_ABNML_INT_MASK 0x100004 #define HPRE_CTRL_CNT_CLR_CE_BIT BIT(0) #define HPRE_COMM_CNT_CLR_CE 0x0 @@ -119,7 +118,6 @@ static struct hisi_qm_list hpre_devices = { }; static const char * const hpre_debug_file_name[] = { - [HPRE_CURRENT_QM] = "current_qm", [HPRE_CLEAR_ENABLE] = "rdclr_en", [HPRE_CLUSTER_CTRL] = "cluster_ctrl", }; @@ -226,41 +224,44 @@ static u32 vfs_num; module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444); MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)"); -struct hisi_qp *hpre_create_qp(void) +struct hisi_qp *hpre_create_qp(u8 type) { int node = cpu_to_node(smp_processor_id()); struct hisi_qp *qp = NULL; int ret; - ret = hisi_qm_alloc_qps_node(&hpre_devices, 1, 0, node, &qp); + if (type != HPRE_V2_ALG_TYPE && type != HPRE_V3_ECC_ALG_TYPE) + return NULL; + + /* + * type: 0 - RSA/DH. algorithm supported in V2, + * 1 - ECC algorithm in V3. + */ + ret = hisi_qm_alloc_qps_node(&hpre_devices, 1, type, node, &qp); if (!ret) return qp; return NULL; } -static void hpre_pasid_enable(struct hisi_qm *qm) +static void hpre_config_pasid(struct hisi_qm *qm) { - u32 val; - - val = readl_relaxed(qm->io_base + HPRE_DATA_RUSER_CFG); - val |= BIT(HPRE_PASID_EN_BIT); - writel_relaxed(val, qm->io_base + HPRE_DATA_RUSER_CFG); - val = readl_relaxed(qm->io_base + HPRE_DATA_WUSER_CFG); - val |= BIT(HPRE_PASID_EN_BIT); - writel_relaxed(val, qm->io_base + HPRE_DATA_WUSER_CFG); -} + u32 val1, val2; -static void hpre_pasid_disable(struct hisi_qm *qm) -{ - u32 val; + if (qm->ver >= QM_HW_V3) + return; - val = readl_relaxed(qm->io_base + HPRE_DATA_RUSER_CFG); - val &= ~BIT(HPRE_PASID_EN_BIT); - writel_relaxed(val, qm->io_base + HPRE_DATA_RUSER_CFG); - val = readl_relaxed(qm->io_base + HPRE_DATA_WUSER_CFG); - val &= ~BIT(HPRE_PASID_EN_BIT); - writel_relaxed(val, qm->io_base + HPRE_DATA_WUSER_CFG); + val1 = readl_relaxed(qm->io_base + HPRE_DATA_RUSER_CFG); + val2 = readl_relaxed(qm->io_base + HPRE_DATA_WUSER_CFG); + if (qm->use_sva) { + val1 |= BIT(HPRE_PASID_EN_BIT); + val2 |= BIT(HPRE_PASID_EN_BIT); + } else { + val1 &= ~BIT(HPRE_PASID_EN_BIT); + val2 &= ~BIT(HPRE_PASID_EN_BIT); + } + writel_relaxed(val1, qm->io_base + HPRE_DATA_RUSER_CFG); + writel_relaxed(val2, qm->io_base + HPRE_DATA_WUSER_CFG); } static int hpre_cfg_by_dsm(struct hisi_qm *qm) @@ -320,7 +321,7 @@ static int hpre_set_cluster(struct hisi_qm *qm) } /* - * For Kunpeng 920, we shoul disable FLR triggered by hardware (BME/PM/SRIOV). + * For Kunpeng 920, we should disable FLR triggered by hardware (BME/PM/SRIOV). * Or it may stay in D3 state when we bind and unbind hpre quickly, * as it does FLR triggered by hardware. */ @@ -383,15 +384,14 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) if (qm->ver == QM_HW_V2) { ret = hpre_cfg_by_dsm(qm); if (ret) - dev_err(dev, "acpi_evaluate_dsm err.\n"); + return ret; disable_flr_of_bme(qm); - - /* Enable data buffer pasid */ - if (qm->use_sva) - hpre_pasid_enable(qm); } + /* Config data buffer pasid needed by Kunpeng 920 */ + hpre_config_pasid(qm); + return ret; } @@ -401,10 +401,6 @@ static void hpre_cnt_regs_clear(struct hisi_qm *qm) unsigned long offset; int i; - /* clear current_qm */ - writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF); - writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF); - /* clear clusterX/cluster_ctrl */ for (i = 0; i < clusters_num; i++) { offset = HPRE_CLSTR_BASE + i * HPRE_CLSTR_ADDR_INTRVL; @@ -456,49 +452,6 @@ static inline struct hisi_qm *hpre_file_to_qm(struct hpre_debugfs_file *file) return &hpre->qm; } -static u32 hpre_current_qm_read(struct hpre_debugfs_file *file) -{ - struct hisi_qm *qm = hpre_file_to_qm(file); - - return readl(qm->io_base + QM_DFX_MB_CNT_VF); -} - -static int hpre_current_qm_write(struct hpre_debugfs_file *file, u32 val) -{ - struct hisi_qm *qm = hpre_file_to_qm(file); - u32 num_vfs = qm->vfs_num; - u32 vfq_num, tmp; - - if (val > num_vfs) - return -EINVAL; - - /* According PF or VF Dev ID to calculation curr_qm_qp_num and store */ - if (val == 0) { - qm->debug.curr_qm_qp_num = qm->qp_num; - } else { - vfq_num = (qm->ctrl_qp_num - qm->qp_num) / num_vfs; - if (val == num_vfs) { - qm->debug.curr_qm_qp_num = - qm->ctrl_qp_num - qm->qp_num - (num_vfs - 1) * vfq_num; - } else { - qm->debug.curr_qm_qp_num = vfq_num; - } - } - - writel(val, qm->io_base + QM_DFX_MB_CNT_VF); - writel(val, qm->io_base + QM_DFX_DB_CNT_VF); - - tmp = val | - (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK); - writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN); - - tmp = val | - (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK); - writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN); - - return 0; -} - static u32 hpre_clear_enable_read(struct hpre_debugfs_file *file) { struct hisi_qm *qm = hpre_file_to_qm(file); @@ -519,7 +472,7 @@ static int hpre_clear_enable_write(struct hpre_debugfs_file *file, u32 val) ~HPRE_CTRL_CNT_CLR_CE_BIT) | val; writel(tmp, qm->io_base + HPRE_CTRL_CNT_CLR_CE); - return 0; + return 0; } static u32 hpre_cluster_inqry_read(struct hpre_debugfs_file *file) @@ -541,7 +494,7 @@ static int hpre_cluster_inqry_write(struct hpre_debugfs_file *file, u32 val) writel(val, qm->io_base + offset + HPRE_CLUSTER_INQURY); - return 0; + return 0; } static ssize_t hpre_ctrl_debug_read(struct file *filp, char __user *buf, @@ -554,9 +507,6 @@ static ssize_t hpre_ctrl_debug_read(struct file *filp, char __user *buf, spin_lock_irq(&file->lock); switch (file->type) { - case HPRE_CURRENT_QM: - val = hpre_current_qm_read(file); - break; case HPRE_CLEAR_ENABLE: val = hpre_clear_enable_read(file); break; @@ -597,11 +547,6 @@ static ssize_t hpre_ctrl_debug_write(struct file *filp, const char __user *buf, spin_lock_irq(&file->lock); switch (file->type) { - case HPRE_CURRENT_QM: - ret = hpre_current_qm_write(file, val); - if (ret) - goto err_input; - break; case HPRE_CLEAR_ENABLE: ret = hpre_clear_enable_write(file, val); if (ret) @@ -740,11 +685,6 @@ static int hpre_ctrl_debug_init(struct hisi_qm *qm) { int ret; - ret = hpre_create_debugfs_file(qm, NULL, HPRE_CURRENT_QM, - HPRE_CURRENT_QM); - if (ret) - return ret; - ret = hpre_create_debugfs_file(qm, NULL, HPRE_CLEAR_ENABLE, HPRE_CLEAR_ENABLE); if (ret) @@ -812,9 +752,9 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) } if (pdev->revision >= QM_HW_V3) - qm->algs = "rsa\ndh\necdh\nx25519\nx448\necdsa\nsm2\n"; + qm->algs = "rsa\ndh\necdh\nx25519\nx448\necdsa\nsm2"; else - qm->algs = "rsa\ndh\n"; + qm->algs = "rsa\ndh"; qm->mode = uacce_mode; qm->pdev = pdev; qm->ver = pdev->revision; @@ -867,6 +807,20 @@ static void hpre_open_axi_master_ooo(struct hisi_qm *qm) HPRE_ADDR(qm, HPRE_AM_OOO_SHUTDOWN_ENB)); } +static void hpre_err_info_init(struct hisi_qm *qm) +{ + struct hisi_qm_err_info *err_info = &qm->err_info; + + err_info->ce = QM_BASE_CE; + err_info->fe = 0; + err_info->ecc_2bits_mask = HPRE_CORE_ECC_2BIT_ERR | + HPRE_OOO_ECC_2BIT_ERR; + err_info->dev_ce_mask = HPRE_HAC_RAS_CE_ENABLE; + err_info->msi_wr_port = HPRE_WR_MSI_PORT; + err_info->acpi_rst = "HRST"; + err_info->nfe = QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT; +} + static const struct hisi_qm_err_ini hpre_err_ini = { .hw_init = hpre_set_user_domain_and_cache, .hw_err_enable = hpre_hw_error_enable, @@ -875,16 +829,7 @@ static const struct hisi_qm_err_ini hpre_err_ini = { .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, - .err_info = { - .ce = QM_BASE_CE, - .nfe = QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT, - .fe = 0, - .ecc_2bits_mask = HPRE_CORE_ECC_2BIT_ERR | - HPRE_OOO_ECC_2BIT_ERR, - .dev_ce_mask = HPRE_HAC_RAS_CE_ENABLE, - .msi_wr_port = HPRE_WR_MSI_PORT, - .acpi_rst = "HRST", - } + .err_info_init = hpre_err_info_init, }; static int hpre_pf_probe_init(struct hpre *hpre) @@ -892,13 +837,12 @@ static int hpre_pf_probe_init(struct hpre *hpre) struct hisi_qm *qm = &hpre->qm; int ret; - qm->ctrl_qp_num = HPRE_QUEUE_NUM_V2; - ret = hpre_set_user_domain_and_cache(qm); if (ret) return ret; qm->err_ini = &hpre_err_ini; + qm->err_ini->err_info_init(qm); hisi_qm_dev_err_init(qm); return 0; @@ -1006,8 +950,6 @@ static void hpre_remove(struct pci_dev *pdev) hisi_qm_stop(qm, QM_NORMAL); if (qm->fun_type == QM_HW_PF) { - if (qm->use_sva && qm->ver == QM_HW_V2) - hpre_pasid_disable(qm); hpre_cnt_regs_clear(qm); qm->debug.curr_qm_qp_num = 0; hisi_qm_dev_err_uninit(qm); @@ -1016,7 +958,6 @@ static void hpre_remove(struct pci_dev *pdev) hisi_qm_uninit(qm); } - static const struct pci_error_handlers hpre_err_handler = { .error_detected = hisi_qm_dev_err_detected, .slot_reset = hisi_qm_dev_slot_reset, @@ -1075,4 +1016,5 @@ module_exit(hpre_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>"); +MODULE_AUTHOR("Meng Yu <yumeng18@huawei.com>"); MODULE_DESCRIPTION("Driver for HiSilicon HPRE accelerator"); diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 13cb4216561a08d8e671f58cc14ee113856fe3bd..ce439a0c66c9ed534ebab22ec6261c66f60ffa86 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -38,6 +38,7 @@ #define QM_MB_CMD_SQC_BT 0x4 #define QM_MB_CMD_CQC_BT 0x5 #define QM_MB_CMD_SQC_VFT_V2 0x6 +#define QM_MB_CMD_STOP_QP 0x8 #define QM_MB_CMD_SEND_BASE 0x300 #define QM_MB_EVENT_SHIFT 8 @@ -93,6 +94,12 @@ #define QM_DB_PRIORITY_SHIFT_V1 48 #define QM_DOORBELL_SQ_CQ_BASE_V2 0x1000 #define QM_DOORBELL_EQ_AEQ_BASE_V2 0x2000 +#define QM_QUE_ISO_CFG_V 0x0030 +#define QM_QUE_ISO_EN 0x100154 +#define QM_CAPBILITY 0x100158 +#define QM_QP_NUN_MASK GENMASK(10, 0) +#define QM_QP_DB_INTERVAL 0x10000 +#define QM_QP_MAX_NUM_SHIFT 11 #define QM_DB_CMD_SHIFT_V2 12 #define QM_DB_RAND_SHIFT_V2 16 #define QM_DB_INDEX_SHIFT_V2 32 @@ -129,9 +136,9 @@ #define QM_DFX_CNT_CLR_CE 0x100118 #define QM_ABNORMAL_INT_SOURCE 0x100000 -#define QM_ABNORMAL_INT_SOURCE_CLR GENMASK(12, 0) +#define QM_ABNORMAL_INT_SOURCE_CLR GENMASK(14, 0) #define QM_ABNORMAL_INT_MASK 0x100004 -#define QM_ABNORMAL_INT_MASK_VALUE 0x1fff +#define QM_ABNORMAL_INT_MASK_VALUE 0x7fff #define QM_ABNORMAL_INT_STATUS 0x100008 #define QM_ABNORMAL_INT_SET 0x10000c #define QM_ABNORMAL_INF00 0x100010 @@ -164,6 +171,14 @@ #define ACC_AM_ROB_ECC_INT_STS 0x300104 #define ACC_ROB_ECC_ERR_MULTPL BIT(1) +#define QM_DFX_MB_CNT_VF 0x104010 +#define QM_DFX_DB_CNT_VF 0x104020 +#define QM_DFX_SQE_CNT_VF_SQN 0x104030 +#define QM_DFX_CQE_CNT_VF_CQN 0x104040 +#define QM_DFX_QN_SHIFT 16 +#define CURRENT_FUN_MASK GENMASK(5, 0) +#define CURRENT_Q_MASK GENMASK(31, 16) + #define POLL_PERIOD 10 #define POLL_TIMEOUT 1000 #define WAIT_PERIOD_US_MAX 200 @@ -173,6 +188,7 @@ #define QM_CACHE_WB_DONE 0x208 #define PCI_BAR_2 2 +#define PCI_BAR_4 4 #define QM_SQE_DATA_ALIGN_MASK GENMASK(6, 0) #define QMC_ALIGN(sz) ALIGN(sz, 32) @@ -334,6 +350,7 @@ struct hisi_qm_hw_ops { void (*hw_error_init)(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe); void (*hw_error_uninit)(struct hisi_qm *qm); enum acc_err_result (*hw_error_handle)(struct hisi_qm *qm); + int (*stop_qp)(struct hisi_qp *qp); }; struct qm_dfx_item { @@ -350,6 +367,7 @@ static struct qm_dfx_item qm_dfx_files[] = { }; static const char * const qm_debug_file_name[] = { + [CURRENT_QM] = "current_qm", [CURRENT_Q] = "current_q", [CLEAR_ENABLE] = "clear_enable", }; @@ -373,6 +391,8 @@ static const struct hisi_qm_hw_error qm_hw_error[] = { { .int_msk = BIT(10), .msg = "qm_db_timeout" }, { .int_msk = BIT(11), .msg = "qm_of_fifo_of" }, { .int_msk = BIT(12), .msg = "qm_db_random_invalid" }, + { .int_msk = BIT(13), .msg = "qm_mailbox_timeout" }, + { .int_msk = BIT(14), .msg = "qm_flr_timeout" }, { /* sentinel */ } }; @@ -557,21 +577,22 @@ static void qm_db_v1(struct hisi_qm *qm, u16 qn, u8 cmd, u16 index, u8 priority) static void qm_db_v2(struct hisi_qm *qm, u16 qn, u8 cmd, u16 index, u8 priority) { - u64 doorbell; - u64 dbase; + void __iomem *io_base = qm->io_base; u16 randata = 0; + u64 doorbell; if (cmd == QM_DOORBELL_CMD_SQ || cmd == QM_DOORBELL_CMD_CQ) - dbase = QM_DOORBELL_SQ_CQ_BASE_V2; + io_base = qm->db_io_base + (u64)qn * qm->db_interval + + QM_DOORBELL_SQ_CQ_BASE_V2; else - dbase = QM_DOORBELL_EQ_AEQ_BASE_V2; + io_base += QM_DOORBELL_EQ_AEQ_BASE_V2; doorbell = qn | ((u64)cmd << QM_DB_CMD_SHIFT_V2) | ((u64)randata << QM_DB_RAND_SHIFT_V2) | ((u64)index << QM_DB_INDEX_SHIFT_V2) | ((u64)priority << QM_DB_PRIORITY_SHIFT_V2); - writeq(doorbell, qm->io_base + dbase); + writeq(doorbell, io_base); } static void qm_db(struct hisi_qm *qm, u16 qn, u8 cmd, u16 index, u8 priority) @@ -865,6 +886,26 @@ static int qm_get_vft_v2(struct hisi_qm *qm, u32 *base, u32 *number) return 0; } +static int qm_get_vf_qp_num(struct hisi_qm *qm, u32 fun_num) +{ + u32 remain_q_num, vfq_num; + u32 num_vfs = qm->vfs_num; + + vfq_num = (qm->ctrl_qp_num - qm->qp_num) / num_vfs; + if (vfq_num >= qm->max_qp_num) + return qm->max_qp_num; + + remain_q_num = (qm->ctrl_qp_num - qm->qp_num) % num_vfs; + if (vfq_num + remain_q_num <= qm->max_qp_num) + return fun_num == num_vfs ? vfq_num + remain_q_num : vfq_num; + + /* + * if vfq_num + remain_q_num > max_qp_num, the last VFs, + * each with one more queue. + */ + return fun_num + remain_q_num > num_vfs ? vfq_num + 1 : vfq_num; +} + static struct hisi_qm *file_to_qm(struct debugfs_file *file) { struct qm_debug *debug = file->debug; @@ -918,6 +959,41 @@ static int clear_enable_write(struct debugfs_file *file, u32 rd_clr_ctrl) return 0; } +static u32 current_qm_read(struct debugfs_file *file) +{ + struct hisi_qm *qm = file_to_qm(file); + + return readl(qm->io_base + QM_DFX_MB_CNT_VF); +} + +static int current_qm_write(struct debugfs_file *file, u32 val) +{ + struct hisi_qm *qm = file_to_qm(file); + u32 tmp; + + if (val > qm->vfs_num) + return -EINVAL; + + /* According PF or VF Dev ID to calculation curr_qm_qp_num and store */ + if (!val) + qm->debug.curr_qm_qp_num = qm->qp_num; + else + qm->debug.curr_qm_qp_num = qm_get_vf_qp_num(qm, val); + + writel(val, qm->io_base + QM_DFX_MB_CNT_VF); + writel(val, qm->io_base + QM_DFX_DB_CNT_VF); + + tmp = val | + (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK); + writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN); + + tmp = val | + (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK); + writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN); + + return 0; +} + static ssize_t qm_debug_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { @@ -929,6 +1005,9 @@ static ssize_t qm_debug_read(struct file *filp, char __user *buf, mutex_lock(&file->lock); switch (index) { + case CURRENT_QM: + val = current_qm_read(file); + break; case CURRENT_Q: val = current_q_read(file); break; @@ -971,27 +1050,24 @@ static ssize_t qm_debug_write(struct file *filp, const char __user *buf, mutex_lock(&file->lock); switch (index) { + case CURRENT_QM: + ret = current_qm_write(file, val); + break; case CURRENT_Q: ret = current_q_write(file, val); - if (ret) - goto err_input; break; case CLEAR_ENABLE: ret = clear_enable_write(file, val); - if (ret) - goto err_input; break; default: ret = -EINVAL; - goto err_input; } mutex_unlock(&file->lock); - return count; + if (ret) + return ret; -err_input: - mutex_unlock(&file->lock); - return ret; + return count; } static const struct file_operations qm_debug_fops = { @@ -1529,12 +1605,12 @@ static const struct file_operations qm_cmd_fops = { .write = qm_cmd_write, }; -static void qm_create_debugfs_file(struct hisi_qm *qm, enum qm_debug_file index) +static void qm_create_debugfs_file(struct hisi_qm *qm, struct dentry *dir, + enum qm_debug_file index) { - struct dentry *qm_d = qm->debug.qm_d; struct debugfs_file *file = qm->debug.files + index; - debugfs_create_file(qm_debug_file_name[index], 0600, qm_d, file, + debugfs_create_file(qm_debug_file_name[index], 0600, dir, file, &qm_debug_fops); file->index = index; @@ -1628,7 +1704,7 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) if (val == (QM_DB_RANDOM_INVALID | QM_BASE_CE)) { writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); - writel(qm->err_ini->err_info.nfe, + writel(qm->err_info.nfe, qm->io_base + QM_RAS_NFE_ENABLE); return ACC_ERR_RECOVERED; } @@ -1639,6 +1715,11 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) return ACC_ERR_RECOVERED; } +static int qm_stop_qp(struct hisi_qp *qp) +{ + return qm_mb(qp->qm, QM_MB_CMD_STOP_QP, 0, qp->qp_id, 0); +} + static const struct hisi_qm_hw_ops qm_hw_ops_v1 = { .qm_db = qm_db_v1, .get_irq_num = qm_get_irq_num_v1, @@ -1654,6 +1735,16 @@ static const struct hisi_qm_hw_ops qm_hw_ops_v2 = { .hw_error_handle = qm_hw_error_handle_v2, }; +static const struct hisi_qm_hw_ops qm_hw_ops_v3 = { + .get_vft = qm_get_vft_v2, + .qm_db = qm_db_v2, + .get_irq_num = qm_get_irq_num_v2, + .hw_error_init = qm_hw_error_init_v2, + .hw_error_uninit = qm_hw_error_uninit_v2, + .hw_error_handle = qm_hw_error_handle_v2, + .stop_qp = qm_stop_qp, +}; + static void *qm_get_avail_sqe(struct hisi_qp *qp) { struct hisi_qp_status *qp_status = &qp->qp_status; @@ -1933,6 +2024,14 @@ static int qm_drain_qp(struct hisi_qp *qp) if (qm->err_status.is_qm_ecc_mbit || qm->err_status.is_dev_ecc_mbit) return 0; + /* Kunpeng930 supports drain qp by device */ + if (qm->ops->stop_qp) { + ret = qm->ops->stop_qp(qp); + if (ret) + dev_err(dev, "Failed to stop qp(%u)!\n", qp->qp_id); + return ret; + } + addr = qm_ctx_alloc(qm, size, &dma_addr); if (IS_ERR(addr)) { dev_err(dev, "Failed to alloc ctx for sqc and cqc!\n"); @@ -2132,6 +2231,8 @@ static int hisi_qm_uacce_mmap(struct uacce_queue *q, { struct hisi_qp *qp = q->priv; struct hisi_qm *qm = qp->qm; + resource_size_t phys_base = qm->db_phys_base + + qp->qp_id * qm->db_interval; size_t sz = vma->vm_end - vma->vm_start; struct pci_dev *pdev = qm->pdev; struct device *dev = &pdev->dev; @@ -2143,16 +2244,19 @@ static int hisi_qm_uacce_mmap(struct uacce_queue *q, if (qm->ver == QM_HW_V1) { if (sz > PAGE_SIZE * QM_DOORBELL_PAGE_NR) return -EINVAL; - } else { + } else if (qm->ver == QM_HW_V2 || !qm->use_db_isolation) { if (sz > PAGE_SIZE * (QM_DOORBELL_PAGE_NR + QM_DOORBELL_SQ_CQ_BASE_V2 / PAGE_SIZE)) return -EINVAL; + } else { + if (sz > qm->db_interval) + return -EINVAL; } vma->vm_flags |= VM_IO; return remap_pfn_range(vma, vma->vm_start, - qm->phys_base >> PAGE_SHIFT, + phys_base >> PAGE_SHIFT, sz, pgprot_noncached(vma->vm_page_prot)); case UACCE_QFRT_DUS: if (sz != qp->qdma.size) @@ -2267,14 +2371,20 @@ static int qm_alloc_uacce(struct hisi_qm *qm) uacce->priv = qm; uacce->algs = qm->algs; - if (qm->ver == QM_HW_V1) { - mmio_page_nr = QM_DOORBELL_PAGE_NR; + if (qm->ver == QM_HW_V1) uacce->api_ver = HISI_QM_API_VER_BASE; - } else { + else if (qm->ver == QM_HW_V2) + uacce->api_ver = HISI_QM_API_VER2_BASE; + else + uacce->api_ver = HISI_QM_API_VER3_BASE; + + if (qm->ver == QM_HW_V1) + mmio_page_nr = QM_DOORBELL_PAGE_NR; + else if (qm->ver == QM_HW_V2 || !qm->use_db_isolation) mmio_page_nr = QM_DOORBELL_PAGE_NR + QM_DOORBELL_SQ_CQ_BASE_V2 / PAGE_SIZE; - uacce->api_ver = HISI_QM_API_VER2_BASE; - } + else + mmio_page_nr = qm->db_interval / PAGE_SIZE; dus_page_nr = (PAGE_SIZE - 1 + qm->sqe_size * QM_Q_DEPTH + sizeof(struct qm_cqe) * QM_Q_DEPTH) >> PAGE_SHIFT; @@ -2482,8 +2592,10 @@ static void hisi_qm_pre_init(struct hisi_qm *qm) if (qm->ver == QM_HW_V1) qm->ops = &qm_hw_ops_v1; - else + else if (qm->ver == QM_HW_V2) qm->ops = &qm_hw_ops_v2; + else + qm->ops = &qm_hw_ops_v3; pci_set_drvdata(pdev, qm); mutex_init(&qm->mailbox_lock); @@ -2492,13 +2604,23 @@ static void hisi_qm_pre_init(struct hisi_qm *qm) qm->misc_ctl = false; } -static void hisi_qm_pci_uninit(struct hisi_qm *qm) +static void qm_put_pci_res(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; - pci_free_irq_vectors(pdev); + if (qm->use_db_isolation) + iounmap(qm->db_io_base); + iounmap(qm->io_base); pci_release_mem_regions(pdev); +} + +static void hisi_qm_pci_uninit(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + + pci_free_irq_vectors(pdev); + qm_put_pci_res(qm); pci_disable_device(pdev); } @@ -2527,7 +2649,6 @@ void hisi_qm_uninit(struct hisi_qm *qm) hisi_qm_cache_wb(qm); dma_free_coherent(dev, qm->qdma.size, qm->qdma.va, qm->qdma.dma); - memset(&qm->qdma, 0, sizeof(qm->qdma)); } qm_irq_unregister(qm); @@ -2681,7 +2802,7 @@ static int __hisi_qm_start(struct hisi_qm *qm) { int ret; - WARN_ON(!qm->qdma.dma); + WARN_ON(!qm->qdma.va); if (qm->fun_type == QM_HW_PF) { ret = qm_dev_mem_reset(qm); @@ -2930,9 +3051,11 @@ void hisi_qm_debug_init(struct hisi_qm *qm) qm->debug.qm_d = qm_d; /* only show this in PF */ - if (qm->fun_type == QM_HW_PF) + if (qm->fun_type == QM_HW_PF) { + qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM); for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++) - qm_create_debugfs_file(qm, i); + qm_create_debugfs_file(qm, qm_d, i); + } debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops); @@ -2960,6 +3083,10 @@ void hisi_qm_debug_regs_clear(struct hisi_qm *qm) struct qm_dfx_registers *regs; int i; + /* clear current_qm */ + writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF); + writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF); + /* clear current_q */ writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN); writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN); @@ -2982,7 +3109,7 @@ EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear); static void qm_hw_error_init(struct hisi_qm *qm) { - const struct hisi_qm_err_info *err_info = &qm->err_ini->err_info; + struct hisi_qm_err_info *err_info = &qm->err_info; if (!qm->ops->hw_error_init) { dev_err(&qm->pdev->dev, "QM doesn't support hw error handling!\n"); @@ -3175,30 +3302,46 @@ EXPORT_SYMBOL_GPL(hisi_qm_alloc_qps_node); static int qm_vf_q_assign(struct hisi_qm *qm, u32 num_vfs) { - u32 remain_q_num, q_num, i, j; + u32 remain_q_num, vfs_q_num, act_q_num, q_num, i, j; + u32 max_qp_num = qm->max_qp_num; u32 q_base = qm->qp_num; int ret; if (!num_vfs) return -EINVAL; - remain_q_num = qm->ctrl_qp_num - qm->qp_num; + vfs_q_num = qm->ctrl_qp_num - qm->qp_num; - /* If remain queues not enough, return error. */ - if (qm->ctrl_qp_num < qm->qp_num || remain_q_num < num_vfs) + /* If vfs_q_num is less than num_vfs, return error. */ + if (vfs_q_num < num_vfs) return -EINVAL; - q_num = remain_q_num / num_vfs; - for (i = 1; i <= num_vfs; i++) { - if (i == num_vfs) - q_num += remain_q_num % num_vfs; - ret = hisi_qm_set_vft(qm, i, q_base, q_num); + q_num = vfs_q_num / num_vfs; + remain_q_num = vfs_q_num % num_vfs; + + for (i = num_vfs; i > 0; i--) { + /* + * if q_num + remain_q_num > max_qp_num in last vf, divide the + * remaining queues equally. + */ + if (i == num_vfs && q_num + remain_q_num <= max_qp_num) { + act_q_num = q_num + remain_q_num; + remain_q_num = 0; + } else if (remain_q_num > 0) { + act_q_num = q_num + 1; + remain_q_num--; + } else { + act_q_num = q_num; + } + + act_q_num = min_t(int, act_q_num, max_qp_num); + ret = hisi_qm_set_vft(qm, i, q_base, act_q_num); if (ret) { - for (j = i; j > 0; j--) + for (j = num_vfs; j > i; j--) hisi_qm_set_vft(qm, j, 0, 0); return ret; } - q_base += q_num; + q_base += act_q_num; } return 0; @@ -3318,15 +3461,15 @@ static enum acc_err_result qm_dev_err_handle(struct hisi_qm *qm) /* get device hardware error status */ err_sts = qm->err_ini->get_dev_hw_err_status(qm); if (err_sts) { - if (err_sts & qm->err_ini->err_info.ecc_2bits_mask) + 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); /* ce error does not need to be reset */ - if ((err_sts | qm->err_ini->err_info.dev_ce_mask) == - qm->err_ini->err_info.dev_ce_mask) { + if ((err_sts | qm->err_info.dev_ce_mask) == + qm->err_info.dev_ce_mask) { if (qm->err_ini->clear_dev_hw_err_status) qm->err_ini->clear_dev_hw_err_status(qm, err_sts); @@ -3639,7 +3782,7 @@ static int qm_soft_reset(struct hisi_qm *qm) acpi_status s; s = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev), - qm->err_ini->err_info.acpi_rst, + qm->err_info.acpi_rst, NULL, &value); if (ACPI_FAILURE(s)) { pci_err(pdev, "NO controller reset method!\n"); @@ -3707,12 +3850,11 @@ static void qm_restart_prepare(struct hisi_qm *qm) /* temporarily close the OOO port used for PEH to write out MSI */ value = readl(qm->io_base + ACC_AM_CFG_PORT_WR_EN); - writel(value & ~qm->err_ini->err_info.msi_wr_port, + writel(value & ~qm->err_info.msi_wr_port, qm->io_base + ACC_AM_CFG_PORT_WR_EN); /* clear dev ecc 2bit error source if having */ - value = qm_get_dev_err_status(qm) & - qm->err_ini->err_info.ecc_2bits_mask; + value = qm_get_dev_err_status(qm) & qm->err_info.ecc_2bits_mask; if (value && qm->err_ini->clear_dev_hw_err_status) qm->err_ini->clear_dev_hw_err_status(qm, value); @@ -3736,7 +3878,7 @@ static void qm_restart_done(struct hisi_qm *qm) /* open the OOO port for PEH to write out MSI */ value = readl(qm->io_base + ACC_AM_CFG_PORT_WR_EN); - value |= qm->err_ini->err_info.msi_wr_port; + value |= qm->err_info.msi_wr_port; writel(value, qm->io_base + ACC_AM_CFG_PORT_WR_EN); qm->err_status.is_qm_ecc_mbit = false; @@ -3875,8 +4017,7 @@ static int qm_check_dev_error(struct hisi_qm *qm) if (ret) return ret; - return (qm_get_dev_err_status(qm) & - qm->err_ini->err_info.ecc_2bits_mask); + return (qm_get_dev_err_status(qm) & qm->err_info.ecc_2bits_mask); } void hisi_qm_reset_prepare(struct pci_dev *pdev) @@ -4084,7 +4225,7 @@ int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list) mutex_unlock(&qm_list->lock); if (flag) { - ret = qm_list->register_to_crypto(); + ret = qm_list->register_to_crypto(qm); if (ret) { mutex_lock(&qm_list->lock); list_del(&qm->list); @@ -4115,59 +4256,134 @@ void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list) mutex_unlock(&qm_list->lock); if (list_empty(&qm_list->list)) - qm_list->unregister_from_crypto(); + qm_list->unregister_from_crypto(qm); } EXPORT_SYMBOL_GPL(hisi_qm_alg_unregister); -static int hisi_qm_pci_init(struct hisi_qm *qm) +static int qm_get_qp_num(struct hisi_qm *qm) +{ + if (qm->ver == QM_HW_V1) + qm->ctrl_qp_num = QM_QNUM_V1; + else if (qm->ver == QM_HW_V2) + qm->ctrl_qp_num = QM_QNUM_V2; + else + qm->ctrl_qp_num = readl(qm->io_base + QM_CAPBILITY) & + QM_QP_NUN_MASK; + + if (qm->use_db_isolation) + qm->max_qp_num = (readl(qm->io_base + QM_CAPBILITY) >> + QM_QP_MAX_NUM_SHIFT) & QM_QP_NUN_MASK; + else + qm->max_qp_num = qm->ctrl_qp_num; + + /* check if qp number is valid */ + if (qm->qp_num > qm->max_qp_num) { + dev_err(&qm->pdev->dev, "qp num(%u) is more than max qp num(%u)!\n", + qm->qp_num, qm->max_qp_num); + return -EINVAL; + } + + return 0; +} + +static int qm_get_pci_res(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; struct device *dev = &pdev->dev; - unsigned int num_vec; int ret; - ret = pci_enable_device_mem(pdev); - if (ret < 0) { - dev_err(dev, "Failed to enable device mem!\n"); - return ret; - } - ret = pci_request_mem_regions(pdev, qm->dev_name); if (ret < 0) { dev_err(dev, "Failed to request mem regions!\n"); - goto err_disable_pcidev; + return ret; } qm->phys_base = pci_resource_start(pdev, PCI_BAR_2); - qm->phys_size = pci_resource_len(qm->pdev, PCI_BAR_2); - qm->io_base = ioremap(qm->phys_base, qm->phys_size); + qm->io_base = ioremap(qm->phys_base, pci_resource_len(pdev, PCI_BAR_2)); if (!qm->io_base) { ret = -EIO; - goto err_release_mem_regions; + goto err_request_mem_regions; + } + + if (qm->ver > QM_HW_V2) { + if (qm->fun_type == QM_HW_PF) + qm->use_db_isolation = readl(qm->io_base + + QM_QUE_ISO_EN) & BIT(0); + else + qm->use_db_isolation = readl(qm->io_base + + QM_QUE_ISO_CFG_V) & BIT(0); + } + + if (qm->use_db_isolation) { + qm->db_interval = QM_QP_DB_INTERVAL; + qm->db_phys_base = pci_resource_start(pdev, PCI_BAR_4); + qm->db_io_base = ioremap(qm->db_phys_base, + pci_resource_len(pdev, PCI_BAR_4)); + if (!qm->db_io_base) { + ret = -EIO; + goto err_ioremap; + } + } else { + qm->db_phys_base = qm->phys_base; + qm->db_io_base = qm->io_base; + qm->db_interval = 0; } + if (qm->fun_type == QM_HW_PF) { + ret = qm_get_qp_num(qm); + if (ret) + goto err_db_ioremap; + } + + return 0; + +err_db_ioremap: + if (qm->use_db_isolation) + iounmap(qm->db_io_base); +err_ioremap: + iounmap(qm->io_base); +err_request_mem_regions: + pci_release_mem_regions(pdev); + return ret; +} + +static int hisi_qm_pci_init(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + unsigned int num_vec; + int ret; + + ret = pci_enable_device_mem(pdev); + if (ret < 0) { + dev_err(dev, "Failed to enable device mem!\n"); + return ret; + } + + ret = qm_get_pci_res(qm); + if (ret) + goto err_disable_pcidev; + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret < 0) - goto err_iounmap; + goto err_get_pci_res; pci_set_master(pdev); if (!qm->ops->get_irq_num) { ret = -EOPNOTSUPP; - goto err_iounmap; + goto err_get_pci_res; } num_vec = qm->ops->get_irq_num(qm); ret = pci_alloc_irq_vectors(pdev, num_vec, num_vec, PCI_IRQ_MSI); if (ret < 0) { dev_err(dev, "Failed to enable MSI vectors!\n"); - goto err_iounmap; + goto err_get_pci_res; } return 0; -err_iounmap: - iounmap(qm->io_base); -err_release_mem_regions: - pci_release_mem_regions(pdev); +err_get_pci_res: + qm_put_pci_res(qm); err_disable_pcidev: pci_disable_device(pdev); return ret; @@ -4187,28 +4403,28 @@ int hisi_qm_init(struct hisi_qm *qm) hisi_qm_pre_init(qm); - ret = qm_alloc_uacce(qm); - if (ret < 0) - dev_warn(dev, "fail to alloc uacce (%d)\n", ret); - ret = hisi_qm_pci_init(qm); if (ret) - goto err_remove_uacce; + return ret; ret = qm_irq_register(qm); if (ret) - goto err_pci_uninit; + goto err_pci_init; if (qm->fun_type == QM_HW_VF && qm->ver != QM_HW_V1) { /* v2 starts to support get vft by mailbox */ ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num); if (ret) - goto err_irq_unregister; + goto err_irq_register; } + ret = qm_alloc_uacce(qm); + if (ret < 0) + dev_warn(dev, "fail to alloc uacce (%d)\n", ret); + ret = hisi_qm_memory_init(qm); if (ret) - goto err_irq_unregister; + goto err_alloc_uacce; INIT_WORK(&qm->work, qm_work_process); if (qm->fun_type == QM_HW_PF) @@ -4218,13 +4434,13 @@ int hisi_qm_init(struct hisi_qm *qm) return 0; -err_irq_unregister: - qm_irq_unregister(qm); -err_pci_uninit: - hisi_qm_pci_uninit(qm); -err_remove_uacce: +err_alloc_uacce: uacce_remove(qm->uacce); qm->uacce = NULL; +err_irq_register: + qm_irq_unregister(qm); +err_pci_init: + hisi_qm_pci_uninit(qm); return ret; } EXPORT_SYMBOL_GPL(hisi_qm_init); diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h index 54967c6b9c78874ff1ed18c9131892b812c8f0b8..acefdf8b3a50e7f5718c113cbe5efa4ab3a0cb73 100644 --- a/drivers/crypto/hisilicon/qm.h +++ b/drivers/crypto/hisilicon/qm.h @@ -51,14 +51,6 @@ #define PEH_AXUSER_CFG 0x401001 #define PEH_AXUSER_CFG_ENABLE 0xffffffff -#define QM_DFX_MB_CNT_VF 0x104010 -#define QM_DFX_DB_CNT_VF 0x104020 -#define QM_DFX_SQE_CNT_VF_SQN 0x104030 -#define QM_DFX_CQE_CNT_VF_CQN 0x104040 -#define QM_DFX_QN_SHIFT 16 -#define CURRENT_FUN_MASK GENMASK(5, 0) -#define CURRENT_Q_MASK GENMASK(31, 16) - #define QM_AXI_RRESP BIT(0) #define QM_AXI_BRESP BIT(1) #define QM_ECC_MBIT BIT(2) @@ -72,10 +64,13 @@ #define QM_DB_TIMEOUT BIT(10) #define QM_OF_FIFO_OF BIT(11) #define QM_DB_RANDOM_INVALID BIT(12) +#define QM_MAILBOX_TIMEOUT BIT(13) +#define QM_FLR_TIMEOUT BIT(14) #define QM_BASE_NFE (QM_AXI_RRESP | QM_AXI_BRESP | QM_ECC_MBIT | \ QM_ACC_GET_TASK_TIMEOUT | QM_DB_TIMEOUT | \ - QM_OF_FIFO_OF | QM_DB_RANDOM_INVALID) + QM_OF_FIFO_OF | QM_DB_RANDOM_INVALID | \ + QM_MAILBOX_TIMEOUT | QM_FLR_TIMEOUT) #define QM_BASE_CE QM_ECC_1BIT #define QM_Q_DEPTH 1024 @@ -123,6 +118,7 @@ enum qm_fun_type { }; enum qm_debug_file { + CURRENT_QM, CURRENT_Q, CLEAR_ENABLE, DEBUG_FILE_NUM, @@ -193,14 +189,14 @@ struct hisi_qm_err_ini { void (*open_axi_master_ooo)(struct hisi_qm *qm); void (*close_axi_master_ooo)(struct hisi_qm *qm); void (*log_dev_hw_err)(struct hisi_qm *qm, u32 err_sts); - struct hisi_qm_err_info err_info; + void (*err_info_init)(struct hisi_qm *qm); }; struct hisi_qm_list { struct mutex lock; struct list_head list; - int (*register_to_crypto)(void); - void (*unregister_from_crypto)(void); + int (*register_to_crypto)(struct hisi_qm *qm); + void (*unregister_from_crypto)(struct hisi_qm *qm); }; struct hisi_qm { @@ -209,12 +205,15 @@ struct hisi_qm { const char *dev_name; struct pci_dev *pdev; void __iomem *io_base; + void __iomem *db_io_base; u32 sqe_size; u32 qp_base; u32 qp_num; u32 qp_in_used; u32 ctrl_qp_num; + u32 max_qp_num; u32 vfs_num; + u32 db_interval; struct list_head list; struct hisi_qm_list *qm_list; @@ -230,6 +229,7 @@ struct hisi_qm { struct hisi_qm_status status; const struct hisi_qm_err_ini *err_ini; + struct hisi_qm_err_info err_info; struct hisi_qm_err_status err_status; unsigned long misc_ctl; /* driver removing and reset sched */ @@ -252,8 +252,11 @@ struct hisi_qm { const char *algs; bool use_sva; bool is_frozen; + + /* doorbell isolation enable */ + bool use_db_isolation; resource_size_t phys_base; - resource_size_t phys_size; + resource_size_t db_phys_base; struct uacce_device *uacce; int mode; }; diff --git a/drivers/crypto/hisilicon/sec/sec_algs.c b/drivers/crypto/hisilicon/sec/sec_algs.c index 8ca945ac297ef2d2c6584d2184dc96eff81b1ed5..0a3c8f019b02518ff108492bd87ddcb9fe8cc056 100644 --- a/drivers/crypto/hisilicon/sec/sec_algs.c +++ b/drivers/crypto/hisilicon/sec/sec_algs.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2016-2017 Hisilicon Limited. */ +/* Copyright (c) 2016-2017 HiSilicon Limited. */ #include <linux/crypto.h> #include <linux/dma-mapping.h> #include <linux/dmapool.h> diff --git a/drivers/crypto/hisilicon/sec/sec_drv.c b/drivers/crypto/hisilicon/sec/sec_drv.c index 91ee2bb575df2fd8e9c4557dd2d96f5e62ff5ff1..c8de1b51c843068fba4fcc0d0aadc4a075f490a0 100644 --- a/drivers/crypto/hisilicon/sec/sec_drv.c +++ b/drivers/crypto/hisilicon/sec/sec_drv.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Driver for the Hisilicon SEC units found on Hip06 Hip07 + * Driver for the HiSilicon SEC units found on Hip06 Hip07 * - * Copyright (c) 2016-2017 Hisilicon Limited. + * Copyright (c) 2016-2017 HiSilicon Limited. */ #include <linux/acpi.h> #include <linux/atomic.h> @@ -233,7 +233,7 @@ static int sec_queue_map_io(struct sec_queue *queue) IORESOURCE_MEM, 2 + queue->queue_id); if (!res) { - dev_err(dev, "Failed to get queue %d memory resource\n", + dev_err(dev, "Failed to get queue %u memory resource\n", queue->queue_id); return -ENOMEM; } @@ -653,12 +653,12 @@ static int sec_queue_free(struct sec_queue *queue) struct sec_dev_info *info = queue->dev_info; if (queue->queue_id >= SEC_Q_NUM) { - dev_err(info->dev, "No queue %d\n", queue->queue_id); + dev_err(info->dev, "No queue %u\n", queue->queue_id); return -ENODEV; } if (!queue->in_use) { - dev_err(info->dev, "Queue %d is idle\n", queue->queue_id); + dev_err(info->dev, "Queue %u is idle\n", queue->queue_id); return -ENODEV; } @@ -834,6 +834,7 @@ int sec_queue_stop_release(struct sec_queue *queue) /** * sec_queue_empty() - Is this hardware queue currently empty. + * @queue: The queue to test * * We need to know if we have an empty queue for some of the chaining modes * as if it is not empty we may need to hold the message in a software queue @@ -1315,6 +1316,6 @@ static struct platform_driver sec_driver = { module_platform_driver(sec_driver); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Hisilicon Security Accelerators"); +MODULE_DESCRIPTION("HiSilicon Security Accelerators"); MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com"); MODULE_AUTHOR("Jonathan Cameron <jonathan.cameron@huawei.com>"); diff --git a/drivers/crypto/hisilicon/sec/sec_drv.h b/drivers/crypto/hisilicon/sec/sec_drv.h index 4d9063a8b10b1d826743bb19910057e8ac63b783..179a8250d691c46c87ca411d56c76603463a7727 100644 --- a/drivers/crypto/hisilicon/sec/sec_drv.h +++ b/drivers/crypto/hisilicon/sec/sec_drv.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2016-2017 Hisilicon Limited. */ +/* Copyright (c) 2016-2017 HiSilicon Limited. */ #ifndef _SEC_DRV_H_ #define _SEC_DRV_H_ diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h index 08491912afd567be84b0d9812b72509707871b4d..dfdce2f21e658855041b896f308a12ddc3a56e30 100644 --- a/drivers/crypto/hisilicon/sec2/sec.h +++ b/drivers/crypto/hisilicon/sec2/sec.h @@ -4,8 +4,6 @@ #ifndef __HISI_SEC_V2_H #define __HISI_SEC_V2_H -#include <linux/list.h> - #include "../qm.h" #include "sec_crypto.h" @@ -50,7 +48,7 @@ struct sec_req { int err_type; int req_id; - int flag; + u32 flag; /* Status of the SEC request */ bool fake_busy; @@ -139,6 +137,7 @@ struct sec_ctx { bool pbuf_supported; struct sec_cipher_ctx c_ctx; struct sec_auth_ctx a_ctx; + struct device *dev; }; enum sec_endian { @@ -148,7 +147,6 @@ enum sec_endian { }; enum sec_debug_file_index { - SEC_CURRENT_QM, SEC_CLEAR_ENABLE, SEC_DEBUG_FILE_NUM, }; @@ -183,6 +181,6 @@ struct sec_dev { void sec_destroy_qps(struct hisi_qp **qps, int qp_num); struct hisi_qp **sec_create_qps(void); -int sec_register_to_crypto(void); -void sec_unregister_from_crypto(void); +int sec_register_to_crypto(struct hisi_qm *qm); +void sec_unregister_from_crypto(struct hisi_qm *qm); #endif diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index 2eaa516b323118c8d897fb5c446c4f5886207a51..133aede8bf078716e8bebce4acf3d760c6f5043e 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -7,6 +7,7 @@ #include <crypto/des.h> #include <crypto/hash.h> #include <crypto/internal/aead.h> +#include <crypto/internal/des.h> #include <crypto/sha1.h> #include <crypto/sha2.h> #include <crypto/skcipher.h> @@ -43,7 +44,6 @@ #define SEC_TOTAL_IV_SZ (SEC_IV_SIZE * QM_Q_DEPTH) #define SEC_SGL_SGE_NR 128 -#define SEC_CTX_DEV(ctx) (&(ctx)->sec->qm.pdev->dev) #define SEC_CIPHER_AUTH 0xfe #define SEC_AUTH_CIPHER 0x1 #define SEC_MAX_MAC_LEN 64 @@ -96,7 +96,7 @@ static int sec_alloc_req_id(struct sec_req *req, struct sec_qp_ctx *qp_ctx) 0, QM_Q_DEPTH, GFP_ATOMIC); mutex_unlock(&qp_ctx->req_lock); if (unlikely(req_id < 0)) { - dev_err(SEC_CTX_DEV(req->ctx), "alloc req id fail!\n"); + dev_err(req->ctx->dev, "alloc req id fail!\n"); return req_id; } @@ -112,7 +112,7 @@ static void sec_free_req_id(struct sec_req *req) int req_id = req->req_id; if (unlikely(req_id < 0 || req_id >= QM_Q_DEPTH)) { - dev_err(SEC_CTX_DEV(req->ctx), "free request id invalid!\n"); + dev_err(req->ctx->dev, "free request id invalid!\n"); return; } @@ -138,7 +138,7 @@ static int sec_aead_verify(struct sec_req *req) aead_req->cryptlen + aead_req->assoclen - authsize); if (unlikely(sz != authsize || memcmp(mac_out, mac, sz))) { - dev_err(SEC_CTX_DEV(req->ctx), "aead verify failure!\n"); + dev_err(req->ctx->dev, "aead verify failure!\n"); return -EBADMSG; } @@ -177,7 +177,7 @@ static void sec_req_cb(struct hisi_qp *qp, void *resp) if (unlikely(req->err_type || done != SEC_SQE_DONE || (ctx->alg_type == SEC_SKCIPHER && flag != SEC_SQE_CFLAG) || (ctx->alg_type == SEC_AEAD && flag != SEC_SQE_AEAD_FLAG))) { - dev_err(SEC_CTX_DEV(ctx), + dev_err_ratelimited(ctx->dev, "err_type[%d],done[%d],flag[%d]\n", req->err_type, done, flag); err = -EIO; @@ -326,8 +326,8 @@ static int sec_alloc_pbuf_resource(struct device *dev, struct sec_alg_res *res) static int sec_alg_resource_alloc(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) { - struct device *dev = SEC_CTX_DEV(ctx); struct sec_alg_res *res = qp_ctx->res; + struct device *dev = ctx->dev; int ret; ret = sec_alloc_civ_resource(dev, res); @@ -360,7 +360,7 @@ alloc_fail: static void sec_alg_resource_free(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) { - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; sec_free_civ_resource(dev, qp_ctx->res); @@ -373,7 +373,7 @@ static void sec_alg_resource_free(struct sec_ctx *ctx, static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx, int qp_ctx_id, int alg_type) { - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; struct sec_qp_ctx *qp_ctx; struct hisi_qp *qp; int ret = -ENOMEM; @@ -428,7 +428,7 @@ err_destroy_idr: static void sec_release_qp_ctx(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) { - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; hisi_qm_stop_qp(qp_ctx->qp); sec_alg_resource_free(ctx, qp_ctx); @@ -452,6 +452,7 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm); ctx->sec = sec; + ctx->dev = &sec->qm.pdev->dev; ctx->hlf_q_num = sec->ctx_q_num >> 1; ctx->pbuf_supported = ctx->sec->iommu_used; @@ -476,11 +477,9 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) err_sec_release_qp_ctx: for (i = i - 1; i >= 0; i--) sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]); - kfree(ctx->qp_ctx); err_destroy_qps: sec_destroy_qps(ctx->qps, sec->ctx_q_num); - return ret; } @@ -499,7 +498,7 @@ static int sec_cipher_init(struct sec_ctx *ctx) { struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; - c_ctx->c_key = dma_alloc_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE, + c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, &c_ctx->c_key_dma, GFP_KERNEL); if (!c_ctx->c_key) return -ENOMEM; @@ -512,7 +511,7 @@ static void sec_cipher_uninit(struct sec_ctx *ctx) struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE); - dma_free_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE, + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, c_ctx->c_key, c_ctx->c_key_dma); } @@ -520,7 +519,7 @@ static int sec_auth_init(struct sec_ctx *ctx) { struct sec_auth_ctx *a_ctx = &ctx->a_ctx; - a_ctx->a_key = dma_alloc_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE, + a_ctx->a_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, &a_ctx->a_key_dma, GFP_KERNEL); if (!a_ctx->a_key) return -ENOMEM; @@ -533,7 +532,7 @@ static void sec_auth_uninit(struct sec_ctx *ctx) struct sec_auth_ctx *a_ctx = &ctx->a_ctx; memzero_explicit(a_ctx->a_key, SEC_MAX_KEY_SIZE); - dma_free_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE, + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, a_ctx->a_key, a_ctx->a_key_dma); } @@ -546,7 +545,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm) crypto_skcipher_set_reqsize(tfm, sizeof(struct sec_req)); ctx->c_ctx.ivsize = crypto_skcipher_ivsize(tfm); if (ctx->c_ctx.ivsize > SEC_IV_SIZE) { - dev_err(SEC_CTX_DEV(ctx), "get error skcipher iv size!\n"); + pr_err("get error skcipher iv size!\n"); return -EINVAL; } @@ -573,10 +572,18 @@ static void sec_skcipher_uninit(struct crypto_skcipher *tfm) sec_ctx_base_uninit(ctx); } -static int sec_skcipher_3des_setkey(struct sec_cipher_ctx *c_ctx, +static int sec_skcipher_3des_setkey(struct crypto_skcipher *tfm, const u8 *key, const u32 keylen, const enum sec_cmode c_mode) { + struct sec_ctx *ctx = crypto_skcipher_ctx(tfm); + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + int ret; + + ret = verify_skcipher_des3_key(tfm, key); + if (ret) + return ret; + switch (keylen) { case SEC_DES3_2KEY_SIZE: c_ctx->c_key_len = SEC_CKEY_3DES_2KEY; @@ -633,12 +640,13 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, { struct sec_ctx *ctx = crypto_skcipher_ctx(tfm); struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + struct device *dev = ctx->dev; int ret; if (c_mode == SEC_CMODE_XTS) { ret = xts_verify_key(tfm, key, keylen); if (ret) { - dev_err(SEC_CTX_DEV(ctx), "xts mode key err!\n"); + dev_err(dev, "xts mode key err!\n"); return ret; } } @@ -648,7 +656,7 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, switch (c_alg) { case SEC_CALG_3DES: - ret = sec_skcipher_3des_setkey(c_ctx, keylen, c_mode); + ret = sec_skcipher_3des_setkey(tfm, key, keylen, c_mode); break; case SEC_CALG_AES: case SEC_CALG_SM4: @@ -659,7 +667,7 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, } if (ret) { - dev_err(SEC_CTX_DEV(ctx), "set sec key err!\n"); + dev_err(dev, "set sec key err!\n"); return ret; } @@ -691,7 +699,7 @@ static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req, struct aead_request *aead_req = req->aead_req.aead_req; struct sec_cipher_req *c_req = &req->c_req; struct sec_qp_ctx *qp_ctx = req->qp_ctx; - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; int copy_size, pbuf_length; int req_id = req->req_id; @@ -701,21 +709,14 @@ static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req, copy_size = c_req->c_len; pbuf_length = sg_copy_to_buffer(src, sg_nents(src), - qp_ctx->res[req_id].pbuf, - copy_size); - + qp_ctx->res[req_id].pbuf, + copy_size); if (unlikely(pbuf_length != copy_size)) { dev_err(dev, "copy src data to pbuf error!\n"); return -EINVAL; } c_req->c_in_dma = qp_ctx->res[req_id].pbuf_dma; - - if (!c_req->c_in_dma) { - dev_err(dev, "fail to set pbuffer address!\n"); - return -ENOMEM; - } - c_req->c_out_dma = c_req->c_in_dma; return 0; @@ -727,7 +728,7 @@ static void sec_cipher_pbuf_unmap(struct sec_ctx *ctx, struct sec_req *req, struct aead_request *aead_req = req->aead_req.aead_req; struct sec_cipher_req *c_req = &req->c_req; struct sec_qp_ctx *qp_ctx = req->qp_ctx; - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; int copy_size, pbuf_length; int req_id = req->req_id; @@ -739,7 +740,6 @@ static void sec_cipher_pbuf_unmap(struct sec_ctx *ctx, struct sec_req *req, pbuf_length = sg_copy_from_buffer(dst, sg_nents(dst), qp_ctx->res[req_id].pbuf, copy_size); - if (unlikely(pbuf_length != copy_size)) dev_err(dev, "copy pbuf data to dst error!\n"); } @@ -751,7 +751,7 @@ static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req, struct sec_aead_req *a_req = &req->aead_req; struct sec_qp_ctx *qp_ctx = req->qp_ctx; struct sec_alg_res *res = &qp_ctx->res[req->req_id]; - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; int ret; if (req->use_pbuf) { @@ -806,7 +806,7 @@ static void sec_cipher_unmap(struct sec_ctx *ctx, struct sec_req *req, struct scatterlist *src, struct scatterlist *dst) { struct sec_cipher_req *c_req = &req->c_req; - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; if (req->use_pbuf) { sec_cipher_pbuf_unmap(ctx, req, dst); @@ -891,6 +891,7 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, { struct sec_ctx *ctx = crypto_aead_ctx(tfm); struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + struct device *dev = ctx->dev; struct crypto_authenc_keys keys; int ret; @@ -904,13 +905,13 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, ret = sec_aead_aes_set_key(c_ctx, &keys); if (ret) { - dev_err(SEC_CTX_DEV(ctx), "set sec cipher key err!\n"); + dev_err(dev, "set sec cipher key err!\n"); goto bad_key; } ret = sec_aead_auth_set_key(&ctx->a_ctx, &keys); if (ret) { - dev_err(SEC_CTX_DEV(ctx), "set sec auth key err!\n"); + dev_err(dev, "set sec auth key err!\n"); goto bad_key; } @@ -1062,7 +1063,7 @@ static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type) sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), iv, iv_size, cryptlen - iv_size); if (unlikely(sz != iv_size)) - dev_err(SEC_CTX_DEV(req->ctx), "copy output iv error!\n"); + dev_err(req->ctx->dev, "copy output iv error!\n"); } static struct sec_req *sec_back_req_clear(struct sec_ctx *ctx, @@ -1160,7 +1161,7 @@ static int sec_aead_bd_fill(struct sec_ctx *ctx, struct sec_req *req) ret = sec_skcipher_bd_fill(ctx, req); if (unlikely(ret)) { - dev_err(SEC_CTX_DEV(ctx), "skcipher bd fill is error!\n"); + dev_err(ctx->dev, "skcipher bd fill is error!\n"); return ret; } @@ -1194,7 +1195,7 @@ static void sec_aead_callback(struct sec_ctx *c, struct sec_req *req, int err) a_req->assoclen); if (unlikely(sz != authsize)) { - dev_err(SEC_CTX_DEV(req->ctx), "copy out mac err!\n"); + dev_err(c->dev, "copy out mac err!\n"); err = -EINVAL; } } @@ -1259,7 +1260,7 @@ static int sec_process(struct sec_ctx *ctx, struct sec_req *req) ret = ctx->req_op->bd_send(ctx, req); if (unlikely((ret != -EBUSY && ret != -EINPROGRESS) || (ret == -EBUSY && !(req->flag & CRYPTO_TFM_REQ_MAY_BACKLOG)))) { - dev_err_ratelimited(SEC_CTX_DEV(ctx), "send sec request failed!\n"); + dev_err_ratelimited(ctx->dev, "send sec request failed!\n"); goto err_send_req; } @@ -1325,7 +1326,7 @@ static int sec_aead_init(struct crypto_aead *tfm) ctx->alg_type = SEC_AEAD; ctx->c_ctx.ivsize = crypto_aead_ivsize(tfm); if (ctx->c_ctx.ivsize > SEC_IV_SIZE) { - dev_err(SEC_CTX_DEV(ctx), "get error aead iv size!\n"); + dev_err(ctx->dev, "get error aead iv size!\n"); return -EINVAL; } @@ -1374,7 +1375,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name) auth_ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0); if (IS_ERR(auth_ctx->hash_tfm)) { - dev_err(SEC_CTX_DEV(ctx), "aead alloc shash error!\n"); + dev_err(ctx->dev, "aead alloc shash error!\n"); sec_aead_exit(tfm); return PTR_ERR(auth_ctx->hash_tfm); } @@ -1405,10 +1406,40 @@ static int sec_aead_sha512_ctx_init(struct crypto_aead *tfm) return sec_aead_ctx_init(tfm, "sha512"); } + +static int sec_skcipher_cryptlen_ckeck(struct sec_ctx *ctx, + struct sec_req *sreq) +{ + u32 cryptlen = sreq->c_req.sk_req->cryptlen; + struct device *dev = ctx->dev; + u8 c_mode = ctx->c_ctx.c_mode; + int ret = 0; + + switch (c_mode) { + case SEC_CMODE_XTS: + if (unlikely(cryptlen < AES_BLOCK_SIZE)) { + dev_err(dev, "skcipher XTS mode input length error!\n"); + ret = -EINVAL; + } + break; + case SEC_CMODE_ECB: + case SEC_CMODE_CBC: + if (unlikely(cryptlen & (AES_BLOCK_SIZE - 1))) { + dev_err(dev, "skcipher AES input length error!\n"); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq) { struct skcipher_request *sk_req = sreq->c_req.sk_req; - struct device *dev = SEC_CTX_DEV(ctx); + struct device *dev = ctx->dev; u8 c_alg = ctx->c_ctx.c_alg; if (unlikely(!sk_req->src || !sk_req->dst)) { @@ -1429,12 +1460,9 @@ static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq) } return 0; } else if (c_alg == SEC_CALG_AES || c_alg == SEC_CALG_SM4) { - if (unlikely(sk_req->cryptlen & (AES_BLOCK_SIZE - 1))) { - dev_err(dev, "skcipher aes input length error!\n"); - return -EINVAL; - } - return 0; + return sec_skcipher_cryptlen_ckeck(ctx, sreq); } + dev_err(dev, "skcipher algorithm error!\n"); return -EINVAL; @@ -1531,14 +1559,15 @@ static struct skcipher_alg sec_skciphers[] = { static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq) { - u8 c_alg = ctx->c_ctx.c_alg; struct aead_request *req = sreq->aead_req.aead_req; struct crypto_aead *tfm = crypto_aead_reqtfm(req); size_t authsize = crypto_aead_authsize(tfm); + struct device *dev = ctx->dev; + u8 c_alg = ctx->c_ctx.c_alg; if (unlikely(!req->src || !req->dst || !req->cryptlen || req->assoclen > SEC_MAX_AAD_LEN)) { - dev_err(SEC_CTX_DEV(ctx), "aead input param error!\n"); + dev_err(dev, "aead input param error!\n"); return -EINVAL; } @@ -1550,7 +1579,7 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq) /* Support AES only */ if (unlikely(c_alg != SEC_CALG_AES)) { - dev_err(SEC_CTX_DEV(ctx), "aead crypto alg error!\n"); + dev_err(dev, "aead crypto alg error!\n"); return -EINVAL; } if (sreq->c_req.encrypt) @@ -1559,7 +1588,7 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq) sreq->c_req.c_len = req->cryptlen - authsize; if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) { - dev_err(SEC_CTX_DEV(ctx), "aead crypto length error!\n"); + dev_err(dev, "aead crypto length error!\n"); return -EINVAL; } @@ -1634,7 +1663,7 @@ static struct aead_alg sec_aeads[] = { AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA512_DIGEST_SIZE), }; -int sec_register_to_crypto(void) +int sec_register_to_crypto(struct hisi_qm *qm) { int ret; @@ -1651,7 +1680,7 @@ int sec_register_to_crypto(void) return ret; } -void sec_unregister_from_crypto(void) +void sec_unregister_from_crypto(struct hisi_qm *qm) { crypto_unregister_skciphers(sec_skciphers, ARRAY_SIZE(sec_skciphers)); diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h index b2786e17d8fe20f8ead13da7f20c12d0c09275c4..9c78edac56a4bd8a6bd5e501ef3677f24ec4950b 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.h +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h @@ -64,7 +64,6 @@ enum sec_addr_type { }; struct sec_sqe_type2 { - /* * mac_len: 0~4 bits * a_key_len: 5~10 bits @@ -120,7 +119,6 @@ struct sec_sqe_type2 { /* c_pad_len_field: 0~1 bits */ __le16 c_pad_len_field; - __le64 long_a_data_len; __le64 a_ivin_addr; __le64 a_key_addr; @@ -211,6 +209,6 @@ struct sec_sqe { struct sec_sqe_type2 type2; }; -int sec_register_to_crypto(void); -void sec_unregister_from_crypto(void); +int sec_register_to_crypto(struct hisi_qm *qm); +void sec_unregister_from_crypto(struct hisi_qm *qm); #endif diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index dc68ba76f65e585bddfb8d4301fcf7f3bd54e165..6f0062d4408c35dcfd0a362f6ba63a9867379be0 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -19,7 +19,6 @@ #define SEC_VF_NUM 63 #define SEC_QUEUE_NUM_V1 4096 -#define SEC_QUEUE_NUM_V2 1024 #define SEC_PF_PCI_DEVICE_ID 0xa255 #define SEC_VF_PCI_DEVICE_ID 0xa256 @@ -35,18 +34,16 @@ #define SEC_CTX_Q_NUM_MAX 32 #define SEC_CTRL_CNT_CLR_CE 0x301120 -#define SEC_CTRL_CNT_CLR_CE_BIT BIT(0) -#define SEC_ENGINE_PF_CFG_OFF 0x300000 -#define SEC_ACC_COMMON_REG_OFF 0x1000 +#define SEC_CTRL_CNT_CLR_CE_BIT BIT(0) #define SEC_CORE_INT_SOURCE 0x301010 #define SEC_CORE_INT_MASK 0x301000 #define SEC_CORE_INT_STATUS 0x301008 #define SEC_CORE_SRAM_ECC_ERR_INFO 0x301C14 -#define SEC_ECC_NUM(err) (((err) >> 16) & 0xFF) -#define SEC_ECC_ADDR(err) ((err) >> 0) +#define SEC_ECC_NUM 16 +#define SEC_ECC_MASH 0xFF #define SEC_CORE_INT_DISABLE 0x0 -#define SEC_CORE_INT_ENABLE 0x1ff -#define SEC_CORE_INT_CLEAR 0x1ff +#define SEC_CORE_INT_ENABLE 0x7c1ff +#define SEC_CORE_INT_CLEAR 0x7c1ff #define SEC_SAA_ENABLE 0x17f #define SEC_RAS_CE_REG 0x301050 @@ -54,24 +51,24 @@ #define SEC_RAS_NFE_REG 0x301058 #define SEC_RAS_CE_ENB_MSK 0x88 #define SEC_RAS_FE_ENB_MSK 0x0 -#define SEC_RAS_NFE_ENB_MSK 0x177 -#define SEC_RAS_DISABLE 0x0 -#define SEC_MEM_START_INIT_REG 0x0100 -#define SEC_MEM_INIT_DONE_REG 0x0104 +#define SEC_RAS_NFE_ENB_MSK 0x7c177 +#define SEC_RAS_DISABLE 0x0 +#define SEC_MEM_START_INIT_REG 0x301100 +#define SEC_MEM_INIT_DONE_REG 0x301104 -#define SEC_CONTROL_REG 0x0200 +#define SEC_CONTROL_REG 0x301200 #define SEC_TRNG_EN_SHIFT 8 #define SEC_CLK_GATE_ENABLE BIT(3) #define SEC_CLK_GATE_DISABLE (~BIT(3)) #define SEC_AXI_SHUTDOWN_ENABLE BIT(12) #define SEC_AXI_SHUTDOWN_DISABLE 0xFFFFEFFF -#define SEC_INTERFACE_USER_CTRL0_REG 0x0220 -#define SEC_INTERFACE_USER_CTRL1_REG 0x0224 -#define SEC_SAA_EN_REG 0x0270 -#define SEC_BD_ERR_CHK_EN_REG0 0x0380 -#define SEC_BD_ERR_CHK_EN_REG1 0x0384 -#define SEC_BD_ERR_CHK_EN_REG3 0x038c +#define SEC_INTERFACE_USER_CTRL0_REG 0x301220 +#define SEC_INTERFACE_USER_CTRL1_REG 0x301224 +#define SEC_SAA_EN_REG 0x301270 +#define SEC_BD_ERR_CHK_EN_REG0 0x301380 +#define SEC_BD_ERR_CHK_EN_REG1 0x301384 +#define SEC_BD_ERR_CHK_EN_REG3 0x30138c #define SEC_USER0_SMMU_NORMAL (BIT(23) | BIT(15)) #define SEC_USER1_SMMU_NORMAL (BIT(31) | BIT(23) | BIT(15) | BIT(7)) @@ -95,9 +92,6 @@ #define SEC_SQE_MASK_OFFSET 64 #define SEC_SQE_MASK_LEN 48 -#define SEC_ADDR(qm, offset) ((qm)->io_base + (offset) + \ - SEC_ENGINE_PF_CFG_OFF + SEC_ACC_COMMON_REG_OFF) - struct sec_hw_error { u32 int_msk; const char *msg; @@ -117,20 +111,66 @@ static struct hisi_qm_list sec_devices = { }; static const struct sec_hw_error sec_hw_errors[] = { - {.int_msk = BIT(0), .msg = "sec_axi_rresp_err_rint"}, - {.int_msk = BIT(1), .msg = "sec_axi_bresp_err_rint"}, - {.int_msk = BIT(2), .msg = "sec_ecc_2bit_err_rint"}, - {.int_msk = BIT(3), .msg = "sec_ecc_1bit_err_rint"}, - {.int_msk = BIT(4), .msg = "sec_req_trng_timeout_rint"}, - {.int_msk = BIT(5), .msg = "sec_fsm_hbeat_rint"}, - {.int_msk = BIT(6), .msg = "sec_channel_req_rng_timeout_rint"}, - {.int_msk = BIT(7), .msg = "sec_bd_err_rint"}, - {.int_msk = BIT(8), .msg = "sec_chain_buff_err_rint"}, - { /* sentinel */ } + { + .int_msk = BIT(0), + .msg = "sec_axi_rresp_err_rint" + }, + { + .int_msk = BIT(1), + .msg = "sec_axi_bresp_err_rint" + }, + { + .int_msk = BIT(2), + .msg = "sec_ecc_2bit_err_rint" + }, + { + .int_msk = BIT(3), + .msg = "sec_ecc_1bit_err_rint" + }, + { + .int_msk = BIT(4), + .msg = "sec_req_trng_timeout_rint" + }, + { + .int_msk = BIT(5), + .msg = "sec_fsm_hbeat_rint" + }, + { + .int_msk = BIT(6), + .msg = "sec_channel_req_rng_timeout_rint" + }, + { + .int_msk = BIT(7), + .msg = "sec_bd_err_rint" + }, + { + .int_msk = BIT(8), + .msg = "sec_chain_buff_err_rint" + }, + { + .int_msk = BIT(14), + .msg = "sec_no_secure_access" + }, + { + .int_msk = BIT(15), + .msg = "sec_wrapping_key_auth_err" + }, + { + .int_msk = BIT(16), + .msg = "sec_km_key_crc_fail" + }, + { + .int_msk = BIT(17), + .msg = "sec_axi_poison_err" + }, + { + .int_msk = BIT(18), + .msg = "sec_sva_err" + }, + {} }; static const char * const sec_dbg_file_name[] = { - [SEC_CURRENT_QM] = "current_qm", [SEC_CLEAR_ENABLE] = "clear_enable", }; @@ -277,9 +317,7 @@ static u8 sec_get_endian(struct hisi_qm *qm) "cannot access a register in VF!\n"); return SEC_LE; } - reg = readl_relaxed(qm->io_base + SEC_ENGINE_PF_CFG_OFF + - SEC_ACC_COMMON_REG_OFF + SEC_CONTROL_REG); - + reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); /* BD little endian mode */ if (!(reg & BIT(0))) return SEC_LE; @@ -299,13 +337,13 @@ static int sec_engine_init(struct hisi_qm *qm) u32 reg; /* disable clock gate control */ - reg = readl_relaxed(SEC_ADDR(qm, SEC_CONTROL_REG)); + reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); reg &= SEC_CLK_GATE_DISABLE; - writel_relaxed(reg, SEC_ADDR(qm, SEC_CONTROL_REG)); + writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); - writel_relaxed(0x1, SEC_ADDR(qm, SEC_MEM_START_INIT_REG)); + writel_relaxed(0x1, qm->io_base + SEC_MEM_START_INIT_REG); - ret = readl_relaxed_poll_timeout(SEC_ADDR(qm, SEC_MEM_INIT_DONE_REG), + ret = readl_relaxed_poll_timeout(qm->io_base + SEC_MEM_INIT_DONE_REG, reg, reg & 0x1, SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); if (ret) { @@ -313,40 +351,40 @@ static int sec_engine_init(struct hisi_qm *qm) return ret; } - reg = readl_relaxed(SEC_ADDR(qm, SEC_CONTROL_REG)); + reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); reg |= (0x1 << SEC_TRNG_EN_SHIFT); - writel_relaxed(reg, SEC_ADDR(qm, SEC_CONTROL_REG)); + writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); - reg = readl_relaxed(SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL0_REG)); + reg = readl_relaxed(qm->io_base + SEC_INTERFACE_USER_CTRL0_REG); reg |= SEC_USER0_SMMU_NORMAL; - writel_relaxed(reg, SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL0_REG)); + writel_relaxed(reg, qm->io_base + SEC_INTERFACE_USER_CTRL0_REG); - reg = readl_relaxed(SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL1_REG)); + reg = readl_relaxed(qm->io_base + SEC_INTERFACE_USER_CTRL1_REG); reg &= SEC_USER1_SMMU_MASK; if (qm->use_sva && qm->ver == QM_HW_V2) reg |= SEC_USER1_SMMU_SVA; else reg |= SEC_USER1_SMMU_NORMAL; - writel_relaxed(reg, SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL1_REG)); + writel_relaxed(reg, qm->io_base + SEC_INTERFACE_USER_CTRL1_REG); writel(SEC_SINGLE_PORT_MAX_TRANS, qm->io_base + AM_CFG_SINGLE_PORT_MAX_TRANS); - writel(SEC_SAA_ENABLE, SEC_ADDR(qm, SEC_SAA_EN_REG)); + writel(SEC_SAA_ENABLE, qm->io_base + SEC_SAA_EN_REG); /* Enable sm4 extra mode, as ctr/ecb */ writel_relaxed(SEC_BD_ERR_CHK_EN0, - SEC_ADDR(qm, SEC_BD_ERR_CHK_EN_REG0)); + qm->io_base + SEC_BD_ERR_CHK_EN_REG0); /* Enable sm4 xts mode multiple iv */ writel_relaxed(SEC_BD_ERR_CHK_EN1, - SEC_ADDR(qm, SEC_BD_ERR_CHK_EN_REG1)); + qm->io_base + SEC_BD_ERR_CHK_EN_REG1); writel_relaxed(SEC_BD_ERR_CHK_EN3, - SEC_ADDR(qm, SEC_BD_ERR_CHK_EN_REG3)); + qm->io_base + SEC_BD_ERR_CHK_EN_REG3); /* config endian */ - reg = readl_relaxed(SEC_ADDR(qm, SEC_CONTROL_REG)); + reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); reg |= sec_get_endian(qm); - writel_relaxed(reg, SEC_ADDR(qm, SEC_CONTROL_REG)); + writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); return 0; } @@ -381,10 +419,6 @@ static void sec_debug_regs_clear(struct hisi_qm *qm) { int i; - /* clear current_qm */ - writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF); - writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF); - /* clear sec dfx regs */ writel(0x1, qm->io_base + SEC_CTRL_CNT_CLR_CE); for (i = 0; i < ARRAY_SIZE(sec_dfx_regs); i++) @@ -406,7 +440,7 @@ static void sec_hw_error_enable(struct hisi_qm *qm) return; } - val = readl(SEC_ADDR(qm, SEC_CONTROL_REG)); + val = readl(qm->io_base + SEC_CONTROL_REG); /* clear SEC hw error source if having */ writel(SEC_CORE_INT_CLEAR, qm->io_base + SEC_CORE_INT_SOURCE); @@ -422,14 +456,14 @@ static void sec_hw_error_enable(struct hisi_qm *qm) /* enable SEC block master OOO when m-bit error occur */ val = val | SEC_AXI_SHUTDOWN_ENABLE; - writel(val, SEC_ADDR(qm, SEC_CONTROL_REG)); + writel(val, qm->io_base + SEC_CONTROL_REG); } static void sec_hw_error_disable(struct hisi_qm *qm) { u32 val; - val = readl(SEC_ADDR(qm, SEC_CONTROL_REG)); + val = readl(qm->io_base + SEC_CONTROL_REG); /* disable RAS int */ writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_CE_REG); @@ -442,51 +476,7 @@ static void sec_hw_error_disable(struct hisi_qm *qm) /* disable SEC block master OOO when m-bit error occur */ val = val & SEC_AXI_SHUTDOWN_DISABLE; - writel(val, SEC_ADDR(qm, SEC_CONTROL_REG)); -} - -static u32 sec_current_qm_read(struct sec_debug_file *file) -{ - struct hisi_qm *qm = file->qm; - - return readl(qm->io_base + QM_DFX_MB_CNT_VF); -} - -static int sec_current_qm_write(struct sec_debug_file *file, u32 val) -{ - struct hisi_qm *qm = file->qm; - u32 vfq_num; - u32 tmp; - - if (val > qm->vfs_num) - return -EINVAL; - - /* According PF or VF Dev ID to calculation curr_qm_qp_num and store */ - if (!val) { - qm->debug.curr_qm_qp_num = qm->qp_num; - } else { - vfq_num = (qm->ctrl_qp_num - qm->qp_num) / qm->vfs_num; - - if (val == qm->vfs_num) - qm->debug.curr_qm_qp_num = - qm->ctrl_qp_num - qm->qp_num - - (qm->vfs_num - 1) * vfq_num; - else - qm->debug.curr_qm_qp_num = vfq_num; - } - - writel(val, qm->io_base + QM_DFX_MB_CNT_VF); - writel(val, qm->io_base + QM_DFX_DB_CNT_VF); - - tmp = val | - (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK); - writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN); - - tmp = val | - (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK); - writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN); - - return 0; + writel(val, qm->io_base + SEC_CONTROL_REG); } static u32 sec_clear_enable_read(struct sec_debug_file *file) @@ -523,9 +513,6 @@ static ssize_t sec_debug_read(struct file *filp, char __user *buf, spin_lock_irq(&file->lock); switch (file->index) { - case SEC_CURRENT_QM: - val = sec_current_qm_read(file); - break; case SEC_CLEAR_ENABLE: val = sec_clear_enable_read(file); break; @@ -566,11 +553,6 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf, spin_lock_irq(&file->lock); switch (file->index) { - case SEC_CURRENT_QM: - ret = sec_current_qm_write(file, val); - if (ret) - goto err_input; - break; case SEC_CLEAR_ENABLE: ret = sec_clear_enable_write(file, val); if (ret) @@ -655,7 +637,7 @@ static int sec_debug_init(struct hisi_qm *qm) int i; if (qm->pdev->device == SEC_PF_PCI_DEVICE_ID) { - for (i = SEC_CURRENT_QM; i < SEC_DEBUG_FILE_NUM; i++) { + for (i = SEC_CLEAR_ENABLE; i < SEC_DEBUG_FILE_NUM; i++) { spin_lock_init(&sec->debug.files[i].lock); sec->debug.files[i].index = i; sec->debug.files[i].qm = qm; @@ -712,7 +694,8 @@ static void sec_log_hw_error(struct hisi_qm *qm, u32 err_sts) err_val = readl(qm->io_base + SEC_CORE_SRAM_ECC_ERR_INFO); dev_err(dev, "multi ecc sram num=0x%x\n", - SEC_ECC_NUM(err_val)); + ((err_val) >> SEC_ECC_NUM) & + SEC_ECC_MASH); } } errs++; @@ -733,9 +716,23 @@ static void sec_open_axi_master_ooo(struct hisi_qm *qm) { u32 val; - val = readl(SEC_ADDR(qm, SEC_CONTROL_REG)); - writel(val & SEC_AXI_SHUTDOWN_DISABLE, SEC_ADDR(qm, SEC_CONTROL_REG)); - writel(val | SEC_AXI_SHUTDOWN_ENABLE, SEC_ADDR(qm, SEC_CONTROL_REG)); + val = readl(qm->io_base + SEC_CONTROL_REG); + writel(val & SEC_AXI_SHUTDOWN_DISABLE, qm->io_base + SEC_CONTROL_REG); + writel(val | SEC_AXI_SHUTDOWN_ENABLE, qm->io_base + SEC_CONTROL_REG); +} + +static void sec_err_info_init(struct hisi_qm *qm) +{ + struct hisi_qm_err_info *err_info = &qm->err_info; + + err_info->ce = QM_BASE_CE; + err_info->fe = 0; + err_info->ecc_2bits_mask = SEC_CORE_INT_STATUS_M_ECC; + err_info->dev_ce_mask = SEC_RAS_CE_ENB_MSK; + err_info->msi_wr_port = BIT(0); + err_info->acpi_rst = "SRST"; + err_info->nfe = QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT | + QM_ACC_WB_NOT_READY_TIMEOUT; } static const struct hisi_qm_err_ini sec_err_ini = { @@ -746,16 +743,7 @@ static const struct hisi_qm_err_ini sec_err_ini = { .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, - .err_info = { - .ce = QM_BASE_CE, - .nfe = QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT | - QM_ACC_WB_NOT_READY_TIMEOUT, - .fe = 0, - .ecc_2bits_mask = SEC_CORE_INT_STATUS_M_ECC, - .dev_ce_mask = SEC_RAS_CE_ENB_MSK, - .msi_wr_port = BIT(0), - .acpi_rst = "SRST", - } + .err_info_init = sec_err_info_init, }; static int sec_pf_probe_init(struct sec_dev *sec) @@ -763,12 +751,8 @@ static int sec_pf_probe_init(struct sec_dev *sec) struct hisi_qm *qm = &sec->qm; int ret; - if (qm->ver == QM_HW_V1) - qm->ctrl_qp_num = SEC_QUEUE_NUM_V1; - else - qm->ctrl_qp_num = SEC_QUEUE_NUM_V2; - qm->err_ini = &sec_err_ini; + qm->err_ini->err_info_init(qm); ret = sec_set_user_domain_and_cache(qm); if (ret) @@ -786,7 +770,7 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) qm->pdev = pdev; qm->ver = pdev->revision; - qm->algs = "cipher\ndigest\naead\n"; + qm->algs = "cipher\ndigest\naead"; qm->mode = uacce_mode; qm->sqe_size = SEC_SQE_SIZE; qm->dev_name = sec_name; @@ -909,10 +893,15 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) pci_warn(pdev, "Failed to init debugfs!\n"); - ret = hisi_qm_alg_register(qm, &sec_devices); - if (ret < 0) { - pr_err("Failed to register driver to crypto.\n"); - goto err_qm_stop; + if (qm->qp_num >= ctx_q_num) { + ret = hisi_qm_alg_register(qm, &sec_devices); + if (ret < 0) { + pr_err("Failed to register driver to crypto.\n"); + goto err_qm_stop; + } + } else { + pci_warn(qm->pdev, + "Failed to use kernel mode, qp not enough!\n"); } if (qm->uacce) { @@ -948,7 +937,9 @@ static void sec_remove(struct pci_dev *pdev) struct hisi_qm *qm = pci_get_drvdata(pdev); hisi_qm_wait_task_finish(qm, &sec_devices); - hisi_qm_alg_unregister(qm, &sec_devices); + if (qm->qp_num >= ctx_q_num) + hisi_qm_alg_unregister(qm, &sec_devices); + if (qm->fun_type == QM_HW_PF && qm->vfs_num) hisi_qm_sriov_disable(pdev, true); diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c index 3bff6394acafdbdad07c8a92d26d3a618bc19faf..057273769f264eebe026942718ac26de93bedf83 100644 --- a/drivers/crypto/hisilicon/sgl.c +++ b/drivers/crypto/hisilicon/sgl.c @@ -56,7 +56,7 @@ struct hisi_acc_sgl_pool { struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, u32 count, u32 sge_nr) { - u32 sgl_size, block_size, sgl_num_per_block, block_num, remain_sgl = 0; + u32 sgl_size, block_size, sgl_num_per_block, block_num, remain_sgl; struct hisi_acc_sgl_pool *pool; struct mem_block *block; u32 i, j; @@ -66,6 +66,11 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, sgl_size = sizeof(struct acc_hw_sge) * sge_nr + sizeof(struct hisi_acc_hw_sgl); + + /* + * the pool may allocate a block of memory of size PAGE_SIZE * 2^(MAX_ORDER - 1), + * block size may exceed 2^31 on ia64, so the max of block size is 2^31 + */ block_size = 1 << (PAGE_SHIFT + MAX_ORDER <= 32 ? PAGE_SHIFT + MAX_ORDER - 1 : 31); sgl_num_per_block = block_size / sgl_size; @@ -85,8 +90,10 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, block[i].sgl = dma_alloc_coherent(dev, block_size, &block[i].sgl_dma, GFP_KERNEL); - if (!block[i].sgl) + if (!block[i].sgl) { + dev_err(dev, "Fail to allocate hw SG buffer!\n"); goto err_free_mem; + } block[i].size = block_size; } @@ -95,8 +102,10 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, block[i].sgl = dma_alloc_coherent(dev, remain_sgl * sgl_size, &block[i].sgl_dma, GFP_KERNEL); - if (!block[i].sgl) + if (!block[i].sgl) { + dev_err(dev, "Fail to allocate remained hw SG buffer!\n"); goto err_free_mem; + } block[i].size = remain_sgl * sgl_size; } @@ -167,6 +176,7 @@ static void sg_map_to_hw_sg(struct scatterlist *sgl, { hw_sge->buf = sg_dma_address(sgl); hw_sge->len = cpu_to_le32(sg_dma_len(sgl)); + hw_sge->page_ctrl = sg_virt(sgl); } static void inc_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl) @@ -182,6 +192,18 @@ static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum) hw_sgl->entry_sum_in_chain = cpu_to_le16(sum); } +static void clear_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl) +{ + struct acc_hw_sge *hw_sge = hw_sgl->sge_entries; + int i; + + for (i = 0; i < le16_to_cpu(hw_sgl->entry_sum_in_sgl); i++) { + hw_sge[i].page_ctrl = NULL; + hw_sge[i].buf = 0; + hw_sge[i].len = 0; + } +} + /** * hisi_acc_sg_buf_map_to_hw_sgl - Map a scatterlist to a hw sgl. * @dev: The device which hw sgl belongs to. @@ -211,16 +233,19 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, sg_n = sg_nents(sgl); sg_n_mapped = dma_map_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); - if (!sg_n_mapped) + if (!sg_n_mapped) { + dev_err(dev, "DMA mapping for SG error!\n"); return ERR_PTR(-EINVAL); + } if (sg_n_mapped > pool->sge_nr) { - dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); + dev_err(dev, "the number of entries in input scatterlist is bigger than SGL pool setting.\n"); return ERR_PTR(-EINVAL); } curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma); if (IS_ERR(curr_hw_sgl)) { + dev_err(dev, "Get SGL error!\n"); dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); return ERR_PTR(-ENOMEM); @@ -256,7 +281,7 @@ void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl, return; dma_unmap_sg(dev, sgl, sg_nents(sgl), DMA_BIDIRECTIONAL); - + clear_hw_sgl_sge(hw_sgl); hw_sgl->entry_sum_in_chain = 0; hw_sgl->entry_sum_in_sgl = 0; hw_sgl->entry_length_in_sgl = 0; diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c index 29712685498a78b35f7f1a5599ccbc17505d6eef..829f2caf0f67fd675b43b980fa0db4ab22b79d68 100644 --- a/drivers/crypto/hisilicon/trng/trng.c +++ b/drivers/crypto/hisilicon/trng/trng.c @@ -18,6 +18,8 @@ #define HISI_TRNG_REG 0x00F0 #define HISI_TRNG_BYTES 4 #define HISI_TRNG_QUALITY 512 +#define HISI_TRNG_VERSION 0x01B8 +#define HISI_TRNG_VER_V1 GENMASK(31, 0) #define SLEEP_US 10 #define TIMEOUT_US 10000 #define SW_DRBG_NUM_SHIFT 2 @@ -50,6 +52,7 @@ struct hisi_trng { struct hisi_trng_list *trng_list; struct list_head list; struct hwrng rng; + u32 ver; bool is_used; struct mutex mutex; }; @@ -260,6 +263,7 @@ static int hisi_trng_probe(struct platform_device *pdev) return PTR_ERR(trng->base); trng->is_used = false; + trng->ver = readl(trng->base + HISI_TRNG_VERSION); if (!trng_devices.is_init) { INIT_LIST_HEAD(&trng_devices.list); mutex_init(&trng_devices.lock); @@ -267,7 +271,8 @@ static int hisi_trng_probe(struct platform_device *pdev) } hisi_trng_add_to_list(trng); - if (atomic_inc_return(&trng_active_devs) == 1) { + if (trng->ver != HISI_TRNG_VER_V1 && + atomic_inc_return(&trng_active_devs) == 1) { ret = crypto_register_rng(&hisi_trng_alg); if (ret) { dev_err(&pdev->dev, @@ -289,7 +294,8 @@ static int hisi_trng_probe(struct platform_device *pdev) return ret; err_crypto_unregister: - if (atomic_dec_return(&trng_active_devs) == 0) + if (trng->ver != HISI_TRNG_VER_V1 && + atomic_dec_return(&trng_active_devs) == 0) crypto_unregister_rng(&hisi_trng_alg); err_remove_from_list: @@ -305,7 +311,8 @@ static int hisi_trng_remove(struct platform_device *pdev) while (hisi_trng_del_from_list(trng)) ; - if (atomic_dec_return(&trng_active_devs) == 0) + if (trng->ver != HISI_TRNG_VER_V1 && + atomic_dec_return(&trng_active_devs) == 0) crypto_unregister_rng(&hisi_trng_alg); return 0; diff --git a/drivers/crypto/hisilicon/zip/zip.h b/drivers/crypto/hisilicon/zip/zip.h index 92397f993e237b941d7cfb99febf494d36662fbb..517fdbdff3ea476c81c327b2295638b1b646b1d8 100644 --- a/drivers/crypto/hisilicon/zip/zip.h +++ b/drivers/crypto/hisilicon/zip/zip.h @@ -33,35 +33,55 @@ struct hisi_zip_sqe { u32 consumed; u32 produced; u32 comp_data_length; + /* + * status: 0~7 bits + * rsvd: 8~31 bits + */ u32 dw3; u32 input_data_length; - u32 lba_l; - u32 lba_h; + u32 dw5; + u32 dw6; + /* + * in_sge_data_offset: 0~23 bits + * rsvd: 24~27 bits + * sqe_type: 29~31 bits + */ u32 dw7; + /* + * out_sge_data_offset: 0~23 bits + * rsvd: 24~31 bits + */ u32 dw8; + /* + * request_type: 0~7 bits + * buffer_type: 8~11 bits + * rsvd: 13~31 bits + */ u32 dw9; u32 dw10; - u32 priv_info; + u32 dw11; u32 dw12; - u32 tag; + /* tag: in sqe type 0 */ + u32 dw13; u32 dest_avail_out; - u32 rsvd0; - u32 comp_head_addr_l; - u32 comp_head_addr_h; + u32 dw15; + u32 dw16; + u32 dw17; u32 source_addr_l; u32 source_addr_h; u32 dest_addr_l; u32 dest_addr_h; - u32 stream_ctx_addr_l; - u32 stream_ctx_addr_h; - u32 cipher_key1_addr_l; - u32 cipher_key1_addr_h; - u32 cipher_key2_addr_l; - u32 cipher_key2_addr_h; + u32 dw22; + u32 dw23; + u32 dw24; + u32 dw25; + /* tag: in sqe type 3 */ + u32 dw26; + u32 dw27; u32 rsvd1[4]; }; int zip_create_qps(struct hisi_qp **qps, int ctx_num, int node); -int hisi_zip_register_to_crypto(void); -void hisi_zip_unregister_from_crypto(void); +int hisi_zip_register_to_crypto(struct hisi_qm *qm); +void hisi_zip_unregister_from_crypto(struct hisi_qm *qm); #endif diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c index 08b4660b014c6f24b1689865956e55e32059ba62..9520a4113c81e5fba635b54b48cc2cc0b87362cb 100644 --- a/drivers/crypto/hisilicon/zip/zip_crypto.c +++ b/drivers/crypto/hisilicon/zip/zip_crypto.c @@ -10,6 +10,7 @@ #define HZIP_BD_STATUS_M GENMASK(7, 0) /* hisi_zip_sqe dw7 */ #define HZIP_IN_SGE_DATA_OFFSET_M GENMASK(23, 0) +#define HZIP_SQE_TYPE_M GENMASK(31, 28) /* hisi_zip_sqe dw8 */ #define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0) /* hisi_zip_sqe dw9 */ @@ -91,8 +92,22 @@ struct hisi_zip_qp_ctx { struct hisi_zip_ctx *ctx; }; +struct hisi_zip_sqe_ops { + u8 sqe_type; + void (*fill_addr)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_buf_size)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_buf_type)(struct hisi_zip_sqe *sqe, u8 buf_type); + void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type); + void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type); + u32 (*get_tag)(struct hisi_zip_sqe *sqe); + u32 (*get_status)(struct hisi_zip_sqe *sqe); + u32 (*get_dstlen)(struct hisi_zip_sqe *sqe); +}; + struct hisi_zip_ctx { struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM]; + const struct hisi_zip_sqe_ops *ops; }; static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp) @@ -119,35 +134,367 @@ static u16 sgl_sge_nr = HZIP_SGL_SGE_NR; module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444); MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)"); -static void hisi_zip_config_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type) +static u16 get_extra_field_size(const u8 *start) +{ + return *((u16 *)start) + GZIP_HEAD_FEXTRA_XLEN; +} + +static u32 get_name_field_size(const u8 *start) +{ + return strlen(start) + 1; +} + +static u32 get_comment_field_size(const u8 *start) +{ + return strlen(start) + 1; +} + +static u32 __get_gzip_head_size(const u8 *src) +{ + u8 head_flg = *(src + GZIP_HEAD_FLG_SHIFT); + u32 size = GZIP_HEAD_FEXTRA_SHIFT; + + if (head_flg & GZIP_HEAD_FEXTRA_BIT) + size += get_extra_field_size(src + size); + if (head_flg & GZIP_HEAD_FNAME_BIT) + size += get_name_field_size(src + size); + if (head_flg & GZIP_HEAD_FCOMMENT_BIT) + size += get_comment_field_size(src + size); + if (head_flg & GZIP_HEAD_FHCRC_BIT) + size += GZIP_HEAD_FHCRC_SIZE; + + return size; +} + +static size_t __maybe_unused get_gzip_head_size(struct scatterlist *sgl) +{ + char buf[HZIP_GZIP_HEAD_BUF]; + + sg_copy_to_buffer(sgl, sg_nents(sgl), buf, sizeof(buf)); + + return __get_gzip_head_size(buf); +} + +static int add_comp_head(struct scatterlist *dst, u8 req_type) +{ + int head_size = TO_HEAD_SIZE(req_type); + const u8 *head = TO_HEAD(req_type); + int ret; + + ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size); + if (ret != head_size) { + pr_err("the head size of buffer is wrong (%d)!\n", ret); + return -ENOMEM; + } + + return head_size; +} + +static int get_comp_head_size(struct acomp_req *acomp_req, u8 req_type) +{ + if (!acomp_req->src || !acomp_req->slen) + return -EINVAL; + + if (req_type == HZIP_ALG_TYPE_GZIP && + acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT) + return -EINVAL; + + switch (req_type) { + case HZIP_ALG_TYPE_ZLIB: + return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB); + case HZIP_ALG_TYPE_GZIP: + return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP); + default: + pr_err("request type does not support!\n"); + return -EINVAL; + } +} + +static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req, + struct hisi_zip_qp_ctx *qp_ctx, + size_t head_size, bool is_comp) +{ + struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct hisi_zip_req *q = req_q->q; + struct hisi_zip_req *req_cache; + int req_id; + + write_lock(&req_q->req_lock); + + req_id = find_first_zero_bit(req_q->req_bitmap, req_q->size); + if (req_id >= req_q->size) { + write_unlock(&req_q->req_lock); + dev_dbg(&qp_ctx->qp->qm->pdev->dev, "req cache is full!\n"); + return ERR_PTR(-EAGAIN); + } + set_bit(req_id, req_q->req_bitmap); + + req_cache = q + req_id; + req_cache->req_id = req_id; + req_cache->req = req; + + if (is_comp) { + req_cache->sskip = 0; + req_cache->dskip = head_size; + } else { + req_cache->sskip = head_size; + req_cache->dskip = 0; + } + + write_unlock(&req_q->req_lock); + + return req_cache; +} + +static void hisi_zip_remove_req(struct hisi_zip_qp_ctx *qp_ctx, + struct hisi_zip_req *req) +{ + struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + + write_lock(&req_q->req_lock); + clear_bit(req->req_id, req_q->req_bitmap); + memset(req, 0, sizeof(struct hisi_zip_req)); + write_unlock(&req_q->req_lock); +} + +static void hisi_zip_fill_addr(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) +{ + sqe->source_addr_l = lower_32_bits(req->dma_src); + sqe->source_addr_h = upper_32_bits(req->dma_src); + sqe->dest_addr_l = lower_32_bits(req->dma_dst); + sqe->dest_addr_h = upper_32_bits(req->dma_dst); +} + +static void hisi_zip_fill_buf_size(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) +{ + struct acomp_req *a_req = req->req; + + sqe->input_data_length = a_req->slen - req->sskip; + sqe->dest_avail_out = a_req->dlen - req->dskip; + sqe->dw7 = FIELD_PREP(HZIP_IN_SGE_DATA_OFFSET_M, req->sskip); + sqe->dw8 = FIELD_PREP(HZIP_OUT_SGE_DATA_OFFSET_M, req->dskip); +} + +static void hisi_zip_fill_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type) { u32 val; - val = (sqe->dw9) & ~HZIP_BUF_TYPE_M; + val = sqe->dw9 & ~HZIP_BUF_TYPE_M; val |= FIELD_PREP(HZIP_BUF_TYPE_M, buf_type); sqe->dw9 = val; } -static void hisi_zip_config_tag(struct hisi_zip_sqe *sqe, u32 tag) +static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) +{ + u32 val; + + val = sqe->dw9 & ~HZIP_REQ_TYPE_M; + val |= FIELD_PREP(HZIP_REQ_TYPE_M, req_type); + sqe->dw9 = val; +} + +static void hisi_zip_fill_tag_v1(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) +{ + sqe->dw13 = req->req_id; +} + +static void hisi_zip_fill_tag_v2(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) +{ + sqe->dw26 = req->req_id; +} + +static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type) { - sqe->tag = tag; + u32 val; + + val = sqe->dw7 & ~HZIP_SQE_TYPE_M; + val |= FIELD_PREP(HZIP_SQE_TYPE_M, sqe_type); + sqe->dw7 = val; } -static void hisi_zip_fill_sqe(struct hisi_zip_sqe *sqe, u8 req_type, - dma_addr_t s_addr, dma_addr_t d_addr, u32 slen, - u32 dlen, u32 sskip, u32 dskip) +static void hisi_zip_fill_sqe(struct hisi_zip_ctx *ctx, struct hisi_zip_sqe *sqe, + u8 req_type, struct hisi_zip_req *req) { + const struct hisi_zip_sqe_ops *ops = ctx->ops; + memset(sqe, 0, sizeof(struct hisi_zip_sqe)); - sqe->input_data_length = slen - sskip; - sqe->dw7 = FIELD_PREP(HZIP_IN_SGE_DATA_OFFSET_M, sskip); - sqe->dw8 = FIELD_PREP(HZIP_OUT_SGE_DATA_OFFSET_M, dskip); - sqe->dw9 = FIELD_PREP(HZIP_REQ_TYPE_M, req_type); - sqe->dest_avail_out = dlen - dskip; - sqe->source_addr_l = lower_32_bits(s_addr); - sqe->source_addr_h = upper_32_bits(s_addr); - sqe->dest_addr_l = lower_32_bits(d_addr); - sqe->dest_addr_h = upper_32_bits(d_addr); + ops->fill_addr(sqe, req); + ops->fill_buf_size(sqe, req); + ops->fill_buf_type(sqe, HZIP_SGL); + ops->fill_req_type(sqe, req_type); + ops->fill_tag(sqe, req); + ops->fill_sqe_type(sqe, ops->sqe_type); +} + +static int hisi_zip_do_work(struct hisi_zip_req *req, + struct hisi_zip_qp_ctx *qp_ctx) +{ + struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; + struct acomp_req *a_req = req->req; + struct hisi_qp *qp = qp_ctx->qp; + struct device *dev = &qp->qm->pdev->dev; + struct hisi_zip_sqe zip_sqe; + int ret; + + if (!a_req->src || !a_req->slen || !a_req->dst || !a_req->dlen) + return -EINVAL; + + req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->src, pool, + req->req_id << 1, &req->dma_src); + if (IS_ERR(req->hw_src)) { + dev_err(dev, "failed to map the src buffer to hw sgl (%ld)!\n", + PTR_ERR(req->hw_src)); + return PTR_ERR(req->hw_src); + } + + req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->dst, pool, + (req->req_id << 1) + 1, + &req->dma_dst); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); + dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", + ret); + goto err_unmap_input; + } + + hisi_zip_fill_sqe(qp_ctx->ctx, &zip_sqe, qp->req_type, req); + + /* send command to start a task */ + atomic64_inc(&dfx->send_cnt); + ret = hisi_qp_send(qp, &zip_sqe); + if (ret < 0) { + atomic64_inc(&dfx->send_busy_cnt); + ret = -EAGAIN; + dev_dbg_ratelimited(dev, "failed to send request!\n"); + goto err_unmap_output; + } + + return -EINPROGRESS; + +err_unmap_output: + hisi_acc_sg_buf_unmap(dev, a_req->dst, req->hw_dst); +err_unmap_input: + hisi_acc_sg_buf_unmap(dev, a_req->src, req->hw_src); + return ret; +} + +static u32 hisi_zip_get_tag_v1(struct hisi_zip_sqe *sqe) +{ + return sqe->dw13; +} + +static u32 hisi_zip_get_tag_v2(struct hisi_zip_sqe *sqe) +{ + return sqe->dw26; +} + +static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe) +{ + return sqe->dw3 & HZIP_BD_STATUS_M; +} + +static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe) +{ + return sqe->produced; +} + +static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) +{ + struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; + const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; + struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct device *dev = &qp->qm->pdev->dev; + struct hisi_zip_sqe *sqe = data; + u32 tag = ops->get_tag(sqe); + struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; + u32 status, dlen, head_size; + int err = 0; + + atomic64_inc(&dfx->recv_cnt); + status = ops->get_status(sqe); + if (status != 0 && status != HZIP_NC_ERR) { + dev_err(dev, "%scompress fail in qp%u: %u, output: %u\n", + (qp->alg_type == 0) ? "" : "de", qp->qp_id, status, + sqe->produced); + atomic64_inc(&dfx->err_bd_cnt); + err = -EIO; + } + + dlen = ops->get_dstlen(sqe); + + hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src); + hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst); + + head_size = (qp->alg_type == 0) ? TO_HEAD_SIZE(qp->req_type) : 0; + acomp_req->dlen = dlen + head_size; + + if (acomp_req->base.complete) + acomp_request_complete(acomp_req, err); + + hisi_zip_remove_req(qp_ctx, req); +} + +static int hisi_zip_acompress(struct acomp_req *acomp_req) +{ + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; + int head_size; + int ret; + + /* let's output compression head now */ + head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); + if (head_size < 0) { + dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", + head_size); + return head_size; + } + + req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true); + if (IS_ERR(req)) + return PTR_ERR(req); + + ret = hisi_zip_do_work(req, qp_ctx); + if (ret != -EINPROGRESS) { + dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret); + hisi_zip_remove_req(qp_ctx, req); + } + + return ret; +} + +static int hisi_zip_adecompress(struct acomp_req *acomp_req) +{ + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; + int head_size, ret; + + head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); + if (head_size < 0) { + dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", + head_size); + return head_size; + } + + req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false); + if (IS_ERR(req)) + return PTR_ERR(req); + + ret = hisi_zip_do_work(req, qp_ctx); + if (ret != -EINPROGRESS) { + dev_info_ratelimited(dev, "failed to do decompress (%d)!\n", + ret); + hisi_zip_remove_req(qp_ctx, req); + } + + return ret; } static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *ctx, @@ -177,9 +524,36 @@ static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *ctx) hisi_qm_release_qp(ctx->qp); } +static const struct hisi_zip_sqe_ops hisi_zip_ops_v1 = { + .sqe_type = 0, + .fill_addr = hisi_zip_fill_addr, + .fill_buf_size = hisi_zip_fill_buf_size, + .fill_buf_type = hisi_zip_fill_buf_type, + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag_v1, + .fill_sqe_type = hisi_zip_fill_sqe_type, + .get_tag = hisi_zip_get_tag_v1, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, +}; + +static const struct hisi_zip_sqe_ops hisi_zip_ops_v2 = { + .sqe_type = 0x3, + .fill_addr = hisi_zip_fill_addr, + .fill_buf_size = hisi_zip_fill_buf_size, + .fill_buf_type = hisi_zip_fill_buf_type, + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag_v2, + .fill_sqe_type = hisi_zip_fill_sqe_type, + .get_tag = hisi_zip_get_tag_v2, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, +}; + static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int node) { struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL }; + struct hisi_zip_qp_ctx *qp_ctx; struct hisi_zip *hisi_zip; int ret, i, j; @@ -193,8 +567,9 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int for (i = 0; i < HZIP_CTX_Q_NUM; i++) { /* alg_type = 0 for compress, 1 for decompress in hw sqe */ - ret = hisi_zip_start_qp(qps[i], &hisi_zip_ctx->qp_ctx[i], i, - req_type); + qp_ctx = &hisi_zip_ctx->qp_ctx[i]; + qp_ctx->ctx = hisi_zip_ctx; + ret = hisi_zip_start_qp(qps[i], qp_ctx, i, req_type); if (ret) { for (j = i - 1; j >= 0; j--) hisi_qm_stop_qp(hisi_zip_ctx->qp_ctx[j].qp); @@ -203,50 +578,23 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int return ret; } - hisi_zip_ctx->qp_ctx[i].zip_dev = hisi_zip; - } - - return 0; -} - -static void hisi_zip_ctx_exit(struct hisi_zip_ctx *hisi_zip_ctx) -{ - int i; - - for (i = 1; i >= 0; i--) - hisi_zip_release_qp(&hisi_zip_ctx->qp_ctx[i]); -} - -static u16 get_extra_field_size(const u8 *start) -{ - return *((u16 *)start) + GZIP_HEAD_FEXTRA_XLEN; -} - -static u32 get_name_field_size(const u8 *start) -{ - return strlen(start) + 1; -} + qp_ctx->zip_dev = hisi_zip; + } -static u32 get_comment_field_size(const u8 *start) -{ - return strlen(start) + 1; + if (hisi_zip->qm.ver < QM_HW_V3) + hisi_zip_ctx->ops = &hisi_zip_ops_v1; + else + hisi_zip_ctx->ops = &hisi_zip_ops_v2; + + return 0; } -static u32 __get_gzip_head_size(const u8 *src) +static void hisi_zip_ctx_exit(struct hisi_zip_ctx *hisi_zip_ctx) { - u8 head_flg = *(src + GZIP_HEAD_FLG_SHIFT); - u32 size = GZIP_HEAD_FEXTRA_SHIFT; - - if (head_flg & GZIP_HEAD_FEXTRA_BIT) - size += get_extra_field_size(src + size); - if (head_flg & GZIP_HEAD_FNAME_BIT) - size += get_name_field_size(src + size); - if (head_flg & GZIP_HEAD_FCOMMENT_BIT) - size += get_comment_field_size(src + size); - if (head_flg & GZIP_HEAD_FHCRC_BIT) - size += GZIP_HEAD_FHCRC_SIZE; + int i; - return size; + for (i = 1; i >= 0; i--) + hisi_zip_release_qp(&hisi_zip_ctx->qp_ctx[i]); } static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx) @@ -336,52 +684,6 @@ static void hisi_zip_release_sgl_pool(struct hisi_zip_ctx *ctx) ctx->qp_ctx[i].sgl_pool); } -static void hisi_zip_remove_req(struct hisi_zip_qp_ctx *qp_ctx, - struct hisi_zip_req *req) -{ - struct hisi_zip_req_q *req_q = &qp_ctx->req_q; - - write_lock(&req_q->req_lock); - clear_bit(req->req_id, req_q->req_bitmap); - memset(req, 0, sizeof(struct hisi_zip_req)); - write_unlock(&req_q->req_lock); -} - -static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) -{ - struct hisi_zip_sqe *sqe = data; - struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; - struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; - struct hisi_zip_req_q *req_q = &qp_ctx->req_q; - struct hisi_zip_req *req = req_q->q + sqe->tag; - struct acomp_req *acomp_req = req->req; - struct device *dev = &qp->qm->pdev->dev; - u32 status, dlen, head_size; - int err = 0; - - atomic64_inc(&dfx->recv_cnt); - status = sqe->dw3 & HZIP_BD_STATUS_M; - if (status != 0 && status != HZIP_NC_ERR) { - dev_err(dev, "%scompress fail in qp%u: %u, output: %u\n", - (qp->alg_type == 0) ? "" : "de", qp->qp_id, status, - sqe->produced); - atomic64_inc(&dfx->err_bd_cnt); - err = -EIO; - } - dlen = sqe->produced; - - hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src); - hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst); - - head_size = (qp->alg_type == 0) ? TO_HEAD_SIZE(qp->req_type) : 0; - acomp_req->dlen = dlen + head_size; - - if (acomp_req->base.complete) - acomp_request_complete(acomp_req, err); - - hisi_zip_remove_req(qp_ctx, req); -} - static void hisi_zip_set_acomp_cb(struct hisi_zip_ctx *ctx, void (*fn)(struct hisi_qp *, void *)) { @@ -439,204 +741,6 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) hisi_zip_ctx_exit(ctx); } -static int add_comp_head(struct scatterlist *dst, u8 req_type) -{ - int head_size = TO_HEAD_SIZE(req_type); - const u8 *head = TO_HEAD(req_type); - int ret; - - ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size); - if (ret != head_size) { - pr_err("the head size of buffer is wrong (%d)!\n", ret); - return -ENOMEM; - } - - return head_size; -} - -static size_t __maybe_unused get_gzip_head_size(struct scatterlist *sgl) -{ - char buf[HZIP_GZIP_HEAD_BUF]; - - sg_copy_to_buffer(sgl, sg_nents(sgl), buf, sizeof(buf)); - - return __get_gzip_head_size(buf); -} - -static int get_comp_head_size(struct acomp_req *acomp_req, u8 req_type) -{ - if (!acomp_req->src || !acomp_req->slen) - return -EINVAL; - - if ((req_type == HZIP_ALG_TYPE_GZIP) && - (acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT)) - return -EINVAL; - - switch (req_type) { - case HZIP_ALG_TYPE_ZLIB: - return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB); - case HZIP_ALG_TYPE_GZIP: - return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP); - default: - pr_err("request type does not support!\n"); - return -EINVAL; - } -} - -static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req, - struct hisi_zip_qp_ctx *qp_ctx, - size_t head_size, bool is_comp) -{ - struct hisi_zip_req_q *req_q = &qp_ctx->req_q; - struct hisi_zip_req *q = req_q->q; - struct hisi_zip_req *req_cache; - int req_id; - - write_lock(&req_q->req_lock); - - req_id = find_first_zero_bit(req_q->req_bitmap, req_q->size); - if (req_id >= req_q->size) { - write_unlock(&req_q->req_lock); - dev_dbg(&qp_ctx->qp->qm->pdev->dev, "req cache is full!\n"); - return ERR_PTR(-EAGAIN); - } - set_bit(req_id, req_q->req_bitmap); - - req_cache = q + req_id; - req_cache->req_id = req_id; - req_cache->req = req; - - if (is_comp) { - req_cache->sskip = 0; - req_cache->dskip = head_size; - } else { - req_cache->sskip = head_size; - req_cache->dskip = 0; - } - - write_unlock(&req_q->req_lock); - - return req_cache; -} - -static int hisi_zip_do_work(struct hisi_zip_req *req, - struct hisi_zip_qp_ctx *qp_ctx) -{ - struct acomp_req *a_req = req->req; - struct hisi_qp *qp = qp_ctx->qp; - struct device *dev = &qp->qm->pdev->dev; - struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool; - struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; - struct hisi_zip_sqe zip_sqe; - dma_addr_t input, output; - int ret; - - if (!a_req->src || !a_req->slen || !a_req->dst || !a_req->dlen) - return -EINVAL; - - req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->src, pool, - req->req_id << 1, &input); - if (IS_ERR(req->hw_src)) { - dev_err(dev, "failed to map the src buffer to hw sgl (%ld)!\n", - PTR_ERR(req->hw_src)); - return PTR_ERR(req->hw_src); - } - req->dma_src = input; - - req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->dst, pool, - (req->req_id << 1) + 1, - &output); - if (IS_ERR(req->hw_dst)) { - ret = PTR_ERR(req->hw_dst); - dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", - ret); - goto err_unmap_input; - } - req->dma_dst = output; - - hisi_zip_fill_sqe(&zip_sqe, qp->req_type, input, output, a_req->slen, - a_req->dlen, req->sskip, req->dskip); - hisi_zip_config_buf_type(&zip_sqe, HZIP_SGL); - hisi_zip_config_tag(&zip_sqe, req->req_id); - - /* send command to start a task */ - atomic64_inc(&dfx->send_cnt); - ret = hisi_qp_send(qp, &zip_sqe); - if (ret < 0) { - atomic64_inc(&dfx->send_busy_cnt); - ret = -EAGAIN; - dev_dbg_ratelimited(dev, "failed to send request!\n"); - goto err_unmap_output; - } - - return -EINPROGRESS; - -err_unmap_output: - hisi_acc_sg_buf_unmap(dev, a_req->dst, req->hw_dst); -err_unmap_input: - hisi_acc_sg_buf_unmap(dev, a_req->src, req->hw_src); - return ret; -} - -static int hisi_zip_acompress(struct acomp_req *acomp_req) -{ - struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); - struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; - struct device *dev = &qp_ctx->qp->qm->pdev->dev; - struct hisi_zip_req *req; - int head_size; - int ret; - - /* let's output compression head now */ - head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); - if (head_size < 0) { - dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", - head_size); - return head_size; - } - - req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true); - if (IS_ERR(req)) - return PTR_ERR(req); - - ret = hisi_zip_do_work(req, qp_ctx); - if (ret != -EINPROGRESS) { - dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret); - hisi_zip_remove_req(qp_ctx, req); - } - - return ret; -} - -static int hisi_zip_adecompress(struct acomp_req *acomp_req) -{ - struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); - struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; - struct device *dev = &qp_ctx->qp->qm->pdev->dev; - struct hisi_zip_req *req; - int head_size, ret; - - head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); - if (head_size < 0) { - dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", - head_size); - return head_size; - } - - req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false); - if (IS_ERR(req)) - return PTR_ERR(req); - - ret = hisi_zip_do_work(req, qp_ctx); - if (ret != -EINPROGRESS) { - dev_info_ratelimited(dev, "failed to do decompress (%d)!\n", - ret); - hisi_zip_remove_req(qp_ctx, req); - } - - return ret; -} - static struct acomp_alg hisi_zip_acomp_zlib = { .init = hisi_zip_acomp_init, .exit = hisi_zip_acomp_exit, @@ -665,7 +769,7 @@ static struct acomp_alg hisi_zip_acomp_gzip = { } }; -int hisi_zip_register_to_crypto(void) +int hisi_zip_register_to_crypto(struct hisi_qm *qm) { int ret; @@ -684,7 +788,7 @@ int hisi_zip_register_to_crypto(void) return ret; } -void hisi_zip_unregister_from_crypto(void) +void hisi_zip_unregister_from_crypto(struct hisi_qm *qm) { crypto_unregister_acomp(&hisi_zip_acomp_gzip); crypto_unregister_acomp(&hisi_zip_acomp_zlib); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 02c445722445d6d4ae2e9c9dbbec2bd98630a3b3..2178b40e9f825bcb5114f6f16efc66abca2e9c2d 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -18,7 +18,6 @@ #define PCI_DEVICE_ID_ZIP_VF 0xa251 #define HZIP_QUEUE_NUM_V1 4096 -#define HZIP_QUEUE_NUM_V2 1024 #define HZIP_CLOCK_GATE_CTRL 0x301004 #define COMP0_ENABLE BIT(0) @@ -69,10 +68,10 @@ #define HZIP_CORE_INT_RAS_CE_ENABLE 0x1 #define HZIP_CORE_INT_RAS_NFE_ENB 0x301164 #define HZIP_CORE_INT_RAS_FE_ENB 0x301168 -#define HZIP_CORE_INT_RAS_NFE_ENABLE 0x7FE +#define HZIP_CORE_INT_RAS_NFE_ENABLE 0x1FFE #define HZIP_SRAM_ECC_ERR_NUM_SHIFT 16 #define HZIP_SRAM_ECC_ERR_ADDR_SHIFT 24 -#define HZIP_CORE_INT_MASK_ALL GENMASK(10, 0) +#define HZIP_CORE_INT_MASK_ALL GENMASK(12, 0) #define HZIP_COMP_CORE_NUM 2 #define HZIP_DECOMP_CORE_NUM 6 #define HZIP_CORE_NUM (HZIP_COMP_CORE_NUM + \ @@ -134,17 +133,17 @@ static const struct hisi_zip_hw_error zip_hw_error[] = { { .int_msk = BIT(8), .msg = "zip_com_inf_err" }, { .int_msk = BIT(9), .msg = "zip_enc_inf_err" }, { .int_msk = BIT(10), .msg = "zip_pre_out_err" }, + { .int_msk = BIT(11), .msg = "zip_axi_poison_err" }, + { .int_msk = BIT(12), .msg = "zip_sva_err" }, { /* sentinel */ } }; enum ctrl_debug_file_index { - HZIP_CURRENT_QM, HZIP_CLEAR_ENABLE, HZIP_DEBUG_FILE_NUM, }; static const char * const ctrl_debug_file_name[] = { - [HZIP_CURRENT_QM] = "current_qm", [HZIP_CLEAR_ENABLE] = "clear_enable", }; @@ -363,48 +362,6 @@ static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file) return &hisi_zip->qm; } -static u32 current_qm_read(struct ctrl_debug_file *file) -{ - struct hisi_qm *qm = file_to_qm(file); - - return readl(qm->io_base + QM_DFX_MB_CNT_VF); -} - -static int current_qm_write(struct ctrl_debug_file *file, u32 val) -{ - struct hisi_qm *qm = file_to_qm(file); - u32 vfq_num; - u32 tmp; - - if (val > qm->vfs_num) - return -EINVAL; - - /* According PF or VF Dev ID to calculation curr_qm_qp_num and store */ - if (val == 0) { - qm->debug.curr_qm_qp_num = qm->qp_num; - } else { - vfq_num = (qm->ctrl_qp_num - qm->qp_num) / qm->vfs_num; - if (val == qm->vfs_num) - qm->debug.curr_qm_qp_num = qm->ctrl_qp_num - - qm->qp_num - (qm->vfs_num - 1) * vfq_num; - else - qm->debug.curr_qm_qp_num = vfq_num; - } - - writel(val, qm->io_base + QM_DFX_MB_CNT_VF); - writel(val, qm->io_base + QM_DFX_DB_CNT_VF); - - tmp = val | - (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK); - writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN); - - tmp = val | - (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK); - writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN); - - return 0; -} - static u32 clear_enable_read(struct ctrl_debug_file *file) { struct hisi_qm *qm = file_to_qm(file); @@ -438,9 +395,6 @@ static ssize_t hisi_zip_ctrl_debug_read(struct file *filp, char __user *buf, spin_lock_irq(&file->lock); switch (file->index) { - case HZIP_CURRENT_QM: - val = current_qm_read(file); - break; case HZIP_CLEAR_ENABLE: val = clear_enable_read(file); break; @@ -478,11 +432,6 @@ static ssize_t hisi_zip_ctrl_debug_write(struct file *filp, spin_lock_irq(&file->lock); switch (file->index) { - case HZIP_CURRENT_QM: - ret = current_qm_write(file, val); - if (ret) - goto err_input; - break; case HZIP_CLEAR_ENABLE: ret = clear_enable_write(file, val); if (ret) @@ -580,7 +529,7 @@ static int hisi_zip_ctrl_debug_init(struct hisi_qm *qm) struct hisi_zip *zip = container_of(qm, struct hisi_zip, qm); int i; - for (i = HZIP_CURRENT_QM; i < HZIP_DEBUG_FILE_NUM; i++) { + for (i = HZIP_CLEAR_ENABLE; i < HZIP_DEBUG_FILE_NUM; i++) { spin_lock_init(&zip->ctrl->files[i].lock); zip->ctrl->files[i].ctrl = zip->ctrl; zip->ctrl->files[i].index = i; @@ -627,10 +576,6 @@ static void hisi_zip_debug_regs_clear(struct hisi_qm *qm) { int i, j; - /* clear current_qm */ - writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF); - writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF); - /* 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 < ARRAY_SIZE(core_offsets); i++) @@ -714,6 +659,22 @@ static void hisi_zip_close_axi_master_ooo(struct hisi_qm *qm) qm->io_base + HZIP_CORE_INT_SET); } +static void hisi_zip_err_info_init(struct hisi_qm *qm) +{ + struct hisi_qm_err_info *err_info = &qm->err_info; + + err_info->ce = QM_BASE_CE; + err_info->fe = 0; + err_info->ecc_2bits_mask = HZIP_CORE_INT_STATUS_M_ECC; + err_info->dev_ce_mask = HZIP_CORE_INT_RAS_CE_ENABLE; + err_info->msi_wr_port = HZIP_WR_PORT; + err_info->acpi_rst = "ZRST"; + err_info->nfe = QM_BASE_NFE | QM_ACC_WB_NOT_READY_TIMEOUT; + + if (qm->ver >= QM_HW_V3) + err_info->nfe |= QM_ACC_DO_TASK_TIMEOUT; +} + static const struct hisi_qm_err_ini hisi_zip_err_ini = { .hw_init = hisi_zip_set_user_domain_and_cache, .hw_err_enable = hisi_zip_hw_error_enable, @@ -723,16 +684,7 @@ static const struct hisi_qm_err_ini hisi_zip_err_ini = { .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, - .err_info = { - .ce = QM_BASE_CE, - .nfe = QM_BASE_NFE | - QM_ACC_WB_NOT_READY_TIMEOUT, - .fe = 0, - .ecc_2bits_mask = HZIP_CORE_INT_STATUS_M_ECC, - .dev_ce_mask = HZIP_CORE_INT_RAS_CE_ENABLE, - .msi_wr_port = HZIP_WR_PORT, - .acpi_rst = "ZRST", - } + .err_info_init = hisi_zip_err_info_init, }; static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) @@ -746,13 +698,8 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) hisi_zip->ctrl = ctrl; ctrl->hisi_zip = hisi_zip; - - if (qm->ver == QM_HW_V1) - qm->ctrl_qp_num = HZIP_QUEUE_NUM_V1; - else - qm->ctrl_qp_num = HZIP_QUEUE_NUM_V2; - qm->err_ini = &hisi_zip_err_ini; + qm->err_ini->err_info_init(qm); hisi_zip_set_user_domain_and_cache(qm); hisi_qm_dev_err_init(qm); diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index e813115d5432684e9c844f3eb99cbf1d77c6de95..aa4c7b2af3e2e758acfe7f8b6c09c26ec8388038 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -963,8 +963,6 @@ static int img_hash_probe(struct platform_device *pdev) hdev->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hdev->io_base)) { err = PTR_ERR(hdev->io_base); - dev_err(dev, "can't ioremap, returned %d\n", err); - goto res_err; } @@ -972,7 +970,6 @@ static int img_hash_probe(struct platform_device *pdev) hash_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); hdev->cpu_addr = devm_ioremap_resource(dev, hash_res); if (IS_ERR(hdev->cpu_addr)) { - dev_err(dev, "can't ioremap write port\n"); err = PTR_ERR(hdev->cpu_addr); goto res_err; } diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 6364583b88b216fdf5c0e2e8fc3f632061413f07..9ff885d50edfcdf6878ea9872dc2e650f3d989e3 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -688,7 +688,7 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) /* Leave the DSE threads reset state */ writel(0, EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); - /* Configure the procesing engine thresholds */ + /* Configure the processing engine thresholds */ writel(EIP197_PE_OUT_DBUF_THRES_MIN(opbuflo) | EIP197_PE_OUT_DBUF_THRES_MAX(opbufhi), EIP197_PE(priv) + EIP197_PE_OUT_DBUF_THRES(pe)); diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 8b0f17fc09fb5c16da0cc7bb85c4e95f63ab5015..0616e369522e97b097850b4bf0e989ccfa154d6b 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -265,7 +265,7 @@ static int setup_crypt_desc(void) return 0; } -static spinlock_t desc_lock; +static DEFINE_SPINLOCK(desc_lock); static struct crypt_ctl *get_crypt_desc(void) { int i; @@ -293,7 +293,7 @@ static struct crypt_ctl *get_crypt_desc(void) } } -static spinlock_t emerg_lock; +static DEFINE_SPINLOCK(emerg_lock); static struct crypt_ctl *get_crypt_desc_emerg(void) { int i; @@ -1379,9 +1379,6 @@ static int __init ixp_module_init(void) if (IS_ERR(pdev)) return PTR_ERR(pdev); - spin_lock_init(&desc_lock); - spin_lock_init(&emerg_lock); - err = init_ixp_crypto(&pdev->dev); if (err) { platform_device_unregister(pdev); diff --git a/drivers/crypto/keembay/keembay-ocs-aes-core.c b/drivers/crypto/keembay/keembay-ocs-aes-core.c index b6b25d994af38515e8bc3125e250d124f8253ba1..e2a39fdaf623e45cd9ddf918bc0876ebbd0e4b0e 100644 --- a/drivers/crypto/keembay/keembay-ocs-aes-core.c +++ b/drivers/crypto/keembay/keembay-ocs-aes-core.c @@ -1623,10 +1623,8 @@ static int kmb_ocs_aes_probe(struct platform_device *pdev) } aes_dev->base_reg = devm_ioremap_resource(&pdev->dev, aes_mem); - if (IS_ERR(aes_dev->base_reg)) { - dev_err(dev, "Failed to get base address\n"); + if (IS_ERR(aes_dev->base_reg)) return PTR_ERR(aes_dev->base_reg); - } /* Get and request IRQ */ aes_dev->irq = platform_get_irq(pdev, 0); @@ -1649,8 +1647,10 @@ static int kmb_ocs_aes_probe(struct platform_device *pdev) /* Initialize crypto engine */ aes_dev->engine = crypto_engine_alloc_init(dev, true); - if (!aes_dev->engine) + if (!aes_dev->engine) { + rc = -ENOMEM; goto list_del; + } rc = crypto_engine_start(aes_dev->engine); if (rc) { diff --git a/drivers/crypto/keembay/keembay-ocs-hcu-core.c b/drivers/crypto/keembay/keembay-ocs-hcu-core.c index c4b97b4160e9b60f2104a0f4059b9cacd1324df2..0379dbf32a4c46f8b6189cd14cab8358841c504d 100644 --- a/drivers/crypto/keembay/keembay-ocs-hcu-core.c +++ b/drivers/crypto/keembay/keembay-ocs-hcu-core.c @@ -1192,10 +1192,8 @@ static int kmb_ocs_hcu_probe(struct platform_device *pdev) } hcu_dev->io_base = devm_ioremap_resource(dev, hcu_mem); - if (IS_ERR(hcu_dev->io_base)) { - dev_err(dev, "Could not io-remap mem resource.\n"); + if (IS_ERR(hcu_dev->io_base)) return PTR_ERR(hcu_dev->io_base); - } init_completion(&hcu_dev->irq_done); @@ -1220,8 +1218,10 @@ static int kmb_ocs_hcu_probe(struct platform_device *pdev) /* Initialize crypto engine */ hcu_dev->engine = crypto_engine_alloc_init(dev, 1); - if (!hcu_dev->engine) + if (!hcu_dev->engine) { + rc = -ENOMEM; goto list_del; + } rc = crypto_engine_start(hcu_dev->engine); if (rc) { diff --git a/drivers/crypto/keembay/ocs-hcu.c b/drivers/crypto/keembay/ocs-hcu.c index 81eecacf603adc25bde90770a2dcc3b80d042086..deb9bd460ee621a542e4ef5606e4f80bf0213e2c 100644 --- a/drivers/crypto/keembay/ocs-hcu.c +++ b/drivers/crypto/keembay/ocs-hcu.c @@ -93,7 +93,7 @@ #define OCS_HCU_WAIT_BUSY_TIMEOUT_US 1000000 /** - * struct ocs_hcu_dma_list - An entry in an OCS DMA linked list. + * struct ocs_hcu_dma_entry - An entry in an OCS DMA linked list. * @src_addr: Source address of the data. * @src_len: Length of data to be fetched. * @nxt_desc: Next descriptor to fetch. @@ -107,7 +107,7 @@ struct ocs_hcu_dma_entry { }; /** - * struct ocs_dma_list - OCS-specific DMA linked list. + * struct ocs_hcu_dma_list - OCS-specific DMA linked list. * @head: The head of the list (points to the array backing the list). * @tail: The current tail of the list; NULL if the list is empty. * @dma_addr: The DMA address of @head (i.e., the DMA address of the backing @@ -597,7 +597,7 @@ int ocs_hcu_hash_init(struct ocs_hcu_hash_ctx *ctx, enum ocs_hcu_algo algo) } /** - * ocs_hcu_digest() - Perform a hashing iteration. + * ocs_hcu_hash_update() - Perform a hashing iteration. * @hcu_dev: The OCS HCU device to use. * @ctx: The OCS HCU hashing context. * @dma_list: The OCS DMA list mapping the input data to process. @@ -632,7 +632,7 @@ int ocs_hcu_hash_update(struct ocs_hcu_dev *hcu_dev, } /** - * ocs_hcu_hash_final() - Update and finalize hash computation. + * ocs_hcu_hash_finup() - Update and finalize hash computation. * @hcu_dev: The OCS HCU device to use. * @ctx: The OCS HCU hashing context. * @dma_list: The OCS DMA list mapping the input data to process. diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h b/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h index 3518fac2983468b3b36b9460fae15f0808f32f7c..ecedd91a8d859c0a9addb32f536054e44a80fb8a 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h @@ -121,14 +121,14 @@ int otx2_cpt_send_mbox_msg(struct otx2_mbox *mbox, struct pci_dev *pdev); int otx2_cpt_send_af_reg_requests(struct otx2_mbox *mbox, struct pci_dev *pdev); -int otx2_cpt_add_read_af_reg(struct otx2_mbox *mbox, - struct pci_dev *pdev, u64 reg, u64 *val); +int otx2_cpt_add_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, + u64 reg, u64 *val, int blkaddr); int otx2_cpt_add_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 val); + u64 reg, u64 val, int blkaddr); int otx2_cpt_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 *val); + u64 reg, u64 *val, int blkaddr); int otx2_cpt_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 val); + u64 reg, u64 val, int blkaddr); struct otx2_cptlfs_info; int otx2_cpt_attach_rscrs_msg(struct otx2_cptlfs_info *lfs); int otx2_cpt_detach_rsrcs_msg(struct otx2_cptlfs_info *lfs); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c b/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c index 51cb6404ded7a33e62e90db928c67adf87c86d8c..9074876d38e5d4e6a09f9507e7e1a440d2add571 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c @@ -43,7 +43,7 @@ int otx2_cpt_send_af_reg_requests(struct otx2_mbox *mbox, struct pci_dev *pdev) } int otx2_cpt_add_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 *val) + u64 reg, u64 *val, int blkaddr) { struct cpt_rd_wr_reg_msg *reg_msg; @@ -62,12 +62,13 @@ int otx2_cpt_add_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, reg_msg->is_write = 0; reg_msg->reg_offset = reg; reg_msg->ret_val = val; + reg_msg->blkaddr = blkaddr; return 0; } int otx2_cpt_add_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 val) + u64 reg, u64 val, int blkaddr) { struct cpt_rd_wr_reg_msg *reg_msg; @@ -86,16 +87,17 @@ int otx2_cpt_add_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, reg_msg->is_write = 1; reg_msg->reg_offset = reg; reg_msg->val = val; + reg_msg->blkaddr = blkaddr; return 0; } int otx2_cpt_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 *val) + u64 reg, u64 *val, int blkaddr) { int ret; - ret = otx2_cpt_add_read_af_reg(mbox, pdev, reg, val); + ret = otx2_cpt_add_read_af_reg(mbox, pdev, reg, val, blkaddr); if (ret) return ret; @@ -103,11 +105,11 @@ int otx2_cpt_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, } int otx2_cpt_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, - u64 reg, u64 val) + u64 reg, u64 val, int blkaddr) { int ret; - ret = otx2_cpt_add_write_af_reg(mbox, pdev, reg, val); + ret = otx2_cpt_add_write_af_reg(mbox, pdev, reg, val, blkaddr); if (ret) return ret; diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c index 823a4571fd674577a864a472af3c439ba0e907ed..34aba1532761231f6e01c2051c5abb44ca9762a9 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c @@ -56,7 +56,7 @@ static int cptlf_set_pri(struct otx2_cptlf_info *lf, int pri) ret = otx2_cpt_read_af_reg(lfs->mbox, lfs->pdev, CPT_AF_LFX_CTL(lf->slot), - &lf_ctrl.u); + &lf_ctrl.u, lfs->blkaddr); if (ret) return ret; @@ -64,7 +64,7 @@ static int cptlf_set_pri(struct otx2_cptlf_info *lf, int pri) ret = otx2_cpt_write_af_reg(lfs->mbox, lfs->pdev, CPT_AF_LFX_CTL(lf->slot), - lf_ctrl.u); + lf_ctrl.u, lfs->blkaddr); return ret; } @@ -77,7 +77,7 @@ static int cptlf_set_eng_grps_mask(struct otx2_cptlf_info *lf, ret = otx2_cpt_read_af_reg(lfs->mbox, lfs->pdev, CPT_AF_LFX_CTL(lf->slot), - &lf_ctrl.u); + &lf_ctrl.u, lfs->blkaddr); if (ret) return ret; @@ -85,7 +85,7 @@ static int cptlf_set_eng_grps_mask(struct otx2_cptlf_info *lf, ret = otx2_cpt_write_af_reg(lfs->mbox, lfs->pdev, CPT_AF_LFX_CTL(lf->slot), - lf_ctrl.u); + lf_ctrl.u, lfs->blkaddr); return ret; } diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.h b/drivers/crypto/marvell/octeontx2/otx2_cptlf.h index 314e973541004fe43b41ce7d7b039df32decb0b6..ab1678fc564d63710cd3dba8790331ca2d6ad493 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.h @@ -95,6 +95,7 @@ struct otx2_cptlfs_info { u8 kcrypto_eng_grp_num; /* Kernel crypto engine group number */ u8 kvf_limits; /* Kernel crypto limits */ atomic_t state; /* LF's state. started/reset */ + int blkaddr; /* CPT blkaddr: BLKADDR_CPT0/BLKADDR_CPT1 */ }; static inline void otx2_cpt_free_instruction_queues( diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf.h b/drivers/crypto/marvell/octeontx2/otx2_cptpf.h index 8c899ad531a5c868a3fe031be625746268b4ead8..e19af1356f1236d2462d7332b69433d9bb161804 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf.h @@ -51,6 +51,7 @@ struct otx2_cptpf_dev { u8 max_vfs; /* Maximum number of VFs supported by CPT */ u8 enabled_vfs; /* Number of enabled VFs */ u8 kvf_limits; /* Kernel crypto limits */ + bool has_cpt1; }; irqreturn_t otx2_cptpf_afpf_mbox_intr(int irq, void *arg); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c index 5277e04badd9abd527995c55553f229375bec766..58f47e3ab62e73c2829101557bb55659771aa1a4 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c @@ -451,19 +451,19 @@ static int cpt_is_pf_usable(struct otx2_cptpf_dev *cptpf) return 0; } -static int cptpf_device_reset(struct otx2_cptpf_dev *cptpf) +static int cptx_device_reset(struct otx2_cptpf_dev *cptpf, int blkaddr) { int timeout = 10, ret; u64 reg = 0; ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_BLK_RST, 0x1); + CPT_AF_BLK_RST, 0x1, blkaddr); if (ret) return ret; do { ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_BLK_RST, ®); + CPT_AF_BLK_RST, ®, blkaddr); if (ret) return ret; @@ -478,11 +478,35 @@ static int cptpf_device_reset(struct otx2_cptpf_dev *cptpf) return ret; } +static int cptpf_device_reset(struct otx2_cptpf_dev *cptpf) +{ + int ret = 0; + + if (cptpf->has_cpt1) { + ret = cptx_device_reset(cptpf, BLKADDR_CPT1); + if (ret) + return ret; + } + return cptx_device_reset(cptpf, BLKADDR_CPT0); +} + +static void cptpf_check_block_implemented(struct otx2_cptpf_dev *cptpf) +{ + u64 cfg; + + cfg = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0, + RVU_PF_BLOCK_ADDRX_DISC(BLKADDR_CPT1)); + if (cfg & BIT_ULL(11)) + cptpf->has_cpt1 = true; +} + static int cptpf_device_init(struct otx2_cptpf_dev *cptpf) { union otx2_cptx_af_constants1 af_cnsts1 = {0}; int ret = 0; + /* check if 'implemented' bit is set for block BLKADDR_CPT1 */ + cptpf_check_block_implemented(cptpf); /* Reset the CPT PF device */ ret = cptpf_device_reset(cptpf); if (ret) @@ -490,7 +514,8 @@ static int cptpf_device_init(struct otx2_cptpf_dev *cptpf) /* Get number of SE, IE and AE engines */ ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_CONSTANTS1, &af_cnsts1.u); + CPT_AF_CONSTANTS1, &af_cnsts1.u, + BLKADDR_CPT0); if (ret) return ret; diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c index 1dc3ba298139ff2c5337cf63df564f4cf8796c69..a531f4c8b4414ae3d5c898115a99a0a0da6a119b 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c @@ -153,16 +153,16 @@ static int get_ucode_type(struct device *dev, } static int __write_ucode_base(struct otx2_cptpf_dev *cptpf, int eng, - dma_addr_t dma_addr) + dma_addr_t dma_addr, int blkaddr) { return otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, CPT_AF_EXEX_UCODE_BASE(eng), - (u64)dma_addr); + (u64)dma_addr, blkaddr); } -static int cpt_set_ucode_base(struct otx2_cpt_eng_grp_info *eng_grp, void *obj) +static int cptx_set_ucode_base(struct otx2_cpt_eng_grp_info *eng_grp, + struct otx2_cptpf_dev *cptpf, int blkaddr) { - struct otx2_cptpf_dev *cptpf = obj; struct otx2_cpt_engs_rsvd *engs; dma_addr_t dma_addr; int i, bit, ret; @@ -170,7 +170,7 @@ static int cpt_set_ucode_base(struct otx2_cpt_eng_grp_info *eng_grp, void *obj) /* Set PF number for microcode fetches */ ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, CPT_AF_PF_FUNC, - cptpf->pf_id << RVU_PFVF_PF_SHIFT); + cptpf->pf_id << RVU_PFVF_PF_SHIFT, blkaddr); if (ret) return ret; @@ -187,7 +187,8 @@ static int cpt_set_ucode_base(struct otx2_cpt_eng_grp_info *eng_grp, void *obj) */ for_each_set_bit(bit, engs->bmap, eng_grp->g->engs_num) if (!eng_grp->g->eng_ref_cnt[bit]) { - ret = __write_ucode_base(cptpf, bit, dma_addr); + ret = __write_ucode_base(cptpf, bit, dma_addr, + blkaddr); if (ret) return ret; } @@ -195,23 +196,32 @@ static int cpt_set_ucode_base(struct otx2_cpt_eng_grp_info *eng_grp, void *obj) return 0; } -static int cpt_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, - void *obj) +static int cpt_set_ucode_base(struct otx2_cpt_eng_grp_info *eng_grp, void *obj) { struct otx2_cptpf_dev *cptpf = obj; - struct otx2_cpt_bitmap bmap; + int ret; + + if (cptpf->has_cpt1) { + ret = cptx_set_ucode_base(eng_grp, cptpf, BLKADDR_CPT1); + if (ret) + return ret; + } + return cptx_set_ucode_base(eng_grp, cptpf, BLKADDR_CPT0); +} + +static int cptx_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, + struct otx2_cptpf_dev *cptpf, + struct otx2_cpt_bitmap bmap, + int blkaddr) +{ int i, timeout = 10; int busy, ret; u64 reg = 0; - bmap = get_cores_bmap(&cptpf->pdev->dev, eng_grp); - if (!bmap.size) - return -EINVAL; - /* Detach the cores from group */ for_each_set_bit(i, bmap.bits, bmap.size) { ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL2(i), ®); + CPT_AF_EXEX_CTL2(i), ®, blkaddr); if (ret) return ret; @@ -221,7 +231,8 @@ static int cpt_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL2(i), reg); + CPT_AF_EXEX_CTL2(i), reg, + blkaddr); if (ret) return ret; } @@ -237,7 +248,8 @@ static int cpt_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, for_each_set_bit(i, bmap.bits, bmap.size) { ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_STS(i), ®); + CPT_AF_EXEX_STS(i), ®, + blkaddr); if (ret) return ret; @@ -253,7 +265,8 @@ static int cpt_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, if (!eng_grp->g->eng_ref_cnt[i]) { ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL(i), 0x0); + CPT_AF_EXEX_CTL(i), 0x0, + blkaddr); if (ret) return ret; } @@ -262,22 +275,39 @@ static int cpt_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, return 0; } -static int cpt_attach_and_enable_cores(struct otx2_cpt_eng_grp_info *eng_grp, - void *obj) +static int cpt_detach_and_disable_cores(struct otx2_cpt_eng_grp_info *eng_grp, + void *obj) { struct otx2_cptpf_dev *cptpf = obj; struct otx2_cpt_bitmap bmap; - u64 reg = 0; - int i, ret; + int ret; bmap = get_cores_bmap(&cptpf->pdev->dev, eng_grp); if (!bmap.size) return -EINVAL; + if (cptpf->has_cpt1) { + ret = cptx_detach_and_disable_cores(eng_grp, cptpf, bmap, + BLKADDR_CPT1); + if (ret) + return ret; + } + return cptx_detach_and_disable_cores(eng_grp, cptpf, bmap, + BLKADDR_CPT0); +} + +static int cptx_attach_and_enable_cores(struct otx2_cpt_eng_grp_info *eng_grp, + struct otx2_cptpf_dev *cptpf, + struct otx2_cpt_bitmap bmap, + int blkaddr) +{ + u64 reg = 0; + int i, ret; + /* Attach the cores to the group */ for_each_set_bit(i, bmap.bits, bmap.size) { ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL2(i), ®); + CPT_AF_EXEX_CTL2(i), ®, blkaddr); if (ret) return ret; @@ -287,7 +317,8 @@ static int cpt_attach_and_enable_cores(struct otx2_cpt_eng_grp_info *eng_grp, ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL2(i), reg); + CPT_AF_EXEX_CTL2(i), reg, + blkaddr); if (ret) return ret; } @@ -295,15 +326,33 @@ static int cpt_attach_and_enable_cores(struct otx2_cpt_eng_grp_info *eng_grp, /* Enable the cores */ for_each_set_bit(i, bmap.bits, bmap.size) { - ret = otx2_cpt_add_write_af_reg(&cptpf->afpf_mbox, - cptpf->pdev, - CPT_AF_EXEX_CTL(i), 0x1); + ret = otx2_cpt_add_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, + CPT_AF_EXEX_CTL(i), 0x1, + blkaddr); if (ret) return ret; } - ret = otx2_cpt_send_af_reg_requests(&cptpf->afpf_mbox, cptpf->pdev); + return otx2_cpt_send_af_reg_requests(&cptpf->afpf_mbox, cptpf->pdev); +} - return ret; +static int cpt_attach_and_enable_cores(struct otx2_cpt_eng_grp_info *eng_grp, + void *obj) +{ + struct otx2_cptpf_dev *cptpf = obj; + struct otx2_cpt_bitmap bmap; + int ret; + + bmap = get_cores_bmap(&cptpf->pdev->dev, eng_grp); + if (!bmap.size) + return -EINVAL; + + if (cptpf->has_cpt1) { + ret = cptx_attach_and_enable_cores(eng_grp, cptpf, bmap, + BLKADDR_CPT1); + if (ret) + return ret; + } + return cptx_attach_and_enable_cores(eng_grp, cptpf, bmap, BLKADDR_CPT0); } static int load_fw(struct device *dev, struct fw_info_t *fw_info, @@ -1140,20 +1189,18 @@ release_fw: return ret; } -int otx2_cpt_disable_all_cores(struct otx2_cptpf_dev *cptpf) +static int cptx_disable_all_cores(struct otx2_cptpf_dev *cptpf, int total_cores, + int blkaddr) { - int i, ret, busy, total_cores; - int timeout = 10; - u64 reg = 0; - - total_cores = cptpf->eng_grps.avail.max_se_cnt + - cptpf->eng_grps.avail.max_ie_cnt + - cptpf->eng_grps.avail.max_ae_cnt; + int timeout = 10, ret; + int i, busy; + u64 reg; /* Disengage the cores from groups */ for (i = 0; i < total_cores; i++) { ret = otx2_cpt_add_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL2(i), 0x0); + CPT_AF_EXEX_CTL2(i), 0x0, + blkaddr); if (ret) return ret; @@ -1173,7 +1220,8 @@ int otx2_cpt_disable_all_cores(struct otx2_cptpf_dev *cptpf) for (i = 0; i < total_cores; i++) { ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_STS(i), ®); + CPT_AF_EXEX_STS(i), ®, + blkaddr); if (ret) return ret; @@ -1187,13 +1235,30 @@ int otx2_cpt_disable_all_cores(struct otx2_cptpf_dev *cptpf) /* Disable the cores */ for (i = 0; i < total_cores; i++) { ret = otx2_cpt_add_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_EXEX_CTL(i), 0x0); + CPT_AF_EXEX_CTL(i), 0x0, + blkaddr); if (ret) return ret; } return otx2_cpt_send_af_reg_requests(&cptpf->afpf_mbox, cptpf->pdev); } +int otx2_cpt_disable_all_cores(struct otx2_cptpf_dev *cptpf) +{ + int total_cores, ret; + + total_cores = cptpf->eng_grps.avail.max_se_cnt + + cptpf->eng_grps.avail.max_ie_cnt + + cptpf->eng_grps.avail.max_ae_cnt; + + if (cptpf->has_cpt1) { + ret = cptx_disable_all_cores(cptpf, total_cores, BLKADDR_CPT1); + if (ret) + return ret; + } + return cptx_disable_all_cores(cptpf, total_cores, BLKADDR_CPT0); +} + void otx2_cpt_cleanup_eng_grps(struct pci_dev *pdev, struct otx2_cpt_eng_grps *eng_grps) { @@ -1354,6 +1419,7 @@ int otx2_cpt_discover_eng_capabilities(struct otx2_cptpf_dev *cptpf) lfs->pdev = pdev; lfs->reg_base = cptpf->reg_base; lfs->mbox = &cptpf->afpf_mbox; + lfs->blkaddr = BLKADDR_CPT0; ret = otx2_cptlf_init(&cptpf->lfs, OTX2_CPT_ALL_ENG_GRPS_MASK, OTX2_CPT_QUEUE_HI_PRIO, 1); if (ret) diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c index 92e921eceed755f874907c15f5a8ad3473d95683..d6314ea9ae896ed4255f122c18defe0ae64737ef 100644 --- a/drivers/crypto/nx/nx-aes-cbc.c +++ b/drivers/crypto/nx/nx-aes-cbc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES CBC routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 4c9362eebefd252a45416aa1cbe01fef43da621b..e7384d1075739b08960fdc27efeee4735a7509df 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES CCM routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c index 6d5ce1a66f1eeb12a949652c14dd38cfe9c904c1..13f518802343d40f3345f293dfbd31b79ddd43b6 100644 --- a/drivers/crypto/nx/nx-aes-ctr.c +++ b/drivers/crypto/nx/nx-aes-ctr.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES CTR routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c index 77e338dc33f1de1988b3df7343fe738b8ac5ca94..7a729dc2bc17a3342f0a53cf1e0d3b96bb173ace 100644 --- a/drivers/crypto/nx/nx-aes-ecb.c +++ b/drivers/crypto/nx/nx-aes-ecb.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES ECB routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index 19c6ed5baea41378837c828628e61bf2b20f8420..fc9baca13920cf0771fb27ef456134fa880837e7 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES GCM routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-aes-xcbc.c b/drivers/crypto/nx/nx-aes-xcbc.c index 48dc1c98ca52587ed055b1c3660b1d00cf848d64..eb5c8f6893601237e1dc0ae30c8328bf03e4bdd3 100644 --- a/drivers/crypto/nx/nx-aes-xcbc.c +++ b/drivers/crypto/nx/nx-aes-xcbc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES XCBC routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c index 13c65deda8e979f75ce4231240bf5549996000f1..446f611726df5a6afabe751828dbd30ebbc4d8fb 100644 --- a/drivers/crypto/nx/nx-common-powernv.c +++ b/drivers/crypto/nx/nx-common-powernv.c @@ -932,8 +932,10 @@ static int __init nx_powernv_probe_vas(struct device_node *pn) ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip); - if (ret) + if (ret) { + of_node_put(dn); return ret; + } } if (!ct_842 || !ct_gzip) { diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c index 90d9a37a57f64565a8d5538e74c0eb04f512be6d..b0ad665e4bda81936c8941198d8f50e2677c49a0 100644 --- a/drivers/crypto/nx/nx-sha256.c +++ b/drivers/crypto/nx/nx-sha256.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * SHA-256 routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c index eb8627a0f3176ee8e6f5890ef1b75e0c1611a907..c29103a1a0b6c93858c28eecf7d7535dde9f80d1 100644 --- a/drivers/crypto/nx/nx-sha512.c +++ b/drivers/crypto/nx/nx-sha512.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * SHA-512 routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 1d0e8a1ba160507337f71ebb8d541ec7c09d76e5..010e87d9da36b75c8ddbd825bc7cf28197000f43 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. @@ -200,7 +200,8 @@ struct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst, * @sg: sg list head * @end: sg lisg end * @delta: is the amount we need to crop in order to bound the list. - * + * @nbytes: length of data in the scatterlists or data length - whichever + * is greater. */ static long int trim_sg_list(struct nx_sg *sg, struct nx_sg *end, diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c index 1975bcbee997481ee095dc3adaa4841708bf61cd..ee7cd88bb10a79506a0cea7eb61fd83bd98130ec 100644 --- a/drivers/crypto/nx/nx_debugfs.c +++ b/drivers/crypto/nx/nx_debugfs.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * debugfs routines supporting the Power 7+ Nest Accelerators driver * * Copyright (C) 2011-2012 International Business Machines Inc. diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index a45bdcf3026df9bdfda3746f4436575cc0df4593..0dd4c6b157de903972cd13179d79e10f87a2a419 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -103,9 +103,8 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd) dd->err = 0; } - err = pm_runtime_get_sync(dd->dev); + err = pm_runtime_resume_and_get(dd->dev); if (err < 0) { - pm_runtime_put_noidle(dd->dev); dev_err(dd->dev, "failed to get sync: %d\n", err); return err; } @@ -1134,7 +1133,7 @@ static int omap_aes_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); - err = pm_runtime_get_sync(dev); + err = pm_runtime_resume_and_get(dev); if (err < 0) { dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err); @@ -1303,7 +1302,7 @@ static int omap_aes_suspend(struct device *dev) static int omap_aes_resume(struct device *dev) { - pm_runtime_get_sync(dev); + pm_runtime_resume_and_get(dev); return 0; } #endif diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index 6a9be01fdf33c2bb176d41e2e723ec338589ea50..3524ddd4893009394f79e0a217204b2ba4498855 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -224,6 +224,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) hw_data->uof_get_name = uof_get_name; hw_data->uof_get_ae_mask = uof_get_ae_mask; hw_data->set_msix_rttable = set_msix_default_rttable; + hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; adf_gen4_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index f5990d042c9a15dce7bcafdccfef2d6ac85bcf42..1dd64af22bea92fa3c7b89f23ab78a116e74f14c 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -212,6 +212,7 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data) hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; hw_data->reset_device = adf_reset_flr; hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index 1d1532e8fb6d98406ac6475ad581afde04340a89..067ca5e17d387cb87c7053aab8ec16a54bd49bb7 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c @@ -184,12 +184,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_err_free_reg; - set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); - ret = adf_dev_init(accel_dev); if (ret) goto out_err_dev_shutdown; + set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); + ret = adf_dev_start(accel_dev); if (ret) goto out_err_dev_stop; diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index cadcf12884c8b4f517f1fd6fcd3f0f08bcb46e51..30337390513c6fdc309c15e66c2e13127b883231 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -214,6 +214,7 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data) hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; hw_data->reset_device = adf_reset_flr; hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c index 04742a6d91cae9df25d4c6b75d01b46ce19b60c0..51ea88c0b17d7751515bb63e316ce85853e3f290 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c @@ -184,12 +184,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_err_free_reg; - set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); - ret = adf_dev_init(accel_dev); if (ret) goto out_err_dev_shutdown; + set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); + ret = adf_dev_start(accel_dev); if (ret) goto out_err_dev_stop; diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 5527344546e5e6b3011e9819153b14e6499637ae..ac435b44f1d20d12cf0c3a00824302ec83452d6e 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -173,6 +173,7 @@ struct adf_hw_device_data { void (*configure_iov_threads)(struct adf_accel_dev *accel_dev, bool enable); void (*enable_ints)(struct adf_accel_dev *accel_dev); + void (*set_ssm_wdtimer)(struct adf_accel_dev *accel_dev); int (*enable_vf2pf_comms)(struct adf_accel_dev *accel_dev); void (*reset_device)(struct adf_accel_dev *accel_dev); void (*set_msix_rttable)(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c index 1aa17303838db325624f9f95657479b03a8a903e..9e560c7d416307aaef29f65c64b89c9f58fc50ca 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c @@ -179,3 +179,28 @@ u32 adf_gen2_get_accel_cap(struct adf_accel_dev *accel_dev) return capabilities; } EXPORT_SYMBOL_GPL(adf_gen2_get_accel_cap); + +void adf_gen2_set_ssm_wdtimer(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 timer_val_pke = ADF_SSM_WDT_PKE_DEFAULT_VALUE; + u32 timer_val = ADF_SSM_WDT_DEFAULT_VALUE; + unsigned long accel_mask = hw_data->accel_mask; + void __iomem *pmisc_addr; + struct adf_bar *pmisc; + int pmisc_id; + u32 i = 0; + + pmisc_id = hw_data->get_misc_bar_id(hw_data); + pmisc = &GET_BARS(accel_dev)[pmisc_id]; + pmisc_addr = pmisc->virt_addr; + + /* Configures WDT timers */ + for_each_set_bit(i, &accel_mask, hw_data->num_accel) { + /* Enable WDT for sym and dc */ + ADF_CSR_WR(pmisc_addr, ADF_SSMWDT(i), timer_val); + /* Enable WDT for pke */ + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTPKE(i), timer_val_pke); + } +} +EXPORT_SYMBOL_GPL(adf_gen2_set_ssm_wdtimer); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h index 3816e6500352a6b6fc8a51fda630e549493688ff..756b0ddfac5e16661ff1f7724ca06afa877a764d 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h +++ b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h @@ -113,11 +113,24 @@ do { \ /* Power gating */ #define ADF_POWERGATE_PKE BIT(24) +/* WDT timers + * + * Timeout is in cycles. Clock speed may vary across products but this + * value should be a few milli-seconds. + */ +#define ADF_SSM_WDT_DEFAULT_VALUE 0x200000 +#define ADF_SSM_WDT_PKE_DEFAULT_VALUE 0x2000000 +#define ADF_SSMWDT_OFFSET 0x54 +#define ADF_SSMWDTPKE_OFFSET 0x58 +#define ADF_SSMWDT(i) (ADF_SSMWDT_OFFSET + ((i) * 0x4000)) +#define ADF_SSMWDTPKE(i) (ADF_SSMWDTPKE_OFFSET + ((i) * 0x4000)) + void adf_gen2_cfg_iov_thds(struct adf_accel_dev *accel_dev, bool enable, int num_a_regs, int num_b_regs); void adf_gen2_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops); void adf_gen2_get_admin_info(struct admin_info *admin_csrs_info); void adf_gen2_get_arb_info(struct arb_info *arb_info); u32 adf_gen2_get_accel_cap(struct adf_accel_dev *accel_dev); +void adf_gen2_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); #endif diff --git a/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c b/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c index b72ff58e0bc791cf71bc464a0b848c88301b0030..000528327b296b08f4509a868352d48d9a881070 100644 --- a/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c +++ b/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c @@ -99,3 +99,43 @@ void adf_gen4_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops) csr_ops->write_csr_ring_srv_arb_en = write_csr_ring_srv_arb_en; } EXPORT_SYMBOL_GPL(adf_gen4_init_hw_csr_ops); + +static inline void adf_gen4_unpack_ssm_wdtimer(u64 value, u32 *upper, + u32 *lower) +{ + *lower = lower_32_bits(value); + *upper = upper_32_bits(value); +} + +void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u64 timer_val_pke = ADF_SSM_WDT_PKE_DEFAULT_VALUE; + u64 timer_val = ADF_SSM_WDT_DEFAULT_VALUE; + u32 ssm_wdt_pke_high = 0; + u32 ssm_wdt_pke_low = 0; + u32 ssm_wdt_high = 0; + u32 ssm_wdt_low = 0; + void __iomem *pmisc_addr; + struct adf_bar *pmisc; + int pmisc_id; + + pmisc_id = hw_data->get_misc_bar_id(hw_data); + pmisc = &GET_BARS(accel_dev)[pmisc_id]; + pmisc_addr = pmisc->virt_addr; + + /* Convert 64bit WDT timer value into 32bit values for + * mmio write to 32bit CSRs. + */ + adf_gen4_unpack_ssm_wdtimer(timer_val, &ssm_wdt_high, &ssm_wdt_low); + adf_gen4_unpack_ssm_wdtimer(timer_val_pke, &ssm_wdt_pke_high, + &ssm_wdt_pke_low); + + /* Enable WDT for sym and dc */ + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTL_OFFSET, ssm_wdt_low); + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTH_OFFSET, ssm_wdt_high); + /* Enable WDT for pke */ + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTPKEL_OFFSET, ssm_wdt_pke_low); + ADF_CSR_WR(pmisc_addr, ADF_SSMWDTPKEH_OFFSET, ssm_wdt_pke_high); +} +EXPORT_SYMBOL_GPL(adf_gen4_set_ssm_wdtimer); diff --git a/drivers/crypto/qat/qat_common/adf_gen4_hw_data.h b/drivers/crypto/qat/qat_common/adf_gen4_hw_data.h index 8ab62b2ac311fec8bc14a21c164b5efab81be7c6..b8fca1ff7aab0fd1c97817cec2e340fcc1be2178 100644 --- a/drivers/crypto/qat/qat_common/adf_gen4_hw_data.h +++ b/drivers/crypto/qat/qat_common/adf_gen4_hw_data.h @@ -94,6 +94,18 @@ do { \ ADF_RING_BUNDLE_SIZE * (bank) + \ ADF_RING_CSR_RING_SRV_ARB_EN, (value)) -void adf_gen4_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops); +/* WDT timers + * + * Timeout is in cycles. Clock speed may vary across products but this + * value should be a few milli-seconds. + */ +#define ADF_SSM_WDT_DEFAULT_VALUE 0x200000 +#define ADF_SSM_WDT_PKE_DEFAULT_VALUE 0x8000000 +#define ADF_SSMWDTL_OFFSET 0x54 +#define ADF_SSMWDTH_OFFSET 0x5C +#define ADF_SSMWDTPKEL_OFFSET 0x58 +#define ADF_SSMWDTPKEH_OFFSET 0x60 +void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); +void adf_gen4_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops); #endif diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index 42029153408ee738b0f0b057d083cbc2c8bf84b9..744c40351428da6ceeda9f01bcdcbd0798cff732 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -162,6 +162,10 @@ int adf_dev_start(struct adf_accel_dev *accel_dev) return -EFAULT; } + /* Set ssm watch dog timer */ + if (hw_data->set_ssm_wdtimer) + hw_data->set_ssm_wdtimer(accel_dev); + list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); if (service->event_hld(accel_dev, ADF_EVENT_START)) { diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index c458534635306801ff983102d4788345121a2774..e3ad5587be49e0fc12897fa5b4d74ab5a89f1237 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -291,19 +291,32 @@ int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev) ret = adf_isr_alloc_msix_entry_table(accel_dev); if (ret) - return ret; - if (adf_enable_msix(accel_dev)) goto err_out; - if (adf_setup_bh(accel_dev)) - goto err_out; + ret = adf_enable_msix(accel_dev); + if (ret) + goto err_free_msix_table; - if (adf_request_irqs(accel_dev)) - goto err_out; + ret = adf_setup_bh(accel_dev); + if (ret) + goto err_disable_msix; + + ret = adf_request_irqs(accel_dev); + if (ret) + goto err_cleanup_bh; return 0; + +err_cleanup_bh: + adf_cleanup_bh(accel_dev); + +err_disable_msix: + adf_disable_msix(&accel_dev->accel_pci_dev); + +err_free_msix_table: + adf_isr_free_msix_entry_table(accel_dev); + err_out: - adf_isr_resource_free(accel_dev); - return -EFAULT; + return ret; } EXPORT_SYMBOL_GPL(adf_isr_resource_alloc); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 8b090b7ae8c6b6b8cdef2eab47253f444396845d..a1b77bd7a89443cc22b4801f49b3ea8868639ce2 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -169,7 +169,7 @@ out: * @msg: Message to send * @vf_nr: VF number to which the message will be sent * - * Function sends a messge from the PF to a VF + * Function sends a message from the PF to a VF * * Return: 0 on success, error code otherwise. */ diff --git a/drivers/crypto/qat/qat_common/adf_transport.c b/drivers/crypto/qat/qat_common/adf_transport.c index 888c1e0472952591ea8105f6d1377db787730486..8ba28409fb74b7ad9da74f6a9ec659a31b4124c2 100644 --- a/drivers/crypto/qat/qat_common/adf_transport.c +++ b/drivers/crypto/qat/qat_common/adf_transport.c @@ -172,6 +172,7 @@ static int adf_init_ring(struct adf_etr_ring_data *ring) dev_err(&GET_DEV(accel_dev), "Ring address not aligned\n"); dma_free_coherent(&GET_DEV(accel_dev), ring_size_bytes, ring->base_addr, ring->dma_addr); + ring->base_addr = NULL; return -EFAULT; } diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index 2c98fb63f7b7218bac08bc56658f7bb18bb08240..e85bd62d134a4224dfb8e5f717e8a0ef74f41393 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -8,7 +8,7 @@ * adf_vf2pf_init() - send init msg to PF * @accel_dev: Pointer to acceleration VF device. * - * Function sends an init messge from the VF to a PF + * Function sends an init message from the VF to a PF * * Return: 0 on success, error code otherwise. */ @@ -31,7 +31,7 @@ EXPORT_SYMBOL_GPL(adf_vf2pf_init); * adf_vf2pf_shutdown() - send shutdown msg to PF * @accel_dev: Pointer to acceleration VF device. * - * Function sends a shutdown messge from the VF to a PF + * Function sends a shutdown message from the VF to a PF * * Return: void */ diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index 38d316a42ba6f7f46b9d2410258891c20a25a6ca..888388acb6bd3e7e3b8019f2d1d6a7d6d038071a 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -261,17 +261,26 @@ int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev) goto err_out; if (adf_setup_pf2vf_bh(accel_dev)) - goto err_out; + goto err_disable_msi; if (adf_setup_bh(accel_dev)) - goto err_out; + goto err_cleanup_pf2vf_bh; if (adf_request_msi_irq(accel_dev)) - goto err_out; + goto err_cleanup_bh; return 0; + +err_cleanup_bh: + adf_cleanup_bh(accel_dev); + +err_cleanup_pf2vf_bh: + adf_cleanup_pf2vf_bh(accel_dev); + +err_disable_msi: + adf_disable_msi(accel_dev); + err_out: - adf_vf_isr_resource_free(accel_dev); return -EFAULT; } EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc); diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index ff78c73c47e382c87fd84543c449967618e5ee5b..f998ed58457c24fb260a208ca5a65a9b65bf38d7 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -718,8 +718,8 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, int n = sg_nents(sgl); struct qat_alg_buf_list *bufl; struct qat_alg_buf_list *buflout = NULL; - dma_addr_t blp; - dma_addr_t bloutp = 0; + dma_addr_t blp = DMA_MAPPING_ERROR; + dma_addr_t bloutp = DMA_MAPPING_ERROR; struct scatterlist *sg; size_t sz_out, sz = struct_size(bufl, bufers, n + 1); @@ -731,9 +731,8 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, if (unlikely(!bufl)) return -ENOMEM; - blp = dma_map_single(dev, bufl, sz, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(dev, blp))) - goto err_in; + for_each_sg(sgl, sg, n, i) + bufl->bufers[i].addr = DMA_MAPPING_ERROR; for_each_sg(sgl, sg, n, i) { int y = sg_nctr; @@ -750,6 +749,9 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, sg_nctr++; } bufl->num_bufs = sg_nctr; + blp = dma_map_single(dev, bufl, sz, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, blp))) + goto err_in; qat_req->buf.bl = bufl; qat_req->buf.blp = blp; qat_req->buf.sz = sz; @@ -764,10 +766,11 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, dev_to_node(&GET_DEV(inst->accel_dev))); if (unlikely(!buflout)) goto err_in; - bloutp = dma_map_single(dev, buflout, sz_out, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(dev, bloutp))) - goto err_out; + bufers = buflout->bufers; + for_each_sg(sglout, sg, n, i) + bufers[i].addr = DMA_MAPPING_ERROR; + for_each_sg(sglout, sg, n, i) { int y = sg_nctr; @@ -784,6 +787,9 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, } buflout->num_bufs = sg_nctr; buflout->num_mapped_bufs = sg_nctr; + bloutp = dma_map_single(dev, buflout, sz_out, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, bloutp))) + goto err_out; qat_req->buf.blout = buflout; qat_req->buf.bloutp = bloutp; qat_req->buf.sz_out = sz_out; @@ -795,17 +801,21 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, return 0; err_out: + if (!dma_mapping_error(dev, bloutp)) + dma_unmap_single(dev, bloutp, sz_out, DMA_TO_DEVICE); + n = sg_nents(sglout); for (i = 0; i < n; i++) if (!dma_mapping_error(dev, buflout->bufers[i].addr)) dma_unmap_single(dev, buflout->bufers[i].addr, buflout->bufers[i].len, DMA_BIDIRECTIONAL); - if (!dma_mapping_error(dev, bloutp)) - dma_unmap_single(dev, bloutp, sz_out, DMA_TO_DEVICE); kfree(buflout); err_in: + if (!dma_mapping_error(dev, blp)) + dma_unmap_single(dev, blp, sz, DMA_TO_DEVICE); + n = sg_nents(sgl); for (i = 0; i < n; i++) if (!dma_mapping_error(dev, bufl->bufers[i].addr)) @@ -813,8 +823,6 @@ err_in: bufl->bufers[i].len, DMA_BIDIRECTIONAL); - if (!dma_mapping_error(dev, blp)) - dma_unmap_single(dev, blp, sz, DMA_TO_DEVICE); kfree(bufl); dev_err(dev, "Failed to map buf for dma\n"); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c index c972554a755e7c47191afc90e5d4a1c5794f85bb..29999da716cc949ed0333d539b5c86b7c57edeb6 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -184,12 +184,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_err_free_reg; - set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); - ret = adf_dev_init(accel_dev); if (ret) goto out_err_dev_shutdown; + set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); + ret = adf_dev_start(accel_dev); if (ret) goto out_err_dev_stop; diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h index cffa9fc628ffd38b13e6cd9f486067f0df778dc2..850f257d00f3aca0397adc1f703aea690c754d60 100644 --- a/drivers/crypto/qce/cipher.h +++ b/drivers/crypto/qce/cipher.h @@ -40,7 +40,6 @@ struct qce_cipher_reqctx { struct scatterlist result_sg; struct sg_table dst_tbl; struct scatterlist *dst_sg; - struct sg_table src_tbl; struct scatterlist *src_sg; unsigned int cryptlen; struct skcipher_request fallback_req; // keep at the end diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c index a73db2a5637f8b2aea8596c313774ccd364d8bb1..dceb9579d87a2d643d4dd3daa51c7ddf01dc29b3 100644 --- a/drivers/crypto/qce/common.c +++ b/drivers/crypto/qce/common.c @@ -140,8 +140,7 @@ static u32 qce_auth_cfg(unsigned long flags, u32 key_size) return cfg; } -static int qce_setup_regs_ahash(struct crypto_async_request *async_req, - u32 totallen, u32 offset) +static int qce_setup_regs_ahash(struct crypto_async_request *async_req) { struct ahash_request *req = ahash_request_cast(async_req); struct crypto_ahash *ahash = __crypto_ahash_cast(async_req->tfm); @@ -295,19 +294,18 @@ static void qce_xtskey(struct qce_device *qce, const u8 *enckey, { u32 xtskey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0}; unsigned int xtsklen = enckeylen / (2 * sizeof(u32)); - unsigned int xtsdusize; qce_cpu_to_be32p_array((__be32 *)xtskey, enckey + enckeylen / 2, enckeylen / 2); qce_write_array(qce, REG_ENCR_XTS_KEY0, xtskey, xtsklen); - /* xts du size 512B */ - xtsdusize = min_t(u32, QCE_SECTOR_SIZE, cryptlen); - qce_write(qce, REG_ENCR_XTS_DU_SIZE, xtsdusize); + /* Set data unit size to cryptlen. Anything else causes + * crypto engine to return back incorrect results. + */ + qce_write(qce, REG_ENCR_XTS_DU_SIZE, cryptlen); } -static int qce_setup_regs_skcipher(struct crypto_async_request *async_req, - u32 totallen, u32 offset) +static int qce_setup_regs_skcipher(struct crypto_async_request *async_req) { struct skcipher_request *req = skcipher_request_cast(async_req); struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req); @@ -367,7 +365,7 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req, qce_write(qce, REG_ENCR_SEG_CFG, encr_cfg); qce_write(qce, REG_ENCR_SEG_SIZE, rctx->cryptlen); - qce_write(qce, REG_ENCR_SEG_START, offset & 0xffff); + qce_write(qce, REG_ENCR_SEG_START, 0); if (IS_CTR(flags)) { qce_write(qce, REG_CNTR_MASK, ~0); @@ -376,7 +374,7 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req, qce_write(qce, REG_CNTR_MASK2, ~0); } - qce_write(qce, REG_SEG_SIZE, totallen); + qce_write(qce, REG_SEG_SIZE, rctx->cryptlen); /* get little endianness */ config = qce_config_reg(qce, 1); @@ -388,17 +386,16 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req, } #endif -int qce_start(struct crypto_async_request *async_req, u32 type, u32 totallen, - u32 offset) +int qce_start(struct crypto_async_request *async_req, u32 type) { switch (type) { #ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER case CRYPTO_ALG_TYPE_SKCIPHER: - return qce_setup_regs_skcipher(async_req, totallen, offset); + return qce_setup_regs_skcipher(async_req); #endif #ifdef CONFIG_CRYPTO_DEV_QCE_SHA case CRYPTO_ALG_TYPE_AHASH: - return qce_setup_regs_ahash(async_req, totallen, offset); + return qce_setup_regs_ahash(async_req); #endif default: return -EINVAL; diff --git a/drivers/crypto/qce/common.h b/drivers/crypto/qce/common.h index 85ba16418a049ec373058a2e25511c5764075f09..3bc244bcca2d9c2a21a55f6a6760b1ed8f8ff935 100644 --- a/drivers/crypto/qce/common.h +++ b/drivers/crypto/qce/common.h @@ -94,7 +94,6 @@ struct qce_alg_template { void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len); int qce_check_status(struct qce_device *qce, u32 *status); void qce_get_version(struct qce_device *qce, u32 *major, u32 *minor, u32 *step); -int qce_start(struct crypto_async_request *async_req, u32 type, u32 totallen, - u32 offset); +int qce_start(struct crypto_async_request *async_req, u32 type); #endif /* _COMMON_H_ */ diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c index 61c418c123458f18244dc19ad1caea56a2821041..8e6fcf2c21cc0a8b1e532d549927a2468276c864 100644 --- a/drivers/crypto/qce/sha.c +++ b/drivers/crypto/qce/sha.c @@ -12,9 +12,15 @@ #include "core.h" #include "sha.h" -/* crypto hw padding constant for first operation */ -#define SHA_PADDING 64 -#define SHA_PADDING_MASK (SHA_PADDING - 1) +struct qce_sha_saved_state { + u8 pending_buf[QCE_SHA_MAX_BLOCKSIZE]; + u8 partial_digest[QCE_SHA_MAX_DIGESTSIZE]; + __be32 byte_count[2]; + unsigned int pending_buflen; + unsigned int flags; + u64 count; + bool first_blk; +}; static LIST_HEAD(ahash_algs); @@ -107,7 +113,7 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req) qce_dma_issue_pending(&qce->dma); - ret = qce_start(async_req, tmpl->crypto_alg_type, 0, 0); + ret = qce_start(async_req, tmpl->crypto_alg_type); if (ret) goto error_terminate; @@ -139,97 +145,37 @@ static int qce_ahash_init(struct ahash_request *req) static int qce_ahash_export(struct ahash_request *req, void *out) { - struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); struct qce_sha_reqctx *rctx = ahash_request_ctx(req); - unsigned long flags = rctx->flags; - unsigned int digestsize = crypto_ahash_digestsize(ahash); - unsigned int blocksize = - crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash)); - - if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) { - struct sha1_state *out_state = out; - - out_state->count = rctx->count; - qce_cpu_to_be32p_array((__be32 *)out_state->state, - rctx->digest, digestsize); - memcpy(out_state->buffer, rctx->buf, blocksize); - } else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) { - struct sha256_state *out_state = out; - - out_state->count = rctx->count; - qce_cpu_to_be32p_array((__be32 *)out_state->state, - rctx->digest, digestsize); - memcpy(out_state->buf, rctx->buf, blocksize); - } else { - return -EINVAL; - } + struct qce_sha_saved_state *export_state = out; - return 0; -} - -static int qce_import_common(struct ahash_request *req, u64 in_count, - const u32 *state, const u8 *buffer, bool hmac) -{ - struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); - struct qce_sha_reqctx *rctx = ahash_request_ctx(req); - unsigned int digestsize = crypto_ahash_digestsize(ahash); - unsigned int blocksize; - u64 count = in_count; - - blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash)); - rctx->count = in_count; - memcpy(rctx->buf, buffer, blocksize); - - if (in_count <= blocksize) { - rctx->first_blk = 1; - } else { - rctx->first_blk = 0; - /* - * For HMAC, there is a hardware padding done when first block - * is set. Therefore the byte_count must be incremened by 64 - * after the first block operation. - */ - if (hmac) - count += SHA_PADDING; - } - - rctx->byte_count[0] = (__force __be32)(count & ~SHA_PADDING_MASK); - rctx->byte_count[1] = (__force __be32)(count >> 32); - qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state, - digestsize); - rctx->buflen = (unsigned int)(in_count & (blocksize - 1)); + memcpy(export_state->pending_buf, rctx->buf, rctx->buflen); + memcpy(export_state->partial_digest, rctx->digest, sizeof(rctx->digest)); + export_state->byte_count[0] = rctx->byte_count[0]; + export_state->byte_count[1] = rctx->byte_count[1]; + export_state->pending_buflen = rctx->buflen; + export_state->count = rctx->count; + export_state->first_blk = rctx->first_blk; + export_state->flags = rctx->flags; return 0; } static int qce_ahash_import(struct ahash_request *req, const void *in) { - struct qce_sha_reqctx *rctx; - unsigned long flags; - bool hmac; - int ret; - - ret = qce_ahash_init(req); - if (ret) - return ret; - - rctx = ahash_request_ctx(req); - flags = rctx->flags; - hmac = IS_SHA_HMAC(flags); - - if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) { - const struct sha1_state *state = in; - - ret = qce_import_common(req, state->count, state->state, - state->buffer, hmac); - } else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) { - const struct sha256_state *state = in; + struct qce_sha_reqctx *rctx = ahash_request_ctx(req); + const struct qce_sha_saved_state *import_state = in; - ret = qce_import_common(req, state->count, state->state, - state->buf, hmac); - } + memset(rctx, 0, sizeof(*rctx)); + rctx->count = import_state->count; + rctx->buflen = import_state->pending_buflen; + rctx->first_blk = import_state->first_blk; + rctx->flags = import_state->flags; + rctx->byte_count[0] = import_state->byte_count[0]; + rctx->byte_count[1] = import_state->byte_count[1]; + memcpy(rctx->buf, import_state->pending_buf, rctx->buflen); + memcpy(rctx->digest, import_state->partial_digest, sizeof(rctx->digest)); - return ret; + return 0; } static int qce_ahash_update(struct ahash_request *req) @@ -270,6 +216,25 @@ static int qce_ahash_update(struct ahash_request *req) /* calculate how many bytes will be hashed later */ hash_later = total % blocksize; + + /* + * At this point, there is more than one block size of data. If + * the available data to transfer is exactly a multiple of block + * size, save the last block to be transferred in qce_ahash_final + * (with the last block bit set) if this is indeed the end of data + * stream. If not this saved block will be transferred as part of + * next update. If this block is not held back and if this is + * indeed the end of data stream, the digest obtained will be wrong + * since qce_ahash_final will see that rctx->buflen is 0 and return + * doing nothing which in turn means that a digest will not be + * copied to the destination result buffer. qce_ahash_final cannot + * be made to alter this behavior and allowed to proceed if + * rctx->buflen is 0 because the crypto engine BAM does not allow + * for zero length transfers. + */ + if (!hash_later) + hash_later = blocksize; + if (hash_later) { unsigned int src_offset = req->nbytes - hash_later; scatterwalk_map_and_copy(rctx->buf, req->src, src_offset, @@ -450,7 +415,7 @@ static const struct qce_ahash_def ahash_def[] = { .drv_name = "sha1-qce", .digestsize = SHA1_DIGEST_SIZE, .blocksize = SHA1_BLOCK_SIZE, - .statesize = sizeof(struct sha1_state), + .statesize = sizeof(struct qce_sha_saved_state), .std_iv = std_iv_sha1, }, { @@ -459,7 +424,7 @@ static const struct qce_ahash_def ahash_def[] = { .drv_name = "sha256-qce", .digestsize = SHA256_DIGEST_SIZE, .blocksize = SHA256_BLOCK_SIZE, - .statesize = sizeof(struct sha256_state), + .statesize = sizeof(struct qce_sha_saved_state), .std_iv = std_iv_sha256, }, { @@ -468,7 +433,7 @@ static const struct qce_ahash_def ahash_def[] = { .drv_name = "hmac-sha1-qce", .digestsize = SHA1_DIGEST_SIZE, .blocksize = SHA1_BLOCK_SIZE, - .statesize = sizeof(struct sha1_state), + .statesize = sizeof(struct qce_sha_saved_state), .std_iv = std_iv_sha1, }, { @@ -477,7 +442,7 @@ static const struct qce_ahash_def ahash_def[] = { .drv_name = "hmac-sha256-qce", .digestsize = SHA256_DIGEST_SIZE, .blocksize = SHA256_BLOCK_SIZE, - .statesize = sizeof(struct sha256_state), + .statesize = sizeof(struct qce_sha_saved_state), .std_iv = std_iv_sha256, }, }; diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c index a2d3da0ad95f3eecc66730b92313fecdd439e6c0..c0a0d8c4fce196e26155ccda0c0836b2c950c550 100644 --- a/drivers/crypto/qce/skcipher.c +++ b/drivers/crypto/qce/skcipher.c @@ -8,6 +8,7 @@ #include <linux/interrupt.h> #include <linux/moduleparam.h> #include <linux/types.h> +#include <linux/errno.h> #include <crypto/aes.h> #include <crypto/internal/des.h> #include <crypto/internal/skcipher.h> @@ -143,7 +144,7 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req) qce_dma_issue_pending(&qce->dma); - ret = qce_start(async_req, tmpl->crypto_alg_type, req->cryptlen, 0); + ret = qce_start(async_req, tmpl->crypto_alg_type); if (ret) goto error_terminate; @@ -167,16 +168,33 @@ static int qce_skcipher_setkey(struct crypto_skcipher *ablk, const u8 *key, struct crypto_tfm *tfm = crypto_skcipher_tfm(ablk); struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm); unsigned long flags = to_cipher_tmpl(ablk)->alg_flags; + unsigned int __keylen; int ret; if (!key || !keylen) return -EINVAL; - switch (IS_XTS(flags) ? keylen >> 1 : keylen) { + /* + * AES XTS key1 = key2 not supported by crypto engine. + * Revisit to request a fallback cipher in this case. + */ + if (IS_XTS(flags)) { + __keylen = keylen >> 1; + if (!memcmp(key, key + __keylen, __keylen)) + return -ENOKEY; + } else { + __keylen = keylen; + } + + switch (__keylen) { case AES_KEYSIZE_128: case AES_KEYSIZE_256: memcpy(ctx->enc_key, key, keylen); break; + case AES_KEYSIZE_192: + break; + default: + return -EINVAL; } ret = crypto_skcipher_setkey(ctx->fallback, key, keylen); @@ -204,12 +222,27 @@ static int qce_des3_setkey(struct crypto_skcipher *ablk, const u8 *key, unsigned int keylen) { struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(ablk); + u32 _key[6]; int err; err = verify_skcipher_des3_key(ablk, key); if (err) return err; + /* + * The crypto engine does not support any two keys + * being the same for triple des algorithms. The + * verify_skcipher_des3_key does not check for all the + * below conditions. Return -ENOKEY in case any two keys + * are the same. Revisit to see if a fallback cipher + * is needed to handle this condition. + */ + memcpy(_key, key, DES3_EDE_KEY_SIZE); + if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) || + !((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) || + !((_key[0] ^ _key[4]) | (_key[1] ^ _key[5]))) + return -ENOKEY; + ctx->enc_keylen = keylen; memcpy(ctx->enc_key, key, keylen); return 0; @@ -221,6 +254,7 @@ static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt) struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req); struct qce_alg_template *tmpl = to_cipher_tmpl(tfm); + unsigned int blocksize = crypto_skcipher_blocksize(tfm); int keylen; int ret; @@ -228,14 +262,31 @@ static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt) rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT; keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen; - /* qce is hanging when AES-XTS request len > QCE_SECTOR_SIZE and - * is not a multiple of it; pass such requests to the fallback + /* CE does not handle 0 length messages */ + if (!req->cryptlen) + return 0; + + /* + * ECB and CBC algorithms require message lengths to be + * multiples of block size. + */ + if (IS_ECB(rctx->flags) || IS_CBC(rctx->flags)) + if (!IS_ALIGNED(req->cryptlen, blocksize)) + return -EINVAL; + + /* + * Conditions for requesting a fallback cipher + * AES-192 (not supported by crypto engine (CE)) + * AES-XTS request with len <= 512 byte (not recommended to use CE) + * AES-XTS request with len > QCE_SECTOR_SIZE and + * is not a multiple of it.(Revisit this condition to check if it is + * needed in all versions of CE) */ if (IS_AES(rctx->flags) && - (((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) || - req->cryptlen <= aes_sw_max_len) || - (IS_XTS(rctx->flags) && req->cryptlen > QCE_SECTOR_SIZE && - req->cryptlen % QCE_SECTOR_SIZE))) { + ((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) || + (IS_XTS(rctx->flags) && ((req->cryptlen <= aes_sw_max_len) || + (req->cryptlen > QCE_SECTOR_SIZE && + req->cryptlen % QCE_SECTOR_SIZE))))) { skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); skcipher_request_set_callback(&rctx->fallback_req, req->base.flags, @@ -307,7 +358,7 @@ static const struct qce_skcipher_def skcipher_def[] = { .name = "ecb(aes)", .drv_name = "ecb-aes-qce", .blocksize = AES_BLOCK_SIZE, - .ivsize = AES_BLOCK_SIZE, + .ivsize = 0, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, }, diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c index 81befe7febaa42ca0025fa1f630424992f3c9fbd..ed03058497bc2863e1c6333fb42f025efd85291b 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c +++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c @@ -48,7 +48,7 @@ static void rk_ahash_reg_init(struct rk_crypto_info *dev) { struct ahash_request *req = ahash_request_cast(dev->async_req); struct rk_ahash_rctx *rctx = ahash_request_ctx(req); - int reg_status = 0; + int reg_status; reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL) | RK_CRYPTO_HASH_FLUSH | _SBF(0xffff, 16); diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 682c8a450a57b8514c8be439e81fcd85bc30979e..55aa3a71169b057d470374d41152ec2a26508d8d 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/scatterlist.h> @@ -401,7 +402,7 @@ static const struct samsung_aes_variant exynos_aes_data = { static const struct samsung_aes_variant exynos5433_slim_aes_data = { .aes_offset = 0x400, .hash_offset = 0x800, - .clk_names = { "pclk", "aclk", }, + .clk_names = { "aclk", "pclk", }, }; static const struct of_device_id s5p_sss_dt_match[] = { @@ -424,13 +425,9 @@ MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); static inline const struct samsung_aes_variant *find_s5p_sss_version (const struct platform_device *pdev) { - if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) { - const struct of_device_id *match; + if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) + return of_device_get_match_data(&pdev->dev); - match = of_match_node(s5p_sss_dt_match, - pdev->dev.of_node); - return (const struct samsung_aes_variant *)match->data; - } return (const struct samsung_aes_variant *) platform_get_device_id(pdev)->driver_data; } @@ -2159,7 +2156,7 @@ static struct skcipher_alg algs[] = { static int s5p_aes_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - int i, j, err = -ENODEV; + int i, j, err; const struct samsung_aes_variant *variant; struct s5p_aes_dev *pdata; struct resource *res; @@ -2189,14 +2186,14 @@ static int s5p_aes_probe(struct platform_device *pdev) } pdata->res = res; - pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + pdata->ioaddr = devm_ioremap_resource(dev, res); if (IS_ERR(pdata->ioaddr)) { if (!pdata->use_hash) return PTR_ERR(pdata->ioaddr); /* try AES without HASH */ res->end -= 0x300; pdata->use_hash = false; - pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + pdata->ioaddr = devm_ioremap_resource(dev, res); if (IS_ERR(pdata->ioaddr)) return PTR_ERR(pdata->ioaddr); } diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c index f300b0a5958a595f4a40f1637fb4534343d667e9..1c6929fb3a13143bc1d172198f676bc239e1df52 100644 --- a/drivers/crypto/sa2ul.c +++ b/drivers/crypto/sa2ul.c @@ -69,8 +69,24 @@ /* Max Authentication tag size */ #define SA_MAX_AUTH_TAG_SZ 64 -#define PRIV_ID 0x1 -#define PRIV 0x1 +enum sa_algo_id { + SA_ALG_CBC_AES = 0, + SA_ALG_EBC_AES, + SA_ALG_CBC_DES3, + SA_ALG_ECB_DES3, + SA_ALG_SHA1, + SA_ALG_SHA256, + SA_ALG_SHA512, + SA_ALG_AUTHENC_SHA1_AES, + SA_ALG_AUTHENC_SHA256_AES, +}; + +struct sa_match_data { + u8 priv; + u8 priv_id; + u32 supported_algos; + bool skip_engine_control; +}; static struct device *sa_k3_dev; @@ -696,8 +712,9 @@ static void sa_dump_sc(u8 *buf, dma_addr_t dma_addr) } static -int sa_init_sc(struct sa_ctx_info *ctx, const u8 *enc_key, - u16 enc_key_sz, const u8 *auth_key, u16 auth_key_sz, +int sa_init_sc(struct sa_ctx_info *ctx, const struct sa_match_data *match_data, + const u8 *enc_key, u16 enc_key_sz, + const u8 *auth_key, u16 auth_key_sz, struct algo_data *ad, u8 enc, u32 *swinfo) { int enc_sc_offset = 0; @@ -732,8 +749,8 @@ int sa_init_sc(struct sa_ctx_info *ctx, const u8 *enc_key, sc_buf[SA_CTX_SCCTL_OWNER_OFFSET] = 0; memcpy(&sc_buf[2], &sc_id, 2); sc_buf[4] = 0x0; - sc_buf[5] = PRIV_ID; - sc_buf[6] = PRIV; + sc_buf[5] = match_data->priv_id; + sc_buf[6] = match_data->priv; sc_buf[7] = 0x0; /* Prepare context for encryption engine */ @@ -892,8 +909,8 @@ static int sa_cipher_setkey(struct crypto_skcipher *tfm, const u8 *key, return ret; /* Setup Encryption Security Context & Command label template */ - if (sa_init_sc(&ctx->enc, key, keylen, NULL, 0, ad, 1, - &ctx->enc.epib[1])) + if (sa_init_sc(&ctx->enc, ctx->dev_data->match_data, key, keylen, NULL, 0, + ad, 1, &ctx->enc.epib[1])) goto badkey; cmdl_len = sa_format_cmdl_gen(&cfg, @@ -905,8 +922,8 @@ static int sa_cipher_setkey(struct crypto_skcipher *tfm, const u8 *key, ctx->enc.cmdl_size = cmdl_len; /* Setup Decryption Security Context & Command label template */ - if (sa_init_sc(&ctx->dec, key, keylen, NULL, 0, ad, 0, - &ctx->dec.epib[1])) + if (sa_init_sc(&ctx->dec, ctx->dev_data->match_data, key, keylen, NULL, 0, + ad, 0, &ctx->dec.epib[1])) goto badkey; cfg.enc_eng_id = ad->enc_eng.eng_id; @@ -1106,7 +1123,7 @@ static int sa_run(struct sa_req *req) else dma_rx = pdata->dma_rx1; - ddev = dma_rx->device->dev; + ddev = dmaengine_get_dma_device(pdata->dma_tx); rxd->ddev = ddev; memcpy(cmdl, sa_ctx->cmdl, sa_ctx->cmdl_size); @@ -1146,8 +1163,10 @@ static int sa_run(struct sa_req *req) mapped_sg->sgt.sgl = src; mapped_sg->sgt.orig_nents = src_nents; ret = dma_map_sgtable(ddev, &mapped_sg->sgt, dir_src, 0); - if (ret) + if (ret) { + kfree(rxd); return ret; + } mapped_sg->dir = dir_src; mapped_sg->mapped = true; @@ -1155,8 +1174,10 @@ static int sa_run(struct sa_req *req) mapped_sg->sgt.sgl = req->src; mapped_sg->sgt.orig_nents = sg_nents; ret = dma_map_sgtable(ddev, &mapped_sg->sgt, dir_src, 0); - if (ret) + if (ret) { + kfree(rxd); return ret; + } mapped_sg->dir = dir_src; mapped_sg->mapped = true; @@ -1446,9 +1467,10 @@ static int sa_sha_setup(struct sa_tfm_ctx *ctx, struct algo_data *ad) cfg.akey = NULL; cfg.akey_len = 0; + ctx->dev_data = dev_get_drvdata(sa_k3_dev); /* Setup Encryption Security Context & Command label template */ - if (sa_init_sc(&ctx->enc, NULL, 0, NULL, 0, ad, 0, - &ctx->enc.epib[1])) + if (sa_init_sc(&ctx->enc, ctx->dev_data->match_data, NULL, 0, NULL, 0, + ad, 0, &ctx->enc.epib[1])) goto badkey; cmdl_len = sa_format_cmdl_gen(&cfg, @@ -1716,6 +1738,7 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, int ret; memzero_explicit(ctx, sizeof(*ctx)); + ctx->dev_data = data; ctx->shash = crypto_alloc_shash(hash, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(ctx->shash)) { @@ -1817,8 +1840,8 @@ static int sa_aead_setkey(struct crypto_aead *authenc, cfg.akey_len = keys.authkeylen; /* Setup Encryption Security Context & Command label template */ - if (sa_init_sc(&ctx->enc, keys.enckey, keys.enckeylen, - keys.authkey, keys.authkeylen, + if (sa_init_sc(&ctx->enc, ctx->dev_data->match_data, keys.enckey, + keys.enckeylen, keys.authkey, keys.authkeylen, ad, 1, &ctx->enc.epib[1])) return -EINVAL; @@ -1831,8 +1854,8 @@ static int sa_aead_setkey(struct crypto_aead *authenc, ctx->enc.cmdl_size = cmdl_len; /* Setup Decryption Security Context & Command label template */ - if (sa_init_sc(&ctx->dec, keys.enckey, keys.enckeylen, - keys.authkey, keys.authkeylen, + if (sa_init_sc(&ctx->dec, ctx->dev_data->match_data, keys.enckey, + keys.enckeylen, keys.authkey, keys.authkeylen, ad, 0, &ctx->dec.epib[1])) return -EINVAL; @@ -1950,7 +1973,7 @@ static int sa_aead_decrypt(struct aead_request *req) } static struct sa_alg_tmpl sa_algs[] = { - { + [SA_ALG_CBC_AES] = { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { .base.cra_name = "cbc(aes)", @@ -1973,7 +1996,7 @@ static struct sa_alg_tmpl sa_algs[] = { .decrypt = sa_decrypt, } }, - { + [SA_ALG_EBC_AES] = { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { .base.cra_name = "ecb(aes)", @@ -1995,7 +2018,7 @@ static struct sa_alg_tmpl sa_algs[] = { .decrypt = sa_decrypt, } }, - { + [SA_ALG_CBC_DES3] = { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { .base.cra_name = "cbc(des3_ede)", @@ -2018,7 +2041,7 @@ static struct sa_alg_tmpl sa_algs[] = { .decrypt = sa_decrypt, } }, - { + [SA_ALG_ECB_DES3] = { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { .base.cra_name = "ecb(des3_ede)", @@ -2040,7 +2063,7 @@ static struct sa_alg_tmpl sa_algs[] = { .decrypt = sa_decrypt, } }, - { + [SA_ALG_SHA1] = { .type = CRYPTO_ALG_TYPE_AHASH, .alg.ahash = { .halg.base = { @@ -2069,7 +2092,7 @@ static struct sa_alg_tmpl sa_algs[] = { .import = sa_sha_import, }, }, - { + [SA_ALG_SHA256] = { .type = CRYPTO_ALG_TYPE_AHASH, .alg.ahash = { .halg.base = { @@ -2098,7 +2121,7 @@ static struct sa_alg_tmpl sa_algs[] = { .import = sa_sha_import, }, }, - { + [SA_ALG_SHA512] = { .type = CRYPTO_ALG_TYPE_AHASH, .alg.ahash = { .halg.base = { @@ -2127,7 +2150,7 @@ static struct sa_alg_tmpl sa_algs[] = { .import = sa_sha_import, }, }, - { + [SA_ALG_AUTHENC_SHA1_AES] = { .type = CRYPTO_ALG_TYPE_AEAD, .alg.aead = { .base = { @@ -2154,7 +2177,7 @@ static struct sa_alg_tmpl sa_algs[] = { .decrypt = sa_aead_decrypt, }, }, - { + [SA_ALG_AUTHENC_SHA256_AES] = { .type = CRYPTO_ALG_TYPE_AEAD, .alg.aead = { .base = { @@ -2185,13 +2208,19 @@ static struct sa_alg_tmpl sa_algs[] = { }; /* Register the algorithms in crypto framework */ -static void sa_register_algos(const struct device *dev) +static void sa_register_algos(struct sa_crypto_data *dev_data) { + const struct sa_match_data *match_data = dev_data->match_data; + struct device *dev = dev_data->dev; char *alg_name; u32 type; int i, err; for (i = 0; i < ARRAY_SIZE(sa_algs); i++) { + /* Skip unsupported algos */ + if (!(match_data->supported_algos & BIT(i))) + continue; + type = sa_algs[i].type; if (type == CRYPTO_ALG_TYPE_SKCIPHER) { alg_name = sa_algs[i].alg.skcipher.base.cra_name; @@ -2329,14 +2358,39 @@ static int sa_link_child(struct device *dev, void *data) return 0; } +static struct sa_match_data am654_match_data = { + .priv = 1, + .priv_id = 1, + .supported_algos = GENMASK(SA_ALG_AUTHENC_SHA256_AES, 0), +}; + +static struct sa_match_data am64_match_data = { + .priv = 0, + .priv_id = 0, + .supported_algos = BIT(SA_ALG_CBC_AES) | + BIT(SA_ALG_EBC_AES) | + BIT(SA_ALG_SHA256) | + BIT(SA_ALG_SHA512) | + BIT(SA_ALG_AUTHENC_SHA256_AES), + .skip_engine_control = true, +}; + +static const struct of_device_id of_match[] = { + { .compatible = "ti,j721e-sa2ul", .data = &am654_match_data, }, + { .compatible = "ti,am654-sa2ul", .data = &am654_match_data, }, + { .compatible = "ti,am64-sa2ul", .data = &am64_match_data, }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_match); + static int sa_ul_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct resource *res; static void __iomem *saul_base; struct sa_crypto_data *dev_data; - u32 val; int ret; dev_data = devm_kzalloc(dev, sizeof(*dev_data), GFP_KERNEL); @@ -2350,7 +2404,7 @@ static int sa_ul_probe(struct platform_device *pdev) dev_set_drvdata(sa_k3_dev, dev_data); pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(&pdev->dev, "%s: failed to get sync: %d\n", __func__, ret); @@ -2362,18 +2416,28 @@ static int sa_ul_probe(struct platform_device *pdev) if (ret) goto disable_pm_runtime; + match = of_match_node(of_match, dev->of_node); + if (!match) { + dev_err(dev, "No compatible match found\n"); + return -ENODEV; + } + dev_data->match_data = match->data; + spin_lock_init(&dev_data->scid_lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); saul_base = devm_ioremap_resource(dev, res); dev_data->base = saul_base; - val = SA_EEC_ENCSS_EN | SA_EEC_AUTHSS_EN | SA_EEC_CTXCACH_EN | - SA_EEC_CPPI_PORT_IN_EN | SA_EEC_CPPI_PORT_OUT_EN | - SA_EEC_TRNG_EN; - writel_relaxed(val, saul_base + SA_ENGINE_ENABLE_CONTROL); + if (!dev_data->match_data->skip_engine_control) { + u32 val = SA_EEC_ENCSS_EN | SA_EEC_AUTHSS_EN | SA_EEC_CTXCACH_EN | + SA_EEC_CPPI_PORT_IN_EN | SA_EEC_CPPI_PORT_OUT_EN | + SA_EEC_TRNG_EN; - sa_register_algos(dev); + writel_relaxed(val, saul_base + SA_ENGINE_ENABLE_CONTROL); + } + + sa_register_algos(dev_data); ret = of_platform_populate(node, NULL, NULL, &pdev->dev); if (ret) @@ -2419,13 +2483,6 @@ static int sa_ul_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id of_match[] = { - {.compatible = "ti,j721e-sa2ul",}, - {.compatible = "ti,am654-sa2ul",}, - {}, -}; -MODULE_DEVICE_TABLE(of, of_match); - static struct platform_driver sa_ul_driver = { .probe = sa_ul_probe, .remove = sa_ul_remove, diff --git a/drivers/crypto/sa2ul.h b/drivers/crypto/sa2ul.h index f597ddecde34f2c626a8440a6cb55fdb0f05a155..ed66d1f111db508e3c35e15352e79139cf4a4d4b 100644 --- a/drivers/crypto/sa2ul.h +++ b/drivers/crypto/sa2ul.h @@ -171,9 +171,12 @@ struct sa_tfm_ctx; #define SA_UNSAFE_DATA_SZ_MIN 240 #define SA_UNSAFE_DATA_SZ_MAX 256 +struct sa_match_data; + /** * struct sa_crypto_data - Crypto driver instance data * @base: Base address of the register space + * @soc_data: Pointer to SoC specific data * @pdev: Platform device pointer * @sc_pool: security context pool * @dev: Device pointer @@ -189,6 +192,7 @@ struct sa_tfm_ctx; */ struct sa_crypto_data { void __iomem *base; + const struct sa_match_data *match_data; struct platform_device *pdev; struct dma_pool *sc_pool; struct device *dev; diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c index 2a4793176c713a98370bca7742614872b7aa238f..7389a0536ff020f782a8902c65a8875ef88ccb62 100644 --- a/drivers/crypto/stm32/stm32-cryp.c +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -542,7 +542,7 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) int ret; u32 cfg, hw_mode; - pm_runtime_get_sync(cryp->dev); + pm_runtime_resume_and_get(cryp->dev); /* Disable interrupt */ stm32_cryp_write(cryp, CRYP_IMSCR, 0); @@ -2043,7 +2043,7 @@ static int stm32_cryp_remove(struct platform_device *pdev) if (!cryp) return -ENODEV; - ret = pm_runtime_get_sync(cryp->dev); + ret = pm_runtime_resume_and_get(cryp->dev); if (ret < 0) return ret; diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c index 7ac0573ef66300ec95d643f56973e39d5647d220..389de9e3302d5658c92e1eb5c7cc3cc4f100a2ac 100644 --- a/drivers/crypto/stm32/stm32-hash.c +++ b/drivers/crypto/stm32/stm32-hash.c @@ -813,7 +813,7 @@ static void stm32_hash_finish_req(struct ahash_request *req, int err) static int stm32_hash_hw_init(struct stm32_hash_dev *hdev, struct stm32_hash_request_ctx *rctx) { - pm_runtime_get_sync(hdev->dev); + pm_runtime_resume_and_get(hdev->dev); if (!(HASH_FLAGS_INIT & hdev->flags)) { stm32_hash_write(hdev, HASH_CR, HASH_CR_INIT); @@ -962,7 +962,7 @@ static int stm32_hash_export(struct ahash_request *req, void *out) u32 *preg; unsigned int i; - pm_runtime_get_sync(hdev->dev); + pm_runtime_resume_and_get(hdev->dev); while ((stm32_hash_read(hdev, HASH_SR) & HASH_SR_BUSY)) cpu_relax(); @@ -1000,7 +1000,7 @@ static int stm32_hash_import(struct ahash_request *req, const void *in) preg = rctx->hw_context; - pm_runtime_get_sync(hdev->dev); + pm_runtime_resume_and_get(hdev->dev); stm32_hash_write(hdev, HASH_IMR, *preg++); stm32_hash_write(hdev, HASH_STR, *preg++); @@ -1566,7 +1566,7 @@ static int stm32_hash_remove(struct platform_device *pdev) if (!hdev) return -ENODEV; - ret = pm_runtime_get_sync(hdev->dev); + ret = pm_runtime_resume_and_get(hdev->dev); if (ret < 0) return ret; diff --git a/drivers/crypto/ux500/cryp/cryp.c b/drivers/crypto/ux500/cryp/cryp.c index 9866c2a5e9a70133ce110fdc8187e8a25f279715..759d0d9786fd19019728a212d76f1d70040f8ae8 100644 --- a/drivers/crypto/ux500/cryp/cryp.c +++ b/drivers/crypto/ux500/cryp/cryp.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson. @@ -15,7 +15,7 @@ #include "cryp_p.h" #include "cryp.h" -/** +/* * cryp_wait_until_done - wait until the device logic is not busy */ void cryp_wait_until_done(struct cryp_device_data *device_data) @@ -285,6 +285,7 @@ int cryp_configure_init_vector(struct cryp_device_data *device_data, * other device context parameter * @device_data: Pointer to the device data struct for base address. * @ctx: Crypto device context + * @cryp_mode: Mode: Polling, Interrupt or DMA */ void cryp_save_device_context(struct cryp_device_data *device_data, struct cryp_device_context *ctx, diff --git a/drivers/crypto/ux500/cryp/cryp.h b/drivers/crypto/ux500/cryp/cryp.h index 8da7f87b339b4785edece0bcfde305a0f96ffb01..db5713d7c9405d4f973c97436f4d5e677c6e2ea1 100644 --- a/drivers/crypto/ux500/cryp/cryp.h +++ b/drivers/crypto/ux500/cryp/cryp.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson. diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c index c3adeb2e58232e80da7e8fa4e392025eee365081..30cdd5253929c4fc737498554186d36356834f95 100644 --- a/drivers/crypto/ux500/cryp/cryp_core.c +++ b/drivers/crypto/ux500/cryp/cryp_core.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson. @@ -62,7 +62,7 @@ struct cryp_driver_data { /** * struct cryp_ctx - Crypto context * @config: Crypto mode. - * @key[CRYP_MAX_KEY_SIZE]: Key. + * @key: Key array. * @keylen: Length of key. * @iv: Pointer to initialization vector. * @indata: Pointer to indata. @@ -73,6 +73,7 @@ struct cryp_driver_data { * @updated: Updated flag. * @dev_ctx: Device dependent context. * @device: Pointer to the device. + * @session_id: Atomic session ID. */ struct cryp_ctx { struct cryp_config config; @@ -608,12 +609,12 @@ static void cryp_dma_done(struct cryp_ctx *ctx) chan = ctx->device->dma.chan_mem2cryp; dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src, - ctx->device->dma.sg_src_len, DMA_TO_DEVICE); + ctx->device->dma.nents_src, DMA_TO_DEVICE); chan = ctx->device->dma.chan_cryp2mem; dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst, - ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE); + ctx->device->dma.nents_dst, DMA_FROM_DEVICE); } static int cryp_dma_write(struct cryp_ctx *ctx, struct scatterlist *sg, @@ -1290,7 +1291,6 @@ static int ux500_cryp_probe(struct platform_device *pdev) device_data->phybase = res->start; device_data->base = devm_ioremap_resource(dev, res); if (IS_ERR(device_data->base)) { - dev_err(dev, "[%s]: ioremap failed!", __func__); ret = PTR_ERR(device_data->base); goto out; } diff --git a/drivers/crypto/ux500/cryp/cryp_irq.c b/drivers/crypto/ux500/cryp/cryp_irq.c index 7ebde69e8c76b839435de7662cb909eb16be787a..6d2f07bec98a7e74beba3c0297de40fa11538094 100644 --- a/drivers/crypto/ux500/cryp/cryp_irq.c +++ b/drivers/crypto/ux500/cryp/cryp_irq.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson. diff --git a/drivers/crypto/ux500/cryp/cryp_irq.h b/drivers/crypto/ux500/cryp/cryp_irq.h index 1984f30100ff7d99df3c2a58c01f2ec03f660376..da90029ea141240bb5c57d98eb31c28043036c13 100644 --- a/drivers/crypto/ux500/cryp/cryp_irq.h +++ b/drivers/crypto/ux500/cryp/cryp_irq.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson. @@ -19,7 +19,7 @@ enum cryp_irq_src_id { CRYP_IRQ_SRC_ALL = 0x3 }; -/** +/* * M0 Funtions */ void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src); diff --git a/drivers/crypto/ux500/cryp/cryp_irqp.h b/drivers/crypto/ux500/cryp/cryp_irqp.h index 879ed68a12d7d52142bfb8631926b9c6d3057596..4981a3f461e5ed6f8bc0e1c378749ce5a857a956 100644 --- a/drivers/crypto/ux500/cryp/cryp_irqp.h +++ b/drivers/crypto/ux500/cryp/cryp_irqp.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson. @@ -13,7 +13,7 @@ #include "cryp_irq.h" -/** +/* * * CRYP Registers - Offset mapping * +-----------------+ diff --git a/drivers/crypto/ux500/cryp/cryp_p.h b/drivers/crypto/ux500/cryp/cryp_p.h index 0df84eaa853141734ef7ea26120caf19afbc3d2e..60b47fe4de35d9b29c3ed2a0e902254f6de1bd38 100644 --- a/drivers/crypto/ux500/cryp/cryp_p.h +++ b/drivers/crypto/ux500/cryp/cryp_p.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) ST-Ericsson SA 2010 * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson. * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson. @@ -17,7 +17,7 @@ #include "cryp.h" #include "cryp_irqp.h" -/** +/* * Generic Macros */ #define CRYP_SET_BITS(reg_name, mask) \ @@ -34,7 +34,7 @@ writel_relaxed(((readl_relaxed(reg) & ~(mask)) | \ (((u32)val << shift) & (mask))), reg) -/** +/* * CRYP specific Macros */ #define CRYP_PERIPHERAL_ID0 0xE3 @@ -48,7 +48,7 @@ #define CRYP_PCELL_ID2 0x05 #define CRYP_PCELL_ID3 0xB1 -/** +/* * CRYP register default values */ #define MAX_DEVICE_SUPPORT 2 @@ -62,7 +62,7 @@ #define CRYP_KEY_DEFAULT 0x0 #define CRYP_INIT_VECT_DEFAULT 0x0 -/** +/* * CRYP Control register specific mask */ #define CRYP_CR_SECURE_MASK BIT(0) @@ -81,7 +81,6 @@ CRYP_CR_PRLG_MASK |\ CRYP_CR_ALGODIR_MASK |\ CRYP_CR_ALGOMODE_MASK |\ - CRYP_CR_DATATYPE_MASK |\ CRYP_CR_KEYSIZE_MASK |\ CRYP_CR_KEYRDEN_MASK |\ CRYP_CR_DATATYPE_MASK) @@ -91,7 +90,7 @@ #define CRYP_SR_IFEM_MASK BIT(0) #define CRYP_SR_BUSY_MASK BIT(4) -/** +/* * Bit position used while setting bits in register */ #define CRYP_CR_PRLG_POS 1 @@ -107,7 +106,7 @@ #define CRYP_SR_BUSY_POS 4 -/** +/* * CRYP PCRs------PC_NAND control register * BIT_MASK */ diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index da284b0ea1b26e72b0af24d8375c8d3be7ec1d23..ecb7412e84e3eb96c3e682368455b212ed2e7e5f 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -190,7 +190,7 @@ static void hash_dma_done(struct hash_ctx *ctx) chan = ctx->device->dma.chan_mem2hash; dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg, - ctx->device->dma.sg_len, DMA_TO_DEVICE); + ctx->device->dma.nents, DMA_TO_DEVICE); } static int hash_dma_write(struct hash_ctx *ctx, @@ -356,7 +356,7 @@ out: /** * hash_get_device_data - Checks for an available hash device and return it. - * @hash_ctx: Structure for the hash context. + * @ctx: Structure for the hash context. * @device_data: Structure for the hash device. * * This function check for an available hash device and return it to @@ -542,7 +542,7 @@ static bool hash_dma_valid_data(struct scatterlist *sg, int datasize) } /** - * hash_init - Common hash init function for SHA1/SHA2 (SHA256). + * ux500_hash_init - Common hash init function for SHA1/SHA2 (SHA256). * @req: The hash request for the job. * * Initialize structures. @@ -585,6 +585,7 @@ static int ux500_hash_init(struct ahash_request *req) * @device_data: Structure for the hash device. * @message: Block (512 bits) of message to be written to * the HASH hardware. + * @length: Message length * */ static void hash_processblock(struct hash_device_data *device_data, @@ -1295,7 +1296,7 @@ void hash_get_digest(struct hash_device_data *device_data, } /** - * hash_update - The hash update function for SHA1/SHA2 (SHA256). + * ahash_update - The hash update function for SHA1/SHA2 (SHA256). * @req: The hash request for the job. */ static int ahash_update(struct ahash_request *req) @@ -1315,7 +1316,7 @@ static int ahash_update(struct ahash_request *req) } /** - * hash_final - The hash final function for SHA1/SHA2 (SHA256). + * ahash_final - The hash final function for SHA1/SHA2 (SHA256). * @req: The hash request for the job. */ static int ahash_final(struct ahash_request *req) @@ -1615,9 +1616,6 @@ static struct hash_algo_template hash_algs[] = { } }; -/** - * hash_algs_register_all - - */ static int ahash_algs_register_all(struct hash_device_data *device_data) { int ret; @@ -1640,9 +1638,6 @@ unreg: return ret; } -/** - * hash_algs_unregister_all - - */ static void ahash_algs_unregister_all(struct hash_device_data *device_data) { int i; @@ -1681,7 +1676,6 @@ static int ux500_hash_probe(struct platform_device *pdev) device_data->phybase = res->start; device_data->base = devm_ioremap_resource(dev, res); if (IS_ERR(device_data->base)) { - dev_err(dev, "%s: ioremap() failed!\n", __func__); ret = PTR_ERR(device_data->base); goto out; } diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c index d05c02baebcf0ce541a85f74cc02c688b33bfe35..ec06189fbf9963b840dbc61ed9c6c2d9d428330e 100644 --- a/drivers/crypto/vmx/aes.c +++ b/drivers/crypto/vmx/aes.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES routines supporting VMX instructions on the Power 8 * * Copyright (C) 2015 International Business Machines Inc. diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index d88084447f1cb59937273d78be8618ebc9526282..ed0debc7acb5fb91a29e7a04a2e9510f72076dfb 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES CBC routines supporting VMX instructions on the Power 8 * * Copyright (C) 2015 International Business Machines Inc. diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 79ba062ee1c1f92b609a4f6725ffa0aa2945c75a..9a3da8cd62f3595efd747e5b4743b1b8dfb4a747 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES CTR routines supporting VMX instructions on the Power 8 * * Copyright (C) 2015 International Business Machines Inc. diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 9fee1b1532a4c14d0ebb7c468c47a15e3fa53173..dabbccb415502ccebb7b335ece652cc627ddcc60 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * AES XTS routines supporting VMX In-core instructions on Power 8 * * Copyright (C) 2015 International Business Machines Inc. diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c index 14807ac2e3b9f0dea9399a172cebda9adaa62879..5bc5710a6de0b5e9b1c32dbf521fedc11bdd3f9f 100644 --- a/drivers/crypto/vmx/ghash.c +++ b/drivers/crypto/vmx/ghash.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * GHASH routines supporting VMX instructions on the Power 8 * * Copyright (C) 2015, 2019 International Business Machines Inc. diff --git a/drivers/crypto/vmx/vmx.c b/drivers/crypto/vmx/vmx.c index a40d08e75fc0bae31c5e379f03170d9f9dae134d..7eb713cc87c8cadc6b7c7bc5c251f8919f8c8790 100644 --- a/drivers/crypto/vmx/vmx.c +++ b/drivers/crypto/vmx/vmx.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Routines supporting VMX instructions on the Power 8 * * Copyright (C) 2015 International Business Machines Inc. diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 00704efe63982cf9a63238d2a1f7cd9c5b690572..20373a893b445580ecdc8f168c73e9da9051e88c 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -62,7 +62,7 @@ config DEVFREQ_GOV_USERSPACE help Sets the frequency at the user specified one. This governor returns the user configured frequency if there - has been an input to /sys/devices/.../power/devfreq_set_freq. + has been an input to /sys/devices/.../userspace/set_freq. Otherwise, the governor does not change the frequency given at the initialization. diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index bf3047896e41ac770b9c67522d0995fbdbfc74aa..fe08c46642f7c5ccda920c949d913796c21c9046 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -11,6 +11,7 @@ #include <linux/kmod.h> #include <linux/sched.h> #include <linux/debugfs.h> +#include <linux/devfreq_cooling.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/init.h> @@ -387,7 +388,7 @@ static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq, devfreq->previous_freq = new_freq; if (devfreq->suspend_freq) - devfreq->resume_freq = cur_freq; + devfreq->resume_freq = new_freq; return err; } @@ -821,7 +822,8 @@ struct devfreq *devfreq_add_device(struct device *dev, if (devfreq->profile->timer < 0 || devfreq->profile->timer >= DEVFREQ_TIMER_NUM) { - goto err_out; + mutex_unlock(&devfreq->lock); + goto err_dev; } if (!devfreq->profile->max_state && !devfreq->profile->freq_table) { @@ -935,6 +937,12 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_unlock(&devfreq_list_lock); + if (devfreq->profile->is_cooling_device) { + devfreq->cdev = devfreq_cooling_em_register(devfreq, NULL); + if (IS_ERR(devfreq->cdev)) + devfreq->cdev = NULL; + } + return devfreq; err_init: @@ -960,6 +968,8 @@ int devfreq_remove_device(struct devfreq *devfreq) if (!devfreq) return -EINVAL; + devfreq_cooling_unregister(devfreq->cdev); + if (devfreq->governor) { devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL); diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index 70f44b3ca42e60c2aa5cc6b440ff38846c350cb9..2d69a0ce6291b75cacaa6be83f4aab75d8c64e4b 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -57,8 +57,6 @@ * Basically, get_target_freq will run * devfreq_dev_profile.get_dev_status() to get the * status of the device (load = busy_time / total_time). - * If no_central_polling is set, this callback is called - * only with update_devfreq() notified by OPP. * @event_handler: Callback for devfreq core framework to notify events * to governors. Events include per device governor * init and exit, opp changes out of devfreq, suspend @@ -91,6 +89,9 @@ int devfreq_update_target(struct devfreq *devfreq, unsigned long freq); static inline int devfreq_update_stats(struct devfreq *df) { + if (!df->profile->get_dev_status) + return -EINVAL; + return df->profile->get_dev_status(df->dev.parent, &df->last_status); } #endif /* _GOVERNOR_H */ diff --git a/drivers/devfreq/imx-bus.c b/drivers/devfreq/imx-bus.c index 4f38455ad74239550ceec80078a6874e45e42a25..3fc3fd77492d58d6e844aae46f73e159918e8589 100644 --- a/drivers/devfreq/imx-bus.c +++ b/drivers/devfreq/imx-bus.c @@ -169,7 +169,7 @@ static struct platform_driver imx_bus_platdrv = { .probe = imx_bus_probe, .driver = { .name = "imx-bus-devfreq", - .of_match_table = of_match_ptr(imx_bus_of_match), + .of_match_table = imx_bus_of_match, }, }; module_platform_driver(imx_bus_platdrv); diff --git a/drivers/devfreq/imx8m-ddrc.c b/drivers/devfreq/imx8m-ddrc.c index bc82d3653bff87fdd0d8e204b03ad53b2955e60b..16636973eb104f2293c3e9b1c69fb3f5b63b484b 100644 --- a/drivers/devfreq/imx8m-ddrc.c +++ b/drivers/devfreq/imx8m-ddrc.c @@ -280,18 +280,6 @@ static int imx8m_ddrc_get_cur_freq(struct device *dev, unsigned long *freq) return 0; } -static int imx8m_ddrc_get_dev_status(struct device *dev, - struct devfreq_dev_status *stat) -{ - struct imx8m_ddrc *priv = dev_get_drvdata(dev); - - stat->busy_time = 0; - stat->total_time = 0; - stat->current_frequency = clk_get_rate(priv->dram_core); - - return 0; -} - static int imx8m_ddrc_init_freq_info(struct device *dev) { struct imx8m_ddrc *priv = dev_get_drvdata(dev); @@ -429,9 +417,7 @@ static int imx8m_ddrc_probe(struct platform_device *pdev) if (ret < 0) goto err; - priv->profile.polling_ms = 1000; priv->profile.target = imx8m_ddrc_target; - priv->profile.get_dev_status = imx8m_ddrc_get_dev_status; priv->profile.exit = imx8m_ddrc_exit; priv->profile.get_cur_freq = imx8m_ddrc_get_cur_freq; priv->profile.initial_freq = clk_get_rate(priv->dram_core); @@ -461,7 +447,7 @@ static struct platform_driver imx8m_ddrc_platdrv = { .probe = imx8m_ddrc_probe, .driver = { .name = "imx8m-ddrc-devfreq", - .of_match_table = of_match_ptr(imx8m_ddrc_of_match), + .of_match_table = imx8m_ddrc_of_match, }, }; module_platform_driver(imx8m_ddrc_platdrv); diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c index 9e9d3b4c6d48c3169d2949084d68527e7e61ce6b..293857ebfd75ddb56933b75a0aeb8bce94434d3e 100644 --- a/drivers/devfreq/rk3399_dmc.c +++ b/drivers/devfreq/rk3399_dmc.c @@ -324,22 +324,14 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) mutex_init(&data->lock); data->vdd_center = devm_regulator_get(dev, "center"); - if (IS_ERR(data->vdd_center)) { - if (PTR_ERR(data->vdd_center) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - dev_err(dev, "Cannot get the regulator \"center\"\n"); - return PTR_ERR(data->vdd_center); - } + if (IS_ERR(data->vdd_center)) + return dev_err_probe(dev, PTR_ERR(data->vdd_center), + "Cannot get the regulator \"center\"\n"); data->dmc_clk = devm_clk_get(dev, "dmc_clk"); - if (IS_ERR(data->dmc_clk)) { - if (PTR_ERR(data->dmc_clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - dev_err(dev, "Cannot get the clk dmc_clk\n"); - return PTR_ERR(data->dmc_clk); - } + if (IS_ERR(data->dmc_clk)) + return dev_err_probe(dev, PTR_ERR(data->dmc_clk), + "Cannot get the clk dmc_clk\n"); data->edev = devfreq_event_get_edev_by_phandle(dev, "devfreq-events", 0); if (IS_ERR(data->edev)) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 0c2827fd8c195bcc3525ef8892ac4e9809c7a734..a0836ffc22e04a29f39417d9329af50d8488e0bb 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -100,7 +100,7 @@ config AT_XDMAC config AXI_DMAC tristate "Analog Devices AXI-DMAC DMA support" - depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_SOCFPGA || COMPILE_TEST + depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST select DMA_ENGINE select DMA_VIRTUAL_CHANNELS select REGMAP_MMIO diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 27d0c4cdc58d5204361044127965d5762c6c8f1b..1e836e320edd965cb0072596a8d9e35a8d699f88 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -396,7 +396,7 @@ config EDAC_THUNDERX config EDAC_ALTERA bool "Altera SOCFPGA ECC" - depends on EDAC=y && (ARCH_SOCFPGA || ARCH_STRATIX10) + depends on EDAC=y && ARCH_INTEL_SOCFPGA help Support for error detection and correction on the Altera SOCs. This is the global enable for the diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index e91cf1147a4e0f4740a65f39560c35bc5a5ecec0..5f7fd79ec82fc98f50b836b3c68a40fc1e14a481 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1501,8 +1501,13 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) dci->mod_name = ecc_name; dci->dev_name = ecc_name; - /* Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly */ -#ifdef CONFIG_ARCH_STRATIX10 + /* + * Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly + * + * FIXME: Instead of ifdefs with different architectures the driver + * should properly use compatibles. + */ +#ifdef CONFIG_64BIT altdev->sb_irq = irq_of_parse_and_map(np, 1); #else altdev->sb_irq = irq_of_parse_and_map(np, 2); @@ -1521,7 +1526,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) goto err_release_group_1; } -#ifdef CONFIG_ARCH_STRATIX10 +#ifdef CONFIG_64BIT /* Use IRQ to determine SError origin instead of assigning IRQ */ rc = of_property_read_u32_index(np, "interrupts", 1, &altdev->db_irq); if (rc) { @@ -1931,7 +1936,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, goto err_release_group1; } -#ifdef CONFIG_ARCH_STRATIX10 +#ifdef CONFIG_64BIT /* Use IRQ to determine SError origin instead of assigning IRQ */ rc = of_property_read_u32_index(np, "interrupts", 0, &altdev->db_irq); if (rc) { @@ -2016,7 +2021,7 @@ static const struct irq_domain_ops a10_eccmgr_ic_ops = { /************** Stratix 10 EDAC Double Bit Error Handler ************/ #define to_a10edac(p, m) container_of(p, struct altr_arria10_edac, m) -#ifdef CONFIG_ARCH_STRATIX10 +#ifdef CONFIG_64BIT /* panic routine issues reboot on non-zero panic_timeout */ extern int panic_timeout; @@ -2109,7 +2114,7 @@ static int altr_edac_a10_probe(struct platform_device *pdev) altr_edac_a10_irq_handler, edac); -#ifdef CONFIG_ARCH_STRATIX10 +#ifdef CONFIG_64BIT { int dberror, err_addr; diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index c211222f5d0ccf6166a394a6b7ff02a16bcb5327..4105df74f2b06f74dee219d86d9f390af58a3144 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -9,6 +9,7 @@ * (originally switch class is supported) */ +#include <linux/devm-helpers.h> #include <linux/extcon-provider.h> #include <linux/gpio/consumer.h> #include <linux/init.h> @@ -112,7 +113,9 @@ static int gpio_extcon_probe(struct platform_device *pdev) if (ret < 0) return ret; - INIT_DELAYED_WORK(&data->work, gpio_extcon_work); + ret = devm_delayed_work_autocancel(dev, &data->work, gpio_extcon_work); + if (ret) + return ret; /* * Request the interrupt of gpio to detect whether external connector @@ -131,15 +134,6 @@ static int gpio_extcon_probe(struct platform_device *pdev) return 0; } -static int gpio_extcon_remove(struct platform_device *pdev) -{ - struct gpio_extcon_data *data = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&data->work); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int gpio_extcon_resume(struct device *dev) { @@ -158,7 +152,6 @@ static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume); static struct platform_driver gpio_extcon_driver = { .probe = gpio_extcon_probe, - .remove = gpio_extcon_remove, .driver = { .name = "extcon-gpio", .pm = &gpio_extcon_pm_ops, diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index 80c9abcc3f97874d4323930c7090b9ae9f60e2e6..fb527c23639e80f689b0f7d2120042d6b62906bb 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -11,6 +11,7 @@ */ #include <linux/acpi.h> +#include <linux/devm-helpers.h> #include <linux/extcon-provider.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> @@ -101,7 +102,9 @@ static int int3496_probe(struct platform_device *pdev) return -ENOMEM; data->dev = dev; - INIT_DELAYED_WORK(&data->work, int3496_do_usb_id); + ret = devm_delayed_work_autocancel(dev, &data->work, int3496_do_usb_id); + if (ret) + return ret; data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN); if (IS_ERR(data->gpio_usb_id)) { @@ -155,16 +158,6 @@ static int int3496_probe(struct platform_device *pdev) return 0; } -static int int3496_remove(struct platform_device *pdev) -{ - struct int3496_data *data = platform_get_drvdata(pdev); - - devm_free_irq(&pdev->dev, data->usb_id_irq, data); - cancel_delayed_work_sync(&data->work); - - return 0; -} - static const struct acpi_device_id int3496_acpi_match[] = { { "INT3496" }, { } @@ -177,7 +170,6 @@ static struct platform_driver int3496_driver = { .acpi_match_table = int3496_acpi_match, }, .probe = int3496_probe, - .remove = int3496_remove, }; module_platform_driver(int3496_driver); diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 337b0eea4e629ea00dd55e96a75299e663a1a67c..e1408075ef7d689f9c7a5f53e1e53de8a6c07722 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -44,6 +44,8 @@ static struct max8997_muic_irq muic_irqs[] = { { MAX8997_MUICIRQ_ChgDetRun, "muic-CHGDETRUN" }, { MAX8997_MUICIRQ_ChgTyp, "muic-CHGTYP" }, { MAX8997_MUICIRQ_OVP, "muic-OVP" }, + { MAX8997_PMICIRQ_CHGINS, "pmic-CHGINS" }, + { MAX8997_PMICIRQ_CHGRM, "pmic-CHGRM" }, }; /* Define supported cable type */ @@ -538,6 +540,8 @@ static void max8997_muic_irq_work(struct work_struct *work) case MAX8997_MUICIRQ_DCDTmr: case MAX8997_MUICIRQ_ChgDetRun: case MAX8997_MUICIRQ_ChgTyp: + case MAX8997_PMICIRQ_CHGINS: + case MAX8997_PMICIRQ_CHGRM: /* Handle charger cable */ ret = max8997_muic_chg_handler(info); break; diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index a2852bcc5f0d5e215a6230262c01053fd395202e..d2c1a8b89c085449eb16ca6a168fc8ec4dabbc1a 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -9,6 +9,7 @@ * Author: Hema HK <hemahk@ti.com> */ +#include <linux/devm-helpers.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/platform_device.h> @@ -237,7 +238,11 @@ static int palmas_usb_probe(struct platform_device *pdev) palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce); } - INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect); + status = devm_delayed_work_autocancel(&pdev->dev, + &palmas_usb->wq_detectid, + palmas_gpio_id_detect); + if (status) + return status; palmas->usb = palmas_usb; palmas_usb->palmas = palmas; @@ -359,15 +364,6 @@ static int palmas_usb_probe(struct platform_device *pdev) return 0; } -static int palmas_usb_remove(struct platform_device *pdev) -{ - struct palmas_usb *palmas_usb = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&palmas_usb->wq_detectid); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int palmas_usb_suspend(struct device *dev) { @@ -422,7 +418,6 @@ static const struct of_device_id of_palmas_match_tbl[] = { static struct platform_driver palmas_usb_driver = { .probe = palmas_usb_probe, - .remove = palmas_usb_remove, .driver = { .name = "palmas-usb", .of_match_table = of_palmas_match_tbl, diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index 6b836ae6217673737962be62b5c678fab9b77fc0..eb02cb962b5e18585ef4be6266351314527a8493 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only /** * extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID - * detection based on extcon-usb-gpio.c. + * and VBUS detection based on extcon-usb-gpio.c. * * Copyright (C) 2016 Linaro, Ltd. * Stephen Boyd <stephen.boyd@linaro.org> */ +#include <linux/devm-helpers.h> #include <linux/extcon-provider.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -21,30 +22,56 @@ struct qcom_usb_extcon_info { struct extcon_dev *edev; - int irq; + int id_irq; + int vbus_irq; struct delayed_work wq_detcable; unsigned long debounce_jiffies; }; static const unsigned int qcom_usb_extcon_cable[] = { + EXTCON_USB, EXTCON_USB_HOST, EXTCON_NONE, }; static void qcom_usb_extcon_detect_cable(struct work_struct *work) { - bool id; + bool state = false; int ret; + union extcon_property_value val; struct qcom_usb_extcon_info *info = container_of(to_delayed_work(work), struct qcom_usb_extcon_info, wq_detcable); - /* check ID and update cable state */ - ret = irq_get_irqchip_state(info->irq, IRQCHIP_STATE_LINE_LEVEL, &id); - if (ret) - return; + if (info->id_irq > 0) { + /* check ID and update cable state */ + ret = irq_get_irqchip_state(info->id_irq, + IRQCHIP_STATE_LINE_LEVEL, &state); + if (ret) + return; + + if (!state) { + val.intval = true; + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS, val); + } + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !state); + } - extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id); + if (info->vbus_irq > 0) { + /* check VBUS and update cable state */ + ret = irq_get_irqchip_state(info->vbus_irq, + IRQCHIP_STATE_LINE_LEVEL, &state); + if (ret) + return; + + if (state) { + val.intval = true; + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_SS, val); + } + extcon_set_state_sync(info->edev, EXTCON_USB, state); + } } static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id) @@ -79,21 +106,52 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) return ret; } + ret = extcon_set_property_capability(info->edev, + EXTCON_USB, EXTCON_PROP_USB_SS); + ret |= extcon_set_property_capability(info->edev, + EXTCON_USB_HOST, EXTCON_PROP_USB_SS); + if (ret) { + dev_err(dev, "failed to register extcon props rc=%d\n", + ret); + return ret; + } + info->debounce_jiffies = msecs_to_jiffies(USB_ID_DEBOUNCE_MS); - INIT_DELAYED_WORK(&info->wq_detcable, qcom_usb_extcon_detect_cable); - info->irq = platform_get_irq_byname(pdev, "usb_id"); - if (info->irq < 0) - return info->irq; + ret = devm_delayed_work_autocancel(dev, &info->wq_detcable, + qcom_usb_extcon_detect_cable); + if (ret) + return ret; - ret = devm_request_threaded_irq(dev, info->irq, NULL, + info->id_irq = platform_get_irq_byname(pdev, "usb_id"); + if (info->id_irq > 0) { + ret = devm_request_threaded_irq(dev, info->id_irq, NULL, qcom_usb_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, pdev->name, info); - if (ret < 0) { - dev_err(dev, "failed to request handler for ID IRQ\n"); - return ret; + if (ret < 0) { + dev_err(dev, "failed to request handler for ID IRQ\n"); + return ret; + } + } + + info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus"); + if (info->vbus_irq > 0) { + ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL, + qcom_usb_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + pdev->name, info); + if (ret < 0) { + dev_err(dev, "failed to request handler for VBUS IRQ\n"); + return ret; + } + } + + if (info->id_irq < 0 && info->vbus_irq < 0) { + dev_err(dev, "ID and VBUS IRQ not found\n"); + return -EINVAL; } platform_set_drvdata(pdev, info); @@ -105,23 +163,18 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) return 0; } -static int qcom_usb_extcon_remove(struct platform_device *pdev) -{ - struct qcom_usb_extcon_info *info = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&info->wq_detcable); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int qcom_usb_extcon_suspend(struct device *dev) { struct qcom_usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) - ret = enable_irq_wake(info->irq); + if (device_may_wakeup(dev)) { + if (info->id_irq > 0) + ret = enable_irq_wake(info->id_irq); + if (info->vbus_irq > 0) + ret = enable_irq_wake(info->vbus_irq); + } return ret; } @@ -131,8 +184,12 @@ static int qcom_usb_extcon_resume(struct device *dev) struct qcom_usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) - ret = disable_irq_wake(info->irq); + if (device_may_wakeup(dev)) { + if (info->id_irq > 0) + ret = disable_irq_wake(info->id_irq); + if (info->vbus_irq > 0) + ret = disable_irq_wake(info->vbus_irq); + } return ret; } @@ -149,7 +206,6 @@ MODULE_DEVICE_TABLE(of, qcom_usb_extcon_dt_match); static struct platform_driver qcom_usb_extcon_driver = { .probe = qcom_usb_extcon_probe, - .remove = qcom_usb_extcon_remove, .driver = { .name = "extcon-pm8941-misc", .pm = &qcom_usb_extcon_pm_ops, diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index 106d4da647bd9097d93ce05f6381402274be6ebb..db41d1c58efd56a1e9e14b88f2a7d8471d2dab8b 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -144,6 +144,7 @@ enum sm5502_muic_acc_type { SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* | 001|11110| */ SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END = 0x5e, /* | 010|11110| */ /* |Dev Type1|--ADC| */ + SM5502_MUIC_ADC_GROUND_USB_OTG = 0x80, /* | 100|00000| */ SM5502_MUIC_ADC_OPEN_USB = 0x5f, /* | 010|11111| */ SM5502_MUIC_ADC_OPEN_TA = 0xdf, /* | 110|11111| */ SM5502_MUIC_ADC_OPEN_USB_OTG = 0xff, /* | 111|11111| */ @@ -291,11 +292,27 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) * connected with to MUIC device. */ cable_type = adc & SM5502_REG_ADC_MASK; - if (cable_type == SM5502_MUIC_ADC_GROUND) - return SM5502_MUIC_ADC_GROUND; switch (cable_type) { case SM5502_MUIC_ADC_GROUND: + ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1, + &dev_type1); + if (ret) { + dev_err(info->dev, "failed to read DEV_TYPE1 reg\n"); + return ret; + } + + switch (dev_type1) { + case SM5502_REG_DEV_TYPE1_USB_OTG_MASK: + cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG; + break; + default: + dev_dbg(info->dev, + "cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n", + adc, dev_type1); + return -EINVAL; + } + break; case SM5502_MUIC_ADC_SEND_END_BUTTON: case SM5502_MUIC_ADC_REMOTE_S1_BUTTON: case SM5502_MUIC_ADC_REMOTE_S2_BUTTON: @@ -396,6 +413,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, con_sw = DM_DP_SWITCH_OPEN; vbus_sw = VBUSIN_SWITCH_VBUSOUT; break; + case SM5502_MUIC_ADC_GROUND_USB_OTG: case SM5502_MUIC_ADC_OPEN_USB_OTG: id = EXTCON_USB_HOST; con_sw = DM_DP_SWITCH_USB; diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 9811c40956e54d7c6afb1962027049e86447fcae..17c9d825188bb4c7f622b39b4e466d40391fa5d3 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2545,7 +2545,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) struct driver_data *driver_data = packet->driver_data; int ret = -ENOENT; - tasklet_disable(&ctx->tasklet); + tasklet_disable_in_atomic(&ctx->tasklet); if (packet->ack != 0) goto out; @@ -3465,7 +3465,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base) struct iso_context *ctx = container_of(base, struct iso_context, base); int ret = 0; - tasklet_disable(&ctx->context.tasklet); + tasklet_disable_in_atomic(&ctx->context.tasklet); if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) { context_tasklet((unsigned long)&ctx->context); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index ac2df7d164aa977fc05a1da70d1f92fc8d40529d..af53778edc7e20c8dff39f4b2ce8efca3263ba24 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -206,7 +206,7 @@ config FW_CFG_SYSFS_CMDLINE config INTEL_STRATIX10_SERVICE tristate "Intel Stratix10 Service Layer" - depends on (ARCH_STRATIX10 || ARCH_AGILEX) && HAVE_ARM_SMCCC + depends on ARCH_INTEL_SOCFPGA && ARM64 && HAVE_ARM_SMCCC default n help Intel Stratix10 service layer runs at privileged exception level, @@ -237,6 +237,7 @@ config INTEL_STRATIX10_RSU config QCOM_SCM tristate "Qcom SCM driver" depends on ARM || ARM64 + depends on HAVE_ARM_SMCCC select RESET_CONTROLLER config QCOM_SCM_DOWNLOAD_MODE_DEFAULT diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 017e5d8bd869a752d14bd7cdf58032e9d8a96787..de416f9e792132ad944a697a46ac2e87f7a84999 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -2,11 +2,12 @@ /* * System Control and Management Interface (SCMI) Base Protocol * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications BASE - " fmt +#include <linux/module.h> #include <linux/scmi_protocol.h> #include "common.h" @@ -50,30 +51,30 @@ struct scmi_base_error_notify_payld { * scmi_base_attributes_get() - gets the implementation details * that are associated with the base protocol. * - * @handle: SCMI entity handle + * @ph: SCMI protocol handle * * Return: 0 on success, else appropriate SCMI error. */ -static int scmi_base_attributes_get(const struct scmi_handle *handle) +static int scmi_base_attributes_get(const struct scmi_protocol_handle *ph) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_base_attributes *attr_info; - struct scmi_revision_info *rev = handle->version; + struct scmi_revision_info *rev = ph->get_priv(ph); - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_BASE, 0, sizeof(*attr_info), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, + 0, sizeof(*attr_info), &t); if (ret) return ret; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { attr_info = t->rx.buf; rev->num_protocols = attr_info->num_protocols; rev->num_agents = attr_info->num_agents; } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -81,19 +82,20 @@ static int scmi_base_attributes_get(const struct scmi_handle *handle) /** * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string. * - * @handle: SCMI entity handle + * @ph: SCMI protocol handle * @sub_vendor: specify true if sub-vendor ID is needed * * Return: 0 on success, else appropriate SCMI error. */ static int -scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) +scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor) { u8 cmd; int ret, size; char *vendor_id; struct scmi_xfer *t; - struct scmi_revision_info *rev = handle->version; + struct scmi_revision_info *rev = ph->get_priv(ph); + if (sub_vendor) { cmd = BASE_DISCOVER_SUB_VENDOR; @@ -105,15 +107,15 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) size = ARRAY_SIZE(rev->vendor_id); } - ret = scmi_xfer_get_init(handle, cmd, SCMI_PROTOCOL_BASE, 0, size, &t); + ret = ph->xops->xfer_get_init(ph, cmd, 0, size, &t); if (ret) return ret; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) memcpy(vendor_id, t->rx.buf, size); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -123,30 +125,30 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) * implementation 32-bit version. The format of the version number is * vendor-specific * - * @handle: SCMI entity handle + * @ph: SCMI protocol handle * * Return: 0 on success, else appropriate SCMI error. */ static int -scmi_base_implementation_version_get(const struct scmi_handle *handle) +scmi_base_implementation_version_get(const struct scmi_protocol_handle *ph) { int ret; __le32 *impl_ver; struct scmi_xfer *t; - struct scmi_revision_info *rev = handle->version; + struct scmi_revision_info *rev = ph->get_priv(ph); - ret = scmi_xfer_get_init(handle, BASE_DISCOVER_IMPLEMENT_VERSION, - SCMI_PROTOCOL_BASE, 0, sizeof(*impl_ver), &t); + ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_IMPLEMENT_VERSION, + 0, sizeof(*impl_ver), &t); if (ret) return ret; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { impl_ver = t->rx.buf; rev->impl_ver = le32_to_cpu(*impl_ver); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -155,23 +157,24 @@ scmi_base_implementation_version_get(const struct scmi_handle *handle) * scmi_base_implementation_list_get() - gets the list of protocols it is * OSPM is allowed to access * - * @handle: SCMI entity handle + * @ph: SCMI protocol handle * @protocols_imp: pointer to hold the list of protocol identifiers * * Return: 0 on success, else appropriate SCMI error. */ -static int scmi_base_implementation_list_get(const struct scmi_handle *handle, - u8 *protocols_imp) +static int +scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph, + u8 *protocols_imp) { u8 *list; int ret, loop; struct scmi_xfer *t; __le32 *num_skip, *num_ret; u32 tot_num_ret = 0, loop_num_ret; - struct device *dev = handle->dev; + struct device *dev = ph->dev; - ret = scmi_xfer_get_init(handle, BASE_DISCOVER_LIST_PROTOCOLS, - SCMI_PROTOCOL_BASE, sizeof(*num_skip), 0, &t); + ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_LIST_PROTOCOLS, + sizeof(*num_skip), 0, &t); if (ret) return ret; @@ -183,7 +186,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, /* Set the number of protocols to be skipped/already read */ *num_skip = cpu_to_le32(tot_num_ret); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (ret) break; @@ -198,10 +201,10 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, tot_num_ret += loop_num_ret; - scmi_reset_rx_to_maxsz(handle, t); + ph->xops->reset_rx_to_maxsz(ph, t); } while (loop_num_ret); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -209,7 +212,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, /** * scmi_base_discover_agent_get() - discover the name of an agent * - * @handle: SCMI entity handle + * @ph: SCMI protocol handle * @id: Agent identifier * @name: Agent identifier ASCII string * @@ -218,63 +221,63 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, * * Return: 0 on success, else appropriate SCMI error. */ -static int scmi_base_discover_agent_get(const struct scmi_handle *handle, +static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph, int id, char *name) { int ret; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, BASE_DISCOVER_AGENT, - SCMI_PROTOCOL_BASE, sizeof(__le32), - SCMI_MAX_STR_SIZE, &t); + ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_AGENT, + sizeof(__le32), SCMI_MAX_STR_SIZE, &t); if (ret) return ret; put_unaligned_le32(id, t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) strlcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_base_error_notify(const struct scmi_handle *handle, bool enable) +static int scmi_base_error_notify(const struct scmi_protocol_handle *ph, + bool enable) { int ret; u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0; struct scmi_xfer *t; struct scmi_msg_base_error_notify *cfg; - ret = scmi_xfer_get_init(handle, BASE_NOTIFY_ERRORS, - SCMI_PROTOCOL_BASE, sizeof(*cfg), 0, &t); + ret = ph->xops->xfer_get_init(ph, BASE_NOTIFY_ERRORS, + sizeof(*cfg), 0, &t); if (ret) return ret; cfg = t->tx.buf; cfg->event_control = cpu_to_le32(evt_cntl); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_base_set_notify_enabled(const struct scmi_handle *handle, +static int scmi_base_set_notify_enabled(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enable) { int ret; - ret = scmi_base_error_notify(handle, enable); + ret = scmi_base_error_notify(ph, enable); if (ret) pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret); return ret; } -static void *scmi_base_fill_custom_report(const struct scmi_handle *handle, +static void *scmi_base_fill_custom_report(const struct scmi_protocol_handle *ph, u8 evt_id, ktime_t timestamp, const void *payld, size_t payld_sz, void *report, u32 *src_id) @@ -318,17 +321,24 @@ static const struct scmi_event_ops base_event_ops = { .fill_custom_report = scmi_base_fill_custom_report, }; -int scmi_base_protocol_init(struct scmi_handle *h) +static const struct scmi_protocol_events base_protocol_events = { + .queue_sz = 4 * SCMI_PROTO_QUEUE_SZ, + .ops = &base_event_ops, + .evts = base_events, + .num_events = ARRAY_SIZE(base_events), + .num_sources = SCMI_BASE_NUM_SOURCES, +}; + +static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) { int id, ret; u8 *prot_imp; u32 version; char name[SCMI_MAX_STR_SIZE]; - const struct scmi_handle *handle = h; - struct device *dev = handle->dev; - struct scmi_revision_info *rev = handle->version; + struct device *dev = ph->dev; + struct scmi_revision_info *rev = scmi_revision_area_get(ph); - ret = scmi_version_get(handle, SCMI_PROTOCOL_BASE, &version); + ret = ph->xops->version_get(ph, &version); if (ret) return ret; @@ -338,13 +348,15 @@ int scmi_base_protocol_init(struct scmi_handle *h) rev->major_ver = PROTOCOL_REV_MAJOR(version), rev->minor_ver = PROTOCOL_REV_MINOR(version); + ph->set_priv(ph, rev); + + scmi_base_attributes_get(ph); + scmi_base_vendor_id_get(ph, false); + scmi_base_vendor_id_get(ph, true); + scmi_base_implementation_version_get(ph); + scmi_base_implementation_list_get(ph, prot_imp); - scmi_base_attributes_get(handle); - scmi_base_vendor_id_get(handle, false); - scmi_base_vendor_id_get(handle, true); - scmi_base_implementation_version_get(handle); - scmi_base_implementation_list_get(handle, prot_imp); - scmi_setup_protocol_implemented(handle, prot_imp); + scmi_setup_protocol_implemented(ph, prot_imp); dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n", rev->major_ver, rev->minor_ver, rev->vendor_id, @@ -352,16 +364,20 @@ int scmi_base_protocol_init(struct scmi_handle *h) dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols, rev->num_agents); - scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE, - (4 * SCMI_PROTO_QUEUE_SZ), - &base_event_ops, base_events, - ARRAY_SIZE(base_events), - SCMI_BASE_NUM_SOURCES); - for (id = 0; id < rev->num_agents; id++) { - scmi_base_discover_agent_get(handle, id, name); + scmi_base_discover_agent_get(ph, id, name); dev_dbg(dev, "Agent %d: %s\n", id, name); } return 0; } + +static const struct scmi_protocol scmi_base = { + .id = SCMI_PROTOCOL_BASE, + .owner = NULL, + .instance_init = &scmi_base_protocol_init, + .ops = NULL, + .events = &base_protocol_events, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base) diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index 1377ec76a45dbb4ee0e54293c4308984c4f0ccb8..784cf0027da3c5a95923f59fc1b9dc99ab8f98b3 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -2,7 +2,7 @@ /* * System Control and Management Interface (SCMI) Message Protocol bus layer * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -51,18 +51,53 @@ static int scmi_dev_match(struct device *dev, struct device_driver *drv) return 0; } -static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle) +static int scmi_match_by_id_table(struct device *dev, void *data) { - scmi_prot_init_fn_t fn = idr_find(&scmi_protocols, protocol_id); + struct scmi_device *sdev = to_scmi_dev(dev); + struct scmi_device_id *id_table = data; - if (unlikely(!fn)) - return -EINVAL; - return fn(handle); + return sdev->protocol_id == id_table->protocol_id && + !strcmp(sdev->name, id_table->name); } -static int scmi_protocol_dummy_init(struct scmi_handle *handle) +struct scmi_device *scmi_child_dev_find(struct device *parent, + int prot_id, const char *name) { - return 0; + struct scmi_device_id id_table; + struct device *dev; + + id_table.protocol_id = prot_id; + id_table.name = name; + + dev = device_find_child(parent, &id_table, scmi_match_by_id_table); + if (!dev) + return NULL; + + return to_scmi_dev(dev); +} + +const struct scmi_protocol *scmi_protocol_get(int protocol_id) +{ + const struct scmi_protocol *proto; + + proto = idr_find(&scmi_protocols, protocol_id); + if (!proto || !try_module_get(proto->owner)) { + pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id); + return NULL; + } + + pr_debug("Found SCMI Protocol 0x%x\n", protocol_id); + + return proto; +} + +void scmi_protocol_put(int protocol_id) +{ + const struct scmi_protocol *proto; + + proto = idr_find(&scmi_protocols, protocol_id); + if (proto) + module_put(proto->owner); } static int scmi_dev_probe(struct device *dev) @@ -70,7 +105,6 @@ static int scmi_dev_probe(struct device *dev) struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver); struct scmi_device *scmi_dev = to_scmi_dev(dev); const struct scmi_device_id *id; - int ret; id = scmi_dev_match_id(scmi_dev, scmi_drv); if (!id) @@ -79,14 +113,6 @@ static int scmi_dev_probe(struct device *dev) if (!scmi_dev->handle) return -EPROBE_DEFER; - ret = scmi_protocol_init(scmi_dev->protocol_id, scmi_dev->handle); - if (ret) - return ret; - - /* Skip protocol initialisation for additional devices */ - idr_replace(&scmi_protocols, &scmi_protocol_dummy_init, - scmi_dev->protocol_id); - return scmi_drv->probe(scmi_dev); } @@ -113,6 +139,10 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, { int retval; + retval = scmi_protocol_device_request(driver->id_table); + if (retval) + return retval; + driver->driver.bus = &scmi_bus_type; driver->driver.name = driver->name; driver->driver.owner = owner; @@ -129,6 +159,7 @@ EXPORT_SYMBOL_GPL(scmi_driver_register); void scmi_driver_unregister(struct scmi_driver *driver) { driver_unregister(&driver->driver); + scmi_protocol_device_unrequest(driver->id_table); } EXPORT_SYMBOL_GPL(scmi_driver_unregister); @@ -194,26 +225,45 @@ void scmi_set_handle(struct scmi_device *scmi_dev) scmi_dev->handle = scmi_handle_get(&scmi_dev->dev); } -int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn) +int scmi_protocol_register(const struct scmi_protocol *proto) { int ret; + if (!proto) { + pr_err("invalid protocol\n"); + return -EINVAL; + } + + if (!proto->instance_init) { + pr_err("missing init for protocol 0x%x\n", proto->id); + return -EINVAL; + } + spin_lock(&protocol_lock); - ret = idr_alloc(&scmi_protocols, fn, protocol_id, protocol_id + 1, - GFP_ATOMIC); + ret = idr_alloc(&scmi_protocols, (void *)proto, + proto->id, proto->id + 1, GFP_ATOMIC); spin_unlock(&protocol_lock); - if (ret != protocol_id) - pr_err("unable to allocate SCMI idr slot, err %d\n", ret); + if (ret != proto->id) { + pr_err("unable to allocate SCMI idr slot for 0x%x - err %d\n", + proto->id, ret); + return ret; + } - return ret; + pr_debug("Registered SCMI Protocol 0x%x\n", proto->id); + + return 0; } EXPORT_SYMBOL_GPL(scmi_protocol_register); -void scmi_protocol_unregister(int protocol_id) +void scmi_protocol_unregister(const struct scmi_protocol *proto) { spin_lock(&protocol_lock); - idr_remove(&scmi_protocols, protocol_id); + idr_remove(&scmi_protocols, proto->id); spin_unlock(&protocol_lock); + + pr_debug("Unregistered SCMI Protocol 0x%x\n", proto->id); + + return; } EXPORT_SYMBOL_GPL(scmi_protocol_unregister); diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 4645677d86f1b1648bccfb99c9f88a2393a98dff..35b56c8ba0c0ef7047ecb0e87678df889385758e 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -2,9 +2,10 @@ /* * System Control and Management Interface (SCMI) Clock Protocol * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ +#include <linux/module.h> #include <linux/sort.h> #include "common.h" @@ -74,52 +75,53 @@ struct clock_info { struct scmi_clock_info *clk; }; -static int scmi_clock_protocol_attributes_get(const struct scmi_handle *handle, - struct clock_info *ci) +static int +scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, + struct clock_info *ci) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_clock_protocol_attributes *attr; - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_CLOCK, 0, sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, + 0, sizeof(*attr), &t); if (ret) return ret; attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { ci->num_clocks = le16_to_cpu(attr->num_clocks); ci->max_async_req = attr->max_async_req; } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_clock_attributes_get(const struct scmi_handle *handle, +static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, u32 clk_id, struct scmi_clock_info *clk) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_clock_attributes *attr; - ret = scmi_xfer_get_init(handle, CLOCK_ATTRIBUTES, SCMI_PROTOCOL_CLOCK, - sizeof(clk_id), sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES, + sizeof(clk_id), sizeof(*attr), &t); if (ret) return ret; put_unaligned_le32(clk_id, t->tx.buf); attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE); else clk->name[0] = '\0'; - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -136,7 +138,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2) } static int -scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, +scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id, struct scmi_clock_info *clk) { u64 *rate = NULL; @@ -148,8 +150,8 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, struct scmi_msg_clock_describe_rates *clk_desc; struct scmi_msg_resp_clock_describe_rates *rlist; - ret = scmi_xfer_get_init(handle, CLOCK_DESCRIBE_RATES, - SCMI_PROTOCOL_CLOCK, sizeof(*clk_desc), 0, &t); + ret = ph->xops->xfer_get_init(ph, CLOCK_DESCRIBE_RATES, + sizeof(*clk_desc), 0, &t); if (ret) return ret; @@ -161,7 +163,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, /* Set the number of rates to be skipped/already read */ clk_desc->rate_index = cpu_to_le32(tot_rate_cnt); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (ret) goto err; @@ -171,7 +173,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, num_returned = NUM_RETURNED(rates_flag); if (tot_rate_cnt + num_returned > SCMI_MAX_NUM_RATES) { - dev_err(handle->dev, "No. of rates > MAX_NUM_RATES"); + dev_err(ph->dev, "No. of rates > MAX_NUM_RATES"); break; } @@ -179,7 +181,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, clk->range.min_rate = RATE_TO_U64(rlist->rate[0]); clk->range.max_rate = RATE_TO_U64(rlist->rate[1]); clk->range.step_size = RATE_TO_U64(rlist->rate[2]); - dev_dbg(handle->dev, "Min %llu Max %llu Step %llu Hz\n", + dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n", clk->range.min_rate, clk->range.max_rate, clk->range.step_size); break; @@ -188,12 +190,12 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, rate = &clk->list.rates[tot_rate_cnt]; for (cnt = 0; cnt < num_returned; cnt++, rate++) { *rate = RATE_TO_U64(rlist->rate[cnt]); - dev_dbg(handle->dev, "Rate %llu Hz\n", *rate); + dev_dbg(ph->dev, "Rate %llu Hz\n", *rate); } tot_rate_cnt += num_returned; - scmi_reset_rx_to_maxsz(handle, t); + ph->xops->reset_rx_to_maxsz(ph, t); /* * check for both returned and remaining to avoid infinite * loop due to buggy firmware @@ -208,42 +210,42 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, clk->rate_discrete = rate_discrete; err: - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static int -scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value) +scmi_clock_rate_get(const struct scmi_protocol_handle *ph, + u32 clk_id, u64 *value) { int ret; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, CLOCK_RATE_GET, SCMI_PROTOCOL_CLOCK, - sizeof(__le32), sizeof(u64), &t); + ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_GET, + sizeof(__le32), sizeof(u64), &t); if (ret) return ret; put_unaligned_le32(clk_id, t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) *value = get_unaligned_le64(t->rx.buf); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id, - u64 rate) +static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph, + u32 clk_id, u64 rate) { int ret; u32 flags = 0; struct scmi_xfer *t; struct scmi_clock_set_rate *cfg; - struct clock_info *ci = handle->clk_priv; + struct clock_info *ci = ph->get_priv(ph); - ret = scmi_xfer_get_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK, - sizeof(*cfg), 0, &t); + ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -258,26 +260,27 @@ static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id, cfg->value_high = cpu_to_le32(rate >> 32); if (flags & CLOCK_SET_ASYNC) - ret = scmi_do_xfer_with_response(handle, t); + ret = ph->xops->do_xfer_with_response(ph, t); else - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (ci->max_async_req) atomic_dec(&ci->cur_async_req); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static int -scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config) +scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id, + u32 config) { int ret; struct scmi_xfer *t; struct scmi_clock_set_config *cfg; - ret = scmi_xfer_get_init(handle, CLOCK_CONFIG_SET, SCMI_PROTOCOL_CLOCK, - sizeof(*cfg), 0, &t); + ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_SET, + sizeof(*cfg), 0, &t); if (ret) return ret; @@ -285,33 +288,33 @@ scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config) cfg->id = cpu_to_le32(clk_id); cfg->attributes = cpu_to_le32(config); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_clock_enable(const struct scmi_handle *handle, u32 clk_id) +static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id) { - return scmi_clock_config_set(handle, clk_id, CLOCK_ENABLE); + return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE); } -static int scmi_clock_disable(const struct scmi_handle *handle, u32 clk_id) +static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id) { - return scmi_clock_config_set(handle, clk_id, 0); + return scmi_clock_config_set(ph, clk_id, 0); } -static int scmi_clock_count_get(const struct scmi_handle *handle) +static int scmi_clock_count_get(const struct scmi_protocol_handle *ph) { - struct clock_info *ci = handle->clk_priv; + struct clock_info *ci = ph->get_priv(ph); return ci->num_clocks; } static const struct scmi_clock_info * -scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id) +scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id) { - struct clock_info *ci = handle->clk_priv; + struct clock_info *ci = ph->get_priv(ph); struct scmi_clock_info *clk = ci->clk + clk_id; if (!clk->name[0]) @@ -320,7 +323,7 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id) return clk; } -static const struct scmi_clk_ops clk_ops = { +static const struct scmi_clk_proto_ops clk_proto_ops = { .count_get = scmi_clock_count_get, .info_get = scmi_clock_info_get, .rate_get = scmi_clock_rate_get, @@ -329,24 +332,24 @@ static const struct scmi_clk_ops clk_ops = { .disable = scmi_clock_disable, }; -static int scmi_clock_protocol_init(struct scmi_handle *handle) +static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) { u32 version; int clkid, ret; struct clock_info *cinfo; - scmi_version_get(handle, SCMI_PROTOCOL_CLOCK, &version); + ph->xops->version_get(ph, &version); - dev_dbg(handle->dev, "Clock Version %d.%d\n", + dev_dbg(ph->dev, "Clock Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - cinfo = devm_kzalloc(handle->dev, sizeof(*cinfo), GFP_KERNEL); + cinfo = devm_kzalloc(ph->dev, sizeof(*cinfo), GFP_KERNEL); if (!cinfo) return -ENOMEM; - scmi_clock_protocol_attributes_get(handle, cinfo); + scmi_clock_protocol_attributes_get(ph, cinfo); - cinfo->clk = devm_kcalloc(handle->dev, cinfo->num_clocks, + cinfo->clk = devm_kcalloc(ph->dev, cinfo->num_clocks, sizeof(*cinfo->clk), GFP_KERNEL); if (!cinfo->clk) return -ENOMEM; @@ -354,16 +357,20 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle) for (clkid = 0; clkid < cinfo->num_clocks; clkid++) { struct scmi_clock_info *clk = cinfo->clk + clkid; - ret = scmi_clock_attributes_get(handle, clkid, clk); + ret = scmi_clock_attributes_get(ph, clkid, clk); if (!ret) - scmi_clock_describe_rates_get(handle, clkid, clk); + scmi_clock_describe_rates_get(ph, clkid, clk); } cinfo->version = version; - handle->clk_ops = &clk_ops; - handle->clk_priv = cinfo; - - return 0; + return ph->set_priv(ph, cinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_CLOCK, clock) +static const struct scmi_protocol scmi_clock = { + .id = SCMI_PROTOCOL_CLOCK, + .owner = THIS_MODULE, + .instance_init = &scmi_clock_protocol_init, + .ops = &clk_proto_ops, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index c0fb45e7c3e8402770c0f2b7cb598b1c4eba586f..228bf4a71d237fdfeb7b4a8bb8c71c1d153da7a0 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -4,7 +4,7 @@ * driver common header file containing some definitions, structures * and function prototypes used in all the different SCMI protocols. * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #ifndef _SCMI_COMMON_H #define _SCMI_COMMON_H @@ -14,11 +14,14 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/scmi_protocol.h> #include <linux/types.h> #include <asm/unaligned.h> +#include "notify.h" + #define PROTOCOL_REV_MINOR_MASK GENMASK(15, 0) #define PROTOCOL_REV_MAJOR_MASK GENMASK(31, 16) #define PROTOCOL_REV_MAJOR(x) (u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))) @@ -141,22 +144,92 @@ struct scmi_xfer { struct completion *async_done; }; -void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer); -int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer); -int scmi_do_xfer_with_response(const struct scmi_handle *h, - struct scmi_xfer *xfer); -int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id, - size_t tx_size, size_t rx_size, struct scmi_xfer **p); -void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle, - struct scmi_xfer *xfer); +struct scmi_xfer_ops; + +/** + * struct scmi_protocol_handle - Reference to an initialized protocol instance + * + * @dev: A reference to the associated SCMI instance device (handle->dev). + * @xops: A reference to a struct holding refs to the core xfer operations that + * can be used by the protocol implementation to generate SCMI messages. + * @set_priv: A method to set protocol private data for this instance. + * @get_priv: A method to get protocol private data previously set. + * + * This structure represents a protocol initialized against specific SCMI + * instance and it will be used as follows: + * - as a parameter fed from the core to the protocol initialization code so + * that it can access the core xfer operations to build and generate SCMI + * messages exclusively for the specific underlying protocol instance. + * - as an opaque handle fed by an SCMI driver user when it tries to access + * this protocol through its own protocol operations. + * In this case this handle will be returned as an opaque object together + * with the related protocol operations when the SCMI driver tries to access + * the protocol. + */ +struct scmi_protocol_handle { + struct device *dev; + const struct scmi_xfer_ops *xops; + int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv); + void *(*get_priv)(const struct scmi_protocol_handle *ph); +}; + +/** + * struct scmi_xfer_ops - References to the core SCMI xfer operations. + * @version_get: Get this version protocol. + * @xfer_get_init: Initialize one struct xfer if any xfer slot is free. + * @reset_rx_to_maxsz: Reset rx size to max transport size. + * @do_xfer: Do the SCMI transfer. + * @do_xfer_with_response: Do the SCMI transfer waiting for a response. + * @xfer_put: Free the xfer slot. + * + * Note that all this operations expect a protocol handle as first parameter; + * they then internally use it to infer the underlying protocol number: this + * way is not possible for a protocol implementation to forge messages for + * another protocol. + */ +struct scmi_xfer_ops { + int (*version_get)(const struct scmi_protocol_handle *ph, u32 *version); + int (*xfer_get_init)(const struct scmi_protocol_handle *ph, u8 msg_id, + size_t tx_size, size_t rx_size, + struct scmi_xfer **p); + void (*reset_rx_to_maxsz)(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer); + int (*do_xfer)(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer); + int (*do_xfer_with_response)(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer); + void (*xfer_put)(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer); +}; + +struct scmi_revision_info * +scmi_revision_area_get(const struct scmi_protocol_handle *ph); int scmi_handle_put(const struct scmi_handle *handle); struct scmi_handle *scmi_handle_get(struct device *dev); void scmi_set_handle(struct scmi_device *scmi_dev); -int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version); -void scmi_setup_protocol_implemented(const struct scmi_handle *handle, +void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph, u8 *prot_imp); -int scmi_base_protocol_init(struct scmi_handle *h); +typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *); + +/** + * struct scmi_protocol - Protocol descriptor + * @id: Protocol ID. + * @owner: Module reference if any. + * @instance_init: Mandatory protocol initialization function. + * @instance_deinit: Optional protocol de-initialization function. + * @ops: Optional reference to the operations provided by the protocol and + * exposed in scmi_protocol.h. + * @events: An optional reference to the events supported by this protocol. + */ +struct scmi_protocol { + const u8 id; + struct module *owner; + const scmi_prot_init_ph_fn_t instance_init; + const scmi_prot_init_ph_fn_t instance_deinit; + const void *ops; + const struct scmi_protocol_events *events; +}; int __init scmi_bus_init(void); void __exit scmi_bus_exit(void); @@ -164,6 +237,7 @@ void __exit scmi_bus_exit(void); #define DECLARE_SCMI_REGISTER_UNREGISTER(func) \ int __init scmi_##func##_register(void); \ void __exit scmi_##func##_unregister(void) +DECLARE_SCMI_REGISTER_UNREGISTER(base); DECLARE_SCMI_REGISTER_UNREGISTER(clock); DECLARE_SCMI_REGISTER_UNREGISTER(perf); DECLARE_SCMI_REGISTER_UNREGISTER(power); @@ -172,17 +246,25 @@ DECLARE_SCMI_REGISTER_UNREGISTER(sensors); DECLARE_SCMI_REGISTER_UNREGISTER(voltage); DECLARE_SCMI_REGISTER_UNREGISTER(system); -#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(id, name) \ -int __init scmi_##name##_register(void) \ -{ \ - return scmi_protocol_register((id), &scmi_##name##_protocol_init); \ -} \ -\ -void __exit scmi_##name##_unregister(void) \ -{ \ - scmi_protocol_unregister((id)); \ +#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \ +static const struct scmi_protocol *__this_proto = &(proto); \ + \ +int __init scmi_##name##_register(void) \ +{ \ + return scmi_protocol_register(__this_proto); \ +} \ + \ +void __exit scmi_##name##_unregister(void) \ +{ \ + scmi_protocol_unregister(__this_proto); \ } +const struct scmi_protocol *scmi_protocol_get(int protocol_id); +void scmi_protocol_put(int protocol_id); + +int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id); +void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id); + /* SCMI Transport */ /** * struct scmi_chan_info - Structure representing a SCMI channel information @@ -227,6 +309,11 @@ struct scmi_transport_ops { bool (*poll_done)(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer); }; +int scmi_protocol_device_request(const struct scmi_device_id *id_table); +void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table); +struct scmi_device *scmi_child_dev_find(struct device *parent, + int prot_id, const char *name); + /** * struct scmi_desc - Description of SoC integration * @@ -265,4 +352,8 @@ void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); +void scmi_notification_instance_data_set(const struct scmi_handle *handle, + void *priv); +void *scmi_notification_instance_data_get(const struct scmi_handle *handle); + #endif /* _SCMI_COMMON_H */ diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index cacdf1589b101d85e4dd6d819bab74aeffa6a48b..66eb3f0e5dafcecebca8dc6ff984f855721c479f 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -11,18 +11,22 @@ * various power domain DVFS including the core/cluster, certain system * clocks configuration, thermal sensors and many others. * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #include <linux/bitmap.h> +#include <linux/device.h> #include <linux/export.h> +#include <linux/idr.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/ktime.h> +#include <linux/list.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/processor.h> +#include <linux/refcount.h> #include <linux/slab.h> #include "common.h" @@ -53,6 +57,14 @@ static DEFINE_MUTEX(scmi_list_mutex); /* Track the unique id for the transfers for debug & profiling purpose */ static atomic_t transfer_last_id; +static DEFINE_IDR(scmi_requested_devices); +static DEFINE_MUTEX(scmi_requested_devices_mtx); + +struct scmi_requested_dev { + const struct scmi_device_id *id_table; + struct list_head node; +}; + /** * struct scmi_xfers_info - Structure to manage transfer information * @@ -68,6 +80,30 @@ struct scmi_xfers_info { spinlock_t xfer_lock; }; +/** + * struct scmi_protocol_instance - Describe an initialized protocol instance. + * @handle: Reference to the SCMI handle associated to this protocol instance. + * @proto: A reference to the protocol descriptor. + * @gid: A reference for per-protocol devres management. + * @users: A refcount to track effective users of this protocol. + * @priv: Reference for optional protocol private data. + * @ph: An embedded protocol handle that will be passed down to protocol + * initialization code to identify this instance. + * + * Each protocol is initialized independently once for each SCMI platform in + * which is defined by DT and implemented by the SCMI server fw. + */ +struct scmi_protocol_instance { + const struct scmi_handle *handle; + const struct scmi_protocol *proto; + void *gid; + refcount_t users; + void *priv; + struct scmi_protocol_handle ph; +}; + +#define ph_to_pi(h) container_of(h, struct scmi_protocol_instance, ph) + /** * struct scmi_info - Structure representing a SCMI instance * @@ -80,8 +116,15 @@ struct scmi_xfers_info { * @rx_minfo: Universal Receive Message management info * @tx_idr: IDR object to map protocol id to Tx channel info pointer * @rx_idr: IDR object to map protocol id to Rx channel info pointer + * @protocols: IDR for protocols' instance descriptors initialized for + * this SCMI instance: populated on protocol's first attempted + * usage. + * @protocols_mtx: A mutex to protect protocols instances initialization. * @protocols_imp: List of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol + * @active_protocols: IDR storing device_nodes for protocols actually defined + * in the DT and confirmed as implemented by fw. + * @notify_priv: Pointer to private data structure specific to notifications. * @node: List head * @users: Number of users of this instance */ @@ -94,7 +137,12 @@ struct scmi_info { struct scmi_xfers_info rx_minfo; struct idr tx_idr; struct idr rx_idr; + struct idr protocols; + /* Ensure mutual exclusive access to protocols instance array */ + struct mutex protocols_mtx; u8 *protocols_imp; + struct idr active_protocols; + void *notify_priv; struct list_head node; int users; }; @@ -136,6 +184,25 @@ static inline void scmi_dump_header_dbg(struct device *dev, hdr->id, hdr->seq, hdr->protocol_id); } +void scmi_notification_instance_data_set(const struct scmi_handle *handle, + void *priv) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + info->notify_priv = priv; + /* Ensure updated protocol private date are visible */ + smp_wmb(); +} + +void *scmi_notification_instance_data_get(const struct scmi_handle *handle) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + /* Ensure protocols_private_data has been updated */ + smp_rmb(); + return info->notify_priv; +} + /** * scmi_xfer_get() - Allocate one message * @@ -316,14 +383,16 @@ void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr) } /** - * scmi_xfer_put() - Release a transmit message + * xfer_put() - Release a transmit message * - * @handle: Pointer to SCMI entity handle + * @ph: Pointer to SCMI protocol handle * @xfer: message that was reserved by scmi_xfer_get */ -void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) +static void xfer_put(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer) { - struct scmi_info *info = handle_to_scmi_info(handle); + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + struct scmi_info *info = handle_to_scmi_info(pi->handle); __scmi_xfer_put(&info->tx_minfo, xfer); } @@ -340,23 +409,32 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, } /** - * scmi_do_xfer() - Do one transfer + * do_xfer() - Do one transfer * - * @handle: Pointer to SCMI entity handle + * @ph: Pointer to SCMI protocol handle * @xfer: Transfer to initiate and wait for response * * Return: -ETIMEDOUT in case of no response, if transmit error, * return corresponding error, else if all goes well, * return 0. */ -int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) +static int do_xfer(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer) { int ret; int timeout; - struct scmi_info *info = handle_to_scmi_info(handle); + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + struct scmi_info *info = handle_to_scmi_info(pi->handle); struct device *dev = info->dev; struct scmi_chan_info *cinfo; + /* + * Re-instate protocol id here from protocol handle so that cannot be + * overridden by mistake (or malice) by the protocol code mangling with + * the scmi_xfer structure. + */ + xfer->hdr.protocol_id = pi->proto->id; + cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id); if (unlikely(!cinfo)) return -EINVAL; @@ -402,10 +480,11 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) return ret; } -void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle, - struct scmi_xfer *xfer) +static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer) { - struct scmi_info *info = handle_to_scmi_info(handle); + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + struct scmi_info *info = handle_to_scmi_info(pi->handle); xfer->rx.len = info->desc->max_msg_size; } @@ -413,24 +492,27 @@ void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle, #define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) /** - * scmi_do_xfer_with_response() - Do one transfer and wait until the delayed + * do_xfer_with_response() - Do one transfer and wait until the delayed * response is received * - * @handle: Pointer to SCMI entity handle + * @ph: Pointer to SCMI protocol handle * @xfer: Transfer to initiate and wait for response * * Return: -ETIMEDOUT in case of no delayed response, if transmit error, * return corresponding error, else if all goes well, return 0. */ -int scmi_do_xfer_with_response(const struct scmi_handle *handle, - struct scmi_xfer *xfer) +static int do_xfer_with_response(const struct scmi_protocol_handle *ph, + struct scmi_xfer *xfer) { int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT); + const struct scmi_protocol_instance *pi = ph_to_pi(ph); DECLARE_COMPLETION_ONSTACK(async_response); + xfer->hdr.protocol_id = pi->proto->id; + xfer->async_done = &async_response; - ret = scmi_do_xfer(handle, xfer); + ret = do_xfer(ph, xfer); if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout)) ret = -ETIMEDOUT; @@ -439,11 +521,10 @@ int scmi_do_xfer_with_response(const struct scmi_handle *handle, } /** - * scmi_xfer_get_init() - Allocate and initialise one message for transmit + * xfer_get_init() - Allocate and initialise one message for transmit * - * @handle: Pointer to SCMI entity handle + * @ph: Pointer to SCMI protocol handle * @msg_id: Message identifier - * @prot_id: Protocol identifier for the message * @tx_size: transmit message size * @rx_size: receive message size * @p: pointer to the allocated and initialised message @@ -454,12 +535,14 @@ int scmi_do_xfer_with_response(const struct scmi_handle *handle, * Return: 0 if all went fine with @p pointing to message, else * corresponding error. */ -int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, - size_t tx_size, size_t rx_size, struct scmi_xfer **p) +static int xfer_get_init(const struct scmi_protocol_handle *ph, + u8 msg_id, size_t tx_size, size_t rx_size, + struct scmi_xfer **p) { int ret; struct scmi_xfer *xfer; - struct scmi_info *info = handle_to_scmi_info(handle); + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + struct scmi_info *info = handle_to_scmi_info(pi->handle); struct scmi_xfers_info *minfo = &info->tx_minfo; struct device *dev = info->dev; @@ -468,7 +551,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, tx_size > info->desc->max_msg_size) return -ERANGE; - xfer = scmi_xfer_get(handle, minfo); + xfer = scmi_xfer_get(pi->handle, minfo); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); dev_err(dev, "failed to get free message slot(%d)\n", ret); @@ -478,7 +561,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, xfer->tx.len = tx_size; xfer->rx.len = rx_size ? : info->desc->max_msg_size; xfer->hdr.id = msg_id; - xfer->hdr.protocol_id = prot_id; + xfer->hdr.protocol_id = pi->proto->id; xfer->hdr.poll_completion = false; *p = xfer; @@ -487,43 +570,276 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, } /** - * scmi_version_get() - command to get the revision of the SCMI entity + * version_get() - command to get the revision of the SCMI entity * - * @handle: Pointer to SCMI entity handle - * @protocol: Protocol identifier for the message + * @ph: Pointer to SCMI protocol handle * @version: Holds returned version of protocol. * * Updates the SCMI information in the internal data structure. * * Return: 0 if all went fine, else return appropriate error. */ -int scmi_version_get(const struct scmi_handle *handle, u8 protocol, - u32 *version) +static int version_get(const struct scmi_protocol_handle *ph, u32 *version) { int ret; __le32 *rev_info; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, PROTOCOL_VERSION, protocol, 0, - sizeof(*version), &t); + ret = xfer_get_init(ph, PROTOCOL_VERSION, 0, sizeof(*version), &t); if (ret) return ret; - ret = scmi_do_xfer(handle, t); + ret = do_xfer(ph, t); if (!ret) { rev_info = t->rx.buf; *version = le32_to_cpu(*rev_info); } - scmi_xfer_put(handle, t); + xfer_put(ph, t); return ret; } -void scmi_setup_protocol_implemented(const struct scmi_handle *handle, - u8 *prot_imp) +/** + * scmi_set_protocol_priv - Set protocol specific data at init time + * + * @ph: A reference to the protocol handle. + * @priv: The private data to set. + * + * Return: 0 on Success + */ +static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph, + void *priv) { + struct scmi_protocol_instance *pi = ph_to_pi(ph); + + pi->priv = priv; + + return 0; +} + +/** + * scmi_get_protocol_priv - Set protocol specific data at init time + * + * @ph: A reference to the protocol handle. + * + * Return: Protocol private data if any was set. + */ +static void *scmi_get_protocol_priv(const struct scmi_protocol_handle *ph) +{ + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + + return pi->priv; +} + +static const struct scmi_xfer_ops xfer_ops = { + .version_get = version_get, + .xfer_get_init = xfer_get_init, + .reset_rx_to_maxsz = reset_rx_to_maxsz, + .do_xfer = do_xfer, + .do_xfer_with_response = do_xfer_with_response, + .xfer_put = xfer_put, +}; + +/** + * scmi_revision_area_get - Retrieve version memory area. + * + * @ph: A reference to the protocol handle. + * + * A helper to grab the version memory area reference during SCMI Base protocol + * initialization. + * + * Return: A reference to the version memory area associated to the SCMI + * instance underlying this protocol handle. + */ +struct scmi_revision_info * +scmi_revision_area_get(const struct scmi_protocol_handle *ph) +{ + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + + return pi->handle->version; +} + +/** + * scmi_alloc_init_protocol_instance - Allocate and initialize a protocol + * instance descriptor. + * @info: The reference to the related SCMI instance. + * @proto: The protocol descriptor. + * + * Allocate a new protocol instance descriptor, using the provided @proto + * description, against the specified SCMI instance @info, and initialize it; + * all resources management is handled via a dedicated per-protocol devres + * group. + * + * Context: Assumes to be called with @protocols_mtx already acquired. + * Return: A reference to a freshly allocated and initialized protocol instance + * or ERR_PTR on failure. On failure the @proto reference is at first + * put using @scmi_protocol_put() before releasing all the devres group. + */ +static struct scmi_protocol_instance * +scmi_alloc_init_protocol_instance(struct scmi_info *info, + const struct scmi_protocol *proto) +{ + int ret = -ENOMEM; + void *gid; + struct scmi_protocol_instance *pi; + const struct scmi_handle *handle = &info->handle; + + /* Protocol specific devres group */ + gid = devres_open_group(handle->dev, NULL, GFP_KERNEL); + if (!gid) { + scmi_protocol_put(proto->id); + goto out; + } + + pi = devm_kzalloc(handle->dev, sizeof(*pi), GFP_KERNEL); + if (!pi) + goto clean; + + pi->gid = gid; + pi->proto = proto; + pi->handle = handle; + pi->ph.dev = handle->dev; + pi->ph.xops = &xfer_ops; + pi->ph.set_priv = scmi_set_protocol_priv; + pi->ph.get_priv = scmi_get_protocol_priv; + refcount_set(&pi->users, 1); + /* proto->init is assured NON NULL by scmi_protocol_register */ + ret = pi->proto->instance_init(&pi->ph); + if (ret) + goto clean; + + ret = idr_alloc(&info->protocols, pi, proto->id, proto->id + 1, + GFP_KERNEL); + if (ret != proto->id) + goto clean; + + /* + * Warn but ignore events registration errors since we do not want + * to skip whole protocols if their notifications are messed up. + */ + if (pi->proto->events) { + ret = scmi_register_protocol_events(handle, pi->proto->id, + &pi->ph, + pi->proto->events); + if (ret) + dev_warn(handle->dev, + "Protocol:%X - Events Registration Failed - err:%d\n", + pi->proto->id, ret); + } + + devres_close_group(handle->dev, pi->gid); + dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id); + + return pi; + +clean: + /* Take care to put the protocol module's owner before releasing all */ + scmi_protocol_put(proto->id); + devres_release_group(handle->dev, gid); +out: + return ERR_PTR(ret); +} + +/** + * scmi_get_protocol_instance - Protocol initialization helper. + * @handle: A reference to the SCMI platform instance. + * @protocol_id: The protocol being requested. + * + * In case the required protocol has never been requested before for this + * instance, allocate and initialize all the needed structures while handling + * resource allocation with a dedicated per-protocol devres subgroup. + * + * Return: A reference to an initialized protocol instance or error on failure: + * in particular returns -EPROBE_DEFER when the desired protocol could + * NOT be found. + */ +static struct scmi_protocol_instance * __must_check +scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id) +{ + struct scmi_protocol_instance *pi; struct scmi_info *info = handle_to_scmi_info(handle); + mutex_lock(&info->protocols_mtx); + pi = idr_find(&info->protocols, protocol_id); + + if (pi) { + refcount_inc(&pi->users); + } else { + const struct scmi_protocol *proto; + + /* Fails if protocol not registered on bus */ + proto = scmi_protocol_get(protocol_id); + if (proto) + pi = scmi_alloc_init_protocol_instance(info, proto); + else + pi = ERR_PTR(-EPROBE_DEFER); + } + mutex_unlock(&info->protocols_mtx); + + return pi; +} + +/** + * scmi_protocol_acquire - Protocol acquire + * @handle: A reference to the SCMI platform instance. + * @protocol_id: The protocol being requested. + * + * Register a new user for the requested protocol on the specified SCMI + * platform instance, possibly triggering its initialization on first user. + * + * Return: 0 if protocol was acquired successfully. + */ +int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id) +{ + return PTR_ERR_OR_ZERO(scmi_get_protocol_instance(handle, protocol_id)); +} + +/** + * scmi_protocol_release - Protocol de-initialization helper. + * @handle: A reference to the SCMI platform instance. + * @protocol_id: The protocol being requested. + * + * Remove one user for the specified protocol and triggers de-initialization + * and resources de-allocation once the last user has gone. + */ +void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + struct scmi_protocol_instance *pi; + + mutex_lock(&info->protocols_mtx); + pi = idr_find(&info->protocols, protocol_id); + if (WARN_ON(!pi)) + goto out; + + if (refcount_dec_and_test(&pi->users)) { + void *gid = pi->gid; + + if (pi->proto->events) + scmi_deregister_protocol_events(handle, protocol_id); + + if (pi->proto->instance_deinit) + pi->proto->instance_deinit(&pi->ph); + + idr_remove(&info->protocols, protocol_id); + + scmi_protocol_put(protocol_id); + + devres_release_group(handle->dev, gid); + dev_dbg(handle->dev, "De-Initialized protocol: 0x%X\n", + protocol_id); + } + +out: + mutex_unlock(&info->protocols_mtx); +} + +void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph, + u8 *prot_imp) +{ + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + struct scmi_info *info = handle_to_scmi_info(pi->handle); + info->protocols_imp = prot_imp; } @@ -542,6 +858,102 @@ scmi_is_protocol_implemented(const struct scmi_handle *handle, u8 prot_id) return false; } +struct scmi_protocol_devres { + const struct scmi_handle *handle; + u8 protocol_id; +}; + +static void scmi_devm_release_protocol(struct device *dev, void *res) +{ + struct scmi_protocol_devres *dres = res; + + scmi_protocol_release(dres->handle, dres->protocol_id); +} + +/** + * scmi_devm_protocol_get - Devres managed get protocol operations and handle + * @sdev: A reference to an scmi_device whose embedded struct device is to + * be used for devres accounting. + * @protocol_id: The protocol being requested. + * @ph: A pointer reference used to pass back the associated protocol handle. + * + * Get hold of a protocol accounting for its usage, eventually triggering its + * initialization, and returning the protocol specific operations and related + * protocol handle which will be used as first argument in most of the + * protocols operations methods. + * Being a devres based managed method, protocol hold will be automatically + * released, and possibly de-initialized on last user, once the SCMI driver + * owning the scmi_device is unbound from it. + * + * Return: A reference to the requested protocol operations or error. + * Must be checked for errors by caller. + */ +static const void __must_check * +scmi_devm_protocol_get(struct scmi_device *sdev, u8 protocol_id, + struct scmi_protocol_handle **ph) +{ + struct scmi_protocol_instance *pi; + struct scmi_protocol_devres *dres; + struct scmi_handle *handle = sdev->handle; + + if (!ph) + return ERR_PTR(-EINVAL); + + dres = devres_alloc(scmi_devm_release_protocol, + sizeof(*dres), GFP_KERNEL); + if (!dres) + return ERR_PTR(-ENOMEM); + + pi = scmi_get_protocol_instance(handle, protocol_id); + if (IS_ERR(pi)) { + devres_free(dres); + return pi; + } + + dres->handle = handle; + dres->protocol_id = protocol_id; + devres_add(&sdev->dev, dres); + + *ph = &pi->ph; + + return pi->proto->ops; +} + +static int scmi_devm_protocol_match(struct device *dev, void *res, void *data) +{ + struct scmi_protocol_devres *dres = res; + + if (WARN_ON(!dres || !data)) + return 0; + + return dres->protocol_id == *((u8 *)data); +} + +/** + * scmi_devm_protocol_put - Devres managed put protocol operations and handle + * @sdev: A reference to an scmi_device whose embedded struct device is to + * be used for devres accounting. + * @protocol_id: The protocol being requested. + * + * Explicitly release a protocol hold previously obtained calling the above + * @scmi_devm_protocol_get. + */ +static void scmi_devm_protocol_put(struct scmi_device *sdev, u8 protocol_id) +{ + int ret; + + ret = devres_release(&sdev->dev, scmi_devm_release_protocol, + scmi_devm_protocol_match, &protocol_id); + WARN_ON(ret); +} + +static inline +struct scmi_handle *scmi_handle_get_from_info_unlocked(struct scmi_info *info) +{ + info->users++; + return &info->handle; +} + /** * scmi_handle_get() - Get the SCMI handle for a device * @@ -563,8 +975,7 @@ struct scmi_handle *scmi_handle_get(struct device *dev) list_for_each(p, &scmi_list) { info = list_entry(p, struct scmi_info, node); if (dev->parent == info->dev) { - handle = &info->handle; - info->users++; + handle = scmi_handle_get_from_info_unlocked(info); break; } } @@ -707,63 +1118,268 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id) return ret; } -static inline void -scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, - int prot_id, const char *name) +/** + * scmi_get_protocol_device - Helper to get/create an SCMI device. + * + * @np: A device node representing a valid active protocols for the referred + * SCMI instance. + * @info: The referred SCMI instance for which we are getting/creating this + * device. + * @prot_id: The protocol ID. + * @name: The device name. + * + * Referring to the specific SCMI instance identified by @info, this helper + * takes care to return a properly initialized device matching the requested + * @proto_id and @name: if device was still not existent it is created as a + * child of the specified SCMI instance @info and its transport properly + * initialized as usual. + */ +static inline struct scmi_device * +scmi_get_protocol_device(struct device_node *np, struct scmi_info *info, + int prot_id, const char *name) { struct scmi_device *sdev; + /* Already created for this parent SCMI instance ? */ + sdev = scmi_child_dev_find(info->dev, prot_id, name); + if (sdev) + return sdev; + + pr_debug("Creating SCMI device (%s) for protocol %x\n", name, prot_id); + sdev = scmi_device_create(np, info->dev, prot_id, name); if (!sdev) { dev_err(info->dev, "failed to create %d protocol device\n", prot_id); - return; + return NULL; } if (scmi_txrx_setup(info, &sdev->dev, prot_id)) { dev_err(&sdev->dev, "failed to setup transport\n"); scmi_device_destroy(sdev); - return; + return NULL; } + return sdev; +} + +static inline void +scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, + int prot_id, const char *name) +{ + struct scmi_device *sdev; + + sdev = scmi_get_protocol_device(np, info, prot_id, name); + if (!sdev) + return; + /* setup handle now as the transport is ready */ scmi_set_handle(sdev); } -#define MAX_SCMI_DEV_PER_PROTOCOL 2 -struct scmi_prot_devnames { - int protocol_id; - char *names[MAX_SCMI_DEV_PER_PROTOCOL]; -}; +/** + * scmi_create_protocol_devices - Create devices for all pending requests for + * this SCMI instance. + * + * @np: The device node describing the protocol + * @info: The SCMI instance descriptor + * @prot_id: The protocol ID + * + * All devices previously requested for this instance (if any) are found and + * created by scanning the proper @&scmi_requested_devices entry. + */ +static void scmi_create_protocol_devices(struct device_node *np, + struct scmi_info *info, int prot_id) +{ + struct list_head *phead; -static struct scmi_prot_devnames devnames[] = { - { SCMI_PROTOCOL_POWER, { "genpd" },}, - { SCMI_PROTOCOL_SYSTEM, { "syspower" },}, - { SCMI_PROTOCOL_PERF, { "cpufreq" },}, - { SCMI_PROTOCOL_CLOCK, { "clocks" },}, - { SCMI_PROTOCOL_SENSOR, { "hwmon" },}, - { SCMI_PROTOCOL_RESET, { "reset" },}, - { SCMI_PROTOCOL_VOLTAGE, { "regulator" },}, -}; + mutex_lock(&scmi_requested_devices_mtx); + phead = idr_find(&scmi_requested_devices, prot_id); + if (phead) { + struct scmi_requested_dev *rdev; -static inline void -scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info, - int prot_id) + list_for_each_entry(rdev, phead, node) + scmi_create_protocol_device(np, info, prot_id, + rdev->id_table->name); + } + mutex_unlock(&scmi_requested_devices_mtx); +} + +/** + * scmi_protocol_device_request - Helper to request a device + * + * @id_table: A protocol/name pair descriptor for the device to be created. + * + * This helper let an SCMI driver request specific devices identified by the + * @id_table to be created for each active SCMI instance. + * + * The requested device name MUST NOT be already existent for any protocol; + * at first the freshly requested @id_table is annotated in the IDR table + * @scmi_requested_devices, then a matching device is created for each already + * active SCMI instance. (if any) + * + * This way the requested device is created straight-away for all the already + * initialized(probed) SCMI instances (handles) and it remains also annotated + * as pending creation if the requesting SCMI driver was loaded before some + * SCMI instance and related transports were available: when such late instance + * is probed, its probe will take care to scan the list of pending requested + * devices and create those on its own (see @scmi_create_protocol_devices and + * its enclosing loop) + * + * Return: 0 on Success + */ +int scmi_protocol_device_request(const struct scmi_device_id *id_table) { - int loop, cnt; + int ret = 0; + unsigned int id = 0; + struct list_head *head, *phead = NULL; + struct scmi_requested_dev *rdev; + struct scmi_info *info; - for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) { - if (devnames[loop].protocol_id != prot_id) - continue; + pr_debug("Requesting SCMI device (%s) for protocol %x\n", + id_table->name, id_table->protocol_id); - for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) { - const char *name = devnames[loop].names[cnt]; + /* + * Search for the matching protocol rdev list and then search + * of any existent equally named device...fails if any duplicate found. + */ + mutex_lock(&scmi_requested_devices_mtx); + idr_for_each_entry(&scmi_requested_devices, head, id) { + if (!phead) { + /* A list found registered in the IDR is never empty */ + rdev = list_first_entry(head, struct scmi_requested_dev, + node); + if (rdev->id_table->protocol_id == + id_table->protocol_id) + phead = head; + } + list_for_each_entry(rdev, head, node) { + if (!strcmp(rdev->id_table->name, id_table->name)) { + pr_err("Ignoring duplicate request [%d] %s\n", + rdev->id_table->protocol_id, + rdev->id_table->name); + ret = -EINVAL; + goto out; + } + } + } + + /* + * No duplicate found for requested id_table, so let's create a new + * requested device entry for this new valid request. + */ + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + ret = -ENOMEM; + goto out; + } + rdev->id_table = id_table; - if (name) - scmi_create_protocol_device(np, info, prot_id, - name); + /* + * Append the new requested device table descriptor to the head of the + * related protocol list, eventually creating such head if not already + * there. + */ + if (!phead) { + phead = kzalloc(sizeof(*phead), GFP_KERNEL); + if (!phead) { + kfree(rdev); + ret = -ENOMEM; + goto out; + } + INIT_LIST_HEAD(phead); + + ret = idr_alloc(&scmi_requested_devices, (void *)phead, + id_table->protocol_id, + id_table->protocol_id + 1, GFP_KERNEL); + if (ret != id_table->protocol_id) { + pr_err("Failed to save SCMI device - ret:%d\n", ret); + kfree(rdev); + kfree(phead); + ret = -EINVAL; + goto out; } + ret = 0; } + list_add(&rdev->node, phead); + + /* + * Now effectively create and initialize the requested device for every + * already initialized SCMI instance which has registered the requested + * protocol as a valid active one: i.e. defined in DT and supported by + * current platform FW. + */ + mutex_lock(&scmi_list_mutex); + list_for_each_entry(info, &scmi_list, node) { + struct device_node *child; + + child = idr_find(&info->active_protocols, + id_table->protocol_id); + if (child) { + struct scmi_device *sdev; + + sdev = scmi_get_protocol_device(child, info, + id_table->protocol_id, + id_table->name); + /* Set handle if not already set: device existed */ + if (sdev && !sdev->handle) + sdev->handle = + scmi_handle_get_from_info_unlocked(info); + } else { + dev_err(info->dev, + "Failed. SCMI protocol %d not active.\n", + id_table->protocol_id); + } + } + mutex_unlock(&scmi_list_mutex); + +out: + mutex_unlock(&scmi_requested_devices_mtx); + + return ret; +} + +/** + * scmi_protocol_device_unrequest - Helper to unrequest a device + * + * @id_table: A protocol/name pair descriptor for the device to be unrequested. + * + * An helper to let an SCMI driver release its request about devices; note that + * devices are created and initialized once the first SCMI driver request them + * but they destroyed only on SCMI core unloading/unbinding. + * + * The current SCMI transport layer uses such devices as internal references and + * as such they could be shared as same transport between multiple drivers so + * that cannot be safely destroyed till the whole SCMI stack is removed. + * (unless adding further burden of refcounting.) + */ +void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table) +{ + struct list_head *phead; + + pr_debug("Unrequesting SCMI device (%s) for protocol %x\n", + id_table->name, id_table->protocol_id); + + mutex_lock(&scmi_requested_devices_mtx); + phead = idr_find(&scmi_requested_devices, id_table->protocol_id); + if (phead) { + struct scmi_requested_dev *victim, *tmp; + + list_for_each_entry_safe(victim, tmp, phead, node) { + if (!strcmp(victim->id_table->name, id_table->name)) { + list_del(&victim->node); + kfree(victim); + break; + } + } + + if (list_empty(phead)) { + idr_remove(&scmi_requested_devices, + id_table->protocol_id); + kfree(phead); + } + } + mutex_unlock(&scmi_requested_devices_mtx); } static int scmi_probe(struct platform_device *pdev) @@ -786,6 +1402,9 @@ static int scmi_probe(struct platform_device *pdev) info->dev = dev; info->desc = desc; INIT_LIST_HEAD(&info->node); + idr_init(&info->protocols); + mutex_init(&info->protocols_mtx); + idr_init(&info->active_protocols); platform_set_drvdata(pdev, info); idr_init(&info->tx_idr); @@ -794,6 +1413,8 @@ static int scmi_probe(struct platform_device *pdev) handle = &info->handle; handle->dev = info->dev; handle->version = &info->version; + handle->devm_protocol_get = scmi_devm_protocol_get; + handle->devm_protocol_put = scmi_devm_protocol_put; ret = scmi_txrx_setup(info, dev, SCMI_PROTOCOL_BASE); if (ret) @@ -806,9 +1427,14 @@ static int scmi_probe(struct platform_device *pdev) if (scmi_notification_init(handle)) dev_err(dev, "SCMI Notifications NOT available.\n"); - ret = scmi_base_protocol_init(handle); + /* + * Trigger SCMI Base protocol initialization. + * It's mandatory and won't be ever released/deinit until the + * SCMI stack is shutdown/unloaded as a whole. + */ + ret = scmi_protocol_acquire(handle, SCMI_PROTOCOL_BASE); if (ret) { - dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); + dev_err(dev, "unable to communicate with SCMI\n"); return ret; } @@ -831,6 +1457,19 @@ static int scmi_probe(struct platform_device *pdev) continue; } + /* + * Save this valid DT protocol descriptor amongst + * @active_protocols for this SCMI instance/ + */ + ret = idr_alloc(&info->active_protocols, child, + prot_id, prot_id + 1, GFP_KERNEL); + if (ret != prot_id) { + dev_err(dev, "SCMI protocol %d already activated. Skip\n", + prot_id); + continue; + } + + of_node_get(child); scmi_create_protocol_devices(child, info, prot_id); } @@ -844,9 +1483,10 @@ void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id) static int scmi_remove(struct platform_device *pdev) { - int ret = 0; + int ret = 0, id; struct scmi_info *info = platform_get_drvdata(pdev); struct idr *idr = &info->tx_idr; + struct device_node *child; mutex_lock(&scmi_list_mutex); if (info->users) @@ -860,6 +1500,14 @@ static int scmi_remove(struct platform_device *pdev) scmi_notification_exit(&info->handle); + mutex_lock(&info->protocols_mtx); + idr_destroy(&info->protocols); + mutex_unlock(&info->protocols_mtx); + + idr_for_each_entry(&info->active_protocols, child, id) + of_node_put(child); + idr_destroy(&info->active_protocols); + /* Safe to free channels since no more users */ ret = idr_for_each(idr, info->desc->ops->chan_free, idr); idr_destroy(&info->tx_idr); @@ -942,6 +1590,8 @@ static int __init scmi_driver_init(void) { scmi_bus_init(); + scmi_base_register(); + scmi_clock_register(); scmi_perf_register(); scmi_power_register(); @@ -956,7 +1606,7 @@ subsys_initcall(scmi_driver_init); static void __exit scmi_driver_exit(void) { - scmi_bus_exit(); + scmi_base_unregister(); scmi_clock_unregister(); scmi_perf_unregister(); @@ -966,6 +1616,8 @@ static void __exit scmi_driver_exit(void) scmi_voltage_unregister(); scmi_system_unregister(); + scmi_bus_exit(); + platform_driver_unregister(&scmi_driver); } module_exit(scmi_driver_exit); diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index 66196b293b6c2a60d580f437ad8b0a15994fdc26..d860bebd984a3d8c62a5479e90b0b90de56c42ff 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -2,7 +2,7 @@ /* * System Control and Management Interface (SCMI) Notification support * - * Copyright (C) 2020 ARM Ltd. + * Copyright (C) 2020-2021 ARM Ltd. */ /** * DOC: Theory of operation @@ -91,6 +91,7 @@ #include <linux/types.h> #include <linux/workqueue.h> +#include "common.h" #include "notify.h" #define SCMI_MAX_PROTO 256 @@ -177,7 +178,7 @@ #define REVT_NOTIFY_SET_STATUS(revt, eid, sid, state) \ ({ \ typeof(revt) r = revt; \ - r->proto->ops->set_notify_enabled(r->proto->ni->handle, \ + r->proto->ops->set_notify_enabled(r->proto->ph, \ (eid), (sid), (state)); \ }) @@ -190,7 +191,7 @@ #define REVT_FILL_REPORT(revt, ...) \ ({ \ typeof(revt) r = revt; \ - r->proto->ops->fill_custom_report(r->proto->ni->handle, \ + r->proto->ops->fill_custom_report(r->proto->ph, \ __VA_ARGS__); \ }) @@ -278,6 +279,7 @@ struct scmi_registered_event; * events' descriptors, whose fixed-size is determined at * compile time. * @registered_mtx: A mutex to protect @registered_events_handlers + * @ph: SCMI protocol handle reference * @registered_events_handlers: An hashtable containing all events' handlers * descriptors registered for this protocol * @@ -302,6 +304,7 @@ struct scmi_registered_events_desc { struct scmi_registered_event **registered_events; /* mutex to protect registered_events_handlers */ struct mutex registered_mtx; + const struct scmi_protocol_handle *ph; DECLARE_HASHTABLE(registered_events_handlers, SCMI_REGISTERED_HASH_SZ); }; @@ -368,7 +371,7 @@ static struct scmi_event_handler * scmi_get_active_handler(struct scmi_notify_instance *ni, u32 evt_key); static void scmi_put_active_handler(struct scmi_notify_instance *ni, struct scmi_event_handler *hndl); -static void scmi_put_handler_unlocked(struct scmi_notify_instance *ni, +static bool scmi_put_handler_unlocked(struct scmi_notify_instance *ni, struct scmi_event_handler *hndl); /** @@ -579,11 +582,9 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id, struct scmi_event_header eh; struct scmi_notify_instance *ni; - /* Ensure notify_priv is updated */ - smp_rmb(); - if (!handle->notify_priv) + ni = scmi_notification_instance_data_get(handle); + if (!ni) return 0; - ni = handle->notify_priv; r_evt = SCMI_GET_REVT(ni, proto_id, evt_id); if (!r_evt) @@ -732,14 +733,10 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni, /** * scmi_register_protocol_events() - Register Protocol Events with the core * @handle: The handle identifying the platform instance against which the - * the protocol's events are registered + * protocol's events are registered * @proto_id: Protocol ID - * @queue_sz: Size in bytes of the associated queue to be allocated - * @ops: Protocol specific event-related operations - * @evt: Event descriptor array - * @num_events: Number of events in @evt array - * @num_sources: Number of possible sources for this protocol on this - * platform. + * @ph: SCMI protocol handle. + * @ee: A structure describing the events supported by this protocol. * * Used by SCMI Protocols initialization code to register with the notification * core the list of supported events and their descriptors: takes care to @@ -748,60 +745,69 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni, * * Return: 0 on Success */ -int scmi_register_protocol_events(const struct scmi_handle *handle, - u8 proto_id, size_t queue_sz, - const struct scmi_event_ops *ops, - const struct scmi_event *evt, int num_events, - int num_sources) +int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, + const struct scmi_protocol_handle *ph, + const struct scmi_protocol_events *ee) { int i; + unsigned int num_sources; size_t payld_sz = 0; struct scmi_registered_events_desc *pd; struct scmi_notify_instance *ni; + const struct scmi_event *evt; - if (!ops || !evt) + if (!ee || !ee->ops || !ee->evts || !ph || + (!ee->num_sources && !ee->ops->get_num_sources)) return -EINVAL; - /* Ensure notify_priv is updated */ - smp_rmb(); - if (!handle->notify_priv) + ni = scmi_notification_instance_data_get(handle); + if (!ni) return -ENOMEM; - ni = handle->notify_priv; - /* Attach to the notification main devres group */ - if (!devres_open_group(ni->handle->dev, ni->gid, GFP_KERNEL)) - return -ENOMEM; + /* num_sources cannot be <= 0 */ + if (ee->num_sources) { + num_sources = ee->num_sources; + } else { + int nsrc = ee->ops->get_num_sources(ph); - for (i = 0; i < num_events; i++) + if (nsrc <= 0) + return -EINVAL; + num_sources = nsrc; + } + + evt = ee->evts; + for (i = 0; i < ee->num_events; i++) payld_sz = max_t(size_t, payld_sz, evt[i].max_payld_sz); payld_sz += sizeof(struct scmi_event_header); - pd = scmi_allocate_registered_events_desc(ni, proto_id, queue_sz, - payld_sz, num_events, ops); + pd = scmi_allocate_registered_events_desc(ni, proto_id, ee->queue_sz, + payld_sz, ee->num_events, + ee->ops); if (IS_ERR(pd)) - goto err; + return PTR_ERR(pd); - for (i = 0; i < num_events; i++, evt++) { + pd->ph = ph; + for (i = 0; i < ee->num_events; i++, evt++) { struct scmi_registered_event *r_evt; r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt), GFP_KERNEL); if (!r_evt) - goto err; + return -ENOMEM; r_evt->proto = pd; r_evt->evt = evt; r_evt->sources = devm_kcalloc(ni->handle->dev, num_sources, sizeof(refcount_t), GFP_KERNEL); if (!r_evt->sources) - goto err; + return -ENOMEM; r_evt->num_sources = num_sources; mutex_init(&r_evt->sources_mtx); r_evt->report = devm_kzalloc(ni->handle->dev, evt->max_report_sz, GFP_KERNEL); if (!r_evt->report) - goto err; + return -ENOMEM; pd->registered_events[i] = r_evt; /* Ensure events are updated */ @@ -815,8 +821,6 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, /* Ensure protocols are updated */ smp_wmb(); - devres_close_group(ni->handle->dev, ni->gid); - /* * Finalize any pending events' handler which could have been waiting * for this protocol's events registration. @@ -824,13 +828,33 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, schedule_work(&ni->init_work); return 0; +} -err: - dev_warn(handle->dev, "Proto:%X - Registration Failed !\n", proto_id); - /* A failing protocol registration does not trigger full failure */ - devres_close_group(ni->handle->dev, ni->gid); +/** + * scmi_deregister_protocol_events - Deregister protocol events with the core + * @handle: The handle identifying the platform instance against which the + * protocol's events are registered + * @proto_id: Protocol ID + */ +void scmi_deregister_protocol_events(const struct scmi_handle *handle, + u8 proto_id) +{ + struct scmi_notify_instance *ni; + struct scmi_registered_events_desc *pd; - return -ENOMEM; + ni = scmi_notification_instance_data_get(handle); + if (!ni) + return; + + pd = ni->registered_protocols[proto_id]; + if (!pd) + return; + + ni->registered_protocols[proto_id] = NULL; + /* Ensure protocols are updated */ + smp_wmb(); + + cancel_work_sync(&pd->equeue.notify_work); } /** @@ -900,9 +924,21 @@ static inline int scmi_bind_event_handler(struct scmi_notify_instance *ni, if (!r_evt) return -EINVAL; - /* Remove from pending and insert into registered */ + /* + * Remove from pending and insert into registered while getting hold + * of protocol instance. + */ hash_del(&hndl->hash); + /* + * Acquire protocols only for NON pending handlers, so as NOT to trigger + * protocol initialization when a notifier is registered against a still + * not registered protocol, since it would make little sense to force init + * protocols for which still no SCMI driver user exists: they wouldn't + * emit any event anyway till some SCMI driver starts using it. + */ + scmi_protocol_acquire(ni->handle, KEY_XTRACT_PROTO_ID(hndl->key)); hndl->r_evt = r_evt; + mutex_lock(&r_evt->proto->registered_mtx); hash_add(r_evt->proto->registered_events_handlers, &hndl->hash, hndl->key); @@ -1193,41 +1229,65 @@ static int scmi_disable_events(struct scmi_event_handler *hndl) * * unregister and free the handler itself * * Context: Assumes all the proper locking has been managed by the caller. + * + * Return: True if handler was freed (users dropped to zero) */ -static void scmi_put_handler_unlocked(struct scmi_notify_instance *ni, +static bool scmi_put_handler_unlocked(struct scmi_notify_instance *ni, struct scmi_event_handler *hndl) { + bool freed = false; + if (refcount_dec_and_test(&hndl->users)) { if (!IS_HNDL_PENDING(hndl)) scmi_disable_events(hndl); scmi_free_event_handler(hndl); + freed = true; } + + return freed; } static void scmi_put_handler(struct scmi_notify_instance *ni, struct scmi_event_handler *hndl) { + bool freed; + u8 protocol_id; struct scmi_registered_event *r_evt = hndl->r_evt; mutex_lock(&ni->pending_mtx); - if (r_evt) + if (r_evt) { + protocol_id = r_evt->proto->id; mutex_lock(&r_evt->proto->registered_mtx); + } - scmi_put_handler_unlocked(ni, hndl); + freed = scmi_put_handler_unlocked(ni, hndl); - if (r_evt) + if (r_evt) { mutex_unlock(&r_evt->proto->registered_mtx); + /* + * Only registered handler acquired protocol; must be here + * released only AFTER unlocking registered_mtx, since + * releasing a protocol can trigger its de-initialization + * (ie. including r_evt and registered_mtx) + */ + if (freed) + scmi_protocol_release(ni->handle, protocol_id); + } mutex_unlock(&ni->pending_mtx); } static void scmi_put_active_handler(struct scmi_notify_instance *ni, struct scmi_event_handler *hndl) { + bool freed; struct scmi_registered_event *r_evt = hndl->r_evt; + u8 protocol_id = r_evt->proto->id; mutex_lock(&r_evt->proto->registered_mtx); - scmi_put_handler_unlocked(ni, hndl); + freed = scmi_put_handler_unlocked(ni, hndl); mutex_unlock(&r_evt->proto->registered_mtx); + if (freed) + scmi_protocol_release(ni->handle, protocol_id); } /** @@ -1247,7 +1307,7 @@ static int scmi_event_handler_enable_events(struct scmi_event_handler *hndl) } /** - * scmi_register_notifier() - Register a notifier_block for an event + * scmi_notifier_register() - Register a notifier_block for an event * @handle: The handle identifying the platform instance against which the * callback is registered * @proto_id: Protocol ID @@ -1279,8 +1339,8 @@ static int scmi_event_handler_enable_events(struct scmi_event_handler *hndl) * * Return: 0 on Success */ -static int scmi_register_notifier(const struct scmi_handle *handle, - u8 proto_id, u8 evt_id, u32 *src_id, +static int scmi_notifier_register(const struct scmi_handle *handle, + u8 proto_id, u8 evt_id, const u32 *src_id, struct notifier_block *nb) { int ret = 0; @@ -1288,11 +1348,9 @@ static int scmi_register_notifier(const struct scmi_handle *handle, struct scmi_event_handler *hndl; struct scmi_notify_instance *ni; - /* Ensure notify_priv is updated */ - smp_rmb(); - if (!handle->notify_priv) + ni = scmi_notification_instance_data_get(handle); + if (!ni) return -ENODEV; - ni = handle->notify_priv; evt_key = MAKE_HASH_KEY(proto_id, evt_id, src_id ? *src_id : SRC_ID_MASK); @@ -1313,7 +1371,7 @@ static int scmi_register_notifier(const struct scmi_handle *handle, } /** - * scmi_unregister_notifier() - Unregister a notifier_block for an event + * scmi_notifier_unregister() - Unregister a notifier_block for an event * @handle: The handle identifying the platform instance against which the * callback is unregistered * @proto_id: Protocol ID @@ -1328,19 +1386,17 @@ static int scmi_register_notifier(const struct scmi_handle *handle, * * Return: 0 on Success */ -static int scmi_unregister_notifier(const struct scmi_handle *handle, - u8 proto_id, u8 evt_id, u32 *src_id, +static int scmi_notifier_unregister(const struct scmi_handle *handle, + u8 proto_id, u8 evt_id, const u32 *src_id, struct notifier_block *nb) { u32 evt_key; struct scmi_event_handler *hndl; struct scmi_notify_instance *ni; - /* Ensure notify_priv is updated */ - smp_rmb(); - if (!handle->notify_priv) + ni = scmi_notification_instance_data_get(handle); + if (!ni) return -ENODEV; - ni = handle->notify_priv; evt_key = MAKE_HASH_KEY(proto_id, evt_id, src_id ? *src_id : SRC_ID_MASK); @@ -1356,7 +1412,7 @@ static int scmi_unregister_notifier(const struct scmi_handle *handle, scmi_put_handler(ni, hndl); /* - * This balances the initial get issued in @scmi_register_notifier. + * This balances the initial get issued in @scmi_notifier_register. * If this notifier_block happened to be the last known user callback * for this event, the handler is here freed and the event's generation * stopped. @@ -1371,6 +1427,129 @@ static int scmi_unregister_notifier(const struct scmi_handle *handle, return 0; } +struct scmi_notifier_devres { + const struct scmi_handle *handle; + u8 proto_id; + u8 evt_id; + u32 __src_id; + u32 *src_id; + struct notifier_block *nb; +}; + +static void scmi_devm_release_notifier(struct device *dev, void *res) +{ + struct scmi_notifier_devres *dres = res; + + scmi_notifier_unregister(dres->handle, dres->proto_id, dres->evt_id, + dres->src_id, dres->nb); +} + +/** + * scmi_devm_notifier_register() - Managed registration of a notifier_block + * for an event + * @sdev: A reference to an scmi_device whose embedded struct device is to + * be used for devres accounting. + * @proto_id: Protocol ID + * @evt_id: Event ID + * @src_id: Source ID, when NULL register for events coming form ALL possible + * sources + * @nb: A standard notifier block to register for the specified event + * + * Generic devres managed helper to register a notifier_block against a + * protocol event. + */ +static int scmi_devm_notifier_register(struct scmi_device *sdev, + u8 proto_id, u8 evt_id, + const u32 *src_id, + struct notifier_block *nb) +{ + int ret; + struct scmi_notifier_devres *dres; + + dres = devres_alloc(scmi_devm_release_notifier, + sizeof(*dres), GFP_KERNEL); + if (!dres) + return -ENOMEM; + + ret = scmi_notifier_register(sdev->handle, proto_id, + evt_id, src_id, nb); + if (ret) { + devres_free(dres); + return ret; + } + + dres->handle = sdev->handle; + dres->proto_id = proto_id; + dres->evt_id = evt_id; + dres->nb = nb; + if (src_id) { + dres->__src_id = *src_id; + dres->src_id = &dres->__src_id; + } else { + dres->src_id = NULL; + } + devres_add(&sdev->dev, dres); + + return ret; +} + +static int scmi_devm_notifier_match(struct device *dev, void *res, void *data) +{ + struct scmi_notifier_devres *dres = res; + struct scmi_notifier_devres *xres = data; + + if (WARN_ON(!dres || !xres)) + return 0; + + return dres->proto_id == xres->proto_id && + dres->evt_id == xres->evt_id && + dres->nb == xres->nb && + ((!dres->src_id && !xres->src_id) || + (dres->src_id && xres->src_id && + dres->__src_id == xres->__src_id)); +} + +/** + * scmi_devm_notifier_unregister() - Managed un-registration of a + * notifier_block for an event + * @sdev: A reference to an scmi_device whose embedded struct device is to + * be used for devres accounting. + * @proto_id: Protocol ID + * @evt_id: Event ID + * @src_id: Source ID, when NULL register for events coming form ALL possible + * sources + * @nb: A standard notifier block to register for the specified event + * + * Generic devres managed helper to explicitly un-register a notifier_block + * against a protocol event, which was previously registered using the above + * @scmi_devm_notifier_register. + */ +static int scmi_devm_notifier_unregister(struct scmi_device *sdev, + u8 proto_id, u8 evt_id, + const u32 *src_id, + struct notifier_block *nb) +{ + int ret; + struct scmi_notifier_devres dres; + + dres.handle = sdev->handle; + dres.proto_id = proto_id; + dres.evt_id = evt_id; + if (src_id) { + dres.__src_id = *src_id; + dres.src_id = &dres.__src_id; + } else { + dres.src_id = NULL; + } + + ret = devres_release(&sdev->dev, scmi_devm_release_notifier, + scmi_devm_notifier_match, &dres); + + WARN_ON(ret); + + return ret; +} + /** * scmi_protocols_late_init() - Worker for late initialization * @work: The work item to use associated to the proper SCMI instance @@ -1428,8 +1607,10 @@ static void scmi_protocols_late_init(struct work_struct *work) * directly from an scmi_driver to register its own notifiers. */ static const struct scmi_notify_ops notify_ops = { - .register_event_notifier = scmi_register_notifier, - .unregister_event_notifier = scmi_unregister_notifier, + .devm_event_notifier_register = scmi_devm_notifier_register, + .devm_event_notifier_unregister = scmi_devm_notifier_unregister, + .event_notifier_register = scmi_notifier_register, + .event_notifier_unregister = scmi_notifier_unregister, }; /** @@ -1490,8 +1671,8 @@ int scmi_notification_init(struct scmi_handle *handle) INIT_WORK(&ni->init_work, scmi_protocols_late_init); + scmi_notification_instance_data_set(handle, ni); handle->notify_ops = ¬ify_ops; - handle->notify_priv = ni; /* Ensure handle is up to date */ smp_wmb(); @@ -1503,7 +1684,7 @@ int scmi_notification_init(struct scmi_handle *handle) err: dev_warn(handle->dev, "Initialization Failed.\n"); - devres_release_group(handle->dev, NULL); + devres_release_group(handle->dev, gid); return -ENOMEM; } @@ -1515,15 +1696,10 @@ void scmi_notification_exit(struct scmi_handle *handle) { struct scmi_notify_instance *ni; - /* Ensure notify_priv is updated */ - smp_rmb(); - if (!handle->notify_priv) + ni = scmi_notification_instance_data_get(handle); + if (!ni) return; - ni = handle->notify_priv; - - handle->notify_priv = NULL; - /* Ensure handle is up to date */ - smp_wmb(); + scmi_notification_instance_data_set(handle, NULL); /* Destroy while letting pending work complete */ destroy_workqueue(ni->notify_wq); diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h index 3485f20fa70e113ddd881a215082f158b6c4c2a4..ce0324be6c71df9580a8e299d3214b5ea2cf6dc9 100644 --- a/drivers/firmware/arm_scmi/notify.h +++ b/drivers/firmware/arm_scmi/notify.h @@ -4,7 +4,7 @@ * notification header file containing some definitions, structures * and function prototypes related to SCMI Notification handling. * - * Copyright (C) 2020 ARM Ltd. + * Copyright (C) 2020-2021 ARM Ltd. */ #ifndef _SCMI_NOTIFY_H #define _SCMI_NOTIFY_H @@ -31,8 +31,12 @@ struct scmi_event { size_t max_report_sz; }; +struct scmi_protocol_handle; + /** * struct scmi_event_ops - Protocol helpers called by the notification core. + * @get_num_sources: Returns the number of possible events' sources for this + * protocol * @set_notify_enabled: Enable/disable the required evt_id/src_id notifications * using the proper custom protocol commands. * Return 0 on Success @@ -46,22 +50,42 @@ struct scmi_event { * process context. */ struct scmi_event_ops { - int (*set_notify_enabled)(const struct scmi_handle *handle, + int (*get_num_sources)(const struct scmi_protocol_handle *ph); + int (*set_notify_enabled)(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enabled); - void *(*fill_custom_report)(const struct scmi_handle *handle, + void *(*fill_custom_report)(const struct scmi_protocol_handle *ph, u8 evt_id, ktime_t timestamp, const void *payld, size_t payld_sz, void *report, u32 *src_id); }; +/** + * struct scmi_protocol_events - Per-protocol description of available events + * @queue_sz: Size in bytes of the per-protocol queue to use. + * @ops: Array of protocol-specific events operations. + * @evts: Array of supported protocol's events. + * @num_events: Number of supported protocol's events described in @evts. + * @num_sources: Number of protocol's sources, should be greater than 0; if not + * available at compile time, it will be provided at run-time via + * @get_num_sources. + */ +struct scmi_protocol_events { + size_t queue_sz; + const struct scmi_event_ops *ops; + const struct scmi_event *evts; + unsigned int num_events; + unsigned int num_sources; +}; + int scmi_notification_init(struct scmi_handle *handle); void scmi_notification_exit(struct scmi_handle *handle); -int scmi_register_protocol_events(const struct scmi_handle *handle, - u8 proto_id, size_t queue_sz, - const struct scmi_event_ops *ops, - const struct scmi_event *evt, int num_events, - int num_sources); +struct scmi_protocol_handle; +int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, + const struct scmi_protocol_handle *ph, + const struct scmi_protocol_events *ee); +void scmi_deregister_protocol_events(const struct scmi_handle *handle, + u8 proto_id); int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id, const void *buf, size_t len, ktime_t ts); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index e374b1125fcabd7765b22e605174af8deb6c0952..f4cd5193b9617f8ed70bd3d5fd10d24573130c96 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -2,7 +2,7 @@ /* * System Control and Management Interface (SCMI) Performance Protocol * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications PERF - " fmt @@ -11,6 +11,7 @@ #include <linux/of.h> #include <linux/io.h> #include <linux/io-64-nonatomic-hi-lo.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_opp.h> #include <linux/scmi_protocol.h> @@ -175,21 +176,21 @@ static enum scmi_performance_protocol_cmd evt_2_cmd[] = { PERF_NOTIFY_LEVEL, }; -static int scmi_perf_attributes_get(const struct scmi_handle *handle, +static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph, struct scmi_perf_info *pi) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_perf_attributes *attr; - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_PERF, 0, sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, + sizeof(*attr), &t); if (ret) return ret; attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { u16 flags = le16_to_cpu(attr->flags); @@ -200,28 +201,27 @@ static int scmi_perf_attributes_get(const struct scmi_handle *handle, pi->stats_size = le32_to_cpu(attr->stats_size); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static int -scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, - struct perf_dom_info *dom_info) +scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, + u32 domain, struct perf_dom_info *dom_info) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_perf_domain_attributes *attr; - ret = scmi_xfer_get_init(handle, PERF_DOMAIN_ATTRIBUTES, - SCMI_PROTOCOL_PERF, sizeof(domain), - sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, PERF_DOMAIN_ATTRIBUTES, + sizeof(domain), sizeof(*attr), &t); if (ret) return ret; put_unaligned_le32(domain, t->tx.buf); attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { u32 flags = le32_to_cpu(attr->flags); @@ -245,7 +245,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -257,7 +257,7 @@ static int opp_cmp_func(const void *opp1, const void *opp2) } static int -scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, +scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain, struct perf_dom_info *perf_dom) { int ret, cnt; @@ -268,8 +268,8 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, struct scmi_msg_perf_describe_levels *dom_info; struct scmi_msg_resp_perf_describe_levels *level_info; - ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_LEVELS, - SCMI_PROTOCOL_PERF, sizeof(*dom_info), 0, &t); + ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_LEVELS, + sizeof(*dom_info), 0, &t); if (ret) return ret; @@ -281,14 +281,14 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, /* Set the number of OPPs to be skipped/already read */ dom_info->level_index = cpu_to_le32(tot_opp_cnt); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (ret) break; num_returned = le16_to_cpu(level_info->num_returned); num_remaining = le16_to_cpu(level_info->num_remaining); if (tot_opp_cnt + num_returned > MAX_OPPS) { - dev_err(handle->dev, "No. of OPPs exceeded MAX_OPPS"); + dev_err(ph->dev, "No. of OPPs exceeded MAX_OPPS"); break; } @@ -299,13 +299,13 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, opp->trans_latency_us = le16_to_cpu (level_info->opp[cnt].transition_latency_us); - dev_dbg(handle->dev, "Level %d Power %d Latency %dus\n", + dev_dbg(ph->dev, "Level %d Power %d Latency %dus\n", opp->perf, opp->power, opp->trans_latency_us); } tot_opp_cnt += num_returned; - scmi_reset_rx_to_maxsz(handle, t); + ph->xops->reset_rx_to_maxsz(ph, t); /* * check for both returned and remaining to avoid infinite * loop due to buggy firmware @@ -313,7 +313,7 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, } while (num_returned && num_remaining); perf_dom->opp_count = tot_opp_cnt; - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL); return ret; @@ -353,15 +353,15 @@ static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db) #endif } -static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain, - u32 max_perf, u32 min_perf) +static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 max_perf, u32 min_perf) { int ret; struct scmi_xfer *t; struct scmi_perf_set_limits *limits; - ret = scmi_xfer_get_init(handle, PERF_LIMITS_SET, SCMI_PROTOCOL_PERF, - sizeof(*limits), 0, &t); + ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_SET, + sizeof(*limits), 0, &t); if (ret) return ret; @@ -370,16 +370,16 @@ static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain, limits->max_level = cpu_to_le32(max_perf); limits->min_level = cpu_to_le32(min_perf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, - u32 max_perf, u32 min_perf) +static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 max_perf, u32 min_perf) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom = pi->dom_info + domain; if (dom->fc_info && dom->fc_info->limit_set_addr) { @@ -389,24 +389,24 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, return 0; } - return scmi_perf_mb_limits_set(handle, domain, max_perf, min_perf); + return scmi_perf_mb_limits_set(ph, domain, max_perf, min_perf); } -static int scmi_perf_mb_limits_get(const struct scmi_handle *handle, u32 domain, - u32 *max_perf, u32 *min_perf) +static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *max_perf, u32 *min_perf) { int ret; struct scmi_xfer *t; struct scmi_perf_get_limits *limits; - ret = scmi_xfer_get_init(handle, PERF_LIMITS_GET, SCMI_PROTOCOL_PERF, - sizeof(__le32), 0, &t); + ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_GET, + sizeof(__le32), 0, &t); if (ret) return ret; put_unaligned_le32(domain, t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { limits = t->rx.buf; @@ -414,14 +414,14 @@ static int scmi_perf_mb_limits_get(const struct scmi_handle *handle, u32 domain, *min_perf = le32_to_cpu(limits->min_level); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, - u32 *max_perf, u32 *min_perf) +static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *max_perf, u32 *min_perf) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom = pi->dom_info + domain; if (dom->fc_info && dom->fc_info->limit_get_addr) { @@ -430,18 +430,17 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, return 0; } - return scmi_perf_mb_limits_get(handle, domain, max_perf, min_perf); + return scmi_perf_mb_limits_get(ph, domain, max_perf, min_perf); } -static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain, - u32 level, bool poll) +static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 level, bool poll) { int ret; struct scmi_xfer *t; struct scmi_perf_set_level *lvl; - ret = scmi_xfer_get_init(handle, PERF_LEVEL_SET, SCMI_PROTOCOL_PERF, - sizeof(*lvl), 0, &t); + ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_SET, sizeof(*lvl), 0, &t); if (ret) return ret; @@ -450,16 +449,16 @@ static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain, lvl->domain = cpu_to_le32(domain); lvl->level = cpu_to_le32(level); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, - u32 level, bool poll) +static int scmi_perf_level_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 level, bool poll) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom = pi->dom_info + domain; if (dom->fc_info && dom->fc_info->level_set_addr) { @@ -468,35 +467,35 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, return 0; } - return scmi_perf_mb_level_set(handle, domain, level, poll); + return scmi_perf_mb_level_set(ph, domain, level, poll); } -static int scmi_perf_mb_level_get(const struct scmi_handle *handle, u32 domain, - u32 *level, bool poll) +static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *level, bool poll) { int ret; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, PERF_LEVEL_GET, SCMI_PROTOCOL_PERF, - sizeof(u32), sizeof(u32), &t); + ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_GET, + sizeof(u32), sizeof(u32), &t); if (ret) return ret; t->hdr.poll_completion = poll; put_unaligned_le32(domain, t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) *level = get_unaligned_le32(t->rx.buf); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, - u32 *level, bool poll) +static int scmi_perf_level_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *level, bool poll) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom = pi->dom_info + domain; if (dom->fc_info && dom->fc_info->level_get_addr) { @@ -504,10 +503,10 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, return 0; } - return scmi_perf_mb_level_get(handle, domain, level, poll); + return scmi_perf_mb_level_get(ph, domain, level, poll); } -static int scmi_perf_level_limits_notify(const struct scmi_handle *handle, +static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph, u32 domain, int message_id, bool enable) { @@ -515,8 +514,7 @@ static int scmi_perf_level_limits_notify(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_perf_notify_level_or_limits *notify; - ret = scmi_xfer_get_init(handle, message_id, SCMI_PROTOCOL_PERF, - sizeof(*notify), 0, &t); + ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t); if (ret) return ret; @@ -524,9 +522,9 @@ static int scmi_perf_level_limits_notify(const struct scmi_handle *handle, notify->domain = cpu_to_le32(domain); notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -540,7 +538,7 @@ static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size) } static void -scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain, +scmi_perf_domain_desc_fc(const struct scmi_protocol_handle *ph, u32 domain, u32 message_id, void __iomem **p_addr, struct scmi_fc_db_info **p_db) { @@ -557,9 +555,8 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain, if (!p_addr) return; - ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_FASTCHANNEL, - SCMI_PROTOCOL_PERF, - sizeof(*info), sizeof(*resp), &t); + ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL, + sizeof(*info), sizeof(*resp), &t); if (ret) return; @@ -567,7 +564,7 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain, info->domain = cpu_to_le32(domain); info->message_id = cpu_to_le32(message_id); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (ret) goto err_xfer; @@ -579,20 +576,20 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain, phys_addr = le32_to_cpu(resp->chan_addr_low); phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32; - addr = devm_ioremap(handle->dev, phys_addr, size); + addr = devm_ioremap(ph->dev, phys_addr, size); if (!addr) goto err_xfer; *p_addr = addr; if (p_db && SUPPORTS_DOORBELL(flags)) { - db = devm_kzalloc(handle->dev, sizeof(*db), GFP_KERNEL); + db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL); if (!db) goto err_xfer; size = 1 << DOORBELL_REG_WIDTH(flags); phys_addr = le32_to_cpu(resp->db_addr_low); phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32; - addr = devm_ioremap(handle->dev, phys_addr, size); + addr = devm_ioremap(ph->dev, phys_addr, size); if (!addr) goto err_xfer; @@ -605,25 +602,25 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain, *p_db = db; } err_xfer: - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); } -static void scmi_perf_domain_init_fc(const struct scmi_handle *handle, +static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph, u32 domain, struct scmi_fc_info **p_fc) { struct scmi_fc_info *fc; - fc = devm_kzalloc(handle->dev, sizeof(*fc), GFP_KERNEL); + fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL); if (!fc) return; - scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_SET, + scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_SET, &fc->level_set_addr, &fc->level_set_db); - scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_GET, + scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_GET, &fc->level_get_addr, NULL); - scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_SET, + scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_SET, &fc->limit_set_addr, &fc->limit_set_db); - scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_GET, + scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_GET, &fc->limit_get_addr, NULL); *p_fc = fc; } @@ -640,14 +637,14 @@ static int scmi_dev_domain_id(struct device *dev) return clkspec.args[0]; } -static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle, +static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, struct device *dev) { int idx, ret, domain; unsigned long freq; struct scmi_opp *opp; struct perf_dom_info *dom; - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); domain = scmi_dev_domain_id(dev); if (domain < 0) @@ -672,11 +669,12 @@ static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle, return 0; } -static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle, - struct device *dev) +static int +scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph, + struct device *dev) { struct perf_dom_info *dom; - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); int domain = scmi_dev_domain_id(dev); if (domain < 0) @@ -687,35 +685,35 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle, return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; } -static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain, +static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain, unsigned long freq, bool poll) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom = pi->dom_info + domain; - return scmi_perf_level_set(handle, domain, freq / dom->mult_factor, - poll); + return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll); } -static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain, +static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain, unsigned long *freq, bool poll) { int ret; u32 level; - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom = pi->dom_info + domain; - ret = scmi_perf_level_get(handle, domain, &level, poll); + ret = scmi_perf_level_get(ph, domain, &level, poll); if (!ret) *freq = level * dom->mult_factor; return ret; } -static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain, - unsigned long *freq, unsigned long *power) +static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, + u32 domain, unsigned long *freq, + unsigned long *power) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom; unsigned long opp_freq; int idx, ret = -EINVAL; @@ -739,25 +737,25 @@ static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain, return ret; } -static bool scmi_fast_switch_possible(const struct scmi_handle *handle, +static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph, struct device *dev) { struct perf_dom_info *dom; - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); dom = pi->dom_info + scmi_dev_domain_id(dev); return dom->fc_info && dom->fc_info->level_set_addr; } -static bool scmi_power_scale_mw_get(const struct scmi_handle *handle) +static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph) { - struct scmi_perf_info *pi = handle->perf_priv; + struct scmi_perf_info *pi = ph->get_priv(ph); return pi->power_scale_mw; } -static const struct scmi_perf_ops perf_ops = { +static const struct scmi_perf_proto_ops perf_proto_ops = { .limits_set = scmi_perf_limits_set, .limits_get = scmi_perf_limits_get, .level_set = scmi_perf_level_set, @@ -772,7 +770,7 @@ static const struct scmi_perf_ops perf_ops = { .power_scale_mw_get = scmi_power_scale_mw_get, }; -static int scmi_perf_set_notify_enabled(const struct scmi_handle *handle, +static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enable) { int ret, cmd_id; @@ -781,7 +779,7 @@ static int scmi_perf_set_notify_enabled(const struct scmi_handle *handle, return -EINVAL; cmd_id = evt_2_cmd[evt_id]; - ret = scmi_perf_level_limits_notify(handle, src_id, cmd_id, enable); + ret = scmi_perf_level_limits_notify(ph, src_id, cmd_id, enable); if (ret) pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", evt_id, src_id, ret); @@ -789,7 +787,7 @@ static int scmi_perf_set_notify_enabled(const struct scmi_handle *handle, return ret; } -static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle, +static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph, u8 evt_id, ktime_t timestamp, const void *payld, size_t payld_sz, void *report, u32 *src_id) @@ -837,6 +835,16 @@ static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle, return rep; } +static int scmi_perf_get_num_sources(const struct scmi_protocol_handle *ph) +{ + struct scmi_perf_info *pi = ph->get_priv(ph); + + if (!pi) + return -EINVAL; + + return pi->num_domains; +} + static const struct scmi_event perf_events[] = { { .id = SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED, @@ -851,28 +859,36 @@ static const struct scmi_event perf_events[] = { }; static const struct scmi_event_ops perf_event_ops = { + .get_num_sources = scmi_perf_get_num_sources, .set_notify_enabled = scmi_perf_set_notify_enabled, .fill_custom_report = scmi_perf_fill_custom_report, }; -static int scmi_perf_protocol_init(struct scmi_handle *handle) +static const struct scmi_protocol_events perf_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &perf_event_ops, + .evts = perf_events, + .num_events = ARRAY_SIZE(perf_events), +}; + +static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) { int domain; u32 version; struct scmi_perf_info *pinfo; - scmi_version_get(handle, SCMI_PROTOCOL_PERF, &version); + ph->xops->version_get(ph, &version); - dev_dbg(handle->dev, "Performance Version %d.%d\n", + dev_dbg(ph->dev, "Performance Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; - scmi_perf_attributes_get(handle, pinfo); + scmi_perf_attributes_get(ph, pinfo); - pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, + pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains, sizeof(*pinfo->dom_info), GFP_KERNEL); if (!pinfo->dom_info) return -ENOMEM; @@ -880,24 +896,24 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle) for (domain = 0; domain < pinfo->num_domains; domain++) { struct perf_dom_info *dom = pinfo->dom_info + domain; - scmi_perf_domain_attributes_get(handle, domain, dom); - scmi_perf_describe_levels_get(handle, domain, dom); + scmi_perf_domain_attributes_get(ph, domain, dom); + scmi_perf_describe_levels_get(ph, domain, dom); if (dom->perf_fastchannels) - scmi_perf_domain_init_fc(handle, domain, &dom->fc_info); + scmi_perf_domain_init_fc(ph, domain, &dom->fc_info); } - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_PERF, SCMI_PROTO_QUEUE_SZ, - &perf_event_ops, perf_events, - ARRAY_SIZE(perf_events), - pinfo->num_domains); - pinfo->version = version; - handle->perf_ops = &perf_ops; - handle->perf_priv = pinfo; - return 0; + return ph->set_priv(ph, pinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_PERF, perf) +static const struct scmi_protocol scmi_perf = { + .id = SCMI_PROTOCOL_PERF, + .owner = THIS_MODULE, + .instance_init = &scmi_perf_protocol_init, + .ops = &perf_proto_ops, + .events = &perf_protocol_events, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf) diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 1f37258e9beec6b59796d7eb25643925903b639d..ad2ab080f3443c251153fa606f2f4fd53e369655 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -2,11 +2,12 @@ /* * System Control and Management Interface (SCMI) Power Protocol * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications POWER - " fmt +#include <linux/module.h> #include <linux/scmi_protocol.h> #include "common.h" @@ -68,21 +69,21 @@ struct scmi_power_info { struct power_dom_info *dom_info; }; -static int scmi_power_attributes_get(const struct scmi_handle *handle, +static int scmi_power_attributes_get(const struct scmi_protocol_handle *ph, struct scmi_power_info *pi) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_power_attributes *attr; - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, + 0, sizeof(*attr), &t); if (ret) return ret; attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { pi->num_domains = le16_to_cpu(attr->num_domains); pi->stats_addr = le32_to_cpu(attr->stats_addr_low) | @@ -90,28 +91,27 @@ static int scmi_power_attributes_get(const struct scmi_handle *handle, pi->stats_size = le32_to_cpu(attr->stats_size); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static int -scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, - struct power_dom_info *dom_info) +scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph, + u32 domain, struct power_dom_info *dom_info) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_power_domain_attributes *attr; - ret = scmi_xfer_get_init(handle, POWER_DOMAIN_ATTRIBUTES, - SCMI_PROTOCOL_POWER, sizeof(domain), - sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, POWER_DOMAIN_ATTRIBUTES, + sizeof(domain), sizeof(*attr), &t); if (ret) return ret; put_unaligned_le32(domain, t->tx.buf); attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { u32 flags = le32_to_cpu(attr->flags); @@ -121,19 +121,18 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int -scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) +static int scmi_power_state_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 state) { int ret; struct scmi_xfer *t; struct scmi_power_set_state *st; - ret = scmi_xfer_get_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER, - sizeof(*st), 0, &t); + ret = ph->xops->xfer_get_init(ph, POWER_STATE_SET, sizeof(*st), 0, &t); if (ret) return ret; @@ -142,64 +141,64 @@ scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) st->domain = cpu_to_le32(domain); st->state = cpu_to_le32(state); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int -scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) +static int scmi_power_state_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *state) { int ret; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER, - sizeof(u32), sizeof(u32), &t); + ret = ph->xops->xfer_get_init(ph, POWER_STATE_GET, sizeof(u32), sizeof(u32), &t); if (ret) return ret; put_unaligned_le32(domain, t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) *state = get_unaligned_le32(t->rx.buf); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_power_num_domains_get(const struct scmi_handle *handle) +static int scmi_power_num_domains_get(const struct scmi_protocol_handle *ph) { - struct scmi_power_info *pi = handle->power_priv; + struct scmi_power_info *pi = ph->get_priv(ph); return pi->num_domains; } -static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain) +static char *scmi_power_name_get(const struct scmi_protocol_handle *ph, + u32 domain) { - struct scmi_power_info *pi = handle->power_priv; + struct scmi_power_info *pi = ph->get_priv(ph); struct power_dom_info *dom = pi->dom_info + domain; return dom->name; } -static const struct scmi_power_ops power_ops = { +static const struct scmi_power_proto_ops power_proto_ops = { .num_domains_get = scmi_power_num_domains_get, .name_get = scmi_power_name_get, .state_set = scmi_power_state_set, .state_get = scmi_power_state_get, }; -static int scmi_power_request_notify(const struct scmi_handle *handle, +static int scmi_power_request_notify(const struct scmi_protocol_handle *ph, u32 domain, bool enable) { int ret; struct scmi_xfer *t; struct scmi_power_state_notify *notify; - ret = scmi_xfer_get_init(handle, POWER_STATE_NOTIFY, - SCMI_PROTOCOL_POWER, sizeof(*notify), 0, &t); + ret = ph->xops->xfer_get_init(ph, POWER_STATE_NOTIFY, + sizeof(*notify), 0, &t); if (ret) return ret; @@ -207,18 +206,18 @@ static int scmi_power_request_notify(const struct scmi_handle *handle, notify->domain = cpu_to_le32(domain); notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_power_set_notify_enabled(const struct scmi_handle *handle, +static int scmi_power_set_notify_enabled(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enable) { int ret; - ret = scmi_power_request_notify(handle, src_id, enable); + ret = scmi_power_request_notify(ph, src_id, enable); if (ret) pr_debug("FAIL_ENABLE - evt[%X] dom[%d] - ret:%d\n", evt_id, src_id, ret); @@ -226,10 +225,11 @@ static int scmi_power_set_notify_enabled(const struct scmi_handle *handle, return ret; } -static void *scmi_power_fill_custom_report(const struct scmi_handle *handle, - u8 evt_id, ktime_t timestamp, - const void *payld, size_t payld_sz, - void *report, u32 *src_id) +static void * +scmi_power_fill_custom_report(const struct scmi_protocol_handle *ph, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) { const struct scmi_power_state_notify_payld *p = payld; struct scmi_power_state_changed_report *r = report; @@ -246,6 +246,16 @@ static void *scmi_power_fill_custom_report(const struct scmi_handle *handle, return r; } +static int scmi_power_get_num_sources(const struct scmi_protocol_handle *ph) +{ + struct scmi_power_info *pinfo = ph->get_priv(ph); + + if (!pinfo) + return -EINVAL; + + return pinfo->num_domains; +} + static const struct scmi_event power_events[] = { { .id = SCMI_EVENT_POWER_STATE_CHANGED, @@ -256,28 +266,36 @@ static const struct scmi_event power_events[] = { }; static const struct scmi_event_ops power_event_ops = { + .get_num_sources = scmi_power_get_num_sources, .set_notify_enabled = scmi_power_set_notify_enabled, .fill_custom_report = scmi_power_fill_custom_report, }; -static int scmi_power_protocol_init(struct scmi_handle *handle) +static const struct scmi_protocol_events power_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &power_event_ops, + .evts = power_events, + .num_events = ARRAY_SIZE(power_events), +}; + +static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph) { int domain; u32 version; struct scmi_power_info *pinfo; - scmi_version_get(handle, SCMI_PROTOCOL_POWER, &version); + ph->xops->version_get(ph, &version); - dev_dbg(handle->dev, "Power Version %d.%d\n", + dev_dbg(ph->dev, "Power Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; - scmi_power_attributes_get(handle, pinfo); + scmi_power_attributes_get(ph, pinfo); - pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, + pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains, sizeof(*pinfo->dom_info), GFP_KERNEL); if (!pinfo->dom_info) return -ENOMEM; @@ -285,20 +303,20 @@ static int scmi_power_protocol_init(struct scmi_handle *handle) for (domain = 0; domain < pinfo->num_domains; domain++) { struct power_dom_info *dom = pinfo->dom_info + domain; - scmi_power_domain_attributes_get(handle, domain, dom); + scmi_power_domain_attributes_get(ph, domain, dom); } - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_POWER, SCMI_PROTO_QUEUE_SZ, - &power_event_ops, power_events, - ARRAY_SIZE(power_events), - pinfo->num_domains); - pinfo->version = version; - handle->power_ops = &power_ops; - handle->power_priv = pinfo; - return 0; + return ph->set_priv(ph, pinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_POWER, power) +static const struct scmi_protocol scmi_power = { + .id = SCMI_PROTOCOL_POWER, + .owner = THIS_MODULE, + .instance_init = &scmi_power_protocol_init, + .ops = &power_proto_ops, + .events = &power_protocol_events, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power) diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index a981a22cfe8912b4ae68bbadc18f275ada8c514f..9bf2478ec6d1765d81e8afafc8b9ec4df0b74ebc 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -2,11 +2,12 @@ /* * System Control and Management Interface (SCMI) Reset Protocol * - * Copyright (C) 2019 ARM Ltd. + * Copyright (C) 2019-2021 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications RESET - " fmt +#include <linux/module.h> #include <linux/scmi_protocol.h> #include "common.h" @@ -64,46 +65,45 @@ struct scmi_reset_info { struct reset_dom_info *dom_info; }; -static int scmi_reset_attributes_get(const struct scmi_handle *handle, +static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph, struct scmi_reset_info *pi) { int ret; struct scmi_xfer *t; u32 attr; - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_RESET, 0, sizeof(attr), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, + 0, sizeof(attr), &t); if (ret) return ret; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { attr = get_unaligned_le32(t->rx.buf); pi->num_domains = attr & NUM_RESET_DOMAIN_MASK; } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static int -scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain, - struct reset_dom_info *dom_info) +scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph, + u32 domain, struct reset_dom_info *dom_info) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_reset_domain_attributes *attr; - ret = scmi_xfer_get_init(handle, RESET_DOMAIN_ATTRIBUTES, - SCMI_PROTOCOL_RESET, sizeof(domain), - sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES, + sizeof(domain), sizeof(*attr), &t); if (ret) return ret; put_unaligned_le32(domain, t->tx.buf); attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { u32 attributes = le32_to_cpu(attr->attributes); @@ -115,47 +115,49 @@ scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain, strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_reset_num_domains_get(const struct scmi_handle *handle) +static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph) { - struct scmi_reset_info *pi = handle->reset_priv; + struct scmi_reset_info *pi = ph->get_priv(ph); return pi->num_domains; } -static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain) +static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph, + u32 domain) { - struct scmi_reset_info *pi = handle->reset_priv; + struct scmi_reset_info *pi = ph->get_priv(ph); + struct reset_dom_info *dom = pi->dom_info + domain; return dom->name; } -static int scmi_reset_latency_get(const struct scmi_handle *handle, u32 domain) +static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph, + u32 domain) { - struct scmi_reset_info *pi = handle->reset_priv; + struct scmi_reset_info *pi = ph->get_priv(ph); struct reset_dom_info *dom = pi->dom_info + domain; return dom->latency_us; } -static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain, +static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain, u32 flags, u32 state) { int ret; struct scmi_xfer *t; struct scmi_msg_reset_domain_reset *dom; - struct scmi_reset_info *pi = handle->reset_priv; + struct scmi_reset_info *pi = ph->get_priv(ph); struct reset_dom_info *rdom = pi->dom_info + domain; if (rdom->async_reset) flags |= ASYNCHRONOUS_RESET; - ret = scmi_xfer_get_init(handle, RESET, SCMI_PROTOCOL_RESET, - sizeof(*dom), 0, &t); + ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t); if (ret) return ret; @@ -165,34 +167,35 @@ static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain, dom->reset_state = cpu_to_le32(state); if (rdom->async_reset) - ret = scmi_do_xfer_with_response(handle, t); + ret = ph->xops->do_xfer_with_response(ph, t); else - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain) +static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph, + u32 domain) { - return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET, + return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET, ARCH_COLD_RESET); } static int -scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain) +scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain) { - return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT, + return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT, ARCH_COLD_RESET); } static int -scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain) +scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain) { - return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET); + return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET); } -static const struct scmi_reset_ops reset_ops = { +static const struct scmi_reset_proto_ops reset_proto_ops = { .num_domains_get = scmi_reset_num_domains_get, .name_get = scmi_reset_name_get, .latency_get = scmi_reset_latency_get, @@ -201,16 +204,15 @@ static const struct scmi_reset_ops reset_ops = { .deassert = scmi_reset_domain_deassert, }; -static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id, - bool enable) +static int scmi_reset_notify(const struct scmi_protocol_handle *ph, + u32 domain_id, bool enable) { int ret; u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0; struct scmi_xfer *t; struct scmi_msg_reset_notify *cfg; - ret = scmi_xfer_get_init(handle, RESET_NOTIFY, - SCMI_PROTOCOL_RESET, sizeof(*cfg), 0, &t); + ret = ph->xops->xfer_get_init(ph, RESET_NOTIFY, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -218,18 +220,18 @@ static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id, cfg->id = cpu_to_le32(domain_id); cfg->event_control = cpu_to_le32(evt_cntl); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_reset_set_notify_enabled(const struct scmi_handle *handle, +static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enable) { int ret; - ret = scmi_reset_notify(handle, src_id, enable); + ret = scmi_reset_notify(ph, src_id, enable); if (ret) pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", evt_id, src_id, ret); @@ -237,10 +239,11 @@ static int scmi_reset_set_notify_enabled(const struct scmi_handle *handle, return ret; } -static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle, - u8 evt_id, ktime_t timestamp, - const void *payld, size_t payld_sz, - void *report, u32 *src_id) +static void * +scmi_reset_fill_custom_report(const struct scmi_protocol_handle *ph, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) { const struct scmi_reset_issued_notify_payld *p = payld; struct scmi_reset_issued_report *r = report; @@ -257,6 +260,16 @@ static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle, return r; } +static int scmi_reset_get_num_sources(const struct scmi_protocol_handle *ph) +{ + struct scmi_reset_info *pinfo = ph->get_priv(ph); + + if (!pinfo) + return -EINVAL; + + return pinfo->num_domains; +} + static const struct scmi_event reset_events[] = { { .id = SCMI_EVENT_RESET_ISSUED, @@ -266,28 +279,36 @@ static const struct scmi_event reset_events[] = { }; static const struct scmi_event_ops reset_event_ops = { + .get_num_sources = scmi_reset_get_num_sources, .set_notify_enabled = scmi_reset_set_notify_enabled, .fill_custom_report = scmi_reset_fill_custom_report, }; -static int scmi_reset_protocol_init(struct scmi_handle *handle) +static const struct scmi_protocol_events reset_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &reset_event_ops, + .evts = reset_events, + .num_events = ARRAY_SIZE(reset_events), +}; + +static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) { int domain; u32 version; struct scmi_reset_info *pinfo; - scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version); + ph->xops->version_get(ph, &version); - dev_dbg(handle->dev, "Reset Version %d.%d\n", + dev_dbg(ph->dev, "Reset Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; - scmi_reset_attributes_get(handle, pinfo); + scmi_reset_attributes_get(ph, pinfo); - pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, + pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains, sizeof(*pinfo->dom_info), GFP_KERNEL); if (!pinfo->dom_info) return -ENOMEM; @@ -295,20 +316,19 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle) for (domain = 0; domain < pinfo->num_domains; domain++) { struct reset_dom_info *dom = pinfo->dom_info + domain; - scmi_reset_domain_attributes_get(handle, domain, dom); + scmi_reset_domain_attributes_get(ph, domain, dom); } - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_RESET, SCMI_PROTO_QUEUE_SZ, - &reset_event_ops, reset_events, - ARRAY_SIZE(reset_events), - pinfo->num_domains); - pinfo->version = version; - handle->reset_ops = &reset_ops; - handle->reset_priv = pinfo; - - return 0; + return ph->set_priv(ph, pinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset) +static const struct scmi_protocol scmi_reset = { + .id = SCMI_PROTOCOL_RESET, + .owner = THIS_MODULE, + .instance_init = &scmi_reset_protocol_init, + .ops = &reset_proto_ops, + .events = &reset_protocol_events, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset) diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c index 9e44479f028424cfe7636b6474320c0cb05d2d10..9d36d5c0622d4d19a305a06ffc119c81e919a488 100644 --- a/drivers/firmware/arm_scmi/scmi_pm_domain.c +++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c @@ -2,7 +2,7 @@ /* * SCMI Generic power domain support. * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #include <linux/err.h> @@ -11,9 +11,11 @@ #include <linux/pm_domain.h> #include <linux/scmi_protocol.h> +static const struct scmi_power_proto_ops *power_ops; + struct scmi_pm_domain { struct generic_pm_domain genpd; - const struct scmi_handle *handle; + const struct scmi_protocol_handle *ph; const char *name; u32 domain; }; @@ -25,16 +27,15 @@ static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on) int ret; u32 state, ret_state; struct scmi_pm_domain *pd = to_scmi_pd(domain); - const struct scmi_power_ops *ops = pd->handle->power_ops; if (power_on) state = SCMI_POWER_STATE_GENERIC_ON; else state = SCMI_POWER_STATE_GENERIC_OFF; - ret = ops->state_set(pd->handle, pd->domain, state); + ret = power_ops->state_set(pd->ph, pd->domain, state); if (!ret) - ret = ops->state_get(pd->handle, pd->domain, &ret_state); + ret = power_ops->state_get(pd->ph, pd->domain, &ret_state); if (!ret && state != ret_state) return -EIO; @@ -60,11 +61,16 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) struct genpd_onecell_data *scmi_pd_data; struct generic_pm_domain **domains; const struct scmi_handle *handle = sdev->handle; + struct scmi_protocol_handle *ph; - if (!handle || !handle->power_ops) + if (!handle) return -ENODEV; - num_domains = handle->power_ops->num_domains_get(handle); + power_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_POWER, &ph); + if (IS_ERR(power_ops)) + return PTR_ERR(power_ops); + + num_domains = power_ops->num_domains_get(ph); if (num_domains < 0) { dev_err(dev, "number of domains not found\n"); return num_domains; @@ -85,14 +91,14 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) for (i = 0; i < num_domains; i++, scmi_pd++) { u32 state; - if (handle->power_ops->state_get(handle, i, &state)) { + if (power_ops->state_get(ph, i, &state)) { dev_warn(dev, "failed to get state for domain %d\n", i); continue; } scmi_pd->domain = i; - scmi_pd->handle = handle; - scmi_pd->name = handle->power_ops->name_get(handle, i); + scmi_pd->ph = ph; + scmi_pd->name = power_ops->name_get(ph, i); scmi_pd->genpd.name = scmi_pd->name; scmi_pd->genpd.power_off = scmi_pd_power_off; scmi_pd->genpd.power_on = scmi_pd_power_on; diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 4541b891b733f80ca5798d4ca06dd38a24738e25..2c88aa22155972e1085b60faa4223dec3f1012dd 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -2,12 +2,13 @@ /* * System Control and Management Interface (SCMI) Sensor Protocol * - * Copyright (C) 2018-2020 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt #include <linux/bitfield.h> +#include <linux/module.h> #include <linux/scmi_protocol.h> #include "common.h" @@ -201,21 +202,21 @@ struct sensors_info { struct scmi_sensor_info *sensors; }; -static int scmi_sensor_attributes_get(const struct scmi_handle *handle, +static int scmi_sensor_attributes_get(const struct scmi_protocol_handle *ph, struct sensors_info *si) { int ret; struct scmi_xfer *t; struct scmi_msg_resp_sensor_attributes *attr; - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, + 0, sizeof(*attr), &t); if (ret) return ret; attr = t->rx.buf; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { si->num_sensors = le16_to_cpu(attr->num_sensors); si->max_requests = attr->max_requests; @@ -224,7 +225,7 @@ static int scmi_sensor_attributes_get(const struct scmi_handle *handle, si->reg_size = le32_to_cpu(attr->reg_size); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -235,7 +236,7 @@ static inline void scmi_parse_range_attrs(struct scmi_range_attrs *out, out->max_range = get_unaligned_le64((void *)&in->max_range_low); } -static int scmi_sensor_update_intervals(const struct scmi_handle *handle, +static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph, struct scmi_sensor_info *s) { int ret, cnt; @@ -245,8 +246,8 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle, struct scmi_msg_resp_sensor_list_update_intervals *buf; struct scmi_msg_sensor_list_update_intervals *msg; - ret = scmi_xfer_get_init(handle, SENSOR_LIST_UPDATE_INTERVALS, - SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &ti); + ret = ph->xops->xfer_get_init(ph, SENSOR_LIST_UPDATE_INTERVALS, + sizeof(*msg), 0, &ti); if (ret) return ret; @@ -259,7 +260,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle, msg->id = cpu_to_le32(s->id); msg->index = cpu_to_le32(desc_index); - ret = scmi_do_xfer(handle, ti); + ret = ph->xops->do_xfer(ph, ti); if (ret) break; @@ -277,7 +278,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle, /* segmented intervals are reported in one triplet */ if (s->intervals.segmented && (num_remaining || num_returned != 3)) { - dev_err(handle->dev, + dev_err(ph->dev, "Sensor ID:%d advertises an invalid segmented interval (%d)\n", s->id, s->intervals.count); s->intervals.segmented = false; @@ -288,7 +289,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle, /* Direct allocation when exceeding pre-allocated */ if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) { s->intervals.desc = - devm_kcalloc(handle->dev, + devm_kcalloc(ph->dev, s->intervals.count, sizeof(*s->intervals.desc), GFP_KERNEL); @@ -300,7 +301,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle, } } } else if (desc_index + num_returned > s->intervals.count) { - dev_err(handle->dev, + dev_err(ph->dev, "No. of update intervals can't exceed %d\n", s->intervals.count); ret = -EINVAL; @@ -313,18 +314,18 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle, desc_index += num_returned; - scmi_reset_rx_to_maxsz(handle, ti); + ph->xops->reset_rx_to_maxsz(ph, ti); /* * check for both returned and remaining to avoid infinite * loop due to buggy firmware */ } while (num_returned && num_remaining); - scmi_xfer_put(handle, ti); + ph->xops->xfer_put(ph, ti); return ret; } -static int scmi_sensor_axis_description(const struct scmi_handle *handle, +static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph, struct scmi_sensor_info *s) { int ret, cnt; @@ -334,13 +335,13 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle, struct scmi_msg_resp_sensor_axis_description *buf; struct scmi_msg_sensor_axis_description_get *msg; - s->axis = devm_kcalloc(handle->dev, s->num_axis, + s->axis = devm_kcalloc(ph->dev, s->num_axis, sizeof(*s->axis), GFP_KERNEL); if (!s->axis) return -ENOMEM; - ret = scmi_xfer_get_init(handle, SENSOR_AXIS_DESCRIPTION_GET, - SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &te); + ret = ph->xops->xfer_get_init(ph, SENSOR_AXIS_DESCRIPTION_GET, + sizeof(*msg), 0, &te); if (ret) return ret; @@ -354,7 +355,7 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle, msg->id = cpu_to_le32(s->id); msg->axis_desc_index = cpu_to_le32(desc_index); - ret = scmi_do_xfer(handle, te); + ret = ph->xops->do_xfer(ph, te); if (ret) break; @@ -363,7 +364,7 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle, num_remaining = NUM_AXIS_REMAINING(flags); if (desc_index + num_returned > s->num_axis) { - dev_err(handle->dev, "No. of axis can't exceed %d\n", + dev_err(ph->dev, "No. of axis can't exceed %d\n", s->num_axis); break; } @@ -405,18 +406,18 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle, desc_index += num_returned; - scmi_reset_rx_to_maxsz(handle, te); + ph->xops->reset_rx_to_maxsz(ph, te); /* * check for both returned and remaining to avoid infinite * loop due to buggy firmware */ } while (num_returned && num_remaining); - scmi_xfer_put(handle, te); + ph->xops->xfer_put(ph, te); return ret; } -static int scmi_sensor_description_get(const struct scmi_handle *handle, +static int scmi_sensor_description_get(const struct scmi_protocol_handle *ph, struct sensors_info *si) { int ret, cnt; @@ -425,8 +426,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_sensor_description *buf; - ret = scmi_xfer_get_init(handle, SENSOR_DESCRIPTION_GET, - SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t); + ret = ph->xops->xfer_get_init(ph, SENSOR_DESCRIPTION_GET, + sizeof(__le32), 0, &t); if (ret) return ret; @@ -437,7 +438,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, /* Set the number of sensors to be skipped/already read */ put_unaligned_le32(desc_index, t->tx.buf); - ret = scmi_do_xfer(handle, t); + + ret = ph->xops->do_xfer(ph, t); if (ret) break; @@ -445,7 +447,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, num_remaining = le16_to_cpu(buf->num_remaining); if (desc_index + num_returned > si->num_sensors) { - dev_err(handle->dev, "No. of sensors can't exceed %d", + dev_err(ph->dev, "No. of sensors can't exceed %d", si->num_sensors); break; } @@ -500,8 +502,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, * Since the command is optional, on error carry * on without any update interval. */ - if (scmi_sensor_update_intervals(handle, s)) - dev_dbg(handle->dev, + if (scmi_sensor_update_intervals(ph, s)) + dev_dbg(ph->dev, "Update Intervals not available for sensor ID:%d\n", s->id); } @@ -535,7 +537,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, } } if (s->num_axis > 0) { - ret = scmi_sensor_axis_description(handle, s); + ret = scmi_sensor_axis_description(ph, s); if (ret) goto out; } @@ -545,7 +547,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, desc_index += num_returned; - scmi_reset_rx_to_maxsz(handle, t); + ph->xops->reset_rx_to_maxsz(ph, t); /* * check for both returned and remaining to avoid infinite * loop due to buggy firmware @@ -553,12 +555,12 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, } while (num_returned && num_remaining); out: - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static inline int -scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id, +scmi_sensor_request_notify(const struct scmi_protocol_handle *ph, u32 sensor_id, u8 message_id, bool enable) { int ret; @@ -566,8 +568,7 @@ scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id, struct scmi_xfer *t; struct scmi_msg_sensor_request_notify *cfg; - ret = scmi_xfer_get_init(handle, message_id, - SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t); + ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -575,40 +576,40 @@ scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id, cfg->id = cpu_to_le32(sensor_id); cfg->event_control = cpu_to_le32(evt_cntl); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle, +static int scmi_sensor_trip_point_notify(const struct scmi_protocol_handle *ph, u32 sensor_id, bool enable) { - return scmi_sensor_request_notify(handle, sensor_id, + return scmi_sensor_request_notify(ph, sensor_id, SENSOR_TRIP_POINT_NOTIFY, enable); } static int -scmi_sensor_continuous_update_notify(const struct scmi_handle *handle, +scmi_sensor_continuous_update_notify(const struct scmi_protocol_handle *ph, u32 sensor_id, bool enable) { - return scmi_sensor_request_notify(handle, sensor_id, + return scmi_sensor_request_notify(ph, sensor_id, SENSOR_CONTINUOUS_UPDATE_NOTIFY, enable); } static int -scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id, - u8 trip_id, u64 trip_value) +scmi_sensor_trip_point_config(const struct scmi_protocol_handle *ph, + u32 sensor_id, u8 trip_id, u64 trip_value) { int ret; u32 evt_cntl = SENSOR_TP_BOTH; struct scmi_xfer *t; struct scmi_msg_set_sensor_trip_point *trip; - ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG, - SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t); + ret = ph->xops->xfer_get_init(ph, SENSOR_TRIP_POINT_CONFIG, + sizeof(*trip), 0, &t); if (ret) return ret; @@ -618,47 +619,46 @@ scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id, trip->value_low = cpu_to_le32(trip_value & 0xffffffff); trip->value_high = cpu_to_le32(trip_value >> 32); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_sensor_config_get(const struct scmi_handle *handle, +static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph, u32 sensor_id, u32 *sensor_config) { int ret; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_GET, - SCMI_PROTOCOL_SENSOR, sizeof(__le32), - sizeof(__le32), &t); + ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_GET, + sizeof(__le32), sizeof(__le32), &t); if (ret) return ret; put_unaligned_le32(cpu_to_le32(sensor_id), t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { - struct sensors_info *si = handle->sensor_priv; + struct sensors_info *si = ph->get_priv(ph); struct scmi_sensor_info *s = si->sensors + sensor_id; *sensor_config = get_unaligned_le64(t->rx.buf); s->sensor_config = *sensor_config; } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_sensor_config_set(const struct scmi_handle *handle, +static int scmi_sensor_config_set(const struct scmi_protocol_handle *ph, u32 sensor_id, u32 sensor_config) { int ret; struct scmi_xfer *t; struct scmi_msg_sensor_config_set *msg; - ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET, - SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &t); + ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_SET, + sizeof(*msg), 0, &t); if (ret) return ret; @@ -666,21 +666,21 @@ static int scmi_sensor_config_set(const struct scmi_handle *handle, msg->id = cpu_to_le32(sensor_id); msg->sensor_config = cpu_to_le32(sensor_config); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { - struct sensors_info *si = handle->sensor_priv; + struct sensors_info *si = ph->get_priv(ph); struct scmi_sensor_info *s = si->sensors + sensor_id; s->sensor_config = sensor_config; } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } /** * scmi_sensor_reading_get - Read scalar sensor value - * @handle: Platform handle + * @ph: Protocol handle * @sensor_id: Sensor ID * @value: The 64bit value sensor reading * @@ -693,17 +693,17 @@ static int scmi_sensor_config_set(const struct scmi_handle *handle, * * Return: 0 on Success */ -static int scmi_sensor_reading_get(const struct scmi_handle *handle, +static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph, u32 sensor_id, u64 *value) { int ret; struct scmi_xfer *t; struct scmi_msg_sensor_reading_get *sensor; - struct sensors_info *si = handle->sensor_priv; + struct sensors_info *si = ph->get_priv(ph); struct scmi_sensor_info *s = si->sensors + sensor_id; - ret = scmi_xfer_get_init(handle, SENSOR_READING_GET, - SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t); + ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET, + sizeof(*sensor), 0, &t); if (ret) return ret; @@ -711,7 +711,7 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, sensor->id = cpu_to_le32(sensor_id); if (s->async) { sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); - ret = scmi_do_xfer_with_response(handle, t); + ret = ph->xops->do_xfer_with_response(ph, t); if (!ret) { struct scmi_resp_sensor_reading_complete *resp; @@ -723,12 +723,12 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, } } else { sensor->flags = cpu_to_le32(0); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) *value = get_unaligned_le64(t->rx.buf); } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -742,7 +742,7 @@ scmi_parse_sensor_readings(struct scmi_sensor_reading *out, /** * scmi_sensor_reading_get_timestamped - Read multiple-axis timestamped values - * @handle: Platform handle + * @ph: Protocol handle * @sensor_id: Sensor ID * @count: The length of the provided @readings array * @readings: An array of elements each representing a timestamped per-axis @@ -755,22 +755,22 @@ scmi_parse_sensor_readings(struct scmi_sensor_reading *out, * Return: 0 on Success */ static int -scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle, +scmi_sensor_reading_get_timestamped(const struct scmi_protocol_handle *ph, u32 sensor_id, u8 count, struct scmi_sensor_reading *readings) { int ret; struct scmi_xfer *t; struct scmi_msg_sensor_reading_get *sensor; - struct sensors_info *si = handle->sensor_priv; + struct sensors_info *si = ph->get_priv(ph); struct scmi_sensor_info *s = si->sensors + sensor_id; if (!count || !readings || (!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis)) return -EINVAL; - ret = scmi_xfer_get_init(handle, SENSOR_READING_GET, - SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t); + ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET, + sizeof(*sensor), 0, &t); if (ret) return ret; @@ -778,7 +778,7 @@ scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle, sensor->id = cpu_to_le32(sensor_id); if (s->async) { sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); - ret = scmi_do_xfer_with_response(handle, t); + ret = ph->xops->do_xfer_with_response(ph, t); if (!ret) { int i; struct scmi_resp_sensor_reading_complete_v3 *resp; @@ -794,7 +794,7 @@ scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle, } } else { sensor->flags = cpu_to_le32(0); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) { int i; struct scmi_sensor_reading_resp *resp_readings; @@ -806,26 +806,26 @@ scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle, } } - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } static const struct scmi_sensor_info * -scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id) +scmi_sensor_info_get(const struct scmi_protocol_handle *ph, u32 sensor_id) { - struct sensors_info *si = handle->sensor_priv; + struct sensors_info *si = ph->get_priv(ph); return si->sensors + sensor_id; } -static int scmi_sensor_count_get(const struct scmi_handle *handle) +static int scmi_sensor_count_get(const struct scmi_protocol_handle *ph) { - struct sensors_info *si = handle->sensor_priv; + struct sensors_info *si = ph->get_priv(ph); return si->num_sensors; } -static const struct scmi_sensor_ops sensor_ops = { +static const struct scmi_sensor_proto_ops sensor_proto_ops = { .count_get = scmi_sensor_count_get, .info_get = scmi_sensor_info_get, .trip_point_config = scmi_sensor_trip_point_config, @@ -835,18 +835,17 @@ static const struct scmi_sensor_ops sensor_ops = { .config_set = scmi_sensor_config_set, }; -static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle, +static int scmi_sensor_set_notify_enabled(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enable) { int ret; switch (evt_id) { case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT: - ret = scmi_sensor_trip_point_notify(handle, src_id, enable); + ret = scmi_sensor_trip_point_notify(ph, src_id, enable); break; case SCMI_EVENT_SENSOR_UPDATE: - ret = scmi_sensor_continuous_update_notify(handle, src_id, - enable); + ret = scmi_sensor_continuous_update_notify(ph, src_id, enable); break; default: ret = -EINVAL; @@ -860,10 +859,11 @@ static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle, return ret; } -static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle, - u8 evt_id, ktime_t timestamp, - const void *payld, size_t payld_sz, - void *report, u32 *src_id) +static void * +scmi_sensor_fill_custom_report(const struct scmi_protocol_handle *ph, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) { void *rep = NULL; @@ -890,7 +890,7 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle, struct scmi_sensor_info *s; const struct scmi_sensor_update_notify_payld *p = payld; struct scmi_sensor_update_report *r = report; - struct sensors_info *sinfo = handle->sensor_priv; + struct sensors_info *sinfo = ph->get_priv(ph); /* payld_sz is variable for this event */ r->sensor_id = le32_to_cpu(p->sensor_id); @@ -920,6 +920,13 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle, return rep; } +static int scmi_sensor_get_num_sources(const struct scmi_protocol_handle *ph) +{ + struct sensors_info *si = ph->get_priv(ph); + + return si->num_sensors; +} + static const struct scmi_event sensor_events[] = { { .id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT, @@ -939,48 +946,55 @@ static const struct scmi_event sensor_events[] = { }; static const struct scmi_event_ops sensor_event_ops = { + .get_num_sources = scmi_sensor_get_num_sources, .set_notify_enabled = scmi_sensor_set_notify_enabled, .fill_custom_report = scmi_sensor_fill_custom_report, }; -static int scmi_sensors_protocol_init(struct scmi_handle *handle) +static const struct scmi_protocol_events sensor_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &sensor_event_ops, + .evts = sensor_events, + .num_events = ARRAY_SIZE(sensor_events), +}; + +static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph) { u32 version; int ret; struct sensors_info *sinfo; - scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version); + ph->xops->version_get(ph, &version); - dev_dbg(handle->dev, "Sensor Version %d.%d\n", + dev_dbg(ph->dev, "Sensor Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL); + sinfo = devm_kzalloc(ph->dev, sizeof(*sinfo), GFP_KERNEL); if (!sinfo) return -ENOMEM; sinfo->version = version; - ret = scmi_sensor_attributes_get(handle, sinfo); + ret = scmi_sensor_attributes_get(ph, sinfo); if (ret) return ret; - sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors, + sinfo->sensors = devm_kcalloc(ph->dev, sinfo->num_sensors, sizeof(*sinfo->sensors), GFP_KERNEL); if (!sinfo->sensors) return -ENOMEM; - ret = scmi_sensor_description_get(handle, sinfo); + ret = scmi_sensor_description_get(ph, sinfo); if (ret) return ret; - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ, - &sensor_event_ops, sensor_events, - ARRAY_SIZE(sensor_events), - sinfo->num_sensors); - - handle->sensor_priv = sinfo; - handle->sensor_ops = &sensor_ops; - - return 0; + return ph->set_priv(ph, sinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors) +static const struct scmi_protocol scmi_sensors = { + .id = SCMI_PROTOCOL_SENSOR, + .owner = THIS_MODULE, + .instance_init = &scmi_sensors_protocol_init, + .ops = &sensor_proto_ops, + .events = &sensor_protocol_events, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors) diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c index 283e12d5f24b7364a4c08103a40c2c46ac0f0065..e5175ef73b40e0d0375466f647203dd91299f3eb 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -2,11 +2,12 @@ /* * System Control and Management Interface (SCMI) System Power Protocol * - * Copyright (C) 2020 ARM Ltd. + * Copyright (C) 2020-2021 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt +#include <linux/module.h> #include <linux/scmi_protocol.h> #include "common.h" @@ -32,43 +33,44 @@ struct scmi_system_info { u32 version; }; -static int scmi_system_request_notify(const struct scmi_handle *handle, +static int scmi_system_request_notify(const struct scmi_protocol_handle *ph, bool enable) { int ret; struct scmi_xfer *t; struct scmi_system_power_state_notify *notify; - ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY, - SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t); + ret = ph->xops->xfer_get_init(ph, SYSTEM_POWER_STATE_NOTIFY, + sizeof(*notify), 0, &t); if (ret) return ret; notify = t->tx.buf; notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_system_set_notify_enabled(const struct scmi_handle *handle, +static int scmi_system_set_notify_enabled(const struct scmi_protocol_handle *ph, u8 evt_id, u32 src_id, bool enable) { int ret; - ret = scmi_system_request_notify(handle, enable); + ret = scmi_system_request_notify(ph, enable); if (ret) pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret); return ret; } -static void *scmi_system_fill_custom_report(const struct scmi_handle *handle, - u8 evt_id, ktime_t timestamp, - const void *payld, size_t payld_sz, - void *report, u32 *src_id) +static void * +scmi_system_fill_custom_report(const struct scmi_protocol_handle *ph, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) { const struct scmi_system_power_state_notifier_payld *p = payld; struct scmi_system_power_state_notifier_report *r = report; @@ -101,31 +103,38 @@ static const struct scmi_event_ops system_event_ops = { .fill_custom_report = scmi_system_fill_custom_report, }; -static int scmi_system_protocol_init(struct scmi_handle *handle) +static const struct scmi_protocol_events system_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &system_event_ops, + .evts = system_events, + .num_events = ARRAY_SIZE(system_events), + .num_sources = SCMI_SYSTEM_NUM_SOURCES, +}; + +static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph) { u32 version; struct scmi_system_info *pinfo; - scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version); + ph->xops->version_get(ph, &version); - dev_dbg(handle->dev, "System Power Version %d.%d\n", + dev_dbg(ph->dev, "System Power Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ, - &system_event_ops, - system_events, - ARRAY_SIZE(system_events), - SCMI_SYSTEM_NUM_SOURCES); - pinfo->version = version; - handle->system_priv = pinfo; - - return 0; + return ph->set_priv(ph, pinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system) +static const struct scmi_protocol scmi_system = { + .id = SCMI_PROTOCOL_SYSTEM, + .owner = THIS_MODULE, + .instance_init = &scmi_system_protocol_init, + .ops = NULL, + .events = &system_protocol_events, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system) diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index e794e4349ae6c916625af64b081760a6718bbe04..a5048956a0be9441be1cb9035b50933b929d658e 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -2,9 +2,10 @@ /* * System Control and Management Interface (SCMI) Voltage Protocol * - * Copyright (C) 2020 ARM Ltd. + * Copyright (C) 2020-2021 ARM Ltd. */ +#include <linux/module.h> #include <linux/scmi_protocol.h> #include "common.h" @@ -59,23 +60,23 @@ struct voltage_info { struct scmi_voltage_info *domains; }; -static int scmi_protocol_attributes_get(const struct scmi_handle *handle, +static int scmi_protocol_attributes_get(const struct scmi_protocol_handle *ph, struct voltage_info *vinfo) { int ret; struct scmi_xfer *t; - ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, - SCMI_PROTOCOL_VOLTAGE, 0, sizeof(__le32), &t); + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, + sizeof(__le32), &t); if (ret) return ret; - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) vinfo->num_domains = NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t->rx.buf)); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } @@ -109,24 +110,23 @@ static int scmi_init_voltage_levels(struct device *dev, return 0; } -static int scmi_voltage_descriptors_get(const struct scmi_handle *handle, +static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph, struct voltage_info *vinfo) { int ret, dom; struct scmi_xfer *td, *tl; - struct device *dev = handle->dev; + struct device *dev = ph->dev; struct scmi_msg_resp_domain_attributes *resp_dom; struct scmi_msg_resp_describe_levels *resp_levels; - ret = scmi_xfer_get_init(handle, VOLTAGE_DOMAIN_ATTRIBUTES, - SCMI_PROTOCOL_VOLTAGE, sizeof(__le32), - sizeof(*resp_dom), &td); + ret = ph->xops->xfer_get_init(ph, VOLTAGE_DOMAIN_ATTRIBUTES, + sizeof(__le32), sizeof(*resp_dom), &td); if (ret) return ret; resp_dom = td->rx.buf; - ret = scmi_xfer_get_init(handle, VOLTAGE_DESCRIBE_LEVELS, - SCMI_PROTOCOL_VOLTAGE, sizeof(__le64), 0, &tl); + ret = ph->xops->xfer_get_init(ph, VOLTAGE_DESCRIBE_LEVELS, + sizeof(__le64), 0, &tl); if (ret) goto outd; resp_levels = tl->rx.buf; @@ -139,7 +139,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle, /* Retrieve domain attributes at first ... */ put_unaligned_le32(dom, td->tx.buf); - ret = scmi_do_xfer(handle, td); + ret = ph->xops->do_xfer(ph, td); /* Skip domain on comms error */ if (ret) continue; @@ -157,7 +157,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle, cmd->domain_id = cpu_to_le32(v->id); cmd->level_index = desc_index; - ret = scmi_do_xfer(handle, tl); + ret = ph->xops->do_xfer(ph, tl); if (ret) break; @@ -176,7 +176,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle, } if (desc_index + num_returned > v->num_levels) { - dev_err(handle->dev, + dev_err(ph->dev, "No. of voltage levels can't exceed %d\n", v->num_levels); ret = -EINVAL; @@ -195,7 +195,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle, desc_index += num_returned; - scmi_reset_rx_to_maxsz(handle, tl); + ph->xops->reset_rx_to_maxsz(ph, tl); /* check both to avoid infinite loop due to buggy fw */ } while (num_returned && num_remaining); @@ -204,55 +204,52 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle, devm_kfree(dev, v->levels_uv); } - scmi_reset_rx_to_maxsz(handle, td); + ph->xops->reset_rx_to_maxsz(ph, td); } - scmi_xfer_put(handle, tl); + ph->xops->xfer_put(ph, tl); outd: - scmi_xfer_put(handle, td); + ph->xops->xfer_put(ph, td); return ret; } -static int __scmi_voltage_get_u32(const struct scmi_handle *handle, +static int __scmi_voltage_get_u32(const struct scmi_protocol_handle *ph, u8 cmd_id, u32 domain_id, u32 *value) { int ret; struct scmi_xfer *t; - struct voltage_info *vinfo = handle->voltage_priv; + struct voltage_info *vinfo = ph->get_priv(ph); if (domain_id >= vinfo->num_domains) return -EINVAL; - ret = scmi_xfer_get_init(handle, cmd_id, - SCMI_PROTOCOL_VOLTAGE, - sizeof(__le32), 0, &t); + ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(__le32), 0, &t); if (ret) return ret; put_unaligned_le32(domain_id, t->tx.buf); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); if (!ret) *value = get_unaligned_le32(t->rx.buf); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_voltage_config_set(const struct scmi_handle *handle, +static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph, u32 domain_id, u32 config) { int ret; struct scmi_xfer *t; - struct voltage_info *vinfo = handle->voltage_priv; + struct voltage_info *vinfo = ph->get_priv(ph); struct scmi_msg_cmd_config_set *cmd; if (domain_id >= vinfo->num_domains) return -EINVAL; - ret = scmi_xfer_get_init(handle, VOLTAGE_CONFIG_SET, - SCMI_PROTOCOL_VOLTAGE, - sizeof(*cmd), 0, &t); + ret = ph->xops->xfer_get_init(ph, VOLTAGE_CONFIG_SET, + sizeof(*cmd), 0, &t); if (ret) return ret; @@ -260,33 +257,32 @@ static int scmi_voltage_config_set(const struct scmi_handle *handle, cmd->domain_id = cpu_to_le32(domain_id); cmd->config = cpu_to_le32(config & GENMASK(3, 0)); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_voltage_config_get(const struct scmi_handle *handle, +static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph, u32 domain_id, u32 *config) { - return __scmi_voltage_get_u32(handle, VOLTAGE_CONFIG_GET, + return __scmi_voltage_get_u32(ph, VOLTAGE_CONFIG_GET, domain_id, config); } -static int scmi_voltage_level_set(const struct scmi_handle *handle, +static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph, u32 domain_id, u32 flags, s32 volt_uV) { int ret; struct scmi_xfer *t; - struct voltage_info *vinfo = handle->voltage_priv; + struct voltage_info *vinfo = ph->get_priv(ph); struct scmi_msg_cmd_level_set *cmd; if (domain_id >= vinfo->num_domains) return -EINVAL; - ret = scmi_xfer_get_init(handle, VOLTAGE_LEVEL_SET, - SCMI_PROTOCOL_VOLTAGE, - sizeof(*cmd), 0, &t); + ret = ph->xops->xfer_get_init(ph, VOLTAGE_LEVEL_SET, + sizeof(*cmd), 0, &t); if (ret) return ret; @@ -295,23 +291,23 @@ static int scmi_voltage_level_set(const struct scmi_handle *handle, cmd->flags = cpu_to_le32(flags); cmd->voltage_level = cpu_to_le32(volt_uV); - ret = scmi_do_xfer(handle, t); + ret = ph->xops->do_xfer(ph, t); - scmi_xfer_put(handle, t); + ph->xops->xfer_put(ph, t); return ret; } -static int scmi_voltage_level_get(const struct scmi_handle *handle, +static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph, u32 domain_id, s32 *volt_uV) { - return __scmi_voltage_get_u32(handle, VOLTAGE_LEVEL_GET, + return __scmi_voltage_get_u32(ph, VOLTAGE_LEVEL_GET, domain_id, (u32 *)volt_uV); } static const struct scmi_voltage_info * __must_check -scmi_voltage_info_get(const struct scmi_handle *handle, u32 domain_id) +scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id) { - struct voltage_info *vinfo = handle->voltage_priv; + struct voltage_info *vinfo = ph->get_priv(ph); if (domain_id >= vinfo->num_domains || !vinfo->domains[domain_id].num_levels) @@ -320,14 +316,14 @@ scmi_voltage_info_get(const struct scmi_handle *handle, u32 domain_id) return vinfo->domains + domain_id; } -static int scmi_voltage_domains_num_get(const struct scmi_handle *handle) +static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph) { - struct voltage_info *vinfo = handle->voltage_priv; + struct voltage_info *vinfo = ph->get_priv(ph); return vinfo->num_domains; } -static struct scmi_voltage_ops voltage_ops = { +static struct scmi_voltage_proto_ops voltage_proto_ops = { .num_domains_get = scmi_voltage_domains_num_get, .info_get = scmi_voltage_info_get, .config_set = scmi_voltage_config_set, @@ -336,45 +332,49 @@ static struct scmi_voltage_ops voltage_ops = { .level_get = scmi_voltage_level_get, }; -static int scmi_voltage_protocol_init(struct scmi_handle *handle) +static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph) { int ret; u32 version; struct voltage_info *vinfo; - ret = scmi_version_get(handle, SCMI_PROTOCOL_VOLTAGE, &version); + ret = ph->xops->version_get(ph, &version); if (ret) return ret; - dev_dbg(handle->dev, "Voltage Version %d.%d\n", + dev_dbg(ph->dev, "Voltage Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - vinfo = devm_kzalloc(handle->dev, sizeof(*vinfo), GFP_KERNEL); + vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL); if (!vinfo) return -ENOMEM; vinfo->version = version; - ret = scmi_protocol_attributes_get(handle, vinfo); + ret = scmi_protocol_attributes_get(ph, vinfo); if (ret) return ret; if (vinfo->num_domains) { - vinfo->domains = devm_kcalloc(handle->dev, vinfo->num_domains, + vinfo->domains = devm_kcalloc(ph->dev, vinfo->num_domains, sizeof(*vinfo->domains), GFP_KERNEL); if (!vinfo->domains) return -ENOMEM; - ret = scmi_voltage_descriptors_get(handle, vinfo); + ret = scmi_voltage_descriptors_get(ph, vinfo); if (ret) return ret; } else { - dev_warn(handle->dev, "No Voltage domains found.\n"); + dev_warn(ph->dev, "No Voltage domains found.\n"); } - handle->voltage_ops = &voltage_ops; - handle->voltage_priv = vinfo; - - return 0; + return ph->set_priv(ph, vinfo); } -DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_VOLTAGE, voltage) +static const struct scmi_protocol scmi_voltage = { + .id = SCMI_PROTOCOL_VOLTAGE, + .owner = THIS_MODULE, + .instance_init = &scmi_voltage_protocol_init, + .ops = &voltage_proto_ops, +}; + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage) diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 86d71b0212b1bd74a3548f60cbd7c7a8dc464ca3..4d5421d14a410e8aedb9bb9ae94aa71051d2efc8 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -85,6 +85,7 @@ static ssize_t get_modalias(char *buffer, size_t buffer_size) { "svn", DMI_SYS_VENDOR }, { "pn", DMI_PRODUCT_NAME }, { "pvr", DMI_PRODUCT_VERSION }, + { "sku", DMI_PRODUCT_SKU }, { "rvn", DMI_BOARD_VENDOR }, { "rn", DMI_BOARD_NAME }, { "rvr", DMI_BOARD_VERSION }, diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index c23466e05e60dff3fd1a6cab9f7dd84c68bc4391..d0537573501e9353446bd45dcf6bf7da026551d1 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -13,7 +13,8 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ -Wno-pointer-sign \ $(call cc-disable-warning, address-of-packed-member) \ $(call cc-disable-warning, gnu) \ - -fno-asynchronous-unwind-tables + -fno-asynchronous-unwind-tables \ + $(CLANG_FLAGS) # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly # disable the stackleak plugin diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 3d77f26c1e8c938796f4b15a3b68459ad100c6b0..bb6e77ee3898c16979542b47024e7526b9e6871d 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -136,12 +136,16 @@ MODULE_PARM_DESC(spincount, "The number of loop iterations to use when using the spin handshake."); /* - * Platforms might not support S0ix logging in their GSMI handlers. In order to - * avoid any side-effects of generating an SMI for S0ix logging, use the S0ix - * related GSMI commands only for those platforms that explicitly enable this - * option. + * Some older platforms with Apollo Lake chipsets do not support S0ix logging + * in their GSMI handlers, and behaved poorly when resuming via power button + * press if the logging was attempted. Updated firmware with proper behavior + * has long since shipped, removing the need for this opt-in parameter. It + * now exists as an opt-out parameter for folks defiantly running old + * firmware, or unforeseen circumstances. After the change from opt-in to + * opt-out has baked sufficiently, this parameter should probably be removed + * entirely. */ -static bool s0ix_logging_enable; +static bool s0ix_logging_enable = true; module_param(s0ix_logging_enable, bool, 0600); static struct gsmi_buf *gsmi_buf_alloc(void) diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 08533ee6762612dedb6f0eebfa255a6ea1d0dfb2..ff6569c4a53bd0a1a97f214620e2b96af374cf32 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -29,6 +29,10 @@ * The framework needs some proper extension to support multi power * domain cases. * + * Update: Genpd assigns the ->of_node for the virtual device before it + * invokes ->attach_dev() callback, hence parsing for device resources via + * DT should work fine. + * * 2. It also breaks most of current drivers as the driver probe sequence * behavior changed if removing ->power_on|off() callback and use * ->start() and ->stop() instead. genpd_dev_pm_attach will only power @@ -39,8 +43,11 @@ * domain enabled will trigger a HW access error. That means we need fix * most drivers probe sequence with proper runtime pm. * - * In summary, we need fix above two issue before being able to switch to - * the "single global power domain" way. + * Update: Runtime PM support isn't necessary. Instead, this can easily be + * fixed in drivers by adding a call to dev_pm_domain_start() during probe. + * + * In summary, the second part needs to be addressed via minor updates to the + * relevant drivers, before the "single global power domain" model can be used. * */ @@ -86,6 +93,8 @@ struct imx_sc_pd_soc { u8 num_ranges; }; +static int imx_con_rsrc; + static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { /* LSIO SS */ { "pwm", IMX_SC_R_PWM_0, 8, true, 0 }, @@ -134,7 +143,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "can", IMX_SC_R_CAN_0, 3, true, 0 }, { "ftm", IMX_SC_R_FTM_0, 2, true, 0 }, { "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 }, - { "adc", IMX_SC_R_ADC_0, 1, true, 0 }, + { "adc", IMX_SC_R_ADC_0, 2, true, 0 }, { "lcd", IMX_SC_R_LCD_0, 1, true, 0 }, { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 }, { "lpuart", IMX_SC_R_UART_0, 4, true, 0 }, @@ -207,6 +216,23 @@ to_imx_sc_pd(struct generic_pm_domain *genpd) return container_of(genpd, struct imx_sc_pm_domain, pd); } +static void imx_sc_pd_get_console_rsrc(void) +{ + struct of_phandle_args specs; + int ret; + + if (!of_stdout) + return; + + ret = of_parse_phandle_with_args(of_stdout, "power-domains", + "#power-domain-cells", + 0, &specs); + if (ret) + return; + + imx_con_rsrc = specs.args[0]; +} + static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on) { struct imx_sc_msg_req_set_resource_power_mode msg; @@ -267,6 +293,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx, const struct imx_sc_pd_range *pd_ranges) { struct imx_sc_pm_domain *sc_pd; + bool is_off = true; int ret; if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx)) @@ -288,6 +315,10 @@ imx_scu_add_pm_domain(struct device *dev, int idx, "%s", pd_ranges->name); sc_pd->pd.name = sc_pd->name; + if (imx_con_rsrc == sc_pd->rsrc) { + sc_pd->pd.flags = GENPD_FLAG_RPM_ALWAYS_ON; + is_off = false; + } if (sc_pd->rsrc >= IMX_SC_R_LAST) { dev_warn(dev, "invalid pd %s rsrc id %d found", @@ -297,7 +328,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx, return NULL; } - ret = pm_genpd_init(&sc_pd->pd, NULL, true); + ret = pm_genpd_init(&sc_pd->pd, NULL, is_off); if (ret) { dev_warn(dev, "failed to init pd %s rsrc id %d", sc_pd->name, sc_pd->rsrc); @@ -363,6 +394,8 @@ static int imx_sc_pd_probe(struct platform_device *pdev) if (!pd_soc) return -ENODEV; + imx_sc_pd_get_console_rsrc(); + return imx_scu_init_pm_domains(&pdev->dev, pd_soc); } diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index 5a0e3af512a82386601d05a7a494e4af17532674..b009da3e31bfd32aba6f0a6666cb6971e20c1aeb 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -333,8 +333,9 @@ static int __init psci_features(u32 psci_func_id) static int psci_suspend_finisher(unsigned long state) { u32 power_state = state; + phys_addr_t pa_cpu_resume = __pa_symbol(function_nocfi(cpu_resume)); - return psci_ops.cpu_suspend(power_state, __pa_symbol(cpu_resume)); + return psci_ops.cpu_suspend(power_state, pa_cpu_resume); } int psci_cpu_suspend_enter(u32 state) @@ -352,8 +353,10 @@ int psci_cpu_suspend_enter(u32 state) static int psci_system_suspend(unsigned long unused) { + phys_addr_t pa_cpu_resume = __pa_symbol(function_nocfi(cpu_resume)); + return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), - __pa_symbol(cpu_resume), 0, 0); + pa_cpu_resume, 0, 0); } static int psci_system_suspend_enter(suspend_state_t state) diff --git a/drivers/firmware/qcom_scm-legacy.c b/drivers/firmware/qcom_scm-legacy.c index eba6b60bfb61fcaa8b9f560dcb8c834f1fe00997..1829ba220576b7839939fc1c1e84daa58008a9d3 100644 --- a/drivers/firmware/qcom_scm-legacy.c +++ b/drivers/firmware/qcom_scm-legacy.c @@ -118,7 +118,7 @@ static void __scm_legacy_do(const struct arm_smccc_args *smc, } /** - * qcom_scm_call() - Sends a command to the SCM and waits for the command to + * scm_legacy_call() - Sends a command to the SCM and waits for the command to * finish processing. * * A note on cache maintenance: @@ -209,7 +209,7 @@ out: (n & 0xf)) /** - * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments + * scm_legacy_call_atomic() - Send an atomic SCM command with up to 5 arguments * and 3 return values * @desc: SCM call descriptor containing arguments * @res: SCM call return values diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c index 497c13ba98d67f15651fd3979dfacf98475d7c29..d111833364ba4f3f5b93faad475be307569ec0e4 100644 --- a/drivers/firmware/qcom_scm-smc.c +++ b/drivers/firmware/qcom_scm-smc.c @@ -77,8 +77,10 @@ static void __scm_smc_do(const struct arm_smccc_args *smc, } while (res->a0 == QCOM_SCM_V2_EBUSY); } -int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, - struct qcom_scm_res *res, bool atomic) + +int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, + enum qcom_scm_convention qcom_convention, + struct qcom_scm_res *res, bool atomic) { int arglen = desc->arginfo & 0xf; int i; @@ -87,9 +89,8 @@ int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, size_t alloc_len; gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL; u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL; - u32 qcom_smccc_convention = - (qcom_scm_convention == SMC_CONVENTION_ARM_32) ? - ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64; + u32 qcom_smccc_convention = (qcom_convention == SMC_CONVENTION_ARM_32) ? + ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64; struct arm_smccc_res smc_res; struct arm_smccc_args smc = {0}; @@ -148,4 +149,5 @@ int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, } return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0; + } diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 31fc5fa817d8b1407fd0f7e334add4bf772c83c7..bb9ce3f92931aab5208c010e13098014dbbd55fb 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -113,14 +113,10 @@ static void qcom_scm_clk_disable(void) clk_disable_unprepare(__scm->bus_clk); } -static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, - u32 cmd_id); +enum qcom_scm_convention qcom_scm_convention = SMC_CONVENTION_UNKNOWN; +static DEFINE_SPINLOCK(scm_query_lock); -enum qcom_scm_convention qcom_scm_convention; -static bool has_queried __read_mostly; -static DEFINE_SPINLOCK(query_lock); - -static void __query_convention(void) +static enum qcom_scm_convention __get_convention(void) { unsigned long flags; struct qcom_scm_desc desc = { @@ -133,36 +129,50 @@ static void __query_convention(void) .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; + enum qcom_scm_convention probed_convention; int ret; + bool forced = false; - spin_lock_irqsave(&query_lock, flags); - if (has_queried) - goto out; + if (likely(qcom_scm_convention != SMC_CONVENTION_UNKNOWN)) + return qcom_scm_convention; - qcom_scm_convention = SMC_CONVENTION_ARM_64; - // Device isn't required as there is only one argument - no device - // needed to dma_map_single to secure world - ret = scm_smc_call(NULL, &desc, &res, true); + /* + * Device isn't required as there is only one argument - no device + * needed to dma_map_single to secure world + */ + probed_convention = SMC_CONVENTION_ARM_64; + ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true); if (!ret && res.result[0] == 1) - goto out; + goto found; + + /* + * Some SC7180 firmwares didn't implement the + * QCOM_SCM_INFO_IS_CALL_AVAIL call, so we fallback to forcing ARM_64 + * calling conventions on these firmwares. Luckily we don't make any + * early calls into the firmware on these SoCs so the device pointer + * will be valid here to check if the compatible matches. + */ + if (of_device_is_compatible(__scm ? __scm->dev->of_node : NULL, "qcom,scm-sc7180")) { + forced = true; + goto found; + } - qcom_scm_convention = SMC_CONVENTION_ARM_32; - ret = scm_smc_call(NULL, &desc, &res, true); + probed_convention = SMC_CONVENTION_ARM_32; + ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true); if (!ret && res.result[0] == 1) - goto out; - - qcom_scm_convention = SMC_CONVENTION_LEGACY; -out: - has_queried = true; - spin_unlock_irqrestore(&query_lock, flags); - pr_info("qcom_scm: convention: %s\n", - qcom_scm_convention_names[qcom_scm_convention]); -} + goto found; + + probed_convention = SMC_CONVENTION_LEGACY; +found: + spin_lock_irqsave(&scm_query_lock, flags); + if (probed_convention != qcom_scm_convention) { + qcom_scm_convention = probed_convention; + pr_info("qcom_scm: convention: %s%s\n", + qcom_scm_convention_names[qcom_scm_convention], + forced ? " (forced)" : ""); + } + spin_unlock_irqrestore(&scm_query_lock, flags); -static inline enum qcom_scm_convention __get_convention(void) -{ - if (unlikely(!has_queried)) - __query_convention(); return qcom_scm_convention; } @@ -219,8 +229,8 @@ static int qcom_scm_call_atomic(struct device *dev, } } -static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, - u32 cmd_id) +static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id, + u32 cmd_id) { int ret; struct qcom_scm_desc desc = { @@ -247,7 +257,7 @@ static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, ret = qcom_scm_call(dev, &desc, &res); - return ret ? : res.result[0]; + return ret ? false : !!res.result[0]; } /** @@ -585,9 +595,8 @@ bool qcom_scm_pas_supported(u32 peripheral) }; struct qcom_scm_res res; - ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, - QCOM_SCM_PIL_PAS_IS_SUPPORTED); - if (ret <= 0) + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PIL_PAS_IS_SUPPORTED)) return false; ret = qcom_scm_call(__scm->dev, &desc, &res); @@ -1060,17 +1069,18 @@ EXPORT_SYMBOL(qcom_scm_ice_set_key); */ bool qcom_scm_hdcp_available(void) { + bool avail; int ret = qcom_scm_clk_enable(); if (ret) return ret; - ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP, + avail = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE); qcom_scm_clk_disable(); - return ret > 0; + return avail; } EXPORT_SYMBOL(qcom_scm_hdcp_available); @@ -1242,7 +1252,7 @@ static int qcom_scm_probe(struct platform_device *pdev) __scm = scm; __scm->dev = &pdev->dev; - __query_convention(); + __get_convention(); /* * If requested enable "download mode", from this point on warmboot @@ -1292,6 +1302,7 @@ static struct platform_driver qcom_scm_driver = { .driver = { .name = "qcom_scm", .of_match_table = qcom_scm_dt_match, + .suppress_bind_attrs = true, }, .probe = qcom_scm_probe, .shutdown = qcom_scm_shutdown, diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 95cd1ac30ab0bb23c57b212a84eb773ae1079330..632fe31424621a79f4793e8d0ee99c53320ae2ff 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -61,8 +61,11 @@ struct qcom_scm_res { }; #define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) -extern int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, - struct qcom_scm_res *res, bool atomic); +extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, + enum qcom_scm_convention qcom_convention, + struct qcom_scm_res *res, bool atomic); +#define scm_smc_call(dev, desc, res, atomic) \ + __scm_smc_call((dev), (desc), qcom_scm_convention, (res), (atomic)) #define SCM_LEGACY_FNID(s, c) (((s) << 10) | ((c) & 0x3ff)) extern int scm_legacy_call_atomic(struct device *dev, diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 30259dc9b805a41dcc31692f09519ba213bca253..250e016807422cd35d3595eeaede241c21de6616 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -7,6 +7,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/kref.h> #include <linux/mailbox_client.h> #include <linux/module.h> #include <linux/of_platform.h> @@ -27,6 +28,8 @@ struct rpi_firmware { struct mbox_chan *chan; /* The property channel. */ struct completion c; u32 enabled; + + struct kref consumers; }; static DEFINE_MUTEX(transaction_lock); @@ -225,12 +228,38 @@ static void rpi_register_clk_driver(struct device *dev) -1, NULL, 0); } +static void rpi_firmware_delete(struct kref *kref) +{ + struct rpi_firmware *fw = container_of(kref, struct rpi_firmware, + consumers); + + mbox_free_channel(fw->chan); + kfree(fw); +} + +void rpi_firmware_put(struct rpi_firmware *fw) +{ + kref_put(&fw->consumers, rpi_firmware_delete); +} +EXPORT_SYMBOL_GPL(rpi_firmware_put); + +static void devm_rpi_firmware_put(void *data) +{ + struct rpi_firmware *fw = data; + + rpi_firmware_put(fw); +} + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpi_firmware *fw; - fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); + /* + * Memory will be freed by rpi_firmware_delete() once all users have + * released their firmware handles. Don't use devm_kzalloc() here. + */ + fw = kzalloc(sizeof(*fw), GFP_KERNEL); if (!fw) return -ENOMEM; @@ -247,6 +276,7 @@ static int rpi_firmware_probe(struct platform_device *pdev) } init_completion(&fw->c); + kref_init(&fw->consumers); platform_set_drvdata(pdev, fw); @@ -275,7 +305,8 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_hwmon = NULL; platform_device_unregister(rpi_clk); rpi_clk = NULL; - mbox_free_channel(fw->chan); + + rpi_firmware_put(fw); return 0; } @@ -284,19 +315,51 @@ static int rpi_firmware_remove(struct platform_device *pdev) * rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. * + * The reference to rpi_firmware has to be released with rpi_firmware_put(). + * * Returns NULL is the firmware device is not ready. */ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { struct platform_device *pdev = of_find_device_by_node(firmware_node); + struct rpi_firmware *fw; if (!pdev) return NULL; - return platform_get_drvdata(pdev); + fw = platform_get_drvdata(pdev); + if (!fw) + return NULL; + + if (!kref_get_unless_zero(&fw->consumers)) + return NULL; + + return fw; } EXPORT_SYMBOL_GPL(rpi_firmware_get); +/** + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. + * @firmware_node: Pointer to the firmware Device Tree node. + * + * Returns NULL is the firmware device is not ready. + */ +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + struct rpi_firmware *fw; + + fw = rpi_firmware_get(firmware_node); + if (!fw) + return NULL; + + if (devm_add_action_or_reset(dev, devm_rpi_firmware_put, fw)) + return NULL; + + return fw; +} +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); + static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 7eb9958662dddddfc673da9b321d812b5ab7a169..83082e2f2e441f6d53f1f3d40d495edebfb5d23c 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -2,7 +2,7 @@ /* * Xilinx Zynq MPSoC Firmware layer * - * Copyright (C) 2014-2020 Xilinx, Inc. + * Copyright (C) 2014-2021 Xilinx, Inc. * * Michal Simek <michal.simek@xilinx.com> * Davorin Mista <davorin.mista@aggios.com> @@ -1280,12 +1280,13 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) static int zynqmp_firmware_remove(struct platform_device *pdev) { struct pm_api_feature_data *feature_data; + struct hlist_node *tmp; int i; mfd_remove_devices(&pdev->dev); zynqmp_pm_api_debugfs_exit(); - hash_for_each(pm_api_features_map, i, feature_data, hentry) { + hash_for_each_safe(pm_api_features_map, i, tmp, feature_data, hentry) { hash_del(&feature_data->hentry); kfree(feature_data); } diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 5ff9438b7b4611803aedf34ebc3e004a0be0de60..33e15058d0dc7a69f31363d248f9f2e2097c42a4 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -14,13 +14,13 @@ if FPGA config FPGA_MGR_SOCFPGA tristate "Altera SOCFPGA FPGA Manager" - depends on ARCH_SOCFPGA || COMPILE_TEST + depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST help FPGA manager driver support for Altera SOCFPGA. config FPGA_MGR_SOCFPGA_A10 tristate "Altera SoCFPGA Arria10" - depends on ARCH_SOCFPGA || COMPILE_TEST + depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST select REGMAP_MMIO help FPGA manager driver support for Altera Arria10 SoCFPGA. @@ -60,7 +60,7 @@ config FPGA_MGR_ZYNQ_FPGA config FPGA_MGR_STRATIX10_SOC tristate "Intel Stratix10 SoC FPGA Manager" - depends on (ARCH_STRATIX10 && INTEL_STRATIX10_SERVICE) + depends on (ARCH_INTEL_SOCFPGA && INTEL_STRATIX10_SERVICE) help FPGA manager driver support for the Intel Stratix10 SoC. @@ -99,7 +99,7 @@ config FPGA_BRIDGE config SOCFPGA_FPGA_BRIDGE tristate "Altera SoCFPGA FPGA Bridges" - depends on ARCH_SOCFPGA && FPGA_BRIDGE + depends on ARCH_INTEL_SOCFPGA && FPGA_BRIDGE help Say Y to enable drivers for FPGA bridges for Altera SOCFPGA devices. @@ -118,10 +118,17 @@ config XILINX_PR_DECOUPLER depends on FPGA_BRIDGE depends on HAS_IOMEM help - Say Y to enable drivers for Xilinx LogiCORE PR Decoupler. + Say Y to enable drivers for Xilinx LogiCORE PR Decoupler + or Xilinx Dynamic Function eXchnage AIX Shutdown Manager. The PR Decoupler exists in the FPGA fabric to isolate one region of the FPGA from the busses while that region is being reprogrammed during partial reconfig. + The Dynamic Function eXchange AXI shutdown manager prevents + AXI traffic from passing through the bridge. The controller + safely handles AXI4MM and AXI4-Lite interfaces on a + Reconfigurable Partition when it is undergoing dynamic + reconfiguration, preventing the system deadlock that can + occur if AXI transactions are interrupted by DFX. config FPGA_REGION tristate "FPGA Region" diff --git a/drivers/fpga/dfl-afu-error.c b/drivers/fpga/dfl-afu-error.c index c4691187cca9118f278ad3894dc95ff638567740..ab7be62173681ae0a0c97676d319eb5032ed30f2 100644 --- a/drivers/fpga/dfl-afu-error.c +++ b/drivers/fpga/dfl-afu-error.c @@ -52,7 +52,7 @@ static int afu_port_err_clear(struct device *dev, u64 err) struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); struct platform_device *pdev = to_platform_device(dev); void __iomem *base_err, *base_hdr; - int ret = -EBUSY; + int enable_ret = 0, ret = -EBUSY; u64 v; base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); @@ -96,18 +96,20 @@ static int afu_port_err_clear(struct device *dev, u64 err) v = readq(base_err + PORT_FIRST_ERROR); writeq(v, base_err + PORT_FIRST_ERROR); } else { + dev_warn(dev, "%s: received 0x%llx, expected 0x%llx\n", + __func__, v, err); ret = -EINVAL; } /* Clear mask */ __afu_port_err_mask(dev, false); - /* Enable the Port by clear the reset */ - __afu_port_enable(pdev); + /* Enable the Port by clearing the reset */ + enable_ret = __afu_port_enable(pdev); done: mutex_unlock(&pdata->lock); - return ret; + return enable_ret ? enable_ret : ret; } static ssize_t errors_show(struct device *dev, struct device_attribute *attr, diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index 753cda4b2568380ec9b9fed5f0ae8a0140b5c3db..7f621e96d3b8d8fb0dce599a07a4394b3a702895 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -21,6 +21,9 @@ #include "dfl-afu.h" +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + /** * __afu_port_enable - enable a port by clear reset * @pdev: port platform device. @@ -32,7 +35,7 @@ * * The caller needs to hold lock for protection. */ -void __afu_port_enable(struct platform_device *pdev) +int __afu_port_enable(struct platform_device *pdev) { struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; @@ -41,7 +44,7 @@ void __afu_port_enable(struct platform_device *pdev) WARN_ON(!pdata->disable_count); if (--pdata->disable_count != 0) - return; + return 0; base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); @@ -49,10 +52,20 @@ void __afu_port_enable(struct platform_device *pdev) v = readq(base + PORT_HDR_CTRL); v &= ~PORT_CTRL_SFTRST; writeq(v, base + PORT_HDR_CTRL); -} -#define RST_POLL_INVL 10 /* us */ -#define RST_POLL_TIMEOUT 1000 /* us */ + /* + * HW clears the ack bit to indicate that the port is fully out + * of reset. + */ + if (readq_poll_timeout(base + PORT_HDR_CTRL, v, + !(v & PORT_CTRL_SFTRST_ACK), + RST_POLL_INVL, RST_POLL_TIMEOUT)) { + dev_err(&pdev->dev, "timeout, failure to enable device\n"); + return -ETIMEDOUT; + } + + return 0; +} /** * __afu_port_disable - disable a port by hold reset @@ -86,7 +99,7 @@ int __afu_port_disable(struct platform_device *pdev) if (readq_poll_timeout(base + PORT_HDR_CTRL, v, v & PORT_CTRL_SFTRST_ACK, RST_POLL_INVL, RST_POLL_TIMEOUT)) { - dev_err(&pdev->dev, "timeout, fail to reset device\n"); + dev_err(&pdev->dev, "timeout, failure to disable device\n"); return -ETIMEDOUT; } @@ -110,10 +123,10 @@ static int __port_reset(struct platform_device *pdev) int ret; ret = __afu_port_disable(pdev); - if (!ret) - __afu_port_enable(pdev); + if (ret) + return ret; - return ret; + return __afu_port_enable(pdev); } static int port_reset(struct platform_device *pdev) @@ -872,11 +885,11 @@ static int afu_dev_destroy(struct platform_device *pdev) static int port_enable_set(struct platform_device *pdev, bool enable) { struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); - int ret = 0; + int ret; mutex_lock(&pdata->lock); if (enable) - __afu_port_enable(pdev); + ret = __afu_port_enable(pdev); else ret = __afu_port_disable(pdev); mutex_unlock(&pdata->lock); diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h index 576e9496008634a400fe73a0d57bfe93e8a9fbbf..e5020e2b1f3df634115b55533234a455be426b55 100644 --- a/drivers/fpga/dfl-afu.h +++ b/drivers/fpga/dfl-afu.h @@ -80,7 +80,7 @@ struct dfl_afu { }; /* hold pdata->lock when call __afu_port_enable/disable */ -void __afu_port_enable(struct platform_device *pdev); +int __afu_port_enable(struct platform_device *pdev); int __afu_port_disable(struct platform_device *pdev); void afu_mmio_region_init(struct dfl_feature_platform_data *pdata); diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index 04e47e266f26d0641e36d3d1b44e7fd1e1f8a61b..b44523ea8c91a407df4fadd8094fa7d61cd2759c 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -69,14 +69,16 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) } /* PCI Device ID */ -#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD -#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 -#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 -#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 +#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD +#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 +#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 +#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 +#define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B /* VF Device */ -#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF -#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 -#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 +#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF +#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 +#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 +#define PCIE_DEVICE_ID_INTEL_PAC_D5005_VF 0x0B2C static struct pci_device_id cci_pcie_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X),}, @@ -86,6 +88,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, {0,} }; MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 7d69af23056773136fa4611d0dd7d178ee2e4567..ea2bde6e5bc4e101b8a5ad116aea8336dba7d654 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017, National Instruments Corp. - * Copyright (c) 2017, Xilix Inc + * Copyright (c) 2017, Xilinx Inc * * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration * Decoupler IP Core. @@ -18,7 +18,12 @@ #define CTRL_CMD_COUPLE 0 #define CTRL_OFFSET 0 +struct xlnx_config_data { + const char *name; +}; + struct xlnx_pr_decoupler_data { + const struct xlnx_config_data *ipconfig; void __iomem *io_base; struct clk *clk; }; @@ -76,15 +81,28 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { .enable_show = xlnx_pr_decoupler_enable_show, }; +static const struct xlnx_config_data decoupler_config = { + .name = "Xilinx PR Decoupler", +}; + +static const struct xlnx_config_data shutdown_config = { + .name = "Xilinx DFX AXI Shutdown Manager", +}; + static const struct of_device_id xlnx_pr_decoupler_of_match[] = { - { .compatible = "xlnx,pr-decoupler-1.00", }, - { .compatible = "xlnx,pr-decoupler", }, + { .compatible = "xlnx,pr-decoupler-1.00", .data = &decoupler_config }, + { .compatible = "xlnx,pr-decoupler", .data = &decoupler_config }, + { .compatible = "xlnx,dfx-axi-shutdown-manager-1.00", + .data = &shutdown_config }, + { .compatible = "xlnx,dfx-axi-shutdown-manager", + .data = &shutdown_config }, {}, }; MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); static int xlnx_pr_decoupler_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct xlnx_pr_decoupler_data *priv; struct fpga_bridge *br; int err; @@ -94,17 +112,23 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + if (np) { + const struct of_device_id *match; + + match = of_match_node(xlnx_pr_decoupler_of_match, np); + if (match && match->data) + priv->ipconfig = match->data; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->io_base)) return PTR_ERR(priv->io_base); priv->clk = devm_clk_get(&pdev->dev, "aclk"); - if (IS_ERR(priv->clk)) { - if (PTR_ERR(priv->clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "input clock not found\n"); - return PTR_ERR(priv->clk); - } + if (IS_ERR(priv->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), + "input clock not found\n"); err = clk_prepare_enable(priv->clk); if (err) { @@ -114,7 +138,7 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) clk_disable(priv->clk); - br = devm_fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler", + br = devm_fpga_bridge_create(&pdev->dev, priv->ipconfig->name, &xlnx_pr_decoupler_br_ops, priv); if (!br) { err = -ENOMEM; @@ -125,7 +149,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) err = fpga_bridge_register(br); if (err) { - dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); + dev_err(&pdev->dev, "unable to register %s", + priv->ipconfig->name); goto err_clk; } diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 27defa98092ddce55d56d3ce3d980cc8104d7481..fee4d0abf6bfe6d349110420c60ecc854d81bf47 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -233,25 +233,19 @@ static int xilinx_spi_probe(struct spi_device *spi) /* PROGRAM_B is active low */ conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); - if (IS_ERR(conf->prog_b)) { - dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", - PTR_ERR(conf->prog_b)); - return PTR_ERR(conf->prog_b); - } + if (IS_ERR(conf->prog_b)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b), + "Failed to get PROGRAM_B gpio\n"); conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN); - if (IS_ERR(conf->init_b)) { - dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n", - PTR_ERR(conf->init_b)); - return PTR_ERR(conf->init_b); - } + if (IS_ERR(conf->init_b)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b), + "Failed to get INIT_B gpio\n"); conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); - if (IS_ERR(conf->done)) { - dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", - PTR_ERR(conf->done)); - return PTR_ERR(conf->done); - } + if (IS_ERR(conf->done)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->done), + "Failed to get DONE gpio\n"); mgr = devm_fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager", diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index bb100e0124e6306698a71c40e721c3fce51a6467..64a552ecc2addde9f9df9c9e1e23295d2d105f80 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -208,7 +208,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index e0b11671703b9e874c20d4c75163c3fe46714c24..c361d472d5ea8c363939e324fed26f04454fee1f 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1290,7 +1290,8 @@ EXPORT_SYMBOL(drm_mode_prune_invalid); * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or * positive if @lh_b is better than @lh_a. */ -static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b) +static int drm_mode_compare(void *priv, const struct list_head *lh_a, + const struct list_head *lh_b) { struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c index 34e6096f196ed8eb647cfcce68faf427a23e60cf..da21d2a10cc94222ba8e1dd2ad35a2e10a6df16d 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_user.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c @@ -49,7 +49,8 @@ static const u8 uabi_classes[] = { [VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE, }; -static int engine_cmp(void *priv, struct list_head *A, struct list_head *B) +static int engine_cmp(void *priv, const struct list_head *A, + const struct list_head *B) { const struct intel_engine_cs *a = container_of((struct rb_node *)A, typeof(*a), uabi_node); diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c index 62e6a14ad58ef78caaa0875c59d70d0059a07368..9f1c209d9251107f95cad7ea4c28e62cf505439f 100644 --- a/drivers/gpu/drm/i915/gvt/debugfs.c +++ b/drivers/gpu/drm/i915/gvt/debugfs.c @@ -41,7 +41,7 @@ struct diff_mmio { /* Compare two diff_mmio items. */ static int mmio_offset_compare(void *priv, - struct list_head *a, struct list_head *b) + const struct list_head *a, const struct list_head *b) { struct diff_mmio *ma; struct diff_mmio *mb; diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index e622aee6e4be90a599f29ae3496108714580f67a..440c35f1abc9e130fdd2053ac399f6b907698d50 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -105,7 +105,7 @@ static inline bool tasklet_is_locked(const struct tasklet_struct *t) static inline void __tasklet_disable_sync_once(struct tasklet_struct *t) { if (!atomic_fetch_inc(&t->count)) - tasklet_unlock_wait(t); + tasklet_unlock_spin_wait(t); } static inline bool __tasklet_is_enabled(const struct tasklet_struct *t) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4b4d8d034782fc6e63761832542dfd1b30b5c1bf..4ba20f959a71a4a09a5bf57eaf77bf5d92d840e5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2993,7 +2993,7 @@ int ilk_wm_max_level(const struct drm_i915_private *dev_priv) static void intel_print_wm_latency(struct drm_i915_private *dev_priv, const char *name, - const u16 wm[8]) + const u16 wm[]) { int level, max_level = ilk_wm_max_level(dev_priv); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index c1adea8765a97cffbfe474ddbb1eafe697cac2b7..52b9c39e015592d8d992a5ea34b3f05024b7bdd7 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1076,7 +1076,8 @@ static int igt_ppgtt_shrink_boom(void *arg) return exercise_ppgtt(arg, shrink_boom); } -static int sort_holes(void *priv, struct list_head *A, struct list_head *B) +static int sort_holes(void *priv, const struct list_head *A, + const struct list_head *B) { struct drm_mm_node *a = list_entry(A, typeof(*a), hole_stack); struct drm_mm_node *b = list_entry(B, typeof(*b), hole_stack); diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c index 5686ad4aaf7c11d6ba70c432a787c6599b1d2140..dbc1d1eb954337271e300d31a9ae8e13828216de 100644 --- a/drivers/gpu/drm/lima/lima_devfreq.c +++ b/drivers/gpu/drm/lima/lima_devfreq.c @@ -99,20 +99,12 @@ void lima_devfreq_fini(struct lima_device *ldev) devm_devfreq_remove_device(ldev->dev, devfreq->devfreq); devfreq->devfreq = NULL; } - - dev_pm_opp_of_remove_table(ldev->dev); - - dev_pm_opp_put_regulators(devfreq->regulators_opp_table); - dev_pm_opp_put_clkname(devfreq->clkname_opp_table); - devfreq->regulators_opp_table = NULL; - devfreq->clkname_opp_table = NULL; } int lima_devfreq_init(struct lima_device *ldev) { struct thermal_cooling_device *cooling; struct device *dev = ldev->dev; - struct opp_table *opp_table; struct devfreq *devfreq; struct lima_devfreq *ldevfreq = &ldev->devfreq; struct dev_pm_opp *opp; @@ -125,40 +117,28 @@ int lima_devfreq_init(struct lima_device *ldev) spin_lock_init(&ldevfreq->lock); - opp_table = dev_pm_opp_set_clkname(dev, "core"); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); - goto err_fini; - } - - ldevfreq->clkname_opp_table = opp_table; - - opp_table = dev_pm_opp_set_regulators(dev, - (const char *[]){ "mali" }, - 1); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); + ret = devm_pm_opp_set_clkname(dev, "core"); + if (ret) + return ret; + ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1); + if (ret) { /* Continue if the optional regulator is missing */ if (ret != -ENODEV) - goto err_fini; - } else { - ldevfreq->regulators_opp_table = opp_table; + return ret; } - ret = dev_pm_opp_of_add_table(dev); + ret = devm_pm_opp_of_add_table(dev); if (ret) - goto err_fini; + return ret; lima_devfreq_reset(ldevfreq); cur_freq = clk_get_rate(ldev->clk_gpu); opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) { - ret = PTR_ERR(opp); - goto err_fini; - } + if (IS_ERR(opp)) + return PTR_ERR(opp); lima_devfreq_profile.initial_freq = cur_freq; dev_pm_opp_put(opp); @@ -167,8 +147,7 @@ int lima_devfreq_init(struct lima_device *ldev) DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); if (IS_ERR(devfreq)) { dev_err(dev, "Couldn't initialize GPU devfreq\n"); - ret = PTR_ERR(devfreq); - goto err_fini; + return PTR_ERR(devfreq); } ldevfreq->devfreq = devfreq; @@ -180,10 +159,6 @@ int lima_devfreq_init(struct lima_device *ldev) ldevfreq->cooling = cooling; return 0; - -err_fini: - lima_devfreq_fini(ldev); - return ret; } void lima_devfreq_record_busy(struct lima_devfreq *devfreq) diff --git a/drivers/gpu/drm/lima/lima_devfreq.h b/drivers/gpu/drm/lima/lima_devfreq.h index 2d9b3008ce778984e6473ff94b02c424514cd29a..688ee71e263a398e3586de2bd5258f7f93c3a1a6 100644 --- a/drivers/gpu/drm/lima/lima_devfreq.h +++ b/drivers/gpu/drm/lima/lima_devfreq.h @@ -8,15 +8,12 @@ #include <linux/ktime.h> struct devfreq; -struct opp_table; struct thermal_cooling_device; struct lima_device; struct lima_devfreq { struct devfreq *devfreq; - struct opp_table *clkname_opp_table; - struct opp_table *regulators_opp_table; struct thermal_cooling_device *cooling; ktime_t busy_time; diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 56b3f5935703ac88d9c904041fb953dc045df349..c878391f3e8cd0f52fba2741ea7c9c7ccf9b3257 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -89,29 +89,25 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) unsigned long cur_freq; struct device *dev = &pfdev->pdev->dev; struct devfreq *devfreq; - struct opp_table *opp_table; struct thermal_cooling_device *cooling; struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; - opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, - pfdev->comp->num_supplies); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); + ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names, + pfdev->comp->num_supplies); + if (ret) { /* Continue if the optional regulator is missing */ if (ret != -ENODEV) { DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); - goto err_fini; + return ret; } - } else { - pfdevfreq->regulators_opp_table = opp_table; } - ret = dev_pm_opp_of_add_table(dev); + ret = devm_pm_opp_of_add_table(dev); if (ret) { /* Optional, continue without devfreq */ if (ret == -ENODEV) ret = 0; - goto err_fini; + return ret; } pfdevfreq->opp_of_table_added = true; @@ -122,10 +118,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) cur_freq = clk_get_rate(pfdev->clock); opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) { - ret = PTR_ERR(opp); - goto err_fini; - } + if (IS_ERR(opp)) + return PTR_ERR(opp); panfrost_devfreq_profile.initial_freq = cur_freq; dev_pm_opp_put(opp); @@ -134,8 +128,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); if (IS_ERR(devfreq)) { DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); - ret = PTR_ERR(devfreq); - goto err_fini; + return PTR_ERR(devfreq); } pfdevfreq->devfreq = devfreq; @@ -146,10 +139,6 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) pfdevfreq->cooling = cooling; return 0; - -err_fini: - panfrost_devfreq_fini(pfdev); - return ret; } void panfrost_devfreq_fini(struct panfrost_device *pfdev) @@ -160,14 +149,6 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev) devfreq_cooling_unregister(pfdevfreq->cooling); pfdevfreq->cooling = NULL; } - - if (pfdevfreq->opp_of_table_added) { - dev_pm_opp_of_remove_table(&pfdev->pdev->dev); - pfdevfreq->opp_of_table_added = false; - } - - dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); - pfdevfreq->regulators_opp_table = NULL; } void panfrost_devfreq_resume(struct panfrost_device *pfdev) diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h index db6ea48e21f9c05178ae64bde882394169a5f4bd..2102699446874d539ce305382e89d4822af5613c 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h @@ -8,14 +8,12 @@ #include <linux/ktime.h> struct devfreq; -struct opp_table; struct thermal_cooling_device; struct panfrost_device; struct panfrost_devfreq { struct devfreq *devfreq; - struct opp_table *regulators_opp_table; struct thermal_cooling_device *cooling; bool opp_of_table_added; diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 35e937d39b51893e270029d4b7d566ce6546c8a5..1a5c3db1d53bc7818e24b31a18be71f8acaf443f 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -393,8 +393,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) return 0; } -static int cmp_size_smaller_first(void *priv, struct list_head *a, - struct list_head *b) +static int cmp_size_smaller_first(void *priv, const struct list_head *a, + const struct list_head *b) { struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head); struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head); diff --git a/drivers/greybus/es2.c b/drivers/greybus/es2.c index 48ad154df3a78c88092807787bb3d5db65d3a334..15661c7f363365a38e962975f1bb4158dbe7d92a 100644 --- a/drivers/greybus/es2.c +++ b/drivers/greybus/es2.c @@ -72,11 +72,11 @@ struct es2_cport_in { }; /** - * es2_ap_dev - ES2 USB Bridge to AP structure + * struct es2_ap_dev - ES2 USB Bridge to AP structure * @usb_dev: pointer to the USB device we are. * @usb_intf: pointer to the USB interface we are bound to. * @hd: pointer to our gb_host_device structure - + * * @cport_in: endpoint, urbs and buffer for cport in messages * @cport_out_endpoint: endpoint for for cport out messages * @cport_out_urb: array of urbs for the CPort out messages @@ -85,7 +85,7 @@ struct es2_cport_in { * @cport_out_urb_cancelled: array of flags indicating whether the * corresponding @cport_out_urb is being cancelled * @cport_out_urb_lock: locks the @cport_out_urb_busy "list" - * + * @cdsi1_in_use: true if cport CDSI1 is in use * @apb_log_task: task pointer for logging thread * @apb_log_dentry: file system entry for the log file interface * @apb_log_enable_dentry: file system entry for enabling logging @@ -1171,7 +1171,7 @@ static ssize_t apb_log_enable_read(struct file *f, char __user *buf, char tmp_buf[3]; sprintf(tmp_buf, "%d\n", enable); - return simple_read_from_buffer(buf, count, ppos, tmp_buf, 3); + return simple_read_from_buffer(buf, count, ppos, tmp_buf, 2); } static ssize_t apb_log_enable_write(struct file *f, const char __user *buf, diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 79e5356a737a2ad6b9fb19a498613eba20aa9761..66c794d92391fc73376934f5617652fcd8213b23 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -23,6 +23,7 @@ config HYPERV_UTILS config HYPERV_BALLOON tristate "Microsoft Hyper-V Balloon driver" depends on HYPERV + select PAGE_REPORTING help Select this option to enable Hyper-V Balloon driver. diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 0bd202de79600393062817ffa160222cd737074d..c2635e913a92f97d8d506f15b1424adc0ca59eba 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -209,31 +209,96 @@ int vmbus_send_tl_connect_request(const guid_t *shv_guest_servie_id, } EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request); +static int send_modifychannel_without_ack(struct vmbus_channel *channel, u32 target_vp) +{ + struct vmbus_channel_modifychannel msg; + int ret; + + memset(&msg, 0, sizeof(msg)); + msg.header.msgtype = CHANNELMSG_MODIFYCHANNEL; + msg.child_relid = channel->offermsg.child_relid; + msg.target_vp = target_vp; + + ret = vmbus_post_msg(&msg, sizeof(msg), true); + trace_vmbus_send_modifychannel(&msg, ret); + + return ret; +} + +static int send_modifychannel_with_ack(struct vmbus_channel *channel, u32 target_vp) +{ + struct vmbus_channel_modifychannel *msg; + struct vmbus_channel_msginfo *info; + unsigned long flags; + int ret; + + info = kzalloc(sizeof(struct vmbus_channel_msginfo) + + sizeof(struct vmbus_channel_modifychannel), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + init_completion(&info->waitevent); + info->waiting_channel = channel; + + msg = (struct vmbus_channel_modifychannel *)info->msg; + msg->header.msgtype = CHANNELMSG_MODIFYCHANNEL; + msg->child_relid = channel->offermsg.child_relid; + msg->target_vp = target_vp; + + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + list_add_tail(&info->msglistentry, &vmbus_connection.chn_msg_list); + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + + ret = vmbus_post_msg(msg, sizeof(*msg), true); + trace_vmbus_send_modifychannel(msg, ret); + if (ret != 0) { + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + list_del(&info->msglistentry); + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + goto free_info; + } + + /* + * Release channel_mutex; otherwise, vmbus_onoffer_rescind() could block on + * the mutex and be unable to signal the completion. + * + * See the caller target_cpu_store() for information about the usage of the + * mutex. + */ + mutex_unlock(&vmbus_connection.channel_mutex); + wait_for_completion(&info->waitevent); + mutex_lock(&vmbus_connection.channel_mutex); + + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + list_del(&info->msglistentry); + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + + if (info->response.modify_response.status) + ret = -EAGAIN; + +free_info: + kfree(info); + return ret; +} + /* * Set/change the vCPU (@target_vp) the channel (@child_relid) will interrupt. * - * CHANNELMSG_MODIFYCHANNEL messages are aynchronous. Also, Hyper-V does not - * ACK such messages. IOW we can't know when the host will stop interrupting - * the "old" vCPU and start interrupting the "new" vCPU for the given channel. + * CHANNELMSG_MODIFYCHANNEL messages are aynchronous. When VMbus version 5.3 + * or later is negotiated, Hyper-V always sends an ACK in response to such a + * message. For VMbus version 5.2 and earlier, it never sends an ACK. With- + * out an ACK, we can not know when the host will stop interrupting the "old" + * vCPU and start interrupting the "new" vCPU for the given channel. * * The CHANNELMSG_MODIFYCHANNEL message type is supported since VMBus version * VERSION_WIN10_V4_1. */ -int vmbus_send_modifychannel(u32 child_relid, u32 target_vp) +int vmbus_send_modifychannel(struct vmbus_channel *channel, u32 target_vp) { - struct vmbus_channel_modifychannel conn_msg; - int ret; - - memset(&conn_msg, 0, sizeof(conn_msg)); - conn_msg.header.msgtype = CHANNELMSG_MODIFYCHANNEL; - conn_msg.child_relid = child_relid; - conn_msg.target_vp = target_vp; - - ret = vmbus_post_msg(&conn_msg, sizeof(conn_msg), true); - - trace_vmbus_send_modifychannel(&conn_msg, ret); - - return ret; + if (vmbus_proto_version >= VERSION_WIN10_V5_3) + return send_modifychannel_with_ack(channel, target_vp); + return send_modifychannel_without_ack(channel, target_vp); } EXPORT_SYMBOL_GPL(vmbus_send_modifychannel); @@ -385,7 +450,7 @@ nomem: * @kbuffer: from kmalloc or vmalloc * @size: page-size multiple * @send_offset: the offset (in bytes) where the send ring buffer starts, - * should be 0 for BUFFER type gpadl + * should be 0 for BUFFER type gpadl * @gpadl_handle: some funky thing */ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, @@ -653,7 +718,7 @@ static int __vmbus_open(struct vmbus_channel *newchannel, if (newchannel->rescind) { err = -ENODEV; - goto error_free_info; + goto error_clean_msglist; } err = vmbus_post_msg(open_msg, diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index f0ed730e2e4e40355764db79f6d77254fe455162..caf6d0c4bc1b1d72efeb1e0d0b2bd2c81321241d 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -333,7 +333,6 @@ fw_error: negop->icversion_data[1].minor = icmsg_minor; return found_match; } - EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp); /* @@ -593,10 +592,10 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) * CPUS_READ_UNLOCK CPUS_WRITE_UNLOCK * * Forbids: CPU1's LOAD from *not* seing CPU2's STORE && - * CPU2's SEARCH from *not* seeing CPU1's INSERT + * CPU2's SEARCH from *not* seeing CPU1's INSERT * * Forbids: CPU2's SEARCH from seeing CPU1's INSERT && - * CPU2's LOAD from *not* seing CPU1's STORE + * CPU2's LOAD from *not* seing CPU1's STORE */ cpus_read_lock(); @@ -756,6 +755,12 @@ static void init_vp_index(struct vmbus_channel *channel) free_cpumask_var(available_mask); } +#define UNLOAD_DELAY_UNIT_MS 10 /* 10 milliseconds */ +#define UNLOAD_WAIT_MS (100*1000) /* 100 seconds */ +#define UNLOAD_WAIT_LOOPS (UNLOAD_WAIT_MS/UNLOAD_DELAY_UNIT_MS) +#define UNLOAD_MSG_MS (5*1000) /* Every 5 seconds */ +#define UNLOAD_MSG_LOOPS (UNLOAD_MSG_MS/UNLOAD_DELAY_UNIT_MS) + static void vmbus_wait_for_unload(void) { int cpu; @@ -773,12 +778,17 @@ static void vmbus_wait_for_unload(void) * vmbus_connection.unload_event. If not, the last thing we can do is * read message pages for all CPUs directly. * - * Wait no more than 10 seconds so that the panic path can't get - * hung forever in case the response message isn't seen. + * Wait up to 100 seconds since an Azure host must writeback any dirty + * data in its disk cache before the VMbus UNLOAD request will + * complete. This flushing has been empirically observed to take up + * to 50 seconds in cases with a lot of dirty data, so allow additional + * leeway and for inaccuracies in mdelay(). But eventually time out so + * that the panic path can't get hung forever in case the response + * message isn't seen. */ - for (i = 0; i < 1000; i++) { + for (i = 1; i <= UNLOAD_WAIT_LOOPS; i++) { if (completion_done(&vmbus_connection.unload_event)) - break; + goto completed; for_each_online_cpu(cpu) { struct hv_per_cpu_context *hv_cpu @@ -801,9 +811,18 @@ static void vmbus_wait_for_unload(void) vmbus_signal_eom(msg, message_type); } - mdelay(10); + /* + * Give a notice periodically so someone watching the + * serial output won't think it is completely hung. + */ + if (!(i % UNLOAD_MSG_LOOPS)) + pr_notice("Waiting for VMBus UNLOAD to complete\n"); + + mdelay(UNLOAD_DELAY_UNIT_MS); } + pr_err("Continuing even though VMBus UNLOAD did not complete\n"); +completed: /* * We're crashing and already got the UNLOAD_RESPONSE, cleanup all * maybe-pending messages on all CPUs to be able to receive new @@ -827,6 +846,11 @@ static void vmbus_unload_response(struct vmbus_channel_message_header *hdr) /* * This is a global event; just wakeup the waiting thread. * Once we successfully unload, we can cleanup the monitor state. + * + * NB. A malicious or compromised Hyper-V could send a spurious + * message of type CHANNELMSG_UNLOAD_RESPONSE, and trigger a call + * of the complete() below. Make sure that unload_event has been + * initialized by the time this complete() is executed. */ complete(&vmbus_connection.unload_event); } @@ -842,7 +866,7 @@ void vmbus_initiate_unload(bool crash) if (vmbus_proto_version < VERSION_WIN8_1) return; - init_completion(&vmbus_connection.unload_event); + reinit_completion(&vmbus_connection.unload_event); memset(&hdr, 0, sizeof(struct vmbus_channel_message_header)); hdr.msgtype = CHANNELMSG_UNLOAD; vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header), @@ -980,7 +1004,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) * UNLOCK channel_mutex * * Forbids: r1 == valid_relid && - * channels[valid_relid] == channel + * channels[valid_relid] == channel * * Note. r1 can be INVALID_RELID only for an hv_sock channel. * None of the hv_sock channels which were present before the @@ -1312,6 +1336,46 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr) spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); } +/* + * vmbus_onmodifychannel_response - Modify Channel response handler. + * + * This is invoked when we received a response to our channel modify request. + * Find the matching request, copy the response and signal the requesting thread. + */ +static void vmbus_onmodifychannel_response(struct vmbus_channel_message_header *hdr) +{ + struct vmbus_channel_modifychannel_response *response; + struct vmbus_channel_msginfo *msginfo; + unsigned long flags; + + response = (struct vmbus_channel_modifychannel_response *)hdr; + + trace_vmbus_onmodifychannel_response(response); + + /* + * Find the modify msg, copy the response and signal/unblock the wait event. + */ + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + + list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list, msglistentry) { + struct vmbus_channel_message_header *responseheader = + (struct vmbus_channel_message_header *)msginfo->msg; + + if (responseheader->msgtype == CHANNELMSG_MODIFYCHANNEL) { + struct vmbus_channel_modifychannel *modifymsg; + + modifymsg = (struct vmbus_channel_modifychannel *)msginfo->msg; + if (modifymsg->child_relid == response->child_relid) { + memcpy(&msginfo->response.modify_response, response, + sizeof(*response)); + complete(&msginfo->waitevent); + break; + } + } + } + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); +} + /* * vmbus_ongpadl_torndown - GPADL torndown handler. * @@ -1429,6 +1493,8 @@ channel_message_table[CHANNELMSG_COUNT] = { { CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL, 0}, { CHANNELMSG_MODIFYCHANNEL, 0, NULL, 0}, { CHANNELMSG_TL_CONNECT_RESULT, 0, NULL, 0}, + { CHANNELMSG_MODIFYCHANNEL_RESPONSE, 1, vmbus_onmodifychannel_response, + sizeof(struct vmbus_channel_modifychannel_response)}, }; /* diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index c83612cddb99508e330cc60155bca724e85c300f..311cd005b3be666e17d36ac98475d76d17953036 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -26,9 +26,11 @@ struct vmbus_connection vmbus_connection = { .conn_state = DISCONNECTED, + .unload_event = COMPLETION_INITIALIZER( + vmbus_connection.unload_event), .next_gpadl_handle = ATOMIC_INIT(0xE1E10), - .ready_for_suspend_event= COMPLETION_INITIALIZER( + .ready_for_suspend_event = COMPLETION_INITIALIZER( vmbus_connection.ready_for_suspend_event), .ready_for_resume_event = COMPLETION_INITIALIZER( vmbus_connection.ready_for_resume_event), @@ -45,6 +47,7 @@ EXPORT_SYMBOL_GPL(vmbus_proto_version); * Table of VMBus versions listed from newest to oldest. */ static __u32 vmbus_versions[] = { + VERSION_WIN10_V5_3, VERSION_WIN10_V5_2, VERSION_WIN10_V5_1, VERSION_WIN10_V5, @@ -60,7 +63,7 @@ static __u32 vmbus_versions[] = { * Maximal VMBus protocol version guests can negotiate. Useful to cap the * VMBus version for testing and debugging purpose. */ -static uint max_version = VERSION_WIN10_V5_2; +static uint max_version = VERSION_WIN10_V5_3; module_param(max_version, uint, S_IRUGO); MODULE_PARM_DESC(max_version, diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index f202ac7f4b3d47c254f1bc90e1f5facaa2d20260..e83507f49676ddd221abda1cdb9e1d8d28af5edf 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -13,9 +13,10 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/hyperv.h> -#include <linux/version.h> #include <linux/random.h> #include <linux/clockchips.h> +#include <linux/delay.h> +#include <linux/interrupt.h> #include <clocksource/hyperv_timer.h> #include <asm/mshyperv.h> #include "hyperv_vmbus.h" @@ -36,6 +37,42 @@ int hv_init(void) return 0; } +/* + * Functions for allocating and freeing memory with size and + * alignment HV_HYP_PAGE_SIZE. These functions are needed because + * the guest page size may not be the same as the Hyper-V page + * size. We depend upon kmalloc() aligning power-of-two size + * allocations to the allocation size boundary, so that the + * allocated memory appears to Hyper-V as a page of the size + * it expects. + */ + +void *hv_alloc_hyperv_page(void) +{ + BUILD_BUG_ON(PAGE_SIZE < HV_HYP_PAGE_SIZE); + + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + return (void *)__get_free_page(GFP_KERNEL); + else + return kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); +} + +void *hv_alloc_hyperv_zeroed_page(void) +{ + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + else + return kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); +} + +void hv_free_hyperv_page(unsigned long addr) +{ + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + free_page(addr); + else + kfree((void *)addr); +} + /* * hv_post_message - Post a message using the hypervisor message IPC. * @@ -68,7 +105,7 @@ int hv_post_message(union hv_connection_id connection_id, */ put_cpu_ptr(hv_cpu); - return status & 0xFFFF; + return hv_result(status); } int hv_synic_alloc(void) @@ -162,34 +199,48 @@ void hv_synic_enable_regs(unsigned int cpu) union hv_synic_scontrol sctrl; /* Setup the Synic's message page */ - hv_get_simp(simp.as_uint64); + simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); simp.simp_enabled = 1; simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) >> HV_HYP_PAGE_SHIFT; - hv_set_simp(simp.as_uint64); + hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); /* Setup the Synic's event page */ - hv_get_siefp(siefp.as_uint64); + siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); siefp.siefp_enabled = 1; siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) >> HV_HYP_PAGE_SHIFT; - hv_set_siefp(siefp.as_uint64); + hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); /* Setup the shared SINT. */ - hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); + if (vmbus_irq != -1) + enable_percpu_irq(vmbus_irq, 0); + shared_sint.as_uint64 = hv_get_register(HV_REGISTER_SINT0 + + VMBUS_MESSAGE_SINT); - shared_sint.vector = hv_get_vector(); + shared_sint.vector = vmbus_interrupt; shared_sint.masked = false; - shared_sint.auto_eoi = hv_recommend_using_aeoi(); - hv_set_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); + + /* + * On architectures where Hyper-V doesn't support AEOI (e.g., ARM64), + * it doesn't provide a recommendation flag and AEOI must be disabled. + */ +#ifdef HV_DEPRECATING_AEOI_RECOMMENDED + shared_sint.auto_eoi = + !(ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED); +#else + shared_sint.auto_eoi = 0; +#endif + hv_set_register(HV_REGISTER_SINT0 + VMBUS_MESSAGE_SINT, + shared_sint.as_uint64); /* Enable the global synic bit */ - hv_get_synic_state(sctrl.as_uint64); + sctrl.as_uint64 = hv_get_register(HV_REGISTER_SCONTROL); sctrl.enable = 1; - hv_set_synic_state(sctrl.as_uint64); + hv_set_register(HV_REGISTER_SCONTROL, sctrl.as_uint64); } int hv_synic_init(unsigned int cpu) @@ -211,30 +262,71 @@ void hv_synic_disable_regs(unsigned int cpu) union hv_synic_siefp siefp; union hv_synic_scontrol sctrl; - hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); + shared_sint.as_uint64 = hv_get_register(HV_REGISTER_SINT0 + + VMBUS_MESSAGE_SINT); shared_sint.masked = 1; /* Need to correctly cleanup in the case of SMP!!! */ /* Disable the interrupt */ - hv_set_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); + hv_set_register(HV_REGISTER_SINT0 + VMBUS_MESSAGE_SINT, + shared_sint.as_uint64); - hv_get_simp(simp.as_uint64); + simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); simp.simp_enabled = 0; simp.base_simp_gpa = 0; - hv_set_simp(simp.as_uint64); + hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); - hv_get_siefp(siefp.as_uint64); + siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); siefp.siefp_enabled = 0; siefp.base_siefp_gpa = 0; - hv_set_siefp(siefp.as_uint64); + hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); /* Disable the global synic bit */ - hv_get_synic_state(sctrl.as_uint64); + sctrl.as_uint64 = hv_get_register(HV_REGISTER_SCONTROL); sctrl.enable = 0; - hv_set_synic_state(sctrl.as_uint64); + hv_set_register(HV_REGISTER_SCONTROL, sctrl.as_uint64); + + if (vmbus_irq != -1) + disable_percpu_irq(vmbus_irq); +} + +#define HV_MAX_TRIES 3 +/* + * Scan the event flags page of 'this' CPU looking for any bit that is set. If we find one + * bit set, then wait for a few milliseconds. Repeat these steps for a maximum of 3 times. + * Return 'true', if there is still any set bit after this operation; 'false', otherwise. + * + * If a bit is set, that means there is a pending channel interrupt. The expectation is + * that the normal interrupt handling mechanism will find and process the channel interrupt + * "very soon", and in the process clear the bit. + */ +static bool hv_synic_event_pending(void) +{ + struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context); + union hv_synic_event_flags *event = + (union hv_synic_event_flags *)hv_cpu->synic_event_page + VMBUS_MESSAGE_SINT; + unsigned long *recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */ + bool pending; + u32 relid; + int tries = 0; + +retry: + pending = false; + for_each_set_bit(relid, recv_int_page, HV_EVENT_FLAGS_COUNT) { + /* Special case - VMBus channel protocol messages */ + if (relid == 0) + continue; + pending = true; + break; + } + if (pending && tries++ < HV_MAX_TRIES) { + usleep_range(10000, 20000); + goto retry; + } + return pending; } int hv_synic_cleanup(unsigned int cpu) @@ -242,6 +334,9 @@ int hv_synic_cleanup(unsigned int cpu) struct vmbus_channel *channel, *sc; bool channel_found = false; + if (vmbus_connection.conn_state != CONNECTED) + goto always_cleanup; + /* * Hyper-V does not provide a way to change the connect CPU once * it is set; we must prevent the connect CPU from going offline @@ -249,8 +344,7 @@ int hv_synic_cleanup(unsigned int cpu) * path where the vmbus is already disconnected, the CPU must be * allowed to shut down. */ - if (cpu == VMBUS_CONNECT_CPU && - vmbus_connection.conn_state == CONNECTED) + if (cpu == VMBUS_CONNECT_CPU) return -EBUSY; /* @@ -277,9 +371,21 @@ int hv_synic_cleanup(unsigned int cpu) } mutex_unlock(&vmbus_connection.channel_mutex); - if (channel_found && vmbus_connection.conn_state == CONNECTED) + if (channel_found) + return -EBUSY; + + /* + * channel_found == false means that any channels that were previously + * assigned to the CPU have been reassigned elsewhere with a call of + * vmbus_send_modifychannel(). Scan the event flags page looking for + * bits that are set and waiting with a timeout for vmbus_chan_sched() + * to process such bits. If bits are still set after this operation + * and VMBus is connected, fail the CPU offlining operation. + */ + if (vmbus_proto_version >= VERSION_WIN10_V4_1 && hv_synic_event_pending()) return -EBUSY; +always_cleanup: hv_stimer_legacy_cleanup(cpu); hv_synic_disable_regs(cpu); diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 2f776d78e3c1a27740d4517363d8525bd19e89f9..58af84e30144b864b952862297c8c62684d6ddb2 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -21,6 +21,7 @@ #include <linux/memory.h> #include <linux/notifier.h> #include <linux/percpu_counter.h> +#include <linux/page_reporting.h> #include <linux/hyperv.h> #include <asm/hyperv-tlfs.h> @@ -563,6 +564,8 @@ struct hv_dynmem_device { * The negotiated version agreed by host. */ __u32 version; + + struct page_reporting_dev_info pr_dev_info; }; static struct hv_dynmem_device dm_device; @@ -1568,6 +1571,89 @@ static void balloon_onchannelcallback(void *context) } +/* Hyper-V only supports reporting 2MB pages or higher */ +#define HV_MIN_PAGE_REPORTING_ORDER 9 +#define HV_MIN_PAGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << HV_MIN_PAGE_REPORTING_ORDER) +static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info, + struct scatterlist *sgl, unsigned int nents) +{ + unsigned long flags; + struct hv_memory_hint *hint; + int i; + u64 status; + struct scatterlist *sg; + + WARN_ON_ONCE(nents > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES); + WARN_ON_ONCE(sgl->length < HV_MIN_PAGE_REPORTING_LEN); + local_irq_save(flags); + hint = *(struct hv_memory_hint **)this_cpu_ptr(hyperv_pcpu_input_arg); + if (!hint) { + local_irq_restore(flags); + return -ENOSPC; + } + + hint->type = HV_EXT_MEMORY_HEAT_HINT_TYPE_COLD_DISCARD; + hint->reserved = 0; + for_each_sg(sgl, sg, nents, i) { + union hv_gpa_page_range *range; + + range = &hint->ranges[i]; + range->address_space = 0; + /* page reporting only reports 2MB pages or higher */ + range->page.largepage = 1; + range->page.additional_pages = + (sg->length / HV_MIN_PAGE_REPORTING_LEN) - 1; + range->page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB; + range->base_large_pfn = + page_to_hvpfn(sg_page(sg)) >> HV_MIN_PAGE_REPORTING_ORDER; + } + + status = hv_do_rep_hypercall(HV_EXT_CALL_MEMORY_HEAT_HINT, nents, 0, + hint, NULL); + local_irq_restore(flags); + if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) { + pr_err("Cold memory discard hypercall failed with status %llx\n", + status); + return -EINVAL; + } + + return 0; +} + +static void enable_page_reporting(void) +{ + int ret; + + /* Essentially, validating 'PAGE_REPORTING_MIN_ORDER' is big enough. */ + if (pageblock_order < HV_MIN_PAGE_REPORTING_ORDER) { + pr_debug("Cold memory discard is only supported on 2MB pages and above\n"); + return; + } + + if (!hv_query_ext_cap(HV_EXT_CAPABILITY_MEMORY_COLD_DISCARD_HINT)) { + pr_debug("Cold memory discard hint not supported by Hyper-V\n"); + return; + } + + BUILD_BUG_ON(PAGE_REPORTING_CAPACITY > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES); + dm_device.pr_dev_info.report = hv_free_page_report; + ret = page_reporting_register(&dm_device.pr_dev_info); + if (ret < 0) { + dm_device.pr_dev_info.report = NULL; + pr_err("Failed to enable cold memory discard: %d\n", ret); + } else { + pr_info("Cold memory discard hint enabled\n"); + } +} + +static void disable_page_reporting(void) +{ + if (dm_device.pr_dev_info.report) { + page_reporting_unregister(&dm_device.pr_dev_info); + dm_device.pr_dev_info.report = NULL; + } +} + static int balloon_connect_vsp(struct hv_device *dev) { struct dm_version_request version_req; @@ -1713,6 +1799,7 @@ static int balloon_probe(struct hv_device *dev, if (ret != 0) return ret; + enable_page_reporting(); dm_device.state = DM_INITIALIZED; dm_device.thread = @@ -1727,6 +1814,7 @@ static int balloon_probe(struct hv_device *dev, probe_error: dm_device.state = DM_INIT_ERROR; dm_device.thread = NULL; + disable_page_reporting(); vmbus_close(dev->channel); #ifdef CONFIG_MEMORY_HOTPLUG unregister_memory_notifier(&hv_memory_nb); @@ -1749,6 +1837,7 @@ static int balloon_remove(struct hv_device *dev) cancel_work_sync(&dm->ha_wrk.wrk); kthread_stop(dm->thread); + disable_page_reporting(); vmbus_close(dev->channel); #ifdef CONFIG_MEMORY_HOTPLUG unregister_memory_notifier(&hv_memory_nb); diff --git a/drivers/hv/hv_trace.h b/drivers/hv/hv_trace.h index 6063bb21bb137198f83a637ccdcbdc505671f8e2..c02a1719e92f2042ab265df2b395114458455440 100644 --- a/drivers/hv/hv_trace.h +++ b/drivers/hv/hv_trace.h @@ -103,6 +103,21 @@ TRACE_EVENT(vmbus_ongpadl_created, ) ); +TRACE_EVENT(vmbus_onmodifychannel_response, + TP_PROTO(const struct vmbus_channel_modifychannel_response *response), + TP_ARGS(response), + TP_STRUCT__entry( + __field(u32, child_relid) + __field(u32, status) + ), + TP_fast_assign(__entry->child_relid = response->child_relid; + __entry->status = response->status; + ), + TP_printk("child_relid 0x%x, status %d", + __entry->child_relid, __entry->status + ) + ); + TRACE_EVENT(vmbus_ongpadl_torndown, TP_PROTO(const struct vmbus_channel_gpadl_torndown *gpadltorndown), TP_ARGS(gpadltorndown), diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 35833d4d1a1dcac54e136291d5f8b755c7a65044..374f8afbf8a58c6ebefb56630136a6a38cdf9fec 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -84,15 +84,6 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, ring_info->ring_buffer->write_index = next_write_location; } -/* Set the next read location for the specified ring buffer. */ -static inline void -hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, - u32 next_read_location) -{ - ring_info->ring_buffer->read_index = next_read_location; - ring_info->priv_read_index = next_read_location; -} - /* Get the size of the ring buffer. */ static inline u32 hv_get_ring_buffersize(const struct hv_ring_buffer_info *ring_info) @@ -313,7 +304,6 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, rqst_id = vmbus_next_request_id(&channel->requestor, requestid); if (rqst_id == VMBUS_RQST_ERROR) { spin_unlock_irqrestore(&outring_info->ring_lock, flags); - pr_err("No request id available\n"); return -EAGAIN; } } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 10dce9f9121689eb32e4c941c6ee8d88927bc5fc..b12d6827b222baca27b6821a5b77e2481f23b74b 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -48,8 +48,10 @@ static int hyperv_cpuhp_online; static void *hv_panic_page; +static long __percpu *vmbus_evt; + /* Values parsed from ACPI DSDT */ -static int vmbus_irq; +int vmbus_irq; int vmbus_interrupt; /* @@ -1381,7 +1383,13 @@ static void vmbus_isr(void) tasklet_schedule(&hv_cpu->msg_dpc); } - add_interrupt_randomness(hv_get_vector(), 0); + add_interrupt_randomness(vmbus_interrupt, 0); +} + +static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) +{ + vmbus_isr(); + return IRQ_HANDLED; } /* @@ -1392,22 +1400,36 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) { size_t bytes_written; - phys_addr_t panic_pa; /* We are only interested in panics. */ if ((reason != KMSG_DUMP_PANIC) || (!sysctl_record_panic_msg)) return; - panic_pa = virt_to_phys(hv_panic_page); - /* * Write dump contents to the page. No need to synchronize; panic should * be single-threaded. */ kmsg_dump_get_buffer(dumper, false, hv_panic_page, HV_HYP_PAGE_SIZE, &bytes_written); - if (bytes_written) - hyperv_report_panic_msg(panic_pa, bytes_written); + if (!bytes_written) + return; + /* + * P3 to contain the physical address of the panic page & P4 to + * contain the size of the panic data in that page. Rest of the + * registers are no-op when the NOTIFY_MSG flag is set. + */ + hv_set_register(HV_REGISTER_CRASH_P0, 0); + hv_set_register(HV_REGISTER_CRASH_P1, 0); + hv_set_register(HV_REGISTER_CRASH_P2, 0); + hv_set_register(HV_REGISTER_CRASH_P3, virt_to_phys(hv_panic_page)); + hv_set_register(HV_REGISTER_CRASH_P4, bytes_written); + + /* + * Let Hyper-V know there is crash data available along with + * the panic message. + */ + hv_set_register(HV_REGISTER_CRASH_CTL, + (HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG)); } static struct kmsg_dumper hv_kmsg_dumper = { @@ -1482,9 +1504,28 @@ static int vmbus_bus_init(void) if (ret) return ret; - ret = hv_setup_vmbus_irq(vmbus_irq, vmbus_isr); - if (ret) - goto err_setup; + /* + * VMbus interrupts are best modeled as per-cpu interrupts. If + * on an architecture with support for per-cpu IRQs (e.g. ARM64), + * allocate a per-cpu IRQ using standard Linux kernel functionality. + * If not on such an architecture (e.g., x86/x64), then rely on + * code in the arch-specific portion of the code tree to connect + * the VMbus interrupt handler. + */ + + if (vmbus_irq == -1) { + hv_setup_vmbus_handler(vmbus_isr); + } else { + vmbus_evt = alloc_percpu(long); + ret = request_percpu_irq(vmbus_irq, vmbus_percpu_isr, + "Hyper-V VMbus", vmbus_evt); + if (ret) { + pr_err("Can't request Hyper-V VMbus IRQ %d, Err %d", + vmbus_irq, ret); + free_percpu(vmbus_evt); + goto err_setup; + } + } ret = hv_synic_alloc(); if (ret) @@ -1521,7 +1562,7 @@ static int vmbus_bus_init(void) * Register for panic kmsg callback only if the right * capability is supported by the hypervisor. */ - hv_get_crash_ctl(hyperv_crash_ctl); + hyperv_crash_ctl = hv_get_register(HV_REGISTER_CRASH_CTL); if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) hv_kmsg_dump_register(); @@ -1545,7 +1586,12 @@ err_connect: err_cpuhp: hv_synic_free(); err_alloc: - hv_remove_vmbus_irq(); + if (vmbus_irq == -1) { + hv_remove_vmbus_handler(); + } else { + free_percpu_irq(vmbus_irq, vmbus_evt); + free_percpu(vmbus_evt); + } err_setup: bus_unregister(&hv_bus); unregister_sysctl_table(hv_ctl_table_hdr); @@ -1802,13 +1848,15 @@ static ssize_t target_cpu_store(struct vmbus_channel *channel, if (target_cpu == origin_cpu) goto cpu_store_unlock; - if (vmbus_send_modifychannel(channel->offermsg.child_relid, + if (vmbus_send_modifychannel(channel, hv_cpu_number_to_vp_number(target_cpu))) { ret = -EIO; goto cpu_store_unlock; } /* + * For version before VERSION_WIN10_V5_3, the following warning holds: + * * Warning. At this point, there is *no* guarantee that the host will * have successfully processed the vmbus_send_modifychannel() request. * See the header comment of vmbus_send_modifychannel() for more info. @@ -2663,6 +2711,18 @@ static int __init hv_acpi_init(void) ret = -ETIMEDOUT; goto cleanup; } + + /* + * If we're on an architecture with a hardcoded hypervisor + * vector (i.e. x86/x64), override the VMbus interrupt found + * in the ACPI tables. Ensure vmbus_irq is not set since the + * normal Linux IRQ mechanism is not used in this case. + */ +#ifdef HYPERVISOR_CALLBACK_VECTOR + vmbus_interrupt = HYPERVISOR_CALLBACK_VECTOR; + vmbus_irq = -1; +#endif + hv_debug_init(); ret = vmbus_bus_init(); @@ -2693,7 +2753,12 @@ static void __exit vmbus_exit(void) vmbus_connection.conn_state = DISCONNECTED; hv_stimer_global_cleanup(); vmbus_disconnect(); - hv_remove_vmbus_irq(); + if (vmbus_irq == -1) { + hv_remove_vmbus_handler(); + } else { + free_percpu_irq(vmbus_irq, vmbus_evt); + free_percpu(vmbus_evt); + } for_each_online_cpu(cpu) { struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 54f04e61fb8364efb92f8d522470b69c25b69e6e..87624902ea8090deee9538f7feee99ab4c908571 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -321,16 +321,6 @@ config SENSORS_FAM15H_POWER This driver can also be built as a module. If so, the module will be called fam15h_power. -config SENSORS_AMD_ENERGY - tristate "AMD RAPL MSR based Energy driver" - depends on X86 - help - If you say yes here you get support for core and package energy - sensors, based on RAPL MSR for AMD family 17h and above CPUs. - - This driver can also be built as a module. If so, the module - will be called as amd_energy. - config SENSORS_APPLESMC tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" depends on INPUT && X86 @@ -1492,6 +1482,16 @@ config SENSORS_NSA320 This driver can also be built as a module. If so, the module will be called nsa320-hwmon. +config SENSORS_NZXT_KRAKEN2 + tristate "NZXT Kraken X42/X51/X62/X72 liquid coolers" + depends on USB_HID + help + If you say yes here you get support for hardware monitoring for the + NZXT Kraken X42/X52/X62/X72 all-in-one CPU liquid coolers. + + This driver can also be built as a module. If so, the module + will be called nzxt-kraken2. + source "drivers/hwmon/occ/Kconfig" config SENSORS_PCF8591 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index fe38e8a5c979ae383a1dad8f4d0b48ce5873b9d2..59e78bc212cf3c9090348bae505813410ecc571a 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o obj-$(CONFIG_SENSORS_NPCM7XX) += npcm750-pwm-fan.o obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o +obj-$(CONFIG_SENSORS_NZXT_KRAKEN2) += nzxt-kraken2.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 7d3ddcba34cea97199e9096db6a2acaf4c3a0603..014505b1faf74791b0b7757d692bbcb87bcfaf64 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -20,7 +20,6 @@ #include <linux/acpi.h> #define ACPI_POWER_METER_NAME "power_meter" -ACPI_MODULE_NAME(ACPI_POWER_METER_NAME); #define ACPI_POWER_METER_DEVICE_NAME "Power Meter" #define ACPI_POWER_METER_CLASS "pwr_meter_resource" @@ -114,7 +113,8 @@ static int update_avg_interval(struct acpi_power_meter_resource *resource) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI", NULL, &data); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_GAI", + status); return -ENODEV; } @@ -166,7 +166,8 @@ static ssize_t set_avg_interval(struct device *dev, mutex_unlock(&resource->lock); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_PAI", + status); return -EINVAL; } @@ -186,7 +187,8 @@ static int update_cap(struct acpi_power_meter_resource *resource) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL", NULL, &data); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_GHL", + status); return -ENODEV; } @@ -237,7 +239,8 @@ static ssize_t set_cap(struct device *dev, struct device_attribute *devattr, mutex_unlock(&resource->lock); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_SHL", + status); return -EINVAL; } @@ -270,7 +273,8 @@ static int set_acpi_trip(struct acpi_power_meter_resource *resource) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP", &args, &data); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_PTP", + status); return -EINVAL; } @@ -322,7 +326,8 @@ static int update_meter(struct acpi_power_meter_resource *resource) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM", NULL, &data); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_PMM", + status); return -ENODEV; } @@ -549,7 +554,8 @@ static int read_domain_devices(struct acpi_power_meter_resource *resource) status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL, &buffer); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_PMD", + status); return -ENODEV; } @@ -745,7 +751,8 @@ static int read_capabilities(struct acpi_power_meter_resource *resource) status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL, &buffer); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC")); + acpi_evaluation_failure_warn(resource->acpi_dev->handle, "_PMC", + status); return -ENODEV; } @@ -765,7 +772,9 @@ static int read_capabilities(struct acpi_power_meter_resource *resource) status = acpi_extract_package(pss, &format, &state); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Invalid data")); + dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME + "_PMC package parsing failed: %s\n", + acpi_format_exception(status)); res = -EFAULT; goto end; } diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 6c9a906631b89ece05c0bf163f8bcb8ff5289146..fd938c70293fb2010f2b535814cf38e17cb7d9fc 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -248,7 +248,7 @@ static ssize_t adc128_alarm_show(struct device *dev, static umode_t adc128_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct adc128_data *data = dev_get_drvdata(dev); if (index < ADC128_ATTR_NUM_VOLT) { diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index cc3e0184e720aaca4c35b7fccdd72e745ec99636..5677263bcf0dea99d8cb0e2850c7e334d8da6bf5 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -28,6 +28,7 @@ * LM81 extended temp reading not implemented */ +#include <linux/bits.h> #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> @@ -37,7 +38,6 @@ #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> -#include <linux/jiffies.h> #include <linux/regmap.h> /* Addresses to scan */ @@ -123,32 +123,18 @@ static inline unsigned int AOUT_FROM_REG(u8 reg) /* per client data */ struct adm9240_data { - struct i2c_client *client; + struct device *dev; struct regmap *regmap; struct mutex update_lock; - char valid; - unsigned long last_updated_measure; - unsigned long last_updated_config; - - u8 in[6]; /* ro in0_input */ - u8 in_max[6]; /* rw in0_max */ - u8 in_min[6]; /* rw in0_min */ - u8 fan[2]; /* ro fan1_input */ - u8 fan_min[2]; /* rw fan1_min */ + u8 fan_div[2]; /* rw fan1_div, read-only accessor */ - s16 temp; /* ro temp1_input, 9-bit sign-extended */ - s8 temp_max[2]; /* rw 0 -> temp_max, 1 -> temp_max_hyst */ - u16 alarms; /* ro alarms */ - u8 aout; /* rw aout_output */ - u8 vid; /* ro vid */ u8 vrm; /* -- vrm set on startup, no accessor */ }; /* write new fan div, callers must hold data->update_lock */ -static int adm9240_write_fan_div(struct adm9240_data *data, int nr, - u8 fan_div) +static int adm9240_write_fan_div(struct adm9240_data *data, int channel, u8 fan_div) { - unsigned int reg, old, shift = (nr + 2) * 2; + unsigned int reg, old, shift = (channel + 2) * 2; int err; err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, ®); @@ -160,336 +146,13 @@ static int adm9240_write_fan_div(struct adm9240_data *data, int nr, err = regmap_write(data->regmap, ADM9240_REG_VID_FAN_DIV, reg); if (err < 0) return err; - dev_dbg(&data->client->dev, - "fan%d clock divider changed from %u to %u\n", - nr + 1, 1 << old, 1 << fan_div); - - return 0; -} - -static int adm9240_update_measure(struct adm9240_data *data) -{ - unsigned int val; - u8 regs[2]; - int err; - int i; - - err = regmap_bulk_read(data->regmap, ADM9240_REG_IN(0), &data->in[0], 6); - if (err < 0) - return err; - err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), ®s, 2); - if (err < 0) - return err; - - data->alarms = regs[0] | regs[1] << 8; - - /* - * read temperature: assume temperature changes less than - * 0.5'C per two measurement cycles thus ignore possible - * but unlikely aliasing error on lsb reading. --Grant - */ - err = regmap_read(data->regmap, ADM9240_REG_TEMP, &val); - if (err < 0) - return err; - data->temp = val << 8; - err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, &val); - if (err < 0) - return err; - data->temp |= val; - - err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN(0), - &data->fan[0], 2); - if (err < 0) - return err; - - for (i = 0; i < 2; i++) { /* read fans */ - /* adjust fan clock divider on overflow */ - if (data->valid && data->fan[i] == 255 && - data->fan_div[i] < 3) { - - err = adm9240_write_fan_div(data, i, - ++data->fan_div[i]); - if (err < 0) - return err; - - /* adjust fan_min if active, but not to 0 */ - if (data->fan_min[i] < 255 && - data->fan_min[i] >= 2) - data->fan_min[i] /= 2; - } - } + dev_dbg(data->dev, + "fan%d clock divider changed from %lu to %lu\n", + channel + 1, BIT(old), BIT(fan_div)); return 0; } -static int adm9240_update_config(struct adm9240_data *data) -{ - unsigned int val; - int i; - int err; - - for (i = 0; i < 6; i++) { - err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MIN(i), - &data->in_min[i], 1); - if (err < 0) - return err; - err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MAX(i), - &data->in_max[i], 1); - if (err < 0) - return err; - } - err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN_MIN(0), - &data->fan_min[0], 2); - if (err < 0) - return err; - err = regmap_bulk_read(data->regmap, ADM9240_REG_TEMP_MAX(0), - &data->temp_max[0], 2); - if (err < 0) - return err; - - /* read fan divs and 5-bit VID */ - err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &val); - if (err < 0) - return err; - data->fan_div[0] = (val >> 4) & 3; - data->fan_div[1] = (val >> 6) & 3; - data->vid = val & 0x0f; - err = regmap_read(data->regmap, ADM9240_REG_VID4, &val); - if (err < 0) - return err; - data->vid |= (val & 1) << 4; - /* read analog out */ - err = regmap_raw_read(data->regmap, ADM9240_REG_ANALOG_OUT, - &data->aout, 1); - - return err; -} - -static struct adm9240_data *adm9240_update_device(struct device *dev) -{ - struct adm9240_data *data = dev_get_drvdata(dev); - int err; - - mutex_lock(&data->update_lock); - - /* minimum measurement cycle: 1.75 seconds */ - if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) - || !data->valid) { - err = adm9240_update_measure(data); - if (err < 0) { - data->valid = 0; - mutex_unlock(&data->update_lock); - return ERR_PTR(err); - } - data->last_updated_measure = jiffies; - } - - /* minimum config reading cycle: 300 seconds */ - if (time_after(jiffies, data->last_updated_config + (HZ * 300)) - || !data->valid) { - err = adm9240_update_config(data); - if (err < 0) { - data->valid = 0; - mutex_unlock(&data->update_lock); - return ERR_PTR(err); - } - data->last_updated_config = jiffies; - data->valid = 1; - } - mutex_unlock(&data->update_lock); - return data; -} - -/*** sysfs accessors ***/ - -/* temperature */ -static ssize_t temp1_input_show(struct device *dev, - struct device_attribute *dummy, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */ -} - -static ssize_t max_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000); -} - -static ssize_t max_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = dev_get_drvdata(dev); - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->temp_max[attr->index] = TEMP_TO_REG(val); - err = regmap_write(data->regmap, ADM9240_REG_TEMP_MAX(attr->index), - data->temp_max[attr->index]); - mutex_unlock(&data->update_lock); - return err < 0 ? err : count; -} - -static DEVICE_ATTR_RO(temp1_input); -static SENSOR_DEVICE_ATTR_RW(temp1_max, max, 0); -static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, max, 1); - -/* voltage */ -static ssize_t in_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index], - attr->index)); -} - -static ssize_t in_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index], - attr->index)); -} - -static ssize_t in_max_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index], - attr->index)); -} - -static ssize_t in_min_store(struct device *dev, - struct device_attribute *devattr, const char *buf, - size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->in_min[attr->index] = IN_TO_REG(val, attr->index); - err = regmap_write(data->regmap, ADM9240_REG_IN_MIN(attr->index), - data->in_min[attr->index]); - mutex_unlock(&data->update_lock); - return err < 0 ? err : count; -} - -static ssize_t in_max_store(struct device *dev, - struct device_attribute *devattr, const char *buf, - size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->in_max[attr->index] = IN_TO_REG(val, attr->index); - err = regmap_write(data->regmap, ADM9240_REG_IN_MAX(attr->index), - data->in_max[attr->index]); - mutex_unlock(&data->update_lock); - return err < 0 ? err : count; -} - -static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0); -static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0); -static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0); -static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1); -static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1); -static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1); -static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2); -static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2); -static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2); -static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3); -static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3); -static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3); -static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4); -static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4); -static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4); -static SENSOR_DEVICE_ATTR_RO(in5_input, in, 5); -static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5); -static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5); - -/* fans */ -static ssize_t fan_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index], - 1 << data->fan_div[attr->index])); -} - -static ssize_t fan_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index], - 1 << data->fan_div[attr->index])); -} - -static ssize_t fan_div_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]); -} - /* * set fan speed low limit: * @@ -501,38 +164,25 @@ static ssize_t fan_div_show(struct device *dev, * - otherwise: select fan clock divider to suit fan speed low limit, * measurement code may adjust registers to ensure fan speed reading */ -static ssize_t fan_min_store(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) +static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long val) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - int nr = attr->index; u8 new_div; - unsigned long val; + u8 fan_min; int err; - err = kstrtoul(buf, 10, &val); - if (err) - return err; - mutex_lock(&data->update_lock); if (!val) { - data->fan_min[nr] = 255; - new_div = data->fan_div[nr]; - - dev_dbg(&client->dev, "fan%u low limit set disabled\n", - nr + 1); + fan_min = 255; + new_div = data->fan_div[channel]; + dev_dbg(data->dev, "fan%u low limit set disabled\n", channel + 1); } else if (val < 1350000 / (8 * 254)) { new_div = 3; - data->fan_min[nr] = 254; - - dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", - nr + 1, FAN_FROM_REG(254, 1 << new_div)); + fan_min = 254; + dev_dbg(data->dev, "fan%u low limit set minimum %u\n", + channel + 1, FAN_FROM_REG(254, BIT(new_div))); } else { unsigned int new_min = 1350000 / val; @@ -544,87 +194,55 @@ static ssize_t fan_min_store(struct device *dev, if (!new_min) /* keep > 0 */ new_min++; - data->fan_min[nr] = new_min; + fan_min = new_min; - dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", - nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); + dev_dbg(data->dev, "fan%u low limit set fan speed %u\n", + channel + 1, FAN_FROM_REG(new_min, BIT(new_div))); } - if (new_div != data->fan_div[nr]) { - data->fan_div[nr] = new_div; - adm9240_write_fan_div(data, nr, new_div); + if (new_div != data->fan_div[channel]) { + data->fan_div[channel] = new_div; + adm9240_write_fan_div(data, channel, new_div); } - err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(nr), - data->fan_min[nr]); + err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(channel), fan_min); mutex_unlock(&data->update_lock); - return err < 0 ? err : count; -} - -static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); -static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); -static SENSOR_DEVICE_ATTR_RO(fan1_div, fan_div, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); -static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); -static SENSOR_DEVICE_ATTR_RO(fan2_div, fan_div, 1); -/* alarms */ -static ssize_t alarms_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%u\n", data->alarms); + return err; } -static DEVICE_ATTR_RO(alarms); -static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - int bitnr = to_sensor_dev_attr(attr)->index; - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); -} -static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); -static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1); -static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2); -static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3); -static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8); -static SENSOR_DEVICE_ATTR_RO(in5_alarm, alarm, 9); -static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4); -static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6); -static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7); - -/* vid */ static ssize_t cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm9240_data *data = adm9240_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); + struct adm9240_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + u8 vid; - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); + err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, ®val); + if (err < 0) + return err; + vid = regval & 0x0f; + err = regmap_read(data->regmap, ADM9240_REG_VID4, ®val); + if (err < 0) + return err; + vid |= (regval & 1) << 4; + return sprintf(buf, "%d\n", vid_from_reg(vid, data->vrm)); } static DEVICE_ATTR_RO(cpu0_vid); -/* analog output */ static ssize_t aout_output_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm9240_data *data = adm9240_update_device(dev); + struct adm9240_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; - if (IS_ERR(data)) - return PTR_ERR(data); + err = regmap_read(data->regmap, ADM9240_REG_ANALOG_OUT, ®val); + if (err) + return err; - return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); + return sprintf(buf, "%d\n", AOUT_FROM_REG(regval)); } static ssize_t aout_output_store(struct device *dev, @@ -639,76 +257,13 @@ static ssize_t aout_output_store(struct device *dev, if (err) return err; - mutex_lock(&data->update_lock); - data->aout = AOUT_TO_REG(val); - err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, data->aout); - mutex_unlock(&data->update_lock); + err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, AOUT_TO_REG(val)); return err < 0 ? err : count; } static DEVICE_ATTR_RW(aout_output); -static ssize_t alarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct adm9240_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - if (kstrtoul(buf, 10, &val) || val != 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80); - data->valid = 0; /* Force cache refresh */ - mutex_unlock(&data->update_lock); - if (err < 0) - return err; - dev_dbg(&data->client->dev, "chassis intrusion latch cleared\n"); - - return count; -} -static SENSOR_DEVICE_ATTR_RW(intrusion0_alarm, alarm, 12); - static struct attribute *adm9240_attrs[] = { - &sensor_dev_attr_in0_input.dev_attr.attr, - &sensor_dev_attr_in0_min.dev_attr.attr, - &sensor_dev_attr_in0_max.dev_attr.attr, - &sensor_dev_attr_in0_alarm.dev_attr.attr, - &sensor_dev_attr_in1_input.dev_attr.attr, - &sensor_dev_attr_in1_min.dev_attr.attr, - &sensor_dev_attr_in1_max.dev_attr.attr, - &sensor_dev_attr_in1_alarm.dev_attr.attr, - &sensor_dev_attr_in2_input.dev_attr.attr, - &sensor_dev_attr_in2_min.dev_attr.attr, - &sensor_dev_attr_in2_max.dev_attr.attr, - &sensor_dev_attr_in2_alarm.dev_attr.attr, - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_in3_min.dev_attr.attr, - &sensor_dev_attr_in3_max.dev_attr.attr, - &sensor_dev_attr_in3_alarm.dev_attr.attr, - &sensor_dev_attr_in4_input.dev_attr.attr, - &sensor_dev_attr_in4_min.dev_attr.attr, - &sensor_dev_attr_in4_max.dev_attr.attr, - &sensor_dev_attr_in4_alarm.dev_attr.attr, - &sensor_dev_attr_in5_input.dev_attr.attr, - &sensor_dev_attr_in5_min.dev_attr.attr, - &sensor_dev_attr_in5_max.dev_attr.attr, - &sensor_dev_attr_in5_alarm.dev_attr.attr, - &dev_attr_temp1_input.attr, - &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_alarm.dev_attr.attr, - &sensor_dev_attr_fan1_input.dev_attr.attr, - &sensor_dev_attr_fan1_div.dev_attr.attr, - &sensor_dev_attr_fan1_min.dev_attr.attr, - &sensor_dev_attr_fan1_alarm.dev_attr.attr, - &sensor_dev_attr_fan2_input.dev_attr.attr, - &sensor_dev_attr_fan2_div.dev_attr.attr, - &sensor_dev_attr_fan2_min.dev_attr.attr, - &sensor_dev_attr_fan2_alarm.dev_attr.attr, - &dev_attr_alarms.attr, &dev_attr_aout_output.attr, - &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, &dev_attr_cpu0_vid.attr, NULL }; @@ -730,26 +285,19 @@ static int adm9240_detect(struct i2c_client *new_client, return -ENODEV; /* verify chip: reg address should match i2c address */ - if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) - != address) { - dev_err(&adapter->dev, "detect fail: address match, 0x%02x\n", - address); + if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) != address) return -ENODEV; - } /* check known chip manufacturer */ man_id = i2c_smbus_read_byte_data(new_client, ADM9240_REG_MAN_ID); - if (man_id == 0x23) { + if (man_id == 0x23) name = "adm9240"; - } else if (man_id == 0xda) { + else if (man_id == 0xda) name = "ds1780"; - } else if (man_id == 0x01) { + else if (man_id == 0x01) name = "lm81"; - } else { - dev_err(&adapter->dev, "detect fail: unknown manuf, 0x%02x\n", - man_id); + else return -ENODEV; - } /* successful detect, print chip info */ die_rev = i2c_smbus_read_byte_data(new_client, ADM9240_REG_DIE_REV); @@ -757,13 +305,14 @@ static int adm9240_detect(struct i2c_client *new_client, man_id == 0x23 ? "ADM9240" : man_id == 0xda ? "DS1780" : "LM81", die_rev); - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } -static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *data) +static int adm9240_init_client(struct adm9240_data *data) { + unsigned int regval; u8 conf, mode; int err; @@ -777,13 +326,13 @@ static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *d data->vrm = vid_which_vrm(); /* need this to report vid as mV */ - dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, - data->vrm % 10); + dev_info(data->dev, "Using VRM: %d.%d\n", data->vrm / 10, + data->vrm % 10); if (conf & 1) { /* measurement cycle running: report state */ - dev_info(&client->dev, "status: config 0x%02x mode %u\n", - conf, mode); + dev_info(data->dev, "status: config 0x%02x mode %u\n", + conf, mode); } else { /* cold start: open limits before starting chip */ int i; @@ -800,13 +349,13 @@ static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *d } for (i = 0; i < 2; i++) { err = regmap_write(data->regmap, - ADM9240_REG_FAN_MIN(i), 255); + ADM9240_REG_FAN_MIN(i), 255); if (err < 0) return err; } for (i = 0; i < 2; i++) { err = regmap_write(data->regmap, - ADM9240_REG_TEMP_MAX(i), 127); + ADM9240_REG_TEMP_MAX(i), 127); if (err < 0) return err; } @@ -816,23 +365,417 @@ static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *d if (err < 0) return err; - dev_info(&client->dev, + dev_info(data->dev, "cold start: config was 0x%02x mode %u\n", conf, mode); } + /* read fan divs */ + err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, ®val); + if (err < 0) + return err; + data->fan_div[0] = (regval >> 4) & 3; + data->fan_div[1] = (regval >> 6) & 3; return 0; } +static int adm9240_chip_read(struct device *dev, u32 attr, long *val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + u8 regs[2]; + int err; + + switch (attr) { + case hwmon_chip_alarms: + err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), ®s, 2); + if (err < 0) + return err; + *val = regs[0] | regs[1] << 8; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int adm9240_intrusion_read(struct device *dev, u32 attr, long *val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + switch (attr) { + case hwmon_intrusion_alarm: + err = regmap_read(data->regmap, ADM9240_REG_INT(1), ®val); + if (err < 0) + return err; + *val = !!(regval & BIT(4)); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int adm9240_intrusion_write(struct device *dev, u32 attr, long val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + int err; + + switch (attr) { + case hwmon_intrusion_alarm: + if (val) + return -EINVAL; + err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80); + if (err < 0) + return err; + dev_dbg(data->dev, "chassis intrusion latch cleared\n"); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int adm9240_in_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + unsigned int regval; + int reg; + int err; + + switch (attr) { + case hwmon_in_input: + reg = ADM9240_REG_IN(channel); + break; + case hwmon_in_min: + reg = ADM9240_REG_IN_MIN(channel); + break; + case hwmon_in_max: + reg = ADM9240_REG_IN_MAX(channel); + break; + case hwmon_in_alarm: + if (channel < 4) { + reg = ADM9240_REG_INT(0); + } else { + reg = ADM9240_REG_INT(1); + channel -= 4; + } + err = regmap_read(data->regmap, reg, ®val); + if (err < 0) + return err; + *val = !!(regval & BIT(channel)); + return 0; + default: + return -EOPNOTSUPP; + } + err = regmap_read(data->regmap, reg, ®val); + if (err < 0) + return err; + *val = IN_FROM_REG(regval, channel); + return 0; +} + +static int adm9240_in_write(struct device *dev, u32 attr, int channel, long val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + int reg; + + switch (attr) { + case hwmon_in_min: + reg = ADM9240_REG_IN_MIN(channel); + break; + case hwmon_in_max: + reg = ADM9240_REG_IN(channel); + break; + default: + return -EOPNOTSUPP; + } + return regmap_write(data->regmap, reg, IN_TO_REG(val, channel)); +} + +static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + switch (attr) { + case hwmon_fan_input: + err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), ®val); + if (err < 0) + return err; + if (regval == 255 && data->fan_div[channel] < 3) { + /* adjust fan clock divider on overflow */ + err = adm9240_write_fan_div(data, channel, + ++data->fan_div[channel]); + if (err) + return err; + } + *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel])); + break; + case hwmon_fan_div: + *val = BIT(data->fan_div[channel]); + break; + case hwmon_fan_min: + err = regmap_read(data->regmap, ADM9240_REG_FAN_MIN(channel), ®val); + if (err < 0) + return err; + *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel])); + break; + case hwmon_fan_alarm: + err = regmap_read(data->regmap, ADM9240_REG_INT(0), ®val); + if (err < 0) + return err; + *val = !!(regval & BIT(channel + 6)); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int adm9240_fan_write(struct device *dev, u32 attr, int channel, long val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + int err; + + switch (attr) { + case hwmon_fan_min: + err = adm9240_fan_min_write(data, channel, val); + if (err < 0) + return err; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int adm9240_temp_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err, temp; + + switch (attr) { + case hwmon_temp_input: + err = regmap_read(data->regmap, ADM9240_REG_TEMP, ®val); + if (err < 0) + return err; + temp = regval << 1; + err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, ®val); + if (err < 0) + return err; + temp |= regval >> 7; + *val = sign_extend32(temp, 8) * 500; + break; + case hwmon_temp_max: + err = regmap_read(data->regmap, ADM9240_REG_TEMP_MAX(0), ®val); + if (err < 0) + return err; + *val = (s8)regval * 1000; + break; + case hwmon_temp_max_hyst: + err = regmap_read(data->regmap, ADM9240_REG_TEMP_MAX(1), ®val); + if (err < 0) + return err; + *val = (s8)regval * 1000; + break; + case hwmon_temp_alarm: + err = regmap_read(data->regmap, ADM9240_REG_INT(0), ®val); + if (err < 0) + return err; + *val = !!(regval & BIT(4)); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int adm9240_temp_write(struct device *dev, u32 attr, int channel, long val) +{ + struct adm9240_data *data = dev_get_drvdata(dev); + int reg; + + switch (attr) { + case hwmon_temp_max: + reg = ADM9240_REG_TEMP_MAX(0); + break; + case hwmon_temp_max_hyst: + reg = ADM9240_REG_TEMP_MAX(1); + break; + default: + return -EOPNOTSUPP; + } + return regmap_write(data->regmap, reg, TEMP_TO_REG(val)); +} + +static int adm9240_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + switch (type) { + case hwmon_chip: + return adm9240_chip_read(dev, attr, val); + case hwmon_intrusion: + return adm9240_intrusion_read(dev, attr, val); + case hwmon_in: + return adm9240_in_read(dev, attr, channel, val); + case hwmon_fan: + return adm9240_fan_read(dev, attr, channel, val); + case hwmon_temp: + return adm9240_temp_read(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int adm9240_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long val) +{ + switch (type) { + case hwmon_intrusion: + return adm9240_intrusion_write(dev, attr, val); + case hwmon_in: + return adm9240_in_write(dev, attr, channel, val); + case hwmon_fan: + return adm9240_fan_write(dev, attr, channel, val); + case hwmon_temp: + return adm9240_temp_write(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t adm9240_is_visible(const void *_data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + umode_t mode = 0; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_alarms: + mode = 0444; + break; + default: + break; + } + break; + case hwmon_intrusion: + switch (attr) { + case hwmon_intrusion_alarm: + mode = 0644; + break; + default: + break; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp: + case hwmon_temp_alarm: + mode = 0444; + break; + case hwmon_temp_max: + case hwmon_temp_max_hyst: + mode = 0644; + break; + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_div: + case hwmon_fan_alarm: + mode = 0444; + break; + case hwmon_fan_min: + mode = 0644; + break; + default: + break; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + case hwmon_in_alarm: + mode = 0444; + break; + case hwmon_in_min: + case hwmon_in_max: + mode = 0644; + break; + default: + break; + } + break; + default: + break; + } + return mode; +} + +static const struct hwmon_ops adm9240_hwmon_ops = { + .is_visible = adm9240_is_visible, + .read = adm9240_read, + .write = adm9240_write, +}; + +static const struct hwmon_channel_info *adm9240_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS), + HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_ALARM), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_DIV | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_DIV | HWMON_F_ALARM), + NULL +}; + +static const struct hwmon_chip_info adm9240_chip_info = { + .ops = &adm9240_hwmon_ops, + .info = adm9240_info, +}; + +static bool adm9240_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADM9240_REG_IN(0) ... ADM9240_REG_IN(5): + case ADM9240_REG_FAN(0) ... ADM9240_REG_FAN(1): + case ADM9240_REG_INT(0) ... ADM9240_REG_INT(1): + case ADM9240_REG_TEMP: + case ADM9240_REG_TEMP_CONF: + case ADM9240_REG_VID_FAN_DIV: + case ADM9240_REG_VID4: + case ADM9240_REG_ANALOG_OUT: + return true; + default: + return false; + } +} + static const struct regmap_config adm9240_regmap_config = { .reg_bits = 8, .val_bits = 8, .use_single_read = true, .use_single_write = true, + .volatile_reg = adm9240_volatile_reg, }; -static int adm9240_probe(struct i2c_client *new_client) +static int adm9240_probe(struct i2c_client *client) { - struct device *dev = &new_client->dev; + struct device *dev = &client->dev; struct device *hwmon_dev; struct adm9240_data *data; int err; @@ -841,20 +784,19 @@ static int adm9240_probe(struct i2c_client *new_client) if (!data) return -ENOMEM; - data->client = new_client; + data->dev = dev; mutex_init(&data->update_lock); - data->regmap = devm_regmap_init_i2c(new_client, &adm9240_regmap_config); + data->regmap = devm_regmap_init_i2c(client, &adm9240_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); - err = adm9240_init_client(new_client, data); + err = adm9240_init_client(data); if (err < 0) return err; - hwmon_dev = devm_hwmon_device_register_with_groups(dev, - new_client->name, - data, - adm9240_groups); + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, + &adm9240_chip_info, + adm9240_groups); return PTR_ERR_OR_ZERO(hwmon_dev); } diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c deleted file mode 100644 index a86cc8d6d93d0d67dfceacf95bea91ca8a273069..0000000000000000000000000000000000000000 --- a/drivers/hwmon/amd_energy.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -/* - * Copyright (C) 2020 Advanced Micro Devices, Inc. - */ -#include <asm/cpu_device_id.h> - -#include <linux/bits.h> -#include <linux/cpu.h> -#include <linux/cpumask.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/hwmon.h> -#include <linux/kernel.h> -#include <linux/kthread.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/processor.h> -#include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/topology.h> -#include <linux/types.h> - -#define DRVNAME "amd_energy" - -#define ENERGY_PWR_UNIT_MSR 0xC0010299 -#define ENERGY_CORE_MSR 0xC001029A -#define ENERGY_PKG_MSR 0xC001029B - -#define AMD_ENERGY_UNIT_MASK 0x01F00 -#define AMD_ENERGY_MASK 0xFFFFFFFF - -struct sensor_accumulator { - u64 energy_ctr; - u64 prev_value; -}; - -struct amd_energy_data { - struct hwmon_channel_info energy_info; - const struct hwmon_channel_info *info[2]; - struct hwmon_chip_info chip; - struct task_struct *wrap_accumulate; - /* Lock around the accumulator */ - struct mutex lock; - /* An accumulator for each core and socket */ - struct sensor_accumulator *accums; - unsigned int timeout_ms; - /* Energy Status Units */ - int energy_units; - int nr_cpus; - int nr_socks; - int core_id; - char (*label)[10]; -}; - -static int amd_energy_read_labels(struct device *dev, - enum hwmon_sensor_types type, - u32 attr, int channel, - const char **str) -{ - struct amd_energy_data *data = dev_get_drvdata(dev); - - *str = data->label[channel]; - return 0; -} - -static void get_energy_units(struct amd_energy_data *data) -{ - u64 rapl_units; - - rdmsrl_safe(ENERGY_PWR_UNIT_MSR, &rapl_units); - data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8; -} - -static void accumulate_delta(struct amd_energy_data *data, - int channel, int cpu, u32 reg) -{ - struct sensor_accumulator *accum; - u64 input; - - mutex_lock(&data->lock); - rdmsrl_safe_on_cpu(cpu, reg, &input); - input &= AMD_ENERGY_MASK; - - accum = &data->accums[channel]; - if (input >= accum->prev_value) - accum->energy_ctr += - input - accum->prev_value; - else - accum->energy_ctr += UINT_MAX - - accum->prev_value + input; - - accum->prev_value = input; - mutex_unlock(&data->lock); -} - -static void read_accumulate(struct amd_energy_data *data) -{ - int sock, scpu, cpu; - - for (sock = 0; sock < data->nr_socks; sock++) { - scpu = cpumask_first_and(cpu_online_mask, - cpumask_of_node(sock)); - - accumulate_delta(data, data->nr_cpus + sock, - scpu, ENERGY_PKG_MSR); - } - - if (data->core_id >= data->nr_cpus) - data->core_id = 0; - - cpu = data->core_id; - if (cpu_online(cpu)) - accumulate_delta(data, cpu, cpu, ENERGY_CORE_MSR); - - data->core_id++; -} - -static void amd_add_delta(struct amd_energy_data *data, int ch, - int cpu, long *val, u32 reg) -{ - struct sensor_accumulator *accum; - u64 input; - - mutex_lock(&data->lock); - rdmsrl_safe_on_cpu(cpu, reg, &input); - input &= AMD_ENERGY_MASK; - - accum = &data->accums[ch]; - if (input >= accum->prev_value) - input += accum->energy_ctr - - accum->prev_value; - else - input += UINT_MAX - accum->prev_value + - accum->energy_ctr; - - /* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */ - *val = div64_ul(input * 1000000UL, BIT(data->energy_units)); - - mutex_unlock(&data->lock); -} - -static int amd_energy_read(struct device *dev, - enum hwmon_sensor_types type, - u32 attr, int channel, long *val) -{ - struct amd_energy_data *data = dev_get_drvdata(dev); - u32 reg; - int cpu; - - if (channel >= data->nr_cpus) { - cpu = cpumask_first_and(cpu_online_mask, - cpumask_of_node - (channel - data->nr_cpus)); - reg = ENERGY_PKG_MSR; - } else { - cpu = channel; - if (!cpu_online(cpu)) - return -ENODEV; - - reg = ENERGY_CORE_MSR; - } - amd_add_delta(data, channel, cpu, val, reg); - - return 0; -} - -static umode_t amd_energy_is_visible(const void *_data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0440; -} - -static int energy_accumulator(void *p) -{ - struct amd_energy_data *data = (struct amd_energy_data *)p; - unsigned int timeout = data->timeout_ms; - - while (!kthread_should_stop()) { - /* - * Ignoring the conditions such as - * cpu being offline or rdmsr failure - */ - read_accumulate(data); - - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) - break; - - schedule_timeout(msecs_to_jiffies(timeout)); - } - return 0; -} - -static const struct hwmon_ops amd_energy_ops = { - .is_visible = amd_energy_is_visible, - .read = amd_energy_read, - .read_string = amd_energy_read_labels, -}; - -static int amd_create_sensor(struct device *dev, - struct amd_energy_data *data, - enum hwmon_sensor_types type, u32 config) -{ - struct hwmon_channel_info *info = &data->energy_info; - struct sensor_accumulator *accums; - int i, num_siblings, cpus, sockets; - u32 *s_config; - char (*label_l)[10]; - - /* Identify the number of siblings per core */ - num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1; - - sockets = num_possible_nodes(); - - /* - * Energy counter register is accessed at core level. - * Hence, filterout the siblings. - */ - cpus = num_present_cpus() / num_siblings; - - s_config = devm_kcalloc(dev, cpus + sockets + 1, - sizeof(u32), GFP_KERNEL); - if (!s_config) - return -ENOMEM; - - accums = devm_kcalloc(dev, cpus + sockets, - sizeof(struct sensor_accumulator), - GFP_KERNEL); - if (!accums) - return -ENOMEM; - - label_l = devm_kcalloc(dev, cpus + sockets, - sizeof(*label_l), GFP_KERNEL); - if (!label_l) - return -ENOMEM; - - info->type = type; - info->config = s_config; - - data->nr_cpus = cpus; - data->nr_socks = sockets; - data->accums = accums; - data->label = label_l; - - for (i = 0; i < cpus + sockets; i++) { - s_config[i] = config; - if (i < cpus) - scnprintf(label_l[i], 10, "Ecore%03u", i); - else - scnprintf(label_l[i], 10, "Esocket%u", (i - cpus)); - } - - s_config[i] = 0; - return 0; -} - -static int amd_energy_probe(struct platform_device *pdev) -{ - struct device *hwmon_dev; - struct amd_energy_data *data; - struct device *dev = &pdev->dev; - int ret; - - data = devm_kzalloc(dev, - sizeof(struct amd_energy_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->chip.ops = &amd_energy_ops; - data->chip.info = data->info; - - dev_set_drvdata(dev, data); - /* Populate per-core energy reporting */ - data->info[0] = &data->energy_info; - ret = amd_create_sensor(dev, data, hwmon_energy, - HWMON_E_INPUT | HWMON_E_LABEL); - if (ret) - return ret; - - mutex_init(&data->lock); - get_energy_units(data); - - hwmon_dev = devm_hwmon_device_register_with_info(dev, DRVNAME, - data, - &data->chip, - NULL); - if (IS_ERR(hwmon_dev)) - return PTR_ERR(hwmon_dev); - - /* - * On a system with peak wattage of 250W - * timeout = 2 ^ 32 / 2 ^ energy_units / 250 secs - */ - data->timeout_ms = 1000 * - BIT(min(28, 31 - data->energy_units)) / 250; - - data->wrap_accumulate = kthread_run(energy_accumulator, data, - "%s", dev_name(hwmon_dev)); - return PTR_ERR_OR_ZERO(data->wrap_accumulate); -} - -static int amd_energy_remove(struct platform_device *pdev) -{ - struct amd_energy_data *data = dev_get_drvdata(&pdev->dev); - - if (data && data->wrap_accumulate) - kthread_stop(data->wrap_accumulate); - - return 0; -} - -static const struct platform_device_id amd_energy_ids[] = { - { .name = DRVNAME, }, - {} -}; -MODULE_DEVICE_TABLE(platform, amd_energy_ids); - -static struct platform_driver amd_energy_driver = { - .probe = amd_energy_probe, - .remove = amd_energy_remove, - .id_table = amd_energy_ids, - .driver = { - .name = DRVNAME, - }, -}; - -static struct platform_device *amd_energy_platdev; - -static const struct x86_cpu_id cpu_ids[] __initconst = { - X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x31, NULL), - X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x01, NULL), - X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x30, NULL), - {} -}; -MODULE_DEVICE_TABLE(x86cpu, cpu_ids); - -static int __init amd_energy_init(void) -{ - int ret; - - if (!x86_match_cpu(cpu_ids)) - return -ENODEV; - - ret = platform_driver_register(&amd_energy_driver); - if (ret) - return ret; - - amd_energy_platdev = platform_device_alloc(DRVNAME, 0); - if (!amd_energy_platdev) { - platform_driver_unregister(&amd_energy_driver); - return -ENOMEM; - } - - ret = platform_device_add(amd_energy_platdev); - if (ret) { - platform_device_put(amd_energy_platdev); - platform_driver_unregister(&amd_energy_driver); - return ret; - } - - return ret; -} - -static void __exit amd_energy_exit(void) -{ - platform_device_unregister(amd_energy_platdev); - platform_driver_unregister(&amd_energy_driver); -} - -module_init(amd_energy_init); -module_exit(amd_energy_exit); - -MODULE_DESCRIPTION("Driver for AMD Energy reporting from RAPL MSR via HWMON interface"); -MODULE_AUTHOR("Naveen Krishna Chatradhi <nchatrad@amd.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 28b137eedf2e0a916bd212af673ce46c50d0689a..c31759794a29ad22afa5aaf65290292a0f30b8bf 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -741,7 +741,7 @@ static void applesmc_idev_poll(struct input_dev *idev) static ssize_t applesmc_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "applesmc\n"); + return sysfs_emit(buf, "applesmc\n"); } static ssize_t applesmc_position_show(struct device *dev, @@ -763,8 +763,8 @@ static ssize_t applesmc_position_show(struct device *dev, out: if (ret) return ret; - else - return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z); + + return sysfs_emit(buf, "(%d,%d,%d)\n", x, y, z); } static ssize_t applesmc_light_show(struct device *dev, @@ -804,8 +804,8 @@ static ssize_t applesmc_light_show(struct device *dev, out: if (ret) return ret; - else - return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right); + + return sysfs_emit(sysfsbuf, "(%d,%d)\n", left, right); } /* Displays sensor key as label */ @@ -814,7 +814,7 @@ static ssize_t applesmc_show_sensor_label(struct device *dev, { const char *key = smcreg.index[to_index(devattr)]; - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key); + return sysfs_emit(sysfsbuf, "%s\n", key); } /* Displays degree Celsius * 1000 */ @@ -832,7 +832,7 @@ static ssize_t applesmc_show_temperature(struct device *dev, temp = 250 * (value >> 6); - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", temp); + return sysfs_emit(sysfsbuf, "%d\n", temp); } static ssize_t applesmc_show_fan_speed(struct device *dev, @@ -851,7 +851,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev, return ret; speed = ((buffer[0] << 8 | buffer[1]) >> 2); - return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed); + return sysfs_emit(sysfsbuf, "%u\n", speed); } static ssize_t applesmc_store_fan_speed(struct device *dev, @@ -891,7 +891,7 @@ static ssize_t applesmc_show_fan_manual(struct device *dev, return ret; manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01; - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual); + return sysfs_emit(sysfsbuf, "%d\n", manual); } static ssize_t applesmc_store_fan_manual(struct device *dev, @@ -943,14 +943,14 @@ static ssize_t applesmc_show_fan_position(struct device *dev, if (ret) return ret; - else - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4); + + return sysfs_emit(sysfsbuf, "%s\n", buffer + 4); } static ssize_t applesmc_calibrate_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { - return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y); + return sysfs_emit(sysfsbuf, "(%d,%d)\n", rest_x, rest_y); } static ssize_t applesmc_calibrate_store(struct device *dev, @@ -992,7 +992,7 @@ static ssize_t applesmc_key_count_show(struct device *dev, count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) + ((u32)buffer[2]<<8) + buffer[3]; - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count); + return sysfs_emit(sysfsbuf, "%d\n", count); } static ssize_t applesmc_key_at_index_read_show(struct device *dev, @@ -1020,7 +1020,7 @@ static ssize_t applesmc_key_at_index_data_length_show(struct device *dev, if (IS_ERR(entry)) return PTR_ERR(entry); - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len); + return sysfs_emit(sysfsbuf, "%d\n", entry->len); } static ssize_t applesmc_key_at_index_type_show(struct device *dev, @@ -1032,7 +1032,7 @@ static ssize_t applesmc_key_at_index_type_show(struct device *dev, if (IS_ERR(entry)) return PTR_ERR(entry); - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type); + return sysfs_emit(sysfsbuf, "%s\n", entry->type); } static ssize_t applesmc_key_at_index_name_show(struct device *dev, @@ -1044,13 +1044,13 @@ static ssize_t applesmc_key_at_index_name_show(struct device *dev, if (IS_ERR(entry)) return PTR_ERR(entry); - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key); + return sysfs_emit(sysfsbuf, "%s\n", entry->key); } static ssize_t applesmc_key_at_index_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index); + return sysfs_emit(sysfsbuf, "%d\n", key_at_index); } static ssize_t applesmc_key_at_index_store(struct device *dev, diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index 99494056f4bd9ff9f8a2be669b043674b02fde28..3a5807e4a2efb8d5d084a3083e9b8c328d0be9b5 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -53,11 +53,17 @@ #define CMD_TIMEOUT_MS 250 #define SECONDS_PER_HOUR (60 * 60) #define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24) +#define RAIL_COUNT 3 /* 3v3 + 5v + 12v */ +#define TEMP_COUNT 2 #define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */ -#define PSU_CMD_IN_VOLTS 0x88 /* the rest of the commands expect length 3 */ +#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */ +#define PSU_CMD_RAIL_VOLTS_LCRIT 0x44 +#define PSU_CMD_RAIL_AMPS_HCRIT 0x46 +#define PSU_CMD_TEMP_HCRIT 0x4F +#define PSU_CMD_IN_VOLTS 0x88 #define PSU_CMD_IN_AMPS 0x89 -#define PSU_CMD_RAIL_OUT_VOLTS 0x8B +#define PSU_CMD_RAIL_VOLTS 0x8B #define PSU_CMD_RAIL_AMPS 0x8C #define PSU_CMD_TEMP0 0x8D #define PSU_CMD_TEMP1 0x8E @@ -116,30 +122,25 @@ struct corsairpsu_data { u8 *cmd_buffer; char vendor[REPLY_SIZE]; char product[REPLY_SIZE]; + long temp_crit[TEMP_COUNT]; + long in_crit[RAIL_COUNT]; + long in_lcrit[RAIL_COUNT]; + long curr_crit[RAIL_COUNT]; + u8 temp_crit_support; + u8 in_crit_support; + u8 in_lcrit_support; + u8 curr_crit_support; + bool in_curr_cmd_support; /* not all commands are supported on every PSU */ }; /* some values are SMBus LINEAR11 data which need a conversion */ -static int corsairpsu_linear11_to_int(const int val) +static int corsairpsu_linear11_to_int(const u16 val, const int scale) { - int exp = (val & 0xFFFF) >> 0x0B; - int mant = val & 0x7FF; - int i; - - if (exp > 0x0F) - exp -= 0x20; - if (mant > 0x3FF) - mant -= 0x800; - if ((mant & 0x01) == 1) - ++mant; - if (exp < 0) { - for (i = 0; i < -exp; ++i) - mant /= 2; - } else { - for (i = 0; i < exp; ++i) - mant *= 2; - } + const int exp = ((s16)val) >> 11; + const int mant = (((s16)(val & 0x7ff)) << 5) >> 5; + const int result = mant * scale; - return mant; + return (exp >= 0) ? (result << exp) : (result >> -exp); } static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data) @@ -207,7 +208,10 @@ static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, voi mutex_lock(&priv->lock); switch (cmd) { - case PSU_CMD_RAIL_OUT_VOLTS: + case PSU_CMD_RAIL_VOLTS_HCRIT: + case PSU_CMD_RAIL_VOLTS_LCRIT: + case PSU_CMD_RAIL_AMPS_HCRIT: + case PSU_CMD_RAIL_VOLTS: case PSU_CMD_RAIL_AMPS: case PSU_CMD_RAIL_WATTS: ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL); @@ -243,20 +247,24 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l */ tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; switch (cmd) { + case PSU_CMD_RAIL_VOLTS_HCRIT: + case PSU_CMD_RAIL_VOLTS_LCRIT: + case PSU_CMD_RAIL_AMPS_HCRIT: + case PSU_CMD_TEMP_HCRIT: case PSU_CMD_IN_VOLTS: case PSU_CMD_IN_AMPS: - case PSU_CMD_RAIL_OUT_VOLTS: + case PSU_CMD_RAIL_VOLTS: case PSU_CMD_RAIL_AMPS: case PSU_CMD_TEMP0: case PSU_CMD_TEMP1: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF) * 1000; + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000); break; case PSU_CMD_FAN: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF); + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); break; case PSU_CMD_RAIL_WATTS: case PSU_CMD_TOTAL_WATTS: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF) * 1000000; + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000); break; case PSU_CMD_TOTAL_UPTIME: case PSU_CMD_UPTIME: @@ -270,75 +278,265 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l return ret; } -static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type, - u32 attr, int channel) +static void corsairpsu_get_criticals(struct corsairpsu_data *priv) { - if (type == hwmon_temp && (attr == hwmon_temp_input || attr == hwmon_temp_label)) - return 0444; - else if (type == hwmon_fan && (attr == hwmon_fan_input || attr == hwmon_fan_label)) - return 0444; - else if (type == hwmon_power && (attr == hwmon_power_input || attr == hwmon_power_label)) - return 0444; - else if (type == hwmon_in && (attr == hwmon_in_input || attr == hwmon_in_label)) + long tmp; + int rail; + + for (rail = 0; rail < TEMP_COUNT; ++rail) { + if (!corsairpsu_get_value(priv, PSU_CMD_TEMP_HCRIT, rail, &tmp)) { + priv->temp_crit_support |= BIT(rail); + priv->temp_crit[rail] = tmp; + } + } + + for (rail = 0; rail < RAIL_COUNT; ++rail) { + if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_HCRIT, rail, &tmp)) { + priv->in_crit_support |= BIT(rail); + priv->in_crit[rail] = tmp; + } + + if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_LCRIT, rail, &tmp)) { + priv->in_lcrit_support |= BIT(rail); + priv->in_lcrit[rail] = tmp; + } + + if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS_HCRIT, rail, &tmp)) { + priv->curr_crit_support |= BIT(rail); + priv->curr_crit[rail] = tmp; + } + } +} + +static void corsairpsu_check_cmd_support(struct corsairpsu_data *priv) +{ + long tmp; + + priv->in_curr_cmd_support = !corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, &tmp); +} + +static umode_t corsairpsu_hwmon_temp_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) +{ + umode_t res = 0444; + + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_label: + case hwmon_temp_crit: + if (channel > 0 && !(priv->temp_crit_support & BIT(channel - 1))) + res = 0; + break; + default: + break; + } + + return res; +} + +static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) +{ + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_label: return 0444; - else if (type == hwmon_curr && (attr == hwmon_curr_input || attr == hwmon_curr_label)) + default: + return 0; + } +} + +static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) +{ + switch (attr) { + case hwmon_power_input: + case hwmon_power_label: return 0444; + default: + return 0; + }; +} - return 0; +static umode_t corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) +{ + umode_t res = 0444; + + switch (attr) { + case hwmon_in_input: + case hwmon_in_label: + case hwmon_in_crit: + if (channel > 0 && !(priv->in_crit_support & BIT(channel - 1))) + res = 0; + break; + case hwmon_in_lcrit: + if (channel > 0 && !(priv->in_lcrit_support & BIT(channel - 1))) + res = 0; + break; + default: + break; + }; + + return res; } -static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, - int channel, long *val) +static umode_t corsairpsu_hwmon_curr_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) { - struct corsairpsu_data *priv = dev_get_drvdata(dev); - int ret; + umode_t res = 0444; + + switch (attr) { + case hwmon_curr_input: + if (channel == 0 && !priv->in_curr_cmd_support) + res = 0; + break; + case hwmon_curr_label: + case hwmon_curr_crit: + if (channel > 0 && !(priv->curr_crit_support & BIT(channel - 1))) + res = 0; + break; + default: + break; + } + + return res; +} + +static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct corsairpsu_data *priv = data; + + switch (type) { + case hwmon_temp: + return corsairpsu_hwmon_temp_is_visible(priv, attr, channel); + case hwmon_fan: + return corsairpsu_hwmon_fan_is_visible(priv, attr, channel); + case hwmon_power: + return corsairpsu_hwmon_power_is_visible(priv, attr, channel); + case hwmon_in: + return corsairpsu_hwmon_in_is_visible(priv, attr, channel); + case hwmon_curr: + return corsairpsu_hwmon_curr_is_visible(priv, attr, channel); + default: + return 0; + } +} + +static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, int channel, + long *val) +{ + int err = -EOPNOTSUPP; + + switch (attr) { + case hwmon_temp_input: + return corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0, + channel, val); + case hwmon_temp_crit: + *val = priv->temp_crit[channel]; + err = 0; + break; + default: + break; + } - if (type == hwmon_temp && attr == hwmon_temp_input && channel < 2) { - ret = corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0, channel, - val); - } else if (type == hwmon_fan && attr == hwmon_fan_input) { - ret = corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val); - } else if (type == hwmon_power && attr == hwmon_power_input) { + return err; +} + +static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel, + long *val) +{ + if (attr == hwmon_power_input) { switch (channel) { case 0: - ret = corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val); - break; + return corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val); case 1 ... 3: - ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val); - break; + return corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val); default: - return -EOPNOTSUPP; + break; } - } else if (type == hwmon_in && attr == hwmon_in_input) { + } + + return -EOPNOTSUPP; +} + +static int corsairpsu_hwmon_in_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val) +{ + int err = -EOPNOTSUPP; + + switch (attr) { + case hwmon_in_input: switch (channel) { case 0: - ret = corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val); - break; + return corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val); case 1 ... 3: - ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_OUT_VOLTS, channel - 1, val); - break; + return corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS, channel - 1, val); default: - return -EOPNOTSUPP; + break; } - } else if (type == hwmon_curr && attr == hwmon_curr_input) { + break; + case hwmon_in_crit: + *val = priv->in_crit[channel - 1]; + err = 0; + break; + case hwmon_in_lcrit: + *val = priv->in_lcrit[channel - 1]; + err = 0; + break; + } + + return err; +} + +static int corsairpsu_hwmon_curr_read(struct corsairpsu_data *priv, u32 attr, int channel, + long *val) +{ + int err = -EOPNOTSUPP; + + switch (attr) { + case hwmon_curr_input: switch (channel) { case 0: - ret = corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val); - break; + return corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val); case 1 ... 3: - ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val); - break; + return corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val); default: - return -EOPNOTSUPP; + break; } - } else { - return -EOPNOTSUPP; + break; + case hwmon_curr_crit: + *val = priv->curr_crit[channel - 1]; + err = 0; + break; + default: + break; } - if (ret < 0) - return ret; + return err; +} - return 0; +static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + struct corsairpsu_data *priv = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + return corsairpsu_hwmon_temp_read(priv, attr, channel, val); + case hwmon_fan: + if (attr == hwmon_fan_input) + return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val); + return -EOPNOTSUPP; + case hwmon_power: + return corsairpsu_hwmon_power_read(priv, attr, channel, val); + case hwmon_in: + return corsairpsu_hwmon_in_read(priv, attr, channel, val); + case hwmon_curr: + return corsairpsu_hwmon_curr_read(priv, attr, channel, val); + default: + return -EOPNOTSUPP; + } } static int corsairpsu_hwmon_ops_read_string(struct device *dev, enum hwmon_sensor_types type, @@ -374,8 +572,8 @@ static const struct hwmon_channel_info *corsairpsu_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL), HWMON_CHANNEL_INFO(power, @@ -385,14 +583,14 @@ static const struct hwmon_channel_info *corsairpsu_info[] = { HWMON_P_INPUT | HWMON_P_LABEL), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, - HWMON_I_INPUT | HWMON_I_LABEL, - HWMON_I_INPUT | HWMON_I_LABEL, - HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT, + HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT, + HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT), HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_LABEL, - HWMON_C_INPUT | HWMON_C_LABEL, - HWMON_C_INPUT | HWMON_C_LABEL, - HWMON_C_INPUT | HWMON_C_LABEL), + HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT, + HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT, + HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT), NULL }; @@ -527,6 +725,9 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id goto fail_and_stop; } + corsairpsu_get_criticals(priv); + corsairpsu_check_cmd_support(priv); + priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv, &corsairpsu_chip_info, 0); diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 73b9db9e3aab66715274f1a73a7e739aeadd3e74..2970892bed829026ff99ba001f12d4b0a012fe66 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1210,6 +1210,14 @@ static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = { }, .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], }, + { + .ident = "Dell Latitude E7440", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude E7440"), + }, + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], + }, { } }; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index e1d742bfc74c97978cf02a0c2523568e37da1998..bf1c4b7ecb404a8223a5aff4085614be34eb3cc1 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -326,7 +326,7 @@ static struct attribute *ds1621_attributes[] = { static umode_t ds1621_attribute_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct ds1621_data *data = dev_get_drvdata(dev); if (attr == &dev_attr_update_interval.attr) diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index ef88a156efc2f862ff0f483c949c40ce68d4187f..ceffc76a0c515437f70387d7f0eba2378597aae9 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -509,7 +509,7 @@ error: /* SysFS structs */ /*****************************************************************************/ -/* Temprature sensors */ +/* Temperature sensors */ static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_value, 0); static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_value, 1); static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_value, 2); @@ -713,7 +713,7 @@ static int fts_detect(struct i2c_client *client, { int val; - /* detection works with revsion greater or equal to 0x2b */ + /* detection works with revision greater or equal to 0x2b */ val = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG); if (val < 0x2b) return -ENODEV; diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 6c684058bfdfc0c14f616e839517df95639b8772..fd47ab4e68922ada1fa724d42c672c0848a6427c 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -79,7 +79,7 @@ static struct attribute *hwmon_dev_attrs[] = { static umode_t hwmon_dev_name_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); if (to_hwmon_device(dev)->name == NULL) return 0; diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index f4c7b5f7635908d3fbc6e0dc2bd162abbbcca6fd..fc3007c3e85caf20cf3caacff8067e159126c242 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -259,7 +259,7 @@ static ssize_t ina209_interval_show(struct device *dev, { struct ina209_data *data = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval); + return sysfs_emit(buf, "%d\n", data->update_interval); } /* @@ -343,7 +343,7 @@ static ssize_t ina209_value_show(struct device *dev, return PTR_ERR(data); val = ina209_from_reg(attr->index, data->regs[attr->index]); - return snprintf(buf, PAGE_SIZE, "%ld\n", val); + return sysfs_emit(buf, "%ld\n", val); } static ssize_t ina209_alarm_show(struct device *dev, @@ -363,7 +363,7 @@ static ssize_t ina209_alarm_show(struct device *dev, * All alarms are in the INA209_STATUS register. To avoid a long * switch statement, the mask is passed in attr->index */ - return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask)); + return sysfs_emit(buf, "%u\n", !!(status & mask)); } /* Shunt voltage, history, limits, alarms */ diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index ca97f9e931bc0232445c0c14216756e615d12d98..00fc70305a890df863e71704ad2452a64221dde5 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -310,8 +310,7 @@ static ssize_t ina2xx_value_show(struct device *dev, if (err < 0) return err; - return snprintf(buf, PAGE_SIZE, "%d\n", - ina2xx_get_value(data, attr->index, regval)); + return sysfs_emit(buf, "%d\n", ina2xx_get_value(data, attr->index, regval)); } static int ina226_reg_to_alert(struct ina2xx_data *data, u8 bit, u16 regval) @@ -386,7 +385,7 @@ static ssize_t ina226_alert_show(struct device *dev, val = ina226_reg_to_alert(data, attr->index, regval); } - ret = snprintf(buf, PAGE_SIZE, "%d\n", val); + ret = sysfs_emit(buf, "%d\n", val); abort: mutex_unlock(&data->config_lock); return ret; @@ -450,7 +449,7 @@ static ssize_t ina226_alarm_show(struct device *dev, alarm = (regval & BIT(attr->index)) && (regval & INA226_ALERT_FUNCTION_FLAG); - return snprintf(buf, PAGE_SIZE, "%d\n", alarm); + return sysfs_emit(buf, "%d\n", alarm); } /* @@ -481,7 +480,7 @@ static ssize_t ina2xx_shunt_show(struct device *dev, { struct ina2xx_data *data = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%li\n", data->rshunt); + return sysfs_emit(buf, "%li\n", data->rshunt); } static ssize_t ina2xx_shunt_store(struct device *dev, @@ -537,7 +536,7 @@ static ssize_t ina226_interval_show(struct device *dev, if (status) return status; - return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval)); + return sysfs_emit(buf, "%d\n", ina226_reg_to_interval(regval)); } /* shunt voltage */ diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index d80bd3efcd6dad68627868fa1ba2867544eb12d4..c602583d19f3e89d8c08956db30bbeecef3cfea5 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -698,7 +698,7 @@ static ssize_t ina3221_shunt_show(struct device *dev, unsigned int channel = sd_attr->index; struct ina3221_input *input = &ina->inputs[channel]; - return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); + return sysfs_emit(buf, "%d\n", input->shunt_resistor); } static ssize_t ina3221_shunt_store(struct device *dev, diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index 17d5e6b91c8a62d9ed6604a7be3d42063a711bd9..bd7ed2ed3a1e63e6912f5febddd146476e670382 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -99,6 +99,50 @@ static const struct hwmon_channel_info *n3000bmc_hinfo[] = { NULL }; +static const struct m10bmc_sdata d5005bmc_temp_tbl[] = { + { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Inlet Air Temperature" }, + { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Core Temperature" }, + { 0x11c, 0x120, 0x124, 0x128, 0x0, 500, "Board Exhaust Air Temperature" }, + { 0x12c, 0x130, 0x134, 0x0, 0x0, 500, "FPGA Transceiver Temperature" }, + { 0x138, 0x13c, 0x140, 0x144, 0x0, 500, "RDIMM0 Temperature" }, + { 0x148, 0x14c, 0x150, 0x154, 0x0, 500, "RDIMM1 Temperature" }, + { 0x158, 0x15c, 0x160, 0x164, 0x0, 500, "RDIMM2 Temperature" }, + { 0x168, 0x16c, 0x170, 0x174, 0x0, 500, "RDIMM3 Temperature" }, + { 0x178, 0x17c, 0x180, 0x0, 0x0, 500, "QSFP0 Temperature" }, + { 0x188, 0x18c, 0x190, 0x0, 0x0, 500, "QSFP1 Temperature" }, + { 0x1a0, 0x1a4, 0x1a8, 0x0, 0x0, 500, "3.3v Temperature" }, + { 0x1bc, 0x1c0, 0x1c4, 0x0, 0x0, 500, "VCCERAM Temperature" }, + { 0x1d8, 0x1dc, 0x1e0, 0x0, 0x0, 500, "VCCR Temperature" }, + { 0x1f4, 0x1f8, 0x1fc, 0x0, 0x0, 500, "VCCT Temperature" }, + { 0x210, 0x214, 0x218, 0x0, 0x0, 500, "1.8v Temperature" }, + { 0x22c, 0x230, 0x234, 0x0, 0x0, 500, "12v Backplane Temperature" }, + { 0x248, 0x24c, 0x250, 0x0, 0x0, 500, "12v AUX Temperature" }, +}; + +static const struct m10bmc_sdata d5005bmc_in_tbl[] = { + { 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" }, + { 0x194, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" }, + { 0x198, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" }, + { 0x1ac, 0x1b0, 0x1b4, 0x0, 0x0, 1, "3.3v Voltage" }, + { 0x1c8, 0x1cc, 0x1d0, 0x0, 0x0, 1, "VCCERAM Voltage" }, + { 0x1e4, 0x1e8, 0x1ec, 0x0, 0x0, 1, "VCCR Voltage" }, + { 0x200, 0x204, 0x208, 0x0, 0x0, 1, "VCCT Voltage" }, + { 0x21c, 0x220, 0x224, 0x0, 0x0, 1, "1.8v Voltage" }, + { 0x238, 0x0, 0x0, 0x0, 0x23c, 1, "12v Backplane Voltage" }, + { 0x254, 0x0, 0x0, 0x0, 0x258, 1, "12v AUX Voltage" }, +}; + +static const struct m10bmc_sdata d5005bmc_curr_tbl[] = { + { 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" }, + { 0x1b8, 0x0, 0x0, 0x0, 0x0, 1, "3.3v Current" }, + { 0x1d4, 0x0, 0x0, 0x0, 0x0, 1, "VCCERAM Current" }, + { 0x1f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCR Current" }, + { 0x20c, 0x0, 0x0, 0x0, 0x0, 1, "VCCT Current" }, + { 0x228, 0x0, 0x0, 0x0, 0x0, 1, "1.8v Current" }, + { 0x240, 0x244, 0x0, 0x0, 0x0, 1, "12v Backplane Current" }, + { 0x25c, 0x260, 0x0, 0x0, 0x0, 1, "12v AUX Current" }, +}; + static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = { .tables = { [hwmon_temp] = n3000bmc_temp_tbl, @@ -110,6 +154,80 @@ static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = { .hinfo = n3000bmc_hinfo, }; +static const struct hwmon_channel_info *d5005bmc_hinfo[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT | + HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT | + HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT | + HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT | + HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT | + HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL), + NULL +}; + +static const struct m10bmc_hwmon_board_data d5005bmc_hwmon_bdata = { + .tables = { + [hwmon_temp] = d5005bmc_temp_tbl, + [hwmon_in] = d5005bmc_in_tbl, + [hwmon_curr] = d5005bmc_curr_tbl, + }, + + .hinfo = d5005bmc_hinfo, +}; + static umode_t m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -316,6 +434,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { .name = "n3000bmc-hwmon", .driver_data = (unsigned long)&n3000bmc_hwmon_bdata, }, + { + .name = "d5005bmc-hwmon", + .driver_data = (unsigned long)&d5005bmc_hwmon_bdata, + }, { } }; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index fac9b5c68a6a03288704482e860f19aa735d5951..1f93134afcb9f90351ea97324d82bde0bf150251 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -1981,7 +1981,7 @@ static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3); static umode_t it87_in_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct it87_data *data = dev_get_drvdata(dev); int i = index / 5; /* voltage index */ int a = index % 5; /* attribute index */ @@ -2065,7 +2065,7 @@ static const struct attribute_group it87_group_in = { static umode_t it87_temp_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct it87_data *data = dev_get_drvdata(dev); int i = index / 7; /* temperature index */ int a = index % 7; /* attribute index */ @@ -2126,7 +2126,7 @@ static const struct attribute_group it87_group_temp = { static umode_t it87_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct it87_data *data = dev_get_drvdata(dev); if ((index == 2 || index == 3) && !data->has_vid) @@ -2158,7 +2158,7 @@ static const struct attribute_group it87_group = { static umode_t it87_fan_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct it87_data *data = dev_get_drvdata(dev); int i = index / 5; /* fan index */ int a = index % 5; /* attribute index */ @@ -2229,7 +2229,7 @@ static const struct attribute_group it87_group_fan = { static umode_t it87_pwm_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct it87_data *data = dev_get_drvdata(dev); int i = index / 4; /* pwm index */ int a = index % 4; /* attribute index */ @@ -2290,7 +2290,7 @@ static const struct attribute_group it87_group_pwm = { static umode_t it87_auto_pwm_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct it87_data *data = dev_get_drvdata(dev); int i = index / 11; /* pwm index */ int a = index % 11; /* attribute index */ diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index c83eb2fd80eb346f43984a72a9ff2b534eb4cba1..1109fffa76fb08954ed654004123c2ddfc442049 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -280,7 +280,7 @@ static ssize_t pem_bool_show(struct device *dev, struct device_attribute *da, return PTR_ERR(data); status = data->data_string[attr->nr] & attr->index; - return snprintf(buf, PAGE_SIZE, "%d\n", !!status); + return sysfs_emit(buf, "%d\n", !!status); } static ssize_t pem_data_show(struct device *dev, struct device_attribute *da, @@ -296,7 +296,7 @@ static ssize_t pem_data_show(struct device *dev, struct device_attribute *da, value = pem_get_data(data->data_string, sizeof(data->data_string), attr->index); - return snprintf(buf, PAGE_SIZE, "%ld\n", value); + return sysfs_emit(buf, "%ld\n", value); } static ssize_t pem_input_show(struct device *dev, struct device_attribute *da, @@ -312,7 +312,7 @@ static ssize_t pem_input_show(struct device *dev, struct device_attribute *da, value = pem_get_input(data->input_string, sizeof(data->input_string), attr->index); - return snprintf(buf, PAGE_SIZE, "%ld\n", value); + return sysfs_emit(buf, "%ld\n", value); } static ssize_t pem_fan_show(struct device *dev, struct device_attribute *da, @@ -328,7 +328,7 @@ static ssize_t pem_fan_show(struct device *dev, struct device_attribute *da, value = pem_get_fan(data->fan_speed, sizeof(data->fan_speed), attr->index); - return snprintf(buf, PAGE_SIZE, "%ld\n", value); + return sysfs_emit(buf, "%ld\n", value); } /* Voltages */ diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 50f67265c71d879a043854e9b83d40cd1e365b83..c8f93c5d1ccc1ce8eda7368b87d881ff02107473 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -931,7 +931,7 @@ static const struct attribute_group lm63_group_extra_lut = { static umode_t lm63_attribute_mode(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct lm63_data *data = dev_get_drvdata(dev); if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index ba9c868a8641e5c363ec121d47d3eb6f68b569d1..9adebb59f6042b1fc9ea9eae1166d4b02221393d 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -226,7 +226,7 @@ static ssize_t ltc2945_value_show(struct device *dev, value = ltc2945_reg_to_val(dev, attr->index); if (value < 0) return value; - return snprintf(buf, PAGE_SIZE, "%lld\n", value); + return sysfs_emit(buf, "%lld\n", value); } static ssize_t ltc2945_value_store(struct device *dev, @@ -333,7 +333,7 @@ static ssize_t ltc2945_bool_show(struct device *dev, if (fault) /* Clear reported faults in chip register */ regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0); - return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); + return sysfs_emit(buf, "%d\n", !!fault); } /* Input voltages */ diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 78b191b26bb2b8eccd504748b29897069907ea38..689f788b856338d14677b62c12d09496e1d21ba9 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -147,13 +147,13 @@ static ssize_t ltc2990_value_show(struct device *dev, if (unlikely(ret < 0)) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static umode_t ltc2990_attrs_visible(struct kobject *kobj, struct attribute *a, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct ltc2990_data *data = dev_get_drvdata(dev); struct device_attribute *da = container_of(a, struct device_attribute, attr); diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index 321f54e237bdfb97eec7fed562a84ab159dc2369..13b85367a21f44b3b685894a74e556450f6f8713 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -128,7 +128,7 @@ static ssize_t ltc4151_value_show(struct device *dev, return PTR_ERR(data); value = ltc4151_get_value(data, attr->index); - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } /* diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index 7cef3cb2962b90d5cfa257b3b2bbcbd8cf901224..1d18c212054fc2451fd966a66ee937d1fd20ff75 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -139,7 +139,7 @@ static ssize_t ltc4215_voltage_show(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); const int voltage = ltc4215_get_voltage(dev, attr->index); - return snprintf(buf, PAGE_SIZE, "%d\n", voltage); + return sysfs_emit(buf, "%d\n", voltage); } static ssize_t ltc4215_current_show(struct device *dev, @@ -147,7 +147,7 @@ static ssize_t ltc4215_current_show(struct device *dev, { const unsigned int curr = ltc4215_get_current(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", curr); + return sysfs_emit(buf, "%u\n", curr); } static ssize_t ltc4215_power_show(struct device *dev, @@ -159,7 +159,7 @@ static ssize_t ltc4215_power_show(struct device *dev, /* current in mA * voltage in mV == power in uW */ const unsigned int power = abs(output_voltage * curr); - return snprintf(buf, PAGE_SIZE, "%u\n", power); + return sysfs_emit(buf, "%u\n", power); } static ssize_t ltc4215_alarm_show(struct device *dev, @@ -170,7 +170,7 @@ static ssize_t ltc4215_alarm_show(struct device *dev, const u8 reg = data->regs[LTC4215_STATUS]; const u32 mask = attr->index; - return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask)); + return sysfs_emit(buf, "%u\n", !!(reg & mask)); } /* diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c index 3efce6d1cb884c1dd6c0b028b9cd94812c8dc4bc..d2027ca5c925499329a4b5a45e10077692b70e30 100644 --- a/drivers/hwmon/ltc4222.c +++ b/drivers/hwmon/ltc4222.c @@ -94,7 +94,7 @@ static ssize_t ltc4222_value_show(struct device *dev, value = ltc4222_get_value(dev, attr->index); if (value < 0) return value; - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t ltc4222_bool_show(struct device *dev, @@ -112,7 +112,7 @@ static ssize_t ltc4222_bool_show(struct device *dev, if (fault) /* Clear reported faults in chip register */ regmap_update_bits(regmap, attr->nr, attr->index, 0); - return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); + return sysfs_emit(buf, "%d\n", !!fault); } /* Voltages */ diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c index d0beb43abf3f4a5c34945f26582730234fde68ac..75e89cec381ea6f3bb652b70b5b1f7dfdd4d7793 100644 --- a/drivers/hwmon/ltc4260.c +++ b/drivers/hwmon/ltc4260.c @@ -79,7 +79,7 @@ static ssize_t ltc4260_value_show(struct device *dev, value = ltc4260_get_value(dev, attr->index); if (value < 0) return value; - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t ltc4260_bool_show(struct device *dev, @@ -98,7 +98,7 @@ static ssize_t ltc4260_bool_show(struct device *dev, if (fault) /* Clear reported faults in chip register */ regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0); - return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); + return sysfs_emit(buf, "%d\n", !!fault); } /* Voltages */ diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index 1dab84b52df578371d3bcdb24c04553a4b3f3180..b81e9c3d297bc27c99dce9ff2671560117dabb3c 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -130,7 +130,7 @@ static ssize_t ltc4261_value_show(struct device *dev, return PTR_ERR(data); value = ltc4261_get_value(data, attr->index); - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t ltc4261_bool_show(struct device *dev, @@ -147,7 +147,7 @@ static ssize_t ltc4261_bool_show(struct device *dev, if (fault) /* Clear reported faults in chip register */ i2c_smbus_write_byte_data(data->client, LTC4261_FAULT, ~fault); - return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0); + return sysfs_emit(buf, "%d\n", fault ? 1 : 0); } /* diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index a26226e7bc374fe3c1f47126c578472f7f621d04..ae3a6a7bdaa23d9a7fecaf9663353613688dd643 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -187,7 +187,7 @@ static ssize_t max16065_alarm_show(struct device *dev, i2c_smbus_write_byte_data(data->client, MAX16065_FAULT(attr2->nr), val); - return snprintf(buf, PAGE_SIZE, "%d\n", !!val); + return sysfs_emit(buf, "%d\n", !!val); } static ssize_t max16065_input_show(struct device *dev, @@ -200,8 +200,8 @@ static ssize_t max16065_input_show(struct device *dev, if (unlikely(adc < 0)) return adc; - return snprintf(buf, PAGE_SIZE, "%d\n", - ADC_TO_MV(adc, data->range[attr->index])); + return sysfs_emit(buf, "%d\n", + ADC_TO_MV(adc, data->range[attr->index])); } static ssize_t max16065_current_show(struct device *dev, @@ -212,8 +212,8 @@ static ssize_t max16065_current_show(struct device *dev, if (unlikely(data->curr_sense < 0)) return data->curr_sense; - return snprintf(buf, PAGE_SIZE, "%d\n", - ADC_TO_CURR(data->curr_sense, data->curr_gain)); + return sysfs_emit(buf, "%d\n", + ADC_TO_CURR(data->curr_sense, data->curr_gain)); } static ssize_t max16065_limit_store(struct device *dev, @@ -249,8 +249,8 @@ static ssize_t max16065_limit_show(struct device *dev, struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da); struct max16065_data *data = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", - data->limit[attr2->nr][attr2->index]); + return sysfs_emit(buf, "%d\n", + data->limit[attr2->nr][attr2->index]); } /* Construct a sensor_device_attribute structure for each register */ @@ -454,7 +454,7 @@ static struct attribute *max16065_max_attributes[] = { static umode_t max16065_basic_is_visible(struct kobject *kobj, struct attribute *a, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct max16065_data *data = dev_get_drvdata(dev); int index = n / 4; @@ -466,7 +466,7 @@ static umode_t max16065_basic_is_visible(struct kobject *kobj, static umode_t max16065_secondary_is_visible(struct kobject *kobj, struct attribute *a, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct max16065_data *data = dev_get_drvdata(dev); if (index >= data->num_adc) diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index fc3241101178de729943d29a588451fe339b0e47..2895cea5419349b0fd010e4a9c6045cc2a4c0a79 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -460,7 +460,7 @@ static DEVICE_ATTR(dummy, 0, NULL, NULL); static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct max6697_data *data = dev_get_drvdata(dev); const struct max6697_chip_data *chip = data->chip; int channel = index / 7; /* channel number */ diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c index ed8d59d4eecb361c288b0926f222ec1e380634ea..116681fde33d2de2aeea021f3edc10e921e76eb5 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -67,11 +67,13 @@ * @connected: indicates if tachometer is connected; * @reg: register offset; * @mask: fault mask; + * @prsnt: present register offset; */ struct mlxreg_fan_tacho { bool connected; u32 reg; u32 mask; + u32 prsnt; }; /* @@ -92,6 +94,7 @@ struct mlxreg_fan_pwm { * @regmap: register map of parent device; * @tacho: tachometer data; * @pwm: PWM data; + * @tachos_per_drwr - number of tachometers per drawer; * @samples: minimum allowed samples per pulse; * @divider: divider value for tachometer RPM calculation; * @cooling: cooling device levels; @@ -103,6 +106,7 @@ struct mlxreg_fan { struct mlxreg_core_platform_data *pdata; struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO]; struct mlxreg_fan_pwm pwm; + int tachos_per_drwr; int samples; int divider; u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1]; @@ -123,6 +127,26 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, tacho = &fan->tacho[channel]; switch (attr) { case hwmon_fan_input: + /* + * Check FAN presence: FAN related bit in presence register is one, + * if FAN is physically connected, zero - otherwise. + */ + if (tacho->prsnt && fan->tachos_per_drwr) { + err = regmap_read(fan->regmap, tacho->prsnt, ®val); + if (err) + return err; + + /* + * Map channel to presence bit - drawer can be equipped with + * one or few FANs, while presence is indicated per drawer. + */ + if (BIT(channel / fan->tachos_per_drwr) & regval) { + /* FAN is not connected - return zero for FAN speed. */ + *val = 0; + return 0; + } + } + err = regmap_read(fan->regmap, tacho->reg, ®val); if (err) return err; @@ -389,8 +413,8 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, struct mlxreg_core_platform_data *pdata) { struct mlxreg_core_data *data = pdata->data; + int tacho_num = 0, tacho_avail = 0, i; bool configured = false; - int tacho_num = 0, i; int err; fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; @@ -415,7 +439,9 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, fan->tacho[tacho_num].reg = data->reg; fan->tacho[tacho_num].mask = data->mask; + fan->tacho[tacho_num].prsnt = data->reg_prsnt; fan->tacho[tacho_num++].connected = true; + tacho_avail++; } else if (strnstr(data->label, "pwm", sizeof(data->label))) { if (fan->pwm.connected) { dev_err(fan->dev, "duplicate pwm entry: %s\n", @@ -453,6 +479,29 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, } } + if (pdata->capability) { + int drwr_avail; + u32 regval; + + /* Obtain the number of FAN drawers, supported by system. */ + err = regmap_read(fan->regmap, pdata->capability, ®val); + if (err) { + dev_err(fan->dev, "Failed to query capability register 0x%08x\n", + pdata->capability); + return err; + } + + drwr_avail = hweight32(regval); + if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) { + dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n", + drwr_avail, tacho_avail); + return -EINVAL; + } + + /* Set the number of tachometers per one drawer. */ + fan->tachos_per_drwr = tacho_avail / drwr_avail; + } + /* Init cooling levels per PWM state. */ for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++) fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL; diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index a23047a3bfe2cba0588db5cd0e3d3a1a7be10a82..35f8635dc7f3baf02783ead99e7f85b3051d7aee 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * nct6683 - Driver for the hardware monitoring functionality of - * Nuvoton NCT6683D/NCT6687D eSIO + * Nuvoton NCT6683D/NCT6686D/NCT6687D eSIO * * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net> * @@ -12,6 +12,7 @@ * * Chip #vin #fan #pwm #temp chip ID * nct6683d 21(1) 16 8 32(1) 0xc730 + * nct6686d 21(1) 16 8 32(1) 0xd440 * nct6687d 21(1) 16 8 32(1) 0xd590 * * Notes: @@ -33,7 +34,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> -enum kinds { nct6683, nct6687 }; +enum kinds { nct6683, nct6686, nct6687 }; static bool force; module_param(force, bool, 0); @@ -41,11 +42,13 @@ MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors"); static const char * const nct6683_device_names[] = { "nct6683", + "nct6686", "nct6687", }; static const char * const nct6683_chip_names[] = { "NCT6683D", + "NCT6686D", "NCT6687D", }; @@ -66,6 +69,7 @@ static const char * const nct6683_chip_names[] = { #define SIO_NCT6681_ID 0xb270 /* for later */ #define SIO_NCT6683_ID 0xc730 +#define SIO_NCT6686_ID 0xd440 #define SIO_NCT6687_ID 0xd590 #define SIO_ID_MASK 0xFFF0 @@ -488,17 +492,6 @@ static inline long in_from_reg(u16 reg, u8 src) return reg * scale; } -static inline u16 in_to_reg(u32 val, u8 src) -{ - int scale = 16; - - if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB || - src == MON_SRC_VBAT) - scale <<= 1; - - return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127); -} - static u16 nct6683_read(struct nct6683_data *data, u16 reg) { int res; @@ -1362,6 +1355,9 @@ static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data) case SIO_NCT6683_ID: sio_data->kind = nct6683; break; + case SIO_NCT6686_ID: + sio_data->kind = nct6686; + break; case SIO_NCT6687_ID: sio_data->kind = nct6687; break; diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 3aad62a0e66197be3fba07f5033861f8e9cd3de4..8587189c7f15090129fad800652dd00afe865f8e 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -326,18 +326,27 @@ struct ntc_data { static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) { struct iio_channel *channel = pdata->chan; - int raw, uv, ret; + int uv, ret; - ret = iio_read_channel_raw(channel, &raw); + ret = iio_read_channel_processed_scale(channel, &uv, 1000); if (ret < 0) { - pr_err("read channel() error: %d\n", ret); - return ret; - } + int raw; - ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000); - if (ret < 0) { - /* Assume 12 bit ADC with vref at pullup_uv */ - uv = (pdata->pullup_uv * (s64)raw) >> 12; + /* + * This fallback uses a raw read and then + * assumes the ADC is 12 bits, scaling with + * a factor 1000 to get to microvolts. + */ + ret = iio_read_channel_raw(channel, &raw); + if (ret < 0) { + pr_err("read channel() error: %d\n", ret); + return ret; + } + ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000); + if (ret < 0) { + /* Assume 12 bit ADC with vref at pullup_uv */ + uv = (pdata->pullup_uv * (s64)raw) >> 12; + } } return uv; diff --git a/drivers/hwmon/nzxt-kraken2.c b/drivers/hwmon/nzxt-kraken2.c new file mode 100644 index 0000000000000000000000000000000000000000..89f7ea4f42d47c2923934fa309b0b0d76f622487 --- /dev/null +++ b/drivers/hwmon/nzxt-kraken2.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * nzxt-kraken2.c - hwmon driver for NZXT Kraken X42/X52/X62/X72 coolers + * + * The device asynchronously sends HID reports (with id 0x04) twice a second to + * communicate current fan speed, pump speed and coolant temperature. The + * device does not respond to Get_Report requests for this status report. + * + * Copyright 2019-2021 Jonas Malaco <jonas@protocubo.io> + */ + +#include <asm/unaligned.h> +#include <linux/hid.h> +#include <linux/hwmon.h> +#include <linux/jiffies.h> +#include <linux/module.h> + +#define STATUS_REPORT_ID 0x04 +#define STATUS_VALIDITY 2 /* seconds; equivalent to 4 missed updates */ + +static const char *const kraken2_temp_label[] = { + "Coolant", +}; + +static const char *const kraken2_fan_label[] = { + "Fan", + "Pump", +}; + +struct kraken2_priv_data { + struct hid_device *hid_dev; + struct device *hwmon_dev; + s32 temp_input[1]; + u16 fan_input[2]; + 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) +{ + struct kraken2_priv_data *priv = dev_get_drvdata(dev); + + if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ)) + return -ENODATA; + + switch (type) { + case hwmon_temp: + *val = priv->temp_input[channel]; + break; + case hwmon_fan: + *val = priv->fan_input[channel]; + break; + default: + return -EOPNOTSUPP; /* unreachable */ + } + + return 0; +} + +static int kraken2_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + *str = kraken2_temp_label[channel]; + break; + case hwmon_fan: + *str = kraken2_fan_label[channel]; + break; + default: + return -EOPNOTSUPP; /* unreachable */ + } + return 0; +} + +static const struct hwmon_ops kraken2_hwmon_ops = { + .is_visible = kraken2_is_visible, + .read = kraken2_read, + .read_string = kraken2_read_string, +}; + +static const struct hwmon_channel_info *kraken2_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL), + NULL +}; + +static const struct hwmon_chip_info kraken2_chip_info = { + .ops = &kraken2_hwmon_ops, + .info = kraken2_info, +}; + +static int kraken2_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct kraken2_priv_data *priv; + + if (size < 7 || report->id != STATUS_REPORT_ID) + return 0; + + priv = hid_get_drvdata(hdev); + + /* + * The fractional byte of the coolant temperature has been observed to + * be in the interval [1,9], but some of these steps are also + * consistently skipped for certain integer parts. + * + * For the lack of a better idea, assume that the resolution is 0.1°C, + * and that the missing steps are artifacts of how the firmware + * processes the raw sensor data. + */ + priv->temp_input[0] = data[1] * 1000 + data[2] * 100; + + priv->fan_input[0] = get_unaligned_be16(data + 3); + priv->fan_input[1] = get_unaligned_be16(data + 5); + + priv->updated = jiffies; + + return 0; +} + +static int kraken2_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct kraken2_priv_data *priv; + int ret; + + priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->hid_dev = hdev; + hid_set_drvdata(hdev, priv); + + /* + * Initialize ->updated to STATUS_VALIDITY seconds in the past, making + * the initial empty data invalid for kraken2_read without the need for + * a special case there. + */ + priv->updated = jiffies - STATUS_VALIDITY * HZ; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parse failed with %d\n", ret); + return ret; + } + + /* + * Enable hidraw so existing user-space tools can continue to work. + */ + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hid hw start failed with %d\n", ret); + goto fail_and_stop; + } + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "hid hw open failed with %d\n", ret); + goto fail_and_close; + } + + priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "kraken2", + priv, &kraken2_chip_info, + NULL); + if (IS_ERR(priv->hwmon_dev)) { + ret = PTR_ERR(priv->hwmon_dev); + hid_err(hdev, "hwmon registration failed with %d\n", ret); + goto fail_and_close; + } + + return 0; + +fail_and_close: + hid_hw_close(hdev); +fail_and_stop: + hid_hw_stop(hdev); + return ret; +} + +static void kraken2_remove(struct hid_device *hdev) +{ + struct kraken2_priv_data *priv = hid_get_drvdata(hdev); + + hwmon_device_unregister(priv->hwmon_dev); + + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id kraken2_table[] = { + { HID_USB_DEVICE(0x1e71, 0x170e) }, /* NZXT Kraken X42/X52/X62/X72 */ + { } +}; + +MODULE_DEVICE_TABLE(hid, kraken2_table); + +static struct hid_driver kraken2_driver = { + .name = "nzxt-kraken2", + .id_table = kraken2_table, + .probe = kraken2_probe, + .remove = kraken2_remove, + .raw_event = kraken2_raw_event, +}; + +static int __init kraken2_init(void) +{ + return hid_register_driver(&kraken2_driver); +} + +static void __exit kraken2_exit(void) +{ + hid_unregister_driver(&kraken2_driver); +} + +/* + * When compiled into the kernel, initialize after the hid bus. + */ +late_initcall(kraken2_init); +module_exit(kraken2_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Malaco <jonas@protocubo.io>"); +MODULE_DESCRIPTION("Hwmon driver for NZXT Kraken X42/X52/X62/X72 coolers"); diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 7a5e539b567bfb8778e2a3c763490a816732e312..f1ac153d0b568a94c771af555569f9517bab248e 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -261,7 +261,7 @@ static ssize_t occ_show_temp_1(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t occ_show_temp_2(struct device *dev, @@ -312,7 +312,7 @@ static ssize_t occ_show_temp_2(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t occ_show_temp_10(struct device *dev, @@ -366,7 +366,7 @@ static ssize_t occ_show_temp_10(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t occ_show_freq_1(struct device *dev, @@ -396,7 +396,7 @@ static ssize_t occ_show_freq_1(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t occ_show_freq_2(struct device *dev, @@ -426,7 +426,7 @@ static ssize_t occ_show_freq_2(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t occ_show_power_1(struct device *dev, @@ -465,7 +465,7 @@ static ssize_t occ_show_power_1(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val); + return sysfs_emit(buf, "%llu\n", val); } static u64 occ_get_powr_avg(u64 *accum, u32 *samples) @@ -494,9 +494,9 @@ static ssize_t occ_show_power_2(struct device *dev, switch (sattr->nr) { case 0: - return snprintf(buf, PAGE_SIZE - 1, "%u_%u_%u\n", - get_unaligned_be32(&power->sensor_id), - power->function_id, power->apss_channel); + return sysfs_emit(buf, "%u_%u_%u\n", + get_unaligned_be32(&power->sensor_id), + power->function_id, power->apss_channel); case 1: val = occ_get_powr_avg(&power->accumulator, &power->update_tag); @@ -512,7 +512,7 @@ static ssize_t occ_show_power_2(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val); + return sysfs_emit(buf, "%llu\n", val); } static ssize_t occ_show_power_a0(struct device *dev, @@ -533,8 +533,8 @@ static ssize_t occ_show_power_a0(struct device *dev, switch (sattr->nr) { case 0: - return snprintf(buf, PAGE_SIZE - 1, "%u_system\n", - get_unaligned_be32(&power->sensor_id)); + return sysfs_emit(buf, "%u_system\n", + get_unaligned_be32(&power->sensor_id)); case 1: val = occ_get_powr_avg(&power->system.accumulator, &power->system.update_tag); @@ -547,8 +547,8 @@ static ssize_t occ_show_power_a0(struct device *dev, val = get_unaligned_be16(&power->system.value) * 1000000ULL; break; case 4: - return snprintf(buf, PAGE_SIZE - 1, "%u_proc\n", - get_unaligned_be32(&power->sensor_id)); + return sysfs_emit(buf, "%u_proc\n", + get_unaligned_be32(&power->sensor_id)); case 5: val = occ_get_powr_avg(&power->proc.accumulator, &power->proc.update_tag); @@ -561,8 +561,8 @@ static ssize_t occ_show_power_a0(struct device *dev, val = get_unaligned_be16(&power->proc.value) * 1000000ULL; break; case 8: - return snprintf(buf, PAGE_SIZE - 1, "%u_vdd\n", - get_unaligned_be32(&power->sensor_id)); + return sysfs_emit(buf, "%u_vdd\n", + get_unaligned_be32(&power->sensor_id)); case 9: val = occ_get_powr_avg(&power->vdd.accumulator, &power->vdd.update_tag); @@ -575,8 +575,8 @@ static ssize_t occ_show_power_a0(struct device *dev, val = get_unaligned_be16(&power->vdd.value) * 1000000ULL; break; case 12: - return snprintf(buf, PAGE_SIZE - 1, "%u_vdn\n", - get_unaligned_be32(&power->sensor_id)); + return sysfs_emit(buf, "%u_vdn\n", + get_unaligned_be32(&power->sensor_id)); case 13: val = occ_get_powr_avg(&power->vdn.accumulator, &power->vdn.update_tag); @@ -592,7 +592,7 @@ static ssize_t occ_show_power_a0(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val); + return sysfs_emit(buf, "%llu\n", val); } static ssize_t occ_show_caps_1_2(struct device *dev, @@ -613,7 +613,7 @@ static ssize_t occ_show_caps_1_2(struct device *dev, switch (sattr->nr) { case 0: - return snprintf(buf, PAGE_SIZE - 1, "system\n"); + return sysfs_emit(buf, "system\n"); case 1: val = get_unaligned_be16(&caps->cap) * 1000000ULL; break; @@ -642,7 +642,7 @@ static ssize_t occ_show_caps_1_2(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val); + return sysfs_emit(buf, "%llu\n", val); } static ssize_t occ_show_caps_3(struct device *dev, @@ -663,7 +663,7 @@ static ssize_t occ_show_caps_3(struct device *dev, switch (sattr->nr) { case 0: - return snprintf(buf, PAGE_SIZE - 1, "system\n"); + return sysfs_emit(buf, "system\n"); case 1: val = get_unaligned_be16(&caps->cap) * 1000000ULL; break; @@ -689,7 +689,7 @@ static ssize_t occ_show_caps_3(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val); + return sysfs_emit(buf, "%llu\n", val); } static ssize_t occ_store_caps_user(struct device *dev, @@ -732,21 +732,22 @@ static ssize_t occ_show_extended(struct device *dev, switch (sattr->nr) { case 0: - if (extn->flags & EXTN_FLAG_SENSOR_ID) - rc = snprintf(buf, PAGE_SIZE - 1, "%u", - get_unaligned_be32(&extn->sensor_id)); - else - rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x\n", - extn->name[0], extn->name[1], - extn->name[2], extn->name[3]); + if (extn->flags & EXTN_FLAG_SENSOR_ID) { + rc = sysfs_emit(buf, "%u", + get_unaligned_be32(&extn->sensor_id)); + } else { + rc = sysfs_emit(buf, "%02x%02x%02x%02x\n", + extn->name[0], extn->name[1], + extn->name[2], extn->name[3]); + } break; case 1: - rc = snprintf(buf, PAGE_SIZE - 1, "%02x\n", extn->flags); + rc = sysfs_emit(buf, "%02x\n", extn->flags); break; case 2: - rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x%02x%02x\n", - extn->data[0], extn->data[1], extn->data[2], - extn->data[3], extn->data[4], extn->data[5]); + rc = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n", + extn->data[0], extn->data[1], extn->data[2], + extn->data[3], extn->data[4], extn->data[5]); break; default: return -EINVAL; diff --git a/drivers/hwmon/occ/sysfs.c b/drivers/hwmon/occ/sysfs.c index c73be0747e66962d4c19682335c53f0a1705ac81..03b16abef67fd3b383e27a632e0807788834f0ff 100644 --- a/drivers/hwmon/occ/sysfs.c +++ b/drivers/hwmon/occ/sysfs.c @@ -67,7 +67,7 @@ static ssize_t occ_sysfs_show(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE - 1, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t occ_error_show(struct device *dev, @@ -77,7 +77,7 @@ static ssize_t occ_error_show(struct device *dev, occ_update_response(occ); - return snprintf(buf, PAGE_SIZE - 1, "%d\n", occ->error); + return sysfs_emit(buf, "%d\n", occ->error); } static SENSOR_DEVICE_ATTR(occ_master, 0444, occ_sysfs_show, NULL, 0); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 32d2fc8506213108c115d68e3051ebfd6e0972da..37a5c39784fa96741c1b222cc28cd92c08464d0b 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -56,6 +56,25 @@ config SENSORS_BEL_PFE This driver can also be built as a module. If so, the module will be called bel-pfe. +config SENSORS_BPA_RS600 + tristate "BluTek BPA-RS600 Power Supplies" + help + If you say yes here you get hardware monitoring support for BluTek + BPA-RS600 Power Supplies. + + This driver can also be built as a module. If so, the module will + be called bpa-rs600. + +config SENSORS_FSP_3Y + tristate "FSP/3Y-Power power supplies" + help + If you say yes here you get hardware monitoring support for + FSP/3Y-Power hot-swap power supplies. + Supported models: YH-5151E, YM-2151E + + This driver can also be built as a module. If so, the module will + be called fsp-3y. + config SENSORS_IBM_CFFPS tristate "IBM Common Form Factor Power Supply" depends on LEDS_CLASS @@ -84,6 +103,15 @@ config SENSORS_IR35221 This driver can also be built as a module. If so, the module will be called ir35221. +config SENSORS_IR36021 + tristate "Infineon IR36021" + help + If you say yes here you get hardware monitoring support for Infineon + IR36021. + + This driver can also be built as a module. If so, the module will + be called ir36021. + config SENSORS_IR38064 tristate "Infineon IR38064" help @@ -148,6 +176,15 @@ config SENSORS_LTC3815 This driver can also be built as a module. If so, the module will be called ltc3815. +config SENSORS_MAX15301 + tristate "Maxim MAX15301" + help + If you say yes here you get hardware monitoring support for Maxim + MAX15301, as well as for Flex BMR461. + + This driver can also be built as a module. If so, the module will + be called max15301. + config SENSORS_MAX16064 tristate "Maxim MAX16064" help @@ -247,6 +284,16 @@ config SENSORS_Q54SJ108A2 This driver can also be built as a module. If so, the module will be called q54sj108a2. +config SENSORS_STPDDC60 + tristate "ST STPDDC60" + help + If you say yes here you get hardware monitoring support for ST + STPDDC60 Universal Digital Multicell Controller, as well as for + Flex BMR481. + + This driver can also be built as a module. If so, the module will + be called stpddc60. + config SENSORS_TPS40422 tristate "TI TPS40422" help @@ -257,10 +304,10 @@ config SENSORS_TPS40422 be called tps40422. config SENSORS_TPS53679 - tristate "TI TPS53647, TPS53667, TPS53679, TPS53681, TPS53688" + tristate "TI TPS53647, TPS53667, TPS53676, TPS53679, TPS53681, TPS53688" help If you say yes here you get hardware monitoring support for TI - TPS53647, TPS53667, TPS53679, TPS53681, and TPS53688. + TPS53647, TPS53667, TPS53676, TPS53679, TPS53681, and TPS53688. This driver can also be built as a module. If so, the module will be called tps53679. diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 6a4ba0fdc1db809d4aa8e9590ebca4901d137702..f8dcc27cd56a80b7a6285c278e9fbcac722f256d 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -8,15 +8,19 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o +obj-$(CONFIG_SENSORS_BPA_RS600) += bpa-rs600.o +obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o obj-$(CONFIG_SENSORS_IR35221) += ir35221.o +obj-$(CONFIG_SENSORS_IR36021) += ir36021.o obj-$(CONFIG_SENSORS_IR38064) += ir38064.o obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o +obj-$(CONFIG_SENSORS_MAX15301) += max15301.o obj-$(CONFIG_SENSORS_MAX16064) += max16064.o obj-$(CONFIG_SENSORS_MAX16601) += max16601.o obj-$(CONFIG_SENSORS_MAX20730) += max20730.o @@ -28,6 +32,7 @@ obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o +obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index 4d2e4ddcfbfdd985e983f37fe03ba79c7db6ce4a..ec5f932fc6f0fb6d489418f25beaa1816710759e 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -510,3 +510,4 @@ module_i2c_driver(adm1266_driver); MODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>"); MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 38a6515b07634ffdb01622f13fcc9c22f5ae72cf..980a3850b2f3945c25e4980850f5130925b5d5dd 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -805,3 +805,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); diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index aed7542d7ce54224a71b58014f8b03a39285da5c..4100eefb7ac3237dfbca8912a789d547c272d5d2 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -129,3 +129,4 @@ module_i2c_driver(pfe_pmbus_driver); MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>"); MODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c new file mode 100644 index 0000000000000000000000000000000000000000..f6558ee9dec36d950ae9a72854a5834008112bb4 --- /dev/null +++ b/drivers/hwmon/pmbus/bpa-rs600.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for BluTek BPA-RS600 Power Supplies + * + * Copyright 2021 Allied Telesis Labs + */ + +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pmbus.h> +#include "pmbus.h" + +#define BPARS600_MFR_VIN_MIN 0xa0 +#define BPARS600_MFR_VIN_MAX 0xa1 +#define BPARS600_MFR_IIN_MAX 0xa2 +#define BPARS600_MFR_PIN_MAX 0xa3 +#define BPARS600_MFR_VOUT_MIN 0xa4 +#define BPARS600_MFR_VOUT_MAX 0xa5 +#define BPARS600_MFR_IOUT_MAX 0xa6 +#define BPARS600_MFR_POUT_MAX 0xa7 + +static int bpa_rs600_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + if (page > 0) + return -ENXIO; + + switch (reg) { + case PMBUS_FAN_CONFIG_12: + /* + * Two fans are reported in PMBUS_FAN_CONFIG_12 but there is + * only one fan in the module. Mask out the FAN2 bits. + */ + ret = pmbus_read_byte_data(client, 0, PMBUS_FAN_CONFIG_12); + if (ret >= 0) + ret &= ~(PB_FAN_2_INSTALLED | PB_FAN_2_PULSE_MASK); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int phase, int reg) +{ + int ret; + + if (page > 0) + return -ENXIO; + + switch (reg) { + case PMBUS_VIN_UV_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VIN_MIN); + break; + case PMBUS_VIN_OV_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VIN_MAX); + break; + case PMBUS_VOUT_UV_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VOUT_MIN); + break; + case PMBUS_VOUT_OV_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VOUT_MAX); + break; + case PMBUS_IIN_OC_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_IIN_MAX); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_IOUT_MAX); + break; + case PMBUS_PIN_OP_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_PIN_MAX); + break; + case PMBUS_POUT_OP_WARN_LIMIT: + ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_POUT_MAX); + break; + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VIN_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + case PMBUS_VOUT_OV_FAULT_LIMIT: + /* These commands return data but it is invalid/un-documented */ + ret = -ENXIO; + break; + default: + if (reg >= PMBUS_VIRT_BASE) + ret = -ENXIO; + else + ret = -ENODATA; + break; + } + + return ret; +} + +static struct pmbus_driver_info bpa_rs600_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_FAN] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | + PMBUS_HAVE_FAN12 | + PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_FAN12, + .read_byte_data = bpa_rs600_read_byte_data, + .read_word_data = bpa_rs600_read_word_data, +}; + +static int bpa_rs600_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_READ_WORD_DATA + | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return -ENODEV; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (ret < 0) { + dev_err(dev, "Failed to read Manufacturer Model\n"); + return ret; + } + + if (strncmp(buf, "BPA-RS600", 8)) { + buf[ret] = '\0'; + dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf); + return -ENODEV; + } + + return pmbus_do_probe(client, &bpa_rs600_info); +} + +static const struct i2c_device_id bpa_rs600_id[] = { + { "bpars600", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, bpa_rs600_id); + +static const struct of_device_id __maybe_unused bpa_rs600_of_match[] = { + { .compatible = "blutek,bpa-rs600" }, + {}, +}; +MODULE_DEVICE_TABLE(of, bpa_rs600_of_match); + +static struct i2c_driver bpa_rs600_driver = { + .driver = { + .name = "bpa-rs600", + .of_match_table = of_match_ptr(bpa_rs600_of_match), + }, + .probe_new = bpa_rs600_probe, + .id_table = bpa_rs600_id, +}; + +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); diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c new file mode 100644 index 0000000000000000000000000000000000000000..b177987286ae07f1d973c31e850cbccf750ea2bf --- /dev/null +++ b/drivers/hwmon/pmbus/fsp-3y.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for FSP 3Y-Power PSUs + * + * Copyright (c) 2021 Václav Kubernát, CESNET + * + * This driver is mostly reverse engineered with the help of a tool called pmbus_peek written by + * David Brownell (and later adopted by Jan Kundrát). The device has some sort of a timing issue + * when switching pages, details are explained in the code. The driver support is limited. It + * exposes only the values, that have been tested to work correctly. Unsupported values either + * aren't supported by the devices or their encondings are unknown. + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +#define YM2151_PAGE_12V_LOG 0x00 +#define YM2151_PAGE_12V_REAL 0x00 +#define YM2151_PAGE_5VSB_LOG 0x01 +#define YM2151_PAGE_5VSB_REAL 0x20 +#define YH5151E_PAGE_12V_LOG 0x00 +#define YH5151E_PAGE_12V_REAL 0x00 +#define YH5151E_PAGE_5V_LOG 0x01 +#define YH5151E_PAGE_5V_REAL 0x10 +#define YH5151E_PAGE_3V3_LOG 0x02 +#define YH5151E_PAGE_3V3_REAL 0x11 + +enum chips { + ym2151e, + yh5151e +}; + +struct fsp3y_data { + struct pmbus_driver_info info; + int chip; + int page; +}; + +#define to_fsp3y_data(x) container_of(x, struct fsp3y_data, info) + +static int page_log_to_page_real(int page_log, enum chips chip) +{ + switch (chip) { + case ym2151e: + switch (page_log) { + case YM2151_PAGE_12V_LOG: + return YM2151_PAGE_12V_REAL; + case YM2151_PAGE_5VSB_LOG: + return YM2151_PAGE_5VSB_REAL; + } + return -EINVAL; + case yh5151e: + switch (page_log) { + case YH5151E_PAGE_12V_LOG: + return YH5151E_PAGE_12V_REAL; + case YH5151E_PAGE_5V_LOG: + return YH5151E_PAGE_5V_LOG; + case YH5151E_PAGE_3V3_LOG: + return YH5151E_PAGE_3V3_REAL; + } + return -EINVAL; + } + + return -EINVAL; +} + +static int set_page(struct i2c_client *client, int page_log) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct fsp3y_data *data = to_fsp3y_data(info); + int rv; + int page_real; + + if (page_log < 0) + return 0; + + page_real = page_log_to_page_real(page_log, data->chip); + if (page_real < 0) + return page_real; + + if (data->page != page_real) { + rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page_real); + if (rv < 0) + return rv; + + data->page = page_real; + + /* + * Testing showed that the device has a timing issue. After + * setting a page, it takes a while, before the device actually + * gives the correct values from the correct page. 20 ms was + * tested to be enough to not give wrong values (15 ms wasn't + * enough). + */ + usleep_range(20000, 30000); + } + + return 0; +} + +static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int rv; + + rv = set_page(client, page); + if (rv < 0) + return rv; + + return i2c_smbus_read_byte_data(client, reg); +} + +static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase, int reg) +{ + int rv; + + /* + * This masks commands which weren't tested to work correctly. Some of + * the masked commands return 0xFFFF. These would probably get tagged as + * invalid by pmbus_core. Other ones do return values which might be + * useful (that is, they are not 0xFFFF), but their encoding is unknown, + * and so they are unsupported. + */ + switch (reg) { + case PMBUS_READ_FAN_SPEED_1: + case PMBUS_READ_IIN: + case PMBUS_READ_IOUT: + case PMBUS_READ_PIN: + case PMBUS_READ_POUT: + case PMBUS_READ_TEMPERATURE_1: + case PMBUS_READ_TEMPERATURE_2: + case PMBUS_READ_TEMPERATURE_3: + case PMBUS_READ_VIN: + case PMBUS_READ_VOUT: + case PMBUS_STATUS_WORD: + break; + default: + return -ENXIO; + } + + rv = set_page(client, page); + if (rv < 0) + return rv; + + return i2c_smbus_read_word_data(client, reg); +} + +static struct pmbus_driver_info fsp3y_info[] = { + [ym2151e] = { + .pages = 2, + .func[YM2151_PAGE_12V_LOG] = + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | + PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | + PMBUS_HAVE_FAN12, + .func[YM2151_PAGE_5VSB_LOG] = + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT, + PMBUS_HAVE_IIN, + .read_word_data = fsp3y_read_word_data, + .read_byte_data = fsp3y_read_byte_data, + }, + [yh5151e] = { + .pages = 3, + .func[YH5151E_PAGE_12V_LOG] = + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_POUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3, + .func[YH5151E_PAGE_5V_LOG] = + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_POUT, + .func[YH5151E_PAGE_3V3_LOG] = + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_POUT, + .read_word_data = fsp3y_read_word_data, + .read_byte_data = fsp3y_read_byte_data, + } +}; + +static int fsp3y_detect(struct i2c_client *client) +{ + int rv; + u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; + + rv = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (rv < 0) + return rv; + + buf[rv] = '\0'; + + if (rv == 8) { + if (!strcmp(buf, "YM-2151E")) + return ym2151e; + else if (!strcmp(buf, "YH-5151E")) + return yh5151e; + } + + dev_err(&client->dev, "Unsupported model %.*s\n", rv, buf); + return -ENODEV; +} + +static const struct i2c_device_id fsp3y_id[] = { + {"ym2151e", ym2151e}, + {"yh5151e", yh5151e}, + { } +}; + +static int fsp3y_probe(struct i2c_client *client) +{ + struct fsp3y_data *data; + const struct i2c_device_id *id; + int rv; + + data = devm_kzalloc(&client->dev, sizeof(struct fsp3y_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->chip = fsp3y_detect(client); + if (data->chip < 0) + return data->chip; + + id = i2c_match_id(fsp3y_id, client); + if (data->chip != id->driver_data) + dev_warn(&client->dev, "Device mismatch: Configured %s (%d), detected %d\n", + id->name, (int)id->driver_data, data->chip); + + rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE); + if (rv < 0) + return rv; + data->page = rv; + + data->info = fsp3y_info[data->chip]; + + return pmbus_do_probe(client, &data->info); +} + +MODULE_DEVICE_TABLE(i2c, fsp3y_id); + +static struct i2c_driver fsp3y_driver = { + .driver = { + .name = "fsp3y", + }, + .probe_new = fsp3y_probe, + .id_table = fsp3y_id +}; + +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); diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index ffde5aaa5036b962d49f31e36d5942f2d925f027..5668d8305b78ecbccecfd417c3c358c2bf3aa983 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -625,3 +625,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); diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 88c5865c4d6f8d29db86479aec11c7cd74b548e3..0f614e8d95f674083a7f2c4db12e65efd2bbb4fb 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -70,7 +70,7 @@ static ssize_t ipsps_string_show(struct device *dev, p = memscan(data, '#', rc); *p = '\0'; - return snprintf(buf, PAGE_SIZE, "%s\n", data); + return sysfs_emit(buf, "%s\n", data); } static ssize_t ipsps_fw_version_show(struct device *dev, @@ -91,9 +91,9 @@ static ssize_t ipsps_fw_version_show(struct device *dev, if (rc != 6) return -EPROTO; - return snprintf(buf, PAGE_SIZE, "%u.%02u%u-%u.%02u\n", - data[1], data[2]/* < 100 */, data[3]/*< 10*/, - data[4], data[5]/* < 100 */); + return sysfs_emit(buf, "%u.%02u%u-%u.%02u\n", + data[1], data[2]/* < 100 */, data[3]/*< 10*/, + data[4], data[5]/* < 100 */); } static ssize_t ipsps_mode_show(struct device *dev, @@ -111,19 +111,19 @@ static ssize_t ipsps_mode_show(struct device *dev, switch (rc) { case MODE_ACTIVE: - return snprintf(buf, PAGE_SIZE, "[%s] %s %s\n", - MODE_ACTIVE_STRING, - MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); + return sysfs_emit(buf, "[%s] %s %s\n", + MODE_ACTIVE_STRING, + MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); case MODE_STANDBY: - return snprintf(buf, PAGE_SIZE, "%s [%s] %s\n", - MODE_ACTIVE_STRING, - MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); + return sysfs_emit(buf, "%s [%s] %s\n", + MODE_ACTIVE_STRING, + MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); case MODE_REDUNDANCY: - return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n", - MODE_ACTIVE_STRING, - MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); + return sysfs_emit(buf, "%s %s [%s]\n", + MODE_ACTIVE_STRING, + MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); default: - return snprintf(buf, PAGE_SIZE, "unspecified\n"); + return sysfs_emit(buf, "unspecified\n"); } } @@ -224,3 +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); diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 3aebeb1443fdf70028549e32b43bb4174132c155..a6cf98e496664e1c5b3e7b1197e08f41ac9e1aaa 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -145,3 +145,4 @@ module_i2c_driver(ir35221_driver); MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com"); MODULE_DESCRIPTION("PMBus driver for IR35221"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/ir36021.c b/drivers/hwmon/pmbus/ir36021.c new file mode 100644 index 0000000000000000000000000000000000000000..4dca4767f571389775e451822fb465910dd84401 --- /dev/null +++ b/drivers/hwmon/pmbus/ir36021.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Infineon IR36021 + * + * Copyright (c) 2021 Allied Telesis + */ +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +static struct pmbus_driver_info ir36021_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT + | PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT + | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_STATUS_TEMP, +}; + +static int ir36021_probe(struct i2c_client *client) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_READ_WORD_DATA + | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return -ENODEV; + + ret = i2c_smbus_read_i2c_block_data(client, PMBUS_MFR_MODEL, 2, buf); + if (ret < 0) { + dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n"); + return ret; + } + if (ret != 2 || buf[0] != 0x01 || buf[1] != 0x2d) { + dev_err(&client->dev, "MFR_MODEL unrecognised\n"); + return -ENODEV; + } + + return pmbus_do_probe(client, &ir36021_info); +} + +static const struct i2c_device_id ir36021_id[] = { + { "ir36021", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, ir36021_id); + +static const struct of_device_id __maybe_unused ir36021_of_id[] = { + { .compatible = "infineon,ir36021" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ir36021_of_id); + +static struct i2c_driver ir36021_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ir36021", + .of_match_table = of_match_ptr(ir36021_of_id), + }, + .probe_new = ir36021_probe, + .id_table = ir36021_id, +}; + +module_i2c_driver(ir36021_driver); + +MODULE_AUTHOR("Chris Packham <chris.packham@alliedtelesis.co.nz>"); +MODULE_DESCRIPTION("PMBus driver for Infineon IR36021"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index 46f17c4b48733ec5fa5accaed8f22a34e5e8ed3e..1fb7f124863941218d6f2bb3e7a5c339d26c9a9a 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -61,3 +61,4 @@ module_i2c_driver(ir38064_driver); MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); MODULE_DESCRIPTION("PMBus driver for Infineon IR38064"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index 93ef6d64a33ae06791cad5eae89010dfcc53142a..de3449e4d77a60d60b8aba53b895e99363ebcc61 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -63,3 +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); diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 2bee930d39002150c3854b937a22553c27a1413a..40597a9e799f5d754861f13af8e9003515e694ae 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -332,3 +332,4 @@ module_i2c_driver(isl68137_driver); MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index e9a66fd9e144ecc65f8bfeaf16ec7c25df02b675..d209e0afc2caab17c92dc3f808ba23fb11efb20f 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -511,3 +511,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); diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 7e53fa95b92dbb5e8f472e7361da4bc1c48ed64c..0127273883f0426020e7ed4881a5c193ed2717a0 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -883,3 +883,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); diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index e45e14d26c9a35fa402786e94af0d975f03aa951..8e13a7ddcb4270e6198f8787cf1812566eb2c189 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -208,3 +208,4 @@ module_i2c_driver(ltc3815_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for LTC3815"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c new file mode 100644 index 0000000000000000000000000000000000000000..0b6f88428ea81dfde9fa699e2f2d83e73c93d8e5 --- /dev/null +++ b/drivers/hwmon/pmbus/max15301.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for Maxim MAX15301 + * + * Copyright (c) 2021 Flextronics International Sweden AB + * + * Even though the specification does not specifically mention it, + * extensive empirical testing has revealed that auto-detection of + * limit-registers will fail in a random fashion unless the delay + * parameter is set to above about 80us. The default delay is set + * to 100us to include some safety margin. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/ktime.h> +#include <linux/delay.h> +#include <linux/pmbus.h> +#include "pmbus.h" + +static const struct i2c_device_id max15301_id[] = { + {"bmr461", 0}, + {"max15301", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, max15301_id); + +struct max15301_data { + int id; + ktime_t access; /* Chip access time */ + int delay; /* Delay between chip accesses in us */ + struct pmbus_driver_info info; +}; + +#define to_max15301_data(x) container_of(x, struct max15301_data, info) + +#define MAX15301_WAIT_TIME 100 /* us */ + +static ushort delay = MAX15301_WAIT_TIME; +module_param(delay, ushort, 0644); +MODULE_PARM_DESC(delay, "Delay between chip accesses in us"); + +static struct max15301_data max15301_data = { + .info = { + .pages = 1, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + } +}; + +/* This chip needs a delay between accesses */ +static inline void max15301_wait(const struct max15301_data *data) +{ + if (data->delay) { + s64 delta = ktime_us_delta(ktime_get(), data->access); + + if (delta < data->delay) + udelay(data->delay - delta); + } +} + +static int max15301_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max15301_data *data = to_max15301_data(info); + int ret; + + if (page > 0) + return -ENXIO; + + if (reg >= PMBUS_VIRT_BASE) + return -ENXIO; + + max15301_wait(data); + ret = pmbus_read_word_data(client, page, phase, reg); + data->access = ktime_get(); + + return ret; +} + +static int max15301_read_byte_data(struct i2c_client *client, int page, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max15301_data *data = to_max15301_data(info); + int ret; + + if (page > 0) + return -ENXIO; + + max15301_wait(data); + ret = pmbus_read_byte_data(client, page, reg); + data->access = ktime_get(); + + return ret; +} + +static int max15301_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max15301_data *data = to_max15301_data(info); + int ret; + + if (page > 0) + return -ENXIO; + + if (reg >= PMBUS_VIRT_BASE) + return -ENXIO; + + max15301_wait(data); + ret = pmbus_write_word_data(client, page, reg, word); + data->access = ktime_get(); + + return ret; +} + +static int max15301_write_byte(struct i2c_client *client, int page, u8 value) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max15301_data *data = to_max15301_data(info); + int ret; + + if (page > 0) + return -ENXIO; + + max15301_wait(data); + ret = pmbus_write_byte(client, page, value); + data->access = ktime_get(); + + return ret; +} + +static int max15301_probe(struct i2c_client *client) +{ + int status; + u8 device_id[I2C_SMBUS_BLOCK_MAX + 1]; + const struct i2c_device_id *mid; + struct pmbus_driver_info *info = &max15301_data.info; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_BLOCK_DATA)) + return -ENODEV; + + status = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, device_id); + if (status < 0) { + dev_err(&client->dev, "Failed to read Device Id\n"); + return status; + } + for (mid = max15301_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, device_id, strlen(mid->name))) + break; + } + if (!mid->name[0]) { + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + + max15301_data.delay = delay; + + info->read_byte_data = max15301_read_byte_data; + info->read_word_data = max15301_read_word_data; + info->write_byte = max15301_write_byte; + info->write_word_data = max15301_write_word_data; + + return pmbus_do_probe(client, info); +} + +static struct i2c_driver max15301_driver = { + .driver = { + .name = "max15301", + }, + .probe_new = max15301_probe, + .id_table = max15301_id, +}; + +module_i2c_driver(max15301_driver); + +MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>"); +MODULE_DESCRIPTION("PMBus driver for Maxim MAX15301"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index d79add99083ee806f8b58aafc821326c98d3ca2f..94f86903907194eb4f5124f12b7c2a1a8e151218 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -111,3 +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); diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 0d1204c2dd54086b9810c06d58de832bafdcdbb1..5a226a564776c984de8a1860ebe5e86be0e478ea 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -359,3 +359,4 @@ module_i2c_driver(max16601_driver); MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX16601"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index 9dd3dd79bc182d3e71c2188578101d3ff279c8f3..ba39f03c63744922a254f1fbdb237d00f957af6a 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -785,3 +785,4 @@ module_i2c_driver(max20730_driver); MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX20710 / MAX20730 / MAX20734 / MAX20743"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index 9d42f82fdd997d93def8f9c8559fdee8a27f4ed7..2272dc8c2e380a870087c2fc1d32c60ce3c196fa 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -51,3 +51,4 @@ module_i2c_driver(max20751_driver); MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 17489abc49d55c6cab859181960cf1af6794f843..95d79a64b4836c0ae59ae28f6fa99511a0dbabbd 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -403,3 +403,4 @@ module_i2c_driver(max31785_driver); MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>"); MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index dad66b3c0116831d1b38781afb03962f6111414b..ea7609058a12fc305d1c59c5e6911f7514c5bbdf 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -529,3 +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); diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 329dc851fc5908586e9b5ba0d6604d9984de1980..5e66c28c0b7186d2e76e5d9ba992e67d71e3baea 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -191,3 +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); diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index 60fbdb3713326030f38eea1afd79162cad79f842..eb94bd5f4e2a883925c55e47615ac543b00e07f6 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -766,3 +766,4 @@ module_i2c_driver(mp2975_driver); MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>"); MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/pm6764tr.c b/drivers/hwmon/pmbus/pm6764tr.c index d97cb6d6c87f630f26850a30fd0255a1c5d147fa..e0bbc8a30d21efb08dcb974d552fd00828289d7e 100644 --- a/drivers/hwmon/pmbus/pm6764tr.c +++ b/drivers/hwmon/pmbus/pm6764tr.c @@ -73,3 +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); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index a1b4260e75b2ce1ecee7068c72fe3b47dd40d9ce..618c377664c4160fc968d1435e92950524aba555 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -246,3 +246,4 @@ module_i2c_driver(pmbus_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("Generic PMBus driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 4c30ec89f5bf82b55e6639211e8b95538baa3e73..3968924f85330ebfc6a3c0a5570040306696c44d 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -475,6 +475,7 @@ extern const struct regulator_ops pmbus_regulator_ops; /* Function declarations */ void pmbus_clear_cache(struct i2c_client *client); +void pmbus_set_update(struct i2c_client *client, u8 reg, bool update); int pmbus_set_page(struct i2c_client *client, int page, int phase); int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index aadea85fe630776806f66d38ba1e9b3f2a90a62f..bbd7451781472d005646afdce3bb5e2d605cdbf0 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -139,7 +139,18 @@ void pmbus_clear_cache(struct i2c_client *client) for (sensor = data->sensors; sensor; sensor = sensor->next) sensor->data = -ENODATA; } -EXPORT_SYMBOL_GPL(pmbus_clear_cache); +EXPORT_SYMBOL_NS_GPL(pmbus_clear_cache, PMBUS); + +void pmbus_set_update(struct i2c_client *client, u8 reg, bool update) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor; + + for (sensor = data->sensors; sensor; sensor = sensor->next) + if (sensor->reg == reg) + sensor->update = update; +} +EXPORT_SYMBOL_NS_GPL(pmbus_set_update, PMBUS); int pmbus_set_page(struct i2c_client *client, int page, int phase) { @@ -175,7 +186,7 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase) return 0; } -EXPORT_SYMBOL_GPL(pmbus_set_page); +EXPORT_SYMBOL_NS_GPL(pmbus_set_page, PMBUS); int pmbus_write_byte(struct i2c_client *client, int page, u8 value) { @@ -187,7 +198,7 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value) return i2c_smbus_write_byte(client, value); } -EXPORT_SYMBOL_GPL(pmbus_write_byte); +EXPORT_SYMBOL_NS_GPL(pmbus_write_byte, PMBUS); /* * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if @@ -218,7 +229,7 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, return i2c_smbus_write_word_data(client, reg, word); } -EXPORT_SYMBOL_GPL(pmbus_write_word_data); +EXPORT_SYMBOL_NS_GPL(pmbus_write_word_data, PMBUS); static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, @@ -288,7 +299,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_GPL(pmbus_update_fan); +EXPORT_SYMBOL_NS_GPL(pmbus_update_fan, PMBUS); int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) { @@ -300,7 +311,7 @@ int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) return i2c_smbus_read_word_data(client, reg); } -EXPORT_SYMBOL_GPL(pmbus_read_word_data); +EXPORT_SYMBOL_NS_GPL(pmbus_read_word_data, PMBUS); static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) { @@ -359,7 +370,7 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -EXPORT_SYMBOL_GPL(pmbus_read_byte_data); +EXPORT_SYMBOL_NS_GPL(pmbus_read_byte_data, PMBUS); int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) { @@ -371,7 +382,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value); } -EXPORT_SYMBOL_GPL(pmbus_write_byte_data); +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) @@ -390,7 +401,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, return rv; } -EXPORT_SYMBOL_GPL(pmbus_update_byte_data); +EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, PMBUS); /* * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if @@ -463,14 +474,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_GPL(pmbus_get_fan_rate_device); +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_GPL(pmbus_get_fan_rate_cached); +EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_cached, PMBUS); static void pmbus_clear_fault_page(struct i2c_client *client, int page) { @@ -485,7 +496,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_GPL(pmbus_clear_faults); +EXPORT_SYMBOL_NS_GPL(pmbus_clear_faults, PMBUS); static int pmbus_check_status_cml(struct i2c_client *client) { @@ -537,13 +548,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_GPL(pmbus_check_byte_register); +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_GPL(pmbus_check_word_register); +EXPORT_SYMBOL_NS_GPL(pmbus_check_word_register, PMBUS); const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) { @@ -551,7 +562,7 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) return data->info; } -EXPORT_SYMBOL_GPL(pmbus_get_driver_info); +EXPORT_SYMBOL_NS_GPL(pmbus_get_driver_info, PMBUS); static int pmbus_get_status(struct i2c_client *client, int page, int reg) { @@ -932,7 +943,7 @@ static ssize_t pmbus_show_boolean(struct device *dev, val = pmbus_get_boolean(client, boolean, attr->index); if (val < 0) return val; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t pmbus_show_sensor(struct device *dev, @@ -948,7 +959,7 @@ static ssize_t pmbus_show_sensor(struct device *dev, if (sensor->data < 0) ret = sensor->data; else - ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); + ret = sysfs_emit(buf, "%lld\n", pmbus_reg2data(data, sensor)); mutex_unlock(&data->update_lock); return ret; } @@ -984,7 +995,7 @@ static ssize_t pmbus_show_label(struct device *dev, { struct pmbus_label *label = to_pmbus_label(da); - return snprintf(buf, PAGE_SIZE, "%s\n", label->label); + return sysfs_emit(buf, "%s\n", label->label); } static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) @@ -2024,7 +2035,7 @@ static ssize_t pmbus_show_samples(struct device *dev, if (val < 0) return val; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t pmbus_set_samples(struct device *dev, @@ -2288,7 +2299,7 @@ const struct regulator_ops pmbus_regulator_ops = { .disable = pmbus_regulator_disable, .is_enabled = pmbus_regulator_is_enabled, }; -EXPORT_SYMBOL_GPL(pmbus_regulator_ops); +EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, PMBUS); static int pmbus_regulator_register(struct pmbus_data *data) { @@ -2557,6 +2568,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) struct pmbus_data *data; size_t groups_num = 0; int ret; + char *name; if (!info) return -ENODEV; @@ -2606,10 +2618,15 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) return -ENODEV; } + name = devm_kstrdup(dev, client->name, GFP_KERNEL); + if (!name) + return -ENOMEM; + strreplace(name, '-', '_'); + data->groups[0] = &data->group; memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, - client->name, data, data->groups); + name, data, data->groups); if (IS_ERR(data->hwmon_dev)) { dev_err(dev, "Failed to register hwmon device\n"); return PTR_ERR(data->hwmon_dev); @@ -2625,7 +2642,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) return 0; } -EXPORT_SYMBOL_GPL(pmbus_do_probe); +EXPORT_SYMBOL_NS_GPL(pmbus_do_probe, PMBUS); struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client) { @@ -2633,7 +2650,7 @@ struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client) return data->debugfs; } -EXPORT_SYMBOL_GPL(pmbus_get_debugfs_dir); +EXPORT_SYMBOL_NS_GPL(pmbus_get_debugfs_dir, PMBUS); static int __init pmbus_core_init(void) { diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index da27ce34ee3fd05153e44b0908a3a32ee2be9235..52bee5de2988359abdfb3fe15ddc0244eaa1ef6c 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -41,6 +41,15 @@ static int pxe1610_identify(struct i2c_client *client, info->vrm_version[i] = vr13; break; default: + /* + * If prior pages are available limit operation + * to them + */ + if (i != 0) { + info->pages = i; + return 0; + } + return -ENODEV; } } @@ -139,3 +148,4 @@ module_i2c_driver(pxe1610_driver); MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>"); MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c index aec512766c319b2f638ba267d15c2637b16318d0..b6e8b20466f15207bc4b7262b27da53a37753043 100644 --- a/drivers/hwmon/pmbus/q54sj108a2.c +++ b/drivers/hwmon/pmbus/q54sj108a2.c @@ -420,3 +420,4 @@ module_i2c_driver(q54sj108a2_driver); MODULE_AUTHOR("Xiao.Ma <xiao.mx.ma@deltaww.com>"); MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2 series modules"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/stpddc60.c b/drivers/hwmon/pmbus/stpddc60.c new file mode 100644 index 0000000000000000000000000000000000000000..357b9d9d896b53c46e450a3dcb2c129024b254be --- /dev/null +++ b/drivers/hwmon/pmbus/stpddc60.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for the STPDDC60 controller + * + * Copyright (c) 2021 Flextronics International Sweden AB. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/pmbus.h> +#include "pmbus.h" + +#define STPDDC60_MFR_READ_VOUT 0xd2 +#define STPDDC60_MFR_OV_LIMIT_OFFSET 0xe5 +#define STPDDC60_MFR_UV_LIMIT_OFFSET 0xe6 + +static const struct i2c_device_id stpddc60_id[] = { + {"stpddc60", 0}, + {"bmr481", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stpddc60_id); + +static struct pmbus_driver_info stpddc60_info = { + .pages = 1, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT, +}; + +/* + * Calculate the closest absolute offset between commanded vout value + * and limit value in steps of 50mv in the range 0 (50mv) to 7 (400mv). + * Return 0 if the upper limit is lower than vout or if the lower limit + * is higher than vout. + */ +static u8 stpddc60_get_offset(int vout, u16 limit, bool over) +{ + int offset; + long v, l; + + v = 250 + (vout - 1) * 5; /* Convert VID to mv */ + l = (limit * 1000L) >> 8; /* Convert LINEAR to mv */ + + if (over == (l < v)) + return 0; + + offset = DIV_ROUND_CLOSEST(abs(l - v), 50); + + if (offset > 0) + offset--; + + return clamp_val(offset, 0, 7); +} + +/* + * Adjust the linear format word to use the given fixed exponent. + */ +static u16 stpddc60_adjust_linear(u16 word, s16 fixed) +{ + s16 e, m, d; + + e = ((s16)word) >> 11; + m = ((s16)((word & 0x7ff) << 5)) >> 5; + d = e - fixed; + + if (d >= 0) + m <<= d; + else + m >>= -d; + + return clamp_val(m, 0, 0x3ff) | ((fixed << 11) & 0xf800); +} + +/* + * The VOUT_COMMAND register uses the VID format but the vout alarm limit + * registers use the LINEAR format so we override VOUT_MODE here to force + * LINEAR format for all registers. + */ +static int stpddc60_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + if (page > 0) + return -ENXIO; + + switch (reg) { + case PMBUS_VOUT_MODE: + ret = 0x18; + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +/* + * The vout related registers return values in LINEAR11 format when LINEAR16 + * is expected. Clear the top 5 bits to set the exponent part to zero to + * convert the value to LINEAR16 format. + */ +static int stpddc60_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + int ret; + + if (page > 0) + return -ENXIO; + + switch (reg) { + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, + STPDDC60_MFR_READ_VOUT); + if (ret < 0) + return ret; + ret &= 0x7ff; + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + ret &= 0x7ff; + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +/* + * The vout under- and over-voltage limits are set as an offset relative to + * the commanded vout voltage. The vin, iout, pout and temp limits must use + * the same fixed exponent the chip uses to encode the data when read. + */ +static int stpddc60_write_word_data(struct i2c_client *client, int page, + int reg, u16 word) +{ + int ret; + u8 offset; + + if (page > 0) + return -ENXIO; + + switch (reg) { + case PMBUS_VOUT_OV_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, 0xff, + PMBUS_VOUT_COMMAND); + if (ret < 0) + return ret; + offset = stpddc60_get_offset(ret, word, true); + ret = pmbus_write_byte_data(client, page, + STPDDC60_MFR_OV_LIMIT_OFFSET, + offset); + break; + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, 0xff, + PMBUS_VOUT_COMMAND); + if (ret < 0) + return ret; + offset = stpddc60_get_offset(ret, word, false); + ret = pmbus_write_byte_data(client, page, + STPDDC60_MFR_UV_LIMIT_OFFSET, + offset); + break; + case PMBUS_VIN_OV_FAULT_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_OT_WARN_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_POUT_OP_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, 0xff, reg); + if (ret < 0) + return ret; + word = stpddc60_adjust_linear(word, ret >> 11); + ret = pmbus_write_word_data(client, page, reg, word); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int stpddc60_probe(struct i2c_client *client) +{ + int status; + u8 device_id[I2C_SMBUS_BLOCK_MAX + 1]; + const struct i2c_device_id *mid; + struct pmbus_driver_info *info = &stpddc60_info; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_BLOCK_DATA)) + return -ENODEV; + + status = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, device_id); + if (status < 0) { + dev_err(&client->dev, "Failed to read Manufacturer Model\n"); + return status; + } + for (mid = stpddc60_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, device_id, strlen(mid->name))) + break; + } + if (!mid->name[0]) { + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + + info->read_byte_data = stpddc60_read_byte_data; + info->read_word_data = stpddc60_read_word_data; + info->write_word_data = stpddc60_write_word_data; + + status = pmbus_do_probe(client, info); + if (status < 0) + return status; + + pmbus_set_update(client, PMBUS_VOUT_OV_FAULT_LIMIT, true); + pmbus_set_update(client, PMBUS_VOUT_UV_FAULT_LIMIT, true); + + return 0; +} + +static struct i2c_driver stpddc60_driver = { + .driver = { + .name = "stpddc60", + }, + .probe_new = stpddc60_probe, + .id_table = stpddc60_id, +}; + +module_i2c_driver(stpddc60_driver); + +MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>"); +MODULE_DESCRIPTION("PMBus driver for ST STPDDC60"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index f7f00ab6f46c687e790b3457b6754f9e884fb2ef..31bb83c0ef3e407f0a2546f716aa5268e18223b8 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -51,3 +51,4 @@ module_i2c_driver(tps40422_driver); MODULE_AUTHOR("Zhu Laiwen <richard.zhu@nsn.com>"); MODULE_DESCRIPTION("PMBus driver for TI TPS40422"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index ba838fa311c3aad94089d98d6cf5222b450ecf02..81b9d813655ad2d02206cdbdfdc1cc29ad382ed8 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -16,11 +16,14 @@ #include "pmbus.h" enum chips { - tps53647, tps53667, tps53679, tps53681, tps53688 + tps53647, tps53667, tps53676, tps53679, tps53681, tps53688 }; #define TPS53647_PAGE_NUM 1 +#define TPS53676_USER_DATA_03 0xb3 +#define TPS53676_MAX_PHASES 7 + #define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ #define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ #define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ @@ -143,6 +146,45 @@ static int tps53681_identify(struct i2c_client *client, TPS53681_DEVICE_ID); } +static int tps53676_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int phases_a = 0, phases_b = 0; + int i, ret; + + ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); + if (ret < 0) + return ret; + if (strncmp("TI\x53\x67\x60", buf, 5)) { + dev_err(&client->dev, "Unexpected device ID: %s\n", buf); + return -ENODEV; + } + + ret = i2c_smbus_read_block_data(client, TPS53676_USER_DATA_03, buf); + if (ret < 0) + return ret; + if (ret != 24) + return -EIO; + for (i = 0; i < 2 * TPS53676_MAX_PHASES; i += 2) { + if (buf[i + 1] & 0x80) { + if (buf[i] & 0x08) + phases_b++; + else + phases_a++; + } + } + + info->format[PSC_VOLTAGE_OUT] = linear; + info->pages = 1; + info->phases[0] = phases_a; + if (phases_b > 0) { + info->pages = 2; + info->phases[1] = phases_b; + } + return 0; +} + static int tps53681_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -183,6 +225,7 @@ static struct pmbus_driver_info tps53679_info = { .pfunc[3] = PMBUS_HAVE_IOUT, .pfunc[4] = PMBUS_HAVE_IOUT, .pfunc[5] = PMBUS_HAVE_IOUT, + .pfunc[6] = PMBUS_HAVE_IOUT, }; static int tps53679_probe(struct i2c_client *client) @@ -206,6 +249,9 @@ static int tps53679_probe(struct i2c_client *client) info->pages = TPS53647_PAGE_NUM; info->identify = tps53679_identify; break; + case tps53676: + info->identify = tps53676_identify; + break; case tps53679: case tps53688: info->pages = TPS53679_PAGE_NUM; @@ -225,8 +271,10 @@ static int tps53679_probe(struct i2c_client *client) } static const struct i2c_device_id tps53679_id[] = { + {"bmr474", tps53676}, {"tps53647", tps53647}, {"tps53667", tps53667}, + {"tps53676", tps53676}, {"tps53679", tps53679}, {"tps53681", tps53681}, {"tps53688", tps53688}, @@ -238,6 +286,7 @@ MODULE_DEVICE_TABLE(i2c, tps53679_id); static const struct of_device_id __maybe_unused tps53679_of_match[] = { {.compatible = "ti,tps53647", .data = (void *)tps53647}, {.compatible = "ti,tps53667", .data = (void *)tps53667}, + {.compatible = "ti,tps53676", .data = (void *)tps53676}, {.compatible = "ti,tps53679", .data = (void *)tps53679}, {.compatible = "ti,tps53681", .data = (void *)tps53681}, {.compatible = "ti,tps53688", .data = (void *)tps53688}, @@ -259,3 +308,4 @@ module_i2c_driver(tps53679_driver); MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index a15e6fe3e425a3cab4cfbb3cb9011bdb4fcca517..75fc770c9e4035b2b982b34b543b5e51f6dd3378 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -629,3 +629,4 @@ module_i2c_driver(ucd9000_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 47cc7ca9d32998aca8e40df220ce326236864e0b..6bc3273e31e72a88b63a1bd4715075e422830575 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -209,3 +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); diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index f8bc0f41cd5fae1807bc94c7698d6ec2a340976c..b07da06a40c9d749c9e834d503e48f47bbf7d8b1 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -168,3 +168,4 @@ module_i2c_driver(xdpe122_driver); MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 69120ca7aaa861fd92c769e912765a382afa820f..b7d4eacdc3ef7ac55c8f637c35705f0bde1260d9 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -404,3 +404,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); diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c index d3a64a35f7a9af2d11fe31de0d37b5abb7c2301a..805d396aa81b0feba50850521b1288d757545a03 100644 --- a/drivers/hwmon/raspberrypi-hwmon.c +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -7,6 +7,7 @@ * Copyright (C) 2018 Stefan Wahren <stefan.wahren@i2se.com> */ #include <linux/device.h> +#include <linux/devm-helpers.h> #include <linux/err.h> #include <linux/hwmon.h> #include <linux/module.h> @@ -106,6 +107,7 @@ static int rpi_hwmon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpi_hwmon_data *data; + int ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -119,7 +121,10 @@ static int rpi_hwmon_probe(struct platform_device *pdev) &rpi_chip_info, NULL); - INIT_DELAYED_WORK(&data->get_values_poll_work, get_values_poll); + ret = devm_delayed_work_autocancel(dev, &data->get_values_poll_work, + get_values_poll); + if (ret) + return ret; platform_set_drvdata(pdev, data); if (!PTR_ERR_OR_ZERO(data->hwmon_dev)) @@ -128,18 +133,8 @@ static int rpi_hwmon_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(data->hwmon_dev); } -static int rpi_hwmon_remove(struct platform_device *pdev) -{ - struct rpi_hwmon_data *data = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&data->get_values_poll_work); - - return 0; -} - static struct platform_driver rpi_hwmon_driver = { .probe = rpi_hwmon_probe, - .remove = rpi_hwmon_remove, .driver = { .name = "raspberrypi-hwmon", }, diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index f2703c5460d059f93b7284b3cc5568959cfe0cae..70ae665db477ddb9b6299a16a219967276d376ea 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -166,7 +166,7 @@ static ssize_t s3c_hwmon_ch_show(struct device *dev, ret *= cfg->mult; ret = DIV_ROUND_CLOSEST(ret, cfg->div); - return snprintf(buf, PAGE_SIZE, "%d\n", ret); + return sysfs_emit(buf, "%d\n", ret); } /** @@ -187,7 +187,7 @@ static ssize_t s3c_hwmon_label_show(struct device *dev, cfg = pdata->in[sen_attr->index]; - return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name); + return sysfs_emit(buf, "%s\n", cfg->name); } /** diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 039644263101baffa0dbc615b6f0b91a02f213ed..4324a5dbc96846c27bc80aaa6fc4b6a6e4045c69 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -12,7 +12,6 @@ #include <linux/jiffies.h> #include <linux/platform_device.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> #include "sch56xx-common.h" @@ -65,7 +64,6 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = { struct sch5627_data { unsigned short addr; - struct device *hwmon_dev; struct sch56xx_watchdog_data *watchdog; u8 control; u8 temp_max[SCH5627_NO_TEMPS]; @@ -74,66 +72,96 @@ struct sch5627_data { struct mutex update_lock; unsigned long last_battery; /* In jiffies */ - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ + char temp_valid; /* !=0 if following fields are valid */ + char fan_valid; + char in_valid; + unsigned long temp_last_updated; /* In jiffies */ + unsigned long fan_last_updated; + unsigned long in_last_updated; u16 temp[SCH5627_NO_TEMPS]; u16 fan[SCH5627_NO_FANS]; u16 in[SCH5627_NO_IN]; }; -static struct sch5627_data *sch5627_update_device(struct device *dev) +static int sch5627_update_temp(struct sch5627_data *data) { - struct sch5627_data *data = dev_get_drvdata(dev); - struct sch5627_data *ret = data; + int ret = 0; int i, val; mutex_lock(&data->update_lock); - /* Trigger a Vbat voltage measurement every 5 minutes */ - if (time_after(jiffies, data->last_battery + 300 * HZ)) { - sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, - data->control | 0x10); - data->last_battery = jiffies; - } - /* Cache the values for 1 second */ - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + if (time_after(jiffies, data->temp_last_updated + HZ) || !data->temp_valid) { for (i = 0; i < SCH5627_NO_TEMPS; i++) { - val = sch56xx_read_virtual_reg12(data->addr, - SCH5627_REG_TEMP_MSB[i], - SCH5627_REG_TEMP_LSN[i], - SCH5627_REG_TEMP_HIGH_NIBBLE[i]); + val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_TEMP_MSB[i], + SCH5627_REG_TEMP_LSN[i], + SCH5627_REG_TEMP_HIGH_NIBBLE[i]); if (unlikely(val < 0)) { - ret = ERR_PTR(val); + ret = val; goto abort; } data->temp[i] = val; } + data->temp_last_updated = jiffies; + data->temp_valid = 1; + } +abort: + mutex_unlock(&data->update_lock); + return ret; +} +static int sch5627_update_fan(struct sch5627_data *data) +{ + int ret = 0; + int i, val; + + mutex_lock(&data->update_lock); + + /* Cache the values for 1 second */ + if (time_after(jiffies, data->fan_last_updated + HZ) || !data->fan_valid) { for (i = 0; i < SCH5627_NO_FANS; i++) { - val = sch56xx_read_virtual_reg16(data->addr, - SCH5627_REG_FAN[i]); + val = sch56xx_read_virtual_reg16(data->addr, SCH5627_REG_FAN[i]); if (unlikely(val < 0)) { - ret = ERR_PTR(val); + ret = val; goto abort; } data->fan[i] = val; } + data->fan_last_updated = jiffies; + data->fan_valid = 1; + } +abort: + mutex_unlock(&data->update_lock); + return ret; +} + +static int sch5627_update_in(struct sch5627_data *data) +{ + int ret = 0; + int i, val; + + mutex_lock(&data->update_lock); + /* Trigger a Vbat voltage measurement every 5 minutes */ + if (time_after(jiffies, data->last_battery + 300 * HZ)) { + sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | 0x10); + data->last_battery = jiffies; + } + + /* Cache the values for 1 second */ + if (time_after(jiffies, data->in_last_updated + HZ) || !data->in_valid) { for (i = 0; i < SCH5627_NO_IN; i++) { - val = sch56xx_read_virtual_reg12(data->addr, - SCH5627_REG_IN_MSB[i], - SCH5627_REG_IN_LSN[i], - SCH5627_REG_IN_HIGH_NIBBLE[i]); + val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_IN_MSB[i], + SCH5627_REG_IN_LSN[i], + SCH5627_REG_IN_HIGH_NIBBLE[i]); if (unlikely(val < 0)) { - ret = ERR_PTR(val); + ret = val; goto abort; } data->in[i] = val; } - - data->last_updated = jiffies; - data->valid = 1; + data->in_last_updated = jiffies; + data->in_valid = 1; } abort: mutex_unlock(&data->update_lock); @@ -192,249 +220,141 @@ static int reg_to_rpm(u16 reg) return 5400540 / reg; } -static ssize_t name_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME); -} - -static ssize_t temp_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = sch5627_update_device(dev); - int val; - - if (IS_ERR(data)) - return PTR_ERR(data); - - val = reg_to_temp(data->temp[attr->index]); - return snprintf(buf, PAGE_SIZE, "%d\n", val); -} - -static ssize_t temp_fault_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = sch5627_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0); -} - -static ssize_t temp_max_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = dev_get_drvdata(dev); - int val; - - val = reg_to_temp_limit(data->temp_max[attr->index]); - return snprintf(buf, PAGE_SIZE, "%d\n", val); -} - -static ssize_t temp_crit_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = dev_get_drvdata(dev); - int val; - - val = reg_to_temp_limit(data->temp_crit[attr->index]); - return snprintf(buf, PAGE_SIZE, "%d\n", val); -} - -static ssize_t fan_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = sch5627_update_device(dev); - int val; - - if (IS_ERR(data)) - return PTR_ERR(data); - - val = reg_to_rpm(data->fan[attr->index]); - if (val < 0) - return val; - - return snprintf(buf, PAGE_SIZE, "%d\n", val); -} - -static ssize_t fan_fault_show(struct device *dev, - struct device_attribute *devattr, char *buf) +static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, + int channel) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = sch5627_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); - - return snprintf(buf, PAGE_SIZE, "%d\n", - data->fan[attr->index] == 0xffff); + return 0444; } -static ssize_t fan_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) +static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long *val) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct sch5627_data *data = dev_get_drvdata(dev); - int val = reg_to_rpm(data->fan_min[attr->index]); - if (val < 0) - return val; - - return snprintf(buf, PAGE_SIZE, "%d\n", val); -} - -static ssize_t in_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct sch5627_data *data = sch5627_update_device(dev); - int val; - - if (IS_ERR(data)) - return PTR_ERR(data); + int ret; + + switch (type) { + case hwmon_temp: + ret = sch5627_update_temp(data); + if (ret < 0) + return ret; + switch (attr) { + case hwmon_temp_input: + *val = reg_to_temp(data->temp[channel]); + return 0; + case hwmon_temp_max: + *val = reg_to_temp_limit(data->temp_max[channel]); + return 0; + case hwmon_temp_crit: + *val = reg_to_temp_limit(data->temp_crit[channel]); + return 0; + case hwmon_temp_fault: + *val = (data->temp[channel] == 0); + return 0; + default: + break; + } + break; + case hwmon_fan: + ret = sch5627_update_fan(data); + if (ret < 0) + return ret; + switch (attr) { + case hwmon_fan_input: + ret = reg_to_rpm(data->fan[channel]); + if (ret < 0) + return ret; + *val = ret; + return 0; + case hwmon_fan_min: + ret = reg_to_rpm(data->fan_min[channel]); + if (ret < 0) + return ret; + *val = ret; + return 0; + case hwmon_fan_fault: + *val = (data->fan[channel] == 0xffff); + return 0; + default: + break; + } + break; + case hwmon_in: + ret = sch5627_update_in(data); + if (ret < 0) + return ret; + switch (attr) { + case hwmon_in_input: + *val = DIV_ROUND_CLOSEST(data->in[channel] * SCH5627_REG_IN_FACTOR[channel], + 10000); + return 0; + default: + break; + } + break; + default: + break; + } - val = DIV_ROUND_CLOSEST( - data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index], - 10000); - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return -EOPNOTSUPP; } -static ssize_t in_label_show(struct device *dev, - struct device_attribute *devattr, char *buf) +static int sch5627_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, const char **str) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_label: + *str = SCH5627_IN_LABELS[channel]; + return 0; + default: + break; + } + break; + default: + break; + } - return snprintf(buf, PAGE_SIZE, "%s\n", - SCH5627_IN_LABELS[attr->index]); + return -EOPNOTSUPP; } -static DEVICE_ATTR_RO(name); -static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); -static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3); -static SENSOR_DEVICE_ATTR_RO(temp5_input, temp, 4); -static SENSOR_DEVICE_ATTR_RO(temp6_input, temp, 5); -static SENSOR_DEVICE_ATTR_RO(temp7_input, temp, 6); -static SENSOR_DEVICE_ATTR_RO(temp8_input, temp, 7); -static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2); -static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3); -static SENSOR_DEVICE_ATTR_RO(temp5_fault, temp_fault, 4); -static SENSOR_DEVICE_ATTR_RO(temp6_fault, temp_fault, 5); -static SENSOR_DEVICE_ATTR_RO(temp7_fault, temp_fault, 6); -static SENSOR_DEVICE_ATTR_RO(temp8_fault, temp_fault, 7); -static SENSOR_DEVICE_ATTR_RO(temp1_max, temp_max, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_max, temp_max, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_max, temp_max, 2); -static SENSOR_DEVICE_ATTR_RO(temp4_max, temp_max, 3); -static SENSOR_DEVICE_ATTR_RO(temp5_max, temp_max, 4); -static SENSOR_DEVICE_ATTR_RO(temp6_max, temp_max, 5); -static SENSOR_DEVICE_ATTR_RO(temp7_max, temp_max, 6); -static SENSOR_DEVICE_ATTR_RO(temp8_max, temp_max, 7); -static SENSOR_DEVICE_ATTR_RO(temp1_crit, temp_crit, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_crit, temp_crit, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_crit, temp_crit, 2); -static SENSOR_DEVICE_ATTR_RO(temp4_crit, temp_crit, 3); -static SENSOR_DEVICE_ATTR_RO(temp5_crit, temp_crit, 4); -static SENSOR_DEVICE_ATTR_RO(temp6_crit, temp_crit, 5); -static SENSOR_DEVICE_ATTR_RO(temp7_crit, temp_crit, 6); -static SENSOR_DEVICE_ATTR_RO(temp8_crit, temp_crit, 7); - -static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); -static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2); -static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3); -static SENSOR_DEVICE_ATTR_RO(fan1_fault, fan_fault, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_fault, fan_fault, 1); -static SENSOR_DEVICE_ATTR_RO(fan3_fault, fan_fault, 2); -static SENSOR_DEVICE_ATTR_RO(fan4_fault, fan_fault, 3); -static SENSOR_DEVICE_ATTR_RO(fan1_min, fan_min, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_min, fan_min, 1); -static SENSOR_DEVICE_ATTR_RO(fan3_min, fan_min, 2); -static SENSOR_DEVICE_ATTR_RO(fan4_min, fan_min, 3); - -static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0); -static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1); -static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2); -static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3); -static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4); -static SENSOR_DEVICE_ATTR_RO(in0_label, in_label, 0); -static SENSOR_DEVICE_ATTR_RO(in1_label, in_label, 1); -static SENSOR_DEVICE_ATTR_RO(in2_label, in_label, 2); -static SENSOR_DEVICE_ATTR_RO(in3_label, in_label, 3); - -static struct attribute *sch5627_attributes[] = { - &dev_attr_name.attr, - - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, - &sensor_dev_attr_temp5_input.dev_attr.attr, - &sensor_dev_attr_temp6_input.dev_attr.attr, - &sensor_dev_attr_temp7_input.dev_attr.attr, - &sensor_dev_attr_temp8_input.dev_attr.attr, - &sensor_dev_attr_temp1_fault.dev_attr.attr, - &sensor_dev_attr_temp2_fault.dev_attr.attr, - &sensor_dev_attr_temp3_fault.dev_attr.attr, - &sensor_dev_attr_temp4_fault.dev_attr.attr, - &sensor_dev_attr_temp5_fault.dev_attr.attr, - &sensor_dev_attr_temp6_fault.dev_attr.attr, - &sensor_dev_attr_temp7_fault.dev_attr.attr, - &sensor_dev_attr_temp8_fault.dev_attr.attr, - &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp2_max.dev_attr.attr, - &sensor_dev_attr_temp3_max.dev_attr.attr, - &sensor_dev_attr_temp4_max.dev_attr.attr, - &sensor_dev_attr_temp5_max.dev_attr.attr, - &sensor_dev_attr_temp6_max.dev_attr.attr, - &sensor_dev_attr_temp7_max.dev_attr.attr, - &sensor_dev_attr_temp8_max.dev_attr.attr, - &sensor_dev_attr_temp1_crit.dev_attr.attr, - &sensor_dev_attr_temp2_crit.dev_attr.attr, - &sensor_dev_attr_temp3_crit.dev_attr.attr, - &sensor_dev_attr_temp4_crit.dev_attr.attr, - &sensor_dev_attr_temp5_crit.dev_attr.attr, - &sensor_dev_attr_temp6_crit.dev_attr.attr, - &sensor_dev_attr_temp7_crit.dev_attr.attr, - &sensor_dev_attr_temp8_crit.dev_attr.attr, - - &sensor_dev_attr_fan1_input.dev_attr.attr, - &sensor_dev_attr_fan2_input.dev_attr.attr, - &sensor_dev_attr_fan3_input.dev_attr.attr, - &sensor_dev_attr_fan4_input.dev_attr.attr, - &sensor_dev_attr_fan1_fault.dev_attr.attr, - &sensor_dev_attr_fan2_fault.dev_attr.attr, - &sensor_dev_attr_fan3_fault.dev_attr.attr, - &sensor_dev_attr_fan4_fault.dev_attr.attr, - &sensor_dev_attr_fan1_min.dev_attr.attr, - &sensor_dev_attr_fan2_min.dev_attr.attr, - &sensor_dev_attr_fan3_min.dev_attr.attr, - &sensor_dev_attr_fan4_min.dev_attr.attr, - - &sensor_dev_attr_in0_input.dev_attr.attr, - &sensor_dev_attr_in1_input.dev_attr.attr, - &sensor_dev_attr_in2_input.dev_attr.attr, - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_in4_input.dev_attr.attr, - &sensor_dev_attr_in0_label.dev_attr.attr, - &sensor_dev_attr_in1_label.dev_attr.attr, - &sensor_dev_attr_in2_label.dev_attr.attr, - &sensor_dev_attr_in3_label.dev_attr.attr, - /* No in4_label as in4 is a generic input pin */ +static const struct hwmon_ops sch5627_ops = { + .is_visible = sch5627_is_visible, + .read = sch5627_read, + .read_string = sch5627_read_string, +}; +static const struct hwmon_channel_info *sch5627_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT + ), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT + ), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT + ), NULL }; -static const struct attribute_group sch5627_group = { - .attrs = sch5627_attributes, +static const struct hwmon_chip_info sch5627_chip_info = { + .ops = &sch5627_ops, + .info = sch5627_info, }; static int sch5627_remove(struct platform_device *pdev) @@ -444,17 +364,13 @@ static int sch5627_remove(struct platform_device *pdev) if (data->watchdog) sch56xx_watchdog_unregister(data->watchdog); - if (data->hwmon_dev) - hwmon_device_unregister(data->hwmon_dev); - - sysfs_remove_group(&pdev->dev.kobj, &sch5627_group); - return 0; } static int sch5627_probe(struct platform_device *pdev) { struct sch5627_data *data; + struct device *hwmon_dev; int err, build_code, build_id, hwmon_rev, val; data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data), @@ -467,72 +383,58 @@ static int sch5627_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID); - if (val < 0) { - err = val; - goto error; - } + if (val < 0) + return val; + if (val != SCH5627_HWMON_ID) { pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon", val, SCH5627_HWMON_ID); - err = -ENODEV; - goto error; + return -ENODEV; } val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID); - if (val < 0) { - err = val; - goto error; - } + if (val < 0) + return val; + if (val != SCH5627_COMPANY_ID) { pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company", val, SCH5627_COMPANY_ID); - err = -ENODEV; - goto error; + return -ENODEV; } val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID); - if (val < 0) { - err = val; - goto error; - } + if (val < 0) + return val; + if (val != SCH5627_PRIMARY_ID) { pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary", val, SCH5627_PRIMARY_ID); - err = -ENODEV; - goto error; + return -ENODEV; } build_code = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_BUILD_CODE); - if (build_code < 0) { - err = build_code; - goto error; - } + if (build_code < 0) + return build_code; build_id = sch56xx_read_virtual_reg16(data->addr, SCH5627_REG_BUILD_ID); - if (build_id < 0) { - err = build_id; - goto error; - } + if (build_id < 0) + return build_id; hwmon_rev = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_REV); - if (hwmon_rev < 0) { - err = hwmon_rev; - goto error; - } + if (hwmon_rev < 0) + return hwmon_rev; val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL); - if (val < 0) { - err = val; - goto error; - } + if (val < 0) + return val; + data->control = val; if (!(data->control & 0x01)) { pr_err("hardware monitoring not enabled\n"); - err = -ENODEV; - goto error; + return -ENODEV; } /* Trigger a Vbat voltage measurement, so that we get a valid reading the first time we read Vbat */ @@ -546,23 +448,16 @@ static int sch5627_probe(struct platform_device *pdev) */ err = sch5627_read_limits(data); if (err) - goto error; + return err; pr_info("found %s chip at %#hx\n", DEVNAME, data->addr); pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n", build_code, build_id, hwmon_rev); - /* Register sysfs interface files */ - err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group); - if (err) - goto error; - - data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - data->hwmon_dev = NULL; - goto error; - } + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, DEVNAME, data, + &sch5627_chip_info, NULL); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); /* Note failing to register the watchdog is not a fatal error */ data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr, @@ -570,10 +465,6 @@ static int sch5627_probe(struct platform_device *pdev) &data->update_lock, 1); return 0; - -error: - sch5627_remove(pdev); - return err; } static struct platform_driver sch5627_driver = { diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 200bb2bfc9861e93088b10df5d6b5d4e81d30b6b..5683a38740f63dfa0730d8fcc0ce0d9b694aa2c9 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -160,7 +160,7 @@ static int reg_to_rpm(u16 reg) static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME); + return sysfs_emit(buf, "%s\n", DEVNAME); } static ssize_t in_value_show(struct device *dev, @@ -176,7 +176,7 @@ static ssize_t in_value_show(struct device *dev, val = DIV_ROUND_CLOSEST( data->in[attr->index] * SCH5636_REG_IN_FACTORS[attr->index], 255); - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t in_label_show(struct device *dev, @@ -184,8 +184,8 @@ static ssize_t in_label_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - return snprintf(buf, PAGE_SIZE, "%s\n", - SCH5636_IN_LABELS[attr->index]); + return sysfs_emit(buf, "%s\n", + SCH5636_IN_LABELS[attr->index]); } static ssize_t temp_value_show(struct device *dev, @@ -199,7 +199,7 @@ static ssize_t temp_value_show(struct device *dev, return PTR_ERR(data); val = (data->temp_val[attr->index] - 64) * 1000; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t temp_fault_show(struct device *dev, @@ -213,7 +213,7 @@ static ssize_t temp_fault_show(struct device *dev, return PTR_ERR(data); val = (data->temp_ctrl[attr->index] & SCH5636_TEMP_WORKING) ? 0 : 1; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t temp_alarm_show(struct device *dev, @@ -227,7 +227,7 @@ static ssize_t temp_alarm_show(struct device *dev, return PTR_ERR(data); val = (data->temp_ctrl[attr->index] & SCH5636_TEMP_ALARM) ? 1 : 0; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t fan_value_show(struct device *dev, @@ -244,7 +244,7 @@ static ssize_t fan_value_show(struct device *dev, if (val < 0) return val; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t fan_fault_show(struct device *dev, @@ -258,7 +258,7 @@ static ssize_t fan_fault_show(struct device *dev, return PTR_ERR(data); val = (data->fan_ctrl[attr->index] & SCH5636_FAN_NOT_PRESENT) ? 1 : 0; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t fan_alarm_show(struct device *dev, @@ -272,7 +272,7 @@ static ssize_t fan_alarm_show(struct device *dev, return PTR_ERR(data); val = (data->fan_ctrl[attr->index] & SCH5636_FAN_ALARM) ? 1 : 0; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static struct sensor_device_attribute sch5636_attr[] = { diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index 17d064e58938bce5464fcc28aaaf603dd8c40356..b1329a58ce403d5fdb185609a6345833bcf1d056 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -2,7 +2,7 @@ /* * System Control and Management Interface(SCMI) based hwmon sensor driver * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. * Sudeep Holla <sudeep.holla@arm.com> */ @@ -13,8 +13,10 @@ #include <linux/sysfs.h> #include <linux/thermal.h> +static const struct scmi_sensor_proto_ops *sensor_ops; + struct scmi_sensors { - const struct scmi_handle *handle; + const struct scmi_protocol_handle *ph; const struct scmi_sensor_info **info[hwmon_max]; }; @@ -69,10 +71,9 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u64 value; const struct scmi_sensor_info *sensor; struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); - const struct scmi_handle *h = scmi_sensors->handle; sensor = *(scmi_sensors->info[type] + channel); - ret = h->sensor_ops->reading_get(h, sensor->id, &value); + ret = sensor_ops->reading_get(scmi_sensors->ph, sensor->id, &value); if (ret) return ret; @@ -169,11 +170,16 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) struct hwmon_channel_info *scmi_hwmon_chan; const struct hwmon_channel_info **ptr_scmi_ci; const struct scmi_handle *handle = sdev->handle; + struct scmi_protocol_handle *ph; - if (!handle || !handle->sensor_ops) + if (!handle) return -ENODEV; - nr_sensors = handle->sensor_ops->count_get(handle); + sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph); + if (IS_ERR(sensor_ops)) + return PTR_ERR(sensor_ops); + + nr_sensors = sensor_ops->count_get(ph); if (!nr_sensors) return -EIO; @@ -181,10 +187,10 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) if (!scmi_sensors) return -ENOMEM; - scmi_sensors->handle = handle; + scmi_sensors->ph = ph; for (i = 0; i < nr_sensors; i++) { - sensor = handle->sensor_ops->info_get(handle, i); + sensor = sensor_ops->info_get(ph, i); if (!sensor) return -EINVAL; @@ -236,7 +242,7 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) } for (i = nr_sensors - 1; i >= 0 ; i--) { - sensor = handle->sensor_ops->info_get(handle, i); + sensor = sensor_ops->info_get(ph, i); if (!sensor) continue; diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index b6cbe9810a1bc955f4869efce9614e132a8ffad6..62906d9c4b86c560639d56e72c0bc6cb1d292fb5 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -351,7 +351,7 @@ static ssize_t smm665_show_crit_alarm(struct device *dev, if (data->faults & (1 << attr->index)) val = 1; - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t smm665_show_input(struct device *dev, @@ -366,7 +366,7 @@ static ssize_t smm665_show_input(struct device *dev, return PTR_ERR(data); val = smm665_convert(data->adc[adc], adc); - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } #define SMM665_SHOW(what) \ diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c index 6928be6dbe4e2b3f962dc4c88c83824b9dbb675e..0ed28408aa077c3ed20133d2087e31fd5f28fba8 100644 --- a/drivers/hwmon/stts751.c +++ b/drivers/hwmon/stts751.c @@ -387,7 +387,7 @@ static ssize_t max_alarm_show(struct device *dev, if (ret < 0) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", priv->max_alert); + return sysfs_emit(buf, "%d\n", priv->max_alert); } static ssize_t min_alarm_show(struct device *dev, @@ -404,7 +404,7 @@ static ssize_t min_alarm_show(struct device *dev, if (ret < 0) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", priv->min_alert); + return sysfs_emit(buf, "%d\n", priv->min_alert); } static ssize_t input_show(struct device *dev, struct device_attribute *attr, @@ -419,7 +419,7 @@ static ssize_t input_show(struct device *dev, struct device_attribute *attr, if (ret < 0) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", priv->temp); + return sysfs_emit(buf, "%d\n", priv->temp); } static ssize_t therm_show(struct device *dev, struct device_attribute *attr, @@ -427,7 +427,7 @@ static ssize_t therm_show(struct device *dev, struct device_attribute *attr, { struct stts751_priv *priv = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm); + return sysfs_emit(buf, "%d\n", priv->therm); } static ssize_t therm_store(struct device *dev, struct device_attribute *attr, @@ -469,7 +469,7 @@ static ssize_t hyst_show(struct device *dev, struct device_attribute *attr, { struct stts751_priv *priv = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", priv->hyst); + return sysfs_emit(buf, "%d\n", priv->hyst); } static ssize_t hyst_store(struct device *dev, struct device_attribute *attr, @@ -509,7 +509,7 @@ static ssize_t therm_trip_show(struct device *dev, if (ret < 0) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm_trip); + return sysfs_emit(buf, "%d\n", priv->therm_trip); } static ssize_t max_show(struct device *dev, struct device_attribute *attr, @@ -517,7 +517,7 @@ static ssize_t max_show(struct device *dev, struct device_attribute *attr, { struct stts751_priv *priv = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_max); + return sysfs_emit(buf, "%d\n", priv->event_max); } static ssize_t max_store(struct device *dev, struct device_attribute *attr, @@ -551,7 +551,7 @@ static ssize_t min_show(struct device *dev, struct device_attribute *attr, { struct stts751_priv *priv = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_min); + return sysfs_emit(buf, "%d\n", priv->event_min); } static ssize_t min_store(struct device *dev, struct device_attribute *attr, @@ -585,8 +585,8 @@ static ssize_t interval_show(struct device *dev, { struct stts751_priv *priv = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", - stts751_intervals[priv->interval]); + return sysfs_emit(buf, "%d\n", + stts751_intervals[priv->interval]); } static ssize_t interval_store(struct device *dev, diff --git a/drivers/hwmon/vexpress-hwmon.c b/drivers/hwmon/vexpress-hwmon.c index e7109657129a0e25f8e741320285c3f9dcee4ee4..44d798be3d599e4c8e9c5ed90ac781f04eebf65d 100644 --- a/drivers/hwmon/vexpress-hwmon.c +++ b/drivers/hwmon/vexpress-hwmon.c @@ -27,7 +27,7 @@ static ssize_t vexpress_hwmon_label_show(struct device *dev, { const char *label = of_get_property(dev->of_node, "label", NULL); - return snprintf(buffer, PAGE_SIZE, "%s\n", label); + return sysfs_emit(buffer, "%s\n", label); } static ssize_t vexpress_hwmon_u32_show(struct device *dev, @@ -41,8 +41,8 @@ static ssize_t vexpress_hwmon_u32_show(struct device *dev, if (err) return err; - return snprintf(buffer, PAGE_SIZE, "%u\n", value / - to_sensor_dev_attr(dev_attr)->index); + return sysfs_emit(buffer, "%u\n", value / + to_sensor_dev_attr(dev_attr)->index); } static ssize_t vexpress_hwmon_u64_show(struct device *dev, @@ -60,9 +60,9 @@ static ssize_t vexpress_hwmon_u64_show(struct device *dev, if (err) return err; - return snprintf(buffer, PAGE_SIZE, "%llu\n", - div_u64(((u64)value_hi << 32) | value_lo, - to_sensor_dev_attr(dev_attr)->index)); + return sysfs_emit(buffer, "%llu\n", + div_u64(((u64)value_hi << 32) | value_lo, + to_sensor_dev_attr(dev_attr)->index)); } static umode_t vexpress_hwmon_attr_is_visible(struct kobject *kobj, diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c index 1489e83cb0c4401162abbfadda802561a1a9c041..382ef0395d8ee3db60b9f8b54b0b7a7d11463d37 100644 --- a/drivers/hwmon/xgene-hwmon.c +++ b/drivers/hwmon/xgene-hwmon.c @@ -329,14 +329,14 @@ static ssize_t temp1_input_show(struct device *dev, temp = sign_extend32(val, TEMP_NEGATIVE_BIT); - return snprintf(buf, PAGE_SIZE, "%d\n", CELSIUS_TO_mCELSIUS(temp)); + return sysfs_emit(buf, "%d\n", CELSIUS_TO_mCELSIUS(temp)); } static ssize_t temp1_label_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "SoC Temperature\n"); + return sysfs_emit(buf, "SoC Temperature\n"); } static ssize_t temp1_critical_alarm_show(struct device *dev, @@ -345,21 +345,21 @@ static ssize_t temp1_critical_alarm_show(struct device *dev, { struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ctx->temp_critical_alarm); + return sysfs_emit(buf, "%d\n", ctx->temp_critical_alarm); } static ssize_t power1_label_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "CPU power\n"); + return sysfs_emit(buf, "CPU power\n"); } static ssize_t power2_label_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "IO power\n"); + return sysfs_emit(buf, "IO power\n"); } static ssize_t power1_input_show(struct device *dev, @@ -374,7 +374,7 @@ static ssize_t power1_input_show(struct device *dev, if (rc < 0) return rc; - return snprintf(buf, PAGE_SIZE, "%u\n", mWATT_TO_uWATT(val)); + return sysfs_emit(buf, "%u\n", mWATT_TO_uWATT(val)); } static ssize_t power2_input_show(struct device *dev, @@ -389,7 +389,7 @@ static ssize_t power2_input_show(struct device *dev, if (rc < 0) return rc; - return snprintf(buf, PAGE_SIZE, "%u\n", mWATT_TO_uWATT(val)); + return sysfs_emit(buf, "%u\n", mWATT_TO_uWATT(val)); } static DEVICE_ATTR_RO(temp1_label); diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 0062c893565300ac7524c0319ba4829159087e32..b57bea16710274d4a7801f05a9821e0e18109bf6 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -86,7 +86,7 @@ static int coresight_id_match(struct device *dev, void *data) i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE) return 0; - /* Get the source ID for both compoment */ + /* Get the source ID for both components */ trace_id = source_ops(csdev)->trace_id(csdev); i_trace_id = source_ops(i_csdev)->trace_id(i_csdev); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 0f603b4094f2214960d0b823052f1e73629b855c..c1bec2ad391191e6545902b8ab04bebbda9cde25 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -52,13 +52,13 @@ static ssize_t format_attr_contextid_show(struct device *dev, { int pid_fmt = ETM_OPT_CTXTID; -#if defined(CONFIG_CORESIGHT_SOURCE_ETM4X) +#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) pid_fmt = is_kernel_in_hyp_mode() ? ETM_OPT_CTXTID2 : ETM_OPT_CTXTID; #endif return sprintf(page, "config:%d\n", pid_fmt); } -struct device_attribute format_attr_contextid = +static struct device_attribute format_attr_contextid = __ATTR(contextid, 0444, format_attr_contextid_show, NULL); static struct attribute *etm_config_formats_attr[] = { diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 15016f757828e6326f6d6d0163264aaa11f01ff8..a5b13a7779c39edfa6ffa52c6798020c1d8ca590 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1951,6 +1951,7 @@ static const struct amba_id etm4_ids[] = { CS_AMBA_UCI_ID(0x000bbd05, uci_id_etm4),/* Cortex-A55 */ CS_AMBA_UCI_ID(0x000bbd0a, uci_id_etm4),/* Cortex-A75 */ CS_AMBA_UCI_ID(0x000bbd0c, uci_id_etm4),/* Neoverse N1 */ + CS_AMBA_UCI_ID(0x000bbd41, uci_id_etm4),/* Cortex-A78 */ CS_AMBA_UCI_ID(0x000f0205, uci_id_etm4),/* Qualcomm Kryo */ CS_AMBA_UCI_ID(0x000f0211, uci_id_etm4),/* Qualcomm Kryo */ CS_AMBA_UCI_ID(0x000bb802, uci_id_etm4),/* Qualcomm Kryo 385 Cortex-A55 */ diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index c9ac3dc651135d156915f425ce9c232c94e568ad..24d0c974bfd55d400c8b7362152fde49f33a427b 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -844,7 +844,7 @@ static irqreturn_t intel_th_irq(int irq, void *data) * @irq: irq number */ struct intel_th * -intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, +intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata, struct resource *devres, unsigned int ndevres) { int err, r, nr_mmios = 0; diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c index f72803a0239109a4c0249f27f45d26247948edbe..28509b02a0b563ab81b2229880d57a533fdbf8e3 100644 --- a/drivers/hwtracing/intel_th/gth.c +++ b/drivers/hwtracing/intel_th/gth.c @@ -543,7 +543,7 @@ static void intel_th_gth_disable(struct intel_th_device *thdev, output->active = false; for_each_set_bit(master, gth->output[output->port].master, - TH_CONFIGURABLE_MASTERS) { + TH_CONFIGURABLE_MASTERS + 1) { gth_master_set(gth, master, -1); } spin_unlock(>h->gth_lock); @@ -697,7 +697,7 @@ static void intel_th_gth_unassign(struct intel_th_device *thdev, othdev->output.port = -1; othdev->output.active = false; gth->output[port].output = NULL; - for (master = 0; master <= TH_CONFIGURABLE_MASTERS; master++) + for (master = 0; master < TH_CONFIGURABLE_MASTERS + 1; master++) if (gth->master[master] == port) gth->master[master] = -1; spin_unlock(>h->gth_lock); diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h index 5fe694708b7a3117991900ea89028b366ae18810..89c67e0e1d348e7184fcbe18df676ca4e2d97bf9 100644 --- a/drivers/hwtracing/intel_th/intel_th.h +++ b/drivers/hwtracing/intel_th/intel_th.h @@ -74,7 +74,7 @@ struct intel_th_drvdata { */ struct intel_th_device { struct device dev; - struct intel_th_drvdata *drvdata; + const struct intel_th_drvdata *drvdata; struct resource *resource; unsigned int num_resources; unsigned int type; @@ -178,7 +178,7 @@ struct intel_th_driver { /* file_operations for those who want a device node */ const struct file_operations *fops; /* optional attributes */ - struct attribute_group *attr_group; + const struct attribute_group *attr_group; /* source ops */ int (*set_output)(struct intel_th_device *thdev, @@ -224,7 +224,7 @@ static inline struct intel_th *to_intel_th(struct intel_th_device *thdev) } struct intel_th * -intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, +intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata, struct resource *devres, unsigned int ndevres); void intel_th_free(struct intel_th *th); @@ -272,7 +272,7 @@ struct intel_th { struct intel_th_device *thdev[TH_SUBDEVICE_MAX]; struct intel_th_device *hub; - struct intel_th_drvdata *drvdata; + const struct intel_th_drvdata *drvdata; struct resource resource[TH_MMIO_END]; int (*activate)(struct intel_th *); diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 7d95242db900f0fa4151280cfcf9fa3cfe2147bc..2edc4666633d0bc974bbe1274cad1a186b2382ad 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -2095,7 +2095,7 @@ static struct attribute *msc_output_attrs[] = { NULL, }; -static struct attribute_group msc_output_group = { +static const struct attribute_group msc_output_group = { .attrs = msc_output_attrs, }; diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index 251e75c9ba9d0dda26e17d2558715a00a7a923bb..7da4f298ed01e4b2b07064170d8bf40792200f43 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -71,7 +71,7 @@ static void intel_th_pci_deactivate(struct intel_th *th) static int intel_th_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct intel_th_drvdata *drvdata = (void *)id->driver_data; + const struct intel_th_drvdata *drvdata = (void *)id->driver_data; struct resource resource[TH_MMIO_END + TH_NVEC_MAX] = { [TH_MMIO_CONFIG] = pdev->resource[TH_PCI_CONFIG_BAR], [TH_MMIO_SW] = pdev->resource[TH_PCI_STH_SW_BAR], @@ -273,11 +273,21 @@ static const struct pci_device_id intel_th_pci_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x51a6), .driver_data = (kernel_ulong_t)&intel_th_2x, }, + { + /* Alder Lake-M */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x54a6), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, { /* Alder Lake CPU */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x466f), .driver_data = (kernel_ulong_t)&intel_th_2x, }, + { + /* Rocket Lake CPU */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c19), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, { 0 }, }; diff --git a/drivers/hwtracing/intel_th/pti.c b/drivers/hwtracing/intel_th/pti.c index 0da6b787f55367ff0a1e07b07e4da673c2656be4..09132ab8bc23265a083597f44a0f44b5bd77d0c4 100644 --- a/drivers/hwtracing/intel_th/pti.c +++ b/drivers/hwtracing/intel_th/pti.c @@ -142,7 +142,7 @@ static struct attribute *pti_output_attrs[] = { NULL, }; -static struct attribute_group pti_output_group = { +static const struct attribute_group pti_output_group = { .attrs = pti_output_attrs, }; @@ -295,7 +295,7 @@ static struct attribute *lpp_output_attrs[] = { NULL, }; -static struct attribute_group lpp_output_group = { +static const struct attribute_group lpp_output_group = { .attrs = lpp_output_attrs, }; diff --git a/drivers/hwtracing/stm/p_sys-t.c b/drivers/hwtracing/stm/p_sys-t.c index 360b5c03df95b87e600843340ae24d6cfb9f0b99..8254971c02e70eec9fd4dad08824a0bfa8cb4ae3 100644 --- a/drivers/hwtracing/stm/p_sys-t.c +++ b/drivers/hwtracing/stm/p_sys-t.c @@ -92,7 +92,7 @@ static void sys_t_policy_node_init(void *priv) { struct sys_t_policy_node *pn = priv; - generate_random_uuid(pn->uuid.b); + uuid_gen(&pn->uuid); } static int sys_t_output_open(void *priv, struct stm_output *output) @@ -292,6 +292,7 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, unsigned int m = output->master; const unsigned char nil = 0; u32 header = DATA_HEADER; + u8 uuid[UUID_SIZE]; ssize_t sz; /* We require an existing policy node to proceed */ @@ -322,7 +323,8 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, return sz; /* GUID */ - sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE); + export_uuid(uuid, &op->node.uuid); + sz = stm_data_write(data, m, c, false, uuid, sizeof(op->node.uuid)); if (sz <= 0) return sz; diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 603b4a9969d3a2622f8ad5b2912f64583105d7c1..42103c3a177f92f85011de8ce638c2994ecaa898 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -57,11 +57,6 @@ void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, *cend = policy_node->last_channel; } -static inline char *stp_policy_node_name(struct stp_policy_node *policy_node) -{ - return policy_node->group.cg_item.ci_name ? : "<none>"; -} - static inline struct stp_policy *to_stp_policy(struct config_item *item) { return item ? diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 05ebf7546e3f61eae46f38cbfc4145b13abc5e96..3eec59f1fed355f80c30ad5e8832ec7db3990c11 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -369,7 +369,7 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)" config I2C_ALTERA tristate "Altera Soft IP I2C" - depends on ARCH_SOCFPGA || NIOS2 || COMPILE_TEST + depends on ARCH_INTEL_SOCFPGA || NIOS2 || COMPILE_TEST depends on OF help If you say yes to this option, support will be included for the diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 3273360f30f731a06ebe74fad94119421ad6b3c8..ec1b9d306ba615d132c49f419b12b74b0787e651 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -744,8 +744,8 @@ static struct cpuidle_state icx_cstates[] __initdata = { .name = "C6", .desc = "MWAIT 0x20", .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, - .exit_latency = 128, - .target_residency = 384, + .exit_latency = 170, + .target_residency = 600, .enter = &intel_idle, .enter_s2idle = intel_idle_s2idle, }, { @@ -1156,6 +1156,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &idle_cpu_skl), X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &idle_cpu_skx), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &idle_cpu_icx), + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &idle_cpu_icx), X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &idle_cpu_knl), X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &idle_cpu_knl), X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &idle_cpu_bxt), diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 267553386c710191abbebe520843025209e09672..2334ad249b462e787c6eeccd16fcbddb1e51b45e 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -72,6 +72,7 @@ source "drivers/iio/accel/Kconfig" source "drivers/iio/adc/Kconfig" source "drivers/iio/afe/Kconfig" source "drivers/iio/amplifiers/Kconfig" +source "drivers/iio/cdc/Kconfig" source "drivers/iio/chemical/Kconfig" source "drivers/iio/common/Kconfig" source "drivers/iio/dac/Kconfig" @@ -85,6 +86,7 @@ source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" source "drivers/iio/multiplexer/Kconfig" source "drivers/iio/orientation/Kconfig" +source "drivers/iio/test/Kconfig" if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 1712011c0f4a1696e5a455fb2a6d45945927d156..65e39bd4f93462e31c0a8bf0f17104e0b1d68dc8 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -18,6 +18,7 @@ obj-y += adc/ obj-y += afe/ obj-y += amplifiers/ obj-y += buffer/ +obj-y += cdc/ obj-y += chemical/ obj-y += common/ obj-y += dac/ @@ -38,4 +39,5 @@ obj-y += pressure/ obj-y += proximity/ obj-y += resolver/ obj-y += temperature/ +obj-y += test/ obj-y += trigger/ diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2e0c62c3915508ea9fa7cda5c0425d36ba560326..cceda3cecbcf47b29a398bc2c1e91571915607e3 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -157,6 +157,24 @@ config BMC150_ACCEL_SPI tristate select REGMAP_SPI +config BMI088_ACCEL + tristate "Bosch BMI088 Accelerometer Driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP + select BMI088_ACCEL_SPI + help + Say yes here to build support for the Bosch BMI088 accelerometer. + + This is a combo module with both accelerometer and gyroscope. This + driver only implements the accelerometer part, which has its own + address and register map. BMG160 provides the gyroscope driver. + +config BMI088_ACCEL_SPI + tristate + select REGMAP_SPI + config DA280 tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 4f6c1ebe13b0fcee29d13043474c35d9ef0c1058..32cd1342a31af42805bf2309e7f0470abaf06af4 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -20,6 +20,8 @@ obj-$(CONFIG_BMA400_SPI) += bma400_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o +obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o +obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o obj-$(CONFIG_DA280) += da280.o obj-$(CONFIG_DA311) += da311.o obj-$(CONFIG_DMARD06) += dmard06.o diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index 3633a4e302c6899864ee1ea5b001339b4ae13018..fe225990de24be8d354f7250f09b9d224bd2ee66 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -215,7 +215,7 @@ static const struct iio_chan_spec adis16201_channels[] = { ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, + ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), IIO_CHAN_SOFT_TIMESTAMP(7) }; diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 8ba1453b8dbf4432b0a3223285cdb3eb317c4acf..9c9a896a872a047cecf119c4263cf6c4359906d4 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1236,8 +1236,6 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, st->dready_trig->ops = &adxl372_trigger_ops; st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; - st->dready_trig->dev.parent = dev; - st->peak_datardy_trig->dev.parent = dev; iio_trigger_set_drvdata(st->dready_trig, indio_dev); iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); ret = devm_iio_trigger_register(dev, st->dready_trig); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 71f85a3e525b2e2df6f1fdbf39569a884c826fe3..b8a7469cdae4185805d69aebd51a2da47d9e0ba1 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1044,7 +1044,7 @@ static int bma180_probe(struct i2c_client *client, indio_dev->info = &bma180_info; if (client->irq > 0) { - data->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!data->trig) { ret = -ENOMEM; @@ -1059,7 +1059,6 @@ static int bma180_probe(struct i2c_client *client, goto err_trigger_free; } - data->trig->dev.parent = dev; data->trig->ops = &bma180_trigger_ops; iio_trigger_set_drvdata(data->trig, indio_dev); indio_dev->trig = iio_trigger_get(data->trig); diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 3c9b0c6954e60ff7a73b0bd9a49b65283a33cb4f..36fc9876dbcaf8eddfaa7fcdcd8d41ffae693c68 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * BMA220 Digital triaxial acceleration sensor driver * * Copyright (c) 2016,2020 Intel Corporation. diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 7e425ebcd7ea8bd34021780d31165df4558a12bc..04d85ce34e9f5703037e67f25b6f5bb3a197467c 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -443,26 +443,32 @@ static bool bmc150_apply_acpi_orientation(struct device *dev, struct iio_mount_matrix *orientation) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct acpi_device *adev = ACPI_COMPANION(dev); + char *name, *alt_name, *label, *str; union acpi_object *obj, *elements; - char *name, *alt_name, *str; acpi_status status; int i, j, val[3]; if (!adev || !acpi_dev_hid_uid_match(adev, "BOSC0200", NULL)) return false; - if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) + if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) { alt_name = "ROMK"; - else + label = "accel-base"; + } else { alt_name = "ROMS"; + label = "accel-display"; + } - if (acpi_has_method(adev->handle, "ROTM")) + if (acpi_has_method(adev->handle, "ROTM")) { name = "ROTM"; - else if (acpi_has_method(adev->handle, alt_name)) + } else if (acpi_has_method(adev->handle, alt_name)) { name = alt_name; - else + indio_dev->label = label; + } else { return false; + } status = acpi_evaluate_object(adev->handle, name, NULL, &buffer); if (ACPI_FAILURE(status)) { @@ -1472,7 +1478,6 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, break; } - t->indio_trig->dev.parent = dev; t->indio_trig->ops = &bmc150_accel_trigger_ops; t->intr = bmc150_accel_triggers[i].intr; t->data = data; diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c new file mode 100644 index 0000000000000000000000000000000000000000..12d00658e46f66315fd49e2f5289be1e1313f9a7 --- /dev/null +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -0,0 +1,567 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: + * - BMI088 + * + * Copyright (c) 2018-2021, Topic Embedded Products + */ + +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <asm/unaligned.h> + +#include "bmi088-accel.h" + +#define BMI088_ACCEL_REG_CHIP_ID 0x00 +#define BMI088_ACCEL_REG_ERROR 0x02 + +#define BMI088_ACCEL_REG_INT_STATUS 0x1D +#define BMI088_ACCEL_INT_STATUS_BIT_DRDY BIT(7) + +#define BMI088_ACCEL_REG_RESET 0x7E +#define BMI088_ACCEL_RESET_VAL 0xB6 + +#define BMI088_ACCEL_REG_PWR_CTRL 0x7D +#define BMI088_ACCEL_REG_PWR_CONF 0x7C + +#define BMI088_ACCEL_REG_INT_MAP_DATA 0x58 +#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT1_DRDY BIT(2) +#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT2_FWM BIT(5) + +#define BMI088_ACCEL_REG_INT1_IO_CONF 0x53 +#define BMI088_ACCEL_INT1_IO_CONF_BIT_ENABLE_OUT BIT(3) +#define BMI088_ACCEL_INT1_IO_CONF_BIT_LVL BIT(1) + +#define BMI088_ACCEL_REG_INT2_IO_CONF 0x54 +#define BMI088_ACCEL_INT2_IO_CONF_BIT_ENABLE_OUT BIT(3) +#define BMI088_ACCEL_INT2_IO_CONF_BIT_LVL BIT(1) + +#define BMI088_ACCEL_REG_ACC_CONF 0x40 +#define BMI088_ACCEL_MODE_ODR_MASK 0x0f + +#define BMI088_ACCEL_REG_ACC_RANGE 0x41 +#define BMI088_ACCEL_RANGE_3G 0x00 +#define BMI088_ACCEL_RANGE_6G 0x01 +#define BMI088_ACCEL_RANGE_12G 0x02 +#define BMI088_ACCEL_RANGE_24G 0x03 + +#define BMI088_ACCEL_REG_TEMP 0x22 +#define BMI088_ACCEL_REG_TEMP_SHIFT 5 +#define BMI088_ACCEL_TEMP_UNIT 125 +#define BMI088_ACCEL_TEMP_OFFSET 23000 + +#define BMI088_ACCEL_REG_XOUT_L 0x12 +#define BMI088_ACCEL_AXIS_TO_REG(axis) \ + (BMI088_ACCEL_REG_XOUT_L + (axis * 2)) + +#define BMI088_ACCEL_MAX_STARTUP_TIME_US 1000 +#define BMI088_AUTO_SUSPEND_DELAY_MS 2000 + +#define BMI088_ACCEL_REG_FIFO_STATUS 0x0E +#define BMI088_ACCEL_REG_FIFO_CONFIG0 0x48 +#define BMI088_ACCEL_REG_FIFO_CONFIG1 0x49 +#define BMI088_ACCEL_REG_FIFO_DATA 0x3F +#define BMI088_ACCEL_FIFO_LENGTH 100 + +#define BMI088_ACCEL_FIFO_MODE_FIFO 0x40 +#define BMI088_ACCEL_FIFO_MODE_STREAM 0x80 + +enum bmi088_accel_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +static const int bmi088_sample_freqs[] = { + 12, 500000, + 25, 0, + 50, 0, + 100, 0, + 200, 0, + 400, 0, + 800, 0, + 1600, 0, +}; + +/* Available OSR (over sampling rate) sets the 3dB cut-off frequency */ +enum bmi088_osr_modes { + BMI088_ACCEL_MODE_OSR_NORMAL = 0xA, + BMI088_ACCEL_MODE_OSR_2 = 0x9, + BMI088_ACCEL_MODE_OSR_4 = 0x8, +}; + +/* Available ODR (output data rates) in Hz */ +enum bmi088_odr_modes { + BMI088_ACCEL_MODE_ODR_12_5 = 0x5, + BMI088_ACCEL_MODE_ODR_25 = 0x6, + BMI088_ACCEL_MODE_ODR_50 = 0x7, + BMI088_ACCEL_MODE_ODR_100 = 0x8, + BMI088_ACCEL_MODE_ODR_200 = 0x9, + BMI088_ACCEL_MODE_ODR_400 = 0xa, + BMI088_ACCEL_MODE_ODR_800 = 0xb, + BMI088_ACCEL_MODE_ODR_1600 = 0xc, +}; + +struct bmi088_scale_info { + int scale; + u8 reg_range; +}; + +struct bmi088_accel_chip_info { + const char *name; + u8 chip_id; + const struct iio_chan_spec *channels; + int num_channels; +}; + +struct bmi088_accel_data { + struct regmap *regmap; + const struct bmi088_accel_chip_info *chip_info; + u8 buffer[2] ____cacheline_aligned; /* shared DMA safe buffer */ +}; + +static const struct regmap_range bmi088_volatile_ranges[] = { + /* All registers below 0x40 are volatile, except the CHIP ID. */ + regmap_reg_range(BMI088_ACCEL_REG_ERROR, 0x3f), + /* Mark the RESET as volatile too, it is self-clearing */ + regmap_reg_range(BMI088_ACCEL_REG_RESET, BMI088_ACCEL_REG_RESET), +}; + +static const struct regmap_access_table bmi088_volatile_table = { + .yes_ranges = bmi088_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(bmi088_volatile_ranges), +}; + +const struct regmap_config bmi088_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x7E, + .volatile_table = &bmi088_volatile_table, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(bmi088_regmap_conf); + +static int bmi088_accel_power_up(struct bmi088_accel_data *data) +{ + int ret; + + /* Enable accelerometer and temperature sensor */ + ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x4); + if (ret) + return ret; + + /* Datasheet recommends to wait at least 5ms before communication */ + usleep_range(5000, 6000); + + /* Disable suspend mode */ + ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x0); + if (ret) + return ret; + + /* Recommended at least 1ms before further communication */ + usleep_range(1000, 1200); + + return 0; +} + +static int bmi088_accel_power_down(struct bmi088_accel_data *data) +{ + int ret; + + /* Enable suspend mode */ + ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x3); + if (ret) + return ret; + + /* Recommended at least 1ms before further communication */ + usleep_range(1000, 1200); + + /* Disable accelerometer and temperature sensor */ + ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x0); + if (ret) + return ret; + + /* Datasheet recommends to wait at least 5ms before communication */ + usleep_range(5000, 6000); + + return 0; +} + +static int bmi088_accel_get_sample_freq(struct bmi088_accel_data *data, + int *val, int *val2) +{ + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, BMI088_ACCEL_REG_ACC_CONF, + &value); + if (ret) + return ret; + + value &= BMI088_ACCEL_MODE_ODR_MASK; + value -= BMI088_ACCEL_MODE_ODR_12_5; + value <<= 1; + + if (value >= ARRAY_SIZE(bmi088_sample_freqs) - 1) + return -EINVAL; + + *val = bmi088_sample_freqs[value]; + *val2 = bmi088_sample_freqs[value + 1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int bmi088_accel_set_sample_freq(struct bmi088_accel_data *data, int val) +{ + unsigned int regval; + int index = 0; + + while (index < ARRAY_SIZE(bmi088_sample_freqs) && + bmi088_sample_freqs[index] != val) + index += 2; + + if (index >= ARRAY_SIZE(bmi088_sample_freqs)) + return -EINVAL; + + regval = (index >> 1) + BMI088_ACCEL_MODE_ODR_12_5; + + return regmap_update_bits(data->regmap, BMI088_ACCEL_REG_ACC_CONF, + BMI088_ACCEL_MODE_ODR_MASK, regval); +} + +static int bmi088_accel_get_temp(struct bmi088_accel_data *data, int *val) +{ + int ret; + s16 temp; + + ret = regmap_bulk_read(data->regmap, BMI088_ACCEL_REG_TEMP, + &data->buffer, sizeof(__be16)); + if (ret) + return ret; + + /* data->buffer is cacheline aligned */ + temp = be16_to_cpu(*(__be16 *)data->buffer); + + *val = temp >> BMI088_ACCEL_REG_TEMP_SHIFT; + + return IIO_VAL_INT; +} + +static int bmi088_accel_get_axis(struct bmi088_accel_data *data, + struct iio_chan_spec const *chan, + int *val) +{ + int ret; + s16 raw_val; + + ret = regmap_bulk_read(data->regmap, + BMI088_ACCEL_AXIS_TO_REG(chan->scan_index), + data->buffer, sizeof(__le16)); + if (ret) + return ret; + + raw_val = le16_to_cpu(*(__le16 *)data->buffer); + *val = raw_val; + + return IIO_VAL_INT; +} + +static int bmi088_accel_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bmi088_accel_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + pm_runtime_get_sync(dev); + ret = bmi088_accel_get_temp(data, val); + goto out_read_raw_pm_put; + case IIO_ACCEL: + pm_runtime_get_sync(dev); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + goto out_read_raw_pm_put; + + ret = bmi088_accel_get_axis(data, chan, val); + iio_device_release_direct_mode(indio_dev); + if (!ret) + ret = IIO_VAL_INT; + + goto out_read_raw_pm_put; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + /* Offset applies before scale */ + *val = BMI088_ACCEL_TEMP_OFFSET/BMI088_ACCEL_TEMP_UNIT; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + /* 0.125 degrees per LSB */ + *val = BMI088_ACCEL_TEMP_UNIT; + return IIO_VAL_INT; + case IIO_ACCEL: + pm_runtime_get_sync(dev); + ret = regmap_read(data->regmap, + BMI088_ACCEL_REG_ACC_RANGE, val); + if (ret) + goto out_read_raw_pm_put; + + *val2 = 15 - (*val & 0x3); + *val = 3 * 980; + ret = IIO_VAL_FRACTIONAL_LOG2; + + goto out_read_raw_pm_put; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + pm_runtime_get_sync(dev); + ret = bmi088_accel_get_sample_freq(data, val, val2); + goto out_read_raw_pm_put; + default: + break; + } + + return -EINVAL; + +out_read_raw_pm_put: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static int bmi088_accel_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_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + *vals = bmi088_sample_freqs; + *length = ARRAY_SIZE(bmi088_sample_freqs); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int bmi088_accel_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmi088_accel_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + pm_runtime_get_sync(dev); + ret = bmi088_accel_set_sample_freq(data, val); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return ret; + default: + return -EINVAL; + } +} + +#define BMI088_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_SAMP_FREQ), \ + .scan_index = AXIS_##_axis, \ +} + +static const struct iio_chan_spec bmi088_accel_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = -1, + }, + BMI088_ACCEL_CHANNEL(X), + BMI088_ACCEL_CHANNEL(Y), + BMI088_ACCEL_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct bmi088_accel_chip_info bmi088_accel_chip_info_tbl[] = { + [0] = { + .name = "bmi088a", + .chip_id = 0x1E, + .channels = bmi088_accel_channels, + .num_channels = ARRAY_SIZE(bmi088_accel_channels), + }, +}; + +static const struct iio_info bmi088_accel_info = { + .read_raw = bmi088_accel_read_raw, + .write_raw = bmi088_accel_write_raw, + .read_avail = bmi088_accel_read_avail, +}; + +static const unsigned long bmi088_accel_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0 +}; + +static int bmi088_accel_chip_init(struct bmi088_accel_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret, i; + unsigned int val; + + /* Do a dummy read to enable SPI interface, won't harm I2C */ + regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val); + + /* + * Reset chip to get it in a known good state. A delay of 1ms after + * reset is required according to the data sheet + */ + ret = regmap_write(data->regmap, BMI088_ACCEL_REG_RESET, + BMI088_ACCEL_RESET_VAL); + if (ret) + return ret; + + usleep_range(1000, 2000); + + /* Do a dummy read again after a reset to enable the SPI interface */ + regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val); + + /* Read chip ID */ + ret = regmap_read(data->regmap, BMI088_ACCEL_REG_CHIP_ID, &val); + if (ret) { + dev_err(dev, "Error: Reading chip id\n"); + return ret; + } + + /* Validate chip ID */ + for (i = 0; i < ARRAY_SIZE(bmi088_accel_chip_info_tbl); i++) { + if (bmi088_accel_chip_info_tbl[i].chip_id == val) { + data->chip_info = &bmi088_accel_chip_info_tbl[i]; + break; + } + } + if (i == ARRAY_SIZE(bmi088_accel_chip_info_tbl)) { + dev_err(dev, "Invalid chip %x\n", val); + return -ENODEV; + } + + return 0; +} + +int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, + int irq, const char *name, bool block_supported) +{ + struct bmi088_accel_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); + dev_set_drvdata(dev, indio_dev); + + data->regmap = regmap; + + ret = bmi088_accel_chip_init(data); + if (ret) + return ret; + + indio_dev->dev.parent = dev; + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; + indio_dev->name = name ? name : data->chip_info->name; + indio_dev->available_scan_masks = bmi088_accel_scan_masks; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmi088_accel_info; + + /* Enable runtime PM */ + pm_runtime_get_noresume(dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + /* We need ~6ms to startup, so set the delay to 6 seconds */ + pm_runtime_set_autosuspend_delay(dev, 6000); + pm_runtime_use_autosuspend(dev); + pm_runtime_put(dev); + + ret = iio_device_register(indio_dev); + if (ret) + dev_err(dev, "Unable to register iio device\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(bmi088_accel_core_probe); + + +int bmi088_accel_core_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmi088_accel_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); + bmi088_accel_power_down(data); + + return 0; +} +EXPORT_SYMBOL_GPL(bmi088_accel_core_remove); + +static int __maybe_unused bmi088_accel_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmi088_accel_data *data = iio_priv(indio_dev); + + return bmi088_accel_power_down(data); +} + +static int __maybe_unused bmi088_accel_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmi088_accel_data *data = iio_priv(indio_dev); + + return bmi088_accel_power_up(data); +} + +const struct dev_pm_ops bmi088_accel_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(bmi088_accel_runtime_suspend, + bmi088_accel_runtime_resume, NULL) +}; +EXPORT_SYMBOL_GPL(bmi088_accel_pm_ops); + +MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMI088 accelerometer driver (core)"); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c new file mode 100644 index 0000000000000000000000000000000000000000..dd1e3f6cf211173607ccf72555f6f9aaaf54376f --- /dev/null +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: + * - BMI088 + * + * Copyright (c) 2018-2020, Topic Embedded Products + */ + +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +#include "bmi088-accel.h" + +static int bmi088_regmap_spi_write(void *context, const void *data, size_t count) +{ + struct spi_device *spi = context; + + /* Write register is same as generic SPI */ + return spi_write(spi, data, count); +} + +static int bmi088_regmap_spi_read(void *context, const void *reg, + size_t reg_size, void *val, size_t val_size) +{ + struct spi_device *spi = context; + u8 addr[2]; + + addr[0] = *(u8 *)reg; + addr[0] |= BIT(7); /* Set RW = '1' */ + addr[1] = 0; /* Read requires a dummy byte transfer */ + + return spi_write_then_read(spi, addr, sizeof(addr), val, val_size); +} + +static struct regmap_bus bmi088_regmap_bus = { + .write = bmi088_regmap_spi_write, + .read = bmi088_regmap_spi_read, +}; + +static int bmi088_accel_probe(struct spi_device *spi) +{ + struct regmap *regmap; + const struct spi_device_id *id = spi_get_device_id(spi); + + regmap = devm_regmap_init(&spi->dev, &bmi088_regmap_bus, + spi, &bmi088_regmap_conf); + + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to initialize spi regmap\n"); + return PTR_ERR(regmap); + } + + return bmi088_accel_core_probe(&spi->dev, regmap, spi->irq, id->name, + true); +} + +static int bmi088_accel_remove(struct spi_device *spi) +{ + return bmi088_accel_core_remove(&spi->dev); +} + +static const struct spi_device_id bmi088_accel_id[] = { + {"bmi088-accel", }, + {} +}; +MODULE_DEVICE_TABLE(spi, bmi088_accel_id); + +static struct spi_driver bmi088_accel_driver = { + .driver = { + .name = "bmi088_accel_spi", + .pm = &bmi088_accel_pm_ops, + }, + .probe = bmi088_accel_probe, + .remove = bmi088_accel_remove, + .id_table = bmi088_accel_id, +}; +module_spi_driver(bmi088_accel_driver); + +MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMI088 accelerometer driver (SPI)"); diff --git a/drivers/iio/accel/bmi088-accel.h b/drivers/iio/accel/bmi088-accel.h new file mode 100644 index 0000000000000000000000000000000000000000..5c25f16b672c961c59b18a4332b151f381fc8e21 --- /dev/null +++ b/drivers/iio/accel/bmi088-accel.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef BMI088_ACCEL_H +#define BMI088_ACCEL_H + +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/types.h> + +struct device; + +extern const struct regmap_config bmi088_regmap_conf; +extern const struct dev_pm_ops bmi088_accel_pm_ops; + +int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name, bool block_supported); +int bmi088_accel_core_remove(struct device *dev); + +#endif /* BMI088_ACCEL_H */ diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index 8f1232c38e0d782dbd68e0ad7148b002aa34685e..b6f3471b62dcf478b2e6cbdc6245f16fac955649 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -215,7 +215,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) return -ENOMEM; ret = cros_ec_sensors_core_init(pdev, indio_dev, true, - cros_ec_sensors_capture, NULL, false); + cros_ec_sensors_capture, NULL); if (ret) return ret; diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 4472dde6899ecfe253d5eb3b5f40998917e7861a..5edff9ba72da757949caa1f052187fd6815eeeac 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * IIO driver for the MiraMEMS DA280 3-axis accelerometer and * IIO driver for the MiraMEMS DA226 2-axis accelerometer * diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 3b3df620ba272323ab5033af4f338c7bc5ee3486..92593a1cd1aa619e4e76f437236fe79a8bfe9ccd 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * IIO driver for the MiraMEMS DA311 3-axis accelerometer * * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 90206f015857da7db26fb8d7a6d567eee9ad4eb6..e84bf8db1e8958420f1b478a89385ba23aacd5d6 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * IIO driver for the 3-axis accelerometer Domintech ARD10. * * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 5d63ed19e6e2578896acf01b27f82113bf308978..2f9465cb382ffd0d6e6445b6b20973d7a839079e 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -43,6 +43,10 @@ static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ACCEL_Z_AXIS }; +static const u32 accel_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ACCELERATION, +}; + /* Channel definitions */ static const struct iio_chan_spec accel_3d_channels[] = { { @@ -317,18 +321,6 @@ static int accel_3d_parse_report(struct platform_device *pdev, &st->accel[CHANNEL_SCAN_INDEX_X], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ACCELERATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - return ret; } @@ -366,8 +358,11 @@ static int hid_accel_3d_probe(struct platform_device *pdev) channel_size = sizeof(gravity_channels); indio_dev->num_channels = ARRAY_SIZE(gravity_channels); } - ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, - &accel_state->common_attributes); + ret = hid_sensor_parse_common_attributes(hsdev, + hsdev->usage, + &accel_state->common_attributes, + accel_3d_sensitivity_addresses, + ARRAY_SIZE(accel_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 2fadafc860fd6d7289ccc25345c44bb4bb16eb53..ff724bc17a458a96a7e0743337645421d57b832f 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1284,7 +1284,8 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) static const char *kxcjk1013_match_acpi_device(struct device *dev, enum kx_chipset *chipset, - enum kx_acpi_type *acpi_type) + enum kx_acpi_type *acpi_type, + const char **label) { const struct acpi_device_id *id; @@ -1292,10 +1293,14 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev, if (!id) return NULL; - if (strcmp(id->id, "SMO8500") == 0) + if (strcmp(id->id, "SMO8500") == 0) { *acpi_type = ACPI_SMO8500; - else if (strcmp(id->id, "KIOX010A") == 0) + } 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; @@ -1368,7 +1373,8 @@ static int kxcjk1013_probe(struct i2c_client *client, } else if (ACPI_HANDLE(&client->dev)) { name = kxcjk1013_match_acpi_device(&client->dev, &data->chipset, - &data->acpi_type); + &data->acpi_type, + &indio_dev->label); } else return -ENODEV; @@ -1413,7 +1419,6 @@ static int kxcjk1013_probe(struct i2c_client *client, goto err_poweroff; } - data->dready_trig->dev.parent = &client->dev; data->dready_trig->ops = &kxcjk1013_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); indio_dev->trig = data->dready_trig; @@ -1422,7 +1427,6 @@ static int kxcjk1013_probe(struct i2c_client *client, if (ret) goto err_poweroff; - data->motion_trig->dev.parent = &client->dev; data->motion_trig->ops = &kxcjk1013_trigger_ops; iio_trigger_set_drvdata(data->motion_trig, indio_dev); ret = iio_trigger_register(data->motion_trig); diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index 46e4283fc037562dfae535f3ce9216358f6e41c1..735002b716f329f272272b5f632e7a3be95f214c 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/** +/* * mCube MC3230 3-Axis Accelerometer * * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index b3c9136d51ec74a90a7c70bcc7c877e086d7ab4d..47f5cd66e996e8325ee6d21e816fd9325cfb3336 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Freescale MMA7660FC 3-Axis Accelerometer * * Copyright (c) 2016, Intel Corporation. diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index b0176d936423db8320dd6ca75d708593cb669926..4d307dfb9169c502e972c2d83ec6626a25e501d0 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -58,7 +58,7 @@ #define MMA8452_FF_MT_THS 0x17 #define MMA8452_FF_MT_THS_MASK 0x7f #define MMA8452_FF_MT_COUNT 0x18 -#define MMA8452_FF_MT_CHAN_SHIFT 3 +#define MMA8452_FF_MT_CHAN_SHIFT 3 #define MMA8452_TRANSIENT_CFG 0x1d #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) @@ -70,7 +70,7 @@ #define MMA8452_TRANSIENT_THS 0x1f #define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) #define MMA8452_TRANSIENT_COUNT 0x20 -#define MMA8452_TRANSIENT_CHAN_SHIFT 1 +#define MMA8452_TRANSIENT_CHAN_SHIFT 1 #define MMA8452_CTRL_REG1 0x2a #define MMA8452_CTRL_ACTIVE BIT(0) #define MMA8452_CTRL_DR_MASK GENMASK(5, 3) @@ -134,33 +134,33 @@ struct mma8452_data { * used for different chips and the relevant registers are included here. */ struct mma8452_event_regs { - u8 ev_cfg; - u8 ev_cfg_ele; - u8 ev_cfg_chan_shift; - u8 ev_src; - u8 ev_ths; - u8 ev_ths_mask; - u8 ev_count; + u8 ev_cfg; + u8 ev_cfg_ele; + u8 ev_cfg_chan_shift; + u8 ev_src; + u8 ev_ths; + u8 ev_ths_mask; + u8 ev_count; }; static const struct mma8452_event_regs ff_mt_ev_regs = { - .ev_cfg = MMA8452_FF_MT_CFG, - .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, - .ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT, - .ev_src = MMA8452_FF_MT_SRC, - .ev_ths = MMA8452_FF_MT_THS, - .ev_ths_mask = MMA8452_FF_MT_THS_MASK, - .ev_count = MMA8452_FF_MT_COUNT + .ev_cfg = MMA8452_FF_MT_CFG, + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, + .ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT, + .ev_src = MMA8452_FF_MT_SRC, + .ev_ths = MMA8452_FF_MT_THS, + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, + .ev_count = MMA8452_FF_MT_COUNT }; static const struct mma8452_event_regs trans_ev_regs = { - .ev_cfg = MMA8452_TRANSIENT_CFG, - .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, - .ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT, - .ev_src = MMA8452_TRANSIENT_SRC, - .ev_ths = MMA8452_TRANSIENT_THS, - .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, - .ev_count = MMA8452_TRANSIENT_COUNT, + .ev_cfg = MMA8452_TRANSIENT_CFG, + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, + .ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT, + .ev_src = MMA8452_TRANSIENT_SRC, + .ev_ths = MMA8452_TRANSIENT_THS, + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, + .ev_count = MMA8452_TRANSIENT_COUNT, }; /** @@ -1465,7 +1465,6 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev) if (!trig) return -ENOMEM; - trig->dev.parent = &data->client->dev; trig->ops = &mma8452_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 0f8fd687866d4d0e086a37bb1ce20a1561f7a3e3..fb3cbaa62bd879ace716fb159b375f66f5e9ae20 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -450,7 +450,6 @@ static int mxc4005_probe(struct i2c_client *client, return ret; } - data->dready_trig->dev.parent = &client->dev; data->dready_trig->ops = &mxc4005_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); indio_dev->trig = data->dready_trig; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 194738660523d45b88560776803e5e2da11f463a..cb753a43533cdd85170f2a8156ce94c07dc3d524 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -351,7 +351,7 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) } /** - * sca3000_write_ctrl_reg() write to a lock protect ctrl register + * sca3000_write_ctrl_reg() - write to a lock protect ctrl register * @st: Driver specific device instance data. * @sel: selects which registers we wish to write to * @val: the value to be written @@ -389,7 +389,7 @@ error_ret: } /** - * sca3000_read_ctrl_reg() read from lock protected control register. + * sca3000_read_ctrl_reg() - read from lock protected control register. * @st: Driver specific device instance data. * @ctrl_reg: Which ctrl register do we want to read. * @@ -421,7 +421,7 @@ error_ret: } /** - * sca3000_show_rev() - sysfs interface to read the chip revision number + * sca3000_print_rev() - sysfs interface to read the chip revision number * @indio_dev: Device instance specific generic IIO data. * Driver specific device instance data can be obtained via * via iio_priv(indio_dev) @@ -902,7 +902,7 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev, } /** - * sca3000_write_value() - control of threshold and period + * sca3000_write_event_value() - control of threshold and period * @indio_dev: Device instance specific IIO information. * @chan: Description of the channel for which the event is being * configured. @@ -1272,20 +1272,6 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev, return ret; } -static int sca3000_configure_ring(struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer; - - buffer = devm_iio_kfifo_allocate(&indio_dev->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->modes |= INDIO_BUFFER_SOFTWARE; - - return 0; -} - static inline int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) { @@ -1479,7 +1465,9 @@ static int sca3000_probe(struct spi_device *spi) } indio_dev->modes = INDIO_DIRECT_MODE; - ret = sca3000_configure_ring(indio_dev); + ret = devm_iio_kfifo_buffer_setup(&spi->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &sca3000_ring_setup_ops); if (ret) return ret; @@ -1493,7 +1481,6 @@ static int sca3000_probe(struct spi_device *spi) if (ret) return ret; } - indio_dev->setup_ops = &sca3000_ring_setup_ops; ret = sca3000_clean_setup(st); if (ret) goto error_free_irq; diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c index 474477e91b5eace7ad6307684d9f333c21089524..04dcb2b657ee6258fbd6be3d8ffd8caba9786995 100644 --- a/drivers/iio/accel/ssp_accel_sensor.c +++ b/drivers/iio/accel/ssp_accel_sensor.c @@ -96,7 +96,6 @@ static int ssp_accel_probe(struct platform_device *pdev) int ret; struct iio_dev *indio_dev; struct ssp_sensor_data *spd; - struct iio_buffer *buffer; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd)); if (!indio_dev) @@ -109,18 +108,15 @@ static int ssp_accel_probe(struct platform_device *pdev) indio_dev->name = ssp_accel_device_name; indio_dev->info = &ssp_accel_iio_info; - indio_dev->modes = INDIO_BUFFER_SOFTWARE; indio_dev->channels = ssp_acc_channels; indio_dev->num_channels = ARRAY_SIZE(ssp_acc_channels); indio_dev->available_scan_masks = ssp_accel_scan_mask; - buffer = devm_iio_kfifo_allocate(&pdev->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - - indio_dev->setup_ops = &ssp_accel_buffer_ops; + ret = devm_iio_kfifo_buffer_setup(&pdev->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &ssp_accel_buffer_ops); + if (ret) + return ret; platform_set_drvdata(pdev, indio_dev); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 3b59887a8581bcd49a925a290ebe7cbe6d6d58a3..157d8faefb9e4c19d05c1c028f70c104dc2e8a3a 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Sensortek STK8312 3-Axis Accelerometer * * Copyright (c) 2015, Intel Corporation. @@ -558,7 +558,6 @@ static int stk8312_probe(struct i2c_client *client, goto err_power_off; } - data->dready_trig->dev.parent = &client->dev; data->dready_trig->ops = &stk8312_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); ret = iio_trigger_register(data->dready_trig); diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 3ead378b02c9b395ffa22ed520b7a287d8763499..7cf9cb7e86667187d2247c9a2844b6fd08afff8e 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Sensortek STK8BA50 3-Axis Accelerometer * * Copyright (c) 2015, Intel Corporation. @@ -454,7 +454,6 @@ static int stk8ba50_probe(struct i2c_client *client, goto err_power_off; } - data->dready_trig->dev.parent = &client->dev; data->dready_trig->ops = &stk8ba50_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); ret = iio_trigger_register(data->dready_trig); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index e0667c4b3c08aed53975bc84a3897cc6e542465d..c7946c439612398a7a074a0bdb0ddf4c0babc119 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -97,7 +97,7 @@ config AD7298 module will be called ad7298. config AD7476 - tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD an TI" + tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI" depends on SPI select IIO_BUFFER select IIO_TRIGGERED_BUFFER @@ -249,7 +249,7 @@ config AD799X config AD9467 tristate "Analog Devices AD9467 High Speed ADC driver" depends on SPI - select ADI_AXI_ADC + depends on ADI_AXI_ADC help Say yes here to build support for Analog Devices: * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter @@ -1154,6 +1154,18 @@ config TI_ADS124S08 This driver can also be built as a module. If so, the module will be called ti-ads124s08. +config TI_ADS131E08 + tristate "Texas Instruments ADS131E08" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to get support for Texas Instruments ADS131E04, ADS131E06 + and ADS131E08 chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads131e08. + config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC && HAS_DMA diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 5fca90ada0ec38177c76d65fc0037d4a978d0f67..a226657d19c0d67f802bb370e06e2f7ecdbebbc7 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o +obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 766c7333360451ea430cf73b7cc8ddaad8ee0746..9d3952b4674f56a83e0f65eff65903570457a26a 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -5,12 +5,14 @@ * Copyright 2018 Analog Devices Inc. */ #include <linux/bitfield.h> +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/kfifo.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/regulator/consumer.h> @@ -86,6 +88,10 @@ #define AD7124_SINC3_FILTER 2 #define AD7124_SINC4_FILTER 0 +#define AD7124_CONF_ADDR_OFFSET 20 +#define AD7124_MAX_CONFIGS 8 +#define AD7124_MAX_CHANNELS 16 + enum ad7124_ids { ID_AD7124_4, ID_AD7124_8, @@ -136,25 +142,37 @@ struct ad7124_chip_info { }; struct ad7124_channel_config { + bool live; + unsigned int cfg_slot; enum ad7124_ref_sel refsel; bool bipolar; bool buf_positive; bool buf_negative; - unsigned int ain; unsigned int vref_mv; unsigned int pga_bits; unsigned int odr; + unsigned int odr_sel_bits; unsigned int filter_type; }; +struct ad7124_channel { + unsigned int nr; + struct ad7124_channel_config cfg; + unsigned int ain; + unsigned int slot; +}; + struct ad7124_state { const struct ad7124_chip_info *chip_info; struct ad_sigma_delta sd; - struct ad7124_channel_config *channel_config; + struct ad7124_channel *channels; struct regulator *vref[4]; struct clk *mclk; unsigned int adc_control; unsigned int num_channels; + struct mutex cfgs_lock; /* lock for configs access */ + unsigned long cfg_slots_status; /* bitmap with slot status (1 means it is used) */ + DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS); }; static const struct iio_chan_spec ad7124_channel_template = { @@ -238,33 +256,9 @@ static int ad7124_set_mode(struct ad_sigma_delta *sd, return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control); } -static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel) -{ - struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); - unsigned int val; - - val = st->channel_config[channel].ain | AD7124_CHANNEL_EN(1) | - AD7124_CHANNEL_SETUP(channel); - - return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(channel), 2, val); -} - -static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { - .set_channel = ad7124_set_channel, - .set_mode = ad7124_set_mode, - .has_registers = true, - .addr_shift = 0, - .read_mask = BIT(6), - .data_reg = AD7124_DATA, - .irq_flags = IRQF_TRIGGER_FALLING, -}; - -static int ad7124_set_channel_odr(struct ad7124_state *st, - unsigned int channel, - unsigned int odr) +static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr) { unsigned int fclk, odr_sel_bits; - int ret; fclk = clk_get_rate(st->mclk); /* @@ -280,36 +274,12 @@ static int ad7124_set_channel_odr(struct ad7124_state *st, else if (odr_sel_bits > 2047) odr_sel_bits = 2047; - ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel), - AD7124_FILTER_FS_MSK, - AD7124_FILTER_FS(odr_sel_bits), 3); - if (ret < 0) - return ret; - /* fADC = fCLK / (FS[10:0] x 32) */ - st->channel_config[channel].odr = - DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32); - - return 0; -} - -static int ad7124_set_channel_gain(struct ad7124_state *st, - unsigned int channel, - unsigned int gain) -{ - unsigned int res; - int ret; + if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits) + st->channels[channel].cfg.live = false; - res = ad7124_find_closest_match(ad7124_gain, - ARRAY_SIZE(ad7124_gain), gain); - ret = ad7124_spi_write_mask(st, AD7124_CONFIG(channel), - AD7124_CONFIG_PGA_MSK, - AD7124_CONFIG_PGA(res), 2); - if (ret < 0) - return ret; - - st->channel_config[channel].pga_bits = res; - - return 0; + /* fADC = fCLK / (FS[10:0] x 32) */ + st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32); + st->channels[channel].cfg.odr_sel_bits = odr_sel_bits; } static int ad7124_get_3db_filter_freq(struct ad7124_state *st, @@ -317,9 +287,9 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st, { unsigned int fadc; - fadc = st->channel_config[channel].odr; + fadc = st->channels[channel].cfg.odr; - switch (st->channel_config[channel].filter_type) { + switch (st->channels[channel].cfg.filter_type) { case AD7124_SINC3_FILTER: return DIV_ROUND_CLOSEST(fadc * 230, 1000); case AD7124_SINC4_FILTER: @@ -329,9 +299,8 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st, } } -static int ad7124_set_3db_filter_freq(struct ad7124_state *st, - unsigned int channel, - unsigned int freq) +static void ad7124_set_3db_filter_freq(struct ad7124_state *st, unsigned int channel, + unsigned int freq) { unsigned int sinc4_3db_odr; unsigned int sinc3_3db_odr; @@ -349,21 +318,211 @@ static int ad7124_set_3db_filter_freq(struct ad7124_state *st, new_odr = sinc3_3db_odr; } - if (st->channel_config[channel].filter_type != new_filter) { - int ret; + if (new_odr != st->channels[channel].cfg.odr) + st->channels[channel].cfg.live = false; - st->channel_config[channel].filter_type = new_filter; - ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel), - AD7124_FILTER_TYPE_MSK, - AD7124_FILTER_TYPE_SEL(new_filter), - 3); - if (ret < 0) - return ret; + st->channels[channel].cfg.filter_type = new_filter; + st->channels[channel].cfg.odr = new_odr; +} + +static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_state *st, + struct ad7124_channel_config *cfg) +{ + struct ad7124_channel_config *cfg_aux; + ptrdiff_t cmp_size; + int i; + + cmp_size = (u8 *)&cfg->live - (u8 *)cfg; + for (i = 0; i < st->num_channels; i++) { + cfg_aux = &st->channels[i].cfg; + + if (cfg_aux->live && !memcmp(cfg, cfg_aux, cmp_size)) + return cfg_aux; + } + + return NULL; +} + +static int ad7124_find_free_config_slot(struct ad7124_state *st) +{ + unsigned int free_cfg_slot; + + free_cfg_slot = find_next_zero_bit(&st->cfg_slots_status, AD7124_MAX_CONFIGS, 0); + if (free_cfg_slot == AD7124_MAX_CONFIGS) + return -1; + + return free_cfg_slot; +} + +static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg) +{ + unsigned int refsel = cfg->refsel; + + switch (refsel) { + case AD7124_REFIN1: + case AD7124_REFIN2: + case AD7124_AVDD_REF: + if (IS_ERR(st->vref[refsel])) { + dev_err(&st->sd.spi->dev, + "Error, trying to use external voltage reference without a %s regulator.\n", + ad7124_ref_names[refsel]); + return PTR_ERR(st->vref[refsel]); + } + cfg->vref_mv = regulator_get_voltage(st->vref[refsel]); + /* Conversion from uV to mV */ + cfg->vref_mv /= 1000; + return 0; + case AD7124_INT_REF: + cfg->vref_mv = 2500; + st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK; + st->adc_control |= AD7124_ADC_CTRL_REF_EN(1); + return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, + 2, st->adc_control); + default: + dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel); + return -EINVAL; + } +} + +static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_config *cfg, + unsigned int cfg_slot) +{ + unsigned int tmp; + unsigned int val; + int ret; + + cfg->cfg_slot = cfg_slot; + + tmp = (cfg->buf_positive << 1) + cfg->buf_negative; + val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) | + AD7124_CONFIG_IN_BUFF(tmp); + ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val); + if (ret < 0) + return ret; + + tmp = AD7124_FILTER_TYPE_SEL(cfg->filter_type); + ret = ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_TYPE_MSK, + tmp, 3); + if (ret < 0) + return ret; + + ret = ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_FS_MSK, + AD7124_FILTER_FS(cfg->odr_sel_bits), 3); + if (ret < 0) + return ret; + + return ad7124_spi_write_mask(st, AD7124_CONFIG(cfg->cfg_slot), AD7124_CONFIG_PGA_MSK, + AD7124_CONFIG_PGA(cfg->pga_bits), 2); +} + +static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st) +{ + struct ad7124_channel_config *lru_cfg; + struct ad7124_channel_config *cfg; + int ret; + int i; + + /* + * Pop least recently used config from the fifo + * in order to make room for the new one + */ + ret = kfifo_get(&st->live_cfgs_fifo, &lru_cfg); + if (ret <= 0) + return NULL; + + lru_cfg->live = false; + + /* mark slot as free */ + assign_bit(lru_cfg->cfg_slot, &st->cfg_slots_status, 0); + + /* invalidate all other configs that pointed to this one */ + for (i = 0; i < st->num_channels; i++) { + cfg = &st->channels[i].cfg; + + if (cfg->cfg_slot == lru_cfg->cfg_slot) + cfg->live = false; + } + + return lru_cfg; +} + +static int ad7124_push_config(struct ad7124_state *st, struct ad7124_channel_config *cfg) +{ + struct ad7124_channel_config *lru_cfg; + int free_cfg_slot; + + free_cfg_slot = ad7124_find_free_config_slot(st); + if (free_cfg_slot >= 0) { + /* push the new config in configs queue */ + kfifo_put(&st->live_cfgs_fifo, cfg); + } else { + /* pop one config to make room for the new one */ + lru_cfg = ad7124_pop_config(st); + if (!lru_cfg) + return -EINVAL; + + /* push the new config in configs queue */ + free_cfg_slot = lru_cfg->cfg_slot; + kfifo_put(&st->live_cfgs_fifo, cfg); + } + + /* mark slot as used */ + assign_bit(free_cfg_slot, &st->cfg_slots_status, 1); + + return ad7124_write_config(st, cfg, free_cfg_slot); +} + +static int ad7124_enable_channel(struct ad7124_state *st, struct ad7124_channel *ch) +{ + ch->cfg.live = true; + return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(ch->nr), 2, ch->ain | + AD7124_CHANNEL_SETUP(ch->cfg.cfg_slot) | AD7124_CHANNEL_EN(1)); +} + +static int ad7124_prepare_read(struct ad7124_state *st, int address) +{ + struct ad7124_channel_config *cfg = &st->channels[address].cfg; + struct ad7124_channel_config *live_cfg; + + /* + * Before doing any reads assign the channel a configuration. + * Check if channel's config is on the device + */ + if (!cfg->live) { + /* check if config matches another one */ + live_cfg = ad7124_find_similar_live_cfg(st, cfg); + if (!live_cfg) + ad7124_push_config(st, cfg); + else + cfg->cfg_slot = live_cfg->cfg_slot; } - return ad7124_set_channel_odr(st, channel, new_odr); + /* point channel to the config slot and enable */ + return ad7124_enable_channel(st, &st->channels[address]); } +static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel) +{ + struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); + int ret; + + mutex_lock(&st->cfgs_lock); + ret = ad7124_prepare_read(st, channel); + mutex_unlock(&st->cfgs_lock); + + return ret; +} + +static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { + .set_channel = ad7124_set_channel, + .set_mode = ad7124_set_mode, + .has_registers = true, + .addr_shift = 0, + .read_mask = BIT(6), + .data_reg = AD7124_DATA, + .irq_flags = IRQF_TRIGGER_FALLING +}; + static int ad7124_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) @@ -378,36 +537,44 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, return ret; /* After the conversion is performed, disable the channel */ - ret = ad_sd_write_reg(&st->sd, - AD7124_CHANNEL(chan->address), 2, - st->channel_config[chan->address].ain | - AD7124_CHANNEL_EN(0)); + ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan->address), 2, + st->channels[chan->address].ain | AD7124_CHANNEL_EN(0)); if (ret < 0) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - idx = st->channel_config[chan->address].pga_bits; - *val = st->channel_config[chan->address].vref_mv; - if (st->channel_config[chan->address].bipolar) + mutex_lock(&st->cfgs_lock); + + idx = st->channels[chan->address].cfg.pga_bits; + *val = st->channels[chan->address].cfg.vref_mv; + if (st->channels[chan->address].cfg.bipolar) *val2 = chan->scan_type.realbits - 1 + idx; else *val2 = chan->scan_type.realbits + idx; + mutex_unlock(&st->cfgs_lock); return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: - if (st->channel_config[chan->address].bipolar) + mutex_lock(&st->cfgs_lock); + if (st->channels[chan->address].cfg.bipolar) *val = -(1 << (chan->scan_type.realbits - 1)); else *val = 0; + mutex_unlock(&st->cfgs_lock); return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - *val = st->channel_config[chan->address].odr; + mutex_lock(&st->cfgs_lock); + *val = st->channels[chan->address].cfg.odr; + mutex_unlock(&st->cfgs_lock); return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + mutex_lock(&st->cfgs_lock); *val = ad7124_get_3db_filter_freq(st, chan->scan_index); + mutex_unlock(&st->cfgs_lock); + return IIO_VAL_INT; default: return -EINVAL; @@ -420,35 +587,54 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, { struct ad7124_state *st = iio_priv(indio_dev); unsigned int res, gain, full_scale, vref; + int ret = 0; + + mutex_lock(&st->cfgs_lock); switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: - if (val2 != 0) - return -EINVAL; + if (val2 != 0) { + ret = -EINVAL; + break; + } - return ad7124_set_channel_odr(st, chan->address, val); + ad7124_set_channel_odr(st, chan->address, val); + break; case IIO_CHAN_INFO_SCALE: - if (val != 0) - return -EINVAL; + if (val != 0) { + ret = -EINVAL; + break; + } - if (st->channel_config[chan->address].bipolar) + if (st->channels[chan->address].cfg.bipolar) full_scale = 1 << (chan->scan_type.realbits - 1); else full_scale = 1 << chan->scan_type.realbits; - vref = st->channel_config[chan->address].vref_mv * 1000000LL; + vref = st->channels[chan->address].cfg.vref_mv * 1000000LL; res = DIV_ROUND_CLOSEST(vref, full_scale); gain = DIV_ROUND_CLOSEST(res, val2); + res = ad7124_find_closest_match(ad7124_gain, ARRAY_SIZE(ad7124_gain), gain); + + if (st->channels[chan->address].cfg.pga_bits != res) + st->channels[chan->address].cfg.live = false; - return ad7124_set_channel_gain(st, chan->address, gain); + st->channels[chan->address].cfg.pga_bits = res; + break; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - if (val2 != 0) - return -EINVAL; + if (val2 != 0) { + ret = -EINVAL; + break; + } - return ad7124_set_3db_filter_freq(st, chan->address, val); + ad7124_set_3db_filter_freq(st, chan->address, val); + break; default: - return -EINVAL; + ret = -EINVAL; } + + mutex_unlock(&st->cfgs_lock); + return ret; } static int ad7124_reg_access(struct iio_dev *indio_dev, @@ -547,47 +733,14 @@ static int ad7124_check_chip_id(struct ad7124_state *st) return 0; } -static int ad7124_init_channel_vref(struct ad7124_state *st, - unsigned int channel_number) -{ - unsigned int refsel = st->channel_config[channel_number].refsel; - - switch (refsel) { - case AD7124_REFIN1: - case AD7124_REFIN2: - case AD7124_AVDD_REF: - if (IS_ERR(st->vref[refsel])) { - dev_err(&st->sd.spi->dev, - "Error, trying to use external voltage reference without a %s regulator.\n", - ad7124_ref_names[refsel]); - return PTR_ERR(st->vref[refsel]); - } - st->channel_config[channel_number].vref_mv = - regulator_get_voltage(st->vref[refsel]); - /* Conversion from uV to mV */ - st->channel_config[channel_number].vref_mv /= 1000; - break; - case AD7124_INT_REF: - st->channel_config[channel_number].vref_mv = 2500; - st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK; - st->adc_control |= AD7124_ADC_CTRL_REF_EN(1); - return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, - 2, st->adc_control); - default: - dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel); - return -EINVAL; - } - - return 0; -} - static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, struct device_node *np) { struct ad7124_state *st = iio_priv(indio_dev); + struct ad7124_channel_config *cfg; + struct ad7124_channel *channels; struct device_node *child; struct iio_chan_spec *chan; - struct ad7124_channel_config *chan_config; unsigned int ain[2], channel = 0, tmp; int ret; @@ -602,16 +755,18 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, if (!chan) return -ENOMEM; - chan_config = devm_kcalloc(indio_dev->dev.parent, st->num_channels, - sizeof(*chan_config), GFP_KERNEL); - if (!chan_config) + channels = devm_kcalloc(indio_dev->dev.parent, st->num_channels, sizeof(*channels), + GFP_KERNEL); + if (!channels) return -ENOMEM; indio_dev->channels = chan; indio_dev->num_channels = st->num_channels; - st->channel_config = chan_config; + st->channels = channels; for_each_available_child_of_node(np, child) { + cfg = &st->channels[channel].cfg; + ret = of_property_read_u32(child, "reg", &channel); if (ret) goto err; @@ -621,21 +776,20 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, if (ret) goto err; - st->channel_config[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | + st->channels[channel].nr = channel; + st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | AD7124_CHANNEL_AINM(ain[1]); - st->channel_config[channel].bipolar = - of_property_read_bool(child, "bipolar"); + + cfg->bipolar = of_property_read_bool(child, "bipolar"); ret = of_property_read_u32(child, "adi,reference-select", &tmp); if (ret) - st->channel_config[channel].refsel = AD7124_INT_REF; + cfg->refsel = AD7124_INT_REF; else - st->channel_config[channel].refsel = tmp; + cfg->refsel = tmp; - st->channel_config[channel].buf_positive = - of_property_read_bool(child, "adi,buffered-positive"); - st->channel_config[channel].buf_negative = - of_property_read_bool(child, "adi,buffered-negative"); + cfg->buf_positive = of_property_read_bool(child, "adi,buffered-positive"); + cfg->buf_negative = of_property_read_bool(child, "adi,buffered-negative"); chan[channel] = ad7124_channel_template; chan[channel].address = channel; @@ -653,8 +807,8 @@ err: static int ad7124_setup(struct ad7124_state *st) { - unsigned int val, fclk, power_mode; - int i, ret, tmp; + unsigned int fclk, power_mode; + int i, ret; fclk = clk_get_rate(st->mclk); if (!fclk) @@ -677,31 +831,20 @@ static int ad7124_setup(struct ad7124_state *st) if (ret < 0) return ret; + mutex_init(&st->cfgs_lock); + INIT_KFIFO(st->live_cfgs_fifo); for (i = 0; i < st->num_channels; i++) { - val = st->channel_config[i].ain | AD7124_CHANNEL_SETUP(i); - ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(i), 2, val); - if (ret < 0) - return ret; - ret = ad7124_init_channel_vref(st, i); + ret = ad7124_init_config_vref(st, &st->channels[i].cfg); if (ret < 0) return ret; - tmp = (st->channel_config[i].buf_positive << 1) + - st->channel_config[i].buf_negative; - - val = AD7124_CONFIG_BIPOLAR(st->channel_config[i].bipolar) | - AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel) | - AD7124_CONFIG_IN_BUFF(tmp); - ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(i), 2, val); - if (ret < 0) - return ret; /* * 9.38 SPS is the minimum output data rate supported * regardless of the selected power mode. Round it up to 10 and - * set all the enabled channels to this default value. + * set all channels to this default value. */ - ret = ad7124_set_channel_odr(st, i, 10); + ad7124_set_channel_odr(st, i, 10); } return ret; diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index 70e33dd1c9f7247c27dea7c75f11d66fe8510223..3271a31afde1cc6a61591f6aa6bf176d7e6fcf09 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -260,7 +260,7 @@ static int ad7292_probe(struct spi_device *spi) struct ad7292_state *st; struct iio_dev *indio_dev; struct device_node *child; - bool diff_channels = 0; + bool diff_channels = false; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 689ecd5dd563e8d4365c22c3109125a0bc7a7cf8..d2163cb62f4f8abe3b605d212a754ab429db3140 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -142,12 +142,6 @@ static int ad7298_update_scan_mode(struct iio_dev *indio_dev, return 0; } -/* - * ad7298_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - */ static irqreturn_t ad7298_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 17402714b3876c8a72131a4462f9fe3f42b23bba..9e9ff07cf972bde7b8289fb1613e82a62470e2dd 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -321,25 +321,15 @@ static int ad7476_probe(struct spi_device *spi) spi_message_init(&st->msg); spi_message_add_tail(&st->xfer, &st->msg); - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ad7476_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + &ad7476_trigger_handler, NULL); if (ret) - goto error_disable_reg; + return ret; if (st->chip_info->reset) st->chip_info->reset(st); - ret = iio_device_register(indio_dev); - if (ret) - goto error_ring_unregister; - return 0; - -error_ring_unregister: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - regulator_disable(st->reg); - - return ret; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad7476_id[] = { diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index ee7b108688b33537095874e988c07905c63f56a2..0af0bb4d5a7fed86dde0472b367a45c0e040839e 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -668,7 +668,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return -ENOMEM; st->trig->ops = &ad7606_trigger_ops; - st->trig->dev.parent = dev; iio_trigger_set_drvdata(st->trig, indio_dev); ret = devm_iio_trigger_register(dev, st->trig); if (ret) diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c index b6b6765be7b49b25e9bea6603f73dbc62866fd9b..1e41759f3ee5d52da2c1d0402761cf30ab2dc777 100644 --- a/drivers/iio/adc/ad7766.c +++ b/drivers/iio/adc/ad7766.c @@ -253,21 +253,19 @@ static int ad7766_probe(struct spi_device *spi) return -ENOMEM; ad7766->trig->ops = &ad7766_trigger_ops; - ad7766->trig->dev.parent = &spi->dev; iio_trigger_set_drvdata(ad7766->trig, ad7766); - ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq, - IRQF_TRIGGER_FALLING, dev_name(&spi->dev), - ad7766->trig); - if (ret < 0) - return ret; - /* * The device generates interrupts as long as it is powered up. * Some platforms might not allow the option to power it down so - * disable the interrupt to avoid extra load on the system + * don't enable the interrupt to avoid extra load on the system */ - disable_irq(spi->irq); + ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq, + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, + dev_name(&spi->dev), + ad7766->trig); + if (ret < 0) + return ret; ret = devm_iio_trigger_register(&spi->dev, ad7766->trig); if (ret) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 5c0cbee032308376c395c3996bfea65eb8944e64..c945f1349623f7ad7f58069710ed02565f022af5 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -631,7 +631,6 @@ static int ad7768_probe(struct spi_device *spi) return -ENOMEM; st->trig->ops = &ad7768_trigger_ops; - st->trig->dev.parent = &spi->dev; iio_trigger_set_drvdata(st->trig, indio_dev); ret = devm_iio_trigger_register(&spi->dev, st->trig); if (ret) diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 4f6f0e0e03ee667401207d52e6443eb3e323838c..9b3cbe1ddc6f8660d52a56ad83618e90a43a6f23 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -109,12 +109,6 @@ static int ad7887_ring_postdisable(struct iio_dev *indio_dev) return spi_sync(st->spi, &st->msg[AD7887_CH0]); } -/* - * ad7887_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ static irqreturn_t ad7887_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index a2cc966580540734e15a7685b046dce8e2f1503b..9a649745cd0a81c2744722c9c6dba0b0118efef6 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -192,12 +192,6 @@ static int ad7923_update_scan_mode(struct iio_dev *indio_dev, return 0; } -/* - * ad7923_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - */ static irqreturn_t ad7923_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -293,6 +287,13 @@ static const struct iio_info ad7923_info = { .update_scan_mode = ad7923_update_scan_mode, }; +static void ad7923_regulator_disable(void *data) +{ + struct ad7923_state *st = data; + + regulator_disable(st->reg); +} + static int ad7923_probe(struct spi_device *spi) { struct ad7923_state *st; @@ -306,8 +307,6 @@ static int ad7923_probe(struct spi_device *spi) st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->spi = spi; st->settings = AD7923_CODING | AD7923_RANGE | AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS); @@ -340,35 +339,16 @@ static int ad7923_probe(struct spi_device *spi) if (ret) return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ad7923_trigger_handler, NULL); + ret = devm_add_action_or_reset(&spi->dev, ad7923_regulator_disable, st); if (ret) - goto error_disable_reg; + return ret; - ret = iio_device_register(indio_dev); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + &ad7923_trigger_handler, NULL); if (ret) - goto error_cleanup_ring; - - return 0; - -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - regulator_disable(st->reg); - - return ret; -} - -static int ad7923_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad7923_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - regulator_disable(st->reg); + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad7923_id[] = { @@ -401,7 +381,6 @@ static struct spi_driver ad7923_driver = { .of_match_table = ad7923_of_match, }, .probe = ad7923_probe, - .remove = ad7923_remove, .id_table = ad7923_id, }; module_spi_driver(ad7923_driver); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 1575b7670207873a3938ed29ae7421b68fdfb7f9..18bf8386d50afe8bc62afe63a600c878d7bbe203 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -182,12 +182,6 @@ static int ad799x_update_config(struct ad799x_state *st, u16 config) return 0; } -/* - * ad799x_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ static irqreturn_t ad799x_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 3a6f239d4acca345fe3984421a26867d6defca06..e777ec718973bae60e5c785d76ffd3f38911b5cd 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -475,8 +475,9 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); int ret; - sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, - indio_dev->id); + sigma_delta->trig = iio_trigger_alloc(&sigma_delta->spi->dev, + "%s-dev%d", indio_dev->name, + indio_dev->id); if (sigma_delta->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -484,19 +485,15 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) sigma_delta->trig->ops = &ad_sd_trigger_ops; init_completion(&sigma_delta->completion); + sigma_delta->irq_dis = true; ret = request_irq(sigma_delta->spi->irq, ad_sd_data_rdy_trig_poll, - sigma_delta->info->irq_flags, + sigma_delta->info->irq_flags | IRQF_NO_AUTOEN, indio_dev->name, sigma_delta); if (ret) goto error_free_trig; - if (!sigma_delta->irq_dis) { - sigma_delta->irq_dis = true; - disable_irq_nosync(sigma_delta->spi->irq); - } - sigma_delta->trig->dev.parent = &sigma_delta->spi->dev; iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta); ret = iio_trigger_register(sigma_delta->trig); diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 9109da2d2e15f154c1c8a1b65d1380cad2cb1ae8..d5f6ffc5b5bc3eb69687a5c67da497b0cff85bf1 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -23,7 +23,7 @@ #include <linux/fpga/adi-axi-common.h> #include <linux/iio/adc/adi-axi-adc.h> -/** +/* * Register definitions: * https://wiki.analog.com/resources/fpga/docs/axi_adc_ip#register_map */ @@ -104,7 +104,6 @@ static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st, static int adi_axi_adc_config_dma_buffer(struct device *dev, struct iio_dev *indio_dev) { - struct iio_buffer *buffer; const char *dma_name; if (!device_property_present(dev, "dmas")) @@ -113,15 +112,8 @@ static int adi_axi_adc_config_dma_buffer(struct device *dev, if (device_property_read_string(dev, "dma-names", &dma_name)) dma_name = "rx"; - buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, - dma_name); - if (IS_ERR(buffer)) - return PTR_ERR(buffer); - - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - iio_device_attach_buffer(indio_dev, buffer); - - return 0; + return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent, + indio_dev, dma_name); } static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 70750abb5dead77219a4f56a36e943360c6b9c30..0b5f0c91d0d734b8a27f8747b9f3e3e27ce88c44 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -625,12 +625,11 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, struct iio_trigger *trig; int ret; - trig = iio_trigger_alloc("%s-dev%d-%s", idev->name, + trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name, idev->id, trigger->name); if (trig == NULL) return NULL; - trig->dev.parent = idev->dev.parent; iio_trigger_set_drvdata(trig, idev); trig->ops = &at91_adc_trigger_ops; diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index f19c9aa93f179b3d6fca940ddf38c8e5a7067953..40e59f4c95bcdd32199e4984485e629c5cc6bd5a 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -100,7 +100,7 @@ struct cpcap_adc_ato { }; /** - * struct cpcap-adc - cpcap adc device driver data + * struct cpcap_adc - cpcap adc device driver data * @reg: cpcap regmap * @dev: struct device * @vendor: cpcap vendor diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 784c10deeb1a04ee374abe514a3a499794d58432..8c98d8c9ab1f8dc0cf8aa113897dc1cfcad8da1d 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -778,9 +778,9 @@ static int exynos_adc_ts_init(struct exynos_adc *info) return ret; } - disable_irq(info->tsirq); ret = request_threaded_irq(info->tsirq, NULL, exynos_ts_isr, - IRQF_ONESHOT, "touchscreen", info); + IRQF_ONESHOT | IRQF_NO_AUTOEN, + "touchscreen", info); if (ret) input_unregister_device(info->input); diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index b573ec60a8b8fea1d1773709b22f2318aecca1a6..2ae54258b2214860d95f6e6ebddf6b044105a207 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -953,7 +953,6 @@ static int ina2xx_probe(struct i2c_client *client, { struct ina2xx_chip_info *chip; struct iio_dev *indio_dev; - struct iio_buffer *buffer; unsigned int val; enum ina2xx_ids type; int ret; @@ -1017,7 +1016,7 @@ static int ina2xx_probe(struct i2c_client *client, return ret; } - indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + indio_dev->modes = INDIO_DIRECT_MODE; if (id->driver_data == ina226) { indio_dev->channels = ina226_channels; indio_dev->num_channels = ARRAY_SIZE(ina226_channels); @@ -1028,13 +1027,12 @@ static int ina2xx_probe(struct i2c_client *client, indio_dev->info = &ina219_info; } indio_dev->name = id->name; - indio_dev->setup_ops = &ina2xx_setup_ops; - buffer = devm_iio_kfifo_allocate(&indio_dev->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); + ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &ina2xx_setup_ops); + if (ret) + return ret; return iio_device_register(indio_dev); } diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index ca1dff3924ff9c8d93802297f299c280a38d922c..e3c8ec107722da41816f01c9add38e9c84d1f346 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -473,7 +473,6 @@ static int max1027_probe(struct spi_device *spi) } st->trig->ops = &max1027_trigger_ops; - st->trig->dev.parent = &spi->dev; iio_trigger_set_drvdata(st->trig, indio_dev); ret = devm_iio_trigger_register(&indio_dev->dev, st->trig); diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index f57db3056fbe4fb84f2133e89b328b878e173964..6b39a139ce286ba0472e613b337f773d343319a5 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -9,13 +9,14 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/regmap.h> -#include <linux/unaligned/be_byteshift.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <asm/unaligned.h> + #define MT6360_REG_PMUCHGCTRL3 0x313 #define MT6360_REG_PMUADCCFG 0x356 #define MT6360_REG_PMUADCIDLET 0x358 diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index 07c85434b56801d20afed2114e652d6f6e7ab6c1..bb70b51d25b13255911946295bb835e011c2c4c7 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -498,7 +498,8 @@ static int nau7802_probe(struct i2c_client *client, ret = request_threaded_irq(client->irq, NULL, nau7802_eoc_trigger, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | + IRQF_NO_AUTOEN, client->dev.driver->name, indio_dev); if (ret) { @@ -513,8 +514,7 @@ static int nau7802_probe(struct i2c_client *client, dev_info(&client->dev, "Failed to allocate IRQ, using polling mode\n"); client->irq = 0; - } else - disable_irq(client->irq); + } } if (!client->irq) { diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index d9d105920001e9747736a4a85b42f7b1273f7da5..f7bc0bb7f11249c154a7960268e6711ba409f7fd 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -25,6 +25,15 @@ struct npcm_adc { wait_queue_head_t wq; struct regulator *vref; struct reset_control *reset; + /* + * Lock to protect the device state during a potential concurrent + * read access from userspace. Reading a raw value requires a sequence + * of register writes, then a wait for a event and finally a register + * read, during which userspace could issue another read request. + * This lock protects a read access from ocurring before another one + * has finished. + */ + struct mutex lock; }; /* ADC registers */ @@ -135,9 +144,9 @@ static int npcm_adc_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); + mutex_lock(&info->lock); ret = npcm_adc_read(info, val, chan->channel); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&info->lock); if (ret) { dev_err(info->dev, "NPCM ADC read failed\n"); return ret; @@ -187,6 +196,8 @@ static int npcm_adc_probe(struct platform_device *pdev) return -ENOMEM; info = iio_priv(indio_dev); + mutex_init(&info->lock); + info->dev = &pdev->dev; info->regs = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 889b88768b630e6d61ba04334ad3af9965f76b6a..6ef09609be9fe442d75359438877de09c942e309 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -90,6 +90,12 @@ static struct palmas_gpadc_info palmas_gpadc_info[] = { * 3: 800 uA * @extended_delay: enable the gpadc extended delay mode * @auto_conversion_period: define the auto_conversion_period + * @lock: Lock to protect the device state during a potential concurrent + * read access from userspace. Reading a raw value requires a sequence + * of register writes, then a wait for a completion callback, + * and finally a register read, during which userspace could issue + * another read request. This lock protects a read access from + * ocurring before another one has finished. * * This is the palmas_gpadc structure to store run-time information * and pointers for this driver instance. @@ -110,6 +116,7 @@ struct palmas_gpadc { bool wakeup1_enable; bool wakeup2_enable; int auto_conversion_period; + struct mutex lock; }; /* @@ -388,7 +395,7 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, if (adc_chan > PALMAS_ADC_CH_MAX) return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(&adc->lock); switch (mask) { case IIO_CHAN_INFO_RAW: @@ -414,12 +421,12 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, goto out; } - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&adc->lock); return ret; out: palmas_gpadc_read_done(adc, adc_chan); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&adc->lock); return ret; } @@ -516,8 +523,11 @@ static int palmas_gpadc_probe(struct platform_device *pdev) adc->dev = &pdev->dev; adc->palmas = dev_get_drvdata(pdev->dev.parent); adc->adc_info = palmas_gpadc_info; + + mutex_init(&adc->lock); + init_completion(&adc->conv_completion); - dev_set_drvdata(&pdev->dev, indio_dev); + platform_set_drvdata(pdev, indio_dev); adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms; adc->irq = palmas_irq_get_virq(adc->palmas, PALMAS_GPADC_EOC_SW_IRQ); diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index 1bc986a7009d27edc18e05a3ff5e0c0f00a9d423..d93e580b3dc5b479cb0761c64c6a97a3891f0a63 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -75,6 +75,15 @@ struct spear_adc_state { struct adc_regs_spear6xx __iomem *adc_base_spear6xx; struct clk *clk; struct completion completion; + /* + * Lock to protect the device state during a potential concurrent + * read access from userspace. Reading a raw value requires a sequence + * of register writes, then a wait for a completion callback, + * and finally a register read, during which userspace could issue + * another read request. This lock protects a read access from + * ocurring before another one has finished. + */ + struct mutex lock; u32 current_clk; u32 sampling_freq; u32 avg_samples; @@ -146,7 +155,7 @@ static int spear_adc_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | @@ -159,7 +168,7 @@ static int spear_adc_read_raw(struct iio_dev *indio_dev, wait_for_completion(&st->completion); /* set by ISR */ *val = st->value; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return IIO_VAL_INT; @@ -187,7 +196,7 @@ static int spear_adc_write_raw(struct iio_dev *indio_dev, if (mask != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); if ((val < SPEAR_ADC_CLK_MIN) || (val > SPEAR_ADC_CLK_MAX) || @@ -199,7 +208,7 @@ static int spear_adc_write_raw(struct iio_dev *indio_dev, spear_adc_set_clk(st, val); out: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret; } @@ -271,6 +280,9 @@ static int spear_adc_probe(struct platform_device *pdev) } st = iio_priv(indio_dev); + + mutex_init(&st->lock); + st->np = np; /* diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index f7c53cea509a2460d9ebb2e862b4e6b022be6a7c..b25386b1937359b83afe0a4c33c470d2350aac58 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -177,7 +177,7 @@ struct stm32_adc_cfg { * @offset: ADC instance register offset in ADC block * @cfg: compatible configuration data * @completion: end of single conversion completion - * @buffer: data buffer + * @buffer: data buffer + 8 bytes for timestamp if enabled * @clk: clock for this adc instance * @irq: interrupt for this adc instance * @lock: spinlock @@ -200,7 +200,7 @@ struct stm32_adc { u32 offset; const struct stm32_adc_cfg *cfg; struct completion completion; - u16 buffer[STM32_ADC_MAX_SQ]; + u16 buffer[STM32_ADC_MAX_SQ + 4] __aligned(8); struct clk *clk; int irq; spinlock_t lock; /* interrupt lock */ @@ -1714,7 +1714,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, } } -static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) +static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) { struct device_node *node = indio_dev->dev.of_node; struct stm32_adc *adc = iio_priv(indio_dev); @@ -1762,6 +1762,9 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) return -EINVAL; } + if (timestamping) + num_channels++; + channels = devm_kcalloc(&indio_dev->dev, num_channels, sizeof(struct iio_chan_spec), GFP_KERNEL); if (!channels) @@ -1812,6 +1815,19 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) stm32_adc_smpr_init(adc, channels[i].channel, smp); } + if (timestamping) { + struct iio_chan_spec *timestamp = &channels[scan_index]; + + timestamp->type = IIO_TIMESTAMP; + timestamp->channel = -1; + timestamp->scan_index = scan_index; + timestamp->scan_type.sign = 's'; + timestamp->scan_type.realbits = 64; + timestamp->scan_type.storagebits = 64; + + scan_index++; + } + indio_dev->num_channels = scan_index; indio_dev->channels = channels; @@ -1871,6 +1887,7 @@ static int stm32_adc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; irqreturn_t (*handler)(int irq, void *p) = NULL; struct stm32_adc *adc; + bool timestamping = false; int ret; if (!pdev->dev.of_node) @@ -1927,16 +1944,22 @@ static int stm32_adc_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = stm32_adc_chan_of_init(indio_dev); - if (ret < 0) - return ret; - ret = stm32_adc_dma_request(dev, indio_dev); if (ret < 0) return ret; - if (!adc->dma_chan) + if (!adc->dma_chan) { + /* For PIO mode only, iio_pollfunc_store_time stores a timestamp + * in the primary trigger IRQ handler and stm32_adc_trigger_handler + * runs in the IRQ thread to push out buffer along with timestamp. + */ handler = &stm32_adc_trigger_handler; + timestamping = true; + } + + ret = stm32_adc_chan_of_init(indio_dev, timestamping); + if (ret < 0) + goto err_dma_disable; ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, handler, diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 9234f14167b7a2fb33635eb7f2802b8bbfa711fd..1cfefb3b5e56cd44018332cda266288e8e62c973 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -198,7 +198,7 @@ static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl, unsigned int p = fl->ford; /* filter order (ford) */ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fast]; - pr_debug("%s: Requested oversampling: %d\n", __func__, oversamp); + pr_debug("Requested oversampling: %d\n", oversamp); /* * This function tries to compute filter oversampling and integrator * oversampling, base on oversampling ratio requested by user. @@ -295,8 +295,8 @@ static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl, flo->max = (s32)max; flo->bits = bits; - pr_debug("%s: fast %d, fosr %d, iosr %d, res 0x%llx/%d bits, rshift %d, lshift %d\n", - __func__, fast, flo->fosr, flo->iosr, + pr_debug("fast %d, fosr %d, iosr %d, res 0x%llx/%d bits, rshift %d, lshift %d\n", + fast, flo->fosr, flo->iosr, flo->res, bits, flo->rshift, flo->lshift); } @@ -864,7 +864,7 @@ static void stm32_dfsdm_dma_buffer_done(void *data) * support in IIO. */ - dev_dbg(&indio_dev->dev, "%s: pos = %d, available = %d\n", __func__, + dev_dbg(&indio_dev->dev, "pos = %d, available = %d\n", adc->bufi, available); old_pos = adc->bufi; @@ -918,7 +918,7 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) if (!adc->dma_chan) return -EINVAL; - dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, + dev_dbg(&indio_dev->dev, "size=%d watermark=%d\n", adc->buf_sz, adc->buf_sz / 2); if (adc->nconv == 1 && !indio_dev->trig) diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 99b43f28e879ae8337e350cf73d965f53d2f1030..2d393a4dfff6a8665ef980768993dc59b0cf2780 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -470,7 +470,8 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name, } *irq = ret; - ret = devm_request_any_context_irq(&pdev->dev, *irq, handler, 0, + ret = devm_request_any_context_irq(&pdev->dev, *irq, handler, + IRQF_NO_AUTOEN, devname, info); if (ret < 0) { dev_err(&pdev->dev, "could not request %s interrupt: %d\n", @@ -478,7 +479,6 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name, return ret; } - disable_irq(*irq); atomic_set(atomic, 0); return 0; diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index fb14b92fa6e710c61be1e3c9a3aa462aad753ba4..33aea961d85088c38c89548ebdacaba29d7582af 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2017 Axis Communications AB * * Driver for Texas Instruments' ADC084S021 ADC chip. @@ -65,7 +65,7 @@ static const struct iio_chan_spec adc084s021_channels[] = { }; /** - * Read an ADC channel and return its value. + * adc084s021_adc_conversion() - Read an ADC channel and return its value. * * @adc: The ADC SPI data. * @data: Buffer for converted data. @@ -136,7 +136,7 @@ static int adc084s021_read_raw(struct iio_dev *indio_dev, } /** - * Read enabled ADC channels and push data to the buffer. + * adc084s021_buffer_trigger_handler() - Read ADC channels and push to buffer. * * @irq: The interrupt number (not used). * @pollfunc: Pointer to the poll func. diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c new file mode 100644 index 0000000000000000000000000000000000000000..764dab087b415c6e55b4d9ab31a32c696d356a07 --- /dev/null +++ b/drivers/iio/adc/ti-ads131e08.c @@ -0,0 +1,954 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments ADS131E0x 4-, 6- and 8-Channel ADCs + * + * Copyright (c) 2020 AVL DiTEST GmbH + * Tomislav Denis <tomislav.denis@avl.com> + * + * Datasheet: https://www.ti.com/lit/ds/symlink/ads131e08.pdf + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> + +#include <asm/unaligned.h> + +/* Commands */ +#define ADS131E08_CMD_RESET 0x06 +#define ADS131E08_CMD_START 0x08 +#define ADS131E08_CMD_STOP 0x0A +#define ADS131E08_CMD_OFFSETCAL 0x1A +#define ADS131E08_CMD_SDATAC 0x11 +#define ADS131E08_CMD_RDATA 0x12 +#define ADS131E08_CMD_RREG(r) (BIT(5) | (r & GENMASK(4, 0))) +#define ADS131E08_CMD_WREG(r) (BIT(6) | (r & GENMASK(4, 0))) + +/* Registers */ +#define ADS131E08_ADR_CFG1R 0x01 +#define ADS131E08_ADR_CFG3R 0x03 +#define ADS131E08_ADR_CH0R 0x05 + +/* Configuration register 1 */ +#define ADS131E08_CFG1R_DR_MASK GENMASK(2, 0) + +/* Configuration register 3 */ +#define ADS131E08_CFG3R_PDB_REFBUF_MASK BIT(7) +#define ADS131E08_CFG3R_VREF_4V_MASK BIT(5) + +/* Channel settings register */ +#define ADS131E08_CHR_GAIN_MASK GENMASK(6, 4) +#define ADS131E08_CHR_MUX_MASK GENMASK(2, 0) +#define ADS131E08_CHR_PWD_MASK BIT(7) + +/* ADC misc */ +#define ADS131E08_DEFAULT_DATA_RATE 1 +#define ADS131E08_DEFAULT_PGA_GAIN 1 +#define ADS131E08_DEFAULT_MUX 0 + +#define ADS131E08_VREF_2V4_mV 2400 +#define ADS131E08_VREF_4V_mV 4000 + +#define ADS131E08_WAIT_RESET_CYCLES 18 +#define ADS131E08_WAIT_SDECODE_CYCLES 4 +#define ADS131E08_WAIT_OFFSETCAL_MS 153 +#define ADS131E08_MAX_SETTLING_TIME_MS 6 + +#define ADS131E08_NUM_STATUS_BYTES 3 +#define ADS131E08_NUM_DATA_BYTES_MAX 24 +#define ADS131E08_NUM_DATA_BYTES(dr) (((dr) >= 32) ? 2 : 3) +#define ADS131E08_NUM_DATA_BITS(dr) (ADS131E08_NUM_DATA_BYTES(dr) * 8) +#define ADS131E08_NUM_STORAGE_BYTES 4 + +enum ads131e08_ids { + ads131e04, + ads131e06, + ads131e08, +}; + +struct ads131e08_info { + unsigned int max_channels; + const char *name; +}; + +struct ads131e08_channel_config { + unsigned int pga_gain; + unsigned int mux; +}; + +struct ads131e08_state { + const struct ads131e08_info *info; + struct spi_device *spi; + struct iio_trigger *trig; + struct clk *adc_clk; + struct regulator *vref_reg; + struct ads131e08_channel_config *channel_config; + unsigned int data_rate; + unsigned int vref_mv; + unsigned int sdecode_delay_us; + unsigned int reset_delay_us; + unsigned int readback_len; + struct completion completion; + struct { + u8 data[ADS131E08_NUM_DATA_BYTES_MAX]; + s64 ts __aligned(8); + } tmp_buf; + + u8 tx_buf[3] ____cacheline_aligned; + /* + * Add extra one padding byte to be able to access the last channel + * value using u32 pointer + */ + u8 rx_buf[ADS131E08_NUM_STATUS_BYTES + + ADS131E08_NUM_DATA_BYTES_MAX + 1]; +}; + +static const struct ads131e08_info ads131e08_info_tbl[] = { + [ads131e04] = { + .max_channels = 4, + .name = "ads131e04", + }, + [ads131e06] = { + .max_channels = 6, + .name = "ads131e06", + }, + [ads131e08] = { + .max_channels = 8, + .name = "ads131e08", + }, +}; + +struct ads131e08_data_rate_desc { + unsigned int rate; /* data rate in kSPS */ + u8 reg; /* reg value */ +}; + +static const struct ads131e08_data_rate_desc ads131e08_data_rate_tbl[] = { + { .rate = 64, .reg = 0x00 }, + { .rate = 32, .reg = 0x01 }, + { .rate = 16, .reg = 0x02 }, + { .rate = 8, .reg = 0x03 }, + { .rate = 4, .reg = 0x04 }, + { .rate = 2, .reg = 0x05 }, + { .rate = 1, .reg = 0x06 }, +}; + +struct ads131e08_pga_gain_desc { + unsigned int gain; /* PGA gain value */ + u8 reg; /* field value */ +}; + +static const struct ads131e08_pga_gain_desc ads131e08_pga_gain_tbl[] = { + { .gain = 1, .reg = 0x01 }, + { .gain = 2, .reg = 0x02 }, + { .gain = 4, .reg = 0x04 }, + { .gain = 8, .reg = 0x05 }, + { .gain = 12, .reg = 0x06 }, +}; + +static const u8 ads131e08_valid_channel_mux_values[] = { 0, 1, 3, 4 }; + +static int ads131e08_exec_cmd(struct ads131e08_state *st, u8 cmd) +{ + int ret; + + ret = spi_write_then_read(st->spi, &cmd, 1, NULL, 0); + if (ret) + dev_err(&st->spi->dev, "Exec cmd(%02x) failed\n", cmd); + + return ret; +} + +static int ads131e08_read_reg(struct ads131e08_state *st, u8 reg) +{ + int ret; + struct spi_transfer transfer[] = { + { + .tx_buf = &st->tx_buf, + .len = 2, + .delay = { + .value = st->sdecode_delay_us, + .unit = SPI_DELAY_UNIT_USECS, + }, + }, { + .rx_buf = &st->rx_buf, + .len = 1, + }, + }; + + st->tx_buf[0] = ADS131E08_CMD_RREG(reg); + st->tx_buf[1] = 0; + + ret = spi_sync_transfer(st->spi, transfer, ARRAY_SIZE(transfer)); + if (ret) { + dev_err(&st->spi->dev, "Read register failed\n"); + return ret; + } + + return st->rx_buf[0]; +} + +static int ads131e08_write_reg(struct ads131e08_state *st, u8 reg, u8 value) +{ + int ret; + struct spi_transfer transfer[] = { + { + .tx_buf = &st->tx_buf, + .len = 3, + .delay = { + .value = st->sdecode_delay_us, + .unit = SPI_DELAY_UNIT_USECS, + }, + } + }; + + st->tx_buf[0] = ADS131E08_CMD_WREG(reg); + st->tx_buf[1] = 0; + st->tx_buf[2] = value; + + ret = spi_sync_transfer(st->spi, transfer, ARRAY_SIZE(transfer)); + if (ret) + dev_err(&st->spi->dev, "Write register failed\n"); + + return ret; +} + +static int ads131e08_read_data(struct ads131e08_state *st, int rx_len) +{ + int ret; + struct spi_transfer transfer[] = { + { + .tx_buf = &st->tx_buf, + .len = 1, + }, { + .rx_buf = &st->rx_buf, + .len = rx_len, + }, + }; + + st->tx_buf[0] = ADS131E08_CMD_RDATA; + + ret = spi_sync_transfer(st->spi, transfer, ARRAY_SIZE(transfer)); + if (ret) + dev_err(&st->spi->dev, "Read data failed\n"); + + return ret; +} + +static int ads131e08_set_data_rate(struct ads131e08_state *st, int data_rate) +{ + int i, reg, ret; + + for (i = 0; i < ARRAY_SIZE(ads131e08_data_rate_tbl); i++) { + if (ads131e08_data_rate_tbl[i].rate == data_rate) + break; + } + + if (i == ARRAY_SIZE(ads131e08_data_rate_tbl)) { + dev_err(&st->spi->dev, "invalid data rate value\n"); + return -EINVAL; + } + + reg = ads131e08_read_reg(st, ADS131E08_ADR_CFG1R); + if (reg < 0) + return reg; + + reg &= ~ADS131E08_CFG1R_DR_MASK; + reg |= FIELD_PREP(ADS131E08_CFG1R_DR_MASK, + ads131e08_data_rate_tbl[i].reg); + + ret = ads131e08_write_reg(st, ADS131E08_ADR_CFG1R, reg); + if (ret) + return ret; + + st->data_rate = data_rate; + st->readback_len = ADS131E08_NUM_STATUS_BYTES + + ADS131E08_NUM_DATA_BYTES(st->data_rate) * + st->info->max_channels; + + return 0; +} + +static int ads131e08_pga_gain_to_field_value(struct ads131e08_state *st, + unsigned int pga_gain) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ads131e08_pga_gain_tbl); i++) { + if (ads131e08_pga_gain_tbl[i].gain == pga_gain) + break; + } + + if (i == ARRAY_SIZE(ads131e08_pga_gain_tbl)) { + dev_err(&st->spi->dev, "invalid PGA gain value\n"); + return -EINVAL; + } + + return ads131e08_pga_gain_tbl[i].reg; +} + +static int ads131e08_set_pga_gain(struct ads131e08_state *st, + unsigned int channel, unsigned int pga_gain) +{ + int field_value, reg; + + field_value = ads131e08_pga_gain_to_field_value(st, pga_gain); + if (field_value < 0) + return field_value; + + reg = ads131e08_read_reg(st, ADS131E08_ADR_CH0R + channel); + if (reg < 0) + return reg; + + reg &= ~ADS131E08_CHR_GAIN_MASK; + reg |= FIELD_PREP(ADS131E08_CHR_GAIN_MASK, field_value); + + return ads131e08_write_reg(st, ADS131E08_ADR_CH0R + channel, reg); +} + +static int ads131e08_validate_channel_mux(struct ads131e08_state *st, + unsigned int mux) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ads131e08_valid_channel_mux_values); i++) { + if (ads131e08_valid_channel_mux_values[i] == mux) + break; + } + + if (i == ARRAY_SIZE(ads131e08_valid_channel_mux_values)) { + dev_err(&st->spi->dev, "invalid channel mux value\n"); + return -EINVAL; + } + + return 0; +} + +static int ads131e08_set_channel_mux(struct ads131e08_state *st, + unsigned int channel, unsigned int mux) +{ + int reg; + + reg = ads131e08_read_reg(st, ADS131E08_ADR_CH0R + channel); + if (reg < 0) + return reg; + + reg &= ~ADS131E08_CHR_MUX_MASK; + reg |= FIELD_PREP(ADS131E08_CHR_MUX_MASK, mux); + + return ads131e08_write_reg(st, ADS131E08_ADR_CH0R + channel, reg); +} + +static int ads131e08_power_down_channel(struct ads131e08_state *st, + unsigned int channel, bool value) +{ + int reg; + + reg = ads131e08_read_reg(st, ADS131E08_ADR_CH0R + channel); + if (reg < 0) + return reg; + + reg &= ~ADS131E08_CHR_PWD_MASK; + reg |= FIELD_PREP(ADS131E08_CHR_PWD_MASK, value); + + return ads131e08_write_reg(st, ADS131E08_ADR_CH0R + channel, reg); +} + +static int ads131e08_config_reference_voltage(struct ads131e08_state *st) +{ + int reg; + + reg = ads131e08_read_reg(st, ADS131E08_ADR_CFG3R); + if (reg < 0) + return reg; + + reg &= ~ADS131E08_CFG3R_PDB_REFBUF_MASK; + if (!st->vref_reg) { + reg |= FIELD_PREP(ADS131E08_CFG3R_PDB_REFBUF_MASK, 1); + reg &= ~ADS131E08_CFG3R_VREF_4V_MASK; + reg |= FIELD_PREP(ADS131E08_CFG3R_VREF_4V_MASK, + st->vref_mv == ADS131E08_VREF_4V_mV); + } + + return ads131e08_write_reg(st, ADS131E08_ADR_CFG3R, reg); +} + +static int ads131e08_initial_config(struct iio_dev *indio_dev) +{ + const struct iio_chan_spec *channel = indio_dev->channels; + struct ads131e08_state *st = iio_priv(indio_dev); + unsigned long active_channels = 0; + int ret, i; + + ret = ads131e08_exec_cmd(st, ADS131E08_CMD_RESET); + if (ret) + return ret; + + udelay(st->reset_delay_us); + + /* Disable read data in continuous mode (enabled by default) */ + ret = ads131e08_exec_cmd(st, ADS131E08_CMD_SDATAC); + if (ret) + return ret; + + ret = ads131e08_set_data_rate(st, ADS131E08_DEFAULT_DATA_RATE); + if (ret) + return ret; + + ret = ads131e08_config_reference_voltage(st); + if (ret) + return ret; + + for (i = 0; i < indio_dev->num_channels; i++) { + ret = ads131e08_set_pga_gain(st, channel->channel, + st->channel_config[i].pga_gain); + if (ret) + return ret; + + ret = ads131e08_set_channel_mux(st, channel->channel, + st->channel_config[i].mux); + if (ret) + return ret; + + active_channels |= BIT(channel->channel); + channel++; + } + + /* Power down unused channels */ + for_each_clear_bit(i, &active_channels, st->info->max_channels) { + ret = ads131e08_power_down_channel(st, i, true); + if (ret) + return ret; + } + + /* Request channel offset calibration */ + ret = ads131e08_exec_cmd(st, ADS131E08_CMD_OFFSETCAL); + if (ret) + return ret; + + /* + * Channel offset calibration is triggered with the first START + * command. Since calibration takes more time than settling operation, + * this causes timeout error when command START is sent first + * time (e.g. first call of the ads131e08_read_direct method). + * To avoid this problem offset calibration is triggered here. + */ + ret = ads131e08_exec_cmd(st, ADS131E08_CMD_START); + if (ret) + return ret; + + msleep(ADS131E08_WAIT_OFFSETCAL_MS); + + return ads131e08_exec_cmd(st, ADS131E08_CMD_STOP); +} + +static int ads131e08_pool_data(struct ads131e08_state *st) +{ + unsigned long timeout; + int ret; + + reinit_completion(&st->completion); + + ret = ads131e08_exec_cmd(st, ADS131E08_CMD_START); + if (ret) + return ret; + + timeout = msecs_to_jiffies(ADS131E08_MAX_SETTLING_TIME_MS); + ret = wait_for_completion_timeout(&st->completion, timeout); + if (!ret) + return -ETIMEDOUT; + + ret = ads131e08_read_data(st, st->readback_len); + if (ret) + return ret; + + return ads131e08_exec_cmd(st, ADS131E08_CMD_STOP); +} + +static int ads131e08_read_direct(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *value) +{ + struct ads131e08_state *st = iio_priv(indio_dev); + u8 num_bits, *src; + int ret; + + ret = ads131e08_pool_data(st); + if (ret) + return ret; + + src = st->rx_buf + ADS131E08_NUM_STATUS_BYTES + + channel->channel * ADS131E08_NUM_DATA_BYTES(st->data_rate); + + num_bits = ADS131E08_NUM_DATA_BITS(st->data_rate); + *value = sign_extend32(get_unaligned_be32(src) >> (32 - num_bits), num_bits - 1); + + return 0; +} + +static int ads131e08_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *value, + int *value2, long mask) +{ + struct ads131e08_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = ads131e08_read_direct(indio_dev, channel, value); + iio_device_release_direct_mode(indio_dev); + if (ret) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + if (st->vref_reg) { + ret = regulator_get_voltage(st->vref_reg); + if (ret < 0) + return ret; + + *value = ret / 1000; + } else { + *value = st->vref_mv; + } + + *value /= st->channel_config[channel->address].pga_gain; + *value2 = ADS131E08_NUM_DATA_BITS(st->data_rate) - 1; + + return IIO_VAL_FRACTIONAL_LOG2; + + case IIO_CHAN_INFO_SAMP_FREQ: + *value = st->data_rate; + + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int ads131e08_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int value, + int value2, long mask) +{ + struct ads131e08_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = ads131e08_set_data_rate(st, value); + iio_device_release_direct_mode(indio_dev); + return ret; + + default: + return -EINVAL; + } +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1 2 4 8 16 32 64"); + +static struct attribute *ads131e08_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group ads131e08_attribute_group = { + .attrs = ads131e08_attributes, +}; + +static int ads131e08_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, unsigned int *readval) +{ + struct ads131e08_state *st = iio_priv(indio_dev); + + if (readval) { + int ret = ads131e08_read_reg(st, reg); + *readval = ret; + return ret; + } + + return ads131e08_write_reg(st, reg, writeval); +} + +static const struct iio_info ads131e08_iio_info = { + .read_raw = ads131e08_read_raw, + .write_raw = ads131e08_write_raw, + .attrs = &ads131e08_attribute_group, + .debugfs_reg_access = &ads131e08_debugfs_reg_access, +}; + +static int ads131e08_set_trigger_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct ads131e08_state *st = iio_priv(indio_dev); + u8 cmd = state ? ADS131E08_CMD_START : ADS131E08_CMD_STOP; + + return ads131e08_exec_cmd(st, cmd); +} + +static const struct iio_trigger_ops ads131e08_trigger_ops = { + .set_trigger_state = &ads131e08_set_trigger_state, + .validate_device = &iio_trigger_validate_own_device, +}; + +static irqreturn_t ads131e08_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct ads131e08_state *st = iio_priv(indio_dev); + unsigned int chn, i = 0; + u8 *src, *dest; + int ret; + + /* + * The number of data bits per channel depends on the data rate. + * For 32 and 64 ksps data rates, number of data bits per channel + * is 16. This case is not compliant with used (fixed) scan element + * type (be:s24/32>>8). So we use a little tweak to pack properly + * 16 bits of data into the buffer. + */ + unsigned int num_bytes = ADS131E08_NUM_DATA_BYTES(st->data_rate); + u8 tweek_offset = num_bytes == 2 ? 1 : 0; + + if (iio_trigger_using_own(indio_dev)) + ret = ads131e08_read_data(st, st->readback_len); + else + ret = ads131e08_pool_data(st); + + if (ret) + goto out; + + for_each_set_bit(chn, indio_dev->active_scan_mask, indio_dev->masklength) { + src = st->rx_buf + ADS131E08_NUM_STATUS_BYTES + chn * num_bytes; + dest = st->tmp_buf.data + i * ADS131E08_NUM_STORAGE_BYTES; + + /* + * Tweek offset is 0: + * +---+---+---+---+ + * |D0 |D1 |D2 | X | (3 data bytes) + * +---+---+---+---+ + * a+0 a+1 a+2 a+3 + * + * Tweek offset is 1: + * +---+---+---+---+ + * |P0 |D0 |D1 | X | (one padding byte and 2 data bytes) + * +---+---+---+---+ + * a+0 a+1 a+2 a+3 + */ + memcpy(dest + tweek_offset, src, num_bytes); + + /* + * Data conversion from 16 bits of data to 24 bits of data + * is done by sign extension (properly filling padding byte). + */ + if (tweek_offset) + *dest = *src & BIT(7) ? 0xff : 0x00; + + i++; + } + + iio_push_to_buffers_with_timestamp(indio_dev, st->tmp_buf.data, + iio_get_time_ns(indio_dev)); + +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static irqreturn_t ads131e08_interrupt(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ads131e08_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) + iio_trigger_poll(st->trig); + else + complete(&st->completion); + + return IRQ_HANDLED; +} + +static int ads131e08_alloc_channels(struct iio_dev *indio_dev) +{ + struct ads131e08_state *st = iio_priv(indio_dev); + struct ads131e08_channel_config *channel_config; + struct device *dev = &st->spi->dev; + struct iio_chan_spec *channels; + struct fwnode_handle *node; + unsigned int channel, tmp; + int num_channels, i, ret; + + ret = device_property_read_u32(dev, "ti,vref-internal", &tmp); + if (ret) + tmp = 0; + + switch (tmp) { + case 0: + st->vref_mv = ADS131E08_VREF_2V4_mV; + break; + case 1: + st->vref_mv = ADS131E08_VREF_4V_mV; + break; + default: + dev_err(&st->spi->dev, "invalid internal voltage reference\n"); + return -EINVAL; + } + + num_channels = device_get_child_node_count(dev); + if (num_channels == 0) { + dev_err(&st->spi->dev, "no channel children\n"); + return -ENODEV; + } + + if (num_channels > st->info->max_channels) { + dev_err(&st->spi->dev, "num of channel children out of range\n"); + return -EINVAL; + } + + channels = devm_kcalloc(&st->spi->dev, num_channels, + sizeof(*channels), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + channel_config = devm_kcalloc(&st->spi->dev, num_channels, + sizeof(*channel_config), GFP_KERNEL); + if (!channel_config) + return -ENOMEM; + + i = 0; + device_for_each_child_node(dev, node) { + ret = fwnode_property_read_u32(node, "reg", &channel); + if (ret) + return ret; + + ret = fwnode_property_read_u32(node, "ti,gain", &tmp); + if (ret) { + channel_config[i].pga_gain = ADS131E08_DEFAULT_PGA_GAIN; + } else { + ret = ads131e08_pga_gain_to_field_value(st, tmp); + if (ret < 0) + return ret; + + channel_config[i].pga_gain = tmp; + } + + ret = fwnode_property_read_u32(node, "ti,mux", &tmp); + if (ret) { + channel_config[i].mux = ADS131E08_DEFAULT_MUX; + } else { + ret = ads131e08_validate_channel_mux(st, tmp); + if (ret) + return ret; + + channel_config[i].mux = tmp; + } + + channels[i].type = IIO_VOLTAGE; + channels[i].indexed = 1; + channels[i].channel = channel; + channels[i].address = i; + channels[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE); + channels[i].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ); + channels[i].scan_index = channel; + channels[i].scan_type.sign = 's'; + channels[i].scan_type.realbits = 24; + channels[i].scan_type.storagebits = 32; + channels[i].scan_type.shift = 8; + channels[i].scan_type.endianness = IIO_BE; + i++; + } + + indio_dev->channels = channels; + indio_dev->num_channels = num_channels; + st->channel_config = channel_config; + + return 0; +} + +static void ads131e08_regulator_disable(void *data) +{ + struct ads131e08_state *st = data; + + regulator_disable(st->vref_reg); +} + +static void ads131e08_clk_disable(void *data) +{ + struct ads131e08_state *st = data; + + clk_disable_unprepare(st->adc_clk); +} + +static int ads131e08_probe(struct spi_device *spi) +{ + const struct ads131e08_info *info; + struct ads131e08_state *st; + struct iio_dev *indio_dev; + unsigned long adc_clk_hz; + unsigned long adc_clk_ns; + int ret; + + info = device_get_match_data(&spi->dev); + if (!info) { + dev_err(&spi->dev, "failed to get match data\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) { + dev_err(&spi->dev, "failed to allocate IIO device\n"); + return -ENOMEM; + } + + st = iio_priv(indio_dev); + st->info = info; + st->spi = spi; + + ret = ads131e08_alloc_channels(indio_dev); + if (ret) + return ret; + + indio_dev->name = st->info->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &ads131e08_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + init_completion(&st->completion); + + if (spi->irq) { + ret = devm_request_irq(&spi->dev, spi->irq, + ads131e08_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + spi->dev.driver->name, indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "request irq failed\n"); + } else { + dev_err(&spi->dev, "data ready IRQ missing\n"); + return -ENODEV; + } + + st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!st->trig) { + dev_err(&spi->dev, "failed to allocate IIO trigger\n"); + return -ENOMEM; + } + + st->trig->ops = &ads131e08_trigger_ops; + st->trig->dev.parent = &spi->dev; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(&spi->dev, st->trig); + if (ret) { + dev_err(&spi->dev, "failed to register IIO trigger\n"); + return -ENOMEM; + } + + indio_dev->trig = iio_trigger_get(st->trig); + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + NULL, &ads131e08_trigger_handler, NULL); + if (ret) { + dev_err(&spi->dev, "failed to setup IIO buffer\n"); + return ret; + } + + 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 external vref supply\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, ads131e08_regulator_disable, st); + if (ret) + return ret; + } else { + if (PTR_ERR(st->vref_reg) != -ENODEV) + return PTR_ERR(st->vref_reg); + + st->vref_reg = NULL; + } + + st->adc_clk = devm_clk_get(&spi->dev, "adc-clk"); + if (IS_ERR(st->adc_clk)) + return dev_err_probe(&spi->dev, PTR_ERR(st->adc_clk), + "failed to get the ADC clock\n"); + + ret = clk_prepare_enable(st->adc_clk); + if (ret) { + dev_err(&spi->dev, "failed to prepare/enable the ADC clock\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, ads131e08_clk_disable, st); + if (ret) + return ret; + + adc_clk_hz = clk_get_rate(st->adc_clk); + if (!adc_clk_hz) { + dev_err(&spi->dev, "failed to get the ADC clock rate\n"); + return -EINVAL; + } + + adc_clk_ns = NSEC_PER_SEC / adc_clk_hz; + st->sdecode_delay_us = DIV_ROUND_UP( + ADS131E08_WAIT_SDECODE_CYCLES * adc_clk_ns, NSEC_PER_USEC); + st->reset_delay_us = DIV_ROUND_UP( + ADS131E08_WAIT_RESET_CYCLES * adc_clk_ns, NSEC_PER_USEC); + + ret = ads131e08_initial_config(indio_dev); + if (ret) { + dev_err(&spi->dev, "initial configuration failed\n"); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ads131e08_of_match[] = { + { .compatible = "ti,ads131e04", + .data = &ads131e08_info_tbl[ads131e04], }, + { .compatible = "ti,ads131e06", + .data = &ads131e08_info_tbl[ads131e06], }, + { .compatible = "ti,ads131e08", + .data = &ads131e08_info_tbl[ads131e08], }, + {} +}; +MODULE_DEVICE_TABLE(of, ads131e08_of_match); + +static struct spi_driver ads131e08_driver = { + .driver = { + .name = "ads131e08", + .of_match_table = ads131e08_of_match, + }, + .probe = ads131e08_probe, +}; +module_spi_driver(ads131e08_driver); + +MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>"); +MODULE_DESCRIPTION("Driver for ADS131E0x ADC family"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index e946903b099367b02faafbc46e5e15da646071ba..855cc2d64ac8ecf3c92cdcb5bbdf98396c3e0d8e 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -385,24 +385,16 @@ static int tiadc_iio_buffered_hardware_setup(struct device *dev, unsigned long flags, const struct iio_buffer_setup_ops *setup_ops) { - struct iio_buffer *buffer; int ret; - buffer = devm_iio_kfifo_allocate(dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - - ret = devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh, - flags, indio_dev->name, indio_dev); + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + setup_ops); if (ret) return ret; - indio_dev->setup_ops = setup_ops; - indio_dev->modes |= INDIO_BUFFER_SOFTWARE; - - return 0; + return devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh, + flags, indio_dev->name, indio_dev); } static const char * const chan_name_ain[] = { diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 34800dccbf698bff2edbd52a150215bbb2bdba2f..6914c1900ed0bf3609f5a898062fa58270beb9d1 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -747,7 +747,6 @@ static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, if (trig == NULL) return ERR_PTR(-ENOMEM); - trig->dev.parent = indio_dev->dev.parent; trig->ops = &xadc_trigger_ops; iio_trigger_set_drvdata(trig, iio_priv(indio_dev)); diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index b0cb9a35f5cd0c22f62e325304351cdf30902a82..d76179878ff95045b97dbe876bd4002cce455dac 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -132,9 +132,9 @@ static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = { static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; struct dmaengine_buffer *dmaengine_buffer = - iio_buffer_to_dmaengine_buffer(indio_dev->buffer); + iio_buffer_to_dmaengine_buffer(buffer); return sprintf(buf, "%zu\n", dmaengine_buffer->align); } @@ -244,7 +244,7 @@ static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res) * * The buffer will be automatically de-allocated once the device gets destroyed. */ -struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, +static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, const char *channel) { struct iio_buffer **bufferp, *buffer; @@ -265,7 +265,34 @@ struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, return buffer; } -EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_alloc); + +/** + * devm_iio_dmaengine_buffer_setup() - Setup a DMA buffer for an IIO device + * @dev: Parent device for the buffer + * @indio_dev: IIO device to which to attach this buffer. + * @channel: DMA channel name, typically "rx". + * + * This allocates a new IIO buffer with devm_iio_dmaengine_buffer_alloc() + * and attaches it to an IIO device with iio_device_attach_buffer(). + * It also appends the INDIO_BUFFER_HARDWARE mode to the supported modes of the + * IIO device. + */ +int devm_iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel) +{ + struct iio_buffer *buffer; + + buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, + channel); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + + return iio_device_attach_buffer(indio_dev, buffer); +} +EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index 92b8aea3e0634aef4d5e858cd3baf84afd9afdaa..b2b1b7d27af4234b9cd89aa5b0eb72863766f464 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -50,8 +50,6 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev, goto error_ret; } - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->pollfunc = iio_alloc_pollfunc(h, thread, IRQF_ONESHOT, @@ -72,10 +70,16 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev, buffer->attrs = buffer_attrs; + ret = iio_device_attach_buffer(indio_dev, buffer); + if (ret < 0) + goto error_dealloc_pollfunc; + return 0; +error_dealloc_pollfunc: + iio_dealloc_pollfunc(indio_dev->pollfunc); error_kfifo_free: - iio_kfifo_free(indio_dev->buffer); + iio_kfifo_free(buffer); error_ret: return ret; } diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 1359abed3b31e173d26ce48b6b9ec5e923c5e981..516eb3465de164c6316e166e83a98d6fb3c40a8a 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -180,13 +180,13 @@ static void devm_iio_kfifo_release(struct device *dev, void *res) } /** - * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate() + * devm_iio_kfifo_allocate - Resource-managed iio_kfifo_allocate() * @dev: Device to allocate kfifo buffer for * * RETURNS: * Pointer to allocated iio_buffer on success, NULL on failure. */ -struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) +static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) { struct iio_buffer **ptr, *r; @@ -204,6 +204,45 @@ struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) return r; } -EXPORT_SYMBOL(devm_iio_kfifo_allocate); + +/** + * devm_iio_kfifo_buffer_setup_ext - Allocate a kfifo buffer & attach it to an IIO device + * @dev: Device object to which to attach the life-time of this kfifo buffer + * @indio_dev: The device the buffer should be attached to + * @mode_flags: The mode flags for this buffer (INDIO_BUFFER_SOFTWARE and/or + * INDIO_BUFFER_TRIGGERED). + * @setup_ops: The setup_ops required to configure the HW part of the buffer (optional) + * @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer + * + * This function allocates a kfifo buffer via devm_iio_kfifo_allocate() and + * attaches it to the IIO device via iio_device_attach_buffer(). + * This is meant to be a bit of a short-hand/helper function as there are a few + * drivers that seem to do this. + */ +int devm_iio_kfifo_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + int mode_flags, + const struct iio_buffer_setup_ops *setup_ops, + const struct attribute **buffer_attrs) +{ + struct iio_buffer *buffer; + + if (!mode_flags) + return -EINVAL; + + buffer = devm_iio_kfifo_allocate(dev); + if (!buffer) + return -ENOMEM; + + mode_flags &= kfifo_access_funcs.modes; + + indio_dev->modes |= mode_flags; + indio_dev->setup_ops = setup_ops; + + buffer->attrs = buffer_attrs; + + return iio_device_attach_buffer(indio_dev, buffer); +} +EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup_ext); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/cdc/Kconfig b/drivers/iio/cdc/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..5e3319a3ff48e5a6e7d3d71475e1a2b46efb9f7e --- /dev/null +++ b/drivers/iio/cdc/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# CDC drivers +# +menu "Capacitance to digital converters" + +config AD7150 + tristate "Analog Devices ad7150/1/6 capacitive sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices capacitive sensors. + (ad7150, ad7151, ad7156) Provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad7150. + +endmenu diff --git a/drivers/iio/cdc/Makefile b/drivers/iio/cdc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ee490637b032516094622cc98464ab6e07e72003 --- /dev/null +++ b/drivers/iio/cdc/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for industrial I/O capacitance to digital converter (CDC) drivers +# + +obj-$(CONFIG_AD7150) += ad7150.o diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c new file mode 100644 index 0000000000000000000000000000000000000000..ebe112b4618b049f922d78941e84790c09aa576d --- /dev/null +++ b/drivers/iio/cdc/ad7150.c @@ -0,0 +1,673 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AD7150 capacitive sensor driver supporting AD7150/1/6 + * + * Copyright 2010-2011 Analog Devices Inc. + * Copyright 2021 Jonathan Cameron <Jonathan.Cameron@huawei.com> + */ + +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> + +#define AD7150_STATUS_REG 0 +#define AD7150_STATUS_OUT1 BIT(3) +#define AD7150_STATUS_OUT2 BIT(5) +#define AD7150_CH1_DATA_HIGH_REG 1 +#define AD7150_CH2_DATA_HIGH_REG 3 +#define AD7150_CH1_AVG_HIGH_REG 5 +#define AD7150_CH2_AVG_HIGH_REG 7 +#define AD7150_CH1_SENSITIVITY_REG 9 +#define AD7150_CH1_THR_HOLD_H_REG 9 +#define AD7150_CH1_TIMEOUT_REG 10 +#define AD7150_CH_TIMEOUT_RECEDING GENMASK(3, 0) +#define AD7150_CH_TIMEOUT_APPROACHING GENMASK(7, 4) +#define AD7150_CH1_SETUP_REG 11 +#define AD7150_CH2_SENSITIVITY_REG 12 +#define AD7150_CH2_THR_HOLD_H_REG 12 +#define AD7150_CH2_TIMEOUT_REG 13 +#define AD7150_CH2_SETUP_REG 14 +#define AD7150_CFG_REG 15 +#define AD7150_CFG_FIX BIT(7) +#define AD7150_CFG_THRESHTYPE_MSK GENMASK(6, 5) +#define AD7150_CFG_TT_NEG 0x0 +#define AD7150_CFG_TT_POS 0x1 +#define AD7150_CFG_TT_IN_WINDOW 0x2 +#define AD7150_CFG_TT_OUT_WINDOW 0x3 +#define AD7150_PD_TIMER_REG 16 +#define AD7150_CH1_CAPDAC_REG 17 +#define AD7150_CH2_CAPDAC_REG 18 +#define AD7150_SN3_REG 19 +#define AD7150_SN2_REG 20 +#define AD7150_SN1_REG 21 +#define AD7150_SN0_REG 22 +#define AD7150_ID_REG 23 + +enum { + AD7150, + AD7151, +}; + +/** + * struct ad7150_chip_info - instance specific chip data + * @client: i2c client for this device + * @threshold: thresholds for simple capacitance value events + * @thresh_sensitivity: threshold for simple capacitance offset + * from 'average' value. + * @thresh_timeout: a timeout, in samples from the moment an + * adaptive threshold event occurs to when the average + * value jumps to current value. Note made up of two fields, + * 3:0 are for timeout receding - applies if below lower threshold + * 7:4 are for timeout approaching - applies if above upper threshold + * @state_lock: ensure consistent state of this structure wrt the + * hardware. + * @interrupts: one or two interrupt numbers depending on device type. + * @int_enabled: is a given interrupt currently enabled. + * @type: threshold type + * @dir: threshold direction + */ +struct ad7150_chip_info { + struct i2c_client *client; + u16 threshold[2][2]; + u8 thresh_sensitivity[2][2]; + u8 thresh_timeout[2][2]; + struct mutex state_lock; + int interrupts[2]; + bool int_enabled[2]; + enum iio_event_type type; + enum iio_event_direction dir; +}; + +static const u8 ad7150_addresses[][6] = { + { AD7150_CH1_DATA_HIGH_REG, AD7150_CH1_AVG_HIGH_REG, + AD7150_CH1_SETUP_REG, AD7150_CH1_THR_HOLD_H_REG, + AD7150_CH1_SENSITIVITY_REG, AD7150_CH1_TIMEOUT_REG }, + { AD7150_CH2_DATA_HIGH_REG, AD7150_CH2_AVG_HIGH_REG, + AD7150_CH2_SETUP_REG, AD7150_CH2_THR_HOLD_H_REG, + AD7150_CH2_SENSITIVITY_REG, AD7150_CH2_TIMEOUT_REG }, +}; + +static int ad7150_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ad7150_chip_info *chip = iio_priv(indio_dev); + int channel = chan->channel; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_swapped(chip->client, + ad7150_addresses[channel][0]); + if (ret < 0) + return ret; + *val = ret >> 4; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_AVERAGE_RAW: + ret = i2c_smbus_read_word_swapped(chip->client, + ad7150_addresses[channel][1]); + if (ret < 0) + return ret; + *val = ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* + * Base units for capacitance are nano farads and the value + * calculated from the datasheet formula is in picofarad + * so multiply by 1000 + */ + *val = 1000; + *val2 = 40944 >> 4; /* To match shift in _RAW */ + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_OFFSET: + *val = -(12288 >> 4); /* To match shift in _RAW */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + /* Strangely same for both 1 and 2 chan parts */ + *val = 100; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ad7150_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 ad7150_chip_info *chip = iio_priv(indio_dev); + u8 threshtype; + bool thrfixed; + int ret; + + ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG_REG); + if (ret < 0) + return ret; + + threshtype = FIELD_GET(AD7150_CFG_THRESHTYPE_MSK, ret); + + /*check if threshold mode is fixed or adaptive*/ + thrfixed = FIELD_GET(AD7150_CFG_FIX, ret); + + switch (type) { + case IIO_EV_TYPE_THRESH_ADAPTIVE: + if (dir == IIO_EV_DIR_RISING) + return !thrfixed && (threshtype == AD7150_CFG_TT_POS); + return !thrfixed && (threshtype == AD7150_CFG_TT_NEG); + case IIO_EV_TYPE_THRESH: + if (dir == IIO_EV_DIR_RISING) + return thrfixed && (threshtype == AD7150_CFG_TT_POS); + return thrfixed && (threshtype == AD7150_CFG_TT_NEG); + default: + break; + } + return -EINVAL; +} + +/* state_lock should be held to ensure consistent state */ +static int ad7150_write_event_params(struct iio_dev *indio_dev, + unsigned int chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct ad7150_chip_info *chip = iio_priv(indio_dev); + int rising = (dir == IIO_EV_DIR_RISING); + + /* Only update value live, if parameter is in use */ + if ((type != chip->type) || (dir != chip->dir)) + return 0; + + switch (type) { + /* Note completely different from the adaptive versions */ + case IIO_EV_TYPE_THRESH: { + u16 value = chip->threshold[rising][chan]; + return i2c_smbus_write_word_swapped(chip->client, + ad7150_addresses[chan][3], + value); + } + case IIO_EV_TYPE_THRESH_ADAPTIVE: { + int ret; + u8 sens, timeout; + + sens = chip->thresh_sensitivity[rising][chan]; + ret = i2c_smbus_write_byte_data(chip->client, + ad7150_addresses[chan][4], + sens); + if (ret) + return ret; + + /* + * Single timeout register contains timeouts for both + * directions. + */ + timeout = FIELD_PREP(AD7150_CH_TIMEOUT_APPROACHING, + chip->thresh_timeout[1][chan]); + timeout |= FIELD_PREP(AD7150_CH_TIMEOUT_RECEDING, + chip->thresh_timeout[0][chan]); + return i2c_smbus_write_byte_data(chip->client, + ad7150_addresses[chan][5], + timeout); + } + default: + return -EINVAL; + } +} + +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) +{ + struct ad7150_chip_info *chip = iio_priv(indio_dev); + int ret = 0; + + /* + * There is only a single shared control and no on chip + * interrupt disables for the two interrupt lines. + * So, enabling will switch the events configured to enable + * whatever was most recently requested and if necessary enable_irq() + * the interrupt and any disable will disable_irq() for that + * channels interrupt. + */ + if (!state) { + if ((chip->int_enabled[chan->channel]) && + (type == chip->type) && (dir == chip->dir)) { + disable_irq(chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = false; + } + return 0; + } + + mutex_lock(&chip->state_lock); + if ((type != chip->type) || (dir != chip->dir)) { + int rising = (dir == IIO_EV_DIR_RISING); + u8 thresh_type, cfg, fixed; + + /* + * Need to temporarily disable both interrupts if + * enabled - this is to avoid races around changing + * config and thresholds. + * Note enable/disable_irq() are reference counted so + * no need to check if already enabled. + */ + disable_irq(chip->interrupts[0]); + disable_irq(chip->interrupts[1]); + + ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG_REG); + if (ret < 0) + goto error_ret; + + cfg = ret & ~(AD7150_CFG_THRESHTYPE_MSK | AD7150_CFG_FIX); + + if (type == IIO_EV_TYPE_THRESH_ADAPTIVE) + fixed = 0; + else + fixed = 1; + + if (rising) + thresh_type = AD7150_CFG_TT_POS; + else + thresh_type = AD7150_CFG_TT_NEG; + + cfg |= FIELD_PREP(AD7150_CFG_FIX, fixed) | + FIELD_PREP(AD7150_CFG_THRESHTYPE_MSK, thresh_type); + + ret = i2c_smbus_write_byte_data(chip->client, AD7150_CFG_REG, + cfg); + if (ret < 0) + goto error_ret; + + /* + * There is a potential race condition here, but not easy + * to close given we can't disable the interrupt at the + * chip side of things. Rely on the status bit. + */ + chip->type = type; + chip->dir = dir; + + /* update control attributes */ + ret = ad7150_write_event_params(indio_dev, chan->channel, type, + dir); + if (ret) + goto error_ret; + /* reenable any irq's we disabled whilst changing mode */ + enable_irq(chip->interrupts[0]); + enable_irq(chip->interrupts[1]); + } + if (!chip->int_enabled[chan->channel]) { + enable_irq(chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = true; + } + +error_ret: + mutex_unlock(&chip->state_lock); + + return ret; +} + +static int ad7150_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 ad7150_chip_info *chip = iio_priv(indio_dev); + int rising = (dir == IIO_EV_DIR_RISING); + + /* Complex register sharing going on here */ + switch (info) { + case IIO_EV_INFO_VALUE: + switch (type) { + case IIO_EV_TYPE_THRESH_ADAPTIVE: + *val = chip->thresh_sensitivity[rising][chan->channel]; + return IIO_VAL_INT; + case IIO_EV_TYPE_THRESH: + *val = chip->threshold[rising][chan->channel]; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_EV_INFO_TIMEOUT: + *val = 0; + *val2 = chip->thresh_timeout[rising][chan->channel] * 10000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int ad7150_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) +{ + int ret; + struct ad7150_chip_info *chip = iio_priv(indio_dev); + int rising = (dir == IIO_EV_DIR_RISING); + + mutex_lock(&chip->state_lock); + switch (info) { + case IIO_EV_INFO_VALUE: + switch (type) { + case IIO_EV_TYPE_THRESH_ADAPTIVE: + chip->thresh_sensitivity[rising][chan->channel] = val; + break; + case IIO_EV_TYPE_THRESH: + chip->threshold[rising][chan->channel] = val; + break; + default: + ret = -EINVAL; + goto error_ret; + } + break; + case IIO_EV_INFO_TIMEOUT: { + /* + * Raw timeout is in cycles of 10 msecs as long as both + * channels are enabled. + * In terms of INT_PLUS_MICRO, that is in units of 10,000 + */ + int timeout = val2 / 10000; + + if (val != 0 || timeout < 0 || timeout > 15 || val2 % 10000) { + ret = -EINVAL; + goto error_ret; + } + + chip->thresh_timeout[rising][chan->channel] = timeout; + break; + } + default: + ret = -EINVAL; + goto error_ret; + } + + /* write back if active */ + ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir); + +error_ret: + mutex_unlock(&chip->state_lock); + return ret; +} + +static const struct iio_event_spec ad7150_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), + }, { + .type = IIO_EV_TYPE_THRESH_ADAPTIVE, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_TIMEOUT), + }, { + .type = IIO_EV_TYPE_THRESH_ADAPTIVE, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_TIMEOUT), + }, +}; + +#define AD7150_CAPACITANCE_CHAN(_chan) { \ + .type = IIO_CAPACITANCE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .event_spec = ad7150_events, \ + .num_event_specs = ARRAY_SIZE(ad7150_events), \ + } + +#define AD7150_CAPACITANCE_CHAN_NO_IRQ(_chan) { \ + .type = IIO_CAPACITANCE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + } + +static const struct iio_chan_spec ad7150_channels[] = { + AD7150_CAPACITANCE_CHAN(0), + AD7150_CAPACITANCE_CHAN(1), +}; + +static const struct iio_chan_spec ad7150_channels_no_irq[] = { + AD7150_CAPACITANCE_CHAN_NO_IRQ(0), + AD7150_CAPACITANCE_CHAN_NO_IRQ(1), +}; + +static const struct iio_chan_spec ad7151_channels[] = { + AD7150_CAPACITANCE_CHAN(0), +}; + +static const struct iio_chan_spec ad7151_channels_no_irq[] = { + AD7150_CAPACITANCE_CHAN_NO_IRQ(0), +}; + +static irqreturn_t __ad7150_event_handler(void *private, u8 status_mask, + int channel) +{ + struct iio_dev *indio_dev = private; + struct ad7150_chip_info *chip = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(indio_dev); + int int_status; + + int_status = i2c_smbus_read_byte_data(chip->client, AD7150_STATUS_REG); + if (int_status < 0) + return IRQ_HANDLED; + + if (!(int_status & status_mask)) + return IRQ_HANDLED; + + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, channel, + chip->type, chip->dir), + timestamp); + + return IRQ_HANDLED; +} + +static irqreturn_t ad7150_event_handler_ch1(int irq, void *private) +{ + return __ad7150_event_handler(private, AD7150_STATUS_OUT1, 0); +} + +static irqreturn_t ad7150_event_handler_ch2(int irq, void *private) +{ + return __ad7150_event_handler(private, AD7150_STATUS_OUT2, 1); +} + +static IIO_CONST_ATTR(in_capacitance_thresh_adaptive_timeout_available, + "[0 0.01 0.15]"); + +static struct attribute *ad7150_event_attributes[] = { + &iio_const_attr_in_capacitance_thresh_adaptive_timeout_available + .dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7150_event_attribute_group = { + .attrs = ad7150_event_attributes, + .name = "events", +}; + +static const struct iio_info ad7150_info = { + .event_attrs = &ad7150_event_attribute_group, + .read_raw = &ad7150_read_raw, + .read_event_config = &ad7150_read_event_config, + .write_event_config = &ad7150_write_event_config, + .read_event_value = &ad7150_read_event_value, + .write_event_value = &ad7150_write_event_value, +}; + +static const struct iio_info ad7150_info_no_irq = { + .read_raw = &ad7150_read_raw, +}; + +static void ad7150_reg_disable(void *data) +{ + struct regulator *reg = data; + + regulator_disable(reg); +} + +static int ad7150_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ad7150_chip_info *chip; + struct iio_dev *indio_dev; + struct regulator *reg; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + mutex_init(&chip->state_lock); + chip->client = client; + + indio_dev->name = id->name; + + indio_dev->modes = INDIO_DIRECT_MODE; + + reg = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + ret = regulator_enable(reg); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&client->dev, ad7150_reg_disable, reg); + if (ret) + return ret; + + chip->interrupts[0] = fwnode_irq_get(dev_fwnode(&client->dev), 0); + if (chip->interrupts[0] < 0) + return chip->interrupts[0]; + if (id->driver_data == AD7150) { + chip->interrupts[1] = fwnode_irq_get(dev_fwnode(&client->dev), 1); + if (chip->interrupts[1] < 0) + return chip->interrupts[1]; + } + if (chip->interrupts[0] && + (id->driver_data == AD7151 || chip->interrupts[1])) { + irq_set_status_flags(chip->interrupts[0], IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(&client->dev, + chip->interrupts[0], + NULL, + &ad7150_event_handler_ch1, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "ad7150_irq1", + indio_dev); + if (ret) + return ret; + + indio_dev->info = &ad7150_info; + switch (id->driver_data) { + case AD7150: + indio_dev->channels = ad7150_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7150_channels); + irq_set_status_flags(chip->interrupts[1], IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(&client->dev, + chip->interrupts[1], + NULL, + &ad7150_event_handler_ch2, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "ad7150_irq2", + indio_dev); + if (ret) + return ret; + break; + case AD7151: + indio_dev->channels = ad7151_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7151_channels); + break; + default: + return -EINVAL; + } + + } else { + indio_dev->info = &ad7150_info_no_irq; + switch (id->driver_data) { + case AD7150: + indio_dev->channels = ad7150_channels_no_irq; + indio_dev->num_channels = + ARRAY_SIZE(ad7150_channels_no_irq); + break; + case AD7151: + indio_dev->channels = ad7151_channels_no_irq; + indio_dev->num_channels = + ARRAY_SIZE(ad7151_channels_no_irq); + break; + default: + return -EINVAL; + } + } + + return devm_iio_device_register(indio_dev->dev.parent, indio_dev); +} + +static const struct i2c_device_id ad7150_id[] = { + { "ad7150", AD7150 }, + { "ad7151", AD7151 }, + { "ad7156", AD7150 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad7150_id); + +static const struct of_device_id ad7150_of_match[] = { + { "adi,ad7150" }, + { "adi,ad7151" }, + { "adi,ad7156" }, + {} +}; +static struct i2c_driver ad7150_driver = { + .driver = { + .name = "ad7150", + .of_match_table = ad7150_of_match, + }, + .probe = ad7150_probe, + .id_table = ad7150_id, +}; +module_i2c_driver(ad7150_driver); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices AD7150/1/6 capacitive sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index cdab9d04dedd0d2dd5fd2904c9d756d6e1eb4210..56ba6c82b501f186f9f34324b9306ff7f464f6f6 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -649,7 +649,6 @@ static int atlas_probe(struct i2c_client *client, data->client = client; data->trig = trig; data->chip = chip; - trig->dev.parent = indio_dev->dev.parent; trig->ops = &atlas_interrupt_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index de9c9e3d23ea347824f0a480031bf46e11021c6a..29c0dfa4702bb34222b392a5f4f6a251aeb58c0b 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -26,8 +26,7 @@ static int bme680_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &bme680_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index 3b838068a7e48d7378597aeec7eef7da5953cd58..6f56ad48cc40487c58fe9eb94bf0764e2b87419f 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -132,8 +132,7 @@ static int bme680_spi_probe(struct spi_device *spi) regmap = devm_regmap_init(&spi->dev, &bme680_regmap_bus, bus_context, &bme680_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 60dd87e96f5f8b0049f9b3af4e7be6e82b3b0ab8..886e96496dbf7eeb79c2fb6147f276883ea6bdff 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -497,7 +497,6 @@ static int ccs811_probe(struct i2c_client *client, goto err_poweroff; } - data->drdy_trig->dev.parent = &client->dev; data->drdy_trig->ops = &ccs811_trigger_ops; iio_trigger_set_drvdata(data->drdy_trig, indio_dev); indio_dev->trig = data->drdy_trig; diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index 4d0d798c7cd347d97d25e6a12347b12d7896ff00..d89f117dd0ef30cc525604960f279dbdbe052035 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -646,7 +646,6 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) return -ENOMEM; } - trig->dev.parent = dev; trig->ops = &scd30_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); @@ -656,19 +655,19 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) indio_dev->trig = iio_trigger_get(trig); + /* + * Interrupt is enabled just before taking a fresh measurement + * and disabled afterwards. This means we need to ensure it is not + * enabled here to keep calls to enable/disable balanced. + */ ret = devm_request_threaded_irq(dev, state->irq, scd30_irq_handler, - scd30_irq_thread_handler, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + scd30_irq_thread_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | + IRQF_NO_AUTOEN, indio_dev->name, indio_dev); if (ret) dev_err(dev, "failed to request irq\n"); - /* - * Interrupt is enabled just before taking a fresh measurement - * and disabled afterwards. This means we need to disable it here - * to keep calls to enable/disable balanced. - */ - disable_irq(state->irq); - return ret; } diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index 06f85eb1a4dd840c2270bb3057aec8aff53df425..568b34486c44cf38fd32c1444838003bc1fc8c11 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -177,7 +177,7 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u static int scd30_serdev_receive_buf(struct serdev_device *serdev, const unsigned char *buf, size_t size) { - struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); + struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct scd30_serdev_priv *priv; struct scd30_state *state; int num; diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig index 2b9ee9161abdc93a13402bde04592205e474ac97..0334b495477338897c44e516745e2a444f832c1a 100644 --- a/drivers/iio/common/Kconfig +++ b/drivers/iio/common/Kconfig @@ -6,5 +6,6 @@ source "drivers/iio/common/cros_ec_sensors/Kconfig" source "drivers/iio/common/hid-sensors/Kconfig" source "drivers/iio/common/ms_sensors/Kconfig" +source "drivers/iio/common/scmi_sensors/Kconfig" source "drivers/iio/common/ssp_sensors/Kconfig" source "drivers/iio/common/st_sensors/Kconfig" diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile index 4bc30bb548e2d5966862f68dcdb043553bd3cc5d..fad40e1e17181912de07b40ff2361f6343b6d405 100644 --- a/drivers/iio/common/Makefile +++ b/drivers/iio/common/Makefile @@ -11,5 +11,6 @@ obj-y += cros_ec_sensors/ obj-y += hid-sensors/ obj-y += ms_sensors/ +obj-y += scmi_sensors/ obj-y += ssp_sensors/ obj-y += st_sensors/ diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index 752f59037715b2e05c94a0ae29d2800f4fa3ed3e..af801e203623e37b00188b4c96985c1165d2c35d 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -97,8 +97,7 @@ static int cros_ec_lid_angle_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, - NULL, false); + ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL); if (ret) return ret; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index dee1191de75280290b749007140a57ae9eb9da78..376a5b30010aeaaefcf06910287214131190a1ed 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -236,8 +236,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) ret = cros_ec_sensors_core_init(pdev, indio_dev, true, cros_ec_sensors_capture, - cros_ec_sensors_push_data, - true); + cros_ec_sensors_push_data); if (ret) return ret; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index c833ec0ef2147efedff723021a28bff5a970d45e..28bde13003b74427fb6e72c7b8dc5dbe57ba9404 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -12,6 +12,7 @@ #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> #include <linux/kernel.h> @@ -240,7 +241,6 @@ static void cros_ec_sensors_core_clean(void *arg) * for backward compatibility. * @push_data: function to call when cros_ec_sensorhub receives * a sample for that sensor. - * @has_hw_fifo: Set true if this device has/uses a HW FIFO * * Return: 0 on success, -errno on failure. */ @@ -248,8 +248,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device, cros_ec_sensors_capture_t trigger_capture, - cros_ec_sensorhub_push_data_cb_t push_data, - bool has_hw_fifo) + cros_ec_sensorhub_push_data_cb_t push_data) { struct device *dev = &pdev->dev; struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); @@ -334,14 +333,11 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, * We can not use trigger here, as events are generated * as soon as sample_frequency is set. */ - struct iio_buffer *buffer; - - buffer = devm_iio_kfifo_allocate(dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->modes = INDIO_BUFFER_SOFTWARE; + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + INDIO_BUFFER_SOFTWARE, NULL, + cros_ec_sensor_fifo_attributes); + if (ret) + return ret; ret = cros_ec_sensorhub_register_push_data( sensor_hub, sensor_platform->sensor_num, @@ -358,21 +354,14 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME); if (ret) return ret; - } else { - const struct attribute **fifo_attrs; - - if (has_hw_fifo) - fifo_attrs = cros_ec_sensor_fifo_attributes; - else - fifo_attrs = NULL; + } else { /* * The only way to get samples in buffer is to set a * software trigger (systrig, hrtimer). */ - ret = devm_iio_triggered_buffer_setup_ext( - dev, indio_dev, NULL, trigger_capture, - NULL, fifo_attrs); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + NULL, trigger_capture, NULL); if (ret) return ret; } @@ -562,7 +551,7 @@ static int cros_ec_sensors_read_until_not_busy( } /** - * read_ec_sensors_data_unsafe() - read acceleration data from EC shared memory + * cros_ec_sensors_read_data_unsafe() - read acceleration data from EC shared memory * @indio_dev: pointer to IIO device * @scan_mask: bitmap of the sensor indices to scan * @data: location to store data diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 5b822a4298a0917b2dd2c061c652bcb88865de7c..cb52b4fd6bf7f27cce691243dd638929efe52319 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -263,6 +263,29 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, } EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value); +int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, + int *val2) +{ + s32 value; + int ret; + + ret = sensor_hub_get_feature(st->hsdev, + st->sensitivity_rel.report_id, + st->sensitivity_rel.index, sizeof(value), + &value); + if (ret < 0 || value < 0) { + *val1 = *val2 = 0; + return -EINVAL; + } + + convert_from_vtf_format(value, st->sensitivity_rel.size, + st->sensitivity_rel.unit_expo, val1, val2); + + return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_read_raw_hyst_rel_value); + + int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, int val1, int val2) { @@ -294,6 +317,37 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, } EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); +int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, + int val1, int val2) +{ + s32 value; + int ret; + + if (val1 < 0 || val2 < 0) + return -EINVAL; + + value = convert_to_vtf_format(st->sensitivity_rel.size, + st->sensitivity_rel.unit_expo, + val1, val2); + ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id, + st->sensitivity_rel.index, sizeof(value), + &value); + if (ret < 0 || value < 0) + return -EINVAL; + + ret = sensor_hub_get_feature(st->hsdev, + st->sensitivity_rel.report_id, + st->sensitivity_rel.index, sizeof(value), + &value); + if (ret < 0 || value < 0) + return -EINVAL; + + st->raw_hystersis = value; + + return 0; +} +EXPORT_SYMBOL(hid_sensor_write_raw_hyst_rel_value); + /* * This fuction applies the unit exponent to the scale. * For example: @@ -448,12 +502,15 @@ EXPORT_SYMBOL(hid_sensor_batch_mode_supported); int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, - struct hid_sensor_common *st) + struct hid_sensor_common *st, + const u32 *sensitivity_addresses, + u32 sensitivity_addresses_len) { struct hid_sensor_hub_attribute_info timestamp; s32 value; int ret; + int i; hid_sensor_get_reporting_interval(hsdev, usage_id, st); @@ -475,6 +532,30 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, &st->sensitivity); + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT, + &st->sensitivity_rel); + /* + * Set Sensitivity field ids, when there is no individual modifier, will + * check absolute sensitivity and relative sensitivity of data field + */ + for (i = 0; i < sensitivity_addresses_len; i++) { + if (st->sensitivity.index < 0) + sensor_hub_input_get_attribute_info( + hsdev, HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + sensitivity_addresses[i], + &st->sensitivity); + + if (st->sensitivity_rel.index < 0) + sensor_hub_input_get_attribute_info( + hsdev, HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT | + sensitivity_addresses[i], + &st->sensitivity_rel); + } + st->raw_hystersis = -1; sensor_hub_input_get_attribute_info(hsdev, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 064c32bec9c7b7ae5d968d13902b41900b2e899d..95ddccb44f1c8150ada1aa3a5aa85760677d7258 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -255,14 +255,14 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, return ret; } - trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id); + trig = iio_trigger_alloc(indio_dev->dev.parent, + "%s-dev%d", name, indio_dev->id); if (trig == NULL) { dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); ret = -ENOMEM; goto error_triggered_buffer_cleanup; } - trig->dev.parent = indio_dev->dev.parent; iio_trigger_set_drvdata(trig, attrb); trig->ops = &hid_sensor_trigger_ops; ret = iio_trigger_register(trig); diff --git a/drivers/iio/common/scmi_sensors/Kconfig b/drivers/iio/common/scmi_sensors/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..67e084cbb1ab52f0081ccb235a8a8694c4a45ca7 --- /dev/null +++ b/drivers/iio/common/scmi_sensors/Kconfig @@ -0,0 +1,18 @@ +# +# IIO over SCMI +# +# When adding new entries keep the list in alphabetical order + +menu "IIO SCMI Sensors" + +config IIO_SCMI + tristate "IIO SCMI" + depends on ARM_SCMI_PROTOCOL + select IIO_BUFFER + select IIO_KFIFO_BUF + help + Say yes here to build support for IIO SCMI Driver. + This provides ARM SCMI Protocol based IIO device. + This driver provides support for accelerometer and gyroscope + sensors available on SCMI based platforms. +endmenu diff --git a/drivers/iio/common/scmi_sensors/Makefile b/drivers/iio/common/scmi_sensors/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f13140a2575a4642e504e9e1dc336478ebfb628b --- /dev/null +++ b/drivers/iio/common/scmi_sensors/Makefile @@ -0,0 +1,5 @@ +# SPDX - License - Identifier : GPL - 2.0 - only +# +# Makefile for the IIO over SCMI +# +obj-$(CONFIG_IIO_SCMI) += scmi_iio.o diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c new file mode 100644 index 0000000000000000000000000000000000000000..141e8aa6911e639400817a519eea7021c6308e3a --- /dev/null +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -0,0 +1,672 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * System Control and Management Interface(SCMI) based IIO sensor driver + * + * Copyright (C) 2021 Google LLC + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/kfifo_buf.h> +#include <linux/iio/sysfs.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/scmi_protocol.h> +#include <linux/time.h> +#include <linux/types.h> + +#define SCMI_IIO_NUM_OF_AXIS 3 + +struct scmi_iio_priv { + const struct scmi_sensor_proto_ops *sensor_ops; + struct scmi_protocol_handle *ph; + const struct scmi_sensor_info *sensor_info; + struct iio_dev *indio_dev; + /* adding one additional channel for timestamp */ + s64 iio_buf[SCMI_IIO_NUM_OF_AXIS + 1]; + struct notifier_block sensor_update_nb; + u32 *freq_avail; +}; + +static int scmi_iio_sensor_update_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct scmi_sensor_update_report *sensor_update = data; + struct iio_dev *scmi_iio_dev; + struct scmi_iio_priv *sensor; + s8 tstamp_scale; + u64 time, time_ns; + int i; + + if (sensor_update->readings_count == 0) + return NOTIFY_DONE; + + sensor = container_of(nb, struct scmi_iio_priv, sensor_update_nb); + + for (i = 0; i < sensor_update->readings_count; i++) + sensor->iio_buf[i] = sensor_update->readings[i].value; + + if (!sensor->sensor_info->timestamped) { + time_ns = ktime_to_ns(sensor_update->timestamp); + } else { + /* + * All the axes are supposed to have the same value for timestamp. + * We are just using the values from the Axis 0 here. + */ + time = sensor_update->readings[0].timestamp; + + /* + * Timestamp returned by SCMI is in seconds and is equal to + * time * power-of-10 multiplier(tstamp_scale) seconds. + * Converting the timestamp to nanoseconds below. + */ + tstamp_scale = sensor->sensor_info->tstamp_scale + + const_ilog2(NSEC_PER_SEC) / const_ilog2(10); + if (tstamp_scale < 0) { + do_div(time, int_pow(10, abs(tstamp_scale))); + time_ns = time; + } else { + time_ns = time * int_pow(10, tstamp_scale); + } + } + + scmi_iio_dev = sensor->indio_dev; + iio_push_to_buffers_with_timestamp(scmi_iio_dev, sensor->iio_buf, + time_ns); + return NOTIFY_OK; +} + +static int scmi_iio_buffer_preenable(struct iio_dev *iio_dev) +{ + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + u32 sensor_config = 0; + int err; + + if (sensor->sensor_info->timestamped) + sensor_config |= FIELD_PREP(SCMI_SENS_CFG_TSTAMP_ENABLED_MASK, + SCMI_SENS_CFG_TSTAMP_ENABLE); + + sensor_config |= FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK, + SCMI_SENS_CFG_SENSOR_ENABLE); + err = sensor->sensor_ops->config_set(sensor->ph, + sensor->sensor_info->id, + sensor_config); + if (err) + dev_err(&iio_dev->dev, "Error in enabling sensor %s err %d", + sensor->sensor_info->name, err); + + return err; +} + +static int scmi_iio_buffer_postdisable(struct iio_dev *iio_dev) +{ + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + u32 sensor_config = 0; + int err; + + sensor_config |= FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK, + SCMI_SENS_CFG_SENSOR_DISABLE); + err = sensor->sensor_ops->config_set(sensor->ph, + sensor->sensor_info->id, + sensor_config); + if (err) { + dev_err(&iio_dev->dev, + "Error in disabling sensor %s with err %d", + sensor->sensor_info->name, err); + } + + return err; +} + +static const struct iio_buffer_setup_ops scmi_iio_buffer_ops = { + .preenable = scmi_iio_buffer_preenable, + .postdisable = scmi_iio_buffer_postdisable, +}; + +static int scmi_iio_set_odr_val(struct iio_dev *iio_dev, int val, int val2) +{ + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + const unsigned long UHZ_PER_HZ = 1000000UL; + u64 sec, mult, uHz, sf; + u32 sensor_config; + char buf[32]; + + int err = sensor->sensor_ops->config_get(sensor->ph, + sensor->sensor_info->id, + &sensor_config); + if (err) { + dev_err(&iio_dev->dev, + "Error in getting sensor config for sensor %s err %d", + sensor->sensor_info->name, err); + return err; + } + + uHz = val * UHZ_PER_HZ + val2; + + /* + * The seconds field in the sensor interval in SCMI is 16 bits long + * Therefore seconds = 1/Hz <= 0xFFFF. As floating point calculations are + * discouraged in the kernel driver code, to calculate the scale factor (sf) + * (1* 1000000 * sf)/uHz <= 0xFFFF. Therefore, sf <= (uHz * 0xFFFF)/1000000 + * To calculate the multiplier,we convert the sf into char string and + * count the number of characters + */ + sf = (u64)uHz * 0xFFFF; + do_div(sf, UHZ_PER_HZ); + mult = scnprintf(buf, sizeof(buf), "%llu", sf) - 1; + + sec = int_pow(10, mult) * UHZ_PER_HZ; + do_div(sec, uHz); + if (sec == 0) { + dev_err(&iio_dev->dev, + "Trying to set invalid sensor update value for sensor %s", + sensor->sensor_info->name); + return -EINVAL; + } + + sensor_config &= ~SCMI_SENS_CFG_UPDATE_SECS_MASK; + sensor_config |= FIELD_PREP(SCMI_SENS_CFG_UPDATE_SECS_MASK, sec); + sensor_config &= ~SCMI_SENS_CFG_UPDATE_EXP_MASK; + sensor_config |= FIELD_PREP(SCMI_SENS_CFG_UPDATE_EXP_MASK, -mult); + + if (sensor->sensor_info->timestamped) { + sensor_config &= ~SCMI_SENS_CFG_TSTAMP_ENABLED_MASK; + sensor_config |= FIELD_PREP(SCMI_SENS_CFG_TSTAMP_ENABLED_MASK, + SCMI_SENS_CFG_TSTAMP_ENABLE); + } + + sensor_config &= ~SCMI_SENS_CFG_ROUND_MASK; + sensor_config |= + FIELD_PREP(SCMI_SENS_CFG_ROUND_MASK, SCMI_SENS_CFG_ROUND_AUTO); + + err = sensor->sensor_ops->config_set(sensor->ph, + sensor->sensor_info->id, + sensor_config); + if (err) + dev_err(&iio_dev->dev, + "Error in setting sensor update interval for sensor %s value %u err %d", + sensor->sensor_info->name, sensor_config, err); + + return err; +} + +static int scmi_iio_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + int err; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&iio_dev->mlock); + err = scmi_iio_set_odr_val(iio_dev, val, val2); + mutex_unlock(&iio_dev->mlock); + return err; + default: + return -EINVAL; + } +} + +static int scmi_iio_read_avail(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = sensor->freq_avail; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = sensor->sensor_info->intervals.count * 2; + if (sensor->sensor_info->intervals.segmented) + return IIO_AVAIL_RANGE; + else + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static void convert_ns_to_freq(u64 interval_ns, u64 *hz, u64 *uhz) +{ + u64 rem, freq; + + freq = NSEC_PER_SEC; + rem = do_div(freq, interval_ns); + *hz = freq; + *uhz = rem * 1000000UL; + do_div(*uhz, interval_ns); +} + +static int scmi_iio_get_odr_val(struct iio_dev *iio_dev, int *val, int *val2) +{ + u64 sensor_update_interval, sensor_interval_mult, hz, uhz; + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + u32 sensor_config; + int mult; + + int err = sensor->sensor_ops->config_get(sensor->ph, + sensor->sensor_info->id, + &sensor_config); + if (err) { + dev_err(&iio_dev->dev, + "Error in getting sensor config for sensor %s err %d", + sensor->sensor_info->name, err); + return err; + } + + sensor_update_interval = + SCMI_SENS_CFG_GET_UPDATE_SECS(sensor_config) * NSEC_PER_SEC; + + mult = SCMI_SENS_CFG_GET_UPDATE_EXP(sensor_config); + if (mult < 0) { + sensor_interval_mult = int_pow(10, abs(mult)); + do_div(sensor_update_interval, sensor_interval_mult); + } else { + sensor_interval_mult = int_pow(10, mult); + sensor_update_interval = + sensor_update_interval * sensor_interval_mult; + } + + convert_ns_to_freq(sensor_update_interval, &hz, &uhz); + *val = hz; + *val2 = uhz; + return 0; +} + +static int scmi_iio_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, int *val, + int *val2, long mask) +{ + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + s8 scale; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + scale = sensor->sensor_info->axis[ch->scan_index].scale; + if (scale < 0) { + *val = 1; + *val2 = int_pow(10, abs(scale)); + return IIO_VAL_FRACTIONAL; + } + *val = int_pow(10, scale); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = scmi_iio_get_odr_val(iio_dev, val, val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info scmi_iio_info = { + .read_raw = scmi_iio_read_raw, + .read_avail = scmi_iio_read_avail, + .write_raw = scmi_iio_write_raw, +}; + +static ssize_t scmi_iio_get_raw_available(struct iio_dev *iio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + u64 resolution, rem; + s64 min_range, max_range; + s8 exponent, scale; + int len = 0; + + /* + * All the axes are supposed to have the same value for range and resolution. + * We are just using the values from the Axis 0 here. + */ + if (sensor->sensor_info->axis[0].extended_attrs) { + min_range = sensor->sensor_info->axis[0].attrs.min_range; + max_range = sensor->sensor_info->axis[0].attrs.max_range; + resolution = sensor->sensor_info->axis[0].resolution; + exponent = sensor->sensor_info->axis[0].exponent; + scale = sensor->sensor_info->axis[0].scale; + + /* + * To provide the raw value for the resolution to the userspace, + * need to divide the resolution exponent by the sensor scale + */ + exponent = exponent - scale; + if (exponent < 0) { + rem = do_div(resolution, + int_pow(10, abs(exponent)) + ); + len = scnprintf(buf, PAGE_SIZE, + "[%lld %llu.%llu %lld]\n", min_range, + resolution, rem, max_range); + } else { + resolution = resolution * int_pow(10, exponent); + len = scnprintf(buf, PAGE_SIZE, "[%lld %llu %lld]\n", + min_range, resolution, max_range); + } + } + return len; +} + +static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = { + { + .name = "raw_available", + .read = scmi_iio_get_raw_available, + .shared = IIO_SHARED_BY_TYPE, + }, + {}, +}; + +static void scmi_iio_set_timestamp_channel(struct iio_chan_spec *iio_chan, + int scan_index) +{ + iio_chan->type = IIO_TIMESTAMP; + iio_chan->channel = -1; + iio_chan->scan_index = scan_index; + iio_chan->scan_type.sign = 'u'; + iio_chan->scan_type.realbits = 64; + iio_chan->scan_type.storagebits = 64; +} + +static void scmi_iio_set_data_channel(struct iio_chan_spec *iio_chan, + enum iio_chan_type type, + enum iio_modifier mod, int scan_index) +{ + iio_chan->type = type; + iio_chan->modified = 1; + iio_chan->channel2 = mod; + iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_SCALE); + iio_chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ); + iio_chan->info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ); + iio_chan->scan_index = scan_index; + iio_chan->scan_type.sign = 's'; + iio_chan->scan_type.realbits = 64; + iio_chan->scan_type.storagebits = 64; + iio_chan->scan_type.endianness = IIO_LE; + iio_chan->ext_info = scmi_iio_ext_info; +} + +static int scmi_iio_get_chan_modifier(const char *name, + enum iio_modifier *modifier) +{ + char *pch, mod; + + if (!name) + return -EINVAL; + + pch = strrchr(name, '_'); + if (!pch) + return -EINVAL; + + mod = *(pch + 1); + switch (mod) { + case 'X': + *modifier = IIO_MOD_X; + return 0; + case 'Y': + *modifier = IIO_MOD_Y; + return 0; + case 'Z': + *modifier = IIO_MOD_Z; + return 0; + default: + return -EINVAL; + } +} + +static int scmi_iio_get_chan_type(u8 scmi_type, enum iio_chan_type *iio_type) +{ + switch (scmi_type) { + case METERS_SEC_SQUARED: + *iio_type = IIO_ACCEL; + return 0; + case RADIANS_SEC: + *iio_type = IIO_ANGL_VEL; + return 0; + default: + return -EINVAL; + } +} + +static u64 scmi_iio_convert_interval_to_ns(u32 val) +{ + u64 sensor_update_interval = + SCMI_SENS_INTVL_GET_SECS(val) * NSEC_PER_SEC; + u64 sensor_interval_mult; + int mult; + + mult = SCMI_SENS_INTVL_GET_EXP(val); + if (mult < 0) { + sensor_interval_mult = int_pow(10, abs(mult)); + do_div(sensor_update_interval, sensor_interval_mult); + } else { + sensor_interval_mult = int_pow(10, mult); + sensor_update_interval = + sensor_update_interval * sensor_interval_mult; + } + return sensor_update_interval; +} + +static int scmi_iio_set_sampling_freq_avail(struct iio_dev *iio_dev) +{ + u64 cur_interval_ns, low_interval_ns, high_interval_ns, step_size_ns, + hz, uhz; + unsigned int cur_interval, low_interval, high_interval, step_size; + struct scmi_iio_priv *sensor = iio_priv(iio_dev); + int i; + + sensor->freq_avail = + devm_kzalloc(&iio_dev->dev, + sizeof(*sensor->freq_avail) * + (sensor->sensor_info->intervals.count * 2), + GFP_KERNEL); + if (!sensor->freq_avail) + return -ENOMEM; + + if (sensor->sensor_info->intervals.segmented) { + low_interval = sensor->sensor_info->intervals + .desc[SCMI_SENS_INTVL_SEGMENT_LOW]; + low_interval_ns = scmi_iio_convert_interval_to_ns(low_interval); + convert_ns_to_freq(low_interval_ns, &hz, &uhz); + sensor->freq_avail[0] = hz; + sensor->freq_avail[1] = uhz; + + step_size = sensor->sensor_info->intervals + .desc[SCMI_SENS_INTVL_SEGMENT_STEP]; + step_size_ns = scmi_iio_convert_interval_to_ns(step_size); + convert_ns_to_freq(step_size_ns, &hz, &uhz); + sensor->freq_avail[2] = hz; + sensor->freq_avail[3] = uhz; + + high_interval = sensor->sensor_info->intervals + .desc[SCMI_SENS_INTVL_SEGMENT_HIGH]; + high_interval_ns = + scmi_iio_convert_interval_to_ns(high_interval); + convert_ns_to_freq(high_interval_ns, &hz, &uhz); + sensor->freq_avail[4] = hz; + sensor->freq_avail[5] = uhz; + } else { + for (i = 0; i < sensor->sensor_info->intervals.count; i++) { + cur_interval = sensor->sensor_info->intervals.desc[i]; + cur_interval_ns = + scmi_iio_convert_interval_to_ns(cur_interval); + convert_ns_to_freq(cur_interval_ns, &hz, &uhz); + sensor->freq_avail[i * 2] = hz; + sensor->freq_avail[i * 2 + 1] = uhz; + } + } + return 0; +} + +static struct iio_dev * +scmi_alloc_iiodev(struct scmi_device *sdev, + const struct scmi_sensor_proto_ops *ops, + struct scmi_protocol_handle *ph, + const struct scmi_sensor_info *sensor_info) +{ + struct iio_chan_spec *iio_channels; + struct scmi_iio_priv *sensor; + enum iio_modifier modifier; + enum iio_chan_type type; + struct iio_dev *iiodev; + struct device *dev = &sdev->dev; + const struct scmi_handle *handle = sdev->handle; + int i, ret; + + iiodev = devm_iio_device_alloc(dev, sizeof(*sensor)); + if (!iiodev) + return ERR_PTR(-ENOMEM); + + iiodev->modes = INDIO_DIRECT_MODE; + iiodev->dev.parent = dev; + sensor = iio_priv(iiodev); + sensor->sensor_ops = ops; + sensor->ph = ph; + sensor->sensor_info = sensor_info; + sensor->sensor_update_nb.notifier_call = scmi_iio_sensor_update_cb; + sensor->indio_dev = iiodev; + + /* adding one additional channel for timestamp */ + iiodev->num_channels = sensor_info->num_axis + 1; + iiodev->name = sensor_info->name; + iiodev->info = &scmi_iio_info; + + iio_channels = + devm_kzalloc(dev, + sizeof(*iio_channels) * (iiodev->num_channels), + GFP_KERNEL); + if (!iio_channels) + return ERR_PTR(-ENOMEM); + + ret = scmi_iio_set_sampling_freq_avail(iiodev); + if (ret < 0) + return ERR_PTR(ret); + + for (i = 0; i < sensor_info->num_axis; i++) { + ret = scmi_iio_get_chan_type(sensor_info->axis[i].type, &type); + if (ret < 0) + return ERR_PTR(ret); + + ret = scmi_iio_get_chan_modifier(sensor_info->axis[i].name, + &modifier); + if (ret < 0) + return ERR_PTR(ret); + + scmi_iio_set_data_channel(&iio_channels[i], type, modifier, + sensor_info->axis[i].id); + } + + ret = handle->notify_ops->devm_event_notifier_register(sdev, + SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE, + &sensor->sensor_info->id, + &sensor->sensor_update_nb); + if (ret) { + dev_err(&iiodev->dev, + "Error in registering sensor update notifier for sensor %s err %d", + sensor->sensor_info->name, ret); + return ERR_PTR(ret); + } + + scmi_iio_set_timestamp_channel(&iio_channels[i], i); + iiodev->channels = iio_channels; + return iiodev; +} + +static int scmi_iio_dev_probe(struct scmi_device *sdev) +{ + const struct scmi_sensor_info *sensor_info; + struct scmi_handle *handle = sdev->handle; + const struct scmi_sensor_proto_ops *sensor_ops; + struct scmi_protocol_handle *ph; + struct device *dev = &sdev->dev; + struct iio_dev *scmi_iio_dev; + u16 nr_sensors; + int err = -ENODEV, i; + + if (!handle) + return -ENODEV; + + sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph); + if (IS_ERR(sensor_ops)) { + dev_err(dev, "SCMI device has no sensor interface\n"); + return PTR_ERR(sensor_ops); + } + + nr_sensors = sensor_ops->count_get(ph); + if (!nr_sensors) { + dev_dbg(dev, "0 sensors found via SCMI bus\n"); + return -ENODEV; + } + + for (i = 0; i < nr_sensors; i++) { + sensor_info = sensor_ops->info_get(ph, i); + if (!sensor_info) { + dev_err(dev, "SCMI sensor %d has missing info\n", i); + return -EINVAL; + } + + /* This driver only supports 3-axis accel and gyro, skipping other sensors */ + if (sensor_info->num_axis != SCMI_IIO_NUM_OF_AXIS) + continue; + + /* This driver only supports 3-axis accel and gyro, skipping other sensors */ + if (sensor_info->axis[0].type != METERS_SEC_SQUARED && + sensor_info->axis[0].type != RADIANS_SEC) + continue; + + scmi_iio_dev = scmi_alloc_iiodev(sdev, sensor_ops, ph, + sensor_info); + if (IS_ERR(scmi_iio_dev)) { + dev_err(dev, + "failed to allocate IIO device for sensor %s: %ld\n", + sensor_info->name, PTR_ERR(scmi_iio_dev)); + return PTR_ERR(scmi_iio_dev); + } + + err = devm_iio_kfifo_buffer_setup(&scmi_iio_dev->dev, + scmi_iio_dev, + INDIO_BUFFER_SOFTWARE, + &scmi_iio_buffer_ops); + if (err < 0) { + dev_err(dev, + "IIO buffer setup error at sensor %s: %d\n", + sensor_info->name, err); + return err; + } + + err = devm_iio_device_register(dev, scmi_iio_dev); + if (err) { + dev_err(dev, + "IIO device registration failed at sensor %s: %d\n", + sensor_info->name, err); + return err; + } + } + return err; +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_SENSOR, "iiodev" }, + {}, +}; + +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_iiodev_driver = { + .name = "scmi-sensor-iiodev", + .probe = scmi_iio_dev_probe, + .id_table = scmi_id_table, +}; + +module_scmi_driver(scmi_iiodev_driver); + +MODULE_AUTHOR("Jyoti Bhayana <jbhayana@google.com>"); +MODULE_DESCRIPTION("SCMI IIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index eee30130ae23871219c1558c933e70f22227ad34..802f9ae04cf4e5eebd7ac5a2a627b83da22f80dc 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -57,7 +57,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) s64 timestamp; /* - * If we do timetamping here, do it before reading the values, because + * If we do timestamping here, do it before reading the values, because * once we've read the values, new interrupts can occur (when using * the hardware trigger) and the hw_timestamp may get updated. * By storing it in a local variable first, we are safe. diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 2dbd2646e44e97f3edd899143b5380245156ebe7..0b511665dee5f24b97e1d8c9d21405bc359107f6 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -123,7 +123,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, unsigned long irq_trig; int err; - sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name); + sdata->trig = iio_trigger_alloc(sdata->dev, "%s-trigger", + indio_dev->name); if (sdata->trig == NULL) { dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n"); return -ENOMEM; @@ -131,7 +132,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, iio_trigger_set_drvdata(sdata->trig, indio_dev); sdata->trig->ops = trigger_ops; - sdata->trig->dev.parent = sdata->dev; irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq)); /* diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index cea07b4cced114c3ba17ca2506c265af6ec5e5e8..75e1f2b486388dd9414a78ed5b2becffc96a1e66 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -142,8 +142,9 @@ config AD5696_I2C select AD5686 help Say yes here to build support for Analog Devices AD5311R, AD5338R, - AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R, AD5694, AD5694R, - AD5695R, AD5696, and AD5696R Digital to Analog converters. + AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, AD5693R, + AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to Analog + converters. To compile this driver as a module, choose M here: the module will be called ad5696. diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 82abd4d6886cfe7668e61b2436aa054c52939d35..dff623b65e4f1214e9a337579eb1fbb0466fadf4 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -277,7 +277,7 @@ static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5064_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->pwr_down[chan->channel]); + return sysfs_emit(buf, "%d\n", st->pwr_down[chan->channel]); } static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index 602dd2ba61b552d4eafd5af0fbdd19d3b56aafa7..2d3b14c407d838f70aa87809acb414ecace27493 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -255,7 +255,7 @@ static ssize_t ad5360_read_dac_powerdown(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5360_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN)); + return sysfs_emit(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN)); } static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set, diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 37ef653564b0a29d62e0f05b1beba1ee0ba3070b..53db5b4e4c53cad75fd94891f3fee682d8aa0101 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -85,7 +85,7 @@ static ssize_t ad5380_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5380_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->pwr_down); + return sysfs_emit(buf, "%d\n", st->pwr_down); } static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index d87e21016863c5b2e2a31df75e4dff8edd8a6109..488ec69967d671f842d6e89591a69508ac806064 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -100,7 +100,7 @@ static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5446_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->pwr_down); + return sysfs_emit(buf, "%d\n", st->pwr_down); } static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index e9297c25d4ef63b38c5407baadf47a10d8b0e716..19cdf9890d02ecb70e0abd68ecb3ae13e4b1946e 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -39,7 +39,7 @@ #define AD5504_DAC_PWRDN_3STATE 1 /** - * struct ad5446_state - driver instance specific data + * struct ad5504_state - driver instance specific data * @spi: spi_device * @reg: supply regulator * @vref_mv: actual reference voltage used @@ -170,8 +170,8 @@ static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5504_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", - !(st->pwr_down_mask & (1 << chan->channel))); + return sysfs_emit(buf, "%d\n", + !(st->pwr_down_mask & (1 << chan->channel))); } static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 2b2b8edfd258cb311ee2126bd609356496959917..9bde8698291211b09bf3f471994e3384764b0765 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -117,8 +117,8 @@ static ssize_t ad5624r_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5624r_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", - !!(st->pwr_down_mask & (1 << chan->channel))); + return sysfs_emit(buf, "%d\n", + !!(st->pwr_down_mask & (1 << chan->channel))); } static ssize_t ad5624r_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 7d6792ac10207bbdca5e2d5087f5498385792f43..fcb64f20ff64d182af02afd97f4e32f0589c253c 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -57,7 +57,7 @@ static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5686_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", !!(st->pwr_down_mask & + return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & (0x3 << (chan->channel * 2)))); } @@ -301,6 +301,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .num_channels = 8, .regmap_type = AD5686_REGMAP, }, + [ID_AD5673R] = { + .channels = ad5674r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, + }, [ID_AD5674R] = { .channels = ad5674r_channels, .int_vref_mv = 2500, @@ -324,6 +330,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .num_channels = 8, .regmap_type = AD5686_REGMAP, }, + [ID_AD5677R] = { + .channels = ad5679r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, + }, [ID_AD5679R] = { .channels = ad5679r_channels, .int_vref_mv = 2500, diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index d9c8ba413fe996cc736e933c64245e7f03c827fe..f89a6f92b4270673085f0a02480ecd8d2eda2e83 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -55,10 +55,12 @@ enum ad5686_supported_device_ids { ID_AD5338R, ID_AD5671R, ID_AD5672R, + ID_AD5673R, ID_AD5674R, ID_AD5675R, ID_AD5676, ID_AD5676R, + ID_AD5677R, ID_AD5679R, ID_AD5681R, ID_AD5682R, diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index a39eda7c02d23d509ab2aec0552310de602d1642..24a6a4a5a2e077c6ba6daaab4e67d2b8a17f1d3a 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R, - * AD5694, AD5694R, AD5695R, AD5696, AD5696R + * AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, + * AD5693R, AD5694, AD5694R, AD5695R, AD5696, AD5696R * Digital to analog converters driver * * Copyright 2018 Analog Devices Inc. @@ -74,7 +74,9 @@ static const struct i2c_device_id ad5686_i2c_id[] = { {"ad5311r", ID_AD5311R}, {"ad5338r", ID_AD5338R}, {"ad5671r", ID_AD5671R}, + {"ad5673r", ID_AD5673R}, {"ad5675r", ID_AD5675R}, + {"ad5677r", ID_AD5677R}, {"ad5691r", ID_AD5691R}, {"ad5692r", ID_AD5692R}, {"ad5693", ID_AD5693}, diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 0df28acf074a858cd3c3f73611eedb7ca449af29..cabc38d540854bf6d36ed44a664c72a993cc3f7a 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -399,8 +399,8 @@ static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv, { struct ad5755_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", - (bool)(st->pwr_down & (1 << chan->channel))); + return sysfs_emit(buf, "%d\n", + (bool)(st->pwr_down & (1 << chan->channel))); } static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv, diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c index bd9ac8359d986c6776f7642014017cd20aec90af..0572ef518101283c56063f1c370cbd217933f25e 100644 --- a/drivers/iio/dac/ad5758.c +++ b/drivers/iio/dac/ad5758.c @@ -574,7 +574,7 @@ static ssize_t ad5758_read_powerdown(struct iio_dev *indio_dev, { struct ad5758_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->pwr_down); + return sysfs_emit(buf, "%d\n", st->pwr_down); } static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index ef1618ea6a20c61d2c193513990b4deb9b3095da..79837a4b3a41e423eacc185bdea7be590da4fcb0 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -89,7 +89,7 @@ static const char * const ad5766_dither_scales[] = { /** * struct ad5766_state - driver instance specific data * @spi: SPI device - * @lock: Lock used to restrict concurent access to SPI device + * @lock: Lock used to restrict concurrent access to SPI device * @chip_info: Chip model specific constants * @gpio_reset: Reset GPIO, used to reset the device * @crt_range: Current selected output range diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index 84dcf149261f96adbba236cbef6086a290ba7aaa..7ab2ccf908639744c876f828015799529733e9a2 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -118,7 +118,7 @@ struct ad5770r_out_range { }; /** - * struct ad5770R_state - driver instance specific data + * struct ad5770r_state - driver instance specific data * @spi: spi_device * @regmap: regmap * @vref_reg: fixed regulator for reference configuration @@ -433,7 +433,7 @@ static ssize_t ad5770r_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5770r_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->ch_pwr_down[chan->channel]); + return sysfs_emit(buf, "%d\n", st->ch_pwr_down[chan->channel]); } static ssize_t ad5770r_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index e3ffa4b9f84cc29018ba5b6a39323e1f5f8fb764..a0923b76e8b65dbb6210447a9af205b33b8c7340 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -76,7 +76,7 @@ struct ad5791_chip_info { * @chip_info: chip model specific constants * @vref_mv: actual reference voltage used * @vref_neg_mv: voltage of the negative supply - * @ctrl: control regster cache + * @ctrl: control register cache * @pwr_down_mode: current power down mode * @pwr_down: true if device is powered down * @data: spi transfer buffers @@ -177,7 +177,7 @@ static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5791_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->pwr_down); + return sysfs_emit(buf, "%d\n", st->pwr_down); } static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index dbb4645ab6b1776653106a33efbabe74c91f8d9d..e1b6a92df12fbb91ea5823ceef9658f3fe123642 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -65,7 +65,7 @@ static ssize_t ad7303_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad7303_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", (bool)(st->config & + return sysfs_emit(buf, "%d\n", (bool)(st->config & AD7303_CFG_POWER_DOWN(chan->channel))); } diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index 4002ed0868be92ad049ff5b1520ec76edfa1b197..53e4b887d372d693c155e17ab387c8645968ef40 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -135,8 +135,8 @@ static ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev, { struct ltc2632_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", - !!(st->powerdown_cache_mask & (1 << chan->channel))); + return sysfs_emit(buf, "%d\n", + !!(st->powerdown_cache_mask & (1 << chan->channel))); } static ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index daa60386bf0c221c0302d582b14100e6576e1358..a6ef555153f4884161e7eb614ff04d3f4982e2a7 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -153,7 +153,6 @@ static int max517_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); data->client = client; switch (id->driver_data) { @@ -186,13 +185,7 @@ static int max517_probe(struct i2c_client *client, data->vref_mv[chan] = platform_data->vref_mv[chan]; } - return iio_device_register(indio_dev); -} - -static int max517_remove(struct i2c_client *client) -{ - iio_device_unregister(i2c_get_clientdata(client)); - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id max517_id[] = { @@ -211,7 +204,6 @@ static struct i2c_driver max517_driver = { .pm = &max517_pm_ops, }, .probe = max517_probe, - .remove = max517_remove, .id_table = max517_id, }; module_i2c_driver(max517_driver); diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index d6bb24db49c4132a362cecc87db8c669fc28b8fd..bd6e75699a636300a842a82457b9aae207699765 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -84,7 +84,7 @@ static ssize_t max5821_read_dac_powerdown(struct iio_dev *indio_dev, { struct max5821_data *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", st->powerdown[chan->channel]); + return sysfs_emit(buf, "%d\n", st->powerdown[chan->channel]); } static int max5821_sync_powerdown_mode(struct max5821_data *data, diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index beb9a15b7c74425cbb714529c53688fe4610f5ff..34b14aafb630188d0e1121cfae085fa8b8973506 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -167,7 +167,7 @@ static ssize_t mcp4725_read_powerdown(struct iio_dev *indio_dev, { struct mcp4725_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d\n", data->powerdown); + return sysfs_emit(buf, "%d\n", data->powerdown); } static ssize_t mcp4725_write_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 12dec68c16f71aa85f98e91e531acbddeaa3a495..a5b0a52bf86eb5687eb0f2062b129b66fe7b0f49 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -210,7 +210,7 @@ static ssize_t stm32_dac_read_powerdown(struct iio_dev *indio_dev, if (ret < 0) return ret; - return sprintf(buf, "%d\n", ret ? 0 : 1); + return sysfs_emit(buf, "%d\n", ret ? 0 : 1); } static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index de33c1fc6e0bd4492406036fe2e39ecac5add346..5c14bfb165219e4e37cb4753545507ef5081ae09 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -121,7 +121,7 @@ static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev, { struct ti_dac_chip *ti_dac = iio_priv(indio_dev); - return sprintf(buf, "%d\n", ti_dac->powerdown); + return sysfs_emit(buf, "%d\n", ti_dac->powerdown); } static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index d3295767a079c83d210143c4c92252f41650a0f9..2a5ba1b08a1d0af6c6aea10ea016a93a95381781 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -166,7 +166,7 @@ static ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev, { struct dac5571_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d\n", data->powerdown[chan->channel]); + return sysfs_emit(buf, "%d\n", data->powerdown[chan->channel]); } static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c index 63171e42f987a4417786f3c8fba132b6766fa74e..9d0b253be8413edd6b5d7bb520a9296b7807c0bd 100644 --- a/drivers/iio/dac/ti-dac7311.c +++ b/drivers/iio/dac/ti-dac7311.c @@ -110,7 +110,7 @@ static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev, { struct ti_dac_chip *ti_dac = iio_priv(indio_dev); - return sprintf(buf, "%d\n", ti_dac->powerdown); + return sysfs_emit(buf, "%d\n", ti_dac->powerdown); } static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev, diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c index 5512d5edc70737ad5cf174c2bf9e753128afdaae..59aa60d4ca370baafd0e7f0e164e5f5f0b89e468 100644 --- a/drivers/iio/dummy/iio_simple_dummy_buffer.c +++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c @@ -16,9 +16,9 @@ #include <linux/bitmap.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger_consumer.h> #include <linux/iio/buffer.h> -#include <linux/iio/kfifo_buf.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include "iio_simple_dummy.h" @@ -103,64 +103,9 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = { int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) { - int ret; - struct iio_buffer *buffer; - - /* Allocate a buffer to use - here a kfifo */ - buffer = iio_kfifo_allocate(); - if (!buffer) { - ret = -ENOMEM; - goto error_ret; - } - - iio_device_attach_buffer(indio_dev, buffer); - - /* - * Tell the core what device type specific functions should - * be run on either side of buffer capture enable / disable. - */ - indio_dev->setup_ops = &iio_simple_dummy_buffer_setup_ops; - - /* - * Configure a polling function. - * When a trigger event with this polling function connected - * occurs, this function is run. Typically this grabs data - * from the device. - * - * NULL for the bottom half. This is normally implemented only if we - * either want to ping a capture now pin (no sleeping) or grab - * a timestamp as close as possible to a data ready trigger firing. - * - * IRQF_ONESHOT ensures irqs are masked such that only one instance - * of the handler can run at a time. - * - * "iio_simple_dummy_consumer%d" formatting string for the irq 'name' - * as seen under /proc/interrupts. Remaining parameters as per printk. - */ - indio_dev->pollfunc = iio_alloc_pollfunc(NULL, - &iio_simple_dummy_trigger_h, - IRQF_ONESHOT, - indio_dev, - "iio_simple_dummy_consumer%d", - indio_dev->id); - - if (!indio_dev->pollfunc) { - ret = -ENOMEM; - goto error_free_buffer; - } - - /* - * Notify the core that this device is capable of buffered capture - * driven by a trigger. - */ - indio_dev->modes |= INDIO_BUFFER_TRIGGERED; - - return 0; - -error_free_buffer: - iio_kfifo_free(indio_dev->buffer); -error_ret: - return ret; + return iio_triggered_buffer_setup(indio_dev, NULL, + iio_simple_dummy_trigger_h, + &iio_simple_dummy_buffer_setup_ops); } /** @@ -169,6 +114,5 @@ error_ret: */ void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev) { - iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_kfifo_free(indio_dev->buffer); + iio_triggered_buffer_cleanup(indio_dev); } diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c index c45d8226cc2b165da09e345c3bc3d57d30aa1098..cec5e1f17c22a655671eec831ad1e52f9d078741 100644 --- a/drivers/iio/gyro/adxrs290.c +++ b/drivers/iio/gyro/adxrs290.c @@ -593,7 +593,6 @@ static int adxrs290_probe_trigger(struct iio_dev *indio_dev) if (!st->dready_trig) return -ENOMEM; - st->dready_trig->dev.parent = &st->spi->dev; st->dready_trig->ops = &adxrs290_trigger_ops; iio_trigger_set_drvdata(st->dready_trig, indio_dev); diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 029ef4c34604662e64385e856882a3acc58697f7..b11ebd9bb7a41839e44f88083036de9cffac07bf 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -1148,14 +1148,12 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, if (!data->motion_trig) return -ENOMEM; - data->dready_trig->dev.parent = dev; data->dready_trig->ops = &bmg160_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); ret = iio_trigger_register(data->dready_trig); if (ret) return ret; - data->motion_trig->dev.parent = dev; data->motion_trig->ops = &bmg160_trigger_ops; iio_trigger_set_drvdata(data->motion_trig, indio_dev); ret = iio_trigger_register(data->motion_trig); diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c index 129eead8febc0ea1a3a5b161296c822d355c7106..1a20c6b88e7db5cf3b28665ab25ab17c9c270882 100644 --- a/drivers/iio/gyro/fxas21002c_core.c +++ b/drivers/iio/gyro/fxas21002c_core.c @@ -875,7 +875,6 @@ static int fxas21002c_trigger_probe(struct fxas21002c_data *data) if (ret < 0) return ret; - data->dready_trig->dev.parent = dev; data->dready_trig->ops = &fxas21002c_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index fb0d678ece1a9e896f541691fb02c1c872bd2c64..dad26ee4fd1f432a79146832c021783bd63bcb3c 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -45,6 +45,10 @@ static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS }; +static const u32 gryo_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, +}; + /* Channel definitions */ static const struct iio_chan_spec gyro_3d_channels[] = { { @@ -271,17 +275,6 @@ static int gyro_3d_parse_report(struct platform_device *pdev, &st->gyro[CHANNEL_SCAN_INDEX_X], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -305,7 +298,9 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_GYRO_3D, - &gyro_state->common_attributes); + &gyro_state->common_attributes, + gryo_3d_sensitivity_addresses, + ARRAY_SIZE(gryo_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index 1c3c1bd53374a4b45aa1917319e1182d5ef4d636..af0aaa146f0cefdf5bc648119fa3bc2186f1821c 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -113,7 +113,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) int ret; struct itg3200 *st = iio_priv(indio_dev); - st->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + st->trig = iio_trigger_alloc(&st->i2c->dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!st->trig) return -ENOMEM; @@ -127,7 +127,6 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) goto error_free_trig; - st->trig->dev.parent = &st->i2c->dev; st->trig->ops = &itg3200_trigger_ops; iio_trigger_set_drvdata(st->trig, indio_dev); ret = iio_trigger_register(st->trig); diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c index ac7c170a20de82dc60d7ade95e7da5c68a944686..46ed12771d2fe84221aa2267e95617f21704ae56 100644 --- a/drivers/iio/gyro/ssp_gyro_sensor.c +++ b/drivers/iio/gyro/ssp_gyro_sensor.c @@ -96,7 +96,6 @@ static int ssp_gyro_probe(struct platform_device *pdev) int ret; struct iio_dev *indio_dev; struct ssp_sensor_data *spd; - struct iio_buffer *buffer; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd)); if (!indio_dev) @@ -109,18 +108,15 @@ static int ssp_gyro_probe(struct platform_device *pdev) indio_dev->name = ssp_gyro_name; indio_dev->info = &ssp_gyro_iio_info; - indio_dev->modes = INDIO_BUFFER_SOFTWARE; indio_dev->channels = ssp_gyro_channels; indio_dev->num_channels = ARRAY_SIZE(ssp_gyro_channels); indio_dev->available_scan_masks = ssp_gyro_scan_mask; - buffer = devm_iio_kfifo_allocate(&pdev->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - - indio_dev->setup_ops = &ssp_gyro_buffer_ops; + ret = devm_iio_kfifo_buffer_setup(&pdev->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &ssp_gyro_buffer_ops); + if (ret) + return ret; platform_set_drvdata(pdev, indio_dev); diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 38734e4ce360570215f352a69ce0e9a3bf9b6443..1fa8d51d50806d3559c3b618101cd19514b42d99 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -531,7 +531,6 @@ static int afe4403_probe(struct spi_device *spi) iio_trigger_set_drvdata(afe->trig, indio_dev); afe->trig->ops = &afe4403_trigger_ops; - afe->trig->dev.parent = afe->dev; ret = iio_trigger_register(afe->trig); if (ret) { diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 61fe4932d81d02269a7b5f776a037da83724b952..e1476bf79fe2a22a00602bd65f5e5696ddc3bcc7 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -538,7 +538,6 @@ static int afe4404_probe(struct i2c_client *client, iio_trigger_set_drvdata(afe->trig, indio_dev); afe->trig->ops = &afe4404_trigger_ops; - afe->trig->dev.parent = afe->dev; ret = iio_trigger_register(afe->trig); if (ret) { diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 38aa2030f3c62d2adcda79c68c0b236183155f8c..36ba7611d9ceb58a1711d7a30b807e0e8fe3fdbe 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -418,7 +418,6 @@ static int max30100_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max30100_data *data; - struct iio_buffer *buffer; struct iio_dev *indio_dev; int ret; @@ -426,19 +425,18 @@ static int max30100_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; - buffer = devm_iio_kfifo_allocate(&client->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->name = MAX30100_DRV_NAME; indio_dev->channels = max30100_channels; indio_dev->info = &max30100_info; indio_dev->num_channels = ARRAY_SIZE(max30100_channels); indio_dev->available_scan_masks = max30100_scan_masks; - indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); - indio_dev->setup_ops = &max30100_buffer_setup_ops; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &max30100_buffer_setup_ops); + if (ret) + return ret; data = iio_priv(indio_dev); data->indio_dev = indio_dev; diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index b35557a54ee269f5750c3e12549c421d3a9566d3..2292876c55e2dc67d71919c29e1f94e3a4fd6929 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -506,7 +506,6 @@ static int max30102_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max30102_data *data; - struct iio_buffer *buffer; struct iio_dev *indio_dev; int ret; unsigned int reg; @@ -515,16 +514,9 @@ static int max30102_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; - buffer = devm_iio_kfifo_allocate(&client->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->name = MAX30102_DRV_NAME; indio_dev->info = &max30102_info; - indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); - indio_dev->setup_ops = &max30102_buffer_setup_ops; + indio_dev->modes = INDIO_DIRECT_MODE; data = iio_priv(indio_dev); data->indio_dev = indio_dev; @@ -549,6 +541,12 @@ static int max30102_probe(struct i2c_client *client, return -ENODEV; } + ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &max30102_buffer_setup_ops); + if (ret) + return ret; + data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config); if (IS_ERR(data->regmap)) { dev_err(&client->dev, "regmap initialization failed\n"); diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 02ad1767c845e8dccc26e6727881d5301cf9d5f2..23bc9c784ef4bb463ce888381312f9ab5b51e454 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Aosong AM2315 relative humidity and temperature * * Copyright (c) 2016, Intel Corporation. diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index d62705448ae2563e0defd707ee6345478fbe3210..74383abc0d446ead9fdb93c966f5f5229b2d1c35 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -25,6 +25,10 @@ struct hid_humidity_state { int value_offset; }; +static const u32 humidity_sensitivity_addresses[] = { + HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, +}; + /* Channel definitions */ static const struct iio_chan_spec humidity_channels[] = { { @@ -176,14 +180,6 @@ static int humidity_parse_report(struct platform_device *pdev, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, - &st->common_attributes.sensitivity); - return ret; } @@ -212,7 +208,9 @@ static int hid_humidity_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_HUMIDITY, - &humid_st->common_attributes); + &humid_st->common_attributes, + humidity_sensitivity_addresses, + ARRAY_SIZE(humidity_sensitivity_addresses)); if (ret) return ret; diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c index 95e56917677faea5ac20410418653962ad329659..f29692b9d2db0e39704991dcdcff07bae184fb25 100644 --- a/drivers/iio/humidity/hts221_buffer.c +++ b/drivers/iio/humidity/hts221_buffer.c @@ -135,7 +135,6 @@ int hts221_allocate_trigger(struct iio_dev *iio_dev) iio_trigger_set_drvdata(hw->trig, iio_dev); hw->trig->ops = &hts221_trigger_ops; - hw->trig->dev.parent = hw->dev; iio_dev->trig = iio_trigger_get(hw->trig); return devm_iio_trigger_register(hw->dev, hw->trig); diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index fced02cadcc3c1ac67f3956e05f888d56bbc71db..8f4a9b264962e8580b04e785a484132ca70cfa77 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -12,11 +12,17 @@ #include <linux/kernel.h> #include <linux/device.h> +struct iio_buffer; struct iio_chan_spec; struct iio_dev; extern struct device_type iio_device_type; +struct iio_dev_buffer_pair { + struct iio_dev *indio_dev; + struct iio_buffer *buffer; +}; + #define IIO_IOCTL_UNHANDLED 1 struct iio_ioctl_handler { struct list_head entry; @@ -43,9 +49,13 @@ int __iio_add_chan_devattr(const char *postfix, u64 mask, enum iio_shared_by shared_by, struct device *dev, + struct iio_buffer *buffer, struct list_head *attr_list); void iio_free_chan_devattr_list(struct list_head *attr_list); +int iio_device_register_sysfs_group(struct iio_dev *indio_dev, + const struct attribute_group *group); + ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); /* Event interface flags */ @@ -54,34 +64,36 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); #ifdef CONFIG_IIO_BUFFER struct poll_table_struct; -__poll_t iio_buffer_poll(struct file *filp, - struct poll_table_struct *wait); -ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, - size_t n, loff_t *f_ps); +__poll_t iio_buffer_poll_wrapper(struct file *filp, + struct poll_table_struct *wait); +ssize_t iio_buffer_read_wrapper(struct file *filp, char __user *buf, + size_t n, loff_t *f_ps); -int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev); -void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev); +int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev); +void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev); -#define iio_buffer_poll_addr (&iio_buffer_poll) -#define iio_buffer_read_outer_addr (&iio_buffer_read_outer) +#define iio_buffer_poll_addr (&iio_buffer_poll_wrapper) +#define iio_buffer_read_outer_addr (&iio_buffer_read_wrapper) void iio_disable_all_buffers(struct iio_dev *indio_dev); void iio_buffer_wakeup_poll(struct iio_dev *indio_dev); +void iio_device_detach_buffers(struct iio_dev *indio_dev); #else #define iio_buffer_poll_addr NULL #define iio_buffer_read_outer_addr NULL -static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) +static inline int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) { return 0; } -static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {} +static inline void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) {} static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {} static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {} +static inline void iio_device_detach_buffers(struct iio_dev *indio_dev) {} #endif diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h index 374816bc3e7371305d6bd35e4f0bc8db142314ec..e1a56824e07fe44f727601169d748b6e147ec99b 100644 --- a/drivers/iio/iio_core_trigger.h +++ b/drivers/iio/iio_core_trigger.h @@ -9,8 +9,10 @@ /** * iio_device_register_trigger_consumer() - set up an iio_dev to use triggers * @indio_dev: iio_dev associated with the device that will consume the trigger + * + * Return 0 if successful, negative otherwise **/ -void iio_device_register_trigger_consumer(struct iio_dev *indio_dev); +int iio_device_register_trigger_consumer(struct iio_dev *indio_dev); /** * iio_device_unregister_trigger_consumer() - reverse the registration process diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 785a4ce606d89a139db19741922477446b3b832e..768aa493a1a60d36bf240b0abffa671d46b6415b 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -504,7 +504,6 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); - struct mutex *slock = &st->adis.state_lock; int ret, sps; switch (info) { @@ -517,18 +516,18 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, * Need to cache values so we can update if the frequency * changes. */ - mutex_lock(slock); + adis_dev_lock(&st->adis); st->filt_int = val; /* Work out update to current value */ sps = st->variant->get_freq(st); if (sps < 0) { - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return sps; } ret = __adis16400_set_filter(indio_dev, sps, val * 1000 + val2 / 1000); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; case IIO_CHAN_INFO_SAMP_FREQ: sps = val * 1000 + val2 / 1000; @@ -536,9 +535,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, if (sps <= 0) return -EINVAL; - mutex_lock(slock); + adis_dev_lock(&st->adis); ret = st->variant->set_freq(st, sps); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; default: return -EINVAL; @@ -549,7 +548,6 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); - struct mutex *slock = &st->adis.state_lock; int16_t val16; int ret; @@ -605,17 +603,17 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = st->variant->temp_offset; return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(slock); + adis_dev_lock(&st->adis); /* Need both the number of taps and the sampling frequency */ ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); if (ret) { - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; } ret = st->variant->get_freq(st); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); if (ret) return ret; ret /= adis16400_3db_divisors[val16 & 0x07]; @@ -623,9 +621,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(slock); + adis_dev_lock(&st->adis); ret = st->variant->get_freq(st); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); if (ret) return ret; *val = ret / 1000; diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index 74a161e3973323ae408e0c20fdbe23bb8187c9ab..73bf45e859b848ad4f543b010eafe44b4590e2b4 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -403,12 +403,12 @@ static int adis16460_probe(struct spi_device *spi) if (ret) return ret; + /* We cannot mask the interrupt, so ensure it isn't auto enabled */ + st->adis.irq_flag |= IRQF_NO_AUTOEN; ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); if (ret) return ret; - adis16460_enable_irq(&st->adis, 0); - ret = __adis_initial_startup(&st->adis); if (ret) return ret; diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 197d482409911ab34b01b1e2f5ea2e36a9acc40b..1de62fc79e0fc4a2d224821eed08d9bc5d9615f9 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -17,6 +17,8 @@ #include <linux/iio/sysfs.h> #include <linux/iio/trigger_consumer.h> #include <linux/irq.h> +#include <linux/lcm.h> +#include <linux/math.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/property.h> @@ -101,6 +103,7 @@ struct adis16475 { u32 clk_freq; bool burst32; unsigned long lsb_flag; + u16 sync_mode; /* Alignment needed for the timestamp */ __be16 data[ADIS16475_MAX_SCAN_DATA] __aligned(8); }; @@ -117,6 +120,11 @@ enum { ADIS16475_SCAN_CRC_FAILURE, }; +static bool low_rate_allow; +module_param(low_rate_allow, bool, 0444); +MODULE_PARM_DESC(low_rate_allow, + "Allow IMU rates below the minimum advisable when external clk is used in SCALED mode (default: N)"); + #ifdef CONFIG_DEBUG_FS static ssize_t adis16475_show_firmware_revision(struct file *file, char __user *userbuf, @@ -253,25 +261,92 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq) { int ret; u16 dec; + u32 sample_rate = st->clk_freq; + + adis_dev_lock(&st->adis); + + if (st->sync_mode == ADIS16475_SYNC_SCALED) { + u16 sync_scale; + + ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, &sync_scale); + if (ret) + goto error; + + sample_rate = st->clk_freq * sync_scale; + } - ret = adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec); + ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec); if (ret) - return -EINVAL; + goto error; + + adis_dev_unlock(&st->adis); - *freq = DIV_ROUND_CLOSEST(st->clk_freq, dec + 1); + *freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1); return 0; +error: + adis_dev_unlock(&st->adis); + return ret; } static int adis16475_set_freq(struct adis16475 *st, const u32 freq) { u16 dec; int ret; + u32 sample_rate = st->clk_freq; if (!freq) return -EINVAL; - dec = DIV_ROUND_CLOSEST(st->clk_freq, freq); + adis_dev_lock(&st->adis); + /* + * When using sync scaled mode, the input clock needs to be scaled so that we have + * an IMU sample rate between (optimally) 1900 and 2100. After this, we can use the + * decimation filter to lower the sampling rate in order to get what the user wants. + * Optimally, the user sample rate is a multiple of both the IMU sample rate and + * the input clock. Hence, calculating the sync_scale dynamically gives us better + * chances of achieving a perfect/integer value for DEC_RATE. The math here is: + * 1. lcm of the input clock and the desired output rate. + * 2. get the highest multiple of the previous result lower than the adis max rate. + * 3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE + * and DEC_RATE (to get the user output rate) + */ + if (st->sync_mode == ADIS16475_SYNC_SCALED) { + unsigned long scaled_rate = lcm(st->clk_freq, freq); + int sync_scale; + + /* + * If lcm is bigger than the IMU maximum sampling rate there's no perfect + * solution. In this case, we get the highest multiple of the input clock + * lower than the IMU max sample rate. + */ + if (scaled_rate > 2100000) + scaled_rate = 2100000 / st->clk_freq * st->clk_freq; + else + scaled_rate = 2100000 / scaled_rate * scaled_rate; + + /* + * This is not an hard requirement but it's not advised to run the IMU + * with a sample rate lower than 4000Hz due to possible undersampling + * issues. However, there are users that might really want to take the risk. + * Hence, we provide a module parameter for them. If set, we allow sample + * rates lower than 4KHz. By default, we won't allow this and we just roundup + * the rate to the next multiple of the input clock bigger than 4KHz. This + * is done like this as in some cases (when DEC_RATE is 0) might give + * us the closest value to the one desired by the user... + */ + if (scaled_rate < 1900000 && !low_rate_allow) + scaled_rate = roundup(1900000, st->clk_freq); + + sync_scale = scaled_rate / st->clk_freq; + ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale); + if (ret) + goto error; + + sample_rate = scaled_rate; + } + + dec = DIV_ROUND_CLOSEST(sample_rate, freq); if (dec) dec--; @@ -281,7 +356,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) ret = adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec); if (ret) - return ret; + goto error; /* * If decimation is used, then gyro and accel data will have meaningful @@ -290,6 +365,9 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) assign_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag, dec); return 0; +error: + adis_dev_unlock(&st->adis); + return ret; } /* The values are approximated. */ @@ -1085,6 +1163,7 @@ static int adis16475_config_sync_mode(struct adis16475 *st) } sync = &st->info->sync[sync_mode]; + st->sync_mode = sync->sync_mode; /* All the other modes require external input signal */ if (sync->sync_mode != ADIS16475_SYNC_OUTPUT) { @@ -1112,37 +1191,20 @@ static int adis16475_config_sync_mode(struct adis16475 *st) if (sync->sync_mode == ADIS16475_SYNC_SCALED) { u16 up_scale; - u32 scaled_out_freq = 0; + /* - * If we are in scaled mode, we must have an up_scale. - * In scaled mode the allowable input clock range is - * 1 Hz to 128 Hz, and the allowable output range is - * 1900 to 2100 Hz. Hence, a scale must be given to - * get the allowable output. + * In sync scaled mode, the IMU sample rate is the clk_freq * sync_scale. + * Hence, default the IMU sample rate to the highest multiple of the input + * clock lower than the IMU max sample rate. The optimal range is + * 1900-2100 sps... */ - ret = device_property_read_u32(dev, - "adi,scaled-output-hz", - &scaled_out_freq); - if (ret) { - dev_err(dev, "adi,scaled-output-hz must be given when in scaled sync mode"); - return -EINVAL; - } else if (scaled_out_freq < 1900 || - scaled_out_freq > 2100) { - dev_err(dev, "Invalid value: %u for adi,scaled-output-hz", - scaled_out_freq); - return -EINVAL; - } - - up_scale = DIV_ROUND_CLOSEST(scaled_out_freq, - st->clk_freq); + up_scale = 2100 / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, up_scale); if (ret) return ret; - - st->clk_freq = scaled_out_freq; } st->clk_freq *= 1000; @@ -1196,6 +1258,9 @@ static int adis16475_config_irq_pin(struct adis16475 *st) return -EINVAL; } + /* We cannot mask the interrupt so ensure it's not enabled at request */ + st->adis.irq_flag |= IRQF_NO_AUTOEN; + val = ADIS16475_MSG_CTRL_DR_POL(polarity); ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL, ADIS16475_MSG_CTRL_DR_POL_MASK, val); @@ -1300,8 +1365,6 @@ static int adis16475_probe(struct spi_device *spi) if (ret) return ret; - adis16475_enable_irq(&st->adis, false); - ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret) return ret; diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index dfe86c5893254057503b6c2e84933a614add79dc..f81b86690b76b5e4cb735e666d4c980aefc1930e 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -10,6 +10,7 @@ #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/math.h> #include <linux/mutex.h> #include <linux/device.h> #include <linux/kernel.h> @@ -17,6 +18,7 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/module.h> +#include <linux/lcm.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -170,6 +172,11 @@ static const char * const adis16480_int_pin_names[4] = { [ADIS16480_PIN_DIO4] = "DIO4", }; +static bool low_rate_allow; +module_param(low_rate_allow, bool, 0444); +MODULE_PARM_DESC(low_rate_allow, + "Allow IMU rates below the minimum advisable when external clk is used in PPS mode (default: N)"); + #ifdef CONFIG_DEBUG_FS static ssize_t adis16480_show_firmware_revision(struct file *file, @@ -312,7 +319,8 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev) static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) { struct adis16480 *st = iio_priv(indio_dev); - unsigned int t, reg; + unsigned int t, sample_rate = st->clk_freq; + int ret; if (val < 0 || val2 < 0) return -EINVAL; @@ -321,28 +329,65 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) if (t == 0) return -EINVAL; + adis_dev_lock(&st->adis); /* - * When using PPS mode, the rate of data collection is equal to the - * product of the external clock frequency and the scale factor in the - * SYNC_SCALE register. - * When using sync mode, or internal clock, the output data rate is - * equal with the clock frequency divided by DEC_RATE + 1. + * When using PPS mode, the input clock needs to be scaled so that we have an IMU + * sample rate between (optimally) 4000 and 4250. After this, we can use the + * decimation filter to lower the sampling rate in order to get what the user wants. + * Optimally, the user sample rate is a multiple of both the IMU sample rate and + * the input clock. Hence, calculating the sync_scale dynamically gives us better + * chances of achieving a perfect/integer value for DEC_RATE. The math here is: + * 1. lcm of the input clock and the desired output rate. + * 2. get the highest multiple of the previous result lower than the adis max rate. + * 3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE + * and DEC_RATE (to get the user output rate) */ if (st->clk_mode == ADIS16480_CLK_PPS) { - t = t / st->clk_freq; - reg = ADIS16495_REG_SYNC_SCALE; - } else { - t = st->clk_freq / t; - reg = ADIS16480_REG_DEC_RATE; + unsigned long scaled_rate = lcm(st->clk_freq, t); + int sync_scale; + + /* + * If lcm is bigger than the IMU maximum sampling rate there's no perfect + * solution. In this case, we get the highest multiple of the input clock + * lower than the IMU max sample rate. + */ + if (scaled_rate > st->chip_info->int_clk) + scaled_rate = st->chip_info->int_clk / st->clk_freq * st->clk_freq; + else + scaled_rate = st->chip_info->int_clk / scaled_rate * scaled_rate; + + /* + * This is not an hard requirement but it's not advised to run the IMU + * with a sample rate lower than 4000Hz due to possible undersampling + * issues. However, there are users that might really want to take the risk. + * Hence, we provide a module parameter for them. If set, we allow sample + * rates lower than 4KHz. By default, we won't allow this and we just roundup + * the rate to the next multiple of the input clock bigger than 4KHz. This + * is done like this as in some cases (when DEC_RATE is 0) might give + * us the closest value to the one desired by the user... + */ + if (scaled_rate < 4000000 && !low_rate_allow) + scaled_rate = roundup(4000000, st->clk_freq); + + sync_scale = scaled_rate / st->clk_freq; + ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale); + if (ret) + goto error; + + sample_rate = scaled_rate; } + t = DIV_ROUND_CLOSEST(sample_rate, t); + if (t) + t--; + if (t > st->chip_info->max_dec_rate) t = st->chip_info->max_dec_rate; - if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS)) - t--; - - return adis_write_reg_16(&st->adis, reg, t); + ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); +error: + adis_dev_unlock(&st->adis); + return ret; } static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) @@ -350,34 +395,35 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) struct adis16480 *st = iio_priv(indio_dev); uint16_t t; int ret; - unsigned int freq; - unsigned int reg; + unsigned int freq, sample_rate = st->clk_freq; - if (st->clk_mode == ADIS16480_CLK_PPS) - reg = ADIS16495_REG_SYNC_SCALE; - else - reg = ADIS16480_REG_DEC_RATE; + adis_dev_lock(&st->adis); + + if (st->clk_mode == ADIS16480_CLK_PPS) { + u16 sync_scale; + + ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale); + if (ret) + goto error; - ret = adis_read_reg_16(&st->adis, reg, &t); + sample_rate = st->clk_freq * sync_scale; + } + + ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); if (ret) - return ret; + goto error; - /* - * When using PPS mode, the rate of data collection is equal to the - * product of the external clock frequency and the scale factor in the - * SYNC_SCALE register. - * When using sync mode, or internal clock, the output data rate is - * equal with the clock frequency divided by DEC_RATE + 1. - */ - if (st->clk_mode == ADIS16480_CLK_PPS) - freq = st->clk_freq * t; - else - freq = st->clk_freq / (t + 1); + adis_dev_unlock(&st->adis); + + freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1)); *val = freq / 1000; *val2 = (freq % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; +error: + adis_dev_unlock(&st->adis); + return ret; } enum { @@ -552,7 +598,6 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int freq) { struct adis16480 *st = iio_priv(indio_dev); - struct mutex *slock = &st->adis.state_lock; unsigned int enable_mask, offset, reg; unsigned int diff, best_diff; unsigned int i, best_freq; @@ -563,7 +608,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, offset = ad16480_filter_data[chan->scan_index][1]; enable_mask = BIT(offset + 2); - mutex_lock(slock); + adis_dev_lock(&st->adis); ret = __adis_read_reg_16(&st->adis, reg, &val); if (ret) @@ -591,7 +636,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, ret = __adis_write_reg_16(&st->adis, reg, val); out_unlock: - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; } @@ -1278,6 +1323,20 @@ static int adis16480_probe(struct spi_device *spi) st->clk_freq = clk_get_rate(st->ext_clk); st->clk_freq *= 1000; /* micro */ + if (st->clk_mode == ADIS16480_CLK_PPS) { + u16 sync_scale; + + /* + * In PPS mode, the IMU sample rate is the clk_freq * sync_scale. Hence, + * default the IMU sample rate to the highest multiple of the input clock + * lower than the IMU max sample rate. The internal sample rate is the + * max... + */ + sync_scale = st->chip_info->int_clk / st->clk_freq; + ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale); + if (ret) + return ret; + } } else { st->clk_freq = st->chip_info->int_clk; } diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index 64e0ba51cb18e3df5c625392bd88cf80c0ca7f70..fa5540fabaccdc67b562f39e39cd601f338c0bde 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -27,27 +27,21 @@ static const struct iio_trigger_ops adis_trigger_ops = { .set_trigger_state = &adis_data_rdy_trigger_set_state, }; -static void adis_trigger_setup(struct adis *adis) -{ - adis->trig->dev.parent = &adis->spi->dev; - adis->trig->ops = &adis_trigger_ops; - iio_trigger_set_drvdata(adis->trig, adis); -} - static int adis_validate_irq_flag(struct adis *adis) { + unsigned long direction = adis->irq_flag & IRQF_TRIGGER_MASK; /* * Typically this devices have data ready either on the rising edge or * on the falling edge of the data ready pin. This checks enforces that * one of those is set in the drivers... It defaults to - * IRQF_TRIGGER_RISING for backward compatibility wiht devices that + * IRQF_TRIGGER_RISING for backward compatibility with devices that * don't support changing the pin polarity. */ - if (!adis->irq_flag) { - adis->irq_flag = IRQF_TRIGGER_RISING; + if (direction == IRQF_TRIGGER_NONE) { + adis->irq_flag |= IRQF_TRIGGER_RISING; return 0; - } else if (adis->irq_flag != IRQF_TRIGGER_RISING && - adis->irq_flag != IRQF_TRIGGER_FALLING) { + } else if (direction != IRQF_TRIGGER_RISING && + direction != IRQF_TRIGGER_FALLING) { dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n", adis->irq_flag); return -EINVAL; @@ -72,7 +66,8 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (!adis->trig) return -ENOMEM; - adis_trigger_setup(adis); + adis->trig->ops = &adis_trigger_ops; + iio_trigger_set_drvdata(adis->trig, adis); ret = adis_validate_irq_flag(adis); if (ret) diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index 3ceb76366313282a1c09918d8d9d5b79adba0e1d..40a570325b0aca3b7c6783d6ae121b30409732d3 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -26,8 +26,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c index 57e7bb6444e7a4b4b77568291a096425feab47df..27e694cce173e05f2312c4b8b6ef6a0a1cc40d0a 100644 --- a/drivers/iio/imu/fxos8700_spi.c +++ b/drivers/iio/imu/fxos8700_spi.c @@ -17,8 +17,7 @@ static int fxos8700_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 3441b0d61c5d53b29222be147597af2ccb9ba931..383cc32503425562b0ed28bff76e3737321ea69a 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -709,7 +709,6 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) const char *name; struct inv_icm42600_timestamp *ts; struct iio_dev *indio_dev; - struct iio_buffer *buffer; int ret; name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name); @@ -720,23 +719,22 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) if (!indio_dev) return ERR_PTR(-ENOMEM); - buffer = devm_iio_kfifo_allocate(dev); - if (!buffer) - return ERR_PTR(-ENOMEM); - ts = iio_priv(indio_dev); inv_icm42600_timestamp_init(ts, inv_icm42600_odr_to_period(st->conf.accel.odr)); iio_device_set_drvdata(indio_dev, st); indio_dev->name = name; indio_dev->info = &inv_icm42600_accel_info; - indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = inv_icm42600_accel_channels; indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels); indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks; - indio_dev->setup_ops = &inv_icm42600_buffer_ops; - iio_device_attach_buffer(indio_dev, buffer); + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &inv_icm42600_buffer_ops); + if (ret) + return ERR_PTR(ret); ret = devm_iio_device_register(dev, indio_dev); if (ret) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index aee7b9ff4bf4f2aae9994ee18f8149b6da687000..cec1dd0e04646b6486a2ec17b2a483a7edd73f45 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -720,7 +720,6 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) const char *name; struct inv_icm42600_timestamp *ts; struct iio_dev *indio_dev; - struct iio_buffer *buffer; int ret; name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name); @@ -731,23 +730,23 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) if (!indio_dev) return ERR_PTR(-ENOMEM); - buffer = devm_iio_kfifo_allocate(dev); - if (!buffer) - return ERR_PTR(-ENOMEM); - ts = iio_priv(indio_dev); inv_icm42600_timestamp_init(ts, inv_icm42600_odr_to_period(st->conf.gyro.odr)); iio_device_set_drvdata(indio_dev, st); indio_dev->name = name; indio_dev->info = &inv_icm42600_gyro_info; - indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = inv_icm42600_gyro_channels; indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_gyro_channels); indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks; indio_dev->setup_ops = &inv_icm42600_buffer_ops; - iio_device_attach_buffer(indio_dev, buffer); + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &inv_icm42600_buffer_ops); + if (ret) + return ERR_PTR(ret); ret = devm_iio_device_register(dev, indio_dev); if (ret) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 453c51c79655574aff194b34f40338f0fa5caded..6244a07048df895cc9a8bd62c820187d0894d7f4 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -731,12 +731,16 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, } } -static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val) +static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val, + int val2) { int result, i; + if (val != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) { - if (gyro_scale_6050[i] == val) { + if (gyro_scale_6050[i] == val2) { result = inv_mpu6050_set_gyro_fsr(st, i); if (result) return result; @@ -767,13 +771,17 @@ static int inv_write_raw_get_fmt(struct iio_dev *indio_dev, return -EINVAL; } -static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val) +static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val, + int val2) { int result, i; u8 d; + if (val != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) { - if (accel_scale[i] == val) { + if (accel_scale[i] == val2) { d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); result = regmap_write(st->map, st->reg->accl_config, d); if (result) @@ -814,10 +822,10 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - result = inv_mpu6050_write_gyro_scale(st, val2); + result = inv_mpu6050_write_gyro_scale(st, val, val2); break; case IIO_ACCEL: - result = inv_mpu6050_write_accel_scale(st, val2); + result = inv_mpu6050_write_accel_scale(st, val, val2); break; default: result = -EINVAL; @@ -1458,15 +1466,21 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, st->plat_data = *pdata; } - desc = irq_get_irq_data(irq); - if (!desc) { - dev_err(dev, "Could not find IRQ %d\n", irq); - return -EINVAL; - } + 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); - if (!irq_type) + irq_type = irqd_get_trigger_type(desc); + if (!irq_type) + irq_type = IRQF_TRIGGER_RISING; + } else { + /* Doesn't really matter, use the default */ irq_type = IRQF_TRIGGER_RISING; + } + if (irq_type & IRQF_TRIGGER_RISING) // rising or both-edge st->irq_mask = INV_MPU6050_ACTIVE_HIGH; else if (irq_type == IRQF_TRIGGER_FALLING) @@ -1591,20 +1605,26 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, } indio_dev->info = &mpu_info; - indio_dev->modes = INDIO_BUFFER_TRIGGERED; - result = devm_iio_triggered_buffer_setup(dev, indio_dev, - iio_pollfunc_store_time, - inv_mpu6050_read_fifo, - NULL); - if (result) { - dev_err(dev, "configure buffer fail %d\n", result); - return result; - } - result = inv_mpu6050_probe_trigger(indio_dev, irq_type); - if (result) { - dev_err(dev, "trigger probe fail %d\n", result); - return result; + if (irq > 0) { + /* + * The driver currently only supports buffered capture with its + * own trigger. So no IRQ, no trigger, no buffer + */ + result = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + inv_mpu6050_read_fifo, + NULL); + if (result) { + dev_err(dev, "configure buffer fail %d\n", result); + return result; + } + + result = inv_mpu6050_probe_trigger(indio_dev, irq_type); + if (result) { + dev_err(dev, "trigger probe fail %d\n", result); + return result; + } } result = devm_iio_device_register(dev, indio_dev); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index f7b5a70be30f92758096f5ee7cf57822ade0a702..de8ed1446d60bac7dbbeb0d44fb218015d7d7551 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -11,6 +11,16 @@ static unsigned int inv_scan_query_mpu6050(struct iio_dev *indio_dev) struct inv_mpu6050_state *st = iio_priv(indio_dev); unsigned int mask; + /* + * If the MPU6050 is just used as a trigger, then the scan mask + * is not allocated so we simply enable the temperature channel + * as a dummy and bail out. + */ + if (!indio_dev->active_scan_mask) { + st->chip_config.temp_fifo_enable = true; + return INV_MPU6050_SENSOR_TEMP; + } + st->chip_config.gyro_fifo_enable = test_bit(INV_MPU6050_SCAN_GYRO_X, indio_dev->active_scan_mask) || diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 4377047d503abe7c2d7df0c35c02606a0c7e283d..fc5a60fcfec054a4eb539517a3291ff4f9530a5d 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1268,7 +1268,6 @@ static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data, if (!trig) return ERR_PTR(-ENOMEM); - trig->dev.parent = &data->client->dev; trig->ops = &kmx61_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index f1103ecedd6494b2d1165708d8e65e24a81fbda5..16730a7809643695d838187d8bf2d6227c86404d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -739,20 +739,17 @@ static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = { int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) { - struct iio_buffer *buffer; - int i; + int i, ret; for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { if (!hw->iio_devs[i]) continue; - buffer = devm_iio_kfifo_allocate(hw->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(hw->iio_devs[i], buffer); - hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE; - hw->iio_devs[i]->setup_ops = &st_lsm6dsx_buffer_ops; + ret = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i], + INDIO_BUFFER_SOFTWARE, + &st_lsm6dsx_buffer_ops); + if (ret) + return ret; } return 0; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index ec8d4351390aa034b01856cc741304b946ec7e8e..8b4fc2c156220931aedf84d639cf3d6e92387b0a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -29,8 +29,7 @@ static int st_lsm6dsx_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &st_lsm6dsx_i2c_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c index 57e633121bdc0dbb039884dbdb53d6be5ad84b0e..8d4201b86e87c337b441890fc8eb1afa7b458276 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -34,8 +34,7 @@ static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); if (IS_ERR(regmap)) { - dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&i3cdev->dev, "Failed to register i3c regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 349ec9c1890dd86038b3b80cfbff817cf2ea12fd..e80110b6b280f2bc46254dd0dd9286f63fba99af 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -29,8 +29,7 @@ static int st_lsm6dsx_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &st_lsm6dsx_spi_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 2f7426a2f47ca571a73851a51ba0c22bb6334996..9a8e16c7e9afe5d85d0510c06d90660731850a29 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -9,9 +9,11 @@ * - Better memory allocation techniques? * - Alternative access techniques? */ +#include <linux/anon_inodes.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/device.h> +#include <linux/file.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/slab.h> @@ -89,7 +91,7 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, } /** - * iio_buffer_read_outer() - chrdev read for buffer access + * iio_buffer_read() - chrdev read for buffer access * @filp: File structure pointer for the char device * @buf: Destination buffer for iio buffer read * @n: First n bytes to read @@ -101,11 +103,12 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, * Return: negative values corresponding to error codes or ret != 0 * for ending the reading activity **/ -ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, - size_t n, loff_t *f_ps) +static ssize_t iio_buffer_read(struct file *filp, char __user *buf, + size_t n, loff_t *f_ps) { - struct iio_dev *indio_dev = filp->private_data; - struct iio_buffer *rb = indio_dev->buffer; + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_buffer *rb = ib->buffer; + struct iio_dev *indio_dev = ib->indio_dev; DEFINE_WAIT_FUNC(wait, woken_wake_function); size_t datum_size; size_t to_wait; @@ -167,11 +170,12 @@ ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, * Return: (EPOLLIN | EPOLLRDNORM) if data is available for reading * or 0 for other cases */ -__poll_t iio_buffer_poll(struct file *filp, - struct poll_table_struct *wait) +static __poll_t iio_buffer_poll(struct file *filp, + struct poll_table_struct *wait) { - struct iio_dev *indio_dev = filp->private_data; - struct iio_buffer *rb = indio_dev->buffer; + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_buffer *rb = ib->buffer; + struct iio_dev *indio_dev = ib->indio_dev; if (!indio_dev->info || rb == NULL) return 0; @@ -182,6 +186,32 @@ __poll_t iio_buffer_poll(struct file *filp, return 0; } +ssize_t iio_buffer_read_wrapper(struct file *filp, char __user *buf, + size_t n, loff_t *f_ps) +{ + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_buffer *rb = ib->buffer; + + /* check if buffer was opened through new API */ + if (test_bit(IIO_BUSY_BIT_POS, &rb->flags)) + return -EBUSY; + + return iio_buffer_read(filp, buf, n, f_ps); +} + +__poll_t iio_buffer_poll_wrapper(struct file *filp, + struct poll_table_struct *wait) +{ + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_buffer *rb = ib->buffer; + + /* check if buffer was opened through new API */ + if (test_bit(IIO_BUSY_BIT_POS, &rb->flags)) + return 0; + + return iio_buffer_poll(filp, wait); +} + /** * iio_buffer_wakeup_poll - Wakes up the buffer waitqueue * @indio_dev: The IIO device @@ -191,12 +221,14 @@ __poll_t iio_buffer_poll(struct file *filp, */ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) { - struct iio_buffer *buffer = indio_dev->buffer; - - if (!buffer) - return; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer *buffer; + unsigned int i; - wake_up(&buffer->pollq); + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { + buffer = iio_dev_opaque->attached_buffers[i]; + wake_up(&buffer->pollq); + } } void iio_buffer_init(struct iio_buffer *buffer) @@ -210,11 +242,25 @@ void iio_buffer_init(struct iio_buffer *buffer) } EXPORT_SYMBOL(iio_buffer_init); +void iio_device_detach_buffers(struct iio_dev *indio_dev) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer *buffer; + unsigned int i; + + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { + buffer = iio_dev_opaque->attached_buffers[i]; + iio_buffer_put(buffer); + } + + kfree(iio_dev_opaque->attached_buffers); +} + static ssize_t iio_show_scan_index(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index); + return sysfs_emit(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index); } static ssize_t iio_show_fixed_type(struct device *dev, @@ -232,15 +278,15 @@ static ssize_t iio_show_fixed_type(struct device *dev, #endif } if (this_attr->c->scan_type.repeat > 1) - return sprintf(buf, "%s:%c%d/%dX%d>>%u\n", + return sysfs_emit(buf, "%s:%c%d/%dX%d>>%u\n", iio_endian_prefix[type], this_attr->c->scan_type.sign, this_attr->c->scan_type.realbits, this_attr->c->scan_type.storagebits, this_attr->c->scan_type.repeat, this_attr->c->scan_type.shift); - else - return sprintf(buf, "%s:%c%d/%d>>%u\n", + else + return sysfs_emit(buf, "%s:%c%d/%d>>%u\n", iio_endian_prefix[type], this_attr->c->scan_type.sign, this_attr->c->scan_type.realbits, @@ -253,14 +299,13 @@ static ssize_t iio_scan_el_show(struct device *dev, char *buf) { int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; /* Ensure ret is 0 or 1. */ ret = !!test_bit(to_iio_dev_attr(attr)->address, buffer->scan_mask); - return sprintf(buf, "%d\n", ret); + return sysfs_emit(buf, "%d\n", ret); } /* Note NULL used as error indicator as it doesn't make sense. */ @@ -367,8 +412,8 @@ static ssize_t iio_scan_el_store(struct device *dev, int ret; bool state; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_buffer *buffer = this_attr->buffer; ret = strtobool(buf, &state); if (ret < 0) @@ -402,10 +447,9 @@ static ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; - return sprintf(buf, "%d\n", buffer->scan_timestamp); + return sysfs_emit(buf, "%d\n", buffer->scan_timestamp); } static ssize_t iio_scan_el_ts_store(struct device *dev, @@ -415,7 +459,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev, { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; bool state; ret = strtobool(buf, &state); @@ -447,7 +491,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, IIO_SEPARATE, &indio_dev->dev, - &buffer->scan_el_dev_attr_list); + buffer, + &buffer->buffer_attr_list); if (ret) return ret; attrcount++; @@ -458,7 +503,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, 0, &indio_dev->dev, - &buffer->scan_el_dev_attr_list); + buffer, + &buffer->buffer_attr_list); if (ret) return ret; attrcount++; @@ -470,7 +516,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, chan->scan_index, 0, &indio_dev->dev, - &buffer->scan_el_dev_attr_list); + buffer, + &buffer->buffer_attr_list); else ret = __iio_add_chan_devattr("en", chan, @@ -479,7 +526,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, chan->scan_index, 0, &indio_dev->dev, - &buffer->scan_el_dev_attr_list); + buffer, + &buffer->buffer_attr_list); if (ret) return ret; attrcount++; @@ -491,10 +539,9 @@ static ssize_t iio_buffer_read_length(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; - return sprintf(buf, "%d\n", buffer->length); + return sysfs_emit(buf, "%d\n", buffer->length); } static ssize_t iio_buffer_write_length(struct device *dev, @@ -502,7 +549,7 @@ static ssize_t iio_buffer_write_length(struct device *dev, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; unsigned int val; int ret; @@ -534,10 +581,9 @@ static ssize_t iio_buffer_show_enable(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; - return sprintf(buf, "%d\n", iio_buffer_is_active(buffer)); + return sysfs_emit(buf, "%d\n", iio_buffer_is_active(buffer)); } static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, @@ -1150,7 +1196,7 @@ static ssize_t iio_buffer_store_enable(struct device *dev, int ret; bool requested_state; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; bool inlist; ret = strtobool(buf, &requested_state); @@ -1175,16 +1221,13 @@ done: return (ret < 0) ? ret : len; } -static const char * const iio_scan_elements_group_name = "scan_elements"; - static ssize_t iio_buffer_show_watermark(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; - return sprintf(buf, "%u\n", buffer->watermark); + return sysfs_emit(buf, "%u\n", buffer->watermark); } static ssize_t iio_buffer_store_watermark(struct device *dev, @@ -1193,7 +1236,7 @@ static ssize_t iio_buffer_store_watermark(struct device *dev, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; unsigned int val; int ret; @@ -1226,10 +1269,9 @@ static ssize_t iio_dma_show_data_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; - return sprintf(buf, "%zu\n", iio_buffer_data_available(buffer)); + return sysfs_emit(buf, "%zu\n", iio_buffer_data_available(buffer)); } static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length, @@ -1252,45 +1294,194 @@ static struct attribute *iio_buffer_attrs[] = { &dev_attr_data_available.attr, }; -static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, - struct iio_dev *indio_dev) +#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) + +static struct attribute *iio_buffer_wrap_attr(struct iio_buffer *buffer, + struct attribute *attr) { - struct iio_dev_attr *p; - struct attribute **attr; - int ret, i, attrn, attrcount; - const struct iio_chan_spec *channels; + struct device_attribute *dattr = to_dev_attr(attr); + struct iio_dev_attr *iio_attr; - attrcount = 0; - if (buffer->attrs) { - while (buffer->attrs[attrcount] != NULL) - attrcount++; - } + iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL); + if (!iio_attr) + return NULL; + + iio_attr->buffer = buffer; + memcpy(&iio_attr->dev_attr, dattr, sizeof(iio_attr->dev_attr)); + iio_attr->dev_attr.attr.name = kstrdup_const(attr->name, GFP_KERNEL); + sysfs_attr_init(&iio_attr->dev_attr.attr); + + list_add(&iio_attr->l, &buffer->buffer_attr_list); + + return &iio_attr->dev_attr.attr; +} + +static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev, + struct attribute **buffer_attrs, + int buffer_attrcount, + int scan_el_attrcount) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct attribute_group *group; + struct attribute **attrs; + int ret; - attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1, - sizeof(struct attribute *), GFP_KERNEL); - if (!attr) + attrs = kcalloc(buffer_attrcount + 1, sizeof(*attrs), GFP_KERNEL); + if (!attrs) return -ENOMEM; - memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs)); - if (!buffer->access->set_length) - attr[0] = &dev_attr_length_ro.attr; + memcpy(attrs, buffer_attrs, buffer_attrcount * sizeof(*attrs)); - if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK) - attr[2] = &dev_attr_watermark_ro.attr; + group = &iio_dev_opaque->legacy_buffer_group; + group->attrs = attrs; + group->name = "buffer"; - if (buffer->attrs) - memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs, - sizeof(struct attribute *) * attrcount); + ret = iio_device_register_sysfs_group(indio_dev, group); + if (ret) + goto error_free_buffer_attrs; - attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL; + attrs = kcalloc(scan_el_attrcount + 1, sizeof(*attrs), GFP_KERNEL); + if (!attrs) { + ret = -ENOMEM; + goto error_free_buffer_attrs; + } - buffer->buffer_group.name = "buffer"; - buffer->buffer_group.attrs = attr; + memcpy(attrs, &buffer_attrs[buffer_attrcount], + scan_el_attrcount * sizeof(*attrs)); + + group = &iio_dev_opaque->legacy_scan_el_group; + group->attrs = attrs; + group->name = "scan_elements"; + + ret = iio_device_register_sysfs_group(indio_dev, group); + if (ret) + goto error_free_scan_el_attrs; + + return 0; + +error_free_buffer_attrs: + kfree(iio_dev_opaque->legacy_buffer_group.attrs); +error_free_scan_el_attrs: + kfree(iio_dev_opaque->legacy_scan_el_group.attrs); + + return ret; +} + +static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); - indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group; + kfree(iio_dev_opaque->legacy_buffer_group.attrs); + kfree(iio_dev_opaque->legacy_scan_el_group.attrs); +} + +static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) +{ + struct iio_dev_buffer_pair *ib = filep->private_data; + struct iio_dev *indio_dev = ib->indio_dev; + struct iio_buffer *buffer = ib->buffer; + + wake_up(&buffer->pollq); + + kfree(ib); + clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); + iio_device_put(indio_dev); + + return 0; +} + +static const struct file_operations iio_buffer_chrdev_fileops = { + .owner = THIS_MODULE, + .llseek = noop_llseek, + .read = iio_buffer_read, + .poll = iio_buffer_poll, + .release = iio_buffer_chrdev_release, +}; + +static long iio_device_buffer_getfd(struct iio_dev *indio_dev, unsigned long arg) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + int __user *ival = (int __user *)arg; + struct iio_dev_buffer_pair *ib; + struct iio_buffer *buffer; + int fd, idx, ret; + + if (copy_from_user(&idx, ival, sizeof(idx))) + return -EFAULT; + + if (idx >= iio_dev_opaque->attached_buffers_cnt) + return -ENODEV; - attrcount = 0; - INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list); + iio_device_get(indio_dev); + + buffer = iio_dev_opaque->attached_buffers[idx]; + + if (test_and_set_bit(IIO_BUSY_BIT_POS, &buffer->flags)) { + ret = -EBUSY; + goto error_iio_dev_put; + } + + ib = kzalloc(sizeof(*ib), GFP_KERNEL); + if (!ib) { + ret = -ENOMEM; + goto error_clear_busy_bit; + } + + ib->indio_dev = indio_dev; + ib->buffer = buffer; + + fd = anon_inode_getfd("iio:buffer", &iio_buffer_chrdev_fileops, + ib, O_RDWR | O_CLOEXEC); + if (fd < 0) { + ret = fd; + goto error_free_ib; + } + + if (copy_to_user(ival, &fd, sizeof(fd))) { + put_unused_fd(fd); + ret = -EFAULT; + goto error_free_ib; + } + + return 0; + +error_free_ib: + kfree(ib); +error_clear_busy_bit: + clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); +error_iio_dev_put: + iio_device_put(indio_dev); + return ret; +} + +static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case IIO_BUFFER_GET_FD_IOCTL: + return iio_device_buffer_getfd(indio_dev, arg); + default: + return IIO_IOCTL_UNHANDLED; + } +} + +static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, + struct iio_dev *indio_dev, + int index) +{ + struct iio_dev_attr *p; + struct attribute **attr; + int ret, i, attrn, scan_el_attrcount, buffer_attrcount; + const struct iio_chan_spec *channels; + + buffer_attrcount = 0; + if (buffer->attrs) { + while (buffer->attrs[buffer_attrcount] != NULL) + buffer_attrcount++; + } + + scan_el_attrcount = 0; + INIT_LIST_HEAD(&buffer->buffer_attr_list); channels = indio_dev->channels; if (channels) { /* new magic */ @@ -1302,7 +1493,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, &channels[i]); if (ret < 0) goto error_cleanup_dynamic; - attrcount += ret; + scan_el_attrcount += ret; if (channels[i].type == IIO_TIMESTAMP) indio_dev->scan_index_timestamp = channels[i].scan_index; @@ -1317,37 +1508,93 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, } } - buffer->scan_el_group.name = iio_scan_elements_group_name; - - buffer->scan_el_group.attrs = kcalloc(attrcount + 1, - sizeof(buffer->scan_el_group.attrs[0]), - GFP_KERNEL); - if (buffer->scan_el_group.attrs == NULL) { + attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs); + attr = kcalloc(attrn + 1, sizeof(* attr), GFP_KERNEL); + if (!attr) { ret = -ENOMEM; goto error_free_scan_mask; } + + memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs)); + if (!buffer->access->set_length) + attr[0] = &dev_attr_length_ro.attr; + + if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK) + attr[2] = &dev_attr_watermark_ro.attr; + + if (buffer->attrs) + memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs, + sizeof(struct attribute *) * buffer_attrcount); + + buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs); + + for (i = 0; i < buffer_attrcount; i++) { + struct attribute *wrapped; + + wrapped = iio_buffer_wrap_attr(buffer, attr[i]); + if (!wrapped) { + ret = -ENOMEM; + goto error_free_scan_mask; + } + attr[i] = wrapped; + } + attrn = 0; + list_for_each_entry(p, &buffer->buffer_attr_list, l) + attr[attrn++] = &p->dev_attr.attr; - list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) - buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr; - indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group; + buffer->buffer_group.name = kasprintf(GFP_KERNEL, "buffer%d", index); + if (!buffer->buffer_group.name) { + ret = -ENOMEM; + goto error_free_buffer_attrs; + } + + buffer->buffer_group.attrs = attr; + + ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group); + if (ret) + goto error_free_buffer_attr_group_name; + + /* we only need to register the legacy groups for the first buffer */ + if (index > 0) + return 0; + + ret = iio_buffer_register_legacy_sysfs_groups(indio_dev, attr, + buffer_attrcount, + scan_el_attrcount); + if (ret) + goto error_free_buffer_attr_group_name; return 0; +error_free_buffer_attr_group_name: + kfree(buffer->buffer_group.name); +error_free_buffer_attrs: + kfree(buffer->buffer_group.attrs); error_free_scan_mask: bitmap_free(buffer->scan_mask); error_cleanup_dynamic: - iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); - kfree(buffer->buffer_group.attrs); + iio_free_chan_devattr_list(&buffer->buffer_attr_list); return ret; } -int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) +static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer) +{ + bitmap_free(buffer->scan_mask); + kfree(buffer->buffer_group.name); + kfree(buffer->buffer_group.attrs); + iio_free_chan_devattr_list(&buffer->buffer_attr_list); +} + +int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) { - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); const struct iio_chan_spec *channels; - int i; + struct iio_buffer *buffer; + int unwind_idx; + int ret, i; + size_t sz; channels = indio_dev->channels; if (channels) { @@ -1358,28 +1605,58 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) indio_dev->masklength = ml; } - if (!buffer) + if (!iio_dev_opaque->attached_buffers_cnt) return 0; - return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev); -} + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { + buffer = iio_dev_opaque->attached_buffers[i]; + ret = __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, i); + if (ret) { + unwind_idx = i; + goto error_unwind_sysfs_and_mask; + } + } + unwind_idx = iio_dev_opaque->attached_buffers_cnt - 1; -static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer) -{ - bitmap_free(buffer->scan_mask); - kfree(buffer->buffer_group.attrs); - kfree(buffer->scan_el_group.attrs); - iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); + sz = sizeof(*(iio_dev_opaque->buffer_ioctl_handler)); + iio_dev_opaque->buffer_ioctl_handler = kzalloc(sz, GFP_KERNEL); + if (!iio_dev_opaque->buffer_ioctl_handler) { + ret = -ENOMEM; + goto error_unwind_sysfs_and_mask; + } + + iio_dev_opaque->buffer_ioctl_handler->ioctl = iio_device_buffer_ioctl; + iio_device_ioctl_handler_register(indio_dev, + iio_dev_opaque->buffer_ioctl_handler); + + return 0; + +error_unwind_sysfs_and_mask: + for (; unwind_idx >= 0; unwind_idx--) { + buffer = iio_dev_opaque->attached_buffers[unwind_idx]; + __iio_buffer_free_sysfs_and_mask(buffer); + } + return ret; } -void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) +void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) { - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer *buffer; + int i; - if (!buffer) + if (!iio_dev_opaque->attached_buffers_cnt) return; - __iio_buffer_free_sysfs_and_mask(buffer); + iio_device_ioctl_handler_unregister(iio_dev_opaque->buffer_ioctl_handler); + kfree(iio_dev_opaque->buffer_ioctl_handler); + + iio_buffer_unregister_legacy_sysfs_groups(indio_dev); + + for (i = iio_dev_opaque->attached_buffers_cnt - 1; i >= 0; i--) { + buffer = iio_dev_opaque->attached_buffers[i]; + __iio_buffer_free_sysfs_and_mask(buffer); + } } /** @@ -1497,13 +1774,37 @@ EXPORT_SYMBOL_GPL(iio_buffer_put); * @indio_dev: The device the buffer should be attached to * @buffer: The buffer to attach to the device * + * Return 0 if successful, negative if error. + * * This function attaches a buffer to a IIO device. The buffer stays attached to - * the device until the device is freed. The function should only be called at - * most once per device. + * the device until the device is freed. For legacy reasons, the first attached + * buffer will also be assigned to 'indio_dev->buffer'. + * The array allocated here, will be free'd via the iio_device_detach_buffers() + * call which is handled by the iio_device_free(). */ -void iio_device_attach_buffer(struct iio_dev *indio_dev, - struct iio_buffer *buffer) +int iio_device_attach_buffer(struct iio_dev *indio_dev, + struct iio_buffer *buffer) { - indio_dev->buffer = iio_buffer_get(buffer); + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer **new, **old = iio_dev_opaque->attached_buffers; + unsigned int cnt = iio_dev_opaque->attached_buffers_cnt; + + cnt++; + + new = krealloc(old, sizeof(*new) * cnt, GFP_KERNEL); + if (!new) + return -ENOMEM; + iio_dev_opaque->attached_buffers = new; + + buffer = iio_buffer_get(buffer); + + /* first buffer is legacy; attach it to the IIO device directly */ + if (!indio_dev->buffer) + indio_dev->buffer = buffer; + + iio_dev_opaque->attached_buffers[cnt - 1] = buffer; + iio_dev_opaque->attached_buffers_cnt = cnt; + + return 0; } EXPORT_SYMBOL_GPL(iio_device_attach_buffer); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 7db761afa578c73f3b44078435b5a785315c2538..d92c58a94fe4f9081f0b47f0d8ed97e37e5d821b 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -157,6 +157,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_PHASE] = "phase", [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain", [IIO_CHAN_INFO_HYSTERESIS] = "hysteresis", + [IIO_CHAN_INFO_HYSTERESIS_RELATIVE] = "hysteresis_relative", [IIO_CHAN_INFO_INT_TIME] = "integration_time", [IIO_CHAN_INFO_ENABLE] = "en", [IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight", @@ -233,7 +234,7 @@ ssize_t iio_read_const_attr(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string); + return sysfs_emit(buf, "%s\n", to_iio_const_attr(attr)->string); } EXPORT_SYMBOL(iio_read_const_attr); @@ -503,7 +504,7 @@ ssize_t iio_enum_available_read(struct iio_dev *indio_dev, for (i = 0; i < e->num_items; ++i) { if (!e->items[i]) continue; - len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", e->items[i]); + len += sysfs_emit_at(buf, len, "%s ", e->items[i]); } /* replace last space with a newline */ @@ -528,7 +529,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev, else if (i >= e->num_items || !e->items[i]) return -EINVAL; - return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]); + return sysfs_emit(buf, "%s\n", e->items[i]); } EXPORT_SYMBOL_GPL(iio_enum_read); @@ -579,10 +580,10 @@ ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv, if (!mtx) mtx = &iio_mount_idmatrix; - return snprintf(buf, PAGE_SIZE, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n", - mtx->rotation[0], mtx->rotation[1], mtx->rotation[2], - mtx->rotation[3], mtx->rotation[4], mtx->rotation[5], - mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]); + return sysfs_emit(buf, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n", + mtx->rotation[0], mtx->rotation[1], mtx->rotation[2], + mtx->rotation[3], mtx->rotation[4], mtx->rotation[5], + mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]); } EXPORT_SYMBOL_GPL(iio_show_mount_matrix); @@ -622,59 +623,62 @@ int iio_read_mount_matrix(struct device *dev, const char *propname, } EXPORT_SYMBOL(iio_read_mount_matrix); -static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, +static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, int size, const int *vals) { - unsigned long long tmp; int tmp0, tmp1; s64 tmp2; bool scale_db = false; switch (type) { case IIO_VAL_INT: - return scnprintf(buf, len, "%d", vals[0]); + return sysfs_emit_at(buf, offset, "%d", vals[0]); case IIO_VAL_INT_PLUS_MICRO_DB: scale_db = true; fallthrough; case IIO_VAL_INT_PLUS_MICRO: if (vals[1] < 0) - return scnprintf(buf, len, "-%d.%06u%s", abs(vals[0]), - -vals[1], scale_db ? " dB" : ""); + return sysfs_emit_at(buf, offset, "-%d.%06u%s", + abs(vals[0]), -vals[1], + scale_db ? " dB" : ""); else - return scnprintf(buf, len, "%d.%06u%s", vals[0], vals[1], - scale_db ? " dB" : ""); + return sysfs_emit_at(buf, offset, "%d.%06u%s", vals[0], + vals[1], scale_db ? " dB" : ""); case IIO_VAL_INT_PLUS_NANO: if (vals[1] < 0) - return scnprintf(buf, len, "-%d.%09u", abs(vals[0]), - -vals[1]); + return sysfs_emit_at(buf, offset, "-%d.%09u", + abs(vals[0]), -vals[1]); else - return scnprintf(buf, len, "%d.%09u", vals[0], vals[1]); + return sysfs_emit_at(buf, offset, "%d.%09u", vals[0], + vals[1]); case IIO_VAL_FRACTIONAL: tmp2 = div_s64((s64)vals[0] * 1000000000LL, vals[1]); tmp1 = vals[1]; tmp0 = (int)div_s64_rem(tmp2, 1000000000, &tmp1); if ((tmp2 < 0) && (tmp0 == 0)) - return snprintf(buf, len, "-0.%09u", abs(tmp1)); + return sysfs_emit_at(buf, offset, "-0.%09u", abs(tmp1)); else - return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); + return sysfs_emit_at(buf, offset, "%d.%09u", tmp0, + abs(tmp1)); case IIO_VAL_FRACTIONAL_LOG2: - tmp = shift_right((s64)vals[0] * 1000000000LL, vals[1]); - tmp0 = (int)div_s64_rem(tmp, 1000000000LL, &tmp1); - return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); + tmp2 = shift_right((s64)vals[0] * 1000000000LL, vals[1]); + tmp0 = (int)div_s64_rem(tmp2, 1000000000LL, &tmp1); + if (tmp0 == 0 && tmp2 < 0) + return sysfs_emit_at(buf, offset, "-0.%09u", abs(tmp1)); + else + return sysfs_emit_at(buf, offset, "%d.%09u", tmp0, + abs(tmp1)); case IIO_VAL_INT_MULTIPLE: { int i; int l = 0; - for (i = 0; i < size; ++i) { - l += scnprintf(&buf[l], len - l, "%d ", vals[i]); - if (l >= len) - break; - } + for (i = 0; i < size; ++i) + l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]); return l; } case IIO_VAL_CHAR: - return scnprintf(buf, len, "%c", (char)vals[0]); + return sysfs_emit_at(buf, offset, "%c", (char)vals[0]); default: return 0; } @@ -698,11 +702,11 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) { ssize_t len; - len = __iio_format_value(buf, PAGE_SIZE, type, size, vals); + len = __iio_format_value(buf, 0, type, size, vals); if (len >= PAGE_SIZE - 1) return -EFBIG; - return len + sprintf(buf + len, "\n"); + return len + sysfs_emit_at(buf, len, "\n"); } EXPORT_SYMBOL_GPL(iio_format_value); @@ -760,22 +764,21 @@ static ssize_t iio_format_list(char *buf, const int *vals, int type, int length, break; } - len = scnprintf(buf, PAGE_SIZE, prefix); + len = sysfs_emit(buf, prefix); for (i = 0; i <= length - stride; i += stride) { if (i != 0) { - len += scnprintf(buf + len, PAGE_SIZE - len, " "); + len += sysfs_emit_at(buf, len, " "); if (len >= PAGE_SIZE) return -EFBIG; } - len += __iio_format_value(buf + len, PAGE_SIZE - len, type, - stride, &vals[i]); + len += __iio_format_value(buf, len, type, stride, &vals[i]); if (len >= PAGE_SIZE) return -EFBIG; } - len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", suffix); + len += sysfs_emit_at(buf, len, "%s\n", suffix); return len; } @@ -1114,6 +1117,7 @@ int __iio_add_chan_devattr(const char *postfix, u64 mask, enum iio_shared_by shared_by, struct device *dev, + struct iio_buffer *buffer, struct list_head *attr_list) { int ret; @@ -1129,6 +1133,7 @@ int __iio_add_chan_devattr(const char *postfix, goto error_iio_dev_attr_free; iio_attr->c = chan; iio_attr->address = mask; + iio_attr->buffer = buffer; list_for_each_entry(t, attr_list, l) if (strcmp(t->dev_attr.attr.name, iio_attr->dev_attr.attr.name) == 0) { @@ -1165,6 +1170,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev, 0, IIO_SEPARATE, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); if (ret < 0) return ret; @@ -1190,6 +1196,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, i, shared_by, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) continue; @@ -1226,6 +1233,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, i, shared_by, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); kfree(avail_postfix); if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) @@ -1322,6 +1330,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, i, ext_info->shared, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); i++; if (ret == -EBUSY && ext_info->shared) @@ -1349,7 +1358,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list) struct iio_dev_attr *p, *n; list_for_each_entry_safe(p, n, attr_list, l) { - kfree(p->dev_attr.attr.name); + kfree_const(p->dev_attr.attr.name); list_del(&p->l); kfree(p); } @@ -1360,7 +1369,7 @@ static ssize_t iio_show_dev_name(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name); + return sysfs_emit(buf, "%s\n", indio_dev->name); } static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); @@ -1370,7 +1379,7 @@ static ssize_t iio_show_dev_label(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->label); + return sysfs_emit(buf, "%s\n", indio_dev->label); } static DEVICE_ATTR(label, S_IRUGO, iio_show_dev_label, NULL); @@ -1452,6 +1461,25 @@ static ssize_t iio_store_timestamp_clock(struct device *dev, return len; } +int iio_device_register_sysfs_group(struct iio_dev *indio_dev, + const struct attribute_group *group) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + const struct attribute_group **new, **old = iio_dev_opaque->groups; + unsigned int cnt = iio_dev_opaque->groupcounter; + + new = krealloc(old, sizeof(*new) * (cnt + 2), GFP_KERNEL); + if (!new) + return -ENOMEM; + + new[iio_dev_opaque->groupcounter++] = group; + new[iio_dev_opaque->groupcounter] = NULL; + + iio_dev_opaque->groups = new; + + return 0; +} + static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR, iio_show_timestamp_clock, iio_store_timestamp_clock); @@ -1525,8 +1553,10 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) if (clk) iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk; - indio_dev->groups[indio_dev->groupcounter++] = - &iio_dev_opaque->chan_attr_group; + ret = iio_device_register_sysfs_group(indio_dev, + &iio_dev_opaque->chan_attr_group); + if (ret) + goto error_clear_attrs; return 0; @@ -1543,6 +1573,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list); kfree(iio_dev_opaque->chan_attr_group.attrs); iio_dev_opaque->chan_attr_group.attrs = NULL; + kfree(iio_dev_opaque->groups); } static void iio_dev_release(struct device *device) @@ -1555,7 +1586,7 @@ static void iio_dev_release(struct device *device) iio_device_unregister_eventset(indio_dev); iio_device_unregister_sysfs(indio_dev); - iio_buffer_put(indio_dev->buffer); + iio_device_detach_buffers(indio_dev); ida_simple_remove(&iio_ida, indio_dev->id); kfree(iio_dev_opaque); @@ -1574,7 +1605,7 @@ struct device_type iio_device_type = { struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) { struct iio_dev_opaque *iio_dev_opaque; - struct iio_dev *dev; + struct iio_dev *indio_dev; size_t alloc_size; alloc_size = sizeof(struct iio_dev_opaque); @@ -1587,32 +1618,31 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) if (!iio_dev_opaque) return NULL; - dev = &iio_dev_opaque->indio_dev; - dev->priv = (char *)iio_dev_opaque + + indio_dev = &iio_dev_opaque->indio_dev; + indio_dev->priv = (char *)iio_dev_opaque + ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN); - dev->dev.parent = parent; - dev->dev.groups = dev->groups; - dev->dev.type = &iio_device_type; - dev->dev.bus = &iio_bus_type; - device_initialize(&dev->dev); - dev_set_drvdata(&dev->dev, (void *)dev); - mutex_init(&dev->mlock); - mutex_init(&dev->info_exist_lock); + indio_dev->dev.parent = parent; + indio_dev->dev.type = &iio_device_type; + indio_dev->dev.bus = &iio_bus_type; + device_initialize(&indio_dev->dev); + iio_device_set_drvdata(indio_dev, (void *)indio_dev); + mutex_init(&indio_dev->mlock); + mutex_init(&indio_dev->info_exist_lock); INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list); - dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); - if (dev->id < 0) { + indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); + if (indio_dev->id < 0) { /* cannot use a dev_err as the name isn't available */ pr_err("failed to get device id\n"); kfree(iio_dev_opaque); return NULL; } - dev_set_name(&dev->dev, "iio:device%d", dev->id); + dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id); INIT_LIST_HEAD(&iio_dev_opaque->buffer_list); INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers); - return dev; + return indio_dev; } EXPORT_SYMBOL(iio_device_alloc); @@ -1676,13 +1706,24 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) { struct iio_dev *indio_dev = container_of(inode->i_cdev, struct iio_dev, chrdev); + struct iio_dev_buffer_pair *ib; if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags)) return -EBUSY; iio_device_get(indio_dev); - filp->private_data = indio_dev; + ib = kmalloc(sizeof(*ib), GFP_KERNEL); + if (!ib) { + iio_device_put(indio_dev); + clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags); + return -ENOMEM; + } + + ib->indio_dev = indio_dev; + ib->buffer = indio_dev->buffer; + + filp->private_data = ib; return 0; } @@ -1696,8 +1737,10 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) */ static int iio_chrdev_release(struct inode *inode, struct file *filp) { + struct iio_dev_buffer_pair *ib = filp->private_data; struct iio_dev *indio_dev = container_of(inode->i_cdev, struct iio_dev, chrdev); + kfree(ib); clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags); iio_device_put(indio_dev); @@ -1719,7 +1762,8 @@ void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h) static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct iio_dev *indio_dev = filp->private_data; + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_dev *indio_dev = ib->indio_dev; struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_ioctl_handler *h; int ret = -ENODEV; @@ -1761,6 +1805,15 @@ static const struct file_operations iio_buffer_fileops = { .release = iio_chrdev_release, }; +static const struct file_operations iio_event_fileops = { + .owner = THIS_MODULE, + .llseek = noop_llseek, + .unlocked_ioctl = iio_ioctl, + .compat_ioctl = compat_ptr_ioctl, + .open = iio_chrdev_open, + .release = iio_chrdev_release, +}; + static int iio_check_unique_scan_index(struct iio_dev *indio_dev) { int i, j; @@ -1788,6 +1841,8 @@ static const struct iio_buffer_setup_ops noop_ring_setup_ops; int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + const char *label; int ret; if (!indio_dev->info) @@ -1798,19 +1853,17 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) if (!indio_dev->dev.of_node && indio_dev->dev.parent) indio_dev->dev.of_node = indio_dev->dev.parent->of_node; - indio_dev->label = of_get_property(indio_dev->dev.of_node, "label", - NULL); + label = of_get_property(indio_dev->dev.of_node, "label", NULL); + if (label) + indio_dev->label = label; ret = iio_check_unique_scan_index(indio_dev); if (ret < 0) return ret; - /* configure elements for the chrdev */ - indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); - iio_device_register_debugfs(indio_dev); - ret = iio_buffer_alloc_sysfs_and_mask(indio_dev); + ret = iio_buffers_alloc_sysfs_and_mask(indio_dev); if (ret) { dev_err(indio_dev->dev.parent, "Failed to create buffer sysfs interfaces\n"); @@ -1836,9 +1889,18 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) indio_dev->setup_ops == NULL) indio_dev->setup_ops = &noop_ring_setup_ops; - cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); + if (iio_dev_opaque->attached_buffers_cnt) + cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); + else if (iio_dev_opaque->event_interface) + cdev_init(&indio_dev->chrdev, &iio_event_fileops); + + if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) { + indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); + indio_dev->chrdev.owner = this_mod; + } - indio_dev->chrdev.owner = this_mod; + /* assign device groups now; they should be all registered now */ + indio_dev->dev.groups = iio_dev_opaque->groups; ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev); if (ret < 0) @@ -1851,7 +1913,7 @@ error_unreg_eventset: error_free_sysfs: iio_device_unregister_sysfs(indio_dev); error_buffer_free_sysfs: - iio_buffer_free_sysfs_and_mask(indio_dev); + iio_buffers_free_sysfs_and_mask(indio_dev); error_unreg_debugfs: iio_device_unregister_debugfs(indio_dev); return ret; @@ -1885,7 +1947,7 @@ void iio_device_unregister(struct iio_dev *indio_dev) mutex_unlock(&indio_dev->info_exist_lock); - iio_buffer_free_sysfs_and_mask(indio_dev); + iio_buffers_free_sysfs_and_mask(indio_dev); } EXPORT_SYMBOL(iio_device_unregister); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 7e532117ac55021e25bce50f243e511ef35751ed..d0732eac0f0aceefefef3e433da9abaf15dae097 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -245,6 +245,7 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_PERIOD] = "period", [IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db", [IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db", + [IIO_EV_INFO_TIMEOUT] = "timeout", }; static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) @@ -297,7 +298,7 @@ static ssize_t iio_ev_state_show(struct device *dev, if (val < 0) return val; else - return sprintf(buf, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t iio_ev_value_show(struct device *dev, @@ -385,6 +386,7 @@ static int iio_device_add_event(struct iio_dev *indio_dev, ret = __iio_add_chan_devattr(postfix, chan, show, store, (i << 16) | spec_index, shared_by, &indio_dev->dev, + NULL, &iio_dev_opaque->event_interface->dev_attr_list); kfree(postfix); @@ -544,7 +546,10 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) /* Add all elements from the list. */ list_for_each_entry(p, &ev_int->dev_attr_list, l) ev_int->group.attrs[attrn++] = &p->dev_attr.attr; - indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group; + + ret = iio_device_register_sysfs_group(indio_dev, &ev_int->group); + if (ret) + goto error_free_setup_event_lines; ev_int->ioctl_handler.ioctl = iio_event_ioctl; iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev, diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index ea3c9859b2589e6b7e7aee8268747f3fc92a6a29..b2c94abbb48781702f535554165bf97edc35a346 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -50,7 +50,7 @@ static ssize_t iio_trigger_read_name(struct device *dev, char *buf) { struct iio_trigger *trig = to_iio_trigger(dev); - return sprintf(buf, "%s\n", trig->name); + return sysfs_emit(buf, "%s\n", trig->name); } static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); @@ -75,8 +75,7 @@ int __iio_trigger_register(struct iio_trigger *trig_info, return trig_info->id; /* Set the name used for the sysfs directory etc */ - dev_set_name(&trig_info->dev, "trigger%ld", - (unsigned long) trig_info->id); + dev_set_name(&trig_info->dev, "trigger%d", trig_info->id); ret = device_add(&trig_info->dev); if (ret) @@ -212,6 +211,7 @@ EXPORT_SYMBOL(iio_trigger_notify_done); static int iio_trigger_get_irq(struct iio_trigger *trig) { int ret; + mutex_lock(&trig->pool_lock); ret = bitmap_find_free_region(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER, @@ -240,9 +240,9 @@ static void iio_trigger_put_irq(struct iio_trigger *trig, int irq) int iio_trigger_attach_poll_func(struct iio_trigger *trig, struct iio_poll_func *pf) { + bool notinuse = + bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); int ret = 0; - bool notinuse - = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); /* Prevent the module from being removed whilst attached to a trigger */ __module_get(pf->indio_dev->driver_module); @@ -291,11 +291,10 @@ out_put_module: int iio_trigger_detach_poll_func(struct iio_trigger *trig, struct iio_poll_func *pf) { + bool no_other_users = + bitmap_weight(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER) == 1; int ret = 0; - bool no_other_users - = (bitmap_weight(trig->pool, - CONFIG_IIO_CONSUMERS_PER_TRIGGER) - == 1); + if (trig->ops && trig->ops->set_trigger_state && no_other_users) { ret = trig->ops->set_trigger_state(trig, false); if (ret) @@ -313,6 +312,7 @@ int iio_trigger_detach_poll_func(struct iio_trigger *trig, irqreturn_t iio_pollfunc_store_time(int irq, void *p) { struct iio_poll_func *pf = p; + pf->timestamp = iio_get_time_ns(pf->indio_dev); return IRQ_WAKE_THREAD; } @@ -375,7 +375,7 @@ static ssize_t iio_trigger_read_current(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); if (indio_dev->trig) - return sprintf(buf, "%s\n", indio_dev->trig->name); + return sysfs_emit(buf, "%s\n", indio_dev->trig->name); return 0; } @@ -499,23 +499,23 @@ static const struct device_type iio_trig_type = { static void iio_trig_subirqmask(struct irq_data *d) { struct irq_chip *chip = irq_data_get_irq_chip(d); - struct iio_trigger *trig - = container_of(chip, - struct iio_trigger, subirq_chip); + struct iio_trigger *trig = container_of(chip, struct iio_trigger, subirq_chip); + trig->subirqs[d->irq - trig->subirq_base].enabled = false; } static void iio_trig_subirqunmask(struct irq_data *d) { struct irq_chip *chip = irq_data_get_irq_chip(d); - struct iio_trigger *trig - = container_of(chip, - struct iio_trigger, subirq_chip); + struct iio_trigger *trig = container_of(chip, struct iio_trigger, subirq_chip); + trig->subirqs[d->irq - trig->subirq_base].enabled = true; } -static __printf(1, 0) -struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs) +static __printf(2, 0) +struct iio_trigger *viio_trigger_alloc(struct device *parent, + const char *fmt, + va_list vargs) { struct iio_trigger *trig; int i; @@ -524,6 +524,7 @@ struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs) if (!trig) return NULL; + trig->dev.parent = parent; trig->dev.type = &iio_trig_type; trig->dev.bus = &iio_bus_type; device_initialize(&trig->dev); @@ -559,13 +560,23 @@ free_trig: return NULL; } -struct iio_trigger *iio_trigger_alloc(const char *fmt, ...) +/** + * iio_trigger_alloc - Allocate a trigger + * @parent: Device to allocate iio_trigger for + * @fmt: trigger name format. If it includes format + * specifiers, the additional arguments following + * format are formatted and inserted in the resulting + * string replacing their respective specifiers. + * RETURNS: + * Pointer to allocated iio_trigger on success, NULL on failure. + */ +struct iio_trigger *iio_trigger_alloc(struct device *parent, const char *fmt, ...) { struct iio_trigger *trig; va_list vargs; va_start(vargs, fmt); - trig = viio_trigger_alloc(fmt, vargs); + trig = viio_trigger_alloc(parent, fmt, vargs); va_end(vargs); return trig; @@ -586,20 +597,19 @@ static void devm_iio_trigger_release(struct device *dev, void *res) /** * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() - * @dev: Device to allocate iio_trigger for + * Managed iio_trigger_alloc. iio_trigger allocated with this function is + * automatically freed on driver detach. + * @parent: Device to allocate iio_trigger for * @fmt: trigger name format. If it includes format * specifiers, the additional arguments following * format are formatted and inserted in the resulting * string replacing their respective specifiers. * - * Managed iio_trigger_alloc. iio_trigger allocated with this function is - * automatically freed on driver detach. * * RETURNS: * Pointer to allocated iio_trigger on success, NULL on failure. */ -struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, - const char *fmt, ...) +struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fmt, ...) { struct iio_trigger **ptr, *trig; va_list vargs; @@ -611,11 +621,11 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, /* use raw alloc_dr for kmalloc caller tracing */ va_start(vargs, fmt); - trig = viio_trigger_alloc(fmt, vargs); + trig = viio_trigger_alloc(parent, fmt, vargs); va_end(vargs); if (trig) { *ptr = trig; - devres_add(dev, ptr); + devres_add(parent, ptr); } else { devres_free(ptr); } @@ -684,7 +694,7 @@ EXPORT_SYMBOL(iio_trigger_using_own); * device, -EINVAL otherwise. */ int iio_trigger_validate_own_device(struct iio_trigger *trig, - struct iio_dev *indio_dev) + struct iio_dev *indio_dev) { if (indio_dev->dev.parent != trig->dev.parent) return -EINVAL; @@ -692,10 +702,10 @@ int iio_trigger_validate_own_device(struct iio_trigger *trig, } EXPORT_SYMBOL(iio_trigger_validate_own_device); -void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) +int iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { - indio_dev->groups[indio_dev->groupcounter++] = - &iio_trigger_consumer_attr_group; + return iio_device_register_sysfs_group(indio_dev, + &iio_trigger_consumer_attr_group); } void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index db77a2d4a56b27acda6d5c486cd0587c6ee4a02a..9c22697b7e835e34f13a7b054c8ce6e6a8b43714 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -688,7 +688,8 @@ int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) } EXPORT_SYMBOL_GPL(iio_read_channel_offset); -int iio_read_channel_processed(struct iio_channel *chan, int *val) +int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, + unsigned int scale) { int ret; @@ -701,11 +702,15 @@ int iio_read_channel_processed(struct iio_channel *chan, int *val) if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_PROCESSED); + if (ret < 0) + goto err_unlock; + *val *= scale; } else { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); if (ret < 0) goto err_unlock; - ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1); + ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, + scale); } err_unlock: @@ -713,6 +718,13 @@ err_unlock: return ret; } +EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale); + +int iio_read_channel_processed(struct iio_channel *chan, int *val) +{ + /* This is just a special case with scale factor 1 */ + return iio_read_channel_processed_scale(chan, val, 1); +} EXPORT_SYMBOL_GPL(iio_read_channel_processed); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 2be7180e2cbfa8a9c0a58efb05cf83c73d82e200..0a6ab5761eece0ef9e87e8c483bf0d388214483b 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -16,18 +16,19 @@ #include <linux/module.h> #include <linux/acpi.h> #include <linux/err.h> +#include <linux/irq.h> #include <linux/mutex.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> -#include <linux/iio/kfifo_buf.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> #define ACPI_ALS_CLASS "als" #define ACPI_ALS_DEVICE_NAME "acpi-als" #define ACPI_ALS_NOTIFY_ILLUMINANCE 0x80 -ACPI_MODULE_NAME("acpi-als"); - /* * So far, there's only one channel in here, but the specification for * ACPI0008 says there can be more to what the block can report. Like @@ -45,24 +46,23 @@ static const struct iio_chan_spec acpi_als_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED), }, + IIO_CHAN_SOFT_TIMESTAMP(1), }; /* * The event buffer contains timestamp and all the data from * the ACPI0008 block. There are multiple, but so far we only - * support _ALI (illuminance). Once someone adds new channels - * to acpi_als_channels[], the evt_buffer below will grow - * automatically. + * support _ALI (illuminance): One channel, padding and timestamp. */ -#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) #define ACPI_ALS_EVT_BUFFER_SIZE \ - (sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32))) + (sizeof(s32) + sizeof(s32) + sizeof(s64)) struct acpi_als { struct acpi_device *device; struct mutex lock; + struct iio_trigger *trig; - s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE]; + s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE / sizeof(s32)] __aligned(8); }; /* @@ -91,7 +91,7 @@ static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val) &temp_val); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Error reading ALS %s", prop)); + acpi_evaluation_failure_warn(als->device->handle, prop, status); return -EIO; } @@ -104,33 +104,19 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) { struct iio_dev *indio_dev = acpi_driver_data(device); struct acpi_als *als = iio_priv(indio_dev); - s32 *buffer = als->evt_buffer; - s64 time_ns = iio_get_time_ns(indio_dev); - s32 val; - int ret; - mutex_lock(&als->lock); - - memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE); - - switch (event) { - case ACPI_ALS_NOTIFY_ILLUMINANCE: - ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); - if (ret < 0) - goto out; - *buffer++ = val; - break; - default: - /* Unhandled event */ - dev_dbg(&device->dev, "Unhandled ACPI ALS event (%08x)!\n", - event); - goto out; + if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) { + switch (event) { + case ACPI_ALS_NOTIFY_ILLUMINANCE: + iio_trigger_poll_chained(als->trig); + break; + default: + /* Unhandled event */ + dev_dbg(&device->dev, + "Unhandled ACPI ALS event (%08x)!\n", + event); + } } - - iio_push_to_buffers_with_timestamp(indio_dev, als->evt_buffer, time_ns); - -out: - mutex_unlock(&als->lock); } static int acpi_als_read_raw(struct iio_dev *indio_dev, @@ -161,13 +147,49 @@ static const struct iio_info acpi_als_info = { .read_raw = acpi_als_read_raw, }; +static irqreturn_t acpi_als_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct acpi_als *als = iio_priv(indio_dev); + s32 *buffer = als->evt_buffer; + s32 val; + int ret; + + mutex_lock(&als->lock); + + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); + if (ret < 0) + goto out; + *buffer = val; + + /* + * When coming from own trigger via polls, set polling function + * timestamp here. Given ACPI notifier is already in a thread and call + * function directly, there is no need to set the timestamp in the + * notify function. + * + * If the timestamp was actually 0, the timestamp is set one more time. + */ + if (!pf->timestamp) + pf->timestamp = iio_get_time_ns(indio_dev); + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); +out: + mutex_unlock(&als->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static int acpi_als_add(struct acpi_device *device) { - struct acpi_als *als; + struct device *dev = &device->dev; struct iio_dev *indio_dev; - struct iio_buffer *buffer; + struct acpi_als *als; + int ret; - indio_dev = devm_iio_device_alloc(&device->dev, sizeof(*als)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*als)); if (!indio_dev) return -ENOMEM; @@ -179,17 +201,30 @@ static int acpi_als_add(struct acpi_device *device) indio_dev->name = ACPI_ALS_DEVICE_NAME; indio_dev->info = &acpi_als_info; - indio_dev->modes = INDIO_BUFFER_SOFTWARE; indio_dev->channels = acpi_als_channels; indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels); - buffer = devm_iio_kfifo_allocate(&device->dev); - if (!buffer) + als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); + if (!als->trig) return -ENOMEM; - iio_device_attach_buffer(indio_dev, buffer); + ret = devm_iio_trigger_register(dev, als->trig); + if (ret) + return ret; + /* + * Set hardware trigger by default to let events flow when + * BIOS support notification. + */ + indio_dev->trig = iio_trigger_get(als->trig); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + acpi_als_trigger_handler, + NULL); + if (ret) + return ret; - return devm_iio_device_register(&device->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct acpi_device_id acpi_als_device_ids[] = { diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index df0647856e5df42f3cc17d5732375fdd0bb75605..4141c0fa7bc46a24014d748b60521f6e512e0cf4 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -988,7 +988,6 @@ static int apds9960_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct apds9960_data *data; - struct iio_buffer *buffer; struct iio_dev *indio_dev; int ret; @@ -996,19 +995,18 @@ static int apds9960_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; - buffer = devm_iio_kfifo_allocate(&client->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->info = &apds9960_info; indio_dev->name = APDS9960_DRV_NAME; indio_dev->channels = apds9960_channels; indio_dev->num_channels = ARRAY_SIZE(apds9960_channels); indio_dev->available_scan_masks = apds9960_scan_masks; - indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); - indio_dev->setup_ops = &apds9960_buffer_setup_ops; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &apds9960_buffer_setup_ops); + if (ret) + return ret; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 75d6b5fcf2cc47c585a360c1cbe5cf99b40cbabb..de472f23d1cbab563bfabdca5f05293c007274fa 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -182,8 +182,7 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) ret = cros_ec_sensors_core_init(pdev, indio_dev, true, cros_ec_sensors_capture, - cros_ec_sensors_push_data, - true); + cros_ec_sensors_push_data); if (ret) return ret; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index 7ba7aa59437c3d51f31707e98cd1af2922f983c1..d048ae257c5198759e576ed2053abfa5207128d9 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -465,8 +465,7 @@ static int gp2ap002_probe(struct i2c_client *client, regmap = devm_regmap_init(dev, &gp2ap002_regmap_bus, dev, &config); if (IS_ERR(regmap)) { - dev_err(dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } gp2ap002->map = regmap; diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index e2850c1a735339b4b9582728b06647383ac77a09..d1d9f2d319e45c801b7f6c5e0fcdde534f285827 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1551,7 +1551,6 @@ static int gp2ap020a00f_probe(struct i2c_client *client, } data->trig->ops = &gp2ap020a00f_trigger_ops; - data->trig->dev.parent = &data->client->dev; init_irq_work(&data->work, gp2ap020a00f_iio_trigger_work); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 4093f2353d9590d22cb98fd68db273fef4fe10d8..85c8a05b73cb7cb4d01f8b5baf2d357af160f95b 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -39,6 +39,11 @@ struct als_state { s64 timestamp; }; +static const u32 als_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_LIGHT, + HID_USAGE_SENSOR_LIGHT_ILLUM, +}; + /* Channel definitions */ static const struct iio_chan_spec als_channels[] = { { @@ -49,7 +54,8 @@ static const struct iio_chan_spec als_channels[] = { .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), + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), .scan_index = CHANNEL_SCAN_INDEX_INTENSITY, }, { @@ -58,7 +64,8 @@ static const struct iio_chan_spec als_channels[] = { .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), + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), .scan_index = CHANNEL_SCAN_INDEX_ILLUM, }, IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) @@ -136,6 +143,10 @@ static int als_read_raw(struct iio_dev *indio_dev, ret_type = hid_sensor_read_raw_hyst_value( &als_state->common_attributes, val, val2); break; + case IIO_CHAN_INFO_HYSTERESIS_RELATIVE: + ret_type = hid_sensor_read_raw_hyst_rel_value( + &als_state->common_attributes, val, val2); + break; default: ret_type = -EINVAL; break; @@ -163,6 +174,10 @@ static int als_write_raw(struct iio_dev *indio_dev, ret = hid_sensor_write_raw_hyst_value( &als_state->common_attributes, val, val2); break; + case IIO_CHAN_INFO_HYSTERESIS_RELATIVE: + ret = hid_sensor_write_raw_hyst_rel_value( + &als_state->common_attributes, val, val2); + break; default: ret = -EINVAL; } @@ -252,17 +267,6 @@ static int als_parse_report(struct platform_device *pdev, &st->als_illum, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_LIGHT, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -285,7 +289,9 @@ static int hid_als_probe(struct platform_device *pdev) als_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS, - &als_state->common_attributes); + &als_state->common_attributes, + als_sensitivity_addresses, + ARRAY_SIZE(als_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index e9e00ce0c6d4d45a19f764f0a1634cce8f93d615..17d167c3d595aaec6b78b0f34b4793b4e43d965a 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -28,6 +28,11 @@ struct prox_state { int scale_precision; }; +static const u32 prox_sensitivity_addresses[] = { + HID_USAGE_SENSOR_HUMAN_PRESENCE, + HID_USAGE_SENSOR_DATA_PRESENCE, +}; + /* Channel definitions */ static const struct iio_chan_spec prox_channels[] = { { @@ -220,29 +225,6 @@ static int prox_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index, st->prox_attr.report_id); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_PRESENCE, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - if (st->common_attributes.sensitivity.index < 0) - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_HUMAN_PRESENCE, - &st->common_attributes.sensitivity); - - st->scale_precision = hid_sensor_format_scale( - hsdev->usage, - &st->prox_attr, - &st->scale_pre_decml, &st->scale_post_decml); - return ret; } @@ -266,7 +248,9 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX, - &prox_state->common_attributes); + &prox_state->common_attributes, + prox_sensitivity_addresses, + ARRAY_SIZE(prox_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 2d48d61909a4de45c1e14c3b6aef2fc2159b560e..52963da401a78e9bdbba5bc186455312a1c9c882 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * opt3001.c - Texas Instruments OPT3001 Light Sensor * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 31224a33bade378efc39dc9622f34a7229b9de38..033578f444e4a6f23b924a5fc5fc131a0f13100a 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -990,7 +990,6 @@ static int rpr0521_probe(struct i2c_client *client, ret = -ENOMEM; goto err_pm_disable; } - data->drdy_trigger0->dev.parent = indio_dev->dev.parent; data->drdy_trigger0->ops = &rpr0521_trigger_ops; indio_dev->available_scan_masks = rpr0521_available_scan_masks; iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev); diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index b304801c791634914f24918cdc0fe78bd3ac36a3..9b5c99823943a1f050dcdfd507c8c392c82a077e 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -1247,7 +1247,6 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev) if (!trig) return -ENOMEM; - trig->dev.parent = &client->dev; trig->ops = &si1145_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index 1055594b22764e5ec7f7df5d0a80163a0150d300..41a2ce5a2d53882c807bde64a67d238aa3ce64e2 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -210,7 +210,6 @@ static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev) return -ENOMEM; iio_trigger_set_drvdata(hw->trig, iio_dev); - hw->trig->dev.parent = dev; return devm_iio_trigger_register(dev, hw->trig); } diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index a2827d03ab0fb4282e4a4bae22aea10be39abd72..07e91846307c7d38474b46e2fafc68767b997724 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor * * Copyright (c) 2015, Intel Corporation. diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index fff4b36b8b58dc04cc197b52a846d9737a95648a..2f7916f95689e873b21bad598138a2c5257deda4 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1002,7 +1002,6 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev) if (!trigger) return -ENOMEM; - trigger->dev.parent = &client->dev; trigger->ops = &vcnl4010_trigger_ops; iio_trigger_set_drvdata(trigger, indio_dev); diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 73a28e30dddccd7b26219e0017467406a75ecc46..ae87740d9cef21a4f5f51821c802d8293367a262 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -511,7 +511,6 @@ static int vcnl4035_probe_trigger(struct iio_dev *indio_dev) if (!data->drdy_trigger0) return -ENOMEM; - data->drdy_trigger0->dev.parent = indio_dev->dev.parent; data->drdy_trigger0->ops = &vcnl4035_trigger_ops; iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev); ret = devm_iio_trigger_register(indio_dev->dev.parent, diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index b2f3129e1b4f3cefe371d487acc93c805b65fa16..00f9766bad5c54bd3b3de8603054356958a68e5d 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -922,7 +922,6 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, goto err_poweroff; } - data->dready_trig->dev.parent = dev; data->dready_trig->ops = &bmc150_magn_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); ret = iio_trigger_register(data->dready_trig); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index fa48044b7f5b574513e9abdefd8a462d652618da..b78691523dd4ce01e17e0a8dc8c09ca6571e8f2d 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -62,6 +62,11 @@ static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_TIME_TIMESTAMP, }; +static const u32 magn_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ORIENTATION, + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX, +}; + /* Channel definitions */ static const struct iio_chan_spec magn_3d_channels[] = { { @@ -448,27 +453,6 @@ static int magn_3d_parse_report(struct platform_device *pdev, &st->rot_attr.scale_pre_decml, &st->rot_attr.scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->magn_flux_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->magn_flux_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->magn_flux_attributes.sensitivity.index, - st->magn_flux_attributes.sensitivity.report_id); - } - if (st->magn_flux_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX, - &st->magn_flux_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->magn_flux_attributes.sensitivity.index, - st->magn_flux_attributes.sensitivity.report_id); - } if (st->rot_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, @@ -507,12 +491,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_COMPASS_3D, - &magn_state->magn_flux_attributes); + &magn_state->magn_flux_attributes, + magn_3d_sensitivity_addresses, + ARRAY_SIZE(magn_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; } magn_state->rot_attributes = magn_state->magn_flux_attributes; + /* sensitivity of rot_attribute is not the same as magn_flux_attributes */ + magn_state->rot_attributes.sensitivity.index = -1; ret = magn_3d_parse_report(pdev, hsdev, &channels, &chan_count, diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index 7242897a05e956ee853ebb30a7c8c862bf72722e..dd811da9cb6dbbae02f67e05ab114d887e5b9416 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -579,7 +579,6 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) if (!data->drdy_trig) return -ENOMEM; - data->drdy_trig->dev.parent = dev; ret = devm_iio_trigger_register(dev, data->drdy_trig); if (ret < 0) return ret; diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 204b285725c8aaf6e60db6c92e14a4a4adf6e04f..7ba6a6ba5c5873c31787181ad21b12703cc94b5c 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -21,6 +21,7 @@ #define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn" #define LIS2MDL_MAGN_DEV_NAME "lis2mdl" #define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn" +#define IIS2MDC_MAGN_DEV_NAME "iis2mdc" const struct st_sensor_settings *st_magn_get_settings(const char *name); int st_magn_common_probe(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 79de721e60159cdc6d7b1271e1abac2dd492364a..71faebd07feb79c0715fc113995e4e6136ee542c 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -337,6 +337,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .sensors_supported = { [0] = LSM303AGR_MAGN_DEV_NAME, [1] = LIS2MDL_MAGN_DEV_NAME, + [2] = IIS2MDC_MAGN_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_magn_3_16bit_channels, .odr = { diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index c6bb4ce7759435be2af4454702259775d266a286..36f4e7b53b24ff4fed8418e764a12aa0408a7b2c 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -46,6 +46,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lsm9ds1-magn", .data = LSM9DS1_MAGN_DEV_NAME, }, + { + .compatible = "st,iis2mdc", + .data = IIS2MDC_MAGN_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -101,6 +105,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LSM303AGR_MAGN_DEV_NAME }, { LIS2MDL_MAGN_DEV_NAME }, { LSM9DS1_MAGN_DEV_NAME }, + { IIS2MDC_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 3d08d74c367da58d9db3fcebd90a101225a39a19..0e2323dfc68751857c185e4a366c913f323bca62 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -41,6 +41,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lsm9ds1-magn", .data = LSM9DS1_MAGN_DEV_NAME, }, + { + .compatible = "st,iis2mdc", + .data = IIS2MDC_MAGN_DEV_NAME, + }, {} }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -92,6 +96,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LSM303AGR_MAGN_DEV_NAME }, { LIS2MDL_MAGN_DEV_NAME }, { LSM9DS1_MAGN_DEV_NAME }, + { IIS2MDC_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index d46f23d82b3da296cd5caa5b9027400f46f76bc5..2f2f8cb3c26cde7d374337f521a85399decbc255 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -32,13 +32,14 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/random.h> -#include <linux/unaligned/be_byteshift.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <asm/unaligned.h> + /* This register map covers YAS530 and YAS532 but differs in YAS 537 and YAS539 */ #define YAS5XX_DEVICE_ID 0x80 #define YAS5XX_ACTUATE_INIT_COIL 0x81 @@ -887,6 +888,7 @@ static int yas5xx_probe(struct i2c_client *i2c, strncpy(yas5xx->name, "yas532", sizeof(yas5xx->name)); break; default: + ret = -ENODEV; dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid); goto assert_reset; } diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 52ebef30f9be062231a5079d5ebbd1f0307f9f3a..7af48d3362853f13b9ebe49a7f5d6b1b3e40a320 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -47,6 +47,11 @@ static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ORIENT_TILT_Z }; +static const u32 incl_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ORIENTATION, + HID_USAGE_SENSOR_ORIENT_TILT, +}; + /* Channel definitions */ static const struct iio_chan_spec incl_3d_channels[] = { { @@ -291,17 +296,6 @@ static int incl_3d_parse_report(struct platform_device *pdev, &st->incl[CHANNEL_SCAN_INDEX_X], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -327,7 +321,9 @@ static int hid_incl_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D, - &incl_state->common_attributes); + &incl_state->common_attributes, + incl_3d_sensitivity_addresses, + ARRAY_SIZE(incl_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 18e4ef0600963cee30c556e124a03a48c491b7ff..cf7f57a476813817dde7af77faa04b422a0584a9 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -21,7 +21,7 @@ struct dev_rot_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info quaternion; struct { - u32 sampled_vals[4] __aligned(16); + s32 sampled_vals[4] __aligned(16); u64 timestamp __aligned(8); } scan; int scale_pre_decml; @@ -31,6 +31,11 @@ struct dev_rot_state { s64 timestamp; }; +static const u32 rotation_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ORIENTATION, + HID_USAGE_SENSOR_ORIENT_QUATERNION, +}; + /* Channel definitions */ static const struct iio_chan_spec dev_rot_channels[] = { { @@ -170,8 +175,15 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, struct dev_rot_state *rot_state = iio_priv(indio_dev); if (usage_id == HID_USAGE_SENSOR_ORIENT_QUATERNION) { - memcpy(&rot_state->scan.sampled_vals, raw_data, - sizeof(rot_state->scan.sampled_vals)); + if (raw_len / 4 == sizeof(s16)) { + rot_state->scan.sampled_vals[0] = ((s16 *)raw_data)[0]; + rot_state->scan.sampled_vals[1] = ((s16 *)raw_data)[1]; + rot_state->scan.sampled_vals[2] = ((s16 *)raw_data)[2]; + rot_state->scan.sampled_vals[3] = ((s16 *)raw_data)[3]; + } else { + memcpy(&rot_state->scan.sampled_vals, raw_data, + sizeof(rot_state->scan.sampled_vals)); + } dev_dbg(&indio_dev->dev, "Recd Quat len:%zu::%zu\n", raw_len, sizeof(rot_state->scan.sampled_vals)); @@ -214,18 +226,6 @@ static int dev_rot_parse_report(struct platform_device *pdev, &st->quaternion, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - return 0; } @@ -263,8 +263,11 @@ static int hid_dev_rot_probe(struct platform_device *pdev) return -EINVAL; } - ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, - &rot_state->common_attributes); + ret = hid_sensor_parse_common_attributes(hsdev, + hsdev->usage, + &rot_state->common_attributes, + rotation_sensitivity_addresses, + ARRAY_SIZE(rotation_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index 64a7fa7db6af96cbc517907d566b8423657c926a..fd77e7ee87f3581f026192a2d54e7d41b403be9a 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -47,6 +47,10 @@ struct hinge_state { u64 timestamp; }; +static const u32 hinge_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1), +}; + /* Channel definitions */ static const struct iio_chan_spec hinge_channels[] = { { @@ -251,18 +255,6 @@ static int hinge_parse_report(struct platform_device *pdev, &st->hinge[CHANNEL_SCAN_INDEX_HINGE_ANGLE], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1), - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - return ret; } @@ -289,7 +281,9 @@ static int hid_hinge_probe(struct platform_device *pdev) st->labels[i] = hinge_labels[i]; ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, - &st->common_attributes); + &st->common_attributes, + hinge_sensitivity_addresses, + ARRAY_SIZE(hinge_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c index a88ed0eb3adc69838b34071a8beac93f85530a85..6e22b538091f0c56d308ce7469b29fdbcedea2df 100644 --- a/drivers/iio/potentiometer/max5481.c +++ b/drivers/iio/potentiometer/max5481.c @@ -136,7 +136,7 @@ static int max5481_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; - dev_set_drvdata(&spi->dev, indio_dev); + spi_set_drvdata(spi, indio_dev); data = iio_priv(indio_dev); data->spi = spi; @@ -163,7 +163,7 @@ static int max5481_probe(struct spi_device *spi) static int max5481_remove(struct spi_device *spi) { - struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + struct iio_dev *indio_dev = spi_get_drvdata(spi); struct max5481_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 7ec51976ec9957c466315955cd327107d0b9b66e..1c0d46a9620002c0fd48ae6fe8262f884ebf3273 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -92,7 +92,7 @@ static int max5487_spi_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; - dev_set_drvdata(&spi->dev, indio_dev); + spi_set_drvdata(spi, indio_dev); data = iio_priv(indio_dev); data->spi = spi; @@ -114,7 +114,7 @@ static int max5487_spi_probe(struct spi_device *spi) static int max5487_spi_remove(struct spi_device *spi) { - struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index f34ca769dc20de80c0d641f809f0b44bb507e683..8a9c576616ee509ec22a420cbab446ea81d19ad8 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -322,7 +322,7 @@ static int lmp91000_probe(struct i2c_client *client, return PTR_ERR(data->regmap); } - data->trig = devm_iio_trigger_alloc(data->dev, "%s-mux%d", + data->trig = devm_iio_trigger_alloc(dev, "%s-mux%d", indio_dev->name, indio_dev->id); if (!data->trig) { dev_err(dev, "cannot allocate iio trigger.\n"); @@ -330,7 +330,6 @@ static int lmp91000_probe(struct i2c_client *client, } data->trig->ops = &lmp91000_trigger_ops; - data->trig->dev.parent = dev; init_completion(&data->completion); ret = lmp91000_read_config(data); diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index aa043cb9ac4265a641581669970ae6c9116af028..2f882e1094232e939c2119861e93eb0d82cb7edc 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -139,8 +139,7 @@ static int cros_ec_baro_probe(struct platform_device *pdev) ret = cros_ec_sensors_core_init(pdev, indio_dev, true, cros_ec_sensors_capture, - cros_ec_sensors_push_data, - true); + cros_ec_sensors_push_data); if (ret) return ret; diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 5c458788f346e72a47d56df9439b39b39ec7e161..c416d261e3e35bcd7348ecf8b7fdd1bb29fc4745 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -29,6 +29,11 @@ struct press_state { int value_offset; }; +static const u32 press_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, + HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE +}; + /* Channel definitions */ static const struct iio_chan_spec press_channels[] = { { @@ -225,17 +230,6 @@ static int press_parse_report(struct platform_device *pdev, &st->press_attr, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -260,7 +254,9 @@ static int hid_press_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PRESSURE, - &press_state->common_attributes); + &press_state->common_attributes, + press_sensitivity_addresses, + ARRAY_SIZE(press_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 2cecbe0adb3f382be11c90b1f3615824f9f28527..a93411216aeeeaf0d178feaab209ff1753a14800 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -103,7 +103,7 @@ static const struct zpa2326_frequency *zpa2326_highest_frequency(void) } /** - * struct zpa_private - Per-device internal private state + * struct zpa2326_private - Per-device internal private state * @timestamp: Buffered samples ready datum. * @regmap: Underlying I2C / SPI bus adapter used to abstract slave register * accesses. @@ -1382,7 +1382,7 @@ static const struct iio_trigger_ops zpa2326_trigger_ops = { }; /** - * zpa2326_init_trigger() - Create an interrupt driven / hardware trigger + * zpa2326_init_managed_trigger() - Create interrupt driven / hardware trigger * allowing to notify external devices a new sample is * ready. * @parent: Hardware sampling device @indio_dev is a child of. @@ -1413,7 +1413,6 @@ static int zpa2326_init_managed_trigger(struct device *parent, return -ENOMEM; /* Basic setup. */ - trigger->dev.parent = parent; trigger->ops = &zpa2326_trigger_ops; private->trigger = trigger; diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 12672a0e89ede30673d9896d28a0ce3d2707848d..7c7203ca3ac63803261ad4ae7aafc690c9ccff89 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -21,6 +21,17 @@ endmenu menu "Proximity and distance sensors" +config CROS_EC_MKBP_PROXIMITY + tristate "ChromeOS EC MKBP Proximity sensor" + depends on CROS_EC + help + Say Y here to enable the proximity sensor implemented via the ChromeOS EC MKBP + switches protocol. You must enable one bus option (CROS_EC_I2C or CROS_EC_SPI) + to use this. + + To compile this driver as a module, choose M here: the + module will be called cros_ec_mkbp_proximity. + config ISL29501 tristate "Intersil ISL29501 Time Of Flight sensor" depends on I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index 9c1aca1a8b79a71127ac32158640b2461e556045..cbdac09433eb51379dc8d7d09d8465c84376508d 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AS3935) += as3935.o +obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_MB1232) += mb1232.o diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index b79ada839e0129b6a28202896569af27bc0934b2..edc4a35ae66d1851d9acfce5ed1c578d9bf6add8 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -411,7 +411,6 @@ static int as3935_probe(struct spi_device *spi) st->trig = trig; st->noise_tripped = jiffies - HZ; - trig->dev.parent = indio_dev->dev.parent; iio_trigger_set_drvdata(trig, indio_dev); trig->ops = &iio_interrupt_trigger_ops; diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c new file mode 100644 index 0000000000000000000000000000000000000000..8213b00817132d7b8c2eec8c76a3beb28a093f99 --- /dev/null +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for cros-ec proximity sensor exposed through MKBP switch + * + * Copyright 2021 Google LLC. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <linux/platform_data/cros_ec_commands.h> +#include <linux/platform_data/cros_ec_proto.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#include <asm/unaligned.h> + +struct cros_ec_mkbp_proximity_data { + struct cros_ec_device *ec; + struct iio_dev *indio_dev; + struct mutex lock; + struct notifier_block notifier; + int last_proximity; + bool enabled; +}; + +static const struct iio_event_spec cros_ec_mkbp_proximity_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec cros_ec_mkbp_proximity_chan_spec[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .event_spec = cros_ec_mkbp_proximity_events, + .num_event_specs = ARRAY_SIZE(cros_ec_mkbp_proximity_events), + }, +}; + +static int cros_ec_mkbp_proximity_parse_state(const void *data) +{ + u32 switches = get_unaligned_le32(data); + + return !!(switches & BIT(EC_MKBP_FRONT_PROXIMITY)); +} + +static int cros_ec_mkbp_proximity_query(struct cros_ec_device *ec_dev, + int *state) +{ + struct { + struct cros_ec_command msg; + union { + struct ec_params_mkbp_info params; + u32 switches; + }; + } __packed buf = { }; + struct ec_params_mkbp_info *params = &buf.params; + struct cros_ec_command *msg = &buf.msg; + u32 *switches = &buf.switches; + size_t insize = sizeof(*switches); + int ret; + + msg->command = EC_CMD_MKBP_INFO; + msg->version = 1; + msg->outsize = sizeof(*params); + msg->insize = insize; + + params->info_type = EC_MKBP_INFO_CURRENT; + params->event_type = EC_MKBP_EVENT_SWITCH; + + ret = cros_ec_cmd_xfer_status(ec_dev, msg); + if (ret < 0) + return ret; + + if (ret != insize) { + dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n", ret, + insize); + return -EPROTO; + } + + *state = cros_ec_mkbp_proximity_parse_state(switches); + return IIO_VAL_INT; +} + +static void cros_ec_mkbp_proximity_push_event(struct cros_ec_mkbp_proximity_data *data, int state) +{ + s64 timestamp; + u64 ev; + int dir; + struct iio_dev *indio_dev = data->indio_dev; + struct cros_ec_device *ec = data->ec; + + mutex_lock(&data->lock); + if (state != data->last_proximity) { + if (data->enabled) { + timestamp = ktime_to_ns(ec->last_event_time); + if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME) + timestamp = iio_get_time_ns(indio_dev); + + dir = state ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; + ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, dir); + iio_push_event(indio_dev, ev, timestamp); + } + data->last_proximity = state; + } + mutex_unlock(&data->lock); +} + +static int cros_ec_mkbp_proximity_notify(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_ec) +{ + struct cros_ec_mkbp_proximity_data *data; + struct cros_ec_device *ec = _ec; + u8 event_type = ec->event_data.event_type & EC_MKBP_EVENT_TYPE_MASK; + void *switches; + int state; + + if (event_type == EC_MKBP_EVENT_SWITCH) { + data = container_of(nb, struct cros_ec_mkbp_proximity_data, + notifier); + + switches = &ec->event_data.data.switches; + state = cros_ec_mkbp_proximity_parse_state(switches); + cros_ec_mkbp_proximity_push_event(data, state); + } + + return NOTIFY_OK; +} + +static int cros_ec_mkbp_proximity_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev); + struct cros_ec_device *ec = data->ec; + + if (chan->type == IIO_PROXIMITY && mask == IIO_CHAN_INFO_RAW) + return cros_ec_mkbp_proximity_query(ec, val); + + return -EINVAL; +} + +static int cros_ec_mkbp_proximity_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 cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev); + + return data->enabled; +} + +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) +{ + struct cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev); + + mutex_lock(&data->lock); + data->enabled = state; + mutex_unlock(&data->lock); + + return 0; +} + +static const struct iio_info cros_ec_mkbp_proximity_info = { + .read_raw = cros_ec_mkbp_proximity_read_raw, + .read_event_config = cros_ec_mkbp_proximity_read_event_config, + .write_event_config = cros_ec_mkbp_proximity_write_event_config, +}; + +static __maybe_unused int cros_ec_mkbp_proximity_resume(struct device *dev) +{ + struct cros_ec_mkbp_proximity_data *data = dev_get_drvdata(dev); + struct cros_ec_device *ec = data->ec; + int ret, state; + + ret = cros_ec_mkbp_proximity_query(ec, &state); + if (ret < 0) { + dev_warn(dev, "failed to fetch proximity state on resume: %d\n", + ret); + } else { + cros_ec_mkbp_proximity_push_event(data, state); + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(cros_ec_mkbp_proximity_pm_ops, NULL, + cros_ec_mkbp_proximity_resume); + +static int cros_ec_mkbp_proximity_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cros_ec_device *ec = dev_get_drvdata(dev->parent); + struct iio_dev *indio_dev; + struct cros_ec_mkbp_proximity_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->ec = ec; + data->indio_dev = indio_dev; + data->last_proximity = -1; /* Unknown to start */ + mutex_init(&data->lock); + platform_set_drvdata(pdev, data); + + indio_dev->name = dev->driver->name; + indio_dev->info = &cros_ec_mkbp_proximity_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = cros_ec_mkbp_proximity_chan_spec; + indio_dev->num_channels = ARRAY_SIZE(cros_ec_mkbp_proximity_chan_spec); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return ret; + + data->notifier.notifier_call = cros_ec_mkbp_proximity_notify; + blocking_notifier_chain_register(&ec->event_notifier, &data->notifier); + + return 0; +} + +static int cros_ec_mkbp_proximity_remove(struct platform_device *pdev) +{ + struct cros_ec_mkbp_proximity_data *data = platform_get_drvdata(pdev); + struct cros_ec_device *ec = data->ec; + + blocking_notifier_chain_unregister(&ec->event_notifier, + &data->notifier); + + return 0; +} + +static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = { + { .compatible = "google,cros-ec-mkbp-proximity" }, + {} +}; +MODULE_DEVICE_TABLE(of, cros_ec_mkbp_proximity_of_match); + +static struct platform_driver cros_ec_mkbp_proximity_driver = { + .driver = { + .name = "cros-ec-mkbp-proximity", + .of_match_table = cros_ec_mkbp_proximity_of_match, + .pm = &cros_ec_mkbp_proximity_pm_ops, + }, + .probe = cros_ec_mkbp_proximity_probe, + .remove = cros_ec_mkbp_proximity_remove, +}; +module_platform_driver(cros_ec_mkbp_proximity_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ChromeOS EC MKBP proximity sensor driver"); diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 37fd0b65a0140085a9672269bd02adf8da391d6f..327ebb7ddbb9cfa3ab06017cb2eb5cd81810f0b6 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -763,7 +763,11 @@ static int sx9310_write_far_debounce(struct sx9310_data *data, int val) int ret; unsigned int regval; - val = ilog2(val); + if (val > 0) + val = ilog2(val); + if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val)) + return -EINVAL; + regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val); mutex_lock(&data->mutex); @@ -780,7 +784,11 @@ static int sx9310_write_close_debounce(struct sx9310_data *data, int val) int ret; unsigned int regval; - val = ilog2(val); + if (val > 0) + val = ilog2(val); + if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val)) + return -EINVAL; + regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val); mutex_lock(&data->mutex); @@ -1213,17 +1221,17 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev) } static const struct sx9310_reg_default * -sx9310_get_default_reg(struct sx9310_data *data, int i, +sx9310_get_default_reg(struct sx9310_data *data, int idx, struct sx9310_reg_default *reg_def) { - int ret; const struct device_node *np = data->client->dev.of_node; - u32 combined[SX9310_NUM_CHANNELS] = { 4, 4, 4, 4 }; + u32 combined[SX9310_NUM_CHANNELS]; + u32 start = 0, raw = 0, pos = 0; unsigned long comb_mask = 0; + int ret, i, count; const char *res; - u32 start = 0, raw = 0, pos = 0; - memcpy(reg_def, &sx9310_default_regs[i], sizeof(*reg_def)); + memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def)); if (!np) return reg_def; @@ -1234,15 +1242,31 @@ sx9310_get_default_reg(struct sx9310_data *data, int i, reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND; } - reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK; - of_property_read_u32_array(np, "semtech,combined-sensors", - combined, ARRAY_SIZE(combined)); - for (i = 0; i < ARRAY_SIZE(combined); i++) { - if (combined[i] <= SX9310_NUM_CHANNELS) - comb_mask |= BIT(combined[i]); + count = of_property_count_elems_of_size(np, "semtech,combined-sensors", + sizeof(u32)); + if (count > 0 && count <= ARRAY_SIZE(combined)) { + ret = of_property_read_u32_array(np, "semtech,combined-sensors", + combined, count); + if (ret) + break; + } else { + /* + * Either the property does not exist in the DT or the + * number of entries is incorrect. + */ + break; } + for (i = 0; i < count; i++) { + if (combined[i] >= SX9310_NUM_CHANNELS) { + /* Invalid sensor (invalid DT). */ + break; + } + comb_mask |= BIT(combined[i]); + } + if (i < count) + break; - comb_mask &= 0xf; + reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK; if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0))) reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3; else if (comb_mask == (BIT(1) | BIT(2))) @@ -1453,7 +1477,6 @@ static int sx9310_probe(struct i2c_client *client) if (!data->trig) return -ENOMEM; - data->trig->dev.parent = dev; data->trig->ops = &sx9310_trigger_ops; iio_trigger_set_drvdata(data->trig, indio_dev); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index acb821cbad46ffdcee84ccf73249c0b8d81a7b06..a87f4a8e43273ac158c071b8f95beb95796c886e 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -758,7 +758,7 @@ static const struct sx9500_reg_default sx9500_default_regs[] = { .reg = SX9500_REG_PROX_CTRL5, /* * Debouncer off, lowest average negative filter, - * highest average postive filter. + * highest average positive filter. */ .def = 0x0f, }, @@ -950,7 +950,6 @@ static int sx9500_probe(struct i2c_client *client, if (!data->trig) return -ENOMEM; - data->trig->dev.parent = &client->dev; data->trig->ops = &sx9500_trigger_ops; iio_trigger_set_drvdata(data->trig, indio_dev); diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index 37264f801ad023cb96b6020d79a93d4ac5023873..43817f6b3086678c5e4eaa1a06778f1fe37e837f 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -40,6 +40,17 @@ #define VCNL_ON_DEMAND_TIMEOUT_US 100000 #define VCNL_POLL_US 20000 +static const int vcnl3020_prox_sampling_frequency[][2] = { + {1, 950000}, + {3, 906250}, + {7, 812500}, + {16, 625000}, + {31, 250000}, + {62, 500000}, + {125, 0}, + {250, 0}, +}; + /** * struct vcnl3020_data - vcnl3020 specific data. * @regmap: device register map. @@ -165,10 +176,51 @@ err_unlock: return rc; } +static int vcnl3020_read_proxy_samp_freq(struct vcnl3020_data *data, int *val, + int *val2) +{ + int rc; + unsigned int prox_rate; + + rc = regmap_read(data->regmap, VCNL_PROXIMITY_RATE, &prox_rate); + if (rc) + return rc; + + if (prox_rate >= ARRAY_SIZE(vcnl3020_prox_sampling_frequency)) + return -EINVAL; + + *val = vcnl3020_prox_sampling_frequency[prox_rate][0]; + *val2 = vcnl3020_prox_sampling_frequency[prox_rate][1]; + + return 0; +} + +static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val, + int val2) +{ + unsigned int i; + int index = -1; + + for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) { + if (val == vcnl3020_prox_sampling_frequency[i][0] && + val2 == vcnl3020_prox_sampling_frequency[i][1]) { + index = i; + break; + } + } + + if (index < 0) + return -EINVAL; + + return regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index); +} + static const struct iio_chan_spec vcnl3020_channels[] = { { .type = IIO_PROXIMITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, }; @@ -185,6 +237,47 @@ static int vcnl3020_read_raw(struct iio_dev *indio_dev, if (rc) return rc; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + rc = vcnl3020_read_proxy_samp_freq(data, val, val2); + if (rc < 0) + return rc; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int vcnl3020_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int rc; + struct vcnl3020_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + rc = iio_device_claim_direct_mode(indio_dev); + if (rc) + return rc; + rc = vcnl3020_write_proxy_samp_freq(data, val, val2); + iio_device_release_direct_mode(indio_dev); + return rc; + default: + return -EINVAL; + } +} + +static int vcnl3020_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_SAMP_FREQ: + *vals = (int *)vcnl3020_prox_sampling_frequency; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = 2 * ARRAY_SIZE(vcnl3020_prox_sampling_frequency); + return IIO_AVAIL_LIST; default: return -EINVAL; } @@ -192,6 +285,8 @@ static int vcnl3020_read_raw(struct iio_dev *indio_dev, static const struct iio_info vcnl3020_info = { .read_raw = vcnl3020_read_raw, + .write_raw = vcnl3020_write_raw, + .read_avail = vcnl3020_read_avail, }; static const struct regmap_config vcnl3020_regmap_config = { diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index da9a247097fa29664d4e144a199d6e566e71e1d6..dc534ed784c39e76535e2ff234924c5ffe53bb75 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -25,6 +25,10 @@ struct temperature_state { int value_offset; }; +static const u32 temperature_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, +}; + /* Channel definitions */ static const struct iio_chan_spec temperature_channels[] = { { @@ -173,14 +177,6 @@ static int temperature_parse_report(struct platform_device *pdev, &st->temperature_attr, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, - &st->common_attributes.sensitivity); - return ret; } @@ -209,7 +205,9 @@ static int hid_temperature_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_TEMPERATURE, - &temp_st->common_attributes); + &temp_st->common_attributes, + temperature_sensitivity_addresses, + ARRAY_SIZE(temperature_sensitivity_addresses)); if (ret) return ret; diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index ad2b35c6554853dc41017d9c237f40562f1a36d6..b422371a46744560fc3e19f6f4f56c0e601df951 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -439,6 +439,13 @@ static bool tmp007_identify(struct i2c_client *client) return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC); } +static void tmp007_powerdown_action_cb(void *priv) +{ + struct tmp007_data *data = priv; + + tmp007_powerdown(data); +} + static int tmp007_probe(struct i2c_client *client, const struct i2c_device_id *tmp007_id) { @@ -489,6 +496,10 @@ static int tmp007_probe(struct i2c_client *client, if (ret < 0) return ret; + ret = devm_add_action_or_reset(&client->dev, tmp007_powerdown_action_cb, data); + if (ret) + return ret; + /* * Only the following flags can activate ALERT pin. Data conversion/validity flags * flags can still be polled for getting temperature data @@ -502,7 +513,7 @@ static int tmp007_probe(struct i2c_client *client, ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK); if (ret < 0) - goto error_powerdown; + return ret; data->status_mask = ret; data->status_mask |= (TMP007_STATUS_OHF | TMP007_STATUS_OLF @@ -510,7 +521,7 @@ static int tmp007_probe(struct i2c_client *client, ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, data->status_mask); if (ret < 0) - goto error_powerdown; + return ret; if (client->irq) { ret = devm_request_threaded_irq(&client->dev, client->irq, @@ -519,27 +530,11 @@ static int tmp007_probe(struct i2c_client *client, tmp007_id->name, indio_dev); if (ret) { dev_err(&client->dev, "irq request error %d\n", -ret); - goto error_powerdown; + return ret; } } - return iio_device_register(indio_dev); - -error_powerdown: - tmp007_powerdown(data); - - return ret; -} - -static int tmp007_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct tmp007_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - tmp007_powerdown(data); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP @@ -582,7 +577,6 @@ static struct i2c_driver tmp007_driver = { .pm = &tmp007_pm_ops, }, .probe = tmp007_probe, - .remove = tmp007_remove, .id_table = tmp007_id, }; module_i2c_driver(tmp007_driver); diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..679a7794af20e6d527d143000ceaf3de663205f0 --- /dev/null +++ b/drivers/iio/test/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Industrial I/O subsystem unit tests configuration +# + +# Keep in alphabetical order +config IIO_TEST_FORMAT + bool "Test IIO formatting functions" + depends on KUNIT=y diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f1099b4953014c628002341426eb949f441fb332 --- /dev/null +++ b/drivers/iio/test/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the industrial I/O unit tests. +# + +# Keep in alphabetical order +obj-$(CONFIG_IIO_TEST_FORMAT) += iio-test-format.o diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c new file mode 100644 index 0000000000000000000000000000000000000000..55a0cfe9181d23cdd1543de7ba296c6e327713a2 --- /dev/null +++ b/drivers/iio/test/iio-test-format.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Unit tests for IIO formatting functions + * + * Copyright (c) 2020 Lars-Peter Clausen <lars@metafoo.de> + */ + +#include <kunit/test.h> +#include <linux/iio/iio.h> + +#define IIO_TEST_FORMAT_EXPECT_EQ(_test, _buf, _ret, _val) do { \ + KUNIT_EXPECT_EQ(_test, (int)strlen(_buf), _ret); \ + KUNIT_EXPECT_STREQ(_test, (_buf), (_val)); \ + } while (0) + +static void iio_test_iio_format_value_integer(struct kunit *test) +{ + char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + int val; + int ret; + + val = 42; + ret = iio_format_value(buf, IIO_VAL_INT, 1, &val); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "42\n"); + + val = -23; + ret = iio_format_value(buf, IIO_VAL_INT, 1, &val); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-23\n"); + + val = 0; + ret = iio_format_value(buf, IIO_VAL_INT, 1, &val); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0\n"); + + val = INT_MAX; + ret = iio_format_value(buf, IIO_VAL_INT, 1, &val); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "2147483647\n"); + + val = INT_MIN; + ret = iio_format_value(buf, IIO_VAL_INT, 1, &val); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-2147483648\n"); +} + +static void iio_test_iio_format_value_fixedpoint(struct kunit *test) +{ + char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + int values[2]; + int ret; + + /* positive >= 1 */ + values[0] = 1; + values[1] = 10; + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000010\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000010 dB\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000000010\n"); + + /* positive < 1 */ + values[0] = 0; + values[1] = 12; + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000012\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000012 dB\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000000012\n"); + + /* negative <= -1 */ + values[0] = -1; + values[1] = 10; + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.000010\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.000010 dB\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.000000010\n"); + + /* negative > -1 */ + values[0] = 0; + values[1] = -123; + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000123\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000123 dB\n"); + + ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000000123\n"); +} + +static void iio_test_iio_format_value_fractional(struct kunit *test) +{ + char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + int values[2]; + int ret; + + /* positive < 1 */ + values[0] = 1; + values[1] = 10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.100000000\n"); + + /* positive >= 1 */ + values[0] = 100; + values[1] = 3; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "33.333333333\n"); + + /* negative > -1 */ + values[0] = -1; + values[1] = 1000000000; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000000001\n"); + + /* negative <= -1 */ + values[0] = -200; + values[1] = 3; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-66.666666666\n"); + + /* Zero */ + values[0] = 0; + values[1] = -10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000000000\n"); +} + +static void iio_test_iio_format_value_fractional_log2(struct kunit *test) +{ + char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + int values[2]; + int ret; + + /* positive < 1 */ + values[0] = 123; + values[1] = 10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.120117187\n"); + + /* positive >= 1 */ + values[0] = 1234567; + values[1] = 10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1205.631835937\n"); + + /* negative > -1 */ + values[0] = -123; + values[1] = 10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.120117187\n"); + + /* negative <= -1 */ + values[0] = -1234567; + values[1] = 10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1205.631835937\n"); + + /* Zero */ + values[0] = 0; + values[1] = 10; + ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000000000\n"); +} + +static void iio_test_iio_format_value_multiple(struct kunit *test) +{ + char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + int values[] = {1, -2, 3, -4, 5}; + int ret; + + ret = iio_format_value(buf, IIO_VAL_INT_MULTIPLE, + ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1 -2 3 -4 5 \n"); +} + +static struct kunit_case iio_format_test_cases[] = { + KUNIT_CASE(iio_test_iio_format_value_integer), + KUNIT_CASE(iio_test_iio_format_value_fixedpoint), + KUNIT_CASE(iio_test_iio_format_value_fractional), + KUNIT_CASE(iio_test_iio_format_value_fractional_log2), + KUNIT_CASE(iio_test_iio_format_value_multiple), + {} +}; + +static struct kunit_suite iio_format_test_suite = { + .name = "iio-format", + .test_cases = iio_format_test_cases, +}; +kunit_test_suite(iio_format_test_suite); diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c index 410de837d0417c9645b7e3dca11d351838466c5c..716c795d08fb99d1fa61f2d099000167739fe258 100644 --- a/drivers/iio/trigger/iio-trig-hrtimer.c +++ b/drivers/iio/trigger/iio-trig-hrtimer.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * The industrial I/O periodic hrtimer trigger driver * * Copyright (C) Intuitive Aerial AB @@ -16,13 +16,16 @@ #include <linux/iio/trigger.h> #include <linux/iio/sw_trigger.h> +/* Defined locally, not in time64.h yet. */ +#define PSEC_PER_SEC 1000000000000LL + /* default sampling frequency - 100Hz */ #define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100 struct iio_hrtimer_info { struct iio_sw_trigger swt; struct hrtimer timer; - unsigned long sampling_frequency; + int sampling_frequency[2]; ktime_t period; }; @@ -38,7 +41,9 @@ ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev, struct iio_trigger *trig = to_iio_trigger(dev); struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); - return snprintf(buf, PAGE_SIZE, "%lu\n", info->sampling_frequency); + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, + ARRAY_SIZE(info->sampling_frequency), + info->sampling_frequency); } static @@ -48,18 +53,26 @@ ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); - unsigned long val; - int ret; + unsigned long long val; + u64 period; + int integer, fract, ret; - ret = kstrtoul(buf, 10, &val); + ret = iio_str_to_fixpoint(buf, 100, &integer, &fract); if (ret) return ret; + if (integer < 0 || fract < 0) + return -ERANGE; + + val = fract + 1000ULL * integer; /* mHz */ - if (!val || val > NSEC_PER_SEC) + if (!val || val > UINT_MAX) return -EINVAL; - info->sampling_frequency = val; - info->period = NSEC_PER_SEC / val; + info->sampling_frequency[0] = integer; /* Hz */ + info->sampling_frequency[1] = fract * 1000; /* uHz */ + period = PSEC_PER_SEC; + do_div(period, val); + info->period = period; /* nS */ return len; } @@ -122,7 +135,7 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name) if (!trig_info) return ERR_PTR(-ENOMEM); - trig_info->swt.trigger = iio_trigger_alloc("%s", name); + trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name); if (!trig_info->swt.trigger) { ret = -ENOMEM; goto err_free_trig_info; @@ -135,8 +148,8 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name) hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); trig_info->timer.function = iio_hrtimer_trig_handler; - trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY; - trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency; + trig_info->sampling_frequency[0] = HRTIMER_DEFAULT_SAMPLING_FREQUENCY; + trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency[0]; ret = iio_trigger_register(trig_info->swt.trigger); if (ret) diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 94a487caf42143c96f69d8e99f14ffd7e87b9106..f746c460bf2a59e2e7f6c40b6450f7f3e9006a6f 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -45,7 +45,7 @@ static int iio_interrupt_trigger_probe(struct platform_device *pdev) irq = irq_res->start; - trig = iio_trigger_alloc("irqtrig%d", irq); + trig = iio_trigger_alloc(NULL, "irqtrig%d", irq); if (!trig) { ret = -ENOMEM; goto error_ret; diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c index 4a00668e32583e795b0dc673d84d29a93f941bf2..96ec06bbe546ae5c49ece7684ee0428a6b029f75 100644 --- a/drivers/iio/trigger/iio-trig-loop.c +++ b/drivers/iio/trigger/iio-trig-loop.c @@ -84,7 +84,7 @@ static struct iio_sw_trigger *iio_trig_loop_probe(const char *name) if (!trig_info) return ERR_PTR(-ENOMEM); - trig_info->swt.trigger = iio_trigger_alloc("%s", name); + trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name); if (!trig_info->swt.trigger) { ret = -ENOMEM; goto err_free_trig_info; diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index 0f6b512a5c37bc059cc20a3e009a15b697d45e39..e9adfff45b39b26e7c86f4f21ec720108bd3cb1f 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -149,7 +149,7 @@ static int iio_sysfs_trigger_probe(int id) goto out1; } t->id = id; - t->trig = iio_trigger_alloc("sysfstrig%d", id); + t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id); if (!t->trig) { ret = -ENOMEM; goto free_t; @@ -157,7 +157,6 @@ static int iio_sysfs_trigger_probe(int id) t->trig->dev.groups = iio_sysfs_trigger_attr_groups; t->trig->ops = &iio_sysfs_trigger_ops; - t->trig->dev.parent = &iio_sysfs_trig_dev; iio_trigger_set_drvdata(t->trig, t); t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work); diff --git a/drivers/infiniband/hw/usnic/usnic_uiom_interval_tree.c b/drivers/infiniband/hw/usnic/usnic_uiom_interval_tree.c index d399523206c78b083c42557134ca858afba1325d..29d71267af786e32534b7209a436eea3412e0ab5 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom_interval_tree.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom_interval_tree.c @@ -83,7 +83,8 @@ usnic_uiom_interval_node_alloc(long int start, long int last, int ref_cnt, return interval; } -static int interval_cmp(void *priv, struct list_head *a, struct list_head *b) +static int interval_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct usnic_uiom_interval_node *node_a, *node_b; diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index ef6aaed217cfb5094126e06c5ea932769f878bc7..5000f5fd9ec387b96203f5b53c0df071c63fa0b7 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -160,7 +160,7 @@ static int rpi_ts_probe(struct platform_device *pdev) touchbuf = (u32)ts->fw_regs_phys; error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, &touchbuf, sizeof(touchbuf)); - + rpi_firmware_put(fw); if (error || touchbuf != 0) { dev_warn(dev, "Failed to set touchbuf, %d\n", error); return error; diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index ca52647f8955077b8670cd85959f09c63f793dfd..cdb3e11462c66b0a1b89bf0b7019ffbc469cac6f 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -74,6 +74,15 @@ config INTERCONNECT_QCOM_SC7180 This is a driver for the Qualcomm Network-on-Chip on sc7180-based platforms. +config INTERCONNECT_QCOM_SDM660 + tristate "Qualcomm SDM660 interconnect driver" + depends on INTERCONNECT_QCOM + depends on QCOM_SMD_RPM + select INTERCONNECT_QCOM_SMD_RPM + help + This is a driver for the Qualcomm Network-on-Chip on sdm660-based + platforms. + config INTERCONNECT_QCOM_SDM845 tristate "Qualcomm SDM845 interconnect driver" depends on INTERCONNECT_QCOM_RPMH_POSSIBLE @@ -110,5 +119,14 @@ config INTERCONNECT_QCOM_SM8250 This is a driver for the Qualcomm Network-on-Chip on sm8250-based platforms. +config INTERCONNECT_QCOM_SM8350 + tristate "Qualcomm SM8350 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 SM8350-based + platforms. + config INTERCONNECT_QCOM_SMD_RPM tristate diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index c6a735df067ecefd49040ba29a3101f97fe9cdfe..46fc62447156bec2900e0bc6816de4fdbd5a51bd 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -8,10 +8,12 @@ icc-osm-l3-objs := osm-l3.o qnoc-qcs404-objs := qcs404.o icc-rpmh-obj := icc-rpmh.o qnoc-sc7180-objs := sc7180.o +qnoc-sdm660-objs := sdm660.o qnoc-sdm845-objs := sdm845.o qnoc-sdx55-objs := sdx55.o qnoc-sm8150-objs := sm8150.o qnoc-sm8250-objs := sm8250.o +qnoc-sm8350-objs := sm8350.o icc-smd-rpm-objs := smd-rpm.o icc-rpm.o obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o @@ -22,8 +24,10 @@ obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o +obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o +obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c index 1cc565bce2f4da956be6a358d04a7c18657d5996..d1591a28b74388cbfb5e9df0bbaae65727425139 100644 --- a/drivers/interconnect/qcom/bcm-voter.c +++ b/drivers/interconnect/qcom/bcm-voter.c @@ -39,7 +39,7 @@ struct bcm_voter { u32 tcs_wait; }; -static int cmp_vcd(void *priv, struct list_head *a, struct list_head *b) +static int cmp_vcd(void *priv, const struct list_head *a, const struct list_head *b) { const struct qcom_icc_bcm *bcm_a = list_entry(a, struct qcom_icc_bcm, list); const struct qcom_icc_bcm *bcm_b = list_entry(b, struct qcom_icc_bcm, list); diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index cc6095492cbeacd6dac07e57efff0dc9f2905179..54de49ca7808a861ec9f4857d954776634965b50 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -59,8 +59,8 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) qn->slv_rpm_id, sum_bw); if (ret) { - pr_err("qcom_icc_rpm_smd_send slv error %d\n", - ret); + pr_err("qcom_icc_rpm_smd_send slv %d error %d\n", + qn->slv_rpm_id, ret); return ret; } } diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c new file mode 100644 index 0000000000000000000000000000000000000000..632dbdd2191500e62efc0ff500e0ac488f07d953 --- /dev/null +++ b/drivers/interconnect/qcom/sdm660.c @@ -0,0 +1,923 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm SDM630/SDM636/SDM660 Network-on-Chip (NoC) QoS driver + * Copyright (C) 2020, AngeloGioacchino Del Regno <kholk11@gmail.com> + */ + +#include <dt-bindings/interconnect/qcom,sdm660.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/interconnect-provider.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include "smd-rpm.h" + +#define RPM_BUS_MASTER_REQ 0x73616d62 +#define RPM_BUS_SLAVE_REQ 0x766c7362 + +/* BIMC QoS */ +#define M_BKE_REG_BASE(n) (0x300 + (0x4000 * n)) +#define M_BKE_EN_ADDR(n) (M_BKE_REG_BASE(n)) +#define M_BKE_HEALTH_CFG_ADDR(i, n) (M_BKE_REG_BASE(n) + 0x40 + (0x4 * i)) + +#define M_BKE_HEALTH_CFG_LIMITCMDS_MASK 0x80000000 +#define M_BKE_HEALTH_CFG_AREQPRIO_MASK 0x300 +#define M_BKE_HEALTH_CFG_PRIOLVL_MASK 0x3 +#define M_BKE_HEALTH_CFG_AREQPRIO_SHIFT 0x8 +#define M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT 0x1f + +#define M_BKE_EN_EN_BMASK 0x1 + +/* Valid for both NoC and BIMC */ +#define NOC_QOS_MODE_FIXED 0x0 +#define NOC_QOS_MODE_LIMITER 0x1 +#define NOC_QOS_MODE_BYPASS 0x2 + +/* NoC QoS */ +#define NOC_PERM_MODE_FIXED 1 +#define NOC_PERM_MODE_BYPASS (1 << NOC_QOS_MODE_BYPASS) + +#define NOC_QOS_PRIORITYn_ADDR(n) (0x8 + (n * 0x1000)) +#define NOC_QOS_PRIORITY_MASK 0xf +#define NOC_QOS_PRIORITY_P1_SHIFT 0x2 +#define NOC_QOS_PRIORITY_P0_SHIFT 0x3 + +#define NOC_QOS_MODEn_ADDR(n) (0xc + (n * 0x1000)) +#define NOC_QOS_MODEn_MASK 0x3 + +enum { + SDM660_MASTER_IPA = 1, + SDM660_MASTER_CNOC_A2NOC, + SDM660_MASTER_SDCC_1, + SDM660_MASTER_SDCC_2, + SDM660_MASTER_BLSP_1, + SDM660_MASTER_BLSP_2, + SDM660_MASTER_UFS, + SDM660_MASTER_USB_HS, + SDM660_MASTER_USB3, + SDM660_MASTER_CRYPTO_C0, + SDM660_MASTER_GNOC_BIMC, + SDM660_MASTER_OXILI, + SDM660_MASTER_MNOC_BIMC, + SDM660_MASTER_SNOC_BIMC, + SDM660_MASTER_PIMEM, + SDM660_MASTER_SNOC_CNOC, + SDM660_MASTER_QDSS_DAP, + SDM660_MASTER_APPS_PROC, + SDM660_MASTER_CNOC_MNOC_MMSS_CFG, + SDM660_MASTER_CNOC_MNOC_CFG, + SDM660_MASTER_CPP, + SDM660_MASTER_JPEG, + SDM660_MASTER_MDP_P0, + SDM660_MASTER_MDP_P1, + SDM660_MASTER_VENUS, + SDM660_MASTER_VFE, + SDM660_MASTER_QDSS_ETR, + SDM660_MASTER_QDSS_BAM, + SDM660_MASTER_SNOC_CFG, + SDM660_MASTER_BIMC_SNOC, + SDM660_MASTER_A2NOC_SNOC, + SDM660_MASTER_GNOC_SNOC, + + SDM660_SLAVE_A2NOC_SNOC, + SDM660_SLAVE_EBI, + SDM660_SLAVE_HMSS_L3, + SDM660_SLAVE_BIMC_SNOC, + SDM660_SLAVE_CNOC_A2NOC, + SDM660_SLAVE_MPM, + SDM660_SLAVE_PMIC_ARB, + SDM660_SLAVE_TLMM_NORTH, + SDM660_SLAVE_TCSR, + SDM660_SLAVE_PIMEM_CFG, + SDM660_SLAVE_IMEM_CFG, + SDM660_SLAVE_MESSAGE_RAM, + SDM660_SLAVE_GLM, + SDM660_SLAVE_BIMC_CFG, + SDM660_SLAVE_PRNG, + SDM660_SLAVE_SPDM, + SDM660_SLAVE_QDSS_CFG, + SDM660_SLAVE_CNOC_MNOC_CFG, + SDM660_SLAVE_SNOC_CFG, + SDM660_SLAVE_QM_CFG, + SDM660_SLAVE_CLK_CTL, + SDM660_SLAVE_MSS_CFG, + SDM660_SLAVE_TLMM_SOUTH, + SDM660_SLAVE_UFS_CFG, + SDM660_SLAVE_A2NOC_CFG, + SDM660_SLAVE_A2NOC_SMMU_CFG, + SDM660_SLAVE_GPUSS_CFG, + SDM660_SLAVE_AHB2PHY, + SDM660_SLAVE_BLSP_1, + SDM660_SLAVE_SDCC_1, + SDM660_SLAVE_SDCC_2, + SDM660_SLAVE_TLMM_CENTER, + SDM660_SLAVE_BLSP_2, + SDM660_SLAVE_PDM, + SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, + SDM660_SLAVE_USB_HS, + SDM660_SLAVE_USB3_0, + SDM660_SLAVE_SRVC_CNOC, + SDM660_SLAVE_GNOC_BIMC, + SDM660_SLAVE_GNOC_SNOC, + SDM660_SLAVE_CAMERA_CFG, + SDM660_SLAVE_CAMERA_THROTTLE_CFG, + SDM660_SLAVE_MISC_CFG, + SDM660_SLAVE_VENUS_THROTTLE_CFG, + SDM660_SLAVE_VENUS_CFG, + SDM660_SLAVE_MMSS_CLK_XPU_CFG, + SDM660_SLAVE_MMSS_CLK_CFG, + SDM660_SLAVE_MNOC_MPU_CFG, + SDM660_SLAVE_DISPLAY_CFG, + SDM660_SLAVE_CSI_PHY_CFG, + SDM660_SLAVE_DISPLAY_THROTTLE_CFG, + SDM660_SLAVE_SMMU_CFG, + SDM660_SLAVE_MNOC_BIMC, + SDM660_SLAVE_SRVC_MNOC, + SDM660_SLAVE_HMSS, + SDM660_SLAVE_LPASS, + SDM660_SLAVE_WLAN, + SDM660_SLAVE_CDSP, + SDM660_SLAVE_IPA, + SDM660_SLAVE_SNOC_BIMC, + SDM660_SLAVE_SNOC_CNOC, + SDM660_SLAVE_IMEM, + SDM660_SLAVE_PIMEM, + SDM660_SLAVE_QDSS_STM, + SDM660_SLAVE_SRVC_SNOC, + + SDM660_A2NOC, + SDM660_BIMC, + SDM660_CNOC, + SDM660_GNOC, + SDM660_MNOC, + SDM660_SNOC, +}; + +#define to_qcom_provider(_provider) \ + container_of(_provider, struct qcom_icc_provider, provider) + +static const struct clk_bulk_data bus_clocks[] = { + { .id = "bus" }, + { .id = "bus_a" }, +}; + +static const struct clk_bulk_data bus_mm_clocks[] = { + { .id = "bus" }, + { .id = "bus_a" }, + { .id = "iface" }, +}; + +/** + * struct qcom_icc_provider - Qualcomm specific interconnect provider + * @provider: generic interconnect provider + * @bus_clks: the clk_bulk_data table of bus clocks + * @num_clks: the total number of clk_bulk_data entries + * @is_bimc_node: indicates whether to use bimc specific setting + * @regmap: regmap for QoS registers read/write access + * @mmio: NoC base iospace + */ +struct qcom_icc_provider { + struct icc_provider provider; + struct clk_bulk_data *bus_clks; + int num_clks; + bool is_bimc_node; + struct regmap *regmap; + void __iomem *mmio; +}; + +#define SDM660_MAX_LINKS 34 + +/** + * struct qcom_icc_qos - Qualcomm specific interconnect QoS parameters + * @areq_prio: node requests priority + * @prio_level: priority level for bus communication + * @limit_commands: activate/deactivate limiter mode during runtime + * @ap_owned: indicates if the node is owned by the AP or by the RPM + * @qos_mode: default qos mode for this node + * @qos_port: qos port number for finding qos registers of this node + */ +struct qcom_icc_qos { + u32 areq_prio; + u32 prio_level; + bool limit_commands; + bool ap_owned; + int qos_mode; + int qos_port; +}; + +/** + * struct qcom_icc_node - Qualcomm specific interconnect nodes + * @name: the node name used in debugfs + * @id: a unique node identifier + * @links: an array of nodes where we can go next while traversing + * @num_links: the total number of @links + * @buswidth: width of the interconnect between a node and the bus (bytes) + * @mas_rpm_id: RPM id for devices that are bus masters + * @slv_rpm_id: RPM id for devices that are bus slaves + * @qos: NoC QoS setting parameters + * @rate: current bus clock rate in Hz + */ +struct qcom_icc_node { + unsigned char *name; + u16 id; + u16 links[SDM660_MAX_LINKS]; + u16 num_links; + u16 buswidth; + int mas_rpm_id; + int slv_rpm_id; + struct qcom_icc_qos qos; + u64 rate; +}; + +struct qcom_icc_desc { + struct qcom_icc_node **nodes; + size_t num_nodes; + const struct regmap_config *regmap_cfg; +}; + +#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \ + _ap_owned, _qos_mode, _qos_prio, _qos_port, ...) \ + static struct qcom_icc_node _name = { \ + .name = #_name, \ + .id = _id, \ + .buswidth = _buswidth, \ + .mas_rpm_id = _mas_rpm_id, \ + .slv_rpm_id = _slv_rpm_id, \ + .qos.ap_owned = _ap_owned, \ + .qos.qos_mode = _qos_mode, \ + .qos.areq_prio = _qos_prio, \ + .qos.prio_level = _qos_prio, \ + .qos.qos_port = _qos_port, \ + .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ + .links = { __VA_ARGS__ }, \ + } + +DEFINE_QNODE(mas_ipa, SDM660_MASTER_IPA, 8, 59, -1, true, NOC_QOS_MODE_FIXED, 1, 3, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_cnoc_a2noc, SDM660_MASTER_CNOC_A2NOC, 8, 146, -1, true, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_sdcc_1, SDM660_MASTER_SDCC_1, 8, 33, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_sdcc_2, SDM660_MASTER_SDCC_2, 8, 35, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_blsp_1, SDM660_MASTER_BLSP_1, 4, 41, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_blsp_2, SDM660_MASTER_BLSP_2, 4, 39, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_ufs, SDM660_MASTER_UFS, 8, 68, -1, true, NOC_QOS_MODE_FIXED, 1, 4, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_usb_hs, SDM660_MASTER_USB_HS, 8, 42, -1, true, NOC_QOS_MODE_FIXED, 1, 1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_usb3, SDM660_MASTER_USB3, 8, 32, -1, true, NOC_QOS_MODE_FIXED, 1, 2, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_crypto, SDM660_MASTER_CRYPTO_C0, 8, 23, -1, true, NOC_QOS_MODE_FIXED, 1, 11, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_gnoc_bimc, SDM660_MASTER_GNOC_BIMC, 4, 144, -1, true, NOC_QOS_MODE_FIXED, 0, 0, SDM660_SLAVE_EBI); +DEFINE_QNODE(mas_oxili, SDM660_MASTER_OXILI, 4, 6, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI, SDM660_SLAVE_BIMC_SNOC); +DEFINE_QNODE(mas_mnoc_bimc, SDM660_MASTER_MNOC_BIMC, 4, 2, -1, true, NOC_QOS_MODE_BYPASS, 0, 2, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI, SDM660_SLAVE_BIMC_SNOC); +DEFINE_QNODE(mas_snoc_bimc, SDM660_MASTER_SNOC_BIMC, 4, 3, -1, false, -1, 0, -1, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI); +DEFINE_QNODE(mas_pimem, SDM660_MASTER_PIMEM, 4, 113, -1, true, NOC_QOS_MODE_FIXED, 1, 4, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI); +DEFINE_QNODE(mas_snoc_cnoc, SDM660_MASTER_SNOC_CNOC, 8, 52, -1, true, -1, 0, -1, SDM660_SLAVE_CLK_CTL, SDM660_SLAVE_QDSS_CFG, SDM660_SLAVE_QM_CFG, SDM660_SLAVE_SRVC_CNOC, SDM660_SLAVE_UFS_CFG, SDM660_SLAVE_TCSR, SDM660_SLAVE_A2NOC_SMMU_CFG, SDM660_SLAVE_SNOC_CFG, SDM660_SLAVE_TLMM_SOUTH, SDM660_SLAVE_MPM, SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, SDM660_SLAVE_SDCC_2, SDM660_SLAVE_SDCC_1, SDM660_SLAVE_SPDM, SDM660_SLAVE_PMIC_ARB, SDM660_SLAVE_PRNG, SDM660_SLAVE_MSS_CFG, SDM660_SLAVE_GPUSS_CFG, SDM660_SLAVE_IMEM_CFG, SDM660_SLAVE_USB3_0, SDM660_SLAVE_A2NOC_CFG, SDM660_SLAVE_TLMM_NORTH, SDM660_SLAVE_USB_HS, SDM660_SLAVE_PDM, SDM660_SLAVE_TLMM_CENTER, SDM660_SLAVE_AHB2PHY, SDM660_SLAVE_BLSP_2, SDM660_SLAVE_BLSP_1, SDM660_SLAVE_PIMEM_CFG, SDM660_SLAVE_GLM, SDM660_SLAVE_MESSAGE_RAM, SDM660_SLAVE_BIMC_CFG, SDM660_SLAVE_CNOC_MNOC_CFG); +DEFINE_QNODE(mas_qdss_dap, SDM660_MASTER_QDSS_DAP, 8, 49, -1, true, -1, 0, -1, SDM660_SLAVE_CLK_CTL, SDM660_SLAVE_QDSS_CFG, SDM660_SLAVE_QM_CFG, SDM660_SLAVE_SRVC_CNOC, SDM660_SLAVE_UFS_CFG, SDM660_SLAVE_TCSR, SDM660_SLAVE_A2NOC_SMMU_CFG, SDM660_SLAVE_SNOC_CFG, SDM660_SLAVE_TLMM_SOUTH, SDM660_SLAVE_MPM, SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, SDM660_SLAVE_SDCC_2, SDM660_SLAVE_SDCC_1, SDM660_SLAVE_SPDM, SDM660_SLAVE_PMIC_ARB, SDM660_SLAVE_PRNG, SDM660_SLAVE_MSS_CFG, SDM660_SLAVE_GPUSS_CFG, SDM660_SLAVE_IMEM_CFG, SDM660_SLAVE_USB3_0, SDM660_SLAVE_A2NOC_CFG, SDM660_SLAVE_TLMM_NORTH, SDM660_SLAVE_USB_HS, SDM660_SLAVE_PDM, SDM660_SLAVE_TLMM_CENTER, SDM660_SLAVE_AHB2PHY, SDM660_SLAVE_BLSP_2, SDM660_SLAVE_BLSP_1, SDM660_SLAVE_PIMEM_CFG, SDM660_SLAVE_GLM, SDM660_SLAVE_MESSAGE_RAM, SDM660_SLAVE_CNOC_A2NOC, SDM660_SLAVE_BIMC_CFG, SDM660_SLAVE_CNOC_MNOC_CFG); +DEFINE_QNODE(mas_apss_proc, SDM660_MASTER_APPS_PROC, 16, 0, -1, true, -1, 0, -1, SDM660_SLAVE_GNOC_SNOC, SDM660_SLAVE_GNOC_BIMC); +DEFINE_QNODE(mas_cnoc_mnoc_mmss_cfg, SDM660_MASTER_CNOC_MNOC_MMSS_CFG, 8, 4, -1, true, -1, 0, -1, SDM660_SLAVE_VENUS_THROTTLE_CFG, SDM660_SLAVE_VENUS_CFG, SDM660_SLAVE_CAMERA_THROTTLE_CFG, SDM660_SLAVE_SMMU_CFG, SDM660_SLAVE_CAMERA_CFG, SDM660_SLAVE_CSI_PHY_CFG, SDM660_SLAVE_DISPLAY_THROTTLE_CFG, SDM660_SLAVE_DISPLAY_CFG, SDM660_SLAVE_MMSS_CLK_CFG, SDM660_SLAVE_MNOC_MPU_CFG, SDM660_SLAVE_MISC_CFG, SDM660_SLAVE_MMSS_CLK_XPU_CFG); +DEFINE_QNODE(mas_cnoc_mnoc_cfg, SDM660_MASTER_CNOC_MNOC_CFG, 4, 5, -1, true, -1, 0, -1, SDM660_SLAVE_SRVC_MNOC); +DEFINE_QNODE(mas_cpp, SDM660_MASTER_CPP, 16, 115, -1, true, NOC_QOS_MODE_BYPASS, 0, 4, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_jpeg, SDM660_MASTER_JPEG, 16, 7, -1, true, NOC_QOS_MODE_BYPASS, 0, 6, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_mdp_p0, SDM660_MASTER_MDP_P0, 16, 8, -1, true, NOC_QOS_MODE_BYPASS, 0, 0, SDM660_SLAVE_MNOC_BIMC); /* vrail-comp???? */ +DEFINE_QNODE(mas_mdp_p1, SDM660_MASTER_MDP_P1, 16, 61, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, SDM660_SLAVE_MNOC_BIMC); /* vrail-comp??? */ +DEFINE_QNODE(mas_venus, SDM660_MASTER_VENUS, 16, 9, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_vfe, SDM660_MASTER_VFE, 16, 11, -1, true, NOC_QOS_MODE_BYPASS, 0, 5, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_qdss_etr, SDM660_MASTER_QDSS_ETR, 8, 31, -1, true, NOC_QOS_MODE_FIXED, 1, 1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IMEM, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_SNOC_BIMC); +DEFINE_QNODE(mas_qdss_bam, SDM660_MASTER_QDSS_BAM, 4, 19, -1, true, NOC_QOS_MODE_FIXED, 1, 0, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IMEM, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_SNOC_BIMC); +DEFINE_QNODE(mas_snoc_cfg, SDM660_MASTER_SNOC_CFG, 4, 20, -1, false, -1, 0, -1, SDM660_SLAVE_SRVC_SNOC); +DEFINE_QNODE(mas_bimc_snoc, SDM660_MASTER_BIMC_SNOC, 8, 21, -1, false, -1, 0, -1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IPA, SDM660_SLAVE_QDSS_STM, SDM660_SLAVE_LPASS, SDM660_SLAVE_HMSS, SDM660_SLAVE_CDSP, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_WLAN, SDM660_SLAVE_IMEM); +DEFINE_QNODE(mas_gnoc_snoc, SDM660_MASTER_GNOC_SNOC, 8, 150, -1, false, -1, 0, -1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IPA, SDM660_SLAVE_QDSS_STM, SDM660_SLAVE_LPASS, SDM660_SLAVE_HMSS, SDM660_SLAVE_CDSP, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_WLAN, SDM660_SLAVE_IMEM); +DEFINE_QNODE(mas_a2noc_snoc, SDM660_MASTER_A2NOC_SNOC, 16, 112, -1, false, -1, 0, -1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IPA, SDM660_SLAVE_QDSS_STM, SDM660_SLAVE_LPASS, SDM660_SLAVE_HMSS, SDM660_SLAVE_SNOC_BIMC, SDM660_SLAVE_CDSP, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_WLAN, SDM660_SLAVE_IMEM); +DEFINE_QNODE(slv_a2noc_snoc, SDM660_SLAVE_A2NOC_SNOC, 16, -1, 143, false, -1, 0, -1, SDM660_MASTER_A2NOC_SNOC); +DEFINE_QNODE(slv_ebi, SDM660_SLAVE_EBI, 4, -1, 0, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_hmss_l3, SDM660_SLAVE_HMSS_L3, 4, -1, 160, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_bimc_snoc, SDM660_SLAVE_BIMC_SNOC, 4, -1, 2, false, -1, 0, -1, SDM660_MASTER_BIMC_SNOC); +DEFINE_QNODE(slv_cnoc_a2noc, SDM660_SLAVE_CNOC_A2NOC, 8, -1, 208, true, -1, 0, -1, SDM660_MASTER_CNOC_A2NOC); +DEFINE_QNODE(slv_mpm, SDM660_SLAVE_MPM, 4, -1, 62, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_pmic_arb, SDM660_SLAVE_PMIC_ARB, 4, -1, 59, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tlmm_north, SDM660_SLAVE_TLMM_NORTH, 8, -1, 214, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tcsr, SDM660_SLAVE_TCSR, 4, -1, 50, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_pimem_cfg, SDM660_SLAVE_PIMEM_CFG, 4, -1, 167, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_imem_cfg, SDM660_SLAVE_IMEM_CFG, 4, -1, 54, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_message_ram, SDM660_SLAVE_MESSAGE_RAM, 4, -1, 55, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_glm, SDM660_SLAVE_GLM, 4, -1, 209, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_bimc_cfg, SDM660_SLAVE_BIMC_CFG, 4, -1, 56, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_prng, SDM660_SLAVE_PRNG, 4, -1, 44, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_spdm, SDM660_SLAVE_SPDM, 4, -1, 60, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_qdss_cfg, SDM660_SLAVE_QDSS_CFG, 4, -1, 63, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_cnoc_mnoc_cfg, SDM660_SLAVE_BLSP_1, 4, -1, 66, true, -1, 0, -1, SDM660_MASTER_CNOC_MNOC_CFG); +DEFINE_QNODE(slv_snoc_cfg, SDM660_SLAVE_SNOC_CFG, 4, -1, 70, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_qm_cfg, SDM660_SLAVE_QM_CFG, 4, -1, 212, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_clk_ctl, SDM660_SLAVE_CLK_CTL, 4, -1, 47, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mss_cfg, SDM660_SLAVE_MSS_CFG, 4, -1, 48, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tlmm_south, SDM660_SLAVE_TLMM_SOUTH, 4, -1, 217, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_ufs_cfg, SDM660_SLAVE_UFS_CFG, 4, -1, 92, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_a2noc_cfg, SDM660_SLAVE_A2NOC_CFG, 4, -1, 150, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_a2noc_smmu_cfg, SDM660_SLAVE_A2NOC_SMMU_CFG, 8, -1, 152, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_gpuss_cfg, SDM660_SLAVE_GPUSS_CFG, 8, -1, 11, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_ahb2phy, SDM660_SLAVE_AHB2PHY, 4, -1, 163, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_blsp_1, SDM660_SLAVE_BLSP_1, 4, -1, 39, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_sdcc_1, SDM660_SLAVE_SDCC_1, 4, -1, 31, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_sdcc_2, SDM660_SLAVE_SDCC_2, 4, -1, 33, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tlmm_center, SDM660_SLAVE_TLMM_CENTER, 4, -1, 218, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_blsp_2, SDM660_SLAVE_BLSP_2, 4, -1, 37, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_pdm, SDM660_SLAVE_PDM, 4, -1, 41, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_cnoc_mnoc_mmss_cfg, SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, 8, -1, 58, true, -1, 0, -1, SDM660_MASTER_CNOC_MNOC_MMSS_CFG); +DEFINE_QNODE(slv_usb_hs, SDM660_SLAVE_USB_HS, 4, -1, 40, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_usb3_0, SDM660_SLAVE_USB3_0, 4, -1, 22, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_srvc_cnoc, SDM660_SLAVE_SRVC_CNOC, 4, -1, 76, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_gnoc_bimc, SDM660_SLAVE_GNOC_BIMC, 16, -1, 210, true, -1, 0, -1, SDM660_MASTER_GNOC_BIMC); +DEFINE_QNODE(slv_gnoc_snoc, SDM660_SLAVE_GNOC_SNOC, 8, -1, 211, true, -1, 0, -1, SDM660_MASTER_GNOC_SNOC); +DEFINE_QNODE(slv_camera_cfg, SDM660_SLAVE_CAMERA_CFG, 4, -1, 3, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_camera_throttle_cfg, SDM660_SLAVE_CAMERA_THROTTLE_CFG, 4, -1, 154, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_misc_cfg, SDM660_SLAVE_MISC_CFG, 4, -1, 8, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_venus_throttle_cfg, SDM660_SLAVE_VENUS_THROTTLE_CFG, 4, -1, 178, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_venus_cfg, SDM660_SLAVE_VENUS_CFG, 4, -1, 10, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mmss_clk_xpu_cfg, SDM660_SLAVE_MMSS_CLK_XPU_CFG, 4, -1, 13, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mmss_clk_cfg, SDM660_SLAVE_MMSS_CLK_CFG, 4, -1, 12, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mnoc_mpu_cfg, SDM660_SLAVE_MNOC_MPU_CFG, 4, -1, 14, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_display_cfg, SDM660_SLAVE_DISPLAY_CFG, 4, -1, 4, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_csi_phy_cfg, SDM660_SLAVE_CSI_PHY_CFG, 4, -1, 224, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_display_throttle_cfg, SDM660_SLAVE_DISPLAY_THROTTLE_CFG, 4, -1, 156, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_smmu_cfg, SDM660_SLAVE_SMMU_CFG, 8, -1, 205, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mnoc_bimc, SDM660_SLAVE_MNOC_BIMC, 16, -1, 16, true, -1, 0, -1, SDM660_MASTER_MNOC_BIMC); +DEFINE_QNODE(slv_srvc_mnoc, SDM660_SLAVE_SRVC_MNOC, 8, -1, 17, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_hmss, SDM660_SLAVE_HMSS, 8, -1, 20, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_lpass, SDM660_SLAVE_LPASS, 4, -1, 21, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_wlan, SDM660_SLAVE_WLAN, 4, -1, 206, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_cdsp, SDM660_SLAVE_CDSP, 4, -1, 221, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_ipa, SDM660_SLAVE_IPA, 4, -1, 183, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_snoc_bimc, SDM660_SLAVE_SNOC_BIMC, 16, -1, 24, false, -1, 0, -1, SDM660_MASTER_SNOC_BIMC); +DEFINE_QNODE(slv_snoc_cnoc, SDM660_SLAVE_SNOC_CNOC, 8, -1, 25, false, -1, 0, -1, SDM660_MASTER_SNOC_CNOC); +DEFINE_QNODE(slv_imem, SDM660_SLAVE_IMEM, 8, -1, 26, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_pimem, SDM660_SLAVE_PIMEM, 8, -1, 166, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_qdss_stm, SDM660_SLAVE_QDSS_STM, 4, -1, 30, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_srvc_snoc, SDM660_SLAVE_SRVC_SNOC, 16, -1, 29, false, -1, 0, -1, 0); + +static struct qcom_icc_node *sdm660_a2noc_nodes[] = { + [MASTER_IPA] = &mas_ipa, + [MASTER_CNOC_A2NOC] = &mas_cnoc_a2noc, + [MASTER_SDCC_1] = &mas_sdcc_1, + [MASTER_SDCC_2] = &mas_sdcc_2, + [MASTER_BLSP_1] = &mas_blsp_1, + [MASTER_BLSP_2] = &mas_blsp_2, + [MASTER_UFS] = &mas_ufs, + [MASTER_USB_HS] = &mas_usb_hs, + [MASTER_USB3] = &mas_usb3, + [MASTER_CRYPTO_C0] = &mas_crypto, + [SLAVE_A2NOC_SNOC] = &slv_a2noc_snoc, +}; + +static const struct regmap_config sdm660_a2noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x20000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_a2noc = { + .nodes = sdm660_a2noc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_a2noc_nodes), + .regmap_cfg = &sdm660_a2noc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_bimc_nodes[] = { + [MASTER_GNOC_BIMC] = &mas_gnoc_bimc, + [MASTER_OXILI] = &mas_oxili, + [MASTER_MNOC_BIMC] = &mas_mnoc_bimc, + [MASTER_SNOC_BIMC] = &mas_snoc_bimc, + [MASTER_PIMEM] = &mas_pimem, + [SLAVE_EBI] = &slv_ebi, + [SLAVE_HMSS_L3] = &slv_hmss_l3, + [SLAVE_BIMC_SNOC] = &slv_bimc_snoc, +}; + +static const struct regmap_config sdm660_bimc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x80000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_bimc = { + .nodes = sdm660_bimc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_bimc_nodes), + .regmap_cfg = &sdm660_bimc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_cnoc_nodes[] = { + [MASTER_SNOC_CNOC] = &mas_snoc_cnoc, + [MASTER_QDSS_DAP] = &mas_qdss_dap, + [SLAVE_CNOC_A2NOC] = &slv_cnoc_a2noc, + [SLAVE_MPM] = &slv_mpm, + [SLAVE_PMIC_ARB] = &slv_pmic_arb, + [SLAVE_TLMM_NORTH] = &slv_tlmm_north, + [SLAVE_TCSR] = &slv_tcsr, + [SLAVE_PIMEM_CFG] = &slv_pimem_cfg, + [SLAVE_IMEM_CFG] = &slv_imem_cfg, + [SLAVE_MESSAGE_RAM] = &slv_message_ram, + [SLAVE_GLM] = &slv_glm, + [SLAVE_BIMC_CFG] = &slv_bimc_cfg, + [SLAVE_PRNG] = &slv_prng, + [SLAVE_SPDM] = &slv_spdm, + [SLAVE_QDSS_CFG] = &slv_qdss_cfg, + [SLAVE_CNOC_MNOC_CFG] = &slv_cnoc_mnoc_cfg, + [SLAVE_SNOC_CFG] = &slv_snoc_cfg, + [SLAVE_QM_CFG] = &slv_qm_cfg, + [SLAVE_CLK_CTL] = &slv_clk_ctl, + [SLAVE_MSS_CFG] = &slv_mss_cfg, + [SLAVE_TLMM_SOUTH] = &slv_tlmm_south, + [SLAVE_UFS_CFG] = &slv_ufs_cfg, + [SLAVE_A2NOC_CFG] = &slv_a2noc_cfg, + [SLAVE_A2NOC_SMMU_CFG] = &slv_a2noc_smmu_cfg, + [SLAVE_GPUSS_CFG] = &slv_gpuss_cfg, + [SLAVE_AHB2PHY] = &slv_ahb2phy, + [SLAVE_BLSP_1] = &slv_blsp_1, + [SLAVE_SDCC_1] = &slv_sdcc_1, + [SLAVE_SDCC_2] = &slv_sdcc_2, + [SLAVE_TLMM_CENTER] = &slv_tlmm_center, + [SLAVE_BLSP_2] = &slv_blsp_2, + [SLAVE_PDM] = &slv_pdm, + [SLAVE_CNOC_MNOC_MMSS_CFG] = &slv_cnoc_mnoc_mmss_cfg, + [SLAVE_USB_HS] = &slv_usb_hs, + [SLAVE_USB3_0] = &slv_usb3_0, + [SLAVE_SRVC_CNOC] = &slv_srvc_cnoc, +}; + +static const struct regmap_config sdm660_cnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_cnoc = { + .nodes = sdm660_cnoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_cnoc_nodes), + .regmap_cfg = &sdm660_cnoc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_gnoc_nodes[] = { + [MASTER_APSS_PROC] = &mas_apss_proc, + [SLAVE_GNOC_BIMC] = &slv_gnoc_bimc, + [SLAVE_GNOC_SNOC] = &slv_gnoc_snoc, +}; + +static const struct regmap_config sdm660_gnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xe000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_gnoc = { + .nodes = sdm660_gnoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_gnoc_nodes), + .regmap_cfg = &sdm660_gnoc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_mnoc_nodes[] = { + [MASTER_CPP] = &mas_cpp, + [MASTER_JPEG] = &mas_jpeg, + [MASTER_MDP_P0] = &mas_mdp_p0, + [MASTER_MDP_P1] = &mas_mdp_p1, + [MASTER_VENUS] = &mas_venus, + [MASTER_VFE] = &mas_vfe, + [MASTER_CNOC_MNOC_MMSS_CFG] = &mas_cnoc_mnoc_mmss_cfg, + [MASTER_CNOC_MNOC_CFG] = &mas_cnoc_mnoc_cfg, + [SLAVE_CAMERA_CFG] = &slv_camera_cfg, + [SLAVE_CAMERA_THROTTLE_CFG] = &slv_camera_throttle_cfg, + [SLAVE_MISC_CFG] = &slv_misc_cfg, + [SLAVE_VENUS_THROTTLE_CFG] = &slv_venus_throttle_cfg, + [SLAVE_VENUS_CFG] = &slv_venus_cfg, + [SLAVE_MMSS_CLK_XPU_CFG] = &slv_mmss_clk_xpu_cfg, + [SLAVE_MMSS_CLK_CFG] = &slv_mmss_clk_cfg, + [SLAVE_MNOC_MPU_CFG] = &slv_mnoc_mpu_cfg, + [SLAVE_DISPLAY_CFG] = &slv_display_cfg, + [SLAVE_CSI_PHY_CFG] = &slv_csi_phy_cfg, + [SLAVE_DISPLAY_THROTTLE_CFG] = &slv_display_throttle_cfg, + [SLAVE_SMMU_CFG] = &slv_smmu_cfg, + [SLAVE_SRVC_MNOC] = &slv_srvc_mnoc, + [SLAVE_MNOC_BIMC] = &slv_mnoc_bimc, +}; + +static const struct regmap_config sdm660_mnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_mnoc = { + .nodes = sdm660_mnoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_mnoc_nodes), + .regmap_cfg = &sdm660_mnoc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_snoc_nodes[] = { + [MASTER_QDSS_ETR] = &mas_qdss_etr, + [MASTER_QDSS_BAM] = &mas_qdss_bam, + [MASTER_SNOC_CFG] = &mas_snoc_cfg, + [MASTER_BIMC_SNOC] = &mas_bimc_snoc, + [MASTER_A2NOC_SNOC] = &mas_a2noc_snoc, + [MASTER_GNOC_SNOC] = &mas_gnoc_snoc, + [SLAVE_HMSS] = &slv_hmss, + [SLAVE_LPASS] = &slv_lpass, + [SLAVE_WLAN] = &slv_wlan, + [SLAVE_CDSP] = &slv_cdsp, + [SLAVE_IPA] = &slv_ipa, + [SLAVE_SNOC_BIMC] = &slv_snoc_bimc, + [SLAVE_SNOC_CNOC] = &slv_snoc_cnoc, + [SLAVE_IMEM] = &slv_imem, + [SLAVE_PIMEM] = &slv_pimem, + [SLAVE_QDSS_STM] = &slv_qdss_stm, + [SLAVE_SRVC_SNOC] = &slv_srvc_snoc, +}; + +static const struct regmap_config sdm660_snoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x20000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_snoc = { + .nodes = sdm660_snoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_snoc_nodes), + .regmap_cfg = &sdm660_snoc_regmap_config, +}; + +static int qcom_icc_bimc_set_qos_health(struct regmap *rmap, + struct qcom_icc_qos *qos, + int regnum) +{ + u32 val; + u32 mask; + + val = qos->prio_level; + mask = M_BKE_HEALTH_CFG_PRIOLVL_MASK; + + val |= qos->areq_prio << M_BKE_HEALTH_CFG_AREQPRIO_SHIFT; + mask |= M_BKE_HEALTH_CFG_AREQPRIO_MASK; + + /* LIMITCMDS is not present on M_BKE_HEALTH_3 */ + if (regnum != 3) { + val |= qos->limit_commands << M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT; + mask |= M_BKE_HEALTH_CFG_LIMITCMDS_MASK; + } + + return regmap_update_bits(rmap, + M_BKE_HEALTH_CFG_ADDR(regnum, qos->qos_port), + mask, val); +} + +static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw, + bool bypass_mode) +{ + struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; + struct icc_provider *provider; + u32 mode = NOC_QOS_MODE_BYPASS; + u32 val = 0; + int i, rc = 0; + + qn = src->data; + provider = src->provider; + qp = to_qcom_provider(provider); + + if (qn->qos.qos_mode != -1) + mode = qn->qos.qos_mode; + + /* QoS Priority: The QoS Health parameters are getting considered + * only if we are NOT in Bypass Mode. + */ + if (mode != NOC_QOS_MODE_BYPASS) { + for (i = 3; i >= 0; i--) { + rc = qcom_icc_bimc_set_qos_health(qp->regmap, + &qn->qos, i); + if (rc) + return rc; + } + + /* Set BKE_EN to 1 when Fixed, Regulator or Limiter Mode */ + val = 1; + } + + return regmap_update_bits(qp->regmap, M_BKE_EN_ADDR(qn->qos.qos_port), + M_BKE_EN_EN_BMASK, val); +} + +static int qcom_icc_noc_set_qos_priority(struct regmap *rmap, + struct qcom_icc_qos *qos) +{ + u32 val; + int rc; + + /* Must be updated one at a time, P1 first, P0 last */ + val = qos->areq_prio << NOC_QOS_PRIORITY_P1_SHIFT; + rc = regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port), + NOC_QOS_PRIORITY_MASK, val); + if (rc) + return rc; + + val = qos->prio_level << NOC_QOS_PRIORITY_P0_SHIFT; + return regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port), + NOC_QOS_PRIORITY_MASK, val); +} + +static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw) +{ + struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; + struct icc_provider *provider; + u32 mode = NOC_QOS_MODE_BYPASS; + int rc = 0; + + qn = src->data; + provider = src->provider; + qp = to_qcom_provider(provider); + + if (qn->qos.qos_port < 0) { + dev_dbg(src->provider->dev, + "NoC QoS: Skipping %s: vote aggregated on parent.\n", + qn->name); + return 0; + } + + if (qn->qos.qos_mode != -1) + mode = qn->qos.qos_mode; + + if (mode == NOC_QOS_MODE_FIXED) { + dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n", + qn->name); + rc = qcom_icc_noc_set_qos_priority(qp->regmap, &qn->qos); + if (rc) + return rc; + } else if (mode == NOC_QOS_MODE_BYPASS) { + dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n", + qn->name); + } + + return regmap_update_bits(qp->regmap, + NOC_QOS_MODEn_ADDR(qn->qos.qos_port), + NOC_QOS_MODEn_MASK, mode); +} + +static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw) +{ + struct qcom_icc_provider *qp = to_qcom_provider(node->provider); + struct qcom_icc_node *qn = node->data; + + dev_dbg(node->provider->dev, "Setting QoS for %s\n", qn->name); + + if (qp->is_bimc_node) + return qcom_icc_set_bimc_qos(node, sum_bw, + (qn->qos.qos_mode == NOC_QOS_MODE_BYPASS)); + + return qcom_icc_set_noc_qos(node, sum_bw); +} + +static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw) +{ + int ret = 0; + + if (mas_rpm_id != -1) { + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, + RPM_BUS_MASTER_REQ, + mas_rpm_id, + sum_bw); + if (ret) { + pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", + mas_rpm_id, ret); + return ret; + } + } + + if (slv_rpm_id != -1) { + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, + RPM_BUS_SLAVE_REQ, + slv_rpm_id, + sum_bw); + if (ret) { + pr_err("qcom_icc_rpm_smd_send slv %d error %d\n", + slv_rpm_id, ret); + return ret; + } + } + + return ret; +} + +static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) +{ + struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; + struct icc_provider *provider; + struct icc_node *n; + u64 sum_bw; + u64 max_peak_bw; + u64 rate; + u32 agg_avg = 0; + u32 agg_peak = 0; + int ret, i; + + qn = src->data; + provider = src->provider; + qp = to_qcom_provider(provider); + + list_for_each_entry(n, &provider->nodes, node_list) + provider->aggregate(n, 0, n->avg_bw, n->peak_bw, + &agg_avg, &agg_peak); + + sum_bw = icc_units_to_bps(agg_avg); + max_peak_bw = icc_units_to_bps(agg_peak); + + if (!qn->qos.ap_owned) { + /* send bandwidth request message to the RPM processor */ + ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw); + if (ret) + return ret; + } else if (qn->qos.qos_mode != -1) { + /* set bandwidth directly from the AP */ + ret = qcom_icc_qos_set(src, sum_bw); + if (ret) + return ret; + } + + rate = max(sum_bw, max_peak_bw); + + do_div(rate, qn->buswidth); + + if (qn->rate == rate) + return 0; + + for (i = 0; i < qp->num_clks; i++) { + ret = clk_set_rate(qp->bus_clks[i].clk, rate); + if (ret) { + pr_err("%s clk_set_rate error: %d\n", + qp->bus_clks[i].id, ret); + return ret; + } + } + + qn->rate = rate; + + return 0; +} + +static int qnoc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct qcom_icc_desc *desc; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node **qnodes; + struct qcom_icc_provider *qp; + struct icc_node *node; + struct resource *res; + size_t num_nodes, i; + int ret; + + /* wait for the RPM proxy */ + if (!qcom_icc_rpm_smd_available()) + return -EPROBE_DEFER; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (of_device_is_compatible(dev->of_node, "qcom,sdm660-mnoc")) { + qp->bus_clks = devm_kmemdup(dev, bus_mm_clocks, + sizeof(bus_mm_clocks), GFP_KERNEL); + qp->num_clks = ARRAY_SIZE(bus_mm_clocks); + } else { + if (of_device_is_compatible(dev->of_node, "qcom,sdm660-bimc")) + qp->is_bimc_node = true; + + qp->bus_clks = devm_kmemdup(dev, bus_clocks, sizeof(bus_clocks), + GFP_KERNEL); + qp->num_clks = ARRAY_SIZE(bus_clocks); + } + if (!qp->bus_clks) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + qp->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(qp->mmio)) { + dev_err(dev, "Cannot ioremap interconnect bus resource\n"); + return PTR_ERR(qp->mmio); + } + + qp->regmap = devm_regmap_init_mmio(dev, qp->mmio, desc->regmap_cfg); + if (IS_ERR(qp->regmap)) { + dev_err(dev, "Cannot regmap interconnect bus resource\n"); + return PTR_ERR(qp->regmap); + } + + ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks); + if (ret) + return ret; + + ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks); + if (ret) + return ret; + + provider = &qp->provider; + INIT_LIST_HEAD(&provider->nodes); + provider->dev = dev; + provider->set = qcom_icc_set; + provider->aggregate = icc_std_aggregate; + provider->xlate = of_icc_xlate_onecell; + provider->data = data; + + ret = icc_provider_add(provider); + if (ret) { + dev_err(dev, "error adding interconnect provider: %d\n", ret); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + return ret; + } + + for (i = 0; i < num_nodes; i++) { + size_t j; + + node = icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qnodes[i]->name; + node->data = qnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = num_nodes; + platform_set_drvdata(pdev, qp); + + return 0; +err: + icc_nodes_remove(provider); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + icc_provider_del(provider); + + return ret; +} + +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + return icc_provider_del(&qp->provider); +} + +static const struct of_device_id sdm660_noc_of_match[] = { + { .compatible = "qcom,sdm660-a2noc", .data = &sdm660_a2noc }, + { .compatible = "qcom,sdm660-bimc", .data = &sdm660_bimc }, + { .compatible = "qcom,sdm660-cnoc", .data = &sdm660_cnoc }, + { .compatible = "qcom,sdm660-gnoc", .data = &sdm660_gnoc }, + { .compatible = "qcom,sdm660-mnoc", .data = &sdm660_mnoc }, + { .compatible = "qcom,sdm660-snoc", .data = &sdm660_snoc }, + { }, +}; +MODULE_DEVICE_TABLE(of, sdm660_noc_of_match); + +static struct platform_driver sdm660_noc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-sdm660", + .of_match_table = sdm660_noc_of_match, + }, +}; +module_platform_driver(sdm660_noc_driver); +MODULE_DESCRIPTION("Qualcomm sdm660 NoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c new file mode 100644 index 0000000000000000000000000000000000000000..579b6ce8e046bd39e3b5db98c759a308b65bf970 --- /dev/null +++ b/drivers/interconnect/qcom/sm8350.c @@ -0,0 +1,633 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Limited + * + */ + +#include <linux/interconnect-provider.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <dt-bindings/interconnect/qcom,sm8350.h> + +#include "bcm-voter.h" +#include "icc-rpmh.h" +#include "sm8350.h" + +DEFINE_QNODE(qhm_qspi, SM8350_MASTER_QSPI_0, 1, 4, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(qhm_qup0, SM8350_MASTER_QUP_0, 1, 4, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qhm_qup1, SM8350_MASTER_QUP_1, 1, 4, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(qhm_qup2, SM8350_MASTER_QUP_2, 1, 4, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qnm_a1noc_cfg, SM8350_MASTER_A1NOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_A1NOC); +DEFINE_QNODE(xm_sdc4, SM8350_MASTER_SDCC_4, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(xm_ufs_mem, SM8350_MASTER_UFS_MEM, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(xm_usb3_0, SM8350_MASTER_USB3_0, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(xm_usb3_1, SM8350_MASTER_USB3_1, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(qhm_qdss_bam, SM8350_MASTER_QDSS_BAM, 1, 4, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qnm_a2noc_cfg, SM8350_MASTER_A2NOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_A2NOC); +DEFINE_QNODE(qxm_crypto, SM8350_MASTER_CRYPTO, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qxm_ipa, SM8350_MASTER_IPA, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(xm_pcie3_0, SM8350_MASTER_PCIE_0, 1, 8, SM8350_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(xm_pcie3_1, SM8350_MASTER_PCIE_1, 1, 8, SM8350_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(xm_qdss_etr, SM8350_MASTER_QDSS_ETR, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(xm_sdc2, SM8350_MASTER_SDCC_2, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(xm_ufs_card, SM8350_MASTER_UFS_CARD, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qnm_gemnoc_cnoc, SM8350_MASTER_GEM_NOC_CNOC, 1, 16, SM8350_SLAVE_AHB2PHY_SOUTH, SM8350_SLAVE_AHB2PHY_NORTH, SM8350_SLAVE_AOSS, SM8350_SLAVE_APPSS, SM8350_SLAVE_CAMERA_CFG, SM8350_SLAVE_CLK_CTL, SM8350_SLAVE_CDSP_CFG, SM8350_SLAVE_RBCPR_CX_CFG, SM8350_SLAVE_RBCPR_MMCX_CFG, SM8350_SLAVE_RBCPR_MX_CFG, SM8350_SLAVE_CRYPTO_0_CFG, SM8350_SLAVE_CX_RDPM, SM8350_SLAVE_DCC_CFG, SM8350_SLAVE_DISPLAY_CFG, SM8350_SLAVE_GFX3D_CFG, SM8350_SLAVE_HWKM, SM8350_SLAVE_IMEM_CFG, SM8350_SLAVE_IPA_CFG, SM8350_SLAVE_IPC_ROUTER_CFG, SM8350_SLAVE_LPASS, SM8350_SLAVE_CNOC_MSS, SM8350_SLAVE_MX_RDPM, SM8350_SLAVE_PCIE_0_CFG, SM8350_SLAVE_PCIE_1_CFG, SM8350_SLAVE_PDM, SM8350_SLAVE_PIMEM_CFG, SM8350_SLAVE_PKA_WRAPPER_CFG, SM8350_SLAVE_PMU_WRAPPER_CFG, SM8350_SLAVE_QDSS_CFG, SM8350_SLAVE_QSPI_0, SM8350_SLAVE_QUP_0, SM8350_SLAVE_QUP_1, SM8350_SLAVE_QUP_2, SM8350_SLAVE_SDCC_2, SM8350_SLAVE_SDCC_4, SM8350_SLAVE_SECURITY, SM8350_SLAVE_SPSS_CFG, SM8350_SLAVE_TCSR, SM8350_SLAVE_TLMM, SM8350_SLAVE_UFS_CARD_CFG, SM8350_SLAVE_UFS_MEM_CFG, SM8350_SLAVE_USB3_0, SM8350_SLAVE_USB3_1, SM8350_SLAVE_VENUS_CFG, SM8350_SLAVE_VSENSE_CTRL_CFG, SM8350_SLAVE_A1NOC_CFG, SM8350_SLAVE_A2NOC_CFG, SM8350_SLAVE_DDRSS_CFG, SM8350_SLAVE_CNOC_MNOC_CFG, SM8350_SLAVE_SNOC_CFG, SM8350_SLAVE_BOOT_IMEM, SM8350_SLAVE_IMEM, SM8350_SLAVE_PIMEM, SM8350_SLAVE_SERVICE_CNOC, SM8350_SLAVE_QDSS_STM, SM8350_SLAVE_TCU); +DEFINE_QNODE(qnm_gemnoc_pcie, SM8350_MASTER_GEM_NOC_PCIE_SNOC, 1, 8, SM8350_SLAVE_PCIE_0, SM8350_SLAVE_PCIE_1); +DEFINE_QNODE(xm_qdss_dap, SM8350_MASTER_QDSS_DAP, 1, 8, SM8350_SLAVE_AHB2PHY_SOUTH, SM8350_SLAVE_AHB2PHY_NORTH, SM8350_SLAVE_AOSS, SM8350_SLAVE_APPSS, SM8350_SLAVE_CAMERA_CFG, SM8350_SLAVE_CLK_CTL, SM8350_SLAVE_CDSP_CFG, SM8350_SLAVE_RBCPR_CX_CFG, SM8350_SLAVE_RBCPR_MMCX_CFG, SM8350_SLAVE_RBCPR_MX_CFG, SM8350_SLAVE_CRYPTO_0_CFG, SM8350_SLAVE_CX_RDPM, SM8350_SLAVE_DCC_CFG, SM8350_SLAVE_DISPLAY_CFG, SM8350_SLAVE_GFX3D_CFG, SM8350_SLAVE_HWKM, SM8350_SLAVE_IMEM_CFG, SM8350_SLAVE_IPA_CFG, SM8350_SLAVE_IPC_ROUTER_CFG, SM8350_SLAVE_LPASS, SM8350_SLAVE_CNOC_MSS, SM8350_SLAVE_MX_RDPM, SM8350_SLAVE_PCIE_0_CFG, SM8350_SLAVE_PCIE_1_CFG, SM8350_SLAVE_PDM, SM8350_SLAVE_PIMEM_CFG, SM8350_SLAVE_PKA_WRAPPER_CFG, SM8350_SLAVE_PMU_WRAPPER_CFG, SM8350_SLAVE_QDSS_CFG, SM8350_SLAVE_QSPI_0, SM8350_SLAVE_QUP_0, SM8350_SLAVE_QUP_1, SM8350_SLAVE_QUP_2, SM8350_SLAVE_SDCC_2, SM8350_SLAVE_SDCC_4, SM8350_SLAVE_SECURITY, SM8350_SLAVE_SPSS_CFG, SM8350_SLAVE_TCSR, SM8350_SLAVE_TLMM, SM8350_SLAVE_UFS_CARD_CFG, SM8350_SLAVE_UFS_MEM_CFG, SM8350_SLAVE_USB3_0, SM8350_SLAVE_USB3_1, SM8350_SLAVE_VENUS_CFG, SM8350_SLAVE_VSENSE_CTRL_CFG, SM8350_SLAVE_A1NOC_CFG, SM8350_SLAVE_A2NOC_CFG, SM8350_SLAVE_DDRSS_CFG, SM8350_SLAVE_CNOC_MNOC_CFG, SM8350_SLAVE_SNOC_CFG, SM8350_SLAVE_BOOT_IMEM, SM8350_SLAVE_IMEM, SM8350_SLAVE_PIMEM, SM8350_SLAVE_SERVICE_CNOC, SM8350_SLAVE_QDSS_STM, SM8350_SLAVE_TCU); +DEFINE_QNODE(qnm_cnoc_dc_noc, SM8350_MASTER_CNOC_DC_NOC, 1, 4, SM8350_SLAVE_LLCC_CFG, SM8350_SLAVE_GEM_NOC_CFG); +DEFINE_QNODE(alm_gpu_tcu, SM8350_MASTER_GPU_TCU, 1, 8, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(alm_sys_tcu, SM8350_MASTER_SYS_TCU, 1, 8, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(chm_apps, SM8350_MASTER_APPSS_PROC, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC, SM8350_SLAVE_MEM_NOC_PCIE_SNOC); +DEFINE_QNODE(qnm_cmpnoc, SM8350_MASTER_COMPUTE_NOC, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_gemnoc_cfg, SM8350_MASTER_GEM_NOC_CFG, 1, 4, SM8350_SLAVE_MSS_PROC_MS_MPU_CFG, SM8350_SLAVE_MCDMA_MS_MPU_CFG, SM8350_SLAVE_SERVICE_GEM_NOC_1, SM8350_SLAVE_SERVICE_GEM_NOC_2, SM8350_SLAVE_SERVICE_GEM_NOC); +DEFINE_QNODE(qnm_gpu, SM8350_MASTER_GFX3D, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_mnoc_hf, SM8350_MASTER_MNOC_HF_MEM_NOC, 2, 32, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_mnoc_sf, SM8350_MASTER_MNOC_SF_MEM_NOC, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_pcie, SM8350_MASTER_ANOC_PCIE_GEM_NOC, 1, 16, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_snoc_gc, SM8350_MASTER_SNOC_GC_MEM_NOC, 1, 8, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_snoc_sf, SM8350_MASTER_SNOC_SF_MEM_NOC, 1, 16, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC, SM8350_SLAVE_MEM_NOC_PCIE_SNOC); +DEFINE_QNODE(qhm_config_noc, SM8350_MASTER_CNOC_LPASS_AG_NOC, 1, 4, SM8350_SLAVE_LPASS_CORE_CFG, SM8350_SLAVE_LPASS_LPI_CFG, SM8350_SLAVE_LPASS_MPU_CFG, SM8350_SLAVE_LPASS_TOP_CFG, SM8350_SLAVE_SERVICES_LPASS_AML_NOC, SM8350_SLAVE_SERVICE_LPASS_AG_NOC); +DEFINE_QNODE(llcc_mc, SM8350_MASTER_LLCC, 4, 4, SM8350_SLAVE_EBI1); +DEFINE_QNODE(qnm_camnoc_hf, SM8350_MASTER_CAMNOC_HF, 2, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qnm_camnoc_icp, SM8350_MASTER_CAMNOC_ICP, 1, 8, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_camnoc_sf, SM8350_MASTER_CAMNOC_SF, 2, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_mnoc_cfg, SM8350_MASTER_CNOC_MNOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_MNOC); +DEFINE_QNODE(qnm_video0, SM8350_MASTER_VIDEO_P0, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_video1, SM8350_MASTER_VIDEO_P1, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_video_cvp, SM8350_MASTER_VIDEO_PROC, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qxm_mdp0, SM8350_MASTER_MDP0, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qxm_mdp1, SM8350_MASTER_MDP1, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qxm_rot, SM8350_MASTER_ROTATOR, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qhm_nsp_noc_config, SM8350_MASTER_CDSP_NOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_NSP_NOC); +DEFINE_QNODE(qxm_nsp, SM8350_MASTER_CDSP_PROC, 2, 32, SM8350_SLAVE_CDSP_MEM_NOC); +DEFINE_QNODE(qnm_aggre1_noc, SM8350_MASTER_A1NOC_SNOC, 1, 16, SM8350_SLAVE_SNOC_GEM_NOC_SF); +DEFINE_QNODE(qnm_aggre2_noc, SM8350_MASTER_A2NOC_SNOC, 1, 16, SM8350_SLAVE_SNOC_GEM_NOC_SF); +DEFINE_QNODE(qnm_snoc_cfg, SM8350_MASTER_SNOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_SNOC); +DEFINE_QNODE(qxm_pimem, SM8350_MASTER_PIMEM, 1, 8, SM8350_SLAVE_SNOC_GEM_NOC_GC); +DEFINE_QNODE(xm_gic, SM8350_MASTER_GIC, 1, 8, SM8350_SLAVE_SNOC_GEM_NOC_GC); +DEFINE_QNODE(qnm_mnoc_hf_disp, SM8350_MASTER_MNOC_HF_MEM_NOC_DISP, 2, 32, SM8350_SLAVE_LLCC_DISP); +DEFINE_QNODE(qnm_mnoc_sf_disp, SM8350_MASTER_MNOC_SF_MEM_NOC_DISP, 2, 32, SM8350_SLAVE_LLCC_DISP); +DEFINE_QNODE(llcc_mc_disp, SM8350_MASTER_LLCC_DISP, 4, 4, SM8350_SLAVE_EBI1_DISP); +DEFINE_QNODE(qxm_mdp0_disp, SM8350_MASTER_MDP0_DISP, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP); +DEFINE_QNODE(qxm_mdp1_disp, SM8350_MASTER_MDP1_DISP, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP); +DEFINE_QNODE(qxm_rot_disp, SM8350_MASTER_ROTATOR_DISP, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP); +DEFINE_QNODE(qns_a1noc_snoc, SM8350_SLAVE_A1NOC_SNOC, 1, 16, SM8350_MASTER_A1NOC_SNOC); +DEFINE_QNODE(srvc_aggre1_noc, SM8350_SLAVE_SERVICE_A1NOC, 1, 4); +DEFINE_QNODE(qns_a2noc_snoc, SM8350_SLAVE_A2NOC_SNOC, 1, 16, SM8350_MASTER_A2NOC_SNOC); +DEFINE_QNODE(qns_pcie_mem_noc, SM8350_SLAVE_ANOC_PCIE_GEM_NOC, 1, 16, SM8350_MASTER_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(srvc_aggre2_noc, SM8350_SLAVE_SERVICE_A2NOC, 1, 4); +DEFINE_QNODE(qhs_ahb2phy0, SM8350_SLAVE_AHB2PHY_SOUTH, 1, 4); +DEFINE_QNODE(qhs_ahb2phy1, SM8350_SLAVE_AHB2PHY_NORTH, 1, 4); +DEFINE_QNODE(qhs_aoss, SM8350_SLAVE_AOSS, 1, 4); +DEFINE_QNODE(qhs_apss, SM8350_SLAVE_APPSS, 1, 8); +DEFINE_QNODE(qhs_camera_cfg, SM8350_SLAVE_CAMERA_CFG, 1, 4); +DEFINE_QNODE(qhs_clk_ctl, SM8350_SLAVE_CLK_CTL, 1, 4); +DEFINE_QNODE(qhs_compute_cfg, SM8350_SLAVE_CDSP_CFG, 1, 4); +DEFINE_QNODE(qhs_cpr_cx, SM8350_SLAVE_RBCPR_CX_CFG, 1, 4); +DEFINE_QNODE(qhs_cpr_mmcx, SM8350_SLAVE_RBCPR_MMCX_CFG, 1, 4); +DEFINE_QNODE(qhs_cpr_mx, SM8350_SLAVE_RBCPR_MX_CFG, 1, 4); +DEFINE_QNODE(qhs_crypto0_cfg, SM8350_SLAVE_CRYPTO_0_CFG, 1, 4); +DEFINE_QNODE(qhs_cx_rdpm, SM8350_SLAVE_CX_RDPM, 1, 4); +DEFINE_QNODE(qhs_dcc_cfg, SM8350_SLAVE_DCC_CFG, 1, 4); +DEFINE_QNODE(qhs_display_cfg, SM8350_SLAVE_DISPLAY_CFG, 1, 4); +DEFINE_QNODE(qhs_gpuss_cfg, SM8350_SLAVE_GFX3D_CFG, 1, 8); +DEFINE_QNODE(qhs_hwkm, SM8350_SLAVE_HWKM, 1, 4); +DEFINE_QNODE(qhs_imem_cfg, SM8350_SLAVE_IMEM_CFG, 1, 4); +DEFINE_QNODE(qhs_ipa, SM8350_SLAVE_IPA_CFG, 1, 4); +DEFINE_QNODE(qhs_ipc_router, SM8350_SLAVE_IPC_ROUTER_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_cfg, SM8350_SLAVE_LPASS, 1, 4, SM8350_MASTER_CNOC_LPASS_AG_NOC); +DEFINE_QNODE(qhs_mss_cfg, SM8350_SLAVE_CNOC_MSS, 1, 4); +DEFINE_QNODE(qhs_mx_rdpm, SM8350_SLAVE_MX_RDPM, 1, 4); +DEFINE_QNODE(qhs_pcie0_cfg, SM8350_SLAVE_PCIE_0_CFG, 1, 4); +DEFINE_QNODE(qhs_pcie1_cfg, SM8350_SLAVE_PCIE_1_CFG, 1, 4); +DEFINE_QNODE(qhs_pdm, SM8350_SLAVE_PDM, 1, 4); +DEFINE_QNODE(qhs_pimem_cfg, SM8350_SLAVE_PIMEM_CFG, 1, 4); +DEFINE_QNODE(qhs_pka_wrapper_cfg, SM8350_SLAVE_PKA_WRAPPER_CFG, 1, 4); +DEFINE_QNODE(qhs_pmu_wrapper_cfg, SM8350_SLAVE_PMU_WRAPPER_CFG, 1, 4); +DEFINE_QNODE(qhs_qdss_cfg, SM8350_SLAVE_QDSS_CFG, 1, 4); +DEFINE_QNODE(qhs_qspi, SM8350_SLAVE_QSPI_0, 1, 4); +DEFINE_QNODE(qhs_qup0, SM8350_SLAVE_QUP_0, 1, 4); +DEFINE_QNODE(qhs_qup1, SM8350_SLAVE_QUP_1, 1, 4); +DEFINE_QNODE(qhs_qup2, SM8350_SLAVE_QUP_2, 1, 4); +DEFINE_QNODE(qhs_sdc2, SM8350_SLAVE_SDCC_2, 1, 4); +DEFINE_QNODE(qhs_sdc4, SM8350_SLAVE_SDCC_4, 1, 4); +DEFINE_QNODE(qhs_security, SM8350_SLAVE_SECURITY, 1, 4); +DEFINE_QNODE(qhs_spss_cfg, SM8350_SLAVE_SPSS_CFG, 1, 4); +DEFINE_QNODE(qhs_tcsr, SM8350_SLAVE_TCSR, 1, 4); +DEFINE_QNODE(qhs_tlmm, SM8350_SLAVE_TLMM, 1, 4); +DEFINE_QNODE(qhs_ufs_card_cfg, SM8350_SLAVE_UFS_CARD_CFG, 1, 4); +DEFINE_QNODE(qhs_ufs_mem_cfg, SM8350_SLAVE_UFS_MEM_CFG, 1, 4); +DEFINE_QNODE(qhs_usb3_0, SM8350_SLAVE_USB3_0, 1, 4); +DEFINE_QNODE(qhs_usb3_1, SM8350_SLAVE_USB3_1, 1, 4); +DEFINE_QNODE(qhs_venus_cfg, SM8350_SLAVE_VENUS_CFG, 1, 4); +DEFINE_QNODE(qhs_vsense_ctrl_cfg, SM8350_SLAVE_VSENSE_CTRL_CFG, 1, 4); +DEFINE_QNODE(qns_a1_noc_cfg, SM8350_SLAVE_A1NOC_CFG, 1, 4); +DEFINE_QNODE(qns_a2_noc_cfg, SM8350_SLAVE_A2NOC_CFG, 1, 4); +DEFINE_QNODE(qns_ddrss_cfg, SM8350_SLAVE_DDRSS_CFG, 1, 4); +DEFINE_QNODE(qns_mnoc_cfg, SM8350_SLAVE_CNOC_MNOC_CFG, 1, 4); +DEFINE_QNODE(qns_snoc_cfg, SM8350_SLAVE_SNOC_CFG, 1, 4); +DEFINE_QNODE(qxs_boot_imem, SM8350_SLAVE_BOOT_IMEM, 1, 8); +DEFINE_QNODE(qxs_imem, SM8350_SLAVE_IMEM, 1, 8); +DEFINE_QNODE(qxs_pimem, SM8350_SLAVE_PIMEM, 1, 8); +DEFINE_QNODE(srvc_cnoc, SM8350_SLAVE_SERVICE_CNOC, 1, 4); +DEFINE_QNODE(xs_pcie_0, SM8350_SLAVE_PCIE_0, 1, 8); +DEFINE_QNODE(xs_pcie_1, SM8350_SLAVE_PCIE_1, 1, 8); +DEFINE_QNODE(xs_qdss_stm, SM8350_SLAVE_QDSS_STM, 1, 4); +DEFINE_QNODE(xs_sys_tcu_cfg, SM8350_SLAVE_TCU, 1, 8); +DEFINE_QNODE(qhs_llcc, SM8350_SLAVE_LLCC_CFG, 1, 4); +DEFINE_QNODE(qns_gemnoc, SM8350_SLAVE_GEM_NOC_CFG, 1, 4); +DEFINE_QNODE(qhs_mdsp_ms_mpu_cfg, SM8350_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4); +DEFINE_QNODE(qhs_modem_ms_mpu_cfg, SM8350_SLAVE_MCDMA_MS_MPU_CFG, 1, 4); +DEFINE_QNODE(qns_gem_noc_cnoc, SM8350_SLAVE_GEM_NOC_CNOC, 1, 16, SM8350_MASTER_GEM_NOC_CNOC); +DEFINE_QNODE(qns_llcc, SM8350_SLAVE_LLCC, 4, 16, SM8350_MASTER_LLCC); +DEFINE_QNODE(qns_pcie, SM8350_SLAVE_MEM_NOC_PCIE_SNOC, 1, 8); +DEFINE_QNODE(srvc_even_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC_1, 1, 4); +DEFINE_QNODE(srvc_odd_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC_2, 1, 4); +DEFINE_QNODE(srvc_sys_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC, 1, 4); +DEFINE_QNODE(qhs_lpass_core, SM8350_SLAVE_LPASS_CORE_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_lpi, SM8350_SLAVE_LPASS_LPI_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_mpu, SM8350_SLAVE_LPASS_MPU_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_top, SM8350_SLAVE_LPASS_TOP_CFG, 1, 4); +DEFINE_QNODE(srvc_niu_aml_noc, SM8350_SLAVE_SERVICES_LPASS_AML_NOC, 1, 4); +DEFINE_QNODE(srvc_niu_lpass_agnoc, SM8350_SLAVE_SERVICE_LPASS_AG_NOC, 1, 4); +DEFINE_QNODE(ebi, SM8350_SLAVE_EBI1, 4, 4); +DEFINE_QNODE(qns_mem_noc_hf, SM8350_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SM8350_MASTER_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qns_mem_noc_sf, SM8350_SLAVE_MNOC_SF_MEM_NOC, 2, 32, SM8350_MASTER_MNOC_SF_MEM_NOC); +DEFINE_QNODE(srvc_mnoc, SM8350_SLAVE_SERVICE_MNOC, 1, 4); +DEFINE_QNODE(qns_nsp_gemnoc, SM8350_SLAVE_CDSP_MEM_NOC, 2, 32, SM8350_MASTER_COMPUTE_NOC); +DEFINE_QNODE(service_nsp_noc, SM8350_SLAVE_SERVICE_NSP_NOC, 1, 4); +DEFINE_QNODE(qns_gemnoc_gc, SM8350_SLAVE_SNOC_GEM_NOC_GC, 1, 8, SM8350_MASTER_SNOC_GC_MEM_NOC); +DEFINE_QNODE(qns_gemnoc_sf, SM8350_SLAVE_SNOC_GEM_NOC_SF, 1, 16, SM8350_MASTER_SNOC_SF_MEM_NOC); +DEFINE_QNODE(srvc_snoc, SM8350_SLAVE_SERVICE_SNOC, 1, 4); +DEFINE_QNODE(qns_llcc_disp, SM8350_SLAVE_LLCC_DISP, 4, 16, SM8350_MASTER_LLCC_DISP); +DEFINE_QNODE(ebi_disp, SM8350_SLAVE_EBI1_DISP, 4, 4); +DEFINE_QNODE(qns_mem_noc_hf_disp, SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP, 2, 32, SM8350_MASTER_MNOC_HF_MEM_NOC_DISP); +DEFINE_QNODE(qns_mem_noc_sf_disp, SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP, 2, 32, SM8350_MASTER_MNOC_SF_MEM_NOC_DISP); + +DEFINE_QBCM(bcm_acv, "ACV", false, &ebi); +DEFINE_QBCM(bcm_ce0, "CE0", false, &qxm_crypto); +DEFINE_QBCM(bcm_cn0, "CN0", true, &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie); +DEFINE_QBCM(bcm_cn1, "CN1", false, &xm_qdss_dap, &qhs_ahb2phy0, &qhs_ahb2phy1, &qhs_aoss, &qhs_apss, &qhs_camera_cfg, &qhs_clk_ctl, &qhs_compute_cfg, &qhs_cpr_cx, &qhs_cpr_mmcx, &qhs_cpr_mx, &qhs_crypto0_cfg, &qhs_cx_rdpm, &qhs_dcc_cfg, &qhs_display_cfg, &qhs_gpuss_cfg, &qhs_hwkm, &qhs_imem_cfg, &qhs_ipa, &qhs_ipc_router, &qhs_mss_cfg, &qhs_mx_rdpm, &qhs_pcie0_cfg, &qhs_pcie1_cfg, &qhs_pimem_cfg, &qhs_pka_wrapper_cfg, &qhs_pmu_wrapper_cfg, &qhs_qdss_cfg, &qhs_qup0, &qhs_qup1, &qhs_qup2, &qhs_security, &qhs_spss_cfg, &qhs_tcsr, &qhs_tlmm, &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg, &qhs_usb3_0, &qhs_usb3_1, &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, &qns_a1_noc_cfg, &qns_a2_noc_cfg, &qns_ddrss_cfg, &qns_mnoc_cfg, &qns_snoc_cfg, &srvc_cnoc); +DEFINE_QBCM(bcm_cn2, "CN2", false, &qhs_lpass_cfg, &qhs_pdm, &qhs_qspi, &qhs_sdc2, &qhs_sdc4); +DEFINE_QBCM(bcm_co0, "CO0", false, &qns_nsp_gemnoc); +DEFINE_QBCM(bcm_co3, "CO3", false, &qxm_nsp); +DEFINE_QBCM(bcm_mc0, "MC0", true, &ebi); +DEFINE_QBCM(bcm_mm0, "MM0", true, &qns_mem_noc_hf); +DEFINE_QBCM(bcm_mm1, "MM1", false, &qnm_camnoc_hf, &qxm_mdp0, &qxm_mdp1); +DEFINE_QBCM(bcm_mm4, "MM4", false, &qns_mem_noc_sf); +DEFINE_QBCM(bcm_mm5, "MM5", false, &qnm_camnoc_icp, &qnm_camnoc_sf, &qnm_video0, &qnm_video1, &qnm_video_cvp, &qxm_rot); +DEFINE_QBCM(bcm_sh0, "SH0", true, &qns_llcc); +DEFINE_QBCM(bcm_sh2, "SH2", false, &alm_gpu_tcu, &alm_sys_tcu); +DEFINE_QBCM(bcm_sh3, "SH3", false, &qnm_cmpnoc); +DEFINE_QBCM(bcm_sh4, "SH4", false, &chm_apps); +DEFINE_QBCM(bcm_sn0, "SN0", true, &qns_gemnoc_sf); +DEFINE_QBCM(bcm_sn2, "SN2", false, &qns_gemnoc_gc); +DEFINE_QBCM(bcm_sn3, "SN3", false, &qxs_pimem); +DEFINE_QBCM(bcm_sn4, "SN4", false, &xs_qdss_stm); +DEFINE_QBCM(bcm_sn5, "SN5", false, &xm_pcie3_0); +DEFINE_QBCM(bcm_sn6, "SN6", false, &xm_pcie3_1); +DEFINE_QBCM(bcm_sn7, "SN7", false, &qnm_aggre1_noc); +DEFINE_QBCM(bcm_sn8, "SN8", false, &qnm_aggre2_noc); +DEFINE_QBCM(bcm_sn14, "SN14", false, &qns_pcie_mem_noc); +DEFINE_QBCM(bcm_acv_disp, "ACV", false, &ebi_disp); +DEFINE_QBCM(bcm_mc0_disp, "MC0", false, &ebi_disp); +DEFINE_QBCM(bcm_mm0_disp, "MM0", false, &qns_mem_noc_hf_disp); +DEFINE_QBCM(bcm_mm1_disp, "MM1", false, &qxm_mdp0_disp, &qxm_mdp1_disp); +DEFINE_QBCM(bcm_mm4_disp, "MM4", false, &qns_mem_noc_sf_disp); +DEFINE_QBCM(bcm_mm5_disp, "MM5", false, &qxm_rot_disp); +DEFINE_QBCM(bcm_sh0_disp, "SH0", false, &qns_llcc_disp); + +static struct qcom_icc_bcm *aggre1_noc_bcms[] = { +}; + +static struct qcom_icc_node *aggre1_noc_nodes[] = { + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_A1NOC_CFG] = &qnm_a1noc_cfg, + [MASTER_SDCC_4] = &xm_sdc4, + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB3_0] = &xm_usb3_0, + [MASTER_USB3_1] = &xm_usb3_1, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, + [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc, +}; + +static struct qcom_icc_desc sm8350_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 *aggre2_noc_bcms[] = { + &bcm_ce0, + &bcm_sn5, + &bcm_sn6, + &bcm_sn14, +}; + +static struct qcom_icc_node *aggre2_noc_nodes[] = { + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_QUP_2] = &qhm_qup2, + [MASTER_A2NOC_CFG] = &qnm_a2noc_cfg, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_IPA] = &qxm_ipa, + [MASTER_PCIE_0] = &xm_pcie3_0, + [MASTER_PCIE_1] = &xm_pcie3_1, + [MASTER_QDSS_ETR] = &xm_qdss_etr, + [MASTER_SDCC_2] = &xm_sdc2, + [MASTER_UFS_CARD] = &xm_ufs_card, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, + [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc, +}; + +static struct qcom_icc_desc sm8350_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 *config_noc_bcms[] = { + &bcm_cn0, + &bcm_cn1, + &bcm_cn2, + &bcm_sn3, + &bcm_sn4, +}; + +static struct qcom_icc_node *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_AHB2PHY_NORTH] = &qhs_ahb2phy1, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_APPSS] = &qhs_apss, + [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_MX_CFG] = &qhs_cpr_mx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_CX_RDPM] = &qhs_cx_rdpm, + [SLAVE_DCC_CFG] = &qhs_dcc_cfg, + [SLAVE_DISPLAY_CFG] = &qhs_display_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_CNOC_MSS] = &qhs_mss_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_PKA_WRAPPER_CFG] = &qhs_pka_wrapper_cfg, + [SLAVE_PMU_WRAPPER_CFG] = &qhs_pmu_wrapper_cfg, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_QUP_2] = &qhs_qup2, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SDCC_4] = &qhs_sdc4, + [SLAVE_SECURITY] = &qhs_security, + [SLAVE_SPSS_CFG] = &qhs_spss_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_UFS_CARD_CFG] = &qhs_ufs_card_cfg, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB3_0] = &qhs_usb3_0, + [SLAVE_USB3_1] = &qhs_usb3_1, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_A1NOC_CFG] = &qns_a1_noc_cfg, + [SLAVE_A2NOC_CFG] = &qns_a2_noc_cfg, + [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg, + [SLAVE_CNOC_MNOC_CFG] = &qns_mnoc_cfg, + [SLAVE_SNOC_CFG] = &qns_snoc_cfg, + [SLAVE_BOOT_IMEM] = &qxs_boot_imem, + [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 struct qcom_icc_desc sm8350_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_bcm *dc_noc_bcms[] = { +}; + +static struct qcom_icc_node *dc_noc_nodes[] = { + [MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc, + [SLAVE_LLCC_CFG] = &qhs_llcc, + [SLAVE_GEM_NOC_CFG] = &qns_gemnoc, +}; + +static struct qcom_icc_desc sm8350_dc_noc = { + .nodes = dc_noc_nodes, + .num_nodes = ARRAY_SIZE(dc_noc_nodes), + .bcms = dc_noc_bcms, + .num_bcms = ARRAY_SIZE(dc_noc_bcms), +}; + +static struct qcom_icc_bcm *gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh2, + &bcm_sh3, + &bcm_sh4, + &bcm_sh0_disp, +}; + +static struct qcom_icc_node *gem_noc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_COMPUTE_NOC] = &qnm_cmpnoc, + [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg, + [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_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg, + [SLAVE_MCDMA_MS_MPU_CFG] = &qhs_modem_ms_mpu_cfg, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &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, + [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp, + [MASTER_MNOC_SF_MEM_NOC_DISP] = &qnm_mnoc_sf_disp, + [SLAVE_LLCC_DISP] = &qns_llcc_disp, +}; + +static struct qcom_icc_desc sm8350_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 *lpass_ag_noc_bcms[] = { +}; + +static struct qcom_icc_node *lpass_ag_noc_nodes[] = { + [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc, + [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_SERVICES_LPASS_AML_NOC] = &srvc_niu_aml_noc, + [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc, +}; + +static struct qcom_icc_desc sm8350_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 *mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, + &bcm_acv_disp, + &bcm_mc0_disp, +}; + +static struct qcom_icc_node *mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, + [MASTER_LLCC_DISP] = &llcc_mc_disp, + [SLAVE_EBI1_DISP] = &ebi_disp, +}; + +static struct qcom_icc_desc sm8350_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 *mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, + &bcm_mm4, + &bcm_mm5, + &bcm_mm0_disp, + &bcm_mm1_disp, + &bcm_mm4_disp, + &bcm_mm5_disp, +}; + +static struct qcom_icc_node *mmss_noc_nodes[] = { + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_CNOC_MNOC_CFG] = &qnm_mnoc_cfg, + [MASTER_VIDEO_P0] = &qnm_video0, + [MASTER_VIDEO_P1] = &qnm_video1, + [MASTER_VIDEO_PROC] = &qnm_video_cvp, + [MASTER_MDP0] = &qxm_mdp0, + [MASTER_MDP1] = &qxm_mdp1, + [MASTER_ROTATOR] = &qxm_rot, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, + [MASTER_MDP0_DISP] = &qxm_mdp0_disp, + [MASTER_MDP1_DISP] = &qxm_mdp1_disp, + [MASTER_ROTATOR_DISP] = &qxm_rot_disp, + [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp, + [SLAVE_MNOC_SF_MEM_NOC_DISP] = &qns_mem_noc_sf_disp, +}; + +static struct qcom_icc_desc sm8350_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 *nsp_noc_bcms[] = { + &bcm_co0, + &bcm_co3, +}; + +static struct qcom_icc_node *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 struct qcom_icc_desc sm8350_compute_noc = { + .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 *system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn2, + &bcm_sn7, + &bcm_sn8, +}; + +static struct qcom_icc_node *system_noc_nodes[] = { + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_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 struct qcom_icc_desc sm8350_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 int qnoc_probe(struct platform_device *pdev) +{ + const struct qcom_icc_desc *desc; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node **qnodes; + struct qcom_icc_provider *qp; + struct icc_node *node; + size_t num_nodes, i; + int ret; + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); + if (!data) + return -ENOMEM; + + provider = &qp->provider; + provider->dev = &pdev->dev; + provider->set = qcom_icc_set; + provider->pre_aggregate = qcom_icc_pre_aggregate; + provider->aggregate = qcom_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; + INIT_LIST_HEAD(&provider->nodes); + provider->data = data; + + qp->dev = &pdev->dev; + qp->bcms = desc->bcms; + qp->num_bcms = desc->num_bcms; + + qp->voter = of_bcm_voter_get(qp->dev, NULL); + if (IS_ERR(qp->voter)) + return PTR_ERR(qp->voter); + + ret = icc_provider_add(provider); + if (ret) { + dev_err(&pdev->dev, "error adding interconnect provider\n"); + return ret; + } + + for (i = 0; i < qp->num_bcms; i++) + qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); + + for (i = 0; i < num_nodes; i++) { + size_t j; + + if (!qnodes[i]) + continue; + + node = icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qnodes[i]->name; + node->data = qnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = num_nodes; + + platform_set_drvdata(pdev, qp); + + return ret; + +err: + icc_nodes_remove(provider); + icc_provider_del(provider); + return ret; +} + +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + return icc_provider_del(&qp->provider); +} + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,sm8350-aggre1-noc", .data = &sm8350_aggre1_noc}, + { .compatible = "qcom,sm8350-aggre2-noc", .data = &sm8350_aggre2_noc}, + { .compatible = "qcom,sm8350-config-noc", .data = &sm8350_config_noc}, + { .compatible = "qcom,sm8350-dc-noc", .data = &sm8350_dc_noc}, + { .compatible = "qcom,sm8350-gem-noc", .data = &sm8350_gem_noc}, + { .compatible = "qcom,sm8350-lpass-ag-noc", .data = &sm8350_lpass_ag_noc}, + { .compatible = "qcom,sm8350-mc-virt", .data = &sm8350_mc_virt}, + { .compatible = "qcom,sm8350-mmss-noc", .data = &sm8350_mmss_noc}, + { .compatible = "qcom,sm8350-compute-noc", .data = &sm8350_compute_noc}, + { .compatible = "qcom,sm8350-system-noc", .data = &sm8350_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-sm8350", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; +module_platform_driver(qnoc_driver); + +MODULE_DESCRIPTION("SM8350 NoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/sm8350.h b/drivers/interconnect/qcom/sm8350.h new file mode 100644 index 0000000000000000000000000000000000000000..328d15238a0dbcb51bf255150285c613213a5118 --- /dev/null +++ b/drivers/interconnect/qcom/sm8350.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Qualcomm SM8350 interconnect IDs + * + * Copyright (c) 2021, Linaro Limited + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_SM8350_H +#define __DRIVERS_INTERCONNECT_QCOM_SM8350_H + +#define SM8350_MASTER_GPU_TCU 0 +#define SM8350_MASTER_SYS_TCU 1 +#define SM8350_MASTER_APPSS_PROC 2 +#define SM8350_MASTER_LLCC 3 +#define SM8350_MASTER_CNOC_LPASS_AG_NOC 4 +#define SM8350_MASTER_CDSP_NOC_CFG 5 +#define SM8350_MASTER_QDSS_BAM 6 +#define SM8350_MASTER_QSPI_0 7 +#define SM8350_MASTER_QUP_0 8 +#define SM8350_MASTER_QUP_1 9 +#define SM8350_MASTER_QUP_2 10 +#define SM8350_MASTER_A1NOC_CFG 11 +#define SM8350_MASTER_A2NOC_CFG 12 +#define SM8350_MASTER_A1NOC_SNOC 13 +#define SM8350_MASTER_A2NOC_SNOC 14 +#define SM8350_MASTER_CAMNOC_HF 15 +#define SM8350_MASTER_CAMNOC_ICP 16 +#define SM8350_MASTER_CAMNOC_SF 17 +#define SM8350_MASTER_COMPUTE_NOC 18 +#define SM8350_MASTER_CNOC_DC_NOC 19 +#define SM8350_MASTER_GEM_NOC_CFG 20 +#define SM8350_MASTER_GEM_NOC_CNOC 21 +#define SM8350_MASTER_GEM_NOC_PCIE_SNOC 22 +#define SM8350_MASTER_GFX3D 23 +#define SM8350_MASTER_CNOC_MNOC_CFG 24 +#define SM8350_MASTER_MNOC_HF_MEM_NOC 25 +#define SM8350_MASTER_MNOC_SF_MEM_NOC 26 +#define SM8350_MASTER_ANOC_PCIE_GEM_NOC 27 +#define SM8350_MASTER_SNOC_CFG 28 +#define SM8350_MASTER_SNOC_GC_MEM_NOC 29 +#define SM8350_MASTER_SNOC_SF_MEM_NOC 30 +#define SM8350_MASTER_VIDEO_P0 31 +#define SM8350_MASTER_VIDEO_P1 32 +#define SM8350_MASTER_VIDEO_PROC 33 +#define SM8350_MASTER_QUP_CORE_0 34 +#define SM8350_MASTER_QUP_CORE_1 35 +#define SM8350_MASTER_QUP_CORE_2 36 +#define SM8350_MASTER_CRYPTO 37 +#define SM8350_MASTER_IPA 38 +#define SM8350_MASTER_MDP0 39 +#define SM8350_MASTER_MDP1 40 +#define SM8350_MASTER_CDSP_PROC 41 +#define SM8350_MASTER_PIMEM 42 +#define SM8350_MASTER_ROTATOR 43 +#define SM8350_MASTER_GIC 44 +#define SM8350_MASTER_PCIE_0 45 +#define SM8350_MASTER_PCIE_1 46 +#define SM8350_MASTER_QDSS_DAP 47 +#define SM8350_MASTER_QDSS_ETR 48 +#define SM8350_MASTER_SDCC_2 49 +#define SM8350_MASTER_SDCC_4 50 +#define SM8350_MASTER_UFS_CARD 51 +#define SM8350_MASTER_UFS_MEM 52 +#define SM8350_MASTER_USB3_0 53 +#define SM8350_MASTER_USB3_1 54 +#define SM8350_SLAVE_EBI1 55 +#define SM8350_SLAVE_AHB2PHY_SOUTH 56 +#define SM8350_SLAVE_AHB2PHY_NORTH 57 +#define SM8350_SLAVE_AOSS 58 +#define SM8350_SLAVE_APPSS 59 +#define SM8350_SLAVE_CAMERA_CFG 60 +#define SM8350_SLAVE_CLK_CTL 61 +#define SM8350_SLAVE_CDSP_CFG 62 +#define SM8350_SLAVE_RBCPR_CX_CFG 63 +#define SM8350_SLAVE_RBCPR_MMCX_CFG 64 +#define SM8350_SLAVE_RBCPR_MX_CFG 65 +#define SM8350_SLAVE_CRYPTO_0_CFG 66 +#define SM8350_SLAVE_CX_RDPM 67 +#define SM8350_SLAVE_DCC_CFG 68 +#define SM8350_SLAVE_DISPLAY_CFG 69 +#define SM8350_SLAVE_GFX3D_CFG 70 +#define SM8350_SLAVE_HWKM 71 +#define SM8350_SLAVE_IMEM_CFG 72 +#define SM8350_SLAVE_IPA_CFG 73 +#define SM8350_SLAVE_IPC_ROUTER_CFG 74 +#define SM8350_SLAVE_LLCC_CFG 75 +#define SM8350_SLAVE_LPASS 76 +#define SM8350_SLAVE_LPASS_CORE_CFG 77 +#define SM8350_SLAVE_LPASS_LPI_CFG 78 +#define SM8350_SLAVE_LPASS_MPU_CFG 79 +#define SM8350_SLAVE_LPASS_TOP_CFG 80 +#define SM8350_SLAVE_MSS_PROC_MS_MPU_CFG 81 +#define SM8350_SLAVE_MCDMA_MS_MPU_CFG 82 +#define SM8350_SLAVE_CNOC_MSS 83 +#define SM8350_SLAVE_MX_RDPM 84 +#define SM8350_SLAVE_PCIE_0_CFG 85 +#define SM8350_SLAVE_PCIE_1_CFG 86 +#define SM8350_SLAVE_PDM 87 +#define SM8350_SLAVE_PIMEM_CFG 88 +#define SM8350_SLAVE_PKA_WRAPPER_CFG 89 +#define SM8350_SLAVE_PMU_WRAPPER_CFG 90 +#define SM8350_SLAVE_QDSS_CFG 91 +#define SM8350_SLAVE_QSPI_0 92 +#define SM8350_SLAVE_QUP_0 93 +#define SM8350_SLAVE_QUP_1 94 +#define SM8350_SLAVE_QUP_2 95 +#define SM8350_SLAVE_SDCC_2 96 +#define SM8350_SLAVE_SDCC_4 97 +#define SM8350_SLAVE_SECURITY 98 +#define SM8350_SLAVE_SPSS_CFG 99 +#define SM8350_SLAVE_TCSR 100 +#define SM8350_SLAVE_TLMM 101 +#define SM8350_SLAVE_UFS_CARD_CFG 102 +#define SM8350_SLAVE_UFS_MEM_CFG 103 +#define SM8350_SLAVE_USB3_0 104 +#define SM8350_SLAVE_USB3_1 105 +#define SM8350_SLAVE_VENUS_CFG 106 +#define SM8350_SLAVE_VSENSE_CTRL_CFG 107 +#define SM8350_SLAVE_A1NOC_CFG 108 +#define SM8350_SLAVE_A1NOC_SNOC 109 +#define SM8350_SLAVE_A2NOC_CFG 110 +#define SM8350_SLAVE_A2NOC_SNOC 111 +#define SM8350_SLAVE_DDRSS_CFG 112 +#define SM8350_SLAVE_GEM_NOC_CNOC 113 +#define SM8350_SLAVE_GEM_NOC_CFG 114 +#define SM8350_SLAVE_SNOC_GEM_NOC_GC 115 +#define SM8350_SLAVE_SNOC_GEM_NOC_SF 116 +#define SM8350_SLAVE_LLCC 117 +#define SM8350_SLAVE_MNOC_HF_MEM_NOC 118 +#define SM8350_SLAVE_MNOC_SF_MEM_NOC 119 +#define SM8350_SLAVE_CNOC_MNOC_CFG 120 +#define SM8350_SLAVE_CDSP_MEM_NOC 121 +#define SM8350_SLAVE_MEM_NOC_PCIE_SNOC 122 +#define SM8350_SLAVE_ANOC_PCIE_GEM_NOC 123 +#define SM8350_SLAVE_SNOC_CFG 124 +#define SM8350_SLAVE_QUP_CORE_0 125 +#define SM8350_SLAVE_QUP_CORE_1 126 +#define SM8350_SLAVE_QUP_CORE_2 127 +#define SM8350_SLAVE_BOOT_IMEM 128 +#define SM8350_SLAVE_IMEM 129 +#define SM8350_SLAVE_PIMEM 130 +#define SM8350_SLAVE_SERVICE_NSP_NOC 131 +#define SM8350_SLAVE_SERVICE_A1NOC 132 +#define SM8350_SLAVE_SERVICE_A2NOC 133 +#define SM8350_SLAVE_SERVICE_CNOC 134 +#define SM8350_SLAVE_SERVICE_GEM_NOC_1 135 +#define SM8350_SLAVE_SERVICE_MNOC 136 +#define SM8350_SLAVE_SERVICES_LPASS_AML_NOC 137 +#define SM8350_SLAVE_SERVICE_LPASS_AG_NOC 138 +#define SM8350_SLAVE_SERVICE_GEM_NOC_2 139 +#define SM8350_SLAVE_SERVICE_SNOC 140 +#define SM8350_SLAVE_SERVICE_GEM_NOC 141 +#define SM8350_SLAVE_PCIE_0 142 +#define SM8350_SLAVE_PCIE_1 143 +#define SM8350_SLAVE_QDSS_STM 144 +#define SM8350_SLAVE_TCU 145 +#define SM8350_MASTER_LLCC_DISP 146 +#define SM8350_MASTER_MNOC_HF_MEM_NOC_DISP 147 +#define SM8350_MASTER_MNOC_SF_MEM_NOC_DISP 148 +#define SM8350_MASTER_MDP0_DISP 149 +#define SM8350_MASTER_MDP1_DISP 150 +#define SM8350_MASTER_ROTATOR_DISP 151 +#define SM8350_SLAVE_EBI1_DISP 152 +#define SM8350_SLAVE_LLCC_DISP 153 +#define SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP 154 +#define SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP 155 + +#endif diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 18494b03a6f39b2fef1799fd35e1178f18262676..41c4f55087791b45f09c545f15e0b0e1551e8556 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -279,8 +279,13 @@ config XTENSA_MX select GENERIC_IRQ_EFFECTIVE_AFF_MASK config XILINX_INTC - bool + bool "Xilinx Interrupt Controller IP" + depends on MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP select IRQ_DOMAIN + help + Support for the Xilinx Interrupt Controller IP core. + This is used as a primary controller with MicroBlaze and can also + be used as a secondary chained controller on other platforms. config IRQ_CROSSBAR bool @@ -579,4 +584,23 @@ config MST_IRQ help Support MStar Interrupt Controller. +config WPCM450_AIC + bool "Nuvoton WPCM450 Advanced Interrupt Controller" + depends on ARCH_WPCM450 + help + Support for the interrupt controller in the Nuvoton WPCM450 BMC SoC. + +config IRQ_IDT3243X + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + +config APPLE_AIC + bool "Apple Interrupt Controller (AIC)" + depends on ARM64 + default ARCH_APPLE + help + Support for the Apple Interrupt Controller found on Apple Silicon SoCs, + such as the M1. + endmenu diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c59b95a0532c9af77c4bf5bf489074ec4ef35dc7..f88cbf36a9d28d5f836d71351dab8676690fc89a 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -113,3 +113,6 @@ obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-loongson-pch-msi.o obj-$(CONFIG_MST_IRQ) += irq-mst-intc.o obj-$(CONFIG_SL28CPLD_INTC) += irq-sl28cpld.o obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o +obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o +obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o +obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c new file mode 100644 index 0000000000000000000000000000000000000000..c179e27062fd52baffb2edca3bac25bd2e2ab349 --- /dev/null +++ b/drivers/irqchip/irq-apple-aic.c @@ -0,0 +1,852 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright The Asahi Linux Contributors + * + * Based on irq-lpc32xx: + * Copyright 2015-2016 Vladimir Zapolskiy <vz@mleia.com> + * Based on irq-bcm2836: + * Copyright 2015 Broadcom + */ + +/* + * AIC is a fairly simple interrupt controller with the following features: + * + * - 896 level-triggered hardware IRQs + * - Single mask bit per IRQ + * - Per-IRQ affinity setting + * - Automatic masking on event delivery (auto-ack) + * - Software triggering (ORed with hw line) + * - 2 per-CPU IPIs (meant as "self" and "other", but they are + * interchangeable if not symmetric) + * - Automatic prioritization (single event/ack register per CPU, lower IRQs = + * higher priority) + * - Automatic masking on ack + * - Default "this CPU" register view and explicit per-CPU views + * + * In addition, this driver also handles FIQs, as these are routed to the same + * IRQ vector. These are used for Fast IPIs (TODO), the ARMv8 timer IRQs, and + * performance counters (TODO). + * + * Implementation notes: + * + * - This driver creates two IRQ domains, one for HW IRQs and internal FIQs, + * and one for IPIs. + * - Since Linux needs more than 2 IPIs, we implement a software IRQ controller + * and funnel all IPIs into one per-CPU IPI (the second "self" IPI is unused). + * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu. + * - DT bindings use 3-cell form (like GIC): + * - <0 nr flags> - hwirq #nr + * - <1 nr flags> - FIQ #nr + * - nr=0 Physical HV timer + * - nr=1 Virtual HV timer + * - nr=2 Physical guest timer + * - nr=3 Virtual guest timer + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/cpuhotplug.h> +#include <linux/io.h> +#include <linux/irqchip.h> +#include <linux/irqdomain.h> +#include <linux/limits.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <asm/exception.h> +#include <asm/sysreg.h> +#include <asm/virt.h> + +#include <dt-bindings/interrupt-controller/apple-aic.h> + +/* + * AIC registers (MMIO) + */ + +#define AIC_INFO 0x0004 +#define AIC_INFO_NR_HW GENMASK(15, 0) + +#define AIC_CONFIG 0x0010 + +#define AIC_WHOAMI 0x2000 +#define AIC_EVENT 0x2004 +#define AIC_EVENT_TYPE GENMASK(31, 16) +#define AIC_EVENT_NUM GENMASK(15, 0) + +#define AIC_EVENT_TYPE_HW 1 +#define AIC_EVENT_TYPE_IPI 4 +#define AIC_EVENT_IPI_OTHER 1 +#define AIC_EVENT_IPI_SELF 2 + +#define AIC_IPI_SEND 0x2008 +#define AIC_IPI_ACK 0x200c +#define AIC_IPI_MASK_SET 0x2024 +#define AIC_IPI_MASK_CLR 0x2028 + +#define AIC_IPI_SEND_CPU(cpu) BIT(cpu) + +#define AIC_IPI_OTHER BIT(0) +#define AIC_IPI_SELF BIT(31) + +#define AIC_TARGET_CPU 0x3000 +#define AIC_SW_SET 0x4000 +#define AIC_SW_CLR 0x4080 +#define AIC_MASK_SET 0x4100 +#define AIC_MASK_CLR 0x4180 + +#define AIC_CPU_IPI_SET(cpu) (0x5008 + ((cpu) << 7)) +#define AIC_CPU_IPI_CLR(cpu) (0x500c + ((cpu) << 7)) +#define AIC_CPU_IPI_MASK_SET(cpu) (0x5024 + ((cpu) << 7)) +#define AIC_CPU_IPI_MASK_CLR(cpu) (0x5028 + ((cpu) << 7)) + +#define MASK_REG(x) (4 * ((x) >> 5)) +#define MASK_BIT(x) BIT((x) & GENMASK(4, 0)) + +/* + * IMP-DEF sysregs that control FIQ sources + * Note: sysreg-based IPIs are not supported yet. + */ + +/* Core PMC control register */ +#define SYS_IMP_APL_PMCR0_EL1 sys_reg(3, 1, 15, 0, 0) +#define PMCR0_IMODE GENMASK(10, 8) +#define PMCR0_IMODE_OFF 0 +#define PMCR0_IMODE_PMI 1 +#define PMCR0_IMODE_AIC 2 +#define PMCR0_IMODE_HALT 3 +#define PMCR0_IMODE_FIQ 4 +#define PMCR0_IACT BIT(11) + +/* IPI request registers */ +#define SYS_IMP_APL_IPI_RR_LOCAL_EL1 sys_reg(3, 5, 15, 0, 0) +#define SYS_IMP_APL_IPI_RR_GLOBAL_EL1 sys_reg(3, 5, 15, 0, 1) +#define IPI_RR_CPU GENMASK(7, 0) +/* Cluster only used for the GLOBAL register */ +#define IPI_RR_CLUSTER GENMASK(23, 16) +#define IPI_RR_TYPE GENMASK(29, 28) +#define IPI_RR_IMMEDIATE 0 +#define IPI_RR_RETRACT 1 +#define IPI_RR_DEFERRED 2 +#define IPI_RR_NOWAKE 3 + +/* IPI status register */ +#define SYS_IMP_APL_IPI_SR_EL1 sys_reg(3, 5, 15, 1, 1) +#define IPI_SR_PENDING BIT(0) + +/* Guest timer FIQ enable register */ +#define SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 sys_reg(3, 5, 15, 1, 3) +#define VM_TMR_FIQ_ENABLE_V BIT(0) +#define VM_TMR_FIQ_ENABLE_P BIT(1) + +/* Deferred IPI countdown register */ +#define SYS_IMP_APL_IPI_CR_EL1 sys_reg(3, 5, 15, 3, 1) + +/* Uncore PMC control register */ +#define SYS_IMP_APL_UPMCR0_EL1 sys_reg(3, 7, 15, 0, 4) +#define UPMCR0_IMODE GENMASK(18, 16) +#define UPMCR0_IMODE_OFF 0 +#define UPMCR0_IMODE_AIC 2 +#define UPMCR0_IMODE_HALT 3 +#define UPMCR0_IMODE_FIQ 4 + +/* Uncore PMC status register */ +#define SYS_IMP_APL_UPMSR_EL1 sys_reg(3, 7, 15, 6, 4) +#define UPMSR_IACT BIT(0) + +#define AIC_NR_FIQ 4 +#define AIC_NR_SWIPI 32 + +/* + * FIQ hwirq index definitions: FIQ sources use the DT binding defines + * directly, except that timers are special. At the irqchip level, the + * two timer types are represented by their access method: _EL0 registers + * or _EL02 registers. In the DT binding, the timers are represented + * by their purpose (HV or guest). This mapping is for when the kernel is + * running at EL2 (with VHE). When the kernel is running at EL1, the + * mapping differs and aic_irq_domain_translate() performs the remapping. + */ + +#define AIC_TMR_EL0_PHYS AIC_TMR_HV_PHYS +#define AIC_TMR_EL0_VIRT AIC_TMR_HV_VIRT +#define AIC_TMR_EL02_PHYS AIC_TMR_GUEST_PHYS +#define AIC_TMR_EL02_VIRT AIC_TMR_GUEST_VIRT + +struct aic_irq_chip { + void __iomem *base; + struct irq_domain *hw_domain; + struct irq_domain *ipi_domain; + int nr_hw; + int ipi_hwirq; +}; + +static DEFINE_PER_CPU(uint32_t, aic_fiq_unmasked); + +static DEFINE_PER_CPU(atomic_t, aic_vipi_flag); +static DEFINE_PER_CPU(atomic_t, aic_vipi_enable); + +static struct aic_irq_chip *aic_irqc; + +static void aic_handle_ipi(struct pt_regs *regs); + +static u32 aic_ic_read(struct aic_irq_chip *ic, u32 reg) +{ + return readl_relaxed(ic->base + reg); +} + +static void aic_ic_write(struct aic_irq_chip *ic, u32 reg, u32 val) +{ + writel_relaxed(val, ic->base + reg); +} + +/* + * IRQ irqchip + */ + +static void aic_irq_mask(struct irq_data *d) +{ + struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d); + + aic_ic_write(ic, AIC_MASK_SET + MASK_REG(irqd_to_hwirq(d)), + MASK_BIT(irqd_to_hwirq(d))); +} + +static void aic_irq_unmask(struct irq_data *d) +{ + struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d); + + aic_ic_write(ic, AIC_MASK_CLR + MASK_REG(d->hwirq), + MASK_BIT(irqd_to_hwirq(d))); +} + +static void aic_irq_eoi(struct irq_data *d) +{ + /* + * Reading the interrupt reason automatically acknowledges and masks + * the IRQ, so we just unmask it here if needed. + */ + if (!irqd_irq_disabled(d) && !irqd_irq_masked(d)) + aic_irq_unmask(d); +} + +static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs) +{ + struct aic_irq_chip *ic = aic_irqc; + u32 event, type, irq; + + do { + /* + * We cannot use a relaxed read here, as reads from DMA buffers + * need to be ordered after the IRQ fires. + */ + event = readl(ic->base + AIC_EVENT); + type = FIELD_GET(AIC_EVENT_TYPE, event); + irq = FIELD_GET(AIC_EVENT_NUM, event); + + if (type == AIC_EVENT_TYPE_HW) + handle_domain_irq(aic_irqc->hw_domain, irq, regs); + else if (type == AIC_EVENT_TYPE_IPI && irq == 1) + aic_handle_ipi(regs); + else if (event != 0) + pr_err_ratelimited("Unknown IRQ event %d, %d\n", type, irq); + } while (event); + + /* + * vGIC maintenance interrupts end up here too, so we need to check + * for them separately. This should never trigger if KVM is working + * properly, because it will have already taken care of clearing it + * on guest exit before this handler runs. + */ + if (is_kernel_in_hyp_mode() && (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) && + read_sysreg_s(SYS_ICH_MISR_EL2) != 0) { + pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n"); + sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0); + } +} + +static int aic_irq_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, bool force) +{ + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d); + int cpu; + + if (force) + cpu = cpumask_first(mask_val); + else + cpu = cpumask_any_and(mask_val, cpu_online_mask); + + aic_ic_write(ic, AIC_TARGET_CPU + hwirq * 4, BIT(cpu)); + irq_data_update_effective_affinity(d, cpumask_of(cpu)); + + return IRQ_SET_MASK_OK; +} + +static int aic_irq_set_type(struct irq_data *d, unsigned int type) +{ + /* + * Some IRQs (e.g. MSIs) implicitly have edge semantics, and we don't + * have a way to find out the type of any given IRQ, so just allow both. + */ + return (type == IRQ_TYPE_LEVEL_HIGH || type == IRQ_TYPE_EDGE_RISING) ? 0 : -EINVAL; +} + +static struct irq_chip aic_chip = { + .name = "AIC", + .irq_mask = aic_irq_mask, + .irq_unmask = aic_irq_unmask, + .irq_eoi = aic_irq_eoi, + .irq_set_affinity = aic_irq_set_affinity, + .irq_set_type = aic_irq_set_type, +}; + +/* + * FIQ irqchip + */ + +static unsigned long aic_fiq_get_idx(struct irq_data *d) +{ + struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d); + + return irqd_to_hwirq(d) - ic->nr_hw; +} + +static void aic_fiq_set_mask(struct irq_data *d) +{ + /* Only the guest timers have real mask bits, unfortunately. */ + switch (aic_fiq_get_idx(d)) { + case AIC_TMR_EL02_PHYS: + sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENABLE_P, 0); + isb(); + break; + case AIC_TMR_EL02_VIRT: + sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENABLE_V, 0); + isb(); + break; + default: + break; + } +} + +static void aic_fiq_clear_mask(struct irq_data *d) +{ + switch (aic_fiq_get_idx(d)) { + case AIC_TMR_EL02_PHYS: + sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, 0, VM_TMR_FIQ_ENABLE_P); + isb(); + break; + case AIC_TMR_EL02_VIRT: + sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, 0, VM_TMR_FIQ_ENABLE_V); + isb(); + break; + default: + break; + } +} + +static void aic_fiq_mask(struct irq_data *d) +{ + aic_fiq_set_mask(d); + __this_cpu_and(aic_fiq_unmasked, ~BIT(aic_fiq_get_idx(d))); +} + +static void aic_fiq_unmask(struct irq_data *d) +{ + aic_fiq_clear_mask(d); + __this_cpu_or(aic_fiq_unmasked, BIT(aic_fiq_get_idx(d))); +} + +static void aic_fiq_eoi(struct irq_data *d) +{ + /* We mask to ack (where we can), so we need to unmask at EOI. */ + if (__this_cpu_read(aic_fiq_unmasked) & BIT(aic_fiq_get_idx(d))) + aic_fiq_clear_mask(d); +} + +#define TIMER_FIRING(x) \ + (((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK | \ + ARCH_TIMER_CTRL_IT_STAT)) == \ + (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT)) + +static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs) +{ + /* + * It would be really nice if we had a system register that lets us get + * the FIQ source state without having to peek down into sources... + * but such a register does not seem to exist. + * + * So, we have these potential sources to test for: + * - Fast IPIs (not yet used) + * - The 4 timers (CNTP, CNTV for each of HV and guest) + * - Per-core PMCs (not yet supported) + * - Per-cluster uncore PMCs (not yet supported) + * + * Since not dealing with any of these results in a FIQ storm, + * we check for everything here, even things we don't support yet. + */ + + if (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) { + pr_err_ratelimited("Fast IPI fired. Acking.\n"); + write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); + } + + if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) + handle_domain_irq(aic_irqc->hw_domain, + aic_irqc->nr_hw + AIC_TMR_EL0_PHYS, regs); + + if (TIMER_FIRING(read_sysreg(cntv_ctl_el0))) + handle_domain_irq(aic_irqc->hw_domain, + aic_irqc->nr_hw + AIC_TMR_EL0_VIRT, regs); + + if (is_kernel_in_hyp_mode()) { + uint64_t enabled = read_sysreg_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2); + + if ((enabled & VM_TMR_FIQ_ENABLE_P) && + TIMER_FIRING(read_sysreg_s(SYS_CNTP_CTL_EL02))) + handle_domain_irq(aic_irqc->hw_domain, + aic_irqc->nr_hw + AIC_TMR_EL02_PHYS, regs); + + if ((enabled & VM_TMR_FIQ_ENABLE_V) && + TIMER_FIRING(read_sysreg_s(SYS_CNTV_CTL_EL02))) + handle_domain_irq(aic_irqc->hw_domain, + aic_irqc->nr_hw + AIC_TMR_EL02_VIRT, regs); + } + + if ((read_sysreg_s(SYS_IMP_APL_PMCR0_EL1) & (PMCR0_IMODE | PMCR0_IACT)) == + (FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_FIQ) | PMCR0_IACT)) { + /* + * Not supported yet, let's figure out how to handle this when + * we implement these proprietary performance counters. For now, + * just mask it and move on. + */ + pr_err_ratelimited("PMC FIQ fired. Masking.\n"); + sysreg_clear_set_s(SYS_IMP_APL_PMCR0_EL1, PMCR0_IMODE | PMCR0_IACT, + FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF)); + } + + if (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ && + (read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) { + /* Same story with uncore PMCs */ + pr_err_ratelimited("Uncore PMC FIQ fired. Masking.\n"); + sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, + FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF)); + } +} + +static int aic_fiq_set_type(struct irq_data *d, unsigned int type) +{ + return (type == IRQ_TYPE_LEVEL_HIGH) ? 0 : -EINVAL; +} + +static struct irq_chip fiq_chip = { + .name = "AIC-FIQ", + .irq_mask = aic_fiq_mask, + .irq_unmask = aic_fiq_unmask, + .irq_ack = aic_fiq_set_mask, + .irq_eoi = aic_fiq_eoi, + .irq_set_type = aic_fiq_set_type, +}; + +/* + * Main IRQ domain + */ + +static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq, + irq_hw_number_t hw) +{ + struct aic_irq_chip *ic = id->host_data; + + if (hw < ic->nr_hw) { + irq_domain_set_info(id, irq, hw, &aic_chip, id->host_data, + handle_fasteoi_irq, NULL, NULL); + irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq))); + } else { + irq_set_percpu_devid(irq); + irq_domain_set_info(id, irq, hw, &fiq_chip, id->host_data, + handle_percpu_devid_irq, NULL, NULL); + } + + return 0; +} + +static int aic_irq_domain_translate(struct irq_domain *id, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + struct aic_irq_chip *ic = id->host_data; + + if (fwspec->param_count != 3 || !is_of_node(fwspec->fwnode)) + return -EINVAL; + + switch (fwspec->param[0]) { + case AIC_IRQ: + if (fwspec->param[1] >= ic->nr_hw) + return -EINVAL; + *hwirq = fwspec->param[1]; + break; + case AIC_FIQ: + if (fwspec->param[1] >= AIC_NR_FIQ) + return -EINVAL; + *hwirq = ic->nr_hw + fwspec->param[1]; + + /* + * In EL1 the non-redirected registers are the guest's, + * not EL2's, so remap the hwirqs to match. + */ + if (!is_kernel_in_hyp_mode()) { + switch (fwspec->param[1]) { + case AIC_TMR_GUEST_PHYS: + *hwirq = ic->nr_hw + AIC_TMR_EL0_PHYS; + break; + case AIC_TMR_GUEST_VIRT: + *hwirq = ic->nr_hw + AIC_TMR_EL0_VIRT; + break; + case AIC_TMR_HV_PHYS: + case AIC_TMR_HV_VIRT: + return -ENOENT; + default: + break; + } + } + break; + default: + return -EINVAL; + } + + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + +static int aic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + unsigned int type = IRQ_TYPE_NONE; + struct irq_fwspec *fwspec = arg; + irq_hw_number_t hwirq; + int i, ret; + + ret = aic_irq_domain_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + for (i = 0; i < nr_irqs; i++) { + ret = aic_irq_domain_map(domain, virq + i, hwirq + i); + if (ret) + return ret; + } + + return 0; +} + +static void aic_irq_domain_free(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + struct irq_data *d = irq_domain_get_irq_data(domain, virq + i); + + irq_set_handler(virq + i, NULL); + irq_domain_reset_irq_data(d); + } +} + +static const struct irq_domain_ops aic_irq_domain_ops = { + .translate = aic_irq_domain_translate, + .alloc = aic_irq_domain_alloc, + .free = aic_irq_domain_free, +}; + +/* + * IPI irqchip + */ + +static void aic_ipi_mask(struct irq_data *d) +{ + u32 irq_bit = BIT(irqd_to_hwirq(d)); + + /* No specific ordering requirements needed here. */ + atomic_andnot(irq_bit, this_cpu_ptr(&aic_vipi_enable)); +} + +static void aic_ipi_unmask(struct irq_data *d) +{ + struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d); + u32 irq_bit = BIT(irqd_to_hwirq(d)); + + atomic_or(irq_bit, this_cpu_ptr(&aic_vipi_enable)); + + /* + * The atomic_or() above must complete before the atomic_read() + * below to avoid racing aic_ipi_send_mask(). + */ + smp_mb__after_atomic(); + + /* + * If a pending vIPI was unmasked, raise a HW IPI to ourselves. + * No barriers needed here since this is a self-IPI. + */ + if (atomic_read(this_cpu_ptr(&aic_vipi_flag)) & irq_bit) + aic_ic_write(ic, AIC_IPI_SEND, AIC_IPI_SEND_CPU(smp_processor_id())); +} + +static void aic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) +{ + struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d); + u32 irq_bit = BIT(irqd_to_hwirq(d)); + u32 send = 0; + int cpu; + unsigned long pending; + + for_each_cpu(cpu, mask) { + /* + * This sequence is the mirror of the one in aic_ipi_unmask(); + * see the comment there. Additionally, release semantics + * ensure that the vIPI flag set is ordered after any shared + * memory accesses that precede it. This therefore also pairs + * with the atomic_fetch_andnot in aic_handle_ipi(). + */ + pending = atomic_fetch_or_release(irq_bit, per_cpu_ptr(&aic_vipi_flag, cpu)); + + /* + * The atomic_fetch_or_release() above must complete before the + * atomic_read() below to avoid racing aic_ipi_unmask(). + */ + smp_mb__after_atomic(); + + if (!(pending & irq_bit) && + (atomic_read(per_cpu_ptr(&aic_vipi_enable, cpu)) & irq_bit)) + send |= AIC_IPI_SEND_CPU(cpu); + } + + /* + * The flag writes must complete before the physical IPI is issued + * to another CPU. This is implied by the control dependency on + * the result of atomic_read_acquire() above, which is itself + * already ordered after the vIPI flag write. + */ + if (send) + aic_ic_write(ic, AIC_IPI_SEND, send); +} + +static struct irq_chip ipi_chip = { + .name = "AIC-IPI", + .irq_mask = aic_ipi_mask, + .irq_unmask = aic_ipi_unmask, + .ipi_send_mask = aic_ipi_send_mask, +}; + +/* + * IPI IRQ domain + */ + +static void aic_handle_ipi(struct pt_regs *regs) +{ + int i; + unsigned long enabled, firing; + + /* + * Ack the IPI. We need to order this after the AIC event read, but + * that is enforced by normal MMIO ordering guarantees. + */ + aic_ic_write(aic_irqc, AIC_IPI_ACK, AIC_IPI_OTHER); + + /* + * The mask read does not need to be ordered. Only we can change + * our own mask anyway, so no races are possible here, as long as + * we are properly in the interrupt handler (which is covered by + * the barrier that is part of the top-level AIC handler's readl()). + */ + enabled = atomic_read(this_cpu_ptr(&aic_vipi_enable)); + + /* + * Clear the IPIs we are about to handle. This pairs with the + * atomic_fetch_or_release() in aic_ipi_send_mask(), and needs to be + * ordered after the aic_ic_write() above (to avoid dropping vIPIs) and + * before IPI handling code (to avoid races handling vIPIs before they + * are signaled). The former is taken care of by the release semantics + * of the write portion, while the latter is taken care of by the + * acquire semantics of the read portion. + */ + firing = atomic_fetch_andnot(enabled, this_cpu_ptr(&aic_vipi_flag)) & enabled; + + for_each_set_bit(i, &firing, AIC_NR_SWIPI) + handle_domain_irq(aic_irqc->ipi_domain, i, regs); + + /* + * No ordering needed here; at worst this just changes the timing of + * when the next IPI will be delivered. + */ + aic_ic_write(aic_irqc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER); +} + +static int aic_ipi_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *args) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_set_percpu_devid(virq + i); + irq_domain_set_info(d, virq + i, i, &ipi_chip, d->host_data, + handle_percpu_devid_irq, NULL, NULL); + } + + return 0; +} + +static void aic_ipi_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) +{ + /* Not freeing IPIs */ +} + +static const struct irq_domain_ops aic_ipi_domain_ops = { + .alloc = aic_ipi_alloc, + .free = aic_ipi_free, +}; + +static int aic_init_smp(struct aic_irq_chip *irqc, struct device_node *node) +{ + struct irq_domain *ipi_domain; + int base_ipi; + + ipi_domain = irq_domain_create_linear(irqc->hw_domain->fwnode, AIC_NR_SWIPI, + &aic_ipi_domain_ops, irqc); + if (WARN_ON(!ipi_domain)) + return -ENODEV; + + ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE; + irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI); + + base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, AIC_NR_SWIPI, + NUMA_NO_NODE, NULL, false, NULL); + + if (WARN_ON(!base_ipi)) { + irq_domain_remove(ipi_domain); + return -ENODEV; + } + + set_smp_ipi_range(base_ipi, AIC_NR_SWIPI); + + irqc->ipi_domain = ipi_domain; + + return 0; +} + +static int aic_init_cpu(unsigned int cpu) +{ + /* Mask all hard-wired per-CPU IRQ/FIQ sources */ + + /* Pending Fast IPI FIQs */ + write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); + + /* Timer FIQs */ + sysreg_clear_set(cntp_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK); + sysreg_clear_set(cntv_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK); + + /* EL2-only (VHE mode) IRQ sources */ + if (is_kernel_in_hyp_mode()) { + /* Guest timers */ + sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, + VM_TMR_FIQ_ENABLE_V | VM_TMR_FIQ_ENABLE_P, 0); + + /* vGIC maintenance IRQ */ + sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0); + } + + /* PMC FIQ */ + sysreg_clear_set_s(SYS_IMP_APL_PMCR0_EL1, PMCR0_IMODE | PMCR0_IACT, + FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF)); + + /* Uncore PMC FIQ */ + sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, + FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF)); + + /* Commit all of the above */ + isb(); + + /* + * Make sure the kernel's idea of logical CPU order is the same as AIC's + * If we ever end up with a mismatch here, we will have to introduce + * a mapping table similar to what other irqchip drivers do. + */ + WARN_ON(aic_ic_read(aic_irqc, AIC_WHOAMI) != smp_processor_id()); + + /* + * Always keep IPIs unmasked at the hardware level (except auto-masking + * by AIC during processing). We manage masks at the vIPI level. + */ + aic_ic_write(aic_irqc, AIC_IPI_ACK, AIC_IPI_SELF | AIC_IPI_OTHER); + aic_ic_write(aic_irqc, AIC_IPI_MASK_SET, AIC_IPI_SELF); + aic_ic_write(aic_irqc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER); + + /* Initialize the local mask state */ + __this_cpu_write(aic_fiq_unmasked, 0); + + return 0; +} + +static int __init aic_of_ic_init(struct device_node *node, struct device_node *parent) +{ + int i; + void __iomem *regs; + u32 info; + struct aic_irq_chip *irqc; + + regs = of_iomap(node, 0); + if (WARN_ON(!regs)) + return -EIO; + + irqc = kzalloc(sizeof(*irqc), GFP_KERNEL); + if (!irqc) + return -ENOMEM; + + aic_irqc = irqc; + irqc->base = regs; + + info = aic_ic_read(irqc, AIC_INFO); + irqc->nr_hw = FIELD_GET(AIC_INFO_NR_HW, info); + + irqc->hw_domain = irq_domain_create_linear(of_node_to_fwnode(node), + irqc->nr_hw + AIC_NR_FIQ, + &aic_irq_domain_ops, irqc); + if (WARN_ON(!irqc->hw_domain)) { + iounmap(irqc->base); + kfree(irqc); + return -ENODEV; + } + + irq_domain_update_bus_token(irqc->hw_domain, DOMAIN_BUS_WIRED); + + if (aic_init_smp(irqc, node)) { + irq_domain_remove(irqc->hw_domain); + iounmap(irqc->base); + kfree(irqc); + return -ENODEV; + } + + set_handle_irq(aic_handle_irq); + set_handle_fiq(aic_handle_fiq); + + for (i = 0; i < BITS_TO_U32(irqc->nr_hw); i++) + aic_ic_write(irqc, AIC_MASK_SET + i * 4, U32_MAX); + for (i = 0; i < BITS_TO_U32(irqc->nr_hw); i++) + aic_ic_write(irqc, AIC_SW_CLR + i * 4, U32_MAX); + for (i = 0; i < irqc->nr_hw; i++) + aic_ic_write(irqc, AIC_TARGET_CPU + i * 4, 1); + + if (!is_kernel_in_hyp_mode()) + pr_info("Kernel running in EL1, mapping interrupts"); + + cpuhp_setup_state(CPUHP_AP_IRQ_APPLE_AIC_STARTING, + "irqchip/apple-aic/ipi:starting", + aic_init_cpu, NULL); + + pr_info("Initialized with %d IRQs, %d FIQs, %d vIPIs\n", + irqc->nr_hw, AIC_NR_FIQ, AIC_NR_SWIPI); + + return 0; +} + +IRQCHIP_DECLARE(apple_m1_aic, "apple,aic", aic_of_ic_init); diff --git a/drivers/irqchip/irq-aspeed-vic.c b/drivers/irqchip/irq-aspeed-vic.c index 6567ed782f82c95ae08c470b5f9c01ba78806c16..58717cd44f99f1545fab75a56bb4fecad43f1906 100644 --- a/drivers/irqchip/irq-aspeed-vic.c +++ b/drivers/irqchip/irq-aspeed-vic.c @@ -71,7 +71,7 @@ static void vic_init_hw(struct aspeed_vic *vic) writel(0, vic->base + AVIC_INT_SELECT); writel(0, vic->base + AVIC_INT_SELECT + 4); - /* Some interrupts have a programable high/low level trigger + /* Some interrupts have a programmable high/low level trigger * (4 GPIO direct inputs), for now we assume this was configured * by firmware. We read which ones are edge now. */ @@ -203,7 +203,7 @@ static int __init avic_of_init(struct device_node *node, } vic->base = regs; - /* Initialize soures, all masked */ + /* Initialize sources, all masked */ vic_init_hw(vic); /* Ready to receive interrupts */ diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index c7c9e976acbb9f06e32cb8246a0bfda05073f122..ad59656ccc282871f8f31cc05cf3f83c803801e7 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -309,7 +309,7 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn, if (data->can_wake) { /* This IRQ chip can wake the system, set all - * relevant child interupts in wake_enabled mask + * relevant child interrupts in wake_enabled mask */ gc->wake_enabled = 0xffffffff; gc->wake_enabled &= ~gc->unused; diff --git a/drivers/irqchip/irq-csky-apb-intc.c b/drivers/irqchip/irq-csky-apb-intc.c index 5a2ec43b7ddd49311be11d71fd8dc998e926934e..ab91afa867557bf9c13221091ef185d66f2b12c3 100644 --- a/drivers/irqchip/irq-csky-apb-intc.c +++ b/drivers/irqchip/irq-csky-apb-intc.c @@ -176,7 +176,7 @@ gx_intc_init(struct device_node *node, struct device_node *parent) writel(0x0, reg_base + GX_INTC_NEN63_32); /* - * Initial mask reg with all unmasked, because we only use enalbe reg + * Initial mask reg with all unmasked, because we only use enable reg */ writel(0x0, reg_base + GX_INTC_NMASK31_00); writel(0x0, reg_base + GX_INTC_NMASK63_32); diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index fbec07d634ad28855d870d97ec51e51e100e3ffe..4116b48e60aff8710ccf7e4472c6a6e79a4f0724 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -371,7 +371,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, * the MSI data is the absolute value within the range from * spi_start to (spi_start + num_spis). * - * Broadom NS2 GICv2m implementation has an erratum where the MSI data + * Broadcom NS2 GICv2m implementation has an erratum where the MSI data * is 'spi_number - 32' * * Reading that register fails on the Graviton implementation diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index ed46e6057e3350fbc31cb381270010b1d56ee746..c3485b230d70ea7e90d5dfbb7523fa3f33625b49 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1492,7 +1492,7 @@ static void its_vlpi_set_doorbell(struct irq_data *d, bool enable) * * Ideally, we'd issue a VMAPTI to set the doorbell to its LPI * value or to 1023, depending on the enable bit. But that - * would be issueing a mapping for an /existing/ DevID+EventID + * would be issuing a mapping for an /existing/ DevID+EventID * pair, which is UNPREDICTABLE. Instead, let's issue a VMOVI * to the /same/ vPE, using this opportunity to adjust the * doorbell. Mouahahahaha. We loves it, Precious. @@ -3122,7 +3122,7 @@ static void its_cpu_init_lpis(void) /* * It's possible for CPU to receive VLPIs before it is - * sheduled as a vPE, especially for the first CPU, and the + * scheduled as a vPE, especially for the first CPU, and the * VLPI with INTID larger than 2^(IDbits+1) will be considered * as out of range and dropped by GIC. * So we initialize IDbits to known value to avoid VLPI drop. @@ -3616,7 +3616,7 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, /* * If all interrupts have been freed, start mopping the - * floor. This is conditionned on the device not being shared. + * floor. This is conditioned on the device not being shared. */ if (!its_dev->shared && bitmap_empty(its_dev->event_map.lpi_map, @@ -4194,7 +4194,7 @@ static int its_sgi_set_affinity(struct irq_data *d, { /* * There is no notion of affinity for virtual SGIs, at least - * not on the host (since they can only be targetting a vPE). + * not on the host (since they can only be targeting a vPE). * Tell the kernel we've done whatever it asked for. */ irq_data_update_effective_affinity(d, mask_val); @@ -4239,7 +4239,7 @@ static int its_sgi_get_irqchip_state(struct irq_data *d, /* * Locking galore! We can race against two different events: * - * - Concurent vPE affinity change: we must make sure it cannot + * - Concurrent vPE affinity change: we must make sure it cannot * happen, or we'll talk to the wrong redistributor. This is * identical to what happens with vLPIs. * diff --git a/drivers/irqchip/irq-gic-v3-mbi.c b/drivers/irqchip/irq-gic-v3-mbi.c index 563a9b36629415db6365d4baceb770b528c75b41..e81e89a81cb5bbdd29b05939570890bd93f21b75 100644 --- a/drivers/irqchip/irq-gic-v3-mbi.c +++ b/drivers/irqchip/irq-gic-v3-mbi.c @@ -303,7 +303,7 @@ int __init mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent) reg = of_get_property(np, "mbi-alias", NULL); if (reg) { mbi_phys_base = of_translate_address(np, reg); - if (mbi_phys_base == OF_BAD_ADDR) { + if (mbi_phys_base == (phys_addr_t)OF_BAD_ADDR) { ret = -ENXIO; goto err_free_mbi; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 26f19a682736d2160782aae8965a05d7a59b5d20..b5bae5d1681bada658d236026a644f1f360cdef9 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -654,6 +654,10 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs irqnr = gic_read_iar(); + /* Check for special IDs first */ + if ((irqnr >= 1020 && irqnr <= 1023)) + return; + if (gic_supports_nmi() && unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) { gic_handle_nmi(irqnr, regs); @@ -665,10 +669,6 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs gic_arch_enable_irqs(); } - /* Check for special IDs first */ - if ((irqnr >= 1020 && irqnr <= 1023)) - return; - if (static_branch_likely(&supports_deactivate_key)) gic_write_eoir(irqnr); else @@ -1411,7 +1411,7 @@ static int gic_irq_domain_translate(struct irq_domain *d, /* * Make it clear that broken DTs are... broken. - * Partitionned PPIs are an unfortunate exception. + * Partitioned PPIs are an unfortunate exception. */ WARN_ON(*type == IRQ_TYPE_NONE && fwspec->param[0] != GIC_IRQ_TYPE_PARTITION); diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c index 5d1dc9915272b1892459e5cd1c4de64c1b6b0c13..4ea71b28f9f5f21ec0c8979bd91f07bf215c75cf 100644 --- a/drivers/irqchip/irq-gic-v4.c +++ b/drivers/irqchip/irq-gic-v4.c @@ -87,17 +87,40 @@ static struct irq_domain *gic_domain; static const struct irq_domain_ops *vpe_domain_ops; static const struct irq_domain_ops *sgi_domain_ops; +#ifdef CONFIG_ARM64 +#include <asm/cpufeature.h> + +bool gic_cpuif_has_vsgi(void) +{ + unsigned long fld, reg = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); + + fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_GIC_SHIFT); + + return fld >= 0x3; +} +#else +bool gic_cpuif_has_vsgi(void) +{ + return false; +} +#endif + static bool has_v4_1(void) { return !!sgi_domain_ops; } +static bool has_v4_1_sgi(void) +{ + return has_v4_1() && gic_cpuif_has_vsgi(); +} + static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx) { char *name; int sgi_base; - if (!has_v4_1()) + if (!has_v4_1_sgi()) return 0; name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current)); @@ -182,7 +205,7 @@ static void its_free_sgi_irqs(struct its_vm *vm) { int i; - if (!has_v4_1()) + if (!has_v4_1_sgi()) return; for (i = 0; i < vm->nr_vpes; i++) { diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index a6ed877d9dd39e88f137209fe309259bc2dab755..058ebaebe2c40e5d0c402f8c7068a5b9cc966e11 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Hisilicon HiP04 INTC + * HiSilicon HiP04 INTC * * Copyright (C) 2002-2014 ARM Limited. - * Copyright (c) 2013-2014 Hisilicon Ltd. + * Copyright (c) 2013-2014 HiSilicon Ltd. * Copyright (c) 2013-2014 Linaro Ltd. * * Interrupt architecture for the HIP04 INTC: diff --git a/drivers/irqchip/irq-idt3243x.c b/drivers/irqchip/irq-idt3243x.c new file mode 100644 index 0000000000000000000000000000000000000000..f0996820077a9fbab9c00c66f7782d9378aeb3aa --- /dev/null +++ b/drivers/irqchip/irq-idt3243x.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for IDT/Renesas 79RC3243x Interrupt Controller. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#define IDT_PIC_NR_IRQS 32 + +#define IDT_PIC_IRQ_PEND 0x00 +#define IDT_PIC_IRQ_MASK 0x08 + +struct idt_pic_data { + void __iomem *base; + struct irq_domain *irq_domain; + struct irq_chip_generic *gc; +}; + +static void idt_irq_dispatch(struct irq_desc *desc) +{ + struct idt_pic_data *idtpic = irq_desc_get_handler_data(desc); + struct irq_chip *host_chip = irq_desc_get_chip(desc); + u32 pending, hwirq, virq; + + chained_irq_enter(host_chip, desc); + + pending = irq_reg_readl(idtpic->gc, IDT_PIC_IRQ_PEND); + pending &= ~idtpic->gc->mask_cache; + while (pending) { + hwirq = __fls(pending); + virq = irq_linear_revmap(idtpic->irq_domain, hwirq); + if (virq) + generic_handle_irq(virq); + pending &= ~(1 << hwirq); + } + + chained_irq_exit(host_chip, desc); +} + +static int idt_pic_init(struct device_node *of_node, struct device_node *parent) +{ + struct irq_domain *domain; + struct idt_pic_data *idtpic; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + unsigned int parent_irq; + int ret = 0; + + idtpic = kzalloc(sizeof(*idtpic), GFP_KERNEL); + if (!idtpic) { + ret = -ENOMEM; + goto out_err; + } + + parent_irq = irq_of_parse_and_map(of_node, 0); + if (!parent_irq) { + pr_err("Failed to map parent IRQ!\n"); + ret = -EINVAL; + goto out_free; + } + + idtpic->base = of_iomap(of_node, 0); + if (!idtpic->base) { + pr_err("Failed to map base address!\n"); + ret = -ENOMEM; + goto out_unmap_irq; + } + + domain = irq_domain_add_linear(of_node, IDT_PIC_NR_IRQS, + &irq_generic_chip_ops, NULL); + if (!domain) { + pr_err("Failed to add irqdomain!\n"); + ret = -ENOMEM; + goto out_iounmap; + } + idtpic->irq_domain = domain; + + ret = irq_alloc_domain_generic_chips(domain, 32, 1, "IDTPIC", + handle_level_irq, 0, + IRQ_NOPROBE | IRQ_LEVEL, 0); + if (ret) + goto out_domain_remove; + + gc = irq_get_domain_generic_chip(domain, 0); + gc->reg_base = idtpic->base; + gc->private = idtpic; + + ct = gc->chip_types; + ct->regs.mask = IDT_PIC_IRQ_MASK; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + idtpic->gc = gc; + + /* Mask interrupts. */ + writel(0xffffffff, idtpic->base + IDT_PIC_IRQ_MASK); + gc->mask_cache = 0xffffffff; + + irq_set_chained_handler_and_data(parent_irq, + idt_irq_dispatch, idtpic); + + return 0; + +out_domain_remove: + irq_domain_remove(domain); +out_iounmap: + iounmap(idtpic->base); +out_unmap_irq: + irq_dispose_mapping(parent_irq); +out_free: + kfree(idtpic); +out_err: + pr_err("Failed to initialize! (errno = %d)\n", ret); + return ret; +} + +IRQCHIP_DECLARE(idt_pic, "idt,32434-pic", idt_pic_init); diff --git a/drivers/irqchip/irq-jcore-aic.c b/drivers/irqchip/irq-jcore-aic.c index 033bccb41455c46c32d5473fa46940c2770973e9..5f47d8ee4ae39e04964a461626b3138fadd11d18 100644 --- a/drivers/irqchip/irq-jcore-aic.c +++ b/drivers/irqchip/irq-jcore-aic.c @@ -100,11 +100,11 @@ static int __init aic_irq_of_init(struct device_node *node, jcore_aic.irq_unmask = noop; jcore_aic.name = "AIC"; - domain = irq_domain_add_linear(node, dom_sz, &jcore_aic_irqdomain_ops, + domain = irq_domain_add_legacy(node, dom_sz - min_irq, min_irq, min_irq, + &jcore_aic_irqdomain_ops, &jcore_aic); if (!domain) return -ENOMEM; - irq_create_strict_mappings(domain, min_irq, min_irq, dom_sz - min_irq); return 0; } diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index 9bf6b9a5f73485cec4942147a8707bf1ec7d0fcf..f790ca6d78aa4c534723a145931e6ece45933523 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -163,7 +163,7 @@ static void pch_pic_reset(struct pch_pic *priv) int i; for (i = 0; i < PIC_COUNT; i++) { - /* Write vectore ID */ + /* Write vectored ID */ writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i)); /* Hardcode route to HT0 Lo */ writeb(1, priv->base + PCH_INT_ROUTE(i)); diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c index ff7627b577726e6e887df1de1ef88137a5f5c4d0..2cb45c6b85011479cc25433b2b4662eaf883e453 100644 --- a/drivers/irqchip/irq-mbigen.c +++ b/drivers/irqchip/irq-mbigen.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved. + * Copyright (C) 2015 HiSilicon Limited, All Rights Reserved. * Author: Jun Ma <majun258@huawei.com> * Author: Yun Wu <wuyun.wu@huawei.com> */ @@ -390,4 +390,4 @@ module_platform_driver(mbigen_platform_driver); MODULE_AUTHOR("Jun Ma <majun258@huawei.com>"); MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Hisilicon MBI Generator driver"); +MODULE_DESCRIPTION("HiSilicon MBI Generator driver"); diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index e3b462bd39819660c4892c3be6de243844e5df2b..cfc5cf5224cbed2e73180580fa05be8743cd3f9d 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -229,7 +229,7 @@ meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl, /* * Get the hwirq number assigned to this channel through - * a pointer the channel_irq table. The added benifit of this + * a pointer the channel_irq table. The added benefit of this * method is that we can also retrieve the channel index with * it, using the table base. */ diff --git a/drivers/irqchip/irq-mst-intc.c b/drivers/irqchip/irq-mst-intc.c index 143657b0cf281aa57b0876d1c167a536ff419d7e..f6133ae28155667f064cecc1b108168d2d63fd3a 100644 --- a/drivers/irqchip/irq-mst-intc.c +++ b/drivers/irqchip/irq-mst-intc.c @@ -13,15 +13,27 @@ #include <linux/of_irq.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/syscore_ops.h> -#define INTC_MASK 0x0 -#define INTC_EOI 0x20 +#define MST_INTC_MAX_IRQS 64 + +#define INTC_MASK 0x0 +#define INTC_REV_POLARITY 0x10 +#define INTC_EOI 0x20 + +#ifdef CONFIG_PM_SLEEP +static LIST_HEAD(mst_intc_list); +#endif struct mst_intc_chip_data { raw_spinlock_t lock; unsigned int irq_start, nr_irqs; void __iomem *base; bool no_eoi; +#ifdef CONFIG_PM_SLEEP + struct list_head entry; + u16 saved_polarity_conf[DIV_ROUND_UP(MST_INTC_MAX_IRQS, 16)]; +#endif }; static void mst_set_irq(struct irq_data *d, u32 offset) @@ -78,6 +90,24 @@ static void mst_intc_eoi_irq(struct irq_data *d) irq_chip_eoi_parent(d); } +static int mst_irq_chip_set_type(struct irq_data *data, unsigned int type) +{ + switch (type) { + case IRQ_TYPE_LEVEL_LOW: + case IRQ_TYPE_EDGE_FALLING: + mst_set_irq(data, INTC_REV_POLARITY); + break; + case IRQ_TYPE_LEVEL_HIGH: + case IRQ_TYPE_EDGE_RISING: + mst_clear_irq(data, INTC_REV_POLARITY); + break; + default: + return -EINVAL; + } + + return irq_chip_set_type_parent(data, IRQ_TYPE_LEVEL_HIGH); +} + static struct irq_chip mst_intc_chip = { .name = "mst-intc", .irq_mask = mst_intc_mask_irq, @@ -87,13 +117,62 @@ static struct irq_chip mst_intc_chip = { .irq_set_irqchip_state = irq_chip_set_parent_state, .irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, - .irq_set_type = irq_chip_set_type_parent, + .irq_set_type = mst_irq_chip_set_type, .irq_retrigger = irq_chip_retrigger_hierarchy, .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, }; +#ifdef CONFIG_PM_SLEEP +static void mst_intc_polarity_save(struct mst_intc_chip_data *cd) +{ + int i; + void __iomem *addr = cd->base + INTC_REV_POLARITY; + + for (i = 0; i < DIV_ROUND_UP(cd->nr_irqs, 16); i++) + cd->saved_polarity_conf[i] = readw_relaxed(addr + i * 4); +} + +static void mst_intc_polarity_restore(struct mst_intc_chip_data *cd) +{ + int i; + void __iomem *addr = cd->base + INTC_REV_POLARITY; + + for (i = 0; i < DIV_ROUND_UP(cd->nr_irqs, 16); i++) + writew_relaxed(cd->saved_polarity_conf[i], addr + i * 4); +} + +static void mst_irq_resume(void) +{ + struct mst_intc_chip_data *cd; + + list_for_each_entry(cd, &mst_intc_list, entry) + mst_intc_polarity_restore(cd); +} + +static int mst_irq_suspend(void) +{ + struct mst_intc_chip_data *cd; + + list_for_each_entry(cd, &mst_intc_list, entry) + mst_intc_polarity_save(cd); + return 0; +} + +static struct syscore_ops mst_irq_syscore_ops = { + .suspend = mst_irq_suspend, + .resume = mst_irq_resume, +}; + +static int __init mst_irq_pm_init(void) +{ + register_syscore_ops(&mst_irq_syscore_ops); + return 0; +} +late_initcall(mst_irq_pm_init); +#endif + static int mst_intc_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, @@ -145,6 +224,15 @@ static int mst_intc_domain_alloc(struct irq_domain *domain, unsigned int virq, parent_fwspec = *fwspec; parent_fwspec.fwnode = domain->parent->fwnode; parent_fwspec.param[1] = cd->irq_start + hwirq; + + /* + * mst-intc latch the interrupt request if it's edge triggered, + * so the output signal to parent GIC is always level sensitive. + * And if the irq signal is active low, configure it to active high + * to meet GIC SPI spec in mst_irq_chip_set_type via REV_POLARITY bit. + */ + parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } @@ -193,6 +281,10 @@ static int __init mst_intc_of_init(struct device_node *dn, return -ENOMEM; } +#ifdef CONFIG_PM_SLEEP + INIT_LIST_HEAD(&cd->entry); + list_add_tail(&cd->entry, &mst_intc_list); +#endif return 0; } diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c index 69ba8ce3c17856be68c9330323f59acb00d55f78..9bca0918078e88cb242ec0d8f873dc9e25a15101 100644 --- a/drivers/irqchip/irq-mtk-cirq.c +++ b/drivers/irqchip/irq-mtk-cirq.c @@ -217,7 +217,7 @@ static void mtk_cirq_resume(void) { u32 value; - /* flush recored interrupts, will send signals to parent controller */ + /* flush recorded interrupts, will send signals to parent controller */ value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL); diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index a671938fd97f6fd25cb2055db3ee52d44c64a3cd..d1f5740cd5755cbc4858e9ff4dbd2d09e86f3eb1 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -58,7 +58,7 @@ struct icoll_priv { static struct icoll_priv icoll_priv; static struct irq_domain *icoll_domain; -/* calculate bit offset depending on number of intterupt per register */ +/* calculate bit offset depending on number of interrupt per register */ static u32 icoll_intr_bitshift(struct irq_data *d, u32 bit) { /* @@ -68,7 +68,7 @@ static u32 icoll_intr_bitshift(struct irq_data *d, u32 bit) return bit << ((d->hwirq & 3) << 3); } -/* calculate mem offset depending on number of intterupt per register */ +/* calculate mem offset depending on number of interrupt per register */ static void __iomem *icoll_intr_reg(struct irq_data *d) { /* offset = hwirq / intr_per_reg * 0x10 */ diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 6f432d2a5cebdc388f5c7d88e1c807f4d83fc28f..97d4d04b0a80eb57346227da018b2f5cdee8ccdc 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -77,8 +77,8 @@ struct plic_handler { void __iomem *enable_base; struct plic_priv *priv; }; -static int plic_parent_irq; -static bool plic_cpuhp_setup_done; +static int plic_parent_irq __ro_after_init; +static bool plic_cpuhp_setup_done __ro_after_init; static DEFINE_PER_CPU(struct plic_handler, plic_handlers); static inline void plic_toggle(struct plic_handler *handler, diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 8662d7b7b2625af83c70235569e8f5da6e603d5e..b9db90c4aa566f186622fe05b50c07b8bbc5e986 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -193,7 +193,14 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = { { .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct }, { .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct }, { .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct }, + { .exti = 26, .irq_parent = 37, .chip = &stm32_exti_h_chip_direct }, + { .exti = 27, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct }, + { .exti = 28, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct }, + { .exti = 29, .irq_parent = 71, .chip = &stm32_exti_h_chip_direct }, { .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct }, + { .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct }, + { .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct }, + { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct }, { .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct }, { .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct }, { .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct }, diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index fb78d6623556c15f065b2053275caa45b838673e..9ea94456b178ccce9fa39ae12d54f7ff50c10a60 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -189,7 +189,7 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) * 3) spurious irq * So if we immediately get a reading of 0, check the irq-pending reg * to differentiate between 2 and 3. We only do this once to avoid - * the extra check in the common case of 1 hapening after having + * the extra check in the common case of 1 happening after having * read the vector-reg once. */ hwirq = readl(irq_ic_data->irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index 9e456497c1c48a7ea2b2dce884e7733cff72edc3..9a63b02b817643991adbb86783263d14aeed4e49 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -60,6 +60,7 @@ static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type) break; case IRQ_TYPE_NONE: flow_type = IRQ_TYPE_LEVEL_LOW; + fallthrough; case IRQ_TYPE_LEVEL_LOW: mod ^= im; pol ^= im; diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index 532d0ae172d9f8f47b9ae7f398f7087a3c8f74be..ca1f593f4d13aa2fd39db911cb230d818fa365ec 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -78,7 +78,7 @@ struct ti_sci_inta_vint_desc { * struct ti_sci_inta_irq_domain - Structure representing a TISCI based * Interrupt Aggregator IRQ domain. * @sci: Pointer to TISCI handle - * @vint: TISCI resource pointer representing IA inerrupts. + * @vint: TISCI resource pointer representing IA interrupts. * @global_event: TISCI resource pointer representing global events. * @vint_list: List of the vints active in the system * @vint_mutex: Mutex to protect vint_list diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index e46036374227297ed9aa1185724df3a735d8bbec..62f3d29f90420e56674f79b10a8f78e1ce5acecd 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -163,7 +163,7 @@ static struct syscore_ops vic_syscore_ops = { }; /** - * vic_pm_init - initicall to register VIC pm + * vic_pm_init - initcall to register VIC pm * * This is called via late_initcall() to register * the resources for the VICs due to the early @@ -397,7 +397,7 @@ static void __init vic_clear_interrupts(void __iomem *base) /* * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. * The original cell has 32 interrupts, while the modified one has 64, - * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case + * replicating two blocks 0x00..0x1f in 0x20..0x3f. In that case * the probe function is called twice, with base set to offset 000 * and 020 within the page. We call this "second block". */ diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c new file mode 100644 index 0000000000000000000000000000000000000000..f3ac392d5bc87fd721aeb499e23653956073acf1 --- /dev/null +++ b/drivers/irqchip/irq-wpcm450-aic.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2021 Jonathan Neuschäfer + +#include <linux/irqchip.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/printk.h> + +#include <asm/exception.h> + +#define AIC_SCR(x) ((x)*4) /* Source control registers */ +#define AIC_GEN 0x84 /* Interrupt group enable control register */ +#define AIC_GRSR 0x88 /* Interrupt group raw status register */ +#define AIC_IRSR 0x100 /* Interrupt raw status register */ +#define AIC_IASR 0x104 /* Interrupt active status register */ +#define AIC_ISR 0x108 /* Interrupt status register */ +#define AIC_IPER 0x10c /* Interrupt priority encoding register */ +#define AIC_ISNR 0x110 /* Interrupt source number register */ +#define AIC_IMR 0x114 /* Interrupt mask register */ +#define AIC_OISR 0x118 /* Output interrupt status register */ +#define AIC_MECR 0x120 /* Mask enable command register */ +#define AIC_MDCR 0x124 /* Mask disable command register */ +#define AIC_SSCR 0x128 /* Source set command register */ +#define AIC_SCCR 0x12c /* Source clear command register */ +#define AIC_EOSCR 0x130 /* End of service command register */ + +#define AIC_SCR_SRCTYPE_LOW_LEVEL (0 << 6) +#define AIC_SCR_SRCTYPE_HIGH_LEVEL (1 << 6) +#define AIC_SCR_SRCTYPE_NEG_EDGE (2 << 6) +#define AIC_SCR_SRCTYPE_POS_EDGE (3 << 6) +#define AIC_SCR_PRIORITY(x) (x) +#define AIC_SCR_PRIORITY_MASK 0x7 + +#define AIC_NUM_IRQS 32 + +struct wpcm450_aic { + void __iomem *regs; + struct irq_domain *domain; +}; + +static struct wpcm450_aic *aic; + +static void wpcm450_aic_init_hw(void) +{ + int i; + + /* Disable (mask) all interrupts */ + writel(0xffffffff, aic->regs + AIC_MDCR); + + /* + * Make sure the interrupt controller is ready to serve new interrupts. + * Reading from IPER indicates that the nIRQ signal may be deasserted, + * and writing to EOSCR indicates that interrupt handling has finished. + */ + readl(aic->regs + AIC_IPER); + writel(0, aic->regs + AIC_EOSCR); + + /* Initialize trigger mode and priority of each interrupt source */ + for (i = 0; i < AIC_NUM_IRQS; i++) + writel(AIC_SCR_SRCTYPE_HIGH_LEVEL | AIC_SCR_PRIORITY(7), + aic->regs + AIC_SCR(i)); +} + +static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs) +{ + int hwirq; + + /* Determine the interrupt source */ + /* Read IPER to signal that nIRQ can be de-asserted */ + hwirq = readl(aic->regs + AIC_IPER) / 4; + + handle_domain_irq(aic->domain, hwirq, regs); +} + +static void wpcm450_aic_eoi(struct irq_data *d) +{ + /* Signal end-of-service */ + writel(0, aic->regs + AIC_EOSCR); +} + +static void wpcm450_aic_mask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + /* Disable (mask) the interrupt */ + writel(mask, aic->regs + AIC_MDCR); +} + +static void wpcm450_aic_unmask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + /* Enable (unmask) the interrupt */ + writel(mask, aic->regs + AIC_MECR); +} + +static int wpcm450_aic_set_type(struct irq_data *d, unsigned int flow_type) +{ + /* + * The hardware supports high/low level, as well as rising/falling edge + * modes, and the DT binding accommodates for that, but as long as + * other modes than high level mode are not used and can't be tested, + * they are rejected in this driver. + */ + if ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) + return -EINVAL; + + return 0; +} + +static struct irq_chip wpcm450_aic_chip = { + .name = "wpcm450-aic", + .irq_eoi = wpcm450_aic_eoi, + .irq_mask = wpcm450_aic_mask, + .irq_unmask = wpcm450_aic_unmask, + .irq_set_type = wpcm450_aic_set_type, +}; + +static int wpcm450_aic_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) +{ + if (hwirq >= AIC_NUM_IRQS) + return -EPERM; + + irq_set_chip_and_handler(irq, &wpcm450_aic_chip, handle_fasteoi_irq); + irq_set_chip_data(irq, aic); + irq_set_probe(irq); + + return 0; +} + +static const struct irq_domain_ops wpcm450_aic_ops = { + .map = wpcm450_aic_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int __init wpcm450_aic_of_init(struct device_node *node, + struct device_node *parent) +{ + if (parent) + return -EINVAL; + + aic = kzalloc(sizeof(*aic), GFP_KERNEL); + if (!aic) + return -ENOMEM; + + aic->regs = of_iomap(node, 0); + if (!aic->regs) { + pr_err("Failed to map WPCM450 AIC registers\n"); + return -ENOMEM; + } + + wpcm450_aic_init_hw(); + + set_handle_irq(wpcm450_aic_handle_irq); + + aic->domain = irq_domain_add_linear(node, AIC_NUM_IRQS, &wpcm450_aic_ops, aic); + + return 0; +} + +IRQCHIP_DECLARE(wpcm450_aic, "nuvoton,wpcm450-aic", wpcm450_aic_of_init); diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c index 1d3d273309bd3a561510298093f9d3b67703d62a..8cd1bfc7305722f1777502f2c21f88b4be205508 100644 --- a/drivers/irqchip/irq-xilinx-intc.c +++ b/drivers/irqchip/irq-xilinx-intc.c @@ -210,7 +210,7 @@ static int __init xilinx_intc_of_init(struct device_node *intc, /* * Disable all external interrupts until they are - * explicity requested. + * explicitly requested. */ xintc_write(irqc, IER, 0); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5d57a5bd171fa1a82beb539f9fa53df95152c659..841e1c1aa5e63aa51677794f0cf578fc9635b65d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -953,7 +953,8 @@ static void dispatch_bio_list(struct bio_list *tmp) submit_bio_noacct(bio); } -static int cmp_stripe(void *priv, struct list_head *a, struct list_head *b) +static int cmp_stripe(void *priv, const struct list_head *a, + const struct list_head *b) { const struct r5pending_data *da = list_entry(a, struct r5pending_data, sibling); diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index c2199042d3db593b8d4f6bf045b791cfb6055f28..e8511787c1e439a72588e9f8609a965372e20bec 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -79,8 +79,8 @@ static void cio2_bridge_create_fwnode_properties( { sensor->prop_names = prop_names; - sensor->local_ref[0].node = &sensor->swnodes[SWNODE_CIO2_ENDPOINT]; - sensor->remote_ref[0].node = &sensor->swnodes[SWNODE_SENSOR_ENDPOINT]; + sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_CIO2_ENDPOINT]); + sensor->remote_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_SENSOR_ENDPOINT]); sensor->dev_properties[0] = PROPERTY_ENTRY_U32( sensor->prop_names.clock_frequency, diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 741be0e694471accd337a74a4506d2896db5dc88..2b8ad2bde8a480c5acfa82d1e5d0d9bd0829d388 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -487,7 +487,7 @@ extern int __must_check dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); /* commonly used remote control parsing */ -extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); +extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[5], u32 *, int *); /* commonly used firmware download types and function */ struct hexline { diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c index 0309bd5a1800879911c777ee89a291c8aa0bbe59..f8ea592c9cb5be478ad7c8dff19d4882a704efc4 100644 --- a/drivers/memory/fsl-corenet-cf.c +++ b/drivers/memory/fsl-corenet-cf.c @@ -192,10 +192,8 @@ static int ccf_probe(struct platform_device *pdev) } ccf->regs = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(ccf->regs)) { - dev_err(&pdev->dev, "%s: can't map mem resource\n", __func__); + if (IS_ERR(ccf->regs)) return PTR_ERR(ccf->regs); - } ccf->dev = &pdev->dev; ccf->info = match->data; diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index b396253fcf4bbe3c56f3fae18bab59129889ee95..c5fb51f73b341546d0da590cdc77b4ec3fdc60d4 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -319,6 +319,7 @@ static int mtk_smi_larb_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *smi_node; struct platform_device *smi_pdev; + struct device_link *link; larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); if (!larb) @@ -358,6 +359,12 @@ static int mtk_smi_larb_probe(struct platform_device *pdev) if (!platform_get_drvdata(smi_pdev)) return -EPROBE_DEFER; larb->smi_common_dev = &smi_pdev->dev; + link = device_link_add(dev, larb->smi_common_dev, + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); + if (!link) { + dev_err(dev, "Unable to link smi-common dev\n"); + return -ENODEV; + } } else { dev_err(dev, "Failed to get the smi_common device\n"); return -EINVAL; @@ -370,6 +377,9 @@ static int mtk_smi_larb_probe(struct platform_device *pdev) static int mtk_smi_larb_remove(struct platform_device *pdev) { + struct mtk_smi_larb *larb = platform_get_drvdata(pdev); + + device_link_remove(&pdev->dev, larb->smi_common_dev); pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &mtk_smi_larb_component_ops); return 0; @@ -381,17 +391,9 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev) const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; int ret; - /* Power on smi-common. */ - ret = pm_runtime_resume_and_get(larb->smi_common_dev); - if (ret < 0) { - dev_err(dev, "Failed to pm get for smi-common(%d).\n", ret); - return ret; - } - ret = mtk_smi_clk_enable(&larb->smi); if (ret < 0) { dev_err(dev, "Failed to enable clock(%d).\n", ret); - pm_runtime_put_sync(larb->smi_common_dev); return ret; } @@ -406,7 +408,6 @@ static int __maybe_unused mtk_smi_larb_suspend(struct device *dev) struct mtk_smi_larb *larb = dev_get_drvdata(dev); mtk_smi_clk_disable(&larb->smi); - pm_runtime_put_sync(larb->smi_common_dev); return 0; } diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index cfa730cfd1453e932ec169d2cf9106a13ad07859..f80c2ea39ca4c1ca69319dc98b220ef6adcddb35 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -1009,8 +1009,8 @@ EXPORT_SYMBOL(gpmc_cs_request); void gpmc_cs_free(int cs) { - struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; - struct resource *res = &gpmc->mem; + struct gpmc_cs_data *gpmc; + struct resource *res; spin_lock(&gpmc_mem_lock); if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { @@ -1018,6 +1018,9 @@ void gpmc_cs_free(int cs) spin_unlock(&gpmc_mem_lock); return; } + gpmc = &gpmc_cs[cs]; + res = &gpmc->mem; + gpmc_cs_disable_mem(cs); if (res->flags) release_resource(res); diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index 3b5b1045edd9044b8cce85f175a3c3419c8fc241..9c0a2841677739fb93d96f3d328121c7f8bcd8c8 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -63,7 +63,7 @@ /* ECC memory config register specific constants */ #define PL353_SMC_ECC_MEMCFG_MODE_MASK 0xC #define PL353_SMC_ECC_MEMCFG_MODE_SHIFT 2 -#define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK 0xC +#define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK 0x3 #define PL353_SMC_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \ (2 << 21)) /* UpdateRegs operation */ diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 8d36e221def149074b9ab3d0f6c4c74ee7248e24..45eed659b0c6de5f14266e2e9242b76f4e38bff4 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -192,10 +192,10 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap"); - rpc->size = resource_size(res); rpc->dirmap = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(rpc->dirmap)) rpc->dirmap = NULL; + rpc->size = resource_size(res); rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index 1dabb509dec3a1a2ebb129e28d17485f143a6f6a..9c8318923ed0b25ea4a48729a6205bfca1395eed 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -343,7 +343,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc, int idx; unsigned long freq; - ret = dev_pm_opp_of_add_table(dmc->dev); + ret = devm_pm_opp_of_add_table(dmc->dev); if (ret < 0) { dev_err(dmc->dev, "Failed to get OPP table\n"); return ret; @@ -354,7 +354,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc, dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count, sizeof(struct dmc_opp_table), GFP_KERNEL); if (!dmc->opp) - goto err_opp; + return -ENOMEM; idx = dmc->opp_count - 1; for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) { @@ -362,7 +362,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc, opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq); if (IS_ERR(opp)) - goto err_opp; + return PTR_ERR(opp); dmc->opp[idx - i].freq_hz = freq; dmc->opp[idx - i].volt_uv = dev_pm_opp_get_voltage(opp); @@ -371,11 +371,6 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc, } return 0; - -err_opp: - dev_pm_opp_of_remove_table(dmc->dev); - - return -EINVAL; } /** @@ -1298,7 +1293,9 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc) dmc->curr_volt = target_volt; - clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll); + ret = clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll); + if (ret) + return ret; clk_prepare_enable(dmc->fout_bpll); clk_prepare_enable(dmc->mout_bpll); @@ -1567,8 +1564,6 @@ static int exynos5_dmc_remove(struct platform_device *pdev) clk_disable_unprepare(dmc->mout_bpll); clk_disable_unprepare(dmc->fout_bpll); - dev_pm_opp_remove_table(dmc->dev); - return 0; } diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index a21163ccadc405a18a8717529dd6f959ba6beb82..e58c3e5baea067f0fee0c5838c7a9a6a834cc708 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -827,6 +827,15 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } + mc->debugfs.root = debugfs_create_dir("mc", NULL); + + if (mc->soc->init) { + err = mc->soc->init(mc); + if (err < 0) + dev_err(&pdev->dev, "failed to initialize SoC driver: %d\n", + err); + } + err = tegra_mc_reset_setup(mc); if (err < 0) dev_err(&pdev->dev, "failed to register reset controller: %d\n", diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 33e40d600592e95863b155a5ce47769e17d790ca..1ee34f0da4f7cdd61a8759bb665154ae514db79c 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -92,12 +92,12 @@ icc_provider_to_tegra_mc(struct icc_provider *provider) return container_of(provider, struct tegra_mc, provider); } -static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) +static inline u32 mc_readl(const struct tegra_mc *mc, unsigned long offset) { return readl_relaxed(mc->regs + offset); } -static inline void mc_writel(struct tegra_mc *mc, u32 value, +static inline void mc_writel(const struct tegra_mc *mc, u32 value, unsigned long offset) { writel_relaxed(value, mc->regs + offset); diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index bee8d9f79b042a15757762538dc695037c8a55a0..5699d909abc22180f9c01e4e0df076a998681e4e 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -905,7 +905,7 @@ static int emc_init(struct tegra_emc *emc) else emc->dram_bus_width = 32; - dev_info(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width); + dev_info_once(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width); emc->dram_type &= EMC_FBIO_CFG5_DRAM_TYPE_MASK; emc->dram_type >>= EMC_FBIO_CFG5_DRAM_TYPE_SHIFT; @@ -1204,7 +1204,7 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_min_rate_fops, +DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_min_rate_fops, tegra_emc_debug_min_rate_get, tegra_emc_debug_min_rate_set, "%llu\n"); @@ -1234,7 +1234,7 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_max_rate_fops, +DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_max_rate_fops, tegra_emc_debug_max_rate_get, tegra_emc_debug_max_rate_set, "%llu\n"); @@ -1419,8 +1419,8 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc) goto put_hw_table; } - dev_info(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", - hw_version, clk_get_rate(emc->clk) / 1000000); + dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", + hw_version, clk_get_rate(emc->clk) / 1000000); /* first dummy rate-set initializes voltage state */ err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk)); @@ -1475,9 +1475,9 @@ static int tegra_emc_probe(struct platform_device *pdev) if (err) return err; } else { - dev_info(&pdev->dev, - "no memory timings for RAM code %u found in DT\n", - ram_code); + dev_info_once(&pdev->dev, + "no memory timings for RAM code %u found in DT\n", + ram_code); } err = emc_init(emc); diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c index d653a6be8d7fd67bca5eefe1fc9d5a7491f237fc..da8a0da8da79f75ae76b0f5bd5feeb4c9b65d697 100644 --- a/drivers/memory/tegra/tegra20-emc.c +++ b/drivers/memory/tegra/tegra20-emc.c @@ -411,12 +411,12 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, NULL); - dev_info(emc->dev, - "got %u timings for RAM code %u (min %luMHz max %luMHz)\n", - emc->num_timings, - tegra_read_ram_code(), - emc->timings[0].rate / 1000000, - emc->timings[emc->num_timings - 1].rate / 1000000); + dev_info_once(emc->dev, + "got %u timings for RAM code %u (min %luMHz max %luMHz)\n", + emc->num_timings, + tegra_read_ram_code(), + emc->timings[0].rate / 1000000, + emc->timings[emc->num_timings - 1].rate / 1000000); return 0; } @@ -429,7 +429,7 @@ tegra_emc_find_node_by_ram_code(struct device *dev) int err; if (of_get_child_count(dev->of_node) == 0) { - dev_info(dev, "device-tree doesn't have memory timings\n"); + dev_info_once(dev, "device-tree doesn't have memory timings\n"); return NULL; } @@ -496,7 +496,7 @@ static int emc_setup_hw(struct tegra_emc *emc) else emc->dram_bus_width = 32; - dev_info(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width); + dev_info_once(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width); return 0; } @@ -931,8 +931,8 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc) goto put_hw_table; } - dev_info(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", - hw_version, clk_get_rate(emc->clk) / 1000000); + dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", + hw_version, clk_get_rate(emc->clk) / 1000000); /* first dummy rate-set initializes voltage state */ err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk)); diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index 29ecf02805a01cb2d6cc7f3d57955407291ee05e..2db68a913b7af0af5a3b9ee23282e77db3887ff7 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -3,6 +3,9 @@ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. */ +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/mutex.h> #include <linux/of_device.h> #include <linux/slab.h> #include <linux/string.h> @@ -11,6 +14,79 @@ #include "mc.h" +#define MC_STAT_CONTROL 0x90 +#define MC_STAT_EMC_CLOCK_LIMIT 0xa0 +#define MC_STAT_EMC_CLOCKS 0xa4 +#define MC_STAT_EMC_CONTROL_0 0xa8 +#define MC_STAT_EMC_CONTROL_1 0xac +#define MC_STAT_EMC_COUNT_0 0xb8 +#define MC_STAT_EMC_COUNT_1 0xbc + +#define MC_STAT_CONTROL_CLIENT_ID GENMASK(13, 8) +#define MC_STAT_CONTROL_EVENT GENMASK(23, 16) +#define MC_STAT_CONTROL_PRI_EVENT GENMASK(25, 24) +#define MC_STAT_CONTROL_FILTER_CLIENT_ENABLE GENMASK(26, 26) +#define MC_STAT_CONTROL_FILTER_PRI GENMASK(29, 28) + +#define MC_STAT_CONTROL_PRI_EVENT_HP 0 +#define MC_STAT_CONTROL_PRI_EVENT_TM 1 +#define MC_STAT_CONTROL_PRI_EVENT_BW 2 + +#define MC_STAT_CONTROL_FILTER_PRI_DISABLE 0 +#define MC_STAT_CONTROL_FILTER_PRI_NO 1 +#define MC_STAT_CONTROL_FILTER_PRI_YES 2 + +#define MC_STAT_CONTROL_EVENT_QUALIFIED 0 +#define MC_STAT_CONTROL_EVENT_ANY_READ 1 +#define MC_STAT_CONTROL_EVENT_ANY_WRITE 2 +#define MC_STAT_CONTROL_EVENT_RD_WR_CHANGE 3 +#define MC_STAT_CONTROL_EVENT_SUCCESSIVE 4 +#define MC_STAT_CONTROL_EVENT_ARB_BANK_AA 5 +#define MC_STAT_CONTROL_EVENT_ARB_BANK_BB 6 +#define MC_STAT_CONTROL_EVENT_PAGE_MISS 7 +#define MC_STAT_CONTROL_EVENT_AUTO_PRECHARGE 8 + +#define EMC_GATHER_RST (0 << 8) +#define EMC_GATHER_CLEAR (1 << 8) +#define EMC_GATHER_DISABLE (2 << 8) +#define EMC_GATHER_ENABLE (3 << 8) + +#define MC_STAT_SAMPLE_TIME_USEC 16000 + +/* we store collected statistics as a fixed point values */ +#define MC_FX_FRAC_SCALE 100 + +static DEFINE_MUTEX(tegra20_mc_stat_lock); + +struct tegra20_mc_stat_gather { + unsigned int pri_filter; + unsigned int pri_event; + unsigned int result; + unsigned int client; + unsigned int event; + bool client_enb; +}; + +struct tegra20_mc_stat { + struct tegra20_mc_stat_gather gather0; + struct tegra20_mc_stat_gather gather1; + unsigned int sample_time_usec; + const struct tegra_mc *mc; +}; + +struct tegra20_mc_client_stat { + unsigned int events; + unsigned int arb_high_prio; + unsigned int arb_timeout; + unsigned int arb_bandwidth; + unsigned int rd_wr_change; + unsigned int successive; + unsigned int page_miss; + unsigned int auto_precharge; + unsigned int arb_bank_aa; + unsigned int arb_bank_bb; +}; + static const struct tegra_mc_client tegra20_mc_clients[] = { { .id = 0x00, @@ -356,6 +432,261 @@ static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = { .set = tegra20_mc_icc_set, }; +static u32 tegra20_mc_stat_gather_control(const struct tegra20_mc_stat_gather *g) +{ + u32 control; + + control = FIELD_PREP(MC_STAT_CONTROL_EVENT, g->event); + control |= FIELD_PREP(MC_STAT_CONTROL_CLIENT_ID, g->client); + control |= FIELD_PREP(MC_STAT_CONTROL_PRI_EVENT, g->pri_event); + control |= FIELD_PREP(MC_STAT_CONTROL_FILTER_PRI, g->pri_filter); + control |= FIELD_PREP(MC_STAT_CONTROL_FILTER_CLIENT_ENABLE, g->client_enb); + + return control; +} + +static void tegra20_mc_stat_gather(struct tegra20_mc_stat *stat) +{ + u32 clocks, count0, count1, control_0, control_1; + const struct tegra_mc *mc = stat->mc; + + control_0 = tegra20_mc_stat_gather_control(&stat->gather0); + control_1 = tegra20_mc_stat_gather_control(&stat->gather1); + + /* + * Reset statistic gathers state, select statistics collection mode + * and set clocks counter saturation limit to maximum. + */ + mc_writel(mc, 0x00000000, MC_STAT_CONTROL); + mc_writel(mc, control_0, MC_STAT_EMC_CONTROL_0); + mc_writel(mc, control_1, MC_STAT_EMC_CONTROL_1); + mc_writel(mc, 0xffffffff, MC_STAT_EMC_CLOCK_LIMIT); + + mc_writel(mc, EMC_GATHER_ENABLE, MC_STAT_CONTROL); + fsleep(stat->sample_time_usec); + mc_writel(mc, EMC_GATHER_DISABLE, MC_STAT_CONTROL); + + count0 = mc_readl(mc, MC_STAT_EMC_COUNT_0); + count1 = mc_readl(mc, MC_STAT_EMC_COUNT_1); + clocks = mc_readl(mc, MC_STAT_EMC_CLOCKS); + clocks = max(clocks / 100 / MC_FX_FRAC_SCALE, 1u); + + stat->gather0.result = DIV_ROUND_UP(count0, clocks); + stat->gather1.result = DIV_ROUND_UP(count1, clocks); +} + +static void tegra20_mc_stat_events(const struct tegra_mc *mc, + const struct tegra_mc_client *client0, + const struct tegra_mc_client *client1, + unsigned int pri_filter, + unsigned int pri_event, + unsigned int event, + unsigned int *result0, + unsigned int *result1) +{ + struct tegra20_mc_stat stat = {}; + + stat.gather0.client = client0 ? client0->id : 0; + stat.gather0.pri_filter = pri_filter; + stat.gather0.client_enb = !!client0; + stat.gather0.pri_event = pri_event; + stat.gather0.event = event; + + stat.gather1.client = client1 ? client1->id : 0; + stat.gather1.pri_filter = pri_filter; + stat.gather1.client_enb = !!client1; + stat.gather1.pri_event = pri_event; + stat.gather1.event = event; + + stat.sample_time_usec = MC_STAT_SAMPLE_TIME_USEC; + stat.mc = mc; + + tegra20_mc_stat_gather(&stat); + + *result0 = stat.gather0.result; + *result1 = stat.gather1.result; +} + +static void tegra20_mc_collect_stats(const struct tegra_mc *mc, + struct tegra20_mc_client_stat *stats) +{ + const struct tegra_mc_client *client0, *client1; + unsigned int i; + + /* collect memory controller utilization percent for each client */ + for (i = 0; i < mc->soc->num_clients; i += 2) { + client0 = &mc->soc->clients[i]; + client1 = &mc->soc->clients[i + 1]; + + if (i + 1 == mc->soc->num_clients) + client1 = NULL; + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_DISABLE, + MC_STAT_CONTROL_PRI_EVENT_HP, + MC_STAT_CONTROL_EVENT_QUALIFIED, + &stats[i + 0].events, + &stats[i + 1].events); + } + + /* collect more info from active clients */ + for (i = 0; i < mc->soc->num_clients; i++) { + unsigned int clienta, clientb = mc->soc->num_clients; + + for (client0 = NULL; i < mc->soc->num_clients; i++) { + if (stats[i].events) { + client0 = &mc->soc->clients[i]; + clienta = i++; + break; + } + } + + for (client1 = NULL; i < mc->soc->num_clients; i++) { + if (stats[i].events) { + client1 = &mc->soc->clients[i]; + clientb = i; + break; + } + } + + if (!client0 && !client1) + break; + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_YES, + MC_STAT_CONTROL_PRI_EVENT_HP, + MC_STAT_CONTROL_EVENT_QUALIFIED, + &stats[clienta].arb_high_prio, + &stats[clientb].arb_high_prio); + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_YES, + MC_STAT_CONTROL_PRI_EVENT_TM, + MC_STAT_CONTROL_EVENT_QUALIFIED, + &stats[clienta].arb_timeout, + &stats[clientb].arb_timeout); + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_YES, + MC_STAT_CONTROL_PRI_EVENT_BW, + MC_STAT_CONTROL_EVENT_QUALIFIED, + &stats[clienta].arb_bandwidth, + &stats[clientb].arb_bandwidth); + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_DISABLE, + MC_STAT_CONTROL_PRI_EVENT_HP, + MC_STAT_CONTROL_EVENT_RD_WR_CHANGE, + &stats[clienta].rd_wr_change, + &stats[clientb].rd_wr_change); + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_DISABLE, + MC_STAT_CONTROL_PRI_EVENT_HP, + MC_STAT_CONTROL_EVENT_SUCCESSIVE, + &stats[clienta].successive, + &stats[clientb].successive); + + tegra20_mc_stat_events(mc, client0, client1, + MC_STAT_CONTROL_FILTER_PRI_DISABLE, + MC_STAT_CONTROL_PRI_EVENT_HP, + MC_STAT_CONTROL_EVENT_PAGE_MISS, + &stats[clienta].page_miss, + &stats[clientb].page_miss); + } +} + +static void tegra20_mc_printf_percents(struct seq_file *s, + const char *fmt, + unsigned int percents_fx) +{ + char percents_str[8]; + + snprintf(percents_str, ARRAY_SIZE(percents_str), "%3u.%02u%%", + percents_fx / MC_FX_FRAC_SCALE, percents_fx % MC_FX_FRAC_SCALE); + + seq_printf(s, fmt, percents_str); +} + +static int tegra20_mc_stats_show(struct seq_file *s, void *unused) +{ + const struct tegra_mc *mc = dev_get_drvdata(s->private); + struct tegra20_mc_client_stat *stats; + unsigned int i; + + stats = kcalloc(mc->soc->num_clients + 1, sizeof(*stats), GFP_KERNEL); + if (!stats) + return -ENOMEM; + + mutex_lock(&tegra20_mc_stat_lock); + + tegra20_mc_collect_stats(mc, stats); + + mutex_unlock(&tegra20_mc_stat_lock); + + seq_puts(s, "Memory client Events Timeout High priority Bandwidth ARB RW change Successive Page miss\n"); + seq_puts(s, "-----------------------------------------------------------------------------------------------------\n"); + + for (i = 0; i < mc->soc->num_clients; i++) { + seq_printf(s, "%-14s ", mc->soc->clients[i].name); + + /* An event is generated when client performs R/W request. */ + tegra20_mc_printf_percents(s, "%-9s", stats[i].events); + + /* + * An event is generated based on the timeout (TM) signal + * accompanying a request for arbitration. + */ + tegra20_mc_printf_percents(s, "%-10s", stats[i].arb_timeout); + + /* + * An event is generated based on the high-priority (HP) signal + * accompanying a request for arbitration. + */ + tegra20_mc_printf_percents(s, "%-16s", stats[i].arb_high_prio); + + /* + * An event is generated based on the bandwidth (BW) signal + * accompanying a request for arbitration. + */ + tegra20_mc_printf_percents(s, "%-16s", stats[i].arb_bandwidth); + + /* + * An event is generated when the memory controller switches + * between making a read request to making a write request. + */ + tegra20_mc_printf_percents(s, "%-12s", stats[i].rd_wr_change); + + /* + * An even generated when the chosen client has wins arbitration + * when it was also the winner at the previous request. If a + * client makes N requests in a row that are honored, SUCCESSIVE + * will be counted (N-1) times. Large values for this event + * imply that if we were patient enough, all of those requests + * could have been coalesced. + */ + tegra20_mc_printf_percents(s, "%-13s", stats[i].successive); + + /* + * An event is generated when the memory controller detects a + * page miss for the current request. + */ + tegra20_mc_printf_percents(s, "%-12s\n", stats[i].page_miss); + } + + kfree(stats); + + return 0; +} + +static int tegra20_mc_init(struct tegra_mc *mc) +{ + debugfs_create_devm_seqfile(mc->dev, "stats", mc->debugfs.root, + tegra20_mc_stats_show); + + return 0; +} + const struct tegra_mc_soc tegra20_mc_soc = { .clients = tegra20_mc_clients, .num_clients = ARRAY_SIZE(tegra20_mc_clients), @@ -367,4 +698,5 @@ const struct tegra_mc_soc tegra20_mc_soc = { .resets = tegra20_mc_resets, .num_resets = ARRAY_SIZE(tegra20_mc_resets), .icc_ops = &tegra20_mc_icc_ops, + .init = tegra20_mc_init, }; diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index 6985da0ffb35ed29973d55dbc6651f0bfe34e658..829f6d673c9615624f3f2a3ef64cf59f15755db6 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -998,12 +998,12 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc, if (err) return err; - dev_info(emc->dev, - "got %u timings for RAM code %u (min %luMHz max %luMHz)\n", - emc->num_timings, - tegra_read_ram_code(), - emc->timings[0].rate / 1000000, - emc->timings[emc->num_timings - 1].rate / 1000000); + dev_info_once(emc->dev, + "got %u timings for RAM code %u (min %luMHz max %luMHz)\n", + emc->num_timings, + tegra_read_ram_code(), + emc->timings[0].rate / 1000000, + emc->timings[emc->num_timings - 1].rate / 1000000); return 0; } @@ -1015,7 +1015,7 @@ static struct device_node *emc_find_node_by_ram_code(struct device *dev) int err; if (of_get_child_count(dev->of_node) == 0) { - dev_info(dev, "device-tree doesn't have memory timings\n"); + dev_info_once(dev, "device-tree doesn't have memory timings\n"); return NULL; } @@ -1503,8 +1503,8 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc) goto put_hw_table; } - dev_info(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", - hw_version, clk_get_rate(emc->clk) / 1000000); + dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", + hw_version, clk_get_rate(emc->clk) / 1000000); /* first dummy rate-set initializes voltage state */ err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk)); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b74efa469e909a8853dc8e0c7396d09f166a5be9..2ce9edb90901d54e0257489b74de3fa934454c18 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -21,7 +21,7 @@ config MFD_CS5535 config MFD_ALTERA_A10SR bool "Altera Arria10 DevKit System Resource chip" - depends on ARCH_SOCFPGA && SPI_MASTER=y && OF + depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF select REGMAP_SPI select MFD_CORE help @@ -32,7 +32,7 @@ config MFD_ALTERA_A10SR config MFD_ALTERA_SYSMGR bool "Altera SOCFPGA System Manager" - depends on (ARCH_SOCFPGA || ARCH_STRATIX10) && OF + depends on ARCH_INTEL_SOCFPGA && OF select MFD_SYSCON help Select this to get System Manager support for all Altera branded diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 06c977519479ac3b1bb941f873e81c30d9cb4445..cb538983246cbf13095099f02c6d5690c62a096f 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -15,6 +15,11 @@ enum m10bmc_type { M10_N3000, + M10_D5005 +}; + +static struct mfd_cell m10bmc_d5005_subdevs[] = { + { .name = "d5005bmc-hwmon" }, }; static struct mfd_cell m10bmc_pacn3000_subdevs[] = { @@ -173,6 +178,10 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) cells = m10bmc_pacn3000_subdevs; n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs); break; + case M10_D5005: + cells = m10bmc_d5005_subdevs; + n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs); + break; default: return -ENODEV; } @@ -187,6 +196,7 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) static const struct spi_device_id m10bmc_spi_id[] = { { "m10-n3000", M10_N3000 }, + { "m10-d5005", M10_D5005 }, { } }; MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); diff --git a/drivers/mfd/intel_pmt.c b/drivers/mfd/intel_pmt.c index 744b230cdccaa4fa096cb3b74b30c9a936eeb940..dd7eb614c28e47d56fd88fb80cf501e0e67fd12b 100644 --- a/drivers/mfd/intel_pmt.c +++ b/drivers/mfd/intel_pmt.c @@ -49,10 +49,14 @@ enum pmt_quirks { /* Use shift instead of mask to read discovery table offset */ PMT_QUIRK_TABLE_SHIFT = BIT(2), + + /* DVSEC not present (provided in driver data) */ + PMT_QUIRK_NO_DVSEC = BIT(3), }; struct pmt_platform_info { unsigned long quirks; + struct intel_dvsec_header **capabilities; }; static const struct pmt_platform_info tgl_info = { @@ -60,6 +64,26 @@ static const struct pmt_platform_info tgl_info = { PMT_QUIRK_TABLE_SHIFT, }; +/* DG1 Platform with DVSEC quirk*/ +static struct intel_dvsec_header dg1_telemetry = { + .length = 0x10, + .id = 2, + .num_entries = 1, + .entry_size = 3, + .tbir = 0, + .offset = 0x466000, +}; + +static struct intel_dvsec_header *dg1_capabilities[] = { + &dg1_telemetry, + NULL +}; + +static const struct pmt_platform_info dg1_info = { + .quirks = PMT_QUIRK_NO_DVSEC, + .capabilities = dg1_capabilities, +}; + static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header, unsigned long quirks) { @@ -79,19 +103,18 @@ static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header, case DVSEC_INTEL_ID_WATCHER: if (quirks & PMT_QUIRK_NO_WATCHER) { dev_info(dev, "Watcher not supported\n"); - return 0; + return -EINVAL; } name = "pmt_watcher"; break; case DVSEC_INTEL_ID_CRASHLOG: if (quirks & PMT_QUIRK_NO_CRASHLOG) { dev_info(dev, "Crashlog not supported\n"); - return 0; + return -EINVAL; } name = "pmt_crashlog"; break; default: - dev_err(dev, "Unrecognized PMT capability: %d\n", id); return -EINVAL; } @@ -148,41 +171,54 @@ static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (info) quirks = info->quirks; - do { - struct intel_dvsec_header header; - u32 table; - u16 vid; - - pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); - if (!pos) - break; - - pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid); - if (vid != PCI_VENDOR_ID_INTEL) - continue; - - pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2, - &header.id); - pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, - &header.num_entries); - pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, - &header.entry_size); - pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, - &table); - - header.tbir = INTEL_DVSEC_TABLE_BAR(table); - header.offset = INTEL_DVSEC_TABLE_OFFSET(table); - - ret = pmt_add_dev(pdev, &header, quirks); - if (ret) { - dev_warn(&pdev->dev, - "Failed to add device for DVSEC id %d\n", - header.id); - continue; - } + if (info && (info->quirks & PMT_QUIRK_NO_DVSEC)) { + struct intel_dvsec_header **header; + + header = info->capabilities; + while (*header) { + ret = pmt_add_dev(pdev, *header, quirks); + if (ret) + dev_warn(&pdev->dev, + "Failed to add device for DVSEC id %d\n", + (*header)->id); + else + found_devices = true; - found_devices = true; - } while (true); + ++header; + } + } else { + do { + struct intel_dvsec_header header; + u32 table; + u16 vid; + + pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); + if (!pos) + break; + + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid); + if (vid != PCI_VENDOR_ID_INTEL) + continue; + + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2, + &header.id); + pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, + &header.num_entries); + pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, + &header.entry_size); + pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, + &table); + + header.tbir = INTEL_DVSEC_TABLE_BAR(table); + header.offset = INTEL_DVSEC_TABLE_OFFSET(table); + + ret = pmt_add_dev(pdev, &header, quirks); + if (ret) + continue; + + found_devices = true; + } while (true); + } if (!found_devices) return -ENODEV; @@ -200,10 +236,12 @@ static void pmt_pci_remove(struct pci_dev *pdev) } #define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d +#define PCI_DEVICE_ID_INTEL_PMT_DG1 0x490e #define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7 #define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d static const struct pci_device_id pmt_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) }, + { PCI_DEVICE_DATA(INTEL, PMT_DG1, &dg1_info) }, { PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) }, { PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) }, { } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 15370219655281fe451f37ba4891315ea7c5af67..830536e6c51a8da450a64fb2ecace38b267d9dec 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -402,6 +402,16 @@ config SRAM config SRAM_EXEC bool +config DW_XDATA_PCIE + depends on PCI + tristate "Synopsys DesignWare xData PCIe driver" + help + This driver allows controlling Synopsys DesignWare PCIe traffic + generator IP also known as xData, present in Synopsys DesignWare + PCIe Endpoint prototype. + + If unsure, say N. + config PCI_ENDPOINT_TEST depends on PCI select CRC32 @@ -442,14 +452,6 @@ config UID_SYS_STATS_DEBUG help Per TASK based io statistics exported to /proc/uid_io -config PVPANIC - tristate "pvpanic device support" - depends on HAS_IOMEM && (ACPI || OF) - help - This driver provides support for the pvpanic device. pvpanic is - a paravirtualized device provided by QEMU; it lets a virtual machine - (guest) communicate panic events to the host. - config HISI_HIKEY_USB tristate "USB GPIO Hub on HiSilicon Hikey 960/970 Platform" depends on (OF && GPIOLIB) || COMPILE_TEST @@ -476,4 +478,5 @@ source "drivers/misc/bcm-vk/Kconfig" source "drivers/misc/cardreader/Kconfig" source "drivers/misc/habanalabs/Kconfig" source "drivers/misc/uacce/Kconfig" +source "drivers/misc/pvpanic/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8be109bc4b11696568a42a35790a11c839bd5e4a..3531ca64045a1e1171e15555dc400b26cc656403 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -47,11 +47,12 @@ obj-$(CONFIG_SRAM_EXEC) += sram-exec.o obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_CXL_BASE) += cxl/ +obj-$(CONFIG_DW_XDATA_PCIE) += dw-xdata-pcie.o obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ obj-$(CONFIG_BCM_VK) += bcm-vk/ obj-y += cardreader/ -obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-$(CONFIG_PVPANIC) += pvpanic/ obj-$(CONFIG_HABANA_AI) += habanalabs/ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 6f164522b02823d9ceb803a88c0bc1cfff6d9e6e..5d8f3f6a95f2a8914bbd72a48b30741cf29851dc 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -139,6 +139,9 @@ static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg) value = dpot_read_r8d8(dpot, DPOT_AD5291_READ_RDAC << 2); + if (value < 0) + return value; + if (dpot->uid == DPOT_UID(AD5291_ID)) value = value >> 2; diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index fb2eff69e449d29aa2670070361c40690bee85c2..e627b405662395eec33405b942e9ba4ad196d456 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -52,7 +52,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) * can always access it when dereferenced from IDR. For the same * reason, the segment table is only destroyed after the context is * removed from the IDR. Access to this in the IOCTL is protected by - * Linux filesytem symantics (can't IOCTL until open is complete). + * Linux filesystem semantics (can't IOCTL until open is complete). */ i = cxl_alloc_sst(ctx); if (i) diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index 01153b74334a1b394a1a9e5dba7fffed5921807d..60c829113299bd771580030b1d616cf272d1daf3 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c @@ -200,7 +200,7 @@ static struct mm_struct *get_mem_context(struct cxl_context *ctx) if (ctx->mm == NULL) return NULL; - if (!atomic_inc_not_zero(&ctx->mm->mm_users)) + if (!mmget_not_zero(ctx->mm)) return NULL; return ctx->mm; diff --git a/drivers/misc/dw-xdata-pcie.c b/drivers/misc/dw-xdata-pcie.c new file mode 100644 index 0000000000000000000000000000000000000000..257c25da5199600d55371429a0458a4a97239e5a --- /dev/null +++ b/drivers/misc/dw-xdata-pcie.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates. + * Synopsys DesignWare xData driver + * + * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com> + */ + +#include <linux/miscdevice.h> +#include <linux/bitfield.h> +#include <linux/pci-epf.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/bitops.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#define DW_XDATA_DRIVER_NAME "dw-xdata-pcie" + +#define DW_XDATA_EP_MEM_OFFSET 0x8000000 + +static DEFINE_IDA(xdata_ida); + +#define STATUS_DONE BIT(0) + +#define CONTROL_DOORBELL BIT(0) +#define CONTROL_IS_WRITE BIT(1) +#define CONTROL_LENGTH(a) FIELD_PREP(GENMASK(13, 2), a) +#define CONTROL_PATTERN_INC BIT(16) +#define CONTROL_NO_ADDR_INC BIT(18) + +#define XPERF_CONTROL_ENABLE BIT(5) + +#define BURST_REPEAT BIT(31) +#define BURST_VALUE 0x1001 + +#define PATTERN_VALUE 0x0 + +struct dw_xdata_regs { + u32 addr_lsb; /* 0x000 */ + u32 addr_msb; /* 0x004 */ + u32 burst_cnt; /* 0x008 */ + u32 control; /* 0x00c */ + u32 pattern; /* 0x010 */ + u32 status; /* 0x014 */ + u32 RAM_addr; /* 0x018 */ + u32 RAM_port; /* 0x01c */ + u32 _reserved0[14]; /* 0x020..0x054 */ + u32 perf_control; /* 0x058 */ + u32 _reserved1[41]; /* 0x05c..0x0fc */ + u32 wr_cnt_lsb; /* 0x100 */ + u32 wr_cnt_msb; /* 0x104 */ + u32 rd_cnt_lsb; /* 0x108 */ + u32 rd_cnt_msb; /* 0x10c */ +} __packed; + +struct dw_xdata_region { + phys_addr_t paddr; /* physical address */ + void __iomem *vaddr; /* virtual address */ +}; + +struct dw_xdata { + struct dw_xdata_region rg_region; /* registers */ + size_t max_wr_len; /* max wr xfer len */ + size_t max_rd_len; /* max rd xfer len */ + struct mutex mutex; + struct pci_dev *pdev; + struct miscdevice misc_dev; +}; + +static inline struct dw_xdata_regs __iomem *__dw_regs(struct dw_xdata *dw) +{ + return dw->rg_region.vaddr; +} + +static void dw_xdata_stop(struct dw_xdata *dw) +{ + u32 burst; + + mutex_lock(&dw->mutex); + + burst = readl(&(__dw_regs(dw)->burst_cnt)); + + if (burst & BURST_REPEAT) { + burst &= ~(u32)BURST_REPEAT; + writel(burst, &(__dw_regs(dw)->burst_cnt)); + } + + mutex_unlock(&dw->mutex); +} + +static void dw_xdata_start(struct dw_xdata *dw, bool write) +{ + struct device *dev = &dw->pdev->dev; + u32 control, status; + + /* Stop first if xfer in progress */ + dw_xdata_stop(dw); + + mutex_lock(&dw->mutex); + + /* Clear status register */ + writel(0x0, &(__dw_regs(dw)->status)); + + /* Burst count register set for continuous until stopped */ + writel(BURST_REPEAT | BURST_VALUE, &(__dw_regs(dw)->burst_cnt)); + + /* Pattern register */ + writel(PATTERN_VALUE, &(__dw_regs(dw)->pattern)); + + /* Control register */ + control = CONTROL_DOORBELL | CONTROL_PATTERN_INC | CONTROL_NO_ADDR_INC; + if (write) { + control |= CONTROL_IS_WRITE; + control |= CONTROL_LENGTH(dw->max_wr_len); + } else { + control |= CONTROL_LENGTH(dw->max_rd_len); + } + writel(control, &(__dw_regs(dw)->control)); + + /* + * The xData HW block needs about 100 ms to initiate the traffic + * generation according this HW block datasheet. + */ + usleep_range(100, 150); + + status = readl(&(__dw_regs(dw)->status)); + + mutex_unlock(&dw->mutex); + + if (!(status & STATUS_DONE)) + dev_dbg(dev, "xData: started %s direction\n", + write ? "write" : "read"); +} + +static void dw_xdata_perf_meas(struct dw_xdata *dw, u64 *data, bool write) +{ + if (write) { + *data = readl(&(__dw_regs(dw)->wr_cnt_msb)); + *data <<= 32; + *data |= readl(&(__dw_regs(dw)->wr_cnt_lsb)); + } else { + *data = readl(&(__dw_regs(dw)->rd_cnt_msb)); + *data <<= 32; + *data |= readl(&(__dw_regs(dw)->rd_cnt_lsb)); + } +} + +static u64 dw_xdata_perf_diff(u64 *m1, u64 *m2, u64 time) +{ + u64 rate = (*m1 - *m2); + + rate *= (1000 * 1000 * 1000); + rate >>= 20; + rate = DIV_ROUND_CLOSEST_ULL(rate, time); + + return rate; +} + +static void dw_xdata_perf(struct dw_xdata *dw, u64 *rate, bool write) +{ + struct device *dev = &dw->pdev->dev; + u64 data[2], time[2], diff; + + mutex_lock(&dw->mutex); + + /* First acquisition of current count frames */ + writel(0x0, &(__dw_regs(dw)->perf_control)); + dw_xdata_perf_meas(dw, &data[0], write); + time[0] = jiffies; + writel((u32)XPERF_CONTROL_ENABLE, &(__dw_regs(dw)->perf_control)); + + /* + * Wait 100ms between the 1st count frame acquisition and the 2nd + * count frame acquisition, in order to calculate the speed later + */ + mdelay(100); + + /* Second acquisition of current count frames */ + writel(0x0, &(__dw_regs(dw)->perf_control)); + dw_xdata_perf_meas(dw, &data[1], write); + time[1] = jiffies; + writel((u32)XPERF_CONTROL_ENABLE, &(__dw_regs(dw)->perf_control)); + + /* + * Speed calculation + * + * rate = (2nd count frames - 1st count frames) / (time elapsed) + */ + diff = jiffies_to_nsecs(time[1] - time[0]); + *rate = dw_xdata_perf_diff(&data[1], &data[0], diff); + + mutex_unlock(&dw->mutex); + + dev_dbg(dev, "xData: time=%llu us, %s=%llu MB/s\n", + diff, write ? "write" : "read", *rate); +} + +static struct dw_xdata *misc_dev_to_dw(struct miscdevice *misc_dev) +{ + return container_of(misc_dev, struct dw_xdata, misc_dev); +} + +static ssize_t write_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + u64 rate; + + dw_xdata_perf(dw, &rate, true); + + return sysfs_emit(buf, "%llu\n", rate); +} + +static ssize_t write_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + bool enabled; + int ret; + + ret = kstrtobool(buf, &enabled); + if (ret < 0) + return ret; + + if (enabled) { + dev_dbg(dev, "xData: requested write transfer\n"); + dw_xdata_start(dw, true); + } else { + dev_dbg(dev, "xData: requested stop transfer\n"); + dw_xdata_stop(dw); + } + + return size; +} + +static DEVICE_ATTR_RW(write); + +static ssize_t read_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + u64 rate; + + dw_xdata_perf(dw, &rate, false); + + return sysfs_emit(buf, "%llu\n", rate); +} + +static ssize_t read_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + bool enabled; + int ret; + + ret = kstrtobool(buf, &enabled); + if (ret < 0) + return ret; + + if (enabled) { + dev_dbg(dev, "xData: requested read transfer\n"); + dw_xdata_start(dw, false); + } else { + dev_dbg(dev, "xData: requested stop transfer\n"); + dw_xdata_stop(dw); + } + + return size; +} + +static DEVICE_ATTR_RW(read); + +static struct attribute *xdata_attrs[] = { + &dev_attr_write.attr, + &dev_attr_read.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(xdata); + +static int dw_xdata_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *pid) +{ + struct device *dev = &pdev->dev; + struct dw_xdata *dw; + char name[24]; + u64 addr; + int err; + int id; + + /* Enable PCI device */ + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "enabling device failed\n"); + return err; + } + + /* Mapping PCI BAR regions */ + err = pcim_iomap_regions(pdev, BIT(BAR_0), pci_name(pdev)); + if (err) { + dev_err(dev, "xData BAR I/O remapping failed\n"); + return err; + } + + pci_set_master(pdev); + + /* Allocate memory */ + dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL); + if (!dw) + return -ENOMEM; + + /* Data structure initialization */ + mutex_init(&dw->mutex); + + dw->rg_region.vaddr = pcim_iomap_table(pdev)[BAR_0]; + if (!dw->rg_region.vaddr) + return -ENOMEM; + + dw->rg_region.paddr = pdev->resource[BAR_0].start; + + dw->max_wr_len = pcie_get_mps(pdev); + dw->max_wr_len >>= 2; + + dw->max_rd_len = pcie_get_readrq(pdev); + dw->max_rd_len >>= 2; + + dw->pdev = pdev; + + id = ida_simple_get(&xdata_ida, 0, 0, GFP_KERNEL); + if (id < 0) { + dev_err(dev, "xData: unable to get id\n"); + return id; + } + + snprintf(name, sizeof(name), DW_XDATA_DRIVER_NAME ".%d", id); + dw->misc_dev.name = kstrdup(name, GFP_KERNEL); + if (!dw->misc_dev.name) { + err = -ENOMEM; + goto err_ida_remove; + } + + dw->misc_dev.minor = MISC_DYNAMIC_MINOR; + dw->misc_dev.parent = dev; + dw->misc_dev.groups = xdata_groups; + + writel(0x0, &(__dw_regs(dw)->RAM_addr)); + writel(0x0, &(__dw_regs(dw)->RAM_port)); + + addr = dw->rg_region.paddr + DW_XDATA_EP_MEM_OFFSET; + writel(lower_32_bits(addr), &(__dw_regs(dw)->addr_lsb)); + writel(upper_32_bits(addr), &(__dw_regs(dw)->addr_msb)); + dev_dbg(dev, "xData: target address = 0x%.16llx\n", addr); + + dev_dbg(dev, "xData: wr_len = %zu, rd_len = %zu\n", + dw->max_wr_len * 4, dw->max_rd_len * 4); + + /* Saving data structure reference */ + pci_set_drvdata(pdev, dw); + + /* Register misc device */ + err = misc_register(&dw->misc_dev); + if (err) { + dev_err(dev, "xData: failed to register device\n"); + goto err_kfree_name; + } + + return 0; + +err_kfree_name: + kfree(dw->misc_dev.name); + +err_ida_remove: + ida_simple_remove(&xdata_ida, id); + + return err; +} + +static void dw_xdata_pcie_remove(struct pci_dev *pdev) +{ + struct dw_xdata *dw = pci_get_drvdata(pdev); + int id; + + if (sscanf(dw->misc_dev.name, DW_XDATA_DRIVER_NAME ".%d", &id) != 1) + return; + + if (id < 0) + return; + + dw_xdata_stop(dw); + misc_deregister(&dw->misc_dev); + kfree(dw->misc_dev.name); + ida_simple_remove(&xdata_ida, id); +} + +static const struct pci_device_id dw_xdata_pcie_id_table[] = { + { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, + { } +}; +MODULE_DEVICE_TABLE(pci, dw_xdata_pcie_id_table); + +static struct pci_driver dw_xdata_pcie_driver = { + .name = DW_XDATA_DRIVER_NAME, + .id_table = dw_xdata_pcie_id_table, + .probe = dw_xdata_pcie_probe, + .remove = dw_xdata_pcie_remove, +}; + +module_pci_driver(dw_xdata_pcie_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Synopsys DesignWare xData PCIe driver"); +MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>"); + diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 0db4000dedf203aef289d9c040ae4fb4730df50e..500b1feaf1f6f5a30ec204abb428705a9bec417a 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -316,7 +316,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue, /** * copy_ddcb_results() - Copy output state from real DDCB to request - * @req: pointer to requsted DDCB parameters + * @req: pointer to requested DDCB parameters * @ddcb_no: pointer to ddcb number being tapped * * Copy DDCB ASV to request struct. There is no endian @@ -356,7 +356,7 @@ static void copy_ddcb_results(struct ddcb_requ *req, int ddcb_no) } /** - * genwqe_check_ddcb_queue() - Checks DDCB queue for completed work equests. + * genwqe_check_ddcb_queue() - Checks DDCB queue for completed work requests. * @cd: pointer to genwqe device descriptor * @queue: queue to be checked * @@ -498,7 +498,7 @@ int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) /* * We need to distinguish 3 cases here: - * 1. rc == 0 timeout occured + * 1. rc == 0 timeout occurred * 2. rc == -ERESTARTSYS signal received * 3. rc > 0 remaining jiffies condition is true */ @@ -982,7 +982,7 @@ static int genwqe_next_ddcb_ready(struct genwqe_dev *cd) spin_lock_irqsave(&queue->ddcb_lock, flags); - if (queue_empty(queue)) { /* emtpy queue */ + if (queue_empty(queue)) { /* empty queue */ spin_unlock_irqrestore(&queue->ddcb_lock, flags); return 0; } @@ -1002,7 +1002,7 @@ static int genwqe_next_ddcb_ready(struct genwqe_dev *cd) * @cd: pointer to genwqe device descriptor * * Keep track on the number of DDCBs which ware currently in the - * queue. This is needed for statistics as well as conditon if we want + * queue. This is needed for statistics as well as condition if we want * to wait or better do polling in case of no interrupts available. */ int genwqe_ddcbs_in_flight(struct genwqe_dev *cd) diff --git a/drivers/misc/habanalabs/common/command_buffer.c b/drivers/misc/habanalabs/common/command_buffer.c index d9adb9a5e4d879a8b097b0ea3366f9ab970f7a71..719168c980a45b3aa41626b37d8771ef253a9dcd 100644 --- a/drivers/misc/habanalabs/common/command_buffer.c +++ b/drivers/misc/habanalabs/common/command_buffer.c @@ -181,7 +181,7 @@ static void cb_release(struct kref *ref) static struct hl_cb *hl_cb_alloc(struct hl_device *hdev, u32 cb_size, int ctx_id, bool internal_cb) { - struct hl_cb *cb; + struct hl_cb *cb = NULL; u32 cb_offset; void *p; @@ -193,9 +193,10 @@ static struct hl_cb *hl_cb_alloc(struct hl_device *hdev, u32 cb_size, * the kernel's copy. Hence, we must never sleep in this code section * and must use GFP_ATOMIC for all memory allocations. */ - if (ctx_id == HL_KERNEL_ASID_ID) + if (ctx_id == HL_KERNEL_ASID_ID && !hdev->disabled) cb = kzalloc(sizeof(*cb), GFP_ATOMIC); - else + + if (!cb) cb = kzalloc(sizeof(*cb), GFP_KERNEL); if (!cb) @@ -214,6 +215,9 @@ static struct hl_cb *hl_cb_alloc(struct hl_device *hdev, u32 cb_size, } else if (ctx_id == HL_KERNEL_ASID_ID) { p = hdev->asic_funcs->asic_dma_alloc_coherent(hdev, cb_size, &cb->bus_address, GFP_ATOMIC); + if (!p) + p = hdev->asic_funcs->asic_dma_alloc_coherent(hdev, + cb_size, &cb->bus_address, GFP_KERNEL); } else { p = hdev->asic_funcs->asic_dma_alloc_coherent(hdev, cb_size, &cb->bus_address, @@ -310,6 +314,8 @@ int hl_cb_create(struct hl_device *hdev, struct hl_cb_mgr *mgr, spin_lock(&mgr->cb_lock); rc = idr_alloc(&mgr->cb_handles, cb, 1, 0, GFP_ATOMIC); + if (rc < 0) + rc = idr_alloc(&mgr->cb_handles, cb, 1, 0, GFP_KERNEL); spin_unlock(&mgr->cb_lock); if (rc < 0) { diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 7bd4a03b34291e686ffa20b75f8eba8f8e481dfc..ff8791a651fd1030b7091b709141f367771c2bd3 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -84,6 +84,38 @@ int hl_gen_sob_mask(u16 sob_base, u8 sob_mask, u8 *mask) return 0; } +static void sob_reset_work(struct work_struct *work) +{ + struct hl_cs_compl *hl_cs_cmpl = + container_of(work, struct hl_cs_compl, sob_reset_work); + struct hl_device *hdev = hl_cs_cmpl->hdev; + + /* + * A signal CS can get completion while the corresponding wait + * for signal CS is on its way to the PQ. The wait for signal CS + * will get stuck if the signal CS incremented the SOB to its + * max value and there are no pending (submitted) waits on this + * SOB. + * We do the following to void this situation: + * 1. The wait for signal CS must get a ref for the signal CS as + * soon as possible in cs_ioctl_signal_wait() and put it + * before being submitted to the PQ but after it incremented + * the SOB refcnt in init_signal_wait_cs(). + * 2. Signal/Wait for signal CS will decrement the SOB refcnt + * here. + * These two measures guarantee that the wait for signal CS will + * reset the SOB upon completion rather than the signal CS and + * hence the above scenario is avoided. + */ + kref_put(&hl_cs_cmpl->hw_sob->kref, hl_sob_reset); + + if (hl_cs_cmpl->type == CS_TYPE_COLLECTIVE_WAIT) + hdev->asic_funcs->reset_sob_group(hdev, + hl_cs_cmpl->sob_group); + + kfree(hl_cs_cmpl); +} + static void hl_fence_release(struct kref *kref) { struct hl_fence *fence = @@ -109,28 +141,9 @@ static void hl_fence_release(struct kref *kref) hl_cs_cmpl->hw_sob->sob_id, hl_cs_cmpl->sob_val); - /* - * A signal CS can get completion while the corresponding wait - * for signal CS is on its way to the PQ. The wait for signal CS - * will get stuck if the signal CS incremented the SOB to its - * max value and there are no pending (submitted) waits on this - * SOB. - * We do the following to void this situation: - * 1. The wait for signal CS must get a ref for the signal CS as - * soon as possible in cs_ioctl_signal_wait() and put it - * before being submitted to the PQ but after it incremented - * the SOB refcnt in init_signal_wait_cs(). - * 2. Signal/Wait for signal CS will decrement the SOB refcnt - * here. - * These two measures guarantee that the wait for signal CS will - * reset the SOB upon completion rather than the signal CS and - * hence the above scenario is avoided. - */ - kref_put(&hl_cs_cmpl->hw_sob->kref, hl_sob_reset); + queue_work(hdev->sob_reset_wq, &hl_cs_cmpl->sob_reset_work); - if (hl_cs_cmpl->type == CS_TYPE_COLLECTIVE_WAIT) - hdev->asic_funcs->reset_sob_group(hdev, - hl_cs_cmpl->sob_group); + return; } free: @@ -454,8 +467,7 @@ static void cs_handle_tdr(struct hl_device *hdev, struct hl_cs *cs) if (next_entry_found && !next->tdr_active) { next->tdr_active = true; - schedule_delayed_work(&next->work_tdr, - hdev->timeout_jiffies); + schedule_delayed_work(&next->work_tdr, next->timeout_jiffies); } spin_unlock(&hdev->cs_mirror_lock); @@ -492,24 +504,6 @@ static void cs_do_release(struct kref *ref) goto out; } - hdev->asic_funcs->hw_queues_lock(hdev); - - hdev->cs_active_cnt--; - if (!hdev->cs_active_cnt) { - struct hl_device_idle_busy_ts *ts; - - ts = &hdev->idle_busy_ts_arr[hdev->idle_busy_ts_idx++]; - ts->busy_to_idle_ts = ktime_get(); - - if (hdev->idle_busy_ts_idx == HL_IDLE_BUSY_TS_ARR_SIZE) - hdev->idle_busy_ts_idx = 0; - } else if (hdev->cs_active_cnt < 0) { - dev_crit(hdev->dev, "CS active cnt %d is negative\n", - hdev->cs_active_cnt); - } - - hdev->asic_funcs->hw_queues_unlock(hdev); - /* Need to update CI for all queue jobs that does not get completion */ hl_hw_queue_update_ci(cs); @@ -620,14 +614,14 @@ static void cs_timedout(struct work_struct *work) cs_put(cs); if (hdev->reset_on_lockup) - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); else hdev->needs_reset = true; } static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, enum hl_cs_type cs_type, u64 user_sequence, - struct hl_cs **cs_new) + struct hl_cs **cs_new, u32 flags, u32 timeout) { struct hl_cs_counters_atomic *cntr; struct hl_fence *other = NULL; @@ -638,6 +632,9 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cntr = &hdev->aggregated_cs_counters; cs = kzalloc(sizeof(*cs), GFP_ATOMIC); + if (!cs) + cs = kzalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -651,12 +648,17 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cs->submitted = false; cs->completed = false; cs->type = cs_type; + cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP); + cs->timeout_jiffies = timeout; INIT_LIST_HEAD(&cs->job_list); INIT_DELAYED_WORK(&cs->work_tdr, cs_timedout); kref_init(&cs->refcount); spin_lock_init(&cs->job_lock); cs_cmpl = kmalloc(sizeof(*cs_cmpl), GFP_ATOMIC); + if (!cs_cmpl) + cs_cmpl = kmalloc(sizeof(*cs_cmpl), GFP_KERNEL); + if (!cs_cmpl) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -664,9 +666,23 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, goto free_cs; } + cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, + sizeof(*cs->jobs_in_queue_cnt), GFP_ATOMIC); + if (!cs->jobs_in_queue_cnt) + cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, + sizeof(*cs->jobs_in_queue_cnt), GFP_KERNEL); + + if (!cs->jobs_in_queue_cnt) { + atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); + atomic64_inc(&cntr->out_of_mem_drop_cnt); + rc = -ENOMEM; + goto free_cs_cmpl; + } + cs_cmpl->hdev = hdev; cs_cmpl->type = cs->type; spin_lock_init(&cs_cmpl->lock); + INIT_WORK(&cs_cmpl->sob_reset_work, sob_reset_work); cs->fence = &cs_cmpl->base_fence; spin_lock(&ctx->cs_lock); @@ -696,15 +712,6 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, goto free_fence; } - cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, - sizeof(*cs->jobs_in_queue_cnt), GFP_ATOMIC); - if (!cs->jobs_in_queue_cnt) { - atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); - atomic64_inc(&cntr->out_of_mem_drop_cnt); - rc = -ENOMEM; - goto free_fence; - } - /* init hl_fence */ hl_fence_init(&cs_cmpl->base_fence, cs_cmpl->cs_seq); @@ -727,6 +734,8 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, free_fence: spin_unlock(&ctx->cs_lock); + kfree(cs->jobs_in_queue_cnt); +free_cs_cmpl: kfree(cs_cmpl); free_cs: kfree(cs); @@ -749,6 +758,8 @@ void hl_cs_rollback_all(struct hl_device *hdev) int i; struct hl_cs *cs, *tmp; + flush_workqueue(hdev->sob_reset_wq); + /* flush all completions before iterating over the CS mirror list in * order to avoid a race with the release functions */ @@ -778,6 +789,44 @@ void hl_pending_cb_list_flush(struct hl_ctx *ctx) } } +static void +wake_pending_user_interrupt_threads(struct hl_user_interrupt *interrupt) +{ + struct hl_user_pending_interrupt *pend; + + spin_lock(&interrupt->wait_list_lock); + list_for_each_entry(pend, &interrupt->wait_list_head, wait_list_node) { + pend->fence.error = -EIO; + complete_all(&pend->fence.completion); + } + spin_unlock(&interrupt->wait_list_lock); +} + +void hl_release_pending_user_interrupts(struct hl_device *hdev) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + struct hl_user_interrupt *interrupt; + int i; + + if (!prop->user_interrupt_count) + return; + + /* We iterate through the user interrupt requests and waking up all + * user threads waiting for interrupt completion. We iterate the + * list under a lock, this is why all user threads, once awake, + * will wait on the same lock and will release the waiting object upon + * unlock. + */ + + for (i = 0 ; i < prop->user_interrupt_count ; i++) { + interrupt = &hdev->user_interrupt[i]; + wake_pending_user_interrupt_threads(interrupt); + } + + interrupt = &hdev->common_user_interrupt; + wake_pending_user_interrupt_threads(interrupt); +} + static void job_wq_completion(struct work_struct *work) { struct hl_cs_job *job = container_of(work, struct hl_cs_job, @@ -889,6 +938,9 @@ struct hl_cs_job *hl_cs_allocate_job(struct hl_device *hdev, struct hl_cs_job *job; job = kzalloc(sizeof(*job), GFP_ATOMIC); + if (!job) + job = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) return NULL; @@ -991,6 +1043,9 @@ static int hl_cs_copy_chunk_array(struct hl_device *hdev, *cs_chunk_array = kmalloc_array(num_chunks, sizeof(**cs_chunk_array), GFP_ATOMIC); + if (!*cs_chunk_array) + *cs_chunk_array = kmalloc_array(num_chunks, + sizeof(**cs_chunk_array), GFP_KERNEL); if (!*cs_chunk_array) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&hdev->aggregated_cs_counters.out_of_mem_drop_cnt); @@ -1038,7 +1093,8 @@ static int cs_staged_submission(struct hl_device *hdev, struct hl_cs *cs, } static int cs_ioctl_default(struct hl_fpriv *hpriv, void __user *chunks, - u32 num_chunks, u64 *cs_seq, u32 flags) + u32 num_chunks, u64 *cs_seq, u32 flags, + u32 timeout) { bool staged_mid, int_queues_only = true; struct hl_device *hdev = hpriv->hdev; @@ -1067,11 +1123,11 @@ static int cs_ioctl_default(struct hl_fpriv *hpriv, void __user *chunks, staged_mid = false; rc = allocate_cs(hdev, hpriv->ctx, CS_TYPE_DEFAULT, - staged_mid ? user_sequence : ULLONG_MAX, &cs); + staged_mid ? user_sequence : ULLONG_MAX, &cs, flags, + timeout); if (rc) goto free_cs_chunk_array; - cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP); *cs_seq = cs->sequence; hl_debugfs_add_cs(cs); @@ -1269,7 +1325,8 @@ static int hl_submit_pending_cb(struct hl_fpriv *hpriv) list_move_tail(&pending_cb->cb_node, &local_cb_list); spin_unlock(&ctx->pending_cb_lock); - rc = allocate_cs(hdev, ctx, CS_TYPE_DEFAULT, ULLONG_MAX, &cs); + rc = allocate_cs(hdev, ctx, CS_TYPE_DEFAULT, ULLONG_MAX, &cs, 0, + hdev->timeout_jiffies); if (rc) goto add_list_elements; @@ -1370,7 +1427,7 @@ static int hl_cs_ctx_switch(struct hl_fpriv *hpriv, union hl_cs_args *args, rc = 0; } else { rc = cs_ioctl_default(hpriv, chunks, num_chunks, - cs_seq, 0); + cs_seq, 0, hdev->timeout_jiffies); } mutex_unlock(&hpriv->restore_phase_mutex); @@ -1419,7 +1476,7 @@ wait_again: out: if ((rc == -ETIMEDOUT || rc == -EBUSY) && (need_soft_reset)) - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); return rc; } @@ -1445,6 +1502,10 @@ static int cs_ioctl_extract_signal_seq(struct hl_device *hdev, signal_seq_arr = kmalloc_array(signal_seq_arr_len, sizeof(*signal_seq_arr), GFP_ATOMIC); + if (!signal_seq_arr) + signal_seq_arr = kmalloc_array(signal_seq_arr_len, + sizeof(*signal_seq_arr), + GFP_KERNEL); if (!signal_seq_arr) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&hdev->aggregated_cs_counters.out_of_mem_drop_cnt); @@ -1536,7 +1597,7 @@ static int cs_ioctl_signal_wait_create_jobs(struct hl_device *hdev, static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, void __user *chunks, u32 num_chunks, - u64 *cs_seq, bool timestamp) + u64 *cs_seq, u32 flags, u32 timeout) { struct hl_cs_chunk *cs_chunk_array, *chunk; struct hw_queue_properties *hw_queue_prop; @@ -1642,7 +1703,7 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, } } - rc = allocate_cs(hdev, ctx, cs_type, ULLONG_MAX, &cs); + rc = allocate_cs(hdev, ctx, cs_type, ULLONG_MAX, &cs, flags, timeout); if (rc) { if (cs_type == CS_TYPE_WAIT || cs_type == CS_TYPE_COLLECTIVE_WAIT) @@ -1650,8 +1711,6 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, goto free_cs_chunk_array; } - cs->timestamp = !!timestamp; - /* * Save the signal CS fence for later initialization right before * hanging the wait CS on the queue. @@ -1709,7 +1768,7 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data) enum hl_cs_type cs_type; u64 cs_seq = ULONG_MAX; void __user *chunks; - u32 num_chunks, flags; + u32 num_chunks, flags, timeout; int rc; rc = hl_cs_sanity_checks(hpriv, args); @@ -1735,16 +1794,20 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data) !(flags & HL_CS_FLAGS_STAGED_SUBMISSION_FIRST)) cs_seq = args->in.seq; + timeout = flags & HL_CS_FLAGS_CUSTOM_TIMEOUT + ? msecs_to_jiffies(args->in.timeout * 1000) + : hpriv->hdev->timeout_jiffies; + switch (cs_type) { case CS_TYPE_SIGNAL: case CS_TYPE_WAIT: case CS_TYPE_COLLECTIVE_WAIT: rc = cs_ioctl_signal_wait(hpriv, cs_type, chunks, num_chunks, - &cs_seq, args->in.cs_flags & HL_CS_FLAGS_TIMESTAMP); + &cs_seq, args->in.cs_flags, timeout); break; default: rc = cs_ioctl_default(hpriv, chunks, num_chunks, &cs_seq, - args->in.cs_flags); + args->in.cs_flags, timeout); break; } @@ -1818,7 +1881,7 @@ static int _hl_cs_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, return rc; } -int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) +static int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) { struct hl_device *hdev = hpriv->hdev; union hl_wait_cs_args *args = data; @@ -1873,3 +1936,176 @@ int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) return 0; } + +static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, + u32 timeout_us, u64 user_address, + u32 target_value, u16 interrupt_offset, + enum hl_cs_wait_status *status) +{ + struct hl_user_pending_interrupt *pend; + struct hl_user_interrupt *interrupt; + unsigned long timeout; + long completion_rc; + u32 completion_value; + int rc = 0; + + if (timeout_us == U32_MAX) + timeout = timeout_us; + else + timeout = usecs_to_jiffies(timeout_us); + + hl_ctx_get(hdev, ctx); + + pend = kmalloc(sizeof(*pend), GFP_KERNEL); + if (!pend) { + hl_ctx_put(ctx); + return -ENOMEM; + } + + hl_fence_init(&pend->fence, ULONG_MAX); + + if (interrupt_offset == HL_COMMON_USER_INTERRUPT_ID) + interrupt = &hdev->common_user_interrupt; + else + interrupt = &hdev->user_interrupt[interrupt_offset]; + + spin_lock(&interrupt->wait_list_lock); + if (!hl_device_operational(hdev, NULL)) { + rc = -EPERM; + goto unlock_and_free_fence; + } + + if (copy_from_user(&completion_value, u64_to_user_ptr(user_address), 4)) { + dev_err(hdev->dev, + "Failed to copy completion value from user\n"); + rc = -EFAULT; + goto unlock_and_free_fence; + } + + if (completion_value >= target_value) + *status = CS_WAIT_STATUS_COMPLETED; + else + *status = CS_WAIT_STATUS_BUSY; + + if (!timeout_us || (*status == CS_WAIT_STATUS_COMPLETED)) + goto unlock_and_free_fence; + + /* Add pending user interrupt to relevant list for the interrupt + * handler to monitor + */ + list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head); + spin_unlock(&interrupt->wait_list_lock); + +wait_again: + /* Wait for interrupt handler to signal completion */ + completion_rc = + wait_for_completion_interruptible_timeout( + &pend->fence.completion, timeout); + + /* If timeout did not expire we need to perform the comparison. + * If comparison fails, keep waiting until timeout expires + */ + if (completion_rc > 0) { + if (copy_from_user(&completion_value, + u64_to_user_ptr(user_address), 4)) { + dev_err(hdev->dev, + "Failed to copy completion value from user\n"); + rc = -EFAULT; + goto remove_pending_user_interrupt; + } + + if (completion_value >= target_value) { + *status = CS_WAIT_STATUS_COMPLETED; + } else { + timeout -= jiffies_to_usecs(completion_rc); + goto wait_again; + } + } else { + *status = CS_WAIT_STATUS_BUSY; + } + +remove_pending_user_interrupt: + spin_lock(&interrupt->wait_list_lock); + list_del(&pend->wait_list_node); + +unlock_and_free_fence: + spin_unlock(&interrupt->wait_list_lock); + kfree(pend); + hl_ctx_put(ctx); + + return rc; +} + +static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data) +{ + u16 interrupt_id, interrupt_offset, first_interrupt, last_interrupt; + struct hl_device *hdev = hpriv->hdev; + struct asic_fixed_properties *prop; + union hl_wait_cs_args *args = data; + enum hl_cs_wait_status status; + int rc; + + prop = &hdev->asic_prop; + + if (!prop->user_interrupt_count) { + dev_err(hdev->dev, "no user interrupts allowed"); + return -EPERM; + } + + interrupt_id = + FIELD_GET(HL_WAIT_CS_FLAGS_INTERRUPT_MASK, args->in.flags); + + first_interrupt = prop->first_available_user_msix_interrupt; + last_interrupt = prop->first_available_user_msix_interrupt + + prop->user_interrupt_count - 1; + + if ((interrupt_id < first_interrupt || interrupt_id > last_interrupt) && + interrupt_id != HL_COMMON_USER_INTERRUPT_ID) { + dev_err(hdev->dev, "invalid user interrupt %u", interrupt_id); + return -EINVAL; + } + + if (interrupt_id == HL_COMMON_USER_INTERRUPT_ID) + interrupt_offset = HL_COMMON_USER_INTERRUPT_ID; + else + interrupt_offset = interrupt_id - first_interrupt; + + rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx, + args->in.interrupt_timeout_us, args->in.addr, + args->in.target, interrupt_offset, &status); + + memset(args, 0, sizeof(*args)); + + if (rc) { + dev_err_ratelimited(hdev->dev, + "interrupt_wait_ioctl failed (%d)\n", rc); + + return rc; + } + + switch (status) { + case CS_WAIT_STATUS_COMPLETED: + args->out.status = HL_WAIT_CS_STATUS_COMPLETED; + break; + case CS_WAIT_STATUS_BUSY: + default: + args->out.status = HL_WAIT_CS_STATUS_BUSY; + break; + } + + return 0; +} + +int hl_wait_ioctl(struct hl_fpriv *hpriv, void *data) +{ + union hl_wait_cs_args *args = data; + u32 flags = args->in.flags; + int rc; + + if (flags & HL_WAIT_CS_FLAGS_INTERRUPT) + rc = hl_interrupt_wait_ioctl(hpriv, data); + else + rc = hl_cs_wait_ioctl(hpriv, data); + + return rc; +} diff --git a/drivers/misc/habanalabs/common/context.c b/drivers/misc/habanalabs/common/context.c index cda871afb8f4224531fd29679ef8d4ea60a6e35d..62d705889ca87d941f83eccd3946bb74dcff302c 100644 --- a/drivers/misc/habanalabs/common/context.c +++ b/drivers/misc/habanalabs/common/context.c @@ -20,6 +20,11 @@ static void hl_ctx_fini(struct hl_ctx *ctx) */ hl_pending_cb_list_flush(ctx); + /* Release all allocated HW block mapped list entries and destroy + * the mutex. + */ + hl_hw_block_mem_fini(ctx); + /* * If we arrived here, there are no jobs waiting for this context * on its queues so we can safely remove it. @@ -160,13 +165,15 @@ int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx) if (!ctx->cs_pending) return -ENOMEM; + hl_hw_block_mem_init(ctx); + if (is_kernel_ctx) { ctx->asid = HL_KERNEL_ASID_ID; /* Kernel driver gets ASID 0 */ rc = hl_vm_ctx_init(ctx); if (rc) { dev_err(hdev->dev, "Failed to init mem ctx module\n"); rc = -ENOMEM; - goto err_free_cs_pending; + goto err_hw_block_mem_fini; } rc = hdev->asic_funcs->ctx_init(ctx); @@ -179,7 +186,7 @@ int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx) if (!ctx->asid) { dev_err(hdev->dev, "No free ASID, failed to create context\n"); rc = -ENOMEM; - goto err_free_cs_pending; + goto err_hw_block_mem_fini; } rc = hl_vm_ctx_init(ctx); @@ -214,7 +221,8 @@ err_vm_ctx_fini: err_asid_free: if (ctx->asid != HL_KERNEL_ASID_ID) hl_asid_free(hdev, ctx->asid); -err_free_cs_pending: +err_hw_block_mem_fini: + hl_hw_block_mem_fini(ctx); kfree(ctx->cs_pending); return rc; diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 9f19bee7b592214e1404efda1b93a3734d9b16b5..8381155578a0875dd990208022d6c38620fbf053 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -9,8 +9,8 @@ #include "../include/hw_ip/mmu/mmu_general.h" #include <linux/pci.h> -#include <linux/debugfs.h> #include <linux/uaccess.h> +#include <linux/vmalloc.h> #define MMU_ADDR_BUF_SIZE 40 #define MMU_ASID_BUF_SIZE 10 @@ -229,6 +229,7 @@ static int vm_show(struct seq_file *s, void *data) { struct hl_debugfs_entry *entry = s->private; struct hl_dbg_device_entry *dev_entry = entry->dev_entry; + struct hl_vm_hw_block_list_node *lnode; struct hl_ctx *ctx; struct hl_vm *vm; struct hl_vm_hash_node *hnode; @@ -272,6 +273,21 @@ static int vm_show(struct seq_file *s, void *data) } mutex_unlock(&ctx->mem_hash_lock); + if (ctx->asid != HL_KERNEL_ASID_ID && + !list_empty(&ctx->hw_block_mem_list)) { + seq_puts(s, "\nhw_block mappings:\n\n"); + seq_puts(s, " virtual address size HW block id\n"); + seq_puts(s, "-------------------------------------------\n"); + mutex_lock(&ctx->hw_block_list_lock); + list_for_each_entry(lnode, &ctx->hw_block_mem_list, + node) { + seq_printf(s, + " 0x%-14lx %-6u %-9u\n", + lnode->vaddr, lnode->size, lnode->id); + } + mutex_unlock(&ctx->hw_block_list_lock); + } + vm = &ctx->hdev->vm; spin_lock(&vm->idr_lock); @@ -441,21 +457,86 @@ out: return false; } -static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr, - u64 *phys_addr) +static bool hl_is_device_internal_memory_va(struct hl_device *hdev, u64 addr, + u32 size) { + struct asic_fixed_properties *prop = &hdev->asic_prop; + u64 dram_start_addr, dram_end_addr; + + if (!hdev->mmu_enable) + return false; + + if (prop->dram_supports_virtual_memory) { + dram_start_addr = prop->dmmu.start_addr; + dram_end_addr = prop->dmmu.end_addr; + } else { + dram_start_addr = prop->dram_base_address; + dram_end_addr = prop->dram_end_address; + } + + if (hl_mem_area_inside_range(addr, size, dram_start_addr, + dram_end_addr)) + return true; + + if (hl_mem_area_inside_range(addr, size, prop->sram_base_address, + prop->sram_end_address)) + return true; + + return false; +} + +static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr, u32 size, + u64 *phys_addr) +{ + struct hl_vm_phys_pg_pack *phys_pg_pack; struct hl_ctx *ctx = hdev->compute_ctx; - int rc = 0; + struct hl_vm_hash_node *hnode; + struct hl_userptr *userptr; + enum vm_type_t *vm_type; + bool valid = false; + u64 end_address; + u32 range_size; + int i, rc = 0; if (!ctx) { dev_err(hdev->dev, "no ctx available\n"); return -EINVAL; } + /* Verify address is mapped */ + mutex_lock(&ctx->mem_hash_lock); + hash_for_each(ctx->mem_hash, i, hnode, node) { + vm_type = hnode->ptr; + + if (*vm_type == VM_TYPE_USERPTR) { + userptr = hnode->ptr; + range_size = userptr->size; + } else { + phys_pg_pack = hnode->ptr; + range_size = phys_pg_pack->total_size; + } + + end_address = virt_addr + size; + if ((virt_addr >= hnode->vaddr) && + (end_address <= hnode->vaddr + range_size)) { + valid = true; + break; + } + } + mutex_unlock(&ctx->mem_hash_lock); + + if (!valid) { + dev_err(hdev->dev, + "virt addr 0x%llx is not mapped\n", + virt_addr); + return -EINVAL; + } + rc = hl_mmu_va_to_pa(ctx, virt_addr, phys_addr); if (rc) { - dev_err(hdev->dev, "virt addr 0x%llx is not mapped to phys addr\n", - virt_addr); + dev_err(hdev->dev, + "virt addr 0x%llx is not mapped to phys addr\n", + virt_addr); rc = -EINVAL; } @@ -467,10 +548,11 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf, { struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; - char tmp_buf[32]; u64 addr = entry->addr; - u32 val; + bool user_address; + char tmp_buf[32]; ssize_t rc; + u32 val; if (atomic_read(&hdev->in_reset)) { dev_warn_ratelimited(hdev->dev, "Can't read during reset\n"); @@ -480,13 +562,14 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf, if (*ppos) return 0; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(val), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_read32(hdev, addr, &val); + rc = hdev->asic_funcs->debugfs_read32(hdev, addr, user_address, &val); if (rc) { dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr); return rc; @@ -503,6 +586,7 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf, struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; u64 addr = entry->addr; + bool user_address; u32 value; ssize_t rc; @@ -515,13 +599,14 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf, if (rc) return rc; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(value), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_write32(hdev, addr, value); + rc = hdev->asic_funcs->debugfs_write32(hdev, addr, user_address, value); if (rc) { dev_err(hdev->dev, "Failed to write 0x%08x to 0x%010llx\n", value, addr); @@ -536,21 +621,28 @@ static ssize_t hl_data_read64(struct file *f, char __user *buf, { struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; - char tmp_buf[32]; u64 addr = entry->addr; - u64 val; + bool user_address; + char tmp_buf[32]; ssize_t rc; + u64 val; + + if (atomic_read(&hdev->in_reset)) { + dev_warn_ratelimited(hdev->dev, "Can't read during reset\n"); + return 0; + } if (*ppos) return 0; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(val), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_read64(hdev, addr, &val); + rc = hdev->asic_funcs->debugfs_read64(hdev, addr, user_address, &val); if (rc) { dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr); return rc; @@ -567,20 +659,27 @@ static ssize_t hl_data_write64(struct file *f, const char __user *buf, struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; u64 addr = entry->addr; + bool user_address; u64 value; ssize_t rc; + if (atomic_read(&hdev->in_reset)) { + dev_warn_ratelimited(hdev->dev, "Can't write during reset\n"); + return 0; + } + rc = kstrtoull_from_user(buf, count, 16, &value); if (rc) return rc; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(value), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_write64(hdev, addr, value); + rc = hdev->asic_funcs->debugfs_write64(hdev, addr, user_address, value); if (rc) { dev_err(hdev->dev, "Failed to write 0x%016llx to 0x%010llx\n", value, addr); @@ -590,6 +689,63 @@ static ssize_t hl_data_write64(struct file *f, const char __user *buf, return count; } +static ssize_t hl_dma_size_write(struct file *f, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct hl_dbg_device_entry *entry = file_inode(f)->i_private; + struct hl_device *hdev = entry->hdev; + u64 addr = entry->addr; + ssize_t rc; + u32 size; + + if (atomic_read(&hdev->in_reset)) { + dev_warn_ratelimited(hdev->dev, "Can't DMA during reset\n"); + return 0; + } + rc = kstrtouint_from_user(buf, count, 16, &size); + if (rc) + return rc; + + if (!size) { + dev_err(hdev->dev, "DMA read failed. size can't be 0\n"); + return -EINVAL; + } + + if (size > SZ_128M) { + dev_err(hdev->dev, + "DMA read failed. size can't be larger than 128MB\n"); + return -EINVAL; + } + + if (!hl_is_device_internal_memory_va(hdev, addr, size)) { + dev_err(hdev->dev, + "DMA read failed. Invalid 0x%010llx + 0x%08x\n", + addr, size); + return -EINVAL; + } + + /* Free the previous allocation, if there was any */ + entry->blob_desc.size = 0; + vfree(entry->blob_desc.data); + + entry->blob_desc.data = vmalloc(size); + if (!entry->blob_desc.data) + return -ENOMEM; + + rc = hdev->asic_funcs->debugfs_read_dma(hdev, addr, size, + entry->blob_desc.data); + if (rc) { + dev_err(hdev->dev, "Failed to DMA from 0x%010llx\n", addr); + vfree(entry->blob_desc.data); + entry->blob_desc.data = NULL; + return -EIO; + } + + entry->blob_desc.size = size; + + return count; +} + static ssize_t hl_get_power_state(struct file *f, char __user *buf, size_t count, loff_t *ppos) { @@ -871,7 +1027,7 @@ static ssize_t hl_stop_on_err_write(struct file *f, const char __user *buf, hdev->stop_on_err = value ? 1 : 0; - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); return count; } @@ -899,6 +1055,11 @@ static const struct file_operations hl_data64b_fops = { .write = hl_data_write64 }; +static const struct file_operations hl_dma_size_fops = { + .owner = THIS_MODULE, + .write = hl_dma_size_write +}; + static const struct file_operations hl_i2c_data_fops = { .owner = THIS_MODULE, .read = hl_i2c_data_read, @@ -1001,6 +1162,9 @@ void hl_debugfs_add_device(struct hl_device *hdev) if (!dev_entry->entry_arr) return; + dev_entry->blob_desc.size = 0; + dev_entry->blob_desc.data = NULL; + INIT_LIST_HEAD(&dev_entry->file_list); INIT_LIST_HEAD(&dev_entry->cb_list); INIT_LIST_HEAD(&dev_entry->cs_list); @@ -1103,6 +1267,17 @@ void hl_debugfs_add_device(struct hl_device *hdev) dev_entry, &hl_security_violations_fops); + debugfs_create_file("dma_size", + 0200, + dev_entry->root, + dev_entry, + &hl_dma_size_fops); + + debugfs_create_blob("data_dma", + 0400, + dev_entry->root, + &dev_entry->blob_desc); + for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) { debugfs_create_file(hl_debugfs_list[i].name, 0444, @@ -1121,6 +1296,9 @@ void hl_debugfs_remove_device(struct hl_device *hdev) debugfs_remove_recursive(entry->root); mutex_destroy(&entry->file_mutex); + + vfree(entry->blob_desc.data); + kfree(entry->entry_arr); } diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 334009e83823677b3779b805add6134c6783889e..00e92b6788284eaf293f8e2d55bc966c7f3d2528 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -70,6 +70,9 @@ static void hpriv_release(struct kref *ref) mutex_unlock(&hdev->fpriv_list_lock); kfree(hpriv); + + if (hdev->reset_upon_device_release) + hl_device_reset(hdev, 0); } void hl_hpriv_get(struct hl_fpriv *hpriv) @@ -77,9 +80,9 @@ void hl_hpriv_get(struct hl_fpriv *hpriv) kref_get(&hpriv->refcount); } -void hl_hpriv_put(struct hl_fpriv *hpriv) +int hl_hpriv_put(struct hl_fpriv *hpriv) { - kref_put(&hpriv->refcount, hpriv_release); + return kref_put(&hpriv->refcount, hpriv_release); } /* @@ -103,10 +106,17 @@ static int hl_device_release(struct inode *inode, struct file *filp) return 0; } - hl_cb_mgr_fini(hpriv->hdev, &hpriv->cb_mgr); - hl_ctx_mgr_fini(hpriv->hdev, &hpriv->ctx_mgr); + /* Each pending user interrupt holds the user's context, hence we + * must release them all before calling hl_ctx_mgr_fini(). + */ + hl_release_pending_user_interrupts(hpriv->hdev); + + hl_cb_mgr_fini(hdev, &hpriv->cb_mgr); + hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); - hl_hpriv_put(hpriv); + if (!hl_hpriv_put(hpriv)) + dev_warn(hdev->dev, + "Device is still in use because there are live CS and/or memory mappings\n"); return 0; } @@ -283,7 +293,7 @@ static void device_hard_reset_pending(struct work_struct *work) struct hl_device *hdev = device_reset_work->hdev; int rc; - rc = hl_device_reset(hdev, true, true); + rc = hl_device_reset(hdev, HL_RESET_HARD | HL_RESET_FROM_RESET_THREAD); if ((rc == -EBUSY) && !hdev->device_fini_pending) { dev_info(hdev->dev, "Could not reset device. will try again in %u seconds", @@ -311,11 +321,15 @@ static int device_early_init(struct hl_device *hdev) switch (hdev->asic_type) { case ASIC_GOYA: goya_set_asic_funcs(hdev); - strlcpy(hdev->asic_name, "GOYA", sizeof(hdev->asic_name)); + strscpy(hdev->asic_name, "GOYA", sizeof(hdev->asic_name)); break; case ASIC_GAUDI: gaudi_set_asic_funcs(hdev); - sprintf(hdev->asic_name, "GAUDI"); + strscpy(hdev->asic_name, "GAUDI", sizeof(hdev->asic_name)); + break; + case ASIC_GAUDI_SEC: + gaudi_set_asic_funcs(hdev); + strscpy(hdev->asic_name, "GAUDI SEC", sizeof(hdev->asic_name)); break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", @@ -334,7 +348,7 @@ static int device_early_init(struct hl_device *hdev) if (hdev->asic_prop.completion_queues_count) { hdev->cq_wq = kcalloc(hdev->asic_prop.completion_queues_count, sizeof(*hdev->cq_wq), - GFP_ATOMIC); + GFP_KERNEL); if (!hdev->cq_wq) { rc = -ENOMEM; goto asid_fini; @@ -358,24 +372,24 @@ static int device_early_init(struct hl_device *hdev) goto free_cq_wq; } - hdev->hl_chip_info = kzalloc(sizeof(struct hwmon_chip_info), - GFP_KERNEL); - if (!hdev->hl_chip_info) { + hdev->sob_reset_wq = alloc_workqueue("hl-sob-reset", WQ_UNBOUND, 0); + if (!hdev->sob_reset_wq) { + dev_err(hdev->dev, + "Failed to allocate SOB reset workqueue\n"); rc = -ENOMEM; goto free_eq_wq; } - hdev->idle_busy_ts_arr = kmalloc_array(HL_IDLE_BUSY_TS_ARR_SIZE, - sizeof(struct hl_device_idle_busy_ts), - (GFP_KERNEL | __GFP_ZERO)); - if (!hdev->idle_busy_ts_arr) { + hdev->hl_chip_info = kzalloc(sizeof(struct hwmon_chip_info), + GFP_KERNEL); + if (!hdev->hl_chip_info) { rc = -ENOMEM; - goto free_chip_info; + goto free_sob_reset_wq; } rc = hl_mmu_if_set_funcs(hdev); if (rc) - goto free_idle_busy_ts_arr; + goto free_chip_info; hl_cb_mgr_init(&hdev->kernel_cb_mgr); @@ -404,10 +418,10 @@ static int device_early_init(struct hl_device *hdev) free_cb_mgr: hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); -free_idle_busy_ts_arr: - kfree(hdev->idle_busy_ts_arr); free_chip_info: kfree(hdev->hl_chip_info); +free_sob_reset_wq: + destroy_workqueue(hdev->sob_reset_wq); free_eq_wq: destroy_workqueue(hdev->eq_wq); free_cq_wq: @@ -441,9 +455,9 @@ static void device_early_fini(struct hl_device *hdev) hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); - kfree(hdev->idle_busy_ts_arr); kfree(hdev->hl_chip_info); + destroy_workqueue(hdev->sob_reset_wq); destroy_workqueue(hdev->eq_wq); destroy_workqueue(hdev->device_reset_work.wq); @@ -485,7 +499,7 @@ static void hl_device_heartbeat(struct work_struct *work) goto reschedule; dev_err(hdev->dev, "Device heartbeat failed!\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD | HL_RESET_HEARTBEAT); return; @@ -561,100 +575,24 @@ static void device_late_fini(struct hl_device *hdev) hdev->late_init_done = false; } -uint32_t hl_device_utilization(struct hl_device *hdev, uint32_t period_ms) +int hl_device_utilization(struct hl_device *hdev, u32 *utilization) { - struct hl_device_idle_busy_ts *ts; - ktime_t zero_ktime, curr = ktime_get(); - u32 overlap_cnt = 0, last_index = hdev->idle_busy_ts_idx; - s64 period_us, last_start_us, last_end_us, last_busy_time_us, - total_busy_time_us = 0, total_busy_time_ms; - - zero_ktime = ktime_set(0, 0); - period_us = period_ms * USEC_PER_MSEC; - ts = &hdev->idle_busy_ts_arr[last_index]; - - /* check case that device is currently in idle */ - if (!ktime_compare(ts->busy_to_idle_ts, zero_ktime) && - !ktime_compare(ts->idle_to_busy_ts, zero_ktime)) { - - last_index--; - /* Handle case idle_busy_ts_idx was 0 */ - if (last_index > HL_IDLE_BUSY_TS_ARR_SIZE) - last_index = HL_IDLE_BUSY_TS_ARR_SIZE - 1; - - ts = &hdev->idle_busy_ts_arr[last_index]; - } - - while (overlap_cnt < HL_IDLE_BUSY_TS_ARR_SIZE) { - /* Check if we are in last sample case. i.e. if the sample - * begun before the sampling period. This could be a real - * sample or 0 so need to handle both cases - */ - last_start_us = ktime_to_us( - ktime_sub(curr, ts->idle_to_busy_ts)); - - if (last_start_us > period_us) { - - /* First check two cases: - * 1. If the device is currently busy - * 2. If the device was idle during the whole sampling - * period - */ - - if (!ktime_compare(ts->busy_to_idle_ts, zero_ktime)) { - /* Check if the device is currently busy */ - if (ktime_compare(ts->idle_to_busy_ts, - zero_ktime)) - return 100; - - /* We either didn't have any activity or we - * reached an entry which is 0. Either way, - * exit and return what was accumulated so far - */ - break; - } - - /* If sample has finished, check it is relevant */ - last_end_us = ktime_to_us( - ktime_sub(curr, ts->busy_to_idle_ts)); - - if (last_end_us > period_us) - break; - - /* It is relevant so add it but with adjustment */ - last_busy_time_us = ktime_to_us( - ktime_sub(ts->busy_to_idle_ts, - ts->idle_to_busy_ts)); - total_busy_time_us += last_busy_time_us - - (last_start_us - period_us); - break; - } - - /* Check if the sample is finished or still open */ - if (ktime_compare(ts->busy_to_idle_ts, zero_ktime)) - last_busy_time_us = ktime_to_us( - ktime_sub(ts->busy_to_idle_ts, - ts->idle_to_busy_ts)); - else - last_busy_time_us = ktime_to_us( - ktime_sub(curr, ts->idle_to_busy_ts)); - - total_busy_time_us += last_busy_time_us; + u64 max_power, curr_power, dc_power, dividend; + int rc; - last_index--; - /* Handle case idle_busy_ts_idx was 0 */ - if (last_index > HL_IDLE_BUSY_TS_ARR_SIZE) - last_index = HL_IDLE_BUSY_TS_ARR_SIZE - 1; + max_power = hdev->asic_prop.max_power_default; + dc_power = hdev->asic_prop.dc_power_default; + rc = hl_fw_cpucp_power_get(hdev, &curr_power); - ts = &hdev->idle_busy_ts_arr[last_index]; + if (rc) + return rc; - overlap_cnt++; - } + curr_power = clamp(curr_power, dc_power, max_power); - total_busy_time_ms = DIV_ROUND_UP_ULL(total_busy_time_us, - USEC_PER_MSEC); + dividend = (curr_power - dc_power) * 100; + *utilization = (u32) div_u64(dividend, (max_power - dc_power)); - return DIV_ROUND_UP_ULL(total_busy_time_ms * 100, period_ms); + return 0; } /* @@ -809,7 +747,7 @@ int hl_device_resume(struct hl_device *hdev) hdev->disabled = false; atomic_set(&hdev->in_reset, 0); - rc = hl_device_reset(hdev, true, false); + rc = hl_device_reset(hdev, HL_RESET_HARD); if (rc) { dev_err(hdev->dev, "Failed to reset device during resume\n"); goto disable_device; @@ -915,9 +853,7 @@ static void device_disable_open_processes(struct hl_device *hdev) * hl_device_reset - reset the device * * @hdev: pointer to habanalabs device structure - * @hard_reset: should we do hard reset to all engines or just reset the - * compute/dma engines - * @from_hard_reset_thread: is the caller the hard-reset thread + * @flags: reset flags. * * Block future CS and wait for pending CS to be enqueued * Call ASIC H/W fini @@ -929,9 +865,10 @@ static void device_disable_open_processes(struct hl_device *hdev) * * Returns 0 for success or an error on failure. */ -int hl_device_reset(struct hl_device *hdev, bool hard_reset, - bool from_hard_reset_thread) +int hl_device_reset(struct hl_device *hdev, u32 flags) { + u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; + bool hard_reset, from_hard_reset_thread; int i, rc; if (!hdev->init_done) { @@ -940,6 +877,9 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset, return 0; } + hard_reset = (flags & HL_RESET_HARD) != 0; + from_hard_reset_thread = (flags & HL_RESET_FROM_RESET_THREAD) != 0; + if ((!hard_reset) && (!hdev->supports_soft_reset)) { dev_dbg(hdev->dev, "Doing hard-reset instead of soft-reset\n"); hard_reset = true; @@ -960,7 +900,11 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset, if (rc) return 0; - if (hard_reset) { + /* + * if reset is due to heartbeat, device CPU is no responsive in + * which case no point sending PCI disable message to it + */ + if (hard_reset && !(flags & HL_RESET_HEARTBEAT)) { /* Disable PCI access from device F/W so he won't send * us additional interrupts. We disable MSI/MSI-X at * the halt_engines function and we can't have the F/W @@ -1030,6 +974,11 @@ again: /* Go over all the queues, release all CS and their jobs */ hl_cs_rollback_all(hdev); + /* Release all pending user interrupts, each pending user interrupt + * holds a reference to user context + */ + hl_release_pending_user_interrupts(hdev); + kill_processes: if (hard_reset) { /* Kill processes here after CS rollback. This is because the @@ -1078,14 +1027,6 @@ kill_processes: for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) hl_cq_reset(hdev, &hdev->completion_queue[i]); - hdev->idle_busy_ts_idx = 0; - hdev->idle_busy_ts_arr[0].busy_to_idle_ts = ktime_set(0, 0); - hdev->idle_busy_ts_arr[0].idle_to_busy_ts = ktime_set(0, 0); - - if (hdev->cs_active_cnt) - dev_crit(hdev->dev, "CS active cnt %d is not 0 during reset\n", - hdev->cs_active_cnt); - mutex_lock(&hdev->fpriv_list_lock); /* Make sure the context switch phase will run again */ @@ -1151,6 +1092,16 @@ kill_processes: goto out_err; } + /* If device is not idle fail the reset process */ + if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, + HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { + dev_err(hdev->dev, + "device is not idle (mask %#llx %#llx) after reset\n", + idle_mask[0], idle_mask[1]); + rc = -EIO; + goto out_err; + } + /* Check that the communication with the device is working */ rc = hdev->asic_funcs->test_queues(hdev); if (rc) { @@ -1235,7 +1186,7 @@ out_err: */ int hl_device_init(struct hl_device *hdev, struct class *hclass) { - int i, rc, cq_cnt, cq_ready_cnt; + int i, rc, cq_cnt, user_interrupt_cnt, cq_ready_cnt; char *name; bool add_cdev_sysfs_on_err = false; @@ -1274,13 +1225,26 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) if (rc) goto free_dev_ctrl; + user_interrupt_cnt = hdev->asic_prop.user_interrupt_count; + + if (user_interrupt_cnt) { + hdev->user_interrupt = kcalloc(user_interrupt_cnt, + sizeof(*hdev->user_interrupt), + GFP_KERNEL); + + if (!hdev->user_interrupt) { + rc = -ENOMEM; + goto early_fini; + } + } + /* * Start calling ASIC initialization. First S/W then H/W and finally * late init */ rc = hdev->asic_funcs->sw_init(hdev); if (rc) - goto early_fini; + goto user_interrupts_fini; /* * Initialize the H/W queues. Must be done before hw_init, because @@ -1478,6 +1442,8 @@ hw_queues_destroy: hl_hw_queues_destroy(hdev); sw_fini: hdev->asic_funcs->sw_fini(hdev); +user_interrupts_fini: + kfree(hdev->user_interrupt); early_fini: device_early_fini(hdev); free_dev_ctrl: @@ -1609,6 +1575,7 @@ void hl_device_fini(struct hl_device *hdev) for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) hl_cq_fini(hdev, &hdev->completion_queue[i]); kfree(hdev->completion_queue); + kfree(hdev->user_interrupt); hl_hw_queues_destroy(hdev); diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 09706c571e9503192efbe57ddf71b01de460cd9d..832dd5c5bb0653952e682f4cf5385c2abd4aa3c0 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -293,6 +293,7 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, u32 cpu_security_boot_status_reg) { u32 err_val, security_val; + bool err_exists = false; /* Some of the firmware status codes are deprecated in newer f/w * versions. In those versions, the errors are reported @@ -307,48 +308,102 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, if (!(err_val & CPU_BOOT_ERR0_ENABLED)) return 0; - if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) + if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) { dev_err(hdev->dev, "Device boot error - DRAM initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED) { dev_err(hdev->dev, "Device boot error - FIT image corrupted\n"); - if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL) { dev_err(hdev->dev, "Device boot error - Thermal Sensor initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) { dev_warn(hdev->dev, "Device boot warning - Skipped DRAM initialization\n"); + /* This is a warning so we don't want it to disable the + * device + */ + err_val &= ~CPU_BOOT_ERR0_DRAM_SKIPPED; + } if (err_val & CPU_BOOT_ERR0_BMC_WAIT_SKIPPED) { - if (hdev->bmc_enable) - dev_warn(hdev->dev, + if (hdev->bmc_enable) { + dev_err(hdev->dev, "Device boot error - Skipped waiting for BMC\n"); - else + err_exists = true; + } else { + dev_info(hdev->dev, + "Device boot message - Skipped waiting for BMC\n"); + /* This is an info so we don't want it to disable the + * device + */ err_val &= ~CPU_BOOT_ERR0_BMC_WAIT_SKIPPED; + } } - if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY) + if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY) { dev_err(hdev->dev, "Device boot error - Serdes data from BMC not available\n"); - if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL) { dev_err(hdev->dev, "Device boot error - NIC F/W initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY) { dev_warn(hdev->dev, "Device boot warning - security not ready\n"); - if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL) + /* This is a warning so we don't want it to disable the + * device + */ + err_val &= ~CPU_BOOT_ERR0_SECURITY_NOT_RDY; + } + + if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL) { dev_err(hdev->dev, "Device boot error - security failure\n"); - if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL) { dev_err(hdev->dev, "Device boot error - eFuse failure\n"); - if (err_val & CPU_BOOT_ERR0_PLL_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_PLL_FAIL) { dev_err(hdev->dev, "Device boot error - PLL failure\n"); + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) { + dev_err(hdev->dev, + "Device boot error - device unusable\n"); + err_exists = true; + } security_val = RREG32(cpu_security_boot_status_reg); if (security_val & CPU_BOOT_DEV_STS0_ENABLED) dev_dbg(hdev->dev, "Device security status %#x\n", security_val); - if (err_val & ~CPU_BOOT_ERR0_ENABLED) + if (!err_exists && (err_val & ~CPU_BOOT_ERR0_ENABLED)) { + dev_err(hdev->dev, + "Device boot error - unknown error 0x%08x\n", + err_val); + err_exists = true; + } + + if (err_exists) return -EIO; return 0; @@ -419,6 +474,73 @@ out: return rc; } +static int hl_fw_send_msi_info_msg(struct hl_device *hdev) +{ + struct cpucp_array_data_packet *pkt; + size_t total_pkt_size, data_size; + u64 result; + int rc; + + /* skip sending this info for unsupported ASICs */ + if (!hdev->asic_funcs->get_msi_info) + return 0; + + data_size = CPUCP_NUM_OF_MSI_TYPES * sizeof(u32); + total_pkt_size = sizeof(struct cpucp_array_data_packet) + data_size; + + /* data should be aligned to 8 bytes in order to CPU-CP to copy it */ + total_pkt_size = (total_pkt_size + 0x7) & ~0x7; + + /* total_pkt_size is casted to u16 later on */ + if (total_pkt_size > USHRT_MAX) { + dev_err(hdev->dev, "CPUCP array data is too big\n"); + return -EINVAL; + } + + pkt = kzalloc(total_pkt_size, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + + pkt->length = cpu_to_le32(CPUCP_NUM_OF_MSI_TYPES); + + hdev->asic_funcs->get_msi_info((u32 *)&pkt->data); + + pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_MSI_INFO_SET << + CPUCP_PKT_CTL_OPCODE_SHIFT); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)pkt, + total_pkt_size, 0, &result); + + /* + * in case packet result is invalid it means that FW does not support + * this feature and will use default/hard coded MSI values. no reason + * to stop the boot + */ + if (rc && result == cpucp_packet_invalid) + rc = 0; + + if (rc) + dev_err(hdev->dev, "failed to send CPUCP array data\n"); + + kfree(pkt); + + return rc; +} + +int hl_fw_cpucp_handshake(struct hl_device *hdev, + u32 cpu_security_boot_status_reg, + u32 boot_err0_reg) +{ + int rc; + + rc = hl_fw_cpucp_info_get(hdev, cpu_security_boot_status_reg, + boot_err0_reg); + if (rc) + return rc; + + return hl_fw_send_msi_info_msg(hdev); +} + int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size) { struct cpucp_packet pkt = {}; @@ -539,18 +661,63 @@ int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy) return rc; } -int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, +int get_used_pll_index(struct hl_device *hdev, enum pll_index input_pll_index, + enum pll_index *pll_index) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + u8 pll_byte, pll_bit_off; + bool dynamic_pll; + + if (input_pll_index >= PLL_MAX) { + dev_err(hdev->dev, "PLL index %d is out of range\n", + input_pll_index); + return -EINVAL; + } + + dynamic_pll = prop->fw_security_status_valid && + (prop->fw_app_security_map & CPU_BOOT_DEV_STS0_DYN_PLL_EN); + + if (!dynamic_pll) { + /* + * in case we are working with legacy FW (each asic has unique + * PLL numbering) extract the legacy numbering + */ + *pll_index = hdev->legacy_pll_map[input_pll_index]; + return 0; + } + + /* PLL map is a u8 array */ + pll_byte = prop->cpucp_info.pll_map[input_pll_index >> 3]; + pll_bit_off = input_pll_index & 0x7; + + if (!(pll_byte & BIT(pll_bit_off))) { + dev_err(hdev->dev, "PLL index %d is not supported\n", + input_pll_index); + return -EINVAL; + } + + *pll_index = input_pll_index; + + return 0; +} + +int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, enum pll_index pll_index, u16 *pll_freq_arr) { struct cpucp_packet pkt; + enum pll_index used_pll_idx; u64 result; int rc; + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return rc; + memset(&pkt, 0, sizeof(pkt)); pkt.ctl = cpu_to_le32(CPUCP_PACKET_PLL_INFO_GET << CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_type = __cpu_to_le16(pll_index); + pkt.pll_type = __cpu_to_le16((u16)used_pll_idx); rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), HL_CPUCP_INFO_TIMEOUT_USEC, &result); @@ -565,6 +732,29 @@ int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, return rc; } +int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power) +{ + struct cpucp_packet pkt; + u64 result; + int rc; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET << + CPUCP_PKT_CTL_OPCODE_SHIFT); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), + HL_CPUCP_INFO_TIMEOUT_USEC, &result); + if (rc) { + dev_err(hdev->dev, "Failed to read power, error %d\n", rc); + return rc; + } + + *power = result; + + return rc; +} + static void detect_cpu_boot_status(struct hl_device *hdev, u32 status) { /* Some of the status codes below are deprecated in newer f/w @@ -623,7 +813,11 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 status, security_status; int rc; - if (!hdev->cpu_enable) + /* pldm was added for cases in which we use preboot on pldm and want + * to load boot fit, but we can't wait for preboot because it runs + * very slowly + */ + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm) return 0; /* Need to check two possible scenarios: @@ -677,16 +871,16 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, if (security_status & CPU_BOOT_DEV_STS0_ENABLED) { prop->fw_security_status_valid = 1; + /* FW security should be derived from PCI ID, we keep this + * check for backward compatibility + */ if (security_status & CPU_BOOT_DEV_STS0_SECURITY_EN) prop->fw_security_disabled = false; - else - prop->fw_security_disabled = true; if (security_status & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; } else { prop->fw_security_status_valid = 0; - prop->fw_security_disabled = true; } dev_dbg(hdev->dev, "Firmware preboot security status %#x\n", @@ -710,7 +904,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 status; int rc; - if (!(hdev->fw_loading & FW_TYPE_BOOT_CPU)) + if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) return 0; dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n", @@ -801,7 +995,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, goto out; } - if (!(hdev->fw_loading & FW_TYPE_LINUX)) { + if (!(hdev->fw_components & FW_TYPE_LINUX)) { dev_info(hdev->dev, "Skip loading Linux F/W\n"); goto out; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 4b321e4f8059f6735a913534662929c0d92c1982..44e89da30b4a70040488c2d838755b62275aa44f 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -19,6 +19,7 @@ #include <linux/dma-direction.h> #include <linux/scatterlist.h> #include <linux/hashtable.h> +#include <linux/debugfs.h> #include <linux/bitfield.h> #include <linux/genalloc.h> #include <linux/sched/signal.h> @@ -61,7 +62,7 @@ #define HL_SIM_MAX_TIMEOUT_US 10000000 /* 10s */ -#define HL_IDLE_BUSY_TS_ARR_SIZE 4096 +#define HL_COMMON_USER_INTERRUPT_ID 0xFFF /* Memory */ #define MEM_HASH_TABLE_BITS 7 /* 1 << 7 buckets */ @@ -102,6 +103,23 @@ enum hl_mmu_page_table_location { #define HL_MAX_DCORES 4 +/* + * Reset Flags + * + * - HL_RESET_HARD + * If set do hard reset to all engines. If not set reset just + * compute/DMA engines. + * + * - HL_RESET_FROM_RESET_THREAD + * Set if the caller is the hard-reset thread + * + * - HL_RESET_HEARTBEAT + * Set if reset is due to heartbeat + */ +#define HL_RESET_HARD (1 << 0) +#define HL_RESET_FROM_RESET_THREAD (1 << 1) +#define HL_RESET_HEARTBEAT (1 << 2) + #define HL_MAX_SOBS_PER_MONITOR 8 /** @@ -169,15 +187,19 @@ enum hl_fw_component { }; /** - * enum hl_fw_types - F/W types to load + * enum hl_fw_types - F/W types present in the system * @FW_TYPE_LINUX: Linux image for device CPU * @FW_TYPE_BOOT_CPU: Boot image for device CPU + * @FW_TYPE_PREBOOT_CPU: Indicates pre-loaded CPUs are present in the system + * (preboot, ppboot etc...) * @FW_TYPE_ALL_TYPES: Mask for all types */ enum hl_fw_types { FW_TYPE_LINUX = 0x1, FW_TYPE_BOOT_CPU = 0x2, - FW_TYPE_ALL_TYPES = (FW_TYPE_LINUX | FW_TYPE_BOOT_CPU) + FW_TYPE_PREBOOT_CPU = 0x4, + FW_TYPE_ALL_TYPES = + (FW_TYPE_LINUX | FW_TYPE_BOOT_CPU | FW_TYPE_PREBOOT_CPU) }; /** @@ -368,6 +390,7 @@ struct hl_mmu_properties { * @dram_size: DRAM total size. * @dram_pci_bar_size: size of PCI bar towards DRAM. * @max_power_default: max power of the device after reset + * @dc_power_default: power consumed by the device in mode idle. * @dram_size_for_default_page_mapping: DRAM size needed to map to avoid page * fault. * @pcie_dbi_base_address: Base address of the PCIE_DBI block. @@ -412,6 +435,7 @@ struct hl_mmu_properties { * @first_available_user_msix_interrupt: first available msix interrupt * reserved for the user * @first_available_cq: first available CQ for the user. + * @user_interrupt_count: number of user interrupts. * @tpc_enabled_mask: which TPCs are enabled. * @completion_queues_count: number of completion queues. * @fw_security_disabled: true if security measures are disabled in firmware, @@ -421,6 +445,7 @@ struct hl_mmu_properties { * @dram_supports_virtual_memory: is there an MMU towards the DRAM * @hard_reset_done_by_fw: true if firmware is handling hard reset flow * @num_functional_hbms: number of functional HBMs in each DCORE. + * @iatu_done_by_fw: true if iATU configuration is being done by FW. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -439,6 +464,7 @@ struct asic_fixed_properties { u64 dram_size; u64 dram_pci_bar_size; u64 max_power_default; + u64 dc_power_default; u64 dram_size_for_default_page_mapping; u64 pcie_dbi_base_address; u64 pcie_aux_dbi_reg_addr; @@ -475,6 +501,7 @@ struct asic_fixed_properties { u16 first_available_user_mon[HL_MAX_DCORES]; u16 first_available_user_msix_interrupt; u16 first_available_cq[HL_MAX_DCORES]; + u16 user_interrupt_count; u8 tpc_enabled_mask; u8 completion_queues_count; u8 fw_security_disabled; @@ -482,6 +509,7 @@ struct asic_fixed_properties { u8 dram_supports_virtual_memory; u8 hard_reset_done_by_fw; u8 num_functional_hbms; + u8 iatu_done_by_fw; }; /** @@ -503,6 +531,7 @@ struct hl_fence { /** * struct hl_cs_compl - command submission completion object. + * @sob_reset_work: workqueue object to run SOB reset flow. * @base_fence: hl fence object. * @lock: spinlock to protect fence. * @hdev: habanalabs device structure. @@ -513,6 +542,7 @@ struct hl_fence { * @sob_group: the SOB group that is used in this collective wait CS. */ struct hl_cs_compl { + struct work_struct sob_reset_work; struct hl_fence base_fence; spinlock_t lock; struct hl_device *hdev; @@ -689,6 +719,31 @@ struct hl_cq { atomic_t free_slots_cnt; }; +/** + * struct hl_user_interrupt - holds user interrupt information + * @hdev: pointer to the device structure + * @wait_list_head: head to the list of user threads pending on this interrupt + * @wait_list_lock: protects wait_list_head + * @interrupt_id: msix interrupt id + */ +struct hl_user_interrupt { + struct hl_device *hdev; + struct list_head wait_list_head; + spinlock_t wait_list_lock; + u32 interrupt_id; +}; + +/** + * struct hl_user_pending_interrupt - holds a context to a user thread + * pending on an interrupt + * @wait_list_node: node in the list of user threads pending on an interrupt + * @fence: hl fence object for interrupt completion + */ +struct hl_user_pending_interrupt { + struct list_head wait_list_node; + struct hl_fence fence; +}; + /** * struct hl_eq - describes the event queue (single one per device) * @hdev: pointer to the device structure @@ -713,11 +768,13 @@ struct hl_eq { * @ASIC_INVALID: Invalid ASIC type. * @ASIC_GOYA: Goya device. * @ASIC_GAUDI: Gaudi device. + * @ASIC_GAUDI_SEC: Gaudi secured device (HL-2000). */ enum hl_asic_type { ASIC_INVALID, ASIC_GOYA, - ASIC_GAUDI + ASIC_GAUDI, + ASIC_GAUDI_SEC }; struct hl_cs_parser; @@ -802,8 +859,12 @@ enum div_select_defs { * @update_eq_ci: update event queue CI. * @context_switch: called upon ASID context switch. * @restore_phase_topology: clear all SOBs amd MONs. - * @debugfs_read32: debug interface for reading u32 from DRAM/SRAM. - * @debugfs_write32: debug interface for writing u32 to DRAM/SRAM. + * @debugfs_read32: debug interface for reading u32 from DRAM/SRAM/Host memory. + * @debugfs_write32: debug interface for writing u32 to DRAM/SRAM/Host memory. + * @debugfs_read64: debug interface for reading u64 from DRAM/SRAM/Host memory. + * @debugfs_write64: debug interface for writing u64 to DRAM/SRAM/Host memory. + * @debugfs_read_dma: debug interface for reading up to 2MB from the device's + * internal memory via DMA engine. * @add_device_attr: add ASIC specific device attributes. * @handle_eqe: handle event queue entry (IRQ) from CPU-CP. * @set_pll_profile: change PLL profile (manual/automatic). @@ -919,10 +980,16 @@ struct hl_asic_funcs { void (*update_eq_ci)(struct hl_device *hdev, u32 val); int (*context_switch)(struct hl_device *hdev, u32 asid); void (*restore_phase_topology)(struct hl_device *hdev); - int (*debugfs_read32)(struct hl_device *hdev, u64 addr, u32 *val); - int (*debugfs_write32)(struct hl_device *hdev, u64 addr, u32 val); - int (*debugfs_read64)(struct hl_device *hdev, u64 addr, u64 *val); - int (*debugfs_write64)(struct hl_device *hdev, u64 addr, u64 val); + int (*debugfs_read32)(struct hl_device *hdev, u64 addr, + bool user_address, u32 *val); + int (*debugfs_write32)(struct hl_device *hdev, u64 addr, + bool user_address, u32 val); + int (*debugfs_read64)(struct hl_device *hdev, u64 addr, + bool user_address, u64 *val); + int (*debugfs_write64)(struct hl_device *hdev, u64 addr, + bool user_address, u64 val); + int (*debugfs_read_dma)(struct hl_device *hdev, u64 addr, u32 size, + void *blob_addr); void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void (*handle_eqe)(struct hl_device *hdev, @@ -986,6 +1053,7 @@ struct hl_asic_funcs { int (*hw_block_mmap)(struct hl_device *hdev, struct vm_area_struct *vma, u32 block_id, u32 block_size); void (*enable_events_from_fw)(struct hl_device *hdev); + void (*get_msi_info)(u32 *table); }; @@ -1070,9 +1138,11 @@ struct hl_pending_cb { * @mem_hash_lock: protects the mem_hash. * @mmu_lock: protects the MMU page tables. Any change to the PGT, modifying the * MMU hash or walking the PGT requires talking this lock. + * @hw_block_list_lock: protects the HW block memory list. * @debugfs_list: node in debugfs list of contexts. * pending_cb_list: list of pending command buffers waiting to be sent upon * next user command submission context. + * @hw_block_mem_list: list of HW block virtual mapped addresses. * @cs_counters: context command submission counters. * @cb_va_pool: device VA pool for command buffers which are mapped to the * device's MMU. @@ -1109,8 +1179,10 @@ struct hl_ctx { struct hl_va_range *va_range[HL_VA_RANGE_TYPE_MAX]; struct mutex mem_hash_lock; struct mutex mmu_lock; + struct mutex hw_block_list_lock; struct list_head debugfs_list; struct list_head pending_cb_list; + struct list_head hw_block_mem_list; struct hl_cs_counters_atomic cs_counters; struct gen_pool *cb_va_pool; u64 cs_sequence; @@ -1185,6 +1257,7 @@ struct hl_userptr { * @sequence: the sequence number of this CS. * @staged_sequence: the sequence of the staged submission this CS is part of, * relevant only if staged_cs is set. + * @timeout_jiffies: cs timeout in jiffies. * @type: CS_TYPE_*. * @submitted: true if CS was submitted to H/W. * @completed: true if CS was completed by device. @@ -1213,6 +1286,7 @@ struct hl_cs { struct list_head debugfs_list; u64 sequence; u64 staged_sequence; + u64 timeout_jiffies; enum hl_cs_type type; u8 submitted; u8 completed; @@ -1329,6 +1403,23 @@ struct hl_vm_hash_node { void *ptr; }; +/** + * struct hl_vm_hw_block_list_node - list element from user virtual address to + * HW block id. + * @node: node to hang on the list in context object. + * @ctx: the context this node belongs to. + * @vaddr: virtual address of the HW block. + * @size: size of the block. + * @id: HW block id (handle). + */ +struct hl_vm_hw_block_list_node { + struct list_head node; + struct hl_ctx *ctx; + unsigned long vaddr; + u32 size; + u32 id; +}; + /** * struct hl_vm_phys_pg_pack - physical page pack. * @vm_type: describes the type of the virtual area descriptor. @@ -1490,12 +1581,13 @@ struct hl_debugfs_entry { * @userptr_spinlock: protects userptr_list. * @ctx_mem_hash_list: list of available contexts with MMU mappings. * @ctx_mem_hash_spinlock: protects cb_list. + * @blob_desc: descriptor of blob * @addr: next address to read/write from/to in read/write32. * @mmu_addr: next virtual address to translate to physical address in mmu_show. * @mmu_asid: ASID to use while translating in mmu_show. * @i2c_bus: generic u8 debugfs file for bus value to use in i2c_data_read. - * @i2c_bus: generic u8 debugfs file for address value to use in i2c_data_read. - * @i2c_bus: generic u8 debugfs file for register value to use in i2c_data_read. + * @i2c_addr: generic u8 debugfs file for address value to use in i2c_data_read. + * @i2c_reg: generic u8 debugfs file for register value to use in i2c_data_read. */ struct hl_dbg_device_entry { struct dentry *root; @@ -1513,6 +1605,7 @@ struct hl_dbg_device_entry { spinlock_t userptr_spinlock; struct list_head ctx_mem_hash_list; spinlock_t ctx_mem_hash_spinlock; + struct debugfs_blob_wrapper blob_desc; u64 addr; u64 mmu_addr; u32 mmu_asid; @@ -1683,16 +1776,6 @@ struct hl_device_reset_work { struct hl_device *hdev; }; -/** - * struct hl_device_idle_busy_ts - used for calculating device utilization rate. - * @idle_to_busy_ts: timestamp where device changed from idle to busy. - * @busy_to_idle_ts: timestamp where device changed from busy to idle. - */ -struct hl_device_idle_busy_ts { - ktime_t idle_to_busy_ts; - ktime_t busy_to_idle_ts; -}; - /** * struct hr_mmu_hop_addrs - used for holding per-device host-resident mmu hop * information. @@ -1821,9 +1904,16 @@ struct hl_mmu_funcs { * @asic_name: ASIC specific name. * @asic_type: ASIC specific type. * @completion_queue: array of hl_cq. + * @user_interrupt: array of hl_user_interrupt. upon the corresponding user + * interrupt, driver will monitor the list of fences + * registered to this interrupt. + * @common_user_interrupt: common user interrupt for all user interrupts. + * upon any user interrupt, driver will monitor the + * list of fences registered to this common structure. * @cq_wq: work queues of completion queues for executing work in process * context. * @eq_wq: work queue of event queue for executing work in process context. + * @sob_reset_wq: work queue for sob reset executions. * @kernel_ctx: Kernel driver context structure. * @kernel_queues: array of hl_hw_queue. * @cs_mirror_list: CS mirror list for TDR. @@ -1857,11 +1947,11 @@ struct hl_mmu_funcs { * when a user opens the device * @fpriv_list_lock: protects the fpriv_list * @compute_ctx: current compute context executing. - * @idle_busy_ts_arr: array to hold time stamps of transitions from idle to busy - * and vice-versa * @aggregated_cs_counters: aggregated cs counters among all contexts * @mmu_priv: device-specific MMU data. * @mmu_func: device-related MMU functions. + * @legacy_pll_map: map holding map between dynamic (common) PLL indexes and + * static (asic specific) PLL indexes. * @dram_used_mem: current DRAM memory consumption. * @timeout_jiffies: device CS timeout value. * @max_power: the max power of the device, as configured by the sysadmin. This @@ -1874,13 +1964,10 @@ struct hl_mmu_funcs { * @curr_pll_profile: current PLL profile. * @card_type: Various ASICs have several card types. This indicates the card * type of the current device. - * @cs_active_cnt: number of active command submissions on this device (active - * means already in H/W queues) * @major: habanalabs kernel driver major. * @high_pll: high PLL profile frequency. * @soft_reset_cnt: number of soft reset since the driver was loaded. * @hard_reset_cnt: number of hard reset since the driver was loaded. - * @idle_busy_ts_idx: index of current entry in idle_busy_ts_arr * @clk_throttling_reason: bitmask represents the current clk throttling reasons * @id: device minor. * @id_control: minor of the control device @@ -1937,8 +2024,11 @@ struct hl_device { char status[HL_DEV_STS_MAX][HL_STR_MAX]; enum hl_asic_type asic_type; struct hl_cq *completion_queue; + struct hl_user_interrupt *user_interrupt; + struct hl_user_interrupt common_user_interrupt; struct workqueue_struct **cq_wq; struct workqueue_struct *eq_wq; + struct workqueue_struct *sob_reset_wq; struct hl_ctx *kernel_ctx; struct hl_hw_queue *kernel_queues; struct list_head cs_mirror_list; @@ -1976,13 +2066,13 @@ struct hl_device { struct hl_ctx *compute_ctx; - struct hl_device_idle_busy_ts *idle_busy_ts_arr; - struct hl_cs_counters_atomic aggregated_cs_counters; struct hl_mmu_priv mmu_priv; struct hl_mmu_funcs mmu_func[MMU_NUM_PGT_LOCATIONS]; + enum pll_index *legacy_pll_map; + atomic64_t dram_used_mem; u64 timeout_jiffies; u64 max_power; @@ -1990,12 +2080,10 @@ struct hl_device { atomic_t in_reset; enum hl_pll_frequency curr_pll_profile; enum cpucp_card_types card_type; - int cs_active_cnt; u32 major; u32 high_pll; u32 soft_reset_cnt; u32 hard_reset_cnt; - u32 idle_busy_ts_idx; u32 clk_throttling_reason; u16 id; u16 id_control; @@ -2029,10 +2117,9 @@ struct hl_device { /* Parameters for bring-up */ u64 nic_ports_mask; - u64 fw_loading; + u64 fw_components; u8 mmu_enable; u8 mmu_huge_page_opt; - u8 cpu_enable; u8 reset_pcilink; u8 cpu_queues_enable; u8 pldm; @@ -2043,6 +2130,7 @@ struct hl_device { u8 bmc_enable; u8 rl_enable; u8 reset_on_preboot_fail; + u8 reset_upon_device_release; }; @@ -2157,6 +2245,8 @@ void hl_cq_reset(struct hl_device *hdev, struct hl_cq *q); void hl_eq_reset(struct hl_device *hdev, struct hl_eq *q); irqreturn_t hl_irq_handler_cq(int irq, void *arg); irqreturn_t hl_irq_handler_eq(int irq, void *arg); +irqreturn_t hl_irq_handler_user_cq(int irq, void *arg); +irqreturn_t hl_irq_handler_default(int irq, void *arg); u32 hl_cq_inc_ptr(u32 ptr); int hl_asid_init(struct hl_device *hdev); @@ -2178,12 +2268,11 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass); void hl_device_fini(struct hl_device *hdev); int hl_device_suspend(struct hl_device *hdev); int hl_device_resume(struct hl_device *hdev); -int hl_device_reset(struct hl_device *hdev, bool hard_reset, - bool from_hard_reset_thread); +int hl_device_reset(struct hl_device *hdev, u32 flags); void hl_hpriv_get(struct hl_fpriv *hpriv); -void hl_hpriv_put(struct hl_fpriv *hpriv); +int hl_hpriv_put(struct hl_fpriv *hpriv); int hl_device_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq); -uint32_t hl_device_utilization(struct hl_device *hdev, uint32_t period_ms); +int hl_device_utilization(struct hl_device *hdev, u32 *utilization); int hl_build_hwmon_channel_info(struct hl_device *hdev, struct cpucp_sensor *sensors_arr); @@ -2235,6 +2324,9 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx); int hl_vm_init(struct hl_device *hdev); void hl_vm_fini(struct hl_device *hdev); +void hl_hw_block_mem_init(struct hl_ctx *ctx); +void hl_hw_block_mem_fini(struct hl_ctx *ctx); + u64 hl_reserve_va_block(struct hl_device *hdev, struct hl_ctx *ctx, enum hl_va_range_type type, u32 size, u32 alignment); int hl_unreserve_va_block(struct hl_device *hdev, struct hl_ctx *ctx, @@ -2287,13 +2379,19 @@ int hl_fw_send_heartbeat(struct hl_device *hdev); int hl_fw_cpucp_info_get(struct hl_device *hdev, u32 cpu_security_boot_status_reg, u32 boot_err0_reg); +int hl_fw_cpucp_handshake(struct hl_device *hdev, + u32 cpu_security_boot_status_reg, + u32 boot_err0_reg); int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size); int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev, struct hl_info_pci_counters *counters); int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy); -int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, +int get_used_pll_index(struct hl_device *hdev, enum pll_index input_pll_index, + enum pll_index *pll_index); +int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, enum pll_index pll_index, u16 *pll_freq_arr); +int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power); int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 msg_to_cpu_reg, u32 cpu_msg_status_reg, u32 cpu_security_boot_status_reg, u32 boot_err0_reg, @@ -2304,6 +2402,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], bool is_wc[3]); +int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data); int hl_pci_iatu_write(struct hl_device *hdev, u32 addr, u32 data); int hl_pci_set_inbound_region(struct hl_device *hdev, u8 region, struct hl_inbound_pci_region *pci_region); @@ -2312,8 +2411,10 @@ int hl_pci_set_outbound_region(struct hl_device *hdev, int hl_pci_init(struct hl_device *hdev); void hl_pci_fini(struct hl_device *hdev); -long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr); -void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq); +long hl_get_frequency(struct hl_device *hdev, enum pll_index pll_index, + bool curr); +void hl_set_frequency(struct hl_device *hdev, enum pll_index pll_index, + u64 freq); int hl_get_temperature(struct hl_device *hdev, int sensor_index, u32 attr, long *value); int hl_set_temperature(struct hl_device *hdev, @@ -2334,6 +2435,7 @@ int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); +void hl_release_pending_user_interrupts(struct hl_device *hdev); #ifdef CONFIG_DEBUG_FS @@ -2434,7 +2536,7 @@ long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg); int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data); int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data); -int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data); +int hl_wait_ioctl(struct hl_fpriv *hpriv, void *data); int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data); #endif /* HABANALABSP_H_ */ diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 032d114f01ea54b705f2f0df0cb93309d07e2947..7135f1e03864107b6bcdf8b6040f1f8ff15dfe3e 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -27,13 +27,13 @@ static struct class *hl_class; static DEFINE_IDR(hl_devs_idr); static DEFINE_MUTEX(hl_devs_idr_lock); -static int timeout_locked = 5; +static int timeout_locked = 30; static int reset_on_lockup = 1; static int memory_scrub = 1; module_param(timeout_locked, int, 0444); MODULE_PARM_DESC(timeout_locked, - "Device lockup timeout in seconds (0 = disabled, default 5s)"); + "Device lockup timeout in seconds (0 = disabled, default 30s)"); module_param(reset_on_lockup, int, 0444); MODULE_PARM_DESC(reset_on_lockup, @@ -47,10 +47,12 @@ MODULE_PARM_DESC(memory_scrub, #define PCI_IDS_GOYA 0x0001 #define PCI_IDS_GAUDI 0x1000 +#define PCI_IDS_GAUDI_SEC 0x1010 static const struct pci_device_id ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_HABANALABS, PCI_IDS_GOYA), }, { PCI_DEVICE(PCI_VENDOR_ID_HABANALABS, PCI_IDS_GAUDI), }, + { PCI_DEVICE(PCI_VENDOR_ID_HABANALABS, PCI_IDS_GAUDI_SEC), }, { 0, } }; MODULE_DEVICE_TABLE(pci, ids); @@ -74,6 +76,9 @@ static enum hl_asic_type get_asic_type(u16 device) case PCI_IDS_GAUDI: asic_type = ASIC_GAUDI; break; + case PCI_IDS_GAUDI_SEC: + asic_type = ASIC_GAUDI_SEC; + break; default: asic_type = ASIC_INVALID; break; @@ -82,6 +87,16 @@ static enum hl_asic_type get_asic_type(u16 device) return asic_type; } +static bool is_asic_secured(enum hl_asic_type asic_type) +{ + switch (asic_type) { + case ASIC_GAUDI_SEC: + return true; + default: + return false; + } +} + /* * hl_device_open - open function for habanalabs device * @@ -234,8 +249,7 @@ out_err: static void set_driver_behavior_per_device(struct hl_device *hdev) { - hdev->cpu_enable = 1; - hdev->fw_loading = FW_TYPE_ALL_TYPES; + hdev->fw_components = FW_TYPE_ALL_TYPES; hdev->cpu_queues_enable = 1; hdev->heartbeat = 1; hdev->mmu_enable = 1; @@ -288,6 +302,12 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, hdev->asic_type = asic_type; } + if (pdev) + hdev->asic_prop.fw_security_disabled = + !is_asic_secured(pdev->device); + else + hdev->asic_prop.fw_security_disabled = true; + /* Assign status description string */ strncpy(hdev->status[HL_DEVICE_STATUS_MALFUNCTION], "disabled", HL_STR_MAX); diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 083a30969c5f3698acc0151bee28808d1b5b90ef..33841c272eb66b37ff0f8fffb47bc7992ecd6d5d 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -226,19 +226,14 @@ static int device_utilization(struct hl_device *hdev, struct hl_info_args *args) struct hl_info_device_utilization device_util = {0}; u32 max_size = args->return_size; void __user *out = (void __user *) (uintptr_t) args->return_pointer; + int rc; if ((!max_size) || (!out)) return -EINVAL; - if ((args->period_ms < 100) || (args->period_ms > 1000) || - (args->period_ms % 100)) { - dev_err(hdev->dev, - "period %u must be between 100 - 1000 and must be divisible by 100\n", - args->period_ms); + rc = hl_device_utilization(hdev, &device_util.utilization); + if (rc) return -EINVAL; - } - - device_util.utilization = hl_device_utilization(hdev, args->period_ms); return copy_to_user(out, &device_util, min((size_t) max_size, sizeof(device_util))) ? -EFAULT : 0; @@ -446,6 +441,25 @@ static int pll_frequency_info(struct hl_fpriv *hpriv, struct hl_info_args *args) min((size_t) max_size, sizeof(freq_info))) ? -EFAULT : 0; } +static int power_info(struct hl_fpriv *hpriv, struct hl_info_args *args) +{ + struct hl_device *hdev = hpriv->hdev; + u32 max_size = args->return_size; + struct hl_power_info power_info = {0}; + void __user *out = (void __user *) (uintptr_t) args->return_pointer; + int rc; + + if ((!max_size) || (!out)) + return -EINVAL; + + rc = hl_fw_cpucp_power_get(hdev, &power_info.power); + if (rc) + return rc; + + return copy_to_user(out, &power_info, + min((size_t) max_size, sizeof(power_info))) ? -EFAULT : 0; +} + static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, struct device *dev) { @@ -526,6 +540,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, case HL_INFO_PLL_FREQUENCY: return pll_frequency_info(hpriv, args); + case HL_INFO_POWER: + return power_info(hpriv, args); + default: dev_err(dev, "Invalid request %d\n", args->op); rc = -ENOTTY; @@ -596,7 +613,7 @@ static const struct hl_ioctl_desc hl_ioctls[] = { HL_IOCTL_DEF(HL_IOCTL_INFO, hl_info_ioctl), HL_IOCTL_DEF(HL_IOCTL_CB, hl_cb_ioctl), HL_IOCTL_DEF(HL_IOCTL_CS, hl_cs_ioctl), - HL_IOCTL_DEF(HL_IOCTL_WAIT_CS, hl_cs_wait_ioctl), + HL_IOCTL_DEF(HL_IOCTL_WAIT_CS, hl_wait_ioctl), HL_IOCTL_DEF(HL_IOCTL_MEMORY, hl_mem_ioctl), HL_IOCTL_DEF(HL_IOCTL_DEBUG, hl_debug_ioctl) }; diff --git a/drivers/misc/habanalabs/common/hw_queue.c b/drivers/misc/habanalabs/common/hw_queue.c index 0f335182267fd19d28982b2c6f518f6ef1b6aae9..1734384618351596db379f42566b17f90ac8748d 100644 --- a/drivers/misc/habanalabs/common/hw_queue.c +++ b/drivers/misc/habanalabs/common/hw_queue.c @@ -629,20 +629,12 @@ int hl_hw_queue_schedule_cs(struct hl_cs *cs) if ((hdev->timeout_jiffies != MAX_SCHEDULE_TIMEOUT) && first_entry && cs_needs_timeout(cs)) { cs->tdr_active = true; - schedule_delayed_work(&cs->work_tdr, hdev->timeout_jiffies); + schedule_delayed_work(&cs->work_tdr, cs->timeout_jiffies); } spin_unlock(&hdev->cs_mirror_lock); - if (!hdev->cs_active_cnt++) { - struct hl_device_idle_busy_ts *ts; - - ts = &hdev->idle_busy_ts_arr[hdev->idle_busy_ts_idx]; - ts->busy_to_idle_ts = ktime_set(0, 0); - ts->idle_to_busy_ts = ktime_get(); - } - list_for_each_entry_safe(job, tmp, &cs->job_list, cs_node) switch (job->queue_type) { case QUEUE_TYPE_EXT: diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c index 44a0522b59b9507e3b4144719a8a9d07bf26c4d2..27129868c71109528c8b7bbf9d0e7601eeb9e726 100644 --- a/drivers/misc/habanalabs/common/irq.c +++ b/drivers/misc/habanalabs/common/irq.c @@ -137,6 +137,62 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg) return IRQ_HANDLED; } +static void handle_user_cq(struct hl_device *hdev, + struct hl_user_interrupt *user_cq) +{ + struct hl_user_pending_interrupt *pend; + + spin_lock(&user_cq->wait_list_lock); + list_for_each_entry(pend, &user_cq->wait_list_head, wait_list_node) + complete_all(&pend->fence.completion); + spin_unlock(&user_cq->wait_list_lock); +} + +/** + * hl_irq_handler_user_cq - irq handler for user completion queues + * + * @irq: irq number + * @arg: pointer to user interrupt structure + * + */ +irqreturn_t hl_irq_handler_user_cq(int irq, void *arg) +{ + struct hl_user_interrupt *user_cq = arg; + struct hl_device *hdev = user_cq->hdev; + + dev_dbg(hdev->dev, + "got user completion interrupt id %u", + user_cq->interrupt_id); + + /* Handle user cq interrupts registered on all interrupts */ + handle_user_cq(hdev, &hdev->common_user_interrupt); + + /* Handle user cq interrupts registered on this specific interrupt */ + handle_user_cq(hdev, user_cq); + + return IRQ_HANDLED; +} + +/** + * hl_irq_handler_default - default irq handler + * + * @irq: irq number + * @arg: pointer to user interrupt structure + * + */ +irqreturn_t hl_irq_handler_default(int irq, void *arg) +{ + struct hl_user_interrupt *user_interrupt = arg; + struct hl_device *hdev = user_interrupt->hdev; + u32 interrupt_id = user_interrupt->interrupt_id; + + dev_err(hdev->dev, + "got invalid user interrupt %u", + interrupt_id); + + return IRQ_HANDLED; +} + /** * hl_irq_handler_eq - irq handler for event queue * diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 1f5910517b0e3ad565d6179fc8d481598fca57ba..2938cbbafbbcfe4eec510243269c32bd76f41697 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -81,16 +81,6 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, num_pgs, total_size); return -ENOMEM; } - - if (hdev->memory_scrub) { - rc = hdev->asic_funcs->scrub_device_mem(hdev, paddr, - total_size); - if (rc) { - dev_err(hdev->dev, - "Failed to scrub contiguous device memory\n"); - goto pages_pack_err; - } - } } phys_pg_pack = kzalloc(sizeof(*phys_pg_pack), GFP_KERNEL); @@ -128,24 +118,13 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, goto page_err; } - if (hdev->memory_scrub) { - rc = hdev->asic_funcs->scrub_device_mem(hdev, - phys_pg_pack->pages[i], - page_size); - if (rc) { - dev_err(hdev->dev, - "Failed to scrub device memory\n"); - goto page_err; - } - } - num_curr_pgs++; } } spin_lock(&vm->idr_lock); handle = idr_alloc(&vm->phys_pg_pack_handles, phys_pg_pack, 1, 0, - GFP_ATOMIC); + GFP_KERNEL); spin_unlock(&vm->idr_lock); if (handle < 0) { @@ -280,37 +259,67 @@ static void dram_pg_pool_do_release(struct kref *ref) * @phys_pg_pack: physical page pack to free. * * This function does the following: - * - For DRAM memory only, iterate over the pack and free each physical block - * structure by returning it to the general pool. + * - For DRAM memory only + * - iterate over the pack, scrub and free each physical block structure by + * returning it to the general pool. + * In case of error during scrubbing, initiate hard reset. + * Once hard reset is triggered, scrubbing is bypassed while freeing the + * memory continues. * - Free the hl_vm_phys_pg_pack structure. */ -static void free_phys_pg_pack(struct hl_device *hdev, +static int free_phys_pg_pack(struct hl_device *hdev, struct hl_vm_phys_pg_pack *phys_pg_pack) { struct hl_vm *vm = &hdev->vm; u64 i; + int rc = 0; - if (!phys_pg_pack->created_from_userptr) { - if (phys_pg_pack->contiguous) { - gen_pool_free(vm->dram_pg_pool, phys_pg_pack->pages[0], + if (phys_pg_pack->created_from_userptr) + goto end; + + if (phys_pg_pack->contiguous) { + if (hdev->memory_scrub && !hdev->disabled) { + rc = hdev->asic_funcs->scrub_device_mem(hdev, + phys_pg_pack->pages[0], phys_pg_pack->total_size); + if (rc) + dev_err(hdev->dev, + "Failed to scrub contiguous device memory\n"); + } - for (i = 0; i < phys_pg_pack->npages ; i++) - kref_put(&vm->dram_pg_pool_refcount, - dram_pg_pool_do_release); - } else { - for (i = 0 ; i < phys_pg_pack->npages ; i++) { - gen_pool_free(vm->dram_pg_pool, + gen_pool_free(vm->dram_pg_pool, phys_pg_pack->pages[0], + phys_pg_pack->total_size); + + for (i = 0; i < phys_pg_pack->npages ; i++) + kref_put(&vm->dram_pg_pool_refcount, + dram_pg_pool_do_release); + } else { + for (i = 0 ; i < phys_pg_pack->npages ; i++) { + if (hdev->memory_scrub && !hdev->disabled && rc == 0) { + rc = hdev->asic_funcs->scrub_device_mem( + hdev, phys_pg_pack->pages[i], phys_pg_pack->page_size); - kref_put(&vm->dram_pg_pool_refcount, - dram_pg_pool_do_release); + if (rc) + dev_err(hdev->dev, + "Failed to scrub device memory\n"); } + gen_pool_free(vm->dram_pg_pool, + phys_pg_pack->pages[i], + phys_pg_pack->page_size); + kref_put(&vm->dram_pg_pool_refcount, + dram_pg_pool_do_release); } } + if (rc && !hdev->disabled) + hl_device_reset(hdev, HL_RESET_HARD); + +end: kvfree(phys_pg_pack->pages); kfree(phys_pg_pack); + + return rc; } /** @@ -349,7 +358,7 @@ static int free_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args) atomic64_sub(phys_pg_pack->total_size, &ctx->dram_phys_mem); atomic64_sub(phys_pg_pack->total_size, &hdev->dram_used_mem); - free_phys_pg_pack(hdev, phys_pg_pack); + return free_phys_pg_pack(hdev, phys_pg_pack); } else { spin_unlock(&vm->idr_lock); dev_err(hdev->dev, @@ -857,6 +866,7 @@ static int map_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, u64 next_vaddr = vaddr, paddr, mapped_pg_cnt = 0, i; u32 page_size = phys_pg_pack->page_size; int rc = 0; + bool is_host_addr; for (i = 0 ; i < phys_pg_pack->npages ; i++) { paddr = phys_pg_pack->pages[i]; @@ -878,6 +888,8 @@ static int map_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, return 0; err: + is_host_addr = !hl_is_dram_va(hdev, vaddr); + next_vaddr = vaddr; for (i = 0 ; i < mapped_pg_cnt ; i++) { if (hl_mmu_unmap_page(ctx, next_vaddr, page_size, @@ -888,6 +900,17 @@ err: phys_pg_pack->pages[i], page_size); next_vaddr += page_size; + + /* + * unmapping on Palladium can be really long, so avoid a CPU + * soft lockup bug by sleeping a little between unmapping pages + * + * In addition, on host num of pages could be huge, + * because page size could be 4KB, so when unmapping host + * pages sleep every 32K pages to avoid soft lockup + */ + if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0)) + usleep_range(50, 200); } return rc; @@ -921,9 +944,9 @@ static void unmap_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, * unmapping on Palladium can be really long, so avoid a CPU * soft lockup bug by sleeping a little between unmapping pages * - * In addition, when unmapping host memory we pass through - * the Linux kernel to unpin the pages and that takes a long - * time. Therefore, sleep every 32K pages to avoid soft lockup + * In addition, on host num of pages could be huge, + * because page size could be 4KB, so when unmapping host + * pages sleep every 32K pages to avoid soft lockup */ if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0)) usleep_range(50, 200); @@ -1117,9 +1140,9 @@ static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, *device_addr = ret_vaddr; if (is_userptr) - free_phys_pg_pack(hdev, phys_pg_pack); + rc = free_phys_pg_pack(hdev, phys_pg_pack); - return 0; + return rc; map_err: if (add_va_block(hdev, va_range, ret_vaddr, @@ -1272,7 +1295,7 @@ static int unmap_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, kfree(hnode); if (is_userptr) { - free_phys_pg_pack(hdev, phys_pg_pack); + rc = free_phys_pg_pack(hdev, phys_pg_pack); dma_unmap_host_va(hdev, userptr); } @@ -1305,9 +1328,15 @@ static int map_block(struct hl_device *hdev, u64 address, u64 *handle, static void hw_block_vm_close(struct vm_area_struct *vma) { - struct hl_ctx *ctx = (struct hl_ctx *) vma->vm_private_data; + struct hl_vm_hw_block_list_node *lnode = + (struct hl_vm_hw_block_list_node *) vma->vm_private_data; + struct hl_ctx *ctx = lnode->ctx; + mutex_lock(&ctx->hw_block_list_lock); + list_del(&lnode->node); + mutex_unlock(&ctx->hw_block_list_lock); hl_ctx_put(ctx); + kfree(lnode); vma->vm_private_data = NULL; } @@ -1325,7 +1354,9 @@ static const struct vm_operations_struct hw_block_vm_ops = { */ int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma) { + struct hl_vm_hw_block_list_node *lnode; struct hl_device *hdev = hpriv->hdev; + struct hl_ctx *ctx = hpriv->ctx; u32 block_id, block_size; int rc; @@ -1351,17 +1382,31 @@ int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma) return -EINVAL; } + lnode = kzalloc(sizeof(*lnode), GFP_KERNEL); + if (!lnode) + return -ENOMEM; + vma->vm_ops = &hw_block_vm_ops; - vma->vm_private_data = hpriv->ctx; + vma->vm_private_data = lnode; - hl_ctx_get(hdev, hpriv->ctx); + hl_ctx_get(hdev, ctx); rc = hdev->asic_funcs->hw_block_mmap(hdev, vma, block_id, block_size); if (rc) { - hl_ctx_put(hpriv->ctx); + hl_ctx_put(ctx); + kfree(lnode); return rc; } + lnode->ctx = ctx; + lnode->vaddr = vma->vm_start; + lnode->size = block_size; + lnode->id = block_id; + + mutex_lock(&ctx->hw_block_list_lock); + list_add_tail(&lnode->node, &ctx->hw_block_mem_list); + mutex_unlock(&ctx->hw_block_list_lock); + vma->vm_pgoff = block_id; return 0; @@ -1574,7 +1619,7 @@ static int get_user_memory(struct hl_device *hdev, u64 addr, u64 size, rc = sg_alloc_table_from_pages(userptr->sgt, userptr->pages, - npages, offset, size, GFP_ATOMIC); + npages, offset, size, GFP_KERNEL); if (rc < 0) { dev_err(hdev->dev, "failed to create SG table from pages\n"); goto put_pages; @@ -1624,11 +1669,7 @@ int hl_pin_host_memory(struct hl_device *hdev, u64 addr, u64 size, return -EINVAL; } - /* - * This function can be called also from data path, hence use atomic - * always as it is not a big allocation. - */ - userptr->sgt = kzalloc(sizeof(*userptr->sgt), GFP_ATOMIC); + userptr->sgt = kzalloc(sizeof(*userptr->sgt), GFP_KERNEL); if (!userptr->sgt) return -ENOMEM; @@ -2122,3 +2163,38 @@ void hl_vm_fini(struct hl_device *hdev) vm->init_done = false; } + +/** + * hl_hw_block_mem_init() - HW block memory initialization. + * @ctx: pointer to the habanalabs context structure. + * + * This function initializes the HW block virtual mapped addresses list and + * it's lock. + */ +void hl_hw_block_mem_init(struct hl_ctx *ctx) +{ + mutex_init(&ctx->hw_block_list_lock); + INIT_LIST_HEAD(&ctx->hw_block_mem_list); +} + +/** + * hl_hw_block_mem_fini() - HW block memory teardown. + * @ctx: pointer to the habanalabs context structure. + * + * This function clears the HW block virtual mapped addresses list and destroys + * it's lock. + */ +void hl_hw_block_mem_fini(struct hl_ctx *ctx) +{ + struct hl_vm_hw_block_list_node *lnode, *tmp; + + if (!list_empty(&ctx->hw_block_mem_list)) + dev_crit(ctx->hdev->dev, "HW block mem list isn't empty\n"); + + list_for_each_entry_safe(lnode, tmp, &ctx->hw_block_mem_list, node) { + list_del(&lnode->node); + kfree(lnode); + } + + mutex_destroy(&ctx->hw_block_list_lock); +} diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/misc/habanalabs/common/mmu/mmu.c index 93c9e5f587e1a476bba17318e532da2e3ecc9bc8..b37189956b146604f5562426a78fb808f8dec281 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu.c +++ b/drivers/misc/habanalabs/common/mmu/mmu.c @@ -532,6 +532,8 @@ int hl_mmu_va_to_pa(struct hl_ctx *ctx, u64 virt_addr, u64 *phys_addr) struct hl_mmu_hop_info hops; int rc; + memset(&hops, 0, sizeof(hops)); + rc = hl_mmu_get_tlb_info(ctx, virt_addr, &hops); if (rc) return rc; @@ -589,6 +591,7 @@ int hl_mmu_if_set_funcs(struct hl_device *hdev) switch (hdev->asic_type) { case ASIC_GOYA: case ASIC_GAUDI: + case ASIC_GAUDI_SEC: hl_mmu_v1_set_funcs(hdev, &hdev->mmu_func[MMU_DR_PGT]); break; default: diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index b799f9258fb014e5a46f36539c8ded2e9aa40825..e941b7eef346d4d6620db0e510fc45a649adfeb6 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -85,6 +85,58 @@ static void hl_pci_bars_unmap(struct hl_device *hdev) pci_release_regions(pdev); } +int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data) +{ + struct pci_dev *pdev = hdev->pdev; + ktime_t timeout; + u64 msec; + u32 val; + + if (hdev->pldm) + msec = HL_PLDM_PCI_ELBI_TIMEOUT_MSEC; + else + msec = HL_PCI_ELBI_TIMEOUT_MSEC; + + /* Clear previous status */ + pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0); + + pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_ADDR, (u32) addr); + pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL, 0); + + timeout = ktime_add_ms(ktime_get(), msec); + for (;;) { + pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val); + if (val & PCI_CONFIG_ELBI_STS_MASK) + break; + if (ktime_compare(ktime_get(), timeout) > 0) { + pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, + &val); + break; + } + + usleep_range(300, 500); + } + + if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE) { + pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data); + + return 0; + } + + if (val & PCI_CONFIG_ELBI_STS_ERR) { + dev_err(hdev->dev, "Error reading from ELBI\n"); + return -EIO; + } + + if (!(val & PCI_CONFIG_ELBI_STS_MASK)) { + dev_err(hdev->dev, "ELBI read didn't finish in time\n"); + return -EIO; + } + + dev_err(hdev->dev, "ELBI read has undefined bits in status\n"); + return -EIO; +} + /** * hl_pci_elbi_write() - Write through the ELBI interface. * @hdev: Pointer to hl_device structure. diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 4366d8f9384290437e05fe23d06044f0bda9e50c..9fa61573a89de89e15d4f80e5a228bb66a890536 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -9,12 +9,18 @@ #include <linux/pci.h> -long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) +long hl_get_frequency(struct hl_device *hdev, enum pll_index pll_index, + bool curr) { struct cpucp_packet pkt; + u32 used_pll_idx; u64 result; int rc; + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return rc; + memset(&pkt, 0, sizeof(pkt)); if (curr) @@ -23,7 +29,7 @@ long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) else pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_index = cpu_to_le32(pll_index); + pkt.pll_index = cpu_to_le32((u32)used_pll_idx); rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result); @@ -31,23 +37,29 @@ long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) if (rc) { dev_err(hdev->dev, "Failed to get frequency of PLL %d, error %d\n", - pll_index, rc); + used_pll_idx, rc); return rc; } return (long) result; } -void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) +void hl_set_frequency(struct hl_device *hdev, enum pll_index pll_index, + u64 freq) { struct cpucp_packet pkt; + u32 used_pll_idx; int rc; + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return; + memset(&pkt, 0, sizeof(pkt)); pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_index = cpu_to_le32(pll_index); + pkt.pll_index = cpu_to_le32((u32)used_pll_idx); pkt.value = cpu_to_le64(freq); rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), @@ -56,7 +68,7 @@ void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) if (rc) dev_err(hdev->dev, "Failed to set frequency to PLL %d, error %d\n", - pll_index, rc); + used_pll_idx, rc); } u64 hl_get_max_power(struct hl_device *hdev) @@ -203,7 +215,7 @@ static ssize_t soft_reset_store(struct device *dev, dev_warn(hdev->dev, "Soft-Reset requested through sysfs\n"); - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); out: return count; @@ -226,7 +238,7 @@ static ssize_t hard_reset_store(struct device *dev, dev_warn(hdev->dev, "Hard-Reset requested through sysfs\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); out: return count; @@ -245,6 +257,9 @@ static ssize_t device_type_show(struct device *dev, case ASIC_GAUDI: str = "GAUDI"; break; + case ASIC_GAUDI_SEC: + str = "GAUDI SEC"; + break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", hdev->asic_type); @@ -344,7 +359,7 @@ static ssize_t eeprom_read_handler(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t offset, size_t max_size) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct hl_device *hdev = dev_get_drvdata(dev); char *data; int rc; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 9152242778f5e7495bb63688e26916612e393612..b751652f80a8ce043359bae5be7b18c98878ecda 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -105,6 +105,36 @@ #define GAUDI_PLL_MAX 10 +/* + * this enum kept here for compatibility with old FW (in which each asic has + * unique PLL numbering + */ +enum gaudi_pll_index { + GAUDI_CPU_PLL = 0, + GAUDI_PCI_PLL, + GAUDI_SRAM_PLL, + GAUDI_HBM_PLL, + GAUDI_NIC_PLL, + GAUDI_DMA_PLL, + GAUDI_MESH_PLL, + GAUDI_MME_PLL, + GAUDI_TPC_PLL, + GAUDI_IF_PLL, +}; + +static enum pll_index gaudi_pll_map[PLL_MAX] = { + [CPU_PLL] = GAUDI_CPU_PLL, + [PCI_PLL] = GAUDI_PCI_PLL, + [SRAM_PLL] = GAUDI_SRAM_PLL, + [HBM_PLL] = GAUDI_HBM_PLL, + [NIC_PLL] = GAUDI_NIC_PLL, + [DMA_PLL] = GAUDI_DMA_PLL, + [MESH_PLL] = GAUDI_MESH_PLL, + [MME_PLL] = GAUDI_MME_PLL, + [TPC_PLL] = GAUDI_TPC_PLL, + [IF_PLL] = GAUDI_IF_PLL, +}; + static const char gaudi_irq_name[GAUDI_MSI_ENTRIES][GAUDI_MAX_STRING_LEN] = { "gaudi cq 0_0", "gaudi cq 0_1", "gaudi cq 0_2", "gaudi cq 0_3", "gaudi cq 1_0", "gaudi cq 1_1", "gaudi cq 1_2", "gaudi cq 1_3", @@ -396,6 +426,19 @@ get_collective_mode(struct hl_device *hdev, u32 queue_id) return HL_COLLECTIVE_NOT_SUPPORTED; } +static inline void set_default_power_values(struct hl_device *hdev) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + + if (hdev->card_type == cpucp_card_type_pmc) { + prop->max_power_default = MAX_POWER_DEFAULT_PMC; + prop->dc_power_default = DC_POWER_DEFAULT_PMC; + } else { + prop->max_power_default = MAX_POWER_DEFAULT_PCI; + prop->dc_power_default = DC_POWER_DEFAULT_PCI; + } +} + static int gaudi_get_fixed_properties(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; @@ -507,7 +550,7 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) prop->num_of_events = GAUDI_EVENT_SIZE; prop->tpc_enabled_mask = TPC_ENABLED_MASK; - prop->max_power_default = MAX_POWER_DEFAULT_PCI; + set_default_power_values(hdev); prop->cb_pool_cb_cnt = GAUDI_CB_POOL_CB_CNT; prop->cb_pool_cb_size = GAUDI_CB_POOL_CB_SIZE; @@ -532,8 +575,6 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) for (i = 0 ; i < HL_MAX_DCORES ; i++) prop->first_available_cq[i] = USHRT_MAX; - /* disable fw security for now, set it in a later stage */ - prop->fw_security_disabled = true; prop->fw_security_status_valid = false; prop->hard_reset_done_by_fw = false; @@ -588,6 +629,11 @@ static int gaudi_init_iatu(struct hl_device *hdev) struct hl_outbound_pci_region outbound_region; int rc; + if (hdev->asic_prop.iatu_done_by_fw) { + hdev->asic_funcs->set_dma_mask_from_fw(hdev); + return 0; + } + /* Inbound Region 0 - Bar 0 - Point to SRAM + CFG */ inbound_region.mode = PCI_BAR_MATCH_MODE; inbound_region.bar = SRAM_BAR_ID; @@ -632,6 +678,7 @@ static int gaudi_early_init(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct pci_dev *pdev = hdev->pdev; + u32 fw_boot_status; int rc; rc = gaudi_get_fixed_properties(hdev); @@ -665,6 +712,23 @@ static int gaudi_early_init(struct hl_device *hdev) prop->dram_pci_bar_size = pci_resource_len(pdev, HBM_BAR_ID); + /* If FW security is enabled at this point it means no access to ELBI */ + if (!hdev->asic_prop.fw_security_disabled) { + hdev->asic_prop.iatu_done_by_fw = true; + goto pci_init; + } + + rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0, + &fw_boot_status); + if (rc) + goto free_queue_props; + + /* Check whether FW is configuring iATU */ + if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) && + (fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN)) + hdev->asic_prop.iatu_done_by_fw = true; + +pci_init: rc = hl_pci_init(hdev); if (rc) goto free_queue_props; @@ -1588,6 +1652,9 @@ static int gaudi_sw_init(struct hl_device *hdev) hdev->asic_specific = gaudi; + /* store legacy PLL map */ + hdev->legacy_pll_map = gaudi_pll_map; + /* Create DMA pool for small allocations */ hdev->dma_pool = dma_pool_create(dev_name(hdev->dev), &hdev->pdev->dev, GAUDI_DMA_POOL_BLK_SIZE, 8, 0); @@ -1766,8 +1833,7 @@ static int gaudi_enable_msi(struct hl_device *hdev) if (gaudi->hw_cap_initialized & HW_CAP_MSI) return 0; - rc = pci_alloc_irq_vectors(hdev->pdev, 1, GAUDI_MSI_ENTRIES, - PCI_IRQ_MSI); + rc = pci_alloc_irq_vectors(hdev->pdev, 1, 1, PCI_IRQ_MSI); if (rc < 0) { dev_err(hdev->dev, "MSI: Failed to enable support %d\n", rc); return rc; @@ -3701,7 +3767,7 @@ static int gaudi_init_cpu(struct hl_device *hdev) struct gaudi_device *gaudi = hdev->asic_specific; int rc; - if (!hdev->cpu_enable) + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU)) return 0; if (gaudi->hw_cap_initialized & HW_CAP_CPU) @@ -4873,7 +4939,7 @@ static int gaudi_pin_memory_before_cs(struct hl_device *hdev, parser->job_userptr_list, &userptr)) goto already_pinned; - userptr = kzalloc(sizeof(*userptr), GFP_ATOMIC); + userptr = kzalloc(sizeof(*userptr), GFP_KERNEL); if (!userptr) return -ENOMEM; @@ -5684,18 +5750,26 @@ release_cb: static int gaudi_schedule_register_memset(struct hl_device *hdev, u32 hw_queue_id, u64 reg_base, u32 num_regs, u32 val) { - struct hl_ctx *ctx = hdev->compute_ctx; + struct hl_ctx *ctx; struct hl_pending_cb *pending_cb; struct packet_msg_long *pkt; u32 cb_size, ctl; struct hl_cb *cb; - int i; + int i, rc; + + mutex_lock(&hdev->fpriv_list_lock); + ctx = hdev->compute_ctx; /* If no compute context available or context is going down * memset registers directly */ - if (!ctx || kref_read(&ctx->refcount) == 0) - return gaudi_memset_registers(hdev, reg_base, num_regs, val); + if (!ctx || kref_read(&ctx->refcount) == 0) { + rc = gaudi_memset_registers(hdev, reg_base, num_regs, val); + mutex_unlock(&hdev->fpriv_list_lock); + return rc; + } + + mutex_unlock(&hdev->fpriv_list_lock); cb_size = (sizeof(*pkt) * num_regs) + sizeof(struct packet_msg_prot) * 2; @@ -5911,13 +5985,16 @@ static void gaudi_restore_phase_topology(struct hl_device *hdev) } -static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) +static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, + bool user_address, u32 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -5949,6 +6026,9 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE); } else { rc = -EFAULT; } @@ -5956,13 +6036,16 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) return rc; } -static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) +static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, + bool user_address, u32 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -5994,6 +6077,9 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; } else { rc = -EFAULT; } @@ -6001,13 +6087,16 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) return rc; } -static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) +static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, + bool user_address, u64 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -6043,6 +6132,9 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE); } else { rc = -EFAULT; } @@ -6050,13 +6142,16 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) return rc; } -static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) +static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, + bool user_address, u64 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -6091,6 +6186,9 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; } else { rc = -EFAULT; } @@ -6098,6 +6196,164 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) return rc; } +static int gaudi_dma_core_transfer(struct hl_device *hdev, int dma_id, u64 addr, + u32 size_to_dma, dma_addr_t dma_addr) +{ + u32 err_cause, val; + u64 dma_offset; + int rc; + + dma_offset = dma_id * DMA_CORE_OFFSET; + + WREG32(mmDMA0_CORE_SRC_BASE_LO + dma_offset, lower_32_bits(addr)); + WREG32(mmDMA0_CORE_SRC_BASE_HI + dma_offset, upper_32_bits(addr)); + WREG32(mmDMA0_CORE_DST_BASE_LO + dma_offset, lower_32_bits(dma_addr)); + WREG32(mmDMA0_CORE_DST_BASE_HI + dma_offset, upper_32_bits(dma_addr)); + WREG32(mmDMA0_CORE_DST_TSIZE_0 + dma_offset, size_to_dma); + WREG32(mmDMA0_CORE_COMMIT + dma_offset, + (1 << DMA0_CORE_COMMIT_LIN_SHIFT)); + + rc = hl_poll_timeout( + hdev, + mmDMA0_CORE_STS0 + dma_offset, + val, + ((val & DMA0_CORE_STS0_BUSY_MASK) == 0), + 0, + 1000000); + + if (rc) { + dev_err(hdev->dev, + "DMA %d timed-out during reading of 0x%llx\n", + dma_id, addr); + return -EIO; + } + + /* Verify DMA is OK */ + err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset); + if (err_cause) { + dev_err(hdev->dev, "DMA Failed, cause 0x%x\n", err_cause); + dev_dbg(hdev->dev, + "Clearing DMA0 engine from errors (cause 0x%x)\n", + err_cause); + WREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset, err_cause); + + return -EIO; + } + + return 0; +} + +static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, + void *blob_addr) +{ + u32 dma_core_sts0, err_cause, cfg1, size_left, pos, size_to_dma; + struct gaudi_device *gaudi = hdev->asic_specific; + u64 dma_offset, qm_offset; + dma_addr_t dma_addr; + void *kernel_addr; + bool is_eng_idle; + int rc = 0, dma_id; + + kernel_addr = hdev->asic_funcs->asic_dma_alloc_coherent( + hdev, SZ_2M, + &dma_addr, + GFP_KERNEL | __GFP_ZERO); + + if (!kernel_addr) + return -ENOMEM; + + mutex_lock(&gaudi->clk_gate_mutex); + + hdev->asic_funcs->disable_clock_gating(hdev); + + hdev->asic_funcs->hw_queues_lock(hdev); + + dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_1]; + dma_offset = dma_id * DMA_CORE_OFFSET; + qm_offset = dma_id * DMA_QMAN_OFFSET; + dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + dma_offset); + is_eng_idle = IS_DMA_IDLE(dma_core_sts0); + + if (!is_eng_idle) { + dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_2]; + dma_offset = dma_id * DMA_CORE_OFFSET; + qm_offset = dma_id * DMA_QMAN_OFFSET; + dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + dma_offset); + is_eng_idle = IS_DMA_IDLE(dma_core_sts0); + + if (!is_eng_idle) { + dev_err_ratelimited(hdev->dev, + "Can't read via DMA because it is BUSY\n"); + rc = -EAGAIN; + goto out; + } + } + + cfg1 = RREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset); + WREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset, + 0xF << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT); + + /* TODO: remove this by mapping the DMA temporary buffer to the MMU + * using the compute ctx ASID, if exists. If not, use the kernel ctx + * ASID + */ + WREG32_OR(mmDMA0_CORE_PROT + dma_offset, BIT(DMA0_CORE_PROT_VAL_SHIFT)); + + /* Verify DMA is OK */ + err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset); + if (err_cause) { + dev_dbg(hdev->dev, + "Clearing DMA0 engine from errors (cause 0x%x)\n", + err_cause); + WREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset, err_cause); + } + + pos = 0; + size_left = size; + size_to_dma = SZ_2M; + + while (size_left > 0) { + + if (size_left < SZ_2M) + size_to_dma = size_left; + + rc = gaudi_dma_core_transfer(hdev, dma_id, addr, size_to_dma, + dma_addr); + if (rc) + break; + + memcpy(blob_addr + pos, kernel_addr, size_to_dma); + + if (size_left <= SZ_2M) + break; + + pos += SZ_2M; + addr += SZ_2M; + size_left -= SZ_2M; + } + + /* TODO: remove this by mapping the DMA temporary buffer to the MMU + * using the compute ctx ASID, if exists. If not, use the kernel ctx + * ASID + */ + WREG32_AND(mmDMA0_CORE_PROT + dma_offset, + ~BIT(DMA0_CORE_PROT_VAL_SHIFT)); + + WREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset, cfg1); + +out: + hdev->asic_funcs->hw_queues_unlock(hdev); + + hdev->asic_funcs->set_clock_gating(hdev); + + mutex_unlock(&gaudi->clk_gate_mutex); + + hdev->asic_funcs->asic_dma_free_coherent(hdev, SZ_2M, kernel_addr, + dma_addr); + + return rc; +} + static u64 gaudi_read_pte(struct hl_device *hdev, u64 addr) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -6851,7 +7107,8 @@ static void gaudi_handle_qman_err_generic(struct hl_device *hdev, } /* Write 1 clear errors */ - WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val); + if (!hdev->stop_on_err) + WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val); } arb_err_val = RREG32(arb_err_addr); @@ -7097,6 +7354,15 @@ static void gaudi_print_irq_info(struct hl_device *hdev, u16 event_type, } } +static void gaudi_print_out_of_sync_info(struct hl_device *hdev, + struct cpucp_pkt_sync_err *sync_err) +{ + struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ]; + + dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n", + sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci)); +} + static int gaudi_soft_reset_late_init(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -7371,18 +7637,14 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_MMU_DERR: gaudi_print_irq_info(hdev, event_type, true); gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_GIC500: case GAUDI_EVENT_AXI_ECC: case GAUDI_EVENT_L2_RAM_ECC: case GAUDI_EVENT_PLL0 ... GAUDI_EVENT_PLL17: gaudi_print_irq_info(hdev, event_type, false); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_HBM0_SPI_0: case GAUDI_EVENT_HBM1_SPI_0: @@ -7392,9 +7654,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, gaudi_hbm_read_interrupts(hdev, gaudi_hbm_event_to_dev(event_type), &eq_entry->hbm_ecc_data); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_HBM0_SPI_1: case GAUDI_EVENT_HBM1_SPI_1: @@ -7423,8 +7683,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, dev_err(hdev->dev, "hard reset required due to %s\n", gaudi_irq_map_table[event_type].name); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + goto reset_device; } else { hl_fw_unmask_irq(hdev, event_type); } @@ -7446,8 +7705,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, dev_err(hdev->dev, "hard reset required due to %s\n", gaudi_irq_map_table[event_type].name); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + goto reset_device; } else { hl_fw_unmask_irq(hdev, event_type); } @@ -7516,9 +7774,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_RAZWI_OR_ADC_SW: gaudi_print_irq_info(hdev, event_type, true); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_TPC0_BMON_SPMU: case GAUDI_EVENT_TPC1_BMON_SPMU: @@ -7552,11 +7808,28 @@ static void gaudi_handle_eqe(struct hl_device *hdev, event_type, cause); break; + case GAUDI_EVENT_DEV_RESET_REQ: + gaudi_print_irq_info(hdev, event_type, false); + goto reset_device; + + case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC: + gaudi_print_irq_info(hdev, event_type, false); + gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); + goto reset_device; + default: dev_err(hdev->dev, "Received invalid H/W interrupt %d\n", event_type); break; } + + return; + +reset_device: + if (hdev->hard_reset_on_fw_events) + hl_device_reset(hdev, HL_RESET_HARD); + else + hl_fw_unmask_irq(hdev, event_type); } static void *gaudi_get_events_stat(struct hl_device *hdev, bool aggregate, @@ -7607,7 +7880,7 @@ static int gaudi_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; @@ -7656,7 +7929,7 @@ static int gaudi_mmu_invalidate_cache_range(struct hl_device *hdev, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; @@ -7714,7 +7987,7 @@ static int gaudi_cpucp_info_get(struct hl_device *hdev) if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q)) return 0; - rc = hl_fw_cpucp_info_get(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); + rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); if (rc) return rc; @@ -7724,10 +7997,7 @@ static int gaudi_cpucp_info_get(struct hl_device *hdev) hdev->card_type = le32_to_cpu(hdev->asic_prop.cpucp_info.card_type); - if (hdev->card_type == cpucp_card_type_pci) - prop->max_power_default = MAX_POWER_DEFAULT_PCI; - else if (hdev->card_type == cpucp_card_type_pmc) - prop->max_power_default = MAX_POWER_DEFAULT_PMC; + set_default_power_values(hdev); hdev->max_power = prop->max_power_default; @@ -8549,6 +8819,7 @@ static const struct hl_asic_funcs gaudi_funcs = { .debugfs_write32 = gaudi_debugfs_write32, .debugfs_read64 = gaudi_debugfs_read64, .debugfs_write64 = gaudi_debugfs_write64, + .debugfs_read_dma = gaudi_debugfs_read_dma, .add_device_attr = gaudi_add_device_attr, .handle_eqe = gaudi_handle_eqe, .set_pll_profile = gaudi_set_pll_profile, diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index 50bb4ad570fdad90e79ab400ca0a84f06c14d49f..5929be81ec230d82feb5b1bdd0506c722c07fb28 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -47,6 +47,9 @@ #define MAX_POWER_DEFAULT_PCI 200000 /* 200W */ #define MAX_POWER_DEFAULT_PMC 350000 /* 350W */ +#define DC_POWER_DEFAULT_PCI 60000 /* 60W */ +#define DC_POWER_DEFAULT_PMC 60000 /* 60W */ + #define GAUDI_CPU_TIMEOUT_USEC 30000000 /* 30s */ #define TPC_ENABLED_MASK 0xFF diff --git a/drivers/misc/habanalabs/gaudi/gaudi_security.c b/drivers/misc/habanalabs/gaudi/gaudi_security.c index 7085f45814ae4d9564b81e206b9dc5e09f7c09c2..9a706c5980ef147a6d7819bcee134742ef61e318 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi_security.c +++ b/drivers/misc/habanalabs/gaudi/gaudi_security.c @@ -9556,7 +9556,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC0_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC0_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_TPC_STALL & 0x7F) >> 2); @@ -10011,7 +10010,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC1_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC1_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_TPC_STALL & 0x7F) >> 2); @@ -10465,7 +10463,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC2_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC2_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_TPC_STALL & 0x7F) >> 2); @@ -10919,7 +10916,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC3_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC3_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_TPC_STALL & 0x7F) >> 2); @@ -11373,7 +11369,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC4_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC4_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_TPC_STALL & 0x7F) >> 2); @@ -11827,7 +11822,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC5_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC5_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_TPC_STALL & 0x7F) >> 2); @@ -12283,7 +12277,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC6_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC6_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_TPC_STALL & 0x7F) >> 2); @@ -12739,7 +12732,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC7_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC7_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_TPC_STALL & 0x7F) >> 2); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index ed566c52ccaa09313f17ab72b2070d42ca11bc18..e27338f4aad2f68afebc1d736ea2014d7e5231e7 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -118,6 +118,29 @@ #define IS_MME_IDLE(mme_arch_sts) \ (((mme_arch_sts) & MME_ARCH_IDLE_MASK) == MME_ARCH_IDLE_MASK) +/* + * this enum kept here for compatibility with old FW (in which each asic has + * unique PLL numbering + */ +enum goya_pll_index { + GOYA_CPU_PLL = 0, + GOYA_IC_PLL, + GOYA_MC_PLL, + GOYA_MME_PLL, + GOYA_PCI_PLL, + GOYA_EMMC_PLL, + GOYA_TPC_PLL, +}; + +static enum pll_index goya_pll_map[PLL_MAX] = { + [CPU_PLL] = GOYA_CPU_PLL, + [IC_PLL] = GOYA_IC_PLL, + [MC_PLL] = GOYA_MC_PLL, + [MME_PLL] = GOYA_MME_PLL, + [PCI_PLL] = GOYA_PCI_PLL, + [EMMC_PLL] = GOYA_EMMC_PLL, + [TPC_PLL] = GOYA_TPC_PLL, +}; static const char goya_irq_name[GOYA_MSIX_ENTRIES][GOYA_MAX_STRING_LEN] = { "goya cq 0", "goya cq 1", "goya cq 2", "goya cq 3", @@ -446,6 +469,7 @@ int goya_get_fixed_properties(struct hl_device *hdev) prop->cb_pool_cb_cnt = GOYA_CB_POOL_CB_CNT; prop->cb_pool_cb_size = GOYA_CB_POOL_CB_SIZE; prop->max_power_default = MAX_POWER_DEFAULT; + prop->dc_power_default = DC_POWER_DEFAULT; prop->tpc_enabled_mask = TPC_ENABLED_MASK; prop->pcie_dbi_base_address = mmPCIE_DBI_BASE; prop->pcie_aux_dbi_reg_addr = CFG_BASE + mmPCIE_AUX_DBI; @@ -460,8 +484,6 @@ int goya_get_fixed_properties(struct hl_device *hdev) for (i = 0 ; i < HL_MAX_DCORES ; i++) prop->first_available_cq[i] = USHRT_MAX; - /* disable fw security for now, set it in a later stage */ - prop->fw_security_disabled = true; prop->fw_security_status_valid = false; prop->hard_reset_done_by_fw = false; @@ -533,6 +555,11 @@ static int goya_init_iatu(struct hl_device *hdev) struct hl_outbound_pci_region outbound_region; int rc; + if (hdev->asic_prop.iatu_done_by_fw) { + hdev->asic_funcs->set_dma_mask_from_fw(hdev); + return 0; + } + /* Inbound Region 0 - Bar 0 - Point to SRAM and CFG */ inbound_region.mode = PCI_BAR_MATCH_MODE; inbound_region.bar = SRAM_CFG_BAR_ID; @@ -580,7 +607,7 @@ static int goya_early_init(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct pci_dev *pdev = hdev->pdev; - u32 val; + u32 fw_boot_status, val; int rc; rc = goya_get_fixed_properties(hdev); @@ -614,6 +641,23 @@ static int goya_early_init(struct hl_device *hdev) prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID); + /* If FW security is enabled at this point it means no access to ELBI */ + if (!hdev->asic_prop.fw_security_disabled) { + hdev->asic_prop.iatu_done_by_fw = true; + goto pci_init; + } + + rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0, + &fw_boot_status); + if (rc) + goto free_queue_props; + + /* Check whether FW is configuring iATU */ + if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) && + (fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN)) + hdev->asic_prop.iatu_done_by_fw = true; + +pci_init: rc = hl_pci_init(hdev); if (rc) goto free_queue_props; @@ -853,6 +897,9 @@ static int goya_sw_init(struct hl_device *hdev) hdev->asic_specific = goya; + /* store legacy PLL map */ + hdev->legacy_pll_map = goya_pll_map; + /* Create DMA pool for small allocations */ hdev->dma_pool = dma_pool_create(dev_name(hdev->dev), &hdev->pdev->dev, GOYA_DMA_POOL_BLK_SIZE, 8, 0); @@ -2429,7 +2476,7 @@ static int goya_init_cpu(struct hl_device *hdev) struct goya_device *goya = hdev->asic_specific; int rc; - if (!hdev->cpu_enable) + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU)) return 0; if (goya->hw_cap_initialized & HW_CAP_CPU) @@ -3221,7 +3268,7 @@ static int goya_pin_memory_before_cs(struct hl_device *hdev, parser->job_userptr_list, &userptr)) goto already_pinned; - userptr = kzalloc(sizeof(*userptr), GFP_ATOMIC); + userptr = kzalloc(sizeof(*userptr), GFP_KERNEL); if (!userptr) return -ENOMEM; @@ -4101,12 +4148,15 @@ static void goya_clear_sm_regs(struct hl_device *hdev) * lead to undefined behavior and therefore, should be done with extreme care * */ -static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) +static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, + bool user_address, u32 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { *val = RREG32(addr - CFG_BASE); @@ -4132,6 +4182,10 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE); + } else { rc = -EFAULT; } @@ -4154,12 +4208,15 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) * lead to undefined behavior and therefore, should be done with extreme care * */ -static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) +static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, + bool user_address, u32 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { WREG32(addr - CFG_BASE, val); @@ -4185,6 +4242,10 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; + } else { rc = -EFAULT; } @@ -4192,12 +4253,15 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) return rc; } -static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) +static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, + bool user_address, u64 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { u32 val_l = RREG32(addr - CFG_BASE); u32 val_h = RREG32(addr + sizeof(u32) - CFG_BASE); @@ -4227,6 +4291,10 @@ static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE); + } else { rc = -EFAULT; } @@ -4234,12 +4302,15 @@ static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) return rc; } -static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) +static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, + bool user_address, u64 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { WREG32(addr - CFG_BASE, lower_32_bits(val)); WREG32(addr + sizeof(u32) - CFG_BASE, upper_32_bits(val)); @@ -4267,6 +4338,10 @@ static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; + } else { rc = -EFAULT; } @@ -4274,6 +4349,13 @@ static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) return rc; } +static int goya_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, + void *blob_addr) +{ + dev_err(hdev->dev, "Reading via DMA is unimplemented yet\n"); + return -EPERM; +} + static u64 goya_read_pte(struct hl_device *hdev, u64 addr) { struct goya_device *goya = hdev->asic_specific; @@ -4401,6 +4483,8 @@ static const char *_goya_get_event_desc(u16 event_type) return "THERMAL_ENV_S"; case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E: return "THERMAL_ENV_E"; + case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: + return "QUEUE_OUT_OF_SYNC"; default: return "N/A"; } @@ -4483,6 +4567,9 @@ static void goya_get_event_desc(u16 event_type, char *desc, size_t size) index = event_type - GOYA_ASYNC_EVENT_ID_DMA_BM_CH0; snprintf(desc, size, _goya_get_event_desc(event_type), index); break; + case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: + snprintf(desc, size, _goya_get_event_desc(event_type)); + break; default: snprintf(desc, size, _goya_get_event_desc(event_type)); break; @@ -4534,6 +4621,15 @@ static void goya_print_mmu_error_info(struct hl_device *hdev) } } +static void goya_print_out_of_sync_info(struct hl_device *hdev, + struct cpucp_pkt_sync_err *sync_err) +{ + struct hl_hw_queue *q = &hdev->kernel_queues[GOYA_QUEUE_ID_CPU_PQ]; + + dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n", + sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci)); +} + static void goya_print_irq_info(struct hl_device *hdev, u16 event_type, bool razwi) { @@ -4698,7 +4794,7 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET: goya_print_irq_info(hdev, event_type, false); if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); break; case GOYA_ASYNC_EVENT_ID_PCIE_DEC: @@ -4754,6 +4850,15 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) goya_unmask_irq(hdev, event_type); break; + case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: + goya_print_irq_info(hdev, event_type, false); + goya_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); + if (hdev->hard_reset_on_fw_events) + hl_device_reset(hdev, HL_RESET_HARD); + else + hl_fw_unmask_irq(hdev, event_type); + break; + default: dev_err(hdev->dev, "Received invalid H/W interrupt %d\n", event_type); @@ -5083,7 +5188,7 @@ static int goya_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; @@ -5134,7 +5239,7 @@ static int goya_mmu_invalidate_cache_range(struct hl_device *hdev, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; @@ -5160,7 +5265,7 @@ int goya_cpucp_info_get(struct hl_device *hdev) if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) return 0; - rc = hl_fw_cpucp_info_get(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); + rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); if (rc) return rc; @@ -5443,6 +5548,7 @@ static const struct hl_asic_funcs goya_funcs = { .debugfs_write32 = goya_debugfs_write32, .debugfs_read64 = goya_debugfs_read64, .debugfs_write64 = goya_debugfs_write64, + .debugfs_read_dma = goya_debugfs_read_dma, .add_device_attr = goya_add_device_attr, .handle_eqe = goya_handle_eqe, .set_pll_profile = goya_set_pll_profile, diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h index 23fe099ed218c73439b9ff665aa8e96e1a00dd5a..ef8c6c8b5c8dc780077850fd460a76ab359de395 100644 --- a/drivers/misc/habanalabs/goya/goyaP.h +++ b/drivers/misc/habanalabs/goya/goyaP.h @@ -49,6 +49,8 @@ #define MAX_POWER_DEFAULT 200000 /* 200W */ +#define DC_POWER_DEFAULT 20000 /* 20W */ + #define DRAM_PHYS_DEFAULT_SIZE 0x100000000ull /* 4GB */ #define GOYA_DEFAULT_CARD_NAME "HL1000" diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index b77c1c16c32cf49acbc0450ef948bc88a49274a3..27cd0ba99aa3381e4ee9c07906cf425658eb7a1c 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -11,6 +11,8 @@ #include <linux/types.h> #include <linux/if_ether.h> +#include "hl_boot_if.h" + #define NUM_HBM_PSEUDO_CH 2 #define NUM_HBM_CH_PER_DEV 8 #define CPUCP_PKT_HBM_ECC_INFO_WR_PAR_SHIFT 0 @@ -28,6 +30,17 @@ #define CPUCP_PKT_HBM_ECC_INFO_HBM_CH_SHIFT 6 #define CPUCP_PKT_HBM_ECC_INFO_HBM_CH_MASK 0x000007C0 +#define PLL_MAP_MAX_BITS 128 +#define PLL_MAP_LEN (PLL_MAP_MAX_BITS / 8) + +/* + * info of the pkt queue pointers in the first async occurrence + */ +struct cpucp_pkt_sync_err { + __le32 pi; + __le32 ci; +}; + struct hl_eq_hbm_ecc_data { /* SERR counter */ __le32 sec_cnt; @@ -77,6 +90,7 @@ struct hl_eq_entry { struct hl_eq_ecc_data ecc_data; struct hl_eq_hbm_ecc_data hbm_ecc_data; struct hl_eq_sm_sei_data sm_sei_data; + struct cpucp_pkt_sync_err pkt_sync_err; __le64 data[7]; }; }; @@ -287,6 +301,30 @@ enum pq_init_status { * The result is composed of 4 outputs, each is 16-bit * frequency in MHz. * + * CPUCP_PACKET_POWER_GET + * Fetch the present power consumption of the device (Current * Voltage). + * + * CPUCP_PACKET_NIC_PFC_SET - + * Enable/Disable the NIC PFC feature. The packet's arguments specify the + * NIC port, relevant lanes to configure and one bit indication for + * enable/disable. + * + * CPUCP_PACKET_NIC_FAULT_GET - + * Fetch the current indication for local/remote faults from the NIC MAC. + * The result is 32-bit value of the relevant register. + * + * CPUCP_PACKET_NIC_LPBK_SET - + * Enable/Disable the MAC loopback feature. The packet's arguments specify + * the NIC port, relevant lanes to configure and one bit indication for + * enable/disable. + * + * CPUCP_PACKET_NIC_MAC_INIT - + * Configure the NIC MAC channels. The packet's arguments specify the + * NIC port and the speed. + * + * CPUCP_PACKET_MSI_INFO_SET - + * set the index number for each supported msi type going from + * host to device */ enum cpucp_packet_id { @@ -320,6 +358,13 @@ enum cpucp_packet_id { CPUCP_PACKET_PCIE_REPLAY_CNT_GET, /* internal */ CPUCP_PACKET_TOTAL_ENERGY_GET, /* internal */ CPUCP_PACKET_PLL_INFO_GET, /* internal */ + CPUCP_PACKET_NIC_STATUS, /* internal */ + CPUCP_PACKET_POWER_GET, /* internal */ + CPUCP_PACKET_NIC_PFC_SET, /* internal */ + CPUCP_PACKET_NIC_FAULT_GET, /* internal */ + CPUCP_PACKET_NIC_LPBK_SET, /* internal */ + CPUCP_PACKET_NIC_MAC_CFG, /* internal */ + CPUCP_PACKET_MSI_INFO_SET, /* internal */ }; #define CPUCP_PACKET_FENCE_VAL 0xFE8CE7A5 @@ -391,6 +436,12 @@ struct cpucp_unmask_irq_arr_packet { __le32 irqs[0]; }; +struct cpucp_array_data_packet { + struct cpucp_packet cpucp_pkt; + __le32 length; + __le32 data[0]; +}; + enum cpucp_packet_rc { cpucp_packet_success, cpucp_packet_invalid, @@ -459,6 +510,51 @@ enum cpucp_pll_type_attributes { cpucp_pll_pci, }; +/* + * MSI type enumeration table for all ASICs and future SW versions. + * For future ASIC-LKD compatibility, we can only add new enumerations. + * at the end of the table (before CPUCP_NUM_OF_MSI_TYPES). + * Changing the order of entries or removing entries is not allowed. + */ +enum cpucp_msi_type { + CPUCP_EVENT_QUEUE_MSI_TYPE, + CPUCP_NIC_PORT1_MSI_TYPE, + CPUCP_NIC_PORT3_MSI_TYPE, + CPUCP_NIC_PORT5_MSI_TYPE, + CPUCP_NIC_PORT7_MSI_TYPE, + CPUCP_NIC_PORT9_MSI_TYPE, + CPUCP_NUM_OF_MSI_TYPES +}; + +/* + * PLL enumeration table used for all ASICs and future SW versions. + * For future ASIC-LKD compatibility, we can only add new enumerations. + * at the end of the table. + * Changing the order of entries or removing entries is not allowed. + */ +enum pll_index { + CPU_PLL = 0, + PCI_PLL = 1, + NIC_PLL = 2, + DMA_PLL = 3, + MESH_PLL = 4, + MME_PLL = 5, + TPC_PLL = 6, + IF_PLL = 7, + SRAM_PLL = 8, + NS_PLL = 9, + HBM_PLL = 10, + MSS_PLL = 11, + DDR_PLL = 12, + VID_PLL = 13, + BANK_PLL = 14, + MMU_PLL = 15, + IC_PLL = 16, + MC_PLL = 17, + EMMC_PLL = 18, + PLL_MAX +}; + /* Event Queue Packets */ struct eq_generic_event { @@ -470,7 +566,6 @@ struct eq_generic_event { */ #define CARD_NAME_MAX_LEN 16 -#define VERSION_MAX_LEN 128 #define CPUCP_MAX_SENSORS 128 #define CPUCP_MAX_NICS 128 #define CPUCP_LANES_PER_NIC 4 @@ -533,6 +628,7 @@ struct cpucp_security_info { * @dram_size: available DRAM size. * @card_name: card name that will be displayed in HWMON subsystem on the host * @sec_info: security information + * @pll_map: Bit map of supported PLLs for current ASIC version. */ struct cpucp_info { struct cpucp_sensor sensors[CPUCP_MAX_SENSORS]; @@ -554,6 +650,7 @@ struct cpucp_info { __u8 pad[7]; struct cpucp_security_info sec_info; __le32 reserved6; + __u8 pll_map[PLL_MAP_LEN]; }; struct cpucp_mac_addr { diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index e87f5a98e19391570977c5d7bcba18eb249551fe..e0a259e0495cfad294bfe6a0ad87f1b6fc7795d2 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -13,6 +13,8 @@ #define BOOT_FIT_SRAM_OFFSET 0x200000 +#define VERSION_MAX_LEN 128 + /* * CPU error bits in BOOT_ERROR registers * @@ -73,6 +75,9 @@ * CPU_BOOT_ERR0_PLL_FAIL PLL settings failed, meaning that one * of the PLLs remains in REF_CLK * + * CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL Device is unusable and customer support + * should be contacted. + * * CPU_BOOT_ERR0_ENABLED Error registers enabled. * This is a main indication that the * running FW populates the error @@ -92,6 +97,7 @@ #define CPU_BOOT_ERR0_PRI_IMG_VER_FAIL (1 << 10) #define CPU_BOOT_ERR0_SEC_IMG_VER_FAIL (1 << 11) #define CPU_BOOT_ERR0_PLL_FAIL (1 << 12) +#define CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL (1 << 13) #define CPU_BOOT_ERR0_ENABLED (1 << 31) /* @@ -170,6 +176,20 @@ * is set to the PI counter. * Initialized in: linux * + * CPU_BOOT_DEV_STS0_FW_LD_COM_EN Flexible FW loading communication + * protocol is enabled. + * Initialized in: preboot + * + * CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN FW iATU configuration is enabled. + * This bit if set, means the iATU has been + * configured and is ready for use. + * Initialized in: ppboot + * + * CPU_BOOT_DEV_STS0_DYN_PLL_EN Dynamic PLL configuration is enabled. + * FW sends to host a bitmap of supported + * PLLs. + * Initialized in: linux + * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the * running FW populates the device status @@ -195,6 +215,9 @@ #define CPU_BOOT_DEV_STS0_CLK_GATE_EN (1 << 13) #define CPU_BOOT_DEV_STS0_HBM_ECC_EN (1 << 14) #define CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN (1 << 15) +#define CPU_BOOT_DEV_STS0_FW_LD_COM_EN (1 << 16) +#define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17) +#define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) enum cpu_boot_status { @@ -230,6 +253,7 @@ enum kmd_msg { KMD_MSG_SKIP_BMC, RESERVED, KMD_MSG_RST_DEV, + KMD_MSG_LAST }; enum cpu_msg_status { @@ -238,4 +262,199 @@ enum cpu_msg_status { CPU_MSG_ERR, }; +/* communication registers mapping - consider ABI when changing */ +struct cpu_dyn_regs { + uint32_t cpu_pq_base_addr_low; + uint32_t cpu_pq_base_addr_high; + uint32_t cpu_pq_length; + uint32_t cpu_pq_init_status; + uint32_t cpu_eq_base_addr_low; + uint32_t cpu_eq_base_addr_high; + uint32_t cpu_eq_length; + uint32_t cpu_eq_ci; + uint32_t cpu_cq_base_addr_low; + uint32_t cpu_cq_base_addr_high; + uint32_t cpu_cq_length; + uint32_t cpu_pf_pq_pi; + uint32_t cpu_boot_dev_sts0; + uint32_t cpu_boot_dev_sts1; + uint32_t cpu_boot_err0; + uint32_t cpu_boot_err1; + uint32_t cpu_boot_status; + uint32_t fw_upd_sts; + uint32_t fw_upd_cmd; + uint32_t fw_upd_pending_sts; + uint32_t fuse_ver_offset; + uint32_t preboot_ver_offset; + uint32_t uboot_ver_offset; + uint32_t hw_state; + uint32_t kmd_msg_to_cpu; + uint32_t cpu_cmd_status_to_host; + uint32_t reserved1[32]; /* reserve for future use */ +}; + +/* HCDM - Habana Communications Descriptor Magic */ +#define HL_COMMS_DESC_MAGIC 0x4843444D +#define HL_COMMS_DESC_VER 1 + +/* this is the comms descriptor header - meta data */ +struct comms_desc_header { + uint32_t magic; /* magic for validation */ + uint32_t crc32; /* CRC32 of the descriptor w/o header */ + uint16_t size; /* size of the descriptor w/o header */ + uint8_t version; /* descriptor version */ + uint8_t reserved[5]; /* pad to 64 bit */ +}; + +/* this is the main FW descriptor - consider ABI when changing */ +struct lkd_fw_comms_desc { + struct comms_desc_header header; + struct cpu_dyn_regs cpu_dyn_regs; + char fuse_ver[VERSION_MAX_LEN]; + char cur_fw_ver[VERSION_MAX_LEN]; + /* can be used for 1 more version w/o ABI change */ + char reserved0[VERSION_MAX_LEN]; + uint64_t img_addr; /* address for next FW component load */ +}; + +/* + * LKD commands: + * + * COMMS_NOOP Used to clear the command register and no actual + * command is send. + * + * COMMS_CLR_STS Clear status command - FW should clear the + * status register. Used for synchronization + * between the commands as part of the race free + * protocol. + * + * COMMS_RST_STATE Reset the current communication state which is + * kept by FW for proper responses. + * Should be used in the beginning of the + * communication cycle to clean any leftovers from + * previous communication attempts. + * + * COMMS_PREP_DESC Prepare descriptor for setting up the + * communication and other dynamic data: + * struct lkd_fw_comms_desc. + * This command has a parameter stating the next FW + * component size, so the FW can actually prepare a + * space for it and in the status response provide + * the descriptor offset. The Offset of the next FW + * data component is a part of the descriptor + * structure. + * + * COMMS_DATA_RDY The FW data has been uploaded and is ready for + * validation. + * + * COMMS_EXEC Execute the next FW component. + * + * COMMS_RST_DEV Reset the device. + * + * COMMS_GOTO_WFE Execute WFE command. Allowed only on non-secure + * devices. + * + * COMMS_SKIP_BMC Perform actions required for BMC-less servers. + * Do not wait for BMC response. + * + * COMMS_LOW_PLL_OPP Initialize PLLs for low OPP. + */ +enum comms_cmd { + COMMS_NOOP = 0, + COMMS_CLR_STS = 1, + COMMS_RST_STATE = 2, + COMMS_PREP_DESC = 3, + COMMS_DATA_RDY = 4, + COMMS_EXEC = 5, + COMMS_RST_DEV = 6, + COMMS_GOTO_WFE = 7, + COMMS_SKIP_BMC = 8, + COMMS_LOW_PLL_OPP = 9, + COMMS_INVLD_LAST +}; + +#define COMMS_COMMAND_SIZE_SHIFT 0 +#define COMMS_COMMAND_SIZE_MASK 0x1FFFFFF +#define COMMS_COMMAND_CMD_SHIFT 27 +#define COMMS_COMMAND_CMD_MASK 0xF8000000 + +/* + * LKD command to FW register structure + * @size - FW component size + * @cmd - command from enum comms_cmd + */ +struct comms_command { + union { /* bit fields are only for FW use */ + struct { + unsigned int size :25; /* 32MB max. */ + unsigned int reserved :2; + enum comms_cmd cmd :5; /* 32 commands */ + }; + unsigned int val; + }; +}; + +/* + * FW status + * + * COMMS_STS_NOOP Used to clear the status register and no actual + * status is provided. + * + * COMMS_STS_ACK Command has been received and recognized. + * + * COMMS_STS_OK Command execution has finished successfully. + * + * COMMS_STS_ERR Command execution was unsuccessful and resulted + * in error. + * + * COMMS_STS_VALID_ERR FW validation has failed. + * + * COMMS_STS_TIMEOUT_ERR Command execution has timed out. + */ +enum comms_sts { + COMMS_STS_NOOP = 0, + COMMS_STS_ACK = 1, + COMMS_STS_OK = 2, + COMMS_STS_ERR = 3, + COMMS_STS_VALID_ERR = 4, + COMMS_STS_TIMEOUT_ERR = 5, + COMMS_STS_INVLD_LAST +}; + +/* RAM types for FW components loading - defines the base address */ +enum comms_ram_types { + COMMS_SRAM = 0, + COMMS_DRAM = 1, +}; + +#define COMMS_STATUS_OFFSET_SHIFT 0 +#define COMMS_STATUS_OFFSET_MASK 0x03FFFFFF +#define COMMS_STATUS_OFFSET_ALIGN_SHIFT 2 +#define COMMS_STATUS_RAM_TYPE_SHIFT 26 +#define COMMS_STATUS_RAM_TYPE_MASK 0x0C000000 +#define COMMS_STATUS_STATUS_SHIFT 28 +#define COMMS_STATUS_STATUS_MASK 0xF0000000 + +/* + * FW status to LKD register structure + * @offset - an offset from the base of the ram_type shifted right by + * 2 bits (always aligned to 32 bits). + * Allows a maximum addressable offset of 256MB from RAM base. + * Example: for real offset in RAM of 0x800000 (8MB), the value + * in offset field is (0x800000 >> 2) = 0x200000. + * @ram_type - the RAM type that should be used for offset from + * enum comms_ram_types + * @status - status from enum comms_sts + */ +struct comms_status { + union { /* bit fields are only for FW use */ + struct { + unsigned int offset :26; + unsigned int ram_type :2; + enum comms_sts status :4; /* 16 statuses */ + }; + unsigned int val; + }; +}; + #endif /* HL_BOOT_IF_H */ diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi.h b/drivers/misc/habanalabs/include/gaudi/gaudi.h index f9ea897ae42c38ec96f281263d74cf52b3060c8b..ffae107b1693502f69f27169e055f075ff246e5d 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi.h @@ -38,7 +38,7 @@ #define QMAN_PQ_ENTRY_SIZE 16 /* Bytes */ -#define MAX_ASID 1024 +#define MAX_ASID 2 #define PROT_BITS_OFFS 0xF80 diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index 49335e8334b424f3fcf87fe86cb24aeaa7a0c7ba..e8651abf84f22be2439251ca712f5fc5f1e05b71 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -303,6 +303,8 @@ enum gaudi_async_event_id { GAUDI_EVENT_NIC3_QP1 = 619, GAUDI_EVENT_NIC4_QP0 = 620, GAUDI_EVENT_NIC4_QP1 = 621, + GAUDI_EVENT_DEV_RESET_REQ = 646, + GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, GAUDI_EVENT_FIX_POWER_ENV_S = 658, GAUDI_EVENT_FIX_POWER_ENV_E = 659, GAUDI_EVENT_FIX_THERMAL_ENV_S = 660, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index 737176ba06fb61c4f3ceb00e8c3663361e927b7c..3dc79c1318059601a59e3f2ab2ea41cf5f0ad744 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -301,10 +301,10 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 274, .cpu_id = 128, .valid = 0, .name = "" }, { .fc_id = 275, .cpu_id = 128, .valid = 0, .name = "" }, { .fc_id = 276, .cpu_id = 128, .valid = 0, .name = "" }, - { .fc_id = 277, .cpu_id = 129, .valid = 0, .name = "" }, - { .fc_id = 278, .cpu_id = 129, .valid = 0, .name = "" }, - { .fc_id = 279, .cpu_id = 129, .valid = 0, .name = "" }, - { .fc_id = 280, .cpu_id = 129, .valid = 0, .name = "" }, + { .fc_id = 277, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_0" }, + { .fc_id = 278, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_1" }, + { .fc_id = 279, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_2" }, + { .fc_id = 280, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_3" }, { .fc_id = 281, .cpu_id = 130, .valid = 0, .name = "" }, { .fc_id = 282, .cpu_id = 131, .valid = 0, .name = "" }, { .fc_id = 283, .cpu_id = 132, .valid = 0, .name = "" }, @@ -670,18 +670,29 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 643, .cpu_id = 492, .valid = 0, .name = "" }, { .fc_id = 644, .cpu_id = 493, .valid = 0, .name = "" }, { .fc_id = 645, .cpu_id = 494, .valid = 0, .name = "" }, - { .fc_id = 646, .cpu_id = 495, .valid = 0, .name = "" }, - { .fc_id = 647, .cpu_id = 496, .valid = 0, .name = "" }, - { .fc_id = 648, .cpu_id = 497, .valid = 0, .name = "" }, - { .fc_id = 649, .cpu_id = 498, .valid = 0, .name = "" }, - { .fc_id = 650, .cpu_id = 499, .valid = 0, .name = "" }, - { .fc_id = 651, .cpu_id = 500, .valid = 0, .name = "" }, - { .fc_id = 652, .cpu_id = 501, .valid = 0, .name = "" }, - { .fc_id = 653, .cpu_id = 502, .valid = 0, .name = "" }, - { .fc_id = 654, .cpu_id = 503, .valid = 0, .name = "" }, - { .fc_id = 655, .cpu_id = 504, .valid = 0, .name = "" }, - { .fc_id = 656, .cpu_id = 505, .valid = 0, .name = "" }, - { .fc_id = 657, .cpu_id = 506, .valid = 0, .name = "" }, + { .fc_id = 646, .cpu_id = 495, .valid = 1, .name = "DEV_RESET_REQ" }, + { .fc_id = 647, .cpu_id = 496, .valid = 1, + .name = "PKT_QUEUE_OUT_SYNC" }, + { .fc_id = 648, .cpu_id = 497, .valid = 1, + .name = "STATUS_NIC0_ENG0" }, + { .fc_id = 649, .cpu_id = 498, .valid = 1, + .name = "STATUS_NIC0_ENG1" }, + { .fc_id = 650, .cpu_id = 499, .valid = 1, + .name = "STATUS_NIC1_ENG0" }, + { .fc_id = 651, .cpu_id = 500, .valid = 1, + .name = "STATUS_NIC1_ENG1" }, + { .fc_id = 652, .cpu_id = 501, .valid = 1, + .name = "STATUS_NIC2_ENG0" }, + { .fc_id = 653, .cpu_id = 502, .valid = 1, + .name = "STATUS_NIC2_ENG1" }, + { .fc_id = 654, .cpu_id = 503, .valid = 1, + .name = "STATUS_NIC3_ENG0" }, + { .fc_id = 655, .cpu_id = 504, .valid = 1, + .name = "STATUS_NIC3_ENG1" }, + { .fc_id = 656, .cpu_id = 505, .valid = 1, + .name = "STATUS_NIC4_ENG0" }, + { .fc_id = 657, .cpu_id = 506, .valid = 1, + .name = "STATUS_NIC4_ENG1" }, { .fc_id = 658, .cpu_id = 507, .valid = 1, .name = "FIX_POWER_ENV_S" }, { .fc_id = 659, .cpu_id = 508, .valid = 1, .name = "FIX_POWER_ENV_E" }, { .fc_id = 660, .cpu_id = 509, .valid = 1, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h index 25acd9e87e209c4bb2826aab80890a1c1a1d7e0f..a9f51f9f9e92bc22298d11472c9ef6a607ecbb77 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h @@ -20,20 +20,6 @@ #define UBOOT_FW_OFFSET 0x100000 /* 1MB in SRAM */ #define LINUX_FW_OFFSET 0x800000 /* 8MB in HBM */ -enum gaudi_pll_index { - CPU_PLL = 0, - PCI_PLL, - SRAM_PLL, - HBM_PLL, - NIC_PLL, - DMA_PLL, - MESH_PLL, - MME_PLL, - TPC_PLL, - IF_PLL, - PLL_MAX -}; - enum gaudi_nic_axi_error { RXB, RXE, diff --git a/drivers/misc/habanalabs/include/goya/goya.h b/drivers/misc/habanalabs/include/goya/goya.h index 43d241891e4560f1cb27ef1db8e89760cf4ea9d8..1b4ca435021d7a39c3390add86800526c666f6f6 100644 --- a/drivers/misc/habanalabs/include/goya/goya.h +++ b/drivers/misc/habanalabs/include/goya/goya.h @@ -30,7 +30,7 @@ #define QMAN_PQ_ENTRY_SIZE 16 /* Bytes */ -#define MAX_ASID 1024 +#define MAX_ASID 2 #define PROT_BITS_OFFS 0xF80 diff --git a/drivers/misc/habanalabs/include/goya/goya_async_events.h b/drivers/misc/habanalabs/include/goya/goya_async_events.h index 5fb92362fc5feae9db36cab37fb5b38e18b09ce8..09081401cb1dd9542c0e2da5121e2165bef45119 100644 --- a/drivers/misc/habanalabs/include/goya/goya_async_events.h +++ b/drivers/misc/habanalabs/include/goya/goya_async_events.h @@ -188,6 +188,7 @@ enum goya_async_event_id { GOYA_ASYNC_EVENT_ID_HALT_MACHINE = 485, GOYA_ASYNC_EVENT_ID_INTS_REGISTER = 486, GOYA_ASYNC_EVENT_ID_SOFT_RESET = 487, + GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC = 506, GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S = 507, GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E = 508, GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S = 509, diff --git a/drivers/misc/habanalabs/include/goya/goya_fw_if.h b/drivers/misc/habanalabs/include/goya/goya_fw_if.h index daf8d8cd14be7e2d8642a8a2b69e301ffd389878..bc05f86c73ac0980ea745408a2596e995e6fcc2d 100644 --- a/drivers/misc/habanalabs/include/goya/goya_fw_if.h +++ b/drivers/misc/habanalabs/include/goya/goya_fw_if.h @@ -15,17 +15,6 @@ #define UBOOT_FW_OFFSET 0x100000 /* 1MB in SRAM */ #define LINUX_FW_OFFSET 0x800000 /* 8MB in DDR */ -enum goya_pll_index { - CPU_PLL = 0, - IC_PLL, - MC_PLL, - MME_PLL, - PCI_PLL, - EMMC_PLL, - TPC_PLL, - PLL_MAX -}; - #define GOYA_PLL_FREQ_LOW 50000000 /* 50 MHz */ #endif /* GOYA_FW_IF_H */ diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 945701bce553692ad660710ac996be427b5deaf6..64d33e3685091352aa6cab2b8ffd4a70c109bb5c 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -92,22 +92,23 @@ #include <linux/kthread.h> #include <linux/module.h> #include <linux/sched/task.h> +#include <linux/kallsyms.h> #include <asm/sections.h> -#define v1printk(a...) do { \ - if (verbose) \ - printk(KERN_INFO a); \ - } while (0) -#define v2printk(a...) do { \ - if (verbose > 1) \ - printk(KERN_INFO a); \ - touch_nmi_watchdog(); \ - } while (0) -#define eprintk(a...) do { \ - printk(KERN_ERR a); \ - WARN_ON(1); \ - } while (0) +#define v1printk(a...) do { \ + if (verbose) \ + printk(KERN_INFO a); \ +} while (0) +#define v2printk(a...) do { \ + if (verbose > 1) \ + printk(KERN_INFO a); \ + touch_nmi_watchdog(); \ +} while (0) +#define eprintk(a...) do { \ + printk(KERN_ERR a); \ + WARN_ON(1); \ +} while (0) #define MAX_CONFIG_LEN 40 static struct kgdb_io kgdbts_io_ops; @@ -200,21 +201,30 @@ static noinline void kgdbts_break_test(void) v2printk("kgdbts: breakpoint complete\n"); } -/* Lookup symbol info in the kernel */ +/* + * This is a cached wrapper for kallsyms_lookup_name(). + * + * The cache is a big win for several tests. For example it more the doubles + * the cycles per second during the sys_open test. This is not theoretic, + * the performance improvement shows up at human scale, especially when + * testing using emulators. + * + * Obviously neither re-entrant nor thread-safe but that is OK since it + * can only be called from the debug trap (and therefore all other CPUs + * are halted). + */ static unsigned long lookup_addr(char *arg) { - unsigned long addr = 0; - - if (!strcmp(arg, "kgdbts_break_test")) - addr = (unsigned long)kgdbts_break_test; - else if (!strcmp(arg, "sys_open")) - addr = (unsigned long)do_sys_open; - else if (!strcmp(arg, "kernel_clone")) - addr = (unsigned long)kernel_clone; - else if (!strcmp(arg, "hw_break_val")) - addr = (unsigned long)&hw_break_val; - addr = (unsigned long) dereference_function_descriptor((void *)addr); - return addr; + static char cached_arg[KSYM_NAME_LEN]; + static unsigned long cached_addr; + + if (strcmp(arg, cached_arg)) { + strscpy(cached_arg, arg, KSYM_NAME_LEN); + cached_addr = kallsyms_lookup_name(arg); + } + + return (unsigned long)dereference_function_descriptor( + (void *)cached_addr); } static void break_helper(char *bp_type, char *arg, unsigned long vaddr) @@ -310,7 +320,7 @@ static int check_and_rewind_pc(char *put_str, char *arg) if (arch_needs_sstep_emulation && sstep_addr && ip + offset == sstep_addr && - ((!strcmp(arg, "sys_open") || !strcmp(arg, "kernel_clone")))) { + ((!strcmp(arg, "do_sys_openat2") || !strcmp(arg, "kernel_clone")))) { /* This is special case for emulated single step */ v2printk("Emul: rewind hit single step bp\n"); restart_from_top_after_write = 1; @@ -619,14 +629,14 @@ static struct test_struct do_kernel_clone_test[] = { */ static struct test_struct sys_open_test[] = { { "?", "S0*" }, /* Clear break points */ - { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ + { "do_sys_openat2", "OK", sw_break, }, /* set sw breakpoint */ { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ - { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ - { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ + { "do_sys_openat2", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "do_sys_openat2", NULL, check_and_rewind_pc }, /* check location */ { "write", "OK", write_regs, emul_reset }, /* Write registers */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ - { "g", "sys_open", NULL, check_single_step }, - { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ + { "g", "do_sys_openat2", NULL, check_single_step }, + { "do_sys_openat2", "OK", sw_break, }, /* set sw breakpoint */ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ { "", "", get_cont_catch, put_cont_catch }, diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index dd65cedf3b125370ed16ebcf8cc5f76349875340..70c5bb1e6f4966058be0dd133dcf6b5047185516 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -208,7 +208,7 @@ static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; static int lis3_3dlh_rates[4] = {50, 100, 400, 1000}; /* ODR is Output Data Rate */ -static int lis3lv02d_get_odr(struct lis3lv02d *lis3) +static int lis3lv02d_get_odr_index(struct lis3lv02d *lis3) { u8 ctrl; int shift; @@ -216,15 +216,23 @@ static int lis3lv02d_get_odr(struct lis3lv02d *lis3) lis3->read(lis3, CTRL_REG1, &ctrl); ctrl &= lis3->odr_mask; shift = ffs(lis3->odr_mask) - 1; - return lis3->odrs[(ctrl >> shift)]; + return (ctrl >> shift); } static int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3) { - int div = lis3lv02d_get_odr(lis3); + int odr_idx = lis3lv02d_get_odr_index(lis3); + int div = lis3->odrs[odr_idx]; - if (WARN_ONCE(div == 0, "device returned spurious data")) + if (div == 0) { + if (odr_idx == 0) { + /* Power-down mode, not sampling no need to sleep */ + return 0; + } + + dev_err(&lis3->pdev->dev, "Error unknown odrs-index: %d\n", odr_idx); return -ENXIO; + } /* LIS3 power on delay is quite long */ msleep(lis3->pwron_delay / div); @@ -816,9 +824,12 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lis3lv02d *lis3 = dev_get_drvdata(dev); + int odr_idx; lis3lv02d_sysfs_poweron(lis3); - return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3)); + + odr_idx = lis3lv02d_get_odr_index(lis3); + return sprintf(buf, "%d\n", lis3->odrs[odr_idx]); } static ssize_t lis3lv02d_rate_set(struct device *dev, @@ -1162,16 +1173,14 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3) break; default: pr_err("unknown sensor type 0x%X\n", lis3->whoami); - return -EINVAL; + return -ENODEV; } lis3->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), sizeof(lis3_wai12_regs)), GFP_KERNEL); - if (lis3->reg_cache == NULL) { - printk(KERN_ERR DRIVER_NAME "out of memory\n"); + if (lis3->reg_cache == NULL) return -ENOMEM; - } mutex_init(&lis3->mutex); atomic_set(&lis3->wake_thread, 0); diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 110f5a8538e9662b39f5bf5003d5a00647c76ebb..0e8254d0cf0ba83b6e0a40d515e972aed30498d9 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -134,6 +134,23 @@ noinline void lkdtm_CORRUPT_STACK_STRONG(void) __lkdtm_CORRUPT_STACK((void *)&data); } +static pid_t stack_pid; +static unsigned long stack_addr; + +void lkdtm_REPORT_STACK(void) +{ + volatile uintptr_t magic; + pid_t pid = task_pid_nr(current); + + if (pid != stack_pid) { + pr_info("Starting stack offset tracking for pid %d\n", pid); + stack_pid = pid; + stack_addr = (uintptr_t)&magic; + } + + pr_info("Stack offset: %d\n", (int)(stack_addr - (uintptr_t)&magic)); +} + void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) { static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5}; diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index b2aff4d87c0143f71c1cbcff0bdf355239c8d31f..8024b6a5cc7fc458c3ab04e33a2d88a6fd56450e 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -110,6 +110,7 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(EXHAUST_STACK), CRASHTYPE(CORRUPT_STACK), CRASHTYPE(CORRUPT_STACK_STRONG), + CRASHTYPE(REPORT_STACK), CRASHTYPE(CORRUPT_LIST_ADD), CRASHTYPE(CORRUPT_LIST_DEL), CRASHTYPE(STACK_GUARD_PAGE_LEADING), diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 5ae48c64df24dffe794a0c7cb9f40b14582c9d85..99f90d3e5e9cb44be2f41f5aba307cc15a4b24d6 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -17,6 +17,7 @@ void lkdtm_LOOP(void); void lkdtm_EXHAUST_STACK(void); void lkdtm_CORRUPT_STACK(void); void lkdtm_CORRUPT_STACK_STRONG(void); +void lkdtm_REPORT_STACK(void); void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void); void lkdtm_SOFTLOCKUP(void); void lkdtm_HARDLOCKUP(void); diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c index 109e8d4302c11332decb0334c55854fa8b390a01..15d220ef35a5695194cf5a212bd166ef2c6f7544 100644 --- a/drivers/misc/lkdtm/usercopy.c +++ b/drivers/misc/lkdtm/usercopy.c @@ -314,7 +314,7 @@ void lkdtm_USERCOPY_KERNEL(void) pr_info("attempting bad copy_to_user from kernel text: %px\n", vm_mmap); - if (copy_to_user((void __user *)user_addr, vm_mmap, + if (copy_to_user((void __user *)user_addr, function_nocfi(vm_mmap), unconst + PAGE_SIZE)) { pr_warn("copy_to_user failed, but lacked Oops\n"); goto free_user; diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 14be76d4c2e618c817f3f5f89fefc1961627bfa8..cb34925e10f15d6cd65b79b48c4870257b9e6189 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -105,6 +105,7 @@ #define MEI_DEV_ID_ADP_S 0x7AE8 /* Alder Lake Point S */ #define MEI_DEV_ID_ADP_LP 0x7A60 /* Alder Lake Point LP */ +#define MEI_DEV_ID_ADP_P 0x51E0 /* Alder Lake Point P */ /* * MEI HW Section diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index a7e179626b6359f156d2db76146c5208113a3a11..c3393b383e5989bf6ed3be487ba219a8b7fcaeb2 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -111,6 +111,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)}, /* required last entry */ {0, } diff --git a/drivers/misc/pvpanic/Kconfig b/drivers/misc/pvpanic/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..12d40a21f69855765e36b7247355e5ec5de506c1 --- /dev/null +++ b/drivers/misc/pvpanic/Kconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Pvpanic Kconfig +# +# Copyright (C) 2021 Oracle. +# + +config PVPANIC + bool "pvpanic device support" + help + This option allows to select a specific pvpanic device driver. + pvpanic is a paravirtualized device provided by QEMU; it lets + a virtual machine (guest) communicate panic events to the host. + +config PVPANIC_MMIO + tristate "pvpanic MMIO device support" + depends on HAS_IOMEM && (ACPI || OF) && PVPANIC + help + This driver provides support for the MMIO pvpanic device. + +config PVPANIC_PCI + tristate "pvpanic PCI device support" + depends on PCI && PVPANIC + help + This driver provides support for the PCI pvpanic device. + pvpanic is a paravirtualized device provided by QEMU which + forwards the panic events from the guest to the host. diff --git a/drivers/misc/pvpanic/Makefile b/drivers/misc/pvpanic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9471df7d4f9cea07e1a94dce1b2aabea4838d36c --- /dev/null +++ b/drivers/misc/pvpanic/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Pvpanic Makefile +# +# Copyright (C) 2021 Oracle. +# +obj-$(CONFIG_PVPANIC_MMIO) += pvpanic.o pvpanic-mmio.o +obj-$(CONFIG_PVPANIC_PCI) += pvpanic.o pvpanic-pci.o diff --git a/drivers/misc/pvpanic.c b/drivers/misc/pvpanic/pvpanic-mmio.c similarity index 62% rename from drivers/misc/pvpanic.c rename to drivers/misc/pvpanic/pvpanic-mmio.c index f1655f5ca016dfd7f09b52885c3e6ebfa320e00f..4c08417760874b0995af3be387c5829f1f3589fc 100644 --- a/drivers/misc/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Pvpanic Device Support + * Pvpanic MMIO Device Support * * Copyright (C) 2013 Fujitsu. * Copyright (C) 2018 ZTE. + * Copyright (C) 2021 Oracle. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/io.h> #include <linux/kernel.h> #include <linux/kexec.h> @@ -15,28 +14,36 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/types.h> +#include <linux/slab.h> #include <uapi/misc/pvpanic.h> -static void __iomem *base; -static unsigned int capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; -static unsigned int events; +#include "pvpanic.h" + +MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>"); +MODULE_DESCRIPTION("pvpanic-mmio device driver"); +MODULE_LICENSE("GPL"); static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sysfs_emit(buf, "%x\n", capability); + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->capability); } static DEVICE_ATTR_RO(capability); static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sysfs_emit(buf, "%x\n", events); + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->events); } static ssize_t events_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct pvpanic_instance *pi = dev_get_drvdata(dev); unsigned int tmp; int err; @@ -44,57 +51,28 @@ static ssize_t events_store(struct device *dev, struct device_attribute *attr, if (err) return err; - if ((tmp & capability) != tmp) + if ((tmp & pi->capability) != tmp) return -EINVAL; - events = tmp; + pi->events = tmp; return count; - } static DEVICE_ATTR_RW(events); -static struct attribute *pvpanic_dev_attrs[] = { +static struct attribute *pvpanic_mmio_dev_attrs[] = { &dev_attr_capability.attr, &dev_attr_events.attr, NULL }; -ATTRIBUTE_GROUPS(pvpanic_dev); - -MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>"); -MODULE_DESCRIPTION("pvpanic device driver"); -MODULE_LICENSE("GPL"); - -static void -pvpanic_send_event(unsigned int event) -{ - if (event & capability & events) - iowrite8(event, base); -} - -static int -pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, - void *unused) -{ - unsigned int event = PVPANIC_PANICKED; - - if (kexec_crash_loaded()) - event = PVPANIC_CRASH_LOADED; - - pvpanic_send_event(event); - - return NOTIFY_DONE; -} - -static struct notifier_block pvpanic_panic_nb = { - .notifier_call = pvpanic_panic_notify, - .priority = 1, /* let this called before broken drm_fb_helper */ -}; +ATTRIBUTE_GROUPS(pvpanic_mmio_dev); static int pvpanic_mmio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct pvpanic_instance *pi; struct resource *res; + void __iomem *base; res = platform_get_mem_or_io(pdev, 0); if (!res) @@ -115,23 +93,28 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) return -EINVAL; } + pi = kmalloc(sizeof(*pi), GFP_ATOMIC); + if (!pi) + return -ENOMEM; + + pi->base = base; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + /* initlize capability by RDPT */ - capability &= ioread8(base); - events = capability; + pi->capability &= ioread8(base); + pi->events = pi->capability; - if (capability) - atomic_notifier_chain_register(&panic_notifier_list, - &pvpanic_panic_nb); + dev_set_drvdata(dev, pi); - return 0; + return pvpanic_probe(pi); } static int pvpanic_mmio_remove(struct platform_device *pdev) { + struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); - if (capability) - atomic_notifier_chain_unregister(&panic_notifier_list, - &pvpanic_panic_nb); + pvpanic_remove(pi); + kfree(pi); return 0; } @@ -153,7 +136,7 @@ static struct platform_driver pvpanic_mmio_driver = { .name = "pvpanic-mmio", .of_match_table = pvpanic_mmio_match, .acpi_match_table = pvpanic_device_ids, - .dev_groups = pvpanic_dev_groups, + .dev_groups = pvpanic_mmio_dev_groups, }, .probe = pvpanic_mmio_probe, .remove = pvpanic_mmio_remove, diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c new file mode 100644 index 0000000000000000000000000000000000000000..9ecc4e8559d5d266e7bd35643c021c4bb97457f6 --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic PCI Device Support + * + * Copyright (C) 2021 Oracle. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/slab.h> + +#include <uapi/misc/pvpanic.h> + +#include "pvpanic.h" + +#define PCI_VENDOR_ID_REDHAT 0x1b36 +#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 + +MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>"); +MODULE_DESCRIPTION("pvpanic device driver "); +MODULE_LICENSE("GPL"); + +static const struct pci_device_id pvpanic_pci_id_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_PVPANIC)}, + {} +}; + +static ssize_t capability_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->capability); +} +static DEVICE_ATTR_RO(capability); + +static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->events); +} + +static ssize_t events_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + unsigned int tmp; + int err; + + err = kstrtouint(buf, 16, &tmp); + if (err) + return err; + + if ((tmp & pi->capability) != tmp) + return -EINVAL; + + pi->events = tmp; + + return count; +} +static DEVICE_ATTR_RW(events); + +static struct attribute *pvpanic_pci_dev_attrs[] = { + &dev_attr_capability.attr, + &dev_attr_events.attr, + NULL +}; +ATTRIBUTE_GROUPS(pvpanic_pci_dev); + +static int pvpanic_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct pvpanic_instance *pi; + void __iomem *base; + int ret; + + ret = pci_enable_device(pdev); + if (ret < 0) + return ret; + + base = pci_iomap(pdev, 0, 0); + if (!base) + return -ENOMEM; + + pi = kmalloc(sizeof(*pi), GFP_ATOMIC); + if (!pi) + return -ENOMEM; + + pi->base = base; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + + /* initlize capability by RDPT */ + pi->capability &= ioread8(base); + pi->events = pi->capability; + + dev_set_drvdata(dev, pi); + + return pvpanic_probe(pi); +} + +static void pvpanic_pci_remove(struct pci_dev *pdev) +{ + struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); + + pvpanic_remove(pi); + iounmap(pi->base); + kfree(pi); + pci_disable_device(pdev); +} + +static struct pci_driver pvpanic_pci_driver = { + .name = "pvpanic-pci", + .id_table = pvpanic_pci_id_tbl, + .probe = pvpanic_pci_probe, + .remove = pvpanic_pci_remove, + .driver = { + .dev_groups = pvpanic_pci_dev_groups, + }, +}; + +module_pci_driver(pvpanic_pci_driver); diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c new file mode 100644 index 0000000000000000000000000000000000000000..65f70a4da8c077afb5ced0cc1b17f860588e93de --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic Device Support + * + * Copyright (C) 2013 Fujitsu. + * Copyright (C) 2018 ZTE. + * Copyright (C) 2021 Oracle. + */ + +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/kexec.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/cdev.h> +#include <linux/list.h> + +#include <uapi/misc/pvpanic.h> + +#include "pvpanic.h" + +MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>"); +MODULE_DESCRIPTION("pvpanic device driver "); +MODULE_LICENSE("GPL"); + +static struct list_head pvpanic_list; +static spinlock_t pvpanic_lock; + +static void +pvpanic_send_event(unsigned int event) +{ + struct pvpanic_instance *pi_cur; + + spin_lock(&pvpanic_lock); + list_for_each_entry(pi_cur, &pvpanic_list, list) { + if (event & pi_cur->capability & pi_cur->events) + iowrite8(event, pi_cur->base); + } + spin_unlock(&pvpanic_lock); +} + +static int +pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, + void *unused) +{ + unsigned int event = PVPANIC_PANICKED; + + if (kexec_crash_loaded()) + event = PVPANIC_CRASH_LOADED; + + pvpanic_send_event(event); + + return NOTIFY_DONE; +} + +static struct notifier_block pvpanic_panic_nb = { + .notifier_call = pvpanic_panic_notify, + .priority = 1, /* let this called before broken drm_fb_helper */ +}; + +int pvpanic_probe(struct pvpanic_instance *pi) +{ + if (!pi || !pi->base) + return -EINVAL; + + spin_lock(&pvpanic_lock); + list_add(&pi->list, &pvpanic_list); + spin_unlock(&pvpanic_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(pvpanic_probe); + +void pvpanic_remove(struct pvpanic_instance *pi) +{ + struct pvpanic_instance *pi_cur, *pi_next; + + if (!pi) + return; + + spin_lock(&pvpanic_lock); + list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) { + if (pi_cur == pi) { + list_del(&pi_cur->list); + break; + } + } + spin_unlock(&pvpanic_lock); +} +EXPORT_SYMBOL_GPL(pvpanic_remove); + +static int pvpanic_init(void) +{ + INIT_LIST_HEAD(&pvpanic_list); + spin_lock_init(&pvpanic_lock); + + atomic_notifier_chain_register(&panic_notifier_list, + &pvpanic_panic_nb); + + return 0; +} + +static void pvpanic_exit(void) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, + &pvpanic_panic_nb); + +} + +module_init(pvpanic_init); +module_exit(pvpanic_exit); diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h new file mode 100644 index 0000000000000000000000000000000000000000..1afccc2e9fec781cc940dc081abea05b5d7bc5bf --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic Device Support + * + * Copyright (C) 2021 Oracle. + */ + +#ifndef PVPANIC_H_ +#define PVPANIC_H_ + +struct pvpanic_instance { + void __iomem *base; + unsigned int capability; + unsigned int events; + struct list_head list; +}; + +int pvpanic_probe(struct pvpanic_instance *pi); +void pvpanic_remove(struct pvpanic_instance *pi); + +#endif /* PVPANIC_H_ */ diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index cf2965aa5c0556748a3d8b245377bf7209f29f82..87d156c15f35bcd790e111bc3eb01f9758716f79 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -21,11 +21,11 @@ /* define the XP debug device structures to be used with dev_dbg() et al */ -struct device_driver xp_dbg_name = { +static struct device_driver xp_dbg_name = { .name = "xp" }; -struct device xp_dbg_subname = { +static struct device xp_dbg_subname = { .init_name = "", /* set to "" */ .driver = &xp_dbg_name }; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 84610bbcc131434c0f0088ce095b82c8377187ca..b2c3c22fc13c1361cd923d7154baa7abf57e6b42 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -207,7 +207,7 @@ xpc_start_hb_beater(void) { xpc_arch_ops.heartbeat_init(); timer_setup(&xpc_hb_timer, xpc_hb_beater, 0); - xpc_hb_beater(0); + xpc_hb_beater(NULL); } static void diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index 6c1a23cb3e8c0fa8ef1f5bf8b871a10c763fa894..202bf951e9095ff6a51038c7ddefb7e6a269587a 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -144,8 +144,8 @@ static void sram_free_partitions(struct sram_dev *sram) } } -static int sram_reserve_cmp(void *priv, struct list_head *a, - struct list_head *b) +static int sram_reserve_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct sram_reserve *ra = list_entry(a, struct sram_reserve, list); struct sram_reserve *rb = list_entry(b, struct sram_reserve, list); diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 5a0a5fc3d3abca6536af520e47b9e4505f2ad48d..071844b58073929e3a7247dbfebfbfff0a7f480b 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -845,7 +845,6 @@ static void st_tty_flush_buffer(struct tty_struct *tty) } static struct tty_ldisc_ops st_ldisc_ops = { - .magic = TTY_LDISC_MAGIC, .name = "n_st", .open = st_tty_open, .close = st_tty_close, diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index d07af4edfcacf4251d51594ed12fefee27f3de50..94843e0e51c66b018d29e07543877cda207ca002 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -126,7 +126,7 @@ static int uacce_fops_open(struct inode *inode, struct file *filep) { struct uacce_device *uacce; struct uacce_queue *q; - int ret = 0; + int ret; uacce = xa_load(&uacce_xa, iminor(inode)); if (!uacce) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index b837e7eba5f7dcec2ae1f15bb2052c18b9a0f306..f1d8ba6d485741336d48382dc00dd2d59f4fe630 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -346,11 +346,6 @@ struct vmballoon { /* statistics */ struct vmballoon_stats *stats; -#ifdef CONFIG_DEBUG_FS - /* debugfs file exporting statistics */ - struct dentry *dbg_entry; -#endif - /** * @b_dev_info: balloon device information descriptor. */ @@ -1709,14 +1704,14 @@ DEFINE_SHOW_ATTRIBUTE(vmballoon_debug); static void __init vmballoon_debugfs_init(struct vmballoon *b) { - b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, - &vmballoon_debug_fops); + debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, + &vmballoon_debug_fops); } static void __exit vmballoon_debugfs_exit(struct vmballoon *b) { static_key_disable(&balloon_stat_enabled.key); - debugfs_remove(b->dbg_entry); + debugfs_remove(debugfs_lookup("vmmemctl", NULL)); kfree(b->stats); b->stats = NULL; } diff --git a/drivers/misc/vmw_vmci/vmci_doorbell.c b/drivers/misc/vmw_vmci/vmci_doorbell.c index 345addd9306defffd6e43d667672df6f22966bc1..fa8a7fce4481bd84e9ef56c3f4ea9cfb0074497e 100644 --- a/drivers/misc/vmw_vmci/vmci_doorbell.c +++ b/drivers/misc/vmw_vmci/vmci_doorbell.c @@ -326,7 +326,7 @@ int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle) bool vmci_dbell_register_notification_bitmap(u64 bitmap_ppn) { int result; - struct vmci_notify_bm_set_msg bitmap_set_msg; + struct vmci_notify_bm_set_msg bitmap_set_msg = { }; bitmap_set_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_SET_NOTIFY_BITMAP); diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index cc8eeb361fcdb580d5e2aa28e3283bfae2ddca18..1018dc77269d47b3079b0c9be6426295b5489fc5 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -168,7 +168,7 @@ static int vmci_check_host_caps(struct pci_dev *pdev) VMCI_UTIL_NUM_RESOURCES * sizeof(u32); struct vmci_datagram *check_msg; - check_msg = kmalloc(msg_size, GFP_KERNEL); + check_msg = kzalloc(msg_size, GFP_KERNEL); if (!check_msg) { dev_err(&pdev->dev, "%s: Insufficient memory\n", __func__); return -ENOMEM; diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index 2d8328d928d53fe78832be7ea6cb793a123b1931..da1e2a773823e06ac6e34e39a6878be5cf5b0adc 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -908,7 +908,7 @@ static long vmci_host_unlocked_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { #define VMCI_DO_IOCTL(ioctl_name, ioctl_fn) do { \ - char *name = __stringify(IOCTL_VMCI_ ## ioctl_name); \ + char *name = "IOCTL_VMCI_" # ioctl_name; \ return vmci_host_do_ ## ioctl_fn( \ vmci_host_dev, name, uptr); \ } while (0) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 5e1da4df096f66d088a2ba959cf946d0b5ced236..d170c919e6e44ee9012f558c289f3f484ad490ad 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -264,7 +264,6 @@ struct sdhci_msm_host { struct clk_bulk_data bulk_clks[5]; unsigned long clk_rate; struct mmc_host *mmc; - struct opp_table *opp_table; bool use_14lpp_dll_reset; bool tuning_done; bool calibration_done; @@ -2551,17 +2550,15 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (ret) goto bus_clk_disable; - msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core"); - if (IS_ERR(msm_host->opp_table)) { - ret = PTR_ERR(msm_host->opp_table); + ret = devm_pm_opp_set_clkname(&pdev->dev, "core"); + if (ret) goto bus_clk_disable; - } /* OPP table is optional */ - ret = dev_pm_opp_of_add_table(&pdev->dev); + ret = devm_pm_opp_of_add_table(&pdev->dev); if (ret && ret != -ENODEV) { dev_err(&pdev->dev, "Invalid OPP table in Device tree\n"); - goto opp_put_clkname; + goto bus_clk_disable; } /* Vote for maximum clock rate for maximum performance */ @@ -2587,7 +2584,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); if (ret) - goto opp_cleanup; + goto bus_clk_disable; /* * xo clock is needed for FLL feature of cm_dll. @@ -2732,10 +2729,6 @@ pm_runtime_disable: clk_disable: clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); -opp_cleanup: - dev_pm_opp_of_remove_table(&pdev->dev); -opp_put_clkname: - dev_pm_opp_put_clkname(msm_host->opp_table); bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); @@ -2754,8 +2747,6 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(msm_host->opp_table); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig index ebfe84e69715d5433c597912bc421ef2a03c8327..4b8145b9e7ad510966a597d145138b7efdbbbf1f 100644 --- a/drivers/most/Kconfig +++ b/drivers/most/Kconfig @@ -32,4 +32,14 @@ config MOST_CDEV To compile this driver as a module, choose M here: the module will be called most_cdev. + +config MOST_SND + tristate "Sound" + depends on SND + select SND_PCM + help + Say Y here if you want to commumicate via ALSA/sound devices. + + To compile this driver as a module, choose M here: the + module will be called most_sound. endif diff --git a/drivers/most/Makefile b/drivers/most/Makefile index 8b53ca46633f14b2408ae198e2cb31a24010037c..60db6cd3787af3127af7b2db7f68e82c41ee7f8a 100644 --- a/drivers/most/Makefile +++ b/drivers/most/Makefile @@ -5,3 +5,4 @@ most_core-y := core.o \ obj-$(CONFIG_MOST_USB_HDM) += most_usb.o obj-$(CONFIG_MOST_CDEV) += most_cdev.o +obj-$(CONFIG_MOST_SND) += most_snd.o diff --git a/drivers/most/most_cdev.c b/drivers/most/most_cdev.c index 044880760b584382fa247cde56d9cabd11cc6a8c..8908b9363a96900aa1d37acb966b1b6b7d13ae5c 100644 --- a/drivers/most/most_cdev.c +++ b/drivers/most/most_cdev.c @@ -44,8 +44,8 @@ struct comp_channel { }; #define to_channel(d) container_of(d, struct comp_channel, cdev) -static struct list_head channel_list; -static spinlock_t ch_list_lock; +static LIST_HEAD(channel_list); +static DEFINE_SPINLOCK(ch_list_lock); static inline bool ch_has_mbo(struct comp_channel *c) { @@ -494,8 +494,6 @@ static int __init mod_init(void) if (IS_ERR(comp.class)) return PTR_ERR(comp.class); - INIT_LIST_HEAD(&channel_list); - spin_lock_init(&ch_list_lock); ida_init(&comp.minor_id); err = alloc_chrdev_region(&comp.devno, 0, CHRDEV_REGION_SIZE, "cdev"); diff --git a/drivers/staging/most/sound/sound.c b/drivers/most/most_snd.c similarity index 100% rename from drivers/staging/most/sound/sound.c rename to drivers/most/most_snd.c diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 42001c49833b9401a3b460df6ab7ed482ef239b0..54f92d09d9cf430c3bd3a63f3dd4634cbbab0400 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -72,7 +72,8 @@ static int cfi_intelext_is_locked(struct mtd_info *mtd, loff_t ofs, #ifdef CONFIG_MTD_OTP static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_write_user_prot_reg(struct mtd_info *, loff_t, size_t, + size_t *, const u_char *); static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t); static int cfi_intelext_get_fact_prot_info(struct mtd_info *, size_t, size_t *, struct otp_info *); @@ -2447,10 +2448,10 @@ static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from, static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, - u_char *buf) + const u_char *buf) { return cfi_intelext_otp_walk(mtd, from, len, retlen, - buf, do_otp_write, 1); + (u_char *)buf, do_otp_write, 1); } static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, @@ -2549,6 +2550,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) anyway? The latter for now. */ printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->state); ret = -EAGAIN; + break; case FL_PM_SUSPENDED: break; } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index a1f3e1031c3d2c687cc420e713c9ded184ea66f5..3097e93787f72625dfc4a22888aec35c68141f1e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -80,7 +80,7 @@ static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t, static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t, - size_t *, u_char *); + size_t *, const u_char *); static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *, loff_t, size_t); static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, @@ -272,6 +272,10 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; + + if (cfi->mfr == CFI_MFR_AMD && cfi->id == 0x2201) + return; + if (cfi->cfiq->BufWriteTimeoutTyp) { pr_debug("Using buffer write method\n"); mtd->_write = cfi_amdstd_write_buffers; @@ -902,6 +906,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr /* Someone else might have been playing with it. */ goto retry; } + return 0; case FL_READY: case FL_CFI_QUERY: @@ -1630,9 +1635,9 @@ static int cfi_amdstd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, - u_char *buf) + const u_char *buf) { - return cfi_amdstd_otp_walk(mtd, from, len, retlen, buf, + return cfi_amdstd_otp_walk(mtd, from, len, retlen, (u_char *)buf, do_otp_write, 1); } @@ -1649,7 +1654,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, unsigned long adr, map_word datum, int mode, struct cfi_private *cfi) { - unsigned long timeo = jiffies + HZ; + unsigned long timeo; /* * We use a 1ms + 1 jiffies generic timeout for writes (most devices * have a max write time of a few hundreds usec). However, we should @@ -2994,6 +2999,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) * as the whole point is that nobody can do anything * with the chip now anyway. */ + break; case FL_PM_SUSPENDED: break; diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 270322bca221752eb325cf7ae158acf284eb2531..d35df526e0a69afde9f40c4b33b1144c780989cc 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -1332,6 +1332,8 @@ static int cfi_staa_suspend(struct mtd_info *mtd) * as the whole point is that nobody can do anything * with the chip now anyway. */ + break; + case FL_PM_SUSPENDED: break; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 6d1eefe941069f1eebe89210aa4c3df6cf9d6a8e..9802e265fca80a56cd7be99488713dc22dc55246 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -527,7 +527,7 @@ static int dataflash_read_user_otp(struct mtd_info *mtd, } static int dataflash_write_user_otp(struct mtd_info *mtd, - loff_t from, size_t len, size_t *retlen, u_char *buf) + loff_t from, size_t len, size_t *retlen, const u_char *buf) { struct spi_message m; const size_t l = 4 + 64; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 2578f27914ef50cff03b05a49a4ddcae7cbefa58..9b33c082179da5065b7bb0968a18b0f073967c7c 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1056,19 +1056,7 @@ static struct mtd_blktrans_ops ftl_tr = { .owner = THIS_MODULE, }; -static int __init init_ftl(void) -{ - return register_mtd_blktrans(&ftl_tr); -} - -static void __exit cleanup_ftl(void) -{ - deregister_mtd_blktrans(&ftl_tr); -} - -module_init(init_ftl); -module_exit(cleanup_ftl); - +module_mtd_blktrans(ftl_tr); MODULE_LICENSE("Dual MPL/GPL"); MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index a0d6c00e7b8508eb8b3286937f3356ff02eae8cf..6b48397c750c2246b7e4b1efd19f60a09245b8a3 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -937,18 +937,7 @@ static struct mtd_blktrans_ops inftl_tr = { .owner = THIS_MODULE, }; -static int __init init_inftl(void) -{ - return register_mtd_blktrans(&inftl_tr); -} - -static void __exit cleanup_inftl(void) -{ - deregister_mtd_blktrans(&inftl_tr); -} - -module_init(init_inftl); -module_exit(cleanup_inftl); +module_mtd_blktrans(inftl_tr); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); diff --git a/drivers/mtd/maps/physmap-bt1-rom.c b/drivers/mtd/maps/physmap-bt1-rom.c index a35450002284cafa15f57d8c554ce21069a0bbe1..58782cfaf71cf048a059ed1d6249d2955c41c71b 100644 --- a/drivers/mtd/maps/physmap-bt1-rom.c +++ b/drivers/mtd/maps/physmap-bt1-rom.c @@ -79,7 +79,7 @@ static void __xipram bt1_rom_map_copy_from(struct map_info *map, if (shift) { chunk = min_t(ssize_t, 4 - shift, len); data = readl_relaxed(src - shift); - memcpy(to, &data + shift, chunk); + memcpy(to, (char *)&data + shift, chunk); src += chunk; to += chunk; len -= chunk; diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c index 001ed5deb622aacfa82b58c0ac7dcf03a3b1085c..4f63b8430c710c017a2e151a64e97e9275d358da 100644 --- a/drivers/mtd/maps/physmap-core.c +++ b/drivers/mtd/maps/physmap-core.c @@ -69,8 +69,10 @@ static int physmap_flash_remove(struct platform_device *dev) int i, err = 0; info = platform_get_drvdata(dev); - if (!info) + if (!info) { + err = -EINVAL; goto out; + } if (info->cmtd) { err = mtd_device_unregister(info->cmtd); diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 32e52d83b961e6ad296f5d6beccb3eede29202ff..a8080954379342385c52bd4edc3ae9887dfd85d9 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -346,19 +346,7 @@ static struct mtd_blktrans_ops mtdblock_tr = { .owner = THIS_MODULE, }; -static int __init init_mtdblock(void) -{ - return register_mtd_blktrans(&mtdblock_tr); -} - -static void __exit cleanup_mtdblock(void) -{ - deregister_mtd_blktrans(&mtdblock_tr); -} - -module_init(init_mtdblock); -module_exit(cleanup_mtdblock); - +module_mtd_blktrans(mtdblock_tr); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net> et al."); diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 7fcf29ef2bdc4664ebf5520c254aee7219621ad1..d92914f73d52c3127163f8f4818224ce51d2b0b7 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -67,18 +67,7 @@ static struct mtd_blktrans_ops mtdblock_tr = { .owner = THIS_MODULE, }; -static int __init mtdblock_init(void) -{ - return register_mtd_blktrans(&mtdblock_tr); -} - -static void __exit mtdblock_exit(void) -{ - deregister_mtd_blktrans(&mtdblock_tr); -} - -module_init(mtdblock_init); -module_exit(mtdblock_exit); +module_mtd_blktrans(mtdblock_tr); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 323035d4f2d019c80e20fd65b5eeedd2ddb62675..155e991d9d7533b1232d2a4c088b7ff3bc4f9cc7 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -27,8 +27,6 @@ #include "mtdcore.h" -static DEFINE_MUTEX(mtd_mutex); - /* * Data structure to hold the pointer to the mtd device as well * as mode information of various use cases. @@ -58,13 +56,10 @@ static int mtdchar_open(struct inode *inode, struct file *file) if ((file->f_mode & FMODE_WRITE) && (minor & 1)) return -EACCES; - mutex_lock(&mtd_mutex); mtd = get_mtd_device(NULL, devnum); - if (IS_ERR(mtd)) { - ret = PTR_ERR(mtd); - goto out; - } + if (IS_ERR(mtd)) + return PTR_ERR(mtd); if (mtd->type == MTD_ABSENT) { ret = -ENODEV; @@ -84,13 +79,10 @@ static int mtdchar_open(struct inode *inode, struct file *file) } mfi->mtd = mtd; file->private_data = mfi; - mutex_unlock(&mtd_mutex); return 0; out1: put_mtd_device(mtd); -out: - mutex_unlock(&mtd_mutex); return ret; } /* mtdchar_open */ @@ -651,16 +643,12 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) case MEMGETINFO: case MEMREADOOB: case MEMREADOOB64: - case MEMLOCK: - case MEMUNLOCK: case MEMISLOCKED: case MEMGETOOBSEL: case MEMGETBADBLOCK: - case MEMSETBADBLOCK: case OTPSELECT: case OTPGETREGIONCOUNT: case OTPGETREGIONINFO: - case OTPLOCK: case ECCGETLAYOUT: case ECCGETSTATS: case MTDFILEMODE: @@ -671,9 +659,14 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) /* "dangerous" commands */ case MEMERASE: case MEMERASE64: + case MEMLOCK: + case MEMUNLOCK: + case MEMSETBADBLOCK: case MEMWRITEOOB: case MEMWRITEOOB64: case MEMWRITE: + case OTPLOCK: + case OTPERASE: if (!(file->f_mode & FMODE_WRITE)) return -EPERM; break; @@ -938,6 +931,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) } case OTPLOCK: + case OTPERASE: { struct otp_info oinfo; @@ -945,7 +939,10 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) return -EINVAL; if (copy_from_user(&oinfo, argp, sizeof(oinfo))) return -EFAULT; - ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length); + if (cmd == OTPLOCK) + ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length); + else + ret = mtd_erase_user_prot_reg(mtd, oinfo.start, oinfo.length); break; } @@ -991,6 +988,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) if (!mtd_has_oob(mtd)) return -EOPNOTSUPP; mfi->mode = arg; + break; case MTD_FILE_MODE_NORMAL: break; @@ -1026,11 +1024,14 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) static long mtdchar_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { + struct mtd_file_info *mfi = file->private_data; + struct mtd_info *mtd = mfi->mtd; + struct mtd_info *master = mtd_get_master(mtd); int ret; - mutex_lock(&mtd_mutex); + mutex_lock(&master->master.chrdev_lock); ret = mtdchar_ioctl(file, cmd, arg); - mutex_unlock(&mtd_mutex); + mutex_unlock(&master->master.chrdev_lock); return ret; } @@ -1051,10 +1052,11 @@ static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd, { struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; + struct mtd_info *master = mtd_get_master(mtd); void __user *argp = compat_ptr(arg); int ret = 0; - mutex_lock(&mtd_mutex); + mutex_lock(&master->master.chrdev_lock); switch (cmd) { case MEMWRITEOOB32: @@ -1117,7 +1119,7 @@ static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd, ret = mtdchar_ioctl(file, cmd, (unsigned long)argp); } - mutex_unlock(&mtd_mutex); + mutex_unlock(&master->master.chrdev_lock); return ret; } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 2d6423d89a1759f182f083156fc87b38c8388ff6..9aaeadd53eb4f77c19112b22b34d73c8e385aa58 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv, unsigned int offset, static int mtd_nvmem_add(struct mtd_info *mtd) { + struct device_node *node = mtd_get_of_node(mtd); struct nvmem_config config = {}; config.id = -1; @@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd) config.stride = 1; config.read_only = true; config.root_only = true; - config.no_of_node = true; + config.no_of_node = !of_device_is_compatible(node, "nvmem-cells"); config.priv = mtd; mtd->nvmem = nvmem_register(&config); @@ -773,6 +774,7 @@ static void mtd_set_dev_defaults(struct mtd_info *mtd) INIT_LIST_HEAD(&mtd->partitions); mutex_init(&mtd->master.partitions_lock); + mutex_init(&mtd->master.chrdev_lock); } /** @@ -820,6 +822,9 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, /* Prefer parsed partitions over driver-provided fallback */ ret = parse_mtd_partitions(mtd, types, parser_data); + if (ret == -EPROBE_DEFER) + goto out; + if (ret > 0) ret = 0; else if (nr_parts) @@ -1884,7 +1889,7 @@ int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg); int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, u_char *buf) + size_t *retlen, const u_char *buf) { struct mtd_info *master = mtd_get_master(mtd); int ret; @@ -1918,6 +1923,18 @@ int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) } EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg); +int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) +{ + struct mtd_info *master = mtd_get_master(mtd); + + if (!master->_erase_user_prot_reg) + return -EOPNOTSUPP; + if (!len) + return 0; + return master->_erase_user_prot_reg(master, from, len); +} +EXPORT_SYMBOL_GPL(mtd_erase_user_prot_reg); + /* Chip-supported device locking */ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -2172,7 +2189,7 @@ static int mtd_proc_show(struct seq_file *m, void *v) /*====================================================================*/ /* Init code */ -static struct backing_dev_info * __init mtd_bdi_init(char *name) +static struct backing_dev_info * __init mtd_bdi_init(const char *name) { struct backing_dev_info *bdi; int ret; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 12ca4f19cb14ab9081b7547aac4bfcc8210823fd..665fd9020b764da7d8c7a69359e57a1bccc78a9e 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -331,7 +331,7 @@ static int __del_mtd_partitions(struct mtd_info *mtd) list_for_each_entry_safe(child, next, &mtd->partitions, part.node) { if (mtd_has_partitions(child)) - del_mtd_partitions(child); + __del_mtd_partitions(child); pr_info("Deleting %s MTD partition\n", child->name); ret = del_mtd_device(child); diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 795dec4483c217e34078bbd3488b5066c722e2c7..7e309270ddd402e2843b8dd8336a5ccd589a1a8a 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1484,19 +1484,7 @@ static struct mtd_blktrans_ops mtdswap_ops = { .owner = THIS_MODULE, }; -static int __init mtdswap_modinit(void) -{ - return register_mtd_blktrans(&mtdswap_ops); -} - -static void __exit mtdswap_modexit(void) -{ - deregister_mtd_blktrans(&mtdswap_ops); -} - -module_init(mtdswap_modinit); -module_exit(mtdswap_modexit); - +module_mtd_blktrans(mtdswap_ops); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>"); diff --git a/drivers/mtd/nand/ecc-sw-bch.c b/drivers/mtd/nand/ecc-sw-bch.c index 0a0ac11d5725a545c5d36396b41c2007646bfcaa..405552d014a884700e217ef6ddf6a5c046a4d23e 100644 --- a/drivers/mtd/nand/ecc-sw-bch.c +++ b/drivers/mtd/nand/ecc-sw-bch.c @@ -236,7 +236,6 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand) goto free_engine_conf; engine_conf->code_size = code_size; - engine_conf->nsteps = nsteps; engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL); engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL); if (!engine_conf->calc_buf || !engine_conf->code_buf) { @@ -245,6 +244,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand) } nand->ecc.ctx.priv = engine_conf; + nand->ecc.ctx.nsteps = nsteps; nand->ecc.ctx.total = nsteps * code_size; ret = nand_ecc_sw_bch_init(nand); @@ -253,7 +253,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand) /* Verify the layout validity */ if (mtd_ooblayout_count_eccbytes(mtd) != - engine_conf->nsteps * engine_conf->code_size) { + nand->ecc.ctx.nsteps * engine_conf->code_size) { pr_err("Invalid ECC layout\n"); ret = -EINVAL; goto cleanup_bch_ctx; @@ -295,7 +295,7 @@ static int nand_ecc_sw_bch_prepare_io_req(struct nand_device *nand, struct mtd_info *mtd = nanddev_to_mtd(nand); int eccsize = nand->ecc.ctx.conf.step_size; int eccbytes = engine_conf->code_size; - int eccsteps = engine_conf->nsteps; + int eccsteps = nand->ecc.ctx.nsteps; int total = nand->ecc.ctx.total; u8 *ecccalc = engine_conf->calc_buf; const u8 *data; @@ -333,7 +333,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand, int eccsize = nand->ecc.ctx.conf.step_size; int total = nand->ecc.ctx.total; int eccbytes = engine_conf->code_size; - int eccsteps = engine_conf->nsteps; + int eccsteps = nand->ecc.ctx.nsteps; u8 *ecccalc = engine_conf->calc_buf; u8 *ecccode = engine_conf->code_buf; unsigned int max_bitflips = 0; @@ -365,7 +365,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand, nand_ecc_sw_bch_calculate(nand, data, &ecccalc[i]); /* Finish a page read: compare and correct */ - for (eccsteps = engine_conf->nsteps, i = 0, data = req->databuf.in; + for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in; eccsteps; eccsteps--, i += eccbytes, data += eccsize) { int stat = nand_ecc_sw_bch_correct(nand, data, diff --git a/drivers/mtd/nand/ecc-sw-hamming.c b/drivers/mtd/nand/ecc-sw-hamming.c index 6334d1d7735d564223edccff287de32d94214360..a7655b668f32e3d05e3f78d4299b8160454bf349 100644 --- a/drivers/mtd/nand/ecc-sw-hamming.c +++ b/drivers/mtd/nand/ecc-sw-hamming.c @@ -504,7 +504,6 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand) goto free_engine_conf; engine_conf->code_size = 3; - engine_conf->nsteps = mtd->writesize / conf->step_size; engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL); engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL); if (!engine_conf->calc_buf || !engine_conf->code_buf) { @@ -513,7 +512,8 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand) } nand->ecc.ctx.priv = engine_conf; - nand->ecc.ctx.total = engine_conf->nsteps * engine_conf->code_size; + nand->ecc.ctx.nsteps = mtd->writesize / conf->step_size; + nand->ecc.ctx.total = nand->ecc.ctx.nsteps * engine_conf->code_size; return 0; @@ -548,7 +548,7 @@ static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand, struct mtd_info *mtd = nanddev_to_mtd(nand); int eccsize = nand->ecc.ctx.conf.step_size; int eccbytes = engine_conf->code_size; - int eccsteps = engine_conf->nsteps; + int eccsteps = nand->ecc.ctx.nsteps; int total = nand->ecc.ctx.total; u8 *ecccalc = engine_conf->calc_buf; const u8 *data; @@ -586,7 +586,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, int eccsize = nand->ecc.ctx.conf.step_size; int total = nand->ecc.ctx.total; int eccbytes = engine_conf->code_size; - int eccsteps = engine_conf->nsteps; + int eccsteps = nand->ecc.ctx.nsteps; u8 *ecccalc = engine_conf->calc_buf; u8 *ecccode = engine_conf->code_buf; unsigned int max_bitflips = 0; @@ -618,7 +618,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]); /* Finish a page read: compare and correct */ - for (eccsteps = engine_conf->nsteps, i = 0, data = req->databuf.in; + for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in; eccsteps; eccsteps--, i += eccbytes, data += eccsize) { int stat = nand_ecc_sw_hamming_correct(nand, data, diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c index a9fdea26ea464be8acf0d773a592c5a9b2a17a7b..958bac54b19078554a06c08019ddcd7abe02c41a 100644 --- a/drivers/mtd/nand/onenand/onenand_base.c +++ b/drivers/mtd/nand/onenand/onenand_base.c @@ -3167,9 +3167,10 @@ static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from, * Write user OTP area. */ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from, - size_t len, size_t *retlen, u_char *buf) + size_t len, size_t *retlen, const u_char *buf) { - return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER); + return onenand_otp_walk(mtd, from, len, retlen, (u_char *)buf, + do_otp_write, MTD_OTP_USER); } /** diff --git a/drivers/mtd/nand/onenand/onenand_samsung.c b/drivers/mtd/nand/onenand/onenand_samsung.c index 87b28e397d671e7d07745c43f9d47f5e22737d5e..b64895573515e5cd83227e039327e6d3d35fb74d 100644 --- a/drivers/mtd/nand/onenand/onenand_samsung.c +++ b/drivers/mtd/nand/onenand/onenand_samsung.c @@ -396,6 +396,7 @@ static int s3c_onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, case ONENAND_CMD_READOOB: case ONENAND_CMD_BUFFERRAM: ONENAND_SET_NEXT_BUFFERRAM(this); + break; default: break; } diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index e6ceec8f50dcecb17d95959757f4c340e2350416..8aab1017b460037d1ba7d5036a89bad20dce0e99 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -883,10 +883,12 @@ static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf, NULL, 0, chip->ecc.strength); - if (ret >= 0) + if (ret >= 0) { + mtd->ecc_stats.corrected += ret; max_bitflips = max(ret, max_bitflips); - else + } else { mtd->ecc_stats.failed++; + } databuf += chip->ecc.size; eccbuf += chip->ecc.bytes; diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 659eaa6f0980cb55339e141d3c557adc9c0cd69c..f75929783b9419ee4827bedbe89c4e97288e59c4 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -242,6 +242,9 @@ struct brcmnand_controller { u32 edu_ext_addr; u32 edu_cmd; u32 edu_config; + int sas; /* spare area size, per flash cache */ + int sector_size_1k; + u8 *oob; /* flash_dma reg */ const u16 *flash_dma_offsets; @@ -249,7 +252,7 @@ struct brcmnand_controller { dma_addr_t dma_pa; int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf, - u32 len, u8 dma_cmd); + u8 *oob, u32 len, u8 dma_cmd); /* in-memory cache of the FLASH_CACHE, used only for some commands */ u8 flash_cache[FC_BYTES]; @@ -1479,6 +1482,23 @@ static irqreturn_t brcmnand_edu_irq(int irq, void *data) edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr); edu_readl(ctrl, EDU_EXT_ADDR); + if (ctrl->oob) { + if (ctrl->edu_cmd == EDU_CMD_READ) { + ctrl->oob += read_oob_from_regs(ctrl, + ctrl->edu_count + 1, + ctrl->oob, ctrl->sas, + ctrl->sector_size_1k); + } else { + brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, + ctrl->edu_ext_addr); + brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + ctrl->oob += write_oob_to_regs(ctrl, + ctrl->edu_count, + ctrl->oob, ctrl->sas, + ctrl->sector_size_1k); + } + } + mb(); /* flush previous writes */ edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd); edu_readl(ctrl, EDU_CMD); @@ -1850,9 +1870,10 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf, * Kick EDU engine */ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, - u32 len, u8 cmd) + u8 *oob, u32 len, u8 cmd) { struct brcmnand_controller *ctrl = host->ctrl; + struct brcmnand_cfg *cfg = &host->hwcfg; unsigned long timeo = msecs_to_jiffies(200); int ret = 0; int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); @@ -1860,6 +1881,9 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, unsigned int trans = len >> FC_SHIFT; dma_addr_t pa; + dev_dbg(ctrl->dev, "EDU %s %p:%p\n", ((edu_cmd == EDU_CMD_READ) ? + "read" : "write"), buf, oob); + pa = dma_map_single(ctrl->dev, buf, len, dir); if (dma_mapping_error(ctrl->dev, pa)) { dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n"); @@ -1871,6 +1895,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, ctrl->edu_ext_addr = addr; ctrl->edu_cmd = edu_cmd; ctrl->edu_count = trans; + ctrl->sas = cfg->spare_area_size; + ctrl->oob = oob; edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr); edu_readl(ctrl, EDU_DRAM_ADDR); @@ -1879,6 +1905,16 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, edu_writel(ctrl, EDU_LENGTH, FC_BYTES); edu_readl(ctrl, EDU_LENGTH); + if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_WRITE)) { + brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, + ctrl->edu_ext_addr); + brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + ctrl->oob += write_oob_to_regs(ctrl, + 1, + ctrl->oob, ctrl->sas, + ctrl->sector_size_1k); + } + /* Start edu engine */ mb(); /* flush previous writes */ edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd); @@ -1893,6 +1929,14 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, dma_unmap_single(ctrl->dev, pa, len, dir); + /* read last subpage oob */ + if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_READ)) { + ctrl->oob += read_oob_from_regs(ctrl, + 1, + ctrl->oob, ctrl->sas, + ctrl->sector_size_1k); + } + /* for program page check NAND status */ if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) & INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) && @@ -2002,7 +2046,7 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc) } static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf, - u32 len, u8 dma_cmd) + u8 *oob, u32 len, u8 dma_cmd) { struct brcmnand_controller *ctrl = host->ctrl; dma_addr_t buf_pa; @@ -2147,8 +2191,9 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, try_dmaread: brcmnand_clear_ecc_addr(ctrl); - if (ctrl->dma_trans && !oob && flash_dma_buf_ok(buf)) { - err = ctrl->dma_trans(host, addr, buf, + if (ctrl->dma_trans && (has_edu(ctrl) || !oob) && + flash_dma_buf_ok(buf)) { + err = ctrl->dma_trans(host, addr, buf, oob, trans * FC_BYTES, CMD_PAGE_READ); @@ -2296,8 +2341,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < ctrl->max_oob; i += 4) oob_reg_write(ctrl, i, 0xffffffff); - if (use_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { - if (ctrl->dma_trans(host, addr, (u32 *)buf, mtd->writesize, + if (mtd->oops_panic_write) + /* switch to interrupt polling and PIO mode */ + disable_ctrl_irqs(ctrl); + + if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) { + if (ctrl->dma_trans(host, addr, (u32 *)buf, oob, mtd->writesize, CMD_PROGRAM_PAGE)) ret = -EIO; @@ -2688,6 +2737,12 @@ static int brcmnand_attach_chip(struct nand_chip *chip) ret = brcmstb_choose_ecc_layout(host); + /* If OOB is written with ECC enabled it will cause ECC errors */ + if (is_hamming_ecc(host->ctrl, &host->hwcfg)) { + chip->ecc.write_oob = brcmnand_write_oob_raw; + chip->ecc.read_oob = brcmnand_read_oob_raw; + } + return ret; } diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 0101c0fab50adc0fca17ee7b5563f94743f793d1..bf695255b43a25ae213db314ee836cb783127e96 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -930,6 +930,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) "Using 4-bit SW BCH ECC scheme\n"); break; } + break; case NAND_ECC_ENGINE_TYPE_ON_DIE: break; @@ -1077,11 +1078,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->read_dma_chan = dma_request_channel(mask, filter, NULL); if (!host->read_dma_chan) { dev_err(&pdev->dev, "Unable to get read dma channel\n"); + ret = -ENODEV; goto disable_clk; } host->write_dma_chan = dma_request_channel(mask, filter, NULL); if (!host->write_dma_chan) { dev_err(&pdev->dev, "Unable to get write dma channel\n"); + ret = -ENODEV; goto release_dma_read_chan; } } diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 3fa8c22d3f36af1da132b9f3932f48101af0ccd7..4d08e4ab5c1b6a1a6caa7f7dcff7237661c668e7 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -2449,7 +2449,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) this->bch_geometry.auxiliary_size = 128; ret = gpmi_alloc_dma_buffer(this); if (ret) - goto err_out; + return ret; nand_controller_init(&this->base); this->base.ops = &gpmi_nand_controller_ops; diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index f78302e16b84e7c712e6f93f844b5a17e3bcd6be..f6c96341b896c7e01c1d65aa794372ff6ff9d2be 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1849,7 +1849,7 @@ static int mxcnd_remove(struct platform_device *pdev) static struct platform_driver mxcnd_driver = { .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(mxcnd_dt_ids), + .of_match_table = mxcnd_dt_ids, }, .probe = mxcnd_probe, .remove = mxcnd_remove, diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index c33fa1b1847f9893722c25c4f04090858510d4dd..fb072c444495013acab4eb5bff26c131d6247ac0 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -278,11 +278,48 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) return 0; } +/** + * nand_region_is_secured() - Check if the region is secured + * @chip: NAND chip object + * @offset: Offset of the region to check + * @size: Size of the region to check + * + * Checks if the region is secured by comparing the offset and size with the + * list of secure regions obtained from DT. Returns true if the region is + * secured else false. + */ +static bool nand_region_is_secured(struct nand_chip *chip, loff_t offset, u64 size) +{ + int i; + + /* Skip touching the secure regions if present */ + for (i = 0; i < chip->nr_secure_regions; i++) { + const struct nand_secure_region *region = &chip->secure_regions[i]; + + if (offset + size <= region->offset || + offset >= region->offset + region->size) + continue; + + pr_debug("%s: Region 0x%llx - 0x%llx is secured!", + __func__, offset, offset + size); + + return true; + } + + return false; +} + static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) { + struct mtd_info *mtd = nand_to_mtd(chip); + if (chip->options & NAND_NO_BBM_QUIRK) return 0; + /* Check if the region is secured */ + if (nand_region_is_secured(chip, ofs, mtd->erasesize)) + return -EIO; + if (chip->legacy.block_bad) return chip->legacy.block_bad(chip, ofs); @@ -397,6 +434,10 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, return -EINVAL; } + /* Check if the region is secured */ + if (nand_region_is_secured(chip, to, ops->ooblen)) + return -EIO; + chipnr = (int)(to >> chip->chip_shift); /* @@ -1294,8 +1335,6 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, }; struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page); - int ret; - u8 status; if (naddrs < 0) return naddrs; @@ -1335,15 +1374,7 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, op.ninstrs--; } - ret = nand_exec_op(chip, &op); - if (!prog || ret) - return ret; - - ret = nand_status_op(chip, &status); - if (ret) - return ret; - - return status; + return nand_exec_op(chip, &op); } /** @@ -1449,7 +1480,8 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page, unsigned int len) { struct mtd_info *mtd = nand_to_mtd(chip); - int status; + u8 status; + int ret; if (!len || !buf) return -EINVAL; @@ -1458,14 +1490,24 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page, return -EINVAL; if (nand_has_exec_op(chip)) { - status = nand_exec_prog_page_op(chip, page, offset_in_page, buf, + ret = nand_exec_prog_page_op(chip, page, offset_in_page, buf, len, true); + if (ret) + return ret; + + ret = nand_status_op(chip, &status); + if (ret) + return ret; } else { chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, page); chip->legacy.write_buf(chip, buf, len); chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); - status = chip->legacy.waitfunc(chip); + ret = chip->legacy.waitfunc(chip); + if (ret < 0) + return ret; + + status = ret; } if (status & NAND_STATUS_FAIL) @@ -3127,6 +3169,10 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, int retry_mode = 0; bool ecc_fail = false; + /* Check if the region is secured */ + if (nand_region_is_secured(chip, from, readlen)) + return -EIO; + chipnr = (int)(from >> chip->chip_shift); nand_select_target(chip, chipnr); @@ -3458,6 +3504,10 @@ static int nand_do_read_oob(struct nand_chip *chip, loff_t from, pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); + /* Check if the region is secured */ + if (nand_region_is_secured(chip, from, readlen)) + return -EIO; + stats = mtd->ecc_stats; len = mtd_oobavail(mtd, ops); @@ -3979,6 +4029,10 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to, return -EINVAL; } + /* Check if the region is secured */ + if (nand_region_is_secured(chip, to, writelen)) + return -EIO; + column = to & (mtd->writesize - 1); chipnr = (int)(to >> chip->chip_shift); @@ -4180,6 +4234,10 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, if (check_offs_len(chip, instr->addr, instr->len)) return -EINVAL; + /* Check if the region is secured */ + if (nand_region_is_secured(chip, instr->addr, instr->len)) + return -EIO; + /* Grab the lock and see if the device is available */ ret = nand_get_device(chip); if (ret) @@ -4995,6 +5053,31 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np) return of_property_read_bool(np, "nand-on-flash-bbt"); } +static int of_get_nand_secure_regions(struct nand_chip *chip) +{ + struct device_node *dn = nand_get_flash_node(chip); + int nr_elem, i, j; + + nr_elem = of_property_count_elems_of_size(dn, "secure-regions", sizeof(u64)); + if (!nr_elem) + return 0; + + chip->nr_secure_regions = nr_elem / 2; + chip->secure_regions = kcalloc(chip->nr_secure_regions, sizeof(*chip->secure_regions), + GFP_KERNEL); + if (!chip->secure_regions) + return -ENOMEM; + + for (i = 0, j = 0; i < chip->nr_secure_regions; i++, j += 2) { + of_property_read_u64_index(dn, "secure-regions", j, + &chip->secure_regions[i].offset); + of_property_read_u64_index(dn, "secure-regions", j + 1, + &chip->secure_regions[i].size); + } + + return 0; +} + static int rawnand_dt_init(struct nand_chip *chip) { struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip)); @@ -5162,8 +5245,8 @@ int rawnand_sw_hamming_init(struct nand_chip *chip) chip->ecc.size = base->ecc.ctx.conf.step_size; chip->ecc.strength = base->ecc.ctx.conf.strength; chip->ecc.total = base->ecc.ctx.total; - chip->ecc.steps = engine_conf->nsteps; - chip->ecc.bytes = engine_conf->code_size; + chip->ecc.steps = nanddev_get_ecc_nsteps(base); + chip->ecc.bytes = base->ecc.ctx.total / nanddev_get_ecc_nsteps(base); return 0; } @@ -5201,7 +5284,7 @@ EXPORT_SYMBOL(rawnand_sw_hamming_cleanup); int rawnand_sw_bch_init(struct nand_chip *chip) { struct nand_device *base = &chip->base; - struct nand_ecc_sw_bch_conf *engine_conf; + const struct nand_ecc_props *ecc_conf = nanddev_get_ecc_conf(base); int ret; base->ecc.user_conf.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; @@ -5213,13 +5296,11 @@ int rawnand_sw_bch_init(struct nand_chip *chip) if (ret) return ret; - engine_conf = base->ecc.ctx.priv; - - chip->ecc.size = base->ecc.ctx.conf.step_size; - chip->ecc.strength = base->ecc.ctx.conf.strength; + chip->ecc.size = ecc_conf->step_size; + chip->ecc.strength = ecc_conf->strength; chip->ecc.total = base->ecc.ctx.total; - chip->ecc.steps = engine_conf->nsteps; - chip->ecc.bytes = engine_conf->code_size; + chip->ecc.steps = nanddev_get_ecc_nsteps(base); + chip->ecc.bytes = base->ecc.ctx.total / nanddev_get_ecc_nsteps(base); return 0; } @@ -5953,6 +6034,16 @@ static int nand_scan_tail(struct nand_chip *chip) goto err_free_interface_config; } + /* + * Look for secure regions in the NAND chip. These regions are supposed + * to be protected by a secure element like Trustzone. So the read/write + * accesses to these regions will be blocked in the runtime by this + * driver. + */ + ret = of_get_nand_secure_regions(chip); + if (ret) + goto err_free_interface_config; + /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; @@ -5960,10 +6051,13 @@ static int nand_scan_tail(struct nand_chip *chip) /* Build bad block table */ ret = nand_create_bbt(chip); if (ret) - goto err_free_interface_config; + goto err_free_secure_regions; return 0; +err_free_secure_regions: + kfree(chip->secure_regions); + err_free_interface_config: kfree(chip->best_interface_config); @@ -6051,6 +6145,9 @@ void nand_cleanup(struct nand_chip *chip) nanddev_cleanup(&chip->base); + /* Free secure regions data */ + kfree(chip->secure_regions); + /* Free bad block table memory */ kfree(chip->bbt); kfree(chip->data_buf); diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index 2c3e65cb68f33053e3cb1901c4f8be876bd00163..c75e7a0b101fe7ff3565d0276c1d44796b11177e 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -1868,18 +1868,19 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_device *nand = mtd_to_nanddev(mtd); - const struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; + unsigned int nsteps = nanddev_get_ecc_nsteps(nand); + unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand); int off = BADBLOCK_MARKER_LENGTH; - if (section >= engine_conf->nsteps) + if (section >= nsteps) return -ERANGE; /* * When SW correction is employed, one OMAP specific marker byte is * reserved after each ECC step. */ - oobregion->offset = off + (section * (engine_conf->code_size + 1)); - oobregion->length = engine_conf->code_size; + oobregion->offset = off + (section * (ecc_bytes + 1)); + oobregion->length = ecc_bytes; return 0; } @@ -1888,7 +1889,8 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_device *nand = mtd_to_nanddev(mtd); - const struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; + unsigned int nsteps = nanddev_get_ecc_nsteps(nand); + unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand); int off = BADBLOCK_MARKER_LENGTH; if (section) @@ -1898,7 +1900,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section, * When SW correction is employed, one OMAP specific marker byte is * reserved after each ECC step. */ - off += ((engine_conf->code_size + 1) * engine_conf->nsteps); + off += ((ecc_bytes + 1) * nsteps); if (off >= mtd->oobsize) return -ERANGE; diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index fd4c318b520f3673cd20215b5b8c910fd03ce5d6..a64fb6ce915daee61a50ac96d6e7ab3a440a6dcf 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -27,7 +27,7 @@ #define NAND_DEV0_CFG0 0x20 #define NAND_DEV0_CFG1 0x24 #define NAND_DEV0_ECC_CFG 0x28 -#define NAND_DEV1_ECC_CFG 0x2c +#define NAND_AUTO_STATUS_EN 0x2c #define NAND_DEV1_CFG0 0x30 #define NAND_DEV1_CFG1 0x34 #define NAND_READ_ID 0x40 @@ -48,6 +48,10 @@ #define NAND_READ_LOCATION_1 0xf24 #define NAND_READ_LOCATION_2 0xf28 #define NAND_READ_LOCATION_3 0xf2c +#define NAND_READ_LOCATION_LAST_CW_0 0xf40 +#define NAND_READ_LOCATION_LAST_CW_1 0xf44 +#define NAND_READ_LOCATION_LAST_CW_2 0xf48 +#define NAND_READ_LOCATION_LAST_CW_3 0xf4c /* dummy register offsets, used by write_reg_dma */ #define NAND_DEV_CMD1_RESTORE 0xdead @@ -181,12 +185,17 @@ #define ECC_BCH_4BIT BIT(2) #define ECC_BCH_8BIT BIT(3) -#define nandc_set_read_loc(nandc, reg, offset, size, is_last) \ -nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ - ((offset) << READ_LOCATION_OFFSET) | \ - ((size) << READ_LOCATION_SIZE) | \ - ((is_last) << READ_LOCATION_LAST)) - +#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \ +nandc_set_reg(chip, reg, \ + ((cw_offset) << READ_LOCATION_OFFSET) | \ + ((read_size) << READ_LOCATION_SIZE) | \ + ((is_last_read_loc) << READ_LOCATION_LAST)) + +#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \ +nandc_set_reg(chip, reg, \ + ((cw_offset) << READ_LOCATION_OFFSET) | \ + ((read_size) << READ_LOCATION_SIZE) | \ + ((is_last_read_loc) << READ_LOCATION_LAST)) /* * Returns the actual register address for all NAND_DEV_ registers * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) @@ -316,6 +325,10 @@ struct nandc_regs { __le32 read_location1; __le32 read_location2; __le32 read_location3; + __le32 read_location_last0; + __le32 read_location_last1; + __le32 read_location_last2; + __le32 read_location_last3; __le32 erased_cw_detect_cfg_clr; __le32 erased_cw_detect_cfg_set; @@ -644,14 +657,23 @@ static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) return ®s->read_location2; case NAND_READ_LOCATION_3: return ®s->read_location3; + case NAND_READ_LOCATION_LAST_CW_0: + return ®s->read_location_last0; + case NAND_READ_LOCATION_LAST_CW_1: + return ®s->read_location_last1; + case NAND_READ_LOCATION_LAST_CW_2: + return ®s->read_location_last2; + case NAND_READ_LOCATION_LAST_CW_3: + return ®s->read_location_last3; default: return NULL; } } -static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset, +static void nandc_set_reg(struct nand_chip *chip, int offset, u32 val) { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nandc_regs *regs = nandc->regs; __le32 *reg; @@ -661,17 +683,43 @@ static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset, *reg = cpu_to_le32(val); } +/* Helper to check the code word, whether it is last cw or not */ +static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) +{ + return cw == (ecc->steps - 1); +} + +/* helper to configure location register values */ +static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg, + int cw_offset, int read_size, int is_last_read_loc) +{ + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int reg_base = NAND_READ_LOCATION_0; + + if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) + reg_base = NAND_READ_LOCATION_LAST_CW_0; + + reg_base += reg * 4; + + if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) + return nandc_set_read_loc_last(chip, reg_base, cw_offset, + read_size, is_last_read_loc); + else + return nandc_set_read_loc_first(chip, reg_base, cw_offset, + read_size, is_last_read_loc); +} + /* helper to configure address register values */ static void set_address(struct qcom_nand_host *host, u16 column, int page) { struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); if (chip->options & NAND_BUSWIDTH_16) column >>= 1; - nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column); - nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff); + nandc_set_reg(chip, NAND_ADDR0, page << 16 | column); + nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff); } /* @@ -680,11 +728,11 @@ static void set_address(struct qcom_nand_host *host, u16 column, int page) * * @num_cw: number of steps for the read/write operation * @read: read or write operation + * @cw : which code word */ -static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) +static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw) { struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); u32 cmd, cfg0, cfg1, ecc_bch_cfg; if (read) { @@ -710,17 +758,17 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; } - nandc_set_reg(nandc, NAND_FLASH_CMD, cmd); - nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0); - nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1); - nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg); - nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg); - nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); - nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); - nandc_set_reg(nandc, NAND_EXEC_CMD, 1); + nandc_set_reg(chip, NAND_FLASH_CMD, cmd); + nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0); + nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1); + nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg); + nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg); + nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus); + nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); if (read) - nandc_set_read_loc(nandc, 0, 0, host->use_ecc ? + nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ? host->cw_data : host->cw_size, 1); } @@ -1079,8 +1127,10 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, * Helper to prepare DMA descriptors for configuring registers * before reading a NAND page. */ -static void config_nand_page_read(struct qcom_nand_controller *nandc) +static void config_nand_page_read(struct nand_chip *chip) { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + write_reg_dma(nandc, NAND_ADDR0, 2, 0); write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); @@ -1094,11 +1144,18 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) * before reading each codeword in NAND page. */ static void -config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc) +config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw) { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + int reg = NAND_READ_LOCATION_0; + + if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) + reg = NAND_READ_LOCATION_LAST_CW_0; + if (nandc->props->is_bam) - write_reg_dma(nandc, NAND_READ_LOCATION_0, 4, - NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -1117,19 +1174,21 @@ config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc) * single codeword in page */ static void -config_nand_single_cw_page_read(struct qcom_nand_controller *nandc, - bool use_ecc) +config_nand_single_cw_page_read(struct nand_chip *chip, + bool use_ecc, int cw) { - config_nand_page_read(nandc); - config_nand_cw_read(nandc, use_ecc); + config_nand_page_read(chip); + config_nand_cw_read(chip, use_ecc, cw); } /* * Helper to prepare DMA descriptors used to configure registers needed for * before writing a NAND page. */ -static void config_nand_page_write(struct qcom_nand_controller *nandc) +static void config_nand_page_write(struct nand_chip *chip) { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + write_reg_dma(nandc, NAND_ADDR0, 2, 0); write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, @@ -1140,8 +1199,10 @@ static void config_nand_page_write(struct qcom_nand_controller *nandc) * Helper to prepare DMA descriptors for configuring registers * before writing each codeword in NAND page. */ -static void config_nand_cw_write(struct qcom_nand_controller *nandc) +static void config_nand_cw_write(struct nand_chip *chip) { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -1168,44 +1229,44 @@ static int nandc_param(struct qcom_nand_host *host) * bytes to read onfi params */ if (nandc->props->qpic_v2) - nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ_ONFI_READ | + nandc_set_reg(chip, NAND_FLASH_CMD, OP_PAGE_READ_ONFI_READ | PAGE_ACC | LAST_PAGE); else - nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ | + nandc_set_reg(chip, NAND_FLASH_CMD, OP_PAGE_READ | PAGE_ACC | LAST_PAGE); - nandc_set_reg(nandc, NAND_ADDR0, 0); - nandc_set_reg(nandc, NAND_ADDR1, 0); - nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE + nandc_set_reg(chip, NAND_ADDR0, 0); + nandc_set_reg(chip, NAND_ADDR1, 0); + nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE | 512 << UD_SIZE_BYTES | 5 << NUM_ADDR_CYCLES | 0 << SPARE_SIZE_BYTES); - nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES + nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES | 0 << CS_ACTIVE_BSY | 17 << BAD_BLOCK_BYTE_NUM | 1 << BAD_BLOCK_IN_SPARE_AREA | 2 << WR_RD_BSY_GAP | 0 << WIDE_FLASH | 1 << DEV0_CFG1_ECC_DISABLE); - nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); + nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ if (!nandc->props->qpic_v2) { - nandc_set_reg(nandc, NAND_DEV_CMD_VLD, + nandc_set_reg(chip, NAND_DEV_CMD_VLD, (nandc->vld & ~READ_START_VLD)); - nandc_set_reg(nandc, NAND_DEV_CMD1, + nandc_set_reg(chip, NAND_DEV_CMD1, (nandc->cmd1 & ~(0xFF << READ_ADDR)) | NAND_CMD_PARAM << READ_ADDR); } - nandc_set_reg(nandc, NAND_EXEC_CMD, 1); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); if (!nandc->props->qpic_v2) { - nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1); - nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); + nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1); + nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); } - nandc_set_read_loc(nandc, 0, 0, 512, 1); + nandc_set_read_loc(chip, 0, 0, 0, 512, 1); if (!nandc->props->qpic_v2) { write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); @@ -1215,7 +1276,7 @@ static int nandc_param(struct qcom_nand_host *host) nandc->buf_count = 512; memset(nandc->data_buffer, 0xff, nandc->buf_count); - config_nand_single_cw_page_read(nandc, false); + config_nand_single_cw_page_read(chip, false, 0); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, nandc->buf_count, 0); @@ -1235,16 +1296,16 @@ static int erase_block(struct qcom_nand_host *host, int page_addr) struct nand_chip *chip = &host->chip; struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - nandc_set_reg(nandc, NAND_FLASH_CMD, + nandc_set_reg(chip, NAND_FLASH_CMD, OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE); - nandc_set_reg(nandc, NAND_ADDR0, page_addr); - nandc_set_reg(nandc, NAND_ADDR1, 0); - nandc_set_reg(nandc, NAND_DEV0_CFG0, + nandc_set_reg(chip, NAND_ADDR0, page_addr); + nandc_set_reg(chip, NAND_ADDR1, 0); + nandc_set_reg(chip, NAND_DEV0_CFG0, host->cfg0_raw & ~(7 << CW_PER_PAGE)); - nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw); - nandc_set_reg(nandc, NAND_EXEC_CMD, 1); - nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); - nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); + nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); + nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus); + nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus); write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); @@ -1267,12 +1328,12 @@ static int read_id(struct qcom_nand_host *host, int column) if (column == -1) return 0; - nandc_set_reg(nandc, NAND_FLASH_CMD, OP_FETCH_ID); - nandc_set_reg(nandc, NAND_ADDR0, column); - nandc_set_reg(nandc, NAND_ADDR1, 0); - nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, + nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID); + nandc_set_reg(chip, NAND_ADDR0, column); + nandc_set_reg(chip, NAND_ADDR1, 0); + nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT, nandc->props->is_bam ? 0 : DM_EN); - nandc_set_reg(nandc, NAND_EXEC_CMD, 1); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -1288,8 +1349,8 @@ static int reset(struct qcom_nand_host *host) struct nand_chip *chip = &host->chip; struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - nandc_set_reg(nandc, NAND_FLASH_CMD, OP_RESET_DEVICE); - nandc_set_reg(nandc, NAND_EXEC_CMD, 1); + nandc_set_reg(chip, NAND_FLASH_CMD, OP_RESET_DEVICE); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -1492,7 +1553,7 @@ static void qcom_nandc_command(struct nand_chip *chip, unsigned int command, host->use_ecc = true; set_address(host, 0, page_addr); - update_rw_regs(host, ecc->steps, true); + update_rw_regs(host, ecc->steps, true, 0); break; case NAND_CMD_SEQIN: @@ -1616,13 +1677,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, clear_bam_transaction(nandc); set_address(host, host->cw_size * cw, page); - update_rw_regs(host, 1, true); - config_nand_page_read(nandc); + update_rw_regs(host, 1, true, cw); + config_nand_page_read(chip); data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); oob_size1 = host->bbm_size; - if (cw == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, cw)) { data_size2 = ecc->size - data_size1 - ((ecc->steps - 1) * 4); oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + @@ -1633,19 +1694,19 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, } if (nandc->props->is_bam) { - nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0); + nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0); read_loc += data_size1; - nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0); + nandc_set_read_loc(chip, cw, 1, read_loc, oob_size1, 0); read_loc += oob_size1; - nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0); + nandc_set_read_loc(chip, cw, 2, read_loc, data_size2, 0); read_loc += data_size2; - nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1); + nandc_set_read_loc(chip, cw, 3, read_loc, oob_size2, 1); } - config_nand_cw_read(nandc, false); + config_nand_cw_read(chip, false, cw); read_data_dma(nandc, reg_off, data_buf, data_size1, 0); reg_off += data_size1; @@ -1703,7 +1764,7 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf, } for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { - if (cw == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, cw)) { data_size = ecc->size - ((ecc->steps - 1) * 4); oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; } else { @@ -1763,7 +1824,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, u32 flash, buffer, erased_cw; int data_len, oob_len; - if (i == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, i)) { data_len = ecc->size - ((ecc->steps - 1) << 2); oob_len = ecc->steps << 2; } else { @@ -1856,13 +1917,13 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf; int i, ret; - config_nand_page_read(nandc); + config_nand_page_read(chip); /* queue cmd descs for each codeword */ for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; - if (i == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, i)) { data_size = ecc->size - ((ecc->steps - 1) << 2); oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + host->spare_bytes; @@ -1873,18 +1934,18 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, if (nandc->props->is_bam) { if (data_buf && oob_buf) { - nandc_set_read_loc(nandc, 0, 0, data_size, 0); - nandc_set_read_loc(nandc, 1, data_size, + nandc_set_read_loc(chip, i, 0, 0, data_size, 0); + nandc_set_read_loc(chip, i, 1, data_size, oob_size, 1); } else if (data_buf) { - nandc_set_read_loc(nandc, 0, 0, data_size, 1); + nandc_set_read_loc(chip, i, 0, 0, data_size, 1); } else { - nandc_set_read_loc(nandc, 0, data_size, + nandc_set_read_loc(chip, i, 0, data_size, oob_size, 1); } } - config_nand_cw_read(nandc, true); + config_nand_cw_read(chip, true, i); if (data_buf) read_data_dma(nandc, FLASH_BUF_ACC, data_buf, @@ -1944,9 +2005,9 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) memset(nandc->data_buffer, 0xff, size); set_address(host, host->cw_size * (ecc->steps - 1), page); - update_rw_regs(host, 1, true); + update_rw_regs(host, 1, true, ecc->steps - 1); - config_nand_single_cw_page_read(nandc, host->use_ecc); + config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); @@ -2011,7 +2072,7 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) host->use_ecc = true; set_address(host, 0, page); - update_rw_regs(host, ecc->steps, true); + update_rw_regs(host, ecc->steps, true, 0); return read_page_ecc(host, NULL, chip->oob_poi, page); } @@ -2035,13 +2096,13 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, oob_buf = chip->oob_poi; host->use_ecc = true; - update_rw_regs(host, ecc->steps, false); - config_nand_page_write(nandc); + update_rw_regs(host, ecc->steps, false, 0); + config_nand_page_write(chip); for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; - if (i == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, i)) { data_size = ecc->size - ((ecc->steps - 1) << 2); oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + host->spare_bytes; @@ -2061,14 +2122,14 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, * itself. For the last codeword, we skip the bbm positions and * write to the free oob area. */ - if (i == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, i)) { oob_buf += host->bbm_size; write_data_dma(nandc, FLASH_BUF_ACC + data_size, oob_buf, oob_size, 0); } - config_nand_cw_write(nandc); + config_nand_cw_write(chip); data_buf += data_size; oob_buf += oob_size; @@ -2106,8 +2167,8 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, oob_buf = chip->oob_poi; host->use_ecc = false; - update_rw_regs(host, ecc->steps, false); - config_nand_page_write(nandc); + update_rw_regs(host, ecc->steps, false, 0); + config_nand_page_write(chip); for (i = 0; i < ecc->steps; i++) { int data_size1, data_size2, oob_size1, oob_size2; @@ -2116,7 +2177,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); oob_size1 = host->bbm_size; - if (i == (ecc->steps - 1)) { + if (qcom_nandc_is_last_cw(ecc, i)) { data_size2 = ecc->size - data_size1 - ((ecc->steps - 1) << 2); oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + @@ -2144,7 +2205,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); oob_buf += oob_size2; - config_nand_cw_write(nandc); + config_nand_cw_write(chip); } ret = submit_descs(nandc); @@ -2189,12 +2250,12 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) 0, mtd->oobavail); set_address(host, host->cw_size * (ecc->steps - 1), page); - update_rw_regs(host, 1, false); + update_rw_regs(host, 1, false, 0); - config_nand_page_write(nandc); + config_nand_page_write(chip); write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, data_size + oob_size, 0); - config_nand_cw_write(nandc); + config_nand_cw_write(chip); ret = submit_descs(nandc); @@ -2268,12 +2329,12 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) /* prepare write */ host->use_ecc = false; set_address(host, host->cw_size * (ecc->steps - 1), page); - update_rw_regs(host, 1, false); + update_rw_regs(host, 1, false, ecc->steps - 1); - config_nand_page_write(nandc); + config_nand_page_write(chip); write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, host->cw_size, 0); - config_nand_cw_write(nandc); + config_nand_cw_write(chip); ret = submit_descs(nandc); @@ -2882,6 +2943,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, if (!nandc->bam_txn) { dev_err(nandc->dev, "failed to allocate bam transaction\n"); + nand_cleanup(chip); return -ENOMEM; } } @@ -2898,7 +2960,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) struct device *dev = nandc->dev; struct device_node *dn = dev->of_node, *child; struct qcom_nand_host *host; - int ret; + int ret = -ENODEV; for_each_available_child_of_node(dn, child) { host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); @@ -2916,10 +2978,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) list_add_tail(&host->node, &nandc->host_list); } - if (list_empty(&nandc->host_list)) - return -ENODEV; - - return 0; + return ret; } /* parse custom DT properties here */ @@ -2992,7 +3051,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) nandc->base_dma = dma_map_resource(dev, res->start, resource_size(res), DMA_BIDIRECTIONAL, 0); - if (!nandc->base_dma) + if (dma_mapping_error(dev, nandc->base_dma)) return -ENXIO; ret = qcom_nandc_alloc(nandc); diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index c742354c1b0becafba04aa2bb99434c32c9c4caf..ebe859ca49cbfa16b67ccd24a24905372ead854e 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -724,10 +724,9 @@ static irqreturn_t r852_irq(int irq, void *data) struct r852_device *dev = (struct r852_device *)data; uint8_t card_status, dma_status; - unsigned long flags; irqreturn_t ret = IRQ_NONE; - spin_lock_irqsave(&dev->irqlock, flags); + spin_lock(&dev->irqlock); /* handle card detection interrupts first */ card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); @@ -813,7 +812,7 @@ static irqreturn_t r852_irq(int irq, void *data) dbg("strange card status = %x", card_status); out: - spin_unlock_irqrestore(&dev->irqlock, flags); + spin_unlock(&dev->irqlock); return ret; } diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index 796b678cb108c4cbfcc449ef481b4c5aec3b272e..b5405bc7ca3a39294bfa46c60bcf9e1522f2e238 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -159,7 +159,7 @@ struct rk_nfc_nand_chip { u32 timing; u8 nsels; - u8 sels[0]; + u8 sels[]; /* Nothing after this field. */ }; diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 550bda4d1415a34745bde133bf32203d3cf604e9..1c277fbb91f2bfad9a18f47e4bfded311af88595 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -531,6 +531,7 @@ static int stm32_fmc2_nfc_ham_correct(struct nand_chip *chip, u8 *dat, switch (b % 4) { case 2: bit_position += shifting; + break; case 1: break; default: @@ -546,6 +547,7 @@ static int stm32_fmc2_nfc_ham_correct(struct nand_chip *chip, u8 *dat, switch (b % 4) { case 2: byte_addr += shifting; + break; case 1: break; default: diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 61d932c1b71806166c089a173182c33a7d4fcc1a..17f63f95f4a280386b57751f72e3976bcb0fea5e 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1263,12 +1263,14 @@ static const struct spi_device_id spinand_ids[] = { { .name = "spi-nand" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(spi, spinand_ids); #ifdef CONFIG_OF static const struct of_device_id spinand_of_ids[] = { { .compatible = "spi-nand" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, spinand_of_ids); #endif static struct spi_mem_driver spinand_drv = { diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index 33c67403c4aa1e89a122b3d930e03c61bc8eec22..1dd1c589809341734d98fb3ebb1eca0be8c91d3a 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -13,7 +13,10 @@ #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4) #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4) -#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0 +#define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS (1 << 4) +#define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS (3 << 4) + +#define GD5FXGQXXEXXG_REG_STATUS2 0xf0 #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4) #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4) @@ -102,7 +105,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } -static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section, +static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { if (section) @@ -114,7 +117,7 @@ static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section, return 0; } -static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section, +static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { if (section) @@ -127,9 +130,10 @@ static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section, return 0; } -static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = { - .ecc = gd5fxgq4_variant2_ooblayout_ecc, - .free = gd5fxgq4_variant2_ooblayout_free, +/* Valid for Q4/Q5 and Q6 (untested) devices */ +static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = { + .ecc = gd5fxgqx_variant2_ooblayout_ecc, + .free = gd5fxgqx_variant2_ooblayout_free, }; static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section, @@ -165,7 +169,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, u8 status) { u8 status2; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2, + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2, &status2); int ret; @@ -203,6 +207,43 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } +static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + u8 status2; + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2, + &status2); + int ret; + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS: + /* + * Read status2 register to determine a more fine grained + * bit error status + */ + ret = spi_mem_exec_op(spinand->spimem, &op); + if (ret) + return ret; + + /* + * 1 ... 4 bits are flipped (and corrected) + */ + /* bits sorted this way (1...0): ECCSE1, ECCSE0 */ + return ((status2 & STATUS_ECC_MASK) >> 4) + 1; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + default: + break; + } + + return -EINVAL; +} + static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand, u8 status) { @@ -282,7 +323,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { &write_cache_variants, &update_cache_variants), SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), SPINAND_INFO("GD5F1GQ4UFxxG", SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48), @@ -292,8 +333,18 @@ static const struct spinand_info gigadevice_spinand_table[] = { &write_cache_variants, &update_cache_variants), SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq4ufxxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ5UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), }; static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index d44641129cdbffc24d55b55fc9141319e67bc04b..bcd0094f172dcc7ded69fdfa8179476adce5bf55 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -797,18 +797,7 @@ static struct mtd_blktrans_ops nftl_tr = { .owner = THIS_MODULE, }; -static int __init init_nftl(void) -{ - return register_mtd_blktrans(&nftl_tr); -} - -static void __exit cleanup_nftl(void) -{ - deregister_mtd_blktrans(&nftl_tr); -} - -module_init(init_nftl); -module_exit(cleanup_nftl); +module_mtd_blktrans(nftl_tr); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index d90c3022905229beca6d7971c5c45493bcead6b4..9babe678c41b0805655350acbc3c5341cbe52644 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -67,6 +67,25 @@ config MTD_OF_PARTS flash memory node, as described in Documentation/devicetree/bindings/mtd/partition.txt. +config MTD_OF_PARTS_BCM4908 + bool "BCM4908 partitioning support" + depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST) + default ARCH_BCM4908 + help + This provides partitions parser for BCM4908 family devices + that can have multiple "firmware" partitions. It takes care of + finding currently used one and backup ones. + +config MTD_OF_PARTS_LINKSYS_NS + bool "Linksys Northstar partitioning support" + depends on MTD_OF_PARTS && (ARCH_BCM_5301X || ARCH_BCM4908 || COMPILE_TEST) + default ARCH_BCM_5301X + help + This provides partitions parser for Linksys devices based on Broadcom + Northstar architecture. Linksys commonly uses fixed flash layout with + two "firmware" partitions. Currently used firmware has to be detected + using CFE environment variable. + config MTD_PARSER_IMAGETAG tristate "Parser for BCM963XX Image Tag format partitions" depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST @@ -162,9 +181,8 @@ config MTD_REDBOOT_PARTS_READONLY endif # MTD_REDBOOT_PARTS config MTD_QCOMSMEM_PARTS - tristate "Qualcomm SMEM NAND flash partition parser" - depends on MTD_NAND_QCOM || COMPILE_TEST + tristate "Qualcomm SMEM flash partition parser" depends on QCOM_SMEM help This provides support for parsing partitions from Shared Memory (SMEM) - for NAND flash on Qualcomm platforms. + for NAND and SPI flash on Qualcomm platforms. diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index 50eb0b0a22105773af1d2e2435730b2753b35c9e..2e98aa0482787611bbf58f2e8e0e71eb0b09e9bf 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o +ofpart-y += ofpart_core.o +ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o +ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o diff --git a/drivers/mtd/parsers/ofpart_bcm4908.c b/drivers/mtd/parsers/ofpart_bcm4908.c new file mode 100644 index 0000000000000000000000000000000000000000..0eddef4c198eccc9be8ae67f45d48d22b6dbb923 --- /dev/null +++ b/drivers/mtd/parsers/ofpart_bcm4908.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/mtd/mtd.h> +#include <linux/slab.h> +#include <linux/mtd/partitions.h> + +#include "ofpart_bcm4908.h" + +#define BLPARAMS_FW_OFFSET "NAND_RFS_OFS" + +static long long bcm4908_partitions_fw_offset(void) +{ + struct device_node *root; + struct property *prop; + const char *s; + + root = of_find_node_by_path("/"); + if (!root) + return -ENOENT; + + of_property_for_each_string(root, "brcm_blparms", prop, s) { + size_t len = strlen(BLPARAMS_FW_OFFSET); + unsigned long offset; + int err; + + if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=') + continue; + + err = kstrtoul(s + len + 1, 0, &offset); + if (err) { + pr_err("failed to parse %s\n", s + len + 1); + return err; + } + + return offset << 10; + } + + return -ENOENT; +} + +int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts) +{ + long long fw_offset; + int i; + + fw_offset = bcm4908_partitions_fw_offset(); + + for (i = 0; i < nr_parts; i++) { + if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) { + if (fw_offset < 0 || parts[i].offset == fw_offset) + parts[i].name = "firmware"; + else + parts[i].name = "backup"; + } + } + + return 0; +} diff --git a/drivers/mtd/parsers/ofpart_bcm4908.h b/drivers/mtd/parsers/ofpart_bcm4908.h new file mode 100644 index 0000000000000000000000000000000000000000..80f8c086641fb0cc6dbcbecc22352067fa66c5bf --- /dev/null +++ b/drivers/mtd/parsers/ofpart_bcm4908.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __BCM4908_PARTITIONS_H +#define __BCM4908_PARTITIONS_H + +#ifdef CONFIG_MTD_OF_PARTS_BCM4908 +int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); +#else +static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, + int nr_parts) +{ + return -EOPNOTSUPP; +} +#endif + +#endif diff --git a/drivers/mtd/parsers/ofpart.c b/drivers/mtd/parsers/ofpart_core.c similarity index 84% rename from drivers/mtd/parsers/ofpart.c rename to drivers/mtd/parsers/ofpart_core.c index daf507c123e6fd4beedd06716ae5abb2f8508610..0fd8d2a0db973c5233ce978835360d777d683adb 100644 --- a/drivers/mtd/parsers/ofpart.c +++ b/drivers/mtd/parsers/ofpart_core.c @@ -16,6 +16,23 @@ #include <linux/slab.h> #include <linux/mtd/partitions.h> +#include "ofpart_bcm4908.h" +#include "ofpart_linksys_ns.h" + +struct fixed_partitions_quirks { + int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); +}; + +static struct fixed_partitions_quirks bcm4908_partitions_quirks = { + .post_parse = bcm4908_partitions_post_parse, +}; + +static struct fixed_partitions_quirks linksys_ns_partitions_quirks = { + .post_parse = linksys_ns_partitions_post_parse, +}; + +static const struct of_device_id parse_ofpart_match_table[]; + static bool node_has_compatible(struct device_node *pp) { return of_get_property(pp, "compatible", NULL); @@ -25,6 +42,8 @@ static int parse_fixed_partitions(struct mtd_info *master, const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { + const struct fixed_partitions_quirks *quirks; + const struct of_device_id *of_id; struct mtd_partition *parts; struct device_node *mtd_node; struct device_node *ofpart_node; @@ -33,14 +52,13 @@ static int parse_fixed_partitions(struct mtd_info *master, int nr_parts, i, ret = 0; bool dedicated = true; - /* Pull of_node from the master device node */ mtd_node = mtd_get_of_node(master); if (!mtd_node) return 0; ofpart_node = of_get_child_by_name(mtd_node, "partitions"); - if (!ofpart_node) { + if (!ofpart_node && !master->parent) { /* * We might get here even when ofpart isn't used at all (e.g., * when using another parser), so don't be louder than @@ -50,11 +68,18 @@ static int parse_fixed_partitions(struct mtd_info *master, master->name, mtd_node); ofpart_node = mtd_node; dedicated = false; - } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) { + } + if (!ofpart_node) + return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { /* The 'partitions' subnode might be used by another parser */ return 0; } + quirks = of_id ? of_id->data : NULL; + /* First count the subnodes */ nr_parts = 0; for_each_child_of_node(ofpart_node, pp) { @@ -126,6 +151,9 @@ static int parse_fixed_partitions(struct mtd_info *master, if (!nr_parts) goto ofpart_none; + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + *pparts = parts; return nr_parts; @@ -140,7 +168,11 @@ ofpart_none: } static const struct of_device_id parse_ofpart_match_table[] = { + /* Generic */ { .compatible = "fixed-partitions" }, + /* Customized */ + { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, }, + { .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, }, {}, }; MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); diff --git a/drivers/mtd/parsers/ofpart_linksys_ns.c b/drivers/mtd/parsers/ofpart_linksys_ns.c new file mode 100644 index 0000000000000000000000000000000000000000..318c42d0256b4517d5625fa8c2a8e10f70a2970f --- /dev/null +++ b/drivers/mtd/parsers/ofpart_linksys_ns.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> + */ + +#include <linux/bcm47xx_nvram.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include "ofpart_linksys_ns.h" + +#define NVRAM_BOOT_PART "bootpartition" + +static int ofpart_linksys_ns_bootpartition(void) +{ + char buf[4]; + int bootpartition; + + /* Check CFE environment variable */ + if (bcm47xx_nvram_getenv(NVRAM_BOOT_PART, buf, sizeof(buf)) > 0) { + if (!kstrtoint(buf, 0, &bootpartition)) + return bootpartition; + pr_warn("Failed to parse %s value \"%s\"\n", NVRAM_BOOT_PART, + buf); + } else { + pr_warn("Failed to get NVRAM \"%s\"\n", NVRAM_BOOT_PART); + } + + return 0; +} + +int linksys_ns_partitions_post_parse(struct mtd_info *mtd, + struct mtd_partition *parts, + int nr_parts) +{ + int bootpartition = ofpart_linksys_ns_bootpartition(); + int trx_idx = 0; + int i; + + for (i = 0; i < nr_parts; i++) { + if (of_device_is_compatible(parts[i].of_node, "linksys,ns-firmware")) { + if (trx_idx++ == bootpartition) + parts[i].name = "firmware"; + else + parts[i].name = "backup"; + } + } + + return 0; +} diff --git a/drivers/mtd/parsers/ofpart_linksys_ns.h b/drivers/mtd/parsers/ofpart_linksys_ns.h new file mode 100644 index 0000000000000000000000000000000000000000..730c46812ebfd38eba98a231c3f4fe94271c6a0b --- /dev/null +++ b/drivers/mtd/parsers/ofpart_linksys_ns.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __OFPART_LINKSYS_NS_H +#define __OFPART_LINKSYS_NS_H + +#ifdef CONFIG_MTD_OF_PARTS_LINKSYS_NS +int linksys_ns_partitions_post_parse(struct mtd_info *mtd, + struct mtd_partition *parts, + int nr_parts); +#else +static inline int linksys_ns_partitions_post_parse(struct mtd_info *mtd, + struct mtd_partition *parts, + int nr_parts) +{ + return -EOPNOTSUPP; +} +#endif + +#endif diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c index 808cb33d71f8ec43b48c14bad2f06f46421e6bd8..d9083308f6ba61c24ebc216a38fd81fac75c535c 100644 --- a/drivers/mtd/parsers/qcomsmempart.c +++ b/drivers/mtd/parsers/qcomsmempart.c @@ -65,6 +65,13 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, int ret, i, numparts; char *name, *c; + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS) + && mtd->type == MTD_NORFLASH) { + pr_err("%s: SMEM partition parser is incompatible with 4K sectors\n", + mtd->name); + return -EINVAL; + } + pr_debug("Parsing partition table info from SMEM\n"); ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); if (IS_ERR(ptable)) { @@ -104,7 +111,7 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, * complete partition table */ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); - if (IS_ERR_OR_NULL(ptable)) { + if (IS_ERR(ptable)) { pr_err("Error reading partition table\n"); return PTR_ERR(ptable); } diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 3d1df82fa105f13900750aa3db0a4bfe493c4142..cce3bf6f99b4ad6d5165102ff7209ce4968d2e6c 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -794,18 +794,7 @@ static struct mtd_blktrans_ops rfd_ftl_tr = { .owner = THIS_MODULE, }; -static int __init init_rfd_ftl(void) -{ - return register_mtd_blktrans(&rfd_ftl_tr); -} - -static void __exit cleanup_rfd_ftl(void) -{ - deregister_mtd_blktrans(&rfd_ftl_tr); -} - -module_init(init_rfd_ftl); -module_exit(cleanup_rfd_ftl); +module_mtd_blktrans(rfd_ftl_tr); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sean Young <sean@mess.org>"); diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 653923896205c2103b9d123ee6c68196c15a0bc2..136f245c91dcec17598e7c6d1fc65ac5087eb905 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -spi-nor-objs := core.o sfdp.o +spi-nor-objs := core.o sfdp.o swp.o otp.o spi-nor-objs += atmel.o spi-nor-objs += catalyst.o spi-nor-objs += eon.o diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c index b54a56a68100e2ac7e298b978ddf60c6fc314045..a413892ff449f4d89f6d88f6e0868a5803c7f666 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi.c @@ -15,7 +15,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/mtd/spi-nor.h> -#include <linux/platform_data/intel-spi.h> #include "intel-spi.h" diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.h b/drivers/mtd/spi-nor/controllers/intel-spi.h index e2f41b8827bfecea44034606ea002165585ac8a3..f2871179fd34def3ac3e22ec341ae4fa2ca2c9d8 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi.h +++ b/drivers/mtd/spi-nor/controllers/intel-spi.h @@ -9,7 +9,7 @@ #ifndef INTEL_SPI_H #define INTEL_SPI_H -#include <linux/platform_data/intel-spi.h> +#include <linux/platform_data/x86/intel-spi.h> struct intel_spi; struct resource; diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0522304f52fade53e77fc4e4afcb23e490d7db04..bd2c7717eb1029b8e592a1a6332a09ca74396e56 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1034,7 +1034,7 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) +int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) { int ret; u8 *sr_cr = nor->bouncebuf; @@ -1610,6 +1610,9 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) list_for_each_entry_safe(cmd, next, &erase_list, list) { nor->erase_opcode = cmd->opcode; while (cmd->count) { + dev_vdbg(nor->dev, "erase_cmd->size = 0x%08x, erase_cmd->opcode = 0x%02x, erase_cmd->count = %u\n", + cmd->size, cmd->opcode, cmd->count); + ret = spi_nor_write_enable(nor); if (ret) goto destroy_erase_cmd_list; @@ -1618,12 +1621,12 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) if (ret) goto destroy_erase_cmd_list; - addr += cmd->size; - cmd->count--; - ret = spi_nor_wait_till_ready(nor); if (ret) goto destroy_erase_cmd_list; + + addr += cmd->size; + cmd->count--; } list_del(&cmd->list); kfree(cmd); @@ -1704,12 +1707,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) if (ret) goto erase_err; - addr += mtd->erasesize; - len -= mtd->erasesize; - ret = spi_nor_wait_till_ready(nor); if (ret) goto erase_err; + + addr += mtd->erasesize; + len -= mtd->erasesize; } /* erase multiple sectors */ @@ -1727,376 +1730,6 @@ erase_err: return ret; } -static u8 spi_nor_get_sr_bp_mask(struct spi_nor *nor) -{ - u8 mask = SR_BP2 | SR_BP1 | SR_BP0; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6) - return mask | SR_BP3_BIT6; - - if (nor->flags & SNOR_F_HAS_4BIT_BP) - return mask | SR_BP3; - - return mask; -} - -static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) -{ - if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) - return SR_TB_BIT6; - else - return SR_TB_BIT5; -} - -static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) -{ - unsigned int bp_slots, bp_slots_needed; - u8 mask = spi_nor_get_sr_bp_mask(nor); - - /* Reserved one for "protect none" and one for "protect all". */ - bp_slots = (1 << hweight8(mask)) - 2; - bp_slots_needed = ilog2(nor->info->n_sectors); - - if (bp_slots_needed > bp_slots) - return nor->info->sector_size << - (bp_slots_needed - bp_slots); - else - return nor->info->sector_size; -} - -static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs, - uint64_t *len) -{ - struct mtd_info *mtd = &nor->mtd; - u64 min_prot_len; - u8 mask = spi_nor_get_sr_bp_mask(nor); - u8 tb_mask = spi_nor_get_sr_tb_mask(nor); - u8 bp, val = sr & mask; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6) - val = (val & ~SR_BP3_BIT6) | SR_BP3; - - bp = val >> SR_BP_SHIFT; - - if (!bp) { - /* No protection */ - *ofs = 0; - *len = 0; - return; - } - - min_prot_len = spi_nor_get_min_prot_length_sr(nor); - *len = min_prot_len << (bp - 1); - - if (*len > mtd->size) - *len = mtd->size; - - if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask) - *ofs = 0; - else - *ofs = mtd->size - *len; -} - -/* - * Return 1 if the entire region is locked (if @locked is true) or unlocked (if - * @locked is false); 0 otherwise - */ -static int spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, - uint64_t len, u8 sr, bool locked) -{ - loff_t lock_offs; - uint64_t lock_len; - - if (!len) - return 1; - - spi_nor_get_locked_range_sr(nor, sr, &lock_offs, &lock_len); - - if (locked) - /* Requested range is a sub-range of locked range */ - return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs); - else - /* Requested range does not overlap with locked range */ - return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs); -} - -static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, - u8 sr) -{ - return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true); -} - -static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, - u8 sr) -{ - return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false); -} - -/* - * Lock a region of the flash. Compatible with ST Micro and similar flash. - * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status - * register - * (SR). Does not support these features found in newer SR bitfields: - * - SEC: sector/block protect - only handle SEC=0 (block protect) - * - CMP: complement protect - only support CMP=0 (range is not complemented) - * - * Support for the following is provided conditionally for some flash: - * - TB: top/bottom protect - * - * Sample table portion for 8MB flash (Winbond w25q64fw): - * - * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion - * -------------------------------------------------------------------------- - * X | X | 0 | 0 | 0 | NONE | NONE - * 0 | 0 | 0 | 0 | 1 | 128 KB | Upper 1/64 - * 0 | 0 | 0 | 1 | 0 | 256 KB | Upper 1/32 - * 0 | 0 | 0 | 1 | 1 | 512 KB | Upper 1/16 - * 0 | 0 | 1 | 0 | 0 | 1 MB | Upper 1/8 - * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4 - * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2 - * X | X | 1 | 1 | 1 | 8 MB | ALL - * ------|-------|-------|-------|-------|---------------|------------------- - * 0 | 1 | 0 | 0 | 1 | 128 KB | Lower 1/64 - * 0 | 1 | 0 | 1 | 0 | 256 KB | Lower 1/32 - * 0 | 1 | 0 | 1 | 1 | 512 KB | Lower 1/16 - * 0 | 1 | 1 | 0 | 0 | 1 MB | Lower 1/8 - * 0 | 1 | 1 | 0 | 1 | 2 MB | Lower 1/4 - * 0 | 1 | 1 | 1 | 0 | 4 MB | Lower 1/2 - * - * Returns negative on errors, 0 on success. - */ -static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) -{ - struct mtd_info *mtd = &nor->mtd; - u64 min_prot_len; - int ret, status_old, status_new; - u8 mask = spi_nor_get_sr_bp_mask(nor); - u8 tb_mask = spi_nor_get_sr_tb_mask(nor); - u8 pow, val; - loff_t lock_len; - bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; - bool use_top; - - ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - status_old = nor->bouncebuf[0]; - - /* If nothing in our range is unlocked, we don't need to do anything */ - if (spi_nor_is_locked_sr(nor, ofs, len, status_old)) - return 0; - - /* If anything below us is unlocked, we can't use 'bottom' protection */ - if (!spi_nor_is_locked_sr(nor, 0, ofs, status_old)) - can_be_bottom = false; - - /* If anything above us is unlocked, we can't use 'top' protection */ - if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len), - status_old)) - can_be_top = false; - - if (!can_be_bottom && !can_be_top) - return -EINVAL; - - /* Prefer top, if both are valid */ - use_top = can_be_top; - - /* lock_len: length of region that should end up locked */ - if (use_top) - lock_len = mtd->size - ofs; - else - lock_len = ofs + len; - - if (lock_len == mtd->size) { - val = mask; - } else { - min_prot_len = spi_nor_get_min_prot_length_sr(nor); - pow = ilog2(lock_len) - ilog2(min_prot_len) + 1; - val = pow << SR_BP_SHIFT; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3) - val = (val & ~SR_BP3) | SR_BP3_BIT6; - - if (val & ~mask) - return -EINVAL; - - /* Don't "lock" with no region! */ - if (!(val & mask)) - return -EINVAL; - } - - status_new = (status_old & ~mask & ~tb_mask) | val; - - /* Disallow further writes if WP pin is asserted */ - status_new |= SR_SRWD; - - if (!use_top) - status_new |= tb_mask; - - /* Don't bother if they're the same */ - if (status_new == status_old) - return 0; - - /* Only modify protection if it will not unlock other areas */ - if ((status_new & mask) < (status_old & mask)) - return -EINVAL; - - return spi_nor_write_sr_and_check(nor, status_new); -} - -/* - * Unlock a region of the flash. See spi_nor_sr_lock() for more info - * - * Returns negative on errors, 0 on success. - */ -static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) -{ - struct mtd_info *mtd = &nor->mtd; - u64 min_prot_len; - int ret, status_old, status_new; - u8 mask = spi_nor_get_sr_bp_mask(nor); - u8 tb_mask = spi_nor_get_sr_tb_mask(nor); - u8 pow, val; - loff_t lock_len; - bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; - bool use_top; - - ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - status_old = nor->bouncebuf[0]; - - /* If nothing in our range is locked, we don't need to do anything */ - if (spi_nor_is_unlocked_sr(nor, ofs, len, status_old)) - return 0; - - /* If anything below us is locked, we can't use 'top' protection */ - if (!spi_nor_is_unlocked_sr(nor, 0, ofs, status_old)) - can_be_top = false; - - /* If anything above us is locked, we can't use 'bottom' protection */ - if (!spi_nor_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len), - status_old)) - can_be_bottom = false; - - if (!can_be_bottom && !can_be_top) - return -EINVAL; - - /* Prefer top, if both are valid */ - use_top = can_be_top; - - /* lock_len: length of region that should remain locked */ - if (use_top) - lock_len = mtd->size - (ofs + len); - else - lock_len = ofs; - - if (lock_len == 0) { - val = 0; /* fully unlocked */ - } else { - min_prot_len = spi_nor_get_min_prot_length_sr(nor); - pow = ilog2(lock_len) - ilog2(min_prot_len) + 1; - val = pow << SR_BP_SHIFT; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3) - val = (val & ~SR_BP3) | SR_BP3_BIT6; - - /* Some power-of-two sizes are not supported */ - if (val & ~mask) - return -EINVAL; - } - - status_new = (status_old & ~mask & ~tb_mask) | val; - - /* Don't protect status register if we're fully unlocked */ - if (lock_len == 0) - status_new &= ~SR_SRWD; - - if (!use_top) - status_new |= tb_mask; - - /* Don't bother if they're the same */ - if (status_new == status_old) - return 0; - - /* Only modify protection if it will not lock other areas */ - if ((status_new & mask) > (status_old & mask)) - return -EINVAL; - - return spi_nor_write_sr_and_check(nor, status_new); -} - -/* - * Check if a region of the flash is (completely) locked. See spi_nor_sr_lock() - * for more info. - * - * Returns 1 if entire region is locked, 0 if any portion is unlocked, and - * negative on errors. - */ -static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) -{ - int ret; - - ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - return spi_nor_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]); -} - -static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = { - .lock = spi_nor_sr_lock, - .unlock = spi_nor_sr_unlock, - .is_locked = spi_nor_sr_is_locked, -}; - -static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; - - ret = spi_nor_lock_and_prep(nor); - if (ret) - return ret; - - ret = nor->params->locking_ops->lock(nor, ofs, len); - - spi_nor_unlock_and_unprep(nor); - return ret; -} - -static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; - - ret = spi_nor_lock_and_prep(nor); - if (ret) - return ret; - - ret = nor->params->locking_ops->unlock(nor, ofs, len); - - spi_nor_unlock_and_unprep(nor); - return ret; -} - -static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; - - ret = spi_nor_lock_and_prep(nor); - if (ret) - return ret; - - ret = nor->params->locking_ops->is_locked(nor, ofs, len); - - spi_nor_unlock_and_unprep(nor); - return ret; -} - /** * spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status * Register 1. @@ -2336,11 +1969,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, * If page_size is a power of two, the offset can be quickly * calculated with an AND operation. On the other cases we * need to do a modulus operation (more expensive). - * Power of two numbers have only one bit set and we can use - * the instruction hweight32 to detect if we need to do a - * modulus (do_div()) or not. */ - if (hweight32(nor->page_size) == 1) { + if (is_power_of_2(nor->page_size)) { page_offset = addr & (nor->page_size - 1); } else { uint64_t aux = addr; @@ -2626,22 +2256,20 @@ void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map, int spi_nor_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { int ret; if (nor->manufacturer && nor->manufacturer->fixups && nor->manufacturer->fixups->post_bfpt) { ret = nor->manufacturer->fixups->post_bfpt(nor, bfpt_header, - bfpt, params); + bfpt); if (ret) return ret; } if (nor->info->fixups && nor->info->fixups->post_bfpt) - return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt, - params); + return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt); return 0; } @@ -2896,7 +2524,7 @@ static void spi_nor_sfdp_init_params(struct spi_nor *nor) memcpy(&sfdp_params, nor->params, sizeof(sfdp_params)); - if (spi_nor_parse_sfdp(nor, nor->params)) { + if (spi_nor_parse_sfdp(nor)) { memcpy(nor->params, &sfdp_params, sizeof(*nor->params)); nor->addr_width = 0; nor->flags &= ~SNOR_F_4B_OPCODES; @@ -2916,10 +2544,12 @@ static void spi_nor_info_init_params(struct spi_nor *nor) struct device_node *np = spi_nor_get_flash_node(nor); u8 i, erase_mask; - /* Initialize legacy flash parameters and settings. */ + /* Initialize default flash parameters and settings. */ params->quad_enable = spi_nor_sr2_bit1_quad_enable; params->set_4byte_addr_mode = spansion_set_4byte_addr_mode; params->setup = spi_nor_default_setup; + params->otp.org = &info->otp_org; + /* Default to 16-bit Write Status (01h) Command */ nor->flags |= SNOR_F_HAS_16BIT_SR; @@ -3048,7 +2678,7 @@ static void spi_nor_late_init_params(struct spi_nor *nor) * the default ones. */ if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops) - nor->params->locking_ops = &spi_nor_sr_locking_ops; + spi_nor_init_default_locking_ops(nor); } /** @@ -3160,32 +2790,6 @@ static int spi_nor_quad_enable(struct spi_nor *nor) return nor->params->quad_enable(nor); } -/** - * spi_nor_try_unlock_all() - Tries to unlock the entire flash memory array. - * @nor: pointer to a 'struct spi_nor'. - * - * Some SPI NOR flashes are write protected by default after a power-on reset - * cycle, in order to avoid inadvertent writes during power-up. Backward - * compatibility imposes to unlock the entire flash memory array at power-up - * by default. - * - * Unprotecting the entire flash array will fail for boards which are hardware - * write-protected. Thus any errors are ignored. - */ -static void spi_nor_try_unlock_all(struct spi_nor *nor) -{ - int ret; - - if (!(nor->flags & SNOR_F_HAS_LOCK)) - return; - - dev_dbg(nor->dev, "Unprotecting entire flash array\n"); - - ret = spi_nor_unlock(&nor->mtd, 0, nor->params->size); - if (ret) - dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n"); -} - static int spi_nor_init(struct spi_nor *nor) { int err; @@ -3301,6 +2905,37 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } +static int spi_nor_get_device(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + struct spi_nor *nor = mtd_to_spi_nor(master); + struct device *dev; + + if (nor->spimem) + dev = nor->spimem->spi->controller->dev.parent; + else + dev = nor->dev; + + if (!try_module_get(dev->driver->owner)) + return -ENODEV; + + return 0; +} + +static void spi_nor_put_device(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + struct spi_nor *nor = mtd_to_spi_nor(master); + struct device *dev; + + if (nor->spimem) + dev = nor->spimem->spi->controller->dev.parent; + else + dev = nor->dev; + + module_put(dev->driver->owner); +} + void spi_nor_restore(struct spi_nor *nor) { /* restore the addressing mode */ @@ -3495,12 +3130,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->_read = spi_nor_read; mtd->_suspend = spi_nor_suspend; mtd->_resume = spi_nor_resume; - - if (nor->params->locking_ops) { - mtd->_lock = spi_nor_lock; - mtd->_unlock = spi_nor_unlock; - mtd->_is_locked = spi_nor_is_locked; - } + mtd->_get_device = spi_nor_get_device; + mtd->_put_device = spi_nor_put_device; if (info->flags & USE_FSR) nor->flags |= SNOR_F_USE_FSR; @@ -3553,11 +3184,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; + spi_nor_register_locking_ops(nor); + /* Send all the required SPI flash commands to initialize device */ ret = spi_nor_init(nor); if (ret) return ret; + /* Configure OTP parameters and ops */ + spi_nor_otp_init(nor); + dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 4a3f7f150b5d677f74c97153af659f1185587341..28a2e0be97a3b6405cafc6dd4a0eca700574f1be 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -187,6 +187,46 @@ struct spi_nor_locking_ops { int (*is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len); }; +/** + * struct spi_nor_otp_organization - Structure to describe the SPI NOR OTP regions + * @len: size of one OTP region in bytes. + * @base: start address of the OTP area. + * @offset: offset between consecutive OTP regions if there are more + * than one. + * @n_regions: number of individual OTP regions. + */ +struct spi_nor_otp_organization { + size_t len; + loff_t base; + loff_t offset; + unsigned int n_regions; +}; + +/** + * struct spi_nor_otp_ops - SPI NOR OTP methods + * @read: read from the SPI NOR OTP area. + * @write: write to the SPI NOR OTP area. + * @lock: lock an OTP region. + * @is_locked: check if an OTP region of the SPI NOR is locked. + */ +struct spi_nor_otp_ops { + int (*read)(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf); + int (*write)(struct spi_nor *nor, loff_t addr, size_t len, + const u8 *buf); + int (*lock)(struct spi_nor *nor, unsigned int region); + int (*is_locked)(struct spi_nor *nor, unsigned int region); +}; + +/** + * struct spi_nor_otp - SPI NOR OTP grouping structure + * @org: OTP region organization + * @ops: OTP access ops + */ +struct spi_nor_otp { + const struct spi_nor_otp_organization *org; + const struct spi_nor_otp_ops *ops; +}; + /** * struct spi_nor_flash_parameter - SPI NOR flash parameters and settings. * Includes legacy flash parameters and settings that can be overwritten @@ -208,6 +248,7 @@ struct spi_nor_locking_ops { * higher index in the array, the higher priority. * @erase_map: the erase map parsed from the SFDP Sector Map Parameter * Table. + * @otp_info: describes the OTP regions. * @octal_dtr_enable: enables SPI NOR octal DTR mode. * @quad_enable: enables SPI NOR quad mode. * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode. @@ -219,6 +260,7 @@ struct spi_nor_locking_ops { * e.g. different opcodes, specific address calculation, * page size, etc. * @locking_ops: SPI NOR locking methods. + * @otp: SPI NOR OTP methods. */ struct spi_nor_flash_parameter { u64 size; @@ -232,6 +274,7 @@ struct spi_nor_flash_parameter { struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX]; struct spi_nor_erase_map erase_map; + struct spi_nor_otp otp; int (*octal_dtr_enable)(struct spi_nor *nor, bool enable); int (*quad_enable)(struct spi_nor *nor); @@ -261,8 +304,7 @@ struct spi_nor_fixups { void (*default_init)(struct spi_nor *nor); int (*post_bfpt)(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params); + const struct sfdp_bfpt *bfpt); void (*post_sfdp)(struct spi_nor *nor); }; @@ -339,6 +381,8 @@ struct flash_info { * power-up in a write-protected state. */ + const struct spi_nor_otp_organization otp_org; + /* Part specific fixup hooks. */ const struct spi_nor_fixups *fixups; }; @@ -393,6 +437,14 @@ struct flash_info { .addr_width = 3, \ .flags = SPI_NOR_NO_FR | SPI_NOR_XSR_RDY, +#define OTP_INFO(_len, _n_regions, _base, _offset) \ + .otp_org = { \ + .len = (_len), \ + .base = (_base), \ + .offset = (_offset), \ + .n_regions = (_n_regions), \ + }, + /** * struct spi_nor_manufacturer - SPI NOR manufacturer object * @name: manufacturer name @@ -444,6 +496,7 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr); int spi_nor_read_cr(struct spi_nor *nor, u8 *cr); int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len); int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1); +int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr); int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr); ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, @@ -451,6 +504,12 @@ ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, const u8 *buf); +int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf); +int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len, + const u8 *buf); +int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region); +int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region); + int spi_nor_hwcaps_read2cmd(u32 hwcaps); u8 spi_nor_convert_3to4_read(u8 opcode); void spi_nor_set_read_settings(struct spi_nor_read_command *read, @@ -470,8 +529,12 @@ void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map, int spi_nor_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params); + const struct sfdp_bfpt *bfpt); + +void spi_nor_init_default_locking_ops(struct spi_nor *nor); +void spi_nor_try_unlock_all(struct spi_nor *nor); +void spi_nor_register_locking_ops(struct spi_nor *nor); +void spi_nor_otp_init(struct spi_nor *nor); static struct spi_nor __maybe_unused *mtd_to_spi_nor(struct mtd_info *mtd) { diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c index ffcb60e54a804071d9f7a93c478331f9f8ae6f7f..1e5bb5408b6835c56eff58cced8bfdc99c241547 100644 --- a/drivers/mtd/spi-nor/issi.c +++ b/drivers/mtd/spi-nor/issi.c @@ -11,8 +11,7 @@ static int is25lp256_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { /* * IS25LP256 supports 4B opcodes, but the BFPT advertises a diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 9203abaac2297c94af83d392c138369772c9959f..42c2cf31702e9d3bd4e0aea821538a6e8051f259 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -11,8 +11,7 @@ static int mx25l25635_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { /* * MX25L25635F supports 4B opcodes but MX25L25635E does not. @@ -73,9 +72,6 @@ static const struct flash_info macronix_parts[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx25l51245g", INFO(0xc2201a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_4B_OPCODES) }, { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, diff --git a/drivers/mtd/spi-nor/otp.c b/drivers/mtd/spi-nor/otp.c new file mode 100644 index 0000000000000000000000000000000000000000..fcf38d26034500e6d3eb7b401d90ce1b74f3fa63 --- /dev/null +++ b/drivers/mtd/spi-nor/otp.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OTP support for SPI NOR flashes + * + * Copyright (C) 2021 Michael Walle <michael@walle.cc> + */ + +#include <linux/log2.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/spi-nor.h> + +#include "core.h" + +#define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len) +#define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions) + +/** + * spi_nor_otp_read_secr() - read OTP data + * @nor: pointer to 'struct spi_nor' + * @from: offset to read from + * @len: number of bytes to read + * @buf: pointer to dst buffer + * + * Read OTP data from one region by using the SPINOR_OP_RSECR commands. This + * method is used on GigaDevice and Winbond flashes. + * + * Return: number of bytes read successfully, -errno otherwise + */ +int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf) +{ + u8 addr_width, read_opcode, read_dummy; + struct spi_mem_dirmap_desc *rdesc; + enum spi_nor_protocol read_proto; + int ret; + + read_opcode = nor->read_opcode; + addr_width = nor->addr_width; + read_dummy = nor->read_dummy; + read_proto = nor->read_proto; + rdesc = nor->dirmap.rdesc; + + nor->read_opcode = SPINOR_OP_RSECR; + nor->addr_width = 3; + nor->read_dummy = 8; + nor->read_proto = SNOR_PROTO_1_1_1; + nor->dirmap.rdesc = NULL; + + ret = spi_nor_read_data(nor, addr, len, buf); + + nor->read_opcode = read_opcode; + nor->addr_width = addr_width; + nor->read_dummy = read_dummy; + nor->read_proto = read_proto; + nor->dirmap.rdesc = rdesc; + + return ret; +} + +/** + * spi_nor_otp_write_secr() - write OTP data + * @nor: pointer to 'struct spi_nor' + * @to: offset to write to + * @len: number of bytes to write + * @buf: pointer to src buffer + * + * Write OTP data to one region by using the SPINOR_OP_PSECR commands. This + * method is used on GigaDevice and Winbond flashes. + * + * Please note, the write must not span multiple OTP regions. + * + * Return: number of bytes written successfully, -errno otherwise + */ +int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len, + const u8 *buf) +{ + enum spi_nor_protocol write_proto; + struct spi_mem_dirmap_desc *wdesc; + u8 addr_width, program_opcode; + int ret, written; + + program_opcode = nor->program_opcode; + addr_width = nor->addr_width; + write_proto = nor->write_proto; + wdesc = nor->dirmap.wdesc; + + nor->program_opcode = SPINOR_OP_PSECR; + nor->addr_width = 3; + nor->write_proto = SNOR_PROTO_1_1_1; + nor->dirmap.wdesc = NULL; + + /* + * We only support a write to one single page. For now all winbond + * flashes only have one page per OTP region. + */ + ret = spi_nor_write_enable(nor); + if (ret) + goto out; + + written = spi_nor_write_data(nor, addr, len, buf); + if (written < 0) + goto out; + + ret = spi_nor_wait_till_ready(nor); + +out: + nor->program_opcode = program_opcode; + nor->addr_width = addr_width; + nor->write_proto = write_proto; + nor->dirmap.wdesc = wdesc; + + return ret ?: written; +} + +static int spi_nor_otp_lock_bit_cr(unsigned int region) +{ + static const int lock_bits[] = { SR2_LB1, SR2_LB2, SR2_LB3 }; + + if (region >= ARRAY_SIZE(lock_bits)) + return -EINVAL; + + return lock_bits[region]; +} + +/** + * spi_nor_otp_lock_sr2() - lock the OTP region + * @nor: pointer to 'struct spi_nor' + * @region: OTP region + * + * Lock the OTP region by writing the status register-2. This method is used on + * GigaDevice and Winbond flashes. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region) +{ + u8 *cr = nor->bouncebuf; + int ret, lock_bit; + + lock_bit = spi_nor_otp_lock_bit_cr(region); + if (lock_bit < 0) + return lock_bit; + + ret = spi_nor_read_cr(nor, cr); + if (ret) + return ret; + + /* no need to write the register if region is already locked */ + if (cr[0] & lock_bit) + return 0; + + cr[0] |= lock_bit; + + return spi_nor_write_16bit_cr_and_check(nor, cr[0]); +} + +/** + * spi_nor_otp_is_locked_sr2() - get the OTP region lock status + * @nor: pointer to 'struct spi_nor' + * @region: OTP region + * + * Retrieve the OTP region lock bit by reading the status register-2. This + * method is used on GigaDevice and Winbond flashes. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region) +{ + u8 *cr = nor->bouncebuf; + int ret, lock_bit; + + lock_bit = spi_nor_otp_lock_bit_cr(region); + if (lock_bit < 0) + return lock_bit; + + ret = spi_nor_read_cr(nor, cr); + if (ret) + return ret; + + return cr[0] & lock_bit; +} + +static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region) +{ + const struct spi_nor_otp_organization *org = nor->params->otp.org; + + return org->base + region * org->offset; +} + +static size_t spi_nor_otp_size(struct spi_nor *nor) +{ + return spi_nor_otp_n_regions(nor) * spi_nor_otp_region_len(nor); +} + +/* Translate the file offsets from and to OTP regions. */ +static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsigned int region) +{ + return region * spi_nor_otp_region_len(nor); +} + +static unsigned int spi_nor_otp_offset_to_region(struct spi_nor *nor, loff_t ofs) +{ + return div64_u64(ofs, spi_nor_otp_region_len(nor)); +} + +static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + const struct spi_nor_otp_ops *ops = nor->params->otp.ops; + unsigned int n_regions = spi_nor_otp_n_regions(nor); + unsigned int i; + int ret, locked; + + if (len < n_regions * sizeof(*buf)) + return -ENOSPC; + + ret = spi_nor_lock_and_prep(nor); + if (ret) + return ret; + + for (i = 0; i < n_regions; i++) { + buf->start = spi_nor_otp_region_to_offset(nor, i); + buf->length = spi_nor_otp_region_len(nor); + + locked = ops->is_locked(nor, i); + if (locked < 0) { + ret = locked; + goto out; + } + + buf->locked = !!locked; + buf++; + } + + *retlen = n_regions * sizeof(*buf); + +out: + spi_nor_unlock_and_unprep(nor); + + return ret; +} + +static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs, + size_t total_len, size_t *retlen, + const u8 *buf, bool is_write) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + const struct spi_nor_otp_ops *ops = nor->params->otp.ops; + const size_t rlen = spi_nor_otp_region_len(nor); + loff_t rstart, rofs; + unsigned int region; + size_t len; + int ret; + + if (ofs < 0 || ofs >= spi_nor_otp_size(nor)) + return 0; + + ret = spi_nor_lock_and_prep(nor); + if (ret) + return ret; + + /* don't access beyond the end */ + total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs); + + *retlen = 0; + while (total_len) { + /* + * The OTP regions are mapped into a contiguous area starting + * at 0 as expected by the MTD layer. This will map the MTD + * file offsets to the address of an OTP region as used in the + * actual SPI commands. + */ + region = spi_nor_otp_offset_to_region(nor, ofs); + rstart = spi_nor_otp_region_start(nor, region); + + /* + * The size of a OTP region is expected to be a power of two, + * thus we can just mask the lower bits and get the offset into + * a region. + */ + rofs = ofs & (rlen - 1); + + /* don't access beyond one OTP region */ + len = min_t(size_t, total_len, rlen - rofs); + + if (is_write) + ret = ops->write(nor, rstart + rofs, len, buf); + else + ret = ops->read(nor, rstart + rofs, len, (u8 *)buf); + if (ret == 0) + ret = -EIO; + if (ret < 0) + goto out; + + *retlen += ret; + ofs += ret; + buf += ret; + total_len -= ret; + } + ret = 0; + +out: + spi_nor_unlock_and_unprep(nor); + return ret; +} + +static int spi_nor_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u8 *buf) +{ + return spi_nor_mtd_otp_read_write(mtd, from, len, retlen, buf, false); +} + +static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u8 *buf) +{ + return spi_nor_mtd_otp_read_write(mtd, to, len, retlen, buf, true); +} + +static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + const struct spi_nor_otp_ops *ops = nor->params->otp.ops; + const size_t rlen = spi_nor_otp_region_len(nor); + unsigned int region; + int ret; + + if (from < 0 || (from + len) > spi_nor_otp_size(nor)) + return -EINVAL; + + /* the user has to explicitly ask for whole regions */ + if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen)) + return -EINVAL; + + ret = spi_nor_lock_and_prep(nor); + if (ret) + return ret; + + while (len) { + region = spi_nor_otp_offset_to_region(nor, from); + ret = ops->lock(nor, region); + if (ret) + goto out; + + len -= rlen; + from += rlen; + } + +out: + spi_nor_unlock_and_unprep(nor); + + return ret; +} + +void spi_nor_otp_init(struct spi_nor *nor) +{ + struct mtd_info *mtd = &nor->mtd; + + if (!nor->params->otp.ops) + return; + + if (WARN_ON(!is_power_of_2(spi_nor_otp_region_len(nor)))) + return; + + /* + * We only support user_prot callbacks (yet). + * + * Some SPI NOR flashes like Macronix ones can be ordered in two + * different variants. One with a factory locked OTP area and one where + * it is left to the user to write to it. The factory locked OTP is + * usually preprogrammed with an "electrical serial number". We don't + * support these for now. + */ + mtd->_get_user_prot_info = spi_nor_mtd_otp_info; + mtd->_read_user_prot_reg = spi_nor_mtd_otp_read; + mtd->_write_user_prot_reg = spi_nor_mtd_otp_write; + mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock; +} diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 25142ec4737b79f49cd40f101ad34b8184d183e9..23c28e91f698ea9be4ae5da8214b66af4c22e5b8 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -405,8 +405,6 @@ static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map) * @nor: pointer to a 'struct spi_nor' * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing * the Basic Flash Parameter Table length and version - * @params: pointer to the 'struct spi_nor_flash_parameter' to be - * filled * * The Basic Flash Parameter Table is the main and only mandatory table as * defined by the SFDP (JESD216) specification. @@ -431,9 +429,9 @@ static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map) * Return: 0 on success, -errno otherwise. */ static int spi_nor_parse_bfpt(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - struct spi_nor_flash_parameter *params) + const struct sfdp_parameter_header *bfpt_header) { + struct spi_nor_flash_parameter *params = nor->params; struct spi_nor_erase_map *map = ¶ms->erase_map; struct spi_nor_erase_type *erase_type = map->erase_type; struct sfdp_bfpt bfpt; @@ -552,8 +550,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, /* Stop here if not JESD216 rev A or later. */ if (bfpt_header->length == BFPT_DWORD_MAX_JESD216) - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, - params); + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt); /* Page size: this field specifies 'N' so the page size = 2^N bytes. */ val = bfpt.dwords[BFPT_DWORD(11)]; @@ -614,8 +611,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, /* Stop here if not JESD216 rev C or later. */ if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B) - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, - params); + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt); + /* 8D-8D-8D command extension. */ switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) { case BFPT_DWORD18_CMD_EXT_REP: @@ -635,7 +632,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, return -EOPNOTSUPP; } - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params); + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt); } /** @@ -800,18 +797,14 @@ spi_nor_region_check_overlay(struct spi_nor_erase_region *region, /** * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map * @nor: pointer to a 'struct spi_nor' - * @params: pointer to a duplicate 'struct spi_nor_flash_parameter' that is - * used for storing SFDP parsed data * @smpt: pointer to the sector map parameter table * * Return: 0 on success, -errno otherwise. */ -static int -spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, - struct spi_nor_flash_parameter *params, - const u32 *smpt) +static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, + const u32 *smpt) { - struct spi_nor_erase_map *map = ¶ms->erase_map; + struct spi_nor_erase_map *map = &nor->params->erase_map; struct spi_nor_erase_type *erase = map->erase_type; struct spi_nor_erase_region *region; u64 offset; @@ -889,8 +882,6 @@ spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, * spi_nor_parse_smpt() - parse Sector Map Parameter Table * @nor: pointer to a 'struct spi_nor' * @smpt_header: sector map parameter table header - * @params: pointer to a duplicate 'struct spi_nor_flash_parameter' - * that is used for storing SFDP parsed data * * This table is optional, but when available, we parse it to identify the * location and size of sectors within the main data array of the flash memory @@ -899,8 +890,7 @@ spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, * Return: 0 on success, -errno otherwise. */ static int spi_nor_parse_smpt(struct spi_nor *nor, - const struct sfdp_parameter_header *smpt_header, - struct spi_nor_flash_parameter *params) + const struct sfdp_parameter_header *smpt_header) { const u32 *sector_map; u32 *smpt; @@ -928,11 +918,11 @@ static int spi_nor_parse_smpt(struct spi_nor *nor, goto out; } - ret = spi_nor_init_non_uniform_erase_map(nor, params, sector_map); + ret = spi_nor_init_non_uniform_erase_map(nor, sector_map); if (ret) goto out; - spi_nor_regions_sort_erase_types(¶ms->erase_map); + spi_nor_regions_sort_erase_types(&nor->params->erase_map); /* fall through */ out: kfree(smpt); @@ -944,13 +934,11 @@ out: * @nor: pointer to a 'struct spi_nor'. * @param_header: pointer to the 'struct sfdp_parameter_header' describing * the 4-Byte Address Instruction Table length and version. - * @params: pointer to the 'struct spi_nor_flash_parameter' to be. * * Return: 0 on success, -errno otherwise. */ static int spi_nor_parse_4bait(struct spi_nor *nor, - const struct sfdp_parameter_header *param_header, - struct spi_nor_flash_parameter *params) + const struct sfdp_parameter_header *param_header) { static const struct sfdp_4bait reads[] = { { SNOR_HWCAPS_READ, BIT(0) }, @@ -974,6 +962,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, { 0u /* not used */, BIT(11) }, { 0u /* not used */, BIT(12) }, }; + struct spi_nor_flash_parameter *params = nor->params; struct spi_nor_pp_command *params_pp = params->page_programs; struct spi_nor_erase_map *map = ¶ms->erase_map; struct spi_nor_erase_type *erase_type = map->erase_type; @@ -1130,13 +1119,11 @@ out: * @nor: pointer to a 'struct spi_nor' * @profile1_header: pointer to the 'struct sfdp_parameter_header' describing * the Profile 1.0 Table length and version. - * @params: pointer to the 'struct spi_nor_flash_parameter' to be. * * Return: 0 on success, -errno otherwise. */ static int spi_nor_parse_profile1(struct spi_nor *nor, - const struct sfdp_parameter_header *profile1_header, - struct spi_nor_flash_parameter *params) + const struct sfdp_parameter_header *profile1_header) { u32 *dwords, addr; size_t len; @@ -1160,14 +1147,14 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, /* Set the Read Status Register dummy cycles and dummy address bytes. */ if (dwords[0] & PROFILE1_DWORD1_RDSR_DUMMY) - params->rdsr_dummy = 8; + nor->params->rdsr_dummy = 8; else - params->rdsr_dummy = 4; + nor->params->rdsr_dummy = 4; if (dwords[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES) - params->rdsr_addr_nbytes = 4; + nor->params->rdsr_addr_nbytes = 4; else - params->rdsr_addr_nbytes = 0; + nor->params->rdsr_addr_nbytes = 0; /* * We don't know what speed the controller is running at. Find the @@ -1193,7 +1180,7 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, dummy = round_up(dummy, 2); /* Update the fast read settings. */ - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR], 0, dummy, opcode, SNOR_PROTO_8_8_8_DTR); @@ -1210,13 +1197,11 @@ out: * @nor: pointer to a 'struct spi_nor' * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing * the SCCR Map table length and version. - * @params: pointer to the 'struct spi_nor_flash_parameter' to be. * * Return: 0 on success, -errno otherwise. */ static int spi_nor_parse_sccr(struct spi_nor *nor, - const struct sfdp_parameter_header *sccr_header, - struct spi_nor_flash_parameter *params) + const struct sfdp_parameter_header *sccr_header) { u32 *dwords, addr; size_t len; @@ -1245,8 +1230,6 @@ out: /** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' - * @params: pointer to the 'struct spi_nor_flash_parameter' to be - * filled * * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216 * specification. This is a standard which tends to supported by almost all @@ -1256,8 +1239,7 @@ out: * * Return: 0 on success, -errno otherwise. */ -int spi_nor_parse_sfdp(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) +int spi_nor_parse_sfdp(struct spi_nor *nor) { const struct sfdp_parameter_header *param_header, *bfpt_header; struct sfdp_parameter_header *param_headers = NULL; @@ -1326,7 +1308,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor, bfpt_header = param_header; } - err = spi_nor_parse_bfpt(nor, bfpt_header, params); + err = spi_nor_parse_bfpt(nor, bfpt_header); if (err) goto exit; @@ -1336,19 +1318,19 @@ int spi_nor_parse_sfdp(struct spi_nor *nor, switch (SFDP_PARAM_HEADER_ID(param_header)) { case SFDP_SECTOR_MAP_ID: - err = spi_nor_parse_smpt(nor, param_header, params); + err = spi_nor_parse_smpt(nor, param_header); break; case SFDP_4BAIT_ID: - err = spi_nor_parse_4bait(nor, param_header, params); + err = spi_nor_parse_4bait(nor, param_header); break; case SFDP_PROFILE1_ID: - err = spi_nor_parse_profile1(nor, param_header, params); + err = spi_nor_parse_profile1(nor, param_header); break; case SFDP_SCCR_MAP_ID: - err = spi_nor_parse_sccr(nor, param_header, params); + err = spi_nor_parse_sccr(nor, param_header); break; default: diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h index 89152ae1cf3e28bb007e368290cf0cbb0293b09e..bbf80d2990ab6b5bfacd1af374b2dfd5a398d793 100644 --- a/drivers/mtd/spi-nor/sfdp.h +++ b/drivers/mtd/spi-nor/sfdp.h @@ -107,7 +107,6 @@ struct sfdp_parameter_header { u8 id_msb; }; -int spi_nor_parse_sfdp(struct spi_nor *nor, - struct spi_nor_flash_parameter *params); +int spi_nor_parse_sfdp(struct spi_nor *nor); #endif /* __LINUX_MTD_SFDP_H */ diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index b0c5521c1e278cd42fb700d4a5223b46e78a4604..ee82dcd75310c52b24f0524b620504cf38af5176 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -142,8 +142,7 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { /* * The BFPT table advertises a 512B page size but the page size is @@ -162,9 +161,9 @@ static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, return ret; if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3V_PGSZ) - params->page_size = 512; + nor->params->page_size = 512; else - params->page_size = 256; + nor->params->page_size = 256; return 0; } @@ -178,8 +177,7 @@ static struct spi_nor_fixups s28hs512t_fixups = { static int s25fs_s_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { /* * The S25FS-S chip family reports 512-byte pages in BFPT but @@ -187,7 +185,7 @@ s25fs_s_post_bfpt_fixups(struct spi_nor *nor, * of 256 bytes. Overwrite the page size advertised by BFPT * to get the writes working. */ - params->page_size = 256; + nor->params->page_size = 256; return 0; } diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c new file mode 100644 index 0000000000000000000000000000000000000000..8594bcbb7dbe0596e9a397eb5f772c2a99df17a2 --- /dev/null +++ b/drivers/mtd/spi-nor/swp.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SPI NOR Software Write Protection logic. + * + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + */ +#include <linux/mtd/mtd.h> +#include <linux/mtd/spi-nor.h> + +#include "core.h" + +static u8 spi_nor_get_sr_bp_mask(struct spi_nor *nor) +{ + u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + + if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6) + return mask | SR_BP3_BIT6; + + if (nor->flags & SNOR_F_HAS_4BIT_BP) + return mask | SR_BP3; + + return mask; +} + +static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) +{ + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; + else + return SR_TB_BIT5; +} + +static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +{ + unsigned int bp_slots, bp_slots_needed; + u8 mask = spi_nor_get_sr_bp_mask(nor); + + /* Reserved one for "protect none" and one for "protect all". */ + bp_slots = (1 << hweight8(mask)) - 2; + bp_slots_needed = ilog2(nor->info->n_sectors); + + if (bp_slots_needed > bp_slots) + return nor->info->sector_size << + (bp_slots_needed - bp_slots); + else + return nor->info->sector_size; +} + +static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs, + uint64_t *len) +{ + struct mtd_info *mtd = &nor->mtd; + u64 min_prot_len; + u8 mask = spi_nor_get_sr_bp_mask(nor); + u8 tb_mask = spi_nor_get_sr_tb_mask(nor); + u8 bp, val = sr & mask; + + if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6) + val = (val & ~SR_BP3_BIT6) | SR_BP3; + + bp = val >> SR_BP_SHIFT; + + if (!bp) { + /* No protection */ + *ofs = 0; + *len = 0; + return; + } + + min_prot_len = spi_nor_get_min_prot_length_sr(nor); + *len = min_prot_len << (bp - 1); + + if (*len > mtd->size) + *len = mtd->size; + + if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask) + *ofs = 0; + else + *ofs = mtd->size - *len; +} + +/* + * Return true if the entire region is locked (if @locked is true) or unlocked + * (if @locked is false); false otherwise. + */ +static bool spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, + uint64_t len, u8 sr, bool locked) +{ + loff_t lock_offs, lock_offs_max, offs_max; + uint64_t lock_len; + + if (!len) + return true; + + spi_nor_get_locked_range_sr(nor, sr, &lock_offs, &lock_len); + + lock_offs_max = lock_offs + lock_len; + offs_max = ofs + len; + + if (locked) + /* Requested range is a sub-range of locked range */ + return (offs_max <= lock_offs_max) && (ofs >= lock_offs); + else + /* Requested range does not overlap with locked range */ + return (ofs >= lock_offs_max) || (offs_max <= lock_offs); +} + +static bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, + u8 sr) +{ + return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true); +} + +static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, + uint64_t len, u8 sr) +{ + return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false); +} + +/* + * Lock a region of the flash. Compatible with ST Micro and similar flash. + * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status + * register + * (SR). Does not support these features found in newer SR bitfields: + * - SEC: sector/block protect - only handle SEC=0 (block protect) + * - CMP: complement protect - only support CMP=0 (range is not complemented) + * + * Support for the following is provided conditionally for some flash: + * - TB: top/bottom protect + * + * Sample table portion for 8MB flash (Winbond w25q64fw): + * + * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion + * -------------------------------------------------------------------------- + * X | X | 0 | 0 | 0 | NONE | NONE + * 0 | 0 | 0 | 0 | 1 | 128 KB | Upper 1/64 + * 0 | 0 | 0 | 1 | 0 | 256 KB | Upper 1/32 + * 0 | 0 | 0 | 1 | 1 | 512 KB | Upper 1/16 + * 0 | 0 | 1 | 0 | 0 | 1 MB | Upper 1/8 + * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4 + * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2 + * X | X | 1 | 1 | 1 | 8 MB | ALL + * ------|-------|-------|-------|-------|---------------|------------------- + * 0 | 1 | 0 | 0 | 1 | 128 KB | Lower 1/64 + * 0 | 1 | 0 | 1 | 0 | 256 KB | Lower 1/32 + * 0 | 1 | 0 | 1 | 1 | 512 KB | Lower 1/16 + * 0 | 1 | 1 | 0 | 0 | 1 MB | Lower 1/8 + * 0 | 1 | 1 | 0 | 1 | 2 MB | Lower 1/4 + * 0 | 1 | 1 | 1 | 0 | 4 MB | Lower 1/2 + * + * Returns negative on errors, 0 on success. + */ +static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + struct mtd_info *mtd = &nor->mtd; + u64 min_prot_len; + int ret, status_old, status_new; + u8 mask = spi_nor_get_sr_bp_mask(nor); + u8 tb_mask = spi_nor_get_sr_tb_mask(nor); + u8 pow, val; + loff_t lock_len; + bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; + bool use_top; + + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + status_old = nor->bouncebuf[0]; + + /* If nothing in our range is unlocked, we don't need to do anything */ + if (spi_nor_is_locked_sr(nor, ofs, len, status_old)) + return 0; + + /* If anything below us is unlocked, we can't use 'bottom' protection */ + if (!spi_nor_is_locked_sr(nor, 0, ofs, status_old)) + can_be_bottom = false; + + /* If anything above us is unlocked, we can't use 'top' protection */ + if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len), + status_old)) + can_be_top = false; + + if (!can_be_bottom && !can_be_top) + return -EINVAL; + + /* Prefer top, if both are valid */ + use_top = can_be_top; + + /* lock_len: length of region that should end up locked */ + if (use_top) + lock_len = mtd->size - ofs; + else + lock_len = ofs + len; + + if (lock_len == mtd->size) { + val = mask; + } else { + min_prot_len = spi_nor_get_min_prot_length_sr(nor); + pow = ilog2(lock_len) - ilog2(min_prot_len) + 1; + val = pow << SR_BP_SHIFT; + + if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3) + val = (val & ~SR_BP3) | SR_BP3_BIT6; + + if (val & ~mask) + return -EINVAL; + + /* Don't "lock" with no region! */ + if (!(val & mask)) + return -EINVAL; + } + + status_new = (status_old & ~mask & ~tb_mask) | val; + + /* Disallow further writes if WP pin is asserted */ + status_new |= SR_SRWD; + + if (!use_top) + status_new |= tb_mask; + + /* Don't bother if they're the same */ + if (status_new == status_old) + return 0; + + /* Only modify protection if it will not unlock other areas */ + if ((status_new & mask) < (status_old & mask)) + return -EINVAL; + + return spi_nor_write_sr_and_check(nor, status_new); +} + +/* + * Unlock a region of the flash. See spi_nor_sr_lock() for more info + * + * Returns negative on errors, 0 on success. + */ +static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + struct mtd_info *mtd = &nor->mtd; + u64 min_prot_len; + int ret, status_old, status_new; + u8 mask = spi_nor_get_sr_bp_mask(nor); + u8 tb_mask = spi_nor_get_sr_tb_mask(nor); + u8 pow, val; + loff_t lock_len; + bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; + bool use_top; + + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + status_old = nor->bouncebuf[0]; + + /* If nothing in our range is locked, we don't need to do anything */ + if (spi_nor_is_unlocked_sr(nor, ofs, len, status_old)) + return 0; + + /* If anything below us is locked, we can't use 'top' protection */ + if (!spi_nor_is_unlocked_sr(nor, 0, ofs, status_old)) + can_be_top = false; + + /* If anything above us is locked, we can't use 'bottom' protection */ + if (!spi_nor_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len), + status_old)) + can_be_bottom = false; + + if (!can_be_bottom && !can_be_top) + return -EINVAL; + + /* Prefer top, if both are valid */ + use_top = can_be_top; + + /* lock_len: length of region that should remain locked */ + if (use_top) + lock_len = mtd->size - (ofs + len); + else + lock_len = ofs; + + if (lock_len == 0) { + val = 0; /* fully unlocked */ + } else { + min_prot_len = spi_nor_get_min_prot_length_sr(nor); + pow = ilog2(lock_len) - ilog2(min_prot_len) + 1; + val = pow << SR_BP_SHIFT; + + if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3) + val = (val & ~SR_BP3) | SR_BP3_BIT6; + + /* Some power-of-two sizes are not supported */ + if (val & ~mask) + return -EINVAL; + } + + status_new = (status_old & ~mask & ~tb_mask) | val; + + /* Don't protect status register if we're fully unlocked */ + if (lock_len == 0) + status_new &= ~SR_SRWD; + + if (!use_top) + status_new |= tb_mask; + + /* Don't bother if they're the same */ + if (status_new == status_old) + return 0; + + /* Only modify protection if it will not lock other areas */ + if ((status_new & mask) > (status_old & mask)) + return -EINVAL; + + return spi_nor_write_sr_and_check(nor, status_new); +} + +/* + * Check if a region of the flash is (completely) locked. See spi_nor_sr_lock() + * for more info. + * + * Returns 1 if entire region is locked, 0 if any portion is unlocked, and + * negative on errors. + */ +static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + int ret; + + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + return spi_nor_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]); +} + +static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = { + .lock = spi_nor_sr_lock, + .unlock = spi_nor_sr_unlock, + .is_locked = spi_nor_sr_is_locked, +}; + +void spi_nor_init_default_locking_ops(struct spi_nor *nor) +{ + nor->params->locking_ops = &spi_nor_sr_locking_ops; +} + +static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor); + if (ret) + return ret; + + ret = nor->params->locking_ops->lock(nor, ofs, len); + + spi_nor_unlock_and_unprep(nor); + return ret; +} + +static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor); + if (ret) + return ret; + + ret = nor->params->locking_ops->unlock(nor, ofs, len); + + spi_nor_unlock_and_unprep(nor); + return ret; +} + +static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor); + if (ret) + return ret; + + ret = nor->params->locking_ops->is_locked(nor, ofs, len); + + spi_nor_unlock_and_unprep(nor); + return ret; +} + +/** + * spi_nor_try_unlock_all() - Tries to unlock the entire flash memory array. + * @nor: pointer to a 'struct spi_nor'. + * + * Some SPI NOR flashes are write protected by default after a power-on reset + * cycle, in order to avoid inadvertent writes during power-up. Backward + * compatibility imposes to unlock the entire flash memory array at power-up + * by default. + * + * Unprotecting the entire flash array will fail for boards which are hardware + * write-protected. Thus any errors are ignored. + */ +void spi_nor_try_unlock_all(struct spi_nor *nor) +{ + int ret; + + if (!(nor->flags & SNOR_F_HAS_LOCK)) + return; + + dev_dbg(nor->dev, "Unprotecting entire flash array\n"); + + ret = spi_nor_unlock(&nor->mtd, 0, nor->params->size); + if (ret) + dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n"); +} + +void spi_nor_register_locking_ops(struct spi_nor *nor) +{ + struct mtd_info *mtd = &nor->mtd; + + if (!nor->params->locking_ops) + return; + + mtd->_lock = spi_nor_lock; + mtd->_unlock = spi_nor_unlock; + mtd->_is_locked = spi_nor_is_locked; +} diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index e5dfa786f190e3ec147529189643c8a187662f9e..9a81c67a60c623fecbc638b4a4bc737e24870039 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -11,8 +11,7 @@ static int w25q256_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { /* * W25Q256JV supports 4B opcodes but W25Q256FV does not. @@ -55,14 +54,18 @@ static const struct flash_info winbond_parts[] = { { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + OTP_INFO(256, 3, 0x1000, 0x1000) + }, + { "w25q32jv", INFO(0xef7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "w25q32jwm", INFO(0xef8016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + OTP_INFO(256, 3, 0x1000, 0x1000) }, { "w25q64jwm", INFO(0xef8017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, @@ -97,6 +100,8 @@ static const struct flash_info winbond_parts[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) }, + { "w25q512jvq", INFO(0xef4020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, }; /** @@ -131,9 +136,18 @@ static int winbond_set_4byte_addr_mode(struct spi_nor *nor, bool enable) return spi_nor_write_disable(nor); } +static const struct spi_nor_otp_ops winbond_otp_ops = { + .read = spi_nor_otp_read_secr, + .write = spi_nor_otp_write_secr, + .lock = spi_nor_otp_lock_sr2, + .is_locked = spi_nor_otp_is_locked_sr2, +}; + static void winbond_default_init(struct spi_nor *nor) { nor->params->set_4byte_addr_mode = winbond_set_4byte_addr_mode; + if (nor->params->otp.org->n_regions) + nor->params->otp.ops = &winbond_otp_ops; } static const struct spi_nor_fixups winbond_fixups = { diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 02c1f2c014e8bf9116df68b26fc08cca612669c1..cc5f2c1861d4a22d984bcd37efb98dd3561ee765 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -7,11 +7,12 @@ * Author: Peter Rosin <peda@axentia.se> */ +#include <linux/bitmap.h> #include <linux/err.h> #include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mux/driver.h> -#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -23,8 +24,9 @@ static int mux_gpio_set(struct mux_control *mux, int state) { struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); DECLARE_BITMAP(values, BITS_PER_TYPE(state)); + u32 value = state; - values[0] = state; + bitmap_from_arr32(values, &value, BITS_PER_TYPE(value)); gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, mux_gpio->gpios->desc, @@ -64,14 +66,11 @@ static int mux_gpio_probe(struct platform_device *pdev) mux_chip->ops = &mux_gpio_ops; mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); - if (IS_ERR(mux_gpio->gpios)) { - ret = PTR_ERR(mux_gpio->gpios); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get gpios\n"); - return ret; - } + if (IS_ERR(mux_gpio->gpios)) + return dev_err_probe(dev, PTR_ERR(mux_gpio->gpios), + "failed to get gpios\n"); WARN_ON(pins != mux_gpio->gpios->ndescs); - mux_chip->mux->states = 1 << pins; + mux_chip->mux->states = BIT(pins); ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state); if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) { @@ -96,7 +95,7 @@ static int mux_gpio_probe(struct platform_device *pdev) static struct platform_driver mux_gpio_driver = { .driver = { .name = "gpio-mux", - .of_match_table = of_match_ptr(mux_gpio_dt_ids), + .of_match_table = mux_gpio_dt_ids, }, .probe = mux_gpio_probe, }; diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 8215cd77301f5430c8deeecf9553fefda859a382..da6fffb4d5a8eb689bd1a74e81d3659e883135bc 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -382,7 +382,6 @@ static void ldisc_close(struct tty_struct *tty) /* The line discipline structure. */ static struct tty_ldisc_ops caif_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_caif", .open = ldisc_open, .close = ldisc_close, @@ -390,18 +389,6 @@ static struct tty_ldisc_ops caif_ldisc = { .write_wakeup = ldisc_tx_wakeup }; -static int register_ldisc(void) -{ - int result; - - result = tty_register_ldisc(N_CAIF, &caif_ldisc); - if (result < 0) { - pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, - result); - return result; - } - return result; -} static const struct net_device_ops netdev_ops = { .ndo_open = caif_net_open, .ndo_stop = caif_net_close, @@ -444,7 +431,10 @@ static int __init caif_ser_init(void) { int ret; - ret = register_ldisc(); + ret = tty_register_ldisc(N_CAIF, &caif_ldisc); + if (ret < 0) + pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, ret); + debugfsdir = debugfs_create_dir("caif_serial", NULL); return ret; } diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 30c8d53c9745d7b9253eb8dc6b1c8151daf9a328..31ba6664503d3558e917d188cdaf02f58be1a369 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -697,7 +697,6 @@ static int slcan_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops slc_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "slcan", .open = slcan_open, .close = slcan_close, diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index e3a8858915b37acda846518e43f0c6395a24a084..df0eab479d51223e1f1c19eeb4e061827a18f68a 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -963,7 +963,7 @@ static void tx_timeout(struct net_device *dev, unsigned int txqueue) unsigned long flag; netif_stop_queue(dev); - tasklet_disable(&np->tx_tasklet); + tasklet_disable_in_atomic(&np->tx_tasklet); iowrite16(0, ioaddr + IntrEnable); printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x " "TxFrameId %2.2x," diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index e9efe074edc113d01d1416cc8bf5bbadab7ea7fc..f1b9284e0bea8c5ef3b3923ccde33d3d4cacdb11 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -1265,9 +1265,9 @@ jme_stop_shutdown_timer(struct jme_adapter *jme) jwrite32f(jme, JME_APMC, apmc); } -static void jme_link_change_tasklet(struct tasklet_struct *t) +static void jme_link_change_work(struct work_struct *work) { - struct jme_adapter *jme = from_tasklet(jme, t, linkch_task); + struct jme_adapter *jme = container_of(work, struct jme_adapter, linkch_task); struct net_device *netdev = jme->dev; int rc; @@ -1510,7 +1510,7 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat) * all other events are ignored */ jwrite32(jme, JME_IEVE, intrstat); - tasklet_schedule(&jme->linkch_task); + schedule_work(&jme->linkch_task); goto out_reenable; } @@ -1832,7 +1832,6 @@ jme_open(struct net_device *netdev) jme_clear_pm_disable_wol(jme); JME_NAPI_ENABLE(jme); - tasklet_setup(&jme->linkch_task, jme_link_change_tasklet); tasklet_setup(&jme->txclean_task, jme_tx_clean_tasklet); tasklet_setup(&jme->rxclean_task, jme_rx_clean_tasklet); tasklet_setup(&jme->rxempty_task, jme_rx_empty_tasklet); @@ -1920,7 +1919,7 @@ jme_close(struct net_device *netdev) JME_NAPI_DISABLE(jme); - tasklet_kill(&jme->linkch_task); + cancel_work_sync(&jme->linkch_task); tasklet_kill(&jme->txclean_task); tasklet_kill(&jme->rxclean_task); tasklet_kill(&jme->rxempty_task); @@ -3035,6 +3034,7 @@ jme_init_one(struct pci_dev *pdev, atomic_set(&jme->rx_empty, 1); tasklet_setup(&jme->pcc_task, jme_pcc_tasklet); + INIT_WORK(&jme->linkch_task, jme_link_change_work); jme->dpi.cur = PCC_P1; jme->reg_ghc = 0; diff --git a/drivers/net/ethernet/jme.h b/drivers/net/ethernet/jme.h index a2c3b00d939d049dd6fb3e7e3627888e1c4aa675..2af76329b4a27d3bb83bce30774ca31d0fecf542 100644 --- a/drivers/net/ethernet/jme.h +++ b/drivers/net/ethernet/jme.h @@ -411,7 +411,7 @@ struct jme_adapter { struct tasklet_struct rxempty_task; struct tasklet_struct rxclean_task; struct tasklet_struct txclean_task; - struct tasklet_struct linkch_task; + struct work_struct linkch_task; struct tasklet_struct pcc_task; unsigned long flags; u32 reg_txcs; diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index e675ba12fde2e3fb42aa850265fc51ec56ad174b..7737e4d0bb9ec4d9ba15072fd8ff5297849b0238 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -140,8 +140,8 @@ config DWMAC_ROCKCHIP config DWMAC_SOCFPGA tristate "SOCFPGA dwmac support" - default (ARCH_SOCFPGA || ARCH_STRATIX10) - depends on OF && (ARCH_SOCFPGA || ARCH_STRATIX10 || COMPILE_TEST) + default ARCH_INTEL_SOCFPGA + depends on OF && (ARCH_INTEL_SOCFPGA || COMPILE_TEST) select MFD_SYSCON help Support for ethernet controller on Altera SOCFPGA diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 9f5b5614a1503734e201d14e8524b74db6e8e884..80f41945709f98edfa6f9e9c6241ec7bc6407dcd 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -744,7 +744,6 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops sp_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "6pack", .open = sixpack_open, .close = sixpack_close, diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 17be2bb2985cd00ab965f072762c1ff7e3f6da93..65154224d5b840c50486941000ad36a5f3bcc2be 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -933,7 +933,6 @@ out: static struct tty_ldisc_ops ax_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "mkiss", .open = mkiss_open, .close = mkiss_close, diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 2a91caa4f37b075d77da8d085a03145afddd2d1e..8b41aa3fb64eaa409cc8fee66f143225233c5d06 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -372,7 +372,6 @@ ppp_asynctty_wakeup(struct tty_struct *tty) static struct tty_ldisc_ops ppp_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "ppp", .open = ppp_asynctty_open, .close = ppp_asynctty_close, diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index d8890923a9e33abecf1668c399410a9ccdcd3a03..576b6a93bf23b2426c24b1dcae8a5cd3e2b373cc 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -365,7 +365,6 @@ ppp_sync_wakeup(struct tty_struct *tty) static struct tty_ldisc_ops ppp_sync_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "pppsync", .open = ppp_sync_open, .close = ppp_sync_close, diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index f81fb0b13a944f6a51d2b5be6135b14055b9f9db..1ab124eba8eb5d0f7f51d4c8e4195e6cc8060bec 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1263,7 +1263,6 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static struct tty_ldisc_ops sl_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "slip", .open = slip_open, .close = slip_close, diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index ed3743dc62b9162eca251a78ba9315efb5a990df..9a6a8353e19215f0f54c3e0fdb0d86e4e15c0426 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -25,13 +25,13 @@ /* Protocol timeouts in ms */ #define TBNET_LOGIN_DELAY 4500 #define TBNET_LOGIN_TIMEOUT 500 -#define TBNET_LOGOUT_TIMEOUT 100 +#define TBNET_LOGOUT_TIMEOUT 1000 #define TBNET_RING_SIZE 256 -#define TBNET_LOCAL_PATH 0xf #define TBNET_LOGIN_RETRIES 60 -#define TBNET_LOGOUT_RETRIES 5 +#define TBNET_LOGOUT_RETRIES 10 #define TBNET_MATCH_FRAGS_ID BIT(1) +#define TBNET_64K_FRAMES BIT(2) #define TBNET_MAX_MTU SZ_64K #define TBNET_FRAME_SIZE SZ_4K #define TBNET_MAX_PAYLOAD_SIZE \ @@ -154,8 +154,8 @@ struct tbnet_ring { * @login_sent: ThunderboltIP login message successfully sent * @login_received: ThunderboltIP login message received from the remote * host - * @transmit_path: HopID the other end needs to use building the - * opposite side path. + * @local_transmit_path: HopID we are using to send out packets + * @remote_transmit_path: HopID the other end is using to send packets to us * @connection_lock: Lock serializing access to @login_sent, * @login_received and @transmit_path. * @login_retries: Number of login retries currently done @@ -184,7 +184,8 @@ struct tbnet { atomic_t command_id; bool login_sent; bool login_received; - u32 transmit_path; + int local_transmit_path; + int remote_transmit_path; struct mutex connection_lock; int login_retries; struct delayed_work login_work; @@ -257,7 +258,7 @@ static int tbnet_login_request(struct tbnet *net, u8 sequence) atomic_inc_return(&net->command_id)); request.proto_version = TBIP_LOGIN_PROTO_VERSION; - request.transmit_path = TBNET_LOCAL_PATH; + request.transmit_path = net->local_transmit_path; return tb_xdomain_request(xd, &request, sizeof(request), TB_CFG_PKG_XDOMAIN_RESP, &reply, @@ -364,10 +365,10 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout) mutex_lock(&net->connection_lock); if (net->login_sent && net->login_received) { - int retries = TBNET_LOGOUT_RETRIES; + int ret, retries = TBNET_LOGOUT_RETRIES; while (send_logout && retries-- > 0) { - int ret = tbnet_logout_request(net); + ret = tbnet_logout_request(net); if (ret != -ETIMEDOUT) break; } @@ -377,8 +378,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout) tbnet_free_buffers(&net->rx_ring); tbnet_free_buffers(&net->tx_ring); - if (tb_xdomain_disable_paths(net->xd)) + ret = tb_xdomain_disable_paths(net->xd, + net->local_transmit_path, + net->rx_ring.ring->hop, + net->remote_transmit_path, + net->tx_ring.ring->hop); + if (ret) netdev_warn(net->dev, "failed to disable DMA paths\n"); + + tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path); + net->remote_transmit_path = 0; } net->login_retries = 0; @@ -424,7 +433,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data) if (!ret) { mutex_lock(&net->connection_lock); net->login_received = true; - net->transmit_path = pkg->transmit_path; + net->remote_transmit_path = pkg->transmit_path; /* If we reached the number of max retries or * previous logout, schedule another round of @@ -597,12 +606,18 @@ static void tbnet_connected_work(struct work_struct *work) if (!connected) return; + ret = tb_xdomain_alloc_in_hopid(net->xd, net->remote_transmit_path); + if (ret != net->remote_transmit_path) { + netdev_err(net->dev, "failed to allocate Rx HopID\n"); + return; + } + /* Both logins successful so enable the high-speed DMA paths and * start the network device queue. */ - ret = tb_xdomain_enable_paths(net->xd, TBNET_LOCAL_PATH, + ret = tb_xdomain_enable_paths(net->xd, net->local_transmit_path, net->rx_ring.ring->hop, - net->transmit_path, + net->remote_transmit_path, net->tx_ring.ring->hop); if (ret) { netdev_err(net->dev, "failed to enable DMA paths\n"); @@ -629,6 +644,7 @@ err_free_rx_buffers: err_stop_rings: tb_ring_stop(net->rx_ring.ring); tb_ring_stop(net->tx_ring.ring); + tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path); } static void tbnet_login_work(struct work_struct *work) @@ -851,6 +867,7 @@ static int tbnet_open(struct net_device *dev) struct tb_xdomain *xd = net->xd; u16 sof_mask, eof_mask; struct tb_ring *ring; + int hopid; netif_carrier_off(dev); @@ -862,6 +879,15 @@ static int tbnet_open(struct net_device *dev) } net->tx_ring.ring = ring; + hopid = tb_xdomain_alloc_out_hopid(xd, -1); + if (hopid < 0) { + netdev_err(dev, "failed to allocate Tx HopID\n"); + tb_ring_free(net->tx_ring.ring); + net->tx_ring.ring = NULL; + return hopid; + } + net->local_transmit_path = hopid; + sof_mask = BIT(TBIP_PDF_FRAME_START); eof_mask = BIT(TBIP_PDF_FRAME_END); @@ -893,6 +919,8 @@ static int tbnet_stop(struct net_device *dev) tb_ring_free(net->rx_ring.ring); net->rx_ring.ring = NULL; + + tb_xdomain_release_out_hopid(net->xd, net->local_transmit_path); tb_ring_free(net->tx_ring.ring); net->tx_ring.ring = NULL; @@ -1340,7 +1368,7 @@ static int __init tbnet_init(void) * the moment. */ tb_property_add_immediate(tbnet_dir, "prtcstns", - TBNET_MATCH_FRAGS_ID); + TBNET_MATCH_FRAGS_ID | TBNET_64K_FRAMES); ret = tb_register_property_dir("network", tbnet_dir); if (ret) { diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 71e2ada86793f5b63ab839faf67aaffcfaee4726..72e2e71aac0e637192ddc37daa94fa1a19123494 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -251,7 +251,7 @@ void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc) int first_slot = ATH_BCBUF; int slot; - tasklet_disable(&sc->bcon_tasklet); + tasklet_disable_in_atomic(&sc->bcon_tasklet); /* Find first taken slot. */ for (slot = 0; slot < ATH_BCBUF; slot++) { diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 0896e21642bebabf4450a5694b9196b77174d91b..5eaaa51a5e308d6d2de41259a953bb1a9de2967a 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3855,7 +3855,8 @@ out_unlock: return ret; } -static int ns_cmp(void *priv, struct list_head *a, struct list_head *b) +static int ns_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct nvme_ns *nsa = container_of(a, struct nvme_ns, list); struct nvme_ns *nsb = container_of(b, struct nvme_ns, list); diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 75d2594c16e19aa64f6bc7119ae8beab87e31064..dd20190068387c82b3e8fe9954e34c9f3ae3eb1c 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -272,10 +272,20 @@ config SPRD_EFUSE config NVMEM_RMEM tristate "Reserved Memory Based Driver Support" + depends on HAS_IOMEM help This driver maps reserved memory into an nvmem device. It might be useful to expose information left by firmware in memory. This driver can also be built as a module. If so, the module will be called nvmem-rmem. + +config NVMEM_BRCM_NVRAM + tristate "Broadcom's NVRAM support" + depends on ARCH_BCM_5301X || COMPILE_TEST + depends on HAS_IOMEM + help + This driver provides support for Broadcom's NVRAM that can be accessed + using I/O mapping. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 5376b8e0dae5a9da24cf957407a37c5bfe0ba011..bbea1410240a887d42b8d959fa2606fd569c2b30 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -57,3 +57,5 @@ obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_efuse.o nvmem_sprd_efuse-y := sprd-efuse.o obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o nvmem-rmem-y := rmem.o +obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o +nvmem_brcm_nvram-y := brcm_nvram.o diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c new file mode 100644 index 0000000000000000000000000000000000000000..bd2ecaaf458518a5684034f722ea74d8d7378094 --- /dev/null +++ b/drivers/nvmem/brcm_nvram.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> + */ + +#include <linux/io.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/platform_device.h> + +struct brcm_nvram { + struct device *dev; + void __iomem *base; +}; + +static int brcm_nvram_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct brcm_nvram *priv = context; + u8 *dst = val; + + while (bytes--) + *dst++ = readb(priv->base + offset++); + + return 0; +} + +static int brcm_nvram_probe(struct platform_device *pdev) +{ + struct nvmem_config config = { + .name = "brcm-nvram", + .reg_read = brcm_nvram_read, + }; + struct device *dev = &pdev->dev; + struct resource *res; + struct brcm_nvram *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + config.dev = dev; + config.priv = priv; + config.size = resource_size(res); + + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); +} + +static const struct of_device_id brcm_nvram_of_match_table[] = { + { .compatible = "brcm,nvram", }, + {}, +}; + +static struct platform_driver brcm_nvram_driver = { + .probe = brcm_nvram_probe, + .driver = { + .name = "brcm_nvram", + .of_match_table = brcm_nvram_of_match_table, + }, +}; + +static int __init brcm_nvram_init(void) +{ + return platform_driver_register(&brcm_nvram_driver); +} + +subsys_initcall_sync(brcm_nvram_init); + +MODULE_AUTHOR("Rafał Miłecki"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index a5ab1e0c74cf644fe978d978f0cc286ae39c80b4..bca671ff4e54607ffd4e53e699b664da7d336f11 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1606,6 +1606,101 @@ int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) } EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); +static void *nvmem_cell_read_variable_common(struct device *dev, + const char *cell_id, + size_t max_len, size_t *len) +{ + struct nvmem_cell *cell; + int nbits; + void *buf; + + cell = nvmem_cell_get(dev, cell_id); + if (IS_ERR(cell)) + return cell; + + nbits = cell->nbits; + buf = nvmem_cell_read(cell, len); + nvmem_cell_put(cell); + if (IS_ERR(buf)) + return buf; + + /* + * If nbits is set then nvmem_cell_read() can significantly exaggerate + * the length of the real data. Throw away the extra junk. + */ + if (nbits) + *len = DIV_ROUND_UP(nbits, 8); + + if (*len > max_len) { + kfree(buf); + return ERR_PTR(-ERANGE); + } + + return buf; +} + +/** + * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, + u32 *val) +{ + size_t len; + u8 *buf; + int i; + + buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* Copy w/ implicit endian conversion */ + *val = 0; + for (i = 0; i < len; i++) + *val |= buf[i] << (8 * i); + + kfree(buf); + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); + +/** + * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, + u64 *val) +{ + size_t len; + u8 *buf; + int i; + + buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* Copy w/ implicit endian conversion */ + *val = 0; + for (i = 0; i < len; i++) + *val |= (uint64_t)buf[i] << (8 * i); + + kfree(buf); + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); + /** * nvmem_device_cell_read() - Read a given nvmem device and cell * diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c index f6e9f96933ca291d65b2d5f8b8118bd4bfd6c3d4..4fcb63507ecd151e95cd8089a5000036a1fa2367 100644 --- a/drivers/nvmem/qcom-spmi-sdam.c +++ b/drivers/nvmem/qcom-spmi-sdam.c @@ -141,7 +141,7 @@ static int sdam_probe(struct platform_device *pdev) sdam->sdam_config.dev = &pdev->dev; sdam->sdam_config.name = "spmi_sdam"; sdam->sdam_config.id = NVMEM_DEVID_AUTO; - sdam->sdam_config.owner = THIS_MODULE, + sdam->sdam_config.owner = THIS_MODULE; sdam->sdam_config.stride = 1; sdam->sdam_config.word_size = 1; sdam->sdam_config.reg_read = sdam_read; diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 6cace24dfbf734d0917fe06e01eed07d59fdb5cb..d6d3f24685a85e1c65c69b60a8ba56eeaeb76314 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -45,11 +45,13 @@ MODULE_PARM_DESC(read_raw_data, "Read raw instead of corrected data"); * @qfprom_blow_timer_value: The timer value of qfprom when doing efuse blow. * @qfprom_blow_set_freq: The frequency required to set when we start the * fuse blowing. + * @qfprom_blow_uV: LDO voltage to be set when doing efuse blow */ struct qfprom_soc_data { u32 accel_value; u32 qfprom_blow_timer_value; u32 qfprom_blow_set_freq; + int qfprom_blow_uV; }; /** @@ -111,6 +113,15 @@ static const struct qfprom_soc_compatible_data sc7180_qfprom = { .nkeepout = ARRAY_SIZE(sc7180_qfprom_keepout) }; +static const struct nvmem_keepout sc7280_qfprom_keepout[] = { + {.start = 0x128, .end = 0x148}, + {.start = 0x238, .end = 0x248} +}; + +static const struct qfprom_soc_compatible_data sc7280_qfprom = { + .keepout = sc7280_qfprom_keepout, + .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout) +}; /** * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing. * @priv: Our driver data. @@ -127,6 +138,16 @@ static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv, { int ret; + /* + * This may be a shared rail and may be able to run at a lower rate + * when we're not blowing fuses. At the moment, the regulator framework + * applies voltage constraints even on disabled rails, so remove our + * constraints and allow the rail to be adjusted by other users. + */ + ret = regulator_set_voltage(priv->vcc, 0, INT_MAX); + if (ret) + dev_warn(priv->dev, "Failed to set 0 voltage (ignoring)\n"); + ret = regulator_disable(priv->vcc); if (ret) dev_warn(priv->dev, "Failed to disable regulator (ignoring)\n"); @@ -158,6 +179,7 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, struct qfprom_touched_values *old) { int ret; + int qfprom_blow_uV = priv->soc_data->qfprom_blow_uV; ret = clk_prepare_enable(priv->secclk); if (ret) { @@ -172,6 +194,17 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, goto err_clk_prepared; } + /* + * Hardware requires 1.8V min for fuse blowing; this may be + * a rail shared do don't specify a max--regulator constraints + * will handle. + */ + ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX); + if (ret) { + dev_err(priv->dev, "Failed to set %duV\n", qfprom_blow_uV); + goto err_clk_rate_set; + } + ret = regulator_enable(priv->vcc); if (ret) { dev_err(priv->dev, "Failed to enable regulator\n"); @@ -290,6 +323,14 @@ static const struct qfprom_soc_data qfprom_7_8_data = { .accel_value = 0xD10, .qfprom_blow_timer_value = 25, .qfprom_blow_set_freq = 4800000, + .qfprom_blow_uV = 1800000, +}; + +static const struct qfprom_soc_data qfprom_7_15_data = { + .accel_value = 0xD08, + .qfprom_blow_timer_value = 24, + .qfprom_blow_set_freq = 4800000, + .qfprom_blow_uV = 1900000, }; static int qfprom_probe(struct platform_device *pdev) @@ -358,6 +399,8 @@ static int qfprom_probe(struct platform_device *pdev) if (major_version == 7 && minor_version == 8) priv->soc_data = &qfprom_7_8_data; + if (major_version == 7 && minor_version == 15) + priv->soc_data = &qfprom_7_15_data; priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); if (IS_ERR(priv->vcc)) @@ -384,6 +427,7 @@ static int qfprom_probe(struct platform_device *pdev) static const struct of_device_id qfprom_of_match[] = { { .compatible = "qcom,qfprom",}, { .compatible = "qcom,sc7180-qfprom", .data = &sc7180_qfprom}, + { .compatible = "qcom,sc7280-qfprom", .data = &sc7280_qfprom}, {/* sentinel */}, }; MODULE_DEVICE_TABLE(of, qfprom_of_match); diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c index c527d26ca6ac12c801fb85c4f215d33e6df0e881..4692aa985bd6ffd847cc644e7669ca5afd2d3422 100644 --- a/drivers/nvmem/snvs_lpgpr.c +++ b/drivers/nvmem/snvs_lpgpr.c @@ -123,7 +123,7 @@ static int snvs_lpgpr_probe(struct platform_device *pdev) cfg->dev = dev; cfg->stride = 4; cfg->word_size = 4; - cfg->size = dcfg->size, + cfg->size = dcfg->size; cfg->owner = THIS_MODULE; cfg->reg_read = snvs_lpgpr_read; cfg->reg_write = snvs_lpgpr_write; diff --git a/drivers/of/address.c b/drivers/of/address.c index 73ddf2540f3fe6f088ddc10d665d72a678745599..a2373fa4a5715b0da081dad7c6ec30b44117dc75 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -26,6 +26,7 @@ static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, const char *name, struct resource *r); +static bool of_mmio_is_nonposted(struct device_node *np); /* Debug utility */ #ifdef DEBUG @@ -847,6 +848,9 @@ static int __of_address_to_resource(struct device_node *dev, return -EINVAL; memset(r, 0, sizeof(struct resource)); + if (of_mmio_is_nonposted(dev)) + flags |= IORESOURCE_MEM_NONPOSTED; + r->start = taddr; r->end = taddr + size - 1; r->flags = flags; @@ -896,7 +900,10 @@ void __iomem *of_iomap(struct device_node *np, int index) if (of_address_to_resource(np, index, &res)) return NULL; - return ioremap(res.start, resource_size(&res)); + if (res.flags & IORESOURCE_MEM_NONPOSTED) + return ioremap_np(res.start, resource_size(&res)); + else + return ioremap(res.start, resource_size(&res)); } EXPORT_SYMBOL(of_iomap); @@ -928,7 +935,11 @@ void __iomem *of_io_request_and_map(struct device_node *np, int index, if (!request_mem_region(res.start, resource_size(&res), name)) return IOMEM_ERR_PTR(-EBUSY); - mem = ioremap(res.start, resource_size(&res)); + if (res.flags & IORESOURCE_MEM_NONPOSTED) + mem = ioremap_np(res.start, resource_size(&res)); + else + mem = ioremap(res.start, resource_size(&res)); + if (!mem) { release_mem_region(res.start, resource_size(&res)); return IOMEM_ERR_PTR(-ENOMEM); @@ -1094,3 +1105,31 @@ bool of_dma_is_coherent(struct device_node *np) return false; } EXPORT_SYMBOL_GPL(of_dma_is_coherent); + +/** + * of_mmio_is_nonposted - Check if device uses non-posted MMIO + * @np: device node + * + * Returns true if the "nonposted-mmio" property was found for + * the device's bus. + * + * 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) +{ + struct device_node *parent; + bool nonposted; + + if (!IS_ENABLED(CONFIG_ARCH_APPLE)) + return false; + + parent = of_get_parent(np); + if (!parent) + return false; + + nonposted = of_property_read_bool(parent, "nonposted-mmio"); + + of_node_put(parent); + return nonposted; +} diff --git a/drivers/of/property.c b/drivers/of/property.c index 78427c85bef38737d850905a1adb143dbfbb930b..aab6383f02198928f47319f9e70ef8b076dd2c00 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -1038,6 +1038,25 @@ static bool of_is_ancestor_of(struct device_node *test_ancestor, return false; } +static struct device_node *of_get_compat_node(struct device_node *np) +{ + of_node_get(np); + + while (np) { + if (!of_device_is_available(np)) { + of_node_put(np); + np = NULL; + } + + if (of_find_property(np, "compatible", NULL)) + break; + + np = of_get_next_parent(np); + } + + return np; +} + /** * of_link_to_phandle - Add fwnode link to supplier from supplier phandle * @con_np: consumer device tree node @@ -1061,25 +1080,11 @@ static int of_link_to_phandle(struct device_node *con_np, struct device *sup_dev; struct device_node *tmp_np = sup_np; - of_node_get(sup_np); /* * Find the device node that contains the supplier phandle. It may be * @sup_np or it may be an ancestor of @sup_np. */ - while (sup_np) { - - /* Don't allow linking to a disabled supplier */ - if (!of_device_is_available(sup_np)) { - of_node_put(sup_np); - sup_np = NULL; - } - - if (of_find_property(sup_np, "compatible", NULL)) - break; - - sup_np = of_get_next_parent(sup_np); - } - + sup_np = of_get_compat_node(sup_np); if (!sup_np) { pr_debug("Not linking %pOFP to %pOFP - No device\n", con_np, tmp_np); @@ -1225,6 +1230,8 @@ static struct device_node *parse_##fname(struct device_node *np, \ * @parse_prop.prop_name: Name of property holding a phandle value * @parse_prop.index: For properties holding a list of phandles, this is the * index into the list + * @optional: The property can be an optional dependency. + * @node_not_dev: The consumer node containing the property is never a device. * * Returns: * parse_prop() return values are @@ -1236,6 +1243,7 @@ struct supplier_bindings { struct device_node *(*parse_prop)(struct device_node *np, const char *prop_name, int index); bool optional; + bool node_not_dev; }; DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells") @@ -1260,6 +1268,7 @@ DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL) DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL) DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL) DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL) +DEFINE_SIMPLE_PROP(remote_endpoint, "remote-endpoint", NULL) DEFINE_SUFFIX_PROP(regulators, "-supply", NULL) DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells") @@ -1343,6 +1352,7 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_pinctrl6, }, { .parse_prop = parse_pinctrl7, }, { .parse_prop = parse_pinctrl8, }, + { .parse_prop = parse_remote_endpoint, .node_not_dev = true, }, { .parse_prop = parse_gpio_compat, }, { .parse_prop = parse_interrupts, }, { .parse_prop = parse_regulators, }, @@ -1387,10 +1397,16 @@ static int of_link_property(struct device_node *con_np, const char *prop_name) } while ((phandle = s->parse_prop(con_np, prop_name, i))) { + struct device_node *con_dev_np; + + con_dev_np = s->node_not_dev + ? of_get_compat_node(con_np) + : of_node_get(con_np); matched = true; i++; - of_link_to_phandle(con_np, phandle); + of_link_to_phandle(con_dev_np, phandle); of_node_put(phandle); + of_node_put(con_dev_np); } s++; } diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 1556998425d5bc752c35970be104b1fbcf09e972..e366218d673679f7dd62e7cda25d281affb864ee 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1857,6 +1857,35 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) } EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); +static void devm_pm_opp_supported_hw_release(void *data) +{ + dev_pm_opp_put_supported_hw(data); +} + +/** + * devm_pm_opp_set_supported_hw() - Set supported platforms + * @dev: Device for which supported-hw has to be set. + * @versions: Array of hierarchy of versions to match. + * @count: Number of elements in the array. + * + * This is a resource-managed variant of dev_pm_opp_set_supported_hw(). + * + * Return: 0 on success and errorno otherwise. + */ +int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, + unsigned int count) +{ + struct opp_table *opp_table; + + opp_table = dev_pm_opp_set_supported_hw(dev, versions, count); + if (IS_ERR(opp_table)) + return PTR_ERR(opp_table); + + return devm_add_action_or_reset(dev, devm_pm_opp_supported_hw_release, + opp_table); +} +EXPORT_SYMBOL_GPL(devm_pm_opp_set_supported_hw); + /** * dev_pm_opp_set_prop_name() - Set prop-extn name * @dev: Device for which the prop-name has to be set. @@ -2047,6 +2076,36 @@ put_opp_table: } EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators); +static void devm_pm_opp_regulators_release(void *data) +{ + dev_pm_opp_put_regulators(data); +} + +/** + * devm_pm_opp_set_regulators() - Set regulator names for the device + * @dev: Device for which regulator name is being set. + * @names: Array of pointers to the names of the regulator. + * @count: Number of regulators. + * + * This is a resource-managed variant of dev_pm_opp_set_regulators(). + * + * Return: 0 on success and errorno otherwise. + */ +int devm_pm_opp_set_regulators(struct device *dev, + const char * const names[], + unsigned int count) +{ + struct opp_table *opp_table; + + opp_table = dev_pm_opp_set_regulators(dev, names, count); + if (IS_ERR(opp_table)) + return PTR_ERR(opp_table); + + return devm_add_action_or_reset(dev, devm_pm_opp_regulators_release, + opp_table); +} +EXPORT_SYMBOL_GPL(devm_pm_opp_set_regulators); + /** * dev_pm_opp_set_clkname() - Set clk name for the device * @dev: Device for which clk name is being set. @@ -2119,6 +2178,33 @@ void dev_pm_opp_put_clkname(struct opp_table *opp_table) } EXPORT_SYMBOL_GPL(dev_pm_opp_put_clkname); +static void devm_pm_opp_clkname_release(void *data) +{ + dev_pm_opp_put_clkname(data); +} + +/** + * devm_pm_opp_set_clkname() - Set clk name for the device + * @dev: Device for which clk name is being set. + * @name: Clk name. + * + * This is a resource-managed variant of dev_pm_opp_set_clkname(). + * + * Return: 0 on success and errorno otherwise. + */ +int devm_pm_opp_set_clkname(struct device *dev, const char *name) +{ + struct opp_table *opp_table; + + opp_table = dev_pm_opp_set_clkname(dev, name); + if (IS_ERR(opp_table)) + return PTR_ERR(opp_table); + + return devm_add_action_or_reset(dev, devm_pm_opp_clkname_release, + opp_table); +} +EXPORT_SYMBOL_GPL(devm_pm_opp_set_clkname); + /** * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper * @dev: Device for which the helper is getting registered. @@ -2209,25 +2295,19 @@ static void devm_pm_opp_unregister_set_opp_helper(void *data) * * This is a resource-managed version of dev_pm_opp_register_set_opp_helper(). * - * Return: pointer to 'struct opp_table' on success and errorno otherwise. + * Return: 0 on success and errorno otherwise. */ -struct opp_table * -devm_pm_opp_register_set_opp_helper(struct device *dev, - int (*set_opp)(struct dev_pm_set_opp_data *data)) +int devm_pm_opp_register_set_opp_helper(struct device *dev, + int (*set_opp)(struct dev_pm_set_opp_data *data)) { struct opp_table *opp_table; - int err; opp_table = dev_pm_opp_register_set_opp_helper(dev, set_opp); if (IS_ERR(opp_table)) - return opp_table; - - err = devm_add_action_or_reset(dev, devm_pm_opp_unregister_set_opp_helper, - opp_table); - if (err) - return ERR_PTR(err); + return PTR_ERR(opp_table); - return opp_table; + return devm_add_action_or_reset(dev, devm_pm_opp_unregister_set_opp_helper, + opp_table); } EXPORT_SYMBOL_GPL(devm_pm_opp_register_set_opp_helper); @@ -2380,25 +2460,19 @@ static void devm_pm_opp_detach_genpd(void *data) * * This is a resource-managed version of dev_pm_opp_attach_genpd(). * - * Return: pointer to 'struct opp_table' on success and errorno otherwise. + * Return: 0 on success and errorno otherwise. */ -struct opp_table * -devm_pm_opp_attach_genpd(struct device *dev, const char **names, - struct device ***virt_devs) +int devm_pm_opp_attach_genpd(struct device *dev, const char **names, + struct device ***virt_devs) { struct opp_table *opp_table; - int err; opp_table = dev_pm_opp_attach_genpd(dev, names, virt_devs); if (IS_ERR(opp_table)) - return opp_table; - - err = devm_add_action_or_reset(dev, devm_pm_opp_detach_genpd, - opp_table); - if (err) - return ERR_PTR(err); + return PTR_ERR(opp_table); - return opp_table; + return devm_add_action_or_reset(dev, devm_pm_opp_detach_genpd, + opp_table); } EXPORT_SYMBOL_GPL(devm_pm_opp_attach_genpd); diff --git a/drivers/opp/of.c b/drivers/opp/of.c index f480c10e63146cbbd0832799fc0390eee6ba4646..c582a9ca397bb4ab6f8b8344240fe5060d6bdd0e 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1104,6 +1104,42 @@ static int _of_add_table_indexed(struct device *dev, int index, bool getclk) return ret; } +static void devm_pm_opp_of_table_release(void *data) +{ + dev_pm_opp_of_remove_table(data); +} + +/** + * devm_pm_opp_of_add_table() - Initialize opp table from device tree + * @dev: device pointer used to lookup OPP table. + * + * Register the initial OPP table with the OPP library for given device. + * + * The opp_table structure will be freed after the device is destroyed. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + * -ENODEV when 'operating-points' property is not found or is invalid data + * in device node. + * -ENODATA when empty 'operating-points' property is found + * -EINVAL when invalid entries are found in opp-v2 table + */ +int devm_pm_opp_of_add_table(struct device *dev) +{ + int ret; + + ret = dev_pm_opp_of_add_table(dev); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_pm_opp_of_table_release, dev); +} +EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table); + /** * dev_pm_opp_of_add_table() - Initialize opp table from device tree * @dev: device pointer used to lookup OPP table. diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c index 73dcf8cf98fbf43efeeb6e54001ee25bb1b757bb..ae1c55503513a910af620620c70997e2913d71c6 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c @@ -345,7 +345,8 @@ static int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc, return 0; } -static int cdns_pcie_host_dma_ranges_cmp(void *priv, struct list_head *a, struct list_head *b) +static int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct resource_entry *entry1, *entry2; diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index b105af63854a3da082b4a43b6aa97292abf3b9a4..047cfbdc13303e3580cdef09c8113d6b8bc56583 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -443,8 +443,8 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { .get_features = dra7xx_pcie_get_features, }; -static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, - struct platform_device *pdev) +static int dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, + struct platform_device *pdev) { int ret; struct dw_pcie_ep *ep; @@ -472,8 +472,8 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, return 0; } -static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, - struct platform_device *pdev) +static int dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, + struct platform_device *pdev) { int ret; struct dw_pcie *pci = dra7xx->pci; @@ -682,7 +682,7 @@ static int dra7xx_pcie_configure_two_lane(struct device *dev, return 0; } -static int __init dra7xx_pcie_probe(struct platform_device *pdev) +static int dra7xx_pcie_probe(struct platform_device *pdev) { u32 reg; int ret; @@ -938,6 +938,7 @@ static const struct dev_pm_ops dra7xx_pcie_pm_ops = { }; static struct platform_driver dra7xx_pcie_driver = { + .probe = dra7xx_pcie_probe, .driver = { .name = "dra7-pcie", .of_match_table = of_dra7xx_pcie_match, @@ -946,4 +947,4 @@ static struct platform_driver dra7xx_pcie_driver = { }, .shutdown = dra7xx_pcie_shutdown, }; -builtin_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe); +builtin_platform_driver(dra7xx_pcie_driver); diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 27a17a1e4a7c3205a60ee2232d10e1caeb4b1846..1ff4ce24f4b300e05c0276f64456cfa6f99caeb0 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1292,7 +1292,7 @@ exit_unlock: * resumes, hv_pci_restore_msi_state() is able to correctly restore * the interrupt with the correct affinity. */ - if (res && hbus->state != hv_pcibus_removing) + if (!hv_result_success(res) && hbus->state != hv_pcibus_removing) dev_err(&hbus->hdev->device, "%s() failed: %#llx", __func__, res); @@ -1458,7 +1458,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) * Prevents hv_pci_onchannelcallback() from running concurrently * in the tasklet. */ - tasklet_disable(&channel->callback_event); + tasklet_disable_in_atomic(&channel->callback_event); /* * Since this function is called with IRQ locks held, can't diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 16a17215f633ddc40d87faa4329bdfb20a7e2ed5..e4d4e399004b48c1a67df666e4076afc296a36c1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1870,20 +1870,10 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) int err; int i, bars = 0; - /* - * Power state could be unknown at this point, either due to a fresh - * boot or a device removal call. So get the current power state - * so that things like MSI message writing will behave as expected - * (e.g. if the device really is in D0 at enable time). - */ - if (dev->pm_cap) { - u16 pmcsr; - pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); - dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); - } - - if (atomic_inc_return(&dev->enable_cnt) > 1) + if (atomic_inc_return(&dev->enable_cnt) > 1) { + pci_update_current_state(dev, dev->current_state); return 0; /* already enabled */ + } bridge = pci_upstream_bridge(dev); if (bridge) diff --git a/drivers/perf/arm-cci.c b/drivers/perf/arm-cci.c index f81e2ec9000507f04742a4bf22b6a09201c428e3..666d8a9b557fced7e4a51b501a2a76d66c867bcd 100644 --- a/drivers/perf/arm-cci.c +++ b/drivers/perf/arm-cci.c @@ -306,7 +306,7 @@ static ssize_t cci400_pmu_cycle_event_show(struct device *dev, { struct dev_ext_attribute *eattr = container_of(attr, struct dev_ext_attribute, attr); - return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var); + return sysfs_emit(buf, "config=0x%lx\n", (unsigned long)eattr->var); } static int cci400_get_event_idx(struct cci_pmu *cci_pmu, @@ -525,8 +525,8 @@ static ssize_t cci5xx_pmu_global_event_show(struct device *dev, struct dev_ext_attribute *eattr = container_of(attr, struct dev_ext_attribute, attr); /* Global events have single fixed source code */ - return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n", - (unsigned long)eattr->var, CCI5xx_PORT_GLOBAL); + return sysfs_emit(buf, "event=0x%lx,source=0x%x\n", + (unsigned long)eattr->var, CCI5xx_PORT_GLOBAL); } /* @@ -696,7 +696,7 @@ static ssize_t cci_pmu_format_show(struct device *dev, { struct dev_ext_attribute *eattr = container_of(attr, struct dev_ext_attribute, attr); - return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var); + return sysfs_emit(buf, "%s\n", (char *)eattr->var); } static ssize_t cci_pmu_event_show(struct device *dev, @@ -705,8 +705,8 @@ static ssize_t cci_pmu_event_show(struct device *dev, struct dev_ext_attribute *eattr = container_of(attr, struct dev_ext_attribute, attr); /* source parameter is mandatory for normal PMU events */ - return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n", - (unsigned long)eattr->var); + return sysfs_emit(buf, "source=?,event=0x%lx\n", + (unsigned long)eattr->var); } static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx) diff --git a/drivers/perf/arm-ccn.c b/drivers/perf/arm-ccn.c index a0a71c1df042abf25ff8935aa95ca80f7a1565bf..96d47cb302dd1001d907ee9773116a07243d4ae9 100644 --- a/drivers/perf/arm-ccn.c +++ b/drivers/perf/arm-ccn.c @@ -221,7 +221,7 @@ static ssize_t arm_ccn_pmu_format_show(struct device *dev, struct dev_ext_attribute *ea = container_of(attr, struct dev_ext_attribute, attr); - return snprintf(buf, PAGE_SIZE, "%s\n", (char *)ea->var); + return sysfs_emit(buf, "%s\n", (char *)ea->var); } #define CCN_FORMAT_ATTR(_name, _config) \ @@ -326,43 +326,38 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev, struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev)); struct arm_ccn_pmu_event *event = container_of(attr, struct arm_ccn_pmu_event, attr); - ssize_t res; + int res; - res = scnprintf(buf, PAGE_SIZE, "type=0x%x", event->type); + res = sysfs_emit(buf, "type=0x%x", event->type); if (event->event) - res += scnprintf(buf + res, PAGE_SIZE - res, ",event=0x%x", - event->event); + res += sysfs_emit_at(buf, res, ",event=0x%x", event->event); if (event->def) - res += scnprintf(buf + res, PAGE_SIZE - res, ",%s", - event->def); + res += sysfs_emit_at(buf, res, ",%s", event->def); if (event->mask) - res += scnprintf(buf + res, PAGE_SIZE - res, ",mask=0x%x", - event->mask); + res += sysfs_emit_at(buf, res, ",mask=0x%x", event->mask); /* Arguments required by an event */ switch (event->type) { case CCN_TYPE_CYCLES: break; case CCN_TYPE_XP: - res += scnprintf(buf + res, PAGE_SIZE - res, - ",xp=?,vc=?"); + res += sysfs_emit_at(buf, res, ",xp=?,vc=?"); if (event->event == CCN_EVENT_WATCHPOINT) - res += scnprintf(buf + res, PAGE_SIZE - res, + res += sysfs_emit_at(buf, res, ",port=?,dir=?,cmp_l=?,cmp_h=?,mask=?"); else - res += scnprintf(buf + res, PAGE_SIZE - res, - ",bus=?"); + res += sysfs_emit_at(buf, res, ",bus=?"); break; case CCN_TYPE_MN: - res += scnprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id); + res += sysfs_emit_at(buf, res, ",node=%d", ccn->mn_id); break; default: - res += scnprintf(buf + res, PAGE_SIZE - res, ",node=?"); + res += sysfs_emit_at(buf, res, ",node=?"); break; } - res += scnprintf(buf + res, PAGE_SIZE - res, "\n"); + res += sysfs_emit_at(buf, res, "\n"); return res; } @@ -476,7 +471,7 @@ static ssize_t arm_ccn_pmu_cmp_mask_show(struct device *dev, struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev)); u64 *mask = arm_ccn_pmu_get_cmp_mask(ccn, attr->attr.name); - return mask ? snprintf(buf, PAGE_SIZE, "0x%016llx\n", *mask) : -EINVAL; + return mask ? sysfs_emit(buf, "0x%016llx\n", *mask) : -EINVAL; } static ssize_t arm_ccn_pmu_cmp_mask_store(struct device *dev, diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index 1328159fe564d6187177ce1d73bc9ccff18d6835..56a5c355701d0192a5d3429c080032f904b45254 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -348,19 +348,19 @@ static ssize_t arm_cmn_event_show(struct device *dev, eattr = container_of(attr, typeof(*eattr), attr); if (eattr->type == CMN_TYPE_DTC) - return snprintf(buf, PAGE_SIZE, "type=0x%x\n", eattr->type); + return sysfs_emit(buf, "type=0x%x\n", eattr->type); if (eattr->type == CMN_TYPE_WP) - return snprintf(buf, PAGE_SIZE, - "type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n", - eattr->type, eattr->eventid); + return sysfs_emit(buf, + "type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n", + eattr->type, eattr->eventid); if (arm_cmn_is_occup_event(eattr->type, eattr->eventid)) - return snprintf(buf, PAGE_SIZE, "type=0x%x,eventid=0x%x,occupid=0x%x\n", - eattr->type, eattr->eventid, eattr->occupid); + return sysfs_emit(buf, "type=0x%x,eventid=0x%x,occupid=0x%x\n", + eattr->type, eattr->eventid, eattr->occupid); - return snprintf(buf, PAGE_SIZE, "type=0x%x,eventid=0x%x\n", - eattr->type, eattr->eventid); + return sysfs_emit(buf, "type=0x%x,eventid=0x%x\n", eattr->type, + eattr->eventid); } static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj, @@ -560,12 +560,12 @@ static ssize_t arm_cmn_format_show(struct device *dev, int lo = __ffs(fmt->field), hi = __fls(fmt->field); if (lo == hi) - return snprintf(buf, PAGE_SIZE, "config:%d\n", lo); + return sysfs_emit(buf, "config:%d\n", lo); if (!fmt->config) - return snprintf(buf, PAGE_SIZE, "config:%d-%d\n", lo, hi); + return sysfs_emit(buf, "config:%d-%d\n", lo, hi); - return snprintf(buf, PAGE_SIZE, "config%d:%d-%d\n", fmt->config, lo, hi); + return sysfs_emit(buf, "config%d:%d-%d\n", fmt->config, lo, hi); } #define _CMN_FORMAT_ATTR(_name, _cfg, _fld) \ diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c index f2a85500258d0bca8bfb57f01bd0d1b4f545d456..b6c2511d59af27862baffdb9028da48f96197bb2 100644 --- a/drivers/perf/arm_dmc620_pmu.c +++ b/drivers/perf/arm_dmc620_pmu.c @@ -113,7 +113,7 @@ dmc620_pmu_event_show(struct device *dev, eattr = container_of(attr, typeof(*eattr), attr); - return sprintf(page, "event=0x%x,clkdiv2=0x%x\n", eattr->eventid, eattr->clkdiv2); + return sysfs_emit(page, "event=0x%x,clkdiv2=0x%x\n", eattr->eventid, eattr->clkdiv2); } #define DMC620_PMU_EVENT_ATTR(_name, _eventid, _clkdiv2) \ diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c index 0459a340346942f96b41e9afc573d16b4930f74f..196faea074d04be361ec9c0b659058426be82958 100644 --- a/drivers/perf/arm_dsu_pmu.c +++ b/drivers/perf/arm_dsu_pmu.c @@ -136,8 +136,7 @@ static ssize_t dsu_pmu_sysfs_event_show(struct device *dev, { struct dev_ext_attribute *eattr = container_of(attr, struct dev_ext_attribute, attr); - return snprintf(buf, PAGE_SIZE, "event=0x%lx\n", - (unsigned long)eattr->var); + return sysfs_emit(buf, "event=0x%lx\n", (unsigned long)eattr->var); } static ssize_t dsu_pmu_sysfs_format_show(struct device *dev, @@ -146,7 +145,7 @@ static ssize_t dsu_pmu_sysfs_format_show(struct device *dev, { struct dev_ext_attribute *eattr = container_of(attr, struct dev_ext_attribute, attr); - return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var); + return sysfs_emit(buf, "%s\n", (char *)eattr->var); } static ssize_t dsu_pmu_cpumask_show(struct device *dev, diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 933bd8410fc2afa94eb186c6be3c58148ea41837..513de1f54e2d7371ceca11b9427a265394aeadc9 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -6,6 +6,7 @@ * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com> */ #define pr_fmt(fmt) "hw perfevents: " fmt +#define dev_fmt pr_fmt #include <linux/bug.h> #include <linux/cpumask.h> @@ -62,7 +63,7 @@ static bool pmu_has_irq_affinity(struct device_node *node) return !!of_find_property(node, "interrupt-affinity", NULL); } -static int pmu_parse_irq_affinity(struct device_node *node, int i) +static int pmu_parse_irq_affinity(struct device *dev, int i) { struct device_node *dn; int cpu; @@ -72,19 +73,18 @@ static int pmu_parse_irq_affinity(struct device_node *node, int i) * affinity matches our logical CPU order, as we used to assume. * This is fragile, so we'll warn in pmu_parse_irqs(). */ - if (!pmu_has_irq_affinity(node)) + if (!pmu_has_irq_affinity(dev->of_node)) return i; - dn = of_parse_phandle(node, "interrupt-affinity", i); + dn = of_parse_phandle(dev->of_node, "interrupt-affinity", i); if (!dn) { - pr_warn("failed to parse interrupt-affinity[%d] for %pOFn\n", - i, node); + dev_warn(dev, "failed to parse interrupt-affinity[%d]\n", i); return -EINVAL; } cpu = of_cpu_node_to_id(dn); if (cpu < 0) { - pr_warn("failed to find logical CPU for %pOFn\n", dn); + dev_warn(dev, "failed to find logical CPU for %pOFn\n", dn); cpu = nr_cpu_ids; } @@ -98,19 +98,18 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) int i = 0, num_irqs; struct platform_device *pdev = pmu->plat_device; struct pmu_hw_events __percpu *hw_events = pmu->hw_events; + struct device *dev = &pdev->dev; num_irqs = platform_irq_count(pdev); - if (num_irqs < 0) { - pr_err("unable to count PMU IRQs\n"); - return num_irqs; - } + if (num_irqs < 0) + return dev_err_probe(dev, num_irqs, "unable to count PMU IRQs\n"); /* * In this case we have no idea which CPUs are covered by the PMU. * To match our prior behaviour, we assume all CPUs in this case. */ if (num_irqs == 0) { - pr_warn("no irqs for PMU, sampling events not supported\n"); + dev_warn(dev, "no irqs for PMU, sampling events not supported\n"); pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; cpumask_setall(&pmu->supported_cpus); return 0; @@ -122,10 +121,8 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) return pmu_parse_percpu_irq(pmu, irq); } - if (nr_cpu_ids != 1 && !pmu_has_irq_affinity(pdev->dev.of_node)) { - pr_warn("no interrupt-affinity property for %pOF, guessing.\n", - pdev->dev.of_node); - } + if (nr_cpu_ids != 1 && !pmu_has_irq_affinity(dev->of_node)) + dev_warn(dev, "no interrupt-affinity property, guessing.\n"); for (i = 0; i < num_irqs; i++) { int cpu, irq; @@ -135,18 +132,18 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) continue; if (irq_is_percpu_devid(irq)) { - pr_warn("multiple PPIs or mismatched SPI/PPI detected\n"); + dev_warn(dev, "multiple PPIs or mismatched SPI/PPI detected\n"); return -EINVAL; } - cpu = pmu_parse_irq_affinity(pdev->dev.of_node, i); + cpu = pmu_parse_irq_affinity(dev, i); if (cpu < 0) return cpu; if (cpu >= nr_cpu_ids) continue; if (per_cpu(hw_events->irq, cpu)) { - pr_warn("multiple PMU IRQs for the same CPU detected\n"); + dev_warn(dev, "multiple PMU IRQs for the same CPU detected\n"); return -EINVAL; } @@ -191,9 +188,8 @@ int arm_pmu_device_probe(struct platform_device *pdev, const struct of_device_id *of_table, const struct pmu_probe_info *probe_table) { - const struct of_device_id *of_id; armpmu_init_fn init_fn; - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct arm_pmu *pmu; int ret = -ENODEV; @@ -207,15 +203,14 @@ int arm_pmu_device_probe(struct platform_device *pdev, if (ret) goto out_free; - if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { - init_fn = of_id->data; - - pmu->secure_access = of_property_read_bool(pdev->dev.of_node, + init_fn = of_device_get_match_data(dev); + if (init_fn) { + pmu->secure_access = of_property_read_bool(dev->of_node, "secure-reg-access"); /* arm64 systems boot only as non-secure */ if (IS_ENABLED(CONFIG_ARM64) && pmu->secure_access) { - pr_warn("ignoring \"secure-reg-access\" property for arm64\n"); + dev_warn(dev, "ignoring \"secure-reg-access\" property for arm64\n"); pmu->secure_access = false; } @@ -226,7 +221,7 @@ int arm_pmu_device_probe(struct platform_device *pdev, } if (ret) { - pr_info("%pOF: failed to probe PMU!\n", node); + dev_err(dev, "failed to probe PMU!\n"); goto out_free; } @@ -235,15 +230,16 @@ int arm_pmu_device_probe(struct platform_device *pdev, goto out_free_irqs; ret = armpmu_register(pmu); - if (ret) - goto out_free; + if (ret) { + dev_err(dev, "failed to register PMU devices!\n"); + goto out_free_irqs; + } return 0; out_free_irqs: armpmu_free_irqs(pmu); out_free: - pr_info("%pOF: failed to register PMU devices!\n", node); armpmu_free(pmu); return ret; } diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c index 8ff7a67f691cf93b9d9576af74bce580a06317f3..ff6fab4bae30dc1873c4d4299cffacb24a015b66 100644 --- a/drivers/perf/arm_smmuv3_pmu.c +++ b/drivers/perf/arm_smmuv3_pmu.c @@ -506,30 +506,24 @@ static ssize_t smmu_pmu_event_show(struct device *dev, pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); - return sprintf(page, "event=0x%02llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } -#define SMMU_EVENT_ATTR(name, config) \ - PMU_EVENT_ATTR(name, smmu_event_attr_##name, \ - config, smmu_pmu_event_show) -SMMU_EVENT_ATTR(cycles, 0); -SMMU_EVENT_ATTR(transaction, 1); -SMMU_EVENT_ATTR(tlb_miss, 2); -SMMU_EVENT_ATTR(config_cache_miss, 3); -SMMU_EVENT_ATTR(trans_table_walk_access, 4); -SMMU_EVENT_ATTR(config_struct_access, 5); -SMMU_EVENT_ATTR(pcie_ats_trans_rq, 6); -SMMU_EVENT_ATTR(pcie_ats_trans_passed, 7); +#define SMMU_EVENT_ATTR(name, config) \ + (&((struct perf_pmu_events_attr) { \ + .attr = __ATTR(name, 0444, smmu_pmu_event_show, NULL), \ + .id = config, \ + }).attr.attr) static struct attribute *smmu_pmu_events[] = { - &smmu_event_attr_cycles.attr.attr, - &smmu_event_attr_transaction.attr.attr, - &smmu_event_attr_tlb_miss.attr.attr, - &smmu_event_attr_config_cache_miss.attr.attr, - &smmu_event_attr_trans_table_walk_access.attr.attr, - &smmu_event_attr_config_struct_access.attr.attr, - &smmu_event_attr_pcie_ats_trans_rq.attr.attr, - &smmu_event_attr_pcie_ats_trans_passed.attr.attr, + SMMU_EVENT_ATTR(cycles, 0), + SMMU_EVENT_ATTR(transaction, 1), + SMMU_EVENT_ATTR(tlb_miss, 2), + SMMU_EVENT_ATTR(config_cache_miss, 3), + SMMU_EVENT_ATTR(trans_table_walk_access, 4), + SMMU_EVENT_ATTR(config_struct_access, 5), + SMMU_EVENT_ATTR(pcie_ats_trans_rq, 6), + SMMU_EVENT_ATTR(pcie_ats_trans_passed, 7), NULL }; @@ -560,7 +554,7 @@ static ssize_t smmu_pmu_identifier_attr_show(struct device *dev, { struct smmu_pmu *smmu_pmu = to_smmu_pmu(dev_get_drvdata(dev)); - return snprintf(page, PAGE_SIZE, "0x%08x\n", smmu_pmu->iidr); + return sysfs_emit(page, "0x%08x\n", smmu_pmu->iidr); } static umode_t smmu_pmu_identifier_attr_visible(struct kobject *kobj, diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c index d3929ccebfd2fa1dbea1d83dbb1c196d086d5781..8a1e86ab2d8e4d4e878ecb0861d73785ccf67557 100644 --- a/drivers/perf/arm_spe_pmu.c +++ b/drivers/perf/arm_spe_pmu.c @@ -126,8 +126,7 @@ static ssize_t arm_spe_pmu_cap_show(struct device *dev, container_of(attr, struct dev_ext_attribute, attr); int cap = (long)ea->var; - return snprintf(buf, PAGE_SIZE, "%u\n", - arm_spe_pmu_cap_get(spe_pmu, cap)); + return sysfs_emit(buf, "%u\n", arm_spe_pmu_cap_get(spe_pmu, cap)); } #define SPE_EXT_ATTR_ENTRY(_name, _func, _var) \ diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c index be1f26b62ddb8a1540449286a789742e9b374c8e..2bbb9318806495687e2d9ef9dceb968a1cab1dbf 100644 --- a/drivers/perf/fsl_imx8_ddr_perf.c +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -110,7 +110,7 @@ static ssize_t ddr_perf_identifier_show(struct device *dev, { struct ddr_pmu *pmu = dev_get_drvdata(dev); - return sprintf(page, "%s\n", pmu->devtype_data->identifier); + return sysfs_emit(page, "%s\n", pmu->devtype_data->identifier); } static umode_t ddr_perf_identifier_attr_visible(struct kobject *kobj, @@ -170,8 +170,7 @@ static ssize_t ddr_perf_filter_cap_show(struct device *dev, container_of(attr, struct dev_ext_attribute, attr); int cap = (long)ea->var; - return snprintf(buf, PAGE_SIZE, "%u\n", - ddr_perf_filter_cap_get(pmu, cap)); + return sysfs_emit(buf, "%u\n", ddr_perf_filter_cap_get(pmu, cap)); } #define PERF_EXT_ATTR_ENTRY(_name, _func, _var) \ @@ -220,7 +219,7 @@ ddr_pmu_event_show(struct device *dev, struct device_attribute *attr, 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); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } #define IMX8_DDR_PMU_EVENT_ATTR(_name, _id) \ diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile index e8377061845ff77f325c2079ecbe3c9110fb37cd..7643c9f93e367a697b17df3efd7aeef9f5f5643f 100644 --- a/drivers/perf/hisilicon/Makefile +++ b/drivers/perf/hisilicon/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \ - hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o + hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \ + hisi_uncore_pa_pmu.o diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c index ac1a8c120a008c124b7f1b044647ecc39662c42f..7c8a4bc21db4ca2fdc1fed3da1d2e2760a714360 100644 --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c @@ -14,12 +14,11 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/list.h> -#include <linux/platform_device.h> #include <linux/smp.h> #include "hisi_uncore_pmu.h" -/* DDRC register definition */ +/* DDRC register definition in v1 */ #define DDRC_PERF_CTRL 0x010 #define DDRC_FLUX_WR 0x380 #define DDRC_FLUX_RD 0x384 @@ -35,12 +34,24 @@ #define DDRC_INT_CLEAR 0x6d0 #define DDRC_VERSION 0x710 +/* DDRC register definition in v2 */ +#define DDRC_V2_INT_MASK 0x528 +#define DDRC_V2_INT_STATUS 0x52c +#define DDRC_V2_INT_CLEAR 0x530 +#define DDRC_V2_EVENT_CNT 0xe00 +#define DDRC_V2_EVENT_CTRL 0xe70 +#define DDRC_V2_EVENT_TYPE 0xe74 +#define DDRC_V2_PERF_CTRL 0xeA0 + /* DDRC has 8-counters */ #define DDRC_NR_COUNTERS 0x8 -#define DDRC_PERF_CTRL_EN 0x2 +#define DDRC_V1_PERF_CTRL_EN 0x2 +#define DDRC_V2_PERF_CTRL_EN 0x1 +#define DDRC_V1_NR_EVENTS 0x7 +#define DDRC_V2_NR_EVENTS 0x90 /* - * For DDRC PMU, there are eight-events and every event has been mapped + * For PMU v1, there are eight-events and every event has been mapped * to fixed-purpose counters which register offset is not consistent. * Therefore there is no write event type and we assume that event * code (0 to 7) is equal to counter index in PMU driver. @@ -54,73 +65,85 @@ static const u32 ddrc_reg_off[] = { /* * Select the counter register offset using the counter index. - * In DDRC there are no programmable counter, the count - * is readed form the statistics counter register itself. + * In PMU v1, there are no programmable counter, the count + * is read form the statistics counter register itself. */ -static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx) +static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx) { return ddrc_reg_off[cntr_idx]; } -static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu, - struct hw_perf_event *hwc) +static u32 hisi_ddrc_pmu_v2_get_counter_offset(int cntr_idx) { - /* Use event code as counter index */ - u32 idx = GET_DDRC_EVENTID(hwc); - - if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) { - dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx); - return 0; - } + return DDRC_V2_EVENT_CNT + cntr_idx * 8; +} - return readl(ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx)); +static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) +{ + return readl(ddrc_pmu->base + + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx)); } -static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu, +static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu, struct hw_perf_event *hwc, u64 val) { - u32 idx = GET_DDRC_EVENTID(hwc); + writel((u32)val, + ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx)); +} - if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) { - dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx); - return; - } +static u64 hisi_ddrc_pmu_v2_read_counter(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) +{ + return readq(ddrc_pmu->base + + hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx)); +} - writel((u32)val, - ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx)); +static void hisi_ddrc_pmu_v2_write_counter(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc, u64 val) +{ + writeq(val, + ddrc_pmu->base + hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx)); } /* - * For DDRC PMU, event has been mapped to fixed-purpose counter by hardware, - * so there is no need to write event type. + * For DDRC PMU v1, event has been mapped to fixed-purpose counter by hardware, + * so there is no need to write event type, while it is programmable counter in + * PMU v2. */ static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx, u32 type) { + u32 offset; + + if (hha_pmu->identifier >= HISI_PMU_V2) { + offset = DDRC_V2_EVENT_TYPE + 4 * idx; + writel(type, hha_pmu->base + offset); + } } -static void hisi_ddrc_pmu_start_counters(struct hisi_pmu *ddrc_pmu) +static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu) { u32 val; /* Set perf_enable in DDRC_PERF_CTRL to start event counting */ val = readl(ddrc_pmu->base + DDRC_PERF_CTRL); - val |= DDRC_PERF_CTRL_EN; + val |= DDRC_V1_PERF_CTRL_EN; writel(val, ddrc_pmu->base + DDRC_PERF_CTRL); } -static void hisi_ddrc_pmu_stop_counters(struct hisi_pmu *ddrc_pmu) +static void hisi_ddrc_pmu_v1_stop_counters(struct hisi_pmu *ddrc_pmu) { u32 val; /* Clear perf_enable in DDRC_PERF_CTRL to stop event counting */ val = readl(ddrc_pmu->base + DDRC_PERF_CTRL); - val &= ~DDRC_PERF_CTRL_EN; + val &= ~DDRC_V1_PERF_CTRL_EN; writel(val, ddrc_pmu->base + DDRC_PERF_CTRL); } -static void hisi_ddrc_pmu_enable_counter(struct hisi_pmu *ddrc_pmu, - struct hw_perf_event *hwc) +static void hisi_ddrc_pmu_v1_enable_counter(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) { u32 val; @@ -130,8 +153,8 @@ static void hisi_ddrc_pmu_enable_counter(struct hisi_pmu *ddrc_pmu, writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL); } -static void hisi_ddrc_pmu_disable_counter(struct hisi_pmu *ddrc_pmu, - struct hw_perf_event *hwc) +static void hisi_ddrc_pmu_v1_disable_counter(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) { u32 val; @@ -141,7 +164,7 @@ static void hisi_ddrc_pmu_disable_counter(struct hisi_pmu *ddrc_pmu, writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL); } -static int hisi_ddrc_pmu_get_event_idx(struct perf_event *event) +static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event) { struct hisi_pmu *ddrc_pmu = to_hisi_pmu(event->pmu); unsigned long *used_mask = ddrc_pmu->pmu_events.used_mask; @@ -157,87 +180,117 @@ static int hisi_ddrc_pmu_get_event_idx(struct perf_event *event) return idx; } -static void hisi_ddrc_pmu_enable_counter_int(struct hisi_pmu *ddrc_pmu, +static int hisi_ddrc_pmu_v2_get_event_idx(struct perf_event *event) +{ + return hisi_uncore_pmu_get_event_idx(event); +} + +static void hisi_ddrc_pmu_v2_start_counters(struct hisi_pmu *ddrc_pmu) +{ + u32 val; + + val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL); + val |= DDRC_V2_PERF_CTRL_EN; + writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL); +} + +static void hisi_ddrc_pmu_v2_stop_counters(struct hisi_pmu *ddrc_pmu) +{ + u32 val; + + val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL); + val &= ~DDRC_V2_PERF_CTRL_EN; + writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL); +} + +static void hisi_ddrc_pmu_v2_enable_counter(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL); + val |= 1 << hwc->idx; + writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL); +} + +static void hisi_ddrc_pmu_v2_disable_counter(struct hisi_pmu *ddrc_pmu, struct hw_perf_event *hwc) { u32 val; + val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL); + val &= ~(1 << hwc->idx); + writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL); +} + +static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + /* Write 0 to enable interrupt */ val = readl(ddrc_pmu->base + DDRC_INT_MASK); - val &= ~(1 << GET_DDRC_EVENTID(hwc)); + val &= ~(1 << hwc->idx); writel(val, ddrc_pmu->base + DDRC_INT_MASK); } -static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu, - struct hw_perf_event *hwc) +static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) { u32 val; /* Write 1 to mask interrupt */ val = readl(ddrc_pmu->base + DDRC_INT_MASK); - val |= (1 << GET_DDRC_EVENTID(hwc)); + val |= 1 << hwc->idx; writel(val, ddrc_pmu->base + DDRC_INT_MASK); } -static irqreturn_t hisi_ddrc_pmu_isr(int irq, void *dev_id) +static void hisi_ddrc_pmu_v2_enable_counter_int(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) { - struct hisi_pmu *ddrc_pmu = dev_id; - struct perf_event *event; - unsigned long overflown; - int idx; - - /* Read the DDRC_INT_STATUS register */ - overflown = readl(ddrc_pmu->base + DDRC_INT_STATUS); - if (!overflown) - return IRQ_NONE; + u32 val; - /* - * Find the counter index which overflowed if the bit was set - * and handle it - */ - for_each_set_bit(idx, &overflown, DDRC_NR_COUNTERS) { - /* Write 1 to clear the IRQ status flag */ - writel((1 << idx), ddrc_pmu->base + DDRC_INT_CLEAR); + val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK); + val &= ~(1 << hwc->idx); + writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK); +} - /* Get the corresponding event struct */ - event = ddrc_pmu->pmu_events.hw_events[idx]; - if (!event) - continue; +static void hisi_ddrc_pmu_v2_disable_counter_int(struct hisi_pmu *ddrc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; - hisi_uncore_pmu_event_update(event); - hisi_uncore_pmu_set_event_period(event); - } + val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK); + val |= 1 << hwc->idx; + writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK); +} - return IRQ_HANDLED; +static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu) +{ + return readl(ddrc_pmu->base + DDRC_INT_STATUS); } -static int hisi_ddrc_pmu_init_irq(struct hisi_pmu *ddrc_pmu, - struct platform_device *pdev) +static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu, + int idx) { - int irq, ret; - - /* Read and init IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(&pdev->dev, irq, hisi_ddrc_pmu_isr, - IRQF_NOBALANCING | IRQF_NO_THREAD, - dev_name(&pdev->dev), ddrc_pmu); - if (ret < 0) { - dev_err(&pdev->dev, - "Fail to request IRQ:%d ret:%d\n", irq, ret); - return ret; - } + writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR); +} - ddrc_pmu->irq = irq; +static u32 hisi_ddrc_pmu_v2_get_int_status(struct hisi_pmu *ddrc_pmu) +{ + return readl(ddrc_pmu->base + DDRC_V2_INT_STATUS); +} - return 0; +static void hisi_ddrc_pmu_v2_clear_int_status(struct hisi_pmu *ddrc_pmu, + int idx) +{ + writel(1 << idx, ddrc_pmu->base + DDRC_V2_INT_CLEAR); } static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = { { "HISI0233", }, - {}, + { "HISI0234", }, + {} }; MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_acpi_match); @@ -269,21 +322,38 @@ static int hisi_ddrc_pmu_init_data(struct platform_device *pdev, } ddrc_pmu->identifier = readl(ddrc_pmu->base + DDRC_VERSION); + if (ddrc_pmu->identifier >= HISI_PMU_V2) { + if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id", + &ddrc_pmu->sub_id)) { + dev_err(&pdev->dev, "Can not read sub-id!\n"); + return -EINVAL; + } + } return 0; } -static struct attribute *hisi_ddrc_pmu_format_attr[] = { +static struct attribute *hisi_ddrc_pmu_v1_format_attr[] = { HISI_PMU_FORMAT_ATTR(event, "config:0-4"), NULL, }; -static const struct attribute_group hisi_ddrc_pmu_format_group = { +static const struct attribute_group hisi_ddrc_pmu_v1_format_group = { + .name = "format", + .attrs = hisi_ddrc_pmu_v1_format_attr, +}; + +static struct attribute *hisi_ddrc_pmu_v2_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-7"), + NULL +}; + +static const struct attribute_group hisi_ddrc_pmu_v2_format_group = { .name = "format", - .attrs = hisi_ddrc_pmu_format_attr, + .attrs = hisi_ddrc_pmu_v2_format_attr, }; -static struct attribute *hisi_ddrc_pmu_events_attr[] = { +static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = { HISI_PMU_EVENT_ATTR(flux_wr, 0x00), HISI_PMU_EVENT_ATTR(flux_rd, 0x01), HISI_PMU_EVENT_ATTR(flux_wcmd, 0x02), @@ -295,9 +365,21 @@ static struct attribute *hisi_ddrc_pmu_events_attr[] = { NULL, }; -static const struct attribute_group hisi_ddrc_pmu_events_group = { +static const struct attribute_group hisi_ddrc_pmu_v1_events_group = { .name = "events", - .attrs = hisi_ddrc_pmu_events_attr, + .attrs = hisi_ddrc_pmu_v1_events_attr, +}; + +static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = { + HISI_PMU_EVENT_ATTR(cycles, 0x00), + HISI_PMU_EVENT_ATTR(flux_wr, 0x83), + HISI_PMU_EVENT_ATTR(flux_rd, 0x84), + NULL +}; + +static const struct attribute_group hisi_ddrc_pmu_v2_events_group = { + .name = "events", + .attrs = hisi_ddrc_pmu_v2_events_attr, }; static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); @@ -323,25 +405,50 @@ static const struct attribute_group hisi_ddrc_pmu_identifier_group = { .attrs = hisi_ddrc_pmu_identifier_attrs, }; -static const struct attribute_group *hisi_ddrc_pmu_attr_groups[] = { - &hisi_ddrc_pmu_format_group, - &hisi_ddrc_pmu_events_group, +static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = { + &hisi_ddrc_pmu_v1_format_group, + &hisi_ddrc_pmu_v1_events_group, &hisi_ddrc_pmu_cpumask_attr_group, &hisi_ddrc_pmu_identifier_group, NULL, }; -static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = { +static const struct attribute_group *hisi_ddrc_pmu_v2_attr_groups[] = { + &hisi_ddrc_pmu_v2_format_group, + &hisi_ddrc_pmu_v2_events_group, + &hisi_ddrc_pmu_cpumask_attr_group, + &hisi_ddrc_pmu_identifier_group, + NULL +}; + +static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = { + .write_evtype = hisi_ddrc_pmu_write_evtype, + .get_event_idx = hisi_ddrc_pmu_v1_get_event_idx, + .start_counters = hisi_ddrc_pmu_v1_start_counters, + .stop_counters = hisi_ddrc_pmu_v1_stop_counters, + .enable_counter = hisi_ddrc_pmu_v1_enable_counter, + .disable_counter = hisi_ddrc_pmu_v1_disable_counter, + .enable_counter_int = hisi_ddrc_pmu_v1_enable_counter_int, + .disable_counter_int = hisi_ddrc_pmu_v1_disable_counter_int, + .write_counter = hisi_ddrc_pmu_v1_write_counter, + .read_counter = hisi_ddrc_pmu_v1_read_counter, + .get_int_status = hisi_ddrc_pmu_v1_get_int_status, + .clear_int_status = hisi_ddrc_pmu_v1_clear_int_status, +}; + +static const struct hisi_uncore_ops hisi_uncore_ddrc_v2_ops = { .write_evtype = hisi_ddrc_pmu_write_evtype, - .get_event_idx = hisi_ddrc_pmu_get_event_idx, - .start_counters = hisi_ddrc_pmu_start_counters, - .stop_counters = hisi_ddrc_pmu_stop_counters, - .enable_counter = hisi_ddrc_pmu_enable_counter, - .disable_counter = hisi_ddrc_pmu_disable_counter, - .enable_counter_int = hisi_ddrc_pmu_enable_counter_int, - .disable_counter_int = hisi_ddrc_pmu_disable_counter_int, - .write_counter = hisi_ddrc_pmu_write_counter, - .read_counter = hisi_ddrc_pmu_read_counter, + .get_event_idx = hisi_ddrc_pmu_v2_get_event_idx, + .start_counters = hisi_ddrc_pmu_v2_start_counters, + .stop_counters = hisi_ddrc_pmu_v2_stop_counters, + .enable_counter = hisi_ddrc_pmu_v2_enable_counter, + .disable_counter = hisi_ddrc_pmu_v2_disable_counter, + .enable_counter_int = hisi_ddrc_pmu_v2_enable_counter_int, + .disable_counter_int = hisi_ddrc_pmu_v2_disable_counter_int, + .write_counter = hisi_ddrc_pmu_v2_write_counter, + .read_counter = hisi_ddrc_pmu_v2_read_counter, + .get_int_status = hisi_ddrc_pmu_v2_get_int_status, + .clear_int_status = hisi_ddrc_pmu_v2_clear_int_status, }; static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev, @@ -353,16 +460,25 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev, if (ret) return ret; - ret = hisi_ddrc_pmu_init_irq(ddrc_pmu, pdev); + ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev); if (ret) return ret; + if (ddrc_pmu->identifier >= HISI_PMU_V2) { + ddrc_pmu->counter_bits = 48; + ddrc_pmu->check_event = DDRC_V2_NR_EVENTS; + ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v2_attr_groups; + ddrc_pmu->ops = &hisi_uncore_ddrc_v2_ops; + } else { + ddrc_pmu->counter_bits = 32; + ddrc_pmu->check_event = DDRC_V1_NR_EVENTS; + ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v1_attr_groups; + ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops; + } + ddrc_pmu->num_counters = DDRC_NR_COUNTERS; - ddrc_pmu->counter_bits = 32; - ddrc_pmu->ops = &hisi_uncore_ddrc_ops; ddrc_pmu->dev = &pdev->dev; ddrc_pmu->on_cpu = -1; - ddrc_pmu->check_event = 7; return 0; } @@ -390,8 +506,16 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev) return ret; } - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u", - ddrc_pmu->sccl_id, ddrc_pmu->index_id); + if (ddrc_pmu->identifier >= HISI_PMU_V2) + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "hisi_sccl%u_ddrc%u_%u", + ddrc_pmu->sccl_id, ddrc_pmu->index_id, + ddrc_pmu->sub_id); + else + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id, + ddrc_pmu->index_id); + ddrc_pmu->pmu = (struct pmu) { .name = name, .module = THIS_MODULE, @@ -404,7 +528,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev) .start = hisi_uncore_pmu_start, .stop = hisi_uncore_pmu_stop, .read = hisi_uncore_pmu_read, - .attr_groups = hisi_ddrc_pmu_attr_groups, + .attr_groups = ddrc_pmu->pmu_events.attr_groups, .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c index 3402f1a395a89e3196a6fecc664d41e2887dc30c..0316fabe32f1a1fc79928e9bd92a19af8e4dd35b 100644 --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/list.h> -#include <linux/platform_device.h> #include <linux/smp.h> #include "hisi_uncore_pmu.h" @@ -26,18 +25,136 @@ #define HHA_VERSION 0x1cf0 #define HHA_PERF_CTRL 0x1E00 #define HHA_EVENT_CTRL 0x1E04 +#define HHA_SRCID_CTRL 0x1E08 +#define HHA_DATSRC_CTRL 0x1BF0 #define HHA_EVENT_TYPE0 0x1E80 /* - * Each counter is 48-bits and [48:63] are reserved - * which are Read-As-Zero and Writes-Ignored. + * If the HW version only supports a 48-bit counter, then + * bits [63:48] are reserved, which are Read-As-Zero and + * Writes-Ignored. */ #define HHA_CNT0_LOWER 0x1F00 -/* HHA has 16-counters */ -#define HHA_NR_COUNTERS 0x10 +/* HHA PMU v1 has 16 counters and v2 only has 8 counters */ +#define HHA_V1_NR_COUNTERS 0x10 +#define HHA_V2_NR_COUNTERS 0x8 #define HHA_PERF_CTRL_EN 0x1 +#define HHA_TRACETAG_EN BIT(31) +#define HHA_SRCID_EN BIT(2) +#define HHA_SRCID_CMD_SHIFT 6 +#define HHA_SRCID_MSK_SHIFT 20 +#define HHA_SRCID_CMD GENMASK(16, 6) +#define HHA_SRCID_MSK GENMASK(30, 20) +#define HHA_DATSRC_SKT_EN BIT(23) #define HHA_EVTYPE_NONE 0xff +#define HHA_V1_NR_EVENT 0x65 +#define HHA_V2_NR_EVENT 0xCE + +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 10, 0); +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 21, 11); +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 22, 22); +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 23, 23); + +static void hisi_hha_pmu_enable_tracetag(struct perf_event *event) +{ + struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); + u32 tt_en = hisi_get_tracetag_en(event); + + if (tt_en) { + u32 val; + + val = readl(hha_pmu->base + HHA_SRCID_CTRL); + val |= HHA_TRACETAG_EN; + writel(val, hha_pmu->base + HHA_SRCID_CTRL); + } +} + +static void hisi_hha_pmu_clear_tracetag(struct perf_event *event) +{ + struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); + u32 val; + + val = readl(hha_pmu->base + HHA_SRCID_CTRL); + val &= ~HHA_TRACETAG_EN; + writel(val, hha_pmu->base + HHA_SRCID_CTRL); +} + +static void hisi_hha_pmu_config_ds(struct perf_event *event) +{ + struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); + u32 ds_skt = hisi_get_datasrc_skt(event); + + if (ds_skt) { + u32 val; + + val = readl(hha_pmu->base + HHA_DATSRC_CTRL); + val |= HHA_DATSRC_SKT_EN; + writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL); + } +} + +static void hisi_hha_pmu_clear_ds(struct perf_event *event) +{ + struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); + u32 ds_skt = hisi_get_datasrc_skt(event); + + if (ds_skt) { + u32 val; + + val = readl(hha_pmu->base + HHA_DATSRC_CTRL); + val &= ~HHA_DATSRC_SKT_EN; + writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL); + } +} + +static void hisi_hha_pmu_config_srcid(struct perf_event *event) +{ + struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_srcid_cmd(event); + + if (cmd) { + u32 val, msk; + + msk = hisi_get_srcid_msk(event); + val = readl(hha_pmu->base + HHA_SRCID_CTRL); + val |= HHA_SRCID_EN | (cmd << HHA_SRCID_CMD_SHIFT) | + (msk << HHA_SRCID_MSK_SHIFT); + writel(val, hha_pmu->base + HHA_SRCID_CTRL); + } +} + +static void hisi_hha_pmu_disable_srcid(struct perf_event *event) +{ + struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_srcid_cmd(event); + + if (cmd) { + u32 val; + + val = readl(hha_pmu->base + HHA_SRCID_CTRL); + val &= ~(HHA_SRCID_EN | HHA_SRCID_MSK | HHA_SRCID_CMD); + writel(val, hha_pmu->base + HHA_SRCID_CTRL); + } +} + +static void hisi_hha_pmu_enable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_hha_pmu_enable_tracetag(event); + hisi_hha_pmu_config_ds(event); + hisi_hha_pmu_config_srcid(event); + } +} + +static void hisi_hha_pmu_disable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_hha_pmu_disable_srcid(event); + hisi_hha_pmu_clear_ds(event); + hisi_hha_pmu_clear_tracetag(event); + } +} /* * Select the counter register offset using the counter index @@ -51,29 +168,15 @@ static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx) static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu, struct hw_perf_event *hwc) { - u32 idx = hwc->idx; - - if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) { - dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx); - return 0; - } - /* Read 64 bits and like L3C, top 16 bits are RAZ */ - return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx)); + return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx)); } static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu, struct hw_perf_event *hwc, u64 val) { - u32 idx = hwc->idx; - - if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) { - dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx); - return; - } - /* Write 64 bits and like L3C, top 16 bits are WI */ - writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx)); + writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx)); } static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx, @@ -169,65 +272,20 @@ static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu, writel(val, hha_pmu->base + HHA_INT_MASK); } -static irqreturn_t hisi_hha_pmu_isr(int irq, void *dev_id) +static u32 hisi_hha_pmu_get_int_status(struct hisi_pmu *hha_pmu) { - struct hisi_pmu *hha_pmu = dev_id; - struct perf_event *event; - unsigned long overflown; - int idx; - - /* Read HHA_INT_STATUS register */ - overflown = readl(hha_pmu->base + HHA_INT_STATUS); - if (!overflown) - return IRQ_NONE; - - /* - * Find the counter index which overflowed if the bit was set - * and handle it - */ - for_each_set_bit(idx, &overflown, HHA_NR_COUNTERS) { - /* Write 1 to clear the IRQ status flag */ - writel((1 << idx), hha_pmu->base + HHA_INT_CLEAR); - - /* Get the corresponding event struct */ - event = hha_pmu->pmu_events.hw_events[idx]; - if (!event) - continue; - - hisi_uncore_pmu_event_update(event); - hisi_uncore_pmu_set_event_period(event); - } - - return IRQ_HANDLED; + return readl(hha_pmu->base + HHA_INT_STATUS); } -static int hisi_hha_pmu_init_irq(struct hisi_pmu *hha_pmu, - struct platform_device *pdev) +static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx) { - int irq, ret; - - /* Read and init IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(&pdev->dev, irq, hisi_hha_pmu_isr, - IRQF_NOBALANCING | IRQF_NO_THREAD, - dev_name(&pdev->dev), hha_pmu); - if (ret < 0) { - dev_err(&pdev->dev, - "Fail to request IRQ:%d ret:%d\n", irq, ret); - return ret; - } - - hha_pmu->irq = irq; - - return 0; + writel(1 << idx, hha_pmu->base + HHA_INT_CLEAR); } static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = { { "HISI0243", }, - {}, + { "HISI0244", }, + {} }; MODULE_DEVICE_TABLE(acpi, hisi_hha_pmu_acpi_match); @@ -237,13 +295,6 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev, unsigned long long id; acpi_status status; - status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev), - "_UID", NULL, &id); - if (ACPI_FAILURE(status)) - return -EINVAL; - - hha_pmu->index_id = id; - /* * Use SCCL_ID and UID to identify the HHA PMU, while * SCCL_ID is in MPIDR[aff2]. @@ -253,6 +304,22 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev, dev_err(&pdev->dev, "Can not read hha sccl-id!\n"); return -EINVAL; } + + /* + * Early versions of BIOS support _UID by mistake, so we support + * both "hisilicon, idx-id" as preference, if available. + */ + if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id", + &hha_pmu->index_id)) { + status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev), + "_UID", NULL, &id); + if (ACPI_FAILURE(status)) { + dev_err(&pdev->dev, "Cannot read idx-id!\n"); + return -EINVAL; + } + + hha_pmu->index_id = id; + } /* HHA PMUs only share the same SCCL */ hha_pmu->ccl_id = -1; @@ -267,17 +334,31 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev, return 0; } -static struct attribute *hisi_hha_pmu_format_attr[] = { +static struct attribute *hisi_hha_pmu_v1_format_attr[] = { HISI_PMU_FORMAT_ATTR(event, "config:0-7"), NULL, }; -static const struct attribute_group hisi_hha_pmu_format_group = { +static const struct attribute_group hisi_hha_pmu_v1_format_group = { + .name = "format", + .attrs = hisi_hha_pmu_v1_format_attr, +}; + +static struct attribute *hisi_hha_pmu_v2_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-7"), + HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:0-10"), + HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:11-21"), + HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:22"), + HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:23"), + NULL +}; + +static const struct attribute_group hisi_hha_pmu_v2_format_group = { .name = "format", - .attrs = hisi_hha_pmu_format_attr, + .attrs = hisi_hha_pmu_v2_format_attr, }; -static struct attribute *hisi_hha_pmu_events_attr[] = { +static struct attribute *hisi_hha_pmu_v1_events_attr[] = { HISI_PMU_EVENT_ATTR(rx_ops_num, 0x00), HISI_PMU_EVENT_ATTR(rx_outer, 0x01), HISI_PMU_EVENT_ATTR(rx_sccl, 0x02), @@ -307,9 +388,23 @@ static struct attribute *hisi_hha_pmu_events_attr[] = { NULL, }; -static const struct attribute_group hisi_hha_pmu_events_group = { +static const struct attribute_group hisi_hha_pmu_v1_events_group = { .name = "events", - .attrs = hisi_hha_pmu_events_attr, + .attrs = hisi_hha_pmu_v1_events_attr, +}; + +static struct attribute *hisi_hha_pmu_v2_events_attr[] = { + HISI_PMU_EVENT_ATTR(rx_ops_num, 0x00), + HISI_PMU_EVENT_ATTR(rx_outer, 0x01), + HISI_PMU_EVENT_ATTR(rx_sccl, 0x02), + HISI_PMU_EVENT_ATTR(hha_retry, 0x2e), + HISI_PMU_EVENT_ATTR(cycles, 0x55), + NULL +}; + +static const struct attribute_group hisi_hha_pmu_v2_events_group = { + .name = "events", + .attrs = hisi_hha_pmu_v2_events_attr, }; static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); @@ -335,14 +430,22 @@ static const struct attribute_group hisi_hha_pmu_identifier_group = { .attrs = hisi_hha_pmu_identifier_attrs, }; -static const struct attribute_group *hisi_hha_pmu_attr_groups[] = { - &hisi_hha_pmu_format_group, - &hisi_hha_pmu_events_group, +static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = { + &hisi_hha_pmu_v1_format_group, + &hisi_hha_pmu_v1_events_group, &hisi_hha_pmu_cpumask_attr_group, &hisi_hha_pmu_identifier_group, NULL, }; +static const struct attribute_group *hisi_hha_pmu_v2_attr_groups[] = { + &hisi_hha_pmu_v2_format_group, + &hisi_hha_pmu_v2_events_group, + &hisi_hha_pmu_cpumask_attr_group, + &hisi_hha_pmu_identifier_group, + NULL +}; + static const struct hisi_uncore_ops hisi_uncore_hha_ops = { .write_evtype = hisi_hha_pmu_write_evtype, .get_event_idx = hisi_uncore_pmu_get_event_idx, @@ -354,6 +457,10 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = { .disable_counter_int = hisi_hha_pmu_disable_counter_int, .write_counter = hisi_hha_pmu_write_counter, .read_counter = hisi_hha_pmu_read_counter, + .get_int_status = hisi_hha_pmu_get_int_status, + .clear_int_status = hisi_hha_pmu_clear_int_status, + .enable_filter = hisi_hha_pmu_enable_filter, + .disable_filter = hisi_hha_pmu_disable_filter, }; static int hisi_hha_pmu_dev_probe(struct platform_device *pdev, @@ -365,16 +472,24 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev, if (ret) return ret; - ret = hisi_hha_pmu_init_irq(hha_pmu, pdev); + ret = hisi_uncore_pmu_init_irq(hha_pmu, pdev); if (ret) return ret; - hha_pmu->num_counters = HHA_NR_COUNTERS; - hha_pmu->counter_bits = 48; + if (hha_pmu->identifier >= HISI_PMU_V2) { + hha_pmu->counter_bits = 64; + hha_pmu->check_event = HHA_V2_NR_EVENT; + hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v2_attr_groups; + hha_pmu->num_counters = HHA_V2_NR_COUNTERS; + } else { + hha_pmu->counter_bits = 48; + hha_pmu->check_event = HHA_V1_NR_EVENT; + hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v1_attr_groups; + hha_pmu->num_counters = HHA_V1_NR_COUNTERS; + } hha_pmu->ops = &hisi_uncore_hha_ops; hha_pmu->dev = &pdev->dev; hha_pmu->on_cpu = -1; - hha_pmu->check_event = 0x65; return 0; } @@ -416,7 +531,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev) .start = hisi_uncore_pmu_start, .stop = hisi_uncore_pmu_stop, .read = hisi_uncore_pmu_read, - .attr_groups = hisi_hha_pmu_attr_groups, + .attr_groups = hha_pmu->pmu_events.attr_groups, .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c index 7d792435c2aa4e2f7889a8a022777ae90f3461e3..bf9f7772cac96e30e73e92dddb44f9daedbf350e 100644 --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/list.h> -#include <linux/platform_device.h> #include <linux/smp.h> #include "hisi_uncore_pmu.h" @@ -24,12 +23,17 @@ #define L3C_INT_MASK 0x0800 #define L3C_INT_STATUS 0x0808 #define L3C_INT_CLEAR 0x080c +#define L3C_CORE_CTRL 0x1b04 +#define L3C_TRACETAG_CTRL 0x1b20 +#define L3C_DATSRC_TYPE 0x1b48 +#define L3C_DATSRC_CTRL 0x1bf0 #define L3C_EVENT_CTRL 0x1c00 #define L3C_VERSION 0x1cf0 #define L3C_EVENT_TYPE0 0x1d00 /* - * Each counter is 48-bits and [48:63] are reserved - * which are Read-As-Zero and Writes-Ignored. + * If the HW version only supports a 48-bit counter, then + * bits [63:48] are reserved, which are Read-As-Zero and + * Writes-Ignored. */ #define L3C_CNTR0_LOWER 0x1e00 @@ -37,7 +41,186 @@ #define L3C_NR_COUNTERS 0x8 #define L3C_PERF_CTRL_EN 0x10000 +#define L3C_TRACETAG_EN BIT(31) +#define L3C_TRACETAG_REQ_SHIFT 7 +#define L3C_TRACETAG_MARK_EN BIT(0) +#define L3C_TRACETAG_REQ_EN (L3C_TRACETAG_MARK_EN | BIT(2)) +#define L3C_TRACETAG_CORE_EN (L3C_TRACETAG_MARK_EN | BIT(3)) +#define L3C_CORE_EN BIT(20) +#define L3C_COER_NONE 0x0 +#define L3C_DATSRC_MASK 0xFF +#define L3C_DATSRC_SKT_EN BIT(23) +#define L3C_DATSRC_NONE 0x0 #define L3C_EVTYPE_NONE 0xff +#define L3C_V1_NR_EVENTS 0x59 +#define L3C_V2_NR_EVENTS 0xFF + +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config1, 7, 0); +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8); +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11); +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16); + +static void hisi_l3c_pmu_config_req_tracetag(struct perf_event *event) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + u32 tt_req = hisi_get_tt_req(event); + + if (tt_req) { + u32 val; + + /* Set request-type for tracetag */ + val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL); + val |= tt_req << L3C_TRACETAG_REQ_SHIFT; + val |= L3C_TRACETAG_REQ_EN; + writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL); + + /* Enable request-tracetag statistics */ + val = readl(l3c_pmu->base + L3C_PERF_CTRL); + val |= L3C_TRACETAG_EN; + writel(val, l3c_pmu->base + L3C_PERF_CTRL); + } +} + +static void hisi_l3c_pmu_clear_req_tracetag(struct perf_event *event) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + u32 tt_req = hisi_get_tt_req(event); + + if (tt_req) { + u32 val; + + /* Clear request-type */ + val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL); + val &= ~(tt_req << L3C_TRACETAG_REQ_SHIFT); + val &= ~L3C_TRACETAG_REQ_EN; + writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL); + + /* Disable request-tracetag statistics */ + val = readl(l3c_pmu->base + L3C_PERF_CTRL); + val &= ~L3C_TRACETAG_EN; + writel(val, l3c_pmu->base + L3C_PERF_CTRL); + } +} + +static void hisi_l3c_pmu_write_ds(struct perf_event *event, u32 ds_cfg) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u32 reg, reg_idx, shift, val; + int idx = hwc->idx; + + /* + * Select the appropriate datasource register(L3C_DATSRC_TYPE0/1). + * There are 2 datasource ctrl register for the 8 hardware counters. + * Datasrc is 8-bits and for the former 4 hardware counters, + * L3C_DATSRC_TYPE0 is chosen. For the latter 4 hardware counters, + * L3C_DATSRC_TYPE1 is chosen. + */ + reg = L3C_DATSRC_TYPE + (idx / 4) * 4; + reg_idx = idx % 4; + shift = 8 * reg_idx; + + val = readl(l3c_pmu->base + reg); + val &= ~(L3C_DATSRC_MASK << shift); + val |= ds_cfg << shift; + writel(val, l3c_pmu->base + reg); +} + +static void hisi_l3c_pmu_config_ds(struct perf_event *event) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + u32 ds_cfg = hisi_get_datasrc_cfg(event); + u32 ds_skt = hisi_get_datasrc_skt(event); + + if (ds_cfg) + hisi_l3c_pmu_write_ds(event, ds_cfg); + + if (ds_skt) { + u32 val; + + val = readl(l3c_pmu->base + L3C_DATSRC_CTRL); + val |= L3C_DATSRC_SKT_EN; + writel(val, l3c_pmu->base + L3C_DATSRC_CTRL); + } +} + +static void hisi_l3c_pmu_clear_ds(struct perf_event *event) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + u32 ds_cfg = hisi_get_datasrc_cfg(event); + u32 ds_skt = hisi_get_datasrc_skt(event); + + if (ds_cfg) + hisi_l3c_pmu_write_ds(event, L3C_DATSRC_NONE); + + if (ds_skt) { + u32 val; + + val = readl(l3c_pmu->base + L3C_DATSRC_CTRL); + val &= ~L3C_DATSRC_SKT_EN; + writel(val, l3c_pmu->base + L3C_DATSRC_CTRL); + } +} + +static void hisi_l3c_pmu_config_core_tracetag(struct perf_event *event) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + u32 core = hisi_get_tt_core(event); + + if (core) { + u32 val; + + /* Config and enable core information */ + writel(core, l3c_pmu->base + L3C_CORE_CTRL); + val = readl(l3c_pmu->base + L3C_PERF_CTRL); + val |= L3C_CORE_EN; + writel(val, l3c_pmu->base + L3C_PERF_CTRL); + + /* Enable core-tracetag statistics */ + val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL); + val |= L3C_TRACETAG_CORE_EN; + writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL); + } +} + +static void hisi_l3c_pmu_clear_core_tracetag(struct perf_event *event) +{ + struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); + u32 core = hisi_get_tt_core(event); + + if (core) { + u32 val; + + /* Clear core information */ + writel(L3C_COER_NONE, l3c_pmu->base + L3C_CORE_CTRL); + val = readl(l3c_pmu->base + L3C_PERF_CTRL); + val &= ~L3C_CORE_EN; + writel(val, l3c_pmu->base + L3C_PERF_CTRL); + + /* Disable core-tracetag statistics */ + val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL); + val &= ~L3C_TRACETAG_CORE_EN; + writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL); + } +} + +static void hisi_l3c_pmu_enable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_l3c_pmu_config_req_tracetag(event); + hisi_l3c_pmu_config_core_tracetag(event); + hisi_l3c_pmu_config_ds(event); + } +} + +static void hisi_l3c_pmu_disable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_l3c_pmu_clear_ds(event); + hisi_l3c_pmu_clear_core_tracetag(event); + hisi_l3c_pmu_clear_req_tracetag(event); + } +} /* * Select the counter register offset using the counter index @@ -50,29 +233,13 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx) static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu, struct hw_perf_event *hwc) { - u32 idx = hwc->idx; - - if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) { - dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx); - return 0; - } - - /* Read 64-bits and the upper 16 bits are RAZ */ - return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx)); + return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx)); } static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu, struct hw_perf_event *hwc, u64 val) { - u32 idx = hwc->idx; - - if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) { - dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx); - return; - } - - /* Write 64-bits and the upper 16 bits are WI */ - writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx)); + writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx)); } static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx, @@ -168,81 +335,26 @@ static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu, writel(val, l3c_pmu->base + L3C_INT_MASK); } -static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id) +static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu) { - struct hisi_pmu *l3c_pmu = dev_id; - struct perf_event *event; - unsigned long overflown; - int idx; - - /* Read L3C_INT_STATUS register */ - overflown = readl(l3c_pmu->base + L3C_INT_STATUS); - if (!overflown) - return IRQ_NONE; - - /* - * Find the counter index which overflowed if the bit was set - * and handle it. - */ - for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) { - /* Write 1 to clear the IRQ status flag */ - writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR); - - /* Get the corresponding event struct */ - event = l3c_pmu->pmu_events.hw_events[idx]; - if (!event) - continue; - - hisi_uncore_pmu_event_update(event); - hisi_uncore_pmu_set_event_period(event); - } - - return IRQ_HANDLED; + return readl(l3c_pmu->base + L3C_INT_STATUS); } -static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu, - struct platform_device *pdev) +static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx) { - int irq, ret; - - /* Read and init IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr, - IRQF_NOBALANCING | IRQF_NO_THREAD, - dev_name(&pdev->dev), l3c_pmu); - if (ret < 0) { - dev_err(&pdev->dev, - "Fail to request IRQ:%d ret:%d\n", irq, ret); - return ret; - } - - l3c_pmu->irq = irq; - - return 0; + writel(1 << idx, l3c_pmu->base + L3C_INT_CLEAR); } static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = { { "HISI0213", }, - {}, + { "HISI0214", }, + {} }; MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match); static int hisi_l3c_pmu_init_data(struct platform_device *pdev, struct hisi_pmu *l3c_pmu) { - unsigned long long id; - acpi_status status; - - status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev), - "_UID", NULL, &id); - if (ACPI_FAILURE(status)) - return -EINVAL; - - l3c_pmu->index_id = id; - /* * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1]. @@ -270,17 +382,31 @@ static int hisi_l3c_pmu_init_data(struct platform_device *pdev, return 0; } -static struct attribute *hisi_l3c_pmu_format_attr[] = { +static struct attribute *hisi_l3c_pmu_v1_format_attr[] = { HISI_PMU_FORMAT_ATTR(event, "config:0-7"), NULL, }; -static const struct attribute_group hisi_l3c_pmu_format_group = { +static const struct attribute_group hisi_l3c_pmu_v1_format_group = { + .name = "format", + .attrs = hisi_l3c_pmu_v1_format_attr, +}; + +static struct attribute *hisi_l3c_pmu_v2_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-7"), + HISI_PMU_FORMAT_ATTR(tt_core, "config1:0-7"), + HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"), + HISI_PMU_FORMAT_ATTR(datasrc_cfg, "config1:11-15"), + HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:16"), + NULL +}; + +static const struct attribute_group hisi_l3c_pmu_v2_format_group = { .name = "format", - .attrs = hisi_l3c_pmu_format_attr, + .attrs = hisi_l3c_pmu_v2_format_attr, }; -static struct attribute *hisi_l3c_pmu_events_attr[] = { +static struct attribute *hisi_l3c_pmu_v1_events_attr[] = { HISI_PMU_EVENT_ATTR(rd_cpipe, 0x00), HISI_PMU_EVENT_ATTR(wr_cpipe, 0x01), HISI_PMU_EVENT_ATTR(rd_hit_cpipe, 0x02), @@ -297,9 +423,22 @@ static struct attribute *hisi_l3c_pmu_events_attr[] = { NULL, }; -static const struct attribute_group hisi_l3c_pmu_events_group = { +static const struct attribute_group hisi_l3c_pmu_v1_events_group = { + .name = "events", + .attrs = hisi_l3c_pmu_v1_events_attr, +}; + +static struct attribute *hisi_l3c_pmu_v2_events_attr[] = { + HISI_PMU_EVENT_ATTR(l3c_hit, 0x48), + HISI_PMU_EVENT_ATTR(cycles, 0x7f), + HISI_PMU_EVENT_ATTR(l3c_ref, 0xb8), + HISI_PMU_EVENT_ATTR(dat_access, 0xb9), + NULL +}; + +static const struct attribute_group hisi_l3c_pmu_v2_events_group = { .name = "events", - .attrs = hisi_l3c_pmu_events_attr, + .attrs = hisi_l3c_pmu_v2_events_attr, }; static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); @@ -325,14 +464,22 @@ static const struct attribute_group hisi_l3c_pmu_identifier_group = { .attrs = hisi_l3c_pmu_identifier_attrs, }; -static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = { - &hisi_l3c_pmu_format_group, - &hisi_l3c_pmu_events_group, +static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = { + &hisi_l3c_pmu_v1_format_group, + &hisi_l3c_pmu_v1_events_group, &hisi_l3c_pmu_cpumask_attr_group, &hisi_l3c_pmu_identifier_group, NULL, }; +static const struct attribute_group *hisi_l3c_pmu_v2_attr_groups[] = { + &hisi_l3c_pmu_v2_format_group, + &hisi_l3c_pmu_v2_events_group, + &hisi_l3c_pmu_cpumask_attr_group, + &hisi_l3c_pmu_identifier_group, + NULL +}; + static const struct hisi_uncore_ops hisi_uncore_l3c_ops = { .write_evtype = hisi_l3c_pmu_write_evtype, .get_event_idx = hisi_uncore_pmu_get_event_idx, @@ -344,6 +491,10 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = { .disable_counter_int = hisi_l3c_pmu_disable_counter_int, .write_counter = hisi_l3c_pmu_write_counter, .read_counter = hisi_l3c_pmu_read_counter, + .get_int_status = hisi_l3c_pmu_get_int_status, + .clear_int_status = hisi_l3c_pmu_clear_int_status, + .enable_filter = hisi_l3c_pmu_enable_filter, + .disable_filter = hisi_l3c_pmu_disable_filter, }; static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev, @@ -355,16 +506,24 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev, if (ret) return ret; - ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev); + ret = hisi_uncore_pmu_init_irq(l3c_pmu, pdev); if (ret) return ret; + if (l3c_pmu->identifier >= HISI_PMU_V2) { + l3c_pmu->counter_bits = 64; + l3c_pmu->check_event = L3C_V2_NR_EVENTS; + l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v2_attr_groups; + } else { + l3c_pmu->counter_bits = 48; + l3c_pmu->check_event = L3C_V1_NR_EVENTS; + l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v1_attr_groups; + } + l3c_pmu->num_counters = L3C_NR_COUNTERS; - l3c_pmu->counter_bits = 48; l3c_pmu->ops = &hisi_uncore_l3c_ops; l3c_pmu->dev = &pdev->dev; l3c_pmu->on_cpu = -1; - l3c_pmu->check_event = 0x59; return 0; } @@ -392,8 +551,12 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev) return ret; } + /* + * CCL_ID is used to identify the L3C in the same SCCL which was + * used _UID by mistake. + */ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u", - l3c_pmu->sccl_id, l3c_pmu->index_id); + l3c_pmu->sccl_id, l3c_pmu->ccl_id); l3c_pmu->pmu = (struct pmu) { .name = name, .module = THIS_MODULE, @@ -406,7 +569,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev) .start = hisi_uncore_pmu_start, .stop = hisi_uncore_pmu_stop, .read = hisi_uncore_pmu_read, - .attr_groups = hisi_l3c_pmu_attr_groups, + .attr_groups = l3c_pmu->pmu_events.attr_groups, .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c new file mode 100644 index 0000000000000000000000000000000000000000..14f23eb31248465a16b963978f2fcba41c04155a --- /dev/null +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c @@ -0,0 +1,500 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HiSilicon PA uncore Hardware event counters support + * + * Copyright (C) 2020 HiSilicon Limited + * Author: Shaokun Zhang <zhangshaokun@hisilicon.com> + * + * This code is based on the uncore PMUs like arm-cci and arm-ccn. + */ +#include <linux/acpi.h> +#include <linux/cpuhotplug.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/list.h> +#include <linux/smp.h> + +#include "hisi_uncore_pmu.h" + +/* PA register definition */ +#define PA_PERF_CTRL 0x1c00 +#define PA_EVENT_CTRL 0x1c04 +#define PA_TT_CTRL 0x1c08 +#define PA_TGTID_CTRL 0x1c14 +#define PA_SRCID_CTRL 0x1c18 +#define PA_INT_MASK 0x1c70 +#define PA_INT_STATUS 0x1c78 +#define PA_INT_CLEAR 0x1c7c +#define PA_EVENT_TYPE0 0x1c80 +#define PA_PMU_VERSION 0x1cf0 +#define PA_EVENT_CNT0_L 0x1f00 + +#define PA_EVTYPE_MASK 0xff +#define PA_NR_COUNTERS 0x8 +#define PA_PERF_CTRL_EN BIT(0) +#define PA_TRACETAG_EN BIT(4) +#define PA_TGTID_EN BIT(11) +#define PA_SRCID_EN BIT(11) +#define PA_TGTID_NONE 0 +#define PA_SRCID_NONE 0 +#define PA_TGTID_MSK_SHIFT 12 +#define PA_SRCID_MSK_SHIFT 12 + +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_cmd, config1, 10, 0); +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_msk, config1, 21, 11); +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22); +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33); +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44); + +static void hisi_pa_pmu_enable_tracetag(struct perf_event *event) +{ + struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu); + u32 tt_en = hisi_get_tracetag_en(event); + + if (tt_en) { + u32 val; + + val = readl(pa_pmu->base + PA_TT_CTRL); + val |= PA_TRACETAG_EN; + writel(val, pa_pmu->base + PA_TT_CTRL); + } +} + +static void hisi_pa_pmu_clear_tracetag(struct perf_event *event) +{ + struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu); + u32 tt_en = hisi_get_tracetag_en(event); + + if (tt_en) { + u32 val; + + val = readl(pa_pmu->base + PA_TT_CTRL); + val &= ~PA_TRACETAG_EN; + writel(val, pa_pmu->base + PA_TT_CTRL); + } +} + +static void hisi_pa_pmu_config_tgtid(struct perf_event *event) +{ + struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_tgtid_cmd(event); + + if (cmd) { + u32 msk = hisi_get_tgtid_msk(event); + u32 val = cmd | PA_TGTID_EN | (msk << PA_TGTID_MSK_SHIFT); + + writel(val, pa_pmu->base + PA_TGTID_CTRL); + } +} + +static void hisi_pa_pmu_clear_tgtid(struct perf_event *event) +{ + struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_tgtid_cmd(event); + + if (cmd) + writel(PA_TGTID_NONE, pa_pmu->base + PA_TGTID_CTRL); +} + +static void hisi_pa_pmu_config_srcid(struct perf_event *event) +{ + struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_srcid_cmd(event); + + if (cmd) { + u32 msk = hisi_get_srcid_msk(event); + u32 val = cmd | PA_SRCID_EN | (msk << PA_SRCID_MSK_SHIFT); + + writel(val, pa_pmu->base + PA_SRCID_CTRL); + } +} + +static void hisi_pa_pmu_clear_srcid(struct perf_event *event) +{ + struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_srcid_cmd(event); + + if (cmd) + writel(PA_SRCID_NONE, pa_pmu->base + PA_SRCID_CTRL); +} + +static void hisi_pa_pmu_enable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_pa_pmu_enable_tracetag(event); + hisi_pa_pmu_config_srcid(event); + hisi_pa_pmu_config_tgtid(event); + } +} + +static void hisi_pa_pmu_disable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_pa_pmu_clear_tgtid(event); + hisi_pa_pmu_clear_srcid(event); + hisi_pa_pmu_clear_tracetag(event); + } +} + +static u32 hisi_pa_pmu_get_counter_offset(int idx) +{ + return (PA_EVENT_CNT0_L + idx * 8); +} + +static u64 hisi_pa_pmu_read_counter(struct hisi_pmu *pa_pmu, + struct hw_perf_event *hwc) +{ + return readq(pa_pmu->base + hisi_pa_pmu_get_counter_offset(hwc->idx)); +} + +static void hisi_pa_pmu_write_counter(struct hisi_pmu *pa_pmu, + struct hw_perf_event *hwc, u64 val) +{ + writeq(val, pa_pmu->base + hisi_pa_pmu_get_counter_offset(hwc->idx)); +} + +static void hisi_pa_pmu_write_evtype(struct hisi_pmu *pa_pmu, int idx, + u32 type) +{ + u32 reg, reg_idx, shift, val; + + /* + * Select the appropriate event select register(PA_EVENT_TYPE0/1). + * There are 2 event select registers for the 8 hardware counters. + * Event code is 8-bits and for the former 4 hardware counters, + * PA_EVENT_TYPE0 is chosen. For the latter 4 hardware counters, + * PA_EVENT_TYPE1 is chosen. + */ + reg = PA_EVENT_TYPE0 + (idx / 4) * 4; + reg_idx = idx % 4; + shift = 8 * reg_idx; + + /* Write event code to pa_EVENT_TYPEx Register */ + val = readl(pa_pmu->base + reg); + val &= ~(PA_EVTYPE_MASK << shift); + val |= (type << shift); + writel(val, pa_pmu->base + reg); +} + +static void hisi_pa_pmu_start_counters(struct hisi_pmu *pa_pmu) +{ + u32 val; + + val = readl(pa_pmu->base + PA_PERF_CTRL); + val |= PA_PERF_CTRL_EN; + writel(val, pa_pmu->base + PA_PERF_CTRL); +} + +static void hisi_pa_pmu_stop_counters(struct hisi_pmu *pa_pmu) +{ + u32 val; + + val = readl(pa_pmu->base + PA_PERF_CTRL); + val &= ~(PA_PERF_CTRL_EN); + writel(val, pa_pmu->base + PA_PERF_CTRL); +} + +static void hisi_pa_pmu_enable_counter(struct hisi_pmu *pa_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Enable counter index in PA_EVENT_CTRL register */ + val = readl(pa_pmu->base + PA_EVENT_CTRL); + val |= 1 << hwc->idx; + writel(val, pa_pmu->base + PA_EVENT_CTRL); +} + +static void hisi_pa_pmu_disable_counter(struct hisi_pmu *pa_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Clear counter index in PA_EVENT_CTRL register */ + val = readl(pa_pmu->base + PA_EVENT_CTRL); + val &= ~(1 << hwc->idx); + writel(val, pa_pmu->base + PA_EVENT_CTRL); +} + +static void hisi_pa_pmu_enable_counter_int(struct hisi_pmu *pa_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Write 0 to enable interrupt */ + val = readl(pa_pmu->base + PA_INT_MASK); + val &= ~(1 << hwc->idx); + writel(val, pa_pmu->base + PA_INT_MASK); +} + +static void hisi_pa_pmu_disable_counter_int(struct hisi_pmu *pa_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + /* Write 1 to mask interrupt */ + val = readl(pa_pmu->base + PA_INT_MASK); + val |= 1 << hwc->idx; + writel(val, pa_pmu->base + PA_INT_MASK); +} + +static u32 hisi_pa_pmu_get_int_status(struct hisi_pmu *pa_pmu) +{ + return readl(pa_pmu->base + PA_INT_STATUS); +} + +static void hisi_pa_pmu_clear_int_status(struct hisi_pmu *pa_pmu, int idx) +{ + writel(1 << idx, pa_pmu->base + PA_INT_CLEAR); +} + +static const struct acpi_device_id hisi_pa_pmu_acpi_match[] = { + { "HISI0273", }, + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_pa_pmu_acpi_match); + +static int hisi_pa_pmu_init_data(struct platform_device *pdev, + struct hisi_pmu *pa_pmu) +{ + /* + * Use the SCCL_ID and the index ID to identify the PA PMU, + * while SCCL_ID is the nearst SCCL_ID from this SICL and + * CPU core is chosen from this SCCL to manage this PMU. + */ + if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", + &pa_pmu->sccl_id)) { + dev_err(&pdev->dev, "Cannot read sccl-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id", + &pa_pmu->index_id)) { + dev_err(&pdev->dev, "Cannot read idx-id!\n"); + return -EINVAL; + } + + pa_pmu->ccl_id = -1; + + pa_pmu->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pa_pmu->base)) { + dev_err(&pdev->dev, "ioremap failed for pa_pmu resource.\n"); + return PTR_ERR(pa_pmu->base); + } + + pa_pmu->identifier = readl(pa_pmu->base + PA_PMU_VERSION); + + return 0; +} + +static struct attribute *hisi_pa_pmu_v2_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-7"), + HISI_PMU_FORMAT_ATTR(tgtid_cmd, "config1:0-10"), + HISI_PMU_FORMAT_ATTR(tgtid_msk, "config1:11-21"), + HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"), + HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:33-43"), + HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"), + NULL, +}; + +static const struct attribute_group hisi_pa_pmu_v2_format_group = { + .name = "format", + .attrs = hisi_pa_pmu_v2_format_attr, +}; + +static struct attribute *hisi_pa_pmu_v2_events_attr[] = { + HISI_PMU_EVENT_ATTR(rx_req, 0x40), + HISI_PMU_EVENT_ATTR(tx_req, 0x5c), + HISI_PMU_EVENT_ATTR(cycle, 0x78), + NULL +}; + +static const struct attribute_group hisi_pa_pmu_v2_events_group = { + .name = "events", + .attrs = hisi_pa_pmu_v2_events_attr, +}; + +static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); + +static struct attribute *hisi_pa_pmu_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL +}; + +static const struct attribute_group hisi_pa_pmu_cpumask_attr_group = { + .attrs = hisi_pa_pmu_cpumask_attrs, +}; + +static struct device_attribute hisi_pa_pmu_identifier_attr = + __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL); + +static struct attribute *hisi_pa_pmu_identifier_attrs[] = { + &hisi_pa_pmu_identifier_attr.attr, + NULL +}; + +static struct attribute_group hisi_pa_pmu_identifier_group = { + .attrs = hisi_pa_pmu_identifier_attrs, +}; + +static const struct attribute_group *hisi_pa_pmu_v2_attr_groups[] = { + &hisi_pa_pmu_v2_format_group, + &hisi_pa_pmu_v2_events_group, + &hisi_pa_pmu_cpumask_attr_group, + &hisi_pa_pmu_identifier_group, + NULL +}; + +static const struct hisi_uncore_ops hisi_uncore_pa_ops = { + .write_evtype = hisi_pa_pmu_write_evtype, + .get_event_idx = hisi_uncore_pmu_get_event_idx, + .start_counters = hisi_pa_pmu_start_counters, + .stop_counters = hisi_pa_pmu_stop_counters, + .enable_counter = hisi_pa_pmu_enable_counter, + .disable_counter = hisi_pa_pmu_disable_counter, + .enable_counter_int = hisi_pa_pmu_enable_counter_int, + .disable_counter_int = hisi_pa_pmu_disable_counter_int, + .write_counter = hisi_pa_pmu_write_counter, + .read_counter = hisi_pa_pmu_read_counter, + .get_int_status = hisi_pa_pmu_get_int_status, + .clear_int_status = hisi_pa_pmu_clear_int_status, + .enable_filter = hisi_pa_pmu_enable_filter, + .disable_filter = hisi_pa_pmu_disable_filter, +}; + +static int hisi_pa_pmu_dev_probe(struct platform_device *pdev, + struct hisi_pmu *pa_pmu) +{ + int ret; + + ret = hisi_pa_pmu_init_data(pdev, pa_pmu); + if (ret) + return ret; + + ret = hisi_uncore_pmu_init_irq(pa_pmu, pdev); + if (ret) + return ret; + + pa_pmu->pmu_events.attr_groups = hisi_pa_pmu_v2_attr_groups; + pa_pmu->num_counters = PA_NR_COUNTERS; + pa_pmu->ops = &hisi_uncore_pa_ops; + pa_pmu->check_event = 0xB0; + pa_pmu->counter_bits = 64; + pa_pmu->dev = &pdev->dev; + pa_pmu->on_cpu = -1; + + return 0; +} + +static int hisi_pa_pmu_probe(struct platform_device *pdev) +{ + struct hisi_pmu *pa_pmu; + char *name; + int ret; + + pa_pmu = devm_kzalloc(&pdev->dev, sizeof(*pa_pmu), GFP_KERNEL); + if (!pa_pmu) + return -ENOMEM; + + ret = hisi_pa_pmu_dev_probe(pdev, pa_pmu); + if (ret) + return ret; + /* + * PA is attached in SICL and the CPU core is chosen to manage this + * PMU which is the nearest SCCL, while its SCCL_ID is greater than + * one with the SICL_ID. + */ + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%u_pa%u", + pa_pmu->sccl_id - 1, pa_pmu->index_id); + if (!name) + return -ENOMEM; + + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE, + &pa_pmu->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug\n", ret); + return ret; + } + + pa_pmu->pmu = (struct pmu) { + .module = THIS_MODULE, + .task_ctx_nr = perf_invalid_context, + .event_init = hisi_uncore_pmu_event_init, + .pmu_enable = hisi_uncore_pmu_enable, + .pmu_disable = hisi_uncore_pmu_disable, + .add = hisi_uncore_pmu_add, + .del = hisi_uncore_pmu_del, + .start = hisi_uncore_pmu_start, + .stop = hisi_uncore_pmu_stop, + .read = hisi_uncore_pmu_read, + .attr_groups = pa_pmu->pmu_events.attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + }; + + ret = perf_pmu_register(&pa_pmu->pmu, name, -1); + if (ret) { + dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret); + cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE, + &pa_pmu->node); + irq_set_affinity_hint(pa_pmu->irq, NULL); + return ret; + } + + platform_set_drvdata(pdev, pa_pmu); + return ret; +} + +static int hisi_pa_pmu_remove(struct platform_device *pdev) +{ + struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev); + + perf_pmu_unregister(&pa_pmu->pmu); + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE, + &pa_pmu->node); + irq_set_affinity_hint(pa_pmu->irq, NULL); + + return 0; +} + +static struct platform_driver hisi_pa_pmu_driver = { + .driver = { + .name = "hisi_pa_pmu", + .acpi_match_table = hisi_pa_pmu_acpi_match, + .suppress_bind_attrs = true, + }, + .probe = hisi_pa_pmu_probe, + .remove = hisi_pa_pmu_remove, +}; + +static int __init hisi_pa_pmu_module_init(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE, + "AP_PERF_ARM_HISI_PA_ONLINE", + hisi_uncore_pmu_online_cpu, + hisi_uncore_pmu_offline_cpu); + if (ret) { + pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret); + return ret; + } + + ret = platform_driver_register(&hisi_pa_pmu_driver); + if (ret) + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE); + + return ret; +} +module_init(hisi_pa_pmu_module_init); + +static void __exit hisi_pa_pmu_module_exit(void) +{ + platform_driver_unregister(&hisi_pa_pmu_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE); +} +module_exit(hisi_pa_pmu_module_exit); + +MODULE_DESCRIPTION("HiSilicon Protocol Adapter uncore PMU driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>"); +MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>"); diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c index 9dbdc3fc3bb4baccf0d91cd86a4bbe4d0a6259ac..13c68b5e39c4c0cc317cd0c3b1e38f1f93cb406e 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c @@ -21,7 +21,7 @@ #include "hisi_uncore_pmu.h" #define HISI_GET_EVENTID(ev) (ev->hw.config_base & 0xff) -#define HISI_MAX_PERIOD(nr) (BIT_ULL(nr) - 1) +#define HISI_MAX_PERIOD(nr) (GENMASK_ULL((nr) - 1, 0)) /* * PMU format attributes @@ -33,7 +33,7 @@ ssize_t hisi_format_sysfs_show(struct device *dev, eattr = container_of(attr, struct dev_ext_attribute, attr); - return sprintf(buf, "%s\n", (char *)eattr->var); + return sysfs_emit(buf, "%s\n", (char *)eattr->var); } EXPORT_SYMBOL_GPL(hisi_format_sysfs_show); @@ -47,7 +47,7 @@ ssize_t hisi_event_sysfs_show(struct device *dev, eattr = container_of(attr, struct dev_ext_attribute, attr); - return sprintf(page, "config=0x%lx\n", (unsigned long)eattr->var); + return sysfs_emit(page, "config=0x%lx\n", (unsigned long)eattr->var); } EXPORT_SYMBOL_GPL(hisi_event_sysfs_show); @@ -59,7 +59,7 @@ ssize_t hisi_cpumask_sysfs_show(struct device *dev, { struct hisi_pmu *hisi_pmu = to_hisi_pmu(dev_get_drvdata(dev)); - return sprintf(buf, "%d\n", hisi_pmu->on_cpu); + return sysfs_emit(buf, "%d\n", hisi_pmu->on_cpu); } EXPORT_SYMBOL_GPL(hisi_cpumask_sysfs_show); @@ -96,12 +96,6 @@ static bool hisi_validate_event_group(struct perf_event *event) return counters <= hisi_pmu->num_counters; } -int hisi_uncore_pmu_counter_valid(struct hisi_pmu *hisi_pmu, int idx) -{ - return idx >= 0 && idx < hisi_pmu->num_counters; -} -EXPORT_SYMBOL_GPL(hisi_uncore_pmu_counter_valid); - int hisi_uncore_pmu_get_event_idx(struct perf_event *event) { struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu); @@ -125,19 +119,68 @@ ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev, { struct hisi_pmu *hisi_pmu = to_hisi_pmu(dev_get_drvdata(dev)); - return snprintf(page, PAGE_SIZE, "0x%08x\n", hisi_pmu->identifier); + return sysfs_emit(page, "0x%08x\n", hisi_pmu->identifier); } EXPORT_SYMBOL_GPL(hisi_uncore_pmu_identifier_attr_show); static void hisi_uncore_pmu_clear_event_idx(struct hisi_pmu *hisi_pmu, int idx) { - if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) { - dev_err(hisi_pmu->dev, "Unsupported event index:%d!\n", idx); - return; + clear_bit(idx, hisi_pmu->pmu_events.used_mask); +} + +static irqreturn_t hisi_uncore_pmu_isr(int irq, void *data) +{ + struct hisi_pmu *hisi_pmu = data; + struct perf_event *event; + unsigned long overflown; + int idx; + + overflown = hisi_pmu->ops->get_int_status(hisi_pmu); + if (!overflown) + return IRQ_NONE; + + /* + * Find the counter index which overflowed if the bit was set + * and handle it. + */ + for_each_set_bit(idx, &overflown, hisi_pmu->num_counters) { + /* Write 1 to clear the IRQ status flag */ + hisi_pmu->ops->clear_int_status(hisi_pmu, idx); + /* Get the corresponding event struct */ + event = hisi_pmu->pmu_events.hw_events[idx]; + if (!event) + continue; + + hisi_uncore_pmu_event_update(event); + hisi_uncore_pmu_set_event_period(event); } - clear_bit(idx, hisi_pmu->pmu_events.used_mask); + return IRQ_HANDLED; +} + +int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu, + struct platform_device *pdev) +{ + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr, + IRQF_NOBALANCING | IRQF_NO_THREAD, + dev_name(&pdev->dev), hisi_pmu); + if (ret < 0) { + dev_err(&pdev->dev, + "Fail to request IRQ: %d ret: %d.\n", irq, ret); + return ret; + } + + hisi_pmu->irq = irq; + + return 0; } +EXPORT_SYMBOL_GPL(hisi_uncore_pmu_init_irq); int hisi_uncore_pmu_event_init(struct perf_event *event) { @@ -202,6 +245,9 @@ static void hisi_uncore_pmu_enable_event(struct perf_event *event) hisi_pmu->ops->write_evtype(hisi_pmu, hwc->idx, HISI_GET_EVENTID(event)); + if (hisi_pmu->ops->enable_filter) + hisi_pmu->ops->enable_filter(event); + hisi_pmu->ops->enable_counter_int(hisi_pmu, hwc); hisi_pmu->ops->enable_counter(hisi_pmu, hwc); } @@ -216,6 +262,9 @@ static void hisi_uncore_pmu_disable_event(struct perf_event *event) hisi_pmu->ops->disable_counter(hisi_pmu, hwc); hisi_pmu->ops->disable_counter_int(hisi_pmu, hwc); + + if (hisi_pmu->ops->disable_filter) + hisi_pmu->ops->disable_filter(event); } void hisi_uncore_pmu_set_event_period(struct perf_event *event) diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h index 25b7cbe1f8185e20250749a96182c23daf63af56..ea9d89bbc1ea0559fd1d6a7a36486d02407bb583 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h @@ -11,16 +11,19 @@ #ifndef __HISI_UNCORE_PMU_H__ #define __HISI_UNCORE_PMU_H__ +#include <linux/bitfield.h> #include <linux/cpumask.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/perf_event.h> +#include <linux/platform_device.h> #include <linux/types.h> #undef pr_fmt #define pr_fmt(fmt) "hisi_pmu: " fmt +#define HISI_PMU_V2 0x30 #define HISI_MAX_COUNTERS 0x10 #define to_hisi_pmu(p) (container_of(p, struct hisi_pmu, pmu)) @@ -34,6 +37,12 @@ #define HISI_PMU_EVENT_ATTR(_name, _config) \ HISI_PMU_ATTR(_name, hisi_event_sysfs_show, (unsigned long)_config) +#define HISI_PMU_EVENT_ATTR_EXTRACTOR(name, config, hi, lo) \ + static inline u32 hisi_get_##name(struct perf_event *event) \ + { \ + return FIELD_GET(GENMASK_ULL(hi, lo), event->attr.config); \ + } + struct hisi_pmu; struct hisi_uncore_ops { @@ -47,11 +56,16 @@ struct hisi_uncore_ops { void (*disable_counter_int)(struct hisi_pmu *, struct hw_perf_event *); void (*start_counters)(struct hisi_pmu *); void (*stop_counters)(struct hisi_pmu *); + u32 (*get_int_status)(struct hisi_pmu *hisi_pmu); + void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx); + void (*enable_filter)(struct perf_event *event); + void (*disable_filter)(struct perf_event *event); }; struct hisi_pmu_hwevents { struct perf_event *hw_events[HISI_MAX_COUNTERS]; DECLARE_BITMAP(used_mask, HISI_MAX_COUNTERS); + const struct attribute_group **attr_groups; }; /* Generic pmu struct for different pmu types */ @@ -71,6 +85,8 @@ struct hisi_pmu { void __iomem *base; /* the ID of the PMU modules */ u32 index_id; + /* For DDRC PMU v2: each DDRC has more than one DMC */ + u32 sub_id; int num_counters; int counter_bits; /* check event code range */ @@ -78,7 +94,6 @@ struct hisi_pmu { u32 identifier; }; -int hisi_uncore_pmu_counter_valid(struct hisi_pmu *hisi_pmu, int idx); int hisi_uncore_pmu_get_event_idx(struct perf_event *event); void hisi_uncore_pmu_read(struct perf_event *event); int hisi_uncore_pmu_add(struct perf_event *event, int flags); @@ -102,6 +117,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node); ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev, struct device_attribute *attr, char *page); - +int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu, + struct platform_device *pdev); #endif /* __HISI_UNCORE_PMU_H__ */ diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c new file mode 100644 index 0000000000000000000000000000000000000000..46be312fa12624e485292bcc18af631d40d5f6e6 --- /dev/null +++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HiSilicon SLLC uncore Hardware event counters support + * + * Copyright (C) 2020 Hisilicon Limited + * Author: Shaokun Zhang <zhangshaokun@hisilicon.com> + * + * This code is based on the uncore PMUs like arm-cci and arm-ccn. + */ +#include <linux/acpi.h> +#include <linux/cpuhotplug.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/list.h> +#include <linux/smp.h> + +#include "hisi_uncore_pmu.h" + +/* SLLC register definition */ +#define SLLC_INT_MASK 0x0814 +#define SLLC_INT_STATUS 0x0818 +#define SLLC_INT_CLEAR 0x081c +#define SLLC_PERF_CTRL 0x1c00 +#define SLLC_SRCID_CTRL 0x1c04 +#define SLLC_TGTID_CTRL 0x1c08 +#define SLLC_EVENT_CTRL 0x1c14 +#define SLLC_EVENT_TYPE0 0x1c18 +#define SLLC_VERSION 0x1cf0 +#define SLLC_EVENT_CNT0_L 0x1d00 + +#define SLLC_EVTYPE_MASK 0xff +#define SLLC_PERF_CTRL_EN BIT(0) +#define SLLC_FILT_EN BIT(1) +#define SLLC_TRACETAG_EN BIT(2) +#define SLLC_SRCID_EN BIT(4) +#define SLLC_SRCID_NONE 0x0 +#define SLLC_TGTID_EN BIT(5) +#define SLLC_TGTID_NONE 0x0 +#define SLLC_TGTID_MIN_SHIFT 1 +#define SLLC_TGTID_MAX_SHIFT 12 +#define SLLC_SRCID_CMD_SHIFT 1 +#define SLLC_SRCID_MSK_SHIFT 12 +#define SLLC_NR_EVENTS 0x80 + +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_min, config1, 10, 0); +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_max, config1, 21, 11); +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22); +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33); +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44); + +static bool tgtid_is_valid(u32 max, u32 min) +{ + return max > 0 && max >= min; +} + +static void hisi_sllc_pmu_enable_tracetag(struct perf_event *event) +{ + struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); + u32 tt_en = hisi_get_tracetag_en(event); + + if (tt_en) { + u32 val; + + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val |= SLLC_TRACETAG_EN | SLLC_FILT_EN; + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); + } +} + +static void hisi_sllc_pmu_disable_tracetag(struct perf_event *event) +{ + struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); + u32 tt_en = hisi_get_tracetag_en(event); + + if (tt_en) { + u32 val; + + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN); + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); + } +} + +static void hisi_sllc_pmu_config_tgtid(struct perf_event *event) +{ + struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); + u32 min = hisi_get_tgtid_min(event); + u32 max = hisi_get_tgtid_max(event); + + if (tgtid_is_valid(max, min)) { + u32 val = (max << SLLC_TGTID_MAX_SHIFT) | (min << SLLC_TGTID_MIN_SHIFT); + + writel(val, sllc_pmu->base + SLLC_TGTID_CTRL); + /* Enable the tgtid */ + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val |= SLLC_TGTID_EN | SLLC_FILT_EN; + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); + } +} + +static void hisi_sllc_pmu_clear_tgtid(struct perf_event *event) +{ + struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); + u32 min = hisi_get_tgtid_min(event); + u32 max = hisi_get_tgtid_max(event); + + if (tgtid_is_valid(max, min)) { + u32 val; + + writel(SLLC_TGTID_NONE, sllc_pmu->base + SLLC_TGTID_CTRL); + /* Disable the tgtid */ + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val &= ~(SLLC_TGTID_EN | SLLC_FILT_EN); + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); + } +} + +static void hisi_sllc_pmu_config_srcid(struct perf_event *event) +{ + struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_srcid_cmd(event); + + if (cmd) { + u32 val, msk; + + msk = hisi_get_srcid_msk(event); + val = (cmd << SLLC_SRCID_CMD_SHIFT) | (msk << SLLC_SRCID_MSK_SHIFT); + writel(val, sllc_pmu->base + SLLC_SRCID_CTRL); + /* Enable the srcid */ + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val |= SLLC_SRCID_EN | SLLC_FILT_EN; + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); + } +} + +static void hisi_sllc_pmu_clear_srcid(struct perf_event *event) +{ + struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); + u32 cmd = hisi_get_srcid_cmd(event); + + if (cmd) { + u32 val; + + writel(SLLC_SRCID_NONE, sllc_pmu->base + SLLC_SRCID_CTRL); + /* Disable the srcid */ + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val &= ~(SLLC_SRCID_EN | SLLC_FILT_EN); + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); + } +} + +static void hisi_sllc_pmu_enable_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_sllc_pmu_enable_tracetag(event); + hisi_sllc_pmu_config_srcid(event); + hisi_sllc_pmu_config_tgtid(event); + } +} + +static void hisi_sllc_pmu_clear_filter(struct perf_event *event) +{ + if (event->attr.config1 != 0x0) { + hisi_sllc_pmu_disable_tracetag(event); + hisi_sllc_pmu_clear_srcid(event); + hisi_sllc_pmu_clear_tgtid(event); + } +} + +static u32 hisi_sllc_pmu_get_counter_offset(int idx) +{ + return (SLLC_EVENT_CNT0_L + idx * 8); +} + +static u64 hisi_sllc_pmu_read_counter(struct hisi_pmu *sllc_pmu, + struct hw_perf_event *hwc) +{ + return readq(sllc_pmu->base + + hisi_sllc_pmu_get_counter_offset(hwc->idx)); +} + +static void hisi_sllc_pmu_write_counter(struct hisi_pmu *sllc_pmu, + struct hw_perf_event *hwc, u64 val) +{ + writeq(val, sllc_pmu->base + + hisi_sllc_pmu_get_counter_offset(hwc->idx)); +} + +static void hisi_sllc_pmu_write_evtype(struct hisi_pmu *sllc_pmu, int idx, + u32 type) +{ + u32 reg, reg_idx, shift, val; + + /* + * Select the appropriate event select register(SLLC_EVENT_TYPE0/1). + * There are 2 event select registers for the 8 hardware counters. + * Event code is 8-bits and for the former 4 hardware counters, + * SLLC_EVENT_TYPE0 is chosen. For the latter 4 hardware counters, + * SLLC_EVENT_TYPE1 is chosen. + */ + reg = SLLC_EVENT_TYPE0 + (idx / 4) * 4; + reg_idx = idx % 4; + shift = 8 * reg_idx; + + /* Write event code to SLLC_EVENT_TYPEx Register */ + val = readl(sllc_pmu->base + reg); + val &= ~(SLLC_EVTYPE_MASK << shift); + val |= (type << shift); + writel(val, sllc_pmu->base + reg); +} + +static void hisi_sllc_pmu_start_counters(struct hisi_pmu *sllc_pmu) +{ + u32 val; + + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val |= SLLC_PERF_CTRL_EN; + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); +} + +static void hisi_sllc_pmu_stop_counters(struct hisi_pmu *sllc_pmu) +{ + u32 val; + + val = readl(sllc_pmu->base + SLLC_PERF_CTRL); + val &= ~(SLLC_PERF_CTRL_EN); + writel(val, sllc_pmu->base + SLLC_PERF_CTRL); +} + +static void hisi_sllc_pmu_enable_counter(struct hisi_pmu *sllc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(sllc_pmu->base + SLLC_EVENT_CTRL); + val |= 1 << hwc->idx; + writel(val, sllc_pmu->base + SLLC_EVENT_CTRL); +} + +static void hisi_sllc_pmu_disable_counter(struct hisi_pmu *sllc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(sllc_pmu->base + SLLC_EVENT_CTRL); + val &= ~(1 << hwc->idx); + writel(val, sllc_pmu->base + SLLC_EVENT_CTRL); +} + +static void hisi_sllc_pmu_enable_counter_int(struct hisi_pmu *sllc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(sllc_pmu->base + SLLC_INT_MASK); + /* Write 0 to enable interrupt */ + val &= ~(1 << hwc->idx); + writel(val, sllc_pmu->base + SLLC_INT_MASK); +} + +static void hisi_sllc_pmu_disable_counter_int(struct hisi_pmu *sllc_pmu, + struct hw_perf_event *hwc) +{ + u32 val; + + val = readl(sllc_pmu->base + SLLC_INT_MASK); + /* Write 1 to mask interrupt */ + val |= 1 << hwc->idx; + writel(val, sllc_pmu->base + SLLC_INT_MASK); +} + +static u32 hisi_sllc_pmu_get_int_status(struct hisi_pmu *sllc_pmu) +{ + return readl(sllc_pmu->base + SLLC_INT_STATUS); +} + +static void hisi_sllc_pmu_clear_int_status(struct hisi_pmu *sllc_pmu, int idx) +{ + writel(1 << idx, sllc_pmu->base + SLLC_INT_CLEAR); +} + +static const struct acpi_device_id hisi_sllc_pmu_acpi_match[] = { + { "HISI0263", }, + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_sllc_pmu_acpi_match); + +static int hisi_sllc_pmu_init_data(struct platform_device *pdev, + struct hisi_pmu *sllc_pmu) +{ + /* + * Use the SCCL_ID and the index ID to identify the SLLC PMU, + * while SCCL_ID is from MPIDR_EL1 by CPU. + */ + if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", + &sllc_pmu->sccl_id)) { + dev_err(&pdev->dev, "Cannot read sccl-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id", + &sllc_pmu->index_id)) { + dev_err(&pdev->dev, "Cannot read idx-id!\n"); + return -EINVAL; + } + + /* SLLC PMUs only share the same SCCL */ + sllc_pmu->ccl_id = -1; + + sllc_pmu->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sllc_pmu->base)) { + dev_err(&pdev->dev, "ioremap failed for sllc_pmu resource.\n"); + return PTR_ERR(sllc_pmu->base); + } + + sllc_pmu->identifier = readl(sllc_pmu->base + SLLC_VERSION); + + return 0; +} + +static struct attribute *hisi_sllc_pmu_v2_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-7"), + HISI_PMU_FORMAT_ATTR(tgtid_min, "config1:0-10"), + HISI_PMU_FORMAT_ATTR(tgtid_max, "config1:11-21"), + HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"), + HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:33-43"), + HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"), + NULL +}; + +static const struct attribute_group hisi_sllc_pmu_v2_format_group = { + .name = "format", + .attrs = hisi_sllc_pmu_v2_format_attr, +}; + +static struct attribute *hisi_sllc_pmu_v2_events_attr[] = { + HISI_PMU_EVENT_ATTR(rx_req, 0x30), + HISI_PMU_EVENT_ATTR(rx_data, 0x31), + HISI_PMU_EVENT_ATTR(tx_req, 0x34), + HISI_PMU_EVENT_ATTR(tx_data, 0x35), + HISI_PMU_EVENT_ATTR(cycles, 0x09), + NULL +}; + +static const struct attribute_group hisi_sllc_pmu_v2_events_group = { + .name = "events", + .attrs = hisi_sllc_pmu_v2_events_attr, +}; + +static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); + +static struct attribute *hisi_sllc_pmu_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL +}; + +static const struct attribute_group hisi_sllc_pmu_cpumask_attr_group = { + .attrs = hisi_sllc_pmu_cpumask_attrs, +}; + +static struct device_attribute hisi_sllc_pmu_identifier_attr = + __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL); + +static struct attribute *hisi_sllc_pmu_identifier_attrs[] = { + &hisi_sllc_pmu_identifier_attr.attr, + NULL +}; + +static struct attribute_group hisi_sllc_pmu_identifier_group = { + .attrs = hisi_sllc_pmu_identifier_attrs, +}; + +static const struct attribute_group *hisi_sllc_pmu_v2_attr_groups[] = { + &hisi_sllc_pmu_v2_format_group, + &hisi_sllc_pmu_v2_events_group, + &hisi_sllc_pmu_cpumask_attr_group, + &hisi_sllc_pmu_identifier_group, + NULL +}; + +static const struct hisi_uncore_ops hisi_uncore_sllc_ops = { + .write_evtype = hisi_sllc_pmu_write_evtype, + .get_event_idx = hisi_uncore_pmu_get_event_idx, + .start_counters = hisi_sllc_pmu_start_counters, + .stop_counters = hisi_sllc_pmu_stop_counters, + .enable_counter = hisi_sllc_pmu_enable_counter, + .disable_counter = hisi_sllc_pmu_disable_counter, + .enable_counter_int = hisi_sllc_pmu_enable_counter_int, + .disable_counter_int = hisi_sllc_pmu_disable_counter_int, + .write_counter = hisi_sllc_pmu_write_counter, + .read_counter = hisi_sllc_pmu_read_counter, + .get_int_status = hisi_sllc_pmu_get_int_status, + .clear_int_status = hisi_sllc_pmu_clear_int_status, + .enable_filter = hisi_sllc_pmu_enable_filter, + .disable_filter = hisi_sllc_pmu_clear_filter, +}; + +static int hisi_sllc_pmu_dev_probe(struct platform_device *pdev, + struct hisi_pmu *sllc_pmu) +{ + int ret; + + ret = hisi_sllc_pmu_init_data(pdev, sllc_pmu); + if (ret) + return ret; + + ret = hisi_uncore_pmu_init_irq(sllc_pmu, pdev); + if (ret) + return ret; + + sllc_pmu->pmu_events.attr_groups = hisi_sllc_pmu_v2_attr_groups; + sllc_pmu->ops = &hisi_uncore_sllc_ops; + sllc_pmu->check_event = SLLC_NR_EVENTS; + sllc_pmu->counter_bits = 64; + sllc_pmu->num_counters = 8; + sllc_pmu->dev = &pdev->dev; + sllc_pmu->on_cpu = -1; + + return 0; +} + +static int hisi_sllc_pmu_probe(struct platform_device *pdev) +{ + struct hisi_pmu *sllc_pmu; + char *name; + int ret; + + sllc_pmu = devm_kzalloc(&pdev->dev, sizeof(*sllc_pmu), GFP_KERNEL); + if (!sllc_pmu) + return -ENOMEM; + + ret = hisi_sllc_pmu_dev_probe(pdev, sllc_pmu); + if (ret) + return ret; + + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_sllc%u", + sllc_pmu->sccl_id, sllc_pmu->index_id); + if (!name) + return -ENOMEM; + + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, + &sllc_pmu->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug\n", ret); + return ret; + } + + sllc_pmu->pmu = (struct pmu) { + .module = THIS_MODULE, + .task_ctx_nr = perf_invalid_context, + .event_init = hisi_uncore_pmu_event_init, + .pmu_enable = hisi_uncore_pmu_enable, + .pmu_disable = hisi_uncore_pmu_disable, + .add = hisi_uncore_pmu_add, + .del = hisi_uncore_pmu_del, + .start = hisi_uncore_pmu_start, + .stop = hisi_uncore_pmu_stop, + .read = hisi_uncore_pmu_read, + .attr_groups = sllc_pmu->pmu_events.attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + }; + + ret = perf_pmu_register(&sllc_pmu->pmu, name, -1); + if (ret) { + dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret); + cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, + &sllc_pmu->node); + irq_set_affinity_hint(sllc_pmu->irq, NULL); + return ret; + } + + platform_set_drvdata(pdev, sllc_pmu); + + return ret; +} + +static int hisi_sllc_pmu_remove(struct platform_device *pdev) +{ + struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev); + + perf_pmu_unregister(&sllc_pmu->pmu); + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, + &sllc_pmu->node); + irq_set_affinity_hint(sllc_pmu->irq, NULL); + + return 0; +} + +static struct platform_driver hisi_sllc_pmu_driver = { + .driver = { + .name = "hisi_sllc_pmu", + .acpi_match_table = hisi_sllc_pmu_acpi_match, + .suppress_bind_attrs = true, + }, + .probe = hisi_sllc_pmu_probe, + .remove = hisi_sllc_pmu_remove, +}; + +static int __init hisi_sllc_pmu_module_init(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, + "AP_PERF_ARM_HISI_SLLC_ONLINE", + hisi_uncore_pmu_online_cpu, + hisi_uncore_pmu_offline_cpu); + if (ret) { + pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret); + return ret; + } + + ret = platform_driver_register(&hisi_sllc_pmu_driver); + if (ret) + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE); + + return ret; +} +module_init(hisi_sllc_pmu_module_init); + +static void __exit hisi_sllc_pmu_module_exit(void) +{ + platform_driver_unregister(&hisi_sllc_pmu_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE); +} +module_exit(hisi_sllc_pmu_module_exit); + +MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>"); +MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>"); diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c index 8883af955a2a3d2f8e59896b11c6d467b726491f..fc54a80f9c5cfc940cacd684c3b1386f92cac619 100644 --- a/drivers/perf/qcom_l2_pmu.c +++ b/drivers/perf/qcom_l2_pmu.c @@ -676,7 +676,7 @@ static ssize_t l2cache_pmu_event_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%02llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } #define L2CACHE_EVENT_ATTR(_name, _id) \ diff --git a/drivers/perf/qcom_l3_pmu.c b/drivers/perf/qcom_l3_pmu.c index fb34b87b94712bf1766ca4775fa13a5290fa7f74..bba078077c93cb417e794f32f5fe8494cfc5c8a5 100644 --- a/drivers/perf/qcom_l3_pmu.c +++ b/drivers/perf/qcom_l3_pmu.c @@ -615,7 +615,7 @@ static ssize_t l3cache_pmu_format_show(struct device *dev, struct dev_ext_attribute *eattr; eattr = container_of(attr, struct dev_ext_attribute, attr); - return sprintf(buf, "%s\n", (char *) eattr->var); + return sysfs_emit(buf, "%s\n", (char *) eattr->var); } #define L3CACHE_PMU_FORMAT_ATTR(_name, _config) \ @@ -643,7 +643,7 @@ static ssize_t l3cache_pmu_event_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%02llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); } #define L3CACHE_EVENT_ATTR(_name, _id) \ diff --git a/drivers/perf/thunderx2_pmu.c b/drivers/perf/thunderx2_pmu.c index e116815fa8092fcc1bc96e7957ccf32ac628ceb8..06a6d569b0b56e556ea4917e4717d44821794fb6 100644 --- a/drivers/perf/thunderx2_pmu.c +++ b/drivers/perf/thunderx2_pmu.c @@ -128,7 +128,7 @@ __tx2_pmu_##_var##_show(struct device *dev, \ char *page) \ { \ BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ - return sprintf(page, _format "\n"); \ + return sysfs_emit(page, _format "\n"); \ } \ \ static struct device_attribute format_attr_##_var = \ @@ -176,7 +176,7 @@ static ssize_t tx2_pmu_event_show(struct device *dev, struct dev_ext_attribute *eattr; eattr = container_of(attr, struct dev_ext_attribute, attr); - return sprintf(buf, "event=0x%lx\n", (unsigned long) eattr->var); + return sysfs_emit(buf, "event=0x%lx\n", (unsigned long) eattr->var); } #define TX2_EVENT_ATTR(name, config) \ diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c index 44faa51ba799291c707242a5327fdc300d84e692..ffe3bdeec8459efe26f0f3823b6e210c09c16b7a 100644 --- a/drivers/perf/xgene_pmu.c +++ b/drivers/perf/xgene_pmu.c @@ -170,7 +170,7 @@ static ssize_t xgene_pmu_format_show(struct device *dev, struct dev_ext_attribute *eattr; eattr = container_of(attr, struct dev_ext_attribute, attr); - return sprintf(buf, "%s\n", (char *) eattr->var); + return sysfs_emit(buf, "%s\n", (char *) eattr->var); } #define XGENE_PMU_FORMAT_ATTR(_name, _config) \ @@ -281,7 +281,7 @@ static ssize_t xgene_pmu_event_show(struct device *dev, struct dev_ext_attribute *eattr; eattr = container_of(attr, struct dev_ext_attribute, attr); - return sprintf(buf, "config=0x%lx\n", (unsigned long) eattr->var); + return sysfs_emit(buf, "config=0x%lx\n", (unsigned long) eattr->var); } #define XGENE_PMU_EVENT_ATTR(_name, _config) \ diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 68d9c2f6a5cafb17354768c7271934e247e8f20c..54c1f2f0985fc818f4d7fedcd60816a53e0cddc3 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -71,6 +71,7 @@ source "drivers/phy/ingenic/Kconfig" source "drivers/phy/lantiq/Kconfig" source "drivers/phy/marvell/Kconfig" source "drivers/phy/mediatek/Kconfig" +source "drivers/phy/microchip/Kconfig" source "drivers/phy/motorola/Kconfig" source "drivers/phy/mscc/Kconfig" source "drivers/phy/qualcomm/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 32261e164abda782ae86c8b4ba158e00091bf077..adac1b1a39d1cded3a2ef03ad043c709aba99b7b 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -20,6 +20,7 @@ obj-y += allwinner/ \ lantiq/ \ marvell/ \ mediatek/ \ + microchip/ \ motorola/ \ mscc/ \ qualcomm/ \ diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig index 09256339bd046694de65b21c37ec88df7eaf84a0..fd92b73b710951fa69848ed76662d2fa18a6906b 100644 --- a/drivers/phy/broadcom/Kconfig +++ b/drivers/phy/broadcom/Kconfig @@ -94,7 +94,7 @@ config PHY_BRCM_USB depends on ARCH_BCM4908 || ARCH_BRCMSTB || COMPILE_TEST depends on OF select GENERIC_PHY - select SOC_BRCMSTB + select SOC_BRCMSTB if ARCH_BRCMSTB default ARCH_BCM4908 default ARCH_BRCMSTB help diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig index 432832bdbd16d13bb6bdbba788825636febc7ab1..a62910ff55910db5c2bdff61ed416c28a0444362 100644 --- a/drivers/phy/cadence/Kconfig +++ b/drivers/phy/cadence/Kconfig @@ -7,6 +7,7 @@ config PHY_CADENCE_TORRENT tristate "Cadence Torrent PHY driver" depends on OF depends on HAS_IOMEM + depends on COMMON_CLK select GENERIC_PHY help Support for Cadence Torrent PHY. @@ -24,6 +25,7 @@ config PHY_CADENCE_DPHY config PHY_CADENCE_SIERRA tristate "Cadence Sierra PHY Driver" depends on OF && HAS_IOMEM && RESET_CONTROLLER + depends on COMMON_CLK select GENERIC_PHY help Enable this to support the Cadence Sierra PHY driver diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 26a0badabe38b77852c03279dbe0ad59bcc8db25..5c68e31c5939985a80c1415c3fef9817a3803fb3 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -7,6 +7,7 @@ * */ #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> @@ -20,10 +21,12 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <dt-bindings/phy/phy.h> +#include <dt-bindings/phy/phy-cadence.h> /* PHY register offsets */ #define SIERRA_COMMON_CDB_OFFSET 0x0 #define SIERRA_MACRO_ID_REG 0x0 +#define SIERRA_CMN_PLLLC_GEN_PREG 0x42 #define SIERRA_CMN_PLLLC_MODE_PREG 0x48 #define SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG 0x49 #define SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG 0x4A @@ -31,6 +34,9 @@ #define SIERRA_CMN_PLLLC_BWCAL_MODE1_PREG 0x4F #define SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG 0x50 #define SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG 0x62 +#define SIERRA_CMN_REFRCV_PREG 0x98 +#define SIERRA_CMN_REFRCV1_PREG 0xB8 +#define SIERRA_CMN_PLLLC1_GEN_PREG 0xC2 #define SIERRA_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \ ((0x4000 << (block_offset)) + \ @@ -144,6 +150,19 @@ #define SIERRA_MAX_LANES 16 #define PLL_LOCK_TIME 100000 +#define CDNS_SIERRA_OUTPUT_CLOCKS 2 +#define CDNS_SIERRA_INPUT_CLOCKS 5 +enum cdns_sierra_clock_input { + PHY_CLK, + CMN_REFCLK_DIG_DIV, + CMN_REFCLK1_DIG_DIV, + PLL0_REFCLK, + PLL1_REFCLK, +}; + +#define SIERRA_NUM_CMN_PLLC 2 +#define SIERRA_NUM_CMN_PLLC_PARENTS 2 + static const struct reg_field macro_id_type = REG_FIELD(SIERRA_MACRO_ID_REG, 0, 15); static const struct reg_field phy_pll_cfg_1 = @@ -151,6 +170,53 @@ static const struct reg_field phy_pll_cfg_1 = static const struct reg_field pllctrl_lock = REG_FIELD(SIERRA_PLLCTRL_STATUS_PREG, 0, 0); +static const char * const clk_names[] = { + [CDNS_SIERRA_PLL_CMNLC] = "pll_cmnlc", + [CDNS_SIERRA_PLL_CMNLC1] = "pll_cmnlc1", +}; + +enum cdns_sierra_cmn_plllc { + CMN_PLLLC, + CMN_PLLLC1, +}; + +struct cdns_sierra_pll_mux_reg_fields { + struct reg_field pfdclk_sel_preg; + struct reg_field plllc1en_field; + struct reg_field termen_field; +}; + +static const struct cdns_sierra_pll_mux_reg_fields cmn_plllc_pfdclk1_sel_preg[] = { + [CMN_PLLLC] = { + .pfdclk_sel_preg = REG_FIELD(SIERRA_CMN_PLLLC_GEN_PREG, 1, 1), + .plllc1en_field = REG_FIELD(SIERRA_CMN_REFRCV1_PREG, 8, 8), + .termen_field = REG_FIELD(SIERRA_CMN_REFRCV1_PREG, 0, 0), + }, + [CMN_PLLLC1] = { + .pfdclk_sel_preg = REG_FIELD(SIERRA_CMN_PLLLC1_GEN_PREG, 1, 1), + .plllc1en_field = REG_FIELD(SIERRA_CMN_REFRCV_PREG, 8, 8), + .termen_field = REG_FIELD(SIERRA_CMN_REFRCV_PREG, 0, 0), + }, +}; + +struct cdns_sierra_pll_mux { + struct clk_hw hw; + struct regmap_field *pfdclk_sel_preg; + struct regmap_field *plllc1en_field; + struct regmap_field *termen_field; + struct clk_init_data clk_data; +}; + +#define to_cdns_sierra_pll_mux(_hw) \ + container_of(_hw, struct cdns_sierra_pll_mux, hw) + +static const int pll_mux_parent_index[][SIERRA_NUM_CMN_PLLC_PARENTS] = { + [CMN_PLLLC] = { PLL0_REFCLK, PLL1_REFCLK }, + [CMN_PLLLC1] = { PLL1_REFCLK, PLL0_REFCLK }, +}; + +static u32 cdns_sierra_pll_mux_table[] = { 0, 1 }; + struct cdns_sierra_inst { struct phy *phy; u32 phy_type; @@ -197,12 +263,15 @@ struct cdns_sierra_phy { struct regmap_field *macro_id_type; struct regmap_field *phy_pll_cfg_1; struct regmap_field *pllctrl_lock[SIERRA_MAX_LANES]; - struct clk *clk; - struct clk *cmn_refclk_dig_div; - struct clk *cmn_refclk1_dig_div; + struct regmap_field *cmn_refrcv_refclk_plllc1en_preg[SIERRA_NUM_CMN_PLLC]; + struct regmap_field *cmn_refrcv_refclk_termen_preg[SIERRA_NUM_CMN_PLLC]; + struct regmap_field *cmn_plllc_pfdclk1_sel_preg[SIERRA_NUM_CMN_PLLC]; + struct clk *input_clks[CDNS_SIERRA_INPUT_CLOCKS]; int nsubnodes; u32 num_lanes; bool autoconf; + struct clk_onecell_data clk_data; + struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS]; }; static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val) @@ -281,8 +350,8 @@ static int cdns_sierra_phy_init(struct phy *gphy) if (phy->autoconf) return 0; - clk_set_rate(phy->cmn_refclk_dig_div, 25000000); - clk_set_rate(phy->cmn_refclk1_dig_div, 25000000); + clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000); + clk_set_rate(phy->input_clks[CMN_REFCLK1_DIG_DIV], 25000000); if (ins->phy_type == PHY_TYPE_PCIE) { num_cmn_regs = phy->init_data->pcie_cmn_regs; num_ln_regs = phy->init_data->pcie_ln_regs; @@ -319,6 +388,12 @@ static int cdns_sierra_phy_on(struct phy *gphy) u32 val; int ret; + ret = reset_control_deassert(sp->phy_rst); + if (ret) { + dev_err(dev, "Failed to take the PHY out of reset\n"); + return ret; + } + /* Take the PHY lane group out of reset */ ret = reset_control_deassert(ins->lnk_rst); if (ret) { @@ -358,6 +433,153 @@ static const struct phy_ops ops = { .owner = THIS_MODULE, }; +static u8 cdns_sierra_pll_mux_get_parent(struct clk_hw *hw) +{ + struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw); + struct regmap_field *field = mux->pfdclk_sel_preg; + unsigned int val; + + regmap_field_read(field, &val); + return clk_mux_val_to_index(hw, cdns_sierra_pll_mux_table, 0, val); +} + +static int cdns_sierra_pll_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw); + struct regmap_field *plllc1en_field = mux->plllc1en_field; + struct regmap_field *termen_field = mux->termen_field; + struct regmap_field *field = mux->pfdclk_sel_preg; + int val, ret; + + ret = regmap_field_write(plllc1en_field, 0); + ret |= regmap_field_write(termen_field, 0); + if (index == 1) { + ret |= regmap_field_write(plllc1en_field, 1); + ret |= regmap_field_write(termen_field, 1); + } + + val = cdns_sierra_pll_mux_table[index]; + ret |= regmap_field_write(field, val); + + return ret; +} + +static const struct clk_ops cdns_sierra_pll_mux_ops = { + .set_parent = cdns_sierra_pll_mux_set_parent, + .get_parent = cdns_sierra_pll_mux_get_parent, +}; + +static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp, + struct regmap_field *pfdclk1_sel_field, + struct regmap_field *plllc1en_field, + struct regmap_field *termen_field, + int clk_index) +{ + struct cdns_sierra_pll_mux *mux; + struct device *dev = sp->dev; + struct clk_init_data *init; + const char **parent_names; + unsigned int num_parents; + char clk_name[100]; + struct clk *clk; + int i; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + num_parents = SIERRA_NUM_CMN_PLLC_PARENTS; + parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) { + clk = sp->input_clks[pll_mux_parent_index[clk_index][i]]; + if (IS_ERR_OR_NULL(clk)) { + dev_err(dev, "No parent clock for derived_refclk\n"); + return PTR_ERR(clk); + } + parent_names[i] = __clk_get_name(clk); + } + + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), clk_names[clk_index]); + + init = &mux->clk_data; + + init->ops = &cdns_sierra_pll_mux_ops; + init->flags = CLK_SET_RATE_NO_REPARENT; + init->parent_names = parent_names; + init->num_parents = num_parents; + init->name = clk_name; + + mux->pfdclk_sel_preg = pfdclk1_sel_field; + mux->plllc1en_field = plllc1en_field; + mux->termen_field = termen_field; + mux->hw.init = init; + + clk = devm_clk_register(dev, &mux->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + sp->output_clks[clk_index] = clk; + + return 0; +} + +static int cdns_sierra_phy_register_pll_mux(struct cdns_sierra_phy *sp) +{ + struct regmap_field *pfdclk1_sel_field; + struct regmap_field *plllc1en_field; + struct regmap_field *termen_field; + struct device *dev = sp->dev; + int ret = 0, i, clk_index; + + clk_index = CDNS_SIERRA_PLL_CMNLC; + for (i = 0; i < SIERRA_NUM_CMN_PLLC; i++, clk_index++) { + pfdclk1_sel_field = sp->cmn_plllc_pfdclk1_sel_preg[i]; + plllc1en_field = sp->cmn_refrcv_refclk_plllc1en_preg[i]; + termen_field = sp->cmn_refrcv_refclk_termen_preg[i]; + + ret = cdns_sierra_pll_mux_register(sp, pfdclk1_sel_field, plllc1en_field, + termen_field, clk_index); + if (ret) { + dev_err(dev, "Fail to register cmn plllc mux\n"); + return ret; + } + } + + return 0; +} + +static void cdns_sierra_clk_unregister(struct cdns_sierra_phy *sp) +{ + struct device *dev = sp->dev; + struct device_node *node = dev->of_node; + + of_clk_del_provider(node); +} + +static int cdns_sierra_clk_register(struct cdns_sierra_phy *sp) +{ + struct device *dev = sp->dev; + struct device_node *node = dev->of_node; + int ret; + + ret = cdns_sierra_phy_register_pll_mux(sp); + if (ret) { + dev_err(dev, "Failed to pll mux clocks\n"); + return ret; + } + + sp->clk_data.clks = sp->output_clks; + sp->clk_data.clk_num = CDNS_SIERRA_OUTPUT_CLOCKS; + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &sp->clk_data); + if (ret) + dev_err(dev, "Failed to add clock provider: %s\n", node->name); + + return ret; +} + static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst, struct device_node *child) { @@ -396,6 +618,7 @@ static int cdns_regfield_init(struct cdns_sierra_phy *sp) { struct device *dev = sp->dev; struct regmap_field *field; + struct reg_field reg_field; struct regmap *regmap; int i; @@ -407,6 +630,32 @@ static int cdns_regfield_init(struct cdns_sierra_phy *sp) } sp->macro_id_type = field; + for (i = 0; i < SIERRA_NUM_CMN_PLLC; i++) { + reg_field = cmn_plllc_pfdclk1_sel_preg[i].pfdclk_sel_preg; + field = devm_regmap_field_alloc(dev, regmap, reg_field); + if (IS_ERR(field)) { + dev_err(dev, "PLLLC%d_PFDCLK1_SEL failed\n", i); + return PTR_ERR(field); + } + sp->cmn_plllc_pfdclk1_sel_preg[i] = field; + + reg_field = cmn_plllc_pfdclk1_sel_preg[i].plllc1en_field; + field = devm_regmap_field_alloc(dev, regmap, reg_field); + if (IS_ERR(field)) { + dev_err(dev, "REFRCV%d_REFCLK_PLLLC1EN failed\n", i); + return PTR_ERR(field); + } + sp->cmn_refrcv_refclk_plllc1en_preg[i] = field; + + reg_field = cmn_plllc_pfdclk1_sel_preg[i].termen_field; + field = devm_regmap_field_alloc(dev, regmap, reg_field); + if (IS_ERR(field)) { + dev_err(dev, "REFRCV%d_REFCLK_TERMEN failed\n", i); + return PTR_ERR(field); + } + sp->cmn_refrcv_refclk_termen_preg[i] = field; + } + regmap = sp->regmap_phy_config_ctrl; field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg_1); if (IS_ERR(field)) { @@ -471,6 +720,110 @@ static int cdns_regmap_init_blocks(struct cdns_sierra_phy *sp, return 0; } +static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, + struct device *dev) +{ + struct clk *clk; + int ret; + + clk = devm_clk_get_optional(dev, "phy_clk"); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clock phy_clk\n"); + return PTR_ERR(clk); + } + sp->input_clks[PHY_CLK] = clk; + + clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div"); + if (IS_ERR(clk)) { + dev_err(dev, "cmn_refclk_dig_div clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->input_clks[CMN_REFCLK_DIG_DIV] = clk; + + clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div"); + if (IS_ERR(clk)) { + dev_err(dev, "cmn_refclk1_dig_div clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->input_clks[CMN_REFCLK1_DIG_DIV] = clk; + + clk = devm_clk_get_optional(dev, "pll0_refclk"); + if (IS_ERR(clk)) { + dev_err(dev, "pll0_refclk clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->input_clks[PLL0_REFCLK] = clk; + + clk = devm_clk_get_optional(dev, "pll1_refclk"); + if (IS_ERR(clk)) { + dev_err(dev, "pll1_refclk clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->input_clks[PLL1_REFCLK] = clk; + + return 0; +} + +static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp) +{ + int ret; + + ret = clk_prepare_enable(sp->input_clks[PHY_CLK]); + if (ret) + return ret; + + ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + if (ret) + goto err_pll_cmnlc; + + ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); + if (ret) + goto err_pll_cmnlc1; + + return 0; + +err_pll_cmnlc1: + clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + +err_pll_cmnlc: + clk_disable_unprepare(sp->input_clks[PHY_CLK]); + + return ret; +} + +static void cdns_sierra_phy_disable_clocks(struct cdns_sierra_phy *sp) +{ + clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); + clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + clk_disable_unprepare(sp->input_clks[PHY_CLK]); +} + +static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, + struct device *dev) +{ + struct reset_control *rst; + + rst = devm_reset_control_get_exclusive(dev, "sierra_reset"); + if (IS_ERR(rst)) { + dev_err(dev, "failed to get reset\n"); + return PTR_ERR(rst); + } + sp->phy_rst = rst; + + rst = devm_reset_control_get_optional_exclusive(dev, "sierra_apb"); + if (IS_ERR(rst)) { + dev_err(dev, "failed to get apb reset\n"); + return PTR_ERR(rst); + } + sp->apb_rst = rst; + + return 0; +} + static int cdns_sierra_phy_probe(struct platform_device *pdev) { struct cdns_sierra_phy *sp; @@ -481,7 +834,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) unsigned int id_value; int i, ret, node = 0; void __iomem *base; - struct clk *clk; struct device_node *dn = dev->of_node, *child; if (of_get_child_count(dn) == 0) @@ -518,43 +870,21 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sp); - sp->clk = devm_clk_get_optional(dev, "phy_clk"); - if (IS_ERR(sp->clk)) { - dev_err(dev, "failed to get clock phy_clk\n"); - return PTR_ERR(sp->clk); - } - - sp->phy_rst = devm_reset_control_get(dev, "sierra_reset"); - if (IS_ERR(sp->phy_rst)) { - dev_err(dev, "failed to get reset\n"); - return PTR_ERR(sp->phy_rst); - } - - sp->apb_rst = devm_reset_control_get_optional(dev, "sierra_apb"); - if (IS_ERR(sp->apb_rst)) { - dev_err(dev, "failed to get apb reset\n"); - return PTR_ERR(sp->apb_rst); - } - - clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div"); - if (IS_ERR(clk)) { - dev_err(dev, "cmn_refclk_dig_div clock not found\n"); - ret = PTR_ERR(clk); + ret = cdns_sierra_phy_get_clocks(sp, dev); + if (ret) return ret; - } - sp->cmn_refclk_dig_div = clk; - clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div"); - if (IS_ERR(clk)) { - dev_err(dev, "cmn_refclk1_dig_div clock not found\n"); - ret = PTR_ERR(clk); + ret = cdns_sierra_clk_register(sp); + if (ret) return ret; - } - sp->cmn_refclk1_dig_div = clk; - ret = clk_prepare_enable(sp->clk); + ret = cdns_sierra_phy_get_resets(sp, dev); if (ret) - return ret; + goto unregister_clk; + + ret = cdns_sierra_phy_enable_clocks(sp); + if (ret) + goto unregister_clk; /* Enable APB */ reset_control_deassert(sp->apb_rst); @@ -571,6 +901,10 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) for_each_available_child_of_node(dn, child) { struct phy *gphy; + if (!(of_node_name_eq(child, "phy") || + of_node_name_eq(child, "link"))) + continue; + sp->phys[node].lnk_rst = of_reset_control_array_get_exclusive(child); @@ -616,7 +950,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) pm_runtime_enable(dev); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - reset_control_deassert(sp->phy_rst); return PTR_ERR_OR_ZERO(phy_provider); put_child: @@ -626,8 +959,10 @@ put_child2: reset_control_put(sp->phys[i].lnk_rst); of_node_put(child); clk_disable: - clk_disable_unprepare(sp->clk); + cdns_sierra_phy_disable_clocks(sp); reset_control_assert(sp->apb_rst); +unregister_clk: + cdns_sierra_clk_unregister(sp); return ret; } @@ -640,6 +975,7 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) reset_control_assert(phy->apb_rst); pm_runtime_disable(&pdev->dev); + cdns_sierra_phy_disable_clocks(phy); /* * The device level resets will be put automatically. * Need to put the subnode resets here though. @@ -648,6 +984,9 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) reset_control_assert(phy->phys[i].lnk_rst); reset_control_put(phy->phys[i].lnk_rst); } + + cdns_sierra_clk_unregister(phy); + return 0; } diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 591a15834b48f7ba5a06f9fe4c2faa2dd5162d32..0477e7beebbf594ea72f1b7eaf55699b360416d9 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -7,7 +7,9 @@ */ #include <dt-bindings/phy/phy.h> +#include <dt-bindings/phy/phy-cadence.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> @@ -84,6 +86,8 @@ #define CMN_PLLSM1_PLLLOCK_TMR 0x0034U #define CMN_CDIAG_CDB_PWRI_OVRD 0x0041U #define CMN_CDIAG_XCVRC_PWRI_OVRD 0x0047U +#define CMN_CDIAG_REFCLK_OVRD 0x004CU +#define CMN_CDIAG_REFCLK_DRV0_CTRL 0x0050U #define CMN_BGCAL_INIT_TMR 0x0064U #define CMN_BGCAL_ITER_TMR 0x0065U #define CMN_IBCAL_INIT_TMR 0x0074U @@ -122,6 +126,8 @@ #define CMN_PLL1_FRACDIVH_M0 0x00D2U #define CMN_PLL1_HIGH_THR_M0 0x00D3U #define CMN_PLL1_DSM_DIAG_M0 0x00D4U +#define CMN_PLL1_DSM_FBH_OVRD_M0 0x00D5U +#define CMN_PLL1_DSM_FBL_OVRD_M0 0x00D6U #define CMN_PLL1_SS_CTRL1_M0 0x00D8U #define CMN_PLL1_SS_CTRL2_M0 0x00D9U #define CMN_PLL1_SS_CTRL3_M0 0x00DAU @@ -163,10 +169,12 @@ #define TX_TXCC_CPOST_MULT_00 0x004CU #define TX_TXCC_CPOST_MULT_01 0x004DU #define TX_TXCC_MGNFS_MULT_000 0x0050U +#define TX_TXCC_MGNFS_MULT_100 0x0054U #define DRV_DIAG_TX_DRV 0x00C6U #define XCVR_DIAG_PLLDRC_CTRL 0x00E5U #define XCVR_DIAG_HSCLK_SEL 0x00E6U #define XCVR_DIAG_HSCLK_DIV 0x00E7U +#define XCVR_DIAG_RXCLK_CTRL 0x00E9U #define XCVR_DIAG_BIDI_CTRL 0x00EAU #define XCVR_DIAG_PSC_OVRD 0x00EBU #define TX_PSC_A0 0x0100U @@ -206,6 +214,7 @@ #define RX_DIAG_ACYA 0x01FFU /* PHY PCS common registers */ +#define PHY_PIPE_CMN_CTRL1 0x0000U #define PHY_PLL_CFG 0x000EU #define PHY_PIPE_USB3_GEN2_PRE_CFG0 0x0020U #define PHY_PIPE_USB3_GEN2_POST_CFG0 0x0022U @@ -216,6 +225,10 @@ #define PHY_PMA_CMN_CTRL2 0x0001U #define PHY_PMA_PLL_RAW_CTRL 0x0003U +static const char * const clk_names[] = { + [CDNS_TORRENT_REFCLK_DRIVER] = "refclk-driver", +}; + static const struct reg_field phy_pll_cfg = REG_FIELD(PHY_PLL_CFG, 0, 1); @@ -231,6 +244,26 @@ static const struct reg_field phy_pma_pll_raw_ctrl = static const struct reg_field phy_reset_ctrl = REG_FIELD(PHY_RESET, 8, 8); +static const struct reg_field phy_pipe_cmn_ctrl1_0 = REG_FIELD(PHY_PIPE_CMN_CTRL1, 0, 0); + +#define REFCLK_OUT_NUM_CMN_CONFIG 5 + +enum cdns_torrent_refclk_out_cmn { + CMN_CDIAG_REFCLK_OVRD_4, + CMN_CDIAG_REFCLK_DRV0_CTRL_1, + CMN_CDIAG_REFCLK_DRV0_CTRL_4, + CMN_CDIAG_REFCLK_DRV0_CTRL_5, + CMN_CDIAG_REFCLK_DRV0_CTRL_6, +}; + +static const struct reg_field refclk_out_cmn_cfg[] = { + [CMN_CDIAG_REFCLK_OVRD_4] = REG_FIELD(CMN_CDIAG_REFCLK_OVRD, 4, 4), + [CMN_CDIAG_REFCLK_DRV0_CTRL_1] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 1, 1), + [CMN_CDIAG_REFCLK_DRV0_CTRL_4] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 4, 4), + [CMN_CDIAG_REFCLK_DRV0_CTRL_5] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 5, 5), + [CMN_CDIAG_REFCLK_DRV0_CTRL_6] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 6, 6), +}; + enum cdns_torrent_phy_type { TYPE_NONE, TYPE_DP, @@ -279,6 +312,8 @@ struct cdns_torrent_phy { struct regmap_field *phy_pma_cmn_ctrl_2; struct regmap_field *phy_pma_pll_raw_ctrl; struct regmap_field *phy_reset_ctrl; + struct clk *clks[CDNS_TORRENT_REFCLK_DRIVER + 1]; + struct clk_onecell_data clk_data; }; enum phy_powerstate { @@ -288,6 +323,16 @@ enum phy_powerstate { POWERSTATE_A3 = 3, }; +struct cdns_torrent_derived_refclk { + struct clk_hw hw; + struct regmap_field *phy_pipe_cmn_ctrl1_0; + struct regmap_field *cmn_fields[REFCLK_OUT_NUM_CMN_CONFIG]; + struct clk_init_data clk_data; +}; + +#define to_cdns_torrent_derived_refclk(_hw) \ + container_of(_hw, struct cdns_torrent_derived_refclk, hw) + static int cdns_torrent_phy_init(struct phy *phy); static int cdns_torrent_dp_init(struct phy *phy); static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, @@ -326,6 +371,19 @@ static const struct phy_ops cdns_torrent_phy_ops = { .owner = THIS_MODULE, }; +static int cdns_torrent_noop_phy_on(struct phy *phy) +{ + /* Give 5ms to 10ms delay for the PIPE clock to be stable */ + usleep_range(5000, 10000); + + return 0; +} + +static const struct phy_ops noop_ops = { + .power_on = cdns_torrent_noop_phy_on, + .owner = THIS_MODULE, +}; + struct cdns_reg_pairs { u32 val; u32 off; @@ -1604,6 +1662,108 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) return ret; } +static int cdns_torrent_derived_refclk_enable(struct clk_hw *hw) +{ + struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); + + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_6], 0); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_5], 1); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 0); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_OVRD_4], 1); + regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 1); + + return 0; +} + +static void cdns_torrent_derived_refclk_disable(struct clk_hw *hw) +{ + struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); + + regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 0); +} + +static int cdns_torrent_derived_refclk_is_enabled(struct clk_hw *hw) +{ + struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); + int val; + + regmap_field_read(derived_refclk->phy_pipe_cmn_ctrl1_0, &val); + + return !!val; +} + +static const struct clk_ops cdns_torrent_derived_refclk_ops = { + .enable = cdns_torrent_derived_refclk_enable, + .disable = cdns_torrent_derived_refclk_disable, + .is_enabled = cdns_torrent_derived_refclk_is_enabled, +}; + +static int cdns_torrent_derived_refclk_register(struct cdns_torrent_phy *cdns_phy) +{ + struct cdns_torrent_derived_refclk *derived_refclk; + struct device *dev = cdns_phy->dev; + struct regmap_field *field; + struct clk_init_data *init; + const char *parent_name; + struct regmap *regmap; + char clk_name[100]; + struct clk *clk; + int i; + + derived_refclk = devm_kzalloc(dev, sizeof(*derived_refclk), GFP_KERNEL); + if (!derived_refclk) + return -ENOMEM; + + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), + clk_names[CDNS_TORRENT_REFCLK_DRIVER]); + + clk = devm_clk_get_optional(dev, "phy_en_refclk"); + if (IS_ERR(clk)) { + dev_err(dev, "No parent clock for derived_refclk\n"); + return PTR_ERR(clk); + } + + init = &derived_refclk->clk_data; + + if (clk) { + parent_name = __clk_get_name(clk); + init->parent_names = &parent_name; + init->num_parents = 1; + } + init->ops = &cdns_torrent_derived_refclk_ops; + init->flags = 0; + init->name = clk_name; + + regmap = cdns_phy->regmap_phy_pcs_common_cdb; + field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0); + if (IS_ERR(field)) { + dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n"); + return PTR_ERR(field); + } + derived_refclk->phy_pipe_cmn_ctrl1_0 = field; + + regmap = cdns_phy->regmap_common_cdb; + for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) { + field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]); + if (IS_ERR(field)) { + dev_err(dev, "CMN reg field init failed\n"); + return PTR_ERR(field); + } + derived_refclk->cmn_fields[i] = field; + } + + derived_refclk->hw.init = init; + + clk = devm_clk_register(dev, &derived_refclk->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + cdns_phy->clks[CDNS_TORRENT_REFCLK_DRIVER] = clk; + + return 0; +} + static int cdns_torrent_phy_on(struct phy *phy) { struct cdns_torrent_inst *inst = phy_get_drvdata(phy); @@ -2071,6 +2231,85 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) return 0; } +static void cdns_torrent_clk_cleanup(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + + of_clk_del_provider(dev->of_node); +} + +static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + struct device_node *node = dev->of_node; + int ret; + + ret = cdns_torrent_derived_refclk_register(cdns_phy); + if (ret) { + dev_err(dev, "failed to register derived refclk\n"); + return ret; + } + + cdns_phy->clk_data.clks = cdns_phy->clks; + cdns_phy->clk_data.clk_num = CDNS_TORRENT_REFCLK_DRIVER + 1; + + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &cdns_phy->clk_data); + if (ret) { + dev_err(dev, "Failed to add clock provider: %s\n", node->name); + return ret; + } + + return 0; +} + +static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + + cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0); + if (IS_ERR(cdns_phy->phy_rst)) { + dev_err(dev, "%s: failed to get reset\n", + dev->of_node->full_name); + return PTR_ERR(cdns_phy->phy_rst); + } + + cdns_phy->apb_rst = devm_reset_control_get_optional_exclusive(dev, "torrent_apb"); + if (IS_ERR(cdns_phy->apb_rst)) { + dev_err(dev, "%s: failed to get apb reset\n", + dev->of_node->full_name); + return PTR_ERR(cdns_phy->apb_rst); + } + + return 0; +} + +static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + int ret; + + cdns_phy->clk = devm_clk_get(dev, "refclk"); + if (IS_ERR(cdns_phy->clk)) { + dev_err(dev, "phy ref clock not found\n"); + return PTR_ERR(cdns_phy->clk); + } + + ret = clk_prepare_enable(cdns_phy->clk); + if (ret) { + dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + return ret; + } + + cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk); + if (!(cdns_phy->ref_clk_rate)) { + dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); + clk_disable_unprepare(cdns_phy->clk); + return -EINVAL; + } + + return 0; +} + static int cdns_torrent_phy_probe(struct platform_device *pdev) { struct cdns_torrent_phy *cdns_phy; @@ -2080,6 +2319,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) struct device_node *child; int ret, subnodes, node = 0, i; u32 total_num_lanes = 0; + int already_configured; u8 init_dp_regmap = 0; u32 phy_type; @@ -2096,26 +2336,6 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) cdns_phy->dev = dev; cdns_phy->init_data = data; - cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0); - if (IS_ERR(cdns_phy->phy_rst)) { - dev_err(dev, "%s: failed to get reset\n", - dev->of_node->full_name); - return PTR_ERR(cdns_phy->phy_rst); - } - - cdns_phy->apb_rst = devm_reset_control_get_optional(dev, "torrent_apb"); - if (IS_ERR(cdns_phy->apb_rst)) { - dev_err(dev, "%s: failed to get apb reset\n", - dev->of_node->full_name); - return PTR_ERR(cdns_phy->apb_rst); - } - - cdns_phy->clk = devm_clk_get(dev, "refclk"); - if (IS_ERR(cdns_phy->clk)) { - dev_err(dev, "phy ref clock not found\n"); - return PTR_ERR(cdns_phy->clk); - } - cdns_phy->sd_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cdns_phy->sd_base)) return PTR_ERR(cdns_phy->sd_base); @@ -2134,21 +2354,24 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_prepare_enable(cdns_phy->clk); - if (ret) { - dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + ret = cdns_torrent_clk_register(cdns_phy); + if (ret) return ret; - } - cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk); - if (!(cdns_phy->ref_clk_rate)) { - dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; - } + regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured); - /* Enable APB */ - reset_control_deassert(cdns_phy->apb_rst); + if (!already_configured) { + ret = cdns_torrent_reset(cdns_phy); + if (ret) + goto clk_cleanup; + + ret = cdns_torrent_clk(cdns_phy); + if (ret) + goto clk_cleanup; + + /* Enable APB */ + reset_control_deassert(cdns_phy->apb_rst); + } for_each_available_child_of_node(dev->of_node, child) { struct phy *gphy; @@ -2218,7 +2441,10 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) of_property_read_u32(child, "cdns,ssc-mode", &cdns_phy->phys[node].ssc_mode); - gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); + if (!already_configured) + gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); + else + gphy = devm_phy_create(dev, child, &noop_ops); if (IS_ERR(gphy)) { ret = PTR_ERR(gphy); goto put_child; @@ -2302,7 +2528,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) goto put_lnk_rst; } - if (cdns_phy->nsubnodes > 1) { + if (cdns_phy->nsubnodes > 1 && !already_configured) { ret = cdns_torrent_phy_configure_multilink(cdns_phy); if (ret) goto put_lnk_rst; @@ -2324,6 +2550,8 @@ put_lnk_rst: of_node_put(child); reset_control_assert(cdns_phy->apb_rst); clk_disable_unprepare(cdns_phy->clk); +clk_cleanup: + cdns_torrent_clk_cleanup(cdns_phy); return ret; } @@ -2340,6 +2568,7 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev) } clk_disable_unprepare(cdns_phy->clk); + cdns_torrent_clk_cleanup(cdns_phy); return 0; } @@ -2455,8 +2684,6 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, @@ -2464,7 +2691,9 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, {0x0005, CMN_PLL1_LOCK_PLLCNT_THR}, {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, - {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD} + {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_torrent_vals usb_100_int_ssc_cmn_vals = { @@ -2507,13 +2736,28 @@ static struct cdns_torrent_vals usb_phy_pcs_cmn_vals = { }; /* USB 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = { +static struct cdns_reg_pairs sl_usb_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, {0x0003, CMN_PLL0_VCOCAL_TCTRL}, {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD} }; +static struct cdns_torrent_vals sl_usb_100_no_ssc_cmn_vals = { + .reg_pairs = sl_usb_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_usb_100_no_ssc_cmn_regs), +}; + +static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = { + {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, + {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + static struct cdns_reg_pairs usb_100_no_ssc_tx_ln_regs[] = { {0x02FF, TX_PSC_A0}, {0x06AF, TX_PSC_A1}, @@ -2645,12 +2889,22 @@ static struct cdns_torrent_vals sgmii_pcie_xcvr_diag_ln_vals = { }; /* SGMII 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = { +static struct cdns_reg_pairs sl_sgmii_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, - {0x3700, CMN_DIAG_BIAS_OVRD1}, - {0x0008, CMN_TXPUCAL_TUNE}, - {0x0008, CMN_TXPDCAL_TUNE} + {0x0003, CMN_PLL1_VCOCAL_TCTRL} +}; + +static struct cdns_torrent_vals sl_sgmii_100_no_ssc_cmn_vals = { + .reg_pairs = sl_sgmii_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_sgmii_100_no_ssc_cmn_regs), +}; + +static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = { + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = { @@ -2661,6 +2915,15 @@ static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = { {0x00B3, DRV_DIAG_TX_DRV} }; +static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = { + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3}, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x00B3, DRV_DIAG_TX_DRV}, + {0x4000, XCVR_DIAG_RXCLK_CTRL}, +}; + static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = { {0x091D, RX_PSC_A0}, {0x0900, RX_PSC_A2}, @@ -2689,6 +2952,11 @@ static struct cdns_torrent_vals sgmii_100_no_ssc_tx_ln_vals = { .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_tx_ln_regs), }; +static struct cdns_torrent_vals ti_sgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = ti_sgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ti_sgmii_100_no_ssc_tx_ln_regs), +}; + static struct cdns_torrent_vals sgmii_100_no_ssc_rx_ln_vals = { .reg_pairs = sgmii_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_rx_ln_regs), @@ -2736,17 +3004,14 @@ static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, {0x00C7, CMN_PLL1_LOCK_PLLCNT_START}, {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, {0x0005, CMN_PLL1_LOCK_PLLCNT_THR}, - {0x3700, CMN_DIAG_BIAS_OVRD1}, - {0x0008, CMN_TXPUCAL_TUNE}, - {0x0008, CMN_TXPDCAL_TUNE} + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = { @@ -2755,19 +3020,43 @@ static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = { }; /* QSGMII 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = { +static struct cdns_reg_pairs sl_qsgmii_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, {0x0003, CMN_PLL0_VCOCAL_TCTRL}, {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; +static struct cdns_torrent_vals sl_qsgmii_100_no_ssc_cmn_vals = { + .reg_pairs = sl_qsgmii_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_qsgmii_100_no_ssc_cmn_regs), +}; + +static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = { + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + static struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = { {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, {0x0003, DRV_DIAG_TX_DRV} }; +static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = { + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3}, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, + {0x0003, DRV_DIAG_TX_DRV}, + {0x4000, XCVR_DIAG_RXCLK_CTRL}, +}; + static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = { {0x091D, RX_PSC_A0}, {0x0900, RX_PSC_A2}, @@ -2796,6 +3085,11 @@ static struct cdns_torrent_vals qsgmii_100_no_ssc_tx_ln_vals = { .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_tx_ln_regs), }; +static struct cdns_torrent_vals ti_qsgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = ti_qsgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ti_qsgmii_100_no_ssc_tx_ln_regs), +}; + static struct cdns_torrent_vals qsgmii_100_no_ssc_rx_ln_vals = { .reg_pairs = qsgmii_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_rx_ln_regs), @@ -2843,14 +3137,14 @@ static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, {0x00C7, CMN_PLL1_LOCK_PLLCNT_START}, {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, - {0x0005, CMN_PLL1_LOCK_PLLCNT_THR} + {0x0005, CMN_PLL1_LOCK_PLLCNT_THR}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_torrent_vals qsgmii_100_int_ssc_cmn_vals = { @@ -2922,8 +3216,6 @@ static struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, @@ -2979,8 +3271,6 @@ static struct cdns_reg_pairs sl_pcie_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, @@ -2996,8 +3286,9 @@ static struct cdns_torrent_vals sl_pcie_100_int_ssc_cmn_vals = { /* PCIe, 100 MHz Ref clk, no SSC & external SSC */ static struct cdns_reg_pairs pcie_100_ext_no_ssc_cmn_regs[] = { - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL} + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0} }; static struct cdns_reg_pairs pcie_100_ext_no_ssc_rx_ln_regs[] = { @@ -3198,8 +3489,8 @@ static const struct cdns_torrent_data cdns_map_torrent = { .cmn_vals = { [TYPE_PCIE] = { [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { @@ -3220,7 +3511,7 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, [TYPE_SGMII] = { [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, @@ -3235,7 +3526,7 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, [TYPE_QSGMII] = { [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, @@ -3250,8 +3541,8 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, [TYPE_USB] = { [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_PCIE] = { @@ -3260,13 +3551,13 @@ static const struct cdns_torrent_data cdns_map_torrent = { [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, }, @@ -3607,8 +3898,8 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { .cmn_vals = { [TYPE_PCIE] = { [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { @@ -3629,7 +3920,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_SGMII] = { [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, @@ -3644,7 +3935,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_QSGMII] = { [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, @@ -3659,8 +3950,8 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_USB] = { [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_PCIE] = { @@ -3669,13 +3960,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, }, @@ -3705,32 +3996,32 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_SGMII] = { [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, }, [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, }, [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, }, }, [TYPE_QSGMII] = { [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, }, [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, }, [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, }, }, [TYPE_USB] = { diff --git a/drivers/phy/hisilicon/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c index be05292df8b817925709ed38dbc587e770046af4..e92ba78da4c83076cd0857d817319bd3fe5bd17e 100644 --- a/drivers/phy/hisilicon/phy-hi6220-usb.c +++ b/drivers/phy/hisilicon/phy-hi6220-usb.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015 Linaro Ltd. - * Copyright (c) 2015 Hisilicon Limited. + * Copyright (c) 2015 HiSilicon Limited. */ #include <linux/mfd/syscon.h> diff --git a/drivers/phy/hisilicon/phy-hix5hd2-sata.c b/drivers/phy/hisilicon/phy-hix5hd2-sata.c index c67b78cd2602029fd163cf8082aee8f53c4143ff..b0f99a9ac857769add79ae6897c0653b88835355 100644 --- a/drivers/phy/hisilicon/phy-hix5hd2-sata.c +++ b/drivers/phy/hisilicon/phy-hix5hd2-sata.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Linaro Ltd. - * Copyright (c) 2014 Hisilicon Limited. + * Copyright (c) 2014 HiSilicon Limited. */ #include <linux/delay.h> diff --git a/drivers/phy/ingenic/phy-ingenic-usb.c b/drivers/phy/ingenic/phy-ingenic-usb.c index ea127b177f46b3a4f69a962a9890af489cbe55c5..28c28d81648492b9e560c45fda35e38276002b3f 100644 --- a/drivers/phy/ingenic/phy-ingenic-usb.c +++ b/drivers/phy/ingenic/phy-ingenic-usb.c @@ -352,8 +352,8 @@ static int ingenic_usb_phy_probe(struct platform_device *pdev) } priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops); - if (IS_ERR(priv)) - return PTR_ERR(priv); + if (IS_ERR(priv->phy)) + return PTR_ERR(priv->phy); phy_set_drvdata(priv->phy, priv); diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index 360b1eb2ebd694a47608ef307df054290a3e685b..157683d10367014e472446b3402032fd9d7dc986 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -462,7 +462,7 @@ static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy) /* * syscfg and hsiocfg variables stores the handle of the registers set - * in which ComboPhy subsytem specific registers are subset. Using + * in which ComboPhy subsystem specific registers are subset. Using * Register map framework to access the registers set. */ ret = fwnode_property_get_reference_args(fwnode, "intel,syscfg", NULL, diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index 6c96f2bf52665789ff67fb391b8dfc877e3df544..bdb87c976243599d61131b7b3d21365c56f825dd 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -3,8 +3,8 @@ # Phy drivers for Marvell platforms # config ARMADA375_USBCLUSTER_PHY - def_bool y - depends on MACH_ARMADA_375 || COMPILE_TEST + bool "Armada 375 USB cluster PHY support" if COMPILE_TEST + default y if MACH_ARMADA_375 depends on OF && HAS_IOMEM select GENERIC_PHY @@ -67,6 +67,14 @@ config PHY_MVEBU_CP110_COMPHY lanes can be used by various controllers (Ethernet, sata, usb, PCIe...). +config PHY_MVEBU_CP110_UTMI + tristate "Marvell CP110 UTMI driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on OF && USB_COMMON + select GENERIC_PHY + help + Enable this to support Marvell CP110 UTMI PHY driver. + config PHY_MVEBU_SATA def_bool y depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile index 7f296ef028292d610e71d2918ea6bf62e8a248b7..90862c4daa262e4ef8525ca412c046e669c98670 100644 --- a/drivers/phy/marvell/Makefile +++ b/drivers/phy/marvell/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o +obj-$(CONFIG_PHY_MVEBU_CP110_UTMI) += phy-mvebu-cp110-utmi.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c new file mode 100644 index 0000000000000000000000000000000000000000..08d178a4dc13f5c5405617af08bb89b5ef91de51 --- /dev/null +++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Marvell + * + * Authors: + * Konstantin Porotchkin <kostap@marvell.com> + * + * Marvell CP110 UTMI PHY driver + */ + +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/usb/of.h> +#include <linux/usb/otg.h> + +#define UTMI_PHY_PORTS 2 + +/* CP110 UTMI register macro definetions */ +#define SYSCON_USB_CFG_REG 0x420 +#define USB_CFG_DEVICE_EN_MASK BIT(0) +#define USB_CFG_DEVICE_MUX_OFFSET 1 +#define USB_CFG_DEVICE_MUX_MASK BIT(1) +#define USB_CFG_PLL_MASK BIT(25) + +#define SYSCON_UTMI_CFG_REG(id) (0x440 + (id) * 4) +#define UTMI_PHY_CFG_PU_MASK BIT(5) + +#define UTMI_PLL_CTRL_REG 0x0 +#define PLL_REFDIV_OFFSET 0 +#define PLL_REFDIV_MASK GENMASK(6, 0) +#define PLL_REFDIV_VAL 0x5 +#define PLL_FBDIV_OFFSET 16 +#define PLL_FBDIV_MASK GENMASK(24, 16) +#define PLL_FBDIV_VAL 0x60 +#define PLL_SEL_LPFR_MASK GENMASK(29, 28) +#define PLL_RDY BIT(31) +#define UTMI_CAL_CTRL_REG 0x8 +#define IMPCAL_VTH_OFFSET 8 +#define IMPCAL_VTH_MASK GENMASK(10, 8) +#define IMPCAL_VTH_VAL 0x7 +#define IMPCAL_DONE BIT(23) +#define PLLCAL_DONE BIT(31) +#define UTMI_TX_CH_CTRL_REG 0xC +#define DRV_EN_LS_OFFSET 12 +#define DRV_EN_LS_MASK GENMASK(15, 12) +#define IMP_SEL_LS_OFFSET 16 +#define IMP_SEL_LS_MASK GENMASK(19, 16) +#define TX_AMP_OFFSET 20 +#define TX_AMP_MASK GENMASK(22, 20) +#define TX_AMP_VAL 0x4 +#define UTMI_RX_CH_CTRL0_REG 0x14 +#define SQ_DET_EN BIT(15) +#define SQ_ANA_DTC_SEL BIT(28) +#define UTMI_RX_CH_CTRL1_REG 0x18 +#define SQ_AMP_CAL_OFFSET 0 +#define SQ_AMP_CAL_MASK GENMASK(2, 0) +#define SQ_AMP_CAL_VAL 1 +#define SQ_AMP_CAL_EN BIT(3) +#define UTMI_CTRL_STATUS0_REG 0x24 +#define SUSPENDM BIT(22) +#define TEST_SEL BIT(25) +#define UTMI_CHGDTC_CTRL_REG 0x38 +#define VDAT_OFFSET 8 +#define VDAT_MASK GENMASK(9, 8) +#define VDAT_VAL 1 +#define VSRC_OFFSET 10 +#define VSRC_MASK GENMASK(11, 10) +#define VSRC_VAL 1 + +#define PLL_LOCK_DELAY_US 10000 +#define PLL_LOCK_TIMEOUT_US 1000000 + +#define PORT_REGS(p) ((p)->priv->regs + (p)->id * 0x1000) + +/** + * struct mvebu_cp110_utmi - PHY driver data + * + * @regs: PHY registers + * @syscom: Regmap with system controller registers + * @dev: device driver handle + * @caps: PHY capabilities + */ +struct mvebu_cp110_utmi { + void __iomem *regs; + struct regmap *syscon; + struct device *dev; + const struct phy_ops *ops; +}; + +/** + * struct mvebu_cp110_utmi_port - PHY port data + * + * @priv: PHY driver data + * @id: PHY port ID + * @dr_mode: PHY connection: USB_DR_MODE_HOST or USB_DR_MODE_PERIPHERAL + */ +struct mvebu_cp110_utmi_port { + struct mvebu_cp110_utmi *priv; + u32 id; + enum usb_dr_mode dr_mode; +}; + +static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port) +{ + u32 reg; + + /* + * Setup PLL. + * The reference clock is the frequency of quartz resonator + * connected to pins REFCLK_XIN and REFCLK_XOUT of the SoC. + * Register init values are matching the 40MHz default clock. + * The crystal used for all platform boards is now 25MHz. + * See the functional specification for details. + */ + reg = readl(PORT_REGS(port) + UTMI_PLL_CTRL_REG); + reg &= ~(PLL_REFDIV_MASK | PLL_FBDIV_MASK | PLL_SEL_LPFR_MASK); + reg |= (PLL_REFDIV_VAL << PLL_REFDIV_OFFSET) | + (PLL_FBDIV_VAL << PLL_FBDIV_OFFSET); + writel(reg, PORT_REGS(port) + UTMI_PLL_CTRL_REG); + + /* Impedance Calibration Threshold Setting */ + reg = readl(PORT_REGS(port) + UTMI_CAL_CTRL_REG); + reg &= ~IMPCAL_VTH_MASK; + reg |= IMPCAL_VTH_VAL << IMPCAL_VTH_OFFSET; + writel(reg, PORT_REGS(port) + UTMI_CAL_CTRL_REG); + + /* Set LS TX driver strength coarse control */ + reg = readl(PORT_REGS(port) + UTMI_TX_CH_CTRL_REG); + reg &= ~TX_AMP_MASK; + reg |= TX_AMP_VAL << TX_AMP_OFFSET; + writel(reg, PORT_REGS(port) + UTMI_TX_CH_CTRL_REG); + + /* Disable SQ and enable analog squelch detect */ + reg = readl(PORT_REGS(port) + UTMI_RX_CH_CTRL0_REG); + reg &= ~SQ_DET_EN; + reg |= SQ_ANA_DTC_SEL; + writel(reg, PORT_REGS(port) + UTMI_RX_CH_CTRL0_REG); + + /* + * Set External squelch calibration number and + * enable the External squelch calibration + */ + reg = readl(PORT_REGS(port) + UTMI_RX_CH_CTRL1_REG); + reg &= ~SQ_AMP_CAL_MASK; + reg |= (SQ_AMP_CAL_VAL << SQ_AMP_CAL_OFFSET) | SQ_AMP_CAL_EN; + writel(reg, PORT_REGS(port) + UTMI_RX_CH_CTRL1_REG); + + /* + * Set Control VDAT Reference Voltage - 0.325V and + * Control VSRC Reference Voltage - 0.6V + */ + reg = readl(PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG); + reg &= ~(VDAT_MASK | VSRC_MASK); + reg |= (VDAT_VAL << VDAT_OFFSET) | (VSRC_VAL << VSRC_OFFSET); + writel(reg, PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG); +} + +static int mvebu_cp110_utmi_phy_power_off(struct phy *phy) +{ + struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy); + struct mvebu_cp110_utmi *utmi = port->priv; + int i; + + /* Power down UTMI PHY port */ + regmap_clear_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id), + UTMI_PHY_CFG_PU_MASK); + + for (i = 0; i < UTMI_PHY_PORTS; i++) { + int test = regmap_test_bits(utmi->syscon, + SYSCON_UTMI_CFG_REG(i), + UTMI_PHY_CFG_PU_MASK); + /* skip PLL shutdown if there are active UTMI PHY ports */ + if (test != 0) + return 0; + } + + /* PLL Power down if all UTMI PHYs are down */ + regmap_clear_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); + + return 0; +} + +static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) +{ + struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy); + struct mvebu_cp110_utmi *utmi = port->priv; + struct device *dev = &phy->dev; + int ret; + u32 reg; + + /* It is necessary to power off UTMI before configuration */ + ret = mvebu_cp110_utmi_phy_power_off(phy); + if (ret) { + dev_err(dev, "UTMI power OFF before power ON failed\n"); + return ret; + } + + /* + * If UTMI port is connected to USB Device controller, + * configure the USB MUX prior to UTMI PHY initialization. + * The single USB device controller can be connected + * to UTMI0 or to UTMI1 PHY port, but not to both. + */ + if (port->dr_mode == USB_DR_MODE_PERIPHERAL) { + regmap_update_bits(utmi->syscon, SYSCON_USB_CFG_REG, + USB_CFG_DEVICE_EN_MASK | USB_CFG_DEVICE_MUX_MASK, + USB_CFG_DEVICE_EN_MASK | + (port->id << USB_CFG_DEVICE_MUX_OFFSET)); + } + + /* Set Test suspendm mode and enable Test UTMI select */ + reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + reg |= SUSPENDM | TEST_SEL; + writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + + /* Wait for UTMI power down */ + mdelay(1); + + /* PHY port setup first */ + mvebu_cp110_utmi_port_setup(port); + + /* Power UP UTMI PHY */ + regmap_set_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id), + UTMI_PHY_CFG_PU_MASK); + + /* Disable Test UTMI select */ + reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + reg &= ~TEST_SEL; + writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + + /* Wait for impedance calibration */ + ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg, + reg & IMPCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end UTMI impedance calibration\n"); + return ret; + } + + /* Wait for PLL calibration */ + ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg, + reg & PLLCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end UTMI PLL calibration\n"); + return ret; + } + + /* Wait for PLL ready */ + ret = readl_poll_timeout(PORT_REGS(port) + UTMI_PLL_CTRL_REG, reg, + reg & PLL_RDY, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "PLL is not ready\n"); + return ret; + } + + /* PLL Power up */ + regmap_set_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); + + return 0; +} + +static const struct phy_ops mvebu_cp110_utmi_phy_ops = { + .power_on = mvebu_cp110_utmi_phy_power_on, + .power_off = mvebu_cp110_utmi_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct of_device_id mvebu_cp110_utmi_of_match[] = { + { .compatible = "marvell,cp110-utmi-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mvebu_cp110_utmi_of_match); + +static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mvebu_cp110_utmi *utmi; + struct phy_provider *provider; + struct device_node *child; + u32 usb_devices = 0; + + utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return -ENOMEM; + + utmi->dev = dev; + + /* Get system controller region */ + utmi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node, + "marvell,system-controller"); + if (IS_ERR(utmi->syscon)) { + dev_err(dev, "Missing UTMI system controller\n"); + return PTR_ERR(utmi->syscon); + } + + /* Get UTMI memory region */ + utmi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(utmi->regs)) + return PTR_ERR(utmi->regs); + + for_each_available_child_of_node(dev->of_node, child) { + struct mvebu_cp110_utmi_port *port; + struct phy *phy; + int ret; + u32 port_id; + + ret = of_property_read_u32(child, "reg", &port_id); + if ((ret < 0) || (port_id >= UTMI_PHY_PORTS)) { + dev_err(dev, + "invalid 'reg' property on child %pOF\n", + child); + continue; + } + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) { + of_node_put(child); + return -ENOMEM; + } + + port->dr_mode = of_usb_get_dr_mode_by_phy(child, -1); + if ((port->dr_mode != USB_DR_MODE_HOST) && + (port->dr_mode != USB_DR_MODE_PERIPHERAL)) { + dev_err(&pdev->dev, + "Missing dual role setting of the port%d, will use HOST mode\n", + port_id); + port->dr_mode = USB_DR_MODE_HOST; + } + + if (port->dr_mode == USB_DR_MODE_PERIPHERAL) { + usb_devices++; + if (usb_devices > 1) { + dev_err(dev, + "Single USB device allowed! Port%d will use HOST mode\n", + port_id); + port->dr_mode = USB_DR_MODE_HOST; + } + } + + /* Retrieve PHY capabilities */ + utmi->ops = &mvebu_cp110_utmi_phy_ops; + + /* Instantiate the PHY */ + phy = devm_phy_create(dev, child, utmi->ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create the UTMI PHY\n"); + of_node_put(child); + return PTR_ERR(phy); + } + + port->priv = utmi; + port->id = port_id; + phy_set_drvdata(phy, port); + + /* Ensure the PHY is powered off */ + mvebu_cp110_utmi_phy_power_off(phy); + } + + dev_set_drvdata(dev, utmi); + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static struct platform_driver mvebu_cp110_utmi_driver = { + .probe = mvebu_cp110_utmi_phy_probe, + .driver = { + .name = "mvebu-cp110-utmi-phy", + .of_match_table = mvebu_cp110_utmi_of_match, + }, +}; +module_platform_driver(mvebu_cp110_utmi_driver); + +MODULE_AUTHOR("Konstatin Porotchkin <kostap@marvell.com>"); +MODULE_DESCRIPTION("Marvell Armada CP110 UTMI PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3728a284bf643d48625a62f4f2c0159066092a05 --- /dev/null +++ b/drivers/phy/microchip/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Phy drivers for Microchip devices +# + +config PHY_SPARX5_SERDES + tristate "Microchip Sparx5 SerDes PHY driver" + select GENERIC_PHY + depends on ARCH_SPARX5 || COMPILE_TEST + depends on OF + depends on HAS_IOMEM + help + Enable this for support of the 10G/25G SerDes on Microchip Sparx5. diff --git a/drivers/phy/microchip/Makefile b/drivers/phy/microchip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7b98345712aac68cf0059b07eaa3f73af67f0124 --- /dev/null +++ b/drivers/phy/microchip/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Microchip phy drivers. +# + +obj-$(CONFIG_PHY_SPARX5_SERDES) := sparx5_serdes.o diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c new file mode 100644 index 0000000000000000000000000000000000000000..c8a7d0927ced10d26ef906c9ee95048117cd4a61 --- /dev/null +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -0,0 +1,2513 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Microchip Sparx5 Switch SerDes driver + * + * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries. + * + * The Sparx5 Chip Register Model can be browsed at this location: + * https://github.com/microchip-ung/sparx-5_reginfo + * and the datasheet is available here: + * https://ww1.microchip.com/downloads/en/DeviceDoc/SparX-5_Family_L2L3_Enterprise_10G_Ethernet_Switches_Datasheet_00003822B.pdf + */ +#include <linux/printk.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/phy.h> +#include <linux/phy/phy.h> + +#include "sparx5_serdes.h" + +#define SPX5_CMU_MAX 14 + +#define SPX5_SERDES_10G_START 13 +#define SPX5_SERDES_25G_START 25 + +enum sparx5_10g28cmu_mode { + SPX5_SD10G28_CMU_MAIN = 0, + SPX5_SD10G28_CMU_AUX1 = 1, + SPX5_SD10G28_CMU_AUX2 = 3, + SPX5_SD10G28_CMU_NONE = 4, +}; + +enum sparx5_sd25g28_mode_preset_type { + SPX5_SD25G28_MODE_PRESET_25000, + SPX5_SD25G28_MODE_PRESET_10000, + SPX5_SD25G28_MODE_PRESET_5000, + SPX5_SD25G28_MODE_PRESET_SD_2G5, + SPX5_SD25G28_MODE_PRESET_1000BASEX, +}; + +enum sparx5_sd10g28_mode_preset_type { + SPX5_SD10G28_MODE_PRESET_10000, + SPX5_SD10G28_MODE_PRESET_SFI_5000_6G, + SPX5_SD10G28_MODE_PRESET_SFI_5000_10G, + SPX5_SD10G28_MODE_PRESET_QSGMII, + SPX5_SD10G28_MODE_PRESET_SD_2G5, + SPX5_SD10G28_MODE_PRESET_1000BASEX, +}; + +struct sparx5_serdes_io_resource { + enum sparx5_serdes_target id; + phys_addr_t offset; +}; + +struct sparx5_sd25g28_mode_preset { + u8 bitwidth; + u8 tx_pre_div; + u8 fifo_ck_div; + u8 pre_divsel; + u8 vco_div_mode; + u8 sel_div; + u8 ck_bitwidth; + u8 subrate; + u8 com_txcal_en; + u8 com_tx_reserve_msb; + u8 com_tx_reserve_lsb; + u8 cfg_itx_ipcml_base; + u8 tx_reserve_lsb; + u8 tx_reserve_msb; + u8 bw; + u8 rxterm; + u8 dfe_tap; + u8 dfe_enable; + bool txmargin; + u8 cfg_ctle_rstn; + u8 r_dfe_rstn; + u8 cfg_pi_bw_3_0; + u8 tx_tap_dly; + u8 tx_tap_adv; +}; + +struct sparx5_sd25g28_media_preset { + u8 cfg_eq_c_force_3_0; + u8 cfg_vga_ctrl_byp_4_0; + u8 cfg_eq_r_force_3_0; + u8 cfg_en_adv; + u8 cfg_en_main; + u8 cfg_en_dly; + u8 cfg_tap_adv_3_0; + u8 cfg_tap_main; + u8 cfg_tap_dly_4_0; + u8 cfg_alos_thr_2_0; +}; + +struct sparx5_sd25g28_args { + u8 if_width; /* UDL if-width: 10/16/20/32/64 */ + bool skip_cmu_cfg:1; /* Enable/disable CMU cfg */ + enum sparx5_10g28cmu_mode cmu_sel; /* Device/Mode serdes uses */ + bool no_pwrcycle:1; /* Omit initial power-cycle */ + bool txinvert:1; /* Enable inversion of output data */ + bool rxinvert:1; /* Enable inversion of input data */ + u16 txswing; /* Set output level */ + u8 rate; /* Rate of network interface */ + u8 pi_bw_gen1; + u8 duty_cycle; /* Set output level to half/full */ + bool mute:1; /* Mute Output Buffer */ + bool reg_rst:1; + u8 com_pll_reserve; +}; + +struct sparx5_sd25g28_params { + u8 reg_rst; + u8 cfg_jc_byp; + u8 cfg_common_reserve_7_0; + u8 r_reg_manual; + u8 r_d_width_ctrl_from_hwt; + u8 r_d_width_ctrl_2_0; + u8 r_txfifo_ck_div_pmad_2_0; + u8 r_rxfifo_ck_div_pmad_2_0; + u8 cfg_pll_lol_set; + u8 cfg_vco_div_mode_1_0; + u8 cfg_pre_divsel_1_0; + u8 cfg_sel_div_3_0; + u8 cfg_vco_start_code_3_0; + u8 cfg_pma_tx_ck_bitwidth_2_0; + u8 cfg_tx_prediv_1_0; + u8 cfg_rxdiv_sel_2_0; + u8 cfg_tx_subrate_2_0; + u8 cfg_rx_subrate_2_0; + u8 r_multi_lane_mode; + u8 cfg_cdrck_en; + u8 cfg_dfeck_en; + u8 cfg_dfe_pd; + u8 cfg_dfedmx_pd; + u8 cfg_dfetap_en_5_1; + u8 cfg_dmux_pd; + u8 cfg_dmux_clk_pd; + u8 cfg_erramp_pd; + u8 cfg_pi_dfe_en; + u8 cfg_pi_en; + u8 cfg_pd_ctle; + u8 cfg_summer_en; + u8 cfg_pmad_ck_pd; + u8 cfg_pd_clk; + u8 cfg_pd_cml; + u8 cfg_pd_driver; + u8 cfg_rx_reg_pu; + u8 cfg_pd_rms_det; + u8 cfg_dcdr_pd; + u8 cfg_ecdr_pd; + u8 cfg_pd_sq; + u8 cfg_itx_ipdriver_base_2_0; + u8 cfg_tap_dly_4_0; + u8 cfg_tap_main; + u8 cfg_en_main; + u8 cfg_tap_adv_3_0; + u8 cfg_en_adv; + u8 cfg_en_dly; + u8 cfg_iscan_en; + u8 l1_pcs_en_fast_iscan; + u8 l0_cfg_bw_1_0; + u8 l0_cfg_txcal_en; + u8 cfg_en_dummy; + u8 cfg_pll_reserve_3_0; + u8 l0_cfg_tx_reserve_15_8; + u8 l0_cfg_tx_reserve_7_0; + u8 cfg_tx_reserve_15_8; + u8 cfg_tx_reserve_7_0; + u8 cfg_bw_1_0; + u8 cfg_txcal_man_en; + u8 cfg_phase_man_4_0; + u8 cfg_quad_man_1_0; + u8 cfg_txcal_shift_code_5_0; + u8 cfg_txcal_valid_sel_3_0; + u8 cfg_txcal_en; + u8 cfg_cdr_kf_2_0; + u8 cfg_cdr_m_7_0; + u8 cfg_pi_bw_3_0; + u8 cfg_pi_steps_1_0; + u8 cfg_dis_2ndorder; + u8 cfg_ctle_rstn; + u8 r_dfe_rstn; + u8 cfg_alos_thr_2_0; + u8 cfg_itx_ipcml_base_1_0; + u8 cfg_rx_reserve_7_0; + u8 cfg_rx_reserve_15_8; + u8 cfg_rxterm_2_0; + u8 cfg_fom_selm; + u8 cfg_rx_sp_ctle_1_0; + u8 cfg_isel_ctle_1_0; + u8 cfg_vga_ctrl_byp_4_0; + u8 cfg_vga_byp; + u8 cfg_agc_adpt_byp; + u8 cfg_eqr_byp; + u8 cfg_eqr_force_3_0; + u8 cfg_eqc_force_3_0; + u8 cfg_sum_setcm_en; + u8 cfg_init_pos_iscan_6_0; + u8 cfg_init_pos_ipi_6_0; + u8 cfg_dfedig_m_2_0; + u8 cfg_en_dfedig; + u8 cfg_pi_DFE_en; + u8 cfg_tx2rx_lp_en; + u8 cfg_txlb_en; + u8 cfg_rx2tx_lp_en; + u8 cfg_rxlb_en; + u8 r_tx_pol_inv; + u8 r_rx_pol_inv; +}; + +struct sparx5_sd10g28_media_preset { + u8 cfg_en_adv; + u8 cfg_en_main; + u8 cfg_en_dly; + u8 cfg_tap_adv_3_0; + u8 cfg_tap_main; + u8 cfg_tap_dly_4_0; + u8 cfg_vga_ctrl_3_0; + u8 cfg_vga_cp_2_0; + u8 cfg_eq_res_3_0; + u8 cfg_eq_r_byp; + u8 cfg_eq_c_force_3_0; + u8 cfg_alos_thr_3_0; +}; + +struct sparx5_sd10g28_mode_preset { + u8 bwidth; /* interface width: 10/16/20/32/64 */ + enum sparx5_10g28cmu_mode cmu_sel; /* Device/Mode serdes uses */ + u8 rate; /* Rate of network interface */ + u8 dfe_tap; + u8 dfe_enable; + u8 pi_bw_gen1; + u8 duty_cycle; /* Set output level to half/full */ +}; + +struct sparx5_sd10g28_args { + bool skip_cmu_cfg:1; /* Enable/disable CMU cfg */ + bool no_pwrcycle:1; /* Omit initial power-cycle */ + bool txinvert:1; /* Enable inversion of output data */ + bool rxinvert:1; /* Enable inversion of input data */ + bool txmargin:1; /* Set output level to half/full */ + u16 txswing; /* Set output level */ + bool mute:1; /* Mute Output Buffer */ + bool is_6g:1; + bool reg_rst:1; +}; + +struct sparx5_sd10g28_params { + u8 cmu_sel; + u8 is_6g; + u8 skip_cmu_cfg; + u8 cfg_lane_reserve_7_0; + u8 cfg_ssc_rtl_clk_sel; + u8 cfg_lane_reserve_15_8; + u8 cfg_txrate_1_0; + u8 cfg_rxrate_1_0; + u8 r_d_width_ctrl_2_0; + u8 cfg_pma_tx_ck_bitwidth_2_0; + u8 cfg_rxdiv_sel_2_0; + u8 r_pcs2pma_phymode_4_0; + u8 cfg_lane_id_2_0; + u8 cfg_cdrck_en; + u8 cfg_dfeck_en; + u8 cfg_dfe_pd; + u8 cfg_dfetap_en_5_1; + u8 cfg_erramp_pd; + u8 cfg_pi_DFE_en; + u8 cfg_pi_en; + u8 cfg_pd_ctle; + u8 cfg_summer_en; + u8 cfg_pd_rx_cktree; + u8 cfg_pd_clk; + u8 cfg_pd_cml; + u8 cfg_pd_driver; + u8 cfg_rx_reg_pu; + u8 cfg_d_cdr_pd; + u8 cfg_pd_sq; + u8 cfg_rxdet_en; + u8 cfg_rxdet_str; + u8 r_multi_lane_mode; + u8 cfg_en_adv; + u8 cfg_en_main; + u8 cfg_en_dly; + u8 cfg_tap_adv_3_0; + u8 cfg_tap_main; + u8 cfg_tap_dly_4_0; + u8 cfg_vga_ctrl_3_0; + u8 cfg_vga_cp_2_0; + u8 cfg_eq_res_3_0; + u8 cfg_eq_r_byp; + u8 cfg_eq_c_force_3_0; + u8 cfg_en_dfedig; + u8 cfg_sum_setcm_en; + u8 cfg_en_preemph; + u8 cfg_itx_ippreemp_base_1_0; + u8 cfg_itx_ipdriver_base_2_0; + u8 cfg_ibias_tune_reserve_5_0; + u8 cfg_txswing_half; + u8 cfg_dis_2nd_order; + u8 cfg_rx_ssc_lh; + u8 cfg_pi_floop_steps_1_0; + u8 cfg_pi_ext_dac_23_16; + u8 cfg_pi_ext_dac_15_8; + u8 cfg_iscan_ext_dac_7_0; + u8 cfg_cdr_kf_gen1_2_0; + u8 cfg_cdr_kf_gen2_2_0; + u8 cfg_cdr_kf_gen3_2_0; + u8 cfg_cdr_kf_gen4_2_0; + u8 r_cdr_m_gen1_7_0; + u8 cfg_pi_bw_gen1_3_0; + u8 cfg_pi_bw_gen2; + u8 cfg_pi_bw_gen3; + u8 cfg_pi_bw_gen4; + u8 cfg_pi_ext_dac_7_0; + u8 cfg_pi_steps; + u8 cfg_mp_max_3_0; + u8 cfg_rstn_dfedig; + u8 cfg_alos_thr_3_0; + u8 cfg_predrv_slewrate_1_0; + u8 cfg_itx_ipcml_base_1_0; + u8 cfg_ip_pre_base_1_0; + u8 r_cdr_m_gen2_7_0; + u8 r_cdr_m_gen3_7_0; + u8 r_cdr_m_gen4_7_0; + u8 r_en_auto_cdr_rstn; + u8 cfg_oscal_afe; + u8 cfg_pd_osdac_afe; + u8 cfg_resetb_oscal_afe[2]; + u8 cfg_center_spreading; + u8 cfg_m_cnt_maxval_4_0; + u8 cfg_ncnt_maxval_7_0; + u8 cfg_ncnt_maxval_10_8; + u8 cfg_ssc_en; + u8 cfg_tx2rx_lp_en; + u8 cfg_txlb_en; + u8 cfg_rx2tx_lp_en; + u8 cfg_rxlb_en; + u8 r_tx_pol_inv; + u8 r_rx_pol_inv; + u8 fx_100; +}; + +static struct sparx5_sd25g28_media_preset media_presets_25g[] = { + { /* ETH_MEDIA_DEFAULT */ + .cfg_en_adv = 0, + .cfg_en_main = 1, + .cfg_en_dly = 0, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_vga_ctrl_byp_4_0 = 4, + .cfg_eq_r_force_3_0 = 12, + .cfg_alos_thr_2_0 = 7, + }, + { /* ETH_MEDIA_SR */ + .cfg_en_adv = 1, + .cfg_en_main = 1, + .cfg_en_dly = 1, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0x10, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_vga_ctrl_byp_4_0 = 8, + .cfg_eq_r_force_3_0 = 4, + .cfg_alos_thr_2_0 = 0, + }, + { /* ETH_MEDIA_DAC */ + .cfg_en_adv = 0, + .cfg_en_main = 1, + .cfg_en_dly = 0, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_vga_ctrl_byp_4_0 = 8, + .cfg_eq_r_force_3_0 = 0xc, + .cfg_alos_thr_2_0 = 0, + }, +}; + +static struct sparx5_sd25g28_mode_preset mode_presets_25g[] = { + { /* SPX5_SD25G28_MODE_PRESET_25000 */ + .bitwidth = 40, + .tx_pre_div = 0, + .fifo_ck_div = 0, + .pre_divsel = 1, + .vco_div_mode = 0, + .sel_div = 15, + .ck_bitwidth = 3, + .subrate = 0, + .com_txcal_en = 0, + .com_tx_reserve_msb = (0x26 << 1), + .com_tx_reserve_lsb = 0xf0, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0xcc, + .tx_reserve_lsb = 0xfe, + .bw = 3, + .rxterm = 0, + .dfe_enable = 1, + .dfe_tap = 0x1f, + .txmargin = 1, + .cfg_ctle_rstn = 1, + .r_dfe_rstn = 1, + .cfg_pi_bw_3_0 = 0, + .tx_tap_dly = 8, + .tx_tap_adv = 0xc, + }, + { /* SPX5_SD25G28_MODE_PRESET_10000 */ + .bitwidth = 64, + .tx_pre_div = 0, + .fifo_ck_div = 2, + .pre_divsel = 0, + .vco_div_mode = 1, + .sel_div = 9, + .ck_bitwidth = 0, + .subrate = 0, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x20 << 1), + .com_tx_reserve_lsb = 0x40, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0x4c, + .tx_reserve_lsb = 0x44, + .bw = 3, + .cfg_pi_bw_3_0 = 0, + .rxterm = 3, + .dfe_enable = 1, + .dfe_tap = 0x1f, + .txmargin = 0, + .cfg_ctle_rstn = 1, + .r_dfe_rstn = 1, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, + { /* SPX5_SD25G28_MODE_PRESET_5000 */ + .bitwidth = 64, + .tx_pre_div = 0, + .fifo_ck_div = 2, + .pre_divsel = 0, + .vco_div_mode = 2, + .sel_div = 9, + .ck_bitwidth = 0, + .subrate = 0, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x20 << 1), + .com_tx_reserve_lsb = 0, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0xe, + .tx_reserve_lsb = 0x80, + .bw = 0, + .rxterm = 0, + .cfg_pi_bw_3_0 = 6, + .dfe_enable = 0, + .dfe_tap = 0, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, + { /* SPX5_SD25G28_MODE_PRESET_SD_2G5 */ + .bitwidth = 10, + .tx_pre_div = 0, + .fifo_ck_div = 0, + .pre_divsel = 0, + .vco_div_mode = 1, + .sel_div = 6, + .ck_bitwidth = 3, + .subrate = 2, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x26 << 1), + .com_tx_reserve_lsb = (0xf << 4), + .cfg_itx_ipcml_base = 2, + .tx_reserve_msb = 0x8, + .tx_reserve_lsb = 0x8a, + .bw = 0, + .cfg_pi_bw_3_0 = 0, + .rxterm = (1 << 2), + .dfe_enable = 0, + .dfe_tap = 0, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, + { /* SPX5_SD25G28_MODE_PRESET_1000BASEX */ + .bitwidth = 10, + .tx_pre_div = 0, + .fifo_ck_div = 1, + .pre_divsel = 0, + .vco_div_mode = 1, + .sel_div = 8, + .ck_bitwidth = 3, + .subrate = 3, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x26 << 1), + .com_tx_reserve_lsb = 0xf0, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0x8, + .tx_reserve_lsb = 0xce, + .bw = 0, + .rxterm = 0, + .cfg_pi_bw_3_0 = 0, + .dfe_enable = 0, + .dfe_tap = 0, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, +}; + +static struct sparx5_sd10g28_media_preset media_presets_10g[] = { + { /* ETH_MEDIA_DEFAULT */ + .cfg_en_adv = 0, + .cfg_en_main = 1, + .cfg_en_dly = 0, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0, + .cfg_vga_ctrl_3_0 = 5, + .cfg_vga_cp_2_0 = 0, + .cfg_eq_res_3_0 = 0xa, + .cfg_eq_r_byp = 1, + .cfg_eq_c_force_3_0 = 0x8, + .cfg_alos_thr_3_0 = 0x3, + }, + { /* ETH_MEDIA_SR */ + .cfg_en_adv = 1, + .cfg_en_main = 1, + .cfg_en_dly = 1, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0xc, + .cfg_vga_ctrl_3_0 = 0xa, + .cfg_vga_cp_2_0 = 0x4, + .cfg_eq_res_3_0 = 0xa, + .cfg_eq_r_byp = 1, + .cfg_eq_c_force_3_0 = 0xF, + .cfg_alos_thr_3_0 = 0x3, + }, + { /* ETH_MEDIA_DAC */ + .cfg_en_adv = 1, + .cfg_en_main = 1, + .cfg_en_dly = 1, + .cfg_tap_adv_3_0 = 12, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 8, + .cfg_vga_ctrl_3_0 = 0xa, + .cfg_vga_cp_2_0 = 4, + .cfg_eq_res_3_0 = 0xa, + .cfg_eq_r_byp = 1, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_alos_thr_3_0 = 0x0, + } +}; + +static struct sparx5_sd10g28_mode_preset mode_presets_10g[] = { + { /* SPX5_SD10G28_MODE_PRESET_10000 */ + .bwidth = 64, + .cmu_sel = SPX5_SD10G28_CMU_MAIN, + .rate = 0x0, + .dfe_enable = 1, + .dfe_tap = 0x1f, + .pi_bw_gen1 = 0x0, + .duty_cycle = 0x2, + }, + { /* SPX5_SD10G28_MODE_PRESET_SFI_5000_6G */ + .bwidth = 16, + .cmu_sel = SPX5_SD10G28_CMU_MAIN, + .rate = 0x1, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x5, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_SFI_5000_10G */ + .bwidth = 64, + .cmu_sel = SPX5_SD10G28_CMU_MAIN, + .rate = 0x1, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x5, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_QSGMII */ + .bwidth = 20, + .cmu_sel = SPX5_SD10G28_CMU_AUX1, + .rate = 0x1, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x5, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_SD_2G5 */ + .bwidth = 10, + .cmu_sel = SPX5_SD10G28_CMU_AUX2, + .rate = 0x2, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x7, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_1000BASEX */ + .bwidth = 10, + .cmu_sel = SPX5_SD10G28_CMU_AUX1, + .rate = 0x3, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x7, + .duty_cycle = 0x0, + }, +}; + +/* map from SD25G28 interface width to configuration value */ +static u8 sd25g28_get_iw_setting(struct device *dev, const u8 interface_width) +{ + switch (interface_width) { + case 10: return 0; + case 16: return 1; + case 32: return 3; + case 40: return 4; + case 64: return 5; + default: + dev_err(dev, "%s: Illegal value %d for interface width\n", + __func__, interface_width); + } + return 0; +} + +/* map from SD10G28 interface width to configuration value */ +static u8 sd10g28_get_iw_setting(struct device *dev, const u8 interface_width) +{ + switch (interface_width) { + case 10: return 0; + case 16: return 1; + case 20: return 2; + case 32: return 3; + case 40: return 4; + case 64: return 7; + default: + dev_err(dev, "%s: Illegal value %d for interface width\n", __func__, + interface_width); + return 0; + } +} + +static int sparx5_sd10g25_get_mode_preset(struct sparx5_serdes_macro *macro, + struct sparx5_sd25g28_mode_preset *mode) +{ + switch (macro->serdesmode) { + case SPX5_SD_MODE_SFI: + if (macro->speed == SPEED_25000) + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_25000]; + else if (macro->speed == SPEED_10000) + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_10000]; + else if (macro->speed == SPEED_5000) + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_5000]; + break; + case SPX5_SD_MODE_2G5: + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_SD_2G5]; + break; + case SPX5_SD_MODE_1000BASEX: + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_1000BASEX]; + break; + case SPX5_SD_MODE_100FX: + /* Not supported */ + return -EINVAL; + default: + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_25000]; + break; + } + return 0; +} + +static int sparx5_sd10g28_get_mode_preset(struct sparx5_serdes_macro *macro, + struct sparx5_sd10g28_mode_preset *mode, + struct sparx5_sd10g28_args *args) +{ + switch (macro->serdesmode) { + case SPX5_SD_MODE_SFI: + if (macro->speed == SPEED_10000) { + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_10000]; + } else if (macro->speed == SPEED_5000) { + if (args->is_6g) + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_SFI_5000_6G]; + else + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_SFI_5000_10G]; + } else { + dev_err(macro->priv->dev, "%s: Illegal speed: %02u, sidx: %02u, mode (%u)", + __func__, macro->speed, macro->sidx, + macro->serdesmode); + return -EINVAL; + } + break; + case SPX5_SD_MODE_QSGMII: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_QSGMII]; + break; + case SPX5_SD_MODE_2G5: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_SD_2G5]; + break; + case SPX5_SD_MODE_100FX: + case SPX5_SD_MODE_1000BASEX: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_1000BASEX]; + break; + default: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_10000]; + break; + } + return 0; +} + +static void sparx5_sd25g28_get_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd25g28_media_preset *media, + struct sparx5_sd25g28_mode_preset *mode, + struct sparx5_sd25g28_args *args, + struct sparx5_sd25g28_params *params) +{ + u8 iw = sd25g28_get_iw_setting(macro->priv->dev, mode->bitwidth); + struct sparx5_sd25g28_params init = { + .r_d_width_ctrl_2_0 = iw, + .r_txfifo_ck_div_pmad_2_0 = mode->fifo_ck_div, + .r_rxfifo_ck_div_pmad_2_0 = mode->fifo_ck_div, + .cfg_vco_div_mode_1_0 = mode->vco_div_mode, + .cfg_pre_divsel_1_0 = mode->pre_divsel, + .cfg_sel_div_3_0 = mode->sel_div, + .cfg_vco_start_code_3_0 = 0, + .cfg_pma_tx_ck_bitwidth_2_0 = mode->ck_bitwidth, + .cfg_tx_prediv_1_0 = mode->tx_pre_div, + .cfg_rxdiv_sel_2_0 = mode->ck_bitwidth, + .cfg_tx_subrate_2_0 = mode->subrate, + .cfg_rx_subrate_2_0 = mode->subrate, + .r_multi_lane_mode = 0, + .cfg_cdrck_en = 1, + .cfg_dfeck_en = mode->dfe_enable, + .cfg_dfe_pd = mode->dfe_enable == 1 ? 0 : 1, + .cfg_dfedmx_pd = 1, + .cfg_dfetap_en_5_1 = mode->dfe_tap, + .cfg_dmux_pd = 0, + .cfg_dmux_clk_pd = 1, + .cfg_erramp_pd = mode->dfe_enable == 1 ? 0 : 1, + .cfg_pi_DFE_en = mode->dfe_enable, + .cfg_pi_en = 1, + .cfg_pd_ctle = 0, + .cfg_summer_en = 1, + .cfg_pmad_ck_pd = 0, + .cfg_pd_clk = 0, + .cfg_pd_cml = 0, + .cfg_pd_driver = 0, + .cfg_rx_reg_pu = 1, + .cfg_pd_rms_det = 1, + .cfg_dcdr_pd = 0, + .cfg_ecdr_pd = 1, + .cfg_pd_sq = 1, + .cfg_itx_ipdriver_base_2_0 = mode->txmargin, + .cfg_tap_dly_4_0 = media->cfg_tap_dly_4_0, + .cfg_tap_main = media->cfg_tap_main, + .cfg_en_main = media->cfg_en_main, + .cfg_tap_adv_3_0 = media->cfg_tap_adv_3_0, + .cfg_en_adv = media->cfg_en_adv, + .cfg_en_dly = media->cfg_en_dly, + .cfg_iscan_en = 0, + .l1_pcs_en_fast_iscan = 0, + .l0_cfg_bw_1_0 = 0, + .cfg_en_dummy = 0, + .cfg_pll_reserve_3_0 = args->com_pll_reserve, + .l0_cfg_txcal_en = mode->com_txcal_en, + .l0_cfg_tx_reserve_15_8 = mode->com_tx_reserve_msb, + .l0_cfg_tx_reserve_7_0 = mode->com_tx_reserve_lsb, + .cfg_tx_reserve_15_8 = mode->tx_reserve_msb, + .cfg_tx_reserve_7_0 = mode->tx_reserve_lsb, + .cfg_bw_1_0 = mode->bw, + .cfg_txcal_man_en = 1, + .cfg_phase_man_4_0 = 0, + .cfg_quad_man_1_0 = 0, + .cfg_txcal_shift_code_5_0 = 2, + .cfg_txcal_valid_sel_3_0 = 4, + .cfg_txcal_en = 0, + .cfg_cdr_kf_2_0 = 1, + .cfg_cdr_m_7_0 = 6, + .cfg_pi_bw_3_0 = mode->cfg_pi_bw_3_0, + .cfg_pi_steps_1_0 = 0, + .cfg_dis_2ndorder = 1, + .cfg_ctle_rstn = mode->cfg_ctle_rstn, + .r_dfe_rstn = mode->r_dfe_rstn, + .cfg_alos_thr_2_0 = media->cfg_alos_thr_2_0, + .cfg_itx_ipcml_base_1_0 = mode->cfg_itx_ipcml_base, + .cfg_rx_reserve_7_0 = 0xbf, + .cfg_rx_reserve_15_8 = 0x61, + .cfg_rxterm_2_0 = mode->rxterm, + .cfg_fom_selm = 0, + .cfg_rx_sp_ctle_1_0 = 0, + .cfg_isel_ctle_1_0 = 0, + .cfg_vga_ctrl_byp_4_0 = media->cfg_vga_ctrl_byp_4_0, + .cfg_vga_byp = 1, + .cfg_agc_adpt_byp = 1, + .cfg_eqr_byp = 1, + .cfg_eqr_force_3_0 = media->cfg_eq_r_force_3_0, + .cfg_eqc_force_3_0 = media->cfg_eq_c_force_3_0, + .cfg_sum_setcm_en = 1, + .cfg_pi_dfe_en = 1, + .cfg_init_pos_iscan_6_0 = 6, + .cfg_init_pos_ipi_6_0 = 9, + .cfg_dfedig_m_2_0 = 6, + .cfg_en_dfedig = mode->dfe_enable, + .r_d_width_ctrl_from_hwt = 0, + .r_reg_manual = 1, + .reg_rst = args->reg_rst, + .cfg_jc_byp = 1, + .cfg_common_reserve_7_0 = 1, + .cfg_pll_lol_set = 1, + .cfg_tx2rx_lp_en = 0, + .cfg_txlb_en = 0, + .cfg_rx2tx_lp_en = 0, + .cfg_rxlb_en = 0, + .r_tx_pol_inv = args->txinvert, + .r_rx_pol_inv = args->rxinvert, + }; + + *params = init; +} + +static void sparx5_sd10g28_get_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd10g28_media_preset *media, + struct sparx5_sd10g28_mode_preset *mode, + struct sparx5_sd10g28_args *args, + struct sparx5_sd10g28_params *params) +{ + u8 iw = sd10g28_get_iw_setting(macro->priv->dev, mode->bwidth); + struct sparx5_sd10g28_params init = { + .skip_cmu_cfg = args->skip_cmu_cfg, + .is_6g = args->is_6g, + .cmu_sel = mode->cmu_sel, + .cfg_lane_reserve_7_0 = (mode->cmu_sel % 2) << 6, + .cfg_ssc_rtl_clk_sel = (mode->cmu_sel / 2), + .cfg_lane_reserve_15_8 = mode->duty_cycle, + .cfg_txrate_1_0 = mode->rate, + .cfg_rxrate_1_0 = mode->rate, + .fx_100 = macro->serdesmode == SPX5_SD_MODE_100FX, + .r_d_width_ctrl_2_0 = iw, + .cfg_pma_tx_ck_bitwidth_2_0 = iw, + .cfg_rxdiv_sel_2_0 = iw, + .r_pcs2pma_phymode_4_0 = 0, + .cfg_lane_id_2_0 = 0, + .cfg_cdrck_en = 1, + .cfg_dfeck_en = mode->dfe_enable, + .cfg_dfe_pd = (mode->dfe_enable == 1) ? 0 : 1, + .cfg_dfetap_en_5_1 = mode->dfe_tap, + .cfg_erramp_pd = (mode->dfe_enable == 1) ? 0 : 1, + .cfg_pi_DFE_en = mode->dfe_enable, + .cfg_pi_en = 1, + .cfg_pd_ctle = 0, + .cfg_summer_en = 1, + .cfg_pd_rx_cktree = 0, + .cfg_pd_clk = 0, + .cfg_pd_cml = 0, + .cfg_pd_driver = 0, + .cfg_rx_reg_pu = 1, + .cfg_d_cdr_pd = 0, + .cfg_pd_sq = mode->dfe_enable, + .cfg_rxdet_en = 0, + .cfg_rxdet_str = 0, + .r_multi_lane_mode = 0, + .cfg_en_adv = media->cfg_en_adv, + .cfg_en_main = 1, + .cfg_en_dly = media->cfg_en_dly, + .cfg_tap_adv_3_0 = media->cfg_tap_adv_3_0, + .cfg_tap_main = media->cfg_tap_main, + .cfg_tap_dly_4_0 = media->cfg_tap_dly_4_0, + .cfg_vga_ctrl_3_0 = media->cfg_vga_ctrl_3_0, + .cfg_vga_cp_2_0 = media->cfg_vga_cp_2_0, + .cfg_eq_res_3_0 = media->cfg_eq_res_3_0, + .cfg_eq_r_byp = media->cfg_eq_r_byp, + .cfg_eq_c_force_3_0 = media->cfg_eq_c_force_3_0, + .cfg_en_dfedig = mode->dfe_enable, + .cfg_sum_setcm_en = 1, + .cfg_en_preemph = 0, + .cfg_itx_ippreemp_base_1_0 = 0, + .cfg_itx_ipdriver_base_2_0 = (args->txswing >> 6), + .cfg_ibias_tune_reserve_5_0 = (args->txswing & 63), + .cfg_txswing_half = (args->txmargin), + .cfg_dis_2nd_order = 0x1, + .cfg_rx_ssc_lh = 0x0, + .cfg_pi_floop_steps_1_0 = 0x0, + .cfg_pi_ext_dac_23_16 = (1 << 5), + .cfg_pi_ext_dac_15_8 = (0 << 6), + .cfg_iscan_ext_dac_7_0 = (1 << 7) + 9, + .cfg_cdr_kf_gen1_2_0 = 1, + .cfg_cdr_kf_gen2_2_0 = 1, + .cfg_cdr_kf_gen3_2_0 = 1, + .cfg_cdr_kf_gen4_2_0 = 1, + .r_cdr_m_gen1_7_0 = 4, + .cfg_pi_bw_gen1_3_0 = mode->pi_bw_gen1, + .cfg_pi_bw_gen2 = mode->pi_bw_gen1, + .cfg_pi_bw_gen3 = mode->pi_bw_gen1, + .cfg_pi_bw_gen4 = mode->pi_bw_gen1, + .cfg_pi_ext_dac_7_0 = 3, + .cfg_pi_steps = 0, + .cfg_mp_max_3_0 = 1, + .cfg_rstn_dfedig = mode->dfe_enable, + .cfg_alos_thr_3_0 = media->cfg_alos_thr_3_0, + .cfg_predrv_slewrate_1_0 = 3, + .cfg_itx_ipcml_base_1_0 = 0, + .cfg_ip_pre_base_1_0 = 0, + .r_cdr_m_gen2_7_0 = 2, + .r_cdr_m_gen3_7_0 = 2, + .r_cdr_m_gen4_7_0 = 2, + .r_en_auto_cdr_rstn = 0, + .cfg_oscal_afe = 1, + .cfg_pd_osdac_afe = 0, + .cfg_resetb_oscal_afe[0] = 0, + .cfg_resetb_oscal_afe[1] = 1, + .cfg_center_spreading = 0, + .cfg_m_cnt_maxval_4_0 = 15, + .cfg_ncnt_maxval_7_0 = 32, + .cfg_ncnt_maxval_10_8 = 6, + .cfg_ssc_en = 1, + .cfg_tx2rx_lp_en = 0, + .cfg_txlb_en = 0, + .cfg_rx2tx_lp_en = 0, + .cfg_rxlb_en = 0, + .r_tx_pol_inv = args->txinvert, + .r_rx_pol_inv = args->rxinvert, + }; + + *params = init; +} + +static void sparx5_sd25g28_reset(void __iomem *regs[], + struct sparx5_sd25g28_params *params, + u32 sd_index) +{ + if (params->reg_rst == 1) { + sdx5_rmw_addr(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(1), + SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index))); + + usleep_range(1000, 2000); + + sdx5_rmw_addr(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(0), + SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index))); + } +} + +static int sparx5_sd25g28_apply_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd25g28_params *params) +{ + struct sparx5_serdes_private *priv = macro->priv; + void __iomem **regs = priv->regs; + struct device *dev = priv->dev; + u32 sd_index = macro->stpidx; + u32 value; + + sdx5_rmw(SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(1), + SD_LANE_25G_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_25G_SD_LANE_CFG(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xFF), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_SET + (params->r_d_width_ctrl_from_hwt) | + SD25G_LANE_CMU_1A_R_REG_MANUAL_SET(params->r_reg_manual), + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT | + SD25G_LANE_CMU_1A_R_REG_MANUAL, + priv, + SD25G_LANE_CMU_1A(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET + (params->cfg_common_reserve_7_0), + SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, + priv, + SD25G_LANE_CMU_31(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_09_CFG_EN_DUMMY_SET(params->cfg_en_dummy), + SD25G_LANE_CMU_09_CFG_EN_DUMMY, + priv, + SD25G_LANE_CMU_09(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET + (params->cfg_pll_reserve_3_0), + SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, + priv, + SD25G_LANE_CMU_13(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_SET(params->l0_cfg_txcal_en), + SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, + priv, + SD25G_LANE_CMU_40(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET + (params->l0_cfg_tx_reserve_15_8), + SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, + priv, + SD25G_LANE_CMU_46(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET + (params->l0_cfg_tx_reserve_7_0), + SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, + priv, + SD25G_LANE_CMU_45(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(0), + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, + priv, + SD25G_LANE_CMU_0B(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(1), + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, + priv, + SD25G_LANE_CMU_0B(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_19_R_CK_RESETB_SET(0), + SD25G_LANE_CMU_19_R_CK_RESETB, + priv, + SD25G_LANE_CMU_19(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_19_R_CK_RESETB_SET(1), + SD25G_LANE_CMU_19_R_CK_RESETB, + priv, + SD25G_LANE_CMU_19(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_18_R_PLL_RSTN_SET(0), + SD25G_LANE_CMU_18_R_PLL_RSTN, + priv, + SD25G_LANE_CMU_18(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_18_R_PLL_RSTN_SET(1), + SD25G_LANE_CMU_18_R_PLL_RSTN, + priv, + SD25G_LANE_CMU_18(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(params->r_d_width_ctrl_2_0), + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, + priv, + SD25G_LANE_CMU_1A(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET + (params->r_txfifo_ck_div_pmad_2_0) | + SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_SET + (params->r_rxfifo_ck_div_pmad_2_0), + SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 | + SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, + priv, + SD25G_LANE_CMU_30(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(params->cfg_pll_lol_set) | + SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_SET + (params->cfg_vco_div_mode_1_0), + SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET | + SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, + priv, + SD25G_LANE_CMU_0C(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_SET + (params->cfg_pre_divsel_1_0), + SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, + priv, + SD25G_LANE_CMU_0D(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(params->cfg_sel_div_3_0), + SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, + priv, + SD25G_LANE_CMU_0E(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0x00), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET + (params->cfg_pma_tx_ck_bitwidth_2_0), + SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, + priv, + SD25G_LANE_LANE_0C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_SET + (params->cfg_tx_prediv_1_0), + SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, + priv, + SD25G_LANE_LANE_01(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_SET + (params->cfg_rxdiv_sel_2_0), + SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET + (params->cfg_tx_subrate_2_0), + SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, + priv, + SD25G_LANE_LANE_2C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_SET + (params->cfg_rx_subrate_2_0), + SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, + priv, + SD25G_LANE_LANE_28(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), + SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET + (params->cfg_dfetap_en_5_1), + SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, + priv, + SD25G_LANE_LANE_0F(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_SET(params->cfg_pi_dfe_en), + SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, + priv, + SD25G_LANE_LANE_1D(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_SET(params->cfg_ecdr_pd), + SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, + priv, + SD25G_LANE_LANE_19(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET + (params->cfg_itx_ipdriver_base_2_0), + SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, + priv, + SD25G_LANE_LANE_01(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(params->cfg_tap_dly_4_0), + SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, + priv, + SD25G_LANE_LANE_03(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_SET(params->cfg_tap_adv_3_0), + SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, + priv, + SD25G_LANE_LANE_06(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(params->cfg_en_adv) | + SD25G_LANE_LANE_07_LN_CFG_EN_DLY_SET(params->cfg_en_dly), + SD25G_LANE_LANE_07_LN_CFG_EN_ADV | + SD25G_LANE_LANE_07_LN_CFG_EN_DLY, + priv, + SD25G_LANE_LANE_07(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET + (params->cfg_tx_reserve_15_8), + SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, + priv, + SD25G_LANE_LANE_43(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET + (params->cfg_tx_reserve_7_0), + SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, + priv, + SD25G_LANE_LANE_42(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_05_LN_CFG_BW_1_0_SET(params->cfg_bw_1_0), + SD25G_LANE_LANE_05_LN_CFG_BW_1_0, + priv, + SD25G_LANE_LANE_05(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET + (params->cfg_txcal_man_en), + SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, + priv, + SD25G_LANE_LANE_0B(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET + (params->cfg_txcal_shift_code_5_0), + SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, + priv, + SD25G_LANE_LANE_0A(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET + (params->cfg_txcal_valid_sel_3_0), + SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, + priv, + SD25G_LANE_LANE_09(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_SET(params->cfg_cdr_kf_2_0), + SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, + priv, + SD25G_LANE_LANE_1A(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(params->cfg_cdr_m_7_0), + SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, + priv, + SD25G_LANE_LANE_1B(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(params->cfg_pi_bw_3_0), + SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, + priv, + SD25G_LANE_LANE_2B(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_SET + (params->cfg_dis_2ndorder), + SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, + priv, + SD25G_LANE_LANE_2C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_SET(params->cfg_ctle_rstn), + SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_SET + (params->cfg_itx_ipcml_base_1_0), + SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, + priv, + SD25G_LANE_LANE_00(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET + (params->cfg_rx_reserve_7_0), + SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, + priv, + SD25G_LANE_LANE_44(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET + (params->cfg_rx_reserve_15_8), + SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, + priv, + SD25G_LANE_LANE_45(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_SET(params->cfg_dfeck_en) | + SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(params->cfg_rxterm_2_0), + SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN | + SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, + priv, + SD25G_LANE_LANE_0D(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET + (params->cfg_vga_ctrl_byp_4_0), + SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, + priv, + SD25G_LANE_LANE_21(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET + (params->cfg_eqr_force_3_0), + SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, + priv, + SD25G_LANE_LANE_22(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_SET + (params->cfg_eqc_force_3_0) | + SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_SET(params->cfg_dfe_pd), + SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0 | + SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, + priv, + SD25G_LANE_LANE_1C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_SET + (params->cfg_sum_setcm_en), + SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, + priv, + SD25G_LANE_LANE_1E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET + (params->cfg_init_pos_iscan_6_0), + SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, + priv, + SD25G_LANE_LANE_25(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET + (params->cfg_init_pos_ipi_6_0), + SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, + priv, + SD25G_LANE_LANE_26(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_SET + (params->cfg_dfedig_m_2_0), + SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, + priv, + SD25G_LANE_LANE_0E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_SET(params->cfg_en_dfedig), + SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, + priv, + SD25G_LANE_LANE_0E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_40_LN_R_TX_POL_INV_SET(params->r_tx_pol_inv) | + SD25G_LANE_LANE_40_LN_R_RX_POL_INV_SET(params->r_rx_pol_inv), + SD25G_LANE_LANE_40_LN_R_TX_POL_INV | + SD25G_LANE_LANE_40_LN_R_RX_POL_INV, + priv, + SD25G_LANE_LANE_40(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_SET(params->cfg_rx2tx_lp_en) | + SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(params->cfg_tx2rx_lp_en), + SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN | + SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, + priv, + SD25G_LANE_LANE_04(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_SET(params->cfg_rxlb_en), + SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, + priv, + SD25G_LANE_LANE_1E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_SET(params->cfg_txlb_en), + SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, + priv, + SD25G_LANE_LANE_19(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(1), + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(0), + SD_LANE_25G_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_25G_SD_LANE_CFG(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(0), + SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, + priv, + SD25G_LANE_LANE_1C(sd_index)); + + usleep_range(1000, 2000); + + sdx5_rmw(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(1), + SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, + priv, + SD25G_LANE_LANE_1C(sd_index)); + + usleep_range(10000, 20000); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xff), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + value = readl(sdx5_addr(regs, SD25G_LANE_CMU_C0(sd_index))); + value = SD25G_LANE_CMU_C0_PLL_LOL_UDL_GET(value); + + if (value) { + dev_err(dev, "25G PLL Loss of Lock: 0x%x\n", value); + return -EINVAL; + } + + value = readl(sdx5_addr(regs, SD_LANE_25G_SD_LANE_STAT(sd_index))); + value = SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_GET(value); + + if (value != 0x1) { + dev_err(dev, "25G PMA Reset failed: 0x%x\n", value); + return -EINVAL; + } + sdx5_rmw(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_SET(0x1), + SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, + priv, + SD25G_LANE_CMU_2A(sd_index)); + + sdx5_rmw(SD_LANE_25G_SD_SER_RST_SER_RST_SET(0x0), + SD_LANE_25G_SD_SER_RST_SER_RST, + priv, + SD_LANE_25G_SD_SER_RST(sd_index)); + + sdx5_rmw(SD_LANE_25G_SD_DES_RST_DES_RST_SET(0x0), + SD_LANE_25G_SD_DES_RST_DES_RST, + priv, + SD_LANE_25G_SD_DES_RST(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET + (params->cfg_alos_thr_2_0), + SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, + priv, + SD25G_LANE_LANE_2D(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + return 0; +} + +static void sparx5_sd10g28_reset(void __iomem *regs[], u32 lane_index) +{ + /* Note: SerDes SD10G_LANE_1 is configured in 10G_LAN mode */ + sdx5_rmw_addr(SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(1), + SD_LANE_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index))); + + usleep_range(1000, 2000); + + sdx5_rmw_addr(SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(0), + SD_LANE_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index))); +} + +static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd10g28_params *params) +{ + struct sparx5_serdes_private *priv = macro->priv; + void __iomem **regs = priv->regs; + struct device *dev = priv->dev; + u32 lane_index = macro->sidx; + u32 sd_index = macro->stpidx; + void __iomem *sd_inst; + u32 value; + + if (params->is_6g) + sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, sd_index); + else + sd_inst = sdx5_inst_get(priv, TARGET_SD10G_LANE, sd_index); + + sdx5_rmw(SD_LANE_SD_LANE_CFG_MACRO_RST_SET(1), + SD_LANE_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_SD_LANE_CFG(lane_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_93_R_REG_MANUAL_SET(0x1) | + SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_SET(0x1) | + SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_SET(0x1) | + SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_SET(0x0), + SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT | + SD10G_LANE_LANE_93_R_REG_MANUAL | + SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT | + SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT | + SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, + sd_inst, + SD10G_LANE_LANE_93(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_94_R_ISCAN_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_TXEQ_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_MISC_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_SWING_REG_SET(0x1), + SD10G_LANE_LANE_94_R_ISCAN_REG | + SD10G_LANE_LANE_94_R_TXEQ_REG | + SD10G_LANE_LANE_94_R_MISC_REG | + SD10G_LANE_LANE_94_R_SWING_REG, + sd_inst, + SD10G_LANE_LANE_94(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(0x1), + SD10G_LANE_LANE_9E_R_RXEQ_REG, + sd_inst, + SD10G_LANE_LANE_9E(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_SET(0x1), + SD10G_LANE_LANE_A1_R_SSC_FROM_HWT | + SD10G_LANE_LANE_A1_R_CDR_FROM_HWT | + SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, + sd_inst, + SD10G_LANE_LANE_A1(sd_index)); + + sdx5_rmw(SD_LANE_SD_LANE_CFG_RX_REF_SEL_SET(params->cmu_sel) | + SD_LANE_SD_LANE_CFG_TX_REF_SEL_SET(params->cmu_sel), + SD_LANE_SD_LANE_CFG_RX_REF_SEL | + SD_LANE_SD_LANE_CFG_TX_REF_SEL, + priv, + SD_LANE_SD_LANE_CFG(lane_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET + (params->cfg_lane_reserve_7_0), + SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, + sd_inst, + SD10G_LANE_LANE_40(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_SET + (params->cfg_ssc_rtl_clk_sel), + SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, + sd_inst, + SD10G_LANE_LANE_50(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET + (params->cfg_txrate_1_0) | + SD10G_LANE_LANE_35_CFG_RXRATE_1_0_SET + (params->cfg_rxrate_1_0), + SD10G_LANE_LANE_35_CFG_TXRATE_1_0 | + SD10G_LANE_LANE_35_CFG_RXRATE_1_0, + sd_inst, + SD10G_LANE_LANE_35(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET + (params->r_d_width_ctrl_2_0), + SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, + sd_inst, + SD10G_LANE_LANE_94(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET + (params->cfg_pma_tx_ck_bitwidth_2_0), + SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, + sd_inst, + SD10G_LANE_LANE_01(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_SET + (params->cfg_rxdiv_sel_2_0), + SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, + sd_inst, + SD10G_LANE_LANE_30(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET + (params->r_pcs2pma_phymode_4_0), + SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, + sd_inst, + SD10G_LANE_LANE_A2(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_13_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), + SD10G_LANE_LANE_13_CFG_CDRCK_EN, + sd_inst, + SD10G_LANE_LANE_13(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_23_CFG_DFECK_EN_SET + (params->cfg_dfeck_en) | + SD10G_LANE_LANE_23_CFG_DFE_PD_SET(params->cfg_dfe_pd) | + SD10G_LANE_LANE_23_CFG_ERRAMP_PD_SET + (params->cfg_erramp_pd), + SD10G_LANE_LANE_23_CFG_DFECK_EN | + SD10G_LANE_LANE_23_CFG_DFE_PD | + SD10G_LANE_LANE_23_CFG_ERRAMP_PD, + sd_inst, + SD10G_LANE_LANE_23(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET + (params->cfg_dfetap_en_5_1), + SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, + sd_inst, + SD10G_LANE_LANE_22(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_SET + (params->cfg_pi_DFE_en), + SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, + sd_inst, + SD10G_LANE_LANE_1A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_02_CFG_EN_ADV_SET(params->cfg_en_adv) | + SD10G_LANE_LANE_02_CFG_EN_MAIN_SET(params->cfg_en_main) | + SD10G_LANE_LANE_02_CFG_EN_DLY_SET(params->cfg_en_dly) | + SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_SET + (params->cfg_tap_adv_3_0), + SD10G_LANE_LANE_02_CFG_EN_ADV | + SD10G_LANE_LANE_02_CFG_EN_MAIN | + SD10G_LANE_LANE_02_CFG_EN_DLY | + SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, + sd_inst, + SD10G_LANE_LANE_02(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(params->cfg_tap_main), + SD10G_LANE_LANE_03_CFG_TAP_MAIN, + sd_inst, + SD10G_LANE_LANE_03(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET + (params->cfg_tap_dly_4_0), + SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, + sd_inst, + SD10G_LANE_LANE_04(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_SET + (params->cfg_vga_ctrl_3_0), + SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, + sd_inst, + SD10G_LANE_LANE_2F(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET + (params->cfg_vga_cp_2_0), + SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, + sd_inst, + SD10G_LANE_LANE_2F(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET + (params->cfg_eq_res_3_0), + SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, + sd_inst, + SD10G_LANE_LANE_0B(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0D_CFG_EQR_BYP_SET(params->cfg_eq_r_byp), + SD10G_LANE_LANE_0D_CFG_EQR_BYP, + sd_inst, + SD10G_LANE_LANE_0D(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET + (params->cfg_eq_c_force_3_0) | + SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_SET + (params->cfg_sum_setcm_en), + SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 | + SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, + sd_inst, + SD10G_LANE_LANE_0E(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_23_CFG_EN_DFEDIG_SET + (params->cfg_en_dfedig), + SD10G_LANE_LANE_23_CFG_EN_DFEDIG, + sd_inst, + SD10G_LANE_LANE_23(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_EN_PREEMPH_SET + (params->cfg_en_preemph), + SD10G_LANE_LANE_06_CFG_EN_PREEMPH, + sd_inst, + SD10G_LANE_LANE_06(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_SET + (params->cfg_itx_ippreemp_base_1_0) | + SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET + (params->cfg_itx_ipdriver_base_2_0), + SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0 | + SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, + sd_inst, + SD10G_LANE_LANE_33(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET + (params->cfg_ibias_tune_reserve_5_0), + SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, + sd_inst, + SD10G_LANE_LANE_52(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_37_CFG_TXSWING_HALF_SET + (params->cfg_txswing_half), + SD10G_LANE_LANE_37_CFG_TXSWING_HALF, + sd_inst, + SD10G_LANE_LANE_37(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_SET + (params->cfg_dis_2nd_order), + SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, + sd_inst, + SD10G_LANE_LANE_3C(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_39_CFG_RX_SSC_LH_SET + (params->cfg_rx_ssc_lh), + SD10G_LANE_LANE_39_CFG_RX_SSC_LH, + sd_inst, + SD10G_LANE_LANE_39(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_SET + (params->cfg_pi_floop_steps_1_0), + SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, + sd_inst, + SD10G_LANE_LANE_1A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET + (params->cfg_pi_ext_dac_23_16), + SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, + sd_inst, + SD10G_LANE_LANE_16(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET + (params->cfg_pi_ext_dac_15_8), + SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, + sd_inst, + SD10G_LANE_LANE_15(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET + (params->cfg_iscan_ext_dac_7_0), + SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, + sd_inst, + SD10G_LANE_LANE_26(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET + (params->cfg_cdr_kf_gen1_2_0), + SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, + sd_inst, + SD10G_LANE_LANE_42(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET + (params->r_cdr_m_gen1_7_0), + SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, + sd_inst, + SD10G_LANE_LANE_0F(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET + (params->cfg_pi_bw_gen1_3_0), + SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, + sd_inst, + SD10G_LANE_LANE_24(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET + (params->cfg_pi_ext_dac_7_0), + SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, + sd_inst, + SD10G_LANE_LANE_14(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_1A_CFG_PI_STEPS_SET(params->cfg_pi_steps), + SD10G_LANE_LANE_1A_CFG_PI_STEPS, + sd_inst, + SD10G_LANE_LANE_1A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_SET + (params->cfg_mp_max_3_0), + SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, + sd_inst, + SD10G_LANE_LANE_3A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_SET + (params->cfg_rstn_dfedig), + SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, + sd_inst, + SD10G_LANE_LANE_31(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET + (params->cfg_alos_thr_3_0), + SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, + sd_inst, + SD10G_LANE_LANE_48(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET + (params->cfg_predrv_slewrate_1_0), + SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, + sd_inst, + SD10G_LANE_LANE_36(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_SET + (params->cfg_itx_ipcml_base_1_0), + SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, + sd_inst, + SD10G_LANE_LANE_32(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_SET + (params->cfg_ip_pre_base_1_0), + SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, + sd_inst, + SD10G_LANE_LANE_37(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET + (params->cfg_lane_reserve_15_8), + SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, + sd_inst, + SD10G_LANE_LANE_41(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_SET + (params->r_en_auto_cdr_rstn), + SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, + sd_inst, + SD10G_LANE_LANE_9E(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET + (params->cfg_oscal_afe) | + SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_SET + (params->cfg_pd_osdac_afe), + SD10G_LANE_LANE_0C_CFG_OSCAL_AFE | + SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, + sd_inst, + SD10G_LANE_LANE_0C(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET + (params->cfg_resetb_oscal_afe[0]), + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, + sd_inst, + SD10G_LANE_LANE_0B(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET + (params->cfg_resetb_oscal_afe[1]), + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, + sd_inst, + SD10G_LANE_LANE_0B(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_83_R_TX_POL_INV_SET + (params->r_tx_pol_inv) | + SD10G_LANE_LANE_83_R_RX_POL_INV_SET + (params->r_rx_pol_inv), + SD10G_LANE_LANE_83_R_TX_POL_INV | + SD10G_LANE_LANE_83_R_RX_POL_INV, + sd_inst, + SD10G_LANE_LANE_83(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_SET + (params->cfg_rx2tx_lp_en) | + SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_SET + (params->cfg_tx2rx_lp_en), + SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN | + SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, + sd_inst, + SD10G_LANE_LANE_06(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0E_CFG_RXLB_EN_SET(params->cfg_rxlb_en) | + SD10G_LANE_LANE_0E_CFG_TXLB_EN_SET(params->cfg_txlb_en), + SD10G_LANE_LANE_0E_CFG_RXLB_EN | + SD10G_LANE_LANE_0E_CFG_TXLB_EN, + sd_inst, + SD10G_LANE_LANE_0E(sd_index)); + + sdx5_rmw(SD_LANE_SD_LANE_CFG_MACRO_RST_SET(0), + SD_LANE_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_SD_LANE_CFG(lane_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), + SD10G_LANE_LANE_50_CFG_SSC_RESETB, + sd_inst, + SD10G_LANE_LANE_50(sd_index)); + + sdx5_rmw(SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), + SD10G_LANE_LANE_50_CFG_SSC_RESETB, + priv, + SD10G_LANE_LANE_50(sd_index)); + + sdx5_rmw(SD_LANE_MISC_SD_125_RST_DIS_SET(params->fx_100), + SD_LANE_MISC_SD_125_RST_DIS, + priv, + SD_LANE_MISC(lane_index)); + + sdx5_rmw(SD_LANE_MISC_RX_ENA_SET(params->fx_100), + SD_LANE_MISC_RX_ENA, + priv, + SD_LANE_MISC(lane_index)); + + sdx5_rmw(SD_LANE_MISC_MUX_ENA_SET(params->fx_100), + SD_LANE_MISC_MUX_ENA, + priv, + SD_LANE_MISC(lane_index)); + + usleep_range(3000, 6000); + + value = readl(sdx5_addr(regs, SD_LANE_SD_LANE_STAT(lane_index))); + value = SD_LANE_SD_LANE_STAT_PMA_RST_DONE_GET(value); + if (value != 1) { + dev_err(dev, "10G PMA Reset failed: 0x%x\n", value); + return -EINVAL; + } + + sdx5_rmw(SD_LANE_SD_SER_RST_SER_RST_SET(0x0), + SD_LANE_SD_SER_RST_SER_RST, + priv, + SD_LANE_SD_SER_RST(lane_index)); + + sdx5_rmw(SD_LANE_SD_DES_RST_DES_RST_SET(0x0), + SD_LANE_SD_DES_RST_DES_RST, + priv, + SD_LANE_SD_DES_RST(lane_index)); + + return 0; +} + +static int sparx5_sd25g28_config(struct sparx5_serdes_macro *macro, bool reset) +{ + struct sparx5_sd25g28_media_preset media = media_presets_25g[macro->media]; + struct sparx5_sd25g28_mode_preset mode; + struct sparx5_sd25g28_args args = { + .rxinvert = 1, + .txinvert = 0, + .txswing = 240, + .com_pll_reserve = 0xf, + .reg_rst = reset, + }; + struct sparx5_sd25g28_params params; + int err; + + err = sparx5_sd10g25_get_mode_preset(macro, &mode); + if (err) + return err; + sparx5_sd25g28_get_params(macro, &media, &mode, &args, ¶ms); + sparx5_sd25g28_reset(macro->priv->regs, ¶ms, macro->stpidx); + return sparx5_sd25g28_apply_params(macro, ¶ms); +} + +static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset) +{ + struct sparx5_sd10g28_media_preset media = media_presets_10g[macro->media]; + struct sparx5_sd10g28_mode_preset mode; + struct sparx5_sd10g28_params params; + struct sparx5_sd10g28_args args = { + .is_6g = (macro->serdestype == SPX5_SDT_6G), + .txinvert = 0, + .rxinvert = 1, + .txswing = 240, + .reg_rst = reset, + }; + int err; + + err = sparx5_sd10g28_get_mode_preset(macro, &mode, &args); + if (err) + return err; + sparx5_sd10g28_get_params(macro, &media, &mode, &args, ¶ms); + sparx5_sd10g28_reset(macro->priv->regs, macro->sidx); + return sparx5_sd10g28_apply_params(macro, ¶ms); +} + +/* Power down serdes TX driver */ +static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn) +{ + struct sparx5_serdes_private *priv = macro->priv; + void __iomem *sd_inst; + + if (macro->serdestype == SPX5_SDT_6G) + sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, macro->stpidx); + else if (macro->serdestype == SPX5_SDT_10G) + sd_inst = sdx5_inst_get(priv, TARGET_SD10G_LANE, macro->stpidx); + else + sd_inst = sdx5_inst_get(priv, TARGET_SD25G_LANE, macro->stpidx); + + if (macro->serdestype == SPX5_SDT_25G) { + sdx5_inst_rmw(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_SET(pwdn), + SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, + sd_inst, + SD25G_LANE_LANE_04(0)); + } else { + /* 6G and 10G */ + sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(pwdn), + SD10G_LANE_LANE_06_CFG_PD_DRIVER, + sd_inst, + SD10G_LANE_LANE_06(0)); + } + return 0; +} + +static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro) +{ + struct sparx5_serdes_private *priv = macro->priv; + + if (macro->serdesmode == SPX5_SD_MODE_100FX) { + u32 freq = priv->coreclock == 250000000 ? 2 : + priv->coreclock == 500000000 ? 1 : 0; + + sdx5_rmw(SD_LANE_MISC_CORE_CLK_FREQ_SET(freq), + SD_LANE_MISC_CORE_CLK_FREQ, + priv, + SD_LANE_MISC(macro->sidx)); + } + return 0; +} + +static int sparx5_cmu_apply_cfg(struct sparx5_serdes_private *priv, + u32 cmu_idx, + void __iomem *cmu_tgt, + void __iomem *cmu_cfg_tgt, + u32 spd10g) +{ + void __iomem **regs = priv->regs; + struct device *dev = priv->dev; + int value; + + cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx); + cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx); + + if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 || + cmu_idx == 10 || cmu_idx == 13) { + spd10g = 0; + } + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(1), + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0), + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(1), + SD_CMU_CFG_SD_CMU_CFG_CMU_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(0x0), + SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT | + SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT | + SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT | + SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT | + SD_CMU_CMU_45_R_EN_RATECHG_CTRL, + cmu_tgt, + SD_CMU_CMU_45(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(0), + SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, + cmu_tgt, + SD_CMU_CMU_47(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(0), + SD_CMU_CMU_1B_CFG_RESERVE_7_0, + cmu_tgt, + SD_CMU_CMU_1B(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_JC_BYP_SET(0x1), + SD_CMU_CMU_0D_CFG_JC_BYP, + cmu_tgt, + SD_CMU_CMU_0D(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(1), + SD_CMU_CMU_1F_CFG_VTUNE_SEL, + cmu_tgt, + SD_CMU_CMU_1F(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(3), + SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, + cmu_tgt, + SD_CMU_CMU_00(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(3), + SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, + cmu_tgt, + SD_CMU_CMU_05(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(1), + SD_CMU_CMU_30_R_PLL_DLOL_EN, + cmu_tgt, + SD_CMU_CMU_30(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_09_CFG_SW_10G_SET(spd10g), + SD_CMU_CMU_09_CFG_SW_10G, + cmu_tgt, + SD_CMU_CMU_09(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(0), + SD_CMU_CFG_SD_CMU_CFG_CMU_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + msleep(20); + + sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(0), + SD_CMU_CMU_44_R_PLL_RSTN, + cmu_tgt, + SD_CMU_CMU_44(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(1), + SD_CMU_CMU_44_R_PLL_RSTN, + cmu_tgt, + SD_CMU_CMU_44(cmu_idx)); + + msleep(20); + + value = readl(sdx5_addr(regs, SD_CMU_CMU_E0(cmu_idx))); + value = SD_CMU_CMU_E0_PLL_LOL_UDL_GET(value); + + if (value) { + dev_err(dev, "CMU PLL Loss of Lock: 0x%x\n", value); + return -EINVAL; + } + sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_SET(0), + SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD, + cmu_tgt, + SD_CMU_CMU_0D(cmu_idx)); + return 0; +} + +static int sparx5_cmu_cfg(struct sparx5_serdes_private *priv, u32 cmu_idx) +{ + void __iomem *cmu_tgt, *cmu_cfg_tgt; + u32 spd10g = 1; + + if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 || + cmu_idx == 10 || cmu_idx == 13) { + spd10g = 0; + } + + cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx); + cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx); + + return sparx5_cmu_apply_cfg(priv, cmu_idx, cmu_tgt, cmu_cfg_tgt, spd10g); +} + +static int sparx5_serdes_cmu_enable(struct sparx5_serdes_private *priv) +{ + int idx, err = 0; + + if (!priv->cmu_enabled) { + for (idx = 0; idx < SPX5_CMU_MAX; idx++) { + err = sparx5_cmu_cfg(priv, idx); + if (err) { + dev_err(priv->dev, "CMU %u, error: %d\n", idx, err); + goto leave; + } + } + priv->cmu_enabled = true; + } +leave: + return err; +} + +static int sparx5_serdes_get_serdesmode(phy_interface_t portmode, int speed) +{ + switch (portmode) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + if (speed == SPEED_2500) + return SPX5_SD_MODE_2G5; + if (speed == SPEED_100) + return SPX5_SD_MODE_100FX; + return SPX5_SD_MODE_1000BASEX; + case PHY_INTERFACE_MODE_SGMII: + /* The same Serdes mode is used for both SGMII and 1000BaseX */ + return SPX5_SD_MODE_1000BASEX; + case PHY_INTERFACE_MODE_QSGMII: + return SPX5_SD_MODE_QSGMII; + case PHY_INTERFACE_MODE_10GBASER: + return SPX5_SD_MODE_SFI; + default: + return -EINVAL; + } +} + +static int sparx5_serdes_config(struct sparx5_serdes_macro *macro) +{ + struct device *dev = macro->priv->dev; + int serdesmode; + int err; + + err = sparx5_serdes_cmu_enable(macro->priv); + if (err) + return err; + + serdesmode = sparx5_serdes_get_serdesmode(macro->portmode, macro->speed); + if (serdesmode < 0) { + dev_err(dev, "SerDes %u, interface not supported: %s\n", + macro->sidx, + phy_modes(macro->portmode)); + return serdesmode; + } + macro->serdesmode = serdesmode; + + sparx5_serdes_clock_config(macro); + + if (macro->serdestype == SPX5_SDT_25G) + err = sparx5_sd25g28_config(macro, false); + else + err = sparx5_sd10g28_config(macro, false); + if (err) { + dev_err(dev, "SerDes %u, config error: %d\n", + macro->sidx, err); + } + return err; +} + +static int sparx5_serdes_power_on(struct phy *phy) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + return sparx5_serdes_power_save(macro, false); +} + +static int sparx5_serdes_power_off(struct phy *phy) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + return sparx5_serdes_power_save(macro, true); +} + +static int sparx5_serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct sparx5_serdes_macro *macro; + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_10GBASER: + macro = phy_get_drvdata(phy); + macro->portmode = submode; + sparx5_serdes_config(macro); + return 0; + default: + return -EINVAL; + } +} + +static int sparx5_serdes_set_media(struct phy *phy, enum phy_media media) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + if (media != macro->media) { + macro->media = media; + if (macro->serdesmode != SPX5_SD_MODE_NONE) + sparx5_serdes_config(macro); + } + return 0; +} + +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 (speed != macro->speed) { + macro->speed = speed; + if (macro->serdesmode != SPX5_SD_MODE_NONE) + sparx5_serdes_config(macro); + } + return 0; +} + +static int sparx5_serdes_reset(struct phy *phy) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + int err; + + err = sparx5_serdes_cmu_enable(macro->priv); + if (err) + return err; + if (macro->serdestype == SPX5_SDT_25G) + err = sparx5_sd25g28_config(macro, true); + else + err = sparx5_sd10g28_config(macro, true); + if (err) { + dev_err(&phy->dev, "SerDes %u, reset error: %d\n", + macro->sidx, err); + } + return err; +} + +static int sparx5_serdes_validate(struct phy *phy, enum phy_mode mode, + int submode, + union phy_configure_opts *opts) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + 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; + + switch (submode) { + case PHY_INTERFACE_MODE_1000BASEX: + if (macro->speed != SPEED_100 && /* This is for 100BASE-FX */ + macro->speed != SPEED_1000) + return -EINVAL; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_QSGMII: + if (macro->speed >= SPEED_5000) + return -EINVAL; + break; + case PHY_INTERFACE_MODE_10GBASER: + if (macro->speed < SPEED_5000) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct phy_ops sparx5_serdes_ops = { + .power_on = sparx5_serdes_power_on, + .power_off = sparx5_serdes_power_off, + .set_mode = sparx5_serdes_set_mode, + .set_media = sparx5_serdes_set_media, + .set_speed = sparx5_serdes_set_speed, + .reset = sparx5_serdes_reset, + .validate = sparx5_serdes_validate, + .owner = THIS_MODULE, +}; + +static int sparx5_phy_create(struct sparx5_serdes_private *priv, + int idx, struct phy **phy) +{ + struct sparx5_serdes_macro *macro; + + *phy = devm_phy_create(priv->dev, NULL, &sparx5_serdes_ops); + if (IS_ERR(*phy)) + return PTR_ERR(*phy); + + macro = devm_kzalloc(priv->dev, sizeof(*macro), GFP_KERNEL); + if (!macro) + return -ENOMEM; + + 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; + } + + phy_set_drvdata(*phy, macro); + + return 0; +} + +static struct sparx5_serdes_io_resource sparx5_serdes_iomap[] = { + { TARGET_SD_CMU, 0x0 }, /* 0x610808000: sd_cmu_0 */ + { TARGET_SD_CMU + 1, 0x8000 }, /* 0x610810000: sd_cmu_1 */ + { TARGET_SD_CMU + 2, 0x10000 }, /* 0x610818000: sd_cmu_2 */ + { TARGET_SD_CMU + 3, 0x18000 }, /* 0x610820000: sd_cmu_3 */ + { TARGET_SD_CMU + 4, 0x20000 }, /* 0x610828000: sd_cmu_4 */ + { TARGET_SD_CMU + 5, 0x28000 }, /* 0x610830000: sd_cmu_5 */ + { TARGET_SD_CMU + 6, 0x30000 }, /* 0x610838000: sd_cmu_6 */ + { TARGET_SD_CMU + 7, 0x38000 }, /* 0x610840000: sd_cmu_7 */ + { TARGET_SD_CMU + 8, 0x40000 }, /* 0x610848000: sd_cmu_8 */ + { TARGET_SD_CMU_CFG, 0x48000 }, /* 0x610850000: sd_cmu_cfg_0 */ + { TARGET_SD_CMU_CFG + 1, 0x50000 }, /* 0x610858000: sd_cmu_cfg_1 */ + { TARGET_SD_CMU_CFG + 2, 0x58000 }, /* 0x610860000: sd_cmu_cfg_2 */ + { TARGET_SD_CMU_CFG + 3, 0x60000 }, /* 0x610868000: sd_cmu_cfg_3 */ + { TARGET_SD_CMU_CFG + 4, 0x68000 }, /* 0x610870000: sd_cmu_cfg_4 */ + { TARGET_SD_CMU_CFG + 5, 0x70000 }, /* 0x610878000: sd_cmu_cfg_5 */ + { TARGET_SD_CMU_CFG + 6, 0x78000 }, /* 0x610880000: sd_cmu_cfg_6 */ + { TARGET_SD_CMU_CFG + 7, 0x80000 }, /* 0x610888000: sd_cmu_cfg_7 */ + { TARGET_SD_CMU_CFG + 8, 0x88000 }, /* 0x610890000: sd_cmu_cfg_8 */ + { TARGET_SD6G_LANE, 0x90000 }, /* 0x610898000: sd6g_lane_0 */ + { TARGET_SD6G_LANE + 1, 0x98000 }, /* 0x6108a0000: sd6g_lane_1 */ + { TARGET_SD6G_LANE + 2, 0xa0000 }, /* 0x6108a8000: sd6g_lane_2 */ + { TARGET_SD6G_LANE + 3, 0xa8000 }, /* 0x6108b0000: sd6g_lane_3 */ + { TARGET_SD6G_LANE + 4, 0xb0000 }, /* 0x6108b8000: sd6g_lane_4 */ + { TARGET_SD6G_LANE + 5, 0xb8000 }, /* 0x6108c0000: sd6g_lane_5 */ + { TARGET_SD6G_LANE + 6, 0xc0000 }, /* 0x6108c8000: sd6g_lane_6 */ + { TARGET_SD6G_LANE + 7, 0xc8000 }, /* 0x6108d0000: sd6g_lane_7 */ + { TARGET_SD6G_LANE + 8, 0xd0000 }, /* 0x6108d8000: sd6g_lane_8 */ + { TARGET_SD6G_LANE + 9, 0xd8000 }, /* 0x6108e0000: sd6g_lane_9 */ + { TARGET_SD6G_LANE + 10, 0xe0000 }, /* 0x6108e8000: sd6g_lane_10 */ + { TARGET_SD6G_LANE + 11, 0xe8000 }, /* 0x6108f0000: sd6g_lane_11 */ + { TARGET_SD6G_LANE + 12, 0xf0000 }, /* 0x6108f8000: sd6g_lane_12 */ + { TARGET_SD10G_LANE, 0xf8000 }, /* 0x610900000: sd10g_lane_0 */ + { TARGET_SD10G_LANE + 1, 0x100000 }, /* 0x610908000: sd10g_lane_1 */ + { TARGET_SD10G_LANE + 2, 0x108000 }, /* 0x610910000: sd10g_lane_2 */ + { TARGET_SD10G_LANE + 3, 0x110000 }, /* 0x610918000: sd10g_lane_3 */ + { TARGET_SD_LANE, 0x1a0000 }, /* 0x6109a8000: sd_lane_0 */ + { TARGET_SD_LANE + 1, 0x1a8000 }, /* 0x6109b0000: sd_lane_1 */ + { TARGET_SD_LANE + 2, 0x1b0000 }, /* 0x6109b8000: sd_lane_2 */ + { TARGET_SD_LANE + 3, 0x1b8000 }, /* 0x6109c0000: sd_lane_3 */ + { TARGET_SD_LANE + 4, 0x1c0000 }, /* 0x6109c8000: sd_lane_4 */ + { TARGET_SD_LANE + 5, 0x1c8000 }, /* 0x6109d0000: sd_lane_5 */ + { TARGET_SD_LANE + 6, 0x1d0000 }, /* 0x6109d8000: sd_lane_6 */ + { TARGET_SD_LANE + 7, 0x1d8000 }, /* 0x6109e0000: sd_lane_7 */ + { TARGET_SD_LANE + 8, 0x1e0000 }, /* 0x6109e8000: sd_lane_8 */ + { TARGET_SD_LANE + 9, 0x1e8000 }, /* 0x6109f0000: sd_lane_9 */ + { TARGET_SD_LANE + 10, 0x1f0000 }, /* 0x6109f8000: sd_lane_10 */ + { TARGET_SD_LANE + 11, 0x1f8000 }, /* 0x610a00000: sd_lane_11 */ + { TARGET_SD_LANE + 12, 0x200000 }, /* 0x610a08000: sd_lane_12 */ + { TARGET_SD_LANE + 13, 0x208000 }, /* 0x610a10000: sd_lane_13 */ + { TARGET_SD_LANE + 14, 0x210000 }, /* 0x610a18000: sd_lane_14 */ + { TARGET_SD_LANE + 15, 0x218000 }, /* 0x610a20000: sd_lane_15 */ + { TARGET_SD_LANE + 16, 0x220000 }, /* 0x610a28000: sd_lane_16 */ + { TARGET_SD_CMU + 9, 0x400000 }, /* 0x610c08000: sd_cmu_9 */ + { TARGET_SD_CMU + 10, 0x408000 }, /* 0x610c10000: sd_cmu_10 */ + { TARGET_SD_CMU + 11, 0x410000 }, /* 0x610c18000: sd_cmu_11 */ + { TARGET_SD_CMU + 12, 0x418000 }, /* 0x610c20000: sd_cmu_12 */ + { TARGET_SD_CMU + 13, 0x420000 }, /* 0x610c28000: sd_cmu_13 */ + { TARGET_SD_CMU_CFG + 9, 0x428000 }, /* 0x610c30000: sd_cmu_cfg_9 */ + { TARGET_SD_CMU_CFG + 10, 0x430000 }, /* 0x610c38000: sd_cmu_cfg_10 */ + { TARGET_SD_CMU_CFG + 11, 0x438000 }, /* 0x610c40000: sd_cmu_cfg_11 */ + { TARGET_SD_CMU_CFG + 12, 0x440000 }, /* 0x610c48000: sd_cmu_cfg_12 */ + { TARGET_SD_CMU_CFG + 13, 0x448000 }, /* 0x610c50000: sd_cmu_cfg_13 */ + { TARGET_SD10G_LANE + 4, 0x450000 }, /* 0x610c58000: sd10g_lane_4 */ + { TARGET_SD10G_LANE + 5, 0x458000 }, /* 0x610c60000: sd10g_lane_5 */ + { TARGET_SD10G_LANE + 6, 0x460000 }, /* 0x610c68000: sd10g_lane_6 */ + { TARGET_SD10G_LANE + 7, 0x468000 }, /* 0x610c70000: sd10g_lane_7 */ + { TARGET_SD10G_LANE + 8, 0x470000 }, /* 0x610c78000: sd10g_lane_8 */ + { TARGET_SD10G_LANE + 9, 0x478000 }, /* 0x610c80000: sd10g_lane_9 */ + { TARGET_SD10G_LANE + 10, 0x480000 }, /* 0x610c88000: sd10g_lane_10 */ + { TARGET_SD10G_LANE + 11, 0x488000 }, /* 0x610c90000: sd10g_lane_11 */ + { TARGET_SD25G_LANE, 0x490000 }, /* 0x610c98000: sd25g_lane_0 */ + { TARGET_SD25G_LANE + 1, 0x498000 }, /* 0x610ca0000: sd25g_lane_1 */ + { TARGET_SD25G_LANE + 2, 0x4a0000 }, /* 0x610ca8000: sd25g_lane_2 */ + { TARGET_SD25G_LANE + 3, 0x4a8000 }, /* 0x610cb0000: sd25g_lane_3 */ + { TARGET_SD25G_LANE + 4, 0x4b0000 }, /* 0x610cb8000: sd25g_lane_4 */ + { TARGET_SD25G_LANE + 5, 0x4b8000 }, /* 0x610cc0000: sd25g_lane_5 */ + { TARGET_SD25G_LANE + 6, 0x4c0000 }, /* 0x610cc8000: sd25g_lane_6 */ + { TARGET_SD25G_LANE + 7, 0x4c8000 }, /* 0x610cd0000: sd25g_lane_7 */ + { TARGET_SD_LANE + 17, 0x550000 }, /* 0x610d58000: sd_lane_17 */ + { TARGET_SD_LANE + 18, 0x558000 }, /* 0x610d60000: sd_lane_18 */ + { TARGET_SD_LANE + 19, 0x560000 }, /* 0x610d68000: sd_lane_19 */ + { TARGET_SD_LANE + 20, 0x568000 }, /* 0x610d70000: sd_lane_20 */ + { TARGET_SD_LANE + 21, 0x570000 }, /* 0x610d78000: sd_lane_21 */ + { TARGET_SD_LANE + 22, 0x578000 }, /* 0x610d80000: sd_lane_22 */ + { TARGET_SD_LANE + 23, 0x580000 }, /* 0x610d88000: sd_lane_23 */ + { TARGET_SD_LANE + 24, 0x588000 }, /* 0x610d90000: sd_lane_24 */ + { TARGET_SD_LANE_25G, 0x590000 }, /* 0x610d98000: sd_lane_25g_25 */ + { TARGET_SD_LANE_25G + 1, 0x598000 }, /* 0x610da0000: sd_lane_25g_26 */ + { TARGET_SD_LANE_25G + 2, 0x5a0000 }, /* 0x610da8000: sd_lane_25g_27 */ + { TARGET_SD_LANE_25G + 3, 0x5a8000 }, /* 0x610db0000: sd_lane_25g_28 */ + { TARGET_SD_LANE_25G + 4, 0x5b0000 }, /* 0x610db8000: sd_lane_25g_29 */ + { TARGET_SD_LANE_25G + 5, 0x5b8000 }, /* 0x610dc0000: sd_lane_25g_30 */ + { TARGET_SD_LANE_25G + 6, 0x5c0000 }, /* 0x610dc8000: sd_lane_25g_31 */ + { TARGET_SD_LANE_25G + 7, 0x5c8000 }, /* 0x610dd0000: sd_lane_25g_32 */ +}; + +/* Client lookup function, uses serdes index */ +static struct phy *sparx5_serdes_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct sparx5_serdes_private *priv = dev_get_drvdata(dev); + int idx; + unsigned int sidx; + + if (args->args_count != 1) + return ERR_PTR(-EINVAL); + + sidx = args->args[0]; + + /* Check validity: ERR_PTR(-ENODEV) if not valid */ + for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + struct sparx5_serdes_macro *macro = + phy_get_drvdata(priv->phys[idx]); + + if (sidx != macro->sidx) + continue; + + return priv->phys[idx]; + } + return ERR_PTR(-ENODEV); +} + +static int sparx5_serdes_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct sparx5_serdes_private *priv; + struct phy_provider *provider; + struct resource *iores; + void __iomem *iomem; + unsigned long clock; + struct clk *clk; + int idx; + int err; + + if (!np && !pdev->dev.platform_data) + return -ENODEV; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + priv->dev = &pdev->dev; + + /* Get coreclock */ + clk = devm_clk_get(priv->dev, NULL); + if (IS_ERR(clk)) { + dev_err(priv->dev, "Failed to get coreclock\n"); + return PTR_ERR(clk); + } + clock = clk_get_rate(clk); + if (clock == 0) { + dev_err(priv->dev, "Invalid coreclock %lu\n", clock); + return -EINVAL; + } + priv->coreclock = clock; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iomem = devm_ioremap(priv->dev, iores->start, resource_size(iores)); + if (IS_ERR(iomem)) { + dev_err(priv->dev, "Unable to get serdes registers: %s\n", + iores->name); + return PTR_ERR(iomem); + } + for (idx = 0; idx < ARRAY_SIZE(sparx5_serdes_iomap); idx++) { + struct sparx5_serdes_io_resource *iomap = &sparx5_serdes_iomap[idx]; + + priv->regs[iomap->id] = iomem + iomap->offset; + } + for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + err = sparx5_phy_create(priv, idx, &priv->phys[idx]); + if (err) + return err; + } + + provider = devm_of_phy_provider_register(priv->dev, sparx5_serdes_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id sparx5_serdes_match[] = { + { .compatible = "microchip,sparx5-serdes" }, + { } +}; +MODULE_DEVICE_TABLE(of, sparx5_serdes_match); + +static struct platform_driver sparx5_serdes_driver = { + .probe = sparx5_serdes_probe, + .driver = { + .name = "sparx5-serdes", + .of_match_table = sparx5_serdes_match, + }, +}; + +module_platform_driver(sparx5_serdes_driver); + +MODULE_DESCRIPTION("Microchip Sparx5 switch serdes driver"); +MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/microchip/sparx5_serdes.h b/drivers/phy/microchip/sparx5_serdes.h new file mode 100644 index 0000000000000000000000000000000000000000..0a3e496e6210ccbfcdef12d5004ac09b02221c59 --- /dev/null +++ b/drivers/phy/microchip/sparx5_serdes.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * Microchip Sparx5 SerDes driver + * + * Copyright (c) 2020 Microchip Technology Inc. + */ + +#ifndef _SPARX5_SERDES_H_ +#define _SPARX5_SERDES_H_ + +#include "sparx5_serdes_regs.h" + +#define SPX5_SERDES_MAX 33 + +enum sparx5_serdes_type { + SPX5_SDT_6G = 6, + SPX5_SDT_10G = 10, + SPX5_SDT_25G = 25, +}; + +enum sparx5_serdes_mode { + SPX5_SD_MODE_NONE, + SPX5_SD_MODE_2G5, + SPX5_SD_MODE_QSGMII, + SPX5_SD_MODE_100FX, + SPX5_SD_MODE_1000BASEX, + SPX5_SD_MODE_SFI, +}; + +struct sparx5_serdes_private { + struct device *dev; + void __iomem *regs[NUM_TARGETS]; + struct phy *phys[SPX5_SERDES_MAX]; + bool cmu_enabled; + unsigned long coreclock; +}; + +struct sparx5_serdes_macro { + struct sparx5_serdes_private *priv; + u32 sidx; + u32 stpidx; + enum sparx5_serdes_type serdestype; + enum sparx5_serdes_mode serdesmode; + phy_interface_t portmode; + int speed; + enum phy_media media; +}; + +/* Read, Write and modify registers content. + * The register definition macros start at the id + */ +static inline void __iomem *sdx5_addr(void __iomem *base[], + int id, int tinst, int tcnt, + int gbase, int ginst, + int gcnt, int gwidth, + int raddr, int rinst, + int rcnt, int rwidth) +{ + WARN_ON((tinst) >= tcnt); + WARN_ON((ginst) >= gcnt); + WARN_ON((rinst) >= rcnt); + return base[id + (tinst)] + + gbase + ((ginst) * gwidth) + + raddr + ((rinst) * rwidth); +} + +static inline void __iomem *sdx5_inst_baseaddr(void __iomem *base, + int gbase, int ginst, + int gcnt, int gwidth, + int raddr, int rinst, + int rcnt, int rwidth) +{ + WARN_ON((ginst) >= gcnt); + WARN_ON((rinst) >= rcnt); + return base + + gbase + ((ginst) * gwidth) + + raddr + ((rinst) * rwidth); +} + +static inline void sdx5_rmw(u32 val, u32 mask, struct sparx5_serdes_private *priv, + int id, int tinst, int tcnt, + int gbase, int ginst, int gcnt, int gwidth, + int raddr, int rinst, int rcnt, int rwidth) +{ + u32 nval; + void __iomem *addr = + sdx5_addr(priv->regs, id, tinst, tcnt, + gbase, ginst, gcnt, gwidth, + raddr, rinst, rcnt, rwidth); + nval = readl(addr); + nval = (nval & ~mask) | (val & mask); + writel(nval, addr); +} + +static inline void sdx5_inst_rmw(u32 val, u32 mask, void __iomem *iomem, + int id, int tinst, int tcnt, + int gbase, int ginst, int gcnt, int gwidth, + int raddr, int rinst, int rcnt, int rwidth) +{ + u32 nval; + void __iomem *addr = + sdx5_inst_baseaddr(iomem, + gbase, ginst, gcnt, gwidth, + raddr, rinst, rcnt, rwidth); + nval = readl(addr); + nval = (nval & ~mask) | (val & mask); + writel(nval, addr); +} + +static inline void sdx5_rmw_addr(u32 val, u32 mask, void __iomem *addr) +{ + u32 nval; + + nval = readl(addr); + nval = (nval & ~mask) | (val & mask); + writel(nval, addr); +} + +static inline void __iomem *sdx5_inst_get(struct sparx5_serdes_private *priv, + int id, int tinst) +{ + return priv->regs[id + tinst]; +} + +static inline void __iomem *sdx5_inst_addr(void __iomem *iomem, + int id, int tinst, int tcnt, + int gbase, + int ginst, int gcnt, int gwidth, + int raddr, + int rinst, int rcnt, int rwidth) +{ + return sdx5_inst_baseaddr(iomem, gbase, ginst, gcnt, gwidth, + raddr, rinst, rcnt, rwidth); +} + + +#endif /* _SPARX5_SERDES_REGS_H_ */ diff --git a/drivers/phy/microchip/sparx5_serdes_regs.h b/drivers/phy/microchip/sparx5_serdes_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..b96386a4df5a26b05c732e5048269df441bace7f --- /dev/null +++ b/drivers/phy/microchip/sparx5_serdes_regs.h @@ -0,0 +1,2695 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * Microchip Sparx5 SerDes driver + * + * Copyright (c) 2020 Microchip Technology Inc. + */ + +/* This file is autogenerated by cml-utils 2020-11-16 13:11:27 +0100. + * Commit ID: 13bdf073131d8bf40c54901df6988ae4e9c8f29f + */ + +#ifndef _SPARX5_SERDES_REGS_H_ +#define _SPARX5_SERDES_REGS_H_ + +#include <linux/bitfield.h> +#include <linux/types.h> +#include <linux/bug.h> + +enum sparx5_serdes_target { + TARGET_SD10G_LANE = 200, + TARGET_SD25G_LANE = 212, + TARGET_SD6G_LANE = 233, + TARGET_SD_CMU = 248, + TARGET_SD_CMU_CFG = 262, + TARGET_SD_LANE = 276, + TARGET_SD_LANE_25G = 301, + NUM_TARGETS = 332 +}; + +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, x) +#define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, x) + +#define SD10G_LANE_LANE_01_CFG_RXDET_EN BIT(4) +#define SD10G_LANE_LANE_01_CFG_RXDET_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_01_CFG_RXDET_EN, x) +#define SD10G_LANE_LANE_01_CFG_RXDET_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_01_CFG_RXDET_EN, x) + +#define SD10G_LANE_LANE_01_CFG_RXDET_STR BIT(5) +#define SD10G_LANE_LANE_01_CFG_RXDET_STR_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_01_CFG_RXDET_STR, x) +#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) + +#define SD10G_LANE_LANE_02_CFG_EN_ADV BIT(0) +#define SD10G_LANE_LANE_02_CFG_EN_ADV_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_ADV, x) +#define SD10G_LANE_LANE_02_CFG_EN_ADV_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_ADV, x) + +#define SD10G_LANE_LANE_02_CFG_EN_MAIN BIT(1) +#define SD10G_LANE_LANE_02_CFG_EN_MAIN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_MAIN, x) +#define SD10G_LANE_LANE_02_CFG_EN_MAIN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_MAIN, x) + +#define SD10G_LANE_LANE_02_CFG_EN_DLY BIT(2) +#define SD10G_LANE_LANE_02_CFG_EN_DLY_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_DLY, x) +#define SD10G_LANE_LANE_02_CFG_EN_DLY_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_DLY, x) + +#define SD10G_LANE_LANE_02_CFG_EN_DLY2 BIT(3) +#define SD10G_LANE_LANE_02_CFG_EN_DLY2_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_DLY2, x) +#define SD10G_LANE_LANE_02_CFG_EN_DLY2_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_DLY2, x) + +#define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, x) +#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) + +#define SD10G_LANE_LANE_03_CFG_TAP_MAIN BIT(0) +#define SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_03_CFG_TAP_MAIN, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, x) +#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) + +#define SD10G_LANE_LANE_06_CFG_PD_DRIVER BIT(0) +#define SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_PD_DRIVER, x) +#define SD10G_LANE_LANE_06_CFG_PD_DRIVER_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_PD_DRIVER, x) + +#define SD10G_LANE_LANE_06_CFG_PD_CLK BIT(1) +#define SD10G_LANE_LANE_06_CFG_PD_CLK_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_PD_CLK, x) +#define SD10G_LANE_LANE_06_CFG_PD_CLK_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_PD_CLK, x) + +#define SD10G_LANE_LANE_06_CFG_PD_CML BIT(2) +#define SD10G_LANE_LANE_06_CFG_PD_CML_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_PD_CML, x) +#define SD10G_LANE_LANE_06_CFG_PD_CML_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_PD_CML, x) + +#define SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN BIT(3) +#define SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, x) +#define SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, x) + +#define SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN BIT(4) +#define SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN, x) +#define SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN, x) + +#define SD10G_LANE_LANE_06_CFG_EN_PREEMPH BIT(5) +#define SD10G_LANE_LANE_06_CFG_EN_PREEMPH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_EN_PREEMPH, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, x) +#define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, x) + +#define SD10G_LANE_LANE_0B_CFG_PD_CTLE BIT(4) +#define SD10G_LANE_LANE_0B_CFG_PD_CTLE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_PD_CTLE, x) +#define SD10G_LANE_LANE_0B_CFG_PD_CTLE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_PD_CTLE, x) + +#define SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN BIT(5) +#define SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN, x) +#define SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN, x) + +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE BIT(6) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, x) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, x) + +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ BIT(7) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ, x) +#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) + +#define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE BIT(0) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSCAL_AFE, x) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSCAL_AFE, x) + +#define SD10G_LANE_LANE_0C_CFG_OSCAL_SQ BIT(1) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSCAL_SQ, x) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSCAL_SQ, x) + +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE BIT(2) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE, x) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE, x) + +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ BIT(3) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ, x) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ, x) + +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE BIT(4) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, x) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, x) + +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ BIT(5) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ, x) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ, x) + +#define SD10G_LANE_LANE_0C_CFG_PD_RX_LS BIT(6) +#define SD10G_LANE_LANE_0C_CFG_PD_RX_LS_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_PD_RX_LS, x) +#define SD10G_LANE_LANE_0C_CFG_PD_RX_LS_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_PD_RX_LS, x) + +#define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12 BIT(7) +#define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0, x) +#define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0, x) + +#define SD10G_LANE_LANE_0D_CFG_EQR_BYP BIT(4) +#define SD10G_LANE_LANE_0D_CFG_EQR_BYP_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0D_CFG_EQR_BYP, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0, x) +#define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0, x) + +#define SD10G_LANE_LANE_0E_CFG_RXLB_EN BIT(4) +#define SD10G_LANE_LANE_0E_CFG_RXLB_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_RXLB_EN, x) +#define SD10G_LANE_LANE_0E_CFG_RXLB_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_RXLB_EN, x) + +#define SD10G_LANE_LANE_0E_CFG_TXLB_EN BIT(5) +#define SD10G_LANE_LANE_0E_CFG_TXLB_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_TXLB_EN, x) +#define SD10G_LANE_LANE_0E_CFG_TXLB_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_TXLB_EN, x) + +#define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN BIT(6) +#define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, x) +#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) + +#define SD10G_LANE_LANE_13_CFG_DCDR_PD BIT(0) +#define SD10G_LANE_LANE_13_CFG_DCDR_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_13_CFG_DCDR_PD, x) +#define SD10G_LANE_LANE_13_CFG_DCDR_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_13_CFG_DCDR_PD, x) + +#define SD10G_LANE_LANE_13_CFG_PHID_1T BIT(1) +#define SD10G_LANE_LANE_13_CFG_PHID_1T_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_13_CFG_PHID_1T, x) +#define SD10G_LANE_LANE_13_CFG_PHID_1T_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_13_CFG_PHID_1T, x) + +#define SD10G_LANE_LANE_13_CFG_CDRCK_EN BIT(2) +#define SD10G_LANE_LANE_13_CFG_CDRCK_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_13_CFG_CDRCK_EN, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, x) +#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) + +#define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN BIT(0) +#define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN, x) +#define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_EN BIT(1) +#define SD10G_LANE_LANE_1A_CFG_PI_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_EN, x) +#define SD10G_LANE_LANE_1A_CFG_PI_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_EN, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_DFE_EN BIT(2) +#define SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, x) +#define SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_STEPS BIT(3) +#define SD10G_LANE_LANE_1A_CFG_PI_STEPS_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_STEPS, x) +#define SD10G_LANE_LANE_1A_CFG_PI_STEPS_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_STEPS, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, x) +#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) + +#define SD10G_LANE_LANE_23_CFG_DFE_PD BIT(0) +#define SD10G_LANE_LANE_23_CFG_DFE_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_DFE_PD, x) +#define SD10G_LANE_LANE_23_CFG_DFE_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_DFE_PD, x) + +#define SD10G_LANE_LANE_23_CFG_EN_DFEDIG BIT(1) +#define SD10G_LANE_LANE_23_CFG_EN_DFEDIG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_EN_DFEDIG, x) +#define SD10G_LANE_LANE_23_CFG_EN_DFEDIG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_EN_DFEDIG, x) + +#define SD10G_LANE_LANE_23_CFG_DFECK_EN BIT(2) +#define SD10G_LANE_LANE_23_CFG_DFECK_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_DFECK_EN, x) +#define SD10G_LANE_LANE_23_CFG_DFECK_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_DFECK_EN, x) + +#define SD10G_LANE_LANE_23_CFG_ERRAMP_PD BIT(3) +#define SD10G_LANE_LANE_23_CFG_ERRAMP_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_ERRAMP_PD, x) +#define SD10G_LANE_LANE_23_CFG_ERRAMP_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_ERRAMP_PD, x) + +#define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0 GENMASK(6, 4) +#define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, x) +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, x) + +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, x) +#define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, x) + +#define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, x) +#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) + +#define SD10G_LANE_LANE_30_CFG_SUMMER_EN BIT(0) +#define SD10G_LANE_LANE_30_CFG_SUMMER_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_30_CFG_SUMMER_EN, x) +#define SD10G_LANE_LANE_30_CFG_SUMMER_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_30_CFG_SUMMER_EN, x) + +#define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0 GENMASK(6, 4) +#define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, x) +#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) + +#define SD10G_LANE_LANE_31_CFG_PI_RSTN BIT(0) +#define SD10G_LANE_LANE_31_CFG_PI_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_PI_RSTN, x) +#define SD10G_LANE_LANE_31_CFG_PI_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_PI_RSTN, x) + +#define SD10G_LANE_LANE_31_CFG_CDR_RSTN BIT(1) +#define SD10G_LANE_LANE_31_CFG_CDR_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_CDR_RSTN, x) +#define SD10G_LANE_LANE_31_CFG_CDR_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_CDR_RSTN, x) + +#define SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG BIT(2) +#define SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, x) +#define SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, x) + +#define SD10G_LANE_LANE_31_CFG_CTLE_RSTN BIT(3) +#define SD10G_LANE_LANE_31_CFG_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_CTLE_RSTN, x) +#define SD10G_LANE_LANE_31_CFG_CTLE_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_CTLE_RSTN, x) + +#define SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8 BIT(4) +#define SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8, x) +#define SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8, x) + +#define SD10G_LANE_LANE_31_CFG_R50_EN BIT(5) +#define SD10G_LANE_LANE_31_CFG_R50_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_R50_EN, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0, x) +#define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0, x) + +#define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, x) +#define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, x) + +#define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0, x) +#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) + +#define SD10G_LANE_LANE_35_CFG_TXRATE_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_35_CFG_TXRATE_1_0, x) +#define SD10G_LANE_LANE_35_CFG_TXRATE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_35_CFG_TXRATE_1_0, x) + +#define SD10G_LANE_LANE_35_CFG_RXRATE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_35_CFG_RXRATE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_35_CFG_RXRATE_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, x) +#define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, x) + +#define SD10G_LANE_LANE_36_CFG_EID_LP BIT(4) +#define SD10G_LANE_LANE_36_CFG_EID_LP_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_EID_LP, x) +#define SD10G_LANE_LANE_36_CFG_EID_LP_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_EID_LP, x) + +#define SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH BIT(5) +#define SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH, x) +#define SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH, x) + +#define SD10G_LANE_LANE_36_CFG_PRBS_SEL BIT(6) +#define SD10G_LANE_LANE_36_CFG_PRBS_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_PRBS_SEL, x) +#define SD10G_LANE_LANE_36_CFG_PRBS_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_PRBS_SEL, x) + +#define SD10G_LANE_LANE_36_CFG_PRBS_SETB BIT(7) +#define SD10G_LANE_LANE_36_CFG_PRBS_SETB_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_PRBS_SETB, x) +#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) + +#define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD BIT(0) +#define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD, x) +#define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD, x) + +#define SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE BIT(1) +#define SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE, x) +#define SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE, x) + +#define SD10G_LANE_LANE_37_CFG_TXSWING_HALF BIT(2) +#define SD10G_LANE_LANE_37_CFG_TXSWING_HALF_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_TXSWING_HALF, x) +#define SD10G_LANE_LANE_37_CFG_TXSWING_HALF_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_TXSWING_HALF, x) + +#define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0, x) +#define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0, x) + +#define SD10G_LANE_LANE_39_CFG_RX_SSC_LH BIT(4) +#define SD10G_LANE_LANE_39_CFG_RX_SSC_LH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_39_CFG_RX_SSC_LH, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0, x) +#define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0, x) + +#define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, x) +#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) + +#define SD10G_LANE_LANE_3C_CFG_DIS_ACC BIT(0) +#define SD10G_LANE_LANE_3C_CFG_DIS_ACC_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3C_CFG_DIS_ACC, x) +#define SD10G_LANE_LANE_3C_CFG_DIS_ACC_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_3C_CFG_DIS_ACC, x) + +#define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER BIT(1) +#define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, x) +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, x) + +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0 GENMASK(6, 4) +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, x) +#define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, x) + +#define SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL BIT(4) +#define SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL, x) +#define SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL, x) + +#define SD10G_LANE_LANE_48_CFG_CLK_ENQ BIT(5) +#define SD10G_LANE_LANE_48_CFG_CLK_ENQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_48_CFG_CLK_ENQ, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0, x) +#define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0, x) + +#define SD10G_LANE_LANE_50_CFG_SSC_RESETB BIT(4) +#define SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_SSC_RESETB, x) +#define SD10G_LANE_LANE_50_CFG_SSC_RESETB_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_SSC_RESETB, x) + +#define SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL BIT(5) +#define SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, x) +#define SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, x) + +#define SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL BIT(6) +#define SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL, x) +#define SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL, x) + +#define SD10G_LANE_LANE_50_CFG_JT_EN BIT(7) +#define SD10G_LANE_LANE_50_CFG_JT_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_JT_EN, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, x) +#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) + +#define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE BIT(0) +#define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_TX_BIT_REVERSE, x) +#define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_TX_BIT_REVERSE, x) + +#define SD10G_LANE_LANE_83_R_TX_POL_INV BIT(1) +#define SD10G_LANE_LANE_83_R_TX_POL_INV_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_TX_POL_INV, x) +#define SD10G_LANE_LANE_83_R_TX_POL_INV_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_TX_POL_INV, x) + +#define SD10G_LANE_LANE_83_R_RX_BIT_REVERSE BIT(2) +#define SD10G_LANE_LANE_83_R_RX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_RX_BIT_REVERSE, x) +#define SD10G_LANE_LANE_83_R_RX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_RX_BIT_REVERSE, x) + +#define SD10G_LANE_LANE_83_R_RX_POL_INV BIT(3) +#define SD10G_LANE_LANE_83_R_RX_POL_INV_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_RX_POL_INV, x) +#define SD10G_LANE_LANE_83_R_RX_POL_INV_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_RX_POL_INV, x) + +#define SD10G_LANE_LANE_83_R_DFE_RSTN BIT(4) +#define SD10G_LANE_LANE_83_R_DFE_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_DFE_RSTN, x) +#define SD10G_LANE_LANE_83_R_DFE_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_DFE_RSTN, x) + +#define SD10G_LANE_LANE_83_R_CDR_RSTN BIT(5) +#define SD10G_LANE_LANE_83_R_CDR_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_CDR_RSTN, x) +#define SD10G_LANE_LANE_83_R_CDR_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_CDR_RSTN, x) + +#define SD10G_LANE_LANE_83_R_CTLE_RSTN BIT(6) +#define SD10G_LANE_LANE_83_R_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_CTLE_RSTN, x) +#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) + +#define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN BIT(0) +#define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN, x) +#define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN, x) + +#define SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT BIT(1) +#define SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT, x) + +#define SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE BIT(2) +#define SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE, x) +#define SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE, x) + +#define SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL BIT(3) +#define SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, x) +#define SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, x) + +#define SD10G_LANE_LANE_93_R_REG_MANUAL BIT(4) +#define SD10G_LANE_LANE_93_R_REG_MANUAL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_REG_MANUAL, x) +#define SD10G_LANE_LANE_93_R_REG_MANUAL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_REG_MANUAL, x) + +#define SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT BIT(5) +#define SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT, x) + +#define SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT BIT(6) +#define SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT, x) + +#define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT BIT(7) +#define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT, x) +#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) + +#define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, x) +#define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, x) + +#define SD10G_LANE_LANE_94_R_ISCAN_REG BIT(4) +#define SD10G_LANE_LANE_94_R_ISCAN_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_ISCAN_REG, x) +#define SD10G_LANE_LANE_94_R_ISCAN_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_ISCAN_REG, x) + +#define SD10G_LANE_LANE_94_R_TXEQ_REG BIT(5) +#define SD10G_LANE_LANE_94_R_TXEQ_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_TXEQ_REG, x) +#define SD10G_LANE_LANE_94_R_TXEQ_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_TXEQ_REG, x) + +#define SD10G_LANE_LANE_94_R_MISC_REG BIT(6) +#define SD10G_LANE_LANE_94_R_MISC_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_MISC_REG, x) +#define SD10G_LANE_LANE_94_R_MISC_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_MISC_REG, x) + +#define SD10G_LANE_LANE_94_R_SWING_REG BIT(7) +#define SD10G_LANE_LANE_94_R_SWING_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_SWING_REG, x) +#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) + +#define SD10G_LANE_LANE_9E_R_RXEQ_REG BIT(0) +#define SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_9E_R_RXEQ_REG, x) +#define SD10G_LANE_LANE_9E_R_RXEQ_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_9E_R_RXEQ_REG, x) + +#define SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN BIT(1) +#define SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN, x) +#define SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN, x) + +#define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN BIT(2) +#define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0, x) +#define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0, x) + +#define SD10G_LANE_LANE_A1_R_SSC_FROM_HWT BIT(4) +#define SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_SSC_FROM_HWT, x) +#define SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_SSC_FROM_HWT, x) + +#define SD10G_LANE_LANE_A1_R_CDR_FROM_HWT BIT(5) +#define SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_CDR_FROM_HWT, x) +#define SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_CDR_FROM_HWT, x) + +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT BIT(6) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, x) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, x) + +#define SD10G_LANE_LANE_A1_R_PCLK_GATING BIT(7) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_PCLK_GATING, x) +#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) + +#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)\ + FIELD_PREP(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, x) +#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) + +#define SD10G_LANE_LANE_DF_LOL_UDL BIT(0) +#define SD10G_LANE_LANE_DF_LOL_UDL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_LOL_UDL, x) +#define SD10G_LANE_LANE_DF_LOL_UDL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_LOL_UDL, x) + +#define SD10G_LANE_LANE_DF_LOL BIT(1) +#define SD10G_LANE_LANE_DF_LOL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_LOL, x) +#define SD10G_LANE_LANE_DF_LOL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_LOL, x) + +#define SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED BIT(2) +#define SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) +#define SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) + +#define SD10G_LANE_LANE_DF_SQUELCH BIT(3) +#define SD10G_LANE_LANE_DF_SQUELCH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_SQUELCH, x) +#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) + +#define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN BIT(0) +#define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN, x) +#define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN, x) + +#define SD25G_LANE_CMU_09_CFG_EN_DUMMY BIT(1) +#define SD25G_LANE_CMU_09_CFG_EN_DUMMY_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_EN_DUMMY, x) +#define SD25G_LANE_CMU_09_CFG_EN_DUMMY_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_EN_DUMMY, x) + +#define SD25G_LANE_CMU_09_CFG_PLL_LOS_SET BIT(2) +#define SD25G_LANE_CMU_09_CFG_PLL_LOS_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_PLL_LOS_SET, x) +#define SD25G_LANE_CMU_09_CFG_PLL_LOS_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_PLL_LOS_SET, x) + +#define SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD BIT(3) +#define SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD, x) +#define SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD, x) + +#define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0, x) +#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) + +#define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT BIT(0) +#define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT, x) +#define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT, x) + +#define SD25G_LANE_CMU_0B_CFG_DISLOL BIT(1) +#define SD25G_LANE_CMU_0B_CFG_DISLOL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_DISLOL, x) +#define SD25G_LANE_CMU_0B_CFG_DISLOL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_DISLOL, x) + +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN BIT(2) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN, x) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN, x) + +#define SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN BIT(3) +#define SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, x) +#define SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, x) + +#define SD25G_LANE_CMU_0B_CFG_VFILT2PAD BIT(4) +#define SD25G_LANE_CMU_0B_CFG_VFILT2PAD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_VFILT2PAD, x) +#define SD25G_LANE_CMU_0B_CFG_VFILT2PAD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_VFILT2PAD, x) + +#define SD25G_LANE_CMU_0B_CFG_DISLOS BIT(5) +#define SD25G_LANE_CMU_0B_CFG_DISLOS_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_DISLOS, x) +#define SD25G_LANE_CMU_0B_CFG_DISLOS_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_DISLOS, x) + +#define SD25G_LANE_CMU_0B_CFG_DCLOL BIT(6) +#define SD25G_LANE_CMU_0B_CFG_DCLOL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_DCLOL, x) +#define SD25G_LANE_CMU_0B_CFG_DCLOL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_DCLOL, x) + +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN BIT(7) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN, x) +#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) + +#define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET BIT(0) +#define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET, x) +#define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET, x) + +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN BIT(1) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN, x) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN, x) + +#define SD25G_LANE_CMU_0C_CFG_VCO_PD BIT(2) +#define SD25G_LANE_CMU_0C_CFG_VCO_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_VCO_PD, x) +#define SD25G_LANE_CMU_0C_CFG_VCO_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_VCO_PD, x) + +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP BIT(3) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP, x) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP, x) + +#define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, x) +#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) + +#define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD BIT(0) +#define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_CK_TREE_PD, x) +#define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_CK_TREE_PD, x) + +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN BIT(1) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN, x) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN, x) + +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP BIT(2) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP, x) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP, x) + +#define SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP BIT(3) +#define SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP, x) +#define SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP, x) + +#define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, x) +#define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, x) + +#define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD BIT(4) +#define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, x) +#define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, x) + +#define SD25G_LANE_CMU_13_CFG_JT_EN BIT(4) +#define SD25G_LANE_CMU_13_CFG_JT_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_13_CFG_JT_EN, x) +#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) + +#define SD25G_LANE_CMU_18_R_PLL_RSTN BIT(0) +#define SD25G_LANE_CMU_18_R_PLL_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_RSTN, x) +#define SD25G_LANE_CMU_18_R_PLL_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_RSTN, x) + +#define SD25G_LANE_CMU_18_R_PLL_LOL_SET BIT(1) +#define SD25G_LANE_CMU_18_R_PLL_LOL_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_LOL_SET, x) +#define SD25G_LANE_CMU_18_R_PLL_LOL_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_LOL_SET, x) + +#define SD25G_LANE_CMU_18_R_PLL_LOS_SET BIT(2) +#define SD25G_LANE_CMU_18_R_PLL_LOS_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_LOS_SET, x) +#define SD25G_LANE_CMU_18_R_PLL_LOS_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_LOS_SET, x) + +#define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0, x) +#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) + +#define SD25G_LANE_CMU_19_R_CK_RESETB BIT(0) +#define SD25G_LANE_CMU_19_R_CK_RESETB_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_19_R_CK_RESETB, x) +#define SD25G_LANE_CMU_19_R_CK_RESETB_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_19_R_CK_RESETB, x) + +#define SD25G_LANE_CMU_19_R_PLL_DLOL_EN BIT(1) +#define SD25G_LANE_CMU_19_R_PLL_DLOL_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_19_R_PLL_DLOL_EN, x) +#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) + +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0 GENMASK(2, 0) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, x) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, x) + +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT BIT(4) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT, x) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT, x) + +#define SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE BIT(5) +#define SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE, x) +#define SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE, x) + +#define SD25G_LANE_CMU_1A_R_REG_MANUAL BIT(6) +#define SD25G_LANE_CMU_1A_R_REG_MANUAL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_REG_MANUAL, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_2A_R_DBG_SEL_1_0, x) +#define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_SEL_1_0, x) + +#define SD25G_LANE_CMU_2A_R_DBG_LINK_LANE BIT(4) +#define SD25G_LANE_CMU_2A_R_DBG_LINK_LANE_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_2A_R_DBG_LINK_LANE, x) +#define SD25G_LANE_CMU_2A_R_DBG_LINK_LANE_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_LINK_LANE, x) + +#define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS BIT(5) +#define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0, x) +#define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0, x) + +#define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0 GENMASK(6, 4) +#define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, x) +#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) + +#define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL BIT(0) +#define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL, x) +#define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL, x) + +#define SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD BIT(1) +#define SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD, x) +#define SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD, x) + +#define SD25G_LANE_CMU_40_L0_CFG_PD_CLK BIT(2) +#define SD25G_LANE_CMU_40_L0_CFG_PD_CLK_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_PD_CLK, x) +#define SD25G_LANE_CMU_40_L0_CFG_PD_CLK_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_PD_CLK, x) + +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN BIT(3) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, x) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, x) + +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN BIT(4) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN, x) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN, x) + +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST BIT(5) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0, x) +#define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0, x) + +#define SD25G_LANE_CMU_C0_PLL_LOL_UDL BIT(4) +#define SD25G_LANE_CMU_C0_PLL_LOL_UDL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_C0_PLL_LOL_UDL, x) +#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) + +#define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX GENMASK(7, 0) +#define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0, x) +#define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0, x) + +#define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, x) +#define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, x) + +#define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, x) +#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) + +#define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN BIT(0) +#define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, x) +#define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, x) + +#define SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN BIT(1) +#define SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN, x) +#define SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN, x) + +#define SD25G_LANE_LANE_04_LN_CFG_PD_CML BIT(2) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CML_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_PD_CML, x) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CML_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_PD_CML, x) + +#define SD25G_LANE_LANE_04_LN_CFG_PD_CLK BIT(3) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CLK_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_PD_CLK, x) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CLK_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_PD_CLK, x) + +#define SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER BIT(4) +#define SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, x) +#define SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, x) + +#define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN BIT(5) +#define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0, x) +#define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0, x) + +#define SD25G_LANE_LANE_05_LN_CFG_BW_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_05_LN_CFG_BW_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_05_LN_CFG_BW_1_0, x) +#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) + +#define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN BIT(0) +#define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_06_LN_CFG_EN_MAIN, x) +#define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_06_LN_CFG_EN_MAIN, x) + +#define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0 GENMASK(7, 4) +#define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, x) +#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) + +#define SD25G_LANE_LANE_07_LN_CFG_EN_ADV BIT(0) +#define SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_07_LN_CFG_EN_ADV, x) +#define SD25G_LANE_LANE_07_LN_CFG_EN_ADV_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_ADV, x) + +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY2 BIT(1) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY2_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_07_LN_CFG_EN_DLY2, x) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY2_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_DLY2, x) + +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY BIT(2) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_07_LN_CFG_EN_DLY, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, x) +#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) + +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN BIT(0) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, x) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, x) + +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST BIT(1) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST, x) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST, x) + +#define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, x) +#define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, x) + +#define SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN BIT(4) +#define SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN, x) +#define SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN, x) + +#define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD BIT(5) +#define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, x) +#define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8 BIT(4) +#define SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8, x) +#define SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN BIT(5) +#define SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN, x) +#define SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD BIT(6) +#define SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD, x) +#define SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN BIT(7) +#define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN, x) +#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) + +#define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN BIT(0) +#define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN, x) +#define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN, x) + +#define SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD BIT(1) +#define SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD, x) +#define SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD, x) + +#define SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG BIT(2) +#define SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, x) +#define SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, x) + +#define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, x) +#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) + +#define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN BIT(0) +#define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, x) +#define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, x) + +#define SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT BIT(1) +#define SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT, x) +#define SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT, x) + +#define SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN BIT(2) +#define SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN, x) +#define SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN, x) + +#define SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD BIT(3) +#define SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, x) +#define SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, x) + +#define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, x) +#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) + +#define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD BIT(0) +#define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_DCDR_PD, x) +#define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_DCDR_PD, x) + +#define SD25G_LANE_LANE_19_LN_CFG_ECDR_PD BIT(1) +#define SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, x) +#define SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, x) + +#define SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL BIT(2) +#define SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL, x) +#define SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL, x) + +#define SD25G_LANE_LANE_19_LN_CFG_TXLB_EN BIT(3) +#define SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, x) +#define SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, x) + +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU BIT(4) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU, x) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU, x) + +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP BIT(5) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP, x) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP, x) + +#define SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET BIT(6) +#define SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET, x) +#define SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET, x) + +#define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE BIT(7) +#define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_PD_CTLE, x) +#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) + +#define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN BIT(0) +#define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN, x) +#define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN, x) + +#define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, x) +#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) + +#define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN BIT(0) +#define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, x) +#define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, x) + +#define SD25G_LANE_LANE_1C_LN_CFG_DFE_PD BIT(1) +#define SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, x) +#define SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, x) + +#define SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD BIT(2) +#define SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD, x) +#define SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD, x) + +#define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0 GENMASK(7, 4) +#define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0, x) +#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) + +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR BIT(0) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR, x) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD BIT(1) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD, x) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN BIT(2) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN, x) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP BIT(3) +#define SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP, x) +#define SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PHID_1T BIT(4) +#define SD25G_LANE_LANE_1D_LN_CFG_PHID_1T_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PHID_1T, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PHID_1T_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PHID_1T, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN BIT(5) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR BIT(6) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD BIT(7) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0, x) +#define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN BIT(4) +#define SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, x) +#define SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN BIT(5) +#define SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, x) +#define SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR BIT(6) +#define SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR, x) +#define SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD BIT(7) +#define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, x) +#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) + +#define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN BIT(0) +#define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN, x) +#define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN, x) + +#define SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH BIT(1) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH, x) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH, x) + +#define SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL BIT(2) +#define SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL, x) +#define SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL, x) + +#define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, x) +#define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, x) + +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR BIT(4) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR, x) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR, x) + +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU BIT(5) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, x) +#define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, x) + +#define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER BIT(4) +#define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, x) +#define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, x) + +#define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0, x) +#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) + +#define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN BIT(0) +#define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN, x) +#define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ BIT(1) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, x) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_PD_SQ BIT(2) +#define SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, x) +#define SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS BIT(3) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS, x) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC BIT(4) +#define SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC, x) +#define SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG BIT(5) +#define SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, x) +#define SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN BIT(6) +#define SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN, x) +#define SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN BIT(7) +#define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, x) +#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) + +#define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE BIT(0) +#define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE, x) +#define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE, x) + +#define SD25G_LANE_LANE_40_LN_R_TX_POL_INV BIT(1) +#define SD25G_LANE_LANE_40_LN_R_TX_POL_INV_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_TX_POL_INV, x) +#define SD25G_LANE_LANE_40_LN_R_TX_POL_INV_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_TX_POL_INV, x) + +#define SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE BIT(2) +#define SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE, x) +#define SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE, x) + +#define SD25G_LANE_LANE_40_LN_R_RX_POL_INV BIT(3) +#define SD25G_LANE_LANE_40_LN_R_RX_POL_INV_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_RX_POL_INV, x) +#define SD25G_LANE_LANE_40_LN_R_RX_POL_INV_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_RX_POL_INV, x) + +#define SD25G_LANE_LANE_40_LN_R_CDR_RSTN BIT(4) +#define SD25G_LANE_LANE_40_LN_R_CDR_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_CDR_RSTN, x) +#define SD25G_LANE_LANE_40_LN_R_CDR_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_CDR_RSTN, x) + +#define SD25G_LANE_LANE_40_LN_R_DFE_RSTN BIT(5) +#define SD25G_LANE_LANE_40_LN_R_DFE_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_DFE_RSTN, x) +#define SD25G_LANE_LANE_40_LN_R_DFE_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_DFE_RSTN, x) + +#define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN BIT(6) +#define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_CTLE_RSTN, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, x) +#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) + +#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)\ + FIELD_PREP(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, x) +#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) + +#define SD25G_LANE_LANE_DE_LN_LOL_UDL BIT(0) +#define SD25G_LANE_LANE_DE_LN_LOL_UDL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_LOL_UDL, x) +#define SD25G_LANE_LANE_DE_LN_LOL_UDL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_LOL_UDL, x) + +#define SD25G_LANE_LANE_DE_LN_LOL BIT(1) +#define SD25G_LANE_LANE_DE_LN_LOL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_LOL, x) +#define SD25G_LANE_LANE_DE_LN_LOL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_LOL, x) + +#define SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED BIT(2) +#define SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED, x) +#define SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED, x) + +#define SD25G_LANE_LANE_DE_LN_PMA_RXEI BIT(3) +#define SD25G_LANE_LANE_DE_LN_PMA_RXEI_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_PMA_RXEI, x) +#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) + +#define SD6G_LANE_LANE_DF_LOL_UDL BIT(0) +#define SD6G_LANE_LANE_DF_LOL_UDL_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_LOL_UDL, x) +#define SD6G_LANE_LANE_DF_LOL_UDL_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_LOL_UDL, x) + +#define SD6G_LANE_LANE_DF_LOL BIT(1) +#define SD6G_LANE_LANE_DF_LOL_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_LOL, x) +#define SD6G_LANE_LANE_DF_LOL_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_LOL, x) + +#define SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED BIT(2) +#define SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) +#define SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) + +#define SD6G_LANE_LANE_DF_SQUELCH BIT(3) +#define SD6G_LANE_LANE_DF_SQUELCH_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_SQUELCH, x) +#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) + +#define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE BIT(0) +#define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_R_HWT_SIMULATION_MODE, x) +#define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_R_HWT_SIMULATION_MODE, x) + +#define SD_CMU_CMU_00_CFG_PLL_LOL_SET BIT(1) +#define SD_CMU_CMU_00_CFG_PLL_LOL_SET_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_CFG_PLL_LOL_SET, x) +#define SD_CMU_CMU_00_CFG_PLL_LOL_SET_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_CFG_PLL_LOL_SET, x) + +#define SD_CMU_CMU_00_CFG_PLL_LOS_SET BIT(2) +#define SD_CMU_CMU_00_CFG_PLL_LOS_SET_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_CFG_PLL_LOS_SET, x) +#define SD_CMU_CMU_00_CFG_PLL_LOS_SET_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_CFG_PLL_LOS_SET, x) + +#define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0 GENMASK(5, 4) +#define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, x) +#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) + +#define SD_CMU_CMU_05_CFG_REFCK_TERM_EN BIT(0) +#define SD_CMU_CMU_05_CFG_REFCK_TERM_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_05_CFG_REFCK_TERM_EN, x) +#define SD_CMU_CMU_05_CFG_REFCK_TERM_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_05_CFG_REFCK_TERM_EN, x) + +#define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0 GENMASK(5, 4) +#define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x) +#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_09 */ +#define SD_CMU_CMU_09(t) __REG(TARGET_SD_CMU, t, 14, 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)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_EN_TX_CK_UP, x) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_UP_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_EN_TX_CK_UP, x) + +#define SD_CMU_CMU_09_CFG_EN_TX_CK_DN BIT(1) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_DN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_EN_TX_CK_DN, x) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_DN_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_EN_TX_CK_DN, x) + +#define SD_CMU_CMU_09_CFG_SW_8G BIT(4) +#define SD_CMU_CMU_09_CFG_SW_8G_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_SW_8G, x) +#define SD_CMU_CMU_09_CFG_SW_8G_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_SW_8G, x) + +#define SD_CMU_CMU_09_CFG_SW_10G BIT(5) +#define SD_CMU_CMU_09_CFG_SW_10G_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_SW_10G, x) +#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) + +#define SD_CMU_CMU_0D_CFG_PD_DIV64 BIT(0) +#define SD_CMU_CMU_0D_CFG_PD_DIV64_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_PD_DIV64, x) +#define SD_CMU_CMU_0D_CFG_PD_DIV64_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_PD_DIV64, x) + +#define SD_CMU_CMU_0D_CFG_PD_DIV66 BIT(1) +#define SD_CMU_CMU_0D_CFG_PD_DIV66_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_PD_DIV66, x) +#define SD_CMU_CMU_0D_CFG_PD_DIV66_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_PD_DIV66, x) + +#define SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD BIT(2) +#define SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD, x) +#define SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD, x) + +#define SD_CMU_CMU_0D_CFG_JC_BYP BIT(3) +#define SD_CMU_CMU_0D_CFG_JC_BYP_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_JC_BYP, x) +#define SD_CMU_CMU_0D_CFG_JC_BYP_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_JC_BYP, x) + +#define SD_CMU_CMU_0D_CFG_REFCK_PD BIT(4) +#define SD_CMU_CMU_0D_CFG_REFCK_PD_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_REFCK_PD, x) +#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) + +#define SD_CMU_CMU_1B_CFG_RESERVE_7_0 GENMASK(7, 0) +#define SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1B_CFG_RESERVE_7_0, x) +#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) + +#define SD_CMU_CMU_1F_CFG_BIAS_DN_EN BIT(0) +#define SD_CMU_CMU_1F_CFG_BIAS_DN_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_BIAS_DN_EN, x) +#define SD_CMU_CMU_1F_CFG_BIAS_DN_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_BIAS_DN_EN, x) + +#define SD_CMU_CMU_1F_CFG_BIAS_UP_EN BIT(1) +#define SD_CMU_CMU_1F_CFG_BIAS_UP_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_BIAS_UP_EN, x) +#define SD_CMU_CMU_1F_CFG_BIAS_UP_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_BIAS_UP_EN, x) + +#define SD_CMU_CMU_1F_CFG_IC2IP_N BIT(2) +#define SD_CMU_CMU_1F_CFG_IC2IP_N_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_IC2IP_N, x) +#define SD_CMU_CMU_1F_CFG_IC2IP_N_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_IC2IP_N, x) + +#define SD_CMU_CMU_1F_CFG_VTUNE_SEL BIT(3) +#define SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_VTUNE_SEL, x) +#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) + +#define SD_CMU_CMU_30_R_PLL_DLOL_EN BIT(0) +#define SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_30_R_PLL_DLOL_EN, x) +#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) + +#define SD_CMU_CMU_44_R_PLL_RSTN BIT(0) +#define SD_CMU_CMU_44_R_PLL_RSTN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_44_R_PLL_RSTN, x) +#define SD_CMU_CMU_44_R_PLL_RSTN_GET(x)\ + FIELD_GET(SD_CMU_CMU_44_R_PLL_RSTN, x) + +#define SD_CMU_CMU_44_R_CK_RESETB BIT(1) +#define SD_CMU_CMU_44_R_CK_RESETB_SET(x)\ + FIELD_PREP(SD_CMU_CMU_44_R_CK_RESETB, x) +#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) + +#define SD_CMU_CMU_45_R_EN_RATECHG_CTRL BIT(0) +#define SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_EN_RATECHG_CTRL, x) +#define SD_CMU_CMU_45_R_EN_RATECHG_CTRL_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_EN_RATECHG_CTRL, x) + +#define SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT BIT(1) +#define SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT, x) +#define SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT, x) + +#define SD_CMU_CMU_45_RESERVED BIT(2) +#define SD_CMU_CMU_45_RESERVED_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_RESERVED, x) +#define SD_CMU_CMU_45_RESERVED_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_RESERVED, x) + +#define SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT BIT(3) +#define SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT, x) +#define SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT, x) + +#define SD_CMU_CMU_45_RESERVED_2 BIT(4) +#define SD_CMU_CMU_45_RESERVED_2_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_RESERVED_2, x) +#define SD_CMU_CMU_45_RESERVED_2_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_RESERVED_2, x) + +#define SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT BIT(5) +#define SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT, x) +#define SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT, x) + +#define SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT BIT(6) +#define SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT, x) +#define SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT, x) + +#define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN BIT(7) +#define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN, x) +#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) + +#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)\ + FIELD_PREP(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, x) +#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) + +#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)\ + FIELD_PREP(SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0, x) +#define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0_GET(x)\ + FIELD_GET(SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0, x) + +#define SD_CMU_CMU_E0_PLL_LOL_UDL BIT(4) +#define SD_CMU_CMU_E0_PLL_LOL_UDL_SET(x)\ + FIELD_PREP(SD_CMU_CMU_E0_PLL_LOL_UDL, x) +#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) + +#define SD_CMU_CFG_SD_CMU_CFG_CMU_RST BIT(0) +#define SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(x)\ + FIELD_PREP(SD_CMU_CFG_SD_CMU_CFG_CMU_RST, x) +#define SD_CMU_CFG_SD_CMU_CFG_CMU_RST_GET(x)\ + FIELD_GET(SD_CMU_CFG_SD_CMU_CFG_CMU_RST, x) + +#define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST BIT(1) +#define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(x)\ + FIELD_PREP(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, x) +#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) + +#define SD_LANE_SD_SER_RST_SER_RST BIT(0) +#define SD_LANE_SD_SER_RST_SER_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_SER_RST_SER_RST, x) +#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) + +#define SD_LANE_SD_DES_RST_DES_RST BIT(0) +#define SD_LANE_SD_DES_RST_DES_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_DES_RST_DES_RST, x) +#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) + +#define SD_LANE_SD_LANE_CFG_MACRO_RST BIT(0) +#define SD_LANE_SD_LANE_CFG_MACRO_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_MACRO_RST, x) +#define SD_LANE_SD_LANE_CFG_MACRO_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_MACRO_RST, x) + +#define SD_LANE_SD_LANE_CFG_EXT_CFG_RST BIT(1) +#define SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_EXT_CFG_RST, x) +#define SD_LANE_SD_LANE_CFG_EXT_CFG_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_EXT_CFG_RST, x) + +#define SD_LANE_SD_LANE_CFG_TX_REF_SEL GENMASK(5, 4) +#define SD_LANE_SD_LANE_CFG_TX_REF_SEL_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_TX_REF_SEL, x) +#define SD_LANE_SD_LANE_CFG_TX_REF_SEL_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_TX_REF_SEL, x) + +#define SD_LANE_SD_LANE_CFG_RX_REF_SEL GENMASK(7, 6) +#define SD_LANE_SD_LANE_CFG_RX_REF_SEL_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_RX_REF_SEL, x) +#define SD_LANE_SD_LANE_CFG_RX_REF_SEL_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_RX_REF_SEL, x) + +#define SD_LANE_SD_LANE_CFG_LANE_RST BIT(8) +#define SD_LANE_SD_LANE_CFG_LANE_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_LANE_RST, x) +#define SD_LANE_SD_LANE_CFG_LANE_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_RST, x) + +#define SD_LANE_SD_LANE_CFG_LANE_TX_RST BIT(9) +#define SD_LANE_SD_LANE_CFG_LANE_TX_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_LANE_TX_RST, x) +#define SD_LANE_SD_LANE_CFG_LANE_TX_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_TX_RST, x) + +#define SD_LANE_SD_LANE_CFG_LANE_RX_RST BIT(10) +#define SD_LANE_SD_LANE_CFG_LANE_RX_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_LANE_RX_RST, x) +#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) + +#define SD_LANE_SD_LANE_STAT_PMA_RST_DONE BIT(0) +#define SD_LANE_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_STAT_PMA_RST_DONE, x) +#define SD_LANE_SD_LANE_STAT_PMA_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_STAT_PMA_RST_DONE, x) + +#define SD_LANE_SD_LANE_STAT_DFE_RST_DONE BIT(1) +#define SD_LANE_SD_LANE_STAT_DFE_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_STAT_DFE_RST_DONE, x) +#define SD_LANE_SD_LANE_STAT_DFE_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_STAT_DFE_RST_DONE, x) + +#define SD_LANE_SD_LANE_STAT_DBG_OBS GENMASK(31, 16) +#define SD_LANE_SD_LANE_STAT_DBG_OBS_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_STAT_DBG_OBS, x) +#define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_STAT_DBG_OBS, 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) + +#define SD_LANE_MISC_SD_125_RST_DIS BIT(0) +#define SD_LANE_MISC_SD_125_RST_DIS_SET(x)\ + FIELD_PREP(SD_LANE_MISC_SD_125_RST_DIS, x) +#define SD_LANE_MISC_SD_125_RST_DIS_GET(x)\ + FIELD_GET(SD_LANE_MISC_SD_125_RST_DIS, x) + +#define SD_LANE_MISC_RX_ENA BIT(1) +#define SD_LANE_MISC_RX_ENA_SET(x)\ + FIELD_PREP(SD_LANE_MISC_RX_ENA, x) +#define SD_LANE_MISC_RX_ENA_GET(x)\ + FIELD_GET(SD_LANE_MISC_RX_ENA, x) + +#define SD_LANE_MISC_MUX_ENA BIT(2) +#define SD_LANE_MISC_MUX_ENA_SET(x)\ + FIELD_PREP(SD_LANE_MISC_MUX_ENA, x) +#define SD_LANE_MISC_MUX_ENA_GET(x)\ + FIELD_GET(SD_LANE_MISC_MUX_ENA, x) + +#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) + +#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)\ + FIELD_PREP(SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM, x) +#define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM_GET(x)\ + FIELD_GET(SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM, x) + +#define SD_LANE_M_STAT_MISC_M_LOCK_CNT GENMASK(31, 24) +#define SD_LANE_M_STAT_MISC_M_LOCK_CNT_SET(x)\ + FIELD_PREP(SD_LANE_M_STAT_MISC_M_LOCK_CNT, x) +#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) + +#define SD_LANE_25G_SD_SER_RST_SER_RST BIT(0) +#define SD_LANE_25G_SD_SER_RST_SER_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_SER_RST_SER_RST, x) +#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) + +#define SD_LANE_25G_SD_DES_RST_DES_RST BIT(0) +#define SD_LANE_25G_SD_DES_RST_DES_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_DES_RST_DES_RST, x) +#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) + +#define SD_LANE_25G_SD_LANE_CFG_MACRO_RST BIT(0) +#define SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_MACRO_RST, x) +#define SD_LANE_25G_SD_LANE_CFG_MACRO_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_MACRO_RST, x) + +#define SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST BIT(1) +#define SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, x) +#define SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, x) + +#define SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE BIT(4) +#define SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE, x) +#define SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE GENMASK(7, 5) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE, x) + +#define SD_LANE_25G_SD_LANE_CFG_LANE_RST BIT(8) +#define SD_LANE_25G_SD_LANE_CFG_LANE_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_LANE_RST, x) +#define SD_LANE_25G_SD_LANE_CFG_LANE_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_LANE_RST, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV BIT(9) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN BIT(10) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY BIT(11) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV GENMASK(15, 12) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN BIT(16) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY GENMASK(21, 17) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN BIT(22) +#define SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN BIT(23) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING BIT(24) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI BIT(25) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN GENMASK(28, 26) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN, x) +#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) + +#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)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL GENMASK(5, 3) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL GENMASK(8, 6) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED GENMASK(10, 9) +#define SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED, x) +#define SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED, x) + +#define SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV GENMASK(13, 11) +#define SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV, x) +#define SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV, x) + +#define SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV GENMASK(16, 14) +#define SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV, x) +#define SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV, x) + +#define SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL GENMASK(19, 17) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV GENMASK(23, 20) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV, x) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV, x) + +#define SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL GENMASK(25, 24) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL GENMASK(28, 26) +#define SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL GENMASK(31, 29) +#define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL, x) +#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) + +#define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE BIT(0) +#define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE, x) +#define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE, x) + +#define SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE BIT(1) +#define SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE, x) +#define SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE, x) + +#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS GENMASK(31, 16) +#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) +#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) + +#endif /* _SPARX5_SERDES_REGS_H_ */ diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 71cb1082632626646014fdb060c70b6d20f2f72b..ccb575b137778151feae9c51c7c18b353c85c2e8 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -373,6 +373,36 @@ int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) } EXPORT_SYMBOL_GPL(phy_set_mode_ext); +int phy_set_media(struct phy *phy, enum phy_media media) +{ + int ret; + + if (!phy || !phy->ops->set_media) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->set_media(phy, media); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_media); + +int phy_set_speed(struct phy *phy, int speed) +{ + int ret; + + if (!phy || !phy->ops->set_speed) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->set_speed(phy, speed); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_speed); + int phy_reset(struct phy *phy) { int ret; diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c index 9061ece7ff6ab1e42aee9ee13528ee3dabf35a2c..bfff0c8c9130389e4c472d22a978548aaf7672f3 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c @@ -276,8 +276,8 @@ static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy) val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP | HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN | HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP | - HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID | - HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70; + HSUSB_CTRL_UTMI_OTG_VBUS_VALID | HSUSB_CTRL_UTMI_CLK_EN | + HSUSB_CTRL_CLAMP_EN | 0x70; /* use core clock if external reference is not present */ if (!phy_dwc3->xo_clk) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 9cdebe7f26cb1d3a66134e2065e32979c7dc30f9..7877f70cf86fa09811307a6433eb0ad50db32e33 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -1840,6 +1840,86 @@ static const struct qmp_phy_init_tbl sm8250_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), }; +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORE_CLK_EN, 0x1f), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_rbr[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x6f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr2[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x8c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr3[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x2a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_INTERFACE_SELECT, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TRAN_DRVR_EMP_EN, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_BAND, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_POL_INV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_DRV_LVL, 0x2a), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_EMP_POST1_LVL, 0x20), +}; + 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), @@ -2268,6 +2348,8 @@ static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), }; +struct qmp_phy; + /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { /* phy-type - PCIE/UFS/USB */ @@ -2307,6 +2389,12 @@ struct qmp_phy_cfg { const struct qmp_phy_init_tbl *serdes_tbl_hbr3; int serdes_tbl_hbr3_num; + /* DP PHY callbacks */ + int (*configure_dp_phy)(struct qmp_phy *qphy); + void (*configure_dp_tx)(struct qmp_phy *qphy); + int (*calibrate_dp_phy)(struct qmp_phy *qphy); + void (*dp_aux_init)(struct qmp_phy *qphy); + /* clock ids to be requested */ const char * const *clk_list; int num_clks; @@ -2423,6 +2511,16 @@ struct qcom_qmp { struct reset_control *ufs_reset; }; +static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy); +static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy); +static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy); +static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy); + +static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy); +static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy); +static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy); +static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy); + static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -2871,6 +2969,11 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = { .has_phy_dp_com_ctrl = true, .is_dual_lane_phy = true, + + .dp_aux_init = qcom_qmp_v3_phy_dp_aux_init, + .configure_dp_tx = qcom_qmp_v3_phy_configure_dp_tx, + .configure_dp_phy = qcom_qmp_v3_phy_configure_dp_phy, + .calibrate_dp_phy = qcom_qmp_v3_dp_phy_calibrate, }; static const struct qmp_phy_combo_cfg sc7180_usb3dpphy_cfg = { @@ -3123,6 +3226,46 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, }; +static const struct qmp_phy_cfg sm8250_dpphy_cfg = { + .type = PHY_TYPE_DP, + .nlanes = 1, + + .serdes_tbl = qmp_v4_dp_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl), + .tx_tbl = qmp_v4_dp_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v4_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), + + .clk_list = qmp_v4_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + + .has_phy_dp_com_ctrl = true, + .is_dual_lane_phy = true, + + .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init, + .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx, + .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy, + .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate, +}; + +static const struct qmp_phy_combo_cfg sm8250_usb3dpphy_cfg = { + .usb_cfg = &sm8250_usb3phy_cfg, + .dp_cfg = &sm8250_dpphy_cfg, +}; + static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { .type = PHY_TYPE_USB3, .nlanes = 1, @@ -3332,24 +3475,24 @@ static int qcom_qmp_phy_serdes_init(struct qmp_phy *qphy) return 0; } -static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy) +static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy) { 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, - qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + qphy->pcs + QSERDES_DP_PHY_PD_CTL); /* Turn on BIAS current for PHY/PLL */ writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL, qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); - writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL); writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, - qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + qphy->pcs + QSERDES_DP_PHY_PD_CTL); writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_R_EN | @@ -3357,16 +3500,16 @@ static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy) QSERDES_V3_COM_CLKBUF_RX_DRIVE_L, qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); - writel(0x00, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG0); - writel(0x13, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG1); - writel(0x24, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG2); - writel(0x00, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG3); - writel(0x0a, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG4); - writel(0x26, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG5); - writel(0x0a, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG6); - writel(0x03, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG7); - writel(0xbb, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG8); - writel(0x03, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG9); + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0); + writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + writel(0x24, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4); + writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7); + writel(0xbb, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9); qphy->dp_aux_cfg = 0; writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | @@ -3375,6 +3518,20 @@ static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy) qphy->pcs + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK); } +static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = { + { 0x00, 0x0c, 0x15, 0x1a }, + { 0x02, 0x0e, 0x16, 0xff }, + { 0x02, 0x11, 0xff, 0xff }, + { 0x04, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v3_voltage_swing_hbr3_hbr2[4][4] = { + { 0x02, 0x12, 0x16, 0x1a }, + { 0x09, 0x19, 0x1f, 0xff }, + { 0x10, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + static const u8 qmp_dp_v3_pre_emphasis_hbr_rbr[4][4] = { { 0x00, 0x0c, 0x14, 0x19 }, { 0x00, 0x0b, 0x12, 0xff }, @@ -3389,11 +3546,11 @@ static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = { { 0x1f, 0xff, 0xff, 0xff } }; -static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy) +static int qcom_qmp_phy_configure_dp_swing(struct qmp_phy *qphy, + unsigned int drv_lvl_reg, unsigned int emp_post_reg) { const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; unsigned int v_level = 0, p_level = 0; - u32 bias_en, drvr_en; u8 voltage_swing_cfg, pre_emphasis_cfg; int i; @@ -3402,56 +3559,58 @@ static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy) p_level = max(p_level, dp_opts->pre[i]); } - if (dp_opts->lanes == 1) { - bias_en = 0x3e; - drvr_en = 0x13; + if (dp_opts->link_rate <= 2700) { + voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level]; + pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level]; } else { - bias_en = 0x3f; - drvr_en = 0x10; + voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr3_hbr2[v_level][p_level]; + pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr3_hbr2[v_level][p_level]; } - voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level]; - pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level]; - /* TODO: Move check to config check */ if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF) - return; + return -EINVAL; /* Enable MUX to use Cursor values from these registers */ voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN; pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN; - writel(voltage_swing_cfg, qphy->tx + QSERDES_V3_TX_TX_DRV_LVL); - writel(pre_emphasis_cfg, qphy->tx + QSERDES_V3_TX_TX_EMP_POST1_LVL); - writel(voltage_swing_cfg, qphy->tx2 + QSERDES_V3_TX_TX_DRV_LVL); - writel(pre_emphasis_cfg, qphy->tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL); + writel(voltage_swing_cfg, qphy->tx + drv_lvl_reg); + writel(pre_emphasis_cfg, qphy->tx + emp_post_reg); + writel(voltage_swing_cfg, qphy->tx2 + drv_lvl_reg); + writel(pre_emphasis_cfg, qphy->tx2 + emp_post_reg); - writel(drvr_en, qphy->tx + QSERDES_V3_TX_HIGHZ_DRVR_EN); - writel(bias_en, qphy->tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); - writel(drvr_en, qphy->tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN); - writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); + return 0; } -static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) +static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) { - const struct phy_configure_opts_dp *dp_opts = &opts->dp; - struct qmp_phy *qphy = phy_get_drvdata(phy); + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 bias_en, drvr_en; - memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts)); - if (qphy->dp_opts.set_voltages) { - qcom_qmp_phy_configure_dp_tx(qphy); - qphy->dp_opts.set_voltages = 0; + if (qcom_qmp_phy_configure_dp_swing(qphy, + QSERDES_V3_TX_TX_DRV_LVL, + QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0) + return; + + if (dp_opts->lanes == 1) { + bias_en = 0x3e; + drvr_en = 0x13; + } else { + bias_en = 0x3f; + drvr_en = 0x10; } - return 0; + writel(drvr_en, qphy->tx + QSERDES_V3_TX_HIGHZ_DRVR_EN); + writel(bias_en, qphy->tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); + writel(drvr_en, qphy->tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN); + writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); } -static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) +static bool qcom_qmp_phy_configure_dp_mode(struct qmp_phy *qphy) { - const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; - const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; - u32 val, phy_vco_div, status; - unsigned long pixel_freq; + u32 val; + bool reverse = false; val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN; @@ -3471,9 +3630,22 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) * writel(0x4c, qphy->pcs + QSERDES_V3_DP_PHY_MODE); */ val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN; - writel(val, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + writel(val, qphy->pcs + QSERDES_DP_PHY_PD_CTL); + + writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE); + + return reverse; +} + +static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) +{ + const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 phy_vco_div, status; + unsigned long pixel_freq; + + qcom_qmp_phy_configure_dp_mode(qphy); - writel(0x5c, qphy->pcs + QSERDES_V3_DP_PHY_MODE); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); @@ -3503,11 +3675,11 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000); clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq); - writel(0x04, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG2); - writel(0x01, qphy->pcs + QSERDES_V3_DP_PHY_CFG); - writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_CFG); - writel(0x01, qphy->pcs + QSERDES_V3_DP_PHY_CFG); - writel(0x09, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x04, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG); writel(0x20, qphy->serdes + QSERDES_V3_COM_RESETSM_CNTRL); @@ -3518,7 +3690,7 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) 10000)) return -ETIMEDOUT; - writel(0x19, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); if (readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS, status, @@ -3527,9 +3699,9 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) 10000)) return -ETIMEDOUT; - writel(0x18, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG); udelay(2000); - writel(0x19, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); return readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS, status, @@ -3542,9 +3714,8 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) * We need to calibrate the aux setting here as many times * as the caller tries */ -static int qcom_qmp_dp_phy_calibrate(struct phy *phy) +static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy) { - struct qmp_phy *qphy = phy_get_drvdata(phy); static const u8 cfg1_settings[] = { 0x13, 0x23, 0x1d }; u8 val; @@ -3552,7 +3723,231 @@ static int qcom_qmp_dp_phy_calibrate(struct phy *phy) qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); val = cfg1_settings[qphy->dp_aux_cfg]; - writel(val, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG1); + writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + + return 0; +} + +static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy) +{ + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + qphy->pcs + QSERDES_DP_PHY_PD_CTL); + + /* Turn on BIAS current for PHY/PLL */ + writel(0x17, qphy->serdes + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); + + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0); + writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4); + writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7); + writel(0xb7, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9); + qphy->dp_aux_cfg = 0; + + writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | + PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | + PHY_AUX_REQ_ERR_MASK, + qphy->pcs + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK); +} + +static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy) +{ + /* Program default values before writing proper values */ + writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL); + + writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + + qcom_qmp_phy_configure_dp_swing(qphy, + QSERDES_V4_TX_TX_DRV_LVL, + QSERDES_V4_TX_TX_EMP_POST1_LVL); +} + +static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy) +{ + const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 phy_vco_div, status; + unsigned long pixel_freq; + u32 bias0_en, drvr0_en, bias1_en, drvr1_en; + bool reverse; + + writel(0x0f, qphy->pcs + QSERDES_V4_DP_PHY_CFG_1); + + reverse = qcom_qmp_phy_configure_dp_mode(qphy); + + writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + + writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL); + writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL); + + switch (dp_opts->link_rate) { + case 1620: + phy_vco_div = 0x1; + pixel_freq = 1620000000UL / 2; + break; + case 2700: + phy_vco_div = 0x1; + pixel_freq = 2700000000UL / 2; + break; + case 5400: + phy_vco_div = 0x2; + pixel_freq = 5400000000UL / 4; + break; + case 8100: + phy_vco_div = 0x0; + pixel_freq = 8100000000UL / 6; + break; + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + writel(phy_vco_div, qphy->pcs + QSERDES_V4_DP_PHY_VCO_DIV); + + clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000); + clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq); + + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG); + + writel(0x20, qphy->serdes + QSERDES_V4_COM_RESETSM_CNTRL); + + if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_C_READY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + /* + * At least for 7nm DP PHY this has to be done after enabling link + * clock. + */ + + if (dp_opts->lanes == 1) { + bias0_en = reverse ? 0x3e : 0x15; + bias1_en = reverse ? 0x15 : 0x3e; + drvr0_en = reverse ? 0x13 : 0x10; + drvr1_en = reverse ? 0x10 : 0x13; + } else if (dp_opts->lanes == 2) { + bias0_en = reverse ? 0x3f : 0x15; + bias1_en = reverse ? 0x15 : 0x3f; + drvr0_en = 0x10; + drvr1_en = 0x10; + } else { + bias0_en = 0x3f; + bias1_en = 0x3f; + drvr0_en = 0x10; + drvr1_en = 0x10; + } + + writel(drvr0_en, qphy->tx + QSERDES_V4_TX_HIGHZ_DRVR_EN); + writel(bias0_en, qphy->tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); + writel(drvr1_en, qphy->tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN); + writel(bias1_en, qphy->tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); + + writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG); + udelay(2000); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + writel(0x0a, qphy->tx + QSERDES_V4_TX_TX_POL_INV); + writel(0x0a, qphy->tx2 + QSERDES_V4_TX_TX_POL_INV); + + writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL); + + writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + + return 0; +} + +/* + * We need to calibrate the aux setting here as many times + * as the caller tries + */ +static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy) +{ + static const u8 cfg1_settings[] = { 0x20, 0x13, 0x23, 0x1d }; + u8 val; + + qphy->dp_aux_cfg++; + qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); + val = cfg1_settings[qphy->dp_aux_cfg]; + + writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + + return 0; +} + +static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + const struct phy_configure_opts_dp *dp_opts = &opts->dp; + struct qmp_phy *qphy = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qphy->cfg; + + memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts)); + if (qphy->dp_opts.set_voltages) { + cfg->configure_dp_tx(qphy); + qphy->dp_opts.set_voltages = 0; + } + + return 0; +} + +static int qcom_qmp_dp_phy_calibrate(struct phy *phy) +{ + struct qmp_phy *qphy = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qphy->cfg; + + if (cfg->calibrate_dp_phy) + return cfg->calibrate_dp_phy(qphy); return 0; } @@ -3729,7 +4124,7 @@ static int qcom_qmp_phy_init(struct phy *phy) return ret; if (cfg->type == PHY_TYPE_DP) - qcom_qmp_phy_dp_aux_init(qphy); + cfg->dp_aux_init(qphy); return 0; } @@ -3783,7 +4178,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy) /* Configure special DP tx tunings */ if (cfg->type == PHY_TYPE_DP) - qcom_qmp_phy_configure_dp_tx(qphy); + cfg->configure_dp_tx(qphy); qcom_qmp_phy_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); @@ -3802,7 +4197,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy) /* Configure link rate, swing, etc. */ if (cfg->type == PHY_TYPE_DP) { - qcom_qmp_phy_configure_dp_phy(qphy); + cfg->configure_dp_phy(qphy); } else { qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (cfg->pcs_tbl_sec) @@ -3874,7 +4269,7 @@ static int qcom_qmp_phy_power_off(struct phy *phy) if (cfg->type == PHY_TYPE_DP) { /* Assert DP PHY power down */ - writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL); } else { /* PHY reset */ if (!cfg->no_pcs_sw_reset) @@ -4577,6 +4972,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,sm8250-qmp-usb3-phy", .data = &sm8250_usb3phy_cfg, + }, { + .compatible = "qcom,sm8250-qmp-usb3-dp-phy", + /* It's a combo phy */ }, { .compatible = "qcom,sm8250-qmp-usb3-uni-phy", .data = &sm8250_usb3_uniphy_cfg, @@ -4611,6 +5009,10 @@ static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = { .compatible = "qcom,sc7180-qmp-usb3-dp-phy", .data = &sc7180_usb3dpphy_cfg, }, + { + .compatible = "qcom,sm8250-qmp-usb3-dp-phy", + .data = &sm8250_usb3dpphy_cfg, + }, { } }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 71ce3aa174ae69fba4dc24ea9eb05cca004083fd..67bd2dd0d8c594d8ff23e2a73507e72ea1aa44e8 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -349,13 +349,13 @@ #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4 0x5c #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5 0x60 -/* Only for QMP V3 PHY - DP PHY registers */ -#define QSERDES_V3_DP_PHY_REVISION_ID0 0x000 -#define QSERDES_V3_DP_PHY_REVISION_ID1 0x004 -#define QSERDES_V3_DP_PHY_REVISION_ID2 0x008 -#define QSERDES_V3_DP_PHY_REVISION_ID3 0x00c -#define QSERDES_V3_DP_PHY_CFG 0x010 -#define QSERDES_V3_DP_PHY_PD_CTL 0x018 +/* QMP PHY - DP PHY registers */ +#define QSERDES_DP_PHY_REVISION_ID0 0x000 +#define QSERDES_DP_PHY_REVISION_ID1 0x004 +#define QSERDES_DP_PHY_REVISION_ID2 0x008 +#define QSERDES_DP_PHY_REVISION_ID3 0x00c +#define QSERDES_DP_PHY_CFG 0x010 +#define QSERDES_DP_PHY_PD_CTL 0x018 # define DP_PHY_PD_CTL_PWRDN 0x001 # define DP_PHY_PD_CTL_PSR_PWRDN 0x002 # define DP_PHY_PD_CTL_AUX_PWRDN 0x004 @@ -363,18 +363,19 @@ # define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 # define DP_PHY_PD_CTL_PLL_PWRDN 0x020 # define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 -#define QSERDES_V3_DP_PHY_MODE 0x01c -#define QSERDES_V3_DP_PHY_AUX_CFG0 0x020 -#define QSERDES_V3_DP_PHY_AUX_CFG1 0x024 -#define QSERDES_V3_DP_PHY_AUX_CFG2 0x028 -#define QSERDES_V3_DP_PHY_AUX_CFG3 0x02c -#define QSERDES_V3_DP_PHY_AUX_CFG4 0x030 -#define QSERDES_V3_DP_PHY_AUX_CFG5 0x034 -#define QSERDES_V3_DP_PHY_AUX_CFG6 0x038 -#define QSERDES_V3_DP_PHY_AUX_CFG7 0x03c -#define QSERDES_V3_DP_PHY_AUX_CFG8 0x040 -#define QSERDES_V3_DP_PHY_AUX_CFG9 0x044 +#define QSERDES_DP_PHY_MODE 0x01c +#define QSERDES_DP_PHY_AUX_CFG0 0x020 +#define QSERDES_DP_PHY_AUX_CFG1 0x024 +#define QSERDES_DP_PHY_AUX_CFG2 0x028 +#define QSERDES_DP_PHY_AUX_CFG3 0x02c +#define QSERDES_DP_PHY_AUX_CFG4 0x030 +#define QSERDES_DP_PHY_AUX_CFG5 0x034 +#define QSERDES_DP_PHY_AUX_CFG6 0x038 +#define QSERDES_DP_PHY_AUX_CFG7 0x03c +#define QSERDES_DP_PHY_AUX_CFG8 0x040 +#define QSERDES_DP_PHY_AUX_CFG9 0x044 +/* Only for QMP V3 PHY - DP PHY registers */ #define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 # define PHY_AUX_STOP_ERR_MASK 0x01 # define PHY_AUX_DEC_ERR_MASK 0x02 @@ -396,6 +397,7 @@ #define QSERDES_V3_DP_PHY_STATUS 0x0c0 /* Only for QMP V4 PHY - QSERDES COM registers */ +#define QSERDES_V4_COM_BG_TIMER 0x00c #define QSERDES_V4_COM_SSC_EN_CENTER 0x010 #define QSERDES_V4_COM_SSC_PER1 0x01c #define QSERDES_V4_COM_SSC_PER2 0x020 @@ -403,7 +405,9 @@ #define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0 0x028 #define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1 0x030 #define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1 0x034 +#define QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN 0x044 #define QSERDES_V4_COM_CLK_ENABLE1 0x048 +#define QSERDES_V4_COM_SYS_CLK_CTRL 0x04c #define QSERDES_V4_COM_SYSCLK_BUF_ENABLE 0x050 #define QSERDES_V4_COM_PLL_IVCO 0x058 #define QSERDES_V4_COM_CMN_IPTRIM 0x060 @@ -414,6 +418,7 @@ #define QSERDES_V4_COM_PLL_CCTRL_MODE0 0x084 #define QSERDES_V4_COM_PLL_CCTRL_MODE1 0x088 #define QSERDES_V4_COM_SYSCLK_EN_SEL 0x094 +#define QSERDES_V4_COM_RESETSM_CNTRL 0x09c #define QSERDES_V4_COM_LOCK_CMP_EN 0x0a4 #define QSERDES_V4_COM_LOCK_CMP1_MODE0 0x0ac #define QSERDES_V4_COM_LOCK_CMP2_MODE0 0x0b0 @@ -427,16 +432,24 @@ #define QSERDES_V4_COM_DIV_FRAC_START1_MODE1 0x0d8 #define QSERDES_V4_COM_DIV_FRAC_START2_MODE1 0x0dc #define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0 +#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0 0x0ec +#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0 0x0f0 +#define QSERDES_V4_COM_VCO_TUNE_CTRL 0x108 #define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c #define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110 #define QSERDES_V4_COM_VCO_TUNE2_MODE0 0x114 #define QSERDES_V4_COM_VCO_TUNE1_MODE1 0x118 #define QSERDES_V4_COM_VCO_TUNE2_MODE1 0x11c #define QSERDES_V4_COM_VCO_TUNE_INITVAL2 0x124 +#define QSERDES_V4_COM_CMN_STATUS 0x140 #define QSERDES_V4_COM_CLK_SELECT 0x154 #define QSERDES_V4_COM_HSCLK_SEL 0x158 #define QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL 0x15c +#define QSERDES_V4_COM_CORECLK_DIV_MODE0 0x168 #define QSERDES_V4_COM_CORECLK_DIV_MODE1 0x16c +#define QSERDES_V4_COM_CORE_CLK_EN 0x174 +#define QSERDES_V4_COM_C_READY_STATUS 0x178 +#define QSERDES_V4_COM_CMN_CONFIG 0x17c #define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184 #define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac #define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0 @@ -445,19 +458,32 @@ #define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8 /* Only for QMP V4 PHY - TX registers */ +#define QSERDES_V4_TX_CLKBUF_ENABLE 0x08 +#define QSERDES_V4_TX_TX_EMP_POST1_LVL 0x0c +#define QSERDES_V4_TX_TX_DRV_LVL 0x14 +#define QSERDES_V4_TX_RESET_TSYNC_EN 0x1c +#define QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN 0x20 +#define QSERDES_V4_TX_TX_BAND 0x24 +#define QSERDES_V4_TX_INTERFACE_SELECT 0x2c #define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34 #define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38 #define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX 0x3c #define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX 0x40 +#define QSERDES_V4_TX_TRANSCEIVER_BIAS_EN 0x54 +#define QSERDES_V4_TX_HIGHZ_DRVR_EN 0x58 +#define QSERDES_V4_TX_TX_POL_INV 0x5c +#define QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN 0x60 #define QSERDES_V4_TX_LANE_MODE_1 0x84 #define QSERDES_V4_TX_LANE_MODE_2 0x88 #define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c +#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8 +#define QSERDES_V4_TX_TX_INTERFACE_MODE 0xbc #define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8 #define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC #define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0xe0 #define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0xe4 -#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8 -#define QSERDES_V4_TX_PI_QEC_CTRL 0x104 +#define QSERDES_V4_TX_VMODE_CTRL1 0xe8 +#define QSERDES_V4_TX_PI_QEC_CTRL 0x104 /* Only for QMP V4 PHY - RX registers */ #define QSERDES_V4_RX_UCDR_FO_GAIN 0x008 @@ -514,6 +540,17 @@ #define QSERDES_V4_RX_DCC_CTRL1 0x1bc #define QSERDES_V4_RX_VTH_CODE 0x1c4 +/* Only for QMP V4 PHY - DP PHY registers */ +#define QSERDES_V4_DP_PHY_CFG_1 0x014 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 +#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 +#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c +#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V4_DP_PHY_STATUS 0x0dc + /* Only for QMP V4 PHY - UFS PCS registers */ #define QPHY_V4_PCS_UFS_PHY_START 0x000 #define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004 diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 327df1a99f77325a1f229cc1638402f5e8bbe5d6..5c6c17673396175493c0a1f2c19b409b6136c2b8 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -56,6 +56,7 @@ static int qcom_usb_hs_phy_set_mode(struct phy *phy, fallthrough; case PHY_MODE_USB_DEVICE: val |= ULPI_INT_SESS_VALID; + break; default: break; } diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c index 9a610b414b1fb36f901765134d69e26ad969ead0..753cb5bab9308f71b9ea41cff320f610d42d7995 100644 --- a/drivers/phy/ralink/phy-mt7621-pci.c +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -62,7 +62,7 @@ #define RG_PE1_FRC_MSTCKDIV BIT(5) -#define XTAL_MASK GENMASK(7, 6) +#define XTAL_MASK GENMASK(8, 6) #define MAX_PHYS 2 @@ -319,9 +319,9 @@ static int mt7621_pci_phy_probe(struct platform_device *pdev) return PTR_ERR(phy->regmap); phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); - if (IS_ERR(phy)) { + if (IS_ERR(phy->phy)) { dev_err(dev, "failed to create phy\n"); - return PTR_ERR(phy); + return PTR_ERR(phy->phy); } phy_set_drvdata(phy->phy, phy); diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 70a31251b202bc5b4e6b6cbf98ae69179ec96df0..d2bbdc96a1672ae1386e365803776bae54e84960 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1180,6 +1180,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) dev_err(dev, "failed to create phy: %pOFn\n", child_np); pm_runtime_disable(dev); + of_node_put(child_np); return PTR_ERR(phy); } diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig index b32f44ff90337500f045a2aed711681ff5ee099b..3fc3d0781fb8accdd5cd15d8e6f627b940cb4388 100644 --- a/drivers/phy/st/Kconfig +++ b/drivers/phy/st/Kconfig @@ -36,6 +36,7 @@ config PHY_STIH407_USB config PHY_STM32_USBPHYC tristate "STMicroelectronics STM32 USB HS PHY Controller driver" depends on ARCH_STM32 || COMPILE_TEST + depends on COMMON_CLK select GENERIC_PHY help Enable this to support the High-Speed USB transceivers that are part diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index d08fbb180e4323c998fdd75eb1430a130f1ddc7a..c184f4e3458447946ab4a9adbdced8f271890f1a 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -7,6 +7,7 @@ */ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/iopoll.h> #include <linux/kernel.h> @@ -70,6 +71,7 @@ struct stm32_usbphyc { struct regulator *vdda1v1; struct regulator *vdda1v8; atomic_t n_pll_cons; + struct clk_hw clk48_hw; int switch_setup; }; @@ -295,6 +297,61 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { .owner = THIS_MODULE, }; +static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) +{ + struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw); + + return stm32_usbphyc_pll_enable(usbphyc); +} + +static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) +{ + struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw); + + stm32_usbphyc_pll_disable(usbphyc); +} + +static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + return 48000000; +} + +static const struct clk_ops usbphyc_clk48_ops = { + .prepare = stm32_usbphyc_clk48_prepare, + .unprepare = stm32_usbphyc_clk48_unprepare, + .recalc_rate = stm32_usbphyc_clk48_recalc_rate, +}; + +static void stm32_usbphyc_clk48_unregister(void *data) +{ + struct stm32_usbphyc *usbphyc = data; + + of_clk_del_provider(usbphyc->dev->of_node); + clk_hw_unregister(&usbphyc->clk48_hw); +} + +static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc) +{ + struct device_node *node = usbphyc->dev->of_node; + struct clk_init_data init = { }; + int ret = 0; + + init.name = "ck_usbo_48m"; + init.ops = &usbphyc_clk48_ops; + + usbphyc->clk48_hw.init = &init; + + ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &usbphyc->clk48_hw); + if (ret) + clk_hw_unregister(&usbphyc->clk48_hw); + + return ret; +} + static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, u32 utmi_switch) { @@ -473,6 +530,12 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto clk_disable; } + ret = stm32_usbphyc_clk48_register(usbphyc); + if (ret) { + dev_err(dev, "failed to register ck_usbo_48m clock: %d\n", ret); + goto clk_disable; + } + version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); dev_info(dev, "registered rev:%lu.%lu\n", FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); @@ -497,6 +560,8 @@ static int stm32_usbphyc_remove(struct platform_device *pdev) if (usbphyc->phys[port]->active) stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy); + stm32_usbphyc_clk48_unregister(usbphyc); + clk_disable_unprepare(usbphyc->clk); return 0; diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index c9cfafe89cbf1ccf22bddad08b810a7259ad98fc..9eb6d37c907ead08f83b1b92bf14e6a75219bed5 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -7,6 +7,8 @@ */ #include <dt-bindings/phy/phy.h> +#include <dt-bindings/phy/phy-ti.h> +#include <linux/slab.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/gpio.h> @@ -26,6 +28,11 @@ #define WIZ_SERDES_RST 0x40c #define WIZ_SERDES_TYPEC 0x410 #define WIZ_LANECTL(n) (0x480 + (0x40 * (n))) +#define WIZ_LANEDIV(n) (0x484 + (0x40 * (n))) + +#define WIZ_MAX_INPUT_CLOCKS 4 +/* To include mux clocks, divider clocks and gate clocks */ +#define WIZ_MAX_OUTPUT_CLOCKS 32 #define WIZ_MAX_LANES 4 #define WIZ_MUX_NUM_CLOCKS 3 @@ -52,8 +59,16 @@ enum wiz_refclk_div_sel { CMN_REFCLK1_DIG_DIV, }; +enum wiz_clock_input { + WIZ_CORE_REFCLK, + WIZ_EXT_REFCLK, + WIZ_CORE_REFCLK1, + WIZ_EXT_REFCLK1, +}; + static const struct reg_field por_en = REG_FIELD(WIZ_SERDES_CTRL, 31, 31); static const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31); +static const struct reg_field phy_en_refclk = REG_FIELD(WIZ_SERDES_RST, 30, 30); static const struct reg_field pll1_refclk_mux_sel = REG_FIELD(WIZ_SERDES_RST, 29, 29); static const struct reg_field pll0_refclk_mux_sel = @@ -70,6 +85,12 @@ static const struct reg_field pma_cmn_refclk_dig_div = REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27); static const struct reg_field pma_cmn_refclk1_dig_div = REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25); +static const char * const output_clk_names[] = { + [TI_WIZ_PLL0_REFCLK] = "pll0-refclk", + [TI_WIZ_PLL1_REFCLK] = "pll1-refclk", + [TI_WIZ_REFCLK_DIG] = "refclk-dig", + [TI_WIZ_PHY_EN_REFCLK] = "phy-en-refclk", +}; static const struct reg_field p_enable[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANECTL(0), 30, 31), @@ -101,13 +122,34 @@ static const struct reg_field p_standard_mode[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANECTL(3), 24, 25), }; +static const struct reg_field p0_fullrt_div[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANECTL(0), 22, 23), + REG_FIELD(WIZ_LANECTL(1), 22, 23), + REG_FIELD(WIZ_LANECTL(2), 22, 23), + REG_FIELD(WIZ_LANECTL(3), 22, 23), +}; + +static const struct reg_field p_mac_div_sel0[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANEDIV(0), 16, 22), + REG_FIELD(WIZ_LANEDIV(1), 16, 22), + REG_FIELD(WIZ_LANEDIV(2), 16, 22), + REG_FIELD(WIZ_LANEDIV(3), 16, 22), +}; + +static const struct reg_field p_mac_div_sel1[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANEDIV(0), 0, 8), + REG_FIELD(WIZ_LANEDIV(1), 0, 8), + REG_FIELD(WIZ_LANEDIV(2), 0, 8), + REG_FIELD(WIZ_LANEDIV(3), 0, 8), +}; + static const struct reg_field typec_ln10_swap = REG_FIELD(WIZ_SERDES_TYPEC, 30, 30); struct wiz_clk_mux { struct clk_hw hw; struct regmap_field *field; - u32 *table; + const u32 *table; struct clk_init_data clk_data; }; @@ -123,18 +165,26 @@ struct wiz_clk_divider { #define to_wiz_clk_div(_hw) container_of(_hw, struct wiz_clk_divider, hw) struct wiz_clk_mux_sel { - struct regmap_field *field; - u32 table[4]; + u32 table[WIZ_MAX_INPUT_CLOCKS]; const char *node_name; + u32 num_parents; + u32 parents[WIZ_MAX_INPUT_CLOCKS]; }; struct wiz_clk_div_sel { - struct regmap_field *field; - const struct clk_div_table *table; + const struct clk_div_table *table; const char *node_name; }; -static struct wiz_clk_mux_sel clk_mux_sel_16g[] = { +struct wiz_phy_en_refclk { + struct clk_hw hw; + struct regmap_field *phy_en_refclk; + struct clk_init_data clk_data; +}; + +#define to_wiz_phy_en_refclk(_hw) container_of(_hw, struct wiz_phy_en_refclk, hw) + +static const struct wiz_clk_mux_sel clk_mux_sel_16g[] = { { /* * Mux value to be configured for each of the input clocks @@ -153,20 +203,26 @@ static struct wiz_clk_mux_sel clk_mux_sel_16g[] = { }, }; -static struct wiz_clk_mux_sel clk_mux_sel_10g[] = { +static const struct wiz_clk_mux_sel clk_mux_sel_10g[] = { { /* * Mux value to be configured for each of the input clocks * in the order populated in device tree */ + .num_parents = 2, + .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, .table = { 1, 0 }, .node_name = "pll0-refclk", }, { + .num_parents = 2, + .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, .table = { 1, 0 }, .node_name = "pll1-refclk", }, { + .num_parents = 2, + .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, .table = { 1, 0 }, .node_name = "refclk-dig", }, @@ -179,7 +235,7 @@ static const struct clk_div_table clk_div_table[] = { { .val = 3, .div = 8, }, }; -static struct wiz_clk_div_sel clk_div_sel[] = { +static const struct wiz_clk_div_sel clk_div_sel[] = { { .table = clk_div_table, .node_name = "cmn-refclk-dig-div", @@ -193,6 +249,7 @@ static struct wiz_clk_div_sel clk_div_sel[] = { enum wiz_type { J721E_WIZ_16G, J721E_WIZ_10G, + AM64_WIZ_10G, }; #define WIZ_TYPEC_DIR_DEBOUNCE_MIN 100 /* ms */ @@ -201,19 +258,25 @@ enum wiz_type { struct wiz { struct regmap *regmap; enum wiz_type type; - struct wiz_clk_mux_sel *clk_mux_sel; - struct wiz_clk_div_sel *clk_div_sel; + const struct wiz_clk_mux_sel *clk_mux_sel; + const struct wiz_clk_div_sel *clk_div_sel; unsigned int clk_div_sel_num; struct regmap_field *por_en; struct regmap_field *phy_reset_n; + struct regmap_field *phy_en_refclk; struct regmap_field *p_enable[WIZ_MAX_LANES]; struct regmap_field *p_align[WIZ_MAX_LANES]; struct regmap_field *p_raw_auto_start[WIZ_MAX_LANES]; struct regmap_field *p_standard_mode[WIZ_MAX_LANES]; + struct regmap_field *p_mac_div_sel0[WIZ_MAX_LANES]; + struct regmap_field *p_mac_div_sel1[WIZ_MAX_LANES]; + struct regmap_field *p0_fullrt_div[WIZ_MAX_LANES]; struct regmap_field *pma_cmn_refclk_int_mode; struct regmap_field *pma_cmn_refclk_mode; struct regmap_field *pma_cmn_refclk_dig_div; struct regmap_field *pma_cmn_refclk1_dig_div; + struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS]; + struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G]; struct regmap_field *typec_ln10_swap; struct device *dev; @@ -223,6 +286,9 @@ struct wiz { struct gpio_desc *gpio_typec_dir; int typec_dir_delay; u32 lane_phy_type[WIZ_MAX_LANES]; + struct clk *input_clks[WIZ_MAX_INPUT_CLOCKS]; + struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS]; + struct clk_onecell_data clk_data; }; static int wiz_reset(struct wiz *wiz) @@ -242,6 +308,27 @@ static int wiz_reset(struct wiz *wiz) return 0; } +static int wiz_p_mac_div_sel(struct wiz *wiz) +{ + u32 num_lanes = wiz->num_lanes; + int ret; + int i; + + for (i = 0; i < num_lanes; i++) { + if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) { + ret = regmap_field_write(wiz->p_mac_div_sel0[i], 1); + if (ret) + return ret; + + ret = regmap_field_write(wiz->p_mac_div_sel1[i], 2); + if (ret) + return ret; + } + } + + return 0; +} + static int wiz_mode_select(struct wiz *wiz) { u32 num_lanes = wiz->num_lanes; @@ -252,8 +339,10 @@ static int wiz_mode_select(struct wiz *wiz) for (i = 0; i < num_lanes; i++) { if (wiz->lane_phy_type[i] == PHY_TYPE_DP) mode = LANE_MODE_GEN1; + else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) + mode = LANE_MODE_GEN2; else - mode = LANE_MODE_GEN4; + continue; ret = regmap_field_write(wiz->p_standard_mode[i], mode); if (ret) @@ -299,6 +388,12 @@ static int wiz_init(struct wiz *wiz) return ret; } + ret = wiz_p_mac_div_sel(wiz); + if (ret) { + dev_err(dev, "Configuring P0 MAC DIV SEL failed\n"); + return ret; + } + ret = wiz_init_raw_interface(wiz, true); if (ret) { dev_err(dev, "WIZ interface initialization failed\n"); @@ -310,8 +405,6 @@ static int wiz_init(struct wiz *wiz) static int wiz_regfield_init(struct wiz *wiz) { - struct wiz_clk_mux_sel *clk_mux_sel; - struct wiz_clk_div_sel *clk_div_sel; struct regmap *regmap = wiz->regmap; int num_lanes = wiz->num_lanes; struct device *dev = wiz->dev; @@ -344,54 +437,49 @@ static int wiz_regfield_init(struct wiz *wiz) return PTR_ERR(wiz->pma_cmn_refclk_mode); } - clk_div_sel = &wiz->clk_div_sel[CMN_REFCLK_DIG_DIV]; - clk_div_sel->field = devm_regmap_field_alloc(dev, regmap, - pma_cmn_refclk_dig_div); - if (IS_ERR(clk_div_sel->field)) { + wiz->div_sel_field[CMN_REFCLK_DIG_DIV] = + devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk_dig_div); + if (IS_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV])) { dev_err(dev, "PMA_CMN_REFCLK_DIG_DIV reg field init failed\n"); - return PTR_ERR(clk_div_sel->field); + return PTR_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV]); } if (wiz->type == J721E_WIZ_16G) { - clk_div_sel = &wiz->clk_div_sel[CMN_REFCLK1_DIG_DIV]; - clk_div_sel->field = + wiz->div_sel_field[CMN_REFCLK1_DIG_DIV] = devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk1_dig_div); - if (IS_ERR(clk_div_sel->field)) { + if (IS_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV])) { dev_err(dev, "PMA_CMN_REFCLK1_DIG_DIV reg field init failed\n"); - return PTR_ERR(clk_div_sel->field); + return PTR_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV]); } } - clk_mux_sel = &wiz->clk_mux_sel[PLL0_REFCLK]; - clk_mux_sel->field = devm_regmap_field_alloc(dev, regmap, - pll0_refclk_mux_sel); - if (IS_ERR(clk_mux_sel->field)) { + wiz->mux_sel_field[PLL0_REFCLK] = + devm_regmap_field_alloc(dev, regmap, pll0_refclk_mux_sel); + if (IS_ERR(wiz->mux_sel_field[PLL0_REFCLK])) { dev_err(dev, "PLL0_REFCLK_SEL reg field init failed\n"); - return PTR_ERR(clk_mux_sel->field); + return PTR_ERR(wiz->mux_sel_field[PLL0_REFCLK]); } - clk_mux_sel = &wiz->clk_mux_sel[PLL1_REFCLK]; - clk_mux_sel->field = devm_regmap_field_alloc(dev, regmap, - pll1_refclk_mux_sel); - if (IS_ERR(clk_mux_sel->field)) { + wiz->mux_sel_field[PLL1_REFCLK] = + devm_regmap_field_alloc(dev, regmap, pll1_refclk_mux_sel); + if (IS_ERR(wiz->mux_sel_field[PLL1_REFCLK])) { dev_err(dev, "PLL1_REFCLK_SEL reg field init failed\n"); - return PTR_ERR(clk_mux_sel->field); + return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]); } - clk_mux_sel = &wiz->clk_mux_sel[REFCLK_DIG]; - if (wiz->type == J721E_WIZ_10G) - clk_mux_sel->field = + if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G) + wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap, refclk_dig_sel_10g); else - clk_mux_sel->field = + wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap, refclk_dig_sel_16g); - if (IS_ERR(clk_mux_sel->field)) { + if (IS_ERR(wiz->mux_sel_field[REFCLK_DIG])) { dev_err(dev, "REFCLK_DIG_SEL reg field init failed\n"); - return PTR_ERR(clk_mux_sel->field); + return PTR_ERR(wiz->mux_sel_field[REFCLK_DIG]); } for (i = 0; i < num_lanes; i++) { @@ -424,6 +512,28 @@ static int wiz_regfield_init(struct wiz *wiz) i); return PTR_ERR(wiz->p_standard_mode[i]); } + + wiz->p0_fullrt_div[i] = devm_regmap_field_alloc(dev, regmap, p0_fullrt_div[i]); + if (IS_ERR(wiz->p0_fullrt_div[i])) { + dev_err(dev, "P%d_FULLRT_DIV reg field init failed\n", i); + return PTR_ERR(wiz->p0_fullrt_div[i]); + } + + wiz->p_mac_div_sel0[i] = + devm_regmap_field_alloc(dev, regmap, p_mac_div_sel0[i]); + if (IS_ERR(wiz->p_mac_div_sel0[i])) { + dev_err(dev, "P%d_MAC_DIV_SEL0 reg field init fail\n", + i); + return PTR_ERR(wiz->p_mac_div_sel0[i]); + } + + wiz->p_mac_div_sel1[i] = + devm_regmap_field_alloc(dev, regmap, p_mac_div_sel1[i]); + if (IS_ERR(wiz->p_mac_div_sel1[i])) { + dev_err(dev, "P%d_MAC_DIV_SEL1 reg field init fail\n", + i); + return PTR_ERR(wiz->p_mac_div_sel1[i]); + } } wiz->typec_ln10_swap = devm_regmap_field_alloc(dev, regmap, @@ -433,6 +543,76 @@ static int wiz_regfield_init(struct wiz *wiz) return PTR_ERR(wiz->typec_ln10_swap); } + wiz->phy_en_refclk = devm_regmap_field_alloc(dev, regmap, phy_en_refclk); + if (IS_ERR(wiz->phy_en_refclk)) { + dev_err(dev, "PHY_EN_REFCLK reg field init failed\n"); + return PTR_ERR(wiz->phy_en_refclk); + } + + return 0; +} + +static int wiz_phy_en_refclk_enable(struct clk_hw *hw) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); + struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; + + regmap_field_write(phy_en_refclk, 1); + + return 0; +} + +static void wiz_phy_en_refclk_disable(struct clk_hw *hw) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); + struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; + + regmap_field_write(phy_en_refclk, 0); +} + +static int wiz_phy_en_refclk_is_enabled(struct clk_hw *hw) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); + struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; + int val; + + regmap_field_read(phy_en_refclk, &val); + + return !!val; +} + +static const struct clk_ops wiz_phy_en_refclk_ops = { + .enable = wiz_phy_en_refclk_enable, + .disable = wiz_phy_en_refclk_disable, + .is_enabled = wiz_phy_en_refclk_is_enabled, +}; + +static int wiz_phy_en_refclk_register(struct wiz *wiz) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk; + struct device *dev = wiz->dev; + struct clk_init_data *init; + struct clk *clk; + + wiz_phy_en_refclk = devm_kzalloc(dev, sizeof(*wiz_phy_en_refclk), GFP_KERNEL); + if (!wiz_phy_en_refclk) + return -ENOMEM; + + init = &wiz_phy_en_refclk->clk_data; + + init->ops = &wiz_phy_en_refclk_ops; + init->flags = 0; + init->name = output_clk_names[TI_WIZ_PHY_EN_REFCLK]; + + wiz_phy_en_refclk->phy_en_refclk = wiz->phy_en_refclk; + wiz_phy_en_refclk->hw.init = init; + + clk = devm_clk_register(dev, &wiz_phy_en_refclk->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + wiz->output_clks[TI_WIZ_PHY_EN_REFCLK] = clk; + return 0; } @@ -443,7 +623,7 @@ static u8 wiz_clk_mux_get_parent(struct clk_hw *hw) unsigned int val; regmap_field_read(field, &val); - return clk_mux_val_to_index(hw, mux->table, 0, val); + return clk_mux_val_to_index(hw, (u32 *)mux->table, 0, val); } static int wiz_clk_mux_set_parent(struct clk_hw *hw, u8 index) @@ -461,8 +641,69 @@ static const struct clk_ops wiz_clk_mux_ops = { .get_parent = wiz_clk_mux_get_parent, }; -static int wiz_mux_clk_register(struct wiz *wiz, struct device_node *node, - struct regmap_field *field, u32 *table) +static int wiz_mux_clk_register(struct wiz *wiz, struct regmap_field *field, + const struct wiz_clk_mux_sel *mux_sel, int clk_index) +{ + struct device *dev = wiz->dev; + struct clk_init_data *init; + const char **parent_names; + unsigned int num_parents; + struct wiz_clk_mux *mux; + char clk_name[100]; + struct clk *clk; + int ret = 0, i; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + num_parents = mux_sel->num_parents; + + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) { + clk = wiz->input_clks[mux_sel->parents[i]]; + if (IS_ERR_OR_NULL(clk)) { + dev_err(dev, "Failed to get parent clk for %s\n", + output_clk_names[clk_index]); + ret = -EINVAL; + goto err; + } + parent_names[i] = __clk_get_name(clk); + } + + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), output_clk_names[clk_index]); + + init = &mux->clk_data; + + init->ops = &wiz_clk_mux_ops; + init->flags = CLK_SET_RATE_NO_REPARENT; + init->parent_names = parent_names; + init->num_parents = num_parents; + init->name = clk_name; + + mux->field = field; + mux->table = mux_sel->table; + mux->hw.init = init; + + clk = devm_clk_register(dev, &mux->hw); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto err; + } + + wiz->output_clks[clk_index] = clk; + +err: + kfree(parent_names); + + return ret; +} + +static int wiz_mux_of_clk_register(struct wiz *wiz, struct device_node *node, + struct regmap_field *field, const u32 *table) { struct device *dev = wiz->dev; struct clk_init_data *init; @@ -606,20 +847,70 @@ static int wiz_div_clk_register(struct wiz *wiz, struct device_node *node, static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) { - struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + struct device *dev = wiz->dev; struct device_node *clk_node; int i; + if (wiz->type == AM64_WIZ_10G) { + of_clk_del_provider(dev->of_node); + return; + } + for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { clk_node = of_get_child_by_name(node, clk_mux_sel[i].node_name); of_clk_del_provider(clk_node); of_node_put(clk_node); } + + for (i = 0; i < wiz->clk_div_sel_num; i++) { + clk_node = of_get_child_by_name(node, clk_div_sel[i].node_name); + of_clk_del_provider(clk_node); + of_node_put(clk_node); + } + + of_clk_del_provider(wiz->dev->of_node); +} + +static int wiz_clock_register(struct wiz *wiz) +{ + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + struct device *dev = wiz->dev; + struct device_node *node = dev->of_node; + int clk_index; + int ret; + int i; + + if (wiz->type != AM64_WIZ_10G) + return 0; + + clk_index = TI_WIZ_PLL0_REFCLK; + for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) { + ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index); + if (ret) { + dev_err(dev, "Failed to register clk: %s\n", output_clk_names[clk_index]); + return ret; + } + } + + ret = wiz_phy_en_refclk_register(wiz); + if (ret) { + dev_err(dev, "Failed to add phy-en-refclk\n"); + return ret; + } + + wiz->clk_data.clks = wiz->output_clks; + wiz->clk_data.clk_num = WIZ_MAX_OUTPUT_CLOCKS; + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &wiz->clk_data); + if (ret) + dev_err(dev, "Failed to add clock provider: %s\n", node->name); + + return ret; } static int wiz_clock_init(struct wiz *wiz, struct device_node *node) { - struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; struct device *dev = wiz->dev; struct device_node *clk_node; const char *node_name; @@ -634,6 +925,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) ret = PTR_ERR(clk); return ret; } + wiz->input_clks[WIZ_CORE_REFCLK] = clk; rate = clk_get_rate(clk); if (rate >= 100000000) @@ -647,6 +939,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) ret = PTR_ERR(clk); return ret; } + wiz->input_clks[WIZ_EXT_REFCLK] = clk; rate = clk_get_rate(clk); if (rate >= 100000000) @@ -654,6 +947,13 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) else regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2); + if (wiz->type == AM64_WIZ_10G) { + ret = wiz_clock_register(wiz); + if (ret) + dev_err(dev, "Failed to register wiz clocks\n"); + return ret; + } + for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { node_name = clk_mux_sel[i].node_name; clk_node = of_get_child_by_name(node, node_name); @@ -663,8 +963,8 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) goto err; } - ret = wiz_mux_clk_register(wiz, clk_node, clk_mux_sel[i].field, - clk_mux_sel[i].table); + ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i], + clk_mux_sel[i].table); if (ret) { dev_err(dev, "Failed to register %s clock\n", node_name); @@ -684,7 +984,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) goto err; } - ret = wiz_div_clk_register(wiz, clk_node, clk_div_sel[i].field, + ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i], clk_div_sel[i].table); if (ret) { dev_err(dev, "Failed to register %s clock\n", @@ -719,6 +1019,17 @@ static int wiz_phy_reset_assert(struct reset_controller_dev *rcdev, return ret; } +static int wiz_phy_fullrt_div(struct wiz *wiz, int lane) +{ + if (wiz->type != AM64_WIZ_10G) + return 0; + + if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) + return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); + + return 0; +} + static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { @@ -742,6 +1053,10 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev, return ret; } + ret = wiz_phy_fullrt_div(wiz, id - 1); + if (ret) + return ret; + if (wiz->lane_phy_type[id - 1] == PHY_TYPE_DP) ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE); else @@ -769,6 +1084,9 @@ static const struct of_device_id wiz_id_table[] = { { .compatible = "ti,j721e-wiz-10g", .data = (void *)J721E_WIZ_10G }, + { + .compatible = "ti,am64-wiz-10g", .data = (void *)AM64_WIZ_10G + }, {} }; MODULE_DEVICE_TABLE(of, wiz_id_table); @@ -787,8 +1105,13 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) u32 reg, num_lanes = 1, phy_type = PHY_NONE; int ret, i; + if (!(of_node_name_eq(subnode, "phy") || + of_node_name_eq(subnode, "link"))) + continue; + ret = of_property_read_u32(subnode, "reg", ®); if (ret) { + of_node_put(subnode); dev_err(dev, "%s: Reading \"reg\" from \"%s\" failed: %d\n", __func__, subnode->name, ret); @@ -813,13 +1136,14 @@ static int wiz_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct platform_device *serdes_pdev; + bool already_configured = false; struct device_node *child_node; struct regmap *regmap; struct resource res; void __iomem *base; struct wiz *wiz; + int ret, val, i; u32 num_lanes; - int ret; wiz = devm_kzalloc(dev, sizeof(*wiz), GFP_KERNEL); if (!wiz) @@ -900,14 +1224,14 @@ static int wiz_probe(struct platform_device *pdev) wiz->dev = dev; wiz->regmap = regmap; wiz->num_lanes = num_lanes; - if (wiz->type == J721E_WIZ_10G) + if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G) wiz->clk_mux_sel = clk_mux_sel_10g; else wiz->clk_mux_sel = clk_mux_sel_16g; wiz->clk_div_sel = clk_div_sel; - if (wiz->type == J721E_WIZ_10G) + if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G) wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G; else wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_16G; @@ -947,27 +1271,34 @@ static int wiz_probe(struct platform_device *pdev) goto err_get_sync; } + for (i = 0; i < wiz->num_lanes; i++) { + regmap_field_read(wiz->p_enable[i], &val); + if (val & (P_ENABLE | P_ENABLE_FORCE)) { + already_configured = true; + break; + } + } + + if (!already_configured) { + ret = wiz_init(wiz); + if (ret) { + dev_err(dev, "WIZ initialization failed\n"); + goto err_wiz_init; + } + } + serdes_pdev = of_platform_device_create(child_node, NULL, dev); if (!serdes_pdev) { dev_WARN(dev, "Unable to create SERDES platform device\n"); ret = -ENOMEM; - goto err_pdev_create; - } - wiz->serdes_pdev = serdes_pdev; - - ret = wiz_init(wiz); - if (ret) { - dev_err(dev, "WIZ initialization failed\n"); goto err_wiz_init; } + wiz->serdes_pdev = serdes_pdev; of_node_put(child_node); return 0; err_wiz_init: - of_platform_device_destroy(&serdes_pdev->dev, NULL); - -err_pdev_create: wiz_clock_cleanup(wiz, node); err_get_sync: diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index d8d0cc11d187e98c31e023ca60da8969bea9d98b..a63213f5972a7e591061bf6dce32d05644528ba2 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -7,15 +7,16 @@ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> */ #include <linux/module.h> +#include <linux/bitfield.h> #include <linux/ulpi/driver.h> #include <linux/ulpi/regs.h> #include <linux/gpio/consumer.h> #include <linux/phy/ulpi_phy.h> #define TUSB1210_VENDOR_SPECIFIC2 0x80 -#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0 -#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4 -#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6 +#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK GENMASK(3, 0) +#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK GENMASK(5, 4) +#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK BIT(6) struct tusb1210 { struct ulpi *ulpi; @@ -118,22 +119,22 @@ static int tusb1210_probe(struct ulpi *ulpi) * diagram optimization and DP/DM swap. */ + reg = ulpi_read(ulpi, TUSB1210_VENDOR_SPECIFIC2); + /* High speed output drive strength configuration */ - device_property_read_u8(&ulpi->dev, "ihstx", &val); - reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT; + if (!device_property_read_u8(&ulpi->dev, "ihstx", &val)) + u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK); /* High speed output impedance configuration */ - device_property_read_u8(&ulpi->dev, "zhsdrv", &val); - reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT; + if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val)) + u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK); /* DP/DM swap control */ - device_property_read_u8(&ulpi->dev, "datapolarity", &val); - reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT; + if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val)) + u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK); - if (reg) { - ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg); - tusb->vendor_specific2 = reg; - } + ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg); + tusb->vendor_specific2 = reg; tusb->phy = ulpi_phy_create(ulpi, &phy_ops); if (IS_ERR(tusb->phy)) diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index 9887f908f5401a11e274159ab82b3c7272070709..812e5409d35958e75cf06a19efc1eec71124739a 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -779,7 +779,7 @@ static int twl4030_usb_remove(struct platform_device *pdev) usb_remove_phy(&twl->phy); pm_runtime_get_sync(twl->dev); - cancel_delayed_work(&twl->id_workaround_work); + cancel_delayed_work_sync(&twl->id_workaround_work); device_remove_file(twl->dev, &dev_attr_vbus); /* set transceiver mode to power on defaults */ diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 2b65f84a5f8937d7622953e7441ee2f29b78e075..35652152ce5d0062a381bf7c0a7b03b5837f2975 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -208,6 +208,7 @@ struct xpsgtr_phy { * @gtr_mutex: mutex for locking * @phys: PHY lanes * @refclk_sscs: spread spectrum settings for the reference clocks + * @clk: reference clocks * @tx_term_fix: fix for GT issue * @saved_icm_cfg0: stored value of ICM CFG0 register * @saved_icm_cfg1: stored value of ICM CFG1 register @@ -219,6 +220,7 @@ struct xpsgtr_dev { struct mutex gtr_mutex; /* mutex for locking */ struct xpsgtr_phy phys[NUM_LANES]; const struct xpsgtr_ssc *refclk_sscs[NUM_LANES]; + struct clk *clk[NUM_LANES]; bool tx_term_fix; unsigned int saved_icm_cfg0; unsigned int saved_icm_cfg1; @@ -818,11 +820,15 @@ static struct phy *xpsgtr_xlate(struct device *dev, static int __maybe_unused xpsgtr_suspend(struct device *dev) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); + unsigned int i; /* Save the snapshot ICM_CFG registers. */ gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) + clk_disable_unprepare(gtr_dev->clk[i]); + return 0; } @@ -832,6 +838,13 @@ static int __maybe_unused xpsgtr_resume(struct device *dev) unsigned int icm_cfg0, icm_cfg1; unsigned int i; bool skip_phy_init; + int err; + + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) { + err = clk_prepare_enable(gtr_dev->clk[i]); + if (err) + goto err_clk_put; + } icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); @@ -852,6 +865,12 @@ static int __maybe_unused xpsgtr_resume(struct device *dev) gtr_dev->phys[i].skip_phy_init = skip_phy_init; return 0; + +err_clk_put: + while (i--) + clk_disable_unprepare(gtr_dev->clk[i]); + + return err; } static const struct dev_pm_ops xpsgtr_pm_ops = { @@ -865,6 +884,7 @@ static const struct dev_pm_ops xpsgtr_pm_ops = { static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) { unsigned int refclk; + int ret; for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { unsigned long rate; @@ -874,14 +894,22 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) snprintf(name, sizeof(name), "ref%u", refclk); clk = devm_clk_get_optional(gtr_dev->dev, name); - if (IS_ERR(clk)) - return dev_err_probe(gtr_dev->dev, PTR_ERR(clk), - "Failed to get reference clock %u\n", - refclk); + if (IS_ERR(clk)) { + ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk), + "Failed to get reference clock %u\n", + refclk); + goto err_clk_put; + } if (!clk) continue; + ret = clk_prepare_enable(clk); + if (ret) + goto err_clk_put; + + gtr_dev->clk[refclk] = clk; + /* * Get the spread spectrum (SSC) settings for the reference * clock rate. @@ -899,11 +927,18 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) dev_err(gtr_dev->dev, "Invalid rate %lu for reference clock %u\n", rate, refclk); - return -EINVAL; + ret = -EINVAL; + goto err_clk_put; } } return 0; + +err_clk_put: + while (refclk--) + clk_disable_unprepare(gtr_dev->clk[refclk]); + + return ret; } static int xpsgtr_probe(struct platform_device *pdev) @@ -912,6 +947,7 @@ static int xpsgtr_probe(struct platform_device *pdev) struct xpsgtr_dev *gtr_dev; struct phy_provider *provider; unsigned int port; + unsigned int i; int ret; gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL); @@ -951,7 +987,8 @@ static int xpsgtr_probe(struct platform_device *pdev) phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops); if (IS_ERR(phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); - return PTR_ERR(phy); + ret = PTR_ERR(phy); + goto err_clk_put; } gtr_phy->phy = phy; @@ -962,9 +999,16 @@ static int xpsgtr_probe(struct platform_device *pdev) provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate); if (IS_ERR(provider)) { dev_err(&pdev->dev, "registering provider failed\n"); - return PTR_ERR(provider); + ret = PTR_ERR(provider); + goto err_clk_put; } return 0; + +err_clk_put: + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) + clk_disable_unprepare(gtr_dev->clk[i]); + + return ret; } static const struct of_device_id xpsgtr_of_match[] = { diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index 0cab4c2576e2a129800b8fb5169c443398c453bc..996ebcba4d3867bb190473d0c40a8c2878ee3093 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -60,7 +60,7 @@ #define COND2 { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 } /* LHCR0 is offset from the end of the H8S/2168-compatible registers */ -#define LHCR0 0x20 +#define LHCR0 0xa0 #define GFX064 0x64 #define B14 0 @@ -2648,14 +2648,19 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx, } if (ip == ASPEED_IP_LPC) { - struct device_node *node; + struct device_node *np; struct regmap *map; - node = of_parse_phandle(ctx->dev->of_node, + np = of_parse_phandle(ctx->dev->of_node, "aspeed,external-nodes", 1); - if (node) { - map = syscon_node_to_regmap(node->parent); - of_node_put(node); + if (np) { + if (!of_device_is_compatible(np->parent, "aspeed,ast2400-lpc-v2") && + !of_device_is_compatible(np->parent, "aspeed,ast2500-lpc-v2") && + !of_device_is_compatible(np->parent, "aspeed,ast2600-lpc-v2")) + return ERR_PTR(-ENODEV); + + map = syscon_node_to_regmap(np->parent); + of_node_put(np); if (IS_ERR(map)) return map; } else diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 8003d1bd169535acbad3f67a8f2c236310728536..fc61aaec34cc9cb710e43221724460dca78e4857 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -23,6 +23,8 @@ /* Since we request GPIOs from ourself */ #include <linux/pinctrl/consumer.h> +#include <soc/at91/pm.h> + #include "pinctrl-at91.h" #include "core.h" diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c index 5d21c6adf1ab6de9647a25d3fb17452d5509b2c8..1c7a288b59a5c52e072b72ae5e615388aa18d6be 100644 --- a/drivers/platform/mellanox/mlxbf-bootctl.c +++ b/drivers/platform/mellanox/mlxbf-bootctl.c @@ -208,7 +208,7 @@ static ssize_t secure_boot_fuse_state_show(struct device *dev, * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits * are a thermometer code indicating key programming has completed for * key n (same encodings as the start bits). This allows for detection - * of an interruption in the progamming process which has left the key + * of an interruption in the programming process which has left the key * partially programmed (and thus invalid). The process is to burn the * eFuse for the new key start bit, burn the key eFuses, then burn the * eFuse for the new key complete bit. diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index b013445147dd5692e688a8808ab01a533b00bc4a..a9db2f32658f2bef0f255e60a5db91b1ddf6f1d2 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -683,13 +683,13 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, priv->irq, mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING - | IRQF_SHARED, "mlxreg-hotplug", priv); + | IRQF_SHARED | IRQF_NO_AUTOEN, + "mlxreg-hotplug", priv); if (err) { dev_err(&pdev->dev, "Failed to request irq: %d\n", err); return err; } - disable_irq(priv->irq); spin_lock_init(&priv->lock); INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); dev_set_drvdata(&pdev->dev, priv); diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig index 0847b2dc97bf5a0a141d0deea1612de9af3335d3..3105f651614ffca224523690626a5b398c45a532 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -77,6 +77,53 @@ config SURFACE_AGGREGATOR_CDEV The provided interface is intended for debugging and development only, and should not be used otherwise. +config SURFACE_AGGREGATOR_REGISTRY + tristate "Surface System Aggregator Module Device Registry" + depends on SURFACE_AGGREGATOR + depends on SURFACE_AGGREGATOR_BUS + help + Device-registry and device-hubs for Surface System Aggregator Module + (SSAM) devices. + + Provides a module and driver which act as a device-registry for SSAM + client devices that cannot be detected automatically, e.g. via ACPI. + Such devices are instead provided via this registry and attached via + device hubs, also provided in this module. + + Devices provided via this registry are: + - Platform profile (performance-/cooling-mode) device (5th- and later + generations). + - Battery/AC devices (7th-generation). + - HID input devices (7th-generation). + + Select M (recommended) or Y here if you want support for the above + mentioned devices on the corresponding Surface models. Without this + module, the respective devices will not be instantiated and thus any + functionality provided by them will be missing, even when drivers for + these devices are present. In other words, this module only provides + the respective client devices. Drivers for these devices still need to + be selected via the other options. + +config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR + depends on INPUT + help + Driver for the Surface Book clipboard detachment system (DTX). + + On the Surface Book series devices, the display part containing the + CPU (called the clipboard) can be detached from the base (containing a + battery, the keyboard, and, optionally, a discrete GPU) by (if + necessary) unlocking and opening the latch connecting both parts. + + This driver provides a user-space interface that can influence the + behavior of this process, which includes the option to abort it in + case the base is still in use or speed it up in case it is not. + + Note that this module can be built without support for the Surface + Aggregator Bus (i.e. CONFIG_SURFACE_AGGREGATOR_BUS=n). In that case, + some devices, specifically the Surface Book 3, will not be supported. + config SURFACE_GPE tristate "Surface GPE/Lid Support Driver" depends on DMI @@ -105,6 +152,28 @@ config SURFACE_HOTPLUG Select M or Y here, if you want to (fully) support hot-plugging of dGPU devices on the Surface Book 2 and/or 3 during D3cold. +config SURFACE_PLATFORM_PROFILE + tristate "Surface Platform Profile Driver" + depends on SURFACE_AGGREGATOR_REGISTRY + select ACPI_PLATFORM_PROFILE + help + Provides support for the ACPI platform profile on 5th- and later + generation Microsoft Surface devices. + + More specifically, this driver provides ACPI platform profile support + on Microsoft Surface devices with a Surface System Aggregator Module + (SSAM) connected via the Surface Serial Hub (SSH / SAM-over-SSH). In + other words, this driver provides platform profile support on the + Surface Pro 5, Surface Book 2, Surface Laptop, Surface Laptop Go and + later. On those devices, the platform profile can significantly + influence cooling behavior, e.g. setting it to 'quiet' (default) or + 'low-power' can significantly limit performance of the discrete GPU on + Surface Books, while in turn leading to lower power consumption and/or + less fan noise. + + Select M or Y here, if you want to include ACPI platform profile + support on the above mentioned devices. + config SURFACE_PRO3_BUTTON tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" depends on INPUT diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile index 990424c5f0c93b69846f79c9f0461f7c0f338352..32889482de55b9e578a02632d95cff0680721e6d 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -10,6 +10,9 @@ obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o +obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o +obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +obj-$(CONFIG_SURFACE_PLATFORM_PROFILE) += surface_platform_profile.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index 5bcb59ed579dbab50c448682b3695d6480f1ca43..69e86cd599d38dce783d91b061ab5d3d6dbdf10b 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -1040,7 +1040,7 @@ static int ssam_dsm_load_u32(acpi_handle handle, u64 funcs, u64 func, u32 *ret) union acpi_object *obj; u64 val; - if (!(funcs & BIT(func))) + if (!(funcs & BIT_ULL(func))) return 0; /* Not supported, leave *ret at its default value */ obj = acpi_evaluate_dsm_typed(handle, &SSAM_SSH_DSM_GUID, @@ -1750,35 +1750,35 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer); /* -- Internal SAM requests. ------------------------------------------------ */ -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, { +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, { .target_category = SSAM_SSH_TC_SAM, .target_id = 0x01, .command_id = 0x13, .instance_id = 0x00, }); -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, { +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, { .target_category = SSAM_SSH_TC_SAM, .target_id = 0x01, .command_id = 0x15, .instance_id = 0x00, }); -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, { +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, { .target_category = SSAM_SSH_TC_SAM, .target_id = 0x01, .command_id = 0x16, .instance_id = 0x00, }); -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, { +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, { .target_category = SSAM_SSH_TC_SAM, .target_id = 0x01, .command_id = 0x33, .instance_id = 0x00, }); -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, { +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, { .target_category = SSAM_SSH_TC_SAM, .target_id = 0x01, .command_id = 0x34, @@ -2483,7 +2483,8 @@ int ssam_irq_setup(struct ssam_controller *ctrl) * interrupt, and let the SAM resume callback during the controller * resume process clear it. */ - const int irqf = IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_RISING; + const int irqf = IRQF_SHARED | IRQF_ONESHOT | + IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN; gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS); if (IS_ERR(gpiod)) @@ -2501,7 +2502,6 @@ int ssam_irq_setup(struct ssam_controller *ctrl) return status; ctrl->irq.num = irq; - disable_irq(ctrl->irq.num); return 0; } diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c new file mode 100644 index 0000000000000000000000000000000000000000..685d37a7add1411f63e065151cca445ffbcd832c --- /dev/null +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface System Aggregator Module (SSAM) client device registry. + * + * Registry for non-platform/non-ACPI SSAM client devices, i.e. devices that + * cannot be auto-detected. Provides device-hubs and performs instantiation + * for these devices. + * + * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> + */ + +#include <linux/acpi.h> +#include <linux/kernel.h> +#include <linux/limits.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/types.h> +#include <linux/workqueue.h> + +#include <linux/surface_aggregator/controller.h> +#include <linux/surface_aggregator/device.h> + + +/* -- Device registry. ------------------------------------------------------ */ + +/* + * SSAM device names follow the SSAM module alias, meaning they are prefixed + * with 'ssam:', followed by domain, category, target ID, instance ID, and + * function, each encoded as two-digit hexadecimal, separated by ':'. In other + * words, it follows the scheme + * + * ssam:dd:cc:tt:ii:ff + * + * Where, 'dd', 'cc', 'tt', 'ii', and 'ff' are the two-digit hexadecimal + * values mentioned above, respectively. + */ + +/* Root node. */ +static const struct software_node ssam_node_root = { + .name = "ssam_platform_hub", +}; + +/* Base device hub (devices attached to Surface Book 3 base). */ +static const struct software_node ssam_node_hub_base = { + .name = "ssam:00:00:02:00:00", + .parent = &ssam_node_root, +}; + +/* AC adapter. */ +static const struct software_node ssam_node_bat_ac = { + .name = "ssam:01:02:01:01:01", + .parent = &ssam_node_root, +}; + +/* Primary battery. */ +static const struct software_node ssam_node_bat_main = { + .name = "ssam:01:02:01:01:00", + .parent = &ssam_node_root, +}; + +/* Secondary battery (Surface Book 3). */ +static const struct software_node ssam_node_bat_sb3base = { + .name = "ssam:01:02:02:01:00", + .parent = &ssam_node_hub_base, +}; + +/* Platform profile / performance-mode device. */ +static const struct software_node ssam_node_tmp_pprof = { + .name = "ssam:01:03:01:00:01", + .parent = &ssam_node_root, +}; + +/* DTX / detachment-system device (Surface Book 3). */ +static const struct software_node ssam_node_bas_dtx = { + .name = "ssam:01:11:01:00:00", + .parent = &ssam_node_root, +}; + +/* HID keyboard. */ +static const struct software_node ssam_node_hid_main_keyboard = { + .name = "ssam:01:15:02:01:00", + .parent = &ssam_node_root, +}; + +/* HID touchpad. */ +static const struct software_node ssam_node_hid_main_touchpad = { + .name = "ssam:01:15:02:03:00", + .parent = &ssam_node_root, +}; + +/* HID device instance 5 (unknown HID device). */ +static const struct software_node ssam_node_hid_main_iid5 = { + .name = "ssam:01:15:02:05:00", + .parent = &ssam_node_root, +}; + +/* HID keyboard (base hub). */ +static const struct software_node ssam_node_hid_base_keyboard = { + .name = "ssam:01:15:02:01:00", + .parent = &ssam_node_hub_base, +}; + +/* HID touchpad (base hub). */ +static const struct software_node ssam_node_hid_base_touchpad = { + .name = "ssam:01:15:02:03:00", + .parent = &ssam_node_hub_base, +}; + +/* HID device instance 5 (unknown HID device, base hub). */ +static const struct software_node ssam_node_hid_base_iid5 = { + .name = "ssam:01:15:02:05:00", + .parent = &ssam_node_hub_base, +}; + +/* HID device instance 6 (unknown HID device, base hub). */ +static const struct software_node ssam_node_hid_base_iid6 = { + .name = "ssam:01:15:02:06:00", + .parent = &ssam_node_hub_base, +}; + +/* Devices for Surface Book 2. */ +static const struct software_node *ssam_node_group_sb2[] = { + &ssam_node_root, + &ssam_node_tmp_pprof, + NULL, +}; + +/* Devices for Surface Book 3. */ +static const struct software_node *ssam_node_group_sb3[] = { + &ssam_node_root, + &ssam_node_hub_base, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_bat_sb3base, + &ssam_node_tmp_pprof, + &ssam_node_bas_dtx, + &ssam_node_hid_base_keyboard, + &ssam_node_hid_base_touchpad, + &ssam_node_hid_base_iid5, + &ssam_node_hid_base_iid6, + NULL, +}; + +/* Devices for Surface Laptop 1. */ +static const struct software_node *ssam_node_group_sl1[] = { + &ssam_node_root, + &ssam_node_tmp_pprof, + NULL, +}; + +/* Devices for Surface Laptop 2. */ +static const struct software_node *ssam_node_group_sl2[] = { + &ssam_node_root, + &ssam_node_tmp_pprof, + NULL, +}; + +/* Devices for Surface Laptop 3. */ +static const struct software_node *ssam_node_group_sl3[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_pprof, + &ssam_node_hid_main_keyboard, + &ssam_node_hid_main_touchpad, + &ssam_node_hid_main_iid5, + NULL, +}; + +/* Devices for Surface Laptop Go. */ +static const struct software_node *ssam_node_group_slg1[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_pprof, + NULL, +}; + +/* Devices for Surface Pro 5. */ +static const struct software_node *ssam_node_group_sp5[] = { + &ssam_node_root, + &ssam_node_tmp_pprof, + NULL, +}; + +/* Devices for Surface Pro 6. */ +static const struct software_node *ssam_node_group_sp6[] = { + &ssam_node_root, + &ssam_node_tmp_pprof, + NULL, +}; + +/* Devices for Surface Pro 7 and Surface Pro 7+. */ +static const struct software_node *ssam_node_group_sp7[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_pprof, + NULL, +}; + + +/* -- Device registry helper functions. ------------------------------------- */ + +static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid) +{ + u8 d, tc, tid, iid, fn; + int n; + + n = sscanf(str, "ssam:%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn); + if (n != 5) + return -EINVAL; + + uid->domain = d; + uid->category = tc; + uid->target = tid; + uid->instance = iid; + uid->function = fn; + + return 0; +} + +static int ssam_hub_remove_devices_fn(struct device *dev, void *data) +{ + if (!is_ssam_device(dev)) + return 0; + + ssam_device_remove(to_ssam_device(dev)); + return 0; +} + +static void ssam_hub_remove_devices(struct device *parent) +{ + device_for_each_child_reverse(parent, NULL, ssam_hub_remove_devices_fn); +} + +static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node) +{ + struct ssam_device_uid uid; + struct ssam_device *sdev; + int status; + + status = ssam_uid_from_string(fwnode_get_name(node), &uid); + if (status) + return status; + + sdev = ssam_device_alloc(ctrl, uid); + if (!sdev) + return -ENOMEM; + + sdev->dev.parent = parent; + sdev->dev.fwnode = node; + + status = ssam_device_add(sdev); + if (status) + ssam_device_put(sdev); + + return status; +} + +static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node) +{ + struct fwnode_handle *child; + int status; + + fwnode_for_each_child_node(node, child) { + /* + * Try to add the device specified in the firmware node. If + * this fails with -EINVAL, the node does not specify any SSAM + * device, so ignore it and continue with the next one. + */ + + status = ssam_hub_add_device(parent, ctrl, child); + if (status && status != -EINVAL) + goto err; + } + + return 0; +err: + ssam_hub_remove_devices(parent); + return status; +} + + +/* -- SSAM base-hub driver. ------------------------------------------------- */ + +/* + * Some devices (especially battery) may need a bit of time to be fully usable + * after being (re-)connected. This delay has been determined via + * experimentation. + */ +#define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500) + +enum ssam_base_hub_state { + SSAM_BASE_HUB_UNINITIALIZED, + SSAM_BASE_HUB_CONNECTED, + SSAM_BASE_HUB_DISCONNECTED, +}; + +struct ssam_base_hub { + struct ssam_device *sdev; + + enum ssam_base_hub_state state; + struct delayed_work update_work; + + struct ssam_event_notifier notif; +}; + +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0d, + .instance_id = 0x00, +}); + +#define SSAM_BAS_OPMODE_TABLET 0x00 +#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c + +static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_hub_state *state) +{ + u8 opmode; + int status; + + status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode); + if (status < 0) { + dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status); + return status; + } + + if (opmode != SSAM_BAS_OPMODE_TABLET) + *state = SSAM_BASE_HUB_CONNECTED; + else + *state = SSAM_BASE_HUB_DISCONNECTED; + + return 0; +} + +static ssize_t ssam_base_hub_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ssam_base_hub *hub = dev_get_drvdata(dev); + bool connected = hub->state == SSAM_BASE_HUB_CONNECTED; + + return sysfs_emit(buf, "%d\n", connected); +} + +static struct device_attribute ssam_base_hub_attr_state = + __ATTR(state, 0444, ssam_base_hub_state_show, NULL); + +static struct attribute *ssam_base_hub_attrs[] = { + &ssam_base_hub_attr_state.attr, + NULL, +}; + +static const struct attribute_group ssam_base_hub_group = { + .attrs = ssam_base_hub_attrs, +}; + +static void ssam_base_hub_update_workfn(struct work_struct *work) +{ + struct ssam_base_hub *hub = container_of(work, struct ssam_base_hub, update_work.work); + struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev); + enum ssam_base_hub_state state; + int status = 0; + + status = ssam_base_hub_query_state(hub, &state); + if (status) + return; + + if (hub->state == state) + return; + hub->state = state; + + if (hub->state == SSAM_BASE_HUB_CONNECTED) + status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node); + else + ssam_hub_remove_devices(&hub->sdev->dev); + + if (status) + dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status); +} + +static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) +{ + struct ssam_base_hub *hub = container_of(nf, struct ssam_base_hub, notif); + unsigned long delay; + + if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION) + return 0; + + if (event->length < 1) { + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); + return 0; + } + + /* + * Delay update when the base is being connected to give devices/EC + * some time to set up. + */ + delay = event->data[0] ? SSAM_BASE_UPDATE_CONNECT_DELAY : 0; + + schedule_delayed_work(&hub->update_work, delay); + + /* + * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and + * consumed by the detachment system driver. We're just a (more or less) + * silent observer. + */ + return 0; +} + +static int __maybe_unused ssam_base_hub_resume(struct device *dev) +{ + struct ssam_base_hub *hub = dev_get_drvdata(dev); + + schedule_delayed_work(&hub->update_work, 0); + return 0; +} +static SIMPLE_DEV_PM_OPS(ssam_base_hub_pm_ops, NULL, ssam_base_hub_resume); + +static int ssam_base_hub_probe(struct ssam_device *sdev) +{ + struct ssam_base_hub *hub; + int status; + + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + hub->sdev = sdev; + hub->state = SSAM_BASE_HUB_UNINITIALIZED; + + hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ + hub->notif.base.fn = ssam_base_hub_notif; + hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; + hub->notif.event.id.target_category = SSAM_SSH_TC_BAS, + hub->notif.event.id.instance = 0, + hub->notif.event.mask = SSAM_EVENT_MASK_NONE; + hub->notif.event.flags = SSAM_EVENT_SEQUENCED; + + INIT_DELAYED_WORK(&hub->update_work, ssam_base_hub_update_workfn); + + ssam_device_set_drvdata(sdev, hub); + + status = ssam_notifier_register(sdev->ctrl, &hub->notif); + if (status) + return status; + + status = sysfs_create_group(&sdev->dev.kobj, &ssam_base_hub_group); + if (status) + goto err; + + schedule_delayed_work(&hub->update_work, 0); + return 0; + +err: + ssam_notifier_unregister(sdev->ctrl, &hub->notif); + cancel_delayed_work_sync(&hub->update_work); + ssam_hub_remove_devices(&sdev->dev); + return status; +} + +static void ssam_base_hub_remove(struct ssam_device *sdev) +{ + struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev); + + sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group); + + ssam_notifier_unregister(sdev->ctrl, &hub->notif); + cancel_delayed_work_sync(&hub->update_work); + ssam_hub_remove_devices(&sdev->dev); +} + +static const struct ssam_device_id ssam_base_hub_match[] = { + { SSAM_VDEV(HUB, 0x02, SSAM_ANY_IID, 0x00) }, + { }, +}; + +static struct ssam_device_driver ssam_base_hub_driver = { + .probe = ssam_base_hub_probe, + .remove = ssam_base_hub_remove, + .match_table = ssam_base_hub_match, + .driver = { + .name = "surface_aggregator_base_hub", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &ssam_base_hub_pm_ops, + }, +}; + + +/* -- SSAM platform/meta-hub driver. ---------------------------------------- */ + +static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Pro 4, 5, and 6 (OMBR < 0x10) */ + { "MSHW0081", (unsigned long)ssam_node_group_sp5 }, + + /* Surface Pro 6 (OMBR >= 0x10) */ + { "MSHW0111", (unsigned long)ssam_node_group_sp6 }, + + /* Surface Pro 7 */ + { "MSHW0116", (unsigned long)ssam_node_group_sp7 }, + + /* Surface Pro 7+ */ + { "MSHW0119", (unsigned long)ssam_node_group_sp7 }, + + /* Surface Book 2 */ + { "MSHW0107", (unsigned long)ssam_node_group_sb2 }, + + /* Surface Book 3 */ + { "MSHW0117", (unsigned long)ssam_node_group_sb3 }, + + /* Surface Laptop 1 */ + { "MSHW0086", (unsigned long)ssam_node_group_sl1 }, + + /* Surface Laptop 2 */ + { "MSHW0112", (unsigned long)ssam_node_group_sl2 }, + + /* Surface Laptop 3 (13", Intel) */ + { "MSHW0114", (unsigned long)ssam_node_group_sl3 }, + + /* Surface Laptop 3 (15", AMD) */ + { "MSHW0110", (unsigned long)ssam_node_group_sl3 }, + + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + + { }, +}; +MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match); + +static int ssam_platform_hub_probe(struct platform_device *pdev) +{ + const struct software_node **nodes; + struct ssam_controller *ctrl; + struct fwnode_handle *root; + int status; + + nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev); + if (!nodes) + return -ENODEV; + + /* + * As we're adding the SSAM client devices as children under this device + * and not the SSAM controller, we need to add a device link to the + * controller to ensure that we remove all of our devices before the + * controller is removed. This also guarantees proper ordering for + * suspend/resume of the devices on this hub. + */ + ctrl = ssam_client_bind(&pdev->dev); + if (IS_ERR(ctrl)) + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + status = software_node_register_node_group(nodes); + if (status) + return status; + + root = software_node_fwnode(&ssam_node_root); + if (!root) { + software_node_unregister_node_group(nodes); + return -ENOENT; + } + + set_secondary_fwnode(&pdev->dev, root); + + status = ssam_hub_add_devices(&pdev->dev, ctrl, root); + if (status) { + set_secondary_fwnode(&pdev->dev, NULL); + software_node_unregister_node_group(nodes); + } + + platform_set_drvdata(pdev, nodes); + return status; +} + +static int ssam_platform_hub_remove(struct platform_device *pdev) +{ + const struct software_node **nodes = platform_get_drvdata(pdev); + + ssam_hub_remove_devices(&pdev->dev); + set_secondary_fwnode(&pdev->dev, NULL); + software_node_unregister_node_group(nodes); + return 0; +} + +static struct platform_driver ssam_platform_hub_driver = { + .probe = ssam_platform_hub_probe, + .remove = ssam_platform_hub_remove, + .driver = { + .name = "surface_aggregator_platform_hub", + .acpi_match_table = ssam_platform_hub_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + + +/* -- Module initialization. ------------------------------------------------ */ + +static int __init ssam_device_hub_init(void) +{ + int status; + + status = platform_driver_register(&ssam_platform_hub_driver); + if (status) + return status; + + status = ssam_device_driver_register(&ssam_base_hub_driver); + if (status) + platform_driver_unregister(&ssam_platform_hub_driver); + + return status; +} +module_init(ssam_device_hub_init); + +static void __exit ssam_device_hub_exit(void) +{ + ssam_device_driver_unregister(&ssam_base_hub_driver); + platform_driver_unregister(&ssam_platform_hub_driver); +} +module_exit(ssam_device_hub_exit); + +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); +MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c new file mode 100644 index 0000000000000000000000000000000000000000..63ce587e79e3ba2470778b2dfc5386dfcb0d8ea4 --- /dev/null +++ b/drivers/platform/surface/surface_dtx.c @@ -0,0 +1,1289 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface Book (gen. 2 and later) detachment system (DTX) driver. + * + * Provides a user-space interface to properly handle clipboard/tablet + * (containing screen and processor) detachment from the base of the device + * (containing the keyboard and optionally a discrete GPU). Allows to + * acknowledge (to speed things up), abort (e.g. in case the dGPU is still in + * use), or request detachment via user-space. + * + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> + */ + +#include <linux/fs.h> +#include <linux/input.h> +#include <linux/ioctl.h> +#include <linux/kernel.h> +#include <linux/kfifo.h> +#include <linux/kref.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/poll.h> +#include <linux/rwsem.h> +#include <linux/slab.h> +#include <linux/workqueue.h> + +#include <linux/surface_aggregator/controller.h> +#include <linux/surface_aggregator/device.h> +#include <linux/surface_aggregator/dtx.h> + + +/* -- SSAM interface. ------------------------------------------------------- */ + +enum sam_event_cid_bas { + SAM_EVENT_CID_DTX_CONNECTION = 0x0c, + SAM_EVENT_CID_DTX_REQUEST = 0x0e, + SAM_EVENT_CID_DTX_CANCEL = 0x0f, + SAM_EVENT_CID_DTX_LATCH_STATUS = 0x11, +}; + +enum ssam_bas_base_state { + SSAM_BAS_BASE_STATE_DETACH_SUCCESS = 0x00, + SSAM_BAS_BASE_STATE_ATTACHED = 0x01, + SSAM_BAS_BASE_STATE_NOT_FEASIBLE = 0x02, +}; + +enum ssam_bas_latch_status { + SSAM_BAS_LATCH_STATUS_CLOSED = 0x00, + SSAM_BAS_LATCH_STATUS_OPENED = 0x01, + SSAM_BAS_LATCH_STATUS_FAILED_TO_OPEN = 0x02, + SSAM_BAS_LATCH_STATUS_FAILED_TO_REMAIN_OPEN = 0x03, + SSAM_BAS_LATCH_STATUS_FAILED_TO_CLOSE = 0x04, +}; + +enum ssam_bas_cancel_reason { + SSAM_BAS_CANCEL_REASON_NOT_FEASIBLE = 0x00, /* Low battery. */ + SSAM_BAS_CANCEL_REASON_TIMEOUT = 0x02, + SSAM_BAS_CANCEL_REASON_FAILED_TO_OPEN = 0x03, + SSAM_BAS_CANCEL_REASON_FAILED_TO_REMAIN_OPEN = 0x04, + SSAM_BAS_CANCEL_REASON_FAILED_TO_CLOSE = 0x05, +}; + +struct ssam_bas_base_info { + u8 state; + u8 base_id; +} __packed; + +static_assert(sizeof(struct ssam_bas_base_info) == 2); + +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x06, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x07, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x08, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x09, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0a, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0b, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0c, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0d, + .instance_id = 0x00, +}); + +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x11, + .instance_id = 0x00, +}); + + +/* -- Main structures. ------------------------------------------------------ */ + +enum sdtx_device_state { + SDTX_DEVICE_SHUTDOWN_BIT = BIT(0), + SDTX_DEVICE_DIRTY_BASE_BIT = BIT(1), + SDTX_DEVICE_DIRTY_MODE_BIT = BIT(2), + SDTX_DEVICE_DIRTY_LATCH_BIT = BIT(3), +}; + +struct sdtx_device { + struct kref kref; + struct rw_semaphore lock; /* Guards device and controller reference. */ + + struct device *dev; + struct ssam_controller *ctrl; + unsigned long flags; + + struct miscdevice mdev; + wait_queue_head_t waitq; + struct mutex write_lock; /* Guards order of events/notifications. */ + struct rw_semaphore client_lock; /* Guards client list. */ + struct list_head client_list; + + struct delayed_work state_work; + struct { + struct ssam_bas_base_info base; + u8 device_mode; + u8 latch_status; + } state; + + struct delayed_work mode_work; + struct input_dev *mode_switch; + + struct ssam_event_notifier notif; +}; + +enum sdtx_client_state { + SDTX_CLIENT_EVENTS_ENABLED_BIT = BIT(0), +}; + +struct sdtx_client { + struct sdtx_device *ddev; + struct list_head node; + unsigned long flags; + + struct fasync_struct *fasync; + + struct mutex read_lock; /* Guards FIFO buffer read access. */ + DECLARE_KFIFO(buffer, u8, 512); +}; + +static void __sdtx_device_release(struct kref *kref) +{ + struct sdtx_device *ddev = container_of(kref, struct sdtx_device, kref); + + mutex_destroy(&ddev->write_lock); + kfree(ddev); +} + +static struct sdtx_device *sdtx_device_get(struct sdtx_device *ddev) +{ + if (ddev) + kref_get(&ddev->kref); + + return ddev; +} + +static void sdtx_device_put(struct sdtx_device *ddev) +{ + if (ddev) + kref_put(&ddev->kref, __sdtx_device_release); +} + + +/* -- Firmware value translations. ------------------------------------------ */ + +static u16 sdtx_translate_base_state(struct sdtx_device *ddev, u8 state) +{ + switch (state) { + case SSAM_BAS_BASE_STATE_ATTACHED: + return SDTX_BASE_ATTACHED; + + case SSAM_BAS_BASE_STATE_DETACH_SUCCESS: + return SDTX_BASE_DETACHED; + + case SSAM_BAS_BASE_STATE_NOT_FEASIBLE: + return SDTX_DETACH_NOT_FEASIBLE; + + default: + dev_err(ddev->dev, "unknown base state: %#04x\n", state); + return SDTX_UNKNOWN(state); + } +} + +static u16 sdtx_translate_latch_status(struct sdtx_device *ddev, u8 status) +{ + switch (status) { + case SSAM_BAS_LATCH_STATUS_CLOSED: + return SDTX_LATCH_CLOSED; + + case SSAM_BAS_LATCH_STATUS_OPENED: + return SDTX_LATCH_OPENED; + + case SSAM_BAS_LATCH_STATUS_FAILED_TO_OPEN: + return SDTX_ERR_FAILED_TO_OPEN; + + case SSAM_BAS_LATCH_STATUS_FAILED_TO_REMAIN_OPEN: + return SDTX_ERR_FAILED_TO_REMAIN_OPEN; + + case SSAM_BAS_LATCH_STATUS_FAILED_TO_CLOSE: + return SDTX_ERR_FAILED_TO_CLOSE; + + default: + dev_err(ddev->dev, "unknown latch status: %#04x\n", status); + return SDTX_UNKNOWN(status); + } +} + +static u16 sdtx_translate_cancel_reason(struct sdtx_device *ddev, u8 reason) +{ + switch (reason) { + case SSAM_BAS_CANCEL_REASON_NOT_FEASIBLE: + return SDTX_DETACH_NOT_FEASIBLE; + + case SSAM_BAS_CANCEL_REASON_TIMEOUT: + return SDTX_DETACH_TIMEDOUT; + + case SSAM_BAS_CANCEL_REASON_FAILED_TO_OPEN: + return SDTX_ERR_FAILED_TO_OPEN; + + case SSAM_BAS_CANCEL_REASON_FAILED_TO_REMAIN_OPEN: + return SDTX_ERR_FAILED_TO_REMAIN_OPEN; + + case SSAM_BAS_CANCEL_REASON_FAILED_TO_CLOSE: + return SDTX_ERR_FAILED_TO_CLOSE; + + default: + dev_err(ddev->dev, "unknown cancel reason: %#04x\n", reason); + return SDTX_UNKNOWN(reason); + } +} + + +/* -- IOCTLs. --------------------------------------------------------------- */ + +static int sdtx_ioctl_get_base_info(struct sdtx_device *ddev, + struct sdtx_base_info __user *buf) +{ + struct ssam_bas_base_info raw; + struct sdtx_base_info info; + int status; + + lockdep_assert_held_read(&ddev->lock); + + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &raw); + if (status < 0) + return status; + + info.state = sdtx_translate_base_state(ddev, raw.state); + info.base_id = SDTX_BASE_TYPE_SSH(raw.base_id); + + if (copy_to_user(buf, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +static int sdtx_ioctl_get_device_mode(struct sdtx_device *ddev, u16 __user *buf) +{ + u8 mode; + int status; + + lockdep_assert_held_read(&ddev->lock); + + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); + if (status < 0) + return status; + + return put_user(mode, buf); +} + +static int sdtx_ioctl_get_latch_status(struct sdtx_device *ddev, u16 __user *buf) +{ + u8 latch; + int status; + + lockdep_assert_held_read(&ddev->lock); + + status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch); + if (status < 0) + return status; + + return put_user(sdtx_translate_latch_status(ddev, latch), buf); +} + +static long __surface_dtx_ioctl(struct sdtx_client *client, unsigned int cmd, unsigned long arg) +{ + struct sdtx_device *ddev = client->ddev; + + lockdep_assert_held_read(&ddev->lock); + + switch (cmd) { + case SDTX_IOCTL_EVENTS_ENABLE: + set_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags); + return 0; + + case SDTX_IOCTL_EVENTS_DISABLE: + clear_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags); + return 0; + + case SDTX_IOCTL_LATCH_LOCK: + return ssam_retry(ssam_bas_latch_lock, ddev->ctrl); + + case SDTX_IOCTL_LATCH_UNLOCK: + return ssam_retry(ssam_bas_latch_unlock, ddev->ctrl); + + case SDTX_IOCTL_LATCH_REQUEST: + return ssam_retry(ssam_bas_latch_request, ddev->ctrl); + + case SDTX_IOCTL_LATCH_CONFIRM: + return ssam_retry(ssam_bas_latch_confirm, ddev->ctrl); + + case SDTX_IOCTL_LATCH_HEARTBEAT: + return ssam_retry(ssam_bas_latch_heartbeat, ddev->ctrl); + + case SDTX_IOCTL_LATCH_CANCEL: + return ssam_retry(ssam_bas_latch_cancel, ddev->ctrl); + + case SDTX_IOCTL_GET_BASE_INFO: + return sdtx_ioctl_get_base_info(ddev, (struct sdtx_base_info __user *)arg); + + case SDTX_IOCTL_GET_DEVICE_MODE: + return sdtx_ioctl_get_device_mode(ddev, (u16 __user *)arg); + + case SDTX_IOCTL_GET_LATCH_STATUS: + return sdtx_ioctl_get_latch_status(ddev, (u16 __user *)arg); + + default: + return -EINVAL; + } +} + +static long surface_dtx_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct sdtx_client *client = file->private_data; + long status; + + if (down_read_killable(&client->ddev->lock)) + return -ERESTARTSYS; + + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) { + up_read(&client->ddev->lock); + return -ENODEV; + } + + status = __surface_dtx_ioctl(client, cmd, arg); + + up_read(&client->ddev->lock); + return status; +} + + +/* -- File operations. ------------------------------------------------------ */ + +static int surface_dtx_open(struct inode *inode, struct file *file) +{ + struct sdtx_device *ddev = container_of(file->private_data, struct sdtx_device, mdev); + struct sdtx_client *client; + + /* Initialize client. */ + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->ddev = sdtx_device_get(ddev); + + INIT_LIST_HEAD(&client->node); + + mutex_init(&client->read_lock); + INIT_KFIFO(client->buffer); + + file->private_data = client; + + /* Attach client. */ + down_write(&ddev->client_lock); + + /* + * Do not add a new client if the device has been shut down. Note that + * it's enough to hold the client_lock here as, during shutdown, we + * only acquire that lock and remove clients after marking the device + * as shut down. + */ + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { + up_write(&ddev->client_lock); + sdtx_device_put(client->ddev); + kfree(client); + return -ENODEV; + } + + list_add_tail(&client->node, &ddev->client_list); + up_write(&ddev->client_lock); + + stream_open(inode, file); + return 0; +} + +static int surface_dtx_release(struct inode *inode, struct file *file) +{ + struct sdtx_client *client = file->private_data; + + /* Detach client. */ + down_write(&client->ddev->client_lock); + list_del(&client->node); + up_write(&client->ddev->client_lock); + + /* Free client. */ + sdtx_device_put(client->ddev); + mutex_destroy(&client->read_lock); + kfree(client); + + return 0; +} + +static ssize_t surface_dtx_read(struct file *file, char __user *buf, size_t count, loff_t *offs) +{ + struct sdtx_client *client = file->private_data; + struct sdtx_device *ddev = client->ddev; + unsigned int copied; + int status = 0; + + if (down_read_killable(&ddev->lock)) + return -ERESTARTSYS; + + /* Make sure we're not shut down. */ + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { + up_read(&ddev->lock); + return -ENODEV; + } + + do { + /* Check availability, wait if necessary. */ + if (kfifo_is_empty(&client->buffer)) { + up_read(&ddev->lock); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + status = wait_event_interruptible(ddev->waitq, + !kfifo_is_empty(&client->buffer) || + test_bit(SDTX_DEVICE_SHUTDOWN_BIT, + &ddev->flags)); + if (status < 0) + return status; + + if (down_read_killable(&ddev->lock)) + return -ERESTARTSYS; + + /* Need to check that we're not shut down again. */ + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { + up_read(&ddev->lock); + return -ENODEV; + } + } + + /* Try to read from FIFO. */ + if (mutex_lock_interruptible(&client->read_lock)) { + up_read(&ddev->lock); + return -ERESTARTSYS; + } + + status = kfifo_to_user(&client->buffer, buf, count, &copied); + mutex_unlock(&client->read_lock); + + if (status < 0) { + up_read(&ddev->lock); + return status; + } + + /* We might not have gotten anything, check this here. */ + if (copied == 0 && (file->f_flags & O_NONBLOCK)) { + up_read(&ddev->lock); + return -EAGAIN; + } + } while (copied == 0); + + up_read(&ddev->lock); + return copied; +} + +static __poll_t surface_dtx_poll(struct file *file, struct poll_table_struct *pt) +{ + struct sdtx_client *client = file->private_data; + __poll_t events = 0; + + if (down_read_killable(&client->ddev->lock)) + return -ERESTARTSYS; + + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) { + up_read(&client->ddev->lock); + return EPOLLHUP | EPOLLERR; + } + + poll_wait(file, &client->ddev->waitq, pt); + + if (!kfifo_is_empty(&client->buffer)) + events |= EPOLLIN | EPOLLRDNORM; + + up_read(&client->ddev->lock); + return events; +} + +static int surface_dtx_fasync(int fd, struct file *file, int on) +{ + struct sdtx_client *client = file->private_data; + + return fasync_helper(fd, file, on, &client->fasync); +} + +static const struct file_operations surface_dtx_fops = { + .owner = THIS_MODULE, + .open = surface_dtx_open, + .release = surface_dtx_release, + .read = surface_dtx_read, + .poll = surface_dtx_poll, + .fasync = surface_dtx_fasync, + .unlocked_ioctl = surface_dtx_ioctl, + .compat_ioctl = surface_dtx_ioctl, + .llseek = no_llseek, +}; + + +/* -- Event handling/forwarding. -------------------------------------------- */ + +/* + * The device operation mode is not immediately updated on the EC when the + * base has been connected, i.e. querying the device mode inside the + * connection event callback yields an outdated value. Thus, we can only + * determine the new tablet-mode switch and device mode values after some + * time. + * + * These delays have been chosen by experimenting. We first delay on connect + * events, then check and validate the device mode against the base state and + * if invalid delay again by the "recheck" delay. + */ +#define SDTX_DEVICE_MODE_DELAY_CONNECT msecs_to_jiffies(100) +#define SDTX_DEVICE_MODE_DELAY_RECHECK msecs_to_jiffies(100) + +struct sdtx_status_event { + struct sdtx_event e; + __u16 v; +} __packed; + +struct sdtx_base_info_event { + struct sdtx_event e; + struct sdtx_base_info v; +} __packed; + +union sdtx_generic_event { + struct sdtx_event common; + struct sdtx_status_event status; + struct sdtx_base_info_event base; +}; + +static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay); + +/* Must be executed with ddev->write_lock held. */ +static void sdtx_push_event(struct sdtx_device *ddev, struct sdtx_event *evt) +{ + const size_t len = sizeof(struct sdtx_event) + evt->length; + struct sdtx_client *client; + + lockdep_assert_held(&ddev->write_lock); + + down_read(&ddev->client_lock); + list_for_each_entry(client, &ddev->client_list, node) { + if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags)) + continue; + + if (likely(kfifo_avail(&client->buffer) >= len)) + kfifo_in(&client->buffer, (const u8 *)evt, len); + else + dev_warn(ddev->dev, "event buffer overrun\n"); + + kill_fasync(&client->fasync, SIGIO, POLL_IN); + } + up_read(&ddev->client_lock); + + wake_up_interruptible(&ddev->waitq); +} + +static u32 sdtx_notifier(struct ssam_event_notifier *nf, const struct ssam_event *in) +{ + struct sdtx_device *ddev = container_of(nf, struct sdtx_device, notif); + union sdtx_generic_event event; + size_t len; + + /* Validate event payload length. */ + switch (in->command_id) { + case SAM_EVENT_CID_DTX_CONNECTION: + len = 2 * sizeof(u8); + break; + + case SAM_EVENT_CID_DTX_REQUEST: + len = 0; + break; + + case SAM_EVENT_CID_DTX_CANCEL: + len = sizeof(u8); + break; + + case SAM_EVENT_CID_DTX_LATCH_STATUS: + len = sizeof(u8); + break; + + default: + return 0; + } + + if (in->length != len) { + dev_err(ddev->dev, + "unexpected payload size for event %#04x: got %u, expected %zu\n", + in->command_id, in->length, len); + return 0; + } + + mutex_lock(&ddev->write_lock); + + /* Translate event. */ + switch (in->command_id) { + case SAM_EVENT_CID_DTX_CONNECTION: + clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); + + /* If state has not changed: do not send new event. */ + if (ddev->state.base.state == in->data[0] && + ddev->state.base.base_id == in->data[1]) + goto out; + + ddev->state.base.state = in->data[0]; + ddev->state.base.base_id = in->data[1]; + + event.base.e.length = sizeof(struct sdtx_base_info); + event.base.e.code = SDTX_EVENT_BASE_CONNECTION; + event.base.v.state = sdtx_translate_base_state(ddev, in->data[0]); + event.base.v.base_id = SDTX_BASE_TYPE_SSH(in->data[1]); + break; + + case SAM_EVENT_CID_DTX_REQUEST: + event.common.code = SDTX_EVENT_REQUEST; + event.common.length = 0; + break; + + case SAM_EVENT_CID_DTX_CANCEL: + event.status.e.length = sizeof(u16); + event.status.e.code = SDTX_EVENT_CANCEL; + event.status.v = sdtx_translate_cancel_reason(ddev, in->data[0]); + break; + + case SAM_EVENT_CID_DTX_LATCH_STATUS: + clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); + + /* If state has not changed: do not send new event. */ + if (ddev->state.latch_status == in->data[0]) + goto out; + + ddev->state.latch_status = in->data[0]; + + event.status.e.length = sizeof(u16); + event.status.e.code = SDTX_EVENT_LATCH_STATUS; + event.status.v = sdtx_translate_latch_status(ddev, in->data[0]); + break; + } + + sdtx_push_event(ddev, &event.common); + + /* Update device mode on base connection change. */ + if (in->command_id == SAM_EVENT_CID_DTX_CONNECTION) { + unsigned long delay; + + delay = in->data[0] ? SDTX_DEVICE_MODE_DELAY_CONNECT : 0; + sdtx_update_device_mode(ddev, delay); + } + +out: + mutex_unlock(&ddev->write_lock); + return SSAM_NOTIF_HANDLED; +} + + +/* -- State update functions. ----------------------------------------------- */ + +static bool sdtx_device_mode_invalid(u8 mode, u8 base_state) +{ + return ((base_state == SSAM_BAS_BASE_STATE_ATTACHED) && + (mode == SDTX_DEVICE_MODE_TABLET)) || + ((base_state == SSAM_BAS_BASE_STATE_DETACH_SUCCESS) && + (mode != SDTX_DEVICE_MODE_TABLET)); +} + +static void sdtx_device_mode_workfn(struct work_struct *work) +{ + struct sdtx_device *ddev = container_of(work, struct sdtx_device, mode_work.work); + struct sdtx_status_event event; + struct ssam_bas_base_info base; + int status, tablet; + u8 mode; + + /* Get operation mode. */ + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); + if (status) { + dev_err(ddev->dev, "failed to get device mode: %d\n", status); + return; + } + + /* Get base info. */ + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base); + if (status) { + dev_err(ddev->dev, "failed to get base info: %d\n", status); + return; + } + + /* + * In some cases (specifically when attaching the base), the device + * mode isn't updated right away. Thus we check if the device mode + * makes sense for the given base state and try again later if it + * doesn't. + */ + if (sdtx_device_mode_invalid(mode, base.state)) { + dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); + sdtx_update_device_mode(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK); + return; + } + + mutex_lock(&ddev->write_lock); + clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); + + /* Avoid sending duplicate device-mode events. */ + if (ddev->state.device_mode == mode) { + mutex_unlock(&ddev->write_lock); + return; + } + + ddev->state.device_mode = mode; + + event.e.length = sizeof(u16); + event.e.code = SDTX_EVENT_DEVICE_MODE; + event.v = mode; + + sdtx_push_event(ddev, &event.e); + + /* Send SW_TABLET_MODE event. */ + tablet = mode != SDTX_DEVICE_MODE_LAPTOP; + input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); + input_sync(ddev->mode_switch); + + mutex_unlock(&ddev->write_lock); +} + +static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay) +{ + schedule_delayed_work(&ddev->mode_work, delay); +} + +/* Must be executed with ddev->write_lock held. */ +static void __sdtx_device_state_update_base(struct sdtx_device *ddev, + struct ssam_bas_base_info info) +{ + struct sdtx_base_info_event event; + + lockdep_assert_held(&ddev->write_lock); + + /* Prevent duplicate events. */ + if (ddev->state.base.state == info.state && + ddev->state.base.base_id == info.base_id) + return; + + ddev->state.base = info; + + event.e.length = sizeof(struct sdtx_base_info); + event.e.code = SDTX_EVENT_BASE_CONNECTION; + event.v.state = sdtx_translate_base_state(ddev, info.state); + event.v.base_id = SDTX_BASE_TYPE_SSH(info.base_id); + + sdtx_push_event(ddev, &event.e); +} + +/* Must be executed with ddev->write_lock held. */ +static void __sdtx_device_state_update_mode(struct sdtx_device *ddev, u8 mode) +{ + struct sdtx_status_event event; + int tablet; + + /* + * Note: This function must be called after updating the base state + * via __sdtx_device_state_update_base(), as we rely on the updated + * base state value in the validity check below. + */ + + lockdep_assert_held(&ddev->write_lock); + + if (sdtx_device_mode_invalid(mode, ddev->state.base.state)) { + dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); + sdtx_update_device_mode(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK); + return; + } + + /* Prevent duplicate events. */ + if (ddev->state.device_mode == mode) + return; + + ddev->state.device_mode = mode; + + /* Send event. */ + event.e.length = sizeof(u16); + event.e.code = SDTX_EVENT_DEVICE_MODE; + event.v = mode; + + sdtx_push_event(ddev, &event.e); + + /* Send SW_TABLET_MODE event. */ + tablet = mode != SDTX_DEVICE_MODE_LAPTOP; + input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); + input_sync(ddev->mode_switch); +} + +/* Must be executed with ddev->write_lock held. */ +static void __sdtx_device_state_update_latch(struct sdtx_device *ddev, u8 status) +{ + struct sdtx_status_event event; + + lockdep_assert_held(&ddev->write_lock); + + /* Prevent duplicate events. */ + if (ddev->state.latch_status == status) + return; + + ddev->state.latch_status = status; + + event.e.length = sizeof(struct sdtx_base_info); + event.e.code = SDTX_EVENT_BASE_CONNECTION; + event.v = sdtx_translate_latch_status(ddev, status); + + sdtx_push_event(ddev, &event.e); +} + +static void sdtx_device_state_workfn(struct work_struct *work) +{ + struct sdtx_device *ddev = container_of(work, struct sdtx_device, state_work.work); + struct ssam_bas_base_info base; + u8 mode, latch; + int status; + + /* Mark everything as dirty. */ + set_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); + set_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); + set_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); + + /* + * Ensure that the state gets marked as dirty before continuing to + * query it. Necessary to ensure that clear_bit() calls in + * sdtx_notifier() and sdtx_device_mode_workfn() actually clear these + * bits if an event is received while updating the state here. + */ + smp_mb__after_atomic(); + + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base); + if (status) { + dev_err(ddev->dev, "failed to get base state: %d\n", status); + return; + } + + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); + if (status) { + dev_err(ddev->dev, "failed to get device mode: %d\n", status); + return; + } + + status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch); + if (status) { + dev_err(ddev->dev, "failed to get latch status: %d\n", status); + return; + } + + mutex_lock(&ddev->write_lock); + + /* + * If the respective dirty-bit has been cleared, an event has been + * received, updating this state. The queried state may thus be out of + * date. At this point, we can safely assume that the state provided + * by the event is either up to date, or we're about to receive + * another event updating it. + */ + + if (test_and_clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags)) + __sdtx_device_state_update_base(ddev, base); + + if (test_and_clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags)) + __sdtx_device_state_update_mode(ddev, mode); + + if (test_and_clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags)) + __sdtx_device_state_update_latch(ddev, latch); + + mutex_unlock(&ddev->write_lock); +} + +static void sdtx_update_device_state(struct sdtx_device *ddev, unsigned long delay) +{ + schedule_delayed_work(&ddev->state_work, delay); +} + + +/* -- Common device initialization. ----------------------------------------- */ + +static int sdtx_device_init(struct sdtx_device *ddev, struct device *dev, + struct ssam_controller *ctrl) +{ + int status, tablet_mode; + + /* Basic initialization. */ + kref_init(&ddev->kref); + init_rwsem(&ddev->lock); + ddev->dev = dev; + ddev->ctrl = ctrl; + + ddev->mdev.minor = MISC_DYNAMIC_MINOR; + ddev->mdev.name = "surface_dtx"; + ddev->mdev.nodename = "surface/dtx"; + ddev->mdev.fops = &surface_dtx_fops; + + ddev->notif.base.priority = 1; + ddev->notif.base.fn = sdtx_notifier; + ddev->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; + ddev->notif.event.id.target_category = SSAM_SSH_TC_BAS; + ddev->notif.event.id.instance = 0; + ddev->notif.event.mask = SSAM_EVENT_MASK_NONE; + ddev->notif.event.flags = SSAM_EVENT_SEQUENCED; + + init_waitqueue_head(&ddev->waitq); + mutex_init(&ddev->write_lock); + init_rwsem(&ddev->client_lock); + INIT_LIST_HEAD(&ddev->client_list); + + INIT_DELAYED_WORK(&ddev->mode_work, sdtx_device_mode_workfn); + INIT_DELAYED_WORK(&ddev->state_work, sdtx_device_state_workfn); + + /* + * Get current device state. We want to guarantee that events are only + * sent when state actually changes. Thus we cannot use special + * "uninitialized" values, as that would cause problems when manually + * querying the state in surface_dtx_pm_complete(). I.e. we would not + * be able to detect state changes there if no change event has been + * received between driver initialization and first device suspension. + * + * Note that we also need to do this before registering the event + * notifier, as that may access the state values. + */ + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &ddev->state.base); + if (status) + return status; + + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &ddev->state.device_mode); + if (status) + return status; + + status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &ddev->state.latch_status); + if (status) + return status; + + /* Set up tablet mode switch. */ + ddev->mode_switch = input_allocate_device(); + if (!ddev->mode_switch) + return -ENOMEM; + + ddev->mode_switch->name = "Microsoft Surface DTX Device Mode Switch"; + ddev->mode_switch->phys = "ssam/01:11:01:00:00/input0"; + ddev->mode_switch->id.bustype = BUS_HOST; + ddev->mode_switch->dev.parent = ddev->dev; + + tablet_mode = (ddev->state.device_mode != SDTX_DEVICE_MODE_LAPTOP); + input_set_capability(ddev->mode_switch, EV_SW, SW_TABLET_MODE); + input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet_mode); + + status = input_register_device(ddev->mode_switch); + if (status) { + input_free_device(ddev->mode_switch); + return status; + } + + /* Set up event notifier. */ + status = ssam_notifier_register(ddev->ctrl, &ddev->notif); + if (status) + goto err_notif; + + /* Register miscdevice. */ + status = misc_register(&ddev->mdev); + if (status) + goto err_mdev; + + /* + * Update device state in case it has changed between getting the + * initial mode and registering the event notifier. + */ + sdtx_update_device_state(ddev, 0); + return 0; + +err_notif: + ssam_notifier_unregister(ddev->ctrl, &ddev->notif); + cancel_delayed_work_sync(&ddev->mode_work); +err_mdev: + input_unregister_device(ddev->mode_switch); + return status; +} + +static struct sdtx_device *sdtx_device_create(struct device *dev, struct ssam_controller *ctrl) +{ + struct sdtx_device *ddev; + int status; + + ddev = kzalloc(sizeof(*ddev), GFP_KERNEL); + if (!ddev) + return ERR_PTR(-ENOMEM); + + status = sdtx_device_init(ddev, dev, ctrl); + if (status) { + sdtx_device_put(ddev); + return ERR_PTR(status); + } + + return ddev; +} + +static void sdtx_device_destroy(struct sdtx_device *ddev) +{ + struct sdtx_client *client; + + /* + * Mark device as shut-down. Prevent new clients from being added and + * new operations from being executed. + */ + set_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags); + + /* Disable notifiers, prevent new events from arriving. */ + ssam_notifier_unregister(ddev->ctrl, &ddev->notif); + + /* Stop mode_work, prevent access to mode_switch. */ + cancel_delayed_work_sync(&ddev->mode_work); + + /* Stop state_work. */ + cancel_delayed_work_sync(&ddev->state_work); + + /* With mode_work canceled, we can unregister the mode_switch. */ + input_unregister_device(ddev->mode_switch); + + /* Wake up async clients. */ + down_write(&ddev->client_lock); + list_for_each_entry(client, &ddev->client_list, node) { + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + } + up_write(&ddev->client_lock); + + /* Wake up blocking clients. */ + wake_up_interruptible(&ddev->waitq); + + /* + * Wait for clients to finish their current operation. After this, the + * controller and device references are guaranteed to be no longer in + * use. + */ + down_write(&ddev->lock); + ddev->dev = NULL; + ddev->ctrl = NULL; + up_write(&ddev->lock); + + /* Finally remove the misc-device. */ + misc_deregister(&ddev->mdev); + + /* + * We're now guaranteed that sdtx_device_open() won't be called any + * more, so we can now drop out reference. + */ + sdtx_device_put(ddev); +} + + +/* -- PM ops. --------------------------------------------------------------- */ + +#ifdef CONFIG_PM_SLEEP + +static void surface_dtx_pm_complete(struct device *dev) +{ + struct sdtx_device *ddev = dev_get_drvdata(dev); + + /* + * Normally, the EC will store events while suspended (i.e. in + * display-off state) and release them when resumed (i.e. transitioned + * to display-on state). During hibernation, however, the EC will be + * shut down and does not store events. Furthermore, events might be + * dropped during prolonged suspension (it is currently unknown how + * big this event buffer is and how it behaves on overruns). + * + * To prevent any problems, we update the device state here. We do + * this delayed to ensure that any events sent by the EC directly + * after resuming will be handled first. The delay below has been + * chosen (experimentally), so that there should be ample time for + * these events to be handled, before we check and, if necessary, + * update the state. + */ + sdtx_update_device_state(ddev, msecs_to_jiffies(1000)); +} + +static const struct dev_pm_ops surface_dtx_pm_ops = { + .complete = surface_dtx_pm_complete, +}; + +#else /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops surface_dtx_pm_ops = {}; + +#endif /* CONFIG_PM_SLEEP */ + + +/* -- Platform driver. ------------------------------------------------------ */ + +static int surface_dtx_platform_probe(struct platform_device *pdev) +{ + struct ssam_controller *ctrl; + struct sdtx_device *ddev; + + /* Link to EC. */ + ctrl = ssam_client_bind(&pdev->dev); + if (IS_ERR(ctrl)) + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + ddev = sdtx_device_create(&pdev->dev, ctrl); + if (IS_ERR(ddev)) + return PTR_ERR(ddev); + + platform_set_drvdata(pdev, ddev); + return 0; +} + +static int surface_dtx_platform_remove(struct platform_device *pdev) +{ + sdtx_device_destroy(platform_get_drvdata(pdev)); + return 0; +} + +static const struct acpi_device_id surface_dtx_acpi_match[] = { + { "MSHW0133", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match); + +static struct platform_driver surface_dtx_platform_driver = { + .probe = surface_dtx_platform_probe, + .remove = surface_dtx_platform_remove, + .driver = { + .name = "surface_dtx_pltf", + .acpi_match_table = surface_dtx_acpi_match, + .pm = &surface_dtx_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + + +/* -- SSAM device driver. --------------------------------------------------- */ + +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS + +static int surface_dtx_ssam_probe(struct ssam_device *sdev) +{ + struct sdtx_device *ddev; + + ddev = sdtx_device_create(&sdev->dev, sdev->ctrl); + if (IS_ERR(ddev)) + return PTR_ERR(ddev); + + ssam_device_set_drvdata(sdev, ddev); + return 0; +} + +static void surface_dtx_ssam_remove(struct ssam_device *sdev) +{ + sdtx_device_destroy(ssam_device_get_drvdata(sdev)); +} + +static const struct ssam_device_id surface_dtx_ssam_match[] = { + { SSAM_SDEV(BAS, 0x01, 0x00, 0x00) }, + { }, +}; +MODULE_DEVICE_TABLE(ssam, surface_dtx_ssam_match); + +static struct ssam_device_driver surface_dtx_ssam_driver = { + .probe = surface_dtx_ssam_probe, + .remove = surface_dtx_ssam_remove, + .match_table = surface_dtx_ssam_match, + .driver = { + .name = "surface_dtx", + .pm = &surface_dtx_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +static int ssam_dtx_driver_register(void) +{ + return ssam_device_driver_register(&surface_dtx_ssam_driver); +} + +static void ssam_dtx_driver_unregister(void) +{ + ssam_device_driver_unregister(&surface_dtx_ssam_driver); +} + +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */ + +static int ssam_dtx_driver_register(void) +{ + return 0; +} + +static void ssam_dtx_driver_unregister(void) +{ +} + +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ + + +/* -- Module setup. --------------------------------------------------------- */ + +static int __init surface_dtx_init(void) +{ + int status; + + status = ssam_dtx_driver_register(); + if (status) + return status; + + status = platform_driver_register(&surface_dtx_platform_driver); + if (status) + ssam_dtx_driver_unregister(); + + return status; +} +module_init(surface_dtx_init); + +static void __exit surface_dtx_exit(void) +{ + platform_driver_unregister(&surface_dtx_platform_driver); + ssam_dtx_driver_unregister(); +} +module_exit(surface_dtx_exit); + +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); +MODULE_DESCRIPTION("Detachment-system driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c new file mode 100644 index 0000000000000000000000000000000000000000..6373d3b5eb7f843b762b817de6724826196782ac --- /dev/null +++ b/drivers/platform/surface/surface_platform_profile.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface Platform Profile / Performance Mode driver for Surface System + * Aggregator Module (thermal subsystem). + * + * Copyright (C) 2021 Maximilian Luz <luzmaximilian@gmail.com> + */ + +#include <asm/unaligned.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_profile.h> +#include <linux/types.h> + +#include <linux/surface_aggregator/device.h> + +enum ssam_tmp_profile { + SSAM_TMP_PROFILE_NORMAL = 1, + SSAM_TMP_PROFILE_BATTERY_SAVER = 2, + SSAM_TMP_PROFILE_BETTER_PERFORMANCE = 3, + SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4, +}; + +struct ssam_tmp_profile_info { + __le32 profile; + __le16 unknown1; + __le16 unknown2; +} __packed; + +struct ssam_tmp_profile_device { + struct ssam_device *sdev; + struct platform_profile_handler handler; +}; + +SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, { + .target_category = SSAM_SSH_TC_TMP, + .command_id = 0x02, +}); + +SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, { + .target_category = SSAM_SSH_TC_TMP, + .command_id = 0x03, +}); + +static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p) +{ + struct ssam_tmp_profile_info info; + int status; + + status = ssam_retry(__ssam_tmp_profile_get, sdev, &info); + if (status < 0) + return status; + + *p = le32_to_cpu(info.profile); + return 0; +} + +static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile p) +{ + __le32 profile_le = cpu_to_le32(p); + + return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le); +} + +static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) +{ + switch (p) { + case SSAM_TMP_PROFILE_NORMAL: + return PLATFORM_PROFILE_BALANCED; + + case SSAM_TMP_PROFILE_BATTERY_SAVER: + return PLATFORM_PROFILE_LOW_POWER; + + case SSAM_TMP_PROFILE_BETTER_PERFORMANCE: + return PLATFORM_PROFILE_BALANCED_PERFORMANCE; + + case SSAM_TMP_PROFILE_BEST_PERFORMANCE: + return PLATFORM_PROFILE_PERFORMANCE; + + default: + dev_err(&sdev->dev, "invalid performance profile: %d", p); + return -EINVAL; + } +} + +static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p) +{ + switch (p) { + case PLATFORM_PROFILE_LOW_POWER: + return SSAM_TMP_PROFILE_BATTERY_SAVER; + + case PLATFORM_PROFILE_BALANCED: + return SSAM_TMP_PROFILE_NORMAL; + + case PLATFORM_PROFILE_BALANCED_PERFORMANCE: + return SSAM_TMP_PROFILE_BETTER_PERFORMANCE; + + case PLATFORM_PROFILE_PERFORMANCE: + return SSAM_TMP_PROFILE_BEST_PERFORMANCE; + + default: + /* This should have already been caught by platform_profile_store(). */ + WARN(true, "unsupported platform profile"); + return -EOPNOTSUPP; + } +} + +static int ssam_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + struct ssam_tmp_profile_device *tpd; + enum ssam_tmp_profile tp; + int status; + + tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); + + status = ssam_tmp_profile_get(tpd->sdev, &tp); + if (status) + return status; + + status = convert_ssam_to_profile(tpd->sdev, tp); + if (status < 0) + return status; + + *profile = status; + return 0; +} + +static int ssam_platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) +{ + struct ssam_tmp_profile_device *tpd; + int tp; + + tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); + + tp = convert_profile_to_ssam(tpd->sdev, profile); + if (tp < 0) + return tp; + + return ssam_tmp_profile_set(tpd->sdev, tp); +} + +static int surface_platform_profile_probe(struct ssam_device *sdev) +{ + struct ssam_tmp_profile_device *tpd; + + tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL); + if (!tpd) + return -ENOMEM; + + tpd->sdev = sdev; + + tpd->handler.profile_get = ssam_platform_profile_get; + tpd->handler.profile_set = ssam_platform_profile_set; + + set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, tpd->handler.choices); + + platform_profile_register(&tpd->handler); + return 0; +} + +static void surface_platform_profile_remove(struct ssam_device *sdev) +{ + platform_profile_remove(); +} + +static const struct ssam_device_id ssam_platform_profile_match[] = { + { SSAM_SDEV(TMP, 0x01, 0x00, 0x01) }, + { }, +}; +MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match); + +static struct ssam_device_driver surface_platform_profile = { + .probe = surface_platform_profile_probe, + .remove = surface_platform_profile_remove, + .match_table = ssam_platform_profile_match, + .driver = { + .name = "surface_platform_profile", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; +module_ssam_device_driver(surface_platform_profile); + +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); +MODULE_DESCRIPTION("Platform Profile Support for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c index d8afed5db94c59f69f58e63e24e5976e9fae2ee7..242fb690dcaf7aff6998cbc22c3e753679fe6a84 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -40,8 +40,6 @@ static const guid_t MSHW0040_DSM_UUID = #define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN 0xc2 #define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN 0xc3 -ACPI_MODULE_NAME("surface pro 3 button"); - MODULE_AUTHOR("Chen Yu"); MODULE_DESCRIPTION("Surface Pro3 Button Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 461ec61530ebf2a12883899f4734d85da62c42a8..2714f7c3843e3d3ea34117b95a2cab422bd95076 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -123,6 +123,17 @@ config XIAOMI_WMI To compile this driver as a module, choose M here: the module will be called xiaomi-wmi. +config GIGABYTE_WMI + tristate "Gigabyte WMI temperature driver" + depends on ACPI_WMI + depends on HWMON + help + Say Y here if you want to support WMI-based temperature reporting on + Gigabyte mainboards. + + To compile this driver as a module, choose M here: the module will + be called gigabyte-wmi. + config ACERHDF tristate "Acer Aspire One temperature and fan driver" depends on ACPI && THERMAL @@ -193,6 +204,17 @@ config AMD_PMC If you choose to compile this driver as a module the module will be called amd-pmc. +config ADV_SWBUTTON + tristate "Advantech ACPI Software Button Driver" + depends on ACPI && INPUT + help + Say Y here to enable support for Advantech software defined + button feature. More information can be found at + <http://www.advantech.com.tw/products/> + + To compile this driver as a module, choose M here. The module will + be called adv_swbutton. + config APPLE_GMUX tristate "Apple Gmux Driver" depends on ACPI && PCI @@ -410,6 +432,7 @@ config HP_WMI depends on INPUT depends on RFKILL || RFKILL = n select INPUT_SPARSEKMAP + select ACPI_PLATFORM_PROFILE help Say Y here if you want to support WMI-based hotkeys on HP laptops and to read data from WMI such as docking or ambient light sensor state. @@ -1171,6 +1194,7 @@ config INTEL_MRFLD_PWRBTN config INTEL_PMC_CORE tristate "Intel PMC Core driver" depends on PCI + depends on ACPI help The Intel Platform Controller Hub for Intel Core SoCs provides access to Power Management Controller registers via various interfaces. This @@ -1192,7 +1216,7 @@ config INTEL_PMT_CLASS tristate help The Intel Platform Monitoring Technology (PMT) class driver provides - the basic sysfs interface and file hierarchy uses by PMT devices. + the basic sysfs interface and file hierarchy used by PMT devices. For more information, see: <file:Documentation/ABI/testing/sysfs-class-intel_pmt> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 60d554073749be314ec79f1fd5fb863c7036dd9f..dcc8cdb95b4dde8dfcb191fd4c32364731ce2a14 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_INTEL_WMI_THUNDERBOLT) += intel-wmi-thunderbolt.o obj-$(CONFIG_MXM_WMI) += mxm-wmi.o obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o +obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o # Acer obj-$(CONFIG_ACERHDF) += acerhdf.o @@ -24,6 +25,9 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o # AMD obj-$(CONFIG_AMD_PMC) += amd-pmc.o +# Advantech +obj-$(CONFIG_ADV_SWBUTTON) += adv_swbutton.o + # Apple obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o diff --git a/drivers/platform/x86/adv_swbutton.c b/drivers/platform/x86/adv_swbutton.c new file mode 100644 index 0000000000000000000000000000000000000000..38693b735c876cc00c53fb0e003bcbf241974507 --- /dev/null +++ b/drivers/platform/x86/adv_swbutton.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * adv_swbutton.c - Software Button Interface Driver. + * + * (C) Copyright 2020 Advantech Corporation, Inc + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/input.h> +#include <linux/acpi.h> +#include <linux/platform_device.h> + +#define ACPI_BUTTON_HID_SWBTN "AHC0310" + +#define ACPI_BUTTON_NOTIFY_SWBTN_RELEASE 0x86 +#define ACPI_BUTTON_NOTIFY_SWBTN_PRESSED 0x85 + +struct adv_swbutton { + struct input_dev *input; + char phys[32]; +}; + +/*------------------------------------------------------------------------- + * Driver Interface + *-------------------------------------------------------------------------- + */ +static void adv_swbutton_notify(acpi_handle handle, u32 event, void *context) +{ + struct platform_device *device = context; + struct adv_swbutton *button = dev_get_drvdata(&device->dev); + + switch (event) { + case ACPI_BUTTON_NOTIFY_SWBTN_RELEASE: + input_report_key(button->input, KEY_PROG1, 0); + input_sync(button->input); + break; + case ACPI_BUTTON_NOTIFY_SWBTN_PRESSED: + input_report_key(button->input, KEY_PROG1, 1); + input_sync(button->input); + break; + default: + dev_dbg(&device->dev, "Unsupported event [0x%x]\n", event); + } +} + +static int adv_swbutton_probe(struct platform_device *device) +{ + struct adv_swbutton *button; + struct input_dev *input; + acpi_handle handle = ACPI_HANDLE(&device->dev); + acpi_status status; + int error; + + button = devm_kzalloc(&device->dev, sizeof(*button), GFP_KERNEL); + if (!button) + return -ENOMEM; + + dev_set_drvdata(&device->dev, button); + + input = devm_input_allocate_device(&device->dev); + if (!input) + return -ENOMEM; + + button->input = input; + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", ACPI_BUTTON_HID_SWBTN); + + input->name = "Advantech Software Button"; + input->phys = button->phys; + input->id.bustype = BUS_HOST; + input->dev.parent = &device->dev; + set_bit(EV_REP, input->evbit); + input_set_capability(input, EV_KEY, KEY_PROG1); + + error = input_register_device(input); + if (error) + return error; + + device_init_wakeup(&device->dev, true); + + status = acpi_install_notify_handler(handle, + ACPI_DEVICE_NOTIFY, + adv_swbutton_notify, + device); + if (ACPI_FAILURE(status)) { + dev_err(&device->dev, "Error installing notify handler\n"); + return -EIO; + } + + return 0; +} + +static int adv_swbutton_remove(struct platform_device *device) +{ + acpi_handle handle = ACPI_HANDLE(&device->dev); + + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, + adv_swbutton_notify); + + return 0; +} + +static const struct acpi_device_id button_device_ids[] = { + {ACPI_BUTTON_HID_SWBTN, 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, button_device_ids); + +static struct platform_driver adv_swbutton_driver = { + .driver = { + .name = "adv_swbutton", + .acpi_match_table = button_device_ids, + }, + .probe = adv_swbutton_probe, + .remove = adv_swbutton_remove, +}; +module_platform_driver(adv_swbutton_driver); + +MODULE_AUTHOR("Andrea Ho"); +MODULE_DESCRIPTION("Advantech ACPI SW Button Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index bfea656e910c25b840af234a5007305d89c63b2a..4d2d32bfbe2a6da7bbff43e3e4047fea3b715c64 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1569,7 +1569,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct asus_laptop *asus = dev_get_drvdata(dev); acpi_handle handle = asus->handle; bool supported; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 9ca15f72434303000a85929fc4e1e82a27ce659d..ebaeb7bb80f5c486b0e8d69bd8a260102635f9d8 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -47,6 +47,9 @@ MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>, " MODULE_DESCRIPTION("Asus Generic WMI Driver"); MODULE_LICENSE("GPL"); +static bool fnlock_default = true; +module_param(fnlock_default, bool, 0444); + #define to_asus_wmi_driver(pdrv) \ (container_of((pdrv), struct asus_wmi_driver, platform_driver)) @@ -2673,7 +2676,7 @@ static int asus_wmi_add(struct platform_device *pdev) err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); if (asus_wmi_has_fnlock_key(asus)) { - asus->fnlock_locked = true; + asus->fnlock_locked = fnlock_default; asus_wmi_fnlock_update(asus); } diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 3e03e8d3a07fa6da6f98619d058a798108d9100b..9309ab5792cbc3710ac9370ca0d3a8ec2ebb316a 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -956,7 +956,7 @@ static int cmpc_ipml_add(struct acpi_device *acpi) /* * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV). * This is OK, however, since all other uses of the device will not - * derefence it. + * dereference it. */ if (ipml->rf) { retval = rfkill_register(ipml->rf); diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c index 5bb2859c828584973c8dae961540a368858e4991..f212482555298ba31d34d35c406068a56465b10b 100644 --- a/drivers/platform/x86/dell/alienware-wmi.c +++ b/drivers/platform/x86/dell/alienware-wmi.c @@ -2,7 +2,7 @@ /* * Alienware AlienFX control * - * Copyright (C) 2014 Dell Inc <mario_limonciello@dell.com> + * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com> */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -26,7 +26,7 @@ #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C -MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); +MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>"); MODULE_DESCRIPTION("Alienware special feature control"); MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID); diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c index 3a1dbf199441385ec4066883bff10a7adb0d857a..fc086b66f70b377374dcd71627f2efb0769c8e1d 100644 --- a/drivers/platform/x86/dell/dell-smbios-base.c +++ b/drivers/platform/x86/dell/dell-smbios-base.c @@ -647,6 +647,6 @@ module_exit(dell_smbios_exit); MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>"); MODULE_AUTHOR("Pali Rohár <pali@kernel.org>"); -MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>"); +MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>"); MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell/dell-smbios-wmi.c b/drivers/platform/x86/dell/dell-smbios-wmi.c index 27a298b7c541b9c8c01f43dadbc8cb59be35acbb..a1753485159ca6164206665fbb7d1e53a08eb442 100644 --- a/drivers/platform/x86/dell/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell/dell-smbios-wmi.c @@ -205,7 +205,7 @@ fail_register: return ret; } -static int dell_smbios_wmi_remove(struct wmi_device *wdev) +static void dell_smbios_wmi_remove(struct wmi_device *wdev) { struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev); int count; @@ -218,7 +218,6 @@ static int dell_smbios_wmi_remove(struct wmi_device *wdev) count = get_order(priv->req_buf_size); free_pages((unsigned long)priv->buf, count); mutex_unlock(&call_mutex); - return 0; } static const struct wmi_device_id dell_smbios_wmi_id_table[] = { diff --git a/drivers/platform/x86/dell/dell-wmi-descriptor.c b/drivers/platform/x86/dell/dell-wmi-descriptor.c index a068900ae8a1ada7ac9c118e13a9efe78396d8fc..c2a1802027190186cc364991a100515266a925a1 100644 --- a/drivers/platform/x86/dell/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell/dell-wmi-descriptor.c @@ -174,14 +174,13 @@ out: return ret; } -static int dell_wmi_descriptor_remove(struct wmi_device *wdev) +static void dell_wmi_descriptor_remove(struct wmi_device *wdev) { struct descriptor_priv *priv = dev_get_drvdata(&wdev->dev); mutex_lock(&list_mutex); list_del(&priv->list); mutex_unlock(&list_mutex); - return 0; } static const struct wmi_device_id dell_wmi_descriptor_id_table[] = { @@ -201,6 +200,6 @@ static struct wmi_driver dell_wmi_descriptor_driver = { module_wmi_driver(dell_wmi_descriptor_driver); MODULE_DEVICE_TABLE(wmi, dell_wmi_descriptor_id_table); -MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>"); +MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>"); MODULE_DESCRIPTION("Dell WMI descriptor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell/dell-wmi-sysman/biosattr-interface.c index f95d8ddace5a705d825b2336c00ca54e281e30cf..c2dd2de6bc2034226d5b62c04e47d1d74506bc9a 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/biosattr-interface.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/biosattr-interface.c @@ -152,12 +152,11 @@ static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *co return 0; } -static int bios_attr_set_interface_remove(struct wmi_device *wdev) +static void bios_attr_set_interface_remove(struct wmi_device *wdev) { mutex_lock(&wmi_priv.mutex); wmi_priv.bios_attr_wdev = NULL; mutex_unlock(&wmi_priv.mutex); - return 0; } static const struct wmi_device_id bios_attr_set_interface_id_table[] = { diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c index 5780b4d94759b24342886ef2c66ef5916f15f0e5..339a082d6c18d1251f4551d3a969a39fd0d1cd14 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c @@ -119,12 +119,11 @@ static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *c return 0; } -static int bios_attr_pass_interface_remove(struct wmi_device *wdev) +static void bios_attr_pass_interface_remove(struct wmi_device *wdev) { mutex_lock(&wmi_priv.mutex); wmi_priv.password_attr_wdev = NULL; mutex_unlock(&wmi_priv.mutex); - return 0; } static const struct wmi_device_id bios_attr_pass_interface_id_table[] = { diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c index 7410ccae650c2ccfd9040f5179ea1970fb4cd7a8..c8d276d78e920ae2cc5b181ebba20e8e5d61a3b4 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c @@ -399,6 +399,7 @@ static int init_bios_attributes(int attr_type, const char *guid) union acpi_object *obj = NULL; union acpi_object *elements; struct kset *tmp_set; + int min_elements; /* instance_id needs to be reset for each type GUID * also, instance IDs are unique within GUID but not across @@ -409,14 +410,38 @@ static int init_bios_attributes(int attr_type, const char *guid) retval = alloc_attributes_data(attr_type); if (retval) return retval; + + switch (attr_type) { + case ENUM: min_elements = 8; break; + case INT: min_elements = 9; break; + case STR: min_elements = 8; break; + case PO: min_elements = 4; break; + default: + pr_err("Error: Unknown attr_type: %d\n", attr_type); + return -EINVAL; + } + /* need to use specific instance_id and guid combination to get right data */ obj = get_wmiobj_pointer(instance_id, guid); - if (!obj || obj->type != ACPI_TYPE_PACKAGE) + if (!obj) return -ENODEV; - elements = obj->package.elements; mutex_lock(&wmi_priv.mutex); - while (elements) { + while (obj) { + if (obj->type != ACPI_TYPE_PACKAGE) { + pr_err("Error: Expected ACPI-package type, got: %d\n", obj->type); + retval = -EIO; + goto err_attr_init; + } + + if (obj->package.count < min_elements) { + pr_err("Error: ACPI-package does not have enough elements: %d < %d\n", + obj->package.count, min_elements); + goto nextobj; + } + + elements = obj->package.elements; + /* sanity checking */ if (elements[ATTR_NAME].type != ACPI_TYPE_STRING) { pr_debug("incorrect element type\n"); @@ -481,7 +506,6 @@ nextobj: kfree(obj); instance_id++; obj = get_wmiobj_pointer(instance_id, guid); - elements = obj ? obj->package.elements : NULL; } mutex_unlock(&wmi_priv.mutex); @@ -604,7 +628,7 @@ static void __exit sysman_exit(void) module_init(sysman_init); module_exit(sysman_exit); -MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>"); +MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>"); MODULE_AUTHOR("Prasanth Ksr <prasanth.ksr@dell.com>"); MODULE_AUTHOR("Divya Bharathi <divya.bharathi@dell.com>"); MODULE_DESCRIPTION("Dell platform setting control interface"); diff --git a/drivers/platform/x86/dell/dell-wmi.c b/drivers/platform/x86/dell/dell-wmi.c index bbdb3e8608927d795c729b6f31995cb19981b297..5e1b7f897df58025be0731e1c7f5644d516fe59d 100644 --- a/drivers/platform/x86/dell/dell-wmi.c +++ b/drivers/platform/x86/dell/dell-wmi.c @@ -714,10 +714,9 @@ static int dell_wmi_probe(struct wmi_device *wdev, const void *context) return dell_wmi_input_setup(wdev); } -static int dell_wmi_remove(struct wmi_device *wdev) +static void dell_wmi_remove(struct wmi_device *wdev) { dell_wmi_input_destroy(wdev); - return 0; } static const struct wmi_device_id dell_wmi_id_table[] = { { .guid_string = DELL_EVENT_GUID }, diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c new file mode 100644 index 0000000000000000000000000000000000000000..13d57434e60f26ee1686bd6286964301faee8ee6 --- /dev/null +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 Thomas Weißschuh <thomas@weissschuh.net> + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/dmi.h> +#include <linux/hwmon.h> +#include <linux/module.h> +#include <linux/wmi.h> + +#define GIGABYTE_WMI_GUID "DEADBEEF-2001-0000-00A0-C90629100000" +#define NUM_TEMPERATURE_SENSORS 6 + +static bool force_load; +module_param(force_load, bool, 0444); +MODULE_PARM_DESC(force_load, "Force loading on unknown platform"); + +static u8 usable_sensors_mask; + +enum gigabyte_wmi_commandtype { + GIGABYTE_WMI_BUILD_DATE_QUERY = 0x1, + GIGABYTE_WMI_MAINBOARD_TYPE_QUERY = 0x2, + GIGABYTE_WMI_FIRMWARE_VERSION_QUERY = 0x4, + GIGABYTE_WMI_MAINBOARD_NAME_QUERY = 0x5, + GIGABYTE_WMI_TEMPERATURE_QUERY = 0x125, +}; + +struct gigabyte_wmi_args { + u32 arg1; +}; + +static int gigabyte_wmi_perform_query(struct wmi_device *wdev, + enum gigabyte_wmi_commandtype command, + struct gigabyte_wmi_args *args, struct acpi_buffer *out) +{ + const struct acpi_buffer in = { + .length = sizeof(*args), + .pointer = args, + }; + + acpi_status ret = wmidev_evaluate_method(wdev, 0x0, command, &in, out); + + if (ACPI_FAILURE(ret)) + return -EIO; + + return 0; +} + +static int gigabyte_wmi_query_integer(struct wmi_device *wdev, + enum gigabyte_wmi_commandtype command, + struct gigabyte_wmi_args *args, u64 *res) +{ + union acpi_object *obj; + struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; + int ret; + + ret = gigabyte_wmi_perform_query(wdev, command, args, &result); + if (ret) + return ret; + obj = result.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + *res = obj->integer.value; + else + ret = -EIO; + kfree(result.pointer); + return ret; +} + +static int gigabyte_wmi_temperature(struct wmi_device *wdev, u8 sensor, long *res) +{ + struct gigabyte_wmi_args args = { + .arg1 = sensor, + }; + u64 temp; + acpi_status ret; + + ret = gigabyte_wmi_query_integer(wdev, GIGABYTE_WMI_TEMPERATURE_QUERY, &args, &temp); + if (ret == 0) { + if (temp == 0) + return -ENODEV; + *res = (s8)temp * 1000; // value is a signed 8-bit integer + } + return ret; +} + +static int gigabyte_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct wmi_device *wdev = dev_get_drvdata(dev); + + return gigabyte_wmi_temperature(wdev, channel, val); +} + +static umode_t gigabyte_wmi_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return usable_sensors_mask & BIT(channel) ? 0444 : 0; +} + +static const struct hwmon_channel_info *gigabyte_wmi_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops gigabyte_wmi_hwmon_ops = { + .read = gigabyte_wmi_hwmon_read, + .is_visible = gigabyte_wmi_hwmon_is_visible, +}; + +static const struct hwmon_chip_info gigabyte_wmi_hwmon_chip_info = { + .ops = &gigabyte_wmi_hwmon_ops, + .info = gigabyte_wmi_hwmon_info, +}; + +static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev) +{ + int i; + long temp; + u8 r = 0; + + for (i = 0; i < NUM_TEMPERATURE_SENSORS; i++) { + if (!gigabyte_wmi_temperature(wdev, i, &temp)) + r |= BIT(i); + } + return r; +} + +static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { + { .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "B550 GAMING X V2"), + }}, + { .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "B550M AORUS PRO-P"), + }}, + { .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "B550M DS3H"), + }}, + { .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Z390 I AORUS PRO WIFI-CF"), + }}, + { .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X570 AORUS ELITE"), + }}, + { .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X570 I AORUS PRO WIFI"), + }}, + { } +}; + +static int gigabyte_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct device *hwmon_dev; + + if (!dmi_check_system(gigabyte_wmi_known_working_platforms)) { + if (!force_load) + return -ENODEV; + dev_warn(&wdev->dev, "Forcing load on unknown platform"); + } + + usable_sensors_mask = gigabyte_wmi_detect_sensor_usability(wdev); + if (!usable_sensors_mask) { + dev_info(&wdev->dev, "No temperature sensors usable"); + return -ENODEV; + } + + hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev, "gigabyte_wmi", wdev, + &gigabyte_wmi_hwmon_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct wmi_device_id gigabyte_wmi_id_table[] = { + { GIGABYTE_WMI_GUID, NULL }, + { } +}; + +static struct wmi_driver gigabyte_wmi_driver = { + .driver = { + .name = "gigabyte-wmi", + }, + .id_table = gigabyte_wmi_id_table, + .probe = gigabyte_wmi_probe, +}; +module_wmi_driver(gigabyte_wmi_driver); + +MODULE_DEVICE_TABLE(wmi, gigabyte_wmi_id_table); +MODULE_AUTHOR("Thomas Weißschuh <thomas@weissschuh.net>"); +MODULE_DESCRIPTION("Gigabyte WMI temperature driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c index 5b516e4c2bfbe2ac53aa68a7bbf99365d1c391a4..7a20f68ae20611f74d6621da1a89601d838cde7d 100644 --- a/drivers/platform/x86/gpd-pocket-fan.c +++ b/drivers/platform/x86/gpd-pocket-fan.c @@ -6,6 +6,7 @@ */ #include <linux/acpi.h> +#include <linux/devm-helpers.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -124,7 +125,7 @@ static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan) static int gpd_pocket_fan_probe(struct platform_device *pdev) { struct gpd_pocket_fan_data *fan; - int i; + int i, ret; for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { if (temp_limits[i] < 20000 || temp_limits[i] > 90000) { @@ -152,7 +153,10 @@ static int gpd_pocket_fan_probe(struct platform_device *pdev) return -ENOMEM; fan->dev = &pdev->dev; - INIT_DELAYED_WORK(&fan->work, gpd_pocket_fan_worker); + ret = devm_delayed_work_autocancel(&pdev->dev, &fan->work, + gpd_pocket_fan_worker); + if (ret) + return ret; /* Note this returns a "weak" reference which we don't need to free */ fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0"); @@ -177,14 +181,6 @@ static int gpd_pocket_fan_probe(struct platform_device *pdev) return 0; } -static int gpd_pocket_fan_remove(struct platform_device *pdev) -{ - struct gpd_pocket_fan_data *fan = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&fan->work); - return 0; -} - #ifdef CONFIG_PM_SLEEP static int gpd_pocket_fan_suspend(struct device *dev) { @@ -215,7 +211,6 @@ MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match); static struct platform_driver gpd_pocket_fan_driver = { .probe = gpd_pocket_fan_probe, - .remove = gpd_pocket_fan_remove, .driver = { .name = "gpd_pocket_fan", .acpi_match_table = gpd_pocket_fan_acpi_match, diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index e94e59283ecb9f5f601f005f5359d35c60522be1..027a1467d009fddb7d1ee06031c7dfad53a9bbdd 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -21,6 +21,7 @@ #include <linux/input.h> #include <linux/input/sparse-keymap.h> #include <linux/platform_device.h> +#include <linux/platform_profile.h> #include <linux/acpi.h> #include <linux/rfkill.h> #include <linux/string.h> @@ -85,7 +86,7 @@ enum hp_wmi_commandtype { HPWMI_FEATURE2_QUERY = 0x0d, HPWMI_WIRELESS2_QUERY = 0x1b, HPWMI_POSTCODEERROR_QUERY = 0x2a, - HPWMI_THERMAL_POLICY_QUERY = 0x4c, + HPWMI_THERMAL_PROFILE_QUERY = 0x4c, }; enum hp_wmi_command { @@ -119,6 +120,12 @@ enum hp_wireless2_bits { HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, }; +enum hp_thermal_profile { + HP_THERMAL_PROFILE_PERFORMANCE = 0x00, + HP_THERMAL_PROFILE_DEFAULT = 0x01, + HP_THERMAL_PROFILE_COOL = 0x02 +}; + #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) @@ -159,6 +166,8 @@ static const struct key_entry hp_wmi_keymap[] = { static struct input_dev *hp_wmi_input_dev; static struct platform_device *hp_wmi_platform_dev; +static struct platform_profile_handler platform_profile_handler; +static bool platform_profile_support; static struct rfkill *wifi_rfkill; static struct rfkill *bluetooth_rfkill; @@ -869,23 +878,98 @@ fail: return err; } -static int thermal_policy_setup(struct platform_device *device) +static int thermal_profile_get(void) +{ + return hp_wmi_read_int(HPWMI_THERMAL_PROFILE_QUERY); +} + +static int thermal_profile_set(int thermal_profile) +{ + return hp_wmi_perform_query(HPWMI_THERMAL_PROFILE_QUERY, HPWMI_WRITE, &thermal_profile, + sizeof(thermal_profile), 0); +} + +static int platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + int tp; + + tp = thermal_profile_get(); + if (tp < 0) + return tp; + + switch (tp) { + case HP_THERMAL_PROFILE_PERFORMANCE: + *profile = PLATFORM_PROFILE_PERFORMANCE; + break; + case HP_THERMAL_PROFILE_DEFAULT: + *profile = PLATFORM_PROFILE_BALANCED; + break; + case HP_THERMAL_PROFILE_COOL: + *profile = PLATFORM_PROFILE_COOL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) { int err, tp; - tp = hp_wmi_read_int(HPWMI_THERMAL_POLICY_QUERY); + switch (profile) { + case PLATFORM_PROFILE_PERFORMANCE: + tp = HP_THERMAL_PROFILE_PERFORMANCE; + break; + case PLATFORM_PROFILE_BALANCED: + tp = HP_THERMAL_PROFILE_DEFAULT; + break; + case PLATFORM_PROFILE_COOL: + tp = HP_THERMAL_PROFILE_COOL; + break; + default: + return -EOPNOTSUPP; + } + + err = thermal_profile_set(tp); + if (err) + return err; + + return 0; +} + +static int thermal_profile_setup(void) +{ + int err, tp; + + tp = thermal_profile_get(); if (tp < 0) return tp; /* - * call thermal policy write command to ensure that the firmware correctly + * call thermal profile write command to ensure that the firmware correctly * sets the OEM variables for the DPTF */ - err = hp_wmi_perform_query(HPWMI_THERMAL_POLICY_QUERY, HPWMI_WRITE, &tp, - sizeof(tp), 0); + err = thermal_profile_set(tp); if (err) return err; + platform_profile_handler.profile_get = platform_profile_get, + platform_profile_handler.profile_set = platform_profile_set, + + set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED, platform_profile_handler.choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, platform_profile_handler.choices); + + err = platform_profile_register(&platform_profile_handler); + if (err) + return err; + + platform_profile_support = true; + return 0; } @@ -900,7 +984,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) if (hp_wmi_rfkill_setup(device)) hp_wmi_rfkill2_setup(device); - thermal_policy_setup(device); + thermal_profile_setup(); return 0; } @@ -927,6 +1011,9 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) rfkill_destroy(wwan_rfkill); } + if (platform_profile_support) + platform_profile_remove(); + return 0; } diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 3fdf4cbec9ad2d7803ea85fdce689d482f602168..888a764efad1ac1b42527c4e457c1262e836c6a7 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -63,9 +63,6 @@ static const struct key_entry intel_vbtn_switchmap[] = { { KE_END } }; -#define KEYMAP_LEN \ - (ARRAY_SIZE(intel_vbtn_keymap) + ARRAY_SIZE(intel_vbtn_switchmap) + 1) - struct intel_vbtn_priv { struct input_dev *buttons_dev; struct input_dev *switches_dev; diff --git a/drivers/platform/x86/intel-wmi-sbl-fw-update.c b/drivers/platform/x86/intel-wmi-sbl-fw-update.c index ea87fa0786e8e05ec56501ea3fe30d5672346388..3c86e0108a24727ece455c08cab0200ea3f1928b 100644 --- a/drivers/platform/x86/intel-wmi-sbl-fw-update.c +++ b/drivers/platform/x86/intel-wmi-sbl-fw-update.c @@ -117,10 +117,9 @@ static int intel_wmi_sbl_fw_update_probe(struct wmi_device *wdev, return 0; } -static int intel_wmi_sbl_fw_update_remove(struct wmi_device *wdev) +static void intel_wmi_sbl_fw_update_remove(struct wmi_device *wdev) { dev_info(&wdev->dev, "Slim Bootloader signaling driver removed\n"); - return 0; } static const struct wmi_device_id intel_wmi_sbl_id_table[] = { diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c index 974c22a7ff61ee4c124f4255bfc053bb892afb0a..4ae87060d18b4c277de34609515f027ea116914d 100644 --- a/drivers/platform/x86/intel-wmi-thunderbolt.c +++ b/drivers/platform/x86/intel-wmi-thunderbolt.c @@ -66,11 +66,10 @@ static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev, return ret; } -static int intel_wmi_thunderbolt_remove(struct wmi_device *wdev) +static void intel_wmi_thunderbolt_remove(struct wmi_device *wdev) { sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group); kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE); - return 0; } static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = { diff --git a/drivers/platform/x86/intel_cht_int33fe_typec.c b/drivers/platform/x86/intel_cht_int33fe_typec.c index 48638d1c56e550eb57356c114af3ede8642112bc..b61bad9cc8d228187bbba67a79f316bfea083f74 100644 --- a/drivers/platform/x86/intel_cht_int33fe_typec.c +++ b/drivers/platform/x86/intel_cht_int33fe_typec.c @@ -124,12 +124,31 @@ static const struct software_node usb_connector_node = { .properties = usb_connector_properties, }; +static const struct software_node altmodes_node = { + .name = "altmodes", + .parent = &usb_connector_node, +}; + +static const struct property_entry dp_altmode_properties[] = { + PROPERTY_ENTRY_U32("svid", 0xff01), + PROPERTY_ENTRY_U32("vdo", 0x0c0086), + { } +}; + +static const struct software_node dp_altmode_node = { + .name = "displayport-altmode", + .parent = &altmodes_node, + .properties = dp_altmode_properties, +}; + static const struct software_node *node_group[] = { &fusb302_node, &max17047_node, &pi3usb30532_node, &displayport_node, &usb_connector_node, + &altmodes_node, + &dp_altmode_node, NULL }; diff --git a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c index 0df2e82dd24924bd6d92ff74f2434b4eb1f30d64..9606a994af22324905a7521c2dc584b8da4fc40c 100644 --- a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c +++ b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c @@ -58,7 +58,7 @@ static int chtdc_ti_pwrbtn_probe(struct platform_device *pdev) err = devm_request_threaded_irq(dev, irq, NULL, chtdc_ti_pwrbtn_interrupt, - 0, KBUILD_MODNAME, input); + IRQF_ONESHOT, KBUILD_MODNAME, input); if (err) return err; diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index b5888aeb4bcff9a79fc7cd913d7f033b183f3257..b0e486a6bdfb0ec72533e227a48d1ac7bb52c066 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -23,7 +23,9 @@ #include <linux/slab.h> #include <linux/suspend.h> #include <linux/uaccess.h> +#include <linux/uuid.h> +#include <acpi/acpi_bus.h> #include <asm/cpu_device_id.h> #include <asm/intel-family.h> #include <asm/msr.h> @@ -31,7 +33,8 @@ #include "intel_pmc_core.h" -static struct pmc_dev pmc; +#define ACPI_S0IX_DSM_UUID "57a6512e-3979-4e9d-9708-ff13b2508972" +#define ACPI_GET_LOW_MODE_REGISTERS 1 /* PKGC MSRs are common across Intel Core SoCs */ static const struct pmc_bit_map msr_map[] = { @@ -380,6 +383,8 @@ static const struct pmc_bit_map cnp_ltr_show_map[] = { * a list of core SoCs using this. */ {"WIGIG", ICL_PMC_LTR_WIGIG}, + {"THC0", TGL_PMC_LTR_THC0}, + {"THC1", TGL_PMC_LTR_THC1}, /* Below two cannot be used for LTR_IGNORE */ {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT}, {"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT}, @@ -401,6 +406,7 @@ static const struct pmc_reg_map cnp_reg_map = { .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, .ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED, + .etr3_offset = ETR3_OFFSET, }; static const struct pmc_reg_map icl_reg_map = { @@ -418,6 +424,7 @@ static const struct pmc_reg_map icl_reg_map = { .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, .ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED, + .etr3_offset = ETR3_OFFSET, }; static const struct pmc_bit_map tgl_clocksource_status_map[] = { @@ -579,14 +586,65 @@ static const struct pmc_reg_map tgl_reg_map = { .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, .ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED, - .lpm_modes = tgl_lpm_modes, + .lpm_num_maps = TGL_LPM_NUM_MAPS, + .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2, + .lpm_sts_latch_en_offset = TGL_LPM_STS_LATCH_EN_OFFSET, .lpm_en_offset = TGL_LPM_EN_OFFSET, + .lpm_priority_offset = TGL_LPM_PRI_OFFSET, .lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET, .lpm_sts = tgl_lpm_maps, .lpm_status_offset = TGL_LPM_STATUS_OFFSET, .lpm_live_status_offset = TGL_LPM_LIVE_STATUS_OFFSET, + .etr3_offset = ETR3_OFFSET, }; +static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev) +{ + struct pmc_dev *pmcdev = platform_get_drvdata(pdev); + const int num_maps = pmcdev->map->lpm_num_maps; + u32 lpm_size = LPM_MAX_NUM_MODES * num_maps * 4; + union acpi_object *out_obj; + struct acpi_device *adev; + guid_t s0ix_dsm_guid; + u32 *lpm_req_regs, *addr; + + adev = ACPI_COMPANION(&pdev->dev); + if (!adev) + return; + + guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid); + + out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0, + ACPI_GET_LOW_MODE_REGISTERS, NULL); + if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { + u32 size = out_obj->buffer.length; + + if (size != lpm_size) { + acpi_handle_debug(adev->handle, + "_DSM returned unexpected buffer size, have %u, expect %u\n", + size, lpm_size); + goto free_acpi_obj; + } + } else { + acpi_handle_debug(adev->handle, + "_DSM function 0 evaluation failed\n"); + goto free_acpi_obj; + } + + addr = (u32 *)out_obj->buffer.pointer; + + lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32), + GFP_KERNEL); + if (!lpm_req_regs) + goto free_acpi_obj; + + memcpy(lpm_req_regs, addr, lpm_size); + pmcdev->lpm_req_regs = lpm_req_regs; + +free_acpi_obj: + ACPI_FREE(out_obj); +} + static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset) { return readl(pmcdev->regbase + reg_offset); @@ -603,6 +661,115 @@ static inline u64 pmc_core_adjust_slp_s0_step(struct pmc_dev *pmcdev, u32 value) return (u64)value * pmcdev->map->slp_s0_res_counter_step; } +static int set_etr3(struct pmc_dev *pmcdev) +{ + const struct pmc_reg_map *map = pmcdev->map; + u32 reg; + int err; + + if (!map->etr3_offset) + return -EOPNOTSUPP; + + mutex_lock(&pmcdev->lock); + + /* check if CF9 is locked */ + reg = pmc_core_reg_read(pmcdev, map->etr3_offset); + if (reg & ETR3_CF9LOCK) { + err = -EACCES; + goto out_unlock; + } + + /* write CF9 global reset bit */ + reg |= ETR3_CF9GR; + pmc_core_reg_write(pmcdev, map->etr3_offset, reg); + + reg = pmc_core_reg_read(pmcdev, map->etr3_offset); + if (!(reg & ETR3_CF9GR)) { + err = -EIO; + goto out_unlock; + } + + err = 0; + +out_unlock: + mutex_unlock(&pmcdev->lock); + return err; +} +static umode_t etr3_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct pmc_dev *pmcdev = dev_get_drvdata(dev); + const struct pmc_reg_map *map = pmcdev->map; + u32 reg; + + mutex_lock(&pmcdev->lock); + reg = pmc_core_reg_read(pmcdev, map->etr3_offset); + mutex_unlock(&pmcdev->lock); + + return reg & ETR3_CF9LOCK ? attr->mode & (SYSFS_PREALLOC | 0444) : attr->mode; +} + +static ssize_t etr3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pmc_dev *pmcdev = dev_get_drvdata(dev); + const struct pmc_reg_map *map = pmcdev->map; + u32 reg; + + if (!map->etr3_offset) + return -EOPNOTSUPP; + + mutex_lock(&pmcdev->lock); + + reg = pmc_core_reg_read(pmcdev, map->etr3_offset); + reg &= ETR3_CF9GR | ETR3_CF9LOCK; + + mutex_unlock(&pmcdev->lock); + + return sysfs_emit(buf, "0x%08x", reg); +} + +static ssize_t etr3_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct pmc_dev *pmcdev = dev_get_drvdata(dev); + int err; + u32 reg; + + err = kstrtouint(buf, 16, ®); + if (err) + return err; + + /* allow only CF9 writes */ + if (reg != ETR3_CF9GR) + return -EINVAL; + + err = set_etr3(pmcdev); + if (err) + return err; + + return len; +} +static DEVICE_ATTR_RW(etr3); + +static struct attribute *pmc_attrs[] = { + &dev_attr_etr3.attr, + NULL +}; + +static const struct attribute_group pmc_attr_group = { + .attrs = pmc_attrs, + .is_visible = etr3_is_visible, +}; + +static const struct attribute_group *pmc_dev_groups[] = { + &pmc_attr_group, + NULL +}; + static int pmc_core_dev_state_get(void *data, u64 *val) { struct pmc_dev *pmcdev = data; @@ -617,9 +784,8 @@ static int pmc_core_dev_state_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n"); -static int pmc_core_check_read_lock_bit(void) +static int pmc_core_check_read_lock_bit(struct pmc_dev *pmcdev) { - struct pmc_dev *pmcdev = &pmc; u32 value; value = pmc_core_reg_read(pmcdev, pmcdev->map->pm_cfg_offset); @@ -744,28 +910,26 @@ static int pmc_core_ppfear_show(struct seq_file *s, void *unused) DEFINE_SHOW_ATTRIBUTE(pmc_core_ppfear); /* This function should return link status, 0 means ready */ -static int pmc_core_mtpmc_link_status(void) +static int pmc_core_mtpmc_link_status(struct pmc_dev *pmcdev) { - struct pmc_dev *pmcdev = &pmc; u32 value; value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET); return value & BIT(SPT_PMC_MSG_FULL_STS_BIT); } -static int pmc_core_send_msg(u32 *addr_xram) +static int pmc_core_send_msg(struct pmc_dev *pmcdev, u32 *addr_xram) { - struct pmc_dev *pmcdev = &pmc; u32 dest; int timeout; for (timeout = NUM_RETRIES; timeout > 0; timeout--) { - if (pmc_core_mtpmc_link_status() == 0) + if (pmc_core_mtpmc_link_status(pmcdev) == 0) break; msleep(5); } - if (timeout <= 0 && pmc_core_mtpmc_link_status()) + if (timeout <= 0 && pmc_core_mtpmc_link_status(pmcdev)) return -EBUSY; dest = (*addr_xram & MTPMC_MASK) | (1U << 1); @@ -791,7 +955,7 @@ static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused) mutex_lock(&pmcdev->lock); - if (pmc_core_send_msg(&mphy_core_reg_low) != 0) { + if (pmc_core_send_msg(pmcdev, &mphy_core_reg_low) != 0) { err = -EBUSY; goto out_unlock; } @@ -799,7 +963,7 @@ static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused) msleep(10); val_low = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); - if (pmc_core_send_msg(&mphy_core_reg_high) != 0) { + if (pmc_core_send_msg(pmcdev, &mphy_core_reg_high) != 0) { err = -EBUSY; goto out_unlock; } @@ -842,7 +1006,7 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused) mphy_common_reg = (SPT_PMC_MPHY_COM_STS_0 << 16); mutex_lock(&pmcdev->lock); - if (pmc_core_send_msg(&mphy_common_reg) != 0) { + if (pmc_core_send_msg(pmcdev, &mphy_common_reg) != 0) { err = -EBUSY; goto out_unlock; } @@ -863,9 +1027,8 @@ out_unlock: } DEFINE_SHOW_ATTRIBUTE(pmc_core_pll); -static int pmc_core_send_ltr_ignore(u32 value) +static int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value) { - struct pmc_dev *pmcdev = &pmc; const struct pmc_reg_map *map = pmcdev->map; u32 reg; int err = 0; @@ -891,6 +1054,8 @@ static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { + struct seq_file *s = file->private_data; + struct pmc_dev *pmcdev = s->private; u32 buf_size, value; int err; @@ -900,7 +1065,7 @@ static ssize_t pmc_core_ltr_ignore_write(struct file *file, if (err) return err; - err = pmc_core_send_ltr_ignore(value); + err = pmc_core_send_ltr_ignore(pmcdev, value); return err == 0 ? count : err; } @@ -1029,21 +1194,26 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr); +static inline u64 adjust_lpm_residency(struct pmc_dev *pmcdev, u32 offset, + const int lpm_adj_x2) +{ + u64 lpm_res = pmc_core_reg_read(pmcdev, offset); + + return GET_X2_COUNTER((u64)lpm_adj_x2 * lpm_res); +} + static int pmc_core_substate_res_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - const char **lpm_modes = pmcdev->map->lpm_modes; + const int lpm_adj_x2 = pmcdev->map->lpm_res_counter_step_x2; u32 offset = pmcdev->map->lpm_residency_offset; - u32 lpm_en; - int index; + int i, mode; - lpm_en = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_en_offset); - seq_printf(s, "status substate residency\n"); - for (index = 0; lpm_modes[index]; index++) { - seq_printf(s, "%7s %7s %-15u\n", - BIT(index) & lpm_en ? "Enabled" : " ", - lpm_modes[index], pmc_core_reg_read(pmcdev, offset)); - offset += 4; + seq_printf(s, "%-10s %-15s\n", "Substate", "Residency"); + + pmc_for_each_mode(i, mode, pmcdev) { + seq_printf(s, "%-10s %-15llu\n", pmc_lpm_modes[mode], + adjust_lpm_residency(pmcdev, offset + (4 * mode), lpm_adj_x2)); } return 0; @@ -1074,6 +1244,190 @@ static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs); +static void pmc_core_substate_req_header_show(struct seq_file *s) +{ + struct pmc_dev *pmcdev = s->private; + int i, mode; + + seq_printf(s, "%30s |", "Element"); + pmc_for_each_mode(i, mode, pmcdev) + seq_printf(s, " %9s |", pmc_lpm_modes[mode]); + + seq_printf(s, " %9s |\n", "Status"); +} + +static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + const struct pmc_bit_map **maps = pmcdev->map->lpm_sts; + const struct pmc_bit_map *map; + const int num_maps = pmcdev->map->lpm_num_maps; + u32 sts_offset = pmcdev->map->lpm_status_offset; + u32 *lpm_req_regs = pmcdev->lpm_req_regs; + int mp; + + /* Display the header */ + pmc_core_substate_req_header_show(s); + + /* Loop over maps */ + for (mp = 0; mp < num_maps; mp++) { + u32 req_mask = 0; + u32 lpm_status; + int mode, idx, i, len = 32; + + /* + * Capture the requirements and create a mask so that we only + * show an element if it's required for at least one of the + * enabled low power modes + */ + pmc_for_each_mode(idx, mode, pmcdev) + req_mask |= lpm_req_regs[mp + (mode * num_maps)]; + + /* Get the last latched status for this map */ + lpm_status = pmc_core_reg_read(pmcdev, sts_offset + (mp * 4)); + + /* Loop over elements in this map */ + map = maps[mp]; + for (i = 0; map[i].name && i < len; i++) { + u32 bit_mask = map[i].bit_mask; + + if (!(bit_mask & req_mask)) + /* + * Not required for any enabled states + * so don't display + */ + continue; + + /* Display the element name in the first column */ + seq_printf(s, "%30s |", map[i].name); + + /* Loop over the enabled states and display if required */ + pmc_for_each_mode(idx, mode, pmcdev) { + if (lpm_req_regs[mp + (mode * num_maps)] & bit_mask) + seq_printf(s, " %9s |", + "Required"); + else + seq_printf(s, " %9s |", " "); + } + + /* In Status column, show the last captured state of this agent */ + if (lpm_status & bit_mask) + seq_printf(s, " %9s |", "Yes"); + else + seq_printf(s, " %9s |", " "); + + seq_puts(s, "\n"); + } + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_req_regs); + +static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + bool c10; + u32 reg; + int idx, mode; + + reg = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_sts_latch_en_offset); + if (reg & LPM_STS_LATCH_MODE) { + seq_puts(s, "c10"); + c10 = false; + } else { + seq_puts(s, "[c10]"); + c10 = true; + } + + pmc_for_each_mode(idx, mode, pmcdev) { + if ((BIT(mode) & reg) && !c10) + seq_printf(s, " [%s]", pmc_lpm_modes[mode]); + else + seq_printf(s, " %s", pmc_lpm_modes[mode]); + } + + seq_puts(s, " clear\n"); + + return 0; +} + +static ssize_t pmc_core_lpm_latch_mode_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct pmc_dev *pmcdev = s->private; + bool clear = false, c10 = false; + unsigned char buf[8]; + int idx, m, mode; + u32 reg; + + if (count > sizeof(buf) - 1) + return -EINVAL; + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = '\0'; + + /* + * Allowed strings are: + * Any enabled substate, e.g. 'S0i2.0' + * 'c10' + * 'clear' + */ + mode = sysfs_match_string(pmc_lpm_modes, buf); + + /* Check string matches enabled mode */ + pmc_for_each_mode(idx, m, pmcdev) + if (mode == m) + break; + + if (mode != m || mode < 0) { + if (sysfs_streq(buf, "clear")) + clear = true; + else if (sysfs_streq(buf, "c10")) + c10 = true; + else + return -EINVAL; + } + + if (clear) { + mutex_lock(&pmcdev->lock); + + reg = pmc_core_reg_read(pmcdev, pmcdev->map->etr3_offset); + reg |= ETR3_CLEAR_LPM_EVENTS; + pmc_core_reg_write(pmcdev, pmcdev->map->etr3_offset, reg); + + mutex_unlock(&pmcdev->lock); + + return count; + } + + if (c10) { + mutex_lock(&pmcdev->lock); + + reg = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_sts_latch_en_offset); + reg &= ~LPM_STS_LATCH_MODE; + pmc_core_reg_write(pmcdev, pmcdev->map->lpm_sts_latch_en_offset, reg); + + mutex_unlock(&pmcdev->lock); + + return count; + } + + /* + * For LPM mode latching we set the latch enable bit and selected mode + * and clear everything else. + */ + reg = LPM_STS_LATCH_MODE | BIT(mode); + mutex_lock(&pmcdev->lock); + pmc_core_reg_write(pmcdev, pmcdev->map->lpm_sts_latch_en_offset, reg); + mutex_unlock(&pmcdev->lock); + + return count; +} +DEFINE_PMC_CORE_ATTR_WRITE(pmc_core_lpm_latch_mode); + static int pmc_core_pkgc_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; @@ -1095,6 +1449,45 @@ static int pmc_core_pkgc_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc); +static void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev) +{ + u8 lpm_priority[LPM_MAX_NUM_MODES]; + u32 lpm_en; + int mode, i, p; + + /* Use LPM Maps to indicate support for substates */ + if (!pmcdev->map->lpm_num_maps) + return; + + lpm_en = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_en_offset); + pmcdev->num_lpm_modes = hweight32(lpm_en); + + /* Each byte contains information for 2 modes (7:4 and 3:0) */ + for (mode = 0; mode < LPM_MAX_NUM_MODES; mode += 2) { + u8 priority = pmc_core_reg_read_byte(pmcdev, + pmcdev->map->lpm_priority_offset + (mode / 2)); + int pri0 = GENMASK(3, 0) & priority; + int pri1 = (GENMASK(7, 4) & priority) >> 4; + + lpm_priority[pri0] = mode; + lpm_priority[pri1] = mode + 1; + } + + /* + * Loop though all modes from lowest to highest priority, + * and capture all enabled modes in order + */ + i = 0; + for (p = LPM_MAX_NUM_MODES - 1; p >= 0; p--) { + int mode = lpm_priority[p]; + + if (!(BIT(mode) & lpm_en)) + continue; + + pmcdev->lpm_en_modes[i++] = mode; + } +} + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -1153,6 +1546,15 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev) debugfs_create_file("substate_live_status_registers", 0444, pmcdev->dbgfs_dir, pmcdev, &pmc_core_substate_l_sts_regs_fops); + debugfs_create_file("lpm_latch_mode", 0644, + pmcdev->dbgfs_dir, pmcdev, + &pmc_core_lpm_latch_mode_fops); + } + + if (pmcdev->lpm_req_regs) { + debugfs_create_file("substate_requirements", 0444, + pmcdev->dbgfs_dir, pmcdev, + &pmc_core_substate_req_regs_fops); } } @@ -1171,6 +1573,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, &tgl_reg_map), X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, &icl_reg_map), X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &tgl_reg_map), + X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &tgl_reg_map), {} }; @@ -1186,9 +1589,15 @@ static const struct pci_device_id pmc_pci_ids[] = { * the platform BIOS enforces 24Mhz crystal to shutdown * before PMC can assert SLP_S0#. */ +static bool xtal_ignore; static int quirk_xtal_ignore(const struct dmi_system_id *id) { - struct pmc_dev *pmcdev = &pmc; + xtal_ignore = true; + return 0; +} + +static void pmc_core_xtal_ignore(struct pmc_dev *pmcdev) +{ u32 value; value = pmc_core_reg_read(pmcdev, pmcdev->map->pm_vric1_offset); @@ -1197,7 +1606,6 @@ static int quirk_xtal_ignore(const struct dmi_system_id *id) /* Low Voltage Mode Enable */ value &= ~SPT_PMC_VRIC1_SLPS0LVEN; pmc_core_reg_write(pmcdev, pmcdev->map->pm_vric1_offset, value); - return 0; } static const struct dmi_system_id pmc_core_dmi_table[] = { @@ -1212,16 +1620,30 @@ static const struct dmi_system_id pmc_core_dmi_table[] = { {} }; +static void pmc_core_do_dmi_quirks(struct pmc_dev *pmcdev) +{ + dmi_check_system(pmc_core_dmi_table); + + if (xtal_ignore) + pmc_core_xtal_ignore(pmcdev); +} + static int pmc_core_probe(struct platform_device *pdev) { static bool device_initialized; - struct pmc_dev *pmcdev = &pmc; + struct pmc_dev *pmcdev; const struct x86_cpu_id *cpu_id; u64 slp_s0_addr; if (device_initialized) return -ENODEV; + pmcdev = devm_kzalloc(&pdev->dev, sizeof(*pmcdev), GFP_KERNEL); + if (!pmcdev) + return -ENOMEM; + + platform_set_drvdata(pdev, pmcdev); + cpu_id = x86_match_cpu(intel_pmc_core_ids); if (!cpu_id) return -ENODEV; @@ -1251,9 +1673,13 @@ static int pmc_core_probe(struct platform_device *pdev) return -ENOMEM; mutex_init(&pmcdev->lock); - platform_set_drvdata(pdev, pmcdev); - pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); - dmi_check_system(pmc_core_dmi_table); + + pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(pmcdev); + pmc_core_get_low_power_modes(pmcdev); + pmc_core_do_dmi_quirks(pmcdev); + + if (pmcdev->map == &tgl_reg_map) + pmc_core_get_tgl_lpm_reqs(pdev); /* * On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when @@ -1261,7 +1687,7 @@ static int pmc_core_probe(struct platform_device *pdev) */ if (pmcdev->map == &tgl_reg_map) { dev_dbg(&pdev->dev, "ignoring GBE LTR\n"); - pmc_core_send_ltr_ignore(3); + pmc_core_send_ltr_ignore(pmcdev, 3); } pmc_core_dbgfs_register(pmcdev); @@ -1384,6 +1810,7 @@ static struct platform_driver pmc_core_driver = { .name = "intel_pmc_core", .acpi_match_table = ACPI_PTR(pmc_core_acpi_ids), .pm = &pmc_core_pm_ops, + .dev_groups = pmc_dev_groups, }, .probe = pmc_core_probe, .remove = pmc_core_remove, diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index f33cd2c3483594fcfcae074e63d97905df7677df..e8dae9c6c45fbdc8fae202c4eae47956bc3a6e9c 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -187,20 +187,38 @@ enum ppfear_regs { #define ICL_PMC_LTR_WIGIG 0x1BFC #define ICL_PMC_SLP_S0_RES_COUNTER_STEP 0x64 -#define TGL_NUM_IP_IGN_ALLOWED 22 +#define LPM_MAX_NUM_MODES 8 +#define GET_X2_COUNTER(v) ((v) >> 1) +#define LPM_STS_LATCH_MODE BIT(31) + #define TGL_PMC_SLP_S0_RES_COUNTER_STEP 0x7A +#define TGL_PMC_LTR_THC0 0x1C04 +#define TGL_PMC_LTR_THC1 0x1C08 +#define TGL_NUM_IP_IGN_ALLOWED 23 +#define TGL_PMC_LPM_RES_COUNTER_STEP_X2 61 /* 30.5us * 2 */ /* * Tigerlake Power Management Controller register offsets */ +#define TGL_LPM_STS_LATCH_EN_OFFSET 0x1C34 #define TGL_LPM_EN_OFFSET 0x1C78 #define TGL_LPM_RESIDENCY_OFFSET 0x1C80 /* Tigerlake Low Power Mode debug registers */ #define TGL_LPM_STATUS_OFFSET 0x1C3C #define TGL_LPM_LIVE_STATUS_OFFSET 0x1C5C +#define TGL_LPM_PRI_OFFSET 0x1C7C +#define TGL_LPM_NUM_MAPS 6 + +/* Extended Test Mode Register 3 (CNL and later) */ +#define ETR3_OFFSET 0x1048 +#define ETR3_CF9GR BIT(20) +#define ETR3_CF9LOCK BIT(31) + +/* Extended Test Mode Register LPM bits (TGL and later */ +#define ETR3_CLEAR_LPM_EVENTS BIT(28) -const char *tgl_lpm_modes[] = { +const char *pmc_lpm_modes[] = { "S0i2.0", "S0i2.1", "S0i2.2", @@ -258,11 +276,15 @@ struct pmc_reg_map { const u32 ltr_ignore_max; const u32 pm_vric1_offset; /* Low Power Mode registers */ - const char **lpm_modes; + const int lpm_num_maps; + const int lpm_res_counter_step_x2; + const u32 lpm_sts_latch_en_offset; const u32 lpm_en_offset; + const u32 lpm_priority_offset; const u32 lpm_residency_offset; const u32 lpm_status_offset; const u32 lpm_live_status_offset; + const u32 etr3_offset; }; /** @@ -278,6 +300,9 @@ struct pmc_reg_map { * @check_counters: On resume, check if counters are getting incremented * @pc10_counter: PC10 residency counter * @s0ix_counter: S0ix residency (step adjusted) + * @num_lpm_modes: Count of enabled modes + * @lpm_en_modes: Array of enabled modes from lowest to highest priority + * @lpm_req_regs: List of substate requirements * * pmc_dev contains info about power management controller device. */ @@ -292,6 +317,28 @@ struct pmc_dev { bool check_counters; /* Check for counter increments on resume */ u64 pc10_counter; u64 s0ix_counter; + int num_lpm_modes; + int lpm_en_modes[LPM_MAX_NUM_MODES]; + u32 *lpm_req_regs; }; +#define pmc_for_each_mode(i, mode, pmcdev) \ + for (i = 0, mode = pmcdev->lpm_en_modes[i]; \ + i < pmcdev->num_lpm_modes; \ + i++, mode = pmcdev->lpm_en_modes[i]) + +#define DEFINE_PMC_CORE_ATTR_WRITE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __name ## _show, inode->i_private); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .write = __name ## _write, \ + .release = single_release, \ +} + #endif /* PMC_CORE_H */ diff --git a/drivers/platform/x86/intel_pmt_class.c b/drivers/platform/x86/intel_pmt_class.c index ee2b3bbeb83da51ab7330dbf790c77663c39b47c..c86ff15b1ed522be06f2c670a2f62c3bef70aa7d 100644 --- a/drivers/platform/x86/intel_pmt_class.c +++ b/drivers/platform/x86/intel_pmt_class.c @@ -19,6 +19,28 @@ #define PMT_XA_MAX INT_MAX #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) +/* + * Early implementations of PMT on client platforms have some + * differences from the server platforms (which use the Out Of Band + * Management Services Module OOBMSM). This list tracks those + * platforms as needed to handle those differences. Newer client + * platforms are expected to be fully compatible with server. + */ +static const struct pci_device_id pmt_telem_early_client_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */ + { PCI_VDEVICE(INTEL, 0x490e) }, /* DG1 */ + { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */ + { } +}; + +bool intel_pmt_is_early_client_hw(struct device *dev) +{ + struct pci_dev *parent = to_pci_dev(dev->parent); + + return !!pci_match_id(pmt_telem_early_client_pci_ids, parent); +} +EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw); + /* * sysfs */ @@ -147,6 +169,30 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry, * base address = end of discovery region + base offset */ entry->base_addr = disc_res->end + 1 + header->base_offset; + + /* + * 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 + * 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. + */ + if (intel_pmt_is_early_client_hw(dev)) { + int i; + + entry->base_addr = 0; + for (i = 0; i < 6; i++) + if (disc_res->start >= pci_resource_start(pci_dev, i) && + (disc_res->start <= pci_resource_end(pci_dev, i))) { + entry->base_addr = pci_resource_start(pci_dev, i) + + header->base_offset; + break; + } + if (!entry->base_addr) + return -EINVAL; + } + break; case ACCESS_BARID: /* diff --git a/drivers/platform/x86/intel_pmt_class.h b/drivers/platform/x86/intel_pmt_class.h index de8f8139ba3116ed9cbb0dc430fa7e071d107d62..1337019c2873eb37b3abda073700228437bb0b36 100644 --- a/drivers/platform/x86/intel_pmt_class.h +++ b/drivers/platform/x86/intel_pmt_class.h @@ -44,6 +44,7 @@ struct intel_pmt_namespace { struct device *dev); }; +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, struct platform_device *pdev, int idx); diff --git a/drivers/platform/x86/intel_pmt_telemetry.c b/drivers/platform/x86/intel_pmt_telemetry.c index f8a87614efa433ceac24bce3b43d72f99bf503d4..9b95ef0504576fcd998b2c567d819961daf37f07 100644 --- a/drivers/platform/x86/intel_pmt_telemetry.c +++ b/drivers/platform/x86/intel_pmt_telemetry.c @@ -34,26 +34,6 @@ struct pmt_telem_priv { struct intel_pmt_entry entry[]; }; -/* - * Early implementations of PMT on client platforms have some - * differences from the server platforms (which use the Out Of Band - * Management Services Module OOBMSM). This list tracks those - * platforms as needed to handle those differences. Newer client - * platforms are expected to be fully compatible with server. - */ -static const struct pci_device_id pmt_telem_early_client_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */ - { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */ - { } -}; - -static bool intel_pmt_is_early_client_hw(struct device *dev) -{ - struct pci_dev *parent = to_pci_dev(dev->parent); - - return !!pci_match_id(pmt_telem_early_client_pci_ids, parent); -} - static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry, struct device *dev) { diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c index a2a2d923e60cbf1347cee9b5785feb3cabb5d524..df1fc6c719f323d0e021208bbe147f4ed19748d3 100644 --- a/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c +++ b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c @@ -21,12 +21,16 @@ #define PUNIT_MAILBOX_BUSY_BIT 31 /* - * The average time to complete some commands is about 40us. The current - * count is enough to satisfy 40us. But when the firmware is very busy, this - * causes timeout occasionally. So increase to deal with some worst case - * scenarios. Most of the command still complete in few us. + * The average time to complete mailbox commands is less than 40us. Most of + * the commands complete in few micro seconds. But the same firmware handles + * requests from all power management features. + * We can create a scenario where we flood the firmware with requests then + * the mailbox response can be delayed for 100s of micro seconds. So define + * two timeouts. One for average case and one for long. + * If the firmware is taking more than average, just call cond_resched(). */ -#define OS_MAILBOX_RETRY_COUNT 100 +#define OS_MAILBOX_TIMEOUT_AVG_US 40 +#define OS_MAILBOX_TIMEOUT_MAX_US 1000 struct isst_if_device { struct mutex mutex; @@ -35,11 +39,13 @@ struct isst_if_device { static int isst_if_mbox_cmd(struct pci_dev *pdev, struct isst_if_mbox_cmd *mbox_cmd) { - u32 retries, data; + s64 tm_delta = 0; + ktime_t tm; + u32 data; int ret; /* Poll for rb bit == 0 */ - retries = OS_MAILBOX_RETRY_COUNT; + tm = ktime_get(); do { ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, &data); @@ -48,11 +54,14 @@ static int isst_if_mbox_cmd(struct pci_dev *pdev, if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) { ret = -EBUSY; + tm_delta = ktime_us_delta(ktime_get(), tm); + if (tm_delta > OS_MAILBOX_TIMEOUT_AVG_US) + cond_resched(); continue; } ret = 0; break; - } while (--retries); + } while (tm_delta < OS_MAILBOX_TIMEOUT_MAX_US); if (ret) return ret; @@ -74,7 +83,8 @@ static int isst_if_mbox_cmd(struct pci_dev *pdev, return ret; /* Poll for rb bit == 0 */ - retries = OS_MAILBOX_RETRY_COUNT; + tm_delta = 0; + tm = ktime_get(); do { ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, &data); @@ -83,6 +93,9 @@ static int isst_if_mbox_cmd(struct pci_dev *pdev, if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) { ret = -EBUSY; + tm_delta = ktime_us_delta(ktime_get(), tm); + if (tm_delta > OS_MAILBOX_TIMEOUT_AVG_US) + cond_resched(); continue; } @@ -96,7 +109,7 @@ static int isst_if_mbox_cmd(struct pci_dev *pdev, mbox_cmd->resp_data = data; ret = 0; break; - } while (--retries); + } while (tm_delta < OS_MAILBOX_TIMEOUT_MAX_US); return ret; } diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index dd900a76d8de5b3846407c88eb565a5eb2b2a3e3..20145b539335b79ee8070ab4cff69215eb05627f 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -678,7 +678,7 @@ static int __init acpi_init(void) result = acpi_bus_register_driver(&acpi_driver); if (result < 0) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error registering driver\n")); + pr_debug("Error registering driver\n"); return -ENODEV; } diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 6388c3c705a6615d28b799dbad5a0e0fd0923b9b..d4f444401496e869c61bb42db051aa96d8590849 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -973,7 +973,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) pcc->mute = pcc->sinf[SINF_MUTE]; pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT]; - result = pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT]; + pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT]; /* add sysfs attributes */ result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group); diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index ca684ed760d147c0cc82753b28d8632b843fa889..a9d2a4b98e57022ec5deadb0ecea5f63c4c33823 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -393,34 +393,10 @@ static const struct dmi_system_id critclk_systems[] = { }, { /* pmc_plt_clk* - are used for ethernet controllers */ - .ident = "Beckhoff CB3163", + .ident = "Beckhoff Baytrail", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"), - DMI_MATCH(DMI_BOARD_NAME, "CB3163"), - }, - }, - { - /* pmc_plt_clk* - are used for ethernet controllers */ - .ident = "Beckhoff CB4063", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"), - DMI_MATCH(DMI_BOARD_NAME, "CB4063"), - }, - }, - { - /* pmc_plt_clk* - are used for ethernet controllers */ - .ident = "Beckhoff CB6263", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"), - DMI_MATCH(DMI_BOARD_NAME, "CB6263"), - }, - }, - { - /* pmc_plt_clk* - are used for ethernet controllers */ - .ident = "Beckhoff CB6363", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"), - DMI_MATCH(DMI_BOARD_NAME, "CB6363"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "CBxx63"), }, }, { diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 0d9e2ddbf904d2c93499dc0da3086d7b4c1a0455..dd60c9397d3521aacb36b03b25100abed8b8f689 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -175,6 +175,12 @@ enum tpacpi_hkey_event_t { or port replicator */ TP_HKEY_EV_HOTPLUG_UNDOCK = 0x4011, /* undocked from hotplug dock or port replicator */ + /* + * Thinkpad X1 Tablet series devices emit 0x4012 and 0x4013 + * when keyboard cover is attached, detached or folded onto the back + */ + TP_HKEY_EV_KBD_COVER_ATTACH = 0x4012, /* keyboard cover attached */ + TP_HKEY_EV_KBD_COVER_DETACH = 0x4013, /* keyboard cover detached or folded back */ /* User-interface events */ TP_HKEY_EV_LID_CLOSE = 0x5001, /* laptop lid closed */ @@ -3991,6 +3997,23 @@ static bool hotkey_notify_dockevent(const u32 hkey, pr_info("undocked from hotplug port replicator\n"); return true; + /* + * Deliberately ignore attaching and detaching the keybord cover to avoid + * duplicates from intel-vbtn, which already emits SW_TABLET_MODE events + * to userspace. + * + * Please refer to the following thread for more information and a preliminary + * implementation using the GTOP ("Get Tablet OPtions") interface that could be + * extended to other attachment options of the ThinkPad X1 Tablet series, such as + * the Pico cartridge dock module: + * https://lore.kernel.org/platform-driver-x86/38cb8265-1e30-d547-9e12-b4ae290be737@a-kobel.de/ + */ + case TP_HKEY_EV_KBD_COVER_ATTACH: + case TP_HKEY_EV_KBD_COVER_DETACH: + *send_acpi_ev = false; + *ignore_acpi_ev = true; + return true; + default: return false; } @@ -4088,7 +4111,7 @@ static bool hotkey_notify_6xxx(const u32 hkey, return true; case TP_HKEY_EV_KEY_FN_ESC: - /* Get the media key status to foce the status LED to update */ + /* Get the media key status to force the status LED to update */ acpi_evalf(hkey_handle, NULL, "GMKS", "v"); *send_acpi_ev = false; *ignore_acpi_ev = true; @@ -6260,6 +6283,7 @@ enum thermal_access_mode { enum { /* TPACPI_THERMAL_TPEC_* */ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ + TP_EC_FUNCREV = 0xEF, /* ACPI EC Functional revision */ TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ TPACPI_THERMAL_SENSOR_NA = -128000, /* Sensor not available */ @@ -6272,6 +6296,8 @@ struct ibm_thermal_sensors_struct { }; static enum thermal_access_mode thermal_read_mode; +static const struct attribute_group *thermal_attr_group; +static bool thermal_use_labels; /* idx is zero-based */ static int thermal_get_sensor(int idx, s32 *value) @@ -6454,11 +6480,33 @@ static const struct attribute_group thermal_temp_input8_group = { #undef THERMAL_SENSOR_ATTR_TEMP #undef THERMAL_ATTRS +static ssize_t temp1_label_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "CPU\n"); +} +static DEVICE_ATTR_RO(temp1_label); + +static ssize_t temp2_label_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "GPU\n"); +} +static DEVICE_ATTR_RO(temp2_label); + +static struct attribute *temp_label_attributes[] = { + &dev_attr_temp1_label.attr, + &dev_attr_temp2_label.attr, + NULL +}; + +static const struct attribute_group temp_label_attr_group = { + .attrs = temp_label_attributes, +}; + /* --------------------------------------------------------------------- */ static int __init thermal_init(struct ibm_init_struct *iibm) { - u8 t, ta1, ta2; + u8 t, ta1, ta2, ver = 0; int i; int acpi_tmp7; int res; @@ -6473,7 +6521,14 @@ static int __init thermal_init(struct ibm_init_struct *iibm) * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for * non-implemented, thermal sensors return 0x80 when * not available + * The above rule is unfortunately flawed. This has been seen with + * 0xC2 (power supply ID) causing thermal control problems. + * The EC version can be determined by offset 0xEF and at least for + * version 3 the Lenovo firmware team confirmed that registers 0xC0-0xC7 + * are not thermal registers. */ + if (!acpi_ec_read(TP_EC_FUNCREV, &ver)) + pr_warn("Thinkpad ACPI EC unable to access EC version\n"); ta1 = ta2 = 0; for (i = 0; i < 8; i++) { @@ -6483,11 +6538,13 @@ static int __init thermal_init(struct ibm_init_struct *iibm) ta1 = 0; break; } - if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { - ta2 |= t; - } else { - ta1 = 0; - break; + if (ver < 3) { + if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { + ta2 |= t; + } else { + ta1 = 0; + break; + } } } if (ta1 == 0) { @@ -6500,9 +6557,14 @@ static int __init thermal_init(struct ibm_init_struct *iibm) thermal_read_mode = TPACPI_THERMAL_NONE; } } else { - thermal_read_mode = - (ta2 != 0) ? - TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; + if (ver >= 3) { + thermal_read_mode = TPACPI_THERMAL_TPEC_8; + thermal_use_labels = true; + } else { + thermal_read_mode = + (ta2 != 0) ? + TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; + } } } else if (acpi_tmp7) { if (tpacpi_is_ibm() && @@ -6524,44 +6586,40 @@ static int __init thermal_init(struct ibm_init_struct *iibm) switch (thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: - res = sysfs_create_group(&tpacpi_hwmon->kobj, - &thermal_temp_input16_group); - if (res) - return res; + thermal_attr_group = &thermal_temp_input16_group; break; case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: - res = sysfs_create_group(&tpacpi_hwmon->kobj, - &thermal_temp_input8_group); - if (res) - return res; + thermal_attr_group = &thermal_temp_input8_group; break; case TPACPI_THERMAL_NONE: default: return 1; } + res = sysfs_create_group(&tpacpi_hwmon->kobj, thermal_attr_group); + if (res) + return res; + + if (thermal_use_labels) { + res = sysfs_create_group(&tpacpi_hwmon->kobj, &temp_label_attr_group); + if (res) { + sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group); + return res; + } + } + return 0; } static void thermal_exit(void) { - switch (thermal_read_mode) { - case TPACPI_THERMAL_TPEC_16: - sysfs_remove_group(&tpacpi_hwmon->kobj, - &thermal_temp_input16_group); - break; - case TPACPI_THERMAL_TPEC_8: - case TPACPI_THERMAL_ACPI_TMP07: - case TPACPI_THERMAL_ACPI_UPDT: - sysfs_remove_group(&tpacpi_hwmon->kobj, - &thermal_temp_input8_group); - break; - case TPACPI_THERMAL_NONE: - default: - break; - } + if (thermal_attr_group) + sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group); + + if (thermal_use_labels) + sysfs_remove_group(&tpacpi_hwmon->kobj, &temp_label_attr_group); } static int thermal_read(struct seq_file *m) @@ -10050,6 +10108,7 @@ static struct ibm_struct proxsensor_driver_data = { */ #define DYTC_CMD_SET 1 /* To enable/disable IC function mode */ +#define DYTC_CMD_MMC_GET 8 /* To get current MMC function and mode */ #define DYTC_CMD_RESET 0x1ff /* To reset back to default */ #define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */ @@ -10066,6 +10125,10 @@ static struct ibm_struct proxsensor_driver_data = { #define DYTC_MODE_PERFORM 2 /* High power mode aka performance */ #define DYTC_MODE_LOWPOWER 3 /* Low power mode */ #define DYTC_MODE_BALANCE 0xF /* Default mode aka balanced */ +#define DYTC_MODE_MMC_BALANCE 0 /* Default mode from MMC_GET, aka balanced */ + +#define DYTC_ERR_MASK 0xF /* Bits 0-3 in cmd result are the error result */ +#define DYTC_ERR_SUCCESS 1 /* CMD completed successful */ #define DYTC_SET_COMMAND(function, mode, on) \ (DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \ @@ -10080,6 +10143,7 @@ static bool dytc_profile_available; static enum platform_profile_option dytc_current_profile; static atomic_t dytc_ignore_event = ATOMIC_INIT(0); static DEFINE_MUTEX(dytc_mutex); +static bool dytc_mmc_get_available; static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile) { @@ -10088,6 +10152,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p *profile = PLATFORM_PROFILE_LOW_POWER; break; case DYTC_MODE_BALANCE: + case DYTC_MODE_MMC_BALANCE: *profile = PLATFORM_PROFILE_BALANCED; break; case DYTC_MODE_PERFORM: @@ -10165,7 +10230,6 @@ static int dytc_cql_command(int command, int *output) if (err) return err; } - return cmd_err; } @@ -10222,7 +10286,10 @@ static void dytc_profile_refresh(void) int perfmode; mutex_lock(&dytc_mutex); - err = dytc_cql_command(DYTC_CMD_GET, &output); + if (dytc_mmc_get_available) + err = dytc_command(DYTC_CMD_MMC_GET, &output); + else + err = dytc_cql_command(DYTC_CMD_GET, &output); mutex_unlock(&dytc_mutex); if (err) return; @@ -10271,6 +10338,16 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) if (dytc_version >= 5) { dbg_printk(TPACPI_DBG_INIT, "DYTC version %d: thermal mode available\n", dytc_version); + /* + * Check if MMC_GET functionality available + * Version > 6 and return success from MMC_GET command + */ + dytc_mmc_get_available = false; + if (dytc_version >= 6) { + err = dytc_command(DYTC_CMD_MMC_GET, &output); + if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) + dytc_mmc_get_available = true; + } /* Create platform_profile structure and register */ err = platform_profile_register(&dytc_profile); /* @@ -10473,6 +10550,111 @@ static struct ibm_struct kbdlang_driver_data = { .exit = kbdlang_exit, }; +/************************************************************************* + * DPRC(Dynamic Power Reduction Control) subdriver, for the Lenovo WWAN + * and WLAN feature. + */ +#define DPRC_GET_WWAN_ANTENNA_TYPE 0x40000 +#define DPRC_WWAN_ANTENNA_TYPE_A_BIT BIT(4) +#define DPRC_WWAN_ANTENNA_TYPE_B_BIT BIT(8) +static bool has_antennatype; +static int wwan_antennatype; + +static int dprc_command(int command, int *output) +{ + acpi_handle dprc_handle; + + if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DPRC", &dprc_handle))) { + /* Platform doesn't support DPRC */ + return -ENODEV; + } + + if (!acpi_evalf(dprc_handle, output, NULL, "dd", command)) + return -EIO; + + /* + * METHOD_ERR gets returned on devices where few commands are not supported + * for example command to get WWAN Antenna type command is not supported on + * some devices. + */ + if (*output & METHOD_ERR) + return -ENODEV; + + return 0; +} + +static int get_wwan_antenna(int *wwan_antennatype) +{ + int output, err; + + /* Get current Antenna type */ + err = dprc_command(DPRC_GET_WWAN_ANTENNA_TYPE, &output); + if (err) + return err; + + if (output & DPRC_WWAN_ANTENNA_TYPE_A_BIT) + *wwan_antennatype = 1; + else if (output & DPRC_WWAN_ANTENNA_TYPE_B_BIT) + *wwan_antennatype = 2; + else + return -ENODEV; + + return 0; +} + +/* sysfs wwan antenna type entry */ +static ssize_t wwan_antenna_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + switch (wwan_antennatype) { + case 1: + return sysfs_emit(buf, "type a\n"); + case 2: + return sysfs_emit(buf, "type b\n"); + default: + return -ENODATA; + } +} +static DEVICE_ATTR_RO(wwan_antenna_type); + +static int tpacpi_dprc_init(struct ibm_init_struct *iibm) +{ + int wwanantenna_err, err; + + wwanantenna_err = get_wwan_antenna(&wwan_antennatype); + /* + * If support isn't available (ENODEV) then quit, but don't + * return an error. + */ + if (wwanantenna_err == -ENODEV) + return 0; + + /* if there was an error return it */ + if (wwanantenna_err && (wwanantenna_err != -ENODEV)) + return wwanantenna_err; + else if (!wwanantenna_err) + has_antennatype = true; + + if (has_antennatype) { + err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr); + if (err) + return err; + } + return 0; +} + +static void dprc_exit(void) +{ + if (has_antennatype) + sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr); +} + +static struct ibm_struct dprc_driver_data = { + .name = "dprc", + .exit = dprc_exit, +}; + /**************************************************************************** **************************************************************************** * @@ -10977,6 +11159,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { .init = tpacpi_kbdlang_init, .data = &kbdlang_driver_data, }, + { + .init = tpacpi_dprc_init, + .data = &dprc_driver_data, + }, }; static int __init set_ibm_param(const char *val, const struct kernel_param *kp) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index c44a6e8dceb8c0a2f1f28e273c8e12e0ca2e7873..90fe4f8f3c2c796b8257bf3733d6b65c84d4c955 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -715,6 +715,32 @@ static const struct ts_dmi_data techbite_arc_11_6_data = { .properties = techbite_arc_11_6_props, }; +static const struct property_entry teclast_tbook11_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 8), + PROPERTY_ENTRY_U32("touchscreen-min-y", 14), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1916), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1264), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-teclast-tbook11.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data teclast_tbook11_data = { + .embedded_fw = { + .name = "silead/gsl3692-teclast-tbook11.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 43560, + .sha256 = { 0x9d, 0xb0, 0x3d, 0xf1, 0x00, 0x3c, 0xb5, 0x25, + 0x62, 0x8a, 0xa0, 0x93, 0x4b, 0xe0, 0x4e, 0x75, + 0xd1, 0x27, 0xb1, 0x65, 0x3c, 0xba, 0xa5, 0x0f, + 0xcd, 0xb4, 0xbe, 0x00, 0xbb, 0xf6, 0x43, 0x29 }, + }, + .acpi_name = "MSSL1680:00", + .properties = teclast_tbook11_props, +}; + static const struct property_entry teclast_x3_plus_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), @@ -1243,6 +1269,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "G8316_272B"), }, }, + { + /* Teclast Tbook 11 */ + .driver_data = (void *)&teclast_tbook11_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "TbooK 11"), + DMI_MATCH(DMI_PRODUCT_SKU, "E5A6_A1"), + }, + }, { /* Teclast X3 Plus */ .driver_data = (void *)&teclast_x3_plus_data, @@ -1355,7 +1390,7 @@ static void ts_dmi_add_props(struct i2c_client *client) if (has_acpi_companion(dev) && !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { - error = device_add_properties(dev, ts_data->properties); + error = device_create_managed_software_node(dev, ts_data->properties, NULL); if (error) dev_err(dev, "failed to add properties: %d\n", error); } diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c index 66b434d6307f759d985b77639d9ffea56f39efcc..80137afb97535364abb1820e312bff4da408d33a 100644 --- a/drivers/platform/x86/wmi-bmof.c +++ b/drivers/platform/x86/wmi-bmof.c @@ -86,13 +86,12 @@ static int wmi_bmof_probe(struct wmi_device *wdev, const void *context) return ret; } -static int wmi_bmof_remove(struct wmi_device *wdev) +static void wmi_bmof_remove(struct wmi_device *wdev) { struct bmof_priv *priv = dev_get_drvdata(&wdev->dev); sysfs_remove_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr); kfree(priv->bmofdata); - return 0; } static const struct wmi_device_id wmi_bmof_id_table[] = { diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index c669676ea8e8a6448e089161bd631f9e1b753e4c..62e0d56a3332b294f0955ff20c5bd04b2fd38291 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -32,7 +32,6 @@ #include <linux/fs.h> #include <uapi/linux/wmi.h> -ACPI_MODULE_NAME("wmi"); MODULE_AUTHOR("Carlos Corbacho"); MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); MODULE_LICENSE("GPL"); @@ -986,7 +985,6 @@ static int wmi_dev_remove(struct device *dev) struct wmi_block *wblock = dev_to_wblock(dev); struct wmi_driver *wdriver = container_of(dev->driver, struct wmi_driver, driver); - int ret = 0; if (wdriver->filter_callback) { misc_deregister(&wblock->char_dev); @@ -995,12 +993,12 @@ static int wmi_dev_remove(struct device *dev) } if (wdriver->remove) - ret = wdriver->remove(dev_to_wdev(dev)); + wdriver->remove(dev_to_wdev(dev)); if (ACPI_FAILURE(wmi_method_enable(wblock, 0))) dev_warn(dev, "failed to disable device\n"); - return ret; + return 0; } static struct class wmi_bus_class = { diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c index 8337c99d2ce25bab372cb82095fdb6a574eed74d..97440462aa258a4d5c52dd650895a75681828574 100644 --- a/drivers/platform/x86/xo15-ebook.c +++ b/drivers/platform/x86/xo15-ebook.c @@ -26,8 +26,6 @@ #define XO15_EBOOK_HID "XO15EBK" #define XO15_EBOOK_DEVICE_NAME "EBook Switch" -ACPI_MODULE_NAME(MODULE_NAME); - MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver"); MODULE_LICENSE("GPL"); @@ -66,8 +64,8 @@ static void ebook_switch_notify(struct acpi_device *device, u32 event) ebook_send_state(device); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); + acpi_handle_debug(device->handle, + "Unsupported event [0x%x]\n", event); break; } } diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 8933ae26c3d6934c07df37c09f5e1d706f3f20b3..e954970b50e698a35a2783558380b827a2a7077e 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -8,6 +8,7 @@ #include <linux/bitops.h> #include <linux/device.h> +#include <linux/devm-helpers.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -593,7 +594,11 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) power->axp20x_id = axp_data->axp20x_id; power->regmap = axp20x->regmap; power->num_irqs = axp_data->num_irq_names; - INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus); + + ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect, + axp20x_usb_power_poll_vbus); + if (ret) + return ret; if (power->axp20x_id == AXP202_ID) { /* Enable vbus valid checking */ @@ -652,15 +657,6 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) return 0; } -static int axp20x_usb_power_remove(struct platform_device *pdev) -{ - struct axp20x_usb_power *power = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&power->vbus_detect); - - return 0; -} - static const struct of_device_id axp20x_usb_power_match[] = { { .compatible = "x-powers,axp202-usb-power-supply", @@ -680,7 +676,6 @@ MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); static struct platform_driver axp20x_usb_power_driver = { .probe = axp20x_usb_power_probe, - .remove = axp20x_usb_power_remove, .driver = { .name = DRVNAME, .of_match_table = axp20x_usb_power_match, diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c index ab2f4bf8f603ffa947458be3b209ae66be22f757..b5d619db79f6be6ccb5978c682c07358d5c16e82 100644 --- a/drivers/power/supply/bq24735-charger.c +++ b/drivers/power/supply/bq24735-charger.c @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <linux/devm-helpers.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/init.h> @@ -473,7 +474,11 @@ static int bq24735_charger_probe(struct i2c_client *client, if (!charger->poll_interval) return 0; - INIT_DELAYED_WORK(&charger->poll, bq24735_poll); + ret = devm_delayed_work_autocancel(&client->dev, &charger->poll, + bq24735_poll); + if (ret) + return ret; + schedule_delayed_work(&charger->poll, msecs_to_jiffies(charger->poll_interval)); } @@ -481,16 +486,6 @@ static int bq24735_charger_probe(struct i2c_client *client, return 0; } -static int bq24735_charger_remove(struct i2c_client *client) -{ - struct bq24735 *charger = i2c_get_clientdata(client); - - if (charger->poll_interval) - cancel_delayed_work_sync(&charger->poll); - - return 0; -} - static const struct i2c_device_id bq24735_charger_id[] = { { "bq24735-charger", 0 }, {} @@ -509,7 +504,6 @@ static struct i2c_driver bq24735_charger_driver = { .of_match_table = bq24735_match_ids, }, .probe = bq24735_charger_probe, - .remove = bq24735_charger_remove, .id_table = bq24735_charger_id, }; diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index 10cd617516ec26168270aff95af4524aec3014e7..09f3e78af4e01fe2bdf9e2d828a7c01659e87b19 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -8,6 +8,7 @@ * Author: Auryn Verwegen * Author: Mike Looijmans */ +#include <linux/devm-helpers.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_device.h> @@ -445,15 +446,6 @@ static enum power_supply_property ltc294x_properties[] = { POWER_SUPPLY_PROP_CURRENT_NOW, }; -static int ltc294x_i2c_remove(struct i2c_client *client) -{ - struct ltc294x_info *info = i2c_get_clientdata(client); - - cancel_delayed_work_sync(&info->work); - power_supply_unregister(info->supply); - return 0; -} - static int ltc294x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -547,7 +539,10 @@ static int ltc294x_i2c_probe(struct i2c_client *client, psy_cfg.drv_data = info; - INIT_DELAYED_WORK(&info->work, ltc294x_work); + ret = devm_delayed_work_autocancel(&client->dev, &info->work, + ltc294x_work); + if (ret) + return ret; ret = ltc294x_reset(info, prescaler_exp); if (ret < 0) { @@ -555,8 +550,8 @@ static int ltc294x_i2c_probe(struct i2c_client *client, return ret; } - info->supply = power_supply_register(&client->dev, &info->supply_desc, - &psy_cfg); + info->supply = devm_power_supply_register(&client->dev, + &info->supply_desc, &psy_cfg); if (IS_ERR(info->supply)) { dev_err(&client->dev, "failed to register ltc2941\n"); return PTR_ERR(info->supply); @@ -655,7 +650,6 @@ static struct i2c_driver ltc294x_driver = { .pm = LTC294X_PM_OPS, }, .probe = ltc294x_i2c_probe, - .remove = ltc294x_i2c_remove, .shutdown = ltc294x_i2c_shutdown, .id_table = ltc294x_i2c_id, }; diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index b6a538ebb378fcde62a42b9d76ac78555af8450f..70ea404b2a36767ecfc313e0df5af4231f61bf81 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -7,6 +7,7 @@ #include <linux/bits.h> #include <linux/delay.h> +#include <linux/devm-helpers.h> #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> @@ -1165,7 +1166,10 @@ skip_gpio: } } - INIT_DELAYED_WORK(&chip->work, sbs_delayed_work); + rc = devm_delayed_work_autocancel(&client->dev, &chip->work, + sbs_delayed_work); + if (rc) + return rc; chip->power_supply = devm_power_supply_register(&client->dev, sbs_desc, &psy_cfg); @@ -1185,15 +1189,6 @@ exit_psupply: return rc; } -static int sbs_remove(struct i2c_client *client) -{ - struct sbs_info *chip = i2c_get_clientdata(client); - - cancel_delayed_work_sync(&chip->work); - - return 0; -} - #if defined CONFIG_PM_SLEEP static int sbs_suspend(struct device *dev) @@ -1248,7 +1243,6 @@ MODULE_DEVICE_TABLE(of, sbs_dt_ids); static struct i2c_driver sbs_battery_driver = { .probe_new = sbs_probe, - .remove = sbs_remove, .alert = sbs_alert, .id_table = sbs_id, .driver = { diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c index fdda2a73718614e67a6d623f8f0efbee3c53dc05..73cf68af97700796678896fa8928fddbe945305b 100644 --- a/drivers/powercap/intel_rapl_common.c +++ b/drivers/powercap/intel_rapl_common.c @@ -1069,6 +1069,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { X86_MATCH_VENDOR_FAM(AMD, 0x17, &rapl_defaults_amd), X86_MATCH_VENDOR_FAM(AMD, 0x19, &rapl_defaults_amd), + X86_MATCH_VENDOR_FAM(HYGON, 0x18, &rapl_defaults_amd), {} }; MODULE_DEVICE_TABLE(x86cpu, rapl_ids); diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c index 78213d4b5b16a9ca35f6477d594a88233f2c93ec..cc3b22881bfe930e710b0200ebb7726a6a54dd79 100644 --- a/drivers/powercap/intel_rapl_msr.c +++ b/drivers/powercap/intel_rapl_msr.c @@ -150,6 +150,7 @@ static int rapl_msr_probe(struct platform_device *pdev) case X86_VENDOR_INTEL: rapl_msr_priv = &rapl_msr_priv_intel; break; + case X86_VENDOR_HYGON: case X86_VENDOR_AMD: rapl_msr_priv = &rapl_msr_priv_amd; break; diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index e0de1df2ede079f4cb81c9f06d1ecb6228a659cd..35799e6401c992960c78e4deb4a325a2d49e9449 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -12,15 +12,14 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/interrupt.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/pps_kernel.h> -#include <linux/pps-gpio.h> #include <linux/gpio/consumer.h> #include <linux/list.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> +#include <linux/property.h> #include <linux/timer.h> #include <linux/jiffies.h> @@ -100,51 +99,42 @@ static void pps_gpio_echo_timer_callback(struct timer_list *t) gpiod_set_value(info->echo_pin, 0); } -static int pps_gpio_setup(struct platform_device *pdev) +static int pps_gpio_setup(struct device *dev) { - struct pps_gpio_device_data *data = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node; + struct pps_gpio_device_data *data = dev_get_drvdata(dev); int ret; u32 value; - data->gpio_pin = devm_gpiod_get(&pdev->dev, - NULL, /* request "gpios" */ - GPIOD_IN); - if (IS_ERR(data->gpio_pin)) { - dev_err(&pdev->dev, - "failed to request PPS GPIO\n"); - return PTR_ERR(data->gpio_pin); + data->gpio_pin = devm_gpiod_get(dev, NULL, GPIOD_IN); + if (IS_ERR(data->gpio_pin)) + return dev_err_probe(dev, PTR_ERR(data->gpio_pin), + "failed to request PPS GPIO\n"); + + data->assert_falling_edge = + device_property_read_bool(dev, "assert-falling-edge"); + + data->echo_pin = devm_gpiod_get_optional(dev, "echo", GPIOD_OUT_LOW); + if (IS_ERR(data->echo_pin)) + return dev_err_probe(dev, PTR_ERR(data->echo_pin), + "failed to request ECHO GPIO\n"); + + if (!data->echo_pin) + return 0; + + ret = device_property_read_u32(dev, "echo-active-ms", &value); + if (ret) { + dev_err(dev, "failed to get echo-active-ms from FW\n"); + return ret; } - data->echo_pin = devm_gpiod_get_optional(&pdev->dev, - "echo", - GPIOD_OUT_LOW); - if (data->echo_pin) { - if (IS_ERR(data->echo_pin)) { - dev_err(&pdev->dev, "failed to request ECHO GPIO\n"); - return PTR_ERR(data->echo_pin); - } - - ret = of_property_read_u32(np, - "echo-active-ms", - &value); - if (ret) { - dev_err(&pdev->dev, - "failed to get echo-active-ms from OF\n"); - return ret; - } - data->echo_active_ms = value; - /* sanity check on echo_active_ms */ - if (!data->echo_active_ms || data->echo_active_ms > 999) { - dev_err(&pdev->dev, - "echo-active-ms: %u - bad value from OF\n", - data->echo_active_ms); - return -EINVAL; - } + /* sanity check on echo_active_ms */ + if (!value || value > 999) { + dev_err(dev, "echo-active-ms: %u - bad value from FW\n", value); + return -EINVAL; } - if (of_property_read_bool(np, "assert-falling-edge")) - data->assert_falling_edge = true; + data->echo_active_ms = value; + return 0; } @@ -165,34 +155,26 @@ get_irqf_trigger_flags(const struct pps_gpio_device_data *data) static int pps_gpio_probe(struct platform_device *pdev) { struct pps_gpio_device_data *data; + struct device *dev = &pdev->dev; int ret; int pps_default_params; - const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data; /* allocate space for device info */ - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - platform_set_drvdata(pdev, data); + + dev_set_drvdata(dev, data); /* GPIO setup */ - if (pdata) { - data->gpio_pin = pdata->gpio_pin; - data->echo_pin = pdata->echo_pin; - - data->assert_falling_edge = pdata->assert_falling_edge; - data->capture_clear = pdata->capture_clear; - data->echo_active_ms = pdata->echo_active_ms; - } else { - ret = pps_gpio_setup(pdev); - if (ret) - return -EINVAL; - } + ret = pps_gpio_setup(dev); + if (ret) + return -EINVAL; /* IRQ setup */ ret = gpiod_to_irq(data->gpio_pin); if (ret < 0) { - dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret); + dev_err(dev, "failed to map GPIO to IRQ: %d\n", ret); return -EINVAL; } data->irq = ret; @@ -218,17 +200,17 @@ static int pps_gpio_probe(struct platform_device *pdev) pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; data->pps = pps_register_source(&data->info, pps_default_params); if (IS_ERR(data->pps)) { - dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n", + dev_err(dev, "failed to register IRQ %d as PPS source\n", data->irq); return PTR_ERR(data->pps); } /* register IRQ interrupt handler */ - ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler, + ret = devm_request_irq(dev, data->irq, pps_gpio_irq_handler, get_irqf_trigger_flags(data), data->info.name, data); if (ret) { pps_unregister_source(data->pps); - dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq); + dev_err(dev, "failed to acquire IRQ %d\n", data->irq); return -EINVAL; } @@ -243,11 +225,9 @@ static int pps_gpio_remove(struct platform_device *pdev) struct pps_gpio_device_data *data = platform_get_drvdata(pdev); pps_unregister_source(data->pps); - if (data->echo_pin) { - del_timer_sync(&data->echo_timer); - /* reset echo pin in any case */ - gpiod_set_value(data->echo_pin, 0); - } + del_timer_sync(&data->echo_timer); + /* reset echo pin in any case */ + gpiod_set_value(data->echo_pin, 0); dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq); return 0; } diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 4fd0cbf7f93180ede539706f59828963831a4f6e..bf26cc56b863a471d369dd9b9e7165a7546b2dee 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -13,8 +13,6 @@ #include <linux/pps_kernel.h> #include <linux/bug.h> -#define PPS_TTY_MAGIC 0x0001 - static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status) { struct pps_device *pps; @@ -114,7 +112,6 @@ static int __init pps_tty_init(void) /* Init PPS_TTY data */ pps_ldisc_ops.owner = THIS_MODULE; - pps_ldisc_ops.magic = PPS_TTY_MAGIC; pps_ldisc_ops.name = "pps_tty"; pps_ldisc_ops.dcd_change = pps_tty_dcd_change; pps_ldisc_ops.open = pps_tty_open; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 9a4f66ae8070da16742c9b4a3d8bfc82c23fbbc2..43d9f1884cd35970f2746c6da88ef265d22b0a7f 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -423,6 +423,15 @@ config PWM_PXA To compile this driver as a module, choose M here: the module will be called pwm-pxa. +config PWM_RASPBERRYPI_POE + tristate "Raspberry Pi Firwmware PoE Hat PWM support" + # Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only + # happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE. + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + Enable Raspberry Pi firmware controller PWM bus used to control the + official RPI PoE hat + config PWM_RCAR tristate "Renesas R-Car PWM support" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 6374d3b1d6f3445ca7f051c27ded8178beb17041..211db810c43989875f44cebd6e41cbcd1f693408 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o +obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c new file mode 100644 index 0000000000000000000000000000000000000000..043fc32e8be882005c3ed6c63e51a95f55f88967 --- /dev/null +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2021 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> + * For more information on Raspberry Pi's PoE hat see: + * https://www.raspberrypi.org/products/poe-hat/ + * + * Limitations: + * - No disable bit, so a disabled PWM is simulated by duty_cycle 0 + * - Only normal polarity + * - Fixed 12.5 kHz period + * + * The current period is completed when HW is reconfigured. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> + +#include <soc/bcm2835/raspberrypi-firmware.h> +#include <dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h> + +#define RPI_PWM_MAX_DUTY 255 +#define RPI_PWM_PERIOD_NS 80000 /* 12.5 kHz */ + +#define RPI_PWM_CUR_DUTY_REG 0x0 + +struct raspberrypi_pwm { + struct rpi_firmware *firmware; + struct pwm_chip chip; + unsigned int duty_cycle; +}; + +struct raspberrypi_pwm_prop { + __le32 reg; + __le32 val; + __le32 ret; +} __packed; + +static inline +struct raspberrypi_pwm *raspberrypi_pwm_from_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct raspberrypi_pwm, chip); +} + +static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware, + u32 reg, u32 val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = cpu_to_le32(reg), + .val = cpu_to_le32(val), + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_SET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + return 0; +} + +static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, + u32 reg, u32 *val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = reg + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_GET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + *val = le32_to_cpu(msg.val); + + return 0; +} + +static void raspberrypi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = raspberrypi_pwm_from_chip(chip); + + state->period = RPI_PWM_PERIOD_NS; + state->duty_cycle = DIV_ROUND_UP(rpipwm->duty_cycle * RPI_PWM_PERIOD_NS, + RPI_PWM_MAX_DUTY); + state->enabled = !!(rpipwm->duty_cycle); + state->polarity = PWM_POLARITY_NORMAL; +} + +static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = raspberrypi_pwm_from_chip(chip); + unsigned int duty_cycle; + int ret; + + if (state->period < RPI_PWM_PERIOD_NS || + state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) + duty_cycle = 0; + else if (state->duty_cycle < RPI_PWM_PERIOD_NS) + duty_cycle = DIV_ROUND_DOWN_ULL(state->duty_cycle * RPI_PWM_MAX_DUTY, + RPI_PWM_PERIOD_NS); + else + duty_cycle = RPI_PWM_MAX_DUTY; + + if (duty_cycle == rpipwm->duty_cycle) + return 0; + + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set duty cycle: %pe\n", + ERR_PTR(ret)); + return ret; + } + + rpipwm->duty_cycle = duty_cycle; + + return 0; +} + +static const struct pwm_ops raspberrypi_pwm_ops = { + .get_state = raspberrypi_pwm_get_state, + .apply = raspberrypi_pwm_apply, + .owner = THIS_MODULE, +}; + +static int raspberrypi_pwm_probe(struct platform_device *pdev) +{ + struct device_node *firmware_node; + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_pwm *rpipwm; + int ret; + + firmware_node = of_get_parent(dev->of_node); + if (!firmware_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); + of_node_put(firmware_node); + if (!firmware) + return dev_err_probe(dev, -EPROBE_DEFER, + "Failed to get firmware handle\n"); + + rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL); + if (!rpipwm) + return -ENOMEM; + + rpipwm->firmware = firmware; + rpipwm->chip.dev = dev; + rpipwm->chip.ops = &raspberrypi_pwm_ops; + rpipwm->chip.base = -1; + rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM; + + platform_set_drvdata(pdev, rpipwm); + + ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + &rpipwm->duty_cycle); + if (ret) { + dev_err(dev, "Failed to get duty cycle: %pe\n", ERR_PTR(ret)); + return ret; + } + + return pwmchip_add(&rpipwm->chip); +} + +static int raspberrypi_pwm_remove(struct platform_device *pdev) +{ + struct raspberrypi_pwm *rpipwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&rpipwm->chip); +} + +static const struct of_device_id raspberrypi_pwm_of_match[] = { + { .compatible = "raspberrypi,firmware-poe-pwm", }, + { } +}; +MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match); + +static struct platform_driver raspberrypi_pwm_driver = { + .driver = { + .name = "raspberrypi-poe-pwm", + .of_match_table = raspberrypi_pwm_of_match, + }, + .probe = raspberrypi_pwm_probe, + .remove = raspberrypi_pwm_remove, +}; +module_platform_driver(raspberrypi_pwm_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); +MODULE_DESCRIPTION("Raspberry Pi Firmware Based PWM Bus Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 77c43134bc9e7e1549ed9f4659381cb956f3ccb7..ea1d284741cbc0c37dc2d4d328dc6d382048ae52 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -422,6 +422,15 @@ config REGULATOR_HI655X This driver provides support for the voltage regulators of the Hisilicon Hi655x PMIC device. +config REGULATOR_HI6421V600 + tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" + depends on MFD_HI6421_SPMI && OF + select REGMAP + help + This driver provides support for the voltage regulators on + HiSilicon Hi6421v600 PMU / Codec IC. + This is used on Kirin 3670 boards, like HiKey 970. + config REGULATOR_ISL9305 tristate "Intersil ISL9305 regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 44d2f8bf4b740fd338b2d5396cbcb5d4a9800ccc..11c145886c981b069fe25d26fe9aeb1c9626cdf4 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o +obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c index a8b5832a5a1bb92f07b3347dfc820d4f39f03929..204a2da054f534da1e2257b4ce083c0f992197ea 100644 --- a/drivers/regulator/bd9576-regulator.c +++ b/drivers/regulator/bd9576-regulator.c @@ -206,7 +206,7 @@ static int bd957x_probe(struct platform_device *pdev) { struct regmap *regmap; struct regulator_config config = { 0 }; - int i, err; + int i; bool vout_mode, ddr_sel; const struct bd957x_regulator_data *reg_data = &bd9576_regulators[0]; unsigned int num_reg_data = ARRAY_SIZE(bd9576_regulators); @@ -279,8 +279,7 @@ static int bd957x_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "Unsupported chip type\n"); - err = -EINVAL; - goto err; + return -EINVAL; } config.dev = pdev->dev.parent; @@ -300,8 +299,7 @@ static int bd957x_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register %s regulator\n", desc->name); - err = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } /* * Clear the VOUT1 GPIO setting - rest of the regulators do not @@ -310,8 +308,7 @@ static int bd957x_probe(struct platform_device *pdev) config.ena_gpiod = NULL; } -err: - return err; + return 0; } static const struct platform_device_id bd957x_pmic_id[] = { diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 16114aea099a288a405f3fa3a69c91daf1041c52..f192bf19492ed5f19022aacaeffabe5613ef4a91 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -538,7 +538,8 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, /* The modes are bitmasks, the most power hungry modes having * the lowest values. If the requested mode isn't supported - * try higher modes. */ + * try higher modes. + */ while (*mode) { if (rdev->constraints->valid_modes_mask & *mode) return 0; @@ -931,7 +932,8 @@ static DEVICE_ATTR(bypass, 0444, regulator_bypass_show, NULL); /* Calculate the new optimum regulator operating mode based on the new total - * consumer load. All locks held by caller */ + * consumer load. All locks held by caller + */ static int drms_uA_update(struct regulator_dev *rdev) { struct regulator *sibling; @@ -1219,7 +1221,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, int cmax = constraints->max_uV; /* it's safe to autoconfigure fixed-voltage supplies - and the constraints are used by list_voltage. */ + * and the constraints are used by list_voltage. + */ if (count == 1 && !cmin) { cmin = 1; cmax = INT_MAX; @@ -1439,6 +1442,8 @@ static int set_machine_constraints(struct regulator_dev *rdev) if (rdev->constraints->always_on) rdev->use_count++; + } else if (rdev->desc->off_on_delay) { + rdev->last_off = ktime_get(); } print_constraints(rdev); @@ -2483,29 +2488,15 @@ static int _regulator_do_enable(struct regulator_dev *rdev) trace_regulator_enable(rdev_get_name(rdev)); - if (rdev->desc->off_on_delay) { + if (rdev->desc->off_on_delay && rdev->last_off) { /* if needed, keep a distance of off_on_delay from last time * this regulator was disabled. */ - unsigned long start_jiffy = jiffies; - unsigned long intended, max_delay, remaining; - - max_delay = usecs_to_jiffies(rdev->desc->off_on_delay); - intended = rdev->last_off_jiffy + max_delay; - - if (time_before(start_jiffy, intended)) { - /* calc remaining jiffies to deal with one-time - * timer wrapping. - * in case of multiple timer wrapping, either it can be - * detected by out-of-range remaining, or it cannot be - * detected and we get a penalty of - * _regulator_enable_delay(). - */ - remaining = intended - start_jiffy; - if (remaining <= max_delay) - _regulator_enable_delay( - jiffies_to_usecs(remaining)); - } + ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay); + s64 remaining = ktime_us_delta(end, ktime_get()); + + if (remaining > 0) + _regulator_enable_delay(remaining); } if (rdev->ena_pin) { @@ -2525,7 +2516,8 @@ static int _regulator_do_enable(struct regulator_dev *rdev) /* Allow the regulator to ramp; it would be useful to extend * this for bulk operations so that the regulators can ramp - * together. */ + * together. + */ trace_regulator_enable_delay(rdev_get_name(rdev)); /* If poll_enabled_time is set, poll upto the delay calculated @@ -2650,7 +2642,10 @@ static int _regulator_enable(struct regulator *regulator) goto err_disable_supply; if (rdev->use_count == 0) { - /* The regulator may on if it's not switchable or left on */ + /* + * The regulator may already be enabled if it's not switchable + * or was left on + */ ret = _regulator_is_enabled(rdev); if (ret == -EINVAL || ret == 0) { if (!regulator_ops_is_valid(rdev, @@ -2731,11 +2726,8 @@ static int _regulator_do_disable(struct regulator_dev *rdev) return ret; } - /* cares about last_off_jiffy only if off_on_delay is required by - * device. - */ if (rdev->desc->off_on_delay) - rdev->last_off_jiffy = jiffies; + rdev->last_off = ktime_get(); trace_regulator_disable_complete(rdev_get_name(rdev)); @@ -5337,10 +5329,12 @@ regulator_register(const struct regulator_desc *regulator_desc, ret = set_machine_constraints(rdev); if (ret == -EPROBE_DEFER) { /* Regulator might be in bypass mode and so needs its supply - * to set the constraints */ + * to set the constraints + */ /* FIXME: this currently triggers a chicken-and-egg problem * when creating -SUPPLY symlink in sysfs to a regulator - * that is just being created */ + * that is just being created + */ rdev_dbg(rdev, "will resolve supply early: %s\n", rdev->supply_name); ret = regulator_resolve_supply(rdev); @@ -5899,7 +5893,8 @@ static int regulator_late_cleanup(struct device *dev, void *data) if (have_full_constraints()) { /* We log since this may kill the system if it goes - * wrong. */ + * wrong. + */ rdev_info(rdev, "disabling\n"); ret = _regulator_do_disable(rdev); if (ret != 0) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index a2ede7d7897eb1a5059ae1978cc45c2e84f119ed..08cbf688e14d3fc8bc29b0519e1da693ec91d19e 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -40,6 +40,7 @@ struct da9121 { unsigned int passive_delay; int chip_irq; int variant_id; + int subvariant_id; }; /* Define ranges for different variants, enabling translation to/from @@ -812,7 +813,6 @@ static struct regmap_config da9121_2ch_regmap_config = { static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) { u32 device_id; - u8 chip_id = chip->variant_id; u32 variant_id; u8 variant_mrc, variant_vrc; char *type; @@ -839,22 +839,34 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) variant_vrc = variant_id & DA9121_MASK_OTP_VARIANT_ID_VRC; - switch (variant_vrc) { - case DA9121_VARIANT_VRC: - type = "DA9121/DA9130"; - config_match = (chip_id == DA9121_TYPE_DA9121_DA9130); + switch (chip->subvariant_id) { + case DA9121_SUBTYPE_DA9121: + type = "DA9121"; + config_match = (variant_vrc == DA9121_VARIANT_VRC); break; - case DA9220_VARIANT_VRC: - type = "DA9220/DA9132"; - config_match = (chip_id == DA9121_TYPE_DA9220_DA9132); + case DA9121_SUBTYPE_DA9130: + type = "DA9130"; + config_match = (variant_vrc == DA9130_VARIANT_VRC); break; - case DA9122_VARIANT_VRC: - type = "DA9122/DA9131"; - config_match = (chip_id == DA9121_TYPE_DA9122_DA9131); + case DA9121_SUBTYPE_DA9220: + type = "DA9220"; + config_match = (variant_vrc == DA9220_VARIANT_VRC); break; - case DA9217_VARIANT_VRC: + case DA9121_SUBTYPE_DA9132: + type = "DA9132"; + config_match = (variant_vrc == DA9132_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9122: + type = "DA9122"; + config_match = (variant_vrc == DA9122_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9131: + type = "DA9131"; + config_match = (variant_vrc == DA9131_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9217: type = "DA9217"; - config_match = (chip_id == DA9121_TYPE_DA9217); + config_match = (variant_vrc == DA9217_VARIANT_VRC); break; default: type = "Unknown"; @@ -892,15 +904,27 @@ static int da9121_assign_chip_model(struct i2c_client *i2c, chip->dev = &i2c->dev; - switch (chip->variant_id) { - case DA9121_TYPE_DA9121_DA9130: - fallthrough; - case DA9121_TYPE_DA9217: + /* Use configured subtype to select the regulator descriptor index and + * register map, common to both consumer and automotive grade variants + */ + switch (chip->subvariant_id) { + case DA9121_SUBTYPE_DA9121: + case DA9121_SUBTYPE_DA9130: + chip->variant_id = DA9121_TYPE_DA9121_DA9130; regmap = &da9121_1ch_regmap_config; break; - case DA9121_TYPE_DA9122_DA9131: - fallthrough; - case DA9121_TYPE_DA9220_DA9132: + case DA9121_SUBTYPE_DA9217: + chip->variant_id = DA9121_TYPE_DA9217; + regmap = &da9121_1ch_regmap_config; + break; + case DA9121_SUBTYPE_DA9122: + case DA9121_SUBTYPE_DA9131: + chip->variant_id = DA9121_TYPE_DA9122_DA9131; + regmap = &da9121_2ch_regmap_config; + break; + case DA9121_SUBTYPE_DA9220: + case DA9121_SUBTYPE_DA9132: + chip->variant_id = DA9121_TYPE_DA9220_DA9132; regmap = &da9121_2ch_regmap_config; break; } @@ -975,13 +999,13 @@ regmap_error: } static const struct of_device_id da9121_dt_ids[] = { - { .compatible = "dlg,da9121", .data = (void *) DA9121_TYPE_DA9121_DA9130 }, - { .compatible = "dlg,da9130", .data = (void *) DA9121_TYPE_DA9121_DA9130 }, - { .compatible = "dlg,da9217", .data = (void *) DA9121_TYPE_DA9217 }, - { .compatible = "dlg,da9122", .data = (void *) DA9121_TYPE_DA9122_DA9131 }, - { .compatible = "dlg,da9131", .data = (void *) DA9121_TYPE_DA9122_DA9131 }, - { .compatible = "dlg,da9220", .data = (void *) DA9121_TYPE_DA9220_DA9132 }, - { .compatible = "dlg,da9132", .data = (void *) DA9121_TYPE_DA9220_DA9132 }, + { .compatible = "dlg,da9121", .data = (void *) DA9121_SUBTYPE_DA9121 }, + { .compatible = "dlg,da9130", .data = (void *) DA9121_SUBTYPE_DA9130 }, + { .compatible = "dlg,da9217", .data = (void *) DA9121_SUBTYPE_DA9217 }, + { .compatible = "dlg,da9122", .data = (void *) DA9121_SUBTYPE_DA9122 }, + { .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 }, + { .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 }, + { .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 }, { } }; MODULE_DEVICE_TABLE(of, da9121_dt_ids); @@ -1011,7 +1035,7 @@ static int da9121_i2c_probe(struct i2c_client *i2c, } chip->pdata = i2c->dev.platform_data; - chip->variant_id = da9121_of_get_id(&i2c->dev); + chip->subvariant_id = da9121_of_get_id(&i2c->dev); ret = da9121_assign_chip_model(i2c, chip); if (ret < 0) diff --git a/drivers/regulator/da9121-regulator.h b/drivers/regulator/da9121-regulator.h index 3c34cb889ca87d1b565e774ec522e53d08db97e1..357f416e17c1df91edf66571928dfe521fe39933 100644 --- a/drivers/regulator/da9121-regulator.h +++ b/drivers/regulator/da9121-regulator.h @@ -29,6 +29,16 @@ enum da9121_variant { DA9121_TYPE_DA9217 }; +enum da9121_subvariant { + DA9121_SUBTYPE_DA9121, + DA9121_SUBTYPE_DA9130, + DA9121_SUBTYPE_DA9220, + DA9121_SUBTYPE_DA9132, + DA9121_SUBTYPE_DA9122, + DA9121_SUBTYPE_DA9131, + DA9121_SUBTYPE_DA9217 +}; + /* Minimum, maximum and default polling millisecond periods are provided * here as an example. It is expected that any final implementation will * include a modification of these settings to match the required @@ -279,6 +289,9 @@ enum da9121_variant { #define DA9220_VARIANT_VRC 0x0 #define DA9122_VARIANT_VRC 0x2 #define DA9217_VARIANT_VRC 0x7 +#define DA9130_VARIANT_VRC 0x0 +#define DA9131_VARIANT_VRC 0x1 +#define DA9132_VARIANT_VRC 0x2 /* DA9121_REG_OTP_CUSTOMER_ID */ diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index aa426183b6a1183a270b0a995af258e8c03f33d2..f3918f03aaf3dfd82d5c71788dc1f85d3fbb8825 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -24,6 +24,12 @@ /* Voltage setting */ #define FAN53555_VSEL0 0x00 #define FAN53555_VSEL1 0x01 + +#define TCS4525_VSEL0 0x11 +#define TCS4525_VSEL1 0x10 +#define TCS4525_TIME 0x13 +#define TCS4525_COMMAND 0x14 + /* Control register */ #define FAN53555_CONTROL 0x02 /* IC Type */ @@ -49,11 +55,20 @@ #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ #define FAN53526_NVOLTAGES 128 +#define TCS4525_NVOLTAGES 127 /* Numbers of voltages */ + +#define TCS_VSEL_NSEL_MASK 0x7f +#define TCS_VSEL0_MODE (1 << 7) +#define TCS_VSEL1_MODE (1 << 6) + +#define TCS_SLEW_SHIFT 3 +#define TCS_SLEW_MASK (0x3 < 3) enum fan53555_vendor { FAN53526_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_FAIRCHILD, FAN53555_VENDOR_SILERGY, + FAN53555_VENDOR_TCS, }; enum { @@ -106,6 +121,11 @@ struct fan53555_device_info { unsigned int mode_mask; /* Sleep voltage cache */ unsigned int sleep_vol_cache; + /* Slew rate */ + unsigned int slew_reg; + unsigned int slew_mask; + unsigned int slew_shift; + unsigned int slew_rate; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -189,13 +209,37 @@ static const int slew_rates[] = { 500, }; +static const int tcs_slew_rates[] = { + 18700, + 9300, + 4600, + 2300, +}; + static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); int regval = -1, i; + const int *slew_rate_t; + int slew_rate_n; - for (i = 0; i < ARRAY_SIZE(slew_rates); i++) { - if (ramp <= slew_rates[i]) + switch (di->vendor) { + case FAN53526_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + slew_rate_t = slew_rates; + slew_rate_n = ARRAY_SIZE(slew_rates); + break; + case FAN53555_VENDOR_TCS: + slew_rate_t = tcs_slew_rates; + slew_rate_n = ARRAY_SIZE(tcs_slew_rates); + break; + default: + return -EINVAL; + } + + for (i = 0; i < slew_rate_n; i++) { + if (ramp <= slew_rate_t[i]) regval = i; else break; @@ -206,8 +250,8 @@ static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) return -EINVAL; } - return regmap_update_bits(rdev->regmap, FAN53555_CONTROL, - CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT); + return regmap_update_bits(rdev->regmap, di->slew_reg, + di->slew_mask, regval << di->slew_shift); } static const struct regulator_ops fan53555_regulator_ops = { @@ -292,7 +336,9 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } - + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->slew_shift = CTL_SLEW_SHIFT; di->vsel_count = FAN53555_NVOLTAGES; return 0; @@ -312,12 +358,29 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } - + di->slew_reg = FAN53555_CONTROL; + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->slew_shift = CTL_SLEW_SHIFT; di->vsel_count = FAN53555_NVOLTAGES; return 0; } +static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di) +{ + di->slew_reg = TCS4525_TIME; + di->slew_mask = TCS_SLEW_MASK; + di->slew_shift = TCS_SLEW_MASK; + + /* Init voltage range and step */ + di->vsel_min = 600000; + di->vsel_step = 6250; + di->vsel_count = TCS4525_NVOLTAGES; + + return 0; +} + /* For 00,01,03,05 options: * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. * For 04 option: @@ -329,17 +392,41 @@ static int fan53555_device_setup(struct fan53555_device_info *di, int ret = 0; /* Setup voltage control register */ - switch (pdata->sleep_vsel_id) { - case FAN53555_VSEL_ID_0: - di->sleep_reg = FAN53555_VSEL0; - di->vol_reg = FAN53555_VSEL1; + switch (di->vendor) { + case FAN53526_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->sleep_reg = FAN53555_VSEL0; + di->vol_reg = FAN53555_VSEL1; + break; + case FAN53555_VSEL_ID_1: + di->sleep_reg = FAN53555_VSEL1; + di->vol_reg = FAN53555_VSEL0; + break; + default: + dev_err(di->dev, "Invalid VSEL ID!\n"); + return -EINVAL; + } break; - case FAN53555_VSEL_ID_1: - di->sleep_reg = FAN53555_VSEL1; - di->vol_reg = FAN53555_VSEL0; + case FAN53555_VENDOR_TCS: + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->sleep_reg = TCS4525_VSEL0; + di->vol_reg = TCS4525_VSEL1; + break; + case FAN53555_VSEL_ID_1: + di->sleep_reg = TCS4525_VSEL1; + di->vol_reg = TCS4525_VSEL0; + break; + default: + dev_err(di->dev, "Invalid VSEL ID!\n"); + return -EINVAL; + } break; default: - dev_err(di->dev, "Invalid VSEL ID!\n"); + dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; } @@ -362,6 +449,18 @@ static int fan53555_device_setup(struct fan53555_device_info *di, di->mode_reg = di->vol_reg; di->mode_mask = VSEL_MODE; break; + case FAN53555_VENDOR_TCS: + di->mode_reg = TCS4525_COMMAND; + + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->mode_mask = TCS_VSEL1_MODE; + break; + case FAN53555_VSEL_ID_1: + di->mode_mask = TCS_VSEL0_MODE; + break; + } + break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; @@ -378,6 +477,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case FAN53555_VENDOR_SILERGY: ret = fan53555_voltages_setup_silergy(di); break; + case FAN53555_VENDOR_TCS: + ret = fan53555_voltages_setup_tcs(di); + break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; @@ -449,6 +551,9 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = { }, { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY, + }, { + .compatible = "tcs,tcs4525", + .data = (void *)FAN53555_VENDOR_TCS }, { } }; @@ -554,6 +659,9 @@ static const struct i2c_device_id fan53555_id[] = { }, { .name = "syr828", .driver_data = FAN53555_VENDOR_SILERGY + }, { + .name = "tcs4525", + .driver_data = FAN53555_VENDOR_TCS }, { }, }; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index f42b394a0c46b733ef66599508846238494316d5..0e16e31c968f124c7b254e4549c994b0c8a49f72 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -508,6 +508,33 @@ int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range); +/** + * regulator_desc_list_voltage_linear - List voltages with simple calculation + * + * @desc: Regulator desc for regulator which volatges are to be listed + * @selector: Selector to convert into a voltage + * + * Regulators with a simple linear mapping between voltages and + * selectors can set min_uV and uV_step in the regulator descriptor + * and then use this function prior regulator registration to list + * the voltages. This is useful when voltages need to be listed during + * device-tree parsing. + */ +int regulator_desc_list_voltage_linear(const struct regulator_desc *desc, + unsigned int selector) +{ + if (selector >= desc->n_voltages) + return -EINVAL; + + if (selector < desc->linear_min_sel) + return 0; + + selector -= desc->linear_min_sel; + + return desc->min_uV + (desc->uV_step * selector); +} +EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear); + /** * regulator_list_voltage_linear - List voltages with simple calculation * @@ -521,14 +548,7 @@ EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range); int regulator_list_voltage_linear(struct regulator_dev *rdev, unsigned int selector) { - if (selector >= rdev->desc->n_voltages) - return -EINVAL; - if (selector < rdev->desc->linear_min_sel) - return 0; - - selector -= rdev->desc->linear_min_sel; - - return rdev->desc->min_uV + (rdev->desc->uV_step * selector); + return regulator_desc_list_voltage_linear(rdev->desc, selector); } EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); @@ -881,3 +901,68 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2) return reg1->rdev == reg2->rdev; } EXPORT_SYMBOL_GPL(regulator_is_equal); + +static int find_closest_bigger(unsigned int target, const unsigned int *table, + unsigned int num_sel, unsigned int *sel) +{ + unsigned int s, tmp, max, maxsel = 0; + bool found = false; + + max = table[0]; + + for (s = 0; s < num_sel; s++) { + if (table[s] > max) { + max = table[s]; + maxsel = s; + } + if (table[s] >= target) { + if (!found || table[s] - target < tmp - target) { + tmp = table[s]; + *sel = s; + found = true; + if (tmp == target) + break; + } + } + } + + if (!found) { + *sel = maxsel; + return -EINVAL; + } + + return 0; +} + +/** + * regulator_set_ramp_delay_regmap - set_ramp_delay() helper + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the ramp_reg + * and ramp_mask fields in their descriptor and then use this as their + * set_ramp_delay operation, saving some code. + */ +int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay) +{ + int ret; + unsigned int sel; + + if (!rdev->desc->n_ramp_values) + return -EINVAL; + + ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table, + rdev->desc->n_ramp_values, &sel); + + if (ret) { + dev_warn(rdev_get_dev(rdev), + "Can't set ramp-delay %u, setting %u\n", ramp_delay, + rdev->desc->ramp_delay_table[sel]); + } + + sel <<= ffs(rdev->desc->ramp_mask) - 1; + + return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg, + rdev->desc->ramp_mask, sel); +} +EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap); diff --git a/drivers/staging/hikey9xx/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c similarity index 100% rename from drivers/staging/hikey9xx/hi6421v600-regulator.c rename to drivers/regulator/hi6421v600-regulator.c diff --git a/drivers/regulator/mt6360-regulator.c b/drivers/regulator/mt6360-regulator.c index 15308ee29c13ef3f9367dd4e36ea76a0ce3c7085..4d34be94d166359341a581ba60a1a1693dbf4940 100644 --- a/drivers/regulator/mt6360-regulator.c +++ b/drivers/regulator/mt6360-regulator.c @@ -380,10 +380,8 @@ static int mt6360_regulator_irq_register(struct platform_device *pdev, const struct mt6360_irq_mapping *irq_desc = tbls + i; irq = platform_get_irq_byname(pdev, irq_desc->name); - if (irq < 0) { - dev_err(&pdev->dev, "Fail to get %s irq\n", irq_desc->name); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, irq_desc->handler, 0, irq_desc->name, rdev); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 564f928eb1dbd9bceef975ddb2f05ffecf68dd82..49f6c05fee34a1f10f557e4a482305f0ffe33fd3 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -422,7 +422,11 @@ device_node *regulator_of_get_init_node(struct device *dev, if (!strcmp(desc->of_match, name)) { of_node_put(search); - return of_node_get(child); + /* + * 'of_node_get(child)' is already performed by the + * for_each loop. + */ + return child; } } diff --git a/drivers/regulator/pf8x00-regulator.c b/drivers/regulator/pf8x00-regulator.c index 9b28bd63208d63af8c77af22ddf60446c5ff7822..5d319fb81288300da840806fe412d04e9c35c3d6 100644 --- a/drivers/regulator/pf8x00-regulator.c +++ b/drivers/regulator/pf8x00-regulator.c @@ -359,6 +359,7 @@ static const struct regulator_ops pf8x00_buck7_ops = { .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .get_current_limit = regulator_get_current_limit_regmap, diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 65a108c9121f55590133f05f05314372556e9531..22fec370fa610dad61778744acea9f650e581a5f 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -723,6 +723,15 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; +static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .n_voltages = 264, + .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_hfsmps515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, @@ -1033,6 +1042,49 @@ static const struct rpmh_vreg_init_data pmx55_vreg_data[] = { {}, }; +static const struct rpmh_vreg_init_data pm7325_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), +}; + +static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"), +}; + static int rpmh_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1127,6 +1179,14 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pmx55-rpmh-regulators", .data = pmx55_vreg_data, }, + { + .compatible = "qcom,pm7325-rpmh-regulators", + .data = pm7325_vreg_data, + }, + { + .compatible = "qcom,pmr735a-rpmh-regulators", + .data = pmr735a_vreg_data, + }, {} }; MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table); diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index e62e1d72d94390f0843dbc06fcd2b09aa71915a8..95677c51c1faddd7046ccecc79fa207dbd3201a8 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -5,6 +5,7 @@ #include <linux/module.h> #include <linux/delay.h> +#include <linux/devm-helpers.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/interrupt.h> @@ -1522,10 +1523,12 @@ static const struct spmi_regulator_mapping supported_regulators[] = { SPMI_VREG(ULT_LDO, N600_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000), SPMI_VREG(ULT_LDO, N900_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000), SPMI_VREG(ULT_LDO, N1200_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000), + SPMI_VREG(ULT_LDO, LV_P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, LV_P150, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, LV_P300, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, LV_P450, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, P600, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), + SPMI_VREG(ULT_LDO, P300, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, P150, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000), SPMI_VREG(ULT_LDO, P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 5000), }; @@ -1842,7 +1845,10 @@ static int spmi_regulator_of_parse(struct device_node *node, return ret; } - INIT_DELAYED_WORK(&vreg->ocp_work, spmi_regulator_vs_ocp_work); + ret = devm_delayed_work_autocancel(dev, &vreg->ocp_work, + spmi_regulator_vs_ocp_work); + if (ret) + return ret; } return 0; @@ -2157,10 +2163,8 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) vreg->regmap = regmap; if (reg->ocp) { vreg->ocp_irq = platform_get_irq_byname(pdev, reg->ocp); - if (vreg->ocp_irq < 0) { - ret = vreg->ocp_irq; - goto err; - } + if (vreg->ocp_irq < 0) + return vreg->ocp_irq; } vreg->desc.id = -1; vreg->desc.owner = THIS_MODULE; @@ -2203,8 +2207,7 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) rdev = devm_regulator_register(dev, &vreg->desc, &config); if (IS_ERR(rdev)) { dev_err(dev, "failed to register %s\n", name); - ret = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } INIT_LIST_HEAD(&vreg->node); @@ -2212,24 +2215,6 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) } return 0; - -err: - list_for_each_entry(vreg, vreg_list, node) - if (vreg->ocp_irq) - cancel_delayed_work_sync(&vreg->ocp_work); - return ret; -} - -static int qcom_spmi_regulator_remove(struct platform_device *pdev) -{ - struct spmi_regulator *vreg; - struct list_head *vreg_list = platform_get_drvdata(pdev); - - list_for_each_entry(vreg, vreg_list, node) - if (vreg->ocp_irq) - cancel_delayed_work_sync(&vreg->ocp_work); - - return 0; } static struct platform_driver qcom_spmi_regulator_driver = { @@ -2238,7 +2223,6 @@ static struct platform_driver qcom_spmi_regulator_driver = { .of_match_table = qcom_spmi_regulator_match, }, .probe = qcom_spmi_regulator_probe, - .remove = qcom_spmi_regulator_remove, }; module_platform_driver(qcom_spmi_regulator_driver); diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index 115f59530852f1e808804ac6e226f9434467e23b..28b424fe7bea7a4e5decab61577152da27a2664d 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -340,7 +340,6 @@ static const struct regulator_desc regulators[] = { static int s2mpa01_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); struct regulator_config config = { }; struct s2mpa01_info *s2mpa01; int i; @@ -356,9 +355,6 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev) for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) { struct regulator_dev *rdev; - if (pdata) - config.init_data = pdata->regulators[i].initdata; - rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(rdev)) { diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 33cf84bce05afd8de6b11c911e294a0419916a57..ebc67e3ddd4f6a3c1fa9aadc3a7155b748e78ef9 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1120,7 +1120,6 @@ static const struct regulator_desc s2mpu02_regulators[] = { static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = NULL; struct of_regulator_match *rdata = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; @@ -1171,17 +1170,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) if (!s2mps11->ext_control_gpiod) return -ENOMEM; - if (!iodev->dev->of_node) { - if (iodev->pdata) { - pdata = iodev->pdata; - goto common_reg; - } else { - dev_err(pdev->dev.parent, - "Platform data or DT node not supplied\n"); - return -ENODEV; - } - } - rdata = kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL); if (!rdata) return -ENOMEM; @@ -1193,7 +1181,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) if (ret) goto out; -common_reg: platform_set_drvdata(pdev, s2mps11); config.dev = &pdev->dev; @@ -1202,13 +1189,8 @@ common_reg: for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; - if (pdata) { - config.init_data = pdata->regulators[i].initdata; - config.of_node = pdata->regulators[i].reg_node; - } else { - config.init_data = rdata[i].init_data; - config.of_node = rdata[i].of_node; - } + config.init_data = rdata[i].init_data; + config.of_node = rdata[i].of_node; config.ena_gpiod = s2mps11->ext_control_gpiod[i]; /* * Hand the GPIO descriptor management over to the regulator diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 0e8b3caa81461cd12d884298acccf31e90c42f9b..bbadf72b94e8c19b28b449465094f40d7b875fbc 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -2,7 +2,7 @@ // // System Control and Management Interface (SCMI) based regulator driver // -// Copyright (C) 2020 ARM Ltd. +// Copyright (C) 2020-2021 ARM Ltd. // // Implements a regulator driver on top of the SCMI Voltage Protocol. // @@ -33,9 +33,12 @@ #include <linux/slab.h> #include <linux/types.h> +static const struct scmi_voltage_proto_ops *voltage_ops; + struct scmi_regulator { u32 id; struct scmi_device *sdev; + struct scmi_protocol_handle *ph; struct regulator_dev *rdev; struct device_node *of_node; struct regulator_desc desc; @@ -50,19 +53,17 @@ struct scmi_regulator_info { static int scmi_reg_enable(struct regulator_dev *rdev) { struct scmi_regulator *sreg = rdev_get_drvdata(rdev); - const struct scmi_handle *handle = sreg->sdev->handle; - return handle->voltage_ops->config_set(handle, sreg->id, - SCMI_VOLTAGE_ARCH_STATE_ON); + return voltage_ops->config_set(sreg->ph, sreg->id, + SCMI_VOLTAGE_ARCH_STATE_ON); } static int scmi_reg_disable(struct regulator_dev *rdev) { struct scmi_regulator *sreg = rdev_get_drvdata(rdev); - const struct scmi_handle *handle = sreg->sdev->handle; - return handle->voltage_ops->config_set(handle, sreg->id, - SCMI_VOLTAGE_ARCH_STATE_OFF); + return voltage_ops->config_set(sreg->ph, sreg->id, + SCMI_VOLTAGE_ARCH_STATE_OFF); } static int scmi_reg_is_enabled(struct regulator_dev *rdev) @@ -70,10 +71,8 @@ static int scmi_reg_is_enabled(struct regulator_dev *rdev) int ret; u32 config; struct scmi_regulator *sreg = rdev_get_drvdata(rdev); - const struct scmi_handle *handle = sreg->sdev->handle; - ret = handle->voltage_ops->config_get(handle, sreg->id, - &config); + ret = voltage_ops->config_get(sreg->ph, sreg->id, &config); if (ret) { dev_err(&sreg->sdev->dev, "Error %d reading regulator %s status.\n", @@ -89,9 +88,8 @@ static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev) int ret; s32 volt_uV; struct scmi_regulator *sreg = rdev_get_drvdata(rdev); - const struct scmi_handle *handle = sreg->sdev->handle; - ret = handle->voltage_ops->level_get(handle, sreg->id, &volt_uV); + ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV); if (ret) return ret; @@ -103,13 +101,12 @@ static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev, { s32 volt_uV; struct scmi_regulator *sreg = rdev_get_drvdata(rdev); - const struct scmi_handle *handle = sreg->sdev->handle; volt_uV = sreg->desc.ops->list_voltage(rdev, selector); if (volt_uV <= 0) return -EINVAL; - return handle->voltage_ops->level_set(handle, sreg->id, 0x0, volt_uV); + return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV); } static const struct regulator_ops scmi_reg_fixed_ops = { @@ -204,11 +201,10 @@ scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg, static int scmi_regulator_common_init(struct scmi_regulator *sreg) { int ret; - const struct scmi_handle *handle = sreg->sdev->handle; struct device *dev = &sreg->sdev->dev; const struct scmi_voltage_info *vinfo; - vinfo = handle->voltage_ops->info_get(handle, sreg->id); + vinfo = voltage_ops->info_get(sreg->ph, sreg->id); if (!vinfo) { dev_warn(dev, "Failure to get voltage domain %d\n", sreg->id); @@ -257,6 +253,7 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg) } static int process_scmi_regulator_of_node(struct scmi_device *sdev, + struct scmi_protocol_handle *ph, struct device_node *np, struct scmi_regulator_info *rinfo) { @@ -284,6 +281,7 @@ static int process_scmi_regulator_of_node(struct scmi_device *sdev, rinfo->sregv[dom]->id = dom; rinfo->sregv[dom]->sdev = sdev; + rinfo->sregv[dom]->ph = ph; /* get hold of good nodes */ of_node_get(np); @@ -302,11 +300,17 @@ static int scmi_regulator_probe(struct scmi_device *sdev) struct device_node *np, *child; const struct scmi_handle *handle = sdev->handle; struct scmi_regulator_info *rinfo; + struct scmi_protocol_handle *ph; - if (!handle || !handle->voltage_ops) + if (!handle) return -ENODEV; - num_doms = handle->voltage_ops->num_domains_get(handle); + voltage_ops = handle->devm_protocol_get(sdev, + SCMI_PROTOCOL_VOLTAGE, &ph); + if (IS_ERR(voltage_ops)) + return PTR_ERR(voltage_ops); + + num_doms = voltage_ops->num_domains_get(ph); if (num_doms <= 0) { if (!num_doms) { dev_err(&sdev->dev, @@ -341,10 +345,12 @@ static int scmi_regulator_probe(struct scmi_device *sdev) */ np = of_find_node_by_name(handle->dev->of_node, "regulators"); for_each_child_of_node(np, child) { - ret = process_scmi_regulator_of_node(sdev, child, rinfo); + ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo); /* abort on any mem issue */ - if (ret == -ENOMEM) + if (ret == -ENOMEM) { + of_node_put(child); return ret; + } } /* diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 4171c6f763858a034b2c35256953e14f237e944b..7043c7f6dcf007a1d85ce1c88f9451b18164bd4f 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -183,7 +183,7 @@ config RESET_SCMI config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST - default ARCH_AGILEX || ARCH_ASPEED || ARCH_BCM4908 || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARC + default ARCH_ASPEED || ARCH_BCM4908 || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC help This enables a simple reset controller driver for reset lines that that can be asserted and deasserted by toggling bits in a contiguous, @@ -205,8 +205,8 @@ config RESET_STM32MP157 This enables the RCC reset controller driver for STM32 MPUs. config RESET_SOCFPGA - bool "SoCFPGA Reset Driver" if COMPILE_TEST && !ARCH_SOCFPGA - default ARCH_SOCFPGA + bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA) + default ARM && ARCH_INTEL_SOCFPGA select RESET_SIMPLE help This enables the reset driver for the SoCFPGA ARMv7 platforms. This diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c index 02f59c06f69bb7edffc442a10e8114aefe57457e..fa23db554bcf7ae4e53314ddb83938e48dbc1b72 100644 --- a/drivers/reset/reset-raspberrypi.c +++ b/drivers/reset/reset-raspberrypi.c @@ -82,7 +82,7 @@ static int rpi_reset_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(np); + fw = devm_rpi_firmware_get(&pdev->dev, np); of_node_put(np); if (!fw) return -EPROBE_DEFER; diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c index 8d3a858e3b19702b86b223b5650a97b18fb6cf7d..4335811e0cfaa54b8d3582754c1aa44bc40c0897 100644 --- a/drivers/reset/reset-scmi.c +++ b/drivers/reset/reset-scmi.c @@ -2,7 +2,7 @@ /* * ARM System Control and Management Interface (ARM SCMI) reset driver * - * Copyright (C) 2019 ARM Ltd. + * Copyright (C) 2019-2021 ARM Ltd. */ #include <linux/module.h> @@ -11,18 +11,20 @@ #include <linux/reset-controller.h> #include <linux/scmi_protocol.h> +static const struct scmi_reset_proto_ops *reset_ops; + /** * struct scmi_reset_data - reset controller information structure * @rcdev: reset controller entity - * @handle: ARM SCMI handle used for communication with system controller + * @ph: ARM SCMI protocol handle used for communication with system controller */ struct scmi_reset_data { struct reset_controller_dev rcdev; - const struct scmi_handle *handle; + const struct scmi_protocol_handle *ph; }; #define to_scmi_reset_data(p) container_of((p), struct scmi_reset_data, rcdev) -#define to_scmi_handle(p) (to_scmi_reset_data(p)->handle) +#define to_scmi_handle(p) (to_scmi_reset_data(p)->ph) /** * scmi_reset_assert() - assert device reset @@ -37,9 +39,9 @@ struct scmi_reset_data { static int scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { - const struct scmi_handle *handle = to_scmi_handle(rcdev); + const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev); - return handle->reset_ops->assert(handle, id); + return reset_ops->assert(ph, id); } /** @@ -55,9 +57,9 @@ scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) static int scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - const struct scmi_handle *handle = to_scmi_handle(rcdev); + const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev); - return handle->reset_ops->deassert(handle, id); + return reset_ops->deassert(ph, id); } /** @@ -73,9 +75,9 @@ scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) static int scmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) { - const struct scmi_handle *handle = to_scmi_handle(rcdev); + const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev); - return handle->reset_ops->reset(handle, id); + return reset_ops->reset(ph, id); } static const struct reset_control_ops scmi_reset_ops = { @@ -90,10 +92,15 @@ static int scmi_reset_probe(struct scmi_device *sdev) struct device *dev = &sdev->dev; struct device_node *np = dev->of_node; const struct scmi_handle *handle = sdev->handle; + struct scmi_protocol_handle *ph; - if (!handle || !handle->reset_ops) + if (!handle) return -ENODEV; + reset_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_RESET, &ph); + if (IS_ERR(reset_ops)) + return PTR_ERR(reset_ops); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -101,8 +108,8 @@ static int scmi_reset_probe(struct scmi_device *sdev) data->rcdev.ops = &scmi_reset_ops; data->rcdev.owner = THIS_MODULE; data->rcdev.of_node = np; - data->rcdev.nr_resets = handle->reset_ops->num_domains_get(handle); - data->handle = handle; + data->rcdev.nr_resets = reset_ops->num_domains_get(ph); + data->ph = ph; return devm_reset_controller_register(dev, &data->rcdev); } diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 1b42ee0758d298af79e67f20c9b2a9d27a37f502..47cd12db23568d641d4795f6ad850a8f7fbc4b92 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -238,7 +238,9 @@ static int hid_time_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_TIME, - &time_state->common_attributes); + &time_state->common_attributes, + NULL, + 0); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes!\n"); return ret; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 671efee612af5e41e649d48de5957d6bd18dc066..d26947d743bcb9d134ac78f4163b4b7220cccbe8 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -85,7 +85,6 @@ struct raw3215_info { int written; /* number of bytes in write requests */ struct raw3215_req *queued_read; /* pointer to queued read requests */ struct raw3215_req *queued_write;/* pointer to queued write requests */ - struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */ wait_queue_head_t empty_wait; /* wait queue for flushing */ struct timer_list timer; /* timer for delayed output */ int line_pos; /* position on the line (for tabs) */ @@ -329,21 +328,6 @@ static inline void raw3215_try_io(struct raw3215_info *raw) } } -/* - * Call tty_wakeup from tasklet context - */ -static void raw3215_wakeup(unsigned long data) -{ - struct raw3215_info *raw = (struct raw3215_info *) data; - struct tty_struct *tty; - - tty = tty_port_tty_get(&raw->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } -} - /* * Try to start the next IO and wake up processes waiting on the tty. */ @@ -352,7 +336,7 @@ static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty) raw3215_mk_write_req(raw); raw3215_try_io(raw); if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) - tasklet_schedule(&raw->tlet); + tty_wakeup(tty); } /* @@ -644,7 +628,6 @@ static struct raw3215_info *raw3215_alloc_info(void) timer_setup(&info->timer, raw3215_timeout, 0); init_waitqueue_head(&info->empty_wait); - tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info); tty_port_init(&info->port); return info; @@ -928,15 +911,13 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp) */ static void tty3215_close(struct tty_struct *tty, struct file * filp) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; if (raw == NULL || tty->count > 1) return; tty->closing = 1; /* Shutdown the terminal */ raw3215_shutdown(raw); - tasklet_kill(&raw->tlet); tty->closing = 0; tty_port_tty_set(&raw->port, NULL); } @@ -946,9 +927,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp) */ static int tty3215_write_room(struct tty_struct *tty) { - struct raw3215_info *raw; - - raw = (struct raw3215_info *) tty->driver_data; + struct raw3215_info *raw = tty->driver_data; /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */ if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0) @@ -963,12 +942,9 @@ static int tty3215_write_room(struct tty_struct *tty) static int tty3215_write(struct tty_struct * tty, const unsigned char *buf, int count) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; int i, written; - if (!tty) - return 0; - raw = (struct raw3215_info *) tty->driver_data; written = count; while (count > 0) { for (i = 0; i < count; i++) @@ -991,12 +967,10 @@ static int tty3215_write(struct tty_struct * tty, */ static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - if (!tty) - return 0; - raw = (struct raw3215_info *) tty->driver_data; raw3215_putchar(raw, ch); + return 1; } @@ -1009,17 +983,15 @@ static void tty3215_flush_chars(struct tty_struct *tty) */ static int tty3215_chars_in_buffer(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; return raw->count; } static void tty3215_flush_buffer(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw3215_flush_buffer(raw); tty_wakeup(tty); } @@ -1029,9 +1001,8 @@ static void tty3215_flush_buffer(struct tty_struct *tty) */ static void tty3215_throttle(struct tty_struct * tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw->flags |= RAW3215_THROTTLED; } @@ -1040,10 +1011,9 @@ static void tty3215_throttle(struct tty_struct * tty) */ static void tty3215_unthrottle(struct tty_struct * tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; unsigned long flags; - raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_THROTTLED) { spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_THROTTLED; @@ -1057,9 +1027,8 @@ static void tty3215_unthrottle(struct tty_struct * tty) */ static void tty3215_stop(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw->flags |= RAW3215_STOPPED; } @@ -1068,10 +1037,9 @@ static void tty3215_stop(struct tty_struct *tty) */ static void tty3215_start(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; unsigned long flags; - raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_STOPPED) { spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_STOPPED; diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index a14684ffe4c1a8ef459a1ce9c5e6691b9e7e6601..ca4f4ca413f11d6b2c0a29ab528da14042f395d2 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -179,6 +179,21 @@ static unsigned int __init save_reg(struct intc_desc_int *d, return 0; } +static bool __init intc_map(struct irq_domain *domain, int irq) +{ + if (!irq_to_desc(irq) && irq_alloc_desc_at(irq, NUMA_NO_NODE) != irq) { + pr_err("uname to allocate IRQ %d\n", irq); + return false; + } + + if (irq_domain_associate(domain, irq, irq)) { + pr_err("domain association failure\n"); + return false; + } + + return true; +} + int __init register_intc_controller(struct intc_desc *desc) { unsigned int i, k, smp; @@ -311,24 +326,12 @@ int __init register_intc_controller(struct intc_desc *desc) for (i = 0; i < hw->nr_vectors; i++) { struct intc_vect *vect = hw->vectors + i; unsigned int irq = evt2irq(vect->vect); - int res; if (!vect->enum_id) continue; - res = irq_create_identity_mapping(d->domain, irq); - if (unlikely(res)) { - if (res == -EEXIST) { - res = irq_domain_associate(d->domain, irq, irq); - if (unlikely(res)) { - pr_err("domain association failure\n"); - continue; - } - } else { - pr_err("can't identity map IRQ %d\n", irq); - continue; - } - } + if (!intc_map(d->domain, irq)) + continue; intc_irq_xlate_set(irq, vect->enum_id, d); intc_register_irq(desc, d, vect->enum_id, irq); @@ -345,22 +348,8 @@ int __init register_intc_controller(struct intc_desc *desc) * IRQ support, each vector still needs to have * its own backing irq_desc. */ - res = irq_create_identity_mapping(d->domain, irq2); - if (unlikely(res)) { - if (res == -EEXIST) { - res = irq_domain_associate(d->domain, - irq2, irq2); - if (unlikely(res)) { - pr_err("domain association " - "failure\n"); - continue; - } - } else { - pr_err("can't identity map IRQ %d\n", - irq); - continue; - } - } + if (!intc_map(d->domain, irq2)) + continue; vect2->enum_id = 0; diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c index 439bcd6b8c4add43b43e98a860980bbaba386c61..c557ffd0992c7760555bc4754aefe8bd00db1c6e 100644 --- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c +++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c @@ -18,15 +18,15 @@ #define DEVICE_NAME "aspeed-lpc-ctrl" -#define HICR5 0x0 +#define HICR5 0x80 #define HICR5_ENL2H BIT(8) #define HICR5_ENFWH BIT(10) -#define HICR6 0x4 +#define HICR6 0x84 #define SW_FWH2AHB BIT(17) -#define HICR7 0x8 -#define HICR8 0xc +#define HICR7 0x88 +#define HICR8 0x8c struct aspeed_lpc_ctrl { struct miscdevice miscdev; @@ -215,6 +215,7 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) struct device_node *node; struct resource resm; struct device *dev; + struct device_node *np; int rc; dev = &pdev->dev; @@ -270,8 +271,15 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) } } - lpc_ctrl->regmap = syscon_node_to_regmap( - pdev->dev.parent->of_node); + np = pdev->dev.parent->of_node; + if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && + !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && + !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { + dev_err(dev, "unsupported LPC device binding\n"); + return -ENODEV; + } + + lpc_ctrl->regmap = syscon_node_to_regmap(np); if (IS_ERR(lpc_ctrl->regmap)) { dev_err(dev, "Couldn't get regmap\n"); return -ENODEV; diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 20acac6342eff6ab074cd5253ed7a9996021d8d8..eceeaf8dfbebaf73bd199cda061d5bebd928dcc5 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c @@ -29,26 +29,25 @@ #define NUM_SNOOP_CHANNELS 2 #define SNOOP_FIFO_SIZE 2048 -#define HICR5 0x0 +#define HICR5 0x80 #define HICR5_EN_SNP0W BIT(0) #define HICR5_ENINT_SNP0W BIT(1) #define HICR5_EN_SNP1W BIT(2) #define HICR5_ENINT_SNP1W BIT(3) - -#define HICR6 0x4 +#define HICR6 0x84 #define HICR6_STR_SNP0W BIT(0) #define HICR6_STR_SNP1W BIT(1) -#define SNPWADR 0x10 +#define SNPWADR 0x90 #define SNPWADR_CH0_MASK GENMASK(15, 0) #define SNPWADR_CH0_SHIFT 0 #define SNPWADR_CH1_MASK GENMASK(31, 16) #define SNPWADR_CH1_SHIFT 16 -#define SNPWDR 0x14 +#define SNPWDR 0x94 #define SNPWDR_CH0_MASK GENMASK(7, 0) #define SNPWDR_CH0_SHIFT 0 #define SNPWDR_CH1_MASK GENMASK(15, 8) #define SNPWDR_CH1_SHIFT 8 -#define HICRB 0x80 +#define HICRB 0x100 #define HICRB_ENSNP0D BIT(14) #define HICRB_ENSNP1D BIT(15) @@ -95,8 +94,10 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer, return -EINTR; } ret = kfifo_to_user(&chan->fifo, buffer, count, &copied); + if (ret) + return ret; - return ret ? ret : copied; + return copied; } static __poll_t snoop_file_poll(struct file *file, @@ -260,6 +261,7 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev) { struct aspeed_lpc_snoop *lpc_snoop; struct device *dev; + struct device_node *np; u32 port; int rc; @@ -269,8 +271,15 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev) if (!lpc_snoop) return -ENOMEM; - lpc_snoop->regmap = syscon_node_to_regmap( - pdev->dev.parent->of_node); + np = pdev->dev.parent->of_node; + if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && + !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && + !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { + dev_err(dev, "unsupported LPC device binding\n"); + return -ENODEV; + } + + lpc_snoop->regmap = syscon_node_to_regmap(np); if (IS_ERR(lpc_snoop->regmap)) { dev_err(dev, "Couldn't get regmap\n"); return -ENODEV; diff --git a/drivers/soc/bcm/bcm63xx/bcm-pmb.c b/drivers/soc/bcm/bcm63xx/bcm-pmb.c index c223023dc64f198adf15319a6c68c8b15313730e..774465c119be224f48d7bc3037cc29604a4a61d8 100644 --- a/drivers/soc/bcm/bcm63xx/bcm-pmb.c +++ b/drivers/soc/bcm/bcm63xx/bcm-pmb.c @@ -209,6 +209,28 @@ static int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device) return err; } +static int bcm_pmb_power_on_sata(struct bcm_pmb *pmb, int bus, u8 device) +{ + int err; + + err = bcm_pmb_power_on_zone(pmb, bus, device, 0); + if (err) + return err; + + /* Does not apply to the BCM963158 */ + err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_MISC_CONTROL, 0); + if (err) + return err; + + err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0xffffffff); + if (err) + return err; + + err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0); + + return err; +} + static int bcm_pmb_power_on(struct generic_pm_domain *genpd) { struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd); @@ -222,6 +244,8 @@ static int bcm_pmb_power_on(struct generic_pm_domain *genpd) return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0); case BCM_PMB_HOST_USB: return bcm_pmb_power_on_device(pmb, data->bus, data->device); + case BCM_PMB_SATA: + return bcm_pmb_power_on_sata(pmb, data->bus, data->device); default: dev_err(pmb->dev, "unsupported device id: %d\n", data->id); return -EINVAL; @@ -317,8 +341,14 @@ static const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = { { }, }; +static const struct bcm_pmb_pd_data bcm_pmb_bcm63138_data[] = { + { .name = "sata", .id = BCM_PMB_SATA, .bus = 0, .device = 3, }, + { }, +}; + static const struct of_device_id bcm_pmb_of_match[] = { { .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, }, + { .compatible = "brcm,bcm63138-pmb", .data = &bcm_pmb_bcm63138_data, }, { }, }; diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index 5d1aacdd84ef345f36820363a2c3b82c8e7c6da1..068715d6e66d7e0bed4a2d099cc6385574e84bc7 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -177,7 +177,7 @@ static int rpi_power_probe(struct platform_device *pdev) return -ENODEV; } - rpi_domains->fw = rpi_firmware_get(fw_np); + rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np); of_node_put(fw_np); if (!rpi_domains->fw) return -EPROBE_DEFER; diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c index 34810f9bb2ee781b3dbf96aa73326b2b5552a57f..d5e9a5f2c08745b75f1dcc49509a9aa856959d31 100644 --- a/drivers/soc/fsl/guts.c +++ b/drivers/soc/fsl/guts.c @@ -117,7 +117,7 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match( if (matches->svr == (svr & matches->mask)) return matches; matches++; - }; + } return NULL; } diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c index c5dd026fe889f053818e31f0759739ee4550eb8a..6cc1847e534a8ac48cb9c8751f5b3580f8d602bc 100644 --- a/drivers/soc/fsl/qbman/bman.c +++ b/drivers/soc/fsl/qbman/bman.c @@ -709,7 +709,6 @@ struct bman_pool *bman_new_pool(void) return pool; err: bm_release_bpid(bpid); - kfree(pool); return NULL; } EXPORT_SYMBOL(bman_new_pool); diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c index 923c44063a9a57b3c02b2d0415b01fd54a788e4d..acda8a5637c52066891aa3ab1f480a397cc8372a 100644 --- a/drivers/soc/fsl/qbman/bman_portal.c +++ b/drivers/soc/fsl/qbman/bman_portal.c @@ -160,7 +160,7 @@ static int bman_portal_probe(struct platform_device *pdev) __bman_portals_probed = 1; /* unassigned portal, skip init */ spin_unlock(&bman_lock); - return 0; + goto check_cleanup; } cpumask_set_cpu(cpu, &portal_cpus); @@ -176,6 +176,7 @@ static int bman_portal_probe(struct platform_device *pdev) if (!cpu_online(cpu)) bman_offline_cpu(cpu); +check_cleanup: if (__bman_portals_probed == 1 && bman_requires_cleanup()) { /* * BMan wasn't reset prior to boot (Kexec for example) diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index 5685b67068931a825a6df70449af295da332df16..4274bd1b0f997f70e7940f3df57242f592453d7c 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -302,7 +302,7 @@ static int qman_portal_probe(struct platform_device *pdev) __qman_portals_probed = 1; /* unassigned portal, skip init */ spin_unlock(&qman_lock); - return 0; + goto check_cleanup; } cpumask_set_cpu(cpu, &portal_cpus); @@ -323,6 +323,7 @@ static int qman_portal_probe(struct platform_device *pdev) if (!cpu_online(cpu)) qman_offline_cpu(cpu); +check_cleanup: if (__qman_portals_probed == 1 && qman_requires_cleanup()) { /* * QMan wasn't reset prior to boot (Kexec for example) diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index ed75198ed2543e8097bdbb66b1828e652841a91c..99f7de43c3c61b16acab8b873c64313bf3a2ffe7 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -41,13 +41,13 @@ static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) container_of(mm_gc, struct qe_gpio_chip, mm_gc); struct qe_pio_regs __iomem *regs = mm_gc->regs; - qe_gc->cpdata = qe_ioread32be(®s->cpdata); + qe_gc->cpdata = ioread32be(®s->cpdata); qe_gc->saved_regs.cpdata = qe_gc->cpdata; - qe_gc->saved_regs.cpdir1 = qe_ioread32be(®s->cpdir1); - qe_gc->saved_regs.cpdir2 = qe_ioread32be(®s->cpdir2); - qe_gc->saved_regs.cppar1 = qe_ioread32be(®s->cppar1); - qe_gc->saved_regs.cppar2 = qe_ioread32be(®s->cppar2); - qe_gc->saved_regs.cpodr = qe_ioread32be(®s->cpodr); + qe_gc->saved_regs.cpdir1 = ioread32be(®s->cpdir1); + qe_gc->saved_regs.cpdir2 = ioread32be(®s->cpdir2); + qe_gc->saved_regs.cppar1 = ioread32be(®s->cppar1); + qe_gc->saved_regs.cppar2 = ioread32be(®s->cppar2); + qe_gc->saved_regs.cpodr = ioread32be(®s->cpodr); } static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) @@ -56,7 +56,7 @@ static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) struct qe_pio_regs __iomem *regs = mm_gc->regs; u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio); - return !!(qe_ioread32be(®s->cpdata) & pin_mask); + return !!(ioread32be(®s->cpdata) & pin_mask); } static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) @@ -74,7 +74,7 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) else qe_gc->cpdata &= ~pin_mask; - qe_iowrite32be(qe_gc->cpdata, ®s->cpdata); + iowrite32be(qe_gc->cpdata, ®s->cpdata); spin_unlock_irqrestore(&qe_gc->lock, flags); } @@ -101,7 +101,7 @@ static void qe_gpio_set_multiple(struct gpio_chip *gc, } } - qe_iowrite32be(qe_gc->cpdata, ®s->cpdata); + iowrite32be(qe_gc->cpdata, ®s->cpdata); spin_unlock_irqrestore(&qe_gc->lock, flags); } @@ -269,7 +269,7 @@ void qe_pin_set_dedicated(struct qe_pin *qe_pin) else qe_gc->cpdata &= ~mask1; - qe_iowrite32be(qe_gc->cpdata, ®s->cpdata); + iowrite32be(qe_gc->cpdata, ®s->cpdata); qe_clrsetbits_be32(®s->cpodr, mask1, sregs->cpodr & mask1); spin_unlock_irqrestore(&qe_gc->lock, flags); diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index 2df20d6f85fa4c3a173e02ee0de3f9b458ac1b21..4d38c80f8be81ac0fe3e29b5ab6f106e37cc3709 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -109,7 +109,7 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) spin_lock_irqsave(&qe_lock, flags); if (cmd == QE_RESET) { - qe_iowrite32be((u32)(cmd | QE_CR_FLG), &qe_immr->cp.cecr); + iowrite32be((u32)(cmd | QE_CR_FLG), &qe_immr->cp.cecr); } else { if (cmd == QE_ASSIGN_PAGE) { /* Here device is the SNUM, not sub-block */ @@ -126,13 +126,13 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) mcn_shift = QE_CR_MCN_NORMAL_SHIFT; } - qe_iowrite32be(cmd_input, &qe_immr->cp.cecdr); - qe_iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) | (u32)mcn_protocol << mcn_shift), + iowrite32be(cmd_input, &qe_immr->cp.cecdr); + iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) | (u32)mcn_protocol << mcn_shift), &qe_immr->cp.cecr); } /* wait for the QE_CR_FLG to clear */ - ret = readx_poll_timeout_atomic(qe_ioread32be, &qe_immr->cp.cecr, val, + ret = readx_poll_timeout_atomic(ioread32be, &qe_immr->cp.cecr, val, (val & QE_CR_FLG) == 0, 0, 100); /* On timeout, ret is -ETIMEDOUT, otherwise it will be 0. */ spin_unlock_irqrestore(&qe_lock, flags); @@ -231,7 +231,7 @@ int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier) tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE | div16; - qe_iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]); + iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]); return 0; } @@ -375,9 +375,9 @@ static int qe_sdma_init(void) return -ENOMEM; } - qe_iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK, + iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK, &sdma->sdebcr); - qe_iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)), + iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)), &sdma->sdmr); return 0; @@ -416,14 +416,14 @@ static void qe_upload_microcode(const void *base, "uploading microcode '%s'\n", ucode->id); /* Use auto-increment */ - qe_iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR, + iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR, &qe_immr->iram.iadd); for (i = 0; i < be32_to_cpu(ucode->count); i++) - qe_iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); + iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); /* Set I-RAM Ready Register */ - qe_iowrite32be(QE_IRAM_READY, &qe_immr->iram.iready); + iowrite32be(QE_IRAM_READY, &qe_immr->iram.iready); } /* @@ -542,12 +542,12 @@ int qe_upload_firmware(const struct qe_firmware *firmware) u32 trap = be32_to_cpu(ucode->traps[j]); if (trap) - qe_iowrite32be(trap, + iowrite32be(trap, &qe_immr->rsp[i].tibcr[j]); } /* Enable traps */ - qe_iowrite32be(be32_to_cpu(ucode->eccr), + iowrite32be(be32_to_cpu(ucode->eccr), &qe_immr->rsp[i].eccr); } diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c index 654e9246ce6b93a4cdac5fc95ffddf7e36bcf973..a0cb8e746879f383c9c55c8d6e50c11a97197da2 100644 --- a/drivers/soc/fsl/qe/qe_common.c +++ b/drivers/soc/fsl/qe/qe_common.c @@ -26,7 +26,7 @@ #include <soc/fsl/qe/qe.h> static struct gen_pool *muram_pool; -static spinlock_t cpm_muram_lock; +static DEFINE_SPINLOCK(cpm_muram_lock); static void __iomem *muram_vbase; static phys_addr_t muram_pbase; @@ -54,7 +54,6 @@ int cpm_muram_init(void) if (muram_pbase) return 0; - spin_lock_init(&cpm_muram_lock); np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data"); if (!np) { /* try legacy bindings */ diff --git a/drivers/soc/fsl/qe/qe_ic.c b/drivers/soc/fsl/qe/qe_ic.c index 0390af999900258a8f8bfe5d5c2ec4cad6699e5f..3f711c1a0996a262a6f35eec9190e7478edb2549 100644 --- a/drivers/soc/fsl/qe/qe_ic.c +++ b/drivers/soc/fsl/qe/qe_ic.c @@ -222,13 +222,13 @@ static struct qe_ic_info qe_ic_info[] = { static inline u32 qe_ic_read(__be32 __iomem *base, unsigned int reg) { - return qe_ioread32be(base + (reg >> 2)); + return ioread32be(base + (reg >> 2)); } static inline void qe_ic_write(__be32 __iomem *base, unsigned int reg, u32 value) { - qe_iowrite32be(value, base + (reg >> 2)); + iowrite32be(value, base + (reg >> 2)); } static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) diff --git a/drivers/soc/fsl/qe/qe_io.c b/drivers/soc/fsl/qe/qe_io.c index 11ea08e97db75e0e2d06a5504c661a5ace8bcab0..e277c827bdf336f4789ff438a8413b235fc1ca1e 100644 --- a/drivers/soc/fsl/qe/qe_io.c +++ b/drivers/soc/fsl/qe/qe_io.c @@ -54,16 +54,16 @@ void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1))); /* Set open drain, if required */ - tmp_val = qe_ioread32be(&par_io->cpodr); + tmp_val = ioread32be(&par_io->cpodr); if (open_drain) - qe_iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr); + iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr); else - qe_iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr); + iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr); /* define direction */ tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? - qe_ioread32be(&par_io->cpdir2) : - qe_ioread32be(&par_io->cpdir1); + ioread32be(&par_io->cpdir2) : + ioread32be(&par_io->cpdir1); /* get all bits mask for 2 bit per port */ pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS - @@ -75,30 +75,30 @@ void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, /* clear and set 2 bits mask */ if (pin > (QE_PIO_PINS / 2) - 1) { - qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2); + iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2); tmp_val &= ~pin_mask2bits; - qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2); + iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2); } else { - qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1); + iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1); tmp_val &= ~pin_mask2bits; - qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1); + iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1); } /* define pin assignment */ tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? - qe_ioread32be(&par_io->cppar2) : - qe_ioread32be(&par_io->cppar1); + ioread32be(&par_io->cppar2) : + ioread32be(&par_io->cppar1); new_mask2bits = (u32) (assignment << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2)); /* clear and set 2 bits mask */ if (pin > (QE_PIO_PINS / 2) - 1) { - qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2); + iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2); tmp_val &= ~pin_mask2bits; - qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2); + iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2); } else { - qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1); + iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1); tmp_val &= ~pin_mask2bits; - qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1); + iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1); } } EXPORT_SYMBOL(__par_io_config_pin); @@ -126,12 +126,12 @@ int par_io_data_set(u8 port, u8 pin, u8 val) /* calculate pin location */ pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin)); - tmp_val = qe_ioread32be(&par_io[port].cpdata); + tmp_val = ioread32be(&par_io[port].cpdata); if (val == 0) /* clear */ - qe_iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata); + iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata); else /* set */ - qe_iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata); + iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata); return 0; } diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c index ad6193ea45974c6bb796bc2eb632e46b7735f78a..53d8aafc9317ecf8f7533fe3c8b4bf834960cd6e 100644 --- a/drivers/soc/fsl/qe/ucc_fast.c +++ b/drivers/soc/fsl/qe/ucc_fast.c @@ -29,42 +29,42 @@ void ucc_fast_dump_regs(struct ucc_fast_private * uccf) printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs); printk(KERN_INFO "gumr : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->gumr, qe_ioread32be(&uccf->uf_regs->gumr)); + &uccf->uf_regs->gumr, ioread32be(&uccf->uf_regs->gumr)); printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->upsmr, qe_ioread32be(&uccf->uf_regs->upsmr)); + &uccf->uf_regs->upsmr, ioread32be(&uccf->uf_regs->upsmr)); printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->utodr, qe_ioread16be(&uccf->uf_regs->utodr)); + &uccf->uf_regs->utodr, ioread16be(&uccf->uf_regs->utodr)); printk(KERN_INFO "udsr : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->udsr, qe_ioread16be(&uccf->uf_regs->udsr)); + &uccf->uf_regs->udsr, ioread16be(&uccf->uf_regs->udsr)); printk(KERN_INFO "ucce : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->ucce, qe_ioread32be(&uccf->uf_regs->ucce)); + &uccf->uf_regs->ucce, ioread32be(&uccf->uf_regs->ucce)); printk(KERN_INFO "uccm : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->uccm, qe_ioread32be(&uccf->uf_regs->uccm)); + &uccf->uf_regs->uccm, ioread32be(&uccf->uf_regs->uccm)); printk(KERN_INFO "uccs : addr=0x%p, val=0x%02x\n", - &uccf->uf_regs->uccs, qe_ioread8(&uccf->uf_regs->uccs)); + &uccf->uf_regs->uccs, ioread8(&uccf->uf_regs->uccs)); printk(KERN_INFO "urfb : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->urfb, qe_ioread32be(&uccf->uf_regs->urfb)); + &uccf->uf_regs->urfb, ioread32be(&uccf->uf_regs->urfb)); printk(KERN_INFO "urfs : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->urfs, qe_ioread16be(&uccf->uf_regs->urfs)); + &uccf->uf_regs->urfs, ioread16be(&uccf->uf_regs->urfs)); printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->urfet, qe_ioread16be(&uccf->uf_regs->urfet)); + &uccf->uf_regs->urfet, ioread16be(&uccf->uf_regs->urfet)); printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n", &uccf->uf_regs->urfset, - qe_ioread16be(&uccf->uf_regs->urfset)); + ioread16be(&uccf->uf_regs->urfset)); printk(KERN_INFO "utfb : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->utfb, qe_ioread32be(&uccf->uf_regs->utfb)); + &uccf->uf_regs->utfb, ioread32be(&uccf->uf_regs->utfb)); printk(KERN_INFO "utfs : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->utfs, qe_ioread16be(&uccf->uf_regs->utfs)); + &uccf->uf_regs->utfs, ioread16be(&uccf->uf_regs->utfs)); printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->utfet, qe_ioread16be(&uccf->uf_regs->utfet)); + &uccf->uf_regs->utfet, ioread16be(&uccf->uf_regs->utfet)); printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->utftt, qe_ioread16be(&uccf->uf_regs->utftt)); + &uccf->uf_regs->utftt, ioread16be(&uccf->uf_regs->utftt)); printk(KERN_INFO "utpt : addr=0x%p, val=0x%04x\n", - &uccf->uf_regs->utpt, qe_ioread16be(&uccf->uf_regs->utpt)); + &uccf->uf_regs->utpt, ioread16be(&uccf->uf_regs->utpt)); printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n", - &uccf->uf_regs->urtry, qe_ioread32be(&uccf->uf_regs->urtry)); + &uccf->uf_regs->urtry, ioread32be(&uccf->uf_regs->urtry)); printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n", - &uccf->uf_regs->guemr, qe_ioread8(&uccf->uf_regs->guemr)); + &uccf->uf_regs->guemr, ioread8(&uccf->uf_regs->guemr)); } EXPORT_SYMBOL(ucc_fast_dump_regs); @@ -86,7 +86,7 @@ EXPORT_SYMBOL(ucc_fast_get_qe_cr_subblock); void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf) { - qe_iowrite16be(UCC_FAST_TOD, &uccf->uf_regs->utodr); + iowrite16be(UCC_FAST_TOD, &uccf->uf_regs->utodr); } EXPORT_SYMBOL(ucc_fast_transmit_on_demand); @@ -98,7 +98,7 @@ void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) uf_regs = uccf->uf_regs; /* Enable reception and/or transmission on this UCC. */ - gumr = qe_ioread32be(&uf_regs->gumr); + gumr = ioread32be(&uf_regs->gumr); if (mode & COMM_DIR_TX) { gumr |= UCC_FAST_GUMR_ENT; uccf->enabled_tx = 1; @@ -107,7 +107,7 @@ void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) gumr |= UCC_FAST_GUMR_ENR; uccf->enabled_rx = 1; } - qe_iowrite32be(gumr, &uf_regs->gumr); + iowrite32be(gumr, &uf_regs->gumr); } EXPORT_SYMBOL(ucc_fast_enable); @@ -119,7 +119,7 @@ void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) uf_regs = uccf->uf_regs; /* Disable reception and/or transmission on this UCC. */ - gumr = qe_ioread32be(&uf_regs->gumr); + gumr = ioread32be(&uf_regs->gumr); if (mode & COMM_DIR_TX) { gumr &= ~UCC_FAST_GUMR_ENT; uccf->enabled_tx = 0; @@ -128,7 +128,7 @@ void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) gumr &= ~UCC_FAST_GUMR_ENR; uccf->enabled_rx = 0; } - qe_iowrite32be(gumr, &uf_regs->gumr); + iowrite32be(gumr, &uf_regs->gumr); } EXPORT_SYMBOL(ucc_fast_disable); @@ -262,7 +262,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc gumr |= uf_info->tenc; gumr |= uf_info->tcrc; gumr |= uf_info->mode; - qe_iowrite32be(gumr, &uf_regs->gumr); + iowrite32be(gumr, &uf_regs->gumr); /* Allocate memory for Tx Virtual Fifo */ uccf->ucc_fast_tx_virtual_fifo_base_offset = @@ -287,16 +287,16 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc } /* Set Virtual Fifo registers */ - qe_iowrite16be(uf_info->urfs, &uf_regs->urfs); - qe_iowrite16be(uf_info->urfet, &uf_regs->urfet); - qe_iowrite16be(uf_info->urfset, &uf_regs->urfset); - qe_iowrite16be(uf_info->utfs, &uf_regs->utfs); - qe_iowrite16be(uf_info->utfet, &uf_regs->utfet); - qe_iowrite16be(uf_info->utftt, &uf_regs->utftt); + iowrite16be(uf_info->urfs, &uf_regs->urfs); + iowrite16be(uf_info->urfet, &uf_regs->urfet); + iowrite16be(uf_info->urfset, &uf_regs->urfset); + iowrite16be(uf_info->utfs, &uf_regs->utfs); + iowrite16be(uf_info->utfet, &uf_regs->utfet); + iowrite16be(uf_info->utftt, &uf_regs->utftt); /* utfb, urfb are offsets from MURAM base */ - qe_iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset, + iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset, &uf_regs->utfb); - qe_iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset, + iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset, &uf_regs->urfb); /* Mux clocking */ @@ -365,14 +365,14 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc } /* Set interrupt mask register at UCC level. */ - qe_iowrite32be(uf_info->uccm_mask, &uf_regs->uccm); + iowrite32be(uf_info->uccm_mask, &uf_regs->uccm); /* First, clear anything pending at UCC level, * otherwise, old garbage may come through * as soon as the dam is opened. */ /* Writing '1' clears */ - qe_iowrite32be(0xffffffff, &uf_regs->ucce); + iowrite32be(0xffffffff, &uf_regs->ucce); *uccf_ret = uccf; return 0; diff --git a/drivers/soc/fsl/qe/ucc_slow.c b/drivers/soc/fsl/qe/ucc_slow.c index 7e11be41ab62ca1ef04eb34d413fa3a24b69213e..d5ac1ac0ed3c552118890d9e358a29163a138b2f 100644 --- a/drivers/soc/fsl/qe/ucc_slow.c +++ b/drivers/soc/fsl/qe/ucc_slow.c @@ -78,7 +78,7 @@ void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) us_regs = uccs->us_regs; /* Enable reception and/or transmission on this UCC. */ - gumr_l = qe_ioread32be(&us_regs->gumr_l); + gumr_l = ioread32be(&us_regs->gumr_l); if (mode & COMM_DIR_TX) { gumr_l |= UCC_SLOW_GUMR_L_ENT; uccs->enabled_tx = 1; @@ -87,7 +87,7 @@ void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) gumr_l |= UCC_SLOW_GUMR_L_ENR; uccs->enabled_rx = 1; } - qe_iowrite32be(gumr_l, &us_regs->gumr_l); + iowrite32be(gumr_l, &us_regs->gumr_l); } EXPORT_SYMBOL(ucc_slow_enable); @@ -99,7 +99,7 @@ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) us_regs = uccs->us_regs; /* Disable reception and/or transmission on this UCC. */ - gumr_l = qe_ioread32be(&us_regs->gumr_l); + gumr_l = ioread32be(&us_regs->gumr_l); if (mode & COMM_DIR_TX) { gumr_l &= ~UCC_SLOW_GUMR_L_ENT; uccs->enabled_tx = 0; @@ -108,7 +108,7 @@ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) gumr_l &= ~UCC_SLOW_GUMR_L_ENR; uccs->enabled_rx = 0; } - qe_iowrite32be(gumr_l, &us_regs->gumr_l); + iowrite32be(gumr_l, &us_regs->gumr_l); } EXPORT_SYMBOL(ucc_slow_disable); @@ -194,7 +194,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc return ret; } - qe_iowrite16be(us_info->max_rx_buf_length, &uccs->us_pram->mrblr); + iowrite16be(us_info->max_rx_buf_length, &uccs->us_pram->mrblr); INIT_LIST_HEAD(&uccs->confQ); @@ -222,27 +222,27 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset); for (i = 0; i < us_info->tx_bd_ring_len - 1; i++) { /* clear bd buffer */ - qe_iowrite32be(0, &bd->buf); + iowrite32be(0, &bd->buf); /* set bd status and length */ - qe_iowrite32be(0, (u32 __iomem *)bd); + iowrite32be(0, (u32 __iomem *)bd); bd++; } /* for last BD set Wrap bit */ - qe_iowrite32be(0, &bd->buf); - qe_iowrite32be(T_W, (u32 __iomem *)bd); + iowrite32be(0, &bd->buf); + iowrite32be(T_W, (u32 __iomem *)bd); /* Init Rx bds */ bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) { /* set bd status and length */ - qe_iowrite32be(0, (u32 __iomem *)bd); + iowrite32be(0, (u32 __iomem *)bd); /* clear bd buffer */ - qe_iowrite32be(0, &bd->buf); + iowrite32be(0, &bd->buf); bd++; } /* for last BD set Wrap bit */ - qe_iowrite32be(R_W, (u32 __iomem *)bd); - qe_iowrite32be(0, &bd->buf); + iowrite32be(R_W, (u32 __iomem *)bd); + iowrite32be(0, &bd->buf); /* Set GUMR (For more details see the hardware spec.). */ /* gumr_h */ @@ -263,7 +263,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc gumr |= UCC_SLOW_GUMR_H_TXSY; if (us_info->rtsm) gumr |= UCC_SLOW_GUMR_H_RTSM; - qe_iowrite32be(gumr, &us_regs->gumr_h); + iowrite32be(gumr, &us_regs->gumr_h); /* gumr_l */ gumr = (u32)us_info->tdcr | (u32)us_info->rdcr | (u32)us_info->tenc | @@ -276,18 +276,18 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc gumr |= UCC_SLOW_GUMR_L_TINV; if (us_info->tend) gumr |= UCC_SLOW_GUMR_L_TEND; - qe_iowrite32be(gumr, &us_regs->gumr_l); + iowrite32be(gumr, &us_regs->gumr_l); /* Function code registers */ /* if the data is in cachable memory, the 'global' */ /* in the function code should be set. */ - qe_iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->tbmr); - qe_iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->rbmr); + iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->tbmr); + iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->rbmr); /* rbase, tbase are offsets from MURAM base */ - qe_iowrite16be(uccs->rx_base_offset, &uccs->us_pram->rbase); - qe_iowrite16be(uccs->tx_base_offset, &uccs->us_pram->tbase); + iowrite16be(uccs->rx_base_offset, &uccs->us_pram->rbase); + iowrite16be(uccs->tx_base_offset, &uccs->us_pram->tbase); /* Mux clocking */ /* Grant Support */ @@ -317,14 +317,14 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc } /* Set interrupt mask register at UCC level. */ - qe_iowrite16be(us_info->uccm_mask, &us_regs->uccm); + iowrite16be(us_info->uccm_mask, &us_regs->uccm); /* First, clear anything pending at UCC level, * otherwise, old garbage may come through * as soon as the dam is opened. */ /* Writing '1' clears */ - qe_iowrite16be(0xffff, &us_regs->ucce); + iowrite16be(0xffff, &us_regs->ucce); /* Issue QE Init command */ if (us_info->init_tx && us_info->init_rx) diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c index 4ace28cab314f46e6097ad9eefbe209927c2d908..90d3f4060b0c915b2d629c4fbc3141d9a5aea3e6 100644 --- a/drivers/soc/fsl/rcpm.c +++ b/drivers/soc/fsl/rcpm.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/suspend.h> #include <linux/kernel.h> +#include <linux/acpi.h> #define RCPM_WAKEUP_CELL_MAX_SIZE 7 @@ -78,10 +79,20 @@ static int rcpm_pm_prepare(struct device *dev) "fsl,rcpm-wakeup", value, rcpm->wakeup_cells + 1); - /* Wakeup source should refer to current rcpm device */ - if (ret || (np->phandle != value[0])) + if (ret) continue; + /* + * For DT mode, would handle devices with "fsl,rcpm-wakeup" + * pointing to the current RCPM node. + * + * For ACPI mode, currently we assume there is only one + * RCPM controller existing. + */ + if (is_of_node(dev->fwnode)) + if (np->phandle != value[0]) + continue; + /* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup" * of wakeup source IP contains an integer array: <phandle to @@ -172,10 +183,19 @@ static const struct of_device_id rcpm_of_match[] = { }; MODULE_DEVICE_TABLE(of, rcpm_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id rcpm_acpi_ids[] = { + {"NXP0015",}, + { } +}; +MODULE_DEVICE_TABLE(acpi, rcpm_acpi_ids); +#endif + static struct platform_driver rcpm_driver = { .driver = { .name = "rcpm", .of_match_table = rcpm_of_match, + .acpi_match_table = ACPI_PTR(rcpm_acpi_ids), .pm = &rcpm_pm_ops, }, .probe = rcpm_probe, diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c index 01bfea1cb64a86c2ccaa8871263754c1f4b2f4a3..0738c0f367929d8b142f4f1fc2fd9f1bfa8e1bae 100644 --- a/drivers/soc/imx/soc-imx.c +++ b/drivers/soc/imx/soc-imx.c @@ -13,6 +13,8 @@ #include <soc/imx/cpu.h> #include <soc/imx/revision.h> +#define IIM_UID 0x820 + #define OCOTP_UID_H 0x420 #define OCOTP_UID_L 0x410 @@ -32,6 +34,7 @@ static int __init imx_soc_device_init(void) u64 soc_uid = 0; u32 val; int ret; + int i; if (of_machine_is_compatible("fsl,ls1021a")) return 0; @@ -68,9 +71,11 @@ static int __init imx_soc_device_init(void) soc_id = "i.MX35"; break; case MXC_CPU_MX51: + ocotp_compat = "fsl,imx51-iim"; soc_id = "i.MX51"; break; case MXC_CPU_MX53: + ocotp_compat = "fsl,imx53-iim"; soc_id = "i.MX53"; break; case MXC_CPU_IMX6SL: @@ -153,6 +158,13 @@ static int __init imx_soc_device_init(void) regmap_read(ocotp, OCOTP_ULP_UID_1, &val); soc_uid <<= 16; soc_uid |= val & 0xffff; + } else if (__mxc_cpu_type == MXC_CPU_MX51 || + __mxc_cpu_type == MXC_CPU_MX53) { + for (i=0; i < 8; i++) { + regmap_read(ocotp, IIM_UID + i*4, &val); + soc_uid <<= 8; + soc_uid |= (val & 0xff); + } } else { regmap_read(ocotp, OCOTP_UID_H, &val); soc_uid = val; diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h new file mode 100644 index 0000000000000000000000000000000000000000..2772ef5e3934cc2a532218dd7231ed3efffc479a --- /dev/null +++ b/drivers/soc/mediatek/mt8167-mmsys.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8167_MMSYS_H +#define __SOC_MEDIATEK_MT8167_MMSYS_H + +#define MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x030 +#define MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN 0x038 +#define MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x058 +#define MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0x064 +#define MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x06c + +#define MT8167_DITHER_MOUT_EN_RDMA0 0x1 +#define MT8167_RDMA0_SOUT_DSI0 0x2 +#define MT8167_DSI0_SEL_IN_RDMA0 0x1 + +static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = { + { + DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, + MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0, + }, { + DDP_COMPONENT_DITHER, DDP_COMPONENT_RDMA0, + MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_RDMA0 + }, { + DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, + MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0, + MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_RDMA0 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0, + MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_DSI0 + }, +}; + +#endif /* __SOC_MEDIATEK_MT8167_MMSYS_H */ diff --git a/drivers/soc/mediatek/mt8167-pm-domains.h b/drivers/soc/mediatek/mt8167-pm-domains.h index ad0b8dfa05275a3d13b88156bf7e1e28159cb292..15559ddf26e4ddf837266539fa6af9d8de15c320 100644 --- a/drivers/soc/mediatek/mt8167-pm-domains.h +++ b/drivers/soc/mediatek/mt8167-pm-domains.h @@ -15,6 +15,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { [MT8167_POWER_DOMAIN_MM] = { + .name = "mm", .sta_mask = PWR_STATUS_DISP, .ctl_offs = SPM_DIS_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), @@ -26,6 +27,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT8167_POWER_DOMAIN_VDEC] = { + .name = "vdec", .sta_mask = PWR_STATUS_VDEC, .ctl_offs = SPM_VDE_PWR_CON, .sram_pdn_bits = GENMASK(8, 8), @@ -33,6 +35,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT8167_POWER_DOMAIN_ISP] = { + .name = "isp", .sta_mask = PWR_STATUS_ISP, .ctl_offs = SPM_ISP_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), @@ -40,6 +43,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT8167_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", .sta_mask = MT8167_PWR_STATUS_MFG_ASYNC, .ctl_offs = SPM_MFG_ASYNC_PWR_CON, .sram_pdn_bits = 0, @@ -50,18 +54,21 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { }, }, [MT8167_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", .sta_mask = MT8167_PWR_STATUS_MFG_2D, .ctl_offs = SPM_MFG_2D_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), }, [MT8167_POWER_DOMAIN_MFG] = { + .name = "mfg", .sta_mask = PWR_STATUS_MFG, .ctl_offs = SPM_MFG_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), }, [MT8167_POWER_DOMAIN_CONN] = { + .name = "conn", .sta_mask = PWR_STATUS_CONN, .ctl_offs = SPM_CONN_PWR_CON, .sram_pdn_bits = GENMASK(8, 8), diff --git a/drivers/soc/mediatek/mt8173-pm-domains.h b/drivers/soc/mediatek/mt8173-pm-domains.h index 3e8ee5dabb437290e41679ad2ae1cf69c0d49f1d..654c717e546711e94286e0141b103918ce04d5e0 100644 --- a/drivers/soc/mediatek/mt8173-pm-domains.h +++ b/drivers/soc/mediatek/mt8173-pm-domains.h @@ -12,24 +12,28 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { [MT8173_POWER_DOMAIN_VDEC] = { + .name = "vdec", .sta_mask = PWR_STATUS_VDEC, .ctl_offs = SPM_VDE_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8173_POWER_DOMAIN_VENC] = { + .name = "venc", .sta_mask = PWR_STATUS_VENC, .ctl_offs = SPM_VEN_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), }, [MT8173_POWER_DOMAIN_ISP] = { + .name = "isp", .sta_mask = PWR_STATUS_ISP, .ctl_offs = SPM_ISP_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(13, 12), }, [MT8173_POWER_DOMAIN_MM] = { + .name = "mm", .sta_mask = PWR_STATUS_DISP, .ctl_offs = SPM_DIS_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), @@ -40,18 +44,21 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { }, }, [MT8173_POWER_DOMAIN_VENC_LT] = { + .name = "venc_lt", .sta_mask = PWR_STATUS_VENC_LT, .ctl_offs = SPM_VEN2_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), }, [MT8173_POWER_DOMAIN_AUDIO] = { + .name = "audio", .sta_mask = PWR_STATUS_AUDIO, .ctl_offs = SPM_AUDIO_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), }, [MT8173_POWER_DOMAIN_USB] = { + .name = "usb", .sta_mask = PWR_STATUS_USB, .ctl_offs = SPM_USB_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), @@ -59,18 +66,21 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT8173_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", .sta_mask = PWR_STATUS_MFG_ASYNC, .ctl_offs = SPM_MFG_ASYNC_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = 0, }, [MT8173_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", .sta_mask = PWR_STATUS_MFG_2D, .ctl_offs = SPM_MFG_2D_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(13, 12), }, [MT8173_POWER_DOMAIN_MFG] = { + .name = "mfg", .sta_mask = PWR_STATUS_MFG, .ctl_offs = SPM_MFG_PWR_CON, .sram_pdn_bits = GENMASK(13, 8), diff --git a/drivers/soc/mediatek/mt8183-mmsys.h b/drivers/soc/mediatek/mt8183-mmsys.h new file mode 100644 index 0000000000000000000000000000000000000000..579dfc8dc8fc97256765cb65b57b626b8f508b91 --- /dev/null +++ b/drivers/soc/mediatek/mt8183-mmsys.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8183_MMSYS_H +#define __SOC_MEDIATEK_MT8183_MMSYS_H + +#define MT8183_DISP_OVL0_MOUT_EN 0xf00 +#define MT8183_DISP_OVL0_2L_MOUT_EN 0xf04 +#define MT8183_DISP_OVL1_2L_MOUT_EN 0xf08 +#define MT8183_DISP_DITHER0_MOUT_EN 0xf0c +#define MT8183_DISP_PATH0_SEL_IN 0xf24 +#define MT8183_DISP_DSI0_SEL_IN 0xf2c +#define MT8183_DISP_DPI0_SEL_IN 0xf30 +#define MT8183_DISP_RDMA0_SOUT_SEL_IN 0xf50 +#define MT8183_DISP_RDMA1_SOUT_SEL_IN 0xf54 + +#define MT8183_OVL0_MOUT_EN_OVL0_2L BIT(4) +#define MT8183_OVL0_2L_MOUT_EN_DISP_PATH0 BIT(0) +#define MT8183_OVL1_2L_MOUT_EN_RDMA1 BIT(4) +#define MT8183_DITHER0_MOUT_IN_DSI0 BIT(0) +#define MT8183_DISP_PATH0_SEL_IN_OVL0_2L 0x1 +#define MT8183_DSI0_SEL_IN_RDMA0 0x1 +#define MT8183_DSI0_SEL_IN_RDMA1 0x3 +#define MT8183_DPI0_SEL_IN_RDMA0 0x1 +#define MT8183_DPI0_SEL_IN_RDMA1 0x2 +#define MT8183_RDMA0_SOUT_COLOR0 0x1 +#define MT8183_RDMA1_SOUT_DSI0 0x1 + +static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = { + { + DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0, + MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L + }, { + DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0, + MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0 + }, { + DDP_COMPONENT_OVL_2L1, DDP_COMPONENT_RDMA1, + MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1 + }, { + DDP_COMPONENT_DITHER, DDP_COMPONENT_DSI0, + MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0 + }, { + DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0, + MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, + MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0, + MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0 + } +}; + +#endif /* __SOC_MEDIATEK_MT8183_MMSYS_H */ + diff --git a/drivers/soc/mediatek/mt8183-pm-domains.h b/drivers/soc/mediatek/mt8183-pm-domains.h index aa5230e6c12f89188553acfbf51d726a4fb4dc0f..98a9940d05fbbb8e1334eec0dc2536f1e344a5ee 100644 --- a/drivers/soc/mediatek/mt8183-pm-domains.h +++ b/drivers/soc/mediatek/mt8183-pm-domains.h @@ -12,12 +12,14 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { [MT8183_POWER_DOMAIN_AUDIO] = { + .name = "audio", .sta_mask = PWR_STATUS_AUDIO, .ctl_offs = 0x0314, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), }, [MT8183_POWER_DOMAIN_CONN] = { + .name = "conn", .sta_mask = PWR_STATUS_CONN, .ctl_offs = 0x032c, .sram_pdn_bits = 0, @@ -28,12 +30,14 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", .sta_mask = PWR_STATUS_MFG_ASYNC, .ctl_offs = 0x0334, .sram_pdn_bits = 0, .sram_pdn_ack_bits = 0, }, [MT8183_POWER_DOMAIN_MFG] = { + .name = "mfg", .sta_mask = PWR_STATUS_MFG, .ctl_offs = 0x0338, .sram_pdn_bits = GENMASK(8, 8), @@ -41,18 +45,21 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .caps = MTK_SCPD_DOMAIN_SUPPLY, }, [MT8183_POWER_DOMAIN_MFG_CORE0] = { + .name = "mfg_core0", .sta_mask = BIT(7), .ctl_offs = 0x034c, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8183_POWER_DOMAIN_MFG_CORE1] = { + .name = "mfg_core1", .sta_mask = BIT(20), .ctl_offs = 0x0310, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8183_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", .sta_mask = PWR_STATUS_MFG_2D, .ctl_offs = 0x0348, .sram_pdn_bits = GENMASK(8, 8), @@ -65,6 +72,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_DISP] = { + .name = "disp", .sta_mask = PWR_STATUS_DISP, .ctl_offs = 0x030c, .sram_pdn_bits = GENMASK(8, 8), @@ -83,6 +91,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_CAM] = { + .name = "cam", .sta_mask = BIT(25), .ctl_offs = 0x0344, .sram_pdn_bits = GENMASK(9, 8), @@ -105,6 +114,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_ISP] = { + .name = "isp", .sta_mask = PWR_STATUS_ISP, .ctl_offs = 0x0308, .sram_pdn_bits = GENMASK(9, 8), @@ -127,6 +137,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_VDEC] = { + .name = "vdec", .sta_mask = BIT(31), .ctl_offs = 0x0300, .sram_pdn_bits = GENMASK(8, 8), @@ -139,6 +150,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_VENC] = { + .name = "venc", .sta_mask = PWR_STATUS_VENC, .ctl_offs = 0x0304, .sram_pdn_bits = GENMASK(11, 8), @@ -151,6 +163,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_VPU_TOP] = { + .name = "vpu_top", .sta_mask = BIT(26), .ctl_offs = 0x0324, .sram_pdn_bits = GENMASK(8, 8), @@ -177,6 +190,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { }, }, [MT8183_POWER_DOMAIN_VPU_CORE0] = { + .name = "vpu_core0", .sta_mask = BIT(27), .ctl_offs = 0x33c, .sram_pdn_bits = GENMASK(11, 8), @@ -194,6 +208,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .caps = MTK_SCPD_SRAM_ISO, }, [MT8183_POWER_DOMAIN_VPU_CORE1] = { + .name = "vpu_core1", .sta_mask = BIT(28), .ctl_offs = 0x0340, .sram_pdn_bits = GENMASK(11, 8), diff --git a/drivers/soc/mediatek/mt8192-pm-domains.h b/drivers/soc/mediatek/mt8192-pm-domains.h index 0fdf6dc6231f4fc3b03ab52af5235d9b2c8cce4d..543dda70de01465ef51512f95be5b9cee3938923 100644 --- a/drivers/soc/mediatek/mt8192-pm-domains.h +++ b/drivers/soc/mediatek/mt8192-pm-domains.h @@ -12,6 +12,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { [MT8192_POWER_DOMAIN_AUDIO] = { + .name = "audio", .sta_mask = BIT(21), .ctl_offs = 0x0354, .sram_pdn_bits = GENMASK(8, 8), @@ -24,6 +25,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_CONN] = { + .name = "conn", .sta_mask = PWR_STATUS_CONN, .ctl_offs = 0x0304, .sram_pdn_bits = 0, @@ -45,12 +47,14 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { .caps = MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8192_POWER_DOMAIN_MFG0] = { + .name = "mfg0", .sta_mask = BIT(2), .ctl_offs = 0x0308, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_MFG1] = { + .name = "mfg1", .sta_mask = BIT(3), .ctl_offs = 0x030c, .sram_pdn_bits = GENMASK(8, 8), @@ -75,36 +79,42 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_MFG2] = { + .name = "mfg2", .sta_mask = BIT(4), .ctl_offs = 0x0310, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_MFG3] = { + .name = "mfg3", .sta_mask = BIT(5), .ctl_offs = 0x0314, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_MFG4] = { + .name = "mfg4", .sta_mask = BIT(6), .ctl_offs = 0x0318, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_MFG5] = { + .name = "mfg5", .sta_mask = BIT(7), .ctl_offs = 0x031c, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_MFG6] = { + .name = "mfg6", .sta_mask = BIT(8), .ctl_offs = 0x0320, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_DISP] = { + .name = "disp", .sta_mask = BIT(20), .ctl_offs = 0x0350, .sram_pdn_bits = GENMASK(8, 8), @@ -133,6 +143,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_IPE] = { + .name = "ipe", .sta_mask = BIT(14), .ctl_offs = 0x0338, .sram_pdn_bits = GENMASK(8, 8), @@ -149,6 +160,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_ISP] = { + .name = "isp", .sta_mask = BIT(12), .ctl_offs = 0x0330, .sram_pdn_bits = GENMASK(8, 8), @@ -165,6 +177,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_ISP2] = { + .name = "isp2", .sta_mask = BIT(13), .ctl_offs = 0x0334, .sram_pdn_bits = GENMASK(8, 8), @@ -181,6 +194,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_MDP] = { + .name = "mdp", .sta_mask = BIT(19), .ctl_offs = 0x034c, .sram_pdn_bits = GENMASK(8, 8), @@ -197,6 +211,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_VENC] = { + .name = "venc", .sta_mask = BIT(17), .ctl_offs = 0x0344, .sram_pdn_bits = GENMASK(8, 8), @@ -213,6 +228,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_VDEC] = { + .name = "vdec", .sta_mask = BIT(15), .ctl_offs = 0x033c, .sram_pdn_bits = GENMASK(8, 8), @@ -229,12 +245,14 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_VDEC2] = { + .name = "vdec2", .sta_mask = BIT(16), .ctl_offs = 0x0340, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_CAM] = { + .name = "cam", .sta_mask = BIT(23), .ctl_offs = 0x035c, .sram_pdn_bits = GENMASK(8, 8), @@ -263,18 +281,21 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { }, }, [MT8192_POWER_DOMAIN_CAM_RAWA] = { + .name = "cam_rawa", .sta_mask = BIT(24), .ctl_offs = 0x0360, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_CAM_RAWB] = { + .name = "cam_rawb", .sta_mask = BIT(25), .ctl_offs = 0x0364, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), }, [MT8192_POWER_DOMAIN_CAM_RAWC] = { + .name = "cam_rawc", .sta_mask = BIT(26), .ctl_offs = 0x0368, .sram_pdn_bits = GENMASK(8, 8), diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 18f93979e14a20199035affa529bd960ddb13d70..080660ef11bfa7d4f2afcecf68321faf6fe3015b 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -10,79 +10,20 @@ #include <linux/platform_device.h> #include <linux/soc/mediatek/mtk-mmsys.h> -#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 -#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 -#define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 -#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c -#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 -#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 -#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 -#define DISP_REG_CONFIG_DSIE_SEL_IN 0x0a4 -#define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8 -#define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac -#define DISP_REG_CONFIG_DISP_RDMA2_SOUT 0x0b8 -#define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 -#define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 -#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 - -#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 -#define DISP_REG_CONFIG_OUT_SEL 0x04c -#define DISP_REG_CONFIG_DSI_SEL 0x050 -#define DISP_REG_CONFIG_DPI_SEL 0x064 - -#define OVL0_MOUT_EN_COLOR0 0x1 -#define OD_MOUT_EN_RDMA0 0x1 -#define OD1_MOUT_EN_RDMA1 BIT(16) -#define UFOE_MOUT_EN_DSI0 0x1 -#define COLOR0_SEL_IN_OVL0 0x1 -#define OVL1_MOUT_EN_COLOR1 0x1 -#define GAMMA_MOUT_EN_RDMA1 0x1 -#define RDMA0_SOUT_DPI0 0x2 -#define RDMA0_SOUT_DPI1 0x3 -#define RDMA0_SOUT_DSI1 0x1 -#define RDMA0_SOUT_DSI2 0x4 -#define RDMA0_SOUT_DSI3 0x5 -#define RDMA1_SOUT_DPI0 0x2 -#define RDMA1_SOUT_DPI1 0x3 -#define RDMA1_SOUT_DSI1 0x1 -#define RDMA1_SOUT_DSI2 0x4 -#define RDMA1_SOUT_DSI3 0x5 -#define RDMA2_SOUT_DPI0 0x2 -#define RDMA2_SOUT_DPI1 0x3 -#define RDMA2_SOUT_DSI1 0x1 -#define RDMA2_SOUT_DSI2 0x4 -#define RDMA2_SOUT_DSI3 0x5 -#define DPI0_SEL_IN_RDMA1 0x1 -#define DPI0_SEL_IN_RDMA2 0x3 -#define DPI1_SEL_IN_RDMA1 (0x1 << 8) -#define DPI1_SEL_IN_RDMA2 (0x3 << 8) -#define DSI0_SEL_IN_RDMA1 0x1 -#define DSI0_SEL_IN_RDMA2 0x4 -#define DSI1_SEL_IN_RDMA1 0x1 -#define DSI1_SEL_IN_RDMA2 0x4 -#define DSI2_SEL_IN_RDMA1 (0x1 << 16) -#define DSI2_SEL_IN_RDMA2 (0x4 << 16) -#define DSI3_SEL_IN_RDMA1 (0x1 << 16) -#define DSI3_SEL_IN_RDMA2 (0x4 << 16) -#define COLOR1_SEL_IN_OVL1 0x1 - -#define OVL_MOUT_EN_RDMA 0x1 -#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8 -#define BLS_TO_DPI_RDMA1_TO_DSI 0x2 -#define DSI_SEL_IN_BLS 0x0 -#define DPI_SEL_IN_BLS 0x0 -#define DSI_SEL_IN_RDMA 0x1 - -struct mtk_mmsys_driver_data { - const char *clk_driver; -}; +#include "mtk-mmsys.h" +#include "mt8167-mmsys.h" +#include "mt8183-mmsys.h" static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { .clk_driver = "clk-mt2701-mm", + .routes = mmsys_default_routing_table, + .num_routes = ARRAY_SIZE(mmsys_default_routing_table), }; static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = { .clk_driver = "clk-mt2712-mm", + .routes = mmsys_default_routing_table, + .num_routes = ARRAY_SIZE(mmsys_default_routing_table), }; static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = { @@ -93,188 +34,43 @@ static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = { .clk_driver = "clk-mt6797-mm", }; +static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = { + .clk_driver = "clk-mt8167-mm", + .routes = mt8167_mmsys_routing_table, + .num_routes = ARRAY_SIZE(mt8167_mmsys_routing_table), +}; + static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { .clk_driver = "clk-mt8173-mm", + .routes = mmsys_default_routing_table, + .num_routes = ARRAY_SIZE(mmsys_default_routing_table), }; static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { .clk_driver = "clk-mt8183-mm", + .routes = mmsys_mt8183_routing_table, + .num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table), }; -static unsigned int mtk_mmsys_ddp_mout_en(enum mtk_ddp_comp_id cur, - enum mtk_ddp_comp_id next, - unsigned int *addr) -{ - unsigned int value; - - if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { - *addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN; - value = OVL0_MOUT_EN_COLOR0; - } else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) { - *addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN; - value = OVL_MOUT_EN_RDMA; - } else if (cur == DDP_COMPONENT_OD0 && next == DDP_COMPONENT_RDMA0) { - *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; - value = OD_MOUT_EN_RDMA0; - } else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) { - *addr = DISP_REG_CONFIG_DISP_UFOE_MOUT_EN; - value = UFOE_MOUT_EN_DSI0; - } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { - *addr = DISP_REG_CONFIG_DISP_OVL1_MOUT_EN; - value = OVL1_MOUT_EN_COLOR1; - } else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) { - *addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN; - value = GAMMA_MOUT_EN_RDMA1; - } else if (cur == DDP_COMPONENT_OD1 && next == DDP_COMPONENT_RDMA1) { - *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; - value = OD1_MOUT_EN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DPI0) { - *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; - value = RDMA0_SOUT_DPI0; - } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DPI1) { - *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; - value = RDMA0_SOUT_DPI1; - } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI1) { - *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; - value = RDMA0_SOUT_DSI1; - } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI2) { - *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; - value = RDMA0_SOUT_DSI2; - } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI3) { - *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; - value = RDMA0_SOUT_DSI3; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { - *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; - value = RDMA1_SOUT_DSI1; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { - *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; - value = RDMA1_SOUT_DSI2; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { - *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; - value = RDMA1_SOUT_DSI3; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { - *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; - value = RDMA1_SOUT_DPI0; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { - *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; - value = RDMA1_SOUT_DPI1; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { - *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; - value = RDMA2_SOUT_DPI0; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { - *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; - value = RDMA2_SOUT_DPI1; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { - *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; - value = RDMA2_SOUT_DSI1; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { - *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; - value = RDMA2_SOUT_DSI2; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI3) { - *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; - value = RDMA2_SOUT_DSI3; - } else { - value = 0; - } - - return value; -} - -static unsigned int mtk_mmsys_ddp_sel_in(enum mtk_ddp_comp_id cur, - enum mtk_ddp_comp_id next, - unsigned int *addr) -{ - unsigned int value; - - if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { - *addr = DISP_REG_CONFIG_DISP_COLOR0_SEL_IN; - value = COLOR0_SEL_IN_OVL0; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { - *addr = DISP_REG_CONFIG_DPI_SEL_IN; - value = DPI0_SEL_IN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { - *addr = DISP_REG_CONFIG_DPI_SEL_IN; - value = DPI1_SEL_IN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI0) { - *addr = DISP_REG_CONFIG_DSIE_SEL_IN; - value = DSI0_SEL_IN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { - *addr = DISP_REG_CONFIG_DSIO_SEL_IN; - value = DSI1_SEL_IN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { - *addr = DISP_REG_CONFIG_DSIE_SEL_IN; - value = DSI2_SEL_IN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { - *addr = DISP_REG_CONFIG_DSIO_SEL_IN; - value = DSI3_SEL_IN_RDMA1; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { - *addr = DISP_REG_CONFIG_DPI_SEL_IN; - value = DPI0_SEL_IN_RDMA2; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { - *addr = DISP_REG_CONFIG_DPI_SEL_IN; - value = DPI1_SEL_IN_RDMA2; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI0) { - *addr = DISP_REG_CONFIG_DSIE_SEL_IN; - value = DSI0_SEL_IN_RDMA2; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { - *addr = DISP_REG_CONFIG_DSIO_SEL_IN; - value = DSI1_SEL_IN_RDMA2; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { - *addr = DISP_REG_CONFIG_DSIE_SEL_IN; - value = DSI2_SEL_IN_RDMA2; - } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI3) { - *addr = DISP_REG_CONFIG_DSIE_SEL_IN; - value = DSI3_SEL_IN_RDMA2; - } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { - *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; - value = COLOR1_SEL_IN_OVL1; - } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { - *addr = DISP_REG_CONFIG_DSI_SEL; - value = DSI_SEL_IN_BLS; - } else { - value = 0; - } - - return value; -} - -static void mtk_mmsys_ddp_sout_sel(void __iomem *config_regs, - enum mtk_ddp_comp_id cur, - enum mtk_ddp_comp_id next) -{ - if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { - writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1, - config_regs + DISP_REG_CONFIG_OUT_SEL); - } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DPI0) { - writel_relaxed(BLS_TO_DPI_RDMA1_TO_DSI, - config_regs + DISP_REG_CONFIG_OUT_SEL); - writel_relaxed(DSI_SEL_IN_RDMA, - config_regs + DISP_REG_CONFIG_DSI_SEL); - writel_relaxed(DPI_SEL_IN_BLS, - config_regs + DISP_REG_CONFIG_DPI_SEL); - } -} +struct mtk_mmsys { + void __iomem *regs; + const struct mtk_mmsys_driver_data *data; +}; void mtk_mmsys_ddp_connect(struct device *dev, enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next) { - void __iomem *config_regs = dev_get_drvdata(dev); - unsigned int addr, value, reg; - - value = mtk_mmsys_ddp_mout_en(cur, next, &addr); - if (value) { - reg = readl_relaxed(config_regs + addr) | value; - writel_relaxed(reg, config_regs + addr); - } - - mtk_mmsys_ddp_sout_sel(config_regs, cur, next); - - value = mtk_mmsys_ddp_sel_in(cur, next, &addr); - if (value) { - reg = readl_relaxed(config_regs + addr) | value; - writel_relaxed(reg, config_regs + addr); - } + struct mtk_mmsys *mmsys = dev_get_drvdata(dev); + const struct mtk_mmsys_routes *routes = mmsys->data->routes; + u32 reg; + int i; + + for (i = 0; i < mmsys->data->num_routes; i++) + if (cur == routes[i].from_comp && next == routes[i].to_comp) { + reg = readl_relaxed(mmsys->regs + routes[i].addr) | routes[i].val; + writel_relaxed(reg, mmsys->regs + routes[i].addr); + } } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect); @@ -282,44 +78,42 @@ void mtk_mmsys_ddp_disconnect(struct device *dev, enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next) { - void __iomem *config_regs = dev_get_drvdata(dev); - unsigned int addr, value, reg; - - value = mtk_mmsys_ddp_mout_en(cur, next, &addr); - if (value) { - reg = readl_relaxed(config_regs + addr) & ~value; - writel_relaxed(reg, config_regs + addr); - } - - value = mtk_mmsys_ddp_sel_in(cur, next, &addr); - if (value) { - reg = readl_relaxed(config_regs + addr) & ~value; - writel_relaxed(reg, config_regs + addr); - } + struct mtk_mmsys *mmsys = dev_get_drvdata(dev); + const struct mtk_mmsys_routes *routes = mmsys->data->routes; + u32 reg; + int i; + + for (i = 0; i < mmsys->data->num_routes; i++) + if (cur == routes[i].from_comp && next == routes[i].to_comp) { + reg = readl_relaxed(mmsys->regs + routes[i].addr) & ~routes[i].val; + writel_relaxed(reg, mmsys->regs + routes[i].addr); + } } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect); static int mtk_mmsys_probe(struct platform_device *pdev) { - const struct mtk_mmsys_driver_data *data; struct device *dev = &pdev->dev; struct platform_device *clks; struct platform_device *drm; - void __iomem *config_regs; + struct mtk_mmsys *mmsys; int ret; - config_regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(config_regs)) { - ret = PTR_ERR(config_regs); + mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL); + if (!mmsys) + return -ENOMEM; + + mmsys->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mmsys->regs)) { + ret = PTR_ERR(mmsys->regs); dev_err(dev, "Failed to ioremap mmsys registers: %d\n", ret); return ret; } - platform_set_drvdata(pdev, config_regs); - - data = of_device_get_match_data(&pdev->dev); + mmsys->data = of_device_get_match_data(&pdev->dev); + platform_set_drvdata(pdev, mmsys); - clks = platform_device_register_data(&pdev->dev, data->clk_driver, + clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver, PLATFORM_DEVID_AUTO, NULL, 0); if (IS_ERR(clks)) return PTR_ERR(clks); @@ -351,6 +145,10 @@ static const struct of_device_id of_match_mtk_mmsys[] = { .compatible = "mediatek,mt6797-mmsys", .data = &mt6797_mmsys_driver_data, }, + { + .compatible = "mediatek,mt8167-mmsys", + .data = &mt8167_mmsys_driver_data, + }, { .compatible = "mediatek,mt8173-mmsys", .data = &mt8173_mmsys_driver_data, diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h new file mode 100644 index 0000000000000000000000000000000000000000..a760a34e6eca866f3c520a0d59c675a90ccda736 --- /dev/null +++ b/drivers/soc/mediatek/mtk-mmsys.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MTK_MMSYS_H +#define __SOC_MEDIATEK_MTK_MMSYS_H + +#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 +#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 +#define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 +#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c +#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 +#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 +#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 +#define DISP_REG_CONFIG_DSIE_SEL_IN 0x0a4 +#define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8 +#define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac +#define DISP_REG_CONFIG_DISP_RDMA2_SOUT 0x0b8 +#define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 +#define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 +#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 + +#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 +#define DISP_REG_CONFIG_OUT_SEL 0x04c +#define DISP_REG_CONFIG_DSI_SEL 0x050 +#define DISP_REG_CONFIG_DPI_SEL 0x064 + +#define OVL0_MOUT_EN_COLOR0 0x1 +#define OD_MOUT_EN_RDMA0 0x1 +#define OD1_MOUT_EN_RDMA1 BIT(16) +#define UFOE_MOUT_EN_DSI0 0x1 +#define COLOR0_SEL_IN_OVL0 0x1 +#define OVL1_MOUT_EN_COLOR1 0x1 +#define GAMMA_MOUT_EN_RDMA1 0x1 +#define RDMA0_SOUT_DPI0 0x2 +#define RDMA0_SOUT_DPI1 0x3 +#define RDMA0_SOUT_DSI1 0x1 +#define RDMA0_SOUT_DSI2 0x4 +#define RDMA0_SOUT_DSI3 0x5 +#define RDMA1_SOUT_DPI0 0x2 +#define RDMA1_SOUT_DPI1 0x3 +#define RDMA1_SOUT_DSI1 0x1 +#define RDMA1_SOUT_DSI2 0x4 +#define RDMA1_SOUT_DSI3 0x5 +#define RDMA2_SOUT_DPI0 0x2 +#define RDMA2_SOUT_DPI1 0x3 +#define RDMA2_SOUT_DSI1 0x1 +#define RDMA2_SOUT_DSI2 0x4 +#define RDMA2_SOUT_DSI3 0x5 +#define DPI0_SEL_IN_RDMA1 0x1 +#define DPI0_SEL_IN_RDMA2 0x3 +#define DPI1_SEL_IN_RDMA1 (0x1 << 8) +#define DPI1_SEL_IN_RDMA2 (0x3 << 8) +#define DSI0_SEL_IN_RDMA1 0x1 +#define DSI0_SEL_IN_RDMA2 0x4 +#define DSI1_SEL_IN_RDMA1 0x1 +#define DSI1_SEL_IN_RDMA2 0x4 +#define DSI2_SEL_IN_RDMA1 (0x1 << 16) +#define DSI2_SEL_IN_RDMA2 (0x4 << 16) +#define DSI3_SEL_IN_RDMA1 (0x1 << 16) +#define DSI3_SEL_IN_RDMA2 (0x4 << 16) +#define COLOR1_SEL_IN_OVL1 0x1 + +#define OVL_MOUT_EN_RDMA 0x1 +#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8 +#define BLS_TO_DPI_RDMA1_TO_DSI 0x2 +#define DSI_SEL_IN_BLS 0x0 +#define DPI_SEL_IN_BLS 0x0 +#define DSI_SEL_IN_RDMA 0x1 + +struct mtk_mmsys_routes { + u32 from_comp; + u32 to_comp; + u32 addr; + u32 val; +}; + +struct mtk_mmsys_driver_data { + const char *clk_driver; + const struct mtk_mmsys_routes *routes; + const unsigned int num_routes; +}; + +/* + * Routes in mt8173, mt2701, mt2712 are different. That means + * in the same register address, it controls different input/output + * selection for each SoC. But, right now, they use the same table as + * default routes meet their requirements. But we don't have the complete + * route information for these three SoC, so just keep them in the same + * table. After we've more information, we could separate mt2701, mt2712 + * to an independent table. + */ +static const struct mtk_mmsys_routes mmsys_default_routing_table[] = { + { + DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0, + DISP_REG_CONFIG_OUT_SEL, BLS_TO_DSI_RDMA1_TO_DPI1 + }, { + DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0, + DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_BLS + }, { + DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_OUT_SEL, BLS_TO_DPI_RDMA1_TO_DSI + }, { + DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_RDMA + }, { + DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DPI_SEL, DPI_SEL_IN_BLS + }, { + DDP_COMPONENT_GAMMA, DDP_COMPONENT_RDMA1, + DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, GAMMA_MOUT_EN_RDMA1 + }, { + DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0, + DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD_MOUT_EN_RDMA0 + }, { + DDP_COMPONENT_OD1, DDP_COMPONENT_RDMA1, + DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD1_MOUT_EN_RDMA1 + }, { + DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, + DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0 + }, { + DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, + DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0 + }, { + DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0, + DISP_REG_CONFIG_DISP_OVL_MOUT_EN, OVL_MOUT_EN_RDMA + }, { + DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1, + DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, OVL1_MOUT_EN_COLOR1 + }, { + DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1, + DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_DPI0 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI1, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_DPI1 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI1, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_DSI1 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI2, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_DSI2 + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI3, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_DSI3 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_DPI0 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_DPI1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1, + DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI0, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_DSI1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_DSI2 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_DSI3 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_RDMA1 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_DPI0 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0, + DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_RDMA2 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_DPI1 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1, + DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_RDMA2 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI0, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_RDMA2 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_DSI1 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_RDMA2 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_DSI2 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_RDMA2 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_DSI3 + }, { + DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_RDMA2 + } +}; + +#endif /* __SOC_MEDIATEK_MTK_MMSYS_H */ diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index f531b119da7a9840406cd7508968b7d754bd60b4..2e4bcc300576f5c4e55f9cb14d24a2b71e272c6c 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -14,6 +14,8 @@ #define MT2701_MUTEX0_MOD0 0x2c #define MT2701_MUTEX0_SOF0 0x30 +#define MT8183_MUTEX0_MOD0 0x30 +#define MT8183_MUTEX0_SOF0 0x2c #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) #define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) @@ -37,6 +39,18 @@ #define MT8167_MUTEX_MOD_DISP_DITHER 15 #define MT8167_MUTEX_MOD_DISP_UFOE 16 +#define MT8183_MUTEX_MOD_DISP_RDMA0 0 +#define MT8183_MUTEX_MOD_DISP_RDMA1 1 +#define MT8183_MUTEX_MOD_DISP_OVL0 9 +#define MT8183_MUTEX_MOD_DISP_OVL0_2L 10 +#define MT8183_MUTEX_MOD_DISP_OVL1_2L 11 +#define MT8183_MUTEX_MOD_DISP_WDMA0 12 +#define MT8183_MUTEX_MOD_DISP_COLOR0 13 +#define MT8183_MUTEX_MOD_DISP_CCORR0 14 +#define MT8183_MUTEX_MOD_DISP_AAL0 15 +#define MT8183_MUTEX_MOD_DISP_GAMMA0 16 +#define MT8183_MUTEX_MOD_DISP_DITHER0 17 + #define MT8173_MUTEX_MOD_DISP_OVL0 11 #define MT8173_MUTEX_MOD_DISP_OVL1 12 #define MT8173_MUTEX_MOD_DISP_RDMA0 13 @@ -87,6 +101,11 @@ #define MT2712_MUTEX_SOF_DSI3 6 #define MT8167_MUTEX_SOF_DPI0 2 #define MT8167_MUTEX_SOF_DPI1 3 +#define MT8183_MUTEX_SOF_DSI0 1 +#define MT8183_MUTEX_SOF_DPI0 2 + +#define MT8183_MUTEX_EOF_DSI0 (MT8183_MUTEX_SOF_DSI0 << 6) +#define MT8183_MUTEX_EOF_DPI0 (MT8183_MUTEX_SOF_DPI0 << 6) struct mtk_mutex { int id; @@ -181,6 +200,20 @@ static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, }; +static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT8183_MUTEX_MOD_DISP_AAL0, + [DDP_COMPONENT_CCORR] = MT8183_MUTEX_MOD_DISP_CCORR0, + [DDP_COMPONENT_COLOR0] = MT8183_MUTEX_MOD_DISP_COLOR0, + [DDP_COMPONENT_DITHER] = MT8183_MUTEX_MOD_DISP_DITHER0, + [DDP_COMPONENT_GAMMA] = MT8183_MUTEX_MOD_DISP_GAMMA0, + [DDP_COMPONENT_OVL0] = MT8183_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL_2L0] = MT8183_MUTEX_MOD_DISP_OVL0_2L, + [DDP_COMPONENT_OVL_2L1] = MT8183_MUTEX_MOD_DISP_OVL1_2L, + [DDP_COMPONENT_RDMA0] = MT8183_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT8183_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0, +}; + static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, @@ -198,6 +231,13 @@ static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = { [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1, }; +/* Add EOF setting so overlay hardware can receive frame done irq */ +static const unsigned int mt8183_mutex_sof[MUTEX_SOF_DSI3 + 1] = { + [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, + [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0 | MT8183_MUTEX_EOF_DSI0, + [MUTEX_SOF_DPI0] = MT8183_MUTEX_SOF_DPI0 | MT8183_MUTEX_EOF_DPI0, +}; + static const struct mtk_mutex_data mt2701_mutex_driver_data = { .mutex_mod = mt2701_mutex_mod, .mutex_sof = mt2712_mutex_sof, @@ -227,6 +267,14 @@ static const struct mtk_mutex_data mt8173_mutex_driver_data = { .mutex_sof_reg = MT2701_MUTEX0_SOF0, }; +static const struct mtk_mutex_data mt8183_mutex_driver_data = { + .mutex_mod = mt8183_mutex_mod, + .mutex_sof = mt8183_mutex_sof, + .mutex_mod_reg = MT8183_MUTEX0_MOD0, + .mutex_sof_reg = MT8183_MUTEX0_SOF0, + .no_clk = true, +}; + struct mtk_mutex *mtk_mutex_get(struct device *dev) { struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev); @@ -457,11 +505,13 @@ static const struct of_device_id mutex_driver_dt_match[] = { .data = &mt8167_mutex_driver_data}, { .compatible = "mediatek,mt8173-disp-mutex", .data = &mt8173_mutex_driver_data}, + { .compatible = "mediatek,mt8183-disp-mutex", + .data = &mt8183_mutex_driver_data}, {}, }; MODULE_DEVICE_TABLE(of, mutex_driver_dt_match); -struct platform_driver mtk_mutex_driver = { +static struct platform_driver mtk_mutex_driver = { .probe = mtk_mutex_probe, .remove = mtk_mutex_remove, .driver = { diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index b7f697666bdd78df120f03ff1b293c3f5125971b..0af00efa0ef830c3b617bd6ece9e97efc91db3e3 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -438,7 +438,11 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no goto err_unprepare_subsys_clocks; } - pd->genpd.name = node->name; + if (!pd->data->name) + pd->genpd.name = node->name; + else + pd->genpd.name = pd->data->name; + pd->genpd.power_off = scpsys_power_off; pd->genpd.power_on = scpsys_power_on; @@ -487,8 +491,9 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren child_pd = scpsys_add_one_domain(scpsys, child); if (IS_ERR(child_pd)) { - dev_err_probe(scpsys->dev, PTR_ERR(child_pd), - "%pOF: failed to get child domain id\n", child); + ret = PTR_ERR(child_pd); + dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n", + child); goto err_put_node; } diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index 141dc76054e69b2bd1b31869f2973752c8588261..21a4e113bbecb3795ddd0e434a829c31d22ba353 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -76,6 +76,7 @@ struct scpsys_bus_prot_data { /** * struct scpsys_domain_data - scp domain data for power on/off flow + * @name: The name of the power domain. * @sta_mask: The mask for power on/off status bit. * @ctl_offs: The offset for main power control register. * @sram_pdn_bits: The mask for sram power control bits. @@ -85,6 +86,7 @@ struct scpsys_bus_prot_data { * @bp_smi: bus protection for smi subsystem */ struct scpsys_domain_data { + const char *name; u32 sta_mask; int ctl_offs; u32 sram_pdn_bits; diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 5d34e8b9c98859bfe04c8558f7d8721dc2421cff..e4de75f35c33ba664831554e795d80893944ca29 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -25,10 +25,12 @@ /* macro for wrapper status */ #define PWRAP_GET_WACS_RDATA(x) (((x) >> 0) & 0x0000ffff) +#define PWRAP_GET_WACS_ARB_FSM(x) (((x) >> 1) & 0x00000007) #define PWRAP_GET_WACS_FSM(x) (((x) >> 16) & 0x00000007) #define PWRAP_GET_WACS_REQ(x) (((x) >> 19) & 0x00000001) -#define PWRAP_STATE_SYNC_IDLE0 (1 << 20) -#define PWRAP_STATE_INIT_DONE0 (1 << 21) +#define PWRAP_STATE_SYNC_IDLE0 BIT(20) +#define PWRAP_STATE_INIT_DONE0 BIT(21) +#define PWRAP_STATE_INIT_DONE1 BIT(15) /* macro for WACS FSM */ #define PWRAP_WACS_FSM_IDLE 0x00 @@ -74,6 +76,7 @@ #define PWRAP_CAP_DCM BIT(2) #define PWRAP_CAP_INT1_EN BIT(3) #define PWRAP_CAP_WDT_SRC1 BIT(4) +#define PWRAP_CAP_ARB BIT(5) /* defines for slave device wrapper registers */ enum dew_regs { @@ -340,6 +343,8 @@ enum pwrap_regs { PWRAP_DCM_DBC_PRD, PWRAP_EINT_STA0_ADR, PWRAP_EINT_STA1_ADR, + PWRAP_SWINF_2_WDATA_31_0, + PWRAP_SWINF_2_RDATA_31_0, /* MT2701 only regs */ PWRAP_ADC_CMD_ADDR, @@ -627,6 +632,17 @@ static int mt6797_regs[] = { [PWRAP_DCM_DBC_PRD] = 0x1D4, }; +static int mt6873_regs[] = { + [PWRAP_INIT_DONE2] = 0x0, + [PWRAP_TIMER_EN] = 0x3E0, + [PWRAP_INT_EN] = 0x448, + [PWRAP_WACS2_CMD] = 0xC80, + [PWRAP_SWINF_2_WDATA_31_0] = 0xC84, + [PWRAP_SWINF_2_RDATA_31_0] = 0xC94, + [PWRAP_WACS2_VLDCLR] = 0xCA4, + [PWRAP_WACS2_RDATA] = 0xCA8, +}; + static int mt7622_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, @@ -1045,6 +1061,7 @@ enum pwrap_type { PWRAP_MT6765, PWRAP_MT6779, PWRAP_MT6797, + PWRAP_MT6873, PWRAP_MT7622, PWRAP_MT8135, PWRAP_MT8173, @@ -1106,18 +1123,25 @@ static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg) writel(val, wrp->base + wrp->master->regs[reg]); } -static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp) +static u32 pwrap_get_fsm_state(struct pmic_wrapper *wrp) { - u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + u32 val; - return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_IDLE; + val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) + return PWRAP_GET_WACS_ARB_FSM(val); + else + return PWRAP_GET_WACS_FSM(val); } -static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp) +static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp) { - u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + return pwrap_get_fsm_state(wrp) == PWRAP_WACS_FSM_IDLE; +} - return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR; +static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp) +{ + return pwrap_get_fsm_state(wrp) == PWRAP_WACS_FSM_WFVLDCLR; } /* @@ -1165,6 +1189,7 @@ static int pwrap_wait_for_state(struct pmic_wrapper *wrp, static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata) { int ret; + u32 val; ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle); if (ret) { @@ -1172,13 +1197,21 @@ static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata) return ret; } - pwrap_writel(wrp, (adr >> 1) << 16, PWRAP_WACS2_CMD); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) + val = adr; + else + val = (adr >> 1) << 16; + pwrap_writel(wrp, val, PWRAP_WACS2_CMD); ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr); if (ret) return ret; - *rdata = PWRAP_GET_WACS_RDATA(pwrap_readl(wrp, PWRAP_WACS2_RDATA)); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) + val = pwrap_readl(wrp, PWRAP_SWINF_2_RDATA_31_0); + else + val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + *rdata = PWRAP_GET_WACS_RDATA(val); pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR); @@ -1228,8 +1261,13 @@ static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata) return ret; } - pwrap_writel(wrp, (1 << 31) | ((adr >> 1) << 16) | wdata, - PWRAP_WACS2_CMD); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) { + pwrap_writel(wrp, wdata, PWRAP_SWINF_2_WDATA_31_0); + pwrap_writel(wrp, BIT(29) | adr, PWRAP_WACS2_CMD); + } else { + pwrap_writel(wrp, BIT(31) | ((adr >> 1) << 16) | wdata, + PWRAP_WACS2_CMD); + } return 0; } @@ -1485,6 +1523,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) case PWRAP_MT7622: pwrap_writel(wrp, 0, PWRAP_CIPHER_EN); break; + case PWRAP_MT6873: case PWRAP_MT8183: break; } @@ -1921,6 +1960,19 @@ static const struct pmic_wrapper_type pwrap_mt6797 = { .init_soc_specific = NULL, }; +static const struct pmic_wrapper_type pwrap_mt6873 = { + .regs = mt6873_regs, + .type = PWRAP_MT6873, + .arb_en_all = 0x777f, + .int_en_all = BIT(4) | BIT(5), + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_ARB, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + static const struct pmic_wrapper_type pwrap_mt7622 = { .regs = mt7622_regs, .type = PWRAP_MT7622, @@ -1998,6 +2050,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { }, { .compatible = "mediatek,mt6797-pwrap", .data = &pwrap_mt6797, + }, { + .compatible = "mediatek,mt6873-pwrap", + .data = &pwrap_mt6873, }, { .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622, @@ -2022,6 +2077,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); static int pwrap_probe(struct platform_device *pdev) { int ret, irq; + u32 mask_done; struct pmic_wrapper *wrp; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_slave_id = NULL; @@ -2116,14 +2172,21 @@ static int pwrap_probe(struct platform_device *pdev) } } - if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_INIT_DONE0)) { + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) + mask_done = PWRAP_STATE_INIT_DONE1; + else + mask_done = PWRAP_STATE_INIT_DONE0; + + if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & mask_done)) { dev_dbg(wrp->dev, "initialization isn't finished\n"); ret = -ENODEV; goto err_out2; } /* Initialize watchdog, may not be done by the bootloader */ - pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT); + if (!HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) + pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT); + /* * Since STAUPD was not used on mt8173 platform, * so STAUPD of WDT_SRC which should be turned off @@ -2132,7 +2195,11 @@ static int pwrap_probe(struct platform_device *pdev) if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC1)) pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN_1); - pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) + pwrap_writel(wrp, 0x3, PWRAP_TIMER_EN); + else + pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); + pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); /* * We add INT1 interrupt to handle starvation and request exception diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 8403a77b59fe9300a970a348ee34c9eeb3ac4361..15a36dcab990e880fe03400e4df91daa2a5a8d19 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -109,6 +109,18 @@ static const struct llcc_slice_config sc7180_data[] = { { LLCC_GPU, 12, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 }, }; +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, 1, 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}, +}; + 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 }, @@ -179,6 +191,12 @@ static const struct qcom_llcc_config sc7180_cfg = { .need_llcc_cfg = true, }; +static const struct qcom_llcc_config sc7280_cfg = { + .sct_data = sc7280_data, + .size = ARRAY_SIZE(sc7280_data), + .need_llcc_cfg = true, +}; + static const struct qcom_llcc_config sdm845_cfg = { .sct_data = sdm845_data, .size = ARRAY_SIZE(sdm845_data), @@ -606,6 +624,7 @@ err: static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg }, + { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg }, { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg }, { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 24cd193dec55053ef3cf30e5136690dd0500bfa7..eba7f76f9d61af329d45381ae7f624c2f5bbd878 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -230,6 +230,14 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, break; } + if (phdr->p_filesz > phdr->p_memsz) { + dev_err(dev, + "refusing to load segment %d with p_filesz > p_memsz\n", + i); + ret = -EINVAL; + break; + } + ptr = mem_region + offset; if (phdr->p_filesz && phdr->p_offset < fw->size) { @@ -253,6 +261,15 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, break; } + if (seg_fw->size != phdr->p_filesz) { + dev_err(dev, + "failed to load segment %d from truncated file %s\n", + i, fw_name); + release_firmware(seg_fw); + ret = -EINVAL; + break; + } + release_firmware(seg_fw); } diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c index 209dcdca923f90c732430708a9fed1037511a0cd..915d5bc3d46e67d188ebd9d51fdb6541c1229f25 100644 --- a/drivers/soc/qcom/pdr_interface.c +++ b/drivers/soc/qcom/pdr_interface.c @@ -153,7 +153,7 @@ static int pdr_register_listener(struct pdr_handle *pdr, if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { pr_err("PDR: %s register listener failed: 0x%x\n", pds->service_path, resp.resp.error); - return ret; + return -EREMOTEIO; } pds->state = resp.curr_state; diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 53acb9423bd6e544aae1ffec587f4fdbdcb8cb06..934fcc4d2b057a7939146fde10a55c8097af9cbd 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -597,6 +597,7 @@ static int qmp_remove(struct platform_device *pdev) static const struct of_device_id qmp_dt_match[] = { { .compatible = "qcom,sc7180-aoss-qmp", }, + { .compatible = "qcom,sc7280-aoss-qmp", }, { .compatible = "qcom,sdm845-aoss-qmp", }, { .compatible = "qcom,sm8150-aoss-qmp", }, { .compatible = "qcom,sm8250-aoss-qmp", }, diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index 3aaab71d1b2c1e52dbe66eb05b15c72332f91911..328cc82371919ff97d4bbe785dc4a988dbd7f48c 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -451,11 +451,11 @@ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src, /** * qmi_decode_struct_elem() - Decodes elements of struct data type - * @ei_array: Struct info array descibing the struct element. + * @ei_array: Struct info array describing the struct element. * @buf_dst: Buffer to store the decoded element. * @buf_src: Buffer containing the elements in QMI wire format. * @elem_len: Number of elements to be decoded. - * @tlv_len: Total size of the encoded inforation corresponding to + * @tlv_len: Total size of the encoded information corresponding to * this struct element. * @dec_level: Depth of the nested structure from the main structure. * @@ -499,10 +499,10 @@ static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array, /** * qmi_decode_string_elem() - Decodes elements of string data type - * @ei_array: Struct info array descibing the string element. + * @ei_array: Struct info array describing the string element. * @buf_dst: Buffer to store the decoded element. * @buf_src: Buffer containing the elements in QMI wire format. - * @tlv_len: Total size of the encoded inforation corresponding to + * @tlv_len: Total size of the encoded information corresponding to * this string element. * @dec_level: Depth of the string element from the main structure. * diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index a84ab0d6a9d4fc124026428695d112a27ab3f6ba..e749a2b285d8d92d9d6833638a06229ada749a88 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -194,22 +194,6 @@ static void write_tcs_reg_sync(const struct rsc_drv *drv, int reg, int tcs_id, data, tcs_id, reg); } -/** - * tcs_is_free() - Return if a TCS is totally free. - * @drv: The RSC controller. - * @tcs_id: The global ID of this TCS. - * - * Returns true if nobody has claimed this TCS (by setting tcs_in_use). - * - * Context: Must be called with the drv->lock held. - * - * Return: true if the given TCS is free. - */ -static bool tcs_is_free(struct rsc_drv *drv, int tcs_id) -{ - return !test_bit(tcs_id, drv->tcs_in_use); -} - /** * tcs_invalidate() - Invalidate all TCSes of the given type (sleep or wake). * @drv: The RSC controller. @@ -408,12 +392,10 @@ static irqreturn_t tcs_tx_done(int irq, void *p) irq_status = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_STATUS); - for_each_set_bit(i, &irq_status, BITS_PER_LONG) { + for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) { req = get_req_from_tcs(drv, i); - if (!req) { - WARN_ON(1); + if (WARN_ON(!req)) goto skip; - } err = 0; for (j = 0; j < req->num_cmds; j++) { @@ -520,7 +502,7 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, * * Return: 0 if nothing in flight or -EBUSY if we should try again later. * The caller must re-enable interrupts between tries since that's - * the only way tcs_is_free() will ever return true and the only way + * the only way tcs_in_use will ever be updated and the only way * RSC_DRV_CMD_ENABLE will ever be cleared. */ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs, @@ -528,17 +510,14 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs, { unsigned long curr_enabled; u32 addr; - int i, j, k; - int tcs_id = tcs->offset; - - for (i = 0; i < tcs->num_tcs; i++, tcs_id++) { - if (tcs_is_free(drv, tcs_id)) - continue; + int j, k; + int i = tcs->offset; - curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id); + for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) { + curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i); for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) { - addr = read_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j); + addr = read_tcs_cmd(drv, RSC_DRV_CMD_ADDR, i, j); for (k = 0; k < msg->num_cmds; k++) { if (addr == msg->cmds[k].addr) return -EBUSY; @@ -556,18 +535,19 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs, * * Must be called with the drv->lock held since that protects tcs_in_use. * - * Return: The first tcs that's free. + * Return: The first tcs that's free or -EBUSY if all in use. */ static int find_free_tcs(struct tcs_group *tcs) { - int i; + const struct rsc_drv *drv = tcs->drv; + unsigned long i; + unsigned long max = tcs->offset + tcs->num_tcs; - for (i = 0; i < tcs->num_tcs; i++) { - if (tcs_is_free(tcs->drv, tcs->offset + i)) - return tcs->offset + i; - } + i = find_next_zero_bit(drv->tcs_in_use, max, tcs->offset); + if (i >= max) + return -EBUSY; - return -EBUSY; + return i; } /** @@ -754,8 +734,9 @@ int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg) */ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv) { - int m; - struct tcs_group *tcs = &drv->tcs[ACTIVE_TCS]; + unsigned long set; + const struct tcs_group *tcs = &drv->tcs[ACTIVE_TCS]; + unsigned long max; /* * If we made an active request on a RSC that does not have a @@ -766,12 +747,10 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv) if (!tcs->num_tcs) tcs = &drv->tcs[WAKE_TCS]; - for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) { - if (!tcs_is_free(drv, m)) - return true; - } + max = tcs->offset + tcs->num_tcs; + set = find_next_bit(drv->tcs_in_use, max, tcs->offset); - return false; + return set < max; } /** diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 7ce06356d24c9dadae50b0fd38d2aa25b52735d5..bb21c4f1c0c4b6cd5062010189f9b59d70a16f39 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -200,6 +200,42 @@ static const struct rpmhpd_desc sm8250_desc = { .num_pds = ARRAY_SIZE(sm8250_rpmhpds), }; +/* SM8350 Power domains */ +static struct rpmhpd sm8350_mxc_ao; +static struct rpmhpd sm8350_mxc = { + .pd = { .name = "mxc", }, + .peer = &sm8150_mmcx_ao, + .res_name = "mxc.lvl", +}; + +static struct rpmhpd sm8350_mxc_ao = { + .pd = { .name = "mxc_ao", }, + .active_only = true, + .peer = &sm8350_mxc, + .res_name = "mxc.lvl", +}; + +static struct rpmhpd *sm8350_rpmhpds[] = { + [SM8350_CX] = &sdm845_cx, + [SM8350_CX_AO] = &sdm845_cx_ao, + [SM8350_EBI] = &sdm845_ebi, + [SM8350_GFX] = &sdm845_gfx, + [SM8350_LCX] = &sdm845_lcx, + [SM8350_LMX] = &sdm845_lmx, + [SM8350_MMCX] = &sm8150_mmcx, + [SM8350_MMCX_AO] = &sm8150_mmcx_ao, + [SM8350_MX] = &sdm845_mx, + [SM8350_MX_AO] = &sdm845_mx_ao, + [SM8350_MXC] = &sm8350_mxc, + [SM8350_MXC_AO] = &sm8350_mxc_ao, + [SM8350_MSS] = &sdm845_mss, +}; + +static const struct rpmhpd_desc sm8350_desc = { + .rpmhpds = sm8350_rpmhpds, + .num_pds = ARRAY_SIZE(sm8350_rpmhpds), +}; + /* SC7180 RPMH powerdomains */ static struct rpmhpd *sc7180_rpmhpds[] = { [SC7180_CX] = &sdm845_cx, @@ -217,12 +253,32 @@ static const struct rpmhpd_desc sc7180_desc = { .num_pds = ARRAY_SIZE(sc7180_rpmhpds), }; +/* SC7280 RPMH powerdomains */ +static struct rpmhpd *sc7280_rpmhpds[] = { + [SC7280_CX] = &sdm845_cx, + [SC7280_CX_AO] = &sdm845_cx_ao, + [SC7280_EBI] = &sdm845_ebi, + [SC7280_GFX] = &sdm845_gfx, + [SC7280_MX] = &sdm845_mx, + [SC7280_MX_AO] = &sdm845_mx_ao, + [SC7280_LMX] = &sdm845_lmx, + [SC7280_LCX] = &sdm845_lcx, + [SC7280_MSS] = &sdm845_mss, +}; + +static const struct rpmhpd_desc sc7280_desc = { + .rpmhpds = sc7280_rpmhpds, + .num_pds = ARRAY_SIZE(sc7280_rpmhpds), +}; + static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, + { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, + { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc }, { } }; MODULE_DEVICE_TABLE(of, rpmhpd_match_table); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index cc4e0655a47b3a0f594359675923fdf00d61182e..4fb5aeeb08439853f675afb8ce0acf946c685702 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -84,7 +84,7 @@ #define SMEM_GLOBAL_HOST 0xfffe /* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 11 +#define SMEM_HOST_COUNT 14 /** * struct smem_proc_comm - proc_comm communication struct (legacy) diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index 32bed249f90e569277c22d94e577e6e07b011abd..2a06d631e415a32b0957cb15b04af837e0b279f0 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -199,6 +199,8 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) { struct wcnss_download_nv_req *req; const struct firmware *fw; + struct device *dev = wcnss->dev; + const char *nvbin = NVBIN_FILE; const void *data; ssize_t left; int ret; @@ -207,10 +209,13 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) if (!req) return -ENOMEM; - ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev); + ret = of_property_read_string(dev->of_node, "firmware-name", &nvbin); + if (ret < 0 && ret != -EINVAL) + goto free_req; + + ret = request_firmware(&fw, nvbin, dev); if (ret < 0) { - dev_err(wcnss->dev, "Failed to load nv file %s: %d\n", - NVBIN_FILE, ret); + dev_err(dev, "Failed to load nv file %s: %d\n", nvbin, ret); goto free_req; } @@ -235,7 +240,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) ret = rpmsg_send(wcnss->channel, req, req->hdr.len); if (ret < 0) { - dev_err(wcnss->dev, "failed to send smd packet\n"); + dev_err(dev, "failed to send smd packet\n"); goto release_fw; } @@ -248,7 +253,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT); if (!ret) { - dev_err(wcnss->dev, "timeout waiting for nv upload ack\n"); + dev_err(dev, "timeout waiting for nv upload ack\n"); ret = -ETIMEDOUT; } else { *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING; diff --git a/drivers/soc/renesas/rmobile-sysc.c b/drivers/soc/renesas/rmobile-sysc.c index 9046b8c933cbe03110931be2a89dd894fa750716..204e6135180b919c240f859901d7dc23df7a63b1 100644 --- a/drivers/soc/renesas/rmobile-sysc.c +++ b/drivers/soc/renesas/rmobile-sysc.c @@ -14,8 +14,6 @@ #include <linux/delay.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_clock.h> #include <linux/pm_domain.h> @@ -344,6 +342,8 @@ static int __init rmobile_init_pm_domains(void) of_node_put(np); break; } + + fwnode_dev_initialized(&np->fwnode, true); } put_special_pds(); diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index df9a5ca8c99c43799ff3d1670acf12f930eb4406..6bd22359d4113da6bd1f6f8bda8923533c13aae4 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -39,6 +39,7 @@ #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/reboot.h> +#include <linux/regmap.h> #include <linux/reset.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -102,6 +103,9 @@ #define PMC_PWR_DET_VALUE 0xe4 +#define PMC_USB_DEBOUNCE_DEL 0xec +#define PMC_USB_AO 0xf0 + #define PMC_SCRATCH41 0x140 #define PMC_WAKE2_MASK 0x160 @@ -133,6 +137,13 @@ #define IO_DPD2_STATUS 0x1c4 #define SEL_DPD_TIM 0x1c8 +#define PMC_UTMIP_UHSIC_TRIGGERS 0x1ec +#define PMC_UTMIP_UHSIC_SAVED_STATE 0x1f0 + +#define PMC_UTMIP_TERM_PAD_CFG 0x1f8 +#define PMC_UTMIP_UHSIC_SLEEP_CFG 0x1fc +#define PMC_UTMIP_UHSIC_FAKE 0x218 + #define PMC_SCRATCH54 0x258 #define PMC_SCRATCH54_DATA_SHIFT 8 #define PMC_SCRATCH54_ADDR_SHIFT 0 @@ -145,8 +156,18 @@ #define PMC_SCRATCH55_CHECKSUM_SHIFT 16 #define PMC_SCRATCH55_I2CSLV1_SHIFT 0 +#define PMC_UTMIP_UHSIC_LINE_WAKEUP 0x26c + +#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x270 +#define PMC_UTMIP_MASTER_CONFIG 0x274 +#define PMC_UTMIP_UHSIC2_TRIGGERS 0x27c +#define PMC_UTMIP_MASTER2_CONFIG 0x29c + #define GPU_RG_CNTRL 0x2d4 +#define PMC_UTMIP_PAD_CFG0 0x4c0 +#define PMC_UTMIP_UHSIC_SLEEP_CFG1 0x4d0 +#define PMC_UTMIP_SLEEPWALK_P3 0x4e0 /* Tegra186 and later */ #define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) #define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) @@ -237,6 +258,7 @@ struct tegra_powergate { unsigned int id; struct clk **clks; unsigned int num_clks; + unsigned long *clk_rates; struct reset_control *reset; }; @@ -317,6 +339,8 @@ struct tegra_pmc_soc { bool invert); int (*irq_set_wake)(struct irq_data *data, unsigned int on); int (*irq_set_type)(struct irq_data *data, unsigned int type); + int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id, + bool new_state); const char * const *reset_sources; unsigned int num_reset_sources; @@ -334,6 +358,7 @@ struct tegra_pmc_soc { const struct pmc_clk_init_data *pmc_clks_data; unsigned int num_pmc_clks; bool has_blink_output; + bool has_usb_sleepwalk; }; /** @@ -517,6 +542,63 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) return -ENODEV; } +static int tegra20_powergate_set(struct tegra_pmc *pmc, unsigned int id, + bool new_state) +{ + unsigned int retries = 100; + bool status; + int ret; + + /* + * As per TRM documentation, the toggle command will be dropped by PMC + * if there is contention with a HW-initiated toggling (i.e. CPU core + * power-gated), the command should be retried in that case. + */ + do { + tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + /* wait for PMC to execute the command */ + ret = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 1, 10); + } while (ret == -ETIMEDOUT && retries--); + + return ret; +} + +static inline bool tegra_powergate_toggle_ready(struct tegra_pmc *pmc) +{ + return !(tegra_pmc_readl(pmc, PWRGATE_TOGGLE) & PWRGATE_TOGGLE_START); +} + +static int tegra114_powergate_set(struct tegra_pmc *pmc, unsigned int id, + bool new_state) +{ + bool status; + int err; + + /* wait while PMC power gating is contended */ + err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, + status == true, 1, 100); + if (err) + return err; + + tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + /* wait for PMC to accept the command */ + err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, + status == true, 1, 100); + if (err) + return err; + + /* wait for PMC to execute the command */ + err = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 10, 100000); + if (err) + return err; + + return 0; +} + /** * tegra_powergate_set() - set the state of a partition * @pmc: power management controller @@ -526,7 +608,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, bool new_state) { - bool status; int err; if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) @@ -539,10 +620,7 @@ static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, return 0; } - tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); - - err = readx_poll_timeout(tegra_powergate_state, id, status, - status == new_state, 10, 100000); + err = pmc->soc->powergate_set(pmc, id, new_state); mutex_unlock(&pmc->powergates_lock); @@ -586,6 +664,57 @@ out: return 0; } +static int tegra_powergate_prepare_clocks(struct tegra_powergate *pg) +{ + unsigned long safe_rate = 100 * 1000 * 1000; + unsigned int i; + int err; + + for (i = 0; i < pg->num_clks; i++) { + pg->clk_rates[i] = clk_get_rate(pg->clks[i]); + + if (!pg->clk_rates[i]) { + err = -EINVAL; + goto out; + } + + if (pg->clk_rates[i] <= safe_rate) + continue; + + /* + * We don't know whether voltage state is okay for the + * current clock rate, hence it's better to temporally + * switch clock to a safe rate which is suitable for + * all voltages, before enabling the clock. + */ + err = clk_set_rate(pg->clks[i], safe_rate); + if (err) + goto out; + } + + return 0; + +out: + while (i--) + clk_set_rate(pg->clks[i], pg->clk_rates[i]); + + return err; +} + +static int tegra_powergate_unprepare_clocks(struct tegra_powergate *pg) +{ + unsigned int i; + int err; + + for (i = 0; i < pg->num_clks; i++) { + err = clk_set_rate(pg->clks[i], pg->clk_rates[i]); + if (err) + return err; + } + + return 0; +} + static void tegra_powergate_disable_clocks(struct tegra_powergate *pg) { unsigned int i; @@ -636,9 +765,13 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, usleep_range(10, 20); + err = tegra_powergate_prepare_clocks(pg); + if (err) + goto powergate_off; + err = tegra_powergate_enable_clocks(pg); if (err) - goto disable_clks; + goto unprepare_clks; usleep_range(10, 20); @@ -662,12 +795,19 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, if (disable_clocks) tegra_powergate_disable_clocks(pg); + err = tegra_powergate_unprepare_clocks(pg); + if (err) + return err; + return 0; disable_clks: tegra_powergate_disable_clocks(pg); usleep_range(10, 20); +unprepare_clks: + tegra_powergate_unprepare_clocks(pg); + powergate_off: tegra_powergate_set(pg->pmc, pg->id, false); @@ -678,10 +818,14 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) { int err; - err = tegra_powergate_enable_clocks(pg); + err = tegra_powergate_prepare_clocks(pg); if (err) return err; + err = tegra_powergate_enable_clocks(pg); + if (err) + goto unprepare_clks; + usleep_range(10, 20); err = reset_control_assert(pg->reset); @@ -698,6 +842,10 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) if (err) goto assert_resets; + err = tegra_powergate_unprepare_clocks(pg); + if (err) + return err; + return 0; assert_resets: @@ -709,6 +857,9 @@ assert_resets: disable_clks: tegra_powergate_disable_clocks(pg); +unprepare_clks: + tegra_powergate_unprepare_clocks(pg); + return err; } @@ -739,7 +890,8 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain) err = reset_control_acquire(pg->reset); if (err < 0) { - pr_err("failed to acquire resets: %d\n", err); + dev_err(dev, "failed to acquire resets for PM domain %s: %d\n", + pg->genpd.name, err); return err; } @@ -826,6 +978,12 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, if (!pg) return -ENOMEM; + pg->clk_rates = kzalloc(sizeof(*pg->clk_rates), GFP_KERNEL); + if (!pg->clk_rates) { + kfree(pg->clks); + return -ENOMEM; + } + pg->id = id; pg->clks = &clk; pg->num_clks = 1; @@ -837,6 +995,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, dev_err(pmc->dev, "failed to turn on partition %d: %d\n", id, err); + kfree(pg->clk_rates); kfree(pg); return err; @@ -987,6 +1146,12 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, if (!pg->clks) return -ENOMEM; + pg->clk_rates = kcalloc(count, sizeof(*pg->clk_rates), GFP_KERNEL); + if (!pg->clk_rates) { + kfree(pg->clks); + return -ENOMEM; + } + for (i = 0; i < count; i++) { pg->clks[i] = of_clk_get(np, i); if (IS_ERR(pg->clks[i])) { @@ -1003,6 +1168,7 @@ err: while (i--) clk_put(pg->clks[i]); + kfree(pg->clk_rates); kfree(pg->clks); return err; @@ -2443,6 +2609,67 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc, err); } +static const struct regmap_range pmc_usb_sleepwalk_ranges[] = { + regmap_reg_range(PMC_USB_DEBOUNCE_DEL, PMC_USB_AO), + regmap_reg_range(PMC_UTMIP_UHSIC_TRIGGERS, PMC_UTMIP_UHSIC_SAVED_STATE), + regmap_reg_range(PMC_UTMIP_TERM_PAD_CFG, PMC_UTMIP_UHSIC_FAKE), + regmap_reg_range(PMC_UTMIP_UHSIC_LINE_WAKEUP, PMC_UTMIP_UHSIC_LINE_WAKEUP), + regmap_reg_range(PMC_UTMIP_BIAS_MASTER_CNTRL, PMC_UTMIP_MASTER_CONFIG), + regmap_reg_range(PMC_UTMIP_UHSIC2_TRIGGERS, PMC_UTMIP_MASTER2_CONFIG), + regmap_reg_range(PMC_UTMIP_PAD_CFG0, PMC_UTMIP_UHSIC_SLEEP_CFG1), + regmap_reg_range(PMC_UTMIP_SLEEPWALK_P3, PMC_UTMIP_SLEEPWALK_P3), +}; + +static const struct regmap_access_table pmc_usb_sleepwalk_table = { + .yes_ranges = pmc_usb_sleepwalk_ranges, + .n_yes_ranges = ARRAY_SIZE(pmc_usb_sleepwalk_ranges), +}; + +static int tegra_pmc_regmap_readl(void *context, unsigned int offset, unsigned int *value) +{ + struct tegra_pmc *pmc = context; + + *value = tegra_pmc_readl(pmc, offset); + return 0; +} + +static int tegra_pmc_regmap_writel(void *context, unsigned int offset, unsigned int value) +{ + struct tegra_pmc *pmc = context; + + tegra_pmc_writel(pmc, value, offset); + return 0; +} + +static const struct regmap_config usb_sleepwalk_regmap_config = { + .name = "usb_sleepwalk", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .fast_io = true, + .rd_table = &pmc_usb_sleepwalk_table, + .wr_table = &pmc_usb_sleepwalk_table, + .reg_read = tegra_pmc_regmap_readl, + .reg_write = tegra_pmc_regmap_writel, +}; + +static int tegra_pmc_regmap_init(struct tegra_pmc *pmc) +{ + struct regmap *regmap; + int err; + + if (pmc->soc->has_usb_sleepwalk) { + regmap = devm_regmap_init(pmc->dev, NULL, pmc, &usb_sleepwalk_regmap_config); + if (IS_ERR(regmap)) { + err = PTR_ERR(regmap); + dev_err(pmc->dev, "failed to allocate register map (%d)\n", err); + return err; + } + } + + return 0; +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base; @@ -2548,6 +2775,10 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (err) goto cleanup_restart_handler; + err = tegra_pmc_regmap_init(pmc); + if (err < 0) + goto cleanup_restart_handler; + err = tegra_powergate_init(pmc, pdev->dev.of_node); if (err < 0) goto cleanup_powergates; @@ -2699,6 +2930,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra20_powergate_set, .reset_sources = NULL, .num_reset_sources = 0, .reset_levels = NULL, @@ -2706,6 +2938,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .pmc_clks_data = NULL, .num_pmc_clks = 0, .has_blink_output = true, + .has_usb_sleepwalk = false, }; static const char * const tegra30_powergates[] = { @@ -2757,6 +2990,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra20_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2764,6 +2998,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = false, }; static const char * const tegra114_powergates[] = { @@ -2811,6 +3046,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2818,6 +3054,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = false, }; static const char * const tegra124_powergates[] = { @@ -2925,6 +3162,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2932,6 +3170,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = true, }; static const char * const tegra210_powergates[] = { @@ -3048,6 +3287,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .irq_set_wake = tegra210_pmc_irq_set_wake, .irq_set_type = tegra210_pmc_irq_set_type, .reset_sources = tegra210_reset_sources, @@ -3059,6 +3299,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = true, }; #define TEGRA186_IO_PAD_TABLE(_pad) \ @@ -3214,6 +3455,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .pmc_clks_data = NULL, .num_pmc_clks = 0, .has_blink_output = false, + .has_usb_sleepwalk = false, }; #define TEGRA194_IO_PAD_TABLE(_pad) \ @@ -3347,6 +3589,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .pmc_clks_data = NULL, .num_pmc_clks = 0, .has_blink_output = false, + .has_usb_sleepwalk = false, }; static const struct tegra_pmc_regs tegra234_pmc_regs = { diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index 7f21f31de09d6822b82569461264c7de342c749d..0e776b20f6252fe08da16a7ffe0d50f40e04c927 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -178,7 +178,7 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, * survive the voltage drop if it's running on a higher frequency. */ if (!cpu_min_uV_consumers) - cpu_min_uV = cpu_uV; + cpu_min_uV = max(cpu_uV, cpu_min_uV); /* * Bootloader shall set up voltages correctly, but if it diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c index 51143a68a8896db434658878f6176dd5de1d0826..ea64e187854eb8579a5a1ff1e1eaf9a6aeeaedd8 100644 --- a/drivers/soc/ti/omap_prm.c +++ b/drivers/soc/ti/omap_prm.c @@ -88,6 +88,7 @@ struct omap_reset_data { #define OMAP_PRM_HAS_RSTCTRL BIT(0) #define OMAP_PRM_HAS_RSTST BIT(1) #define OMAP_PRM_HAS_NO_CLKDM BIT(2) +#define OMAP_PRM_RET_WHEN_IDLE BIT(3) #define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST) @@ -174,7 +175,8 @@ static const struct omap_prm_data omap4_prm_data[] = { .name = "core", .base = 0x4a306700, .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", - .rstmap = rst_map_012 + .rstmap = rst_map_012, + .flags = OMAP_PRM_RET_WHEN_IDLE, }, { .name = "ivahd", .base = 0x4a306f00, @@ -199,7 +201,8 @@ static const struct omap_prm_data omap4_prm_data[] = { }, { .name = "l4per", .base = 0x4a307400, - .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton + .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, + .flags = OMAP_PRM_RET_WHEN_IDLE, }, { .name = "cefuse", .base = 0x4a307600, @@ -517,7 +520,7 @@ static int omap_prm_domain_power_on(struct generic_pm_domain *domain) { struct omap_prm_domain *prmd; int ret; - u32 v; + u32 v, mode; prmd = genpd_to_prm_domain(domain); if (!prmd->cap) @@ -530,7 +533,12 @@ static int omap_prm_domain_power_on(struct generic_pm_domain *domain) else v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); - writel_relaxed(v | OMAP_PRMD_ON_ACTIVE, + if (prmd->prm->data->flags & OMAP_PRM_RET_WHEN_IDLE) + mode = OMAP_PRMD_RETENTION; + else + mode = OMAP_PRMD_ON_ACTIVE; + + writel_relaxed((v & ~PRM_POWERSTATE_MASK) | mode, prmd->prm->base + prmd->pwrstctrl); /* wait for the transition bit to get cleared */ diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index bf1e250d50dd9b715c72b36c56089e6eb323d283..986776787b9eaddf17ef3ca2ff472623eb94fead 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -20,7 +20,7 @@ soundwire-cadence-y := cadence_master.o obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o #Intel driver -soundwire-intel-y := intel.o intel_init.o +soundwire-intel-y := intel.o intel_init.o dmi-quirks.o obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o #Qualcomm driver diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 46885429928ab817b1d0b07950ad457db28a0119..a9e0aa72654dd8a940c0d4e8773920405843ab0a 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -44,13 +44,13 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, } ret = sdw_get_id(bus); - if (ret) { + if (ret < 0) { dev_err(parent, "Failed to get bus id\n"); return ret; } ret = sdw_master_device_add(bus, parent, fwnode); - if (ret) { + if (ret < 0) { dev_err(parent, "Failed to add master device at link %d\n", bus->link_id); return ret; @@ -121,7 +121,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, else ret = -ENOTSUPP; /* No ACPI/DT so error out */ - if (ret) { + if (ret < 0) { dev_err(bus->dev, "Finding slaves failed:%d\n", ret); return ret; } @@ -422,7 +422,7 @@ sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_READ, &buf); - if (ret) + if (ret < 0) return ret; ret = sdw_transfer(bus, &msg); @@ -440,7 +440,7 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_WRITE, &value); - if (ret) + if (ret < 0) return ret; return sdw_transfer(bus, &msg); @@ -454,7 +454,7 @@ int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_READ, &buf); - if (ret) + if (ret < 0) return ret; ret = sdw_transfer_unlocked(bus, &msg); @@ -472,7 +472,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_WRITE, &value); - if (ret) + if (ret < 0) return ret; return sdw_transfer_unlocked(bus, &msg); @@ -593,7 +593,7 @@ EXPORT_SYMBOL(sdw_write); /* called with bus_lock held */ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) { - struct sdw_slave *slave = NULL; + struct sdw_slave *slave; list_for_each_entry(slave, &bus->slaves, node) { if (slave->dev_num == i) @@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) return NULL; } -static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) +int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) { if (slave->id.mfg_id != id.mfg_id || slave->id.part_id != id.part_id || @@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) return 0; } +EXPORT_SYMBOL(sdw_compare_devid); /* called with bus_lock held */ static int sdw_get_device_num(struct sdw_slave *slave) @@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus, "SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, unique_id 0x%x, version 0x%x\n", id->class_id, id->mfg_id, id->part_id, id->unique_id, id->sdw_version); } +EXPORT_SYMBOL(sdw_extract_slave_id); static int sdw_program_device_num(struct sdw_bus *bus) { @@ -705,7 +707,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) struct sdw_slave *slave, *_s; struct sdw_slave_id id; struct sdw_msg msg; - bool found = false; + bool found; int count = 0, ret; u64 addr; @@ -737,6 +739,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) sdw_extract_slave_id(bus, addr, &id); + found = false; /* Now compare with entries */ list_for_each_entry_safe(slave, _s, &bus->slaves, node) { if (sdw_compare_devid(slave, id) == 0) { @@ -749,7 +752,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) * dev_num */ ret = sdw_assign_device_num(slave); - if (ret) { + if (ret < 0) { dev_err(bus->dev, "Assign dev_num failed:%d\n", ret); @@ -875,14 +878,18 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, if (wake_en) val |= SDW_SCP_SYSTEMCTRL_WAKE_UP_EN; } else { - val = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); - + ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); + if (ret < 0) { + dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret); + return ret; + } + val = ret; val &= ~(SDW_SCP_SYSTEMCTRL_CLK_STP_PREP); } ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val); - if (ret != 0) + if (ret < 0) dev_err(&slave->dev, "Clock Stop prepare failed for slave: %d", ret); @@ -895,11 +902,15 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) int val; do { - val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT) & - SDW_SCP_STAT_CLK_STP_NF; + val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT); + if (val < 0) { + dev_err(bus->dev, "SDW_SCP_STAT bread failed:%d\n", val); + return val; + } + val &= SDW_SCP_STAT_CLK_STP_NF; if (!val) { - dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", - dev_num); + dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d", + dev_num); return 0; } @@ -1253,6 +1264,7 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) static int sdw_initialize_slave(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; + int status; int ret; u8 val; @@ -1260,6 +1272,44 @@ static int sdw_initialize_slave(struct sdw_slave *slave) if (ret < 0) return ret; + if (slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH) { + /* Clear bus clash interrupt before enabling interrupt mask */ + status = sdw_read_no_pm(slave, SDW_SCP_INT1); + if (status < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (BUS_CLASH) read failed:%d\n", status); + return status; + } + if (status & SDW_SCP_INT1_BUS_CLASH) { + dev_warn(&slave->dev, "Bus clash detected before INT mask is enabled\n"); + ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_BUS_CLASH); + if (ret < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (BUS_CLASH) write failed:%d\n", ret); + return ret; + } + } + } + if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) && + !(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) { + /* Clear parity interrupt before enabling interrupt mask */ + status = sdw_read_no_pm(slave, SDW_SCP_INT1); + if (status < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (PARITY) read failed:%d\n", status); + return status; + } + if (status & SDW_SCP_INT1_PARITY) { + dev_warn(&slave->dev, "PARITY error detected before INT mask is enabled\n"); + ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_PARITY); + if (ret < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (PARITY) write failed:%d\n", ret); + return ret; + } + } + } + /* * Set SCP_INT1_MASK register, typically bus clash and * implementation-defined interrupt mask. The Parity detection @@ -1589,7 +1639,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_read_no_pm(slave, SDW_SCP_INT1); if (ret < 0) { dev_err(&slave->dev, - "SDW_SCP_INT1 read failed:%d\n", ret); + "SDW_SCP_INT1 recheck read failed:%d\n", ret); goto io_err; } _buf = ret; @@ -1597,7 +1647,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2); if (ret < 0) { dev_err(&slave->dev, - "SDW_SCP_INT2/3 read failed:%d\n", ret); + "SDW_SCP_INT2/3 recheck read failed:%d\n", ret); goto io_err; } @@ -1605,7 +1655,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_read_no_pm(slave, SDW_DP0_INT); if (ret < 0) { dev_err(&slave->dev, - "SDW_DP0_INT read failed:%d\n", ret); + "SDW_DP0_INT recheck read failed:%d\n", ret); goto io_err; } sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; @@ -1701,7 +1751,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (status[0] == SDW_SLAVE_ATTACHED) { dev_dbg(bus->dev, "Slave attached, programming device number\n"); ret = sdw_program_device_num(bus); - if (ret) + if (ret < 0) dev_err(bus->dev, "Slave attach failed: %d\n", ret); /* * programming a device number will have side effects, @@ -1735,7 +1785,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, case SDW_SLAVE_ALERT: ret = sdw_handle_slave_alerts(slave); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Slave %d alert handling failed: %d\n", i, ret); @@ -1754,7 +1804,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, attached_initializing = true; ret = sdw_initialize_slave(slave); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Slave %d initialization failed: %d\n", i, ret); @@ -1768,7 +1818,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, } ret = sdw_update_slave_status(slave, status[i]); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Update Slave status failed:%d\n", ret); if (attached_initializing) { diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 2e049d39c6e5c667c7906174e49210688966f323..40354469860a746f2e52a180170941abbdc283b7 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -7,6 +7,8 @@ #define DEFAULT_BANK_SWITCH_TIMEOUT 3000 #define DEFAULT_PROBE_TIMEOUT 2000 +u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr); + #if IS_ENABLED(CONFIG_ACPI) int sdw_acpi_find_slaves(struct sdw_bus *bus); #else diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 575b9bad99d510459fca1fed8fc22bc4e1f2af64..893296f3fe395ea7fdf069b0def0010a6b71df91 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -82,6 +82,7 @@ static int sdw_drv_probe(struct device *dev) struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); const struct sdw_device_id *id; + const char *name; int ret; /* @@ -108,7 +109,10 @@ static int sdw_drv_probe(struct device *dev) ret = drv->probe(slave, id); if (ret) { - dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); + name = drv->name; + if (!name) + name = drv->driver.name; + dev_err(dev, "Probe of %s failed: %d\n", name, ret); dev_pm_domain_detach(dev, false); return ret; } @@ -174,11 +178,16 @@ static void sdw_drv_shutdown(struct device *dev) */ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) { + const char *name; + drv->driver.bus = &sdw_bus_type; if (!drv->probe) { - pr_err("driver %s didn't provide SDW probe routine\n", - drv->name); + name = drv->name; + if (!name) + name = drv->driver.name; + + pr_err("driver %s didn't provide SDW probe routine\n", name); return -EINVAL; } diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index d05442e646a38317c125ef5e9bf5606deff1c130..192dac10f0c2c0d326b297e09cf2d517abc79186 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -905,7 +905,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) EXPORT_SYMBOL(sdw_cdns_irq); /** - * To update slave status in a work since we will need to handle + * cdns_update_slave_status_work - update slave status in a work since we will need to handle * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave * process. * @work: cdns worker thread @@ -968,7 +968,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns) EXPORT_SYMBOL(sdw_cdns_exit_reset); /** - * sdw_cdns_enable_slave_interrupt() - Enable SDW slave interrupts + * cdns_enable_slave_interrupts() - Enable SDW slave interrupts * @cdns: Cadence instance * @state: boolean for true/false */ @@ -1450,10 +1450,12 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) } /* Prepare slaves for clock stop */ - ret = sdw_bus_prep_clk_stop(&cdns->bus); - if (ret < 0) { - dev_err(cdns->dev, "prepare clock stop failed %d", ret); - return ret; + if (slave_present) { + ret = sdw_bus_prep_clk_stop(&cdns->bus); + if (ret < 0 && ret != -ENODATA) { + dev_err(cdns->dev, "prepare clock stop failed %d\n", ret); + return ret; + } } /* @@ -1462,7 +1464,7 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) */ ret = sdw_bus_clk_stop(&cdns->bus); if (ret < 0 && slave_present && ret != -ENODATA) { - dev_err(cdns->dev, "bus clock stop failed %d", ret); + dev_err(cdns->dev, "bus clock stop failed %d\n", ret); return ret; } diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c new file mode 100644 index 0000000000000000000000000000000000000000..82061c1d98356e10060a9d9d5b8a46ba77b8b7f0 --- /dev/null +++ b/drivers/soundwire/dmi-quirks.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2021 Intel Corporation. + +/* + * Soundwire DMI quirks + */ + +#include <linux/device.h> +#include <linux/dmi.h> +#include <linux/soundwire/sdw.h> +#include "bus.h" + +struct adr_remap { + u64 adr; + u64 remapped_adr; +}; + +/* + * HP Spectre 360 Convertible devices do not expose the correct _ADR + * in the DSDT. + * Remap the bad _ADR values to the ones reported by hardware + */ +static const struct adr_remap hp_spectre_360[] = { + { + 0x000010025D070100, + 0x000020025D071100 + }, + { + 0x000110025d070100, + 0x000120025D130800 + }, + {} +}; + +/* + * The initial version of the Dell SKU 0A3E did not expose the devices + * on the correct links. + */ +static const struct adr_remap dell_sku_0A3E[] = { + /* rt715 on link0 */ + { + 0x00020025d071100, + 0x00021025d071500 + }, + /* rt711 on link1 */ + { + 0x000120025d130800, + 0x000120025d071100, + }, + /* rt1308 on link2 */ + { + 0x000220025d071500, + 0x000220025d130800 + }, + {} +}; + +static const struct dmi_system_id adr_remap_quirk_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"), + }, + .driver_data = (void *)hp_spectre_360, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E") + }, + .driver_data = (void *)dell_sku_0A3E, + }, + {} +}; + +u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr) +{ + const struct dmi_system_id *dmi_id; + + /* check if any address remap quirk applies */ + dmi_id = dmi_first_match(adr_remap_quirk_table); + if (dmi_id) { + struct adr_remap *map = dmi_id->driver_data; + + for (map = dmi_id->driver_data; map->adr; map++) { + if (map->adr == addr) { + dev_dbg(bus->dev, "remapped _ADR 0x%llx as 0x%llx\n", + addr, map->remapped_adr); + addr = map->remapped_adr; + break; + } + } + } + + return addr; +} diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 0bdef38c9a301f92c55d83781bcd02ea0206c676..84d1295870842034958a9a1b256087eb6bcbfc67 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -62,7 +62,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, sample_int, port_bo, port_bo >> 8, t_data->hstart, t_data->hstop, - (SDW_BLK_GRP_CNT_1 * ch), 0x0); + SDW_BLK_PKG_PER_PORT, 0x0); sdw_fill_port_params(&p_rt->port_params, p_rt->num, bps, @@ -95,7 +95,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, struct sdw_bus *bus = m_rt->bus; struct sdw_bus_params *b_params = &bus->params; int sample_int, hstart = 0; - unsigned int rate, bps, ch, no_ch; + unsigned int rate, bps, ch; rate = m_rt->stream->params.rate; bps = m_rt->stream->params.bps; @@ -110,12 +110,11 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, t_data.hstart = hstart; list_for_each_entry(p_rt, &m_rt->port_list, port_node) { - no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask); sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false, SDW_BLK_GRP_CNT_1, sample_int, port_bo, port_bo >> 8, hstart, hstop, - (SDW_BLK_GRP_CNT_1 * no_ch), 0x0); + SDW_BLK_PKG_PER_PORT, 0x0); sdw_fill_port_params(&p_rt->port_params, p_rt->num, bps, @@ -143,7 +142,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_params *params, int count) { - struct sdw_master_runtime *m_rt = NULL; + struct sdw_master_runtime *m_rt; int hstop = bus->params.col - 1; int block_offset, port_bo, i; @@ -169,7 +168,7 @@ static int sdw_compute_group_params(struct sdw_bus *bus, struct sdw_group_params *params, int *rates, int count) { - struct sdw_master_runtime *m_rt = NULL; + struct sdw_master_runtime *m_rt; int sel_col = bus->params.col; unsigned int rate, bps, ch; int i, column_needed = 0; @@ -406,14 +405,14 @@ int sdw_compute_params(struct sdw_bus *bus) /* Computes clock frequency, frame shape and frame frequency */ ret = sdw_compute_bus_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute bus params failed: %d", ret); + dev_err(bus->dev, "Compute bus params failed: %d\n", ret); return ret; } /* Compute transport and port params */ ret = sdw_compute_port_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute transport params failed: %d", ret); + dev_err(bus->dev, "Compute transport params failed: %d\n", ret); return ret; } diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index a2d5cdaa9998b66a390b8f9b5dd0a1703ca52436..fd95f94630b1c59e4842f1a60c2d0167f119d96e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -561,8 +561,6 @@ static int intel_link_power_down(struct sdw_intel *sdw) ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); } - link_control = intel_readl(shim, SDW_SHIM_LCTL); - mutex_unlock(sdw->link_res->shim_lock); if (ret < 0) { @@ -997,7 +995,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) { - dev_err(dai->dev, "failed to get dma data in %s", + dev_err(dai->dev, "failed to get dma data in %s\n", __func__); return -EIO; } @@ -1061,7 +1059,7 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ret = intel_free_stream(sdw, substream, dai, sdw->instance); if (ret < 0) { - dev_err(dai->dev, "intel_free_stream: failed %d", ret); + dev_err(dai->dev, "intel_free_stream: failed %d\n", ret); return ret; } @@ -1286,6 +1284,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) prop->hw_disabled = true; + prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH | + SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY; + return 0; } @@ -1302,6 +1303,7 @@ static int intel_prop_read(struct sdw_bus *bus) static struct sdw_master_ops sdw_intel_ops = { .read_prop = sdw_master_read_prop, + .override_adr = sdw_dmi_override_adr, .xfer_msg = cdns_xfer_msg, .xfer_msg_defer = cdns_xfer_msg_defer, .reset_page_addr = cdns_reset_page_addr, @@ -1630,7 +1632,7 @@ static int __maybe_unused intel_suspend(struct device *dev) ret = intel_link_power_down(sdw); if (ret) { - dev_err(dev, "Link power down failed: %d", ret); + dev_err(dev, "Link power down failed: %d\n", ret); return ret; } @@ -1665,7 +1667,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ret = intel_link_power_down(sdw); if (ret) { - dev_err(dev, "Link power down failed: %d", ret); + dev_err(dev, "Link power down failed: %d\n", ret); return ret; } @@ -1689,7 +1691,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ret = intel_link_power_down(sdw); if (ret) { - dev_err(dev, "Link power down failed: %d", ret); + dev_err(dev, "Link power down failed: %d\n", ret); return ret; } @@ -1738,7 +1740,7 @@ static int __maybe_unused intel_resume(struct device *dev) ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } @@ -1822,7 +1824,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } @@ -1867,7 +1869,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } @@ -1945,7 +1947,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 05b726cdfebc5804a7a2608e45341f8dbbf54511..30ce95ec2d703bec11b05b218741a63e7d9f623f 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -178,6 +178,15 @@ static struct sdw_intel_ctx link->pdev = pdev; link->cdns = platform_get_drvdata(pdev); + if (!link->cdns) { + dev_err(&adev->dev, "failed to get link->cdns\n"); + /* + * 1 will be subtracted from i in the err label, but we need to call + * intel_link_dev_unregister for this ldev, so plus 1 now + */ + i++; + goto err; + } list_add_tail(&link->list, &ctx->link_list); bus = &link->cdns->bus; /* Calculate number of slaves */ diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 6d22df01f35471e8a8803c09d6ea074a756e9734..2827085a323b85078641c055019ea2346c89c203 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -24,28 +24,50 @@ #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) #define SWRM_COMP_CFG_ENABLE_MSK BIT(0) #define SWRM_COMP_PARAMS 0x100 +#define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10) +#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15) #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) #define SWRM_INTERRUPT_STATUS 0x200 #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0) +#define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ BIT(0) #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1) #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2) +#define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3) +#define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4) +#define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW BIT(5) +#define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6) #define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7) +#define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION BIT(8) +#define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH BIT(9) #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10) +#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13) +#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 BIT(14) +#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP BIT(16) +#define SWRM_INTERRUPT_MAX 17 #define SWRM_INTERRUPT_MASK_ADDR 0x204 #define SWRM_INTERRUPT_CLEAR 0x208 #define SWRM_INTERRUPT_CPU_EN 0x210 #define SWRM_CMD_FIFO_WR_CMD 0x300 #define SWRM_CMD_FIFO_RD_CMD 0x304 #define SWRM_CMD_FIFO_CMD 0x308 +#define SWRM_CMD_FIFO_FLUSH 0x1 #define SWRM_CMD_FIFO_STATUS 0x30C +#define SWRM_RD_CMD_FIFO_CNT_MASK GENMASK(20, 16) +#define SWRM_WR_CMD_FIFO_CNT_MASK GENMASK(12, 8) #define SWRM_CMD_FIFO_CFG_ADDR 0x314 +#define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31) #define SWRM_RD_WR_CMD_RETRIES 0x7 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 +#define SWRM_RD_FIFO_CMD_ID_MASK GENMASK(11, 8) #define SWRM_ENUMERATOR_CFG_ADDR 0x500 +#define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m) (0x530 + 0x8 * (m)) +#define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m) (0x534 + 0x8 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3) +#define SWRM_MCP_BUS_CTRL 0x1044 +#define SWRM_MCP_BUS_CLK_START BIT(1) #define SWRM_MCP_CFG_ADDR 0x1048 #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17) #define SWRM_DEF_CMD_NO_PINGS 0x1f @@ -53,8 +75,15 @@ #define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0) #define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) +#define SWRM_MCP_SLV_STATUS_SZ 2 #define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) +#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) + #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18 #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 @@ -69,16 +98,28 @@ #define SWRM_SPECIAL_CMD_ID 0xF #define MAX_FREQ_NUM 1 #define TIMEOUT_MS (2 * HZ) -#define QCOM_SWRM_MAX_RD_LEN 0xf +#define QCOM_SWRM_MAX_RD_LEN 0x1 #define QCOM_SDW_MAX_PORTS 14 #define DEFAULT_CLK_FREQ 9600000 #define SWRM_MAX_DAIS 0xF +#define SWR_INVALID_PARAM 0xFF +#define SWR_HSTOP_MAX_VAL 0xF +#define SWR_HSTART_MIN_VAL 0x0 +#define SWR_BROADCAST_CMD_ID 0x0F +#define SWR_MAX_CMD_ID 14 +#define MAX_FIFO_RD_RETRY 3 +#define SWR_OVERFLOW_RETRY_COUNT 30 struct qcom_swrm_port_config { u8 si; u8 off1; u8 off2; u8 bp_mode; + u8 hstart; + u8 hstop; + u8 word_length; + u8 blk_group_count; + u8 lane_control; }; struct qcom_swrm_ctrl { @@ -86,10 +127,9 @@ struct qcom_swrm_ctrl { struct device *dev; struct regmap *regmap; void __iomem *mmio; - struct completion *comp; + struct completion broadcast; + struct completion enumeration; struct work_struct slave_work; - /* read/write lock */ - spinlock_t comp_lock; /* Port alloc/free lock */ struct mutex port_lock; struct clk *hclk; @@ -103,11 +143,17 @@ struct qcom_swrm_ctrl { int rows_index; unsigned long dout_port_mask; unsigned long din_port_mask; + u32 intr_mask; + u8 rcmd_id; + u8 wcmd_id; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; enum sdw_slave_status status[SDW_MAX_DEVICES]; int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); + u32 slave_status; + u32 wr_fifo_depth; + u32 rd_fifo_depth; }; struct qcom_swrm_data { @@ -181,77 +227,180 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg, return SDW_CMD_OK; } -static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data, +static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data, + u8 dev_addr, u16 reg_addr) +{ + u32 val; + u8 id = *cmd_id; + + if (id != SWR_BROADCAST_CMD_ID) { + if (id < SWR_MAX_CMD_ID) + id += 1; + else + id = 0; + *cmd_id = id; + } + val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, id, reg_addr); + + return val; +} + +static int swrm_wait_for_rd_fifo_avail(struct qcom_swrm_ctrl *swrm) +{ + u32 fifo_outstanding_data, value; + int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; + + do { + /* Check for fifo underflow during read */ + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + fifo_outstanding_data = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, value); + + /* Check if read data is available in read fifo */ + if (fifo_outstanding_data > 0) + return 0; + + usleep_range(500, 510); + } while (fifo_retry_count--); + + if (fifo_outstanding_data == 0) { + dev_err_ratelimited(swrm->dev, "%s err read underflow\n", __func__); + return -EIO; + } + + return 0; +} + +static int swrm_wait_for_wr_fifo_avail(struct qcom_swrm_ctrl *swrm) +{ + u32 fifo_outstanding_cmds, value; + int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; + + do { + /* Check for fifo overflow during write */ + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + fifo_outstanding_cmds = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, value); + + /* Check for space in write fifo before writing */ + if (fifo_outstanding_cmds < swrm->wr_fifo_depth) + return 0; + + usleep_range(500, 510); + } while (fifo_retry_count--); + + if (fifo_outstanding_cmds == swrm->wr_fifo_depth) { + dev_err_ratelimited(swrm->dev, "%s err write overflow\n", __func__); + return -EIO; + } + + return 0; +} + +static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data, u8 dev_addr, u16 reg_addr) { - DECLARE_COMPLETION_ONSTACK(comp); - unsigned long flags; + u32 val; - int ret; + int ret = 0; + u8 cmd_id = 0x0; - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = ∁ - spin_unlock_irqrestore(&ctrl->comp_lock, flags); - val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, - SWRM_SPECIAL_CMD_ID, reg_addr); - ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val); - if (ret) - goto err; + if (dev_addr == SDW_BROADCAST_DEV_NUM) { + cmd_id = SWR_BROADCAST_CMD_ID; + val = swrm_get_packed_reg_val(&cmd_id, cmd_data, + dev_addr, reg_addr); + } else { + val = swrm_get_packed_reg_val(&swrm->wcmd_id, cmd_data, + dev_addr, reg_addr); + } - ret = wait_for_completion_timeout(ctrl->comp, - msecs_to_jiffies(TIMEOUT_MS)); + if (swrm_wait_for_wr_fifo_avail(swrm)) + return SDW_CMD_FAIL_OTHER; + + /* Its assumed that write is okay as we do not get any status back */ + swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); + + /* version 1.3 or less */ + if (swrm->version <= 0x01030000) + usleep_range(150, 155); + + if (cmd_id == SWR_BROADCAST_CMD_ID) { + /* + * sleep for 10ms for MSM soundwire variant to allow broadcast + * command to complete. + */ + ret = wait_for_completion_timeout(&swrm->broadcast, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) + ret = SDW_CMD_IGNORED; + else + ret = SDW_CMD_OK; - if (!ret) - ret = SDW_CMD_IGNORED; - else + } else { ret = SDW_CMD_OK; -err: - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = NULL; - spin_unlock_irqrestore(&ctrl->comp_lock, flags); - + } return ret; } -static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl, +static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm, u8 dev_addr, u16 reg_addr, u32 len, u8 *rval) { - int i, ret; - u32 val; - DECLARE_COMPLETION_ONSTACK(comp); - unsigned long flags; + u32 cmd_data, cmd_id, val, retry_attempt = 0; + + val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr); + + /* wait for FIFO RD to complete to avoid overflow */ + usleep_range(100, 105); + swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); + /* wait for FIFO RD CMD complete to avoid overflow */ + usleep_range(250, 255); + + if (swrm_wait_for_rd_fifo_avail(swrm)) + return SDW_CMD_FAIL_OTHER; + + do { + swrm->reg_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR, &cmd_data); + rval[0] = cmd_data & 0xFF; + cmd_id = FIELD_GET(SWRM_RD_FIFO_CMD_ID_MASK, cmd_data); + + if (cmd_id != swrm->rcmd_id) { + if (retry_attempt < (MAX_FIFO_RD_RETRY - 1)) { + /* wait 500 us before retry on fifo read failure */ + usleep_range(500, 505); + swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, + SWRM_CMD_FIFO_FLUSH); + swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); + } + retry_attempt++; + } else { + return SDW_CMD_OK; + } - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = ∁ - spin_unlock_irqrestore(&ctrl->comp_lock, flags); + } while (retry_attempt < MAX_FIFO_RD_RETRY); - val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr); - ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val); - if (ret) - goto err; + dev_err(swrm->dev, "failed to read fifo: reg: 0x%x, rcmd_id: 0x%x,\ + dev_num: 0x%x, cmd_data: 0x%x\n", + reg_addr, swrm->rcmd_id, dev_addr, cmd_data); - ret = wait_for_completion_timeout(ctrl->comp, - msecs_to_jiffies(TIMEOUT_MS)); + return SDW_CMD_IGNORED; +} - if (!ret) { - ret = SDW_CMD_IGNORED; - goto err; - } else { - ret = SDW_CMD_OK; - } +static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) +{ + u32 val, status; + int dev_num; - for (i = 0; i < len; i++) { - ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val); - rval[i] = val & 0xFF; - } + ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); -err: - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = NULL; - spin_unlock_irqrestore(&ctrl->comp_lock, flags); + for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) { + status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); - return ret; + if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { + ctrl->status[dev_num] = status; + return dev_num; + } + } + + return -EINVAL; } static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) @@ -260,6 +409,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) int i; ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); + ctrl->slave_status = val; for (i = 0; i < SDW_MAX_DEVICES; i++) { u32 s; @@ -270,42 +420,188 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) } } -static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) +static void qcom_swrm_set_slave_dev_num(struct sdw_bus *bus, + struct sdw_slave *slave, int devnum) { - struct qcom_swrm_ctrl *ctrl = dev_id; - u32 sts, value; - unsigned long flags; + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + u32 status; + + ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &status); + status = (status >> (devnum * SWRM_MCP_SLV_STATUS_SZ)); + status &= SWRM_MCP_SLV_STATUS_MASK; + + if (status == SDW_SLAVE_ATTACHED) { + if (slave) + slave->dev_num = devnum; + mutex_lock(&bus->bus_lock); + set_bit(devnum, bus->assigned); + mutex_unlock(&bus->bus_lock); + } +} - ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts); +static int qcom_swrm_enumerate(struct sdw_bus *bus) +{ + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + struct sdw_slave *slave, *_s; + struct sdw_slave_id id; + u32 val1, val2; + bool found; + u64 addr; + int i; + char *buf1 = (char *)&val1, *buf2 = (char *)&val2; + + for (i = 1; i <= SDW_MAX_DEVICES; i++) { + /*SCP_Devid5 - Devid 4*/ + ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), &val1); + + /*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/ + ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_2(i), &val2); + + if (!val1 && !val2) + break; + + addr = buf2[1] | (buf2[0] << 8) | (buf1[3] << 16) | + ((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) | + ((u64)buf1[0] << 40); + + sdw_extract_slave_id(bus, addr, &id); + found = false; + /* Now compare with entries */ + list_for_each_entry_safe(slave, _s, &bus->slaves, node) { + if (sdw_compare_devid(slave, id) == 0) { + qcom_swrm_set_slave_dev_num(bus, slave, i); + found = true; + break; + } + } - if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) { - ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value); - dev_err_ratelimited(ctrl->dev, - "CMD error, fifo status 0x%x\n", - value); - ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1); + if (!found) { + qcom_swrm_set_slave_dev_num(bus, NULL, i); + sdw_slave_add(bus, &id, NULL); + } } - if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) || - sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) - schedule_work(&ctrl->slave_work); - - /** - * clear the interrupt before complete() is called, as complete can - * schedule new read/writes which require interrupts, clearing the - * interrupt would avoid missing interrupts in such cases. - */ - ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts); - - if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) { - spin_lock_irqsave(&ctrl->comp_lock, flags); - if (ctrl->comp) - complete(ctrl->comp); - spin_unlock_irqrestore(&ctrl->comp_lock, flags); - } + complete(&ctrl->enumeration); + return 0; +} + +static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) +{ + struct qcom_swrm_ctrl *swrm = dev_id; + u32 value, intr_sts, intr_sts_masked, slave_status; + u32 i; + int devnum; + int ret = IRQ_HANDLED; + + swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); + intr_sts_masked = intr_sts & swrm->intr_mask; + + do { + for (i = 0; i < SWRM_INTERRUPT_MAX; i++) { + value = intr_sts_masked & BIT(i); + if (!value) + continue; + + switch (value) { + case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ: + devnum = qcom_swrm_get_alert_slave_dev_num(swrm); + if (devnum < 0) { + dev_err_ratelimited(swrm->dev, + "no slave alert found.spurious interrupt\n"); + } else { + sdw_handle_slave_status(&swrm->bus, swrm->status); + } - return IRQ_HANDLED; + break; + case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED: + case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS: + dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n", + __func__); + swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status); + if (swrm->slave_status == slave_status) { + dev_err(swrm->dev, "Slave status not changed %x\n", + slave_status); + } else { + qcom_swrm_get_device_status(swrm); + qcom_swrm_enumerate(&swrm->bus); + sdw_handle_slave_status(&swrm->bus, swrm->status); + } + break; + case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET: + dev_err_ratelimited(swrm->dev, + "%s: SWR bus clsh detected\n", + __func__); + swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET; + swrm->reg_write(swrm, SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); + break; + case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err_ratelimited(swrm->dev, + "%s: SWR read FIFO overflow fifo status 0x%x\n", + __func__, value); + break; + case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err_ratelimited(swrm->dev, + "%s: SWR read FIFO underflow fifo status 0x%x\n", + __func__, value); + break; + case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err(swrm->dev, + "%s: SWR write FIFO overflow fifo status %x\n", + __func__, value); + swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); + break; + case SWRM_INTERRUPT_STATUS_CMD_ERROR: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err_ratelimited(swrm->dev, + "%s: SWR CMD error, fifo status 0x%x, flushing fifo\n", + __func__, value); + swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); + break; + case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION: + dev_err_ratelimited(swrm->dev, + "%s: SWR Port collision detected\n", + __func__); + swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION; + swrm->reg_write(swrm, + SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); + break; + case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH: + dev_err_ratelimited(swrm->dev, + "%s: SWR read enable valid mismatch\n", + __func__); + swrm->intr_mask &= + ~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH; + swrm->reg_write(swrm, + SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); + break; + case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED: + complete(&swrm->broadcast); + break; + case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2: + break; + case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2: + break; + case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP: + break; + default: + dev_err_ratelimited(swrm->dev, + "%s: SWR unknown interrupt value: %d\n", + __func__, value); + ret = IRQ_NONE; + break; + } + } + swrm->reg_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts); + swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); + intr_sts_masked = intr_sts & swrm->intr_mask; + } while (intr_sts_masked); + + return ret; } + static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) { u32 val; @@ -316,9 +612,10 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val); - /* Disable Auto enumeration */ - ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0); + /* Enable Auto enumeration */ + ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 1); + ctrl->intr_mask = SWRM_INTERRUPT_STATUS_RMSK; /* Mask soundwire interrupts */ ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, SWRM_INTERRUPT_STATUS_RMSK); @@ -328,8 +625,17 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK); ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); + ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START); /* Configure number of retries of a read/write cmd */ - ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES); + if (ctrl->version > 0x01050001) { + /* Only for versions >= 1.5.1 */ + ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, + SWRM_RD_WR_CMD_RETRIES | + SWRM_CONTINUE_EXEC_ON_CMD_IGNORE); + } else { + ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, + SWRM_RD_WR_CMD_RETRIES); + } /* Set IRQ to PULSE */ ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR, @@ -341,6 +647,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, SWRM_INTERRUPT_STATUS_RMSK); } + ctrl->slave_status = 0; + ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); + ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val); + ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); + return 0; } @@ -396,8 +707,11 @@ static int qcom_swrm_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params, unsigned int bank) { - /* TBD */ - return 0; + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + + return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num), + p_params->bps - 1); + } static int qcom_swrm_transport_params(struct sdw_bus *bus, @@ -405,22 +719,57 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, enum sdw_reg_bank bank) { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + struct qcom_swrm_port_config *pcfg; u32 value; int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); int ret; - value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; - value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; - value |= params->sample_interval - 1; + pcfg = &ctrl->pconfig[params->port_num]; + + value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; + value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; + value |= pcfg->si; ret = ctrl->reg_write(ctrl, reg, value); + if (ret) + goto err; - if (!ret && params->blk_pkg_mode) { - reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + if (pcfg->lane_control != SWR_INVALID_PARAM) { + reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); + value = pcfg->lane_control; + ret = ctrl->reg_write(ctrl, reg, value); + if (ret) + goto err; + } + + if (pcfg->blk_group_count != SWR_INVALID_PARAM) { + reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); + value = pcfg->blk_group_count; + ret = ctrl->reg_write(ctrl, reg, value); + if (ret) + goto err; + } + + if (pcfg->hstart != SWR_INVALID_PARAM + && pcfg->hstop != SWR_INVALID_PARAM) { + reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + value = (pcfg->hstop << 4) | pcfg->hstart; + ret = ctrl->reg_write(ctrl, reg, value); + } else { + reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; + ret = ctrl->reg_write(ctrl, reg, value); + } + + if (ret) + goto err; - ret = ctrl->reg_write(ctrl, reg, 1); + if (pcfg->bp_mode != SWR_INVALID_PARAM) { + reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); } +err: return ret; } @@ -460,27 +809,50 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) struct sdw_slave_runtime *s_rt; struct sdw_port_runtime *p_rt; struct qcom_swrm_port_config *pcfg; - int i = 0; + struct sdw_slave *slave; + unsigned int m_port; + int i = 1; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { list_for_each_entry(p_rt, &m_rt->port_list, port_node) { - pcfg = &ctrl->pconfig[p_rt->num - 1]; + pcfg = &ctrl->pconfig[p_rt->num]; p_rt->transport_params.port_num = p_rt->num; - p_rt->transport_params.sample_interval = pcfg->si + 1; - p_rt->transport_params.offset1 = pcfg->off1; - p_rt->transport_params.offset2 = pcfg->off2; - p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; + if (pcfg->word_length != SWR_INVALID_PARAM) { + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, pcfg->word_length + 1, + SDW_PORT_FLOW_MODE_ISOCH, + SDW_PORT_DATA_MODE_NORMAL); + } + } list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { + slave = s_rt->slave; list_for_each_entry(p_rt, &s_rt->port_list, port_node) { - pcfg = &ctrl->pconfig[i]; + m_port = slave->m_port_map[p_rt->num]; + /* port config starts at offset 0 so -1 from actual port number */ + if (m_port) + pcfg = &ctrl->pconfig[m_port]; + else + pcfg = &ctrl->pconfig[i]; p_rt->transport_params.port_num = p_rt->num; p_rt->transport_params.sample_interval = pcfg->si + 1; p_rt->transport_params.offset1 = pcfg->off1; p_rt->transport_params.offset2 = pcfg->off2; p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; + p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count; + + p_rt->transport_params.hstart = pcfg->hstart; + p_rt->transport_params.hstop = pcfg->hstop; + p_rt->transport_params.lane_ctrl = pcfg->lane_control; + if (pcfg->word_length != SWR_INVALID_PARAM) { + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, + pcfg->word_length + 1, + SDW_PORT_FLOW_MODE_ISOCH, + SDW_PORT_DATA_MODE_NORMAL); + } i++; } } @@ -493,16 +865,6 @@ static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = { DEFAULT_CLK_FREQ, }; -static void qcom_swrm_slave_wq(struct work_struct *work) -{ - struct qcom_swrm_ctrl *ctrl = - container_of(work, struct qcom_swrm_ctrl, slave_work); - - qcom_swrm_get_device_status(ctrl); - sdw_handle_slave_status(&ctrl->bus, ctrl->status); -} - - static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, struct sdw_stream_runtime *stream) { @@ -519,7 +881,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, port_mask = &ctrl->din_port_mask; list_for_each_entry(p_rt, &m_rt->port_list, port_node) - clear_bit(p_rt->num - 1, port_mask); + clear_bit(p_rt->num, port_mask); } mutex_unlock(&ctrl->port_lock); @@ -535,8 +897,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, struct sdw_master_runtime *m_rt; struct sdw_slave_runtime *s_rt; struct sdw_port_runtime *p_rt; + struct sdw_slave *slave; unsigned long *port_mask; int i, maxport, pn, nports = 0, ret = 0; + unsigned int m_port; mutex_lock(&ctrl->port_lock); list_for_each_entry(m_rt, &stream->master_list, stream_node) { @@ -549,16 +913,22 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, } list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { + slave = s_rt->slave; list_for_each_entry(p_rt, &s_rt->port_list, port_node) { + m_port = slave->m_port_map[p_rt->num]; /* Port numbers start from 1 - 14*/ - pn = find_first_zero_bit(port_mask, maxport); - if (pn > (maxport - 1)) { + if (m_port) + pn = m_port; + else + pn = find_first_zero_bit(port_mask, maxport); + + if (pn > maxport) { dev_err(ctrl->dev, "All ports busy\n"); ret = -EBUSY; goto err; } set_bit(pn, port_mask); - pconfig[nports].num = pn + 1; + pconfig[nports].num = pn; pconfig[nports].ch_mask = p_rt->ch_mask; nports++; } @@ -580,7 +950,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, err: if (ret) { for (i = 0; i < nports; i++) - clear_bit(pconfig[i].num - 1, port_mask); + clear_bit(pconfig[i].num, port_mask); } mutex_unlock(&ctrl->port_lock); @@ -652,7 +1022,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime, substream->stream); if (ret < 0 && ret != -ENOTSUPP) { - dev_err(dai->dev, "Failed to set sdw stream on %s", + dev_err(dai->dev, "Failed to set sdw stream on %s\n", codec_dai->name); sdw_release_stream(sruntime); return ret; @@ -728,6 +1098,11 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) u8 off2[QCOM_SDW_MAX_PORTS]; u8 si[QCOM_SDW_MAX_PORTS]; u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; + u8 hstart[QCOM_SDW_MAX_PORTS]; + u8 hstop[QCOM_SDW_MAX_PORTS]; + u8 word_length[QCOM_SDW_MAX_PORTS]; + u8 blk_group_count[QCOM_SDW_MAX_PORTS]; + u8 lane_control[QCOM_SDW_MAX_PORTS]; int i, ret, nports, val; ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); @@ -754,6 +1129,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ctrl->num_dout_ports = val; nports = ctrl->num_dout_ports + ctrl->num_din_ports; + /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ + set_bit(0, &ctrl->dout_port_mask); + set_bit(0, &ctrl->din_port_mask); ret = of_property_read_u8_array(np, "qcom,ports-offset1", off1, nports); @@ -772,11 +1150,35 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", bp_mode, nports); + if (ret) + return ret; + + memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); + + memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); + + memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); + + memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports); + + memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); + for (i = 0; i < nports; i++) { - ctrl->pconfig[i].si = si[i]; - ctrl->pconfig[i].off1 = off1[i]; - ctrl->pconfig[i].off2 = off2[i]; - ctrl->pconfig[i].bp_mode = bp_mode[i]; + /* Valid port number range is from 1-14 */ + ctrl->pconfig[i + 1].si = si[i]; + ctrl->pconfig[i + 1].off1 = off1[i]; + ctrl->pconfig[i + 1].off2 = off2[i]; + ctrl->pconfig[i + 1].bp_mode = bp_mode[i]; + ctrl->pconfig[i + 1].hstart = hstart[i]; + ctrl->pconfig[i + 1].hstop = hstop[i]; + ctrl->pconfig[i + 1].word_length = word_length[i]; + ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i]; + ctrl->pconfig[i + 1].lane_control = lane_control[i]; } return 0; @@ -833,9 +1235,9 @@ static int qcom_swrm_probe(struct platform_device *pdev) ctrl->dev = dev; dev_set_drvdata(&pdev->dev, ctrl); - spin_lock_init(&ctrl->comp_lock); mutex_init(&ctrl->port_lock); - INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq); + init_completion(&ctrl->broadcast); + init_completion(&ctrl->enumeration); ctrl->bus.ops = &qcom_swrm_ops; ctrl->bus.port_ops = &qcom_swrm_port_ops; @@ -882,6 +1284,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) } qcom_swrm_init(ctrl); + wait_for_completion_timeout(&ctrl->enumeration, + msecs_to_jiffies(TIMEOUT_MS)); ret = qcom_swrm_register_dais(ctrl); if (ret) goto err_master_add; diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 180f38bd003bcacd622af7b50c4a89dc8c213a13..0eed38a79c6dd1a01d95bb50e556a42018784ac9 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -88,6 +88,7 @@ int sdw_slave_add(struct sdw_bus *bus, return ret; } +EXPORT_SYMBOL(sdw_slave_add); #if IS_ENABLED(CONFIG_ACPI) @@ -95,7 +96,7 @@ static bool find_slave(struct sdw_bus *bus, struct acpi_device *adev, struct sdw_slave_id *id) { - unsigned long long addr; + u64 addr; unsigned int link_id; acpi_status status; @@ -108,6 +109,12 @@ static bool find_slave(struct sdw_bus *bus, return false; } + if (bus->ops->override_adr) + addr = bus->ops->override_adr(bus, addr); + + if (!addr) + return false; + /* Extract link id from ADR, Bit 51 to 48 (included) */ link_id = SDW_DISCO_LINK_ID(addr); diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 1099b5d1262be6cdfb66e1dc5a7ffddacc884aa9..1eaedaaba09441cc5086d424463e1fae0014d226 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -261,7 +261,7 @@ static int sdw_program_master_port_params(struct sdw_bus *bus, */ static int sdw_program_port_params(struct sdw_master_runtime *m_rt) { - struct sdw_slave_runtime *s_rt = NULL; + struct sdw_slave_runtime *s_rt; struct sdw_bus *bus = m_rt->bus; struct sdw_port_runtime *p_rt; int ret = 0; @@ -1375,8 +1375,16 @@ int sdw_stream_add_slave(struct sdw_slave *slave, } ret = sdw_config_stream(&slave->dev, stream, stream_config, true); - if (ret) + if (ret) { + /* + * sdw_release_master_stream will release s_rt in slave_rt_list in + * stream_error case, but s_rt is only added to slave_rt_list + * when sdw_config_stream is successful, so free s_rt explicitly + * when sdw_config_stream is failed. + */ + kfree(s_rt); goto stream_error; + } list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); @@ -1449,7 +1457,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) { struct sdw_master_runtime *m_rt; - struct sdw_bus *bus = NULL; + struct sdw_bus *bus; /* Iterate for all Master(s) in Master list */ list_for_each_entry(m_rt, &stream->master_list, stream_node) { @@ -1470,8 +1478,8 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) */ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = NULL; - struct sdw_bus *bus = NULL; + struct sdw_master_runtime *m_rt; + struct sdw_bus *bus; /* Iterate for all Master(s) in Master list */ list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) { @@ -1513,7 +1521,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, if (bus->compute_params) { ret = bus->compute_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute params failed: %d", + dev_err(bus->dev, "Compute params failed: %d\n", ret); return ret; } @@ -1791,7 +1799,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) if (bus->compute_params) { ret = bus->compute_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute params failed: %d", + dev_err(bus->dev, "Compute params failed: %d\n", ret); return ret; } @@ -1855,7 +1863,7 @@ static int set_stream(struct snd_pcm_substream *substream, for_each_rtd_dais(rtd, i, dai) { ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream); if (ret < 0) { - dev_err(rtd->dev, "failed to set stream pointer on dai %s", dai->name); + dev_err(rtd->dev, "failed to set stream pointer on dai %s\n", dai->name); break; } } @@ -1888,7 +1896,7 @@ int sdw_startup_stream(void *sdw_substream) sdw_stream = sdw_alloc_stream(name); if (!sdw_stream) { - dev_err(rtd->dev, "alloc stream failed for substream DAI %s", substream->name); + dev_err(rtd->dev, "alloc stream failed for substream DAI %s\n", substream->name); ret = -ENOMEM; goto error; } @@ -1927,7 +1935,7 @@ void sdw_shutdown_stream(void *sdw_substream) sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return; } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 09a263cf4ae2ed2d5c47b617f3288bc1db42ede7..8b161ec4943bfe05d4b406c7eb96bd04c6273100 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -58,11 +58,27 @@ config SPI_MEM comment "SPI Master Controller Drivers" config SPI_ALTERA - tristate "Altera SPI Controller" + tristate "Altera SPI Controller platform driver" + select SPI_ALTERA_CORE select REGMAP_MMIO help This is the driver for the Altera SPI Controller. +config SPI_ALTERA_CORE + tristate "Altera SPI Controller core code" + select REGMAP + help + "The core code for the Altera SPI Controller" + +config SPI_ALTERA_DFL + tristate "DFL bus driver for Altera SPI Controller" + depends on FPGA_DFL + select SPI_ALTERA_CORE + help + This is a Device Feature List (DFL) bus driver for the + Altera SPI master controller. The SPI master is connected + to a SPI slave to Avalon bridge in a Intel MAX BMC. + config SPI_AR934X tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver" depends on ATH79 || COMPILE_TEST @@ -332,6 +348,16 @@ config SPI_FSL_QUADSPI This controller does not support generic SPI messages. It only supports the high-level SPI memory interface. +config SPI_HISI_KUNPENG + tristate "HiSilicon SPI Controller for Kunpeng SoCs" + depends on (ARM64 && ACPI) || COMPILE_TEST + help + This enables support for HiSilicon SPI controller found on + Kunpeng SoCs. + + This driver can also be built as a module. If so, the module + will be called hisi-kunpeng-spi. + config SPI_HISI_SFC_V3XX tristate "HiSilicon SPI NOR Flash Controller for Hi16XX chipsets" depends on (ARM64 && ACPI) || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 0f06fc0813c616b22acbe53b21f16a1053aa34f8..13e54c45e9df07e201e26fc35672ac92a0250dc5 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -14,7 +14,9 @@ obj-$(CONFIG_SPI_SPIDEV) += spidev.o obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o # SPI master controller drivers (bus) -obj-$(CONFIG_SPI_ALTERA) += spi-altera.o +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_AR934X) += spi-ar934x.o obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o @@ -53,6 +55,7 @@ obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-qspi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o +obj-$(CONFIG_SPI_HISI_KUNPENG) += spi-hisi-kunpeng.o obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMX) += spi-imx.o diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera-core.c similarity index 56% rename from drivers/spi/spi-altera.c rename to drivers/spi/spi-altera-core.c index 62ea0c9e321b4c1e7e095ed6f70091ae775c5e5b..de4d31c530d90019125475b7484dd4f77c49cdac 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera-core.c @@ -10,7 +10,6 @@ * Ben Dooks <ben@simtec.co.uk> */ -#include <linux/interrupt.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -41,36 +40,6 @@ #define ALTERA_SPI_CONTROL_IE_MSK 0x100 #define ALTERA_SPI_CONTROL_SSO_MSK 0x400 -#define ALTERA_SPI_MAX_CS 32 - -enum altera_spi_type { - ALTERA_SPI_TYPE_UNKNOWN, - ALTERA_SPI_TYPE_SUBDEV, -}; - -struct altera_spi { - int irq; - int len; - int count; - int bytes_per_word; - u32 imr; - - /* data buffers */ - const unsigned char *tx; - unsigned char *rx; - - struct regmap *regmap; - u32 regoff; - struct device *dev; -}; - -static const struct regmap_config spi_altera_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .fast_io = true, -}; - static int altr_spi_writel(struct altera_spi *hw, unsigned int reg, unsigned int val) { @@ -211,7 +180,7 @@ static int altera_spi_txrx(struct spi_master *master, return 0; } -static irqreturn_t altera_spi_irq(int irq, void *dev) +irqreturn_t altera_spi_irq(int irq, void *dev) { struct spi_master *master = dev; struct altera_spi *hw = spi_master_get_devdata(master); @@ -230,84 +199,16 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(altera_spi_irq); -static int altera_spi_probe(struct platform_device *pdev) +void altera_spi_init_master(struct spi_master *master) { - const struct platform_device_id *platid = platform_get_device_id(pdev); - struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev); - enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN; - struct altera_spi *hw; - struct spi_master *master; - int err = -ENODEV; + struct altera_spi *hw = spi_master_get_devdata(master); u32 val; - u16 i; - - master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi)); - if (!master) - return err; - - /* setup the master state. */ - master->bus_num = pdev->id; - - if (pdata) { - if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) { - dev_err(&pdev->dev, - "Invalid number of chipselect: %hu\n", - pdata->num_chipselect); - err = -EINVAL; - goto exit; - } - master->num_chipselect = pdata->num_chipselect; - master->mode_bits = pdata->mode_bits; - master->bits_per_word_mask = pdata->bits_per_word_mask; - } else { - master->num_chipselect = 16; - master->mode_bits = SPI_CS_HIGH; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); - } - - master->dev.of_node = pdev->dev.of_node; master->transfer_one = altera_spi_txrx; master->set_cs = altera_spi_set_cs; - hw = spi_master_get_devdata(master); - hw->dev = &pdev->dev; - - if (platid) - type = platid->driver_data; - - /* find and map our resources */ - if (type == ALTERA_SPI_TYPE_SUBDEV) { - struct resource *regoff; - - hw->regmap = dev_get_regmap(pdev->dev.parent, NULL); - if (!hw->regmap) { - dev_err(&pdev->dev, "get regmap failed\n"); - goto exit; - } - - regoff = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (regoff) - hw->regoff = regoff->start; - } else { - void __iomem *res; - - res = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(res)) { - err = PTR_ERR(res); - goto exit; - } - - hw->regmap = devm_regmap_init_mmio(&pdev->dev, res, - &spi_altera_config); - if (IS_ERR(hw->regmap)) { - dev_err(&pdev->dev, "regmap mmio init failed\n"); - err = PTR_ERR(hw->regmap); - goto exit; - } - } - /* program defaults into the registers */ hw->imr = 0; /* disable spi interrupts */ altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); @@ -315,64 +216,7 @@ static int altera_spi_probe(struct platform_device *pdev) altr_spi_readl(hw, ALTERA_SPI_STATUS, &val); if (val & ALTERA_SPI_STATUS_RRDY_MSK) altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */ - /* irq is optional */ - hw->irq = platform_get_irq(pdev, 0); - if (hw->irq >= 0) { - err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0, - pdev->name, master); - if (err) - goto exit; - } - - err = devm_spi_register_master(&pdev->dev, master); - if (err) - goto exit; - - if (pdata) { - for (i = 0; i < pdata->num_devices; i++) { - if (!spi_new_device(master, pdata->devices + i)) - dev_warn(&pdev->dev, - "unable to create SPI device: %s\n", - pdata->devices[i].modalias); - } - } - - dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq); - - return 0; -exit: - spi_master_put(master); - return err; } +EXPORT_SYMBOL_GPL(altera_spi_init_master); -#ifdef CONFIG_OF -static const struct of_device_id altera_spi_match[] = { - { .compatible = "ALTR,spi-1.0", }, - { .compatible = "altr,spi-1.0", }, - {}, -}; -MODULE_DEVICE_TABLE(of, altera_spi_match); -#endif /* CONFIG_OF */ - -static const struct platform_device_id altera_spi_ids[] = { - { DRV_NAME, ALTERA_SPI_TYPE_UNKNOWN }, - { "subdev_spi_altera", ALTERA_SPI_TYPE_SUBDEV }, - { } -}; -MODULE_DEVICE_TABLE(platform, altera_spi_ids); - -static struct platform_driver altera_spi_driver = { - .probe = altera_spi_probe, - .driver = { - .name = DRV_NAME, - .pm = NULL, - .of_match_table = of_match_ptr(altera_spi_match), - }, - .id_table = altera_spi_ids, -}; -module_platform_driver(altera_spi_driver); - -MODULE_DESCRIPTION("Altera SPI driver"); -MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c new file mode 100644 index 0000000000000000000000000000000000000000..3e32e4fe589503193cc9925fa8b1b6c853e1cafe --- /dev/null +++ b/drivers/spi/spi-altera-dfl.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// DFL bus driver for Altera SPI Master +// +// Copyright (C) 2020 Intel Corporation, Inc. +// +// Authors: +// Matthew Gerlach <matthew.gerlach@linux.intel.com> +// + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/stddef.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/bitfield.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/spi/altera.h> +#include <linux/dfl.h> + +#define FME_FEATURE_ID_MAX10_SPI 0xe +#define FME_FEATURE_REV_MAX10_SPI_N5010 0x1 + +#define SPI_CORE_PARAMETER 0x8 +#define SHIFT_MODE BIT_ULL(1) +#define SHIFT_MODE_MSB 0 +#define SHIFT_MODE_LSB 1 +#define DATA_WIDTH GENMASK_ULL(7, 2) +#define NUM_CHIPSELECT GENMASK_ULL(13, 8) +#define CLK_POLARITY BIT_ULL(14) +#define CLK_PHASE BIT_ULL(15) +#define PERIPHERAL_ID GENMASK_ULL(47, 32) +#define SPI_CLK GENMASK_ULL(31, 22) +#define SPI_INDIRECT_ACC_OFST 0x10 + +#define INDIRECT_ADDR (SPI_INDIRECT_ACC_OFST+0x0) +#define INDIRECT_WR BIT_ULL(8) +#define INDIRECT_RD BIT_ULL(9) +#define INDIRECT_RD_DATA (SPI_INDIRECT_ACC_OFST+0x8) +#define INDIRECT_DATA_MASK GENMASK_ULL(31, 0) +#define INDIRECT_DEBUG BIT_ULL(32) +#define INDIRECT_WR_DATA (SPI_INDIRECT_ACC_OFST+0x10) +#define INDIRECT_TIMEOUT 10000 + +static int indirect_bus_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + void __iomem *base = context; + int loops; + u64 v; + + writeq((reg >> 2) | INDIRECT_RD, base + INDIRECT_ADDR); + + loops = 0; + while ((readq(base + INDIRECT_ADDR) & INDIRECT_RD) && + (loops++ < INDIRECT_TIMEOUT)) + cpu_relax(); + + if (loops >= INDIRECT_TIMEOUT) { + pr_err("%s timed out %d\n", __func__, loops); + return -ETIME; + } + + v = readq(base + INDIRECT_RD_DATA); + + *val = v & INDIRECT_DATA_MASK; + + return 0; +} + +static int indirect_bus_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + void __iomem *base = context; + int loops; + + writeq(val, base + INDIRECT_WR_DATA); + writeq((reg >> 2) | INDIRECT_WR, base + INDIRECT_ADDR); + + loops = 0; + while ((readq(base + INDIRECT_ADDR) & INDIRECT_WR) && + (loops++ < INDIRECT_TIMEOUT)) + cpu_relax(); + + if (loops >= INDIRECT_TIMEOUT) { + pr_err("%s timed out %d\n", __func__, loops); + return -ETIME; + } + return 0; +} + +static const struct regmap_config indirect_regbus_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + .max_register = 24, + + .reg_write = indirect_bus_reg_write, + .reg_read = indirect_bus_reg_read, +}; + +static struct spi_board_info m10_bmc_info = { + .modalias = "m10-d5005", + .max_speed_hz = 12500000, + .bus_num = 0, + .chip_select = 0, +}; + +static void config_spi_master(void __iomem *base, struct spi_master *master) +{ + u64 v; + + v = readq(base + SPI_CORE_PARAMETER); + + master->mode_bits = SPI_CS_HIGH; + if (FIELD_GET(CLK_POLARITY, v)) + master->mode_bits |= SPI_CPOL; + if (FIELD_GET(CLK_PHASE, v)) + master->mode_bits |= SPI_CPHA; + + master->num_chipselect = FIELD_GET(NUM_CHIPSELECT, v); + master->bits_per_word_mask = + SPI_BPW_RANGE_MASK(1, FIELD_GET(DATA_WIDTH, v)); +} + +static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) +{ + struct device *dev = &dfl_dev->dev; + struct spi_master *master; + struct altera_spi *hw; + void __iomem *base; + int err = -ENODEV; + + master = spi_alloc_master(dev, sizeof(struct altera_spi)); + if (!master) + return -ENOMEM; + + master->bus_num = dfl_dev->id; + + hw = spi_master_get_devdata(master); + + hw->dev = dev; + + base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); + + if (IS_ERR(base)) { + dev_err(dev, "%s get mem resource fail!\n", __func__); + return PTR_ERR(base); + } + + config_spi_master(base, master); + dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__, + master->num_chipselect, master->bits_per_word_mask, + master->mode_bits); + + hw->regmap = devm_regmap_init(dev, NULL, base, &indirect_regbus_cfg); + if (IS_ERR(hw->regmap)) + return PTR_ERR(hw->regmap); + + hw->irq = -EINVAL; + + altera_spi_init_master(master); + + err = devm_spi_register_master(dev, master); + if (err) { + dev_err(dev, "%s failed to register spi master %d\n", __func__, err); + goto exit; + } + + if (!spi_new_device(master, &m10_bmc_info)) { + dev_err(dev, "%s failed to create SPI device: %s\n", + __func__, m10_bmc_info.modalias); + } + + return 0; +exit: + spi_master_put(master); + return err; +} + +static const struct dfl_device_id dfl_spi_altera_ids[] = { + { FME_ID, FME_FEATURE_ID_MAX10_SPI }, + { } +}; + +static struct dfl_driver dfl_spi_altera_driver = { + .drv = { + .name = "dfl-spi-altera", + }, + .id_table = dfl_spi_altera_ids, + .probe = dfl_spi_altera_probe, +}; + +module_dfl_driver(dfl_spi_altera_driver); + +MODULE_DEVICE_TABLE(dfl, dfl_spi_altera_ids); +MODULE_DESCRIPTION("DFL spi altera driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c new file mode 100644 index 0000000000000000000000000000000000000000..f7a7c14e36790eeeb9247caccfa678d63a25403f --- /dev/null +++ b/drivers/spi/spi-altera-platform.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Altera SPI driver + * + * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw> + * + * Based on spi_s3c24xx.c, which is: + * Copyright (c) 2006 Ben Dooks + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + */ + +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spi/altera.h> +#include <linux/spi/spi.h> +#include <linux/io.h> +#include <linux/of.h> + +#define DRV_NAME "spi_altera" + +enum altera_spi_type { + ALTERA_SPI_TYPE_UNKNOWN, + ALTERA_SPI_TYPE_SUBDEV, +}; + +static const struct regmap_config spi_altera_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, +}; + +static int altera_spi_probe(struct platform_device *pdev) +{ + const struct platform_device_id *platid = platform_get_device_id(pdev); + struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev); + enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN; + struct altera_spi *hw; + struct spi_master *master; + int err = -ENODEV; + u16 i; + + master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi)); + if (!master) + return err; + + /* setup the master state. */ + master->bus_num = pdev->id; + + if (pdata) { + if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) { + dev_err(&pdev->dev, + "Invalid number of chipselect: %u\n", + pdata->num_chipselect); + err = -EINVAL; + goto exit; + } + + master->num_chipselect = pdata->num_chipselect; + master->mode_bits = pdata->mode_bits; + master->bits_per_word_mask = pdata->bits_per_word_mask; + } else { + master->num_chipselect = 16; + master->mode_bits = SPI_CS_HIGH; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + } + + master->dev.of_node = pdev->dev.of_node; + + hw = spi_master_get_devdata(master); + hw->dev = &pdev->dev; + + if (platid) + type = platid->driver_data; + + /* find and map our resources */ + if (type == ALTERA_SPI_TYPE_SUBDEV) { + struct resource *regoff; + + hw->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!hw->regmap) { + dev_err(&pdev->dev, "get regmap failed\n"); + goto exit; + } + + regoff = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (regoff) + hw->regoff = regoff->start; + } else { + void __iomem *res; + + res = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(res)) { + err = PTR_ERR(res); + goto exit; + } + + hw->regmap = devm_regmap_init_mmio(&pdev->dev, res, + &spi_altera_config); + if (IS_ERR(hw->regmap)) { + dev_err(&pdev->dev, "regmap mmio init failed\n"); + err = PTR_ERR(hw->regmap); + goto exit; + } + } + + altera_spi_init_master(master); + + /* irq is optional */ + hw->irq = platform_get_irq(pdev, 0); + if (hw->irq >= 0) { + err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0, + pdev->name, master); + if (err) + goto exit; + } + + err = devm_spi_register_master(&pdev->dev, master); + if (err) + goto exit; + + if (pdata) { + for (i = 0; i < pdata->num_devices; i++) { + if (!spi_new_device(master, pdata->devices + i)) + dev_warn(&pdev->dev, + "unable to create SPI device: %s\n", + pdata->devices[i].modalias); + } + } + + dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq); + + return 0; +exit: + spi_master_put(master); + return err; +} + +#ifdef CONFIG_OF +static const struct of_device_id altera_spi_match[] = { + { .compatible = "ALTR,spi-1.0", }, + { .compatible = "altr,spi-1.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, altera_spi_match); +#endif /* CONFIG_OF */ + +static const struct platform_device_id altera_spi_ids[] = { + { DRV_NAME, ALTERA_SPI_TYPE_UNKNOWN }, + { "subdev_spi_altera", ALTERA_SPI_TYPE_SUBDEV }, + { } +}; +MODULE_DEVICE_TABLE(platform, altera_spi_ids); + +static struct platform_driver altera_spi_driver = { + .probe = altera_spi_probe, + .driver = { + .name = DRV_NAME, + .pm = NULL, + .of_match_table = of_match_ptr(altera_spi_match), + }, + .id_table = altera_spi_ids, +}; +module_platform_driver(altera_spi_driver); + +MODULE_DESCRIPTION("Altera SPI driver"); +MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index eb9a243e95265c3fb0c4780ebbbf7bbc6a65a53b..98ace748cd986af7ec3d038b9b8f5ca7da64ecf7 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -156,8 +156,7 @@ static int ath79_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); - master->setup = spi_bitbang_setup; - master->cleanup = spi_bitbang_cleanup; + master->flags = SPI_MASTER_GPIO_SS; if (pdata) { master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index f429436082afae7ceae481bf04c10b447e851f66..7cd5fe00dfc1130f12bb2155f2d46f744ddad799 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -506,10 +506,6 @@ static int atmel_spi_configure_dma(struct spi_master *master, struct device *dev = &as->pdev->dev; int err; - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { err = PTR_ERR(master->dma_tx); diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index af86e6d6e16b9b9ce17466e2b86c045eabccf07f..80c3e38f5c1b52483866d161fdbc3d37c7792717 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -170,14 +170,10 @@ static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry, unsigned int t; int delay; - if (xfer->delay_usecs) { - delay = xfer->delay_usecs; - } else { - delay = spi_delay_to_ns(&xfer->delay, xfer); - if (delay < 0) - return; - delay /= 1000; - } + delay = spi_delay_to_ns(&xfer->delay, xfer); + if (delay < 0) + return; + delay /= 1000; if (delay == 0) return; diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 707fe3a5d8effcd04cbc54d1c82d7eb5dd3ba804..a78e56f566dd8933169fa6615bc3d6cb61a33305 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -671,7 +671,7 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, if (qt->byte >= qt->trans->len) { /* we're at the end of the spi_transfer */ /* in TX mode, need to pause for a delay or CS change */ - if (qt->trans->delay_usecs && + if (qt->trans->delay.value && (flags & TRANS_STATUS_BREAK_DELAY)) ret |= TRANS_STATUS_BREAK_DELAY; if (qt->trans->cs_change && diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 1f08d7553f079c29c8995ce4a0517d313f85d50f..b871fd810d8015d15ce50b4da7e299c1132df807 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -21,6 +21,7 @@ #include <linux/mutex.h> #include <linux/of.h> #include <linux/reset.h> +#include <linux/pm_runtime.h> #define HSSPI_GLOBAL_CTRL_REG 0x0 #define GLOBAL_CTRL_CS_POLARITY_SHIFT 0 @@ -439,13 +440,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) if (ret) goto out_put_master; + pm_runtime_enable(&pdev->dev); + /* register and we are done */ ret = devm_spi_register_master(dev, master); if (ret) - goto out_put_master; + goto out_pm_disable; return 0; +out_pm_disable: + pm_runtime_disable(&pdev->dev); out_put_master: spi_master_put(master); out_disable_pll_clk: diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 96d075e633f4320db621d174976ed431b90ff847..80fa0ef8909caabff1cf0c87acfc42a77f96b0c1 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -369,7 +369,7 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master, } /* CS will be deasserted directly after transfer */ - if (t->delay_usecs || t->delay.value) { + if (t->delay.value) { dev_err(&spi->dev, "unable to keep CS asserted after transfer\n"); status = -EINVAL; goto exit; @@ -593,11 +593,13 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); + pm_runtime_enable(&pdev->dev); + /* register and we are done */ ret = devm_spi_register_master(dev, master); if (ret) { dev_err(dev, "spi register failed\n"); - goto out_clk_disable; + goto out_pm_disable; } dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n", @@ -605,6 +607,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) return 0; +out_pm_disable: + pm_runtime_disable(&pdev->dev); out_clk_disable: clk_disable_unprepare(clk); out_err: diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 1a7352abd87860956d6f989eb638ad2c42a0003b..6a6af85aebfd800cecdd1edcab171a5a92992ada 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -60,7 +60,8 @@ static unsigned bitbang_txrx_8( unsigned ns, struct spi_transfer *t, unsigned flags -) { +) +{ unsigned bits = t->bits_per_word; unsigned count = t->len; const u8 *tx = t->tx_buf; @@ -88,7 +89,8 @@ static unsigned bitbang_txrx_16( unsigned ns, struct spi_transfer *t, unsigned flags -) { +) +{ unsigned bits = t->bits_per_word; unsigned count = t->len; const u16 *tx = t->tx_buf; @@ -116,7 +118,8 @@ static unsigned bitbang_txrx_32( unsigned ns, struct spi_transfer *t, unsigned flags -) { +) +{ unsigned bits = t->bits_per_word; unsigned count = t->len; const u32 *tx = t->tx_buf; diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 7e71a351f3b732fe628b72e6d6d5b1d15d56bbab..cceae816cebc21ef4cbed58b7b62e4ddd964db3f 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -317,18 +317,7 @@ static struct parport_driver butterfly_driver = { .detach = butterfly_detach, .devmodel = true, }; - -static int __init butterfly_init(void) -{ - return parport_register_driver(&butterfly_driver); -} -device_initcall(butterfly_init); - -static void __exit butterfly_exit(void) -{ - parport_unregister_driver(&butterfly_driver); -} -module_exit(butterfly_exit); +module_parport_driver(butterfly_driver); MODULE_DESCRIPTION("Parport Adapter driver for AVR Butterfly"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 52ddb3255d88c14dbcbc5a3da493171d5d81dad3..7a00346ff9b92b61ac18c9e2021bea580ba8cbad 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -264,7 +264,7 @@ static bool cqspi_is_idle(struct cqspi_st *cqspi) { u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); - return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB); + return reg & (1UL << CQSPI_REG_CONFIG_IDLE_LSB); } static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi) @@ -1389,11 +1389,13 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) ret = of_property_read_u32(np, "reg", &cs); if (ret) { dev_err(dev, "Couldn't determine chip select.\n"); + of_node_put(np); return ret; } if (cs >= CQSPI_MAX_CHIPSELECT) { dev_err(dev, "Chip select %d out of range.\n", cs); + of_node_put(np); return -EINVAL; } @@ -1402,8 +1404,10 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) f_pdata->cs = cs; ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np); - if (ret) + if (ret) { + of_node_put(np); return ret; + } } return 0; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 7453a1dbbc0614a089f0f3e687a41be34b904502..e114e6fe5ea5b4029324186cd6b1b17ddae45669 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -817,18 +817,13 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, struct davinci_spi *dspi) { struct device_node *node = pdev->dev.of_node; - struct davinci_spi_of_data *spi_data; + const struct davinci_spi_of_data *spi_data; struct davinci_spi_platform_data *pdata; unsigned int num_cs, intr_line = 0; - const struct of_device_id *match; pdata = &dspi->pdata; - match = of_match_device(davinci_spi_of_match, &pdev->dev); - if (!match) - return -ENODEV; - - spi_data = (struct davinci_spi_of_data *)match->data; + spi_data = device_get_match_data(&pdev->dev); pdata->version = spi_data->version; pdata->prescaler_limit = spi_data->prescaler_limit; diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c index 75b33d7d14b0460c2540e2a69506eda2dc39091c..3ff63ab82f4fbc2d3cc5cafd20f140efb319eff7 100644 --- a/drivers/spi/spi-dln2.c +++ b/drivers/spi/spi-dln2.c @@ -543,7 +543,8 @@ static int dln2_spi_read_write_one(struct dln2_spi *dln2, const u8 *tx_data, * single ones due to device buffer constraints. */ static int dln2_spi_rdwr(struct dln2_spi *dln2, const u8 *tx_data, - u8 *rx_data, u16 data_len, u8 attr) { + u8 *rx_data, u16 data_len, u8 attr) +{ int ret; u16 len; u8 temp_attr; @@ -780,7 +781,7 @@ exit_free_master: static int dln2_spi_remove(struct platform_device *pdev) { - struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct spi_master *master = platform_get_drvdata(pdev); struct dln2_spi *dln2 = spi_master_get_devdata(master); pm_runtime_disable(&pdev->dev); diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index d3336a63f462dcd0da856d206a1db37639883f71..a7d4dffac66b25a90fbdc85dc102c1f61a35b082 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -377,7 +377,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master, m->actual_length += t->len; - WARN_ON(t->delay_usecs || t->delay.value || t->cs_change); + WARN_ON(t->delay.value || t->cs_change); spi_flags = 0; } diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 3920cd3286d8a7d24c2430b9ec5e3c52f734c822..87f8829c399521cb5c83d953fe44b9c2b1f3b816 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -26,7 +26,7 @@ #define SPI_FSI_BASE 0x70000 #define SPI_FSI_INIT_TIMEOUT_MS 1000 #define SPI_FSI_MAX_XFR_SIZE 2048 -#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED 32 +#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED 8 #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG 0x1 @@ -265,14 +265,12 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, struct fsi_spi_sequence *seq, struct spi_transfer *transfer) { - bool docfg = false; int loops; int idx; int rc; u8 val = 0; u8 len = min(transfer->len, 8U); u8 rem = transfer->len % len; - u64 cfg = 0ULL; loops = transfer->len / len; @@ -292,28 +290,17 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, return -EINVAL; } - if (ctx->restricted) { - const int eidx = rem ? 5 : 6; - - while (loops > 1 && idx <= eidx) { - idx = fsi_spi_sequence_add(seq, val); - loops--; - docfg = true; - } - - if (loops > 1) { - dev_warn(ctx->dev, "No sequencer slots; aborting.\n"); - return -EINVAL; - } + if (ctx->restricted && loops > 1) { + dev_warn(ctx->dev, + "Transfer too large; no branches permitted.\n"); + return -EINVAL; } if (loops > 1) { + u64 cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); + fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - docfg = true; - } - if (docfg) { - cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); if (transfer->rx_buf) cfg |= SPI_FSI_COUNTER_CFG_N2_RX | SPI_FSI_COUNTER_CFG_N2_TX | @@ -579,8 +566,10 @@ static int fsi_spi_probe(struct device *dev) continue; ctlr = spi_alloc_master(dev, sizeof(*ctx)); - if (!ctlr) + if (!ctlr) { + of_node_put(np); break; + } ctlr->dev.of_node = np; ctlr->num_chipselect = of_get_available_child_count(np) ?: 1; diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index cf2b947c600eb5988a2d1333f14a68f101a8dd47..f7066bef7b06fbb57ae57d1d9d71b6a465af99db 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -435,8 +435,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { - unsigned int delay_usecs = 0, rx_nbits = 0; - unsigned int delay_nsecs = 0, delay_nsecs1 = 0; + unsigned int rx_nbits = 0, delay_nsecs = 0; struct spi_transfer *t, trans = {}; int ret; @@ -445,16 +444,10 @@ static int fsl_espi_do_one_msg(struct spi_master *master, goto out; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->delay_usecs) { - if (t->delay_usecs > delay_usecs) { - delay_usecs = t->delay_usecs; - delay_nsecs = delay_usecs * 1000; - } - } else { - delay_nsecs1 = spi_delay_to_ns(&t->delay, t); - if (delay_nsecs1 > delay_nsecs) - delay_nsecs = delay_nsecs1; - } + unsigned int delay = spi_delay_to_ns(&t->delay, t); + + if (delay > delay_nsecs) + delay_nsecs = delay; if (t->rx_nbits > rx_nbits) rx_nbits = t->rx_nbits; } diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index a2886ee44e4cb38569ab917248f3b8f53f86fb87..5d98611dd999d19b0cd10facd8501e05c8090944 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -200,7 +200,7 @@ static int lpspi_prepare_xfer_hardware(struct spi_controller *controller) spi_controller_get_devdata(controller); int ret; - ret = pm_runtime_get_sync(fsl_lpspi->dev); + ret = pm_runtime_resume_and_get(fsl_lpspi->dev); if (ret < 0) { dev_err(fsl_lpspi->dev, "failed to enable clock\n"); return ret; diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index e4a8d203f94081a60bf9b06f1eacaa07e729410c..d0e5aa18b7bad7f156b2018aa383df30e4fb91cc 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -707,6 +707,11 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) struct resource mem; int irq, type; int ret; + bool spisel_boot = false; +#if IS_ENABLED(CONFIG_FSL_SOC) + struct mpc8xxx_spi_probe_info *pinfo = NULL; +#endif + ret = of_mpc8xxx_spi_probe(ofdev); if (ret) @@ -715,9 +720,8 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) type = fsl_spi_get_type(&ofdev->dev); if (type == TYPE_FSL) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); - bool spisel_boot = false; #if IS_ENABLED(CONFIG_FSL_SOC) - struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); + pinfo = to_of_pinfo(pdata); spisel_boot = of_property_read_bool(np, "fsl,spisel_boot"); if (spisel_boot) { @@ -746,15 +750,24 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) ret = of_address_to_resource(np, 0, &mem); if (ret) - return ret; + goto unmap_out; irq = platform_get_irq(ofdev, 0); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto unmap_out; + } master = fsl_spi_probe(dev, &mem, irq); return PTR_ERR_OR_ZERO(master); + +unmap_out: +#if IS_ENABLED(CONFIG_FSL_SOC) + if (spisel_boot) + iounmap(pinfo->immr_spi_cs); +#endif + return ret; } static int of_fsl_spi_remove(struct platform_device *ofdev) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 881f645661cc6137fd20cc7376e90b57e265a9f1..3d0d8ddd5772089051257060274b25b282fe55e0 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -691,14 +691,15 @@ static int spi_geni_probe(struct platform_device *pdev) mas->se.wrapper = dev_get_drvdata(dev->parent); mas->se.base = base; mas->se.clk = clk; - mas->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se"); - if (IS_ERR(mas->se.opp_table)) - return PTR_ERR(mas->se.opp_table); + + ret = devm_pm_opp_set_clkname(&pdev->dev, "se"); + if (ret) + return ret; /* OPP table is optional */ - ret = dev_pm_opp_of_add_table(&pdev->dev); + ret = devm_pm_opp_of_add_table(&pdev->dev); if (ret && ret != -ENODEV) { dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - goto put_clkname; + return ret; } spi->bus_num = -1; @@ -750,9 +751,6 @@ spi_geni_probe_free_irq: free_irq(mas->irq, spi); spi_geni_probe_runtime_disable: pm_runtime_disable(dev); - dev_pm_opp_of_remove_table(&pdev->dev); -put_clkname: - dev_pm_opp_put_clkname(mas->se.opp_table); return ret; } @@ -766,8 +764,6 @@ static int spi_geni_remove(struct platform_device *pdev) free_irq(mas->irq, spi); pm_runtime_disable(&pdev->dev); - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(mas->se.opp_table); return 0; } diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c new file mode 100644 index 0000000000000000000000000000000000000000..3f986ba1c328c5d7a6679198b7ac704ac66d2c20 --- /dev/null +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// HiSilicon SPI Controller Driver for Kunpeng SoCs +// +// Copyright (c) 2021 HiSilicon Technologies Co., Ltd. +// Author: Jay Fang <f.fangjian@huawei.com> +// +// This code is based on spi-dw-core.c. + +#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +/* Register offsets */ +#define HISI_SPI_CSCR 0x00 /* cs control register */ +#define HISI_SPI_CR 0x04 /* spi common control register */ +#define HISI_SPI_ENR 0x08 /* spi enable register */ +#define HISI_SPI_FIFOC 0x0c /* fifo level control register */ +#define HISI_SPI_IMR 0x10 /* interrupt mask register */ +#define HISI_SPI_DIN 0x14 /* data in register */ +#define HISI_SPI_DOUT 0x18 /* data out register */ +#define HISI_SPI_SR 0x1c /* status register */ +#define HISI_SPI_RISR 0x20 /* raw interrupt status register */ +#define HISI_SPI_ISR 0x24 /* interrupt status register */ +#define HISI_SPI_ICR 0x28 /* interrupt clear register */ +#define HISI_SPI_VERSION 0xe0 /* version register */ + +/* Bit fields in HISI_SPI_CR */ +#define CR_LOOP_MASK GENMASK(1, 1) +#define CR_CPOL_MASK GENMASK(2, 2) +#define CR_CPHA_MASK GENMASK(3, 3) +#define CR_DIV_PRE_MASK GENMASK(11, 4) +#define CR_DIV_POST_MASK GENMASK(19, 12) +#define CR_BPW_MASK GENMASK(24, 20) +#define CR_SPD_MODE_MASK GENMASK(25, 25) + +/* Bit fields in HISI_SPI_FIFOC */ +#define FIFOC_TX_MASK GENMASK(5, 3) +#define FIFOC_RX_MASK GENMASK(11, 9) + +/* Bit fields in HISI_SPI_IMR, 4 bits */ +#define IMR_RXOF BIT(0) /* Receive Overflow */ +#define IMR_RXTO BIT(1) /* Receive Timeout */ +#define IMR_RX BIT(2) /* Receive */ +#define IMR_TX BIT(3) /* Transmit */ +#define IMR_MASK (IMR_RXOF | IMR_RXTO | IMR_RX | IMR_TX) + +/* Bit fields in HISI_SPI_SR, 5 bits */ +#define SR_TXE BIT(0) /* Transmit FIFO empty */ +#define SR_TXNF BIT(1) /* Transmit FIFO not full */ +#define SR_RXNE BIT(2) /* Receive FIFO not empty */ +#define SR_RXF BIT(3) /* Receive FIFO full */ +#define SR_BUSY BIT(4) /* Busy Flag */ + +/* Bit fields in HISI_SPI_ISR, 4 bits */ +#define ISR_RXOF BIT(0) /* Receive Overflow */ +#define ISR_RXTO BIT(1) /* Receive Timeout */ +#define ISR_RX BIT(2) /* Receive */ +#define ISR_TX BIT(3) /* Transmit */ +#define ISR_MASK (ISR_RXOF | ISR_RXTO | ISR_RX | ISR_TX) + +/* Bit fields in HISI_SPI_ICR, 2 bits */ +#define ICR_RXOF BIT(0) /* Receive Overflow */ +#define ICR_RXTO BIT(1) /* Receive Timeout */ +#define ICR_MASK (ICR_RXOF | ICR_RXTO) + +#define DIV_POST_MAX 0xFF +#define DIV_POST_MIN 0x00 +#define DIV_PRE_MAX 0xFE +#define DIV_PRE_MIN 0x02 +#define CLK_DIV_MAX ((1 + DIV_POST_MAX) * DIV_PRE_MAX) +#define CLK_DIV_MIN ((1 + DIV_POST_MIN) * DIV_PRE_MIN) + +#define DEFAULT_NUM_CS 1 + +#define HISI_SPI_WAIT_TIMEOUT_MS 10UL + +enum hisi_spi_rx_level_trig { + HISI_SPI_RX_1, + HISI_SPI_RX_4, + HISI_SPI_RX_8, + HISI_SPI_RX_16, + HISI_SPI_RX_32, + HISI_SPI_RX_64, + HISI_SPI_RX_128 +}; + +enum hisi_spi_tx_level_trig { + HISI_SPI_TX_1_OR_LESS, + HISI_SPI_TX_4_OR_LESS, + HISI_SPI_TX_8_OR_LESS, + HISI_SPI_TX_16_OR_LESS, + HISI_SPI_TX_32_OR_LESS, + HISI_SPI_TX_64_OR_LESS, + HISI_SPI_TX_128_OR_LESS +}; + +enum hisi_spi_frame_n_bytes { + HISI_SPI_N_BYTES_NULL, + HISI_SPI_N_BYTES_U8, + HISI_SPI_N_BYTES_U16, + HISI_SPI_N_BYTES_U32 = 4 +}; + +/* Slave spi_dev related */ +struct hisi_chip_data { + u32 cr; + u32 speed_hz; /* baud rate */ + u16 clk_div; /* baud rate divider */ + + /* clk_div = (1 + div_post) * div_pre */ + u8 div_post; /* value from 0 to 255 */ + u8 div_pre; /* value from 2 to 254 (even only!) */ +}; + +struct hisi_spi { + struct device *dev; + + void __iomem *regs; + int irq; + u32 fifo_len; /* depth of the FIFO buffer */ + + /* Current message transfer state info */ + const void *tx; + unsigned int tx_len; + void *rx; + unsigned int rx_len; + u8 n_bytes; /* current is a 1/2/4 bytes op */ +}; + +static u32 hisi_spi_busy(struct hisi_spi *hs) +{ + return readl(hs->regs + HISI_SPI_SR) & SR_BUSY; +} + +static u32 hisi_spi_rx_not_empty(struct hisi_spi *hs) +{ + return readl(hs->regs + HISI_SPI_SR) & SR_RXNE; +} + +static u32 hisi_spi_tx_not_full(struct hisi_spi *hs) +{ + return readl(hs->regs + HISI_SPI_SR) & SR_TXNF; +} + +static void hisi_spi_flush_fifo(struct hisi_spi *hs) +{ + unsigned long limit = loops_per_jiffy << 1; + + do { + while (hisi_spi_rx_not_empty(hs)) + readl(hs->regs + HISI_SPI_DOUT); + } while (hisi_spi_busy(hs) && limit--); +} + +/* Disable the controller and all interrupts */ +static void hisi_spi_disable(struct hisi_spi *hs) +{ + writel(0, hs->regs + HISI_SPI_ENR); + writel(IMR_MASK, hs->regs + HISI_SPI_IMR); + writel(ICR_MASK, hs->regs + HISI_SPI_ICR); +} + +static u8 hisi_spi_n_bytes(struct spi_transfer *transfer) +{ + if (transfer->bits_per_word <= 8) + return HISI_SPI_N_BYTES_U8; + else if (transfer->bits_per_word <= 16) + return HISI_SPI_N_BYTES_U16; + else + return HISI_SPI_N_BYTES_U32; +} + +static void hisi_spi_reader(struct hisi_spi *hs) +{ + u32 max = min_t(u32, hs->rx_len, hs->fifo_len); + u32 rxw; + + while (hisi_spi_rx_not_empty(hs) && max--) { + rxw = readl(hs->regs + HISI_SPI_DOUT); + /* Check the transfer's original "rx" is not null */ + if (hs->rx) { + switch (hs->n_bytes) { + case HISI_SPI_N_BYTES_U8: + *(u8 *)(hs->rx) = rxw; + break; + case HISI_SPI_N_BYTES_U16: + *(u16 *)(hs->rx) = rxw; + break; + case HISI_SPI_N_BYTES_U32: + *(u32 *)(hs->rx) = rxw; + break; + } + hs->rx += hs->n_bytes; + } + --hs->rx_len; + } +} + +static void hisi_spi_writer(struct hisi_spi *hs) +{ + u32 max = min_t(u32, hs->tx_len, hs->fifo_len); + u32 txw = 0; + + while (hisi_spi_tx_not_full(hs) && max--) { + /* Check the transfer's original "tx" is not null */ + if (hs->tx) { + switch (hs->n_bytes) { + case HISI_SPI_N_BYTES_U8: + txw = *(u8 *)(hs->tx); + break; + case HISI_SPI_N_BYTES_U16: + txw = *(u16 *)(hs->tx); + break; + case HISI_SPI_N_BYTES_U32: + txw = *(u32 *)(hs->tx); + break; + } + hs->tx += hs->n_bytes; + } + writel(txw, hs->regs + HISI_SPI_DIN); + --hs->tx_len; + } +} + +static void __hisi_calc_div_reg(struct hisi_chip_data *chip) +{ + chip->div_pre = DIV_PRE_MAX; + while (chip->div_pre >= DIV_PRE_MIN) { + if (chip->clk_div % chip->div_pre == 0) + break; + + chip->div_pre -= 2; + } + + if (chip->div_pre > chip->clk_div) + chip->div_pre = chip->clk_div; + + chip->div_post = (chip->clk_div / chip->div_pre) - 1; +} + +static u32 hisi_calc_effective_speed(struct spi_controller *master, + struct hisi_chip_data *chip, u32 speed_hz) +{ + u32 effective_speed; + + /* Note clock divider doesn't support odd numbers */ + chip->clk_div = DIV_ROUND_UP(master->max_speed_hz, speed_hz) + 1; + chip->clk_div &= 0xfffe; + if (chip->clk_div > CLK_DIV_MAX) + chip->clk_div = CLK_DIV_MAX; + + effective_speed = master->max_speed_hz / chip->clk_div; + if (chip->speed_hz != effective_speed) { + __hisi_calc_div_reg(chip); + chip->speed_hz = effective_speed; + } + + return effective_speed; +} + +static u32 hisi_spi_prepare_cr(struct spi_device *spi) +{ + u32 cr = FIELD_PREP(CR_SPD_MODE_MASK, 1); + + cr |= FIELD_PREP(CR_CPHA_MASK, (spi->mode & SPI_CPHA) ? 1 : 0); + cr |= FIELD_PREP(CR_CPOL_MASK, (spi->mode & SPI_CPOL) ? 1 : 0); + cr |= FIELD_PREP(CR_LOOP_MASK, (spi->mode & SPI_LOOP) ? 1 : 0); + + return cr; +} + +static void hisi_spi_hw_init(struct hisi_spi *hs) +{ + hisi_spi_disable(hs); + + /* FIFO default config */ + writel(FIELD_PREP(FIFOC_TX_MASK, HISI_SPI_TX_64_OR_LESS) | + FIELD_PREP(FIFOC_RX_MASK, HISI_SPI_RX_16), + hs->regs + HISI_SPI_FIFOC); + + hs->fifo_len = 256; +} + +static irqreturn_t hisi_spi_irq(int irq, void *dev_id) +{ + struct spi_controller *master = dev_id; + struct hisi_spi *hs = spi_controller_get_devdata(master); + u32 irq_status = readl(hs->regs + HISI_SPI_ISR) & ISR_MASK; + + if (!irq_status) + return IRQ_NONE; + + if (!master->cur_msg) + return IRQ_HANDLED; + + /* Error handling */ + if (irq_status & ISR_RXOF) { + dev_err(hs->dev, "interrupt_transfer: fifo overflow\n"); + master->cur_msg->status = -EIO; + goto finalize_transfer; + } + + /* + * Read data from the Rx FIFO every time. If there is + * nothing left to receive, finalize the transfer. + */ + hisi_spi_reader(hs); + if (!hs->rx_len) + goto finalize_transfer; + + /* Send data out when Tx FIFO IRQ triggered */ + if (irq_status & ISR_TX) + hisi_spi_writer(hs); + + return IRQ_HANDLED; + +finalize_transfer: + hisi_spi_disable(hs); + spi_finalize_current_transfer(master); + return IRQ_HANDLED; +} + +static int hisi_spi_transfer_one(struct spi_controller *master, + struct spi_device *spi, struct spi_transfer *transfer) +{ + struct hisi_spi *hs = spi_controller_get_devdata(master); + struct hisi_chip_data *chip = spi_get_ctldata(spi); + u32 cr = chip->cr; + + /* Update per transfer options for speed and bpw */ + transfer->effective_speed_hz = + hisi_calc_effective_speed(master, chip, transfer->speed_hz); + cr |= FIELD_PREP(CR_DIV_PRE_MASK, chip->div_pre); + cr |= FIELD_PREP(CR_DIV_POST_MASK, chip->div_post); + cr |= FIELD_PREP(CR_BPW_MASK, transfer->bits_per_word - 1); + writel(cr, hs->regs + HISI_SPI_CR); + + hisi_spi_flush_fifo(hs); + + hs->n_bytes = hisi_spi_n_bytes(transfer); + hs->tx = transfer->tx_buf; + hs->tx_len = transfer->len / hs->n_bytes; + hs->rx = transfer->rx_buf; + hs->rx_len = hs->tx_len; + + /* + * Ensure that the transfer data above has been updated + * before the interrupt to start. + */ + smp_mb(); + + /* Enable all interrupts and the controller */ + writel(~(u32)IMR_MASK, hs->regs + HISI_SPI_IMR); + writel(1, hs->regs + HISI_SPI_ENR); + + return 1; +} + +static void hisi_spi_handle_err(struct spi_controller *master, + struct spi_message *msg) +{ + struct hisi_spi *hs = spi_controller_get_devdata(master); + + hisi_spi_disable(hs); + + /* + * Wait for interrupt handler that is + * already in timeout to complete. + */ + msleep(HISI_SPI_WAIT_TIMEOUT_MS); +} + +static int hisi_spi_setup(struct spi_device *spi) +{ + struct hisi_chip_data *chip; + + /* Only alloc on first setup */ + chip = spi_get_ctldata(spi); + if (!chip) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + spi_set_ctldata(spi, chip); + } + + chip->cr = hisi_spi_prepare_cr(spi); + + return 0; +} + +static void hisi_spi_cleanup(struct spi_device *spi) +{ + struct hisi_chip_data *chip = spi_get_ctldata(spi); + + kfree(chip); + spi_set_ctldata(spi, NULL); +} + +static int hisi_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_controller *master; + struct hisi_spi *hs; + int ret, irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + master = devm_spi_alloc_master(dev, sizeof(*hs)); + if (!master) + return -ENOMEM; + + platform_set_drvdata(pdev, master); + + hs = spi_controller_get_devdata(master); + hs->dev = dev; + hs->irq = irq; + + hs->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hs->regs)) + return PTR_ERR(hs->regs); + + /* Specify maximum SPI clocking speed (master only) by firmware */ + ret = device_property_read_u32(dev, "spi-max-frequency", + &master->max_speed_hz); + if (ret) { + dev_err(dev, "failed to get max SPI clocking speed, ret=%d\n", + ret); + return -EINVAL; + } + + ret = device_property_read_u16(dev, "num-cs", + &master->num_chipselect); + if (ret) + master->num_chipselect = DEFAULT_NUM_CS; + + master->use_gpio_descriptors = true; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + master->bus_num = pdev->id; + master->setup = hisi_spi_setup; + master->cleanup = hisi_spi_cleanup; + master->transfer_one = hisi_spi_transfer_one; + master->handle_err = hisi_spi_handle_err; + master->dev.fwnode = dev->fwnode; + + hisi_spi_hw_init(hs); + + ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev), + master); + if (ret < 0) { + dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret); + return ret; + } + + ret = spi_register_controller(master); + if (ret) { + dev_err(dev, "failed to register spi master, ret=%d\n", ret); + return ret; + } + + dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", + readl(hs->regs + HISI_SPI_VERSION), + master->max_speed_hz / 1000); + + return 0; +} + +static int hisi_spi_remove(struct platform_device *pdev) +{ + struct spi_controller *master = platform_get_drvdata(pdev); + + spi_unregister_controller(master); + + return 0; +} + +static const struct acpi_device_id hisi_spi_acpi_match[] = { + {"HISI03E1", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match); + +static struct platform_driver hisi_spi_driver = { + .probe = hisi_spi_probe, + .remove = hisi_spi_remove, + .driver = { + .name = "hisi-kunpeng-spi", + .acpi_match_table = hisi_spi_acpi_match, + }, +}; +module_platform_driver(hisi_spi_driver); + +MODULE_AUTHOR("Jay Fang <f.fangjian@huawei.com>"); +MODULE_DESCRIPTION("HiSilicon SPI Controller Driver for Kunpeng SoCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index 385eb7bba05a5afd7320a80f94e756e97ccbd19d..d3a23b1c2a4c546ff702f477a36e32989932bdd0 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -5,13 +5,13 @@ // Copyright (c) 2019 HiSilicon Technologies Co., Ltd. // Author: John Garry <john.garry@huawei.com> -#include <linux/acpi.h> #include <linux/bitops.h> #include <linux/completion.h> #include <linux/dmi.h> #include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> @@ -342,6 +342,7 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, ret = 0; hisi_sfc_v3xx_disable_int(host); + synchronize_irq(host->irq); host->completion = NULL; } else { ret = hisi_sfc_v3xx_wait_cmd_idle(host); @@ -507,18 +508,16 @@ err_put_master: return ret; } -#if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id hisi_sfc_v3xx_acpi_ids[] = { {"HISI0341", 0}, {} }; MODULE_DEVICE_TABLE(acpi, hisi_sfc_v3xx_acpi_ids); -#endif static struct platform_driver hisi_sfc_v3xx_spi_driver = { .driver = { .name = "hisi-sfc-v3xx", - .acpi_match_table = ACPI_PTR(hisi_sfc_v3xx_acpi_ids), + .acpi_match_table = hisi_sfc_v3xx_acpi_ids, }, .probe = hisi_sfc_v3xx_probe, }; diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 5dc4ea4b4450e55d6c25c276b2e1c522456723ed..64e8f0828e85604525aa63397e678ba4fce30d4a 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -66,8 +66,7 @@ struct spi_imx_data; struct spi_imx_devtype_data { void (*intctrl)(struct spi_imx_data *, int); int (*prepare_message)(struct spi_imx_data *, struct spi_message *); - int (*prepare_transfer)(struct spi_imx_data *, struct spi_device *, - struct spi_transfer *); + int (*prepare_transfer)(struct spi_imx_data *, struct spi_device *); void (*trigger)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *); @@ -572,11 +571,10 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, } static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi, - struct spi_transfer *t) + struct spi_device *spi) { u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); - u32 clk = t->speed_hz, delay; + u32 clk, delay; /* Clear BL field and set the right value */ ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; @@ -590,7 +588,7 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, /* set clock speed */ ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET | 0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET); - ctrl |= mx51_ecspi_clkdiv(spi_imx, t->speed_hz, &clk); + ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk); spi_imx->spi_bus_clk = clk; if (spi_imx->usedma) @@ -702,13 +700,12 @@ 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_transfer *t) + struct spi_device *spi) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; unsigned int clk; - reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, t->speed_hz, &clk) << + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) << MX31_CSPICTRL_DR_SHIFT; spi_imx->spi_bus_clk = clk; @@ -807,14 +804,13 @@ 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_transfer *t) + struct spi_device *spi) { unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; unsigned int clk; - reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, t->speed_hz, max, &clk) + reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->spi_bus_clk, max, &clk) << MX21_CSPICTRL_DR_SHIFT; spi_imx->spi_bus_clk = clk; @@ -883,13 +879,12 @@ 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_transfer *t) + struct spi_device *spi) { unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; unsigned int clk; - reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, t->speed_hz, &clk) << + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) << MX1_CSPICTRL_DR_SHIFT; spi_imx->spi_bus_clk = clk; @@ -1168,6 +1163,16 @@ static int spi_imx_setupxfer(struct spi_device *spi, if (!t) return 0; + if (!t->speed_hz) { + if (!spi->max_speed_hz) { + dev_err(&spi->dev, "no speed_hz provided!\n"); + return -EINVAL; + } + dev_dbg(&spi->dev, "using spi->max_speed_hz!\n"); + spi_imx->spi_bus_clk = spi->max_speed_hz; + } else + spi_imx->spi_bus_clk = t->speed_hz; + spi_imx->bits_per_word = t->bits_per_word; /* @@ -1209,7 +1214,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->slave_burst = t->len; } - spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t); + spi_imx->devtype_data->prepare_transfer(spi_imx, spi); return 0; } @@ -1801,7 +1806,7 @@ static struct platform_driver spi_imx_driver = { }; module_platform_driver(spi_imx_driver); -MODULE_DESCRIPTION("SPI Controller driver"); +MODULE_DESCRIPTION("i.MX SPI Controller driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c index bba10f030e33daa4b7e404582ff86ed3b18b01df..74c8319c29f1706aef9e4b2bea9b7956d4c937f6 100644 --- a/drivers/spi/spi-jcore.c +++ b/drivers/spi/spi-jcore.c @@ -82,7 +82,8 @@ static void jcore_spi_chipsel(struct spi_device *spi, bool value) static void jcore_spi_baudrate(struct jcore_spi *hw, int speed) { - if (speed == hw->speed_hz) return; + if (speed == hw->speed_hz) + return; hw->speed_hz = speed; if (speed >= hw->clock_freq / 2) hw->speed_reg = 0; diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 174dba29b1ddeb03763a918934b2a22e6ef85bf1..f914b8d2043e3e9108d624c0b6e43aad842236cd 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -320,18 +320,7 @@ static struct parport_driver spi_lm70llp_drv = { .detach = spi_lm70llp_detach, .devmodel = true, }; - -static int __init init_spi_lm70llp(void) -{ - return parport_register_driver(&spi_lm70llp_drv); -} -module_init(init_spi_lm70llp); - -static void __exit cleanup_spi_lm70llp(void) -{ - parport_unregister_driver(&spi_lm70llp_drv); -} -module_exit(cleanup_spi_lm70llp); +module_parport_driver(spi_lm70llp_drv); MODULE_AUTHOR("Kaiwan N Billimoria <kaiwan@designergraphix.com>"); MODULE_DESCRIPTION( diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index df981e55c24c99b618fa4a0e2849bfaab6b88ebc..f1cf2232f0b5e2b7567fb0314501c43fb3e5c6ae 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -454,7 +454,8 @@ struct rx_ranges { u8 *end; }; -static int rx_ranges_cmp(void *priv, struct list_head *a, struct list_head *b) +static int rx_ranges_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct rx_ranges *rx_a = list_entry(a, struct rx_ranges, list); struct rx_ranges *rx_b = list_entry(b, struct rx_ranges, list); diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index dc713b0c3c4d84be4f0c7afeed7ff6fadda350e4..1513553e40805a91d02f9c68952bd0b68c869aa0 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -621,10 +621,10 @@ EXPORT_SYMBOL_GPL(devm_spi_mem_dirmap_create); static int devm_spi_mem_dirmap_match(struct device *dev, void *res, void *data) { - struct spi_mem_dirmap_desc **ptr = res; + struct spi_mem_dirmap_desc **ptr = res; - if (WARN_ON(!ptr || !*ptr)) - return 0; + if (WARN_ON(!ptr || !*ptr)) + return 0; return *ptr == data; } diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 2e2f36a2e38501fac241c59dfea0cdfa95d629fa..41e7b341d2616f28fd8625490c8af265dacea673 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -292,7 +292,7 @@ static bool mtk_nor_supports_op(struct spi_mem *mem, return false; if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) { - switch(op->data.dir) { + switch (op->data.dir) { case SPI_MEM_DATA_IN: if (mtk_nor_match_read(op)) return true; diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index ab9035662717a3b0464bdefb6bb3ca4d10376401..6e6c2403944dd21d23b1a4501c4c1706475ffa41 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -49,8 +49,11 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_qos.h> +#include <linux/regmap.h> #include <linux/sizes.h> +#include <linux/sys_soc.h> +#include <linux/mfd/syscon.h> #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> @@ -311,6 +314,11 @@ #define NXP_FSPI_MAX_CHIPSELECT 4 #define NXP_FSPI_MIN_IOMAP SZ_4M +#define DCFG_RCWSR1 0x100 + +/* Access flash memory using IP bus only */ +#define FSPI_QUIRK_USE_IP_ONLY BIT(0) + struct nxp_fspi_devtype_data { unsigned int rxfifo; unsigned int txfifo; @@ -319,7 +327,7 @@ struct nxp_fspi_devtype_data { bool little_endian; }; -static const struct nxp_fspi_devtype_data lx2160a_data = { +static struct nxp_fspi_devtype_data lx2160a_data = { .rxfifo = SZ_512, /* (64 * 64 bits) */ .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ @@ -327,7 +335,7 @@ static const struct nxp_fspi_devtype_data lx2160a_data = { .little_endian = true, /* little-endian */ }; -static const struct nxp_fspi_devtype_data imx8mm_data = { +static struct nxp_fspi_devtype_data imx8mm_data = { .rxfifo = SZ_512, /* (64 * 64 bits) */ .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ @@ -335,7 +343,7 @@ static const struct nxp_fspi_devtype_data imx8mm_data = { .little_endian = true, /* little-endian */ }; -static const struct nxp_fspi_devtype_data imx8qxp_data = { +static struct nxp_fspi_devtype_data imx8qxp_data = { .rxfifo = SZ_512, /* (64 * 64 bits) */ .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ @@ -343,6 +351,14 @@ static const struct nxp_fspi_devtype_data imx8qxp_data = { .little_endian = true, /* little-endian */ }; +static struct nxp_fspi_devtype_data imx8dxl_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = FSPI_QUIRK_USE_IP_ONLY, + .little_endian = true, /* little-endian */ +}; + struct nxp_fspi { void __iomem *iobase; void __iomem *ahb_addr; @@ -353,12 +369,17 @@ struct nxp_fspi { struct clk *clk, *clk_en; struct device *dev; struct completion c; - const struct nxp_fspi_devtype_data *devtype_data; + struct nxp_fspi_devtype_data *devtype_data; struct mutex lock; struct pm_qos_request pm_qos_req; int selected; }; +static inline int needs_ip_only(struct nxp_fspi *f) +{ + return f->devtype_data->quirks & FSPI_QUIRK_USE_IP_ONLY; +} + /* * R/W functions for big- or little-endian registers: * The FSPI controller's endianness is independent of @@ -553,8 +574,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, for (i = 0; i < ARRAY_SIZE(lutval); i++) fspi_writel(f, lutval[i], base + FSPI_LUT_REG(i)); - dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x]\n", - op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3]); + dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n", + op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes); /* lock LUT */ fspi_writel(f, FSPI_LUTKEY_VALUE, f->iobase + FSPI_LUTKEY); @@ -852,12 +873,14 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) nxp_fspi_prepare_lut(f, op); /* - * If we have large chunks of data, we read them through the AHB bus - * by accessing the mapped memory. In all other cases we use - * IP commands to access the flash. + * If we have large chunks of data, we read them through the AHB bus by + * accessing the mapped memory. In all other cases we use IP commands + * to access the flash. Read via AHB bus may be corrupted due to + * existence of an errata and therefore discard AHB read in such cases. */ if (op->data.nbytes > (f->devtype_data->rxfifo - 4) && - op->data.dir == SPI_MEM_DATA_IN) { + op->data.dir == SPI_MEM_DATA_IN && + !needs_ip_only(f)) { err = nxp_fspi_read_ahb(f, op); } else { if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) @@ -888,9 +911,68 @@ static int nxp_fspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) op->data.nbytes = ALIGN_DOWN(op->data.nbytes, 8); } + /* Limit data bytes to RX FIFO in case of IP read only */ + if (op->data.dir == SPI_MEM_DATA_IN && + needs_ip_only(f) && + op->data.nbytes > f->devtype_data->rxfifo) + op->data.nbytes = f->devtype_data->rxfifo; + return 0; } +static void erratum_err050568(struct nxp_fspi *f) +{ + const struct soc_device_attribute ls1028a_soc_attr[] = { + { .family = "QorIQ LS1028A" }, + { /* sentinel */ } + }; + struct device_node *np; + struct regmap *map; + u32 val = 0, sysclk = 0; + int ret; + + /* Check for LS1028A family */ + if (!soc_device_match(ls1028a_soc_attr)) { + dev_dbg(f->dev, "Errata applicable only for LS1028A\n"); + return; + } + + /* Compute system clock frequency multiplier ratio */ + map = syscon_regmap_lookup_by_compatible("fsl,ls1028a-dcfg"); + if (IS_ERR(map)) { + dev_err(f->dev, "No syscon regmap\n"); + goto err; + } + + ret = regmap_read(map, DCFG_RCWSR1, &val); + if (ret < 0) + goto err; + + /* Strap bits 6:2 define SYS_PLL_RAT i.e frequency multiplier ratio */ + val = (val >> 2) & 0x1F; + WARN(val == 0, "Strapping is zero: Cannot determine ratio"); + + /* Compute system clock frequency */ + np = of_find_node_by_name(NULL, "clock-sysclk"); + if (!np) + goto err; + + if (of_property_read_u32(np, "clock-frequency", &sysclk)) + goto err; + + sysclk = (sysclk * val) / 1000000; /* Convert sysclk to Mhz */ + dev_dbg(f->dev, "val: 0x%08x, sysclk: %dMhz\n", val, sysclk); + + /* Use IP bus only if PLL is 300MHz */ + if (sysclk == 300) + f->devtype_data->quirks |= FSPI_QUIRK_USE_IP_ONLY; + + return; + +err: + dev_err(f->dev, "Errata cannot be executed. Read via IP bus may not work\n"); +} + static int nxp_fspi_default_setup(struct nxp_fspi *f) { void __iomem *base = f->iobase; @@ -909,6 +991,15 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) if (ret) return ret; + /* + * ERR050568: Flash access by FlexSPI AHB command may not work with + * platform frequency equal to 300 MHz on LS1028A. + * LS1028A reuses LX2160A compatible entry. Make errata applicable for + * Layerscape LS1028A platform. + */ + if (of_device_is_compatible(f->dev->of_node, "nxp,lx2160a-fspi")) + erratum_err050568(f); + /* Reset the module */ /* w1c register, wait unit clear */ ret = fspi_readl_poll_tout(f, f->iobase + FSPI_MCR0, @@ -1012,7 +1103,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) f = spi_controller_get_devdata(ctlr); f->dev = dev; - f->devtype_data = device_get_match_data(dev); + f->devtype_data = (struct nxp_fspi_devtype_data *)device_get_match_data(dev); if (!f->devtype_data) { ret = -ENODEV; goto err_put_ctrl; @@ -1151,7 +1242,9 @@ static int nxp_fspi_resume(struct device *dev) static const struct of_device_id nxp_fspi_dt_ids[] = { { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, }, { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, }, + { .compatible = "nxp,imx8mp-fspi", .data = (void *)&imx8mm_data, }, { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, }, + { .compatible = "nxp,imx8dxl-fspi", .data = (void *)&imx8dxl_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids); diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 36a4922a134a13f4c6214ee2a1bced9585f61225..7062f290225394f61b39649f39c846b6954e7d76 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -110,7 +110,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) } spi100k_enable_clock(master); - writew(data , spi100k->base + SPI_TX_MSB); + writew(data, spi100k->base + SPI_TX_MSB); writew(SPI_CTRL_SEN(0) | SPI_CTRL_WORD_SIZE(len) | @@ -246,9 +246,9 @@ static int omap1_spi100k_setup_transfer(struct spi_device *spi, cs->word_len = word_len; /* SPI init before transfer */ - writew(0x3e , spi100k->base + SPI_SETUP1); - writew(0x00 , spi100k->base + SPI_STATUS); - writew(0x3e , spi100k->base + SPI_CTRL); + writew(0x3e, spi100k->base + SPI_SETUP1); + writew(0x00, spi100k->base + SPI_STATUS); + writew(0x3e, spi100k->base + SPI_CTRL); return 0; } @@ -424,7 +424,7 @@ err: static int omap1_spi100k_remove(struct platform_device *pdev) { - struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct spi_master *master = platform_get_drvdata(pdev); struct omap1_spi100k *spi100k = spi_master_get_devdata(master); pm_runtime_disable(&pdev->dev); @@ -438,7 +438,7 @@ static int omap1_spi100k_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int omap1_spi100k_runtime_suspend(struct device *dev) { - struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct omap1_spi100k *spi100k = spi_master_get_devdata(master); clk_disable_unprepare(spi100k->ick); @@ -449,7 +449,7 @@ static int omap1_spi100k_runtime_suspend(struct device *dev) static int omap1_spi100k_runtime_resume(struct device *dev) { - struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct omap1_spi100k *spi100k = spi_master_get_devdata(master); int ret; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index d4c9510af3931ae97b29bb1fcbb0c5c44c5565ba..999c2273641642434f65349dd91b6e24192e3ec3 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1327,6 +1327,17 @@ static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi) return 0; } +static int omap_mcspi_runtime_suspend(struct device *dev) +{ + int error; + + error = pinctrl_pm_select_idle_state(dev); + if (error) + dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error); + + return 0; +} + /* * When SPI wake up from off-mode, CS is in activate state. If it was in * inactive state when driver was suspend, then force it to inactive state at @@ -1338,6 +1349,11 @@ static int omap_mcspi_runtime_resume(struct device *dev) struct omap2_mcspi *mcspi = spi_master_get_devdata(master); struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_cs *cs; + int error; + + error = pinctrl_pm_select_default_state(dev); + if (error) + dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error); /* McSPI: context restore */ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); @@ -1566,11 +1582,6 @@ static int __maybe_unused omap2_mcspi_resume(struct device *dev) struct omap2_mcspi *mcspi = spi_master_get_devdata(master); int error; - error = pinctrl_pm_select_default_state(dev); - if (error) - dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", - __func__, error); - error = spi_master_resume(master); if (error) dev_warn(mcspi->dev, "%s: master resume failed: %i\n", @@ -1582,7 +1593,8 @@ static int __maybe_unused omap2_mcspi_resume(struct device *dev) static const struct dev_pm_ops omap2_mcspi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(omap2_mcspi_suspend, omap2_mcspi_resume) - .runtime_resume = omap_mcspi_runtime_resume, + .runtime_suspend = omap_mcspi_runtime_suspend, + .runtime_resume = omap_mcspi_runtime_resume, }; static struct platform_driver omap2_mcspi_driver = { diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 68ed7fd642569d14dabf6cc27160ebcd70cf2fa4..34b31aba3981711f679f19dd21ca3598db64906d 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -634,7 +634,6 @@ MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); static int orion_spi_probe(struct platform_device *pdev) { - const struct of_device_id *of_id; const struct orion_spi_dev *devdata; struct spi_master *master; struct orion_spi *spi; @@ -676,8 +675,8 @@ static int orion_spi_probe(struct platform_device *pdev) spi->master = master; spi->dev = &pdev->dev; - of_id = of_match_device(orion_spi_of_match_table, &pdev->dev); - devdata = (of_id) ? of_id->data : &orion_spi_dev_data; + devdata = device_get_match_data(&pdev->dev); + devdata = devdata ? devdata : &orion_spi_dev_data; spi->devdata = devdata; spi->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index fd74ddfbb686975fef4598d823cdbe37db1864d6..0c9e3f270f05a3a6a12302fb87fbb9f2ebf00001 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -31,8 +31,7 @@ #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/pm_runtime.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> /* @@ -362,8 +361,8 @@ struct vendor_data { * @sgt_tx: scattertable for the TX transfer * @dummypage: a dummy page used for driving data on the bus with DMA * @dma_running: indicates whether DMA is in operation - * @cur_cs: current chip select (gpio) - * @chipselects: list of chipselects (gpios) + * @cur_cs: current chip select index + * @cur_gpiod: current chip select GPIO descriptor */ struct pl022 { struct amba_device *adev; @@ -398,7 +397,7 @@ struct pl022 { bool dma_running; #endif int cur_cs; - int *chipselects; + struct gpio_desc *cur_gpiod; }; /** @@ -412,7 +411,6 @@ struct pl022 { * @enable_dma: Whether to enable DMA or not * @read: function ptr to be used to read when doing xfer for this chip * @write: function ptr to be used to write when doing xfer for this chip - * @cs_control: chip select callback provided by chip * @xfer_type: polling/interrupt/DMA * * Runtime state of the SSP controller, maintained per chip, @@ -427,22 +425,9 @@ struct chip_data { bool enable_dma; enum ssp_reading read; enum ssp_writing write; - void (*cs_control) (u32 command); int xfer_type; }; -/** - * null_cs_control - Dummy chip select function - * @command: select/delect the chip - * - * If no chip select function is provided by client this is used as dummy - * chip select - */ -static void null_cs_control(u32 command) -{ - pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); -} - /** * internal_cs_control - Control chip select signals via SSP_CSR. * @pl022: SSP driver private data structure @@ -468,10 +453,16 @@ static void pl022_cs_control(struct pl022 *pl022, u32 command) { if (pl022->vendor->internal_cs_ctrl) internal_cs_control(pl022, command); - else if (gpio_is_valid(pl022->cur_cs)) - gpio_set_value(pl022->cur_cs, command); - else - pl022->cur_chip->cs_control(command); + else if (pl022->cur_gpiod) + /* + * This needs to be inverted since with GPIOLIB in + * control, the inversion will be handled by + * GPIOLIB's active low handling. The "command" + * passed into this function will be SSP_CHIP_SELECT + * which is enum:ed to 0, so we need the inverse + * (1) to activate chip select. + */ + gpiod_set_value(pl022->cur_gpiod, !command); } /** @@ -1195,7 +1186,7 @@ err_no_txchan: err_no_rxchan: return err; } - + static void terminate_dma(struct pl022 *pl022) { struct dma_chan *rxchan = pl022->dma_rx_channel; @@ -1596,7 +1587,9 @@ static int pl022_transfer_one_message(struct spi_master *master, /* Setup the SPI using the per chip configuration */ pl022->cur_chip = spi_get_ctldata(msg->spi); - pl022->cur_cs = pl022->chipselects[msg->spi->chip_select]; + pl022->cur_cs = msg->spi->chip_select; + /* This is always available but may be set to -ENOENT */ + pl022->cur_gpiod = msg->spi->cs_gpiod; restore_state(pl022); flush(pl022); @@ -1820,16 +1813,15 @@ static int calculate_effective_freq(struct pl022 *pl022, int freq, struct * supplies it. */ static const struct pl022_config_chip pl022_default_chip_info = { - .com_mode = POLLING_TRANSFER, + .com_mode = INTERRUPT_TRANSFER, .iface = SSP_INTERFACE_MOTOROLA_SPI, - .hierarchy = SSP_SLAVE, + .hierarchy = SSP_MASTER, .slave_tx_disable = DO_NOT_DRIVE_TX, .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, .ctrl_len = SSP_BITS_8, .wait_state = SSP_MWIRE_WAIT_ZERO, .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, - .cs_control = null_cs_control, }; /** @@ -1940,13 +1932,6 @@ static int pl022_setup(struct spi_device *spi) /* Now set controller state based on controller data */ chip->xfer_type = chip_info->com_mode; - if (!chip_info->cs_control) { - chip->cs_control = null_cs_control; - if (!gpio_is_valid(pl022->chipselects[spi->chip_select])) - dev_warn(&spi->dev, - "invalid chip select\n"); - } else - chip->cs_control = chip_info->cs_control; /* Check bits per word with vendor specific range */ if ((bits <= 3) || (bits > pl022->vendor->max_bpw)) { @@ -2094,7 +2079,6 @@ pl022_platform_data_dt_get(struct device *dev) { struct device_node *np = dev->of_node; struct pl022_ssp_controller *pd; - u32 tmp = 0; if (!np) { dev_err(dev, "no dt node defined\n"); @@ -2107,8 +2091,6 @@ pl022_platform_data_dt_get(struct device *dev) pd->bus_id = -1; pd->enable_dma = 1; - of_property_read_u32(np, "num-cs", &tmp); - pd->num_chipselect = tmp; of_property_read_u32(np, "pl022,autosuspend-delay", &pd->autosuspend_delay); pd->rt = of_property_read_bool(np, "pl022,rt"); @@ -2123,8 +2105,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) dev_get_platdata(&adev->dev); struct spi_master *master; struct pl022 *pl022 = NULL; /*Data for this driver */ - struct device_node *np = adev->dev.of_node; - int status = 0, i, num_cs; + int status = 0; dev_info(&adev->dev, "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); @@ -2136,13 +2117,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) return -ENODEV; } - if (platform_info->num_chipselect) { - num_cs = platform_info->num_chipselect; - } else { - dev_err(dev, "probe: no chip select defined\n"); - return -ENODEV; - } - /* Allocate master with space for data */ master = spi_alloc_master(dev, sizeof(struct pl022)); if (master == NULL) { @@ -2155,19 +2129,12 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022->master_info = platform_info; pl022->adev = adev; pl022->vendor = id->data; - pl022->chipselects = devm_kcalloc(dev, num_cs, sizeof(int), - GFP_KERNEL); - if (!pl022->chipselects) { - status = -ENOMEM; - goto err_no_mem; - } /* * Bus Number Which has been Assigned to this SSP controller * on this board */ master->bus_num = platform_info->bus_id; - master->num_chipselect = num_cs; master->cleanup = pl022_cleanup; master->setup = pl022_setup; master->auto_runtime_pm = true; @@ -2175,36 +2142,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; master->rt = platform_info->rt; master->dev.of_node = dev->of_node; - - if (platform_info->num_chipselect && platform_info->chipselects) { - for (i = 0; i < num_cs; i++) - pl022->chipselects[i] = platform_info->chipselects[i]; - } else if (pl022->vendor->internal_cs_ctrl) { - for (i = 0; i < num_cs; i++) - pl022->chipselects[i] = i; - } else if (IS_ENABLED(CONFIG_OF)) { - for (i = 0; i < num_cs; i++) { - int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); - - if (cs_gpio == -EPROBE_DEFER) { - status = -EPROBE_DEFER; - goto err_no_gpio; - } - - pl022->chipselects[i] = cs_gpio; - - if (gpio_is_valid(cs_gpio)) { - if (devm_gpio_request(dev, cs_gpio, "ssp-pl022")) - dev_err(&adev->dev, - "could not request %d gpio\n", - cs_gpio); - else if (gpio_direction_output(cs_gpio, 1)) - dev_err(&adev->dev, - "could not set gpio %d as output\n", - cs_gpio); - } - } - } + master->use_gpio_descriptors = true; /* * Supports mode 0-3, loopback, and active low CS. Transfers are @@ -2308,8 +2246,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) err_no_ioremap: amba_release_regions(adev); err_no_ioregion: - err_no_gpio: - err_no_mem: spi_master_put(master); return status; } diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 14fc41ed2361df3e8df6fd7dadb1937dd3fd6c0f..1833f5876e9fa1c6c0a15a094be6422df7766a31 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -252,7 +252,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp->irq = pci_irq_vector(dev, 0); snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); - ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, 0, + ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0, c->max_clk_rate); if (IS_ERR(ssp->clk)) return PTR_ERR(ssp->clk); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 0cc767283674b21f54ed1f6ae59f312dc1336e97..5e59ba075bc7aefd582987bd88d7f233d3bf1c1f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -618,7 +618,7 @@ static void reset_sccr1(struct driver_data *drv_data) pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } -static void int_error_stop(struct driver_data *drv_data, const char* msg) +static void int_error_stop(struct driver_data *drv_data, const char *msg) { /* Stop and reset SSP */ write_SSSR_CS(drv_data, drv_data->clear_sr); @@ -1496,6 +1496,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x51aa), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x51ab), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x51fb), LPSS_CNL_SSP }, + /* ADL-M */ + { PCI_VDEVICE(INTEL, 0x54aa), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x54ab), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x54fb), LPSS_CNL_SSP }, /* APL */ { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 1dbcc410cd3541a6ff96c2758077d88ebedcc0c2..c334dfec4117a71a47e0a64b26157847181dc051 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -142,7 +142,6 @@ struct qcom_qspi { struct clk_bulk_data *clks; struct qspi_xfer xfer; struct icc_path *icc_path_cpu_to_qspi; - struct opp_table *opp_table; unsigned long last_speed; /* Lock to protect data accessed by IRQs */ spinlock_t lock; @@ -530,14 +529,14 @@ static int qcom_qspi_probe(struct platform_device *pdev) master->handle_err = qcom_qspi_handle_err; master->auto_runtime_pm = true; - ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core"); - if (IS_ERR(ctrl->opp_table)) - return PTR_ERR(ctrl->opp_table); + ret = devm_pm_opp_set_clkname(&pdev->dev, "core"); + if (ret) + return ret; /* OPP table is optional */ - ret = dev_pm_opp_of_add_table(&pdev->dev); + ret = devm_pm_opp_of_add_table(&pdev->dev); if (ret && ret != -ENODEV) { dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - goto exit_probe_put_clkname; + return ret; } pm_runtime_use_autosuspend(dev); @@ -549,10 +548,6 @@ static int qcom_qspi_probe(struct platform_device *pdev) return 0; pm_runtime_disable(dev); - dev_pm_opp_of_remove_table(&pdev->dev); - -exit_probe_put_clkname: - dev_pm_opp_put_clkname(ctrl->opp_table); return ret; } @@ -560,14 +555,11 @@ exit_probe_put_clkname: static int qcom_qspi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); - struct qcom_qspi *ctrl = spi_master_get_devdata(master); /* Unregister _before_ disabling pm_runtime() so we stop transfers */ spi_unregister_master(master); pm_runtime_disable(&pdev->dev); - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(ctrl->opp_table); return 0; } diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 8dcb2e70735c9143dfebbb7505fd93abbabdfcd1..d39dec6d1c91e8e68fc46e48c464ad8a0ac1edc6 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1263,7 +1263,7 @@ static int spi_qup_remove(struct platform_device *pdev) struct spi_qup *controller = spi_master_get_devdata(master); int ret; - ret = pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) return ret; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 936ef54e09037b715907e00c31eda71a926b5ff8..52d6259d96edad6b14b477d408d2cfb394533f40 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -476,14 +476,14 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, return 1; } -static void rockchip_spi_config(struct rockchip_spi *rs, +static int rockchip_spi_config(struct rockchip_spi *rs, struct spi_device *spi, struct spi_transfer *xfer, bool use_dma, bool slave_mode) { u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET - | CR0_BHT_8BIT << CR0_BHT_OFFSET - | CR0_SSD_ONE << CR0_SSD_OFFSET - | CR0_EM_BIG << CR0_EM_OFFSET; + | CR0_BHT_8BIT << CR0_BHT_OFFSET + | CR0_SSD_ONE << CR0_SSD_OFFSET + | CR0_EM_BIG << CR0_EM_OFFSET; u32 cr1; u32 dmacr = 0; @@ -521,7 +521,9 @@ static void rockchip_spi_config(struct rockchip_spi *rs, * ctlr->bits_per_word_mask, so this shouldn't * happen */ - unreachable(); + dev_err(rs->dev, "unknown bits per word: %d\n", + xfer->bits_per_word); + return -EINVAL; } if (use_dma) { @@ -554,6 +556,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs, */ writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz), rs->regs + ROCKCHIP_SPI_BAUDR); + + return 0; } static size_t rockchip_spi_max_transfer_size(struct spi_device *spi) @@ -577,6 +581,7 @@ static int rockchip_spi_transfer_one( struct spi_transfer *xfer) { struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + int ret; bool use_dma; WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && @@ -596,7 +601,9 @@ static int rockchip_spi_transfer_one( use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false; - rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); + ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); + if (ret) + return ret; if (use_dma) return rockchip_spi_prepare_dma(rs, ctlr, xfer); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index dfa7c91e13aa5849e9ff3b965a056e9e61241f6e..8755cd85e83ceb05c48716f131ed222d81d366d8 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -15,6 +15,7 @@ #include <linux/spi/spi.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/platform_data/spi-s3c64xx.h> @@ -127,7 +128,7 @@ struct s3c64xx_spi_dma_data { }; /** - * struct s3c64xx_spi_info - SPI Controller hardware info + * struct s3c64xx_spi_port_config - SPI Controller hardware info * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register. * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter. * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter. @@ -189,7 +190,7 @@ struct s3c64xx_spi_driver_data { unsigned cur_speed; struct s3c64xx_spi_dma_data rx_dma; struct s3c64xx_spi_dma_data tx_dma; - struct s3c64xx_spi_port_config *port_conf; + const struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; }; @@ -1048,20 +1049,14 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) } #endif -static const struct of_device_id s3c64xx_spi_dt_match[]; - -static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config( +static inline const struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config( struct platform_device *pdev) { #ifdef CONFIG_OF - if (pdev->dev.of_node) { - const struct of_device_id *match; - match = of_match_node(s3c64xx_spi_dt_match, pdev->dev.of_node); - return (struct s3c64xx_spi_port_config *)match->data; - } + if (pdev->dev.of_node) + return of_device_get_match_data(&pdev->dev); #endif - return (struct s3c64xx_spi_port_config *) - platform_get_device_id(pdev)->driver_data; + return (const struct s3c64xx_spi_port_config *)platform_get_device_id(pdev)->driver_data; } static int s3c64xx_spi_probe(struct platform_device *pdev) @@ -1399,27 +1394,27 @@ static const struct dev_pm_ops s3c64xx_spi_pm = { s3c64xx_spi_runtime_resume, NULL) }; -static struct s3c64xx_spi_port_config s3c2443_spi_port_config = { +static const struct s3c64xx_spi_port_config s3c2443_spi_port_config = { .fifo_lvl_mask = { 0x7f }, .rx_lvl_offset = 13, .tx_st_done = 21, .high_speed = true, }; -static struct s3c64xx_spi_port_config s3c6410_spi_port_config = { +static const struct s3c64xx_spi_port_config s3c6410_spi_port_config = { .fifo_lvl_mask = { 0x7f, 0x7F }, .rx_lvl_offset = 13, .tx_st_done = 21, }; -static struct s3c64xx_spi_port_config s5pv210_spi_port_config = { +static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = { .fifo_lvl_mask = { 0x1ff, 0x7F }, .rx_lvl_offset = 15, .tx_st_done = 25, .high_speed = true, }; -static struct s3c64xx_spi_port_config exynos4_spi_port_config = { +static const struct s3c64xx_spi_port_config exynos4_spi_port_config = { .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F }, .rx_lvl_offset = 15, .tx_st_done = 25, @@ -1428,7 +1423,7 @@ static struct s3c64xx_spi_port_config exynos4_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, }; -static struct s3c64xx_spi_port_config exynos7_spi_port_config = { +static const struct s3c64xx_spi_port_config exynos7_spi_port_config = { .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, .rx_lvl_offset = 15, .tx_st_done = 25, @@ -1437,7 +1432,7 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, }; -static struct s3c64xx_spi_port_config exynos5433_spi_port_config = { +static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = { .fifo_lvl_mask = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff}, .rx_lvl_offset = 15, .tx_st_done = 25, diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 15123a8f41e1e7ff79eec15882604fcdb1661d54..45f304935332199063387bea1fbd10607c5bac99 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -290,8 +290,8 @@ static void spi_sh_work(struct work_struct *work) list_for_each_entry(t, &mesg->transfers, transfer_list) { pr_debug("tx_buf = %p, rx_buf = %p\n", t->tx_buf, t->rx_buf); - pr_debug("len = %d, delay_usecs = %d\n", - t->len, t->delay_usecs); + pr_debug("len = %d, delay.value = %d\n", + t->len, t->delay.value); if (t->tx_buf) { ret = spi_sh_send(ss, mesg, t); diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 44edaa360405a67b3dc360833d50028861bab65e..f199a6c4738a0bf6426d73ad90b1ac870118d3a6 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -10,6 +10,8 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/spi/spi.h> +#include <linux/of.h> + #define SPIS_IRQ_EN_REG 0x0 #define SPIS_IRQ_CLR_REG 0x4 @@ -61,8 +63,6 @@ #define SPIS_DMA_ADDR_EN BIT(1) #define SPIS_SOFT_RST BIT(0) -#define MTK_SPI_SLAVE_MAX_FIFO_SIZE 512U - struct mtk_spi_slave { struct device *dev; void __iomem *base; @@ -70,10 +70,27 @@ struct mtk_spi_slave { struct completion xfer_done; struct spi_transfer *cur_transfer; bool slave_aborted; + const struct mtk_spi_compatible *dev_comp; +}; + +struct mtk_spi_compatible { + const u32 max_fifo_size; + bool must_rx; +}; + +static const struct mtk_spi_compatible mt2712_compat = { + .max_fifo_size = 512, +}; +static const struct mtk_spi_compatible mt8195_compat = { + .max_fifo_size = 128, + .must_rx = true, }; static const struct of_device_id mtk_spi_slave_of_match[] = { - { .compatible = "mediatek,mt2712-spi-slave", }, + { .compatible = "mediatek,mt2712-spi-slave", + .data = (void *)&mt2712_compat,}, + { .compatible = "mediatek,mt8195-spi-slave", + .data = (void *)&mt8195_compat,}, {} }; MODULE_DEVICE_TABLE(of, mtk_spi_slave_of_match); @@ -272,7 +289,7 @@ static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr, mdata->slave_aborted = false; mdata->cur_transfer = xfer; - if (xfer->len > MTK_SPI_SLAVE_MAX_FIFO_SIZE) + if (xfer->len > mdata->dev_comp->max_fifo_size) return mtk_spi_slave_dma_transfer(ctlr, spi, xfer); else return mtk_spi_slave_fifo_transfer(ctlr, spi, xfer); @@ -369,6 +386,7 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) struct spi_controller *ctlr; struct mtk_spi_slave *mdata; int irq, ret; + const struct of_device_id *of_id; ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata)); if (!ctlr) { @@ -386,7 +404,17 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) ctlr->setup = mtk_spi_slave_setup; ctlr->slave_abort = mtk_slave_abort; + of_id = of_match_node(mtk_spi_slave_of_match, pdev->dev.of_node); + if (!of_id) { + dev_err(&pdev->dev, "failed to probe of_node\n"); + ret = -EINVAL; + goto err_put_ctlr; + } mdata = spi_controller_get_devdata(ctlr); + mdata->dev_comp = of_id->data; + + if (mdata->dev_comp->must_rx) + ctlr->flags = SPI_MASTER_MUST_RX; platform_set_drvdata(pdev, ctlr); diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index 392ec5cfa3d61e41979dc1d116587c4e9fd1875a..ab19068be8675561f2529d5271b77cb2f8d06dfe 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -210,7 +210,7 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) * address. Then we can check the returned register address to validate * data. */ - rd_addr = (val & RD_ADDR_MASK ) >> RD_ADDR_SHIFT; + rd_addr = (val & RD_ADDR_MASK) >> RD_ADDR_SHIFT; if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) { dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n", diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 947e6b9dc9f4d5ab5b43d0bb9b736e8b4ff12594..7e640ccc7e77427cbffa669c621ed5f81c9df9da 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -269,8 +269,9 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) if (qspi->fmode == CCR_FMODE_MM) return stm32_qspi_tx_mm(qspi, op); - else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || - (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) + else if (((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || + (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) && + op->data.nbytes > 4) if (!stm32_qspi_tx_dma(qspi, op)) return 0; @@ -330,7 +331,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) { struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; - u32 ccr, cr, addr_max; + u32 ccr, cr; int timeout, err = 0; dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", @@ -342,18 +343,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) if (err) goto abort; - addr_max = op->addr.val + op->data.nbytes + 1; - - if (op->data.dir == SPI_MEM_DATA_IN) { - if (addr_max < qspi->mm_size && - op->addr.buswidth) - qspi->fmode = CCR_FMODE_MM; - else - qspi->fmode = CCR_FMODE_INDR; - } else { - qspi->fmode = CCR_FMODE_INDW; - } - cr = readl_relaxed(qspi->io_base + QSPI_CR); cr &= ~CR_PRESC_MASK & ~CR_FSEL; cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); @@ -363,8 +352,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) if (op->data.nbytes) writel_relaxed(op->data.nbytes - 1, qspi->io_base + QSPI_DLR); - else - qspi->fmode = CCR_FMODE_INDW; ccr = qspi->fmode; ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); @@ -440,6 +427,11 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) } mutex_lock(&qspi->lock); + if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) + qspi->fmode = CCR_FMODE_INDR; + else + qspi->fmode = CCR_FMODE_INDW; + ret = stm32_qspi_send(mem, op); mutex_unlock(&qspi->lock); @@ -449,6 +441,64 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) return ret; } +static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); + + if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + return -EOPNOTSUPP; + + /* should never happen, as mm_base == null is an error probe exit condition */ + if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + return -EOPNOTSUPP; + + if (!qspi->mm_size) + return -EOPNOTSUPP; + + return 0; +} + +static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); + struct spi_mem_op op; + u32 addr_max; + int ret; + + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) { + pm_runtime_put_noidle(qspi->dev); + return ret; + } + + mutex_lock(&qspi->lock); + /* make a local copy of desc op_tmpl and complete dirmap rdesc + * spi_mem_op template with offs, len and *buf in order to get + * all needed transfer information into struct spi_mem_op + */ + memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); + + op.data.nbytes = len; + op.addr.val = desc->info.offset + offs; + op.data.buf.in = buf; + + addr_max = op.addr.val + op.data.nbytes + 1; + if (addr_max < qspi->mm_size && op.addr.buswidth) + qspi->fmode = CCR_FMODE_MM; + else + qspi->fmode = CCR_FMODE_INDR; + + ret = stm32_qspi_send(desc->mem, &op); + mutex_unlock(&qspi->lock); + + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + + return ret ?: len; +} + static int stm32_qspi_setup(struct spi_device *spi) { struct spi_controller *ctrl = spi->master; @@ -554,7 +604,9 @@ static void stm32_qspi_dma_free(struct stm32_qspi *qspi) * to check supported mode. */ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { - .exec_op = stm32_qspi_exec_op, + .exec_op = stm32_qspi_exec_op, + .dirmap_create = stm32_qspi_dirmap_create, + .dirmap_read = stm32_qspi_dirmap_read, }; static int stm32_qspi_probe(struct platform_device *pdev) @@ -727,21 +779,31 @@ static int __maybe_unused stm32_qspi_suspend(struct device *dev) { pinctrl_pm_select_sleep_state(dev); - return 0; + return pm_runtime_force_suspend(dev); } static int __maybe_unused stm32_qspi_resume(struct device *dev) { struct stm32_qspi *qspi = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; pinctrl_pm_select_default_state(dev); - clk_prepare_enable(qspi->clk); + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); - pm_runtime_mark_last_busy(qspi->dev); - pm_runtime_put_autosuspend(qspi->dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; } diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 25c0764610119050093027e822bd97bbdfef69aa..8ffcffbb81571c98bcc36f0840d18c6c786550d4 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1803,7 +1803,7 @@ static int stm32_spi_probe(struct platform_device *pdev) struct reset_control *rst; int ret; - master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); if (!master) { dev_err(&pdev->dev, "spi master allocation failed\n"); return -ENOMEM; @@ -1821,18 +1821,16 @@ static int stm32_spi_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(spi->base)) { - ret = PTR_ERR(spi->base); - goto err_master_put; - } + if (IS_ERR(spi->base)) + return PTR_ERR(spi->base); spi->phys_addr = (dma_addr_t)res->start; spi->irq = platform_get_irq(pdev, 0); - if (spi->irq <= 0) { - ret = dev_err_probe(&pdev->dev, spi->irq, "failed to get irq\n"); - goto err_master_put; - } + if (spi->irq <= 0) + return dev_err_probe(&pdev->dev, spi->irq, + "failed to get irq\n"); + ret = devm_request_threaded_irq(&pdev->dev, spi->irq, spi->cfg->irq_handler_event, spi->cfg->irq_handler_thread, @@ -1840,20 +1838,20 @@ static int stm32_spi_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq, ret); - goto err_master_put; + return ret; } spi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(spi->clk)) { ret = PTR_ERR(spi->clk); dev_err(&pdev->dev, "clk get failed: %d\n", ret); - goto err_master_put; + return ret; } ret = clk_prepare_enable(spi->clk); if (ret) { dev_err(&pdev->dev, "clk enable failed: %d\n", ret); - goto err_master_put; + return ret; } spi->clk_rate = clk_get_rate(spi->clk); if (!spi->clk_rate) { @@ -1929,7 +1927,7 @@ static int stm32_spi_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - ret = devm_spi_register_master(&pdev->dev, master); + ret = spi_register_master(master); if (ret) { dev_err(&pdev->dev, "spi master registration failed: %d\n", ret); @@ -1949,8 +1947,6 @@ err_dma_release: dma_release_channel(spi->dma_rx); err_clk_disable: clk_disable_unprepare(spi->clk); -err_master_put: - spi_master_put(master); return ret; } @@ -1960,6 +1956,7 @@ static int stm32_spi_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct stm32_spi *spi = spi_master_get_devdata(master); + spi_unregister_master(master); spi->cfg->disable(spi); if (master->dma_tx) @@ -1976,8 +1973,7 @@ static int stm32_spi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int stm32_spi_runtime_suspend(struct device *dev) +static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct stm32_spi *spi = spi_master_get_devdata(master); @@ -1987,7 +1983,7 @@ static int stm32_spi_runtime_suspend(struct device *dev) return pinctrl_pm_select_sleep_state(dev); } -static int stm32_spi_runtime_resume(struct device *dev) +static int __maybe_unused stm32_spi_runtime_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct stm32_spi *spi = spi_master_get_devdata(master); @@ -1999,10 +1995,8 @@ static int stm32_spi_runtime_resume(struct device *dev) return clk_prepare_enable(spi->clk); } -#endif -#ifdef CONFIG_PM_SLEEP -static int stm32_spi_suspend(struct device *dev) +static int __maybe_unused stm32_spi_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); int ret; @@ -2014,7 +2008,7 @@ static int stm32_spi_suspend(struct device *dev) return pm_runtime_force_suspend(dev); } -static int stm32_spi_resume(struct device *dev) +static int __maybe_unused stm32_spi_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct stm32_spi *spi = spi_master_get_devdata(master); @@ -2044,7 +2038,6 @@ static int stm32_spi_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops stm32_spi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(stm32_spi_suspend, stm32_spi_resume) diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index cfb7de73793763023ca42645c25c79359820af5d..2888d8a8dc6d5cb5f9ede2ae84be14ac03aec0ee 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -341,8 +341,7 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master, goto exit; } msg->actual_length += xfer->len; - if (xfer->cs_change && - (xfer->delay_usecs || xfer->delay.value)) { + if (xfer->cs_change && xfer->delay.value) { tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND); spi_transfer_delay_exec(xfer); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 9417385c092175dc4572e541d111670fcd9d7c04..e06aafe169e0cb5333eb800329154c28196253f1 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -733,6 +733,17 @@ static int ti_qspi_runtime_resume(struct device *dev) return 0; } +static void ti_qspi_dma_cleanup(struct ti_qspi *qspi) +{ + if (qspi->rx_bb_addr) + dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE, + qspi->rx_bb_addr, + qspi->rx_bb_dma_addr); + + if (qspi->rx_chan) + dma_release_channel(qspi->rx_chan); +} + static const struct of_device_id ti_qspi_match[] = { {.compatible = "ti,dra7xxx-qspi" }, {.compatible = "ti,am4372-qspi" }, @@ -886,6 +897,8 @@ no_dma: if (!ret) return 0; + ti_qspi_dma_cleanup(qspi); + pm_runtime_disable(&pdev->dev); free_master: spi_master_put(master); @@ -904,12 +917,7 @@ static int ti_qspi_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (qspi->rx_bb_addr) - dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE, - qspi->rx_bb_addr, - qspi->rx_bb_dma_addr); - if (qspi->rx_chan) - dma_release_channel(qspi->rx_chan); + ti_qspi_dma_cleanup(qspi); return 0; } diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index b459e369079f8128d83b152240ea37210f907db4..b8870784fc6eff115c4040169f4662b47303e9bf 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1201,7 +1201,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) if (data->use_dma) { int i; char *save_rx_buf = data->cur_trans->rx_buf; - for (i = 0; i < cnt; i ++) { + + for (i = 0; i < cnt; i++) { pch_spi_handle_dma(data, &bpw); if (!pch_spi_start_transfer(data)) { data->transfer_complete = true; diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index c8fa6ee18ae77b31ef860d31a8b46aa878cd544b..328b6559bb19a2f9240f793e58bc746d941e3959 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -157,6 +157,7 @@ enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; * @data_completion: completion structure */ struct zynqmp_qspi { + struct spi_controller *ctlr; void __iomem *regs; struct clk *refclk; struct clk *pclk; @@ -173,6 +174,7 @@ struct zynqmp_qspi { u32 genfifoentry; enum mode_type mode; struct completion data_completion; + struct mutex op_lock; }; /** @@ -486,24 +488,10 @@ static int zynqmp_qspi_setup_op(struct spi_device *qspi) { struct spi_controller *ctlr = qspi->master; struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); - struct device *dev = &ctlr->dev; - int ret; if (ctlr->busy) return -EBUSY; - ret = clk_enable(xqspi->refclk); - if (ret) { - dev_err(dev, "Cannot enable device clock.\n"); - return ret; - } - - ret = clk_enable(xqspi->pclk); - if (ret) { - dev_err(dev, "Cannot enable APB clock.\n"); - clk_disable(xqspi->refclk); - return ret; - } zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); return 0; @@ -520,18 +508,20 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size) { u32 count = 0, intermediate; - while ((xqspi->bytes_to_transfer > 0) && (count < size)) { - memcpy(&intermediate, xqspi->txbuf, 4); - zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate); - + while ((xqspi->bytes_to_transfer > 0) && (count < size) && (xqspi->txbuf)) { if (xqspi->bytes_to_transfer >= 4) { + memcpy(&intermediate, xqspi->txbuf, 4); xqspi->txbuf += 4; xqspi->bytes_to_transfer -= 4; + count += 4; } else { + memcpy(&intermediate, xqspi->txbuf, + xqspi->bytes_to_transfer); xqspi->txbuf += xqspi->bytes_to_transfer; xqspi->bytes_to_transfer = 0; + count += xqspi->bytes_to_transfer; } - count++; + zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate); } } @@ -579,7 +569,7 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits, genfifoentry |= GQSPI_GENFIFO_DATA_XFER; genfifoentry |= GQSPI_GENFIFO_TX; transfer_len = xqspi->bytes_to_transfer; - } else { + } else if (xqspi->rxbuf) { genfifoentry &= ~GQSPI_GENFIFO_TX; genfifoentry |= GQSPI_GENFIFO_DATA_XFER; genfifoentry |= GQSPI_GENFIFO_RX; @@ -587,6 +577,11 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits, transfer_len = xqspi->dma_rx_bytes; else transfer_len = xqspi->bytes_to_receive; + } else { + /* Sending dummy circles here */ + genfifoentry &= ~(GQSPI_GENFIFO_TX | GQSPI_GENFIFO_RX); + genfifoentry |= GQSPI_GENFIFO_DATA_XFER; + transfer_len = xqspi->bytes_to_transfer; } genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits); xqspi->genfifoentry = genfifoentry; @@ -738,7 +733,7 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) * zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation * @xqspi: xqspi is a pointer to the GQSPI instance. */ -static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) +static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) { u32 rx_bytes, rx_rem, config_reg; dma_addr_t addr; @@ -752,7 +747,7 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg); xqspi->mode = GQSPI_MODE_IO; xqspi->dma_rx_bytes = 0; - return; + return 0; } rx_rem = xqspi->bytes_to_receive % 4; @@ -760,8 +755,10 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf, rx_bytes, DMA_FROM_DEVICE); - if (dma_mapping_error(xqspi->dev, addr)) + if (dma_mapping_error(xqspi->dev, addr)) { dev_err(xqspi->dev, "ERR:rxdma:memory not mapped\n"); + return -ENOMEM; + } xqspi->dma_rx_bytes = rx_bytes; xqspi->dma_addr = addr; @@ -782,6 +779,8 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) /* Write the number of bytes to transfer */ zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_SIZE_OFST, rx_bytes); + + return 0; } /** @@ -818,11 +817,17 @@ static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits, * @genfifoentry: genfifoentry is pointer to the variable in which * GENFIFO mask is returned to calling function */ -static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, +static int zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, u32 genfifoentry) { + int ret; + + ret = zynqmp_qspi_setuprxdma(xqspi); + if (ret) + return ret; zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry); - zynqmp_qspi_setuprxdma(xqspi); + + return 0; } /** @@ -835,10 +840,13 @@ static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, */ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) { - struct spi_controller *ctlr = dev_get_drvdata(dev); - struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); + struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); + struct spi_controller *ctlr = xqspi->ctlr; + int ret; - spi_controller_suspend(ctlr); + ret = spi_controller_suspend(ctlr); + if (ret) + return ret; zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); @@ -856,27 +864,13 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) */ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) { - struct spi_controller *ctlr = dev_get_drvdata(dev); - struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); - int ret = 0; - - ret = clk_enable(xqspi->pclk); - if (ret) { - dev_err(dev, "Cannot enable APB clock.\n"); - return ret; - } + struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); + struct spi_controller *ctlr = xqspi->ctlr; - ret = clk_enable(xqspi->refclk); - if (ret) { - dev_err(dev, "Cannot enable device clock.\n"); - clk_disable(xqspi->pclk); - return ret; - } + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); spi_controller_resume(ctlr); - clk_disable(xqspi->refclk); - clk_disable(xqspi->pclk); return 0; } @@ -890,10 +884,10 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) */ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) { - struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_get_drvdata(dev); + struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); - clk_disable(xqspi->refclk); - clk_disable(xqspi->pclk); + clk_disable_unprepare(xqspi->refclk); + clk_disable_unprepare(xqspi->pclk); return 0; } @@ -908,19 +902,19 @@ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) */ static int __maybe_unused zynqmp_runtime_resume(struct device *dev) { - struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_get_drvdata(dev); + struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); int ret; - ret = clk_enable(xqspi->pclk); + ret = clk_prepare_enable(xqspi->pclk); if (ret) { dev_err(dev, "Cannot enable APB clock.\n"); return ret; } - ret = clk_enable(xqspi->refclk); + ret = clk_prepare_enable(xqspi->refclk); if (ret) { dev_err(dev, "Cannot enable device clock.\n"); - clk_disable(xqspi->pclk); + clk_disable_unprepare(xqspi->pclk); return ret; } @@ -944,25 +938,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, struct zynqmp_qspi *xqspi = spi_controller_get_devdata (mem->spi->master); int err = 0, i; - u8 *tmpbuf; u32 genfifoentry = 0; + u16 opcode = op->cmd.opcode; + u64 opaddr; dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n", op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, op->dummy.buswidth, op->data.buswidth); + mutex_lock(&xqspi->op_lock); zynqmp_qspi_config_op(xqspi, mem->spi); zynqmp_qspi_chipselect(mem->spi, false); genfifoentry |= xqspi->genfifocs; genfifoentry |= xqspi->genfifobus; if (op->cmd.opcode) { - tmpbuf = kzalloc(op->cmd.nbytes, GFP_KERNEL | GFP_DMA); - if (!tmpbuf) - return -ENOMEM; - tmpbuf[0] = op->cmd.opcode; reinit_completion(&xqspi->data_completion); - xqspi->txbuf = tmpbuf; + xqspi->txbuf = &opcode; xqspi->rxbuf = NULL; xqspi->bytes_to_transfer = op->cmd.nbytes; xqspi->bytes_to_receive = 0; @@ -973,16 +965,15 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, GQSPI_IER_GENFIFOEMPTY_MASK | GQSPI_IER_TXNOT_FULL_MASK); - if (!wait_for_completion_interruptible_timeout + if (!wait_for_completion_timeout (&xqspi->data_completion, msecs_to_jiffies(1000))) { err = -ETIMEDOUT; - kfree(tmpbuf); goto return_err; } - kfree(tmpbuf); } if (op->addr.nbytes) { + xqspi->txbuf = &opaddr; for (i = 0; i < op->addr.nbytes; i++) { *(((u8 *)xqspi->txbuf) + i) = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); @@ -1001,7 +992,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, GQSPI_IER_TXEMPTY_MASK | GQSPI_IER_GENFIFOEMPTY_MASK | GQSPI_IER_TXNOT_FULL_MASK); - if (!wait_for_completion_interruptible_timeout + if (!wait_for_completion_timeout (&xqspi->data_completion, msecs_to_jiffies(1000))) { err = -ETIMEDOUT; goto return_err; @@ -1009,32 +1000,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, } if (op->dummy.nbytes) { - tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL | GFP_DMA); - if (!tmpbuf) - return -ENOMEM; - memset(tmpbuf, 0xff, op->dummy.nbytes); - reinit_completion(&xqspi->data_completion); - xqspi->txbuf = tmpbuf; + xqspi->txbuf = NULL; xqspi->rxbuf = NULL; - xqspi->bytes_to_transfer = op->dummy.nbytes; + /* + * xqspi->bytes_to_transfer here represents the dummy circles + * which need to be sent. + */ + xqspi->bytes_to_transfer = op->dummy.nbytes * 8 / op->dummy.buswidth; xqspi->bytes_to_receive = 0; - zynqmp_qspi_write_op(xqspi, op->dummy.buswidth, + /* + * Using op->data.buswidth instead of op->dummy.buswidth here because + * we need to use it to configure the correct SPI mode. + */ + zynqmp_qspi_write_op(xqspi, op->data.buswidth, genfifoentry); zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | GQSPI_CFG_START_GEN_FIFO_MASK); - zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, - GQSPI_IER_TXEMPTY_MASK | - GQSPI_IER_GENFIFOEMPTY_MASK | - GQSPI_IER_TXNOT_FULL_MASK); - if (!wait_for_completion_interruptible_timeout - (&xqspi->data_completion, msecs_to_jiffies(1000))) { - err = -ETIMEDOUT; - kfree(tmpbuf); - goto return_err; - } - - kfree(tmpbuf); } if (op->data.nbytes) { @@ -1059,8 +1041,11 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, xqspi->rxbuf = (u8 *)op->data.buf.in; xqspi->bytes_to_receive = op->data.nbytes; xqspi->bytes_to_transfer = 0; - zynqmp_qspi_read_op(xqspi, op->data.buswidth, + err = zynqmp_qspi_read_op(xqspi, op->data.buswidth, genfifoentry); + if (err) + goto return_err; + zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, zynqmp_gqspi_read (xqspi, GQSPI_CONFIG_OFST) | @@ -1076,7 +1061,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, GQSPI_IER_RXEMPTY_MASK); } } - if (!wait_for_completion_interruptible_timeout + if (!wait_for_completion_timeout (&xqspi->data_completion, msecs_to_jiffies(1000))) err = -ETIMEDOUT; } @@ -1084,6 +1069,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, return_err: zynqmp_qspi_chipselect(mem->spi, true); + mutex_unlock(&xqspi->op_lock); return err; } @@ -1120,6 +1106,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) xqspi = spi_controller_get_devdata(ctlr); xqspi->dev = dev; + xqspi->ctlr = ctlr; platform_set_drvdata(pdev, xqspi); xqspi->regs = devm_platform_ioremap_resource(pdev, 0); @@ -1135,13 +1122,11 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto remove_master; } - init_completion(&xqspi->data_completion); - xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk"); if (IS_ERR(xqspi->refclk)) { dev_err(dev, "ref_clk clock not found.\n"); ret = PTR_ERR(xqspi->refclk); - goto clk_dis_pclk; + goto remove_master; } ret = clk_prepare_enable(xqspi->pclk); @@ -1156,15 +1141,24 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_pclk; } + init_completion(&xqspi->data_completion); + + mutex_init(&xqspi->op_lock); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to pm_runtime_get_sync: %d\n", ret); + goto clk_dis_all; + } + /* QSPI controller initializations */ zynqmp_qspi_init_hw(xqspi); - pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); xqspi->irq = platform_get_irq(pdev, 0); if (xqspi->irq <= 0) { ret = -ENXIO; @@ -1178,6 +1172,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } + dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; ctlr->mem_ops = &zynqmp_qspi_mem_ops; @@ -1187,6 +1182,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; ctlr->dev.of_node = np; + ctlr->auto_runtime_pm = true; ret = devm_spi_register_controller(&pdev->dev, ctlr); if (ret) { @@ -1194,9 +1190,13 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; clk_dis_all: + pm_runtime_put_sync(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(xqspi->refclk); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b2b6ef13c79bf8bea34d5fb3b2769ad2969d3484..f0762a926e72e71b620a4989fb87ad388fc0487d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -676,11 +676,10 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr, proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; - if (chip->properties) { - status = device_add_properties(&proxy->dev, chip->properties); + if (chip->swnode) { + status = device_add_software_node(&proxy->dev, chip->swnode); if (status) { - dev_err(&ctlr->dev, - "failed to add properties to '%s': %d\n", + dev_err(&ctlr->dev, "failed to add software node to '%s': %d\n", chip->modalias, status); goto err_dev_put; } @@ -688,14 +687,12 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr, status = spi_add_device(proxy); if (status < 0) - goto err_remove_props; + goto err_dev_put; return proxy; -err_remove_props: - if (chip->properties) - device_remove_properties(&proxy->dev); err_dev_put: + device_remove_software_node(&proxy->dev); spi_dev_put(proxy); return NULL; } @@ -719,6 +716,7 @@ void spi_unregister_device(struct spi_device *spi) } if (ACPI_COMPANION(&spi->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev)); + device_remove_software_node(&spi->dev); device_unregister(&spi->dev); } EXPORT_SYMBOL_GPL(spi_unregister_device); @@ -755,7 +753,6 @@ static void spi_match_controller_to_boardinfo(struct spi_controller *ctlr, * * The board info passed can safely be __initdata ... but be careful of * any embedded pointers (platform_data, etc), they're copied as-is. - * Device properties are deep-copied though. * * Return: zero on success, else a negative error code. */ @@ -775,12 +772,6 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) struct spi_controller *ctlr; memcpy(&bi->board_info, info, sizeof(*info)); - if (info->properties) { - bi->board_info.properties = - property_entries_dup(info->properties); - if (IS_ERR(bi->board_info.properties)) - return PTR_ERR(bi->board_info.properties); - } mutex_lock(&board_lock); list_add_tail(&bi->list, &board_list); @@ -795,15 +786,15 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) /*-------------------------------------------------------------------------*/ -static void spi_set_cs(struct spi_device *spi, bool enable) +static void spi_set_cs(struct spi_device *spi, bool enable, bool force) { - bool enable1 = enable; + bool activate = enable; /* * Avoid calling into the driver (or doing delays) if the chip select * isn't actually changing from the last time this was called. */ - if ((spi->controller->last_cs_enable == enable) && + if (!force && (spi->controller->last_cs_enable == enable) && (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH))) return; @@ -812,7 +803,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || !spi->controller->set_cs_timing) { - if (enable1) + if (activate) spi_delay_exec(&spi->controller->cs_setup, NULL); else spi_delay_exec(&spi->controller->cs_hold, NULL); @@ -825,8 +816,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (!(spi->mode & SPI_NO_CS)) { if (spi->cs_gpiod) /* polarity handled by gpiolib */ - gpiod_set_value_cansleep(spi->cs_gpiod, - enable1); + gpiod_set_value_cansleep(spi->cs_gpiod, activate); else /* * invert the enable line, as active low is @@ -844,7 +834,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || !spi->controller->set_cs_timing) { - if (!enable1) + if (!activate) spi_delay_exec(&spi->controller->cs_inactive, NULL); } } @@ -1253,7 +1243,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, struct spi_statistics *statm = &ctlr->statistics; struct spi_statistics *stats = &msg->spi->statistics; - spi_set_cs(msg->spi, true); + spi_set_cs(msg->spi, true, false); SPI_STATISTICS_INCREMENT_FIELD(statm, messages); SPI_STATISTICS_INCREMENT_FIELD(stats, messages); @@ -1321,9 +1311,9 @@ fallback_pio: &msg->transfers)) { keep_cs = true; } else { - spi_set_cs(msg->spi, false); + spi_set_cs(msg->spi, false, false); _spi_transfer_cs_change_delay(msg, xfer); - spi_set_cs(msg->spi, true); + spi_set_cs(msg->spi, true, false); } } @@ -1332,7 +1322,7 @@ fallback_pio: out: if (ret != 0 || !keep_cs) - spi_set_cs(msg->spi, false); + spi_set_cs(msg->spi, false, false); if (msg->status == -EINPROGRESS) msg->status = ret; @@ -2497,6 +2487,7 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev, ctlr = __spi_alloc_controller(dev, size, slave); if (ctlr) { + ctlr->devm_allocated = true; *ptr = ctlr; devres_add(dev, ptr); } else { @@ -2560,13 +2551,14 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) unsigned int num_cs_gpios = 0; nb = gpiod_count(dev, "cs"); - ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); - - /* No GPIOs at all is fine, else return the error */ - if (nb == 0 || nb == -ENOENT) - return 0; - else if (nb < 0) + if (nb < 0) { + /* No GPIOs at all is fine, else return the error */ + if (nb == -ENOENT) + return 0; return nb; + } + + ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); cs = devm_kcalloc(dev, ctlr->num_chipselect, sizeof(*cs), GFP_KERNEL); @@ -2803,9 +2795,9 @@ free_bus_id: } EXPORT_SYMBOL_GPL(spi_register_controller); -static void devm_spi_unregister(struct device *dev, void *res) +static void devm_spi_unregister(void *ctlr) { - spi_unregister_controller(*(struct spi_controller **)res); + spi_unregister_controller(ctlr); } /** @@ -2824,30 +2816,16 @@ static void devm_spi_unregister(struct device *dev, void *res) int devm_spi_register_controller(struct device *dev, struct spi_controller *ctlr) { - struct spi_controller **ptr; int ret; - ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - ret = spi_register_controller(ctlr); - if (!ret) { - *ptr = ctlr; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } + if (ret) + return ret; - return ret; + return devm_add_action_or_reset(dev, devm_spi_unregister, ctlr); } EXPORT_SYMBOL_GPL(devm_spi_register_controller); -static int devm_spi_match_controller(struct device *dev, void *res, void *ctlr) -{ - return *(struct spi_controller **)res == ctlr; -} - static int __unregister(struct device *dev, void *null) { spi_unregister_device(to_spi_device(dev)); @@ -2894,8 +2872,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(). */ - if (!devres_find(ctlr->dev.parent, devm_spi_release_controller, - devm_spi_match_controller, ctlr)) + if (!ctlr->devm_allocated) put_device(&ctlr->dev); /* free bus id */ @@ -3179,7 +3156,6 @@ struct spi_replaced_transfers *spi_replace_transfers( /* clear cs_change and delay for all but the last */ if (i) { xfer->cs_change = false; - xfer->delay_usecs = 0; xfer->delay.value = 0; } } @@ -3403,8 +3379,15 @@ int spi_setup(struct spi_device *spi) mutex_lock(&spi->controller->io_mutex); - if (spi->controller->setup) + if (spi->controller->setup) { status = spi->controller->setup(spi); + if (status) { + mutex_unlock(&spi->controller->io_mutex); + dev_err(&spi->controller->dev, "Failed to setup device: %d\n", + status); + return status; + } + } if (spi->controller->auto_runtime_pm && spi->controller->set_cs) { status = pm_runtime_get_sync(spi->controller->dev.parent); @@ -3424,11 +3407,11 @@ int spi_setup(struct spi_device *spi) */ status = 0; - spi_set_cs(spi, false); + spi_set_cs(spi, false, true); pm_runtime_mark_last_busy(spi->controller->dev.parent); pm_runtime_put_autosuspend(spi->controller->dev.parent); } else { - spi_set_cs(spi, false); + spi_set_cs(spi, false, true); } mutex_unlock(&spi->controller->io_mutex); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 8cb4d923aeaab3b9c67332f86b7fa72dc924b484..f56e0e975a4691209a13e008c4f5197af3eea509 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -683,6 +683,7 @@ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "dh,dhcom-board" }, { .compatible = "menlo,m53cpld" }, { .compatible = "cisco,spi-petra" }, + { .compatible = "micron,spi-authenta" }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index b22f73d7bfc42eedfdeb5fbd72a4aa0bc02cab9f..808e78d6cd98617495843e421a2f9fa5cac68a45 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -26,8 +26,6 @@ if STAGING source "drivers/staging/wlan-ng/Kconfig" -source "drivers/staging/comedi/Kconfig" - source "drivers/staging/olpc_dcon/Kconfig" source "drivers/staging/rtl8192u/Kconfig" @@ -98,8 +96,6 @@ source "drivers/staging/ralink-gdma/Kconfig" source "drivers/staging/mt7621-dts/Kconfig" -source "drivers/staging/gasket/Kconfig" - source "drivers/staging/axis-fifo/Kconfig" source "drivers/staging/fieldbus/Kconfig" @@ -108,8 +104,6 @@ source "drivers/staging/kpc2000/Kconfig" source "drivers/staging/qlge/Kconfig" -source "drivers/staging/wimax/Kconfig" - source "drivers/staging/wfx/Kconfig" source "drivers/staging/hikey9xx/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2245059e69c701cbe2b378ee52b40ec6626dfffa..5a871f0ff2f4bda66528eb4363b6ad4d5c26492c 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -3,7 +3,6 @@ obj-y += media/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ -obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ obj-$(CONFIG_RTL8192U) += rtl8192u/ obj-$(CONFIG_RTL8192E) += rtl8192e/ @@ -39,11 +38,9 @@ obj-$(CONFIG_PCI_MT7621) += mt7621-pci/ obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ obj-$(CONFIG_DMA_RALINK) += ralink-gdma/ obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ -obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ obj-$(CONFIG_KPC2000) += kpc2000/ obj-$(CONFIG_QLGE) += qlge/ -obj-$(CONFIG_WIMAX) += wimax/ obj-$(CONFIG_WFX) += wfx/ obj-y += hikey9xx/ diff --git a/drivers/staging/android/uapi/ashmem.h b/drivers/staging/android/uapi/ashmem.h index 5442e0019dcd933213e17d95297ad6c4dba47007..134efacb32190cec25ba4aa965cb44b0d53911f3 100644 --- a/drivers/staging/android/uapi/ashmem.h +++ b/drivers/staging/android/uapi/ashmem.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */ /* - * drivers/staging/android/uapi/ashmem.h - * * Copyright 2008 Google Inc. * Author: Robert Love */ diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 2bb1c2e9cb57139a4bda4dd8f9a38f37e63f3193..ed92810897389eea8f0dcc0ea6262dc0d48846f8 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -853,7 +853,6 @@ static int axis_fifo_probe(struct platform_device *pdev) fifo->base_addr = devm_ioremap_resource(fifo->dt_device, r_mem); if (IS_ERR(fifo->base_addr)) { rc = PTR_ERR(fifo->base_addr); - dev_err(fifo->dt_device, "can't remap IO resource (%d)\n", rc); goto err_initial; } diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c index e52a64be93f3e1bc33578f04f5b3251d56ba07ae..39367712ef540ab62ff6c21329a2cd7f111e32b3 100644 --- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c +++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c @@ -15,6 +15,7 @@ #include <linux/of.h> #include <linux/module.h> #include <linux/err.h> +#include <linux/iopoll.h> #define WZRD_NUM_OUTPUTS 7 #define WZRD_ACLK_MAX_FREQ 250000000UL @@ -26,19 +27,41 @@ #define WZRD_CLKFBOUT_MULT_SHIFT 8 #define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT) +#define WZRD_CLKFBOUT_FRAC_SHIFT 16 +#define WZRD_CLKFBOUT_FRAC_MASK (0x3ff << WZRD_CLKFBOUT_FRAC_SHIFT) #define WZRD_DIVCLK_DIVIDE_SHIFT 0 #define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) #define WZRD_CLKOUT_DIVIDE_SHIFT 0 +#define WZRD_CLKOUT_DIVIDE_WIDTH 8 #define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) +#define WZRD_CLKOUT_FRAC_SHIFT 8 +#define WZRD_CLKOUT_FRAC_MASK 0x3ff + +#define WZRD_DR_MAX_INT_DIV_VALUE 255 +#define WZRD_DR_STATUS_REG_OFFSET 0x04 +#define WZRD_DR_LOCK_BIT_MASK 0x00000001 +#define WZRD_DR_INIT_REG_OFFSET 0x25C +#define WZRD_DR_DIV_TO_PHASE_OFFSET 4 +#define WZRD_DR_BEGIN_DYNA_RECONF 0x03 + +#define WZRD_USEC_POLL 10 +#define WZRD_TIMEOUT_POLL 1000 +/* Get the mask from width */ +#define div_mask(width) ((1 << (width)) - 1) + +/* Extract divider instance from clock hardware instance */ +#define to_clk_wzrd_divider(_hw) container_of(_hw, struct clk_wzrd_divider, hw) enum clk_wzrd_int_clks { wzrd_clk_mul, wzrd_clk_mul_div, + wzrd_clk_mul_frac, wzrd_clk_int_max }; /** - * struct clk_wzrd: + * struct clk_wzrd - Clock wizard private data structure + * * @clk_data: Clock data * @nb: Notifier block * @base: Memory base @@ -61,6 +84,29 @@ struct clk_wzrd { bool suspended; }; +/** + * struct clk_wzrd_divider - clock divider specific to clk_wzrd + * + * @hw: handle between common and hardware-specific interfaces + * @base: base address of register containing the divider + * @offset: offset address of register containing the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @flags: clk_wzrd divider flags + * @table: array of value/divider pairs, last entry should have div = 0 + * @lock: register lock + */ +struct clk_wzrd_divider { + struct clk_hw hw; + void __iomem *base; + u16 offset; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; + spinlock_t *lock; /* divider lock */ +}; + #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb) /* maximum frequencies for input/output clocks per speed grade */ @@ -70,6 +116,242 @@ static const unsigned long clk_wzrd_max_freq[] = { 1066000000UL }; +/* spin lock variable for clk_wzrd */ +static DEFINE_SPINLOCK(clkwzrd_lock); + +static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + unsigned int val; + + val = readl(div_addr) >> divider->shift; + val &= div_mask(divider->width); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + +static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int err; + u32 value; + unsigned long flags = 0; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + value = DIV_ROUND_CLOSEST(parent_rate, rate); + + /* Cap the value to max */ + min_t(u32, value, WZRD_DR_MAX_INT_DIV_VALUE); + + /* Set divisor and clear phase offset */ + writel(value, div_addr); + writel(0x00, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET); + + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + goto err_reconfig; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_REG_OFFSET); + + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +err_reconfig: + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + return err; +} + +static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u8 div; + + /* + * since we don't change parent rate we just round rate to closest + * achievable + */ + div = DIV_ROUND_CLOSEST(*prate, rate); + + return *prate / div; +} + +static const struct clk_ops clk_wzrd_clk_divider_ops = { + .round_rate = clk_wzrd_round_rate, + .set_rate = clk_wzrd_dynamic_reconfig, + .recalc_rate = clk_wzrd_recalc_rate, +}; + +static unsigned long clk_wzrd_recalc_ratef(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned int val; + u32 div, frac; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + + val = readl(div_addr); + div = val & div_mask(divider->width); + frac = (val >> WZRD_CLKOUT_FRAC_SHIFT) & WZRD_CLKOUT_FRAC_MASK; + + return mult_frac(parent_rate, 1000, (div * 1000) + frac); +} + +static int clk_wzrd_dynamic_reconfig_f(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int err; + u32 value, pre; + unsigned long rate_div, f, clockout0_div; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + + rate_div = ((parent_rate * 1000) / rate); + clockout0_div = rate_div / 1000; + + pre = DIV_ROUND_CLOSEST((parent_rate * 1000), rate); + f = (u32)(pre - (clockout0_div * 1000)); + f = f & WZRD_CLKOUT_FRAC_MASK; + f = f << WZRD_CLKOUT_DIVIDE_WIDTH; + + value = (f | (clockout0_div & WZRD_CLKOUT_DIVIDE_MASK)); + + /* Set divisor and clear phase offset */ + writel(value, div_addr); + writel(0x0, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET); + + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + return err; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_REG_OFFSET); + + /* Check status register */ + return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +} + +static long clk_wzrd_round_rate_f(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return rate; +} + +static const struct clk_ops clk_wzrd_clk_divider_ops_f = { + .round_rate = clk_wzrd_round_rate_f, + .set_rate = clk_wzrd_dynamic_reconfig_f, + .recalc_rate = clk_wzrd_recalc_ratef, +}; + +static struct clk *clk_wzrd_register_divf(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, u16 offset, + u8 shift, u8 width, + u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_wzrd_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + + init.ops = &clk_wzrd_clk_divider_ops_f; + + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->base = base; + div->offset = offset; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + hw = &div->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + return ERR_PTR(ret); + + return hw->clk; +} + +static struct clk *clk_wzrd_register_divider(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, u16 offset, + u8 shift, u8 width, + u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_wzrd_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_wzrd_clk_divider_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->base = base; + div->offset = offset; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + hw = &div->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + hw = ERR_PTR(ret); + + return hw->clk; +} + static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event, void *data) { @@ -131,11 +413,14 @@ static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend, static int clk_wzrd_probe(struct platform_device *pdev) { int i, ret; - u32 reg; + u32 reg, reg_f, mult; unsigned long rate; const char *clk_name; + void __iomem *ctrl_reg; struct clk_wzrd *clk_wzrd; struct device_node *np = pdev->dev.of_node; + int nr_outputs; + unsigned long flags = 0; clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); if (!clk_wzrd) @@ -146,7 +431,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) if (IS_ERR(clk_wzrd->base)) return PTR_ERR(clk_wzrd->base); - ret = of_property_read_u32(np, "speed-grade", &clk_wzrd->speed_grade); + 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", @@ -181,46 +466,50 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } - /* we don't support fractional div/mul yet */ - reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & - WZRD_CLKFBOUT_FRAC_EN; - reg |= readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2)) & - WZRD_CLKOUT0_FRAC_EN; - if (reg) - dev_warn(&pdev->dev, "fractional div/mul not supported\n"); - - /* register multiplier */ - reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & - WZRD_CLKFBOUT_MULT_MASK) >> WZRD_CLKFBOUT_MULT_SHIFT; + reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)); + reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; + reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; + + reg = reg & WZRD_CLKFBOUT_MULT_MASK; + reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; + mult = (reg * 1000) + reg_f; clk_name = kasprintf(GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; goto err_disable_clk; } + + ret = of_property_read_u32(np, "nr-outputs", &nr_outputs); + if (ret || nr_outputs > WZRD_NUM_OUTPUTS) { + ret = -EINVAL; + goto err_disable_clk; + } + if (nr_outputs == 1) + flags = CLK_SET_RATE_PARENT; + clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clk_in1), - 0, reg, 1); - kfree(clk_name); + 0, mult, 1000); 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; } - /* register div */ - reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & - WZRD_DIVCLK_DIVIDE_MASK) >> WZRD_DIVCLK_DIVIDE_SHIFT; clk_name = kasprintf(GFP_KERNEL, "%s_mul_div", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; goto err_rm_int_clk; } - clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor + ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(0); + /* register div */ + 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]), - 0, 1, reg); + 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]); @@ -228,25 +517,37 @@ static int clk_wzrd_probe(struct platform_device *pdev) } /* register div per output */ - for (i = WZRD_NUM_OUTPUTS - 1; i >= 0 ; i--) { + for (i = nr_outputs - 1; i >= 0 ; i--) { const char *clkout_name; - if (of_property_read_string_index(np, "clock-output-names", i, - &clkout_name)) { - dev_err(&pdev->dev, - "clock output name not specified\n"); - ret = -EINVAL; - goto err_rm_int_clks; + clkout_name = kasprintf(GFP_KERNEL, "%s_out%d", dev_name(&pdev->dev), i); + if (!clkout_name) { + ret = -ENOMEM; + goto err_rm_int_clk; } - reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2) + i * 12); - reg &= WZRD_CLKOUT_DIVIDE_MASK; - reg >>= WZRD_CLKOUT_DIVIDE_SHIFT; - clk_wzrd->clkout[i] = clk_register_fixed_factor - (&pdev->dev, clkout_name, clk_name, 0, 1, reg); + + if (!i) + clk_wzrd->clkout[i] = clk_wzrd_register_divf + (&pdev->dev, clkout_name, + clk_name, flags, + clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + NULL, &clkwzrd_lock); + else + clk_wzrd->clkout[i] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, + clk_name, 0, + clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + NULL, &clkwzrd_lock); if (IS_ERR(clk_wzrd->clkout[i])) { int j; - for (j = i + 1; j < WZRD_NUM_OUTPUTS; 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"); diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 3536c03ff523596f54560ee31e30b4800de933bd..741147a4f0fe4ee262eb38e0d144ddd914e91a7f 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -38,7 +38,6 @@ static struct gpio_desc *vbus_gpio; static int vbus_irq; static const char driver_name[] = "emxx_udc"; -static const char driver_desc[] = DRIVER_DESC; /*===========================================================================*/ /* Prototype */ diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c index 26e52cc2de64df72ec2c08f4aeadb0e1016dbefa..39e8d28066cbe1b06ea94681b99c2cbf244a872e 100644 --- a/drivers/staging/fbtft/fbtft-sysfs.c +++ b/drivers/staging/fbtft/fbtft-sysfs.c @@ -199,7 +199,7 @@ static ssize_t show_debug(struct device *device, struct fb_info *fb_info = dev_get_drvdata(device); struct fbtft_par *par = fb_info->par; - return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug); + return sysfs_emit(buf, "%lu\n", par->debug); } static struct device_attribute debug_device_attr = diff --git a/drivers/staging/fieldbus/anybuss/host.c b/drivers/staging/fieldbus/anybuss/host.c index 549cb7d51af81dd677007fa66b4829feba39eb87..c97df91124a443abe9752fa69943b04b8f57bf77 100644 --- a/drivers/staging/fieldbus/anybuss/host.c +++ b/drivers/staging/fieldbus/anybuss/host.c @@ -1406,32 +1406,26 @@ void anybuss_host_common_remove(struct anybuss_host *host) } EXPORT_SYMBOL_GPL(anybuss_host_common_remove); -static void host_release(struct device *dev, void *res) +static void host_release(void *res) { - struct anybuss_host **dr = res; - - anybuss_host_common_remove(*dr); + 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 **dr; struct anybuss_host *host; - - dr = devres_alloc(host_release, sizeof(struct anybuss_host *), - GFP_KERNEL); - if (!dr) - return ERR_PTR(-ENOMEM); + int ret; host = anybuss_host_common_probe(dev, ops); - if (IS_ERR(host)) { - devres_free(dr); + if (IS_ERR(host)) return host; - } - *dr = host; - devres_add(dev, dr); + + 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); diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index c368082aae1aa87b33605587788f0ee2f608522e..1ee6382cafc4293665ddc5f1f07bd2dcd0347f82 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -1218,13 +1218,12 @@ static int get_serial_info(struct tty_struct *tty, struct fwtty_port *port = tty->driver_data; mutex_lock(&port->port.mutex); - ss->type = PORT_UNKNOWN; - ss->line = port->port.tty->index; - ss->flags = port->port.flags; - ss->xmit_fifo_size = FWTTY_PORT_TXFIFO_LEN; + ss->line = port->index; ss->baud_base = 400000000; - ss->close_delay = port->port.close_delay; + ss->close_delay = jiffies_to_msecs(port->port.close_delay) / 10; + ss->closing_wait = 3000; mutex_unlock(&port->port.mutex); + return 0; } @@ -1232,20 +1231,20 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct fwtty_port *port = tty->driver_data; + unsigned int cdelay; - if (ss->irq != 0 || ss->port != 0 || ss->custom_divisor != 0 || - ss->baud_base != 400000000) - return -EPERM; + cdelay = msecs_to_jiffies(ss->close_delay * 10); mutex_lock(&port->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if (((ss->flags & ~ASYNC_USR_MASK) != + if (cdelay != port->port.close_delay || + ((ss->flags & ~ASYNC_USR_MASK) != (port->port.flags & ~ASYNC_USR_MASK))) { mutex_unlock(&port->port.mutex); return -EPERM; } } - port->port.close_delay = ss->close_delay * HZ / 100; + port->port.close_delay = cdelay; mutex_unlock(&port->port.mutex); return 0; @@ -1318,8 +1317,8 @@ static int fwtty_break_ctl(struct tty_struct *tty, int state) if (state == -1) { set_bit(STOP_TX, &port->flags); ret = wait_event_interruptible_timeout(port->wait_tx, - !test_bit(IN_TX, &port->flags), - 10); + !test_bit(IN_TX, &port->flags), + 10); if (ret == 0 || ret == -ERESTARTSYS) { clear_bit(STOP_TX, &port->flags); fwtty_restart_tx(port); @@ -2632,7 +2631,7 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer, rcode = RCODE_COMPLETE; - fwtty_dbg(&peer->unit, "mgmt: hdr.code: %04hx\n", pkt->hdr.code); + fwtty_dbg(&peer->unit, "mgmt: hdr.code: %04x\n", pkt->hdr.code); switch (be16_to_cpu(pkt->hdr.code) & FWSC_CODE_MASK) { case FWSC_VIRT_CABLE_PLUG: diff --git a/drivers/staging/gasket/Kconfig b/drivers/staging/gasket/Kconfig deleted file mode 100644 index d9bef8ca41ef7c6cd58d2cb521bf96872fdc048d..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -menu "Gasket devices" - -config STAGING_GASKET_FRAMEWORK - tristate "Gasket framework" - depends on PCI && (X86_64 || ARM64) - help - This framework supports Gasket-compatible devices, such as Apex. - It is required for any of the following module(s). - - To compile this driver as a module, choose M here. The module - will be called "gasket". - -config STAGING_APEX_DRIVER - tristate "Apex Driver" - depends on STAGING_GASKET_FRAMEWORK - help - This driver supports the Apex Edge TPU device. See - https://cloud.google.com/edge-tpu/ for more information. - Say Y if you want to include this driver in the kernel. - - To compile this driver as a module, choose M here. The module - will be called "apex". - -endmenu diff --git a/drivers/staging/gasket/Makefile b/drivers/staging/gasket/Makefile deleted file mode 100644 index ce03e256f501d72fd8a01b37be0f5979a4ca66dc..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Gasket framework and dependent drivers. -# - -obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket.o -obj-$(CONFIG_STAGING_APEX_DRIVER) += apex.o - -gasket-objs := gasket_core.o gasket_ioctl.o gasket_interrupt.o gasket_page_table.o gasket_sysfs.o -apex-objs := apex_driver.o diff --git a/drivers/staging/gasket/TODO b/drivers/staging/gasket/TODO deleted file mode 100644 index 5b1865f8af2d9f46014451e0da4ecc9b3b423c03..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/TODO +++ /dev/null @@ -1,22 +0,0 @@ -This is a list of things that need to be done to get this driver out of the -staging directory. - -- Implement the gasket framework's functionality through UIO instead of - introducing a new user-space drivers framework that is quite similar. - - UIO provides the necessary bits to implement user-space drivers. Meanwhile - the gasket APIs adds some extra conveniences like PCI BAR mapping, and - MSI interrupts. Add these features to the UIO subsystem, then re-implement - the Apex driver as a basic UIO driver instead (include/linux/uio_driver.h) - -- Document sysfs files with Documentation/ABI/ entries. - -- Use misc interface instead of major number for driver version description. - -- Add descriptions of module_param's - -- apex_get_status() should actually check status. - -- "drivers" should never be dealing with "raw" sysfs calls or mess around with - kobjects at all. The driver core should handle all of this for you - automaically. There should not be a need for raw attribute macros. diff --git a/drivers/staging/gasket/apex.h b/drivers/staging/gasket/apex.h deleted file mode 100644 index 3bbceffff5e41b628720220df47045173274132f..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/apex.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Apex kernel-userspace interface definitions. - * - * Copyright (C) 2018 Google, Inc. - */ -#ifndef __APEX_H__ -#define __APEX_H__ - -#include <linux/ioctl.h> - -/* Clock Gating ioctl. */ -struct apex_gate_clock_ioctl { - /* Enter or leave clock gated state. */ - u64 enable; - - /* If set, enter clock gating state, regardless of custom block's - * internal idle state - */ - u64 force_idle; -}; - -/* Base number for all Apex-common IOCTLs */ -#define APEX_IOCTL_BASE 0x7F - -/* Enable/Disable clock gating. */ -#define APEX_IOCTL_GATE_CLOCK \ - _IOW(APEX_IOCTL_BASE, 0, struct apex_gate_clock_ioctl) - -#endif /* __APEX_H__ */ diff --git a/drivers/staging/gasket/apex_driver.c b/drivers/staging/gasket/apex_driver.c deleted file mode 100644 index f12f81c8dd2fb68bfd50ea16d79aa6bc84c2f6f6..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/apex_driver.c +++ /dev/null @@ -1,726 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Driver for the Apex chip. - * - * Copyright (C) 2018 Google, Inc. - */ - -#include <linux/compiler.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pci.h> -#include <linux/printk.h> -#include <linux/sched.h> -#include <linux/uaccess.h> - -#include "apex.h" - -#include "gasket_core.h" -#include "gasket_interrupt.h" -#include "gasket_page_table.h" -#include "gasket_sysfs.h" - -/* Constants */ -#define APEX_DEVICE_NAME "Apex" -#define APEX_DRIVER_VERSION "1.0" - -/* CSRs are in BAR 2. */ -#define APEX_BAR_INDEX 2 - -#define APEX_PCI_VENDOR_ID 0x1ac1 -#define APEX_PCI_DEVICE_ID 0x089a - -/* Bar Offsets. */ -#define APEX_BAR_OFFSET 0 -#define APEX_CM_OFFSET 0x1000000 - -/* The sizes of each Apex BAR 2. */ -#define APEX_BAR_BYTES 0x100000 -#define APEX_CH_MEM_BYTES (PAGE_SIZE * MAX_NUM_COHERENT_PAGES) - -/* The number of user-mappable memory ranges in BAR2 of a Apex chip. */ -#define NUM_REGIONS 3 - -/* The number of nodes in a Apex chip. */ -#define NUM_NODES 1 - -/* - * The total number of entries in the page table. Should match the value read - * from the register APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE_SIZE. - */ -#define APEX_PAGE_TABLE_TOTAL_ENTRIES 8192 - -#define APEX_EXTENDED_SHIFT 63 /* Extended address bit position. */ - -/* Check reset 120 times */ -#define APEX_RESET_RETRY 120 -/* Wait 100 ms between checks. Total 12 sec wait maximum. */ -#define APEX_RESET_DELAY 100 - -/* Enumeration of the supported sysfs entries. */ -enum sysfs_attribute_type { - ATTR_KERNEL_HIB_PAGE_TABLE_SIZE, - ATTR_KERNEL_HIB_SIMPLE_PAGE_TABLE_SIZE, - ATTR_KERNEL_HIB_NUM_ACTIVE_PAGES, -}; - -/* - * Register offsets into BAR2 memory. - * Only values necessary for driver implementation are defined. - */ -enum apex_bar2_regs { - APEX_BAR2_REG_SCU_BASE = 0x1A300, - APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE_SIZE = 0x46000, - APEX_BAR2_REG_KERNEL_HIB_EXTENDED_TABLE = 0x46008, - APEX_BAR2_REG_KERNEL_HIB_TRANSLATION_ENABLE = 0x46010, - APEX_BAR2_REG_KERNEL_HIB_INSTR_QUEUE_INTVECCTL = 0x46018, - APEX_BAR2_REG_KERNEL_HIB_INPUT_ACTV_QUEUE_INTVECCTL = 0x46020, - APEX_BAR2_REG_KERNEL_HIB_PARAM_QUEUE_INTVECCTL = 0x46028, - APEX_BAR2_REG_KERNEL_HIB_OUTPUT_ACTV_QUEUE_INTVECCTL = 0x46030, - APEX_BAR2_REG_KERNEL_HIB_SC_HOST_INTVECCTL = 0x46038, - APEX_BAR2_REG_KERNEL_HIB_TOP_LEVEL_INTVECCTL = 0x46040, - APEX_BAR2_REG_KERNEL_HIB_FATAL_ERR_INTVECCTL = 0x46048, - APEX_BAR2_REG_KERNEL_HIB_DMA_PAUSE = 0x46050, - APEX_BAR2_REG_KERNEL_HIB_DMA_PAUSE_MASK = 0x46058, - APEX_BAR2_REG_KERNEL_HIB_STATUS_BLOCK_DELAY = 0x46060, - APEX_BAR2_REG_KERNEL_HIB_MSIX_PENDING_BIT_ARRAY0 = 0x46068, - APEX_BAR2_REG_KERNEL_HIB_MSIX_PENDING_BIT_ARRAY1 = 0x46070, - APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE_INIT = 0x46078, - APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE_INIT = 0x46080, - APEX_BAR2_REG_KERNEL_WIRE_INT_PENDING_BIT_ARRAY = 0x48778, - APEX_BAR2_REG_KERNEL_WIRE_INT_MASK_ARRAY = 0x48780, - APEX_BAR2_REG_USER_HIB_DMA_PAUSE = 0x486D8, - APEX_BAR2_REG_USER_HIB_DMA_PAUSED = 0x486E0, - APEX_BAR2_REG_IDLEGENERATOR_IDLEGEN_IDLEREGISTER = 0x4A000, - APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE = 0x50000, - - /* Error registers - Used mostly for debug */ - APEX_BAR2_REG_USER_HIB_ERROR_STATUS = 0x86f0, - APEX_BAR2_REG_SCALAR_CORE_ERROR_STATUS = 0x41a0, -}; - -/* Addresses for packed registers. */ -#define APEX_BAR2_REG_AXI_QUIESCE (APEX_BAR2_REG_SCU_BASE + 0x2C) -#define APEX_BAR2_REG_GCB_CLOCK_GATE (APEX_BAR2_REG_SCU_BASE + 0x14) -#define APEX_BAR2_REG_SCU_0 (APEX_BAR2_REG_SCU_BASE + 0xc) -#define APEX_BAR2_REG_SCU_1 (APEX_BAR2_REG_SCU_BASE + 0x10) -#define APEX_BAR2_REG_SCU_2 (APEX_BAR2_REG_SCU_BASE + 0x14) -#define APEX_BAR2_REG_SCU_3 (APEX_BAR2_REG_SCU_BASE + 0x18) -#define APEX_BAR2_REG_SCU_4 (APEX_BAR2_REG_SCU_BASE + 0x1c) -#define APEX_BAR2_REG_SCU_5 (APEX_BAR2_REG_SCU_BASE + 0x20) - -#define SCU3_RG_PWR_STATE_OVR_BIT_OFFSET 26 -#define SCU3_RG_PWR_STATE_OVR_MASK_WIDTH 2 -#define SCU3_CUR_RST_GCB_BIT_MASK 0x10 -#define SCU2_RG_RST_GCB_BIT_MASK 0xc - -/* Configuration for page table. */ -static struct gasket_page_table_config apex_page_table_configs[NUM_NODES] = { - { - .id = 0, - .mode = GASKET_PAGE_TABLE_MODE_NORMAL, - .total_entries = APEX_PAGE_TABLE_TOTAL_ENTRIES, - .base_reg = APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE, - .extended_reg = APEX_BAR2_REG_KERNEL_HIB_EXTENDED_TABLE, - .extended_bit = APEX_EXTENDED_SHIFT, - }, -}; - -/* The regions in the BAR2 space that can be mapped into user space. */ -static const struct gasket_mappable_region mappable_regions[NUM_REGIONS] = { - { 0x40000, 0x1000 }, - { 0x44000, 0x1000 }, - { 0x48000, 0x1000 }, -}; - -/* Gasket device interrupts enums must be dense (i.e., no empty slots). */ -enum apex_interrupt { - APEX_INTERRUPT_INSTR_QUEUE = 0, - APEX_INTERRUPT_INPUT_ACTV_QUEUE = 1, - APEX_INTERRUPT_PARAM_QUEUE = 2, - APEX_INTERRUPT_OUTPUT_ACTV_QUEUE = 3, - APEX_INTERRUPT_SC_HOST_0 = 4, - APEX_INTERRUPT_SC_HOST_1 = 5, - APEX_INTERRUPT_SC_HOST_2 = 6, - APEX_INTERRUPT_SC_HOST_3 = 7, - APEX_INTERRUPT_TOP_LEVEL_0 = 8, - APEX_INTERRUPT_TOP_LEVEL_1 = 9, - APEX_INTERRUPT_TOP_LEVEL_2 = 10, - APEX_INTERRUPT_TOP_LEVEL_3 = 11, - APEX_INTERRUPT_FATAL_ERR = 12, - APEX_INTERRUPT_COUNT = 13, -}; - -/* Interrupt descriptors for Apex */ -static struct gasket_interrupt_desc apex_interrupts[] = { - { - APEX_INTERRUPT_INSTR_QUEUE, - APEX_BAR2_REG_KERNEL_HIB_INSTR_QUEUE_INTVECCTL, - UNPACKED, - }, - { - APEX_INTERRUPT_INPUT_ACTV_QUEUE, - APEX_BAR2_REG_KERNEL_HIB_INPUT_ACTV_QUEUE_INTVECCTL, - UNPACKED - }, - { - APEX_INTERRUPT_PARAM_QUEUE, - APEX_BAR2_REG_KERNEL_HIB_PARAM_QUEUE_INTVECCTL, - UNPACKED - }, - { - APEX_INTERRUPT_OUTPUT_ACTV_QUEUE, - APEX_BAR2_REG_KERNEL_HIB_OUTPUT_ACTV_QUEUE_INTVECCTL, - UNPACKED - }, - { - APEX_INTERRUPT_SC_HOST_0, - APEX_BAR2_REG_KERNEL_HIB_SC_HOST_INTVECCTL, - PACK_0 - }, - { - APEX_INTERRUPT_SC_HOST_1, - APEX_BAR2_REG_KERNEL_HIB_SC_HOST_INTVECCTL, - PACK_1 - }, - { - APEX_INTERRUPT_SC_HOST_2, - APEX_BAR2_REG_KERNEL_HIB_SC_HOST_INTVECCTL, - PACK_2 - }, - { - APEX_INTERRUPT_SC_HOST_3, - APEX_BAR2_REG_KERNEL_HIB_SC_HOST_INTVECCTL, - PACK_3 - }, - { - APEX_INTERRUPT_TOP_LEVEL_0, - APEX_BAR2_REG_KERNEL_HIB_TOP_LEVEL_INTVECCTL, - PACK_0 - }, - { - APEX_INTERRUPT_TOP_LEVEL_1, - APEX_BAR2_REG_KERNEL_HIB_TOP_LEVEL_INTVECCTL, - PACK_1 - }, - { - APEX_INTERRUPT_TOP_LEVEL_2, - APEX_BAR2_REG_KERNEL_HIB_TOP_LEVEL_INTVECCTL, - PACK_2 - }, - { - APEX_INTERRUPT_TOP_LEVEL_3, - APEX_BAR2_REG_KERNEL_HIB_TOP_LEVEL_INTVECCTL, - PACK_3 - }, - { - APEX_INTERRUPT_FATAL_ERR, - APEX_BAR2_REG_KERNEL_HIB_FATAL_ERR_INTVECCTL, - UNPACKED - }, -}; - -/* Allows device to enter power save upon driver close(). */ -static int allow_power_save = 1; - -/* Allows SW based clock gating. */ -static int allow_sw_clock_gating; - -/* Allows HW based clock gating. */ -/* Note: this is not mutual exclusive with SW clock gating. */ -static int allow_hw_clock_gating = 1; - -/* Act as if only GCB is instantiated. */ -static int bypass_top_level; - -module_param(allow_power_save, int, 0644); -module_param(allow_sw_clock_gating, int, 0644); -module_param(allow_hw_clock_gating, int, 0644); -module_param(bypass_top_level, int, 0644); - -/* Check the device status registers and return device status ALIVE or DEAD. */ -static int apex_get_status(struct gasket_dev *gasket_dev) -{ - /* TODO: Check device status. */ - return GASKET_STATUS_ALIVE; -} - -/* Enter GCB reset state. */ -static int apex_enter_reset(struct gasket_dev *gasket_dev) -{ - if (bypass_top_level) - return 0; - - /* - * Software reset: - * Enable sleep mode - * - Software force GCB idle - * - Enable GCB idle - */ - gasket_read_modify_write_64(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_IDLEGENERATOR_IDLEGEN_IDLEREGISTER, - 0x0, 1, 32); - - /* - Initiate DMA pause */ - gasket_dev_write_64(gasket_dev, 1, APEX_BAR_INDEX, - APEX_BAR2_REG_USER_HIB_DMA_PAUSE); - - /* - Wait for DMA pause complete. */ - if (gasket_wait_with_reschedule(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_USER_HIB_DMA_PAUSED, 1, 1, - APEX_RESET_DELAY, APEX_RESET_RETRY)) { - dev_err(gasket_dev->dev, - "DMAs did not quiesce within timeout (%d ms)\n", - APEX_RESET_RETRY * APEX_RESET_DELAY); - return -ETIMEDOUT; - } - - /* - Enable GCB reset (0x1 to rg_rst_gcb) */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_2, 0x1, 2, 2); - - /* - Enable GCB clock Gate (0x1 to rg_gated_gcb) */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_2, 0x1, 2, 18); - - /* - Enable GCB memory shut down (0x3 to rg_force_ram_sd) */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, 0x3, 2, 14); - - /* - Wait for RAM shutdown. */ - if (gasket_wait_with_reschedule(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, BIT(6), BIT(6), - APEX_RESET_DELAY, APEX_RESET_RETRY)) { - dev_err(gasket_dev->dev, - "RAM did not shut down within timeout (%d ms)\n", - APEX_RESET_RETRY * APEX_RESET_DELAY); - return -ETIMEDOUT; - } - - return 0; -} - -/* Quit GCB reset state. */ -static int apex_quit_reset(struct gasket_dev *gasket_dev) -{ - u32 val0, val1; - - if (bypass_top_level) - return 0; - - /* - * Disable sleep mode: - * - Disable GCB memory shut down: - * - b00: Not forced (HW controlled) - * - b1x: Force disable - */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, 0x0, 2, 14); - - /* - * - Disable software clock gate: - * - b00: Not forced (HW controlled) - * - b1x: Force disable - */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_2, 0x0, 2, 18); - - /* - * - Disable GCB reset (rg_rst_gcb): - * - b00: Not forced (HW controlled) - * - b1x: Force disable = Force not Reset - */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_2, 0x2, 2, 2); - - /* - Wait for RAM enable. */ - if (gasket_wait_with_reschedule(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, BIT(6), 0, - APEX_RESET_DELAY, APEX_RESET_RETRY)) { - dev_err(gasket_dev->dev, - "RAM did not enable within timeout (%d ms)\n", - APEX_RESET_RETRY * APEX_RESET_DELAY); - return -ETIMEDOUT; - } - - /* - Wait for Reset complete. */ - if (gasket_wait_with_reschedule(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, - SCU3_CUR_RST_GCB_BIT_MASK, 0, - APEX_RESET_DELAY, APEX_RESET_RETRY)) { - dev_err(gasket_dev->dev, - "GCB did not leave reset within timeout (%d ms)\n", - APEX_RESET_RETRY * APEX_RESET_DELAY); - return -ETIMEDOUT; - } - - if (!allow_hw_clock_gating) { - val0 = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3); - /* Inactive and Sleep mode are disabled. */ - gasket_read_modify_write_32(gasket_dev, - APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, 0x3, - SCU3_RG_PWR_STATE_OVR_MASK_WIDTH, - SCU3_RG_PWR_STATE_OVR_BIT_OFFSET); - val1 = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3); - dev_dbg(gasket_dev->dev, - "Disallow HW clock gating 0x%x -> 0x%x\n", val0, val1); - } else { - val0 = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3); - /* Inactive mode enabled - Sleep mode disabled. */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3, 2, - SCU3_RG_PWR_STATE_OVR_MASK_WIDTH, - SCU3_RG_PWR_STATE_OVR_BIT_OFFSET); - val1 = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3); - dev_dbg(gasket_dev->dev, "Allow HW clock gating 0x%x -> 0x%x\n", - val0, val1); - } - - return 0; -} - -/* Reset the Apex hardware. Called on final close via device_close_cb. */ -static int apex_device_cleanup(struct gasket_dev *gasket_dev) -{ - u64 scalar_error; - u64 hib_error; - int ret = 0; - - hib_error = gasket_dev_read_64(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_USER_HIB_ERROR_STATUS); - scalar_error = gasket_dev_read_64(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCALAR_CORE_ERROR_STATUS); - - dev_dbg(gasket_dev->dev, - "%s 0x%p hib_error 0x%llx scalar_error 0x%llx\n", - __func__, gasket_dev, hib_error, scalar_error); - - if (allow_power_save) - ret = apex_enter_reset(gasket_dev); - - return ret; -} - -/* Determine if GCB is in reset state. */ -static bool is_gcb_in_reset(struct gasket_dev *gasket_dev) -{ - u32 val = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_SCU_3); - - /* Masks rg_rst_gcb bit of SCU_CTRL_2 */ - return (val & SCU3_CUR_RST_GCB_BIT_MASK); -} - -/* Reset the hardware, then quit reset. Called on device open. */ -static int apex_reset(struct gasket_dev *gasket_dev) -{ - int ret; - - if (bypass_top_level) - return 0; - - if (!is_gcb_in_reset(gasket_dev)) { - /* We are not in reset - toggle the reset bit so as to force - * re-init of custom block - */ - dev_dbg(gasket_dev->dev, "%s: toggle reset\n", __func__); - - ret = apex_enter_reset(gasket_dev); - if (ret) - return ret; - } - return apex_quit_reset(gasket_dev); -} - -/* - * Check permissions for Apex ioctls. - * Returns true if the current user may execute this ioctl, and false otherwise. - */ -static bool apex_ioctl_check_permissions(struct file *filp, uint cmd) -{ - return !!(filp->f_mode & FMODE_WRITE); -} - -/* Gates or un-gates Apex clock. */ -static long apex_clock_gating(struct gasket_dev *gasket_dev, - struct apex_gate_clock_ioctl __user *argp) -{ - struct apex_gate_clock_ioctl ibuf; - - if (bypass_top_level || !allow_sw_clock_gating) - return 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - dev_dbg(gasket_dev->dev, "%s %llu\n", __func__, ibuf.enable); - - if (ibuf.enable) { - /* Quiesce AXI, gate GCB clock. */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_AXI_QUIESCE, 0x1, 1, - 16); - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_GCB_CLOCK_GATE, 0x1, - 2, 18); - } else { - /* Un-gate GCB clock, un-quiesce AXI. */ - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_GCB_CLOCK_GATE, 0x0, - 2, 18); - gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_AXI_QUIESCE, 0x0, 1, - 16); - } - return 0; -} - -/* Apex-specific ioctl handler. */ -static long apex_ioctl(struct file *filp, uint cmd, void __user *argp) -{ - struct gasket_dev *gasket_dev = filp->private_data; - - if (!apex_ioctl_check_permissions(filp, cmd)) - return -EPERM; - - switch (cmd) { - case APEX_IOCTL_GATE_CLOCK: - return apex_clock_gating(gasket_dev, argp); - default: - return -ENOTTY; /* unknown command */ - } -} - -/* Display driver sysfs entries. */ -static ssize_t sysfs_show(struct device *device, struct device_attribute *attr, - char *buf) -{ - int ret; - struct gasket_dev *gasket_dev; - struct gasket_sysfs_attribute *gasket_attr; - enum sysfs_attribute_type type; - struct gasket_page_table *gpt; - uint val; - - gasket_dev = gasket_sysfs_get_device_data(device); - if (!gasket_dev) { - dev_err(device, "No Apex device sysfs mapping found\n"); - return -ENODEV; - } - - gasket_attr = gasket_sysfs_get_attr(device, attr); - if (!gasket_attr) { - dev_err(device, "No Apex device sysfs attr data found\n"); - gasket_sysfs_put_device_data(device, gasket_dev); - return -ENODEV; - } - - type = (enum sysfs_attribute_type)gasket_attr->data.attr_type; - gpt = gasket_dev->page_table[0]; - switch (type) { - case ATTR_KERNEL_HIB_PAGE_TABLE_SIZE: - val = gasket_page_table_num_entries(gpt); - break; - case ATTR_KERNEL_HIB_SIMPLE_PAGE_TABLE_SIZE: - val = gasket_page_table_num_simple_entries(gpt); - break; - case ATTR_KERNEL_HIB_NUM_ACTIVE_PAGES: - val = gasket_page_table_num_active_pages(gpt); - break; - default: - dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n", - attr->attr.name); - ret = 0; - goto exit; - } - ret = scnprintf(buf, PAGE_SIZE, "%u\n", val); -exit: - gasket_sysfs_put_attr(device, gasket_attr); - gasket_sysfs_put_device_data(device, gasket_dev); - return ret; -} - -static struct gasket_sysfs_attribute apex_sysfs_attrs[] = { - GASKET_SYSFS_RO(node_0_page_table_entries, sysfs_show, - ATTR_KERNEL_HIB_PAGE_TABLE_SIZE), - GASKET_SYSFS_RO(node_0_simple_page_table_entries, sysfs_show, - ATTR_KERNEL_HIB_SIMPLE_PAGE_TABLE_SIZE), - GASKET_SYSFS_RO(node_0_num_mapped_pages, sysfs_show, - ATTR_KERNEL_HIB_NUM_ACTIVE_PAGES), - GASKET_END_OF_ATTR_ARRAY -}; - -/* On device open, perform a core reinit reset. */ -static int apex_device_open_cb(struct gasket_dev *gasket_dev) -{ - return gasket_reset_nolock(gasket_dev); -} - -static const struct pci_device_id apex_pci_ids[] = { - { PCI_DEVICE(APEX_PCI_VENDOR_ID, APEX_PCI_DEVICE_ID) }, { 0 } -}; - -static int apex_pci_probe(struct pci_dev *pci_dev, - const struct pci_device_id *id) -{ - int ret; - ulong page_table_ready, msix_table_ready; - int retries = 0; - struct gasket_dev *gasket_dev; - - ret = pci_enable_device(pci_dev); - if (ret) { - dev_err(&pci_dev->dev, "error enabling PCI device\n"); - return ret; - } - - pci_set_master(pci_dev); - - ret = gasket_pci_add_device(pci_dev, &gasket_dev); - if (ret) { - dev_err(&pci_dev->dev, "error adding gasket device\n"); - pci_disable_device(pci_dev); - return ret; - } - - pci_set_drvdata(pci_dev, gasket_dev); - apex_reset(gasket_dev); - - while (retries < APEX_RESET_RETRY) { - page_table_ready = - gasket_dev_read_64(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE_INIT); - msix_table_ready = - gasket_dev_read_64(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE_INIT); - if (page_table_ready && msix_table_ready) - break; - schedule_timeout(msecs_to_jiffies(APEX_RESET_DELAY)); - retries++; - } - - if (retries == APEX_RESET_RETRY) { - if (!page_table_ready) - dev_err(gasket_dev->dev, "Page table init timed out\n"); - if (!msix_table_ready) - dev_err(gasket_dev->dev, "MSI-X table init timed out\n"); - ret = -ETIMEDOUT; - goto remove_device; - } - - ret = gasket_sysfs_create_entries(gasket_dev->dev_info.device, - apex_sysfs_attrs); - if (ret) - dev_err(&pci_dev->dev, "error creating device sysfs entries\n"); - - ret = gasket_enable_device(gasket_dev); - if (ret) { - dev_err(&pci_dev->dev, "error enabling gasket device\n"); - goto remove_device; - } - - /* Place device in low power mode until opened */ - if (allow_power_save) - apex_enter_reset(gasket_dev); - - return 0; - -remove_device: - gasket_pci_remove_device(pci_dev); - pci_disable_device(pci_dev); - return ret; -} - -static void apex_pci_remove(struct pci_dev *pci_dev) -{ - struct gasket_dev *gasket_dev = pci_get_drvdata(pci_dev); - - gasket_disable_device(gasket_dev); - gasket_pci_remove_device(pci_dev); - pci_disable_device(pci_dev); -} - -static const struct gasket_driver_desc apex_desc = { - .name = "apex", - .driver_version = APEX_DRIVER_VERSION, - .major = 120, - .minor = 0, - .module = THIS_MODULE, - .pci_id_table = apex_pci_ids, - - .num_page_tables = NUM_NODES, - .page_table_bar_index = APEX_BAR_INDEX, - .page_table_configs = apex_page_table_configs, - .page_table_extended_bit = APEX_EXTENDED_SHIFT, - - .bar_descriptions = { - GASKET_UNUSED_BAR, - GASKET_UNUSED_BAR, - { APEX_BAR_BYTES, (VM_WRITE | VM_READ), APEX_BAR_OFFSET, - NUM_REGIONS, mappable_regions, PCI_BAR }, - GASKET_UNUSED_BAR, - GASKET_UNUSED_BAR, - GASKET_UNUSED_BAR, - }, - .coherent_buffer_description = { - APEX_CH_MEM_BYTES, - (VM_WRITE | VM_READ), - APEX_CM_OFFSET, - }, - .interrupt_type = PCI_MSIX, - .interrupt_bar_index = APEX_BAR_INDEX, - .num_interrupts = APEX_INTERRUPT_COUNT, - .interrupts = apex_interrupts, - .interrupt_pack_width = 7, - - .device_open_cb = apex_device_open_cb, - .device_close_cb = apex_device_cleanup, - - .ioctl_handler_cb = apex_ioctl, - .device_status_cb = apex_get_status, - .hardware_revision_cb = NULL, - .device_reset_cb = apex_reset, -}; - -static struct pci_driver apex_pci_driver = { - .name = "apex", - .probe = apex_pci_probe, - .remove = apex_pci_remove, - .id_table = apex_pci_ids, -}; - -static int __init apex_init(void) -{ - int ret; - - ret = gasket_register_device(&apex_desc); - if (ret) - return ret; - ret = pci_register_driver(&apex_pci_driver); - if (ret) - gasket_unregister_device(&apex_desc); - return ret; -} - -static void apex_exit(void) -{ - pci_unregister_driver(&apex_pci_driver); - gasket_unregister_device(&apex_desc); -} -MODULE_DESCRIPTION("Google Apex driver"); -MODULE_VERSION(APEX_DRIVER_VERSION); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("John Joseph <jnjoseph@google.com>"); -MODULE_DEVICE_TABLE(pci, apex_pci_ids); -module_init(apex_init); -module_exit(apex_exit); diff --git a/drivers/staging/gasket/gasket.h b/drivers/staging/gasket/gasket.h deleted file mode 100644 index a0f065c517a526f4e6f3eb87be1a95f5fd297e48..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket.h +++ /dev/null @@ -1,122 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Common Gasket device kernel and user space declarations. - * - * Copyright (C) 2018 Google, Inc. - */ -#ifndef __GASKET_H__ -#define __GASKET_H__ - -#include <linux/ioctl.h> -#include <linux/types.h> - -/* ioctl structure declarations */ - -/* Ioctl structures are padded to a multiple of 64 bits */ -/* and padded to put 64 bit values on 64 bit boundaries. */ -/* Unsigned 64 bit integers are used to hold pointers. */ -/* This helps compatibility between 32 and 64 bits. */ - -/* - * Common structure for ioctls associating an eventfd with a device interrupt, - * when using the Gasket interrupt module. - */ -struct gasket_interrupt_eventfd { - u64 interrupt; - u64 event_fd; -}; - -/* - * Common structure for ioctls mapping and unmapping buffers when using the - * Gasket page_table module. - */ -struct gasket_page_table_ioctl { - u64 page_table_index; - u64 size; - u64 host_address; - u64 device_address; -}; - -/* - * Common structure for ioctls mapping and unmapping buffers when using the - * Gasket page_table module. - * dma_address: phys addr start of coherent memory, allocated by kernel - */ -struct gasket_coherent_alloc_config_ioctl { - u64 page_table_index; - u64 enable; - u64 size; - u64 dma_address; -}; - -/* Base number for all Gasket-common IOCTLs */ -#define GASKET_IOCTL_BASE 0xDC - -/* Reset the device. */ -#define GASKET_IOCTL_RESET _IO(GASKET_IOCTL_BASE, 0) - -/* Associate the specified [event]fd with the specified interrupt. */ -#define GASKET_IOCTL_SET_EVENTFD \ - _IOW(GASKET_IOCTL_BASE, 1, struct gasket_interrupt_eventfd) - -/* - * Clears any eventfd associated with the specified interrupt. The (ulong) - * argument is the interrupt number to clear. - */ -#define GASKET_IOCTL_CLEAR_EVENTFD _IOW(GASKET_IOCTL_BASE, 2, unsigned long) - -/* - * [Loopbacks only] Requests that the loopback device send the specified - * interrupt to the host. The (ulong) argument is the number of the interrupt to - * send. - */ -#define GASKET_IOCTL_LOOPBACK_INTERRUPT \ - _IOW(GASKET_IOCTL_BASE, 3, unsigned long) - -/* Queries the kernel for the number of page tables supported by the device. */ -#define GASKET_IOCTL_NUMBER_PAGE_TABLES _IOR(GASKET_IOCTL_BASE, 4, u64) - -/* - * Queries the kernel for the maximum size of the page table. Only the size and - * page_table_index fields are used from the struct gasket_page_table_ioctl. - */ -#define GASKET_IOCTL_PAGE_TABLE_SIZE \ - _IOWR(GASKET_IOCTL_BASE, 5, struct gasket_page_table_ioctl) - -/* - * Queries the kernel for the current simple page table size. Only the size and - * page_table_index fields are used from the struct gasket_page_table_ioctl. - */ -#define GASKET_IOCTL_SIMPLE_PAGE_TABLE_SIZE \ - _IOWR(GASKET_IOCTL_BASE, 6, struct gasket_page_table_ioctl) - -/* - * Tells the kernel to change the split between the number of simple and - * extended entries in the given page table. Only the size and page_table_index - * fields are used from the struct gasket_page_table_ioctl. - */ -#define GASKET_IOCTL_PARTITION_PAGE_TABLE \ - _IOW(GASKET_IOCTL_BASE, 7, struct gasket_page_table_ioctl) - -/* - * Tells the kernel to map size bytes at host_address to device_address in - * page_table_index page table. - */ -#define GASKET_IOCTL_MAP_BUFFER \ - _IOW(GASKET_IOCTL_BASE, 8, struct gasket_page_table_ioctl) - -/* - * Tells the kernel to unmap size bytes at host_address from device_address in - * page_table_index page table. - */ -#define GASKET_IOCTL_UNMAP_BUFFER \ - _IOW(GASKET_IOCTL_BASE, 9, struct gasket_page_table_ioctl) - -/* Clear the interrupt counts stored for this device. */ -#define GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS _IO(GASKET_IOCTL_BASE, 10) - -/* Enable/Disable and configure the coherent allocator. */ -#define GASKET_IOCTL_CONFIG_COHERENT_ALLOCATOR \ - _IOWR(GASKET_IOCTL_BASE, 11, struct gasket_coherent_alloc_config_ioctl) - -#endif /* __GASKET_H__ */ diff --git a/drivers/staging/gasket/gasket_constants.h b/drivers/staging/gasket/gasket_constants.h deleted file mode 100644 index 9ea9c8833f27a066b4d2a7a5eb188a153ee4f7b4..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_constants.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2018 Google, Inc. */ -#ifndef __GASKET_CONSTANTS_H__ -#define __GASKET_CONSTANTS_H__ - -#define GASKET_FRAMEWORK_VERSION "1.1.2" - -/* - * The maximum number of simultaneous device types supported by the framework. - */ -#define GASKET_FRAMEWORK_DESC_MAX 2 - -/* The maximum devices per each type. */ -#define GASKET_DEV_MAX 256 - -/* The number of supported Gasket page tables per device. */ -#define GASKET_MAX_NUM_PAGE_TABLES 1 - -/* Maximum length of device names (driver name + minor number suffix + NULL). */ -#define GASKET_NAME_MAX 32 - -/* Device status enumeration. */ -enum gasket_status { - /* - * A device is DEAD if it has not been initialized or has had an error. - */ - GASKET_STATUS_DEAD = 0, - /* - * A device is LAMED if the hardware is healthy but the kernel was - * unable to enable some functionality (e.g. interrupts). - */ - GASKET_STATUS_LAMED, - - /* A device is ALIVE if it is ready for operation. */ - GASKET_STATUS_ALIVE, - - /* - * This status is set when the driver is exiting and waiting for all - * handles to be closed. - */ - GASKET_STATUS_DRIVER_EXIT, -}; - -#endif diff --git a/drivers/staging/gasket/gasket_core.c b/drivers/staging/gasket/gasket_core.c deleted file mode 100644 index 28dab302183bcf24e9bce8b7c843827aaa4cd802..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_core.c +++ /dev/null @@ -1,1815 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Gasket generic driver framework. This file contains the implementation - * for the Gasket generic driver framework - the functionality that is common - * across Gasket devices. - * - * Copyright (C) 2018 Google, Inc. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "gasket_core.h" - -#include "gasket_interrupt.h" -#include "gasket_ioctl.h" -#include "gasket_page_table.h" -#include "gasket_sysfs.h" - -#include <linux/capability.h> -#include <linux/compiler.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/of.h> -#include <linux/pid_namespace.h> -#include <linux/printk.h> -#include <linux/sched.h> - -#ifdef GASKET_KERNEL_TRACE_SUPPORT -#define CREATE_TRACE_POINTS -#include <trace/events/gasket_mmap.h> -#else -#define trace_gasket_mmap_exit(x) -#define trace_gasket_mmap_entry(x, ...) -#endif - -/* - * "Private" members of gasket_driver_desc. - * - * Contains internal per-device type tracking data, i.e., data not appropriate - * as part of the public interface for the generic framework. - */ -struct gasket_internal_desc { - /* Device-specific-driver-provided configuration information. */ - const struct gasket_driver_desc *driver_desc; - - /* Protects access to per-driver data (i.e. this structure). */ - struct mutex mutex; - - /* Kernel-internal device class. */ - struct class *class; - - /* Instantiated / present devices of this type. */ - struct gasket_dev *devs[GASKET_DEV_MAX]; -}; - -/* do_map_region() needs be able to return more than just true/false. */ -enum do_map_region_status { - /* The region was successfully mapped. */ - DO_MAP_REGION_SUCCESS, - - /* Attempted to map region and failed. */ - DO_MAP_REGION_FAILURE, - - /* The requested region to map was not part of a mappable region. */ - DO_MAP_REGION_INVALID, -}; - -/* Global data definitions. */ -/* Mutex - only for framework-wide data. Other data should be protected by - * finer-grained locks. - */ -static DEFINE_MUTEX(g_mutex); - -/* List of all registered device descriptions & their supporting data. */ -static struct gasket_internal_desc g_descs[GASKET_FRAMEWORK_DESC_MAX]; - -/* Mapping of statuses to human-readable strings. Must end with {0,NULL}. */ -static const struct gasket_num_name gasket_status_name_table[] = { - { GASKET_STATUS_DEAD, "DEAD" }, - { GASKET_STATUS_ALIVE, "ALIVE" }, - { GASKET_STATUS_LAMED, "LAMED" }, - { GASKET_STATUS_DRIVER_EXIT, "DRIVER_EXITING" }, - { 0, NULL }, -}; - -/* Enumeration of the automatic Gasket framework sysfs nodes. */ -enum gasket_sysfs_attribute_type { - ATTR_BAR_OFFSETS, - ATTR_BAR_SIZES, - ATTR_DRIVER_VERSION, - ATTR_FRAMEWORK_VERSION, - ATTR_DEVICE_TYPE, - ATTR_HARDWARE_REVISION, - ATTR_PCI_ADDRESS, - ATTR_STATUS, - ATTR_IS_DEVICE_OWNED, - ATTR_DEVICE_OWNER, - ATTR_WRITE_OPEN_COUNT, - ATTR_RESET_COUNT, - ATTR_USER_MEM_RANGES -}; - -/* Perform a standard Gasket callback. */ -static inline int -check_and_invoke_callback(struct gasket_dev *gasket_dev, - int (*cb_function)(struct gasket_dev *)) -{ - int ret = 0; - - if (cb_function) { - mutex_lock(&gasket_dev->mutex); - ret = cb_function(gasket_dev); - mutex_unlock(&gasket_dev->mutex); - } - return ret; -} - -/* Perform a standard Gasket callback without grabbing gasket_dev->mutex. */ -static inline int -gasket_check_and_invoke_callback_nolock(struct gasket_dev *gasket_dev, - int (*cb_function)(struct gasket_dev *)) -{ - int ret = 0; - - if (cb_function) - ret = cb_function(gasket_dev); - return ret; -} - -/* - * Return nonzero if the gasket_cdev_info is owned by the current thread group - * ID. - */ -static int gasket_owned_by_current_tgid(struct gasket_cdev_info *info) -{ - return (info->ownership.is_owned && - (info->ownership.owner == current->tgid)); -} - -/* - * Find the next free gasket_internal_dev slot. - * - * Returns the located slot number on success or a negative number on failure. - */ -static int gasket_find_dev_slot(struct gasket_internal_desc *internal_desc, - const char *kobj_name) -{ - int i; - - mutex_lock(&internal_desc->mutex); - - /* Search for a previous instance of this device. */ - for (i = 0; i < GASKET_DEV_MAX; i++) { - if (internal_desc->devs[i] && - strcmp(internal_desc->devs[i]->kobj_name, kobj_name) == 0) { - pr_err("Duplicate device %s\n", kobj_name); - mutex_unlock(&internal_desc->mutex); - return -EBUSY; - } - } - - /* Find a free device slot. */ - for (i = 0; i < GASKET_DEV_MAX; i++) { - if (!internal_desc->devs[i]) - break; - } - - if (i == GASKET_DEV_MAX) { - pr_err("Too many registered devices; max %d\n", GASKET_DEV_MAX); - mutex_unlock(&internal_desc->mutex); - return -EBUSY; - } - - mutex_unlock(&internal_desc->mutex); - return i; -} - -/* - * Allocate and initialize a Gasket device structure, add the device to the - * device list. - * - * Returns 0 if successful, a negative error code otherwise. - */ -static int gasket_alloc_dev(struct gasket_internal_desc *internal_desc, - struct device *parent, struct gasket_dev **pdev) -{ - int dev_idx; - const struct gasket_driver_desc *driver_desc = - internal_desc->driver_desc; - struct gasket_dev *gasket_dev; - struct gasket_cdev_info *dev_info; - const char *parent_name = dev_name(parent); - - pr_debug("Allocating a Gasket device, parent %s.\n", parent_name); - - *pdev = NULL; - - dev_idx = gasket_find_dev_slot(internal_desc, parent_name); - if (dev_idx < 0) - return dev_idx; - - gasket_dev = *pdev = kzalloc(sizeof(*gasket_dev), GFP_KERNEL); - if (!gasket_dev) { - pr_err("no memory for device, parent %s\n", parent_name); - return -ENOMEM; - } - internal_desc->devs[dev_idx] = gasket_dev; - - mutex_init(&gasket_dev->mutex); - - gasket_dev->internal_desc = internal_desc; - gasket_dev->dev_idx = dev_idx; - snprintf(gasket_dev->kobj_name, GASKET_NAME_MAX, "%s", parent_name); - gasket_dev->dev = get_device(parent); - /* gasket_bar_data is uninitialized. */ - gasket_dev->num_page_tables = driver_desc->num_page_tables; - /* max_page_table_size and *page table are uninit'ed */ - /* interrupt_data is not initialized. */ - /* status is 0, or GASKET_STATUS_DEAD */ - - dev_info = &gasket_dev->dev_info; - snprintf(dev_info->name, GASKET_NAME_MAX, "%s_%u", driver_desc->name, - gasket_dev->dev_idx); - dev_info->devt = - MKDEV(driver_desc->major, driver_desc->minor + - gasket_dev->dev_idx); - dev_info->device = - device_create(internal_desc->class, parent, dev_info->devt, - gasket_dev, dev_info->name); - - /* cdev has not yet been added; cdev_added is 0 */ - dev_info->gasket_dev_ptr = gasket_dev; - /* ownership is all 0, indicating no owner or opens. */ - - return 0; -} - -/* Free a Gasket device. */ -static void gasket_free_dev(struct gasket_dev *gasket_dev) -{ - struct gasket_internal_desc *internal_desc = gasket_dev->internal_desc; - - mutex_lock(&internal_desc->mutex); - internal_desc->devs[gasket_dev->dev_idx] = NULL; - mutex_unlock(&internal_desc->mutex); - put_device(gasket_dev->dev); - kfree(gasket_dev); -} - -/* - * Maps the specified bar into kernel space. - * - * Returns 0 on success, a negative error code otherwise. - * A zero-sized BAR will not be mapped, but is not an error. - */ -static int gasket_map_pci_bar(struct gasket_dev *gasket_dev, int bar_num) -{ - struct gasket_internal_desc *internal_desc = gasket_dev->internal_desc; - const struct gasket_driver_desc *driver_desc = - internal_desc->driver_desc; - ulong desc_bytes = driver_desc->bar_descriptions[bar_num].size; - struct gasket_bar_data *data; - int ret; - - if (desc_bytes == 0) - return 0; - - if (driver_desc->bar_descriptions[bar_num].type != PCI_BAR) { - /* not PCI: skip this entry */ - return 0; - } - - data = &gasket_dev->bar_data[bar_num]; - - /* - * pci_resource_start and pci_resource_len return a "resource_size_t", - * which is safely castable to ulong (which itself is the arg to - * request_mem_region). - */ - data->phys_base = - (ulong)pci_resource_start(gasket_dev->pci_dev, bar_num); - if (!data->phys_base) { - dev_err(gasket_dev->dev, "Cannot get BAR%u base address\n", - bar_num); - return -EINVAL; - } - - data->length_bytes = - (ulong)pci_resource_len(gasket_dev->pci_dev, bar_num); - if (data->length_bytes < desc_bytes) { - dev_err(gasket_dev->dev, - "PCI BAR %u space is too small: %lu; expected >= %lu\n", - bar_num, data->length_bytes, desc_bytes); - return -ENOMEM; - } - - if (!request_mem_region(data->phys_base, data->length_bytes, - gasket_dev->dev_info.name)) { - dev_err(gasket_dev->dev, - "Cannot get BAR %d memory region %p\n", - bar_num, &gasket_dev->pci_dev->resource[bar_num]); - return -EINVAL; - } - - data->virt_base = ioremap(data->phys_base, data->length_bytes); - if (!data->virt_base) { - dev_err(gasket_dev->dev, - "Cannot remap BAR %d memory region %p\n", - bar_num, &gasket_dev->pci_dev->resource[bar_num]); - ret = -ENOMEM; - goto fail; - } - - dma_set_mask(&gasket_dev->pci_dev->dev, DMA_BIT_MASK(64)); - dma_set_coherent_mask(&gasket_dev->pci_dev->dev, DMA_BIT_MASK(64)); - - return 0; - -fail: - iounmap(data->virt_base); - release_mem_region(data->phys_base, data->length_bytes); - return ret; -} - -/* - * Releases PCI BAR mapping. - * - * A zero-sized or not-mapped BAR will not be unmapped, but is not an error. - */ -static void gasket_unmap_pci_bar(struct gasket_dev *dev, int bar_num) -{ - ulong base, bytes; - struct gasket_internal_desc *internal_desc = dev->internal_desc; - const struct gasket_driver_desc *driver_desc = - internal_desc->driver_desc; - - if (driver_desc->bar_descriptions[bar_num].size == 0 || - !dev->bar_data[bar_num].virt_base) - return; - - if (driver_desc->bar_descriptions[bar_num].type != PCI_BAR) - return; - - iounmap(dev->bar_data[bar_num].virt_base); - dev->bar_data[bar_num].virt_base = NULL; - - base = pci_resource_start(dev->pci_dev, bar_num); - if (!base) { - dev_err(dev->dev, "cannot get PCI BAR%u base address\n", - bar_num); - return; - } - - bytes = pci_resource_len(dev->pci_dev, bar_num); - release_mem_region(base, bytes); -} - -/* - * Setup PCI memory mapping for the specified device. - * - * Reads the BAR registers and sets up pointers to the device's memory mapped - * IO space. - * - * Returns 0 on success and a negative value otherwise. - */ -static int gasket_setup_pci(struct pci_dev *pci_dev, - struct gasket_dev *gasket_dev) -{ - int i, mapped_bars, ret; - - for (i = 0; i < PCI_STD_NUM_BARS; i++) { - ret = gasket_map_pci_bar(gasket_dev, i); - if (ret) { - mapped_bars = i; - goto fail; - } - } - - return 0; - -fail: - for (i = 0; i < mapped_bars; i++) - gasket_unmap_pci_bar(gasket_dev, i); - - return -ENOMEM; -} - -/* Unmaps memory for the specified device. */ -static void gasket_cleanup_pci(struct gasket_dev *gasket_dev) -{ - int i; - - for (i = 0; i < PCI_STD_NUM_BARS; i++) - gasket_unmap_pci_bar(gasket_dev, i); -} - -/* Determine the health of the Gasket device. */ -static int gasket_get_hw_status(struct gasket_dev *gasket_dev) -{ - int status; - int i; - const struct gasket_driver_desc *driver_desc = - gasket_dev->internal_desc->driver_desc; - - status = gasket_check_and_invoke_callback_nolock(gasket_dev, - driver_desc->device_status_cb); - if (status != GASKET_STATUS_ALIVE) { - dev_dbg(gasket_dev->dev, "Hardware reported status %d.\n", - status); - return status; - } - - status = gasket_interrupt_system_status(gasket_dev); - if (status != GASKET_STATUS_ALIVE) { - dev_dbg(gasket_dev->dev, - "Interrupt system reported status %d.\n", status); - return status; - } - - for (i = 0; i < driver_desc->num_page_tables; ++i) { - status = gasket_page_table_system_status(gasket_dev->page_table[i]); - if (status != GASKET_STATUS_ALIVE) { - dev_dbg(gasket_dev->dev, - "Page table %d reported status %d.\n", - i, status); - return status; - } - } - - return GASKET_STATUS_ALIVE; -} - -static ssize_t -gasket_write_mappable_regions(char *buf, - const struct gasket_driver_desc *driver_desc, - int bar_index) -{ - int i; - ssize_t written; - ssize_t total_written = 0; - ulong min_addr, max_addr; - struct gasket_bar_desc bar_desc = - driver_desc->bar_descriptions[bar_index]; - - if (bar_desc.permissions == GASKET_NOMAP) - return 0; - for (i = 0; - i < bar_desc.num_mappable_regions && total_written < PAGE_SIZE; - i++) { - min_addr = bar_desc.mappable_regions[i].start - - driver_desc->legacy_mmap_address_offset; - max_addr = bar_desc.mappable_regions[i].start - - driver_desc->legacy_mmap_address_offset + - bar_desc.mappable_regions[i].length_bytes; - written = scnprintf(buf, PAGE_SIZE - total_written, - "0x%08lx-0x%08lx\n", min_addr, max_addr); - total_written += written; - buf += written; - } - return total_written; -} - -static ssize_t gasket_sysfs_data_show(struct device *device, - struct device_attribute *attr, char *buf) -{ - int i, ret = 0; - ssize_t current_written = 0; - const struct gasket_driver_desc *driver_desc; - struct gasket_dev *gasket_dev; - struct gasket_sysfs_attribute *gasket_attr; - const struct gasket_bar_desc *bar_desc; - enum gasket_sysfs_attribute_type sysfs_type; - - gasket_dev = gasket_sysfs_get_device_data(device); - if (!gasket_dev) { - dev_err(device, "No sysfs mapping found for device\n"); - return 0; - } - - gasket_attr = gasket_sysfs_get_attr(device, attr); - if (!gasket_attr) { - dev_err(device, "No sysfs attr found for device\n"); - gasket_sysfs_put_device_data(device, gasket_dev); - return 0; - } - - driver_desc = gasket_dev->internal_desc->driver_desc; - - sysfs_type = - (enum gasket_sysfs_attribute_type)gasket_attr->data.attr_type; - switch (sysfs_type) { - case ATTR_BAR_OFFSETS: - for (i = 0; i < PCI_STD_NUM_BARS; i++) { - bar_desc = &driver_desc->bar_descriptions[i]; - if (bar_desc->size == 0) - continue; - current_written = - snprintf(buf, PAGE_SIZE - ret, "%d: 0x%lx\n", i, - (ulong)bar_desc->base); - buf += current_written; - ret += current_written; - } - break; - case ATTR_BAR_SIZES: - for (i = 0; i < PCI_STD_NUM_BARS; i++) { - bar_desc = &driver_desc->bar_descriptions[i]; - if (bar_desc->size == 0) - continue; - current_written = - snprintf(buf, PAGE_SIZE - ret, "%d: 0x%lx\n", i, - (ulong)bar_desc->size); - buf += current_written; - ret += current_written; - } - break; - case ATTR_DRIVER_VERSION: - ret = snprintf(buf, PAGE_SIZE, "%s\n", - gasket_dev->internal_desc->driver_desc->driver_version); - break; - case ATTR_FRAMEWORK_VERSION: - ret = snprintf(buf, PAGE_SIZE, "%s\n", - GASKET_FRAMEWORK_VERSION); - break; - case ATTR_DEVICE_TYPE: - ret = snprintf(buf, PAGE_SIZE, "%s\n", - gasket_dev->internal_desc->driver_desc->name); - break; - case ATTR_HARDWARE_REVISION: - ret = snprintf(buf, PAGE_SIZE, "%d\n", - gasket_dev->hardware_revision); - break; - case ATTR_PCI_ADDRESS: - ret = snprintf(buf, PAGE_SIZE, "%s\n", gasket_dev->kobj_name); - break; - case ATTR_STATUS: - ret = snprintf(buf, PAGE_SIZE, "%s\n", - gasket_num_name_lookup(gasket_dev->status, - gasket_status_name_table)); - break; - case ATTR_IS_DEVICE_OWNED: - ret = snprintf(buf, PAGE_SIZE, "%d\n", - gasket_dev->dev_info.ownership.is_owned); - break; - case ATTR_DEVICE_OWNER: - ret = snprintf(buf, PAGE_SIZE, "%d\n", - gasket_dev->dev_info.ownership.owner); - break; - case ATTR_WRITE_OPEN_COUNT: - ret = snprintf(buf, PAGE_SIZE, "%d\n", - gasket_dev->dev_info.ownership.write_open_count); - break; - case ATTR_RESET_COUNT: - ret = snprintf(buf, PAGE_SIZE, "%d\n", gasket_dev->reset_count); - break; - case ATTR_USER_MEM_RANGES: - for (i = 0; i < PCI_STD_NUM_BARS; ++i) { - current_written = - gasket_write_mappable_regions(buf, driver_desc, - i); - buf += current_written; - ret += current_written; - } - break; - default: - dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n", - attr->attr.name); - ret = 0; - break; - } - - gasket_sysfs_put_attr(device, gasket_attr); - gasket_sysfs_put_device_data(device, gasket_dev); - return ret; -} - -/* These attributes apply to all Gasket driver instances. */ -static const struct gasket_sysfs_attribute gasket_sysfs_generic_attrs[] = { - GASKET_SYSFS_RO(bar_offsets, gasket_sysfs_data_show, ATTR_BAR_OFFSETS), - GASKET_SYSFS_RO(bar_sizes, gasket_sysfs_data_show, ATTR_BAR_SIZES), - GASKET_SYSFS_RO(driver_version, gasket_sysfs_data_show, - ATTR_DRIVER_VERSION), - GASKET_SYSFS_RO(framework_version, gasket_sysfs_data_show, - ATTR_FRAMEWORK_VERSION), - GASKET_SYSFS_RO(device_type, gasket_sysfs_data_show, ATTR_DEVICE_TYPE), - GASKET_SYSFS_RO(revision, gasket_sysfs_data_show, - ATTR_HARDWARE_REVISION), - GASKET_SYSFS_RO(pci_address, gasket_sysfs_data_show, ATTR_PCI_ADDRESS), - GASKET_SYSFS_RO(status, gasket_sysfs_data_show, ATTR_STATUS), - GASKET_SYSFS_RO(is_device_owned, gasket_sysfs_data_show, - ATTR_IS_DEVICE_OWNED), - GASKET_SYSFS_RO(device_owner, gasket_sysfs_data_show, - ATTR_DEVICE_OWNER), - GASKET_SYSFS_RO(write_open_count, gasket_sysfs_data_show, - ATTR_WRITE_OPEN_COUNT), - GASKET_SYSFS_RO(reset_count, gasket_sysfs_data_show, ATTR_RESET_COUNT), - GASKET_SYSFS_RO(user_mem_ranges, gasket_sysfs_data_show, - ATTR_USER_MEM_RANGES), - GASKET_END_OF_ATTR_ARRAY -}; - -/* Add a char device and related info. */ -static int gasket_add_cdev(struct gasket_cdev_info *dev_info, - const struct file_operations *file_ops, - struct module *owner) -{ - int ret; - - cdev_init(&dev_info->cdev, file_ops); - dev_info->cdev.owner = owner; - ret = cdev_add(&dev_info->cdev, dev_info->devt, 1); - if (ret) { - dev_err(dev_info->gasket_dev_ptr->dev, - "cannot add char device [ret=%d]\n", ret); - return ret; - } - dev_info->cdev_added = 1; - - return 0; -} - -/* Disable device operations. */ -void gasket_disable_device(struct gasket_dev *gasket_dev) -{ - const struct gasket_driver_desc *driver_desc = - gasket_dev->internal_desc->driver_desc; - int i; - - /* Only delete the device if it has been successfully added. */ - if (gasket_dev->dev_info.cdev_added) - cdev_del(&gasket_dev->dev_info.cdev); - - gasket_dev->status = GASKET_STATUS_DEAD; - - gasket_interrupt_cleanup(gasket_dev); - - for (i = 0; i < driver_desc->num_page_tables; ++i) { - if (gasket_dev->page_table[i]) { - gasket_page_table_reset(gasket_dev->page_table[i]); - gasket_page_table_cleanup(gasket_dev->page_table[i]); - } - } -} -EXPORT_SYMBOL(gasket_disable_device); - -/* - * Registered driver descriptor lookup for PCI devices. - * - * Precondition: Called with g_mutex held (to avoid a race on return). - * Returns NULL if no matching device was found. - */ -static struct gasket_internal_desc * -lookup_pci_internal_desc(struct pci_dev *pci_dev) -{ - int i; - - __must_hold(&g_mutex); - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (g_descs[i].driver_desc && - g_descs[i].driver_desc->pci_id_table && - pci_match_id(g_descs[i].driver_desc->pci_id_table, pci_dev)) - return &g_descs[i]; - } - - return NULL; -} - -/* - * Verifies that the user has permissions to perform the requested mapping and - * that the provided descriptor/range is of adequate size to hold the range to - * be mapped. - */ -static bool gasket_mmap_has_permissions(struct gasket_dev *gasket_dev, - struct vm_area_struct *vma, - int bar_permissions) -{ - int requested_permissions; - /* Always allow sysadmin to access. */ - if (capable(CAP_SYS_ADMIN)) - return true; - - /* Never allow non-sysadmins to access to a dead device. */ - if (gasket_dev->status != GASKET_STATUS_ALIVE) { - dev_dbg(gasket_dev->dev, "Device is dead.\n"); - return false; - } - - /* Make sure that no wrong flags are set. */ - requested_permissions = - (vma->vm_flags & VM_ACCESS_FLAGS); - if (requested_permissions & ~(bar_permissions)) { - dev_dbg(gasket_dev->dev, - "Attempting to map a region with requested permissions 0x%x, but region has permissions 0x%x.\n", - requested_permissions, bar_permissions); - return false; - } - - /* Do not allow a non-owner to write. */ - if ((vma->vm_flags & VM_WRITE) && - !gasket_owned_by_current_tgid(&gasket_dev->dev_info)) { - dev_dbg(gasket_dev->dev, - "Attempting to mmap a region for write without owning device.\n"); - return false; - } - - return true; -} - -/* - * Verifies that the input address is within the region allocated to coherent - * buffer. - */ -static bool -gasket_is_coherent_region(const struct gasket_driver_desc *driver_desc, - ulong address) -{ - struct gasket_coherent_buffer_desc coh_buff_desc = - driver_desc->coherent_buffer_description; - - if (coh_buff_desc.permissions != GASKET_NOMAP) { - if ((address >= coh_buff_desc.base) && - (address < coh_buff_desc.base + coh_buff_desc.size)) { - return true; - } - } - return false; -} - -static int gasket_get_bar_index(const struct gasket_dev *gasket_dev, - ulong phys_addr) -{ - int i; - const struct gasket_driver_desc *driver_desc; - - driver_desc = gasket_dev->internal_desc->driver_desc; - for (i = 0; i < PCI_STD_NUM_BARS; ++i) { - struct gasket_bar_desc bar_desc = - driver_desc->bar_descriptions[i]; - - if (bar_desc.permissions != GASKET_NOMAP) { - if (phys_addr >= bar_desc.base && - phys_addr < (bar_desc.base + bar_desc.size)) { - return i; - } - } - } - /* If we haven't found the address by now, it is invalid. */ - return -EINVAL; -} - -/* - * Sets the actual bounds to map, given the device's mappable region. - * - * Given the device's mappable region, along with the user-requested mapping - * start offset and length of the user region, determine how much of this - * mappable region can be mapped into the user's region (start/end offsets), - * and the physical offset (phys_offset) into the BAR where the mapping should - * begin (either the VMA's or region lower bound). - * - * In other words, this calculates the overlap between the VMA - * (bar_offset, requested_length) and the given gasket_mappable_region. - * - * Returns true if there's anything to map, and false otherwise. - */ -static bool -gasket_mm_get_mapping_addrs(const struct gasket_mappable_region *region, - ulong bar_offset, ulong requested_length, - struct gasket_mappable_region *mappable_region, - ulong *virt_offset) -{ - ulong range_start = region->start; - ulong range_length = region->length_bytes; - ulong range_end = range_start + range_length; - - *virt_offset = 0; - if (bar_offset + requested_length < range_start) { - /* - * If the requested region is completely below the range, - * there is nothing to map. - */ - return false; - } else if (bar_offset <= range_start) { - /* If the bar offset is below this range's start - * but the requested length continues into it: - * 1) Only map starting from the beginning of this - * range's phys. offset, so we don't map unmappable - * memory. - * 2) The length of the virtual memory to not map is the - * delta between the bar offset and the - * mappable start (and since the mappable start is - * bigger, start - req.) - * 3) The map length is the minimum of the mappable - * requested length (requested_length - virt_offset) - * and the actual mappable length of the range. - */ - mappable_region->start = range_start; - *virt_offset = range_start - bar_offset; - mappable_region->length_bytes = - min(requested_length - *virt_offset, range_length); - return true; - } else if (bar_offset > range_start && - bar_offset < range_end) { - /* - * If the bar offset is within this range: - * 1) Map starting from the bar offset. - * 2) Because there is no forbidden memory between the - * bar offset and the range start, - * virt_offset is 0. - * 3) The map length is the minimum of the requested - * length and the remaining length in the buffer - * (range_end - bar_offset) - */ - mappable_region->start = bar_offset; - *virt_offset = 0; - mappable_region->length_bytes = - min(requested_length, range_end - bar_offset); - return true; - } - - /* - * If the requested [start] offset is above range_end, - * there's nothing to map. - */ - return false; -} - -/* - * Calculates the offset where the VMA range begins in its containing BAR. - * The offset is written into bar_offset on success. - * Returns zero on success, anything else on error. - */ -static int gasket_mm_vma_bar_offset(const struct gasket_dev *gasket_dev, - const struct vm_area_struct *vma, - ulong *bar_offset) -{ - ulong raw_offset; - int bar_index; - const struct gasket_driver_desc *driver_desc = - gasket_dev->internal_desc->driver_desc; - - raw_offset = (vma->vm_pgoff << PAGE_SHIFT) + - driver_desc->legacy_mmap_address_offset; - bar_index = gasket_get_bar_index(gasket_dev, raw_offset); - if (bar_index < 0) { - dev_err(gasket_dev->dev, - "Unable to find matching bar for address 0x%lx\n", - raw_offset); - trace_gasket_mmap_exit(bar_index); - return bar_index; - } - *bar_offset = - raw_offset - driver_desc->bar_descriptions[bar_index].base; - - return 0; -} - -int gasket_mm_unmap_region(const struct gasket_dev *gasket_dev, - struct vm_area_struct *vma, - const struct gasket_mappable_region *map_region) -{ - ulong bar_offset; - ulong virt_offset; - struct gasket_mappable_region mappable_region; - int ret; - - if (map_region->length_bytes == 0) - return 0; - - ret = gasket_mm_vma_bar_offset(gasket_dev, vma, &bar_offset); - if (ret) - return ret; - - if (!gasket_mm_get_mapping_addrs(map_region, bar_offset, - vma->vm_end - vma->vm_start, - &mappable_region, &virt_offset)) - return 1; - - /* - * The length passed to zap_vma_ptes MUST BE A MULTIPLE OF - * PAGE_SIZE! Trust me. I have the scars. - * - * Next multiple of y: ceil_div(x, y) * y - */ - zap_vma_ptes(vma, vma->vm_start + virt_offset, - DIV_ROUND_UP(mappable_region.length_bytes, PAGE_SIZE) * - PAGE_SIZE); - return 0; -} -EXPORT_SYMBOL(gasket_mm_unmap_region); - -/* Maps a virtual address + range to a physical offset of a BAR. */ -static enum do_map_region_status -do_map_region(const struct gasket_dev *gasket_dev, struct vm_area_struct *vma, - struct gasket_mappable_region *mappable_region) -{ - /* Maximum size of a single call to io_remap_pfn_range. */ - /* I pulled this number out of thin air. */ - const ulong max_chunk_size = 64 * 1024 * 1024; - ulong chunk_size, mapped_bytes = 0; - - const struct gasket_driver_desc *driver_desc = - gasket_dev->internal_desc->driver_desc; - - ulong bar_offset, virt_offset; - struct gasket_mappable_region region_to_map; - ulong phys_offset, map_length; - ulong virt_base, phys_base; - int bar_index, ret; - - ret = gasket_mm_vma_bar_offset(gasket_dev, vma, &bar_offset); - if (ret) - return DO_MAP_REGION_INVALID; - - if (!gasket_mm_get_mapping_addrs(mappable_region, bar_offset, - vma->vm_end - vma->vm_start, - ®ion_to_map, &virt_offset)) - return DO_MAP_REGION_INVALID; - phys_offset = region_to_map.start; - map_length = region_to_map.length_bytes; - - virt_base = vma->vm_start + virt_offset; - bar_index = - gasket_get_bar_index(gasket_dev, - (vma->vm_pgoff << PAGE_SHIFT) + - driver_desc->legacy_mmap_address_offset); - - if (bar_index < 0) - return DO_MAP_REGION_INVALID; - - phys_base = gasket_dev->bar_data[bar_index].phys_base + phys_offset; - while (mapped_bytes < map_length) { - /* - * io_remap_pfn_range can take a while, so we chunk its - * calls and call cond_resched between each. - */ - chunk_size = min(max_chunk_size, map_length - mapped_bytes); - - cond_resched(); - ret = io_remap_pfn_range(vma, virt_base + mapped_bytes, - (phys_base + mapped_bytes) >> - PAGE_SHIFT, chunk_size, - vma->vm_page_prot); - if (ret) { - dev_err(gasket_dev->dev, - "Error remapping PFN range.\n"); - goto fail; - } - mapped_bytes += chunk_size; - } - - return DO_MAP_REGION_SUCCESS; - -fail: - /* Unmap the partial chunk we mapped. */ - mappable_region->length_bytes = mapped_bytes; - if (gasket_mm_unmap_region(gasket_dev, vma, mappable_region)) - dev_err(gasket_dev->dev, - "Error unmapping partial region 0x%lx (0x%lx bytes)\n", - (ulong)virt_offset, - (ulong)mapped_bytes); - - return DO_MAP_REGION_FAILURE; -} - -/* Map a region of coherent memory. */ -static int gasket_mmap_coherent(struct gasket_dev *gasket_dev, - struct vm_area_struct *vma) -{ - const struct gasket_driver_desc *driver_desc = - gasket_dev->internal_desc->driver_desc; - const ulong requested_length = vma->vm_end - vma->vm_start; - int ret; - ulong permissions; - - if (requested_length == 0 || requested_length > - gasket_dev->coherent_buffer.length_bytes) { - trace_gasket_mmap_exit(-EINVAL); - return -EINVAL; - } - - permissions = driver_desc->coherent_buffer_description.permissions; - if (!gasket_mmap_has_permissions(gasket_dev, vma, permissions)) { - dev_err(gasket_dev->dev, "Permission checking failed.\n"); - trace_gasket_mmap_exit(-EPERM); - return -EPERM; - } - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - ret = remap_pfn_range(vma, vma->vm_start, - (gasket_dev->coherent_buffer.phys_base) >> - PAGE_SHIFT, requested_length, vma->vm_page_prot); - if (ret) { - dev_err(gasket_dev->dev, "Error remapping PFN range err=%d.\n", - ret); - trace_gasket_mmap_exit(ret); - return ret; - } - - /* Record the user virtual to dma_address mapping that was - * created by the kernel. - */ - gasket_set_user_virt(gasket_dev, requested_length, - gasket_dev->coherent_buffer.phys_base, - vma->vm_start); - return 0; -} - -/* Map a device's BARs into user space. */ -static int gasket_mmap(struct file *filp, struct vm_area_struct *vma) -{ - int i, ret; - int bar_index; - int has_mapped_anything = 0; - ulong permissions; - ulong raw_offset, vma_size; - bool is_coherent_region; - const struct gasket_driver_desc *driver_desc; - struct gasket_dev *gasket_dev = (struct gasket_dev *)filp->private_data; - const struct gasket_bar_desc *bar_desc; - struct gasket_mappable_region *map_regions = NULL; - int num_map_regions = 0; - enum do_map_region_status map_status; - - driver_desc = gasket_dev->internal_desc->driver_desc; - - if (vma->vm_start & ~PAGE_MASK) { - dev_err(gasket_dev->dev, - "Base address not page-aligned: 0x%lx\n", - vma->vm_start); - trace_gasket_mmap_exit(-EINVAL); - return -EINVAL; - } - - /* Calculate the offset of this range into physical mem. */ - raw_offset = (vma->vm_pgoff << PAGE_SHIFT) + - driver_desc->legacy_mmap_address_offset; - vma_size = vma->vm_end - vma->vm_start; - trace_gasket_mmap_entry(gasket_dev->dev_info.name, raw_offset, - vma_size); - - /* - * Check if the raw offset is within a bar region. If not, check if it - * is a coherent region. - */ - bar_index = gasket_get_bar_index(gasket_dev, raw_offset); - is_coherent_region = gasket_is_coherent_region(driver_desc, raw_offset); - if (bar_index < 0 && !is_coherent_region) { - dev_err(gasket_dev->dev, - "Unable to find matching bar for address 0x%lx\n", - raw_offset); - trace_gasket_mmap_exit(bar_index); - return bar_index; - } - if (bar_index > 0 && is_coherent_region) { - dev_err(gasket_dev->dev, - "double matching bar and coherent buffers for address 0x%lx\n", - raw_offset); - trace_gasket_mmap_exit(bar_index); - return -EINVAL; - } - - vma->vm_private_data = gasket_dev; - - if (is_coherent_region) - return gasket_mmap_coherent(gasket_dev, vma); - - /* Everything in the rest of this function is for normal BAR mapping. */ - - /* - * Subtract the base of the bar from the raw offset to get the - * memory location within the bar to map. - */ - bar_desc = &driver_desc->bar_descriptions[bar_index]; - permissions = bar_desc->permissions; - if (!gasket_mmap_has_permissions(gasket_dev, vma, permissions)) { - dev_err(gasket_dev->dev, "Permission checking failed.\n"); - trace_gasket_mmap_exit(-EPERM); - return -EPERM; - } - - if (driver_desc->get_mappable_regions_cb) { - ret = driver_desc->get_mappable_regions_cb(gasket_dev, - bar_index, - &map_regions, - &num_map_regions); - if (ret) - return ret; - } else { - if (!gasket_mmap_has_permissions(gasket_dev, vma, - bar_desc->permissions)) { - dev_err(gasket_dev->dev, - "Permission checking failed.\n"); - trace_gasket_mmap_exit(-EPERM); - return -EPERM; - } - num_map_regions = bar_desc->num_mappable_regions; - map_regions = kcalloc(num_map_regions, - sizeof(*bar_desc->mappable_regions), - GFP_KERNEL); - if (map_regions) { - memcpy(map_regions, bar_desc->mappable_regions, - num_map_regions * - sizeof(*bar_desc->mappable_regions)); - } - } - - if (!map_regions || num_map_regions == 0) { - dev_err(gasket_dev->dev, "No mappable regions returned!\n"); - return -EINVAL; - } - - /* Marks the VMA's pages as uncacheable. */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - for (i = 0; i < num_map_regions; i++) { - map_status = do_map_region(gasket_dev, vma, &map_regions[i]); - /* Try the next region if this one was not mappable. */ - if (map_status == DO_MAP_REGION_INVALID) - continue; - if (map_status == DO_MAP_REGION_FAILURE) { - ret = -ENOMEM; - goto fail; - } - - has_mapped_anything = 1; - } - - kfree(map_regions); - - /* If we could not map any memory, the request was invalid. */ - if (!has_mapped_anything) { - dev_err(gasket_dev->dev, - "Map request did not contain a valid region.\n"); - trace_gasket_mmap_exit(-EINVAL); - return -EINVAL; - } - - trace_gasket_mmap_exit(0); - return 0; - -fail: - /* Need to unmap any mapped ranges. */ - num_map_regions = i; - for (i = 0; i < num_map_regions; i++) - if (gasket_mm_unmap_region(gasket_dev, vma, - &bar_desc->mappable_regions[i])) - dev_err(gasket_dev->dev, "Error unmapping range %d.\n", - i); - kfree(map_regions); - - return ret; -} - -/* - * Open the char device file. - * - * If the open is for writing, and the device is not owned, this process becomes - * the owner. If the open is for writing and the device is already owned by - * some other process, it is an error. If this process is the owner, increment - * the open count. - * - * Returns 0 if successful, a negative error number otherwise. - */ -static int gasket_open(struct inode *inode, struct file *filp) -{ - int ret; - struct gasket_dev *gasket_dev; - const struct gasket_driver_desc *driver_desc; - struct gasket_ownership *ownership; - char task_name[TASK_COMM_LEN]; - struct gasket_cdev_info *dev_info = - container_of(inode->i_cdev, struct gasket_cdev_info, cdev); - struct pid_namespace *pid_ns = task_active_pid_ns(current); - bool is_root = ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN); - - gasket_dev = dev_info->gasket_dev_ptr; - driver_desc = gasket_dev->internal_desc->driver_desc; - ownership = &dev_info->ownership; - get_task_comm(task_name, current); - filp->private_data = gasket_dev; - inode->i_size = 0; - - dev_dbg(gasket_dev->dev, - "Attempting to open with tgid %u (%s) (f_mode: 0%03o, fmode_write: %d is_root: %u)\n", - current->tgid, task_name, filp->f_mode, - (filp->f_mode & FMODE_WRITE), is_root); - - /* Always allow non-writing accesses. */ - if (!(filp->f_mode & FMODE_WRITE)) { - dev_dbg(gasket_dev->dev, "Allowing read-only opening.\n"); - return 0; - } - - mutex_lock(&gasket_dev->mutex); - - dev_dbg(gasket_dev->dev, - "Current owner open count (owning tgid %u): %d.\n", - ownership->owner, ownership->write_open_count); - - /* Opening a node owned by another TGID is an error (unless root) */ - if (ownership->is_owned && ownership->owner != current->tgid && - !is_root) { - dev_err(gasket_dev->dev, - "Process %u is opening a node held by %u.\n", - current->tgid, ownership->owner); - mutex_unlock(&gasket_dev->mutex); - return -EPERM; - } - - /* If the node is not owned, assign it to the current TGID. */ - if (!ownership->is_owned) { - ret = gasket_check_and_invoke_callback_nolock(gasket_dev, - driver_desc->device_open_cb); - if (ret) { - dev_err(gasket_dev->dev, - "Error in device open cb: %d\n", ret); - mutex_unlock(&gasket_dev->mutex); - return ret; - } - ownership->is_owned = 1; - ownership->owner = current->tgid; - dev_dbg(gasket_dev->dev, "Device owner is now tgid %u\n", - ownership->owner); - } - - ownership->write_open_count++; - - dev_dbg(gasket_dev->dev, "New open count (owning tgid %u): %d\n", - ownership->owner, ownership->write_open_count); - - mutex_unlock(&gasket_dev->mutex); - return 0; -} - -/* - * Called on a close of the device file. If this process is the owner, - * decrement the open count. On last close by the owner, free up buffers and - * eventfd contexts, and release ownership. - * - * Returns 0 if successful, a negative error number otherwise. - */ -static int gasket_release(struct inode *inode, struct file *file) -{ - int i; - struct gasket_dev *gasket_dev; - struct gasket_ownership *ownership; - const struct gasket_driver_desc *driver_desc; - char task_name[TASK_COMM_LEN]; - struct gasket_cdev_info *dev_info = - container_of(inode->i_cdev, struct gasket_cdev_info, cdev); - struct pid_namespace *pid_ns = task_active_pid_ns(current); - bool is_root = ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN); - - gasket_dev = dev_info->gasket_dev_ptr; - driver_desc = gasket_dev->internal_desc->driver_desc; - ownership = &dev_info->ownership; - get_task_comm(task_name, current); - mutex_lock(&gasket_dev->mutex); - - dev_dbg(gasket_dev->dev, - "Releasing device node. Call origin: tgid %u (%s) (f_mode: 0%03o, fmode_write: %d, is_root: %u)\n", - current->tgid, task_name, file->f_mode, - (file->f_mode & FMODE_WRITE), is_root); - dev_dbg(gasket_dev->dev, "Current open count (owning tgid %u): %d\n", - ownership->owner, ownership->write_open_count); - - if (file->f_mode & FMODE_WRITE) { - ownership->write_open_count--; - if (ownership->write_open_count == 0) { - dev_dbg(gasket_dev->dev, "Device is now free\n"); - ownership->is_owned = 0; - ownership->owner = 0; - - /* Forces chip reset before we unmap the page tables. */ - driver_desc->device_reset_cb(gasket_dev); - - for (i = 0; i < driver_desc->num_page_tables; ++i) { - gasket_page_table_unmap_all(gasket_dev->page_table[i]); - gasket_page_table_garbage_collect(gasket_dev->page_table[i]); - gasket_free_coherent_memory_all(gasket_dev, i); - } - - /* Closes device, enters power save. */ - gasket_check_and_invoke_callback_nolock(gasket_dev, - driver_desc->device_close_cb); - } - } - - dev_dbg(gasket_dev->dev, "New open count (owning tgid %u): %d\n", - ownership->owner, ownership->write_open_count); - mutex_unlock(&gasket_dev->mutex); - return 0; -} - -/* - * Gasket ioctl dispatch function. - * - * Check if the ioctl is a generic ioctl. If not, pass the ioctl to the - * ioctl_handler_cb registered in the driver description. - * If the ioctl is a generic ioctl, pass it to gasket_ioctl_handler. - */ -static long gasket_ioctl(struct file *filp, uint cmd, ulong arg) -{ - struct gasket_dev *gasket_dev; - const struct gasket_driver_desc *driver_desc; - void __user *argp = (void __user *)arg; - char path[256]; - - gasket_dev = (struct gasket_dev *)filp->private_data; - driver_desc = gasket_dev->internal_desc->driver_desc; - if (!driver_desc) { - dev_dbg(gasket_dev->dev, - "Unable to find device descriptor for file %s\n", - d_path(&filp->f_path, path, 256)); - return -ENODEV; - } - - if (!gasket_is_supported_ioctl(cmd)) { - /* - * The ioctl handler is not a standard Gasket callback, since - * it requires different arguments. This means we can't use - * check_and_invoke_callback. - */ - if (driver_desc->ioctl_handler_cb) - return driver_desc->ioctl_handler_cb(filp, cmd, argp); - - dev_dbg(gasket_dev->dev, "Received unknown ioctl 0x%x\n", cmd); - return -EINVAL; - } - - return gasket_handle_ioctl(filp, cmd, argp); -} - -/* File operations for all Gasket devices. */ -static const struct file_operations gasket_file_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .mmap = gasket_mmap, - .open = gasket_open, - .release = gasket_release, - .unlocked_ioctl = gasket_ioctl, -}; - -/* Perform final init and marks the device as active. */ -int gasket_enable_device(struct gasket_dev *gasket_dev) -{ - int tbl_idx; - int ret; - const struct gasket_driver_desc *driver_desc = - gasket_dev->internal_desc->driver_desc; - - ret = gasket_interrupt_init(gasket_dev); - if (ret) { - dev_err(gasket_dev->dev, - "Critical failure to allocate interrupts: %d\n", ret); - gasket_interrupt_cleanup(gasket_dev); - return ret; - } - - for (tbl_idx = 0; tbl_idx < driver_desc->num_page_tables; tbl_idx++) { - dev_dbg(gasket_dev->dev, "Initializing page table %d.\n", - tbl_idx); - ret = gasket_page_table_init(&gasket_dev->page_table[tbl_idx], - &gasket_dev->bar_data[driver_desc->page_table_bar_index], - &driver_desc->page_table_configs[tbl_idx], - gasket_dev->dev, - gasket_dev->pci_dev); - if (ret) { - dev_err(gasket_dev->dev, - "Couldn't init page table %d: %d\n", - tbl_idx, ret); - return ret; - } - /* - * Make sure that the page table is clear and set to simple - * addresses. - */ - gasket_page_table_reset(gasket_dev->page_table[tbl_idx]); - } - - /* - * hardware_revision_cb returns a positive integer (the rev) if - * successful.) - */ - ret = check_and_invoke_callback(gasket_dev, - driver_desc->hardware_revision_cb); - if (ret < 0) { - dev_err(gasket_dev->dev, - "Error getting hardware revision: %d\n", ret); - return ret; - } - gasket_dev->hardware_revision = ret; - - /* device_status_cb returns a device status, not an error code. */ - gasket_dev->status = gasket_get_hw_status(gasket_dev); - if (gasket_dev->status == GASKET_STATUS_DEAD) - dev_err(gasket_dev->dev, "Device reported as unhealthy.\n"); - - ret = gasket_add_cdev(&gasket_dev->dev_info, &gasket_file_ops, - driver_desc->module); - if (ret) - return ret; - - return 0; -} -EXPORT_SYMBOL(gasket_enable_device); - -static int __gasket_add_device(struct device *parent_dev, - struct gasket_internal_desc *internal_desc, - struct gasket_dev **gasket_devp) -{ - int ret; - struct gasket_dev *gasket_dev; - const struct gasket_driver_desc *driver_desc = - internal_desc->driver_desc; - - ret = gasket_alloc_dev(internal_desc, parent_dev, &gasket_dev); - if (ret) - return ret; - if (IS_ERR(gasket_dev->dev_info.device)) { - dev_err(parent_dev, "Cannot create %s device %s [ret = %ld]\n", - driver_desc->name, gasket_dev->dev_info.name, - PTR_ERR(gasket_dev->dev_info.device)); - ret = -ENODEV; - goto free_gasket_dev; - } - - ret = gasket_sysfs_create_mapping(gasket_dev->dev_info.device, - gasket_dev); - if (ret) - goto remove_device; - - ret = gasket_sysfs_create_entries(gasket_dev->dev_info.device, - gasket_sysfs_generic_attrs); - if (ret) - goto remove_sysfs_mapping; - - *gasket_devp = gasket_dev; - return 0; - -remove_sysfs_mapping: - gasket_sysfs_remove_mapping(gasket_dev->dev_info.device); -remove_device: - device_destroy(internal_desc->class, gasket_dev->dev_info.devt); -free_gasket_dev: - gasket_free_dev(gasket_dev); - return ret; -} - -static void __gasket_remove_device(struct gasket_internal_desc *internal_desc, - struct gasket_dev *gasket_dev) -{ - gasket_sysfs_remove_mapping(gasket_dev->dev_info.device); - device_destroy(internal_desc->class, gasket_dev->dev_info.devt); - gasket_free_dev(gasket_dev); -} - -/* - * Add PCI gasket device. - * - * Called by Gasket device probe function. - * Allocates device metadata and maps device memory. The device driver must - * call gasket_enable_device after driver init is complete to place the device - * in active use. - */ -int gasket_pci_add_device(struct pci_dev *pci_dev, - struct gasket_dev **gasket_devp) -{ - int ret; - struct gasket_internal_desc *internal_desc; - struct gasket_dev *gasket_dev; - struct device *parent; - - dev_dbg(&pci_dev->dev, "add PCI gasket device\n"); - - mutex_lock(&g_mutex); - internal_desc = lookup_pci_internal_desc(pci_dev); - mutex_unlock(&g_mutex); - if (!internal_desc) { - dev_err(&pci_dev->dev, - "PCI add device called for unknown driver type\n"); - return -ENODEV; - } - - parent = &pci_dev->dev; - ret = __gasket_add_device(parent, internal_desc, &gasket_dev); - if (ret) - return ret; - - gasket_dev->pci_dev = pci_dev; - ret = gasket_setup_pci(pci_dev, gasket_dev); - if (ret) - goto cleanup_pci; - - /* - * Once we've created the mapping structures successfully, attempt to - * create a symlink to the pci directory of this object. - */ - ret = sysfs_create_link(&gasket_dev->dev_info.device->kobj, - &pci_dev->dev.kobj, dev_name(&pci_dev->dev)); - if (ret) { - dev_err(gasket_dev->dev, - "Cannot create sysfs pci link: %d\n", ret); - goto cleanup_pci; - } - - *gasket_devp = gasket_dev; - return 0; - -cleanup_pci: - gasket_cleanup_pci(gasket_dev); - __gasket_remove_device(internal_desc, gasket_dev); - return ret; -} -EXPORT_SYMBOL(gasket_pci_add_device); - -/* Remove a PCI gasket device. */ -void gasket_pci_remove_device(struct pci_dev *pci_dev) -{ - int i; - struct gasket_internal_desc *internal_desc; - struct gasket_dev *gasket_dev = NULL; - /* Find the device desc. */ - mutex_lock(&g_mutex); - internal_desc = lookup_pci_internal_desc(pci_dev); - if (!internal_desc) { - mutex_unlock(&g_mutex); - return; - } - mutex_unlock(&g_mutex); - - /* Now find the specific device */ - mutex_lock(&internal_desc->mutex); - for (i = 0; i < GASKET_DEV_MAX; i++) { - if (internal_desc->devs[i] && - internal_desc->devs[i]->pci_dev == pci_dev) { - gasket_dev = internal_desc->devs[i]; - break; - } - } - mutex_unlock(&internal_desc->mutex); - - if (!gasket_dev) - return; - - dev_dbg(gasket_dev->dev, "remove %s PCI gasket device\n", - internal_desc->driver_desc->name); - - gasket_cleanup_pci(gasket_dev); - __gasket_remove_device(internal_desc, gasket_dev); -} -EXPORT_SYMBOL(gasket_pci_remove_device); - -/** - * Lookup a name by number in a num_name table. - * @num: Number to lookup. - * @table: Array of num_name structures, the table for the lookup. - * - * Description: Searches for num in the table. If found, the - * corresponding name is returned; otherwise NULL - * is returned. - * - * The table must have a NULL name pointer at the end. - */ -const char *gasket_num_name_lookup(uint num, - const struct gasket_num_name *table) -{ - uint i = 0; - - while (table[i].snn_name) { - if (num == table[i].snn_num) - break; - ++i; - } - - return table[i].snn_name; -} -EXPORT_SYMBOL(gasket_num_name_lookup); - -int gasket_reset(struct gasket_dev *gasket_dev) -{ - int ret; - - mutex_lock(&gasket_dev->mutex); - ret = gasket_reset_nolock(gasket_dev); - mutex_unlock(&gasket_dev->mutex); - return ret; -} -EXPORT_SYMBOL(gasket_reset); - -int gasket_reset_nolock(struct gasket_dev *gasket_dev) -{ - int ret; - int i; - const struct gasket_driver_desc *driver_desc; - - driver_desc = gasket_dev->internal_desc->driver_desc; - if (!driver_desc->device_reset_cb) - return 0; - - ret = driver_desc->device_reset_cb(gasket_dev); - if (ret) { - dev_dbg(gasket_dev->dev, "Device reset cb returned %d.\n", - ret); - return ret; - } - - /* Reinitialize the page tables and interrupt framework. */ - for (i = 0; i < driver_desc->num_page_tables; ++i) - gasket_page_table_reset(gasket_dev->page_table[i]); - - ret = gasket_interrupt_reinit(gasket_dev); - if (ret) { - dev_dbg(gasket_dev->dev, "Unable to reinit interrupts: %d.\n", - ret); - return ret; - } - - /* Get current device health. */ - gasket_dev->status = gasket_get_hw_status(gasket_dev); - if (gasket_dev->status == GASKET_STATUS_DEAD) { - dev_dbg(gasket_dev->dev, "Device reported as dead.\n"); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(gasket_reset_nolock); - -gasket_ioctl_permissions_cb_t -gasket_get_ioctl_permissions_cb(struct gasket_dev *gasket_dev) -{ - return gasket_dev->internal_desc->driver_desc->ioctl_permissions_cb; -} -EXPORT_SYMBOL(gasket_get_ioctl_permissions_cb); - -/* Get the driver structure for a given gasket_dev. - * @dev: pointer to gasket_dev, implementing the requested driver. - */ -const struct gasket_driver_desc *gasket_get_driver_desc(struct gasket_dev *dev) -{ - return dev->internal_desc->driver_desc; -} - -/* Get the device structure for a given gasket_dev. - * @dev: pointer to gasket_dev, implementing the requested driver. - */ -struct device *gasket_get_device(struct gasket_dev *dev) -{ - return dev->dev; -} - -/** - * Asynchronously waits on device. - * @gasket_dev: Device struct. - * @bar: Bar - * @offset: Register offset - * @mask: Register mask - * @val: Expected value - * @max_retries: number of sleep periods - * @delay_ms: Timeout in milliseconds - * - * Description: Busy waits for a specific combination of bits to be set on a - * Gasket register. - **/ -int gasket_wait_with_reschedule(struct gasket_dev *gasket_dev, int bar, - u64 offset, u64 mask, u64 val, - uint max_retries, u64 delay_ms) -{ - uint retries = 0; - u64 tmp; - - while (retries < max_retries) { - tmp = gasket_dev_read_64(gasket_dev, bar, offset); - if ((tmp & mask) == val) - return 0; - msleep(delay_ms); - retries++; - } - dev_dbg(gasket_dev->dev, "%s timeout: reg %llx timeout (%llu ms)\n", - __func__, offset, max_retries * delay_ms); - return -ETIMEDOUT; -} -EXPORT_SYMBOL(gasket_wait_with_reschedule); - -/* See gasket_core.h for description. */ -int gasket_register_device(const struct gasket_driver_desc *driver_desc) -{ - int i, ret; - int desc_idx = -1; - struct gasket_internal_desc *internal; - - pr_debug("Loading %s driver version %s\n", driver_desc->name, - driver_desc->driver_version); - /* Check for duplicates and find a free slot. */ - mutex_lock(&g_mutex); - - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (g_descs[i].driver_desc == driver_desc) { - pr_err("%s driver already loaded/registered\n", - driver_desc->name); - mutex_unlock(&g_mutex); - return -EBUSY; - } - } - - /* This and the above loop could be combined, but this reads easier. */ - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (!g_descs[i].driver_desc) { - g_descs[i].driver_desc = driver_desc; - desc_idx = i; - break; - } - } - mutex_unlock(&g_mutex); - - if (desc_idx == -1) { - pr_err("too many drivers loaded, max %d\n", - GASKET_FRAMEWORK_DESC_MAX); - return -EBUSY; - } - - internal = &g_descs[desc_idx]; - mutex_init(&internal->mutex); - memset(internal->devs, 0, sizeof(struct gasket_dev *) * GASKET_DEV_MAX); - internal->class = - class_create(driver_desc->module, driver_desc->name); - - if (IS_ERR(internal->class)) { - pr_err("Cannot register %s class [ret=%ld]\n", - driver_desc->name, PTR_ERR(internal->class)); - ret = PTR_ERR(internal->class); - goto unregister_gasket_driver; - } - - ret = register_chrdev_region(MKDEV(driver_desc->major, - driver_desc->minor), GASKET_DEV_MAX, - driver_desc->name); - if (ret) { - pr_err("cannot register %s char driver [ret=%d]\n", - driver_desc->name, ret); - goto destroy_class; - } - - return 0; - -destroy_class: - class_destroy(internal->class); - -unregister_gasket_driver: - mutex_lock(&g_mutex); - g_descs[desc_idx].driver_desc = NULL; - mutex_unlock(&g_mutex); - return ret; -} -EXPORT_SYMBOL(gasket_register_device); - -/* See gasket_core.h for description. */ -void gasket_unregister_device(const struct gasket_driver_desc *driver_desc) -{ - int i, desc_idx; - struct gasket_internal_desc *internal_desc = NULL; - - mutex_lock(&g_mutex); - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (g_descs[i].driver_desc == driver_desc) { - internal_desc = &g_descs[i]; - desc_idx = i; - break; - } - } - - if (!internal_desc) { - mutex_unlock(&g_mutex); - pr_err("request to unregister unknown desc: %s, %d:%d\n", - driver_desc->name, driver_desc->major, - driver_desc->minor); - return; - } - - unregister_chrdev_region(MKDEV(driver_desc->major, driver_desc->minor), - GASKET_DEV_MAX); - - class_destroy(internal_desc->class); - - /* Finally, effectively "remove" the driver. */ - g_descs[desc_idx].driver_desc = NULL; - mutex_unlock(&g_mutex); - - pr_debug("removed %s driver\n", driver_desc->name); -} -EXPORT_SYMBOL(gasket_unregister_device); - -static int __init gasket_init(void) -{ - int i; - - mutex_lock(&g_mutex); - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - g_descs[i].driver_desc = NULL; - mutex_init(&g_descs[i].mutex); - } - - gasket_sysfs_init(); - - mutex_unlock(&g_mutex); - return 0; -} - -MODULE_DESCRIPTION("Google Gasket driver framework"); -MODULE_VERSION(GASKET_FRAMEWORK_VERSION); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Rob Springer <rspringer@google.com>"); -module_init(gasket_init); diff --git a/drivers/staging/gasket/gasket_core.h b/drivers/staging/gasket/gasket_core.h deleted file mode 100644 index c417acadb0d51ac2d9f2b235da6fb3e9f1d8966b..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_core.h +++ /dev/null @@ -1,638 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Gasket generic driver. Defines the set of data types and functions necessary - * to define a driver using the Gasket generic driver framework. - * - * Copyright (C) 2018 Google, Inc. - */ -#ifndef __GASKET_CORE_H__ -#define __GASKET_CORE_H__ - -#include <linux/cdev.h> -#include <linux/compiler.h> -#include <linux/device.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/slab.h> - -#include "gasket_constants.h" - -/** - * struct gasket_num_name - Map numbers to names. - * @ein_num: Number. - * @ein_name: Name associated with the number, a char pointer. - * - * This structure maps numbers to names. It is used to provide printable enum - * names, e.g {0, "DEAD"} or {1, "ALIVE"}. - */ -struct gasket_num_name { - uint snn_num; - const char *snn_name; -}; - -/* - * Register location for packed interrupts. - * Each value indicates the location of an interrupt field (in units of - * gasket_driver_desc->interrupt_pack_width) within the containing register. - * In other words, this indicates the shift to use when creating a mask to - * extract/set bits within a register for a given interrupt. - */ -enum gasket_interrupt_packing { - PACK_0 = 0, - PACK_1 = 1, - PACK_2 = 2, - PACK_3 = 3, - UNPACKED = 4, -}; - -/* Type of the interrupt supported by the device. */ -enum gasket_interrupt_type { - PCI_MSIX = 0, -}; - -/* - * Used to describe a Gasket interrupt. Contains an interrupt index, a register, - * and packing data for that interrupt. The register and packing data - * fields are relevant only for PCI_MSIX interrupt type and can be - * set to 0 for everything else. - */ -struct gasket_interrupt_desc { - /* Device-wide interrupt index/number. */ - int index; - /* The register offset controlling this interrupt. */ - u64 reg; - /* The location of this interrupt inside register reg, if packed. */ - int packing; -}; - -/* - * This enum is used to identify memory regions being part of the physical - * memory that belongs to a device. - */ -enum mappable_area_type { - PCI_BAR = 0, /* Default */ - BUS_REGION, /* For SYSBUS devices, i.e. AXI etc... */ - COHERENT_MEMORY -}; - -/* - * Metadata for each BAR mapping. - * This struct is used so as to track PCI memory, I/O space, AXI and coherent - * memory area... i.e. memory objects which can be referenced in the device's - * mmap function. - */ -struct gasket_bar_data { - /* Virtual base address. */ - u8 __iomem *virt_base; - - /* Physical base address. */ - ulong phys_base; - - /* Length of the mapping. */ - ulong length_bytes; - - /* Type of mappable area */ - enum mappable_area_type type; -}; - -/* Maintains device open ownership data. */ -struct gasket_ownership { - /* 1 if the device is owned, 0 otherwise. */ - int is_owned; - - /* TGID of the owner. */ - pid_t owner; - - /* Count of current device opens in write mode. */ - int write_open_count; -}; - -/* Page table modes of operation. */ -enum gasket_page_table_mode { - /* The page table is partitionable as normal, all simple by default. */ - GASKET_PAGE_TABLE_MODE_NORMAL, - - /* All entries are always simple. */ - GASKET_PAGE_TABLE_MODE_SIMPLE, - - /* All entries are always extended. No extended bit is used. */ - GASKET_PAGE_TABLE_MODE_EXTENDED, -}; - -/* Page table configuration. One per table. */ -struct gasket_page_table_config { - /* The identifier/index of this page table. */ - int id; - - /* The operation mode of this page table. */ - enum gasket_page_table_mode mode; - - /* Total (first-level) entries in this page table. */ - ulong total_entries; - - /* Base register for the page table. */ - int base_reg; - - /* - * Register containing the extended page table. This value is unused in - * GASKET_PAGE_TABLE_MODE_SIMPLE and GASKET_PAGE_TABLE_MODE_EXTENDED - * modes. - */ - int extended_reg; - - /* The bit index indicating whether a PT entry is extended. */ - int extended_bit; -}; - -/* Maintains information about a device node. */ -struct gasket_cdev_info { - /* The internal name of this device. */ - char name[GASKET_NAME_MAX]; - - /* Device number. */ - dev_t devt; - - /* Kernel-internal device structure. */ - struct device *device; - - /* Character device for real. */ - struct cdev cdev; - - /* Flag indicating if cdev_add has been called for the devices. */ - int cdev_added; - - /* Pointer to the overall gasket_dev struct for this device. */ - struct gasket_dev *gasket_dev_ptr; - - /* Ownership data for the device in question. */ - struct gasket_ownership ownership; -}; - -/* Describes the offset and length of mmapable device BAR regions. */ -struct gasket_mappable_region { - u64 start; - u64 length_bytes; -}; - -/* Describe the offset, size, and permissions for a device bar. */ -struct gasket_bar_desc { - /* - * The size of each PCI BAR range, in bytes. If a value is 0, that BAR - * will not be mapped into kernel space at all. - * For devices with 64 bit BARs, only elements 0, 2, and 4 should be - * populated, and 1, 3, and 5 should be set to 0. - * For example, for a device mapping 1M in each of the first two 64-bit - * BARs, this field would be set as { 0x100000, 0, 0x100000, 0, 0, 0 } - * (one number per bar_desc struct.) - */ - u64 size; - /* The permissions for this bar. (Should be VM_WRITE/VM_READ/VM_EXEC, - * and can be or'd.) If set to GASKET_NOMAP, the bar will - * not be used for mmapping. - */ - ulong permissions; - /* The memory address corresponding to the base of this bar, if used. */ - u64 base; - /* The number of mappable regions in this bar. */ - int num_mappable_regions; - - /* The mappable subregions of this bar. */ - const struct gasket_mappable_region *mappable_regions; - - /* Type of mappable area */ - enum mappable_area_type type; -}; - -/* Describes the offset, size, and permissions for a coherent buffer. */ -struct gasket_coherent_buffer_desc { - /* The size of the coherent buffer. */ - u64 size; - - /* The permissions for this bar. (Should be VM_WRITE/VM_READ/VM_EXEC, - * and can be or'd.) If set to GASKET_NOMAP, the bar will - * not be used for mmaping. - */ - ulong permissions; - - /* device side address. */ - u64 base; -}; - -/* Coherent buffer structure. */ -struct gasket_coherent_buffer { - /* Virtual base address. */ - u8 *virt_base; - - /* Physical base address. */ - ulong phys_base; - - /* Length of the mapping. */ - ulong length_bytes; -}; - -/* Description of Gasket-specific permissions in the mmap field. */ -enum gasket_mapping_options { GASKET_NOMAP = 0 }; - -/* This struct represents an undefined bar that should never be mapped. */ -#define GASKET_UNUSED_BAR \ - { \ - 0, GASKET_NOMAP, 0, 0, NULL, 0 \ - } - -/* Internal data for a Gasket device. See gasket_core.c for more information. */ -struct gasket_internal_desc; - -#define MAX_NUM_COHERENT_PAGES 16 - -/* - * Device data for Gasket device instances. - * - * This structure contains the data required to manage a Gasket device. - */ -struct gasket_dev { - /* Pointer to the internal driver description for this device. */ - struct gasket_internal_desc *internal_desc; - - /* Device info */ - struct device *dev; - - /* PCI subsystem metadata. */ - struct pci_dev *pci_dev; - - /* This device's index into internal_desc->devs. */ - int dev_idx; - - /* The name of this device, as reported by the kernel. */ - char kobj_name[GASKET_NAME_MAX]; - - /* Virtual address of mapped BAR memory range. */ - struct gasket_bar_data bar_data[PCI_STD_NUM_BARS]; - - /* Coherent buffer. */ - struct gasket_coherent_buffer coherent_buffer; - - /* Number of page tables for this device. */ - int num_page_tables; - - /* Address translations. Page tables have a private implementation. */ - struct gasket_page_table *page_table[GASKET_MAX_NUM_PAGE_TABLES]; - - /* Interrupt data for this device. */ - struct gasket_interrupt_data *interrupt_data; - - /* Status for this device - GASKET_STATUS_ALIVE or _DEAD. */ - uint status; - - /* Number of times this device has been reset. */ - uint reset_count; - - /* Dev information for the cdev node. */ - struct gasket_cdev_info dev_info; - - /* Hardware revision value for this device. */ - int hardware_revision; - - /* Protects access to per-device data (i.e. this structure). */ - struct mutex mutex; - - /* cdev hash tracking/membership structure, Accel and legacy. */ - /* Unused until Accel is upstreamed. */ - struct hlist_node hlist_node; - struct hlist_node legacy_hlist_node; -}; - -/* Type of the ioctl handler callback. */ -typedef long (*gasket_ioctl_handler_cb_t)(struct file *file, uint cmd, - void __user *argp); -/* Type of the ioctl permissions check callback. See below. */ -typedef int (*gasket_ioctl_permissions_cb_t)(struct file *filp, uint cmd, - void __user *argp); - -/* - * Device type descriptor. - * - * This structure contains device-specific data needed to identify and address a - * type of device to be administered via the Gasket generic driver. - * - * Device IDs are per-driver. In other words, two drivers using the Gasket - * framework will each have a distinct device 0 (for example). - */ -struct gasket_driver_desc { - /* The name of this device type. */ - const char *name; - - /* The name of this specific device model. */ - const char *chip_model; - - /* The version of the chip specified in chip_model. */ - const char *chip_version; - - /* The version of this driver: "1.0.0", "2.1.3", etc. */ - const char *driver_version; - - /* - * Non-zero if we should create "legacy" (device and device-class- - * specific) character devices and sysfs nodes. - */ - /* Unused until Accel is upstreamed. */ - int legacy_support; - - /* Major and minor numbers identifying the device. */ - int major, minor; - - /* Module structure for this driver. */ - struct module *module; - - /* PCI ID table. */ - const struct pci_device_id *pci_id_table; - - /* The number of page tables handled by this driver. */ - int num_page_tables; - - /* The index of the bar containing the page tables. */ - int page_table_bar_index; - - /* Registers used to control each page table. */ - const struct gasket_page_table_config *page_table_configs; - - /* The bit index indicating whether a PT entry is extended. */ - int page_table_extended_bit; - - /* - * Legacy mmap address adjusment for legacy devices only. Should be 0 - * for any new device. - */ - ulong legacy_mmap_address_offset; - - /* Set of 6 bar descriptions that describe all PCIe bars. - * Note that BUS/AXI devices (i.e. non PCI devices) use those. - */ - struct gasket_bar_desc bar_descriptions[PCI_STD_NUM_BARS]; - - /* - * Coherent buffer description. - */ - struct gasket_coherent_buffer_desc coherent_buffer_description; - - /* Interrupt type. (One of gasket_interrupt_type). */ - int interrupt_type; - - /* Index of the bar containing the interrupt registers to program. */ - int interrupt_bar_index; - - /* Number of interrupts in the gasket_interrupt_desc array */ - int num_interrupts; - - /* Description of the interrupts for this device. */ - const struct gasket_interrupt_desc *interrupts; - - /* - * If this device packs multiple interrupt->MSI-X mappings into a - * single register (i.e., "uses packed interrupts"), only a single bit - * width is supported for each interrupt mapping (unpacked/"full-width" - * interrupts are always supported). This value specifies that width. If - * packed interrupts are not used, this value is ignored. - */ - int interrupt_pack_width; - - /* Driver callback functions - all may be NULL */ - /* - * device_open_cb: Callback for when a device node is opened in write - * mode. - * @dev: The gasket_dev struct for this driver instance. - * - * This callback should perform device-specific setup that needs to - * occur only once when a device is first opened. - */ - int (*device_open_cb)(struct gasket_dev *dev); - - /* - * device_release_cb: Callback when a device is closed. - * @gasket_dev: The gasket_dev struct for this driver instance. - * - * This callback is called whenever a device node fd is closed, as - * opposed to device_close_cb, which is called when the _last_ - * descriptor for an open file is closed. This call is intended to - * handle any per-user or per-fd cleanup. - */ - int (*device_release_cb)(struct gasket_dev *gasket_dev, - struct file *file); - - /* - * device_close_cb: Callback for when a device node is closed for the - * last time. - * @dev: The gasket_dev struct for this driver instance. - * - * This callback should perform device-specific cleanup that only - * needs to occur when the last reference to a device node is closed. - * - * This call is intended to handle and device-wide cleanup, as opposed - * to per-fd cleanup (which should be handled by device_release_cb). - */ - int (*device_close_cb)(struct gasket_dev *dev); - - /* - * get_mappable_regions_cb: Get descriptors of mappable device memory. - * @gasket_dev: Pointer to the struct gasket_dev for this device. - * @bar_index: BAR for which to retrieve memory ranges. - * @mappable_regions: Out-pointer to the list of mappable regions on the - * device/BAR for this process. - * @num_mappable_regions: Out-pointer for the size of mappable_regions. - * - * Called when handling mmap(), this callback is used to determine which - * regions of device memory may be mapped by the current process. This - * information is then compared to mmap request to determine which - * regions to actually map. - */ - int (*get_mappable_regions_cb)(struct gasket_dev *gasket_dev, - int bar_index, - struct gasket_mappable_region **mappable_regions, - int *num_mappable_regions); - - /* - * ioctl_permissions_cb: Check permissions for generic ioctls. - * @filp: File structure pointer describing this node usage session. - * @cmd: ioctl number to handle. - * @arg: ioctl-specific data pointer. - * - * Returns 1 if the ioctl may be executed, 0 otherwise. If this callback - * isn't specified a default routine will be used, that only allows the - * original device opener (i.e, the "owner") to execute state-affecting - * ioctls. - */ - gasket_ioctl_permissions_cb_t ioctl_permissions_cb; - - /* - * ioctl_handler_cb: Callback to handle device-specific ioctls. - * @filp: File structure pointer describing this node usage session. - * @cmd: ioctl number to handle. - * @arg: ioctl-specific data pointer. - * - * Invoked whenever an ioctl is called that the generic Gasket - * framework doesn't support. If no cb is registered, unknown ioctls - * return -EINVAL. Should return an error status (either -EINVAL or - * the error result of the ioctl being handled). - */ - gasket_ioctl_handler_cb_t ioctl_handler_cb; - - /* - * device_status_cb: Callback to determine device health. - * @dev: Pointer to the gasket_dev struct for this device. - * - * Called to determine if the device is healthy or not. Should return - * a member of the gasket_status_type enum. - * - */ - int (*device_status_cb)(struct gasket_dev *dev); - - /* - * hardware_revision_cb: Get the device's hardware revision. - * @dev: Pointer to the gasket_dev struct for this device. - * - * Called to determine the reported rev of the physical hardware. - * Revision should be >0. A negative return value is an error. - */ - int (*hardware_revision_cb)(struct gasket_dev *dev); - - /* - * device_reset_cb: Reset the hardware in question. - * @dev: Pointer to the gasket_dev structure for this device. - * - * Called by reset ioctls. This function should not - * lock the gasket_dev mutex. It should return 0 on success - * and an error on failure. - */ - int (*device_reset_cb)(struct gasket_dev *dev); -}; - -/* - * Register the specified device type with the framework. - * @desc: Populated/initialized device type descriptor. - * - * This function does _not_ take ownership of desc; the underlying struct must - * exist until the matching call to gasket_unregister_device. - * This function should be called from your driver's module_init function. - */ -int gasket_register_device(const struct gasket_driver_desc *desc); - -/* - * Remove the specified device type from the framework. - * @desc: Descriptor for the device type to unregister; it should have been - * passed to gasket_register_device in a previous call. - * - * This function should be called from your driver's module_exit function. - */ -void gasket_unregister_device(const struct gasket_driver_desc *desc); - -/* Add a PCI gasket device. */ -int gasket_pci_add_device(struct pci_dev *pci_dev, - struct gasket_dev **gasket_devp); -/* Remove a PCI gasket device. */ -void gasket_pci_remove_device(struct pci_dev *pci_dev); - -/* Enable a Gasket device. */ -int gasket_enable_device(struct gasket_dev *gasket_dev); - -/* Disable a Gasket device. */ -void gasket_disable_device(struct gasket_dev *gasket_dev); - -/* - * Reset the Gasket device. - * @gasket_dev: Gasket device struct. - * - * Calls device_reset_cb. Returns 0 on success and an error code othewrise. - * gasket_reset_nolock will not lock the mutex, gasket_reset will. - * - */ -int gasket_reset(struct gasket_dev *gasket_dev); -int gasket_reset_nolock(struct gasket_dev *gasket_dev); - -/* - * Memory management functions. These will likely be spun off into their own - * file in the future. - */ - -/* Unmaps the specified mappable region from a VMA. */ -int gasket_mm_unmap_region(const struct gasket_dev *gasket_dev, - struct vm_area_struct *vma, - const struct gasket_mappable_region *map_region); - -/* - * Get the ioctl permissions callback. - * @gasket_dev: Gasket device structure. - */ -gasket_ioctl_permissions_cb_t -gasket_get_ioctl_permissions_cb(struct gasket_dev *gasket_dev); - -/** - * Lookup a name by number in a num_name table. - * @num: Number to lookup. - * @table: Array of num_name structures, the table for the lookup. - * - */ -const char *gasket_num_name_lookup(uint num, - const struct gasket_num_name *table); - -/* Handy inlines */ -static inline ulong gasket_dev_read_64(struct gasket_dev *gasket_dev, int bar, - ulong location) -{ - return readq_relaxed(&gasket_dev->bar_data[bar].virt_base[location]); -} - -static inline void gasket_dev_write_64(struct gasket_dev *dev, u64 value, - int bar, ulong location) -{ - writeq_relaxed(value, &dev->bar_data[bar].virt_base[location]); -} - -static inline void gasket_dev_write_32(struct gasket_dev *dev, u32 value, - int bar, ulong location) -{ - writel_relaxed(value, &dev->bar_data[bar].virt_base[location]); -} - -static inline u32 gasket_dev_read_32(struct gasket_dev *dev, int bar, - ulong location) -{ - return readl_relaxed(&dev->bar_data[bar].virt_base[location]); -} - -static inline void gasket_read_modify_write_64(struct gasket_dev *dev, int bar, - ulong location, u64 value, - u64 mask_width, u64 mask_shift) -{ - u64 mask, tmp; - - tmp = gasket_dev_read_64(dev, bar, location); - mask = ((1ULL << mask_width) - 1) << mask_shift; - tmp = (tmp & ~mask) | (value << mask_shift); - gasket_dev_write_64(dev, tmp, bar, location); -} - -static inline void gasket_read_modify_write_32(struct gasket_dev *dev, int bar, - ulong location, u32 value, - u32 mask_width, u32 mask_shift) -{ - u32 mask, tmp; - - tmp = gasket_dev_read_32(dev, bar, location); - mask = ((1 << mask_width) - 1) << mask_shift; - tmp = (tmp & ~mask) | (value << mask_shift); - gasket_dev_write_32(dev, tmp, bar, location); -} - -/* Get the Gasket driver structure for a given device. */ -const struct gasket_driver_desc *gasket_get_driver_desc(struct gasket_dev *dev); - -/* Get the device structure for a given device. */ -struct device *gasket_get_device(struct gasket_dev *dev); - -/* Helper function, Asynchronous waits on a given set of bits. */ -int gasket_wait_with_reschedule(struct gasket_dev *gasket_dev, int bar, - u64 offset, u64 mask, u64 val, - uint max_retries, u64 delay_ms); - -#endif /* __GASKET_CORE_H__ */ diff --git a/drivers/staging/gasket/gasket_interrupt.c b/drivers/staging/gasket/gasket_interrupt.c deleted file mode 100644 index 864342acfd86e8917304842a79f8c094dd687a9e..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_interrupt.c +++ /dev/null @@ -1,515 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2018 Google, Inc. */ - -#include "gasket_interrupt.h" - -#include "gasket_constants.h" -#include "gasket_core.h" -#include "gasket_sysfs.h" -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/printk.h> -#ifdef GASKET_KERNEL_TRACE_SUPPORT -#define CREATE_TRACE_POINTS -#include <trace/events/gasket_interrupt.h> -#else -#define trace_gasket_interrupt_event(x, ...) -#endif -/* Retry attempts if the requested number of interrupts aren't available. */ -#define MSIX_RETRY_COUNT 3 - -/* Instance interrupt management data. */ -struct gasket_interrupt_data { - /* The name associated with this interrupt data. */ - const char *name; - - /* Interrupt type. See gasket_interrupt_type in gasket_core.h */ - int type; - - /* The PCI device [if any] associated with the owning device. */ - struct pci_dev *pci_dev; - - /* Set to 1 if MSI-X has successfully been configred, 0 otherwise. */ - int msix_configured; - - /* The number of interrupts requested by the owning device. */ - int num_interrupts; - - /* A pointer to the interrupt descriptor struct for this device. */ - const struct gasket_interrupt_desc *interrupts; - - /* The index of the bar into which interrupts should be mapped. */ - int interrupt_bar_index; - - /* The width of a single interrupt in a packed interrupt register. */ - int pack_width; - - /* - * Design-wise, these elements should be bundled together, but - * pci_enable_msix's interface requires that they be managed - * individually (requires array of struct msix_entry). - */ - - /* The number of successfully configured interrupts. */ - int num_configured; - - /* The MSI-X data for each requested/configured interrupt. */ - struct msix_entry *msix_entries; - - /* The eventfd "callback" data for each interrupt. */ - struct eventfd_ctx **eventfd_ctxs; - - /* The number of times each interrupt has been called. */ - ulong *interrupt_counts; - - /* Linux IRQ number. */ - int irq; -}; - -/* Structures to display interrupt counts in sysfs. */ -enum interrupt_sysfs_attribute_type { - ATTR_INTERRUPT_COUNTS, -}; - -/* Set up device registers for interrupt handling. */ -static void gasket_interrupt_setup(struct gasket_dev *gasket_dev) -{ - int i; - int pack_shift; - ulong mask; - ulong value; - struct gasket_interrupt_data *interrupt_data = - gasket_dev->interrupt_data; - - if (!interrupt_data) { - dev_dbg(gasket_dev->dev, "Interrupt data is not initialized\n"); - return; - } - - dev_dbg(gasket_dev->dev, "Running interrupt setup\n"); - - /* Setup the MSIX table. */ - - for (i = 0; i < interrupt_data->num_interrupts; i++) { - /* - * If the interrupt is not packed, we can write the index into - * the register directly. If not, we need to deal with a read- - * modify-write and shift based on the packing index. - */ - dev_dbg(gasket_dev->dev, - "Setting up interrupt index %d with index 0x%llx and packing %d\n", - interrupt_data->interrupts[i].index, - interrupt_data->interrupts[i].reg, - interrupt_data->interrupts[i].packing); - if (interrupt_data->interrupts[i].packing == UNPACKED) { - value = interrupt_data->interrupts[i].index; - } else { - switch (interrupt_data->interrupts[i].packing) { - case PACK_0: - pack_shift = 0; - break; - case PACK_1: - pack_shift = interrupt_data->pack_width; - break; - case PACK_2: - pack_shift = 2 * interrupt_data->pack_width; - break; - case PACK_3: - pack_shift = 3 * interrupt_data->pack_width; - break; - default: - dev_dbg(gasket_dev->dev, - "Found interrupt description with unknown enum %d\n", - interrupt_data->interrupts[i].packing); - return; - } - - mask = ~(0xFFFF << pack_shift); - value = gasket_dev_read_64(gasket_dev, - interrupt_data->interrupt_bar_index, - interrupt_data->interrupts[i].reg); - value &= mask; - value |= interrupt_data->interrupts[i].index - << pack_shift; - } - gasket_dev_write_64(gasket_dev, value, - interrupt_data->interrupt_bar_index, - interrupt_data->interrupts[i].reg); - } -} - -static void -gasket_handle_interrupt(struct gasket_interrupt_data *interrupt_data, - int interrupt_index) -{ - struct eventfd_ctx *ctx; - - trace_gasket_interrupt_event(interrupt_data->name, interrupt_index); - ctx = interrupt_data->eventfd_ctxs[interrupt_index]; - if (ctx) - eventfd_signal(ctx, 1); - - ++(interrupt_data->interrupt_counts[interrupt_index]); -} - -static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id) -{ - struct gasket_interrupt_data *interrupt_data = dev_id; - int interrupt = -1; - int i; - - /* If this linear lookup is a problem, we can maintain a map/hash. */ - for (i = 0; i < interrupt_data->num_interrupts; i++) { - if (interrupt_data->msix_entries[i].vector == irq) { - interrupt = interrupt_data->msix_entries[i].entry; - break; - } - } - if (interrupt == -1) { - pr_err("Received unknown irq %d\n", irq); - return IRQ_HANDLED; - } - gasket_handle_interrupt(interrupt_data, interrupt); - return IRQ_HANDLED; -} - -static int -gasket_interrupt_msix_init(struct gasket_interrupt_data *interrupt_data) -{ - int ret = 1; - int i; - - interrupt_data->msix_entries = - kcalloc(interrupt_data->num_interrupts, - sizeof(*interrupt_data->msix_entries), GFP_KERNEL); - if (!interrupt_data->msix_entries) - return -ENOMEM; - - for (i = 0; i < interrupt_data->num_interrupts; i++) { - interrupt_data->msix_entries[i].entry = i; - interrupt_data->msix_entries[i].vector = 0; - interrupt_data->eventfd_ctxs[i] = NULL; - } - - /* Retry MSIX_RETRY_COUNT times if not enough IRQs are available. */ - for (i = 0; i < MSIX_RETRY_COUNT && ret > 0; i++) - ret = pci_enable_msix_exact(interrupt_data->pci_dev, - interrupt_data->msix_entries, - interrupt_data->num_interrupts); - - if (ret) - return ret > 0 ? -EBUSY : ret; - interrupt_data->msix_configured = 1; - - for (i = 0; i < interrupt_data->num_interrupts; i++) { - ret = request_irq(interrupt_data->msix_entries[i].vector, - gasket_msix_interrupt_handler, 0, - interrupt_data->name, interrupt_data); - - if (ret) { - dev_err(&interrupt_data->pci_dev->dev, - "Cannot get IRQ for interrupt %d, vector %d; " - "%d\n", - i, interrupt_data->msix_entries[i].vector, ret); - return ret; - } - - interrupt_data->num_configured++; - } - - return 0; -} - -/* - * On QCM DragonBoard, we exit gasket_interrupt_msix_init() and kernel interrupt - * setup code with MSIX vectors masked. This is wrong because nothing else in - * the driver will normally touch the MSIX vectors. - * - * As a temporary hack, force unmasking there. - * - * TODO: Figure out why QCM kernel doesn't unmask the MSIX vectors, after - * gasket_interrupt_msix_init(), and remove this code. - */ -static void force_msix_interrupt_unmasking(struct gasket_dev *gasket_dev) -{ - int i; -#define MSIX_VECTOR_SIZE 16 -#define MSIX_MASK_BIT_OFFSET 12 -#define APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE 0x46800 - for (i = 0; i < gasket_dev->interrupt_data->num_configured; i++) { - /* Check if the MSIX vector is unmasked */ - ulong location = APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE + - MSIX_MASK_BIT_OFFSET + i * MSIX_VECTOR_SIZE; - u32 mask = - gasket_dev_read_32(gasket_dev, - gasket_dev->interrupt_data->interrupt_bar_index, - location); - if (!(mask & 1)) - continue; - /* Unmask the msix vector (clear 32 bits) */ - gasket_dev_write_32(gasket_dev, 0, - gasket_dev->interrupt_data->interrupt_bar_index, - location); - } -#undef MSIX_VECTOR_SIZE -#undef MSIX_MASK_BIT_OFFSET -#undef APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE -} - -static ssize_t interrupt_sysfs_show(struct device *device, - struct device_attribute *attr, char *buf) -{ - int i, ret; - ssize_t written = 0, total_written = 0; - struct gasket_interrupt_data *interrupt_data; - struct gasket_dev *gasket_dev; - struct gasket_sysfs_attribute *gasket_attr; - enum interrupt_sysfs_attribute_type sysfs_type; - - gasket_dev = gasket_sysfs_get_device_data(device); - if (!gasket_dev) { - dev_dbg(device, "No sysfs mapping found for device\n"); - return 0; - } - - gasket_attr = gasket_sysfs_get_attr(device, attr); - if (!gasket_attr) { - dev_dbg(device, "No sysfs attr data found for device\n"); - gasket_sysfs_put_device_data(device, gasket_dev); - return 0; - } - - sysfs_type = (enum interrupt_sysfs_attribute_type) - gasket_attr->data.attr_type; - interrupt_data = gasket_dev->interrupt_data; - switch (sysfs_type) { - case ATTR_INTERRUPT_COUNTS: - for (i = 0; i < interrupt_data->num_interrupts; ++i) { - written = - scnprintf(buf, PAGE_SIZE - total_written, - "0x%02x: %ld\n", i, - interrupt_data->interrupt_counts[i]); - total_written += written; - buf += written; - } - ret = total_written; - break; - default: - dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n", - attr->attr.name); - ret = 0; - break; - } - - gasket_sysfs_put_attr(device, gasket_attr); - gasket_sysfs_put_device_data(device, gasket_dev); - return ret; -} - -static struct gasket_sysfs_attribute interrupt_sysfs_attrs[] = { - GASKET_SYSFS_RO(interrupt_counts, interrupt_sysfs_show, - ATTR_INTERRUPT_COUNTS), - GASKET_END_OF_ATTR_ARRAY, -}; - -int gasket_interrupt_init(struct gasket_dev *gasket_dev) -{ - int ret; - struct gasket_interrupt_data *interrupt_data; - const struct gasket_driver_desc *driver_desc = - gasket_get_driver_desc(gasket_dev); - - interrupt_data = kzalloc(sizeof(*interrupt_data), GFP_KERNEL); - if (!interrupt_data) - return -ENOMEM; - gasket_dev->interrupt_data = interrupt_data; - interrupt_data->name = driver_desc->name; - interrupt_data->type = driver_desc->interrupt_type; - interrupt_data->pci_dev = gasket_dev->pci_dev; - interrupt_data->num_interrupts = driver_desc->num_interrupts; - interrupt_data->interrupts = driver_desc->interrupts; - interrupt_data->interrupt_bar_index = driver_desc->interrupt_bar_index; - interrupt_data->pack_width = driver_desc->interrupt_pack_width; - interrupt_data->num_configured = 0; - - interrupt_data->eventfd_ctxs = - kcalloc(driver_desc->num_interrupts, - sizeof(*interrupt_data->eventfd_ctxs), GFP_KERNEL); - if (!interrupt_data->eventfd_ctxs) { - kfree(interrupt_data); - return -ENOMEM; - } - - interrupt_data->interrupt_counts = - kcalloc(driver_desc->num_interrupts, - sizeof(*interrupt_data->interrupt_counts), GFP_KERNEL); - if (!interrupt_data->interrupt_counts) { - kfree(interrupt_data->eventfd_ctxs); - kfree(interrupt_data); - return -ENOMEM; - } - - switch (interrupt_data->type) { - case PCI_MSIX: - ret = gasket_interrupt_msix_init(interrupt_data); - if (ret) - break; - force_msix_interrupt_unmasking(gasket_dev); - break; - - default: - ret = -EINVAL; - } - - if (ret) { - /* Failing to setup interrupts will cause the device to report - * GASKET_STATUS_LAMED. But it is not fatal. - */ - dev_warn(gasket_dev->dev, - "Couldn't initialize interrupts: %d\n", ret); - return 0; - } - - gasket_interrupt_setup(gasket_dev); - gasket_sysfs_create_entries(gasket_dev->dev_info.device, - interrupt_sysfs_attrs); - - return 0; -} - -static void -gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data) -{ - int i; - - for (i = 0; i < interrupt_data->num_configured; i++) - free_irq(interrupt_data->msix_entries[i].vector, - interrupt_data); - interrupt_data->num_configured = 0; - - if (interrupt_data->msix_configured) - pci_disable_msix(interrupt_data->pci_dev); - interrupt_data->msix_configured = 0; - kfree(interrupt_data->msix_entries); -} - -int gasket_interrupt_reinit(struct gasket_dev *gasket_dev) -{ - int ret; - - if (!gasket_dev->interrupt_data) { - dev_dbg(gasket_dev->dev, - "Attempted to reinit uninitialized interrupt data\n"); - return -EINVAL; - } - - switch (gasket_dev->interrupt_data->type) { - case PCI_MSIX: - gasket_interrupt_msix_cleanup(gasket_dev->interrupt_data); - ret = gasket_interrupt_msix_init(gasket_dev->interrupt_data); - if (ret) - break; - force_msix_interrupt_unmasking(gasket_dev); - break; - - default: - ret = -EINVAL; - } - - if (ret) { - /* Failing to setup interrupts will cause the device - * to report GASKET_STATUS_LAMED, but is not fatal. - */ - dev_warn(gasket_dev->dev, "Couldn't reinit interrupts: %d\n", - ret); - return 0; - } - - gasket_interrupt_setup(gasket_dev); - - return 0; -} - -/* See gasket_interrupt.h for description. */ -int gasket_interrupt_reset_counts(struct gasket_dev *gasket_dev) -{ - dev_dbg(gasket_dev->dev, "Clearing interrupt counts\n"); - memset(gasket_dev->interrupt_data->interrupt_counts, 0, - gasket_dev->interrupt_data->num_interrupts * - sizeof(*gasket_dev->interrupt_data->interrupt_counts)); - return 0; -} - -/* See gasket_interrupt.h for description. */ -void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev) -{ - struct gasket_interrupt_data *interrupt_data = - gasket_dev->interrupt_data; - /* - * It is possible to get an error code from gasket_interrupt_init - * before interrupt_data has been allocated, so check it. - */ - if (!interrupt_data) - return; - - switch (interrupt_data->type) { - case PCI_MSIX: - gasket_interrupt_msix_cleanup(interrupt_data); - break; - - default: - break; - } - - kfree(interrupt_data->interrupt_counts); - kfree(interrupt_data->eventfd_ctxs); - kfree(interrupt_data); - gasket_dev->interrupt_data = NULL; -} - -int gasket_interrupt_system_status(struct gasket_dev *gasket_dev) -{ - if (!gasket_dev->interrupt_data) { - dev_dbg(gasket_dev->dev, "Interrupt data is null\n"); - return GASKET_STATUS_DEAD; - } - - if (gasket_dev->interrupt_data->num_configured != - gasket_dev->interrupt_data->num_interrupts) { - dev_dbg(gasket_dev->dev, - "Not all interrupts were configured\n"); - return GASKET_STATUS_LAMED; - } - - return GASKET_STATUS_ALIVE; -} - -int gasket_interrupt_set_eventfd(struct gasket_interrupt_data *interrupt_data, - int interrupt, int event_fd) -{ - struct eventfd_ctx *ctx; - - if (interrupt < 0 || interrupt >= interrupt_data->num_interrupts) - return -EINVAL; - - ctx = eventfd_ctx_fdget(event_fd); - - if (IS_ERR(ctx)) - return PTR_ERR(ctx); - - interrupt_data->eventfd_ctxs[interrupt] = ctx; - return 0; -} - -int gasket_interrupt_clear_eventfd(struct gasket_interrupt_data *interrupt_data, - int interrupt) -{ - if (interrupt < 0 || interrupt >= interrupt_data->num_interrupts) - return -EINVAL; - - if (interrupt_data->eventfd_ctxs[interrupt]) { - eventfd_ctx_put(interrupt_data->eventfd_ctxs[interrupt]); - interrupt_data->eventfd_ctxs[interrupt] = NULL; - } - return 0; -} diff --git a/drivers/staging/gasket/gasket_interrupt.h b/drivers/staging/gasket/gasket_interrupt.h deleted file mode 100644 index 85526a1374a1af10ac178e62cdff6fc147d49016..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_interrupt.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Gasket common interrupt module. Defines functions for enabling - * eventfd-triggered interrupts between a Gasket device and a host process. - * - * Copyright (C) 2018 Google, Inc. - */ -#ifndef __GASKET_INTERRUPT_H__ -#define __GASKET_INTERRUPT_H__ - -#include <linux/eventfd.h> -#include <linux/pci.h> - -#include "gasket_core.h" - -/* Note that this currently assumes that device interrupts are a dense set, - * numbered from 0 - (num_interrupts - 1). Should this have to change, these - * APIs will have to be updated. - */ - -/* Opaque type used to hold interrupt subsystem data. */ -struct gasket_interrupt_data; - -/* - * Initialize the interrupt module. - * @gasket_dev: The Gasket device structure for the device to be initted. - */ -int gasket_interrupt_init(struct gasket_dev *gasket_dev); - -/* - * Clean up a device's interrupt structure. - * @gasket_dev: The Gasket information structure for this device. - * - * Cleans up the device's interrupts and deallocates data. - */ -void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev); - -/* - * Clean up and re-initialize the MSI-x subsystem. - * @gasket_dev: The Gasket information structure for this device. - * - * Performs a teardown of the MSI-x subsystem and re-initializes it. Does not - * free the underlying data structures. Returns 0 on success and an error code - * on error. - */ -int gasket_interrupt_reinit(struct gasket_dev *gasket_dev); - -/* - * Reset the counts stored in the interrupt subsystem. - * @gasket_dev: The Gasket information structure for this device. - * - * Sets the counts of all interrupts in the subsystem to 0. - */ -int gasket_interrupt_reset_counts(struct gasket_dev *gasket_dev); - -/* - * Associates an eventfd with a device interrupt. - * @data: Pointer to device interrupt data. - * @interrupt: The device interrupt to configure. - * @event_fd: The eventfd to associate with the interrupt. - * - * Prepares the host to receive notification of device interrupts by associating - * event_fd with interrupt. Upon receipt of a device interrupt, event_fd will be - * signaled, after successful configuration. - * - * Returns 0 on success, a negative error code otherwise. - */ -int gasket_interrupt_set_eventfd(struct gasket_interrupt_data *interrupt_data, - int interrupt, int event_fd); - -/* - * Removes an interrupt-eventfd association. - * @data: Pointer to device interrupt data. - * @interrupt: The device interrupt to de-associate. - * - * Removes any eventfd associated with the specified interrupt, if any. - */ -int gasket_interrupt_clear_eventfd(struct gasket_interrupt_data *interrupt_data, - int interrupt); - -/* - * The below functions exist for backwards compatibility. - * No new uses should be written. - */ -/* - * Get the health of the interrupt subsystem. - * @gasket_dev: The Gasket device struct. - * - * Returns DEAD if not set up, LAMED if initialization failed, and ALIVE - * otherwise. - */ - -int gasket_interrupt_system_status(struct gasket_dev *gasket_dev); - -#endif diff --git a/drivers/staging/gasket/gasket_ioctl.c b/drivers/staging/gasket/gasket_ioctl.c deleted file mode 100644 index aa65f4fbf860a246c723ac0cbe6fca0b6a5b86d2..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_ioctl.c +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2018 Google, Inc. */ -#include "gasket.h" -#include "gasket_ioctl.h" -#include "gasket_constants.h" -#include "gasket_core.h" -#include "gasket_interrupt.h" -#include "gasket_page_table.h" -#include <linux/compiler.h> -#include <linux/device.h> -#include <linux/fs.h> -#include <linux/uaccess.h> - -#ifdef GASKET_KERNEL_TRACE_SUPPORT -#define CREATE_TRACE_POINTS -#include <trace/events/gasket_ioctl.h> -#else -#define trace_gasket_ioctl_entry(x, ...) -#define trace_gasket_ioctl_exit(x) -#define trace_gasket_ioctl_integer_data(x) -#define trace_gasket_ioctl_eventfd_data(x, ...) -#define trace_gasket_ioctl_page_table_data(x, ...) -#define trace_gasket_ioctl_config_coherent_allocator(x, ...) -#endif - -/* Associate an eventfd with an interrupt. */ -static int gasket_set_event_fd(struct gasket_dev *gasket_dev, - struct gasket_interrupt_eventfd __user *argp) -{ - struct gasket_interrupt_eventfd die; - - if (copy_from_user(&die, argp, sizeof(struct gasket_interrupt_eventfd))) - return -EFAULT; - - trace_gasket_ioctl_eventfd_data(die.interrupt, die.event_fd); - - return gasket_interrupt_set_eventfd(gasket_dev->interrupt_data, - die.interrupt, die.event_fd); -} - -/* Read the size of the page table. */ -static int gasket_read_page_table_size(struct gasket_dev *gasket_dev, - struct gasket_page_table_ioctl __user *argp) -{ - int ret = 0; - struct gasket_page_table_ioctl ibuf; - struct gasket_page_table *table; - - if (copy_from_user(&ibuf, argp, sizeof(struct gasket_page_table_ioctl))) - return -EFAULT; - - if (ibuf.page_table_index >= gasket_dev->num_page_tables) - return -EFAULT; - - table = gasket_dev->page_table[ibuf.page_table_index]; - ibuf.size = gasket_page_table_num_entries(table); - - trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, - ibuf.host_address, - ibuf.device_address); - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) - return -EFAULT; - - return ret; -} - -/* Read the size of the simple page table. */ -static int gasket_read_simple_page_table_size(struct gasket_dev *gasket_dev, - struct gasket_page_table_ioctl __user *argp) -{ - int ret = 0; - struct gasket_page_table_ioctl ibuf; - struct gasket_page_table *table; - - if (copy_from_user(&ibuf, argp, sizeof(struct gasket_page_table_ioctl))) - return -EFAULT; - - if (ibuf.page_table_index >= gasket_dev->num_page_tables) - return -EFAULT; - - table = gasket_dev->page_table[ibuf.page_table_index]; - ibuf.size = gasket_page_table_num_simple_entries(table); - - trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, - ibuf.host_address, - ibuf.device_address); - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) - return -EFAULT; - - return ret; -} - -/* Set the boundary between the simple and extended page tables. */ -static int gasket_partition_page_table(struct gasket_dev *gasket_dev, - struct gasket_page_table_ioctl __user *argp) -{ - int ret; - struct gasket_page_table_ioctl ibuf; - uint max_page_table_size; - struct gasket_page_table *table; - - if (copy_from_user(&ibuf, argp, sizeof(struct gasket_page_table_ioctl))) - return -EFAULT; - - trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, - ibuf.host_address, - ibuf.device_address); - - if (ibuf.page_table_index >= gasket_dev->num_page_tables) - return -EFAULT; - table = gasket_dev->page_table[ibuf.page_table_index]; - max_page_table_size = gasket_page_table_max_size(table); - - if (ibuf.size > max_page_table_size) { - dev_dbg(gasket_dev->dev, - "Partition request 0x%llx too large, max is 0x%x\n", - ibuf.size, max_page_table_size); - return -EINVAL; - } - - mutex_lock(&gasket_dev->mutex); - - ret = gasket_page_table_partition(table, ibuf.size); - mutex_unlock(&gasket_dev->mutex); - - return ret; -} - -/* Map a userspace buffer to a device virtual address. */ -static int gasket_map_buffers(struct gasket_dev *gasket_dev, - struct gasket_page_table_ioctl __user *argp) -{ - struct gasket_page_table_ioctl ibuf; - struct gasket_page_table *table; - - if (copy_from_user(&ibuf, argp, sizeof(struct gasket_page_table_ioctl))) - return -EFAULT; - - trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, - ibuf.host_address, - ibuf.device_address); - - if (ibuf.page_table_index >= gasket_dev->num_page_tables) - return -EFAULT; - - table = gasket_dev->page_table[ibuf.page_table_index]; - if (gasket_page_table_are_addrs_bad(table, ibuf.host_address, - ibuf.device_address, ibuf.size)) - return -EINVAL; - - return gasket_page_table_map(table, ibuf.host_address, ibuf.device_address, - ibuf.size / PAGE_SIZE); -} - -/* Unmap a userspace buffer from a device virtual address. */ -static int gasket_unmap_buffers(struct gasket_dev *gasket_dev, - struct gasket_page_table_ioctl __user *argp) -{ - struct gasket_page_table_ioctl ibuf; - struct gasket_page_table *table; - - if (copy_from_user(&ibuf, argp, sizeof(struct gasket_page_table_ioctl))) - return -EFAULT; - - trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, - ibuf.host_address, - ibuf.device_address); - - if (ibuf.page_table_index >= gasket_dev->num_page_tables) - return -EFAULT; - - table = gasket_dev->page_table[ibuf.page_table_index]; - if (gasket_page_table_is_dev_addr_bad(table, ibuf.device_address, ibuf.size)) - return -EINVAL; - - gasket_page_table_unmap(table, ibuf.device_address, ibuf.size / PAGE_SIZE); - - return 0; -} - -/* - * Reserve structures for coherent allocation, and allocate or free the - * corresponding memory. - */ -static int gasket_config_coherent_allocator(struct gasket_dev *gasket_dev, - struct gasket_coherent_alloc_config_ioctl __user *argp) -{ - int ret; - struct gasket_coherent_alloc_config_ioctl ibuf; - - if (copy_from_user(&ibuf, argp, - sizeof(struct gasket_coherent_alloc_config_ioctl))) - return -EFAULT; - - trace_gasket_ioctl_config_coherent_allocator(ibuf.enable, ibuf.size, - ibuf.dma_address); - - if (ibuf.page_table_index >= gasket_dev->num_page_tables) - return -EFAULT; - - if (ibuf.size > PAGE_SIZE * MAX_NUM_COHERENT_PAGES) - return -ENOMEM; - - if (ibuf.enable == 0) { - ret = gasket_free_coherent_memory(gasket_dev, ibuf.size, - ibuf.dma_address, - ibuf.page_table_index); - } else { - ret = gasket_alloc_coherent_memory(gasket_dev, ibuf.size, - &ibuf.dma_address, - ibuf.page_table_index); - } - if (ret) - return ret; - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) - return -EFAULT; - - return 0; -} - -/* Check permissions for Gasket ioctls. */ -static bool gasket_ioctl_check_permissions(struct file *filp, uint cmd) -{ - bool alive; - bool read, write; - struct gasket_dev *gasket_dev = (struct gasket_dev *)filp->private_data; - - alive = (gasket_dev->status == GASKET_STATUS_ALIVE); - if (!alive) - dev_dbg(gasket_dev->dev, "%s alive %d status %d\n", - __func__, alive, gasket_dev->status); - - read = !!(filp->f_mode & FMODE_READ); - write = !!(filp->f_mode & FMODE_WRITE); - - switch (cmd) { - case GASKET_IOCTL_RESET: - case GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS: - return write; - - case GASKET_IOCTL_PAGE_TABLE_SIZE: - case GASKET_IOCTL_SIMPLE_PAGE_TABLE_SIZE: - case GASKET_IOCTL_NUMBER_PAGE_TABLES: - return read; - - case GASKET_IOCTL_PARTITION_PAGE_TABLE: - case GASKET_IOCTL_CONFIG_COHERENT_ALLOCATOR: - return alive && write; - - case GASKET_IOCTL_MAP_BUFFER: - case GASKET_IOCTL_UNMAP_BUFFER: - return alive && write; - - case GASKET_IOCTL_CLEAR_EVENTFD: - case GASKET_IOCTL_SET_EVENTFD: - return alive && write; - } - - return false; /* unknown permissions */ -} - -/* - * standard ioctl dispatch function. - * @filp: File structure pointer describing this node usage session. - * @cmd: ioctl number to handle. - * @argp: ioctl-specific data pointer. - * - * Standard ioctl dispatcher; forwards operations to individual handlers. - */ -long gasket_handle_ioctl(struct file *filp, uint cmd, void __user *argp) -{ - struct gasket_dev *gasket_dev; - unsigned long arg = (unsigned long)argp; - gasket_ioctl_permissions_cb_t ioctl_permissions_cb; - int retval; - - gasket_dev = (struct gasket_dev *)filp->private_data; - trace_gasket_ioctl_entry(gasket_dev->dev_info.name, cmd); - - ioctl_permissions_cb = gasket_get_ioctl_permissions_cb(gasket_dev); - if (ioctl_permissions_cb) { - retval = ioctl_permissions_cb(filp, cmd, argp); - if (retval < 0) { - trace_gasket_ioctl_exit(retval); - return retval; - } else if (retval == 0) { - trace_gasket_ioctl_exit(-EPERM); - return -EPERM; - } - } else if (!gasket_ioctl_check_permissions(filp, cmd)) { - trace_gasket_ioctl_exit(-EPERM); - dev_dbg(gasket_dev->dev, "ioctl cmd=%x noperm\n", cmd); - return -EPERM; - } - - /* Tracing happens in this switch statement for all ioctls with - * an integer argrument, but ioctls with a struct argument - * that needs copying and decoding, that tracing is done within - * the handler call. - */ - switch (cmd) { - case GASKET_IOCTL_RESET: - retval = gasket_reset(gasket_dev); - break; - case GASKET_IOCTL_SET_EVENTFD: - retval = gasket_set_event_fd(gasket_dev, argp); - break; - case GASKET_IOCTL_CLEAR_EVENTFD: - trace_gasket_ioctl_integer_data(arg); - retval = - gasket_interrupt_clear_eventfd(gasket_dev->interrupt_data, - (int)arg); - break; - case GASKET_IOCTL_PARTITION_PAGE_TABLE: - trace_gasket_ioctl_integer_data(arg); - retval = gasket_partition_page_table(gasket_dev, argp); - break; - case GASKET_IOCTL_NUMBER_PAGE_TABLES: - trace_gasket_ioctl_integer_data(gasket_dev->num_page_tables); - if (copy_to_user(argp, &gasket_dev->num_page_tables, - sizeof(uint64_t))) - retval = -EFAULT; - else - retval = 0; - break; - case GASKET_IOCTL_PAGE_TABLE_SIZE: - retval = gasket_read_page_table_size(gasket_dev, argp); - break; - case GASKET_IOCTL_SIMPLE_PAGE_TABLE_SIZE: - retval = gasket_read_simple_page_table_size(gasket_dev, argp); - break; - case GASKET_IOCTL_MAP_BUFFER: - retval = gasket_map_buffers(gasket_dev, argp); - break; - case GASKET_IOCTL_CONFIG_COHERENT_ALLOCATOR: - retval = gasket_config_coherent_allocator(gasket_dev, argp); - break; - case GASKET_IOCTL_UNMAP_BUFFER: - retval = gasket_unmap_buffers(gasket_dev, argp); - break; - case GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS: - /* Clear interrupt counts doesn't take an arg, so use 0. */ - trace_gasket_ioctl_integer_data(0); - retval = gasket_interrupt_reset_counts(gasket_dev); - break; - default: - /* If we don't understand the ioctl, the best we can do is trace - * the arg. - */ - trace_gasket_ioctl_integer_data(arg); - dev_dbg(gasket_dev->dev, - "Unknown ioctl cmd=0x%x not caught by gasket_is_supported_ioctl\n", - cmd); - retval = -EINVAL; - break; - } - - trace_gasket_ioctl_exit(retval); - return retval; -} - -/* - * Determines if an ioctl is part of the standard Gasket framework. - * @cmd: The ioctl number to handle. - * - * Returns 1 if the ioctl is supported and 0 otherwise. - */ -long gasket_is_supported_ioctl(uint cmd) -{ - switch (cmd) { - case GASKET_IOCTL_RESET: - case GASKET_IOCTL_SET_EVENTFD: - case GASKET_IOCTL_CLEAR_EVENTFD: - case GASKET_IOCTL_PARTITION_PAGE_TABLE: - case GASKET_IOCTL_NUMBER_PAGE_TABLES: - case GASKET_IOCTL_PAGE_TABLE_SIZE: - case GASKET_IOCTL_SIMPLE_PAGE_TABLE_SIZE: - case GASKET_IOCTL_MAP_BUFFER: - case GASKET_IOCTL_UNMAP_BUFFER: - case GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS: - case GASKET_IOCTL_CONFIG_COHERENT_ALLOCATOR: - return 1; - default: - return 0; - } -} diff --git a/drivers/staging/gasket/gasket_ioctl.h b/drivers/staging/gasket/gasket_ioctl.h deleted file mode 100644 index 51f468c77f04115a6e7812ce95dd07fa09ce888a..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_ioctl.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2018 Google, Inc. */ -#ifndef __GASKET_IOCTL_H__ -#define __GASKET_IOCTL_H__ - -#include "gasket_core.h" - -#include <linux/compiler.h> - -/* - * Handle Gasket common ioctls. - * @filp: Pointer to the ioctl's file. - * @cmd: Ioctl command. - * @arg: Ioctl argument pointer. - * - * Returns 0 on success and nonzero on failure. - */ -long gasket_handle_ioctl(struct file *filp, uint cmd, void __user *argp); - -/* - * Determines if an ioctl is part of the standard Gasket framework. - * @cmd: The ioctl number to handle. - * - * Returns 1 if the ioctl is supported and 0 otherwise. - */ -long gasket_is_supported_ioctl(uint cmd); - -#endif diff --git a/drivers/staging/gasket/gasket_page_table.c b/drivers/staging/gasket/gasket_page_table.c deleted file mode 100644 index 6f6273c83822c7cc23667344536f41f110079908..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_page_table.c +++ /dev/null @@ -1,1359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Implementation of Gasket page table support. - * - * Copyright (C) 2018 Google, Inc. - */ - -/* - * Implementation of Gasket page table support. - * - * This file assumes 4kB pages throughout; can be factored out when necessary. - * - * There is a configurable number of page table entries, as well as a - * configurable bit index for the extended address flag. Both of these are - * specified in gasket_page_table_init through the page_table_config parameter. - * - * The following example assumes: - * page_table_config->total_entries = 8192 - * page_table_config->extended_bit = 63 - * - * Address format: - * Simple addresses - those whose containing pages are directly placed in the - * device's address translation registers - are laid out as: - * [ 63 - 25: 0 | 24 - 12: page index | 11 - 0: page offset ] - * page index: The index of the containing page in the device's address - * translation registers. - * page offset: The index of the address into the containing page. - * - * Extended address - those whose containing pages are contained in a second- - * level page table whose address is present in the device's address translation - * registers - are laid out as: - * [ 63: flag | 62 - 34: 0 | 33 - 21: dev/level 0 index | - * 20 - 12: host/level 1 index | 11 - 0: page offset ] - * flag: Marker indicating that this is an extended address. Always 1. - * dev index: The index of the first-level page in the device's extended - * address translation registers. - * host index: The index of the containing page in the [host-resident] second- - * level page table. - * page offset: The index of the address into the containing [second-level] - * page. - */ -#include "gasket_page_table.h" - -#include <linux/device.h> -#include <linux/file.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pagemap.h> -#include <linux/vmalloc.h> - -#include "gasket_constants.h" -#include "gasket_core.h" - -/* Constants & utility macros */ -/* The number of pages that can be mapped into each second-level page table. */ -#define GASKET_PAGES_PER_SUBTABLE 512 - -/* The starting position of the page index in a simple virtual address. */ -#define GASKET_SIMPLE_PAGE_SHIFT 12 - -/* Flag indicating that a [device] slot is valid for use. */ -#define GASKET_VALID_SLOT_FLAG 1 - -/* - * The starting position of the level 0 page index (i.e., the entry in the - * device's extended address registers) in an extended address. - * Also can be thought of as (log2(PAGE_SIZE) + log2(PAGES_PER_SUBTABLE)), - * or (12 + 9). - */ -#define GASKET_EXTENDED_LVL0_SHIFT 21 - -/* - * Number of first level pages that Gasket chips support. Equivalent to - * log2(NUM_LVL0_PAGE_TABLES) - * - * At a maximum, allowing for a 34 bits address space (or 16GB) - * = GASKET_EXTENDED_LVL0_WIDTH + (log2(PAGE_SIZE) + log2(PAGES_PER_SUBTABLE) - * or, = 13 + 9 + 12 - */ -#define GASKET_EXTENDED_LVL0_WIDTH 13 - -/* - * The starting position of the level 1 page index (i.e., the entry in the - * host second-level/sub- table) in an extended address. - */ -#define GASKET_EXTENDED_LVL1_SHIFT 12 - -/* Type declarations */ -/* Valid states for a struct gasket_page_table_entry. */ -enum pte_status { - PTE_FREE, - PTE_INUSE, -}; - -/* - * Mapping metadata for a single page. - * - * In this file, host-side page table entries are referred to as that (or PTEs). - * Where device vs. host entries are differentiated, device-side or -visible - * entries are called "slots". A slot may be either an entry in the device's - * address translation table registers or an entry in a second-level page - * table ("subtable"). - * - * The full data in this structure is visible on the host [of course]. Only - * the address contained in dma_addr is communicated to the device; that points - * to the actual page mapped and described by this structure. - */ -struct gasket_page_table_entry { - /* The status of this entry/slot: free or in use. */ - enum pte_status status; - - /* - * Index for alignment into host vaddrs. - * When a user specifies a host address for a mapping, that address may - * not be page-aligned. Offset is the index into the containing page of - * the host address (i.e., host_vaddr & (PAGE_SIZE - 1)). - * This is necessary for translating between user-specified addresses - * and page-aligned addresses. - */ - int offset; - - /* Address of the page in DMA space. */ - dma_addr_t dma_addr; - - /* Linux page descriptor for the page described by this structure. */ - struct page *page; - - /* - * If this is an extended and first-level entry, sublevel points - * to the second-level entries underneath this entry. - */ - struct gasket_page_table_entry *sublevel; -}; - -/* - * Maintains virtual to physical address mapping for a coherent page that is - * allocated by this module for a given device. - * Note that coherent pages mappings virt mapping cannot be tracked by the - * Linux kernel, and coherent pages don't have a struct page associated, - * hence Linux kernel cannot perform a get_user_page_xx() on a phys address - * that was allocated coherent. - * This structure trivially implements this mechanism. - */ -struct gasket_coherent_page_entry { - /* Phys address, dma'able by the owner device */ - dma_addr_t paddr; - - /* Kernel virtual address */ - u64 user_virt; - - /* User virtual address that was mapped by the mmap kernel subsystem */ - u64 kernel_virt; - - /* - * Whether this page has been mapped into a user land process virtual - * space - */ - u32 in_use; -}; - -/* - * [Host-side] page table descriptor. - * - * This structure tracks the metadata necessary to manage both simple and - * extended page tables. - */ -struct gasket_page_table { - /* The config used to create this page table. */ - struct gasket_page_table_config config; - - /* The number of simple (single-level) entries in the page table. */ - uint num_simple_entries; - - /* The number of extended (two-level) entries in the page table. */ - uint num_extended_entries; - - /* Array of [host-side] page table entries. */ - struct gasket_page_table_entry *entries; - - /* Number of actively mapped kernel pages in this table. */ - uint num_active_pages; - - /* Device register: base of/first slot in the page table. */ - u64 __iomem *base_slot; - - /* Device register: holds the offset indicating the start of the - * extended address region of the device's address translation table. - */ - u64 __iomem *extended_offset_reg; - - /* Device structure for the underlying device. Only used for logging. */ - struct device *device; - - /* PCI system descriptor for the underlying device. */ - struct pci_dev *pci_dev; - - /* Location of the extended address bit for this Gasket device. */ - u64 extended_flag; - - /* Mutex to protect page table internals. */ - struct mutex mutex; - - /* Number of coherent pages accessible thru by this page table */ - int num_coherent_pages; - - /* - * List of coherent memory (physical) allocated for a device. - * - * This structure also remembers the user virtual mapping, this is - * hacky, but we need to do this because the kernel doesn't keep track - * of the user coherent pages (pfn pages), and virt to coherent page - * mapping. - * TODO: use find_vma() APIs to convert host address to vm_area, to - * dma_addr_t instead of storing user virtu address in - * gasket_coherent_page_entry - * - * Note that the user virtual mapping is created by the driver, in - * gasket_mmap function, so user_virt belongs in the driver anyhow. - */ - struct gasket_coherent_page_entry *coherent_pages; -}; - -/* See gasket_page_table.h for description. */ -int gasket_page_table_init(struct gasket_page_table **ppg_tbl, - const struct gasket_bar_data *bar_data, - const struct gasket_page_table_config *page_table_config, - struct device *device, struct pci_dev *pci_dev) -{ - ulong bytes; - struct gasket_page_table *pg_tbl; - ulong total_entries = page_table_config->total_entries; - - /* - * TODO: Verify config->total_entries against value read from the - * hardware register that contains the page table size. - */ - if (total_entries == ULONG_MAX) { - dev_dbg(device, - "Error reading page table size. Initializing page table with size 0\n"); - total_entries = 0; - } - - dev_dbg(device, - "Attempting to initialize page table of size 0x%lx\n", - total_entries); - - dev_dbg(device, - "Table has base reg 0x%x, extended offset reg 0x%x\n", - page_table_config->base_reg, - page_table_config->extended_reg); - - *ppg_tbl = kzalloc(sizeof(**ppg_tbl), GFP_KERNEL); - if (!*ppg_tbl) { - dev_dbg(device, "No memory for page table\n"); - return -ENOMEM; - } - - pg_tbl = *ppg_tbl; - bytes = total_entries * sizeof(struct gasket_page_table_entry); - if (bytes != 0) { - pg_tbl->entries = vzalloc(bytes); - if (!pg_tbl->entries) { - dev_dbg(device, - "No memory for address translation metadata\n"); - kfree(pg_tbl); - *ppg_tbl = NULL; - return -ENOMEM; - } - } - - mutex_init(&pg_tbl->mutex); - memcpy(&pg_tbl->config, page_table_config, sizeof(*page_table_config)); - if (pg_tbl->config.mode == GASKET_PAGE_TABLE_MODE_NORMAL || - pg_tbl->config.mode == GASKET_PAGE_TABLE_MODE_SIMPLE) { - pg_tbl->num_simple_entries = total_entries; - pg_tbl->num_extended_entries = 0; - pg_tbl->extended_flag = 1ull << page_table_config->extended_bit; - } else { - pg_tbl->num_simple_entries = 0; - pg_tbl->num_extended_entries = total_entries; - pg_tbl->extended_flag = 0; - } - pg_tbl->num_active_pages = 0; - pg_tbl->base_slot = - (u64 __iomem *)&bar_data->virt_base[page_table_config->base_reg]; - pg_tbl->extended_offset_reg = - (u64 __iomem *)&bar_data->virt_base[page_table_config->extended_reg]; - pg_tbl->device = get_device(device); - pg_tbl->pci_dev = pci_dev; - - dev_dbg(device, "Page table initialized successfully\n"); - - return 0; -} - -/* - * Check if a range of PTEs is free. - * The page table mutex must be held by the caller. - */ -static bool gasket_is_pte_range_free(struct gasket_page_table_entry *ptes, - uint num_entries) -{ - int i; - - for (i = 0; i < num_entries; i++) { - if (ptes[i].status != PTE_FREE) - return false; - } - - return true; -} - -/* - * Free a second level page [sub]table. - * The page table mutex must be held before this call. - */ -static void gasket_free_extended_subtable(struct gasket_page_table *pg_tbl, - struct gasket_page_table_entry *pte, - u64 __iomem *slot) -{ - /* Release the page table from the driver */ - pte->status = PTE_FREE; - - /* Release the page table from the device */ - writeq(0, slot); - - if (pte->dma_addr) - dma_unmap_page(pg_tbl->device, pte->dma_addr, PAGE_SIZE, - DMA_TO_DEVICE); - - vfree(pte->sublevel); - - if (pte->page) - free_page((ulong)page_address(pte->page)); - - memset(pte, 0, sizeof(struct gasket_page_table_entry)); -} - -/* - * Actually perform collection. - * The page table mutex must be held by the caller. - */ -static void -gasket_page_table_garbage_collect_nolock(struct gasket_page_table *pg_tbl) -{ - struct gasket_page_table_entry *pte; - u64 __iomem *slot; - - /* XXX FIX ME XXX -- more efficient to keep a usage count */ - /* rather than scanning the second level page tables */ - - for (pte = pg_tbl->entries + pg_tbl->num_simple_entries, - slot = pg_tbl->base_slot + pg_tbl->num_simple_entries; - pte < pg_tbl->entries + pg_tbl->config.total_entries; - pte++, slot++) { - if (pte->status == PTE_INUSE) { - if (gasket_is_pte_range_free(pte->sublevel, - GASKET_PAGES_PER_SUBTABLE)) - gasket_free_extended_subtable(pg_tbl, pte, - slot); - } - } -} - -/* See gasket_page_table.h for description. */ -void gasket_page_table_garbage_collect(struct gasket_page_table *pg_tbl) -{ - mutex_lock(&pg_tbl->mutex); - gasket_page_table_garbage_collect_nolock(pg_tbl); - mutex_unlock(&pg_tbl->mutex); -} - -/* See gasket_page_table.h for description. */ -void gasket_page_table_cleanup(struct gasket_page_table *pg_tbl) -{ - /* Deallocate free second-level tables. */ - gasket_page_table_garbage_collect(pg_tbl); - - /* TODO: Check that all PTEs have been freed? */ - - vfree(pg_tbl->entries); - pg_tbl->entries = NULL; - - put_device(pg_tbl->device); - kfree(pg_tbl); -} - -/* See gasket_page_table.h for description. */ -int gasket_page_table_partition(struct gasket_page_table *pg_tbl, - uint num_simple_entries) -{ - int i, start; - - mutex_lock(&pg_tbl->mutex); - if (num_simple_entries > pg_tbl->config.total_entries) { - mutex_unlock(&pg_tbl->mutex); - return -EINVAL; - } - - gasket_page_table_garbage_collect_nolock(pg_tbl); - - start = min(pg_tbl->num_simple_entries, num_simple_entries); - - for (i = start; i < pg_tbl->config.total_entries; i++) { - if (pg_tbl->entries[i].status != PTE_FREE) { - dev_err(pg_tbl->device, "entry %d is not free\n", i); - mutex_unlock(&pg_tbl->mutex); - return -EBUSY; - } - } - - pg_tbl->num_simple_entries = num_simple_entries; - pg_tbl->num_extended_entries = - pg_tbl->config.total_entries - num_simple_entries; - writeq(num_simple_entries, pg_tbl->extended_offset_reg); - - mutex_unlock(&pg_tbl->mutex); - return 0; -} -EXPORT_SYMBOL(gasket_page_table_partition); - -/* - * Return whether a host buffer was mapped as coherent memory. - * - * A Gasket page_table currently support one contiguous dma range, mapped to one - * contiguous virtual memory range. Check if the host_addr is within that range. - */ -static int is_coherent(struct gasket_page_table *pg_tbl, ulong host_addr) -{ - u64 min, max; - - /* whether the host address is within user virt range */ - if (!pg_tbl->coherent_pages) - return 0; - - min = (u64)pg_tbl->coherent_pages[0].user_virt; - max = min + PAGE_SIZE * pg_tbl->num_coherent_pages; - - return min <= host_addr && host_addr < max; -} - -/* Safely return a page to the OS. */ -static bool gasket_release_page(struct page *page) -{ - if (!page) - return false; - - if (!PageReserved(page)) - SetPageDirty(page); - unpin_user_page(page); - - return true; -} - -/* - * Get and map last level page table buffers. - * - * slots is the location(s) to write device-mapped page address. If this is a - * simple mapping, these will be address translation registers. If this is - * an extended mapping, these will be within a second-level page table - * allocated by the host and so must have their __iomem attribute casted away. - */ -static int gasket_perform_mapping(struct gasket_page_table *pg_tbl, - struct gasket_page_table_entry *ptes, - u64 __iomem *slots, ulong host_addr, - uint num_pages, int is_simple_mapping) -{ - int ret; - ulong offset; - struct page *page; - dma_addr_t dma_addr; - ulong page_addr; - int i; - - for (i = 0; i < num_pages; i++) { - page_addr = host_addr + i * PAGE_SIZE; - offset = page_addr & (PAGE_SIZE - 1); - if (is_coherent(pg_tbl, host_addr)) { - u64 off = - (u64)host_addr - - (u64)pg_tbl->coherent_pages[0].user_virt; - ptes[i].page = NULL; - ptes[i].offset = offset; - ptes[i].dma_addr = pg_tbl->coherent_pages[0].paddr + - off + i * PAGE_SIZE; - } else { - ret = pin_user_pages_fast(page_addr - offset, 1, - FOLL_WRITE, &page); - - if (ret <= 0) { - dev_err(pg_tbl->device, - "pin user pages failed for addr=0x%lx, offset=0x%lx [ret=%d]\n", - page_addr, offset, ret); - return ret ? ret : -ENOMEM; - } - ++pg_tbl->num_active_pages; - - ptes[i].page = page; - ptes[i].offset = offset; - - /* Map the page into DMA space. */ - ptes[i].dma_addr = - dma_map_page(pg_tbl->device, page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(pg_tbl->device, - ptes[i].dma_addr)) { - if (gasket_release_page(ptes[i].page)) - --pg_tbl->num_active_pages; - - memset(&ptes[i], 0, - sizeof(struct gasket_page_table_entry)); - return -EINVAL; - } - } - - /* Make the DMA-space address available to the device. */ - dma_addr = (ptes[i].dma_addr + offset) | GASKET_VALID_SLOT_FLAG; - - if (is_simple_mapping) { - writeq(dma_addr, &slots[i]); - } else { - ((u64 __force *)slots)[i] = dma_addr; - /* Extended page table vectors are in DRAM, - * and so need to be synced each time they are updated. - */ - dma_map_single(pg_tbl->device, - (void *)&((u64 __force *)slots)[i], - sizeof(u64), DMA_TO_DEVICE); - } - ptes[i].status = PTE_INUSE; - } - return 0; -} - -/* - * Return the index of the page for the address in the simple table. - * Does not perform validity checking. - */ -static int gasket_simple_page_idx(struct gasket_page_table *pg_tbl, - ulong dev_addr) -{ - return (dev_addr >> GASKET_SIMPLE_PAGE_SHIFT) & - (pg_tbl->config.total_entries - 1); -} - -/* - * Return the level 0 page index for the given address. - * Does not perform validity checking. - */ -static ulong gasket_extended_lvl0_page_idx(struct gasket_page_table *pg_tbl, - ulong dev_addr) -{ - return (dev_addr >> GASKET_EXTENDED_LVL0_SHIFT) & - (pg_tbl->config.total_entries - 1); -} - -/* - * Return the level 1 page index for the given address. - * Does not perform validity checking. - */ -static ulong gasket_extended_lvl1_page_idx(struct gasket_page_table *pg_tbl, - ulong dev_addr) -{ - return (dev_addr >> GASKET_EXTENDED_LVL1_SHIFT) & - (GASKET_PAGES_PER_SUBTABLE - 1); -} - -/* - * Allocate page table entries in a simple table. - * The page table mutex must be held by the caller. - */ -static int gasket_alloc_simple_entries(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_pages) -{ - if (!gasket_is_pte_range_free(pg_tbl->entries + - gasket_simple_page_idx(pg_tbl, dev_addr), - num_pages)) - return -EBUSY; - - return 0; -} - -/* - * Unmap and release mapped pages. - * The page table mutex must be held by the caller. - */ -static void gasket_perform_unmapping(struct gasket_page_table *pg_tbl, - struct gasket_page_table_entry *ptes, - u64 __iomem *slots, uint num_pages, - int is_simple_mapping) -{ - int i; - /* - * For each page table entry and corresponding entry in the device's - * address translation table: - */ - for (i = 0; i < num_pages; i++) { - /* release the address from the device, */ - if (is_simple_mapping || ptes[i].status == PTE_INUSE) { - writeq(0, &slots[i]); - } else { - ((u64 __force *)slots)[i] = 0; - /* sync above PTE update before updating mappings */ - wmb(); - } - - /* release the address from the driver, */ - if (ptes[i].status == PTE_INUSE) { - if (ptes[i].page && ptes[i].dma_addr) { - dma_unmap_page(pg_tbl->device, ptes[i].dma_addr, - PAGE_SIZE, DMA_BIDIRECTIONAL); - } - if (gasket_release_page(ptes[i].page)) - --pg_tbl->num_active_pages; - } - - /* and clear the PTE. */ - memset(&ptes[i], 0, sizeof(struct gasket_page_table_entry)); - } -} - -/* - * Unmap and release pages mapped to simple addresses. - * The page table mutex must be held by the caller. - */ -static void gasket_unmap_simple_pages(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_pages) -{ - uint slot = gasket_simple_page_idx(pg_tbl, dev_addr); - - gasket_perform_unmapping(pg_tbl, pg_tbl->entries + slot, - pg_tbl->base_slot + slot, num_pages, 1); -} - -/* - * Unmap and release buffers to extended addresses. - * The page table mutex must be held by the caller. - */ -static void gasket_unmap_extended_pages(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_pages) -{ - uint slot_idx, remain, len; - struct gasket_page_table_entry *pte; - u64 __iomem *slot_base; - - remain = num_pages; - slot_idx = gasket_extended_lvl1_page_idx(pg_tbl, dev_addr); - pte = pg_tbl->entries + pg_tbl->num_simple_entries + - gasket_extended_lvl0_page_idx(pg_tbl, dev_addr); - - while (remain > 0) { - /* TODO: Add check to ensure pte remains valid? */ - len = min(remain, GASKET_PAGES_PER_SUBTABLE - slot_idx); - - if (pte->status == PTE_INUSE) { - slot_base = (u64 __iomem *)(page_address(pte->page) + - pte->offset); - gasket_perform_unmapping(pg_tbl, - pte->sublevel + slot_idx, - slot_base + slot_idx, len, 0); - } - - remain -= len; - slot_idx = 0; - pte++; - } -} - -/* Evaluates to nonzero if the specified virtual address is simple. */ -static inline bool gasket_addr_is_simple(struct gasket_page_table *pg_tbl, - ulong addr) -{ - return !((addr) & (pg_tbl)->extended_flag); -} - -/* - * Convert (simple, page, offset) into a device address. - * Examples: - * Simple page 0, offset 32: - * Input (1, 0, 32), Output 0x20 - * Simple page 1000, offset 511: - * Input (1, 1000, 511), Output 0x3E81FF - * Extended page 0, offset 32: - * Input (0, 0, 32), Output 0x8000000020 - * Extended page 1000, offset 511: - * Input (0, 1000, 511), Output 0x8003E81FF - */ -static ulong gasket_components_to_dev_address(struct gasket_page_table *pg_tbl, - int is_simple, uint page_index, - uint offset) -{ - ulong dev_addr = (page_index << GASKET_SIMPLE_PAGE_SHIFT) | offset; - - return is_simple ? dev_addr : (pg_tbl->extended_flag | dev_addr); -} - -/* - * Validity checking for simple addresses. - * - * Verify that address translation commutes (from address to/from page + offset) - * and that the requested page range starts and ends within the set of - * currently-partitioned simple pages. - */ -static bool gasket_is_simple_dev_addr_bad(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_pages) -{ - ulong page_offset = dev_addr & (PAGE_SIZE - 1); - ulong page_index = - (dev_addr / PAGE_SIZE) & (pg_tbl->config.total_entries - 1); - - if (gasket_components_to_dev_address(pg_tbl, 1, page_index, - page_offset) != dev_addr) { - dev_err(pg_tbl->device, "address is invalid, 0x%lX\n", - dev_addr); - return true; - } - - if (page_index >= pg_tbl->num_simple_entries) { - dev_err(pg_tbl->device, - "starting slot at %lu is too large, max is < %u\n", - page_index, pg_tbl->num_simple_entries); - return true; - } - - if (page_index + num_pages > pg_tbl->num_simple_entries) { - dev_err(pg_tbl->device, - "ending slot at %lu is too large, max is <= %u\n", - page_index + num_pages, pg_tbl->num_simple_entries); - return true; - } - - return false; -} - -/* - * Validity checking for extended addresses. - * - * Verify that address translation commutes (from address to/from page + - * offset) and that the requested page range starts and ends within the set of - * currently-partitioned extended pages. - */ -static bool gasket_is_extended_dev_addr_bad(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_pages) -{ - /* Starting byte index of dev_addr into the first mapped page */ - ulong page_offset = dev_addr & (PAGE_SIZE - 1); - ulong page_global_idx, page_lvl0_idx; - ulong num_lvl0_pages; - ulong addr; - - /* check if the device address is out of bound */ - addr = dev_addr & ~((pg_tbl)->extended_flag); - if (addr >> (GASKET_EXTENDED_LVL0_WIDTH + GASKET_EXTENDED_LVL0_SHIFT)) { - dev_err(pg_tbl->device, "device address out of bounds: 0x%lx\n", - dev_addr); - return true; - } - - /* Find the starting sub-page index in the space of all sub-pages. */ - page_global_idx = (dev_addr / PAGE_SIZE) & - (pg_tbl->config.total_entries * GASKET_PAGES_PER_SUBTABLE - 1); - - /* Find the starting level 0 index. */ - page_lvl0_idx = gasket_extended_lvl0_page_idx(pg_tbl, dev_addr); - - /* Get the count of affected level 0 pages. */ - num_lvl0_pages = DIV_ROUND_UP(num_pages, GASKET_PAGES_PER_SUBTABLE); - - if (gasket_components_to_dev_address(pg_tbl, 0, page_global_idx, - page_offset) != dev_addr) { - dev_err(pg_tbl->device, "address is invalid: 0x%lx\n", - dev_addr); - return true; - } - - if (page_lvl0_idx >= pg_tbl->num_extended_entries) { - dev_err(pg_tbl->device, - "starting level 0 slot at %lu is too large, max is < %u\n", - page_lvl0_idx, pg_tbl->num_extended_entries); - return true; - } - - if (page_lvl0_idx + num_lvl0_pages > pg_tbl->num_extended_entries) { - dev_err(pg_tbl->device, - "ending level 0 slot at %lu is too large, max is <= %u\n", - page_lvl0_idx + num_lvl0_pages, - pg_tbl->num_extended_entries); - return true; - } - - return false; -} - -/* - * Non-locking entry to unmapping routines. - * The page table mutex must be held by the caller. - */ -static void gasket_page_table_unmap_nolock(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_pages) -{ - if (!num_pages) - return; - - if (gasket_addr_is_simple(pg_tbl, dev_addr)) - gasket_unmap_simple_pages(pg_tbl, dev_addr, num_pages); - else - gasket_unmap_extended_pages(pg_tbl, dev_addr, num_pages); -} - -/* - * Allocate and map pages to simple addresses. - * If there is an error, no pages are mapped. - */ -static int gasket_map_simple_pages(struct gasket_page_table *pg_tbl, - ulong host_addr, ulong dev_addr, - uint num_pages) -{ - int ret; - uint slot_idx = gasket_simple_page_idx(pg_tbl, dev_addr); - - ret = gasket_alloc_simple_entries(pg_tbl, dev_addr, num_pages); - if (ret) { - dev_err(pg_tbl->device, - "page table slots %u (@ 0x%lx) to %u are not available\n", - slot_idx, dev_addr, slot_idx + num_pages - 1); - return ret; - } - - ret = gasket_perform_mapping(pg_tbl, pg_tbl->entries + slot_idx, - pg_tbl->base_slot + slot_idx, host_addr, - num_pages, 1); - - if (ret) { - gasket_page_table_unmap_nolock(pg_tbl, dev_addr, num_pages); - dev_err(pg_tbl->device, "gasket_perform_mapping %d\n", ret); - } - return ret; -} - -/* - * Allocate a second level page table. - * The page table mutex must be held by the caller. - */ -static int gasket_alloc_extended_subtable(struct gasket_page_table *pg_tbl, - struct gasket_page_table_entry *pte, - u64 __iomem *slot) -{ - ulong page_addr, subtable_bytes; - dma_addr_t dma_addr; - - /* XXX FIX ME XXX this is inefficient for non-4K page sizes */ - - /* GFP_DMA flag must be passed to architectures for which - * part of the memory range is not considered DMA'able. - * This seems to be the case for Juno board with 4.5.0 Linaro kernel - */ - page_addr = get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!page_addr) - return -ENOMEM; - pte->page = virt_to_page((void *)page_addr); - pte->offset = 0; - - subtable_bytes = sizeof(struct gasket_page_table_entry) * - GASKET_PAGES_PER_SUBTABLE; - pte->sublevel = vzalloc(subtable_bytes); - if (!pte->sublevel) { - free_page(page_addr); - memset(pte, 0, sizeof(struct gasket_page_table_entry)); - return -ENOMEM; - } - - /* Map the page into DMA space. */ - pte->dma_addr = dma_map_page(pg_tbl->device, pte->page, 0, PAGE_SIZE, - DMA_TO_DEVICE); - if (dma_mapping_error(pg_tbl->device, pte->dma_addr)) { - free_page(page_addr); - vfree(pte->sublevel); - memset(pte, 0, sizeof(struct gasket_page_table_entry)); - return -ENOMEM; - } - - /* make the addresses available to the device */ - dma_addr = (pte->dma_addr + pte->offset) | GASKET_VALID_SLOT_FLAG; - writeq(dma_addr, slot); - - pte->status = PTE_INUSE; - - return 0; -} - -/* - * Allocate slots in an extended page table. Check to see if a range of page - * table slots are available. If necessary, memory is allocated for second level - * page tables. - * - * Note that memory for second level page tables is allocated as needed, but - * that memory is only freed on the final close of the device file, when the - * page tables are repartitioned, or the device is removed. If there is an - * error or if the full range of slots is not available, any memory - * allocated for second level page tables remains allocated until final close, - * repartition, or device removal. - * - * The page table mutex must be held by the caller. - */ -static int gasket_alloc_extended_entries(struct gasket_page_table *pg_tbl, - ulong dev_addr, uint num_entries) -{ - int ret = 0; - uint remain, subtable_slot_idx, len; - struct gasket_page_table_entry *pte; - u64 __iomem *slot; - - remain = num_entries; - subtable_slot_idx = gasket_extended_lvl1_page_idx(pg_tbl, dev_addr); - pte = pg_tbl->entries + pg_tbl->num_simple_entries + - gasket_extended_lvl0_page_idx(pg_tbl, dev_addr); - slot = pg_tbl->base_slot + pg_tbl->num_simple_entries + - gasket_extended_lvl0_page_idx(pg_tbl, dev_addr); - - while (remain > 0) { - len = min(remain, - GASKET_PAGES_PER_SUBTABLE - subtable_slot_idx); - - if (pte->status == PTE_FREE) { - ret = gasket_alloc_extended_subtable(pg_tbl, pte, slot); - if (ret) { - dev_err(pg_tbl->device, - "no memory for extended addr subtable\n"); - return ret; - } - } else { - if (!gasket_is_pte_range_free(pte->sublevel + - subtable_slot_idx, len)) - return -EBUSY; - } - - remain -= len; - subtable_slot_idx = 0; - pte++; - slot++; - } - - return 0; -} - -/* - * gasket_map_extended_pages - Get and map buffers to extended addresses. - * If there is an error, no pages are mapped. - */ -static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl, - ulong host_addr, ulong dev_addr, - uint num_pages) -{ - int ret; - ulong dev_addr_end; - uint slot_idx, remain, len; - struct gasket_page_table_entry *pte; - u64 __iomem *slot_base; - - ret = gasket_alloc_extended_entries(pg_tbl, dev_addr, num_pages); - if (ret) { - dev_addr_end = dev_addr + (num_pages / PAGE_SIZE) - 1; - dev_err(pg_tbl->device, - "page table slots (%lu,%lu) (@ 0x%lx) to (%lu,%lu) are not available\n", - gasket_extended_lvl0_page_idx(pg_tbl, dev_addr), - dev_addr, - gasket_extended_lvl1_page_idx(pg_tbl, dev_addr), - gasket_extended_lvl0_page_idx(pg_tbl, dev_addr_end), - gasket_extended_lvl1_page_idx(pg_tbl, dev_addr_end)); - return ret; - } - - remain = num_pages; - slot_idx = gasket_extended_lvl1_page_idx(pg_tbl, dev_addr); - pte = pg_tbl->entries + pg_tbl->num_simple_entries + - gasket_extended_lvl0_page_idx(pg_tbl, dev_addr); - - while (remain > 0) { - len = min(remain, GASKET_PAGES_PER_SUBTABLE - slot_idx); - - slot_base = - (u64 __iomem *)(page_address(pte->page) + pte->offset); - ret = gasket_perform_mapping(pg_tbl, pte->sublevel + slot_idx, - slot_base + slot_idx, host_addr, - len, 0); - if (ret) { - gasket_page_table_unmap_nolock(pg_tbl, dev_addr, - num_pages); - return ret; - } - - remain -= len; - slot_idx = 0; - pte++; - host_addr += len * PAGE_SIZE; - } - - return 0; -} - -/* - * See gasket_page_table.h for general description. - * - * gasket_page_table_map calls either gasket_map_simple_pages() or - * gasket_map_extended_pages() to actually perform the mapping. - * - * The page table mutex is held for the entire operation. - */ -int gasket_page_table_map(struct gasket_page_table *pg_tbl, ulong host_addr, - ulong dev_addr, uint num_pages) -{ - int ret; - - if (!num_pages) - return 0; - - mutex_lock(&pg_tbl->mutex); - - if (gasket_addr_is_simple(pg_tbl, dev_addr)) { - ret = gasket_map_simple_pages(pg_tbl, host_addr, dev_addr, - num_pages); - } else { - ret = gasket_map_extended_pages(pg_tbl, host_addr, dev_addr, - num_pages); - } - - mutex_unlock(&pg_tbl->mutex); - return ret; -} -EXPORT_SYMBOL(gasket_page_table_map); - -/* - * See gasket_page_table.h for general description. - * - * gasket_page_table_unmap takes the page table lock and calls either - * gasket_unmap_simple_pages() or gasket_unmap_extended_pages() to - * actually unmap the pages from device space. - * - * The page table mutex is held for the entire operation. - */ -void gasket_page_table_unmap(struct gasket_page_table *pg_tbl, ulong dev_addr, - uint num_pages) -{ - if (!num_pages) - return; - - mutex_lock(&pg_tbl->mutex); - gasket_page_table_unmap_nolock(pg_tbl, dev_addr, num_pages); - mutex_unlock(&pg_tbl->mutex); -} -EXPORT_SYMBOL(gasket_page_table_unmap); - -static void gasket_page_table_unmap_all_nolock(struct gasket_page_table *pg_tbl) -{ - gasket_unmap_simple_pages(pg_tbl, - gasket_components_to_dev_address(pg_tbl, 1, 0, - 0), - pg_tbl->num_simple_entries); - gasket_unmap_extended_pages(pg_tbl, - gasket_components_to_dev_address(pg_tbl, 0, - 0, 0), - pg_tbl->num_extended_entries * - GASKET_PAGES_PER_SUBTABLE); -} - -/* See gasket_page_table.h for description. */ -void gasket_page_table_unmap_all(struct gasket_page_table *pg_tbl) -{ - mutex_lock(&pg_tbl->mutex); - gasket_page_table_unmap_all_nolock(pg_tbl); - mutex_unlock(&pg_tbl->mutex); -} -EXPORT_SYMBOL(gasket_page_table_unmap_all); - -/* See gasket_page_table.h for description. */ -void gasket_page_table_reset(struct gasket_page_table *pg_tbl) -{ - mutex_lock(&pg_tbl->mutex); - gasket_page_table_unmap_all_nolock(pg_tbl); - writeq(pg_tbl->config.total_entries, pg_tbl->extended_offset_reg); - mutex_unlock(&pg_tbl->mutex); -} - -/* See gasket_page_table.h for description. */ -int gasket_page_table_lookup_page(struct gasket_page_table *pg_tbl, - ulong dev_addr, struct page **ppage, - ulong *poffset) -{ - uint page_num; - struct gasket_page_table_entry *pte; - - mutex_lock(&pg_tbl->mutex); - if (gasket_addr_is_simple(pg_tbl, dev_addr)) { - page_num = gasket_simple_page_idx(pg_tbl, dev_addr); - if (page_num >= pg_tbl->num_simple_entries) - goto fail; - - pte = pg_tbl->entries + page_num; - if (pte->status != PTE_INUSE) - goto fail; - } else { - /* Find the level 0 entry, */ - page_num = gasket_extended_lvl0_page_idx(pg_tbl, dev_addr); - if (page_num >= pg_tbl->num_extended_entries) - goto fail; - - pte = pg_tbl->entries + pg_tbl->num_simple_entries + page_num; - if (pte->status != PTE_INUSE) - goto fail; - - /* and its contained level 1 entry. */ - page_num = gasket_extended_lvl1_page_idx(pg_tbl, dev_addr); - pte = pte->sublevel + page_num; - if (pte->status != PTE_INUSE) - goto fail; - } - - *ppage = pte->page; - *poffset = pte->offset; - mutex_unlock(&pg_tbl->mutex); - return 0; - -fail: - *ppage = NULL; - *poffset = 0; - mutex_unlock(&pg_tbl->mutex); - return -EINVAL; -} - -/* See gasket_page_table.h for description. */ -bool gasket_page_table_are_addrs_bad(struct gasket_page_table *pg_tbl, - ulong host_addr, ulong dev_addr, - ulong bytes) -{ - if (host_addr & (PAGE_SIZE - 1)) { - dev_err(pg_tbl->device, - "host mapping address 0x%lx must be page aligned\n", - host_addr); - return true; - } - - return gasket_page_table_is_dev_addr_bad(pg_tbl, dev_addr, bytes); -} -EXPORT_SYMBOL(gasket_page_table_are_addrs_bad); - -/* See gasket_page_table.h for description. */ -bool gasket_page_table_is_dev_addr_bad(struct gasket_page_table *pg_tbl, - ulong dev_addr, ulong bytes) -{ - uint num_pages = bytes / PAGE_SIZE; - - if (bytes & (PAGE_SIZE - 1)) { - dev_err(pg_tbl->device, - "mapping size 0x%lX must be page aligned\n", bytes); - return true; - } - - if (num_pages == 0) { - dev_err(pg_tbl->device, - "requested mapping is less than one page: %lu / %lu\n", - bytes, PAGE_SIZE); - return true; - } - - if (gasket_addr_is_simple(pg_tbl, dev_addr)) - return gasket_is_simple_dev_addr_bad(pg_tbl, dev_addr, - num_pages); - return gasket_is_extended_dev_addr_bad(pg_tbl, dev_addr, num_pages); -} -EXPORT_SYMBOL(gasket_page_table_is_dev_addr_bad); - -/* See gasket_page_table.h for description. */ -uint gasket_page_table_max_size(struct gasket_page_table *page_table) -{ - if (!page_table) - return 0; - return page_table->config.total_entries; -} -EXPORT_SYMBOL(gasket_page_table_max_size); - -/* See gasket_page_table.h for description. */ -uint gasket_page_table_num_entries(struct gasket_page_table *pg_tbl) -{ - if (!pg_tbl) - return 0; - return pg_tbl->num_simple_entries + pg_tbl->num_extended_entries; -} -EXPORT_SYMBOL(gasket_page_table_num_entries); - -/* See gasket_page_table.h for description. */ -uint gasket_page_table_num_simple_entries(struct gasket_page_table *pg_tbl) -{ - if (!pg_tbl) - return 0; - return pg_tbl->num_simple_entries; -} -EXPORT_SYMBOL(gasket_page_table_num_simple_entries); - -/* See gasket_page_table.h for description. */ -uint gasket_page_table_num_active_pages(struct gasket_page_table *pg_tbl) -{ - if (!pg_tbl) - return 0; - return pg_tbl->num_active_pages; -} -EXPORT_SYMBOL(gasket_page_table_num_active_pages); - -/* See gasket_page_table.h */ -int gasket_page_table_system_status(struct gasket_page_table *page_table) -{ - if (!page_table) - return GASKET_STATUS_LAMED; - - if (gasket_page_table_num_entries(page_table) == 0) { - dev_dbg(page_table->device, "Page table size is 0\n"); - return GASKET_STATUS_LAMED; - } - - return GASKET_STATUS_ALIVE; -} - -/* Record the host_addr to coherent dma memory mapping. */ -int gasket_set_user_virt(struct gasket_dev *gasket_dev, u64 size, - dma_addr_t dma_address, ulong vma) -{ - int j; - struct gasket_page_table *pg_tbl; - - unsigned int num_pages = size / PAGE_SIZE; - - /* - * TODO: for future chipset, better handling of the case where multiple - * page tables are supported on a given device - */ - pg_tbl = gasket_dev->page_table[0]; - if (!pg_tbl) { - dev_dbg(gasket_dev->dev, "%s: invalid page table index\n", - __func__); - return 0; - } - for (j = 0; j < num_pages; j++) { - pg_tbl->coherent_pages[j].user_virt = - (u64)vma + j * PAGE_SIZE; - } - return 0; -} - -/* Allocate a block of coherent memory. */ -int gasket_alloc_coherent_memory(struct gasket_dev *gasket_dev, u64 size, - dma_addr_t *dma_address, u64 index) -{ - dma_addr_t handle; - void *mem; - int j; - unsigned int num_pages = DIV_ROUND_UP(size, PAGE_SIZE); - const struct gasket_driver_desc *driver_desc = - gasket_get_driver_desc(gasket_dev); - - if (!gasket_dev->page_table[index]) - return -EFAULT; - - if (num_pages == 0) - return -EINVAL; - - mem = dma_alloc_coherent(gasket_get_device(gasket_dev), - num_pages * PAGE_SIZE, &handle, GFP_KERNEL); - if (!mem) - goto nomem; - - gasket_dev->page_table[index]->num_coherent_pages = num_pages; - - /* allocate the physical memory block */ - gasket_dev->page_table[index]->coherent_pages = - kcalloc(num_pages, - sizeof(*gasket_dev->page_table[index]->coherent_pages), - GFP_KERNEL); - if (!gasket_dev->page_table[index]->coherent_pages) - goto nomem; - - gasket_dev->coherent_buffer.length_bytes = - PAGE_SIZE * (num_pages); - gasket_dev->coherent_buffer.phys_base = handle; - gasket_dev->coherent_buffer.virt_base = mem; - - *dma_address = driver_desc->coherent_buffer_description.base; - for (j = 0; j < num_pages; j++) { - gasket_dev->page_table[index]->coherent_pages[j].paddr = - handle + j * PAGE_SIZE; - gasket_dev->page_table[index]->coherent_pages[j].kernel_virt = - (u64)mem + j * PAGE_SIZE; - } - - return 0; - -nomem: - if (mem) { - dma_free_coherent(gasket_get_device(gasket_dev), - num_pages * PAGE_SIZE, mem, handle); - gasket_dev->coherent_buffer.length_bytes = 0; - gasket_dev->coherent_buffer.virt_base = NULL; - gasket_dev->coherent_buffer.phys_base = 0; - } - - kfree(gasket_dev->page_table[index]->coherent_pages); - gasket_dev->page_table[index]->coherent_pages = NULL; - gasket_dev->page_table[index]->num_coherent_pages = 0; - return -ENOMEM; -} - -/* Free a block of coherent memory. */ -int gasket_free_coherent_memory(struct gasket_dev *gasket_dev, u64 size, - dma_addr_t dma_address, u64 index) -{ - const struct gasket_driver_desc *driver_desc; - - if (!gasket_dev->page_table[index]) - return -EFAULT; - - driver_desc = gasket_get_driver_desc(gasket_dev); - - if (driver_desc->coherent_buffer_description.base != dma_address) - return -EADDRNOTAVAIL; - - if (gasket_dev->coherent_buffer.length_bytes) { - dma_free_coherent(gasket_get_device(gasket_dev), - gasket_dev->coherent_buffer.length_bytes, - gasket_dev->coherent_buffer.virt_base, - gasket_dev->coherent_buffer.phys_base); - gasket_dev->coherent_buffer.length_bytes = 0; - gasket_dev->coherent_buffer.virt_base = NULL; - gasket_dev->coherent_buffer.phys_base = 0; - } - - kfree(gasket_dev->page_table[index]->coherent_pages); - gasket_dev->page_table[index]->coherent_pages = NULL; - gasket_dev->page_table[index]->num_coherent_pages = 0; - - return 0; -} - -/* Release all coherent memory. */ -void gasket_free_coherent_memory_all(struct gasket_dev *gasket_dev, u64 index) -{ - if (!gasket_dev->page_table[index]) - return; - - if (gasket_dev->coherent_buffer.length_bytes) { - dma_free_coherent(gasket_get_device(gasket_dev), - gasket_dev->coherent_buffer.length_bytes, - gasket_dev->coherent_buffer.virt_base, - gasket_dev->coherent_buffer.phys_base); - gasket_dev->coherent_buffer.length_bytes = 0; - gasket_dev->coherent_buffer.virt_base = NULL; - gasket_dev->coherent_buffer.phys_base = 0; - } -} diff --git a/drivers/staging/gasket/gasket_page_table.h b/drivers/staging/gasket/gasket_page_table.h deleted file mode 100644 index 7b01b73ea3e70303843a3ea97cb56ea1c28fdc6c..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_page_table.h +++ /dev/null @@ -1,249 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Gasket Page Table functionality. This file describes the address - * translation/paging functionality supported by the Gasket driver framework. - * As much as possible, internal details are hidden to simplify use - - * all calls are thread-safe (protected by an internal mutex) except where - * indicated otherwise. - * - * Copyright (C) 2018 Google, Inc. - */ - -#ifndef __GASKET_PAGE_TABLE_H__ -#define __GASKET_PAGE_TABLE_H__ - -#include <linux/pci.h> -#include <linux/types.h> - -#include "gasket_constants.h" -#include "gasket_core.h" - -/* - * Structure used for managing address translation on a device. All details are - * internal to the implementation. - */ -struct gasket_page_table; - -/* - * Allocate and init address translation data. - * @ppage_table: Pointer to Gasket page table pointer. Set by this call. - * @att_base_reg: [Mapped] pointer to the first entry in the device's address - * translation table. - * @extended_offset_reg: [Mapped] pointer to the device's register containing - * the starting index of the extended translation table. - * @extended_bit_location: The index of the bit indicating whether an address - * is extended. - * @total_entries: The total number of entries in the device's address - * translation table. - * @device: Device structure for the underlying device. Only used for logging. - * @pci_dev: PCI system descriptor for the underlying device. - * whether the driver will supply its own. - * - * Description: Allocates and initializes data to track address translation - - * simple and extended page table metadata. Initially, the page table is - * partitioned such that all addresses are "simple" (single-level lookup). - * gasket_partition_page_table can be called to change this paritioning. - * - * Returns 0 on success, a negative error code otherwise. - */ -int gasket_page_table_init(struct gasket_page_table **ppg_tbl, - const struct gasket_bar_data *bar_data, - const struct gasket_page_table_config *page_table_config, - struct device *device, struct pci_dev *pci_dev); - -/* - * Deallocate and cleanup page table data. - * @page_table: Gasket page table pointer. - * - * Description: The inverse of gasket_init; frees page_table and its contained - * elements. - * - * Because this call destroys the page table, it cannot be - * thread-safe (mutex-protected)! - */ -void gasket_page_table_cleanup(struct gasket_page_table *page_table); - -/* - * Sets the size of the simple page table. - * @page_table: Gasket page table pointer. - * @num_simple_entries: Desired size of the simple page table (in entries). - * - * Description: gasket_partition_page_table checks to see if the simple page - * size can be changed (i.e., if there are no active extended - * mappings in the new simple size range), and, if so, - * sets the new simple and extended page table sizes. - * - * Returns 0 if successful, or non-zero if the page table entries - * are not free. - */ -int gasket_page_table_partition(struct gasket_page_table *page_table, - uint num_simple_entries); - -/* - * Get and map [host] user space pages into device memory. - * @page_table: Gasket page table pointer. - * @host_addr: Starting host virtual memory address of the pages. - * @dev_addr: Starting device address of the pages. - * @num_pages: Number of [4kB] pages to map. - * - * Description: Maps the "num_pages" pages of host memory pointed to by - * host_addr to the address "dev_addr" in device memory. - * - * The caller is responsible for checking the addresses ranges. - * - * Returns 0 if successful or a non-zero error number otherwise. - * If there is an error, no pages are mapped. - */ -int gasket_page_table_map(struct gasket_page_table *page_table, ulong host_addr, - ulong dev_addr, uint num_pages); - -/* - * Un-map host pages from device memory. - * @page_table: Gasket page table pointer. - * @dev_addr: Starting device address of the pages to unmap. - * @num_pages: The number of [4kB] pages to unmap. - * - * Description: The inverse of gasket_map_pages. Unmaps pages from the device. - */ -void gasket_page_table_unmap(struct gasket_page_table *page_table, - ulong dev_addr, uint num_pages); - -/* - * Unmap ALL host pages from device memory. - * @page_table: Gasket page table pointer. - */ -void gasket_page_table_unmap_all(struct gasket_page_table *page_table); - -/* - * Unmap all host pages from device memory and reset the table to fully simple - * addressing. - * @page_table: Gasket page table pointer. - */ -void gasket_page_table_reset(struct gasket_page_table *page_table); - -/* - * Reclaims unused page table memory. - * @page_table: Gasket page table pointer. - * - * Description: Examines the page table and frees any currently-unused - * allocations. Called internally on gasket_cleanup(). - */ -void gasket_page_table_garbage_collect(struct gasket_page_table *page_table); - -/* - * Retrieve the backing page for a device address. - * @page_table: Gasket page table pointer. - * @dev_addr: Gasket device address. - * @ppage: Pointer to a page pointer for the returned page. - * @poffset: Pointer to an unsigned long for the returned offset. - * - * Description: Interprets the address and looks up the corresponding page - * in the page table and the offset in that page. (We need an - * offset because the host page may be larger than the Gasket chip - * page it contains.) - * - * Returns 0 if successful, -1 for an error. The page pointer - * and offset are returned through the pointers, if successful. - */ -int gasket_page_table_lookup_page(struct gasket_page_table *page_table, - ulong dev_addr, struct page **page, - ulong *poffset); - -/* - * Checks validity for input addrs and size. - * @page_table: Gasket page table pointer. - * @host_addr: Host address to check. - * @dev_addr: Gasket device address. - * @bytes: Size of the range to check (in bytes). - * - * Description: This call performs a number of checks to verify that the ranges - * specified by both addresses and the size are valid for mapping pages into - * device memory. - * - * Returns true if the mapping is bad, false otherwise. - */ -bool gasket_page_table_are_addrs_bad(struct gasket_page_table *page_table, - ulong host_addr, ulong dev_addr, - ulong bytes); - -/* - * Checks validity for input dev addr and size. - * @page_table: Gasket page table pointer. - * @dev_addr: Gasket device address. - * @bytes: Size of the range to check (in bytes). - * - * Description: This call performs a number of checks to verify that the range - * specified by the device address and the size is valid for mapping pages into - * device memory. - * - * Returns true if the address is bad, false otherwise. - */ -bool gasket_page_table_is_dev_addr_bad(struct gasket_page_table *page_table, - ulong dev_addr, ulong bytes); - -/* - * Gets maximum size for the given page table. - * @page_table: Gasket page table pointer. - */ -uint gasket_page_table_max_size(struct gasket_page_table *page_table); - -/* - * Gets the total number of entries in the arg. - * @page_table: Gasket page table pointer. - */ -uint gasket_page_table_num_entries(struct gasket_page_table *page_table); - -/* - * Gets the number of simple entries. - * @page_table: Gasket page table pointer. - */ -uint gasket_page_table_num_simple_entries(struct gasket_page_table *page_table); - -/* - * Gets the number of actively pinned pages. - * @page_table: Gasket page table pointer. - */ -uint gasket_page_table_num_active_pages(struct gasket_page_table *page_table); - -/* - * Get status of page table managed by @page_table. - * @page_table: Gasket page table pointer. - */ -int gasket_page_table_system_status(struct gasket_page_table *page_table); - -/* - * Allocate a block of coherent memory. - * @gasket_dev: Gasket Device. - * @size: Size of the memory block. - * @dma_address: Dma address allocated by the kernel. - * @index: Index of the gasket_page_table within this Gasket device - * - * Description: Allocate a contiguous coherent memory block, DMA'ble - * by this device. - */ -int gasket_alloc_coherent_memory(struct gasket_dev *gasket_dev, uint64_t size, - dma_addr_t *dma_address, uint64_t index); -/* Release a block of contiguous coherent memory, in use by a device. */ -int gasket_free_coherent_memory(struct gasket_dev *gasket_dev, uint64_t size, - dma_addr_t dma_address, uint64_t index); - -/* Release all coherent memory. */ -void gasket_free_coherent_memory_all(struct gasket_dev *gasket_dev, - uint64_t index); - -/* - * Records the host_addr to coherent dma memory mapping. - * @gasket_dev: Gasket Device. - * @size: Size of the virtual address range to map. - * @dma_address: Dma address within the coherent memory range. - * @vma: Virtual address we wish to map to coherent memory. - * - * Description: For each page in the virtual address range, record the - * coherent page mapping. - * - * Does not perform validity checking. - */ -int gasket_set_user_virt(struct gasket_dev *gasket_dev, uint64_t size, - dma_addr_t dma_address, ulong vma); - -#endif /* __GASKET_PAGE_TABLE_H__ */ diff --git a/drivers/staging/gasket/gasket_sysfs.c b/drivers/staging/gasket/gasket_sysfs.c deleted file mode 100644 index af26bc9f184a544753652989f3168a955bf75166..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_sysfs.c +++ /dev/null @@ -1,398 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2018 Google, Inc. */ -#include "gasket_sysfs.h" - -#include "gasket_core.h" - -#include <linux/device.h> -#include <linux/printk.h> - -/* - * Pair of kernel device and user-specified pointer. Used in lookups in sysfs - * "show" functions to return user data. - */ - -struct gasket_sysfs_mapping { - /* - * The device bound to this mapping. If this is NULL, then this mapping - * is free. - */ - struct device *device; - - /* The Gasket descriptor for this device. */ - struct gasket_dev *gasket_dev; - - /* This device's set of sysfs attributes/nodes. */ - struct gasket_sysfs_attribute *attributes; - - /* The number of live elements in "attributes". */ - int attribute_count; - - /* Protects structure from simultaneous access. */ - struct mutex mutex; - - /* Tracks active users of this mapping. */ - struct kref refcount; -}; - -/* - * Data needed to manage users of this sysfs utility. - * Currently has a fixed size; if space is a concern, this can be dynamically - * allocated. - */ -/* - * 'Global' (file-scoped) list of mappings between devices and gasket_data - * pointers. This removes the requirement to have a gasket_sysfs_data - * handle in all files. - */ -static struct gasket_sysfs_mapping dev_mappings[GASKET_SYSFS_NUM_MAPPINGS]; - -/* Callback when a mapping's refcount goes to zero. */ -static void release_entry(struct kref *ref) -{ - /* All work is done after the return from kref_put. */ -} - -/* Look up mapping information for the given device. */ -static struct gasket_sysfs_mapping *get_mapping(struct device *device) -{ - int i; - - for (i = 0; i < GASKET_SYSFS_NUM_MAPPINGS; i++) { - mutex_lock(&dev_mappings[i].mutex); - if (dev_mappings[i].device == device) { - kref_get(&dev_mappings[i].refcount); - mutex_unlock(&dev_mappings[i].mutex); - return &dev_mappings[i]; - } - mutex_unlock(&dev_mappings[i].mutex); - } - - dev_dbg(device, "%s: Mapping to device %s not found\n", - __func__, device->kobj.name); - return NULL; -} - -/* Put a reference to a mapping. */ -static void put_mapping(struct gasket_sysfs_mapping *mapping) -{ - int i; - int num_files_to_remove = 0; - struct device_attribute *files_to_remove; - struct device *device; - - if (!mapping) { - pr_debug("%s: Mapping should not be NULL\n", __func__); - return; - } - - mutex_lock(&mapping->mutex); - if (kref_put(&mapping->refcount, release_entry)) { - dev_dbg(mapping->device, "Removing Gasket sysfs mapping\n"); - /* - * We can't remove the sysfs nodes in the kref callback, since - * device_remove_file() blocks until the node is free. - * Readers/writers of sysfs nodes, though, will be blocked on - * the mapping mutex, resulting in deadlock. To fix this, the - * sysfs nodes are removed outside the lock. - */ - device = mapping->device; - num_files_to_remove = mapping->attribute_count; - files_to_remove = kcalloc(num_files_to_remove, - sizeof(*files_to_remove), - GFP_KERNEL); - if (files_to_remove) - for (i = 0; i < num_files_to_remove; i++) - files_to_remove[i] = - mapping->attributes[i].attr; - else - num_files_to_remove = 0; - - kfree(mapping->attributes); - mapping->attributes = NULL; - mapping->attribute_count = 0; - put_device(mapping->device); - mapping->device = NULL; - mapping->gasket_dev = NULL; - } - mutex_unlock(&mapping->mutex); - - if (num_files_to_remove != 0) { - for (i = 0; i < num_files_to_remove; ++i) - device_remove_file(device, &files_to_remove[i]); - kfree(files_to_remove); - } -} - -/* - * Put a reference to a mapping N times. - * - * In higher-level resource acquire/release function pairs, the release function - * will need to release a mapping 2x - once for the refcount taken in the - * release function itself, and once for the count taken in the acquire call. - */ -static void put_mapping_n(struct gasket_sysfs_mapping *mapping, int times) -{ - int i; - - for (i = 0; i < times; i++) - put_mapping(mapping); -} - -void gasket_sysfs_init(void) -{ - int i; - - for (i = 0; i < GASKET_SYSFS_NUM_MAPPINGS; i++) { - dev_mappings[i].device = NULL; - mutex_init(&dev_mappings[i].mutex); - } -} - -int gasket_sysfs_create_mapping(struct device *device, - struct gasket_dev *gasket_dev) -{ - struct gasket_sysfs_mapping *mapping; - int map_idx = -1; - - /* - * We need a function-level mutex to protect against the same device - * being added [multiple times] simultaneously. - */ - static DEFINE_MUTEX(function_mutex); - - mutex_lock(&function_mutex); - dev_dbg(device, "Creating sysfs entries for device\n"); - - /* Check that the device we're adding hasn't already been added. */ - mapping = get_mapping(device); - if (mapping) { - dev_err(device, - "Attempting to re-initialize sysfs mapping for device\n"); - put_mapping(mapping); - mutex_unlock(&function_mutex); - return -EBUSY; - } - - /* Find the first empty entry in the array. */ - for (map_idx = 0; map_idx < GASKET_SYSFS_NUM_MAPPINGS; ++map_idx) { - mutex_lock(&dev_mappings[map_idx].mutex); - if (!dev_mappings[map_idx].device) - /* Break with the mutex held! */ - break; - mutex_unlock(&dev_mappings[map_idx].mutex); - } - - if (map_idx == GASKET_SYSFS_NUM_MAPPINGS) { - dev_err(device, "All mappings have been exhausted\n"); - mutex_unlock(&function_mutex); - return -ENOMEM; - } - - dev_dbg(device, "Creating sysfs mapping for device %s\n", - device->kobj.name); - - mapping = &dev_mappings[map_idx]; - mapping->attributes = kcalloc(GASKET_SYSFS_MAX_NODES, - sizeof(*mapping->attributes), - GFP_KERNEL); - if (!mapping->attributes) { - dev_dbg(device, "Unable to allocate sysfs attribute array\n"); - mutex_unlock(&mapping->mutex); - mutex_unlock(&function_mutex); - return -ENOMEM; - } - - kref_init(&mapping->refcount); - mapping->device = get_device(device); - mapping->gasket_dev = gasket_dev; - mapping->attribute_count = 0; - mutex_unlock(&mapping->mutex); - mutex_unlock(&function_mutex); - - /* Don't decrement the refcount here! One open count keeps it alive! */ - return 0; -} - -int gasket_sysfs_create_entries(struct device *device, - const struct gasket_sysfs_attribute *attrs) -{ - int i; - int ret; - struct gasket_sysfs_mapping *mapping = get_mapping(device); - - if (!mapping) { - dev_dbg(device, - "Creating entries for device without first initializing mapping\n"); - return -EINVAL; - } - - mutex_lock(&mapping->mutex); - for (i = 0; attrs[i].attr.attr.name != NULL; i++) { - if (mapping->attribute_count == GASKET_SYSFS_MAX_NODES) { - dev_err(device, - "Maximum number of sysfs nodes reached for device\n"); - mutex_unlock(&mapping->mutex); - put_mapping(mapping); - return -ENOMEM; - } - - ret = device_create_file(device, &attrs[i].attr); - if (ret) { - dev_dbg(device, "Unable to create device entries\n"); - mutex_unlock(&mapping->mutex); - put_mapping(mapping); - return ret; - } - - mapping->attributes[mapping->attribute_count] = attrs[i]; - ++mapping->attribute_count; - } - - mutex_unlock(&mapping->mutex); - put_mapping(mapping); - return 0; -} -EXPORT_SYMBOL(gasket_sysfs_create_entries); - -void gasket_sysfs_remove_mapping(struct device *device) -{ - struct gasket_sysfs_mapping *mapping = get_mapping(device); - - if (!mapping) { - dev_err(device, - "Attempted to remove non-existent sysfs mapping to device\n"); - return; - } - - put_mapping_n(mapping, 2); -} - -struct gasket_dev *gasket_sysfs_get_device_data(struct device *device) -{ - struct gasket_sysfs_mapping *mapping = get_mapping(device); - - if (!mapping) { - dev_err(device, "device not registered\n"); - return NULL; - } - - return mapping->gasket_dev; -} -EXPORT_SYMBOL(gasket_sysfs_get_device_data); - -void gasket_sysfs_put_device_data(struct device *device, struct gasket_dev *dev) -{ - struct gasket_sysfs_mapping *mapping = get_mapping(device); - - if (!mapping) - return; - - /* See comment of put_mapping_n() for why the '2' is necessary. */ - put_mapping_n(mapping, 2); -} -EXPORT_SYMBOL(gasket_sysfs_put_device_data); - -struct gasket_sysfs_attribute * -gasket_sysfs_get_attr(struct device *device, struct device_attribute *attr) -{ - int i; - int num_attrs; - struct gasket_sysfs_mapping *mapping = get_mapping(device); - struct gasket_sysfs_attribute *attrs = NULL; - - if (!mapping) - return NULL; - - attrs = mapping->attributes; - num_attrs = mapping->attribute_count; - for (i = 0; i < num_attrs; ++i) { - if (!strcmp(attrs[i].attr.attr.name, attr->attr.name)) - return &attrs[i]; - } - - dev_err(device, "Unable to find match for device_attribute %s\n", - attr->attr.name); - return NULL; -} -EXPORT_SYMBOL(gasket_sysfs_get_attr); - -void gasket_sysfs_put_attr(struct device *device, - struct gasket_sysfs_attribute *attr) -{ - int i; - int num_attrs; - struct gasket_sysfs_mapping *mapping = get_mapping(device); - struct gasket_sysfs_attribute *attrs = NULL; - - if (!mapping) - return; - - attrs = mapping->attributes; - num_attrs = mapping->attribute_count; - for (i = 0; i < num_attrs; ++i) { - if (&attrs[i] == attr) { - put_mapping_n(mapping, 2); - return; - } - } - - dev_err(device, "Unable to put unknown attribute: %s\n", - attr->attr.attr.name); - put_mapping(mapping); -} -EXPORT_SYMBOL(gasket_sysfs_put_attr); - -ssize_t gasket_sysfs_register_store(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) -{ - ulong parsed_value = 0; - struct gasket_sysfs_mapping *mapping; - struct gasket_dev *gasket_dev; - struct gasket_sysfs_attribute *gasket_attr; - - if (count < 3 || buf[0] != '0' || buf[1] != 'x') { - dev_err(device, - "sysfs register write format: \"0x<hex value>\"\n"); - return -EINVAL; - } - - if (kstrtoul(buf, 16, &parsed_value) != 0) { - dev_err(device, - "Unable to parse input as 64-bit hex value: %s\n", buf); - return -EINVAL; - } - - mapping = get_mapping(device); - if (!mapping) { - dev_err(device, "Device driver may have been removed\n"); - return 0; - } - - gasket_dev = mapping->gasket_dev; - if (!gasket_dev) { - dev_err(device, "Device driver may have been removed\n"); - put_mapping(mapping); - return 0; - } - - gasket_attr = gasket_sysfs_get_attr(device, attr); - if (!gasket_attr) { - put_mapping(mapping); - return count; - } - - gasket_dev_write_64(gasket_dev, parsed_value, - gasket_attr->data.bar_address.bar, - gasket_attr->data.bar_address.offset); - - if (gasket_attr->write_callback) - gasket_attr->write_callback(gasket_dev, gasket_attr, - parsed_value); - - gasket_sysfs_put_attr(device, gasket_attr); - put_mapping(mapping); - return count; -} -EXPORT_SYMBOL(gasket_sysfs_register_store); diff --git a/drivers/staging/gasket/gasket_sysfs.h b/drivers/staging/gasket/gasket_sysfs.h deleted file mode 100644 index d5e167dfbe76013e1baafc443c2ab301859cd99f..0000000000000000000000000000000000000000 --- a/drivers/staging/gasket/gasket_sysfs.h +++ /dev/null @@ -1,175 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Set of common sysfs utilities. - * - * Copyright (C) 2018 Google, Inc. - */ - -/* The functions described here are a set of utilities to allow each file in the - * Gasket driver framework to manage their own set of sysfs entries, instead of - * centralizing all that work in one file. - * - * The goal of these utilities is to allow for sysfs entries to be easily - * created without causing a proliferation of sysfs "show" functions. This - * requires O(N) string lookups during show function execution, but as reading - * sysfs entries is rarely performance-critical, this is likely acceptible. - */ -#ifndef __GASKET_SYSFS_H__ -#define __GASKET_SYSFS_H__ - -#include "gasket_constants.h" -#include "gasket_core.h" -#include <linux/device.h> -#include <linux/stringify.h> -#include <linux/sysfs.h> - -/* The maximum number of mappings/devices a driver needs to support. */ -#define GASKET_SYSFS_NUM_MAPPINGS (GASKET_FRAMEWORK_DESC_MAX * GASKET_DEV_MAX) - -/* The maximum number of sysfs nodes in a directory. - */ -#define GASKET_SYSFS_MAX_NODES 196 - -/* - * Terminator struct for a gasket_sysfs_attr array. Must be at the end of - * all gasket_sysfs_attribute arrays. - */ -#define GASKET_END_OF_ATTR_ARRAY \ - { \ - .attr = __ATTR_NULL, \ - .data.attr_type = 0, \ - } - -/* - * Pairing of sysfs attribute and user data. - * Used in lookups in sysfs "show" functions to return attribute metadata. - */ -struct gasket_sysfs_attribute { - /* The underlying sysfs device attribute associated with this data. */ - struct device_attribute attr; - - /* User-specified data to associate with the attribute. */ - union { - struct bar_address_ { - ulong bar; - ulong offset; - } bar_address; - uint attr_type; - } data; - - /* - * Function pointer to a callback to be invoked when this attribute is - * written (if so configured). The arguments are to the Gasket device - * pointer, the enclosing gasket_attr structure, and the value written. - * The callback should perform any logging necessary, as errors cannot - * be returned from the callback. - */ - void (*write_callback)(struct gasket_dev *dev, - struct gasket_sysfs_attribute *attr, - ulong value); -}; - -#define GASKET_SYSFS_RO(_name, _show_function, _attr_type) \ - { \ - .attr = __ATTR(_name, 0444, _show_function, NULL), \ - .data.attr_type = _attr_type \ - } - -/* Initializes the Gasket sysfs subsystem. - * - * Description: Performs one-time initialization. Must be called before usage - * at [Gasket] module load time. - */ -void gasket_sysfs_init(void); - -/* - * Create an entry in mapping_data between a device and a Gasket device. - * @device: Device struct to map to. - * @gasket_dev: The dev struct associated with the driver controlling @device. - * - * Description: This function maps a gasket_dev* to a device*. This mapping can - * be used in sysfs_show functions to get a handle to the gasket_dev struct - * controlling the device node. - * - * If this function is not called before gasket_sysfs_create_entries, a warning - * will be logged. - */ -int gasket_sysfs_create_mapping(struct device *device, - struct gasket_dev *gasket_dev); - -/* - * Creates bulk entries in sysfs. - * @device: Kernel device structure. - * @attrs: List of attributes/sysfs entries to create. - * - * Description: Creates each sysfs entry described in "attrs". Can be called - * multiple times for a given @device. If the gasket_dev specified in - * gasket_sysfs_create_mapping had a legacy device, the entries will be created - * for it, as well. - */ -int gasket_sysfs_create_entries(struct device *device, - const struct gasket_sysfs_attribute *attrs); - -/* - * Removes a device mapping from the global table. - * @device: Device to unmap. - * - * Description: Removes the device->Gasket device mapping from the internal - * table. - */ -void gasket_sysfs_remove_mapping(struct device *device); - -/* - * User data lookup based on kernel device structure. - * @device: Kernel device structure. - * - * Description: Returns the user data associated with "device" in a prior call - * to gasket_sysfs_create_entries. Returns NULL if no mapping can be found. - * Upon success, this call take a reference to internal sysfs data that must be - * released with gasket_sysfs_put_device_data. While this reference is held, the - * underlying device sysfs information/structure will remain valid/will not be - * deleted. - */ -struct gasket_dev *gasket_sysfs_get_device_data(struct device *device); - -/* - * Releases a references to internal data. - * @device: Kernel device structure. - * @dev: Gasket device descriptor (returned by gasket_sysfs_get_device_data). - */ -void gasket_sysfs_put_device_data(struct device *device, - struct gasket_dev *gasket_dev); - -/* - * Gasket-specific attribute lookup. - * @device: Kernel device structure. - * @attr: Device attribute to look up. - * - * Returns the Gasket sysfs attribute associated with the kernel device - * attribute and device structure itself. Upon success, this call will take a - * reference to internal sysfs data that must be released with a call to - * gasket_sysfs_put_attr. While this reference is held, the underlying device - * sysfs information/structure will remain valid/will not be deleted. - */ -struct gasket_sysfs_attribute * -gasket_sysfs_get_attr(struct device *device, struct device_attribute *attr); - -/* - * Releases a references to internal data. - * @device: Kernel device structure. - * @attr: Gasket sysfs attribute descriptor (returned by - * gasket_sysfs_get_attr). - */ -void gasket_sysfs_put_attr(struct device *device, - struct gasket_sysfs_attribute *attr); - -/* - * Write to a register sysfs node. - * @buf: NULL-terminated data being written. - * @count: number of bytes in the "buf" argument. - */ -ssize_t gasket_sysfs_register_store(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count); - -#endif /* __GASKET_SYSFS_H__ */ diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index 6e813693a76692d4355bded902c07f014da7ff29..0ccc8c24e754432f24121bc4663edd8bc7b16086 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -188,7 +188,7 @@ static int gdm_tty_write_room(struct tty_struct *tty) struct gdm *gdm = tty->driver_data; if (!GDM_TTY_READY(gdm)) - return -ENODEV; + return 0; return WRITE_SIZE; } diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index eebf0deb39f50d2315fa118d44edaea94f12e8df..e374dfc0c92fd69cd19b6812331a53143b7288e6 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -77,9 +77,8 @@ static void arche_platform_set_state(struct arche_platform_drvdata *arche_pdata, } /* Requires arche_pdata->wake_lock is held by calling context */ -static void arche_platform_set_wake_detect_state( - struct arche_platform_drvdata *arche_pdata, - enum svc_wakedetect_state state) +static void arche_platform_set_wake_detect_state(struct arche_platform_drvdata *arche_pdata, + enum svc_wakedetect_state state) { arche_pdata->wake_detect_state = state; } @@ -181,9 +180,8 @@ static irqreturn_t arche_platform_wd_irq(int irq, void *devid) WD_STATE_COLDBOOT_START) { arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_COLDBOOT_TRIG); - spin_unlock_irqrestore( - &arche_pdata->wake_lock, - flags); + spin_unlock_irqrestore(&arche_pdata->wake_lock, + flags); return IRQ_WAKE_THREAD; } } diff --git a/drivers/staging/greybus/audio_module.c b/drivers/staging/greybus/audio_module.c index 0f9fdc077b4cfde65af19341eb859f914389d2aa..12c376c477b3c59d9336801692b0af9c3fd973a0 100644 --- a/drivers/staging/greybus/audio_module.c +++ b/drivers/staging/greybus/audio_module.c @@ -260,7 +260,7 @@ static int gb_audio_probe(struct gb_bundle *bundle, INIT_LIST_HEAD(&gbmodule->widget_ctl_list); INIT_LIST_HEAD(&gbmodule->jack_list); gbmodule->dev = dev; - snprintf(gbmodule->name, NAME_SIZE, "%s.%s", dev->driver->name, + snprintf(gbmodule->name, sizeof(gbmodule->name), "%s.%s", dev->driver->name, dev_name(dev)); greybus_set_drvdata(bundle, gbmodule); @@ -342,7 +342,7 @@ static int gb_audio_probe(struct gb_bundle *bundle, /* inform above layer for uevent */ dev_dbg(dev, "Inform set_event:%d to above layer\n", 1); /* prepare for the audio manager */ - strscpy(desc.name, gbmodule->name, GB_AUDIO_MANAGER_MODULE_NAME_LEN); + strscpy(desc.name, gbmodule->name, sizeof(desc.name)); desc.vid = 2; /* todo */ desc.pid = 3; /* todo */ desc.intf_id = gbmodule->dev_id; diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c index e816e4db555ea60955ba68552cb315042bc148d0..1fc7727ab7be188bdb1fb0b07cb9bbb36d4e61bc 100644 --- a/drivers/staging/greybus/audio_topology.c +++ b/drivers/staging/greybus/audio_topology.c @@ -200,7 +200,7 @@ static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol, return -EINVAL; name = gbaudio_map_controlid(module, data->ctl_id, uinfo->value.enumerated.item); - strscpy(uinfo->value.enumerated.name, name, NAME_SIZE); + strscpy(uinfo->value.enumerated.name, name, sizeof(uinfo->value.enumerated.name)); break; default: dev_err(comp->dev, "Invalid type: %d for %s:kcontrol\n", @@ -363,7 +363,7 @@ static int gbcodec_mixer_dapm_ctl_info(struct snd_kcontrol *kcontrol, platform_min = le32_to_cpu(info->value.integer.min); if (platform_max == 1 && - !strnstr(kcontrol->id.name, " Volume", NAME_SIZE)) + !strnstr(kcontrol->id.name, " Volume", sizeof(kcontrol->id.name))) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -1047,8 +1047,8 @@ static int gbaudio_tplg_create_widget(struct gbaudio_module_info *module, } /* Prefix dev_id to widget control_name */ - strscpy(temp_name, w->name, NAME_SIZE); - snprintf(w->name, NAME_SIZE, "GB %d %s", module->dev_id, temp_name); + strscpy(temp_name, w->name, sizeof(temp_name)); + snprintf(w->name, sizeof(w->name), "GB %d %s", module->dev_id, temp_name); switch (w->type) { case snd_soc_dapm_spk: @@ -1169,8 +1169,8 @@ static int gbaudio_tplg_process_kcontrols(struct gbaudio_module_info *module, } control->id = curr->id; /* Prefix dev_id to widget_name */ - strscpy(temp_name, curr->name, NAME_SIZE); - snprintf(curr->name, NAME_SIZE, "GB %d %s", module->dev_id, + strscpy(temp_name, curr->name, sizeof(temp_name)); + snprintf(curr->name, sizeof(curr->name), "GB %d %s", module->dev_id, temp_name); control->name = curr->name; if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED) { diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index b570e13394ac3b14cf1c7f5750f3fc25919f35b7..cdbb42cd413baf14b433a6f75bd81165789d5987 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1120,16 +1120,9 @@ static ssize_t gb_camera_debugfs_write(struct file *file, if (len > 1024) return -EINVAL; - kbuf = kmalloc(len + 1, GFP_KERNEL); - if (!kbuf) - return -ENOMEM; - - if (copy_from_user(kbuf, buf, len)) { - ret = -EFAULT; - goto done; - } - - kbuf[len] = '\0'; + kbuf = memdup_user_nul(buf, len); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); ret = op->execute(gcam, kbuf, len); diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c index 0939f4a4c963b11a0ddd50d1d20f9682a3199147..37bf04c22dbccf1c9e2a8ccbc3900e1aaa7a1fb8 100644 --- a/drivers/staging/greybus/sdio.c +++ b/drivers/staging/greybus/sdio.c @@ -33,7 +33,6 @@ struct gb_sdio_host { bool read_only; }; - #define GB_SDIO_RSP_R1_R5_R6_R7 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \ GB_SDIO_RSP_OPCODE) #define GB_SDIO_RSP_R3_R4 (GB_SDIO_RSP_PRESENT) diff --git a/drivers/staging/greybus/spilib.c b/drivers/staging/greybus/spilib.c index 672d540d336553f7956a9cb5a44052484be48904..30655153df6ac73e3e82bf9053c0765b4c97afd3 100644 --- a/drivers/staging/greybus/spilib.c +++ b/drivers/staging/greybus/spilib.c @@ -245,6 +245,7 @@ static struct gb_operation *gb_spi_operation_create(struct gb_spilib *spi, /* Fill in the transfers array */ xfer = spi->first_xfer; while (msg->state != GB_SPI_STATE_OP_DONE) { + int xfer_delay; if (xfer == spi->last_xfer) xfer_len = spi->last_xfer_size; else @@ -259,7 +260,9 @@ static struct gb_operation *gb_spi_operation_create(struct gb_spilib *spi, gb_xfer->speed_hz = cpu_to_le32(xfer->speed_hz); gb_xfer->len = cpu_to_le32(xfer_len); - gb_xfer->delay_usecs = cpu_to_le16(xfer->delay_usecs); + xfer_delay = spi_delay_to_ns(&xfer->delay, xfer) / 1000; + xfer_delay = clamp_t(u16, xfer_delay, 0, U16_MAX); + gb_xfer->delay_usecs = cpu_to_le16(xfer_delay); gb_xfer->cs_change = xfer->cs_change; gb_xfer->bits_per_word = xfer->bits_per_word; diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 607378bfebb7ef5be2976bdaa671fcf24c76e9ec..b1e63f7798b02e7ef25a55194686bf6a7c7a7aae 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -610,14 +610,13 @@ static int get_serial_info(struct tty_struct *tty, { struct gb_tty *gb_tty = tty->driver_data; - ss->type = PORT_16550A; ss->line = gb_tty->minor; - ss->xmit_fifo_size = 16; - ss->baud_base = 9600; - ss->close_delay = gb_tty->port.close_delay / 10; + 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 : gb_tty->port.closing_wait / 10; + ASYNC_CLOSING_WAIT_NONE : + jiffies_to_msecs(gb_tty->port.closing_wait) / 10; + return 0; } @@ -629,17 +628,16 @@ static int set_serial_info(struct tty_struct *tty, unsigned int close_delay; int retval = 0; - close_delay = ss->close_delay * 10; + close_delay = msecs_to_jiffies(ss->close_delay * 10); closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; + ASYNC_CLOSING_WAIT_NONE : + msecs_to_jiffies(ss->closing_wait * 10); mutex_lock(&gb_tty->port.mutex); if (!capable(CAP_SYS_ADMIN)) { if ((close_delay != gb_tty->port.close_delay) || (closing_wait != gb_tty->port.closing_wait)) retval = -EPERM; - else - retval = -EOPNOTSUPP; } else { gb_tty->port.close_delay = close_delay; gb_tty->port.closing_wait = closing_wait; diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig index 82bb4a22b286ff4e6abb7fc987d0e4d7cfd74637..c4dc1016edf22eba53ceb101e42897292a61c971 100644 --- a/drivers/staging/hikey9xx/Kconfig +++ b/drivers/staging/hikey9xx/Kconfig @@ -39,14 +39,3 @@ config MFD_HI6421_SPMI individual components like voltage regulators under corresponding menus in order to enable them. We communicate with the Hi6421v600 via a SPMI bus. - -# to be placed at drivers/regulator -config REGULATOR_HI6421V600 - tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" - depends on MFD_HI6421_SPMI && OF - depends on REGULATOR - select REGMAP - help - This driver provides support for the voltage regulators on - HiSilicon Hi6421v600 PMU / Codec IC. - This is used on Kirin 3670 boards, like HiKey 970. diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile index 1924fadac9520932f3c66aaafc6ce1bedb3676d7..9103735d837750c77b3b697f48d74d089397ec81 100644 --- a/drivers/staging/hikey9xx/Makefile +++ b/drivers/staging/hikey9xx/Makefile @@ -4,4 +4,3 @@ obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o -obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c index 4ebcfea9f3bf9a4f5ab14d340ae9e31d896b46b8..626140cb96f2c71f3b9aa485095b9c9f49f3576e 100644 --- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c +++ b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c @@ -48,9 +48,9 @@ enum hi6421_spmi_pmic_irq_list { /* * The IRQs are mapped as: * - * ====================== ============= ============ ===== - * IRQ MASK REGISTER IRQ REGISTER BIT - * ====================== ============= ============ ===== + * ====================== ============= ============ ===== + * IRQ MASK REGISTER IRQ REGISTER BIT + * ====================== ============= ============ ===== * OTMP 0x0202 0x212 bit 0 * VBUS_CONNECT 0x0202 0x212 bit 1 * VBUS_DISCONNECT 0x0202 0x212 bit 2 @@ -66,7 +66,7 @@ enum hi6421_spmi_pmic_irq_list { * SIM0_HPD_F 0x0203 0x213 bit 3 * SIM1_HPD_R 0x0203 0x213 bit 4 * SIM1_HPD_F 0x0203 0x213 bit 5 - * ====================== ============= ============ ===== + * ====================== ============= ============ ===== */ #define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202 #define SOC_PMIC_IRQ0_ADDR 0x0212 diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml index 21f68a9c2df156f9072f1196ebb92b7ce067e668..6b755039a74c3b78c65b5ac6f7c3cdbe7586fb78 100644 --- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml +++ b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml @@ -16,7 +16,11 @@ description: | The PMIC part is provided by drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. +allOf: + - $ref: spmi.yaml# + properties: + $nodename: pattern: "spmi@[0-9a-f]" @@ -26,13 +30,8 @@ properties: reg: maxItems: 1 - "#address-cells": - const: 2 - - "#size-cells": - const: 0 - spmi-channel: + $ref: /schemas/types.yaml#/definitions/uint32 description: | number of the Kirin 970 SPMI channel where the SPMI devices are connected. @@ -40,18 +39,16 @@ required: - compatible - reg - spmi-channel - - "#address-cells" - - "#size-cells" patternProperties: - "^pmic@[0-9a-f]$": + "@[0-9a-f]$": description: | PMIC properties, which are specific to the used SPMI PMIC device(s). When used in combination with HiSilicon 6421v600, the properties are documented at drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -63,7 +60,6 @@ examples: compatible = "hisilicon,kirin970-spmi-controller"; #address-cells = <2>; #size-cells = <0>; - status = "ok"; reg = <0x0 0xfff24000 0x0 0x1000>; spmi-channel = <2>; diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index 4d469016a13a53bc754c61b5bf42ca8434a60f28..0fa6a5500bdb10c59d4e09c0326be3e73d5e7b22 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -1,9 +1,5 @@ 2020-02-25 -ADI Drivers: -CC the device-drivers-devel@blackfin.uclinux.org mailing list when -e-mailing the normal IIO list (see below). - Contact: Jonathan Cameron <jic23@kernel.org>. Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/cdc/Kconfig b/drivers/staging/iio/cdc/Kconfig index e0a5ce66a9845c37aa5c2a938a1d13d2a9de4de3..a7386bbbcb79cbd9bcb50772b6f6df810949c3c1 100644 --- a/drivers/staging/iio/cdc/Kconfig +++ b/drivers/staging/iio/cdc/Kconfig @@ -4,16 +4,6 @@ # menu "Capacitance to digital converters" -config AD7150 - tristate "Analog Devices ad7150/1/6 capacitive sensor driver" - depends on I2C - help - Say yes here to build support for Analog Devices capacitive sensors. - (ad7150, ad7151, ad7156) Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad7150. - config AD7746 tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver" depends on I2C diff --git a/drivers/staging/iio/cdc/Makefile b/drivers/staging/iio/cdc/Makefile index ab8222579e7ec0d71014df6ca44d39f8306eebb7..afb7499a7090aea9e0111eb0e8afc51ebf54ce29 100644 --- a/drivers/staging/iio/cdc/Makefile +++ b/drivers/staging/iio/cdc/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # -# Makefile for industrial I/O DAC drivers +# Makefile for industrial I/O CDC drivers # -obj-$(CONFIG_AD7150) += ad7150.o obj-$(CONFIG_AD7746) += ad7746.o diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c deleted file mode 100644 index 48132ab157ef80686aac6045ae22a04765a0da37..0000000000000000000000000000000000000000 --- a/drivers/staging/iio/cdc/ad7150.c +++ /dev/null @@ -1,655 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * AD7150 capacitive sensor driver supporting AD7150/1/6 - * - * Copyright 2010-2011 Analog Devices Inc. - */ - -#include <linux/bitfield.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -/* - * AD7150 registers definition - */ - -#define AD7150_STATUS 0 -#define AD7150_STATUS_OUT1 BIT(3) -#define AD7150_STATUS_OUT2 BIT(5) -#define AD7150_CH1_DATA_HIGH 1 -#define AD7150_CH2_DATA_HIGH 3 -#define AD7150_CH1_AVG_HIGH 5 -#define AD7150_CH2_AVG_HIGH 7 -#define AD7150_CH1_SENSITIVITY 9 -#define AD7150_CH1_THR_HOLD_H 9 -#define AD7150_CH1_TIMEOUT 10 -#define AD7150_CH1_SETUP 11 -#define AD7150_CH2_SENSITIVITY 12 -#define AD7150_CH2_THR_HOLD_H 12 -#define AD7150_CH2_TIMEOUT 13 -#define AD7150_CH2_SETUP 14 -#define AD7150_CFG 15 -#define AD7150_CFG_FIX BIT(7) -#define AD7150_PD_TIMER 16 -#define AD7150_CH1_CAPDAC 17 -#define AD7150_CH2_CAPDAC 18 -#define AD7150_SN3 19 -#define AD7150_SN2 20 -#define AD7150_SN1 21 -#define AD7150_SN0 22 -#define AD7150_ID 23 - -/* AD7150 masks */ -#define AD7150_THRESHTYPE_MSK GENMASK(6, 5) - -/** - * struct ad7150_chip_info - instance specific chip data - * @client: i2c client for this device - * @current_event: device always has one type of event enabled. - * This element stores the event code of the current one. - * @threshold: thresholds for simple capacitance value events - * @thresh_sensitivity: threshold for simple capacitance offset - * from 'average' value. - * @mag_sensitity: threshold for magnitude of capacitance offset from - * from 'average' value. - * @thresh_timeout: a timeout, in samples from the moment an - * adaptive threshold event occurs to when the average - * value jumps to current value. - * @mag_timeout: a timeout, in sample from the moment an - * adaptive magnitude event occurs to when the average - * value jumps to the current value. - * @old_state: store state from previous event, allowing confirmation - * of new condition. - * @conversion_mode: the current conversion mode. - * @state_lock: ensure consistent state of this structure wrt the - * hardware. - */ -struct ad7150_chip_info { - struct i2c_client *client; - u64 current_event; - u16 threshold[2][2]; - u8 thresh_sensitivity[2][2]; - u8 mag_sensitivity[2][2]; - u8 thresh_timeout[2][2]; - u8 mag_timeout[2][2]; - int old_state; - char *conversion_mode; - struct mutex state_lock; -}; - -/* - * sysfs nodes - */ - -static const u8 ad7150_addresses[][6] = { - { AD7150_CH1_DATA_HIGH, AD7150_CH1_AVG_HIGH, - AD7150_CH1_SETUP, AD7150_CH1_THR_HOLD_H, - AD7150_CH1_SENSITIVITY, AD7150_CH1_TIMEOUT }, - { AD7150_CH2_DATA_HIGH, AD7150_CH2_AVG_HIGH, - AD7150_CH2_SETUP, AD7150_CH2_THR_HOLD_H, - AD7150_CH2_SENSITIVITY, AD7150_CH2_TIMEOUT }, -}; - -static int ad7150_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - int ret; - struct ad7150_chip_info *chip = iio_priv(indio_dev); - int channel = chan->channel; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = i2c_smbus_read_word_data(chip->client, - ad7150_addresses[channel][0]); - if (ret < 0) - return ret; - *val = swab16(ret); - return IIO_VAL_INT; - case IIO_CHAN_INFO_AVERAGE_RAW: - ret = i2c_smbus_read_word_data(chip->client, - ad7150_addresses[channel][1]); - if (ret < 0) - return ret; - *val = swab16(ret); - return IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static int ad7150_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - int ret; - u8 threshtype; - bool thrfixed; - struct ad7150_chip_info *chip = iio_priv(indio_dev); - - ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG); - if (ret < 0) - return ret; - - threshtype = FIELD_GET(AD7150_THRESHTYPE_MSK, ret); - - /*check if threshold mode is fixed or adaptive*/ - thrfixed = FIELD_GET(AD7150_CFG_FIX, ret); - - switch (type) { - case IIO_EV_TYPE_MAG_ADAPTIVE: - if (dir == IIO_EV_DIR_RISING) - return !thrfixed && (threshtype == 0x1); - return !thrfixed && (threshtype == 0x0); - case IIO_EV_TYPE_THRESH_ADAPTIVE: - if (dir == IIO_EV_DIR_RISING) - return !thrfixed && (threshtype == 0x3); - return !thrfixed && (threshtype == 0x2); - case IIO_EV_TYPE_THRESH: - if (dir == IIO_EV_DIR_RISING) - return thrfixed && (threshtype == 0x1); - return thrfixed && (threshtype == 0x0); - default: - break; - } - return -EINVAL; -} - -/* state_lock should be held to ensure consistent state*/ - -static int ad7150_write_event_params(struct iio_dev *indio_dev, - unsigned int chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - int ret; - u16 value; - u8 sens, timeout; - struct ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = (dir == IIO_EV_DIR_RISING); - u64 event_code; - - event_code = IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, chan, type, dir); - - if (event_code != chip->current_event) - return 0; - - switch (type) { - /* Note completely different from the adaptive versions */ - case IIO_EV_TYPE_THRESH: - value = chip->threshold[rising][chan]; - return i2c_smbus_write_word_data(chip->client, - ad7150_addresses[chan][3], - swab16(value)); - case IIO_EV_TYPE_MAG_ADAPTIVE: - sens = chip->mag_sensitivity[rising][chan]; - timeout = chip->mag_timeout[rising][chan]; - break; - case IIO_EV_TYPE_THRESH_ADAPTIVE: - sens = chip->thresh_sensitivity[rising][chan]; - timeout = chip->thresh_timeout[rising][chan]; - break; - default: - return -EINVAL; - } - ret = i2c_smbus_write_byte_data(chip->client, - ad7150_addresses[chan][4], - sens); - if (ret) - return ret; - return i2c_smbus_write_byte_data(chip->client, - ad7150_addresses[chan][5], - timeout); -} - -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) -{ - u8 thresh_type, cfg, adaptive; - int ret; - struct ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = (dir == IIO_EV_DIR_RISING); - u64 event_code; - - /* Something must always be turned on */ - if (!state) - return -EINVAL; - - event_code = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, type, dir); - if (event_code == chip->current_event) - return 0; - mutex_lock(&chip->state_lock); - ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG); - if (ret < 0) - goto error_ret; - - cfg = ret & ~((0x03 << 5) | BIT(7)); - - switch (type) { - case IIO_EV_TYPE_MAG_ADAPTIVE: - adaptive = 1; - if (rising) - thresh_type = 0x1; - else - thresh_type = 0x0; - break; - case IIO_EV_TYPE_THRESH_ADAPTIVE: - adaptive = 1; - if (rising) - thresh_type = 0x3; - else - thresh_type = 0x2; - break; - case IIO_EV_TYPE_THRESH: - adaptive = 0; - if (rising) - thresh_type = 0x1; - else - thresh_type = 0x0; - break; - default: - ret = -EINVAL; - goto error_ret; - } - - cfg |= (!adaptive << 7) | (thresh_type << 5); - - ret = i2c_smbus_write_byte_data(chip->client, AD7150_CFG, cfg); - if (ret < 0) - goto error_ret; - - chip->current_event = event_code; - - /* update control attributes */ - ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir); -error_ret: - mutex_unlock(&chip->state_lock); - - return ret; -} - -static int ad7150_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 ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = (dir == IIO_EV_DIR_RISING); - - /* Complex register sharing going on here */ - switch (type) { - case IIO_EV_TYPE_MAG_ADAPTIVE: - *val = chip->mag_sensitivity[rising][chan->channel]; - return IIO_VAL_INT; - case IIO_EV_TYPE_THRESH_ADAPTIVE: - *val = chip->thresh_sensitivity[rising][chan->channel]; - return IIO_VAL_INT; - case IIO_EV_TYPE_THRESH: - *val = chip->threshold[rising][chan->channel]; - return IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static int ad7150_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) -{ - int ret; - struct ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = (dir == IIO_EV_DIR_RISING); - - mutex_lock(&chip->state_lock); - switch (type) { - case IIO_EV_TYPE_MAG_ADAPTIVE: - chip->mag_sensitivity[rising][chan->channel] = val; - break; - case IIO_EV_TYPE_THRESH_ADAPTIVE: - chip->thresh_sensitivity[rising][chan->channel] = val; - break; - case IIO_EV_TYPE_THRESH: - chip->threshold[rising][chan->channel] = val; - break; - default: - ret = -EINVAL; - goto error_ret; - } - - /* write back if active */ - ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir); - -error_ret: - mutex_unlock(&chip->state_lock); - return ret; -} - -static ssize_t ad7150_show_timeout(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7150_chip_info *chip = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u8 value; - - /* use the event code for consistency reasons */ - int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address); - int rising = (IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address) - == IIO_EV_DIR_RISING) ? 1 : 0; - - switch (IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address)) { - case IIO_EV_TYPE_MAG_ADAPTIVE: - value = chip->mag_timeout[rising][chan]; - break; - case IIO_EV_TYPE_THRESH_ADAPTIVE: - value = chip->thresh_timeout[rising][chan]; - break; - default: - return -EINVAL; - } - - return sprintf(buf, "%d\n", value); -} - -static ssize_t ad7150_store_timeout(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7150_chip_info *chip = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address); - enum iio_event_direction dir; - enum iio_event_type type; - int rising; - u8 data; - int ret; - - type = IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address); - dir = IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address); - rising = (dir == IIO_EV_DIR_RISING); - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; - - mutex_lock(&chip->state_lock); - switch (type) { - case IIO_EV_TYPE_MAG_ADAPTIVE: - chip->mag_timeout[rising][chan] = data; - break; - case IIO_EV_TYPE_THRESH_ADAPTIVE: - chip->thresh_timeout[rising][chan] = data; - break; - default: - ret = -EINVAL; - goto error_ret; - } - - ret = ad7150_write_event_params(indio_dev, chan, type, dir); -error_ret: - mutex_unlock(&chip->state_lock); - - if (ret < 0) - return ret; - - return len; -} - -#define AD7150_TIMEOUT(chan, type, dir, ev_type, ev_dir) \ - IIO_DEVICE_ATTR(in_capacitance##chan##_##type##_##dir##_timeout, \ - 0644, \ - &ad7150_show_timeout, \ - &ad7150_store_timeout, \ - IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, \ - chan, \ - IIO_EV_TYPE_##ev_type, \ - IIO_EV_DIR_##ev_dir)) -static AD7150_TIMEOUT(0, mag_adaptive, rising, MAG_ADAPTIVE, RISING); -static AD7150_TIMEOUT(0, mag_adaptive, falling, MAG_ADAPTIVE, FALLING); -static AD7150_TIMEOUT(1, mag_adaptive, rising, MAG_ADAPTIVE, RISING); -static AD7150_TIMEOUT(1, mag_adaptive, falling, MAG_ADAPTIVE, FALLING); -static AD7150_TIMEOUT(0, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING); -static AD7150_TIMEOUT(0, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); -static AD7150_TIMEOUT(1, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING); -static AD7150_TIMEOUT(1, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); - -static const struct iio_event_spec ad7150_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), - }, { - .type = IIO_EV_TYPE_THRESH_ADAPTIVE, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_THRESH_ADAPTIVE, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_MAG_ADAPTIVE, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_MAG_ADAPTIVE, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, -}; - -#define AD7150_CAPACITANCE_CHAN(_chan) { \ - .type = IIO_CAPACITANCE, \ - .indexed = 1, \ - .channel = _chan, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ - .event_spec = ad7150_events, \ - .num_event_specs = ARRAY_SIZE(ad7150_events), \ - } - -static const struct iio_chan_spec ad7150_channels[] = { - AD7150_CAPACITANCE_CHAN(0), - AD7150_CAPACITANCE_CHAN(1) -}; - -static irqreturn_t ad7150_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct ad7150_chip_info *chip = iio_priv(indio_dev); - u8 int_status; - s64 timestamp = iio_get_time_ns(indio_dev); - int ret; - - ret = i2c_smbus_read_byte_data(chip->client, AD7150_STATUS); - if (ret < 0) - return IRQ_HANDLED; - - int_status = ret; - - if ((int_status & AD7150_STATUS_OUT1) && - !(chip->old_state & AD7150_STATUS_OUT1)) - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - timestamp); - else if ((!(int_status & AD7150_STATUS_OUT1)) && - (chip->old_state & AD7150_STATUS_OUT1)) - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - timestamp); - - if ((int_status & AD7150_STATUS_OUT2) && - !(chip->old_state & AD7150_STATUS_OUT2)) - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, - 1, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - timestamp); - else if ((!(int_status & AD7150_STATUS_OUT2)) && - (chip->old_state & AD7150_STATUS_OUT2)) - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, - 1, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - timestamp); - /* store the status to avoid repushing same events */ - chip->old_state = int_status; - - return IRQ_HANDLED; -} - -/* Timeouts not currently handled by core */ -static struct attribute *ad7150_event_attributes[] = { - &iio_dev_attr_in_capacitance0_mag_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance0_mag_adaptive_falling_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_mag_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_mag_adaptive_falling_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance0_thresh_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance0_thresh_adaptive_falling_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_thresh_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_thresh_adaptive_falling_timeout - .dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7150_event_attribute_group = { - .attrs = ad7150_event_attributes, - .name = "events", -}; - -static const struct iio_info ad7150_info = { - .event_attrs = &ad7150_event_attribute_group, - .read_raw = &ad7150_read_raw, - .read_event_config = &ad7150_read_event_config, - .write_event_config = &ad7150_write_event_config, - .read_event_value = &ad7150_read_event_value, - .write_event_value = &ad7150_write_event_value, -}; - -static int ad7150_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct ad7150_chip_info *chip; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); - if (!indio_dev) - return -ENOMEM; - chip = iio_priv(indio_dev); - mutex_init(&chip->state_lock); - /* this is only used for device removal purposes */ - i2c_set_clientdata(client, indio_dev); - - chip->client = client; - - indio_dev->name = id->name; - indio_dev->channels = ad7150_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7150_channels); - - indio_dev->info = &ad7150_info; - - indio_dev->modes = INDIO_DIRECT_MODE; - - if (client->irq) { - ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, - &ad7150_event_handler, - IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - "ad7150_irq1", - indio_dev); - if (ret) - return ret; - } - - if (client->dev.platform_data) { - ret = devm_request_threaded_irq(&client->dev, *(unsigned int *) - client->dev.platform_data, - NULL, - &ad7150_event_handler, - IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - "ad7150_irq2", - indio_dev); - if (ret) - return ret; - } - - ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev); - if (ret) - return ret; - - dev_info(&client->dev, "%s capacitive sensor registered,irq: %d\n", - id->name, client->irq); - - return 0; -} - -static const struct i2c_device_id ad7150_id[] = { - { "ad7150", 0 }, - { "ad7151", 0 }, - { "ad7156", 0 }, - {} -}; - -MODULE_DEVICE_TABLE(i2c, ad7150_id); - -static struct i2c_driver ad7150_driver = { - .driver = { - .name = "ad7150", - }, - .probe = ad7150_probe, - .id_table = ad7150_id, -}; -module_i2c_driver(ad7150_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices AD7150/1/6 capacitive sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index 447937e04ebdc55028d8064946af18bc5f26c4b8..3f1981e287f504f6f6212b5bbac86bdbd0d072e5 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -86,7 +86,7 @@ * @freq_msg: tuning word spi message * @phase_xfer: tuning word spi transfer * @phase_msg: tuning word spi message - * @lock protect sensor state + * @lock: protect sensor state * @data: spi transmit buffer * @phase_data: tuning word spi transmit buffer * @freq_data: tuning word spi transmit buffer @@ -248,7 +248,7 @@ error_ret: return ret ? ret : len; } -/** +/* * see dds.h for further information */ diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 262c3590e64e3db820cf18046a015093696b0516..60a3ae5587b9056043ba0d865520b0a34a8949c9 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -56,7 +56,6 @@ /** * struct ad9834_state - driver instance specific data * @spi: spi_device - * @reg: supply regulator * @mclk: external master clock * @control: cached control word * @xfer: default spi transfer @@ -70,7 +69,6 @@ struct ad9834_state { struct spi_device *spi; - struct regulator *reg; struct clk *mclk; unsigned short control; unsigned short devid; @@ -390,6 +388,20 @@ static const struct iio_info ad9833_info = { .attrs = &ad9833_attribute_group, }; +static void ad9834_disable_reg(void *data) +{ + struct regulator *reg = data; + + regulator_disable(reg); +} + +static void ad9834_disable_clk(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + static int ad9834_probe(struct spi_device *spi) { struct ad9834_state *st; @@ -407,29 +419,35 @@ static int ad9834_probe(struct spi_device *spi) return ret; } + ret = devm_add_action_or_reset(&spi->dev, ad9834_disable_reg, reg); + if (ret) + return ret; + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) { ret = -ENOMEM; - goto error_disable_reg; + return ret; } - spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); mutex_init(&st->lock); st->mclk = devm_clk_get(&spi->dev, NULL); if (IS_ERR(st->mclk)) { ret = PTR_ERR(st->mclk); - goto error_disable_reg; + return ret; } ret = clk_prepare_enable(st->mclk); if (ret) { dev_err(&spi->dev, "Failed to enable master clock\n"); - goto error_disable_reg; + return ret; } + ret = devm_add_action_or_reset(&spi->dev, ad9834_disable_clk, st->mclk); + if (ret) + return ret; + st->spi = spi; st->devid = spi_get_device_id(spi)->driver_data; - st->reg = reg; indio_dev->name = spi_get_device_id(spi)->name; switch (st->devid) { case ID_AD9833: @@ -470,48 +488,26 @@ static int ad9834_probe(struct spi_device *spi) ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); - goto error_clock_unprepare; + return ret; } ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, 1000000); if (ret) - goto error_clock_unprepare; + return ret; ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, 5000000); if (ret) - goto error_clock_unprepare; + return ret; ret = ad9834_write_phase(st, AD9834_REG_PHASE0, 512); if (ret) - goto error_clock_unprepare; + return ret; ret = ad9834_write_phase(st, AD9834_REG_PHASE1, 1024); if (ret) - goto error_clock_unprepare; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_clock_unprepare; - - return 0; -error_clock_unprepare: - clk_disable_unprepare(st->mclk); -error_disable_reg: - regulator_disable(reg); - - return ret; -} - -static int ad9834_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad9834_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - clk_disable_unprepare(st->mclk); - regulator_disable(st->reg); + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad9834_id[] = { @@ -539,7 +535,6 @@ static struct spi_driver ad9834_driver = { .of_match_table = ad9834_of_match }, .probe = ad9834_probe, - .remove = ad9834_remove, .id_table = ad9834_id, }; module_spi_driver(ad9834_driver); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index dba78896ea8f28506979ffa22afc1d38c5105bad..793918e1c45fa400ce3189ffb0b7b71079f0ea7a 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -602,23 +602,6 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = { .postdisable = ad5933_ring_postdisable, }; -static int ad5933_register_ring_funcs_and_init(struct device *dev, - struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer; - - buffer = devm_iio_kfifo_allocate(dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - - /* Ring buffer functions - here trigger setup related */ - indio_dev->setup_ops = &ad5933_ring_setup_ops; - - return 0; -} - static void ad5933_work(struct work_struct *work) { struct ad5933_state *st = container_of(work, @@ -761,11 +744,13 @@ static int ad5933_probe(struct i2c_client *client, indio_dev->info = &ad5933_info; indio_dev->name = id->name; - indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); + indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ad5933_channels; indio_dev->num_channels = ARRAY_SIZE(ad5933_channels); - ret = ad5933_register_ring_funcs_and_init(&client->dev, indio_dev); + ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &ad5933_ring_setup_ops); if (ret) return ret; diff --git a/drivers/staging/kpc2000/kpc2000/pcie.h b/drivers/staging/kpc2000/kpc2000/pcie.h index cb815c30faa41f84c10ef2e6582cf7716b3be62c..f1fc91b4c704cb51065be715c8abc32220d18c29 100644 --- a/drivers/staging/kpc2000/kpc2000/pcie.h +++ b/drivers/staging/kpc2000/kpc2000/pcie.h @@ -6,7 +6,6 @@ #include "../kpc.h" #include "dma_common_defs.h" - /* System Register Map (BAR 1, Start Addr 0) * * BAR Size: diff --git a/drivers/staging/kpc2000/kpc2000_i2c.c b/drivers/staging/kpc2000/kpc2000_i2c.c index 25bb5c97dd21a9c2b166b8b2afaf3f3ff51ce3d8..14f7940fa4fb5abffcccb2f5931709fef3e9c577 100644 --- a/drivers/staging/kpc2000/kpc2000_i2c.c +++ b/drivers/staging/kpc2000/kpc2000_i2c.c @@ -200,7 +200,9 @@ static int i801_check_post(struct kpc_i2c *priv, int status, int timeout) outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv)); status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; if (status) - dev_warn(&priv->adapter.dev, "Failed clearing status flags at end of transaction (%02x)\n", status); + dev_warn(&priv->adapter.dev, + "Failed clearing status flags at end of transaction (%02x)\n", + status); } return result; @@ -269,7 +271,7 @@ static int i801_block_transaction_by_block(struct kpc_i2c *priv, } status = i801_transaction(priv, - I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec); + I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec); if (status) return status; diff --git a/drivers/staging/kpc2000/kpc2000_spi.c b/drivers/staging/kpc2000/kpc2000_spi.c index 44017d523da5f3a8cb0375c23fe27c8ade142d4f..16ca18b8aa15929dc8f68369b02792f51e9b3e36 100644 --- a/drivers/staging/kpc2000/kpc2000_spi.c +++ b/drivers/staging/kpc2000/kpc2000_spi.c @@ -465,7 +465,7 @@ kp_spi_probe(struct platform_device *pldev) } kpspi->base = devm_ioremap(&pldev->dev, r->start, - resource_size(r)); + resource_size(r)); status = spi_register_master(master); if (status < 0) { diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 535e6dec3504d45402b404fe552570ee724feb3d..6f420cbcdcfff67f02db4a47e3d587dee8a22151 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -20,8 +20,6 @@ if MOST_COMPONENTS source "drivers/staging/most/net/Kconfig" -source "drivers/staging/most/sound/Kconfig" - source "drivers/staging/most/video/Kconfig" source "drivers/staging/most/dim2/Kconfig" diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index be94673209f5f3ee74d569d92b7c263374c5f2c7..8b3fc5a7af5148d520ae5cfb3a0e4bdbf14fe3c3 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_MOST_NET) += net/ -obj-$(CONFIG_MOST_SOUND) += sound/ obj-$(CONFIG_MOST_VIDEO) += video/ obj-$(CONFIG_MOST_DIM2) += dim2/ obj-$(CONFIG_MOST_I2C) += i2c/ diff --git a/drivers/staging/most/sound/Kconfig b/drivers/staging/most/sound/Kconfig deleted file mode 100644 index ad9f7821af7d70ae5953daef8b59e224435839ef..0000000000000000000000000000000000000000 --- a/drivers/staging/most/sound/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# MOST ALSA configuration -# - -config MOST_SOUND - tristate "Sound" - depends on SND - select SND_PCM - help - Say Y here if you want to commumicate via ALSA/sound devices. - - To compile this driver as a module, choose M here: the - module will be called most_sound. diff --git a/drivers/staging/most/sound/Makefile b/drivers/staging/most/sound/Makefile deleted file mode 100644 index f0cd9d8d213e21bbfa1b91ce1b4f954ce1aede72..0000000000000000000000000000000000000000 --- a/drivers/staging/most/sound/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MOST_SOUND) += most_sound.o - -most_sound-objs := sound.o diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index c3532bc138fba0f344c96c885d3f14132ea98350..115250115f1046f3252d2f75cd2a9f6fbae80d28 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -301,18 +301,19 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct pci_host_bridge *host) /* * IO_SPACE_LIMIT for MIPS is 0xffff but this platform uses IO at - * upper address 0x001e160000 so we have to get the resource from - * the DT because when it has been requested it failed and has been - * removed from bridge->dma_ranges and bridge->windows. So parse it - * and remap it manually to make things work. + * upper address 0x001e160000. of_pci_range_to_resource does not work + * well for MIPS platforms that don't define PCI_IOBASE, so set the IO + * resource manually instead. */ + pcie->io.name = node->full_name; + pcie->io.parent = pcie->io.child = pcie->io.sibling = NULL; for_each_of_pci_range(&parser, &range) { switch (range.flags & IORESOURCE_TYPE_BITS) { case IORESOURCE_IO: pcie->io_map_base = (unsigned long)ioremap(range.cpu_addr, range.size); - of_pci_range_to_resource(&range, node, &pcie->io); + pcie->io.flags = range.flags; pcie->io.start = range.cpu_addr; pcie->io.end = range.cpu_addr + range.size - 1; set_io_port_base(pcie->io_map_base); @@ -521,7 +522,6 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie) if (slot == 1 && tmp && !tmp->enabled) phy_power_off(tmp->phy); - } } } diff --git a/drivers/staging/netlogic/Kconfig b/drivers/staging/netlogic/Kconfig index b2a4d45866972d6dcdcf78fda992cb8b1294c43a..e1712606ee3ce07ebc5b029bab90ea947de5bfc0 100644 --- a/drivers/staging/netlogic/Kconfig +++ b/drivers/staging/netlogic/Kconfig @@ -2,6 +2,7 @@ config NETLOGIC_XLR_NET tristate "Netlogic XLR/XLS network device" depends on CPU_XLR + depends on NETDEVICES select PHYLIB help This driver support Netlogic XLR/XLS on chip gigabit diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c index 157009015c3b459e8f0a9ce6360f26b4c0b7880c..06041c7f7d4ff0d12d93e0fcd25443aa585f9bb6 100644 --- a/drivers/staging/nvec/nvec_ps2.c +++ b/drivers/staging/nvec/nvec_ps2.c @@ -28,7 +28,7 @@ print_hex_dump(KERN_DEBUG, str, DUMP_PREFIX_NONE, \ 16, 1, buf, len, false) #else -#define NVEC_PHD(str, buf, len) +#define NVEC_PHD(str, buf, len) do { } while (0) #endif enum ps2_subcmds { diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c index e2f8b6b67f75e29b49ab6efc3607b90fd0f188cc..f27f20a4aa2d2dd192d8534ee1a86ffeddeac17f 100644 --- a/drivers/staging/octeon-usb/octeon-hcd.c +++ b/drivers/staging/octeon-usb/octeon-hcd.c @@ -1258,7 +1258,7 @@ static void cvmx_usb_poll_tx_fifo(struct octeon_hcd *usb) union cvmx_usbcx_hptxsts tx_status; tx_status.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HPTXSTS(usb->index)); + CVMX_USBCX_HPTXSTS(usb->index)); if (cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail)) USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), @@ -1272,7 +1272,7 @@ static void cvmx_usb_poll_tx_fifo(struct octeon_hcd *usb) union cvmx_usbcx_gnptxsts tx_status; tx_status.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_GNPTXSTS(usb->index)); + CVMX_USBCX_GNPTXSTS(usb->index)); if (cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail)) USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), @@ -1298,13 +1298,13 @@ static void cvmx_usb_fill_tx_fifo(struct octeon_hcd *usb, int channel) /* We only need to fill data on outbound channels */ hcchar.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCCHARX(channel, usb->index)); + CVMX_USBCX_HCCHARX(channel, usb->index)); if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT) return; /* OUT Splits only have data on the start and not the complete */ usbc_hcsplt.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCSPLTX(channel, usb->index)); + CVMX_USBCX_HCSPLTX(channel, usb->index)); if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt) return; @@ -1313,7 +1313,7 @@ static void cvmx_usb_fill_tx_fifo(struct octeon_hcd *usb, int channel) * words. */ usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCTSIZX(channel, usb->index)); + CVMX_USBCX_HCTSIZX(channel, usb->index)); if (!usbc_hctsiz.s.xfersize) return; @@ -1360,7 +1360,7 @@ static void cvmx_usb_start_channel_control(struct octeon_hcd *usb, union cvmx_usbcx_hctsizx usbc_hctsiz; usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCTSIZX(channel, usb->index)); + CVMX_USBCX_HCTSIZX(channel, usb->index)); switch (transaction->stage) { case CVMX_USB_STAGE_NON_CONTROL: @@ -1517,7 +1517,7 @@ static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel, /* Clear all channel status bits */ usbc_hcint.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCINTX(channel, usb->index)); + CVMX_USBCX_HCINTX(channel, usb->index)); cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), @@ -1552,7 +1552,7 @@ static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel, /* Enable the channel interrupt to propagate */ usbc_haintmsk.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HAINTMSK(usb->index)); + CVMX_USBCX_HAINTMSK(usb->index)); usbc_haintmsk.s.haintmsk |= 1 << channel; cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32); @@ -1836,7 +1836,7 @@ static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel, * Returns: Pipe or NULL if none are ready */ static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(struct octeon_hcd *usb, - enum cvmx_usb_transfer xfer_type) + enum cvmx_usb_transfer xfer_type) { struct list_head *list = usb->active_pipes + xfer_type; u64 current_frame = usb->frame_number; @@ -2309,7 +2309,8 @@ static int cvmx_usb_cancel(struct octeon_hcd *usb, CVMX_SYNCW; usbc_hcchar.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCCHARX(pipe->channel, usb->index)); + CVMX_USBCX_HCCHARX(pipe->channel, + usb->index)); /* * If the channel isn't enabled then the transaction already * completed. @@ -2605,11 +2606,12 @@ static int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel) /* Read the interrupt status bits for the channel */ usbc_hcint.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCINTX(channel, usb->index)); + CVMX_USBCX_HCINTX(channel, usb->index)); if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { usbc_hcchar.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCCHARX(channel, usb->index)); + CVMX_USBCX_HCCHARX(channel, + usb->index)); if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) { /* @@ -2688,9 +2690,9 @@ static int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel) * transferred */ usbc_hcchar.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCCHARX(channel, usb->index)); + CVMX_USBCX_HCCHARX(channel, usb->index)); usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HCTSIZX(channel, usb->index)); + CVMX_USBCX_HCTSIZX(channel, usb->index)); /* * Calculating the number of bytes successfully transferred is dependent @@ -3010,7 +3012,7 @@ static int cvmx_usb_poll(struct octeon_hcd *usb) union cvmx_usbcx_haint usbc_haint; usbc_haint.u32 = cvmx_usb_read_csr32(usb, - CVMX_USBCX_HAINT(usb->index)); + CVMX_USBCX_HAINT(usb->index)); while (usbc_haint.u32) { int channel; diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c index c582403e6a1f5338a61dd19363887aaba1d48ca2..699c98c5ec13bd1f188dcc8c6f41ac686fc4fc24 100644 --- a/drivers/staging/octeon/ethernet-spi.c +++ b/drivers/staging/octeon/ethernet-spi.c @@ -202,7 +202,7 @@ int cvm_oct_spi_init(struct net_device *dev) } number_spi_ports++; - if ((priv->port == 0) || (priv->port == 16)) { + if (priv->port == 0 || priv->port == 16) { cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port)); priv->poll = cvm_oct_spi_poll; } diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 5dea6e96ec901806beecb1df1931f669e642b247..7c60b0cd8bf7e21eeb0925a5df66aec14475e185 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -614,14 +614,11 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = { static struct device_node *cvm_oct_of_get_child (const struct device_node *parent, int reg_val) { - struct device_node *node = NULL; - int size; + struct device_node *node; const __be32 *addr; + int size; - for (;;) { - node = of_get_next_child(parent, node); - if (!node) - break; + for_each_child_of_node(parent, node) { addr = of_get_property(node, "reg", &size); if (addr && (be32_to_cpu(*addr) == reg_val)) break; diff --git a/drivers/staging/qlge/qlge_devlink.c b/drivers/staging/qlge/qlge_devlink.c index 86834d96cebf39610b28bd442788badaf04db7ce..0ab02d6d3817b77c71e2e7444bbf06a630ae4515 100644 --- a/drivers/staging/qlge/qlge_devlink.c +++ b/drivers/staging/qlge/qlge_devlink.c @@ -148,16 +148,20 @@ static const struct devlink_health_reporter_ops qlge_reporter_ops = { .dump = qlge_reporter_coredump, }; -void qlge_health_create_reporters(struct qlge_adapter *priv) +long qlge_health_create_reporters(struct qlge_adapter *priv) { struct devlink *devlink; + long err = 0; devlink = priv_to_devlink(priv); priv->reporter = devlink_health_reporter_create(devlink, &qlge_reporter_ops, 0, priv); - if (IS_ERR(priv->reporter)) + if (IS_ERR(priv->reporter)) { + err = PTR_ERR(priv->reporter); netdev_warn(priv->ndev, "Failed to create reporter, err = %ld\n", - PTR_ERR(priv->reporter)); + err); + } + return err; } diff --git a/drivers/staging/qlge/qlge_devlink.h b/drivers/staging/qlge/qlge_devlink.h index 19078e1ac6944f569c2a15e7443041d32290c37d..94538e923f2fb0fb006da04b5f35c145f88c91e9 100644 --- a/drivers/staging/qlge/qlge_devlink.h +++ b/drivers/staging/qlge/qlge_devlink.h @@ -4,6 +4,6 @@ #include <net/devlink.h> -void qlge_health_create_reporters(struct qlge_adapter *priv); +long qlge_health_create_reporters(struct qlge_adapter *priv); #endif /* QLGE_DEVLINK_H */ diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 5516be3af8983d93cd3d613ee5bc445ab84923ca..c9dc6a852af4aac0ba42b1987c62d1c3025a829b 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -3815,8 +3815,7 @@ static int qlge_adapter_down(struct qlge_adapter *qdev) qlge_tx_ring_clean(qdev); - /* Call netif_napi_del() from common point. - */ + /* Call netif_napi_del() from common point. */ for (i = 0; i < qdev->rss_ring_count; i++) netif_napi_del(&qdev->rx_ring[i].napi); @@ -4550,7 +4549,7 @@ static int qlge_probe(struct pci_dev *pdev, struct net_device *ndev = NULL; struct devlink *devlink; static int cards_found; - int err = 0; + int err; devlink = devlink_alloc(&qlge_devlink_ops, sizeof(struct qlge_adapter)); if (!devlink) @@ -4561,8 +4560,10 @@ static int qlge_probe(struct pci_dev *pdev, ndev = alloc_etherdev_mq(sizeof(struct qlge_netdev_priv), min(MAX_CPUS, netif_get_num_default_rss_queues())); - if (!ndev) + if (!ndev) { + err = -ENOMEM; goto devlink_free; + } ndev_priv = netdev_priv(ndev); ndev_priv->qdev = qdev; @@ -4620,7 +4621,11 @@ static int qlge_probe(struct pci_dev *pdev, if (err) goto netdev_free; - qlge_health_create_reporters(qdev); + err = qlge_health_create_reporters(qdev); + + if (err) + goto devlink_unregister; + /* Start up the timer to trigger EEH if * the bus goes dead */ @@ -4632,6 +4637,8 @@ static int qlge_probe(struct pci_dev *pdev, cards_found++; return 0; +devlink_unregister: + devlink_unregister(devlink); netdev_free: free_netdev(ndev); devlink_free: diff --git a/drivers/staging/ralink-gdma/ralink-gdma.c b/drivers/staging/ralink-gdma/ralink-gdma.c index 655df317d0ee338b3861adc5b122559f968538b7..33e28ccf4d855adc1856d00b5e7e990f774f3a01 100644 --- a/drivers/staging/ralink-gdma/ralink-gdma.c +++ b/drivers/staging/ralink-gdma/ralink-gdma.c @@ -788,6 +788,7 @@ static const struct of_device_id gdma_of_match_table[] = { { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data }, { }, }; +MODULE_DEVICE_TABLE(of, gdma_of_match_table); static int gdma_dma_probe(struct platform_device *pdev) { @@ -833,7 +834,9 @@ static int gdma_dma_probe(struct platform_device *pdev) return ret; } - device_reset(&pdev->dev); + ret = device_reset(&pdev->dev); + if (ret) + dev_err(&pdev->dev, "failed to reset: %d\n", ret); dd = &dma_dev->ddev; dma_cap_set(DMA_MEMCPY, dd->cap_mask); diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 182bb944c9b3b0ba50cc2b1527ef3705c6e887b2..008b60e7275861da8a04c1cbd4d173b48a291388 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -507,7 +507,6 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) struct ht_priv *phtpriv_sta = &psta->htpriv; psta->mac_id = psta->aid + 1; - DBG_88E("%s\n", __func__); /* ap mode */ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); @@ -571,8 +570,6 @@ static void update_hw_ht_param(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - DBG_88E("%s\n", __func__); - /* handle A-MPDU parameter field * ampdu_params_info [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k * ampdu_params_info [4:2]:Min MPDU Start Spacing @@ -1166,8 +1163,6 @@ static void update_bcn_wps_ie(struct adapter *padapter) unsigned char *ie = pnetwork->ies; u32 ielen = pnetwork->ie_length; - DBG_88E("%s\n", __func__); - pwps_ie_src = pmlmepriv->wps_beacon_ie; if (!pwps_ie_src) return; @@ -1207,7 +1202,6 @@ static void update_bcn_wps_ie(struct adapter *padapter) static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui) { - DBG_88E("%s\n", __func__); if (!memcmp(WPS_OUI, oui, 4)) update_bcn_wps_ie(padapter); diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index 1724dfd7edbc45366c883a8ee9b6da781f16ecb6..6728391d39e38823d44e776c8de7f12ba5187e7a 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c @@ -4,7 +4,6 @@ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. * ******************************************************************************/ -#define _RTW_CMD_C_ #include <osdep_service.h> #include <drv_types.h> @@ -12,6 +11,42 @@ #include <mlme_osdep.h> #include <rtw_mlme_ext.h> +static struct cmd_hdl wlancmds[] = { + {sizeof(struct wlan_bssid_ex), join_cmd_hdl}, + {sizeof(struct disconnect_parm), disconnect_hdl}, + {sizeof(struct wlan_bssid_ex), createbss_hdl}, + {sizeof(struct setopmode_parm), setopmode_hdl}, + {sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl}, + {sizeof(struct setauth_parm), setauth_hdl}, + {sizeof(struct setkey_parm), setkey_hdl}, + {sizeof(struct set_stakey_parm), set_stakey_hdl}, + {sizeof(struct set_assocsta_parm), NULL}, + {sizeof(struct addBaReq_parm), add_ba_hdl}, + {sizeof(struct set_ch_parm), set_ch_hdl}, + {sizeof(struct wlan_bssid_ex), tx_beacon_hdl}, + {0, mlme_evt_hdl}, + {0, rtw_drvextra_cmd_hdl}, + {sizeof(struct SetChannelPlan_param), set_chplan_hdl} +}; + +static struct _cmd_callback rtw_cmd_callback[] = { + {_JoinBss_CMD_, &rtw_joinbss_cmd_callback}, + {_DisConnect_CMD_, &rtw_disassoc_cmd_callback}, + {_CreateBss_CMD_, &rtw_createbss_cmd_callback}, + {_SetOpMode_CMD_, NULL}, + {_SiteSurvey_CMD_, &rtw_survey_cmd_callback}, + {_SetAuth_CMD_, NULL}, + {_SetKey_CMD_, NULL}, + {_SetStaKey_CMD_, &rtw_setstaKey_cmdrsp_callback}, + {_SetAssocSta_CMD_, &rtw_setassocsta_cmdrsp_callback}, + {_AddBAReq_CMD_, NULL}, + {_SetChannel_CMD_, NULL}, + {_TX_Beacon_CMD_, NULL}, + {_Set_MLME_EVT_CMD_, NULL}, + {_Set_Drv_Extra_CMD_, NULL}, + {_SetChannelPlan_CMD_, NULL}, +}; + /* * Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. * No irqsave is necessary. @@ -153,17 +188,6 @@ int rtw_cmd_thread(void *context) ("start r871x %s !!!!\n", __func__)); while (1) { - if (wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp)) - break; - - if (padapter->bDriverStopped || - padapter->bSurpriseRemoved) { - DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", - __func__, padapter->bDriverStopped, - padapter->bSurpriseRemoved, __LINE__); - break; - } -_next: if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", @@ -173,8 +197,13 @@ _next: } pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue); - if (!pcmd) + if (!pcmd) { + /* The queue is empty. Wait until someone enqueues a command. */ + if (wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp)) + break; + continue; + } if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) { pcmd->res = H2C_DROPPED; @@ -189,8 +218,6 @@ _next: } else { pcmd->res = H2C_PARAMETERS_ERROR; } - - cmd_hdl = NULL; } /* call callback function for post-processed */ @@ -200,22 +227,19 @@ _next: RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode)); - rtw_free_cmd_obj(pcmd); } else { /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */ - pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */ + pcmd_callback(pcmd->padapter, pcmd); } } else { RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode)); - rtw_free_cmd_obj(pcmd); } + rtw_free_cmd_obj(pcmd); if (signal_pending(current)) flush_signals(current); - - goto _next; } pcmdpriv->cmdthd_running = false; @@ -1151,9 +1175,6 @@ void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n.")); } - - /* free cmd */ - rtw_free_cmd_obj(pcmd); } void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) @@ -1167,11 +1188,7 @@ void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n.")); - return; } - - /* free cmd */ - rtw_free_cmd_obj(pcmd); } void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) @@ -1189,8 +1206,6 @@ void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1)); } - - rtw_free_cmd_obj(pcmd); } void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) @@ -1257,8 +1272,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) createbss_cmd_fail: spin_unlock_bh(&pmlmepriv->lock); - - rtw_free_cmd_obj(pcmd); } void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) @@ -1270,10 +1283,7 @@ void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pc if (!psta) { RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: %s => can't get sta_info\n\n", __func__)); - goto exit; } -exit: - rtw_free_cmd_obj(pcmd); } void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) @@ -1287,7 +1297,7 @@ void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj * if (!psta) { RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: %s => can't get sta_info\n\n", __func__)); - goto exit; + return; } psta->aid = passocsta_rsp->cam_id; @@ -1297,7 +1307,4 @@ void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj * set_fwstate(pmlmepriv, _FW_LINKED); spin_unlock_bh(&pmlmepriv->lock); - -exit: - rtw_free_cmd_obj(pcmd); } diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c index 11198d43a371cb2b0dbe51b483e929a3946207c9..1060837fe463937c079e3c25d04540e9d4b4d8a3 100644 --- a/drivers/staging/rtl8188eu/core/rtw_debug.c +++ b/drivers/staging/rtl8188eu/core/rtw_debug.c @@ -33,7 +33,7 @@ int proc_set_write_reg(struct file *file, const char __user *buffer, unsigned long count, void *data) { struct net_device *dev = data; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); char tmp[32]; u32 addr, val, len; @@ -75,7 +75,7 @@ int proc_get_read_reg(char *page, char **start, int *eof, void *data) { struct net_device *dev = data; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); int len = 0; @@ -139,7 +139,7 @@ int proc_get_adapter_state(char *page, char **start, int *eof, void *data) { struct net_device *dev = data; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); int len = 0; len += scnprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n", @@ -155,7 +155,7 @@ int proc_get_best_channel(char *page, char **start, int *eof, void *data) { struct net_device *dev = data; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; int len = 0; u32 i, best_channel_24G = 1, index_24G = 0; diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c index ec5b8be14c2bfaaa48170972303d0a377db8ff5e..7a706fe11750cd0fd593980f3e313bb6c654e3e5 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c @@ -223,13 +223,13 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv) /* capability info */ *(u16 *)ie = 0; - *(__le16 *)ie |= cpu_to_le16(cap_IBSS); + *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_IBSS); if (pregistrypriv->preamble == PREAMBLE_SHORT) - *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble); + *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); if (pdev_network->Privacy) - *(__le16 *)ie |= cpu_to_le16(cap_Privacy); + *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); sz += 2; ie += 2; diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c index 1ef32ff900a9882897fe2b95748ea51887d21d83..17b999f45132077f4c3ef720149f7e9788b81ae0 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c @@ -11,6 +11,14 @@ #include <rtw_ioctl_set.h> #include <hal_intf.h> +static const struct { + int channel_plan; + char *name; +} channel_table[] = { { RT_CHANNEL_DOMAIN_FCC, "US" }, + { RT_CHANNEL_DOMAIN_ETSI, "EU" }, + { RT_CHANNEL_DOMAIN_MKK, "JP" }, + { RT_CHANNEL_DOMAIN_CHINA, "CN"} }; + extern void indicate_wx_scan_complete_event(struct adapter *padapter); u8 rtw_do_join(struct adapter *padapter) diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index f87dd71934c39eb889e40dd245d1a2d3ef6771df..b6ac5b8915b1c3e644e0e2d972d26b5d58c60175 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -37,7 +37,7 @@ int rtw_init_mlme_priv(struct adapter *padapter) pmlmepriv->pscanned = NULL; pmlmepriv->fw_state = 0; pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; - pmlmepriv->scan_mode = SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ + pmlmepriv->scan_mode = SCAN_ACTIVE;/* 1: active, 0: passive. Maybe someday we should rename this variable to "active_mode" (Jeff) */ spin_lock_init(&pmlmepriv->lock); _rtw_init_queue(&pmlmepriv->free_bss_pool); diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index ebd9b96a8211a25395a12b85d71be534bd823f1a..50d3c3631be0ad740ef2bc0662d99d8a410b6cc9 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -2188,7 +2188,7 @@ static void start_create_ibss(struct adapter *padapter) /* update capability */ caps = rtw_get_capability(pnetwork); update_capinfo(padapter, caps); - if (caps & cap_IBSS) {/* adhoc master */ + if (caps & WLAN_CAPABILITY_IBSS) {/* adhoc master */ val8 = 0xcf; rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); @@ -2240,7 +2240,7 @@ static void start_clnt_join(struct adapter *padapter) /* update capability */ caps = rtw_get_capability(pnetwork); update_capinfo(padapter, caps); - if (caps & cap_ESS) { + if (caps & WLAN_CAPABILITY_ESS) { Set_MSR(padapter, WIFI_FW_STATION_STATE); val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; @@ -2258,7 +2258,7 @@ static void start_clnt_join(struct adapter *padapter) msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO * REASSOC_LIMIT) + beacon_timeout)); pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; - } else if (caps & cap_IBSS) { /* adhoc client */ + } else if (caps & WLAN_CAPABILITY_IBSS) { /* adhoc client */ Set_MSR(padapter, WIFI_FW_ADHOC_STATE); val8 = 0xcf; @@ -2526,7 +2526,7 @@ static unsigned int OnProbeReq(struct adapter *padapter, if (check_fwstate(pmlmepriv, _FW_LINKED) && pmlmepriv->cur_network.join_res) - issue_probersp(padapter, get_sa(pframe)); + issue_probersp(padapter, ieee80211_get_SA((struct ieee80211_hdr *)pframe)); } return _SUCCESS; } @@ -2819,7 +2819,7 @@ static unsigned int OnAuthClient(struct adapter *padapter, DBG_88E("%s\n", __func__); /* check A1 matches or not */ - if (memcmp(myid(&padapter->eeprompriv), get_da(pframe), ETH_ALEN)) + if (memcmp(myid(&padapter->eeprompriv), ieee80211_get_DA((struct ieee80211_hdr *)pframe), ETH_ALEN)) return _SUCCESS; if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) @@ -3332,7 +3332,7 @@ static unsigned int OnAssocRsp(struct adapter *padapter, DBG_88E("%s\n", __func__); /* check A1 matches or not */ - if (memcmp(myid(&padapter->eeprompriv), get_da(pframe), ETH_ALEN)) + if (memcmp(myid(&padapter->eeprompriv), ieee80211_get_DA((struct ieee80211_hdr *)pframe), ETH_ALEN)) return _SUCCESS; if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c index 3848e695ac846f07c6d4aa0279ebf86fcf7e6877..4d507d9faec20425834cf3f4f723c4ba17ef3a4b 100644 --- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c @@ -84,7 +84,7 @@ static int rtw_hw_resume(struct adapter *padapter) pwrpriv->bips_processing = true; rtw_reset_drv_sw(padapter); - if (ips_netdrv_open(rtw_netdev_priv(pnetdev)) != _SUCCESS) { + if (ips_netdrv_open(netdev_priv(pnetdev)) != _SUCCESS) { mutex_unlock(&pwrpriv->mutex_lock); goto error_exit; } @@ -480,10 +480,9 @@ void LPS_Leave(struct adapter *padapter) void LeaveAllPowerSaveMode(struct adapter *Adapter) { struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; - u8 enqueue = 0; if (check_fwstate(pmlmepriv, _FW_LINKED)) - rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); + rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, 0); } void rtw_init_pwrctrl_priv(struct adapter *padapter) diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 36bcbe635cf480916e6b68beb526974351af0fe3..b2fe448d999d503f4012945af76ef6e5649ded8f 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -1029,8 +1029,8 @@ static int validate_recv_data_frame(struct adapter *adapter, int ret = _SUCCESS; bretry = GetRetry(ptr); - pda = get_da(ptr); - psa = get_sa(ptr); + pda = ieee80211_get_DA((struct ieee80211_hdr *)ptr); + psa = ieee80211_get_SA((struct ieee80211_hdr *)ptr); pbssid = get_hdr_bssid(ptr); if (!pbssid) { @@ -1962,27 +1962,18 @@ exit: return ret; } -s32 rtw_recv_entry(struct recv_frame *precvframe) +int rtw_recv_entry(struct recv_frame *precvframe) { - struct adapter *padapter; - struct recv_priv *precvpriv; - s32 ret = _SUCCESS; - - padapter = precvframe->adapter; - - precvpriv = &padapter->recvpriv; + struct adapter *padapter = precvframe->adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + int ret; ret = recv_func(padapter, precvframe); - if (ret == _FAIL) { + if (ret == _SUCCESS) + precvpriv->rx_pkts++; + else RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s: recv_func return fail!!!\n", __func__)); - goto _recv_entry_drop; - } - - precvpriv->rx_pkts++; - - return ret; -_recv_entry_drop: return ret; } diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index 46ba55a8952ab5f6c2e27addc068ec6d85b37c58..617f89842c8124ba5872d9817b2f4a3c37bacce1 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -126,9 +126,7 @@ static __le32 getcrc32(u8 *buf, int len) return cpu_to_le32(~crc); /* transmit complement, per CRC-32 spec */ } -/* - Need to consider the fragment situation -*/ +/* Need to consider the fragment situation */ void rtw_wep_encrypt(struct adapter *padapter, struct xmit_frame *pxmitframe) { int curfragnum, length; @@ -427,9 +425,9 @@ static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) 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 of table is unsigned char-reversed version of first! */ + { /* second half of table 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, @@ -462,26 +460,20 @@ static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) 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. -* -********************************************************************** -*/ +/** + * phase1() - generate P1K, given TA, TK, IV32 + * @tk[]: temporal key [128 bits] + * @ta[]: transmitter's MAC address [ 48 bits] + * @iv32: upper 32 bits of IV [ 32 bits] + * + * This function only needs to be called every 2**16 packets, + * although in theory it could be called every packet. + * + * Return: p1k[] - Phase 1 key [ 80 bits] + */ static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) { int i; @@ -504,29 +496,23 @@ static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) } } -/* -********************************************************************** -* 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[]. -* -********************************************************************** -*/ +/** + * phase2() - generate RC4KEY, given TK, P1K, IV16 + * @tk[]: Temporal key [128 bits] + * @p1k[]: Phase 1 output key [ 80 bits] + * @iv16: low 16 bits of IV counter [ 16 bits] + * + * 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[]. + * + * Return: rc4key[] - the key used to encrypt the packet [128 bits] + */ static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) { int i; diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index 317355f830cbd0007c86f83752248cc24f54e9e3..99e44b2c6f36aeb42b0e8b231512a927c89565bd 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -44,7 +44,10 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; - /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ + /* + * We don't need to memset padapter->XXX to zero because adapter is + * allocated by alloc_etherdev_mq, which eventually calls kvzalloc. + */ spin_lock_init(&pxmitpriv->lock); @@ -1240,7 +1243,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) * 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... + * Must be very, very cautious... * */ diff --git a/drivers/staging/rtl8188eu/hal/odm_hwconfig.c b/drivers/staging/rtl8188eu/hal/odm_hwconfig.c index 65a346ae3cb0fe43f7057c7950af775671f89002..684b6cec0f094ad30ff54e3f829235060827056f 100644 --- a/drivers/staging/rtl8188eu/hal/odm_hwconfig.c +++ b/drivers/staging/rtl8188eu/hal/odm_hwconfig.c @@ -385,14 +385,13 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm, } /* Endianness before calling this API */ -void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm, - struct odm_phy_status_info *pPhyInfo, - u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo) +void odm_phy_status_query(struct odm_dm_struct *dm_odm, + struct odm_phy_status_info *phy_info, + u8 *phy_status, struct odm_per_pkt_info *pkt_info) { - odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus, - pPktinfo); + odm_RxPhyStatus92CSeries_Parsing(dm_odm, phy_info, phy_status, pkt_info); if (dm_odm->RSSI_test) ;/* Select the packets to do RSSI checking for antenna switching. */ else - odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo); + odm_Process_RSSIForDM(dm_odm, phy_info, pkt_info); } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c index 7d0135fde795fbc36a80cb10c762dd2894b8e94e..8669bf09747957d607beb11e8dd480d35b483109 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c @@ -133,6 +133,8 @@ void update_recvframe_phyinfo_88e(struct recv_frame *precvframe, struct rx_pkt_attrib *pattrib = &precvframe->attrib; struct odm_phy_status_info *pPHYInfo = (struct odm_phy_status_info *)(&pattrib->phy_info); u8 *wlanhdr; + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *)precvframe->pkt->data; struct odm_per_pkt_info pkt_info; u8 *sa = NULL; struct sta_priv *pstapriv; @@ -144,13 +146,13 @@ void update_recvframe_phyinfo_88e(struct recv_frame *precvframe, wlanhdr = precvframe->pkt->data; - pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && + pkt_info.bPacketMatchBSSID = (!ieee80211_is_ctl(hdr->frame_control) && !pattrib->icv_err && !pattrib->crc_err && !memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN)); pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && - (!memcmp(get_da(wlanhdr), + (!memcmp(ieee80211_get_DA(hdr), myid(&padapter->eeprompriv), ETH_ALEN)); pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && @@ -161,7 +163,7 @@ void update_recvframe_phyinfo_88e(struct recv_frame *precvframe, sa = padapter->mlmepriv.cur_network.network.MacAddress; /* to do Ad-hoc */ } else { - sa = get_sa(wlanhdr); + sa = ieee80211_get_SA(hdr); } pstapriv = &padapter->stapriv; @@ -171,8 +173,8 @@ void update_recvframe_phyinfo_88e(struct recv_frame *precvframe, pkt_info.StationID = psta->mac_id; pkt_info.Rate = pattrib->mcs_rate; - ODM_PhyStatusQuery(&padapter->HalData->odmpriv, pPHYInfo, - (u8 *)pphy_status, &(pkt_info)); + odm_phy_status_query(&padapter->HalData->odmpriv, pPHYInfo, + (u8 *)pphy_status, &(pkt_info)); precvframe->psta = NULL; if (pkt_info.bPacketMatchBSSID && diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c index 25f46b2f49207fdba636614b90bb20467e84090c..09bc915994db2ba25a7e49efaa9f36b979ae2ae6 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c @@ -38,7 +38,7 @@ int rtw_hal_init_recv_priv(struct adapter *padapter) precvbuf = precvpriv->precv_buf; for (i = 0; i < NR_RECVBUFF; i++) { - res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); + res = rtw_os_recvbuf_resource_alloc(precvbuf); if (res == _FAIL) break; precvbuf->adapter = padapter; diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index abe58cf2de1646945a5f5f7328b5d7af6877e9df..80cdcf6f787945f656cf4c076f1838aa49293f8d 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -574,8 +574,7 @@ static void _InitBeaconParameters(struct adapter *Adapter) haldata->RegCR_1 = usb_read8(Adapter, REG_CR + 1); } -static void _BeaconFunctionEnable(struct adapter *Adapter, - bool Enable, bool Linked) +static void _BeaconFunctionEnable(struct adapter *Adapter) { usb_write8(Adapter, REG_BCN_CTRL, (BIT(4) | BIT(3) | BIT(1))); @@ -1961,7 +1960,7 @@ void beacon_timing_control(struct adapter *adapt) usb_write8(adapt, REG_RXTSF_OFFSET_CCK, 0x50); usb_write8(adapt, REG_RXTSF_OFFSET_OFDM, 0x50); - _BeaconFunctionEnable(adapt, true, true); + _BeaconFunctionEnable(adapt); ResumeTxBeacon(adapt); diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h index 0a3acb378d6dc1b3a5f97d7cb52b364bc0a9d277..4116051a9a654f764127d643033343646bc963bb 100644 --- a/drivers/staging/rtl8188eu/include/drv_types.h +++ b/drivers/staging/rtl8188eu/include/drv_types.h @@ -150,7 +150,7 @@ struct adapter { u8 hw_init_completed; - void *cmdThread; + struct task_struct *cmdThread; struct net_device *pnetdev; struct net_device *pmondev; diff --git a/drivers/staging/rtl8188eu/include/odm_hwconfig.h b/drivers/staging/rtl8188eu/include/odm_hwconfig.h index 2cd8a47a36735f134859068c2933a11f3fdf39c3..4f4d3cfb6c77c6ed353580984cebfd5c1a132c73 100644 --- a/drivers/staging/rtl8188eu/include/odm_hwconfig.h +++ b/drivers/staging/rtl8188eu/include/odm_hwconfig.h @@ -93,9 +93,9 @@ struct phy_status_rpt { #endif }; -void ODM_PhyStatusQuery(struct odm_dm_struct *pDM_Odm, - struct odm_phy_status_info *pPhyInfo, - u8 *pPhyStatus, - struct odm_per_pkt_info *pPktinfo); +void odm_phy_status_query(struct odm_dm_struct *dm_odm, + struct odm_phy_status_info *phy_info, + u8 *phy_status, + struct odm_per_pkt_info *pkt_info); #endif diff --git a/drivers/staging/rtl8188eu/include/osdep_intf.h b/drivers/staging/rtl8188eu/include/osdep_intf.h index 5ee4ed99502549437e6d88cd16ca915339f3b109..5012b9176526bbe116a2bb36ad4d4b687fb5f6d1 100644 --- a/drivers/staging/rtl8188eu/include/osdep_intf.h +++ b/drivers/staging/rtl8188eu/include/osdep_intf.h @@ -23,7 +23,7 @@ void rtw_cancel_all_timer(struct adapter *padapter); int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -struct net_device *rtw_init_netdev(struct adapter *padapter); +struct net_device *rtw_init_netdev(void); u16 rtw_recv_select_queue(struct sk_buff *skb); int netdev_open(struct net_device *pnetdev); diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h index 56e937b264070d1aeeb5bd5a5fc5e3bc67ef8d42..efd0833e28c8525b18876cc2d8bcd65773642623 100644 --- a/drivers/staging/rtl8188eu/include/osdep_service.h +++ b/drivers/staging/rtl8188eu/include/osdep_service.h @@ -66,19 +66,6 @@ u8 *_rtw_malloc(u32 sz); void _rtw_init_queue(struct __queue *pqueue); -struct rtw_netdev_priv_indicator { - void *priv; -}; - -struct net_device *rtw_alloc_etherdev_with_old_priv(void *old_priv); - -static inline struct adapter *rtw_netdev_priv(struct net_device *netdev) -{ - return ((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv; -} - -void rtw_free_netdev(struct net_device *netdev); - #define FUNC_NDEV_FMT "%s(%s)" #define FUNC_NDEV_ARG(ndev) __func__, ndev->name #define FUNC_ADPT_FMT "%s(%s)" diff --git a/drivers/staging/rtl8188eu/include/recv_osdep.h b/drivers/staging/rtl8188eu/include/recv_osdep.h index 3b771702810dfa7982c37efd8418daac449413c5..614245d4b17976ae4601a79c536c7b9fc662173e 100644 --- a/drivers/staging/rtl8188eu/include/recv_osdep.h +++ b/drivers/staging/rtl8188eu/include/recv_osdep.h @@ -19,7 +19,7 @@ int rtw_recv_indicatepkt(struct adapter *adapter, void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); -int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf); +int rtw_os_recvbuf_resource_alloc(struct recv_buf *precvbuf); void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h index 6035c12ec5785f04893bfcf20f83066e6e74833a..0c4c23be1dd5a3152dee4ed7f8512774a2d47c37 100644 --- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h +++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h @@ -211,10 +211,6 @@ struct hal_data_8188e { u8 bAPKThermalMeterIgnore; bool EepromOrEfuse; - /* 92C:256bytes, 88E:512bytes, we use union set (512bytes) */ - u8 EfuseMap[2][HWSET_MAX_SIZE_512]; - u8 EfuseUsedPercentage; - struct efuse_hal EfuseHal; u8 Index24G_CCK_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; u8 Index24G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; diff --git a/drivers/staging/rtl8188eu/include/rtw_cmd.h b/drivers/staging/rtl8188eu/include/rtw_cmd.h index 002a797c6d0a7447f7453b4f2af22cc65168e3a7..68b8ad1a412f72ff3f9c334b5437ea56d0d16147 100644 --- a/drivers/staging/rtl8188eu/include/rtw_cmd.h +++ b/drivers/staging/rtl8188eu/include/rtw_cmd.h @@ -361,24 +361,4 @@ enum rtw_h2c_cmd { MAX_H2CCMD }; -#ifdef _RTW_CMD_C_ -static struct _cmd_callback rtw_cmd_callback[] = { - {_JoinBss_CMD_, &rtw_joinbss_cmd_callback}, - {_DisConnect_CMD_, &rtw_disassoc_cmd_callback}, - {_CreateBss_CMD_, &rtw_createbss_cmd_callback}, - {_SetOpMode_CMD_, NULL}, - {_SiteSurvey_CMD_, &rtw_survey_cmd_callback}, - {_SetAuth_CMD_, NULL}, - {_SetKey_CMD_, NULL}, - {_SetStaKey_CMD_, &rtw_setstaKey_cmdrsp_callback}, - {_SetAssocSta_CMD_, &rtw_setassocsta_cmdrsp_callback}, - {_AddBAReq_CMD_, NULL}, - {_SetChannel_CMD_, NULL}, - {_TX_Beacon_CMD_, NULL}, - {_Set_MLME_EVT_CMD_, NULL}, - {_Set_Drv_Extra_CMD_, NULL}, - {_SetChannelPlan_CMD_, NULL}, -}; -#endif - #endif /* _CMD_H_ */ diff --git a/drivers/staging/rtl8188eu/include/rtw_efuse.h b/drivers/staging/rtl8188eu/include/rtw_efuse.h index 5926fc9b5e6b85cc8dfe32b1b4e79e80d8be2ce9..74182c32c4ec40f55fa7ba30102aea8fb84b0874 100644 --- a/drivers/staging/rtl8188eu/include/rtw_efuse.h +++ b/drivers/staging/rtl8188eu/include/rtw_efuse.h @@ -56,26 +56,6 @@ struct pgpkt { u8 word_cnts; }; -/*------------------------------Define structure----------------------------*/ -struct efuse_hal { - u8 fakeEfuseBank; - u32 fakeEfuseUsedBytes; - u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]; - u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]; - u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]; - - u16 BTEfuseUsedBytes; - u8 BTEfuseUsedPercentage; - u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; - u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; - u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; - - u16 fakeBTEfuseUsedBytes; - u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; - u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; - u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; -}; - u8 Efuse_CalculateWordCnts(u8 word_en); u8 efuse_OneByteRead(struct adapter *adapter, u16 addr, u8 *data); u8 efuse_OneByteWrite(struct adapter *adapter, u16 addr, u8 data); diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h index b11a6886a0838fc205d89cfdefeffcfddaa150bf..03d55eb7dc16bc577a3b3fdd34cf87d8f52c2db3 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h @@ -171,14 +171,6 @@ struct rt_channel_plan_map { unsigned char Index2G; }; -static const struct { - int channel_plan; - char *name; -} channel_table[] = { { RT_CHANNEL_DOMAIN_FCC, "US" }, - { RT_CHANNEL_DOMAIN_ETSI, "EU" }, - { RT_CHANNEL_DOMAIN_MKK, "JP" }, - { RT_CHANNEL_DOMAIN_CHINA, "CN"} }; - enum Associated_AP { atherosAP = 0, broadcomAP = 1, @@ -606,28 +598,6 @@ u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf); u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf); u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf); -#ifdef _RTW_CMD_C_ - -static struct cmd_hdl wlancmds[] = { - {sizeof(struct wlan_bssid_ex), join_cmd_hdl}, - {sizeof(struct disconnect_parm), disconnect_hdl}, - {sizeof(struct wlan_bssid_ex), createbss_hdl}, - {sizeof(struct setopmode_parm), setopmode_hdl}, - {sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl}, - {sizeof(struct setauth_parm), setauth_hdl}, - {sizeof(struct setkey_parm), setkey_hdl}, - {sizeof(struct set_stakey_parm), set_stakey_hdl}, - {sizeof(struct set_assocsta_parm), NULL}, - {sizeof(struct addBaReq_parm), add_ba_hdl}, - {sizeof(struct set_ch_parm), set_ch_hdl}, - {sizeof(struct wlan_bssid_ex), tx_beacon_hdl}, - {0, mlme_evt_hdl}, - {0, rtw_drvextra_cmd_hdl}, - {sizeof(struct SetChannelPlan_param), set_chplan_hdl} -}; - -#endif - struct C2HEvent_Header { #ifdef __LITTLE_ENDIAN unsigned int len:16; diff --git a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h index 06062643c868c34531be1c616f96fb660811cbb4..4345dc0c7cf9c781ad437131bb47a812ba69bd9f 100644 --- a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h +++ b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h @@ -171,7 +171,7 @@ struct pwrctrl_priv { unsigned long ips_deny_time; /* will deny IPS when system time less than this */ u8 ps_processing; /* temp used to mark whether in rtw_ps_processor */ - u8 bLeisurePs; + bool bLeisurePs; u8 LpsIdleCount; u8 power_mgnt; u8 bFwCurrentInPSMode; diff --git a/drivers/staging/rtl8188eu/include/usb_ops_linux.h b/drivers/staging/rtl8188eu/include/usb_ops_linux.h index 70d729742839731236b123a7bc3284b63367a08e..19c6e76d747ee4e7071547567889660c00357359 100644 --- a/drivers/staging/rtl8188eu/include/usb_ops_linux.h +++ b/drivers/staging/rtl8188eu/include/usb_ops_linux.h @@ -7,46 +7,14 @@ #ifndef __USB_OPS_LINUX_H__ #define __USB_OPS_LINUX_H__ -#define VENDOR_CMD_MAX_DATA_LEN 254 - -#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST 10/* ms */ -#define RTW_USB_CONTROL_MSG_TIMEOUT 500/* ms */ - -#define MAX_USBCTRL_VENDORREQ_TIMES 10 - -#define RTW_USB_BULKOUT_TIME 5000/* ms */ - -#define REALTEK_USB_VENQT_READ 0xC0 -#define REALTEK_USB_VENQT_WRITE 0x40 - -#define ALIGNMENT_UNIT 16 -#define MAX_VENDOR_REQ_CMD_SIZE 254 /* 8188cu SIE Support */ -#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE + ALIGNMENT_UNIT) - #define USB_HIGH_SPEED_BULK_SIZE 512 #define USB_FULL_SPEED_BULK_SIZE 64 -#define _usbctrl_vendorreq_async_callback(urb, regs) \ - _usbctrl_vendorreq_async_callback(urb) -#define usb_bulkout_zero_complete(purb, regs) \ - usb_bulkout_zero_complete(purb) -#define usb_write_mem_complete(purb, regs) \ - usb_write_mem_complete(purb) -#define usb_write_port_complete(purb, regs) \ - usb_write_port_complete(purb) -#define usb_read_port_complete(purb, regs) \ - usb_read_port_complete(purb) -#define usb_read_interrupt_complete(purb, regs) \ - usb_read_interrupt_complete(purb) - -unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr); - u8 usb_read8(struct adapter *adapter, u32 addr); u16 usb_read16(struct adapter *adapter, u32 addr); u32 usb_read32(struct adapter *adapter, u32 addr); u32 usb_read_port(struct adapter *adapter, u32 addr, struct recv_buf *precvbuf); -void usb_read_port_cancel(struct adapter *adapter); int usb_write8(struct adapter *adapter, u32 addr, u8 val); int usb_write16(struct adapter *adapter, u32 addr, u16 val); diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h index 1b9006879a11aba821b1a2a491c858b7aeeb15d5..84e17330628e2f9c747124d1d3c45187ec0e6112 100644 --- a/drivers/staging/rtl8188eu/include/wifi.h +++ b/drivers/staging/rtl8188eu/include/wifi.h @@ -7,21 +7,8 @@ #ifndef _WIFI_H_ #define _WIFI_H_ -#define WLAN_IEEE_OUI_LEN 3 -#define WLAN_CRC_LEN 4 -#define WLAN_BSSID_LEN 6 -#define WLAN_BSS_TS_LEN 8 #define WLAN_HDR_A3_LEN 24 -#define WLAN_HDR_A4_LEN 30 #define WLAN_HDR_A3_QOS_LEN 26 -#define WLAN_HDR_A4_QOS_LEN 32 -#define WLAN_DATA_MAXLEN 2312 - -#define WLAN_A3_PN_OFFSET 24 -#define WLAN_A4_PN_OFFSET 30 - -#define WLAN_MIN_ETHFRM_LEN 60 -#define WLAN_MAX_ETHFRM_LEN 1514 #define P80211CAPTURE_VERSION 0x80211001 @@ -74,20 +61,6 @@ enum WIFI_FRAME_SUBTYPE { WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE), }; -enum WIFI_REG_DOMAIN { - DOMAIN_FCC = 1, - DOMAIN_IC = 2, - DOMAIN_ETSI = 3, - DOMAIN_SPA = 4, - DOMAIN_FRANCE = 5, - DOMAIN_MKK = 6, - DOMAIN_ISRAEL = 7, - DOMAIN_MKK1 = 8, - DOMAIN_MKK2 = 9, - DOMAIN_MKK3 = 10, - DOMAIN_MAX -}; - #define SetToDs(pbuf) \ *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS) @@ -199,52 +172,6 @@ enum WIFI_REG_DOMAIN { #define GetAddr3Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 16)) -#define GetAddr4Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 24)) - -static inline unsigned char *get_da(unsigned char *pframe) -{ - unsigned char *da; - unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); - - switch (to_fr_ds) { - case 0x00: /* ToDs=0, FromDs=0 */ - da = GetAddr1Ptr(pframe); - break; - case 0x01: /* ToDs=0, FromDs=1 */ - da = GetAddr1Ptr(pframe); - break; - case 0x02: /* ToDs=1, FromDs=0 */ - da = GetAddr3Ptr(pframe); - break; - default: /* ToDs=1, FromDs=1 */ - da = GetAddr3Ptr(pframe); - break; - } - return da; -} - -static inline unsigned char *get_sa(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 = GetAddr2Ptr(pframe); - break; - case 0x01: /* ToDs=0, FromDs=1 */ - sa = GetAddr3Ptr(pframe); - break; - case 0x02: /* ToDs=1, FromDs=0 */ - sa = GetAddr2Ptr(pframe); - break; - default: /* ToDs=1, FromDs=1 */ - sa = GetAddr4Ptr(pframe); - break; - } - return sa; -} - static inline unsigned char *get_hdr_bssid(unsigned char *pframe) { unsigned char *sa; @@ -270,30 +197,9 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe) return sa; } -static inline int IsFrameTypeCtrl(unsigned char *pframe) -{ - if (GetFrameType(pframe) == WIFI_CTRL_TYPE) - return true; - else - return false; -} - /*----------------------------------------------------------------------------- Below is for the security related definition ------------------------------------------------------------------------------*/ -#define _RESERVED_FRAME_TYPE_ 0 -#define _SKB_FRAME_TYPE_ 2 -#define _PRE_ALLOCMEM_ 1 -#define _PRE_ALLOCHDR_ 3 -#define _PRE_ALLOCLLCHDR_ 4 -#define _PRE_ALLOCICVHDR_ 5 -#define _PRE_ALLOCMICHDR_ 6 - -#define _SIFSTIME_ \ - ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) ? 16 : 10) -#define _ACKCTSLNG_ 14 /* 14 bytes long, including crclng */ -#define _CRCLNG_ 4 - #define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */ #define _ASOCRSP_IE_OFFSET_ 6 #define _REASOCREQ_IE_OFFSET_ 10 @@ -324,22 +230,6 @@ static inline int IsFrameTypeCtrl(unsigned char *pframe) #define AUTH_ODD_TO 0 #define AUTH_EVEN_TO 1 -#define WLAN_ETHCONV_ENCAP 1 -#define WLAN_ETHCONV_RFC1042 2 -#define WLAN_ETHCONV_8021h 3 - -#define cap_ESS BIT(0) -#define cap_IBSS BIT(1) -#define cap_CFPollable BIT(2) -#define cap_CFRequest BIT(3) -#define cap_Privacy BIT(4) -#define cap_ShortPremble BIT(5) -#define cap_PBCC BIT(6) -#define cap_ChAgility BIT(7) -#define cap_SpecMgmt BIT(8) -#define cap_QoSi BIT(9) -#define cap_ShortSlot BIT(10) - /*----------------------------------------------------------------------------- Below is the definition for 802.11i / 802.1x ------------------------------------------------------------------------------*/ @@ -360,7 +250,6 @@ static inline int IsFrameTypeCtrl(unsigned char *pframe) Below is the definition for WMM ------------------------------------------------------------------------------*/ #define _WMM_IE_Length_ 7 /* for WMM STA */ -#define _WMM_Para_Element_Length_ 24 /*----------------------------------------------------------------------------- Below is the definition for 802.11n @@ -432,13 +321,6 @@ enum ht_cap_ampdu_factor { #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8)BIT(3)) #define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8)BIT(4)) -#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16)BIT(6)) -#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16)BIT(7)) -#define HT_INFO_STBC_PARAM_SECONDARY_BC ((u16)BIT(8)) -#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16)BIT(9)) -#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16)BIT(10)) -#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16)BIT(11)) - /* ===============WPS Section=============== */ /* For WPSv1.0 */ #define WPSOUI 0x0050f204 @@ -497,48 +379,10 @@ enum ht_cap_ampdu_factor { #define WPS_CONFIG_METHOD_VDISPLAY 0x2008 #define WPS_CONFIG_METHOD_PDISPLAY 0x4008 -/* Value of Category ID of WPS Primary Device Type Attribute */ -#define WPS_PDT_CID_DISPLAYS 0x0007 -#define WPS_PDT_CID_MULIT_MEDIA 0x0008 -#define WPS_PDT_CID_RTK_WIDI WPS_PDT_CID_MULIT_MEDIA - -/* Value of Sub Category ID of WPS Primary Device Type Attribute */ -#define WPS_PDT_SCID_MEDIA_SERVER 0x0005 -#define WPS_PDT_SCID_RTK_DMP WPS_PDT_SCID_MEDIA_SERVER - -/* Value of Device Password ID */ -#define WPS_DPID_P 0x0000 -#define WPS_DPID_USER_SPEC 0x0001 -#define WPS_DPID_MACHINE_SPEC 0x0002 -#define WPS_DPID_REKEY 0x0003 -#define WPS_DPID_PBC 0x0004 -#define WPS_DPID_REGISTRAR_SPEC 0x0005 - /* Value of WPS RF Bands Attribute */ #define WPS_RF_BANDS_2_4_GHZ 0x01 #define WPS_RF_BANDS_5_GHZ 0x02 -/* Value of WPS Association State Attribute */ -#define WPS_ASSOC_STATE_NOT_ASSOCIATED 0x00 -#define WPS_ASSOC_STATE_CONNECTION_SUCCESS 0x01 -#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE 0x02 -#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03 -#define WPS_ASSOC_STATE_IP_FAILURE 0x04 - -/* WPS Configuration Method */ -#define WPS_CM_NONE 0x0000 -#define WPS_CM_LABEL 0x0004 -#define WPS_CM_DISPLYA 0x0008 -#define WPS_CM_EXTERNAL_NFC_TOKEN 0x0010 -#define WPS_CM_INTEGRATED_NFC_TOKEN 0x0020 -#define WPS_CM_NFC_INTERFACE 0x0040 -#define WPS_CM_PUSH_BUTTON 0x0080 -#define WPS_CM_KEYPAD 0x0100 -#define WPS_CM_SW_PUHS_BUTTON 0x0280 -#define WPS_CM_HW_PUHS_BUTTON 0x0480 -#define WPS_CM_SW_DISPLAY_P 0x2008 -#define WPS_CM_LCD_DISPLAY_P 0x4008 - #define IP_MCAST_MAC(mac) \ ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x5e)) #define ICMPV6_MCAST_MAC(mac) \ diff --git a/drivers/staging/rtl8188eu/include/wlan_bssdef.h b/drivers/staging/rtl8188eu/include/wlan_bssdef.h index 2c184ce8746b7713e665b3db083351b2965b95e0..350bbf9057b85a7be49036813653509b09cb2723 100644 --- a/drivers/staging/rtl8188eu/include/wlan_bssdef.h +++ b/drivers/staging/rtl8188eu/include/wlan_bssdef.h @@ -64,7 +64,7 @@ struct ndis_802_11_fixed_ie { struct ndis_802_11_var_ie { u8 ElementID; u8 Length; - u8 data[1]; + u8 data[]; }; /* diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 58954b88a817de795353ad9eb39a4896f0a81446..c95ae4d6a3b6bb507721cb45e1dc20c56ba0cd2d 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -311,7 +311,7 @@ static char *translate_scan(struct adapter *padapter, static int wpa_set_auth_algs(struct net_device *dev, u32 value) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); int ret = 0; if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) { @@ -345,7 +345,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, int ret = 0; u32 wep_key_idx, wep_key_len, wep_total_len; struct ndis_802_11_wep *pwep = NULL; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; @@ -617,7 +617,7 @@ static int rtw_wx_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); u32 ht_ielen = 0; char *p; u8 ht_cap = false; @@ -669,7 +669,7 @@ static int rtw_wx_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; @@ -690,7 +690,7 @@ static int rtw_wx_get_freq(struct net_device *dev, static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *b) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); enum ndis_802_11_network_infra networkType; int ret = 0; @@ -738,7 +738,7 @@ exit: static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *b) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__)); @@ -760,7 +760,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); u8 j, blInserted = false; int ret = false; struct security_priv *psecuritypriv = &padapter->securitypriv; @@ -837,7 +837,7 @@ static int rtw_wx_get_range(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct iw_range *range = (struct iw_range *)extra; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; u16 val; @@ -925,7 +925,7 @@ static int rtw_wx_set_wap(struct net_device *dev, union iwreq_data *awrq, char *extra) { uint ret = 0; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct sockaddr *temp = (struct sockaddr *)awrq; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct list_head *phead; @@ -990,7 +990,7 @@ static int rtw_wx_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; @@ -1015,7 +1015,7 @@ static int rtw_wx_set_mlme(struct net_device *dev, { int ret = 0; u16 reason; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; if (!mlme) @@ -1047,7 +1047,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, { u8 _status = false; int ret = 0; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; @@ -1178,7 +1178,7 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *extra) { struct list_head *plist, *phead; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct __queue *queue = &pmlmepriv->scanned_queue; struct wlan_network *pnetwork = NULL; @@ -1246,7 +1246,7 @@ static int rtw_wx_set_essid(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct __queue *queue = &pmlmepriv->scanned_queue; struct list_head *phead; @@ -1348,7 +1348,7 @@ static int rtw_wx_get_essid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u32 len; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; @@ -1453,7 +1453,7 @@ static int rtw_wx_get_rate(struct net_device *dev, { u16 max_rate = 0; - max_rate = rtw_get_cur_max_rate(rtw_netdev_priv(dev)); + max_rate = rtw_get_cur_max_rate(netdev_priv(dev)); if (max_rate == 0) return -EPERM; @@ -1468,7 +1468,7 @@ static int rtw_wx_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); if (wrqu->rts.disabled) { padapter->registrypriv.rts_thresh = 2347; @@ -1489,7 +1489,7 @@ static int rtw_wx_get_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); @@ -1504,7 +1504,7 @@ static int rtw_wx_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); if (wrqu->frag.disabled) { padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD; @@ -1525,7 +1525,7 @@ static int rtw_wx_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); @@ -1556,7 +1556,7 @@ static int rtw_wx_set_enc(struct net_device *dev, enum ndis_802_11_auth_mode authmode; struct iw_point *erq = &wrqu->encoding; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; DBG_88E("+%s, flags = 0x%x\n", __func__, erq->flags); @@ -1665,7 +1665,7 @@ static int rtw_wx_get_enc(struct net_device *dev, union iwreq_data *wrqu, char *keybuf) { uint key; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct iw_point *erq = &wrqu->encoding; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -1740,7 +1740,7 @@ static int rtw_wx_set_gen_ie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); return rtw_set_wpa_ie(padapter, extra, wrqu->data.length); } @@ -1749,7 +1749,7 @@ static int rtw_wx_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct iw_param *param = (struct iw_param *)&wrqu->param; int ret = 0; @@ -1919,7 +1919,7 @@ static int dummy(struct net_device *dev, struct iw_request_info *a, static int wpa_set_param(struct net_device *dev, u8 name, u32 value) { uint ret = 0; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); switch (name) { case IEEE_PARAM_WPA_ENABLED: @@ -1974,7 +1974,7 @@ static int wpa_set_param(struct net_device *dev, u8 name, u32 value) static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) { int ret = 0; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); switch (command) { case IEEE_MLME_STA_DEAUTH: @@ -2011,7 +2011,7 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) break; case IEEE_CMD_SET_WPA_IE: - ret = rtw_set_wpa_ie(rtw_netdev_priv(dev), + ret = rtw_set_wpa_ie(netdev_priv(dev), (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len); break; @@ -2155,7 +2155,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 wep_key_idx, wep_key_len, wep_total_len; struct ndis_802_11_wep *pwep = NULL; struct sta_info *psta = NULL, *pbcmc_sta = NULL; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; struct sta_priv *pstapriv = &padapter->stapriv; @@ -2381,7 +2381,7 @@ exit: static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len) { int ret = 0; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct sta_priv *pstapriv = &padapter->stapriv; unsigned char *pbuf = param->u.bcn_ie.buf; @@ -2406,7 +2406,7 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int static int rtw_hostapd_sta_flush(struct net_device *dev) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); DBG_88E("%s\n", __func__); @@ -2419,7 +2419,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) { int ret = 0; struct sta_info *psta = NULL; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct sta_priv *pstapriv = &padapter->stapriv; @@ -2472,7 +2472,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) { struct sta_info *psta = NULL; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct sta_priv *pstapriv = &padapter->stapriv; int updated = 0; @@ -2507,7 +2507,7 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par { int ret = 0; struct sta_info *psta = NULL; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct sta_priv *pstapriv = &padapter->stapriv; struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param; @@ -2563,7 +2563,7 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) { int ret = 0; struct sta_info *psta = NULL; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct sta_priv *pstapriv = &padapter->stapriv; @@ -2599,7 +2599,7 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len) { unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; int ie_len; @@ -2634,7 +2634,7 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; int ie_len; @@ -2663,7 +2663,7 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; int ie_len; @@ -2693,7 +2693,7 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -2717,7 +2717,7 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) @@ -2731,7 +2731,7 @@ static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *p static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) @@ -2745,7 +2745,7 @@ static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *para static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) @@ -2760,7 +2760,7 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) { struct ieee_param *param; int ret = 0; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); /* * this function is expect to call in master mode, which allows no power saving @@ -2841,7 +2841,7 @@ static int rtw_wx_set_priv(struct net_device *dev, int ret = 0; int len = 0; char *ext; - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct iw_point *dwrq = (struct iw_point *)awrq; if (dwrq->length == 0) @@ -2959,7 +2959,7 @@ static iw_handler rtw_handlers[] = { static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct iw_statistics *piwstats = &padapter->iwstats; int tmp_level = 0; int tmp_qual = 0; diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index c80d30f31869cd17172bd067f0390935eee6a60f..a826228cbbe989984896cc615cecc970db5ef9a1 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -187,7 +187,7 @@ static void loadparam(struct adapter *padapter, struct net_device *pnetdev) static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) { - struct adapter *padapter = rtw_netdev_priv(pnetdev); + struct adapter *padapter = netdev_priv(pnetdev); struct sockaddr *addr = p; if (!padapter->bup) @@ -198,7 +198,7 @@ static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) { - struct adapter *padapter = rtw_netdev_priv(pnetdev); + struct adapter *padapter = netdev_priv(pnetdev); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct recv_priv *precvpriv = &padapter->recvpriv; @@ -248,7 +248,7 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb) static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; skb->priority = rtw_classify8021d(skb); @@ -296,21 +296,19 @@ static const struct device_type wlan_type = { .name = "wlan", }; -struct net_device *rtw_init_netdev(struct adapter *old_padapter) +struct net_device *rtw_init_netdev(void) { struct adapter *padapter; - struct net_device *pnetdev = NULL; + struct net_device *pnetdev; RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n")); - if (old_padapter) - pnetdev = rtw_alloc_etherdev_with_old_priv((void *)old_padapter); - + pnetdev = alloc_etherdev_mq(sizeof(struct adapter), 4); if (!pnetdev) return NULL; pnetdev->dev.type = &wlan_type; - padapter = rtw_netdev_priv(pnetdev); + padapter = netdev_priv(pnetdev); padapter->pnetdev = pnetdev; DBG_88E("register rtw_netdev_ops to netdev_ops\n"); pnetdev->netdev_ops = &rtw_netdev_ops; @@ -534,7 +532,7 @@ static int _netdev_open(struct net_device *pnetdev) { uint status; int err; - struct adapter *padapter = rtw_netdev_priv(pnetdev); + struct adapter *padapter = netdev_priv(pnetdev); struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - dev_open\n")); @@ -603,7 +601,7 @@ netdev_open_error: int netdev_open(struct net_device *pnetdev) { int ret; - struct adapter *padapter = rtw_netdev_priv(pnetdev); + struct adapter *padapter = netdev_priv(pnetdev); if (mutex_lock_interruptible(&padapter->hw_init_mutex)) return -ERESTARTSYS; @@ -689,7 +687,7 @@ void rtw_ips_dev_unload(struct adapter *padapter) static int netdev_close(struct net_device *pnetdev) { - struct adapter *padapter = rtw_netdev_priv(pnetdev); + struct adapter *padapter = netdev_priv(pnetdev); RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - drv_close\n")); diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c index 4d6d0347ab8e235149231cd01be7fe7619e6d6ee..57453df0ced868427f2c7f154b141f24b1727ab3 100644 --- a/drivers/staging/rtl8188eu/os_dep/osdep_service.c +++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c @@ -24,37 +24,6 @@ void _rtw_init_queue(struct __queue *pqueue) spin_lock_init(&pqueue->lock); } -struct net_device *rtw_alloc_etherdev_with_old_priv(void *old_priv) -{ - struct net_device *netdev; - struct rtw_netdev_priv_indicator *pnpi; - - netdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); - if (!netdev) - return NULL; - - pnpi = netdev_priv(netdev); - pnpi->priv = old_priv; - - return netdev; -} - -void rtw_free_netdev(struct net_device *netdev) -{ - struct rtw_netdev_priv_indicator *pnpi; - - if (!netdev) - return; - - pnpi = netdev_priv(netdev); - - if (!pnpi->priv) - return; - - vfree(pnpi->priv); - free_netdev(netdev); -} - void rtw_buf_free(u8 **buf, u32 *buf_len) { *buf_len = 0; diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index 9c9339863a4a9236110df3598ed3a2d546373bdc..a647cdc330e49c348971a95f8bd5ac60dd915781 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -14,8 +14,7 @@ #include <usb_ops_linux.h> /* alloc os related resource in struct recv_buf */ -int rtw_os_recvbuf_resource_alloc(struct adapter *padapter, - struct recv_buf *precvbuf) +int rtw_os_recvbuf_resource_alloc(struct recv_buf *precvbuf) { precvbuf->pskb = NULL; precvbuf->reuse = false; diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c index b5209627fd1af06e5269ba6c0627742c0ec1bbaf..f1470ac56874ad7cd140f38a2358c80873a1eae4 100644 --- a/drivers/staging/rtl8188eu/os_dep/rtw_android.c +++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c @@ -52,16 +52,6 @@ struct android_wifi_priv_cmd { int total_len; }; -/** - * Local (static) functions and variables - */ - -/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first - * time (only) in dhd_open, subsequential wifi on will be handled by - * wl_android_wifi_on - */ -static int g_wifi_on = true; - int rtw_android_cmdstr_to_num(char *cmdstr) { int cmd_num; @@ -76,7 +66,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr) static int rtw_android_get_rssi(struct net_device *net, char *command, int total_len) { - struct adapter *padapter = rtw_netdev_priv(net); + struct adapter *padapter = netdev_priv(net); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *pcur_network = &pmlmepriv->cur_network; int bytes_written = 0; @@ -93,7 +83,7 @@ static int rtw_android_get_rssi(struct net_device *net, char *command, static int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len) { - struct adapter *padapter = rtw_netdev_priv(net); + struct adapter *padapter = netdev_priv(net); u16 link_speed; link_speed = rtw_get_cur_max_rate(padapter) / 10; @@ -111,7 +101,7 @@ static int rtw_android_get_macaddr(struct net_device *net, char *command, static int android_set_cntry(struct net_device *net, char *command, int total_len) { - struct adapter *adapter = rtw_netdev_priv(net); + struct adapter *adapter = netdev_priv(net); char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1; int ret; @@ -154,12 +144,6 @@ int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) case ANDROID_WIFI_CMD_SETFWPATH: goto response; } - if (!g_wifi_on) { - DBG_88E("%s: Ignore private cmd \"%s\" - iface %s is down\n", - __func__, command, ifr->ifr_name); - ret = 0; - goto free; - } switch (cmd_num) { case ANDROID_WIFI_CMD_STOP: break; @@ -244,7 +228,6 @@ response: } else { ret = bytes_written; } -free: kfree(command); return ret; } diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index efad43d8e465d9b2a41a5454a322ba09800ab5f6..3a970d67aa8c86cc7ef234d9ed49ae808e20c0cf 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -48,7 +48,7 @@ static const struct usb_device_id rtw_usb_id_tbl[] = { MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl); -static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) +static int usb_dvobj_init(struct usb_interface *usb_intf) { int i; struct dvobj_priv *pdvobjpriv; @@ -61,7 +61,7 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); if (!pdvobjpriv) - return NULL; + return -ENOMEM; pdvobjpriv->pusbintf = usb_intf; pusbd = interface_to_usbdev(usb_intf); @@ -108,7 +108,7 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) mutex_init(&pdvobjpriv->usb_vendor_req_mutex); usb_get_dev(pusbd); - return pdvobjpriv; + return 0; } static void usb_dvobj_deinit(struct usb_interface *usb_intf) @@ -322,30 +322,26 @@ static int rtw_resume(struct usb_interface *pusb_intf) * We accept the new device by returning 0. */ -static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, - struct usb_interface *pusb_intf, - const struct usb_device_id *pdid) +static int rtw_usb_if1_init(struct usb_interface *pusb_intf) { - struct adapter *padapter = NULL; - struct net_device *pnetdev = NULL; + struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); + struct adapter *padapter; + struct net_device *pnetdev; struct net_device *pmondev; - int status = _FAIL; + int err = 0; - padapter = vzalloc(sizeof(*padapter)); - if (!padapter) - goto exit; + pnetdev = rtw_init_netdev(); + if (!pnetdev) + return -ENOMEM; + SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); + + padapter = netdev_priv(pnetdev); padapter->dvobj = dvobj; dvobj->if1 = padapter; padapter->bDriverStopped = true; mutex_init(&padapter->hw_init_mutex); - pnetdev = rtw_init_netdev(padapter); - if (!pnetdev) - goto free_adapter; - SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); - padapter = rtw_netdev_priv(pnetdev); - if (padapter->registrypriv.monitor_enable) { pmondev = rtl88eu_mon_init(); if (!pmondev) @@ -356,6 +352,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, padapter->HalData = kzalloc(sizeof(struct hal_data_8188e), GFP_KERNEL); if (!padapter->HalData) { DBG_88E("Failed to allocate memory for HAL data\n"); + err = -ENOMEM; goto free_adapter; } @@ -372,6 +369,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, if (rtw_init_drv_sw(padapter) == _FAIL) { RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("Initialize driver software resource Failed!\n")); + err = -ENOMEM; goto free_hal_data; } @@ -380,7 +378,6 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, dvobj->pusbdev->do_remote_wakeup = 1; pusb_intf->needs_remote_wakeup = 1; device_init_wakeup(&pusb_intf->dev, 1); - pr_debug("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); pr_debug("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", device_may_wakeup(&pusb_intf->dev)); } @@ -402,7 +399,8 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, pnetdev->dev_addr); /* step 6. Tell the network stack we exist */ - if (register_netdev(pnetdev) != 0) { + err = register_netdev(pnetdev); + if (err) { RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("register_netdev() failed\n")); goto free_hal_data; } @@ -414,21 +412,13 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, , padapter->hw_init_completed ); - status = _SUCCESS; + return 0; free_hal_data: - if (status != _SUCCESS) - kfree(padapter->HalData); + kfree(padapter->HalData); free_adapter: - if (status != _SUCCESS) { - if (pnetdev) - rtw_free_netdev(pnetdev); - else - vfree(padapter); - padapter = NULL; - } -exit: - return padapter; + free_netdev(pnetdev); + return err; } static void rtw_usb_if1_deinit(struct adapter *if1) @@ -453,34 +443,28 @@ static void rtw_usb_if1_deinit(struct adapter *if1) pr_debug("+r871xu_dev_remove, hw_init_completed=%d\n", if1->hw_init_completed); rtw_free_drv_sw(if1); - rtw_free_netdev(pnetdev); + if (pnetdev) + free_netdev(pnetdev); } static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid) { - struct adapter *if1 = NULL; - struct dvobj_priv *dvobj; + int err; - /* Initialize dvobj_priv */ - dvobj = usb_dvobj_init(pusb_intf); - if (!dvobj) { - RT_TRACE(_module_hci_intfs_c_, _drv_err_, - ("initialize device object priv Failed!\n")); - goto exit; + err = usb_dvobj_init(pusb_intf); + if (err) { + pr_debug("usb_dvobj_init failed\n"); + return err; } - if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid); - if (!if1) { - pr_debug("rtw_init_primarystruct adapter Failed!\n"); - goto free_dvobj; + err = rtw_usb_if1_init(pusb_intf); + if (err) { + pr_debug("rtw_usb_if1_init failed\n"); + usb_dvobj_deinit(pusb_intf); + return err; } return 0; - -free_dvobj: - usb_dvobj_deinit(pusb_intf); -exit: - return -ENODEV; } /* diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c index 6926443bba4e4566f8f2ad9fe10c5faa952252b7..e8222ffb6feac35a83ece16aa3e089186a76a68c 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c @@ -10,6 +10,20 @@ #include <recv_osdep.h> #include <rtw_sreset.h> +#define RTW_USB_CONTROL_MSG_TIMEOUT 500 /* ms */ + +#define MAX_USBCTRL_VENDORREQ_TIMES 10 + +#define ALIGNMENT_UNIT 16 +#define MAX_VENDOR_REQ_CMD_SIZE 254 +#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE + ALIGNMENT_UNIT) + +#define REALTEK_USB_VENQT_READ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define REALTEK_USB_VENQT_WRITE (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) + +#define REALTEK_USB_VENQT_CMD_REQ 0x05 +#define REALTEK_USB_VENQT_CMD_IDX 0x00 + static void interrupt_handler_8188eu(struct adapter *adapt, u16 pkt_len, u8 *pbuf) { struct hal_data_8188e *haldata = adapt->HalData; @@ -181,7 +195,7 @@ _exit_recvbuf2recvframe: return _SUCCESS; } -unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) +static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) { unsigned int pipe = 0, ep_num = 0; struct usb_device *pusbd = pdvobj->pusbdev; @@ -198,13 +212,13 @@ unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) return pipe; } -static int usbctrl_vendorreq(struct adapter *adapt, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype) +static int +usbctrl_vendorreq(struct adapter *adapt, u16 value, void *pdata, u16 len, u8 reqtype) { struct dvobj_priv *dvobjpriv = adapter_to_dvobj(adapt); struct usb_device *udev = dvobjpriv->pusbdev; unsigned int pipe; int status = 0; - u8 reqtype; u8 *pIo_buf; int vendorreq_times = 0; @@ -235,36 +249,41 @@ static int usbctrl_vendorreq(struct adapter *adapt, u8 request, u16 value, u16 i goto release_mutex; } - while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { - memset(pIo_buf, 0, len); + if (reqtype == REALTEK_USB_VENQT_READ) { + pipe = usb_rcvctrlpipe(udev, 0); + } else if (reqtype == REALTEK_USB_VENQT_WRITE) { + pipe = usb_sndctrlpipe(udev, 0); + } else { + status = -EINVAL; + goto free_buf; + } - if (requesttype == 0x01) { - pipe = usb_rcvctrlpipe(udev, 0);/* read_in */ - reqtype = REALTEK_USB_VENQT_READ; - } else { - pipe = usb_sndctrlpipe(udev, 0);/* write_out */ - reqtype = REALTEK_USB_VENQT_WRITE; + while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { + if (reqtype == REALTEK_USB_VENQT_READ) + memset(pIo_buf, 0, len); + else memcpy(pIo_buf, pdata, len); - } - status = usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT); + status = usb_control_msg(udev, pipe, REALTEK_USB_VENQT_CMD_REQ, + reqtype, value, REALTEK_USB_VENQT_CMD_IDX, + pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT); if (status == len) { /* Success this control transfer. */ - if (requesttype == 0x01) + if (reqtype == REALTEK_USB_VENQT_READ) memcpy(pdata, pIo_buf, len); } else { /* error cases */ DBG_88E("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n", - value, (requesttype == 0x01) ? "read" : "write", + value, (reqtype == REALTEK_USB_VENQT_READ) ? "read" : "write", len, status, *(u32 *)pdata, vendorreq_times); if (status < 0) { - if (status == (-ESHUTDOWN) || status == -ENODEV) + if (status == -ESHUTDOWN || status == -ENODEV) adapt->bSurpriseRemoved = true; else adapt->HalData->srestpriv.wifi_error_status = USB_VEN_REQ_CMD_FAIL; } else { /* status != len && status >= 0 */ if (status > 0) { - if (requesttype == 0x01) { + if (reqtype == REALTEK_USB_VENQT_READ) { /* For Control read transfer, we have to copy the read data from pIo_buf to pdata. */ memcpy(pdata, pIo_buf, len); } @@ -276,8 +295,9 @@ static int usbctrl_vendorreq(struct adapter *adapt, u8 request, u16 value, u16 i if ((value >= FW_8188E_START_ADDRESS && value <= FW_8188E_END_ADDRESS) || status == len) break; } - kfree(pIo_buf); +free_buf: + kfree(pIo_buf); release_mutex: mutex_unlock(&dvobjpriv->usb_vendor_req_mutex); exit: @@ -286,66 +306,35 @@ exit: u8 usb_read8(struct adapter *adapter, u32 addr) { - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - u8 data = 0; - - request = 0x05; - requesttype = 0x01;/* read_in */ - index = 0;/* n/a */ - - wvalue = (u16)(addr & 0x0000ffff); - len = 1; + u16 wvalue = (u16)(addr & 0xffff); + u8 data; - usbctrl_vendorreq(adapter, request, wvalue, index, &data, len, requesttype); + usbctrl_vendorreq(adapter, wvalue, &data, 1, REALTEK_USB_VENQT_READ); return data; } u16 usb_read16(struct adapter *adapter, u32 addr) { - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; + u16 wvalue = (u16)(addr & 0xffff); __le32 data; - request = 0x05; - requesttype = 0x01;/* read_in */ - index = 0;/* n/a */ - wvalue = (u16)(addr & 0x0000ffff); - len = 2; - usbctrl_vendorreq(adapter, request, wvalue, index, &data, len, requesttype); + usbctrl_vendorreq(adapter, wvalue, &data, 2, REALTEK_USB_VENQT_READ); return (u16)(le32_to_cpu(data) & 0xffff); } u32 usb_read32(struct adapter *adapter, u32 addr) { - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; + u16 wvalue = (u16)(addr & 0xffff); __le32 data; - request = 0x05; - requesttype = 0x01;/* read_in */ - index = 0;/* n/a */ - - wvalue = (u16)(addr & 0x0000ffff); - len = 4; - - usbctrl_vendorreq(adapter, request, wvalue, index, &data, len, requesttype); + usbctrl_vendorreq(adapter, wvalue, &data, 4, REALTEK_USB_VENQT_READ); return le32_to_cpu(data); } -static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) +static void usb_read_port_complete(struct urb *purb) { struct recv_buf *precvbuf = (struct recv_buf *)purb->context; struct adapter *adapt = (struct adapter *)precvbuf->adapter; @@ -508,67 +497,29 @@ void rtw_hal_inirp_deinit(struct adapter *padapter) int usb_write8(struct adapter *adapter, u32 addr, u8 val) { - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - u8 data; + u16 wvalue = (u16)(addr & 0xffff); + u8 data = val; - request = 0x05; - requesttype = 0x00;/* write_out */ - index = 0;/* n/a */ - wvalue = (u16)(addr & 0x0000ffff); - len = 1; - data = val; - return usbctrl_vendorreq(adapter, request, wvalue, - index, &data, len, requesttype); + return usbctrl_vendorreq(adapter, wvalue, &data, 1, REALTEK_USB_VENQT_WRITE); } int usb_write16(struct adapter *adapter, u32 addr, u16 val) { - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - __le32 data; - - request = 0x05; - requesttype = 0x00;/* write_out */ - index = 0;/* n/a */ + u16 wvalue = (u16)(addr & 0xffff); + __le32 data = cpu_to_le32(val & 0xffff); - wvalue = (u16)(addr & 0x0000ffff); - len = 2; - - data = cpu_to_le32(val & 0x0000ffff); - - return usbctrl_vendorreq(adapter, request, wvalue, - index, &data, len, requesttype); + return usbctrl_vendorreq(adapter, wvalue, &data, 2, REALTEK_USB_VENQT_WRITE); } int usb_write32(struct adapter *adapter, u32 addr, u32 val) { - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - __le32 data; - - request = 0x05; - requesttype = 0x00;/* write_out */ - index = 0;/* n/a */ + u16 wvalue = (u16)(addr & 0xffff); + __le32 data = cpu_to_le32(val); - wvalue = (u16)(addr & 0x0000ffff); - len = 4; - data = cpu_to_le32(val); - - return usbctrl_vendorreq(adapter, request, wvalue, - index, &data, len, requesttype); + return usbctrl_vendorreq(adapter, wvalue, &data, 4, REALTEK_USB_VENQT_WRITE); } -static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) +static void usb_write_port_complete(struct urb *purb) { struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; struct adapter *padapter = pxmitbuf->padapter; @@ -724,20 +675,14 @@ u32 usb_write_port(struct adapter *padapter, u32 addr, u32 cnt, struct xmit_buf ("%s(): usb_submit_urb, status =%x\n", __func__, status)); - switch (status) { - case -ENODEV: + if (status == -ENODEV) padapter->bDriverStopped = true; - break; - default: - break; - } + goto exit; } ret = _SUCCESS; -/* We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */ - RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-%s\n", __func__)); exit: diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c index b0efa2eb705ec4f4b11c385d0f7e14004423a254..a9c42fb80583371bd1c6174b2674ac43cf4e6670 100644 --- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c @@ -164,7 +164,7 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev) { - struct adapter *padapter = rtw_netdev_priv(pnetdev); + struct adapter *padapter = netdev_priv(pnetdev); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; s32 res = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index ff843d7ec6060602dc8e96d1656e43a770b0974f..b626ac45db8047a11f27a4bad6863cc0b4de9a57 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -690,7 +690,7 @@ bool rtl92e_start_adapter(struct net_device *dev) u8 tmpvalue; u8 ICVersion, SwitchingRegulatorOutput; bool bfirmwareok = true; - u32 tmpRegA, tmpRegC, TempCCk; + u32 tmpRegA, TempCCk; int i = 0; u32 retry_times = 0; @@ -800,12 +800,10 @@ start: } rtl92e_writew(dev, ATIMWND, 2); rtl92e_writew(dev, BCN_INTERVAL, 100); - { - int i; - for (i = 0; i < QOS_QUEUE_NUM; i++) - rtl92e_writel(dev, WDCAPARA_ADD[i], 0x005e4332); - } + for (i = 0; i < QOS_QUEUE_NUM; i++) + rtl92e_writel(dev, WDCAPARA_ADD[i], 0x005e4332); + rtl92e_writeb(dev, 0xbe, 0xc0); rtl92e_config_mac(dev); @@ -889,8 +887,8 @@ start: if (priv->IC_Cut >= IC_VersionCut_D) { tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord); - tmpRegC = rtl92e_get_bb_reg(dev, rOFDM0_XCTxIQImbalance, - bMaskDWord); + rtl92e_get_bb_reg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord); + for (i = 0; i < TxBBGainTableLength; i++) { if (tmpRegA == dm_tx_bb_gain[i]) { priv->rfa_txpowertrackingindex = (u8)i; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 9078fadd65f961cbc0f103cb0755635073c08587..e85d9c2cdc96b192139fd04eda068f03db4ad703 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -375,9 +375,8 @@ static void _rtl92e_update_beacon(void *data) if (ieee->pHTInfo->bCurrentHTSupport) HT_update_self_and_peer_setting(ieee, net); - ieee->pHTInfo->bCurrentRT2RTLongSlotTime = - net->bssht.bdRT2RTLongSlotTime; - ieee->pHTInfo->RT2RT_HT_Mode = net->bssht.RT2RT_HT_Mode; + ieee->pHTInfo->bCurrentRT2RTLongSlotTime = net->bssht.bd_rt2rt_long_slot_time; + ieee->pHTInfo->RT2RT_HT_Mode = net->bssht.rt2rt_ht_mode; _rtl92e_update_cap(dev, net->capability); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index e340be3ebb971608194e088e10047a694a24681f..c53aa2d305ca271a4d2919d59000f5033afe1a3a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -260,7 +260,7 @@ void rtl92e_dm_watchdog(struct net_device *dev) static void _rtl92e_dm_check_ac_dc_power(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); - static char const ac_dc_script[] = "/etc/acpi/wireless-rtl-ac-dc-power.sh"; + static const char ac_dc_script[] = "/etc/acpi/wireless-rtl-ac-dc-power.sh"; char *argv[] = {(char *)ac_dc_script, DRV_NAME, NULL}; static char *envp[] = {"HOME=/", "TERM=linux", @@ -1801,7 +1801,7 @@ static void _rtl92e_dm_check_rf_ctrl_gpio(void *data) enum rt_rf_power_state eRfPowerStateToSet; bool bActuallySet = false; char *argv[3]; - static char const RadioPowerPath[] = "/etc/acpi/events/RadioPower.sh"; + static const char RadioPowerPath[] = "/etc/acpi/events/RadioPower.sh"; static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL}; diff --git a/drivers/staging/rtl8192e/rtl819x_BA.h b/drivers/staging/rtl8192e/rtl819x_BA.h index 8b6e4c26f0fbf74b06340bc88d03ae8a2c280399..8a35d7a3eee10fe968f38a6dd892bb628d3c9df9 100644 --- a/drivers/staging/rtl8192e/rtl819x_BA.h +++ b/drivers/staging/rtl8192e/rtl819x_BA.h @@ -20,41 +20,41 @@ #define DELBA_REASON_UNKNOWN_BA 38 #define DELBA_REASON_TIMEOUT 39 union sequence_control { - u16 ShortData; + u16 short_data; struct { - u16 FragNum:4; - u16 SeqNum:12; + u16 frag_num:4; + u16 seq_num:12; } field; }; union ba_param_set { - u8 charData[2]; - u16 shortData; + u8 char_data[2]; + u16 short_data; struct { - u16 AMSDU_Support:1; - u16 BAPolicy:1; - u16 TID:4; - u16 BufferSize:10; + u16 amsdu_support:1; + u16 ba_policy:1; + u16 tid:4; + u16 buffer_size:10; } field; }; union delba_param_set { - u8 charData[2]; - u16 shortData; + u8 char_data[2]; + u16 short_data; struct { - u16 Reserved:11; - u16 Initiator:1; - u16 TID:4; + u16 reserved:11; + u16 initiator:1; + u16 tid:4; } field; }; struct ba_record { - struct timer_list Timer; - u8 bValid; - u8 DialogToken; - union ba_param_set BaParamSet; - u16 BaTimeoutValue; - union sequence_control BaStartSeqCtrl; + 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 index 2d5e4a0330c62c5dd8f79eb990691dcd9055e834..7dfe7a0558767817036870e3920cde84ae3f96bf 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -13,15 +13,15 @@ static void ActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA, u16 Time) { - pBA->bValid = true; + pBA->b_valid = true; if (Time != 0) - mod_timer(&pBA->Timer, jiffies + msecs_to_jiffies(Time)); + mod_timer(&pBA->timer, jiffies + msecs_to_jiffies(Time)); } static void DeActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA) { - pBA->bValid = false; - del_timer_sync(&pBA->Timer); + pBA->b_valid = false; + del_timer_sync(&pBA->timer); } static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) @@ -30,12 +30,12 @@ static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) struct ba_record *pPendingBa = &pTxTs->TxPendingBARecord; u8 bSendDELBA = false; - if (pPendingBa->bValid) { + if (pPendingBa->b_valid) { DeActivateBAEntry(ieee, pPendingBa); bSendDELBA = true; } - if (pAdmittedBa->bValid) { + if (pAdmittedBa->b_valid) { DeActivateBAEntry(ieee, pAdmittedBa); bSendDELBA = true; } @@ -44,10 +44,10 @@ static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) static u8 RxTsDeleteBA(struct rtllib_device *ieee, struct rx_ts_record *pRxTs) { - struct ba_record *pBa = &pRxTs->RxAdmittedBARecord; + struct ba_record *pBa = &pRxTs->rx_admitted_ba_record; u8 bSendDELBA = false; - if (pBa->bValid) { + if (pBa->b_valid) { DeActivateBAEntry(ieee, pBa); bSendDELBA = true; } @@ -57,11 +57,11 @@ static u8 RxTsDeleteBA(struct rtllib_device *ieee, struct rx_ts_record *pRxTs) void ResetBaEntry(struct ba_record *pBA) { - pBA->bValid = false; - pBA->BaParamSet.shortData = 0; - pBA->BaTimeoutValue = 0; - pBA->DialogToken = 0; - pBA->BaStartSeqCtrl.ShortData = 0; + pBA->b_valid = false; + pBA->ba_param_set.short_data = 0; + pBA->ba_timeout_value = 0; + pBA->dialog_token = 0; + pBA->ba_start_seq_ctrl.short_data = 0; } static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, struct ba_record *pBA, @@ -98,7 +98,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, tag = skb_put(skb, 9); *tag++ = ACT_CAT_BA; *tag++ = type; - *tag++ = pBA->DialogToken; + *tag++ = pBA->dialog_token; if (type == ACT_ADDBARSP) { RT_TRACE(COMP_DBG, "====>to send ADDBARSP\n"); @@ -107,14 +107,14 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, tag += 2; } - put_unaligned_le16(pBA->BaParamSet.shortData, tag); + put_unaligned_le16(pBA->ba_param_set.short_data, tag); tag += 2; - put_unaligned_le16(pBA->BaTimeoutValue, tag); + put_unaligned_le16(pBA->ba_timeout_value, tag); tag += 2; if (type == ACT_ADDBAREQ) { - memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2); + memcpy(tag, (u8 *)&(pBA->ba_start_seq_ctrl), 2); tag += 2; } @@ -141,8 +141,8 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, memset(&DelbaParamSet, 0, 2); - DelbaParamSet.field.Initiator = (TxRxSelect == TX_DIR) ? 1 : 0; - DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; + DelbaParamSet.field.initiator = (TxRxSelect == TX_DIR) ? 1 : 0; + DelbaParamSet.field.tid = pBA->ba_param_set.field.tid; skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); if (!skb) @@ -163,7 +163,7 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, *tag++ = ACT_DELBA; - put_unaligned_le16(DelbaParamSet.shortData, tag); + put_unaligned_le16(DelbaParamSet.short_data, tag); tag += 2; put_unaligned_le16(ReasonCode, tag); @@ -260,14 +260,14 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb) goto OnADDBAReq_Fail; } if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, - (u8)(pBaParamSet->field.TID), RX_DIR, true)) { + (u8)(pBaParamSet->field.tid), RX_DIR, true)) { rc = ADDBA_STATUS_REFUSED; netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__); goto OnADDBAReq_Fail; } - pBA = &pTS->RxAdmittedBARecord; + pBA = &pTS->rx_admitted_ba_record; - if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { + if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) { rc = ADDBA_STATUS_INVALID_PARAM; netdev_warn(ieee->dev, "%s(): BA Policy is not correct\n", __func__); @@ -277,16 +277,16 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb) rtllib_FlushRxTsPendingPkts(ieee, pTS); DeActivateBAEntry(ieee, pBA); - pBA->DialogToken = *pDialogToken; - pBA->BaParamSet = *pBaParamSet; - pBA->BaTimeoutValue = *pBaTimeoutVal; - pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; + pBA->dialog_token = *pDialogToken; + pBA->ba_param_set = *pBaParamSet; + pBA->ba_timeout_value = *pBaTimeoutVal; + pBA->ba_start_seq_ctrl = *pBaStartSeqCtrl; if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) || (ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) - pBA->BaParamSet.field.BufferSize = 1; + pBA->ba_param_set.field.buffer_size = 1; else - pBA->BaParamSet.field.BufferSize = 32; + pBA->ba_param_set.field.buffer_size = 32; ActivateBAEntry(ieee, pBA, 0); rtllib_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); @@ -297,10 +297,10 @@ OnADDBAReq_Fail: { struct ba_record BA; - BA.BaParamSet = *pBaParamSet; - BA.BaTimeoutValue = *pBaTimeoutVal; - BA.DialogToken = *pDialogToken; - BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; + BA.ba_param_set = *pBaParamSet; + BA.ba_timeout_value = *pBaTimeoutVal; + BA.dialog_token = *pDialogToken; + BA.ba_param_set.field.ba_policy = BA_POLICY_IMMEDIATE; rtllib_send_ADDBARsp(ieee, dst, &BA, rc); return 0; } @@ -346,7 +346,7 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, - (u8)(pBaParamSet->field.TID), TX_DIR, false)) { + (u8)(pBaParamSet->field.tid), TX_DIR, false)) { netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__); ReasonCode = DELBA_REASON_UNKNOWN_BA; goto OnADDBARsp_Reject; @@ -357,12 +357,12 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) pAdmittedBA = &pTS->TxAdmittedBARecord; - if (pAdmittedBA->bValid) { + if (pAdmittedBA->b_valid) { netdev_dbg(ieee->dev, "%s(): ADDBA response already admitted\n", __func__); return -1; - } else if (!pPendingBA->bValid || - (*pDialogToken != pPendingBA->DialogToken)) { + } else if (!pPendingBA->b_valid || + (*pDialogToken != pPendingBA->dialog_token)) { netdev_warn(ieee->dev, "%s(): ADDBA Rsp. BA invalid, DELBA!\n", __func__); @@ -377,7 +377,7 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) if (*pStatusCode == ADDBA_STATUS_SUCCESS) { - if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { + if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) { pTS->bAddBaReqDelayed = true; DeActivateBAEntry(ieee, pAdmittedBA); ReasonCode = DELBA_REASON_END_BA; @@ -385,10 +385,10 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) } - pAdmittedBA->DialogToken = *pDialogToken; - pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; - pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; - pAdmittedBA->BaParamSet = *pBaParamSet; + pAdmittedBA->dialog_token = *pDialogToken; + pAdmittedBA->ba_timeout_value = *pBaTimeoutVal; + pAdmittedBA->ba_start_seq_ctrl = pPendingBA->ba_start_seq_ctrl; + pAdmittedBA->ba_param_set = *pBaParamSet; DeActivateBAEntry(ieee, pAdmittedBA); ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); } else { @@ -404,7 +404,7 @@ OnADDBARsp_Reject: { struct ba_record BA; - BA.BaParamSet = *pBaParamSet; + BA.ba_param_set = *pBaParamSet; rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); return 0; } @@ -440,15 +440,15 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) dst = (u8 *)(&delba->addr2[0]); pDelBaParamSet = (union delba_param_set *)&delba->payload[2]; - if (pDelBaParamSet->field.Initiator == 1) { + if (pDelBaParamSet->field.initiator == 1) { struct rx_ts_record *pRxTs; if (!GetTs(ieee, (struct ts_common_info **)&pRxTs, dst, - (u8)pDelBaParamSet->field.TID, RX_DIR, false)) { + (u8)pDelBaParamSet->field.tid, RX_DIR, false)) { netdev_warn(ieee->dev, "%s(): can't get TS for RXTS. dst:%pM TID:%d\n", __func__, dst, - (u8)pDelBaParamSet->field.TID); + (u8)pDelBaParamSet->field.tid); return -1; } @@ -457,7 +457,7 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) struct tx_ts_record *pTxTs; if (!GetTs(ieee, (struct ts_common_info **)&pTxTs, dst, - (u8)pDelBaParamSet->field.TID, TX_DIR, false)) { + (u8)pDelBaParamSet->field.tid, TX_DIR, false)) { netdev_warn(ieee->dev, "%s(): can't get TS for TXTS\n", __func__); return -1; @@ -477,19 +477,18 @@ void TsInitAddBA(struct rtllib_device *ieee, struct tx_ts_record *pTS, { struct ba_record *pBA = &pTS->TxPendingBARecord; - if (pBA->bValid && !bOverwritePending) + if (pBA->b_valid && !bOverwritePending) return; DeActivateBAEntry(ieee, pBA); - pBA->DialogToken++; - pBA->BaParamSet.field.AMSDU_Support = 0; - pBA->BaParamSet.field.BAPolicy = Policy; - pBA->BaParamSet.field.TID = - pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; - pBA->BaParamSet.field.BufferSize = 32; - pBA->BaTimeoutValue = 0; - pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; + pBA->dialog_token++; + pBA->ba_param_set.field.amsdu_support = 0; + pBA->ba_param_set.field.ba_policy = Policy; + pBA->ba_param_set.field.tid = pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; + pBA->ba_param_set.field.buffer_size = 32; + pBA->ba_timeout_value = 0; + pBA->ba_start_seq_ctrl.field.seq_num = (pTS->TxCurSeq + 3) % 4096; ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); @@ -506,7 +505,7 @@ void TsInitDelBA(struct rtllib_device *ieee, if (TxTsDeleteBA(ieee, pTxTs)) rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, - (pTxTs->TxAdmittedBARecord.bValid) ? + (pTxTs->TxAdmittedBARecord.b_valid) ? (&pTxTs->TxAdmittedBARecord) : (&pTxTs->TxPendingBARecord), TxRxSelect, DELBA_REASON_END_BA); @@ -515,7 +514,7 @@ void TsInitDelBA(struct rtllib_device *ieee, (struct rx_ts_record *)pTsCommonInfo; if (RxTsDeleteBA(ieee, pRxTs)) rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, - &pRxTs->RxAdmittedBARecord, + &pRxTs->rx_admitted_ba_record, TxRxSelect, DELBA_REASON_END_BA); } } @@ -523,17 +522,17 @@ void TsInitDelBA(struct rtllib_device *ieee, void BaSetupTimeOut(struct timer_list *t) { struct tx_ts_record *pTxTs = from_timer(pTxTs, t, - TxPendingBARecord.Timer); + TxPendingBARecord.timer); pTxTs->bAddBaReqInProgress = false; pTxTs->bAddBaReqDelayed = true; - pTxTs->TxPendingBARecord.bValid = false; + pTxTs->TxPendingBARecord.b_valid = false; } void TxBaInactTimeout(struct timer_list *t) { struct tx_ts_record *pTxTs = from_timer(pTxTs, t, - TxAdmittedBARecord.Timer); + TxAdmittedBARecord.timer); struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, TxTsRecord[pTxTs->num]); TxTsDeleteBA(ieee, pTxTs); @@ -545,12 +544,12 @@ void TxBaInactTimeout(struct timer_list *t) void RxBaInactTimeout(struct timer_list *t) { struct rx_ts_record *pRxTs = from_timer(pRxTs, t, - RxAdmittedBARecord.Timer); + rx_admitted_ba_record.timer); struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, RxTsRecord[pRxTs->num]); RxTsDeleteBA(ieee, pRxTs); - rtllib_send_DELBA(ieee, pRxTs->TsCommonInfo.Addr, - &pRxTs->RxAdmittedBARecord, RX_DIR, + rtllib_send_DELBA(ieee, pRxTs->ts_common_info.Addr, + &pRxTs->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 index 11269fe6b395a9862472e224d3881e6692beb725..ce13b41074a7b1c44907d4d4b94b458a5bc4c1cd 100644 --- a/drivers/staging/rtl8192e/rtl819x_HT.h +++ b/drivers/staging/rtl8192e/rtl819x_HT.h @@ -179,21 +179,20 @@ struct rt_hi_throughput { } __packed; struct bss_ht { + u8 bd_support_ht; - u8 bdSupportHT; + u8 bd_ht_cap_buf[32]; + u16 bd_ht_cap_len; + u8 bd_ht_info_buf[32]; + u16 bd_ht_info_len; - u8 bdHTCapBuf[32]; - u16 bdHTCapLen; - u8 bdHTInfoBuf[32]; - u16 bdHTInfoLen; + enum ht_spec_ver bd_ht_spec_ver; + enum ht_channel_width bd_bandwidth; - enum ht_spec_ver bdHTSpecVer; - enum ht_channel_width bdBandWidth; - - u8 bdRT2RTAggregation; - u8 bdRT2RTLongSlotTime; - u8 RT2RT_HT_Mode; - u8 bdHT1R; + u8 bd_rt2rt_aggregation; + u8 bd_rt2rt_long_slot_time; + u8 rt2rt_ht_mode; + u8 bd_ht_1r; }; extern u8 MCS_FILTER_ALL[16]; diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index 9377e48c3f329f7373003cc46860286255ffa0e6..48d28c7d870b3f7b3bacf5a06545daa19ec78a5f 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -138,7 +138,7 @@ u16 TxCountToDataRate(struct rtllib_device *ieee, u8 nDataRate) is40MHz = 1; isShortGI = 1; } - return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate&0xf]; + return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate & 0xf]; } bool IsHTHalfNmodeAPs(struct rtllib_device *ieee) @@ -158,7 +158,7 @@ bool IsHTHalfNmodeAPs(struct rtllib_device *ieee) !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) || (net->broadcom_cap_exist)) retValue = true; - else if (net->bssht.bdRT2RTAggregation) + else if (net->bssht.bd_rt2rt_aggregation) retValue = true; else retValue = false; @@ -171,11 +171,11 @@ static void HTIOTPeerDetermine(struct rtllib_device *ieee) struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; struct rtllib_network *net = &ieee->current_network; - if (net->bssht.bdRT2RTAggregation) { + if (net->bssht.bd_rt2rt_aggregation) { pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK; - if (net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_92SE) + if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_92SE) pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK_92SE; - if (net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_SOFTAP) + if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_SOFTAP) pHTInfo->IOTPeer = HT_IOT_PEER_92U_SOFTAP; } else if (net->broadcom_cap_exist) { pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; @@ -214,7 +214,6 @@ static u8 HTIOTActIsDisableMCS14(struct rtllib_device *ieee, u8 *PeerMacAddr) return 0; } - static bool HTIOTActIsDisableMCS15(struct rtllib_device *ieee) { return false; @@ -236,7 +235,6 @@ static u8 HTIOTActIsMgntUseCCK6M(struct rtllib_device *ieee, { u8 retValue = 0; - if (ieee->pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) retValue = 1; @@ -263,7 +261,6 @@ static void HTIOTActDetermineRaFunc(struct rtllib_device *ieee, bool bPeerRx2ss) if (pHTInfo->IOTAction & HT_IOT_ACT_AMSDU_ENABLE) pHTInfo->IOTRaFunc |= HT_IOT_RAFUNC_TX_AMSDU; - } void HTResetIOTSetting(struct rt_hi_throughput *pHTInfo) @@ -316,7 +313,6 @@ void HTConstructCapabilityElement(struct rtllib_device *ieee, u8 *posHTCap, pCapELE->PSMP = 0; pCapELE->LSigTxopProtect = 0; - netdev_dbg(ieee->dev, "TX HT cap/info ele BW=%d MaxAMSDUSize:%d DssCCk:%d\n", pCapELE->ChlWidth, pCapELE->MaxAMSDUSize, pCapELE->DssCCk); @@ -391,7 +387,6 @@ void HTConstructInfoElement(struct rtllib_device *ieee, u8 *posHTInfo, memset(pHTInfoEle->BasicMSC, 0, 16); - *len = 22 + 2; } else { @@ -445,7 +440,6 @@ static u8 HT_PickMCSRate(struct rtllib_device *ieee, u8 *pOperateMCS) break; default: break; - } return true; @@ -479,8 +473,8 @@ u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet, if (availableMcsRate[i] != 0) { bitMap = availableMcsRate[i]; for (j = 0; j < 8; j++) { - if ((bitMap%2) != 0) { - if (HTMcsToDataRate(ieee, (8*i+j)) > + if ((bitMap % 2) != 0) { + if (HTMcsToDataRate(ieee, (8 * i + j)) > HTMcsToDataRate(ieee, mcsRate)) mcsRate = 8 * i + j; } @@ -494,7 +488,6 @@ u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet, static u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS, u8 *pOperateMCS) { - u8 i; for (i = 0; i <= 15; i++) @@ -544,7 +537,6 @@ void HTOnAssocRsp(struct rtllib_device *ieee) else pPeerHTInfo = (struct ht_info_ele *)(pHTInfo->PeerHTInfoBuf); - #ifdef VERBOSE_DEBUG print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE, pPeerHTCap, sizeof(struct ht_capab_ele)); @@ -565,7 +557,6 @@ void HTOnAssocRsp(struct rtllib_device *ieee) ((pPeerHTCap->DssCCk == 1) ? true : false) : false); - pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; nMaxAMSDUSize = (pPeerHTCap->MaxAMSDUSize == 0) ? 3839 : 7935; @@ -577,7 +568,7 @@ void HTOnAssocRsp(struct rtllib_device *ieee) pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; if (ieee->rtllib_ap_sec_type && - (ieee->rtllib_ap_sec_type(ieee)&(SEC_ALG_WEP|SEC_ALG_TKIP))) { + (ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_WEP | SEC_ALG_TKIP))) { if ((pHTInfo->IOTPeer == HT_IOT_PEER_ATHEROS) || (pHTInfo->IOTPeer == HT_IOT_PEER_UNKNOWN)) pHTInfo->bCurrentAMPDUEnable = false; @@ -591,7 +582,7 @@ void HTOnAssocRsp(struct rtllib_device *ieee) pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; } else { - if (ieee->current_network.bssht.bdRT2RTAggregation) { + if (ieee->current_network.bssht.bd_rt2rt_aggregation) { if (ieee->pairwise_key_type != KEY_TYPE_NA) pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; @@ -639,7 +630,6 @@ void HTInitializeHTInfo(struct rtllib_device *ieee) { struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; - netdev_vdbg(ieee->dev, "%s()\n", __func__); pHTInfo->bCurrentHTSupport = false; pHTInfo->bCurBW40MHz = false; @@ -688,18 +678,17 @@ void HTInitializeHTInfo(struct rtllib_device *ieee) void HTInitializeBssDesc(struct bss_ht *pBssHT) { + pBssHT->bd_support_ht = false; + memset(pBssHT->bd_ht_cap_buf, 0, sizeof(pBssHT->bd_ht_cap_buf)); + pBssHT->bd_ht_cap_len = 0; + memset(pBssHT->bd_ht_info_buf, 0, sizeof(pBssHT->bd_ht_info_buf)); + pBssHT->bd_ht_info_len = 0; - pBssHT->bdSupportHT = false; - memset(pBssHT->bdHTCapBuf, 0, sizeof(pBssHT->bdHTCapBuf)); - pBssHT->bdHTCapLen = 0; - memset(pBssHT->bdHTInfoBuf, 0, sizeof(pBssHT->bdHTInfoBuf)); - pBssHT->bdHTInfoLen = 0; + pBssHT->bd_ht_spec_ver = HT_SPEC_VER_IEEE; - pBssHT->bdHTSpecVer = HT_SPEC_VER_IEEE; - - pBssHT->bdRT2RTAggregation = false; - pBssHT->bdRT2RTLongSlotTime = false; - pBssHT->RT2RT_HT_Mode = (enum rt_ht_capability)0; + pBssHT->bd_rt2rt_aggregation = false; + pBssHT->bd_rt2rt_long_slot_time = false; + pBssHT->rt2rt_ht_mode = (enum rt_ht_capability)0; } void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, @@ -708,33 +697,32 @@ void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; u8 bIOTAction = 0; - netdev_vdbg(ieee->dev, "%s()\n", __func__); /* unmark bEnableHT flag here is the same reason why unmarked in * function rtllib_softmac_new_net. WB 2008.09.10 */ - if (pNetwork->bssht.bdSupportHT) { + if (pNetwork->bssht.bd_support_ht) { pHTInfo->bCurrentHTSupport = true; - pHTInfo->ePeerHTSpecVer = pNetwork->bssht.bdHTSpecVer; + pHTInfo->ePeerHTSpecVer = pNetwork->bssht.bd_ht_spec_ver; - if (pNetwork->bssht.bdHTCapLen > 0 && - pNetwork->bssht.bdHTCapLen <= sizeof(pHTInfo->PeerHTCapBuf)) + if (pNetwork->bssht.bd_ht_cap_len > 0 && + pNetwork->bssht.bd_ht_cap_len <= sizeof(pHTInfo->PeerHTCapBuf)) memcpy(pHTInfo->PeerHTCapBuf, - pNetwork->bssht.bdHTCapBuf, - pNetwork->bssht.bdHTCapLen); + pNetwork->bssht.bd_ht_cap_buf, + pNetwork->bssht.bd_ht_cap_len); - if (pNetwork->bssht.bdHTInfoLen > 0 && - pNetwork->bssht.bdHTInfoLen <= + if (pNetwork->bssht.bd_ht_info_len > 0 && + pNetwork->bssht.bd_ht_info_len <= sizeof(pHTInfo->PeerHTInfoBuf)) memcpy(pHTInfo->PeerHTInfoBuf, - pNetwork->bssht.bdHTInfoBuf, - pNetwork->bssht.bdHTInfoLen); + pNetwork->bssht.bd_ht_info_buf, + pNetwork->bssht.bd_ht_info_len); if (pHTInfo->bRegRT2RTAggregation) { pHTInfo->bCurrentRT2RTAggregation = - pNetwork->bssht.bdRT2RTAggregation; + pNetwork->bssht.bd_rt2rt_aggregation; pHTInfo->bCurrentRT2RTLongSlotTime = - pNetwork->bssht.bdRT2RTLongSlotTime; - pHTInfo->RT2RT_HT_Mode = pNetwork->bssht.RT2RT_HT_Mode; + pNetwork->bssht.bd_rt2rt_long_slot_time; + pHTInfo->RT2RT_HT_Mode = pNetwork->bssht.rt2rt_ht_mode; } else { pHTInfo->bCurrentRT2RTAggregation = false; pHTInfo->bCurrentRT2RTLongSlotTime = false; @@ -756,7 +744,6 @@ void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, if (bIOTAction) pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_ALL_2SS; - bIOTAction = HTIOTActIsDisableEDCATurbo(ieee, pNetwork->bssid); if (bIOTAction) pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_EDCA_TURBO; @@ -783,10 +770,10 @@ void HT_update_self_and_peer_setting(struct rtllib_device *ieee, { struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; struct ht_info_ele *pPeerHTInfo = - (struct ht_info_ele *)pNetwork->bssht.bdHTInfoBuf; + (struct ht_info_ele *)pNetwork->bssht.bd_ht_info_buf; if (pHTInfo->bCurrentHTSupport) { - if (pNetwork->bssht.bdHTInfoLen != 0) + if (pNetwork->bssht.bd_ht_info_len != 0) pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; } } @@ -843,8 +830,6 @@ static void HTSetConnectBwModeCallback(struct rtllib_device *ieee) { struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; - netdev_vdbg(ieee->dev, "%s()\n", __func__); - if (pHTInfo->bCurBW40MHz) { if (pHTInfo->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_UPPER) ieee->set_chan(ieee->dev, diff --git a/drivers/staging/rtl8192e/rtl819x_TS.h b/drivers/staging/rtl8192e/rtl819x_TS.h index 9dc93d41939d4979702c29fee30b123ee1bf82c2..4aa9b12a2dd56435ff8e7262cb8d1658eb0dc397 100644 --- a/drivers/staging/rtl8192e/rtl819x_TS.h +++ b/drivers/staging/rtl8192e/rtl819x_TS.h @@ -42,15 +42,15 @@ struct tx_ts_record { }; struct rx_ts_record { - struct ts_common_info TsCommonInfo; - u16 RxIndicateSeq; - u16 RxTimeoutIndicateSeq; - struct list_head RxPendingPktList; - struct timer_list RxPktPendingTimer; - struct ba_record RxAdmittedBARecord; - u16 RxLastSeqNum; - u8 RxLastFragNum; - u8 num; + 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; }; diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c index 47b2669a3a8e8501df9bb893f1636b40475c765f..34b00a76b6bd7c116ca435ec3555a0da5a512cd5 100644 --- a/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -19,7 +19,7 @@ static void TsInactTimeout(struct timer_list *unused) static void RxPktPendingTimeout(struct timer_list *t) { struct rx_ts_record *pRxTs = from_timer(pRxTs, t, - RxPktPendingTimer); + rx_pkt_pending_timer); struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, RxTsRecord[pRxTs->num]); @@ -30,24 +30,24 @@ static void RxPktPendingTimeout(struct timer_list *t) bool bPktInBuf = false; spin_lock_irqsave(&(ieee->reorder_spinlock), flags); - if (pRxTs->RxTimeoutIndicateSeq != 0xffff) { - while (!list_empty(&pRxTs->RxPendingPktList)) { + if (pRxTs->rx_timeout_indicate_seq != 0xffff) { + while (!list_empty(&pRxTs->rx_pending_pkt_list)) { pReorderEntry = (struct rx_reorder_entry *) - list_entry(pRxTs->RxPendingPktList.prev, + list_entry(pRxTs->rx_pending_pkt_list.prev, struct rx_reorder_entry, List); if (index == 0) - pRxTs->RxIndicateSeq = pReorderEntry->SeqNum; + pRxTs->rx_indicate_seq = pReorderEntry->SeqNum; if (SN_LESS(pReorderEntry->SeqNum, - pRxTs->RxIndicateSeq) || + pRxTs->rx_indicate_seq) || SN_EQUAL(pReorderEntry->SeqNum, - pRxTs->RxIndicateSeq)) { + pRxTs->rx_indicate_seq)) { list_del_init(&pReorderEntry->List); if (SN_EQUAL(pReorderEntry->SeqNum, - pRxTs->RxIndicateSeq)) - pRxTs->RxIndicateSeq = - (pRxTs->RxIndicateSeq + 1) % 4096; + pRxTs->rx_indicate_seq)) + pRxTs->rx_indicate_seq = + (pRxTs->rx_indicate_seq + 1) % 4096; netdev_dbg(ieee->dev, "%s(): Indicate SeqNum: %d\n", @@ -66,7 +66,7 @@ static void RxPktPendingTimeout(struct timer_list *t) } if (index > 0) { - pRxTs->RxTimeoutIndicateSeq = 0xffff; + pRxTs->rx_timeout_indicate_seq = 0xffff; if (index > REORDER_WIN_SIZE) { netdev_warn(ieee->dev, @@ -80,9 +80,9 @@ static void RxPktPendingTimeout(struct timer_list *t) bPktInBuf = false; } - if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) { - pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; - mod_timer(&pRxTs->RxPktPendingTimer, jiffies + + if (bPktInBuf && (pRxTs->rx_timeout_indicate_seq == 0xffff)) { + pRxTs->rx_timeout_indicate_seq = pRxTs->rx_indicate_seq; + mod_timer(&pRxTs->rx_pkt_pending_timer, jiffies + msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime) ); } @@ -104,7 +104,7 @@ static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo) { eth_zero_addr(pTsCommonInfo->Addr); memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body)); - memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM); + memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas) * TCLAS_NUM); pTsCommonInfo->TClasProc = 0; pTsCommonInfo->TClasNum = 0; } @@ -123,10 +123,10 @@ static void ResetTxTsEntry(struct tx_ts_record *pTS) static void ResetRxTsEntry(struct rx_ts_record *pTS) { - ResetTsCommonInfo(&pTS->TsCommonInfo); - pTS->RxIndicateSeq = 0xffff; - pTS->RxTimeoutIndicateSeq = 0xffff; - ResetBaEntry(&pTS->RxAdmittedBARecord); + ResetTsCommonInfo(&pTS->ts_common_info); + pTS->rx_indicate_seq = 0xffff; + pTS->rx_timeout_indicate_seq = 0xffff; + ResetBaEntry(&pTS->rx_admitted_ba_record); } void TSInitialize(struct rtllib_device *ieee) @@ -136,7 +136,6 @@ void TSInitialize(struct rtllib_device *ieee) struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; u8 count = 0; - netdev_vdbg(ieee->dev, "%s()\n", __func__); INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); @@ -151,9 +150,9 @@ void TSInitialize(struct rtllib_device *ieee) timer_setup(&pTxTS->TsAddBaTimer, TsAddBaProcess, 0); - timer_setup(&pTxTS->TxPendingBARecord.Timer, BaSetupTimeOut, + timer_setup(&pTxTS->TxPendingBARecord.timer, BaSetupTimeOut, 0); - timer_setup(&pTxTS->TxAdmittedBARecord.Timer, + timer_setup(&pTxTS->TxAdmittedBARecord.timer, TxBaInactTimeout, 0); ResetTxTsEntry(pTxTS); @@ -167,21 +166,21 @@ void TSInitialize(struct rtllib_device *ieee) INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); for (count = 0; count < TOTAL_TS_NUM; count++) { pRxTS->num = count; - INIT_LIST_HEAD(&pRxTS->RxPendingPktList); + INIT_LIST_HEAD(&pRxTS->rx_pending_pkt_list); - timer_setup(&pRxTS->TsCommonInfo.SetupTimer, TsSetupTimeOut, + timer_setup(&pRxTS->ts_common_info.SetupTimer, TsSetupTimeOut, 0); - timer_setup(&pRxTS->TsCommonInfo.InactTimer, TsInactTimeout, + timer_setup(&pRxTS->ts_common_info.InactTimer, TsInactTimeout, 0); - timer_setup(&pRxTS->RxAdmittedBARecord.Timer, + timer_setup(&pRxTS->rx_admitted_ba_record.timer, RxBaInactTimeout, 0); - timer_setup(&pRxTS->RxPktPendingTimer, RxPktPendingTimeout, 0); + timer_setup(&pRxTS->rx_pkt_pending_timer, RxPktPendingTimeout, 0); ResetRxTsEntry(pRxTS); - list_add_tail(&pRxTS->TsCommonInfo.List, + list_add_tail(&pRxTS->ts_common_info.List, &ieee->Rx_TS_Unused_List); pRxTS++; } @@ -189,11 +188,10 @@ void TSInitialize(struct rtllib_device *ieee) for (count = 0; count < REORDER_ENTRY_NUM; count++) { list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List); - if (count == (REORDER_ENTRY_NUM-1)) + if (count == (REORDER_ENTRY_NUM - 1)) break; - pRxReorderEntry = &ieee->RxReorderEntry[count+1]; + pRxReorderEntry = &ieee->RxReorderEntry[count + 1]; } - } static void AdmitTS(struct rtllib_device *ieee, @@ -254,7 +252,6 @@ static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee, pRet->TSpec.f.TSInfo.field.ucTSID == TID && pRet->TSpec.f.TSInfo.field.ucDirection == dir) break; - } if (&pRet->List != psearch_list) break; @@ -271,12 +268,12 @@ static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr, { u8 count; - if (pTsCommonInfo == NULL) + if (!pTsCommonInfo) return; memcpy(pTsCommonInfo->Addr, Addr, 6); - if (pTSPEC != NULL) + if (pTSPEC) memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC, sizeof(union tspec_body)); @@ -330,7 +327,7 @@ bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, } *ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect); - if (*ppTS != NULL) + if (*ppTS) return true; if (!bAddNewTs) { @@ -364,7 +361,7 @@ bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, struct rx_ts_record *tmp = container_of(*ppTS, struct rx_ts_record, - TsCommonInfo); + ts_common_info); ResetRxTsEntry(tmp); } @@ -405,12 +402,12 @@ static void RemoveTsEntry(struct rtllib_device *ieee, struct rx_reorder_entry *pRxReorderEntry; struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs; - if (timer_pending(&pRxTS->RxPktPendingTimer)) - del_timer_sync(&pRxTS->RxPktPendingTimer); + if (timer_pending(&pRxTS->rx_pkt_pending_timer)) + del_timer_sync(&pRxTS->rx_pkt_pending_timer); - while (!list_empty(&pRxTS->RxPendingPktList)) { + while (!list_empty(&pRxTS->rx_pending_pkt_list)) { pRxReorderEntry = (struct rx_reorder_entry *) - list_entry(pRxTS->RxPendingPktList.prev, + list_entry(pRxTS->rx_pending_pkt_list.prev, struct rx_reorder_entry, List); netdev_dbg(ieee->dev, "%s(): Delete SeqNum %d!\n", __func__, pRxReorderEntry->SeqNum); @@ -518,7 +515,7 @@ void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) msecs_to_jiffies(TS_ADDBA_DELAY)); } else { netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); - mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); + mod_timer(&pTxTS->TsAddBaTimer, jiffies + 10); } } else netdev_dbg(ieee->dev, "BA timer is already added\n"); diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c index 238387d6221beaafd9e94d4429f5d712bc4a281d..4a760ecbc31e3011867f7b3d9b1acc7b6e61f25a 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c @@ -291,7 +291,7 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); } else - tkey->tx_phase1_done = 1; + tkey->tx_phase1_done = 1; len = skb->len - hdr_len; diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 15bbb63ca130ad43657e11278149e8a6ae508df1..6e48b31a9afc749513181a6d234c8a259f60c5a1 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -449,9 +449,9 @@ drop: static bool AddReorderEntry(struct rx_ts_record *pTS, struct rx_reorder_entry *pReorderEntry) { - struct list_head *pList = &pTS->RxPendingPktList; + struct list_head *pList = &pTS->rx_pending_pkt_list; - while (pList->next != &pTS->RxPendingPktList) { + while (pList->next != &pTS->rx_pending_pkt_list) { if (SN_LESS(pReorderEntry->SeqNum, ((struct rx_reorder_entry *) list_entry(pList->next, struct rx_reorder_entry, List))->SeqNum)) @@ -536,8 +536,8 @@ void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee, struct rx_reorder_entry *pRxReorderEntry; u8 RfdCnt = 0; - del_timer_sync(&pTS->RxPktPendingTimer); - while (!list_empty(&pTS->RxPendingPktList)) { + del_timer_sync(&pTS->rx_pkt_pending_timer); + while (!list_empty(&pTS->rx_pending_pkt_list)) { if (RfdCnt >= REORDER_WIN_SIZE) { netdev_info(ieee->dev, "-------------->%s() error! RfdCnt >= REORDER_WIN_SIZE\n", @@ -546,7 +546,7 @@ void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee, } pRxReorderEntry = (struct rx_reorder_entry *) - list_entry(pTS->RxPendingPktList.prev, + list_entry(pTS->rx_pending_pkt_list.prev, struct rx_reorder_entry, List); netdev_dbg(ieee->dev, "%s(): Indicate SeqNum %d!\n", __func__, pRxReorderEntry->SeqNum); @@ -560,7 +560,7 @@ void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee, } rtllib_indicate_packets(ieee, ieee->RfdArray, RfdCnt); - pTS->RxIndicateSeq = 0xffff; + pTS->rx_indicate_seq = 0xffff; } static void RxReorderIndicatePacket(struct rtllib_device *ieee, @@ -576,21 +576,21 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, unsigned long flags; netdev_dbg(ieee->dev, - "%s(): Seq is %d, pTS->RxIndicateSeq is %d, WinSize is %d\n", - __func__, SeqNum, pTS->RxIndicateSeq, WinSize); + "%s(): Seq is %d, pTS->rx_indicate_seq is %d, WinSize is %d\n", + __func__, SeqNum, pTS->rx_indicate_seq, WinSize); spin_lock_irqsave(&(ieee->reorder_spinlock), flags); - WinEnd = (pTS->RxIndicateSeq + WinSize - 1) % 4096; + WinEnd = (pTS->rx_indicate_seq + WinSize - 1) % 4096; /* Rx Reorder initialize condition.*/ - if (pTS->RxIndicateSeq == 0xffff) - pTS->RxIndicateSeq = SeqNum; + if (pTS->rx_indicate_seq == 0xffff) + pTS->rx_indicate_seq = SeqNum; /* Drop out the packet which SeqNum is smaller than WinStart */ - if (SN_LESS(SeqNum, pTS->RxIndicateSeq)) { + if (SN_LESS(SeqNum, pTS->rx_indicate_seq)) { netdev_dbg(ieee->dev, "Packet Drop! IndicateSeq: %d, NewSeq: %d\n", - pTS->RxIndicateSeq, SeqNum); + pTS->rx_indicate_seq, SeqNum); pHTInfo->RxReorderDropCounter++; { int i; @@ -608,18 +608,18 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, * 1. Incoming SeqNum is equal to WinStart =>Window shift 1 * 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ - if (SN_EQUAL(SeqNum, pTS->RxIndicateSeq)) { - pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; + if (SN_EQUAL(SeqNum, pTS->rx_indicate_seq)) { + pTS->rx_indicate_seq = (pTS->rx_indicate_seq + 1) % 4096; bMatchWinStart = true; } else if (SN_LESS(WinEnd, SeqNum)) { if (SeqNum >= (WinSize - 1)) - pTS->RxIndicateSeq = SeqNum + 1 - WinSize; + pTS->rx_indicate_seq = SeqNum + 1 - WinSize; else - pTS->RxIndicateSeq = 4095 - + pTS->rx_indicate_seq = 4095 - (WinSize - (SeqNum + 1)) + 1; netdev_dbg(ieee->dev, "Window Shift! IndicateSeq: %d, NewSeq: %d\n", - pTS->RxIndicateSeq, SeqNum); + pTS->rx_indicate_seq, SeqNum); } /* Indication process. @@ -636,7 +636,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, /* Current packet is going to be indicated.*/ netdev_dbg(ieee->dev, "Packets indication! IndicateSeq: %d, NewSeq: %d\n", - pTS->RxIndicateSeq, SeqNum); + pTS->rx_indicate_seq, SeqNum); ieee->prxbIndicateArray[0] = prxb; index = 1; } else { @@ -658,7 +658,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, netdev_dbg(ieee->dev, "%s(): Duplicate packet is dropped. IndicateSeq: %d, NewSeq: %d\n", - __func__, pTS->RxIndicateSeq, + __func__, pTS->rx_indicate_seq, SeqNum); list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List); @@ -670,7 +670,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, } else { netdev_dbg(ieee->dev, "Pkt insert into struct buffer. IndicateSeq: %d, NewSeq: %d\n", - pTS->RxIndicateSeq, SeqNum); + pTS->rx_indicate_seq, SeqNum); } } else { /* Packets are dropped if there are not enough reorder @@ -693,16 +693,16 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, } /* Check if there is any packet need indicate.*/ - while (!list_empty(&pTS->RxPendingPktList)) { + while (!list_empty(&pTS->rx_pending_pkt_list)) { netdev_dbg(ieee->dev, "%s(): start RREORDER indicate\n", __func__); pReorderEntry = (struct rx_reorder_entry *) - list_entry(pTS->RxPendingPktList.prev, + list_entry(pTS->rx_pending_pkt_list.prev, struct rx_reorder_entry, List); - if (SN_LESS(pReorderEntry->SeqNum, pTS->RxIndicateSeq) || - SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) { + if (SN_LESS(pReorderEntry->SeqNum, pTS->rx_indicate_seq) || + SN_EQUAL(pReorderEntry->SeqNum, pTS->rx_indicate_seq)) { /* This protect struct buffer from overflow. */ if (index >= REORDER_WIN_SIZE) { netdev_err(ieee->dev, @@ -714,8 +714,8 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, list_del_init(&pReorderEntry->List); - if (SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) - pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % + if (SN_EQUAL(pReorderEntry->SeqNum, pTS->rx_indicate_seq)) + pTS->rx_indicate_seq = (pTS->rx_indicate_seq + 1) % 4096; ieee->prxbIndicateArray[index] = pReorderEntry->prxb; @@ -735,9 +735,9 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, * Rx buffering. */ if (index > 0) { - if (timer_pending(&pTS->RxPktPendingTimer)) - del_timer_sync(&pTS->RxPktPendingTimer); - pTS->RxTimeoutIndicateSeq = 0xffff; + if (timer_pending(&pTS->rx_pkt_pending_timer)) + del_timer_sync(&pTS->rx_pkt_pending_timer); + pTS->rx_timeout_indicate_seq = 0xffff; if (index > REORDER_WIN_SIZE) { netdev_err(ieee->dev, @@ -751,10 +751,10 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, bPktInBuf = false; } - if (bPktInBuf && pTS->RxTimeoutIndicateSeq == 0xffff) { + if (bPktInBuf && pTS->rx_timeout_indicate_seq == 0xffff) { netdev_dbg(ieee->dev, "%s(): SET rx timeout timer\n", __func__); - pTS->RxTimeoutIndicateSeq = pTS->RxIndicateSeq; - mod_timer(&pTS->RxPktPendingTimer, jiffies + + pTS->rx_timeout_indicate_seq = pTS->rx_indicate_seq; + mod_timer(&pTS->rx_pkt_pending_timer, jiffies + msecs_to_jiffies(pHTInfo->RxReorderPendingTime)); } spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); @@ -938,11 +938,11 @@ static int rtllib_rx_check_duplicate(struct rtllib_device *ieee, if (GetTs(ieee, (struct ts_common_info **) &pRxTS, hdr->addr2, (u8)Frame_QoSTID((u8 *)(skb->data)), RX_DIR, true)) { - if ((fc & (1<<11)) && (frag == pRxTS->RxLastFragNum) && - (WLAN_GET_SEQ_SEQ(sc) == pRxTS->RxLastSeqNum)) + if ((fc & (1<<11)) && (frag == pRxTS->rx_last_frag_num) && + (WLAN_GET_SEQ_SEQ(sc) == pRxTS->rx_last_seq_num)) return -1; - pRxTS->RxLastFragNum = frag; - pRxTS->RxLastSeqNum = WLAN_GET_SEQ_SEQ(sc); + pRxTS->rx_last_frag_num = frag; + pRxTS->rx_last_seq_num = WLAN_GET_SEQ_SEQ(sc); } else { netdev_warn(ieee->dev, "%s(): No TS! Skip the check!\n", __func__); @@ -1850,19 +1850,20 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee, *tmp_htcap_len = min_t(u8, info_element->len, MAX_IE_LEN); if (*tmp_htcap_len != 0) { - network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; - network->bssht.bdHTCapLen = min_t(u16, *tmp_htcap_len, sizeof(network->bssht.bdHTCapBuf)); - memcpy(network->bssht.bdHTCapBuf, + 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.bdHTCapLen); + network->bssht.bd_ht_cap_len); } } if (*tmp_htcap_len != 0) { - network->bssht.bdSupportHT = true; - network->bssht.bdHT1R = ((((struct ht_capab_ele *)(network->bssht.bdHTCapBuf))->MCS[1]) == 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.bdSupportHT = false; - network->bssht.bdHT1R = false; + network->bssht.bd_support_ht = false; + network->bssht.bd_ht_1r = false; } } @@ -1876,16 +1877,17 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee, *tmp_htinfo_len = min_t(u8, info_element->len, MAX_IE_LEN); if (*tmp_htinfo_len != 0) { - network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; - network->bssht.bdHTInfoLen = min_t(u16, *tmp_htinfo_len, sizeof(network->bssht.bdHTInfoBuf)); - memcpy(network->bssht.bdHTInfoBuf, + 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.bdHTInfoLen); + network->bssht.bd_ht_info_len); } } } - if (network->bssht.bdSupportHT) { + if (network->bssht.bd_support_ht) { if (info_element->len >= 4 && info_element->data[0] == 0x00 && info_element->data[1] == 0xe0 && @@ -1898,20 +1900,20 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee, } if (ht_realtek_agg_len >= 5) { network->realtek_cap_exit = true; - network->bssht.bdRT2RTAggregation = true; + network->bssht.bd_rt2rt_aggregation = true; if ((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02)) - network->bssht.bdRT2RTLongSlotTime = true; + 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; + 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; + network->bssht.rt2rt_ht_mode |= RT_HT_CAP_USE_SOFTAP; } if ((info_element->len >= 3 && @@ -2020,22 +2022,22 @@ static void rtllib_parse_mfie_ht_cap(struct rtllib_info_element *info_element, *tmp_htcap_len = min_t(u8, info_element->len, MAX_IE_LEN); if (*tmp_htcap_len != 0) { - ht->bdHTSpecVer = HT_SPEC_VER_EWC; - ht->bdHTCapLen = min_t(u16, *tmp_htcap_len, - sizeof(ht->bdHTCapBuf)); - memcpy(ht->bdHTCapBuf, info_element->data, ht->bdHTCapLen); + 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->bdSupportHT = true; - ht->bdHT1R = ((((struct ht_capab_ele *) - ht->bdHTCapBuf))->MCS[1]) == 0; + ht->bd_support_ht = true; + ht->bd_ht_1r = ((((struct ht_capab_ele *) + ht->bd_ht_cap_buf))->MCS[1]) == 0; - ht->bdBandWidth = (enum ht_channel_width) + ht->bd_bandwidth = (enum ht_channel_width) (((struct ht_capab_ele *) - (ht->bdHTCapBuf))->ChlWidth); + (ht->bd_ht_cap_buf))->ChlWidth); } else { - ht->bdSupportHT = false; - ht->bdHT1R = false; - ht->bdBandWidth = HT_CHANNEL_WIDTH_20; + ht->bd_support_ht = false; + ht->bd_ht_1r = false; + ht->bd_bandwidth = HT_CHANNEL_WIDTH_20; } } @@ -2232,14 +2234,14 @@ int rtllib_parse_info_param(struct rtllib_device *ieee, tmp_htinfo_len = min_t(u8, info_element->len, MAX_IE_LEN); if (tmp_htinfo_len) { - network->bssht.bdHTSpecVer = HT_SPEC_VER_IEEE; - network->bssht.bdHTInfoLen = tmp_htinfo_len > - sizeof(network->bssht.bdHTInfoBuf) ? - sizeof(network->bssht.bdHTInfoBuf) : + 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.bdHTInfoBuf, + memcpy(network->bssht.bd_ht_info_buf, info_element->data, - network->bssht.bdHTInfoLen); + network->bssht.bd_ht_info_len); } break; @@ -2289,7 +2291,7 @@ int rtllib_parse_info_param(struct rtllib_device *ieee, if (!network->atheros_cap_exist && !network->broadcom_cap_exist && !network->cisco_cap_exist && !network->ralink_cap_exist && - !network->bssht.bdRT2RTAggregation) + !network->bssht.bd_rt2rt_aggregation) network->unknown_cap_exist = true; else network->unknown_cap_exist = false; @@ -2380,7 +2382,7 @@ static inline int rtllib_network_init( return 1; } - if (network->bssht.bdSupportHT) { + if (network->bssht.bd_support_ht) { if (network->mode == IEEE_A) network->mode = IEEE_N_5G; else if (network->mode & (IEEE_G | IEEE_B)) @@ -2456,16 +2458,16 @@ static inline void update_network(struct rtllib_device *ieee, dst->last_dtim_sta_time = src->last_dtim_sta_time; memcpy(&dst->tim, &src->tim, sizeof(struct rtllib_tim_parameters)); - dst->bssht.bdSupportHT = src->bssht.bdSupportHT; - dst->bssht.bdRT2RTAggregation = src->bssht.bdRT2RTAggregation; - dst->bssht.bdHTCapLen = src->bssht.bdHTCapLen; - memcpy(dst->bssht.bdHTCapBuf, src->bssht.bdHTCapBuf, - src->bssht.bdHTCapLen); - dst->bssht.bdHTInfoLen = src->bssht.bdHTInfoLen; - memcpy(dst->bssht.bdHTInfoBuf, src->bssht.bdHTInfoBuf, - src->bssht.bdHTInfoLen); - dst->bssht.bdHTSpecVer = src->bssht.bdHTSpecVer; - dst->bssht.bdRT2RTLongSlotTime = src->bssht.bdRT2RTLongSlotTime; + 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; diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 2d3be91b113d1f2024486206a1d27b36c25ffc1c..f9a51f3620d29ab6e8b36a9939730c67b7694bd3 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -1692,7 +1692,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee, ieee->current_network.channel, ieee->current_network.qos_data.supported, ieee->pHTInfo->bEnableHT, - ieee->current_network.bssht.bdSupportHT, + ieee->current_network.bssht.bd_support_ht, ieee->current_network.mode, ieee->current_network.flags); @@ -1706,7 +1706,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee, /* Join the network for the first time */ ieee->AsocRetryCount = 0; if ((ieee->current_network.qos_data.supported == 1) && - ieee->current_network.bssht.bdSupportHT) + ieee->current_network.bssht.bd_support_ht) HTResetSelfAndSavePeerSetting(ieee, &(ieee->current_network)); else @@ -2238,11 +2238,11 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb, return 1; } memcpy(ieee->pHTInfo->PeerHTCapBuf, - network->bssht.bdHTCapBuf, - network->bssht.bdHTCapLen); + network->bssht.bd_ht_cap_buf, + network->bssht.bd_ht_cap_len); memcpy(ieee->pHTInfo->PeerHTInfoBuf, - network->bssht.bdHTInfoBuf, - network->bssht.bdHTInfoLen); + network->bssht.bd_ht_info_buf, + network->bssht.bd_ht_info_len); if (ieee->handle_assoc_response != NULL) ieee->handle_assoc_response(ieee->dev, (struct rtllib_assoc_response_frame *)header, @@ -2443,7 +2443,7 @@ inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee, * 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 - * to the driver later, when it wakes the queue. + * the driver later, when it wakes the queue. */ void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee) { diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 8add17752eed577c902ff97c33082637e6fe775f..89ec72b1895aff00c8e4a36e264134d5d4bc98f7 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -297,7 +297,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee, netdev_info(ieee->dev, "%s: can't get TS\n", __func__); return; } - if (!pTxTs->TxAdmittedBARecord.bValid) { + if (!pTxTs->TxAdmittedBARecord.b_valid) { if (ieee->wpa_ie_len && (ieee->pairwise_key_type == KEY_TYPE_NA)) { ; @@ -308,7 +308,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee, } goto FORCED_AGG_SETTING; } else if (!pTxTs->bUsingBa) { - if (SN_LESS(pTxTs->TxAdmittedBARecord.BaStartSeqCtrl.field.SeqNum, + if (SN_LESS(pTxTs->TxAdmittedBARecord.ba_start_seq_ctrl.field.seq_num, (pTxTs->TxCurSeq+1)%4096)) pTxTs->bUsingBa = true; else @@ -339,7 +339,7 @@ FORCED_AGG_SETTING: } } -static void rtllib_qurey_ShortPreambleMode(struct rtllib_device *ieee, +static void rtllib_query_ShortPreambleMode(struct rtllib_device *ieee, struct cb_desc *tcb_desc) { tcb_desc->bUseShortPreamble = false; @@ -928,7 +928,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) tcb_desc->bdhcp = 1; } - rtllib_qurey_ShortPreambleMode(ieee, tcb_desc); + rtllib_query_ShortPreambleMode(ieee, tcb_desc); rtllib_tx_query_agg_cap(ieee, txb->fragments[0], tcb_desc); rtllib_query_HTCapShortGI(ieee, tcb_desc); diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index 2e486ccb643205ffe546876ac2e78b13062fa934..ab1b8217c4e089fac57bf8850aeaa9c4b834493f 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -140,12 +140,12 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, bool is40M = false, isShortGI = false; u8 max_mcs = 0; - if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4)) + if (!memcmp(network->bssht.bd_ht_cap_buf, EWC11NHTCap, 4)) ht_cap = (struct ht_capab_ele *) - &network->bssht.bdHTCapBuf[4]; + &network->bssht.bd_ht_cap_buf[4]; else ht_cap = (struct ht_capab_ele *) - &network->bssht.bdHTCapBuf[0]; + &network->bssht.bd_ht_cap_buf[0]; is40M = (ht_cap->ChlWidth) ? 1 : 0; isShortGI = (ht_cap->ChlWidth) ? ((ht_cap->ShortGI40Mhz) ? 1 : 0) : @@ -160,8 +160,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, iwe.cmd = SIOCGIWRATE; iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; iwe.u.bitrate.value = max_rate * 500000; - start = iwe_stream_add_event_rsl(info, start, stop, &iwe, - IW_EV_PARAM_LEN); + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_PARAM_LEN); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = p - custom; if (iwe.u.data.length) @@ -181,15 +180,13 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL)) iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; iwe.u.qual.updated = 7; - start = iwe_stream_add_event_rsl(info, start, stop, &iwe, - IW_EV_QUAL_LEN); + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN); iwe.cmd = IWEVCUSTOM; p = custom; iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point_rsl(info, start, stop, - &iwe, custom); + start = iwe_stream_add_point_rsl(info, start, stop, &iwe, custom); memset(&iwe, 0, sizeof(iwe)); if (network->wpa_ie_len) { @@ -238,8 +235,8 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, } int rtllib_wx_get_scan(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct rtllib_network *network; unsigned long flags; @@ -285,8 +282,8 @@ int rtllib_wx_get_scan(struct rtllib_device *ieee, 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_request_info *info, + union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); struct net_device *dev = ieee->dev; @@ -324,11 +321,11 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, * 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] != NULL) { + if (ieee->crypt_info.crypt[i]) { if (key_provided) break; lib80211_crypt_delayed_deinit(&ieee->crypt_info, - &ieee->crypt_info.crypt[i]); + &ieee->crypt_info.crypt[i]); } } @@ -344,7 +341,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, sec.enabled = 1; sec.flags |= SEC_ENABLED; - if (*crypt != NULL && (*crypt)->ops != NULL && + if (*crypt && (*crypt)->ops && strcmp((*crypt)->ops->name, "R-WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key @@ -352,12 +349,12 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } - if (*crypt == NULL) { + if (!*crypt) { struct lib80211_crypt_data *new_crypt; /* take WEP into use */ new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); - if (new_crypt == NULL) + if (!new_crypt) return -ENOMEM; new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); if (!new_crypt->ops) { @@ -406,8 +403,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, 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); + 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, @@ -460,8 +456,8 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, 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_request_info *info, + union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); int len, key; @@ -484,7 +480,7 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee, erq->flags = key + 1; - if (crypt == NULL || crypt->ops == NULL) { + if (!crypt || !crypt->ops) { erq->length = 0; erq->flags |= IW_ENCODE_DISABLED; return 0; @@ -505,8 +501,8 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee, 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) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; struct net_device *dev = ieee->dev; @@ -549,7 +545,7 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ieee->crypt_info.crypt[i] != NULL) + if (ieee->crypt_info.crypt[i]) break; } if (i == NUM_WEP_KEYS) { @@ -582,7 +578,7 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, netdev_dbg(dev, "alg name:%s\n", alg); ops = lib80211_get_crypto_ops(alg); - if (ops == NULL) { + if (!ops) { char tempbuf[100]; memset(tempbuf, 0x00, 100); @@ -590,19 +586,19 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, request_module("%s", tempbuf); ops = lib80211_get_crypto_ops(alg); } - if (ops == NULL) { + if (!ops) { netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg); ret = -EINVAL; goto done; } - if (*crypt == NULL || (*crypt)->ops != ops) { + 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 == NULL) { + if (!new_crypt) { ret = -ENOMEM; goto done; } @@ -610,7 +606,7 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) new_crypt->priv = new_crypt->ops->init(idx); - if (new_crypt->priv == NULL) { + if (!new_crypt->priv) { kfree(new_crypt); ret = -EINVAL; goto done; @@ -663,8 +659,8 @@ done: 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) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { u8 i = 0; bool deauth = false; @@ -710,8 +706,8 @@ int rtllib_wx_set_mlme(struct rtllib_device *ieee, 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) + struct iw_request_info *info, + struct iw_param *data, char *extra) { switch (data->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -766,17 +762,15 @@ 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 == NULL)) + 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))) { - + 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 == NULL) + if (!buf) return -ENOMEM; ieee->wps_ie = buf; return 0; @@ -789,7 +783,7 @@ int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) if (len != ie[1]+2) return -EINVAL; buf = kmemdup(ie, len, GFP_KERNEL); - if (buf == NULL) + if (!buf) return -ENOMEM; kfree(ieee->wpa_ie); ieee->wpa_ie = buf; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index b6fee7230ce0588d570fcc9ac8658e8aaa964236..b0e01ee65f7f8b10d28694866b4153f92349c560 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -612,9 +612,9 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee, pHTInfo->RxReorderDropCounter++; { int i; - for (i = 0; i < prxb->nr_subframes; i++) { + for (i = 0; i < prxb->nr_subframes; i++) dev_kfree_skb(prxb->subframes[i]); - } + kfree(prxb); prxb = NULL; } @@ -632,11 +632,11 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee, pTS->rx_indicate_seq = (pTS->rx_indicate_seq + 1) % 4096; bMatchWinStart = true; } else if (SN_LESS(WinEnd, SeqNum)) { - if (SeqNum >= (WinSize - 1)) { + if (SeqNum >= (WinSize - 1)) pTS->rx_indicate_seq = SeqNum + 1 - WinSize; - } else { + else pTS->rx_indicate_seq = 4095 - (WinSize - (SeqNum + 1)) + 1; - } + IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->rx_indicate_seq, SeqNum); } @@ -674,9 +674,9 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee, list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List); { int i; - for (i = 0; i < prxb->nr_subframes; i++) { + for (i = 0; i < prxb->nr_subframes; i++) dev_kfree_skb(prxb->subframes[i]); - } + kfree(prxb); prxb = NULL; } @@ -693,9 +693,9 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee, IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n"); { int i; - for (i = 0; i < prxb->nr_subframes; i++) { + for (i = 0; i < prxb->nr_subframes; i++) dev_kfree_skb(prxb->subframes[i]); - } + kfree(prxb); prxb = NULL; } @@ -785,13 +785,12 @@ static u8 parse_subframe(struct ieee80211_device *ieee, bIsAggregateFrame = true; } - if (IEEE80211_QOS_HAS_SEQ(fc)) { + if (IEEE80211_QOS_HAS_SEQ(fc)) LLCOffset += 2; - } - if (rx_stats->bContainHTC) { + if (rx_stats->bContainHTC) LLCOffset += HTCLNG; - } + // Null packet, don't indicate it to upper layer ChkLength = LLCOffset;/* + (Frame_WEP(frame)!=0 ?Adapter->MgntInfo.SecurityInfo.EncryptionHeadOverhead:0);*/ @@ -855,13 +854,11 @@ static u8 parse_subframe(struct ieee80211_device *ieee, if (skb->len != 0) { nPadding_Length = 4 - ((nSubframe_Length + ETHERNET_HEADER_SIZE) % 4); - if (nPadding_Length == 4) { + if (nPadding_Length == 4) nPadding_Length = 0; - } - if (skb->len < nPadding_Length) { + if (skb->len < nPadding_Length) return 0; - } skb_pull(skb, nPadding_Length); } @@ -1248,9 +1245,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, TID = Frame_QoSTID(skb->data); SeqNum = WLAN_GET_SEQ_SEQ(sc); GetTs(ieee, (struct ts_common_info **)&pTS, hdr->addr2, TID, RX_DIR, true); - if (TID != 0 && TID != 3) { + if (TID != 0 && TID != 3) ieee->bis_any_nonbepkts = true; - } } //added by amy for reorder /* skb: hdr + (possible reassembled) full plaintext payload */ @@ -1262,9 +1258,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* 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++) { + for (i = 0; i < rxb->nr_subframes; i++) dev_kfree_skb(rxb->subframes[i]); - } + kfree(rxb); rxb = NULL; goto rx_dropped; @@ -1523,11 +1519,9 @@ static inline void ieee80211_extract_country_ie( // some AP (e.g. Cisco 1242) don't include country IE in their // probe response frame. // - if (IS_EQUAL_CIE_SRC(ieee, addr2)) { + if (IS_EQUAL_CIE_SRC(ieee, addr2)) UPDATE_CIE_WATCHDOG(ieee); - } } - } int ieee80211_parse_info_param(struct ieee80211_device *ieee, diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 690b664df8faee218ce92c9b2c95840d28d080f6..25ea8e1b6b65dd5e88688b4319f2cff6b183f52e 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -2052,7 +2052,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device * #else if ((skb_queue_len(&ieee->skb_waitQ[queue_index]) != 0) || #endif - (!ieee->check_nic_enough_desc(ieee->dev, queue_index)) || \ + (!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 diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index bd8914645e95416b0f05a7341544f0c09764dbcc..96e6aaf859ecc4a5793c8cc0b1074a08043bbe82 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -301,9 +301,9 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee, if (is_multicast_ether_addr(hdr->addr1)) return; //check packet and mode later - if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) { + if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) return; - } + if (pHTInfo->bCurrentAMPDUEnable) { if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true)) { printk("===>can't get TS\n"); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c index 22373c0afebc19dee212da33f39beb36f2a28993..78cc8f357bbce44b4ef9c4cfb4c46fba0fea1a0f 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c @@ -184,9 +184,8 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, // printk("WPA IE\n"); u8 *p = buf; p += sprintf(p, "wpa_ie="); - for (i = 0; i < network->wpa_ie_len; i++) { + for (i = 0; i < network->wpa_ie_len; i++) p += sprintf(p, "%02x", network->wpa_ie[i]); - } memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; @@ -199,9 +198,8 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, u8 *p = buf; p += sprintf(p, "rsn_ie="); - for (i = 0; i < network->rsn_ie_len; i++) { + for (i = 0; i < network->rsn_ie_len; i++) p += sprintf(p, "%02x", network->rsn_ie[i]); - } memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index 379a2ccf4d9f730572d216d44404c2789d1a19cc..6823e405eeb8ec113258d350ec6801366042109e 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -140,7 +140,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, s // Dialog Token *tag++ = pBA->dialog_token; - if (ACT_ADDBARSP == type) { + if (type == ACT_ADDBARSP) { // Status Code netdev_info(ieee->dev, "=====>to send ADDBARSP\n"); @@ -156,7 +156,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, s put_unaligned_le16(pBA->timeout_value, tag); tag += 2; - if (ACT_ADDBAREQ == type) { + if (type == ACT_ADDBAREQ) { // BA Start SeqCtrl memcpy(tag, (u8 *)&(pBA->start_seq_ctrl), 2); tag += 2; diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c index fee3bfb9907578be57ea5be258c4ede06953d6a2..54747fda552fd2a19642c5de7985d6562f3f3391 100644 --- a/drivers/staging/rtl8192u/r8190_rtl8256.c +++ b/drivers/staging/rtl8192u/r8190_rtl8256.c @@ -73,11 +73,11 @@ void phy_set_rf8256_bandwidth(struct net_device *dev, enum ht_channel_width Band else rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x14, bMask12Bits, 0x5ab); } else { - RT_TRACE(COMP_ERR, "phy_set_rf8256_bandwidth(): unknown hardware version\n"); + RT_TRACE(COMP_ERR, "%s(): unknown hardware version\n", __func__); } break; default: - RT_TRACE(COMP_ERR, "phy_set_rf8256_bandwidth(): unknown Bandwidth: %#X\n", Bandwidth); + RT_TRACE(COMP_ERR, "%s(): unknown Bandwidth: %#X\n", __func__, Bandwidth); break; } } @@ -213,7 +213,7 @@ static void phy_rf8256_config_para_file(struct net_device *dev) } if (ret) { - RT_TRACE(COMP_ERR, "phy_rf8256_config_para_file():Radio[%d] Fail!!", eRFPath); + RT_TRACE(COMP_ERR, "%s():Radio[%d] Fail!!", __func__, eRFPath); goto phy_RF8256_Config_ParaFile_Fail; } } @@ -291,5 +291,4 @@ void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel) } rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); } - return; } diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index ec33fb9122e96092ba1919f3aa20fc730ac9ae9e..4013107cd93a256f1a54bd3accbe4a78c72f2c43 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -46,9 +46,9 @@ #define KEY_BUF_SIZE 5 #define RX_SMOOTH_FACTOR 20 -#define DMESG(x, a...) -#define DMESGW(x, a...) -#define DMESGE(x, a...) +#define DMESG(x, a...) no_printk(x, ##a) +#define DMESGW(x, a...) no_printk(x, ##a) +#define DMESGE(x, a...) no_printk(x, ##a) extern u32 rt_global_debug_component; #define RT_TRACE(component, x, args...) \ do { \ diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 9fc4adc83d77d2431d2924d45dd4f3a20dd38919..f48186a89fa1463a547d6a20635e31164e0fd804 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -3210,7 +3210,7 @@ static void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum, u32 *TotalRxDataNum) { u16 SlotIndex; - u8 i; + u16 i; *TotalRxBcnNum = 0; *TotalRxDataNum = 0; @@ -3416,7 +3416,6 @@ int rtl8192_down(struct net_device *dev) void rtl8192_commit(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); - int reset_status = 0; if (priv->up == 0) return; @@ -3428,7 +3427,7 @@ void rtl8192_commit(struct net_device *dev) ieee80211_softmac_stop_protocol(priv->ieee80211); rtl8192_rtx_disable(dev); - reset_status = _rtl8192_up(dev); + _rtl8192_up(dev); } static void rtl8192_restart(struct work_struct *work) diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c index 77bf88696a84492d838c6b5f67335d6d1c027342..203ea3bfc8434d8635a74c2b15fe9ce4644b24e4 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.c +++ b/drivers/staging/rtl8192u/r8192U_wx.c @@ -77,8 +77,8 @@ static int r8192_wx_set_rate(struct net_device *dev, } static int r8192_wx_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret; struct r8192_priv *priv = ieee80211_priv(dev); @@ -93,8 +93,8 @@ static int r8192_wx_set_rts(struct net_device *dev, } static int r8192_wx_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -102,8 +102,8 @@ static int r8192_wx_get_rts(struct net_device *dev, } static int r8192_wx_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret; struct r8192_priv *priv = ieee80211_priv(dev); @@ -118,8 +118,8 @@ static int r8192_wx_set_power(struct net_device *dev, } static int r8192_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -127,8 +127,8 @@ static int r8192_wx_get_power(struct net_device *dev, } static int r8192_wx_force_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -141,8 +141,8 @@ static int r8192_wx_force_reset(struct net_device *dev, } static int r8192_wx_set_rawtx(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); int ret; @@ -276,7 +276,7 @@ static int rtl8180_wx_get_range(struct net_device *dev, range->min_pmp = 0; range->max_pmp = 5000000; range->min_pmt = 0; - range->max_pmt = 65535*1000; + 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; @@ -294,7 +294,7 @@ static int rtl8180_wx_get_range(struct net_device *dev, for (i = 0, val = 0; i < 14; i++) { /* Include only legal frequencies for some countries */ - if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { + if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i + 1]) { range->freq[val].i = i + 1; range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; range->freq[val].e = 1; @@ -309,8 +309,8 @@ static int rtl8180_wx_get_range(struct net_device *dev, } 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->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; tmp->scan_capa = 0x01; return 0; } @@ -429,9 +429,9 @@ static int r8192_wx_set_frag(struct net_device *dev, { struct r8192_priv *priv = ieee80211_priv(dev); - if (wrqu->frag.disabled) + if (wrqu->frag.disabled) { priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; - else { + } else { if (wrqu->frag.value < MIN_FRAG_THRESHOLD || wrqu->frag.value > MAX_FRAG_THRESHOLD) return -EINVAL; @@ -456,9 +456,9 @@ static int r8192_wx_get_frag(struct net_device *dev, } static int r8192_wx_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *awrq, - char *extra) + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) { int ret; struct r8192_priv *priv = ieee80211_priv(dev); @@ -519,14 +519,14 @@ static int r8192_wx_set_enc(struct net_device *dev, /* sometimes, the length is zero while we do not type key value */ 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) + 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) + 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; + hwkey[i] |= (key[4 * i + 1] & mask) << 8; + hwkey[i] |= (key[4 * i + 2] & mask) << 16; + hwkey[i] |= (key[4 * i + 3] & mask) << 24; } #define CONF_WEP40 0x4 @@ -557,23 +557,23 @@ static int r8192_wx_set_enc(struct net_device *dev, EnableHWSecurityConfig8192(dev); setKey(dev, - key_idx, /* EntryNo */ - key_idx, /* KeyIndex */ - KEY_TYPE_WEP40, /* KeyType */ - zero_addr[key_idx], - 0, /* DefaultKey */ - hwkey); /* KeyContent */ + key_idx, /* EntryNo */ + key_idx, /* KeyIndex */ + KEY_TYPE_WEP40, /* KeyType */ + zero_addr[key_idx], + 0, /* DefaultKey */ + hwkey); /* KeyContent */ } else if (wrqu->encoding.length == 0xd) { ieee->pairwise_key_type = KEY_TYPE_WEP104; EnableHWSecurityConfig8192(dev); setKey(dev, - key_idx, /* EntryNo */ - key_idx, /* KeyIndex */ - KEY_TYPE_WEP104, /* KeyType */ - zero_addr[key_idx], - 0, /* DefaultKey */ - hwkey); /* KeyContent */ + key_idx, /* EntryNo */ + key_idx, /* KeyIndex */ + KEY_TYPE_WEP104, /* KeyType */ + zero_addr[key_idx], + 0, /* DefaultKey */ + hwkey); /* KeyContent */ } else { netdev_warn(dev, "wrong type in WEP, not WEP40 and WEP104\n"); } @@ -583,7 +583,7 @@ static int r8192_wx_set_enc(struct net_device *dev, } static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, - union iwreq_data *wrqu, char *p) + union iwreq_data *wrqu, char *p) { struct r8192_priv *priv = ieee80211_priv(dev); int *parms = (int *)p; @@ -595,8 +595,8 @@ static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info } static int r8192_wx_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); int err = 0; @@ -640,8 +640,8 @@ exit: } static int r8192_wx_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -663,8 +663,8 @@ static int r8192_wx_get_retry(struct net_device *dev, } static int r8192_wx_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -675,8 +675,8 @@ static int r8192_wx_get_sens(struct net_device *dev, } static int r8192_wx_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct r8192_priv *priv = ieee80211_priv(dev); short err = 0; @@ -699,8 +699,8 @@ exit: /* hw security need to reorganized. */ static int r8192_wx_set_enc_ext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); @@ -722,13 +722,13 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, goto end_hw_sec; /* as IW_ENCODE_ALG_CCMP is defined to be 3 and KEY_TYPE_CCMP is defined to 4; */ - alg = (ext->alg == IW_ENCODE_ALG_CCMP)?KEY_TYPE_CCMP:ext->alg; + 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) || (IW_MODE_ADHOC == ieee->iw_mode) || (alg == KEY_TYPE_WEP40)) { + if ((!group) || (ieee->iw_mode == IW_MODE_ADHOC) || (alg == KEY_TYPE_WEP40)) { if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40)) alg = KEY_TYPE_WEP104; ieee->pairwise_key_type = alg; @@ -738,29 +738,29 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) { setKey(dev, - idx, /* EntryNao */ - idx, /* KeyIndex */ - alg, /* KeyType */ - zero, /* MacAddr */ - 0, /* DefaultKey */ - key); /* KeyContent */ + idx, /* EntryNao */ + idx, /* KeyIndex */ + alg, /* KeyType */ + zero, /* MacAddr */ + 0, /* DefaultKey */ + key); /* KeyContent */ } else if (group) { ieee->group_key_type = alg; setKey(dev, - idx, /* EntryNo */ - idx, /* KeyIndex */ - alg, /* KeyType */ - broadcast_addr, /* MacAddr */ - 0, /* DefaultKey */ - key); /* KeyContent */ + idx, /* EntryNo */ + idx, /* KeyIndex */ + alg, /* KeyType */ + broadcast_addr, /* MacAddr */ + 0, /* DefaultKey */ + key); /* KeyContent */ } else { /* pairwise key */ setKey(dev, - 4, /* EntryNo */ - idx, /* KeyIndex */ - alg, /* KeyType */ - (u8 *)ieee->ap_mac_addr,/* MacAddr */ - 0, /* DefaultKey */ - key); /* KeyContent */ + 4, /* EntryNo */ + idx, /* KeyIndex */ + alg, /* KeyType */ + (u8 *)ieee->ap_mac_addr,/* MacAddr */ + 0, /* DefaultKey */ + key); /* KeyContent */ } } @@ -771,21 +771,21 @@ end_hw_sec: } static int r8192_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) + struct iw_request_info *info, + union iwreq_data *data, char *extra) { int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); mutex_lock(&priv->wx_mutex); - ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra); + ret = ieee80211_wx_set_auth(priv->ieee80211, info, &data->param, extra); mutex_unlock(&priv->wx_mutex); return ret; } static int r8192_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); @@ -798,8 +798,8 @@ static int r8192_wx_set_mlme(struct net_device *dev, } static int r8192_wx_set_gen_ie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) + struct iw_request_info *info, + union iwreq_data *data, char *extra) { int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); @@ -877,14 +877,11 @@ static iw_handler r8192_wx_handlers[] = { }; - static const struct iw_priv_args r8192_private_args[] = { - { SIOCIWFIRSTPRIV + 0x0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" }, - { SIOCIWFIRSTPRIV + 0x1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" @@ -897,9 +894,7 @@ static const struct iw_priv_args r8192_private_args[] = { { SIOCIWFIRSTPRIV + 0x3, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset" - } - }; static iw_handler r8192_private_handler[] = { diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h index 0c4325073c638c7a9594c781cbeb3e3485051cdd..a44d04effc8bf8be8f95f867ea8891c57d43c29f 100644 --- a/drivers/staging/rtl8712/drv_types.h +++ b/drivers/staging/rtl8712/drv_types.h @@ -36,8 +36,6 @@ enum _NIC_VERSION { RTL8716_NIC }; -struct _adapter; - struct qos_priv { /* bit mask option: u-apsd, s-apsd, ts, block ack... */ unsigned int qos_option; diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c index b4a099169c7c8d1ac4cee68533aa2637cc5e649f..f926809b10219af7ae2727f8381264e5df8eaaa2 100644 --- a/drivers/staging/rtl8712/ieee80211.c +++ b/drivers/staging/rtl8712/ieee80211.c @@ -173,33 +173,33 @@ int r8712_generate_ie(struct registry_priv *registrypriv) ie += 2; /*capability info*/ *(u16 *)ie = 0; - *(__le16 *)ie |= cpu_to_le16(cap_IBSS); + *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_IBSS); if (registrypriv->preamble == PREAMBLE_SHORT) - *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble); + *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); if (dev_network->Privacy) - *(__le16 *)ie |= cpu_to_le16(cap_Privacy); + *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); sz += 2; ie += 2; /*SSID*/ - ie = r8712_set_ie(ie, _SSID_IE_, dev_network->Ssid.SsidLength, + 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, _SUPPORTEDRATES_IE_, 8, + ie = r8712_set_ie(ie, WLAN_EID_SUPP_RATES, 8, dev_network->rates, &sz); - ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), + ie = r8712_set_ie(ie, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), (dev_network->rates + 8), &sz); } else { - ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, + ie = r8712_set_ie(ie, WLAN_EID_SUPP_RATES, rate_len, dev_network->rates, &sz); } /*DS parameter set*/ - ie = r8712_set_ie(ie, _DSSET_IE_, 1, + ie = r8712_set_ie(ie, WLAN_EID_DS_PARAMS, 1, (u8 *)&dev_network->Configuration.DSConfig, &sz); /*IBSS Parameter Set*/ - ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2, + ie = r8712_set_ie(ie, WLAN_EID_IBSS_PARAMS, 2, (u8 *)&dev_network->Configuration.ATIMWindow, &sz); return sz; } diff --git a/drivers/staging/rtl8712/mlme_osdep.h b/drivers/staging/rtl8712/mlme_osdep.h index 9eaf94f072ff373f5c4ac2822a765c2af9d2d436..a02c782588ddbfd0bfcd233948b5a2ccf6f84bcf 100644 --- a/drivers/staging/rtl8712/mlme_osdep.h +++ b/drivers/staging/rtl8712/mlme_osdep.h @@ -22,8 +22,8 @@ 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); + 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); diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h index 3e385b2242d8fa502828f9573156b55124848199..f4d20b0efd4e87a18f20b32069ad8973d1492dda 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.h +++ b/drivers/staging/rtl8712/rtl8712_recv.h @@ -66,6 +66,7 @@ struct phy_stat { __le32 phydw6; __le32 phydw7; }; + #define PHY_STAT_GAIN_TRSW_SHT 0 #define PHY_STAT_PWDB_ALL_SHT 4 #define PHY_STAT_CFOSHO_SHT 5 @@ -84,7 +85,6 @@ union recvstat { unsigned int value[RXDESC_SIZE>>2]; }; - struct recv_buf { struct list_head list; spinlock_t recvbuf_lock; diff --git a/drivers/staging/rtl8712/rtl8712_wmac_regdef.h b/drivers/staging/rtl8712/rtl8712_wmac_regdef.h index 662383fe7a8da34748be918498a529bdf925b059..dfe3e9fbed4313ff370c4c924c9742533ef91ab6 100644 --- a/drivers/staging/rtl8712/rtl8712_wmac_regdef.h +++ b/drivers/staging/rtl8712/rtl8712_wmac_regdef.h @@ -32,6 +32,5 @@ #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 index c247f92207f5ce7bd2493061eba6e4489f1f103b..116cb812dcb9b5196e46c3747c7d8c1f7bdd43af 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/drivers/staging/rtl8712/rtl8712_xmit.c @@ -228,9 +228,9 @@ void r8712_do_queue_select(struct _adapter *padapter, struct dvobj_priv *pdvobj = &padapter->dvobjpriv; if (pdvobj->nr_endpoint == 6) { - qsel = (unsigned int) pattrib->priority; + qsel = (unsigned int)pattrib->priority; } else if (pdvobj->nr_endpoint == 4) { - qsel = (unsigned int) pattrib->priority; + qsel = (unsigned int)pattrib->priority; if (qsel == 0 || qsel == 3) qsel = 3; else if (qsel == 1 || qsel == 2) @@ -317,7 +317,6 @@ void r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf, 0x0000ffff))); } - void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, struct xmit_frame *pxmitframe) { @@ -360,7 +359,7 @@ void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, 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); + u16 total_length = (u16)(ptxdesc->txdw0 & 0xffff); /* use 1st xmitframe as media */ xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); @@ -369,7 +368,7 @@ void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, 0xffff0000)); /* urb length in cmd_dw1 */ - pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff)| + pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff) | ((total_length + TXDESC_SIZE) << 16)); pxmitframe->last[0] = 1; pxmitframe->bpending[0] = false; @@ -507,7 +506,7 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) /*offset 12*/ /* f/w will increase the seqnum by itself, driver pass the - * correct priority to fw + * 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, @@ -560,7 +559,7 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) ptxdesc->txdw2 |= cpu_to_le32(BMC); /* offset 12 */ /* f/w will increase the seqnum by itself, driver pass the - * correct priority to fw + * 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, diff --git a/drivers/staging/rtl8712/rtl8712_xmit.h b/drivers/staging/rtl8712/rtl8712_xmit.h index 0b56bd3ac4d01d9e046bd1713cc872ae9aed5deb..5cd651a0de75a900d1abadb9b1b987afd70e9d11 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.h +++ b/drivers/staging/rtl8712/rtl8712_xmit.h @@ -36,10 +36,8 @@ #define MAX_AMSDU_XMITBUF_SZ 8704 #define MAX_TXAGG_XMITBUF_SZ 16384 /*16k*/ - #define tx_cmd tx_desc - /* *defined for TX DESC Operation */ @@ -89,10 +87,9 @@ struct tx_desc { __le32 txdw7; }; - union txdesc { struct tx_desc txdesc; - unsigned int value[TXDESC_SIZE>>2]; + unsigned int value[TXDESC_SIZE >> 2]; }; int r8712_xmitframe_complete(struct _adapter *padapter, diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h index 254182a6ce8e47de95dd0e2baa95085482cb5f16..bf6f0c6a86e55f766b5bfe596b6c7fcac932b418 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.h +++ b/drivers/staging/rtl8712/rtl871x_cmd.h @@ -333,6 +333,7 @@ struct getdatarate_parm { u32 rsvd; }; + struct getdatarate_rsp { u8 datarates[NumRates]; }; @@ -377,6 +378,7 @@ struct getphy_rsp { struct readBB_parm { u8 offset; }; + struct readBB_rsp { u8 value; }; @@ -384,6 +386,7 @@ struct readBB_rsp { struct readTSSI_parm { u8 offset; }; + struct readTSSI_rsp { u8 value; }; @@ -400,6 +403,7 @@ struct writePTM_parm { struct readRF_parm { u8 offset; }; + struct readRF_rsp { u32 value; }; @@ -498,6 +502,7 @@ struct settxagctbl_parm { struct gettxagctbl_parm { u32 rsvd; }; + struct gettxagctbl_rsp { u32 txagc[MAX_RATES_LENGTH]; }; @@ -513,6 +518,7 @@ struct setssup_parm { struct getssup_parm { u32 rsvd; }; + struct getssup_rsp { u8 ss_ForceUp[MAX_RATES_LENGTH]; }; @@ -524,6 +530,7 @@ struct setssdlevel_parm { struct getssdlevel_parm { u32 rsvd; }; + struct getssdlevel_rsp { u8 ss_DLevel[MAX_RATES_LENGTH]; }; @@ -535,6 +542,7 @@ struct setssulevel_parm { struct getssulevel_parm { u32 rsvd; }; + struct getssulevel_rsp { u8 ss_ULevel[MAX_RATES_LENGTH]; }; @@ -585,6 +593,7 @@ struct setratable_parm { struct getratable_parm { uint rsvd; }; + struct getratable_rsp { u8 ss_ForceUp[NumRates]; u8 ss_ULevel[NumRates]; @@ -621,6 +630,7 @@ struct getbcnokcnt_rsp { struct getbcnerrcnt_parm { unsigned int rsvd; }; + struct getbcnerrcnt_rsp { unsigned long bcnerrcnt; }; diff --git a/drivers/staging/rtl8712/rtl871x_event.h b/drivers/staging/rtl8712/rtl871x_event.h index d9a5476d2426cc1e59dadbe5972bc4fb7b9e24f7..759a2d27d8f22d4c5faabc51951ddd3ca31a2253 100644 --- a/drivers/staging/rtl8712/rtl871x_event.h +++ b/drivers/staging/rtl8712/rtl871x_event.h @@ -102,6 +102,7 @@ struct ADDBA_Req_Report_parm { 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 index 4bcf5591c44dce5865b64a64f23442e459553918..ebd78665775dd02862b9d20af703b0b0e67435be 100644 --- a/drivers/staging/rtl8712/rtl871x_ht.h +++ b/drivers/staging/rtl8712/rtl871x_ht.h @@ -26,7 +26,7 @@ struct ht_priv { unsigned int rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, * updated when join_callback. */ - struct rtl_ieee80211_ht_cap ht_cap; + struct ieee80211_ht_cap ht_cap; }; #endif /*_RTL871X_HT_H_ */ diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h index c20dd5a6bbd1ef9476e7508cd78f81a583a8522a..c5b12f74ebf89265f6b4e5822c3be47265e990b6 100644 --- a/drivers/staging/rtl8712/rtl871x_io.h +++ b/drivers/staging/rtl8712/rtl871x_io.h @@ -123,7 +123,6 @@ struct intf_hdl { }; struct reg_protocol_rd { - #ifdef __LITTLE_ENDIAN /* DW1 */ u32 NumOfTrans:4; diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 60dd798a6e5157c18f2f019ba3d7f30afa2bd574..3b69266132578e9586c58b904835784787f9f1b4 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -36,14 +36,12 @@ #include <linux/if_arp.h> #include <linux/etherdevice.h> - #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}; @@ -144,7 +142,7 @@ static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info, 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) + if (n == MAX_WPA_IE_LEN - 1) break; } memset(iwe, 0, sizeof(*iwe)); @@ -164,7 +162,7 @@ static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info, 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) + if (n == MAX_WPA_IE_LEN - 1) break; } memset(iwe, 0, sizeof(*iwe)); @@ -236,7 +234,7 @@ static char *translate_scan(struct _adapter *padapter, 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], _HT_CAPABILITY_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; @@ -567,7 +565,7 @@ static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie, while (cnt < ielen) { eid = buf[cnt]; - if ((eid == _VENDOR_SPECIFIC_IE_) && + 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 = @@ -609,7 +607,7 @@ static int r8711_wx_get_name(struct net_device *dev, if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == true) { /* parsing HT_CAP_IE */ - p = r8712_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_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; @@ -1391,7 +1389,7 @@ static int r8711_wx_get_rate(struct net_device *dev, struct _adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - struct rtl_ieee80211_ht_cap *pht_capie; + struct ieee80211_ht_cap *pht_capie; unsigned char rf_type = padapter->registrypriv.rf_config; int i; u8 *p; @@ -1403,12 +1401,12 @@ static int r8711_wx_get_rate(struct net_device *dev, i = 0; if (!check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) return -ENOLINK; - p = r8712_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, + 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 rtl_ieee80211_ht_cap *)(p + 2); - memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2); + 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) & diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 6074383ec0b508279340803f86467699f763119e..ba4a71e91ae075e862ba82e2b265e27fb62f0ade 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -124,7 +124,6 @@ static void free_network_nolock(struct mlme_priv *pmlmepriv, pmlmepriv->num_of_scanned--; } - /* return the wlan_network with the matching addr * Shall be called under atomic context... * to avoid possible racing condition... @@ -147,6 +146,8 @@ static struct wlan_network *r8712_find_network(struct __queue *scanned_queue, if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN)) break; } + if (plist == phead) + pnetwork = NULL; spin_unlock_irqrestore(&scanned_queue->lock, irqL); return pnetwork; } @@ -358,7 +359,6 @@ static void update_scanned_network(struct _adapter *adapter, plist = plist->next; } - /* If we didn't find a match, then get a new network slot to initialize * with this beacon's information */ @@ -621,7 +621,6 @@ void r8712_indicate_connect(struct _adapter *padapter) jiffies + msecs_to_jiffies(60000)); } - /* * r8712_ind_disconnect: the caller has to lock pmlmepriv->lock */ @@ -728,7 +727,8 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) r8712_find_network(&pmlmepriv-> scanned_queue, cur_network->network.MacAddress); - pcur_wlan->fixed = false; + if (pcur_wlan) + pcur_wlan->fixed = false; pcur_sta = r8712_get_stainfo(pstapriv, cur_network->network.MacAddress); @@ -1642,23 +1642,23 @@ unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, { u32 ielen, out_len; unsigned char *p; - struct rtl_ieee80211_ht_cap ht_capie; + 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, _HT_CAPABILITY_IE_, &ielen, in_len - 12); + 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, _VENDOR_SPECIFIC_IE_, + 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 rtl_ieee80211_ht_cap)); + 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 | @@ -1667,8 +1667,8 @@ unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, 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, _HT_CAPABILITY_IE_, - sizeof(struct rtl_ieee80211_ht_cap), + 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; } @@ -1682,7 +1682,7 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) int i; uint len; struct sta_info *bmc_sta, *psta; - struct rtl_ieee80211_ht_cap *pht_capie; + struct ieee80211_ht_cap *pht_capie; struct recv_reorder_ctrl *preorder_ctrl; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct ht_priv *phtpriv = &pmlmepriv->htpriv; @@ -1698,11 +1698,11 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) /*check Max Rx A-MPDU Size*/ len = 0; p = r8712_get_ie(pie + sizeof(struct NDIS_802_11_FIXED_IEs), - _HT_CAPABILITY_IE_, + WLAN_EID_HT_CAPABILITY, &len, ie_len - sizeof(struct NDIS_802_11_FIXED_IEs)); if (p && len > 0) { - pht_capie = (struct rtl_ieee80211_ht_cap *)(p + 2); + 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); */ @@ -1733,7 +1733,7 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) } len = 0; p = r8712_get_ie(pie + sizeof(struct NDIS_802_11_FIXED_IEs), - _HT_ADD_INFO_IE_, &len, + WLAN_EID_HT_OPERATION, &len, ie_len - sizeof(struct NDIS_802_11_FIXED_IEs)); } diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h index 46effb469fd4424fe000c6e2968fbf5cb719d16f..d7d25f240111fadf20365c72bb0297582a081d30 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.h +++ b/drivers/staging/rtl8712/rtl871x_mlme.h @@ -77,7 +77,6 @@ struct sitesurvey_ctrl { }; struct mlme_priv { - spinlock_t lock; spinlock_t lock2; sint fw_state; /*shall we protect this variable? */ diff --git a/drivers/staging/rtl8712/rtl871x_mp.c b/drivers/staging/rtl8712/rtl871x_mp.c index 24020257bc58372c52862200b65fef7c28b137e6..099c512c8519fac29681eacd09335f8e76c70e77 100644 --- a/drivers/staging/rtl8712/rtl871x_mp.c +++ b/drivers/staging/rtl8712/rtl871x_mp.c @@ -387,6 +387,7 @@ void r8712_SwitchBandwidth(struct _adapter *pAdapter) break; } } + /*------------------------------Define structure----------------------------*/ struct R_ANTENNA_SELECT_OFDM { u32 r_tx_antenna:4; diff --git a/drivers/staging/rtl8712/rtl871x_mp.h b/drivers/staging/rtl8712/rtl871x_mp.h index e79a67676469d2b7fc8521b87727e4cab4666b7f..0a60b1e6ccafc5a92b34fa8f19241e950e82c17d 100644 --- a/drivers/staging/rtl8712/rtl871x_mp.h +++ b/drivers/staging/rtl8712/rtl871x_mp.h @@ -121,6 +121,7 @@ struct bb_reg_param { u32 offset; u32 value; }; + /* ======================================================================= */ #define LOWER true diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c index f906d3fbe1799864fe62a586a0ac7e0883f00060..31414a960c9edb8f002fea867dd0f1648116e34b 100644 --- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c +++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c @@ -681,6 +681,7 @@ uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) *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) { @@ -708,6 +709,7 @@ uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) status = RNDIS_STATUS_FAILURE; return status; } + /*----------------------------------------------------------------------*/ uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) @@ -849,6 +851,7 @@ 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) { diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h index dd5a79f90b1a6010849057661cadaaece4808fc5..bf6623cfaf27bb42834cf11910caa76562e8c221 100644 --- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h +++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h @@ -17,7 +17,6 @@ #include "osdep_service.h" #include "drv_types.h" - #define CMD_ALIVE BIT(2) enum Power_Mgnt { @@ -63,12 +62,10 @@ enum Power_Mgnt { #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 */ diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c index eb4e46a7f743f29dcd564fa8f1de14140cb437a9..db2add5764189127cc9537561d9ad4609711ea36 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ b/drivers/staging/rtl8712/rtl871x_recv.c @@ -21,6 +21,7 @@ #include <linux/if_ether.h> #include <linux/kmemleak.h> #include <linux/etherdevice.h> +#include <linux/ieee80211.h> #include <net/cfg80211.h> #include "osdep_service.h" @@ -69,7 +70,7 @@ void _r8712_init_recv_priv(struct recv_priv *precvpriv, for (i = 0; i < NR_RECVFRAME; i++) { INIT_LIST_HEAD(&(precvframe->u.list)); list_add_tail(&(precvframe->u.list), - &(precvpriv->free_recv_queue.queue)); + &(precvpriv->free_recv_queue.queue)); r8712_os_recv_resource_alloc(padapter, precvframe); precvframe->u.hdr.adapter = padapter; precvframe++; @@ -175,7 +176,7 @@ sint r8712_recvframe_chkmic(struct _adapter *adapter, if (bmic_err) { if (prxattrib->bdecrypted) r8712_handle_tkip_mic_err(adapter, - (u8)is_multicast_ether_addr(prxattrib->ra)); + (u8)is_multicast_ether_addr(prxattrib->ra)); res = _FAIL; } else { /* mic checked ok */ @@ -191,14 +192,14 @@ sint r8712_recvframe_chkmic(struct _adapter *adapter, /* decrypt and set the ivlen,icvlen of the recv_frame */ union recv_frame *r8712_decryptor(struct _adapter *padapter, - union recv_frame *precv_frame) + 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->sw_decrypt)) { psecuritypriv->hw_decrypted = false; switch (prxattrib->encrypt) { case _WEP40_: @@ -219,6 +220,7 @@ union recv_frame *r8712_decryptor(struct _adapter *padapter, } return return_packet; } + /*###set the security information in the recv_frame */ union recv_frame *r8712_portctrl(struct _adapter *adapter, union recv_frame *precv_frame) @@ -251,7 +253,7 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter, } else { /*free this frame*/ r8712_free_recvframe(precv_frame, - &adapter->recvpriv.free_recv_queue); + &adapter->recvpriv.free_recv_queue); prtnframe = NULL; } } else { @@ -273,7 +275,7 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter, } static sint recv_decache(union recv_frame *precv_frame, u8 bretry, - struct stainfo_rxcache *prxcache) + struct stainfo_rxcache *prxcache) { sint tid = precv_frame->u.hdr.attrib.priority; u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num & 0xffff) << 4) | @@ -372,7 +374,7 @@ static sint ap2sta_data_frame(struct _adapter *adapter, if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { /* if NULL-frame, drop packet */ - if ((GetFrameSubType(ptr)) == WIFI_DATA_NULL) + if ((GetFrameSubType(ptr)) == IEEE80211_STYPE_NULLFUNC) return _FAIL; /* drop QoS-SubType Data, including QoS NULL, * excluding QoS-Data @@ -392,7 +394,7 @@ static sint ap2sta_data_frame(struct _adapter *adapter, return _FAIL; /* check BSSID */ if (is_zero_ether_addr(pattrib->bssid) || - is_zero_ether_addr(mybssid) || + is_zero_ether_addr(mybssid) || (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) return _FAIL; if (bmcast) @@ -442,20 +444,20 @@ static sint sta2ap_data_frame(struct _adapter *adapter, } static sint validate_recv_ctrl_frame(struct _adapter *adapter, - union recv_frame *precv_frame) + union recv_frame *precv_frame) { return _FAIL; } static sint validate_recv_mgnt_frame(struct _adapter *adapter, - union recv_frame *precv_frame) + union recv_frame *precv_frame) { return _FAIL; } static sint validate_recv_data_frame(struct _adapter *adapter, - union recv_frame *precv_frame) + union recv_frame *precv_frame) { int res; u8 bretry; @@ -466,8 +468,8 @@ static sint validate_recv_data_frame(struct _adapter *adapter, struct security_priv *psecuritypriv = &adapter->securitypriv; bretry = GetRetry(ptr); - pda = get_da(ptr); - psa = get_sa(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; @@ -564,13 +566,13 @@ sint r8712_validate_recv_frame(struct _adapter *adapter, pattrib->privacy = GetPrivacy(ptr); pattrib->order = GetOrder(ptr); switch (type) { - case WIFI_MGT_TYPE: /*mgnt*/ + case IEEE80211_FTYPE_MGMT: retval = validate_recv_mgnt_frame(adapter, precv_frame); break; - case WIFI_CTRL_TYPE:/*ctrl*/ + case IEEE80211_FTYPE_CTL: retval = validate_recv_ctrl_frame(adapter, precv_frame); break; - case WIFI_DATA_TYPE: /*data*/ + case IEEE80211_FTYPE_DATA: pattrib->qos = (subtype & BIT(7)) ? 1 : 0; retval = validate_recv_data_frame(adapter, precv_frame); break; @@ -601,7 +603,7 @@ int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe) 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_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 diff --git a/drivers/staging/rtl8712/rtl871x_recv.h b/drivers/staging/rtl8712/rtl871x_recv.h index e83c256e14741f1b7e0def4247c5bca85ca04b6d..1c8298bde033973e811338d18db61962db1fa353 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.h +++ b/drivers/staging/rtl8712/rtl871x_recv.h @@ -29,7 +29,6 @@ struct stainfo_rxcache { #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 */ @@ -38,7 +37,6 @@ struct smooth_rssi_data { }; struct rx_pkt_attrib { - u8 amsdu; u8 order; u8 qos; @@ -136,7 +134,7 @@ int recv_func(struct _adapter *padapter, void *pcontext); static inline u8 *get_rxmem(union recv_frame *precvframe) { /* always return rx_head... */ - if (precvframe == NULL) + if (!precvframe) return NULL; return precvframe->u.hdr.rx_head; } @@ -144,7 +142,7 @@ static inline u8 *get_rxmem(union recv_frame *precvframe) static inline u8 *get_recvframe_data(union recv_frame *precvframe) { /* always return rx_data */ - if (precvframe == NULL) + if (!precvframe) return NULL; return precvframe->u.hdr.rx_data; } @@ -154,7 +152,7 @@ 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 == NULL) + if (!precvframe) return NULL; precvframe->u.hdr.rx_data += sz; if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) { @@ -171,7 +169,7 @@ static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz) * return the updated rx_tail to the caller * after putting, rx_tail must be still larger than rx_end. */ - if (precvframe == NULL) + if (!precvframe) return NULL; precvframe->u.hdr.rx_tail += sz; if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) { @@ -189,7 +187,7 @@ static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz) * updated rx_end to the caller * after pulling, rx_end must be still larger than rx_data. */ - if (precvframe == NULL) + if (!precvframe) return NULL; precvframe->u.hdr.rx_tail -= sz; if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) { diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c index 5000c87752d3c2359a6d2e7713ff0921361791fe..63d63f7be481abd60744053e7e72c3db337f62fb 100644 --- a/drivers/staging/rtl8712/rtl871x_security.c +++ b/drivers/staging/rtl8712/rtl871x_security.c @@ -30,10 +30,10 @@ #include <linux/atomic.h> #include <linux/crc32poly.h> #include <linux/semaphore.h> +#include <linux/ieee80211.h> #include "osdep_service.h" #include "drv_types.h" -#include "wifi.h" #include "osdep_intf.h" /* =====WEP related===== */ @@ -259,7 +259,7 @@ static void secmicputuint32(u8 *p, u32 val) long i; for (i = 0; i < 4; i++) { - *p++ = (u8) (val & 0xff); + *p++ = (u8)(val & 0xff); val >>= 8; } } @@ -907,8 +907,8 @@ static void construct_mic_iv(u8 *mic_iv, sint qc_exists, sint a4_exists, 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); + mic_iv[14] = (unsigned char)(payload_length / 256); + mic_iv[15] = (unsigned char)(payload_length % 256); } /************************************************/ @@ -995,8 +995,8 @@ static void construct_ctr_preload(u8 *ctr_preload, 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); + ctr_preload[14] = (unsigned char)(c / 256); /* Ctr */ + ctr_preload[15] = (unsigned char)(c % 256); } /************************************/ @@ -1045,9 +1045,9 @@ static void aes_cipher(u8 *key, uint hdrlen, else a4_exists = 1; - if ((frtype == WIFI_DATA_CFACK) || - (frtype == WIFI_DATA_CFPOLL) || - (frtype == WIFI_DATA_CFACKPOLL)) { + if ((frtype == IEEE80211_STYPE_DATA_CFACK) || + (frtype == IEEE80211_STYPE_DATA_CFPOLL) || + (frtype == IEEE80211_STYPE_DATA_CFACKPOLL)) { qc_exists = 1; if (hdrlen != WLAN_HDR_A3_QOS_LEN) hdrlen += 2; @@ -1225,9 +1225,9 @@ static void aes_decipher(u8 *key, uint hdrlen, a4_exists = 0; else a4_exists = 1; - if ((frtype == WIFI_DATA_CFACK) || - (frtype == WIFI_DATA_CFPOLL) || - (frtype == WIFI_DATA_CFACKPOLL)) { + if ((frtype == IEEE80211_STYPE_DATA_CFACK) || + (frtype == IEEE80211_STYPE_DATA_CFPOLL) || + (frtype == IEEE80211_STYPE_DATA_CFACKPOLL)) { qc_exists = 1; if (hdrlen != WLAN_HDR_A3_QOS_LEN) hdrlen += 2; diff --git a/drivers/staging/rtl8712/rtl871x_security.h b/drivers/staging/rtl8712/rtl871x_security.h index b2dda16cbd0a9b93f0bc0bceb69350fafa9a873c..8461b7f05359a0d97ab7ae8ff5ad75a8ee28a3a2 100644 --- a/drivers/staging/rtl8712/rtl871x_security.h +++ b/drivers/staging/rtl8712/rtl871x_security.h @@ -101,7 +101,7 @@ struct security_priv { 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]; + u8 wps_ie[MAX_WPA_IE_LEN << 2]; int wps_ie_len; u8 binstallGrpkey; u8 busetkipkey; @@ -185,7 +185,7 @@ do {\ txpn._byte_.TSC5 = iv[7];\ } while (0) -#define ROL32(A, n) (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1))) +#define ROL32(A, n) (((A) << (n)) | (((A) >> (32 - (n))) & ((1UL << (n)) - 1))) #define ROR32(A, n) ROL32((A), 32 - (n)) struct mic_data { diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c index fd99782a400a05f92695354bef97ad39233c42e6..bb4de927fb026403a682fe1837fb87cc31526f39 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.c +++ b/drivers/staging/rtl8712/rtl871x_xmit.c @@ -18,10 +18,10 @@ #include "osdep_service.h" #include "drv_types.h" -#include "wifi.h" #include "osdep_intf.h" #include "usb_ops.h" +#include <linux/ieee80211.h> static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8}; static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00}; @@ -293,7 +293,7 @@ int r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, r8712_set_qos(&pktfile, pattrib); } else { pattrib->hdrlen = WLAN_HDR_A3_LEN; - pattrib->subtype = WIFI_DATA_TYPE; + pattrib->subtype = IEEE80211_FTYPE_DATA; pattrib->priority = 0; } if (psta->ieee8021x_blocked) { @@ -479,7 +479,7 @@ static int make_wlanhdr(struct _adapter *padapter, u8 *hdr, memset(hdr, 0, WLANHDR_OFFSET); SetFrameSubType(fctrl, pattrib->subtype); - if (!(pattrib->subtype & WIFI_DATA_TYPE)) + if (!(pattrib->subtype & IEEE80211_FTYPE_DATA)) return 0; bssid = get_bssid(pmlmepriv); @@ -709,7 +709,7 @@ void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len) break; case AUTO_VCS: default: - perp = r8712_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); + perp = r8712_get_ie(ie, WLAN_EID_ERP_INFO, &erp_len, ie_len); if (!perp) { pxmitpriv->vcs = NONE_VCS; } else { diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h index cc58c72169355ded185a5accc9a38b82acb5e936..2e6afc7bb0a15240c95d8dcd9a7e74713fbe761e 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.h +++ b/drivers/staging/rtl8712/rtl871x_xmit.h @@ -42,7 +42,7 @@ do { \ 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);\ + txpn.val = (txpn.val == 0xffffff) ? 0 : (txpn.val + 1);\ } while (0) /* Fixed the Big Endian bug when doing the Tx. @@ -53,13 +53,13 @@ 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[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);\ + (txpn.val + 1);\ } while (0) #define AES_IV(pattrib_iv, txpn, keyidx)\ @@ -67,13 +67,13 @@ 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[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);\ + (txpn.val + 1);\ } while (0) struct hw_xmit { @@ -280,7 +280,7 @@ 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); + struct xmit_buf *pxmitbuf); #include "rtl8712_xmit.h" diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h index d042d900f30c46c8ab62af06db8d9d12660754ad..9b7e5ffa380dc1140bb70d3118cd4d78a944aea1 100644 --- a/drivers/staging/rtl8712/sta_info.h +++ b/drivers/staging/rtl8712/sta_info.h @@ -36,7 +36,6 @@ struct wlan_acl_pool { }; struct stainfo_stats { - uint rx_pkts; uint rx_bytes; u64 tx_pkts; diff --git a/drivers/staging/rtl8712/usb_ops.h b/drivers/staging/rtl8712/usb_ops.h index d62975447d29b15f442b4c7af40d62ec37314f11..7a6b619b73fabe6bb2f1f966ed620ed91fdb2e71 100644 --- a/drivers/staging/rtl8712/usb_ops.h +++ b/drivers/staging/rtl8712/usb_ops.h @@ -21,9 +21,9 @@ 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 cnt, u8 *wmem); u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, - u32 cnt, u8 *rmem); + 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); @@ -32,7 +32,7 @@ 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); + u16 index, void *pdata, u16 len, u8 requesttype); #endif diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h index 1b32b351009373bc1fd1dfb18031c399ae0e13ad..577a95c62d6c0363a0b6389c2817b4da465d0604 100644 --- a/drivers/staging/rtl8712/wifi.h +++ b/drivers/staging/rtl8712/wifi.h @@ -15,90 +15,15 @@ #define _WIFI_H_ #include <linux/compiler.h> +#include <linux/ieee80211.h> -#define WLAN_IEEE_OUI_LEN 3 -#define WLAN_CRC_LEN 4 -#define WLAN_BSSID_LEN 6 -#define WLAN_BSS_TS_LEN 8 #define WLAN_HDR_A3_LEN 24 -#define WLAN_HDR_A4_LEN 30 #define WLAN_HDR_A3_QOS_LEN 26 -#define WLAN_HDR_A4_QOS_LEN 32 -#define WLAN_SSID_MAXLEN 32 -#define WLAN_DATA_MAXLEN 2312 - -#define WLAN_A3_PN_OFFSET 24 -#define WLAN_A4_PN_OFFSET 30 - -#define WLAN_MIN_ETHFRM_LEN 60 -#define WLAN_MAX_ETHFRM_LEN 1514 #define P80211CAPTURE_VERSION 0x80211001 enum WIFI_FRAME_TYPE { - WIFI_MGT_TYPE = (0), - WIFI_CTRL_TYPE = (BIT(2)), - WIFI_DATA_TYPE = (BIT(3)), - WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /*!< QoS Data */ -}; - -enum WIFI_FRAME_SUBTYPE { - /* below is for mgt frame */ - WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), - WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE), - WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE), - WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE), - WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE), - WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE), - WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE), - WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE), - WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE), - WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE), - WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE), - WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE), - /* below is for control frame */ - WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE), - WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), - WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE), - WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE), - WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE), - WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), - /* below is for data frame */ - WIFI_DATA = (0 | WIFI_DATA_TYPE), - WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE), - WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE), - WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE), - WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE), - WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE), - WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE), - WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE), -}; - -enum WIFI_REASON_CODE { - _RSON_RESERVED_ = 0, - _RSON_UNSPECIFIED_ = 1, - _RSON_AUTH_NO_LONGER_VALID_ = 2, - _RSON_DEAUTH_STA_LEAVING_ = 3, - _RSON_INACTIVITY_ = 4, - _RSON_UNABLE_HANDLE_ = 5, - _RSON_CLS2_ = 6, - _RSON_CLS3_ = 7, - _RSON_DISAOC_STA_LEAVING_ = 8, - _RSON_ASOC_NOT_AUTH_ = 9, - /* WPA reason */ - _RSON_INVALID_IE_ = 13, - _RSON_MIC_FAILURE_ = 14, - _RSON_4WAY_HNDSHK_TIMEOUT_ = 15, - _RSON_GROUP_KEY_UPDATE_TIMEOUT_ = 16, - _RSON_DIFF_IE_ = 17, - _RSON_MLTCST_CIPHER_NOT_VALID_ = 18, - _RSON_UNICST_CIPHER_NOT_VALID_ = 19, - _RSON_AKMP_NOT_VALID_ = 20, - _RSON_UNSUPPORT_RSNE_VER_ = 21, - _RSON_INVALID_RSNE_CAP_ = 22, - _RSON_IEEE_802DOT1X_AUTH_FAIL_ = 23, - /* below are Realtek definitions */ - _RSON_PMK_NOT_AVAILABLE_ = 24, + WIFI_QOS_DATA_TYPE = (BIT(7) | BIT(3)), /*!< QoS Data */ }; enum WIFI_REG_DOMAIN { @@ -115,33 +40,24 @@ enum WIFI_REG_DOMAIN { DOMAIN_MAX }; -#define _TO_DS_ BIT(8) -#define _FROM_DS_ BIT(9) -#define _MORE_FRAG_ BIT(10) -#define _RETRY_ BIT(11) -#define _PWRMGT_ BIT(12) -#define _MORE_DATA_ BIT(13) -#define _PRIVACY_ BIT(14) -#define _ORDER_ BIT(15) - #define SetToDs(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS); \ }) -#define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_TO_DS_)) != 0) +#define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_TODS)) != 0) #define ClearToDs(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_TO_DS_)); \ + *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_TODS)); \ }) #define SetFrDs(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_FROMDS); \ }) -#define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_FROM_DS_)) != 0) +#define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_FROMDS)) != 0) #define ClearFrDs(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_FROM_DS_)); \ + *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_FROMDS)); \ }) static inline unsigned char get_tofr_ds(unsigned char *pframe) @@ -150,56 +66,56 @@ static inline unsigned char get_tofr_ds(unsigned char *pframe) } #define SetMFrag(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); \ }) -#define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_FRAG_)) != 0) +#define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) != 0) #define ClearMFrag(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_)); \ + *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)); \ }) #define SetRetry(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_RETRY_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_RETRY); \ }) -#define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_RETRY_)) != 0) +#define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_RETRY)) != 0) #define ClearRetry(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_)); \ + *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_RETRY)); \ }) #define SetPwrMgt(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PM); \ }) #define GetPwrMgt(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(_PWRMGT_)) != 0) + cpu_to_le16(IEEE80211_FCTL_PM)) != 0) #define ClearPwrMgt(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_)); \ + *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_PM)); \ }) #define SetMData(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); \ }) #define GetMData(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(_MORE_DATA_)) != 0) + cpu_to_le16(IEEE80211_FCTL_MOREDATA)) != 0) #define ClearMData(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_)); \ + *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREDATA)); \ }) #define SetPrivacy(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_); \ + *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); \ }) #define GetPrivacy(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(_PRIVACY_)) != 0) + cpu_to_le16(IEEE80211_FCTL_PROTECTED)) != 0) #define GetOrder(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(_ORDER_)) != 0) + cpu_to_le16(IEEE80211_FCTL_ORDER)) != 0) #define GetFrameType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & \ (BIT(3) | BIT(2))) @@ -234,11 +150,6 @@ static inline unsigned char get_tofr_ds(unsigned char *pframe) 0x000f) | (0xfff0 & (num << 4))); \ }) -#define SetDuration(pbuf, dur) ({ \ - *(__le16 *)((addr_t)(pbuf) + 2) |= \ - cpu_to_le16(0xffff & (dur)); \ -}) - #define SetPriority(pbuf, tid) ({ \ *(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf); \ }) @@ -253,9 +164,6 @@ static inline unsigned char get_tofr_ds(unsigned char *pframe) #define GetAMsdu(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 7) & 0x1) -#define GetAid(pbuf) (cpu_to_le16(*(__le16 *)((addr_t)(pbuf) + 2)) \ - & 0x3fff) - #define GetAddr1Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 4)) #define GetAddr2Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 10)) @@ -264,51 +172,6 @@ static inline unsigned char get_tofr_ds(unsigned char *pframe) #define GetAddr4Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 24)) -static inline unsigned char *get_da(unsigned char *pframe) -{ - unsigned char *da; - unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); - - switch (to_fr_ds) { - case 0x00: /* ToDs=0, FromDs=0 */ - da = GetAddr1Ptr(pframe); - break; - case 0x01: /* ToDs=0, FromDs=1 */ - da = GetAddr1Ptr(pframe); - break; - case 0x02: /* ToDs=1, FromDs=0 */ - da = GetAddr3Ptr(pframe); - break; - default: /* ToDs=1, FromDs=1 */ - da = GetAddr3Ptr(pframe); - break; - } - return da; -} - -static inline unsigned char *get_sa(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 = GetAddr2Ptr(pframe); - break; - case 0x01: /* ToDs=0, FromDs=1 */ - sa = GetAddr3Ptr(pframe); - break; - case 0x02: /* ToDs=1, FromDs=0 */ - sa = GetAddr2Ptr(pframe); - break; - default: /* ToDs=1, FromDs=1 */ - sa = GetAddr4Ptr(pframe); - break; - } - - return sa; -} - static inline unsigned char *get_hdr_bssid(unsigned char *pframe) { unsigned char *sa; @@ -335,19 +198,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe) * Below is for the security related definition *----------------------------------------------------------------------------- */ -#define _RESERVED_FRAME_TYPE_ 0 -#define _SKB_FRAME_TYPE_ 2 -#define _PRE_ALLOCMEM_ 1 -#define _PRE_ALLOCHDR_ 3 -#define _PRE_ALLOCLLCHDR_ 4 -#define _PRE_ALLOCICVHDR_ 5 -#define _PRE_ALLOCMICHDR_ 6 - -#define _SIFSTIME_ ((priv->pmib->BssType.net_work_type & \ - WIRELESS_11A) ? 16 : 10) -#define _ACKCTSLNG_ 14 /*14 bytes long, including crclng */ -#define _CRCLNG_ 4 - #define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */ #define _ASOCRSP_IE_OFFSET_ 6 #define _REASOCREQ_IE_OFFSET_ 10 @@ -360,21 +210,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe) #define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ -#define _SSID_IE_ 0 -#define _SUPPORTEDRATES_IE_ 1 -#define _DSSET_IE_ 3 -#define _IBSS_PARA_IE_ 6 -#define _ERPINFO_IE_ 42 -#define _EXT_SUPPORTEDRATES_IE_ 50 - -#define _HT_CAPABILITY_IE_ 45 -#define _HT_EXTRA_INFO_IE_ 61 -#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */ - -#define _VENDOR_SPECIFIC_IE_ 221 - -#define _RESERVED47_ 47 - /* --------------------------------------------------------------------------- * Below is the fixed elements... * --------------------------------------------------------------------------- @@ -393,17 +228,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe) #define AUTH_ODD_TO 0 #define AUTH_EVEN_TO 1 -#define WLAN_ETHCONV_ENCAP 1 -#define WLAN_ETHCONV_RFC1042 2 -#define WLAN_ETHCONV_8021h 3 - -#define cap_ESS BIT(0) -#define cap_IBSS BIT(1) -#define cap_CFPollable BIT(2) -#define cap_CFRequest BIT(3) -#define cap_Privacy BIT(4) -#define cap_ShortPremble BIT(5) - /*----------------------------------------------------------------------------- * Below is the definition for 802.11i / 802.1x *------------------------------------------------------------------------------ @@ -416,49 +240,6 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe) *------------------------------------------------------------------------------ */ #define _WMM_IE_Length_ 7 /* for WMM STA */ -#define _WMM_Para_Element_Length_ 24 - -/*----------------------------------------------------------------------------- - * Below is the definition for 802.11n - *------------------------------------------------------------------------------ - */ - -#define SetOrderBit(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(_ORDER_); \ -}) - -#define GetOrderBit(pbuf) (((*(__le16 *)(pbuf)) & \ - le16_to_cpu(_ORDER_)) != 0) - -/* - * struct rtl_ieee80211_ht_cap - HT capabilities - * - * This structure refers to "HT capabilities element" as - * described in 802.11n draft section 7.3.2.52 - */ - -struct rtl_ieee80211_ht_cap { - __le16 cap_info; - unsigned char ampdu_params_info; - unsigned char supp_mcs_set[16]; - __le16 extended_ht_cap_info; - __le32 tx_BF_cap_info; - unsigned char antenna_selection_info; -} __packed; - -/** - * struct ieee80211_ht_addt_info - HT additional information - * - * This structure refers to "HT information element" as - * described in 802.11n draft section 7.3.2.53 - */ -struct ieee80211_ht_addt_info { - unsigned char control_chan; - unsigned char ht_param; - __le16 operation_mode; - __le16 stbc_param; - unsigned char basic_set[16]; -} __packed; #endif /* _WIFI_H_ */ diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h index b54ccaacc527f8f1dc736f0421982c87846cf730..ec3749813728d9b6a8611a4e010e2f08abe098bc 100644 --- a/drivers/staging/rtl8712/wlan_bssdef.h +++ b/drivers/staging/rtl8712/wlan_bssdef.h @@ -176,7 +176,7 @@ struct NDIS_802_11_WEP { #define MIC_CHECK_TIME 60000000 #ifndef Ndis802_11APMode -#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1) +#define Ndis802_11APMode (Ndis802_11InfrastructureMax + 1) #endif struct wlan_network { diff --git a/drivers/staging/rtl8712/xmit_osdep.h b/drivers/staging/rtl8712/xmit_osdep.h index 21f6b31e0f500fe820c309d53ad815f66c95cd76..b76021b568f8e920f87412ddc809ddcf82f644fc 100644 --- a/drivers/staging/rtl8712/xmit_osdep.h +++ b/drivers/staging/rtl8712/xmit_osdep.h @@ -37,16 +37,16 @@ struct xmit_buf; int 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); + struct xmit_buf *pxmitbuf); void r8712_xmit_resource_free(struct _adapter *padapter, - struct xmit_buf *pxmitbuf); + struct xmit_buf *pxmitbuf); void r8712_set_qos(struct pkt_file *ppktfile, - struct pkt_attrib *pattrib); + 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); + struct xmit_frame *pxframe); #endif diff --git a/drivers/staging/rtl8723bs/TODO b/drivers/staging/rtl8723bs/TODO index 45065fd3fd5d5a08e4b18835346e814c9db64531..afa620ceb2d86e328deea00e669054125a999140 100644 --- a/drivers/staging/rtl8723bs/TODO +++ b/drivers/staging/rtl8723bs/TODO @@ -1,5 +1,4 @@ TODO: -- find and remove code blocks guarded by never set CONFIG_FOO defines - find and remove remaining code valid only for 5 GHz. Most of the obvious ones have been removed, but things like channel > 14 still exist. - find and remove any code for other chips that is left over diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index b6f944b37b08f11c1cdf27d1006737ea495c12ee..4a9bd4825fab93c006ad8e716cd91249a0e89c65 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -10,11 +10,6 @@ #include <rtw_debug.h> #include <asm/unaligned.h> -extern unsigned char RTW_WPA_OUI[]; -extern unsigned char WMM_OUI[]; -extern unsigned char WPS_OUI[]; -extern unsigned char P2P_OUI[]; - void init_mlme_ap_info(struct adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -63,8 +58,6 @@ static void update_BCNTIM(struct adapter *padapter) struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; unsigned char *pie = pnetwork_mlmeext->IEs; - /* DBG_871X("%s\n", __func__); */ - /* update TIM IE */ /* if (pstapriv->tim_bitmap) */ if (true) { @@ -74,18 +67,17 @@ static void update_BCNTIM(struct adapter *padapter) tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); - p = rtw_get_ie( - pie + _FIXED_IE_LENGTH_, - WLAN_EID_TIM, - &tim_ielen, - pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_ + p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, + WLAN_EID_TIM, + &tim_ielen, + pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_ ); if (p && tim_ielen > 0) { tim_ielen += 2; premainder_ie = p + tim_ielen; - tim_ie_offset = (sint)(p - pie); + tim_ie_offset = (signed int)(p - pie); remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; @@ -98,20 +90,18 @@ static void update_BCNTIM(struct adapter *padapter) offset = _FIXED_IE_LENGTH_; /* get ssid_ie len */ - p = rtw_get_ie( - pie + _BEACON_IE_OFFSET_, - WLAN_EID_SSID, - &tmp_len, - (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_) + p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, + WLAN_EID_SSID, + &tmp_len, + (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_) ); if (p) offset += tmp_len + 2; /* get supported rates len */ - p = rtw_get_ie( - pie + _BEACON_IE_OFFSET_, - WLAN_EID_SUPP_RATES, &tmp_len, - (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_) + p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, + WLAN_EID_SUPP_RATES, &tmp_len, + (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_) ); if (p) offset += tmp_len + 2; @@ -180,20 +170,6 @@ static void update_BCNTIM(struct adapter *padapter) u8 chk_sta_is_alive(struct sta_info *psta); u8 chk_sta_is_alive(struct sta_info *psta) { - #ifdef DBG_EXPIRATION_CHK - DBG_871X( - "sta:%pM, rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n" - , MAC_ARG(psta->hwaddr) - , psta->rssi_stat.UndecoratedSmoothedPWDB - /* STA_RX_PKTS_ARG(psta) */ - , STA_RX_PKTS_DIFF_ARG(psta) - , psta->expire_to - , psta->state & WIFI_SLEEP_STATE ? "PS, " : "" - , psta->state & WIFI_STA_ALIVE_CHK_STATE ? "SAC, " : "" - , psta->sleepq_len - ); - #endif - sta_update_last_rx_pkts(psta); return true; @@ -215,13 +191,6 @@ void expire_timeout_chk(struct adapter *padapter) plist = get_next(phead); /* check auth_queue */ - #ifdef DBG_EXPIRATION_CHK - if (phead != plist) { - DBG_871X(FUNC_NDEV_FMT " auth_list, cnt:%u\n", - FUNC_NDEV_ARG(padapter->pnetdev), - pstapriv->auth_list_cnt); - } - #endif while (phead != plist) { psta = container_of(plist, struct sta_info, auth_list); @@ -233,16 +202,6 @@ void expire_timeout_chk(struct adapter *padapter) list_del_init(&psta->auth_list); pstapriv->auth_list_cnt--; - DBG_871X( - "auth expire %02X%02X%02X%02X%02X%02X\n", - psta->hwaddr[0], - psta->hwaddr[1], - psta->hwaddr[2], - psta->hwaddr[3], - psta->hwaddr[4], - psta->hwaddr[5] - ); - spin_unlock_bh(&pstapriv->auth_list_lock); rtw_free_stainfo(padapter, psta); @@ -261,19 +220,9 @@ void expire_timeout_chk(struct adapter *padapter) plist = get_next(phead); /* check asoc_queue */ - #ifdef DBG_EXPIRATION_CHK - if (phead != plist) { - DBG_871X(FUNC_NDEV_FMT" asoc_list, cnt:%u\n" - , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt); - } - #endif while (phead != plist) { psta = container_of(plist, struct sta_info, asoc_list); plist = get_next(plist); -#ifdef CONFIG_AUTO_AP_MODE - if (psta->isrc) - continue; -#endif if (chk_sta_is_alive(psta) || !psta->expire_to) { psta->expire_to = pstapriv->expire_to; psta->keep_alive_trycnt = 0; @@ -293,12 +242,11 @@ void expire_timeout_chk(struct adapter *padapter) if (psta->state & WIFI_SLEEP_STATE) { if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { - /* to check if alive by another methods if station is at ps mode. */ + /* to check if alive by another methods */ + /* if station is at ps mode. */ psta->expire_to = pstapriv->expire_to; psta->state |= WIFI_STA_ALIVE_CHK_STATE; - /* DBG_871X("alive chk, sta:%pM is at ps mode!\n", MAC_ARG(psta->hwaddr)); */ - /* to update bcn with tim_bitmap for this station */ pstapriv->tim_bitmap |= BIT(psta->aid); update_beacon(padapter, WLAN_EID_TIM, NULL, true); @@ -318,29 +266,16 @@ void expire_timeout_chk(struct adapter *padapter) } list_del_init(&psta->asoc_list); pstapriv->asoc_list_cnt--; - DBG_871X( - "asoc expire %pM, state = 0x%x\n", - MAC_ARG(psta->hwaddr), - psta->state - ); updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); } else { - /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ + /* TODO: Aging mechanism to digest frames in sleep_q to */ + /* avoid running out of xmitframe */ if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) && padapter->xmitpriv.free_xmitframe_cnt < (( NR_XMITFRAME / pstapriv->asoc_list_cnt ) / 2) - ) { - DBG_871X( - "%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", - __func__, - MAC_ARG(psta->hwaddr), - psta->sleepq_len, - padapter->xmitpriv.free_xmitframe_cnt, - pstapriv->asoc_list_cnt - ); + ) wakeup_sta_to_xmit(padapter, psta); - } } } @@ -371,29 +306,21 @@ void expire_timeout_chk(struct adapter *padapter) psta->keep_alive_trycnt++; if (ret == _SUCCESS) { - DBG_871X( - "asoc check, sta(%pM) is alive\n", - MAC_ARG(psta->hwaddr) - ); psta->expire_to = pstapriv->expire_to; psta->keep_alive_trycnt = 0; continue; } else if (psta->keep_alive_trycnt <= 3) { - DBG_871X( - "ack check for asoc expire, keep_alive_trycnt =%d\n", - psta->keep_alive_trycnt); psta->expire_to = 1; continue; } psta->keep_alive_trycnt = 0; - DBG_871X("asoc expire %pM, state = 0x%x\n", MAC_ARG(psta->hwaddr), - psta->state); spin_lock_bh(&pstapriv->asoc_list_lock); if (list_empty(&psta->asoc_list) == false) { list_del_init(&psta->asoc_list); pstapriv->asoc_list_cnt--; - updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); + updated = ap_free_sta(padapter, psta, false, + WLAN_REASON_DEAUTH_LEAVING); } spin_unlock_bh(&pstapriv->asoc_list_lock); } @@ -452,12 +379,7 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level) arg[2] = shortGIrate; arg[3] = psta->init_rate; - DBG_871X("%s => mac_id:%d , raid:%d , shortGIrate =%d, bitmap = 0x%x\n", - __func__, psta->mac_id, psta->raid, shortGIrate, tx_ra_bitmap); - rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level); - } else { - DBG_871X("station aid %d exceed the max number\n", psta->aid); } } @@ -491,10 +413,9 @@ void update_bmc_sta(struct adapter *padapter) /* prepare for add_RATid */ supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates); - network_type = rtw_check_network_type( - (u8 *)&pcur_network->SupportedRates, - supportRateNum, - pcur_network->Configuration.DSConfig + network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, + supportRateNum, + pcur_network->Configuration.DSConfig ); if (IsSupportedTxCCK(network_type)) { network_type = WIRELESS_11B; @@ -525,9 +446,6 @@ void update_bmc_sta(struct adapter *padapter) arg[2] = 0; arg[3] = psta->init_rate; - DBG_871X("%s => mac_id:%d , raid:%d , bitmap = 0x%x\n", - __func__, psta->mac_id, psta->raid, tx_ra_bitmap); - rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0); } @@ -537,8 +455,6 @@ void update_bmc_sta(struct adapter *padapter) psta->state = _FW_LINKED; spin_unlock_bh(&psta->lock); - } else { - DBG_871X("add_RATid_bmc_sta error!\n"); } } @@ -560,8 +476,6 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) /* set intf_tag to if1 */ /* psta->intf_tag = 0; */ - DBG_871X("%s\n", __func__); - /* psta->mac_id = psta->aid+4; */ /* psta->mac_id = psta->aid+1;//alloc macid when call rtw_alloc_stainfo(), */ /* release macid when call rtw_free_stainfo() */ @@ -621,17 +535,13 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) /* B0 Config LDPC Coding Capability */ if (TEST_FLAG(phtpriv_ap->ldpc_cap, LDPC_HT_ENABLE_TX) && - GET_HT_CAPABILITY_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap))) { + GET_HT_CAPABILITY_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap))) SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); - DBG_871X("Enable HT Tx LDPC for STA(%d)\n", psta->aid); - } /* B7 B8 B9 Config STBC setting */ if (TEST_FLAG(phtpriv_ap->stbc_cap, STBC_HT_ENABLE_TX) && - GET_HT_CAPABILITY_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap))) { + GET_HT_CAPABILITY_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap))) SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); - DBG_871X("Enable HT Tx STBC for STA(%d)\n", psta->aid); - } } else { phtpriv_sta->ampdu_enable = false; @@ -717,24 +627,16 @@ static void update_hw_ht_param(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - DBG_871X("%s\n", __func__); - - /* handle A-MPDU parameter field */ - /* - AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k - AMPDU_para [4:2]:Min MPDU Start Spacing - */ + /* handle A-MPDU parameter field + * + * AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + * AMPDU_para [4:2]:Min MPDU Start Spacing + */ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; - min_MPDU_spacing = ( - pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c - ) >> 2; + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; - rtw_hal_set_hwreg( - padapter, - HW_VAR_AMPDU_MIN_SPACE, - (u8 *)(&min_MPDU_spacing) - ); + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); @@ -744,8 +646,6 @@ static void update_hw_ht_param(struct adapter *padapter) pmlmeinfo->SM_PS = (le16_to_cpu( pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info ) & 0x0C) >> 2; - if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) - DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); /* */ /* Config current HT Protection mode. */ @@ -771,8 +671,6 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf) struct HT_info_element *pht_info = NULL; u8 cbw40_enable = 0; - /* DBG_871X("%s\n", __func__); */ - bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; cur_channel = pnetwork->Configuration.DSConfig; cur_bwmode = CHANNEL_WIDTH_20; @@ -802,10 +700,8 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf) if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */ /* WEP Key will be set before this function, do not clear CAM. */ - if ( - (psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && - (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) - ) + if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && + (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) flush_all_cam_entry(padapter); /* clear CAM */ } @@ -853,11 +749,10 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf) } /* set channel, bwmode */ - p = rtw_get_ie( - (pnetwork->IEs + sizeof(struct ndis_802_11_fix_ie)), - WLAN_EID_HT_OPERATION, - &ie_len, - (pnetwork->IELength - sizeof(struct ndis_802_11_fix_ie)) + p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fix_ie)), + WLAN_EID_HT_OPERATION, + &ie_len, + (pnetwork->IELength - sizeof(struct ndis_802_11_fix_ie)) ); if (p && ie_len) { pht_info = (struct HT_info_element *)(p + 2); @@ -894,12 +789,6 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf) } set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); - DBG_871X( - "CH =%d, BW =%d, offset =%d\n", - cur_channel, - cur_bwmode, - cur_ch_offset - ); pmlmeext->cur_channel = cur_channel; pmlmeext->cur_bwmode = cur_bwmode; pmlmeext->cur_ch_offset = cur_ch_offset; @@ -924,12 +813,8 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf) if (pmlmeext->bstart_bss) { update_beacon(padapter, WLAN_EID_TIM, NULL, true); -#ifndef CONFIG_INTERRUPT_BASED_TXBCN /* other case will tx beacon when bcn interrupt coming in. */ /* issue beacon frame */ - if (send_beacon(padapter) == _FAIL) - DBG_871X("issue_beacon, fail!\n"); - -#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ + send_beacon(padapter); } /* update bc/mc sta_info */ @@ -959,19 +844,6 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; u8 *ie = pbss_network->IEs; - /* SSID */ - /* Supported rates */ - /* DS Params */ - /* WLAN_EID_COUNTRY */ - /* ERP Information element */ - /* Extended supported rates */ - /* WPA/WPA2 */ - /* Wi-Fi Wireless Multimedia Extensions */ - /* ht_capab, ht_oper */ - /* WPS IE */ - - DBG_871X("%s, len =%d\n", __func__, len); - if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) return _FAIL; @@ -1136,7 +1008,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) } if ((p == NULL) || (ie_len == 0)) - break; + break; } /* wmm */ @@ -1155,7 +1027,8 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) *(p + 8) |= BIT(7);/* QoS Info, support U-APSD */ - /* disable all ACM bits since the WMM admission control is not supported */ + /* disable all ACM bits since the WMM admission */ + /* control is not supported */ *(p + 10) &= ~BIT(4); /* BE */ *(p + 14) &= ~BIT(4); /* BK */ *(p + 18) &= ~BIT(4); /* VI */ @@ -1208,7 +1081,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) ); if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || - (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) { + (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) { pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (0x07 << 2)); } else { pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00); @@ -1265,7 +1138,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) pmlmepriv->htpriv.ht_option = false; if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) || - (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) { + (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) { /* todo: */ /* ht_cap = false; */ } @@ -1318,8 +1191,6 @@ void rtw_set_macaddr_acl(struct adapter *padapter, int mode) struct sta_priv *pstapriv = &padapter->stapriv; struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; - DBG_871X("%s, mode =%d\n", __func__, mode); - pacl_list->mode = mode; } @@ -1333,8 +1204,6 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; struct __queue *pacl_node_q = &pacl_list->acl_node_q; - DBG_871X("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, MAC_ARG(addr)); - if ((NUM_ACL - 1) < pacl_list->num) return (-1); @@ -1350,7 +1219,6 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { if (paclnode->valid == true) { added = true; - DBG_871X("%s, sta has been added\n", __func__); break; } } @@ -1381,8 +1249,6 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) } } - DBG_871X("%s, acl_num =%d\n", __func__, pacl_list->num); - spin_unlock_bh(&(pacl_node_q->lock)); return ret; @@ -1397,8 +1263,6 @@ void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr) struct __queue *pacl_node_q = &pacl_list->acl_node_q; u8 baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* Baddr is used for clearing acl_list */ - DBG_871X("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, MAC_ARG(addr)); - spin_lock_bh(&(pacl_node_q->lock)); phead = get_list_head(pacl_node_q); @@ -1424,8 +1288,6 @@ void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr) spin_unlock_bh(&(pacl_node_q->lock)); - DBG_871X("%s, acl_num =%d\n", __func__, pacl_list->num); - } u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta) @@ -1477,8 +1339,6 @@ static int rtw_ap_set_key( struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); int res = _SUCCESS; - /* DBG_871X("%s\n", __func__); */ - pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); if (pcmd == NULL) { res = _FAIL; @@ -1532,8 +1392,6 @@ exit: int rtw_ap_set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid) { - DBG_871X("%s\n", __func__); - return rtw_ap_set_key(padapter, key, alg, keyid, 1); } @@ -1558,14 +1416,11 @@ int rtw_ap_set_wep_key( alg = _NO_PRIVACY_; } - DBG_871X("%s\n", __func__); - return rtw_ap_set_key(padapter, key, alg, keyid, set_tx); } static void update_bcn_fixed_ie(struct adapter *padapter) { - DBG_871X("%s\n", __func__); } static void update_bcn_erpinfo_ie(struct adapter *padapter) @@ -1577,8 +1432,6 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter) unsigned char *p, *ie = pnetwork->IEs; u32 len = 0; - DBG_871X("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable); - if (!pmlmeinfo->ERP_enable) return; @@ -1610,27 +1463,22 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter) static void update_bcn_htcap_ie(struct adapter *padapter) { - DBG_871X("%s\n", __func__); } static void update_bcn_htinfo_ie(struct adapter *padapter) { - DBG_871X("%s\n", __func__); } static void update_bcn_rsn_ie(struct adapter *padapter) { - DBG_871X("%s\n", __func__); } static void update_bcn_wpa_ie(struct adapter *padapter) { - DBG_871X("%s\n", __func__); } static void update_bcn_wmm_ie(struct adapter *padapter) { - DBG_871X("%s\n", __func__); } static void update_bcn_wps_ie(struct adapter *padapter) @@ -1648,8 +1496,6 @@ static void update_bcn_wps_ie(struct adapter *padapter) unsigned char *ie = pnetwork->IEs; u32 ielen = pnetwork->IELength; - DBG_871X("%s\n", __func__); - pwps_ie = rtw_get_wps_ie( ie + _FIXED_IE_LENGTH_, ielen - _FIXED_IE_LENGTH_, @@ -1689,26 +1535,6 @@ static void update_bcn_wps_ie(struct adapter *padapter) } kfree(pbackup_remainder_ie); - - /* deal with the case without set_tx_beacon_cmd() in update_beacon() */ -#if defined(CONFIG_INTERRUPT_BASED_TXBCN) - if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { - u8 sr = 0; - - rtw_get_wps_attr_content( - pwps_ie_src, - wps_ielen, - WPS_ATTR_SELECTED_REGISTRAR, - (u8 *)(&sr), - NULL - ); - - if (sr) { - set_fwstate(pmlmepriv, WIFI_UNDER_WPS); - DBG_871X("%s, set WIFI_UNDER_WPS\n", __func__); - } - } -#endif } static void update_bcn_p2p_ie(struct adapter *padapter) @@ -1717,8 +1543,6 @@ static void update_bcn_p2p_ie(struct adapter *padapter) static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui) { - DBG_871X("%s\n", __func__); - if (!memcmp(RTW_WPA_OUI, oui, 4)) update_bcn_wpa_ie(padapter); @@ -1730,9 +1554,6 @@ static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui) else if (!memcmp(P2P_OUI, oui, 4)) update_bcn_p2p_ie(padapter); - - else - DBG_871X("unknown OUI type!\n"); } void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) @@ -1741,8 +1562,6 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) struct mlme_ext_priv *pmlmeext; /* struct mlme_ext_info *pmlmeinfo; */ - /* DBG_871X("%s\n", __func__); */ - if (!padapter) return; @@ -1806,26 +1625,24 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) spin_unlock_bh(&pmlmepriv->bcn_update_lock); -#ifndef CONFIG_INTERRUPT_BASED_TXBCN if (tx) { /* send_beacon(padapter);//send_beacon must execute on TSR level */ set_tx_beacon_cmd(padapter); } -#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ } /* -op_mode -Set to 0 (HT pure) under the following conditions - - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or - - all STAs in the BSS are 20 MHz HT in 20 MHz BSS -Set to 1 (HT non-member protection) if there may be non-HT STAs - in both the primary and the secondary channel -Set to 2 if only HT STAs are associated in BSS, - however and at least one 20 MHz HT STA is associated -Set to 3 (HT mixed mode) when one or more non-HT STAs are associated - (currently non-GF HT station is considered as non-HT STA also) -*/ + * op_mode + * Set to 0 (HT pure) under the following conditions + * - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or + * - all STAs in the BSS are 20 MHz HT in 20 MHz BSS + * Set to 1 (HT non-member protection) if there may be non-HT STAs + * in both the primary and the secondary channel + * Set to 2 if only HT STAs are associated in BSS, + * however and at least one 20 MHz HT STA is associated + * Set to 3 (HT mixed mode) when one or more non-HT STAs are associated + * (currently non-GF HT station is considered as non-HT STA also) + */ static int rtw_ht_operation_update(struct adapter *padapter) { u16 cur_op_mode, new_op_mode; @@ -1836,12 +1653,6 @@ static int rtw_ht_operation_update(struct adapter *padapter) if (pmlmepriv->htpriv.ht_option) return 0; - /* if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) */ - /* return 0; */ - - DBG_871X("%s current operation mode = 0x%X\n", - __func__, pmlmepriv->ht_op_mode); - if (!(pmlmepriv->ht_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) && pmlmepriv->num_sta_ht_no_gf) { pmlmepriv->ht_op_mode |= @@ -1891,9 +1702,6 @@ static int rtw_ht_operation_update(struct adapter *padapter) op_mode_changes++; } - DBG_871X("%s new operation mode = 0x%X changes =%d\n", - __func__, pmlmepriv->ht_op_mode, op_mode_changes); - return op_mode_changes; } @@ -1937,7 +1745,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) pmlmepriv->num_sta_no_short_preamble++; if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && - (pmlmepriv->num_sta_no_short_preamble == 1)) { + (pmlmepriv->num_sta_no_short_preamble == 1)) { beacon_updated = true; update_beacon(padapter, 0xFF, NULL, true); } @@ -2009,9 +1817,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) if (psta->flags & WLAN_STA_HT) { u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); - DBG_871X("HT: STA %pM HT Capabilities " - "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab); - if (psta->no_ht_set) { psta->no_ht_set = 0; pmlmepriv->num_sta_no_ht--; @@ -2022,10 +1827,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) psta->no_ht_gf_set = 1; pmlmepriv->num_sta_ht_no_gf++; } - DBG_871X("%s STA %pM - no " - "greenfield, num of non-gf stations %d\n", - __func__, MAC_ARG(psta->hwaddr), - pmlmepriv->num_sta_ht_no_gf); } if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) { @@ -2033,10 +1834,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) psta->ht_20mhz_set = 1; pmlmepriv->num_sta_ht_20mhz++; } - DBG_871X("%s STA %pM - 20 MHz HT, " - "num of 20MHz HT STAs %d\n", - __func__, MAC_ARG(psta->hwaddr), - pmlmepriv->num_sta_ht_20mhz); } } else { @@ -2044,11 +1841,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) psta->no_ht_set = 1; pmlmepriv->num_sta_no_ht++; } - if (pmlmepriv->htpriv.ht_option == true) { - DBG_871X("%s STA %pM - no HT, num of non-HT stations %d\n", - __func__, MAC_ARG(psta->hwaddr), - pmlmepriv->num_sta_no_ht); - } } if (rtw_ht_operation_update(padapter) > 0) { @@ -2058,8 +1850,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) /* update associated stations cap. */ associated_clients_update(padapter, beacon_updated); - - DBG_871X("%s, updated =%d\n", __func__, beacon_updated); } u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta) @@ -2120,11 +1910,6 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta) update_beacon(padapter, WLAN_EID_HT_OPERATION, NULL, true); } - /* update associated stations cap. */ - /* associated_clients_update(padapter, beacon_updated); //move it to avoid deadlock */ - - DBG_871X("%s, updated =%d\n", __func__, beacon_updated); - return beacon_updated; } @@ -2182,8 +1967,6 @@ void rtw_sta_flush(struct adapter *padapter) struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); - if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) return; @@ -2310,9 +2093,10 @@ void rtw_ap_restore_network(struct adapter *padapter) for (i = 0; i < chk_alive_num; i++) { psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); - if (psta == NULL) { - DBG_871X(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter)); - } else if (psta->state & _FW_LINKED) { + if (!psta) + continue; + + if (psta->state & _FW_LINKED) { rtw_sta_media_status_rpt(padapter, psta, 1); Update_RA_Entry(padapter, psta); /* pairwise key */ @@ -2415,8 +2199,6 @@ void stop_ap_mode(struct adapter *padapter) } spin_unlock_bh(&(pacl_node_q->lock)); - DBG_871X("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num); - rtw_sta_flush(padapter); /* free_assoc_sta_resources */ diff --git a/drivers/staging/rtl8723bs/core/rtw_btcoex.c b/drivers/staging/rtl8723bs/core/rtw_btcoex.c index 44219b7b61235d2bf881f5c3204321c628979709..62cbf84b079a4c5bbae5389756e7b7675f1852e6 100644 --- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c +++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c @@ -21,19 +21,11 @@ void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus) void rtw_btcoex_HaltNotify(struct adapter *padapter) { - if (!padapter->bup) { - DBG_871X(FUNC_ADPT_FMT ": bup =%d Skip!\n", - FUNC_ADPT_ARG(padapter), padapter->bup); - + if (!padapter->bup) return; - } - - if (padapter->bSurpriseRemoved) { - DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n", - FUNC_ADPT_ARG(padapter), padapter->bSurpriseRemoved); + if (padapter->bSurpriseRemoved) return; - } hal_btcoex_HaltNotify(padapter); } diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 3fe79169a811cacfdad93112572a7d9dd38eff32..e1a8f8b47edd5cdcdac8e5bd4015e602819ca953 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -78,13 +78,12 @@ static struct _cmd_callback rtw_cmd_callback[] = { {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/ {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/ {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/ - {GEN_CMD_CODE(_LedBlink), NULL},/*60*/ - {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/ - {GEN_CMD_CODE(_TDLS), NULL},/*62*/ - {GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*63*/ + {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*60*/ + {GEN_CMD_CODE(_TDLS), NULL},/*61*/ + {GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*62*/ - {GEN_CMD_CODE(_RunInThreadCMD), NULL},/*64*/ + {GEN_CMD_CODE(_RunInThreadCMD), NULL},/*63*/ }; static struct cmd_hdl wlancmds[] = { @@ -150,11 +149,10 @@ static struct cmd_hdl wlancmds[] = { GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/ - GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl) /*60*/ - GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*61*/ - GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*62*/ - GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*63*/ + GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*60*/ + GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*61*/ + GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*62*/ GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*63*/ }; @@ -203,7 +201,7 @@ exit: return res; } -static void c2h_wk_callback(_workitem * work); +static void c2h_wk_callback(struct work_struct *work); int rtw_init_evt_priv(struct evt_priv *pevtpriv) { /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ @@ -221,8 +219,6 @@ int rtw_init_evt_priv(struct evt_priv *pevtpriv) void _rtw_free_evt_priv(struct evt_priv *pevtpriv) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+_rtw_free_evt_priv\n")); - _cancel_workitem_sync(&pevtpriv->c2h_wk); while (pevtpriv->c2h_wk_alive) msleep(10); @@ -233,8 +229,6 @@ void _rtw_free_evt_priv(struct evt_priv *pevtpriv) kfree(c2h); } kfree(pevtpriv->c2h_queue); - - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-_rtw_free_evt_priv\n")); } void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) @@ -260,7 +254,7 @@ ISR/Call-Back functions can't call this sub-function. int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) { - _irqL irqL; + unsigned long irqL; if (obj == NULL) goto exit; @@ -279,7 +273,7 @@ exit: struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) { - _irqL irqL; + unsigned long irqL; struct cmd_obj *obj; /* spin_lock_bh(&(queue->lock)); */ @@ -299,13 +293,11 @@ struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) void rtw_free_evt_priv(struct evt_priv *pevtpriv) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_evt_priv\n")); _rtw_free_evt_priv(pevtpriv); } void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n")); _rtw_free_cmd_priv(pcmdpriv); } @@ -319,15 +311,9 @@ int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) if ((pcmdpriv->padapter->hw_init_completed == false && bAllow == false) || atomic_read(&(pcmdpriv->cmdthd_running)) == false /* com_thread not running */ - ) { - /* DBG_871X("%s:%s: drop cmdcode:%u, hw_init_completed:%u, cmdthd_running:%u\n", caller_func, __func__, */ - /* cmd_obj->cmdcode, */ - /* pcmdpriv->padapter->hw_init_completed, */ - /* pcmdpriv->cmdthd_running */ - /* */ - + ) return _FAIL; - } + return _SUCCESS; } @@ -399,8 +385,6 @@ int rtw_cmd_thread(void *context) u8 ret; struct cmd_obj *pcmd; u8 *pcmdbuf; - unsigned long cmd_start_time; - unsigned long cmd_process_time; u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf); void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd); struct adapter *padapter = context; @@ -415,40 +399,42 @@ int rtw_cmd_thread(void *context) atomic_set(&(pcmdpriv->cmdthd_running), true); complete(&pcmdpriv->terminate_cmdthread_comp); - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("start r871x rtw_cmd_thread !!!!\n")); - while (1) { if (wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp)) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp) return != 0, break\n", FUNC_ADPT_ARG(padapter)); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp) return != 0, break\n", + FUNC_ADPT_ARG(padapter)); break; } if ((padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true)) { - DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", - __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); + netdev_dbg(padapter->pnetdev, + "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", + __func__, padapter->bDriverStopped, + padapter->bSurpriseRemoved, __LINE__); break; } if (pcmdpriv->stop_req) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" stop_req:%u, break\n", FUNC_ADPT_ARG(padapter), pcmdpriv->stop_req); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " stop_req:%u, break\n", + FUNC_ADPT_ARG(padapter), + pcmdpriv->stop_req); break; } - if (list_empty(&(pcmdpriv->cmd_queue.queue))) { - /* DBG_871X("%s: cmd queue is empty!\n", __func__); */ + if (list_empty(&pcmdpriv->cmd_queue.queue)) continue; - } - if (rtw_register_cmd_alive(padapter) != _SUCCESS) { - RT_TRACE(_module_hal_xmit_c_, _drv_notice_, - ("%s: wait to leave LPS_LCLK\n", __func__)); + if (rtw_register_cmd_alive(padapter) != _SUCCESS) continue; - } _next: if ((padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true)) { - DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", - __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); + netdev_dbg(padapter->pnetdev, + "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", + __func__, padapter->bDriverStopped, + padapter->bSurpriseRemoved, __LINE__); break; } @@ -458,8 +444,6 @@ _next: continue; } - cmd_start_time = jiffies; - if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) { pcmd->res = H2C_DROPPED; goto post_process; @@ -490,8 +474,9 @@ post_process: if (mutex_lock_interruptible(&(pcmd->padapter->cmdpriv.sctx_mutex)) == 0) { if (pcmd->sctx) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pcmd->sctx\n", - FUNC_ADPT_ARG(pcmd->padapter)); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " pcmd->sctx\n", + FUNC_ADPT_ARG(pcmd->padapter)); if (pcmd->res == H2C_SUCCESS) rtw_sctx_done(&pcmd->sctx); @@ -501,25 +486,16 @@ post_process: mutex_unlock(&(pcmd->padapter->cmdpriv.sctx_mutex)); } - cmd_process_time = jiffies_to_msecs(jiffies - cmd_start_time); - if (cmd_process_time > 1000) { - DBG_871X("%s cmd= %d process_time= %lu > 1 sec\n", - ADPT_ARG(pcmd->padapter), pcmd->cmdcode, - cmd_process_time); - } - /* call callback function for post-processed */ if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) { pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; if (pcmd_callback == NULL) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode)); rtw_free_cmd_obj(pcmd); } else { /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */ pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */ } } else { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode)); rtw_free_cmd_obj(pcmd); } @@ -537,8 +513,6 @@ post_process: break; } - /* DBG_871X("%s: leaving... drop cmdcode:%u size:%d\n", __func__, pcmd->cmdcode, pcmd->cmdsz); */ - if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf; if (extra_parm->pbuf && extra_parm->size > 0) @@ -583,8 +557,6 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, rtw_free_network_queue(padapter, false); - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__)); - init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); /* psurveyPara->bsslimit = 48; */ @@ -597,9 +569,6 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, if (ssid[i].SsidLength) { memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid)); psurveyPara->ssid_num++; - - DBG_871X(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter), - psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength); } } } @@ -611,9 +580,6 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) { memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); psurveyPara->ch_num++; - - DBG_871X(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), - psurveyPara->ch[i].hw_value); } } } @@ -672,16 +638,9 @@ u8 rtw_createbss_cmd(struct adapter *padapter) { struct cmd_obj *pcmd; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network; u8 res = _SUCCESS; - if (pmlmepriv->assoc_ssid.SsidLength == 0) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); - } else { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); - } - pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); if (pcmd == NULL) { res = _FAIL; @@ -761,22 +720,15 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) struct security_priv *psecuritypriv = &padapter->securitypriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; struct ht_priv *phtpriv = &pmlmepriv->htpriv; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork->network.InfrastructureMode; + enum ndis_802_11_network_infrastructure ndis_network_mode = pnetwork->network.InfrastructureMode; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u32 tmp_len; u8 *ptmp = NULL; - if (pmlmepriv->assoc_ssid.SsidLength == 0) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n")); - } else { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid)); - } - pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); if (pcmd == NULL) { res = _FAIL; - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n")); goto exit; } /* for IEs is fix buf size */ @@ -810,11 +762,10 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength; - if ((psecnetwork->IELength-12) < (256-1)) { + if ((psecnetwork->IELength-12) < (256-1)) memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12); - } else { + else memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1)); - } psecnetwork->IELength = 0; /* Added by Albert 2009/02/18 */ @@ -886,8 +837,6 @@ u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueu struct cmd_priv *cmdpriv = &padapter->cmdpriv; u8 res = _SUCCESS; - RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n")); - /* prepare cmd parameter */ param = rtw_zmalloc(sizeof(*param)); if (param == NULL) { @@ -917,7 +866,7 @@ exit: return res; } -u8 rtw_setopmode_cmd(struct adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue) +u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infrastructure networktype, bool enqueue) { struct cmd_obj *ph2c; struct setopmode_parm *psetop; @@ -970,17 +919,15 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm; - } else { + else GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false); - } - if (unicast_key == true) { + if (unicast_key == true) memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); - } else { + else memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); - } /* jeff: set this because at least sw key is ready */ padapter->securitypriv.busetkipkey = true; @@ -1024,7 +971,9 @@ u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueu if (!enqueue) { while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1)) >= 0) { - DBG_871X_LEVEL(_drv_always_, "clear key for addr:%pM, camid:%d\n", MAC_ARG(sta->hwaddr), cam_id); + netdev_dbg(padapter->pnetdev, + "clear key for addr:%pM, camid:%d\n", + MAC_ARG(sta->hwaddr), cam_id); clear_cam_entry(padapter, cam_id); rtw_camid_free(padapter, cam_id); } @@ -1092,8 +1041,6 @@ u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr) init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); - /* DBG_871X("rtw_addbareq_cmd, tid =%d\n", tid); */ - /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ res = rtw_enqueue_cmd(pcmdpriv, ph2c); @@ -1214,8 +1161,6 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue, u8 swconf u8 res = _SUCCESS; - RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n")); - /* check if allow software config */ if (swconfig && rtw_hal_is_disable_sw_channel_plan(padapter) == true) { res = _FAIL; @@ -1333,7 +1278,6 @@ u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer) /* check traffic for powersaving. */ if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) { - /* DBG_871X("(-)Tx = %d, Rx = %d\n", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ bEnterPS = false; if (bBusyTraffic == true) { @@ -1342,14 +1286,10 @@ u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer) pmlmepriv->LinkDetectInfo.TrafficTransitionCount++; - /* DBG_871X("Set TrafficTransitionCount to %d\n", pmlmepriv->LinkDetectInfo.TrafficTransitionCount); */ - if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount > 30/*TrafficTransitionLevel*/) pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 30; } } else { - /* DBG_871X("(+)Tx = %d, Rx = %d\n", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ - if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount >= 2) pmlmepriv->LinkDetectInfo.TrafficTransitionCount -= 2; else @@ -1441,7 +1381,6 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) switch (lps_ctrl_type) { case LPS_CTRL_SCAN: - /* DBG_871X("LPS_CTRL_SCAN\n"); */ hal_btcoex_ScanNotify(padapter, true); if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { @@ -1450,11 +1389,9 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) } break; case LPS_CTRL_JOINBSS: - /* DBG_871X("LPS_CTRL_JOINBSS\n"); */ LPS_Leave(padapter, "LPS_CTRL_JOINBSS"); break; case LPS_CTRL_CONNECT: - /* DBG_871X("LPS_CTRL_CONNECT\n"); */ mstatus = 1;/* connect */ /* Reset LPS Setting */ pwrpriv->LpsIdleCount = 0; @@ -1462,20 +1399,17 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) rtw_btcoex_MediaStatusNotify(padapter, mstatus); break; case LPS_CTRL_DISCONNECT: - /* DBG_871X("LPS_CTRL_DISCONNECT\n"); */ mstatus = 0;/* disconnect */ rtw_btcoex_MediaStatusNotify(padapter, mstatus); LPS_Leave(padapter, "LPS_CTRL_DISCONNECT"); rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); break; case LPS_CTRL_SPECIAL_PACKET: - /* DBG_871X("LPS_CTRL_SPECIAL_PACKET\n"); */ pwrpriv->DelayLPSLastTimeStamp = jiffies; hal_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP); LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET"); break; case LPS_CTRL_LEAVE: - /* DBG_871X("LPS_CTRL_LEAVE\n"); */ LPS_Leave(padapter, "LPS_CTRL_LEAVE"); break; case LPS_CTRL_TRAFFIC_BUSY: @@ -1580,18 +1514,12 @@ static void rtw_lps_change_dtim_hdl(struct adapter *padapter, u8 dtim) mutex_lock(&pwrpriv->lock); - if (pwrpriv->dtim != dtim) { - DBG_871X("change DTIM from %d to %d, bFwCurrentInPSMode =%d, ps_mode =%d\n", pwrpriv->dtim, dtim, - pwrpriv->bFwCurrentInPSMode, pwrpriv->pwr_mode); - + if (pwrpriv->dtim != dtim) pwrpriv->dtim = dtim; - } - if ((pwrpriv->bFwCurrentInPSMode == true) && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) { + if (pwrpriv->fw_current_in_ps_mode && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) { u8 ps_mode = pwrpriv->pwr_mode; - /* DBG_871X("change DTIM from %d to %d, ps_mode =%d\n", pwrpriv->dtim, dtim, ps_mode); */ - rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); } @@ -1875,7 +1803,7 @@ exit: return res; } -static void c2h_wk_callback(_workitem *work) +static void c2h_wk_callback(struct work_struct *work) { struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv); @@ -1986,7 +1914,6 @@ void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) _set_timer(&pmlmepriv->scan_to_timer, 1); } else if (pcmd->res != H2C_SUCCESS) { _set_timer(&pmlmepriv->scan_to_timer, 1); - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n.")); } /* free cmd */ @@ -2002,7 +1929,6 @@ void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) set_fwstate(pmlmepriv, _FW_LINKED); spin_unlock_bh(&pmlmepriv->lock); - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n.")); return; } /* free cmd */ @@ -2035,10 +1961,8 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) if (pcmd->parmbuf == NULL) goto exit; - if ((pcmd->res != H2C_SUCCESS)) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback Fail ************\n\n.")); + if (pcmd->res != H2C_SUCCESS) _set_timer(&pmlmepriv->assoc_timer, 1); - } del_timer_sync(&pmlmepriv->assoc_timer); @@ -2049,10 +1973,8 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress); if (!psta) { psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); - if (psta == NULL) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n")); + if (!psta) goto createbss_cmd_fail; - } } rtw_indicate_connect(padapter); @@ -2062,7 +1984,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) if (pwlan == NULL) { pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); if (pwlan == NULL) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n Error: can't get pwlan in rtw_joinbss_event_callback\n")); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); goto createbss_cmd_fail; } @@ -2106,10 +2027,9 @@ void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pc struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) (pcmd->rsp); struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); - if (psta == NULL) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n")); + if (!psta) goto exit; - } + exit: rtw_free_cmd_obj(pcmd); } @@ -2122,10 +2042,8 @@ void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj * struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *) (pcmd->rsp); struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); - if (psta == NULL) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n")); + if (!psta) goto exit; - } psta->aid = passocsta_rsp->cam_id; psta->mac_id = passocsta_rsp->cam_id; diff --git a/drivers/staging/rtl8723bs/core/rtw_debug.c b/drivers/staging/rtl8723bs/core/rtw_debug.c index c48a8b80af4c14aff1b9b8335b5ae3f8e7116e58..79fd968bb147761fe456931f19b67560d22d30b2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_debug.c +++ b/drivers/staging/rtl8723bs/core/rtw_debug.c @@ -12,60 +12,15 @@ u32 GlobalDebugLevel = _drv_err_; -#ifdef DEBUG_RTL871X - - u64 GlobalDebugComponents = \ - _module_rtl871x_xmit_c_ | - _module_xmit_osdep_c_ | - _module_rtl871x_recv_c_ | - _module_recv_osdep_c_ | - _module_rtl871x_mlme_c_ | - _module_mlme_osdep_c_ | - _module_rtl871x_sta_mgt_c_ | - _module_rtl871x_cmd_c_ | - _module_cmd_osdep_c_ | - _module_rtl871x_io_c_ | - _module_io_osdep_c_ | - _module_os_intfs_c_| - _module_rtl871x_security_c_| - _module_rtl871x_eeprom_c_| - _module_hal_init_c_| - _module_hci_hal_init_c_| - _module_rtl871x_ioctl_c_| - _module_rtl871x_ioctl_set_c_| - _module_rtl871x_ioctl_query_c_| - _module_rtl871x_pwrctrl_c_| - _module_hci_intfs_c_| - _module_hci_ops_c_| - _module_hci_ops_os_c_| - _module_rtl871x_ioctl_os_c| - _module_rtl8712_cmd_c_| - _module_hal_xmit_c_| - _module_rtl8712_recv_c_ | - _module_mp_ | - _module_efuse_; - -#endif /* DEBUG_RTL871X */ - #include <rtw_version.h> -void dump_drv_version(void *sel) -{ - DBG_871X_SEL_NL(sel, "%s %s\n", "rtl8723bs", DRIVERVERSION); -} - -void dump_log_level(void *sel) -{ - DBG_871X_SEL_NL(sel, "log_level:%d\n", GlobalDebugLevel); -} - void sd_f0_reg_dump(void *sel, struct adapter *adapter) { int i; for (i = 0x0; i <= 0xff; i++) { if (i%16 == 0) - DBG_871X_SEL_NL(sel, "0x%02x ", i); + netdev_dbg(adapter->pnetdev, "0x%02x ", i); DBG_871X_SEL(sel, "%02x ", rtw_sd_f0_read8(adapter, i)); @@ -80,11 +35,11 @@ void mac_reg_dump(void *sel, struct adapter *adapter) { int i, j = 1; - DBG_871X_SEL_NL(sel, "======= MAC REG =======\n"); + netdev_dbg(adapter->pnetdev, "======= MAC REG =======\n"); for (i = 0x0; i < 0x800; i += 4) { if (j%4 == 1) - DBG_871X_SEL_NL(sel, "0x%03x", i); + netdev_dbg(adapter->pnetdev, "0x%03x", i); DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); if ((j++)%4 == 0) DBG_871X_SEL(sel, "\n"); @@ -95,10 +50,10 @@ void bb_reg_dump(void *sel, struct adapter *adapter) { int i, j = 1; - DBG_871X_SEL_NL(sel, "======= BB REG =======\n"); + netdev_dbg(adapter->pnetdev, "======= BB REG =======\n"); for (i = 0x800; i < 0x1000 ; i += 4) { if (j%4 == 1) - DBG_871X_SEL_NL(sel, "0x%03x", i); + netdev_dbg(adapter->pnetdev, "0x%03x", i); DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); if ((j++)%4 == 0) DBG_871X_SEL(sel, "\n"); @@ -118,14 +73,14 @@ void rf_reg_dump(void *sel, struct adapter *adapter) else path_nums = 2; - DBG_871X_SEL_NL(sel, "======= RF REG =======\n"); + netdev_dbg(adapter->pnetdev, "======= RF REG =======\n"); for (path = 0; path < path_nums; path++) { - DBG_871X_SEL_NL(sel, "RF_Path(%x)\n", path); + netdev_dbg(adapter->pnetdev, "RF_Path(%x)\n", path); for (i = 0; i < 0x100; i++) { value = rtw_hal_read_rfreg(adapter, path, i, 0xffffffff); if (j%4 == 1) - DBG_871X_SEL_NL(sel, "0x%02x ", i); + netdev_dbg(adapter->pnetdev, "0x%02x ", i); DBG_871X_SEL(sel, " 0x%08x ", value); if ((j++)%4 == 0) DBG_871X_SEL(sel, "\n"); diff --git a/drivers/staging/rtl8723bs/core/rtw_eeprom.c b/drivers/staging/rtl8723bs/core/rtw_eeprom.c index 3cbd65dee741b1adfe31fd728e78a49c0f12c62b..be0eda1604d062c5e39d1907bcb1bd5847bede6d 100644 --- a/drivers/staging/rtl8723bs/core/rtw_eeprom.c +++ b/drivers/staging/rtl8723bs/core/rtw_eeprom.c @@ -35,10 +35,9 @@ void shift_out_bits(_adapter *padapter, u16 data, u16 count) u16 x, mask; _func_enter_; - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + mask = 0x01 << (count - 1); x = rtw_read8(padapter, EE_9346CR); @@ -48,20 +47,18 @@ _func_enter_; x &= ~_EEDI; if (data & mask) x |= _EEDI; - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); - goto out; - } + if (padapter->bSurpriseRemoved) + goto out; + rtw_write8(padapter, EE_9346CR, (u8)x); udelay(CLOCK_RATE); up_clk(padapter, &x); down_clk(padapter, &x); mask = mask >> 1; } while (mask); - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + x &= ~_EEDI; rtw_write8(padapter, EE_9346CR, (u8)x); out: @@ -72,10 +69,9 @@ u16 shift_in_bits(_adapter *padapter) { u16 x, d = 0, i; _func_enter_; - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + x = rtw_read8(padapter, EE_9346CR); x &= ~(_EEDO | _EEDI); @@ -84,10 +80,9 @@ _func_enter_; for (i = 0; i < 16; i++) { d = d << 1; up_clk(padapter, &x); - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + x = rtw_read8(padapter, EE_9346CR); x &= ~(_EEDI); @@ -122,26 +117,22 @@ void eeprom_clean(_adapter *padapter) { u16 x; _func_enter_; - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + x = rtw_read8(padapter, EE_9346CR); - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + x &= ~(_EECS | _EEDI); rtw_write8(padapter, EE_9346CR, (u8)x); - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + up_clk(padapter, &x); - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + down_clk(padapter, &x); out: _func_exit_; @@ -155,17 +146,14 @@ u16 eeprom_read16(_adapter *padapter, u16 reg) /*ReadEEprom*/ _func_enter_; - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } + /* select EEPROM, reset bits, set _EECS*/ x = rtw_read8(padapter, EE_9346CR); - if (padapter->bSurpriseRemoved == true) { - RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true")); + if (padapter->bSurpriseRemoved) goto out; - } x &= ~(_EEDI | _EEDO | _EESK | _EEM0); x |= _EEM1 | _EECS; diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 32ca10f01413d8fa73a6d492bc248175e6fe7478..a28a06d5a576439733ace6b3a3c4febf90f77173 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -32,12 +32,7 @@ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; #define REG_EFUSE_CTRL 0x0030 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ -bool -Efuse_Read1ByteFromFakeContent( - struct adapter *padapter, - u16 Offset, - u8 *Value); -bool +static bool Efuse_Read1ByteFromFakeContent( struct adapter *padapter, u16 Offset, @@ -53,12 +48,7 @@ Efuse_Read1ByteFromFakeContent( return true; } -bool -Efuse_Write1ByteToFakeContent( - struct adapter *padapter, - u16 Offset, - u8 Value); -bool +static bool Efuse_Write1ByteToFakeContent( struct adapter *padapter, u16 Offset, @@ -262,9 +252,6 @@ bool bPseudoTest) u8 bResult; u8 readbyte; - /* DBG_871X("===> EFUSE_OneByteRead(), addr = %x\n", addr); */ - /* DBG_871X("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ - if (bPseudoTest) { return Efuse_Read1ByteFromFakeContent(padapter, addr, data); } @@ -295,8 +282,6 @@ bool bPseudoTest) } else { *data = 0xff; bResult = false; - DBG_871X("%s: [ERROR] addr = 0x%x bResult =%d time out 1s !!!\n", __func__, addr, bResult); - DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); } return bResult; @@ -309,9 +294,6 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT u8 bResult = false; u32 efuseValue = 0; - /* DBG_871X("===> EFUSE_OneByteWrite(), addr = %x data =%x\n", addr, data); */ - /* DBG_871X("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ - if (bPseudoTest) { return Efuse_Write1ByteToFakeContent(padapter, addr, data); } @@ -344,9 +326,6 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT bResult = true; } else { bResult = false; - DBG_871X("%s: [ERROR] addr = 0x%x , efuseValue = 0x%x , bResult =%d time out 1s !!!\n", - __func__, addr, efuseValue, bResult); - DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); } /* disable Efuse program enable */ diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index be4cffce4f5d693e923e06df59f36c404b314517..ae057eefeeb3603c5d8cb663452cf20371d818ab 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -120,7 +120,7 @@ u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *sourc /* rtw_set_ie will update frame length */ u8 *rtw_set_ie(u8 *pbuf, - sint index, + signed int index, uint len, u8 *source, uint *frlen) /* frame length */ @@ -140,9 +140,9 @@ u8 *rtw_set_ie(u8 *pbuf, /*---------------------------------------------------------------------------- index: the information element id index, limit is the limit for search -----------------------------------------------------------------------------*/ -u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit) +u8 *rtw_get_ie(u8 *pbuf, signed int index, signed int *len, signed int limit) { - sint tmp, i; + signed int tmp, i; u8 *p; if (limit < 1) @@ -488,11 +488,8 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; - } else if (left > 0) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left)); - + } else if (left > 0) return _FAIL; - } /* pairwise_cipher */ if (left >= 2) { @@ -501,11 +498,8 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis pos += 2; left -= 2; - if (count == 0 || left < count * WPA_SELECTOR_LEN) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), " - "count %u left %u", __func__, count, left)); + if (count == 0 || left < count * WPA_SELECTOR_LEN) return _FAIL; - } for (i = 0; i < count; i++) { *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos); @@ -514,16 +508,13 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis left -= WPA_SELECTOR_LEN; } - } else if (left == 1) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__)); + } else if (left == 1) return _FAIL; - } if (is_8021x) { if (left >= 6) { pos += 2; if (!memcmp(pos, SUITE_1X, 4)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__)); *is_8021x = 1; } } @@ -559,10 +550,8 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; - } else if (left > 0) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left)); + } else if (left > 0) return _FAIL; - } /* pairwise_cipher */ if (left >= 2) { @@ -571,11 +560,8 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi pos += 2; left -= 2; - if (count == 0 || left < count * RSN_SELECTOR_LEN) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), " - "count %u left %u", __func__, count, left)); + if (count == 0 || left < count * RSN_SELECTOR_LEN) return _FAIL; - } for (i = 0; i < count; i++) { *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos); @@ -584,19 +570,14 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi left -= RSN_SELECTOR_LEN; } - } else if (left == 1) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__)); - + } else if (left == 1) return _FAIL; - } if (is_8021x) { if (left >= 6) { pos += 2; - if (!memcmp(pos, SUITE_1X, 4)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__)); + if (!memcmp(pos, SUITE_1X, 4)) *is_8021x = 1; - } } } @@ -607,7 +588,7 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len) { int len = 0; - u8 authmode, i; + u8 authmode; uint cnt; u8 wapi_oui1[4] = {0x0, 0x14, 0x72, 0x01}; u8 wapi_oui2[4] = {0x0, 0x14, 0x72, 0x02}; @@ -626,16 +607,9 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len) /* if (authmode == WLAN_EID_BSS_AC_ACCESS_DELAY) */ if (authmode == WLAN_EID_BSS_AC_ACCESS_DELAY && (!memcmp(&in_ie[cnt+6], wapi_oui1, 4) || !memcmp(&in_ie[cnt+6], wapi_oui2, 4))) { - if (wapi_ie) { + if (wapi_ie) memcpy(wapi_ie, &in_ie[cnt], in_ie[cnt+1]+2); - for (i = 0; i < (in_ie[cnt+1]+2); i = i+8) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n", - wapi_ie[i], wapi_ie[i+1], wapi_ie[i+2], wapi_ie[i+3], wapi_ie[i+4], - wapi_ie[i+5], wapi_ie[i+6], wapi_ie[i+7])); - } - } - if (wapi_len) *wapi_len = in_ie[cnt+1]+2; @@ -654,7 +628,7 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len) void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len) { - u8 authmode, sec_idx, i; + u8 authmode; u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; uint cnt; @@ -662,39 +636,19 @@ void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); - sec_idx = 0; - while (cnt < in_len) { authmode = in_ie[cnt]; if ((authmode == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n", sec_idx, in_ie[cnt+1]+2)); - - if (wpa_ie) { + if (wpa_ie) memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt+1]+2); - for (i = 0; i < (in_ie[cnt+1]+2); i = i+8) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n", - wpa_ie[i], wpa_ie[i+1], wpa_ie[i+2], wpa_ie[i+3], wpa_ie[i+4], - wpa_ie[i+5], wpa_ie[i+6], wpa_ie[i+7])); - } - } - - *wpa_len = in_ie[cnt+1]+2; - cnt += in_ie[cnt+1]+2; /* get next */ + *wpa_len = in_ie[cnt + 1] + 2; + cnt += in_ie[cnt + 1] + 2; /* get next */ } else { if (authmode == WLAN_EID_RSN) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n get_rsn_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n", sec_idx, in_ie[cnt+1]+2)); - - if (rsn_ie) { - memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt+1]+2); - - for (i = 0; i < (in_ie[cnt+1]+2); i = i+8) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n", - rsn_ie[i], rsn_ie[i+1], rsn_ie[i+2], rsn_ie[i+3], rsn_ie[i+4], - rsn_ie[i+5], rsn_ie[i+6], rsn_ie[i+7])); - } - } + if (rsn_ie) + 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 */ @@ -716,7 +670,6 @@ u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen) eid = ie_ptr[0]; if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&ie_ptr[2], wps_oui, 4))) { - /* DBG_8192C("==> found WPS_IE.....\n"); */ *wps_ielen = ie_ptr[1]+2; match = true; } @@ -802,7 +755,6 @@ u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_att u16 attr_data_len = get_unaligned_be16(attr_ptr + 2); u16 attr_len = attr_data_len + 4; - /* DBG_871X("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */ if (attr_id == target_attr_id) { target_attr_ptr = attr_ptr; @@ -863,14 +815,8 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, /* first 3 bytes in vendor specific information element are the IEEE * OUI of the vendor. The following byte is used a vendor specific * sub-type. */ - if (elen < 4) { - if (show_errors) { - DBG_871X("short vendor specific " - "information element ignored (len =%lu)\n", - (unsigned long) elen); - } + if (elen < 4) return -1; - } oui = get_unaligned_be24(pos); switch (oui) { @@ -885,13 +831,9 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, elems->wpa_ie_len = elen; break; case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ - if (elen < 5) { - DBG_871X("short WME " - "information element ignored " - "(len =%lu)\n", - (unsigned long) elen); + if (elen < 5) return -1; - } + switch (pos[4]) { case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: @@ -903,10 +845,6 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, elems->wme_tspec_len = elen; break; default: - DBG_871X("unknown WME " - "information element ignored " - "(subtype =%d len =%lu)\n", - pos[4], (unsigned long) elen); return -1; } break; @@ -916,10 +854,6 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, elems->wps_ie_len = elen; break; default: - DBG_871X("Unknown Microsoft " - "information element ignored " - "(type =%d len =%lu)\n", - pos[3], (unsigned long) elen); return -1; } break; @@ -931,19 +865,11 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, elems->vendor_ht_cap_len = elen; break; default: - DBG_871X("Unknown Broadcom " - "information element ignored " - "(type =%d len =%lu)\n", - pos[3], (unsigned long) elen); return -1; } break; default: - DBG_871X("unknown vendor specific information " - "element ignored (vendor OUI %02x:%02x:%02x " - "len =%lu)\n", - pos[0], pos[1], pos[2], (unsigned long) elen); return -1; } @@ -958,7 +884,7 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, * @show_errors: Whether to show parsing errors in debug log * Returns: Parsing result */ -ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, +enum ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, struct rtw_ieee802_11_elems *elems, int show_errors) { @@ -975,15 +901,8 @@ ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, elen = *pos++; left -= 2; - if (elen > left) { - if (show_errors) { - DBG_871X("IEEE 802.11 element " - "parse failed (id =%d elen =%d " - "left =%lu)\n", - id, elen, (unsigned long) left); - } + if (elen > left) return ParseFailed; - } switch (id) { case WLAN_EID_SSID: @@ -1078,11 +997,6 @@ ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, break; default: unknown++; - if (!show_errors) - break; - DBG_871X("IEEE 802.11 element parse " - "ignored unknown element (id =%d elen =%d)\n", - id, elen); break; } @@ -1115,16 +1029,14 @@ void rtw_macaddr_cfg(struct device *dev, u8 *mac_addr) } if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) { - if ((addr = of_get_property(np, "local-mac-address", &len)) && - len == ETH_ALEN) { + addr = of_get_property(np, "local-mac-address", &len); + + if (addr && len == ETH_ALEN) { ether_addr_copy(mac_addr, addr); } else { eth_random_addr(mac_addr); - DBG_871X("MAC Address from efuse error, assign random one !!!\n"); } } - - DBG_871X("rtw_macaddr_cfg MAC Address = %pM\n", MAC_ARG(mac_addr)); } static int rtw_get_cipher_info(struct wlan_network *pnetwork) @@ -1137,28 +1049,20 @@ static int rtw_get_cipher_info(struct wlan_network *pnetwork) pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); if (pbuf && (wpa_ielen > 0)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; pnetwork->BcnInfo.group_cipher = group_cipher; pnetwork->BcnInfo.is_8021x = is8021x; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d", - __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x)); ret = _SUCCESS; } } else { pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); if (pbuf && (wpa_ielen > 0)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n")); if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE OK!!!\n")); pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; pnetwork->BcnInfo.group_cipher = group_cipher; pnetwork->BcnInfo.is_8021x = is8021x; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d," - "pnetwork->group_cipher is %d, is_8021x is %d", __func__, pnetwork->BcnInfo.pairwise_cipher, - pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x)); ret = _SUCCESS; } } @@ -1188,10 +1092,6 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork) pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; } rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); if (rsn_len > 0) { pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; @@ -1201,10 +1101,6 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork) if (bencrypt) pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; } - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", - pnetwork->BcnInfo.encryp_protocol)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", - pnetwork->BcnInfo.encryp_protocol)); rtw_get_cipher_info(pnetwork); /* get bwmode and ch_offset */ diff --git a/drivers/staging/rtl8723bs/core/rtw_io.c b/drivers/staging/rtl8723bs/core/rtw_io.c index c3f63f90354718ca8b8874dbd7eb2c4a0b27d7da..c860ab7d618c3ec9af39f81d0e6b0e06b05f9c84 100644 --- a/drivers/staging/rtl8723bs/core/rtw_io.c +++ b/drivers/staging/rtl8723bs/core/rtw_io.c @@ -130,7 +130,9 @@ u8 _rtw_sd_f0_read8(struct adapter *adapter, u32 addr) if (_sd_f0_read8) r_val = _sd_f0_read8(pintfhdl, addr); else - DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" _sd_f0_read8 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + netdev_warn(adapter->pnetdev, + FUNC_ADPT_FMT " _sd_f0_read8 callback is NULL\n", + FUNC_ADPT_ARG(adapter)); return r_val; } @@ -172,12 +174,9 @@ int rtw_inc_and_chk_continual_io_error(struct dvobj_priv *dvobj) { int ret = false; int value = atomic_inc_return(&dvobj->continual_io_error); - if (value > MAX_CONTINUAL_IO_ERR) { - DBG_871X("[dvobj:%p][ERROR] continual_io_error:%d > %d\n", dvobj, value, MAX_CONTINUAL_IO_ERR); + if (value > MAX_CONTINUAL_IO_ERR) ret = true; - } else { - /* DBG_871X("[dvobj:%p] continual_io_error:%d\n", dvobj, value); */ - } + return ret; } diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c index 1cfdf7c9366201b04ecea501a031c74449cbed73..bd5056507f5376487c1de1f3192b213f0d59c61b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c @@ -28,27 +28,14 @@ u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid) u8 ret = true; if (ssid->SsidLength > 32) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n")); ret = false; goto exit; } -#ifdef CONFIG_VALIDATE_SSID - for (i = 0; i < ssid->SsidLength; i++) { - /* wifi, printable ascii code must be supported */ - if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid has non-printable ascii\n")); - ret = false; - break; - } - } -#endif /* CONFIG_VALIDATE_SSID */ - exit: return ret; } -u8 rtw_do_join(struct adapter *padapter); u8 rtw_do_join(struct adapter *padapter) { struct list_head *plist, *phead; @@ -61,8 +48,6 @@ u8 rtw_do_join(struct adapter *padapter) phead = get_list_head(queue); plist = get_next(phead); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n rtw_do_join: phead = %p; plist = %p\n\n\n", phead, plist)); - pmlmepriv->cur_network.join_res = -2; set_fwstate(pmlmepriv, _FW_UNDER_LINKING); @@ -81,13 +66,11 @@ u8 rtw_do_join(struct adapter *padapter) if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false || rtw_to_roam(padapter) > 0 ) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join(): site survey if scanned_queue is empty\n.")); /* submit site_survey_cmd */ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); - if (_SUCCESS != ret) { + if (ret != _SUCCESS) pmlmepriv->to_join = false; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_do_join(): site survey return error\n.")); - } + } else { pmlmepriv->to_join = false; ret = _FAIL; @@ -119,15 +102,12 @@ u8 rtw_do_join(struct adapter *padapter) rtw_generate_random_ibss(pibss); if (rtw_createbss_cmd(padapter) != _SUCCESS) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>do_goin: rtw_createbss_cmd status FAIL***\n ")); ret = false; goto exit; } pmlmepriv->to_join = false; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("***Error => rtw_select_and_join_from_scanned_queue FAIL under STA_Mode***\n ")); - } else { /* can't associate ; reset under-linking */ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); @@ -137,12 +117,10 @@ u8 rtw_do_join(struct adapter *padapter) if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false || rtw_to_roam(padapter) > 0 ) { - /* DBG_871X("rtw_do_join() when no desired bss in scanning queue\n"); */ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); - if (_SUCCESS != ret) { + if (ret != _SUCCESS) pmlmepriv->to_join = false; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n.")); - } + } else { ret = _FAIL; pmlmepriv->to_join = false; @@ -163,7 +141,7 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - DBG_871X_LEVEL(_drv_always_, "set bssid:%pM\n", bssid); + netdev_dbg(padapter->pnetdev, "set bssid:%pM\n", bssid); if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 && bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) || (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF && bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) { @@ -174,23 +152,16 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) spin_lock_bh(&pmlmepriv->lock); - DBG_871X("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) goto handle_tkip_countermeasure; else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) goto release_mlme_lock; if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); - if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) { if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false) goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ } else { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n")); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid =%pM\n", MAC_ARG(bssid))); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid =%pM\n", MAC_ARG(pmlmepriv->cur_network.network.MacAddress))); - rtw_disassoc_cmd(padapter, 0, true); if (check_fwstate(pmlmepriv, _FW_LINKED) == true) @@ -224,8 +195,6 @@ release_mlme_lock: spin_unlock_bh(&pmlmepriv->lock); exit: - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("rtw_set_802_11_bssid: status =%d\n", status)); return status; } @@ -237,35 +206,25 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *pnetwork = &pmlmepriv->cur_network; - DBG_871X_LEVEL(_drv_always_, "set ssid [%s] fw_state = 0x%08x\n", - ssid->Ssid, get_fwstate(pmlmepriv)); + netdev_dbg(padapter->pnetdev, "set ssid [%s] fw_state = 0x%08x\n", + ssid->Ssid, get_fwstate(pmlmepriv)); if (padapter->hw_init_completed == false) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("set_ssid: hw_init_completed ==false =>exit!!!\n")); status = _FAIL; goto exit; } spin_lock_bh(&pmlmepriv->lock); - DBG_871X("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) goto handle_tkip_countermeasure; else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) goto release_mlme_lock; if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, - ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); - if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) { if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("Set SSID is the same ssid, fw_state = 0x%08x\n", - get_fwstate(pmlmepriv))); - if (rtw_is_same_ibss(padapter, pnetwork) == false) { /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */ rtw_disassoc_cmd(padapter, 0, true); @@ -286,10 +245,6 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1); } } else { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n")); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength)); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength)); - rtw_disassoc_cmd(padapter, 0, true); if (check_fwstate(pmlmepriv, _FW_LINKED) == true) @@ -327,8 +282,6 @@ release_mlme_lock: spin_unlock_bh(&pmlmepriv->lock); exit: - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("-rtw_set_802_11_ssid: status =%d\n", status)); return status; } @@ -347,23 +300,19 @@ u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_1 bssid_valid = false; if (!ssid_valid && !bssid_valid) { - DBG_871X(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n", - FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid); status = _FAIL; goto exit; } if (padapter->hw_init_completed == false) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("set_ssid: hw_init_completed ==false =>exit!!!\n")); status = _FAIL; goto exit; } spin_lock_bh(&pmlmepriv->lock); - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" fw_state = 0x%08x\n", - FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); + netdev_dbg(padapter->pnetdev, FUNC_ADPT_FMT " fw_state = 0x%08x\n", + FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) goto handle_tkip_countermeasure; @@ -401,20 +350,13 @@ exit: } u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) + enum ndis_802_11_network_infrastructure networktype) { 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); - - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_, - ("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n", - *pold_state, networktype, get_fwstate(pmlmepriv))); + enum ndis_802_11_network_infrastructure *pold_state = &(cur_network->network.InfrastructureMode); if (*pold_state != networktype) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!")); - /* DBG_871X("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ - if (*pold_state == Ndis802_11APMode) { /* change to other mode from Ndis802_11APMode */ cur_network->join_res = -1; @@ -463,9 +405,6 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, /* SecClearAllKeys(adapter); */ - /* RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", */ - /* get_fwstate(pmlmepriv))); */ - spin_unlock_bh(&pmlmepriv->lock); } return true; @@ -479,14 +418,11 @@ u8 rtw_set_802_11_disassociate(struct adapter *padapter) spin_lock_bh(&pmlmepriv->lock); if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n")); - rtw_disassoc_cmd(padapter, 0, true); rtw_indicate_disconnect(padapter); /* modify for CONFIG_IEEE80211W, none 11w can use it */ rtw_free_assoc_resources_cmd(padapter); - if (_FAIL == rtw_pwr_wakeup(padapter)) - DBG_871X("%s(): rtw_pwr_wakeup fail !!!\n", __func__); + rtw_pwr_wakeup(padapter); } spin_unlock_bh(&pmlmepriv->lock); @@ -499,31 +435,22 @@ u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_s struct mlme_priv *pmlmepriv = &padapter->mlmepriv; u8 res = true; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv))); - if (padapter == NULL) { res = false; goto exit; } if (padapter->hw_init_completed == false) { res = false; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n ===rtw_set_802_11_bssid_list_scan:hw_init_completed ==false ===\n")); goto exit; } if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) || (pmlmepriv->LinkDetectInfo.bBusyTraffic == true)) { /* Scan or linking is in progress, do nothing. */ - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv))); res = true; - if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true) - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n")); - else - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy ==true\n\n")); } else { if (rtw_is_scan_deny(padapter)) { - DBG_871X(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter)); indicate_wx_scan_complete_event(padapter); return _SUCCESS; } @@ -539,18 +466,14 @@ exit: return res; } -u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum NDIS_802_11_AUTHENTICATION_MODE authmode) +u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_authentication_mode authmode) { struct security_priv *psecuritypriv = &padapter->securitypriv; int res; u8 ret; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_802_11_auth.mode(): mode =%x\n", authmode)); - psecuritypriv->ndisauthtype = authmode; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype =%d", psecuritypriv->ndisauthtype)); - if (psecuritypriv->ndisauthtype > 3) psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; @@ -567,14 +490,13 @@ u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum NDIS_802_11 u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep) { - sint keyid, res; + signed int keyid, res; struct security_priv *psecuritypriv = &(padapter->securitypriv); u8 ret = _SUCCESS; keyid = wep->KeyIndex & 0x3fffffff; if (keyid >= 4) { - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MgntActrtw_set_802_11_add_wep:keyid>4 =>fail\n")); ret = false; goto exit; } @@ -582,35 +504,21 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep) switch (wep->KeyLength) { case 5: psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength =5\n")); break; case 13: psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 13\n")); break; default: psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength!=5 or 13\n")); break; } - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, - ("rtw_set_802_11_add_wep:before memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n", - wep->KeyLength, wep->KeyIndex, keyid)); - memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength); psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength; psecuritypriv->dot11PrivacyKeyIndex = keyid; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_set_802_11_add_wep:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x\n", - psecuritypriv->dot11DefKey[keyid].skey[0], psecuritypriv->dot11DefKey[keyid].skey[1], psecuritypriv->dot11DefKey[keyid].skey[2], - psecuritypriv->dot11DefKey[keyid].skey[3], psecuritypriv->dot11DefKey[keyid].skey[4], psecuritypriv->dot11DefKey[keyid].skey[5], - psecuritypriv->dot11DefKey[keyid].skey[6], psecuritypriv->dot11DefKey[keyid].skey[7], psecuritypriv->dot11DefKey[keyid].skey[8], - psecuritypriv->dot11DefKey[keyid].skey[9], psecuritypriv->dot11DefKey[keyid].skey[10], psecuritypriv->dot11DefKey[keyid].skey[11], - psecuritypriv->dot11DefKey[keyid].skey[12])); - res = rtw_set_key(padapter, psecuritypriv, keyid, 1, true); if (res == _FAIL) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 2c9425e2a1e99df4e0f610724ab0b8086f3685fb..4707dba90397e1e3e3377f3681b545da81f96bc9 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -12,8 +12,6 @@ #include <hal_btcoex.h> #include <linux/jiffies.h> -extern u8 rtw_do_join(struct adapter *padapter); - int rtw_init_mlme_priv(struct adapter *padapter) { int i; @@ -67,9 +65,6 @@ int rtw_init_mlme_priv(struct adapter *padapter) pmlmepriv->roam_flags = 0 | RTW_ROAM_ON_EXPIRED | RTW_ROAM_ON_RESUME - #ifdef CONFIG_LAYER2_ROAMING_ACTIVE /* FIXME */ - | RTW_ROAM_ACTIVE - #endif ; pmlmepriv->roam_scanr_exp_ms = RTW_ROAM_SCAN_RESULT_EXP_MS; @@ -160,8 +155,6 @@ struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) list_del_init(&pnetwork->list); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("rtw_alloc_network: ptr =%p\n", plist)); pnetwork->network_type = 0; pnetwork->fixed = false; pnetwork->last_scanned = jiffies; @@ -207,8 +200,6 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor pmlmepriv->num_of_scanned--; - /* DBG_871X("_rtw_free_network:SSID =%s\n", pnetwork->network.Ssid.Ssid); */ - spin_unlock_bh(&free_queue->lock); } @@ -298,16 +289,16 @@ void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall) spin_unlock_bh(&scanned_queue->lock); } -sint rtw_if_up(struct adapter *padapter) +signed int rtw_if_up(struct adapter *padapter) { - sint res; + signed int res; if (padapter->bDriverStopped || padapter->bSurpriseRemoved || - (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); + (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) res = false; - } else + else res = true; + return res; } @@ -344,7 +335,6 @@ u8 *rtw_get_beacon_interval_from_ie(u8 *ie) void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv\n")); _rtw_free_mlme_priv(pmlmepriv); } @@ -361,7 +351,6 @@ static struct wlan_network *rtw_dequeue_network(struct __queue *queue) void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork); void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork) { - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_network ==> ssid = %s\n\n" , pnetwork->network.Ssid.Ssid)); */ _rtw_free_network_nolock(&(padapter->mlmepriv), pnetwork); rtw_cfg80211_unlink_bss(padapter, pnetwork); } @@ -398,8 +387,6 @@ int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork) inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) { - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("(%s,%d)(%s,%d)\n", */ - /* a->Ssid.Ssid, a->Ssid.SsidLength, b->Ssid.Ssid, b->Ssid.SsidLength)); */ return (a->Ssid.SsidLength == b->Ssid.SsidLength) && !memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength); } @@ -492,17 +479,6 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, u8 sq_final; long rssi_final; - #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 - if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { - DBG_871X(FUNC_ADPT_FMT" %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n" - , FUNC_ADPT_ARG(padapter) - , src->Ssid.Ssid, MAC_ARG(src->MacAddress), src->Configuration.DSConfig - , ss_ori, sq_ori, rssi_ori - , ss_smp, sq_smp, rssi_smp - ); - } - #endif - /* The rule below is 1/5 for sample value, 4/5 for history value */ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) { /* Take the recvpriv's value for the connected AP*/ @@ -536,14 +512,6 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, dst->PhyInfo.SignalStrength = ss_final; dst->PhyInfo.SignalQuality = sq_final; dst->Rssi = rssi_final; - - #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 - if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { - DBG_871X(FUNC_ADPT_FMT" %s(%pM), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n" - , FUNC_ADPT_ARG(padapter) - , dst->Ssid.Ssid, MAC_ARG(dst->MacAddress), dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi); - } - #endif } static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) @@ -556,8 +524,6 @@ static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex &(pmlmepriv->cur_network.network)); if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) { - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"Same Network\n"); */ - /* if (pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */ { update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true); @@ -599,7 +565,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t } if (rtw_roam_flags(adapter)) { - /* TODO: don't select netowrk in the same ess as oldest if it's new enough*/ + /* TODO: don't select network in the same ess as oldest if it's new enough*/ } if (oldest == NULL || time_after(oldest->last_scanned, pnetwork->last_scanned)) @@ -617,10 +583,9 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t /* If there are no more slots, expire the oldest */ /* list_del_init(&oldest->list); */ pnetwork = oldest; - if (!pnetwork) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); + if (!pnetwork) goto exit; - } + memcpy(&(pnetwork->network), target, get_wlan_bssid_ex_sz(target)); /* variable initialize */ pnetwork->fixed = false; @@ -638,10 +603,8 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */ - if (!pnetwork) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); + if (!pnetwork) goto exit; - } bssid_ex_sz = get_wlan_bssid_ex_sz(target); target->Length = bssid_ex_sz; @@ -744,10 +707,8 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor } } - if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { - DBG_871X("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); + if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) bselected = false; - } if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) @@ -760,7 +721,6 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor /* TODO: Perry : For Power Management */ void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_event\n")); } void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) @@ -771,19 +731,14 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) pnetwork = (struct wlan_bssid_ex *)pbuf; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_survey_event_callback, ssid =%s\n", pnetwork->Ssid.Ssid)); - len = get_wlan_bssid_ex_sz(pnetwork); - if (len > (sizeof(struct wlan_bssid_ex))) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n ****rtw_survey_event_callback: return a wrong bss ***\n")); + if (len > (sizeof(struct wlan_bssid_ex))) return; - } spin_lock_bh(&pmlmepriv->lock); /* update IBSS_network 's timestamp */ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) { - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"rtw_survey_event_callback : WIFI_ADHOC_MASTER_STATE\n\n"); */ if (!memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) { struct wlan_network *ibss_wlan = NULL; @@ -822,14 +777,9 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) pmlmepriv->wps_probe_req_ie = NULL; } - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback: fw_state:%x\n\n", get_fwstate(pmlmepriv))); - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { del_timer_sync(&pmlmepriv->scan_to_timer); _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); - } else { - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status =%x, survey done event comes too late!\n", get_fwstate(pmlmepriv))); } rtw_set_signal_stat_timer(&adapter->recvpriv); @@ -842,14 +792,13 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) { _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); } else { + u8 ret = _SUCCESS; struct wlan_bssid_ex *pdev_network = &(adapter->registrypriv.dev_network); u8 *pibss = adapter->registrypriv.dev_network.MacAddress; /* pmlmepriv->fw_state ^= _FW_UNDER_SURVEY;because don't set assoc_timer */ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); - memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); @@ -857,10 +806,11 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; - if (rtw_createbss_cmd(adapter) != _SUCCESS) - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd status FAIL\n")); - pmlmepriv->to_join = false; + + ret = rtw_createbss_cmd(adapter); + if (ret != _SUCCESS) + goto unlock; } } } else { @@ -875,8 +825,6 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); rtw_indicate_connect(adapter); } else { - DBG_871X("try_to_join, but select scanning queue fail, to_roam:%d\n", rtw_to_roam(adapter)); - if (rtw_to_roam(adapter) != 0) { if (rtw_dec_to_roam(adapter) == 0 || _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) @@ -905,8 +853,7 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) } } - /* DBG_871X("scan complete in %dms\n", jiffies_to_msecs(jiffies - pmlmepriv->scan_start_time)); */ - +unlock: spin_unlock_bh(&pmlmepriv->lock); rtw_os_xmit_schedule(adapter); @@ -930,7 +877,6 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv) struct __queue *scan_queue = &pmlmepriv->scanned_queue; struct list_head *plist, *phead, *ptemp; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n")); spin_lock_bh(&scan_queue->lock); spin_lock_bh(&free_queue->lock); @@ -967,8 +913,6 @@ static void find_network(struct adapter *adapter) pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); if (pwlan) pwlan->fixed = false; - else - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources : pwlan == NULL\n\n")); if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)) @@ -986,10 +930,6 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) struct dvobj_priv *psdpriv = adapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n")); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress =%pM ssid =%s\n", - MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid)); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) { struct sta_info *psta; @@ -1027,8 +967,6 @@ void rtw_indicate_connect(struct adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n")); - pmlmepriv->to_join = false; if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { @@ -1041,7 +979,6 @@ void rtw_indicate_connect(struct adapter *padapter) rtw_set_to_roam(padapter, 0); rtw_set_scan_deny(padapter, 3000); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state = 0x%08x\n", get_fwstate(pmlmepriv))); } /* @@ -1051,12 +988,8 @@ void rtw_indicate_disconnect(struct adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n")); - _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS); - /* DBG_871X("clear wps when %s\n", __func__); */ - if (rtw_to_roam(padapter) > 0) _clr_fwstate_(pmlmepriv, _FW_LINKED); @@ -1078,8 +1011,6 @@ void rtw_indicate_disconnect(struct adapter *padapter) inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) { - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); - rtw_os_indicate_scan_done(padapter, aborted); if (is_primary_adapter(padapter) && @@ -1105,15 +1036,12 @@ void rtw_scan_abort(struct adapter *adapter) if (adapter->bDriverStopped || adapter->bSurpriseRemoved) break; - DBG_871X(FUNC_NDEV_FMT"fw_state = _FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); msleep(20); } - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { - if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) - DBG_871X(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) rtw_indicate_scan_done(adapter, true); - } + pmlmeext->scan_abort = false; } @@ -1131,8 +1059,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str if (psta) { /* update ptarget_sta */ - DBG_871X("%s\n", __func__); - psta->aid = pnetwork->join_res; update_sta_info(padapter, psta); @@ -1184,10 +1110,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str preorder_ctrl = &psta->recvreorder_ctrl[i]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, - preorder_ctrl->indicate_seq); - #endif preorder_ctrl->wend_b = 0xffff; preorder_ctrl->wsize_b = 64;/* max_ampdu_sz;ex. 32(kbytes) -> wsize_b =32 */ } @@ -1199,10 +1121,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, - preorder_ctrl->indicate_seq); - #endif preorder_ctrl->wend_b = 0xffff; preorder_ctrl->wsize_b = 64;/* max_ampdu_sz;ex. 32(kbytes) -> wsize_b =32 */ } @@ -1220,11 +1138,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct wlan_network *cur_network = &(pmlmepriv->cur_network); - DBG_871X("%s\n", __func__); - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:%pM\n" - , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); - /* why not use ptarget_wlan?? */ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ @@ -1239,15 +1152,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); - #if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 - DBG_871X(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" - "\n" - , FUNC_ADPT_ARG(padapter) - , padapter->recvpriv.signal_strength - , padapter->recvpriv.rssi - , padapter->recvpriv.signal_qual - ); - #endif rtw_set_signal_stat_timer(&padapter->recvpriv); @@ -1266,7 +1170,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net break; default: pmlmepriv->fw_state = WIFI_NULL_STATE; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n")); break; } @@ -1295,30 +1198,19 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; unsigned int the_same_macaddr = false; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res =%d\n", pnetwork->join_res)); - rtw_get_encrypt_decrypt_from_registrypriv(adapter); - if (pmlmepriv->assoc_ssid.SsidLength == 0) - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n")); - else - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); - the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network); - if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n")); + if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) return; - } spin_lock_bh(&pmlmepriv->lock); pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n rtw_joinbss_event_callback !! spin_lock_irqsave\n")); - if (pnetwork->join_res > 0) { spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); retry = 0; @@ -1355,7 +1247,8 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) if (ptarget_wlan) { rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork); } else { - DBG_871X_LEVEL(_drv_always_, "Can't find ptarget_wlan when joinbss_event callback\n"); + netdev_dbg(adapter->pnetdev, + "Can't find ptarget_wlan when joinbss_event callback\n"); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); goto ignore_joinbss_callback; } @@ -1364,7 +1257,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); if (!ptarget_sta) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n")); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); goto ignore_joinbss_callback; } @@ -1374,18 +1266,12 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { pmlmepriv->cur_network_scanned = ptarget_wlan; rtw_indicate_connect(adapter); - } else { - /* adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback */ - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); } /* s5. Cancel assoc_timer */ del_timer_sync(&pmlmepriv->assoc_timer); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("Cancel assoc_timer\n")); - } else { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv))); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); goto ignore_joinbss_callback; } @@ -1398,19 +1284,15 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) /* rtw_free_assoc_resources(adapter, 1); */ - if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("fail! clear _FW_UNDER_LINKING ^^^fw_state =%x\n", get_fwstate(pmlmepriv))); + if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); - } } else {/* if join_res < 0 (join fails), then try again */ #ifdef REJOIN res = _FAIL; - if (retry < 2) { + if (retry < 2) res = rtw_select_and_join_from_scanned_queue(pmlmepriv); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_select_and_join_from_scanned_queue again! res:%d\n", res)); - } if (res == _SUCCESS) { /* extend time of assoc_timer */ @@ -1420,7 +1302,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); rtw_indicate_connect(adapter); } else { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Set Assoc_Timer = 1; can't find match ssid in scanned_q\n")); #endif _set_timer(&pmlmepriv->assoc_timer, 1); @@ -1478,12 +1359,9 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) rtw_sta_media_status_rpt(adapter, psta, 1); -#ifndef CONFIG_AUTO_AP_MODE - ap_sta_info_defer_update(adapter, psta); /* report to upper layer */ - DBG_871X("indicate_sta_assoc_event to upper layer - hostapd\n"); spin_lock_bh(&psta->lock); if (psta->passoc_req && psta->assoc_req_len > 0) { passoc_req = rtw_zmalloc(psta->assoc_req_len); @@ -1503,7 +1381,6 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) kfree(passoc_req); } -#endif /* CONFIG_AUTO_AP_MODE */ } return; } @@ -1513,22 +1390,18 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) if (psta) { /* the sta have been in sta_info_queue => do nothing */ - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n")); - return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */ } psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); - if (!psta) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n")); + if (!psta) return; - } /* to do : init sta_info variable */ psta->qos_option = 0; psta->mac_id = (uint)pstassoc->cam_id; /* psta->aid = (uint)pstassoc->cam_id; */ - DBG_871X("%s\n", __func__); + /* for ad-hoc mode */ rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true); @@ -1579,8 +1452,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) else mac_id = pstadel->mac_id; - DBG_871X("%s(mac_id =%d) =%pM\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); - if (mac_id >= 0) { u16 media_status; @@ -1643,6 +1514,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) rtw_free_stainfo(adapter, psta); if (adapter->stapriv.asoc_sta_count == 1) {/* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + u8 ret = _SUCCESS; /* rtw_indicate_disconnect(adapter);removed@20091105 */ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); /* free old ibss network */ @@ -1670,12 +1542,14 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); } - if (rtw_createbss_cmd(adapter) != _SUCCESS) - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>stadel_event_callback: rtw_createbss_cmd status FAIL***\n ")); + ret = rtw_createbss_cmd(adapter); + if (ret != _SUCCESS) + goto unlock; } } +unlock: spin_unlock_bh(&pmlmepriv->lock); } @@ -1683,7 +1557,6 @@ void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf) { struct reportpwrstate_parm *preportpwrstate; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_cpwm_event_callback !!!\n")); preportpwrstate = (struct reportpwrstate_parm *)pbuf; preportpwrstate->state |= (u8)(adapter_to_pwrctl(padapter)->cpwm_tog + 0x80); cpwm_int_hdl(padapter, preportpwrstate); @@ -1704,8 +1577,6 @@ void _rtw_join_timeout_handler(struct timer_list *t) mlmepriv.assoc_timer); struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - DBG_871X("%s, fw_state =%x\n", __func__, get_fwstate(pmlmepriv)); - if (adapter->bDriverStopped || adapter->bSurpriseRemoved) return; @@ -1717,15 +1588,12 @@ void _rtw_join_timeout_handler(struct timer_list *t) if (rtw_to_roam(adapter) != 0) { /* try another */ int do_join_r; - DBG_871X("%s try another roaming\n", __func__); do_join_r = rtw_do_join(adapter); if (_SUCCESS != do_join_r) { - DBG_871X("%s roaming do_join return %d\n", __func__, do_join_r); continue; } break; } else { - DBG_871X("%s We've try roaming but fail\n", __func__); rtw_indicate_disconnect(adapter); break; } @@ -1753,8 +1621,6 @@ void rtw_scan_timeout_handler(struct timer_list *t) mlmepriv.scan_to_timer); struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - DBG_871X(FUNC_ADPT_FMT" fw_state =%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); - spin_lock_bh(&pmlmepriv->lock); _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); @@ -1791,19 +1657,13 @@ static void rtw_auto_scan_handler(struct adapter *padapter) && jiffies_to_msecs(jiffies - pmlmepriv->scan_start_time) > pmlmepriv->auto_scan_int_ms) { if (!padapter->registrypriv.wifi_spec) { - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) { - DBG_871X(FUNC_ADPT_FMT" _FW_UNDER_SURVEY|_FW_UNDER_LINKING\n", FUNC_ADPT_ARG(padapter)); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) == true) goto exit; - } - if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { - DBG_871X(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter)); + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) goto exit; - } } - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); - rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); } @@ -1825,10 +1685,7 @@ void rtw_dynamic_check_timer_handler(struct adapter *adapter) if (adapter->net_closed) return; - if (is_primary_adapter(adapter)) - DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", hal_btcoex_IsBtDisabled(adapter), hal_btcoex_IsBtControlLps(adapter)); - - if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + if ((adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) && !(hal_btcoex_IsBtControlLps(adapter)) ) { u8 bEnterPS; @@ -1864,15 +1721,12 @@ inline void rtw_clear_scan_deny(struct adapter *adapter) struct mlme_priv *mlmepriv = &adapter->mlmepriv; atomic_set(&mlmepriv->set_scan_deny, 0); - - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); } void rtw_set_scan_deny(struct adapter *adapter, u32 ms) { struct mlme_priv *mlmepriv = &adapter->mlmepriv; - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); atomic_set(&mlmepriv->set_scan_deny, 1); _set_timer(&mlmepriv->set_scan_deny_timer, ms); } @@ -1894,15 +1748,6 @@ static int rtw_check_roaming_candidate(struct mlme_priv *mlme if (rtw_is_desired_network(adapter, competitor) == false) goto exit; - DBG_871X("roam candidate:%s %s(%pM, ch%3u) rssi:%d, age:%5d\n", - (competitor == mlme->cur_network_scanned)?"*":" ", - competitor->network.Ssid.Ssid, - MAC_ARG(competitor->network.MacAddress), - competitor->network.Configuration.DSConfig, - (int)competitor->network.Rssi, - jiffies_to_msecs(jiffies - competitor->last_scanned) - ); - /* got specific addr to roam */ if (!is_zero_mac_addr(mlme->roam_tgt_addr)) { if (!memcmp(mlme->roam_tgt_addr, competitor->network.MacAddress, ETH_ALEN)) @@ -1949,32 +1794,20 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) pnetwork = container_of(mlme->pscanned, struct wlan_network, list); if (!pnetwork) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork == NULL)\n", __func__)); ret = _FAIL; goto exit; } mlme->pscanned = get_next(mlme->pscanned); - DBG_871X("%s(%pM, ch%u) rssi:%d\n" - , pnetwork->network.Ssid.Ssid - , MAC_ARG(pnetwork->network.MacAddress) - , pnetwork->network.Configuration.DSConfig - , (int)pnetwork->network.Rssi); - rtw_check_roaming_candidate(mlme, &candidate, pnetwork); } if (!candidate) { - DBG_871X("%s: return _FAIL(candidate == NULL)\n", __func__); ret = _FAIL; goto exit; } else { - DBG_871X("%s: candidate: %s(%pM, ch:%u)\n", __func__, - candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), - candidate->network.Configuration.DSConfig); - mlme->roam_network = candidate; if (!memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN)) @@ -2028,20 +1861,6 @@ static int rtw_check_join_candidate(struct mlme_priv *mlme updated = true; } - if (updated) { - DBG_871X("[by_bssid:%u][assoc_ssid:%s]" - "[to_roam:%u] " - "new candidate: %s(%pM, ch%u) rssi:%d\n", - mlme->assoc_by_bssid, - mlme->assoc_ssid.Ssid, - rtw_to_roam(adapter), - (*candidate)->network.Ssid.Ssid, - MAC_ARG((*candidate)->network.MacAddress), - (*candidate)->network.Configuration.DSConfig, - (int)(*candidate)->network.Rssi - ); - } - exit: return updated; } @@ -2079,34 +1898,20 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); if (!pnetwork) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork == NULL)\n", __func__)); ret = _FAIL; goto exit; } pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); - DBG_871X("%s(%pM, ch%u) rssi:%d\n" - , pnetwork->network.Ssid.Ssid - , MAC_ARG(pnetwork->network.MacAddress) - , pnetwork->network.Configuration.DSConfig - , (int)pnetwork->network.Rssi); - rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); } if (!candidate) { - DBG_871X("%s: return _FAIL(candidate == NULL)\n", __func__); -#ifdef CONFIG_WOWLAN - _clr_fwstate_(pmlmepriv, _FW_LINKED|_FW_UNDER_LINKING); -#endif ret = _FAIL; goto exit; } else { - DBG_871X("%s: candidate: %s(%pM, ch:%u)\n", __func__, - candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), - candidate->network.Configuration.DSConfig); goto candidate_exist; } @@ -2114,8 +1919,6 @@ candidate_exist: /* check for situation of _FW_LINKED */ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { - DBG_871X("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__); - rtw_disassoc_cmd(adapter, 0, true); rtw_indicate_disconnect(adapter); rtw_free_assoc_resources(adapter, 0); @@ -2129,12 +1932,12 @@ exit: return ret; } -sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) +signed int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) { struct cmd_obj *pcmd; struct setauth_parm *psetauthparm; struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); - sint res = _SUCCESS; + signed int res = _SUCCESS; pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); if (!pcmd) { @@ -2159,21 +1962,19 @@ sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) INIT_LIST_HEAD(&pcmd->list); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("after enqueue set_auth_cmd, auth_mode =%x\n", psecuritypriv->dot11AuthAlgrthm)); - res = rtw_enqueue_cmd(pcmdpriv, pcmd); exit: return res; } -sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue) +signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, signed int keyid, u8 set_tx, bool enqueue) { u8 keylen; struct cmd_obj *pcmd; struct setkey_parm *psetkeyparm; struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); - sint res = _SUCCESS; + signed int res = _SUCCESS; psetkeyparm = rtw_zmalloc(sizeof(struct setkey_parm)); if (!psetkeyparm) { @@ -2181,22 +1982,16 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s goto exit; } - if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key: psetkeyparm->algorithm =(unsigned char)psecuritypriv->dot118021XGrpPrivacy =%d\n", psetkeyparm->algorithm)); - } else { + else psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key: psetkeyparm->algorithm =(u8)psecuritypriv->dot11PrivacyAlgrthm =%d\n", psetkeyparm->algorithm)); - } psetkeyparm->keyid = (u8)keyid;/* 0~3 */ psetkeyparm->set_tx = set_tx; if (is_wep_enc(psetkeyparm->algorithm)) adapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); - DBG_871X("==> rtw_set_key algorithm(%x), keyid(%x), key_mask(%x)\n", psetkeyparm->algorithm, psetkeyparm->keyid, adapter->securitypriv.key_mask); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key: psetkeyparm->algorithm =%d psetkeyparm->keyid =(u8)keyid =%d\n", psetkeyparm->algorithm, keyid)); - switch (psetkeyparm->algorithm) { case _WEP40_: @@ -2218,7 +2013,6 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s psetkeyparm->grpkey = 1; break; default: - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm = %x (must be 1 or 2 or 4 or 5)\n", psecuritypriv->dot11PrivacyAlgrthm)); res = _FAIL; kfree(psetkeyparm); goto exit; @@ -2342,7 +2136,7 @@ static int rtw_append_pmkid(struct adapter *Adapter, int iEntry, u8 *ie, uint ie return ie_len; } -sint rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) +signed int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) { u8 authmode = 0x0; uint ielength; @@ -2352,9 +2146,6 @@ sint rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in struct security_priv *psecuritypriv = &adapter->securitypriv; uint ndisauthmode = psecuritypriv->ndisauthtype; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("+rtw_restruct_sec_ie: ndisauthmode =%d\n", ndisauthmode)); - /* copy fixed ie only */ memcpy(out_ie, in_ie, 12); ielength = 12; @@ -2451,7 +2242,6 @@ void rtw_update_registrypriv_dev_network(struct adapter *adapter) } pdev_network->Configuration.DSConfig = (pregistrypriv->channel); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("pregistrypriv->channel =%d, pdev_network->Configuration.DSConfig = 0x%x\n", pregistrypriv->channel, pdev_network->Configuration.DSConfig)); if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) pdev_network->Configuration.ATIMWindow = (0); @@ -2534,8 +2324,6 @@ void rtw_ht_use_default_setting(struct adapter *padapter) if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT5)) SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX); } - if (phtpriv->ldpc_cap) - DBG_871X("[HT] Support LDPC = 0x%02X\n", phtpriv->ldpc_cap); /* STBC */ rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport); @@ -2549,21 +2337,16 @@ void rtw_ht_use_default_setting(struct adapter *padapter) if (TEST_FLAG(pregistrypriv->stbc_cap, BIT4)) SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX); } - if (phtpriv->stbc_cap) - DBG_871X("[HT] Support STBC = 0x%02X\n", phtpriv->stbc_cap); /* Beamforming setting */ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&bHwSupportBeamformer); rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&bHwSupportBeamformee); CLEAR_FLAGS(phtpriv->beamform_cap); - if (TEST_FLAG(pregistrypriv->beamform_cap, BIT4) && bHwSupportBeamformer) { + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT4) && bHwSupportBeamformer) SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); - DBG_871X("[HT] Support Beamformer\n"); - } - if (TEST_FLAG(pregistrypriv->beamform_cap, BIT5) && bHwSupportBeamformee) { + + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT5) && bHwSupportBeamformee) SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); - DBG_871X("[HT] Support Beamformee\n"); - } } void rtw_build_wmm_ie_ht(struct adapter *padapter, u8 *out_ie, uint *pout_len) @@ -2659,10 +2442,8 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) { if ((channel <= 14 && pregistrypriv->rx_stbc == 0x1) || /* enable for 2.4GHz */ - (pregistrypriv->wifi_spec == 1)) { + (pregistrypriv->wifi_spec == 1)) stbc_rx_enable = 1; - DBG_871X("declare supporting RX STBC\n"); - } } /* fill default supported_mcs_set */ @@ -2685,14 +2466,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ if (stbc_rx_enable) ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_RX_STBC_2R);/* RX STBC two spatial stream */ - #ifdef CONFIG_DISABLE_MCS13TO15 - if (((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) && (pregistrypriv->wifi_spec != 1)) - set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R_13TO15_OFF); - else - set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R); - #else /* CONFIG_DISABLE_MCS13TO15 */ - set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R); - #endif /* CONFIG_DISABLE_MCS13TO15 */ + set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R); break; } @@ -2759,8 +2533,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) return; - DBG_871X("+rtw_update_ht_cap()\n"); - /* maybe needs check if ap supports rx ampdu. */ if (!(phtpriv->ampdu_enable) && pregistrypriv->ampdu_enable == 1) { phtpriv->ampdu_enable = true; @@ -2774,7 +2546,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR); max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ - /* DBG_871X("rtw_update_ht_cap(): max_ampdu_sz =%d\n", max_ampdu_sz); */ phtpriv->rx_ampdu_maxlen = max_ampdu_sz; } @@ -2815,14 +2586,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe break; case RF_2T2R: default: -#ifdef CONFIG_DISABLE_MCS13TO15 - if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1) - set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF); - else - set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); -#else /* CONFIG_DISABLE_MCS13TO15 */ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); -#endif /* CONFIG_DISABLE_MCS13TO15 */ } /* switch to the 40M Hz mode according to the AP */ @@ -2848,8 +2612,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2; - if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) - DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); /* */ /* Config current HT Protection mode. */ @@ -2873,20 +2635,14 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr priority = pattrib->priority; psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); - if (pattrib->psta != psta) { - DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + if (pattrib->psta != psta) return; - } - if (!psta) { - DBG_871X("%s, psta ==NUL\n", __func__); + if (!psta) return; - } - if (!(psta->state & _FW_LINKED)) { - DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + if (!(psta->state & _FW_LINKED)) return; - } phtpriv = &psta->htpriv; @@ -2895,7 +2651,6 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; if (0 == issued) { - DBG_871X("rtw_issue_addbareq_cmd, p =%d\n", priority); psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra); } @@ -2948,9 +2703,6 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) int do_join_r; if (0 < rtw_to_roam(padapter)) { - DBG_871X("roaming from %s(%pM), length:%d\n", - cur_network->network.Ssid.Ssid, MAC_ARG(cur_network->network.MacAddress), - cur_network->network.Ssid.SsidLength); memcpy(&pmlmepriv->assoc_ssid, &cur_network->network.Ssid, sizeof(struct ndis_802_11_ssid)); pmlmepriv->assoc_by_bssid = false; @@ -2960,13 +2712,11 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) if (_SUCCESS == do_join_r) { break; } else { - DBG_871X("roaming do_join return %d\n", do_join_r); rtw_dec_to_roam(padapter); if (rtw_to_roam(padapter) > 0) { continue; } else { - DBG_871X("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__); rtw_indicate_disconnect(padapter); break; } @@ -2976,7 +2726,7 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) } -sint rtw_linked_check(struct adapter *padapter) +signed int rtw_linked_check(struct adapter *padapter) { if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) || (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true)) { diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index fa4b0259c5ae18fda0846c3dfe1f5933bb498e55..9031cf7657ae91c300f13d6e99623441dbe87e3a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -71,7 +71,7 @@ static unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; /******************************************************** ChannelPlan definitions *********************************************************/ -static RT_CHANNEL_PLAN_2G RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { +static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */ @@ -81,7 +81,7 @@ static RT_CHANNEL_PLAN_2G RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { {{}, 0}, /* 0x06, RT_CHANNEL_DOMAIN_2G_NULL */ }; -static RT_CHANNEL_PLAN_5G RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = { +static struct rt_channel_plan_5g RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = { {{}, 0}, /* 0x00, RT_CHANNEL_DOMAIN_5G_NULL */ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 */ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 */ @@ -121,7 +121,7 @@ static RT_CHANNEL_PLAN_5G RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = { {{36, 40, 44, 48, 149, 153, 157, 161}, 8}, /* 0x22, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS */ }; -static RT_CHANNEL_PLAN_MAP RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { +static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { /* 0x00 ~ 0x1F , Old Define ===== */ {0x02, 0x20}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */ {0x02, 0x0A}, /* 0x01, RT_CHANNEL_DOMAIN_IC */ @@ -209,7 +209,7 @@ static RT_CHANNEL_PLAN_MAP RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { }; /* use the combination for max channel numbers */ -static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02}; +static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02}; /* Search the @param ch in given @param ch_set * @ch_set: the given channel set @@ -217,7 +217,7 @@ static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02}; * * return the index of channel_num in channel_set, -1 if not found */ -int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch) +int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch) { int i; @@ -325,7 +325,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) pmlmeext->action_public_dialog_token = 0xff; } -static int has_channel(RT_CHANNEL_INFO *channel_set, +static int has_channel(struct rt_channel_info *channel_set, u8 chanset_size, u8 chan) { @@ -340,7 +340,7 @@ static int has_channel(RT_CHANNEL_INFO *channel_set, return 0; } -static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel_set, +static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, u8 chanset_size, struct p2p_channels *channel_list) { @@ -392,18 +392,16 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel } -static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, RT_CHANNEL_INFO *channel_set) +static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set) { u8 index, chanset_size = 0; u8 b5GBand = false, b2_4GBand = false; u8 Index2G = 0, Index5G = 0; - memset(channel_set, 0, sizeof(RT_CHANNEL_INFO)*MAX_CHANNEL_NUM); + memset(channel_set, 0, sizeof(struct rt_channel_info)*MAX_CHANNEL_NUM); - if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { - DBG_871X("ChannelPlan ID %x error !!!!!\n", ChannelPlan); + if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) return chanset_size; - } if (IsSupported24G(padapter->registrypriv.wireless_mode)) { b2_4GBand = true; @@ -446,13 +444,11 @@ static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, RT_CHANNEL_ channel_set[chanset_size].ScanType = SCAN_PASSIVE; else channel_set[chanset_size].ScanType = SCAN_ACTIVE; - DBG_871X("%s(): channel_set[%d].ChannelNum = %d\n", __func__, chanset_size, channel_set[chanset_size].ChannelNum); chanset_size++; } } } - DBG_871X("%s ChannelPlan ID %x Chan num:%d \n", __func__, ChannelPlan, chanset_size); return chanset_size; } @@ -526,14 +522,8 @@ void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame) struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", - GetFrameType(pframe), GetFrameSubType(pframe))); - - if (GetFrameType(pframe) != WIFI_MGT_TYPE) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe))); + if (GetFrameType(pframe) != WIFI_MGT_TYPE) return; - } /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && @@ -545,10 +535,9 @@ void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame) index = GetFrameSubType(pframe) >> 4; - if (index >= ARRAY_SIZE(mlme_sta_tbl)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type =%d\n", index)); + if (index >= ARRAY_SIZE(mlme_sta_tbl)) return; - } + ptable += index; if (psta) { @@ -556,7 +545,6 @@ void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame) if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) { /* drop the duplicate management frame */ pdbgpriv->dbg_rx_dup_mgt_frame_drop_count++; - DBG_871X("Drop duplicate management frame with seq_num = %d.\n", precv_frame->u.hdr.attrib.seq_num); return; } } @@ -616,118 +604,6 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame) return _SUCCESS; } - - /* DBG_871X("+OnProbeReq\n"); */ - -#ifdef CONFIG_AUTO_AP_MODE - if (check_fwstate(pmlmepriv, _FW_LINKED) && - pmlmepriv->cur_network.join_res) { - struct sta_info *psta; - u8 *mac_addr, *peer_addr; - struct sta_priv *pstapriv = &padapter->stapriv; - u8 RC_OUI[4] = {0x00, 0xE0, 0x4C, 0x0A}; - /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ - - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, WLAN_EID_VENDOR_SPECIFIC, (int *)&ielen, - len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); - - if (!p || ielen != 14) - goto _non_rc_device; - - if (memcmp(p+2, RC_OUI, sizeof(RC_OUI))) - goto _non_rc_device; - - if (memcmp(p+6, get_sa(pframe), ETH_ALEN)) { - DBG_871X("%s, do rc pairing (%pM), but mac addr mismatch!(%pM)\n", __func__, - MAC_ARG(get_sa(pframe)), MAC_ARG(p+6)); - - goto _non_rc_device; - } - - DBG_871X("%s, got the pairing device(%pM)\n", __func__, MAC_ARG(get_sa(pframe))); - - /* new a station */ - psta = rtw_get_stainfo(pstapriv, get_sa(pframe)); - if (psta == NULL) { - /* allocate a new one */ - DBG_871X("going to alloc stainfo for rc =%pM\n", MAC_ARG(get_sa(pframe))); - psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe)); - if (!psta) { - /* TODO: */ - DBG_871X(" Exceed the upper limit of supported clients...\n"); - return _SUCCESS; - } - - spin_lock_bh(&pstapriv->asoc_list_lock); - if (list_empty(&psta->asoc_list)) { - psta->expire_to = pstapriv->expire_to; - list_add_tail(&psta->asoc_list, &pstapriv->asoc_list); - pstapriv->asoc_list_cnt++; - } - spin_unlock_bh(&pstapriv->asoc_list_lock); - - /* generate pairing ID */ - mac_addr = myid(&(padapter->eeprompriv)); - peer_addr = psta->hwaddr; - psta->pid = (u16)(((mac_addr[4]<<8) + mac_addr[5]) + ((peer_addr[4]<<8) + peer_addr[5])); - - /* update peer stainfo */ - psta->isrc = true; - /* psta->aid = 0; */ - /* psta->mac_id = 2; */ - - /* get a unique AID */ - if (psta->aid > 0) { - DBG_871X("old AID %d\n", psta->aid); - } else { - for (psta->aid = 1; psta->aid <= NUM_STA; psta->aid++) - if (pstapriv->sta_aid[psta->aid - 1] == NULL) - break; - - if (psta->aid > pstapriv->max_num_sta) { - psta->aid = 0; - DBG_871X("no room for more AIDs\n"); - return _SUCCESS; - } - pstapriv->sta_aid[psta->aid - 1] = psta; - DBG_871X("allocate new AID = (%d)\n", psta->aid); - } - - psta->qos_option = 1; - psta->bw_mode = CHANNEL_WIDTH_20; - psta->ieee8021x_blocked = false; - psta->htpriv.ht_option = true; - psta->htpriv.ampdu_enable = false; - psta->htpriv.sgi_20m = false; - psta->htpriv.sgi_40m = false; - psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; - psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ - psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ - - rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); - - memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); - - spin_lock_bh(&psta->lock); - psta->state |= _FW_LINKED; - spin_unlock_bh(&psta->lock); - - report_add_sta_event(padapter, psta->hwaddr, psta->aid); - - } - - issue_probersp(padapter, get_sa(pframe), false); - - return _SUCCESS; - - } - -_non_rc_device: - - return _SUCCESS; - -#endif /* CONFIG_AUTO_AP_MODE */ - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, WLAN_EID_SSID, (int *)&ielen, len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); @@ -743,12 +619,10 @@ _non_rc_device: return _SUCCESS; _issue_probersp: - if ((check_fwstate(pmlmepriv, _FW_LINKED) && - pmlmepriv->cur_network.join_res) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { - /* DBG_871X("+issue_probersp during ap mode\n"); */ + if ((check_fwstate(pmlmepriv, _FW_LINKED) && + pmlmepriv->cur_network.join_res) || + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); - } - } return _SUCCESS; @@ -785,11 +659,9 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) p = rtw_get_ie(pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, WLAN_EID_EXT_SUPP_RATES, &ielen, precv_frame->u.hdr.len - sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_); if (p && ielen > 0) { - if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) { + if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ - DBG_871X("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:%pM. Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe))); *(p + 1) = ielen - 1; - } } if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { @@ -834,14 +706,15 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) if (psta) { ret = rtw_check_bcn_info(padapter, pframe, len); if (!ret) { - DBG_871X_LEVEL(_drv_always_, "ap has changed, disconnect now\n "); - receive_disconnect(padapter, pmlmeinfo->network.MacAddress, 0); - return _SUCCESS; + netdev_dbg(padapter->pnetdev, + "ap has changed, disconnect now\n "); + receive_disconnect(padapter, + pmlmeinfo->network.MacAddress, 0); + return _SUCCESS; } /* update WMM, ERP in the beacon */ /* todo: the timer is used instead of the number of the beacon received */ if ((sta_rx_pkts(psta) & 0xf) == 0) - /* DBG_871X("update_bcn_info\n"); */ update_beacon_info(padapter, pframe, len, psta); adaptive_early_32k(pmlmeext, pframe, len); @@ -852,7 +725,6 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) /* update WMM, ERP in the beacon */ /* todo: the timer is used instead of the number of the beacon received */ if ((sta_rx_pkts(psta) & 0xf) == 0) { - /* DBG_871X("update_bcn_info\n"); */ update_beacon_info(padapter, pframe, len, psta); } } else { @@ -901,8 +773,6 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) return _FAIL; - DBG_871X("+OnAuth\n"); - sa = GetAddr2Ptr(pframe); auth_mode = psecuritypriv->dot11AuthAlgrthm; @@ -928,8 +798,6 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) algorithm = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); seq = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); - DBG_871X("auth alg =%x, seq =%X\n", algorithm, seq); - if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) @@ -937,8 +805,6 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ - DBG_871X("auth rejected due to bad alg [alg =%d, auth_mib =%d] %02X%02X%02X%02X%02X%02X\n", - algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); status = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; @@ -954,10 +820,8 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) if (pstat == NULL) { /* allocate a new one */ - DBG_871X("going to alloc stainfo for sa =%pM\n", MAC_ARG(sa)); pstat = rtw_alloc_stainfo(pstapriv, sa); if (pstat == NULL) { - DBG_871X(" Exceed the upper limit of supported clients...\n"); status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto auth_fail; } @@ -997,8 +861,6 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) if ((pstat->auth_seq + 1) != seq) { - DBG_871X("(1)auth rejected because out of seq [rx_seq =%d, exp_seq =%d]!\n", - seq, pstat->auth_seq+1); status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; goto auth_fail; } @@ -1010,8 +872,6 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) pstat->expire_to = pstapriv->assoc_to; pstat->authalg = algorithm; } else { - DBG_871X("(2)auth rejected because out of seq [rx_seq =%d, exp_seq =%d]!\n", - seq, pstat->auth_seq+1); status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; goto auth_fail; } @@ -1025,14 +885,11 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) pstat->authalg = algorithm; pstat->auth_seq = 2; } else if (seq == 3) { - /* checking for challenging txt... */ - DBG_871X("checking for challenging txt...\n"); p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_, WLAN_EID_CHALLENGE, (int *)&ie_len, len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); if ((p == NULL) || (ie_len <= 0)) { - DBG_871X("auth rejected because challenge failure!(1)\n"); status = WLAN_STATUS_CHALLENGE_FAIL; goto auth_fail; } @@ -1043,13 +900,10 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) /* challenging txt is correct... */ pstat->expire_to = pstapriv->assoc_to; } else { - DBG_871X("auth rejected because challenge failure!\n"); status = WLAN_STATUS_CHALLENGE_FAIL; goto auth_fail; } } else { - DBG_871X("(3)auth rejected because out of seq [rx_seq =%d, exp_seq =%d]!\n", - seq, pstat->auth_seq+1); status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; goto auth_fail; } @@ -1093,8 +947,6 @@ unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_fram u8 *pframe = precv_frame->u.hdr.rx_data; uint pkt_len = precv_frame->u.hdr.len; - DBG_871X("%s\n", __func__); - /* check A1 matches or not */ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) return _SUCCESS; @@ -1108,7 +960,6 @@ unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_fram status = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4)); if (status != 0) { - DBG_871X("clnt auth fail, status: %d\n", status); if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; @@ -1127,10 +978,8 @@ unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_fram p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, WLAN_EID_CHALLENGE, (int *)&len, pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); - if (p == NULL) { - /* DBG_871X("marc: no challenge text?\n"); */ + if (!p) goto authclnt_fail; - } memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); pmlmeinfo->auth_seq = 3; @@ -1150,12 +999,11 @@ unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_fram } } else { /* this is also illegal */ - /* DBG_871X("marc: clnt auth failed due to illegal seq =%x\n", seq); */ goto authclnt_fail; } if (go2asoc) { - DBG_871X_LEVEL(_drv_always_, "auth success, start assoc\n"); + netdev_dbg(padapter->pnetdev, "auth success, start assoc\n"); start_clnt_assoc(padapter); return _SUCCESS; } @@ -1202,11 +1050,8 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) } - if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) { - DBG_871X("handle_assoc(reassoc =%d) - too short payload (len =%lu)" - "\n", reassoc, (unsigned long)pkt_len); + if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) return _FAIL; - } pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); if (!pstat) { @@ -1220,9 +1065,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset); pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset); - - DBG_871X("%s\n", __func__); - /* check if this stat has been successfully authenticated/assocated */ if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { @@ -1243,8 +1085,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) /* now parse all ieee802_11 ie to point to elems */ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || !elems.ssid) { - DBG_871X("STA %pM sent invalid association request\n", - MAC_ARG(pstat->hwaddr)); status = WLAN_STATUS_CHALLENGE_FAIL; goto OnAssocReqFail; } @@ -1273,7 +1113,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) /* check if the supported rate is ok */ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, WLAN_EID_SUPP_RATES, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); if (p == NULL) { - DBG_871X("Rx a sta assoc-req which supported rate is empty!\n"); /* use our own rate set as statoin used */ /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ /* supportRateNum = AP_BSSRATE_LEN; */ @@ -1369,17 +1208,11 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); if (!wpa_ie) { if (elems.wps_ie) { - DBG_871X("STA included WPS IE in " - "(Re)Association Request - assume WPS is " - "used\n"); pstat->flags |= WLAN_STA_WPS; /* wpabuf_free(sta->wps_ie); */ /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ /* elems.wps_ie_len - 4); */ } else { - DBG_871X("STA did not include WPA/RSN IE " - "in (Re)Association Request - possible WPS " - "use\n"); pstat->flags |= WLAN_STA_MAYBE_WPS; } @@ -1394,8 +1227,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL); if (!selected_registrar) { - DBG_871X("selected_registrar is false , or AP is not ready to do WPS\n"); - status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto OnAssocReqFail; @@ -1407,9 +1238,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) int copy_len; if (psecuritypriv->wpa_psk == 0) { - DBG_871X("STA %pM: WPA/RSN IE in association " - "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); - status = WLAN_STATUS_INVALID_IE; goto OnAssocReqFail; @@ -1417,9 +1245,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) } if (elems.wps_ie) { - DBG_871X("STA included WPS IE in " - "(Re)Association Request - WPS is " - "used\n"); pstat->flags |= WLAN_STA_WPS; copy_len = 0; } else { @@ -1515,8 +1340,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) if ((pstat->flags & WLAN_STA_HT) && ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) { - DBG_871X("HT: %pM tried to use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); - /* status = WLAN_STATUS_CIPHER_SUITE_REJECTED; */ /* goto OnAssocReqFail; */ } @@ -1547,9 +1370,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) /* get a unique AID */ - if (pstat->aid > 0) { - DBG_871X(" old AID %d\n", pstat->aid); - } else { + if (pstat->aid == 0) { for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) if (pstapriv->sta_aid[pstat->aid - 1] == NULL) break; @@ -1559,8 +1380,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) pstat->aid = 0; - DBG_871X(" no room for more AIDs\n"); - status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto OnAssocReqFail; @@ -1568,7 +1387,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) } else { pstapriv->sta_aid[pstat->aid - 1] = pstat; - DBG_871X("allocate new AID = (%d)\n", pstat->aid); } } @@ -1653,8 +1471,6 @@ unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame) u8 *pframe = precv_frame->u.hdr.rx_data; uint pkt_len = precv_frame->u.hdr.len; - DBG_871X("%s\n", __func__); - /* check A1 matches or not */ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) return _SUCCESS; @@ -1670,7 +1486,6 @@ unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame) /* status */ status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2)); if (status > 0) { - DBG_871X("assoc reject, status code: %d\n", status); pmlmeinfo->state = WIFI_FW_NULL_STATE; res = -4; goto report_assoc_result; @@ -1748,8 +1563,6 @@ unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame) reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); - DBG_871X("%s Reason code(%d)\n", __func__, reason); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { struct sta_info *psta; struct sta_priv *pstapriv = &padapter->stapriv; @@ -1758,8 +1571,9 @@ unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame) /* rtw_free_stainfo(padapter, psta); */ /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */ - DBG_871X_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", - reason, GetAddr2Ptr(pframe)); + netdev_dbg(padapter->pnetdev, + "ap recv deauth reason code(%d) sta:%pM\n", reason, + GetAddr2Ptr(pframe)); psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); if (psta) { @@ -1797,8 +1611,10 @@ unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame) } } - DBG_871X_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n", - reason, GetAddr3Ptr(pframe), ignore_received_deauth); + netdev_dbg(padapter->pnetdev, + "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n", + reason, GetAddr3Ptr(pframe), + ignore_received_deauth); if (0 == ignore_received_deauth) { receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); @@ -1823,8 +1639,6 @@ unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame) reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); - DBG_871X("%s Reason code(%d)\n", __func__, reason); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { struct sta_info *psta; struct sta_priv *pstapriv = &padapter->stapriv; @@ -1833,8 +1647,9 @@ unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame) /* rtw_free_stainfo(padapter, psta); */ /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */ - DBG_871X_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", - reason, GetAddr2Ptr(pframe)); + netdev_dbg(padapter->pnetdev, + "ap recv disassoc reason code(%d) sta:%pM\n", + reason, GetAddr2Ptr(pframe)); psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); if (psta) { @@ -1854,8 +1669,9 @@ unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame) return _SUCCESS; } else { - DBG_871X_LEVEL(_drv_always_, "sta recv disassoc reason code(%d) sta:%pM\n", - reason, GetAddr3Ptr(pframe)); + netdev_dbg(padapter->pnetdev, + "sta recv disassoc reason code(%d) sta:%pM\n", + reason, GetAddr3Ptr(pframe)); receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); } @@ -1866,7 +1682,6 @@ unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame) unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame) { - DBG_871X("%s\n", __func__); return _SUCCESS; } @@ -1879,8 +1694,6 @@ unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_fr u8 category; u8 action; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); - psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); if (!psta) @@ -1919,8 +1732,6 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra u8 *pframe = precv_frame->u.hdr.rx_data; struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("%s\n", __func__); - /* check RA matches or not */ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ return _SUCCESS; @@ -1943,7 +1754,6 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra return _SUCCESS; action = frame_body[1]; - DBG_871X("%s, action =%d\n", __func__, action); switch (action) { case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ @@ -1965,7 +1775,6 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra if (status == 0) { /* successful */ - DBG_871X("agg_enable for TID =%d\n", tid); psta->htpriv.agg_enable_bitmap |= BIT(tid); psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); } else { @@ -1973,13 +1782,11 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra } if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { - DBG_871X("%s alive check - rx ADDBA response\n", __func__); psta->htpriv.agg_enable_bitmap &= ~BIT(tid); psta->expire_to = pstapriv->expire_to; psta->state ^= WIFI_STA_ALIVE_CHK_STATE; } - /* DBG_871X("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); */ break; case WLAN_ACTION_DELBA: /* DELBA */ @@ -1997,13 +1804,7 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra preorder_ctrl = &psta->recvreorder_ctrl[tid]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, - preorder_ctrl->indicate_seq); - #endif } - - DBG_871X("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); /* todo: how to notify the host while receiving DELETE BA */ break; @@ -2025,17 +1826,11 @@ static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token) if (GetRetry(frame)) { if (token >= 0) { if ((seq_ctrl == mlmeext->action_public_rxseq) - && (token == mlmeext->action_public_dialog_token)) { - DBG_871X(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n", - FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); + && (token == mlmeext->action_public_dialog_token)) return _FAIL; - } } else { - if (seq_ctrl == mlmeext->action_public_rxseq) { - DBG_871X(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n", - FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); + if (seq_ctrl == mlmeext->action_public_rxseq) return _FAIL; - } } } @@ -2084,7 +1879,6 @@ static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 a u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); u8 token; struct adapter *adapter = precv_frame->u.hdr.adapter; - int cnt = 0; char msg[64]; token = frame_body[2]; @@ -2092,7 +1886,7 @@ static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 a if (rtw_action_public_decache(precv_frame, token) == _FAIL) goto exit; - cnt += sprintf((msg+cnt), "%s(token:%u)", action_public_str(action), token); + scnprintf(msg, sizeof(msg), "%s(token:%u)", action_public_str(action), token); rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg); ret = _SUCCESS; @@ -2163,20 +1957,15 @@ unsigned int OnAction_sa_query(struct adapter *padapter, union recv_frame *precv struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); unsigned short tid; - /* Baron */ - - DBG_871X("OnAction_sa_query\n"); switch (pframe[WLAN_HDR_A3_LEN+1]) { case 0: /* SA Query req */ memcpy(&tid, &pframe[WLAN_HDR_A3_LEN+2], sizeof(unsigned short)); - DBG_871X("OnAction_sa_query request, action =%d, tid =%04x\n", pframe[WLAN_HDR_A3_LEN+1], tid); issue_action_SA_Query(padapter, GetAddr2Ptr(pframe), 1, tid); break; case 1: /* SA Query rsp */ del_timer_sync(&pmlmeext->sa_query_timer); - DBG_871X("OnAction_sa_query response, action =%d, tid =%04x, cancel timer\n", pframe[WLAN_HDR_A3_LEN+1], pframe[WLAN_HDR_A3_LEN+2]); break; default: break; @@ -2219,8 +2008,6 @@ unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame) unsigned int DoReserved(struct adapter *padapter, union recv_frame *precv_frame) { - - /* DBG_871X("rcvd mgt frame(%x, %x)\n", (GetFrameSubType(pframe) >> 4), *(unsigned int *)GetAddr1Ptr(pframe)); */ return _SUCCESS; } @@ -2234,14 +2021,11 @@ static struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool else pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv); - if (pmgntframe == NULL) { - DBG_871X(FUNC_ADPT_FMT" alloc xmitframe fail, once:%d\n", FUNC_ADPT_ARG(pxmitpriv->adapter), once); + if (!pmgntframe) goto exit; - } pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); if (pxmitbuf == NULL) { - DBG_871X(FUNC_ADPT_FMT" alloc xmitbuf fail\n", FUNC_ADPT_ARG(pxmitpriv->adapter)); rtw_free_xmitframe(pxmitpriv, pmgntframe); pmgntframe = NULL; goto exit; @@ -2273,7 +2057,6 @@ void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); pmlmeext->tx_rate = rate; - /* DBG_871X("%s(): rate = %x\n", __func__, rate); */ } void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) @@ -2341,7 +2124,7 @@ void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) { s32 ret = _FAIL; - _irqL irqL; + unsigned long irqL; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; struct submit_ctx sctx; @@ -2399,13 +2182,11 @@ s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmg static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) { u8 *ssid_ie; - sint ssid_len_ori; + signed int ssid_len_ori; int len_diff = 0; ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); - /* DBG_871X("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __func__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */ - if (ssid_ie && ssid_len_ori > 0) { switch (hidden_ssid_mode) { case 1: @@ -2447,13 +2228,9 @@ void issue_beacon(struct adapter *padapter, int timeout_ms) struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - /* DBG_871X("%s\n", __func__); */ - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (!pmgntframe) { - DBG_871X("%s, alloc mgnt frame fail\n", __func__); + if (!pmgntframe) return; - } spin_lock_bh(&pmlmepriv->bcn_update_lock); @@ -2483,7 +2260,6 @@ void issue_beacon(struct adapter *padapter, int timeout_ms) pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { - /* DBG_871X("ie len =%d\n", cur_network->IELength); */ { int len_diff; @@ -2573,14 +2349,11 @@ _issue_bcn: spin_unlock_bh(&pmlmepriv->bcn_update_lock); - if ((pattrib->pktlen + TXDESC_SIZE) > 512) { - DBG_871X("beacon frame too large\n"); + if ((pattrib->pktlen + TXDESC_SIZE) > 512) return; - } pattrib->last_txcmdsz = pattrib->pktlen; - /* DBG_871X("issue bcn_sz =%d\n", pattrib->last_txcmdsz); */ if (timeout_ms > 0) dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); else @@ -2606,17 +2379,12 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); unsigned int rate_len; - /* DBG_871X("%s\n", __func__); */ - if (da == NULL) return; pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) { - DBG_871X("%s, alloc mgnt frame fail\n", __func__); + if (!pmgntframe) return; - } - /* update attribute */ pattrib = &pmgntframe->attrib; @@ -2687,8 +2455,8 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p /* retrieve SSID IE from cur_network->Ssid */ { u8 *ssid_ie; - sint ssid_ielen; - sint ssid_ielen_diff; + signed int ssid_ielen; + signed int ssid_ielen_diff; u8 buf[MAX_IE_SZ]; u8 *ies = pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr); @@ -2705,7 +2473,9 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p remainder_ielen = (pframe-remainder_ie); if (remainder_ielen > MAX_IE_SZ) { - DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); + netdev_warn(padapter->pnetdev, + FUNC_ADPT_FMT " remainder_ielen > MAX_IE_SZ\n", + FUNC_ADPT_ARG(padapter)); remainder_ielen = MAX_IE_SZ; } @@ -2772,36 +2542,6 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p } -#ifdef CONFIG_AUTO_AP_MODE -{ - struct sta_info *psta; - struct sta_priv *pstapriv = &padapter->stapriv; - - DBG_871X("(%s)\n", __func__); - - /* check rc station */ - psta = rtw_get_stainfo(pstapriv, da); - if (psta && psta->isrc && psta->pid > 0) { - u8 RC_OUI[4] = {0x00, 0xE0, 0x4C, 0x0A}; - u8 RC_INFO[14] = {0}; - /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ - u16 cu_ch = (u16)cur_network->Configuration.DSConfig; - - DBG_871X("%s, reply rc(pid = 0x%x) device %pM in ch =%d\n", __func__, - psta->pid, MAC_ARG(psta->hwaddr), cu_ch); - - /* append vendor specific ie */ - memcpy(RC_INFO, RC_OUI, sizeof(RC_OUI)); - memcpy(&RC_INFO[4], mac, ETH_ALEN); - memcpy(&RC_INFO[10], (u8 *)&psta->pid, 2); - memcpy(&RC_INFO[12], (u8 *)&cu_ch, 2); - - pframe = rtw_set_ie(pframe, WLAN_EID_VENDOR_SPECIFIC, sizeof(RC_INFO), RC_INFO, &pattrib->pktlen); - } -} -#endif /* CONFIG_AUTO_AP_MODE */ - - pattrib->last_txcmdsz = pattrib->pktlen; @@ -2829,8 +2569,6 @@ static int _issue_probereq(struct adapter *padapter, int bssrate_len = 0; u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n")); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (!pmgntframe) goto exit; @@ -2897,8 +2635,6 @@ static int _issue_probereq(struct adapter *padapter, pattrib->last_txcmdsz = pattrib->pktlen; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz)); - if (wait_ack) { ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); } else { @@ -2942,16 +2678,6 @@ int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, #endif } - if (try_cnt && wait_ms) { - if (da) - DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - else - DBG_871X(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - } exit: return ret; } @@ -3039,13 +2765,11 @@ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short use_shared_key = 1; } le_tmp = cpu_to_le16(val16); - /* DBG_871X("%s auth_algo = %s auth_seq =%d\n", __func__, (pmlmeinfo->auth_algo == 0)?"OPEN":"SHARED", pmlmeinfo->auth_seq); */ /* setting IV for auth seq #3 */ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { __le32 le_tmp32; - /* DBG_871X("==> iv(%d), key_index(%d)\n", pmlmeinfo->iv, pmlmeinfo->key_index); */ val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); le_tmp32 = cpu_to_le32(val32); pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen)); @@ -3085,7 +2809,6 @@ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short pattrib->last_txcmdsz = pattrib->pktlen; rtw_wep_encrypt(padapter, (u8 *)pmgntframe); - DBG_871X("%s\n", __func__); dump_mgntframe(padapter, pmgntframe); } @@ -3106,8 +2829,6 @@ void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_i u8 *ie = pnetwork->IEs; __le16 lestatus, le_tmp; - DBG_871X("%s\n", __func__); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) return; @@ -3286,20 +3007,17 @@ void issue_assocreq(struct adapter *padapter) /* Check if the AP's supported rates are also supported by STA. */ get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); - /* DBG_871X("sta_bssrate_len =%d\n", sta_bssrate_len); */ if (pmlmeext->cur_channel == 14) /* for JAPAN, channel 14 can only uses B Mode(CCK) */ sta_bssrate_len = 4; /* for (i = 0; i < sta_bssrate_len; i++) { */ - /* DBG_871X("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */ /* */ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { if (pmlmeinfo->network.SupportedRates[i] == 0) break; - DBG_871X("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); } @@ -3311,26 +3029,17 @@ void issue_assocreq(struct adapter *padapter) /* Check if the AP's supported rates are also supported by STA. */ for (j = 0; j < sta_bssrate_len; j++) { /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ - if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) - == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) { - /* DBG_871X("match i = %d, j =%d\n", i, j); */ + if ((pmlmeinfo->network.SupportedRates[i] | IEEE80211_BASIC_RATE_MASK) + == (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) break; - } else { - /* DBG_871X("not match: %02X != %02X\n", (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK), (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)); */ - } } - if (j == sta_bssrate_len) { - /* the rate is not supported by STA */ - DBG_871X("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]); - } else { + if (j != sta_bssrate_len) /* the rate is supported by STA */ bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; - } } bssrate_len = index; - DBG_871X("bssrate_len = %d\n", bssrate_len); if (bssrate_len == 0) { rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); @@ -3422,8 +3131,6 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, struct mlme_ext_priv *pmlmeext; struct mlme_ext_info *pmlmeinfo; - /* DBG_871X("%s:%d\n", __func__, power_mode); */ - if (!padapter) goto exit; @@ -3506,8 +3213,6 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow else rtw_hal_macid_wakeup(padapter, psta->mac_id); } else { - DBG_871X(FUNC_ADPT_FMT ": Can't find sta info for %pM, skip macid %s!!\n", - FUNC_ADPT_ARG(padapter), MAC_ARG(da), power_mode?"sleep":"wakeup"); rtw_warn_on(1); } @@ -3531,16 +3236,6 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow #endif } - if (try_cnt && wait_ms) { - if (da) - DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - else - DBG_871X(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - } exit: return ret; } @@ -3582,8 +3277,6 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - DBG_871X("%s\n", __func__); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) goto exit; @@ -3679,16 +3372,6 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int #endif } - if (try_cnt && wait_ms) { - if (da) - DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - else - DBG_871X(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - } exit: return ret; } @@ -3707,8 +3390,6 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da, int ret = _FAIL; __le16 le_tmp; - /* DBG_871X("%s to %pM\n", __func__, MAC_ARG(da)); */ - pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) { goto exit; @@ -3757,7 +3438,6 @@ exit: int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) { - DBG_871X("%s to %pM\n", __func__, MAC_ARG(da)); return _issue_deauth(padapter, da, reason, false); } @@ -3787,16 +3467,6 @@ int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int #endif } - if (try_cnt && wait_ms) { - if (da) - DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - else - DBG_871X(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); - } exit: return ret; } @@ -3814,13 +3484,9 @@ void issue_action_SA_Query(struct adapter *padapter, unsigned char *raddr, unsig struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); __le16 le_tmp; - DBG_871X("%s\n", __func__); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) { - DBG_871X("%s: alloc_mgtxmitframe fail\n", __func__); + if (!pmgntframe) return; - } /* update attribute */ pattrib = &pmgntframe->attrib; @@ -3894,8 +3560,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch struct registry_priv *pregpriv = &padapter->registrypriv; __le16 le_tmp; - DBG_871X("%s, category =%d, action =%d, status =%d\n", __func__, category, action, status); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (!pmgntframe) return; @@ -3959,8 +3623,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch if (psta) { start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; - DBG_871X("BA_starting_seqctrl = %d for TID =%d\n", start_seq, status & 0x07); - psta->BA_starting_seqctrl[status & 0x07] = start_seq; BA_starting_seqctrl = start_seq << 4; @@ -4051,10 +3713,6 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter) if (true == pmlmeinfo->bwmode_updated) return; - - DBG_871X("%s\n", __func__); - - category = RTW_WLAN_CATEGORY_PUBLIC; action = ACT_PUBLIC_BSSCOEXIST; @@ -4192,26 +3850,17 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) if (psta == NULL) return _SUCCESS; - /* DBG_871X("%s:%s\n", __func__, (initiator == 0)?"RX_DIR":"TX_DIR"); */ - if (initiator == 0) {/* recipient */ for (tid = 0; tid < MAXTID; tid++) { if (psta->recvreorder_ctrl[tid].enable) { - DBG_871X("rx agg disable tid(%d)\n", tid); issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); psta->recvreorder_ctrl[tid].enable = false; psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, - psta->recvreorder_ctrl[tid].indicate_seq); - #endif } } } else if (initiator == 1) {/* originator */ - /* DBG_871X("tx agg_enable_bitmap(0x%08x)\n", psta->htpriv.agg_enable_bitmap); */ for (tid = 0; tid < MAXTID; tid++) { if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { - DBG_871X("tx agg disable tid(%d)\n", tid); issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); psta->htpriv.agg_enable_bitmap &= ~BIT(tid); psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); @@ -4229,7 +3878,6 @@ unsigned int send_beacon(struct adapter *padapter) u8 bxmitok = false; int issue = 0; int poll = 0; - unsigned long start = jiffies; rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); @@ -4249,19 +3897,10 @@ unsigned int send_beacon(struct adapter *padapter) } - if (false == bxmitok) { - DBG_871X("%s fail! %u ms\n", __func__, jiffies_to_msecs(jiffies - start)); + if (!bxmitok) return _FAIL; - } else { - unsigned long passing_time = jiffies_to_msecs(jiffies - start); - - if (passing_time > 100 || issue > 3) - DBG_871X("%s success, issue:%d, poll:%d, %lu ms\n", __func__, issue, poll, passing_time); - /* else */ - /* DBG_871X("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, passing_time); */ - + else return _SUCCESS; - } } /**************************************************************************** @@ -4273,7 +3912,7 @@ Following are some utility functions for WiFi MLME void site_survey(struct adapter *padapter) { unsigned char survey_channel = 0, val8; - RT_SCAN_TYPE ScanType = SCAN_PASSIVE; + enum rt_scan_type ScanType = SCAN_PASSIVE; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u32 initialgain = 0; @@ -4289,18 +3928,6 @@ void site_survey(struct adapter *padapter) } } - DBG_871X(FUNC_ADPT_FMT" ch:%u (cnt:%u) at %dms, %c%c%c\n" - , FUNC_ADPT_ARG(padapter) - , survey_channel - , pmlmeext->sitesurvey_res.channel_idx - , jiffies_to_msecs(jiffies - padapter->mlmepriv.scan_start_time) - , ScanType?'A':'P', pmlmeext->sitesurvey_res.scan_mode?'A':'P' - , pmlmeext->sitesurvey_res.ssid[0].SsidLength?'S':' ' - ); -#ifdef DBG_FIXED_CHAN - DBG_871X(FUNC_ADPT_FMT" fixed_chan:%u\n", pmlmeext->fixed_chan); -#endif - if (survey_channel != 0) { /* PAUSE 4-AC Queue when site_survey */ /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ @@ -4351,18 +3978,6 @@ void site_survey(struct adapter *padapter) channel_scan_time_ms = pmlmeext->chan_scan_time; set_survey_timer(pmlmeext, channel_scan_time_ms); -#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - { - struct noise_info info; - - info.bPauseDIG = false; - info.IGIValue = 0; - info.max_time = channel_scan_time_ms/2;/* ms */ - info.chan = survey_channel; - rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &info, false); - } -#endif - } else { /* channel number is 0 or this channel is not valid. */ @@ -4426,10 +4041,8 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str len = packet_len - sizeof(struct ieee80211_hdr_3addr); - if (len > MAX_IE_SZ) { - /* DBG_871X("IE too long for survey event\n"); */ + if (len > MAX_IE_SZ) return _FAIL; - } memset(bssid, 0, sizeof(struct wlan_bssid_ex)); @@ -4465,16 +4078,13 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str /* checking SSID */ p = rtw_get_ie(bssid->IEs + ie_offset, WLAN_EID_SSID, &len, bssid->IELength - ie_offset); - if (p == NULL) { - DBG_871X("marc: cannot find SSID for survey event\n"); + if (!p) return _FAIL; - } if (*(p + 1)) { - if (len > NDIS_802_11_LENGTH_SSID) { - DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + if (len > NDIS_802_11_LENGTH_SSID) return _FAIL; - } + memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); bssid->Ssid.SsidLength = *(p + 1); } else @@ -4486,20 +4096,18 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str i = 0; p = rtw_get_ie(bssid->IEs + ie_offset, WLAN_EID_SUPP_RATES, &len, bssid->IELength - ie_offset); if (p) { - if (len > NDIS_802_11_LENGTH_RATES_EX) { - DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + if (len > NDIS_802_11_LENGTH_RATES_EX) return _FAIL; - } + memcpy(bssid->SupportedRates, (p + 2), len); i = len; } p = rtw_get_ie(bssid->IEs + ie_offset, WLAN_EID_EXT_SUPP_RATES, &len, bssid->IELength - ie_offset); if (p) { - if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) { - DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) return _FAIL; - } + memcpy(bssid->SupportedRates + i, (p + 2), len); } @@ -4565,16 +4173,6 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str pmlmepriv->num_sta_no_ht++; } - #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) & 1 - if (strcmp(bssid->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { - DBG_871X("Receiving %s(%pM, DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n" - , bssid->Ssid.Ssid, MAC_ARG(bssid->MacAddress), bssid->Configuration.DSConfig - , rtw_get_oper_ch(padapter) - , bssid->PhyInfo.SignalStrength, bssid->PhyInfo.SignalQuality, bssid->Rssi - ); - } - #endif - /* mark bss info receiving from nearby channel as SignalQuality 101 */ if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) bssid->PhyInfo.SignalQuality = 101; @@ -4618,8 +4216,6 @@ void start_create_ibss(struct adapter *padapter) /* issue beacon */ if (send_beacon(padapter) == _FAIL) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n")); - report_join_res(padapter, -1); pmlmeinfo->state = WIFI_FW_NULL_STATE; } else { @@ -4632,7 +4228,6 @@ void start_create_ibss(struct adapter *padapter) rtw_indicate_connect(padapter); } } else { - DBG_871X("start_create_ibss, invalid cap:%x\n", caps); return; } /* update bc/mc sta_info */ @@ -4693,7 +4288,6 @@ void start_clnt_join(struct adapter *padapter) report_join_res(padapter, 1); } else { - /* DBG_871X("marc: invalid cap:%x\n", caps); */ return; } @@ -4716,7 +4310,7 @@ void start_clnt_auth(struct adapter *padapter) pmlmeext->retry = 0; - DBG_871X_LEVEL(_drv_always_, "start auth\n"); + netdev_dbg(padapter->pnetdev, "start auth\n"); issue_auth(padapter, NULL, 0); set_link_timer(pmlmeext, REAUTH_TO); @@ -4748,8 +4342,6 @@ unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr if (!(!memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) return _SUCCESS; - DBG_871X("%s\n", __func__); - if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { pmlmeinfo->state = WIFI_FW_NULL_STATE; @@ -4768,7 +4360,7 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid { struct registry_priv *pregistrypriv; struct mlme_ext_priv *pmlmeext; - RT_CHANNEL_INFO *chplan_new; + struct rt_channel_info *chplan_new; u8 channel; u8 i; @@ -4781,8 +4373,8 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid (!pmlmeext->update_channel_plan_by_ap_done)) { u8 *ie, *p; u32 len; - RT_CHANNEL_PLAN chplan_ap; - RT_CHANNEL_INFO chplan_sta[MAX_CHANNEL_NUM]; + struct rt_channel_plan chplan_ap; + struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; u8 country[4]; u8 fcn; /* first channel number */ u8 noc; /* number of channel */ @@ -4801,8 +4393,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid memset(country, 0, 4); memcpy(country, p, 3); p += 3; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("%s: 802.11d country =%s\n", __func__, country)); i = 0; while ((ie - p) >= 3) { @@ -4821,26 +4411,7 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid } chplan_ap.Len = i; -#ifdef DEBUG_RTL871X - i = 0; - DBG_871X("%s: AP[%s] channel plan {", __func__, bssid->Ssid.Ssid); - while ((i < chplan_ap.Len) && (chplan_ap.Channel[i] != 0)) { - DBG_8192C("%02d,", chplan_ap.Channel[i]); - i++; - } - DBG_871X("}\n"); -#endif - memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); -#ifdef DEBUG_RTL871X - i = 0; - DBG_871X("%s: STA channel plan {", __func__); - while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { - DBG_871X("%02d(%c),", chplan_sta[i].ChannelNum, chplan_sta[i].ScanType == SCAN_PASSIVE?'p':'a'); - i++; - } - DBG_871X("}\n"); -#endif memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); chplan_new = pmlmeext->channel_set; @@ -4968,16 +4539,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid } pmlmeext->update_channel_plan_by_ap_done = 1; - -#ifdef DEBUG_RTL871X - k = 0; - DBG_871X("%s: new STA channel plan {", __func__); - while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) { - DBG_871X("%02d(%c),", chplan_new[k].ChannelNum, chplan_new[k].ScanType == SCAN_PASSIVE?'p':'c'); - k++; - } - DBG_871X("}\n"); -#endif } /* If channel is used by AP, set channel scan type to active */ @@ -4992,9 +4553,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid break; chplan_new[i].ScanType = SCAN_ACTIVE; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("%s: change channel %d scan type from passive to active\n", - __func__, channel)); } break; } @@ -5107,8 +4665,6 @@ void report_surveydone_event(struct adapter *padapter) psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; - DBG_871X("survey done event(%x) band:%d for %s\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter)); - rtw_enqueue_cmd(pcmdpriv, pcmd_obj); return; @@ -5155,8 +4711,6 @@ void report_join_res(struct adapter *padapter, int res) memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = res; - DBG_871X("report_join_res(%d)\n", res); - rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); @@ -5262,8 +4816,6 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi pdel_sta_evt->mac_id = mac_id; - DBG_871X("report_del_sta_event: delete STA, mac_id =%d\n", mac_id); - rtw_enqueue_cmd(pcmdpriv, pcmd_obj); } @@ -5306,8 +4858,6 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); padd_sta_evt->cam_id = cam_idx; - DBG_871X("report_add_sta_event: add STA\n"); - rtw_enqueue_cmd(pcmdpriv, pcmd_obj); } @@ -5439,7 +4989,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); - goto exit_mlmeext_joinbss_event_callback; + return; } if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) @@ -5475,8 +5025,6 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; - /* DBG_871X("set_sta_rate\n"); */ - psta->wireless_mode = pmlmeext->cur_wireless_mode; /* set per sta rate after updating HT cap. */ @@ -5501,11 +5049,6 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) if (get_iface_type(padapter) == IFACE_PORT0) rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); - -exit_mlmeext_joinbss_event_callback: - - DBG_871X("=>%s\n", __func__); - } /* currently only adhoc mode will go here */ @@ -5515,8 +5058,6 @@ void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *p struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 join_type; - DBG_871X("%s\n", __func__); - if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { /* adhoc master or sta_count>1 */ @@ -5584,13 +5125,8 @@ void _linked_info_dump(struct adapter *padapter) if (padapter->bLinkInfoDump) { - DBG_871X("\n ============[%s] linked status check ===================\n", ADPT_ARG(padapter)); - if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); - - DBG_871X("AP[%pM] - UndecoratedSmoothedPWDB:%d\n", - MAC_ARG(padapter->mlmepriv.cur_network.network.MacAddress), UndecoratedSmoothedPWDB); } else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) { struct list_head *phead, *plist; @@ -5603,9 +5139,6 @@ void _linked_info_dump(struct adapter *padapter) while (phead != plist) { psta = container_of(plist, struct sta_info, asoc_list); plist = get_next(plist); - - DBG_871X("STA[%pM]:UndecoratedSmoothedPWDB:%d\n", - MAC_ARG(psta->hwaddr), psta->rssi_stat.UndecoratedSmoothedPWDB); } spin_unlock_bh(&pstapriv->asoc_list_lock); @@ -5629,27 +5162,6 @@ static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta) { u8 ret = false; - #ifdef DBG_EXPIRATION_CHK - DBG_871X(FUNC_ADPT_FMT" rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu" - /*", probersp_bm:%llu, probersp_uo:%llu, probereq:%llu, BI:%u"*/ - ", retry:%u\n" - , FUNC_ADPT_ARG(padapter) - , STA_RX_PKTS_DIFF_ARG(psta) - , psta->sta_stats.rx_beacon_pkts - psta->sta_stats.last_rx_beacon_pkts - , psta->sta_stats.rx_probersp_pkts - psta->sta_stats.last_rx_probersp_pkts - /*, psta->sta_stats.rx_probersp_bm_pkts - psta->sta_stats.last_rx_probersp_bm_pkts - , psta->sta_stats.rx_probersp_uo_pkts - psta->sta_stats.last_rx_probersp_uo_pkts - , psta->sta_stats.rx_probereq_pkts - psta->sta_stats.last_rx_probereq_pkts - , pmlmeinfo->bcn_interval*/ - , pmlmeext->retry - ); - - DBG_871X(FUNC_ADPT_FMT" tx_pkts:%llu, link_count:%u\n", FUNC_ADPT_ARG(padapter) - , padapter->xmitpriv.tx_pkts - , pmlmeinfo->link_count - ); - #endif - if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) && sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) && sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta) @@ -5702,28 +5214,23 @@ void linked_status_chk(struct adapter *padapter) { if (rx_chk != _SUCCESS) { if (pmlmeext->retry == 0) { - #ifdef DBG_EXPIRATION_CHK - DBG_871X("issue_probereq to trigger probersp, retry =%d\n", pmlmeext->retry); - #endif issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); } } - if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit) { - #ifdef DBG_EXPIRATION_CHK - DBG_871X("%s issue_nulldata 0\n", __func__); - #endif + if (tx_chk != _SUCCESS && + pmlmeinfo->link_count++ == link_count_limit) tx_chk = issue_nulldata_in_interrupt(padapter, NULL); - } } if (rx_chk == _FAIL) { pmlmeext->retry++; if (pmlmeext->retry > rx_chk_limit) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n", - FUNC_ADPT_ARG(padapter)); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " disconnect or roaming\n", + FUNC_ADPT_ARG(padapter)); receive_disconnect(padapter, pmlmeinfo->network.MacAddress , WLAN_REASON_EXPIRATION_CHK); return; @@ -5783,8 +5290,6 @@ void survey_timer_hdl(struct timer_list *t) struct cmd_priv *pcmdpriv = &padapter->cmdpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - /* DBG_871X("marc: survey timer\n"); */ - /* issue rtw_sitesurvey_cmd */ if (pmlmeext->sitesurvey_res.state > SCAN_START) { if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { @@ -5792,12 +5297,7 @@ void survey_timer_hdl(struct timer_list *t) } if (pmlmeext->scan_abort) { - { - pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; - DBG_871X("%s idx:%d\n", __func__ - , pmlmeext->sitesurvey_res.channel_idx - ); - } + pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; pmlmeext->scan_abort = false;/* reset */ } @@ -5836,7 +5336,6 @@ void link_timer_hdl(struct timer_list *t) if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { - DBG_871X("link_timer_hdl:no beacon while connecting\n"); pmlmeinfo->state = WIFI_FW_NULL_STATE; report_join_res(padapter, -3); } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) { @@ -5855,7 +5354,6 @@ void link_timer_hdl(struct timer_list *t) /* */ } - DBG_871X("link_timer_hdl: auth timeout and try again\n"); pmlmeinfo->auth_seq = 1; issue_auth(padapter, NULL, 0); set_link_timer(pmlmeext, REAUTH_TO); @@ -5867,7 +5365,6 @@ void link_timer_hdl(struct timer_list *t) return; } - DBG_871X("link_timer_hdl: assoc timeout and try again\n"); issue_assocreq(padapter); set_link_timer(pmlmeext, REASSOC_TO); } @@ -5905,7 +5402,6 @@ void sa_query_timer_hdl(struct timer_list *t) } spin_unlock_bh(&pmlmepriv->lock); - DBG_871X("SA query timeout disconnect\n"); } u8 NULL_hdl(struct adapter *padapter, u8 *pbuf) @@ -5913,99 +5409,6 @@ u8 NULL_hdl(struct adapter *padapter, u8 *pbuf) return H2C_SUCCESS; } -#ifdef CONFIG_AUTO_AP_MODE -static int rtw_auto_ap_start_beacon(struct adapter *adapter) -{ - int ret = 0; - u8 *pbuf = NULL; - uint len; - u8 supportRate[16]; - int sz = 0, rateLen; - u8 *ie; - u8 wireless_mode, oper_channel; - u8 ssid[3] = {0}; /* hidden ssid */ - u32 ssid_len = sizeof(ssid); - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); - - - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) - return -EINVAL; - - - len = 128; - pbuf = rtw_zmalloc(len); - if (!pbuf) - return -ENOMEM; - - - /* generate beacon */ - ie = pbuf; - - /* timestamp will be inserted by hardware */ - sz += 8; - ie += sz; - - /* beacon interval : 2bytes */ - *(u16 *)ie = cpu_to_le16((u16)100);/* BCN_INTERVAL = 100; */ - sz += 2; - ie += 2; - - /* capability info */ - *(u16 *)ie = 0; - *(u16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_ESS); - *(u16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - /* u16*)ie |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); */ - sz += 2; - ie += 2; - - /* SSID */ - ie = rtw_set_ie(ie, WLAN_EID_SSID, ssid_len, ssid, &sz); - - /* supported rates */ - wireless_mode = WIRELESS_11BG_24N; - rtw_set_supported_rate(supportRate, wireless_mode); - rateLen = rtw_get_rateset_len(supportRate); - if (rateLen > 8) { - ie = rtw_set_ie(ie, WLAN_EID_SUPP_RATES, 8, supportRate, &sz); - } else { - ie = rtw_set_ie(ie, WLAN_EID_SUPP_RATES, rateLen, supportRate, &sz); - } - - - /* DS parameter set */ - if (check_buddy_fwstate(adapter, _FW_LINKED) && - check_buddy_fwstate(adapter, WIFI_STATION_STATE)) { - struct adapter *pbuddystruct adapter = adapter->pbuddystruct adapter; - struct mlme_ext_priv *pbuddy_mlmeext = &pbuddystruct adapter->mlmeextpriv; - - oper_channel = pbuddy_mlmeext->cur_channel; - } else { - oper_channel = adapter_to_dvobj(adapter)->oper_channel; - } - ie = rtw_set_ie(ie, WLAN_EID_DS_PARAMS, 1, &oper_channel, &sz); - - /* ext supported rates */ - if (rateLen > 8) { - ie = rtw_set_ie(ie, WLAN_EID_EXT_SUPP_RATES, (rateLen - 8), (supportRate + 8), &sz); - } - - DBG_871X("%s, start auto ap beacon sz =%d\n", __func__, sz); - - /* lunch ap mode & start to issue beacon */ - if (rtw_check_beacon_data(adapter, pbuf, sz) == _SUCCESS) { - - } else { - ret = -EINVAL; - } - - - kfree(pbuf); - - return ret; - -} -#endif/* CONFIG_AUTO_AP_MODE */ - u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) { u8 type; @@ -6030,12 +5433,6 @@ u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); /* Set_MSR(padapter, type); */ - -#ifdef CONFIG_AUTO_AP_MODE - if (psetop->mode == Ndis802_11APMode) - rtw_auto_ap_start_beacon(padapter); -#endif - if (psetop->mode == Ndis802_11APMode) { /* Do this after port switch to */ /* prevent from downloading rsvd page to wrong port */ @@ -6214,8 +5611,6 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf) pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; break; } - - DBG_871X("set HT ch/bw before connected\n"); } } break; @@ -6294,16 +5689,15 @@ static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_c j = 0; for (i = 0; i < in_num; i++) { - DBG_871X(FUNC_ADPT_FMT" "CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(&in[i])); - set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value); if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) && set_idx >= 0 && rtw_mlme_band_check(padapter, in[i].hw_value) ) { if (j >= out_num) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" out_num:%u not enough\n", - FUNC_ADPT_ARG(padapter), out_num); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " out_num:%u not enough\n", + FUNC_ADPT_ARG(padapter), out_num); break; } @@ -6322,13 +5716,13 @@ static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_c if (j == 0) { for (i = 0; i < pmlmeext->max_chan_nums; i++) { - DBG_871X(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), pmlmeext->channel_set[i].ChannelNum); - if (rtw_mlme_band_check(padapter, pmlmeext->channel_set[i].ChannelNum)) { if (j >= out_num) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" out_num:%u not enough\n", - FUNC_ADPT_ARG(padapter), out_num); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " out_num:%u not enough\n", + FUNC_ADPT_ARG(padapter), + out_num); break; } @@ -6454,8 +5848,10 @@ u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) ctrl = BIT(15) | BIT6 | ((pparm->algorithm) << 2) | pparm->keyid; write_cam(padapter, cam_id, ctrl, addr, pparm->key); - DBG_871X_LEVEL(_drv_always_, "set group key camid:%d, addr:%pM, kid:%d, type:%s\n" - , cam_id, MAC_ARG(addr), pparm->keyid, security_type_str(pparm->algorithm)); + netdev_dbg(padapter->pnetdev, + "set group key camid:%d, addr:%pM, kid:%d, type:%s\n", + cam_id, MAC_ARG(addr), pparm->keyid, + security_type_str(pparm->algorithm)); } if (cam_id >= 0 && cam_id <= 3) @@ -6483,7 +5879,8 @@ u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) psta = rtw_get_stainfo(pstapriv, pparm->addr); if (!psta) { - DBG_871X_LEVEL(_drv_always_, "%s sta:%pM not found\n", __func__, MAC_ARG(pparm->addr)); + netdev_dbg(padapter->pnetdev, "%s sta:%pM not found\n", + __func__, MAC_ARG(pparm->addr)); ret = H2C_REJECTED; goto exit; } @@ -6496,13 +5893,17 @@ u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) write_to_cam: if (pparm->algorithm == _NO_PRIVACY_) { while ((cam_id = rtw_camid_search(padapter, pparm->addr, -1)) >= 0) { - DBG_871X_LEVEL(_drv_always_, "clear key for addr:%pM, camid:%d\n", MAC_ARG(pparm->addr), cam_id); + netdev_dbg(padapter->pnetdev, + "clear key for addr:%pM, camid:%d\n", + MAC_ARG(pparm->addr), cam_id); clear_cam_entry(padapter, cam_id); rtw_camid_free(padapter, cam_id); } } else { - DBG_871X_LEVEL(_drv_always_, "set pairwise key camid:%d, addr:%pM, kid:%d, type:%s\n", - cam_id, MAC_ARG(pparm->addr), pparm->keyid, security_type_str(pparm->algorithm)); + netdev_dbg(padapter->pnetdev, + "set pairwise key camid:%d, addr:%pM, kid:%d, type:%s\n", + cam_id, MAC_ARG(pparm->addr), pparm->keyid, + security_type_str(pparm->algorithm)); ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); } @@ -6617,10 +6018,6 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) #ifdef CHECK_EVENT_SEQ /* checking event sequence... */ if (evt_seq != (atomic_read(&pevt_priv->event_seq) & 0x7f)) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("Event Seq Error! %d vs %d\n", (evt_seq & 0x7f), - (atomic_read(&pevt_priv->event_seq) & 0x7f))); - pevt_priv->event_seq = (evt_seq+1)&0x7f; goto _abort_event_; @@ -6628,21 +6025,14 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) #endif /* checking if event code is valid */ - if (evt_code >= MAX_C2HEVT) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code)); + if (evt_code >= MAX_C2HEVT) goto _abort_event_; - } /* checking if event size match the event parm size */ if ((wlanevents[evt_code].parmsize != 0) && - (wlanevents[evt_code].parmsize != evt_sz)) { - - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n", - evt_code, wlanevents[evt_code].parmsize, evt_sz)); + (wlanevents[evt_code].parmsize != evt_sz)) goto _abort_event_; - } - atomic_inc(&pevt_priv->event_seq); peventbuf += 2; @@ -6725,10 +6115,8 @@ u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf) u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf) { - if (send_beacon(padapter) == _FAIL) { - DBG_871X("issue_beacon, fail!\n"); + if (send_beacon(padapter) == _FAIL) return H2C_PARAMETERS_ERROR; - } /* tx bc/mc frames after update TIM */ chk_bmc_sleepq_hdl(padapter, NULL); @@ -6750,7 +6138,6 @@ int rtw_chk_start_clnt_join(struct adapter *padapter, u8 *ch, u8 *bw, u8 *offset } if (connect_allow) { - DBG_871X("start_join_set_ch_bw: ch =%d, bwmode =%d, ch_offset =%d\n", cur_ch, cur_bw, cur_ch_offset); *ch = cur_ch; *bw = cur_bw; *offset = cur_ch_offset; @@ -6790,10 +6177,6 @@ u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf) set_ch_parm = (struct set_ch_parm *)pbuf; - DBG_871X(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", - FUNC_NDEV_ARG(padapter->pnetdev), - set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); - pmlmeext->cur_channel = set_ch_parm->ch; pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; pmlmeext->cur_bwmode = set_ch_parm->bw; @@ -6826,17 +6209,6 @@ u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf) -{ - struct LedBlink_param *ledBlink_param; - - if (!pbuf) - return H2C_PARAMETERS_ERROR; - - ledBlink_param = (struct LedBlink_param *)pbuf; - return H2C_SUCCESS; -} - u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf) { return H2C_REJECTED; diff --git a/drivers/staging/rtl8723bs/core/rtw_odm.c b/drivers/staging/rtl8723bs/core/rtw_odm.c index 93e8f17d2574f9f7ad8719ce23675115ac3b9dae..f6b73a2a0270fb5e601b192596e72e780a5254a2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_odm.c +++ b/drivers/staging/rtl8723bs/core/rtw_odm.c @@ -90,18 +90,19 @@ static const char * const odm_dbg_level_str[] = { #define RTW_ODM_DBG_LEVEL_NUM 6 -void rtw_odm_dbg_comp_msg(void *sel, struct adapter *adapter) +void rtw_odm_dbg_comp_msg(struct adapter *adapter) { u64 dbg_comp; int i; rtw_hal_get_def_var(adapter, HW_DEF_ODM_DBG_FLAG, &dbg_comp); - DBG_871X_SEL_NL(sel, "odm.DebugComponents = 0x%016llx\n", dbg_comp); + netdev_dbg(adapter->pnetdev, "odm.DebugComponents = 0x%016llx\n", + dbg_comp); for (i = 0; i < RTW_ODM_COMP_MAX; i++) { if (odm_comp_str[i]) - DBG_871X_SEL_NL(sel, "%cBIT%-2d %s\n", - (BIT0 << i) & dbg_comp ? '+' : ' ', - i, odm_comp_str[i]); + netdev_dbg(adapter->pnetdev, "%cBIT%-2d %s\n", + (BIT0 << i) & dbg_comp ? '+' : ' ', i, + odm_comp_str[i]); } } @@ -116,11 +117,11 @@ void rtw_odm_dbg_level_msg(void *sel, struct adapter *adapter) int i; rtw_hal_get_def_var(adapter, HW_DEF_ODM_DBG_LEVEL, &dbg_level); - DBG_871X_SEL_NL(sel, "odm.DebugLevel = %u\n", dbg_level); + netdev_dbg(adapter->pnetdev, "odm.DebugLevel = %u\n", dbg_level); for (i = 0; i < RTW_ODM_DBG_LEVEL_NUM; i++) { if (odm_dbg_level_str[i]) - DBG_871X_SEL_NL(sel, "%u %s\n", - i, odm_dbg_level_str[i]); + netdev_dbg(adapter->pnetdev, "%u %s\n", i, + odm_dbg_level_str[i]); } } @@ -135,12 +136,12 @@ void rtw_odm_ability_msg(void *sel, struct adapter *adapter) int i; rtw_hal_get_hwreg(adapter, HW_VAR_DM_FLAG, (u8 *)&ability); - DBG_871X_SEL_NL(sel, "odm.SupportAbility = 0x%08x\n", ability); + netdev_dbg(adapter->pnetdev, "odm.SupportAbility = 0x%08x\n", ability); for (i = 0; i < RTW_ODM_ABILITY_MAX; i++) { if (odm_ability_str[i]) - DBG_871X_SEL_NL(sel, "%cBIT%-2d %s\n", - (BIT0 << i) & ability ? '+' : ' ', i, - odm_ability_str[i]); + netdev_dbg(adapter->pnetdev, "%cBIT%-2d %s\n", + (BIT0 << i) & ability ? '+' : ' ', i, + odm_ability_str[i]); } } @@ -152,19 +153,19 @@ inline void rtw_odm_ability_set(struct adapter *adapter, u32 ability) void rtw_odm_adaptivity_parm_msg(void *sel, struct adapter *adapter) { struct hal_com_data *pHalData = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &pHalData->odmpriv; - - DBG_871X_SEL_NL(sel, "%10s %16s %8s %10s %11s %14s\n", - "TH_L2H_ini", "TH_EDCCA_HL_diff", "IGI_Base", - "ForceEDCCA", "AdapEn_RSSI", "IGI_LowerBound"); - DBG_871X_SEL_NL(sel, "0x%-8x %-16d 0x%-6x %-10d %-11u %-14u\n", - (u8)odm->TH_L2H_ini, - odm->TH_EDCCA_HL_diff, - odm->IGI_Base, - odm->ForceEDCCA, - odm->AdapEn_RSSI, - odm->IGI_LowerBound - ); + struct dm_odm_t *odm = &pHalData->odmpriv; + + netdev_dbg(adapter->pnetdev, "%10s %16s %8s %10s %11s %14s\n", + "TH_L2H_ini", "TH_EDCCA_HL_diff", "IGI_Base", "ForceEDCCA", + "AdapEn_RSSI", "IGI_LowerBound"); + netdev_dbg(adapter->pnetdev, + "0x%-8x %-16d 0x%-6x %-10d %-11u %-14u\n", + (u8)odm->TH_L2H_ini, + odm->TH_EDCCA_HL_diff, + odm->IGI_Base, + odm->ForceEDCCA, + odm->AdapEn_RSSI, + odm->IGI_LowerBound); } void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, @@ -173,7 +174,7 @@ void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, u8 IGI_LowerBound) { struct hal_com_data *pHalData = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &pHalData->odmpriv; + struct dm_odm_t *odm = &pHalData->odmpriv; odm->TH_L2H_ini = TH_L2H_ini; odm->TH_EDCCA_HL_diff = TH_EDCCA_HL_diff; @@ -186,8 +187,9 @@ void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, void rtw_odm_get_perpkt_rssi(void *sel, struct adapter *adapter) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &hal_data->odmpriv; + struct dm_odm_t *odm = &hal_data->odmpriv; - DBG_871X_SEL_NL(sel, "RxRate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", - HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); + netdev_dbg(adapter->pnetdev, + "RxRate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", + HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); } diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 5b05d1eaa32832fbdfa2644a730756abd187180d..251b9abdf591bafcedd2ed6eb553c5981a74e66e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -22,11 +22,9 @@ void _ips_enter(struct adapter *padapter) pwrpriv->ips_mode = pwrpriv->ips_mode_req; pwrpriv->ips_enter_cnts++; - DBG_871X("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts); if (rf_off == pwrpriv->change_rfpwrstate) { pwrpriv->bpower_saving = true; - DBG_871X("nolinked power save enter\n"); if (pwrpriv->ips_mode == IPS_LEVEL_2) pwrpriv->bkeepfwalive = true; @@ -59,15 +57,11 @@ int _ips_leave(struct adapter *padapter) pwrpriv->bips_processing = true; pwrpriv->change_rfpwrstate = rf_on; pwrpriv->ips_leave_cnts++; - DBG_871X("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts); result = rtw_ips_pwr_up(padapter); if (result == _SUCCESS) { pwrpriv->rf_pwrstate = rf_on; } - DBG_871X("nolinked power save leave\n"); - - DBG_871X("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c)); pwrpriv->bips_processing = false; pwrpriv->bkeepfwalive = false; @@ -89,7 +83,7 @@ int ips_leave(struct adapter *padapter) ret = _ips_leave(padapter); mutex_unlock(&pwrpriv->lock); - if (_SUCCESS == ret) + if (ret == _SUCCESS) hal_btcoex_IpsNotify(padapter, IPS_NONE); return ret; @@ -103,15 +97,11 @@ static bool rtw_pwr_unassociated_idle(struct adapter *adapter) bool ret = false; - if (adapter_to_pwrctl(adapter)->bpower_saving) { - /* DBG_871X("%s: already in LPS or IPS mode\n", __func__); */ + if (adapter_to_pwrctl(adapter)->bpower_saving) goto exit; - } - if (time_before(jiffies, adapter_to_pwrctl(adapter)->ips_deny_time)) { - /* DBG_871X("%s ips_deny_time\n", __func__); */ + if (time_before(jiffies, adapter_to_pwrctl(adapter)->ips_deny_time)) goto exit; - } if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) @@ -134,9 +124,12 @@ static bool rtw_pwr_unassociated_idle(struct adapter *adapter) if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { - DBG_871X_LEVEL(_drv_always_, "There are some pkts to transmit\n"); - DBG_871X_LEVEL(_drv_always_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", - pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); + netdev_dbg(adapter->pnetdev, + "There are some pkts to transmit\n"); + netdev_dbg(adapter->pnetdev, + "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", + pxmit_priv->free_xmitbuf_cnt, + pxmit_priv->free_xmit_extbuf_cnt); goto exit; } @@ -161,15 +154,11 @@ void rtw_ps_processor(struct adapter *padapter) mutex_lock(&adapter_to_pwrctl(padapter)->lock); ps_deny = rtw_ps_deny_get(padapter); mutex_unlock(&adapter_to_pwrctl(padapter)->lock); - if (ps_deny != 0) { - DBG_871X(FUNC_ADPT_FMT ": ps_deny = 0x%08X, skip power save!\n", - FUNC_ADPT_ARG(padapter), ps_deny); + if (ps_deny != 0) goto exit; - } if (pwrpriv->bInSuspend) {/* system suspend or autosuspend */ pdbgpriv->dbg_ps_insuspend_cnt++; - DBG_871X("%s, pwrpriv->bInSuspend == true ignore this process\n", __func__); return; } @@ -182,7 +171,6 @@ void rtw_ps_processor(struct adapter *padapter) goto exit; if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) { - DBG_871X("==>%s\n", __func__); pwrpriv->change_rfpwrstate = rf_off; { ips_enter(padapter); @@ -221,7 +209,6 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets if (adapter_to_pwrctl(padapter)->bLeisurePs && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE) && !(hal_btcoex_IsBtControlLps(padapter))) { - DBG_871X("leave lps via Tx = %d\n", xmit_cnt); bLeaveLPS = true; } } @@ -234,15 +221,12 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) { if (adapter_to_pwrctl(padapter)->bLeisurePs && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE) - && !(hal_btcoex_IsBtControlLps(padapter))) { - DBG_871X("leave lps via Rx = %d\n", pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); + && !(hal_btcoex_IsBtControlLps(padapter))) bLeaveLPS = true; - } } } if (bLeaveLPS) - /* DBG_871X("leave lps via %s, Tx = %d, Rx = %d\n", tx?"Tx":"Rx", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ /* rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); */ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, tx?0:1); } @@ -264,44 +248,28 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv) pslv = PS_STATE(pslv); - if (pwrpriv->brpwmtimeout) { - DBG_871X("%s: RPWM timeout, force to set RPWM(0x%02X) again!\n", __func__, pslv); - } else { - if ((pwrpriv->rpwm == pslv) - || ((pwrpriv->rpwm >= PS_STATE_S2) && (pslv >= PS_STATE_S2))) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, - ("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", __func__, pwrpriv->rpwm, pslv)); + if (!pwrpriv->brpwmtimeout) { + if (pwrpriv->rpwm == pslv || + (pwrpriv->rpwm >= PS_STATE_S2 && pslv >= PS_STATE_S2)) return; - } + } if ((padapter->bSurpriseRemoved) || !(padapter->hw_init_completed)) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, - ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", - __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); - pwrpriv->cpwm = PS_STATE_S4; return; } if (padapter->bDriverStopped) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, - ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv)); - - if (pslv < PS_STATE_S2) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, - ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv)); + if (pslv < PS_STATE_S2) return; - } } rpwm = pslv | pwrpriv->tog; /* only when from PS_STATE S0/S1 to S2 and higher needs ACK */ if ((pwrpriv->cpwm < PS_STATE_S2) && (pslv >= PS_STATE_S2)) rpwm |= PS_ACK; - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("rtw_set_rpwm: rpwm = 0x%02x cpwm = 0x%02x\n", rpwm, pwrpriv->cpwm)); pwrpriv->rpwm = pslv; @@ -335,7 +303,6 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv) } if (jiffies_to_msecs(jiffies - start_time) > LPS_RPWM_WAIT_MS) { - DBG_871X("%s: polling cpwm timeout! poll_cnt =%d, cpwm_orig =%02x, cpwm_now =%02x\n", __func__, poll_cnt, cpwm_orig, cpwm_now); _set_timer(&pwrpriv->pwr_rpwm_timer, 1); break; } @@ -350,17 +317,8 @@ static u8 PS_RDY_CHECK(struct adapter *padapter) struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) - if (pwrpriv->bInSuspend && pwrpriv->wowlan_mode) - return true; - else if (pwrpriv->bInSuspend && pwrpriv->wowlan_ap_mode) - return true; - else if (pwrpriv->bInSuspend) - return false; -#else if (pwrpriv->bInSuspend) return false; -#endif curr_time = jiffies; @@ -377,10 +335,9 @@ static u8 PS_RDY_CHECK(struct adapter *padapter) ) return false; - if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && !(padapter->securitypriv.binstallGrpkey)) { - DBG_871X("Group handshake still in progress !!!\n"); + if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && + !padapter->securitypriv.binstallGrpkey) return false; - } if (!rtw_cfg80211_pwr_mgmt(padapter)) return false; @@ -391,21 +348,12 @@ static u8 PS_RDY_CHECK(struct adapter *padapter) void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode, const char *msg) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) - struct debug_priv *pdbgpriv = &padapter->dvobj->drv_dbg; -#endif - - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("%s: PowerMode =%d Smart_PS =%d\n", - __func__, ps_mode, smart_ps)); - if (ps_mode > PM_Card_Disable) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode)); + if (ps_mode > PM_Card_Disable) return; - } if (pwrpriv->pwr_mode == ps_mode) - if (PS_MODE_ACTIVE == ps_mode) + if (ps_mode == PS_MODE_ACTIVE) return; @@ -416,37 +364,11 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a if (!(hal_btcoex_IsBtControlLps(padapter)) || (hal_btcoex_IsBtControlLps(padapter) && !(hal_btcoex_IsLpsOn(padapter)))) { - DBG_871X(FUNC_ADPT_FMT" Leave 802.11 power save - %s\n", - FUNC_ADPT_ARG(padapter), msg); - pwrpriv->pwr_mode = ps_mode; rtw_set_rpwm(padapter, PS_STATE_S4); -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) - if (pwrpriv->wowlan_mode || pwrpriv->wowlan_ap_mode) { - unsigned long start_time; - u32 delay_ms; - u8 val8; - delay_ms = 20; - start_time = jiffies; - do { - rtw_hal_get_hwreg(padapter, HW_VAR_SYS_CLKR, &val8); - if (!(val8 & BIT(4))) { /* 0x08 bit4 = 1 --> in 32k, bit4 = 0 --> leave 32k */ - pwrpriv->cpwm = PS_STATE_S4; - break; - } - if (jiffies_to_msecs(jiffies - start_time) > delay_ms) { - DBG_871X("%s: Wait for FW 32K leave more than %u ms!!!\n", - __func__, delay_ms); - pdbgpriv->dbg_wow_leave_ps_fail_cnt++; - break; - } - msleep(1); - } while (1); - } -#endif rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); - pwrpriv->bFwCurrentInPSMode = false; + pwrpriv->fw_current_in_ps_mode = false; hal_btcoex_LpsNotify(padapter, ps_mode); } @@ -456,12 +378,9 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a ) { u8 pslv; - DBG_871X(FUNC_ADPT_FMT" Enter 802.11 power save - %s\n", - FUNC_ADPT_ARG(padapter), msg); - hal_btcoex_LpsNotify(padapter, ps_mode); - pwrpriv->bFwCurrentInPSMode = true; + pwrpriv->fw_current_in_ps_mode = true; pwrpriv->pwr_mode = ps_mode; pwrpriv->smart_ps = smart_ps; pwrpriv->bcn_ant_mode = bcn_ant_mode; @@ -508,13 +427,11 @@ s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) if (padapter->bSurpriseRemoved) { err = -2; - DBG_871X("%s: device surprise removed!!\n", __func__); break; } if (jiffies_to_msecs(jiffies - start_time) > delay_ms) { err = -1; - DBG_871X("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); break; } msleep(1); @@ -554,15 +471,13 @@ void LPS_Enter(struct adapter *padapter, const char *msg) /* Idle for a while if we connect to AP a while ago. */ if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { - sprintf(buf, "WIFI-%s", msg); + scnprintf(buf, sizeof(buf), "WIFI-%s", msg); pwrpriv->bpower_saving = true; rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, padapter->registrypriv.smart_ps, 0, buf); } } else pwrpriv->LpsIdleCount++; } - -/* DBG_871X("-LeisurePSEnter\n"); */ } /* */ @@ -577,14 +492,12 @@ void LPS_Leave(struct adapter *padapter, const char *msg) struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); char buf[32] = {0}; -/* DBG_871X("+LeisurePSLeave\n"); */ - if (hal_btcoex_IsBtControlLps(padapter)) return; if (pwrpriv->bLeisurePs) { if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { - sprintf(buf, "WIFI-%s", msg); + scnprintf(buf, sizeof(buf), "WIFI-%s", msg); rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, buf); if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) @@ -593,8 +506,6 @@ void LPS_Leave(struct adapter *padapter, const char *msg) } pwrpriv->bpower_saving = false; -/* DBG_871X("-LeisurePSLeave\n"); */ - } void LeaveAllPowerSaveModeDirect(struct adapter *Adapter) @@ -603,20 +514,13 @@ void LeaveAllPowerSaveModeDirect(struct adapter *Adapter) struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter); - DBG_871X("%s.....\n", __func__); - - if (Adapter->bSurpriseRemoved) { - DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n", - FUNC_ADPT_ARG(Adapter), Adapter->bSurpriseRemoved); + if (Adapter->bSurpriseRemoved) return; - } if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */ - if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { - DBG_871X("%s: Driver Already Leave LPS\n", __func__); + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) return; - } mutex_lock(&pwrpriv->lock); @@ -627,8 +531,7 @@ void LeaveAllPowerSaveModeDirect(struct adapter *Adapter) rtw_lps_ctrl_wk_cmd(pri_padapter, LPS_CTRL_LEAVE, 0); } else { if (pwrpriv->rf_pwrstate == rf_off) - if (!ips_leave(pri_padapter)) - DBG_871X("======> ips_leave fail.............\n"); + ips_leave(pri_padapter); } } @@ -642,17 +545,11 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter) u8 enqueue = 0; int n_assoc_iface = 0; - if (!Adapter->bup) { - DBG_871X(FUNC_ADPT_FMT ": bup =%d Skip!\n", - FUNC_ADPT_ARG(Adapter), Adapter->bup); + if (!Adapter->bup) return; - } - if (Adapter->bSurpriseRemoved) { - DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n", - FUNC_ADPT_ARG(Adapter), Adapter->bSurpriseRemoved); + if (Adapter->bSurpriseRemoved) return; - } if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE)) n_assoc_iface++; @@ -665,8 +562,7 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter) LPS_Leave_check(Adapter); } else { if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) { - if (!ips_leave(Adapter)) - DBG_871X("======> ips_leave fail.............\n"); + ips_leave(Adapter); } } } @@ -697,10 +593,9 @@ void LPS_Leave_check(struct adapter *padapter) if (bReady) break; - if (jiffies_to_msecs(jiffies - start_time) > 100) { - DBG_871X("Wait for cpwm event than 100 ms!!!\n"); + if (jiffies_to_msecs(jiffies - start_time) > 100) break; - } + msleep(1); } } @@ -720,10 +615,8 @@ void cpwm_int_hdl(struct adapter *padapter, struct reportpwrstate_parm *preportp mutex_lock(&pwrpriv->lock); - if (pwrpriv->rpwm < PS_STATE_S2) { - DBG_871X("%s: Redundant CPWM Int. RPWM = 0x%02X CPWM = 0x%02x\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); + if (pwrpriv->rpwm < PS_STATE_S2) goto exit; - } pwrpriv->cpwm = PS_STATE(preportpwrstate->state); pwrpriv->cpwm_tog = preportpwrstate->state & PS_TOGGLE; @@ -739,8 +632,6 @@ void cpwm_int_hdl(struct adapter *padapter, struct reportpwrstate_parm *preportp exit: mutex_unlock(&pwrpriv->lock); - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("cpwm_int_hdl: cpwm = 0x%02x\n", pwrpriv->cpwm)); } static void cpwm_event_callback(struct work_struct *work) @@ -750,8 +641,6 @@ static void cpwm_event_callback(struct work_struct *work) struct adapter *adapter = dvobj->if1; struct reportpwrstate_parm report; - /* DBG_871X("%s\n", __func__); */ - report.state = PS_STATE_S2; cpwm_int_hdl(adapter, &report); } @@ -766,20 +655,17 @@ static void rpwmtimeout_workitem_callback(struct work_struct *work) pwrpriv = container_of(work, struct pwrctrl_priv, rpwmtimeoutwi); dvobj = pwrctl_to_dvobj(pwrpriv); padapter = dvobj->if1; -/* DBG_871X("+%s: rpwm = 0x%02X cpwm = 0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); */ mutex_lock(&pwrpriv->lock); - if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) { - DBG_871X("%s: rpwm = 0x%02X cpwm = 0x%02X CPWM done!\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); + if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) goto exit; - } + mutex_unlock(&pwrpriv->lock); if (rtw_read8(padapter, 0x100) != 0xEA) { struct reportpwrstate_parm report; report.state = PS_STATE_S2; - DBG_871X("\n%s: FW already leave 32K!\n\n", __func__); cpwm_int_hdl(padapter, &report); return; @@ -787,10 +673,9 @@ static void rpwmtimeout_workitem_callback(struct work_struct *work) mutex_lock(&pwrpriv->lock); - if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) { - DBG_871X("%s: cpwm =%d, nothing to do!\n", __func__, pwrpriv->cpwm); + if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) goto exit; - } + pwrpriv->brpwmtimeout = true; rtw_set_rpwm(padapter, pwrpriv->rpwm); pwrpriv->brpwmtimeout = false; @@ -806,12 +691,8 @@ static void pwr_rpwm_timeout_handler(struct timer_list *t) { struct pwrctrl_priv *pwrpriv = from_timer(pwrpriv, t, pwr_rpwm_timer); - DBG_871X("+%s: rpwm = 0x%02X cpwm = 0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); - - if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) { - DBG_871X("+%s: cpwm =%d, nothing to do!\n", __func__, pwrpriv->cpwm); + if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) return; - } _set_workitem(&pwrpriv->rpwmtimeoutwi); } @@ -856,11 +737,7 @@ s32 rtw_register_task_alive(struct adapter *padapter, u32 task) register_task_alive(pwrctrl, task); - if (pwrctrl->bFwCurrentInPSMode) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("%s: task = 0x%x cpwm = 0x%02x alives = 0x%08x\n", - __func__, task, pwrctrl->cpwm, pwrctrl->alives)); - + if (pwrctrl->fw_current_in_ps_mode) { if (pwrctrl->cpwm < pslv) { if (pwrctrl->cpwm < PS_STATE_S2) res = _FAIL; @@ -871,7 +748,7 @@ s32 rtw_register_task_alive(struct adapter *padapter, u32 task) mutex_unlock(&pwrctrl->lock); - if (_FAIL == res) + if (res == _FAIL) if (pwrctrl->cpwm >= PS_STATE_S2) res = _SUCCESS; @@ -908,11 +785,7 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task) unregister_task_alive(pwrctrl, task); - if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->bFwCurrentInPSMode) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("%s: cpwm = 0x%02x alives = 0x%08x\n", - __func__, pwrctrl->cpwm, pwrctrl->alives)); - + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->fw_current_in_ps_mode) { if (pwrctrl->cpwm > pslv) if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) rtw_set_rpwm(padapter, pslv); @@ -949,11 +822,7 @@ s32 rtw_register_tx_alive(struct adapter *padapter) register_task_alive(pwrctrl, XMIT_ALIVE); - if (pwrctrl->bFwCurrentInPSMode) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("rtw_register_tx_alive: cpwm = 0x%02x alives = 0x%08x\n", - pwrctrl->cpwm, pwrctrl->alives)); - + if (pwrctrl->fw_current_in_ps_mode) { if (pwrctrl->cpwm < pslv) { if (pwrctrl->cpwm < PS_STATE_S2) res = _FAIL; @@ -964,7 +833,7 @@ s32 rtw_register_tx_alive(struct adapter *padapter) mutex_unlock(&pwrctrl->lock); - if (_FAIL == res) + if (res == _FAIL) if (pwrctrl->cpwm >= PS_STATE_S2) res = _SUCCESS; @@ -998,11 +867,7 @@ s32 rtw_register_cmd_alive(struct adapter *padapter) register_task_alive(pwrctrl, CMD_ALIVE); - if (pwrctrl->bFwCurrentInPSMode) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, - ("rtw_register_cmd_alive: cpwm = 0x%02x alives = 0x%08x\n", - pwrctrl->cpwm, pwrctrl->alives)); - + if (pwrctrl->fw_current_in_ps_mode) { if (pwrctrl->cpwm < pslv) { if (pwrctrl->cpwm < PS_STATE_S2) res = _FAIL; @@ -1013,7 +878,7 @@ s32 rtw_register_cmd_alive(struct adapter *padapter) mutex_unlock(&pwrctrl->lock); - if (_FAIL == res) + if (res == _FAIL) if (pwrctrl->cpwm >= PS_STATE_S2) res = _SUCCESS; @@ -1047,11 +912,7 @@ void rtw_unregister_tx_alive(struct adapter *padapter) unregister_task_alive(pwrctrl, XMIT_ALIVE); - if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->bFwCurrentInPSMode) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, - ("%s: cpwm = 0x%02x alives = 0x%08x\n", - __func__, pwrctrl->cpwm, pwrctrl->alives)); - + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->fw_current_in_ps_mode) { if (pwrctrl->cpwm > pslv) if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) rtw_set_rpwm(padapter, pslv); @@ -1087,11 +948,7 @@ void rtw_unregister_cmd_alive(struct adapter *padapter) unregister_task_alive(pwrctrl, CMD_ALIVE); - if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->bFwCurrentInPSMode) { - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, - ("%s: cpwm = 0x%02x alives = 0x%08x\n", - __func__, pwrctrl->cpwm, pwrctrl->alives)); - + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->fw_current_in_ps_mode) { if (pwrctrl->cpwm > pslv) { if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) rtw_set_rpwm(padapter, pslv); @@ -1124,7 +981,7 @@ void rtw_init_pwrctrl_priv(struct adapter *padapter) pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ pwrctrlpriv->bLeisurePs = pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE; - pwrctrlpriv->bFwCurrentInPSMode = false; + pwrctrlpriv->fw_current_in_ps_mode = false; pwrctrlpriv->rpwm = 0; pwrctrlpriv->cpwm = PS_STATE_S4; @@ -1149,29 +1006,11 @@ void rtw_init_pwrctrl_priv(struct adapter *padapter) pwrctrlpriv->wowlan_mode = false; pwrctrlpriv->wowlan_ap_mode = false; - -#ifdef CONFIG_PNO_SUPPORT - pwrctrlpriv->pno_inited = false; - pwrctrlpriv->pnlo_info = NULL; - pwrctrlpriv->pscan_info = NULL; - pwrctrlpriv->pno_ssid_list = NULL; - pwrctrlpriv->pno_in_resume = true; -#endif } void rtw_free_pwrctrl_priv(struct adapter *adapter) { -#ifdef CONFIG_PNO_SUPPORT - if (pwrctrlpriv->pnlo_info) - printk("****** pnlo_info memory leak********\n"); - - if (pwrctrlpriv->pscan_info) - printk("****** pscan_info memory leak********\n"); - - if (pwrctrlpriv->pno_ssid_list) - printk("****** pno_ssid_list memory leak********\n"); -#endif } inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) @@ -1207,27 +1046,14 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal pwrpriv->ips_deny_time = deny_time; - if (pwrpriv->ps_processing) { - DBG_871X("%s wait ps_processing...\n", __func__); + if (pwrpriv->ps_processing) while (pwrpriv->ps_processing && jiffies_to_msecs(jiffies - start) <= 3000) mdelay(10); - if (pwrpriv->ps_processing) - DBG_871X("%s wait ps_processing timeout\n", __func__); - else - DBG_871X("%s wait ps_processing done\n", __func__); - } - if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) { - DBG_871X("%s wait bInSuspend...\n", __func__); + if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) while (pwrpriv->bInSuspend && jiffies_to_msecs(jiffies - start) <= 3000 - ) { + ) mdelay(10); - } - if (pwrpriv->bInSuspend) - DBG_871X("%s wait bInSuspend timeout\n", __func__); - else - DBG_871X("%s wait bInSuspend done\n", __func__); - } /* System suspend is not allowed to wakeup */ if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) { @@ -1249,9 +1075,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal if (rf_off == pwrpriv->rf_pwrstate) { { - DBG_8192C("%s call ips_leave....\n", __func__); - if (_FAIL == ips_leave(padapter)) { - DBG_8192C("======> ips_leave fail.............\n"); + if (ips_leave(padapter) == _FAIL) { ret = _FAIL; goto exit; } @@ -1260,11 +1084,6 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal /* TODO: the following checking need to be merged... */ if (padapter->bDriverStopped || !padapter->bup || !padapter->hw_init_completed) { - DBG_8192C("%s: bDriverStopped =%d, bup =%d, hw_init_completed =%u\n" - , caller - , padapter->bDriverStopped - , padapter->bup - , padapter->hw_init_completed); ret = false; goto exit; } @@ -1284,7 +1103,7 @@ int rtw_pm_set_lps(struct adapter *padapter, u8 mode) if (mode < PS_MODE_NUM) { if (pwrctrlpriv->power_mgnt != mode) { - if (PS_MODE_ACTIVE == mode) + if (mode == PS_MODE_ACTIVE) LeaveAllPowerSaveMode(padapter); else pwrctrlpriv->LpsIdleCount = 2; @@ -1305,12 +1124,10 @@ int rtw_pm_set_ips(struct adapter *padapter, u8 mode) if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { rtw_ips_mode_req(pwrctrlpriv, mode); - DBG_871X("%s %s\n", __func__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2"); return 0; } else if (mode == IPS_NONE) { rtw_ips_mode_req(pwrctrlpriv, mode); - DBG_871X("%s %s\n", __func__, "IPS_NONE"); - if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter))) + if ((padapter->bSurpriseRemoved == 0) && (rtw_pwr_wakeup(padapter) == _FAIL)) return -EFAULT; } else return -EINVAL; @@ -1322,51 +1139,30 @@ int rtw_pm_set_ips(struct adapter *padapter, u8 mode) * ATTENTION: *This function will request pwrctrl LOCK! */ -void rtw_ps_deny(struct adapter *padapter, enum PS_DENY_REASON reason) +void rtw_ps_deny(struct adapter *padapter, enum ps_deny_reason reason) { struct pwrctrl_priv *pwrpriv; - /* DBG_871X("+" FUNC_ADPT_FMT ": Request PS deny for %d (0x%08X)\n", */ - /* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ - pwrpriv = adapter_to_pwrctl(padapter); mutex_lock(&pwrpriv->lock); - if (pwrpriv->ps_deny & BIT(reason)) { - DBG_871X(FUNC_ADPT_FMT ": [WARNING] Reason %d had been set before!!\n", - FUNC_ADPT_ARG(padapter), reason); - } pwrpriv->ps_deny |= BIT(reason); mutex_unlock(&pwrpriv->lock); - - /* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ - /* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ } /* * ATTENTION: *This function will request pwrctrl LOCK! */ -void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason) +void rtw_ps_deny_cancel(struct adapter *padapter, enum ps_deny_reason reason) { struct pwrctrl_priv *pwrpriv; - - /* DBG_871X("+" FUNC_ADPT_FMT ": Cancel PS deny for %d(0x%08X)\n", */ - /* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ - pwrpriv = adapter_to_pwrctl(padapter); mutex_lock(&pwrpriv->lock); - if ((pwrpriv->ps_deny & BIT(reason)) == 0) { - DBG_871X(FUNC_ADPT_FMT ": [ERROR] Reason %d had been canceled before!!\n", - FUNC_ADPT_ARG(padapter), reason); - } pwrpriv->ps_deny &= ~BIT(reason); mutex_unlock(&pwrpriv->lock); - - /* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ - /* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ } /* diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 3c9dbd7443d900b7d044463717a07c5b3dc45011..668a703dee7fdcd0a1b6f3a452b7d4dbfbe9978b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -30,11 +30,11 @@ void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) _rtw_init_queue(&psta_recvpriv->defrag_q); } -sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) +signed int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) { - sint i; + signed int i; union recv_frame *precvframe; - sint res = _SUCCESS; + signed int res = _SUCCESS; spin_lock_init(&precvpriv->lock); @@ -168,7 +168,7 @@ int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_ -sint _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) +signed int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) { struct adapter *padapter = precvframe->u.hdr.adapter; @@ -187,9 +187,9 @@ sint _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) return _SUCCESS; } -sint rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) +signed int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) { - sint ret; + signed int ret; /* _spinlock(&pfree_recv_queue->lock); */ spin_lock_bh(&queue->lock); @@ -201,7 +201,7 @@ sint rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) } /* -sint rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) +signed int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) { return rtw_free_recvframe(precvframe, queue); } @@ -248,14 +248,11 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) cnt++; } - if (cnt) - DBG_871X(FUNC_ADPT_FMT" dequeue %d\n", FUNC_ADPT_ARG(adapter), cnt); - return cnt; } -sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) +signed int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) { spin_lock_bh(&queue->lock); @@ -267,7 +264,7 @@ sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queu return _SUCCESS; } -sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) +signed int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) { spin_lock_bh(&queue->lock); @@ -305,11 +302,10 @@ struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue) } -sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe); -sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) +static signed int recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) { - sint i, res = _SUCCESS; + signed int i, res = _SUCCESS; u32 datalen; u8 miccode[8]; u8 bmic_err = false, brpt_micerror = true; @@ -326,10 +322,6 @@ sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); if (prxattrib->encrypt == _TKIP_) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:prxattrib->encrypt == _TKIP_\n")); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:da = 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5])); - /* calculate mic code */ if (stainfo) { if (IS_MCAST(prxattrib->ra)) { @@ -338,28 +330,20 @@ sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) /* rxdata_key_idx =(((iv[3])>>6)&0x3) ; */ mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n")); - /* DBG_871X("\n recvframe_chkmic: bcmc key psecuritypriv->dot118021XGrpKeyid(%d), pmlmeinfo->key_index(%d) , recv key_id(%d)\n", */ /* psecuritypriv->dot118021XGrpKeyid, pmlmeinfo->key_index, rxdata_key_idx); */ if (psecuritypriv->binstallGrpkey == false) { res = _FAIL; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n")); - DBG_871X("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); goto exit; } } else { mickey = &stainfo->dot11tkiprxmickey.skey[0]; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n")); } datalen = precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */ pframe = precvframe->u.hdr.rx_data; payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len =%d prxattrib->icv_len =%d\n", prxattrib->iv_len, prxattrib->icv_len)); - - rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], (unsigned char)prxattrib->priority); /* care the length of the data */ pframemic = payload+datalen; @@ -367,64 +351,29 @@ sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) bmic_err = false; for (i = 0; i < 8; i++) { - if (miccode[i] != *(pframemic+i)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic:miccode[%d](%02x) != *(pframemic+%d)(%02x) ", i, miccode[i], i, *(pframemic+i))); + if (miccode[i] != *(pframemic + i)) bmic_err = true; - } } if (bmic_err == true) { - - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n *(pframemic-8)-*(pframemic-1) = 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - *(pframemic-8), *(pframemic-7), *(pframemic-6), *(pframemic-5), *(pframemic-4), *(pframemic-3), *(pframemic-2), *(pframemic-1))); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n *(pframemic-16)-*(pframemic-9) = 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - *(pframemic-16), *(pframemic-15), *(pframemic-14), *(pframemic-13), *(pframemic-12), *(pframemic-11), *(pframemic-10), *(pframemic-9))); - - { - uint i; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len =%d) ======\n", precvframe->u.hdr.len)); - for (i = 0; i < precvframe->u.hdr.len; i = i+8) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", - *(precvframe->u.hdr.rx_data+i), *(precvframe->u.hdr.rx_data+i+1), - *(precvframe->u.hdr.rx_data+i+2), *(precvframe->u.hdr.rx_data+i+3), - *(precvframe->u.hdr.rx_data+i+4), *(precvframe->u.hdr.rx_data+i+5), - *(precvframe->u.hdr.rx_data+i+6), *(precvframe->u.hdr.rx_data+i+7))); - } - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet end [len =%d]======\n", precvframe->u.hdr.len)); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen =%d,\n", prxattrib->hdrlen)); - } - - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ra = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey =%d ", - prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], - prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey)); - /* double check key_index for some timing issue , */ /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index)) brpt_micerror = false; - if ((prxattrib->bdecrypted == true) && (brpt_micerror == true)) { + if (prxattrib->bdecrypted && brpt_micerror) rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra)); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted =%d ", prxattrib->bdecrypted)); - DBG_871X(" mic error :prxattrib->bdecrypted =%d\n", prxattrib->bdecrypted); - } else { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted =%d ", prxattrib->bdecrypted)); - DBG_871X(" mic error :prxattrib->bdecrypted =%d\n", prxattrib->bdecrypted); - } res = _FAIL; } else { /* mic checked ok */ - if ((psecuritypriv->bcheck_grpkey == false) && (IS_MCAST(prxattrib->ra) == true)) { + if (!psecuritypriv->bcheck_grpkey && + IS_MCAST(prxattrib->ra)) psecuritypriv->bcheck_grpkey = true; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey =true")); - } } - - } else - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo == NULL!!!\n")); + } recvframe_pull_tail(precvframe, 8); @@ -436,8 +385,7 @@ exit: } /* decrypt and set the ivlen, icvlen of the recv_frame */ -union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_frame); -union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_frame) +static union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_frame) { struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; @@ -445,17 +393,11 @@ union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_fr union recv_frame *return_packet = precv_frame; u32 res = _SUCCESS; - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt); - - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted =%x prxattrib->encrypt = 0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt)); - if (prxattrib->encrypt > 0) { u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen; prxattrib->key_index = (((iv[3])>>6)&0x3); if (prxattrib->key_index > WEP_KEYS) { - DBG_871X("prxattrib->key_index(%d) > WEP_KEYS\n", prxattrib->key_index); - switch (prxattrib->encrypt) { case _WEP40_: case _WEP104_: @@ -473,27 +415,15 @@ union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_fr if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt == true))) { psecuritypriv->hw_decrypted = false; - #ifdef DBG_RX_DECRYPTOR - DBG_871X("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", - __func__, - __LINE__, - prxattrib->bdecrypted, - prxattrib->encrypt, - psecuritypriv->hw_decrypted); - #endif - switch (prxattrib->encrypt) { case _WEP40_: case _WEP104_: - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_wep); rtw_wep_decrypt(padapter, (u8 *)precv_frame); break; case _TKIP_: - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_tkip); res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); break; case _AES_: - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_aes); res = rtw_aes_decrypt(padapter, (u8 *)precv_frame); break; default: @@ -502,28 +432,8 @@ union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_fr } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_) ) { - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_hw); - psecuritypriv->hw_decrypted = true; - #ifdef DBG_RX_DECRYPTOR - DBG_871X("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", - __func__, - __LINE__, - prxattrib->bdecrypted, - prxattrib->encrypt, - psecuritypriv->hw_decrypted); - - #endif } else { - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_unknown); - #ifdef DBG_RX_DECRYPTOR - DBG_871X("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", - __func__, - __LINE__, - prxattrib->bdecrypted, - prxattrib->encrypt, - psecuritypriv->hw_decrypted); - #endif } if (res == _FAIL) { @@ -536,8 +446,7 @@ union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_fr } /* set the security information in the recv_frame */ -union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_frame); -union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_frame) +static union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_frame) { u8 *psta_addr = NULL; u8 *ptr; @@ -563,15 +472,12 @@ union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_fram psta = rtw_get_stainfo(pstapriv, psta_addr); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm =%d\n", adapter->securitypriv.dot11AuthAlgrthm)); - if (auth_alg == 2) { if ((psta) && (psta->ieee8021x_blocked)) { __be16 be_tmp; /* blocked */ /* only accept EAPOL frame */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked == 1\n")); prtnframe = precv_frame; @@ -590,22 +496,15 @@ union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_fram } else { /* allowed */ /* check decryption status, and decrypt the frame if needed */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked == 0\n")); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy =%x\n", precv_frame->u.hdr.attrib.privacy)); - - if (pattrib->bdecrypted == 0) - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted =%x\n", pattrib->bdecrypted)); prtnframe = precv_frame; /* check is the EAPOL frame or not (Rekey) */ /* if (ether_type == eapol_type) { */ - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type == 0x888e\n")); */ /* check Rekey */ /* prtnframe =precv_frame; */ /* */ /* else { */ - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type = 0x%04x\n", ether_type)); */ /* */ } } else @@ -614,26 +513,19 @@ union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_fram return prtnframe; } -sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache); -sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) +static signed int recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) { - sint tid = precv_frame->u.hdr.attrib.priority; + signed int 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) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl = 0x%x, tid = 0x%x\n", seq_ctrl, tid)); - + if (tid > 15) return _FAIL; - } if (1) { /* if (bretry) */ - if (seq_ctrl == prxcache->tid_rxseq[tid]) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl = 0x%x, tid = 0x%x, tid_rxseq = 0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid])); - + if (seq_ctrl == prxcache->tid_rxseq[tid]) return _FAIL; - } } prxcache->tid_rxseq[tid] = seq_ctrl; @@ -642,8 +534,7 @@ sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcac } -void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame); -void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame) +static void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame) { unsigned char pwrbit; u8 *ptr = precv_frame->u.hdr.rx_data; @@ -663,7 +554,6 @@ void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame stop_sta_xmit(padapter, psta); - /* DBG_871X("to sleep, sta_dz_bitmap =%x\n", pstapriv->sta_dz_bitmap); */ } } else { if (psta->state & WIFI_SLEEP_STATE) { @@ -671,16 +561,13 @@ void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame /* pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); */ wakeup_sta_to_xmit(padapter, psta); - - /* DBG_871X("to wakeup, sta_dz_bitmap =%x\n", pstapriv->sta_dz_bitmap); */ } } } } -void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame); -void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame) +static void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame) { struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; struct sta_priv *pstapriv = &padapter->stapriv; @@ -731,8 +618,7 @@ void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame) } } -void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta); -void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta) +static void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta) { int sz; struct sta_info *psta = NULL; @@ -763,29 +649,24 @@ void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct traffic_check_for_leave_lps(padapter, false, 0); } -sint sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, - struct sta_info **psta); -sint sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, +static signed int 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; + signed int 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; - sint bmcast = IS_MCAST(pattrib->dst); - - /* DBG_871X("[%s] %d, seqnum:%d\n", __func__, __LINE__, pattrib->seq_num); */ + signed int bmcast = IS_MCAST(pattrib->dst); if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { /* filter packets that SA is myself or multicast or broadcast */ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA ==myself\n")); ret = _FAIL; goto exit; } @@ -807,7 +688,6 @@ sint sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */ if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid != TA under STATION_MODE; drop pkt\n")); ret = _FAIL; goto exit; } @@ -849,7 +729,6 @@ sint sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ if (!*psta) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n")); ret = _FAIL; goto exit; } @@ -858,19 +737,17 @@ exit: return ret; } -sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, - struct sta_info **psta); -sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, +static signed int 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; - sint ret = _SUCCESS; + signed int ret = _SUCCESS; struct sta_priv *pstapriv = &adapter->stapriv; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; u8 *mybssid = get_bssid(pmlmepriv); u8 *myhwaddr = myid(&adapter->eeprompriv); - sint bmcast = IS_MCAST(pattrib->dst); + signed int bmcast = IS_MCAST(pattrib->dst); if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) && (check_fwstate(pmlmepriv, _FW_LINKED) == true || @@ -879,22 +756,12 @@ sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, /* filter packets that SA is myself or multicast or broadcast */ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA ==myself\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s SA =%pM, myhwaddr =%pM\n", - __func__, MAC_ARG(pattrib->src), MAC_ARG(myhwaddr)); - #endif ret = _FAIL; goto exit; } /* da should be for me */ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - (" ap2sta_data_frame: compare DA fail; DA =%pM\n", MAC_ARG(pattrib->dst))); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s DA =%pM\n", __func__, MAC_ARG(pattrib->dst)); - #endif ret = _FAIL; goto exit; } @@ -904,19 +771,9 @@ sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - (" ap2sta_data_frame: compare BSSID fail ; BSSID =%pM\n", MAC_ARG(pattrib->bssid))); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid =%pM\n", MAC_ARG(mybssid))); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s BSSID =%pM, mybssid =%pM\n", - __func__, MAC_ARG(pattrib->bssid), MAC_ARG(mybssid)); - DBG_871X("this adapter = %d, buddy adapter = %d\n", adapter->adapter_type, adapter->pbuddystruct adapter->adapter_type); - #endif - - if (!bmcast) { - DBG_871X("issue_deauth to the nonassociated ap =%pM for the reason(7)\n", MAC_ARG(pattrib->bssid)); + + if (!bmcast) issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - } ret = _FAIL; goto exit; @@ -928,10 +785,6 @@ sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */ if (!*psta) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under STATION_MODE ; drop pkt\n", __func__); - #endif ret = _FAIL; goto exit; } @@ -957,10 +810,6 @@ sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ if (!*psta) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __func__); - #endif ret = _FAIL; goto exit; } @@ -978,31 +827,22 @@ sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, /* for AP multicast issue , modify by yiwei */ static unsigned long send_issue_deauth_time; - /* DBG_871X("After send deauth , %u ms has elapsed.\n", jiffies_to_msecs(jiffies - send_issue_deauth_time)); */ - if (jiffies_to_msecs(jiffies - send_issue_deauth_time) > 10000 || send_issue_deauth_time == 0) { send_issue_deauth_time = jiffies; - DBG_871X("issue_deauth to the ap =%pM for the reason(7)\n", MAC_ARG(pattrib->bssid)); - issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); } } } ret = _FAIL; - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s fw_state:0x%x\n", __func__, get_fwstate(pmlmepriv)); - #endif } exit: return ret; } -sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, - struct sta_info **psta); -sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, +static signed int sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, struct sta_info **psta) { u8 *ptr = precv_frame->u.hdr.rx_data; @@ -1010,7 +850,7 @@ sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, struct sta_priv *pstapriv = &adapter->stapriv; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; unsigned char *mybssid = get_bssid(pmlmepriv); - sint ret = _SUCCESS; + signed int ret = _SUCCESS; if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { /* For AP mode, RA =BSSID, TX =STA(SRC_ADDR), A3 =DST_ADDR */ @@ -1021,9 +861,6 @@ sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, *psta = rtw_get_stainfo(pstapriv, pattrib->src); if (!*psta) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n")); - DBG_871X("issue_deauth to sta =%pM for the reason(7)\n", MAC_ARG(pattrib->src)); - issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ret = RTW_RX_HANDLED; @@ -1047,7 +884,6 @@ sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, ret = RTW_RX_HANDLED; goto exit; } - DBG_871X("issue_deauth to sta =%pM for the reason(7)\n", MAC_ARG(pattrib->src)); issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ret = RTW_RX_HANDLED; goto exit; @@ -1057,8 +893,7 @@ exit: return ret; } -sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_frame); -sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_frame) +static signed int validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_frame) { struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; struct sta_priv *pstapriv = &padapter->stapriv; @@ -1066,8 +901,6 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_ struct sta_info *psta = NULL; /* uint len = precv_frame->u.hdr.len; */ - /* DBG_871X("+validate_recv_ctrl_frame\n"); */ - if (GetFrameType(pframe) != WIFI_CTRL_TYPE) return _FAIL; @@ -1115,7 +948,6 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_ return _FAIL; if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { - DBG_871X("%s alive check-rx ps-poll\n", __func__); psta->expire_to = pstapriv->expire_to; psta->state ^= WIFI_STA_ALIVE_CHK_STATE; } @@ -1147,15 +979,11 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_ pxmitframe->attrib.triggered = 1; - /* DBG_871X("handling ps-poll, q_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ - rtw_hal_xmitframe_enqueue(padapter, pxmitframe); if (psta->sleepq_len == 0) { pstapriv->tim_bitmap &= ~BIT(psta->aid); - /* DBG_871X("after handling ps-poll, tim =%x\n", pstapriv->tim_bitmap); */ - /* update BCN for TIM IE */ /* update_BCNTIM(padapter); */ update_beacon(padapter, WLAN_EID_TIM, NULL, true); @@ -1168,15 +996,11 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_ /* spin_unlock_bh(&psta->sleep_q.lock); */ spin_unlock_bh(&pxmitpriv->lock); - /* DBG_871X("no buffered packets to xmit\n"); */ if (pstapriv->tim_bitmap&BIT(psta->aid)) { if (psta->sleepq_len == 0) { - DBG_871X("no buffered packets to xmit\n"); - /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ issue_nulldata_in_interrupt(padapter, psta->hwaddr); } else { - DBG_871X("error!psta->sleepq_len =%d\n", psta->sleepq_len); psta->sleepq_len = 0; } @@ -1194,19 +1018,189 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_ } -union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame); -sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_frame); -sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_frame) +/* perform defrag */ +static union recv_frame *recvframe_defrag(struct adapter *adapter, + struct __queue *defrag_q) { - /* struct mlme_priv *pmlmepriv = &adapter->mlmepriv; */ + 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; + + curfragnum = 0; + pfree_recv_queue = &adapter->recvpriv.free_recv_queue; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n")); + phead = get_list_head(defrag_q); + plist = get_next(phead); + prframe = (union recv_frame *)plist; + pfhdr = &prframe->u.hdr; + list_del_init(&(prframe->u.list)); + + if (curfragnum != pfhdr->attrib.frag_num) { + /* the first fragment number must be 0 */ + /* free the whole queue */ + rtw_free_recvframe(prframe, pfree_recv_queue); + rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); + + return NULL; + } + + curfragnum++; + + plist = get_list_head(defrag_q); + + plist = get_next(plist); + + while (phead != plist) { + pnextrframe = (union recv_frame *)plist; + pnfhdr = &pnextrframe->u.hdr; + + + /* check the fragment sequence (2nd ~n fragment frame) */ + + if (curfragnum != pnfhdr->attrib.frag_num) { + /* the fragment number must be increasing (after decache) */ + /* release the defrag_q & prframe */ + rtw_free_recvframe(prframe, pfree_recv_queue); + rtw_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 */ + memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); + + recvframe_put(prframe, pnfhdr->len); + + pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; + plist = get_next(plist); + + } + + /* free the defrag_q queue and return the prframe */ + rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); + + return prframe; +} + +/* check if need to defrag, if needed queue the frame to defrag_q */ +static union recv_frame *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 = rtw_get_stainfo(pstapriv, psta_addr); + if (!psta) { + u8 type = GetFrameType(pfhdr->rx_data); + if (type != WIFI_DATA_TYPE) { + psta = rtw_get_bcmc_stainfo(padapter); + pdefrag_q = &psta->sta_recvpriv.defrag_q; + } else + 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 */ + rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); + + + /* Then enqueue the 0~(n-1) fragment into the defrag_q */ + + /* spin_lock(&pdefrag_q->lock); */ + phead = get_list_head(pdefrag_q); + list_add_tail(&pfhdr->list, phead); + /* spin_unlock(&pdefrag_q->lock); */ + + prtnframe = NULL; + + } else { + /* can't find this ta's defrag_queue, so free this recv_frame */ + rtw_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) { + /* spin_lock(&pdefrag_q->lock); */ + phead = get_list_head(pdefrag_q); + list_add_tail(&pfhdr->list, phead); + /* spin_unlock(&pdefrag_q->lock); */ + + /* 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 */ + rtw_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 (recvframe_chkmic(padapter, prtnframe) == _FAIL) { + rtw_free_recvframe(prtnframe, pfree_recv_queue); + prtnframe = NULL; + } + } + return prtnframe; +} + +static signed int validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_frame) +{ + /* struct mlme_priv *pmlmepriv = &adapter->mlmepriv; */ precv_frame = recvframe_chk_defrag(padapter, precv_frame); - if (!precv_frame) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__)); + if (!precv_frame) return _SUCCESS; - } { /* for rx pkt statistics */ @@ -1235,8 +1229,7 @@ sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_ } -sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_frame); -sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_frame) +static signed int validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_frame) { u8 bretry; u8 *psa, *pda, *pbssid; @@ -1244,7 +1237,7 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f u8 *ptr = precv_frame->u.hdr.rx_data; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; struct security_priv *psecuritypriv = &adapter->securitypriv; - sint ret = _SUCCESS; + signed int ret = _SUCCESS; bretry = GetRetry(ptr); pda = get_da(ptr); @@ -1252,9 +1245,6 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f pbssid = get_hdr_bssid(ptr); if (!pbssid) { - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s pbssid == NULL\n", __func__); - #endif ret = _FAIL; goto exit; } @@ -1287,7 +1277,6 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ret = _FAIL; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n")); break; default: @@ -1297,9 +1286,6 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f } if (ret == _FAIL) { - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s case:%d, res:%d\n", __func__, pattrib->to_fr_ds, ret); - #endif goto exit; } else if (ret == RTW_RX_HANDLED) { goto exit; @@ -1307,10 +1293,6 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f if (!psta) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta == NULL\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s psta == NULL\n", __func__); - #endif ret = _FAIL; goto exit; } @@ -1345,23 +1327,13 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f /* decache, drop duplicate recv packets */ if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s recv_decache return _FAIL\n", __func__); - #endif ret = _FAIL; goto exit; } if (pattrib->privacy) { - - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy =%x\n", pattrib->privacy)); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x)) =%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra))); - GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt =%d\n", pattrib->encrypt)); - SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); } else { pattrib->encrypt = 0; @@ -1372,7 +1344,7 @@ exit: return ret; } -static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *precv_frame) +static signed int validate_80211w_mgmt(struct adapter *adapter, union recv_frame *precv_frame) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; @@ -1401,7 +1373,6 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; mgmt_DATA = rtw_zmalloc(data_len); if (!mgmt_DATA) { - DBG_871X("%s mgmt allocate fail !!!!!!!!!\n", __func__); goto validate_80211w_fail; } precv_frame = decryptor(adapter, precv_frame); @@ -1413,19 +1384,16 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec pattrib->pkt_len = pattrib->pkt_len - pattrib->iv_len - pattrib->icv_len; kfree(mgmt_DATA); if (!precv_frame) { - DBG_871X("%s mgmt descrypt fail !!!!!!!!!\n", __func__); goto validate_80211w_fail; } } else if (IS_MCAST(GetAddr1Ptr(ptr)) && (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC)) { - sint BIP_ret = _SUCCESS; + signed int BIP_ret = _SUCCESS; /* verify BIP MME IE of broadcast/multicast de-auth/disassoc packet */ BIP_ret = rtw_BIP_verify(adapter, (u8 *)precv_frame); if (BIP_ret == _FAIL) { - /* DBG_871X("802.11w BIP verify fail\n"); */ goto validate_80211w_fail; } else if (BIP_ret == RTW_RX_HANDLED) { - /* DBG_871X("802.11w recv none protected packet\n"); */ /* issue sa query request */ issue_action_SA_Query(adapter, NULL, 0, 0); goto validate_80211w_fail; @@ -1438,11 +1406,9 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_UNPROTECTED_WNM && ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_SELF_PROTECTED && ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_P2P) { - DBG_871X("action frame category =%d should robust\n", ptr[WLAN_HDR_A3_LEN]); goto validate_80211w_fail; } } else if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC) { - DBG_871X("802.11w recv none protected packet\n"); /* issue sa query request */ issue_action_SA_Query(adapter, NULL, 0, 0); goto validate_80211w_fail; @@ -1456,19 +1422,7 @@ validate_80211w_fail: } -static inline void dump_rx_packet(u8 *ptr) -{ - int i; - - DBG_871X("#############################\n"); - for (i = 0; i < 64; i = i+8) - DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), - *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); - DBG_871X("#############################\n"); -} - -sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame); -sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) +static signed int validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) { /* shall check frame subtype, to / from ds, da, bssid */ @@ -1476,7 +1430,7 @@ sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) u8 type; u8 subtype; - sint retval = _SUCCESS; + signed int retval = _SUCCESS; u8 bDumpRxPkt; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; @@ -1486,9 +1440,7 @@ sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) /* add version chk */ if (ver != 0) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!= 0)\n")); retval = _FAIL; - DBG_COUNTER(adapter->rx_logs.core_rx_pre_ver_err); goto exit; } @@ -1506,48 +1458,27 @@ sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) pattrib->privacy = GetPrivacy(ptr); pattrib->order = GetOrder(ptr); rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); - if (bDumpRxPkt == 1) /* dump all rx packets */ - dump_rx_packet(ptr); - else if ((bDumpRxPkt == 2) && (type == WIFI_MGT_TYPE)) - dump_rx_packet(ptr); - else if ((bDumpRxPkt == 3) && (type == WIFI_DATA_TYPE)) - dump_rx_packet(ptr); switch (type) { case WIFI_MGT_TYPE: /* mgnt */ - DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt); if (validate_80211w_mgmt(adapter, precv_frame) == _FAIL) { retval = _FAIL; - DBG_COUNTER(padapter->rx_logs.core_rx_pre_mgmt_err_80211w); break; } retval = validate_recv_mgnt_frame(adapter, precv_frame); - if (retval == _FAIL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n")); - DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt_err); - } retval = _FAIL; /* only data frame return _SUCCESS */ break; case WIFI_CTRL_TYPE: /* ctrl */ - DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl); retval = validate_recv_ctrl_frame(adapter, precv_frame); - if (retval == _FAIL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n")); - DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl_err); - } retval = _FAIL; /* only data frame return _SUCCESS */ break; case WIFI_DATA_TYPE: /* data */ - DBG_COUNTER(adapter->rx_logs.core_rx_pre_data); - pattrib->qos = (subtype & BIT(7)) ? 1:0; retval = validate_recv_data_frame(adapter, precv_frame); if (retval == _FAIL) { struct recv_priv *precvpriv = &adapter->recvpriv; - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail\n")); */ precvpriv->rx_drop++; - DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_err); } else if (retval == _SUCCESS) { #ifdef DBG_RX_DUMP_EAP u8 bDumpRxPkt; @@ -1558,18 +1489,10 @@ sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) /* get ether_type */ memcpy(ð_type, ptr + pattrib->hdrlen + pattrib->iv_len + LLC_HEADER_SIZE, 2); eth_type = ntohs((unsigned short) eth_type); - if ((bDumpRxPkt == 4) && (eth_type == 0x888e)) - dump_rx_packet(ptr); #endif - } else - DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_handled); + } break; default: - DBG_COUNTER(adapter->rx_logs.core_rx_pre_unknown); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type = 0x%x\n", type)); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME validate_recv_data_frame fail! type = 0x%x\n", type); - #endif retval = _FAIL; break; } @@ -1578,12 +1501,10 @@ exit: return retval; } - /* remove the wlanhdr and add the eth_hdr */ -sint wlanhdr_to_ethhdr(union recv_frame *precvframe); -sint wlanhdr_to_ethhdr(union recv_frame *precvframe) +static signed int wlanhdr_to_ethhdr(union recv_frame *precvframe) { - sint rmv_len; + signed int rmv_len; u16 eth_type, len; u8 bsnaphdr; u8 *psnap_type; @@ -1615,44 +1536,10 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe) rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr?SNAP_SIZE:0); len = precvframe->u.hdr.len - rmv_len; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ===pattrib->hdrlen: %x, pattrib->iv_len:%x ===\n\n", pattrib->hdrlen, pattrib->iv_len)); - memcpy(&be_tmp, ptr+rmv_len, 2); eth_type = ntohs(be_tmp); /* pattrib->ether_type */ pattrib->eth_type = eth_type; -#ifdef CONFIG_AUTO_AP_MODE - if (0x8899 == pattrib->eth_type) { - struct sta_info *psta = precvframe->u.hdr.psta; - - DBG_871X("wlan rx: got eth_type = 0x%x\n", pattrib->eth_type); - - if (psta && psta->isrc && psta->pid > 0) { - u16 rx_pid; - - rx_pid = *(u16 *)(ptr+rmv_len+2); - - DBG_871X("wlan rx(pid = 0x%x): sta(%pM) pid = 0x%x\n", - rx_pid, MAC_ARG(psta->hwaddr), psta->pid); - - if (rx_pid == psta->pid) { - int i; - u16 len = *(u16 *)(ptr+rmv_len+4); - /* u16 ctrl_type = *(u16*)(ptr+rmv_len+6); */ - - /* DBG_871X("RC: len = 0x%x, ctrl_type = 0x%x\n", len, ctrl_type); */ - DBG_871X("RC: len = 0x%x\n", len); - - for (i = 0; i < len ; i++) - DBG_871X("0x%x\n", *(ptr+rmv_len+6+i)); - /* DBG_871X("0x%x\n", *(ptr+rmv_len+8+i)); */ - - DBG_871X("RC-end\n"); - } - } - } -#endif /* CONFIG_AUTO_AP_MODE */ - if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) { ptr += rmv_len; *ptr = 0x87; @@ -1677,197 +1564,13 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe) return _SUCCESS; } -/* 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; - - curfragnum = 0; - pfree_recv_queue = &adapter->recvpriv.free_recv_queue; - - phead = get_list_head(defrag_q); - plist = get_next(phead); - prframe = (union recv_frame *)plist; - pfhdr = &prframe->u.hdr; - list_del_init(&(prframe->u.list)); - - if (curfragnum != pfhdr->attrib.frag_num) { - /* the first fragment number must be 0 */ - /* free the whole queue */ - rtw_free_recvframe(prframe, pfree_recv_queue); - rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); - - return NULL; - } - - curfragnum++; - - plist = get_list_head(defrag_q); - - plist = get_next(plist); - - while (phead != plist) { - pnextrframe = (union recv_frame *)plist; - pnfhdr = &pnextrframe->u.hdr; - - - /* check the fragment sequence (2nd ~n fragment frame) */ - - if (curfragnum != pnfhdr->attrib.frag_num) { - /* the fragment number must be increasing (after decache) */ - /* release the defrag_q & prframe */ - rtw_free_recvframe(prframe, pfree_recv_queue); - rtw_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 */ - memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); - - recvframe_put(prframe, pnfhdr->len); - - pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; - plist = get_next(plist); - - } - - /* free the defrag_q queue and return the prframe */ - rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); - - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n")); - - return prframe; -} - -/* check if need to defrag, if needed queue the frame to defrag_q */ -union recv_frame *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 = rtw_get_stainfo(pstapriv, psta_addr); - if (!psta) { - u8 type = GetFrameType(pfhdr->rx_data); - if (type != WIFI_DATA_TYPE) { - psta = rtw_get_bcmc_stainfo(padapter); - pdefrag_q = &psta->sta_recvpriv.defrag_q; - } else - 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 */ - rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); - - - /* Then enqueue the 0~(n-1) fragment into the defrag_q */ - - /* spin_lock(&pdefrag_q->lock); */ - phead = get_list_head(pdefrag_q); - list_add_tail(&pfhdr->list, phead); - /* spin_unlock(&pdefrag_q->lock); */ - - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); - - prtnframe = NULL; - - } else { - /* can't find this ta's defrag_queue, so free this recv_frame */ - rtw_free_recvframe(precv_frame, pfree_recv_queue); - prtnframe = NULL; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q == NULL: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); - } - - } - - if ((ismfrag == 0) && (fragnum != 0)) { - /* the last fragment frame */ - /* enqueue the last fragment */ - if (pdefrag_q) { - /* spin_lock(&pdefrag_q->lock); */ - phead = get_list_head(pdefrag_q); - list_add_tail(&pfhdr->list, phead); - /* spin_unlock(&pdefrag_q->lock); */ - - /* call recvframe_defrag to defrag */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); - precv_frame = recvframe_defrag(padapter, pdefrag_q); - prtnframe = precv_frame; - - } else { - /* can't find this ta's defrag_queue, so free this recv_frame */ - rtw_free_recvframe(precv_frame, pfree_recv_queue); - prtnframe = NULL; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q == NULL: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); - } - - } - - - if ((prtnframe) && (prtnframe->u.hdr.attrib.privacy)) { - /* after defrag we must check tkip mic code */ - if (recvframe_chkmic(padapter, prtnframe) == _FAIL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe) == _FAIL\n")); - rtw_free_recvframe(prtnframe, pfree_recv_queue); - prtnframe = NULL; - } - } - return prtnframe; -} - static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) { int a_len, padding_len; u16 nSubframe_Length; u8 nr_subframes, i; u8 *pdata; - _pkt *sub_pkt, *subframes[MAX_SUBFRAME_COUNT]; + struct sk_buff *sub_pkt, *subframes[MAX_SUBFRAME_COUNT]; struct recv_priv *precvpriv = &padapter->recvpriv; struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue); @@ -1887,16 +1590,12 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) /* Offset 12 denote 2 mac address */ nSubframe_Length = get_unaligned_be16(pdata + 12); - if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { - DBG_871X("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length); + if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) break; - } sub_pkt = rtw_os_alloc_msdu_pkt(prframe, nSubframe_Length, pdata); - if (!sub_pkt) { - DBG_871X("%s(): allocate sub packet fail !!!\n", __func__); + if (!sub_pkt) break; - } /* move the data point to data content */ pdata += ETH_HLEN; @@ -1904,10 +1603,8 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) subframes[nr_subframes++] = sub_pkt; - if (nr_subframes >= MAX_SUBFRAME_COUNT) { - DBG_871X("ParseSubframe(): Too many Subframes! Packets dropped!\n"); + if (nr_subframes >= MAX_SUBFRAME_COUNT) break; - } pdata += nSubframe_Length; a_len -= nSubframe_Length; @@ -1916,10 +1613,9 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) if (padding_len == 4) padding_len = 0; - if (a_len < padding_len) { - DBG_871X("ParseSubframe(): a_len < padding_len !\n"); + if (a_len < padding_len) break; - } + pdata += padding_len; a_len -= padding_len; } @@ -1939,8 +1635,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) return _SUCCESS; } -int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num); -int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) +static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) { struct adapter *padapter = preorder_ctrl->padapter; struct dvobj_priv *psdpriv = padapter->dvobj; @@ -1951,10 +1646,6 @@ int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) /* Rx Reorder initialize condition. */ if (preorder_ctrl->indicate_seq == 0xFFFF) { preorder_ctrl->indicate_seq = seq_num; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d init IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, seq_num); - #endif /* DbgPrint("check_indicate_seq, 1st->indicate_seq =%d\n", precvpriv->indicate_seq); */ } @@ -1963,15 +1654,8 @@ int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) /* Drop out the packet which SeqNum is smaller than WinStart */ if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) { - /* RT_TRACE(COMP_RX_REORDER, DBG_LOUD, ("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, NewSeqNum)); */ /* DbgPrint("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ - #ifdef DBG_RX_DROP_FRAME - DBG_871X("%s IndicateSeq: %d > NewSeq: %d\n", __func__, - preorder_ctrl->indicate_seq, seq_num); - #endif - - return false; } @@ -1983,12 +1667,7 @@ int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d SN_EQUAL IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, seq_num); - #endif } else if (SN_LESS(wend, seq_num)) { - /* RT_TRACE(COMP_RX_REORDER, DBG_LOUD, ("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, NewSeqNum)); */ /* DbgPrint("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ /* boundary situation, when seq_num cross 0xFFF */ @@ -1997,10 +1676,6 @@ int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) else preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; pdbgpriv->dbg_rx_ampdu_window_shift_cnt++; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d SN_LESS(wend, seq_num) IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, seq_num); - #endif } /* DbgPrint("exit->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ @@ -2008,8 +1683,7 @@ int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) return true; } -int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe); -int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe) +static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe) { struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; @@ -2034,7 +1708,6 @@ int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union rec plist = get_next(plist); else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) /* Duplicate entry is found!! Do not insert current entry. */ - /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ return false; else @@ -2055,14 +1728,11 @@ int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union rec /* spin_unlock(&ppending_recvframe_queue->lock); */ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ - - /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */ return true; } -void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq); -void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq) +static void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq) { if (current_seq < prev_seq) pdbgpriv->dbg_rx_ampdu_loss_count += (4096 + current_seq - prev_seq); @@ -2070,8 +1740,8 @@ void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u pdbgpriv->dbg_rx_ampdu_loss_count += (current_seq - prev_seq); } -int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced); -int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) + +static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) { struct list_head *phead, *plist; union recv_frame *prframe; @@ -2083,8 +1753,6 @@ int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctr struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_in_oder); - /* DbgPrint("+recv_indicatepkts_in_order\n"); */ /* spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); */ @@ -2105,10 +1773,6 @@ int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctr prframe = (union recv_frame *)plist; pattrib = &prframe->u.hdr.attrib; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, pattrib->seq_num); - #endif recv_indicatepkts_pkt_loss_cnt(pdbgpriv, preorder_ctrl->indicate_seq, pattrib->seq_num); preorder_ctrl->indicate_seq = pattrib->seq_num; @@ -2122,20 +1786,11 @@ int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctr pattrib = &prframe->u.hdr.attrib; if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, - ("recv_indicatepkts_in_order: indicate =%d seq =%d amsdu =%d\n", - preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); - plist = get_next(plist); list_del_init(&(prframe->u.hdr.list)); - if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) { + if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, pattrib->seq_num); - #endif - } /* Set this as a lock to make sure that only one thread is indicating packet. */ /* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */ @@ -2147,8 +1802,6 @@ int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctr /* indicate this recv_frame */ /* DbgPrint("recv_indicatepkts_in_order, indicate_seq =%d, seq_num =%d\n", precvpriv->indicate_seq, pattrib->seq_num); */ if (!pattrib->amsdu) { - /* DBG_871X("recv_indicatepkts_in_order, amsdu!= 1, indicate_seq =%d, seq_num =%d\n", preorder_ctrl->indicate_seq, pattrib->seq_num); */ - if ((padapter->bDriverStopped == false) && (padapter->bSurpriseRemoved == false)) rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */ @@ -2180,8 +1833,7 @@ int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctr return bPktInBuf; } -int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe); -int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe) +static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe) { int retval = _SUCCESS; struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; @@ -2190,8 +1842,6 @@ int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_reoder); - if (!pattrib->amsdu) { /* s1. */ wlanhdr_to_ethhdr(prframe); @@ -2199,17 +1849,11 @@ int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe if (pattrib->qos != 1) { if ((padapter->bDriverStopped == false) && (padapter->bSurpriseRemoved == false)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n")); - rtw_recv_indicatepkt(padapter, prframe); return _SUCCESS; } - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s pattrib->qos != 1\n", __func__); - #endif - return _FAIL; } @@ -2217,41 +1861,22 @@ int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe if (preorder_ctrl->enable == false) { /* indicate this recv_frame */ preorder_ctrl->indicate_seq = pattrib->seq_num; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, pattrib->seq_num); - #endif rtw_recv_indicatepkt(padapter, prframe); preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, pattrib->seq_num); - #endif return _SUCCESS; } } else if (pattrib->amsdu == 1) { /* temp filter -> means didn't support A-MSDUs in a A-MPDU */ if (preorder_ctrl->enable == false) { preorder_ctrl->indicate_seq = pattrib->seq_num; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, pattrib->seq_num); - #endif retval = amsdu_to_msdu(padapter, prframe); preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, pattrib->seq_num); - #endif if (retval != _SUCCESS) { - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s amsdu_to_msdu fail\n", __func__); - #endif } return retval; @@ -2260,16 +1885,9 @@ int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe spin_lock_bh(&ppending_recvframe_queue->lock); - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, - ("recv_indicatepkt_reorder: indicate =%d seq =%d\n", - preorder_ctrl->indicate_seq, pattrib->seq_num)); - /* s2. check if winstart_b(indicate_seq) needs to been updated */ if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) { pdbgpriv->dbg_rx_ampdu_drop_count++; - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s check_indicate_seq fail\n", __func__); - #endif goto _err_exit; } @@ -2279,9 +1897,6 @@ int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe /* DbgPrint("recv_indicatepkt_reorder, enqueue_reorder_recvframe fail!\n"); */ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ /* return _FAIL; */ - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s enqueue_reorder_recvframe fail\n", __func__); - #endif goto _err_exit; } @@ -2325,8 +1940,6 @@ void rtw_reordering_ctrl_timeout_handler(struct timer_list *t) if (padapter->bDriverStopped || padapter->bSurpriseRemoved) return; - /* DBG_871X("+rtw_reordering_ctrl_timeout_handler() =>\n"); */ - spin_lock_bh(&ppending_recvframe_queue->lock); if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true) @@ -2336,8 +1949,7 @@ void rtw_reordering_ctrl_timeout_handler(struct timer_list *t) } -int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe); -int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe) +static int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe) { int retval = _SUCCESS; /* struct recv_priv *precvpriv = &padapter->recvpriv; */ @@ -2345,15 +1957,10 @@ int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prfram struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct ht_priv *phtpriv = &pmlmepriv->htpriv; - DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate); - if (phtpriv->ht_option == true) { /* B/G/N Mode */ /* prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { /* including perform A-MPDU Rx Ordering Buffer Control */ - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s recv_indicatepkt_reorder error!\n", __func__); - #endif if ((padapter->bDriverStopped == false) && (padapter->bSurpriseRemoved == false)) { @@ -2363,24 +1970,13 @@ int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prfram } } else { /* B/G mode */ retval = wlanhdr_to_ethhdr(prframe); - if (retval != _SUCCESS) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr error!\n", __func__); - #endif + if (retval != _SUCCESS) return retval; - } if ((padapter->bDriverStopped == false) && (padapter->bSurpriseRemoved == false)) { /* indicate this recv_frame */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n")); rtw_recv_indicatepkt(padapter, prframe); - - } else { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n")); - - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); retval = _FAIL; return retval; } @@ -2396,12 +1992,9 @@ static int recv_func_prehandle(struct adapter *padapter, union recv_frame *rfram int ret = _SUCCESS; struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; - DBG_COUNTER(padapter->rx_logs.core_rx_pre); - /* check the frame crtl field and decache */ ret = validate_recv_frame(padapter, rframe); if (ret != _SUCCESS) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ goto exit; } @@ -2417,37 +2010,19 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr struct recv_priv *precvpriv = &padapter->recvpriv; struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; - DBG_COUNTER(padapter->rx_logs.core_rx_post); - prframe = decryptor(padapter, prframe); if (!prframe) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s decryptor: drop pkt\n", __func__); - #endif ret = _FAIL; - DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_err); goto _recv_data_drop; } prframe = recvframe_chk_defrag(padapter, prframe); - if (!prframe) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s recvframe_chk_defrag: drop pkt\n", __func__); - #endif - DBG_COUNTER(padapter->rx_logs.core_rx_post_defrag_err); + if (!prframe) goto _recv_data_drop; - } prframe = portctrl(padapter, prframe); if (!prframe) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s portctrl: drop pkt\n", __func__); - #endif ret = _FAIL; - DBG_COUNTER(padapter->rx_logs.core_rx_post_portctrl_err); goto _recv_data_drop; } @@ -2455,12 +2030,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr ret = process_recv_indicatepkts(padapter, prframe); if (ret != _SUCCESS) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n")); - #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s process_recv_indicatepkts fail!\n", __func__); - #endif rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ - DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_err); goto _recv_data_drop; } @@ -2469,9 +2039,7 @@ _recv_data_drop: return ret; } - -int recv_func(struct adapter *padapter, union recv_frame *rframe); -int recv_func(struct adapter *padapter, union recv_frame *rframe) +static int recv_func(struct adapter *padapter, union recv_frame *rframe) { int ret; struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib; @@ -2486,16 +2054,10 @@ int recv_func(struct adapter *padapter, union recv_frame *rframe) while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) { cnt++; - DBG_COUNTER(padapter->rx_logs.core_rx_dequeue); recv_func_posthandle(padapter, pending_frame); } - - if (cnt) - DBG_871X(FUNC_ADPT_FMT" dequeue %d from uc_swdec_pending_queue\n", - FUNC_ADPT_ARG(padapter), cnt); } - DBG_COUNTER(padapter->rx_logs.core_rx); ret = recv_func_prehandle(padapter, rframe); if (ret == _SUCCESS) { @@ -2506,9 +2068,7 @@ int recv_func(struct adapter *padapter, union recv_frame *rframe) (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt == true) && psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && !psecuritypriv->busetkipkey) { - DBG_COUNTER(padapter->rx_logs.core_rx_enqueue); rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); - /* DBG_871X("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); */ if (recvpriv->free_recvframe_cnt < NR_RECVFRAME/4) { /* to prevent from recvframe starvation, get recvframe from uc_swdec_pending_queue to free_recvframe_cnt */ @@ -2534,15 +2094,12 @@ s32 rtw_recv_entry(union recv_frame *precvframe) struct recv_priv *precvpriv; s32 ret = _SUCCESS; - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+rtw_recv_entry\n")); */ - padapter = precvframe->u.hdr.adapter; precvpriv = &padapter->recvpriv; ret = recv_func(padapter, precvframe); if (ret == _FAIL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n")); goto _recv_entry_drop; } @@ -2553,8 +2110,6 @@ s32 rtw_recv_entry(union recv_frame *precvframe) _recv_entry_drop: - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("_recv_entry_drop\n")); */ - return ret; } @@ -2625,20 +2180,6 @@ static void rtw_signal_stat_timer_hdl(struct timer_list *t) recvpriv->signal_strength = tmp_s; recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); recvpriv->signal_qual = tmp_q; - - #if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 - DBG_871X(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" - ", num_signal_strength:%u, num_signal_qual:%u" - ", on_cur_ch_ms:%d" - "\n" - , FUNC_ADPT_ARG(adapter) - , recvpriv->signal_strength - , recvpriv->rssi - , recvpriv->signal_qual - , num_signal_strength, num_signal_qual - , rtw_get_on_cur_ch_time(adapter) ? jiffies_to_msecs(jiffies - rtw_get_on_cur_ch_time(adapter)) : 0 - ); - #endif } set_timer: diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index a311595deafb90248ea664257f0147c0e9b91158..7823055ed32d7bb7fee25ae1fd88c9dc6e402140 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -29,63 +29,6 @@ const char *security_type_str(u8 value) return NULL; } -#ifdef DBG_SW_SEC_CNT -#define WEP_SW_ENC_CNT_INC(sec, ra) \ - if (is_broadcast_mac_addr(ra)) \ - sec->wep_sw_enc_cnt_bc++; \ - else if (is_multicast_mac_addr(ra)) \ - sec->wep_sw_enc_cnt_mc++; \ - else \ - sec->wep_sw_enc_cnt_uc++; - -#define WEP_SW_DEC_CNT_INC(sec, ra) \ - if (is_broadcast_mac_addr(ra)) \ - sec->wep_sw_dec_cnt_bc++; \ - else if (is_multicast_mac_addr(ra)) \ - sec->wep_sw_dec_cnt_mc++; \ - else \ - sec->wep_sw_dec_cnt_uc++; - -#define TKIP_SW_ENC_CNT_INC(sec, ra) \ - if (is_broadcast_mac_addr(ra)) \ - sec->tkip_sw_enc_cnt_bc++; \ - else if (is_multicast_mac_addr(ra)) \ - sec->tkip_sw_enc_cnt_mc++; \ - else \ - sec->tkip_sw_enc_cnt_uc++; - -#define TKIP_SW_DEC_CNT_INC(sec, ra) \ - if (is_broadcast_mac_addr(ra)) \ - sec->tkip_sw_dec_cnt_bc++; \ - else if (is_multicast_mac_addr(ra)) \ - sec->tkip_sw_dec_cnt_mc++; \ - else \ - sec->tkip_sw_dec_cnt_uc++; - -#define AES_SW_ENC_CNT_INC(sec, ra) \ - if (is_broadcast_mac_addr(ra)) \ - sec->aes_sw_enc_cnt_bc++; \ - else if (is_multicast_mac_addr(ra)) \ - sec->aes_sw_enc_cnt_mc++; \ - else \ - sec->aes_sw_enc_cnt_uc++; - -#define AES_SW_DEC_CNT_INC(sec, ra) \ - if (is_broadcast_mac_addr(ra)) \ - sec->aes_sw_dec_cnt_bc++; \ - else if (is_multicast_mac_addr(ra)) \ - sec->aes_sw_dec_cnt_mc++; \ - else \ - sec->aes_sw_dec_cnt_uc++; -#else -#define WEP_SW_ENC_CNT_INC(sec, ra) -#define WEP_SW_DEC_CNT_INC(sec, ra) -#define TKIP_SW_ENC_CNT_INC(sec, ra) -#define TKIP_SW_DEC_CNT_INC(sec, ra) -#define AES_SW_ENC_CNT_INC(sec, ra) -#define AES_SW_DEC_CNT_INC(sec, ra) -#endif /* DBG_SW_SEC_CNT */ - /* WEP related ===== */ struct arc4context { @@ -148,7 +91,7 @@ static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); } -static sint bcrc32initialized; +static signed int bcrc32initialized; static u32 crc32_table[256]; @@ -162,7 +105,7 @@ static void crc32_init(void) if (bcrc32initialized == 1) return; else { - sint i, j; + signed int i, j; u32 c; u8 *p = (u8 *)&c, *p1; u8 k; @@ -184,7 +127,7 @@ static void crc32_init(void) } } -static __le32 getcrc32(u8 *buf, sint len) +static __le32 getcrc32(u8 *buf, signed int len) { u8 *p; u32 crc; @@ -209,7 +152,7 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) unsigned char crc[4]; struct arc4context mycontext; - sint curfragnum, length; + signed int curfragnum, length; u32 keylength; u8 *pframe, *payload, *iv; /* wepkey */ @@ -256,8 +199,6 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4); } } - - WEP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); } } @@ -266,7 +207,7 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) /* exclude ICV */ u8 crc[4]; struct arc4context mycontext; - sint length; + signed int length; u32 keylength; u8 *pframe, *payload, *iv, wepkey[16]; u8 keyindex; @@ -295,18 +236,6 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) /* calculate icv and compare the icv */ *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4)); - if (crc[3] != payload[length-1] || crc[2] != payload[length-2] || crc[1] != payload[length-3] || crc[0] != payload[length-4]) { - RT_TRACE(_module_rtl871x_security_c_, - _drv_err_, - ("%s:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", - __func__, - crc[3], payload[length - 1], - crc[2], payload[length - 2], - crc[1], payload[length - 3], - crc[0], payload[length - 4])); - } - - WEP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); } } @@ -319,7 +248,7 @@ static u32 secmicgetuint32(u8 *p) u32 res = 0; for (i = 0; i < 4; i++) - res |= ((u32)(*p++)) << (8*i); + res |= ((u32)(*p++)) << (8 * i); return res; } @@ -397,7 +326,7 @@ void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst) rtw_secmicappendbyte(pmicdata, 0); /* The appendByte function has already computed the result. */ secmicputuint32(dst, pmicdata->L); - secmicputuint32(dst+4, pmicdata->R); + secmicputuint32(dst + 4, pmicdata->R); /* Reset to the empty message. */ secmicclear(pmicdata); } @@ -413,15 +342,15 @@ void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_cod priority[0] = pri; /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ - if (header[1]&1) { /* ToDS == 1 */ + if (header[1] & 1) { /* ToDS == 1 */ rtw_secmicappend(&micdata, &header[16], 6); /* DA */ - if (header[1]&2) /* From Ds == 1 */ + if (header[1] & 2) /* From Ds == 1 */ rtw_secmicappend(&micdata, &header[24], 6); else rtw_secmicappend(&micdata, &header[10], 6); } else { /* ToDS == 0 */ rtw_secmicappend(&micdata, &header[4], 6); /* DA */ - if (header[1]&2) /* From Ds == 1 */ + if (header[1] & 2) /* From Ds == 1 */ rtw_secmicappend(&micdata, &header[16], 6); else rtw_secmicappend(&micdata, &header[10], 6); @@ -549,7 +478,7 @@ static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in R */ static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) { - sint i; + signed int i; /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ p1k[0] = Lo16(iv32); @@ -597,7 +526,7 @@ static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) */ static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) { - sint i; + signed int i; u16 PPK[6]; /* temporary key for mixing */ /* Note: all adds in the PPK[] equations below are mod 2**16 */ @@ -651,7 +580,7 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) u8 crc[4]; u8 hw_hdr_offset = 0; struct arc4context mycontext; - sint curfragnum, length; + signed int curfragnum, length; u8 *pframe, *payload, *iv, *prwskey; union pn48 dot11txpn; @@ -670,8 +599,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) if (pattrib->encrypt == _TKIP_) { { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); - if (IS_MCAST(pattrib->ra)) prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; else @@ -692,7 +619,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len; - RT_TRACE(_module_rtl871x_security_c_, _drv_info_, ("pattrib->iv_len =%x, pattrib->icv_len =%x\n", pattrib->iv_len, pattrib->icv_len)); *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/ arcfour_init(&mycontext, rc4key, 16); @@ -710,8 +636,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4); } } - - TKIP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); } } return res; @@ -727,7 +651,7 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) u8 ttkey[16]; u8 crc[4]; struct arc4context mycontext; - sint length; + signed int length; u8 *pframe, *payload, *iv, *prwskey; union pn48 dot11txpn; @@ -760,8 +684,11 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) if (jiffies_to_msecs(jiffies - start) > 1000) { if (no_gkey_bc_cnt || no_gkey_mc_cnt) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", - FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), + no_gkey_bc_cnt, + no_gkey_mc_cnt); } start = jiffies; no_gkey_bc_cnt = 0; @@ -771,8 +698,11 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) } if (no_gkey_bc_cnt || no_gkey_mc_cnt) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", - FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), + no_gkey_bc_cnt, + no_gkey_mc_cnt); } start = 0; no_gkey_bc_cnt = 0; @@ -802,20 +732,10 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4)); - if (crc[3] != payload[length-1] || crc[2] != payload[length-2] || crc[1] != payload[length-3] || crc[0] != payload[length-4]) { - RT_TRACE(_module_rtl871x_security_c_, - _drv_err_, - ("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", - crc[3], payload[length - 1], - crc[2], payload[length - 2], - crc[1], payload[length - 3], - crc[0], payload[length - 4])); + if (crc[3] != payload[length - 1] || crc[2] != payload[length - 2] || + crc[1] != payload[length - 3] || crc[0] != payload[length - 4]) res = _FAIL; - } - - TKIP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); } else { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo == NULL!!!\n", __func__)); res = _FAIL; } } @@ -874,31 +794,31 @@ exit: static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); static void construct_mic_iv(u8 *mic_header1, - sint qc_exists, - sint a4_exists, + signed int qc_exists, + signed int a4_exists, u8 *mpdu, uint payload_length, u8 *pn_vector, uint frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ static void construct_mic_header1(u8 *mic_header1, - sint header_length, + signed int header_length, u8 *mpdu, uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */ static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, - sint a4_exists, - sint qc_exists); + signed int a4_exists, + signed int qc_exists); static void construct_ctr_preload(u8 *ctr_preload, - sint a4_exists, - sint qc_exists, + signed int a4_exists, + signed int qc_exists, u8 *mpdu, u8 *pn_vector, - sint c, + signed int c, uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */ static void xor_128(u8 *a, u8 *b, u8 *out); static void xor_32(u8 *a, u8 *b, u8 *out); static u8 sbox(u8 a); -static void next_key(u8 *key, sint round); +static void next_key(u8 *key, signed int round); static void byte_sub(u8 *in, u8 *out); static void shift_row(u8 *in, u8 *out); static void mix_column(u8 *in, u8 *out); @@ -912,7 +832,7 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); /****************************************/ static void xor_128(u8 *a, u8 *b, u8 *out) { - sint i; + signed int i; for (i = 0; i < 16; i++) out[i] = a[i] ^ b[i]; @@ -921,7 +841,7 @@ static void xor_128(u8 *a, u8 *b, u8 *out) static void xor_32(u8 *a, u8 *b, u8 *out) { - sint i; + signed int i; for (i = 0; i < 4; i++) out[i] = a[i] ^ b[i]; @@ -930,11 +850,11 @@ static void xor_32(u8 *a, u8 *b, u8 *out) static u8 sbox(u8 a) { - return sbox_table[(sint)a]; + return sbox_table[(signed int)a]; } -static void next_key(u8 *key, sint round) +static void next_key(u8 *key, signed int round) { u8 rcon; u8 sbox_key[4]; @@ -961,7 +881,7 @@ static void next_key(u8 *key, sint round) static void byte_sub(u8 *in, u8 *out) { - sint i; + signed int i; for (i = 0; i < 16; i++) out[i] = sbox(in[i]); @@ -990,7 +910,7 @@ static void shift_row(u8 *in, u8 *out) static void mix_column(u8 *in, u8 *out) { - sint i; + signed int i; u8 add1b[4]; u8 add1bf7[4]; u8 rotl[4]; @@ -1047,8 +967,8 @@ static void mix_column(u8 *in, u8 *out) static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) { - sint round; - sint i; + signed int round; + signed int i; u8 intermediatea[16]; u8 intermediateb[16]; u8 round_key[16]; @@ -1084,14 +1004,14 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) /* nonce */ /************************************************/ static void construct_mic_iv(u8 *mic_iv, - sint qc_exists, - sint a4_exists, + signed int qc_exists, + signed int a4_exists, u8 *mpdu, uint payload_length, u8 *pn_vector, uint frtype) /* add for CONFIG_IEEE80211W, none 11w also can use */ { - sint i; + signed int i; mic_iv[0] = 0x59; @@ -1128,7 +1048,7 @@ static void construct_mic_iv(u8 *mic_iv, /* Build AAD SC, A1, A2 */ /************************************************/ static void construct_mic_header1(u8 *mic_header1, - sint header_length, + signed int header_length, u8 *mpdu, uint frtype) /* for CONFIG_IEEE80211W, none 11w also can use */ { @@ -1163,10 +1083,10 @@ static void construct_mic_header1(u8 *mic_header1, /************************************************/ static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, - sint a4_exists, - sint qc_exists) + signed int a4_exists, + signed int qc_exists) { - sint i; + signed int i; for (i = 0; i < 16; i++) mic_header2[i] = 0x00; @@ -1208,14 +1128,14 @@ static void construct_mic_header2(u8 *mic_header2, /* nonce */ /************************************************/ static void construct_ctr_preload(u8 *ctr_preload, - sint a4_exists, - sint qc_exists, + signed int a4_exists, + signed int qc_exists, u8 *mpdu, u8 *pn_vector, - sint c, + signed int c, uint frtype) /* for CONFIG_IEEE80211W, none 11w also can use */ { - sint i = 0; + signed int i = 0; for (i = 0; i < 16; i++) ctr_preload[i] = 0x00; @@ -1250,13 +1170,13 @@ static void construct_ctr_preload(u8 *ctr_preload, /************************************/ static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) { - sint i; + signed int i; for (i = 0; i < 16; i++) out[i] = ina[i] ^ inb[i]; } -static sint aes_cipher(u8 *key, uint hdrlen, +static signed int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) { uint qc_exists, a4_exists, i, j, payload_remainder, @@ -1428,7 +1348,7 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) /* unsigned char message[MAX_MSG_SIZE]; */ /* Intermediate Buffers */ - sint curfragnum, length; + signed int curfragnum, length; u8 *pframe, *prwskey; /* *payload,*iv */ u8 hw_hdr_offset = 0; struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; @@ -1445,8 +1365,6 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) /* 4 start to encrypt each fragment */ if (pattrib->encrypt == _AES_) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); - if (IS_MCAST(pattrib->ra)) prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; else @@ -1465,19 +1383,17 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4); } } - - AES_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); } return res; } -static sint aes_decipher(u8 *key, uint hdrlen, +static signed int 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, num_blocks, payload_index; - sint res = _SUCCESS; + signed int res = _SUCCESS; u8 pn_vector[6]; u8 mic_iv[16]; u8 mic_header1[16]; @@ -1677,21 +1593,8 @@ static sint aes_decipher(u8 *key, uint hdrlen, /* compare the mic */ for (i = 0; i < 8; i++) { - if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) { - RT_TRACE(_module_rtl871x_security_c_, - _drv_err_, - ("%s:mic check error mic[%d]: pframe(%x) != message(%x)\n", - __func__, - i, - pframe[hdrlen + 8 + plen - 8 + i], - message[hdrlen + 8 + plen - 8 + i])); - DBG_871X("%s:mic check error mic[%d]: pframe(%x) != message(%x)\n", - __func__, - i, - pframe[hdrlen + 8 + plen - 8 + i], - message[hdrlen + 8 + plen - 8 + i]); + if (pframe[hdrlen + 8 + plen - 8 + i] != message[hdrlen + 8 + plen - 8 + i]) res = _FAIL; - } } return res; } @@ -1704,7 +1607,7 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) /* Intermediate Buffers */ - sint length; + signed int length; u8 *pframe, *prwskey; /* *payload,*iv */ struct sta_info *stainfo; struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; @@ -1716,10 +1619,6 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) if (prxattrib->encrypt == _AES_) { stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); if (stainfo) { - RT_TRACE(_module_rtl871x_security_c_, - _drv_err_, - ("%s: stainfo!= NULL!!!\n", __func__)); - if (IS_MCAST(prxattrib->ra)) { static unsigned long start; static u32 no_gkey_bc_cnt; @@ -1738,8 +1637,11 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) if (jiffies_to_msecs(jiffies - start) > 1000) { if (no_gkey_bc_cnt || no_gkey_mc_cnt) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", - FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), + no_gkey_bc_cnt, + no_gkey_mc_cnt); } start = jiffies; no_gkey_bc_cnt = 0; @@ -1750,8 +1652,11 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) } if (no_gkey_bc_cnt || no_gkey_mc_cnt) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", - FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), + no_gkey_bc_cnt, + no_gkey_mc_cnt); } start = 0; no_gkey_bc_cnt = 0; @@ -1759,8 +1664,6 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { - DBG_871X("not match packet_index =%d, install_index =%d\n" - , prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); res = _FAIL; goto exit; } @@ -1772,11 +1675,7 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); - AES_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); } else { - RT_TRACE(_module_rtl871x_security_c_, - _drv_err_, - ("%s: stainfo == NULL!!!\n", __func__)); res = _FAIL; } } @@ -1800,10 +1699,9 @@ u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe) ori_len = pattrib->pkt_len-WLAN_HDR_A3_LEN+BIP_AAD_SIZE; BIP_AAD = rtw_zmalloc(ori_len); - if (BIP_AAD == NULL) { - DBG_871X("BIP AAD allocate fail\n"); + if (!BIP_AAD) return _FAIL; - } + /* PKT start */ pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; /* mapping to wlan header */ @@ -1820,17 +1718,15 @@ u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe) memcpy(&le_tmp64, p+4, 6); temp_ipn = le64_to_cpu(le_tmp64); /* BIP packet number should bigger than previous BIP packet */ - if (temp_ipn <= pmlmeext->mgnt_80211w_IPN_rx) { - DBG_871X("replay BIP packet\n"); + if (temp_ipn <= pmlmeext->mgnt_80211w_IPN_rx) goto BIP_exit; - } + /* copy key index */ memcpy(&le_tmp, p+2, 2); keyid = le16_to_cpu(le_tmp); - if (keyid != padapter->securitypriv.dot11wBIPKeyid) { - DBG_871X("BIP key index error!\n"); + if (keyid != padapter->securitypriv.dot11wBIPKeyid) goto BIP_exit; - } + /* clear the MIC field of MME to zero */ memset(p+2+len-8, 0, 8); @@ -1851,7 +1747,6 @@ u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe) pmlmeext->mgnt_80211w_IPN_rx = temp_ipn; res = _SUCCESS; } else { - DBG_871X("BIP MIC error!\n"); } } else { @@ -2080,10 +1975,12 @@ static void rijndaelEncrypt(u32 rk[/*44*/], u8 pt[16], u8 ct[16]) s3 = GETU32(pt + 12) ^ rk[3]; #define ROUND(i, d, s) \ -d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ -d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ -d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ -d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] + do { \ + d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ + d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ + d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ + d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \ + } while (0) /* Nr - 1 full rounds: */ r = Nr >> 1; @@ -2241,7 +2138,7 @@ int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac) void rtw_sec_restore_wep_key(struct adapter *adapter) { struct security_priv *securitypriv = &(adapter->securitypriv); - sint keyid; + signed int keyid; if ((_WEP40_ == securitypriv->dot11PrivacyAlgrthm) || (_WEP104_ == securitypriv->dot11PrivacyAlgrthm)) { for (keyid = 0; keyid < 4; keyid++) { @@ -2264,13 +2161,17 @@ u8 rtw_handle_tkip_countermeasure(struct adapter *adapter, const char *caller) unsigned long passing_ms = jiffies_to_msecs(jiffies - securitypriv->btkip_countermeasure_time); if (passing_ms > 60*1000) { - DBG_871X_LEVEL(_drv_always_, "%s(%s) countermeasure time:%lus > 60s\n", - caller, ADPT_ARG(adapter), passing_ms/1000); + netdev_dbg(adapter->pnetdev, + "%s(%s) countermeasure time:%lus > 60s\n", + caller, ADPT_ARG(adapter), + passing_ms / 1000); securitypriv->btkip_countermeasure = false; securitypriv->btkip_countermeasure_time = 0; } else { - DBG_871X_LEVEL(_drv_always_, "%s(%s) countermeasure time:%lus < 60s\n", - caller, ADPT_ARG(adapter), passing_ms/1000); + netdev_dbg(adapter->pnetdev, + "%s(%s) countermeasure time:%lus < 60s\n", + caller, ADPT_ARG(adapter), + passing_ms / 1000); status = _FAIL; } } diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index f96dd0b40e04c1c5f796566411fc853be57c1926..85663182b388a8293b315a1195f6add70d297f86 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -106,17 +106,11 @@ inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) { int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info); - if (!stainfo_offset_valid(offset)) - DBG_871X("%s invalid offset(%d), out of range!!!", __func__, offset); - return offset; } inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) { - if (!stainfo_offset_valid(offset)) - DBG_871X("%s invalid offset(%d), out of range!!!", __func__, offset); - return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); } @@ -216,10 +210,7 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) index = wifi_mac_hash(hwaddr); - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index = %x", index)); - if (index >= NUM_STA) { - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA")); spin_unlock_bh(&(pstapriv->sta_hash_lock)); psta = NULL; goto exit; @@ -242,17 +233,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) for (i = 0; i < 16; i++) memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, - ("alloc number_%d stainfo with hwaddr = %x %x %x %x %x %x \n", - pstapriv->asoc_sta_count, - hwaddr[0], - hwaddr[1], - hwaddr[2], - hwaddr[3], - hwaddr[4], - hwaddr[5]) - ); - init_addba_retry_timer(pstapriv->padapter, psta); /* for A-MPDU Rx reordering buffer control */ @@ -264,10 +244,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq); - #endif preorder_ctrl->wend_b = 0xffff; /* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */ preorder_ctrl->wsize_b = 64;/* 64; */ @@ -363,16 +339,6 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) spin_unlock_bh(&pxmitpriv->lock); list_del_init(&psta->hash_list); - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, - ("\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", - pstapriv->asoc_sta_count, - psta->hwaddr[0], - psta->hwaddr[1], - psta->hwaddr[2], - psta->hwaddr[3], - psta->hwaddr[4], - psta->hwaddr[5]) - ); pstapriv->asoc_sta_count--; /* re-init sta_info; 20061114 will be init in alloc_stainfo */ @@ -543,7 +509,6 @@ u32 rtw_init_bcmc_stainfo(struct adapter *padapter) if (!psta) { res = _FAIL; - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("rtw_alloc_stainfo fail")); goto exit; } diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index 975f2830e29eb9025db91590ed5f73c5f9ee062e..f9bd7c167da7332d37dff665af520c53046597c2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -10,10 +10,6 @@ #include <rtw_debug.h> #include <hal_com_h2c.h> -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -#include <linux/inetdevice.h> -#endif - static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; @@ -29,9 +25,6 @@ static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; static unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; static unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; -extern unsigned char RTW_WPA_OUI[]; -extern unsigned char WPA_TKIP_CIPHER[4]; - #define R2T_PHY_DELAY (0) /* define WAIT_FOR_BCN_TO_MIN (3000) */ @@ -319,7 +312,6 @@ inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) cnt += scnprintf(msg+cnt, len-cnt, "]"); } - DBG_871X(FUNC_ADPT_FMT" %s\n", FUNC_ADPT_ARG(adapter), msg); #endif /* DBG_CH_SWITCH */ } @@ -387,9 +379,6 @@ void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigne { u8 center_ch, chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; - if (padapter->bNotifyChannelChange) - DBG_871X("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode); - center_ch = rtw_get_center_ch(channel, bwmode, channel_offset); if (bwmode == CHANNEL_WIDTH_80) { @@ -515,14 +504,11 @@ void read_cam(struct adapter *padapter, u8 entry, u8 *get_key) addr = entry << 3; - /* DBG_8192C("********* DUMP CAM Entry_#%02d***************\n", entry); */ for (j = 0; j < 6; j++) { cmd = _ReadCAM(padapter, addr+j); - /* DBG_8192C("offset:0x%02x => 0x%08x\n", addr+j, cmd); */ if (j > 1) /* get key from cam */ memcpy(get_key+(j-2)*4, &cmd, 4); } - /* DBG_8192C("*********************************\n"); */ } void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) @@ -634,13 +620,6 @@ static s16 _rtw_camid_search(struct adapter *adapter, u8 *addr, s16 kid) break; } - if (addr) - DBG_871X(FUNC_ADPT_FMT" addr:%pM kid:%d, return cam_id:%d\n" - , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), kid, cam_id); - else - DBG_871X(FUNC_ADPT_FMT" addr:%p kid:%d, return cam_id:%d\n" - , FUNC_ADPT_ARG(adapter), addr, kid, cam_id); - return cam_id; } @@ -672,8 +651,9 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) && !sta) { /* AP/Ad-hoc mode group key: static alloction to default key by key ID */ if (kid > 3) { - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key with invalid key id:%u\n" - , FUNC_ADPT_ARG(adapter), kid); + netdev_dbg(adapter->pnetdev, + FUNC_ADPT_FMT " group key with invalid key id:%u\n", + FUNC_ADPT_ARG(adapter), kid); rtw_warn_on(1); goto bitmap_handle; } @@ -698,8 +678,9 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) if (sta || _rtw_camid_is_gk(adapter, i)) cam_id = i; else - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u the same key id as pairwise key\n" - , FUNC_ADPT_ARG(adapter), kid); + netdev_dbg(adapter->pnetdev, + FUNC_ADPT_FMT " group key id:%u the same key id as pairwise key\n", + FUNC_ADPT_ARG(adapter), kid); goto bitmap_handle; } @@ -709,11 +690,14 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) if (i == TOTAL_CAM_ENTRY) { if (sta) - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pairwise key with %pM id:%u no room\n" - , FUNC_ADPT_ARG(adapter), MAC_ARG(sta->hwaddr), kid); + netdev_dbg(adapter->pnetdev, + FUNC_ADPT_FMT " pairwise key with %pM id:%u no room\n", + FUNC_ADPT_ARG(adapter), + MAC_ARG(sta->hwaddr), kid); else - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u no room\n" - , FUNC_ADPT_ARG(adapter), kid); + netdev_dbg(adapter->pnetdev, + FUNC_ADPT_FMT " group key id:%u no room\n", + FUNC_ADPT_ARG(adapter), kid); rtw_warn_on(1); goto bitmap_handle; } @@ -880,8 +864,6 @@ void WMMOnAssocRsp(struct adapter *padapter) edca[XMIT_VO_QUEUE] = acParm; break; } - - DBG_871X("WMM(%x): %x, %x\n", ACI, ACM, acParm); } if (padapter->registrypriv.acm_method == 1) @@ -921,10 +903,8 @@ void WMMOnAssocRsp(struct adapter *padapter) } } - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) pxmitpriv->wmm_para_seq[i] = inx[i]; - DBG_871X("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); - } } } @@ -1075,36 +1055,29 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE) break; case RF_2T2R: default: -#ifdef CONFIG_DISABLE_MCS13TO15 - if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1) - set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF); - else - set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); -#else /* CONFIG_DISABLE_MCS13TO15 */ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); -#endif /* CONFIG_DISABLE_MCS13TO15 */ } if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* Config STBC setting */ - if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAPABILITY_ELE_TX_STBC(pIE->data)) { + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && + GET_HT_CAPABILITY_ELE_TX_STBC(pIE->data)) SET_FLAG(cur_stbc_cap, STBC_HT_ENABLE_TX); - DBG_871X("Enable HT Tx STBC !\n"); - } + phtpriv->stbc_cap = cur_stbc_cap; } else { /* Config LDPC Coding Capability */ - if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX) && GET_HT_CAPABILITY_ELE_LDPC_CAP(pIE->data)) { + if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX) && + GET_HT_CAPABILITY_ELE_LDPC_CAP(pIE->data)) SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); - DBG_871X("Enable HT Tx LDPC!\n"); - } + phtpriv->ldpc_cap = cur_ldpc_cap; /* Config STBC setting */ - if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAPABILITY_ELE_RX_STBC(pIE->data)) { + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && + GET_HT_CAPABILITY_ELE_RX_STBC(pIE->data)) SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); - DBG_871X("Enable HT Tx STBC!\n"); - } + phtpriv->stbc_cap = cur_stbc_cap; } } @@ -1137,8 +1110,6 @@ void HTOnAssocRsp(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - DBG_871X("%s\n", __func__); - if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) { pmlmeinfo->HT_enable = 1; } else { @@ -1254,22 +1225,15 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) len = packet_len - sizeof(struct ieee80211_hdr_3addr); - if (len > MAX_IE_SZ) { - DBG_871X("%s IE too long for survey event\n", __func__); + if (len > MAX_IE_SZ) return _FAIL; - } - if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { - DBG_871X("Oops: rtw_check_network_encrypt linked but recv other bssid bcn %pM %pM\n", - MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); + if (memcmp(cur_network->network.MacAddress, pbssid, 6)) return true; - } bssid = rtw_zmalloc(sizeof(struct wlan_bssid_ex)); - if (!bssid) { - DBG_871X("%s rtw_zmalloc fail !!!\n", __func__); + if (!bssid) return true; - } if ((pmlmepriv->timeBcnInfoChkStart != 0) && (jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart) > DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS)) { pmlmepriv->timeBcnInfoChkStart = 0; @@ -1306,11 +1270,6 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) } if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) { - DBG_871X("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, - ht_cap_info, ht_info_infos_0); - DBG_871X("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, - cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); - DBG_871X("%s bw mode change\n", __func__); { /* bcn_info_update */ cur_network->BcnInfo.ht_cap_info = ht_cap_info; @@ -1325,19 +1284,16 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) if (p) { bcn_channel = *(p + 2); } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ - rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, WLAN_EID_HT_OPERATION, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (pht_info) { - bcn_channel = pht_info->primary_channel; - } else { /* we don't find channel IE, so don't check it */ - /* DBG_871X("Oops: %s we don't find channel IE, so don't check it\n", __func__); */ - bcn_channel = Adapter->mlmeextpriv.cur_channel; - } + rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, WLAN_EID_HT_OPERATION, + &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (pht_info) + bcn_channel = pht_info->primary_channel; + else /* we don't find channel IE, so don't check it */ + bcn_channel = Adapter->mlmeextpriv.cur_channel; } - if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { - DBG_871X("%s beacon channel:%d cur channel:%d disconnect\n", __func__, - bcn_channel, Adapter->mlmeextpriv.cur_channel); + + if (bcn_channel != Adapter->mlmeextpriv.cur_channel) goto _mismatch; - } /* checking SSID */ ssid_len = 0; @@ -1350,18 +1306,11 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) memcpy(bssid->Ssid.Ssid, (p + 2), ssid_len); bssid->Ssid.SsidLength = ssid_len; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " - "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid, - bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid, - cur_network->network.Ssid.SsidLength)); - if (memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) || - bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { - if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ - DBG_871X("%s(), SSID is not match\n", __func__); + bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) + if (bssid->Ssid.Ssid[0] != '\0' && + bssid->Ssid.SsidLength != 0) /* not hidden ssid */ goto _mismatch; - } - } /* check encryption info */ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); @@ -1371,63 +1320,41 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) else bssid->Privacy = 0; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n", - __func__, cur_network->network.Privacy, bssid->Privacy)); - if (cur_network->network.Privacy != bssid->Privacy) { - DBG_871X("%s(), privacy is not match\n", __func__); + if (cur_network->network.Privacy != bssid->Privacy) goto _mismatch; - } rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, &wpa_len); - if (rsn_len > 0) { + if (rsn_len > 0) encryp_protocol = ENCRYP_PROTOCOL_WPA2; - } else if (wpa_len > 0) { + else if (wpa_len > 0) encryp_protocol = ENCRYP_PROTOCOL_WPA; - } else { + else if (bssid->Privacy) encryp_protocol = ENCRYP_PROTOCOL_WEP; - } - if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { - DBG_871X("%s(): enctyp is not match\n", __func__); + if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) goto _mismatch; - } if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); if (pbuf && (wpa_ielen > 0)) { - if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__, - pairwise_cipher, group_cipher, is_8021x)); - } + rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, + &pairwise_cipher, &is_8021x); } else { pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); - if (pbuf && (wpa_ielen > 0)) { - if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n", - __func__, pairwise_cipher, group_cipher, is_8021x)); - } - } + if (pbuf && (wpa_ielen > 0)) + rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, + &pairwise_cipher, &is_8021x); } - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher)); - if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { - DBG_871X("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match\n", __func__, - pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, - group_cipher, cur_network->BcnInfo.group_cipher); + if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || + group_cipher != cur_network->BcnInfo.group_cipher) goto _mismatch; - } - if (is_8021x != cur_network->BcnInfo.is_8021x) { - DBG_871X("%s authentication is not match\n", __func__); + if (is_8021x != cur_network->BcnInfo.is_8021x) goto _mismatch; - } } kfree(bssid); @@ -1440,12 +1367,9 @@ _mismatch: pmlmepriv->timeBcnInfoChkStart = jiffies; pmlmepriv->NumOfBcnInfoChkFail++; - DBG_871X("%s by %s - NumOfChkFail = %d (SeqNum of this Beacon frame = %d).\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, GetSequence(pframe)); if ((pmlmepriv->timeBcnInfoChkStart != 0) && (jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart) <= DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS) && (pmlmepriv->NumOfBcnInfoChkFail >= DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD)) { - DBG_871X("%s by %s - NumOfChkFail = %d >= threshold : %d (in %d ms), return FAIL.\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, - DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD, jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart)); pmlmepriv->timeBcnInfoChkStart = 0; pmlmepriv->NumOfBcnInfoChkFail = 0; return _FAIL; @@ -1583,21 +1507,16 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) switch (pIE->ElementID) { case WLAN_EID_VENDOR_SPECIFIC: if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) { - DBG_871X("link to Artheros AP\n"); return HT_IOT_PEER_ATHEROS; } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) || (!memcmp(pIE->data, BROADCOM_OUI2, 3)) || (!memcmp(pIE->data, BROADCOM_OUI3, 3))) { - DBG_871X("link to Broadcom AP\n"); return HT_IOT_PEER_BROADCOM; } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) { - DBG_871X("link to Marvell AP\n"); return HT_IOT_PEER_MARVELL; } else if (!memcmp(pIE->data, RALINK_OUI, 3)) { - DBG_871X("link to Ralink AP\n"); return HT_IOT_PEER_RALINK; } else if (!memcmp(pIE->data, CISCO_OUI, 3)) { - DBG_871X("link to Cisco AP\n"); return HT_IOT_PEER_CISCO; } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) { u32 Vender = HT_IOT_PEER_REALTEK; @@ -1614,21 +1533,16 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) Vender = HT_IOT_PEER_REALTEK_SOFTAP; if (pIE->data[4] == 2) { - if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_BCUT) { + if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_BCUT) Vender = HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP; - DBG_871X("link to Realtek JAGUAR_BCUTAP\n"); - } - if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_CCUT) { + + if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_CCUT) Vender = HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP; - DBG_871X("link to Realtek JAGUAR_CCUTAP\n"); - } } } - DBG_871X("link to Realtek AP\n"); return Vender; } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) { - DBG_871X("link to Airgo Cap\n"); return HT_IOT_PEER_AIRGO; } else { break; @@ -1641,7 +1555,6 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) i += (pIE->Length + 2); } - DBG_871X("link to new AP\n"); return HT_IOT_PEER_UNKNOWN; } @@ -1760,7 +1673,7 @@ void update_wireless_mode(struct adapter *padapter) if (pmlmeext->cur_wireless_mode & WIRELESS_11B) update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); - else + else update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); } @@ -1820,15 +1733,7 @@ void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr) preorder_ctrl = &psta->recvreorder_ctrl[tid]; - #ifdef CONFIG_UPDATE_INDICATE_SEQ_WHILE_PROCESS_ADDBA_REQ - preorder_ctrl->indicate_seq = start_seq; - #ifdef DBG_RX_SEQ - DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, start_seq: %d\n", __func__, __LINE__, - preorder_ctrl->indicate_seq, start_seq); - #endif - #else preorder_ctrl->indicate_seq = 0xffff; - #endif preorder_ctrl->enable = pmlmeinfo->accept_addba_req; } @@ -1872,8 +1777,6 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) tsf = tsf << 32; tsf |= le32_to_cpu(*pbuf); - /* DBG_871X("%s(): tsf_upper = 0x%08x, tsf_lower = 0x%08x\n", __func__, (u32)(tsf>>32), (u32)tsf); */ - /* delay = (timestamp mod 1024*100)/1000 (unit: ms) */ /* delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024))/1000; */ delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024)); @@ -1887,11 +1790,9 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) /* pmlmeext->bcn_delay_ratio[delay_ms] = (pmlmeext->bcn_delay_cnt[delay_ms] * 100) /pmlmeext->bcn_cnt; */ /* - DBG_871X("%s(): (a)bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); for (i = 0; i<9; i++) { - DBG_871X("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, pmlmeext->bcn_delay_cnt[i] , i, pmlmeext->bcn_delay_ratio[i]); } */ @@ -1906,26 +1807,17 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) DrvBcnEarly = 0xff; DrvBcnTimeOut = 0xff; - DBG_871X("%s(): bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); - for (i = 0; i < 9; i++) { pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i] * 100) / pmlmeext->bcn_cnt; - DBG_871X("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, - pmlmeext->bcn_delay_cnt[i], i, pmlmeext->bcn_delay_ratio[i]); - ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; - if (ratio_20_delay > 20 && DrvBcnEarly == 0xff) { + if (ratio_20_delay > 20 && DrvBcnEarly == 0xff) DrvBcnEarly = i; - DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, DrvBcnEarly); - } - if (ratio_80_delay > 80 && DrvBcnTimeOut == 0xff) { + if (ratio_80_delay > 80 && DrvBcnTimeOut == 0xff) DrvBcnTimeOut = i; - DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, DrvBcnTimeOut); - } /* reset adaptive_early_32k cnt */ pmlmeext->bcn_delay_cnt[i] = 0; @@ -1962,13 +1854,10 @@ void rtw_alloc_macid(struct adapter *padapter, struct sta_info *psta) } spin_unlock_bh(&pdvobj->lock); - if (i > (NUM_STA-1)) { + if (i > (NUM_STA - 1)) psta->mac_id = NUM_STA; - DBG_871X(" no room for more MACIDs\n"); - } else { + else psta->mac_id = i; - DBG_871X("%s = %d\n", __func__, psta->mac_id); - } } void rtw_release_macid(struct adapter *padapter, struct sta_info *psta) @@ -1985,7 +1874,6 @@ void rtw_release_macid(struct adapter *padapter, struct sta_info *psta) spin_lock_bh(&pdvobj->lock); if (psta->mac_id < NUM_STA && psta->mac_id != 1) { if (pdvobj->macid[psta->mac_id] == true) { - DBG_871X("%s = %d\n", __func__, psta->mac_id); pdvobj->macid[psta->mac_id] = false; psta->mac_id = NUM_STA; } @@ -2018,182 +1906,3 @@ struct adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj) return dvobj->padapters; } - -#ifdef CONFIG_GPIO_API -int rtw_get_gpio(struct net_device *netdev, int gpio_num) -{ - u8 value; - u8 direction; - struct adapter *adapter = rtw_netdev_priv(netdev); - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); - - rtw_ps_deny(adapter, PS_DENY_IOCTL); - - DBG_871X("rf_pwrstate = 0x%02x\n", pwrpriv->rf_pwrstate); - LeaveAllPowerSaveModeDirect(adapter); - - /* Read GPIO Direction */ - direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; - - /* According the direction to read register value */ - if (direction) - value = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 1) & BIT(gpio_num)) >> gpio_num; - else - value = (rtw_read8(adapter, REG_GPIO_PIN_CTRL) & BIT(gpio_num)) >> gpio_num; - - rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); - DBG_871X("%s direction =%d value =%d\n", __func__, direction, value); - - return value; -} -EXPORT_SYMBOL(rtw_get_gpio); - -int rtw_set_gpio_output_value(struct net_device *netdev, int gpio_num, bool isHigh) -{ - u8 direction = 0; - u8 res = -1; - struct adapter *adapter = rtw_netdev_priv(netdev); - - /* Check GPIO is 4~7 */ - if (gpio_num > 7 || gpio_num < 4) { - DBG_871X("%s The gpio number does not included 4~7.\n", __func__); - return -1; - } - - rtw_ps_deny(adapter, PS_DENY_IOCTL); - - LeaveAllPowerSaveModeDirect(adapter); - - /* Read GPIO direction */ - direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; - - /* If GPIO is output direction, setting value. */ - if (direction) { - if (isHigh) - rtw_write8(adapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 1) | BIT(gpio_num)); - else - rtw_write8(adapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(gpio_num)); - - DBG_871X("%s Set gpio %x[%d]=%d\n", __func__, REG_GPIO_PIN_CTRL+1, gpio_num, isHigh); - res = 0; - } else { - DBG_871X("%s The gpio is input, not be set!\n", __func__); - res = -1; - } - - rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); - return res; -} -EXPORT_SYMBOL(rtw_set_gpio_output_value); - -int rtw_config_gpio(struct net_device *netdev, int gpio_num, bool isOutput) -{ - struct adapter *adapter = rtw_netdev_priv(netdev); - - if (gpio_num > 7 || gpio_num < 4) { - DBG_871X("%s The gpio number does not included 4~7.\n", __func__); - return -1; - } - - DBG_871X("%s gpio_num =%d direction =%d\n", __func__, gpio_num, isOutput); - - rtw_ps_deny(adapter, PS_DENY_IOCTL); - - LeaveAllPowerSaveModeDirect(adapter); - - if (isOutput) - rtw_write8(adapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) | BIT(gpio_num)); - else - rtw_write8(adapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & ~BIT(gpio_num)); - - rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); - - return 0; -} -EXPORT_SYMBOL(rtw_config_gpio); -#endif - -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -void rtw_get_current_ip_address(struct adapter *padapter, u8 *pcurrentip) -{ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct in_device *my_ip_ptr = padapter->pnetdev->ip_ptr; - u8 ipaddress[4]; - - if ((pmlmeinfo->state & WIFI_FW_LINKING_STATE) || - pmlmeinfo->state & WIFI_FW_AP_STATE) { - if (my_ip_ptr) { - struct in_ifaddr *my_ifa_list = my_ip_ptr->ifa_list; - - if (my_ifa_list) { - ipaddress[0] = my_ifa_list->ifa_address & 0xFF; - ipaddress[1] = (my_ifa_list->ifa_address >> 8) & 0xFF; - ipaddress[2] = (my_ifa_list->ifa_address >> 16) & 0xFF; - ipaddress[3] = my_ifa_list->ifa_address >> 24; - DBG_871X("%s: %d.%d.%d.%d ==========\n", __func__, - ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]); - memcpy(pcurrentip, ipaddress, 4); - } - } - } -} -#endif -#ifdef CONFIG_WOWLAN -void rtw_get_sec_iv(struct adapter *padapter, u8 *pcur_dot11txpn, u8 *StaAddr) -{ - struct sta_info *psta; - struct security_priv *psecpriv = &padapter->securitypriv; - - memset(pcur_dot11txpn, 0, 8); - if (NULL == StaAddr) - return; - psta = rtw_get_stainfo(&padapter->stapriv, StaAddr); - DBG_871X("%s(): StaAddr: %02x %02x %02x %02x %02x %02x\n", - __func__, StaAddr[0], StaAddr[1], StaAddr[2], - StaAddr[3], StaAddr[4], StaAddr[5]); - - if (psta) { - if (psecpriv->dot11PrivacyAlgrthm != _NO_PRIVACY_ && psta->dot11txpn.val > 0) - psta->dot11txpn.val--; - AES_IV(pcur_dot11txpn, psta->dot11txpn, 0); - - DBG_871X("%s(): CurrentIV: %02x %02x %02x %02x %02x %02x %02x %02x\n" - , __func__, pcur_dot11txpn[0], pcur_dot11txpn[1], - pcur_dot11txpn[2], pcur_dot11txpn[3], pcur_dot11txpn[4], - pcur_dot11txpn[5], pcur_dot11txpn[6], pcur_dot11txpn[7]); - } -} - -void rtw_set_sec_pn(struct adapter *padapter) -{ - struct sta_info *psta; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - struct security_priv *psecpriv = &padapter->securitypriv; - - psta = rtw_get_stainfo(&padapter->stapriv, - get_my_bssid(&pmlmeinfo->network)); - - if (psta) { - if (pwrpriv->wowlan_fw_iv > psta->dot11txpn.val) { - if (psecpriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) - psta->dot11txpn.val = pwrpriv->wowlan_fw_iv + 2; - } else { - DBG_871X("%s(): FW IV is smaller than driver\n", __func__); - psta->dot11txpn.val += 2; - } - DBG_871X("%s: dot11txpn: 0x%016llx\n", __func__, psta->dot11txpn.val); - } -} -#endif /* CONFIG_WOWLAN */ - -#ifdef CONFIG_PNO_SUPPORT -#define CSCAN_TLV_TYPE_SSID_IE 'S' -#define CIPHER_IE "key_mgmt =" -#define CIPHER_NONE "NONE" -#define CIPHER_WPA_PSK "WPA-PSK" -#define CIPHER_WPA_EAP "WPA-EAP IEEE8021X" - -#endif /* CONFIG_PNO_SUPPORT */ diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 41632fa0b3c811cbe9118ed489f93bbbdc54fb5b..bd3acdd7d75f6d3096c9f431d26bdd6f156113e2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -38,7 +38,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) int i; struct xmit_buf *pxmitbuf; struct xmit_frame *pxframe; - sint res = _SUCCESS; + signed int res = _SUCCESS; spin_lock_init(&pxmitpriv->lock); spin_lock_init(&pxmitpriv->lock_sctx); @@ -46,8 +46,8 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) init_completion(&pxmitpriv->terminate_xmitthread_comp); /* - Please insert all the queue initializaiton using _rtw_init_queue below - */ + * Please insert all the queue initializaiton using _rtw_init_queue below + */ pxmitpriv->adapter = padapter; @@ -60,16 +60,15 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) _rtw_init_queue(&pxmitpriv->free_xmit_queue); /* - Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, - and initialize free_xmit_frame below. - Please also apply free_txobj to link_up all the xmit_frames... - */ + * Please allocate memory with the 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 = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); if (!pxmitpriv->pallocated_frame_buf) { pxmitpriv->pxmit_frame_buf = NULL; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n")); res = _FAIL; goto exit; } @@ -105,7 +104,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); if (!pxmitpriv->pallocated_xmitbuf) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n")); res = _FAIL; goto exit; } @@ -155,7 +153,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) if (!pxmitpriv->xframe_ext_alloc_addr) { pxmitpriv->xframe_ext = NULL; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xframe_ext fail!\n")); res = _FAIL; goto exit; } @@ -188,7 +185,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxmitpriv->pallocated_xmit_extbuf = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4); if (!pxmitpriv->pallocated_xmit_extbuf) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n")); res = _FAIL; goto exit; } @@ -467,34 +463,23 @@ static void update_attrib_phy_info(struct adapter *padapter, struct pkt_attrib * pattrib->ampdu_spacing = psta->htpriv.rx_ampdu_min_spacing; pattrib->retry_ctrl = false; - -#ifdef CONFIG_AUTO_AP_MODE - if (psta->isrc && psta->pid > 0) - pattrib->pctrl = true; -#endif } static s32 update_attrib_sec_info(struct adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) { - sint res = _SUCCESS; + signed int res = _SUCCESS; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; - sint bmcast = IS_MCAST(pattrib->ra); + signed int bmcast = IS_MCAST(pattrib->ra); memset(pattrib->dot118021x_UncstKey.skey, 0, 16); memset(pattrib->dot11tkiptxmickey.skey, 0, 16); pattrib->mac_id = psta->mac_id; if (psta->ieee8021x_blocked == true) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n")); - pattrib->encrypt = 0; if ((pattrib->ether_type != 0x888e) && (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != 0x888e\n", pattrib->ether_type)); - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s psta->ieee8021x_blocked == true, pattrib->ether_type(%04x) != 0x888e\n", __func__, pattrib->ether_type); - #endif res = _FAIL; goto exit; } @@ -536,9 +521,6 @@ static s32 update_attrib_sec_info(struct adapter *padapter, struct pkt_attrib *p pattrib->icv_len = 4; if (psecuritypriv->busetkipkey == _FAIL) { - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s psecuritypriv->busetkipkey(%d) == _FAIL drop packet\n", __func__, psecuritypriv->busetkipkey); - #endif res = _FAIL; goto exit; } @@ -573,20 +555,11 @@ static s32 update_attrib_sec_info(struct adapter *padapter, struct pkt_attrib *p if (pattrib->encrypt > 0) memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, - ("update_attrib: encrypt =%d securitypriv.sw_encrypt =%d\n", - pattrib->encrypt, padapter->securitypriv.sw_encrypt)); - if (pattrib->encrypt && - ((padapter->securitypriv.sw_encrypt == true) || (psecuritypriv->hw_decrypted == false))) { + ((padapter->securitypriv.sw_encrypt) || (!psecuritypriv->hw_decrypted))) pattrib->bswenc = true; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, - ("update_attrib: encrypt =%d securitypriv.hw_decrypted =%d bswenc =true\n", - pattrib->encrypt, padapter->securitypriv.sw_encrypt)); - } else { + else pattrib->bswenc = false; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc =false\n")); - } exit: @@ -615,7 +588,6 @@ u8 qos_acm(u8 acm_mask, u8 priority) priority = 5; break; default: - DBG_871X("qos_acm(): invalid pattrib->priority: %d!!!\n", priority); break; } @@ -641,19 +613,17 @@ static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) pattrib->subtype = WIFI_QOS_DATA_TYPE; } -static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib *pattrib) +static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib) { struct pkt_file pktfile; struct sta_info *psta = NULL; struct ethhdr etherhdr; - sint bmcast; + signed int bmcast; struct sta_priv *pstapriv = &padapter->stapriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct qos_priv *pqospriv = &pmlmepriv->qospriv; - sint res = _SUCCESS; - - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib); + signed int res = _SUCCESS; _rtw_open_pktfile(pkt, &pktfile); _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); @@ -667,17 +637,12 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_adhoc); } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_sta); } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_ap); - } else { - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_unknown); } pattrib->pktlen = pktfile.pkt_len; @@ -697,9 +662,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib ((tmp[21] == 67) && (tmp[23] == 68))) { /* 68 : UDP BOOTP client */ /* 67 : UDP BOOTP server */ - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======================update_attrib: get DHCP Packet\n")); pattrib->dhcp_pkt = 1; - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_dhcp); } } } @@ -709,13 +672,11 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib struct iphdr *piphdr = (struct iphdr *)tmp; pattrib->icmp_pkt = 0; - if (piphdr->protocol == 0x1) { /* protocol type in ip header 0x1 is ICMP */ + if (piphdr->protocol == 0x1) /* protocol type in ip header 0x1 is ICMP */ pattrib->icmp_pkt = 1; - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_icmp); - } } } else if (0x888e == pattrib->ether_type) { - DBG_871X_LEVEL(_drv_always_, "send eapol packet\n"); + netdev_dbg(padapter->pnetdev, "send eapol packet\n"); } if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) @@ -724,10 +685,8 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ if (pattrib->icmp_pkt == 1) rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); - else if (pattrib->dhcp_pkt == 1) { - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_active); + else if (pattrib->dhcp_pkt == 1) rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); - } bmcast = IS_MCAST(pattrib->ra); @@ -737,15 +696,9 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib } else { psta = rtw_get_stainfo(pstapriv, pattrib->ra); if (!psta) { /* if we cannot get psta => drop the pkt */ - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_sta); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", MAC_ARG(pattrib->ra))); - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:%pM\n", __func__, MAC_ARG(pattrib->ra)); - #endif res = _FAIL; goto exit; } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) && (!(psta->state & _FW_LINKED))) { - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_ap_link); res = _FAIL; goto exit; } @@ -753,24 +706,15 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib if (!psta) { /* if we cannot get psta => drop the pkt */ - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sta); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", MAC_ARG(pattrib->ra))); - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:%pM\n", __func__, MAC_ARG(pattrib->ra)); - #endif res = _FAIL; goto exit; } - if (!(psta->state & _FW_LINKED)) { - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_link); - DBG_871X("%s, psta(%pM)->state(0x%x) != _FW_LINKED\n", __func__, MAC_ARG(psta->hwaddr), psta->state); + if (!(psta->state & _FW_LINKED)) return _FAIL; - } /* TODO:_lock */ if (update_attrib_sec_info(padapter, pattrib, psta) == _FAIL) { - DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sec); res = _FAIL; goto exit; } @@ -810,7 +754,7 @@ exit: static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe) { - sint curfragnum, length; + signed int curfragnum, length; u8 *pframe, *payload, mic[8]; struct mic_data micdata; struct pkt_attrib *pattrib = &pxmitframe->attrib; @@ -818,7 +762,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr struct xmit_priv *pxmitpriv = &padapter->xmitpriv; u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; u8 hw_hdr_offset = 0; - sint bmcst = IS_MCAST(pattrib->ra); + signed int bmcst = IS_MCAST(pattrib->ra); hw_hdr_offset = TXDESC_OFFSET; @@ -846,7 +790,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr if (pframe[1]&2) /* From Ds == 1 */ rtw_secmicappend(&micdata, &pframe[24], 6); else - rtw_secmicappend(&micdata, &pframe[10], 6); + rtw_secmicappend(&micdata, &pframe[10], 6); } else { /* ToDS == 0 */ rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ if (pframe[1]&2) /* From Ds == 1 */ @@ -864,11 +808,8 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { payload = (u8 *)round_up((SIZE_PTR)(payload), 4); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("===curfragnum =%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n", - curfragnum, *payload, *(payload+1), *(payload+2), *(payload+3), *(payload+4), *(payload+5), *(payload+6), *(payload+7))); - payload = payload+pattrib->hdrlen+pattrib->iv_len; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum =%d pattrib->hdrlen =%d pattrib->iv_len =%d", curfragnum, pattrib->hdrlen, pattrib->iv_len)); + if ((curfragnum+1) == pattrib->nr_frags) { length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); rtw_secmicappend(&micdata, payload, length); @@ -877,29 +818,14 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); rtw_secmicappend(&micdata, payload, length); payload = payload+length+pattrib->icv_len; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum =%d length =%d pattrib->icv_len =%d", curfragnum, length, pattrib->icv_len)); } } rtw_secgetmic(&micdata, &mic[0]); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n")); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz =%d!!!\n", pattrib->last_txcmdsz)); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]= 0x%.2x , mic[1]= 0x%.2x , mic[2]= 0x%.2x , mic[3]= 0x%.2x\n\ - mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n", - mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); /* add mic code and add the mic code length in last_txcmdsz */ memcpy(payload, &mic[0], 8); pattrib->last_txcmdsz += 8; - - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ========last pkt ========\n")); - payload = payload-pattrib->last_txcmdsz+8; - for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum = curfragnum+8) - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, (" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ", - *(payload+curfragnum), *(payload+curfragnum+1), *(payload+curfragnum+2), *(payload+curfragnum+3), - *(payload+curfragnum+4), *(payload+curfragnum+5), *(payload+curfragnum+6), *(payload+curfragnum+7))); } -/* -*/ } return _SUCCESS; } @@ -909,7 +835,6 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi struct pkt_attrib *pattrib = &pxmitframe->attrib; if (pattrib->bswenc) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n")); switch (pattrib->encrypt) { case _WEP40_: case _WEP104_: @@ -924,8 +849,6 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi default: break; } - } else { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n")); } return _SUCCESS; @@ -939,7 +862,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct qos_priv *pqospriv = &pmlmepriv->qospriv; u8 qos_option = false; - sint res = _SUCCESS; + signed int res = _SUCCESS; __le16 *fctrl = &pwlanhdr->frame_control; memset(hdr, 0, WLANHDR_OFFSET); @@ -979,7 +902,6 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr if (pattrib->qos_en) qos_option = true; } else { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); res = _FAIL; goto exit; } @@ -1008,20 +930,14 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr struct sta_info *psta; psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); - if (pattrib->psta != psta) { - DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + if (pattrib->psta != psta) return _FAIL; - } - if (!psta) { - DBG_871X("%s, psta ==NUL\n", __func__); + if (!psta) return _FAIL; - } - if (!(psta->state & _FW_LINKED)) { - DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + if (!(psta->state & _FW_LINKED)) return _FAIL; - } if (psta) { psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; @@ -1091,18 +1007,15 @@ u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) } /* - -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. - -*/ -s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) + * 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. + */ +s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) { struct pkt_file pktfile; @@ -1122,10 +1035,8 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram s32 bmcst = IS_MCAST(pattrib->ra); s32 res = _SUCCESS; - if (!pxmitframe->buf_addr) { - DBG_8192C("==> %s buf_addr == NULL\n", __func__); + if (!pxmitframe->buf_addr) return _FAIL; - } pbuf_start = pxmitframe->buf_addr; @@ -1133,8 +1044,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram mem_start = pbuf_start + hw_hdr_offset; if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n")); - DBG_8192C("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); res = _FAIL; goto exit; } @@ -1161,10 +1070,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram if (pattrib->iv_len) { memcpy(pframe, pattrib->iv, pattrib->iv_len); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, - ("rtw_xmitframe_coalesce: keyid =%d pattrib->iv[3]=%.2x pframe =%.2x %.2x %.2x %.2x\n", - padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3))); - pframe += pattrib->iv_len; mpdu_len -= pattrib->iv_len; @@ -1204,8 +1109,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram ClearMFrag(mem_start); break; - } else { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); } addr = (SIZE_PTR)(pframe); @@ -1215,8 +1118,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram } if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); - DBG_8192C("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); res = _FAIL; goto exit; } @@ -1233,7 +1134,7 @@ exit: } /* broadcast or multicast management pkt use BIP, unicast management pkt use CCMP encryption */ -s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) +s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) { u8 *pframe, *mem_start = NULL, *tmp_buf = NULL; u8 subtype; @@ -1266,10 +1167,9 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit goto xmitframe_coalesce_success; /* IGTK key is not install, it may not support 802.11w */ - if (padapter->securitypriv.binstallBIPkey != true) { - DBG_871X("no instll BIP key\n"); + if (!padapter->securitypriv.binstallBIPkey) goto xmitframe_coalesce_success; - } + /* station mode doesn't need TX BIP, just ready the code */ if (bmcst) { int frame_body_len; @@ -1323,15 +1223,11 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit else psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); - if (!psta) { - DBG_871X("%s, psta ==NUL\n", __func__); + if (!psta) goto xmitframe_coalesce_fail; - } - if (!(psta->state & _FW_LINKED) || !pxmitframe->buf_addr) { - DBG_871X("%s, not _FW_LINKED or addr null\n", __func__); + if (!(psta->state & _FW_LINKED) || !pxmitframe->buf_addr) goto xmitframe_coalesce_fail; - } /* according 802.11-2012 standard, these five types are not robust types */ if (subtype == WIFI_ACTION && @@ -1433,7 +1329,7 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) { uint protection; u8 *perp; - sint erp_len; + signed int erp_len; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; @@ -1508,12 +1404,8 @@ static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv, pxmitbuf->agg_num = 0; pxmitbuf->pg_num = 0; - if (pxmitbuf->sctx) { - DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); + if (pxmitbuf->sctx) rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); - } - } else { - DBG_871X("%s fail, no xmitbuf available !!!\n", __func__); } return pxmitbuf; @@ -1526,14 +1418,11 @@ struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf; pcmdframe = rtw_alloc_xmitframe(pxmitpriv); - if (!pcmdframe) { - DBG_871X("%s, alloc xmitframe fail\n", __func__); + if (!pcmdframe) return NULL; - } pxmitbuf = __rtw_alloc_cmd_xmitbuf(pxmitpriv, buf_type); if (!pxmitbuf) { - DBG_871X("%s, alloc xmitbuf fail\n", __func__); rtw_free_xmitframe(pxmitpriv, pcmdframe); return NULL; } @@ -1551,7 +1440,7 @@ struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) { - _irqL irqL; + unsigned long irqL; struct xmit_buf *pxmitbuf = NULL; struct list_head *plist, *phead; struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; @@ -1572,9 +1461,6 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) if (pxmitbuf) { pxmitpriv->free_xmit_extbuf_cnt--; - #ifdef DBG_XMIT_BUF_EXT - DBG_871X("DBG_XMIT_BUF_EXT ALLOC no =%d, free_xmit_extbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt); - #endif pxmitbuf->priv_data = NULL; @@ -1582,10 +1468,8 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; pxmitbuf->agg_num = 1; - if (pxmitbuf->sctx) { - DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); + if (pxmitbuf->sctx) rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); - } } spin_unlock_irqrestore(&pfree_queue->lock, irqL); @@ -1595,7 +1479,7 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { - _irqL irqL; + unsigned long irqL; struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; if (!pxmitbuf) @@ -1607,9 +1491,6 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue)); pxmitpriv->free_xmit_extbuf_cnt++; - #ifdef DBG_XMIT_BUF_EXT - DBG_871X("DBG_XMIT_BUF_EXT FREE no =%d, free_xmit_extbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt); - #endif spin_unlock_irqrestore(&pfree_queue->lock, irqL); @@ -1618,7 +1499,7 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) { - _irqL irqL; + unsigned long irqL; struct xmit_buf *pxmitbuf = NULL; struct list_head *plist, *phead; struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; @@ -1639,9 +1520,6 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) if (pxmitbuf) { pxmitpriv->free_xmitbuf_cnt--; - #ifdef DBG_XMIT_BUF - DBG_871X("DBG_XMIT_BUF ALLOC no =%d, free_xmitbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt); - #endif pxmitbuf->priv_data = NULL; @@ -1650,15 +1528,9 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) pxmitbuf->agg_num = 0; pxmitbuf->pg_num = 0; - if (pxmitbuf->sctx) { - DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); + if (pxmitbuf->sctx) rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); - } } - #ifdef DBG_XMIT_BUF - else - DBG_871X("DBG_XMIT_BUF rtw_alloc_xmitbuf return NULL\n"); - #endif spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); @@ -1667,16 +1539,14 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { - _irqL irqL; + unsigned long irqL; struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; if (!pxmitbuf) return _FAIL; - if (pxmitbuf->sctx) { - DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); + if (pxmitbuf->sctx) rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); - } if (pxmitbuf->buf_tag == XMITBUF_CMD) { } else if (pxmitbuf->buf_tag == XMITBUF_MGNT) { @@ -1690,9 +1560,6 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) get_list_head(pfree_xmitbuf_queue)); pxmitpriv->free_xmitbuf_cnt++; - #ifdef DBG_XMIT_BUF - DBG_871X("DBG_XMIT_BUF FREE no =%d, free_xmitbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt); - #endif spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); } return _SUCCESS; @@ -1715,23 +1582,22 @@ static void rtw_init_xmitframe(struct xmit_frame *pxframe) } /* -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... - -*/ + * 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 *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */ { /* - Please remember to use all the osdep_service api, - and lock/unlock or _enter/_exit critical to protect - pfree_xmit_queue - */ + * Please remember to use all the osdep_service api, + * and lock/unlock or _enter/_exit critical to protect + * pfree_xmit_queue + */ struct xmit_frame *pxframe = NULL; struct list_head *plist, *phead; @@ -1740,7 +1606,6 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pf spin_lock_bh(&pfree_xmit_queue->lock); if (list_empty(&pfree_xmit_queue->queue)) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe:%d\n", pxmitpriv->free_xmitframe_cnt)); pxframe = NULL; } else { phead = get_list_head(pfree_xmit_queue); @@ -1751,7 +1616,6 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pf list_del_init(&pxframe->list); pxmitpriv->free_xmitframe_cnt--; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); } spin_unlock_bh(&pfree_xmit_queue->lock); @@ -1769,7 +1633,6 @@ struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) spin_lock_bh(&queue->lock); if (list_empty(&queue->queue)) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe_ext:%d\n", pxmitpriv->free_xframe_ext_cnt)); pxframe = NULL; } else { phead = get_list_head(queue); @@ -1778,7 +1641,6 @@ struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) list_del_init(&pxframe->list); pxmitpriv->free_xframe_ext_cnt--; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe_ext():free_xmitframe_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); } spin_unlock_bh(&queue->lock); @@ -1811,8 +1673,6 @@ struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv) rtw_init_xmitframe(pxframe); - DBG_871X("################## %s ##################\n", __func__); - exit: return pxframe; } @@ -1821,12 +1681,10 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram { struct __queue *queue = NULL; struct adapter *padapter = pxmitpriv->adapter; - _pkt *pndis_pkt = NULL; + struct sk_buff *pndis_pkt = NULL; - if (!pxmitframe) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n")); + if (!pxmitframe) goto exit; - } if (pxmitframe->pkt) { pndis_pkt = pxmitframe->pkt; @@ -1834,7 +1692,6 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram } if (pxmitframe->alloc_addr) { - DBG_871X("################## %s with alloc_addr ##################\n", __func__); kfree(pxmitframe->alloc_addr); goto check_pkt_complete; } @@ -1850,14 +1707,10 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram list_del_init(&pxmitframe->list); list_add_tail(&pxmitframe->list, get_list_head(queue)); - if (pxmitframe->ext_tag == 0) { + if (pxmitframe->ext_tag == 0) pxmitpriv->free_xmitframe_cnt++; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); - } else if (pxmitframe->ext_tag == 1) { + else if (pxmitframe->ext_tag == 1) pxmitpriv->free_xframe_ext_cnt++; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xframe_ext_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); - } else { - } spin_unlock_bh(&queue->lock); @@ -1892,17 +1745,13 @@ void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pfram s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) { - DBG_COUNTER(padapter->tx_logs.core_tx_enqueue); - if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, - ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n")); + if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) return _FAIL; - } return _SUCCESS; } -struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, sint up, u8 *ac) +struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, signed int up, u8 *ac) { struct tx_servq *ptxservq = NULL; @@ -1911,21 +1760,18 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info * case 2: ptxservq = &psta->sta_xmitpriv.bk_q; *(ac) = 3; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n")); break; case 4: case 5: ptxservq = &psta->sta_xmitpriv.vi_q; *(ac) = 1; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n")); break; case 6: case 7: ptxservq = &psta->sta_xmitpriv.vo_q; *(ac) = 0; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n")); break; case 0: @@ -1933,7 +1779,6 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info * default: ptxservq = &psta->sta_xmitpriv.be_q; *(ac) = 2; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n")); break; } @@ -1951,30 +1796,19 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) struct tx_servq *ptxservq; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; - sint res = _SUCCESS; - - DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class); + signed int res = _SUCCESS; psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); - if (pattrib->psta != psta) { - DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_sta); - DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + if (pattrib->psta != psta) return _FAIL; - } if (!psta) { - DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_nosta); res = _FAIL; - DBG_8192C("rtw_xmit_classifier: psta == NULL\n"); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n")); goto exit; } - if (!(psta->state & _FW_LINKED)) { - DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_fwlink); - DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + if (!(psta->state & _FW_LINKED)) return _FAIL; - } ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); @@ -2037,9 +1871,9 @@ void rtw_free_hwxmits(struct adapter *padapter) kfree(pxmitpriv->hwxmits); } -void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry) +void rtw_init_hwxmits(struct hw_xmit *phwxmit, signed int entry) { - sint i; + signed int i; for (i = 0; i < entry; i++, phwxmit++) phwxmit->accnt = 0; @@ -2087,7 +1921,6 @@ static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib u8 qsel; qsel = pattrib->priority; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority =%d , qsel = %d\n", pattrib->priority, qsel)); pattrib->qsel = qsel; } @@ -2100,7 +1933,7 @@ static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib *0 success, hardware will handle this xmit frame(packet) *<0 fail */ -s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) +s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) { static unsigned long start; static u32 drop_cnt; @@ -2110,34 +1943,24 @@ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) s32 res; - DBG_COUNTER(padapter->tx_logs.core_tx); - if (start == 0) start = jiffies; pxmitframe = rtw_alloc_xmitframe(pxmitpriv); if (jiffies_to_msecs(jiffies - start) > 2000) { - if (drop_cnt) - DBG_871X("DBG_TX_DROP_FRAME %s no more pxmitframe, drop_cnt:%u\n", __func__, drop_cnt); start = jiffies; drop_cnt = 0; } if (!pxmitframe) { drop_cnt++; - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: no more pxmitframe\n", __func__)); - DBG_COUNTER(padapter->tx_logs.core_tx_err_pxmitframe); return -1; } res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); if (res == _FAIL) { - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: update attrib fail\n", __func__)); - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s update attrib fail\n", __func__); - #endif rtw_free_xmitframe(pxmitpriv, pxmitframe); return -1; } @@ -2148,7 +1971,6 @@ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) spin_lock_bh(&pxmitpriv->lock); if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe) == true) { spin_unlock_bh(&pxmitpriv->lock); - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue); return 1; } spin_unlock_bh(&pxmitpriv->lock); @@ -2176,11 +1998,9 @@ inline bool xmitframe_hiq_filter(struct xmit_frame *xmitframe) if (attrib->ether_type == 0x0806 || attrib->ether_type == 0x888e || attrib->dhcp_pkt - ) { - DBG_871X(FUNC_ADPT_FMT" ether_type:0x%04x%s\n", FUNC_ADPT_ARG(xmitframe->padapter) - , attrib->ether_type, attrib->dhcp_pkt?" DHCP":""); + ) allow = true; - } + } else if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_ALL) allow = true; else if (registry->hiq_filter == RTW_HIQ_FILTER_DENY_ALL) { @@ -2190,42 +2010,29 @@ inline bool xmitframe_hiq_filter(struct xmit_frame *xmitframe) return allow; } -sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) +signed int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) { - sint ret = false; + signed int ret = false; struct sta_info *psta = NULL; struct sta_priv *pstapriv = &padapter->stapriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - sint bmcst = IS_MCAST(pattrib->ra); + signed int bmcst = IS_MCAST(pattrib->ra); bool update_tim = false; - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) { - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_fwstate); + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) return ret; - } psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); - if (pattrib->psta != psta) { - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_sta); - DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + if (pattrib->psta != psta) return false; - } - if (!psta) { - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_nosta); - DBG_871X("%s, psta ==NUL\n", __func__); + if (!psta) return false; - } - if (!(psta->state & _FW_LINKED)) { - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_link); - DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + if (!(psta->state & _FW_LINKED)) return false; - } if (pattrib->triggered == 1) { - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_trigger); - if (bmcst && xmitframe_hiq_filter(pxmitframe)) pattrib->qsel = 0x11;/* HIQ */ @@ -2256,8 +2063,6 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr chk_bmc_sleepq_cmd(padapter); ret = true; - - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_mcast); } spin_unlock_bh(&psta->sleep_q.lock); @@ -2312,8 +2117,6 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr } ret = true; - - DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_ucast); } } @@ -2324,7 +2127,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue) { - sint ret; + signed int ret; struct list_head *plist, *phead; u8 ac_index; struct tx_servq *ptxservq; @@ -2469,7 +2272,6 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) psta->state ^= WIFI_SLEEP_STATE; if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { - DBG_871X("%s alive check\n", __func__); psta->expire_to = pstapriv->expire_to; psta->state ^= WIFI_STA_ALIVE_CHK_STATE; } @@ -2677,10 +2479,10 @@ struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpri return pxmitbuf; } -sint check_pending_xmitbuf(struct xmit_priv *pxmitpriv) +signed int check_pending_xmitbuf(struct xmit_priv *pxmitpriv) { struct __queue *pqueue; - sint ret = false; + signed int ret = false; pqueue = &pxmitpriv->pending_xmitbuf_queue; @@ -2729,13 +2531,11 @@ int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg) int status = 0; expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; - if (!wait_for_completion_timeout(&sctx->done, expire)) { + if (!wait_for_completion_timeout(&sctx->done, expire)) /* timeout, do something?? */ status = RTW_SCTX_DONE_TIMEOUT; - DBG_871X("%s timeout: %s\n", __func__, msg); - } else { + else status = sctx->status; - } if (status == RTW_SCTX_DONE_SUCCESS) ret = _SUCCESS; @@ -2743,26 +2543,9 @@ int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg) return ret; } -static bool rtw_sctx_chk_warning_status(int status) -{ - switch (status) { - case RTW_SCTX_DONE_UNKNOWN: - case RTW_SCTX_DONE_BUF_ALLOC: - case RTW_SCTX_DONE_BUF_FREE: - - case RTW_SCTX_DONE_DRV_STOP: - case RTW_SCTX_DONE_DEV_REMOVE: - return true; - default: - return false; - } -} - void rtw_sctx_done_err(struct submit_ctx **sctx, int status) { if (*sctx) { - if (rtw_sctx_chk_warning_status(status)) - DBG_871X("%s status:%d\n", __func__, status); (*sctx)->status = status; complete(&((*sctx)->done)); *sctx = NULL; @@ -2791,6 +2574,4 @@ void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) if (pxmitpriv->ack_tx) rtw_sctx_done_err(&pack_tx_ops, status); - else - DBG_871X("%s ack_tx not set\n", __func__); } diff --git a/drivers/staging/rtl8723bs/hal/Hal8723BReg.h b/drivers/staging/rtl8723bs/hal/Hal8723BReg.h index b9aca99478db67e720fedf0f2a94d34bc4f21037..6bf7933cbe4a1030a93d630ea5d09c8962188853 100644 --- a/drivers/staging/rtl8723bs/hal/Hal8723BReg.h +++ b/drivers/staging/rtl8723bs/hal/Hal8723BReg.h @@ -19,111 +19,109 @@ #ifndef __INC_HAL8723BREG_H #define __INC_HAL8723BREG_H - - /* */ /* */ /* */ /* */ /* */ -/* 0x0000h ~ 0x00FFh System Configuration */ +/* 0x0000h ~ 0x00FFh System Configuration */ /* */ /* */ #define REG_SYS_ISO_CTRL_8723B 0x0000 /* 2 Byte */ #define REG_SYS_FUNC_EN_8723B 0x0002 /* 2 Byte */ #define REG_APS_FSMCO_8723B 0x0004 /* 4 Byte */ -#define REG_SYS_CLKR_8723B 0x0008 /* 2 Byte */ -#define REG_9346CR_8723B 0x000A /* 2 Byte */ -#define REG_EE_VPD_8723B 0x000C /* 2 Byte */ -#define REG_AFE_MISC_8723B 0x0010 /* 1 Byte */ -#define REG_SPS0_CTRL_8723B 0x0011 /* 7 Byte */ +#define REG_SYS_CLKR_8723B 0x0008 /* 2 Byte */ +#define REG_9346CR_8723B 0x000A /* 2 Byte */ +#define REG_EE_VPD_8723B 0x000C /* 2 Byte */ +#define REG_AFE_MISC_8723B 0x0010 /* 1 Byte */ +#define REG_SPS0_CTRL_8723B 0x0011 /* 7 Byte */ #define REG_SPS_OCP_CFG_8723B 0x0018 /* 4 Byte */ -#define REG_RSV_CTRL_8723B 0x001C /* 3 Byte */ -#define REG_RF_CTRL_8723B 0x001F /* 1 Byte */ +#define REG_RSV_CTRL_8723B 0x001C /* 3 Byte */ +#define REG_RF_CTRL_8723B 0x001F /* 1 Byte */ #define REG_LPLDO_CTRL_8723B 0x0023 /* 1 Byte */ -#define REG_AFE_XTAL_CTRL_8723B 0x0024 /* 4 Byte */ +#define REG_AFE_XTAL_CTRL_8723B 0x0024 /* 4 Byte */ #define REG_AFE_PLL_CTRL_8723B 0x0028 /* 4 Byte */ #define REG_MAC_PLL_CTRL_EXT_8723B 0x002c /* 4 Byte */ #define REG_EFUSE_CTRL_8723B 0x0030 #define REG_EFUSE_TEST_8723B 0x0034 -#define REG_PWR_DATA_8723B 0x0038 -#define REG_CAL_TIMER_8723B 0x003C -#define REG_ACLK_MON_8723B 0x003E +#define REG_PWR_DATA_8723B 0x0038 +#define REG_CAL_TIMER_8723B 0x003C +#define REG_ACLK_MON_8723B 0x003E #define REG_GPIO_MUXCFG_8723B 0x0040 #define REG_GPIO_IO_SEL_8723B 0x0042 #define REG_MAC_PINMUX_CFG_8723B 0x0043 #define REG_GPIO_PIN_CTRL_8723B 0x0044 -#define REG_GPIO_INTM_8723B 0x0048 -#define REG_LEDCFG0_8723B 0x004C -#define REG_LEDCFG1_8723B 0x004D -#define REG_LEDCFG2_8723B 0x004E -#define REG_LEDCFG3_8723B 0x004F -#define REG_FSIMR_8723B 0x0050 -#define REG_FSISR_8723B 0x0054 -#define REG_HSIMR_8723B 0x0058 -#define REG_HSISR_8723B 0x005c -#define REG_GPIO_EXT_CTRL 0x0060 +#define REG_GPIO_INTM_8723B 0x0048 +#define REG_LEDCFG0_8723B 0x004C +#define REG_LEDCFG1_8723B 0x004D +#define REG_LEDCFG2_8723B 0x004E +#define REG_LEDCFG3_8723B 0x004F +#define REG_FSIMR_8723B 0x0050 +#define REG_FSISR_8723B 0x0054 +#define REG_HSIMR_8723B 0x0058 +#define REG_HSISR_8723B 0x005c +#define REG_GPIO_EXT_CTRL 0x0060 #define REG_MULTI_FUNC_CTRL_8723B 0x0068 #define REG_GPIO_STATUS_8723B 0x006C -#define REG_SDIO_CTRL_8723B 0x0070 -#define REG_OPT_CTRL_8723B 0x0074 -#define REG_AFE_XTAL_CTRL_EXT_8723B 0x0078 -#define REG_MCUFWDL_8723B 0x0080 +#define REG_SDIO_CTRL_8723B 0x0070 +#define REG_OPT_CTRL_8723B 0x0074 +#define REG_AFE_XTAL_CTRL_EXT_8723B 0x0078 +#define REG_MCUFWDL_8723B 0x0080 #define REG_BT_PATCH_STATUS_8723B 0x0088 -#define REG_HIMR0_8723B 0x00B0 -#define REG_HISR0_8723B 0x00B4 -#define REG_HIMR1_8723B 0x00B8 -#define REG_HISR1_8723B 0x00BC +#define REG_HIMR0_8723B 0x00B0 +#define REG_HISR0_8723B 0x00B4 +#define REG_HIMR1_8723B 0x00B8 +#define REG_HISR1_8723B 0x00BC #define REG_PMC_DBG_CTRL2_8723B 0x00CC #define REG_EFUSE_BURN_GNT_8723B 0x00CF -#define REG_HPON_FSM_8723B 0x00EC -#define REG_SYS_CFG_8723B 0x00F0 -#define REG_SYS_CFG1_8723B 0x00FC -#define REG_ROM_VERSION 0x00FD +#define REG_HPON_FSM_8723B 0x00EC +#define REG_SYS_CFG_8723B 0x00F0 +#define REG_SYS_CFG1_8723B 0x00FC +#define REG_ROM_VERSION 0x00FD /* */ /* */ -/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ /* */ /* */ -#define REG_CR_8723B 0x0100 -#define REG_PBP_8723B 0x0104 -#define REG_PKT_BUFF_ACCESS_CTRL_8723B 0x0106 +#define REG_CR_8723B 0x0100 +#define REG_PBP_8723B 0x0104 +#define REG_PKT_BUFF_ACCESS_CTRL_8723B 0x0106 #define REG_TRXDMA_CTRL_8723B 0x010C #define REG_TRXFF_BNDY_8723B 0x0114 #define REG_TRXFF_STATUS_8723B 0x0118 -#define REG_RXFF_PTR_8723B 0x011C -#define REG_CPWM_8723B 0x012F -#define REG_FWIMR_8723B 0x0130 -#define REG_FWISR_8723B 0x0134 -#define REG_FTIMR_8723B 0x0138 +#define REG_RXFF_PTR_8723B 0x011C +#define REG_CPWM_8723B 0x012F +#define REG_FWIMR_8723B 0x0130 +#define REG_FWISR_8723B 0x0134 +#define REG_FTIMR_8723B 0x0138 #define REG_PKTBUF_DBG_CTRL_8723B 0x0140 -#define REG_RXPKTBUF_CTRL_8723B 0x0142 -#define REG_PKTBUF_DBG_DATA_L_8723B 0x0144 -#define REG_PKTBUF_DBG_DATA_H_8723B 0x0148 - -#define REG_TC0_CTRL_8723B 0x0150 -#define REG_TC1_CTRL_8723B 0x0154 -#define REG_TC2_CTRL_8723B 0x0158 -#define REG_TC3_CTRL_8723B 0x015C -#define REG_TC4_CTRL_8723B 0x0160 +#define REG_RXPKTBUF_CTRL_8723B 0x0142 +#define REG_PKTBUF_DBG_DATA_L_8723B 0x0144 +#define REG_PKTBUF_DBG_DATA_H_8723B 0x0148 + +#define REG_TC0_CTRL_8723B 0x0150 +#define REG_TC1_CTRL_8723B 0x0154 +#define REG_TC2_CTRL_8723B 0x0158 +#define REG_TC3_CTRL_8723B 0x015C +#define REG_TC4_CTRL_8723B 0x0160 #define REG_TCUNIT_BASE_8723B 0x0164 -#define REG_RSVD3_8723B 0x0168 -#define REG_C2HEVT_MSG_NORMAL_8723B 0x01A0 -#define REG_C2HEVT_CMD_SEQ_88XX 0x01A1 -#define REG_C2hEVT_CMD_CONTENT_88XX 0x01A2 -#define REG_C2HEVT_CMD_LEN_88XX 0x01AE +#define REG_RSVD3_8723B 0x0168 +#define REG_C2HEVT_MSG_NORMAL_8723B 0x01A0 +#define REG_C2HEVT_CMD_SEQ_88XX 0x01A1 +#define REG_C2HEVT_CMD_CONTENT_88XX 0x01A2 +#define REG_C2HEVT_CMD_LEN_88XX 0x01AE #define REG_C2HEVT_CLEAR_8723B 0x01AF -#define REG_MCUTST_1_8723B 0x01C0 -#define REG_MCUTST_WOWLAN_8723B 0x01C7 -#define REG_FMETHR_8723B 0x01C8 -#define REG_HMETFR_8723B 0x01CC -#define REG_HMEBOX_0_8723B 0x01D0 -#define REG_HMEBOX_1_8723B 0x01D4 -#define REG_HMEBOX_2_8723B 0x01D8 -#define REG_HMEBOX_3_8723B 0x01DC -#define REG_LLT_INIT_8723B 0x01E0 +#define REG_MCUTST_1_8723B 0x01C0 +#define REG_MCUTST_WOWLAN_8723B 0x01C7 +#define REG_FMETHR_8723B 0x01C8 +#define REG_HMETFR_8723B 0x01CC +#define REG_HMEBOX_0_8723B 0x01D0 +#define REG_HMEBOX_1_8723B 0x01D4 +#define REG_HMEBOX_2_8723B 0x01D8 +#define REG_HMEBOX_3_8723B 0x01DC +#define REG_LLT_INIT_8723B 0x01E0 #define REG_HMEBOX_EXT0_8723B 0x01F0 #define REG_HMEBOX_EXT1_8723B 0x01F4 #define REG_HMEBOX_EXT2_8723B 0x01F8 @@ -131,65 +129,63 @@ /* */ /* */ -/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ /* */ /* */ -#define REG_RQPN_8723B 0x0200 -#define REG_FIFOPAGE_8723B 0x0204 +#define REG_RQPN_8723B 0x0200 +#define REG_FIFOPAGE_8723B 0x0204 #define REG_DWBCN0_CTRL_8723B REG_TDECTRL -#define REG_TXDMA_OFFSET_CHK_8723B 0x020C -#define REG_TXDMA_STATUS_8723B 0x0210 +#define REG_TXDMA_OFFSET_CHK_8723B 0x020C +#define REG_TXDMA_STATUS_8723B 0x0210 #define REG_RQPN_NPQ_8723B 0x0214 #define REG_DWBCN1_CTRL_8723B 0x0228 - /* */ /* */ -/* 0x0280h ~ 0x02FFh RXDMA Configuration */ +/* 0x0280h ~ 0x02FFh RXDMA Configuration */ /* */ /* */ #define REG_RXDMA_AGG_PG_TH_8723B 0x0280 -#define REG_FW_UPD_RDPTR_8723B 0x0284 /* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */ -#define REG_RXDMA_CONTROL_8723B 0x0286 /* Control the RX DMA. */ +#define REG_FW_UPD_RDPTR_8723B 0x0284 /* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */ +#define REG_RXDMA_CONTROL_8723B 0x0286 /* Control the RX DMA. */ #define REG_RXPKT_NUM_8723B 0x0287 /* The number of packets in RXPKTBUF. */ #define REG_RXDMA_STATUS_8723B 0x0288 #define REG_RXDMA_PRO_8723B 0x0290 -#define REG_EARLY_MODE_CONTROL_8723B 0x02BC -#define REG_RSVD5_8723B 0x02F0 -#define REG_RSVD6_8723B 0x02F4 - +#define REG_EARLY_MODE_CONTROL_8723B 0x02BC +#define REG_RSVD5_8723B 0x02F0 +#define REG_RSVD6_8723B 0x02F4 /* */ /* */ -/* 0x0300h ~ 0x03FFh PCIe */ +/* 0x0300h ~ 0x03FFh PCIe */ /* */ /* */ -#define REG_PCIE_CTRL_REG_8723B 0x0300 -#define REG_INT_MIG_8723B 0x0304 /* Interrupt Migration */ +#define REG_PCIE_CTRL_REG_8723B 0x0300 +#define REG_INT_MIG_8723B 0x0304 /* Interrupt Migration */ #define REG_BCNQ_DESA_8723B 0x0308 /* TX Beacon Descriptor Address */ -#define REG_HQ_DESA_8723B 0x0310 /* TX High Queue Descriptor Address */ +#define REG_HQ_DESA_8723B 0x0310 /* TX High Queue Descriptor Address */ #define REG_MGQ_DESA_8723B 0x0318 /* TX Manage Queue Descriptor Address */ #define REG_VOQ_DESA_8723B 0x0320 /* TX VO Queue Descriptor Address */ -#define REG_VIQ_DESA_8723B 0x0328 /* TX VI Queue Descriptor Address */ +#define REG_VIQ_DESA_8723B 0x0328 /* TX VI Queue Descriptor Address */ #define REG_BEQ_DESA_8723B 0x0330 /* TX BE Queue Descriptor Address */ #define REG_BKQ_DESA_8723B 0x0338 /* TX BK Queue Descriptor Address */ -#define REG_RX_DESA_8723B 0x0340 /* RX Queue Descriptor Address */ +#define REG_RX_DESA_8723B 0x0340 /* RX Queue Descriptor Address */ #define REG_DBI_WDATA_8723B 0x0348 /* DBI Write Data */ #define REG_DBI_RDATA_8723B 0x034C /* DBI Read Data */ -#define REG_DBI_ADDR_8723B 0x0350 /* DBI Address */ -#define REG_DBI_FLAG_8723B 0x0352 /* DBI Read/Write Flag */ -#define REG_MDIO_WDATA_8723B 0x0354 /* MDIO for Write PCIE PHY */ +#define REG_DBI_ADDR_8723B 0x0350 /* DBI Address */ +#define REG_DBI_FLAG_8723B 0x0352 /* DBI Read/Write Flag */ +#define REG_MDIO_WDATA_8723B 0x0354 /* MDIO for Write PCIE PHY */ #define REG_MDIO_RDATA_8723B 0x0356 /* MDIO for Reads PCIE PHY */ #define REG_MDIO_CTL_8723B 0x0358 /* MDIO for Control */ -#define REG_DBG_SEL_8723B 0x0360 /* Debug Selection Register */ +#define REG_DBG_SEL_8723B 0x0360 /* Debug Selection Register */ #define REG_PCIE_HRPWM_8723B 0x0361 /* PCIe RPWM */ #define REG_PCIE_HCPWM_8723B 0x0363 /* PCIe CPWM */ -#define REG_PCIE_MULTIFET_CTRL_8723B 0x036A /* PCIE Multi-Fethc Control */ +#define REG_PCIE_MULTIFET_CTRL_8723B 0x036A /* PCIE Multi-Fethc Control */ /* spec version 11 */ /* */ /* */ -/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ /* */ /* */ #define REG_VOQ_INFORMATION_8723B 0x0400 @@ -198,75 +194,75 @@ #define REG_BKQ_INFORMATION_8723B 0x040C #define REG_MGQ_INFORMATION_8723B 0x0410 #define REG_HGQ_INFORMATION_8723B 0x0414 -#define REG_BCNQ_INFORMATION_8723B 0x0418 +#define REG_BCNQ_INFORMATION_8723B 0x0418 #define REG_TXPKT_EMPTY_8723B 0x041A -#define REG_FWHW_TXQ_CTRL_8723B 0x0420 +#define REG_FWHW_TXQ_CTRL_8723B 0x0420 #define REG_HWSEQ_CTRL_8723B 0x0423 -#define REG_TXPKTBUF_BCNQ_BDNY_8723B 0x0424 -#define REG_TXPKTBUF_MGQ_BDNY_8723B 0x0425 +#define REG_TXPKTBUF_BCNQ_BDNY_8723B 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY_8723B 0x0425 #define REG_LIFECTRL_CTRL_8723B 0x0426 -#define REG_MULTI_BCNQ_OFFSET_8723B 0x0427 -#define REG_SPEC_SIFS_8723B 0x0428 -#define REG_RL_8723B 0x042A -#define REG_TXBF_CTRL_8723B 0x042C -#define REG_DARFRC_8723B 0x0430 -#define REG_RARFRC_8723B 0x0438 -#define REG_RRSR_8723B 0x0440 -#define REG_ARFR0_8723B 0x0444 -#define REG_ARFR1_8723B 0x044C -#define REG_CCK_CHECK_8723B 0x0454 +#define REG_MULTI_BCNQ_OFFSET_8723B 0x0427 +#define REG_SPEC_SIFS_8723B 0x0428 +#define REG_RL_8723B 0x042A +#define REG_TXBF_CTRL_8723B 0x042C +#define REG_DARFRC_8723B 0x0430 +#define REG_RARFRC_8723B 0x0438 +#define REG_RRSR_8723B 0x0440 +#define REG_ARFR0_8723B 0x0444 +#define REG_ARFR1_8723B 0x044C +#define REG_CCK_CHECK_8723B 0x0454 #define REG_AMPDU_MAX_TIME_8723B 0x0456 -#define REG_TXPKTBUF_BCNQ_BDNY1_8723B 0x0457 +#define REG_TXPKTBUF_BCNQ_BDNY1_8723B 0x0457 -#define REG_AMPDU_MAX_LENGTH_8723B 0x0458 +#define REG_AMPDU_MAX_LENGTH_8723B 0x0458 #define REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B 0x045D -#define REG_NDPA_OPT_CTRL_8723B 0x045F +#define REG_NDPA_OPT_CTRL_8723B 0x045F #define REG_FAST_EDCA_CTRL_8723B 0x0460 #define REG_RD_RESP_PKT_TH_8723B 0x0463 -#define REG_DATA_SC_8723B 0x0483 -#define REG_TXRPT_START_OFFSET 0x04AC -#define REG_POWER_STAGE1_8723B 0x04B4 -#define REG_POWER_STAGE2_8723B 0x04B8 -#define REG_AMPDU_BURST_MODE_8723B 0x04BC -#define REG_PKT_VO_VI_LIFE_TIME_8723B 0x04C0 -#define REG_PKT_BE_BK_LIFE_TIME_8723B 0x04C2 +#define REG_DATA_SC_8723B 0x0483 +#define REG_TXRPT_START_OFFSET 0x04AC +#define REG_POWER_STAGE1_8723B 0x04B4 +#define REG_POWER_STAGE2_8723B 0x04B8 +#define REG_AMPDU_BURST_MODE_8723B 0x04BC +#define REG_PKT_VO_VI_LIFE_TIME_8723B 0x04C0 +#define REG_PKT_BE_BK_LIFE_TIME_8723B 0x04C2 #define REG_STBC_SETTING_8723B 0x04C4 #define REG_HT_SINGLE_AMPDU_8723B 0x04C7 #define REG_PROT_MODE_CTRL_8723B 0x04C8 -#define REG_MAX_AGGR_NUM_8723B 0x04CA -#define REG_RTS_MAX_AGGR_NUM_8723B 0x04CB -#define REG_BAR_MODE_CTRL_8723B 0x04CC -#define REG_RA_TRY_RATE_AGG_LMT_8723B 0x04CF +#define REG_MAX_AGGR_NUM_8723B 0x04CA +#define REG_RTS_MAX_AGGR_NUM_8723B 0x04CB +#define REG_BAR_MODE_CTRL_8723B 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT_8723B 0x04CF #define REG_MACID_PKT_DROP0_8723B 0x04D0 #define REG_MACID_PKT_SLEEP_8723B 0x04D4 /* */ /* */ -/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ /* */ /* */ -#define REG_EDCA_VO_PARAM_8723B 0x0500 -#define REG_EDCA_VI_PARAM_8723B 0x0504 -#define REG_EDCA_BE_PARAM_8723B 0x0508 -#define REG_EDCA_BK_PARAM_8723B 0x050C -#define REG_BCNTCFG_8723B 0x0510 -#define REG_PIFS_8723B 0x0512 -#define REG_RDG_PIFS_8723B 0x0513 -#define REG_SIFS_CTX_8723B 0x0514 -#define REG_SIFS_TRX_8723B 0x0516 +#define REG_EDCA_VO_PARAM_8723B 0x0500 +#define REG_EDCA_VI_PARAM_8723B 0x0504 +#define REG_EDCA_BE_PARAM_8723B 0x0508 +#define REG_EDCA_BK_PARAM_8723B 0x050C +#define REG_BCNTCFG_8723B 0x0510 +#define REG_PIFS_8723B 0x0512 +#define REG_RDG_PIFS_8723B 0x0513 +#define REG_SIFS_CTX_8723B 0x0514 +#define REG_SIFS_TRX_8723B 0x0516 #define REG_AGGR_BREAK_TIME_8723B 0x051A -#define REG_SLOT_8723B 0x051B +#define REG_SLOT_8723B 0x051B #define REG_TX_PTCL_CTRL_8723B 0x0520 -#define REG_TXPAUSE_8723B 0x0522 -#define REG_DIS_TXREQ_CLR_8723B 0x0523 -#define REG_RD_CTRL_8723B 0x0524 +#define REG_TXPAUSE_8723B 0x0522 +#define REG_DIS_TXREQ_CLR_8723B 0x0523 +#define REG_RD_CTRL_8723B 0x0524 /* */ /* Format for offset 540h-542h: */ -/* [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting beacon content before TBTT. */ -/* [7:4]: Reserved. */ -/* [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding to send the beacon packet. */ -/* [23:20]: Reserved */ +/* [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting beacon content before TBTT. */ +/* [7:4]: Reserved. */ +/* [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding to send the beacon packet. */ +/* [23:20]: Reserved */ /* Description: */ /* | */ /* |<--Setup--|--Hold------------>| */ @@ -276,87 +272,86 @@ /* Note: We cannot update beacon content to HW or send any AC packets during the time between Setup and Hold. */ /* Described by Designer Tim and Bruce, 2011-01-14. */ /* */ -#define REG_TBTT_PROHIBIT_8723B 0x0540 -#define REG_RD_NAV_NXT_8723B 0x0544 -#define REG_NAV_PROT_LEN_8723B 0x0546 -#define REG_BCN_CTRL_8723B 0x0550 -#define REG_BCN_CTRL_1_8723B 0x0551 -#define REG_MBID_NUM_8723B 0x0552 -#define REG_DUAL_TSF_RST_8723B 0x0553 -#define REG_BCN_INTERVAL_8723B 0x0554 -#define REG_DRVERLYINT_8723B 0x0558 -#define REG_BCNDMATIM_8723B 0x0559 -#define REG_ATIMWND_8723B 0x055A -#define REG_USTIME_TSF_8723B 0x055C -#define REG_BCN_MAX_ERR_8723B 0x055D -#define REG_RXTSF_OFFSET_CCK_8723B 0x055E -#define REG_RXTSF_OFFSET_OFDM_8723B 0x055F -#define REG_TSFTR_8723B 0x0560 -#define REG_CTWND_8723B 0x0572 -#define REG_SECONDARY_CCA_CTRL_8723B 0x0577 -#define REG_PSTIMER_8723B 0x0580 -#define REG_TIMER0_8723B 0x0584 -#define REG_TIMER1_8723B 0x0588 -#define REG_ACMHWCTRL_8723B 0x05C0 -#define REG_SCH_TXCMD_8723B 0x05F8 - -/* 0x0600h ~ 0x07FFh WMAC Configuration */ -#define REG_MAC_CR_8723B 0x0600 -#define REG_TCR_8723B 0x0604 -#define REG_RCR_8723B 0x0608 -#define REG_RX_PKT_LIMIT_8723B 0x060C -#define REG_RX_DLK_TIME_8723B 0x060D -#define REG_RX_DRVINFO_SZ_8723B 0x060F - -#define REG_MACID_8723B 0x0610 -#define REG_BSSID_8723B 0x0618 -#define REG_MAR_8723B 0x0620 -#define REG_MBIDCAMCFG_8723B 0x0628 - -#define REG_USTIME_EDCA_8723B 0x0638 -#define REG_MAC_SPEC_SIFS_8723B 0x063A -#define REG_RESP_SIFP_CCK_8723B 0x063C -#define REG_RESP_SIFS_OFDM_8723B 0x063E -#define REG_ACKTO_8723B 0x0640 -#define REG_CTS2TO_8723B 0x0641 -#define REG_EIFS_8723B 0x0642 - -#define REG_NAV_UPPER_8723B 0x0652 /* unit of 128 */ -#define REG_TRXPTCL_CTL_8723B 0x0668 +#define REG_TBTT_PROHIBIT_8723B 0x0540 +#define REG_RD_NAV_NXT_8723B 0x0544 +#define REG_NAV_PROT_LEN_8723B 0x0546 +#define REG_BCN_CTRL_8723B 0x0550 +#define REG_BCN_CTRL_1_8723B 0x0551 +#define REG_MBID_NUM_8723B 0x0552 +#define REG_DUAL_TSF_RST_8723B 0x0553 +#define REG_BCN_INTERVAL_8723B 0x0554 +#define REG_DRVERLYINT_8723B 0x0558 +#define REG_BCNDMATIM_8723B 0x0559 +#define REG_ATIMWND_8723B 0x055A +#define REG_USTIME_TSF_8723B 0x055C +#define REG_BCN_MAX_ERR_8723B 0x055D +#define REG_RXTSF_OFFSET_CCK_8723B 0x055E +#define REG_RXTSF_OFFSET_OFDM_8723B 0x055F +#define REG_TSFTR_8723B 0x0560 +#define REG_CTWND_8723B 0x0572 +#define REG_SECONDARY_CCA_CTRL_8723B 0x0577 +#define REG_PSTIMER_8723B 0x0580 +#define REG_TIMER0_8723B 0x0584 +#define REG_TIMER1_8723B 0x0588 +#define REG_ACMHWCTRL_8723B 0x05C0 +#define REG_SCH_TXCMD_8723B 0x05F8 + +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +#define REG_MAC_CR_8723B 0x0600 +#define REG_TCR_8723B 0x0604 +#define REG_RCR_8723B 0x0608 +#define REG_RX_PKT_LIMIT_8723B 0x060C +#define REG_RX_DLK_TIME_8723B 0x060D +#define REG_RX_DRVINFO_SZ_8723B 0x060F + +#define REG_MACID_8723B 0x0610 +#define REG_BSSID_8723B 0x0618 +#define REG_MAR_8723B 0x0620 +#define REG_MBIDCAMCFG_8723B 0x0628 + +#define REG_USTIME_EDCA_8723B 0x0638 +#define REG_MAC_SPEC_SIFS_8723B 0x063A +#define REG_RESP_SIFP_CCK_8723B 0x063C +#define REG_RESP_SIFS_OFDM_8723B 0x063E +#define REG_ACKTO_8723B 0x0640 +#define REG_CTS2TO_8723B 0x0641 +#define REG_EIFS_8723B 0x0642 + +#define REG_NAV_UPPER_8723B 0x0652 /* unit of 128 */ +#define REG_TRXPTCL_CTL_8723B 0x0668 /* Security */ -#define REG_CAMCMD_8723B 0x0670 -#define REG_CAMWRITE_8723B 0x0674 -#define REG_CAMREAD_8723B 0x0678 -#define REG_CAMDBG_8723B 0x067C -#define REG_SECCFG_8723B 0x0680 +#define REG_CAMCMD_8723B 0x0670 +#define REG_CAMWRITE_8723B 0x0674 +#define REG_CAMREAD_8723B 0x0678 +#define REG_CAMDBG_8723B 0x067C +#define REG_SECCFG_8723B 0x0680 /* Power */ -#define REG_WOW_CTRL_8723B 0x0690 -#define REG_PS_RX_INFO_8723B 0x0692 -#define REG_UAPSD_TID_8723B 0x0693 -#define REG_WKFMCAM_CMD_8723B 0x0698 -#define REG_WKFMCAM_NUM_8723B 0x0698 -#define REG_WKFMCAM_RWD_8723B 0x069C -#define REG_RXFLTMAP0_8723B 0x06A0 -#define REG_RXFLTMAP1_8723B 0x06A2 -#define REG_RXFLTMAP2_8723B 0x06A4 -#define REG_BCN_PSR_RPT_8723B 0x06A8 -#define REG_BT_COEX_TABLE_8723B 0x06C0 -#define REG_BFMER0_INFO_8723B 0x06E4 -#define REG_BFMER1_INFO_8723B 0x06EC -#define REG_CSI_RPT_PARAM_BW20_8723B 0x06F4 -#define REG_CSI_RPT_PARAM_BW40_8723B 0x06F8 -#define REG_CSI_RPT_PARAM_BW80_8723B 0x06FC +#define REG_WOW_CTRL_8723B 0x0690 +#define REG_PS_RX_INFO_8723B 0x0692 +#define REG_UAPSD_TID_8723B 0x0693 +#define REG_WKFMCAM_CMD_8723B 0x0698 +#define REG_WKFMCAM_NUM_8723B 0x0698 +#define REG_WKFMCAM_RWD_8723B 0x069C +#define REG_RXFLTMAP0_8723B 0x06A0 +#define REG_RXFLTMAP1_8723B 0x06A2 +#define REG_RXFLTMAP2_8723B 0x06A4 +#define REG_BCN_PSR_RPT_8723B 0x06A8 +#define REG_BT_COEX_TABLE_8723B 0x06C0 +#define REG_BFMER0_INFO_8723B 0x06E4 +#define REG_BFMER1_INFO_8723B 0x06EC +#define REG_CSI_RPT_PARAM_BW20_8723B 0x06F4 +#define REG_CSI_RPT_PARAM_BW40_8723B 0x06F8 +#define REG_CSI_RPT_PARAM_BW80_8723B 0x06FC /* Hardware Port 2 */ -#define REG_MACID1_8723B 0x0700 -#define REG_BSSID1_8723B 0x0708 -#define REG_BFMEE_SEL_8723B 0x0714 -#define REG_SND_PTCL_CTRL_8723B 0x0718 - +#define REG_MACID1_8723B 0x0700 +#define REG_BSSID1_8723B 0x0708 +#define REG_BFMEE_SEL_8723B 0x0714 +#define REG_SND_PTCL_CTRL_8723B 0x0718 -/* Redifine 8192C register definition for compatibility */ +/* Redifine 8192C register definition for compatibility */ /* TODO: use these definition when using REG_xxx naming rule. */ /* NOTE: DO NOT Remove these definition. Use later. */ @@ -429,13 +424,13 @@ #define IMR_RXFOVW_8723B BIT8 /* Receive FIFO Overflow */ /* 2 ACMHWCTRL 0x05C0 */ -#define AcmHw_HwEn_8723B BIT(0) -#define AcmHw_VoqEn_8723B BIT(1) -#define AcmHw_ViqEn_8723B BIT(2) -#define AcmHw_BeqEn_8723B BIT(3) -#define AcmHw_VoqStatus_8723B BIT(5) -#define AcmHw_ViqStatus_8723B BIT(6) -#define AcmHw_BeqStatus_8723B BIT(7) +#define ACMHW_HWEN_8723B BIT(0) +#define ACMHW_VOQEN_8723B BIT(1) +#define ACMHW_VIQEN_8723B BIT(2) +#define ACMHW_BEQEN_8723B BIT(3) +#define ACMHW_VOQSTATUS_8723B BIT(5) +#define ACMHW_VIQSTATUS_8723B BIT(6) +#define ACMHW_BEQSTATUS_8723B BIT(7) /* 8195 (RCR) Receive Configuration Register (Offset 0x608, 32 bits) */ #define RCR_TCPOFLD_EN BIT25 /* Enable TCP checksum offload */ diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c index c60e8c58d9cc5731bd47ace9607ca3e9f0e327dc..5037909245320b8eeda1ebb8fb81d95000564c45 100644 --- a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c +++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c @@ -8,10 +8,10 @@ #include "Mp_Precomp.h" /* Global variables, these are static variables */ -static COEX_DM_8723B_1ANT GLCoexDm8723b1Ant; -static PCOEX_DM_8723B_1ANT pCoexDm = &GLCoexDm8723b1Ant; -static COEX_STA_8723B_1ANT GLCoexSta8723b1Ant; -static PCOEX_STA_8723B_1ANT pCoexSta = &GLCoexSta8723b1Ant; +static struct coex_dm_8723b_1ant GLCoexDm8723b1Ant; +static struct coex_dm_8723b_1ant *pCoexDm = &GLCoexDm8723b1Ant; +static struct coex_sta_8723b_1ant GLCoexSta8723b1Ant; +static struct coex_sta_8723b_1ant *pCoexSta = &GLCoexSta8723b1Ant; static const char *const GLBtInfoSrc8723b1Ant[] = { "BT Info[wifi fw]", @@ -38,7 +38,7 @@ static u8 halbtc8723b1ant_BtRssiState( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW) ) { - if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) { + if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) { btRssiState = BTC_RSSI_STATE_HIGH; BTC_PRINT( @@ -85,7 +85,7 @@ static u8 halbtc8723b1ant_BtRssiState( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW) ) { - if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) { + if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) { btRssiState = BTC_RSSI_STATE_MEDIUM; BTC_PRINT( BTC_MSG_ALGORITHM, @@ -104,7 +104,7 @@ static u8 halbtc8723b1ant_BtRssiState( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) { - if (btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) { + if (btRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) { btRssiState = BTC_RSSI_STATE_HIGH; BTC_PRINT( BTC_MSG_ALGORITHM, @@ -151,7 +151,7 @@ static u8 halbtc8723b1ant_BtRssiState( } static void halbtc8723b1ant_UpdateRaMask( - PBTC_COEXIST pBtCoexist, bool bForceExec, u32 disRateMask + struct btc_coexist *pBtCoexist, bool bForceExec, u32 disRateMask ) { pCoexDm->curRaMask = disRateMask; @@ -166,7 +166,7 @@ static void halbtc8723b1ant_UpdateRaMask( } static void halbtc8723b1ant_AutoRateFallbackRetry( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, u8 type ) { bool bWifiUnderBMode = false; @@ -204,7 +204,7 @@ static void halbtc8723b1ant_AutoRateFallbackRetry( } static void halbtc8723b1ant_RetryLimit( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, u8 type ) { pCoexDm->curRetryLimitType = type; @@ -231,7 +231,7 @@ static void halbtc8723b1ant_RetryLimit( } static void halbtc8723b1ant_AmpduMaxTime( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, u8 type ) { pCoexDm->curAmpduTimeType = type; @@ -257,7 +257,7 @@ static void halbtc8723b1ant_AmpduMaxTime( } static void halbtc8723b1ant_LimitedTx( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bForceExec, u8 raMaskType, u8 arfrType, @@ -285,7 +285,7 @@ static void halbtc8723b1ant_LimitedTx( } static void halbtc8723b1ant_LimitedRx( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bForceExec, bool bRejApAggPkt, bool bBtCtrlAggBufSize, @@ -314,7 +314,7 @@ static void halbtc8723b1ant_LimitedRx( } -static void halbtc8723b1ant_QueryBtInfo(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_QueryBtInfo(struct btc_coexist *pBtCoexist) { u8 H2C_Parameter[1] = {0}; @@ -331,7 +331,7 @@ static void halbtc8723b1ant_QueryBtInfo(PBTC_COEXIST pBtCoexist) pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); } -static void halbtc8723b1ant_MonitorBtCtr(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_MonitorBtCtr(struct btc_coexist *pBtCoexist) { u32 regHPTxRx, regLPTxRx, u4Tmp; u32 regHPTx = 0, regHPRx = 0, regLPTx = 0, regLPRx = 0; @@ -353,11 +353,11 @@ static void halbtc8723b1ant_MonitorBtCtr(PBTC_COEXIST pBtCoexist) u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); regHPTx = u4Tmp & bMaskLWord; - regHPRx = (u4Tmp & bMaskHWord)>>16; + regHPRx = (u4Tmp & bMaskHWord) >> 16; u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); regLPTx = u4Tmp & bMaskLWord; - regLPRx = (u4Tmp & bMaskHWord)>>16; + regLPRx = (u4Tmp & bMaskHWord) >> 16; pCoexSta->highPriorityTx = regHPTx; pCoexSta->highPriorityRx = regHPRx; @@ -392,7 +392,7 @@ static void halbtc8723b1ant_MonitorBtCtr(PBTC_COEXIST pBtCoexist) } -static void halbtc8723b1ant_MonitorWiFiCtr(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_MonitorWiFiCtr(struct btc_coexist *pBtCoexist) { s32 wifiRssi = 0; bool bWifiBusy = false, bWifiUnderBMode = false; @@ -478,7 +478,7 @@ static void halbtc8723b1ant_MonitorWiFiCtr(PBTC_COEXIST pBtCoexist) } -static bool halbtc8723b1ant_IsWifiStatusChanged(PBTC_COEXIST pBtCoexist) +static bool halbtc8723b1ant_IsWifiStatusChanged(struct btc_coexist *pBtCoexist) { static bool bPreWifiBusy, bPreUnder4way, bPreBtHsOn; bool bWifiBusy = false, bUnder4way = false, bBtHsOn = false; @@ -513,9 +513,9 @@ static bool halbtc8723b1ant_IsWifiStatusChanged(PBTC_COEXIST pBtCoexist) return false; } -static void halbtc8723b1ant_UpdateBtLinkInfo(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_UpdateBtLinkInfo(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bBtHsOn = false; pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); @@ -577,9 +577,9 @@ static void halbtc8723b1ant_UpdateBtLinkInfo(PBTC_COEXIST pBtCoexist) pBtLinkInfo->bHidOnly = false; } -static u8 halbtc8723b1ant_ActionAlgorithm(PBTC_COEXIST pBtCoexist) +static u8 halbtc8723b1ant_ActionAlgorithm(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bBtHsOn = false; u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED; u8 numOfDiffProfile = 0; @@ -805,7 +805,7 @@ static u8 halbtc8723b1ant_ActionAlgorithm(PBTC_COEXIST pBtCoexist) } static void halbtc8723b1ant_SetSwPenaltyTxRateAdaptive( - PBTC_COEXIST pBtCoexist, bool bLowPenaltyRa + struct btc_coexist *pBtCoexist, bool bLowPenaltyRa ) { u8 H2C_Parameter[6] = {0}; @@ -833,7 +833,7 @@ static void halbtc8723b1ant_SetSwPenaltyTxRateAdaptive( } static void halbtc8723b1ant_LowPenaltyRa( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bLowPenaltyRa + struct btc_coexist *pBtCoexist, bool bForceExec, bool bLowPenaltyRa ) { pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; @@ -850,7 +850,7 @@ static void halbtc8723b1ant_LowPenaltyRa( } static void halbtc8723b1ant_SetCoexTable( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, u32 val0x6c0, u32 val0x6c4, u32 val0x6c8, @@ -887,7 +887,7 @@ static void halbtc8723b1ant_SetCoexTable( } static void halbtc8723b1ant_CoexTable( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bForceExec, u32 val0x6c0, u32 val0x6c4, @@ -930,7 +930,7 @@ static void halbtc8723b1ant_CoexTable( } static void halbtc8723b1ant_CoexTableWithType( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, u8 type ) { BTC_PRINT( @@ -988,7 +988,7 @@ static void halbtc8723b1ant_CoexTableWithType( } static void halbtc8723b1ant_SetFwIgnoreWlanAct( - PBTC_COEXIST pBtCoexist, bool bEnable + struct btc_coexist *pBtCoexist, bool bEnable ) { u8 H2C_Parameter[1] = {0}; @@ -1009,7 +1009,7 @@ static void halbtc8723b1ant_SetFwIgnoreWlanAct( } static void halbtc8723b1ant_IgnoreWlanAct( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bEnable + struct btc_coexist *pBtCoexist, bool bForceExec, bool bEnable ) { BTC_PRINT( @@ -1043,7 +1043,7 @@ static void halbtc8723b1ant_IgnoreWlanAct( } static void halbtc8723b1ant_SetLpsRpwm( - PBTC_COEXIST pBtCoexist, u8 lpsVal, u8 rpwmVal + struct btc_coexist *pBtCoexist, u8 lpsVal, u8 rpwmVal ) { u8 lps = lpsVal; @@ -1054,7 +1054,7 @@ static void halbtc8723b1ant_SetLpsRpwm( } static void halbtc8723b1ant_LpsRpwm( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 lpsVal, u8 rpwmVal + struct btc_coexist *pBtCoexist, bool bForceExec, u8 lpsVal, u8 rpwmVal ) { BTC_PRINT( @@ -1105,7 +1105,7 @@ static void halbtc8723b1ant_LpsRpwm( } static void halbtc8723b1ant_SwMechanism( - PBTC_COEXIST pBtCoexist, bool bLowPenaltyRA + struct btc_coexist *pBtCoexist, bool bLowPenaltyRA ) { BTC_PRINT( @@ -1118,10 +1118,10 @@ static void halbtc8723b1ant_SwMechanism( } static void halbtc8723b1ant_SetAntPath( - PBTC_COEXIST pBtCoexist, u8 antPosType, bool bInitHwCfg, bool bWifiOff + struct btc_coexist *pBtCoexist, u8 antPosType, bool bInitHwCfg, bool bWifiOff ) { - PBTC_BOARD_INFO pBoardInfo = &pBtCoexist->boardInfo; + struct btc_board_info *pBoardInfo = &pBtCoexist->boardInfo; u32 fwVer = 0, u4Tmp = 0, cntBtCalChk = 0; bool bPgExtSwitch = false; bool bUseExtSwitch = false; @@ -1307,7 +1307,7 @@ static void halbtc8723b1ant_SetAntPath( } static void halbtc8723b1ant_SetFwPstdma( - PBTC_COEXIST pBtCoexist, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5 + struct btc_coexist *pBtCoexist, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5 ) { u8 H2C_Parameter[5] = {0}; @@ -1317,7 +1317,7 @@ static void halbtc8723b1ant_SetFwPstdma( pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); if (bApEnable) { - if (byte1&BIT4 && !(byte1&BIT5)) { + if (byte1 & BIT4 && !(byte1 & BIT5)) { BTC_PRINT( BTC_MSG_INTERFACE, INTF_NOTIFY, @@ -1349,9 +1349,9 @@ static void halbtc8723b1ant_SetFwPstdma( ( "[BTCoex], PS-TDMA H2C cmd = 0x%x%08x\n", H2C_Parameter[0], - H2C_Parameter[1]<<24| - H2C_Parameter[2]<<16| - H2C_Parameter[3]<<8| + H2C_Parameter[1] << 24 | + H2C_Parameter[2] << 16 | + H2C_Parameter[3] << 8 | H2C_Parameter[4] ) ); @@ -1361,10 +1361,10 @@ static void halbtc8723b1ant_SetFwPstdma( static void halbtc8723b1ant_PsTdma( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bTurnOn, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, bool bTurnOn, u8 type ) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bWifiBusy = false; u8 rssiAdjustVal = 0; u8 psTdmaByte4Val = 0x50, psTdmaByte0Val = 0x51, psTdmaByte3Val = 0x10; @@ -1435,7 +1435,7 @@ static void halbtc8723b1ant_PsTdma( halbtc8723b1ant_SetFwPstdma( pBtCoexist, psTdmaByte0Val, - 0x3a+nWiFiDurationAdjust, + 0x3a + nWiFiDurationAdjust, 0x03, psTdmaByte3Val, psTdmaByte4Val @@ -1445,7 +1445,7 @@ static void halbtc8723b1ant_PsTdma( halbtc8723b1ant_SetFwPstdma( pBtCoexist, psTdmaByte0Val, - 0x2d+nWiFiDurationAdjust, + 0x2d + nWiFiDurationAdjust, 0x03, psTdmaByte3Val, psTdmaByte4Val @@ -1661,7 +1661,7 @@ static void halbtc8723b1ant_PsTdma( pCoexDm->prePsTdma = pCoexDm->curPsTdma; } -static bool halbtc8723b1ant_IsCommonAction(PBTC_COEXIST pBtCoexist) +static bool halbtc8723b1ant_IsCommonAction(struct btc_coexist *pBtCoexist) { bool bCommon = false, bWifiConnected = false, bWifiBusy = false; @@ -1752,7 +1752,7 @@ static bool halbtc8723b1ant_IsCommonAction(PBTC_COEXIST pBtCoexist) static void halbtc8723b1ant_TdmaDurationAdjustForAcl( - PBTC_COEXIST pBtCoexist, u8 wifiStatus + struct btc_coexist *pBtCoexist, u8 wifiStatus ) { static s32 up, dn, m, n, WaitCount; @@ -1855,7 +1855,7 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl( if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ m = 20; - n = 3*m; + n = 3 * m; up = 0; dn = 0; WaitCount = 0; @@ -1871,7 +1871,7 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl( if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ m = 20; - n = 3*m; + n = 3 * m; up = 0; dn = 0; WaitCount = 0; @@ -1941,7 +1941,7 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl( } static void halbtc8723b1ant_PsTdmaCheckForPowerSaveState( - PBTC_COEXIST pBtCoexist, bool bNewPsState + struct btc_coexist *pBtCoexist, bool bNewPsState ) { u8 lpsMode = 0x0; @@ -1963,7 +1963,7 @@ static void halbtc8723b1ant_PsTdmaCheckForPowerSaveState( } static void halbtc8723b1ant_PowerSaveState( - PBTC_COEXIST pBtCoexist, u8 psType, u8 lpsVal, u8 rpwmVal + struct btc_coexist *pBtCoexist, u8 psType, u8 lpsVal, u8 rpwmVal ) { bool bLowPwrDisable = false; @@ -2011,7 +2011,7 @@ static void halbtc8723b1ant_PowerSaveState( /* Non-Software Coex Mechanism start */ /* */ /* */ -static void halbtc8723b1ant_ActionWifiMultiPort(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_ActionWifiMultiPort(struct btc_coexist *pBtCoexist) { halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -2019,15 +2019,15 @@ static void halbtc8723b1ant_ActionWifiMultiPort(PBTC_COEXIST pBtCoexist) halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); } -static void halbtc8723b1ant_ActionHs(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_ActionHs(struct btc_coexist *pBtCoexist) { halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); } -static void halbtc8723b1ant_ActionBtInquiry(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_ActionBtInquiry(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bWifiConnected = false; bool bApEnable = false; bool bWifiBusy = false; @@ -2067,10 +2067,10 @@ static void halbtc8723b1ant_ActionBtInquiry(PBTC_COEXIST pBtCoexist) } static void halbtc8723b1ant_ActionBtScoHidOnlyBusy( - PBTC_COEXIST pBtCoexist, u8 wifiStatus + struct btc_coexist *pBtCoexist, u8 wifiStatus ) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bWifiConnected = false; pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); @@ -2087,13 +2087,11 @@ static void halbtc8723b1ant_ActionBtScoHidOnlyBusy( } static void halbtc8723b1ant_ActionWifiConnectedBtAclBusy( - PBTC_COEXIST pBtCoexist, u8 wifiStatus + struct btc_coexist *pBtCoexist, u8 wifiStatus ) { - u8 btRssiState; - - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; - btRssiState = halbtc8723b1ant_BtRssiState(2, 28, 0); + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; + halbtc8723b1ant_BtRssiState(2, 28, 0); if ((pCoexSta->lowPriorityRx >= 1000) && (pCoexSta->lowPriorityRx != 65535)) pBtLinkInfo->bSlaveRole = true; @@ -2141,7 +2139,7 @@ static void halbtc8723b1ant_ActionWifiConnectedBtAclBusy( } } -static void halbtc8723b1ant_ActionWifiNotConnected(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_ActionWifiNotConnected(struct btc_coexist *pBtCoexist) { /* power save state */ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -2152,10 +2150,10 @@ static void halbtc8723b1ant_ActionWifiNotConnected(PBTC_COEXIST pBtCoexist) } static void halbtc8723b1ant_ActionWifiNotConnectedScan( - PBTC_COEXIST pBtCoexist + struct btc_coexist *pBtCoexist ) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -2186,10 +2184,10 @@ static void halbtc8723b1ant_ActionWifiNotConnectedScan( } static void halbtc8723b1ant_ActionWifiNotConnectedAssoAuth( - PBTC_COEXIST pBtCoexist + struct btc_coexist *pBtCoexist ) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -2210,9 +2208,9 @@ static void halbtc8723b1ant_ActionWifiNotConnectedAssoAuth( } } -static void halbtc8723b1ant_ActionWifiConnectedScan(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_ActionWifiConnectedScan(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -2243,10 +2241,10 @@ static void halbtc8723b1ant_ActionWifiConnectedScan(PBTC_COEXIST pBtCoexist) } static void halbtc8723b1ant_ActionWifiConnectedSpecialPacket( - PBTC_COEXIST pBtCoexist + struct btc_coexist *pBtCoexist ) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -2267,7 +2265,7 @@ static void halbtc8723b1ant_ActionWifiConnectedSpecialPacket( } } -static void halbtc8723b1ant_ActionWifiConnected(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_ActionWifiConnected(struct btc_coexist *pBtCoexist) { bool bWifiBusy = false; bool bScan = false, bLink = false, bRoam = false; @@ -2387,7 +2385,7 @@ static void halbtc8723b1ant_ActionWifiConnected(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b1ant_RunSwCoexistMechanism(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_RunSwCoexistMechanism(struct btc_coexist *pBtCoexist) { u8 algorithm = 0; @@ -2446,9 +2444,9 @@ static void halbtc8723b1ant_RunSwCoexistMechanism(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b1ant_RunCoexistMechanism(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bWifiConnected = false, bBtHsOn = false; bool bIncreaseScanDevNum = false; bool bBtCtrlAggBufSize = false; @@ -2497,9 +2495,9 @@ static void halbtc8723b1ant_RunCoexistMechanism(PBTC_COEXIST pBtCoexist) BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus ); - numOfWifiLink = wifiLinkStatus>>16; + numOfWifiLink = wifiLinkStatus >> 16; - if ((numOfWifiLink >= 2) || (wifiLinkStatus&WIFI_P2P_GO_CONNECTED)) { + if ((numOfWifiLink >= 2) || (wifiLinkStatus & WIFI_P2P_GO_CONNECTED)) { BTC_PRINT( BTC_MSG_INTERFACE, INTF_NOTIFY, @@ -2579,7 +2577,7 @@ static void halbtc8723b1ant_RunCoexistMechanism(PBTC_COEXIST pBtCoexist) halbtc8723b1ant_ActionWifiConnected(pBtCoexist); } -static void halbtc8723b1ant_InitCoexDm(PBTC_COEXIST pBtCoexist) +static void halbtc8723b1ant_InitCoexDm(struct btc_coexist *pBtCoexist) { /* force to reset coex mechanism */ @@ -2593,7 +2591,7 @@ static void halbtc8723b1ant_InitCoexDm(PBTC_COEXIST pBtCoexist) } static void halbtc8723b1ant_InitHwConfig( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bBackUp, bool bWifiOnly ) @@ -2648,9 +2646,9 @@ static void halbtc8723b1ant_InitHwConfig( /* */ /* extern function start with EXhalbtc8723b1ant_ */ /* */ -void EXhalbtc8723b1ant_PowerOnSetting(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b1ant_PowerOnSetting(struct btc_coexist *pBtCoexist) { - PBTC_BOARD_INFO pBoardInfo = &pBtCoexist->boardInfo; + struct btc_board_info *pBoardInfo = &pBtCoexist->boardInfo; u8 u1Tmp = 0x0; u16 u2Tmp = 0x0; @@ -2658,7 +2656,7 @@ void EXhalbtc8723b1ant_PowerOnSetting(PBTC_COEXIST pBtCoexist) /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ u2Tmp = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x2); - pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x2, u2Tmp|BIT0|BIT1); + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x2, u2Tmp | BIT0 | BIT1); /* set GRAN_BT = 1 */ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); @@ -2700,12 +2698,12 @@ void EXhalbtc8723b1ant_PowerOnSetting(PBTC_COEXIST pBtCoexist) } } -void EXhalbtc8723b1ant_InitHwConfig(PBTC_COEXIST pBtCoexist, bool bWifiOnly) +void EXhalbtc8723b1ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bWifiOnly) { halbtc8723b1ant_InitHwConfig(pBtCoexist, true, bWifiOnly); } -void EXhalbtc8723b1ant_InitCoexDm(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b1ant_InitCoexDm(struct btc_coexist *pBtCoexist) { BTC_PRINT( BTC_MSG_INTERFACE, @@ -2720,11 +2718,11 @@ void EXhalbtc8723b1ant_InitCoexDm(PBTC_COEXIST pBtCoexist) halbtc8723b1ant_QueryBtInfo(pBtCoexist); } -void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist) { - PBTC_BOARD_INFO pBoardInfo = &pBtCoexist->boardInfo; - PBTC_STACK_INFO pStackInfo = &pBtCoexist->stackInfo; - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_board_info *pBoardInfo = &pBtCoexist->boardInfo; + struct btc_stack_info *pStackInfo = &pBtCoexist->stackInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; u8 *cliBuf = pBtCoexist->cliBuf; u8 u1Tmp[4], i, btInfoExt, psTdmaCase = 0; u16 u2Tmp[4]; @@ -2839,7 +2837,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ - wifiRssi-100, btHsRssi-100 + wifiRssi - 100, btHsRssi - 100 ); CL_PRINTF(cliBuf); @@ -2883,11 +2881,11 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "sta/vwifi/hs/p2pGo/p2pGc", \ - ((wifiLinkStatus&WIFI_STA_CONNECTED) ? 1 : 0), - ((wifiLinkStatus&WIFI_AP_CONNECTED) ? 1 : 0), - ((wifiLinkStatus&WIFI_HS_CONNECTED) ? 1 : 0), - ((wifiLinkStatus&WIFI_P2P_GO_CONNECTED) ? 1 : 0), - ((wifiLinkStatus&WIFI_P2P_GC_CONNECTED) ? 1 : 0) + ((wifiLinkStatus & WIFI_STA_CONNECTED) ? 1 : 0), + ((wifiLinkStatus & WIFI_AP_CONNECTED) ? 1 : 0), + ((wifiLinkStatus & WIFI_HS_CONNECTED) ? 1 : 0), + ((wifiLinkStatus & WIFI_P2P_GO_CONNECTED) ? 1 : 0), + ((wifiLinkStatus & WIFI_P2P_GC_CONNECTED) ? 1 : 0) ); CL_PRINTF(cliBuf); @@ -2934,7 +2932,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ - (btInfoExt&BIT0) ? "Basic rate" : "EDR rate" + (btInfoExt & BIT0) ? "Basic rate" : "EDR rate" ); CL_PRINTF(cliBuf); @@ -3046,7 +3044,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) CL_SPRINTF( cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/0x6cc/0x880[29:25]", \ - u1Tmp[0], u4Tmp[0], (u4Tmp[1]&0x3e000000) >> 25 + u1Tmp[0], u4Tmp[0], (u4Tmp[1] & 0x3e000000) >> 25 ); CL_PRINTF(cliBuf); @@ -3058,7 +3056,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x764 / 0x76e", \ - u4Tmp[0], ((u1Tmp[0]&0x20) >> 5), (u4Tmp[1] & 0xffff), u1Tmp[1] + u4Tmp[0], ((u1Tmp[0] & 0x20) >> 5), (u4Tmp[1] & 0xffff), u1Tmp[1] ); CL_PRINTF(cliBuf); @@ -3069,7 +3067,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \ - u4Tmp[0]&0x3, u4Tmp[1]&0xff, u4Tmp[2]&0x3 + u4Tmp[0] & 0x3, u4Tmp[1] & 0xff, u4Tmp[2] & 0x3 ); CL_PRINTF(cliBuf); @@ -3081,10 +3079,10 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \ - ((u1Tmp[0] & 0x8)>>3), + ((u1Tmp[0] & 0x8) >> 3), u1Tmp[1], - ((u4Tmp[0]&0x01800000)>>23), - u1Tmp[2]&0x1 + ((u4Tmp[0] & 0x01800000) >> 23), + u1Tmp[2] & 0x1 ); CL_PRINTF(cliBuf); @@ -3104,7 +3102,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \ - u4Tmp[0]&0xff, u1Tmp[0] + u4Tmp[0] & 0xff, u1Tmp[0] ); CL_PRINTF(cliBuf); @@ -3117,17 +3115,17 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); faOfdm = - ((u4Tmp[0]&0xffff0000) >> 16) + - ((u4Tmp[1]&0xffff0000) >> 16) + + ((u4Tmp[0] & 0xffff0000) >> 16) + + ((u4Tmp[1] & 0xffff0000) >> 16) + (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \ - ((u4Tmp[3]&0xffff0000) >> 16) + (u4Tmp[3] & 0xffff); + ((u4Tmp[3] & 0xffff0000) >> 16) + (u4Tmp[3] & 0xffff); faCck = (u1Tmp[0] << 8) + u1Tmp[1]; CL_SPRINTF( cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \ - u4Tmp[0]&0xffff, faOfdm, faCck + u4Tmp[0] & 0xffff, faOfdm, faCck ); CL_PRINTF(cliBuf); @@ -3183,7 +3181,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) } -void EXhalbtc8723b1ant_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b1ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type) { if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) return; @@ -3209,7 +3207,7 @@ void EXhalbtc8723b1ant_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b1ant_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b1ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type) { if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) return; @@ -3227,7 +3225,7 @@ void EXhalbtc8723b1ant_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b1ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b1ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type) { bool bWifiConnected = false, bBtHsOn = false; u32 wifiLinkStatus = 0; @@ -3283,7 +3281,7 @@ void EXhalbtc8723b1ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) halbtc8723b1ant_QueryBtInfo(pBtCoexist); pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); - numOfWifiLink = wifiLinkStatus>>16; + numOfWifiLink = wifiLinkStatus >> 16; if (numOfWifiLink >= 2) { halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); @@ -3317,7 +3315,7 @@ void EXhalbtc8723b1ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b1ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b1ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type) { bool bWifiConnected = false, bBtHsOn = false; u32 wifiLinkStatus = 0; @@ -3343,7 +3341,7 @@ void EXhalbtc8723b1ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type) } pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); - numOfWifiLink = wifiLinkStatus>>16; + numOfWifiLink = wifiLinkStatus >> 16; if (numOfWifiLink >= 2) { halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, bBtCtrlAggBufSize, aggBufSize); @@ -3374,7 +3372,7 @@ void EXhalbtc8723b1ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b1ant_MediaStatusNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b1ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type) { u8 H2C_Parameter[3] = {0}; u32 wifiBw; @@ -3437,14 +3435,14 @@ void EXhalbtc8723b1ant_MediaStatusNotify(PBTC_COEXIST pBtCoexist, u8 type) ALGO_TRACE_FW_EXEC, ( "[BTCoex], FW write 0x66 = 0x%x\n", - H2C_Parameter[0]<<16 | H2C_Parameter[1]<<8 | H2C_Parameter[2] + H2C_Parameter[0] << 16 | H2C_Parameter[1] << 8 | H2C_Parameter[2] ) ); pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); } -void EXhalbtc8723b1ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b1ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 type) { bool bBtHsOn = false; u32 wifiLinkStatus = 0; @@ -3504,7 +3502,7 @@ void EXhalbtc8723b1ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type) pBtCoexist->fBtcGet( pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus ); - numOfWifiLink = wifiLinkStatus>>16; + numOfWifiLink = wifiLinkStatus >> 16; if (numOfWifiLink >= 2) { halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); @@ -3533,7 +3531,7 @@ void EXhalbtc8723b1ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type) } void EXhalbtc8723b1ant_BtInfoNotify( - PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length + struct btc_coexist *pBtCoexist, u8 *tmpBuf, u8 length ) { u8 btInfo = 0; @@ -3543,7 +3541,7 @@ void EXhalbtc8723b1ant_BtInfoNotify( pCoexSta->bC2hBtInfoReqSent = false; - rspSource = tmpBuf[0]&0xf; + rspSource = tmpBuf[0] & 0xf; if (rspSource >= BT_INFO_SRC_8723B_1ANT_MAX) rspSource = BT_INFO_SRC_8723B_1ANT_WIFI_FW; pCoexSta->btInfoC2hCnt[rspSource]++; @@ -3559,7 +3557,7 @@ void EXhalbtc8723b1ant_BtInfoNotify( pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; if (i == 1) btInfo = tmpBuf[i]; - if (i == length-1) + if (i == length - 1) BTC_PRINT( BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i]) ); @@ -3568,22 +3566,22 @@ void EXhalbtc8723b1ant_BtInfoNotify( } if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rspSource) { - pCoexSta->btRetryCnt = pCoexSta->btInfoC2h[rspSource][2]&0xf; + pCoexSta->btRetryCnt = pCoexSta->btInfoC2h[rspSource][2] & 0xf; if (pCoexSta->btRetryCnt >= 1) pCoexSta->popEventCnt++; - if (pCoexSta->btInfoC2h[rspSource][2]&0x20) + if (pCoexSta->btInfoC2h[rspSource][2] & 0x20) pCoexSta->bC2hBtPage = true; else pCoexSta->bC2hBtPage = false; - pCoexSta->btRssi = pCoexSta->btInfoC2h[rspSource][3]*2-90; + pCoexSta->btRssi = pCoexSta->btInfoC2h[rspSource][3] * 2 - 90; /* pCoexSta->btInfoC2h[rspSource][3]*2+10; */ pCoexSta->btInfoExt = pCoexSta->btInfoC2h[rspSource][4]; - pCoexSta->bBtTxRxMask = (pCoexSta->btInfoC2h[rspSource][2]&0x40); + pCoexSta->bBtTxRxMask = (pCoexSta->btInfoC2h[rspSource][2] & 0x40); pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TX_RX_MASK, &pCoexSta->bBtTxRxMask); if (!pCoexSta->bBtTxRxMask) { @@ -3628,7 +3626,7 @@ void EXhalbtc8723b1ant_BtInfoNotify( pCoexSta->bC2hBtInquiryPage = false; /* set link exist status */ - if (!(btInfo&BT_INFO_8723B_1ANT_B_CONNECTION)) { + if (!(btInfo & BT_INFO_8723B_1ANT_B_CONNECTION)) { pCoexSta->bBtLinkExist = false; pCoexSta->bPanExist = false; pCoexSta->bA2dpExist = false; @@ -3661,7 +3659,7 @@ void EXhalbtc8723b1ant_BtInfoNotify( btInfo = btInfo & 0x1f; /* mask profile bit for connect-ilde identification (for CSR case: A2DP idle --> 0x41) */ - if (!(btInfo&BT_INFO_8723B_1ANT_B_CONNECTION)) { + if (!(btInfo & BT_INFO_8723B_1ANT_B_CONNECTION)) { pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); } else if (btInfo == BT_INFO_8723B_1ANT_B_CONNECTION) { @@ -3669,12 +3667,12 @@ void EXhalbtc8723b1ant_BtInfoNotify( pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); } else if ( - (btInfo&BT_INFO_8723B_1ANT_B_SCO_ESCO) || - (btInfo&BT_INFO_8723B_1ANT_B_SCO_BUSY) + (btInfo & BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (btInfo & BT_INFO_8723B_1ANT_B_SCO_BUSY) ) { pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); - } else if (btInfo&BT_INFO_8723B_1ANT_B_ACL_BUSY) { + } else if (btInfo & BT_INFO_8723B_1ANT_B_ACL_BUSY) { if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) pCoexDm->bAutoTdmaAdjust = false; @@ -3698,7 +3696,7 @@ void EXhalbtc8723b1ant_BtInfoNotify( halbtc8723b1ant_RunCoexistMechanism(pBtCoexist); } -void EXhalbtc8723b1ant_HaltNotify(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b1ant_HaltNotify(struct btc_coexist *pBtCoexist) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); @@ -3713,7 +3711,7 @@ void EXhalbtc8723b1ant_HaltNotify(PBTC_COEXIST pBtCoexist) pBtCoexist->bStopCoexDm = true; } -void EXhalbtc8723b1ant_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) +void EXhalbtc8723b1ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); @@ -3735,7 +3733,7 @@ void EXhalbtc8723b1ant_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) } } -void EXhalbtc8723b1ant_Periodical(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b1ant_Periodical(struct btc_coexist *pBtCoexist) { static u8 disVerInfoCnt; u32 fwVer = 0, btPatchVer = 0; diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.h b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.h index cdffa391bd9d99f181b0bde224908736c8b9c69e..719e19420a3b463de59e0c6c371259e5d7799dcd 100644 --- a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.h +++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.h @@ -15,20 +15,20 @@ #define BT_INFO_8723B_1ANT_B_CONNECTION BIT0 #define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ - (((_BT_INFO_EXT_&BIT0)) ? true : false) + (((_BT_INFO_EXT_ & BIT0)) ? true : false) #define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 #define BT_8723B_1ANT_WIFI_NOISY_THRESH 30 /* max: 255 */ -typedef enum _BT_INFO_SRC_8723B_1ANT { +enum { BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2, BT_INFO_SRC_8723B_1ANT_MAX -} BT_INFO_SRC_8723B_1ANT, *PBT_INFO_SRC_8723B_1ANT; +}; -typedef enum _BT_8723B_1ANT_BT_STATUS { +enum { BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2, @@ -36,9 +36,9 @@ typedef enum _BT_8723B_1ANT_BT_STATUS { BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4, BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, BT_8723B_1ANT_BT_STATUS_MAX -} BT_8723B_1ANT_BT_STATUS, *PBT_8723B_1ANT_BT_STATUS; +}; -typedef enum _BT_8723B_1ANT_WIFI_STATUS { +enum { BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, @@ -46,9 +46,9 @@ typedef enum _BT_8723B_1ANT_WIFI_STATUS { BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, BT_8723B_1ANT_WIFI_STATUS_MAX -} BT_8723B_1ANT_WIFI_STATUS, *PBT_8723B_1ANT_WIFI_STATUS; +}; -typedef enum _BT_8723B_1ANT_COEX_ALGO { +enum { BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0, BT_8723B_1ANT_COEX_ALGO_SCO = 0x1, BT_8723B_1ANT_COEX_ALGO_HID = 0x2, @@ -61,9 +61,9 @@ typedef enum _BT_8723B_1ANT_COEX_ALGO { BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa, BT_8723B_1ANT_COEX_ALGO_MAX = 0xb, -} BT_8723B_1ANT_COEX_ALGO, *PBT_8723B_1ANT_COEX_ALGO; +}; -typedef struct _COEX_DM_8723B_1ANT { +struct coex_dm_8723b_1ant { /* fw mechanism */ bool bCurIgnoreWlanAct; bool bPreIgnoreWlanAct; @@ -116,9 +116,9 @@ typedef struct _COEX_DM_8723B_1ANT { u32 nArpCnt; u8 errorCondition; -} COEX_DM_8723B_1ANT, *PCOEX_DM_8723B_1ANT; +}; -typedef struct _COEX_STA_8723B_1ANT { +struct coex_sta_8723b_1ant { bool bBtLinkExist; bool bScoExist; bool bA2dpExist; @@ -162,24 +162,24 @@ typedef struct _COEX_STA_8723B_1ANT { u8 nCoexTableType; bool bForceLpsOn; -} COEX_STA_8723B_1ANT, *PCOEX_STA_8723B_1ANT; +}; /* */ /* The following is interface which will notify coex module. */ /* */ -void EXhalbtc8723b1ant_PowerOnSetting(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b1ant_InitHwConfig(PBTC_COEXIST pBtCoexist, bool bWifiOnly); -void EXhalbtc8723b1ant_InitCoexDm(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b1ant_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b1ant_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b1ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b1ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b1ant_MediaStatusNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b1ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type); +void EXhalbtc8723b1ant_PowerOnSetting(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b1ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bWifiOnly); +void EXhalbtc8723b1ant_InitCoexDm(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b1ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b1ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b1ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b1ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b1ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b1ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 type); void EXhalbtc8723b1ant_BtInfoNotify( - PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length + struct btc_coexist *pBtCoexist, u8 *tmpBuf, u8 length ); -void EXhalbtc8723b1ant_HaltNotify(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b1ant_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState); -void EXhalbtc8723b1ant_Periodical(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b1ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist); +void EXhalbtc8723b1ant_HaltNotify(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b1ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState); +void EXhalbtc8723b1ant_Periodical(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist); diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c index 2779dba92bab19a641e49aa455317a2b04c78e07..4b570ec75e6733d450ce76a70ea5eb4f8b765870 100644 --- a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c +++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c @@ -15,10 +15,10 @@ do { \ } while (0) /* Global variables, these are static variables */ -static COEX_DM_8723B_2ANT GLCoexDm8723b2Ant; -static PCOEX_DM_8723B_2ANT pCoexDm = &GLCoexDm8723b2Ant; -static COEX_STA_8723B_2ANT GLCoexSta8723b2Ant; -static PCOEX_STA_8723B_2ANT pCoexSta = &GLCoexSta8723b2Ant; +static struct coex_dm_8723b_2ant GLCoexDm8723b2Ant; +static struct coex_dm_8723b_2ant *pCoexDm = &GLCoexDm8723b2Ant; +static struct coex_sta_8723b_2ant GLCoexSta8723b2Ant; +static struct coex_sta_8723b_2ant *pCoexSta = &GLCoexSta8723b2Ant; static const char *const GLBtInfoSrc8723b2Ant[] = { "BT Info[wifi fw]", @@ -44,7 +44,7 @@ static u8 halbtc8723b2ant_BtRssiState( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW) ) { - if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { + if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { btRssiState = BTC_RSSI_STATE_HIGH; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); } else { @@ -70,7 +70,7 @@ static u8 halbtc8723b2ant_BtRssiState( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW) ) { - if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { + if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { btRssiState = BTC_RSSI_STATE_MEDIUM; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); } else { @@ -81,7 +81,7 @@ static u8 halbtc8723b2ant_BtRssiState( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) { - if (btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { + if (btRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { btRssiState = BTC_RSSI_STATE_HIGH; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); } else if (btRssi < rssiThresh) { @@ -108,7 +108,7 @@ static u8 halbtc8723b2ant_BtRssiState( } static u8 halbtc8723b2ant_WifiRssiState( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, u8 index, u8 levelNum, u8 rssiThresh, @@ -125,7 +125,7 @@ static u8 halbtc8723b2ant_WifiRssiState( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW) ) { - if (wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { + if (wifiRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { wifiRssiState = BTC_RSSI_STATE_HIGH; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); } else { @@ -151,7 +151,7 @@ static u8 halbtc8723b2ant_WifiRssiState( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW) ) { - if (wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { + if (wifiRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { wifiRssiState = BTC_RSSI_STATE_MEDIUM; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); } else { @@ -162,7 +162,7 @@ static u8 halbtc8723b2ant_WifiRssiState( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM) ) { - if (wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { + if (wifiRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) { wifiRssiState = BTC_RSSI_STATE_HIGH; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); } else if (wifiRssi < rssiThresh) { @@ -189,7 +189,7 @@ static u8 halbtc8723b2ant_WifiRssiState( } static void halbtc8723b2ant_LimitedRx( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bForceExec, bool bRejApAggPkt, bool bBtCtrlAggBufSize, @@ -212,7 +212,7 @@ static void halbtc8723b2ant_LimitedRx( pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); } -static void halbtc8723b2ant_MonitorBtCtr(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_MonitorBtCtr(struct btc_coexist *pBtCoexist) { u32 regHPTxRx, regLPTxRx, u4Tmp; u32 regHPTx = 0, regHPRx = 0, regLPTx = 0, regLPRx = 0; @@ -222,11 +222,11 @@ static void halbtc8723b2ant_MonitorBtCtr(PBTC_COEXIST pBtCoexist) u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); regHPTx = u4Tmp & bMaskLWord; - regHPRx = (u4Tmp & bMaskHWord)>>16; + regHPRx = (u4Tmp & bMaskHWord) >> 16; u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); regLPTx = u4Tmp & bMaskLWord; - regLPRx = (u4Tmp & bMaskHWord)>>16; + regLPRx = (u4Tmp & bMaskHWord) >> 16; pCoexSta->highPriorityTx = regHPTx; pCoexSta->highPriorityRx = regHPRx; @@ -262,7 +262,7 @@ static void halbtc8723b2ant_MonitorBtCtr(PBTC_COEXIST pBtCoexist) pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); } -static void halbtc8723b2ant_QueryBtInfo(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_QueryBtInfo(struct btc_coexist *pBtCoexist) { u8 H2C_Parameter[1] = {0}; @@ -279,7 +279,7 @@ static void halbtc8723b2ant_QueryBtInfo(PBTC_COEXIST pBtCoexist) pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); } -static bool halbtc8723b2ant_IsWifiStatusChanged(PBTC_COEXIST pBtCoexist) +static bool halbtc8723b2ant_IsWifiStatusChanged(struct btc_coexist *pBtCoexist) { static bool bPreWifiBusy, bPreUnder4way, bPreBtHsOn; bool bWifiBusy = false, bUnder4way = false, bBtHsOn = false; @@ -310,9 +310,9 @@ static bool halbtc8723b2ant_IsWifiStatusChanged(PBTC_COEXIST pBtCoexist) return false; } -static void halbtc8723b2ant_UpdateBtLinkInfo(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_UpdateBtLinkInfo(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bBtHsOn = false; pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); @@ -374,9 +374,9 @@ static void halbtc8723b2ant_UpdateBtLinkInfo(PBTC_COEXIST pBtCoexist) pBtLinkInfo->bHidOnly = false; } -static u8 halbtc8723b2ant_ActionAlgorithm(PBTC_COEXIST pBtCoexist) +static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist) { - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; bool bBtHsOn = false; u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED; u8 numOfDiffProfile = 0; @@ -549,7 +549,7 @@ static u8 halbtc8723b2ant_ActionAlgorithm(PBTC_COEXIST pBtCoexist) } static void halbtc8723b2ant_SetFwDacSwingLevel( - PBTC_COEXIST pBtCoexist, u8 dacSwingLvl + struct btc_coexist *pBtCoexist, u8 dacSwingLvl ) { u8 H2C_Parameter[1] = {0}; @@ -573,7 +573,7 @@ static void halbtc8723b2ant_SetFwDacSwingLevel( } static void halbtc8723b2ant_SetFwDecBtPwr( - PBTC_COEXIST pBtCoexist, u8 decBtPwrLvl + struct btc_coexist *pBtCoexist, u8 decBtPwrLvl ) { u8 H2C_Parameter[1] = {0}; @@ -594,7 +594,7 @@ static void halbtc8723b2ant_SetFwDecBtPwr( } static void halbtc8723b2ant_DecBtPwr( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 decBtPwrLvl + struct btc_coexist *pBtCoexist, bool bForceExec, u8 decBtPwrLvl ) { BTC_PRINT( @@ -628,7 +628,7 @@ static void halbtc8723b2ant_DecBtPwr( } static void halbtc8723b2ant_FwDacSwingLvl( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 fwDacSwingLvl + struct btc_coexist *pBtCoexist, bool bForceExec, u8 fwDacSwingLvl ) { BTC_PRINT( @@ -663,7 +663,7 @@ static void halbtc8723b2ant_FwDacSwingLvl( } static void halbtc8723b2ant_SetSwRfRxLpfCorner( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bRxRfShrinkOn ) { @@ -686,7 +686,7 @@ static void halbtc8723b2ant_SetSwRfRxLpfCorner( } static void halbtc8723b2ant_RfShrink( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bRxRfShrinkOn + struct btc_coexist *pBtCoexist, bool bForceExec, bool bRxRfShrinkOn ) { BTC_PRINT( @@ -720,7 +720,7 @@ static void halbtc8723b2ant_RfShrink( } static void halbtc8723b2ant_SetSwPenaltyTxRateAdaptive( - PBTC_COEXIST pBtCoexist, bool bLowPenaltyRa + struct btc_coexist *pBtCoexist, bool bLowPenaltyRa ) { u8 H2C_Parameter[6] = {0}; @@ -748,7 +748,7 @@ static void halbtc8723b2ant_SetSwPenaltyTxRateAdaptive( } static void halbtc8723b2ant_LowPenaltyRa( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bLowPenaltyRa + struct btc_coexist *pBtCoexist, bool bForceExec, bool bLowPenaltyRa ) { /* return; */ @@ -782,7 +782,7 @@ static void halbtc8723b2ant_LowPenaltyRa( pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; } -static void halbtc8723b2ant_SetDacSwingReg(PBTC_COEXIST pBtCoexist, u32 level) +static void halbtc8723b2ant_SetDacSwingReg(struct btc_coexist *pBtCoexist, u32 level) { u8 val = (u8)level; @@ -795,7 +795,7 @@ static void halbtc8723b2ant_SetDacSwingReg(PBTC_COEXIST pBtCoexist, u32 level) } static void halbtc8723b2ant_SetSwFullTimeDacSwing( - PBTC_COEXIST pBtCoexist, bool bSwDacSwingOn, u32 swDacSwingLvl + struct btc_coexist *pBtCoexist, bool bSwDacSwingOn, u32 swDacSwingLvl ) { if (bSwDacSwingOn) @@ -806,7 +806,7 @@ static void halbtc8723b2ant_SetSwFullTimeDacSwing( static void halbtc8723b2ant_DacSwing( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bForceExec, bool bDacSwingOn, u32 dacSwingLvl @@ -850,7 +850,7 @@ static void halbtc8723b2ant_DacSwing( } static void halbtc8723b2ant_SetAgcTable( - PBTC_COEXIST pBtCoexist, bool bAgcTableEn + struct btc_coexist *pBtCoexist, bool bAgcTableEn ) { u8 rssiAdjustVal = 0; @@ -910,7 +910,7 @@ static void halbtc8723b2ant_SetAgcTable( } static void halbtc8723b2ant_AgcTable( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bAgcTableEn + struct btc_coexist *pBtCoexist, bool bForceExec, bool bAgcTableEn ) { BTC_PRINT( @@ -944,7 +944,7 @@ static void halbtc8723b2ant_AgcTable( } static void halbtc8723b2ant_SetCoexTable( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, u32 val0x6c0, u32 val0x6c4, u32 val0x6c8, @@ -981,7 +981,7 @@ static void halbtc8723b2ant_SetCoexTable( } static void halbtc8723b2ant_CoexTable( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bForceExec, u32 val0x6c0, u32 val0x6c4, @@ -1047,7 +1047,7 @@ static void halbtc8723b2ant_CoexTable( } static void halbtc8723b2ant_CoexTableWithType( - PBTC_COEXIST pBtCoexist, bool bForceExec, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, u8 type ) { switch (type) { @@ -1096,7 +1096,7 @@ static void halbtc8723b2ant_CoexTableWithType( } static void halbtc8723b2ant_SetFwIgnoreWlanAct( - PBTC_COEXIST pBtCoexist, bool bEnable + struct btc_coexist *pBtCoexist, bool bEnable ) { u8 H2C_Parameter[1] = {0}; @@ -1117,7 +1117,7 @@ static void halbtc8723b2ant_SetFwIgnoreWlanAct( } static void halbtc8723b2ant_IgnoreWlanAct( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bEnable + struct btc_coexist *pBtCoexist, bool bForceExec, bool bEnable ) { BTC_PRINT( @@ -1145,7 +1145,7 @@ static void halbtc8723b2ant_IgnoreWlanAct( } static void halbtc8723b2ant_SetFwPstdma( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, u8 byte1, u8 byte2, u8 byte3, @@ -1173,9 +1173,9 @@ static void halbtc8723b2ant_SetFwPstdma( ( "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", H2C_Parameter[0], - H2C_Parameter[1]<<24| - H2C_Parameter[2]<<16| - H2C_Parameter[3]<<8| + H2C_Parameter[1] << 24 | + H2C_Parameter[2] << 16 | + H2C_Parameter[3] << 8 | H2C_Parameter[4] ) ); @@ -1184,7 +1184,7 @@ static void halbtc8723b2ant_SetFwPstdma( } static void halbtc8723b2ant_SwMechanism1( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bShrinkRxLPF, bool bLowPenaltyRA, bool bLimitedDIG, @@ -1196,7 +1196,7 @@ static void halbtc8723b2ant_SwMechanism1( } static void halbtc8723b2ant_SwMechanism2( - PBTC_COEXIST pBtCoexist, + struct btc_coexist *pBtCoexist, bool bAGCTableShift, bool bADCBackOff, bool bSWDACSwing, @@ -1208,10 +1208,10 @@ static void halbtc8723b2ant_SwMechanism2( } static void halbtc8723b2ant_SetAntPath( - PBTC_COEXIST pBtCoexist, u8 antPosType, bool bInitHwCfg, bool bWifiOff + struct btc_coexist *pBtCoexist, u8 antPosType, bool bInitHwCfg, bool bWifiOff ) { - PBTC_BOARD_INFO pBoardInfo = &pBtCoexist->boardInfo; + struct btc_board_info *pBoardInfo = &pBtCoexist->boardInfo; u32 fwVer = 0, u4Tmp = 0; bool bPgExtSwitch = false; bool bUseExtSwitch = false; @@ -1302,7 +1302,7 @@ static void halbtc8723b2ant_SetAntPath( } static void halbtc8723b2ant_PsTdma( - PBTC_COEXIST pBtCoexist, bool bForceExec, bool bTurnOn, u8 type + struct btc_coexist *pBtCoexist, bool bForceExec, bool bTurnOn, u8 type ) { BTC_PRINT( @@ -1434,7 +1434,7 @@ static void halbtc8723b2ant_PsTdma( pCoexDm->prePsTdma = pCoexDm->curPsTdma; } -static void halbtc8723b2ant_CoexAllOff(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_CoexAllOff(struct btc_coexist *pBtCoexist) { /* fw all off */ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); @@ -1450,7 +1450,7 @@ static void halbtc8723b2ant_CoexAllOff(PBTC_COEXIST pBtCoexist) halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); } -static void halbtc8723b2ant_InitCoexDm(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_InitCoexDm(struct btc_coexist *pBtCoexist) { /* force to reset coex mechanism */ @@ -1462,7 +1462,7 @@ static void halbtc8723b2ant_InitCoexDm(PBTC_COEXIST pBtCoexist) halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); } -static void halbtc8723b2ant_ActionBtInquiry(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionBtInquiry(struct btc_coexist *pBtCoexist) { bool bWifiConnected = false; bool bLowPwrDisable = true; @@ -1490,7 +1490,7 @@ static void halbtc8723b2ant_ActionBtInquiry(PBTC_COEXIST pBtCoexist) halbtc8723b2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_AUX, false, false); } -static bool halbtc8723b2ant_IsCommonAction(PBTC_COEXIST pBtCoexist) +static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist) { u8 btRssiState = BTC_RSSI_STATE_HIGH; bool bCommon = false, bWifiConnected = false, bWifiBusy = false; @@ -1591,7 +1591,7 @@ static bool halbtc8723b2ant_IsCommonAction(PBTC_COEXIST pBtCoexist) } static void halbtc8723b2ant_TdmaDurationAdjust( - PBTC_COEXIST pBtCoexist, bool bScoHid, bool bTxPause, u8 maxInterval + struct btc_coexist *pBtCoexist, bool bScoHid, bool bTxPause, u8 maxInterval ) { static s32 up, dn, m, n, WaitCount; @@ -1691,7 +1691,7 @@ static void halbtc8723b2ant_TdmaDurationAdjust( if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ m = 20; - n = 3*m; + n = 3 * m; up = 0; dn = 0; WaitCount = 0; @@ -1707,7 +1707,7 @@ static void halbtc8723b2ant_TdmaDurationAdjust( if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ m = 20; - n = 3*m; + n = 3 * m; up = 0; dn = 0; WaitCount = 0; @@ -2041,7 +2041,7 @@ static void halbtc8723b2ant_TdmaDurationAdjust( } /* SCO only or SCO+PAN(HS) */ -static void halbtc8723b2ant_ActionSco(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionSco(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2096,7 +2096,7 @@ static void halbtc8723b2ant_ActionSco(PBTC_COEXIST pBtCoexist) } -static void halbtc8723b2ant_ActionHid(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionHid(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2157,7 +2157,7 @@ static void halbtc8723b2ant_ActionHid(PBTC_COEXIST pBtCoexist) } /* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ -static void halbtc8723b2ant_ActionA2dp(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionA2dp(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, wifiRssiState1, btRssiState; u32 wifiBw; @@ -2238,7 +2238,7 @@ static void halbtc8723b2ant_ActionA2dp(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b2ant_ActionA2dpPanHs(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionA2dpPanHs(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2288,7 +2288,7 @@ static void halbtc8723b2ant_ActionA2dpPanHs(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b2ant_ActionPanEdr(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionPanEdr(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2346,7 +2346,7 @@ static void halbtc8723b2ant_ActionPanEdr(PBTC_COEXIST pBtCoexist) /* PAN(HS) only */ -static void halbtc8723b2ant_ActionPanHs(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionPanHs(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2396,7 +2396,7 @@ static void halbtc8723b2ant_ActionPanHs(PBTC_COEXIST pBtCoexist) } /* PAN(EDR)+A2DP */ -static void halbtc8723b2ant_ActionPanEdrA2dp(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionPanEdrA2dp(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2457,7 +2457,7 @@ static void halbtc8723b2ant_ActionPanEdrA2dp(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b2ant_ActionPanEdrHid(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionPanEdrHid(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2521,7 +2521,7 @@ static void halbtc8723b2ant_ActionPanEdrHid(PBTC_COEXIST pBtCoexist) } /* HID+A2DP+PAN(EDR) */ -static void halbtc8723b2ant_ActionHidA2dpPanEdr(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionHidA2dpPanEdr(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2581,7 +2581,7 @@ static void halbtc8723b2ant_ActionHidA2dpPanEdr(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b2ant_ActionHidA2dp(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_ActionHidA2dp(struct btc_coexist *pBtCoexist) { u8 wifiRssiState, btRssiState; u32 wifiBw; @@ -2656,7 +2656,7 @@ static void halbtc8723b2ant_ActionHidA2dp(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b2ant_RunCoexistMechanism(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist) { u8 algorithm = 0; @@ -2755,7 +2755,7 @@ static void halbtc8723b2ant_RunCoexistMechanism(PBTC_COEXIST pBtCoexist) } } -static void halbtc8723b2ant_WifiOffHwCfg(PBTC_COEXIST pBtCoexist) +static void halbtc8723b2ant_WifiOffHwCfg(struct btc_coexist *pBtCoexist) { bool bIsInMpMode = false; u8 H2C_Parameter[2] = {0}; @@ -2780,7 +2780,7 @@ static void halbtc8723b2ant_WifiOffHwCfg(PBTC_COEXIST pBtCoexist) pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); /* BT select s0/s1 is controlled by WiFi */ } -static void halbtc8723b2ant_InitHwConfig(PBTC_COEXIST pBtCoexist, bool bBackUp) +static void halbtc8723b2ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bBackUp) { u8 u1Tmp = 0; @@ -2814,9 +2814,9 @@ static void halbtc8723b2ant_InitHwConfig(PBTC_COEXIST pBtCoexist, bool bBackUp) /* */ /* extern function start with EXhalbtc8723b2ant_ */ /* */ -void EXhalbtc8723b2ant_PowerOnSetting(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b2ant_PowerOnSetting(struct btc_coexist *pBtCoexist) { - PBTC_BOARD_INFO pBoardInfo = &pBtCoexist->boardInfo; + struct btc_board_info *pBoardInfo = &pBtCoexist->boardInfo; u8 u1Tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ u16 u2Tmp = 0x0; @@ -2824,7 +2824,7 @@ void EXhalbtc8723b2ant_PowerOnSetting(PBTC_COEXIST pBtCoexist) /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ u2Tmp = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x2); - pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x2, u2Tmp|BIT0|BIT1); + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x2, u2Tmp | BIT0 | BIT1); /* set GRAN_BT = 1 */ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); @@ -2866,23 +2866,23 @@ void EXhalbtc8723b2ant_PowerOnSetting(PBTC_COEXIST pBtCoexist) } } -void EXhalbtc8723b2ant_InitHwConfig(PBTC_COEXIST pBtCoexist, bool bWifiOnly) +void EXhalbtc8723b2ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bWifiOnly) { halbtc8723b2ant_InitHwConfig(pBtCoexist, true); } -void EXhalbtc8723b2ant_InitCoexDm(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b2ant_InitCoexDm(struct btc_coexist *pBtCoexist) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); halbtc8723b2ant_InitCoexDm(pBtCoexist); } -void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b2ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist) { - PBTC_BOARD_INFO pBoardInfo = &pBtCoexist->boardInfo; - PBTC_STACK_INFO pStackInfo = &pBtCoexist->stackInfo; - PBTC_BT_LINK_INFO pBtLinkInfo = &pBtCoexist->btLinkInfo; + struct btc_board_info *pBoardInfo = &pBtCoexist->boardInfo; + struct btc_stack_info *pStackInfo = &pBtCoexist->stackInfo; + struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo; u8 *cliBuf = pBtCoexist->cliBuf; u8 u1Tmp[4], i, btInfoExt, psTdmaCase = 0; u32 u4Tmp[4]; @@ -3019,7 +3019,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ - (btInfoExt&BIT0) ? "Basic rate" : "EDR rate" + (btInfoExt & BIT0) ? "Basic rate" : "EDR rate" ); CL_PRINTF(cliBuf); @@ -3126,7 +3126,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x880[29:25]", \ u1Tmp[0], - (u4Tmp[0]&0x3e000000) >> 25 + (u4Tmp[0] & 0x3e000000) >> 25 ); CL_PRINTF(cliBuf); @@ -3139,7 +3139,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x765", \ u4Tmp[0], - ((u1Tmp[0]&0x20)>>5), + ((u1Tmp[0] & 0x20) >> 5), u1Tmp[1] ); CL_PRINTF(cliBuf); @@ -3151,9 +3151,9 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \ - u4Tmp[0]&0x3, - u4Tmp[1]&0xff, - u4Tmp[2]&0x3 + u4Tmp[0] & 0x3, + u4Tmp[1] & 0xff, + u4Tmp[2] & 0x3 ); CL_PRINTF(cliBuf); @@ -3166,10 +3166,10 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \ - ((u1Tmp[0] & 0x8)>>3), + ((u1Tmp[0] & 0x8) >> 3), u1Tmp[1], - ((u4Tmp[0]&0x01800000)>>23), - u1Tmp[2]&0x1 + ((u4Tmp[0] & 0x01800000) >> 23), + u1Tmp[2] & 0x1 ); CL_PRINTF(cliBuf); @@ -3190,7 +3190,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \ - u4Tmp[0]&0xff, + u4Tmp[0] & 0xff, u1Tmp[0] ); CL_PRINTF(cliBuf); @@ -3204,10 +3204,10 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); faOfdm = - ((u4Tmp[0]&0xffff0000) >> 16) + - ((u4Tmp[1]&0xffff0000) >> 16) + + ((u4Tmp[0] & 0xffff0000) >> 16) + + ((u4Tmp[1] & 0xffff0000) >> 16) + (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \ - ((u4Tmp[3]&0xffff0000) >> 16) + + ((u4Tmp[3] & 0xffff0000) >> 16) + (u4Tmp[3] & 0xffff); faCck = (u1Tmp[0] << 8) + u1Tmp[1]; @@ -3216,7 +3216,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \ - u4Tmp[0]&0xffff, + u4Tmp[0] & 0xffff, faOfdm, faCck ); @@ -3259,7 +3259,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist) } -void EXhalbtc8723b2ant_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type) { if (BTC_IPS_ENTER == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); @@ -3276,7 +3276,7 @@ void EXhalbtc8723b2ant_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b2ant_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b2ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type) { if (BTC_LPS_ENABLE == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); @@ -3287,7 +3287,7 @@ void EXhalbtc8723b2ant_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b2ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b2ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type) { if (BTC_SCAN_START == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); @@ -3296,7 +3296,7 @@ void EXhalbtc8723b2ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b2ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b2ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type) { if (BTC_ASSOCIATE_START == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); @@ -3305,7 +3305,7 @@ void EXhalbtc8723b2ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type) } } -void EXhalbtc8723b2ant_MediaStatusNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b2ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type) { u8 H2C_Parameter[3] = {0}; u32 wifiBw; @@ -3344,14 +3344,14 @@ void EXhalbtc8723b2ant_MediaStatusNotify(PBTC_COEXIST pBtCoexist, u8 type) ALGO_TRACE_FW_EXEC, ( "[BTCoex], FW write 0x66 = 0x%x\n", - H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2] + H2C_Parameter[0] << 16 | H2C_Parameter[1] << 8 | H2C_Parameter[2] ) ); pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); } -void EXhalbtc8723b2ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtc8723b2ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 type) { if (type == BTC_PACKET_DHCP) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); @@ -3359,7 +3359,7 @@ void EXhalbtc8723b2ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type) } void EXhalbtc8723b2ant_BtInfoNotify( - PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length + struct btc_coexist *pBtCoexist, u8 *tmpBuf, u8 length ) { u8 btInfo = 0; @@ -3369,7 +3369,7 @@ void EXhalbtc8723b2ant_BtInfoNotify( pCoexSta->bC2hBtInfoReqSent = false; - rspSource = tmpBuf[0]&0xf; + rspSource = tmpBuf[0] & 0xf; if (rspSource >= BT_INFO_SRC_8723B_2ANT_MAX) rspSource = BT_INFO_SRC_8723B_2ANT_WIFI_FW; @@ -3381,7 +3381,7 @@ void EXhalbtc8723b2ant_BtInfoNotify( if (i == 1) btInfo = tmpBuf[i]; - if (i == length-1) { + if (i == length - 1) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); } else { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); @@ -3394,13 +3394,13 @@ void EXhalbtc8723b2ant_BtInfoNotify( } if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rspSource) { - pCoexSta->btRetryCnt = pCoexSta->btInfoC2h[rspSource][2]&0xf; /* [3:0] */ + pCoexSta->btRetryCnt = pCoexSta->btInfoC2h[rspSource][2] & 0xf; /* [3:0] */ - pCoexSta->btRssi = pCoexSta->btInfoC2h[rspSource][3]*2+10; + pCoexSta->btRssi = pCoexSta->btInfoC2h[rspSource][3] * 2 + 10; pCoexSta->btInfoExt = pCoexSta->btInfoC2h[rspSource][4]; - pCoexSta->bBtTxRxMask = (pCoexSta->btInfoC2h[rspSource][2]&0x40); + pCoexSta->bBtTxRxMask = (pCoexSta->btInfoC2h[rspSource][2] & 0x40); pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TX_RX_MASK, &pCoexSta->bBtTxRxMask); if (pCoexSta->bBtTxRxMask) { /* BT into is responded by BT FW and BT RF REG 0x3C != 0x01 => Need to switch BT TRx Mask */ @@ -3435,7 +3435,7 @@ void EXhalbtc8723b2ant_BtInfoNotify( pCoexSta->bC2hBtInquiryPage = false; /* set link exist status */ - if (!(btInfo&BT_INFO_8723B_2ANT_B_CONNECTION)) { + if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) { pCoexSta->bBtLinkExist = false; pCoexSta->bPanExist = false; pCoexSta->bA2dpExist = false; @@ -3463,19 +3463,19 @@ void EXhalbtc8723b2ant_BtInfoNotify( halbtc8723b2ant_UpdateBtLinkInfo(pBtCoexist); - if (!(btInfo&BT_INFO_8723B_2ANT_B_CONNECTION)) { + if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) { pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); } else if (btInfo == BT_INFO_8723B_2ANT_B_CONNECTION) { /* connection exists but no busy */ pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); } else if ( - (btInfo&BT_INFO_8723B_2ANT_B_SCO_ESCO) || - (btInfo&BT_INFO_8723B_2ANT_B_SCO_BUSY) + (btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) || + (btInfo & BT_INFO_8723B_2ANT_B_SCO_BUSY) ) { pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_SCO_BUSY; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); - } else if (btInfo&BT_INFO_8723B_2ANT_B_ACL_BUSY) { + } else if (btInfo & BT_INFO_8723B_2ANT_B_ACL_BUSY) { pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_ACL_BUSY; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); } else { @@ -3503,7 +3503,7 @@ void EXhalbtc8723b2ant_BtInfoNotify( halbtc8723b2ant_RunCoexistMechanism(pBtCoexist); } -void EXhalbtc8723b2ant_HaltNotify(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b2ant_HaltNotify(struct btc_coexist *pBtCoexist) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); @@ -3514,7 +3514,7 @@ void EXhalbtc8723b2ant_HaltNotify(PBTC_COEXIST pBtCoexist) EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); } -void EXhalbtc8723b2ant_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) +void EXhalbtc8723b2ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); @@ -3528,7 +3528,7 @@ void EXhalbtc8723b2ant_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) } } -void EXhalbtc8723b2ant_Periodical(PBTC_COEXIST pBtCoexist) +void EXhalbtc8723b2ant_Periodical(struct btc_coexist *pBtCoexist) { static u8 disVerInfoCnt; u32 fwVer = 0, btPatchVer = 0; diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.h b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.h index df973fcda48cf07ab26cdf5f9e1f7ecd64ce9f02..80db3ba34a3f44c80888f1c3d0f48939ca9cae51 100644 --- a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.h +++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.h @@ -16,14 +16,14 @@ #define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 -typedef enum _BT_INFO_SRC_8723B_2ANT { +enum { BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2, BT_INFO_SRC_8723B_2ANT_MAX -} BT_INFO_SRC_8723B_2ANT, *PBT_INFO_SRC_8723B_2ANT; +}; -typedef enum _BT_8723B_2ANT_BT_STATUS { +enum { BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2, @@ -31,9 +31,9 @@ typedef enum _BT_8723B_2ANT_BT_STATUS { BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4, BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, BT_8723B_2ANT_BT_STATUS_MAX -} BT_8723B_2ANT_BT_STATUS, *PBT_8723B_2ANT_BT_STATUS; +}; -typedef enum _BT_8723B_2ANT_COEX_ALGO { +enum { BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0, BT_8723B_2ANT_COEX_ALGO_SCO = 0x1, BT_8723B_2ANT_COEX_ALGO_HID = 0x2, @@ -46,9 +46,9 @@ typedef enum _BT_8723B_2ANT_COEX_ALGO { BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa, BT_8723B_2ANT_COEX_ALGO_MAX = 0xb, -} BT_8723B_2ANT_COEX_ALGO, *PBT_8723B_2ANT_COEX_ALGO; +}; -typedef struct _COEX_DM_8723B_2ANT { +struct coex_dm_8723b_2ant { /* fw mechanism */ u8 preBtDecPwrLvl; u8 curBtDecPwrLvl; @@ -99,9 +99,9 @@ typedef struct _COEX_DM_8723B_2ANT { bool bNeedRecover0x948; u32 backup0x948; -} COEX_DM_8723B_2ANT, *PCOEX_DM_8723B_2ANT; +}; -typedef struct _COEX_STA_8723B_2ANT { +struct coex_sta_8723b_2ant { bool bBtLinkExist; bool bScoExist; bool bA2dpExist; @@ -124,24 +124,24 @@ typedef struct _COEX_STA_8723B_2ANT { bool bC2hBtInquiryPage; u8 btRetryCnt; u8 btInfoExt; -} COEX_STA_8723B_2ANT, *PCOEX_STA_8723B_2ANT; +}; /* */ /* The following is interface which will notify coex module. */ /* */ -void EXhalbtc8723b2ant_PowerOnSetting(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b2ant_InitHwConfig(PBTC_COEXIST pBtCoexist, bool bWifiOnly); -void EXhalbtc8723b2ant_InitCoexDm(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b2ant_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b2ant_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b2ant_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b2ant_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b2ant_MediaStatusNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtc8723b2ant_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 type); +void EXhalbtc8723b2ant_PowerOnSetting(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b2ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bWifiOnly); +void EXhalbtc8723b2ant_InitCoexDm(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b2ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b2ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b2ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b2ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtc8723b2ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 type); void EXhalbtc8723b2ant_BtInfoNotify( - PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length + struct btc_coexist *pBtCoexist, u8 *tmpBuf, u8 length ); -void EXhalbtc8723b2ant_HaltNotify(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b2ant_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState); -void EXhalbtc8723b2ant_Periodical(PBTC_COEXIST pBtCoexist); -void EXhalbtc8723b2ant_DisplayCoexInfo(PBTC_COEXIST pBtCoexist); +void EXhalbtc8723b2ant_HaltNotify(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b2ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState); +void EXhalbtc8723b2ant_Periodical(struct btc_coexist *pBtCoexist); +void EXhalbtc8723b2ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist); diff --git a/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h b/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h index c758d143c57f3b0fac2cb808cc9a8c6d5e2cc7bc..7b2d94a33d9cda216315e9a9749affb5956afbd0 100644 --- a/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h +++ b/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h @@ -44,31 +44,31 @@ #define BTC_ANT_WIFI_AT_CPL_MAIN 0 #define BTC_ANT_WIFI_AT_CPL_AUX 1 -typedef enum _BTC_POWERSAVE_TYPE { +enum { BTC_PS_WIFI_NATIVE = 0, /* wifi original power save behavior */ BTC_PS_LPS_ON = 1, BTC_PS_LPS_OFF = 2, BTC_PS_MAX -} BTC_POWERSAVE_TYPE, *PBTC_POWERSAVE_TYPE; +}; -typedef enum _BTC_BT_REG_TYPE { +enum { BTC_BT_REG_RF = 0, BTC_BT_REG_MODEM = 1, BTC_BT_REG_BLUEWIZE = 2, BTC_BT_REG_VENDOR = 3, BTC_BT_REG_LE = 4, BTC_BT_REG_MAX -} BTC_BT_REG_TYPE, *PBTC_BT_REG_TYPE; +}; -typedef enum _BTC_CHIP_INTERFACE { +enum btc_chip_interface { BTC_INTF_UNKNOWN = 0, BTC_INTF_PCI = 1, BTC_INTF_USB = 2, BTC_INTF_SDIO = 3, BTC_INTF_MAX -} BTC_CHIP_INTERFACE, *PBTC_CHIP_INTERFACE; +}; -typedef enum _BTC_CHIP_TYPE { +enum { BTC_CHIP_UNDEF = 0, BTC_CHIP_CSR_BC4 = 1, BTC_CHIP_CSR_BC8 = 2, @@ -76,13 +76,13 @@ typedef enum _BTC_CHIP_TYPE { BTC_CHIP_RTL8821 = 4, BTC_CHIP_RTL8723B = 5, BTC_CHIP_MAX -} BTC_CHIP_TYPE, *PBTC_CHIP_TYPE; +}; -typedef enum _BTC_MSG_TYPE { +enum { BTC_MSG_INTERFACE = 0x0, BTC_MSG_ALGORITHM = 0x1, BTC_MSG_MAX -} BTC_MSG_TYPE; +}; extern u32 GLBtcDbgType[]; /* following is for BTC_MSG_INTERFACE */ @@ -120,14 +120,6 @@ extern u32 GLBtcDbgType[]; DbgPrint printstr;\ } -#define BTC_PRINT_F(dbgtype, dbgflag, printstr)\ -{\ - if (GLBtcDbgType[dbgtype] & dbgflag) {\ - DbgPrint("%s(): ", __func__);\ - DbgPrint printstr;\ - } \ -} - #define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\ {\ if (GLBtcDbgType[dbgtype] & dbgflag) {\ @@ -164,7 +156,7 @@ extern u32 GLBtcDbgType[]; no_printk("%s %p %zu", _TitleString, _HexData, _HexDataLen) #endif -typedef struct _BTC_BOARD_INFO { +struct btc_board_info { /* The following is some board information */ u8 btChipType; u8 pgAntNum; /* pg ant number */ @@ -172,19 +164,9 @@ typedef struct _BTC_BOARD_INFO { u8 btdmAntPos; /* Bryant Add to indicate Antenna Position for (pgAntNum = 2) && (btdmAntNum = 1) (DPDT+1Ant case) */ u8 singleAntPath; /* current used for 8723b only, 1 =>s0, 0 =>s1 */ /* bool bBtExist; */ -} BTC_BOARD_INFO, *PBTC_BOARD_INFO; - -typedef enum _BTC_DBG_OPCODE { - BTC_DBG_SET_COEX_NORMAL = 0x0, - BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, - BTC_DBG_SET_COEX_BT_ONLY = 0x2, - BTC_DBG_SET_COEX_DEC_BT_PWR = 0x3, - BTC_DBG_SET_COEX_BT_AFH_MAP = 0x4, - BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT = 0x5, - BTC_DBG_MAX -} BTC_DBG_OPCODE, *PBTC_DBG_OPCODE; - -typedef enum _BTC_RSSI_STATE { +}; + +enum { BTC_RSSI_STATE_HIGH = 0x0, BTC_RSSI_STATE_MEDIUM = 0x1, BTC_RSSI_STATE_LOW = 0x2, @@ -192,51 +174,32 @@ typedef enum _BTC_RSSI_STATE { BTC_RSSI_STATE_STAY_MEDIUM = 0x4, BTC_RSSI_STATE_STAY_LOW = 0x5, BTC_RSSI_MAX -} BTC_RSSI_STATE, *PBTC_RSSI_STATE; +}; #define BTC_RSSI_HIGH(_rssi_) ((_rssi_ == BTC_RSSI_STATE_HIGH || _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false) #define BTC_RSSI_MEDIUM(_rssi_) ((_rssi_ == BTC_RSSI_STATE_MEDIUM || _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false) #define BTC_RSSI_LOW(_rssi_) ((_rssi_ == BTC_RSSI_STATE_LOW || _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false) -typedef enum _BTC_WIFI_ROLE { - BTC_ROLE_STATION = 0x0, - BTC_ROLE_AP = 0x1, - BTC_ROLE_IBSS = 0x2, - BTC_ROLE_HS_MODE = 0x3, - BTC_ROLE_MAX -} BTC_WIFI_ROLE, *PBTC_WIFI_ROLE; - -typedef enum _BTC_WIFI_BW_MODE { +enum { BTC_WIFI_BW_LEGACY = 0x0, BTC_WIFI_BW_HT20 = 0x1, BTC_WIFI_BW_HT40 = 0x2, BTC_WIFI_BW_MAX -} BTC_WIFI_BW_MODE, *PBTC_WIFI_BW_MODE; +}; -typedef enum _BTC_WIFI_TRAFFIC_DIR { +enum { BTC_WIFI_TRAFFIC_TX = 0x0, BTC_WIFI_TRAFFIC_RX = 0x1, BTC_WIFI_TRAFFIC_MAX -} BTC_WIFI_TRAFFIC_DIR, *PBTC_WIFI_TRAFFIC_DIR; +}; -typedef enum _BTC_WIFI_PNP { +enum { BTC_WIFI_PNP_WAKE_UP = 0x0, BTC_WIFI_PNP_SLEEP = 0x1, BTC_WIFI_PNP_MAX -} BTC_WIFI_PNP, *PBTC_WIFI_PNP; - -/* for 8723b-d cut large current issue */ -typedef enum _BT_WIFI_COEX_STATE { - BTC_WIFI_STAT_INIT, - BTC_WIFI_STAT_IQK, - BTC_WIFI_STAT_NORMAL_OFF, - BTC_WIFI_STAT_MP_OFF, - BTC_WIFI_STAT_NORMAL, - BTC_WIFI_STAT_ANT_DIV, - BTC_WIFI_STAT_MAX -} BT_WIFI_COEX_STATE, *PBT_WIFI_COEX_STATE; +}; /* defined for BFP_BTC_GET */ -typedef enum _BTC_GET_TYPE { +enum { /* type bool */ BTC_GET_BL_HS_OPERATION, BTC_GET_BL_HS_CONNECTING, @@ -275,10 +238,10 @@ typedef enum _BTC_GET_TYPE { BTC_GET_U1_LPS_MODE, BTC_GET_MAX -} BTC_GET_TYPE, *PBTC_GET_TYPE; +}; /* defined for BFP_BTC_SET */ -typedef enum _BTC_SET_TYPE { +enum { /* type bool */ BTC_SET_BL_BT_DISABLE, BTC_SET_BL_BT_TRAFFIC_BUSY, @@ -316,65 +279,58 @@ typedef enum _BTC_SET_TYPE { BTC_SET_ACT_CTRL_8723B_ANT, /* */ BTC_SET_MAX -} BTC_SET_TYPE, *PBTC_SET_TYPE; +}; -typedef enum _BTC_DBG_DISP_TYPE { +enum { BTC_DBG_DISP_COEX_STATISTICS = 0x0, BTC_DBG_DISP_BT_LINK_INFO = 0x1, BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x2, BTC_DBG_DISP_MAX -} BTC_DBG_DISP_TYPE, *PBTC_DBG_DISP_TYPE; +}; -typedef enum _BTC_NOTIFY_TYPE_IPS { +enum { BTC_IPS_LEAVE = 0x0, BTC_IPS_ENTER = 0x1, BTC_IPS_MAX -} BTC_NOTIFY_TYPE_IPS, *PBTC_NOTIFY_TYPE_IPS; +}; -typedef enum _BTC_NOTIFY_TYPE_LPS { +enum { BTC_LPS_DISABLE = 0x0, BTC_LPS_ENABLE = 0x1, BTC_LPS_MAX -} BTC_NOTIFY_TYPE_LPS, *PBTC_NOTIFY_TYPE_LPS; +}; -typedef enum _BTC_NOTIFY_TYPE_SCAN { +enum { BTC_SCAN_FINISH = 0x0, BTC_SCAN_START = 0x1, BTC_SCAN_MAX -} BTC_NOTIFY_TYPE_SCAN, *PBTC_NOTIFY_TYPE_SCAN; +}; -typedef enum _BTC_NOTIFY_TYPE_ASSOCIATE { +enum { BTC_ASSOCIATE_FINISH = 0x0, BTC_ASSOCIATE_START = 0x1, BTC_ASSOCIATE_MAX -} BTC_NOTIFY_TYPE_ASSOCIATE, *PBTC_NOTIFY_TYPE_ASSOCIATE; +}; -typedef enum _BTC_NOTIFY_TYPE_MEDIA_STATUS { +enum { BTC_MEDIA_DISCONNECT = 0x0, BTC_MEDIA_CONNECT = 0x1, BTC_MEDIA_MAX -} BTC_NOTIFY_TYPE_MEDIA_STATUS, *PBTC_NOTIFY_TYPE_MEDIA_STATUS; +}; -typedef enum _BTC_NOTIFY_TYPE_SPECIAL_PACKET { +enum { BTC_PACKET_UNKNOWN = 0x0, BTC_PACKET_DHCP = 0x1, BTC_PACKET_ARP = 0x2, BTC_PACKET_EAPOL = 0x3, BTC_PACKET_MAX -} BTC_NOTIFY_TYPE_SPECIAL_PACKET, *PBTC_NOTIFY_TYPE_SPECIAL_PACKET; - -typedef enum _BTC_NOTIFY_TYPE_STACK_OPERATION { - BTC_STACK_OP_NONE = 0x0, - BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, - BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, - BTC_STACK_OP_MAX -} BTC_NOTIFY_TYPE_STACK_OPERATION, *PBTC_NOTIFY_TYPE_STACK_OPERATION; +}; /* Bryant Add */ -typedef enum _BTC_ANTENNA_POS { +enum { BTC_ANTENNA_AT_MAIN_PORT = 0x1, BTC_ANTENNA_AT_AUX_PORT = 0x2, -} BTC_ANTENNA_POS, *PBTC_ANTENNA_POS; +}; typedef u8 (*BFP_BTC_R1)(void *pBtcContext, u32 RegAddr); typedef u16(*BFP_BTC_R2)(void *pBtcContext, u32 RegAddr); @@ -409,7 +365,7 @@ typedef void (*BFP_BTC_SET_BT_REG)( typedef u32 (*BFP_BTC_GET_BT_REG)(void *pBtcContext, u8 regType, u32 offset); typedef void (*BFP_BTC_DISP_DBG_MSG)(void *pBtCoexist, u8 dispType); -typedef struct _BTC_BT_INFO { +struct btc_bt_info { bool bBtDisabled; u8 rssiAdjustForAgcTableOn; u8 rssiAdjustFor1AntCoexType; @@ -435,9 +391,9 @@ typedef struct _BTC_BT_INFO { u8 lpsVal; u8 rpwmVal; u32 raMask; -} BTC_BT_INFO, *PBTC_BT_INFO; +}; -typedef struct _BTC_STACK_INFO { +struct btc_stack_info { bool bProfileNotified; u16 hciVersion; /* stack hci version */ u8 numOfLink; @@ -450,9 +406,9 @@ typedef struct _BTC_STACK_INFO { bool bPanExist; bool bUnknownAclExist; s8 minBtRssi; -} BTC_STACK_INFO, *PBTC_STACK_INFO; +}; -typedef struct _BTC_BT_LINK_INFO { +struct btc_bt_link_info { bool bBtLinkExist; bool bScoExist; bool bScoOnly; @@ -463,9 +419,9 @@ typedef struct _BTC_BT_LINK_INFO { bool bPanExist; bool bPanOnly; bool bSlaveRole; -} BTC_BT_LINK_INFO, *PBTC_BT_LINK_INFO; +}; -typedef struct _BTC_STATISTICS { +struct btc_statistics { u32 cntBind; u32 cntPowerOn; u32 cntInitHwConfig; @@ -482,22 +438,22 @@ typedef struct _BTC_STATISTICS { u32 cntCoexDmSwitch; u32 cntStackOperationNotify; u32 cntDbgCtrl; -} BTC_STATISTICS, *PBTC_STATISTICS; +}; -typedef struct _BTC_COEXIST { +struct btc_coexist { bool bBinded; /* make sure only one adapter can bind the data context */ void *Adapter; /* default adapter */ - BTC_BOARD_INFO boardInfo; - BTC_BT_INFO btInfo; /* some bt info referenced by non-bt module */ - BTC_STACK_INFO stackInfo; - BTC_BT_LINK_INFO btLinkInfo; - BTC_CHIP_INTERFACE chipInterface; + struct btc_board_info boardInfo; + struct btc_bt_info btInfo; /* some bt info referenced by non-bt module */ + struct btc_stack_info stackInfo; + struct btc_bt_link_info btLinkInfo; + enum btc_chip_interface chipInterface; bool bInitilized; bool bStopCoexDm; bool bManualControl; u8 *cliBuf; - BTC_STATISTICS statistics; + struct btc_statistics statistics; u8 pwrModeVal[10]; /* function pointers */ @@ -528,30 +484,30 @@ typedef struct _BTC_COEXIST { BFP_BTC_GET_BT_REG fBtcGetBtReg; BFP_BTC_SET_BT_REG fBtcSetBtReg; -} BTC_COEXIST, *PBTC_COEXIST; +}; -extern BTC_COEXIST GLBtCoexist; +extern struct btc_coexist GLBtCoexist; -void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist); -void EXhalbtcoutsrc_InitHwConfig(PBTC_COEXIST pBtCoexist, u8 bWifiOnly); -void EXhalbtcoutsrc_InitCoexDm(PBTC_COEXIST pBtCoexist); -void EXhalbtcoutsrc_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtcoutsrc_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtcoutsrc_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type); -void EXhalbtcoutsrc_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 action); +void EXhalbtcoutsrc_PowerOnSetting(struct btc_coexist *pBtCoexist); +void EXhalbtcoutsrc_InitHwConfig(struct btc_coexist *pBtCoexist, u8 bWifiOnly); +void EXhalbtcoutsrc_InitCoexDm(struct btc_coexist *pBtCoexist); +void EXhalbtcoutsrc_IpsNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtcoutsrc_LpsNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtcoutsrc_ScanNotify(struct btc_coexist *pBtCoexist, u8 type); +void EXhalbtcoutsrc_ConnectNotify(struct btc_coexist *pBtCoexist, u8 action); void EXhalbtcoutsrc_MediaStatusNotify( - PBTC_COEXIST pBtCoexist, RT_MEDIA_STATUS mediaStatus + struct btc_coexist *pBtCoexist, enum rt_media_status mediaStatus ); -void EXhalbtcoutsrc_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 pktType); +void EXhalbtcoutsrc_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 pktType); void EXhalbtcoutsrc_BtInfoNotify( - PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length + struct btc_coexist *pBtCoexist, u8 *tmpBuf, u8 length ); -void EXhalbtcoutsrc_HaltNotify(PBTC_COEXIST pBtCoexist); -void EXhalbtcoutsrc_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState); -void EXhalbtcoutsrc_Periodical(PBTC_COEXIST pBtCoexist); +void EXhalbtcoutsrc_HaltNotify(struct btc_coexist *pBtCoexist); +void EXhalbtcoutsrc_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState); +void EXhalbtcoutsrc_Periodical(struct btc_coexist *pBtCoexist); void EXhalbtcoutsrc_SetChipType(u8 chipType); void EXhalbtcoutsrc_SetAntNum(u8 type, u8 antNum); void EXhalbtcoutsrc_SetSingleAntPath(u8 singleAntPath); -void EXhalbtcoutsrc_DisplayBtCoexInfo(PBTC_COEXIST pBtCoexist); +void EXhalbtcoutsrc_DisplayBtCoexInfo(struct btc_coexist *pBtCoexist); #endif diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c index 19856e806b1f174a58707d15235cf423fd3d66b9..016d257b90a07acbf814c46f2a631f5307898707 100644 --- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c +++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c @@ -9,7 +9,7 @@ #include "odm_precomp.h" static bool CheckPositive( - PDM_ODM_T pDM_Odm, const u32 Condition1, const u32 Condition2 + struct dm_odm_t *pDM_Odm, const u32 Condition1, const u32 Condition2 ) { u8 _BoardType = @@ -112,7 +112,7 @@ static bool CheckPositive( } static bool CheckNegative( - PDM_ODM_T pDM_Odm, const u32 Condition1, const u32 Condition2 + struct dm_odm_t *pDM_Odm, const u32 Condition1, const u32 Condition2 ) { return true; @@ -257,7 +257,7 @@ static u32 Array_MP_8723B_AGC_TAB[] = { }; -void ODM_ReadAndConfig_MP_8723B_AGC_TAB(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_AGC_TAB(struct dm_odm_t *pDM_Odm) { u32 i = 0; u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_AGC_TAB); @@ -526,7 +526,7 @@ static u32 Array_MP_8723B_PHY_REG[] = { }; -void ODM_ReadAndConfig_MP_8723B_PHY_REG(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_PHY_REG(struct dm_odm_t *pDM_Odm) { u32 i = 0; u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_PHY_REG); @@ -606,7 +606,7 @@ static u32 Array_MP_8723B_PHY_REG_PG[] = { 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436 }; -void ODM_ReadAndConfig_MP_8723B_PHY_REG_PG(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_PHY_REG_PG(struct dm_odm_t *pDM_Odm) { u32 i = 0; u32 *Array = Array_MP_8723B_PHY_REG_PG; diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.h b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.h index c1fbe91cd4f341433d88e0a7e23094190863ca55..186007ce57d52000baa38f6adbd3fa04840517f9 100644 --- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.h +++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.h @@ -15,7 +15,7 @@ void ODM_ReadAndConfig_MP_8723B_AGC_TAB(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); /****************************************************************************** @@ -24,7 +24,7 @@ ODM_ReadAndConfig_MP_8723B_AGC_TAB(/* TC: Test Chip, MP: MP Chip */ void ODM_ReadAndConfig_MP_8723B_PHY_REG(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); /****************************************************************************** @@ -33,7 +33,7 @@ ODM_ReadAndConfig_MP_8723B_PHY_REG(/* TC: Test Chip, MP: MP Chip */ void ODM_ReadAndConfig_MP_8723B_PHY_REG_PG(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); u32 ODM_GetVersion_MP_8723B_PHY_REG_PG(void); diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c index b80c5b11796bb8f9e8e8a80f871b29db22c0ce5a..677bcfa10b0d51fea7830c9052adbec42dd2d010 100644 --- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c +++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c @@ -9,7 +9,7 @@ #include "odm_precomp.h" static bool CheckPositive( - PDM_ODM_T pDM_Odm, const u32 Condition1, const u32 Condition2 + struct dm_odm_t *pDM_Odm, const u32 Condition1, const u32 Condition2 ) { u8 _BoardType = @@ -111,7 +111,7 @@ static bool CheckPositive( } static bool CheckNegative( - PDM_ODM_T pDM_Odm, const u32 Condition1, const u32 Condition2 + struct dm_odm_t *pDM_Odm, const u32 Condition1, const u32 Condition2 ) { return true; @@ -228,7 +228,7 @@ static u32 Array_MP_8723B_MAC_REG[] = { }; -void ODM_ReadAndConfig_MP_8723B_MAC_REG(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_MAC_REG(struct dm_odm_t *pDM_Odm) { u32 i = 0; u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_MAC_REG); diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.h b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.h index 788fdca1337b7a7518eb34a084568421c4c3beb9..50429c159feeba23f1d0673c7e54b74cf87d5c25 100644 --- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.h +++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.h @@ -15,6 +15,6 @@ void ODM_ReadAndConfig_MP_8723B_MAC_REG(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); #endif diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c index 426f68b8f0d2b1374d222b0244a6bc7c5d87d5a7..2c450c1ce7e7cd3bed3847821b96d80f6d77846c 100644 --- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c +++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c @@ -9,7 +9,7 @@ #include "odm_precomp.h" static bool CheckPositive( - PDM_ODM_T pDM_Odm, const u32 Condition1, const u32 Condition2 + struct dm_odm_t *pDM_Odm, const u32 Condition1, const u32 Condition2 ) { u8 _BoardType = @@ -121,7 +121,7 @@ static bool CheckPositive( } static bool CheckNegative( - PDM_ODM_T pDM_Odm, const u32 Condition1, const u32 Condition2 + struct dm_odm_t *pDM_Odm, const u32 Condition1, const u32 Condition2 ) { return true; @@ -259,7 +259,7 @@ static u32 Array_MP_8723B_RadioA[] = { }; -void ODM_ReadAndConfig_MP_8723B_RadioA(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_RadioA(struct dm_odm_t *pDM_Odm) { u32 i = 0; u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_RadioA); @@ -420,9 +420,9 @@ static u8 gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_SDIO_8723B[] = { 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15 }; -void ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(struct dm_odm_t *pDM_Odm) { - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo; ODM_RT_TRACE( pDM_Odm, @@ -755,7 +755,7 @@ static u8 *Array_MP_8723B_TXPWR_LMT[] = { "MKK", "2.4G", "40M", "HT", "2T", "14", "63" }; -void ODM_ReadAndConfig_MP_8723B_TXPWR_LMT(PDM_ODM_T pDM_Odm) +void ODM_ReadAndConfig_MP_8723B_TXPWR_LMT(struct dm_odm_t *pDM_Odm) { u32 i = 0; u8 **Array = Array_MP_8723B_TXPWR_LMT; diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.h b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.h index 36a47437f97420c0c7be3e87edd810903ed05045..acf5679d188cf62488ea215725c5b5f5a93b1c0d 100644 --- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.h +++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.h @@ -15,7 +15,7 @@ void ODM_ReadAndConfig_MP_8723B_RadioA(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); /****************************************************************************** @@ -24,7 +24,7 @@ ODM_ReadAndConfig_MP_8723B_RadioA(/* TC: Test Chip, MP: MP Chip */ void ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); u32 ODM_GetVersion_MP_8723B_TxPowerTrack_SDIO(void); @@ -34,7 +34,7 @@ u32 ODM_GetVersion_MP_8723B_TxPowerTrack_SDIO(void); void ODM_ReadAndConfig_MP_8723B_TXPWR_LMT(/* TC: Test Chip, MP: MP Chip */ - PDM_ODM_T pDM_Odm + struct dm_odm_t *pDM_Odm ); u32 ODM_GetVersion_MP_8723B_TXPWR_LMT(void); diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf.c b/drivers/staging/rtl8723bs/hal/HalPhyRf.c index 7b435840746d580838e512cd6d3cafae88ebcd35..14426151faaeced45a7ed39c0a25e8ef391b8ed0 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf.c +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf.c @@ -23,7 +23,7 @@ } while (0) -void ConfigureTxpowerTrack(PDM_ODM_T pDM_Odm, PTXPWRTRACK_CFG pConfig) +void ConfigureTxpowerTrack(struct dm_odm_t *pDM_Odm, struct txpwrtrack_cfg *pConfig) { ConfigureTxpowerTrack_8723B(pConfig); } @@ -36,7 +36,7 @@ void ConfigureTxpowerTrack(PDM_ODM_T pDM_Odm, PTXPWRTRACK_CFG pConfig) /* NOTE: If Tx BB swing or Tx scaling is varified during run-time, still */ /* need to call this function. */ /* */ -void ODM_ClearTxPowerTrackingState(PDM_ODM_T pDM_Odm) +void ODM_ClearTxPowerTrackingState(struct dm_odm_t *pDM_Odm) { struct hal_com_data *pHalData = GET_HAL_DATA(pDM_Odm->Adapter); u8 p = 0; @@ -74,7 +74,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0; u8 ThermalValue_AVG_count = 0; @@ -83,7 +83,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter) u8 OFDM_min_index = 0; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ u8 Indexforchannel = 0; /* GetRightChnlPlaceforIQK(pHalData->CurrentChannel) */ - TXPWRTRACK_CFG c; + struct txpwrtrack_cfg c; /* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */ diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf.h b/drivers/staging/rtl8723bs/hal/HalPhyRf.h index 643fcf37c9ad2e55f333475dfe41f4c6dcfa3da7..fdbdd68edf2a6e928afcec34f1c9c825dd5fac45 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf.h +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf.h @@ -8,23 +8,18 @@ #ifndef __HAL_PHY_RF_H__ #define __HAL_PHY_RF_H__ -typedef enum _SPUR_CAL_METHOD { - PLL_RESET, - AFE_PHASE_SEL -} SPUR_CAL_METHOD; - -typedef enum _PWRTRACK_CONTROL_METHOD { +enum pwrtrack_method { BBSWING, TXAGC, MIX_MODE -} PWRTRACK_METHOD; +}; -typedef void (*FuncSetPwr)(PDM_ODM_T, PWRTRACK_METHOD, u8, u8); -typedef void (*FuncIQK)(PDM_ODM_T, u8, u8, u8); -typedef void (*FuncLCK)(PDM_ODM_T); -typedef void (*FuncSwing)(PDM_ODM_T, u8 **, u8 **, u8 **, u8 **); +typedef void (*FuncSetPwr)(struct dm_odm_t *, enum pwrtrack_method, u8, u8); +typedef void (*FuncIQK)(struct dm_odm_t *, u8, u8, u8); +typedef void (*FuncLCK)(struct dm_odm_t *); +typedef void (*FuncSwing)(struct dm_odm_t *, u8 **, u8 **, u8 **, u8 **); -typedef struct _TXPWRTRACK_CFG { +struct txpwrtrack_cfg { u8 SwingTableSize_CCK; u8 SwingTableSize_OFDM; u8 Threshold_IQK; @@ -35,12 +30,12 @@ typedef struct _TXPWRTRACK_CFG { FuncIQK DoIQK; FuncLCK PHY_LCCalibrate; FuncSwing GetDeltaSwingTable; -} TXPWRTRACK_CFG, *PTXPWRTRACK_CFG; +}; -void ConfigureTxpowerTrack(PDM_ODM_T pDM_Odm, PTXPWRTRACK_CFG pConfig); +void ConfigureTxpowerTrack(struct dm_odm_t *pDM_Odm, struct txpwrtrack_cfg *pConfig); -void ODM_ClearTxPowerTrackingState(PDM_ODM_T pDM_Odm); +void ODM_ClearTxPowerTrackingState(struct dm_odm_t *pDM_Odm); void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter); diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c index 645f4f2a835ee60a07aab4262df4061a1cf6fd42..c70b9cf2da320ff30cc3778027854eed315d8dfd 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c @@ -54,7 +54,7 @@ static u8 DeltaSwingTableIdx_2GA_P_8188E[] = { static void setIqkMatrix_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 OFDM_index, u8 RFPath, s32 IqkResult_X, @@ -135,7 +135,7 @@ static void setIqkMatrix_8723B( } -static void setCCKFilterCoefficient(PDM_ODM_T pDM_Odm, u8 CCKSwingIndex) +static void setCCKFilterCoefficient(struct dm_odm_t *pDM_Odm, u8 CCKSwingIndex) { if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) { rtw_write8(pDM_Odm->Adapter, 0xa22, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][0]); @@ -159,7 +159,7 @@ static void setCCKFilterCoefficient(PDM_ODM_T pDM_Odm, u8 CCKSwingIndex) } void DoIQK_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 DeltaThermalIndex, u8 ThermalValue, u8 Threshold @@ -185,8 +185,8 @@ void DoIQK_8723B( * *---------------------------------------------------------------------------*/ void ODM_TxPwrTrackSetPwr_8723B( - PDM_ODM_T pDM_Odm, - PWRTRACK_METHOD Method, + struct dm_odm_t *pDM_Odm, + enum pwrtrack_method Method, u8 RFPath, u8 ChannelMappedIndex ) @@ -360,7 +360,7 @@ void ODM_TxPwrTrackSetPwr_8723B( } static void GetDeltaSwingTable_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 **TemperatureUP_A, u8 **TemperatureDOWN_A, u8 **TemperatureUP_B, @@ -368,7 +368,7 @@ static void GetDeltaSwingTable_8723B( ) { struct adapter *Adapter = pDM_Odm->Adapter; - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); u16 rate = *(pDM_Odm->pForcedDataRate); u8 channel = pHalData->CurrentChannel; @@ -409,7 +409,7 @@ static void GetDeltaSwingTable_8723B( } -void ConfigureTxpowerTrack_8723B(PTXPWRTRACK_CFG pConfig) +void ConfigureTxpowerTrack_8723B(struct txpwrtrack_cfg *pConfig) { pConfig->SwingTableSize_CCK = CCK_TABLE_SIZE; pConfig->SwingTableSize_OFDM = OFDM_TABLE_SIZE; @@ -437,7 +437,7 @@ static u8 phy_PathA_IQK_8723B( u8 result = 0x00; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; /* Save RF Path */ Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); @@ -548,7 +548,7 @@ static u8 phy_PathA_RxIQK8723B( u32 regEAC, regE94, regE9C, regEA4, u4tmp, tmp, Path_SEL_BB; u8 result = 0x00; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n")); */ @@ -762,7 +762,7 @@ static u8 phy_PathB_IQK_8723B(struct adapter *padapter) u32 regEAC, regE94, regE9C, tmp, Path_SEL_BB/*, regEC4, regECC, Path_SEL_BB*/; u8 result = 0x00; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n")); @@ -869,7 +869,7 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB) u32 regE94, regE9C, regEA4, regEAC, u4tmp, tmp, Path_SEL_BB; u8 result = 0x00; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK!\n")); */ @@ -1092,9 +1092,9 @@ static void _PHY_PathAFillIQKMatrix8723B( u32 Oldval_0, X, TX0_A, reg; s32 Y, TX0_C; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed")); @@ -1172,9 +1172,9 @@ static void _PHY_PathBFillIQKMatrix8723B( u32 Oldval_1, X, TX1_A, reg; s32 Y, TX1_C; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed")); @@ -1247,10 +1247,10 @@ static void _PHY_PathBFillIQKMatrix8723B( /* */ /* MP Already declare in odm.c */ -void ODM_SetIQCbyRFpath(PDM_ODM_T pDM_Odm, u32 RFpath) +void ODM_SetIQCbyRFpath(struct dm_odm_t *pDM_Odm, u32 RFpath) { - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo; if ( (pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC80][VAL] != 0x0) && @@ -1292,7 +1292,7 @@ static void _PHY_SaveADDARegisters8723B( { u32 i; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; if (!ODM_CheckPowerStatus(padapter)) return; @@ -1310,7 +1310,7 @@ static void _PHY_SaveMACRegisters8723B( { u32 i; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n")); for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) { @@ -1330,7 +1330,7 @@ static void _PHY_ReloadADDARegisters8723B( { u32 i; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n")); for (i = 0 ; i < RegiesterNum; i++) { @@ -1360,7 +1360,7 @@ static void _PHY_PathADDAOn8723B( u32 pathOn; u32 i; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n")); @@ -1384,7 +1384,7 @@ static void _PHY_MACSettingCalibration8723B( { u32 i = 0; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n")); @@ -1489,7 +1489,7 @@ static void phy_IQCalibrate_8723B( ) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; u32 i; u8 PathAOK, PathBOK; @@ -1697,7 +1697,7 @@ static void phy_IQCalibrate_8723B( } -static void phy_LCCalibrate_8723B(PDM_ODM_T pDM_Odm, bool is2T) +static void phy_LCCalibrate_8723B(struct dm_odm_t *pDM_Odm, bool is2T) { u8 tmpReg; u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal; @@ -1784,7 +1784,7 @@ void PHY_IQCalibrate_8723B( { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; s32 result[4][8]; /* last is final result */ u8 i, final_candidate; @@ -1830,7 +1830,7 @@ void PHY_IQCalibrate_8723B( if (bRestore) { u32 offset, data; u8 path, bResult = SUCCESS; - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo; path = (PHY_QueryBBReg(pDM_Odm->Adapter, rS0S1_PathSwitch, bMaskByte0) == 0x00) ? ODM_RF_PATH_A : ODM_RF_PATH_B; @@ -1839,15 +1839,9 @@ void PHY_IQCalibrate_8723B( offset = pRFCalibrateInfo->TxIQC_8723B[path][i][0]; data = pRFCalibrateInfo->TxIQC_8723B[path][i][1]; if ((offset == 0) || (data == 0)) { - DBG_871X( - "%s =>path:%s Restore TX IQK result failed\n", - __func__, - (path == ODM_RF_PATH_A)?"A":"B" - ); bResult = FAIL; break; } - /* RT_TRACE(_module_mp_, _drv_notice_, ("Switch to S1 TxIQC(offset, data) = (0x%X, 0x%X)\n", offset, data)); */ PHY_SetBBReg(pDM_Odm->Adapter, offset, bMaskDWord, data); } @@ -1856,20 +1850,13 @@ void PHY_IQCalibrate_8723B( offset = pRFCalibrateInfo->RxIQC_8723B[path][i][0]; data = pRFCalibrateInfo->RxIQC_8723B[path][i][1]; if ((offset == 0) || (data == 0)) { - DBG_871X( - "%s =>path:%s Restore RX IQK result failed\n", - __func__, - (path == ODM_RF_PATH_A)?"A":"B" - ); bResult = FAIL; break; } - /* RT_TRACE(_module_mp_, _drv_notice_, ("Switch to S1 RxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data)); */ PHY_SetBBReg(pDM_Odm->Adapter, offset, bMaskDWord, data); } if (pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_A] == 0) { - DBG_871X("%s => Restore Path-A TxLOK result failed\n", __func__); bResult = FAIL; } else { PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXM_IDAC, bRFRegOffsetMask, pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_A]); @@ -1950,7 +1937,6 @@ void PHY_IQCalibrate_8723B( } } } -/* RT_TRACE(COMP_INIT, DBG_LOUD, ("Release Mutex in IQCalibrate\n")); */ for (i = 0; i < 4; i++) { RegE94 = result[i][0]; @@ -2038,7 +2024,7 @@ void PHY_IQCalibrate_8723B( } -void PHY_LCCalibrate_8723B(PDM_ODM_T pDM_Odm) +void PHY_LCCalibrate_8723B(struct dm_odm_t *pDM_Odm) { bool bSingleTone = false, bCarrierSuppression = false; u32 timeout = 2000, timecount = 0; diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h index a4d5150007befe3a81f739be75087f0434a5fb8f..775095ad0921c751fad4ecd838b6e9fc30a6f5ce 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h @@ -16,18 +16,18 @@ #define RF_T_METER_8723B 0x42 /* */ -void ConfigureTxpowerTrack_8723B(PTXPWRTRACK_CFG pConfig); +void ConfigureTxpowerTrack_8723B(struct txpwrtrack_cfg *pConfig); void DoIQK_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 DeltaThermalIndex, u8 ThermalValue, u8 Threshold ); void ODM_TxPwrTrackSetPwr_8723B( - PDM_ODM_T pDM_Odm, - PWRTRACK_METHOD Method, + struct dm_odm_t *pDM_Odm, + enum pwrtrack_method Method, u8 RFPath, u8 ChannelMappedIndex ); @@ -41,12 +41,12 @@ void PHY_IQCalibrate_8723B( u8 RF_Path ); -void ODM_SetIQCbyRFpath(PDM_ODM_T pDM_Odm, u32 RFpath); +void ODM_SetIQCbyRFpath(struct dm_odm_t *pDM_Odm, u32 RFpath); /* */ /* LC calibrate */ /* */ -void PHY_LCCalibrate_8723B(PDM_ODM_T pDM_Odm); +void PHY_LCCalibrate_8723B(struct dm_odm_t *pDM_Odm); /* */ /* AP calibrate */ diff --git a/drivers/staging/rtl8723bs/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8723bs/hal/HalPwrSeqCmd.c index 3b34a516075fc548c02405de2965ab52ea3117ea..5f9e94a7e6ad6c4187e91bca697fd8b72cca7097 100644 --- a/drivers/staging/rtl8723bs/hal/HalPwrSeqCmd.c +++ b/drivers/staging/rtl8723bs/hal/HalPwrSeqCmd.c @@ -39,10 +39,10 @@ u8 HalPwrSeqCmdParsing( u8 CutVersion, u8 FabVersion, u8 InterfaceType, - WLAN_PWR_CFG PwrSeqCmd[] + struct wlan_pwr_cfg PwrSeqCmd[] ) { - WLAN_PWR_CFG PwrCfgCmd; + struct wlan_pwr_cfg PwrCfgCmd; u8 bPollingBit = false; u32 AryIdx = 0; u8 value = 0; @@ -53,22 +53,6 @@ u8 HalPwrSeqCmdParsing( do { PwrCfgCmd = PwrSeqCmd[AryIdx]; - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ( - "HalPwrSeqCmdParsing: offset(%#x) cut_msk(%#x) fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) msk(%#x) value(%#x)\n", - GET_PWR_CFG_OFFSET(PwrCfgCmd), - GET_PWR_CFG_CUT_MASK(PwrCfgCmd), - GET_PWR_CFG_FAB_MASK(PwrCfgCmd), - GET_PWR_CFG_INTF_MASK(PwrCfgCmd), - GET_PWR_CFG_BASE(PwrCfgCmd), - GET_PWR_CFG_CMD(PwrCfgCmd), - GET_PWR_CFG_MASK(PwrCfgCmd), - GET_PWR_CFG_VALUE(PwrCfgCmd) - ) - ); - /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ if ( (GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && @@ -77,19 +61,9 @@ u8 HalPwrSeqCmdParsing( ) { switch (GET_PWR_CFG_CMD(PwrCfgCmd)) { case PWR_CMD_READ: - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ("HalPwrSeqCmdParsing: PWR_CMD_READ\n") - ); break; case PWR_CMD_WRITE: - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ("HalPwrSeqCmdParsing: PWR_CMD_WRITE\n") - ); offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); /* */ @@ -124,11 +98,6 @@ u8 HalPwrSeqCmdParsing( break; case PWR_CMD_POLLING: - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ("HalPwrSeqCmdParsing: PWR_CMD_POLLING\n") - ); bPollingBit = false; offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); @@ -147,24 +116,14 @@ u8 HalPwrSeqCmdParsing( else udelay(10); - if (pollingCount++ > maxPollingCnt) { - DBG_871X( - "Fail to polling Offset[%#x]=%02x\n", - offset, - value - ); + if (pollingCount++ > maxPollingCnt) return false; - } + } while (!bPollingBit); break; case PWR_CMD_DELAY: - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ("HalPwrSeqCmdParsing: PWR_CMD_DELAY\n") - ); if (GET_PWR_CFG_VALUE(PwrCfgCmd) == PWRSEQ_DELAY_US) udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd)); else @@ -173,19 +132,9 @@ u8 HalPwrSeqCmdParsing( case PWR_CMD_END: /* When this command is parsed, end the process */ - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ("HalPwrSeqCmdParsing: PWR_CMD_END\n") - ); return true; default: - RT_TRACE( - _module_hal_init_c_, - _drv_err_, - ("HalPwrSeqCmdParsing: Unknown CMD!!\n") - ); break; } } diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c index 3705a60a0546219663d7a55dcca17caccf094a35..5802ed4c6f82d08f4d42ea467a471b1c5001bc3f 100644 --- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c +++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c @@ -13,29 +13,29 @@ /* Global variables */ -BTC_COEXIST GLBtCoexist; +struct btc_coexist GLBtCoexist; static u8 GLBtcWiFiInScanState; static u8 GLBtcWiFiInIQKState; u32 GLBtcDbgType[BTC_MSG_MAX]; static u8 GLBtcDbgBuf[BT_TMP_BUF_SIZE]; -typedef struct _btcoexdbginfo { +struct btcdbginfo { /* _btcoexdbginfo */ u8 *info; u32 size; /* buffer total size */ u32 len; /* now used length */ -} BTCDBGINFO, *PBTCDBGINFO; +}; -static BTCDBGINFO GLBtcDbgInfo; +static struct btcdbginfo GLBtcDbgInfo; #define BT_Operation(Adapter) false -static void DBG_BT_INFO_INIT(PBTCDBGINFO pinfo, u8 *pbuf, u32 size) +static void DBG_BT_INFO_INIT(struct btcdbginfo *pinfo, u8 *pbuf, u32 size) { if (!pinfo) return; - memset(pinfo, 0, sizeof(BTCDBGINFO)); + memset(pinfo, 0, sizeof(struct btcdbginfo)); if (pbuf && size) { pinfo->info = pbuf; @@ -45,7 +45,7 @@ static void DBG_BT_INFO_INIT(PBTCDBGINFO pinfo, u8 *pbuf, u32 size) void DBG_BT_INFO(u8 *dbgmsg) { - PBTCDBGINFO pinfo; + struct btcdbginfo *pinfo; u32 msglen; u8 *pbuf; @@ -67,7 +67,7 @@ void DBG_BT_INFO(u8 *dbgmsg) /* */ /* Debug related function */ /* */ -static u8 halbtcoutsrc_IsBtCoexistAvailable(PBTC_COEXIST pBtCoexist) +static u8 halbtcoutsrc_IsBtCoexistAvailable(struct btc_coexist *pBtCoexist) { if (!pBtCoexist->bBinded || !pBtCoexist->Adapter) return false; @@ -101,7 +101,7 @@ static void halbtcoutsrc_DbgInit(void) 0; } -static void halbtcoutsrc_LeaveLps(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_LeaveLps(struct btc_coexist *pBtCoexist) { struct adapter *padapter; @@ -114,7 +114,7 @@ static void halbtcoutsrc_LeaveLps(PBTC_COEXIST pBtCoexist) rtw_btcoex_LPS_Leave(padapter); } -static void halbtcoutsrc_EnterLps(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_EnterLps(struct btc_coexist *pBtCoexist) { struct adapter *padapter; @@ -127,7 +127,7 @@ static void halbtcoutsrc_EnterLps(PBTC_COEXIST pBtCoexist) rtw_btcoex_LPS_Enter(padapter); } -static void halbtcoutsrc_NormalLps(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_NormalLps(struct btc_coexist *pBtCoexist) { struct adapter *padapter; @@ -149,7 +149,7 @@ static void halbtcoutsrc_NormalLps(PBTC_COEXIST pBtCoexist) * Constraint: * 1. this function will request pwrctrl->lock */ -static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_LeaveLowPower(struct btc_coexist *pBtCoexist) { struct adapter *padapter; s32 ready; @@ -184,7 +184,7 @@ static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist) * Constraint: * 1. this function will request pwrctrl->lock */ -static void halbtcoutsrc_NormalLowPower(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_NormalLowPower(struct btc_coexist *pBtCoexist) { struct adapter *padapter; @@ -193,7 +193,7 @@ static void halbtcoutsrc_NormalLowPower(PBTC_COEXIST pBtCoexist) rtw_unregister_task_alive(padapter, BTCOEX_ALIVE); } -static void halbtcoutsrc_DisableLowPower(PBTC_COEXIST pBtCoexist, u8 bLowPwrDisable) +static void halbtcoutsrc_DisableLowPower(struct btc_coexist *pBtCoexist, u8 bLowPwrDisable) { pBtCoexist->btInfo.bBtDisableLowPwr = bLowPwrDisable; if (bLowPwrDisable) @@ -202,7 +202,7 @@ static void halbtcoutsrc_DisableLowPower(PBTC_COEXIST pBtCoexist, u8 bLowPwrDisa halbtcoutsrc_NormalLowPower(pBtCoexist); /* original 32k low power behavior. */ } -static void halbtcoutsrc_AggregationCheck(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_AggregationCheck(struct btc_coexist *pBtCoexist) { struct adapter *padapter; bool bNeedToAct; @@ -280,7 +280,7 @@ static u32 _halbtcoutsrc_GetWifiLinkStatus(struct adapter *padapter) return portConnectedStatus; } -static u32 halbtcoutsrc_GetWifiLinkStatus(PBTC_COEXIST pBtCoexist) +static u32 halbtcoutsrc_GetWifiLinkStatus(struct btc_coexist *pBtCoexist) { /* */ /* return value: */ @@ -308,7 +308,7 @@ static u32 halbtcoutsrc_GetWifiLinkStatus(PBTC_COEXIST pBtCoexist) return retVal; } -static u32 halbtcoutsrc_GetBtPatchVer(PBTC_COEXIST pBtCoexist) +static u32 halbtcoutsrc_GetBtPatchVer(struct btc_coexist *pBtCoexist) { return pBtCoexist->btInfo.btRealFwVer; } @@ -339,7 +339,7 @@ static u8 halbtcoutsrc_GetWifiScanAPNum(struct adapter *padapter) static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; struct hal_com_data *pHalData; struct mlme_ext_priv *mlmeext; @@ -349,7 +349,7 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) u8 ret; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return false; @@ -445,7 +445,7 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: { - PRT_LINK_DETECT_T plinkinfo; + struct rt_link_detect_t *plinkinfo; plinkinfo = &padapter->mlmepriv.LinkDetectInfo; if (plinkinfo->NumTxOkInPeriod > plinkinfo->NumRxOkInPeriod) @@ -507,14 +507,14 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; u8 *pu8; u32 *pU4Tmp; u8 ret; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; pu8 = pInBuf; pU4Tmp = pInBuf; @@ -642,7 +642,7 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf) return ret; } -static void halbtcoutsrc_DisplayFwPwrModeCmd(PBTC_COEXIST pBtCoexist) +static void halbtcoutsrc_DisplayFwPwrModeCmd(struct btc_coexist *pBtCoexist) { u8 *cliBuf = pBtCoexist->cliBuf; @@ -658,11 +658,11 @@ static void halbtcoutsrc_DisplayFwPwrModeCmd(PBTC_COEXIST pBtCoexist) /* */ static u8 halbtcoutsrc_Read1Byte(void *pBtcContext, u32 RegAddr) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; return rtw_read8(padapter, RegAddr); @@ -670,11 +670,11 @@ static u8 halbtcoutsrc_Read1Byte(void *pBtcContext, u32 RegAddr) static u16 halbtcoutsrc_Read2Byte(void *pBtcContext, u32 RegAddr) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; return rtw_read16(padapter, RegAddr); @@ -682,11 +682,11 @@ static u16 halbtcoutsrc_Read2Byte(void *pBtcContext, u32 RegAddr) static u32 halbtcoutsrc_Read4Byte(void *pBtcContext, u32 RegAddr) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; return rtw_read32(padapter, RegAddr); @@ -694,11 +694,11 @@ static u32 halbtcoutsrc_Read4Byte(void *pBtcContext, u32 RegAddr) static void halbtcoutsrc_Write1Byte(void *pBtcContext, u32 RegAddr, u8 Data) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; rtw_write8(padapter, RegAddr, Data); @@ -706,13 +706,13 @@ static void halbtcoutsrc_Write1Byte(void *pBtcContext, u32 RegAddr, u8 Data) static void halbtcoutsrc_BitMaskWrite1Byte(void *pBtcContext, u32 regAddr, u8 bitMask, u8 data1b) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; u8 originalValue, bitShift; u8 i; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; originalValue = 0; bitShift = 0; @@ -721,7 +721,7 @@ static void halbtcoutsrc_BitMaskWrite1Byte(void *pBtcContext, u32 regAddr, u8 bi originalValue = rtw_read8(padapter, regAddr); for (i = 0; i <= 7; i++) { - if ((bitMask>>i)&0x1) + if ((bitMask >> i) & 0x1) break; } bitShift = i; @@ -734,11 +734,11 @@ static void halbtcoutsrc_BitMaskWrite1Byte(void *pBtcContext, u32 regAddr, u8 bi static void halbtcoutsrc_Write2Byte(void *pBtcContext, u32 RegAddr, u16 Data) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; rtw_write16(padapter, RegAddr, Data); @@ -746,11 +746,11 @@ static void halbtcoutsrc_Write2Byte(void *pBtcContext, u32 RegAddr, u16 Data) static void halbtcoutsrc_Write4Byte(void *pBtcContext, u32 RegAddr, u32 Data) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; rtw_write32(padapter, RegAddr, Data); @@ -758,7 +758,7 @@ static void halbtcoutsrc_Write4Byte(void *pBtcContext, u32 RegAddr, u32 Data) static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 Data) { - PBTC_COEXIST pBtCoexist = (PBTC_COEXIST)pBtcContext; + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; struct adapter *Adapter = pBtCoexist->Adapter; if (BTC_INTF_SDIO == pBtCoexist->chipInterface) @@ -769,11 +769,11 @@ static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 D static void halbtcoutsrc_SetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask, u32 Data) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; PHY_SetBBReg(padapter, RegAddr, BitMask, Data); @@ -782,11 +782,11 @@ static void halbtcoutsrc_SetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask, u static u32 halbtcoutsrc_GetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; return PHY_QueryBBReg(padapter, RegAddr, BitMask); @@ -794,11 +794,11 @@ static u32 halbtcoutsrc_GetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask) static void halbtcoutsrc_SetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; PHY_SetRFReg(padapter, eRFPath, RegAddr, BitMask, Data); @@ -806,11 +806,11 @@ static void halbtcoutsrc_SetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u3 static u32 halbtcoutsrc_GetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 BitMask) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; return PHY_QueryRFReg(padapter, eRFPath, RegAddr, BitMask); @@ -818,7 +818,7 @@ static u32 halbtcoutsrc_GetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 static void halbtcoutsrc_SetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr, u32 Data) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; u8 CmdBuffer1[4] = {0}; u8 CmdBuffer2[4] = {0}; @@ -827,7 +827,7 @@ static void halbtcoutsrc_SetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr, u3 u8 OperVer = 0; u8 ReqNum = 0; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; CmdBuffer1[0] |= (OperVer & 0x0f); /* Set OperVer */ @@ -854,11 +854,11 @@ static u32 halbtcoutsrc_GetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr) static void halbtcoutsrc_FillH2cCmd(void *pBtcContext, u8 elementId, u32 cmdLen, u8 *pCmdBuffer) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; struct adapter *padapter; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; padapter = pBtCoexist->Adapter; rtw_hal_fill_h2c_cmd(padapter, elementId, cmdLen, pCmdBuffer); @@ -866,10 +866,10 @@ static void halbtcoutsrc_FillH2cCmd(void *pBtcContext, u8 elementId, u32 cmdLen, static void halbtcoutsrc_DisplayDbgMsg(void *pBtcContext, u8 dispType) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; - pBtCoexist = (PBTC_COEXIST)pBtcContext; + pBtCoexist = (struct btc_coexist *)pBtcContext; switch (dispType) { case BTC_DBG_DISP_COEX_STATISTICS: break; @@ -888,7 +888,7 @@ static void halbtcoutsrc_DisplayDbgMsg(void *pBtcContext, u8 dispType) /* */ static u8 EXhalbtcoutsrc_BindBtCoexWithAdapter(void *padapter) { - PBTC_COEXIST pBtCoexist = &GLBtCoexist; + struct btc_coexist *pBtCoexist = &GLBtCoexist; if (pBtCoexist->bBinded) return false; @@ -914,7 +914,7 @@ static u8 EXhalbtcoutsrc_BindBtCoexWithAdapter(void *padapter) void hal_btcoex_Initialize(void *padapter) { - PBTC_COEXIST pBtCoexist; + struct btc_coexist *pBtCoexist; memset(&GLBtCoexist, 0, sizeof(GLBtCoexist)); @@ -960,7 +960,7 @@ void hal_btcoex_Initialize(void *padapter) GLBtcWiFiInIQKState = false; } -void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist) +void EXhalbtcoutsrc_PowerOnSetting(struct btc_coexist *pBtCoexist) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -972,7 +972,7 @@ void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist) EXhalbtc8723b1ant_PowerOnSetting(pBtCoexist); } -void EXhalbtcoutsrc_InitHwConfig(PBTC_COEXIST pBtCoexist, u8 bWifiOnly) +void EXhalbtcoutsrc_InitHwConfig(struct btc_coexist *pBtCoexist, u8 bWifiOnly) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -985,7 +985,7 @@ void EXhalbtcoutsrc_InitHwConfig(PBTC_COEXIST pBtCoexist, u8 bWifiOnly) EXhalbtc8723b1ant_InitHwConfig(pBtCoexist, bWifiOnly); } -void EXhalbtcoutsrc_InitCoexDm(PBTC_COEXIST pBtCoexist) +void EXhalbtcoutsrc_InitCoexDm(struct btc_coexist *pBtCoexist) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -1000,7 +1000,7 @@ void EXhalbtcoutsrc_InitCoexDm(PBTC_COEXIST pBtCoexist) pBtCoexist->bInitilized = true; } -void EXhalbtcoutsrc_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtcoutsrc_IpsNotify(struct btc_coexist *pBtCoexist, u8 type) { u8 ipsType; @@ -1027,7 +1027,7 @@ void EXhalbtcoutsrc_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ } -void EXhalbtcoutsrc_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtcoutsrc_LpsNotify(struct btc_coexist *pBtCoexist, u8 type) { u8 lpsType; @@ -1050,7 +1050,7 @@ void EXhalbtcoutsrc_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) EXhalbtc8723b1ant_LpsNotify(pBtCoexist, lpsType); } -void EXhalbtcoutsrc_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) +void EXhalbtcoutsrc_ScanNotify(struct btc_coexist *pBtCoexist, u8 type) { u8 scanType; @@ -1079,7 +1079,7 @@ void EXhalbtcoutsrc_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ } -void EXhalbtcoutsrc_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 action) +void EXhalbtcoutsrc_ConnectNotify(struct btc_coexist *pBtCoexist, u8 action) { u8 assoType; @@ -1105,7 +1105,8 @@ void EXhalbtcoutsrc_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 action) /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ } -void EXhalbtcoutsrc_MediaStatusNotify(PBTC_COEXIST pBtCoexist, RT_MEDIA_STATUS mediaStatus) +void EXhalbtcoutsrc_MediaStatusNotify(struct btc_coexist *pBtCoexist, enum + rt_media_status mediaStatus) { u8 mStatus; @@ -1132,7 +1133,7 @@ void EXhalbtcoutsrc_MediaStatusNotify(PBTC_COEXIST pBtCoexist, RT_MEDIA_STATUS m /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ } -void EXhalbtcoutsrc_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 pktType) +void EXhalbtcoutsrc_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 pktType) { u8 packetType; @@ -1163,7 +1164,7 @@ void EXhalbtcoutsrc_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 pktType) /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ } -void EXhalbtcoutsrc_BtInfoNotify(PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length) +void EXhalbtcoutsrc_BtInfoNotify(struct btc_coexist *pBtCoexist, u8 *tmpBuf, u8 length) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -1181,7 +1182,7 @@ void EXhalbtcoutsrc_BtInfoNotify(PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length) /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ } -void EXhalbtcoutsrc_HaltNotify(PBTC_COEXIST pBtCoexist) +void EXhalbtcoutsrc_HaltNotify(struct btc_coexist *pBtCoexist) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -1194,7 +1195,7 @@ void EXhalbtcoutsrc_HaltNotify(PBTC_COEXIST pBtCoexist) pBtCoexist->bBinded = false; } -void EXhalbtcoutsrc_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) +void EXhalbtcoutsrc_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -1210,7 +1211,7 @@ void EXhalbtcoutsrc_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) EXhalbtc8723b2ant_PnpNotify(pBtCoexist, pnpState); } -void EXhalbtcoutsrc_Periodical(PBTC_COEXIST pBtCoexist) +void EXhalbtcoutsrc_Periodical(struct btc_coexist *pBtCoexist) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -1255,7 +1256,7 @@ void EXhalbtcoutsrc_SetSingleAntPath(u8 singleAntPath) GLBtCoexist.boardInfo.singleAntPath = singleAntPath; } -void EXhalbtcoutsrc_DisplayBtCoexInfo(PBTC_COEXIST pBtCoexist) +void EXhalbtcoutsrc_DisplayBtCoexInfo(struct btc_coexist *pBtCoexist) { if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) return; @@ -1481,15 +1482,15 @@ u32 hal_btcoex_GetRaMask(struct adapter *padapter) void hal_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write pwrModeCmd = 0x%04x%08x\n", - pCmdBuf[0]<<8|pCmdBuf[1], - pCmdBuf[2]<<24|pCmdBuf[3]<<16|pCmdBuf[4]<<8|pCmdBuf[5])); + pCmdBuf[0] << 8 | pCmdBuf[1], + pCmdBuf[2] << 24 | pCmdBuf[3] << 16 | pCmdBuf[4] << 8 | pCmdBuf[5])); memcpy(GLBtCoexist.pwrModeVal, pCmdBuf, cmdLen); } void hal_btcoex_DisplayBtCoexInfo(struct adapter *padapter, u8 *pbuf, u32 bufsize) { - PBTCDBGINFO pinfo; + struct btcdbginfo *pinfo; pinfo = &GLBtcDbgInfo; @@ -1522,7 +1523,6 @@ u32 hal_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize) pstr = pStrBuf; leftSize = bufSize; -/* DBG_871X(FUNC_ADPT_FMT ": bufsize =%d\n", FUNC_ADPT_ARG(padapter), bufSize); */ count = rtw_sprintf(pstr, leftSize, "#define DBG\t%d\n", DBG); if ((count < 0) || (count >= leftSize)) @@ -1551,13 +1551,13 @@ u32 hal_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize) pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for INTF_INIT\n", - (GLBtcDbgType[BTC_MSG_INTERFACE]&INTF_INIT)?1:0); + (GLBtcDbgType[BTC_MSG_INTERFACE] & INTF_INIT) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for INTF_NOTIFY\n\n", - (GLBtcDbgType[BTC_MSG_INTERFACE]&INTF_NOTIFY)?1:0); + (GLBtcDbgType[BTC_MSG_INTERFACE] & INTF_NOTIFY) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; @@ -1569,61 +1569,61 @@ u32 hal_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize) pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for BT_RSSI_STATE\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_BT_RSSI_STATE)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_BT_RSSI_STATE) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[1]=%d for WIFI_RSSI_STATE\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_WIFI_RSSI_STATE)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_WIFI_RSSI_STATE) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for BT_MONITOR\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_BT_MONITOR)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_BT_MONITOR) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[3]=%d for TRACE\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[4]=%d for TRACE_FW\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_FW)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[5]=%d for TRACE_FW_DETAIL\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_FW_DETAIL)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW_DETAIL) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[6]=%d for TRACE_FW_EXEC\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_FW_EXEC)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW_EXEC) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[7]=%d for TRACE_SW\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_SW)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[8]=%d for TRACE_SW_DETAIL\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_SW_DETAIL)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW_DETAIL) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; leftSize -= count; count = rtw_sprintf(pstr, leftSize, "\tbit[9]=%d for TRACE_SW_EXEC\n", - (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_SW_EXEC)?1:0); + (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW_EXEC) ? 1 : 0); if ((count < 0) || (count >= leftSize)) goto exit; pstr += count; @@ -1631,7 +1631,6 @@ u32 hal_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize) exit: count = pstr - pStrBuf; -/* DBG_871X(FUNC_ADPT_FMT ": usedsize =%d\n", FUNC_ADPT_ARG(padapter), count); */ return count; } diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index 16b259acbe1aab8647cb114b2334eefb945ce51b..e82f59fc5e9bc511160ff59846c585a1ccfff62d 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -18,10 +18,8 @@ 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) { - DBG_8192C("cannot alloc memory for HAL DATA\n"); + if (!padapter->HalData) return _FAIL; - } } return _SUCCESS; } @@ -38,51 +36,52 @@ void rtw_hal_data_deinit(struct adapter *padapter) } -void dump_chip_info(HAL_VERSION ChipVersion) +void dump_chip_info(struct hal_version ChipVersion) { - int cnt = 0; - u8 buf[128]; + char buf[128]; + size_t cnt = 0; + + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "Chip Version Info: CHIP_8723B_%s_", + IS_NORMAL_CHIP(ChipVersion) ? "Normal_Chip" : "Test_Chip"); - cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723B_"); - cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(ChipVersion) ? "Normal_Chip" : "Test_Chip"); if (IS_CHIP_VENDOR_TSMC(ChipVersion)) - cnt += sprintf((buf+cnt), "%s_", "TSMC"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "TSMC_"); else if (IS_CHIP_VENDOR_UMC(ChipVersion)) - cnt += sprintf((buf+cnt), "%s_", "UMC"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "UMC_"); else if (IS_CHIP_VENDOR_SMIC(ChipVersion)) - cnt += sprintf((buf+cnt), "%s_", "SMIC"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "SMIC_"); if (IS_A_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "A_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "A_CUT_"); else if (IS_B_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "B_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "B_CUT_"); else if (IS_C_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "C_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "C_CUT_"); else if (IS_D_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "D_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "D_CUT_"); else if (IS_E_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "E_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "E_CUT_"); else if (IS_I_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "I_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "I_CUT_"); else if (IS_J_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "J_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "J_CUT_"); else if (IS_K_CUT(ChipVersion)) - cnt += sprintf((buf+cnt), "K_CUT_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "K_CUT_"); else - cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, + "UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion); if (IS_1T1R(ChipVersion)) - cnt += sprintf((buf+cnt), "1T1R_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "1T1R_"); else if (IS_1T2R(ChipVersion)) - cnt += sprintf((buf+cnt), "1T2R_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "1T2R_"); else if (IS_2T2R(ChipVersion)) - cnt += sprintf((buf+cnt), "2T2R_"); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "2T2R_"); else - cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_", ChipVersion.RFType); - - cnt += sprintf((buf+cnt), "RomVer(%d)\n", ChipVersion.ROMVer); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, + "UNKNOWN_RFTYPE(%d)_", ChipVersion.RFType); - DBG_871X("%s", buf); + cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "RomVer(%d)\n", ChipVersion.ROMVer); } @@ -129,10 +128,8 @@ u8 hal_com_config_channel_plan( hw_chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK); if (rtw_is_channel_plan_valid(hw_chnlPlan)) { -#ifndef CONFIG_SW_CHANNEL_PLAN if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) pHalData->bDisableSWChannelPlan = true; -#endif /* !CONFIG_SW_CHANNEL_PLAN */ chnlPlan = hw_chnlPlan; } @@ -152,13 +149,10 @@ bool HAL_IsLegalChannel(struct adapter *Adapter, u32 Channel) bool bLegalChannel = true; if ((Channel <= 14) && (Channel >= 1)) { - if (IsSupported24G(Adapter->registrypriv.wireless_mode) == false) { + if (IsSupported24G(Adapter->registrypriv.wireless_mode) == false) bLegalChannel = false; - DBG_871X("(Channel <= 14) && (Channel >= 1) but wireless_mode do not support 2.4G\n"); - } } else { bLegalChannel = false; - DBG_871X("Channel is Invalid !!!\n"); } return bLegalChannel; @@ -687,7 +681,6 @@ u8 HwRateToMRate(u8 rate) break; default: - DBG_871X("HwRateToMRate(): Non supported Rate [%x]!!!\n", rate); break; } @@ -923,29 +916,15 @@ s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf) c2h_evt->seq = rtw_read8(adapter, REG_C2HEVT_CMD_SEQ_88XX); c2h_evt->plen = rtw_read8(adapter, REG_C2HEVT_CMD_LEN_88XX); - RT_PRINT_DATA( - _module_hal_init_c_, - _drv_info_, - "c2h_evt_read(): ", - &c2h_evt, - sizeof(c2h_evt) - ); - - DBG_871X( - "%s id:%u, len:%u, seq:%u, trigger:0x%02x\n", - __func__, - c2h_evt->id, - c2h_evt->plen, - c2h_evt->seq, - trigger - ); + print_hex_dump_debug(DRIVER_PREFIX ": c2h_evt_read(): ", DUMP_PREFIX_NONE, + 16, 1, &c2h_evt, sizeof(c2h_evt), false); /* Read the content */ for (i = 0; i < c2h_evt->plen; i++) c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i); - RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): Command Content:\n", - c2h_evt->payload, c2h_evt->plen); + print_hex_dump_debug(DRIVER_PREFIX ": c2h_evt_read(): Command Content:\n", + DUMP_PREFIX_NONE, 16, 1, c2h_evt->payload, c2h_evt->plen, false); ret = _SUCCESS; @@ -1005,7 +984,7 @@ void hw_var_port_switch(struct adapter *adapter) void SetHwReg(struct adapter *adapter, u8 variable, u8 *val) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &(hal_data->odmpriv); + struct dm_odm_t *odm = &(hal_data->odmpriv); switch (variable) { case HW_VAR_PORT_SWITCH: @@ -1072,12 +1051,9 @@ void SetHwReg(struct adapter *adapter, u8 variable, u8 *val) /* TODO - Is something needed here? */ break; default: - DBG_871X_LEVEL( - _drv_always_, - FUNC_ADPT_FMT" variable(%d) not defined!\n", - FUNC_ADPT_ARG(adapter), - variable - ); + netdev_dbg(adapter->pnetdev, + FUNC_ADPT_FMT " variable(%d) not defined!\n", + FUNC_ADPT_ARG(adapter), variable); break; } } @@ -1085,7 +1061,7 @@ void SetHwReg(struct adapter *adapter, u8 variable, u8 *val) void GetHwReg(struct adapter *adapter, u8 variable, u8 *val) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &(hal_data->odmpriv); + struct dm_odm_t *odm = &(hal_data->odmpriv); switch (variable) { case HW_VAR_BASIC_RATE: @@ -1098,12 +1074,9 @@ void GetHwReg(struct adapter *adapter, u8 variable, u8 *val) *((u8 *)val) = hal_data->rf_type; break; default: - DBG_871X_LEVEL( - _drv_always_, - FUNC_ADPT_FMT" variable(%d) not defined!\n", - FUNC_ADPT_ARG(adapter), - variable - ); + netdev_dbg(adapter->pnetdev, + FUNC_ADPT_FMT " variable(%d) not defined!\n", + FUNC_ADPT_ARG(adapter), variable); break; } } @@ -1112,11 +1085,11 @@ void GetHwReg(struct adapter *adapter, u8 variable, u8 *val) u8 SetHalDefVar( - struct adapter *adapter, enum HAL_DEF_VARIABLE variable, void *value + struct adapter *adapter, enum hal_def_variable variable, void *value ) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &(hal_data->odmpriv); + struct dm_odm_t *odm = &(hal_data->odmpriv); u8 bResult = _SUCCESS; switch (variable) { @@ -1128,14 +1101,8 @@ u8 SetHalDefVar( odm->DebugComponents &= ~(ODM_COMP_DIG | ODM_COMP_FA_CNT); break; case HAL_DEF_DBG_RX_INFO_DUMP: - DBG_871X("============ Rx Info dump ===================\n"); - DBG_871X("bLinked = %d, RSSI_Min = %d(%%)\n", - odm->bLinked, odm->RSSI_Min); if (odm->bLinked) { - DBG_871X("RxRate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", - HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); - #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA rtw_dump_raw_rssi_info(adapter); #endif @@ -1154,27 +1121,23 @@ u8 SetHalDefVar( if (dm_func == 0) { /* disable all dynamic func */ odm->SupportAbility = DYNAMIC_FUNC_DISABLE; - DBG_8192C("==> Disable all dynamic function...\n"); } else if (dm_func == 1) {/* disable DIG */ odm->SupportAbility &= (~DYNAMIC_BB_DIG); - DBG_8192C("==> Disable DIG...\n"); } else if (dm_func == 2) {/* disable High power */ odm->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); } else if (dm_func == 3) {/* disable tx power tracking */ odm->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); - DBG_8192C("==> Disable tx power tracking...\n"); } else if (dm_func == 4) {/* disable BT coexistence */ dm->DMFlag &= (~DYNAMIC_FUNC_BT); } else if (dm_func == 5) {/* disable antenna diversity */ odm->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); } else if (dm_func == 6) {/* turn on all dynamic func */ if (!(odm->SupportAbility & DYNAMIC_BB_DIG)) { - DIG_T *pDigTable = &odm->DM_DigTable; + struct dig_t *pDigTable = &odm->DM_DigTable; pDigTable->CurIGValue = rtw_read8(adapter, 0xc50); } dm->DMFlag |= DYNAMIC_FUNC_BT; odm->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; - DBG_8192C("==> Turn on all dynamic function...\n"); } } break; @@ -1188,7 +1151,9 @@ u8 SetHalDefVar( hal_data->AntDetection = *((u8 *)value); break; default: - DBG_871X_LEVEL(_drv_always_, "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __func__, variable); + netdev_dbg(adapter->pnetdev, + "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", + __func__, variable); bResult = _FAIL; break; } @@ -1197,11 +1162,11 @@ u8 SetHalDefVar( } u8 GetHalDefVar( - struct adapter *adapter, enum HAL_DEF_VARIABLE variable, void *value + struct adapter *adapter, enum hal_def_variable variable, void *value ) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); - DM_ODM_T *odm = &(hal_data->odmpriv); + struct dm_odm_t *odm = &(hal_data->odmpriv); u8 bResult = _SUCCESS; switch (variable) { @@ -1243,7 +1208,9 @@ u8 GetHalDefVar( *((u32 *)value) = PAGE_SIZE_128; break; default: - DBG_871X_LEVEL(_drv_always_, "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __func__, variable); + netdev_dbg(adapter->pnetdev, + "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", + __func__, variable); bResult = _FAIL; break; } @@ -1253,26 +1220,12 @@ u8 GetHalDefVar( void GetHalODMVar( struct adapter *Adapter, - enum HAL_ODM_VARIABLE eVariable, + enum hal_odm_variable eVariable, void *pValue1, void *pValue2 ) { switch (eVariable) { -#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - case HAL_ODM_NOISE_MONITOR: - { - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - u8 chan = *(u8 *)pValue1; - *(s16 *)pValue2 = pHalData->noise[chan]; - #ifdef DBG_NOISE_MONITOR - DBG_8192C("### Noise monitor chan(%d)-noise:%d (dBm) ###\n", - chan, pHalData->noise[chan]); - #endif - - } - break; -#endif/* ifdef CONFIG_BACKGROUND_NOISE_MONITOR */ default: break; } @@ -1280,23 +1233,21 @@ void GetHalODMVar( void SetHalODMVar( struct adapter *Adapter, - enum HAL_ODM_VARIABLE eVariable, + enum hal_odm_variable eVariable, void *pValue1, bool bSet ) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - PDM_ODM_T podmpriv = &pHalData->odmpriv; + struct dm_odm_t *podmpriv = &pHalData->odmpriv; /* _irqL irqL; */ switch (eVariable) { case HAL_ODM_STA_INFO: { struct sta_info *psta = pValue1; if (bSet) { - DBG_8192C("### Set STA_(%d) info ###\n", psta->mac_id); ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta); } else { - DBG_8192C("### Clean STA_(%d) info ###\n", psta->mac_id); /* spin_lock_bh(&pHalData->odm_stainfo_lock); */ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL); @@ -1310,27 +1261,6 @@ void SetHalODMVar( case HAL_ODM_WIFI_DISPLAY_STATE: ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet); break; - #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - case HAL_ODM_NOISE_MONITOR: - { - struct noise_info *pinfo = pValue1; - - #ifdef DBG_NOISE_MONITOR - DBG_8192C("### Noise monitor chan(%d)-bPauseDIG:%d, IGIValue:0x%02x, max_time:%d (ms) ###\n", - pinfo->chan, pinfo->bPauseDIG, pinfo->IGIValue, pinfo->max_time); - #endif - - pHalData->noise[pinfo->chan] = ODM_InbandNoise_Monitor(podmpriv, pinfo->bPauseDIG, pinfo->IGIValue, pinfo->max_time); - DBG_871X("chan_%d, noise = %d (dBm)\n", pinfo->chan, pHalData->noise[pinfo->chan]); - #ifdef DBG_NOISE_MONITOR - DBG_871X("noise_a = %d, noise_b = %d noise_all:%d\n", - podmpriv->noise_level.noise[ODM_RF_PATH_A], - podmpriv->noise_level.noise[ODM_RF_PATH_B], - podmpriv->noise_level.noise_all); - #endif - } - break; - #endif/* ifdef CONFIG_BACKGROUND_NOISE_MONITOR */ default: break; @@ -1394,11 +1324,8 @@ bool GetHexValueFromString(char *szStr, u32 *pu4bVal, u32 *pu4bMove) char *szScan = szStr; /* Check input parameter. */ - if (!szStr || !pu4bVal || !pu4bMove) { - DBG_871X("GetHexValueFromString(): Invalid input arguments! szStr: %p, pu4bVal: %p, pu4bMove: %p\n", - szStr, pu4bVal, pu4bMove); + if (!szStr || !pu4bVal || !pu4bMove) return false; - } /* Initialize output. */ *pu4bMove = 0; @@ -1572,8 +1499,6 @@ void linked_info_dump(struct adapter *padapter, u8 benable) if (padapter->bLinkInfoDump == benable) return; - DBG_871X("%s %s\n", __func__, (benable) ? "enable" : "disable"); - if (benable) { pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); @@ -1595,12 +1520,10 @@ void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter) struct hal_com_data *pHalData = GET_HAL_DATA(padapter); struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; - DBG_871X_SEL_NL( - sel, - "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", - HDATA_RATE(psample_pkt_rssi->data_rate), - psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all - ); + netdev_dbg(padapter->pnetdev, + "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", + HDATA_RATE(psample_pkt_rssi->data_rate), + psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); isCCKrate = psample_pkt_rssi->data_rate <= DESC_RATE11M; @@ -1608,20 +1531,17 @@ void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter) psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { - DBG_871X_SEL_NL( - sel, - "RF_PATH_%d =>signal_strength:%d(%%), signal_quality:%d(%%)\n", - rf_path, psample_pkt_rssi->mimo_signal_strength[rf_path], - psample_pkt_rssi->mimo_signal_quality[rf_path] - ); + netdev_dbg(padapter->pnetdev, + "RF_PATH_%d =>signal_strength:%d(%%), signal_quality:%d(%%)\n", + rf_path, + psample_pkt_rssi->mimo_signal_strength[rf_path], + psample_pkt_rssi->mimo_signal_quality[rf_path]); if (!isCCKrate) { - DBG_871X_SEL_NL( - sel, - "\trx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", - psample_pkt_rssi->ofdm_pwr[rf_path], - psample_pkt_rssi->ofdm_snr[rf_path] - ); + netdev_dbg(padapter->pnetdev, + "\trx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", + psample_pkt_rssi->ofdm_pwr[rf_path], + psample_pkt_rssi->ofdm_snr[rf_path]); } } } @@ -1631,9 +1551,6 @@ void rtw_dump_raw_rssi_info(struct adapter *padapter) u8 isCCKrate, rf_path; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; - DBG_871X("============ RAW Rx Info dump ===================\n"); - DBG_871X("RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", - HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); isCCKrate = psample_pkt_rssi->data_rate <= DESC_RATE11M; @@ -1641,9 +1558,6 @@ void rtw_dump_raw_rssi_info(struct adapter *padapter) psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { - DBG_871X("RF_PATH_%d =>signal_strength:%d(%%), signal_quality:%d(%%)" - , rf_path, psample_pkt_rssi->mimo_signal_strength[rf_path], psample_pkt_rssi->mimo_signal_quality[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]); @@ -1698,34 +1612,25 @@ void rtw_bb_rf_gain_offset(struct adapter *padapter) u32 res, i = 0; u32 *Array = Array_kfreemap; u32 v1 = 0, v2 = 0, target = 0; - /* DBG_871X("+%s value: 0x%02x+\n", __func__, value); */ if (value & BIT4) { - DBG_871X("Offset RF Gain.\n"); - DBG_871X("Offset RF Gain. padapter->eeprompriv.EEPROMRFGainVal = 0x%x\n", padapter->eeprompriv.EEPROMRFGainVal); if (padapter->eeprompriv.EEPROMRFGainVal != 0xff) { res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); res &= 0xfff87fff; - DBG_871X("Offset RF Gain. before reg 0x7f = 0x%08x\n", res); /* res &= 0xfff87fff; */ for (i = 0; i < ARRAY_SIZE(Array_kfreemap); i += 2) { v1 = Array[i]; v2 = Array[i+1]; if (v1 == padapter->eeprompriv.EEPROMRFGainVal) { - DBG_871X("Offset RF Gain. got v1 = 0x%x , v2 = 0x%x\n", v1, v2); target = v2; break; } } - DBG_871X("padapter->eeprompriv.EEPROMRFGainVal = 0x%x , Gain offset Target Value = 0x%x\n", padapter->eeprompriv.EEPROMRFGainVal, target); PHY_SetRFReg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18|BIT17|BIT16|BIT15, target); /* res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; */ /* rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); */ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); - DBG_871X("Offset RF Gain. After reg 0x7f = 0x%08x\n", res); - } else - DBG_871X("Offset RF Gain. padapter->eeprompriv.EEPROMRFGainVal = 0x%x != 0xff, didn't run Kfree\n", padapter->eeprompriv.EEPROMRFGainVal); - } else - DBG_871X("Using the default RF gain.\n"); + } + } } diff --git a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c index 10250642d30ae707842a5f905d807b3729487b05..94d11689b4ac6b9c2f039699820cebadb9f63c7b 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c @@ -12,15 +12,13 @@ #include <linux/kernel.h> u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath, - u8 TxNum, enum RATE_SECTION RateSection) + u8 TxNum, enum rate_section RateSection) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); u8 value = 0; - if (RfPath > ODM_RF_PATH_D) { - DBG_871X("Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n", RfPath); + if (RfPath > ODM_RF_PATH_D) return 0; - } if (Band == BAND_ON_2_4G) { switch (RateSection) { @@ -55,8 +53,6 @@ u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath, value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][9]; break; default: - DBG_871X("Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n", - RateSection, RfPath, TxNum); break; } } else if (Band == BAND_ON_5G) { @@ -89,12 +85,9 @@ u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath, value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][8]; break; default: - DBG_871X("Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n", - RateSection, RfPath, TxNum); break; } - } else - DBG_871X("Invalid Band %d in PHY_GetTxPowerByRateBase()\n", Band); + } return value; } @@ -104,17 +97,15 @@ phy_SetTxPowerByRateBase( struct adapter *Adapter, u8 Band, u8 RfPath, - enum RATE_SECTION RateSection, + enum rate_section RateSection, u8 TxNum, u8 Value ) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - if (RfPath > ODM_RF_PATH_D) { - DBG_871X("Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n", RfPath); + if (RfPath > ODM_RF_PATH_D) return; - } if (Band == BAND_ON_2_4G) { switch (RateSection) { @@ -149,8 +140,6 @@ phy_SetTxPowerByRateBase( pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][9] = Value; break; default: - DBG_871X("Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in phy_SetTxPowerByRateBase()\n", - RateSection, RfPath, TxNum); break; } } else if (Band == BAND_ON_5G) { @@ -183,12 +172,9 @@ phy_SetTxPowerByRateBase( pHalData->TxPwrByRateBase5G[RfPath][TxNum][8] = Value; break; default: - DBG_871X("Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in phy_SetTxPowerByRateBase()\n", - RateSection, RfPath, TxNum); break; } - } else - DBG_871X("Invalid Band %d in phy_SetTxPowerByRateBase()\n", Band); + } } static void @@ -198,71 +184,52 @@ struct adapter *padapter { u8 path, base; - /* DBG_871X("===>%s\n", __func__); */ - for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_B; ++path) { base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_11M); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, CCK, RF_1TX, base); - /* DBG_871X("Power index base of 2.4G path %d 1Tx CCK = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_54M); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, OFDM, RF_1TX, base); - /* DBG_871X("Power index base of 2.4G path %d 1Tx OFDM = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS0_MCS7, RF_1TX, base); - /* DBG_871X("Power index base of 2.4G path %d 1Tx MCS0-7 = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_2TX, MGN_MCS15); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS8_MCS15, RF_2TX, base); - /* DBG_871X("Power index base of 2.4G path %d 2Tx MCS8-15 = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_3TX, MGN_MCS23); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS16_MCS23, RF_3TX, base); - /* DBG_871X("Power index base of 2.4G path %d 3Tx MCS16-23 = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_VHT1SS_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base); - /* DBG_871X("Power index base of 2.4G path %d 1Tx VHT1SS = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_2TX, MGN_VHT2SS_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base); - /* DBG_871X("Power index base of 2.4G path %d 2Tx VHT2SS = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_3TX, MGN_VHT3SS_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_3SSMCS0_3SSMCS9, RF_3TX, base); - /* DBG_871X("Power index base of 2.4G path %d 3Tx VHT3SS = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_54M); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, OFDM, RF_1TX, base); - /* DBG_871X("Power index base of 5G path %d 1Tx OFDM = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS0_MCS7, RF_1TX, base); - /* DBG_871X("Power index base of 5G path %d 1Tx MCS0~7 = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_2TX, MGN_MCS15); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS8_MCS15, RF_2TX, base); - /* DBG_871X("Power index base of 5G path %d 2Tx MCS8~15 = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_3TX, MGN_MCS23); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS16_MCS23, RF_3TX, base); - /* DBG_871X("Power index base of 5G path %d 3Tx MCS16~23 = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_VHT1SS_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base); - /* DBG_871X("Power index base of 5G path %d 1Tx VHT1SS = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_2TX, MGN_VHT2SS_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base); - /* DBG_871X("Power index base of 5G path %d 2Tx VHT2SS = > 0x%x\n", path, base); */ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_3TX, MGN_VHT2SS_MCS7); phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_3SSMCS0_3SSMCS9, RF_3TX, base); - /* DBG_871X("Power index base of 5G path %d 3Tx VHT3SS = > 0x%x\n", path, base); */ } - - /* DBG_871X("<===%s\n", __func__); */ } u8 PHY_GetRateSectionIndexOfTxPowerByRate( @@ -270,7 +237,7 @@ u8 PHY_GetRateSectionIndexOfTxPowerByRate( ) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; u8 index = 0; if (pDM_Odm->PhyRegPgVersion == 0) { @@ -325,7 +292,6 @@ u8 PHY_GetRateSectionIndexOfTxPowerByRate( index = 13; break; default: - DBG_871X("Invalid RegAddr 0x3%x in PHY_GetRateSectionIndexOfTxPowerByRate()", RegAddr); break; } } @@ -715,7 +681,6 @@ PHY_GetRateValuesOfTxPowerByRate( break; default: - DBG_871X("Invalid RegAddr 0x%x in %s()\n", RegAddr, __func__); break; } } @@ -736,20 +701,14 @@ static void PHY_StoreTxPowerByRateNew( PHY_GetRateValuesOfTxPowerByRate(padapter, RegAddr, BitMask, Data, rateIndex, PwrByRateVal, &rateNum); - if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { - DBG_871X("Invalid Band %d\n", Band); + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) return; - } - if (RfPath > ODM_RF_PATH_D) { - DBG_871X("Invalid RfPath %d\n", RfPath); + if (RfPath > ODM_RF_PATH_D) return; - } - if (TxNum > ODM_RF_PATH_D) { - DBG_871X("Invalid TxNum %d\n", TxNum); + if (TxNum > ODM_RF_PATH_D) return; - } for (i = 0; i < rateNum; ++i) { if (rateIndex[i] == PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS0) || @@ -768,8 +727,6 @@ static void PHY_StoreTxPowerByRateOld( u8 index = PHY_GetRateSectionIndexOfTxPowerByRate(padapter, RegAddr, BitMask); pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][index] = Data; - /* DBG_871X("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n", pHalData->pwrGroupCnt, */ - /* pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0]); */ } void PHY_InitTxPowerByRate(struct adapter *padapter) @@ -795,7 +752,7 @@ void PHY_StoreTxPowerByRate( ) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; if (pDM_Odm->PhyRegPgVersion > 0) PHY_StoreTxPowerByRateNew(padapter, Band, RfPath, TxNum, RegAddr, BitMask, Data); @@ -806,9 +763,7 @@ void PHY_StoreTxPowerByRate( pHalData->pwrGroupCnt++; else if (RegAddr == rTxAGC_B_Mcs15_Mcs12 && pHalData->rf_type != RF_1T1R) pHalData->pwrGroupCnt++; - } else - DBG_871X("Invalid PHY_REG_PG.txt version %d\n", pDM_Odm->PhyRegPgVersion); - + } } static void @@ -845,8 +800,6 @@ struct adapter *padapter MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9 }; - /* DBG_871X("===>PHY_ConvertTxPowerByRateInDbmToRelativeValues()\n"); */ - for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) { for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_D; ++path) { for (txNum = RF_1TX; txNum < RF_MAX_TX_NUM; ++txNum) { @@ -908,8 +861,6 @@ struct adapter *padapter } } } - - /* DBG_871X("<===PHY_ConvertTxPowerByRateInDbmToRelativeValues()\n"); */ } /* @@ -1003,8 +954,7 @@ void PHY_SetTxPowerIndexByRateSection( pHalData->CurrentChannelBW, Channel, vhtRates4T, ARRAY_SIZE(vhtRates4T)); - } else - DBG_871X("Invalid RateSection %d in %s", RateSection, __func__); + } } static bool phy_GetChnlIndex(u8 Channel, u8 *ChannelIdx) @@ -1039,7 +989,7 @@ u8 PHY_GetTxPowerIndexBase( struct adapter *padapter, u8 RFPath, u8 Rate, - enum CHANNEL_WIDTH BandWidth, + enum channel_width BandWidth, u8 Channel, bool *bIn24G ) @@ -1049,31 +999,21 @@ u8 PHY_GetTxPowerIndexBase( u8 txPower = 0; u8 chnlIdx = (Channel-1); - if (HAL_IsLegalChannel(padapter, Channel) == false) { + if (HAL_IsLegalChannel(padapter, Channel) == false) chnlIdx = 0; - DBG_871X("Illegal channel!!\n"); - } *bIn24G = phy_GetChnlIndex(Channel, &chnlIdx); - /* DBG_871X("[%s] Channel Index: %d\n", (*bIn24G?"2.4G":"5G"), chnlIdx); */ - if (*bIn24G) { /* 3 ============================== 2.4 G ============================== */ if (IS_CCK_RATE(Rate)) txPower = pHalData->Index24G_CCK_Base[RFPath][chnlIdx]; else if (MGN_6M <= Rate) txPower = pHalData->Index24G_BW40_Base[RFPath][chnlIdx]; - else - DBG_871X("PHY_GetTxPowerIndexBase: INVALID Rate.\n"); - - /* DBG_871X("Base Tx power(RF-%c, Rate #%d, Channel Index %d) = 0x%X\n", */ - /* ((RFPath == 0)?'A':'B'), Rate, chnlIdx, txPower); */ /* OFDM-1T */ - if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate)) { + if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate)) txPower += pHalData->OFDM_24G_Diff[RFPath][TX_1S]; - /* DBG_871X("+PowerDiff 2.4G (RF-%c): (OFDM-1T) = (%d)\n", ((RFPath == 0)?'A':'B'), pHalData->OFDM_24G_Diff[RFPath][TX_1S]); */ - } + if (BandWidth == CHANNEL_WIDTH_20) { /* BW20-1S, BW20-2S */ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW20_24G_Diff[RFPath][TX_1S]; @@ -1084,9 +1024,6 @@ u8 PHY_GetTxPowerIndexBase( if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW20_24G_Diff[RFPath][TX_4S]; - /* DBG_871X("+PowerDiff 2.4G (RF-%c): (BW20-1S, BW20-2S, BW20-3S, BW20-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ - /* pHalData->BW20_24G_Diff[RFPath][TX_1S], pHalData->BW20_24G_Diff[RFPath][TX_2S], */ - /* pHalData->BW20_24G_Diff[RFPath][TX_3S], pHalData->BW20_24G_Diff[RFPath][TX_4S]); */ } else if (BandWidth == CHANNEL_WIDTH_40) { /* BW40-1S, BW40-2S */ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S]; @@ -1097,9 +1034,6 @@ u8 PHY_GetTxPowerIndexBase( if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S]; - /* DBG_871X("+PowerDiff 2.4G (RF-%c): (BW40-1S, BW40-2S, BW40-3S, BW40-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ - /* pHalData->BW40_24G_Diff[RFPath][TX_1S], pHalData->BW40_24G_Diff[RFPath][TX_2S], */ - /* pHalData->BW40_24G_Diff[RFPath][TX_3S], pHalData->BW40_24G_Diff[RFPath][TX_4S]); */ } /* Willis suggest adopt BW 40M power index while in BW 80 mode */ else if (BandWidth == CHANNEL_WIDTH_80) { @@ -1112,24 +1046,14 @@ u8 PHY_GetTxPowerIndexBase( if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S]; - /* DBG_871X("+PowerDiff 2.4G (RF-%c): (BW40-1S, BW40-2S, BW40-3S, BW40-4T) = (%d, %d, %d, %d) P.S. Current is in BW 80MHz\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ - /* pHalData->BW40_24G_Diff[RFPath][TX_1S], pHalData->BW40_24G_Diff[RFPath][TX_2S], */ - /* pHalData->BW40_24G_Diff[RFPath][TX_3S], pHalData->BW40_24G_Diff[RFPath][TX_4S]); */ } } else {/* 3 ============================== 5 G ============================== */ if (MGN_6M <= Rate) txPower = pHalData->Index5G_BW40_Base[RFPath][chnlIdx]; - else - DBG_871X("===> mpt_ProQueryCalTxPower_Jaguar: INVALID Rate.\n"); - - /* DBG_871X("Base Tx power(RF-%c, Rate #%d, Channel Index %d) = 0x%X\n", */ - /* ((RFPath == 0)?'A':'B'), Rate, chnlIdx, txPower); */ /* OFDM-1T */ - if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate)) { + if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate)) txPower += pHalData->OFDM_5G_Diff[RFPath][TX_1S]; - /* DBG_871X("+PowerDiff 5G (RF-%c): (OFDM-1T) = (%d)\n", ((RFPath == 0)?'A':'B'), pHalData->OFDM_5G_Diff[RFPath][TX_1S]); */ - } /* BW20-1S, BW20-2S */ if (BandWidth == CHANNEL_WIDTH_20) { @@ -1142,9 +1066,6 @@ u8 PHY_GetTxPowerIndexBase( if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW20_5G_Diff[RFPath][TX_4S]; - /* DBG_871X("+PowerDiff 5G (RF-%c): (BW20-1S, BW20-2S, BW20-3S, BW20-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ - /* pHalData->BW20_5G_Diff[RFPath][TX_1S], pHalData->BW20_5G_Diff[RFPath][TX_2S], */ - /* pHalData->BW20_5G_Diff[RFPath][TX_3S], pHalData->BW20_5G_Diff[RFPath][TX_4S]); */ } else if (BandWidth == CHANNEL_WIDTH_40) { /* BW40-1S, BW40-2S */ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW40_5G_Diff[RFPath][TX_1S]; @@ -1155,9 +1076,6 @@ u8 PHY_GetTxPowerIndexBase( if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW40_5G_Diff[RFPath][TX_4S]; - /* DBG_871X("+PowerDiff 5G(RF-%c): (BW40-1S, BW40-2S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ - /* pHalData->BW40_5G_Diff[RFPath][TX_1S], pHalData->BW40_5G_Diff[RFPath][TX_2S], */ - /* pHalData->BW40_5G_Diff[RFPath][TX_3S], pHalData->BW40_5G_Diff[RFPath][TX_4S]); */ } else if (BandWidth == CHANNEL_WIDTH_80) { /* BW80-1S, BW80-2S */ /* <20121220, Kordan> Get the index of array "Index5G_BW80_Base". */ u8 channel5G_80M[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171}; @@ -1175,10 +1093,6 @@ u8 PHY_GetTxPowerIndexBase( txPower += pHalData->BW80_5G_Diff[RFPath][TX_3S]; if ((MGN_MCS23 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) txPower += pHalData->BW80_5G_Diff[RFPath][TX_4S]; - - /* DBG_871X("+PowerDiff 5G(RF-%c): (BW80-1S, BW80-2S, BW80-3S, BW80-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ - /* pHalData->BW80_5G_Diff[RFPath][TX_1S], pHalData->BW80_5G_Diff[RFPath][TX_2S], */ - /* pHalData->BW80_5G_Diff[RFPath][TX_3S], pHalData->BW80_5G_Diff[RFPath][TX_4S]); */ } } @@ -1188,20 +1102,16 @@ u8 PHY_GetTxPowerIndexBase( s8 PHY_GetTxPowerTrackingOffset(struct adapter *padapter, u8 RFPath, u8 Rate) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; s8 offset = 0; if (pDM_Odm->RFCalibrateInfo.TxPowerTrackControl == false) return offset; - if ((Rate == MGN_1M) || (Rate == MGN_2M) || (Rate == MGN_5_5M) || (Rate == MGN_11M)) { + if ((Rate == MGN_1M) || (Rate == MGN_2M) || (Rate == MGN_5_5M) || (Rate == MGN_11M)) offset = pDM_Odm->Remnant_CCKSwingIdx; - /* DBG_871X("+Remnant_CCKSwingIdx = 0x%x\n", RFPath, Rate, pDM_Odm->Remnant_CCKSwingIdx); */ - } else { + else offset = pDM_Odm->Remnant_OFDMSwingIdx[RFPath]; - /* DBG_871X("+Remanant_OFDMSwingIdx[RFPath %u][Rate 0x%x] = 0x%x\n", RFPath, Rate, pDM_Odm->Remnant_OFDMSwingIdx[RFPath]); */ - - } return offset; } @@ -1463,7 +1373,6 @@ u8 PHY_GetRateIndexOfTxPowerByRate(u8 Rate) index = 83; break; default: - DBG_871X("Invalid rate 0x%x in %s\n", Rate, __func__); break; } return index; @@ -1481,22 +1390,17 @@ s8 PHY_GetTxPowerByRate( padapter->registrypriv.RegEnableTxPowerByRate == 0) return 0; - if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { - DBG_871X("Invalid band %d in %s\n", Band, __func__); + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) return value; - } - if (RFPath > ODM_RF_PATH_D) { - DBG_871X("Invalid RfPath %d in %s\n", RFPath, __func__); + + if (RFPath > ODM_RF_PATH_D) return value; - } - if (TxNum >= RF_MAX_TX_NUM) { - DBG_871X("Invalid TxNum %d in %s\n", TxNum, __func__); + + if (TxNum >= RF_MAX_TX_NUM) return value; - } - if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) { - DBG_871X("Invalid RateIndex %d in %s\n", rateIndex, __func__); + + if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) return value; - } return pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex]; @@ -1514,22 +1418,17 @@ void PHY_SetTxPowerByRate( struct hal_com_data *pHalData = GET_HAL_DATA(padapter); u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate); - if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { - DBG_871X("Invalid band %d in %s\n", Band, __func__); + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) return; - } - if (RFPath > ODM_RF_PATH_D) { - DBG_871X("Invalid RfPath %d in %s\n", RFPath, __func__); + + if (RFPath > ODM_RF_PATH_D) return; - } - if (TxNum >= RF_MAX_TX_NUM) { - DBG_871X("Invalid TxNum %d in %s\n", TxNum, __func__); + + if (TxNum >= RF_MAX_TX_NUM) return; - } - if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) { - DBG_871X("Invalid RateIndex %d in %s\n", rateIndex, __func__); + + if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) return; - } pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex] = Value; } @@ -1556,7 +1455,7 @@ void PHY_SetTxPowerLevelByPath(struct adapter *Adapter, u8 channel, u8 path) void PHY_SetTxPowerIndexByRateArray( struct adapter *padapter, u8 RFPath, - enum CHANNEL_WIDTH BandWidth, + enum channel_width BandWidth, u8 Channel, u8 *Rates, u8 RateArraySize @@ -1601,16 +1500,12 @@ static s8 phy_GetChannelIndexOfTxPowerLimit(u8 Band, u8 Channel) if (channel5G[i] == Channel) channelIndex = i; } - } else - DBG_871X("Invalid Band %d in %s", Band, __func__); - - if (channelIndex == -1) - DBG_871X("Invalid Channel %d of Band %d in %s", Channel, Band, __func__); + } return channelIndex; } -static s16 get_bandwidth_idx(const enum CHANNEL_WIDTH bandwidth) +static s16 get_bandwidth_idx(const enum channel_width bandwidth) { switch (bandwidth) { case CHANNEL_WIDTH_20: @@ -1667,13 +1562,12 @@ static s16 get_rate_sctn_idx(const u8 rate) case MGN_VHT4SS_MCS9: return 9; default: - DBG_871X("Wrong rate 0x%x\n", rate); return -1; } } s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel, - enum BAND_TYPE band_type, enum CHANNEL_WIDTH bandwidth, + enum band_type band_type, enum channel_width bandwidth, u8 rf_path, u8 data_rate, u8 channel) { s16 idx_band = -1; @@ -1709,9 +1603,6 @@ s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel, break; } - /* DBG_871X("pMgntInfo->RegPwrTblSel %d, final regulation %d\n", */ - /* adapter->registrypriv.RegPwrTblSel, idx_regulation); */ - if (band_type == BAND_ON_2_4G) idx_band = 0; else if (band_type == BAND_ON_5G) @@ -1720,9 +1611,6 @@ s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel, idx_bandwidth = get_bandwidth_idx(bandwidth); idx_rate_sctn = get_rate_sctn_idx(data_rate); - if (band_type == BAND_ON_5G && idx_rate_sctn == 0) - DBG_871X("Wrong rate 0x%x: No CCK in 5G Band\n", DataRate); - /* workaround for wrong index combination to obtain tx power limit, */ /* OFDM only exists in BW 20M */ /* CCK table will only be given in BW 20M */ @@ -1737,13 +1625,8 @@ s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel, channel = phy_GetChannelIndexOfTxPowerLimit(band_type, channel); if (idx_band == -1 || idx_regulation == -1 || idx_bandwidth == -1 || - idx_rate_sctn == -1 || idx_channel == -1) { - /* DBG_871X("Wrong index value to access power limit table [band %d][regulation %d][bandwidth %d][rf_path %d][rate_section %d][chnlGroup %d]\n", */ - /* idx_band, idx_regulation, idx_bandwidth, rf_path, */ - /* idx_rate_sctn, channel); */ - + idx_rate_sctn == -1 || idx_channel == -1) return MAX_POWER_INDEX; - } if (band_type == BAND_ON_2_4G) { s8 limits[10] = {0}; u8 i = 0; @@ -1780,32 +1663,8 @@ s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel, [idx_rate_sctn] [idx_channel] [rf_path]; - } else { - DBG_871X("No power limit table of the specified band\n"); } - /* combine 5G VHT & HT rate */ - /* 5G 20M and 40M HT and VHT can cross reference */ - /* - if (band_type == BAND_ON_5G && pwr_lmt == MAX_POWER_INDEX) { - if (idx_bandwidth == 0 || idx_bandwidth == 1) { - RT_TRACE(COMP_INIT, DBG_LOUD, ("No power limit table of the specified band %d, bandwidth %d, ratesection %d, rf path %d\n", - idx_band, idx_bandwidth, - idx_rate_sctn, rf_path)); - if (idx_rate_sctn == 2) - pwr_lmt = hal_data->TxPwrLimit_5G[idx_regulation][idx_bandwidth][4][idx_channel][rf_path]; - else if (idx_rate_sctn == 4) - pwr_lmt = hal_data->TxPwrLimit_5G[idx_regulation][idx_bandwidth][2][idx_channel][rf_path]; - else if (idx_rate_sctn == 3) - pwr_lmt = hal_data->TxPwrLimit_5G[idx_regulation][idx_bandwidth][5][idx_channel][rf_path]; - else if (idx_rate_sctn == 5) - pwr_lmt = hal_data->TxPwrLimit_5G[idx_regulation][idx_bandwidth][3][idx_channel][rf_path]; - } - } - */ - - /* DBG_871X("TxPwrLmt[Regulation %d][Band %d][BW %d][RFPath %d][Rate 0x%x][Chnl %d] = %d\n", */ - /* idx_regulation, hal_data->CurrentBandType, bandwidth, rf_path, data_rate, channel, pwr_lmt); */ return pwr_lmt; } @@ -1823,7 +1682,6 @@ static void phy_CrossReferenceHTAndVHTTxPowerLimit(struct adapter *padapter) if (tempPwrLmt == MAX_POWER_INDEX) { u8 baseSection = 2, refSection = 6; if (bw == 0 || bw == 1) { /* 5G 20M 40M VHT and HT can cross reference */ - /* DBG_871X("No power limit table of the specified band %d, bandwidth %d, ratesection %d, channel %d, rf path %d\n", */ /* 1, bw, rateSection, channel, ODM_RF_PATH_A); */ if (rateSection >= 2 && rateSection <= 9) { if (rateSection == 2) { @@ -1854,8 +1712,6 @@ static void phy_CrossReferenceHTAndVHTTxPowerLimit(struct adapter *padapter) pHalData->TxPwrLimit_5G[regulation][bw][baseSection][channel][ODM_RF_PATH_A] = pHalData->TxPwrLimit_5G[regulation][bw][refSection][channel][ODM_RF_PATH_A]; } - - /* DBG_871X("use other value %d", tempPwrLmt); */ } } } @@ -1872,8 +1728,6 @@ void PHY_ConvertTxPowerLimitToPowerIndex(struct adapter *Adapter) s8 tempValue = 0, tempPwrLmt = 0; u8 rfPath = 0; - /* DBG_871X("=====> PHY_ConvertTxPowerLimitToPowerIndex()\n"); */ - phy_CrossReferenceHTAndVHTTxPowerLimit(Adapter); for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { @@ -1908,8 +1762,6 @@ void PHY_ConvertTxPowerLimitToPowerIndex(struct adapter *Adapter) } } } - - /* DBG_871X("<===== PHY_ConvertTxPowerLimitToPowerIndex()\n"); */ } void PHY_InitTxPowerLimit(struct adapter *Adapter) @@ -1917,8 +1769,6 @@ void PHY_InitTxPowerLimit(struct adapter *Adapter) struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); u8 i, j, k, l, m; - /* DBG_871X("=====> PHY_InitTxPowerLimit()!\n"); */ - for (i = 0; i < MAX_REGULATION_NUM; ++i) { for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j) for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) @@ -1934,8 +1784,6 @@ void PHY_InitTxPowerLimit(struct adapter *Adapter) for (l = 0; l < MAX_RF_PATH_NUM; ++l) pHalData->TxPwrLimit_5G[i][j][k][m][l] = MAX_POWER_INDEX; } - - /* DBG_871X("<===== PHY_InitTxPowerLimit()!\n"); */ } void PHY_SetTxPowerLimit( @@ -1953,12 +1801,8 @@ void PHY_SetTxPowerLimit( u8 regulation = 0, bandwidth = 0, rateSection = 0, channel; s8 powerLimit = 0, prevPowerLimit, channelIndex; - /* DBG_871X("Index of power limit table [band %s][regulation %s][bw %s][rate section %s][rf path %s][chnl %s][val %s]\n", */ - /* Band, Regulation, Bandwidth, RateSection, RfPath, Channel, PowerLimit); */ - - if (!GetU1ByteIntegerFromStringInDecimal((s8 *)Channel, &channel) || - !GetU1ByteIntegerFromStringInDecimal((s8 *)PowerLimit, &powerLimit)) - DBG_871X("Illegal index of power limit table [chnl %s][val %s]\n", Channel, PowerLimit); + GetU1ByteIntegerFromStringInDecimal((s8 *)Channel, &channel); + GetU1ByteIntegerFromStringInDecimal((s8 *)PowerLimit, &powerLimit); powerLimit = powerLimit > MAX_POWER_INDEX ? MAX_POWER_INDEX : powerLimit; @@ -1991,11 +1835,8 @@ void PHY_SetTxPowerLimit( rateSection = 8; else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("4T"), 2)) rateSection = 9; - else { - DBG_871X("Wrong rate section!\n"); + else return; - } - if (eqNByte(Bandwidth, (u8 *)("20M"), 3)) bandwidth = 0; @@ -2017,8 +1858,6 @@ void PHY_SetTxPowerLimit( if (powerLimit < prevPowerLimit) pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit; - /* DBG_871X("2.4G Band value : [regulation %d][bw %d][rate_section %d][chnl %d][val %d]\n", */ - /* regulation, bandwidth, rateSection, channelIndex, pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]); */ } else if (eqNByte(Band, (u8 *)("5G"), 2)) { channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_5G, channel); @@ -2030,10 +1869,7 @@ void PHY_SetTxPowerLimit( if (powerLimit < prevPowerLimit) pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit; - /* DBG_871X("5G Band value : [regulation %d][bw %d][rate_section %d][chnl %d][val %d]\n", */ - /* regulation, bandwidth, rateSection, channel, pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]); */ } else { - DBG_871X("Cannot recognize the band info in %s\n", Band); return; } } diff --git a/drivers/staging/rtl8723bs/hal/hal_intf.c b/drivers/staging/rtl8723bs/hal/hal_intf.c index ac3066a91c84edacf926c99e4aef1dac0a73055a..8dc4dd8c6d4c6ff198d3c6444ec607224f345aef 100644 --- a/drivers/staging/rtl8723bs/hal/hal_intf.c +++ b/drivers/staging/rtl8723bs/hal/hal_intf.c @@ -63,9 +63,9 @@ void rtw_hal_dm_deinit(struct adapter *padapter) static void rtw_hal_init_opmode(struct adapter *padapter) { - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType = Ndis802_11InfrastructureMax; + enum ndis_802_11_network_infrastructure networkType = Ndis802_11InfrastructureMax; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - sint fw_state; + signed int fw_state; fw_state = get_fwstate(pmlmepriv); @@ -105,18 +105,14 @@ uint rtw_hal_init(struct adapter *padapter) rtw_bb_rf_gain_offset(padapter); } else { dvobj->padapters->hw_init_completed = false; - DBG_871X("rtw_hal_init: hal__init fail\n"); } - RT_TRACE(_module_hal_init_c_, _drv_err_, ("-rtl871x_hal_init:status = 0x%x\n", status)); - return status; - } uint rtw_hal_deinit(struct adapter *padapter) { - uint status = _SUCCESS; + uint status = _SUCCESS; struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); status = padapter->HalFunc.hal_deinit(padapter); @@ -124,9 +120,8 @@ uint rtw_hal_deinit(struct adapter *padapter) if (status == _SUCCESS) { padapter = dvobj->padapters; padapter->hw_init_completed = false; - } else { - DBG_871X("\n rtw_hal_deinit: hal_init fail\n"); } + return status; } @@ -148,27 +143,27 @@ void rtw_hal_set_hwreg_with_buf(struct adapter *padapter, u8 variable, u8 *pbuf, padapter->HalFunc.SetHwRegHandlerWithBuf(padapter, variable, pbuf, len); } -u8 rtw_hal_set_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue) +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; } -u8 rtw_hal_get_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *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; } -void rtw_hal_set_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, bool bSet) +void rtw_hal_set_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) { if (padapter->HalFunc.SetHalODMVarHandler) padapter->HalFunc.SetHalODMVarHandler(padapter, eVariable, pValue1, bSet); } -void rtw_hal_get_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, void *pValue2) +void rtw_hal_get_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, void *pValue2) { if (padapter->HalFunc.GetHalODMVarHandler) padapter->HalFunc.GetHalODMVarHandler(padapter, eVariable, pValue1, pValue2); @@ -178,18 +173,12 @@ void rtw_hal_enable_interrupt(struct adapter *padapter) { if (padapter->HalFunc.enable_interrupt) padapter->HalFunc.enable_interrupt(padapter); - else - DBG_871X("%s: HalFunc.enable_interrupt is NULL!\n", __func__); - } void rtw_hal_disable_interrupt(struct adapter *padapter) { if (padapter->HalFunc.disable_interrupt) padapter->HalFunc.disable_interrupt(padapter); - else - DBG_871X("%s: HalFunc.disable_interrupt is NULL!\n", __func__); - } u8 rtw_hal_check_ips_status(struct adapter *padapter) @@ -197,8 +186,6 @@ 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); - else - DBG_871X("%s: HalFunc.check_ips_status is NULL!\n", __func__); return val; } @@ -269,7 +256,6 @@ s32 rtw_hal_init_recv_priv(struct adapter *padapter) void rtw_hal_free_recv_priv(struct adapter *padapter) { - if (padapter->HalFunc.free_recv_priv) padapter->HalFunc.free_recv_priv(padapter); } @@ -346,7 +332,7 @@ void rtw_hal_set_chan(struct adapter *padapter, u8 channel) } void rtw_hal_set_chnl_bw(struct adapter *padapter, u8 channel, - enum CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80) + enum channel_width Bandwidth, u8 Offset40, u8 Offset80) { if (padapter->HalFunc.set_chnl_bw_handler) padapter->HalFunc.set_chnl_bw_handler(padapter, channel, @@ -358,12 +344,11 @@ void rtw_hal_dm_watchdog(struct adapter *padapter) { if (padapter->HalFunc.hal_dm_watchdog) padapter->HalFunc.hal_dm_watchdog(padapter); - } void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter) { - if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == true) { + 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 */ } @@ -422,7 +407,6 @@ s32 rtw_hal_macid_sleep(struct adapter *padapter, u32 macid) { u8 support; - support = false; rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support); if (false == support) @@ -437,7 +421,6 @@ s32 rtw_hal_macid_wakeup(struct adapter *padapter, u32 macid) { u8 support; - support = false; rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support); if (false == support) @@ -454,8 +437,6 @@ s32 rtw_hal_fill_h2c_cmd(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 if (padapter->HalFunc.fill_h2c_cmd) ret = padapter->HalFunc.fill_h2c_cmd(padapter, ElementID, CmdLen, pCmdBuffer); - else - DBG_871X("%s: func[fill_h2c_cmd] not defined!\n", __func__); return ret; } diff --git a/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c b/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c index 589e7aae7bbd817dd1489213d2dbad199f58dc71..fba67a7c069ce69e95fd570c3e3d43a04c197e7a 100644 --- a/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c +++ b/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c @@ -21,7 +21,7 @@ Major Change History: /* drivers should parse below arrays and do the corresponding actions */ /* 3 Power on Array */ -WLAN_PWR_CFG rtl8723B_power_on_flow[ +struct wlan_pwr_cfg rtl8723B_power_on_flow[ RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+ RTL8723B_TRANS_END_STEPS ] = { @@ -30,7 +30,7 @@ WLAN_PWR_CFG rtl8723B_power_on_flow[ }; /* 3Radio off GPIO Array */ -WLAN_PWR_CFG rtl8723B_radio_off_flow[ +struct wlan_pwr_cfg rtl8723B_radio_off_flow[ RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+ RTL8723B_TRANS_END_STEPS ] = { @@ -39,7 +39,7 @@ WLAN_PWR_CFG rtl8723B_radio_off_flow[ }; /* 3Card Disable Array */ -WLAN_PWR_CFG rtl8723B_card_disable_flow[ +struct wlan_pwr_cfg rtl8723B_card_disable_flow[ RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+ RTL8723B_TRANS_END_STEPS @@ -50,7 +50,7 @@ WLAN_PWR_CFG rtl8723B_card_disable_flow[ }; /* 3 Card Enable Array */ -WLAN_PWR_CFG rtl8723B_card_enable_flow[ +struct wlan_pwr_cfg rtl8723B_card_enable_flow[ RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+ RTL8723B_TRANS_END_STEPS @@ -61,7 +61,7 @@ WLAN_PWR_CFG rtl8723B_card_enable_flow[ }; /* 3Suspend Array */ -WLAN_PWR_CFG rtl8723B_suspend_flow[ +struct wlan_pwr_cfg rtl8723B_suspend_flow[ RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+ RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+ RTL8723B_TRANS_END_STEPS @@ -72,7 +72,7 @@ WLAN_PWR_CFG rtl8723B_suspend_flow[ }; /* 3 Resume Array */ -WLAN_PWR_CFG rtl8723B_resume_flow[ +struct wlan_pwr_cfg rtl8723B_resume_flow[ RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+ RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+ RTL8723B_TRANS_END_STEPS @@ -83,7 +83,7 @@ WLAN_PWR_CFG rtl8723B_resume_flow[ }; /* 3HWPDN Array */ -WLAN_PWR_CFG rtl8723B_hwpdn_flow[ +struct wlan_pwr_cfg rtl8723B_hwpdn_flow[ RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+ RTL8723B_TRANS_END_STEPS @@ -94,7 +94,7 @@ WLAN_PWR_CFG rtl8723B_hwpdn_flow[ }; /* 3 Enter LPS */ -WLAN_PWR_CFG rtl8723B_enter_lps_flow[ +struct wlan_pwr_cfg rtl8723B_enter_lps_flow[ RTL8723B_TRANS_ACT_TO_LPS_STEPS+RTL8723B_TRANS_END_STEPS ] = { /* FW behavior */ @@ -103,7 +103,7 @@ WLAN_PWR_CFG rtl8723B_enter_lps_flow[ }; /* 3 Leave LPS */ -WLAN_PWR_CFG rtl8723B_leave_lps_flow[ +struct wlan_pwr_cfg rtl8723B_leave_lps_flow[ RTL8723B_TRANS_LPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS ] = { /* FW behavior */ @@ -112,7 +112,7 @@ WLAN_PWR_CFG rtl8723B_leave_lps_flow[ }; /* 3 Enter SW LPS */ -WLAN_PWR_CFG rtl8723B_enter_swlps_flow[ +struct wlan_pwr_cfg rtl8723B_enter_swlps_flow[ RTL8723B_TRANS_ACT_TO_SWLPS_STEPS+RTL8723B_TRANS_END_STEPS ] = { /* SW behavior */ @@ -121,7 +121,7 @@ WLAN_PWR_CFG rtl8723B_enter_swlps_flow[ }; /* 3 Leave SW LPS */ -WLAN_PWR_CFG rtl8723B_leave_swlps_flow[ +struct wlan_pwr_cfg rtl8723B_leave_swlps_flow[ RTL8723B_TRANS_SWLPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS ] = { /* SW behavior */ diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c index f2a9e95a1563e81d6ed79a1ca85dc0b38848016d..092b32c41ff3e57169e2a45c8ff9a871e6e3dff8 100644 --- a/drivers/staging/rtl8723bs/hal/odm.c +++ b/drivers/staging/rtl8723bs/hal/odm.c @@ -279,1130 +279,1050 @@ u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE] = { 0x3FE /* 36, +6.0dB */ }; -/* Local Function predefine. */ - -/* START------------COMMON INFO RELATED--------------- */ -void odm_CommonInfoSelfInit(PDM_ODM_T pDM_Odm); - -void odm_CommonInfoSelfUpdate(PDM_ODM_T pDM_Odm); - -void odm_CmnInfoInit_Debug(PDM_ODM_T pDM_Odm); - -void odm_BasicDbgMessage(PDM_ODM_T pDM_Odm); - -/* END------------COMMON INFO RELATED--------------- */ +/* Remove Edca by Yu Chen */ -/* START---------------DIG--------------------------- */ -/* Remove by Yuchen */ +#define RxDefaultAnt1 0x65a9 +#define RxDefaultAnt2 0x569a -/* END---------------DIG--------------------------- */ +static void odm_CommonInfoSelfInit(struct dm_odm_t *pDM_Odm) +{ + pDM_Odm->bCckHighPower = (bool) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(CCK_RPT_FORMAT, pDM_Odm), ODM_BIT(CCK_RPT_FORMAT, pDM_Odm)); + pDM_Odm->RFPathRxEnable = (u8) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(BB_RX_PATH, pDM_Odm), ODM_BIT(BB_RX_PATH, pDM_Odm)); -/* START-------BB POWER SAVE----------------------- */ -/* Remove BB power Saving by YuChen */ -/* END---------BB POWER SAVE----------------------- */ + ODM_InitDebugSetting(pDM_Odm); -void odm_RefreshRateAdaptiveMaskCE(PDM_ODM_T pDM_Odm); + pDM_Odm->TxRate = 0xFF; +} -/* Remove by YuChen */ +static void odm_CommonInfoSelfUpdate(struct dm_odm_t *pDM_Odm) +{ + u8 EntryCnt = 0; + u8 i; + PSTA_INFO_T pEntry; -void odm_RSSIMonitorInit(PDM_ODM_T pDM_Odm); + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) { + if (*(pDM_Odm->pSecChOffset) == 1) + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel)-2; + else if (*(pDM_Odm->pSecChOffset) == 2) + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel)+2; + } else + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); -void odm_RSSIMonitorCheckCE(PDM_ODM_T pDM_Odm); + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + pEntry = pDM_Odm->pODM_StaInfo[i]; + if (IS_STA_VALID(pEntry)) + EntryCnt++; + } -void odm_RSSIMonitorCheck(PDM_ODM_T pDM_Odm); + if (EntryCnt == 1) + pDM_Odm->bOneEntryOnly = true; + else + pDM_Odm->bOneEntryOnly = false; +} -void odm_SwAntDetectInit(PDM_ODM_T pDM_Odm); +static void odm_CmnInfoInit_Debug(struct dm_odm_t *pDM_Odm) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug ==>\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform =%d\n", pDM_Odm->SupportPlatform)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility = 0x%x\n", pDM_Odm->SupportAbility)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface =%d\n", pDM_Odm->SupportInterface)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType = 0x%x\n", pDM_Odm->SupportICType)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion =%d\n", pDM_Odm->CutVersion)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion =%d\n", pDM_Odm->FabVersion)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType =%d\n", pDM_Odm->RFType)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType =%d\n", pDM_Odm->BoardType)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA =%d\n", pDM_Odm->ExtLNA)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA =%d\n", pDM_Odm->ExtPA)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW =%d\n", pDM_Odm->ExtTRSW)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID =%d\n", pDM_Odm->PatchID)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest =%d\n", pDM_Odm->bInHctTest)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest =%d\n", pDM_Odm->bWIFITest)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent =%d\n", pDM_Odm->bDualMacSmartConcurrent)); -void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext); +} +static void odm_BasicDbgMessage(struct dm_odm_t *pDM_Odm) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_BasicDbgMsg ==>\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked = %d, RSSI_Min = %d,\n", + pDM_Odm->bLinked, pDM_Odm->RSSI_Min)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RxRate = 0x%x, RSSI_A = %d, RSSI_B = %d\n", + pDM_Odm->RxRate, pDM_Odm->RSSI_A, pDM_Odm->RSSI_B)); +} +/* 3 ============================================================ */ +/* 3 RATR MASK */ +/* 3 ============================================================ */ +/* 3 ============================================================ */ +/* 3 Rate Adaptive */ +/* 3 ============================================================ */ -void odm_GlobalAdapterCheck(void); +static void odm_RateAdaptiveMaskInit(struct dm_odm_t *pDM_Odm) +{ + struct odm_rate_adaptive *pOdmRA = &pDM_Odm->RateAdaptive; -void odm_RefreshRateAdaptiveMask(PDM_ODM_T pDM_Odm); + pOdmRA->Type = DM_Type_ByDriver; + if (pOdmRA->Type == DM_Type_ByDriver) + pDM_Odm->bUseRAMask = true; + else + pDM_Odm->bUseRAMask = false; -void ODM_TXPowerTrackingCheck(PDM_ODM_T pDM_Odm); + pOdmRA->RATRState = DM_RATR_STA_INIT; + pOdmRA->LdpcThres = 35; + pOdmRA->bUseLdpc = false; + pOdmRA->HighRSSIThresh = 50; + pOdmRA->LowRSSIThresh = 20; +} -void odm_RateAdaptiveMaskInit(PDM_ODM_T pDM_Odm); +u32 ODM_Get_Rate_Bitmap( + struct dm_odm_t *pDM_Odm, + u32 macid, + u32 ra_mask, + u8 rssi_level +) +{ + PSTA_INFO_T pEntry; + u32 rate_bitmap = 0; + u8 WirelessMode; + pEntry = pDM_Odm->pODM_StaInfo[macid]; + if (!IS_STA_VALID(pEntry)) + return ra_mask; -void odm_TXPowerTrackingInit(PDM_ODM_T pDM_Odm); + WirelessMode = pEntry->wireless_mode; -/* Remove Edca by Yu Chen */ + switch (WirelessMode) { + case ODM_WM_B: + if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */ + rate_bitmap = 0x0000000d; + else + rate_bitmap = 0x0000000f; + break; + case (ODM_WM_G): + case (ODM_WM_A): + if (rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x00000f00; + else + rate_bitmap = 0x00000ff0; + break; -#define RxDefaultAnt1 0x65a9 -#define RxDefaultAnt2 0x569a + case (ODM_WM_B|ODM_WM_G): + if (rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x00000f00; + else if (rssi_level == DM_RATR_STA_MIDDLE) + rate_bitmap = 0x00000ff0; + else + rate_bitmap = 0x00000ff5; + break; -void odm_InitHybridAntDiv(PDM_ODM_T pDM_Odm); + case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G): + case (ODM_WM_B|ODM_WM_N24G): + case (ODM_WM_G|ODM_WM_N24G): + case (ODM_WM_A|ODM_WM_N5G): + if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) { + if (rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x000f0000; + else if (rssi_level == DM_RATR_STA_MIDDLE) + rate_bitmap = 0x000ff000; + else { + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) + rate_bitmap = 0x000ff015; + else + rate_bitmap = 0x000ff005; + } + } else { + if (rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x0f8f0000; + else if (rssi_level == DM_RATR_STA_MIDDLE) + rate_bitmap = 0x0f8ff000; + else { + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) + rate_bitmap = 0x0f8ff015; + else + rate_bitmap = 0x0f8ff005; + } + } + break; -bool odm_StaDefAntSel( - PDM_ODM_T pDM_Odm, - u32 OFDM_Ant1_Cnt, - u32 OFDM_Ant2_Cnt, - u32 CCK_Ant1_Cnt, - u32 CCK_Ant2_Cnt, - u8 *pDefAnt -); + case (ODM_WM_AC|ODM_WM_G): + if (rssi_level == 1) + rate_bitmap = 0xfc3f0000; + else if (rssi_level == 2) + rate_bitmap = 0xfffff000; + else + rate_bitmap = 0xffffffff; + break; -void odm_SetRxIdleAnt(PDM_ODM_T pDM_Odm, u8 Ant, bool bDualPath); + case (ODM_WM_AC|ODM_WM_A): + if (pDM_Odm->RFType == RF_1T1R) { + if (rssi_level == 1) /* add by Gary for ac-series */ + rate_bitmap = 0x003f8000; + else if (rssi_level == 2) + rate_bitmap = 0x003ff000; + else + rate_bitmap = 0x003ff010; + } else { + if (rssi_level == 1) /* add by Gary for ac-series */ + rate_bitmap = 0xfe3f8000; /* VHT 2SS MCS3~9 */ + else if (rssi_level == 2) + rate_bitmap = 0xfffff000; /* VHT 2SS MCS0~9 */ + else + rate_bitmap = 0xfffff010; /* All */ + } + break; + default: + if (pDM_Odm->RFType == RF_1T2R) + rate_bitmap = 0x000fffff; + else + rate_bitmap = 0x0fffffff; + break; + } -void odm_HwAntDiv(PDM_ODM_T pDM_Odm); + /* printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", __func__, rssi_level, WirelessMode, rate_bitmap); */ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", rssi_level, WirelessMode, rate_bitmap)); + return ra_mask & rate_bitmap; -/* */ -/* 3 Export Interface */ -/* */ +} -/* */ -/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */ -/* */ -void ODM_DMInit(PDM_ODM_T pDM_Odm) +static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm) { + u8 i; + struct adapter *padapter = pDM_Odm->Adapter; - odm_CommonInfoSelfInit(pDM_Odm); - odm_CmnInfoInit_Debug(pDM_Odm); - odm_DIGInit(pDM_Odm); - odm_NHMCounterStatisticsInit(pDM_Odm); - odm_AdaptivityInit(pDM_Odm); - odm_RateAdaptiveMaskInit(pDM_Odm); - ODM_CfoTrackingInit(pDM_Odm); - ODM_EdcaTurboInit(pDM_Odm); - odm_RSSIMonitorInit(pDM_Odm); - odm_TXPowerTrackingInit(pDM_Odm); + if (padapter->bDriverStopped) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); + return; + } - ODM_ClearTxPowerTrackingState(pDM_Odm); + if (!pDM_Odm->bUseRAMask) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); + return; + } - if (*(pDM_Odm->mp_mode) != 1) - odm_PathDiversityInit(pDM_Odm); + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + PSTA_INFO_T pstat = pDM_Odm->pODM_StaInfo[i]; - odm_DynamicBBPowerSavingInit(pDM_Odm); - odm_DynamicTxPowerInit(pDM_Odm); + if (IS_STA_VALID(pstat)) { + if (IS_MCAST(pstat->hwaddr)) /* if (psta->mac_id == 1) */ + continue; - odm_SwAntDetectInit(pDM_Odm); + if (true == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, 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); + } + + } + } } -/* */ -/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */ -/* You can not add any dummy function here, be care, you can only use DM structure */ -/* to perform any new ODM_DM. */ -/* */ -void ODM_DMWatchdog(PDM_ODM_T pDM_Odm) +/*----------------------------------------------------------------------------- +* Function: odm_RefreshRateAdaptiveMask() +* +* Overview: Update rate table mask according to rssi +* +* Input: NONE +* +* Output: NONE +* +* Return: NONE +* +* Revised History: +*When Who Remark +*05/27/2009 hpfan Create Version 0. +* +* -------------------------------------------------------------------------- +*/ +static void odm_RefreshRateAdaptiveMask(struct dm_odm_t *pDM_Odm) { - odm_CommonInfoSelfUpdate(pDM_Odm); - odm_BasicDbgMessage(pDM_Odm); - odm_FalseAlarmCounterStatistics(pDM_Odm); - odm_NHMCounterStatistics(pDM_Odm); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): RSSI = 0x%x\n", pDM_Odm->RSSI_Min)); - odm_RSSIMonitorCheck(pDM_Odm); - - /* For CE Platform(SPRD or Tablet) */ - /* 8723A or 8189ES platform */ - /* NeilChen--2012--08--24-- */ - /* Fix Leave LPS issue */ - if ((adapter_to_pwrctl(pDM_Odm->Adapter)->pwr_mode != PS_MODE_ACTIVE) /* in LPS mode */ - /* */ - /* (pDM_Odm->SupportICType & (ODM_RTL8723A))|| */ - /* (pDM_Odm->SupportICType & (ODM_RTL8188E) &&(&&(((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))) */ - /* */ - ) { - ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n")); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); - odm_DIGbyRSSI_LPS(pDM_Odm); - } else - odm_DIG(pDM_Odm); - - { - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; - - odm_Adaptivity(pDM_Odm, pDM_DigTable->CurIGValue); - } - odm_CCKPacketDetectionThresh(pDM_Odm); - - if (*(pDM_Odm->pbPowerSaving) == true) + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask()---------->\n")); + if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask(): Return cos not supported\n")); return; - - - odm_RefreshRateAdaptiveMask(pDM_Odm); - odm_EdcaTurboCheck(pDM_Odm); - odm_PathDiversity(pDM_Odm); - ODM_CfoTracking(pDM_Odm); - - ODM_TXPowerTrackingCheck(pDM_Odm); - - /* odm_EdcaTurboCheck(pDM_Odm); */ - - /* 2010.05.30 LukeLee: For CE platform, files in IC subfolders may not be included to be compiled, */ - /* so compile flags must be left here to prevent from compile errors */ - pDM_Odm->PhyDbgInfo.NumQryBeaconPkt = 0; + } + odm_RefreshRateAdaptiveMaskCE(pDM_Odm); } - -/* */ -/* Init /.. Fixed HW value. Only init time. */ -/* */ -void ODM_CmnInfoInit(PDM_ODM_T pDM_Odm, ODM_CMNINFO_E CmnInfo, u32 Value) +/* Return Value: bool */ +/* - true: RATRState is changed. */ +bool ODM_RAStateCheck( + struct dm_odm_t *pDM_Odm, + s32 RSSI, + bool bForceUpdate, + u8 *pRATRState +) { - /* */ - /* This section is used for init value */ - /* */ - switch (CmnInfo) { - /* */ - /* Fixed ODM value. */ - /* */ - case ODM_CMNINFO_ABILITY: - pDM_Odm->SupportAbility = (u32)Value; - break; + struct odm_rate_adaptive *pRA = &pDM_Odm->RateAdaptive; + const u8 GoUpGap = 5; + u8 HighRSSIThreshForRA = pRA->HighRSSIThresh; + u8 LowRSSIThreshForRA = pRA->LowRSSIThresh; + u8 RATRState; - case ODM_CMNINFO_RF_TYPE: - pDM_Odm->RFType = (u8)Value; + /* Threshold Adjustment: */ + /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */ + /* Here GoUpGap is added to solve the boundary's level alternation issue. */ + switch (*pRATRState) { + case DM_RATR_STA_INIT: + case DM_RATR_STA_HIGH: break; - case ODM_CMNINFO_PLATFORM: - pDM_Odm->SupportPlatform = (u8)Value; + case DM_RATR_STA_MIDDLE: + HighRSSIThreshForRA += GoUpGap; break; - case ODM_CMNINFO_INTERFACE: - pDM_Odm->SupportInterface = (u8)Value; + case DM_RATR_STA_LOW: + HighRSSIThreshForRA += GoUpGap; + LowRSSIThreshForRA += GoUpGap; break; - case ODM_CMNINFO_MP_TEST_CHIP: - pDM_Odm->bIsMPChip = (u8)Value; + default: + ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState)); break; + } - case ODM_CMNINFO_IC_TYPE: - pDM_Odm->SupportICType = Value; - break; + /* Decide RATRState by RSSI. */ + if (RSSI > HighRSSIThreshForRA) + RATRState = DM_RATR_STA_HIGH; + else if (RSSI > LowRSSIThreshForRA) + RATRState = DM_RATR_STA_MIDDLE; + else + RATRState = DM_RATR_STA_LOW; + /* printk("==>%s, RATRState:0x%02x , RSSI:%d\n", __func__, RATRState, RSSI); */ - case ODM_CMNINFO_CUT_VER: - pDM_Odm->CutVersion = (u8)Value; - break; + if (*pRATRState != RATRState || bForceUpdate) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState)); + *pRATRState = RATRState; + return true; + } - case ODM_CMNINFO_FAB_VER: - pDM_Odm->FabVersion = (u8)Value; - break; + return false; +} - case ODM_CMNINFO_RFE_TYPE: - pDM_Odm->RFEType = (u8)Value; - break; +/* */ - case ODM_CMNINFO_RF_ANTENNA_TYPE: - pDM_Odm->AntDivType = (u8)Value; - break; +/* 3 ============================================================ */ +/* 3 RSSI Monitor */ +/* 3 ============================================================ */ - case ODM_CMNINFO_BOARD_TYPE: - pDM_Odm->BoardType = (u8)Value; - break; +static void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm) +{ + struct ra_t *pRA_Table = &pDM_Odm->DM_RA_Table; - case ODM_CMNINFO_PACKAGE_TYPE: - pDM_Odm->PackageType = (u8)Value; - break; + pRA_Table->firstconnect = false; - case ODM_CMNINFO_EXT_LNA: - pDM_Odm->ExtLNA = (u8)Value; - break; +} - case ODM_CMNINFO_5G_EXT_LNA: - pDM_Odm->ExtLNA5G = (u8)Value; - break; +static void FindMinimumRSSI(struct adapter *padapter) +{ + struct hal_com_data *pHalData = GET_HAL_DATA(padapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; - case ODM_CMNINFO_EXT_PA: - pDM_Odm->ExtPA = (u8)Value; - break; + /* 1 1.Determine the minimum RSSI */ - case ODM_CMNINFO_5G_EXT_PA: - pDM_Odm->ExtPA5G = (u8)Value; - break; + if ( + (pDM_Odm->bLinked != true) && + (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0) + ) { + pdmpriv->MinUndecoratedPWDBForDM = 0; + /* ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, ("Not connected to any\n")); */ + } else + pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; - case ODM_CMNINFO_GPA: - pDM_Odm->TypeGPA = (ODM_TYPE_GPA_E)Value; - break; - case ODM_CMNINFO_APA: - pDM_Odm->TypeAPA = (ODM_TYPE_APA_E)Value; - break; - case ODM_CMNINFO_GLNA: - pDM_Odm->TypeGLNA = (ODM_TYPE_GLNA_E)Value; - break; - case ODM_CMNINFO_ALNA: - pDM_Odm->TypeALNA = (ODM_TYPE_ALNA_E)Value; - break; + /* ODM_RT_TRACE(pDM_Odm, COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", pHalData->MinUndecoratedPWDBForDM)); */ +} - case ODM_CMNINFO_EXT_TRSW: - pDM_Odm->ExtTRSW = (u8)Value; - break; - case ODM_CMNINFO_PATCH_ID: - pDM_Odm->PatchID = (u8)Value; - break; - case ODM_CMNINFO_BINHCT_TEST: - pDM_Odm->bInHctTest = (bool)Value; - break; - case ODM_CMNINFO_BWIFI_TEST: - pDM_Odm->bWIFITest = (bool)Value; - break; +static void odm_RSSIMonitorCheckCE(struct dm_odm_t *pDM_Odm) +{ + struct adapter *Adapter = pDM_Odm->Adapter; + struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + int i; + int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff; + u8 sta_cnt = 0; + u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */ + struct ra_t *pRA_Table = &pDM_Odm->DM_RA_Table; - case ODM_CMNINFO_SMART_CONCURRENT: - pDM_Odm->bDualMacSmartConcurrent = (bool)Value; - break; + if (pDM_Odm->bLinked != true) + return; - /* To remove the compiler warning, must add an empty default statement to handle the other values. */ - default: - /* do nothing */ - break; - } + pRA_Table->firstconnect = pDM_Odm->bLinked; -} + /* if (check_fwstate(&Adapter->mlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true) */ + { + struct sta_info *psta; + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + psta = pDM_Odm->pODM_StaInfo[i]; + if (IS_STA_VALID(psta)) { + if (IS_MCAST(psta->hwaddr)) /* if (psta->mac_id == 1) */ + continue; -void ODM_CmnInfoHook(PDM_ODM_T pDM_Odm, ODM_CMNINFO_E CmnInfo, void *pValue) -{ - /* */ - /* Hook call by reference pointer. */ - /* */ - switch (CmnInfo) { - /* */ - /* Dynamic call by reference pointer. */ - /* */ - case ODM_CMNINFO_MAC_PHY_MODE: - pDM_Odm->pMacPhyMode = pValue; - break; + if (psta->rssi_stat.UndecoratedSmoothedPWDB == (-1)) + continue; - case ODM_CMNINFO_TX_UNI: - pDM_Odm->pNumTxBytesUnicast = pValue; - break; + if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) + tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; - case ODM_CMNINFO_RX_UNI: - pDM_Odm->pNumRxBytesUnicast = pValue; - break; + if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) + tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; - case ODM_CMNINFO_WM_MODE: - pDM_Odm->pwirelessmode = pValue; - break; + if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) + PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16)); + } + } - case ODM_CMNINFO_BAND: - pDM_Odm->pBandType = pValue; - break; + /* printk("%s ==> sta_cnt(%d)\n", __func__, sta_cnt); */ - case ODM_CMNINFO_SEC_CHNL_OFFSET: - pDM_Odm->pSecChOffset = pValue; - break; + for (i = 0; i < sta_cnt; i++) { + if (PWDB_rssi[i] != (0)) { + if (pHalData->fw_ractrl == true)/* Report every sta's RSSI to FW */ + rtl8723b_set_rssi_cmd(Adapter, (u8 *)(&PWDB_rssi[i])); + } + } + } - case ODM_CMNINFO_SEC_MODE: - pDM_Odm->pSecurity = pValue; - break; - case ODM_CMNINFO_BW: - pDM_Odm->pBandWidth = pValue; - break; - case ODM_CMNINFO_CHNL: - pDM_Odm->pChannel = pValue; - break; + if (tmpEntryMaxPWDB != 0) /* If associated entry is found */ + pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; + else + pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; - case ODM_CMNINFO_DMSP_GET_VALUE: - pDM_Odm->pbGetValueFromOtherMac = pValue; - break; + if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */ + pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; + else + pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; - case ODM_CMNINFO_BUDDY_ADAPTOR: - pDM_Odm->pBuddyAdapter = pValue; - break; + FindMinimumRSSI(Adapter);/* get pdmpriv->MinUndecoratedPWDBForDM */ - case ODM_CMNINFO_DMSP_IS_MASTER: - pDM_Odm->pbMasterOfDMSP = pValue; - break; + pDM_Odm->RSSI_Min = pdmpriv->MinUndecoratedPWDBForDM; + /* ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); */ +} - case ODM_CMNINFO_SCAN: - pDM_Odm->pbScanInProcess = pValue; - break; +static void odm_RSSIMonitorCheck(struct dm_odm_t *pDM_Odm) +{ + if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) + return; - case ODM_CMNINFO_POWER_SAVING: - pDM_Odm->pbPowerSaving = pValue; - break; + odm_RSSIMonitorCheckCE(pDM_Odm); - case ODM_CMNINFO_ONE_PATH_CCA: - pDM_Odm->pOnePathCCA = pValue; - break; +} /* odm_RSSIMonitorCheck */ - case ODM_CMNINFO_DRV_STOP: - pDM_Odm->pbDriverStopped = pValue; - break; +/* 3 ============================================================ */ +/* 3 SW Antenna Diversity */ +/* 3 ============================================================ */ +static void odm_SwAntDetectInit(struct dm_odm_t *pDM_Odm) +{ + struct swat_t *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; - case ODM_CMNINFO_PNP_IN: - pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = pValue; - break; + pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c = rtw_read32(pDM_Odm->Adapter, rDPDT_control); + pDM_SWAT_Table->PreAntenna = MAIN_ANT; + pDM_SWAT_Table->CurAntenna = MAIN_ANT; + pDM_SWAT_Table->SWAS_NoLink_State = 0; +} - case ODM_CMNINFO_INIT_ON: - pDM_Odm->pinit_adpt_in_progress = pValue; - break; +/* 3 ============================================================ */ +/* 3 Tx Power Tracking */ +/* 3 ============================================================ */ - case ODM_CMNINFO_ANT_TEST: - pDM_Odm->pAntennaTest = pValue; - break; +static u8 getSwingIndex(struct dm_odm_t *pDM_Odm) +{ + struct adapter *Adapter = pDM_Odm->Adapter; + u8 i = 0; + u32 bbSwing; + u32 swingTableSize; + u32 *pSwingTable; - case ODM_CMNINFO_NET_CLOSED: - pDM_Odm->pbNet_closed = pValue; - break; + bbSwing = PHY_QueryBBReg(Adapter, rOFDM0_XATxIQImbalance, 0xFFC00000); - case ODM_CMNINFO_FORCED_RATE: - pDM_Odm->pForcedDataRate = pValue; - break; + pSwingTable = OFDMSwingTable_New; + swingTableSize = OFDM_TABLE_SIZE; - case ODM_CMNINFO_FORCED_IGI_LB: - pDM_Odm->pu1ForcedIgiLb = pValue; - break; + for (i = 0; i < swingTableSize; ++i) { + u32 tableValue = pSwingTable[i]; - case ODM_CMNINFO_MP_MODE: - pDM_Odm->mp_mode = pValue; - break; + if (tableValue >= 0x100000) + tableValue >>= 22; + if (bbSwing == tableValue) + break; + } + return i; +} - /* case ODM_CMNINFO_RTSTA_AID: */ - /* pDM_Odm->pAidMap = (u8 *)pValue; */ - /* break; */ +void odm_TXPowerTrackingInit(struct dm_odm_t *pDM_Odm) +{ + u8 defaultSwingIndex = getSwingIndex(pDM_Odm); + u8 p = 0; + struct adapter *Adapter = pDM_Odm->Adapter; + struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - /* case ODM_CMNINFO_BT_COEXIST: */ - /* pDM_Odm->BTCoexist = (bool *)pValue; */ - /* case ODM_CMNINFO_STA_STATUS: */ - /* pDM_Odm->pODM_StaInfo[] = (PSTA_INFO_T)pValue; */ - /* break; */ + struct dm_priv *pdmpriv = &pHalData->dmpriv; - /* case ODM_CMNINFO_PHY_STATUS: */ - /* pDM_Odm->pPhyInfo = (ODM_PHY_INFO *)pValue; */ - /* break; */ + pdmpriv->bTXPowerTracking = true; + pdmpriv->TXPowercount = 0; + pdmpriv->bTXPowerTrackingInit = false; - /* case ODM_CMNINFO_MAC_STATUS: */ - /* pDM_Odm->pMacInfo = (struct odm_mac_status_info *)pValue; */ - /* break; */ - /* To remove the compiler warning, must add an empty default statement to handle the other values. */ - default: - /* do nothing */ - break; + if (*(pDM_Odm->mp_mode) != 1) + pdmpriv->TxPowerTrackControl = true; + else + pdmpriv->TxPowerTrackControl = false; + + /* pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; */ + pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; + pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter; + pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter; + + /* The index of "0 dB" in SwingTable. */ + pDM_Odm->DefaultOfdmIndex = (defaultSwingIndex >= OFDM_TABLE_SIZE) ? 30 : defaultSwingIndex; + pDM_Odm->DefaultCckIndex = 20; + + pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; + pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->DefaultCckIndex; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) { + pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex; + pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0; + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; } } - -void ODM_CmnInfoPtrArrayHook( - PDM_ODM_T pDM_Odm, - ODM_CMNINFO_E CmnInfo, - u16 Index, - void *pValue -) +void ODM_TXPowerTrackingCheck(struct dm_odm_t *pDM_Odm) { - /* */ - /* Hook call by reference pointer. */ - /* */ - switch (CmnInfo) { - /* */ - /* Dynamic call by reference pointer. */ - /* */ - case ODM_CMNINFO_STA_STATUS: - pDM_Odm->pODM_StaInfo[Index] = (PSTA_INFO_T)pValue; - break; - /* To remove the compiler warning, must add an empty default statement to handle the other values. */ - default: - /* do nothing */ - break; - } + struct adapter *Adapter = pDM_Odm->Adapter; + + if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) + return; + + if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) { /* at least delay 1 sec */ + PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_T_METER_NEW, (BIT17 | BIT16), 0x03); + pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; + return; + } else { + ODM_TXPowerTrackingCallback_ThermalMeter(Adapter); + pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; + } } +/* */ +/* 3 Export Interface */ +/* */ /* */ -/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */ +/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */ /* */ -void ODM_CmnInfoUpdate(PDM_ODM_T pDM_Odm, u32 CmnInfo, u64 Value) +void ODM_DMInit(struct dm_odm_t *pDM_Odm) { - /* */ - /* This init variable may be changed in run time. */ - /* */ - switch (CmnInfo) { - case ODM_CMNINFO_LINK_IN_PROGRESS: - pDM_Odm->bLinkInProcess = (bool)Value; - break; - case ODM_CMNINFO_ABILITY: - pDM_Odm->SupportAbility = (u32)Value; - break; + odm_CommonInfoSelfInit(pDM_Odm); + odm_CmnInfoInit_Debug(pDM_Odm); + odm_DIGInit(pDM_Odm); + odm_NHMCounterStatisticsInit(pDM_Odm); + odm_AdaptivityInit(pDM_Odm); + odm_RateAdaptiveMaskInit(pDM_Odm); + ODM_CfoTrackingInit(pDM_Odm); + ODM_EdcaTurboInit(pDM_Odm); + odm_RSSIMonitorInit(pDM_Odm); + odm_TXPowerTrackingInit(pDM_Odm); - case ODM_CMNINFO_RF_TYPE: - pDM_Odm->RFType = (u8)Value; - break; + ODM_ClearTxPowerTrackingState(pDM_Odm); - case ODM_CMNINFO_WIFI_DIRECT: - pDM_Odm->bWIFI_Direct = (bool)Value; - break; + if (*(pDM_Odm->mp_mode) != 1) + odm_PathDiversityInit(pDM_Odm); - case ODM_CMNINFO_WIFI_DISPLAY: - pDM_Odm->bWIFI_Display = (bool)Value; - break; + odm_DynamicBBPowerSavingInit(pDM_Odm); + odm_DynamicTxPowerInit(pDM_Odm); - case ODM_CMNINFO_LINK: - pDM_Odm->bLinked = (bool)Value; - break; + odm_SwAntDetectInit(pDM_Odm); +} - case ODM_CMNINFO_STATION_STATE: - pDM_Odm->bsta_state = (bool)Value; - break; +/* */ +/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */ +/* You can not add any dummy function here, be care, you can only use DM structure */ +/* to perform any new ODM_DM. */ +/* */ +void ODM_DMWatchdog(struct dm_odm_t *pDM_Odm) +{ + odm_CommonInfoSelfUpdate(pDM_Odm); + odm_BasicDbgMessage(pDM_Odm); + odm_FalseAlarmCounterStatistics(pDM_Odm); + odm_NHMCounterStatistics(pDM_Odm); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): RSSI = 0x%x\n", pDM_Odm->RSSI_Min)); - case ODM_CMNINFO_RSSI_MIN: - pDM_Odm->RSSI_Min = (u8)Value; - break; + odm_RSSIMonitorCheck(pDM_Odm); - case ODM_CMNINFO_DBG_COMP: - pDM_Odm->DebugComponents = Value; - break; + /* For CE Platform(SPRD or Tablet) */ + /* 8723A or 8189ES platform */ + /* NeilChen--2012--08--24-- */ + /* Fix Leave LPS issue */ + if ((adapter_to_pwrctl(pDM_Odm->Adapter)->pwr_mode != PS_MODE_ACTIVE) /* in LPS mode */ + /* */ + /* (pDM_Odm->SupportICType & (ODM_RTL8723A))|| */ + /* (pDM_Odm->SupportICType & (ODM_RTL8188E) &&(&&(((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))) */ + /* */ + ) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); + odm_DIGbyRSSI_LPS(pDM_Odm); + } else + odm_DIG(pDM_Odm); - case ODM_CMNINFO_DBG_LEVEL: - pDM_Odm->DebugLevel = (u32)Value; - break; - case ODM_CMNINFO_RA_THRESHOLD_HIGH: - pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value; - break; - - case ODM_CMNINFO_RA_THRESHOLD_LOW: - pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value; - break; - /* The following is for BT HS mode and BT coexist mechanism. */ - case ODM_CMNINFO_BT_ENABLED: - pDM_Odm->bBtEnabled = (bool)Value; - break; - - case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: - pDM_Odm->bBtConnectProcess = (bool)Value; - break; - - case ODM_CMNINFO_BT_HS_RSSI: - pDM_Odm->btHsRssi = (u8)Value; - break; - - case ODM_CMNINFO_BT_OPERATION: - pDM_Odm->bBtHsOperation = (bool)Value; - break; - - case ODM_CMNINFO_BT_LIMITED_DIG: - pDM_Odm->bBtLimitedDig = (bool)Value; - break; - - case ODM_CMNINFO_BT_DISABLE_EDCA: - pDM_Odm->bBtDisableEdcaTurbo = (bool)Value; - break; - -/* - case ODM_CMNINFO_OP_MODE: - pDM_Odm->OPMode = (u8)Value; - break; - - case ODM_CMNINFO_WM_MODE: - pDM_Odm->WirelessMode = (u8)Value; - break; - - case ODM_CMNINFO_BAND: - pDM_Odm->BandType = (u8)Value; - break; - - case ODM_CMNINFO_SEC_CHNL_OFFSET: - pDM_Odm->SecChOffset = (u8)Value; - break; - - case ODM_CMNINFO_SEC_MODE: - pDM_Odm->Security = (u8)Value; - break; - - case ODM_CMNINFO_BW: - pDM_Odm->BandWidth = (u8)Value; - break; + { + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; - case ODM_CMNINFO_CHNL: - pDM_Odm->Channel = (u8)Value; - break; -*/ - default: - /* do nothing */ - break; + odm_Adaptivity(pDM_Odm, pDM_DigTable->CurIGValue); } + odm_CCKPacketDetectionThresh(pDM_Odm); + if (*(pDM_Odm->pbPowerSaving) == true) + return; -} - -void odm_CommonInfoSelfInit(PDM_ODM_T pDM_Odm) -{ - pDM_Odm->bCckHighPower = (bool) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(CCK_RPT_FORMAT, pDM_Odm), ODM_BIT(CCK_RPT_FORMAT, pDM_Odm)); - pDM_Odm->RFPathRxEnable = (u8) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(BB_RX_PATH, pDM_Odm), ODM_BIT(BB_RX_PATH, pDM_Odm)); - - ODM_InitDebugSetting(pDM_Odm); - - pDM_Odm->TxRate = 0xFF; -} - -void odm_CommonInfoSelfUpdate(PDM_ODM_T pDM_Odm) -{ - u8 EntryCnt = 0; - u8 i; - PSTA_INFO_T pEntry; - - if (*(pDM_Odm->pBandWidth) == ODM_BW40M) { - if (*(pDM_Odm->pSecChOffset) == 1) - pDM_Odm->ControlChannel = *(pDM_Odm->pChannel)-2; - else if (*(pDM_Odm->pSecChOffset) == 2) - pDM_Odm->ControlChannel = *(pDM_Odm->pChannel)+2; - } else - pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); - - for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { - pEntry = pDM_Odm->pODM_StaInfo[i]; - if (IS_STA_VALID(pEntry)) - EntryCnt++; - } - if (EntryCnt == 1) - pDM_Odm->bOneEntryOnly = true; - else - pDM_Odm->bOneEntryOnly = false; -} + odm_RefreshRateAdaptiveMask(pDM_Odm); + odm_EdcaTurboCheck(pDM_Odm); + odm_PathDiversity(pDM_Odm); + ODM_CfoTracking(pDM_Odm); -void odm_CmnInfoInit_Debug(PDM_ODM_T pDM_Odm) -{ - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug ==>\n")); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform =%d\n", pDM_Odm->SupportPlatform)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility = 0x%x\n", pDM_Odm->SupportAbility)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface =%d\n", pDM_Odm->SupportInterface)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType = 0x%x\n", pDM_Odm->SupportICType)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion =%d\n", pDM_Odm->CutVersion)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion =%d\n", pDM_Odm->FabVersion)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType =%d\n", pDM_Odm->RFType)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType =%d\n", pDM_Odm->BoardType)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA =%d\n", pDM_Odm->ExtLNA)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA =%d\n", pDM_Odm->ExtPA)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW =%d\n", pDM_Odm->ExtTRSW)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID =%d\n", pDM_Odm->PatchID)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest =%d\n", pDM_Odm->bInHctTest)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest =%d\n", pDM_Odm->bWIFITest)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent =%d\n", pDM_Odm->bDualMacSmartConcurrent)); + ODM_TXPowerTrackingCheck(pDM_Odm); -} + /* odm_EdcaTurboCheck(pDM_Odm); */ -void odm_BasicDbgMessage(PDM_ODM_T pDM_Odm) -{ - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_BasicDbgMsg ==>\n")); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked = %d, RSSI_Min = %d,\n", - pDM_Odm->bLinked, pDM_Odm->RSSI_Min)); - ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RxRate = 0x%x, RSSI_A = %d, RSSI_B = %d\n", - pDM_Odm->RxRate, pDM_Odm->RSSI_A, pDM_Odm->RSSI_B)); + /* 2010.05.30 LukeLee: For CE platform, files in IC subfolders may not be included to be compiled, */ + /* so compile flags must be left here to prevent from compile errors */ + pDM_Odm->PhyDbgInfo.NumQryBeaconPkt = 0; } -/* 3 ============================================================ */ -/* 3 DIG */ -/* 3 ============================================================ */ -/*----------------------------------------------------------------------------- - * Function: odm_DIGInit() - * - * Overview: Set DIG scheme init value. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - *When Who Remark - * - *--------------------------------------------------------------------------- - */ - -/* Remove DIG by yuchen */ - -/* Remove DIG and FA check by Yu Chen */ - - -/* 3 ============================================================ */ -/* 3 BB Power Save */ -/* 3 ============================================================ */ - -/* Remove BB power saving by Yuchen */ - -/* 3 ============================================================ */ -/* 3 RATR MASK */ -/* 3 ============================================================ */ -/* 3 ============================================================ */ -/* 3 Rate Adaptive */ -/* 3 ============================================================ */ - -void odm_RateAdaptiveMaskInit(PDM_ODM_T pDM_Odm) -{ - PODM_RATE_ADAPTIVE pOdmRA = &pDM_Odm->RateAdaptive; - - pOdmRA->Type = DM_Type_ByDriver; - if (pOdmRA->Type == DM_Type_ByDriver) - pDM_Odm->bUseRAMask = true; - else - pDM_Odm->bUseRAMask = false; - - pOdmRA->RATRState = DM_RATR_STA_INIT; - pOdmRA->LdpcThres = 35; - pOdmRA->bUseLdpc = false; - pOdmRA->HighRSSIThresh = 50; - pOdmRA->LowRSSIThresh = 20; -} -u32 ODM_Get_Rate_Bitmap( - PDM_ODM_T pDM_Odm, - u32 macid, - u32 ra_mask, - u8 rssi_level -) +/* */ +/* Init /.. Fixed HW value. Only init time. */ +/* */ +void ODM_CmnInfoInit(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, u32 Value) { - PSTA_INFO_T pEntry; - u32 rate_bitmap = 0; - u8 WirelessMode; - - pEntry = pDM_Odm->pODM_StaInfo[macid]; - if (!IS_STA_VALID(pEntry)) - return ra_mask; - - WirelessMode = pEntry->wireless_mode; - - switch (WirelessMode) { - case ODM_WM_B: - if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */ - rate_bitmap = 0x0000000d; - else - rate_bitmap = 0x0000000f; - break; - - case (ODM_WM_G): - case (ODM_WM_A): - if (rssi_level == DM_RATR_STA_HIGH) - rate_bitmap = 0x00000f00; - else - rate_bitmap = 0x00000ff0; - break; - - case (ODM_WM_B|ODM_WM_G): - if (rssi_level == DM_RATR_STA_HIGH) - rate_bitmap = 0x00000f00; - else if (rssi_level == DM_RATR_STA_MIDDLE) - rate_bitmap = 0x00000ff0; - else - rate_bitmap = 0x00000ff5; - break; - - case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G): - case (ODM_WM_B|ODM_WM_N24G): - case (ODM_WM_G|ODM_WM_N24G): - case (ODM_WM_A|ODM_WM_N5G): - if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) { - if (rssi_level == DM_RATR_STA_HIGH) - rate_bitmap = 0x000f0000; - else if (rssi_level == DM_RATR_STA_MIDDLE) - rate_bitmap = 0x000ff000; - else { - if (*(pDM_Odm->pBandWidth) == ODM_BW40M) - rate_bitmap = 0x000ff015; - else - rate_bitmap = 0x000ff005; - } - } else { - if (rssi_level == DM_RATR_STA_HIGH) - rate_bitmap = 0x0f8f0000; - else if (rssi_level == DM_RATR_STA_MIDDLE) - rate_bitmap = 0x0f8ff000; - else { - if (*(pDM_Odm->pBandWidth) == ODM_BW40M) - rate_bitmap = 0x0f8ff015; - else - rate_bitmap = 0x0f8ff005; - } - } + /* */ + /* This section is used for init value */ + /* */ + switch (CmnInfo) { + /* */ + /* Fixed ODM value. */ + /* */ + case ODM_CMNINFO_ABILITY: + pDM_Odm->SupportAbility = (u32)Value; break; - case (ODM_WM_AC|ODM_WM_G): - if (rssi_level == 1) - rate_bitmap = 0xfc3f0000; - else if (rssi_level == 2) - rate_bitmap = 0xfffff000; - else - rate_bitmap = 0xffffffff; + case ODM_CMNINFO_RF_TYPE: + pDM_Odm->RFType = (u8)Value; break; - case (ODM_WM_AC|ODM_WM_A): - - if (pDM_Odm->RFType == RF_1T1R) { - if (rssi_level == 1) /* add by Gary for ac-series */ - rate_bitmap = 0x003f8000; - else if (rssi_level == 2) - rate_bitmap = 0x003ff000; - else - rate_bitmap = 0x003ff010; - } else { - if (rssi_level == 1) /* add by Gary for ac-series */ - rate_bitmap = 0xfe3f8000; /* VHT 2SS MCS3~9 */ - else if (rssi_level == 2) - rate_bitmap = 0xfffff000; /* VHT 2SS MCS0~9 */ - else - rate_bitmap = 0xfffff010; /* All */ - } + case ODM_CMNINFO_PLATFORM: + pDM_Odm->SupportPlatform = (u8)Value; break; - default: - if (pDM_Odm->RFType == RF_1T2R) - rate_bitmap = 0x000fffff; - else - rate_bitmap = 0x0fffffff; + case ODM_CMNINFO_INTERFACE: + pDM_Odm->SupportInterface = (u8)Value; break; - } - - /* printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", __func__, rssi_level, WirelessMode, rate_bitmap); */ - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", rssi_level, WirelessMode, rate_bitmap)); - - return ra_mask & rate_bitmap; - -} - -/*----------------------------------------------------------------------------- -* Function: odm_RefreshRateAdaptiveMask() -* -* Overview: Update rate table mask according to rssi -* -* Input: NONE -* -* Output: NONE -* -* Return: NONE -* -* Revised History: -*When Who Remark -*05/27/2009 hpfan Create Version 0. -* -* -------------------------------------------------------------------------- -*/ -void odm_RefreshRateAdaptiveMask(PDM_ODM_T pDM_Odm) -{ - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask()---------->\n")); - if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) { - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask(): Return cos not supported\n")); - return; - } - odm_RefreshRateAdaptiveMaskCE(pDM_Odm); -} + case ODM_CMNINFO_MP_TEST_CHIP: + pDM_Odm->bIsMPChip = (u8)Value; + break; -void odm_RefreshRateAdaptiveMaskCE(PDM_ODM_T pDM_Odm) -{ - u8 i; - struct adapter *padapter = pDM_Odm->Adapter; + case ODM_CMNINFO_IC_TYPE: + pDM_Odm->SupportICType = Value; + break; - if (padapter->bDriverStopped) { - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); - return; - } + case ODM_CMNINFO_CUT_VER: + pDM_Odm->CutVersion = (u8)Value; + break; - if (!pDM_Odm->bUseRAMask) { - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); - return; - } + case ODM_CMNINFO_FAB_VER: + pDM_Odm->FabVersion = (u8)Value; + break; - /* printk("==> %s\n", __func__); */ + case ODM_CMNINFO_RFE_TYPE: + pDM_Odm->RFEType = (u8)Value; + break; - for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { - PSTA_INFO_T pstat = pDM_Odm->pODM_StaInfo[i]; + case ODM_CMNINFO_RF_ANTENNA_TYPE: + pDM_Odm->AntDivType = (u8)Value; + break; - if (IS_STA_VALID(pstat)) { - if (IS_MCAST(pstat->hwaddr)) /* if (psta->mac_id == 1) */ - continue; - if (IS_MCAST(pstat->hwaddr)) - continue; + case ODM_CMNINFO_BOARD_TYPE: + pDM_Odm->BoardType = (u8)Value; + break; - if (true == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) { - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, 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); - } + case ODM_CMNINFO_PACKAGE_TYPE: + pDM_Odm->PackageType = (u8)Value; + break; - } - } -} + case ODM_CMNINFO_EXT_LNA: + pDM_Odm->ExtLNA = (u8)Value; + break; -/* Return Value: bool */ -/* - true: RATRState is changed. */ -bool ODM_RAStateCheck( - PDM_ODM_T pDM_Odm, - s32 RSSI, - bool bForceUpdate, - u8 *pRATRState -) -{ - PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; - const u8 GoUpGap = 5; - u8 HighRSSIThreshForRA = pRA->HighRSSIThresh; - u8 LowRSSIThreshForRA = pRA->LowRSSIThresh; - u8 RATRState; + case ODM_CMNINFO_5G_EXT_LNA: + pDM_Odm->ExtLNA5G = (u8)Value; + break; - /* Threshold Adjustment: */ - /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */ - /* Here GoUpGap is added to solve the boundary's level alternation issue. */ - switch (*pRATRState) { - case DM_RATR_STA_INIT: - case DM_RATR_STA_HIGH: + case ODM_CMNINFO_EXT_PA: + pDM_Odm->ExtPA = (u8)Value; break; - case DM_RATR_STA_MIDDLE: - HighRSSIThreshForRA += GoUpGap; + case ODM_CMNINFO_5G_EXT_PA: + pDM_Odm->ExtPA5G = (u8)Value; break; - case DM_RATR_STA_LOW: - HighRSSIThreshForRA += GoUpGap; - LowRSSIThreshForRA += GoUpGap; + case ODM_CMNINFO_GPA: + pDM_Odm->TypeGPA = (enum odm_type_gpa_e)Value; + break; + case ODM_CMNINFO_APA: + pDM_Odm->TypeAPA = (enum odm_type_apa_e)Value; + break; + case ODM_CMNINFO_GLNA: + pDM_Odm->TypeGLNA = (enum odm_type_glna_e)Value; + break; + case ODM_CMNINFO_ALNA: + pDM_Odm->TypeALNA = (enum odm_type_alna_e)Value; break; - default: - ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState)); + case ODM_CMNINFO_EXT_TRSW: + pDM_Odm->ExtTRSW = (u8)Value; + break; + case ODM_CMNINFO_PATCH_ID: + pDM_Odm->PatchID = (u8)Value; + break; + case ODM_CMNINFO_BINHCT_TEST: + pDM_Odm->bInHctTest = (bool)Value; + break; + case ODM_CMNINFO_BWIFI_TEST: + pDM_Odm->bWIFITest = (bool)Value; break; - } - /* Decide RATRState by RSSI. */ - if (RSSI > HighRSSIThreshForRA) - RATRState = DM_RATR_STA_HIGH; - else if (RSSI > LowRSSIThreshForRA) - RATRState = DM_RATR_STA_MIDDLE; - else - RATRState = DM_RATR_STA_LOW; - /* printk("==>%s, RATRState:0x%02x , RSSI:%d\n", __func__, RATRState, RSSI); */ + case ODM_CMNINFO_SMART_CONCURRENT: + pDM_Odm->bDualMacSmartConcurrent = (bool)Value; + break; - if (*pRATRState != RATRState || bForceUpdate) { - ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState)); - *pRATRState = RATRState; - return true; + /* To remove the compiler warning, must add an empty default statement to handle the other values. */ + default: + /* do nothing */ + break; } - return false; } -/* */ +void ODM_CmnInfoHook(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, void *pValue) +{ + /* */ + /* Hook call by reference pointer. */ + /* */ + switch (CmnInfo) { + /* */ + /* Dynamic call by reference pointer. */ + /* */ + case ODM_CMNINFO_MAC_PHY_MODE: + pDM_Odm->pMacPhyMode = pValue; + break; -/* 3 ============================================================ */ -/* 3 Dynamic Tx Power */ -/* 3 ============================================================ */ + case ODM_CMNINFO_TX_UNI: + pDM_Odm->pNumTxBytesUnicast = pValue; + break; -/* Remove BY YuChen */ + case ODM_CMNINFO_RX_UNI: + pDM_Odm->pNumRxBytesUnicast = pValue; + break; -/* 3 ============================================================ */ -/* 3 RSSI Monitor */ -/* 3 ============================================================ */ + case ODM_CMNINFO_WM_MODE: + pDM_Odm->pwirelessmode = pValue; + break; -void odm_RSSIMonitorInit(PDM_ODM_T pDM_Odm) -{ - pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; + case ODM_CMNINFO_BAND: + pDM_Odm->pBandType = pValue; + break; - pRA_Table->firstconnect = false; + case ODM_CMNINFO_SEC_CHNL_OFFSET: + pDM_Odm->pSecChOffset = pValue; + break; -} + case ODM_CMNINFO_SEC_MODE: + pDM_Odm->pSecurity = pValue; + break; -void odm_RSSIMonitorCheck(PDM_ODM_T pDM_Odm) -{ - if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) - return; + case ODM_CMNINFO_BW: + pDM_Odm->pBandWidth = pValue; + break; - odm_RSSIMonitorCheckCE(pDM_Odm); + case ODM_CMNINFO_CHNL: + pDM_Odm->pChannel = pValue; + break; -} /* odm_RSSIMonitorCheck */ + case ODM_CMNINFO_DMSP_GET_VALUE: + pDM_Odm->pbGetValueFromOtherMac = pValue; + break; -static void FindMinimumRSSI(struct adapter *padapter) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct dm_priv *pdmpriv = &pHalData->dmpriv; - PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); + case ODM_CMNINFO_BUDDY_ADAPTOR: + pDM_Odm->pBuddyAdapter = pValue; + break; - /* 1 1.Determine the minimum RSSI */ + case ODM_CMNINFO_DMSP_IS_MASTER: + pDM_Odm->pbMasterOfDMSP = pValue; + break; - if ( - (pDM_Odm->bLinked != true) && - (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0) - ) { - pdmpriv->MinUndecoratedPWDBForDM = 0; - /* ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, ("Not connected to any\n")); */ - } else - pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + case ODM_CMNINFO_SCAN: + pDM_Odm->pbScanInProcess = pValue; + break; - /* DBG_8192C("%s =>MinUndecoratedPWDBForDM(%d)\n", __func__, pdmpriv->MinUndecoratedPWDBForDM); */ - /* ODM_RT_TRACE(pDM_Odm, COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", pHalData->MinUndecoratedPWDBForDM)); */ -} + case ODM_CMNINFO_POWER_SAVING: + pDM_Odm->pbPowerSaving = pValue; + break; -void odm_RSSIMonitorCheckCE(PDM_ODM_T pDM_Odm) -{ - struct adapter *Adapter = pDM_Odm->Adapter; - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - struct dm_priv *pdmpriv = &pHalData->dmpriv; - int i; - int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff; - u8 sta_cnt = 0; - u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */ - pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; + case ODM_CMNINFO_ONE_PATH_CCA: + pDM_Odm->pOnePathCCA = pValue; + break; - if (pDM_Odm->bLinked != true) - return; + case ODM_CMNINFO_DRV_STOP: + pDM_Odm->pbDriverStopped = pValue; + break; - pRA_Table->firstconnect = pDM_Odm->bLinked; + case ODM_CMNINFO_PNP_IN: + pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = pValue; + break; - /* if (check_fwstate(&Adapter->mlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true) */ - { - struct sta_info *psta; + case ODM_CMNINFO_INIT_ON: + pDM_Odm->pinit_adpt_in_progress = pValue; + break; - for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { - psta = pDM_Odm->pODM_StaInfo[i]; - if (IS_STA_VALID(psta)) { - if (IS_MCAST(psta->hwaddr)) /* if (psta->mac_id == 1) */ - continue; + case ODM_CMNINFO_ANT_TEST: + pDM_Odm->pAntennaTest = pValue; + break; + + case ODM_CMNINFO_NET_CLOSED: + pDM_Odm->pbNet_closed = pValue; + break; + + case ODM_CMNINFO_FORCED_RATE: + pDM_Odm->pForcedDataRate = pValue; + break; + + case ODM_CMNINFO_FORCED_IGI_LB: + pDM_Odm->pu1ForcedIgiLb = pValue; + break; + + case ODM_CMNINFO_MP_MODE: + pDM_Odm->mp_mode = pValue; + break; + + /* case ODM_CMNINFO_RTSTA_AID: */ + /* pDM_Odm->pAidMap = (u8 *)pValue; */ + /* break; */ - if (psta->rssi_stat.UndecoratedSmoothedPWDB == (-1)) - continue; + /* case ODM_CMNINFO_BT_COEXIST: */ + /* pDM_Odm->BTCoexist = (bool *)pValue; */ - if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) - tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + /* case ODM_CMNINFO_STA_STATUS: */ + /* pDM_Odm->pODM_StaInfo[] = (PSTA_INFO_T)pValue; */ + /* break; */ - if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) - tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + /* case ODM_CMNINFO_PHY_STATUS: */ + /* pDM_Odm->pPhyInfo = (ODM_PHY_INFO *)pValue; */ + /* break; */ - if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) - PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16)); - } - } + /* case ODM_CMNINFO_MAC_STATUS: */ + /* pDM_Odm->pMacInfo = (struct odm_mac_status_info *)pValue; */ + /* break; */ + /* To remove the compiler warning, must add an empty default statement to handle the other values. */ + default: + /* do nothing */ + break; + } - /* 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 */ - rtl8723b_set_rssi_cmd(Adapter, (u8 *)(&PWDB_rssi[i])); - } - } + +void ODM_CmnInfoPtrArrayHook( + struct dm_odm_t *pDM_Odm, + enum odm_cmninfo_e CmnInfo, + u16 Index, + void *pValue +) +{ + /* */ + /* Hook call by reference pointer. */ + /* */ + switch (CmnInfo) { + /* */ + /* Dynamic call by reference pointer. */ + /* */ + case ODM_CMNINFO_STA_STATUS: + pDM_Odm->pODM_StaInfo[Index] = (PSTA_INFO_T)pValue; + break; + /* To remove the compiler warning, must add an empty default statement to handle the other values. */ + default: + /* do nothing */ + break; } +} - if (tmpEntryMaxPWDB != 0) /* If associated entry is found */ - pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; - else - pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; +/* */ +/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */ +/* */ +void ODM_CmnInfoUpdate(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value) +{ + /* */ + /* This init variable may be changed in run time. */ + /* */ + switch (CmnInfo) { + case ODM_CMNINFO_LINK_IN_PROGRESS: + pDM_Odm->bLinkInProcess = (bool)Value; + break; - if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */ - pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; - else - pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; + case ODM_CMNINFO_ABILITY: + pDM_Odm->SupportAbility = (u32)Value; + break; - FindMinimumRSSI(Adapter);/* get pdmpriv->MinUndecoratedPWDBForDM */ + case ODM_CMNINFO_RF_TYPE: + pDM_Odm->RFType = (u8)Value; + break; - pDM_Odm->RSSI_Min = pdmpriv->MinUndecoratedPWDBForDM; - /* ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); */ -} + case ODM_CMNINFO_WIFI_DIRECT: + pDM_Odm->bWIFI_Direct = (bool)Value; + break; -/* 3 ============================================================ */ -/* 3 Tx Power Tracking */ -/* 3 ============================================================ */ + case ODM_CMNINFO_WIFI_DISPLAY: + pDM_Odm->bWIFI_Display = (bool)Value; + break; -static u8 getSwingIndex(PDM_ODM_T pDM_Odm) -{ - struct adapter *Adapter = pDM_Odm->Adapter; - u8 i = 0; - u32 bbSwing; - u32 swingTableSize; - u32 *pSwingTable; + case ODM_CMNINFO_LINK: + pDM_Odm->bLinked = (bool)Value; + break; - bbSwing = PHY_QueryBBReg(Adapter, rOFDM0_XATxIQImbalance, 0xFFC00000); + case ODM_CMNINFO_STATION_STATE: + pDM_Odm->bsta_state = (bool)Value; + break; - pSwingTable = OFDMSwingTable_New; - swingTableSize = OFDM_TABLE_SIZE; + case ODM_CMNINFO_RSSI_MIN: + pDM_Odm->RSSI_Min = (u8)Value; + break; - for (i = 0; i < swingTableSize; ++i) { - u32 tableValue = pSwingTable[i]; + case ODM_CMNINFO_DBG_COMP: + pDM_Odm->DebugComponents = Value; + break; - if (tableValue >= 0x100000) - tableValue >>= 22; - if (bbSwing == tableValue) - break; - } - return i; -} + case ODM_CMNINFO_DBG_LEVEL: + pDM_Odm->DebugLevel = (u32)Value; + break; + case ODM_CMNINFO_RA_THRESHOLD_HIGH: + pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value; + break; -void odm_TXPowerTrackingInit(PDM_ODM_T pDM_Odm) -{ - u8 defaultSwingIndex = getSwingIndex(pDM_Odm); - u8 p = 0; - struct adapter *Adapter = pDM_Odm->Adapter; - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); + case ODM_CMNINFO_RA_THRESHOLD_LOW: + pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value; + break; + /* The following is for BT HS mode and BT coexist mechanism. */ + case ODM_CMNINFO_BT_ENABLED: + pDM_Odm->bBtEnabled = (bool)Value; + break; + case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: + pDM_Odm->bBtConnectProcess = (bool)Value; + break; - struct dm_priv *pdmpriv = &pHalData->dmpriv; + case ODM_CMNINFO_BT_HS_RSSI: + pDM_Odm->btHsRssi = (u8)Value; + break; - pdmpriv->bTXPowerTracking = true; - pdmpriv->TXPowercount = 0; - pdmpriv->bTXPowerTrackingInit = false; + case ODM_CMNINFO_BT_OPERATION: + pDM_Odm->bBtHsOperation = (bool)Value; + break; - if (*(pDM_Odm->mp_mode) != 1) - pdmpriv->TxPowerTrackControl = true; - else - pdmpriv->TxPowerTrackControl = false; + case ODM_CMNINFO_BT_LIMITED_DIG: + pDM_Odm->bBtLimitedDig = (bool)Value; + break; + case ODM_CMNINFO_BT_DISABLE_EDCA: + pDM_Odm->bBtDisableEdcaTurbo = (bool)Value; + break; - /* MSG_8192C("pdmpriv->TxPowerTrackControl = %d\n", pdmpriv->TxPowerTrackControl); */ +/* + case ODM_CMNINFO_OP_MODE: + pDM_Odm->OPMode = (u8)Value; + break; - /* pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; */ - pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; - pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter; - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter; + case ODM_CMNINFO_WM_MODE: + pDM_Odm->WirelessMode = (u8)Value; + break; - /* The index of "0 dB" in SwingTable. */ - pDM_Odm->DefaultOfdmIndex = (defaultSwingIndex >= OFDM_TABLE_SIZE) ? 30 : defaultSwingIndex; - pDM_Odm->DefaultCckIndex = 20; + case ODM_CMNINFO_BAND: + pDM_Odm->BandType = (u8)Value; + break; - pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; - pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->DefaultCckIndex; + case ODM_CMNINFO_SEC_CHNL_OFFSET: + pDM_Odm->SecChOffset = (u8)Value; + break; - for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) { - pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex; - pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex; - pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0; - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0; - pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; + case ODM_CMNINFO_SEC_MODE: + pDM_Odm->Security = (u8)Value; + break; + + case ODM_CMNINFO_BW: + pDM_Odm->BandWidth = (u8)Value; + break; + + case ODM_CMNINFO_CHNL: + pDM_Odm->Channel = (u8)Value; + break; +*/ + default: + /* do nothing */ + break; } + } -void ODM_TXPowerTrackingCheck(PDM_ODM_T pDM_Odm) -{ - struct adapter *Adapter = pDM_Odm->Adapter; +/* 3 ============================================================ */ +/* 3 DIG */ +/* 3 ============================================================ */ +/*----------------------------------------------------------------------------- + * Function: odm_DIGInit() + * + * Overview: Set DIG scheme init value. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + *When Who Remark + * + *--------------------------------------------------------------------------- + */ - if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) - return; +/* Remove DIG by yuchen */ - if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) { /* at least delay 1 sec */ - PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_T_METER_NEW, (BIT17 | BIT16), 0x03); +/* Remove DIG and FA check by Yu Chen */ - /* DBG_871X("Trigger Thermal Meter!!\n"); */ +/* 3 ============================================================ */ +/* 3 BB Power Save */ +/* 3 ============================================================ */ - pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; - return; - } else { - /* DBG_871X("Schedule TxPowerTracking direct call!!\n"); */ - ODM_TXPowerTrackingCallback_ThermalMeter(Adapter); - pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; - } -} +/* Remove BB power saving by Yuchen */ /* 3 ============================================================ */ -/* 3 SW Antenna Diversity */ +/* 3 Dynamic Tx Power */ /* 3 ============================================================ */ -void odm_SwAntDetectInit(PDM_ODM_T pDM_Odm) -{ - pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; - pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c = rtw_read32(pDM_Odm->Adapter, rDPDT_control); - pDM_SWAT_Table->PreAntenna = MAIN_ANT; - pDM_SWAT_Table->CurAntenna = MAIN_ANT; - pDM_SWAT_Table->SWAS_NoLink_State = 0; -} +/* Remove BY YuChen */ + diff --git a/drivers/staging/rtl8723bs/hal/odm.h b/drivers/staging/rtl8723bs/hal/odm.h index 16e8f66a31714dceba9de1e48b8850d848c1535e..ff21343fbe0be8bf7638af95cf0c6f7a5451c87c 100644 --- a/drivers/staging/rtl8723bs/hal/odm.h +++ b/drivers/staging/rtl8723bs/hal/odm.h @@ -92,11 +92,11 @@ struct dynamic_primary_CCA { u8 MF_state; }; -typedef struct _Rate_Adaptive_Table_ { +struct ra_t { u8 firstconnect; -} RA_T, *pRA_T; +}; -typedef struct _RX_High_Power_ { +struct rxhp_t { u8 RXHP_flag; u8 PSD_func_trigger; u8 PSD_bitmap_RXHP[80]; @@ -107,8 +107,8 @@ typedef struct _RX_High_Power_ { bool First_time_enter; bool RXHP_enable; u8 TP_Mode; - RT_TIMER PSDTimer; -} RXHP_T, *pRXHP_T; + struct timer_list PSDTimer; +}; #define ASSOCIATE_ENTRY_NUM 32 /* Max size of AsocEntry[]. */ #define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM @@ -126,7 +126,7 @@ typedef struct _RX_High_Power_ { #define TRAFFIC_HIGH 1 #define TRAFFIC_UltraLOW 2 -typedef struct _SW_Antenna_Switch_ { +struct swat_t { /* _SW_Antenna_Switch_ */ u8 Double_chk_flag; u8 try_flag; s32 PreRSSI; @@ -169,16 +169,16 @@ typedef struct _SW_Antenna_Switch_ { u8 TrafficLoad; u8 Train_time; u8 Train_time_flag; - RT_TIMER SwAntennaSwitchTimer; - RT_TIMER SwAntennaSwitchTimer_8723B; + struct timer_list SwAntennaSwitchTimer; + struct timer_list SwAntennaSwitchTimer_8723B; u32 PktCnt_SWAntDivByCtrlFrame; bool bSWAntDivByCtrlFrame; -} SWAT_T, *pSWAT_T; +}; /* Remove Edca by YuChen */ -typedef struct _ODM_RATE_ADAPTIVE { +struct odm_rate_adaptive { u8 Type; /* DM_Type_ByFW/DM_Type_ByDriver */ u8 LdpcThres; /* if RSSI > LdpcThres => switch from LPDC to BCC */ bool bUseLdpc; @@ -187,7 +187,7 @@ typedef struct _ODM_RATE_ADAPTIVE { u8 LowRSSIThresh; /* if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW */ u8 RATRState; /* Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */ -} ODM_RATE_ADAPTIVE, *PODM_RATE_ADAPTIVE; +}; #define IQK_MAC_REG_NUM 4 #define IQK_ADDA_REG_NUM 16 @@ -277,55 +277,10 @@ struct odm_mac_status_info { u8 test; }; -typedef enum tag_Dynamic_ODM_Support_Ability_Type { - /* BB Team */ - ODM_DIG = 0x00000001, - ODM_HIGH_POWER = 0x00000002, - ODM_CCK_CCA_TH = 0x00000004, - ODM_FA_STATISTICS = 0x00000008, - ODM_RAMASK = 0x00000010, - ODM_RSSI_MONITOR = 0x00000020, - ODM_SW_ANTDIV = 0x00000040, - ODM_HW_ANTDIV = 0x00000080, - ODM_BB_PWRSV = 0x00000100, - ODM_2TPATHDIV = 0x00000200, - ODM_1TPATHDIV = 0x00000400, - ODM_PSD2AFH = 0x00000800 -} ODM_Ability_E; - -/* */ -/* 2011/20/20 MH For MP driver RT_WLAN_STA = STA_INFO_T */ -/* Please declare below ODM relative info in your STA info structure. */ -/* */ -typedef struct _ODM_STA_INFO { - /* Driver Write */ - bool bUsed; /* record the sta status link or not? */ - /* u8 WirelessMode; */ - u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ - - /* ODM Write */ - /* 1 PHY_STATUS_INFO */ - u8 RSSI_Path[4]; /* */ - u8 RSSI_Ave; - u8 RXEVM[4]; - u8 RXSNR[4]; - - /* ODM Write */ - /* 1 TX_INFO (may changed by IC) */ - /* TX_INFO_T pTxInfo; Define in IC folder. Move lower layer. */ - - /* */ - /* Please use compile flag to disabe the strcutrue for other IC except 88E. */ - /* Move To lower layer. */ - /* */ - /* ODM Write Wilson will handle this part(said by Luke.Lee) */ - /* TX_RPT_T pTxRpt; Define in IC folder. Move lower layer. */ -} ODM_STA_INFO_T, *PODM_STA_INFO_T; - /* */ /* 2011/10/20 MH Define Common info enum for all team. */ /* */ -typedef enum _ODM_Common_Info_Definition { +enum odm_cmninfo_e { /* Fixed value: */ /* HOOK BEFORE REG INIT----------- */ @@ -412,10 +367,10 @@ typedef enum _ODM_Common_Info_Definition { ODM_CMNINFO_MAC_STATUS, ODM_CMNINFO_MAX, -} ODM_CMNINFO_E; +}; /* 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY */ -typedef enum _ODM_Support_Ability_Definition { +enum { /* _ODM_Support_Ability_Definition */ /* */ /* BB ODM section BIT 0-15 */ /* */ @@ -443,21 +398,21 @@ typedef enum _ODM_Support_Ability_Definition { ODM_RF_TX_PWR_TRACK = BIT24, ODM_RF_RX_GAIN_TRACK = BIT25, ODM_RF_CALIBRATION = BIT26, -} ODM_ABILITY_E; +}; /* ODM_CMNINFO_INTERFACE */ -typedef enum tag_ODM_Support_Interface_Definition { +enum { /* tag_ODM_Support_Interface_Definition */ ODM_ITRF_SDIO = 0x4, ODM_ITRF_ALL = 0x7, -} ODM_INTERFACE_E; +}; /* ODM_CMNINFO_IC_TYPE */ -typedef enum tag_ODM_Support_IC_Type_Definition { +enum { /* tag_ODM_Support_IC_Type_Definition */ ODM_RTL8723B = BIT8, -} ODM_IC_TYPE_E; +}; /* ODM_CMNINFO_CUT_VER */ -typedef enum tag_ODM_Cut_Version_Definition { +enum { /* tag_ODM_Cut_Version_Definition */ ODM_CUT_A = 0, ODM_CUT_B = 1, ODM_CUT_C = 2, @@ -469,30 +424,19 @@ typedef enum tag_ODM_Cut_Version_Definition { ODM_CUT_J = 9, ODM_CUT_K = 10, ODM_CUT_TEST = 15, -} ODM_CUT_VERSION_E; +}; /* ODM_CMNINFO_FAB_VER */ -typedef enum tag_ODM_Fab_Version_Definition { +enum { /* tag_ODM_Fab_Version_Definition */ ODM_TSMC = 0, ODM_UMC = 1, -} ODM_FAB_E; +}; /* ODM_CMNINFO_RF_TYPE */ /* */ /* For example 1T2R (A+AB = BIT0|BIT4|BIT5) */ /* */ -typedef enum tag_ODM_RF_Path_Bit_Definition { - ODM_RF_TX_A = BIT0, - ODM_RF_TX_B = BIT1, - ODM_RF_TX_C = BIT2, - ODM_RF_TX_D = BIT3, - ODM_RF_RX_A = BIT4, - ODM_RF_RX_B = BIT5, - ODM_RF_RX_C = BIT6, - ODM_RF_RX_D = BIT7, -} ODM_RF_PATH_E; - -typedef enum tag_ODM_RF_Type_Definition { +enum { /* tag_ODM_RF_Type_Definition */ ODM_1T1R = 0, ODM_1T2R = 1, ODM_2T2R = 2, @@ -501,46 +445,14 @@ typedef enum tag_ODM_RF_Type_Definition { ODM_3T3R = 5, ODM_3T4R = 6, ODM_4T4R = 7, -} ODM_RF_TYPE_E; +}; /* */ /* ODM Dynamic common info value definition */ /* */ -/* typedef enum _MACPHY_MODE_8192D{ */ -/* SINGLEMAC_SINGLEPHY, */ -/* DUALMAC_DUALPHY, */ -/* DUALMAC_SINGLEPHY, */ -/* MACPHY_MODE_8192D,*PMACPHY_MODE_8192D; */ -/* Above is the original define in MP driver. Please use the same define. THX. */ -typedef enum tag_ODM_MAC_PHY_Mode_Definition { - ODM_SMSP = 0, - ODM_DMSP = 1, - ODM_DMDP = 2, -} ODM_MAC_PHY_MODE_E; - -typedef enum tag_BT_Coexist_Definition { - ODM_BT_BUSY = 1, - ODM_BT_ON = 2, - ODM_BT_OFF = 3, - ODM_BT_NONE = 4, -} ODM_BT_COEXIST_E; - -/* ODM_CMNINFO_OP_MODE */ -typedef enum tag_Operation_Mode_Definition { - ODM_NO_LINK = BIT0, - ODM_LINK = BIT1, - ODM_SCAN = BIT2, - ODM_POWERSAVE = BIT3, - ODM_AP_MODE = BIT4, - ODM_CLIENT_MODE = BIT5, - ODM_AD_HOC = BIT6, - ODM_WIFI_DIRECT = BIT7, - ODM_WIFI_DISPLAY = BIT8, -} ODM_OPERATION_MODE_E; - /* ODM_CMNINFO_WM_MODE */ -typedef enum tag_Wireless_Mode_Definition { +enum { /* tag_Wireless_Mode_Definition */ ODM_WM_UNKNOWN = 0x0, ODM_WM_B = BIT0, ODM_WM_G = BIT1, @@ -549,138 +461,62 @@ typedef enum tag_Wireless_Mode_Definition { ODM_WM_N5G = BIT4, ODM_WM_AUTO = BIT5, ODM_WM_AC = BIT6, -} ODM_WIRELESS_MODE_E; +}; /* ODM_CMNINFO_BAND */ -typedef enum tag_Band_Type_Definition { +enum { /* tag_Band_Type_Definition */ ODM_BAND_2_4G = 0, ODM_BAND_5G, ODM_BAND_ON_BOTH, ODM_BANDMAX -} ODM_BAND_TYPE_E; - -/* ODM_CMNINFO_SEC_CHNL_OFFSET */ -typedef enum tag_Secondary_Channel_Offset_Definition { - ODM_DONT_CARE = 0, - ODM_BELOW = 1, - ODM_ABOVE = 2 -} ODM_SEC_CHNL_OFFSET_E; - -/* ODM_CMNINFO_SEC_MODE */ -typedef enum tag_Security_Definition { - ODM_SEC_OPEN = 0, - ODM_SEC_WEP40 = 1, - ODM_SEC_TKIP = 2, - ODM_SEC_RESERVE = 3, - ODM_SEC_AESCCMP = 4, - ODM_SEC_WEP104 = 5, - ODM_WEP_WPA_MIXED = 6, /* WEP + WPA */ - ODM_SEC_SMS4 = 7, -} ODM_SECURITY_E; +}; /* ODM_CMNINFO_BW */ -typedef enum tag_Bandwidth_Definition { +enum { /* tag_Bandwidth_Definition */ ODM_BW20M = 0, ODM_BW40M = 1, ODM_BW80M = 2, ODM_BW160M = 3, ODM_BW10M = 4, -} ODM_BW_E; +}; /* ODM_CMNINFO_BOARD_TYPE */ /* For non-AC-series IC , ODM_BOARD_5G_EXT_PA and ODM_BOARD_5G_EXT_LNA are ignored */ /* For AC-series IC, external PA & LNA can be indivisuallly added on 2.4G and/or 5G */ -typedef enum tag_Board_Definition { - ODM_BOARD_DEFAULT = 0, /* The DEFAULT case. */ - ODM_BOARD_MINICARD = BIT(0), /* 0 = non-mini card, 1 = mini card. */ - ODM_BOARD_SLIM = BIT(1), /* 0 = non-slim card, 1 = slim card */ - ODM_BOARD_BT = BIT(2), /* 0 = without BT card, 1 = with BT */ - ODM_BOARD_EXT_PA = BIT(3), /* 0 = no 2G ext-PA, 1 = existing 2G ext-PA */ - ODM_BOARD_EXT_LNA = BIT(4), /* 0 = no 2G ext-LNA, 1 = existing 2G ext-LNA */ - ODM_BOARD_EXT_TRSW = BIT(5), /* 0 = no ext-TRSW, 1 = existing ext-TRSW */ - ODM_BOARD_EXT_PA_5G = BIT(6), /* 0 = no 5G ext-PA, 1 = existing 5G ext-PA */ - ODM_BOARD_EXT_LNA_5G = BIT(7), /* 0 = no 5G ext-LNA, 1 = existing 5G ext-LNA */ -} ODM_BOARD_TYPE_E; - -typedef enum tag_ODM_Package_Definition { - ODM_PACKAGE_DEFAULT = 0, - ODM_PACKAGE_QFN68 = BIT(0), - ODM_PACKAGE_TFBGA90 = BIT(1), - ODM_PACKAGE_TFBGA79 = BIT(2), -} ODM_Package_TYPE_E; - -typedef enum tag_ODM_TYPE_GPA_Definition { + +enum odm_type_gpa_e { /* tag_ODM_TYPE_GPA_Definition */ TYPE_GPA0 = 0, TYPE_GPA1 = BIT(1)|BIT(0) -} ODM_TYPE_GPA_E; +}; -typedef enum tag_ODM_TYPE_APA_Definition { +enum odm_type_apa_e { /* tag_ODM_TYPE_APA_Definition */ TYPE_APA0 = 0, TYPE_APA1 = BIT(1)|BIT(0) -} ODM_TYPE_APA_E; +}; -typedef enum tag_ODM_TYPE_GLNA_Definition { +enum odm_type_glna_e { /* tag_ODM_TYPE_GLNA_Definition */ TYPE_GLNA0 = 0, TYPE_GLNA1 = BIT(2)|BIT(0), TYPE_GLNA2 = BIT(3)|BIT(1), TYPE_GLNA3 = BIT(3)|BIT(2)|BIT(1)|BIT(0) -} ODM_TYPE_GLNA_E; +}; -typedef enum tag_ODM_TYPE_ALNA_Definition { +enum odm_type_alna_e { /* tag_ODM_TYPE_ALNA_Definition */ TYPE_ALNA0 = 0, TYPE_ALNA1 = BIT(2)|BIT(0), TYPE_ALNA2 = BIT(3)|BIT(1), TYPE_ALNA3 = BIT(3)|BIT(2)|BIT(1)|BIT(0) -} ODM_TYPE_ALNA_E; - -/* ODM_CMNINFO_ONE_PATH_CCA */ -typedef enum tag_CCA_Path { - ODM_CCA_2R = 0, - ODM_CCA_1R_A = 1, - ODM_CCA_1R_B = 2, -} ODM_CCA_PATH_E; - -typedef struct _ODM_RA_Info_ { - u8 RateID; - u32 RateMask; - u32 RAUseRate; - u8 RateSGI; - u8 RssiStaRA; - u8 PreRssiStaRA; - u8 SGIEnable; - u8 DecisionRate; - u8 PreRate; - u8 HighestRate; - u8 LowestRate; - u32 NscUp; - u32 NscDown; - u16 RTY[5]; - u32 TOTAL; - u16 DROP; - u8 Active; - u16 RptTime; - u8 RAWaitingCounter; - u8 RAPendingCounter; - u8 PTActive; /* on or off */ - u8 PTTryState; /* 0 trying state, 1 for decision state */ - u8 PTStage; /* 0~6 */ - u8 PTStopCount; /* Stop PT counter */ - u8 PTPreRate; /* if rate change do PT */ - u8 PTPreRssi; /* if RSSI change 5% do PT */ - u8 PTModeSS; /* decide whitch rate should do PT */ - u8 RAstage; /* StageRA, decide how many times RA will be done between PT */ - u8 PTSmoothFactor; -} ODM_RA_INFO_T, *PODM_RA_INFO_T; - -typedef struct _IQK_MATRIX_REGS_SETTING { +}; + +struct iqk_matrix_regs_setting { /* _IQK_MATRIX_REGS_SETTING */ bool bIQKDone; s32 Value[3][IQK_Matrix_REG_NUM]; bool bBWIqkResultSaved[3]; -} IQK_MATRIX_REGS_SETTING, *PIQK_MATRIX_REGS_SETTING; +}; /* Remove PATHDIV_PARA struct to odm_PathDiv.h */ -typedef struct ODM_RF_Calibration_Structure { +struct odm_rf_cal_t { /* ODM_RF_Calibration_Structure */ /* for tx power tracking */ u32 RegA24; /* for TempCCK */ @@ -724,7 +560,7 @@ typedef struct ODM_RF_Calibration_Structure { u8 ThermalValue_HP[HP_THERMAL_NUM]; u8 ThermalValue_HP_index; - IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; + struct iqk_matrix_regs_setting IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; bool bNeedIQK; bool bIQKInProgress; u8 Delta_IQK; @@ -780,12 +616,12 @@ typedef struct ODM_RF_Calibration_Structure { u32 TxLOK[2]; -} ODM_RF_CAL_T, *PODM_RF_CAL_T; +}; /* */ /* ODM Dynamic common info value definition */ /* */ -typedef struct _FAST_ANTENNA_TRAINNING_ { +struct fat_t { /* _FAST_ANTENNA_TRAINNING_ */ u8 Bssid[6]; u8 antsel_rx_keep_0; u8 antsel_rx_keep_1; @@ -823,14 +659,9 @@ typedef struct _FAST_ANTENNA_TRAINNING_ { u32 MainAnt_CtrlFrame_Cnt; u32 AuxAnt_CtrlFrame_Cnt; -} FAT_T, *pFAT_T; - -typedef enum _FAT_STATE { - FAT_NORMAL_STATE = 0, - FAT_TRAINING_STATE = 1, -} FAT_STATE_E, *PFAT_STATE_E; +}; -typedef enum _ANT_DIV_TYPE { +enum { NO_ANTDIV = 0xFF, CG_TRX_HW_ANTDIV = 0x01, CGCS_RX_HW_ANTDIV = 0x02, @@ -838,37 +669,37 @@ typedef enum _ANT_DIV_TYPE { CG_TRX_SMART_ANTDIV = 0x04, CGCS_RX_SW_ANTDIV = 0x05, S0S1_SW_ANTDIV = 0x06 /* 8723B intrnal switch S0 S1 */ -} ANT_DIV_TYPE_E, *PANT_DIV_TYPE_E; +}; -typedef struct _ODM_PATH_DIVERSITY_ { +struct pathdiv_t { /* _ODM_PATH_DIVERSITY_ */ u8 RespTxPath; u8 PathSel[ODM_ASSOCIATE_ENTRY_NUM]; u32 PathA_Sum[ODM_ASSOCIATE_ENTRY_NUM]; u32 PathB_Sum[ODM_ASSOCIATE_ENTRY_NUM]; u32 PathA_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; u32 PathB_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; -} PATHDIV_T, *pPATHDIV_T; +}; -typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE { +enum phy_reg_pg_type { /* _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE */ PHY_REG_PG_RELATIVE_VALUE = 0, PHY_REG_PG_EXACT_VALUE = 1 -} PHY_REG_PG_TYPE; +}; /* */ /* Antenna detection information from single tone mechanism, added by Roger, 2012.11.27. */ /* */ -typedef struct _ANT_DETECTED_INFO { +struct ant_detected_info { bool bAntDetected; u32 dBForAntA; u32 dBForAntB; u32 dBForAntO; -} ANT_DETECTED_INFO, *PANT_DETECTED_INFO; +}; /* */ /* 2011/09/22 MH Copy from SD4 defined structure. We use to support PHY DM integration. */ /* */ -typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { - /* RT_TIMER FastAntTrainingTimer; */ +struct dm_odm_t { /* DM_Out_Source_Dynamic_Mechanism_Structure */ + /* struct timer_list FastAntTrainingTimer; */ /* */ /* Add for different team use temporarily */ /* */ @@ -876,7 +707,7 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { /* WHen you use Adapter or priv pointer, you must make sure the pointer is ready. */ bool odm_ready; - PHY_REG_PG_TYPE PhyRegPgValueType; + enum phy_reg_pg_type PhyRegPgValueType; u8 PhyRegPgVersion; u64 DebugComponents; @@ -1076,7 +907,7 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { u8 Adaptivity_IGI_upper; u8 NHM_cnt_0; - ODM_NOISE_MONITOR noise_level;/* ODM_MAX_CHANNEL_NUM]; */ + struct odm_noise_monitor noise_level;/* ODM_MAX_CHANNEL_NUM]; */ /* */ /* 2 Define STA info. */ /* _ODM_STA_INFO */ @@ -1109,21 +940,21 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { /* */ /* ODM Structure */ /* */ - FAT_T DM_FatTable; - DIG_T DM_DigTable; - PS_T DM_PSTable; + struct fat_t DM_FatTable; + struct dig_t DM_DigTable; + struct ps_t DM_PSTable; struct dynamic_primary_CCA DM_PriCCA; - RXHP_T DM_RXHP_Table; - RA_T DM_RA_Table; - false_ALARM_STATISTICS FalseAlmCnt; - false_ALARM_STATISTICS FlaseAlmCntBuddyAdapter; - SWAT_T DM_SWAT_Table; + struct rxhp_t dM_RXHP_Table; + struct ra_t DM_RA_Table; + struct false_ALARM_STATISTICS FalseAlmCnt; + struct false_ALARM_STATISTICS FlaseAlmCntBuddyAdapter; + struct swat_t DM_SWAT_Table; bool RSSI_test; - CFO_TRACKING DM_CfoTrack; + struct cfo_tracking DM_CfoTrack; - EDCA_T DM_EDCA_Table; + struct edca_t DM_EDCA_Table; u32 WMMEDCA_BE; - PATHDIV_T DM_PathDiv; + struct pathdiv_t DM_PathDiv; /* Copy from SD4 structure */ /* */ /* ================================================== */ @@ -1146,23 +977,23 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { /* PSD */ bool bUserAssignLevel; - RT_TIMER PSDTimer; + struct timer_list PSDTimer; u8 RSSI_BT; /* come from BT */ bool bPSDinProcess; bool bPSDactive; bool bDMInitialGainEnable; /* MPT DIG */ - RT_TIMER MPT_DIGTimer; + struct timer_list MPT_DIGTimer; /* for rate adaptive, in fact, 88c/92c fw will handle this */ u8 bUseRAMask; - ODM_RATE_ADAPTIVE RateAdaptive; + struct odm_rate_adaptive RateAdaptive; - ANT_DETECTED_INFO AntDetectedInfo; /* Antenna detected information for RSSI tool */ + struct ant_detected_info AntDetectedInfo; /* Antenna detected information for RSSI tool */ - ODM_RF_CAL_T RFCalibrateInfo; + struct odm_rf_cal_t RFCalibrateInfo; /* */ /* TX power tracking */ @@ -1194,21 +1025,21 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { /* */ /* ODM relative time. */ - RT_TIMER PathDivSwitchTimer; + struct timer_list PathDivSwitchTimer; /* 2011.09.27 add for Path Diversity */ - RT_TIMER CCKPathDiversityTimer; - RT_TIMER FastAntTrainingTimer; + struct timer_list CCKPathDiversityTimer; + struct timer_list FastAntTrainingTimer; /* ODM relative workitem. */ #if (BEAMFORMING_SUPPORT == 1) RT_BEAMFORMING_INFO BeamformingInfo; #endif -} DM_ODM_T, *PDM_ODM_T; /* DM_Dynamic_Mechanism_Structure */ +}; #define ODM_RF_PATH_MAX 2 -typedef enum _ODM_RF_RADIO_PATH { +enum odm_rf_radio_path_e { ODM_RF_PATH_A = 0, /* Radio Path A */ ODM_RF_PATH_B = 1, /* Radio Path B */ ODM_RF_PATH_C = 2, /* Radio Path C */ @@ -1224,16 +1055,16 @@ typedef enum _ODM_RF_RADIO_PATH { ODM_RF_PATH_BCD, ODM_RF_PATH_ABCD, /* ODM_RF_PATH_MAX, Max RF number 90 support */ -} ODM_RF_RADIO_PATH_E, *PODM_RF_RADIO_PATH_E; +}; - typedef enum _ODM_RF_CONTENT { + enum odm_rf_content { odm_radioa_txt = 0x1000, odm_radiob_txt = 0x1001, odm_radioc_txt = 0x1002, odm_radiod_txt = 0x1003 -} ODM_RF_CONTENT; +}; -typedef enum _ODM_BB_Config_Type { +enum ODM_BB_Config_Type { CONFIG_BB_PHY_REG, CONFIG_BB_AGC_TAB, CONFIG_BB_AGC_TAB_2G, @@ -1241,14 +1072,14 @@ typedef enum _ODM_BB_Config_Type { CONFIG_BB_PHY_REG_PG, CONFIG_BB_PHY_REG_MP, CONFIG_BB_AGC_TAB_DIFF, -} ODM_BB_Config_Type, *PODM_BB_Config_Type; +}; -typedef enum _ODM_RF_Config_Type { +enum ODM_RF_Config_Type { CONFIG_RF_RADIO, CONFIG_RF_TXPWR_LMT, -} ODM_RF_Config_Type, *PODM_RF_Config_Type; +}; -typedef enum _ODM_FW_Config_Type { +enum ODM_FW_Config_Type { CONFIG_FW_NIC, CONFIG_FW_NIC_2, CONFIG_FW_AP, @@ -1256,19 +1087,7 @@ typedef enum _ODM_FW_Config_Type { CONFIG_FW_WoWLAN_2, CONFIG_FW_AP_WoWLAN, CONFIG_FW_BT, -} ODM_FW_Config_Type; - -/* Status code */ -typedef enum _RT_STATUS { - RT_STATUS_SUCCESS, - RT_STATUS_FAILURE, - RT_STATUS_PENDING, - RT_STATUS_RESOURCE, - RT_STATUS_INVALID_CONTEXT, - RT_STATUS_INVALID_PARAMETER, - RT_STATUS_NOT_SUPPORT, - RT_STATUS_OS_API_FAILED, -} RT_STATUS, *PRT_STATUS; +}; #ifdef REMOVE_PACK #pragma pack() @@ -1316,26 +1135,17 @@ typedef enum _RT_STATUS { /* 3 BB Power Save */ /* 3 =========================================================== */ -typedef enum tag_1R_CCA_Type_Definition { +enum { /* tag_1R_CCA_Type_Definition */ CCA_1R = 0, CCA_2R = 1, CCA_MAX = 2, -} DM_1R_CCA_E; +}; -typedef enum tag_RF_Type_Definition { +enum { /* tag_RF_Type_Definition */ RF_Save = 0, RF_Normal = 1, RF_MAX = 2, -} DM_RF_E; - -/* 3 =========================================================== */ -/* 3 Antenna Diversity */ -/* 3 =========================================================== */ -typedef enum tag_SW_Antenna_Switch_Definition { - Antenna_A = 1, - Antenna_B = 2, - Antenna_MAX = 3, -} DM_SWAS_E; +}; /* Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. */ #define MAX_ANTENNA_DETECTION_CNT 10 @@ -1368,10 +1178,10 @@ extern u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE]; /* Remove BB power saving by Yuchen */ #define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck -void ODM_TXPowerTrackingCheck(PDM_ODM_T pDM_Odm); +void ODM_TXPowerTrackingCheck(struct dm_odm_t *pDM_Odm); bool ODM_RAStateCheck( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate, u8 *pRATRState @@ -1379,13 +1189,13 @@ bool ODM_RAStateCheck( #define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi void ODM_SwAntDivChkPerPktRssi( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 StationID, struct odm_phy_info *pPhyInfo ); u32 ODM_Get_Rate_Bitmap( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level @@ -1395,38 +1205,38 @@ u32 ODM_Get_Rate_Bitmap( BEAMFORMING_CAP Beamforming_GetEntryBeamCapByMacId(PMGNT_INFO pMgntInfo, u8 MacId); #endif -void odm_TXPowerTrackingInit(PDM_ODM_T pDM_Odm); +void odm_TXPowerTrackingInit(struct dm_odm_t *pDM_Odm); -void ODM_DMInit(PDM_ODM_T pDM_Odm); +void ODM_DMInit(struct dm_odm_t *pDM_Odm); -void ODM_DMWatchdog(PDM_ODM_T pDM_Odm); /* For common use in the future */ +void ODM_DMWatchdog(struct dm_odm_t *pDM_Odm); /* For common use in the future */ -void ODM_CmnInfoInit(PDM_ODM_T pDM_Odm, ODM_CMNINFO_E CmnInfo, u32 Value); +void ODM_CmnInfoInit(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, u32 Value); -void ODM_CmnInfoHook(PDM_ODM_T pDM_Odm, ODM_CMNINFO_E CmnInfo, void *pValue); +void ODM_CmnInfoHook(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, void *pValue); void ODM_CmnInfoPtrArrayHook( - PDM_ODM_T pDM_Odm, - ODM_CMNINFO_E CmnInfo, + struct dm_odm_t *pDM_Odm, + enum odm_cmninfo_e CmnInfo, u16 Index, void *pValue ); -void ODM_CmnInfoUpdate(PDM_ODM_T pDM_Odm, u32 CmnInfo, u64 Value); +void ODM_CmnInfoUpdate(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value); -void ODM_InitAllTimers(PDM_ODM_T pDM_Odm); +void ODM_InitAllTimers(struct dm_odm_t *pDM_Odm); -void ODM_CancelAllTimers(PDM_ODM_T pDM_Odm); +void ODM_CancelAllTimers(struct dm_odm_t *pDM_Odm); -void ODM_ReleaseAllTimers(PDM_ODM_T pDM_Odm); +void ODM_ReleaseAllTimers(struct dm_odm_t *pDM_Odm); void ODM_AntselStatistics_88C( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate ); -void ODM_DynamicARFBSelect(PDM_ODM_T pDM_Odm, u8 rate, bool Collision_State); +void ODM_DynamicARFBSelect(struct dm_odm_t *pDM_Odm, u8 rate, bool Collision_State); #endif diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c index 3ea1972545e5bd71b3e76993eaf6c4162929ed37..75471c6c168e7e888b551d08444ca1950a10969b 100644 --- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c +++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c @@ -9,8 +9,8 @@ static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack; if (pCfoTrack->CrystalCap == CrystalCap) return; @@ -39,7 +39,7 @@ static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap) static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; struct adapter *Adapter = pDM_Odm->Adapter; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); @@ -49,8 +49,8 @@ static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID) static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack; if (pCfoTrack->bATCStatus == ATCStatus) return; @@ -67,7 +67,7 @@ static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus) static bool odm_GetATCStatus(void *pDM_VOID) { bool ATCStatus; - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; ATCStatus = (bool)PHY_QueryBBReg( pDM_Odm->Adapter, @@ -79,8 +79,8 @@ static bool odm_GetATCStatus(void *pDM_VOID) void ODM_CfoTrackingReset(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack; pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm); pCfoTrack->bAdjust = true; @@ -91,8 +91,8 @@ void ODM_CfoTrackingReset(void *pDM_VOID) void ODM_CfoTrackingInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack; pCfoTrack->DefXCap = pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm); @@ -118,8 +118,8 @@ void ODM_CfoTrackingInit(void *pDM_VOID) void ODM_CfoTracking(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack; int CFO_kHz_A, CFO_kHz_B, CFO_ave = 0; int CFO_ave_diff; int CrystalCap = (int)pCfoTrack->CrystalCap; @@ -297,9 +297,9 @@ void ODM_CfoTracking(void *pDM_VOID) void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; struct odm_packet_info *pPktinfo = pPktinfo_VOID; - PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; + struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack; u8 i; if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.h b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.h index 81db63efe286c4a730bd3717e8c6017417f623a9..bb00d8c893bdf4485d5fff369738e145a80c5035 100644 --- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.h +++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.h @@ -12,7 +12,7 @@ #define CFO_TH_XTAL_LOW 10 /* kHz */ #define CFO_TH_ATC 80 /* kHz */ -typedef struct _CFO_TRACKING_ { +struct cfo_tracking { bool bATCStatus; bool largeCFOHit; bool bAdjust; @@ -25,7 +25,7 @@ typedef struct _CFO_TRACKING_ { bool bForceXtalCap; bool bReset; -} CFO_TRACKING, *PCFO_TRACKING; +}; void ODM_CfoTrackingReset(void *pDM_VOID ); diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c index 40fe43c62c45d9f5d1534244de97ada6fe0247e5..dcef7fb17389db7d089c5984d86e909d4d102149 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DIG.c +++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c @@ -11,7 +11,7 @@ void odm_NHMCounterStatisticsInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; /* PHY parameters initialize for n series */ rtw_write16(pDM_Odm->Adapter, ODM_REG_NHM_TIMER_11N+2, 0x2710); /* 0x894[31:16]= 0x2710 Time duration for NHM unit: 4us, 0x2710 =40ms */ @@ -27,7 +27,7 @@ void odm_NHMCounterStatisticsInit(void *pDM_VOID) void odm_NHMCounterStatistics(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; /* Get NHM report */ odm_GetNHMCounterStatistics(pDM_Odm); @@ -38,7 +38,7 @@ void odm_NHMCounterStatistics(void *pDM_VOID) void odm_GetNHMCounterStatistics(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; u32 value32 = 0; value32 = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_NHM_CNT_11N, bMaskDWord); @@ -48,7 +48,7 @@ void odm_GetNHMCounterStatistics(void *pDM_VOID) void odm_NHMCounterStatisticsReset(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_NHM_TH9_TH10_11N, BIT1, 0); PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_NHM_TH9_TH10_11N, BIT1, 1); @@ -56,7 +56,7 @@ void odm_NHMCounterStatisticsReset(void *pDM_VOID) void odm_NHMBBInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; pDM_Odm->adaptivity_flag = 0; pDM_Odm->tolerance_cnt = 3; @@ -69,9 +69,9 @@ void odm_NHMBBInit(void *pDM_VOID) /* */ void odm_NHMBB(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; /* u8 test_status; */ - /* Pfalse_ALARM_STATISTICS pFalseAlmCnt = &(pDM_Odm->FalseAlmCnt); */ + /* struct false_ALARM_STATISTICS *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; */ pDM_Odm->NHMCurTxOkcnt = *(pDM_Odm->pNumTxBytesUnicast)-pDM_Odm->NHMLastTxOkcnt; @@ -133,7 +133,7 @@ void odm_NHMBB(void *pDM_VOID) void odm_SearchPwdBLowerBound(void *pDM_VOID, u8 IGI_target) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; u32 value32 = 0; u8 cnt, IGI; bool bAdjust = true; @@ -205,7 +205,7 @@ void odm_SearchPwdBLowerBound(void *pDM_VOID, u8 IGI_target) void odm_AdaptivityInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; if (pDM_Odm->Carrier_Sense_enable == false) pDM_Odm->TH_L2H_ini = 0xf7; /* -7 */ @@ -233,7 +233,7 @@ void odm_AdaptivityInit(void *pDM_VOID) void odm_Adaptivity(void *pDM_VOID, u8 IGI) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; s8 TH_L2H_dmc, TH_H2L_dmc; s8 Diff, IGI_target; bool EDCCA_State = false; @@ -322,8 +322,8 @@ void odm_Adaptivity(void *pDM_VOID, u8 IGI) void ODM_Write_DIG(void *pDM_VOID, u8 CurrentIGI) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; if (pDM_DigTable->bStopDIG) { ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("Stop Writing IGI\n")); @@ -358,12 +358,12 @@ void ODM_Write_DIG(void *pDM_VOID, u8 CurrentIGI) void odm_PauseDIG( void *pDM_VOID, - ODM_Pause_DIG_TYPE PauseType, + enum ODM_Pause_DIG_TYPE PauseType, u8 IGIValue ) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; static bool bPaused; ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG() =========>\n")); @@ -435,7 +435,7 @@ void odm_PauseDIG( bool odm_DigAbort(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; /* SupportAbility */ if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) { @@ -466,8 +466,8 @@ bool odm_DigAbort(void *pDM_VOID) void odm_DIGInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; pDM_DigTable->bStopDIG = false; pDM_DigTable->bPSDInProgress = false; @@ -504,11 +504,11 @@ void odm_DIGInit(void *pDM_VOID) void odm_DIG(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; /* Common parameters */ - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; - Pfalse_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; + struct false_ALARM_STATISTICS *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; bool FirstConnect, FirstDisConnect; u8 DIG_MaxOfMin, DIG_Dynamic_MIN; u8 dm_dig_max, dm_dig_min; @@ -823,8 +823,8 @@ void odm_DIG(void *pDM_VOID) void odm_DIGbyRSSI_LPS(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - Pfalse_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct false_ALARM_STATISTICS *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; u8 RSSI_Lower = DM_DIG_MIN_NIC; /* 0x1E or 0x1C */ u8 CurrentIGI = pDM_Odm->RSSI_Min; @@ -892,8 +892,8 @@ void odm_DIGbyRSSI_LPS(void *pDM_VOID) void odm_FalseAlarmCounterStatistics(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - Pfalse_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct false_ALARM_STATISTICS *FalseAlmCnt = &pDM_Odm->FalseAlmCnt; u32 ret_value; if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) @@ -1062,7 +1062,7 @@ void odm_FAThresholdCheck( u32 *dm_FA_thres ) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; if (pDM_Odm->bLinked && (bPerformance || bDFSBand)) { /* For NIC */ @@ -1078,9 +1078,9 @@ void odm_FAThresholdCheck( u8 odm_ForbiddenIGICheck(void *pDM_VOID, u8 DIG_Dynamic_MIN, u8 CurrentIGI) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; - Pfalse_ALARM_STATISTICS pFalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; + struct false_ALARM_STATISTICS *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; u8 rx_gain_range_min = pDM_DigTable->rx_gain_range_min; if (pFalseAlmCnt->Cnt_all > 10000) { @@ -1134,8 +1134,8 @@ u8 odm_ForbiddenIGICheck(void *pDM_VOID, u8 DIG_Dynamic_MIN, u8 CurrentIGI) void odm_CCKPacketDetectionThresh(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - Pfalse_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct false_ALARM_STATISTICS *FalseAlmCnt = &pDM_Odm->FalseAlmCnt; u8 CurCCK_CCAThres; @@ -1195,8 +1195,8 @@ void odm_CCKPacketDetectionThresh(void *pDM_VOID) void ODM_Write_CCK_CCA_Thres(void *pDM_VOID, u8 CurCCK_CCAThres) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; /* modify by Guo.Mingzhi 2012-01-03 */ if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres) diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.h b/drivers/staging/rtl8723bs/hal/odm_DIG.h index f6777e97a24a27a2510a8344429028520cd5a3f8..88cfd542df16bef4c1577aa3e7fcfefcc64dd70e 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DIG.h +++ b/drivers/staging/rtl8723bs/hal/odm_DIG.h @@ -8,7 +8,7 @@ #ifndef __ODMDIG_H__ #define __ODMDIG_H__ -typedef struct _Dynamic_Initial_Gain_Threshold_ { +struct dig_t { /* _Dynamic_Initial_Gain_Threshold_ */ bool bStopDIG; bool bPSDInProgress; @@ -57,9 +57,9 @@ typedef struct _Dynamic_Initial_Gain_Threshold_ { u32 RSSI_max; u8 *pbP2pLinkInProgress; -} DIG_T, *pDIG_T; +}; -typedef struct false_ALARM_STATISTICS { +struct false_ALARM_STATISTICS { u32 Cnt_Parity_Fail; u32 Cnt_Rate_Illegal; u32 Cnt_Crc8_fail; @@ -75,28 +75,12 @@ typedef struct false_ALARM_STATISTICS { u32 Cnt_CCA_all; u32 Cnt_BW_USC; /* Gary */ u32 Cnt_BW_LSC; /* Gary */ -} false_ALARM_STATISTICS, *Pfalse_ALARM_STATISTICS; - -typedef enum tag_Dynamic_Init_Gain_Operation_Type_Definition { - DIG_TYPE_THRESH_HIGH = 0, - DIG_TYPE_THRESH_LOW = 1, - DIG_TYPE_BACKOFF = 2, - DIG_TYPE_RX_GAIN_MIN = 3, - DIG_TYPE_RX_GAIN_MAX = 4, - DIG_TYPE_ENABLE = 5, - DIG_TYPE_DISABLE = 6, - DIG_OP_TYPE_MAX -} DM_DIG_OP_E; - -typedef enum tag_ODM_PauseDIG_Type { +}; + +enum ODM_Pause_DIG_TYPE { ODM_PAUSE_DIG = BIT0, ODM_RESUME_DIG = BIT1 -} ODM_Pause_DIG_TYPE; - -typedef enum tag_ODM_PauseCCKPD_Type { - ODM_PAUSE_CCKPD = BIT0, - ODM_RESUME_CCKPD = BIT1 -} ODM_Pause_CCKPD_TYPE; +}; #define DM_DIG_THRESH_HIGH 40 #define DM_DIG_THRESH_LOW 35 @@ -157,7 +141,7 @@ void odm_Adaptivity(void *pDM_VOID, u8 IGI); void ODM_Write_DIG(void *pDM_VOID, u8 CurrentIGI); -void odm_PauseDIG(void *pDM_VOID, ODM_Pause_DIG_TYPE PauseType, u8 IGIValue); +void odm_PauseDIG(void *pDM_VOID, enum ODM_Pause_DIG_TYPE PauseType, u8 IGIValue); void odm_DIGInit(void *pDM_VOID); diff --git a/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.c b/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.c index e18c9d65eee2b88f80369923af9007ff25725a7a..57c5736527d2fd7225d21c6c88b72b373174dd0d 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.c +++ b/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.c @@ -9,8 +9,8 @@ void odm_DynamicBBPowerSavingInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct ps_t *pDM_PSTable = &pDM_Odm->DM_PSTable; pDM_PSTable->PreCCAState = CCA_MAX; pDM_PSTable->CurCCAState = CCA_MAX; @@ -22,8 +22,8 @@ void odm_DynamicBBPowerSavingInit(void *pDM_VOID) void ODM_RF_Saving(void *pDM_VOID, u8 bForceInNormal) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; + struct ps_t *pDM_PSTable = &pDM_Odm->DM_PSTable; u8 Rssi_Up_bound = 30; u8 Rssi_Low_bound = 25; diff --git a/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.h b/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.h index dba19271d526c7921685b856d7de9e3ed83b0de9..3ebbbfd1dd1fe95c7f33e36698cf774723b5f38a 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.h +++ b/drivers/staging/rtl8723bs/hal/odm_DynamicBBPowerSaving.h @@ -8,7 +8,7 @@ #ifndef __ODMDYNAMICBBPOWERSAVING_H__ #define __ODMDYNAMICBBPOWERSAVING_H__ -typedef struct _Dynamic_Power_Saving_ { +struct ps_t { /* _Dynamic_Power_Saving_ */ u8 PreCCAState; u8 CurCCAState; @@ -20,7 +20,7 @@ typedef struct _Dynamic_Power_Saving_ { u8 initialize; u32 Reg874, RegC70, Reg85C, RegA74; -} PS_T, *pPS_T; +}; #define dm_RF_Saving ODM_RF_Saving diff --git a/drivers/staging/rtl8723bs/hal/odm_DynamicTxPower.c b/drivers/staging/rtl8723bs/hal/odm_DynamicTxPower.c index 17f90f4cc1ad7be04f31a0b61cf0a9b07e48b3e6..398dfa13449d0bf0296e496abda5428298a89c88 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DynamicTxPower.c +++ b/drivers/staging/rtl8723bs/hal/odm_DynamicTxPower.c @@ -9,7 +9,7 @@ void odm_DynamicTxPowerInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; struct adapter *Adapter = pDM_Odm->Adapter; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); diff --git a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c index b7ebce7a6ff92947cb90d178a88fb36a08dbb069..12b37c17ea0c0d8cfed3fc6506a85c85fc305397 100644 --- a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c +++ b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c @@ -31,7 +31,7 @@ static u32 edca_setting_DL[HT_IOT_PEER_MAX] = { void ODM_EdcaTurboInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; struct adapter *Adapter = pDM_Odm->Adapter; pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; @@ -58,7 +58,7 @@ void odm_EdcaTurboCheck(void *pDM_VOID) * operate at the same time. In stage2/3, we need to prove universal * interface and merge all HW dynamic mechanism. */ - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("odm_EdcaTurboCheck ========================>\n")); @@ -73,7 +73,7 @@ void odm_EdcaTurboCheck(void *pDM_VOID) void odm_EdcaTurboCheckCE(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; struct adapter *Adapter = pDM_Odm->Adapter; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); struct recv_priv *precvpriv = &(Adapter->recvpriv); diff --git a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.h b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.h index bc574d2ad0657ae72e517462adbb591b2ff21b7f..e9f9f07221f2d7aa24c86fb8b267c2484f1e7d7d 100644 --- a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.h +++ b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.h @@ -8,12 +8,12 @@ #ifndef __ODMEDCATURBOCHECK_H__ #define __ODMEDCATURBOCHECK_H__ -typedef struct _EDCA_TURBO_ { +struct edca_t { /* _EDCA_TURBO_ */ bool bCurrentTurboEDCA; bool bIsCurRDLState; u32 prv_traffic_idx; /* edca turbo */ -} EDCA_T, *pEDCA_T; +}; void odm_EdcaTurboCheck(void *pDM_VOID); void ODM_EdcaTurboInit(void *pDM_VOID); diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c index 9c190b1024d8a7f59972d36acc47d3bf2155617c..638c16f5c66890cc51e5c1faf657a0e6213f1519 100644 --- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c +++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c @@ -23,7 +23,7 @@ static u8 odm_QueryRxPwrPercentage(s8 AntPower) } -s32 odm_SignalScaleMapping(PDM_ODM_T pDM_Odm, s32 CurrSig) +s32 odm_SignalScaleMapping(struct dm_odm_t *pDM_Odm, s32 CurrSig) { s32 RetSig = 0; @@ -77,7 +77,7 @@ static u8 odm_EVMdbToPercentage(s8 Value) } static void odm_RxPhyStatus92CSeries_Parsing( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, struct odm_packet_info *pPktinfo @@ -90,7 +90,7 @@ static void odm_RxPhyStatus92CSeries_Parsing( bool isCCKrate = false; u8 rf_rx_num = 0; u8 LNA_idx, VGA_idx; - PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus; + struct phy_status_rpt_8192cd_t *pPhyStaRpt = (struct phy_status_rpt_8192cd_t *)pPhyStatus; isCCKrate = pPktinfo->data_rate <= DESC_RATE11M; pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_A] = -1; @@ -226,19 +226,10 @@ static void odm_RxPhyStatus92CSeries_Parsing( /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */ /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ if (isCCKrate) { -#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING - pPhyInfo->SignalStrength = (u8)PWDB_ALL; -#else pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */ -#endif } else { if (rf_rx_num != 0) { -#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING - total_rssi /= rf_rx_num; - pPhyInfo->signal_strength = (u8)total_rssi; -#else pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num)); -#endif } } @@ -247,7 +238,7 @@ static void odm_RxPhyStatus92CSeries_Parsing( } static void odm_Process_RSSIForDM( - PDM_ODM_T pDM_Odm, struct odm_phy_info *pPhyInfo, struct odm_packet_info *pPktinfo + struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, struct odm_packet_info *pPktinfo ) { @@ -401,7 +392,7 @@ static void odm_Process_RSSIForDM( /* Endianness before calling this API */ /* */ static void ODM_PhyStatusQuery_92CSeries( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, struct odm_packet_info *pPktinfo @@ -415,7 +406,7 @@ static void ODM_PhyStatusQuery_92CSeries( } void ODM_PhyStatusQuery( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, struct odm_packet_info *pPktinfo @@ -430,10 +421,10 @@ void ODM_PhyStatusQuery( /* */ /* */ -HAL_STATUS ODM_ConfigRFWithHeaderFile( - PDM_ODM_T pDM_Odm, - ODM_RF_Config_Type ConfigType, - ODM_RF_RADIO_PATH_E eRFPath +enum hal_status ODM_ConfigRFWithHeaderFile( + struct dm_odm_t *pDM_Odm, + enum ODM_RF_Config_Type ConfigType, + enum odm_rf_radio_path_e eRFPath ) { ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, @@ -450,7 +441,7 @@ HAL_STATUS ODM_ConfigRFWithHeaderFile( return HAL_STATUS_SUCCESS; } -HAL_STATUS ODM_ConfigRFWithTxPwrTrackHeaderFile(PDM_ODM_T pDM_Odm) +enum hal_status ODM_ConfigRFWithTxPwrTrackHeaderFile(struct dm_odm_t *pDM_Odm) { ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===>ODM_ConfigRFWithTxPwrTrackHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); @@ -464,8 +455,8 @@ HAL_STATUS ODM_ConfigRFWithTxPwrTrackHeaderFile(PDM_ODM_T pDM_Odm) return HAL_STATUS_SUCCESS; } -HAL_STATUS ODM_ConfigBBWithHeaderFile( - PDM_ODM_T pDM_Odm, ODM_BB_Config_Type ConfigType +enum hal_status ODM_ConfigBBWithHeaderFile( + struct dm_odm_t *pDM_Odm, enum ODM_BB_Config_Type ConfigType ) { ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h index 945366bc37ce051d274ee4d26b780a5604c3361d..574f9cfe81900e13521e4671cf840f8ccca543ab 100644 --- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h +++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h @@ -30,16 +30,16 @@ /* structure and define */ /* */ -typedef struct _Phy_Rx_AGC_Info { +struct phy_rx_agc_info_t { #if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) u8 gain:7, trsw:1; #else u8 trsw:1, gain:7; #endif -} PHY_RX_AGC_INFO_T, *pPHY_RX_AGC_INFO_T; +}; -typedef struct _Phy_Status_Rpt_8192cd { - PHY_RX_AGC_INFO_T path_agc[2]; +struct phy_status_rpt_8192cd_t { + struct phy_rx_agc_info_t path_agc[2]; u8 ch_corr[2]; u8 cck_sig_qual_ofdm_pwdb_all; u8 cck_agc_rpt_ofdm_cfosho_a; @@ -74,79 +74,34 @@ typedef struct _Phy_Status_Rpt_8192cd { u8 sgi_en:1; u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ #endif -} PHY_STATUS_RPT_8192CD_T, *PPHY_STATUS_RPT_8192CD_T; - - -typedef struct _Phy_Status_Rpt_8812 { - /* 2012.05.24 LukeLee: This structure should take big/little endian in consideration later..... */ - - /* DWORD 0 */ - u8 gain_trsw[2]; -#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) - u16 chl_num:10; - u16 sub_chnl:4; - u16 r_RFMOD:2; -#else /* _BIG_ENDIAN_ */ - u16 r_RFMOD:2; - u16 sub_chnl:4; - u16 chl_num:10; -#endif - - /* DWORD 1 */ - u8 pwdb_all; - u8 cfosho[4]; /* DW 1 byte 1 DW 2 byte 0 */ - - /* DWORD 2 */ - s8 cfotail[4]; /* DW 2 byte 1 DW 3 byte 0 */ - - /* DWORD 3 */ - s8 rxevm[2]; /* DW 3 byte 1 DW 3 byte 2 */ - s8 rxsnr[2]; /* DW 3 byte 3 DW 4 byte 0 */ - - /* DWORD 4 */ - u8 PCTS_MSK_RPT[2]; - u8 pdsnr[2]; /* DW 4 byte 3 DW 5 Byte 0 */ - - /* DWORD 5 */ - u8 csi_current[2]; - u8 rx_gain_c; - - /* DWORD 6 */ - u8 rx_gain_d; - s8 sigevm; - u8 resvd_0; - u8 antidx_anta:3; - u8 antidx_antb:3; - u8 resvd_1:2; -} PHY_STATUS_RPT_8812_T, *PPHY_STATUS_RPT_8812_T; - +}; void ODM_PhyStatusQuery( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, struct odm_packet_info *pPktinfo ); -HAL_STATUS ODM_ConfigRFWithTxPwrTrackHeaderFile(PDM_ODM_T pDM_Odm); +enum hal_status ODM_ConfigRFWithTxPwrTrackHeaderFile(struct dm_odm_t *pDM_Odm); -HAL_STATUS ODM_ConfigRFWithHeaderFile( - PDM_ODM_T pDM_Odm, - ODM_RF_Config_Type ConfigType, - ODM_RF_RADIO_PATH_E eRFPath +enum hal_status ODM_ConfigRFWithHeaderFile( + struct dm_odm_t *pDM_Odm, + enum ODM_RF_Config_Type ConfigType, + enum odm_rf_radio_path_e eRFPath ); -HAL_STATUS ODM_ConfigBBWithHeaderFile( - PDM_ODM_T pDM_Odm, ODM_BB_Config_Type ConfigType +enum hal_status ODM_ConfigBBWithHeaderFile( + struct dm_odm_t *pDM_Odm, enum ODM_BB_Config_Type ConfigType ); -HAL_STATUS ODM_ConfigFWWithHeaderFile( - PDM_ODM_T pDM_Odm, - ODM_FW_Config_Type ConfigType, +enum hal_status ODM_ConfigFWWithHeaderFile( + struct dm_odm_t *pDM_Odm, + enum ODM_FW_Config_Type ConfigType, u8 *pFirmware, u32 *pSize ); -s32 odm_SignalScaleMapping(PDM_ODM_T pDM_Odm, s32 CurrSig); +s32 odm_SignalScaleMapping(struct dm_odm_t *pDM_Odm, s32 CurrSig); #endif diff --git a/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c b/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c index 6ca799816c08371e5ed5adfe09af77c1481c7c52..c3de123e2a487ed9a0d27ac2eb5cc71870e2581e 100644 --- a/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c +++ b/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c @@ -19,7 +19,7 @@ #define ValidCnt 5 static s16 odm_InbandNoise_Monitor_NSeries( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 bPauseDIG, u8 IGIValue, u32 max_time diff --git a/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.h b/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.h index a7f13a85559c79dd943955f72f44e6547da75755..ab114543f39c3ff567e5dbdb4fa7deafd4b7d7eb 100644 --- a/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.h +++ b/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.h @@ -24,10 +24,10 @@ struct noise_level { }; -typedef struct _ODM_NOISE_MONITOR_ { +struct odm_noise_monitor { s8 noise[MAX_RF_PATH]; s16 noise_all; -} ODM_NOISE_MONITOR; +}; s16 ODM_InbandNoise_Monitor( void *pDM_VOID, diff --git a/drivers/staging/rtl8723bs/hal/odm_PathDiv.c b/drivers/staging/rtl8723bs/hal/odm_PathDiv.c index 4d22360934f68a8a9eb7facf6ca437755658da3b..92b708265d4757e50f6c168c8ff38155f4290426 100644 --- a/drivers/staging/rtl8723bs/hal/odm_PathDiv.c +++ b/drivers/staging/rtl8723bs/hal/odm_PathDiv.c @@ -9,7 +9,7 @@ void odm_PathDiversityInit(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; if (!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV)) ODM_RT_TRACE( @@ -22,7 +22,7 @@ void odm_PathDiversityInit(void *pDM_VOID) void odm_PathDiversity(void *pDM_VOID) { - PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; if (!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV)) ODM_RT_TRACE( diff --git a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c index 39f989bf341078e77fdea5c1ee7b4e8567419e9b..63bf5ba3e0d5efec9b6d1d7ef5b21695a22db39b 100644 --- a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c +++ b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c @@ -8,10 +8,10 @@ #include "odm_precomp.h" void odm_ConfigRFReg_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data, - ODM_RF_RADIO_PATH_E RF_PATH, + enum odm_rf_radio_path_e RF_PATH, u32 RegAddr ) { @@ -106,7 +106,7 @@ void odm_ConfigRFReg_8723B( } -void odm_ConfigRF_RadioA_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u32 Data) +void odm_ConfigRF_RadioA_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data) { u32 content = 0x1000; /* RF_Content: radioa_txt */ u32 maskforPhySet = (u32)(content&0xE000); @@ -131,7 +131,7 @@ void odm_ConfigRF_RadioA_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u32 Data) ); } -void odm_ConfigMAC_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u8 Data) +void odm_ConfigMAC_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u8 Data) { rtw_write8(pDM_Odm->Adapter, Addr, Data); ODM_RT_TRACE( @@ -147,7 +147,7 @@ void odm_ConfigMAC_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u8 Data) } void odm_ConfigBB_AGC_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data @@ -170,7 +170,7 @@ void odm_ConfigBB_AGC_8723B( } void odm_ConfigBB_PHY_REG_PG_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u32 Band, u32 RfPath, u32 TxNum, @@ -198,7 +198,7 @@ void odm_ConfigBB_PHY_REG_PG_8723B( } void odm_ConfigBB_PHY_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data @@ -226,7 +226,7 @@ void odm_ConfigBB_PHY_8723B( } void odm_ConfigBB_TXPWR_LMT_8723B( - PDM_ODM_T pDM_Odm, + struct dm_odm_t *pDM_Odm, u8 *Regulation, u8 *Band, u8 *Bandwidth, diff --git a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h index 07b585950cf96f561bfc8e7b7f2ae80683240b4b..b392d14c389d5dc79eabb4374efe33c46d6c8b7a 100644 --- a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h +++ b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h @@ -7,24 +7,24 @@ #ifndef __INC_ODM_REGCONFIG_H_8723B #define __INC_ODM_REGCONFIG_H_8723B -void odm_ConfigRFReg_8723B(PDM_ODM_T pDM_Odm, +void odm_ConfigRFReg_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data, - ODM_RF_RADIO_PATH_E RF_PATH, + enum odm_rf_radio_path_e RF_PATH, u32 RegAddr ); -void odm_ConfigRF_RadioA_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u32 Data); +void odm_ConfigRF_RadioA_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data); -void odm_ConfigMAC_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u8 Data); +void odm_ConfigMAC_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u8 Data); -void odm_ConfigBB_AGC_8723B(PDM_ODM_T pDM_Odm, +void odm_ConfigBB_AGC_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data ); -void odm_ConfigBB_PHY_REG_PG_8723B(PDM_ODM_T pDM_Odm, +void odm_ConfigBB_PHY_REG_PG_8723B(struct dm_odm_t *pDM_Odm, u32 Band, u32 RfPath, u32 TxNum, @@ -33,13 +33,13 @@ void odm_ConfigBB_PHY_REG_PG_8723B(PDM_ODM_T pDM_Odm, u32 Data ); -void odm_ConfigBB_PHY_8723B(PDM_ODM_T pDM_Odm, +void odm_ConfigBB_PHY_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data ); -void odm_ConfigBB_TXPWR_LMT_8723B(PDM_ODM_T pDM_Odm, +void odm_ConfigBB_TXPWR_LMT_8723B(struct dm_odm_t *pDM_Odm, u8 *Regulation, u8 *Band, u8 *Bandwidth, diff --git a/drivers/staging/rtl8723bs/hal/odm_debug.c b/drivers/staging/rtl8723bs/hal/odm_debug.c index b92422c8fb8e4336910136c0544df7545182f696..b35451bcb437e728f2b13e8910b20c42c386c7b8 100644 --- a/drivers/staging/rtl8723bs/hal/odm_debug.c +++ b/drivers/staging/rtl8723bs/hal/odm_debug.c @@ -7,7 +7,7 @@ #include "odm_precomp.h" -void ODM_InitDebugSetting(PDM_ODM_T pDM_Odm) +void ODM_InitDebugSetting(struct dm_odm_t *pDM_Odm) { pDM_Odm->DebugLevel = ODM_DBG_LOUD; diff --git a/drivers/staging/rtl8723bs/hal/odm_debug.h b/drivers/staging/rtl8723bs/hal/odm_debug.h index a7381173d1a3cb0701e591ca58c9bbf93a662812..be0d4c49a7477de9342571bdb91d18d60e802ec9 100644 --- a/drivers/staging/rtl8723bs/hal/odm_debug.h +++ b/drivers/staging/rtl8723bs/hal/odm_debug.h @@ -131,8 +131,6 @@ ASSERT(false);\ } \ } while (0) -#define ODM_dbg_enter() { DbgPrint("==> %s\n", __func__); } -#define ODM_dbg_exit() { DbgPrint("<== %s\n", __func__); } #define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); } #define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr)\ @@ -162,6 +160,6 @@ no_printk("%s %p", title_str, ptr) #endif -void ODM_InitDebugSetting(PDM_ODM_T pDM_Odm); +void ODM_InitDebugSetting(struct dm_odm_t *pDM_Odm); #endif /* __ODM_DBG_H__ */ diff --git a/drivers/staging/rtl8723bs/hal/odm_interface.h b/drivers/staging/rtl8723bs/hal/odm_interface.h index 63f374f0bda7bdb553fff9fbad88d97a11bbe314..d19347b0289087b0816ae2049325afc689803d8c 100644 --- a/drivers/staging/rtl8723bs/hal/odm_interface.h +++ b/drivers/staging/rtl8723bs/hal/odm_interface.h @@ -11,8 +11,6 @@ -/* =========== Constant/Structure/Enum/... Define */ - /* =========== Macro Define */ #define _reg_all(_name) ODM_##_name @@ -39,13 +37,4 @@ ODM_REG(DIG, _pDM_Odm) #define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg) #define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit) -typedef enum _ODM_H2C_CMD { - ODM_H2C_RSSI_REPORT = 0, - ODM_H2C_PSD_RESULT = 1, - ODM_H2C_PathDiv = 2, - ODM_H2C_WIFI_CALIBRATION = 3, - ODM_MAX_H2CCMD -} ODM_H2C_CMD; - - #endif /* __ODM_INTERFACE_H__ */ diff --git a/drivers/staging/rtl8723bs/hal/odm_types.h b/drivers/staging/rtl8723bs/hal/odm_types.h index c79fc1813c3fee0f344bb8eb17f93fe30e0052a9..8168dc14e87960feaa7e673e4c832256fb02bb12 100644 --- a/drivers/staging/rtl8723bs/hal/odm_types.h +++ b/drivers/staging/rtl8723bs/hal/odm_types.h @@ -15,7 +15,7 @@ #define GET_ODM(__padapter) ((PDM_ODM_T)(&((GET_HAL_DATA(__padapter))->odmpriv))) -typedef enum _HAL_STATUS { +enum hal_status { HAL_STATUS_SUCCESS, HAL_STATUS_FAILURE, /*RT_STATUS_PENDING, @@ -24,58 +24,15 @@ typedef enum _HAL_STATUS { RT_STATUS_INVALID_PARAMETER, RT_STATUS_NOT_SUPPORT, RT_STATUS_OS_API_FAILED,*/ -} HAL_STATUS, *PHAL_STATUS; +}; -/* */ -/* Declare for ODM spin lock definition temporarily from compile pass. */ -/* */ -typedef enum _RT_SPINLOCK_TYPE { - RT_TX_SPINLOCK = 1, - RT_RX_SPINLOCK = 2, - RT_RM_SPINLOCK = 3, - RT_CAM_SPINLOCK = 4, - RT_SCAN_SPINLOCK = 5, - RT_LOG_SPINLOCK = 7, - RT_BW_SPINLOCK = 8, - RT_CHNLOP_SPINLOCK = 9, - RT_RF_OPERATE_SPINLOCK = 10, - RT_INITIAL_SPINLOCK = 11, - RT_RF_STATE_SPINLOCK = 12, /* For RF state. Added by Bruce, 2007-10-30. */ - /* Shall we define Ndis 6.2 SpinLock Here ? */ - RT_PORT_SPINLOCK = 16, - RT_H2C_SPINLOCK = 20, /* For H2C cmd. Added by tynli. 2009.11.09. */ - - RT_BTData_SPINLOCK = 25, - - RT_WAPI_OPTION_SPINLOCK = 26, - RT_WAPI_RX_SPINLOCK = 27, - - /* add for 92D CCK control issue */ - RT_CCK_PAGEA_SPINLOCK = 28, - RT_BUFFER_SPINLOCK = 29, - RT_CHANNEL_AND_BANDWIDTH_SPINLOCK = 30, - RT_GEN_TEMP_BUF_SPINLOCK = 31, - RT_AWB_SPINLOCK = 32, - RT_FW_PS_SPINLOCK = 33, - RT_HW_TIMER_SPIN_LOCK = 34, - RT_MPT_WI_SPINLOCK = 35, - RT_P2P_SPIN_LOCK = 36, /* Protect P2P context */ - RT_DBG_SPIN_LOCK = 37, - RT_IQK_SPINLOCK = 38, - RT_PENDED_OID_SPINLOCK = 39, - RT_CHNLLIST_SPINLOCK = 40, - RT_INDIC_SPINLOCK = 41, /* protect indication */ -} RT_SPINLOCK_TYPE; - #if defined(__LITTLE_ENDIAN) #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE #else #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG #endif - typedef struct timer_list RT_TIMER, *PRT_TIMER; - typedef void *RT_TIMER_CALL_BACK; #define STA_INFO_T struct sta_info #define PSTA_INFO_T struct sta_info * diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c index 86f31d98349abed01fad1969906f4586ec44220e..2451875ab3c07a7b8adb697129788cd0e42974d6 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c @@ -24,17 +24,11 @@ static u8 _is_fw_read_cmd_down(struct adapter *padapter, u8 msgbox_num) u8 valid; - /* DBG_8192C(" _is_fw_read_cmd_down , reg_1cc(%x), msg_box(%d)...\n", rtw_read8(padapter, REG_HMETFR), msgbox_num); */ - do { valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num); if (0 == valid) { read_down = true; } -#ifdef CONFIG_WOWLAN - else - msleep(1); -#endif } while ((!read_down) && (retry_cnts--)); return read_down; @@ -80,12 +74,8 @@ s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmd do { h2c_box_num = pHalData->LastHMEBoxNum; - if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) { - DBG_8192C(" fw read cmd failed...\n"); - /* DBG_8192C(" 0x1c0: 0x%8x\n", rtw_read32(padapter, 0x1c0)); */ - /* DBG_8192C(" 0x1c4: 0x%8x\n", rtw_read32(padapter, 0x1c4)); */ + if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) goto exit; - } if (CmdLen <= 3) memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); @@ -104,9 +94,6 @@ s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmd msgbox_addr = REG_HMEBOX_0 + (h2c_box_num*MESSAGE_BOX_SIZE); rtw_write32(padapter, msgbox_addr, h2c_cmd); - /* DBG_8192C("MSG_BOX:%d, CmdLen(%d), CmdID(0x%x), reg:0x%x =>h2c_cmd:0x%.8x, reg:0x%x =>h2c_cmd_ex:0x%.8x\n" */ - /* , pHalData->LastHMEBoxNum , CmdLen, ElementID, msgbox_addr, h2c_cmd, msgbox_ex_addr, h2c_cmd_ex); */ - pHalData->LastHMEBoxNum = (h2c_box_num+1) % MAX_H2C_BOX_NUMS; } while (0); @@ -129,9 +116,6 @@ static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength) struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - /* DBG_871X("%s\n", __func__); */ - pwlanhdr = (struct ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_control); @@ -165,7 +149,6 @@ static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength) pktlen += 2; if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { - /* DBG_871X("ie len =%d\n", cur_network->IELength); */ pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fix_ie); memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fix_ie), pktlen); @@ -205,15 +188,11 @@ static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength) _ConstructBeacon: - if ((pktlen + TXDESC_SIZE) > 512) { - DBG_871X("beacon frame too large\n"); + if ((pktlen + TXDESC_SIZE) > 512) return; - } *pLength = pktlen; - /* DBG_871X("%s bcn_sz =%d\n", __func__, pktlen); */ - } static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength) @@ -223,8 +202,6 @@ static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength) struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - /* DBG_871X("%s\n", __func__); */ - pwlanhdr = (struct ieee80211_hdr *)pframe; /* Frame control. */ @@ -264,9 +241,6 @@ static void ConstructNullFunctionData( struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - - /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ - pwlanhdr = (struct ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_control; @@ -316,513 +290,6 @@ static void ConstructNullFunctionData( *pLength = pktlen; } - -#ifdef CONFIG_WOWLAN -/* */ -/* Description: */ -/* Construct the ARP response packet to support ARP offload. */ -/* */ -static void ConstructARPResponse( - struct adapter *padapter, - u8 *pframe, - u32 *pLength, - u8 *pIPAddress -) -{ - struct ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct security_priv *psecuritypriv = &padapter->securitypriv; - static u8 ARPLLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}; - u8 *pARPRspPkt = pframe; - /* for TKIP Cal MIC */ - u8 *payload = pframe; - u8 EncryptionHeadOverhead = 0; - /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ - - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *(fctrl) = 0; - - /* */ - /* MAC Header. */ - /* */ - SetFrameType(fctrl, WIFI_DATA); - /* SetFrameSubType(fctrl, 0); */ - SetToDs(fctrl); - memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); - - SetSeqNum(pwlanhdr, 0); - SetDuration(pwlanhdr, 0); - /* SET_80211_HDR_FRAME_CONTROL(pARPRspPkt, 0); */ - /* SET_80211_HDR_TYPE_AND_SUBTYPE(pARPRspPkt, Type_Data); */ - /* SET_80211_HDR_TO_DS(pARPRspPkt, 1); */ - /* SET_80211_HDR_ADDRESS1(pARPRspPkt, pMgntInfo->Bssid); */ - /* SET_80211_HDR_ADDRESS2(pARPRspPkt, Adapter->CurrentAddress); */ - /* SET_80211_HDR_ADDRESS3(pARPRspPkt, pMgntInfo->Bssid); */ - - /* SET_80211_HDR_DURATION(pARPRspPkt, 0); */ - /* SET_80211_HDR_FRAGMENT_SEQUENCE(pARPRspPkt, 0); */ - *pLength = 24; - - /* */ - /* Security Header: leave space for it if necessary. */ - /* */ - - switch (psecuritypriv->dot11PrivacyAlgrthm) { - case _WEP40_: - case _WEP104_: - EncryptionHeadOverhead = 4; - break; - case _TKIP_: - EncryptionHeadOverhead = 8; - break; - case _AES_: - EncryptionHeadOverhead = 8; - break; - default: - EncryptionHeadOverhead = 0; - } - - if (EncryptionHeadOverhead > 0) { - memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); - *pLength += EncryptionHeadOverhead; - SetPrivacy(fctrl); - } - - /* */ - /* Frame Body. */ - /* */ - pARPRspPkt = (u8 *)(pframe + *pLength); - payload = pARPRspPkt; /* Get Payload pointer */ - /* LLC header */ - memcpy(pARPRspPkt, ARPLLCHeader, 8); - *pLength += 8; - - /* ARP element */ - pARPRspPkt += 8; - SET_ARP_PKT_HW(pARPRspPkt, 0x0100); - SET_ARP_PKT_PROTOCOL(pARPRspPkt, 0x0008); /* IP protocol */ - SET_ARP_PKT_HW_ADDR_LEN(pARPRspPkt, 6); - SET_ARP_PKT_PROTOCOL_ADDR_LEN(pARPRspPkt, 4); - SET_ARP_PKT_OPERATION(pARPRspPkt, 0x0200); /* ARP response */ - SET_ARP_PKT_SENDER_MAC_ADDR(pARPRspPkt, myid(&(padapter->eeprompriv))); - SET_ARP_PKT_SENDER_IP_ADDR(pARPRspPkt, pIPAddress); - { - SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, get_my_bssid(&(pmlmeinfo->network))); - SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pIPAddress); - DBG_871X("%s Target Mac Addr:%pM\n", __func__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); - DBG_871X("%s Target IP Addr:%pI4\n", __func__, IP_ARG(pIPAddress)); - } - - *pLength += 28; - - if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) { - u8 mic[8]; - struct mic_data micdata; - struct sta_info *psta = NULL; - u8 priority[4] = { - 0x0, 0x0, 0x0, 0x0 - }; - u8 null_key[16] = { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 - }; - - DBG_871X("%s(): Add MIC\n", __func__); - - psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network))); - if (psta) { - if (!memcmp(&psta->dot11tkiptxmickey.skey[0], null_key, 16)) { - DBG_871X("%s(): STA dot11tkiptxmickey == 0\n", __func__); - } - /* start to calculate the mic code */ - rtw_secmicsetkey(&micdata, &psta->dot11tkiptxmickey.skey[0]); - } - - rtw_secmicappend(&micdata, pwlanhdr->addr3, 6); /* DA */ - - rtw_secmicappend(&micdata, pwlanhdr->addr2, 6); /* SA */ - - priority[0] = 0; - rtw_secmicappend(&micdata, &priority[0], 4); - - rtw_secmicappend(&micdata, payload, 36); /* payload length = 8 + 28 */ - - rtw_secgetmic(&micdata, &(mic[0])); - - pARPRspPkt += 28; - memcpy(pARPRspPkt, &(mic[0]), 8); - - *pLength += 8; - } -} - -#ifdef CONFIG_PNO_SUPPORT -static void ConstructPnoInfo( - struct adapter *padapter, u8 *pframe, u32 *pLength -) -{ - - struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); - - u8 *pPnoInfoPkt = pframe; - pPnoInfoPkt = (u8 *)(pframe + *pLength); - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_num, 4); - - *pLength += 4; - pPnoInfoPkt += 4; - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_period, 4); - - *pLength += 4; - pPnoInfoPkt += 4; - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_iterations, 4); - - *pLength += 4; - pPnoInfoPkt += 4; - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->slow_scan_period, 4); - - *pLength += 4; - pPnoInfoPkt += 4; - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_length, - MAX_PNO_LIST_COUNT); - - *pLength += MAX_PNO_LIST_COUNT; - pPnoInfoPkt += MAX_PNO_LIST_COUNT; - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_cipher_info, - MAX_PNO_LIST_COUNT); - - *pLength += MAX_PNO_LIST_COUNT; - pPnoInfoPkt += MAX_PNO_LIST_COUNT; - memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_channel_info, - MAX_PNO_LIST_COUNT); - - *pLength += MAX_PNO_LIST_COUNT; - pPnoInfoPkt += MAX_PNO_LIST_COUNT; -} - -static void ConstructSSIDList( - struct adapter *padapter, u8 *pframe, u32 *pLength -) -{ - int i = 0; - u8 *pSSIDListPkt = pframe; - struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); - - pSSIDListPkt = (u8 *)(pframe + *pLength); - - for (i = 0; i < pwrctl->pnlo_info->ssid_num ; i++) { - memcpy(pSSIDListPkt, &pwrctl->pno_ssid_list->node[i].SSID, - pwrctl->pnlo_info->ssid_length[i]); - - *pLength += WLAN_SSID_MAXLEN; - pSSIDListPkt += WLAN_SSID_MAXLEN; - } -} - -static void ConstructScanInfo( - struct adapter *padapter, u8 *pframe, u32 *pLength -) -{ - int i = 0; - u8 *pScanInfoPkt = pframe; - struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); - - pScanInfoPkt = (u8 *)(pframe + *pLength); - - memcpy(pScanInfoPkt, &pwrctl->pscan_info->channel_num, 1); - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_ch, 1); - - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_bw, 1); - - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_40_offset, 1); - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_80_offset, 1); - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->periodScan, 1); - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->period_scan_time, 1); - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->enableRFE, 1); - - *pLength += 1; - pScanInfoPkt += 1; - memcpy(pScanInfoPkt, &pwrctl->pscan_info->rfe_type, 8); - - *pLength += 8; - pScanInfoPkt += 8; - - for (i = 0; i < MAX_SCAN_LIST_COUNT; i++) { - memcpy(pScanInfoPkt, &pwrctl->pscan_info->ssid_channel_info[i], 4); - *pLength += 4; - pScanInfoPkt += 4; - } -} -#endif - -#ifdef CONFIG_GTK_OL -static void ConstructGTKResponse( - struct adapter *padapter, u8 *pframe, u32 *pLength -) -{ - struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct security_priv *psecuritypriv = &padapter->securitypriv; - static u8 LLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E}; - static u8 GTKbody_a[11] = {0x01, 0x03, 0x00, 0x5F, 0x02, 0x03, 0x12, 0x00, 0x10, 0x42, 0x0B}; - u8 *pGTKRspPkt = pframe; - u8 EncryptionHeadOverhead = 0; - /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ - - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *(fctrl) = 0; - - /* */ - /* MAC Header. */ - /* */ - SetFrameType(fctrl, WIFI_DATA); - /* SetFrameSubType(fctrl, 0); */ - SetToDs(fctrl); - memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); - - SetSeqNum(pwlanhdr, 0); - SetDuration(pwlanhdr, 0); - - *pLength = 24; - - /* */ - /* Security Header: leave space for it if necessary. */ - /* */ - - switch (psecuritypriv->dot11PrivacyAlgrthm) { - case _WEP40_: - case _WEP104_: - EncryptionHeadOverhead = 4; - break; - case _TKIP_: - EncryptionHeadOverhead = 8; - break; - case _AES_: - EncryptionHeadOverhead = 8; - break; - default: - EncryptionHeadOverhead = 0; - } - - if (EncryptionHeadOverhead > 0) { - memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); - *pLength += EncryptionHeadOverhead; - /* GTK's privacy bit is done by FW */ - /* SetPrivacy(fctrl); */ - } - - /* */ - /* Frame Body. */ - /* */ - pGTKRspPkt = (u8 *)(pframe + *pLength); - /* LLC header */ - memcpy(pGTKRspPkt, LLCHeader, 8); - *pLength += 8; - - /* GTK element */ - pGTKRspPkt += 8; - - /* GTK frame body after LLC, part 1 */ - memcpy(pGTKRspPkt, GTKbody_a, 11); - *pLength += 11; - pGTKRspPkt += 11; - /* GTK frame body after LLC, part 2 */ - memset(&(pframe[*pLength]), 0, 88); - *pLength += 88; - pGTKRspPkt += 88; - -} -#endif /* CONFIG_GTK_OL */ - -#ifdef CONFIG_PNO_SUPPORT -static void ConstructProbeReq(struct adapter *padapter, u8 *pframe, u32 *pLength) -{ - struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; - u32 pktlen; - unsigned char *mac; - unsigned char bssrate[NumRates]; - int bssrate_len = 0; - u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - pwlanhdr = (struct ieee80211_hdr *)pframe; - mac = myid(&(padapter->eeprompriv)); - - fctrl = &(pwlanhdr->frame_control); - *(fctrl) = 0; - - /* broadcast probe request frame */ - memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); - memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); - - memcpy(pwlanhdr->addr2, mac, ETH_ALEN); - - SetSeqNum(pwlanhdr, 0); - SetFrameSubType(pframe, WIFI_PROBEREQ); - - pktlen = sizeof(struct ieee80211_hdr_3addr); - pframe += pktlen; - - pframe = rtw_set_ie(pframe, WLAN_EID_SSID, 0, NULL, &pktlen); - - get_rate_set(padapter, bssrate, &bssrate_len); - - if (bssrate_len > 8) { - pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, 8, bssrate, &pktlen); - pframe = rtw_set_ie(pframe, WLAN_EID_EXT_SUPP_RATES, (bssrate_len - 8), (bssrate + 8), &pktlen); - } else - pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, bssrate_len, bssrate, &pktlen); - - *pLength = pktlen; -} -#endif /* CONFIG_PNO_SUPPORT */ -#endif /* CONFIG_WOWLAN */ - -#ifdef CONFIG_AP_WOWLAN -static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) -{ - struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; - u8 *mac, *bssid; - u32 pktlen; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); - u8 *pwps_ie; - uint wps_ielen; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - /* DBG_871X("%s\n", __func__); */ - - pwlanhdr = (struct ieee80211_hdr *)pframe; - - mac = myid(&(padapter->eeprompriv)); - bssid = cur_network->MacAddress; - - fctrl = &(pwlanhdr->frame_control); - *(fctrl) = 0; - memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); - memcpy(pwlanhdr->addr2, mac, ETH_ALEN); - memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); - - DBG_871X("%s FW Mac Addr:%pM\n", __func__, MAC_ARG(mac)); - DBG_871X("%s FW IP Addr:%pI4\n", __func__, IP_ARG(StaAddr)); - - SetSeqNum(pwlanhdr, 0); - SetFrameSubType(fctrl, WIFI_PROBERSP); - - pktlen = sizeof(struct ieee80211_hdr_3addr); - pframe += pktlen; - - if (cur_network->IELength > MAX_IE_SZ) - return; - - pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, - cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); - - /* inerset & update wps_probe_resp_ie */ - if (pmlmepriv->wps_probe_resp_ie && pwps_ie && (wps_ielen > 0)) { - uint wps_offset, remainder_ielen; - u8 *premainder_ie; - - wps_offset = (uint)(pwps_ie - cur_network->IEs); - - premainder_ie = pwps_ie + wps_ielen; - - remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; - - memcpy(pframe, cur_network->IEs, wps_offset); - pframe += wps_offset; - pktlen += wps_offset; - - wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ - if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) { - memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); - pframe += wps_ielen+2; - pktlen += wps_ielen+2; - } - - if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { - memcpy(pframe, premainder_ie, remainder_ielen); - pframe += remainder_ielen; - pktlen += remainder_ielen; - } - } else { - memcpy(pframe, cur_network->IEs, cur_network->IELength); - pframe += cur_network->IELength; - pktlen += cur_network->IELength; - } - - /* retrieve SSID IE from cur_network->Ssid */ - { - u8 *ssid_ie; - sint ssid_ielen; - sint ssid_ielen_diff; - u8 buf[MAX_IE_SZ]; - u8 *ies = pframe + sizeof(struct ieee80211_hdr_3addr); - - ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, WLAN_EID_SSID, &ssid_ielen, - (pframe-ies)-_FIXED_IE_LENGTH_); - - ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen; - - if (ssid_ie && cur_network->Ssid.SsidLength) { - uint remainder_ielen; - u8 *remainder_ie; - remainder_ie = ssid_ie+2; - remainder_ielen = (pframe-remainder_ie); - - if (remainder_ielen > MAX_IE_SZ) { - DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); - remainder_ielen = MAX_IE_SZ; - } - - memcpy(buf, remainder_ie, remainder_ielen); - memcpy(remainder_ie+ssid_ielen_diff, buf, remainder_ielen); - *(ssid_ie+1) = cur_network->Ssid.SsidLength; - memcpy(ssid_ie+2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength); - pframe += ssid_ielen_diff; - pktlen += ssid_ielen_diff; - } - } - - *pLength = pktlen; - -} -#endif /* CONFIG_AP_WOWLAN */ - /* * To check if reserved page content is destroyed by beacon because beacon * is too large. @@ -832,155 +299,46 @@ void CheckFwRsvdPageContent(struct adapter *Adapter) { } -static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc) +static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) { u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0}; - DBG_871X("8723BRsvdPageLoc: ProbeRsp =%d PsPoll =%d Null =%d QoSNull =%d BTNull =%d\n", - rsvdpageloc->LocProbeRsp, rsvdpageloc->LocPsPoll, - rsvdpageloc->LocNullData, rsvdpageloc->LocQosNull, - rsvdpageloc->LocBTQosNull); - SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CRsvdPageParm:", u1H2CRsvdPageParm, H2C_RSVDPAGE_LOC_LEN); - FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); -} - -static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc) -{ -#ifdef CONFIG_WOWLAN - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - u8 u1H2CAoacRsvdPageParm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; + print_hex_dump_debug(DRIVER_PREFIX ": u1H2CRsvdPageParm:", DUMP_PREFIX_NONE, + 16, 1, u1H2CRsvdPageParm, H2C_RSVDPAGE_LOC_LEN, false); - DBG_871X("8723BAOACRsvdPageLoc: RWC =%d ArpRsp =%d NbrAdv =%d GtkRsp =%d GtkInfo =%d ProbeReq =%d NetworkList =%d\n", - rsvdpageloc->LocRemoteCtrlInfo, rsvdpageloc->LocArpRsp, - rsvdpageloc->LocNbrAdv, rsvdpageloc->LocGTKRsp, - rsvdpageloc->LocGTKInfo, rsvdpageloc->LocProbeReq, - rsvdpageloc->LocNetList); - - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - SET_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocRemoteCtrlInfo); - SET_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocArpRsp); - /* SET_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(u1H2CAoacRsvdPageParm, rsvdpageloc->LocNbrAdv); */ - SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKRsp); - SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKInfo); -#ifdef CONFIG_GTK_OL - SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKEXTMEM); -#endif /* CONFIG_GTK_OL */ - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CAoacRsvdPageParm:", u1H2CAoacRsvdPageParm, H2C_AOAC_RSVDPAGE_LOC_LEN); - FillH2CCmd8723B(padapter, H2C_8723B_AOAC_RSVD_PAGE, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); - } else { -#ifdef CONFIG_PNO_SUPPORT - if (!pwrpriv->pno_in_resume) { - DBG_871X("NLO_INFO =%d\n", rsvdpageloc->LocPNOInfo); - memset(&u1H2CAoacRsvdPageParm, 0, sizeof(u1H2CAoacRsvdPageParm)); - SET_H2CCMD_AOAC_RSVDPAGE_LOC_NLO_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocPNOInfo); - FillH2CCmd8723B(padapter, H2C_AOAC_RSVDPAGE3, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); - msleep(10); - } -#endif - } - -#endif /* CONFIG_WOWLAN */ + FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); } -#ifdef CONFIG_AP_WOWLAN -static void rtl8723b_set_ap_wow_rsvdpage_cmd( - struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc -) +static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) { - u8 header; - u8 rsvdparm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; - - header = rtw_read8(padapter, REG_BCNQ_BDNY); - - DBG_871X("%s: beacon: %d, probeRsp: %d, header:0x%02x\n", __func__, - rsvdpageloc->LocApOffloadBCN, - rsvdpageloc->LocProbeRsp, - header); - - SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(rsvdparm, - rsvdpageloc->LocApOffloadBCN + header); - - FillH2CCmd8723B(padapter, H2C_8723B_BCN_RSVDPAGE, - H2C_BCN_RSVDPAGE_LEN, rsvdparm); - - msleep(10); - - memset(&rsvdparm, 0, sizeof(rsvdparm)); - - SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp( - rsvdparm, - rsvdpageloc->LocProbeRsp + header); - - FillH2CCmd8723B(padapter, H2C_8723B_PROBERSP_RSVDPAGE, - H2C_PROBERSP_RSVDPAGE_LEN, rsvdparm); - - msleep(10); } -#endif /* CONFIG_AP_WOWLAN */ void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid) { u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN] = {0}; u8 macid_end = 0; - DBG_871X("%s(): mstatus = %d macid =%d\n", __func__, mstatus, macid); - SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(u1H2CMediaStatusRptParm, mstatus); SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(u1H2CMediaStatusRptParm, 0); SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid); SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end); - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CMediaStatusRptParm:", u1H2CMediaStatusRptParm, H2C_MEDIA_STATUS_RPT_LEN); - FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm); -} - -#ifdef CONFIG_WOWLAN -static void rtl8723b_set_FwKeepAlive_cmd(struct adapter *padapter, u8 benable, u8 pkt_type) -{ - u8 u1H2CKeepAliveParm[H2C_KEEP_ALIVE_CTRL_LEN] = {0}; - u8 adopt = 1, check_period = 5; - - DBG_871X("%s(): benable = %d\n", __func__, benable); - SET_8723B_H2CCMD_KEEPALIVE_PARM_ENABLE(u1H2CKeepAliveParm, benable); - SET_8723B_H2CCMD_KEEPALIVE_PARM_ADOPT(u1H2CKeepAliveParm, adopt); - SET_8723B_H2CCMD_KEEPALIVE_PARM_PKT_TYPE(u1H2CKeepAliveParm, pkt_type); - SET_8723B_H2CCMD_KEEPALIVE_PARM_CHECK_PERIOD(u1H2CKeepAliveParm, check_period); - - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CKeepAliveParm:", u1H2CKeepAliveParm, H2C_KEEP_ALIVE_CTRL_LEN); + print_hex_dump_debug(DRIVER_PREFIX ": u1H2CMediaStatusRptParm:", DUMP_PREFIX_NONE, + 16, 1, u1H2CMediaStatusRptParm, H2C_MEDIA_STATUS_RPT_LEN, false); - FillH2CCmd8723B(padapter, H2C_8723B_KEEP_ALIVE, H2C_KEEP_ALIVE_CTRL_LEN, u1H2CKeepAliveParm); -} - -static void rtl8723b_set_FwDisconDecision_cmd(struct adapter *padapter, u8 benable) -{ - u8 u1H2CDisconDecisionParm[H2C_DISCON_DECISION_LEN] = {0}; - u8 adopt = 1, check_period = 10, trypkt_num = 0; - - DBG_871X("%s(): benable = %d\n", __func__, benable); - SET_8723B_H2CCMD_DISCONDECISION_PARM_ENABLE(u1H2CDisconDecisionParm, benable); - SET_8723B_H2CCMD_DISCONDECISION_PARM_ADOPT(u1H2CDisconDecisionParm, adopt); - SET_8723B_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(u1H2CDisconDecisionParm, check_period); - SET_8723B_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(u1H2CDisconDecisionParm, trypkt_num); - - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CDisconDecisionParm:", u1H2CDisconDecisionParm, H2C_DISCON_DECISION_LEN); - - FillH2CCmd8723B(padapter, H2C_8723B_DISCON_DECISION, H2C_DISCON_DECISION_LEN, u1H2CDisconDecisionParm); + FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm); } -#endif /* CONFIG_WOWLAN */ void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask) { u8 u1H2CMacIdConfigParm[H2C_MACID_CFG_LEN] = {0}; - DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x\n", __func__, mac_id, raid, bw, mask); - SET_8723B_H2CCMD_MACID_CFG_MACID(u1H2CMacIdConfigParm, mac_id); SET_8723B_H2CCMD_MACID_CFG_RAID(u1H2CMacIdConfigParm, raid); SET_8723B_H2CCMD_MACID_CFG_SGI_EN(u1H2CMacIdConfigParm, sgi ? 1 : 0); @@ -990,7 +348,9 @@ void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16)); SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24)); - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CMacIdConfigParm:", u1H2CMacIdConfigParm, H2C_MACID_CFG_LEN); + print_hex_dump_debug(DRIVER_PREFIX ": u1H2CMacIdConfigParm:", DUMP_PREFIX_NONE, + 16, 1, u1H2CMacIdConfigParm, H2C_MACID_CFG_LEN, false); + FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm); } @@ -1001,14 +361,13 @@ void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param) u8 rssi = *(param+2); u8 uldl_state = 0; - /* DBG_871X("%s(): param =%.2x-%.2x-%.2x\n", __func__, *param, *(param+1), *(param+2)); */ - /* DBG_871X("%s(): mac_id =%d rssi =%d\n", __func__, mac_id, rssi); */ - SET_8723B_H2CCMD_RSSI_SETTING_MACID(u1H2CRssiSettingParm, mac_id); SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi); SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state); - RT_PRINT_DATA(_module_hal_init_c_, _drv_notice_, "u1H2CRssiSettingParm:", u1H2CRssiSettingParm, H2C_RSSI_SETTING_LEN); + print_hex_dump_debug(DRIVER_PREFIX ": u1H2CRssiSettingParm:", DUMP_PREFIX_NONE, + 16, 1, u1H2CRssiSettingParm, H2C_RSSI_SETTING_LEN, false); + FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm); } @@ -1020,26 +379,12 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) u8 u1H2CPwrModeParm[H2C_PWRMODE_LEN] = {0}; u8 PowerState = 0, awake_intvl = 1, byte5 = 0, rlbm = 0; - if (pwrpriv->dtim > 0) - DBG_871X("%s(): FW LPS mode = %d, SmartPS =%d, dtim =%d\n", __func__, psmode, pwrpriv->smart_ps, pwrpriv->dtim); + if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16) + awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */ else - DBG_871X("%s(): FW LPS mode = %d, SmartPS =%d\n", __func__, psmode, pwrpriv->smart_ps); - -#ifdef CONFIG_WOWLAN - if (psmode == PS_MODE_DTIM) { /* For WOWLAN LPS, DTIM = (awake_intvl - 1) */ awake_intvl = 3;/* DTIM =2 */ - rlbm = 2; - } else -#endif /* CONFIG_WOWLAN */ - { - if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16) - awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */ - else - awake_intvl = 3;/* DTIM =2 */ - - rlbm = 2; - } + rlbm = 2; if (padapter->registrypriv.wifi_spec == 1) { awake_intvl = 2; @@ -1085,32 +430,17 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) pmlmeext->DrvBcnEarly = 0xff; pmlmeext->DrvBcnTimeOut = 0xff; - DBG_871X("%s(): bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); - for (i = 0; i < 9; i++) { pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i]*100)/pmlmeext->bcn_cnt; - DBG_871X( - "%s(): bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d] = %d\n", - __func__, - i, - pmlmeext->bcn_delay_cnt[i], - i, - pmlmeext->bcn_delay_ratio[i] - ); - ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; - if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff) { + if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff) pmlmeext->DrvBcnEarly = i; - DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, pmlmeext->DrvBcnEarly); - } - if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff) { + if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff) pmlmeext->DrvBcnTimeOut = i; - DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, pmlmeext->DrvBcnTimeOut); - } /* reset adaptive_early_32k cnt */ pmlmeext->bcn_delay_cnt[i] = 0; @@ -1121,9 +451,6 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) pmlmeext->bcn_cnt = 0; pmlmeext->adaptive_tsf_done = true; - } else { - DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, pmlmeext->DrvBcnEarly); - DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, pmlmeext->DrvBcnTimeOut); } /* offload to FW if fw version > v15.10 @@ -1138,7 +465,8 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN); - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPwrModeParm:", u1H2CPwrModeParm, H2C_PWRMODE_LEN); + print_hex_dump_debug(DRIVER_PREFIX ": u1H2CPwrModeParm:", DUMP_PREFIX_NONE, + 16, 1, u1H2CPwrModeParm, H2C_PWRMODE_LEN, false); FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm); } @@ -1151,267 +479,24 @@ void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter) u8 ps_timeout = 20; /* ms Keep awake when tx */ u8 dtim_period = 3; - /* DBG_871X("%s(): FW LPS mode = %d\n", __func__, psmode); */ - SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(u1H2CPsTuneParm, bcn_to_limit); SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(u1H2CPsTuneParm, dtim_timeout); SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(u1H2CPsTuneParm, ps_timeout); SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1); SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period); - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPsTuneParm:", u1H2CPsTuneParm, H2C_PSTUNEPARAM_LEN); + print_hex_dump_debug(DRIVER_PREFIX ": u1H2CPsTuneParm:", DUMP_PREFIX_NONE, + 16, 1, u1H2CPsTuneParm, H2C_PSTUNEPARAM_LEN, false); FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm); } void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param) { - /* BIT0:enable, BIT1:NoConnect32k */ - - DBG_871X("%s()\n", __func__); FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &cmd_param); } -#ifdef CONFIG_WOWLAN -static void rtl8723b_set_FwWoWlanCtrl_Cmd(struct adapter *padapter, u8 bFuncEn) -{ - struct security_priv *psecpriv = &padapter->securitypriv; - u8 u1H2CWoWlanCtrlParm[H2C_WOWLAN_LEN] = {0}; - u8 discont_wake = 1, gpionum = 0, gpio_dur = 0, hw_unicast = 0; - u8 sdio_wakeup_enable = 1; - u8 gpio_high_active = 0; /* 0: low active, 1: high active */ - u8 magic_pkt = 0; - -#ifdef CONFIG_GPIO_WAKEUP - gpionum = WAKEUP_GPIO_IDX; - sdio_wakeup_enable = 0; -#endif - -#ifdef CONFIG_PNO_SUPPORT - if (!ppwrpriv->wowlan_pno_enable) - magic_pkt = 1; -#endif - - if (psecpriv->dot11PrivacyAlgrthm == _WEP40_ || psecpriv->dot11PrivacyAlgrthm == _WEP104_) - hw_unicast = 1; - - DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); - - SET_H2CCMD_WOWLAN_FUNC_ENABLE(u1H2CWoWlanCtrlParm, bFuncEn); - SET_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(u1H2CWoWlanCtrlParm, 0); - SET_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(u1H2CWoWlanCtrlParm, magic_pkt); - SET_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(u1H2CWoWlanCtrlParm, hw_unicast); - SET_H2CCMD_WOWLAN_ALL_PKT_DROP(u1H2CWoWlanCtrlParm, 0); - SET_H2CCMD_WOWLAN_GPIO_ACTIVE(u1H2CWoWlanCtrlParm, gpio_high_active); - SET_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(u1H2CWoWlanCtrlParm, discont_wake); - SET_H2CCMD_WOWLAN_GPIONUM(u1H2CWoWlanCtrlParm, gpionum); - SET_H2CCMD_WOWLAN_DATAPIN_WAKE_UP(u1H2CWoWlanCtrlParm, sdio_wakeup_enable); - SET_H2CCMD_WOWLAN_GPIO_DURATION(u1H2CWoWlanCtrlParm, gpio_dur); - /* SET_H2CCMD_WOWLAN_GPIO_PULSE_EN(u1H2CWoWlanCtrlParm, 1); */ - SET_H2CCMD_WOWLAN_GPIO_PULSE_COUNT(u1H2CWoWlanCtrlParm, 0x09); - - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CWoWlanCtrlParm:", u1H2CWoWlanCtrlParm, H2C_WOWLAN_LEN); - - FillH2CCmd8723B(padapter, H2C_8723B_WOWLAN, H2C_WOWLAN_LEN, u1H2CWoWlanCtrlParm); -} - -static void rtl8723b_set_FwRemoteWakeCtrl_Cmd(struct adapter *padapter, u8 benable) -{ - u8 u1H2CRemoteWakeCtrlParm[H2C_REMOTE_WAKE_CTRL_LEN] = {0}; - struct security_priv *psecuritypriv = &(padapter->securitypriv); - struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter); - - DBG_871X("%s(): Enable =%d\n", __func__, benable); - - if (!ppwrpriv->wowlan_pno_enable) { - SET_H2CCMD_REMOTE_WAKECTRL_ENABLE(u1H2CRemoteWakeCtrlParm, benable); - SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, 1); -#ifdef CONFIG_GTK_OL - if (psecuritypriv->binstallKCK_KEK && - psecuritypriv->dot11PrivacyAlgrthm == _AES_) { - SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, 1); - } else { - DBG_871X("no kck or security is not AES\n"); - SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, 0); - } -#endif /* CONFIG_GTK_OL */ - - SET_H2CCMD_REMOTE_WAKE_CTRL_FW_UNICAST_EN(u1H2CRemoteWakeCtrlParm, 1); - - if ((psecuritypriv->dot11PrivacyAlgrthm == _AES_) || - (psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_)) - SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION(u1H2CRemoteWakeCtrlParm, 0); - else - SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION(u1H2CRemoteWakeCtrlParm, 1); - } -#ifdef CONFIG_PNO_SUPPORT - else { - SET_H2CCMD_REMOTE_WAKECTRL_ENABLE(u1H2CRemoteWakeCtrlParm, benable); - SET_H2CCMD_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, benable); - } -#endif - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CRemoteWakeCtrlParm:", u1H2CRemoteWakeCtrlParm, H2C_REMOTE_WAKE_CTRL_LEN); - FillH2CCmd8723B(padapter, H2C_8723B_REMOTE_WAKE_CTRL, - H2C_REMOTE_WAKE_CTRL_LEN, u1H2CRemoteWakeCtrlParm); -#ifdef CONFIG_PNO_SUPPORT - if (ppwrpriv->wowlan_pno_enable && !ppwrpriv->pno_in_resume) { - res = rtw_read8(padapter, REG_PNO_STATUS); - DBG_871X("cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", res); - while (!(res&BIT(7)) && count < 25) { - DBG_871X("[%d] cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", count, res); - res = rtw_read8(padapter, REG_PNO_STATUS); - count++; - msleep(2); - } - DBG_871X("cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", res); - } -#endif /* CONFIG_PNO_SUPPORT */ -} - -static void rtl8723b_set_FwAOACGlobalInfo_Cmd(struct adapter *padapter, u8 group_alg, u8 pairwise_alg) -{ - u8 u1H2CAOACGlobalInfoParm[H2C_AOAC_GLOBAL_INFO_LEN] = {0}; - - DBG_871X("%s(): group_alg =%d pairwise_alg =%d\n", __func__, group_alg, pairwise_alg); - - SET_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(u1H2CAOACGlobalInfoParm, pairwise_alg); - SET_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(u1H2CAOACGlobalInfoParm, group_alg); - - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CAOACGlobalInfoParm:", u1H2CAOACGlobalInfoParm, H2C_AOAC_GLOBAL_INFO_LEN); - - FillH2CCmd8723B(padapter, H2C_8723B_AOAC_GLOBAL_INFO, H2C_AOAC_GLOBAL_INFO_LEN, u1H2CAOACGlobalInfoParm); -} - -#ifdef CONFIG_PNO_SUPPORT -static void rtl8723b_set_FwScanOffloadInfo_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc, u8 enable) -{ - u8 u1H2CScanOffloadInfoParm[H2C_SCAN_OFFLOAD_CTRL_LEN] = {0}; - - DBG_871X("%s: loc_probe_packet:%d, loc_scan_info: %d loc_ssid_info:%d\n", - __func__, rsvdpageloc->LocProbePacket, rsvdpageloc->LocScanInfo, rsvdpageloc->LocSSIDInfo); - - SET_H2CCMD_AOAC_NLO_FUN_EN(u1H2CScanOffloadInfoParm, enable); - SET_H2CCMD_AOAC_RSVDPAGE_LOC_SCAN_INFO(u1H2CScanOffloadInfoParm, rsvdpageloc->LocScanInfo); - SET_H2CCMD_AOAC_RSVDPAGE_LOC_PROBE_PACKET(u1H2CScanOffloadInfoParm, rsvdpageloc->LocProbePacket); - SET_H2CCMD_AOAC_RSVDPAGE_LOC_SSID_INFO(u1H2CScanOffloadInfoParm, rsvdpageloc->LocSSIDInfo); - - RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CScanOffloadInfoParm:", u1H2CScanOffloadInfoParm, H2C_SCAN_OFFLOAD_CTRL_LEN); - FillH2CCmd8723B(padapter, H2C_8723B_D0_SCAN_OFFLOAD_INFO, H2C_SCAN_OFFLOAD_CTRL_LEN, u1H2CScanOffloadInfoParm); - - msleep(20); -} -#endif /* CONFIG_PNO_SUPPORT */ - -void rtl8723b_set_wowlan_cmd(struct adapter *padapter, u8 enable) -{ - struct security_priv *psecpriv = &padapter->securitypriv; - struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct sta_info *psta = NULL; - u8 pkt_type = 0; - - DBG_871X_LEVEL(_drv_always_, "+%s()+: enable =%d\n", __func__, enable); - if (enable) { - rtl8723b_set_FwAOACGlobalInfo_Cmd(padapter, psecpriv->dot118021XGrpPrivacy, psecpriv->dot11PrivacyAlgrthm); - - rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); /* RT_MEDIA_CONNECT will confuse in the future */ - - if (!(ppwrpriv->wowlan_pno_enable)) { - psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv)); - if (psta) - rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id); - } else - DBG_871X("%s(): Disconnected, no FwMediaStatusRpt CONNECT\n", __func__); - - msleep(2); - - if (!(ppwrpriv->wowlan_pno_enable)) { - rtl8723b_set_FwDisconDecision_cmd(padapter, enable); - msleep(2); - - if ((psecpriv->dot11PrivacyAlgrthm != _WEP40_) || (psecpriv->dot11PrivacyAlgrthm != _WEP104_)) - pkt_type = 1; - - rtl8723b_set_FwKeepAlive_cmd(padapter, enable, pkt_type); - msleep(2); - } - - rtl8723b_set_FwWoWlanCtrl_Cmd(padapter, enable); - msleep(2); - - rtl8723b_set_FwRemoteWakeCtrl_Cmd(padapter, enable); - } else { - rtl8723b_set_FwRemoteWakeCtrl_Cmd(padapter, enable); - msleep(2); - rtl8723b_set_FwWoWlanCtrl_Cmd(padapter, enable); - } - - DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__); -} -#endif /* CONFIG_WOWLAN */ - -#ifdef CONFIG_AP_WOWLAN -static void rtl8723b_set_FwAPWoWlanCtrl_Cmd(struct adapter *padapter, u8 bFuncEn) -{ - u8 u1H2CAPWoWlanCtrlParm[H2C_WOWLAN_LEN] = {0}; - u8 gpionum = 0, gpio_dur = 0; - u8 gpio_high_active = 1; /* 0: low active, 1: high active */ - u8 gpio_pulse = bFuncEn; -#ifdef CONFIG_GPIO_WAKEUP - gpionum = WAKEUP_GPIO_IDX; -#endif - - DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); - - if (bFuncEn) - gpio_dur = 16; - else - gpio_dur = 0; - - SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(u1H2CAPWoWlanCtrlParm, - gpionum); - SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(u1H2CAPWoWlanCtrlParm, - gpio_pulse); - SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(u1H2CAPWoWlanCtrlParm, - gpio_high_active); - SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(u1H2CAPWoWlanCtrlParm, - bFuncEn); - SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(u1H2CAPWoWlanCtrlParm, - gpio_dur); - - FillH2CCmd8723B(padapter, H2C_8723B_AP_WOW_GPIO_CTRL, - H2C_AP_WOW_GPIO_CTRL_LEN, u1H2CAPWoWlanCtrlParm); -} - -static void rtl8723b_set_Fw_AP_Offload_Cmd(struct adapter *padapter, u8 bFuncEn) -{ - u8 u1H2CAPOffloadCtrlParm[H2C_WOWLAN_LEN] = {0}; - - DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); - - SET_H2CCMD_AP_WOWLAN_EN(u1H2CAPOffloadCtrlParm, bFuncEn); - - FillH2CCmd8723B(padapter, H2C_8723B_AP_OFFLOAD, - H2C_AP_OFFLOAD_LEN, u1H2CAPOffloadCtrlParm); -} - -void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable) -{ - DBG_871X_LEVEL(_drv_always_, "+%s()+: enable =%d\n", __func__, enable); - if (enable) { - rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); - issue_beacon(padapter, 0); - } - - rtl8723b_set_FwAPWoWlanCtrl_Cmd(padapter, enable); - msleep(10); - rtl8723b_set_Fw_AP_Offload_Cmd(padapter, enable); - msleep(10); - DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__); -} -#endif /* CONFIG_AP_WOWLAN */ - /* * Description: Fill the reserved packets that FW will use to RSVD page. * Now we just send 4 types packet to rsvd page. @@ -1435,7 +520,6 @@ static void rtl8723b_set_FwRsvdPagePkt( struct xmit_priv *pxmitpriv; struct mlme_ext_priv *pmlmeext; struct mlme_ext_info *pmlmeinfo; - struct pwrctrl_priv *pwrctl; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; u32 BeaconLength = 0, PSPollLength = 0; u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0; @@ -1444,37 +528,22 @@ static void rtl8723b_set_FwRsvdPagePkt( u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; u16 BufIndex, PageSize = 128; u32 TotalPacketLen, MaxRsvdPageBufSize = 0; - RSVDPAGE_LOC RsvdPageLoc; -#ifdef CONFIG_WOWLAN - u32 ARPLegnth = 0, GTKLegnth = 0; - u8 currentip[4]; - u8 cur_dot11txpn[8]; -#ifdef CONFIG_GTK_OL - struct sta_priv *pstapriv = &padapter->stapriv; - struct sta_info *psta; - u8 kek[RTW_KEK_LEN]; - u8 kck[RTW_KCK_LEN]; -#endif -#endif - /* DBG_871X("%s---->\n", __func__); */ + struct rsvdpage_loc RsvdPageLoc; pxmitpriv = &padapter->xmitpriv; pmlmeext = &padapter->mlmeextpriv; pmlmeinfo = &pmlmeext->mlmext_info; - pwrctl = adapter_to_pwrctl(padapter); RsvdPageNum = BCNQ_PAGE_NUM_8723B + WOWLAN_PAGE_NUM_8723B; MaxRsvdPageBufSize = RsvdPageNum*PageSize; pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); - if (!pcmdframe) { - DBG_871X("%s: alloc ReservedPagePacket fail!\n", __func__); + if (!pcmdframe) return; - } ReservedPagePacket = pcmdframe->buf_addr; - memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); + memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc)); /* 3 (1) beacon */ BufIndex = TxDescOffset; @@ -1496,9 +565,6 @@ static void rtl8723b_set_FwRsvdPagePkt( ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength); rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, false); - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: PS-POLL %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (PSPollLength+TxDescLen)); */ - CurtPktPageNum = (u8)PageNum_128(TxDescLen + PSPollLength); TotalPageNum += CurtPktPageNum; @@ -1516,9 +582,6 @@ static void rtl8723b_set_FwRsvdPagePkt( ); rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, false); - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: NULL DATA %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (NullDataLength+TxDescLen)); */ - CurtPktPageNum = (u8)PageNum_128(TxDescLen + NullDataLength); TotalPageNum += CurtPktPageNum; @@ -1536,9 +599,6 @@ static void rtl8723b_set_FwRsvdPagePkt( ); rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, false); - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (QosNullLength+TxDescLen)); */ - CurtPktPageNum = (u8)PageNum_128(TxDescLen + QosNullLength); TotalPageNum += CurtPktPageNum; @@ -1556,215 +616,15 @@ static void rtl8723b_set_FwRsvdPagePkt( ); rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: BT QOS NULL DATA %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (BTQosNullLength+TxDescLen)); */ - CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); TotalPageNum += CurtPktPageNum; BufIndex += (CurtPktPageNum*PageSize); -#ifdef CONFIG_WOWLAN - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - /* if (pwrctl->wowlan_mode == true) { */ - /* BufIndex += (CurtPktPageNum*PageSize); */ - - /* 3(7) ARP RSP */ - rtw_get_current_ip_address(padapter, currentip); - RsvdPageLoc.LocArpRsp = TotalPageNum; - { - ConstructARPResponse( - padapter, - &ReservedPagePacket[BufIndex], - &ARPLegnth, - currentip - ); - rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ARPLegnth, false, false, true); - - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: ARP RSP %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (ARPLegnth+TxDescLen)); */ - - CurtPktPageNum = (u8)PageNum_128(TxDescLen + ARPLegnth); - } - TotalPageNum += CurtPktPageNum; - - BufIndex += (CurtPktPageNum*PageSize); - - /* 3(8) SEC IV */ - rtw_get_sec_iv(padapter, cur_dot11txpn, get_my_bssid(&pmlmeinfo->network)); - RsvdPageLoc.LocRemoteCtrlInfo = TotalPageNum; - memcpy(ReservedPagePacket+BufIndex-TxDescLen, cur_dot11txpn, _AES_IV_LEN_); - - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: SEC IV %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], _AES_IV_LEN_); */ - - CurtPktPageNum = (u8)PageNum_128(_AES_IV_LEN_); - - TotalPageNum += CurtPktPageNum; - -#ifdef CONFIG_GTK_OL - BufIndex += (CurtPktPageNum*PageSize); - - /* if the ap station info. exists, get the kek, kck from station info. */ - psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); - if (!psta) { - memset(kek, 0, RTW_KEK_LEN); - memset(kck, 0, RTW_KCK_LEN); - DBG_8192C("%s, KEK, KCK download rsvd page all zero\n", __func__); - } else { - memcpy(kek, psta->kek, RTW_KEK_LEN); - memcpy(kck, psta->kck, RTW_KCK_LEN); - } - - /* 3(9) KEK, KCK */ - RsvdPageLoc.LocGTKInfo = TotalPageNum; - memcpy(ReservedPagePacket+BufIndex-TxDescLen, kck, RTW_KCK_LEN); - memcpy(ReservedPagePacket+BufIndex-TxDescLen+RTW_KCK_LEN, kek, RTW_KEK_LEN); - - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: KEK KCK %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (TxDescLen + RTW_KCK_LEN + RTW_KEK_LEN)); */ - - CurtPktPageNum = (u8)PageNum_128(TxDescLen + RTW_KCK_LEN + RTW_KEK_LEN); - - TotalPageNum += CurtPktPageNum; - - BufIndex += (CurtPktPageNum*PageSize); - - /* 3(10) GTK Response */ - RsvdPageLoc.LocGTKRsp = TotalPageNum; - ConstructGTKResponse( - padapter, - &ReservedPagePacket[BufIndex], - >KLegnth - ); - - rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], GTKLegnth, false, false, true); - /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: GTK RSP %p %d\n", */ - /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (TxDescLen + GTKLegnth)); */ - - CurtPktPageNum = (u8)PageNum_128(TxDescLen + GTKLegnth); - - TotalPageNum += CurtPktPageNum; - - BufIndex += (CurtPktPageNum*PageSize); - - /* below page is empty for GTK extension memory */ - /* 3(11) GTK EXT MEM */ - RsvdPageLoc.LocGTKEXTMEM = TotalPageNum; - - CurtPktPageNum = 2; - - TotalPageNum += CurtPktPageNum; - - TotalPacketLen = BufIndex-TxDescLen + 256; /* extension memory for FW */ -#else - TotalPacketLen = BufIndex - TxDescLen + sizeof(union pn48); /* IV len */ -#endif /* CONFIG_GTK_OL */ - } else -#endif /* CONFIG_WOWLAN */ - { -#ifdef CONFIG_PNO_SUPPORT - if (!pwrctl->pno_in_resume && pwrctl->pno_inited) { - /* Probe Request */ - RsvdPageLoc.LocProbePacket = TotalPageNum; - ConstructProbeReq( - padapter, - &ReservedPagePacket[BufIndex], - &ProbeReqLength); - - rtl8723b_fill_fake_txdesc(padapter, - &ReservedPagePacket[BufIndex-TxDescLen], - ProbeReqLength, false, false, false); -#ifdef CONFIG_PNO_SET_DEBUG - { - int gj; - printk("probe req pkt =>\n"); - for (gj = 0; gj < ProbeReqLength+TxDescLen; gj++) { - printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen+gj]); - if ((gj+1)%8 == 0) - printk("\n"); - } - printk(" <=end\n"); - } -#endif - CurtPktPageNum = - (u8)PageNum_128(TxDescLen + ProbeReqLength); - - TotalPageNum += CurtPktPageNum; - - BufIndex += (CurtPktPageNum*PageSize); - - /* PNO INFO Page */ - RsvdPageLoc.LocPNOInfo = TotalPageNum; - ConstructPnoInfo(padapter, &ReservedPagePacket[BufIndex-TxDescLen], &PNOLength); -#ifdef CONFIG_PNO_SET_DEBUG - { - int gj; - printk("PNO pkt =>\n"); - for (gj = 0; gj < PNOLength; gj++) { - printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen+gj]); - if ((gj + 1)%8 == 0) - printk("\n"); - } - printk(" <=end\n"); - } -#endif - - CurtPktPageNum = (u8)PageNum_128(PNOLength); - TotalPageNum += CurtPktPageNum; - BufIndex += (CurtPktPageNum*PageSize); - - /* SSID List Page */ - RsvdPageLoc.LocSSIDInfo = TotalPageNum; - ConstructSSIDList(padapter, &ReservedPagePacket[BufIndex-TxDescLen], &SSIDLegnth); -#ifdef CONFIG_PNO_SET_DEBUG - { - int gj; - printk("SSID list pkt =>\n"); - for (gj = 0; gj < SSIDLegnth; gj++) { - printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen+gj]); - if ((gj + 1)%8 == 0) - printk("\n"); - } - printk(" <=end\n"); - } -#endif - CurtPktPageNum = (u8)PageNum_128(SSIDLegnth); - TotalPageNum += CurtPktPageNum; - BufIndex += (CurtPktPageNum*PageSize); - - /* Scan Info Page */ - RsvdPageLoc.LocScanInfo = TotalPageNum; - ConstructScanInfo(padapter, &ReservedPagePacket[BufIndex-TxDescLen], &ScanInfoLength); -#ifdef CONFIG_PNO_SET_DEBUG - { - int gj; - printk("Scan info pkt =>\n"); - for (gj = 0; gj < ScanInfoLength; gj++) { - printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen+gj]); - if ((gj + 1)%8 == 0) - printk("\n"); - } - printk(" <=end\n"); - } -#endif - CurtPktPageNum = (u8)PageNum_128(ScanInfoLength); - TotalPageNum += CurtPktPageNum; - BufIndex += (CurtPktPageNum*PageSize); - - TotalPacketLen = BufIndex + ScanInfoLength; - } else { - TotalPacketLen = BufIndex + BTQosNullLength; - } -#else /* CONFIG_PNO_SUPPORT */ - TotalPacketLen = BufIndex + BTQosNullLength; -#endif - } + TotalPacketLen = BufIndex + BTQosNullLength; if (TotalPacketLen > MaxRsvdPageBufSize) { - DBG_871X("%s(): ERROR: The rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", __func__, - TotalPacketLen, MaxRsvdPageBufSize); goto error; } else { /* update attribute */ @@ -1775,20 +635,11 @@ static void rtl8723b_set_FwRsvdPagePkt( dump_mgntframe_and_wait(padapter, pcmdframe, 100); } - DBG_871X("%s: Set RSVD page location to Fw , TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); if (check_fwstate(pmlmepriv, _FW_LINKED)) { rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); } else { rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); -#ifdef CONFIG_PNO_SUPPORT - if (pwrctl->pno_in_resume) - rtl8723b_set_FwScanOffloadInfo_cmd(padapter, - &RsvdPageLoc, 0); - else - rtl8723b_set_FwScanOffloadInfo_cmd(padapter, - &RsvdPageLoc, 1); -#endif } return; @@ -1797,134 +648,9 @@ error: rtw_free_xmitframe(pxmitpriv, pcmdframe); } -#ifdef CONFIG_AP_WOWLAN -/* - * Description: Fill the reserved packets that FW will use to RSVD page. - * Now we just send 2 types packet to rsvd page. (1)Beacon, (2)ProbeRsp. - * - * Input: bDLFinished - * - * false: At the first time we will send all the packets as a large packet to - * Hw, so we need to set the packet length to total length. - * - * true: At the second time, we should send the first packet (default:beacon) - * to Hw again and set the length in descriptor to the real beacon length. - */ -/* 2009.10.15 by tynli. */ -static void rtl8723b_set_AP_FwRsvdPagePkt( - struct adapter *padapter, bool bDLFinished -) -{ - struct hal_com_data *pHalData; - struct xmit_frame *pcmdframe; - struct pkt_attrib *pattrib; - struct xmit_priv *pxmitpriv; - struct mlme_ext_priv *pmlmeext; - struct mlme_ext_info *pmlmeinfo; - struct pwrctrl_priv *pwrctl; - u32 BeaconLength = 0, ProbeRspLength = 0; - u8 *ReservedPagePacket; - u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; - u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; - u8 currentip[4]; - u16 BufIndex, PageSize = 128; - u32 TotalPacketLen = 0, MaxRsvdPageBufSize = 0; - RSVDPAGE_LOC RsvdPageLoc; - - /* DBG_871X("%s---->\n", __func__); */ - DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d\n", - FUNC_ADPT_ARG(padapter), get_iface_type(padapter)); - - pHalData = GET_HAL_DATA(padapter); - pxmitpriv = &padapter->xmitpriv; - pmlmeext = &padapter->mlmeextpriv; - pmlmeinfo = &pmlmeext->mlmext_info; - pwrctl = adapter_to_pwrctl(padapter); - - RsvdPageNum = BCNQ_PAGE_NUM_8723B + AP_WOWLAN_PAGE_NUM_8723B; - MaxRsvdPageBufSize = RsvdPageNum*PageSize; - - pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); - if (!pcmdframe) { - DBG_871X("%s: alloc ReservedPagePacket fail!\n", __func__); - return; - } - - ReservedPagePacket = pcmdframe->buf_addr; - memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); - - /* 3 (1) beacon */ - BufIndex = TxDescOffset; - ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); - - /* When we count the first page size, we need to reserve description size for the RSVD */ - /* packet, it will be filled in front of the packet in TXPKTBUF. */ - CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); - /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ - if (CurtPktPageNum == 1) - CurtPktPageNum += 1; - TotalPageNum += CurtPktPageNum; - - BufIndex += (CurtPktPageNum*PageSize); - - /* 2 (4) probe response */ - RsvdPageLoc.LocProbeRsp = TotalPageNum; - - rtw_get_current_ip_address(padapter, currentip); - - ConstructProbeRsp( - padapter, - &ReservedPagePacket[BufIndex], - &ProbeRspLength, - currentip, - false); - rtl8723b_fill_fake_txdesc(padapter, - &ReservedPagePacket[BufIndex-TxDescLen], - ProbeRspLength, - false, false, false); - - DBG_871X("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", - __func__, &ReservedPagePacket[BufIndex-TxDescLen], - (ProbeRspLength+TxDescLen)); - - CurtPktPageNum = (u8)PageNum_128(TxDescLen + ProbeRspLength); - - TotalPageNum += CurtPktPageNum; - - BufIndex += (CurtPktPageNum*PageSize); - - TotalPacketLen = BufIndex + ProbeRspLength; - - if (TotalPacketLen > MaxRsvdPageBufSize) { - DBG_871X("%s(): ERROR: The rsvd page size is not enough \ - !!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", - __func__, TotalPacketLen, MaxRsvdPageBufSize); - goto error; - } else { - /* update attribute */ - pattrib = &pcmdframe->attrib; - update_mgntframe_attrib(padapter, pattrib); - pattrib->qsel = 0x10; - pattrib->pktlen = TotalPacketLen - TxDescOffset; - pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; - dump_mgntframe_and_wait(padapter, pcmdframe, 100); - } - - DBG_871X("%s: Set RSVD page location to Fw , TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); - rtl8723b_set_ap_wow_rsvdpage_cmd(padapter, &RsvdPageLoc); - - return; -error: - rtw_free_xmitframe(pxmitpriv, pcmdframe); -} -#endif /* CONFIG_AP_WOWLAN */ - void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); -#ifdef CONFIG_AP_WOWLAN - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); -#endif struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); bool bcn_valid = false; @@ -1932,9 +658,6 @@ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) u32 poll = 0; u8 val8; - DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d mstatus(%x)\n", - FUNC_ADPT_ARG(padapter), get_iface_type(padapter), mstatus); - if (mstatus == RT_MEDIA_CONNECT) { bool bRecover = false; u8 v8; @@ -1971,15 +694,8 @@ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) DLBcnCount = 0; poll = 0; do { -#ifdef CONFIG_AP_WOWLAN - if (pwrpriv->wowlan_ap_mode) - rtl8723b_set_AP_FwRsvdPagePkt(padapter, 0); - else - rtl8723b_set_FwRsvdPagePkt(padapter, 0); -#else /* download rsvd page. */ rtl8723b_set_FwRsvdPagePkt(padapter, 0); -#endif DLBcnCount++; do { yield(); @@ -1992,14 +708,9 @@ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) } while (!bcn_valid && DLBcnCount <= 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); if (padapter->bSurpriseRemoved || padapter->bDriverStopped) { - } else if (!bcn_valid) - DBG_871X("%s: 1 DL RSVD page failed! DLBcnCount:%u, poll:%u\n", - ADPT_ARG(padapter), DLBcnCount, poll); - else { + } else { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); pwrctl->fw_psmode_iface_id = padapter->iface_id; - DBG_871X("%s: 1 DL RSVD page success! DLBcnCount:%u, poll:%u\n", - ADPT_ARG(padapter), DLBcnCount, poll); } /* 2010.05.11. Added by tynli. */ @@ -2061,7 +772,6 @@ void rtl8723b_Add_RateATid( if (rssi_level != DM_RATR_STA_INIT) mask = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level); - DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x\n", __func__, mac_id, raid, bw, mask); rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, shortGI, mask); } @@ -2081,10 +791,6 @@ static void ConstructBtNullFunctionData( u32 pktlen; u8 bssid[ETH_ALEN]; - - DBG_871X("+" FUNC_ADPT_FMT ": qos =%d eosp =%d ps =%d\n", - FUNC_ADPT_ARG(padapter), bQoS, bEosp, bForcePowerSave); - pwlanhdr = (struct ieee80211_hdr *)pframe; if (!StaAddr) { @@ -2136,10 +842,7 @@ static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; u16 BufIndex, PageSize; u32 TotalPacketLen, MaxRsvdPageBufSize = 0; - RSVDPAGE_LOC RsvdPageLoc; - - -/* DBG_8192C("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); */ + struct rsvdpage_loc RsvdPageLoc; pxmitpriv = &padapter->xmitpriv; TxDescLen = TXDESC_SIZE; @@ -2150,13 +853,11 @@ static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) MaxRsvdPageBufSize = RsvdPageNum*PageSize; pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); - if (!pcmdframe) { - DBG_8192C("%s: alloc ReservedPagePacket fail!\n", __func__); + if (!pcmdframe) return; - } ReservedPagePacket = pcmdframe->buf_addr; - memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); + memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc)); /* 3 (1) beacon */ BufIndex = TxDescOffset; @@ -2194,11 +895,8 @@ static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) TotalPageNum += CurtPktPageNum; TotalPacketLen = BufIndex + BTQosNullLength; - if (TotalPacketLen > MaxRsvdPageBufSize) { - DBG_8192C(FUNC_ADPT_FMT ": ERROR: The rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", - FUNC_ADPT_ARG(padapter), TotalPacketLen, MaxRsvdPageBufSize); + if (TotalPacketLen > MaxRsvdPageBufSize) goto error; - } /* update attribute */ pattrib = &pcmdframe->attrib; @@ -2207,8 +905,6 @@ static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; dump_mgntframe_and_wait(padapter, pcmdframe, 100); -/* DBG_8192C(FUNC_ADPT_FMT ": Set RSVD page location to Fw, TotalPacketLen(%d), TotalPageNum(%d)\n", */ -/* FUNC_ADPT_ARG(padapter), TotalPacketLen, TotalPageNum); */ rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); @@ -2229,17 +925,6 @@ void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter) u32 poll = 0; u8 val8; - - DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d fw_state = 0x%08X\n", - FUNC_ADPT_ARG(padapter), get_iface_type(padapter), get_fwstate(&padapter->mlmepriv)); - -#ifdef DEBUG - if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == false) { - DBG_8192C(FUNC_ADPT_FMT ": [WARNING] not in AP mode!!\n", - FUNC_ADPT_ARG(padapter)); - } -#endif /* DEBUG */ - pHalData = GET_HAL_DATA(padapter); pmlmeext = &padapter->mlmeextpriv; pmlmeinfo = &pmlmeext->mlmext_info; @@ -2290,15 +975,6 @@ void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter) if (bcn_valid) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); pwrctl->fw_psmode_iface_id = padapter->iface_id; - DBG_8192C("%s: DL RSVD page success! DLBcnCount:%d, poll:%d\n", - ADPT_ARG(padapter), DLBcnCount, poll); - } else { - DBG_8192C("%s: DL RSVD page fail! DLBcnCount:%d, poll:%d\n", - ADPT_ARG(padapter), DLBcnCount, poll); - DBG_8192C("%s: DL RSVD page fail! bSurpriseRemoved =%d\n", - ADPT_ARG(padapter), padapter->bSurpriseRemoved); - DBG_8192C("%s: DL RSVD page fail! bDriverStopped =%d\n", - ADPT_ARG(padapter), padapter->bDriverStopped); } /* 2010.05.11. Added by tynli. */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c index 650fbedd34e828037d703b9a7bb1b52acc311247..23be025ceb5b4c02e872145a9b10a7eff1269583 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c @@ -25,7 +25,7 @@ static void Init_ODM_ComInfo_8723b(struct adapter *Adapter) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; struct dm_priv *pdmpriv = &pHalData->dmpriv; u8 cut_ver, fab_ver; @@ -44,7 +44,6 @@ static void Init_ODM_ComInfo_8723b(struct adapter *Adapter) fab_ver = ODM_TSMC; cut_ver = ODM_CUT_A; - DBG_871X("%s(): fab_ver =%d cut_ver =%d\n", __func__, fab_ver, cut_ver); ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_FAB_VER, fab_ver); ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_CUT_VER, cut_ver); ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(pHalData->VersionID)); @@ -74,7 +73,7 @@ static void Update_ODM_ComInfo_8723b(struct adapter *Adapter) struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter); struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(Adapter); struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; struct dm_priv *pdmpriv = &pHalData->dmpriv; int i; u8 zero = 0; @@ -91,9 +90,6 @@ static void Update_ODM_ComInfo_8723b(struct adapter *Adapter) | ODM_MAC_EDCA_TURBO | ODM_RF_TX_PWR_TRACK | ODM_RF_CALIBRATION -#ifdef CONFIG_ODM_ADAPTIVITY - | ODM_BB_ADAPTIVITY -#endif ; /* */ @@ -129,7 +125,7 @@ void rtl8723b_InitHalDm(struct adapter *Adapter) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); struct dm_priv *pdmpriv = &pHalData->dmpriv; - PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; pdmpriv->DM_Type = DM_Type_ByDriver; pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE; @@ -145,7 +141,7 @@ void rtl8723b_InitHalDm(struct adapter *Adapter) void rtl8723b_HalDmWatchDog(struct adapter *Adapter) { - bool bFwCurrentInPSMode = false; + bool fw_current_in_ps_mode = false; bool bFwPSAwake = true; u8 hw_init_completed = false; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); @@ -155,12 +151,12 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter) if (hw_init_completed == false) goto skip_dm; - bFwCurrentInPSMode = adapter_to_pwrctl(Adapter)->bFwCurrentInPSMode; + fw_current_in_ps_mode = adapter_to_pwrctl(Adapter)->fw_current_in_ps_mode; rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bFwPSAwake)); if ( (hw_init_completed == true) && - ((!bFwCurrentInPSMode) && bFwPSAwake) + ((!fw_current_in_ps_mode) && bFwPSAwake) ) { /* */ /* Calculate Tx/Rx statistics. */ @@ -203,12 +199,10 @@ void rtl8723b_hal_dm_in_lps(struct adapter *padapter) u32 PWDB_rssi = 0; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; struct sta_priv *pstapriv = &padapter->stapriv; struct sta_info *psta = NULL; - DBG_871X("%s, RSSI_Min =%d\n", __func__, pDM_Odm->RSSI_Min); - /* update IGI */ ODM_Write_DIG(pDM_Odm, pDM_Odm->RSSI_Min); @@ -229,8 +223,8 @@ void rtl8723b_HalDmWatchDog_in_LPS(struct adapter *Adapter) struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; struct dm_priv *pdmpriv = &pHalData->dmpriv; - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; - pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; struct sta_priv *pstapriv = &Adapter->stapriv; struct sta_info *psta = NULL; @@ -260,8 +254,6 @@ void rtl8723b_HalDmWatchDog_in_LPS(struct adapter *Adapter) pdmpriv->EntryMinUndecoratedSmoothedPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; - DBG_871X("CurIGValue =%d, EntryMinUndecoratedSmoothedPWDB = %d\n", pDM_DigTable->CurIGValue, pdmpriv->EntryMinUndecoratedSmoothedPWDB); - if (pdmpriv->EntryMinUndecoratedSmoothedPWDB <= 0) goto skip_lps_dm; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 84e963909283f9b0c1059ecc01962ab7f7b27d6b..082448557b53de9edd5040fd091eb0cb999f1acb 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -33,9 +33,6 @@ static void _FWDownloadEnable(struct adapter *padapter, bool enable) msleep(1); } while (count++ < 100); - if (count > 0) - DBG_871X("%s: !!!!!!!!Write 0x80 Fail!: count = %d\n", __func__, count); - /* 8051 reset */ tmp = rtw_read8(padapter, REG_MCUFWDL+2); rtw_write8(padapter, REG_MCUFWDL+2, tmp&0xf7); @@ -64,20 +61,6 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) blockCount_p1 = buffSize / blockSize_p1; remainSize_p1 = buffSize % blockSize_p1; - if (blockCount_p1) { - RT_TRACE( - _module_hal_init_c_, - _drv_notice_, - ( - "_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n", - buffSize, - blockSize_p1, - blockCount_p1, - remainSize_p1 - ) - ); - } - 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) { @@ -92,21 +75,6 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) blockCount_p2 = remainSize_p1/blockSize_p2; remainSize_p2 = remainSize_p1%blockSize_p2; - - if (blockCount_p2) { - RT_TRACE( - _module_hal_init_c_, - _drv_notice_, - ( - "_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n", - (buffSize-offset), - blockSize_p2, - blockCount_p2, - remainSize_p2 - ) - ); - } - } /* 3 Phase #3 */ @@ -115,10 +83,6 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) blockCount_p3 = remainSize_p2 / blockSize_p3; - RT_TRACE(_module_hal_init_c_, _drv_notice_, - ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n", - (buffSize-offset), blockSize_p3, blockCount_p3)); - for (i = 0; i < blockCount_p3; i++) { ret = rtw_write8(padapter, (FW_8723B_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); @@ -181,7 +145,6 @@ static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) goto exit; } } - RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n")); exit: return ret; @@ -213,8 +176,6 @@ void _8051Reset8723(struct adapter *padapter) cpu_rst = rtw_read8(padapter, REG_SYS_FUNC_EN+1); cpu_rst |= BIT(2); rtw_write8(padapter, REG_SYS_FUNC_EN+1, cpu_rst); - - DBG_8192C("%s: Finish\n", __func__); } u8 g_fwdl_chksum_fail; @@ -242,7 +203,6 @@ static s32 polling_fwdl_chksum( } if (g_fwdl_chksum_fail) { - DBG_871X("%s: fwdl test case: fwdl_chksum_fail\n", __func__); g_fwdl_chksum_fail--; goto exit; } @@ -250,14 +210,6 @@ static s32 polling_fwdl_chksum( ret = _SUCCESS; exit: - DBG_871X( - "%s: Checksum report %s! (%u, %dms), REG_MCUFWDL:0x%08x\n", - __func__, - (ret == _SUCCESS) ? "OK" : "Fail", - cnt, - jiffies_to_msecs(jiffies-start), - value32 - ); return ret; } @@ -292,7 +244,6 @@ static s32 _FWFreeToGo(struct adapter *adapter, u32 min_cnt, u32 timeout_ms) } if (g_fwdl_wintint_rdy_fail) { - DBG_871X("%s: fwdl test case: wintint_rdy_fail\n", __func__); g_fwdl_wintint_rdy_fail--; goto exit; } @@ -300,14 +251,6 @@ static s32 _FWFreeToGo(struct adapter *adapter, u32 min_cnt, u32 timeout_ms) ret = _SUCCESS; exit: - DBG_871X( - "%s: Polling FW ready %s! (%u, %dms), REG_MCUFWDL:0x%08x\n", - __func__, - (ret == _SUCCESS) ? "OK" : "Fail", - cnt, - jiffies_to_msecs(jiffies-start), - value32 - ); return ret; } @@ -334,10 +277,8 @@ void rtl8723b_FirmwareSelfReset(struct adapter *padapter) udelay(50); u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); } - RT_TRACE(_module_hal_init_c_, _drv_notice_, ("-%s: 8051 reset success (%d)\n", __func__, Delay)); if (Delay == 0) { - RT_TRACE(_module_hal_init_c_, _drv_notice_, ("%s: Force 8051 reset!!!\n", __func__)); /* force firmware reset */ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2)); @@ -368,10 +309,6 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; u8 tmp_ps; - RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__)); -#ifdef CONFIG_WOWLAN - RT_TRACE(_module_hal_init_c_, _drv_notice_, ("+%s, bUsedWoWLANFw:%d\n", __func__, bUsedWoWLANFw)); -#endif pFirmware = kzalloc(sizeof(struct rt_firmware), GFP_KERNEL); if (!pFirmware) return _FAIL; @@ -388,17 +325,10 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) /* 2. read power_state = 0xA0[1:0] */ tmp_ps = rtw_read8(padapter, 0xa0); tmp_ps &= 0x03; - if (tmp_ps != 0x01) { - DBG_871X(FUNC_ADPT_FMT" tmp_ps =%x\n", FUNC_ADPT_ARG(padapter), tmp_ps); + if (tmp_ps != 0x01) pdbgpriv->dbg_downloadfw_pwr_state_cnt++; - } -#ifdef CONFIG_WOWLAN - if (bUsedWoWLANFw) - fwfilepath = "rtlwifi/rtl8723bs_wowlan.bin"; - else -#endif /* CONFIG_WOWLAN */ - fwfilepath = "rtlwifi/rtl8723bs_nic.bin"; + fwfilepath = "rtlwifi/rtl8723bs_nic.bin"; pr_info("rtl8723bs: acquire FW from file:%s\n", fwfilepath); @@ -417,11 +347,6 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) if (fw->size > FW_8723B_SIZE) { rtStatus = _FAIL; - RT_TRACE( - _module_hal_init_c_, - _drv_err_, - ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE) - ); goto exit; } @@ -435,7 +360,9 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) release_firmware(fw); if (pFirmware->fw_length > FW_8723B_SIZE) { rtStatus = _FAIL; - DBG_871X_LEVEL(_drv_emerg_, "Firmware size:%u exceed %u\n", pFirmware->fw_length, FW_8723B_SIZE); + netdev_emerg(padapter->pnetdev, + "Firmware size:%u exceed %u\n", + pFirmware->fw_length, FW_8723B_SIZE); goto release_fw1; } @@ -449,20 +376,7 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) pHalData->FirmwareSubVersion = le16_to_cpu(pFwHdr->subversion); pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->signature); - DBG_871X( - "%s: fw_ver =%x fw_subver =%04x sig = 0x%x, Month =%02x, Date =%02x, Hour =%02x, Minute =%02x\n", - __func__, - pHalData->FirmwareVersion, - pHalData->FirmwareSubVersion, - pHalData->FirmwareSignature, - pFwHdr->month, - pFwHdr->date, - pFwHdr->hour, - pFwHdr->minute - ); - if (IS_FW_HEADER_EXIST_8723B(pFwHdr)) { - DBG_871X("%s(): Shift for fw header!\n", __func__); /* Shift 32 bytes for FW header */ pFirmwareBuf = pFirmwareBuf + 32; FirmwareLen = FirmwareLen - 32; @@ -502,19 +416,12 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) goto fwdl_stat; fwdl_stat: - DBG_871X( - "FWDL %s. write_fw:%u, %dms\n", - (rtStatus == _SUCCESS)?"success":"fail", - write_fw, - jiffies_to_msecs(jiffies - fwdl_start_time) - ); exit: kfree(pFirmware->fw_buffer_sz); kfree(pFirmware); release_fw1: kfree(pBTFirmware); - DBG_871X(" <=== rtl8723b_FirmwareDownload()\n"); return rtStatus; } @@ -523,7 +430,7 @@ void rtl8723b_InitializeFirmwareVars(struct adapter *padapter) struct hal_com_data *pHalData = GET_HAL_DATA(padapter); /* Init Fw LPS related. */ - adapter_to_pwrctl(padapter)->bFwCurrentInPSMode = false; + adapter_to_pwrctl(padapter)->fw_current_in_ps_mode = false; /* Init H2C cmd. */ rtw_write8(padapter, REG_HMETFR, 0x0f); @@ -535,39 +442,6 @@ void rtl8723b_InitializeFirmwareVars(struct adapter *padapter) /* pHalData->H2CStopInsertQueue = false; */ } -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -/* */ - -/* */ -/* Description: Prepare some information to Fw for WoWLAN. */ -/* (1) Download wowlan Fw. */ -/* (2) Download RSVD page packets. */ -/* (3) Enable AP offload if needed. */ -/* */ -/* 2011.04.12 by tynli. */ -/* */ -void SetFwRelatedForWoWLAN8723b( - struct adapter *padapter, u8 bHostIsGoingtoSleep -) -{ - int status = _FAIL; - /* */ - /* 1. Before WoWLAN we need to re-download WoWLAN Fw. */ - /* */ - status = rtl8723b_FirmwareDownload(padapter, bHostIsGoingtoSleep); - if (status != _SUCCESS) { - DBG_871X("SetFwRelatedForWoWLAN8723b(): Re-Download Firmware failed!!\n"); - return; - } else { - DBG_871X("SetFwRelatedForWoWLAN8723b(): Re-Download Firmware Success !!\n"); - } - /* */ - /* 2. Re-Init the variables about Fw related setting. */ - /* */ - rtl8723b_InitializeFirmwareVars(padapter); -} -#endif /* CONFIG_WOWLAN */ - static void rtl8723b_free_hal_data(struct adapter *padapter) { } @@ -583,11 +457,10 @@ static u8 hal_EfuseSwitchToBank( u32 value32 = 0; #ifdef HAL_EFUSE_MEMORY struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; #endif - DBG_8192C("%s: Efuse switch bank to %d\n", __func__, bank); if (bPseudoTest) { #ifdef HAL_EFUSE_MEMORY pEfuseHal->fakeEfuseBank = bank; @@ -807,14 +680,6 @@ static void Hal_EfusePowerSwitch( mdelay(10); } while (1); - - if (count >= 100) { - DBG_8192C(FUNC_ADPT_FMT ": Leave SDIO local register suspend fail! Local 0x86 =%#X\n", - FUNC_ADPT_ARG(padapter), tempval); - } else { - DBG_8192C(FUNC_ADPT_FMT ": Leave SDIO local register suspend OK! Local 0x86 =%#X\n", - FUNC_ADPT_ARG(padapter), tempval); - } } rtw_write8(padapter, REG_EFUSE_ACCESS_8723, EFUSE_ACCESS_ON_8723); @@ -864,7 +729,7 @@ static void hal_ReadEFuse_WiFi( { #ifdef HAL_EFUSE_MEMORY struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; #endif u8 *efuseTbl = NULL; u16 eFuse_Addr = 0; @@ -873,57 +738,32 @@ static void hal_ReadEFuse_WiFi( u16 i, total, used; u8 efuse_usage = 0; - /* DBG_871X("YJ: ====>%s():_offset =%d _size_byte =%d bPseudoTest =%d\n", __func__, _offset, _size_byte, bPseudoTest); */ /* */ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ /* */ - if ((_offset+_size_byte) > EFUSE_MAX_MAP_LEN) { - DBG_8192C("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __func__, _offset, _size_byte); + if ((_offset + _size_byte) > EFUSE_MAX_MAP_LEN) return; - } efuseTbl = rtw_malloc(EFUSE_MAX_MAP_LEN); - if (!efuseTbl) { - DBG_8192C("%s: alloc efuseTbl fail!\n", __func__); + if (!efuseTbl) return; - } + /* 0xff will be efuse default value instead of 0x00. */ memset(efuseTbl, 0xFF, EFUSE_MAX_MAP_LEN); - -#ifdef DEBUG -if (0) { - for (i = 0; i < 256; i++) - efuse_OneByteRead(padapter, i, &efuseTbl[i], false); - DBG_871X("Efuse Content:\n"); - for (i = 0; i < 256; i++) { - if (i % 16 == 0) - printk("\n"); - printk("%02X ", efuseTbl[i]); - } - printk("\n"); -} -#endif - - /* switch bank back to bank 0 for later BT and wifi use. */ hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); - if (efuseHeader == 0xFF) { - DBG_8192C("%s: data end at address =%#x\n", __func__, eFuse_Addr-1); + if (efuseHeader == 0xFF) break; - } - /* DBG_8192C("%s: efuse[0x%X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseHeader); */ /* Check PG header for section num. */ if (EXT_HEADER(efuseHeader)) { /* extended header */ offset = GET_HDR_OFFSET_2_0(efuseHeader); - /* DBG_8192C("%s: extended header offset = 0x%X\n", __func__, offset); */ efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); - /* DBG_8192C("%s: efuse[0x%X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseExtHdr); */ if (ALL_WORDS_DISABLED(efuseExtHdr)) continue; @@ -933,29 +773,24 @@ if (0) { offset = ((efuseHeader >> 4) & 0x0f); wden = (efuseHeader & 0x0f); } - /* DBG_8192C("%s: Offset =%d Worden = 0x%X\n", __func__, offset, wden); */ if (offset < EFUSE_MAX_SECTION_8723B) { u16 addr; /* Get word enable value from PG header */ -/* DBG_8192C("%s: Offset =%d Worden = 0x%X\n", __func__, offset, wden); */ addr = offset * PGPKT_DATA_SIZE; for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ if (!(wden & (0x01<<i))) { efuse_OneByteRead(padapter, eFuse_Addr++, &efuseData, bPseudoTest); -/* DBG_8192C("%s: efuse[%#X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseData); */ efuseTbl[addr] = efuseData; efuse_OneByteRead(padapter, eFuse_Addr++, &efuseData, bPseudoTest); -/* DBG_8192C("%s: efuse[%#X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseData); */ efuseTbl[addr+1] = efuseData; } addr += 2; } } else { - DBG_8192C(KERN_ERR "%s: offset(%d) is illegal!!\n", __func__, offset); eFuse_Addr += Efuse_CalculateWordCnts(wden)*2; } } @@ -964,17 +799,6 @@ if (0) { for (i = 0; i < _size_byte; i++) pbuf[i] = efuseTbl[_offset+i]; -#ifdef DEBUG -if (1) { - DBG_871X("Efuse Realmap:\n"); - for (i = 0; i < _size_byte; i++) { - if (i % 16 == 0) - printk("\n"); - printk("%02X ", pbuf[i]); - } - printk("\n"); -} -#endif /* Calculate Efuse utilization */ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, bPseudoTest); used = eFuse_Addr - 1; @@ -1003,7 +827,7 @@ static void hal_ReadEFuse_BT( { #ifdef HAL_EFUSE_MEMORY struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; #endif u8 *efuseTbl; u8 bank; @@ -1017,26 +841,21 @@ static void hal_ReadEFuse_BT( /* */ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ /* */ - if ((_offset+_size_byte) > EFUSE_BT_MAP_LEN) { - DBG_8192C("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __func__, _offset, _size_byte); + if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) return; - } efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN); - if (!efuseTbl) { - DBG_8192C("%s: efuseTbl malloc fail!\n", __func__); + if (!efuseTbl) return; - } + /* 0xff will be efuse default value instead of 0x00. */ memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, bPseudoTest); for (bank = 1; bank < 3; bank++) { /* 8723b Max bake 0~2 */ - if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) { - DBG_8192C("%s: hal_EfuseSwitchToBank Fail!!\n", __func__); + if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) goto exit; - } eFuse_Addr = 0; @@ -1044,15 +863,12 @@ static void hal_ReadEFuse_BT( efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); if (efuseHeader == 0xFF) break; - DBG_8192C("%s: efuse[%#X]= 0x%02x (header)\n", __func__, (((bank-1)*EFUSE_REAL_CONTENT_LEN_8723B)+eFuse_Addr-1), efuseHeader); /* Check PG header for section num. */ if (EXT_HEADER(efuseHeader)) { /* extended header */ offset = GET_HDR_OFFSET_2_0(efuseHeader); - DBG_8192C("%s: extended header offset_2_0 = 0x%X\n", __func__, offset); efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); - DBG_8192C("%s: efuse[%#X]= 0x%02x (ext header)\n", __func__, (((bank-1)*EFUSE_REAL_CONTENT_LEN_8723B)+eFuse_Addr-1), efuseExtHdr); if (ALL_WORDS_DISABLED(efuseExtHdr)) continue; @@ -1067,33 +883,26 @@ static void hal_ReadEFuse_BT( if (offset < EFUSE_BT_MAX_SECTION) { u16 addr; - /* Get word enable value from PG header */ - DBG_8192C("%s: Offset =%d Worden =%#X\n", __func__, offset, wden); - addr = offset * PGPKT_DATA_SIZE; for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ if (!(wden & (0x01<<i))) { efuse_OneByteRead(padapter, eFuse_Addr++, &efuseData, bPseudoTest); - DBG_8192C("%s: efuse[%#X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseData); efuseTbl[addr] = efuseData; efuse_OneByteRead(padapter, eFuse_Addr++, &efuseData, bPseudoTest); - DBG_8192C("%s: efuse[%#X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseData); efuseTbl[addr+1] = efuseData; } addr += 2; } } else { - DBG_8192C("%s: offset(%d) is illegal!!\n", __func__, offset); eFuse_Addr += Efuse_CalculateWordCnts(wden)*2; } } - if ((eFuse_Addr-1) < total) { - DBG_8192C("%s: bank(%d) data end at %#x\n", __func__, bank, eFuse_Addr-1); + if ((eFuse_Addr - 1) < total) break; - } + } /* switch bank back to bank 0 for later BT and wifi use. */ @@ -1108,7 +917,6 @@ static void hal_ReadEFuse_BT( /* */ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, bPseudoTest); used = (EFUSE_BT_REAL_BANK_CONTENT_LEN*(bank-1)) + eFuse_Addr - 1; - DBG_8192C("%s: bank(%d) data end at %#x , used =%d\n", __func__, bank, eFuse_Addr-1, used); efuse_usage = (u8)((used*100)/total); if (bPseudoTest) { #ifdef HAL_EFUSE_MEMORY @@ -1146,7 +954,7 @@ static u16 hal_EfuseGetCurrentSize_WiFi( { #ifdef HAL_EFUSE_MEMORY struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; #endif u16 efuse_addr = 0; u16 start_addr = 0; /* for debug */ @@ -1165,25 +973,20 @@ static u16 hal_EfuseGetCurrentSize_WiFi( rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); start_addr = efuse_addr; - DBG_8192C("%s: start_efuse_addr = 0x%X\n", __func__, efuse_addr); /* switch bank back to bank 0 for later BT and wifi use. */ hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); count = 0; while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { - if (efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) == false) { - DBG_8192C(KERN_ERR "%s: efuse_OneByteRead Fail! addr = 0x%X !!\n", __func__, efuse_addr); + if (efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) == false) goto error; - } if (efuse_data == 0xFF) break; if ((start_addr != 0) && (efuse_addr == start_addr)) { count++; - DBG_8192C(FUNC_ADPT_FMT ": [WARNING] efuse raw 0x%X = 0x%02X not 0xFF!!(%d times)\n", - FUNC_ADPT_ARG(padapter), efuse_addr, efuse_data, count); efuse_data = 0xFF; if (count < 4) { @@ -1235,7 +1038,6 @@ error: EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr, bPseudoTest); exit: - DBG_8192C("%s: CurrentSize =%d\n", __func__, efuse_addr); return efuse_addr; } @@ -1244,7 +1046,7 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) { #ifdef HAL_EFUSE_MEMORY struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; #endif u16 btusedbytes; u16 efuse_addr; @@ -1265,16 +1067,12 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) efuse_addr = (u16)((btusedbytes%EFUSE_BT_REAL_BANK_CONTENT_LEN)); startBank = (u8)(1+(btusedbytes/EFUSE_BT_REAL_BANK_CONTENT_LEN)); - DBG_8192C("%s: start from bank =%d addr = 0x%X\n", __func__, startBank, efuse_addr); - EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2, bPseudoTest); for (bank = startBank; bank < 3; bank++) { - if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) { - DBG_8192C(KERN_ERR "%s: switch bank(%d) Fail!!\n", __func__, bank); + if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) /* bank = EFUSE_MAX_BANK; */ break; - } /* only when bank is switched we have to reset the efuse_addr. */ if (bank != startBank) @@ -1282,12 +1080,10 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) #if 1 while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { - if (efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) == false) { - DBG_8192C(KERN_ERR "%s: efuse_OneByteRead Fail! addr = 0x%X !!\n", __func__, efuse_addr); + if (efuse_OneByteRead(padapter, efuse_addr, + &efuse_data, bPseudoTest) == false) /* bank = EFUSE_MAX_BANK; */ break; - } - DBG_8192C("%s: efuse_OneByteRead ! addr = 0x%X !efuse_data = 0x%X! bank =%d\n", __func__, efuse_addr, efuse_data, bank); if (efuse_data == 0xFF) break; @@ -1296,7 +1092,6 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) hoffset = GET_HDR_OFFSET_2_0(efuse_data); efuse_addr++; efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); - DBG_8192C("%s: efuse_OneByteRead EXT_HEADER ! addr = 0x%X !efuse_data = 0x%X! bank =%d\n", __func__, efuse_addr, efuse_data, bank); if (ALL_WORDS_DISABLED(efuse_data)) { efuse_addr++; @@ -1311,9 +1106,6 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) hworden = efuse_data & 0x0F; } - DBG_8192C(FUNC_ADPT_FMT": Offset =%d Worden =%#X\n", - FUNC_ADPT_ARG(padapter), hoffset, hworden); - word_cnts = Efuse_CalculateWordCnts(hworden); /* read next header */ efuse_addr += (word_cnts*2)+1; @@ -1363,7 +1155,6 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) /* RT_DISP(FEEPROM, EFUSE_PG, ("Hal_EfuseGetCurrentSize_BT92C(), already use %u bytes\n", pEfuseHal->BTEfuseUsedBytes)); */ } - DBG_8192C("%s: CurrentSize =%d\n", __func__, retU2); return retU2; } @@ -1394,8 +1185,6 @@ static u8 Hal_EfuseWordEnableDataWrite( u8 badworden = 0x0F; u8 tmpdata[PGPKT_DATA_SIZE]; - -/* DBG_8192C("%s: efuse_addr =%#x word_en =%#x\n", __func__, efuse_addr, word_en); */ memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); if (!(word_en & BIT(0))) { @@ -1467,10 +1256,8 @@ static s32 Hal_EfusePgPacketRead( return false; EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, &max_section, bPseudoTest); - if (offset > max_section) { - DBG_8192C("%s: Packet offset(%d) is illegal(>%d)!\n", __func__, offset, max_section); + if (offset > max_section) return false; - } memset(data, 0xFF, PGPKT_DATA_SIZE); ret = true; @@ -1492,10 +1279,8 @@ static s32 Hal_EfusePgPacketRead( 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)) { - DBG_8192C("%s: Error!! All words disabled!\n", __func__); + if (ALL_WORDS_DISABLED(efuse_data)) continue; - } hoffset |= ((efuse_data & 0xF0) >> 1); hworden = efuse_data & 0x0F; @@ -1509,11 +1294,9 @@ static s32 Hal_EfusePgPacketRead( /* Check word enable condition in the section */ if (!(hworden & (0x01<<i))) { efuse_OneByteRead(padapter, efuse_addr++, &efuse_data, bPseudoTest); -/* DBG_8192C("%s: efuse[%#X]= 0x%02X\n", __func__, efuse_addr+tmpidx, efuse_data); */ data[i*2] = efuse_data; efuse_OneByteRead(padapter, efuse_addr++, &efuse_data, bPseudoTest); -/* DBG_8192C("%s: efuse[%#X]= 0x%02X\n", __func__, efuse_addr+tmpidx, efuse_data); */ data[(i*2)+1] = efuse_data; } } @@ -1535,13 +1318,11 @@ static u8 hal_EfusePgCheckAvailableAddr( EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &max_available, bPseudoTest); -/* DBG_8192C("%s: max_available =%d\n", __func__, max_available); */ current_size = Efuse_GetCurrentSize(padapter, efuseType, bPseudoTest); - if (current_size >= max_available) { - DBG_8192C("%s: Error!! current_size(%d)>max_available(%d)\n", __func__, current_size, max_available); + if (current_size >= max_available) return false; - } + return true; } @@ -1549,7 +1330,7 @@ static void hal_EfuseConstructPGPkt( u8 offset, u8 word_en, u8 *pData, - PPGPKT_STRUCT pTargetPkt + struct pgpkt_struct *pTargetPkt ) { memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); @@ -1563,12 +1344,12 @@ static u8 hal_EfusePartialWriteCheck( struct adapter *padapter, u8 efuseType, u16 *pAddr, - PPGPKT_STRUCT pTargetPkt, + struct pgpkt_struct *pTargetPkt, u8 bPseudoTest ) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; u8 bRet = false; u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; u8 efuse_data = 0; @@ -1596,20 +1377,16 @@ static u8 hal_EfusePartialWriteCheck( rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&startAddr); } startAddr %= efuse_max; - DBG_8192C("%s: startAddr =%#X\n", __func__, startAddr); while (1) { if (startAddr >= efuse_max_available_len) { bRet = false; - DBG_8192C("%s: startAddr(%d) >= efuse_max_available_len(%d)\n", __func__, startAddr, efuse_max_available_len); break; } if (efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { #if 1 bRet = false; - DBG_8192C("%s: Something Wrong! last bytes(%#X = 0x%02X) is not 0xFF\n", - __func__, startAddr, efuse_data); break; #else if (EXT_HEADER(efuse_data)) { @@ -1617,7 +1394,6 @@ static u8 hal_EfusePartialWriteCheck( startAddr++; efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest); if (ALL_WORDS_DISABLED(efuse_data)) { - DBG_8192C("%s: Error condition, all words disabled!", __func__); bRet = false; break; } else { @@ -1638,7 +1414,6 @@ static u8 hal_EfusePartialWriteCheck( (hal_EfuseCheckIfDatafollowed(padapter, curPkt.word_cnts, startAddr+1, bPseudoTest) == false) && wordEnMatched(pTargetPkt, &curPkt, &matched_wden) == true ) { - DBG_8192C("%s: Need to partial write data by the previous wrote header\n", __func__); /* Here to write partial data */ badworden = Efuse_WordEnableDataWrite(padapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest); if (badworden != 0x0F) { @@ -1668,7 +1443,6 @@ static u8 hal_EfusePartialWriteCheck( } else { /* not used header, 0xff */ *pAddr = startAddr; -/* DBG_8192C("%s: Started from unused header offset =%d\n", __func__, startAddr)); */ bRet = true; break; } @@ -1681,7 +1455,7 @@ static u8 hal_EfusePgPacketWrite1ByteHeader( struct adapter *padapter, u8 efuseType, u16 *pAddr, - PPGPKT_STRUCT pTargetPkt, + struct pgpkt_struct *pTargetPkt, u8 bPseudoTest ) { @@ -1689,8 +1463,6 @@ static u8 hal_EfusePgPacketWrite1ByteHeader( u16 efuse_addr = *pAddr; u8 repeatcnt = 0; - -/* DBG_8192C("%s\n", __func__); */ pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; do { @@ -1698,16 +1470,13 @@ static u8 hal_EfusePgPacketWrite1ByteHeader( efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); if (tmp_header != 0xFF) break; - if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { - DBG_8192C("%s: Repeat over limit for pg_header!!\n", __func__); + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) return false; - } + } while (1); - if (tmp_header != pg_header) { - DBG_8192C(KERN_ERR "%s: PG Header Fail!!(pg = 0x%02X read = 0x%02X)\n", __func__, pg_header, tmp_header); + if (tmp_header != pg_header) return false; - } *pAddr = efuse_addr; @@ -1718,7 +1487,7 @@ static u8 hal_EfusePgPacketWrite2ByteHeader( struct adapter *padapter, u8 efuseType, u16 *pAddr, - PPGPKT_STRUCT pTargetPkt, + struct pgpkt_struct *pTargetPkt, u8 bPseudoTest ) { @@ -1726,35 +1495,26 @@ static u8 hal_EfusePgPacketWrite2ByteHeader( u8 pg_header = 0, tmp_header = 0; u8 repeatcnt = 0; - -/* DBG_8192C("%s\n", __func__); */ EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &efuse_max_available_len, bPseudoTest); efuse_addr = *pAddr; - if (efuse_addr >= efuse_max_available_len) { - DBG_8192C("%s: addr(%d) over available (%d)!!\n", __func__, - efuse_addr, efuse_max_available_len); + if (efuse_addr >= efuse_max_available_len) return false; - } pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; -/* DBG_8192C("%s: pg_header = 0x%x\n", __func__, pg_header); */ 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_) { - DBG_8192C("%s: Repeat over limit for pg_header!!\n", __func__); + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) return false; - } + } while (1); - if (tmp_header != pg_header) { - DBG_8192C(KERN_ERR "%s: PG Header Fail!!(pg = 0x%02X read = 0x%02X)\n", __func__, pg_header, tmp_header); + if (tmp_header != pg_header) return false; - } /* to write ext_header */ efuse_addr++; @@ -1765,16 +1525,13 @@ static u8 hal_EfusePgPacketWrite2ByteHeader( efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); if (tmp_header != 0xFF) break; - if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { - DBG_8192C("%s: Repeat over limit for ext_header!!\n", __func__); + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) return false; - } + } while (1); - if (tmp_header != pg_header) { /* offset PG fail */ - DBG_8192C(KERN_ERR "%s: PG EXT Header Fail!!(pg = 0x%02X read = 0x%02X)\n", __func__, pg_header, tmp_header); + if (tmp_header != pg_header) /* offset PG fail */ return false; - } *pAddr = efuse_addr; @@ -1785,7 +1542,7 @@ static u8 hal_EfusePgPacketWriteHeader( struct adapter *padapter, u8 efuseType, u16 *pAddr, - PPGPKT_STRUCT pTargetPkt, + struct pgpkt_struct *pTargetPkt, u8 bPseudoTest ) { @@ -1803,7 +1560,7 @@ static u8 hal_EfusePgPacketWriteData( struct adapter *padapter, u8 efuseType, u16 *pAddr, - PPGPKT_STRUCT pTargetPkt, + struct pgpkt_struct *pTargetPkt, u8 bPseudoTest ) { @@ -1813,12 +1570,9 @@ static u8 hal_EfusePgPacketWriteData( efuse_addr = *pAddr; badworden = Efuse_WordEnableDataWrite(padapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); - if (badworden != 0x0F) { - DBG_8192C("%s: Fail!!\n", __func__); + if (badworden != 0x0F) return false; - } -/* DBG_8192C("%s: ok\n", __func__); */ return true; } @@ -1830,7 +1584,7 @@ static s32 Hal_EfusePgPacketWrite( bool bPseudoTest ) { - PGPKT_STRUCT targetPkt; + struct pgpkt_struct targetPkt; u16 startAddr = 0; u8 efuseType = EFUSE_WIFI; @@ -1859,7 +1613,7 @@ static bool Hal_EfusePgPacketWrite_BT( bool bPseudoTest ) { - PGPKT_STRUCT targetPkt; + struct pgpkt_struct targetPkt; u16 startAddr = 0; u8 efuseType = EFUSE_BT; @@ -1880,10 +1634,10 @@ static bool Hal_EfusePgPacketWrite_BT( return true; } -static HAL_VERSION ReadChipVersion8723B(struct adapter *padapter) +static struct hal_version ReadChipVersion8723B(struct adapter *padapter) { u32 value32; - HAL_VERSION ChipVersion; + struct hal_version ChipVersion; struct hal_com_data *pHalData; /* YJ, TODO, move read chip type here */ @@ -1920,8 +1674,6 @@ static HAL_VERSION ReadChipVersion8723B(struct adapter *padapter) else pHalData->rf_type = RF_1T1R; - MSG_8192C("RF_Type is %x!!\n", pHalData->rf_type); - return ChipVersion; } @@ -1993,12 +1745,6 @@ static void ResumeTxBeacon(struct adapter *padapter) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - - /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ - /* which should be read from register to a global variable. */ - - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+ResumeTxBeacon\n")); - pHalData->RegFwHwTxQCtrl |= BIT(6); rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0xff); @@ -2010,12 +1756,6 @@ static void StopTxBeacon(struct adapter *padapter) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - - /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ - /* which should be read from register to a global variable. */ - - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+StopTxBeacon\n")); - pHalData->RegFwHwTxQCtrl &= ~BIT(6); rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0x64); @@ -2094,7 +1834,7 @@ static void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) static void rtl8723b_GetHalODMVar( struct adapter *Adapter, - enum HAL_ODM_VARIABLE eVariable, + enum hal_odm_variable eVariable, void *pValue1, void *pValue2 ) @@ -2104,7 +1844,7 @@ static void rtl8723b_GetHalODMVar( static void rtl8723b_SetHalODMVar( struct adapter *Adapter, - enum HAL_ODM_VARIABLE eVariable, + enum hal_odm_variable eVariable, void *pValue1, bool bSet ) @@ -2114,13 +1854,10 @@ static void rtl8723b_SetHalODMVar( static void hal_notch_filter_8723b(struct adapter *adapter, bool enable) { - if (enable) { - DBG_871X("Enable notch filter\n"); + if (enable) rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1); - } else { - DBG_871X("Disable notch filter\n"); + else 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) @@ -2133,8 +1870,6 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - DBG_871X("%s(): mac_id =%d rssi_level =%d\n", __func__, mac_id, rssi_level); - if (mac_id >= NUM_STA) /* CAM_SIZE */ return; @@ -2148,31 +1883,18 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l rate_bitmap = 0xffffffff; rate_bitmap = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level); - DBG_871X("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", - __func__, mac_id, psta->wireless_mode, mask, rssi_level, rate_bitmap); mask &= rate_bitmap; rate_bitmap = hal_btcoex_GetRaMask(padapter); mask &= ~rate_bitmap; -#ifdef CONFIG_CMCC_TEST - if (pmlmeext->cur_wireless_mode & WIRELESS_11G) { - if (mac_id == 0) { - DBG_871X("CMCC_BT update raid entry, mask = 0x%x\n", mask); - mask &= 0xffffff00; /* disable CCK & <24M OFDM rate for 11G mode for CMCC */ - DBG_871X("CMCC_BT update raid entry, mask = 0x%x\n", mask); - } - } -#endif - if (pHalData->fw_ractrl) { rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, psta->raid, psta->bw_mode, shortGIrate, mask); } /* set correct initial date rate for each mac_id */ pdmpriv->INIDATA_RATE[mac_id] = psta->init_rate; - DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x init_rate = 0x%x\n", __func__, mac_id, psta->raid, psta->bw_mode, mask, psta->init_rate); } @@ -2302,8 +2024,6 @@ u8 GetEEPROMSize8723B(struct adapter *padapter) /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */ size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; - MSG_8192C("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46"); - return size; } @@ -2335,15 +2055,8 @@ s32 rtl8723b_InitLLTTable(struct adapter *padapter) } passing_time = jiffies_to_msecs(jiffies - start); - if (passing_time > 1000) { - DBG_8192C( - "%s: FAIL!! REG_AUTO_LLT(0x%X) =%08x\n", - __func__, - REG_AUTO_LLT, - val32 - ); + if (passing_time > 1000) break; - } msleep(1); } while (1); @@ -2368,9 +2081,6 @@ static bool Hal_GetChnlGroup8723B(u8 Channel, u8 *pGroup) *pGroup = 3; else if (12 <= Channel && Channel <= 14) *pGroup = 4; - else { - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("==>Hal_GetChnlGroup8723B in 2.4 G, but Channel %d in Group not found\n", Channel)); - } } else { bIn24G = false; @@ -2402,21 +2112,7 @@ static bool Hal_GetChnlGroup8723B(u8 Channel, u8 *pGroup) *pGroup = 12; else if (173 <= Channel && Channel <= 177) *pGroup = 13; - else { - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("==>Hal_GetChnlGroup8723B in 5G, but Channel %d in Group not found\n", Channel)); - } - } - RT_TRACE( - _module_hci_hal_init_c_, - _drv_info_, - ( - "<==Hal_GetChnlGroup8723B, (%s) Channel = %d, Group =%d,\n", - bIn24G ? "2.4G" : "5G", - Channel, - *pGroup - ) - ); return bIn24G; } @@ -2431,7 +2127,6 @@ void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent) memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); } } else {/* autoload fail */ - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n")); if (!pEEPROM->EepromOrEfuse) EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); @@ -2448,12 +2143,9 @@ void Hal_EfuseParseIDCode(struct adapter *padapter, u8 *hwinfo) /* Checl 0x8129 again for making sure autoload status!! */ EEPROMId = le16_to_cpu(*((__le16 *)hwinfo)); if (EEPROMId != RTL_EEPROM_ID) { - DBG_8192C("EEPROM ID(%#x) is invalid!!\n", EEPROMId); pEEPROM->bautoload_fail_flag = true; } else pEEPROM->bautoload_fail_flag = false; - - RT_TRACE(_module_hal_init_c_, _drv_notice_, ("EEPROM ID = 0x%04x\n", EEPROMId)); } static void Hal_ReadPowerValueFromPROM_8723B( @@ -2472,7 +2164,6 @@ static void Hal_ReadPowerValueFromPROM_8723B( AutoLoadFail = true; if (AutoLoadFail) { - DBG_871X("%s(): Use Default value!\n", __func__); for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) { /* 2.4G default value */ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { @@ -2594,11 +2285,6 @@ void Hal_EfuseParseTxPowerInfo_8723B( pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group]; pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; } -#ifdef DEBUG - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("======= Path %d, ChannelIndex %d, Group %d =======\n", rfPath, ch, group)); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch, pHalData->Index24G_CCK_Base[rfPath][ch])); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch, pHalData->Index24G_BW40_Base[rfPath][ch])); -#endif } for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { @@ -2606,14 +2292,6 @@ void Hal_EfuseParseTxPowerInfo_8723B( pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount]; pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount]; pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount]; - -#ifdef DEBUG - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("--------------------------------------- 2.4G ---------------------------------------\n")); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("CCK_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount])); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("OFDM_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount])); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("BW20_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount])); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("BW40_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount])); -#endif } } @@ -2624,8 +2302,6 @@ void Hal_EfuseParseTxPowerInfo_8723B( pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */ } else pHalData->EEPROMRegulatory = 0; - - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory)); } void Hal_EfuseParseBTCoexistInfo_8723B( @@ -2666,13 +2342,6 @@ void Hal_EfuseParseBTCoexistInfo_8723B( } if (padapter->registrypriv.ant_num > 0) { - DBG_8192C( - "%s: Apply driver defined antenna number(%d) to replace origin(%d)\n", - __func__, - padapter->registrypriv.ant_num, - pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1 - ); - switch (padapter->registrypriv.ant_num) { case 1: pHalData->EEPROMBluetoothAntNum = Ant_x1; @@ -2681,11 +2350,6 @@ void Hal_EfuseParseBTCoexistInfo_8723B( pHalData->EEPROMBluetoothAntNum = Ant_x2; break; default: - DBG_8192C( - "%s: Discard invalid driver defined antenna number(%d)!\n", - __func__, - padapter->registrypriv.ant_num - ); break; } } @@ -2695,13 +2359,6 @@ void Hal_EfuseParseBTCoexistInfo_8723B( hal_btcoex_SetPgAntNum(padapter, pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1); if (pHalData->EEPROMBluetoothAntNum == Ant_x1) hal_btcoex_SetSingleAntPath(padapter, pHalData->ant_path); - - DBG_8192C( - "%s: %s BT-coex, ant_num =%d\n", - __func__, - pHalData->EEPROMBluetoothCoexist == true ? "Enable" : "Disable", - pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1 - ); } void Hal_EfuseParseEEPROMVer_8723B( @@ -2710,13 +2367,10 @@ void Hal_EfuseParseEEPROMVer_8723B( { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); -/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ if (!AutoLoadFail) pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_8723B]; else pHalData->EEPROMVersion = 1; - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n", - pHalData->EEPROMVersion)); } @@ -2731,7 +2385,6 @@ void Hal_EfuseParsePackageType_8723B( Efuse_PowerSwitch(padapter, false, true); efuse_OneByteRead(padapter, 0x1FB, &efuseContent, false); - DBG_871X("%s phy efuse read 0x1FB =%x\n", __func__, efuseContent); Efuse_PowerSwitch(padapter, false, false); package = efuseContent & 0x7; @@ -2753,8 +2406,6 @@ void Hal_EfuseParsePackageType_8723B( pHalData->PackageType = PACKAGE_DEFAULT; break; } - - DBG_871X("PackageType = 0x%X\n", pHalData->PackageType); } @@ -2765,9 +2416,7 @@ void Hal_EfuseParseVoltage_8723B( struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); /* memcpy(pEEPROM->adjuseVoltageVal, &hwinfo[EEPROM_Voltage_ADDR_8723B], 1); */ - DBG_871X("%s hwinfo[EEPROM_Voltage_ADDR_8723B] =%02x\n", __func__, hwinfo[EEPROM_Voltage_ADDR_8723B]); pEEPROM->adjuseVoltageVal = (hwinfo[EEPROM_Voltage_ADDR_8723B] & 0xf0) >> 4; - DBG_871X("%s pEEPROM->adjuseVoltageVal =%x\n", __func__, pEEPROM->adjuseVoltageVal); } void Hal_EfuseParseChnlPlan_8723B( @@ -2783,8 +2432,6 @@ void Hal_EfuseParseChnlPlan_8723B( ); Hal_ChannelPlanToRegulation(padapter, padapter->mlmepriv.ChannelPlan); - - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan)); } void Hal_EfuseParseCustomerID_8723B( @@ -2793,13 +2440,10 @@ void Hal_EfuseParseCustomerID_8723B( { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); -/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ if (!AutoLoadFail) pHalData->EEPROMCustomerID = hwinfo[EEPROM_CustomID_8723B]; else pHalData->EEPROMCustomerID = 0; - - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID)); } void Hal_EfuseParseAntennaDiversity_8723B( @@ -2816,15 +2460,12 @@ void Hal_EfuseParseXtal_8723B( { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); -/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ if (!AutoLoadFail) { pHalData->CrystalCap = hwinfo[EEPROM_XTAL_8723B]; if (pHalData->CrystalCap == 0xFF) pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723B; /* what value should 8812 set? */ } else pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723B; - - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM CrystalCap: 0x%2x\n", pHalData->CrystalCap)); } @@ -2834,7 +2475,6 @@ void Hal_EfuseParseThermalMeter_8723B( { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); -/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ /* */ /* ThermalMeter from EEPROM */ /* */ @@ -2847,8 +2487,6 @@ void Hal_EfuseParseThermalMeter_8723B( pHalData->bAPKThermalMeterIgnore = true; pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B; } - - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter)); } @@ -2862,15 +2500,11 @@ void Hal_ReadRFGainOffset( if (!AutoloadFail) { Adapter->eeprompriv.EEPROMRFGainOffset = PROMContent[EEPROM_RF_GAIN_OFFSET]; - DBG_871X("AutoloadFail =%x,\n", AutoloadFail); Adapter->eeprompriv.EEPROMRFGainVal = EFUSE_Read1Byte(Adapter, EEPROM_RF_GAIN_VAL); - DBG_871X("Adapter->eeprompriv.EEPROMRFGainVal =%x\n", Adapter->eeprompriv.EEPROMRFGainVal); } else { Adapter->eeprompriv.EEPROMRFGainOffset = 0; Adapter->eeprompriv.EEPROMRFGainVal = 0xFF; - DBG_871X("else AutoloadFail =%x,\n", AutoloadFail); } - DBG_871X("EEPRORFGainOffset = 0x%02x\n", Adapter->eeprompriv.EEPROMRFGainOffset); } u8 BWMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) @@ -2878,8 +2512,6 @@ u8 BWMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) u8 BWSettingOfDesc = 0; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - /* DBG_871X("BWMapping pHalData->CurrentChannelBW %d, pattrib->bwmode %d\n", pHalData->CurrentChannelBW, pattrib->bwmode); */ - if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) { if (pattrib->bwmode == CHANNEL_WIDTH_80) BWSettingOfDesc = 2; @@ -2906,8 +2538,6 @@ u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) u8 SCSettingOfDesc = 0; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - /* DBG_871X("SCMapping: pHalData->CurrentChannelBW %d, pHalData->nCur80MhzPrimeSC %d, pHalData->nCur40MhzPrimeSC %d\n", pHalData->CurrentChannelBW, pHalData->nCur80MhzPrimeSC, pHalData->nCur40MhzPrimeSC); */ - if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) { if (pattrib->bwmode == CHANNEL_WIDTH_80) { SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE; @@ -2916,8 +2546,6 @@ u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) SCSettingOfDesc = VHT_DATA_SC_40_LOWER_OF_80MHZ; else if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) SCSettingOfDesc = VHT_DATA_SC_40_UPPER_OF_80MHZ; - else - DBG_871X("SCMapping: Not Correct Primary40MHz Setting\n"); } else { if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)) SCSettingOfDesc = VHT_DATA_SC_20_LOWEST_OF_80MHZ; @@ -2927,12 +2555,8 @@ u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) SCSettingOfDesc = VHT_DATA_SC_20_UPPER_OF_80MHZ; else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)) SCSettingOfDesc = VHT_DATA_SC_20_UPPERST_OF_80MHZ; - else - DBG_871X("SCMapping: Not Correct Primary40MHz Setting\n"); } } else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) { - /* DBG_871X("SCMapping: HT Case: pHalData->CurrentChannelBW %d, pHalData->nCur40MhzPrimeSC %d\n", pHalData->CurrentChannelBW, pHalData->nCur40MhzPrimeSC); */ - if (pattrib->bwmode == CHANNEL_WIDTH_40) { SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE; } else if (pattrib->bwmode == CHANNEL_WIDTH_20) { @@ -2999,10 +2623,8 @@ static u8 fill_txdesc_sectype(struct pkt_attrib *pattrib) return sectype; } -static void fill_txdesc_vcs_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, PTXDESC_8723B ptxdesc) +static void fill_txdesc_vcs_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, struct txdesc_8723b *ptxdesc) { - /* DBG_8192C("cvs_mode =%d\n", pattrib->vcs_mode); */ - if (pattrib->vcs_mode) { switch (pattrib->vcs_mode) { case RTS_CTS: @@ -3032,10 +2654,8 @@ static void fill_txdesc_vcs_8723b(struct adapter *padapter, struct pkt_attrib *p } } -static void fill_txdesc_phy_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, PTXDESC_8723B ptxdesc) +static void fill_txdesc_phy_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, struct txdesc_8723b *ptxdesc) { - /* DBG_8192C("bwmode =%d, ch_off =%d\n", pattrib->bwmode, pattrib->ch_offset); */ - if (pattrib->ht_en) { ptxdesc->data_bw = BWMapping_8723B(padapter, pattrib); @@ -3052,7 +2672,7 @@ static void rtl8723b_fill_default_txdesc( struct mlme_ext_priv *pmlmeext; struct mlme_ext_info *pmlmeinfo; struct pkt_attrib *pattrib; - PTXDESC_8723B ptxdesc; + struct txdesc_8723b *ptxdesc; s32 bmcst; memset(pbuf, 0, TXDESC_SIZE); @@ -3065,7 +2685,7 @@ static void rtl8723b_fill_default_txdesc( pattrib = &pxmitframe->attrib; bmcst = IS_MCAST(pattrib->ra); - ptxdesc = (PTXDESC_8723B)pbuf; + ptxdesc = (struct txdesc_8723b *)pbuf; if (pxmitframe->frame_tag == DATA_FRAMETAG) { u8 drv_userate = 0; @@ -3087,9 +2707,6 @@ static void rtl8723b_fill_default_txdesc( (pattrib->ether_type != 0x88B4) && (pattrib->dhcp_pkt != 1) && (drv_userate != 1) -#ifdef CONFIG_AUTO_AP_MODE - && (!pattrib->pctrl) -#endif ) { /* Non EAP & ARP & DHCP type data packet */ @@ -3126,10 +2743,6 @@ static void rtl8723b_fill_default_txdesc( ptxdesc->data_ldpc = 1; if (pattrib->stbc) ptxdesc->data_stbc = 1; - -#ifdef CONFIG_CMCC_TEST - ptxdesc->data_short = 1; /* use cck short premble */ -#endif } else { /* EAP data packet and ARP packet. */ /* Use the 1M data rate to send the EAP/ARP packet. */ @@ -3140,13 +2753,10 @@ static void rtl8723b_fill_default_txdesc( if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) ptxdesc->data_short = 1;/* DATA_SHORT */ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); - DBG_871X("YJ: %s(): ARP Data: userate =%d, datarate = 0x%x\n", __func__, ptxdesc->userate, ptxdesc->datarate); } ptxdesc->usb_txagg_num = pxmitframe->agg_num; } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { -/* RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: MGNT_FRAMETAG\n", __func__)); */ - ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ ptxdesc->qsel = pattrib->qsel; ptxdesc->rate_id = pattrib->raid; /* Rate ID */ @@ -3166,17 +2776,10 @@ static void rtl8723b_fill_default_txdesc( /* CCX-TXRPT ack for xmit mgmt frames. */ if (pxmitframe->ack_report) { - #ifdef DBG_CCX - DBG_8192C("%s set spe_rpt\n", __func__); - #endif ptxdesc->spe_rpt = 1; ptxdesc->sw_define = (u8)(GET_PRIMARY_ADAPTER(padapter)->xmitpriv.seq_no); } - } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { - RT_TRACE(_module_hal_xmit_c_, _drv_warning_, ("%s: TXAGG_FRAMETAG\n", __func__)); } else { - RT_TRACE(_module_hal_xmit_c_, _drv_warning_, ("%s: frame_tag = 0x%x\n", __func__, pxmitframe->frame_tag)); - ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ ptxdesc->rate_id = pattrib->raid; /* Rate ID */ ptxdesc->qsel = pattrib->qsel; @@ -3325,22 +2928,10 @@ static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val) /* set net_type */ Set_MSR(padapter, mode); - DBG_871X("#### %s() -%d iface_type(0) mode = %d ####\n", __func__, __LINE__, mode); if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { { StopTxBeacon(padapter); -#ifdef CONFIG_INTERRUPT_BASED_TXBCN -#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT - rtw_write8(padapter, REG_DRVERLYINT, 0x05); /* restore early int time to 5ms */ - UpdateInterruptMask8812AU(padapter, true, 0, IMR_BCNDMAINT0_8723B); -#endif /* CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT */ - -#ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR - UpdateInterruptMask8812AU(padapter, true, 0, (IMR_TXBCN0ERR_8723B|IMR_TXBCN0OK_8723B)); -#endif /* CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR */ - -#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ } /* disable atim wnd */ @@ -3350,16 +2941,6 @@ static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val) ResumeTxBeacon(padapter); rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_BCNQ_SUB); } else if (mode == _HW_STATE_AP_) { -#ifdef CONFIG_INTERRUPT_BASED_TXBCN -#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT - UpdateInterruptMask8723BU(padapter, true, IMR_BCNDMAINT0_8723B, 0); -#endif /* CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT */ - -#ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR - UpdateInterruptMask8723BU(padapter, true, (IMR_TXBCN0ERR_8723B|IMR_TXBCN0OK_8723B), 0); -#endif /* CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR */ - -#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ ResumeTxBeacon(padapter); @@ -3620,22 +3201,15 @@ static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val) void CCX_FwC2HTxRpt_8723b(struct adapter *padapter, u8 *pdata, u8 len) { - u8 seq_no; #define GET_8723B_C2H_TX_RPT_LIFE_TIME_OVER(_Header) LE_BITS_TO_1BYTE((_Header + 0), 6, 1) #define GET_8723B_C2H_TX_RPT_RETRY_OVER(_Header) LE_BITS_TO_1BYTE((_Header + 0), 7, 1) - /* DBG_871X("%s, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", __func__, */ - /* *pdata, *(pdata+1), *(pdata+2), *(pdata+3), *(pdata+4), *(pdata+5), *(pdata+6), *(pdata+7)); */ - - seq_no = *(pdata+6); - if (GET_8723B_C2H_TX_RPT_RETRY_OVER(pdata) | GET_8723B_C2H_TX_RPT_LIFE_TIME_OVER(pdata)) { rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); } /* else if (seq_no != padapter->xmitpriv.seq_no) { - DBG_871X("tx_seq_no =%d, rpt_seq_no =%d\n", padapter->xmitpriv.seq_no, seq_no); rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); } */ @@ -3658,10 +3232,8 @@ s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf) { struct c2h_evt_hdr_88xx *pC2hEvent = (struct c2h_evt_hdr_88xx *)buf; s32 ret = _SUCCESS; - u8 index = 0; if (!pC2hEvent) { - DBG_8192C("%s(): pC2hEventis NULL\n", __func__); ret = _FAIL; goto exit; } @@ -3671,7 +3243,6 @@ s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf) break; case C2H_DBG: { - RT_TRACE(_module_hal_init_c_, _drv_info_, ("c2h_handler_8723b: %s\n", pC2hEvent->payload)); } break; @@ -3684,10 +3255,6 @@ s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf) break; case C2H_HW_INFO_EXCH: - RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], C2H_HW_INFO_EXCH\n")); - for (index = 0; index < pC2hEvent->plen; index++) { - RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], tmpBuf[%d]= 0x%x\n", index, pC2hEvent->payload[index])); - } break; case C2H_8723B_BT_INFO: @@ -3706,21 +3273,16 @@ exit: return ret; } -static void process_c2h_event(struct adapter *padapter, PC2H_EVT_HDR pC2hEvent, u8 *c2hBuf) +static void process_c2h_event(struct adapter *padapter, struct c2h_evt_hdr_t *pC2hEvent, u8 *c2hBuf) { - u8 index = 0; - - if (!c2hBuf) { - DBG_8192C("%s c2hbuff is NULL\n", __func__); + if (!c2hBuf) return; - } switch (pC2hEvent->CmdID) { case C2H_AP_RPT_RSP: break; case C2H_DBG: { - RT_TRACE(_module_hal_init_c_, _drv_info_, ("C2HCommandHandler: %s\n", c2hBuf)); } break; @@ -3733,10 +3295,6 @@ static void process_c2h_event(struct adapter *padapter, PC2H_EVT_HDR pC2hEvent, break; case C2H_HW_INFO_EXCH: - RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], C2H_HW_INFO_EXCH\n")); - for (index = 0; index < pC2hEvent->CmdLen; index++) { - RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], tmpBuf[%d]= 0x%x\n", index, c2hBuf[index])); - } break; case C2H_8723B_BT_INFO: @@ -3750,24 +3308,15 @@ static void process_c2h_event(struct adapter *padapter, PC2H_EVT_HDR pC2hEvent, void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length) { - C2H_EVT_HDR C2hEvent; + struct c2h_evt_hdr_t C2hEvent; u8 *tmpBuf = NULL; -#ifdef CONFIG_WOWLAN - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - - if (pwrpriv->wowlan_mode) { - DBG_871X("%s(): return because wowolan_mode ==true! CMDID =%d\n", __func__, pbuffer[0]); - return; - } -#endif C2hEvent.CmdID = pbuffer[0]; C2hEvent.CmdSeq = pbuffer[1]; C2hEvent.CmdLen = length-2; tmpBuf = pbuffer+2; - /* DBG_871X("%s C2hEvent.CmdID:%x C2hEvent.CmdLen:%x C2hEvent.CmdSeq:%x\n", */ - /* __func__, C2hEvent.CmdID, C2hEvent.CmdLen, C2hEvent.CmdSeq); */ - RT_PRINT_DATA(_module_hal_init_c_, _drv_notice_, "C2HPacketHandler_8723B(): Command Content:\n", tmpBuf, C2hEvent.CmdLen); + print_hex_dump_debug(DRIVER_PREFIX ": C2HPacketHandler_8723B(): Command Content:\n", + DUMP_PREFIX_NONE, 16, 1, tmpBuf, C2hEvent.CmdLen, false); process_c2h_event(padapter, &C2hEvent, tmpBuf); /* c2h_handler_8723b(padapter,&C2hEvent); */ @@ -3807,22 +3356,15 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) case HW_VAR_BASIC_RATE: { struct mlme_ext_info *mlmext_info = &padapter->mlmeextpriv.mlmext_info; - u16 input_b = 0, masked = 0, ioted = 0, BrateCfg = 0; + u16 BrateCfg = 0; u16 rrsr_2g_force_mask = (RRSR_11M|RRSR_5_5M|RRSR_1M); u16 rrsr_2g_allow_mask = (RRSR_24M|RRSR_12M|RRSR_6M|RRSR_CCK_RATES); HalSetBrateCfg(padapter, val, &BrateCfg); - input_b = BrateCfg; /* apply force and allow mask */ BrateCfg |= rrsr_2g_force_mask; BrateCfg &= rrsr_2g_allow_mask; - masked = BrateCfg; - - #ifdef CONFIG_CMCC_TEST - BrateCfg |= (RRSR_11M|RRSR_5_5M|RRSR_1M); /* use 11M to send ACK */ - BrateCfg |= (RRSR_24M|RRSR_18M|RRSR_12M); /* CMCC_OFDM_ACK 12/18/24M */ - #endif /* IOT consideration */ if (mlmext_info->assoc_AP_vendor == HT_IOT_PEER_CISCO) { @@ -3830,12 +3372,9 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) if ((BrateCfg & (RRSR_24M|RRSR_12M|RRSR_6M)) == 0) BrateCfg |= RRSR_6M; } - ioted = BrateCfg; pHalData->BasicRateSet = BrateCfg; - DBG_8192C("HW_VAR_BASIC_RATE: %#x -> %#x -> %#x\n", input_b, masked, ioted); - /* Set RRSR rate table. */ rtw_write16(padapter, REG_RRSR, BrateCfg); rtw_write8(padapter, REG_RRSR+2, rtw_read8(padapter, REG_RRSR+2)&0xf0); @@ -3899,14 +3438,12 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) val32 = rtw_read32(padapter, REG_RCR); val32 |= RCR_AM; rtw_write32(padapter, REG_RCR, val32); - DBG_8192C("%s, %d, RCR = %x\n", __func__, __LINE__, rtw_read32(padapter, REG_RCR)); break; case HW_VAR_OFF_RCR_AM: val32 = rtw_read32(padapter, REG_RCR); val32 &= ~RCR_AM; rtw_write32(padapter, REG_RCR, val32); - DBG_8192C("%s, %d, RCR = %x\n", __func__, __LINE__, rtw_read32(padapter, REG_RCR)); break; case HW_VAR_BEACON_INTERVAL: @@ -3962,9 +3499,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE; /* write content 0 is equall to mark invalid */ rtw_write32(padapter, WCAMI, ulContent); /* mdelay(40); */ - /* RT_TRACE(COMP_SEC, DBG_LOUD, ("CAM_empty_entry(): WRITE A4: %lx\n", ulContent)); */ rtw_write32(padapter, RWCAM, ulCommand); /* mdelay(40); */ - /* RT_TRACE(COMP_SEC, DBG_LOUD, ("CAM_empty_entry(): WRITE A0: %lx\n", ulCommand)); */ } } break; @@ -4020,7 +3555,6 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) hwctrl |= AcmHw_VoqEn; } - DBG_8192C("[HW_VAR_ACM_CTRL] Write 0x%02X\n", hwctrl); rtw_write8(padapter, REG_ACMHWCTRL, hwctrl); } break; @@ -4066,7 +3600,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) case HW_VAR_INITIAL_GAIN: { - DIG_T *pDigTable = &pHalData->odmpriv.DM_DigTable; + struct dig_t *pDigTable = &pHalData->odmpriv.DM_DigTable; u32 rx_gain = *(u32 *)val; if (rx_gain == 0xff) {/* restore rx gain */ @@ -4124,14 +3658,8 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) val32 &= RXDMA_IDLE; if (val32) break; - - DBG_871X("%s: [HW_VAR_FIFO_CLEARN_UP] val =%x times:%d\n", __func__, val32, trycnt); } while (--trycnt); - if (trycnt == 0) { - DBG_8192C("[HW_VAR_FIFO_CLEARN_UP] Stop RX DMA failed......\n"); - } - /* RQPN Load 0 */ rtw_write16(padapter, REG_RQPN_NPQ, 0); rtw_write32(padapter, REG_RQPN, 0x80000000); @@ -4142,17 +3670,14 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) case HW_VAR_APFM_ON_MAC: pHalData->bMacPwrCtrlOn = *val; - DBG_8192C("%s: bMacPwrCtrlOn =%d\n", __func__, pHalData->bMacPwrCtrlOn); break; case HW_VAR_NAV_UPPER: { u32 usNavUpper = *((u32 *)val); - if (usNavUpper > HAL_NAV_UPPER_UNIT_8723B * 0xFF) { - RT_TRACE(_module_hal_init_c_, _drv_notice_, ("The setting value (0x%08X us) of NAV_UPPER is larger than (%d * 0xFF)!!!\n", usNavUpper, HAL_NAV_UPPER_UNIT_8723B)); + if (usNavUpper > HAL_NAV_UPPER_UNIT_8723B * 0xFF) break; - } usNavUpper = DIV_ROUND_UP(usNavUpper, HAL_NAV_UPPER_UNIT_8723B); @@ -4202,16 +3727,12 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) case HW_VAR_MACID_SLEEP: /* Input is MACID */ val32 = *(u32 *)val; - if (val32 > 31) { - DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_SLEEP] Invalid macid(%d)\n", - FUNC_ADPT_ARG(padapter), val32); + if (val32 > 31) break; - } + val8 = (u8)val32; /* macid is between 0~31 */ val32 = rtw_read32(padapter, REG_MACID_SLEEP); - DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_SLEEP] macid =%d, org MACID_SLEEP = 0x%08X\n", - FUNC_ADPT_ARG(padapter), val8, val32); if (val32 & BIT(val8)) break; val32 |= BIT(val8); @@ -4221,16 +3742,12 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) case HW_VAR_MACID_WAKEUP: /* Input is MACID */ val32 = *(u32 *)val; - if (val32 > 31) { - DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_WAKEUP] Invalid macid(%d)\n", - FUNC_ADPT_ARG(padapter), val32); + if (val32 > 31) break; - } + val8 = (u8)val32; /* macid is between 0~31 */ val32 = rtw_read32(padapter, REG_MACID_SLEEP); - DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_WAKEUP] macid =%d, org MACID_SLEEP = 0x%08X\n", - FUNC_ADPT_ARG(padapter), val8, val32); if (!(val32 & BIT(val8))) break; val32 &= ~BIT(val8); @@ -4314,19 +3831,6 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) val16 = rtw_read16(padapter, REG_TXPKT_EMPTY); *val = (val16 & BIT(10)) ? true:false; break; -#ifdef CONFIG_WOWLAN - case HW_VAR_RPWM_TOG: - *val = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1) & BIT7; - break; - case HW_VAR_WAKEUP_REASON: - *val = rtw_read8(padapter, REG_WOWLAN_WAKE_REASON); - if (*val == 0xEA) - *val = 0; - break; - case HW_VAR_SYS_CLKR: - *val = rtw_read8(padapter, REG_SYS_CLKR); - break; -#endif default: GetHwReg(padapter, variable, val); break; @@ -4336,7 +3840,7 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) /* Description: * Change default setting of specified variable. */ -u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval) +u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval) { u8 bResult; @@ -4354,7 +3858,7 @@ u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, v /* Description: * Query setting of specified variable. */ -u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval) +u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval) { u8 bResult; @@ -4398,19 +3902,12 @@ u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, v u32 rate_mask1, rate_mask2; u8 curr_tx_rate, curr_tx_sgi, hight_rate, lowest_rate; - DBG_8192C("============ RA status check Mac_id:%d ===================\n", mac_id); - cmd = 0x40000100 | mac_id; rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd); msleep(10); ra_info1 = rtw_read32(padapter, 0x2F0); curr_tx_rate = ra_info1&0x7F; curr_tx_sgi = (ra_info1>>7)&0x01; - DBG_8192C("[ ra_info1:0x%08x ] =>cur_tx_rate = %s, cur_sgi:%d, PWRSTS = 0x%02x \n", - ra_info1, - HDATA_RATE(curr_tx_rate), - curr_tx_sgi, - (ra_info1>>8) & 0x07); cmd = 0x40000400 | mac_id; rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd); @@ -4422,22 +3919,6 @@ u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, v hight_rate = ra_info2&0xFF; lowest_rate = (ra_info2>>8) & 0xFF; - DBG_8192C("[ ra_info1:0x%08x ] =>RSSI =%d, BW_setting = 0x%02x, DISRA = 0x%02x, VHT_EN = 0x%02x\n", - ra_info1, - ra_info1&0xFF, - (ra_info1>>8) & 0xFF, - (ra_info1>>16) & 0xFF, - (ra_info1>>24) & 0xFF); - - DBG_8192C("[ ra_info2:0x%08x ] =>hight_rate =%s, lowest_rate =%s, SGI = 0x%02x, RateID =%d\n", - ra_info2, - HDATA_RATE(hight_rate), - HDATA_RATE(lowest_rate), - (ra_info2>>16) & 0xFF, - (ra_info2>>24) & 0xFF); - - DBG_8192C("rate_mask2 = 0x%08x, rate_mask1 = 0x%08x\n", rate_mask2, rate_mask1); - } break; @@ -4461,29 +3942,15 @@ u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, v return bResult; } -#ifdef CONFIG_WOWLAN -void Hal_DetectWoWMode(struct adapter *padapter) -{ - adapter_to_pwrctl(padapter)->bSupportRemoteWakeup = true; - DBG_871X("%s\n", __func__); -} -#endif /* CONFIG_WOWLAN */ - void rtl8723b_start_thread(struct adapter *padapter) { -#ifndef CONFIG_SDIO_TX_TASKLET struct xmit_priv *xmitpriv = &padapter->xmitpriv; xmitpriv->SdioXmitThread = kthread_run(rtl8723bs_xmit_thread, padapter, "RTWHALXT"); - if (IS_ERR(xmitpriv->SdioXmitThread)) { - RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: start rtl8723bs_xmit_thread FAIL!!\n", __func__)); - } -#endif } void rtl8723b_stop_thread(struct adapter *padapter) { -#ifndef CONFIG_SDIO_TX_TASKLET struct xmit_priv *xmitpriv = &padapter->xmitpriv; /* stop xmit_buf_thread */ @@ -4492,36 +3959,4 @@ void rtl8723b_stop_thread(struct adapter *padapter) wait_for_completion(&xmitpriv->SdioXmitTerminate); xmitpriv->SdioXmitThread = NULL; } -#endif -} - -#if defined(CONFIG_CHECK_BT_HANG) -extern void check_bt_status_work(void *data); -void rtl8723bs_init_checkbthang_workqueue(struct adapter *adapter) -{ - adapter->priv_checkbt_wq = alloc_workqueue("sdio_wq", 0, 0); - INIT_DELAYED_WORK(&adapter->checkbt_work, (void *)check_bt_status_work); -} - -void rtl8723bs_free_checkbthang_workqueue(struct adapter *adapter) -{ - if (adapter->priv_checkbt_wq) { - cancel_delayed_work_sync(&adapter->checkbt_work); - flush_workqueue(adapter->priv_checkbt_wq); - destroy_workqueue(adapter->priv_checkbt_wq); - adapter->priv_checkbt_wq = NULL; - } } - -void rtl8723bs_cancle_checkbthang_workqueue(struct adapter *adapter) -{ - if (adapter->priv_checkbt_wq) - cancel_delayed_work_sync(&adapter->checkbt_work); -} - -void rtl8723bs_hal_check_bt_hang(struct adapter *adapter) -{ - if (adapter->priv_checkbt_wq) - queue_delayed_work(adapter->priv_checkbt_wq, &(adapter->checkbt_work), 0); -} -#endif diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c index 22365926a9f8a5c0e134f2a744f35a5dd87dca62..f43abf9b0d2250adf2585972322c4b9343a55112 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c @@ -108,7 +108,7 @@ void PHY_SetBBReg_8723B( /* */ static u32 phy_RFSerialRead_8723B( - struct adapter *Adapter, enum RF_PATH eRFPath, u32 Offset + struct adapter *Adapter, enum rf_path eRFPath, u32 Offset ) { u32 retValue = 0; @@ -202,7 +202,7 @@ static u32 phy_RFSerialRead_8723B( */ static void phy_RFSerialWrite_8723B( struct adapter *Adapter, - enum RF_PATH eRFPath, + enum rf_path eRFPath, u32 Offset, u32 Data ) @@ -547,11 +547,8 @@ void PHY_SetTxPowerIndex( break; default: - DBG_871X("Invalid Rate!!\n"); break; } - } else { - RT_TRACE(_module_hal_init_c_, _drv_err_, ("Invalid RFPath!!\n")); } } @@ -559,7 +556,7 @@ u8 PHY_GetTxPowerIndex( struct adapter *padapter, u8 RFPath, u8 Rate, - enum CHANNEL_WIDTH BandWidth, + enum channel_width BandWidth, u8 Channel ) { @@ -594,8 +591,8 @@ u8 PHY_GetTxPowerIndex( void PHY_SetTxPowerLevel8723B(struct adapter *Adapter, u8 Channel) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; - pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + struct fat_t *pDM_FatTable = &pDM_Odm->DM_FatTable; u8 RFPath = ODM_RF_PATH_A; if (pHalData->AntDivCfg) {/* antenna diversity Enable */ @@ -604,11 +601,7 @@ void PHY_SetTxPowerLevel8723B(struct adapter *Adapter, u8 Channel) RFPath = pHalData->ant_path; } - RT_TRACE(_module_hal_init_c_, _drv_info_, ("==>PHY_SetTxPowerLevel8723B()\n")); - PHY_SetTxPowerLevelByPath(Adapter, Channel, RFPath); - - RT_TRACE(_module_hal_init_c_, _drv_info_, ("<==PHY_SetTxPowerLevel8723B()\n")); } void PHY_GetTxPowerLevel8723B(struct adapter *Adapter, s32 *powerlevel) @@ -616,7 +609,7 @@ void PHY_GetTxPowerLevel8723B(struct adapter *Adapter, s32 *powerlevel) } static void phy_SetRegBW_8723B( - struct adapter *Adapter, enum CHANNEL_WIDTH CurrentBW + struct adapter *Adapter, enum channel_width CurrentBW ) { u16 RegRfMod_BW, u2tmp = 0; @@ -638,7 +631,6 @@ static void phy_SetRegBW_8723B( break; default: - DBG_871X("phy_PostSetBWMode8723B(): unknown Bandwidth: %#X\n", CurrentBW); break; } } @@ -648,23 +640,11 @@ static u8 phy_GetSecondaryChnl_8723B(struct adapter *Adapter) u8 SCSettingOf40 = 0, SCSettingOf20 = 0; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ( - "SCMapping: VHT Case: pHalData->CurrentChannelBW %d, pHalData->nCur80MhzPrimeSC %d, pHalData->nCur40MhzPrimeSC %d\n", - pHalData->CurrentChannelBW, - pHalData->nCur80MhzPrimeSC, - pHalData->nCur40MhzPrimeSC - ) - ); if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) { if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) SCSettingOf40 = VHT_DATA_SC_40_LOWER_OF_80MHZ; else if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) SCSettingOf40 = VHT_DATA_SC_40_UPPER_OF_80MHZ; - else - RT_TRACE(_module_hal_init_c_, _drv_err_, ("SCMapping: Not Correct Primary40MHz Setting\n")); if ( (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && @@ -686,28 +666,13 @@ static u8 phy_GetSecondaryChnl_8723B(struct adapter *Adapter) (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) ) SCSettingOf20 = VHT_DATA_SC_20_UPPERST_OF_80MHZ; - else - RT_TRACE(_module_hal_init_c_, _drv_err_, ("SCMapping: Not Correct Primary40MHz Setting\n")); } else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) { - RT_TRACE( - _module_hal_init_c_, - _drv_info_, - ( - "SCMapping: VHT Case: pHalData->CurrentChannelBW %d, pHalData->nCur40MhzPrimeSC %d\n", - pHalData->CurrentChannelBW, - pHalData->nCur40MhzPrimeSC - ) - ); - if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) SCSettingOf20 = VHT_DATA_SC_20_UPPER_OF_80MHZ; else if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) SCSettingOf20 = VHT_DATA_SC_20_LOWER_OF_80MHZ; - else - RT_TRACE(_module_hal_init_c_, _drv_err_, ("SCMapping: Not Correct Primary40MHz Setting\n")); } - RT_TRACE(_module_hal_init_c_, _drv_info_, ("SCMapping: SC Value %x\n", ((SCSettingOf40 << 4) | SCSettingOf20))); return (SCSettingOf40 << 4) | SCSettingOf20; } @@ -768,23 +733,12 @@ static void phy_SwChnl8723B(struct adapter *padapter) pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff00) | channelToSW); PHY_SetRFReg(padapter, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, pHalData->RfRegChnlVal[0]); PHY_SetRFReg(padapter, ODM_RF_PATH_B, RF_CHNLBW, 0x3FF, pHalData->RfRegChnlVal[0]); - - DBG_8192C("===>phy_SwChnl8723B: Channel = %d\n", channelToSW); } static void phy_SwChnlAndSetBwMode8723B(struct adapter *Adapter) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - if (Adapter->bNotifyChannelChange) { - DBG_871X("[%s] bSwChnl =%d, ch =%d, bSetChnlBW =%d, bw =%d\n", - __func__, - pHalData->bSwChnl, - pHalData->CurrentChannel, - pHalData->bSetChnlBW, - pHalData->CurrentChannelBW); - } - if (Adapter->bDriverStopped || Adapter->bSurpriseRemoved) return; @@ -806,25 +760,23 @@ static void PHY_HandleSwChnlAndSetBW8723B( bool bSwitchChannel, bool bSetBandWidth, u8 ChannelNum, - enum CHANNEL_WIDTH ChnlWidth, - enum EXTCHNL_OFFSET ExtChnlOffsetOf40MHz, - enum EXTCHNL_OFFSET ExtChnlOffsetOf80MHz, + enum channel_width ChnlWidth, + enum extchnl_offset ExtChnlOffsetOf40MHz, + enum extchnl_offset ExtChnlOffsetOf80MHz, u8 CenterFrequencyIndex1 ) { /* static bool bInitialzed = false; */ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); u8 tmpChannel = pHalData->CurrentChannel; - enum CHANNEL_WIDTH tmpBW = pHalData->CurrentChannelBW; + enum channel_width tmpBW = pHalData->CurrentChannelBW; u8 tmpnCur40MhzPrimeSC = pHalData->nCur40MhzPrimeSC; u8 tmpnCur80MhzPrimeSC = pHalData->nCur80MhzPrimeSC; u8 tmpCenterFrequencyIndex1 = pHalData->CurrentCenterFrequencyIndex1; /* check is swchnl or setbw */ - if (!bSwitchChannel && !bSetBandWidth) { - DBG_871X("PHY_HandleSwChnlAndSetBW8812: not switch channel and not set bandwidth\n"); + if (!bSwitchChannel && !bSetBandWidth) return; - } /* skip change for channel or bandwidth is the same */ if (bSwitchChannel) { @@ -874,7 +826,7 @@ static void PHY_HandleSwChnlAndSetBW8723B( void PHY_SetBWMode8723B( struct adapter *Adapter, - enum CHANNEL_WIDTH Bandwidth, /* 20M or 40M */ + enum channel_width Bandwidth, /* 20M or 40M */ unsigned char Offset /* Upper, Lower, or Don't care */ ) { @@ -892,7 +844,7 @@ void PHY_SwChnl8723B(struct adapter *Adapter, u8 channel) void PHY_SetSwChnlBWMode8723B( struct adapter *Adapter, u8 channel, - enum CHANNEL_WIDTH Bandwidth, + enum channel_width Bandwidth, u8 Offset40, u8 Offset80 ) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c index aafceaf9b1394c2e44d1c0a64ce4056acb9c1152..38228b46b1eeec5d2febc16e783d8a7206801b65 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c @@ -55,7 +55,7 @@ * Note: For RF type 0222D *---------------------------------------------------------------------------*/ void PHY_RF6052SetBandwidth8723B( - struct adapter *Adapter, enum CHANNEL_WIDTH Bandwidth + struct adapter *Adapter, enum channel_width Bandwidth ) /* 20M or 40M */ { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); @@ -74,7 +74,6 @@ void PHY_RF6052SetBandwidth8723B( break; default: - /* RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n", Bandwidth)); */ break; } @@ -153,7 +152,6 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) ODM_ConfigRFWithTxPwrTrackHeaderFile(&pHalData->odmpriv); - /* RT_TRACE(COMP_INIT, DBG_LOUD, ("<---phy_RF6052_Config_ParaFile()\n")); */ return _SUCCESS; } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c index 86512264e2803960fc99a4531234c98b494ad56c..f2f02a69f0af920a4bf4d6b2c3a6bcb965f8964f 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c @@ -13,7 +13,6 @@ static void process_rssi(struct adapter *padapter, union recv_frame *prframe) struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data; - /* DBG_8192C("process_rssi => pattrib->rssil(%d) signal_strength(%d)\n ", pattrib->RecvSignalPower, pattrib->signal_strength); */ /* if (pRfd->Status.bPacketToSelf || pRfd->Status.bPacketBeacon) */ { if (signal_stat->update_req) { @@ -40,8 +39,6 @@ static void process_link_qual(struct adapter *padapter, union recv_frame *prfram pattrib = &prframe->u.hdr.attrib; signal_stat = &padapter->recvpriv.signal_qual_data; - /* DBG_8192C("process_link_qual => pattrib->signal_qual(%d)\n ", pattrib->signal_qual); */ - if (signal_stat->update_req) { signal_stat->total_num = 0; signal_stat->total_val = 0; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c index 2d15a5f7648d5486114c47ce06373704f44d2bde..7c2680b6508c275b1a7d63b748b0f64d0eb255c0 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c @@ -38,7 +38,6 @@ static void update_recvframe_attrib(struct adapter *padapter, /* update rx report to recv_frame attribute */ pattrib->pkt_rpt_type = prxreport->c2h_ind ? C2H_PACKET : NORMAL_RX; -/* DBG_871X("%s: pkt_rpt_type =%d\n", __func__, pattrib->pkt_rpt_type); */ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */ @@ -98,7 +97,7 @@ static void update_recvframe_phyinfo(union recv_frame *precvframe, .is_beacon = false, }; - /* _irqL irqL; */ + /* unsigned long irqL; */ struct sta_priv *pstapriv; struct sta_info *psta; @@ -124,11 +123,9 @@ static void update_recvframe_phyinfo(union recv_frame *precvframe, pstapriv = &padapter->stapriv; psta = rtw_get_stainfo(pstapriv, sa); - if (psta) { + if (psta) pkt_info.station_id = psta->mac_id; - /* DBG_8192C("%s ==> StationID(%d)\n", - * __func__, pkt_info.station_id); */ - } + pkt_info.data_rate = pattrib->data_rate; /* rtl8723b_query_rx_phy_status(precvframe, pphy_status); */ @@ -165,8 +162,6 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, if (length == 0) return; - /* DBG_871X("+%s() length =%d\n", __func__, length); */ - tmp = rtw_zmalloc(length); if (!tmp) return; @@ -177,8 +172,6 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, if (!res) kfree(tmp); - - /* DBG_871X("-%s res(%d)\n", __func__, res); */ } static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv, @@ -188,7 +181,6 @@ static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv, precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue); if (!precvframe) { - DBG_8192C("%s: no enough recv frame!\n", __func__); rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); @@ -207,8 +199,6 @@ static inline bool rx_crc_err(struct recv_priv *precvpriv, { /* fix Hardware RX data error, drop whole recv_buffer */ if ((!(p_hal_data->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) { - DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", - __func__, __LINE__); rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); return true; } @@ -221,8 +211,6 @@ static inline bool pkt_exceeds_tail(struct recv_priv *precvpriv, union recv_frame *precvframe) { if (end > tail) { - DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", - __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail); rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); return true; } @@ -242,7 +230,7 @@ static void rtl8723bs_recv_tasklet(struct tasklet_struct *t) struct __queue *recv_buf_queue; u8 *ptr; u32 pkt_offset, skb_len, alloc_sz; - _pkt *pkt_copy = NULL; + struct sk_buff *pkt_copy = NULL; u8 shift_sz = 0, rx_report_sz = 0; p_hal_data = GET_HAL_DATA(padapter); @@ -281,9 +269,6 @@ static void rtl8723bs_recv_tasklet(struct tasklet_struct *t) break; if ((pattrib->crc_err) || (pattrib->icv_err)) { - DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n", - __func__, pattrib->crc_err, - pattrib->icv_err); rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); } else { @@ -312,7 +297,6 @@ static void rtl8723bs_recv_tasklet(struct tasklet_struct *t) pkt_copy = rtw_skb_alloc(alloc_sz); if (!pkt_copy) { - DBG_8192C("%s: alloc_skb fail, drop frame\n", __func__); rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); break; } @@ -345,11 +329,9 @@ static void rtl8723bs_recv_tasklet(struct tasklet_struct *t) if (pattrib->physt) update_recvframe_phyinfo(precvframe, (struct phy_stat *)ptr); - if (rtw_recv_entry(precvframe) != _SUCCESS) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_dump_, ("%s: rtw_recv_entry(precvframe) != _SUCCESS\n", __func__)); - } + rtw_recv_entry(precvframe); } else if (pattrib->pkt_rpt_type == C2H_PACKET) { - C2H_EVT_HDR C2hEvent; + struct c2h_evt_hdr_t C2hEvent; u16 len_c2h = pattrib->pkt_len; u8 *pbuf_c2h = precvframe->u.hdr.rx_data; @@ -404,7 +386,6 @@ s32 rtl8723bs_init_recv_priv(struct adapter *padapter) precvpriv->pallocated_recv_buf = rtw_zmalloc(n); if (!precvpriv->pallocated_recv_buf) { res = _FAIL; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n")); goto exit; } @@ -428,10 +409,6 @@ s32 rtl8723bs_init_recv_priv(struct adapter *padapter) alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); } - - if (!precvbuf->pskb) { - DBG_871X("%s: alloc_skb fail!\n", __func__); - } } list_add_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue); diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index a3bd9c2002c9936c53455e82eb59b379a6167c1d..bd95e62fb053ff07171f6e66287e8e15af9fa1d8 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -19,18 +19,12 @@ static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num) if ( (padapter->bSurpriseRemoved) || (padapter->bDriverStopped) - ) { - DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__); + ) return false; - } HalQueryTxOQTBufferStatus8723BSdio(padapter); if ((++n % 60) == 0) { - if ((n % 300) == 0) { - DBG_871X("%s(%d): QOT free space(%d), agg_num: %d\n", - __func__, n, pHalData->SdioTxOQTFreeSpace, agg_num); - } msleep(1); /* yield(); */ } @@ -101,14 +95,8 @@ query_free_page: if ( (padapter->bSurpriseRemoved) || (padapter->bDriverStopped) - ) { - RT_TRACE( - _module_hal_xmit_c_, - _drv_notice_, - ("%s: bSurpriseRemoved(write port)\n", __func__) - ); + ) goto free_xmitbuf; - } if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == false) goto free_xmitbuf; @@ -124,10 +112,6 @@ free_xmitbuf: /* pxmitbuf->priv_data = NULL; */ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); -#ifdef CONFIG_SDIO_TX_TASKLET - tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); -#endif - return _FAIL; } @@ -149,24 +133,14 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter) pxmitpriv = &padapter->xmitpriv; if (wait_for_completion_interruptible(&pxmitpriv->xmit_comp)) { - DBG_871X_LEVEL(_drv_emerg_, "%s: down SdioXmitBufSema fail!\n", __func__); + netdev_emerg(padapter->pnetdev, + "%s: down SdioXmitBufSema fail!\n", __func__); return _FAIL; } ret = (padapter->bDriverStopped) || (padapter->bSurpriseRemoved); - if (ret) { - RT_TRACE( - _module_hal_xmit_c_, - _drv_err_, - ( - "%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n", - __func__, - padapter->bDriverStopped, - padapter->bSurpriseRemoved - ) - ); + if (ret) return _FAIL; - } queue_pending = check_pending_xmitbuf(pxmitpriv); @@ -256,22 +230,6 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv ptxservq = container_of(sta_plist, struct tx_servq, tx_pending); sta_plist = get_next(sta_plist); -#ifdef DBG_XMIT_BUF - DBG_871X( - "%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n", - __func__, - idx, - phwxmit->accnt, - ptxservq->qcnt - ); - DBG_871X( - "%s free_xmit_extbuf_cnt =%d free_xmitbuf_cnt =%d free_xmitframe_cnt =%d\n", - __func__, - pxmitpriv->free_xmit_extbuf_cnt, - pxmitpriv->free_xmitbuf_cnt, - pxmitpriv->free_xmitframe_cnt - ); -#endif pframe_queue = &ptxservq->sta_pending; frame_phead = get_list_head(pframe_queue); @@ -307,7 +265,9 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (!pxmitbuf) { #ifdef DBG_XMIT_BUF - DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __func__); + netdev_err(padapter->pnetdev, + "%s: xmit_buf is not enough!\n", + __func__); #endif err = -2; complete(&(pxmitpriv->xmit_comp)); @@ -317,19 +277,12 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv } /* ok to send, remove frame from queue */ - if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) { + if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) if ( (pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) && (pxmitframe->attrib.triggered == 0) - ) { - DBG_871X( - "%s: one not triggered pkt in queue when this STA sleep," - " break and goto next sta\n", - __func__ - ); + ) break; - } - } list_del_init(&pxmitframe->list); ptxservq->qcnt--; @@ -346,7 +299,9 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); if (ret == _FAIL) { - DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __func__); + netdev_err(padapter->pnetdev, + "%s: coalesce FAIL!", + __func__); /* Todo: error handler */ } else { k++; @@ -378,8 +333,6 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv /* dump xmit_buf to hw tx fifo */ if (pxmitbuf) { - RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len =%d enqueue\n", pxmitbuf->len)); - if (pxmitbuf->len > 0) { struct xmit_frame *pframe; pframe = (struct xmit_frame *)pxmitbuf->priv_data; @@ -419,7 +372,8 @@ static s32 rtl8723bs_xmit_handler(struct adapter *padapter) pxmitpriv = &padapter->xmitpriv; if (wait_for_completion_interruptible(&pxmitpriv->SdioXmitStart)) { - DBG_871X_LEVEL(_drv_emerg_, "%s: SdioXmitStart fail!\n", __func__); + netdev_emerg(padapter->pnetdev, "%s: SdioXmitStart fail!\n", + __func__); return _FAIL; } @@ -427,19 +381,8 @@ next: if ( (padapter->bDriverStopped) || (padapter->bSurpriseRemoved) - ) { - RT_TRACE( - _module_hal_xmit_c_, - _drv_notice_, - ( - "%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n", - __func__, - padapter->bDriverStopped, - padapter->bSurpriseRemoved - ) - ); + ) return _FAIL; - } spin_lock_bh(&pxmitpriv->lock); ret = rtw_txframes_pending(padapter); @@ -485,8 +428,6 @@ int rtl8723bs_xmit_thread(void *context) rtw_sprintf(thread_name, 20, "RTWHALXT-%s", ADPT_ARG(padapter)); thread_enter(thread_name); - DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); - do { ret = rtl8723bs_xmit_handler(padapter); if (signal_pending(current)) { @@ -496,8 +437,6 @@ int rtl8723bs_xmit_thread(void *context) complete(&pxmitpriv->SdioXmitTerminate); - RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __func__)); - thread_exit(); } @@ -513,8 +452,6 @@ s32 rtl8723bs_mgnt_xmit( u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; u8 txdesc_size = TXDESC_SIZE; - RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __func__)); - pattrib = &pmgntframe->attrib; pxmitbuf = pmgntframe->pxmitbuf; @@ -576,7 +513,6 @@ s32 rtl8723bs_hal_xmit( err = rtw_xmitframe_enqueue(padapter, pxmitframe); spin_unlock_bh(&pxmitpriv->lock); if (err != _SUCCESS) { - RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n")); rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitpriv->tx_drop++; @@ -601,11 +537,7 @@ s32 rtl8723bs_hal_xmitframe_enqueue( pxmitpriv->tx_drop++; } else { -#ifdef CONFIG_SDIO_TX_TASKLET - tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); -#else complete(&pxmitpriv->SdioXmitStart); -#endif } return err; diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c index 718ee9eee87c05b1a6c6d1ede337113e40dcec47..abd90026a8c78e5671ff01c5b172d7a218369106 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c +++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c @@ -42,63 +42,6 @@ static u8 CardEnable(struct adapter *padapter) return ret; } -#ifdef CONFIG_GPIO_WAKEUP -/* we set it high under init and fw will */ -/* give us Low Pulse when host wake up */ -void HostWakeUpGpioClear(struct adapter *Adapter) -{ - u32 value32; - - value32 = rtw_read32(Adapter, REG_GPIO_PIN_CTRL_2); - - /* set GPIO 12 1 */ - value32 |= BIT(12);/* 4+8 */ - /* GPIO 12 out put */ - value32 |= BIT(20);/* 4+16 */ - - rtw_write32(Adapter, REG_GPIO_PIN_CTRL_2, value32); -} /* HostWakeUpGpioClear */ - -void HalSetOutPutGPIO(struct adapter *padapter, u8 index, u8 OutPutValue) -{ - if (index <= 7) { - /* config GPIO mode */ - rtw_write8(padapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(index)); - - /* config GPIO Sel */ - /* 0: input */ - /* 1: output */ - rtw_write8(padapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 2) | BIT(index)); - - /* set output value */ - if (OutPutValue) - rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) | BIT(index)); - else - rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(index)); - } else { - /* 88C Series: */ - /* index: 11~8 transform to 3~0 */ - /* 8723 Series: */ - /* index: 12~8 transform to 4~0 */ - index -= 8; - - /* config GPIO mode */ - rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 3) & ~BIT(index)); - - /* config GPIO Sel */ - /* 0: input */ - /* 1: output */ - rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 2) | BIT(index)); - - /* set output value */ - if (OutPutValue) - rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) | BIT(index)); - else - rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) & ~BIT(index)); - } -} -#endif - static u8 _InitPowerOn_8723BS(struct adapter *padapter) { @@ -110,31 +53,11 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter) /* all of these MUST be configured before power on */ -#ifdef CONFIG_EXT_CLK - /* Use external crystal(XTAL) */ - value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B + 2); - value8 |= BIT(7); - rtw_write8(padapter, REG_PAD_CTRL1_8723B + 2, value8); - - /* CLK_REQ High active or Low Active */ - /* Request GPIO polarity: */ - /* 0: low active */ - /* 1: high active */ - value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL + 1); - value8 |= BIT(5); - rtw_write8(padapter, REG_MULTI_FUNC_CTRL + 1, value8); -#endif /* CONFIG_EXT_CLK */ /* only cmd52 can be used before power on(card enable) */ ret = CardEnable(padapter); - if (!ret) { - RT_TRACE( - _module_hci_hal_init_c_, - _drv_emerg_, - ("%s: run power on flow fail\n", __func__) - ); + if (!ret) return _FAIL; - } /* Radio-Off Pin Trigger */ value8 = rtw_read8(padapter, REG_GPIO_INTM + 1); @@ -178,21 +101,14 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter) /* Switch the control of EESK, EECS to RFC for DPDT or Antenna switch */ value16 |= BIT(11); /* BIT_EEPRPAD_RFE_CTRL_EN */ rtw_write16(padapter, REG_PWR_DATA, value16); -/* DBG_8192C("%s: REG_PWR_DATA(0x%x) = 0x%04X\n", __func__, REG_PWR_DATA, rtw_read16(padapter, REG_PWR_DATA)); */ value32 = rtw_read32(padapter, REG_LEDCFG0); value32 |= BIT(23); /* DPDT_SEL_EN, 1 for SW control */ rtw_write32(padapter, REG_LEDCFG0, value32); -/* DBG_8192C("%s: REG_LEDCFG0(0x%x) = 0x%08X\n", __func__, REG_LEDCFG0, rtw_read32(padapter, REG_LEDCFG0)); */ value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B); value8 &= ~BIT(0); /* BIT_SW_DPDT_SEL_DATA, DPDT_SEL default configuration */ rtw_write8(padapter, REG_PAD_CTRL1_8723B, value8); -/* DBG_8192C("%s: REG_PAD_CTRL1(0x%x) = 0x%02X\n", __func__, REG_PAD_CTRL1_8723B, rtw_read8(padapter, REG_PAD_CTRL1_8723B)); */ - -#ifdef CONFIG_GPIO_WAKEUP - HostWakeUpGpioClear(padapter); -#endif return _SUCCESS; } @@ -214,7 +130,6 @@ static void _init_available_page_threshold(struct adapter *padapter, u8 numHQ, u rtw_write16(padapter, 0x218, HQ_threshold); rtw_write16(padapter, 0x21A, NQ_threshold); rtw_write16(padapter, 0x21C, LQ_threshold); - DBG_8192C("%s(): Enable Tx FIFO Page Threshold H:0x%x, N:0x%x, L:0x%x\n", __func__, HQ_threshold, NQ_threshold, LQ_threshold); } static void _InitQueueReservedPage(struct adapter *padapter) @@ -660,7 +575,6 @@ static void _InitRFType(struct adapter *padapter) pHalData->rf_chip = RF_6052; pHalData->rf_type = RF_1T1R; - DBG_8192C("Set RF Chip ID to RF_6052 and RF type to 1T1R.\n"); } static void _RfPowerSave(struct adapter *padapter) @@ -686,8 +600,6 @@ static bool HalDetectPwrDownMode(struct adapter *Adapter) else pHalData->pwrdown = false; - DBG_8192C("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown); - return pHalData->pwrdown; } /* HalDetectPwrDownMode */ @@ -710,8 +622,6 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) u8 cpwm_orig, cpwm_now; u8 val8, bMacPwrCtrlOn = true; - DBG_871X("%s: Leaving IPS in FWLPS state\n", __func__); - /* for polling cpwm */ cpwm_orig = 0; rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig); @@ -722,7 +632,6 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) val8 += 0x80; val8 |= BIT(6); rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8); - DBG_871X("%s: write rpwm =%02x\n", __func__, val8); adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80; /* do polling cpwm */ @@ -735,10 +644,9 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) if ((cpwm_orig ^ cpwm_now) & 0x80) break; - if (jiffies_to_msecs(jiffies - start_time) > 100) { - DBG_871X("%s: polling cpwm timeout when leaving IPS in FWLPS state\n", __func__); + if (jiffies_to_msecs(jiffies - start_time) > 100) break; - } + } while (1); rtl8723b_set_FwPwrModeInIPS_cmd(padapter, 0); @@ -750,49 +658,21 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) return _SUCCESS; } -#ifdef CONFIG_WOWLAN - if (rtw_read8(padapter, REG_MCUFWDL) & BIT7) { - u8 reg_val = 0; - DBG_871X("+Reset Entry+\n"); - rtw_write8(padapter, REG_MCUFWDL, 0x00); - _8051Reset8723(padapter); - /* reset BB */ - reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN); - reg_val &= ~(BIT(0) | BIT(1)); - rtw_write8(padapter, REG_SYS_FUNC_EN, reg_val); - /* reset RF */ - rtw_write8(padapter, REG_RF_CTRL, 0); - /* reset TRX path */ - rtw_write16(padapter, REG_CR, 0); - /* reset MAC, Digital Core */ - reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); - reg_val &= ~(BIT(4) | BIT(7)); - rtw_write8(padapter, REG_SYS_FUNC_EN + 1, reg_val); - reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); - reg_val |= BIT(4) | BIT(7); - rtw_write8(padapter, REG_SYS_FUNC_EN + 1, reg_val); - DBG_871X("-Reset Entry-\n"); - } -#endif /* CONFIG_WOWLAN */ /* Disable Interrupt first. */ /* rtw_hal_disable_interrupt(padapter); */ ret = _InitPowerOn_8723BS(padapter); - if (_FAIL == ret) { - RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init Power On!\n")); + if (ret == _FAIL) return _FAIL; - } rtw_write8(padapter, REG_EARLY_MODE_CONTROL, 0); ret = rtl8723b_FirmwareDownload(padapter, false); if (ret != _SUCCESS) { - RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("%s: Download Firmware failed!!\n", __func__)); padapter->bFWReady = false; pHalData->fw_ractrl = false; return ret; } else { - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("rtl8723bs_hal_init(): Download Firmware Success!!\n")); padapter->bFWReady = true; pHalData->fw_ractrl = true; } @@ -817,20 +697,16 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) #if (HAL_MAC_ENABLE == 1) ret = PHY_MACConfig8723B(padapter); - if (ret != _SUCCESS) { - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Fail to configure MAC!!\n")); + if (ret != _SUCCESS) return ret; - } #endif /* */ /* d. Initialize BB related configurations. */ /* */ #if (HAL_BB_ENABLE == 1) ret = PHY_BBConfig8723B(padapter); - if (ret != _SUCCESS) { - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Fail to configure BB!!\n")); + if (ret != _SUCCESS) return ret; - } #endif /* If RF is on, we need to init RF. Otherwise, skip the procedure. */ @@ -839,10 +715,8 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) { #if (HAL_RF_ENABLE == 1) ret = PHY_RFConfig8723B(padapter); - if (ret != _SUCCESS) { - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Fail to configure RF!!\n")); + if (ret != _SUCCESS) return ret; - } #endif } @@ -850,9 +724,9 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) /* Joseph Note: Keep RfRegChnlVal for later use. */ /* */ pHalData->RfRegChnlVal[0] = - PHY_QueryRFReg(padapter, (enum RF_PATH)0, RF_CHNLBW, bRFRegOffsetMask); + PHY_QueryRFReg(padapter, (enum rf_path)0, RF_CHNLBW, bRFRegOffsetMask); pHalData->RfRegChnlVal[1] = - PHY_QueryRFReg(padapter, (enum RF_PATH)1, RF_CHNLBW, bRFRegOffsetMask); + PHY_QueryRFReg(padapter, (enum rf_path)1, RF_CHNLBW, bRFRegOffsetMask); /* if (!pHalData->bMACFuncEnable) { */ @@ -861,10 +735,9 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) /* init LLT after tx buffer boundary is defined */ ret = rtl8723b_InitLLTTable(padapter); - if (_SUCCESS != ret) { - DBG_8192C("%s: Failed to init LLT Table!\n", __func__); + if (ret != _SUCCESS) return _FAIL; - } + /* */ _InitQueuePriority(padapter); _InitPageBoundary(padapter); @@ -992,8 +865,6 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter) /* Init BT hw config. */ hal_btcoex_InitHwConfig(padapter, false); - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("-%s\n", __func__)); - return _SUCCESS; } @@ -1011,9 +882,6 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter) /* Run LPS WL RFOFF flow */ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_enter_lps_flow); - if (ret == _FAIL) { - DBG_8192C(KERN_ERR "%s: run RF OFF flow fail!\n", __func__); - } /* ==== Reset digital sequence ====== */ @@ -1044,9 +912,6 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter) ret = false; rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_disable_flow); - if (!ret) { - DBG_8192C(KERN_ERR "%s: run CARD DISABLE flow fail!\n", __func__); - } } static u32 rtl8723bs_hal_deinit(struct adapter *padapter) @@ -1060,14 +925,11 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter) int cnt = 0; u8 val8 = 0; - DBG_871X("%s: issue H2C to FW when entering IPS\n", __func__); - rtl8723b_set_FwPwrModeInIPS_cmd(padapter, 0x3); /* poll 0x1cc to make sure H2C command already finished by FW; MAC_0x1cc = 0 means H2C done by FW. */ do { val8 = rtw_read8(padapter, REG_HMETFR); cnt++; - DBG_871X("%s polling REG_HMETFR = 0x%x, cnt =%d\n", __func__, val8, cnt); mdelay(10); } while (cnt < 100 && (val8 != 0)); /* H2C done, enter 32k */ @@ -1077,32 +939,15 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter) val8 += 0x80; val8 |= BIT(0); rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8); - DBG_871X("%s: write rpwm =%02x\n", __func__, val8); adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80; cnt = val8 = 0; do { val8 = rtw_read8(padapter, REG_CR); cnt++; - DBG_871X("%s polling 0x100 = 0x%x, cnt =%d\n", __func__, val8, cnt); mdelay(10); } while (cnt < 100 && (val8 != 0xEA)); - } else { - DBG_871X( - "MAC_1C0 =%08x, MAC_1C4 =%08x, MAC_1C8 =%08x, MAC_1CC =%08x\n", - rtw_read32(padapter, 0x1c0), - rtw_read32(padapter, 0x1c4), - rtw_read32(padapter, 0x1c8), - rtw_read32(padapter, 0x1cc) - ); } - DBG_871X( - "polling done when entering IPS, check result : 0x100 = 0x%x, cnt =%d, MAC_1cc = 0x%02x\n", - rtw_read8(padapter, REG_CR), - cnt, - rtw_read8(padapter, REG_HMETFR) - ); - adapter_to_pwrctl(padapter)->pre_ips_type = 0; } else { @@ -1129,10 +974,6 @@ static u32 rtl8723bs_inirp_init(struct adapter *padapter) static u32 rtl8723bs_inirp_deinit(struct adapter *padapter) { - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+rtl8723bs_inirp_deinit\n")); - - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("-rtl8723bs_inirp_deinit\n")); - return _SUCCESS; } @@ -1229,10 +1070,6 @@ static void Hal_EfuseParseMACAddr_8723BS( /* Read Permanent MAC address */ memcpy(pEEPROM->mac_addr, &hwinfo[EEPROM_MAC_ADDR_8723BS], ETH_ALEN); } -/* NicIFSetMacAddress(padapter, padapter->PermanentAddress); */ - - RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, - ("Hal_EfuseParseMACAddr_8723BS: Permanent Address = %pM\n", pEEPROM->mac_addr)); } static void Hal_EfuseParseBoardType_8723BS( @@ -1247,7 +1084,6 @@ static void Hal_EfuseParseBoardType_8723BS( pHalData->BoardType = (EEPROM_DEFAULT_BOARD_OPTION & 0xE0) >> 5; } else pHalData->BoardType = 0; - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Board Type: 0x%2x\n", pHalData->BoardType)); } static void _ReadEfuseInfo8723BS(struct adapter *padapter) @@ -1255,15 +1091,10 @@ static void _ReadEfuseInfo8723BS(struct adapter *padapter) struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); u8 *hwinfo = NULL; - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("====>_ReadEfuseInfo8723BS()\n")); - /* */ /* This part read and parse the eeprom/efuse content */ /* */ - if (sizeof(pEEPROM->efuse_eeprom_data) < HWSET_MAX_SIZE_8723B) - DBG_871X("[WARNING] size of efuse_eeprom_data is less than HWSET_MAX_SIZE_8723B!\n"); - hwinfo = pEEPROM->efuse_eeprom_data; Hal_InitPGData(padapter, hwinfo); @@ -1289,13 +1120,7 @@ static void _ReadEfuseInfo8723BS(struct adapter *padapter) Hal_EfuseParseVoltage_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); -#ifdef CONFIG_WOWLAN - Hal_DetectWoWMode(padapter); -#endif - Hal_ReadRFGainOffset(padapter, hwinfo, pEEPROM->bautoload_fail_flag); - - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<==== _ReadEfuseInfo8723BS()\n")); } static void _ReadPROMContent(struct adapter *padapter) @@ -1308,12 +1133,6 @@ static void _ReadPROMContent(struct adapter *padapter) pEEPROM->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false; pEEPROM->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true; - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, - ("%s: 9346CR = 0x%02X, Boot from %s, Autoload %s\n", - __func__, eeValue, - (pEEPROM->EepromOrEfuse ? "EEPROM" : "EFUSE"), - (pEEPROM->bautoload_fail_flag ? "Fail" : "OK"))); - /* pHalData->EEType = IS_BOOT_FROM_EEPROM(Adapter) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; */ _ReadEfuseInfo8723BS(padapter); @@ -1334,9 +1153,6 @@ static void _InitOtherVariable(struct adapter *Adapter) static s32 _ReadAdapterInfo8723BS(struct adapter *padapter) { u8 val8; - unsigned long start; - - RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+_ReadAdapterInfo8723BS\n")); /* before access eFuse, make sure card enable has been called */ if (!padapter->hw_init_completed) @@ -1344,13 +1160,9 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter) val8 = rtw_read8(padapter, 0x4e); - MSG_8192C("%s, 0x4e = 0x%x\n", __func__, val8); val8 |= BIT(6); rtw_write8(padapter, 0x4e, val8); - - start = jiffies; - _EfuseCellSel(padapter); _ReadRFType(padapter); _ReadPROMContent(padapter); @@ -1361,9 +1173,6 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter) CardDisableRTL8723BSdio(padapter);/* for the power consumption issue, wifi ko module is loaded during booting, but wifi GUI is off */ } - - MSG_8192C("<==== _ReadAdapterInfo8723BS in %d ms\n", jiffies_to_msecs(jiffies - start)); - return _SUCCESS; } @@ -1383,23 +1192,6 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) { u8 val8; -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) - struct wowlan_ioctl_param *poidparam; - struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); - int res; - u32 tmp; - u16 len = 0; - u8 trycnt = 100; - u32 himr = 0; -#if defined(CONFIG_WOWLAN) - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct sta_info *psta = NULL; - u64 iv_low = 0, iv_high = 0; - u8 mstatus = (*(u8 *)val); -#endif -#endif - switch (variable) { case HW_VAR_SET_RPWM: /* rpwm value only use BIT0(clock bit) , BIT6(Ack bit), and BIT7(Toggle bit) */ @@ -1424,322 +1216,6 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) val8 = *val; break; -#ifdef CONFIG_WOWLAN - case HW_VAR_WOWLAN: - { - poidparam = (struct wowlan_ioctl_param *)val; - switch (poidparam->subcode) { - case WOWLAN_ENABLE: - DBG_871X_LEVEL(_drv_always_, "WOWLAN_ENABLE\n"); - - /* backup data rate to register 0x8b for wowlan FW */ - rtw_write8(padapter, 0x8d, 1); - rtw_write8(padapter, 0x8c, 0); - rtw_write8(padapter, 0x8f, 0x40); - rtw_write8(padapter, 0x8b, - rtw_read8(padapter, 0x2f0)); - - /* 1. Download WOWLAN FW */ - DBG_871X_LEVEL(_drv_always_, "Re-download WoWlan FW!\n"); - SetFwRelatedForWoWLAN8723b(padapter, true); - - /* 2. RX DMA stop */ - DBG_871X_LEVEL(_drv_always_, "Pause DMA\n"); - rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM) | RW_RELEASE_EN)); - do { - if ((rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE)) { - DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n"); - break; - } else { - /* If RX_DMA is not idle, receive one pkt from DMA */ - res = sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, (u8 *)&tmp); - len = le16_to_cpu(tmp); - DBG_871X_LEVEL(_drv_always_, "RX len:%d\n", len); - if (len > 0) - res = RecvOnePkt(padapter, len); - else - DBG_871X_LEVEL(_drv_always_, "read length fail %d\n", len); - - DBG_871X_LEVEL(_drv_always_, "RecvOnePkt Result: %d\n", res); - } - } while (trycnt--); - if (trycnt == 0) - DBG_871X_LEVEL(_drv_always_, "Stop RX DMA failed......\n"); - - /* 3. Clear IMR and ISR */ - DBG_871X_LEVEL(_drv_always_, "Clear IMR and ISR\n"); - tmp = 0; - sdio_local_write(padapter, SDIO_REG_HIMR_ON, 4, (u8 *)&tmp); - sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); - sdio_local_read(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); - sdio_local_write(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); - - /* 4. Enable CPWM2 only */ - DBG_871X_LEVEL(_drv_always_, "Enable only CPWM2\n"); - sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); - DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp); - - himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK; - sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr); - - sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); - DBG_871X("DisableInterruptButCpwm28723BSdio(): Read again SDIO_REG_HIMR: 0x%08x\n", tmp); - - /* 5. Set Enable WOWLAN H2C command. */ - DBG_871X_LEVEL(_drv_always_, "Set Enable WOWLan cmd\n"); - rtl8723b_set_wowlan_cmd(padapter, 1); - - /* 6. Check EnableWoWlan CMD is ready */ - if (!pwrctl->wowlan_pno_enable) { - DBG_871X_LEVEL(_drv_always_, "Check EnableWoWlan CMD is ready\n"); - mstatus = rtw_read8(padapter, REG_WOW_CTRL); - trycnt = 10; - while (!(mstatus & BIT1) && trycnt > 1) { - mstatus = rtw_read8(padapter, REG_WOW_CTRL); - DBG_871X("Loop index: %d :0x%02x\n", trycnt, mstatus); - trycnt--; - msleep(2); - } - } - break; - - case WOWLAN_DISABLE: - DBG_871X_LEVEL(_drv_always_, "WOWLAN_DISABLE\n"); - - psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv)); - if (psta) - rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_DISCONNECT, psta->mac_id); - else - DBG_871X("psta is null\n"); - - /* 1. Read wakeup reason */ - pwrctl->wowlan_wake_reason = rtw_read8(padapter, REG_WOWLAN_WAKE_REASON); - DBG_871X_LEVEL( - _drv_always_, - "wakeup_reason: 0x%02x, mac_630 = 0x%08x, mac_634 = 0x%08x, mac_1c0 = 0x%08x, mac_1c4 = 0x%08x" - ", mac_494 = 0x%08x, , mac_498 = 0x%08x, mac_49c = 0x%08x, mac_608 = 0x%08x, mac_4a0 = 0x%08x, mac_4a4 = 0x%08x\n" - ", mac_1cc = 0x%08x, mac_2f0 = 0x%08x, mac_2f4 = 0x%08x, mac_2f8 = 0x%08x, mac_2fc = 0x%08x, mac_8c = 0x%08x", - pwrctl->wowlan_wake_reason, - rtw_read32(padapter, REG_WOWLAN_GTK_DBG1), - rtw_read32(padapter, REG_WOWLAN_GTK_DBG2), - rtw_read32(padapter, 0x1c0), - rtw_read32(padapter, 0x1c4), - rtw_read32(padapter, 0x494), - rtw_read32(padapter, 0x498), - rtw_read32(padapter, 0x49c), - rtw_read32(padapter, 0x608), - rtw_read32(padapter, 0x4a0), - rtw_read32(padapter, 0x4a4), - rtw_read32(padapter, 0x1cc), - rtw_read32(padapter, 0x2f0), - rtw_read32(padapter, 0x2f4), - rtw_read32(padapter, 0x2f8), - rtw_read32(padapter, 0x2fc), - rtw_read32(padapter, 0x8c) - ); -#ifdef CONFIG_PNO_SET_DEBUG - DBG_871X("0x1b9: 0x%02x, 0x632: 0x%02x\n", rtw_read8(padapter, 0x1b9), rtw_read8(padapter, 0x632)); - DBG_871X("0x4fc: 0x%02x, 0x4fd: 0x%02x\n", rtw_read8(padapter, 0x4fc), rtw_read8(padapter, 0x4fd)); - DBG_871X("TXDMA STATUS: 0x%08x\n", rtw_read32(padapter, REG_TXDMA_STATUS)); -#endif - - { - /* 2. Set Disable WOWLAN H2C command. */ - DBG_871X_LEVEL(_drv_always_, "Set Disable WOWLan cmd\n"); - rtl8723b_set_wowlan_cmd(padapter, 0); - - /* 3. Check Disable WoWlan CMD ready. */ - DBG_871X_LEVEL(_drv_always_, "Check DisableWoWlan CMD is ready\n"); - mstatus = rtw_read8(padapter, REG_WOW_CTRL); - trycnt = 50; - while (mstatus & BIT1 && trycnt > 1) { - mstatus = rtw_read8(padapter, REG_WOW_CTRL); - DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus); - trycnt--; - msleep(10); - } - - if (mstatus & BIT1) { - DBG_871X_LEVEL(_drv_always_, "Disable WOW mode fail!!\n"); - DBG_871X("Set 0x690 = 0x00\n"); - rtw_write8(padapter, REG_WOW_CTRL, (rtw_read8(padapter, REG_WOW_CTRL) & 0xf0)); - DBG_871X_LEVEL(_drv_always_, "Release RXDMA\n"); - rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); - } - - /* 3.1 read fw iv */ - iv_low = rtw_read32(padapter, REG_TXPKTBUF_IV_LOW); - /* only low two bytes is PN, check AES_IV macro for detail */ - iv_low &= 0xffff; - iv_high = rtw_read32(padapter, REG_TXPKTBUF_IV_HIGH); - /* get the real packet number */ - pwrctl->wowlan_fw_iv = iv_high << 16 | iv_low; - DBG_871X_LEVEL(_drv_always_, "fw_iv: 0x%016llx\n", pwrctl->wowlan_fw_iv); - /* Update TX iv data. */ - rtw_set_sec_pn(padapter); - - /* 3.2 read GTK index and key */ - if ( - psecuritypriv->binstallKCK_KEK == true && - psecuritypriv->dot11PrivacyAlgrthm == _AES_ - ) { - u8 gtk_keyindex = 0; - u8 get_key[16]; - /* read gtk key index */ - gtk_keyindex = rtw_read8(padapter, 0x48c); - - if (gtk_keyindex < 4) { - psecuritypriv->dot118021XGrpKeyid = gtk_keyindex; - read_cam(padapter, gtk_keyindex, get_key); - memcpy(psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, get_key, 16); - DBG_871X_LEVEL( - _drv_always_, - "GTK (%d) = 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", - gtk_keyindex, - psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[0], - psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[1], - psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[2], - psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[3] - ); - } else - DBG_871X_LEVEL(_drv_always_, "GTK index =%d\n", gtk_keyindex); - } - - /* 4. Re-download Normal FW. */ - DBG_871X_LEVEL(_drv_always_, "Re-download Normal FW!\n"); - SetFwRelatedForWoWLAN8723b(padapter, false); - } -#ifdef CONFIG_GPIO_WAKEUP - DBG_871X_LEVEL(_drv_always_, "Set Wake GPIO to high for default.\n"); - HalSetOutPutGPIO(padapter, WAKEUP_GPIO_IDX, 1); -#endif - - /* 5. Download reserved pages and report media status if needed. */ - if ( - (pwrctl->wowlan_wake_reason != FWDecisionDisconnect) && - (pwrctl->wowlan_wake_reason != Rx_Pairwisekey) && - (pwrctl->wowlan_wake_reason != Rx_DisAssoc) && - (pwrctl->wowlan_wake_reason != Rx_DeAuth) - ) { - rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); - if (psta) - rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id); - } -#ifdef CONFIG_PNO_SUPPORT - rtw_write8(padapter, 0x1b8, 0); - DBG_871X("reset 0x1b8: %d\n", rtw_read8(padapter, 0x1b8)); - rtw_write8(padapter, 0x1b9, 0); - DBG_871X("reset 0x1b9: %d\n", rtw_read8(padapter, 0x1b9)); - rtw_write8(padapter, REG_PNO_STATUS, 0); - DBG_871X("reset REG_PNO_STATUS: %d\n", rtw_read8(padapter, REG_PNO_STATUS)); -#endif - break; - - default: - break; - } - } - break; -#endif /* CONFIG_WOWLAN */ -#ifdef CONFIG_AP_WOWLAN - case HW_VAR_AP_WOWLAN: - { - poidparam = (struct wowlan_ioctl_param *)val; - switch (poidparam->subcode) { - case WOWLAN_AP_ENABLE: - DBG_871X("%s, WOWLAN_AP_ENABLE\n", __func__); - /* 1. Download WOWLAN FW */ - DBG_871X_LEVEL(_drv_always_, "Re-download WoWlan FW!\n"); - SetFwRelatedForWoWLAN8723b(padapter, true); - - /* 2. RX DMA stop */ - DBG_871X_LEVEL(_drv_always_, "Pause DMA\n"); - rtw_write32(padapter, REG_RXPKT_NUM, - (rtw_read32(padapter, REG_RXPKT_NUM) | RW_RELEASE_EN)); - do { - if ((rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE)) { - DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n"); - break; - } else { - /* If RX_DMA is not idle, receive one pkt from DMA */ - res = sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, (u8 *)&tmp); - len = le16_to_cpu(tmp); - - DBG_871X_LEVEL(_drv_always_, "RX len:%d\n", len); - if (len > 0) - res = RecvOnePkt(padapter, len); - else - DBG_871X_LEVEL(_drv_always_, "read length fail %d\n", len); - - DBG_871X_LEVEL(_drv_always_, "RecvOnePkt Result: %d\n", res); - } - } while (trycnt--); - - if (trycnt == 0) - DBG_871X_LEVEL(_drv_always_, "Stop RX DMA failed......\n"); - - /* 3. Clear IMR and ISR */ - DBG_871X_LEVEL(_drv_always_, "Clear IMR and ISR\n"); - tmp = 0; - sdio_local_write(padapter, SDIO_REG_HIMR_ON, 4, (u8 *)&tmp); - sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); - sdio_local_read(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); - sdio_local_write(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); - - /* 4. Enable CPWM2 only */ - DBG_871X_LEVEL(_drv_always_, "Enable only CPWM2\n"); - sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); - DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp); - - himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK; - sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr); - - sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); - DBG_871X("DisableInterruptButCpwm28723BSdio(): Read again SDIO_REG_HIMR: 0x%08x\n", tmp); - - /* 5. Set Enable WOWLAN H2C command. */ - DBG_871X_LEVEL(_drv_always_, "Set Enable AP WOWLan cmd\n"); - rtl8723b_set_ap_wowlan_cmd(padapter, 1); - /* 6. add some delay for H2C cmd ready */ - msleep(10); - - rtw_write8(padapter, REG_WOWLAN_WAKE_REASON, 0); - break; - case WOWLAN_AP_DISABLE: - DBG_871X("%s, WOWLAN_AP_DISABLE\n", __func__); - /* 1. Read wakeup reason */ - pwrctl->wowlan_wake_reason = - rtw_read8(padapter, REG_WOWLAN_WAKE_REASON); - - DBG_871X_LEVEL(_drv_always_, "wakeup_reason: 0x%02x\n", - pwrctl->wowlan_wake_reason); - - /* 2. Set Disable WOWLAN H2C command. */ - DBG_871X_LEVEL(_drv_always_, "Set Disable WOWLan cmd\n"); - rtl8723b_set_ap_wowlan_cmd(padapter, 0); - /* 6. add some delay for H2C cmd ready */ - msleep(2); - - DBG_871X_LEVEL(_drv_always_, "Release RXDMA\n"); - - rtw_write32(padapter, REG_RXPKT_NUM, - (rtw_read32(padapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); - - SetFwRelatedForWoWLAN8723b(padapter, false); - -#ifdef CONFIG_GPIO_WAKEUP - DBG_871X_LEVEL(_drv_always_, "Set Wake GPIO to high for default.\n"); - HalSetOutPutGPIO(padapter, WAKEUP_GPIO_IDX, 1); -#endif /* CONFIG_GPIO_WAKEUP */ - rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); - issue_beacon(padapter, 0); - break; - default: - break; - } -} - break; -#endif /* CONFIG_AP_WOWLAN */ case HW_VAR_DM_IN_LPS: rtl8723b_hal_dm_in_lps(padapter); break; @@ -1776,7 +1252,6 @@ static void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf { switch (variable) { case HW_VAR_C2H_HANDLE: - /* DBG_8192C("%s len =%d\n", __func__, len); */ C2HPacketHandler_8723B(padapter, pbuf, len); break; default: @@ -1789,7 +1264,7 @@ static void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf /* Query setting of specified variable. */ /* */ static u8 GetHalDefVar8723BSDIO( - struct adapter *Adapter, enum HAL_DEF_VARIABLE eVariable, void *pValue + struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue ) { u8 bResult = _SUCCESS; @@ -1817,7 +1292,7 @@ static u8 GetHalDefVar8723BSDIO( /* Change default setting of specified variable. */ /* */ static u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, - enum HAL_DEF_VARIABLE eVariable, void *pValue) + enum hal_def_variable eVariable, void *pValue) { return SetHalDefVar8723B(Adapter, eVariable, pValue); } @@ -1847,9 +1322,6 @@ void rtl8723bs_set_hal_ops(struct adapter *padapter) pHalFunc->enable_interrupt = &EnableInterrupt8723BSdio; pHalFunc->disable_interrupt = &DisableInterrupt8723BSdio; pHalFunc->check_ips_status = &CheckIPSStatus; -#ifdef CONFIG_WOWLAN - pHalFunc->clear_interrupt = &ClearInterrupt8723BSdio; -#endif pHalFunc->SetHwRegHandler = &SetHwReg8723BS; pHalFunc->GetHwRegHandler = &GetHwReg8723BS; pHalFunc->SetHwRegHandlerWithBuf = &SetHwRegWithBuf8723B; @@ -1859,11 +1331,4 @@ void rtl8723bs_set_hal_ops(struct adapter *padapter) pHalFunc->hal_xmit = &rtl8723bs_hal_xmit; pHalFunc->mgnt_xmit = &rtl8723bs_mgnt_xmit; pHalFunc->hal_xmitframe_enqueue = &rtl8723bs_hal_xmitframe_enqueue; - -#if defined(CONFIG_CHECK_BT_HANG) - pHalFunc->hal_init_checkbthang_workqueue = &rtl8723bs_init_checkbthang_workqueue; - pHalFunc->hal_free_checkbthang_workqueue = &rtl8723bs_free_checkbthang_workqueue; - pHalFunc->hal_cancle_checkbthang_workqueue = &rtl8723bs_cancle_checkbthang_workqueue; - pHalFunc->hal_checke_bt_hang = &rtl8723bs_hal_check_bt_hang; -#endif } diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c index 369f55d115192d42a70887975c47f5b6a41d8586..a31694525bc1ee500fd26ea5e3afe5e6560dc4ae 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_ops.c +++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c @@ -10,16 +10,13 @@ #include <rtw_debug.h> #include <rtl8723b_hal.h> -/* define SDIO_DEBUG_IO 1 */ - - /* */ /* Description: */ /* The following mapping is for SDIO host local register space. */ /* */ /* Creadted by Roger, 2011.01.31. */ /* */ -static void HalSdioGetCmdAddr8723BSdio( +static void hal_sdio_get_cmd_addr_8723b( struct adapter *adapter, u8 device_id, u32 addr, @@ -95,10 +92,6 @@ static u8 get_deviceid(u32 addr) return devide_id; } -/* - * Ref: - *HalSdioGetCmdAddr8723BSdio() - */ static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset) { u8 device_id; @@ -177,19 +170,10 @@ static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr) if ( ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || (!mac_pwr_ctrl_on) || - (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) ) { err = sd_cmd52_read(intfhdl, ftaddr, 4, (u8 *)&le_tmp); -#ifdef SDIO_DEBUG_IO - if (!err) { -#endif - return le32_to_cpu(le_tmp); -#ifdef SDIO_DEBUG_IO - } - - DBG_8192C(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr = 0x%x\n", __func__, err, addr); - return SDIO_ERR_VAL32; -#endif + return le32_to_cpu(le_tmp); } /* 4 bytes alignment */ @@ -200,10 +184,8 @@ static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr) u8 *tmpbuf; tmpbuf = rtw_malloc(8); - if (!tmpbuf) { - DBG_8192C(KERN_ERR "%s: Allocate memory FAIL!(size =8) addr = 0x%x\n", __func__, addr); + if (!tmpbuf) return SDIO_ERR_VAL32; - } ftaddr &= ~(u16)0x3; sd_read(intfhdl, ftaddr, 8, tmpbuf); @@ -234,7 +216,7 @@ static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) if ( ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || (!mac_pwr_ctrl_on) || - (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) ) return sd_cmd52_read(intfhdl, ftaddr, cnt, buf); @@ -301,7 +283,7 @@ static s32 sdio_write32(struct intf_hdl *intfhdl, u32 addr, u32 val) if ( ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || (!mac_pwr_ctrl_on) || - (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) ) { le_tmp = cpu_to_le32(val); @@ -338,7 +320,7 @@ static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) if ( ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || (!mac_pwr_ctrl_on) || - (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) ) return sd_cmd52_write(intfhdl, ftaddr, cnt, buf); @@ -426,7 +408,7 @@ static u32 sdio_read_port( psdio = &adapter_to_dvobj(adapter)->intf_data; hal = GET_HAL_DATA(adapter); - HalSdioGetCmdAddr8723BSdio(adapter, addr, hal->SdioRxFIFOCnt++, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, addr, hal->SdioRxFIFOCnt++, &addr); if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); @@ -469,13 +451,11 @@ static u32 sdio_write_port( adapter = intfhdl->padapter; psdio = &adapter_to_dvobj(adapter)->intf_data; - if (!adapter->hw_init_completed) { - DBG_871X("%s [addr = 0x%x cnt =%d] adapter->hw_init_completed == false\n", __func__, addr, cnt); + if (!adapter->hw_init_completed) return _FAIL; - } cnt = round_up(cnt, 4); - HalSdioGetCmdAddr8723BSdio(adapter, addr, cnt >> 2, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, addr, cnt >> 2, &addr); if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); @@ -528,7 +508,7 @@ static s32 _sdio_local_read( intfhdl = &adapter->iopriv.intf; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); if (!mac_pwr_ctrl_on) @@ -566,12 +546,12 @@ s32 sdio_local_read( intfhdl = &adapter->iopriv.intf; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); if ( (!mac_pwr_ctrl_on) || - (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) ) return sd_cmd52_read(intfhdl, addr, cnt, buf); @@ -604,20 +584,14 @@ s32 sdio_local_write( s32 err; u8 *tmpbuf; - if (addr & 0x3) - DBG_8192C("%s, address must be 4 bytes alignment\n", __func__); - - if (cnt & 0x3) - DBG_8192C("%s, size must be the multiple of 4\n", __func__); - intfhdl = &adapter->iopriv.intf; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); if ( (!mac_pwr_ctrl_on) || - (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) ) return sd_cmd52_write(intfhdl, addr, cnt, buf); @@ -639,24 +613,24 @@ u8 SdioLocalCmd52Read1Byte(struct adapter *adapter, u32 addr) u8 val = 0; struct intf_hdl *intfhdl = &adapter->iopriv.intf; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); sd_cmd52_read(intfhdl, addr, 1, &val); return val; } -static u16 SdioLocalCmd52Read2Byte(struct adapter *adapter, u32 addr) +static u16 sdio_local_cmd52_read2byte(struct adapter *adapter, u32 addr) { __le16 val = 0; struct intf_hdl *intfhdl = &adapter->iopriv.intf; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); sd_cmd52_read(intfhdl, addr, 2, (u8 *)&val); return le16_to_cpu(val); } -static u32 SdioLocalCmd53Read4Byte(struct adapter *adapter, u32 addr) +static u32 sdio_local_cmd53_read4byte(struct adapter *adapter, u32 addr) { u8 mac_pwr_ctrl_on; @@ -664,9 +638,9 @@ static u32 SdioLocalCmd53Read4Byte(struct adapter *adapter, u32 addr) struct intf_hdl *intfhdl = &adapter->iopriv.intf; __le32 le_tmp; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); - if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) { + if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) { sd_cmd52_read(intfhdl, addr, 4, (u8 *)&le_tmp); val = le32_to_cpu(le_tmp); } else { @@ -679,21 +653,21 @@ void SdioLocalCmd52Write1Byte(struct adapter *adapter, u32 addr, u8 v) { struct intf_hdl *intfhdl = &adapter->iopriv.intf; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); sd_cmd52_write(intfhdl, addr, 1, &v); } -static void SdioLocalCmd52Write4Byte(struct adapter *adapter, u32 addr, u32 v) +static void sdio_local_cmd52_write4byte(struct adapter *adapter, u32 addr, u32 v) { struct intf_hdl *intfhdl = &adapter->iopriv.intf; __le32 le_tmp; - HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); le_tmp = cpu_to_le32(v); sd_cmd52_write(intfhdl, addr, 4, (u8 *)&le_tmp); } -static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr) +static s32 read_interrupt_8723b_sdio(struct adapter *adapter, u32 *phisr) { u32 hisr, himr; u8 val8, hisr_len; @@ -777,30 +751,10 @@ void EnableInterrupt8723BSdio(struct adapter *adapter) himr = cpu_to_le32(haldata->sdio_himr); sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr); - RT_TRACE( - _module_hci_ops_c_, - _drv_notice_, - ( - "%s: enable SDIO HIMR = 0x%08X\n", - __func__, - haldata->sdio_himr - ) - ); - /* Update current system IMR settings */ tmp = rtw_read32(adapter, REG_HSIMR); rtw_write32(adapter, REG_HSIMR, tmp | haldata->SysIntrMask); - RT_TRACE( - _module_hci_ops_c_, - _drv_notice_, - ( - "%s: enable HSIMR = 0x%08X\n", - __func__, - haldata->SysIntrMask - ) - ); - /* */ /* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */ /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */ @@ -837,13 +791,6 @@ void DisableInterrupt8723BSdio(struct adapter *adapter) /* */ u8 CheckIPSStatus(struct adapter *adapter) { - DBG_871X( - "%s(): Read 0x100 = 0x%02x 0x86 = 0x%02x\n", - __func__, - rtw_read8(adapter, 0x100), - rtw_read8(adapter, 0x86) - ); - if (rtw_read8(adapter, 0x100) == 0xEA) return true; else @@ -865,7 +812,8 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) recv_priv = &adapter->recvpriv; recvbuf = rtw_dequeue_recvbuf(&recv_priv->free_recv_buf_queue); if (!recvbuf) { - DBG_871X_LEVEL(_drv_err_, "%s: alloc recvbuf FAIL!\n", __func__); + netdev_err(adapter->pnetdev, "%s: alloc recvbuf FAIL!\n", + __func__); return NULL; } @@ -884,19 +832,15 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); } - if (!recvbuf->pskb) { - DBG_871X("%s: alloc_skb fail! read =%d\n", __func__, readsize); + if (!recvbuf->pskb) return NULL; - } } /* 3 3. read data from rxfifo */ readbuf = recvbuf->pskb->data; ret = sdio_read_port(&adapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, readbuf); - if (ret == _FAIL) { - RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __func__)); + if (ret == _FAIL) return NULL; - } /* 3 4. init recvbuf */ recvbuf->len = size; @@ -943,11 +887,9 @@ void sd_int_dpc(struct adapter *adapter) } if (hal->sdio_hisr & SDIO_HISR_CPWM1) { - struct reportpwrstate_parm report; - del_timer_sync(&(pwrctl->pwr_rpwm_timer)); - report.state = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B); + SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B); _set_workitem(&(pwrctl->cpwm_event)); } @@ -959,26 +901,16 @@ void sd_int_dpc(struct adapter *adapter) status = rtw_malloc(4); if (status) { addr = REG_TXDMA_STATUS; - HalSdioGetCmdAddr8723BSdio(adapter, WLAN_IOREG_DEVICE_ID, addr, &addr); + hal_sdio_get_cmd_addr_8723b(adapter, WLAN_IOREG_DEVICE_ID, addr, &addr); _sd_read(intfhdl, addr, 4, status); _sd_write(intfhdl, addr, 4, status); - DBG_8192C("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32 *)status)); kfree(status); - } else { - DBG_8192C("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__); } } - if (hal->sdio_hisr & SDIO_HISR_TXBCNOK) - DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__); - - if (hal->sdio_hisr & SDIO_HISR_TXBCNERR) - DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__); -#ifndef CONFIG_C2H_PACKET_EN if (hal->sdio_hisr & SDIO_HISR_C2HCMD) { struct c2h_evt_hdr_88xx *c2h_evt; - DBG_8192C("%s: C2H Command\n", __func__); c2h_evt = rtw_zmalloc(16); if (c2h_evt) { if (c2h_evt_read_88xx(adapter, (u8 *)c2h_evt) == _SUCCESS) { @@ -992,18 +924,10 @@ void sd_int_dpc(struct adapter *adapter) } } else { /* Error handling for malloc fail */ - if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, NULL) != _SUCCESS) - DBG_871X("%s rtw_cbuf_push fail\n", __func__); + rtw_cbuf_push(adapter->evtpriv.c2h_queue, NULL); _set_workitem(&adapter->evtpriv.c2h_wk); } } -#endif - - if (hal->sdio_hisr & SDIO_HISR_RXFOVW) - DBG_8192C("%s: Rx Overflow\n", __func__); - - if (hal->sdio_hisr & SDIO_HISR_RXERR) - DBG_8192C("%s: Rx Error\n", __func__); if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) { struct recv_buf *recvbuf; @@ -1012,14 +936,13 @@ void sd_int_dpc(struct adapter *adapter) hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST; do { - hal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(adapter, SDIO_REG_RX0_REQ_LEN); + hal->SdioRxFIFOSize = sdio_local_cmd52_read2byte(adapter, SDIO_REG_RX0_REQ_LEN); if (hal->SdioRxFIFOSize != 0) { recvbuf = sd_recv_rxfifo(adapter, hal->SdioRxFIFOSize); if (recvbuf) sd_rxhandler(adapter, recvbuf); else { alloc_fail_time++; - DBG_871X("recvbuf is Null for %d times because alloc memory failed\n", alloc_fail_time); if (alloc_fail_time >= 10) break; } @@ -1028,15 +951,11 @@ void sd_int_dpc(struct adapter *adapter) break; hisr = 0; - ReadInterrupt8723BSdio(adapter, &hisr); + read_interrupt_8723b_sdio(adapter, &hisr); hisr &= SDIO_HISR_RX_REQUEST; if (!hisr) break; } while (1); - - if (alloc_fail_time == 10) - DBG_871X("exit because alloc memory failed more than 10 times\n"); - } } @@ -1052,7 +971,7 @@ void sd_int_hdl(struct adapter *adapter) hal = GET_HAL_DATA(adapter); hal->sdio_hisr = 0; - ReadInterrupt8723BSdio(adapter, &hal->sdio_hisr); + read_interrupt_8723b_sdio(adapter, &hal->sdio_hisr); if (hal->sdio_hisr & hal->sdio_himr) { u32 v32; @@ -1062,13 +981,9 @@ void sd_int_hdl(struct adapter *adapter) /* clear HISR */ v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR; if (v32) - SdioLocalCmd52Write4Byte(adapter, SDIO_REG_HISR, v32); + sdio_local_cmd52_write4byte(adapter, SDIO_REG_HISR, v32); sd_int_dpc(adapter); - } else { - RT_TRACE(_module_hci_ops_c_, _drv_err_, - ("%s: HISR(0x%08x) and HIMR(0x%08x) not match!\n", - __func__, hal->sdio_hisr, hal->sdio_himr)); } } @@ -1089,16 +1004,9 @@ u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter) hal = GET_HAL_DATA(adapter); - numof_free_page = SdioLocalCmd53Read4Byte(adapter, SDIO_REG_FREE_TXPG); + numof_free_page = sdio_local_cmd53_read4byte(adapter, SDIO_REG_FREE_TXPG); memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4); - RT_TRACE(_module_hci_ops_c_, _drv_notice_, - ("%s: Free page for HIQ(%#x), MIDQ(%#x), LOWQ(%#x), PUBQ(%#x)\n", - __func__, - hal->SdioTxFIFOFreePage[HI_QUEUE_IDX], - hal->SdioTxFIFOFreePage[MID_QUEUE_IDX], - hal->SdioTxFIFOFreePage[LOW_QUEUE_IDX], - hal->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX])); return true; } @@ -1114,39 +1022,4 @@ void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter) haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG); } -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -u8 RecvOnePkt(struct adapter *adapter, u32 size) -{ - struct recv_buf *recvbuf; - struct dvobj_priv *sddev; - struct sdio_func *func; - - u8 res = false; - - DBG_871X("+%s: size: %d+\n", __func__, size); - if (!adapter) { - DBG_871X(KERN_ERR "%s: adapter is NULL!\n", __func__); - return false; - } - - sddev = adapter_to_dvobj(adapter); - psdio_data = &sddev->intf_data; - func = psdio_data->func; - - if (size) { - sdio_claim_host(func); - recvbuf = sd_recv_rxfifo(adapter, size); - - if (recvbuf) { - sd_rxhandler(adapter, recvbuf); - res = true; - } else { - res = false; - } - sdio_release_host(func); - } - DBG_871X("-%s-\n", __func__); - return res; -} -#endif /* CONFIG_WOWLAN */ diff --git a/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h b/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h index fb80901f07884747d29eb0e2056ad3f0d53caabe..4b3a7c051630a3ee710bbaea47faa1e0127f14b5 100644 --- a/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h +++ b/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h @@ -34,7 +34,7 @@ /*--------------------------Define Parameters-------------------------------*/ /* */ -/* 8192S Regsiter offset definition */ +/* 8192S Register offset definition */ /* */ /* */ @@ -43,7 +43,7 @@ /* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */ /* 3. RF register 0x00-2E */ /* 4. Bit Mask for BB/RF register */ -/* 5. Other defintion for BB/RF R/W */ +/* 5. Other definition for BB/RF R/W */ /* */ @@ -137,7 +137,7 @@ #define rFPGA0_AnalogParameter3 0x888 /* Useless now */ #define rFPGA0_AnalogParameter4 0x88c -#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */ +#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Transceiver LSSI Readback */ #define rFPGA0_XB_LSSIReadBack 0x8a4 #define rFPGA0_XC_LSSIReadBack 0x8a8 #define rFPGA0_XD_LSSIReadBack 0x8ac @@ -206,7 +206,7 @@ #define rOFDM0_TRSWIsolation 0xc0c #define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ -#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ +#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */ #define rOFDM0_XBRxAFE 0xc18 #define rOFDM0_XBRxIQImbalance 0xc1c #define rOFDM0_XCRxAFE 0xc20 diff --git a/drivers/staging/rtl8723bs/include/HalPwrSeqCmd.h b/drivers/staging/rtl8723bs/include/HalPwrSeqCmd.h index 459f2f9d4bbbe14497d3ed12cf20830f50a24491..e30071935d27028585a81f8e8117b04d9e6dbc85 100644 --- a/drivers/staging/rtl8723bs/include/HalPwrSeqCmd.h +++ b/drivers/staging/rtl8723bs/include/HalPwrSeqCmd.h @@ -82,12 +82,12 @@ #define PWR_CUT_ALL_MSK 0xFF -typedef enum _PWRSEQ_CMD_DELAY_UNIT_ { +enum { PWRSEQ_DELAY_US, PWRSEQ_DELAY_MS, -} PWRSEQ_DELAY_UNIT; +}; -typedef struct _WL_PWR_CFG_ { +struct wlan_pwr_cfg { u16 offset; u8 cut_msk; u8 fab_msk:4; @@ -96,7 +96,7 @@ typedef struct _WL_PWR_CFG_ { u8 cmd:4; u8 msk; u8 value; -} WLAN_PWR_CFG, *PWLAN_PWR_CFG; +}; #define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset @@ -113,10 +113,10 @@ typedef struct _WL_PWR_CFG_ { /* Prototype of protected function. */ /* */ u8 HalPwrSeqCmdParsing( - struct adapter * padapter, + struct adapter *padapter, u8 CutVersion, u8 FabVersion, u8 InterfaceType, - WLAN_PWR_CFG PwrCfgCmd[]); + struct wlan_pwr_cfg PwrCfgCmd[]); #endif diff --git a/drivers/staging/rtl8723bs/include/HalVerDef.h b/drivers/staging/rtl8723bs/include/HalVerDef.h index b4744be2cbe171b19b92d77c5a860960b338afb9..bab226f77b24cf4e930bbd4dc6634162d444db66 100644 --- a/drivers/staging/rtl8723bs/include/HalVerDef.h +++ b/drivers/staging/rtl8723bs/include/HalVerDef.h @@ -7,8 +7,8 @@ #ifndef __HAL_VERSION_DEF_H__ #define __HAL_VERSION_DEF_H__ -/* HAL_IC_TYPE_E */ -typedef enum tag_HAL_IC_Type_Definition { +/* hal_ic_type_e */ +enum hal_ic_type_e { /* tag_HAL_IC_Type_Definition */ CHIP_8192S = 0, CHIP_8188C = 1, CHIP_8192C = 2, @@ -19,17 +19,17 @@ typedef enum tag_HAL_IC_Type_Definition { CHIP_8821 = 7, CHIP_8723B = 8, CHIP_8192E = 9, -} HAL_IC_TYPE_E; +}; -/* HAL_CHIP_TYPE_E */ -typedef enum tag_HAL_CHIP_Type_Definition { +/* hal_chip_type_e */ +enum hal_chip_type_e { /* tag_HAL_CHIP_Type_Definition */ TEST_CHIP = 0, NORMAL_CHIP = 1, FPGA = 2, -} HAL_CHIP_TYPE_E; +}; -/* HAL_CUT_VERSION_E */ -typedef enum tag_HAL_Cut_Version_Definition { +/* hal_cut_version_e */ +enum hal_cut_version_e { /* tag_HAL_Cut_Version_Definition */ A_CUT_VERSION = 0, B_CUT_VERSION = 1, C_CUT_VERSION = 2, @@ -41,16 +41,16 @@ typedef enum tag_HAL_Cut_Version_Definition { I_CUT_VERSION = 8, J_CUT_VERSION = 9, K_CUT_VERSION = 10, -} HAL_CUT_VERSION_E; +}; /* HAL_Manufacturer */ -typedef enum tag_HAL_Manufacturer_Version_Definition { +enum hal_vendor_e { /* tag_HAL_Manufacturer_Version_Definition */ CHIP_VENDOR_TSMC = 0, CHIP_VENDOR_UMC = 1, CHIP_VENDOR_SMIC = 2, -} HAL_VENDOR_E; +}; -typedef enum tag_HAL_RF_Type_Definition { +enum hal_rf_type_e { /* tag_HAL_RF_Type_Definition */ RF_TYPE_1T1R = 0, RF_TYPE_1T2R = 1, RF_TYPE_2T2R = 2, @@ -59,38 +59,38 @@ typedef enum tag_HAL_RF_Type_Definition { RF_TYPE_3T3R = 5, RF_TYPE_3T4R = 6, RF_TYPE_4T4R = 7, -} HAL_RF_TYPE_E; +}; -typedef struct tag_HAL_VERSION { - HAL_IC_TYPE_E ICType; - HAL_CHIP_TYPE_E ChipType; - HAL_CUT_VERSION_E CUTVersion; - HAL_VENDOR_E VendorType; - HAL_RF_TYPE_E RFType; +struct hal_version { /* tag_HAL_VERSION */ + enum hal_ic_type_e ICType; + enum hal_chip_type_e ChipType; + enum hal_cut_version_e CUTVersion; + enum hal_vendor_e VendorType; + enum hal_rf_type_e RFType; u8 ROMVer; -} HAL_VERSION, *PHAL_VERSION; +}; /* VERSION_8192C VersionID; */ -/* HAL_VERSION VersionID; */ +/* hal_version VersionID; */ /* Get element */ -#define GET_CVID_IC_TYPE(version) ((HAL_IC_TYPE_E)((version).ICType)) -#define GET_CVID_CHIP_TYPE(version) ((HAL_CHIP_TYPE_E)((version).ChipType)) -#define GET_CVID_RF_TYPE(version) ((HAL_RF_TYPE_E)((version).RFType)) -#define GET_CVID_MANUFACTUER(version) ((HAL_VENDOR_E)((version).VendorType)) -#define GET_CVID_CUT_VERSION(version) ((HAL_CUT_VERSION_E)((version).CUTVersion)) +#define GET_CVID_IC_TYPE(version) ((enum hal_ic_type_e)((version).ICType)) +#define GET_CVID_CHIP_TYPE(version) ((enum hal_chip_type_e)((version).ChipType)) +#define GET_CVID_RF_TYPE(version) ((enum hal_rf_type_e)((version).RFType)) +#define GET_CVID_MANUFACTUER(version) ((enum hal_vendor_e)((version).VendorType)) +#define GET_CVID_CUT_VERSION(version) ((enum hal_cut_version_e)((version).CUTVersion)) #define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK) /* */ /* Common Macro. -- */ /* */ -/* HAL_VERSION VersionID */ +/* hal_version VersionID */ -/* HAL_CHIP_TYPE_E */ +/* hal_chip_type_e */ #define IS_TEST_CHIP(version) ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false) #define IS_NORMAL_CHIP(version) ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false) -/* HAL_CUT_VERSION_E */ +/* hal_cut_version_e */ #define IS_A_CUT(version) ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false) #define IS_B_CUT(version) ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false) #define IS_C_CUT(version) ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false) @@ -100,12 +100,12 @@ typedef struct tag_HAL_VERSION { #define IS_J_CUT(version) ((GET_CVID_CUT_VERSION(version) == J_CUT_VERSION) ? true : false) #define IS_K_CUT(version) ((GET_CVID_CUT_VERSION(version) == K_CUT_VERSION) ? true : false) -/* HAL_VENDOR_E */ +/* hal_vendor_e */ #define IS_CHIP_VENDOR_TSMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false) #define IS_CHIP_VENDOR_UMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false) #define IS_CHIP_VENDOR_SMIC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_SMIC) ? true : false) -/* HAL_RF_TYPE_E */ +/* hal_rf_type_e */ #define IS_1T1R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false) #define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false) #define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false) diff --git a/drivers/staging/rtl8723bs/include/autoconf.h b/drivers/staging/rtl8723bs/include/autoconf.h index 86cf09ca5f06ee1baa50dc16dc58e4f25b1200d3..944a7d2a1e537834d41f16fb959551871b97b56d 100644 --- a/drivers/staging/rtl8723bs/include/autoconf.h +++ b/drivers/staging/rtl8723bs/include/autoconf.h @@ -12,7 +12,6 @@ /* * Functions Config */ -/* define DEBUG_CFG80211 */ #ifndef CONFIG_WIRELESS_EXT #error CONFIG_WIRELESS_EXT needs to be enabled for this driver to work @@ -40,21 +39,12 @@ * Platform dependent */ #define WAKEUP_GPIO_IDX 12 /* WIFI Chip Side */ -#ifdef CONFIG_WOWLAN -#define CONFIG_GTK_OL -#endif /* CONFIG_WOWLAN */ /* * Debug Related Config */ -#undef DEBUG -#ifdef DEBUG -#define DBG 1 /* for ODM & BTCOEX debug */ -/*#define DEBUG_RTL871X */ -#else /* !DEBUG */ #define DBG 0 /* for ODM & BTCOEX debug */ -#endif /* !DEBUG */ /* define DBG_XMIT_BUF */ /* define DBG_XMIT_BUF_EXT */ diff --git a/drivers/staging/rtl8723bs/include/basic_types.h b/drivers/staging/rtl8723bs/include/basic_types.h index bab9811aeb5fa242cfa75f0a0c1c6f0590e08b90..57bb717327ce06cc92105ad2c1c9447ab23297f3 100644 --- a/drivers/staging/rtl8723bs/include/basic_types.h +++ b/drivers/staging/rtl8723bs/include/basic_types.h @@ -13,9 +13,7 @@ #include <linux/types.h> -typedef signed int sint; - -#define FIELD_OFFSET(s, field) ((__kernel_ssize_t)&((s*)(0))->field) +#define FIELD_OFFSET(s, field) ((__kernel_ssize_t)&((s *)(0))->field) #define SIZE_PTR __kernel_size_t #define SSIZE_PTR __kernel_ssize_t @@ -189,7 +187,7 @@ typedef signed int sint; ); \ } -/* Get the N-bytes aligment offset from the current length */ +/* Get the N-bytes alignent offset from the current length */ #define N_BYTE_ALIGMENT(__Value, __Aligment) ((__Aligment == 1) ? (__Value) : (((__Value + __Aligment - 1) / __Aligment) * __Aligment)) #define TEST_FLAG(__Flag, __testFlag) (((__Flag) & (__testFlag)) != 0) diff --git a/drivers/staging/rtl8723bs/include/drv_conf.h b/drivers/staging/rtl8723bs/include/drv_conf.h index 7fc88b07a25ede494d140e8dcdbaa48616854f83..9cef9ce589a1c5713e0876dce4636b4f2fe11a5d 100644 --- a/drivers/staging/rtl8723bs/include/drv_conf.h +++ b/drivers/staging/rtl8723bs/include/drv_conf.h @@ -8,16 +8,6 @@ #define __DRV_CONF_H__ #include "autoconf.h" -//About USB VENDOR REQ -#if defined(CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC) && !defined(CONFIG_USB_VENDOR_REQ_MUTEX) - #warning "define CONFIG_USB_VENDOR_REQ_MUTEX for CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC automatically" - #define CONFIG_USB_VENDOR_REQ_MUTEX -#endif -#if defined(CONFIG_VENDOR_REQ_RETRY) && !defined(CONFIG_USB_VENDOR_REQ_MUTEX) - #warning "define CONFIG_USB_VENDOR_REQ_MUTEX for CONFIG_VENDOR_REQ_RETRY automatically" - #define CONFIG_USB_VENDOR_REQ_MUTEX -#endif - #define DYNAMIC_CAMID_ALLOC #ifndef CONFIG_RTW_HIQ_FILTER diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index c73f581aea064f77784c702df068308f32848bdf..83d43e5726ddc25be4f203f3f8ef38645acf26e1 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -14,7 +14,6 @@ #ifndef __DRV_TYPES_H__ #define __DRV_TYPES_H__ -#include <linux/version.h> #include <linux/sched/signal.h> #include <autoconf.h> #include <basic_types.h> @@ -24,15 +23,6 @@ #include <wifi.h> #include <ieee80211.h> -enum _NIC_VERSION { - - RTL8711_NIC, - RTL8712_NIC, - RTL8713_NIC, - RTL8716_NIC - -}; - #include <rtw_rf.h> #include <rtw_ht.h> @@ -77,15 +67,6 @@ enum _NIC_VERSION { #define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4) #define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5) -struct specific_device_id { - - u32 flags; - - u16 idVendor; - u16 idProduct; - -}; - struct registry_priv { u8 chip_version; u8 rfintfs; @@ -196,9 +177,6 @@ struct registry_priv { u8 RFE_Type; u8 check_fw_ps; -#ifdef CONFIG_MULTI_VIR_IFACES - u8 ext_iface_num;/* primary/secondary iface is excluded */ -#endif u8 qos_opt_enable; u8 hiq_filter; @@ -207,7 +185,7 @@ struct registry_priv { /* For registry parameters */ #define RGTRY_OFT(field) ((u32)FIELD_OFFSET(struct registry_priv, field)) -#define RGTRY_SZ(field) sizeof(((struct registry_priv*) 0)->field) +#define RGTRY_SZ(field) sizeof(((struct registry_priv *)0)->field) #define BSSID_OFT(field) ((u32)FIELD_OFFSET(struct wlan_bssid_ex, field)) #define BSSID_SZ(field) sizeof(((struct wlan_bssid_ex *) 0)->field) @@ -219,131 +197,6 @@ struct registry_priv { #define GET_IFACE_NUMS(padapter) (((struct adapter *)padapter)->dvobj->iface_nums) #define GET_ADAPTER(padapter, iface_id) (((struct adapter *)padapter)->dvobj->padapters[iface_id]) -#ifdef CONFIG_DBG_COUNTER - -struct rx_logs { - u32 intf_rx; - u32 intf_rx_err_recvframe; - u32 intf_rx_err_skb; - u32 intf_rx_report; - u32 core_rx; - u32 core_rx_pre; - u32 core_rx_pre_ver_err; - u32 core_rx_pre_mgmt; - u32 core_rx_pre_mgmt_err_80211w; - u32 core_rx_pre_mgmt_err; - u32 core_rx_pre_ctrl; - u32 core_rx_pre_ctrl_err; - u32 core_rx_pre_data; - u32 core_rx_pre_data_wapi_seq_err; - u32 core_rx_pre_data_wapi_key_err; - u32 core_rx_pre_data_handled; - u32 core_rx_pre_data_err; - u32 core_rx_pre_data_unknown; - u32 core_rx_pre_unknown; - u32 core_rx_enqueue; - u32 core_rx_dequeue; - u32 core_rx_post; - u32 core_rx_post_decrypt; - u32 core_rx_post_decrypt_wep; - u32 core_rx_post_decrypt_tkip; - u32 core_rx_post_decrypt_aes; - u32 core_rx_post_decrypt_wapi; - u32 core_rx_post_decrypt_hw; - u32 core_rx_post_decrypt_unknown; - u32 core_rx_post_decrypt_err; - u32 core_rx_post_defrag_err; - u32 core_rx_post_portctrl_err; - u32 core_rx_post_indicate; - u32 core_rx_post_indicate_in_oder; - u32 core_rx_post_indicate_reoder; - u32 core_rx_post_indicate_err; - u32 os_indicate; - u32 os_indicate_ap_mcast; - u32 os_indicate_ap_forward; - u32 os_indicate_ap_self; - u32 os_indicate_err; - u32 os_netif_ok; - u32 os_netif_err; -}; - -struct tx_logs { - u32 os_tx; - u32 os_tx_err_up; - u32 os_tx_err_xmit; - u32 os_tx_m2u; - u32 os_tx_m2u_ignore_fw_linked; - u32 os_tx_m2u_ignore_self; - u32 os_tx_m2u_entry; - u32 os_tx_m2u_entry_err_xmit; - u32 os_tx_m2u_entry_err_skb; - u32 os_tx_m2u_stop; - u32 core_tx; - u32 core_tx_err_pxmitframe; - u32 core_tx_err_brtx; - u32 core_tx_upd_attrib; - u32 core_tx_upd_attrib_adhoc; - u32 core_tx_upd_attrib_sta; - u32 core_tx_upd_attrib_ap; - u32 core_tx_upd_attrib_unknown; - u32 core_tx_upd_attrib_dhcp; - u32 core_tx_upd_attrib_icmp; - u32 core_tx_upd_attrib_active; - u32 core_tx_upd_attrib_err_ucast_sta; - u32 core_tx_upd_attrib_err_ucast_ap_link; - u32 core_tx_upd_attrib_err_sta; - u32 core_tx_upd_attrib_err_link; - u32 core_tx_upd_attrib_err_sec; - u32 core_tx_ap_enqueue_warn_fwstate; - u32 core_tx_ap_enqueue_warn_sta; - u32 core_tx_ap_enqueue_warn_nosta; - u32 core_tx_ap_enqueue_warn_link; - u32 core_tx_ap_enqueue_warn_trigger; - u32 core_tx_ap_enqueue_mcast; - u32 core_tx_ap_enqueue_ucast; - u32 core_tx_ap_enqueue; - u32 intf_tx; - u32 intf_tx_pending_ac; - u32 intf_tx_pending_fw_under_survey; - u32 intf_tx_pending_fw_under_linking; - u32 intf_tx_pending_xmitbuf; - u32 intf_tx_enqueue; - u32 core_tx_enqueue; - u32 core_tx_enqueue_class; - u32 core_tx_enqueue_class_err_sta; - u32 core_tx_enqueue_class_err_nosta; - u32 core_tx_enqueue_class_err_fwlink; - u32 intf_tx_direct; - u32 intf_tx_direct_err_coalesce; - u32 intf_tx_dequeue; - u32 intf_tx_dequeue_err_coalesce; - u32 intf_tx_dump_xframe; - u32 intf_tx_dump_xframe_err_txdesc; - u32 intf_tx_dump_xframe_err_port; -}; - -struct int_logs { - u32 all; - u32 err; - u32 tbdok; - u32 tbder; - u32 bcnderr; - u32 bcndma; - u32 bcndma_e; - u32 rx; - u32 rx_rdu; - u32 rx_fovw; - u32 txfovw; - u32 mgntok; - u32 highdok; - u32 bkdok; - u32 bedok; - u32 vidok; - u32 vodok; -}; - -#endif /* CONFIG_DBG_COUNTER */ - struct debug_priv { u32 dbg_sdio_free_irq_error_cnt; u32 dbg_sdio_alloc_irq_error_cnt; @@ -402,7 +255,7 @@ struct rtw_traffic_statistics { }; struct cam_ctl_t { - _lock lock; + spinlock_t lock; u64 bitmap; }; @@ -412,15 +265,9 @@ struct cam_entry_cache { u8 key[16]; }; -#define KEY_FMT "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" -#define KEY_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5], \ - ((u8 *)(x))[6], ((u8 *)(x))[7], ((u8 *)(x))[8], ((u8 *)(x))[9], ((u8 *)(x))[10], ((u8 *)(x))[11], \ - ((u8 *)(x))[12], ((u8 *)(x))[13], ((u8 *)(x))[14], ((u8 *)(x))[15] - struct dvobj_priv { /*-------- below is common data --------*/ struct adapter *if1; /* PRIMARY_ADAPTER */ - struct adapter *if2; /* SECONDARY_ADAPTER */ s32 processing_dev_remove; @@ -428,13 +275,13 @@ struct dvobj_priv { /* for local/global synchronization */ /* */ - _lock lock; + spinlock_t lock; int macid[NUM_STA]; - _mutex hw_init_mutex; - _mutex h2c_fwcmd_mutex; - _mutex setch_mutex; - _mutex setbw_mutex; + struct mutex hw_init_mutex; + struct mutex h2c_fwcmd_mutex; + struct mutex setch_mutex; + struct mutex setbw_mutex; unsigned char oper_channel; /* saved channel info when call set_channel_bw */ unsigned char oper_bwmode; @@ -446,10 +293,6 @@ struct dvobj_priv { struct cam_ctl_t cam_ctl; struct cam_entry_cache cam_cache[TOTAL_CAM_ENTRY]; - /* For 92D, DMDP have 2 interface. */ - u8 InterfaceNumber; - u8 NumInterfaces; - /* In /Out Pipe information */ int RtInPipe[2]; int RtOutPipe[4]; @@ -484,23 +327,17 @@ static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj) struct adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj); -enum _IFACE_TYPE { +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 ADAPTER_TYPE { - PRIMARY_ADAPTER, - SECONDARY_ADAPTER, - MAX_ADAPTER = 0xFF, -}; - -typedef enum _DRIVER_STATE { +enum { DRIVER_NORMAL = 0, DRIVER_DISAPPEAR = 1, DRIVER_REPLACE_DONGLE = 2, -} DRIVER_STATE; +}; struct adapter { int DriverState;/* for disable driver using module, use dongle to replace module. */ @@ -518,7 +355,7 @@ struct adapter { struct recv_priv recvpriv; struct sta_priv stapriv; struct security_priv securitypriv; - _lock security_key_mutex; /* add for CONFIG_IEEE80211W, none 11w also can use */ + spinlock_t security_key_mutex; /* add for CONFIG_IEEE80211W, none 11w also can use */ struct registry_priv registrypriv; struct eeprom_priv eeprompriv; @@ -526,7 +363,7 @@ struct adapter { u32 setband; - void * HalData; + void *HalData; u32 hal_data_sz; struct hal_ops HalFunc; @@ -554,17 +391,16 @@ struct adapter { void (*intf_free_irq)(struct dvobj_priv *dvobj); - void (*intf_start)(struct adapter * adapter); - void (*intf_stop)(struct adapter * adapter); + void (*intf_start)(struct adapter *adapter); + void (*intf_stop)(struct adapter *adapter); - _nic_hdl pnetdev; + struct net_device *pnetdev; char old_ifname[IFNAMSIZ]; /* used by rtw_rereg_nd_name related function */ struct rereg_nd_name_data { - _nic_hdl old_pnetdev; + struct net_device *old_pnetdev; char old_ifname[IFNAMSIZ]; - u8 old_ips_mode; u8 old_bRegUseLed; } rereg_nd_name_priv; @@ -587,7 +423,7 @@ struct adapter { /* The driver will show up the desired channel number when this flag is 1. */ u8 bNotifyChannelChange; - /* pbuddystruct adapter is used only in two inteface case, (iface_nums =2 in struct dvobj_priv) */ + /* pbuddystruct adapter is used only in two interface case, (iface_nums =2 in struct dvobj_priv) */ /* PRIMARY ADAPTER's buddy is SECONDARY_ADAPTER */ /* SECONDARY_ADAPTER's buddy is PRIMARY_ADAPTER */ /* for iface_id > SECONDARY_ADAPTER(IFACE_ID1), refer to padapters[iface_id] in struct dvobj_priv */ @@ -608,12 +444,6 @@ struct adapter { u8 driver_rx_ampdu_factor;/* 0xff: disable drv ctrl, 0:8k, 1:16k, 2:32k, 3:64k; */ unsigned char in_cta_test; - -#ifdef CONFIG_DBG_COUNTER - struct rx_logs rx_logs; - struct tx_logs tx_logs; - struct int_logs int_logs; -#endif }; #define adapter_to_dvobj(adapter) (adapter->dvobj) @@ -659,17 +489,6 @@ static inline void RTW_ENABLE_FUNC(struct adapter *padapter, int func_bit) (padapter)->bSurpriseRemoved || \ RTW_IS_FUNC_DISABLED((padapter), DF_TX_BIT)) -#ifdef CONFIG_GPIO_API -int rtw_get_gpio(struct net_device *netdev, int gpio_num); -int rtw_set_gpio_output_value(struct net_device *netdev, int gpio_num, bool isHigh); -int rtw_config_gpio(struct net_device *netdev, int gpio_num, bool isOutput); -#endif - -#ifdef CONFIG_WOWLAN -void rtw_suspend_wow(struct adapter *padapter); -int rtw_resume_process_wow(struct adapter *padapter); -#endif - static inline u8 *myid(struct eeprom_priv *peepriv) { return peepriv->mac_addr; diff --git a/drivers/staging/rtl8723bs/include/drv_types_sdio.h b/drivers/staging/rtl8723bs/include/drv_types_sdio.h index 5e079838f59cbec286aa87c0c286f93bc12eff1e..25b3c3a39ee44a009b82041cb96759a5b0d17244 100644 --- a/drivers/staging/rtl8723bs/include/drv_types_sdio.h +++ b/drivers/staging/rtl8723bs/include/drv_types_sdio.h @@ -11,11 +11,6 @@ #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) - #include <linux/mmc/host.h> - #include <linux/mmc/card.h> -#endif - struct sdio_data { u8 func_number; diff --git a/drivers/staging/rtl8723bs/include/hal_btcoex.h b/drivers/staging/rtl8723bs/include/hal_btcoex.h index 29318b49c3ff36c82092435e0f75f17257cb5687..3c03be210d8748cf03d22d7646cfa89e5bb53cd4 100644 --- a/drivers/staging/rtl8723bs/include/hal_btcoex.h +++ b/drivers/staging/rtl8723bs/include/hal_btcoex.h @@ -11,12 +11,12 @@ /* Some variables can't get from outsrc BT-Coex, */ /* so we need to save here */ -typedef struct _BT_COEXIST { +struct bt_coexist { u8 bBtExist; u8 btTotalAntNum; u8 btChipType; u8 bInitlized; -} BT_COEXIST, *PBT_COEXIST; +}; void DBG_BT_INFO(u8 *dbgmsg); diff --git a/drivers/staging/rtl8723bs/include/hal_com.h b/drivers/staging/rtl8723bs/include/hal_com.h index fe7e2efce0e3a7dfbf0d9fda31e488506e6b49ca..6bcc443d59fbf15ef27c5446cfa839b3101a5f3e 100644 --- a/drivers/staging/rtl8723bs/include/hal_com.h +++ b/drivers/staging/rtl8723bs/include/hal_com.h @@ -158,23 +158,19 @@ (rate == DESC_RATEVHTSS2MCS6) ? "VHTSS2MCS6" : \ (rate == DESC_RATEVHTSS2MCS7) ? "VHTSS2MCS7" : \ (rate == DESC_RATEVHTSS2MCS8) ? "VHTSS2MCS8" : \ -(rate == DESC_RATEVHTSS2MCS9) ? "VHTSS2MCS9" : "UNKNOW" +(rate == DESC_RATEVHTSS2MCS9) ? "VHTSS2MCS9" : "UNKNOWN" enum{ UP_LINK, DOWN_LINK, }; -typedef enum _RT_MEDIA_STATUS { +enum rt_media_status { RT_MEDIA_DISCONNECT = 0, RT_MEDIA_CONNECT = 1 -} RT_MEDIA_STATUS; +}; #define MAX_DLFW_PAGE_SIZE 4096 /* @ page : 4k bytes */ -enum FIRMWARE_SOURCE { - FW_SOURCE_IMG_FILE = 0, - FW_SOURCE_HEADER_FILE = 1, /* from header file */ -}; /* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */ /* define MAX_TX_QUEUE 9 */ @@ -184,16 +180,12 @@ enum FIRMWARE_SOURCE { #define TX_SELE_NQ BIT(2) /* Normal Queue */ #define TX_SELE_EQ BIT(3) /* Extern Queue */ -#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) -#define PageNum_256(_Len) (u32)(((_Len)>>8) + ((_Len)&0xFF ? 1:0)) -#define PageNum_512(_Len) (u32)(((_Len)>>9) + ((_Len)&0x1FF ? 1:0)) -#define PageNum(_Len, _Size) (u32)(((_Len)/(_Size)) + ((_Len)&((_Size) - 1) ? 1:0)) - +#define PageNum_128(_Len) ((u32)(((_Len) >> 7) + ((_Len) & 0x7F ? 1 : 0))) u8 rtw_hal_data_init(struct adapter *padapter); void rtw_hal_data_deinit(struct adapter *padapter); -void dump_chip_info(HAL_VERSION ChipVersion); +void dump_chip_info(struct hal_version ChipVersion); u8 /* return the final channel plan decision */ hal_com_config_channel_plan( @@ -215,9 +207,9 @@ u8 MRateToHwRate(u8 rate); u8 HwRateToMRate(u8 rate); void HalSetBrateCfg( - struct adapter * Adapter, - u8 *mBratesOS, - u16 *pBrateCfg); + struct adapter *Adapter, + u8 *mBratesOS, + u16 *pBrateCfg); bool Hal_MappingOutPipe( @@ -227,7 +219,7 @@ u8 NumOutPipe void hal_init_macaddr(struct adapter *adapter); -void rtw_init_hal_com_default_value(struct adapter * Adapter); +void rtw_init_hal_com_default_value(struct adapter *Adapter); void c2h_evt_clear(struct adapter *adapter); s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf); @@ -241,9 +233,9 @@ void SetHwReg(struct adapter *padapter, u8 variable, u8 *val); void GetHwReg(struct adapter *padapter, u8 variable, u8 *val); void rtw_hal_check_rxfifo_full(struct adapter *adapter); -u8 SetHalDefVar(struct adapter *adapter, enum HAL_DEF_VARIABLE variable, +u8 SetHalDefVar(struct adapter *adapter, enum hal_def_variable variable, void *value); -u8 GetHalDefVar(struct adapter *adapter, enum HAL_DEF_VARIABLE variable, +u8 GetHalDefVar(struct adapter *adapter, enum hal_def_variable variable, void *value); bool eqNByte(u8 *str1, u8 *str2, u32 num); @@ -278,22 +270,12 @@ 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); + enum hal_odm_variable eVariable, + void *pValue1, + void *pValue2); void SetHalODMVar( - struct adapter * Adapter, - enum HAL_ODM_VARIABLE eVariable, - void * pValue1, + struct adapter *Adapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet); - -#ifdef CONFIG_BACKGROUND_NOISE_MONITOR -struct noise_info { - u8 bPauseDIG; - u8 IGIValue; - u32 max_time;/* ms */ - u8 chan; -}; -#endif - #endif /* __HAL_COMMON_H__ */ diff --git a/drivers/staging/rtl8723bs/include/hal_com_h2c.h b/drivers/staging/rtl8723bs/include/hal_com_h2c.h index b951bc288b89438d3e951bc30fec053b5158b139..24cd9415fa95d39760ecfe81968f7d93938bc00d 100644 --- a/drivers/staging/rtl8723bs/include/hal_com_h2c.h +++ b/drivers/staging/rtl8723bs/include/hal_com_h2c.h @@ -7,71 +7,6 @@ #ifndef __COMMON_H2C_H__ #define __COMMON_H2C_H__ -/* */ -/* H2C CMD DEFINITION ------------------------------------------------ */ -/* */ -/* 88e, 8723b, 8812, 8821, 92e use the same FW code base */ -enum h2c_cmd { - /* Common Class: 000 */ - H2C_RSVD_PAGE = 0x00, - H2C_MEDIA_STATUS_RPT = 0x01, - H2C_SCAN_ENABLE = 0x02, - H2C_KEEP_ALIVE = 0x03, - H2C_DISCON_DECISION = 0x04, - H2C_PSD_OFFLOAD = 0x05, - H2C_AP_OFFLOAD = 0x08, - H2C_BCN_RSVDPAGE = 0x09, - H2C_PROBERSP_RSVDPAGE = 0x0A, - H2C_FCS_RSVDPAGE = 0x10, - H2C_FCS_INFO = 0x11, - H2C_AP_WOW_GPIO_CTRL = 0x13, - - /* PoweSave Class: 001 */ - H2C_SET_PWR_MODE = 0x20, - H2C_PS_TUNING_PARA = 0x21, - H2C_PS_TUNING_PARA2 = 0x22, - H2C_P2P_LPS_PARAM = 0x23, - H2C_P2P_PS_OFFLOAD = 0x24, - H2C_PS_SCAN_ENABLE = 0x25, - H2C_SAP_PS_ = 0x26, - H2C_INACTIVE_PS_ = 0x27, /* Inactive_PS */ - H2C_FWLPS_IN_IPS_ = 0x28, - - /* Dynamic Mechanism Class: 010 */ - H2C_MACID_CFG = 0x40, - H2C_TXBF = 0x41, - H2C_RSSI_SETTING = 0x42, - H2C_AP_REQ_TXRPT = 0x43, - H2C_INIT_RATE_COLLECT = 0x44, - - /* BT Class: 011 */ - H2C_B_TYPE_TDMA = 0x60, - H2C_BT_INFO = 0x61, - H2C_FORCE_BT_TXPWR = 0x62, - H2C_BT_IGNORE_WLANACT = 0x63, - H2C_DAC_SWING_VALUE = 0x64, - H2C_ANT_SEL_RSV = 0x65, - H2C_WL_OPMODE = 0x66, - H2C_BT_MP_OPER = 0x67, - H2C_BT_CONTROL = 0x68, - H2C_BT_WIFI_CTRL = 0x69, - H2C_BT_FW_PATCH = 0x6A, - - /* WOWLAN Class: 100 */ - H2C_WOWLAN = 0x80, - H2C_REMOTE_WAKE_CTRL = 0x81, - H2C_AOAC_GLOBAL_INFO = 0x82, - H2C_AOAC_RSVD_PAGE = 0x83, - H2C_AOAC_RSVD_PAGE2 = 0x84, - H2C_D0_SCAN_OFFLOAD_CTRL = 0x85, - H2C_D0_SCAN_OFFLOAD_INFO = 0x86, - H2C_CHNL_SWITCH_OFFLOAD = 0x87, - H2C_AOAC_RSVDPAGE3 = 0x88, - - H2C_RESET_TSF = 0xC0, - H2C_MAXID, -}; - #define H2C_RSVDPAGE_LOC_LEN 5 #define H2C_MEDIA_STATUS_RPT_LEN 3 #define H2C_KEEP_ALIVE_CTRL_LEN 2 @@ -95,60 +30,6 @@ enum h2c_cmd { #define H2C_BCN_RSVDPAGE_LEN 5 #define H2C_PROBERSP_RSVDPAGE_LEN 5 -#ifdef CONFIG_WOWLAN -#define eqMacAddr(a, b) (((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1 : 0) -#define cpMacAddr(des, src) ((des)[0] = (src)[0], (des)[1] = (src)[1], (des)[2] = (src)[2], (des)[3] = (src)[3], (des)[4] = (src)[4], (des)[5] = (src)[5]) -#define cpIpAddr(des, src) ((des)[0] = (src)[0], (des)[1] = (src)[1], (des)[2] = (src)[2], (des)[3] = (src)[3]) - -/* */ -/* ARP packet */ -/* */ -/* LLC Header */ -#define GET_ARP_PKT_LLC_TYPE(__pHeader) ReadEF2Byte(((u8 *)(__pHeader)) + 6) - -/* ARP element */ -#define GET_ARP_PKT_OPERATION(__pHeader) ReadEF2Byte(((u8 *)(__pHeader)) + 6) -#define GET_ARP_PKT_SENDER_MAC_ADDR(__pHeader, _val) cpMacAddr((u8 *)(_val), ((u8 *)(__pHeader))+8) -#define GET_ARP_PKT_SENDER_IP_ADDR(__pHeader, _val) cpIpAddr((u8 *)(_val), ((u8 *)(__pHeader))+14) -#define GET_ARP_PKT_TARGET_MAC_ADDR(__pHeader, _val) cpMacAddr((u8 *)(_val), ((u8 *)(__pHeader))+18) -#define GET_ARP_PKT_TARGET_IP_ADDR(__pHeader, _val) cpIpAddr((u8 *)(_val), ((u8 *)(__pHeader))+24) - -#define SET_ARP_PKT_HW(__pHeader, __Value) WRITEEF2BYTE(((u8 *)(__pHeader)) + 0, __Value) -#define SET_ARP_PKT_PROTOCOL(__pHeader, __Value) WRITEEF2BYTE(((u8 *)(__pHeader)) + 2, __Value) -#define SET_ARP_PKT_HW_ADDR_LEN(__pHeader, __Value) WRITEEF1BYTE(((u8 *)(__pHeader)) + 4, __Value) -#define SET_ARP_PKT_PROTOCOL_ADDR_LEN(__pHeader, __Value) WRITEEF1BYTE(((u8 *)(__pHeader)) + 5, __Value) -#define SET_ARP_PKT_OPERATION(__pHeader, __Value) WRITEEF2BYTE(((u8 *)(__pHeader)) + 6, __Value) -#define SET_ARP_PKT_SENDER_MAC_ADDR(__pHeader, _val) cpMacAddr(((u8 *)(__pHeader))+8, (u8 *)(_val)) -#define SET_ARP_PKT_SENDER_IP_ADDR(__pHeader, _val) cpIpAddr(((u8 *)(__pHeader))+14, (u8 *)(_val)) -#define SET_ARP_PKT_TARGET_MAC_ADDR(__pHeader, _val) cpMacAddr(((u8 *)(__pHeader))+18, (u8 *)(_val)) -#define SET_ARP_PKT_TARGET_IP_ADDR(__pHeader, _val) cpIpAddr(((u8 *)(__pHeader))+24, (u8 *)(_val)) - -#define FW_WOWLAN_FUN_EN BIT(0) -#define FW_WOWLAN_PATTERN_MATCH BIT(1) -#define FW_WOWLAN_MAGIC_PKT BIT(2) -#define FW_WOWLAN_UNICAST BIT(3) -#define FW_WOWLAN_ALL_PKT_DROP BIT(4) -#define FW_WOWLAN_GPIO_ACTIVE BIT(5) -#define FW_WOWLAN_REKEY_WAKEUP BIT(6) -#define FW_WOWLAN_DEAUTH_WAKEUP BIT(7) - -#define FW_WOWLAN_GPIO_WAKEUP_EN BIT(0) -#define FW_FW_PARSE_MAGIC_PKT BIT(1) - -#define FW_REMOTE_WAKE_CTRL_EN BIT(0) -#define FW_REALWOWLAN_EN BIT(5) - -#define FW_WOWLAN_KEEP_ALIVE_EN BIT(0) -#define FW_ADOPT_USER BIT(1) -#define FW_WOWLAN_KEEP_ALIVE_PKT_TYPE BIT(2) - -#define FW_REMOTE_WAKE_CTRL_EN BIT(0) -#define FW_ARP_EN BIT(1) -#define FW_REALWOWLAN_EN BIT(5) -#define FW_WOW_FW_UNICAST_EN BIT(7) - -#endif /* CONFIG_WOWLAN */ - /* _RSVDPAGE_LOC_CMD_0x00 */ #define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) #define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) @@ -174,28 +55,6 @@ enum h2c_cmd { #define SET_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) #define SET_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+2, 0, 8, __Value) -#ifdef CONFIG_AP_WOWLAN -/* _AP_Offload 0x08 */ -#define SET_H2CCMD_AP_WOWLAN_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) -/* _BCN_RsvdPage 0x09 */ -#define SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) -/* _Probersp_RsvdPage 0x0a */ -#define SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) -/* _Probersp_RsvdPage 0x13 */ -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 4, __Value) -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_C2H_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 1, __Value) -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 5, 1, __Value) -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 6, 1, __Value) -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 7, 1, __Value) -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) -#define SET_H2CCMD_AP_WOW_GPIO_CTRL_C2H_DURATION(__pH2CCmd, __Value)SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) -/* _AP_PS 0x26 */ -#define SET_H2CCMD_AP_WOW_PS_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) -#define SET_H2CCMD_AP_WOW_PS_32K_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) -#define SET_H2CCMD_AP_WOW_PS_RF(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) -#define SET_H2CCMD_AP_WOW_PS_DURATION(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) -#endif - /* _WoWLAN PARAM_CMD_0x80 */ #define SET_H2CCMD_WOWLAN_FUNC_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) #define SET_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) @@ -230,56 +89,16 @@ enum h2c_cmd { #define SET_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) #define SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) #define SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+4, 0, 8, __Value) -#ifdef CONFIG_GTK_OL -#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+5, 0, 8, __Value) -#endif /* CONFIG_GTK_OL */ -#ifdef CONFIG_PNO_SUPPORT -#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_NLO_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd), 0, 8, __Value) -#endif - -#ifdef CONFIG_PNO_SUPPORT -/* D0_Scan_Offload_Info_0x86 */ -#define SET_H2CCMD_AOAC_NLO_FUN_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd), 3, 1, __Value) -#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_PROBE_PACKET(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) -#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_SCAN_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) -#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_SSID_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) -#endif /* CONFIG_PNO_SUPPORT */ /* */ /* Structure -------------------------------------------------- */ /* */ -typedef struct _RSVDPAGE_LOC { +struct rsvdpage_loc { u8 LocProbeRsp; u8 LocPsPoll; u8 LocNullData; u8 LocQosNull; u8 LocBTQosNull; -#ifdef CONFIG_WOWLAN - u8 LocRemoteCtrlInfo; - u8 LocArpRsp; - u8 LocNbrAdv; - u8 LocGTKRsp; - u8 LocGTKInfo; - u8 LocProbeReq; - u8 LocNetList; -#ifdef CONFIG_GTK_OL - u8 LocGTKEXTMEM; -#endif /* CONFIG_GTK_OL */ -#ifdef CONFIG_PNO_SUPPORT - u8 LocPNOInfo; - u8 LocScanInfo; - u8 LocSSIDInfo; - u8 LocProbePacket; -#endif /* CONFIG_PNO_SUPPORT */ -#endif /* CONFIG_WOWLAN */ -#ifdef CONFIG_AP_WOWLAN - u8 LocApOffloadBCN; -#endif /* CONFIG_AP_WOWLAN */ -} RSVDPAGE_LOC, *PRSVDPAGE_LOC; +}; #endif -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -void rtw_get_current_ip_address(struct adapter *padapter, u8 *pcurrentip); -void rtw_get_sec_iv(struct adapter *padapter, u8*pcur_dot11txpn, u8 *StaAddr); -void rtw_set_sec_pn(struct adapter *padapter); -#endif diff --git a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h index 9fff4aa36546761778db3555c6bb1fd16008847d..73f6cadb5c790f30645deabdfc4ff2c2310b2147 100644 --- a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h +++ b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h @@ -12,7 +12,7 @@ #define PathC 0x2 #define PathD 0x3 -enum RATE_SECTION { +enum rate_section { CCK = 0, OFDM, HT_MCS0_MCS7, @@ -25,7 +25,7 @@ enum RATE_SECTION { VHT_4SSMCS0_4SSMCS9, }; -enum RF_TX_NUM { +enum { RF_1TX = 0, RF_2TX, RF_3TX, @@ -36,7 +36,7 @@ enum RF_TX_NUM { #define MAX_POWER_INDEX 0x3F -enum _REGULATION_TXPWR_LMT { +enum { TXPWR_LMT_FCC = 0, TXPWR_LMT_MKK, TXPWR_LMT_ETSI, @@ -72,11 +72,11 @@ struct bb_register_def { u8 PHY_GetTxPowerByRateBase( -struct adapter * Adapter, +struct adapter *Adapter, u8 Band, u8 RfPath, u8 TxNum, -enum RATE_SECTION RateSection +enum rate_section RateSection ); u8 @@ -92,9 +92,9 @@ struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Value, - u8* RateIndex, - s8* PwrByRateVal, - u8* RateNum +u8 *RateIndex, +s8 *PwrByRateVal, +u8 *RateNum ); u8 @@ -104,7 +104,7 @@ u8 Rate void PHY_SetTxPowerIndexByRateSection( -struct adapter * padapter, +struct adapter *padapter, u8 RFPath, u8 Channel, u8 RateSection @@ -138,11 +138,11 @@ u8 path void PHY_SetTxPowerIndexByRateArray( -struct adapter * padapter, +struct adapter *padapter, u8 RFPath, -enum CHANNEL_WIDTH BandWidth, +enum channel_width BandWidth, u8 Channel, -u8* Rates, +u8 *Rates, u8 RateArraySize ); @@ -164,21 +164,21 @@ u32 Data void PHY_TxPowerByRateConfiguration( - struct adapter * padapter + struct adapter *padapter ); u8 PHY_GetTxPowerIndexBase( -struct adapter * padapter, +struct adapter *padapter, u8 RFPath, u8 Rate, -enum CHANNEL_WIDTH BandWidth, +enum channel_width BandWidth, u8 Channel, bool *bIn24G ); s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 RegPwrTblSel, - enum BAND_TYPE Band, enum CHANNEL_WIDTH Bandwidth, + enum band_type Band, enum channel_width Bandwidth, u8 RfPath, u8 DataRate, u8 Channel @@ -186,7 +186,7 @@ u8 Channel void PHY_SetTxPowerLimit( -struct adapter * Adapter, +struct adapter *Adapter, u8 *Regulation, u8 *Band, u8 *Bandwidth, @@ -198,12 +198,12 @@ u8 *PowerLimit void PHY_ConvertTxPowerLimitToPowerIndex( -struct adapter * Adapter +struct adapter *Adapter ); void PHY_InitTxPowerLimit( -struct adapter * Adapter +struct adapter *Adapter ); s8 @@ -215,7 +215,7 @@ PHY_GetTxPowerTrackingOffset( void Hal_ChannelPlanToRegulation( -struct adapter * Adapter, +struct adapter *Adapter, u16 ChannelPlan ); diff --git a/drivers/staging/rtl8723bs/include/hal_com_reg.h b/drivers/staging/rtl8723bs/include/hal_com_reg.h index 37fa59a352d60e24a700c963a301238082d16d43..b14585cb023317b9868a4d32d175b11bef5a101f 100644 --- a/drivers/staging/rtl8723bs/include/hal_com_reg.h +++ b/drivers/staging/rtl8723bs/include/hal_com_reg.h @@ -707,14 +707,6 @@ Default: 00b. /* ALL CCK Rate */ -#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 - #define RATE_BITMAP_ALL 0xFFFFF /* Only use CCK 1M rate for ACK */ @@ -776,14 +768,14 @@ Default: 00b. #define IMR_BCNDMAINT3 BIT28 /* Beacon DMA Interrupt 3 */ #define IMR_BCNDMAINT2 BIT27 /* Beacon DMA Interrupt 2 */ #define IMR_BCNDMAINT1 BIT26 /* Beacon DMA Interrupt 1 */ -#define IMR_BCNDOK8 BIT25 /* Beacon Queue DMA OK Interrup 8 */ -#define IMR_BCNDOK7 BIT24 /* Beacon Queue DMA OK Interrup 7 */ -#define IMR_BCNDOK6 BIT23 /* Beacon Queue DMA OK Interrup 6 */ -#define IMR_BCNDOK5 BIT22 /* Beacon Queue DMA OK Interrup 5 */ -#define IMR_BCNDOK4 BIT21 /* Beacon Queue DMA OK Interrup 4 */ -#define IMR_BCNDOK3 BIT20 /* Beacon Queue DMA OK Interrup 3 */ -#define IMR_BCNDOK2 BIT19 /* Beacon Queue DMA OK Interrup 2 */ -#define IMR_BCNDOK1 BIT18 /* Beacon Queue DMA OK Interrup 1 */ +#define IMR_BCNDOK8 BIT25 /* Beacon Queue DMA OK Interrupt 8 */ +#define IMR_BCNDOK7 BIT24 /* Beacon Queue DMA OK Interrupt 7 */ +#define IMR_BCNDOK6 BIT23 /* Beacon Queue DMA OK Interrupt 6 */ +#define IMR_BCNDOK5 BIT22 /* Beacon Queue DMA OK Interrupt 5 */ +#define IMR_BCNDOK4 BIT21 /* Beacon Queue DMA OK Interrupt 4 */ +#define IMR_BCNDOK3 BIT20 /* Beacon Queue DMA OK Interrupt 3 */ +#define IMR_BCNDOK2 BIT19 /* Beacon Queue DMA OK Interrupt 2 */ +#define IMR_BCNDOK1 BIT18 /* Beacon Queue DMA OK Interrupt 1 */ #define IMR_TIMEOUT2 BIT17 /* Timeout interrupt 2 */ #define IMR_TIMEOUT1 BIT16 /* Timeout interrupt 1 */ #define IMR_TXFOVW BIT15 /* Transmit FIFO Overflow */ @@ -792,9 +784,9 @@ Default: 00b. #define IMR_RXFOVW BIT12 /* Receive FIFO Overflow */ #define IMR_RDU BIT11 /* Receive Descriptor Unavailable */ #define IMR_ATIMEND BIT10 /* For 92C, ATIM Window End Interrupt. For 8723 and later ICs, it also means P2P CTWin End interrupt. */ -#define IMR_BDOK BIT9 /* Beacon Queue DMA OK Interrup */ +#define IMR_BDOK BIT9 /* Beacon Queue DMA OK Interrupt */ #define IMR_HIGHDOK BIT8 /* High Queue DMA OK Interrupt */ -#define IMR_TBDOK BIT7 /* Transmit Beacon OK interrup */ +#define IMR_TBDOK BIT7 /* Transmit Beacon OK interrupt */ #define IMR_MGNTDOK BIT6 /* Management Queue DMA OK Interrupt */ #define IMR_TBDER BIT5 /* For 92C, Transmit Beacon Error Interrupt */ #define IMR_BKDOK BIT4 /* AC_BK DMA OK Interrupt */ @@ -964,13 +956,13 @@ Default: 00b. #define IMR_BCNDMAINT3_88E BIT23 /* Beacon DMA Interrupt 3 */ #define IMR_BCNDMAINT2_88E BIT22 /* Beacon DMA Interrupt 2 */ #define IMR_BCNDMAINT1_88E BIT21 /* Beacon DMA Interrupt 1 */ -#define IMR_BCNDOK7_88E BIT20 /* Beacon Queue DMA OK Interrup 7 */ -#define IMR_BCNDOK6_88E BIT19 /* Beacon Queue DMA OK Interrup 6 */ -#define IMR_BCNDOK5_88E BIT18 /* Beacon Queue DMA OK Interrup 5 */ -#define IMR_BCNDOK4_88E BIT17 /* Beacon Queue DMA OK Interrup 4 */ -#define IMR_BCNDOK3_88E BIT16 /* Beacon Queue DMA OK Interrup 3 */ -#define IMR_BCNDOK2_88E BIT15 /* Beacon Queue DMA OK Interrup 2 */ -#define IMR_BCNDOK1_88E BIT14 /* Beacon Queue DMA OK Interrup 1 */ +#define IMR_BCNDOK7_88E BIT20 /* Beacon Queue DMA OK Interrupt 7 */ +#define IMR_BCNDOK6_88E BIT19 /* Beacon Queue DMA OK Interrupt 6 */ +#define IMR_BCNDOK5_88E BIT18 /* Beacon Queue DMA OK Interrupt 5 */ +#define IMR_BCNDOK4_88E BIT17 /* Beacon Queue DMA OK Interrupt 4 */ +#define IMR_BCNDOK3_88E BIT16 /* Beacon Queue DMA OK Interrupt 3 */ +#define IMR_BCNDOK2_88E BIT15 /* Beacon Queue DMA OK Interrupt 2 */ +#define IMR_BCNDOK1_88E BIT14 /* Beacon Queue DMA OK Interrupt 1 */ #define IMR_ATIMEND_E_88E BIT13 /* ATIM Window End Extension for Win7 */ #define IMR_TXERR_88E BIT11 /* Tx Error Flag Interrupt Status, write 1 clear. */ #define IMR_RXERR_88E BIT10 /* Rx Error Flag INT Status, Write 1 clear */ @@ -1002,9 +994,9 @@ Current IOREG MAP /* 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) */ /* */ /* Note: */ -/* The the bits of stoping AC(VO/VI/BE/BK) queue in datasheet RTL8192S/RTL8192C are wrong, */ -/* the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2, and BK - Bit3. */ -/* 8723 and 88E may be not correct either in the eralier version. Confirmed with DD Tim. */ +/* The bits of stopping AC(VO/VI/BE/BK) queue in datasheet RTL8192S/RTL8192C are wrong, */ +/* the correct arrangement is VO - Bit0, VI - Bit1, BE - Bit2, and BK - Bit3. */ +/* 8723 and 88E may be not correct either in the earlier version. Confirmed with DD Tim. */ /* By Bruce, 2011-09-22. */ #define StopBecon BIT6 #define StopHigh BIT5 diff --git a/drivers/staging/rtl8723bs/include/hal_data.h b/drivers/staging/rtl8723bs/include/hal_data.h index fa5d70016f0582846e83a1049b32486ad209e845..babcb03a7c231392bd7bdb3e0d3c256013c8e3b1 100644 --- a/drivers/staging/rtl8723bs/include/hal_data.h +++ b/drivers/staging/rtl8723bs/include/hal_data.h @@ -15,7 +15,7 @@ /* */ /* <Roger_Notes> For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. */ /* */ -enum RT_MULTI_FUNC { +enum rt_multi_func { RT_MULTI_FUNC_NONE = 0x00, RT_MULTI_FUNC_WIFI = 0x01, RT_MULTI_FUNC_BT = 0x02, @@ -24,18 +24,18 @@ enum RT_MULTI_FUNC { /* */ /* <Roger_Notes> For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. */ /* */ -enum RT_POLARITY_CTL { +enum rt_polarity_ctl { RT_POLARITY_LOW_ACT = 0, RT_POLARITY_HIGH_ACT = 1, }; /* For RTL8723 regulator mode. by tynli. 2011.01.14. */ -enum RT_REGULATOR_MODE { +enum rt_regulator_mode { RT_SWITCHING_REGULATOR = 0, RT_LDO_REGULATOR = 1, }; -enum RT_AMPDU_BURST { +enum rt_ampdu_burst { RT_AMPDU_BURST_NONE = 0, RT_AMPDU_BURST_92D = 1, RT_AMPDU_BURST_88E = 2, @@ -46,16 +46,14 @@ enum RT_AMPDU_BURST { RT_AMPDU_BURST_8723B = 7, }; -#define CHANNEL_MAX_NUMBER 14+24+21 /* 14 is the max channel number */ +#define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel number */ #define CHANNEL_MAX_NUMBER_2G 14 #define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to "phy_GetChnlGroup8812A" and "Hal_ReadTxPowerInfo8812A" */ #define CHANNEL_MAX_NUMBER_5G_80M 7 -#define CHANNEL_GROUP_MAX 3+9 /* ch1~3, ch4~9, ch10~14 total three groups */ #define MAX_PG_GROUP 13 /* Tx Power Limit Table Size */ #define MAX_REGULATION_NUM 4 -#define MAX_RF_PATH_NUM_IN_POWER_LIMIT_TABLE 4 #define MAX_2_4G_BANDWIDTH_NUM 4 #define MAX_RATE_SECTION_NUM 10 #define MAX_5G_BANDWIDTH_NUM 4 @@ -69,11 +67,6 @@ enum RT_AMPDU_BURST { /* define IQK_ADDA_REG_NUM 16 */ /* define IQK_BB_REG_NUM 10 */ -#define IQK_BB_REG_NUM_92C 9 -#define IQK_BB_REG_NUM_92D 10 -#define IQK_BB_REG_NUM_test 6 - -#define IQK_Matrix_Settings_NUM_92D 1+24+21 /* define HP_THERMAL_NUM 8 */ /* duplicate code, will move to ODM ######### */ @@ -176,10 +169,10 @@ struct dm_priv { struct hal_com_data { - HAL_VERSION VersionID; - enum RT_MULTI_FUNC MultiFunc; /* For multi-function consideration. */ - enum RT_POLARITY_CTL PolarityCtl; /* For Wifi PDn Polarity control. */ - enum RT_REGULATOR_MODE RegulatorMode; /* switching regulator or LDO */ + struct hal_version VersionID; + enum rt_multi_func MultiFunc; /* For multi-function consideration. */ + enum rt_polarity_ctl PolarityCtl; /* For Wifi PDn Polarity control. */ + enum rt_regulator_mode RegulatorMode; /* switching regulator or LDO */ u16 FirmwareVersion; u16 FirmwareVersionRev; @@ -187,10 +180,10 @@ struct hal_com_data { u16 FirmwareSignature; /* current WIFI_PHY values */ - enum WIRELESS_MODE CurrentWirelessMode; - enum CHANNEL_WIDTH CurrentChannelBW; - enum BAND_TYPE CurrentBandType; /* 0:2.4G, 1:5G */ - enum BAND_TYPE BandSet; + enum wireless_mode CurrentWirelessMode; + enum channel_width CurrentChannelBW; + enum band_type CurrentBandType; /* 0:2.4G, 1:5G */ + enum band_type BandSet; u8 CurrentChannel; u8 CurrentCenterFrequencyIndex1; u8 nCur40MhzPrimeSC;/* Control channel sub-carrier */ @@ -233,7 +226,7 @@ struct hal_com_data { bool EepromOrEfuse; u8 EfuseUsedPercentage; u16 EfuseUsedBytes; - EFUSE_HAL EfuseHal; + struct efuse_hal EfuseHal; /* 3 [2.4G] */ u8 Index24G_CCK_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; @@ -396,7 +389,7 @@ struct hal_com_data { u8 OutEpQueueSel; u8 OutEpNumber; - /* 2010/12/10 MH Add for USB aggreation mode dynamic shceme. */ + /* 2010/12/10 MH Add for USB aggregation mode dynamic scheme. */ bool UsbRxHighSpeedMode; /* 2010/11/22 MH Add for slim combo debug mode selective. */ @@ -411,7 +404,7 @@ struct hal_com_data { u8 RegIQKFWOffload; struct submit_ctx iqk_sctx; - enum RT_AMPDU_BURST AMPDUBurstMode; /* 92C maybe not use, but for compile successfully */ + enum rt_ampdu_burst AMPDUBurstMode; /* 92C maybe not use, but for compile successfully */ u32 sdio_himr; u32 sdio_hisr; @@ -419,7 +412,7 @@ struct hal_com_data { /* SDIO Tx FIFO related. */ /* HIQ, MID, LOW, PUB free pages; padapter->xmitpriv.free_txpg */ u8 SdioTxFIFOFreePage[SDIO_TX_FREE_PG_QUEUE]; - _lock SdioTxFIFOFreePageLock; + spinlock_t SdioTxFIFOFreePageLock; u8 SdioTxOQTMaxFreeSpace; u8 SdioTxOQTFreeSpace; @@ -431,19 +424,14 @@ struct hal_com_data { u32 sdio_tx_max_len[SDIO_MAX_TX_QUEUE];/* H, N, L, used for sdio tx aggregation max length per queue */ struct dm_priv dmpriv; - DM_ODM_T odmpriv; + struct dm_odm_t odmpriv; /* For bluetooth co-existance */ - BT_COEXIST bt_coexist; + struct bt_coexist bt_coexist; /* Interrupt related register information. */ u32 SysIntrStatus; u32 SysIntrMask; - -#ifdef CONFIG_BACKGROUND_NOISE_MONITOR - s16 noise[ODM_MAX_CHANNEL_NUM]; -#endif - }; #define GET_HAL_DATA(__padapter) ((struct hal_com_data *)((__padapter)->HalData)) diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index 426c8d58c444ab045e49189e3e38a56eb5180bfe..45bebbadb7ca9b77193d420aef3d4475350144d7 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -8,14 +8,14 @@ #define __HAL_INTF_H__ -enum RTL871X_HCI_TYPE { +enum { RTW_PCIE = BIT0, RTW_USB = BIT1, RTW_SDIO = BIT2, RTW_GSPI = BIT3, }; -enum HW_VARIABLES { +enum { HW_VAR_MEDIA_STATUS, HW_VAR_MEDIA_STATUS1, HW_VAR_SET_OPMODE, @@ -85,14 +85,6 @@ enum HW_VARIABLES { HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ /* The valid upper nav range for the HW updating, if the true value is larger than the upper range, the HW won't update it. */ /* Unit in microsecond. 0 means disable this function. */ -#ifdef CONFIG_WOWLAN - HW_VAR_WOWLAN, - HW_VAR_WAKEUP_REASON, - HW_VAR_RPWM_TOG, -#endif -#ifdef CONFIG_AP_WOWLAN - HW_VAR_AP_WOWLAN, -#endif HW_VAR_SYS_CLKR, HW_VAR_NAV_UPPER, HW_VAR_C2H_HANDLE, @@ -120,7 +112,7 @@ enum HW_VARIABLES { HW_VAR_MACID_WAKEUP, }; -enum HAL_DEF_VARIABLE { +enum hal_def_variable { HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, HAL_DEF_IS_SUPPORT_ANT_DIV, HAL_DEF_CURRENT_ANTENNA, @@ -155,14 +147,14 @@ enum HAL_DEF_VARIABLE { HAL_DEF_DBG_RX_INFO_DUMP, }; -enum HAL_ODM_VARIABLE { +enum hal_odm_variable { HAL_ODM_STA_INFO, HAL_ODM_P2P_STATE, HAL_ODM_WIFI_DISPLAY_STATE, HAL_ODM_NOISE_MONITOR, }; -enum HAL_INTF_PS_FUNC { +enum hal_intf_ps_func { HAL_USB_SELECT_SUSPEND, HAL_MAX_ID, }; @@ -202,9 +194,9 @@ struct hal_ops { 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_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_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); @@ -218,11 +210,11 @@ struct hal_ops { 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); + 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 (*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); @@ -232,7 +224,7 @@ struct hal_ops { 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); + 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); /* @@ -265,12 +257,6 @@ struct hal_ops { s32 (*fill_h2c_cmd)(struct adapter *, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); }; -enum RT_EEPROM_TYPE { - EEPROM_93C46, - EEPROM_93C56, - EEPROM_BOOT_EFUSE, -}; - #define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_IPS BIT28 #define RF_CHANGE_BY_PS BIT29 @@ -280,30 +266,6 @@ enum RT_EEPROM_TYPE { #define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv) #define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) -enum wowlan_subcode { - WOWLAN_PATTERN_MATCH = 1, - WOWLAN_MAGIC_PACKET = 2, - WOWLAN_UNICAST = 3, - WOWLAN_SET_PATTERN = 4, - WOWLAN_DUMP_REG = 5, - WOWLAN_ENABLE = 6, - WOWLAN_DISABLE = 7, - WOWLAN_STATUS = 8, - WOWLAN_DEBUG_RELOAD_FW = 9, - WOWLAN_DEBUG_1 = 10, - WOWLAN_DEBUG_2 = 11, - WOWLAN_AP_ENABLE = 12, - WOWLAN_AP_DISABLE = 13 -}; - -struct wowlan_ioctl_param { - unsigned int subcode; - unsigned int subcode_value; - unsigned int wakeup_reason; - unsigned int len; - unsigned char pattern[0]; -}; - #define Rx_Pairwisekey 0x01 #define Rx_GTK 0x02 #define Rx_DisAssoc 0x04 @@ -335,11 +297,11 @@ void rtw_hal_chip_configure(struct adapter *padapter); void rtw_hal_read_chip_info(struct adapter *padapter); void rtw_hal_read_chip_version(struct adapter *padapter); -u8 rtw_hal_set_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue); -u8 rtw_hal_get_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue); +u8 rtw_hal_set_def_var(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue); +u8 rtw_hal_get_def_var(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue); -void rtw_hal_set_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, bool bSet); -void rtw_hal_get_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, void *pValue2); +void rtw_hal_set_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet); +void rtw_hal_get_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, void *pValue2); void rtw_hal_enable_interrupt(struct adapter *padapter); void rtw_hal_disable_interrupt(struct adapter *padapter); @@ -378,7 +340,7 @@ void rtw_hal_write_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 #define PHY_QueryMacReg PHY_QueryBBReg void rtw_hal_set_chan(struct adapter *padapter, u8 channel); -void rtw_hal_set_chnl_bw(struct adapter *padapter, u8 channel, enum CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80); +void rtw_hal_set_chnl_bw(struct adapter *padapter, u8 channel, enum channel_width Bandwidth, u8 Offset40, u8 Offset80); void rtw_hal_dm_watchdog(struct adapter *padapter); void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/include/hal_phy.h b/drivers/staging/rtl8723bs/include/hal_phy.h index ed0caa0574e393d97cf24ffdc3b15840c441a6b9..521eb1c2efad0f9e5ac285cb23fd5e677dea46cb 100644 --- a/drivers/staging/rtl8723bs/include/hal_phy.h +++ b/drivers/staging/rtl8723bs/include/hal_phy.h @@ -20,17 +20,6 @@ #define HAL_RF_ENABLE 1 #endif -#define RF6052_MAX_TX_PWR 0x3F -#define RF6052_MAX_REG_88E 0xFF -#define RF6052_MAX_REG_92C 0x7F - -#define RF6052_MAX_REG \ - (RF6052_MAX_REG_88E > RF6052_MAX_REG_92C) ? RF6052_MAX_REG_88E : RF6052_MAX_REG_92C - -#define GET_RF6052_REAL_MAX_REG(_Adapter) RF6052_MAX_REG_92C - -#define RF6052_MAX_PATH 2 - /* */ /* Antenna detection method, i.e., using single tone detection or RSSI reported from each antenna detected. */ /* Added by Roger, 2013.05.22. */ @@ -42,14 +31,14 @@ /*--------------------------Define Parameters-------------------------------*/ -enum BAND_TYPE { +enum band_type { BAND_ON_2_4G = 0, BAND_ON_5G, BAND_ON_BOTH, BANDMAX }; -enum RF_TYPE { +enum { RF_TYPE_MIN = 0, /* 0 */ RF_8225 = 1, /* 1 11b/g RF for verification only */ RF_8256 = 2, /* 2 11b/g/n */ @@ -59,7 +48,7 @@ enum RF_TYPE { RF_TYPE_MAX }; -enum RF_PATH { +enum rf_path { RF_PATH_A = 0, RF_PATH_B, RF_PATH_C, @@ -74,49 +63,7 @@ enum RF_PATH { #define RF_PATH_MAX_92C_88E 2 #define RF_PATH_MAX_90_8812 4 /* Max RF number 90 support */ -enum ANTENNA_PATH { - ANTENNA_NONE = 0, - ANTENNA_D = 1, - ANTENNA_C = 2, - ANTENNA_CD = 3, - ANTENNA_B = 4, - ANTENNA_BD = 5, - ANTENNA_BC = 6, - ANTENNA_BCD = 7, - ANTENNA_A = 8, - ANTENNA_AD = 9, - ANTENNA_AC = 10, - ANTENNA_ACD = 11, - ANTENNA_AB = 12, - ANTENNA_ABD = 13, - ANTENNA_ABC = 14, - ANTENNA_ABCD = 15 -}; - -enum RF_CONTENT { - radioa_txt = 0x1000, - radiob_txt = 0x1001, - radioc_txt = 0x1002, - radiod_txt = 0x1003 -}; - -enum BaseBand_Config_Type { - BaseBand_Config_PHY_REG = 0, /* Radio Path A */ - BaseBand_Config_AGC_TAB = 1, /* Radio Path B */ - BaseBand_Config_AGC_TAB_2G = 2, - BaseBand_Config_AGC_TAB_5G = 3, - BaseBand_Config_PHY_REG_PG -}; - -enum HW_BLOCK { - HW_BLOCK_MAC = 0, - HW_BLOCK_PHY0 = 1, - HW_BLOCK_PHY1 = 2, - HW_BLOCK_RF = 3, - HW_BLOCK_MAXIMUM = 4, /* Never use this */ -}; - -enum WIRELESS_MODE { +enum wireless_mode { WIRELESS_MODE_UNKNOWN = 0x00, WIRELESS_MODE_A = 0x01, WIRELESS_MODE_B = 0x02, @@ -146,30 +93,6 @@ struct SwChnlCmd { u32 msDelay; }; -struct R_ANTENNA_SELECT_OFDM { -#ifdef __LITTLE_ENDIAN - 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; -#else - u32 Reserved:2; - u32 OFDM_TXSC:2; - u32 r_ant_non_ht_s1:4; - u32 r_ant_ht_s1:4; - u32 r_ant_ht2:4; - u32 r_ant_ht1:4; - u32 r_ant_non_ht:4; - u32 r_ant_l:4; - u32 r_tx_antenna:4; -#endif -}; - /*--------------------------Exported Function prototype---------------------*/ #endif /* __HAL_COMMON_H__ */ diff --git a/drivers/staging/rtl8723bs/include/hal_phy_cfg.h b/drivers/staging/rtl8723bs/include/hal_phy_cfg.h index ed3488a09d7982a106c8ee7b4ae4e366a3507ae8..ea494bcf830b81e5e62053eca557b94478abec0c 100644 --- a/drivers/staging/rtl8723bs/include/hal_phy_cfg.h +++ b/drivers/staging/rtl8723bs/include/hal_phy_cfg.h @@ -47,20 +47,20 @@ void PHY_SetTxPowerIndex(struct adapter *Adapter, u32 PowerIndex, u8 RFPath, u8 Rate); u8 PHY_GetTxPowerIndex(struct adapter *padapter, u8 RFPath, u8 Rate, - enum CHANNEL_WIDTH BandWidth, u8 Channel); + 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, +void PHY_SetBWMode8723B(struct adapter *Adapter, enum channel_width Bandwidth, unsigned char Offset); /* Call after initialization */ void PHY_SwChnl8723B(struct adapter *Adapter, u8 channel); void PHY_SetSwChnlBWMode8723B(struct adapter *Adapter, u8 channel, - enum CHANNEL_WIDTH Bandwidth, + enum channel_width Bandwidth, u8 Offset40, u8 Offset80); /*--------------------------Exported Function prototype End---------------------*/ diff --git a/drivers/staging/rtl8723bs/include/hal_pwr_seq.h b/drivers/staging/rtl8723bs/include/hal_pwr_seq.h index 28aca047dce63ad7c3247b50bb610e3891951cd7..0a2e607706686f3091f557f9182b67c8448a3500 100644 --- a/drivers/staging/rtl8723bs/include/hal_pwr_seq.h +++ b/drivers/staging/rtl8723bs/include/hal_pwr_seq.h @@ -14,7 +14,7 @@ 4: LPS--Low Power State 5: SUS--Suspend - The transision from different states are defined below + The transition from different states are defined below TRANS_CARDEMU_TO_ACT TRANS_ACT_TO_CARDEMU TRANS_CARDEMU_TO_SUS @@ -219,15 +219,15 @@ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, -extern WLAN_PWR_CFG rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_card_disable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_card_enable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_enter_swlps_flow[RTL8723B_TRANS_ACT_TO_SWLPS_STEPS+RTL8723B_TRANS_END_STEPS]; -extern WLAN_PWR_CFG rtl8723B_leave_swlps_flow[RTL8723B_TRANS_SWLPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_card_disable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_card_enable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_enter_swlps_flow[RTL8723B_TRANS_ACT_TO_SWLPS_STEPS+RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_leave_swlps_flow[RTL8723B_TRANS_SWLPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; #endif diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index f80db2c984a4ee5cd59aed5466c6dba9087781ad..6540c7a229385455a8a770a07226821da7861195 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -125,7 +125,7 @@ extern u8 RSN_CIPHER_SUITE_CCMP[]; extern u8 RSN_CIPHER_SUITE_WEP104[]; -typedef enum _RATEID_IDX_ { +enum { RATEID_IDX_BGN_40M_2SS = 0, RATEID_IDX_BGN_40M_1SS = 1, RATEID_IDX_BGN_20M_2SS_BN = 2, @@ -137,22 +137,9 @@ typedef enum _RATEID_IDX_ { RATEID_IDX_B = 8, RATEID_IDX_VHT_2SS = 9, RATEID_IDX_VHT_1SS = 10, -} RATEID_IDX, *PRATEID_IDX; - -typedef enum _RATR_TABLE_MODE { - RATR_INX_WIRELESS_NGB = 0, /* BGN 40 Mhz 2SS 1SS */ - RATR_INX_WIRELESS_NG = 1, /* GN or N */ - RATR_INX_WIRELESS_NB = 2, /* BGN 20 Mhz 2SS 1SS or BN */ - RATR_INX_WIRELESS_N = 3, - RATR_INX_WIRELESS_GB = 4, - RATR_INX_WIRELESS_G = 5, - RATR_INX_WIRELESS_B = 6, - RATR_INX_WIRELESS_MC = 7, - RATR_INX_WIRELESS_AC_N = 8, -} RATR_TABLE_MODE, *PRATR_TABLE_MODE; - - -enum NETWORK_TYPE { +}; + +enum network_type { WIRELESS_INVALID = 0, /* Sub-Element */ WIRELESS_11B = BIT(0), /* tx: cck only , rx: cck only, hw: cck */ @@ -266,14 +253,6 @@ struct sta_data { /* this is stolen from ipw2200 driver */ #define IEEE_IBSS_MAC_HASH_SIZE 31 -struct ieee_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - struct eapol { u8 snap[6]; u16 ethertype; @@ -282,14 +261,6 @@ struct eapol { u16 length; } __attribute__ ((packed)); -enum eap_type { - EAP_PACKET = 0, - EAPOL_START, - EAPOL_LOGOFF, - EAPOL_KEY, - EAPOL_ENCAP_ASF_ALERT -}; - #define IEEE80211_FCS_LEN 4 #define MIN_FRAG_THRESHOLD 256U @@ -423,7 +394,7 @@ struct ieee80211_snap_hdr { #define IEEE80211_OFDM_SHIFT_MASK_A 4 -enum MGN_RATE { +enum { MGN_1M = 0x02, MGN_2M = 0x04, MGN_5_5M = 0x0B, @@ -521,16 +492,6 @@ enum MGN_RATE { /* 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 ieee80211_rx_stats { - s8 rssi; - u8 signal; - u8 noise; - u8 received_channel; - u16 rate; /* in 100 kbps */ - u8 mask; - u8 freq; - u16 len; -}; /* IEEE 802.11 requires that STA supports concurrent reception of at least * three fragmented frames. This define can be increased to support more @@ -538,61 +499,6 @@ struct ieee80211_rx_stats { * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ #define IEEE80211_FRAG_CACHE_LEN 4 -struct ieee80211_frag_entry { - u32 first_frag_time; - uint seq; - uint last_frag; - uint qos; /* jackson */ - uint tid; /* jackson */ - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - -struct ieee80211_stats { - uint tx_unicast_frames; - uint tx_multicast_frames; - uint tx_fragments; - uint tx_unicast_octets; - uint tx_multicast_octets; - uint tx_deferred_transmissions; - uint tx_single_retry_frames; - uint tx_multiple_retry_frames; - uint tx_retry_limit_exceeded; - uint tx_discards; - uint rx_unicast_frames; - uint rx_multicast_frames; - uint rx_fragments; - uint rx_unicast_octets; - uint rx_multicast_octets; - uint rx_fcs_errors; - uint rx_discards_no_buffer; - uint tx_discards_wrong_sa; - uint rx_discards_undecryptable; - uint rx_message_in_msg_fragments; - uint rx_message_in_bad_msg_fragments; -}; - -struct ieee80211_softmac_stats { - uint rx_ass_ok; - uint rx_ass_err; - uint rx_probe_rq; - uint tx_probe_rs; - uint tx_beacons; - uint rx_auth_rq; - uint rx_auth_rs_ok; - uint rx_auth_rs_err; - uint tx_auth_rq; - uint no_auth_rs; - uint no_ass_rs; - uint tx_ass_rq; - uint rx_ass_rq; - uint tx_probe_rq; - uint reassoc; - uint swtxstop; - uint swtxawake; -}; - #define SEC_KEY_1 (1<<0) #define SEC_KEY_2 (1<<1) #define SEC_KEY_3 (1<<2) @@ -615,18 +521,6 @@ struct ieee80211_softmac_stats { #define BIP_MAX_KEYID 5 #define BIP_AAD_SIZE 20 -struct ieee80211_security { - u16 active_key:2, - enabled:1, - auth_mode:2, - auth_algo:4, - unicast_uses_group:1; - u8 key_sizes[WEP_KEYS]; - u8 keys[WEP_KEYS][WEP_KEY_LEN]; - u8 level; - u16 flags; -} __attribute__ ((packed)); - /* 802.11 data frame from AP @@ -642,15 +536,6 @@ Total: 28-2340 bytes */ -struct ieee80211_header_data { - u16 frame_ctl; - u16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - u16 seq_ctrl; -}; - #define BEACON_PROBE_SSID_ID_POSITION 12 /* Management Frame Information Element Types */ @@ -709,45 +594,6 @@ join_res: > 0: TID */ -enum ieee80211_state { - - /* the card is not linked at all */ - IEEE80211_NOLINK = 0, - - /* IEEE80211_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)*/ - IEEE80211_ASSOCIATING, - IEEE80211_ASSOCIATING_RETRY, - - /* the association procedure is sending AUTH request*/ - IEEE80211_ASSOCIATING_AUTHENTICATING, - - /* the association procedure has successfully authentcated - * and is sending association request - */ - IEEE80211_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 - */ - IEEE80211_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. - */ - IEEE80211_LINKED_SCANNING, - -}; - #define DEFAULT_MAX_SCAN_AGE (15 * HZ) #define DEFAULT_FTS 2346 #define MAC_ARG(x) (x) @@ -781,7 +627,7 @@ static inline int is_zero_mac_addr(const u8 *addr) #define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) /* Action category code */ -enum rtw_ieee80211_category { +enum { RTW_WLAN_CATEGORY_SPECTRUM_MGMT = 0, RTW_WLAN_CATEGORY_QOS = 1, RTW_WLAN_CATEGORY_DLS = 2, @@ -799,7 +645,7 @@ enum rtw_ieee80211_category { RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */ }; -enum _PUBLIC_ACTION { +enum { ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */ ACT_PUBLIC_DSE_ENABLE = 1, ACT_PUBLIC_DSE_DEENABLE = 2, @@ -819,21 +665,6 @@ enum _PUBLIC_ACTION { ACT_PUBLIC_MAX }; -/* BACK (block-ack) parties */ -enum rtw_ieee80211_back_parties { - RTW_WLAN_BACK_RECIPIENT = 0, - RTW_WLAN_BACK_INITIATOR = 1, - RTW_WLAN_BACK_TIMER = 2, -}; - -/* VHT features action code */ -enum rtw_ieee80211_vht_actioncode { - RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING = 0, - RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT = 1, - RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION = 2, -}; - - #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WME_OUI_TYPE 2 @@ -983,22 +814,16 @@ struct rtw_ieee802_11_elems { u8 vht_op_mode_notify_len; }; -typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; +enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 }; -ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, +enum ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, struct rtw_ieee802_11_elems *elems, int show_errors); u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, unsigned int *frlen); -u8 *rtw_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen); - -enum secondary_ch_offset { - SCN = 0, /* no secondary channel */ - SCA = 1, /* secondary channel above */ - SCB = 3, /* secondary channel below */ -}; +u8 *rtw_set_ie(u8 *pbuf, signed int index, uint len, u8 *source, uint *frlen); -u8 *rtw_get_ie(u8*pbuf, sint index, sint *len, sint limit); +u8 *rtw_get_ie(u8 *pbuf, signed int index, signed int *len, signed int limit); u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen); int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len); @@ -1026,7 +851,8 @@ u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 * @buf_len: */ #define for_each_ie(ie, buf, buf_len) \ - for (ie = (void*)buf; (((u8 *)ie) - ((u8 *)buf) + 1) < buf_len; ie = (void*)(((u8 *)ie) + *(((u8 *)ie)+1) + 2)) + for (ie = (void *)buf; (((u8 *)ie) - ((u8 *)buf) + 1) < buf_len; \ + ie = (void *)(((u8 *)ie) + *(((u8 *)ie) + 1) + 2)) uint rtw_get_rateset_len(u8 *rateset); @@ -1046,7 +872,7 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork); void rtw_macaddr_cfg(struct device *dev, u8 *mac_addr); -u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char * MCS_rate); +u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char *MCS_rate); int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action); const char *action_public_str(u8 action); diff --git a/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h b/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h index 44d0a098265970c93cb8029f5c6a42e61e0e1bd1..993a7b3c3d22b6c20825274bacf996070bbdab49 100644 --- a/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h +++ b/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h @@ -7,8 +7,6 @@ #ifndef __IOCTL_CFG80211_H__ #define __IOCTL_CFG80211_H__ -#include <linux/version.h> - struct rtw_wdev_invit_info { u8 state; /* 0: req, 1:rep */ u8 peer_mac[ETH_ALEN]; @@ -67,7 +65,7 @@ struct rtw_wdev_priv { struct adapter *padapter; struct cfg80211_scan_request *scan_request; - _lock scan_req_lock; + spinlock_t scan_req_lock; struct net_device *pmon_ndev;/* for monitor interface */ char ifname_mon[IFNAMSIZ + 1]; /* interface name for monitor interface */ @@ -106,7 +104,7 @@ void rtw_cfg80211_indicate_scan_done(struct adapter *adapter, bool aborted); void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter, u8 *pmgmt_frame, uint frame_len); void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char *da, unsigned short reason); -void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, const char*msg); +void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, const char *msg); bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter); diff --git a/drivers/staging/rtl8723bs/include/osdep_intf.h b/drivers/staging/rtl8723bs/include/osdep_intf.h index c59c1384944b4ea1d5cafc44116dfac467430d0c..48c90f00cc2ebb1d38b305d41d171e023baba8f6 100644 --- a/drivers/staging/rtl8723bs/include/osdep_intf.h +++ b/drivers/staging/rtl8723bs/include/osdep_intf.h @@ -32,15 +32,9 @@ Under Async. IRP (SDIO/USB) The protection mechanism is through the pending queue. */ - _mutex ioctl_mutex; + struct mutex ioctl_mutex; }; - -#ifdef CONFIG_R871X_TEST -int rtw_start_pseudo_adhoc(struct adapter *padapter); -int rtw_stop_pseudo_adhoc(struct adapter *padapter); -#endif - struct dvobj_priv *devobj_init(void); void devobj_deinit(struct dvobj_priv *pdvobj); @@ -70,9 +64,11 @@ int rtw_ips_pwr_up(struct adapter *padapter); void rtw_ips_pwr_down(struct adapter *padapter); int rtw_drv_register_netdev(struct adapter *padapter); -void rtw_ndev_destructor(_nic_hdl ndev); +void rtw_ndev_destructor(struct net_device *ndev); int rtw_suspend_common(struct adapter *padapter); int rtw_resume_common(struct adapter *padapter); +int netdev_open(struct net_device *pnetdev); + #endif /* _OSDEP_INTF_H_ */ diff --git a/drivers/staging/rtl8723bs/include/osdep_service.h b/drivers/staging/rtl8723bs/include/osdep_service.h index dcc3cdce6d4b7a497751c64af26daea6638b60a8..b49838c7e457d4b49c57a0cf158228c2b14970e0 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service.h +++ b/drivers/staging/rtl8723bs/include/osdep_service.h @@ -58,43 +58,13 @@ extern int RTW_STATUS_CODE(int error_code); -/* flags used for rtw_mstat_update() */ -enum mstat_f { - /* type: 0x00ff */ - MSTAT_TYPE_VIR = 0x00, - MSTAT_TYPE_PHY = 0x01, - MSTAT_TYPE_SKB = 0x02, - MSTAT_TYPE_USB = 0x03, - MSTAT_TYPE_MAX = 0x04, - - /* func: 0xff00 */ - MSTAT_FUNC_UNSPECIFIED = 0x00<<8, - MSTAT_FUNC_IO = 0x01<<8, - MSTAT_FUNC_TX_IO = 0x02<<8, - MSTAT_FUNC_RX_IO = 0x03<<8, - MSTAT_FUNC_TX = 0x04<<8, - MSTAT_FUNC_RX = 0x05<<8, - MSTAT_FUNC_MAX = 0x06<<8, -}; - -#define mstat_tf_idx(flags) ((flags)&0xff) -#define mstat_ff_idx(flags) (((flags)&0xff00) >> 8) - -typedef enum mstat_status { - MSTAT_ALLOC_SUCCESS = 0, - MSTAT_ALLOC_FAIL, - MSTAT_FREE -} MSTAT_STATUS; - -#define rtw_mstat_update(flag, status, sz) do {} while (0) -#define rtw_mstat_dump(sel) do {} while (0) void *_rtw_zmalloc(u32 sz); void *_rtw_malloc(u32 sz); void _kfree(u8 *pbuf, u32 sz); struct sk_buff *_rtw_skb_alloc(u32 sz); struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb); -int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb); +int _rtw_netif_rx(struct net_device *ndev, struct sk_buff *skb); #define rtw_malloc(sz) _rtw_malloc((sz)) #define rtw_zmalloc(sz) _rtw_zmalloc((sz)) @@ -136,15 +106,8 @@ static inline int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *par #define MAC_ARG(x) (x) #endif - -#ifdef CONFIG_AP_WOWLAN -extern void rtw_softap_lock_suspend(void); -extern void rtw_softap_unlock_suspend(void); -#endif - extern void rtw_free_netdev(struct net_device * netdev); - /* Macros for handling unaligned memory accesses */ void rtw_buf_free(u8 **buf, u32 *buf_len); diff --git a/drivers/staging/rtl8723bs/include/osdep_service_linux.h b/drivers/staging/rtl8723bs/include/osdep_service_linux.h index 9194dea217fb670548c7959b9fbdd579f2a36d53..3492ec1efd1e05af2a1ec919941700615a3035fc 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service_linux.h +++ b/drivers/staging/rtl8723bs/include/osdep_service_linux.h @@ -40,30 +40,13 @@ #include <net/ieee80211_radiotap.h> #include <net/cfg80211.h> - typedef spinlock_t _lock; - typedef struct mutex _mutex; - typedef struct timer_list _timer; - struct __queue { struct list_head queue; - _lock lock; + spinlock_t lock; }; - typedef struct sk_buff _pkt; - typedef unsigned char _buffer; - - typedef int _OS_STATUS; - /* typedef u32 _irqL; */ - typedef unsigned long _irqL; - typedef struct net_device * _nic_hdl; - #define thread_exit() complete_and_exit(NULL, 0) - typedef void timer_hdl_return; - typedef void* timer_hdl_context; - - typedef struct work_struct _workitem; - static inline struct list_head *get_next(struct list_head *list) { return list->next; @@ -74,22 +57,22 @@ static inline struct list_head *get_list_head(struct __queue *queue) return (&(queue->queue)); } -static inline void _set_timer(_timer *ptimer, u32 delay_time) +static inline void _set_timer(struct timer_list *ptimer, u32 delay_time) { mod_timer(ptimer, (jiffies + (delay_time * HZ / 1000))); } -static inline void _init_workitem(_workitem *pwork, void *pfunc, void *cntx) +static inline void _init_workitem(struct work_struct *pwork, void *pfunc, void *cntx) { INIT_WORK(pwork, pfunc); } -static inline void _set_workitem(_workitem *pwork) +static inline void _set_workitem(struct work_struct *pwork) { schedule_work(pwork); } -static inline void _cancel_workitem_sync(_workitem *pwork) +static inline void _cancel_workitem_sync(struct work_struct *pwork) { cancel_work_sync(pwork); } @@ -137,6 +120,6 @@ static inline struct adapter *rtw_netdev_priv(struct net_device *netdev) } struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv); -extern struct net_device * rtw_alloc_etherdev(int sizeof_priv); +extern struct net_device *rtw_alloc_etherdev(int sizeof_priv); #endif diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index e85aafc93f6d89837d8d728e4a6cd4f4e65edc0b..83330ea98fbf7381b28ec82d85dc72c452be6f7a 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -8,13 +8,13 @@ #define __RECV_OSDEP_H_ -extern sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); +extern signed int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); extern void _rtw_free_recv_priv(struct recv_priv *precvpriv); extern s32 rtw_recv_entry(union recv_frame *precv_frame); extern int rtw_recv_indicatepkt(struct adapter *adapter, union recv_frame *precv_frame); -extern void rtw_recv_returnpacket(_nic_hdl cnxt, _pkt *preturnedpkt); +extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt); extern void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); @@ -31,8 +31,8 @@ void rtw_os_free_recvframe(union recv_frame *precvframe); void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf); -_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); -void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib); +struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); +void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib); void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h b/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h index 3bfb0e9be58214ac184eba2ff33027c94df96bed..dbcf01bbf05107479e445a95fb79a4a2350125b1 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h @@ -11,7 +11,7 @@ /* H2C CMD DEFINITION ------------------------------------------------ */ /* */ -enum h2c_cmd_8723B { +enum { /* Common Class: 000 */ H2C_8723B_RSVD_PAGE = 0x00, H2C_8723B_MEDIA_STATUS_RPT = 0x01, @@ -177,12 +177,6 @@ void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter); void CheckFwRsvdPageContent(struct adapter *padapter); -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -void rtl8723b_set_wowlan_cmd(struct adapter *padapter, u8 enable); -void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable); -void SetFwRelatedForWoWLAN8723b(struct adapter *padapter, u8 bHostIsGoingtoSleep); -#endif/* CONFIG_WOWLAN */ - void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param); s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h index 8e6e972dd8436175c81fc1a526a480f7641378a6..c1d7249e3e9def8887e44c2f58ffe01facfb7324 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h @@ -92,29 +92,11 @@ struct rt_firmware_hdr { #define BCNQ_PAGE_NUM_8723B 0x08 #define BCNQ1_PAGE_NUM_8723B 0x00 -#ifdef CONFIG_PNO_SUPPORT -#undef BCNQ1_PAGE_NUM_8723B -#define BCNQ1_PAGE_NUM_8723B 0x00 /* 0x04 */ -#endif - #define MAX_RX_DMA_BUFFER_SIZE_8723B 0x2800 /* RX 10K */ /* For WoWLan, more reserved page */ /* ARP Rsp:1, RWC:1, GTK Info:1, GTK RSP:2, GTK EXT MEM:2, PNO: 6 */ -#ifdef CONFIG_WOWLAN -#define WOWLAN_PAGE_NUM_8723B 0x07 -#else #define WOWLAN_PAGE_NUM_8723B 0x00 -#endif - -#ifdef CONFIG_PNO_SUPPORT -#undef WOWLAN_PAGE_NUM_8723B -#define WOWLAN_PAGE_NUM_8723B 0x0d -#endif - -#ifdef CONFIG_AP_WOWLAN -#define AP_WOWLAN_PAGE_NUM_8723B 0x02 -#endif #define TX_TOTAL_PAGE_NUMBER_8723B \ (0xFF - BCNQ_PAGE_NUM_8723B - \ @@ -170,7 +152,7 @@ struct rt_firmware_hdr { /* Description: Determine the types of C2H events that are the same in driver * and FW; First constructed by tynli. 2009.10.09. */ -typedef enum _C2H_EVT { +enum { C2H_DBG = 0, C2H_TSF = 1, C2H_AP_RPT_RSP = 2, @@ -184,21 +166,21 @@ typedef enum _C2H_EVT { C2H_HW_INFO_EXCH = 10, C2H_8723B_BT_MP_INFO = 11, MAX_C2HEVENT -} C2H_EVT; +}; -typedef struct _C2H_EVT_HDR { +struct c2h_evt_hdr_t { u8 CmdID; u8 CmdLen; u8 CmdSeq; -} __attribute__((__packed__)) C2H_EVT_HDR, *PC2H_EVT_HDR; +} __attribute__((__packed__)); -typedef enum tag_Package_Definition { +enum { /* tag_Package_Definition */ PACKAGE_DEFAULT, PACKAGE_QFN68, PACKAGE_TFBGA90, PACKAGE_TFBGA80, PACKAGE_TFBGA79 -} PACKAGE_TYPE_E; +}; #define INCLUDE_MULTI_FUNC_BT(_Adapter) \ (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) @@ -245,33 +227,19 @@ void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length); void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc); void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val); void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val); -u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, +u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval); -u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, +u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval); /* register */ void rtl8723b_InitBeaconParameters(struct adapter *padapter); void _InitBurstPktLen_8723BS(struct adapter *adapter); void _8051Reset8723(struct adapter *padapter); -#ifdef CONFIG_WOWLAN -void Hal_DetectWoWMode(struct adapter *padapter); -#endif /* CONFIG_WOWLAN */ void rtl8723b_start_thread(struct adapter *padapter); void rtl8723b_stop_thread(struct adapter *padapter); -#if defined(CONFIG_CHECK_BT_HANG) -void rtl8723bs_init_checkbthang_workqueue(struct adapter *adapter); -void rtl8723bs_free_checkbthang_workqueue(struct adapter *adapter); -void rtl8723bs_cancle_checkbthang_workqueue(struct adapter *adapter); -void rtl8723bs_hal_check_bt_hang(struct adapter *adapter); -#endif - -#ifdef CONFIG_GPIO_WAKEUP -void HalSetOutPutGPIO(struct adapter *padapter, u8 index, u8 OutPutValue); -#endif - int FirmwareDownloadBT(struct adapter *adapter, struct rt_firmware *firmware); void CCX_FwC2HTxRpt_8723b(struct adapter *padapter, u8 *pdata, u8 len); diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_recv.h b/drivers/staging/rtl8723bs/include/rtl8723b_recv.h index 60a1df703c8e48b2326e5b592153794c3d06d14c..a108ce89bce43298d6a154c403737f6b714c457c 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_recv.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_recv.h @@ -81,50 +81,6 @@ struct rxreport_8723b { u32 tsfl; }; -struct phystatus_8723b { - u32 rxgain_a:7; - u32 trsw_a:1; - u32 rxgain_b:7; - u32 trsw_b:1; - u32 chcorr_l:16; - - u32 sigqualcck:8; - u32 cfo_a:8; - u32 cfo_b:8; - u32 chcorr_h:8; - - u32 noisepwrdb_h:8; - u32 cfo_tail_a:8; - u32 cfo_tail_b:8; - u32 rsvd0824:8; - - u32 rsvd1200:8; - u32 rxevm_a:8; - u32 rxevm_b:8; - u32 rxsnr_a:8; - - u32 rxsnr_b:8; - u32 noisepwrdb_l:8; - u32 rsvd1616:8; - u32 postsnr_a:8; - - u32 postsnr_b:8; - u32 csi_a:8; - u32 csi_b:8; - u32 targetcsi_a:8; - - u32 targetcsi_b:8; - u32 sigevm:8; - u32 maxexpwr:8; - u32 exintflag:1; - u32 sgien:1; - u32 rxsc:2; - u32 idlelong:1; - u32 anttrainen:1; - u32 antselb:1; - u32 antsel:1; -}; - s32 rtl8723bs_init_recv_priv(struct adapter *padapter); void rtl8723bs_free_recv_priv(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_rf.h b/drivers/staging/rtl8723bs/include/rtl8723b_rf.h index d712c6d36a0849e25165980d8032219e47b491cc..525eb2facca068d7b2ed765de36ff57e867f75dd 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_rf.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_rf.h @@ -12,6 +12,6 @@ int PHY_RF6052_Config8723B(struct adapter *Adapter); void PHY_RF6052SetBandwidth8723B(struct adapter *Adapter, - enum CHANNEL_WIDTH Bandwidth); + enum channel_width Bandwidth); #endif diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_spec.h b/drivers/staging/rtl8723bs/include/rtl8723b_spec.h index 9149fe5985456f143b14e6844c0b8d15ed89e915..999555476ebcc291cb1b9b4300747e65c9696333 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_spec.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_spec.h @@ -96,10 +96,6 @@ #define REG_TXPKTBUF_BCNQ_BDNY_8723B 0x0424 #define REG_TXPKTBUF_MGQ_BDNY_8723B 0x0425 #define REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B 0x045D -#ifdef CONFIG_WOWLAN -#define REG_TXPKTBUF_IV_LOW 0x0484 -#define REG_TXPKTBUF_IV_HIGH 0x0488 -#endif #define REG_AMPDU_BURST_MODE_8723B 0x04BC /* */ @@ -164,12 +160,6 @@ #define BIT_USB_RXDMA_AGG_EN BIT(31) #define RXDMA_AGG_MODE_EN BIT(1) -#ifdef CONFIG_WOWLAN -#define RXPKT_RELEASE_POLL BIT(16) -#define RXDMA_IDLE BIT(17) -#define RW_RELEASE_EN BIT(18) -#endif - /* */ /* */ /* 0x0400h ~ 0x047Fh Protocol Configuration */ diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h index 243d36d9bc7bd88249f0185710c8f90b15b64622..56bdc14af47d19002b06205eb8be988eeedffd52 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h @@ -59,7 +59,7 @@ /* */ /* defined for TX DESC Operation */ /* */ -typedef struct txdesc_8723b { +struct txdesc_8723b { /* Offset 0 */ u32 pktlen:16; u32 offset:8; @@ -175,7 +175,7 @@ typedef struct txdesc_8723b { u32 txbf_path:1; u32 seq:12; u32 final_data_rate:8; -} TXDESC_8723B, *PTXDESC_8723B; +}; #ifndef __INC_HAL8723BDESC_H #define __INC_HAL8723BDESC_H @@ -443,7 +443,7 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter); int rtl8723bs_xmit_thread(void *context); #define hal_xmit_handler rtl8723bs_xmit_buf_handler -u8 BWMapping_8723B(struct adapter * Adapter, struct pkt_attrib *pattrib); -u8 SCMapping_8723B(struct adapter * Adapter, struct pkt_attrib *pattrib); +u8 BWMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib); +u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib); #endif diff --git a/drivers/staging/rtl8723bs/include/rtw_cmd.h b/drivers/staging/rtl8723bs/include/rtw_cmd.h index 56c77bc7ca815cdfd0b64e6e8506a709ae60c2e0..28d2d27323746dd5868988a61d106aa468eea495 100644 --- a/drivers/staging/rtl8723bs/include/rtw_cmd.h +++ b/drivers/staging/rtl8723bs/include/rtw_cmd.h @@ -53,11 +53,11 @@ /* u8 cmdthd_running; */ u8 stop_req; struct adapter *padapter; - _mutex sctx_mutex; + struct mutex sctx_mutex; }; struct evt_priv { - _workitem c2h_wk; + struct work_struct c2h_wk; bool c2h_wk_alive; struct rtw_cbuf *c2h_queue; #define C2H_QUEUE_MAX_LEN 10 @@ -107,21 +107,6 @@ struct c2h_evt_hdr_88xx { #define c2h_evt_valid(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen) -struct P2P_PS_Offload_t { - u8 Offload_En:1; - u8 role:1; /* 1: Owner, 0: Client */ - u8 CTWindow_En:1; - u8 NoA0_En:1; - u8 NoA1_En:1; - u8 AllStaSleep:1; /* Only valid in Owner */ - u8 discovery:1; - u8 rsvd:1; -}; - -struct P2P_PS_CTWPeriod_t { - u8 CTWPeriod; /* TU */ -}; - int rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); extern struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv); extern void rtw_free_cmd_obj(struct cmd_obj *pcmd); @@ -134,7 +119,7 @@ extern void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv); extern void rtw_free_evt_priv(struct evt_priv *pevtpriv); extern void rtw_evt_notify_isr(struct evt_priv *pevtpriv); -enum rtw_drvextra_cmd_id { +enum { NONE_WK_CID, DYNAMIC_CHK_WK_CID, DM_CTRL_WK_CID, @@ -151,14 +136,14 @@ enum rtw_drvextra_cmd_id { RESET_SECURITYPRIV, /* add for CONFIG_IEEE80211W, none 11w also can use */ FREE_ASSOC_RESOURCES, /* add for CONFIG_IEEE80211W, none 11w also can use */ DM_IN_LPS_WK_CID, - DM_RA_MSK_WK_CID, /* add for STA update RAMask when bandwith change. */ + DM_RA_MSK_WK_CID, /* add for STA update RAMask when bandwidth change. */ BEAMFORMING_WK_CID, LPS_CHANGE_DTIM_CID, BTINFO_WK_CID, MAX_WK_CID }; -enum LPS_CTRL_TYPE { +enum { LPS_CTRL_SCAN = 0, LPS_CTRL_JOINBSS = 1, LPS_CTRL_CONNECT = 2, @@ -168,24 +153,12 @@ enum LPS_CTRL_TYPE { LPS_CTRL_TRAFFIC_BUSY = 6, }; -enum RFINTFS { +enum { 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 @@ -265,7 +238,7 @@ Command-Event Mode #define RTW_SSID_SCAN_AMOUNT 9 /* for WEXT_CSCAN_AMOUNT 9 */ #define RTW_CHANNEL_SCAN_AMOUNT (14+37) struct sitesurvey_parm { - sint scan_mode; /* active: 1, passive: 0 */ + signed int scan_mode; /* active: 1, passive: 0 */ u8 ssid_num; u8 ch_num; struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; @@ -399,10 +372,6 @@ struct getbasicrate_parm { u32 rsvd; }; -struct getbasicrate_rsp { - u8 basicrates[NumRates]; -}; - /* Caller Mode: Any @@ -428,10 +397,6 @@ struct getdatarate_parm { u32 rsvd; }; -struct getdatarate_rsp { - u8 datarates[NumRates]; -}; - /* Caller Mode: Any @@ -456,11 +421,6 @@ struct getphyinfo_parm { u32 rsvd; }; -struct getphyinfo_rsp { - struct regulatory_class class_sets[NUM_REGULATORYS]; - u8 status; -}; - /* Caller Mode: Any @@ -487,46 +447,6 @@ struct getphy_parm { u32 rsvd; }; -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 readRF_parm { - u8 offset; -}; -struct readRF_rsp { - u32 value; -}; - -struct writeRF_parm { - u32 offset; - u32 value; -}; - -struct getrfintfs_parm { - u8 rfintfs; -}; - struct Tx_Beacon_param { struct wlan_bssid_ex network; @@ -594,163 +514,12 @@ struct drvextra_cmd_parm { unsigned char *pbuf; }; -/*------------------- Below are used for RF/BB tunning ---------------------*/ - -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]; -}; +/*------------------- Below are used for RF/BB tuning ---------------------*/ -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 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; -}; - -struct setprobereqextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[0]; -}; - -struct setassocreqextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[0]; -}; - -struct setproberspextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[0]; -}; - -struct setassocrspextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[0]; -}; - - struct addBaReq_parm { unsigned int tid; u8 addr[ETH_ALEN]; @@ -768,11 +537,6 @@ struct SetChannelPlan_param { u8 channel_plan; }; -/*H2C Handler index: 60 */ -struct LedBlink_param { - void *pLed; -}; - /*H2C Handler index: 61 */ struct SetChannelSwitch_param { u8 new_ch_no; @@ -786,7 +550,7 @@ struct TDLSoption_param { /*H2C Handler index: 64 */ struct RunInThread_param { - void (*func)(void*); + void (*func)(void *); void *context; }; @@ -798,7 +562,7 @@ struct RunInThread_param { Result: 0x00: success -0x01: sucess, and check Response. +0x01: success, and check Response. 0x02: cmd ignored due to duplicated sequcne number 0x03: cmd dropped due to invalid cmd code 0x04: reserved. @@ -824,9 +588,9 @@ struct sta_info; extern u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_key, bool enqueue); extern u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueue); -extern u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network* pnetwork); +extern u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork); u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue); -extern u8 rtw_setopmode_cmd(struct adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue); +extern u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infrastructure networktype, bool enqueue); extern u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset); extern u8 rtw_setrfintfs_cmd(struct adapter *padapter, u8 mode); @@ -872,7 +636,7 @@ struct _cmd_callback { void (*callback)(struct adapter *padapter, struct cmd_obj *cmd); }; -enum rtw_h2c_cmd { +enum { GEN_CMD_CODE(_Read_MACREG), /*0*/ GEN_CMD_CODE(_Write_MACREG), GEN_CMD_CODE(_Read_BBREG), @@ -940,13 +704,12 @@ enum rtw_h2c_cmd { GEN_CMD_CODE(_Set_H2C_MSG), /*58*/ GEN_CMD_CODE(_SetChannelPlan), /*59*/ - GEN_CMD_CODE(_LedBlink), /*60*/ - GEN_CMD_CODE(_SetChannelSwitch), /*61*/ - GEN_CMD_CODE(_TDLS), /*62*/ - GEN_CMD_CODE(_ChkBMCSleepq), /*63*/ + GEN_CMD_CODE(_SetChannelSwitch), /*60*/ + GEN_CMD_CODE(_TDLS), /*61*/ + GEN_CMD_CODE(_ChkBMCSleepq), /*62*/ - GEN_CMD_CODE(_RunInThreadCMD), /*64*/ + GEN_CMD_CODE(_RunInThreadCMD), /*63*/ MAX_H2CCMD }; diff --git a/drivers/staging/rtl8723bs/include/rtw_debug.h b/drivers/staging/rtl8723bs/include/rtw_debug.h index c90adfb8726111e7e1cb1bff414f904f2058254f..23f4cb4711d4dac2b2d7a0aa0b40332292d82aa1 100644 --- a/drivers/staging/rtl8723bs/include/rtw_debug.h +++ b/drivers/staging/rtl8723bs/include/rtw_debug.h @@ -131,14 +131,6 @@ #define _MODULE_DEFINE_ _module_efuse_ #endif -#define RT_TRACE(_Comp, _Level, Fmt) do {} while (0) -#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) do {} while (0) - -#define DBG_871X(x, ...) do {} while (0) -#define MSG_8192C(x, ...) do {} while (0) -#define DBG_8192C(x, ...) do {} while (0) -#define DBG_871X_LEVEL(x, ...) do {} while (0) - #undef _dbgdump #ifndef _RTL871X_DEBUG_C_ @@ -152,18 +144,6 @@ #if defined(_dbgdump) -/* with driver-defined prefix */ -#undef DBG_871X_LEVEL -#define DBG_871X_LEVEL(level, fmt, arg...) \ - do {\ - if (level <= GlobalDebugLevel) {\ - if (level <= _drv_err_ && level > _drv_always_) \ - _dbgdump(DRIVER_PREFIX"ERROR " fmt, ##arg);\ - else \ - _dbgdump(DRIVER_PREFIX fmt, ##arg);\ - } \ - } while (0) - /* without driver-defined prefix */ #undef _DBG_871X_LEVEL #define _DBG_871X_LEVEL(level, fmt, arg...) \ @@ -187,80 +167,8 @@ seq_printf(sel, fmt, ##arg); \ } while (0) -/* dump message to selected 'stream' with driver-defined prefix */ -#define DBG_871X_SEL_NL(sel, fmt, arg...) \ - do { \ - if (sel == RTW_DBGDUMP) \ - DBG_871X_LEVEL(_drv_always_, fmt, ##arg); \ - else \ - seq_printf(sel, fmt, ##arg); \ - } while (0) - #endif /* defined(_dbgdump) */ -#ifdef DEBUG -#if defined(_dbgdump) - #undef DBG_871X - #define DBG_871X(...) do {\ - _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ - } while (0) - - #undef MSG_8192C - #define MSG_8192C(...) do {\ - _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ - } while (0) - - #undef DBG_8192C - #define DBG_8192C(...) do {\ - _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ - } while (0) -#endif /* defined(_dbgdump) */ -#endif /* DEBUG */ - -#ifdef DEBUG_RTL871X - -#if defined(_dbgdump) && defined(_MODULE_DEFINE_) - - #undef RT_TRACE - #define RT_TRACE(_Comp, _Level, Fmt)\ - do {\ - if ((_Comp & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) {\ - _dbgdump("%s [0x%08x,%d]", DRIVER_PREFIX, (unsigned int)_Comp, _Level);\ - _dbgdump Fmt;\ - } \ - } while (0) - -#endif /* defined(_dbgdump) && defined(_MODULE_DEFINE_) */ - - -#if defined(_dbgdump) - #undef RT_PRINT_DATA - #define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) \ - if (((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ - { \ - int __i; \ - u8 *ptr = (u8 *)_HexData; \ - _dbgdump("%s", DRIVER_PREFIX); \ - _dbgdump(_TitleString); \ - for (__i = 0; __i < (int)_HexDataLen; __i++) \ - { \ - _dbgdump("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" "); \ - if (((__i + 1) % 16) == 0) _dbgdump("\n"); \ - } \ - _dbgdump("\n"); \ - } -#endif /* defined(_dbgdump) */ -#endif /* DEBUG_RTL871X */ - -#ifdef CONFIG_DBG_COUNTER -#define DBG_COUNTER(counter) counter++ -#else -#define DBG_COUNTER(counter) do {} while (0) -#endif - -void dump_drv_version(void *sel); -void dump_log_level(void *sel); - void sd_f0_reg_dump(void *sel, struct adapter *adapter); void mac_reg_dump(void *sel, struct adapter *adapter); diff --git a/drivers/staging/rtl8723bs/include/rtw_eeprom.h b/drivers/staging/rtl8723bs/include/rtw_eeprom.h index 78f34f6cebb4b8d7ae68e32bea34bf96968db96c..9b84105af816bbec1913088b4db913dba77e5d27 100644 --- a/drivers/staging/rtl8723bs/include/rtw_eeprom.h +++ b/drivers/staging/rtl8723bs/include/rtw_eeprom.h @@ -42,7 +42,7 @@ /* Besides, CustomerID of registry has precedence of that of EEPROM. */ /* defined below. 060703, by rcnjko. */ /* */ -typedef enum _RT_CUSTOMER_ID { +enum { RT_CID_DEFAULT = 0, RT_CID_8187_ALPHA0 = 1, RT_CID_8187_SERCOMM_PS = 2, @@ -90,7 +90,7 @@ typedef enum _RT_CUSTOMER_ID { RT_CID_819x_ALPHA_Dlink = 44,/* add by ylb 20121012 for customer led for alpha */ RT_CID_WNC_NEC = 45,/* add by page for NEC */ RT_CID_DNI_BUFFALO = 46,/* add by page for NEC */ -} RT_CUSTOMER_ID, *PRT_CUSTOMER_ID; +}; struct eeprom_priv { u8 bautoload_fail_flag; diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 4abcbbc8f513b8501ea2612cfa3ff8266afc184b..5938a6bfb573b4f81d6319a16d10bcb688b11532 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -25,7 +25,7 @@ #define EFUSE_WIFI 0 #define EFUSE_BT 1 -enum _EFUSE_DEF_TYPE { +enum { TYPE_EFUSE_MAX_SECTION = 0, TYPE_EFUSE_REAL_CONTENT_LEN = 1, TYPE_AVAILABLE_EFUSE_BYTES_BANK = 2, @@ -57,15 +57,15 @@ enum _EFUSE_DEF_TYPE { #define EFUSE_MAX_WORD_UNIT 4 /*------------------------------Define structure----------------------------*/ -typedef struct PG_PKT_STRUCT_A { +struct pgpkt_struct { u8 offset; u8 word_en; u8 data[8]; u8 word_cnts; -} PGPKT_STRUCT, *PPGPKT_STRUCT; +}; /*------------------------------Define structure----------------------------*/ -typedef struct _EFUSE_HAL { +struct efuse_hal { u8 fakeEfuseBank; u32 fakeEfuseUsedBytes; u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]; @@ -82,7 +82,7 @@ typedef struct _EFUSE_HAL { u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; -} EFUSE_HAL, *PEFUSE_HAL; +}; /*------------------------Export global variable----------------------------*/ diff --git a/drivers/staging/rtl8723bs/include/rtw_event.h b/drivers/staging/rtl8723bs/include/rtw_event.h index 560521c80ace919809edbad35b859c00ef771fd2..d48bae5416fe62dfb943da113c0f2f49600a755c 100644 --- a/drivers/staging/rtl8723bs/include/rtw_event.h +++ b/drivers/staging/rtl8723bs/include/rtw_event.h @@ -60,10 +60,6 @@ struct stadel_event { int mac_id; }; -struct addba_event { - unsigned int tid; -}; - struct wmm_event { unsigned char wmm; }; @@ -88,13 +84,6 @@ struct event_node { 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 { diff --git a/drivers/staging/rtl8723bs/include/rtw_ht.h b/drivers/staging/rtl8723bs/include/rtw_ht.h index a72f51031f89ee2a83fdc1672ca1c57eed0e4faf..e3f353fe1e473bdbe48f7317383ff25b99c4f734 100644 --- a/drivers/staging/rtl8723bs/include/rtw_ht.h +++ b/drivers/staging/rtl8723bs/include/rtw_ht.h @@ -37,7 +37,7 @@ struct ht_priv { }; -typedef enum AGGRE_SIZE { +enum { HT_AGG_SIZE_8K = 0, HT_AGG_SIZE_16K = 1, HT_AGG_SIZE_32K = 2, @@ -46,9 +46,9 @@ typedef enum AGGRE_SIZE { VHT_AGG_SIZE_256K = 5, VHT_AGG_SIZE_512K = 6, VHT_AGG_SIZE_1024K = 7, -} AGGRE_SIZE_E, *PAGGRE_SIZE_E; +}; -typedef enum _RT_HT_INF0_CAP { +enum { RT_HT_CAP_USE_TURBO_AGGR = 0x01, RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, RT_HT_CAP_USE_AMPDU = 0x04, @@ -57,13 +57,13 @@ typedef enum _RT_HT_INF0_CAP { RT_HT_CAP_USE_92SE = 0x20, RT_HT_CAP_USE_88C_92C = 0x40, RT_HT_CAP_USE_AP_CLIENT_MODE = 0x80, /* AP team request to reserve this bit, by Emily */ -} RT_HT_INF0_CAPBILITY, *PRT_HT_INF0_CAPBILITY; +}; -typedef enum _RT_HT_INF1_CAP { +enum { RT_HT_CAP_USE_VIDEO_CLIENT = 0x01, RT_HT_CAP_USE_JAGUAR_BCUT = 0x02, RT_HT_CAP_USE_JAGUAR_CCUT = 0x04, -} RT_HT_INF1_CAPBILITY, *PRT_HT_INF1_CAPBILITY; +}; #define LDPC_HT_ENABLE_RX BIT0 #define LDPC_HT_ENABLE_TX BIT1 diff --git a/drivers/staging/rtl8723bs/include/rtw_io.h b/drivers/staging/rtl8723bs/include/rtw_io.h index b7076b590d84a3bdc9abc061380bcf876ac9f8e5..fbb73e698e09d3a7223a6aa08a8c10c1d0fed4c8 100644 --- a/drivers/staging/rtl8723bs/include/rtw_io.h +++ b/drivers/staging/rtl8723bs/include/rtw_io.h @@ -127,117 +127,6 @@ struct intf_hdl { 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 */ - /* 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 - -}; - - -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 - -}; #define SD_IO_TRY_CNT (8) #define MAX_CONTINUAL_IO_ERR SD_IO_TRY_CNT @@ -250,7 +139,7 @@ Below is the data structure used by _io_handler */ struct io_queue { - _lock lock; + spinlock_t lock; struct list_head free_ioreqs; struct list_head pending; /* The io_req list that will be served in the single protocol read/write. */ struct list_head processing; diff --git a/drivers/staging/rtl8723bs/include/rtw_ioctl_set.h b/drivers/staging/rtl8723bs/include/rtw_ioctl_set.h index f0457e91d00f3f01fe810590afddee095725b4ea..31424bf2d9261da9a5d49d9236274006438bd9cb 100644 --- a/drivers/staging/rtl8723bs/include/rtw_ioctl_set.h +++ b/drivers/staging/rtl8723bs/include/rtw_ioctl_set.h @@ -10,24 +10,20 @@ typedef u8 NDIS_802_11_PMKID_VALUE[16]; -typedef struct _BSSIDInfo { - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_PMKID_VALUE PMKID; -} BSSIDInfo, *PBSSIDInfo; - - -u8 rtw_set_802_11_authentication_mode(struct adapter *pdapter, enum NDIS_802_11_AUTHENTICATION_MODE authmode); +u8 rtw_set_802_11_authentication_mode(struct adapter *pdapter, enum ndis_802_11_authentication_mode authmode); u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid); -u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep * wep); +u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep); u8 rtw_set_802_11_disassociate(struct adapter *padapter); u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num); -u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); -u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid * ssid); +u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, enum ndis_802_11_network_infrastructure networktype); +u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid); u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_11_ssid *ssid); u8 rtw_validate_bssid(u8 *bssid); u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid); +u8 rtw_do_join(struct adapter *padapter); + u16 rtw_get_cur_max_rate(struct adapter *adapter); #endif diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h index d8655cb619a19f9c0f53dfdda1cbe92872fc5dcc..5deb73fe3885eba8d570f60ccb3da85f6c50783f 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h @@ -57,11 +57,11 @@ /* ifdef UNDER_MPTEST */ #define WIFI_MP_STATE 0x00010000 -#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continous tx background */ -#define WIFI_MP_CTX_ST 0x00040000 /* in continous tx with single-tone */ -#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continous tx background due to out of skb */ -#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continous tx */ -#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continous tx with carrier suppression */ +#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continuous tx background */ +#define WIFI_MP_CTX_ST 0x00040000 /* in continuous tx with single-tone */ +#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continuous 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 continuous tx with carrier suppression */ #define WIFI_MP_LPBK_STATE 0x00400000 /* endif */ @@ -71,7 +71,7 @@ #define _FW_UNDER_SURVEY WIFI_SITE_MONITOR -enum dot11AuthAlgrthmNum { +enum { dot11AuthAlgrthm_Open = 0, dot11AuthAlgrthm_Shared, dot11AuthAlgrthm_8021X, @@ -81,13 +81,13 @@ enum dot11AuthAlgrthmNum { }; /* Scan type including active and passive scan. */ -typedef enum _RT_SCAN_TYPE { +enum rt_scan_type { SCAN_PASSIVE, SCAN_ACTIVE, SCAN_MIX, -} RT_SCAN_TYPE, *PRT_SCAN_TYPE; +}; -enum _BAND { +enum { GHZ24_50 = 0, GHZ_50, GHZ_24, @@ -96,18 +96,6 @@ enum _BAND { #define rtw_band_valid(band) ((band) >= GHZ24_50 && (band) < GHZ_MAX) -enum DriverInterface { - DRIVER_WEXT = 1, - DRIVER_CFG80211 = 2 -}; - -enum SCAN_RESULT_TYPE { - SCAN_RESULT_P2P_ONLY = 0, /* Will return all the P2P devices. */ - SCAN_RESULT_ALL = 1, /* Will return all the scanned device, include AP. */ - SCAN_RESULT_WFD_TYPE = 2 /* Will just return the correct WFD device. */ - /* If this device is Miracast sink device, it will just return all the Miracast source devices. */ -}; - /* there are several "locks" in mlme_priv, @@ -130,11 +118,11 @@ SHALL not lock up more than one locks at a time! struct sitesurvey_ctrl { u64 last_tx_pkts; uint last_rx_pkts; - sint traffic_busy; - _timer sitesurvey_ctrl_timer; + signed int traffic_busy; + struct timer_list sitesurvey_ctrl_timer; }; -typedef struct _RT_LINK_DETECT_T { +struct rt_link_detect_t { u32 NumTxOkInPeriod; u32 NumRxOkInPeriod; u32 NumRxUnicastOkInPeriod; @@ -147,7 +135,7 @@ typedef struct _RT_LINK_DETECT_T { /* u8 TrafficBusyState; */ u8 TrafficTransitionCount; u32 LowPowerTransitionCount; -} RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; +}; struct profile_info { u8 ssidlen; @@ -180,7 +168,7 @@ struct tx_provdisc_req_info { u8 benable; /* This provision discovery request frame is trigger to send or not */ }; -struct rx_provdisc_req_info { /* When peer device issue prov_disc_req first, we should store the following informations */ +struct rx_provdisc_req_info { /* When peer device issue prov_disc_req first, we should store the following information */ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ u8 strconfig_method_desc_of_prov_disc_req[4]; /* description for the config method located in the provisioning discovery request frame. */ /* The UI must know this information to know which config method the remote p2p device is requiring. */ @@ -189,7 +177,7 @@ struct rx_provdisc_req_info { /* When peer device issue prov_disc_req first, we struct tx_nego_req_info { u16 peer_channel_num[2]; /* The channel number which the receiver stands. */ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ - u8 benable; /* This negoitation request frame is trigger to send or not */ + u8 benable; /* This negotiation request frame is trigger to send or not */ }; struct group_id_info { @@ -202,25 +190,15 @@ struct scan_limit_info { u8 operation_ch[2]; /* Store the operation channel of invitation request frame */ }; -struct cfg80211_wifidirect_info { - _timer remain_on_ch_timer; - u8 restore_channel; - struct ieee80211_channel remain_on_ch_channel; - enum nl80211_channel_type remain_on_ch_type; - u64 remain_on_ch_cookie; - bool is_ro_ch; - unsigned long last_ro_ch_time; /* this will be updated at the beginning and end of ro_ch */ -}; - struct wifidirect_info { struct adapter *padapter; - _timer find_phase_timer; - _timer restore_p2p_state_timer; + struct timer_list find_phase_timer; + struct timer_list restore_p2p_state_timer; /* Used to do the scanning. After confirming the peer is availalble, the driver transmits the P2P frame to peer. */ - _timer pre_tx_scan_timer; - _timer reset_ch_sitesurvey; - _timer reset_ch_sitesurvey2; /* Just for resetting the scan limit function by using p2p nego */ + struct timer_list pre_tx_scan_timer; + struct timer_list reset_ch_sitesurvey; + struct timer_list reset_ch_sitesurvey2; /* Just for resetting the scan limit function by using p2p nego */ struct tx_provdisc_req_info tx_prov_disc_info; struct rx_provdisc_req_info rx_prov_disc_info; struct tx_invite_req_info invitereq_info; @@ -230,9 +208,9 @@ struct wifidirect_info { struct group_id_info groupid_info; /* Store the group id information when doing the group negotiation handshake. */ struct scan_limit_info rx_invitereq_info; /* Used for get the limit scan channel from the Invitation procedure */ struct scan_limit_info p2p_info; /* Used for get the limit scan channel from the P2P negotiation handshake */ - enum P2P_ROLE role; - enum P2P_STATE pre_p2p_state; - enum P2P_STATE p2p_state; + enum p2p_role role; + enum p2p_state pre_p2p_state; + enum p2p_state p2p_state; u8 device_addr[ETH_ALEN]; /* The device address should be the mac address of this device. */ u8 interface_addr[ETH_ALEN]; u8 social_chan[4]; @@ -250,9 +228,9 @@ struct wifidirect_info { u8 profileindex; /* Used to point to the index of profileinfo array */ u8 peer_operating_ch; u8 find_phase_state_exchange_cnt; - u16 device_password_id_for_nego; /* The device password ID for group negotation */ + u16 device_password_id_for_nego; /* The device password ID for group negotiation */ u8 negotiation_dialog_token; - u8 nego_ssid[WLAN_SSID_MAXLEN]; /* SSID information for group negotitation */ + u8 nego_ssid[WLAN_SSID_MAXLEN]; /* SSID information for group negotiation */ u8 nego_ssidlen; u8 p2p_group_ssid[WLAN_SSID_MAXLEN]; u8 p2p_group_ssid_len; @@ -275,7 +253,7 @@ struct wifidirect_info { /* In this case, the driver can issue the tdls setup request frame */ /* even the current security is weak security. */ - enum P2P_WPSINFO ui_got_wps_info; /* This field will store the WPS value (PIN value or PBC) that UI had got from the user. */ + enum p2p_wpsinfo ui_got_wps_info; /* This field will store the WPS value (PIN value or PBC) that UI had got from the user. */ u16 supported_wps_cm; /* This field describes the WPS config method which this driver supported. */ /* The value should be the combination of config method defined in page104 of WPS v2.0 spec. */ u8 external_uuid; /* UUID flag */ @@ -292,34 +270,6 @@ struct tdls_ss_record { /* signal strength record */ u8 is_tdls_sta; /* true: direct link sta, false: else */ }; -struct tdls_info { - u8 ap_prohibited; - u8 link_established; - u8 sta_cnt; - u8 sta_maximum; /* 1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; */ - struct tdls_ss_record ss_record; - u8 ch_sensing; - u8 cur_channel; - u8 candidate_ch; - u8 collect_pkt_num[MAX_CHANNEL_NUM]; - _lock cmd_lock; - _lock hdl_lock; - u8 watchdog_count; - u8 dev_discovered; /* WFD_TDLS: for sigma test */ - u8 tdls_enable; - u8 external_setup; /* true: setup is handled by wpa_supplicant */ -}; - -struct tdls_txmgmt { - u8 peer[ETH_ALEN]; - u8 action_code; - u8 dialog_token; - u16 status_code; - u8 *buf; - size_t len; - u8 external_support; -}; - /* used for mlme_priv.roam_flags */ enum { RTW_ROAM_ON_EXPIRED = BIT0, @@ -329,8 +279,8 @@ enum { struct mlme_priv { - _lock lock; - sint fw_state; /* shall we protect this variable? maybe not necessarily... */ + spinlock_t lock; + signed int fw_state; /* shall we protect this variable? maybe not necessarily... */ u8 bScanInProcess; u8 to_join; /* flag */ @@ -361,15 +311,15 @@ struct mlme_priv { u32 auto_scan_int_ms; - _timer assoc_timer; + struct timer_list assoc_timer; uint assoc_by_bssid; uint assoc_by_rssi; - _timer scan_to_timer; /* driver itself handles scan_timeout status. */ + struct timer_list scan_to_timer; /* driver itself handles scan_timeout status. */ unsigned long scan_start_time; /* used to evaluate the time spent in scanning */ - _timer set_scan_deny_timer; + struct timer_list set_scan_deny_timer; atomic_t set_scan_deny; /* 0: allowed, 1: deny */ struct qos_priv qospriv; @@ -385,12 +335,12 @@ struct mlme_priv { struct ht_priv htpriv; - RT_LINK_DETECT_T LinkDetectInfo; - _timer dynamic_chk_timer; /* dynamic/periodic check timer */ + struct rt_link_detect_t LinkDetectInfo; + struct timer_list dynamic_chk_timer; /* dynamic/periodic check timer */ u8 acm_mask; /* for wmm acm mask */ u8 ChannelPlan; - RT_SCAN_TYPE scan_mode; /* active: 1, passive: 0 */ + enum rt_scan_type scan_mode; /* active: 1, passive: 0 */ u8 *wps_probe_req_ie; u32 wps_probe_req_ie_len; @@ -448,7 +398,7 @@ struct mlme_priv { u32 p2p_go_probe_resp_ie_len; /* for GO */ u32 p2p_assoc_req_ie_len; - _lock bcn_update_lock; + spinlock_t bcn_update_lock; u8 update_bcn; u8 NumOfBcnInfoChkFail; @@ -490,9 +440,9 @@ extern int rtw_init_mlme_priv(struct adapter *adapter);/* (struct mlme_priv *pm extern void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv); -extern sint rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv); -extern sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue); -extern sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv); +extern signed int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv); +extern signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, signed int keyid, u8 set_tx, bool enqueue); +extern signed int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv); static inline u8 *get_bssid(struct mlme_priv *pmlmepriv) { /* if sta_mode:pmlmepriv->cur_network.network.MacAddress => bssid */ @@ -500,7 +450,7 @@ static inline u8 *get_bssid(struct mlme_priv *pmlmepriv) return pmlmepriv->cur_network.network.MacAddress; } -static inline sint check_fwstate(struct mlme_priv *pmlmepriv, sint state) +static inline signed int check_fwstate(struct mlme_priv *pmlmepriv, signed int state) { if (pmlmepriv->fw_state & state) return true; @@ -508,7 +458,7 @@ static inline sint check_fwstate(struct mlme_priv *pmlmepriv, sint state) return false; } -static inline sint get_fwstate(struct mlme_priv *pmlmepriv) +static inline signed int get_fwstate(struct mlme_priv *pmlmepriv) { return pmlmepriv->fw_state; } @@ -520,7 +470,7 @@ static inline sint get_fwstate(struct mlme_priv *pmlmepriv) * ### NOTE:#### (!!!!) * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock */ -static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state) +static inline void set_fwstate(struct mlme_priv *pmlmepriv, signed int state) { pmlmepriv->fw_state |= state; /* FOR HW integration */ @@ -528,7 +478,7 @@ static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state) pmlmepriv->bScanInProcess = true; } -static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state) +static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, signed int state) { pmlmepriv->fw_state &= ~state; /* FOR HW integration */ @@ -540,7 +490,7 @@ static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint 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) +static inline void clr_fwstate(struct mlme_priv *pmlmepriv, signed int state) { spin_lock_bh(&pmlmepriv->lock); if (check_fwstate(pmlmepriv, state) == true) @@ -548,7 +498,7 @@ static inline void clr_fwstate(struct mlme_priv *pmlmepriv, sint state) spin_unlock_bh(&pmlmepriv->lock); } -static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, sint val) +static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, signed int val) { spin_lock_bh(&pmlmepriv->lock); pmlmepriv->num_of_scanned = val; @@ -600,9 +550,9 @@ extern void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_ne extern struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr); -extern sint rtw_if_up(struct adapter *padapter); +extern signed int rtw_if_up(struct adapter *padapter); -sint rtw_linked_check(struct adapter *padapter); +signed int rtw_linked_check(struct adapter *padapter); u8 *rtw_get_capability_from_ie(u8 *ie); u8 *rtw_get_beacon_interval_from_ie(u8 *ie); diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 1567831caf914a7453492a9e33e07eff919c8224..472818c5fd8355f8319241f445c2b21fcb2bdcaa 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -112,10 +112,10 @@ extern unsigned char WMM_PARA_OUI[]; /* Note: */ /* We just add new channel plan when the new channel plan is different from any of the following */ /* channel plan. */ -/* If you just wnat to customize the acitions(scan period or join actions) about one of the channel plan, */ -/* customize them in RT_CHANNEL_INFO in the RT_CHANNEL_LIST. */ +/* If you just want to customize the actions(scan period or join actions) about one of the channel plan, */ +/* customize them in rt_channel_info in the RT_CHANNEL_LIST. */ /* */ -typedef enum _RT_CHANNEL_DOMAIN { +enum { /* old channel plan mapping ===== */ RT_CHANNEL_DOMAIN_FCC = 0x00, RT_CHANNEL_DOMAIN_IC = 0x01, @@ -181,9 +181,9 @@ typedef enum _RT_CHANNEL_DOMAIN { /* Add new channel plan above this line =============== */ RT_CHANNEL_DOMAIN_MAX, RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F, -} RT_CHANNEL_DOMAIN, *PRT_CHANNEL_DOMAIN; +}; -typedef enum _RT_CHANNEL_DOMAIN_2G { +enum { RT_CHANNEL_DOMAIN_2G_WORLD = 0x00, /* Worldwird 13 */ RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01, /* Europe */ RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02, /* US */ @@ -193,9 +193,9 @@ typedef enum _RT_CHANNEL_DOMAIN_2G { RT_CHANNEL_DOMAIN_2G_NULL = 0x06, /* Add new channel plan above this line =============== */ RT_CHANNEL_DOMAIN_2G_MAX, -} RT_CHANNEL_DOMAIN_2G, *PRT_CHANNEL_DOMAIN_2G; +}; -typedef enum _RT_CHANNEL_DOMAIN_5G { +enum { RT_CHANNEL_DOMAIN_5G_NULL = 0x00, RT_CHANNEL_DOMAIN_5G_ETSI1 = 0x01, /* Europe */ RT_CHANNEL_DOMAIN_5G_ETSI2 = 0x02, /* Australia, New Zealand */ @@ -234,43 +234,31 @@ typedef enum _RT_CHANNEL_DOMAIN_5G { RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x21, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x22, RT_CHANNEL_DOMAIN_5G_MAX, -} RT_CHANNEL_DOMAIN_5G, *PRT_CHANNEL_DOMAIN_5G; +}; #define rtw_is_channel_plan_valid(chplan) (chplan < RT_CHANNEL_DOMAIN_MAX || chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE) -typedef struct _RT_CHANNEL_PLAN { +struct rt_channel_plan { unsigned char Channel[MAX_CHANNEL_NUM]; unsigned char Len; -} RT_CHANNEL_PLAN, *PRT_CHANNEL_PLAN; +}; -typedef struct _RT_CHANNEL_PLAN_2G { +struct rt_channel_plan_2g { unsigned char Channel[MAX_CHANNEL_NUM_2G]; unsigned char Len; -} RT_CHANNEL_PLAN_2G, *PRT_CHANNEL_PLAN_2G; +}; -typedef struct _RT_CHANNEL_PLAN_5G { +struct rt_channel_plan_5g { unsigned char Channel[MAX_CHANNEL_NUM_5G]; unsigned char Len; -} RT_CHANNEL_PLAN_5G, *PRT_CHANNEL_PLAN_5G; +}; -typedef struct _RT_CHANNEL_PLAN_MAP { +struct rt_channel_plan_map { unsigned char Index2G; unsigned char Index5G; -} RT_CHANNEL_PLAN_MAP, *PRT_CHANNEL_PLAN_MAP; - -enum Associated_AP { - atherosAP = 0, - broadcomAP = 1, - ciscoAP = 2, - marvellAP = 3, - ralinkAP = 4, - realtekAP = 5, - airgocapAP = 6, - unknownAP = 7, - maxAP, }; -typedef enum _HT_IOT_PEER { +enum { HT_IOT_PEER_UNKNOWN = 0, HT_IOT_PEER_REALTEK = 1, HT_IOT_PEER_REALTEK_92SE = 2, @@ -290,10 +278,10 @@ typedef enum _HT_IOT_PEER { HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 16, HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 17, HT_IOT_PEER_MAX = 18 -} HT_IOT_PEER_E, *PHTIOT_PEER_E; +}; -enum SCAN_STATE { +enum { SCAN_DISABLE = 0, SCAN_START = 1, SCAN_TXNULL = 2, @@ -304,13 +292,13 @@ enum SCAN_STATE { struct mlme_handler { unsigned int num; - char* str; + char *str; unsigned int (*func)(struct adapter *padapter, union recv_frame *precv_frame); }; struct action_handler { unsigned int num; - char* str; + char *str; unsigned int (*func)(struct adapter *padapter, union recv_frame *precv_frame); }; @@ -417,12 +405,12 @@ struct mlme_ext_info { }; /* The channel information about this channel including joining, scanning, and power constraints. */ -typedef struct _RT_CHANNEL_INFO { +struct rt_channel_info { u8 ChannelNum; /* The channel number. */ - RT_SCAN_TYPE ScanType; /* Scan type such as passive or active scan. */ -} RT_CHANNEL_INFO, *PRT_CHANNEL_INFO; + enum rt_scan_type ScanType; /* Scan type such as passive or active scan. */ +}; -int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch); +int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch); bool rtw_mlme_band_check(struct adapter *adapter, const u32 ch); /* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */ @@ -474,7 +462,7 @@ struct mlme_ext_priv { unsigned char cur_wireless_mode; /* NETWORK_TYPE */ unsigned char max_chan_nums; - RT_CHANNEL_INFO channel_set[MAX_CHANNEL_NUM]; + struct rt_channel_info channel_set[MAX_CHANNEL_NUM]; struct p2p_channels channel_list; unsigned char basicrate[NumRates]; unsigned char datarate[NumRates]; @@ -483,10 +471,10 @@ struct mlme_ext_priv { struct ss_res sitesurvey_res; struct mlme_ext_info mlmext_info;/* for sta/adhoc mode, including current scanning/connecting/connected related info. */ /* for ap mode, network includes ap's cap_info */ - _timer survey_timer; - _timer link_timer; - _timer sa_query_timer; - /* _timer ADDBA_timer; */ + struct timer_list survey_timer; + struct timer_list link_timer; + struct timer_list sa_query_timer; + /* struct timer_list ADDBA_timer; */ u16 chan_scan_time; unsigned long last_scan_time; u8 scan_abort; @@ -589,21 +577,21 @@ int is_IBSS_empty(struct adapter *padapter); unsigned char check_assoc_AP(u8 *pframe, uint len); -int WMM_param_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE); +int WMM_param_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE); void WMMOnAssocRsp(struct adapter *padapter); -void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE); -void HT_info_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE); +void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE); +void HT_info_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE); void HTOnAssocRsp(struct adapter *padapter); -void ERP_IE_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE); +void ERP_IE_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE); void VCS_update(struct adapter *padapter, struct sta_info *psta); void update_ldpc_stbc_cap(struct sta_info *psta); void update_beacon_info(struct adapter *padapter, u8 *pframe, uint len, struct sta_info *psta); int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len); void update_IOT_info(struct adapter *padapter); -void update_capinfo(struct adapter * Adapter, u16 updateCap); +void update_capinfo(struct adapter *Adapter, u16 updateCap); void update_wireless_mode(struct adapter *padapter); void update_sta_basic_rate(struct sta_info *psta, u8 wireless_mode); int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx); @@ -630,8 +618,8 @@ 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); void report_surveydone_event(struct adapter *padapter); -void report_del_sta_event(struct adapter *padapter, unsigned char* MacAddr, unsigned short reason); -void report_add_sta_event(struct adapter *padapter, unsigned char* MacAddr, int cam_idx); +void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason); +void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx); void report_wmm_edca_update(struct adapter *padapter); u8 chk_bmc_sleepq_cmd(struct adapter *padapter); @@ -702,18 +690,15 @@ void sa_query_timer_hdl(struct timer_list *t); #define set_survey_timer(mlmeext, ms) \ do { \ - /*DBG_871X("%s set_survey_timer(%p, %d)\n", __func__, (mlmeext), (ms));*/ \ _set_timer(&(mlmeext)->survey_timer, (ms)); \ } while (0) #define set_link_timer(mlmeext, ms) \ do { \ - /*DBG_871X("%s set_link_timer(%p, %d)\n", __func__, (mlmeext), (ms));*/ \ _set_timer(&(mlmeext)->link_timer, (ms)); \ } while (0) #define set_sa_query_timer(mlmeext, ms) \ do { \ - DBG_871X("%s set_sa_query_timer(%p, %d)\n", __func__, (mlmeext), (ms)); \ _set_timer(&(mlmeext)->sa_query_timer, (ms)); \ } while (0) @@ -760,7 +745,6 @@ u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf); u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf); u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf); u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf); -u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf); u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf); u8 run_in_thread_hdl(struct adapter *padapter, u8 *pbuf); @@ -787,7 +771,7 @@ struct C2HEvent_Header { void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf); void rtw_fwdbg_event_callback(struct adapter *adapter, u8 *pbuf); -enum rtw_c2h_event { +enum { GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ GEN_EVT_CODE(_Read_BBREG), GEN_EVT_CODE(_Read_RFREG), diff --git a/drivers/staging/rtl8723bs/include/rtw_mp.h b/drivers/staging/rtl8723bs/include/rtw_mp.h index ab7cd51ce68182823b45e15b4a630fd878612f04..2788ad80b11480b889e2dd1b8132eca18fc25ec0 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mp.h +++ b/drivers/staging/rtl8723bs/include/rtw_mp.h @@ -15,7 +15,7 @@ struct mp_xmit_frame { struct pkt_attrib attrib; - _pkt *pkt; + struct sk_buff *pkt; int frame_tag; @@ -31,8 +31,6 @@ struct mp_wiparam { u32 io_value; }; -typedef void(*wi_act_func)(void *padapter); - struct mp_tx { u8 stop; u32 count, sended; @@ -51,14 +49,14 @@ struct mp_tx { #define MP_MAX_LINES_BYTES 256 typedef void (*MPT_WORK_ITEM_HANDLER)(void *Adapter); -typedef struct _MPT_CONTEXT { +struct mpt_context { /* Indicate if we have started Mass Production Test. */ bool bMassProdTest; /* Indicate if the driver is unloading or unloaded. */ bool bMptDrvUnload; - _timer MPh2c_timeout_timer; + struct timer_list MPh2c_timeout_timer; /* Event used to sync H2c for BT control */ bool MptH2cRspEvent; @@ -91,7 +89,7 @@ typedef struct _MPT_CONTEXT { /* The RfPath of IO operation is depend of MptActType. */ u32 MptRfPath; - enum WIRELESS_MODE MptWirelessModeToSw; /* Wireless mode to switch. */ + enum wireless_mode MptWirelessModeToSw; /* Wireless mode to switch. */ u8 MptChannelToSw; /* Channel to switch. */ u8 MptInitGainToSet; /* Initial gain to set. */ u32 MptBandWidth; /* bandwidth to switch. */ @@ -103,7 +101,7 @@ typedef struct _MPT_CONTEXT { /* For MP Tx Power index */ u8 TxPwrLevel[2]; /* rf-A, rf-B */ u32 RegTxPwrLimit; - /* Content of RCR Regsiter for Mass Production Test. */ + /* Content of RCR Register for Mass Production Test. */ u32 MptRCR; /* true if we only receive packets with specific pattern. */ bool bMptFilterPattern; @@ -150,7 +148,7 @@ typedef struct _MPT_CONTEXT { u32 mptOutLen; u8 mptOutBuf[100]; -} MPT_CONTEXT, *PMPT_CONTEXT; +}; /* endif */ /* E-Fuse */ @@ -191,12 +189,6 @@ enum { CTA_TEST, MP_DISABLE_BT_COEXIST, MP_PwrCtlDM, -#ifdef CONFIG_WOWLAN - MP_WOW_ENABLE, -#endif -#ifdef CONFIG_AP_WOWLAN - MP_AP_WOW_ENABLE, -#endif MP_NULL, MP_GET_TXPOWER_INX, }; @@ -262,125 +254,23 @@ struct mp_priv { bool bSetRxBssid; bool bTxBufCkFail; - MPT_CONTEXT MptCtx; + struct mpt_context MptCtx; u8 *TXradomBuffer; }; -typedef struct _IOCMD_STRUCT_ { - u8 cmdclass; - u16 value; - u8 index; -} IOCMD_STRUCT; - -struct rf_reg_param { - u32 path; - u32 offset; - u32 value; -}; - -struct bb_reg_param { - u32 offset; - u32 value; -}; - #define LOWER true #define RAISE false /* Hardware Registers */ #define BB_REG_BASE_ADDR 0x800 -/* MP variables */ -enum MP_MODE { - MP_OFF, - MP_ON, - MP_ERR, - MP_CONTINUOUS_TX, - MP_SINGLE_CARRIER_TX, - MP_CARRIER_SUPPRISSION_TX, - MP_SINGLE_TONE_TX, - MP_PACKET_TX, - MP_PACKET_RX -}; - #define MAX_RF_PATH_NUMS RF_PATH_MAX extern u8 mpdatarate[NumRates]; -/* MP set force data rate base on the definition. */ -enum MPT_RATE_INDEX { - /* CCK rate. */ - MPT_RATE_1M = 0, /* 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 */ - /* VHT rate. Total: 20*/ - MPT_RATE_VHT1SS_MCS0 = 100,/* To reserve MCS16~MCS31, the index starts from #100. */ - MPT_RATE_VHT1SS_MCS1, /* #101 */ - MPT_RATE_VHT1SS_MCS2, - MPT_RATE_VHT1SS_MCS3, - MPT_RATE_VHT1SS_MCS4, - MPT_RATE_VHT1SS_MCS5, - MPT_RATE_VHT1SS_MCS6, /* #106 */ - MPT_RATE_VHT1SS_MCS7, - MPT_RATE_VHT1SS_MCS8, - MPT_RATE_VHT1SS_MCS9, - MPT_RATE_VHT2SS_MCS0, - MPT_RATE_VHT2SS_MCS1, /* #111 */ - MPT_RATE_VHT2SS_MCS2, - MPT_RATE_VHT2SS_MCS3, - MPT_RATE_VHT2SS_MCS4, - MPT_RATE_VHT2SS_MCS5, - MPT_RATE_VHT2SS_MCS6, /* #116 */ - MPT_RATE_VHT2SS_MCS7, - MPT_RATE_VHT2SS_MCS8, - MPT_RATE_VHT2SS_MCS9, - MPT_RATE_LAST -}; - #define MAX_TX_PWR_INDEX_N_MODE 64 /* 0x3F */ -enum POWER_MODE { - POWER_LOW = 0, - POWER_NORMAL -}; - -/* The following enumeration is used to define the value of Reg0xD00[30:28] or JaguarReg0x914[18:16]. */ -enum OFDM_TX_MODE { - OFDM_ALL_OFF = 0, - OFDM_ContinuousTx = 1, - OFDM_SingleCarrier = 2, - OFDM_SingleTone = 4, -}; - #define RX_PKT_BROADCAST 1 #define RX_PKT_DEST_ADDR 2 #define RX_PKT_PHY_MATCH 3 @@ -396,19 +286,6 @@ enum OFDM_TX_MODE { #define Mac_HT_FasleAlarm 0x90000000 #define Mac_DropPacket 0xA0000000 -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 */ -}; - -enum MPT_TXPWR_DEF { - MPT_CCK, - MPT_OFDM, /* L and HT OFDM */ - MPT_VHT_OFDM -}; - #define REG_RF_BB_GAIN_OFFSET 0x7f #define RF_GAIN_OFFSET_MASK 0xfffff diff --git a/drivers/staging/rtl8723bs/include/rtw_odm.h b/drivers/staging/rtl8723bs/include/rtw_odm.h index 263e92cfea963ad7f42f660aa7a8635422785286..94fc68a5c424fa0d4fab0b2529b2662c139d1088 100644 --- a/drivers/staging/rtl8723bs/include/rtw_odm.h +++ b/drivers/staging/rtl8723bs/include/rtw_odm.h @@ -13,7 +13,7 @@ * This file provides utilities/wrappers for rtw driver to use ODM */ -void rtw_odm_dbg_comp_msg(void *sel, struct adapter *adapter); +void rtw_odm_dbg_comp_msg(struct adapter *adapter); void rtw_odm_dbg_comp_set(struct adapter *adapter, u64 comps); void rtw_odm_dbg_level_msg(void *sel, struct adapter *adapter); void rtw_odm_dbg_level_set(struct adapter *adapter, u32 level); diff --git a/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h b/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h index 0987891e85aee339f9f55e07fec4d32671aded05..0767dbb84199ef995e7961494e32099355f9df1e 100644 --- a/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h +++ b/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h @@ -31,7 +31,7 @@ #define BTCOEX_ALIVE BIT(4) -enum Power_Mgnt { +enum { PS_MODE_ACTIVE = 0, PS_MODE_MIN, PS_MODE_MAX, @@ -46,11 +46,6 @@ enum Power_Mgnt { PS_MODE_NUM, }; -#ifdef CONFIG_PNO_SUPPORT -#define MAX_PNO_LIST_COUNT 16 -#define MAX_SCAN_LIST_COUNT 14 /* 2.4G only */ -#endif - /* BIT[2:0] = HW state BIT[3] = Protocol PS state, 0: register active state , 1: register sleep state @@ -94,7 +89,7 @@ struct reportpwrstate_parm { unsigned short rsvd; }; -#define LPS_DELAY_TIME 1*HZ /* 1 sec */ +#define LPS_DELAY_TIME (1 * HZ) /* 1 sec */ #define EXE_PWR_NONE 0x01 #define EXE_PWR_IPS 0x02 @@ -117,7 +112,7 @@ enum rt_rf_power_state { #define RT_RF_OFF_LEVL_FREE_FW BIT(4) /* FW free, re-download the FW */ #define RT_RF_OFF_LEVL_FW_32K BIT(5) /* FW in 32k */ #define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) /* Always enable ASPM and Clock Req in initialization. */ -#define RT_RF_LPS_DISALBE_2R BIT(30) /* When LPS is on, disable 2R if no packet is received or transmittd. */ +#define RT_RF_LPS_DISALBE_2R BIT(30) /* When LPS is on, disable 2R if no packet is received or transmitted. */ #define RT_RF_LPS_LEVEL_ASPM BIT(31) /* LPS with ASPM */ #define RT_IN_PS_LEVEL(ppsc, _PS_FLAG) ((ppsc->cur_ps_level & _PS_FLAG) ? true : false) @@ -129,8 +124,7 @@ enum rt_rf_power_state { #define RT_PCI_ASPM_OSC_ENABLE BIT0 /* PCI ASPM controlled by OS according to ACPI Spec 5.0 */ #define RT_PCI_ASPM_OSC_DISABLE BIT1 /* PCI ASPM controlled by driver or BIOS, i.e., force enable ASPM */ - -enum _PS_BBRegBackup_ { +enum { PSBBREG_RF0 = 0, PSBBREG_RF1, PSBBREG_RF2, @@ -146,7 +140,7 @@ enum { /* for ips_mode */ }; /* Design for pwrctrl_priv.ips_deny, 32 bits for 32 reasons at most */ -enum PS_DENY_REASON { +enum ps_deny_reason { PS_DENY_DRV_INITIAL = 0, PS_DENY_SCAN, PS_DENY_JOIN, @@ -158,47 +152,6 @@ enum PS_DENY_REASON { PS_DENY_OTHERS = 31 }; -#ifdef CONFIG_PNO_SUPPORT -struct pno_nlo_info { - u32 fast_scan_period; /* Fast scan period */ - u32 ssid_num; /* number of entry */ - u32 slow_scan_period; /* slow scan period */ - u32 fast_scan_iterations; /* Fast scan iterations */ - u8 ssid_length[MAX_PNO_LIST_COUNT]; /* SSID Length Array */ - u8 ssid_cipher_info[MAX_PNO_LIST_COUNT]; /* Cipher information for security */ - u8 ssid_channel_info[MAX_PNO_LIST_COUNT]; /* channel information */ -}; - -struct pno_ssid { - u32 SSID_len; - u8 SSID[32]; -}; - -struct pno_ssid_list { - struct pno_ssid node[MAX_PNO_LIST_COUNT]; -}; - -struct pno_scan_channel_info { - u8 channel; - u8 tx_power; - u8 timeout; - u8 active; /* set 1 means active scan, or pasivite scan. */ -}; - -struct pno_scan_info { - u8 enableRFE; /* Enable RFE */ - u8 period_scan_time; /* exclusive with fast_scan_period and slow_scan_period */ - u8 periodScan; /* exclusive with fast_scan_period and slow_scan_period */ - u8 orig_80_offset; /* original channel 80 offset */ - u8 orig_40_offset; /* original channel 40 offset */ - u8 orig_bw; /* original bandwidth */ - u8 orig_ch; /* original channel */ - u8 channel_num; /* number of channel */ - u64 rfe_type; /* rfe_type && 0x00000000000000ff */ - struct pno_scan_channel_info ssid_channel_info[MAX_SCAN_LIST_COUNT]; -}; -#endif /* CONFIG_PNO_SUPPORT */ - struct pwrctrl_priv { struct mutex lock; volatile u8 rpwm; /* requested power state for fw */ @@ -212,10 +165,10 @@ struct pwrctrl_priv { u8 dtim; u32 alives; - _workitem cpwm_event; + struct work_struct cpwm_event; u8 brpwmtimeout; - _workitem rpwmtimeoutwi; - _timer pwr_rpwm_timer; + struct work_struct rpwmtimeoutwi; + struct timer_list pwr_rpwm_timer; u8 bpower_saving; /* for LPS/IPS */ u8 b_hw_radio_off; @@ -238,7 +191,7 @@ struct pwrctrl_priv { u8 pre_ips_type;/* 0: default flow, 1: carddisbale flow */ /* ps_deny: if 0, power save is free to go; otherwise deny all kinds of power save. */ - /* Use PS_DENY_REASON to decide reason. */ + /* Use enum ps_deny_reason to decide reason. */ /* Don't access this variable directly without control function, */ /* and this variable should be protected by lock. */ u32 ps_deny; @@ -250,7 +203,7 @@ struct pwrctrl_priv { u8 LpsIdleCount; u8 power_mgnt; u8 org_power_mgnt; - u8 bFwCurrentInPSMode; + bool fw_current_in_ps_mode; unsigned long DelayLPSLastTimeStamp; s32 pnp_current_pwr_state; u8 pnp_bstop_trx; @@ -266,23 +219,7 @@ struct pwrctrl_priv { u8 wowlan_wake_reason; u8 wowlan_ap_mode; u8 wowlan_mode; -#ifdef CONFIG_WOWLAN - u8 wowlan_pattern; - u8 wowlan_magic; - u8 wowlan_unicast; - u8 wowlan_pattern_idx; - u8 wowlan_pno_enable; -#ifdef CONFIG_PNO_SUPPORT - u8 pno_in_resume; - u8 pno_inited; - struct pno_nlo_info *pnlo_info; - struct pno_scan_info *pscan_info; - struct pno_ssid_list *pno_ssid_list; -#endif - u32 wowlan_pattern_context[8][5]; - u64 wowlan_fw_iv; -#endif /* CONFIG_WOWLAN */ - _timer pwr_state_check_timer; + struct timer_list pwr_state_check_timer; struct adapter *adapter; int pwr_state_check_interval; u8 pwr_state_check_cnts; @@ -300,17 +237,13 @@ struct pwrctrl_priv { unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT]; }; -#define rtw_get_ips_mode_req(pwrctl) \ - (pwrctl)->ips_mode_req - #define rtw_ips_mode_req(pwrctl, ips_mode) \ - (pwrctl)->ips_mode_req = (ips_mode) + ((pwrctl)->ips_mode_req = (ips_mode)) #define RTW_PWR_STATE_CHK_INTERVAL 2000 #define _rtw_set_pwr_state_check_timer(pwrctl, ms) \ do { \ - /*DBG_871X("%s _rtw_set_pwr_state_check_timer(%p, %d)\n", __func__, (pwrctl), (ms));*/ \ _set_timer(&(pwrctl)->pwr_state_check_timer, (ms)); \ } while (0) @@ -352,8 +285,8 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal int rtw_pm_set_ips(struct adapter *padapter, u8 mode); int rtw_pm_set_lps(struct adapter *padapter, u8 mode); -void rtw_ps_deny(struct adapter *padapter, enum PS_DENY_REASON reason); -void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason); +void rtw_ps_deny(struct adapter *padapter, enum ps_deny_reason reason); +void rtw_ps_deny_cancel(struct adapter *padapter, enum ps_deny_reason reason); u32 rtw_ps_deny_get(struct adapter *padapter); #endif /* __RTL871X_PWRCTRL_H_ */ diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h index b4aeb44d5d6e2142640571ccc2a0a1e9dc58a604..9c3cdcc990fa9da974735d28cc0d2eeff3629175 100644 --- a/drivers/staging/rtl8723bs/include/rtw_recv.h +++ b/drivers/staging/rtl8723bs/include/rtw_recv.h @@ -7,13 +7,9 @@ #ifndef _RTW_RECV_H_ #define _RTW_RECV_H_ - #ifdef CONFIG_SINGLE_RECV_BUF - #define NR_RECVBUFF (1) - #else - #define NR_RECVBUFF (8) - #endif /* CONFIG_SINGLE_RECV_BUF */ +#define NR_RECVBUFF (8) - #define NR_PREALLOC_RECV_SKB (8) +#define NR_PREALLOC_RECV_SKB (8) #define NR_RECVFRAME 256 @@ -47,7 +43,7 @@ struct recv_reorder_ctrl { u16 wend_b; u8 wsize_b; struct __queue pending_recvframe_queue; - _timer reordering_ctrl_timer; + struct timer_list reordering_ctrl_timer; }; struct stainfo_rxcache { @@ -73,13 +69,6 @@ struct stainfo_rxcache { }; -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 signal_stat { u8 update_req; /* used to indicate */ u8 avg_val; /* avg of valid elements */ @@ -143,7 +132,7 @@ struct rx_pkt_attrib { u8 order; u8 privacy; /* in frame_ctrl field */ u8 bdecrypted; - u8 encrypt; /* when 0 indicate no encrypt. when non-zero, indicate the encrypt algorith */ + u8 encrypt; /* when 0 indicates no encryption; when non-zero, indicates the encryption algorithm */ u8 iv_len; u8 icv_len; u8 crc_err; @@ -159,11 +148,6 @@ struct rx_pkt_attrib { u8 ack_policy; -/* ifdef CONFIG_TCP_CSUM_OFFLOAD_RX */ - u8 tcpchk_valid; /* 0: invalid, 1: valid */ - u8 ip_chkrpt; /* 0: incorrect, 1: correct */ - u8 tcp_chkrpt; /* 0: incorrect, 1: correct */ -/* endif */ u8 key_index; u8 data_rate; @@ -214,7 +198,7 @@ accesser of recv_priv: rtw_recv_entry(dispatch / passive level); recv_thread(pas using enter_critical section to protect */ struct recv_priv { - _lock lock; + spinlock_t lock; struct __queue free_recv_queue; struct __queue recv_pending_queue; struct __queue uc_swdec_pending_queue; @@ -235,10 +219,6 @@ struct recv_priv { struct tasklet_struct recv_tasklet; struct sk_buff_head free_recv_skb_queue; struct sk_buff_head rx_skb_queue; -#ifdef CONFIG_RX_INDICATE_QUEUE - struct task rx_indicate_tasklet; - struct ifqueue rx_indicate_queue; -#endif /* CONFIG_RX_INDICATE_QUEUE */ u8 *pallocated_recv_buf; u8 *precv_buf; /* 4 alignment */ @@ -247,7 +227,7 @@ struct recv_priv { struct __queue recv_buf_pending_queue; - /* For display the phy informatiom */ + /* For display the phy information */ u8 is_signal_dbg; /* for debug */ u8 signal_strength_dbg; /* for debug */ @@ -264,7 +244,7 @@ struct recv_priv { /* int FalseAlmCnt_all; */ - _timer signal_stat_timer; + struct timer_list signal_stat_timer; u32 signal_stat_sampling_interval; /* u32 signal_stat_converging_constant; */ struct signal_stat signal_qual_data; @@ -275,8 +255,8 @@ struct recv_priv { struct sta_recv_priv { - _lock lock; - sint option; + spinlock_t lock; + signed int option; /* struct __queue blk_strms[MAX_RX_NUMBLKS]; */ struct __queue defrag_q; /* keeping the fragment frame until defrag */ @@ -293,7 +273,7 @@ struct sta_recv_priv { struct recv_buf { struct list_head list; - _lock recvbuf_lock; + spinlock_t recvbuf_lock; u32 ref_cnt; @@ -308,7 +288,7 @@ struct recv_buf { u8 *ptail; u8 *pend; - _pkt *pskb; + struct sk_buff *pskb; u8 reuse; }; @@ -330,13 +310,8 @@ struct recv_buf { */ struct recv_frame_hdr { struct list_head list; -#ifndef CONFIG_BSD_RX_USE_MBUF struct sk_buff *pkt; struct sk_buff *pkt_newalloc; -#else /* CONFIG_BSD_RX_USE_MBUF */ - _pkt *pkt; - _pkt *pkt_newalloc; -#endif /* CONFIG_BSD_RX_USE_MBUF */ struct adapter *adapter; @@ -374,7 +349,7 @@ union recv_frame { }; -enum RX_PACKET_TYPE { +enum { NORMAL_RX,/* Normal rx packet */ TX_REPORT1,/* CCX */ TX_REPORT2,/* TX RPT */ @@ -393,8 +368,8 @@ extern int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *q extern void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue); u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter); -sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue); -sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue); +signed int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue); +signed int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue); struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue); void rtw_reordering_ctrl_timeout_handler(struct timer_list *t); @@ -419,7 +394,7 @@ static inline u8 *get_recvframe_data(union recv_frame *precvframe) } -static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz) +static inline u8 *recvframe_pull(union recv_frame *precvframe, signed int sz) { /* rx_data += sz; move rx_data sz bytes hereafter */ @@ -444,7 +419,7 @@ static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz) } -static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz) +static inline u8 *recvframe_put(union recv_frame *precvframe, signed int sz) { /* rx_tai += sz; move rx_tail sz bytes hereafter */ @@ -473,7 +448,7 @@ static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz) -static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz) +static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, signed int sz) { /* rmv data from rx_tail (by yitsen) */ @@ -507,7 +482,7 @@ static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem) } -static inline sint get_recvframe_len(union recv_frame *precvframe) +static inline signed int get_recvframe_len(union recv_frame *precvframe) { return precvframe->u.hdr.len; } @@ -517,14 +492,9 @@ static inline s32 translate_percentage_to_dbm(u32 SignalStrengthIndex) { s32 SignalPower; /* in dBm. */ -#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING - /* Translate to dBm (x =y-100) */ - SignalPower = SignalStrengthIndex - 100; -#else /* Translate to dBm (x = 0.5y-95). */ SignalPower = (s32)((SignalStrengthIndex + 1) >> 1); SignalPower -= 95; -#endif return SignalPower; } diff --git a/drivers/staging/rtl8723bs/include/rtw_rf.h b/drivers/staging/rtl8723bs/include/rtw_rf.h index d3a8e4b7069affcba3a686da5415af0f42dcdb0c..cb6beccd3d23d5df402fc999f7cbbb824b10e2d3 100644 --- a/drivers/staging/rtl8723bs/include/rtw_rf.h +++ b/drivers/staging/rtl8723bs/include/rtw_rf.h @@ -49,7 +49,7 @@ struct regulatory_class { u8 modem; }; -enum CAPABILITY { +enum { cESS = 0x0001, cIBSS = 0x0002, cPollable = 0x0004, @@ -68,37 +68,19 @@ enum CAPABILITY { cImmediateBA = 0x8000, }; -enum _REG_PREAMBLE_MODE { +enum { PREAMBLE_LONG = 1, PREAMBLE_AUTO = 2, PREAMBLE_SHORT = 3, }; -enum _RTL8712_RF_MIMO_CONFIG_ { - RTL8712_RFCONFIG_1T = 0x10, - RTL8712_RFCONFIG_2T = 0x20, - RTL8712_RFCONFIG_1R = 0x01, - RTL8712_RFCONFIG_2R = 0x02, - RTL8712_RFCONFIG_1T1R = 0x11, - RTL8712_RFCONFIG_1T2R = 0x12, - RTL8712_RFCONFIG_TURBO = 0x92, - RTL8712_RFCONFIG_2T2R = 0x22 -}; - -enum RF90_RADIO_PATH { - RF90_PATH_A = 0, /* Radio Path A */ - RF90_PATH_B = 1, /* Radio Path B */ - RF90_PATH_C = 2, /* Radio Path C */ - RF90_PATH_D = 3 /* Radio Path D */ -}; - /* Bandwidth Offset */ #define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 #define HAL_PRIME_CHNL_OFFSET_LOWER 1 #define HAL_PRIME_CHNL_OFFSET_UPPER 2 /* Represent Channel Width in HT Capabilities */ -enum CHANNEL_WIDTH { +enum channel_width { CHANNEL_WIDTH_20 = 0, CHANNEL_WIDTH_40 = 1, CHANNEL_WIDTH_80 = 2, @@ -109,14 +91,14 @@ enum CHANNEL_WIDTH { /* Represent Extension Channel Offset in HT Capabilities */ /* This is available only in 40Mhz mode. */ -enum EXTCHNL_OFFSET { +enum extchnl_offset { EXTCHNL_OFFSET_NO_EXT = 0, EXTCHNL_OFFSET_UPPER = 1, EXTCHNL_OFFSET_NO_DEF = 2, EXTCHNL_OFFSET_LOWER = 3, }; -enum VHT_DATA_SC { +enum { VHT_DATA_SC_DONOT_CARE = 0, VHT_DATA_SC_20_UPPER_OF_80MHZ = 1, VHT_DATA_SC_20_LOWER_OF_80MHZ = 2, @@ -130,14 +112,8 @@ enum VHT_DATA_SC { VHT_DATA_SC_40_LOWER_OF_80MHZ = 10, }; -enum PROTECTION_MODE { - PROTECTION_MODE_AUTO = 0, - PROTECTION_MODE_FORCE_ENABLE = 1, - PROTECTION_MODE_FORCE_DISABLE = 2, -}; - /* 2007/11/15 MH Define different RF type. */ -enum RT_RF_TYPE_DEFINITION { +enum { RF_1T2R = 0, RF_2T4R = 1, RF_2T2R = 2, diff --git a/drivers/staging/rtl8723bs/include/rtw_security.h b/drivers/staging/rtl8723bs/include/rtw_security.h index 85ffd4ec4ce538af0a0192e6d794796854e281e6..5c787e999aab310516d71772429b0b46c5c70529 100644 --- a/drivers/staging/rtl8723bs/include/rtw_security.h +++ b/drivers/staging/rtl8723bs/include/rtw_security.h @@ -84,14 +84,14 @@ union Keytype { }; -typedef struct _RT_PMKID_LIST { +struct rt_pmkid_list { u8 bUsed; u8 Bssid[6]; u8 PMKID[16]; u8 SsidBuf[33]; u8 *ssid_octet; u16 ssid_length; -} RT_PMKID_LIST, *PRT_PMKID_LIST; +}; struct security_priv { @@ -129,9 +129,6 @@ struct security_priv { u8 binstallGrpkey; -#ifdef CONFIG_GTK_OL - u8 binstallKCK_KEK; -#endif /* CONFIG_GTK_OL */ u8 binstallBIPkey; u8 busetkipkey; /* _timer tkip_timer; */ @@ -145,7 +142,7 @@ struct security_priv { /* keeps the auth_type & enc_status from upper layer ioctl(wpa_supplicant or wzc) */ - u32 ndisauthtype; /* enum NDIS_802_11_AUTHENTICATION_MODE */ + u32 ndisauthtype; /* enum ndis_802_11_authentication_mode */ u32 ndisencryptstatus; /* NDIS_802_11_ENCRYPTION_STATUS */ struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */ @@ -166,40 +163,11 @@ struct security_priv { u32 btkip_countermeasure_time; /* For WPA2 Pre-Authentication. */ - RT_PMKID_LIST PMKIDList[NUM_PMKID_CACHE]; /* Renamed from PreAuthKey[NUM_PRE_AUTH_KEY]. Annie, 2006-10-13. */ + struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE]; /* Renamed from PreAuthKey[NUM_PRE_AUTH_KEY]. Annie, 2006-10-13. */ u8 PMKIDIndex; u8 bWepDefaultKeyIdxSet; -#define DBG_SW_SEC_CNT -#ifdef DBG_SW_SEC_CNT - u64 wep_sw_enc_cnt_bc; - u64 wep_sw_enc_cnt_mc; - u64 wep_sw_enc_cnt_uc; - u64 wep_sw_dec_cnt_bc; - u64 wep_sw_dec_cnt_mc; - u64 wep_sw_dec_cnt_uc; - - u64 tkip_sw_enc_cnt_bc; - u64 tkip_sw_enc_cnt_mc; - u64 tkip_sw_enc_cnt_uc; - u64 tkip_sw_dec_cnt_bc; - u64 tkip_sw_dec_cnt_mc; - u64 tkip_sw_dec_cnt_uc; - - u64 aes_sw_enc_cnt_bc; - u64 aes_sw_enc_cnt_mc; - u64 aes_sw_enc_cnt_uc; - u64 aes_sw_dec_cnt_bc; - u64 aes_sw_dec_cnt_mc; - u64 aes_sw_dec_cnt_uc; -#endif /* DBG_SW_SEC_CNT */ -}; - -struct sha256_state { - u64 length; - u32 state[8], curlen; - u8 buf[64]; }; #define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\ @@ -364,24 +332,6 @@ static inline u32 rotr(u32 val, int bits) /* This is based on SHA256 implementation in LibTomCrypt that was released into * public domain by Tom St Denis. */ -/* the K array */ -static const unsigned long K[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, - 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, - 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, - 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, - 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, - 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, - 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, - 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, - 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, - 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - - /* Various logical functions */ #define RORc(x, y) \ (((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ diff --git a/drivers/staging/rtl8723bs/include/rtw_wifi_regd.h b/drivers/staging/rtl8723bs/include/rtw_wifi_regd.h index f798b0c744a4fc028cb6833b4795ca49b6673cc2..e611651cb40b558efe705e86532979ebfde34de6 100644 --- a/drivers/staging/rtl8723bs/include/rtw_wifi_regd.h +++ b/drivers/staging/rtl8723bs/include/rtw_wifi_regd.h @@ -8,18 +8,6 @@ #ifndef __RTW_WIFI_REGD_H__ #define __RTW_WIFI_REGD_H__ -struct country_code_to_enum_rd { - u16 countrycode; - const char *iso_name; -}; - -enum country_code_type_t { - COUNTRY_CODE_USER = 0, - - /*add new channel plan above this line */ - COUNTRY_CODE_MAX -}; - void rtw_regd_init(struct wiphy *wiphy, void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)); diff --git a/drivers/staging/rtl8723bs/include/rtw_xmit.h b/drivers/staging/rtl8723bs/include/rtw_xmit.h index c04318573f8f9b5176f245c62c2d6d17a6d8fcbb..e45753d17313721b9ea08c3b74881347c3568afd 100644 --- a/drivers/staging/rtl8723bs/include/rtw_xmit.h +++ b/drivers/staging/rtl8723bs/include/rtw_xmit.h @@ -83,13 +83,6 @@ do {\ #define TXDESC_OFFSET TXDESC_SIZE -enum TXDESC_SC { - SC_DONT_CARE = 0x00, - SC_UPPER = 0x01, - SC_LOWER = 0x02, - SC_DUPLICATE = 0x03 -}; - #define TXDESC_40_BYTES struct tx_desc { @@ -128,11 +121,11 @@ union txdesc { }; struct hw_xmit { - /* _lock xmit_lock; */ + /* spinlock_t xmit_lock; */ /* struct list_head pending; */ struct __queue *sta_queue; /* struct hw_txqueue *phwtxqueue; */ - /* sint txcmdcnt; */ + /* signed int txcmdcnt; */ int accnt; }; @@ -149,7 +142,7 @@ struct pkt_attrib { u32 pktlen; /* the original 802.3 pkt raw_data len (not include ether_hdr data) */ u32 last_txcmdsz; u8 nr_frags; - u8 encrypt; /* when 0 indicate no encrypt. when non-zero, indicate the encrypt algorith */ + u8 encrypt; /* when 0 indicates no encryption; when non-zero, indicates the encryption algorithm */ u8 iv_len; u8 icv_len; u8 iv[18]; @@ -284,7 +277,7 @@ struct xmit_frame { struct pkt_attrib attrib; - _pkt *pkt; + struct sk_buff *pkt; int frame_tag; @@ -312,9 +305,9 @@ struct tx_servq { struct sta_xmit_priv { - _lock lock; - sint option; - sint apsd_setting; /* When bit mask is on, the associated edca queue supports APSD. */ + spinlock_t lock; + signed int option; + signed int apsd_setting; /* When bit mask is on, the associated edca queue supports APSD. */ /* struct tx_servq blk_q[MAX_NUMBLKS]; */ @@ -336,19 +329,14 @@ struct sta_xmit_priv { struct hw_txqueue { - volatile sint head; - volatile sint tail; - volatile sint free_sz; /* in units of 64 bytes */ - volatile sint free_cmdsz; - volatile sint txsz[8]; + volatile signed int head; + volatile signed int tail; + volatile signed int free_sz; /* in units of 64 bytes */ + volatile signed int free_cmdsz; + volatile signed int txsz[8]; uint ff_hwaddr; uint cmd_hwaddr; - sint ac_tag; -}; - -struct agg_pkt_info { - u16 offset; - u16 pkt_len; + signed int ac_tag; }; enum cmdbuf_type { @@ -359,7 +347,7 @@ enum cmdbuf_type { struct xmit_priv { - _lock lock; + spinlock_t lock; struct completion xmit_comp; struct completion terminate_xmitthread_comp; @@ -412,13 +400,9 @@ struct xmit_priv { u8 wmm_para_seq[4];/* sequence for wmm ac parameter strength from large to small. it's value is 0->vo, 1->vi, 2->be, 3->bk. */ -#ifdef CONFIG_SDIO_TX_TASKLET - struct tasklet_struct xmit_tasklet; -#else void *SdioXmitThread; struct completion SdioXmitStart; struct completion SdioXmitTerminate; -#endif /* CONFIG_SDIO_TX_TASKLET */ struct __queue free_xmitbuf_queue; struct __queue pending_xmitbuf_queue; @@ -436,10 +420,10 @@ struct xmit_priv { u16 nqos_ssn; int ack_tx; - _mutex ack_tx_mutex; + struct mutex ack_tx_mutex; struct submit_ctx ack_tx_ops; u8 seq_no; - _lock lock_sctx; + spinlock_t lock_sctx; }; extern struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, @@ -463,20 +447,20 @@ struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv); struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv); extern s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe); extern void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue); -struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, sint up, u8 *ac); +struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, signed int up, u8 *ac); extern s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe); extern s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe); extern u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib); #define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib) -extern s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); -extern s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); +extern s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe); +extern s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe); s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag); void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); s32 rtw_txframes_pending(struct adapter *padapter); -void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry); +void rtw_init_hwxmits(struct hw_xmit *phwxmit, signed int entry); s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter); @@ -487,10 +471,10 @@ s32 rtw_alloc_hwxmits(struct adapter *padapter); void rtw_free_hwxmits(struct adapter *padapter); -s32 rtw_xmit(struct adapter *padapter, _pkt **pkt); +s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt); bool xmitframe_hiq_filter(struct xmit_frame *xmitframe); -sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe); +signed int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe); void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta); void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta); void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta); @@ -503,7 +487,7 @@ void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmit void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); struct xmit_buf *dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv); struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv); -sint check_pending_xmitbuf(struct xmit_priv *pxmitpriv); +signed int check_pending_xmitbuf(struct xmit_priv *pxmitpriv); int rtw_xmit_thread(void *context); u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe); diff --git a/drivers/staging/rtl8723bs/include/sdio_ops.h b/drivers/staging/rtl8723bs/include/sdio_ops.h index 6b0446be6d19c902bb8e33d0fd2a94c23b2bc3a1..c7559a884608f87a877c38e02f57fd6a28ef748d 100644 --- a/drivers/staging/rtl8723bs/include/sdio_ops.h +++ b/drivers/staging/rtl8723bs/include/sdio_ops.h @@ -25,17 +25,10 @@ s32 _sdio_write32(struct adapter *padapter, u32 addr, u32 val); extern void sd_int_hdl(struct adapter *padapter); extern u8 CheckIPSStatus(struct adapter *padapter); -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -extern u8 RecvOnePkt(struct adapter *padapter, u32 size); -#endif /* CONFIG_WOWLAN */ extern void InitInterrupt8723BSdio(struct adapter *padapter); extern void InitSysInterrupt8723BSdio(struct adapter *padapter); extern void EnableInterrupt8723BSdio(struct adapter *padapter); extern void DisableInterrupt8723BSdio(struct adapter *padapter); extern u8 HalQueryTxBufferStatus8723BSdio(struct adapter *padapter); extern void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter); -#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) -extern void ClearInterrupt8723BSdio(struct adapter *padapter); -#endif /* CONFIG_WOWLAN */ - #endif /* !__SDIO_OPS_H__ */ diff --git a/drivers/staging/rtl8723bs/include/sta_info.h b/drivers/staging/rtl8723bs/include/sta_info.h index 734f4e2ecd66d417fd4a77c7c4bcf44909b8b0aa..69c377eeeaf08fca79771acfb6ef6c9cf875fea1 100644 --- a/drivers/staging/rtl8723bs/include/sta_info.h +++ b/drivers/staging/rtl8723bs/include/sta_info.h @@ -31,13 +31,13 @@ struct wlan_acl_pool { struct __queue acl_node_q; }; -typedef struct _RSSI_STA { +struct rssi_sta { s32 UndecoratedSmoothedPWDB; s32 UndecoratedSmoothedCCK; s32 UndecoratedSmoothedOFDM; u64 PacketMap; u8 ValidBit; -} RSSI_STA, *PRSSI_STA; +}; struct stainfo_stats { @@ -69,7 +69,7 @@ struct stainfo_stats { struct sta_info { - _lock lock; + spinlock_t lock; struct list_head list; /* free_sta_queue */ struct list_head hash_list; /* sta_hash */ struct adapter *padapter; @@ -92,11 +92,6 @@ struct sta_info { union Keytype dot11tkiprxmickey; union Keytype dot118021x_UncstKey; union pn48 dot11txpn; /* PN48 used for Unicast xmit */ -#ifdef CONFIG_GTK_OL - u8 kek[RTW_KEK_LEN]; - u8 kck[RTW_KCK_LEN]; - u8 replay_ctr[RTW_REPLAY_CTR_LEN]; -#endif /* CONFIG_GTK_OL */ union pn48 dot11wtxpn; /* PN48 used for Unicast mgmt xmit. */ union pn48 dot11rxpn; /* PN48 used for Unicast recv. */ @@ -121,7 +116,7 @@ struct sta_info { struct stainfo_stats sta_stats; /* for A-MPDU TX, ADDBA timeout check */ - _timer addba_retry_timer; + struct timer_list addba_retry_timer; /* for A-MPDU Rx reordering buffer control */ struct recv_reorder_ctrl recvreorder_ctrl[16]; @@ -187,16 +182,11 @@ struct sta_info { u8 keep_alive_trycnt; -#ifdef CONFIG_AUTO_AP_MODE - u8 isrc; /* this device is rc */ - u16 pid; /* pairing id */ -#endif - u8 *passoc_req; u32 assoc_req_len; /* for DM */ - RSSI_STA rssi_stat; + struct rssi_sta rssi_stat; /* ODM_STA_INFO_T */ /* ================ODM Relative Info ======================= */ @@ -314,7 +304,7 @@ struct sta_priv { u8 *pstainfo_buf; struct __queue free_sta_queue; - _lock sta_hash_lock; + spinlock_t sta_hash_lock; struct list_head sta_hash[NUM_STA]; int asoc_sta_count; struct __queue sleep_q; @@ -324,8 +314,8 @@ struct sta_priv { struct list_head asoc_list; struct list_head auth_list; - _lock asoc_list_lock; - _lock auth_list_lock; + spinlock_t asoc_list_lock; + spinlock_t auth_list_lock; u8 asoc_list_cnt; u8 auth_list_cnt; @@ -339,7 +329,7 @@ struct sta_priv { */ struct sta_info *sta_aid[NUM_STA]; - u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap for sleeping sta. */ + u16 sta_dz_bitmap;/* only support for 15 stations, aid bitmap for sleeping stations. */ u16 tim_bitmap;/* only support 15 stations, aid = 0~15 mapping bit0~bit15 */ u16 max_num_sta; diff --git a/drivers/staging/rtl8723bs/include/wifi.h b/drivers/staging/rtl8723bs/include/wifi.h index fe984fcb66a9416afec6486f87ef575af2a343fc..036cf57c65a98090fe245d740dffad2bcc63f631 100644 --- a/drivers/staging/rtl8723bs/include/wifi.h +++ b/drivers/staging/rtl8723bs/include/wifi.h @@ -43,14 +43,14 @@ /* This test verifies the WLAN NIC can update the NAV through sending the CTS with large duration. */ #define WiFiNavUpperUs 30000 /* 30 ms */ -enum WIFI_FRAME_TYPE { +enum { WIFI_MGT_TYPE = (0), WIFI_CTRL_TYPE = (BIT(2)), WIFI_DATA_TYPE = (BIT(3)), WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /* QoS Data */ }; -enum WIFI_FRAME_SUBTYPE { +enum { /* below is for mgt frame */ WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), @@ -88,20 +88,6 @@ enum WIFI_FRAME_SUBTYPE { WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE), }; -enum WIFI_REG_DOMAIN { - DOMAIN_FCC = 1, - DOMAIN_IC = 2, - DOMAIN_ETSI = 3, - DOMAIN_SPAIN = 4, - DOMAIN_FRANCE = 5, - DOMAIN_MKK = 6, - DOMAIN_ISRAEL = 7, - DOMAIN_MKK1 = 8, - DOMAIN_MKK2 = 9, - DOMAIN_MKK3 = 10, - DOMAIN_MAX -}; - #define _TO_DS_ BIT(8) #define _FROM_DS_ BIT(9) #define _MORE_FRAG_ BIT(10) @@ -112,65 +98,52 @@ enum WIFI_REG_DOMAIN { #define _ORDER_ BIT(15) #define SetToDs(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_) + (*(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_)) #define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_TO_DS_)) != 0) -#define ClearToDs(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_TO_DS_)) - #define SetFrDs(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_) + (*(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_)) #define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_FROM_DS_)) != 0) -#define ClearFrDs(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_FROM_DS_)) - #define get_tofr_ds(pframe) ((GetToDs(pframe) << 1) | GetFrDs(pframe)) #define SetMFrag(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_) + (*(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_)) #define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_FRAG_)) != 0) #define ClearMFrag(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_)) - -#define SetRetry(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_RETRY_) + (*(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_))) #define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_RETRY_)) != 0) #define ClearRetry(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_)) + (*(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_))) #define SetPwrMgt(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_) + (*(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_)) #define GetPwrMgt(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_PWRMGT_)) != 0) #define ClearPwrMgt(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_)) + (*(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_))) #define SetMData(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_) + (*(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_)) #define GetMData(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_DATA_)) != 0) #define ClearMData(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_)) + (*(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_))) #define SetPrivacy(pbuf) \ - *(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_) + (*(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_)) #define GetPrivacy(pbuf) \ (((*(__le16 *)(pbuf)) & cpu_to_le16(_PRIVACY_)) != 0) -#define ClearPrivacy(pbuf) \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(_PRIVACY_)) - - #define GetOrder(pbuf) \ (((*(__le16 *)(pbuf)) & cpu_to_le16(_ORDER_)) != 0) @@ -218,33 +191,26 @@ enum WIFI_REG_DOMAIN { } while (0) #define SetDuration(pbuf, dur) \ - *(__le16 *)((size_t)(pbuf) + 2) = cpu_to_le16(0xffff & (dur)) + (*(__le16 *)((size_t)(pbuf) + 2) = cpu_to_le16(0xffff & (dur))) #define SetPriority(pbuf, tid) \ - *(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf) + (*(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf)) #define GetPriority(pbuf) ((le16_to_cpu(*(__le16 *)(pbuf))) & 0xf) #define SetEOSP(pbuf, eosp) \ - *(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4) + (*(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4)) #define SetAckpolicy(pbuf, ack) \ - *(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5) + (*(__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 SetAMsdu(pbuf, amsdu) \ - *(__le16 *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7) - #define GetAid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 2)) & 0x3fff) -#define GetTid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + \ - (((GetToDs(pbuf)<<1) | GetFrDs(pbuf)) == 3 ? \ - 30 : 24))) & 0x000f) - #define GetAddr1Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 4)) #define GetAddr2Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 10)) @@ -435,21 +401,6 @@ static inline int IsFrameTypeCtrl(unsigned char *pframe) #define ACT_CAT_VENDOR 0x7F/* 127 */ -/** - * struct rtw_ieee80211_bar - HT Block Ack Request - * - * This structure refers to "HT BlockAckReq" as - * described in 802.11n draft section 7.2.1.7.1 - */ -struct rtw_ieee80211_bar { - __le16 frame_control; - __le16 duration; - unsigned char ra[6]; - unsigned char ta[6]; - __le16 control; - __le16 start_seq_num; -} __attribute__((packed)); - /** * struct rtw_ieee80211_ht_cap - HT additional information * @@ -719,7 +670,7 @@ struct ADDBA_request { #define P2P_WILDCARD_SSID_LEN 7 -#define P2P_FINDPHASE_EX_NONE 0 /* default value, used when: (1)p2p disabed or (2)p2p enabled but only do 1 scan phase */ +#define P2P_FINDPHASE_EX_NONE 0 /* default value, used when: (1)p2p disabled or (2)p2p enabled but only do 1 scan phase */ #define P2P_FINDPHASE_EX_FULL 1 /* used when p2p enabled and want to do 1 scan phase and P2P_FINDPHASE_EX_MAX-1 find phase */ #define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1) #define P2P_FINDPHASE_EX_MAX 4 @@ -727,7 +678,7 @@ struct ADDBA_request { #define P2P_PROVISION_TIMEOUT 5000 /* 5 seconds timeout for sending the provision discovery request */ #define P2P_CONCURRENT_PROVISION_TIMEOUT 3000 /* 3 seconds timeout for sending the provision discovery request under concurrent mode */ -#define P2P_GO_NEGO_TIMEOUT 5000 /* 5 seconds timeout for receiving the group negotation response */ +#define P2P_GO_NEGO_TIMEOUT 5000 /* 5 seconds timeout for receiving the group negotiation response */ #define P2P_CONCURRENT_GO_NEGO_TIMEOUT 3000 /* 3 seconds timeout for sending the negotiation request under concurrent mode */ #define P2P_TX_PRESCAN_TIMEOUT 100 /* 100ms */ #define P2P_INVITE_TIMEOUT 5000 /* 5 seconds timeout for sending the invitation request */ @@ -751,14 +702,14 @@ struct ADDBA_request { #define WPS_CM_SW_DISPLAY_PIN 0x2008 #define WPS_CM_LCD_DISPLAY_PIN 0x4008 -enum P2P_ROLE { +enum p2p_role { P2P_ROLE_DISABLE = 0, P2P_ROLE_DEVICE = 1, P2P_ROLE_CLIENT = 2, P2P_ROLE_GO = 3 }; -enum P2P_STATE { +enum p2p_state { P2P_STATE_NONE = 0, /* P2P disable */ P2P_STATE_IDLE = 1, /* P2P had enabled and do nothing */ P2P_STATE_LISTEN = 2, /* In pure listen state */ @@ -784,7 +735,7 @@ enum P2P_STATE { P2P_STATE_TX_INFOR_NOREADY = 22, /* sending p2p negotiation response with information is not available */ }; -enum P2P_WPSINFO { +enum p2p_wpsinfo { P2P_NO_WPSINFO = 0, P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, @@ -793,16 +744,6 @@ enum P2P_WPSINFO { #define P2P_PRIVATE_IOCTL_SET_LEN 64 -enum P2P_PROTO_WK_ID { - P2P_FIND_PHASE_WK = 0, - P2P_RESTORE_STATE_WK = 1, - P2P_PRE_TX_PROVDISC_PROCESS_WK = 2, - P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3, - P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4, - P2P_AP_P2P_CH_SWITCH_PROCESS_WK = 5, - P2P_RO_CH_WK = 6, -}; - /* =====================WFD Section ===================== */ /* For Wi-Fi Display */ #define WFD_ATTR_DEVICE_INFO 0x00 diff --git a/drivers/staging/rtl8723bs/include/wlan_bssdef.h b/drivers/staging/rtl8723bs/include/wlan_bssdef.h index 27cd2c5d90af07f4be39fb970314c153eed5f5bc..a45990bed80cffa618c7f7df9ac37db8aa3eab17 100644 --- a/drivers/staging/rtl8723bs/include/wlan_bssdef.h +++ b/drivers/staging/rtl8723bs/include/wlan_bssdef.h @@ -24,7 +24,7 @@ struct ndis_802_11_ssid { u8 Ssid[32]; }; -enum NDIS_802_11_NETWORK_TYPE { +enum ndis_802_11_network_type { Ndis802_11FH, Ndis802_11DS, Ndis802_11OFDM5, @@ -51,7 +51,7 @@ struct ndis_802_11_conf { struct ndis_802_11_conf_fh FHConfig; }; -enum NDIS_802_11_NETWORK_INFRASTRUCTURE { +enum ndis_802_11_network_infrastructure { Ndis802_11IBSS, Ndis802_11Infrastructure, Ndis802_11AutoUnknown, @@ -74,13 +74,13 @@ struct ndis_80211_var_ie { /* Length is the 4 bytes multiples of the sum of * sizeof (NDIS_802_11_MAC_ADDRESS) + 2 + * sizeof (struct ndis_802_11_ssid) + sizeof (u32) + - * sizeof (long) + sizeof (enum NDIS_802_11_NETWORK_TYPE) + + * sizeof (long) + sizeof (enum ndis_802_11_network_type) + * sizeof (struct ndis_802_11_conf) + sizeof (NDIS_802_11_RATES_EX) + IELength * * Except for IELength, all other fields are fixed length. Therefore, we can * define a macro to present the partial sum. */ -enum NDIS_802_11_AUTHENTICATION_MODE { +enum ndis_802_11_authentication_mode { Ndis802_11AuthModeOpen, Ndis802_11AuthModeShared, Ndis802_11AuthModeAutoSwitch, @@ -91,7 +91,7 @@ enum NDIS_802_11_AUTHENTICATION_MODE { Ndis802_11AuthModeMax /* Not a real mode, defined as upper bound */ }; -enum NDIS_802_11_WEP_STATUS { +enum { Ndis802_11WEPEnabled, Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, Ndis802_11WEPDisabled, @@ -127,38 +127,7 @@ struct ndis_801_11_ai_resfi { u16 AssociationId; }; -typedef 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_801_11_ai_resfi ResponseFixedIEs; - u32 ResponseIELength; - u32 OffsetResponseIEs; -} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; - -enum NDIS_802_11_RELOAD_DEFAULTS { - Ndis802_11ReloadWEPKeys -}; - - /* Key mapping keys require a BSSID */ -typedef struct _NDIS_802_11_KEY { - u32 Length; /* Length of this structure */ - u32 KeyIndex; - u32 KeyLength; /* length of key in bytes */ - NDIS_802_11_MAC_ADDRESS BSSID; - unsigned long long KeyRSC; - u8 KeyMaterial[32]; /* variable length depending on above field */ -} NDIS_802_11_KEY, *PNDIS_802_11_KEY; - -typedef struct _NDIS_802_11_REMOVE_KEY { - u32 Length; /* Length of this structure */ - u32 KeyIndex; - NDIS_802_11_MAC_ADDRESS BSSID; -} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; struct ndis_802_11_wep { u32 Length; /* Length of this structure */ @@ -211,9 +180,9 @@ struct wlan_bssid_ex { struct ndis_802_11_ssid Ssid; u32 Privacy; long Rssi;/* in dBM, raw data , get from PHY) */ - enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + enum ndis_802_11_network_type NetworkTypeInUse; struct ndis_802_11_conf Configuration; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + enum ndis_802_11_network_infrastructure InfrastructureMode; NDIS_802_11_RATES_EX SupportedRates; struct wlan_phy_info PhyInfo; u32 IELength; @@ -236,13 +205,13 @@ struct wlan_network { struct wlan_bcn_info BcnInfo; }; -enum VRTL_CARRIER_SENSE { +enum { DISABLE_VCS, ENABLE_VCS, AUTO_VCS }; -enum VCS_TYPE { +enum { NONE_VCS, RTS_CTS, CTS_TO_SELF @@ -254,7 +223,7 @@ enum VCS_TYPE { #define PWR_UAPSD 3 #define PWR_VOIP 4 -enum UAPSD_MAX_SP { +enum { NO_LIMIT, TWO_MSDU, FOUR_MSDU, diff --git a/drivers/staging/rtl8723bs/include/xmit_osdep.h b/drivers/staging/rtl8723bs/include/xmit_osdep.h index e9ff274f7474616ca754d97c6597f48b971a7ab1..e781cd5dfd01eb864173533825b8a4739d82671a 100644 --- a/drivers/staging/rtl8723bs/include/xmit_osdep.h +++ b/drivers/staging/rtl8723bs/include/xmit_osdep.h @@ -9,9 +9,9 @@ struct pkt_file { - _pkt *pkt; + struct sk_buff *pkt; __kernel_size_t pkt_len; /* the remainder length of the open_file */ - _buffer *cur_buffer; + unsigned char *cur_buffer; u8 *buf_start; u8 *cur_addr; __kernel_size_t buf_len; @@ -25,8 +25,8 @@ struct sta_xmit_priv; struct xmit_frame; struct xmit_buf; -extern int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); -extern int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); +extern int _rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev); +extern int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev); void rtw_os_xmit_schedule(struct adapter *padapter); @@ -34,11 +34,11 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitb void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag); extern uint rtw_remainder_len(struct pkt_file *pfile); -extern void _rtw_open_pktfile(_pkt *pkt, struct pkt_file *pfile); +extern void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile); extern uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen); -extern sint rtw_endofpktfile(struct pkt_file *pfile); +extern signed int rtw_endofpktfile(struct pkt_file *pfile); -extern void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt); +extern void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt); extern void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe); #endif /* __XMIT_OSDEP_H_ */ diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index ff164a8c8679a080ad72b71aa2fb492847da84a7..c1dac6eec59f5bf777ee45c88ee4b2b7c668964d 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -235,14 +235,9 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl struct wiphy *wiphy = wdev->wiphy; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - - /* DBG_8192C("%s\n", __func__); */ - bssinf_len = pnetwork->network.IELength + sizeof(struct ieee80211_hdr_3addr); - if (bssinf_len > MAX_BSSINFO_LEN) { - DBG_871X("%s IE Length too long > %d byte\n", __func__, MAX_BSSINFO_LEN); + if (bssinf_len > MAX_BSSINFO_LEN) goto exit; - } { u16 wapi_len = 0; @@ -250,10 +245,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl if (rtw_get_wapi_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &wapi_len) > 0) { if (wapi_len > 0) - { - DBG_871X("%s, no support wapi!\n", __func__); goto exit; - } } } @@ -277,16 +269,9 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl { if (request->n_ssids == 1 && request->n_channels == 1) /* it means under processing WPS */ { - DBG_8192C("ssid =%s, len =%d\n", pssid->Ssid, pssid->SsidLength); - - if (ssids[0].ssid_len == 0) { - } - else if (pssid->SsidLength == ssids[0].ssid_len && - !memcmp(pssid->Ssid, ssids[0].ssid, ssids[0].ssid_len)) - { - DBG_871X("%s, got sr and ssid match!\n", __func__); - } - else + if (ssids[0].ssid_len != 0 && + (pssid->SsidLength != ssids[0].ssid_len || + memcmp(pssid->Ssid, ssids[0].ssid, ssids[0].ssid_len))) { if (psr) *psr = 0; /* clear sr */ @@ -347,10 +332,8 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl bss = cfg80211_inform_bss_frame(wiphy, notify_channel, (struct ieee80211_mgmt *)buf, len, notify_signal, GFP_ATOMIC); - if (unlikely(!bss)) { - DBG_8192C(FUNC_ADPT_FMT" bss NULL\n", FUNC_ADPT_ARG(padapter)); + if (unlikely(!bss)) goto exit; - } cfg80211_put_bss(wiphy, bss); kfree(buf); @@ -398,7 +381,6 @@ void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter) int freq = (int)cur_network->network.Configuration.DSConfig; struct ieee80211_channel *chan; - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); if (pwdev->iftype != NL80211_IFTYPE_ADHOC) { return; @@ -412,10 +394,7 @@ void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter) { memcpy(&cur_network->network, pnetwork, sizeof(struct wlan_bssid_ex)); - if (!rtw_cfg80211_inform_bss(padapter, cur_network)) - DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); - else - DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); + rtw_cfg80211_inform_bss(padapter, cur_network); } else { @@ -425,20 +404,16 @@ void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter) } if (!memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(struct ndis_802_11_ssid)) && !memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) - ) { - if (!rtw_cfg80211_inform_bss(padapter, scanned)) { - DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); - } else { - /* DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */ - } - } else { - DBG_871X("scanned & pnetwork compare fail\n"); + ) + rtw_cfg80211_inform_bss(padapter, scanned); + else rtw_warn_on(1); - } } if (!rtw_cfg80211_check_bss(padapter)) - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter)); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " BSS not found !!\n", + FUNC_ADPT_ARG(padapter)); } /* notify cfg80211 that device joined an IBSS */ chan = ieee80211_get_channel(wiphy, freq); @@ -451,7 +426,6 @@ void rtw_cfg80211_indicate_connect(struct adapter *padapter) struct wlan_network *cur_network = &(pmlmepriv->cur_network); struct wireless_dev *pwdev = padapter->rtw_wdev; - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); if (pwdev->iftype != NL80211_IFTYPE_STATION && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT ) { @@ -465,8 +439,6 @@ void rtw_cfg80211_indicate_connect(struct adapter *padapter) struct wlan_bssid_ex *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); struct wlan_network *scanned = pmlmepriv->cur_network_scanned; - /* DBG_871X(FUNC_ADPT_FMT" BSS not found\n", FUNC_ADPT_ARG(padapter)); */ - if (scanned == NULL) { rtw_warn_on(1); goto check_bss; @@ -474,24 +446,17 @@ void rtw_cfg80211_indicate_connect(struct adapter *padapter) if (!memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) && !memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(struct ndis_802_11_ssid)) - ) { - if (!rtw_cfg80211_inform_bss(padapter, scanned)) { - DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); - } else { - /* DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */ - } - } else { - DBG_871X("scanned: %s(%pM), cur: %s(%pM)\n", - scanned->network.Ssid.Ssid, MAC_ARG(scanned->network.MacAddress), - pnetwork->Ssid.Ssid, MAC_ARG(pnetwork->MacAddress) - ); + ) + rtw_cfg80211_inform_bss(padapter, scanned); + else rtw_warn_on(1); - } } check_bss: if (!rtw_cfg80211_check_bss(padapter)) - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter)); + netdev_dbg(padapter->pnetdev, + FUNC_ADPT_FMT " BSS not found !!\n", + FUNC_ADPT_ARG(padapter)); if (rtw_to_roam(padapter) > 0) { struct wiphy *wiphy = pwdev->wiphy; @@ -504,7 +469,6 @@ check_bss: notify_channel = ieee80211_get_channel(wiphy, freq); - DBG_871X(FUNC_ADPT_FMT" call cfg80211_roamed\n", FUNC_ADPT_ARG(padapter)); roam_info.channel = notify_channel; roam_info.bssid = cur_network->network.MacAddress; roam_info.req_ie = @@ -533,8 +497,6 @@ void rtw_cfg80211_indicate_disconnect(struct adapter *padapter) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wireless_dev *pwdev = padapter->rtw_wdev; - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); - if (pwdev->iftype != NL80211_IFTYPE_STATION && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT ) { @@ -566,8 +528,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa struct security_priv *psecuritypriv = &(padapter->securitypriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_8192C("%s\n", __func__); - param->u.crypt.err = 0; param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; @@ -591,32 +551,18 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa { psta = rtw_get_stainfo(pstapriv, param->sta_addr); if (!psta) - { /* ret = -EINVAL; */ - DBG_8192C("rtw_set_encryption(), sta has already been removed or never been added\n"); goto exit; - } } if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) - { - /* todo:clear default encryption keys */ - - DBG_8192C("clear default encryption keys, keyid =%d\n", param->u.crypt.idx); - goto exit; - } - if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) { - DBG_8192C("r871x_set_encryption, crypt.alg = WEP\n"); - wep_key_idx = param->u.crypt.idx; wep_key_len = param->u.crypt.key_len; - DBG_8192C("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len); - if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) { ret = -EINVAL; @@ -663,8 +609,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa { if (strcmp(param->u.crypt.alg, "WEP") == 0) { - DBG_8192C("%s, set group_key, WEP\n", __func__); - memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); psecuritypriv->dot118021XGrpPrivacy = _WEP40_; @@ -676,8 +620,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - DBG_8192C("%s, set group_key, TKIP\n", __func__); - psecuritypriv->dot118021XGrpPrivacy = _TKIP_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); @@ -692,16 +634,12 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { - DBG_8192C("%s, set group_key, CCMP\n", __func__); - psecuritypriv->dot118021XGrpPrivacy = _AES_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); } else { - DBG_8192C("%s, set group_key, none\n", __func__); - psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; } @@ -736,8 +674,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa if (strcmp(param->u.crypt.alg, "WEP") == 0) { - DBG_8192C("%s, set pairwise key, WEP\n", __func__); - psta->dot118021XPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) { @@ -746,8 +682,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - DBG_8192C("%s, set pairwise key, TKIP\n", __func__); - psta->dot118021XPrivacy = _TKIP_; /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ @@ -761,14 +695,10 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { - DBG_8192C("%s, set pairwise key, CCMP\n", __func__); - psta->dot118021XPrivacy = _AES_; } else { - DBG_8192C("%s, set pairwise key, none\n", __func__); - psta->dot118021XPrivacy = _NO_PRIVACY_; } @@ -851,8 +781,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; - DBG_8192C("%s\n", __func__); - param->u.crypt.err = 0; param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; @@ -882,9 +810,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param if (strcmp(param->u.crypt.alg, "WEP") == 0) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n")); - DBG_8192C("wpa_set_encryption, crypt.alg = WEP\n"); - wep_key_idx = param->u.crypt.idx; wep_key_len = param->u.crypt.key_len; @@ -927,17 +852,10 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param struct sta_info *psta, *pbcmc_sta; struct sta_priv *pstapriv = &padapter->stapriv; - /* DBG_8192C("%s, : dot11AuthAlgrthm == dot11AuthAlgrthm_8021X\n", __func__); */ - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) /* sta mode */ { psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); - if (psta == NULL) { - /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ - DBG_8192C("%s, : Obtain Sta_info fail\n", __func__); - } - else - { + if (psta) { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) psta->ieee8021x_blocked = false; @@ -952,8 +870,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param if (param->u.crypt.set_tx == 1)/* pairwise key */ { - DBG_8192C("%s, : param->u.crypt.set_tx == 1\n", __func__); - 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 */ @@ -966,9 +882,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ } - /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ - DBG_871X(" ~~~~set sta key:unicastkey\n"); - rtw_setstakey_cmd(padapter, psta, true, true); } else/* group key */ @@ -979,24 +892,20 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); padapter->securitypriv.binstallGrpkey = true; - /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ - DBG_871X(" ~~~~set sta key:groupkey\n"); padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true); } else if (strcmp(param->u.crypt.alg, "BIP") == 0) { - /* DBG_871X("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)); - /*DBG_871X("IGTK key below:\n"); + /* for (no = 0;no<16;no++) printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); - DBG_871X("\n");*/ + */ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; padapter->securitypriv.binstallBIPkey = true; - DBG_871X(" ~~~~set sta key:IGKT\n"); } } } @@ -1026,8 +935,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param exit: - DBG_8192C("%s, ret =%d\n", __func__, ret); - return ret; } @@ -1042,13 +949,6 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, struct adapter *padapter = rtw_netdev_priv(ndev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - DBG_871X(FUNC_NDEV_FMT" adding key for %pM\n", FUNC_NDEV_ARG(ndev), mac_addr); - DBG_871X("cipher = 0x%x\n", params->cipher); - DBG_871X("key_len = 0x%x\n", params->key_len); - DBG_871X("seq_len = 0x%x\n", params->seq_len); - DBG_871X("key_index =%d\n", key_index); - DBG_871X("pairwise =%d\n", pairwise); - param_len = sizeof(struct ieee_param) + params->key_len; param = rtw_malloc(param_len); if (param == NULL) @@ -1120,14 +1020,8 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { - /* DBG_8192C("@@@@@@@@@@ fw_state = 0x%x, iftype =%d\n", pmlmepriv->fw_state, rtw_wdev->iftype); */ ret = rtw_cfg80211_set_encryption(ndev, param, param_len); } - else - { - DBG_8192C("error!\n"); - - } addkey_end: kfree(param); @@ -1142,7 +1036,6 @@ static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev, void (*callback)(void *cookie, struct key_params*)) { - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); return 0; } @@ -1152,8 +1045,6 @@ static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, struct adapter *padapter = rtw_netdev_priv(ndev); struct security_priv *psecuritypriv = &padapter->securitypriv; - DBG_871X(FUNC_NDEV_FMT" key_index =%d\n", FUNC_NDEV_ARG(ndev), key_index); - if (key_index == psecuritypriv->dot11PrivacyKeyIndex) { /* clear the flag of wep default key set. */ @@ -1171,9 +1062,6 @@ static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, struct adapter *padapter = rtw_netdev_priv(ndev); struct security_priv *psecuritypriv = &padapter->securitypriv; - DBG_871X(FUNC_NDEV_FMT" key_index =%d, unicast =%d, multicast =%d\n", - FUNC_NDEV_ARG(ndev), key_index, unicast, multicast); - if ((key_index < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) /* set wep default key */ { psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; @@ -1209,22 +1097,16 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, sinfo->filled = 0; if (!mac) { - DBG_871X(FUNC_NDEV_FMT" mac ==%p\n", FUNC_NDEV_ARG(ndev), mac); ret = -ENOENT; goto exit; } psta = rtw_get_stainfo(pstapriv, (u8 *)mac); if (psta == NULL) { - DBG_8192C("%s, sta_info is null\n", __func__); ret = -ENOENT; goto exit; } -#ifdef DEBUG_CFG80211 - DBG_871X(FUNC_NDEV_FMT" mac =%pM\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac)); -#endif - /* for infra./P2PClient mode */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) @@ -1233,7 +1115,6 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, struct wlan_network *cur_network = &(pmlmepriv->cur_network); if (memcmp((u8 *)mac, cur_network->network.MacAddress, ETH_ALEN)) { - DBG_871X("%s, mismatch bssid =%pM\n", __func__, MAC_ARG(cur_network->network.MacAddress)); ret = -ENOENT; goto exit; } @@ -1266,22 +1147,18 @@ exit: return ret; } -extern int netdev_open(struct net_device *pnetdev); - static int cfg80211_rtw_change_iface(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type, struct vif_params *params) { enum nl80211_iftype old_type; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType; + enum ndis_802_11_network_infrastructure networkType; struct adapter *padapter = rtw_netdev_priv(ndev); struct wireless_dev *rtw_wdev = padapter->rtw_wdev; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); int ret = 0; - DBG_871X(FUNC_NDEV_FMT" type =%d\n", FUNC_NDEV_ARG(ndev), type); - if (adapter_to_dvobj(padapter)->processing_dev_remove == true) { ret = -EPERM; @@ -1289,23 +1166,18 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, } { - DBG_871X(FUNC_NDEV_FMT" call netdev_open\n", FUNC_NDEV_ARG(ndev)); if (netdev_open(ndev) != 0) { - DBG_871X(FUNC_NDEV_FMT" call netdev_open fail\n", FUNC_NDEV_ARG(ndev)); ret = -EPERM; goto exit; } } if (_FAIL == rtw_pwr_wakeup(padapter)) { - DBG_871X(FUNC_NDEV_FMT" call rtw_pwr_wakeup fail\n", FUNC_NDEV_ARG(ndev)); ret = -EPERM; goto exit; } old_type = rtw_wdev->iftype; - DBG_871X(FUNC_NDEV_FMT" old_iftype =%d, new_iftype =%d\n", - FUNC_NDEV_ARG(ndev), old_type, type); if (old_type != type) { @@ -1341,7 +1213,6 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, exit: - DBG_871X(FUNC_NDEV_FMT" ret:%d\n", FUNC_NDEV_ARG(ndev), ret); return ret; } @@ -1354,25 +1225,11 @@ void rtw_cfg80211_indicate_scan_done(struct adapter *adapter, bool aborted) spin_lock_bh(&pwdev_priv->scan_req_lock); if (pwdev_priv->scan_request) { - #ifdef DEBUG_CFG80211 - DBG_871X("%s with scan req\n", __func__); - #endif - /* avoid WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); */ - if (pwdev_priv->scan_request->wiphy != pwdev_priv->rtw_wdev->wiphy) - { - DBG_8192C("error wiphy compare\n"); - } - else - { + if (pwdev_priv->scan_request->wiphy == pwdev_priv->rtw_wdev->wiphy) cfg80211_scan_done(pwdev_priv->scan_request, &info); - } pwdev_priv->scan_request = NULL; - } else { - #ifdef DEBUG_CFG80211 - DBG_871X("%s without scan req\n", __func__); - #endif } spin_unlock_bh(&pwdev_priv->scan_req_lock); } @@ -1391,8 +1248,6 @@ void rtw_cfg80211_unlink_bss(struct adapter *padapter, struct wlan_network *pnet if (bss) { cfg80211_unlink_bss(wiphy, bss); - DBG_8192C("%s(): cfg80211_unlink %s!! () ", __func__, - select_network->Ssid.Ssid); cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss); } } @@ -1404,10 +1259,6 @@ void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter) struct __queue *queue = &(pmlmepriv->scanned_queue); struct wlan_network *pnetwork = NULL; -#ifdef DEBUG_CFG80211 - DBG_8192C("%s\n", __func__); -#endif - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); phead = get_list_head(queue); @@ -1444,18 +1295,11 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct adapter *padapter, char *b u8 *wps_ie; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -#ifdef DEBUG_CFG80211 - DBG_8192C("%s, ielen =%d\n", __func__, len); -#endif - if (len > 0) { - if ((wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen))) + wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen); + if (wps_ie) { - #ifdef DEBUG_CFG80211 - DBG_8192C("probe_req_wps_ielen =%d\n", wps_ielen); - #endif - if (pmlmepriv->wps_probe_req_ie) { pmlmepriv->wps_probe_req_ie_len = 0; @@ -1464,11 +1308,9 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct adapter *padapter, char *b } pmlmepriv->wps_probe_req_ie = rtw_malloc(wps_ielen); - if (pmlmepriv->wps_probe_req_ie == NULL) { - DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); + if (!pmlmepriv->wps_probe_req_ie) return -EINVAL; - } memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen); pmlmepriv->wps_probe_req_ie_len = wps_ielen; } @@ -1505,9 +1347,6 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy padapter = rtw_netdev_priv(ndev); pwdev_priv = adapter_wdev_data(padapter); pmlmepriv = &padapter->mlmepriv; - -/* ifdef DEBUG_CFG80211 */ - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); /* endif */ spin_lock_bh(&pwdev_priv->scan_req_lock); @@ -1516,19 +1355,8 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { -#ifdef DEBUG_CFG80211 - DBG_871X("%s under WIFI_AP_STATE\n", __func__); -#endif - if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) { - DBG_8192C("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); - - if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) - { - DBG_8192C("AP mode process WPS\n"); - } - need_indicate_scan_done = true; goto check_need_indicate_scan_done; } @@ -1541,16 +1369,12 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy } if (request->ie && request->ie_len > 0) - { rtw_cfg80211_set_probe_req_wpsp2pie(padapter, (u8 *)request->ie, request->ie_len); - } if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { - DBG_8192C("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); need_indicate_scan_done = true; goto check_need_indicate_scan_done; } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { - DBG_8192C("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); ret = -EBUSY; goto check_need_indicate_scan_done; } @@ -1564,14 +1388,12 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy lastscantime = jiffies; if (passtime > 12000) { - DBG_871X("%s: bBusyTraffic == true\n", __func__); need_indicate_scan_done = true; goto check_need_indicate_scan_done; } } if (rtw_is_scan_deny(padapter)) { - DBG_871X(FUNC_ADPT_FMT ": scan deny\n", FUNC_ADPT_ARG(padapter)); need_indicate_scan_done = true; goto check_need_indicate_scan_done; } @@ -1585,9 +1407,6 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy /* parsing request ssids, n_ssids */ for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { - #ifdef DEBUG_CFG80211 - DBG_8192C("ssid =%s, len =%d\n", ssids[i].ssid, ssids[i].ssid_len); - #endif memcpy(ssid[i].Ssid, ssids[i].ssid, ssids[i].ssid_len); ssid[i].SsidLength = ssids[i].ssid_len; } @@ -1595,9 +1414,6 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy /* parsing channels, n_channels */ memset(ch, 0, sizeof(struct rtw_ieee80211_channel)*RTW_CHANNEL_SCAN_AMOUNT); for (i = 0; i < request->n_channels && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { - #ifdef DEBUG_CFG80211 - DBG_871X(FUNC_ADPT_FMT CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(request->channels[i])); - #endif ch[i].hw_value = request->channels[i]->hw_value; ch[i].flags = request->channels[i]->flags; } @@ -1642,16 +1458,11 @@ exit: static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed) { - DBG_8192C("%s\n", __func__); return 0; } - - static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, u32 wpa_version) { - DBG_8192C("%s, wpa_version =%d\n", __func__, wpa_version); - if (!wpa_version) { psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; return 0; @@ -1670,9 +1481,6 @@ static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, u32 static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv, enum nl80211_auth_type sme_auth_type) { - DBG_8192C("%s, nl80211_auth_type =%d\n", __func__, sme_auth_type); - - switch (sme_auth_type) { case NL80211_AUTHTYPE_AUTOMATIC: @@ -1711,8 +1519,6 @@ static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 ciph u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm : &psecuritypriv->dot118021XGrpPrivacy; - DBG_8192C("%s, ucast =%d, cipher = 0x%x\n", __func__, ucast, cipher); - if (!cipher) { *profile_cipher = _NO_PRIVACY_; @@ -1742,7 +1548,6 @@ static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 ciph ndisencryptstatus = Ndis802_11Encryption3Enabled; break; default: - DBG_8192C("Unsupported cipher: 0x%x\n", cipher); return -ENOTSUPP; } @@ -1758,18 +1563,12 @@ static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 ciph static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, u32 key_mgt) { - DBG_8192C("%s, key_mgt = 0x%x\n", __func__, key_mgt); - if (key_mgt == WLAN_AKM_SUITE_8021X) /* auth_type = UMAC_AUTH_TYPE_8021X; */ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; else if (key_mgt == WLAN_AKM_SUITE_PSK) { psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; } - else { - DBG_8192C("Invalid key mgt: 0x%x\n", key_mgt); - /* return -EINVAL; */ - } return 0; } @@ -1803,16 +1602,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel memcpy(buf, pie, ielen); - /* dump */ - { - int i; - DBG_8192C("set wpa_ie(length:%zu):\n", ielen); - for (i = 0; i < ielen; i = i + 8) - DBG_8192C("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]); - } - if (ielen < RSN_HEADER_LEN) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen)); ret = -1; goto exit; } @@ -1823,8 +1613,6 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], wpa_ielen+2); - - DBG_8192C("got wpa_ie, wpa_ielen:%u\n", wpa_ielen); } } @@ -1834,8 +1622,6 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], wpa2_ielen+2); - - DBG_8192C("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen); } } @@ -1899,7 +1685,6 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel wps_ie = rtw_get_wps_ie(buf, ielen, NULL, &wps_ielen); if (wps_ie && wps_ielen > 0) { - DBG_8192C("got wps_ie, wps_ielen:%u\n", wps_ielen); padapter->securitypriv.wps_ie_len = wps_ielen < MAX_WPS_IE_LEN ? wps_ielen : MAX_WPS_IE_LEN; memcpy(padapter->securitypriv.wps_ie, wps_ie, padapter->securitypriv.wps_ie_len); set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); @@ -1916,10 +1701,6 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true) */ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, - ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n", - pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype)); - exit: kfree(buf); if (ret) @@ -1961,8 +1742,6 @@ static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, ndis_ssid.SsidLength = params->ssid_len; memcpy(ndis_ssid.Ssid, (u8 *)params->ssid, params->ssid_len); - /* DBG_8192C("ssid =%s, len =%zu\n", ndis_ssid.Ssid, params->ssid_len); */ - psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; @@ -1988,8 +1767,6 @@ static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) enum nl80211_iftype old_type; int ret = 0; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - old_type = rtw_wdev->iftype; rtw_set_to_roam(padapter, 0); @@ -2017,7 +1794,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) { int ret = 0; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; + enum ndis_802_11_authentication_mode authmode; struct ndis_802_11_ssid ndis_ssid; struct adapter *padapter = rtw_netdev_priv(ndev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -2025,14 +1802,9 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, padapter->mlmepriv.not_indic_disco = true; - DBG_871X("=>"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - DBG_871X("privacy =%d, key =%p, key_len =%d, key_idx =%d\n", - sme->privacy, sme->key, sme->key_len, sme->key_idx); - if (adapter_wdev_data(padapter)->block == true) { ret = -EBUSY; - DBG_871X("%s wdev_priv.block is set\n", __func__); goto exit; } @@ -2062,16 +1834,8 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, ndis_ssid.SsidLength = sme->ssid_len; memcpy(ndis_ssid.Ssid, (u8 *)sme->ssid, sme->ssid_len); - DBG_8192C("ssid =%s, len =%zu\n", ndis_ssid.Ssid, sme->ssid_len); - - - if (sme->bssid) - DBG_8192C("bssid =%pM\n", MAC_ARG(sme->bssid)); - - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ret = -EBUSY; - DBG_8192C("%s, fw_state = 0x%x, goto exit\n", __func__, pmlmepriv->fw_state); goto exit; } if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { @@ -2093,8 +1857,6 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, if (ret < 0) goto exit; - DBG_8192C("%s, ie_len =%zu\n", __func__, sme->ie_len); - ret = rtw_cfg80211_set_wpa_ie(padapter, (u8 *)sme->ie, sme->ie_len); if (ret < 0) goto exit; @@ -2110,7 +1872,6 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && sme->key) { u32 wep_key_idx, wep_key_len, wep_total_len; struct ndis_802_11_wep *pwep = NULL; - DBG_871X("%s(): Shared/Auto WEP\n", __func__); wep_key_idx = sme->key_idx; wep_key_len = sme->key_len; @@ -2125,7 +1886,6 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); pwep = rtw_malloc(wep_total_len); if (pwep == NULL) { - DBG_871X(" wpa_set_encryption: pwep allocate fail !!!\n"); ret = -ENOMEM; goto exit; } @@ -2178,14 +1938,10 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, goto exit; } - DBG_8192C("set ssid:dot11AuthAlgrthm =%d, dot11PrivacyAlgrthm =%d, dot118021XGrpPrivacy =%d\n", psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, psecuritypriv->dot118021XGrpPrivacy); - exit: rtw_ps_deny_cancel(padapter, PS_DENY_JOIN); - DBG_8192C("<=%s, ret %d\n", __func__, ret); - padapter->mlmepriv.not_indic_disco = false; return ret; @@ -2196,22 +1952,17 @@ static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev, { struct adapter *padapter = rtw_netdev_priv(ndev); - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - rtw_set_to_roam(padapter, 0); rtw_scan_abort(padapter); LeaveAllPowerSaveMode(padapter); rtw_disassoc_cmd(padapter, 500, false); - DBG_871X("%s...call rtw_indicate_disconnect\n", __func__); - rtw_indicate_disconnect(padapter); rtw_free_assoc_resources(padapter, 1); rtw_pwr_wakeup(padapter); - DBG_871X(FUNC_NDEV_FMT" return 0\n", FUNC_NDEV_ARG(ndev)); return 0; } @@ -2219,7 +1970,6 @@ static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { - DBG_8192C("%s\n", __func__); return 0; } @@ -2227,8 +1977,6 @@ static int cfg80211_rtw_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm) { - DBG_8192C("%s\n", __func__); - *dbm = (12); return 0; @@ -2247,9 +1995,6 @@ static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy, struct adapter *padapter = rtw_netdev_priv(ndev); struct rtw_wdev_priv *rtw_wdev_priv = adapter_wdev_data(padapter); - DBG_871X(FUNC_NDEV_FMT" enabled:%u, timeout:%d\n", FUNC_NDEV_ARG(ndev), - enabled, timeout); - rtw_wdev_priv->power_mgmt = enabled; if (!enabled) @@ -2267,8 +2012,6 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, struct security_priv *psecuritypriv = &padapter->securitypriv; u8 strZeroMacAddress[ETH_ALEN] = { 0x00 }; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - if (!memcmp((u8 *)pmksa->bssid, strZeroMacAddress, ETH_ALEN)) return -EINVAL; @@ -2277,8 +2020,6 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, /* overwrite PMKID */ for (index = 0 ; index < NUM_PMKID_CACHE; index++) { if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) { - /* BSSID is matched, the same AP => rewrite with new PMKID. */ - DBG_871X(FUNC_NDEV_FMT" BSSID exists in the PMKList.\n", FUNC_NDEV_ARG(ndev)); memcpy(psecuritypriv->PMKIDList[index].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN); psecuritypriv->PMKIDList[index].bUsed = true; @@ -2289,9 +2030,6 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, } if (!blInserted) { - /* Find a new entry */ - DBG_871X(FUNC_NDEV_FMT" Use the new entry index = %d for this PMKID.\n", - FUNC_NDEV_ARG(ndev), psecuritypriv->PMKIDIndex); memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, (u8 *)pmksa->bssid, ETH_ALEN); memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN); @@ -2313,8 +2051,6 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, struct adapter *padapter = rtw_netdev_priv(ndev); struct security_priv *psecuritypriv = &padapter->securitypriv; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - for (index = 0 ; index < NUM_PMKID_CACHE; index++) { if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) { /* @@ -2329,11 +2065,8 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, } } - if (false == bMatched) { - DBG_871X(FUNC_NDEV_FMT" do not have matched BSSID\n" - , FUNC_NDEV_ARG(ndev)); + if (!bMatched) return -EINVAL; - } return 0; } @@ -2344,9 +2077,7 @@ static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, struct adapter *padapter = rtw_netdev_priv(ndev); struct security_priv *psecuritypriv = &padapter->securitypriv; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - - memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); + memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); psecuritypriv->PMKIDIndex = 0; return 0; @@ -2356,8 +2087,6 @@ void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter, u8 *pmgmt_frame, { struct net_device *ndev = padapter->pnetdev; - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); - { struct station_info sinfo; u8 ie_offset; @@ -2377,8 +2106,6 @@ void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char { struct net_device *ndev = padapter->pnetdev; - DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); - cfg80211_del_sta(ndev, da, GFP_ATOMIC); } @@ -2398,13 +2125,9 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc struct ieee80211_radiotap_header *rtap_hdr; struct adapter *padapter = rtw_netdev_priv(ndev); - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - if (!skb) goto fail; - rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, skb->truesize); - if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) goto fail; @@ -2416,10 +2139,8 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc if (unlikely(skb->len < rtap_len)) goto fail; - if (rtap_len != 14) { - DBG_8192C("radiotap len (should be 14): %d\n", rtap_len); + if (rtap_len != 14) goto fail; - } /* Skip the ratio tap header */ skb_pull(skb, rtap_len); @@ -2447,8 +2168,6 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); - DBG_8192C("should be eapol packet\n"); - /* Use the real net device to transmit the packet */ return _rtw_xmit_entry(skb, padapter->pnetdev); @@ -2467,21 +2186,12 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc u32 len = skb->len; u8 category, action; - if (rtw_action_frame_parse(buf, len, &category, &action) == false) { - DBG_8192C(FUNC_NDEV_FMT" frame_control:0x%x\n", FUNC_NDEV_ARG(ndev), - le16_to_cpu(((struct ieee80211_hdr_3addr *)buf)->frame_control)); + if (rtw_action_frame_parse(buf, len, &category, &action) == false) goto fail; - } - - DBG_8192C("RTW_Tx:da =%pM via "FUNC_NDEV_FMT"\n", - MAC_ARG(GetAddr1Ptr(buf)), FUNC_NDEV_ARG(ndev)); - if (category == RTW_WLAN_CATEGORY_PUBLIC) - DBG_871X("RTW_Tx:%s\n", action_public_str(action)); - else - DBG_871X("RTW_Tx:category(%u), action(%u)\n", category, action); /* starting alloc mgmt frame to dump it */ - if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (!pmgntframe) goto fail; /* update attribute */ @@ -2507,11 +2217,8 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc dump_mgntframe(padapter, pmgntframe); - } else { - DBG_8192C("frame_control = 0x%x\n", frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)); } - fail: dev_kfree_skb_any(skb); @@ -2535,21 +2242,17 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter); if (!name) { - DBG_871X(FUNC_ADPT_FMT" without specific name\n", FUNC_ADPT_ARG(padapter)); ret = -EINVAL; goto out; } if (pwdev_priv->pmon_ndev) { - DBG_871X(FUNC_ADPT_FMT" monitor interface exist: %s\n", - FUNC_ADPT_ARG(padapter), NDEV_ARG(pwdev_priv->pmon_ndev)); ret = -EBUSY; goto out; } mon_ndev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator)); if (!mon_ndev) { - DBG_871X(FUNC_ADPT_FMT" allocate ndev fail\n", FUNC_ADPT_ARG(padapter)); ret = -ENOMEM; goto out; } @@ -2569,7 +2272,6 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str /* wdev */ mon_wdev = rtw_zmalloc(sizeof(struct wireless_dev)); if (!mon_wdev) { - DBG_871X(FUNC_ADPT_FMT" allocate mon_wdev fail\n", FUNC_ADPT_ARG(padapter)); ret = -ENOMEM; goto out; } @@ -2612,9 +2314,6 @@ static struct wireless_dev * struct net_device *ndev = NULL; struct adapter *padapter = wiphy_to_adapter(wiphy); - DBG_871X(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n", - FUNC_ADPT_ARG(padapter), wiphy_name(wiphy), name, type); - switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP_VLAN: @@ -2635,12 +2334,9 @@ static struct wireless_dev * break; default: ret = -ENODEV; - DBG_871X("Unsupported interface type\n"); break; } - DBG_871X(FUNC_ADPT_FMT" ndev:%p, ret:%d\n", FUNC_ADPT_ARG(padapter), ndev, ret); - return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret); } @@ -2666,7 +2362,6 @@ static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy, if (ndev == pwdev_priv->pmon_ndev) { pwdev_priv->pmon_ndev = NULL; pwdev_priv->ifname_mon[0] = '\0'; - DBG_871X(FUNC_NDEV_FMT" remove monitor interface\n", FUNC_NDEV_ARG(ndev)); } exit: @@ -2680,8 +2375,6 @@ static int rtw_add_beacon(struct adapter *adapter, const u8 *head, size_t head_l uint len, wps_ielen = 0; struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); - DBG_8192C("%s beacon_head_len =%zu, beacon_tail_len =%zu\n", __func__, head_len, tail_len); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) return -EINVAL; @@ -2698,8 +2391,7 @@ static int rtw_add_beacon(struct adapter *adapter, const u8 *head, size_t head_l len = head_len+tail_len-24; /* check wps ie if inclued */ - if (rtw_get_wps_ie(pbuf+_FIXED_IE_LENGTH_, len-_FIXED_IE_LENGTH_, NULL, &wps_ielen)) - DBG_8192C("add bcn, wps_ielen =%d\n", wps_ielen); + rtw_get_wps_ie(pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, &wps_ielen); /* pbss_network->IEs will not include p2p_ie, wfd ie */ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, WLAN_EID_VENDOR_SPECIFIC, P2P_OUI, 4); @@ -2723,9 +2415,6 @@ static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev, int ret = 0; struct adapter *adapter = rtw_netdev_priv(ndev); - DBG_871X(FUNC_NDEV_FMT" hidden_ssid:%d, auth_type:%d\n", FUNC_NDEV_ARG(ndev), - settings->hidden_ssid, settings->auth_type); - ret = rtw_add_beacon(adapter, settings->beacon.head, settings->beacon.head_len, settings->beacon.tail, settings->beacon.tail_len); @@ -2749,14 +2438,11 @@ static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *nd { struct adapter *adapter = rtw_netdev_priv(ndev); - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - return rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); } static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); return 0; } @@ -2764,8 +2450,6 @@ static int cfg80211_rtw_add_station(struct wiphy *wiphy, struct net_device *ndev const u8 *mac, struct station_parameters *params) { - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - return 0; } @@ -2781,17 +2465,10 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev struct sta_priv *pstapriv = &padapter->stapriv; const u8 *mac = params->mac; - DBG_871X("+"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - - if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) { - DBG_8192C("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", __func__); + if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true) return -EINVAL; - } - if (!mac) { - DBG_8192C("flush all sta, and cam_entry\n"); - flush_all_cam_entry(padapter); /* clear CAM */ rtw_sta_flush(padapter); @@ -2799,9 +2476,6 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev return 0; } - - DBG_8192C("free sta macaddr =%pM\n", MAC_ARG(mac)); - if (mac[0] == 0xff && mac[1] == 0xff && mac[2] == 0xff && mac[3] == 0xff && mac[4] == 0xff && mac[5] == 0xff) { @@ -2821,11 +2495,7 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev plist = get_next(plist); if (!memcmp((u8 *)mac, psta->hwaddr, ETH_ALEN)) { - if (psta->dot8021xalg == 1 && psta->bpairwise_key_installed == false) { - DBG_8192C("%s, sta's dot8021xalg = 1 and key_installed = false\n", __func__); - } else { - DBG_8192C("free psta =%p, aid =%d\n", psta, psta->aid); - + if (psta->dot8021xalg != 1 || psta->bpairwise_key_installed) { list_del_init(&psta->asoc_list); pstapriv->asoc_list_cnt--; @@ -2844,8 +2514,6 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev associated_clients_update(padapter, updated); - DBG_871X("-"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - return ret; } @@ -2853,8 +2521,6 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev static int cfg80211_rtw_change_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_parameters *params) { - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - return 0; } @@ -2886,13 +2552,11 @@ static int cfg80211_rtw_dump_station(struct wiphy *wiphy, struct net_device *nde struct adapter *padapter = rtw_netdev_priv(ndev); struct sta_info *psta = NULL; struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); spin_lock_bh(&pstapriv->asoc_list_lock); psta = rtw_sta_info_get_by_idx(idx, pstapriv); spin_unlock_bh(&pstapriv->asoc_list_lock); if (NULL == psta) { - DBG_871X("Station is not found\n"); ret = -ENOENT; goto exit; } @@ -2907,7 +2571,6 @@ exit: static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, struct bss_parameters *params) { - DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); return 0; } @@ -2921,12 +2584,6 @@ void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, rtw_action_frame_parse(frame, frame_len, &category, &action); - DBG_8192C("RTW_Rx:cur_ch =%d\n", channel); - if (msg) - DBG_871X("RTW_Rx:%s\n", msg); - else - DBG_871X("RTW_Rx:category(%u), action(%u)\n", category, action); - freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); @@ -2953,7 +2610,8 @@ static int _cfg80211_rtw_mgmt_tx(struct adapter *padapter, u8 tx_ch, const u8 *b } /* starting alloc mgmt frame to dump it */ - if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) { + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (!pmgntframe) { /* ret = -ENOMEM; */ ret = _FAIL; goto exit; @@ -2983,24 +2641,14 @@ static int _cfg80211_rtw_mgmt_tx(struct adapter *padapter, u8 tx_ch, const u8 *b ack = false; ret = _FAIL; - #ifdef DEBUG_CFG80211 - DBG_8192C("%s, ack == _FAIL\n", __func__); - #endif } else { msleep(50); - #ifdef DEBUG_CFG80211 - DBG_8192C("%s, ack =%d, ok!\n", __func__, ack); - #endif ret = _SUCCESS; } exit: - #ifdef DEBUG_CFG80211 - DBG_8192C("%s, ret =%d\n", __func__, ret); - #endif - return ret; } @@ -3036,27 +2684,11 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, /* cookie generation */ *cookie = (unsigned long) buf; -#ifdef DEBUG_CFG80211 - DBG_871X(FUNC_ADPT_FMT" len =%zu, ch =%d" - "\n", FUNC_ADPT_ARG(padapter), - len, tx_ch - ); -#endif /* DEBUG_CFG80211 */ - /* indicate ack before issue frame to avoid racing with rsp frame */ rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack, GFP_KERNEL); - if (rtw_action_frame_parse(buf, len, &category, &action) == false) { - DBG_8192C(FUNC_ADPT_FMT" frame_control:0x%x\n", FUNC_ADPT_ARG(padapter), - le16_to_cpu(((struct ieee80211_hdr_3addr *)buf)->frame_control)); + if (rtw_action_frame_parse(buf, len, &category, &action) == false) goto exit; - } - - DBG_8192C("RTW_Tx:tx_ch =%d, da =%pM\n", tx_ch, MAC_ARG(GetAddr1Ptr(buf))); - if (category == RTW_WLAN_CATEGORY_PUBLIC) - DBG_871X("RTW_Tx:%s\n", action_public_str(action)); - else - DBG_871X("RTW_Tx:category(%u), action(%u)\n", category, action); rtw_ps_deny(padapter, PS_DENY_MGNT_TX); if (_FAIL == rtw_pwr_wakeup(padapter)) { @@ -3069,19 +2701,12 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); } while (dump_cnt < dump_limit && tx_ret != _SUCCESS); - if (tx_ret != _SUCCESS || dump_cnt > 1) { - DBG_871X(FUNC_ADPT_FMT" %s (%d/%d)\n", FUNC_ADPT_ARG(padapter), - tx_ret == _SUCCESS?"OK":"FAIL", dump_cnt, dump_limit); - } - switch (type) { case P2P_GO_NEGO_CONF: rtw_clear_scan_deny(padapter); break; case P2P_INVIT_RESP: if (pwdev_priv->invit_info.flags & BIT(0) && pwdev_priv->invit_info.status == 0) { - DBG_871X(FUNC_ADPT_FMT" agree with invitation of persistent group\n", - FUNC_ADPT_ARG(padapter)); rtw_set_scan_deny(padapter, 5000); rtw_pwr_wakeup_ex(padapter, 5000); rtw_clear_scan_deny(padapter); @@ -3095,54 +2720,6 @@ exit: return ret; } -#if defined(CONFIG_PNO_SUPPORT) -static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_sched_scan_request *request) -{ - struct adapter *padapter = rtw_netdev_priv(dev); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - int ret; - - if (padapter->bup == false) { - DBG_871X("%s: net device is down.\n", __func__); - return -EIO; - } - - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true || - check_fwstate(pmlmepriv, _FW_LINKED) == true || - check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { - DBG_871X("%s: device is busy.\n", __func__); - rtw_scan_abort(padapter); - } - - if (request == NULL) { - DBG_871X("%s: invalid cfg80211_requests parameters.\n", __func__); - return -EINVAL; - } - - ret = rtw_android_cfg80211_pno_setup(dev, request->ssids, - request->n_ssids, request->interval); - - if (ret < 0) { - DBG_871X("%s ret: %d\n", __func__, ret); - goto exit; - } - - ret = rtw_android_pno_enable(dev, true); - if (ret < 0) { - DBG_871X("%s ret: %d\n", __func__, ret); - goto exit; - } -exit: - return ret; -} - -static int cfg80211_rtw_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) -{ - return rtw_android_pno_enable(dev, false); -} -#endif /* CONFIG_PNO_SUPPORT */ - static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum nl80211_band band, u8 rf_type) { @@ -3188,10 +2765,7 @@ static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum ht_cap->mcs.rx_mask[4] = 0x01; ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); - } else { - DBG_8192C("%s, error rf_type =%d\n", __func__, rf_type); } - } void rtw_cfg80211_init_wiphy(struct adapter *padapter) @@ -3203,8 +2777,6 @@ void rtw_cfg80211_init_wiphy(struct adapter *padapter) rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); - DBG_8192C("%s:rf_type =%d\n", __func__, rf_type); - { bands = wiphy->bands[NL80211_BAND_2GHZ]; if (bands) @@ -3248,9 +2820,6 @@ static void rtw_cfg80211_preinit_wiphy(struct adapter *padapter, struct wiphy *w #if defined(CONFIG_PM) wiphy->max_sched_scan_reqs = 1; -#ifdef CONFIG_PNO_SUPPORT - wiphy->max_sched_scan_ssids = MAX_PNO_LIST_COUNT; -#endif #endif #if defined(CONFIG_PM) @@ -3297,11 +2866,6 @@ static struct cfg80211_ops rtw_cfg80211_ops = { .change_bss = cfg80211_rtw_change_bss, .mgmt_tx = cfg80211_rtw_mgmt_tx, - -#if defined(CONFIG_PNO_SUPPORT) - .sched_scan_start = cfg80211_rtw_sched_scan_start, - .sched_scan_stop = cfg80211_rtw_sched_scan_stop, -#endif /* CONFIG_PNO_SUPPORT */ }; int rtw_wdev_alloc(struct adapter *padapter, struct device *dev) @@ -3312,12 +2876,9 @@ int rtw_wdev_alloc(struct adapter *padapter, struct device *dev) struct rtw_wdev_priv *pwdev_priv; struct net_device *pnetdev = padapter->pnetdev; - DBG_8192C("%s(padapter =%p)\n", __func__, padapter); - /* wiphy */ wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct adapter *)); if (!wiphy) { - DBG_8192C("Couldn't allocate wiphy device\n"); ret = -ENOMEM; goto exit; } @@ -3329,15 +2890,12 @@ int rtw_wdev_alloc(struct adapter *padapter, struct device *dev) rtw_regd_init(wiphy, rtw_reg_notifier); ret = wiphy_register(wiphy); - if (ret < 0) { - DBG_8192C("Couldn't register wiphy device\n"); + if (ret < 0) goto free_wiphy; - } /* wdev */ wdev = rtw_zmalloc(sizeof(struct wireless_dev)); if (!wdev) { - DBG_8192C("Couldn't allocate wireless device\n"); ret = -ENOMEM; goto unregister_wiphy; } @@ -3384,8 +2942,6 @@ exit: void rtw_wdev_free(struct wireless_dev *wdev) { - DBG_8192C("%s(wdev =%p)\n", __func__, wdev); - if (!wdev) return; @@ -3402,12 +2958,10 @@ void rtw_wdev_unregister(struct wireless_dev *wdev) struct adapter *adapter; struct rtw_wdev_priv *pwdev_priv; - DBG_8192C("%s(wdev =%p)\n", __func__, wdev); - if (!wdev) return; - - if (!(ndev = wdev_to_ndev(wdev))) + ndev = wdev_to_ndev(wdev); + if (!ndev) return; adapter = rtw_netdev_priv(ndev); @@ -3415,10 +2969,8 @@ void rtw_wdev_unregister(struct wireless_dev *wdev) rtw_cfg80211_indicate_scan_done(adapter, true); - if (pwdev_priv->pmon_ndev) { - DBG_8192C("%s, unregister monitor interface\n", __func__); + if (pwdev_priv->pmon_ndev) unregister_netdev(pwdev_priv->pmon_ndev); - } wiphy_unregister(wdev->wiphy); } diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 41389e266f5415da550f0d795493f239cf69d874..e98e5388d5c7b8c8828b0fd4ab74616cd8b719f9 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -33,17 +33,11 @@ static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000, 6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000}; -static const char * const iw_operation_mode[] = { - "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Monitor" -}; - void indicate_wx_scan_complete_event(struct adapter *padapter) { union iwreq_data wrqu; memset(&wrqu, 0, sizeof(union iwreq_data)); - - /* DBG_871X("+rtw_indicate_wx_scan_complete_event\n"); */ } @@ -64,7 +58,7 @@ void rtw_indicate_wx_assoc_event(struct adapter *padapter) else memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN); - DBG_871X_LEVEL(_drv_always_, "assoc success\n"); + netdev_dbg(padapter->pnetdev, "assoc success\n"); } void rtw_indicate_wx_disassoc_event(struct adapter *padapter) @@ -210,12 +204,10 @@ static char *translate_scan(struct adapter *padapter, if (vht_cap) { max_rate = vht_data_rate; } else if (ht_cap) { - if (mcs_rate&0x8000) { /* MCS15 */ + if (mcs_rate & 0x8000) /* MCS15 */ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); - } else { /* default MCS7 */ - /* DBG_871X("wx_get_scan, mcs_rate_bitmap = 0x%x\n", mcs_rate); */ + else /* default MCS7 */ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); - } max_rate = max_rate*2;/* Mbps/2; */ } @@ -232,17 +224,16 @@ static char *translate_scan(struct adapter *padapter, u16 wpa_len = 0, rsn_len = 0; u8 *p; rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); buf = kzalloc(MAX_WPA_IE_LEN*2, GFP_ATOMIC); if (!buf) return start; if (wpa_len > 0) { p = buf; - p += sprintf(p, "wpa_ie ="); + p += scnprintf(p, (MAX_WPA_IE_LEN * 2) - (p - buf), "wpa_ie ="); for (i = 0; i < wpa_len; i++) - p += sprintf(p, "%02x", wpa_ie[i]); + p += scnprintf(p, (MAX_WPA_IE_LEN * 2) - (p - buf), + "%02x", wpa_ie[i]); if (wpa_len > 100) { printk("-----------------Len %d----------------\n", wpa_len); @@ -265,9 +256,10 @@ static char *translate_scan(struct adapter *padapter, if (rsn_len > 0) { p = buf; memset(buf, 0, MAX_WPA_IE_LEN*2); - p += sprintf(p, "rsn_ie ="); + p += scnprintf(p, (MAX_WPA_IE_LEN * 2) - (p - buf), "rsn_ie ="); for (i = 0; i < rsn_len; i++) - p += sprintf(p, "%02x", rsn_ie[i]); + p += scnprintf(p, (MAX_WPA_IE_LEN * 2) - (p - buf), + "%02x", rsn_ie[i]); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = strlen(buf); @@ -311,15 +303,7 @@ static char *translate_scan(struct adapter *padapter, /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED - #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - | IW_QUAL_NOISE_UPDATED - #else - | IW_QUAL_NOISE_INVALID - #endif - #ifdef CONFIG_SIGNAL_DISPLAY_DBM - | IW_QUAL_DBM - #endif - ; + | IW_QUAL_NOISE_INVALID; if (check_fwstate(pmlmepriv, _FW_LINKED) == true && is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { @@ -331,51 +315,26 @@ static char *translate_scan(struct adapter *padapter, } - #ifdef CONFIG_SIGNAL_DISPLAY_DBM - iwe.u.qual.level = (u8)translate_percentage_to_dbm(ss);/* dbm */ - #else - #ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING - { - /* Do signal scale mapping when using percentage as the unit of signal strength, since the scale mapping is skipped in odm */ - - struct hal_com_data *pHal = GET_HAL_DATA(padapter); - - iwe.u.qual.level = (u8)odm_SignalScaleMapping(&pHal->odmpriv, ss); - } - #else iwe.u.qual.level = (u8)ss;/* */ - #endif - #endif iwe.u.qual.qual = (u8)sq; /* signal quality */ - #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - { - s16 tmp_noise = 0; - rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(pnetwork->network.Configuration.DSConfig), &(tmp_noise)); - iwe.u.qual.noise = tmp_noise; - } - #else iwe.u.qual.noise = 0; /* noise level */ - #endif - - /* DBG_871X("iqual =%d, ilevel =%d, inoise =%d, iupdated =%d\n", iwe.u.qual.qual, iwe.u.qual.level , iwe.u.qual.noise, iwe.u.qual.updated); */ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); { u8 *buf; - u8 *p, *pos; + u8 *pos; buf = kzalloc(MAX_WPA_IE_LEN, GFP_ATOMIC); if (!buf) goto exit; - p = buf; + pos = pnetwork->network.Reserved; - p += sprintf(p, "fm =%02X%02X", pos[1], pos[0]); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = strlen(buf); + iwe.u.data.length = scnprintf(buf, MAX_WPA_IE_LEN, "fm =%02X%02X", pos[1], pos[0]); start = iwe_stream_add_point(info, start, stop, &iwe, buf); kfree(buf); } @@ -391,27 +350,21 @@ static int wpa_set_auth_algs(struct net_device *dev, u32 value) int ret = 0; if ((value & WLAN_AUTH_SHARED_KEY) && (value & WLAN_AUTH_OPEN)) { - DBG_871X("wpa_set_auth_algs, WLAN_AUTH_SHARED_KEY and WLAN_AUTH_OPEN [value:0x%x]\n", value); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; } else if (value & WLAN_AUTH_SHARED_KEY) { - DBG_871X("wpa_set_auth_algs, WLAN_AUTH_SHARED_KEY [value:0x%x]\n", value); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; } else if (value & WLAN_AUTH_OPEN) { - DBG_871X("wpa_set_auth_algs, WLAN_AUTH_OPEN\n"); /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */ if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) { padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; } - } else if (value & WLAN_AUTH_LEAP) { - DBG_871X("wpa_set_auth_algs, WLAN_AUTH_LEAP\n"); } else { - DBG_871X("wpa_set_auth_algs, error!\n"); ret = -EINVAL; } @@ -452,8 +405,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, } if (strcmp(param->u.crypt.alg, "WEP") == 0) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n")); - DBG_871X("wpa_set_encryption, crypt.alg = WEP\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; @@ -462,22 +413,15 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, wep_key_idx = param->u.crypt.idx; wep_key_len = param->u.crypt.key_len; - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(1)wep_key_idx =%d\n", wep_key_idx)); - DBG_871X("(1)wep_key_idx =%d\n", wep_key_idx); - if (wep_key_idx > WEP_KEYS) return -EINVAL; - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(2)wep_key_idx =%d\n", wep_key_idx)); - if (wep_key_len > 0) { wep_key_len = wep_key_len <= 5 ? 5 : 13; wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); pwep = kzalloc(wep_total_len, GFP_KERNEL); - if (pwep == NULL) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, (" wpa_set_encryption: pwep allocate fail !!!\n")); + if (!pwep) goto exit; - } pwep->KeyLength = wep_key_len; pwep->Length = wep_total_len; @@ -497,13 +441,9 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); if (param->u.crypt.set_tx) { - DBG_871X("wep, set_tx = 1\n"); - if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) ret = -EOPNOTSUPP; } else { - DBG_871X("wep, set_tx = 0\n"); - /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to fw/cam */ @@ -550,9 +490,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ } - /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ - DBG_871X(" ~~~~set sta key:unicastkey\n"); - rtw_setstakey_cmd(padapter, psta, true, true); } else { /* group key */ if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) { @@ -563,8 +500,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); } padapter->securitypriv.binstallGrpkey = true; - /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ - DBG_871X(" ~~~~set sta key:groupkey\n"); padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; @@ -579,7 +514,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, printk("\n");*/ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; padapter->securitypriv.binstallBIPkey = true; - DBG_871X(" ~~~~set sta key:IGKT\n"); } } } @@ -632,16 +566,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie memcpy(buf, pie, ielen); - /* dump */ - { - int i; - DBG_871X("\n wpa_ie(length:%d):\n", ielen); - for (i = 0; i < ielen; i = i + 8) - DBG_871X("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]); - } - if (ielen < RSN_HEADER_LEN) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen)); ret = -1; goto exit; } @@ -718,8 +643,6 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie eid = buf[cnt]; if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&buf[cnt+2], wps_oui, 4))) { - DBG_871X("SET WPS_IE\n"); - padapter->securitypriv.wps_ie_len = ((buf[cnt+1]+2) < MAX_WPS_IE_LEN) ? (buf[cnt+1]+2):MAX_WPS_IE_LEN; memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len); @@ -744,10 +667,6 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true) */ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, - ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n", - pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype)); - exit: kfree(buf); @@ -767,8 +686,6 @@ static int rtw_wx_get_name(struct net_device *dev, struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; NDIS_802_11_RATES_EX *prates = NULL; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd)); - if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { /* parsing HT_CAP_IE */ p = rtw_get_ie(&pcur_bss->IEs[12], WLAN_EID_HT_CAPABILITY, &ht_ielen, pcur_bss->IELength-12); @@ -814,8 +731,6 @@ static int rtw_wx_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_wx_set_freq\n")); - return 0; } @@ -846,7 +761,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *b) { struct adapter *padapter = rtw_netdev_priv(dev); - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType; + enum ndis_802_11_network_infrastructure networkType; int ret = 0; if (_FAIL == rtw_pwr_wakeup(padapter)) { @@ -862,24 +777,19 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, switch (wrqu->mode) { case IW_MODE_AUTO: networkType = Ndis802_11AutoUnknown; - DBG_871X("set_mode = IW_MODE_AUTO\n"); break; case IW_MODE_ADHOC: networkType = Ndis802_11IBSS; - DBG_871X("set_mode = IW_MODE_ADHOC\n"); break; case IW_MODE_MASTER: networkType = Ndis802_11APMode; - DBG_871X("set_mode = IW_MODE_MASTER\n"); /* rtw_setopmode_cmd(padapter, networkType, true); */ break; case IW_MODE_INFRA: networkType = Ndis802_11Infrastructure; - DBG_871X("set_mode = IW_MODE_INFRA\n"); break; default: ret = -EINVAL; - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported \n", iw_operation_mode[wrqu->mode])); goto exit; } @@ -913,8 +823,6 @@ static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a, struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_get_mode\n")); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { wrqu->mode = IW_MODE_INFRA; } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || @@ -950,7 +858,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev, memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); if (pPMK->cmd == IW_PMKSA_ADD) { - DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n"); if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) return intReturn; else @@ -961,8 +868,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev, /* overwrite PMKID */ for (j = 0; j < NUM_PMKID_CACHE; j++) { if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { - /* BSSID is matched, the same AP => rewrite with new PMKID. */ - DBG_871X("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n"); memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN); psecuritypriv->PMKIDList[j].bUsed = true; @@ -973,9 +878,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev, } if (!blInserted) { - /* Find a new entry */ - DBG_871X("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n", - psecuritypriv->PMKIDIndex); memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN); memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN); @@ -986,7 +888,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev, psecuritypriv->PMKIDIndex = 0; } } else if (pPMK->cmd == IW_PMKSA_REMOVE) { - DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n"); intReturn = true; for (j = 0; j < NUM_PMKID_CACHE; j++) { if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { @@ -997,8 +898,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev, } } } else if (pPMK->cmd == IW_PMKSA_FLUSH) { - DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n"); - memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); + memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); psecuritypriv->PMKIDIndex = 0; intReturn = true; } @@ -1028,8 +928,6 @@ static int rtw_wx_get_range(struct net_device *dev, u16 val; int i; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_range. cmd_code =%x\n", info->cmd)); - wrqu->data.length = sizeof(*range); memset(range, 0, sizeof(*range)); @@ -1132,7 +1030,7 @@ static int rtw_wx_set_wap(struct net_device *dev, u8 *dst_bssid, *src_bssid; struct __queue *queue = &(pmlmepriv->scanned_queue); struct wlan_network *pnetwork = NULL; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; + enum ndis_802_11_authentication_mode authmode; rtw_ps_deny(padapter, PS_DENY_JOIN); if (_FAIL == rtw_pwr_wakeup(padapter)) { @@ -1207,8 +1105,6 @@ static int rtw_wx_get_wap(struct net_device *dev, eth_zero_addr(wrqu->ap_addr.sa_data); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n")); - if (((check_fwstate(pmlmepriv, _FW_LINKED)) == true) || ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) || ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true)) { @@ -1225,7 +1121,6 @@ static int rtw_wx_set_mlme(struct net_device *dev, union iwreq_data *wrqu, char *extra) { int ret = 0; - u16 reason; struct adapter *padapter = rtw_netdev_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; @@ -1233,12 +1128,6 @@ static int rtw_wx_set_mlme(struct net_device *dev, if (mlme == NULL) return -1; - DBG_871X("%s\n", __func__); - - reason = mlme->reason_code; - - DBG_871X("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason); - switch (mlme->cmd) { case IW_MLME_DEAUTH: if (!rtw_set_802_11_disassociate(padapter)) @@ -1263,11 +1152,6 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_set_scan\n")); - - #ifdef DBG_IOCTL - DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); - #endif rtw_ps_deny(padapter, PS_DENY_SCAN); if (_FAIL == rtw_pwr_wakeup(padapter)) { @@ -1276,7 +1160,6 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, } if (padapter->bDriverStopped) { - DBG_871X("bDriverStopped =%d\n", padapter->bDriverStopped); ret = -1; goto exit; } @@ -1315,16 +1198,12 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, memcpy(ssid[0].Ssid, req->essid, len); ssid[0].SsidLength = len; - DBG_871X("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len); - spin_lock_bh(&pmlmepriv->lock); _status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0); spin_unlock_bh(&pmlmepriv->lock); - } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { - DBG_871X("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n"); } } else if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE @@ -1335,14 +1214,11 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, char sec_len; int ssid_index = 0; - /* DBG_871X("%s COMBO_SCAN header is recognized\n", __func__); */ - while (len >= 1) { section = *(pos++); len -= 1; switch (section) { case WEXT_CSCAN_SSID_SECTION: - /* DBG_871X("WEXT_CSCAN_SSID_SECTION\n"); */ if (len < 1) { len = 0; break; @@ -1353,8 +1229,6 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, if (sec_len > 0 && sec_len <= len) { ssid[ssid_index].SsidLength = sec_len; memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); - /* DBG_871X("%s COMBO_SCAN with specific ssid:%s, %d\n", __func__ */ - /* , ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength); */ ssid_index++; } @@ -1363,31 +1237,23 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, case WEXT_CSCAN_CHANNEL_SECTION: - /* DBG_871X("WEXT_CSCAN_CHANNEL_SECTION\n"); */ pos += 1; len -= 1; break; case WEXT_CSCAN_ACTV_DWELL_SECTION: - /* DBG_871X("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); */ pos += 2; len -= 2; break; case WEXT_CSCAN_PASV_DWELL_SECTION: - /* DBG_871X("WEXT_CSCAN_PASV_DWELL_SECTION\n"); */ pos += 2; len -= 2; break; case WEXT_CSCAN_HOME_DWELL_SECTION: - /* DBG_871X("WEXT_CSCAN_HOME_DWELL_SECTION\n"); */ pos += 2; len -= 2; break; case WEXT_CSCAN_TYPE_SECTION: - /* DBG_871X("WEXT_CSCAN_TYPE_SECTION\n"); */ pos += 1; len -= 1; break; default: - /* DBG_871X("Unknown CSCAN section %c\n", section); */ len = 0; /* stop parsing */ } - /* DBG_871X("len:%d\n", len); */ - } /* jeff: it has still some scan parameter to parse, we only do this now... */ @@ -1404,10 +1270,6 @@ exit: rtw_ps_deny_cancel(padapter, PS_DENY_SCAN); - #ifdef DBG_IOCTL - DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret); - #endif - return ret; } @@ -1422,14 +1284,7 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, char *ev = extra; char *stop = ev + wrqu->data.length; u32 ret = 0; - sint wait_status; - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan\n")); - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n")); - - #ifdef DBG_IOCTL - DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); - #endif + signed int wait_status; if (adapter_to_pwrctl(padapter)->brfoffbyhw && padapter->bDriverStopped) { ret = -EINVAL; @@ -1476,10 +1331,6 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, exit: - #ifdef DBG_IOCTL - DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret); - #endif - return ret; } @@ -1498,19 +1349,12 @@ static int rtw_wx_set_essid(struct net_device *dev, struct __queue *queue = &pmlmepriv->scanned_queue; struct list_head *phead; struct wlan_network *pnetwork = NULL; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; + enum ndis_802_11_authentication_mode authmode; struct ndis_802_11_ssid ndis_ssid; u8 *dst_ssid, *src_ssid; uint ret = 0, len; - #ifdef DBG_IOCTL - DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); - #endif - - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, - ("+rtw_wx_set_essid: fw_state = 0x%08x\n", get_fwstate(pmlmepriv))); - rtw_ps_deny(padapter, PS_DENY_JOIN); if (_FAIL == rtw_pwr_wakeup(padapter)) { ret = -1; @@ -1533,30 +1377,21 @@ static int rtw_wx_set_essid(struct net_device *dev, } authmode = padapter->securitypriv.ndisauthtype; - DBG_871X("=>%s\n", __func__); if (wrqu->essid.flags && wrqu->essid.length) { len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE; - if (wrqu->essid.length != 33) - DBG_871X("ssid =%s, len =%d\n", extra, wrqu->essid.length); - 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; - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid)); spin_lock_bh(&queue->lock); phead = get_list_head(queue); pmlmepriv->pscanned = get_next(phead); while (1) { - if (phead == pmlmepriv->pscanned) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_warning_, - ("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n")); - + if (phead == pmlmepriv->pscanned) break; - } pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); @@ -1564,15 +1399,8 @@ static int rtw_wx_set_essid(struct net_device *dev, dst_ssid = pnetwork->network.Ssid.Ssid; - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, - ("rtw_wx_set_essid: dst_ssid =%s\n", - pnetwork->network.Ssid.Ssid)); - if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) && (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, - ("rtw_wx_set_essid: find match, set infra mode\n")); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) continue; @@ -1588,8 +1416,6 @@ static int rtw_wx_set_essid(struct net_device *dev, } } spin_unlock_bh(&queue->lock); - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, - ("set ssid: set_802_11_auth. mode =%d\n", authmode)); rtw_set_802_11_authentication_mode(padapter, authmode); /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) { @@ -1602,12 +1428,6 @@ exit: rtw_ps_deny_cancel(padapter, PS_DENY_JOIN); - DBG_871X("<=%s, ret %d\n", __func__, ret); - - #ifdef DBG_IOCTL - DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret); - #endif - return ret; } @@ -1620,8 +1440,6 @@ static int rtw_wx_get_essid(struct net_device *dev, struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_essid\n")); - if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { len = pcur_bss->Ssid.SsidLength; @@ -1652,9 +1470,6 @@ static int rtw_wx_set_rate(struct net_device *dev, u32 ratevalue = 0; u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff}; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n")); - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed)); - if (target_rate == -1) { ratevalue = 11; goto set_rate; @@ -1713,14 +1528,11 @@ set_rate: } else { datarates[i] = 0xff; } - - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("datarate_inx =%d\n", datarates[i])); } - if (rtw_setdatarate_cmd(padapter, datarates) != _SUCCESS) { - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("rtw_wx_set_rate Fail!!!\n")); + if (rtw_setdatarate_cmd(padapter, datarates) != _SUCCESS) ret = -1; - } + return ret; } @@ -1757,8 +1569,6 @@ static int rtw_wx_set_rts(struct net_device *dev, padapter->registrypriv.rts_thresh = wrqu->rts.value; } - DBG_871X("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); - return 0; } @@ -1768,8 +1578,6 @@ static int rtw_wx_get_rts(struct net_device *dev, { struct adapter *padapter = rtw_netdev_priv(dev); - DBG_871X("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); - wrqu->rts.value = padapter->registrypriv.rts_thresh; wrqu->rts.fixed = 0; /* no auto select */ /* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */ @@ -1793,8 +1601,6 @@ static int rtw_wx_set_frag(struct net_device *dev, padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1; } - DBG_871X("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); - return 0; } @@ -1805,8 +1611,6 @@ static int rtw_wx_get_frag(struct net_device *dev, { struct adapter *padapter = rtw_netdev_priv(dev); - DBG_871X("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); - wrqu->frag.value = padapter->xmitpriv.frag_len; wrqu->frag.fixed = 0; /* no auto select */ /* wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); */ @@ -1836,19 +1640,17 @@ static int rtw_wx_set_enc(struct net_device *dev, u32 key, ret = 0; u32 keyindex_provided; struct ndis_802_11_wep wep; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; + enum ndis_802_11_authentication_mode authmode; struct iw_point *erq = &(wrqu->encoding); struct adapter *padapter = rtw_netdev_priv(dev); struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - DBG_871X("+rtw_wx_set_enc, flags = 0x%x\n", erq->flags); memset(&wep, 0, sizeof(struct ndis_802_11_wep)); key = erq->flags & IW_ENCODE_INDEX; if (erq->flags & IW_ENCODE_DISABLED) { - DBG_871X("EncryptionDisabled\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; @@ -1867,12 +1669,10 @@ static int rtw_wx_set_enc(struct net_device *dev, } else { keyindex_provided = 0; key = padapter->securitypriv.dot11PrivacyKeyIndex; - DBG_871X("rtw_wx_set_enc, key =%d\n", key); } /* set authentication mode */ if (erq->flags & IW_ENCODE_OPEN) { - DBG_871X("rtw_wx_set_enc():IW_ENCODE_OPEN\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; @@ -1882,7 +1682,6 @@ static int rtw_wx_set_enc(struct net_device *dev, authmode = Ndis802_11AuthModeOpen; padapter->securitypriv.ndisauthtype = authmode; } else if (erq->flags & IW_ENCODE_RESTRICTED) { - DBG_871X("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n"); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; @@ -1892,8 +1691,6 @@ static int rtw_wx_set_enc(struct net_device *dev, authmode = Ndis802_11AuthModeShared; padapter->securitypriv.ndisauthtype = authmode; } else { - DBG_871X("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags); - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; @@ -1913,8 +1710,6 @@ static int rtw_wx_set_enc(struct net_device *dev, if (keyindex_provided == 1) { /* set key_id only, no given KeyMaterial(erq->length == 0). */ padapter->securitypriv.dot11PrivacyKeyIndex = key; - DBG_871X("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]); - switch (padapter->securitypriv.dot11DefKeylen[key]) { case 5: padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; @@ -2103,7 +1898,6 @@ static int rtw_wx_set_auth(struct net_device *dev, if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { LeaveAllPowerSaveMode(padapter); rtw_disassoc_cmd(padapter, 500, false); - DBG_871X("%s...call rtw_indicate_disconnect\n ", __func__); rtw_indicate_disconnect(padapter); rtw_free_assoc_resources(padapter, 1); } @@ -2269,11 +2063,9 @@ static int rtw_wx_read32(struct net_device *dev, sprintf(extra, "0x%08X", data32); break; default: - DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__); ret = -EINVAL; goto exit; } - DBG_871X(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra); exit: kfree(ptmp); @@ -2300,18 +2092,14 @@ static int rtw_wx_write32(struct net_device *dev, switch (bytes) { case 1: rtw_write8(padapter, addr, (u8)data32); - DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32); break; case 2: rtw_write16(padapter, addr, (u16)data32); - DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32); break; case 4: rtw_write32(padapter, addr, data32); - DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32); break; default: - DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__); return -EINVAL; } @@ -2350,7 +2138,6 @@ static int rtw_wx_write_rf(struct net_device *dev, path = *(u32 *)extra; addr = *((u32 *)extra + 1); data32 = *((u32 *)extra + 2); -/* DBG_871X("%s: path =%d addr = 0x%02x data = 0x%05x\n", __func__, path, addr, data32); */ rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32); return 0; @@ -2368,8 +2155,6 @@ static int dummy(struct net_device *dev, struct iw_request_info *a, /* struct adapter *padapter = rtw_netdev_priv(dev); */ /* struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); */ - /* DBG_871X("cmd_code =%x, fwstate = 0x%x\n", a->cmd, get_fwstate(pmlmepriv)); */ - return -1; } @@ -2381,9 +2166,7 @@ static int rtw_wx_set_channel_plan(struct net_device *dev, struct adapter *padapter = rtw_netdev_priv(dev); u8 channel_plan_req = (u8)(*((int *)wrqu)); - if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1, 1)) - DBG_871X("%s set channel_plan = 0x%02X\n", __func__, channel_plan_req); - else + if (rtw_set_chplan_cmd(padapter, channel_plan_req, 1, 1) != _SUCCESS) return -EPERM; return 0; @@ -2441,8 +2224,6 @@ static int rtw_get_ap_info(struct net_device *dev, struct __queue *queue = &(pmlmepriv->scanned_queue); struct iw_point *pdata = &wrqu->data; - DBG_871X("+rtw_get_aplist_info\n"); - if ((padapter->bDriverStopped) || (pdata == NULL)) { ret = -EINVAL; goto exit; @@ -2481,14 +2262,12 @@ static int rtw_get_ap_info(struct net_device *dev, pnetwork = container_of(plist, struct wlan_network, list); if (!mac_pton(data, bssid)) { - DBG_871X("Invalid BSSID '%s'.\n", (u8 *)data); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); return -EINVAL; } if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) { /* BSSID match, then check if supporting wpa/wpa2 */ - DBG_871X("BSSID:%pM\n", MAC_ARG(bssid)); pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); if (pbuf && (wpa_ielen > 0)) { @@ -2538,12 +2317,8 @@ static int rtw_set_pid(struct net_device *dev, } selector = *pdata; - if (selector < 3 && selector >= 0) { + if (selector < 3 && selector >= 0) padapter->pid[selector] = *(pdata+1); - DBG_871X("%s set pid[%d]=%d\n", __func__, selector, padapter->pid[selector]); - } - else - DBG_871X("%s selector %d error\n", __func__, selector); exit: @@ -2573,8 +2348,6 @@ static int rtw_wps_start(struct net_device *dev, if (u32wps_start == 0) u32wps_start = *extra; - DBG_871X("[%s] wps_start = %d\n", __func__, u32wps_start); - exit: return ret; @@ -2625,7 +2398,6 @@ static int rtw_rereg_nd_name(struct net_device *dev, rereg_priv->old_ifname[IFNAMSIZ-1] = 0; } - /* DBG_871X("%s wrqu->data.length:%d\n", __func__, wrqu->data.length); */ if (wrqu->data.length > IFNAMSIZ) return -EFAULT; @@ -2635,21 +2407,18 @@ static int rtw_rereg_nd_name(struct net_device *dev, if (0 == strcmp(rereg_priv->old_ifname, new_ifname)) return ret; - DBG_871X("%s new_ifname:%s\n", __func__, new_ifname); - if (0 != (ret = rtw_change_ifname(padapter, new_ifname))) + ret = rtw_change_ifname(padapter, new_ifname); + if (ret != 0) goto exit; strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ); rereg_priv->old_ifname[IFNAMSIZ-1] = 0; if (!memcmp(new_ifname, "disable%d", 9)) { - - DBG_871X("%s disable\n", __func__); /* free network queue for Android's timming issue */ rtw_free_network_queue(padapter, true); /* the interface is being "disabled", we can do deeper IPS */ - /* rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv); */ /* rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL); */ } exit: @@ -2664,14 +2433,9 @@ static int rtw_dbg_port(struct net_device *dev, u8 major_cmd, minor_cmd; u16 arg; u32 extra_arg, *pdata, val32; - struct sta_info *psta; struct adapter *padapter = rtw_netdev_priv(dev); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_network *cur_network = &(pmlmepriv->cur_network); - struct sta_priv *pstapriv = &padapter->stapriv; - pdata = (u32 *)&wrqu->data; @@ -2686,13 +2450,10 @@ static int rtw_dbg_port(struct net_device *dev, case 0x70:/* read_reg */ switch (minor_cmd) { case 1: - DBG_871X("rtw_read8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); break; case 2: - DBG_871X("rtw_read16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg)); break; case 4: - DBG_871X("rtw_read32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg)); break; } break; @@ -2700,31 +2461,24 @@ static int rtw_dbg_port(struct net_device *dev, switch (minor_cmd) { case 1: rtw_write8(padapter, arg, extra_arg); - DBG_871X("rtw_write8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); break; case 2: rtw_write16(padapter, arg, extra_arg); - DBG_871X("rtw_write16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg)); break; case 4: rtw_write32(padapter, arg, extra_arg); - DBG_871X("rtw_write32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg)); break; } break; case 0x72:/* read_bb */ - DBG_871X("read_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); break; case 0x73:/* write_bb */ rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg); - DBG_871X("write_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); break; case 0x74:/* read_rf */ - DBG_871X("read RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); break; case 0x75:/* write_rf */ rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg); - DBG_871X("write RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); break; case 0x76: @@ -2751,8 +2505,6 @@ static int rtw_dbg_port(struct net_device *dev, u8 sign = minor_cmd; u16 write_value = 0; - DBG_871X("%s set RESP_TXAGC to %s %u\n", __func__, sign?"minus":"plus", value); - if (sign) value = value | 0x10; @@ -2767,124 +2519,33 @@ static int rtw_dbg_port(struct net_device *dev, case 0x7F: switch (minor_cmd) { case 0x0: - DBG_871X("fwstate = 0x%x\n", get_fwstate(pmlmepriv)); break; case 0x01: - DBG_871X("minor_cmd 0x%x\n", minor_cmd); break; case 0x02: - DBG_871X("pmlmeinfo->state = 0x%x\n", pmlmeinfo->state); - DBG_871X("DrvBcnEarly =%d\n", pmlmeext->DrvBcnEarly); - DBG_871X("DrvBcnTimeOut =%d\n", pmlmeext->DrvBcnTimeOut); break; case 0x03: - DBG_871X("qos_option =%d\n", pmlmepriv->qospriv.qos_option); - DBG_871X("ht_option =%d\n", pmlmepriv->htpriv.ht_option); break; case 0x04: - DBG_871X("cur_ch =%d\n", pmlmeext->cur_channel); - DBG_871X("cur_bw =%d\n", pmlmeext->cur_bwmode); - DBG_871X("cur_ch_off =%d\n", pmlmeext->cur_ch_offset); - - DBG_871X("oper_ch =%d\n", rtw_get_oper_ch(padapter)); - DBG_871X("oper_bw =%d\n", rtw_get_oper_bw(padapter)); - DBG_871X("oper_ch_offset =%d\n", rtw_get_oper_choffset(padapter)); break; case 0x05: - psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); - if (psta) { - int i; - struct recv_reorder_ctrl *preorder_ctrl; - - DBG_871X("SSID =%s\n", cur_network->network.Ssid.Ssid); - DBG_871X("sta's macaddr:%pM\n", MAC_ARG(psta->hwaddr)); - DBG_871X("cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); - DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); - DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); - DBG_871X("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); - DBG_871X("bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); - DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); - DBG_871X("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); - - for (i = 0; i < 16; i++) { - preorder_ctrl = &psta->recvreorder_ctrl[i]; - if (preorder_ctrl->enable) - DBG_871X("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq); - } - - } else { - DBG_871X("can't get sta's macaddr, cur_network's macaddr:%pM\n", MAC_ARG(cur_network->network.MacAddress)); - } break; case 0x06: { u32 ODMFlag; rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); - DBG_871X("(B)DMFlag = 0x%x, arg = 0x%x\n", ODMFlag, arg); ODMFlag = (u32)(0x0f&arg); - DBG_871X("(A)DMFlag = 0x%x\n", ODMFlag); rtw_hal_set_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); } break; case 0x07: - DBG_871X("bSurpriseRemoved =%d, bDriverStopped =%d\n", - padapter->bSurpriseRemoved, padapter->bDriverStopped); break; case 0x08: { - DBG_871X("minor_cmd 0x%x\n", minor_cmd); } break; case 0x09: - { - int i, j; - struct list_head *plist, *phead; - struct recv_reorder_ctrl *preorder_ctrl; - - DBG_871X("sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); - - spin_lock_bh(&pstapriv->sta_hash_lock); - - for (i = 0; i < NUM_STA; i++) { - phead = &(pstapriv->sta_hash[i]); - plist = get_next(phead); - - while (phead != plist) { - psta = container_of(plist, struct sta_info, hash_list); - - plist = get_next(plist); - - if (extra_arg == psta->aid) { - DBG_871X("sta's macaddr:%pM\n", MAC_ARG(psta->hwaddr)); - DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); - DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); - DBG_871X("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); - DBG_871X("bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); - DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); - DBG_871X("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); - DBG_871X("capability = 0x%x\n", psta->capability); - DBG_871X("flags = 0x%x\n", psta->flags); - DBG_871X("wpa_psk = 0x%x\n", psta->wpa_psk); - DBG_871X("wpa2_group_cipher = 0x%x\n", psta->wpa2_group_cipher); - DBG_871X("wpa2_pairwise_cipher = 0x%x\n", psta->wpa2_pairwise_cipher); - DBG_871X("qos_info = 0x%x\n", psta->qos_info); - DBG_871X("dot118021XPrivacy = 0x%x\n", psta->dot118021XPrivacy); - - - - for (j = 0; j < 16; j++) { - preorder_ctrl = &psta->recvreorder_ctrl[j]; - if (preorder_ctrl->enable) - DBG_871X("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq); - } - } - } - } - - spin_unlock_bh(&pstapriv->sta_hash_lock); - - } break; case 0x0a: { @@ -2895,10 +2556,8 @@ static int rtw_dbg_port(struct net_device *dev, break; case 0x0b: /* Enable = 1, Disable = 0 driver control vrtl_carrier_sense. */ if (arg == 0) { - DBG_871X("disable driver ctrl vcs\n"); padapter->driver_vcs_en = 0; } else if (arg == 1) { - DBG_871X("enable driver ctrl vcs = %d\n", extra_arg); padapter->driver_vcs_en = 1; if (extra_arg > 2) @@ -2909,25 +2568,19 @@ static int rtw_dbg_port(struct net_device *dev, break; case 0x0c:/* dump rx/tx packet */ { - if (arg == 0) { - DBG_871X("dump rx packet (%d)\n", extra_arg); + if (arg == 0) /* pHalData->bDumpRxPkt =extra_arg; */ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg)); - } else if (arg == 1) { - DBG_871X("dump tx packet (%d)\n", extra_arg); + else if (arg == 1) rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg)); - } } break; case 0x0e: { if (arg == 0) { - DBG_871X("disable driver ctrl rx_ampdu_factor\n"); padapter->driver_rx_ampdu_factor = 0xFF; } else if (arg == 1) { - DBG_871X("enable driver ctrl rx_ampdu_factor = %d\n", extra_arg); - if ((extra_arg & 0x03) > 0x03) padapter->driver_rx_ampdu_factor = 0xFF; else @@ -2937,7 +2590,7 @@ static int rtw_dbg_port(struct net_device *dev, break; case 0x10:/* driver version display */ - dump_drv_version(RTW_DBGDUMP); + netdev_dbg(dev, "%s %s\n", "rtl8723bs", DRIVERVERSION); break; case 0x11:/* dump linked status */ { @@ -2949,35 +2602,27 @@ static int rtw_dbg_port(struct net_device *dev, struct registry_priv *pregpriv = &padapter->registrypriv; /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */ /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ - if (extra_arg == 0 || extra_arg == 1 || extra_arg == 2 || extra_arg == 3) { + if (extra_arg == 0 || extra_arg == 1 || + extra_arg == 2 || extra_arg == 3) pregpriv->rx_stbc = extra_arg; - DBG_871X("set rx_stbc =%d\n", pregpriv->rx_stbc); - } else - DBG_871X("get rx_stbc =%d\n", pregpriv->rx_stbc); - } break; case 0x13: /* set ampdu_enable */ { struct registry_priv *pregpriv = &padapter->registrypriv; /* 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */ - if (extra_arg < 3) { + if (extra_arg < 3) pregpriv->ampdu_enable = extra_arg; - DBG_871X("set ampdu_enable =%d\n", pregpriv->ampdu_enable); - } else - DBG_871X("get ampdu_enable =%d\n", pregpriv->ampdu_enable); - } break; case 0x14: { - DBG_871X("minor_cmd 0x%x\n", minor_cmd); } break; case 0x16: { if (arg == 0xff) { - rtw_odm_dbg_comp_msg(RTW_DBGDUMP, padapter); + rtw_odm_dbg_comp_msg(padapter); } else { u64 dbg_comp = (u64)extra_arg; rtw_odm_dbg_comp_set(padapter, dbg_comp); @@ -3006,13 +2651,10 @@ static int rtw_dbg_port(struct net_device *dev, /* extra_arg : */ /* BIT0: Enable VHT LDPC Rx, BIT1: Enable VHT LDPC Tx, */ /* BIT4: Enable HT LDPC Rx, BIT5: Enable HT LDPC Tx */ - if (arg == 0) { - DBG_871X("driver disable LDPC\n"); + if (arg == 0) pregistrypriv->ldpc_cap = 0x00; - } else if (arg == 1) { - DBG_871X("driver set LDPC cap = 0x%x\n", extra_arg); + else if (arg == 1) pregistrypriv->ldpc_cap = (u8)(extra_arg&0x33); - } } break; case 0x1a: @@ -3021,13 +2663,10 @@ static int rtw_dbg_port(struct net_device *dev, /* extra_arg : */ /* BIT0: Enable VHT STBC Rx, BIT1: Enable VHT STBC Tx, */ /* BIT4: Enable HT STBC Rx, BIT5: Enable HT STBC Tx */ - if (arg == 0) { - DBG_871X("driver disable STBC\n"); + if (arg == 0) pregistrypriv->stbc_cap = 0x00; - } else if (arg == 1) { - DBG_871X("driver set STBC cap = 0x%x\n", extra_arg); + else if (arg == 1) pregistrypriv->stbc_cap = (u8)(extra_arg&0x33); - } } break; case 0x1b: @@ -3035,7 +2674,6 @@ static int rtw_dbg_port(struct net_device *dev, struct registry_priv *pregistrypriv = &padapter->registrypriv; if (arg == 0) { - DBG_871X("disable driver ctrl max_rx_rate, reset to default_rate_set\n"); init_mlme_default_rate_set(padapter); pregistrypriv->ht_enable = (u8)rtw_ht_enable; } else if (arg == 1) { @@ -3043,8 +2681,6 @@ static int rtw_dbg_port(struct net_device *dev, int i; u8 max_rx_rate; - DBG_871X("enable driver ctrl max_rx_rate = 0x%x\n", extra_arg); - max_rx_rate = (u8)extra_arg; if (max_rx_rate < 0xc) { /* max_rx_rate < MSC0 -> B or G -> disable HT */ @@ -3069,12 +2705,9 @@ static int rtw_dbg_port(struct net_device *dev, case 0x1c: /* enable/disable driver control AMPDU Density for peer sta's rx */ { if (arg == 0) { - DBG_871X("disable driver ctrl ampdu density\n"); padapter->driver_ampdu_spacing = 0xFF; } else if (arg == 1) { - DBG_871X("enable driver ctrl ampdu density = %d\n", extra_arg); - if (extra_arg > 0x07) padapter->driver_ampdu_spacing = 0xFF; else @@ -3082,26 +2715,8 @@ static int rtw_dbg_port(struct net_device *dev, } } break; -#ifdef CONFIG_BACKGROUND_NOISE_MONITOR - case 0x1e: - { - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; - u8 chan = rtw_get_oper_ch(padapter); - DBG_871X("===========================================\n"); - ODM_InbandNoise_Monitor(pDM_Odm, true, 0x1e, 100); - DBG_871X("channel(%d), noise_a = %d, noise_b = %d , noise_all:%d\n", - chan, pDM_Odm->noise_level.noise[ODM_RF_PATH_A], - pDM_Odm->noise_level.noise[ODM_RF_PATH_B], - pDM_Odm->noise_level.noise_all); - DBG_871X("===========================================\n"); - - } - break; -#endif case 0x23: { - DBG_871X("turn %s the bNotifyChannelChange Variable\n", (extra_arg == 1)?"on":"off"); padapter->bNotifyChannelChange = extra_arg; break; } @@ -3109,51 +2724,10 @@ static int rtw_dbg_port(struct net_device *dev, { break; } -#ifdef CONFIG_GPIO_API - case 0x25: /* Get GPIO register */ - { - /* - * dbg 0x7f250000 [gpio_num], Get gpio value, gpio_num:0~7 - */ - - int value; - DBG_871X("Read GPIO Value extra_arg = %d\n", extra_arg); - value = rtw_get_gpio(dev, extra_arg); - DBG_871X("Read GPIO Value = %d\n", value); - break; - } - case 0x26: /* Set GPIO direction */ - { - - /* dbg 0x7f26000x [y], Set gpio direction, - * x: gpio_num, 4~7 y: indicate direction, 0~1 - */ - - int value; - DBG_871X("Set GPIO Direction! arg = %d , extra_arg =%d\n", arg, extra_arg); - value = rtw_config_gpio(dev, arg, extra_arg); - DBG_871X("Set GPIO Direction %s\n", (value == -1) ? "Fail!!!" : "Success"); - break; - } - case 0x27: /* Set GPIO output direction value */ - { - /* - * dbg 0x7f27000x [y], Set gpio output direction value, - * x: gpio_num, 4~7 y: indicate direction, 0~1 - */ - - int value; - DBG_871X("Set GPIO Value! arg = %d , extra_arg =%d\n", arg, extra_arg); - value = rtw_set_gpio_output_value(dev, arg, extra_arg); - DBG_871X("Set GPIO Value %s\n", (value == -1) ? "Fail!!!" : "Success"); - break; - } -#endif case 0xaa: { if ((extra_arg & 0x7F) > 0x3F) extra_arg = 0xFF; - DBG_871X("chang data rate to :0x%02x\n", extra_arg); padapter->fix_rate = extra_arg; } break; @@ -3174,14 +2748,6 @@ static int rtw_dbg_port(struct net_device *dev, if (0xf == extra_arg) { rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag); - DBG_871X(" === DMFlag(0x%08x) ===\n", odm_flag); - DBG_871X("extra_arg = 0 - disable all dynamic func\n"); - DBG_871X("extra_arg = 1 - disable DIG- BIT(0)\n"); - DBG_871X("extra_arg = 2 - disable High power - BIT(1)\n"); - DBG_871X("extra_arg = 3 - disable tx power tracking - BIT(2)\n"); - DBG_871X("extra_arg = 4 - disable BT coexistence - BIT(3)\n"); - DBG_871X("extra_arg = 5 - disable antenna diversity - BIT(4)\n"); - DBG_871X("extra_arg = 6 - enable all dynamic func\n"); } else { /*extra_arg = 0 - disable all dynamic func extra_arg = 1 - disable DIG @@ -3190,54 +2756,23 @@ static int rtw_dbg_port(struct net_device *dev, */ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg)); rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag); - DBG_871X(" === DMFlag(0x%08x) ===\n", odm_flag); } } break; case 0xfd: rtw_write8(padapter, 0xc50, arg); - DBG_871X("wr(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50)); rtw_write8(padapter, 0xc58, arg); - DBG_871X("wr(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58)); break; case 0xfe: - DBG_871X("rd(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50)); - DBG_871X("rd(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58)); break; case 0xff: { - DBG_871X("dbg(0x210) = 0x%x\n", rtw_read32(padapter, 0x210)); - DBG_871X("dbg(0x608) = 0x%x\n", rtw_read32(padapter, 0x608)); - DBG_871X("dbg(0x280) = 0x%x\n", rtw_read32(padapter, 0x280)); - DBG_871X("dbg(0x284) = 0x%x\n", rtw_read32(padapter, 0x284)); - DBG_871X("dbg(0x288) = 0x%x\n", rtw_read32(padapter, 0x288)); - - DBG_871X("dbg(0x664) = 0x%x\n", rtw_read32(padapter, 0x664)); - - - DBG_871X("\n"); - - DBG_871X("dbg(0x430) = 0x%x\n", rtw_read32(padapter, 0x430)); - DBG_871X("dbg(0x438) = 0x%x\n", rtw_read32(padapter, 0x438)); - - DBG_871X("dbg(0x440) = 0x%x\n", rtw_read32(padapter, 0x440)); - - DBG_871X("dbg(0x458) = 0x%x\n", rtw_read32(padapter, 0x458)); - - DBG_871X("dbg(0x484) = 0x%x\n", rtw_read32(padapter, 0x484)); - DBG_871X("dbg(0x488) = 0x%x\n", rtw_read32(padapter, 0x488)); - - DBG_871X("dbg(0x444) = 0x%x\n", rtw_read32(padapter, 0x444)); - DBG_871X("dbg(0x448) = 0x%x\n", rtw_read32(padapter, 0x448)); - DBG_871X("dbg(0x44c) = 0x%x\n", rtw_read32(padapter, 0x44c)); - DBG_871X("dbg(0x450) = 0x%x\n", rtw_read32(padapter, 0x450)); } break; } break; default: - DBG_871X("error dbg cmd!\n"); break; } @@ -3269,8 +2804,6 @@ static int wpa_set_param(struct net_device *dev, u8 name, u32 value) break; } - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("wpa_set_param:padapter->securitypriv.ndisauthtype =%d\n", padapter->securitypriv.ndisauthtype)); - break; case IEEE_PARAM_TKIP_COUNTERMEASURES: @@ -3314,7 +2847,6 @@ static int wpa_set_param(struct net_device *dev, u8 name, u32 value) case IEEE_PARAM_WPAX_SELECT: /* added for WPA2 mixed mode */ - /* DBG_871X(KERN_WARNING "------------------------>wpax value = %x\n", value); */ /* spin_lock_irqsave(&ieee->wpax_suitlist_lock, flags); ieee->wpax_type_set = 1; @@ -3407,7 +2939,6 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) break; default: - DBG_871X("Unknown WPA supplicant request: %d\n", param->cmd); ret = -EOPNOTSUPP; break; @@ -3433,8 +2964,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, struct security_priv *psecuritypriv = &(padapter->securitypriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("%s\n", __func__); - param->u.crypt.err = 0; param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; @@ -3454,11 +2983,9 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, } } else { psta = rtw_get_stainfo(pstapriv, param->sta_addr); - if (!psta) { + if (!psta) /* ret = -EINVAL; */ - DBG_871X("rtw_set_encryption(), sta has already been removed or never been added\n"); goto exit; - } } if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) { @@ -3469,20 +2996,14 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; - DBG_871X("clear default encryption keys, keyid =%d\n", param->u.crypt.idx); - goto exit; } if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) { - DBG_871X("r871x_set_encryption, crypt.alg = WEP\n"); - wep_key_idx = param->u.crypt.idx; wep_key_len = param->u.crypt.key_len; - DBG_871X("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len); - if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) { ret = -EINVAL; goto exit; @@ -3493,10 +3014,8 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, wep_key_len = wep_key_len <= 5 ? 5 : 13; wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); pwep = kzalloc(wep_total_len, GFP_KERNEL); - if (pwep == NULL) { - DBG_871X(" r871x_set_encryption: pwep allocate fail !!!\n"); + if (!pwep) goto exit; - } pwep->KeyLength = wep_key_len; pwep->Length = wep_total_len; @@ -3508,8 +3027,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); if (param->u.crypt.set_tx) { - DBG_871X("wep, set_tx = 1\n"); - psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; @@ -3529,8 +3046,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 1); } else { - DBG_871X("wep, set_tx = 0\n"); - /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to cam */ @@ -3549,8 +3064,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */ if (param->u.crypt.set_tx == 1) { if (strcmp(param->u.crypt.alg, "WEP") == 0) { - DBG_871X("%s, set group_key, WEP\n", __func__); - memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); psecuritypriv->dot118021XGrpPrivacy = _WEP40_; @@ -3558,8 +3071,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, psecuritypriv->dot118021XGrpPrivacy = _WEP104_; } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - DBG_871X("%s, set group_key, TKIP\n", __func__); - psecuritypriv->dot118021XGrpPrivacy = _TKIP_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); @@ -3573,14 +3084,10 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { - DBG_871X("%s, set group_key, CCMP\n", __func__); - psecuritypriv->dot118021XGrpPrivacy = _AES_; memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); } else { - DBG_871X("%s, set group_key, none\n", __func__); - psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; } @@ -3609,14 +3116,10 @@ static int rtw_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, "WEP") == 0) { - DBG_871X("%s, set pairwise key, WEP\n", __func__); - psta->dot118021XPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) psta->dot118021XPrivacy = _WEP104_; } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - DBG_871X("%s, set pairwise key, TKIP\n", __func__); - psta->dot118021XPrivacy = _TKIP_; /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ @@ -3628,12 +3131,8 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { - DBG_871X("%s, set pairwise key, CCMP\n", __func__); - psta->dot118021XPrivacy = _AES_; } else { - DBG_871X("%s, set pairwise key, none\n", __func__); - psta->dot118021XPrivacy = _NO_PRIVACY_; } @@ -3700,9 +3199,6 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int struct sta_priv *pstapriv = &padapter->stapriv; unsigned char *pbuf = param->u.bcn_ie.buf; - - DBG_871X("%s, len =%d\n", __func__, len); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) return -EINVAL; @@ -3730,8 +3226,6 @@ static void rtw_hostapd_sta_flush(struct net_device *dev) struct adapter *padapter = rtw_netdev_priv(dev); /* struct sta_priv *pstapriv = &padapter->stapriv; */ - DBG_871X("%s\n", __func__); - flush_all_cam_entry(padapter); /* clear CAM */ rtw_sta_flush(padapter); @@ -3745,8 +3239,6 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("rtw_add_sta(aid =%d) =%pM\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr)); - if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3760,7 +3252,6 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) psta = rtw_get_stainfo(pstapriv, param->sta_addr); if (psta) { - DBG_871X("rtw_add_sta(), free has been added psta =%p\n", psta); spin_lock_bh(&(pstapriv->sta_hash_lock)); rtw_free_stainfo(padapter, psta); spin_unlock_bh(&(pstapriv->sta_hash_lock)); @@ -3773,8 +3264,6 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) if (psta) { int flags = param->u.add_sta.flags; - /* DBG_871X("rtw_add_sta(), init sta's variables, psta =%p\n", psta); */ - psta->aid = param->u.add_sta.aid;/* aid = 1~2007 */ memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16); @@ -3820,8 +3309,6 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("rtw_del_sta =%pM\n", MAC_ARG(param->sta_addr)); - if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3835,8 +3322,6 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) if (psta) { u8 updated = false; - /* DBG_871X("free psta =%p, aid =%d\n", psta, psta->aid); */ - spin_lock_bh(&pstapriv->asoc_list_lock); if (list_empty(&psta->asoc_list) == false) { list_del_init(&psta->asoc_list); @@ -3850,13 +3335,8 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) psta = NULL; - } else { - DBG_871X("rtw_del_sta(), sta has already been removed or never been added\n"); - - /* ret = -1; */ } - return ret; } @@ -3871,8 +3351,6 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param; struct sta_data *psta_data = (struct sta_data *)param_ex->data; - DBG_871X("rtw_ioctl_get_sta_info, sta_addr: %pM\n", MAC_ARG(param_ex->sta_addr)); - if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3932,8 +3410,6 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("rtw_get_sta_wpaie, sta_addr: %pM\n", MAC_ARG(param->sta_addr)); - if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3956,9 +3432,6 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) param->u.wpa_ie.len = copy_len; memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len); - } else { - /* ret = -1; */ - DBG_871X("sta's wpa_ie is NONE\n"); } } else { ret = -1; @@ -3977,8 +3450,6 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); int ie_len; - DBG_871X("%s, len =%d\n", __func__, len); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) return -EINVAL; @@ -3991,10 +3462,8 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, if (ie_len > 0) { pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len); pmlmepriv->wps_beacon_ie_len = ie_len; - if (pmlmepriv->wps_beacon_ie == NULL) { - DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); + if (!pmlmepriv->wps_beacon_ie) return -EINVAL; - } memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len); @@ -4015,8 +3484,6 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); int ie_len; - DBG_871X("%s, len =%d\n", __func__, len); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) return -EINVAL; @@ -4029,10 +3496,9 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par if (ie_len > 0) { pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len); pmlmepriv->wps_probe_resp_ie_len = ie_len; - if (pmlmepriv->wps_probe_resp_ie == NULL) { - DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); + if (!pmlmepriv->wps_probe_resp_ie) return -EINVAL; - } + memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len); } @@ -4048,8 +3514,6 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); int ie_len; - DBG_871X("%s, len =%d\n", __func__, len); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) return -EINVAL; @@ -4062,10 +3526,8 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par if (ie_len > 0) { pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len); pmlmepriv->wps_assoc_resp_ie_len = ie_len; - if (pmlmepriv->wps_assoc_resp_ie == NULL) { - DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); + if (!pmlmepriv->wps_assoc_resp_ie) return -EINVAL; - } memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len); } @@ -4085,7 +3547,7 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int ie_len; u8 *ssid_ie; char ssid[NDIS_802_11_LENGTH_SSID + 1]; - sint ssid_len; + signed int ssid_len; u8 ignore_broadcast_ssid; if (check_fwstate(mlmepriv, WIFI_AP_STATE) != true) @@ -4106,26 +3568,12 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, memcpy(ssid, ssid_ie+2, ssid_len); ssid[ssid_len] = 0x0; - if (0) - DBG_871X(FUNC_ADPT_FMT" ssid:(%s,%d), from ie:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), - ssid, ssid_len, - pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, - pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); - memcpy(pbss_network->Ssid.Ssid, (void *)ssid, ssid_len); pbss_network->Ssid.SsidLength = ssid_len; memcpy(pbss_network_ext->Ssid.Ssid, (void *)ssid, ssid_len); pbss_network_ext->Ssid.SsidLength = ssid_len; - - if (0) - DBG_871X(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), - pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, - pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); } - DBG_871X(FUNC_ADPT_FMT" ignore_broadcast_ssid:%d, %s,%d\n", FUNC_ADPT_ARG(adapter), - ignore_broadcast_ssid, ssid, ssid_len); - return ret; } @@ -4186,8 +3634,6 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) int ret = 0; struct adapter *padapter = rtw_netdev_priv(dev); - /* DBG_871X("%s\n", __func__); */ - /* * this function is expect to call in master mode, which allows no power saving * so, we just check hw_init_completed @@ -4208,8 +3654,6 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) return -EFAULT; } - /* DBG_871X("%s, cmd =%d\n", __func__, param->cmd); */ - switch (param->cmd) { case RTL871X_HOSTAPD_FLUSH: @@ -4296,7 +3740,6 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) break; default: - DBG_871X("Unknown hostapd request: %d\n", param->cmd); ret = -EOPNOTSUPP; break; @@ -4326,12 +3769,12 @@ static int rtw_wx_set_priv(struct net_device *dev, struct adapter *padapter = rtw_netdev_priv(dev); struct iw_point *dwrq = (struct iw_point *)awrq; - /* RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ("+rtw_wx_set_priv\n")); */ if (dwrq->length == 0) return -EFAULT; len = dwrq->length; - if (!(ext = vmalloc(len))) + ext = vmalloc(len); + if (!ext) return -ENOMEM; if (copy_from_user(ext, dwrq->pointer, len)) { @@ -4339,13 +3782,9 @@ static int rtw_wx_set_priv(struct net_device *dev, return -EFAULT; } - - /* RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, */ - /* ("rtw_wx_set_priv: %s req =%s\n", */ - /* dev->name, ext)); */ - #ifdef DEBUG_RTW_WX_SET_PRIV - if (!(ext_dbg = vmalloc(len))) { + ext_dbg = vmalloc(len); + if (!ext_dbg) { vfree(ext, len); return -ENOMEM; } @@ -4401,9 +3840,6 @@ FREE_EXT: vfree(ext_dbg); #endif - /* DBG_871X("rtw_wx_set_priv: (SIOCSIWPRIV) %s ret =%d\n", */ - /* dev->name, ret); */ - return ret; } @@ -4416,8 +3852,6 @@ static int rtw_pm_set(struct net_device *dev, unsigned mode = 0; struct adapter *padapter = rtw_netdev_priv(dev); - DBG_871X("[%s] extra = %s\n", __func__, extra); - if (!memcmp(extra, "lps =", 4)) { sscanf(extra+4, "%u", &mode); ret = rtw_pm_set_lps(padapter, mode); @@ -4443,27 +3877,21 @@ static int rtw_test( struct adapter *padapter = rtw_netdev_priv(dev); - DBG_871X("+%s\n", __func__); len = wrqu->data.length; pbuf = rtw_zmalloc(len); - if (pbuf == NULL) { - DBG_871X("%s: no memory!\n", __func__); + if (!pbuf) return -ENOMEM; - } if (copy_from_user(pbuf, wrqu->data.pointer, len)) { kfree(pbuf); - DBG_871X("%s: copy from user fail!\n", __func__); return -EFAULT; } - DBG_871X("%s: string =\"%s\"\n", __func__, pbuf); ptmp = (char *)pbuf; pch = strsep(&ptmp, delim); if ((pch == NULL) || (strlen(pch) == 0)) { kfree(pbuf); - DBG_871X("%s: parameter error(level 1)!\n", __func__); return -EFAULT; } @@ -4493,7 +3921,6 @@ static int rtw_test( if (count == 0) { kfree(pbuf); - DBG_871X("%s: parameter error(level 2)!\n", __func__); return -EFAULT; } @@ -4667,13 +4094,6 @@ static const struct iw_priv_args rtw_private_args[] = { SIOCIWFIRSTPRIV + 0x1D, IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test" }, - -#ifdef CONFIG_WOWLAN - { MP_WOW_ENABLE, IW_PRIV_TYPE_CHAR | 1024, 0, "wow_mode" }, /* set */ -#endif -#ifdef CONFIG_AP_WOWLAN - { MP_AP_WOW_ENABLE, IW_PRIV_TYPE_CHAR | 1024, 0, "ap_wow_mode" }, /* set */ -#endif }; static iw_handler rtw_private_handler[] = { @@ -4732,45 +4152,10 @@ static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) piwstats->qual.qual = 0; piwstats->qual.level = 0; piwstats->qual.noise = 0; - /* DBG_871X("No link level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); */ } else { - #ifdef CONFIG_SIGNAL_DISPLAY_DBM - tmp_level = translate_percentage_to_dbm(padapter->recvpriv.signal_strength); - #else - #ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING - { - /* Do signal scale mapping when using percentage as the unit of signal strength, since the scale mapping is skipped in odm */ - - struct hal_com_data *pHal = GET_HAL_DATA(padapter); - - tmp_level = (u8)odm_SignalScaleMapping(&pHal->odmpriv, padapter->recvpriv.signal_strength); - } - #else tmp_level = padapter->recvpriv.signal_strength; - #endif - #endif - tmp_qual = padapter->recvpriv.signal_qual; -#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - if (rtw_linked_check(padapter)) { - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct noise_info info; - info.bPauseDIG = true; - info.IGIValue = 0x1e; - info.max_time = 100;/* ms */ - info.chan = pmlmeext->cur_channel ;/* rtw_get_oper_ch(padapter); */ - rtw_ps_deny(padapter, PS_DENY_IOCTL); - LeaveAllPowerSaveModeDirect(padapter); - - rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &info, false); - /* ODM_InbandNoise_Monitor(podmpriv, true, 0x20, 100); */ - rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL); - rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(info.chan), &(padapter->recvpriv.noise)); - DBG_871X("chan:%d, noise_level:%d\n", info.chan, padapter->recvpriv.noise); - } -#endif tmp_noise = padapter->recvpriv.noise; - DBG_871X("level:%d, qual:%d, noise:%d, rssi (%d)\n", tmp_level, tmp_qual, tmp_noise, padapter->recvpriv.rssi); piwstats->qual.level = tmp_level; piwstats->qual.qual = tmp_qual; @@ -4778,10 +4163,6 @@ static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) } piwstats->qual.updated = IW_QUAL_ALL_UPDATED ;/* IW_QUAL_DBM; */ - #ifdef CONFIG_SIGNAL_DISPLAY_DBM - piwstats->qual.updated = piwstats->qual.updated | IW_QUAL_DBM; - #endif - return &padapter->iwstats; } @@ -4867,14 +4248,12 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ sscanf(ptr, "%16s", cmdname); cmdlen = strlen(cmdname); - DBG_8192C("%s: cmd =%s\n", __func__, cmdname); /* skip command string */ if (cmdlen > 0) cmdlen += 1; /* skip one space */ ptr += cmdlen; len -= cmdlen; - DBG_8192C("%s: parameters =%s\n", __func__, ptr); priv = rtw_private_handler; priv_args = rtw_private_args; @@ -4985,15 +4364,12 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ break; default: - DBG_8192C("%s: Not yet implemented...\n", __func__); err = -1; goto exit; } if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) { - DBG_8192C("%s: The command %s needs exactly %d argument(s)...\n", - __func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK); err = -EINVAL; goto exit; } @@ -5082,8 +4458,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ case IW_PRIV_TYPE_BYTE: /* Display args */ for (j = 0; j < n; j++) { - sprintf(str, "%d ", extra[j]); - len = strlen(str); + len = scnprintf(str, sizeof(str), "%d ", extra[j]); output_len = strlen(output); if ((output_len + len + 1) > 4096) { err = -E2BIG; @@ -5096,8 +4471,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ case IW_PRIV_TYPE_INT: /* Display args */ for (j = 0; j < n; j++) { - sprintf(str, "%d ", ((__s32 *)extra)[j]); - len = strlen(str); + len = scnprintf(str, sizeof(str), "%d ", ((__s32 *)extra)[j]); output_len = strlen(output); if ((output_len + len + 1) > 4096) { err = -E2BIG; @@ -5113,7 +4487,6 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ break; default: - DBG_8192C("%s: Not yet implemented...\n", __func__); err = -1; goto exit; } diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index d46c65ab384b5c6f5f9f4c820be12c4705888abb..0a16752f805bf2707598fc82cf5bb00806529d28 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -65,7 +65,7 @@ void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted) indicate_wx_scan_complete_event(padapter); } -static RT_PMKID_LIST backupPMKIDList[NUM_PMKID_CACHE]; +static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; void rtw_reset_securitypriv(struct adapter *adapter) { u8 backupPMKIDIndex = 0; @@ -84,7 +84,7 @@ void rtw_reset_securitypriv(struct adapter *adapter) /* Backup the btkip_countermeasure information. */ /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ - memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); + memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; @@ -96,7 +96,7 @@ void rtw_reset_securitypriv(struct adapter *adapter) /* Added by Albert 2009/02/18 */ /* Restore the PMK information to securitypriv structure for the following connection. */ - memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); + memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; @@ -127,7 +127,7 @@ void rtw_reset_securitypriv(struct adapter *adapter) void rtw_os_indicate_disconnect(struct adapter *adapter) { - /* RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ]; */ + /* struct rt_pmkid_list backupPMKIDList[ NUM_PMKID_CACHE ]; */ netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */ @@ -145,29 +145,23 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) u8 *buff, *p, i; union iwreq_data wrqu; - RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("+rtw_report_sec_ie, authmode =%d\n", authmode)); - buff = NULL; if (authmode == WLAN_EID_VENDOR_SPECIFIC) { - RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("rtw_report_sec_ie, authmode =%d\n", authmode)); - buff = rtw_zmalloc(IW_CUSTOM_MAX); - if (NULL == buff) { - DBG_871X(FUNC_ADPT_FMT ": alloc memory FAIL!!\n", - FUNC_ADPT_ARG(adapter)); + if (!buff) return; - } + p = buff; - p += sprintf(p, "ASSOCINFO(ReqIEs ="); + p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), "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 += scnprintf(p, IW_CUSTOM_MAX - (p - buff), "%02x", sec_ie[i]); - p += sprintf(p, ")"); + p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), ")"); memset(&wrqu, 0, sizeof(wrqu)); diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index b62fe9238e6d92524ac9ef7f07edaaf88b0346d4..160f624612c778c7e73a06941b35e24b257b9819 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -113,11 +113,7 @@ static int rtw_enusbss;/* 0:disable, 1:enable */ static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */ -#ifdef CONFIG_HW_PWRP_DETECTION -static int rtw_hwpwrp_detect = 1; -#else static int rtw_hwpwrp_detect; /* HW power ping detect 0:disable , 1:enable */ -#endif static int rtw_hw_wps_pbc; @@ -125,11 +121,7 @@ int rtw_mc2u_disable = 0; static int rtw_80211d; -#ifdef CONFIG_QOS_OPTIMIZATION -static int rtw_qos_opt_enable = 1;/* 0: disable, 1:enable */ -#else static int rtw_qos_opt_enable;/* 0: disable, 1:enable */ -#endif module_param(rtw_qos_opt_enable, int, 0644); static char *ifname = "wlan%d"; @@ -201,11 +193,9 @@ MODULE_PARM_DESC(rtw_tx_pwr_lmt_enable, "0:Disable, 1:Enable, 2: Depend on efuse module_param(rtw_tx_pwr_by_rate, int, 0644); MODULE_PARM_DESC(rtw_tx_pwr_by_rate, "0:Disable, 1:Enable, 2: Depend on efuse"); -int _netdev_open(struct net_device *pnetdev); -int netdev_open(struct net_device *pnetdev); static int netdev_close(struct net_device *pnetdev); -static void loadparam(struct adapter *padapter, _nic_hdl pnetdev) +static void loadparam(struct adapter *padapter, struct net_device *pnetdev) { struct registry_priv *registry_par = &padapter->registrypriv; @@ -314,7 +304,6 @@ static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) struct sockaddr *addr = p; if (!padapter->bup) { - /* DBG_871X("r8711_net_set_mac_address(), MAC =%x:%x:%x:%x:%x:%x\n", addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3], */ /* addr->sa_data[4], addr->sa_data[5]); */ memcpy(padapter->eeprompriv.mac_addr, addr->sa_data, ETH_ALEN); /* memcpy(pnetdev->dev_addr, addr->sa_data, ETH_ALEN); */ @@ -423,7 +412,8 @@ static int rtw_ndev_notifier_call(struct notifier_block *nb, unsigned long state if (dev->netdev_ops->ndo_do_ioctl != rtw_ioctl) return NOTIFY_DONE; - DBG_871X_LEVEL(_drv_info_, FUNC_NDEV_FMT " state:%lu\n", FUNC_NDEV_ARG(dev), state); + netdev_info(dev, FUNC_NDEV_FMT " state:%lu\n", FUNC_NDEV_ARG(dev), + state); return NOTIFY_DONE; } @@ -447,7 +437,7 @@ static int rtw_ndev_init(struct net_device *dev) { struct adapter *adapter = rtw_netdev_priv(dev); - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter)); + netdev_dbg(dev, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter)); strncpy(adapter->old_ifname, dev->name, IFNAMSIZ); return 0; @@ -457,7 +447,7 @@ static void rtw_ndev_uninit(struct net_device *dev) { struct adapter *adapter = rtw_netdev_priv(dev); - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter)); + netdev_dbg(dev, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter)); } static const struct net_device_ops rtw_netdev_ops = { @@ -489,8 +479,6 @@ struct net_device *rtw_init_netdev(struct adapter *old_padapter) struct adapter *padapter; struct net_device *pnetdev; - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n")); - if (old_padapter) pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(struct adapter), (void *)old_padapter); else @@ -505,7 +493,6 @@ struct net_device *rtw_init_netdev(struct adapter *old_padapter) /* pnetdev->init = NULL; */ - DBG_871X("register rtw_netdev_ops to netdev_ops\n"); pnetdev->netdev_ops = &rtw_netdev_ops; /* pnetdev->tx_timeout = NULL; */ @@ -539,7 +526,6 @@ u32 rtw_start_drv_threads(struct adapter *padapter) { u32 _status = _SUCCESS; - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_start_drv_threads\n")); padapter->xmitThread = kthread_run(rtw_xmit_thread, padapter, "RTW_XMIT_THREAD"); if (IS_ERR(padapter->xmitThread)) _status = _FAIL; @@ -556,14 +542,11 @@ u32 rtw_start_drv_threads(struct adapter *padapter) void rtw_stop_drv_threads(struct adapter *padapter) { - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads\n")); - rtw_stop_cmd_thread(padapter); /* Below is to termindate tx_thread... */ complete(&padapter->xmitpriv.xmit_comp); wait_for_completion(&padapter->xmitpriv.terminate_xmitthread_comp); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("\n drv_halt: rtw_xmit_thread can be terminated !\n")); rtw_hal_stop_thread(padapter); } @@ -596,9 +579,6 @@ static void rtw_init_default_value(struct adapter *padapter) /* security_priv */ /* rtw_get_encrypt_decrypt_from_registrypriv(padapter); */ psecuritypriv->binstallGrpkey = _FAIL; -#ifdef CONFIG_GTK_OL - psecuritypriv->binstallKCK_KEK = _FAIL; -#endif /* CONFIG_GTK_OL */ psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt; psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt; @@ -710,14 +690,11 @@ u8 rtw_init_drv_sw(struct adapter *padapter) { u8 ret8 = _SUCCESS; - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n")); - rtw_init_default_value(padapter); rtw_init_hal_com_default_value(padapter); if (rtw_init_cmd_priv(&padapter->cmdpriv)) { - RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init cmd_priv\n")); ret8 = _FAIL; goto exit; } @@ -725,14 +702,12 @@ u8 rtw_init_drv_sw(struct adapter *padapter) padapter->cmdpriv.padapter = padapter; if (rtw_init_evt_priv(&padapter->evtpriv)) { - RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init evt_priv\n")); ret8 = _FAIL; goto exit; } if (rtw_init_mlme_priv(padapter) == _FAIL) { - RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_priv\n")); ret8 = _FAIL; goto exit; } @@ -740,13 +715,11 @@ u8 rtw_init_drv_sw(struct adapter *padapter) init_mlme_ext_priv(padapter); if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) { - DBG_871X("Can't _rtw_init_xmit_priv\n"); ret8 = _FAIL; goto exit; } if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) { - DBG_871X("Can't _rtw_init_recv_priv\n"); ret8 = _FAIL; goto exit; } @@ -757,7 +730,6 @@ u8 rtw_init_drv_sw(struct adapter *padapter) /* memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); */ if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) { - DBG_871X("Can't _rtw_init_sta_priv\n"); ret8 = _FAIL; goto exit; } @@ -773,29 +745,21 @@ u8 rtw_init_drv_sw(struct adapter *padapter) exit: - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw\n")); - return ret8; } void rtw_cancel_all_timer(struct adapter *padapter) { - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer\n")); - del_timer_sync(&padapter->mlmepriv.assoc_timer); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel association timer complete!\n")); del_timer_sync(&padapter->mlmepriv.scan_to_timer); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel scan_to_timer!\n")); del_timer_sync(&padapter->mlmepriv.dynamic_chk_timer); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel dynamic_chk_timer!\n")); del_timer_sync(&(adapter_to_pwrctl(padapter)->pwr_state_check_timer)); del_timer_sync(&padapter->mlmepriv.set_scan_deny_timer); rtw_clear_scan_deny(padapter); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel set_scan_deny_timer!\n")); del_timer_sync(&padapter->recvpriv.signal_stat_timer); @@ -805,8 +769,6 @@ void rtw_cancel_all_timer(struct adapter *padapter) u8 rtw_free_drv_sw(struct adapter *padapter) { - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw")); - free_mlme_ext_priv(&padapter->mlmeextpriv); rtw_free_cmd_priv(&padapter->cmdpriv); @@ -829,8 +791,6 @@ u8 rtw_free_drv_sw(struct adapter *padapter) rtw_hal_free_data(padapter); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<==rtw_free_drv_sw\n")); - /* free the old_pnetdev */ if (padapter->rereg_nd_name_priv.old_pnetdev) { free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); @@ -841,8 +801,6 @@ u8 rtw_free_drv_sw(struct adapter *padapter) if (padapter->pbuddy_adapter) padapter->pbuddy_adapter->pbuddy_adapter = NULL; - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw\n")); - return _SUCCESS; } @@ -859,13 +817,10 @@ static int _rtw_drv_register_netdev(struct adapter *padapter, char *name) /* Tell the network stack we exist */ if (register_netdev(pnetdev) != 0) { - DBG_871X(FUNC_NDEV_FMT "Failed!\n", FUNC_NDEV_ARG(pnetdev)); ret = _FAIL; goto error_register_netdev; } - DBG_871X("%s, MAC Address (if%d) = %pM\n", __func__, (padapter->iface_id + 1), MAC_ARG(pnetdev->dev_addr)); - return ret; error_register_netdev: @@ -886,15 +841,12 @@ int rtw_drv_register_netdev(struct adapter *if1) return _rtw_drv_register_netdev(padapter, name); } -int _netdev_open(struct net_device *pnetdev) +static int _netdev_open(struct net_device *pnetdev) { uint status; struct adapter *padapter = rtw_netdev_priv(pnetdev); struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - dev_open\n")); - DBG_871X("+871x_drv - drv_open, bup =%d\n", padapter->bup); - padapter->netif_up = true; if (pwrctrlpriv->ps_flag) { @@ -908,18 +860,12 @@ int _netdev_open(struct net_device *pnetdev) padapter->bCardDisableWOHSM = false; status = rtw_hal_init(padapter); - if (status == _FAIL) { - RT_TRACE(_module_os_intfs_c_, _drv_err_, ("rtl871x_hal_init(): Can't init h/w!\n")); + if (status == _FAIL) goto netdev_open_error; - } - - DBG_871X("MAC Address = %pM\n", MAC_ARG(pnetdev->dev_addr)); status = rtw_start_drv_threads(padapter); - if (status == _FAIL) { - DBG_871X("Initialize driver software resource Failed!\n"); + if (status == _FAIL) goto netdev_open_error; - } if (padapter->intf_start) padapter->intf_start(padapter); @@ -940,9 +886,6 @@ int _netdev_open(struct net_device *pnetdev) netdev_open_normal_process: - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - dev_open\n")); - DBG_871X("-871x_drv - drv_open, bup =%d\n", padapter->bup); - return 0; netdev_open_error: @@ -952,9 +895,6 @@ netdev_open_error: netif_carrier_off(pnetdev); rtw_netif_stop_queue(pnetdev); - RT_TRACE(_module_os_intfs_c_, _drv_err_, ("-871x_drv - dev_open, fail!\n")); - DBG_871X("-871x_drv - drv_open fail, bup =%d\n", padapter->bup); - return (-1); } @@ -964,10 +904,8 @@ int netdev_open(struct net_device *pnetdev) struct adapter *padapter = rtw_netdev_priv(pnetdev); struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); - if (pwrctrlpriv->bInSuspend) { - DBG_871X("+871x_drv - drv_open, bInSuspend =%d\n", pwrctrlpriv->bInSuspend); + if (pwrctrlpriv->bInSuspend) return 0; - } if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->hw_init_mutex))) return -1; @@ -985,18 +923,13 @@ static int ips_netdrv_open(struct adapter *padapter) padapter->net_closed = false; - DBG_871X("===> %s.........\n", __func__); - - padapter->bDriverStopped = false; padapter->bCardDisableWOHSM = false; /* padapter->bup = true; */ status = rtw_hal_init(padapter); - if (status == _FAIL) { - RT_TRACE(_module_os_intfs_c_, _drv_err_, ("ips_netdrv_open(): Can't init h/w!\n")); + if (status == _FAIL) goto netdev_open_error; - } if (padapter->intf_start) padapter->intf_start(padapter); @@ -1006,8 +939,6 @@ static int ips_netdrv_open(struct adapter *padapter) return _SUCCESS; netdev_open_error: - /* padapter->bup = false; */ - DBG_871X("-ips_netdrv_open - drv_open failure, bup =%d\n", padapter->bup); return _FAIL; } @@ -1016,36 +947,28 @@ netdev_open_error: int rtw_ips_pwr_up(struct adapter *padapter) { int result; - DBG_871X("===> rtw_ips_pwr_up..............\n"); result = ips_netdrv_open(padapter); - DBG_871X("<=== rtw_ips_pwr_up..............\n"); return result; } void rtw_ips_pwr_down(struct adapter *padapter) { - DBG_871X("===> rtw_ips_pwr_down...................\n"); - padapter->bCardDisableWOHSM = true; padapter->net_closed = true; rtw_ips_dev_unload(padapter); padapter->bCardDisableWOHSM = false; - DBG_871X("<=== rtw_ips_pwr_down.....................\n"); } void rtw_ips_dev_unload(struct adapter *padapter) { - DBG_871X("====> %s...\n", __func__); - if (!padapter->bSurpriseRemoved) rtw_hal_deinit(padapter); } - static int pm_netdev_open(struct net_device *pnetdev, u8 bnormal) { int status = -1; @@ -1069,8 +992,6 @@ static int netdev_close(struct net_device *pnetdev) struct adapter *padapter = rtw_netdev_priv(pnetdev); struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - drv_close\n")); - if (pwrctl->bInternalAutoSuspend) { /* rtw_pwr_wakeup(padapter); */ if (pwrctl->rf_pwrstate == rf_off) @@ -1081,7 +1002,6 @@ static int netdev_close(struct net_device *pnetdev) /*if (!padapter->hw_init_completed) { - DBG_871X("(1)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n", padapter->bup, padapter->hw_init_completed); padapter->bDriverStopped = true; @@ -1089,8 +1009,6 @@ static int netdev_close(struct net_device *pnetdev) } else*/ if (pwrctl->rf_pwrstate == rf_on) { - DBG_871X("(2)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n", padapter->bup, padapter->hw_init_completed); - /* s1. */ if (pnetdev) { if (!rtw_netif_queue_stopped(pnetdev)) @@ -1111,16 +1029,11 @@ static int netdev_close(struct net_device *pnetdev) rtw_scan_abort(padapter); adapter_wdev_data(padapter)->bandroid_scan = false; - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - drv_close\n")); - DBG_871X("-871x_drv - drv_close, bup =%d\n", padapter->bup); - return 0; } void rtw_ndev_destructor(struct net_device *ndev) { - DBG_871X(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); - kfree(ndev->ieee80211_ptr); } @@ -1132,10 +1045,7 @@ void rtw_dev_unload(struct adapter *padapter) struct cmd_priv *pcmdpriv = &padapter->cmdpriv; u8 cnt = 0; - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+%s\n", __func__)); - if (padapter->bup) { - DBG_871X("===> %s\n", __func__); padapter->bDriverStopped = true; if (padapter->xmitpriv.ack_tx) @@ -1144,76 +1054,51 @@ void rtw_dev_unload(struct adapter *padapter) if (padapter->intf_stop) padapter->intf_stop(padapter); - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop intf complete!\n")); - if (!pwrctl->bInternalAutoSuspend) rtw_stop_drv_threads(padapter); while (atomic_read(&pcmdpriv->cmdthd_running)) { if (cnt > 5) { - DBG_871X("stop cmdthd timeout\n"); break; } else { cnt++; - DBG_871X("cmdthd is running(%d)\n", cnt); msleep(10); } } - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ %s: stop thread complete!\n", __func__)); - /* check the status of IPS */ if (rtw_hal_check_ips_status(padapter) || pwrctl->rf_pwrstate == rf_off) { /* check HW status and SW state */ - DBG_871X_LEVEL(_drv_always_, "%s: driver in IPS-FWLPS\n", __func__); + netdev_dbg(padapter->pnetdev, + "%s: driver in IPS-FWLPS\n", __func__); pdbgpriv->dbg_dev_unload_inIPS_cnt++; LeaveAllPowerSaveMode(padapter); } else { - DBG_871X_LEVEL(_drv_always_, "%s: driver not in IPS\n", __func__); + netdev_dbg(padapter->pnetdev, + "%s: driver not in IPS\n", __func__); } if (!padapter->bSurpriseRemoved) { hal_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req); -#ifdef CONFIG_WOWLAN - if (pwrctl->bSupportRemoteWakeup && pwrctl->wowlan_mode) { - DBG_871X_LEVEL(_drv_always_, "%s bSupportRemoteWakeup ==true do not run rtw_hal_deinit()\n", __func__); - } - else -#endif - { - /* amy modify 20120221 for power seq is different between driver open and ips */ - rtw_hal_deinit(padapter); - } + + /* amy modify 20120221 for power seq is different between driver open and ips */ + rtw_hal_deinit(padapter); + padapter->bSurpriseRemoved = true; } - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, - ("@ %s: deinit hal complete!\n", __func__)); padapter->bup = false; - DBG_871X("<=== %s\n", __func__); - } else { - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("%s: bup ==false\n", __func__)); - DBG_871X("%s: bup ==false\n", __func__); } - - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-%s\n", __func__)); } static int rtw_suspend_free_assoc_resource(struct adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); - if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { - DBG_871X("%s %s(%pM), length:%d assoc_ssid.length:%d\n", __func__, - pmlmepriv->cur_network.network.Ssid.Ssid, - MAC_ARG(pmlmepriv->cur_network.network.MacAddress), - pmlmepriv->cur_network.network.Ssid.SsidLength, - pmlmepriv->assoc_ssid.SsidLength); rtw_set_to_roam(padapter, 1); } } @@ -1236,146 +1121,18 @@ static int rtw_suspend_free_assoc_resource(struct adapter *padapter) rtw_indicate_scan_done(padapter, 1); if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { - DBG_871X_LEVEL(_drv_always_, "%s: fw_under_linking\n", __func__); + netdev_dbg(padapter->pnetdev, "%s: fw_under_linking\n", + __func__); rtw_indicate_disconnect(padapter); } - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); return _SUCCESS; } -#ifdef CONFIG_WOWLAN -void rtw_suspend_wow(struct adapter *padapter) -{ - u8 ch, bw, offset; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct net_device *pnetdev = padapter->pnetdev; - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - struct wowlan_ioctl_param poidparam; - - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); - - - DBG_871X("wowlan_mode: %d\n", pwrpriv->wowlan_mode); - DBG_871X("wowlan_pno_enable: %d\n", pwrpriv->wowlan_pno_enable); - - if (pwrpriv->wowlan_mode) { - if (pnetdev) - rtw_netif_stop_queue(pnetdev); - /* 1. stop thread */ - padapter->bDriverStopped = true; /* for stop thread */ - rtw_stop_drv_threads(padapter); - padapter->bDriverStopped = false; /* for 32k command */ - - /* 2. disable interrupt */ - if (padapter->intf_stop) - padapter->intf_stop(padapter); - - /* 2.1 clean interrupt */ - if (padapter->HalFunc.clear_interrupt) - padapter->HalFunc.clear_interrupt(padapter); - - /* 2.2 free irq */ - /* sdio_free_irq(adapter_to_dvobj(padapter)); */ - if (padapter->intf_free_irq) - padapter->intf_free_irq(adapter_to_dvobj(padapter)); - - poidparam.subcode = WOWLAN_ENABLE; - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam); - if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { - DBG_871X("%s %s(%pM), length:%d assoc_ssid.length:%d\n", __func__, - pmlmepriv->cur_network.network.Ssid.Ssid, - MAC_ARG(pmlmepriv->cur_network.network.MacAddress), - pmlmepriv->cur_network.network.Ssid.SsidLength, - pmlmepriv->assoc_ssid.SsidLength); - - rtw_set_to_roam(padapter, 0); - } - } - - DBG_871X_LEVEL(_drv_always_, "%s: wowmode suspending\n", __func__); - - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { - DBG_871X_LEVEL(_drv_always_, "%s: fw_under_survey\n", __func__); - rtw_indicate_scan_done(padapter, 1); - clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); - } - - if (rtw_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) { - DBG_871X(FUNC_ADPT_FMT " back to linked/linking union - ch:%u, bw:%u, offset:%u\n", - FUNC_ADPT_ARG(padapter), ch, bw, offset); - set_channel_bwmode(padapter, ch, offset, bw); - } - - if (pwrpriv->wowlan_pno_enable) - DBG_871X_LEVEL(_drv_always_, "%s: pno: %d\n", __func__, pwrpriv->wowlan_pno_enable); - else - rtw_set_ps_mode(padapter, PS_MODE_DTIM, 0, 0, "WOWLAN"); - } else { - DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR ### wowlan_mode =%d\n", __func__, pwrpriv->wowlan_mode); - } - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); -} -#endif /* ifdef CONFIG_WOWLAN */ - -#ifdef CONFIG_AP_WOWLAN -void rtw_suspend_ap_wow(struct adapter *padapter) -{ - u8 ch, bw, offset; - struct net_device *pnetdev = padapter->pnetdev; - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - struct wowlan_ioctl_param poidparam; - - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); - - pwrpriv->wowlan_ap_mode = true; - - DBG_871X("wowlan_ap_mode: %d\n", pwrpriv->wowlan_ap_mode); - - if (pnetdev) - rtw_netif_stop_queue(pnetdev); - /* 1. stop thread */ - padapter->bDriverStopped = true; /* for stop thread */ - rtw_stop_drv_threads(padapter); - padapter->bDriverStopped = false; /* for 32k command */ - - /* 2. disable interrupt */ - rtw_hal_disable_interrupt(padapter); /* It need wait for leaving 32K. */ - - /* 2.1 clean interrupt */ - if (padapter->HalFunc.clear_interrupt) - padapter->HalFunc.clear_interrupt(padapter); - - /* 2.2 free irq */ - /* sdio_free_irq(adapter_to_dvobj(padapter)); */ - if (padapter->intf_free_irq) - padapter->intf_free_irq(adapter_to_dvobj(padapter)); - - poidparam.subcode = WOWLAN_AP_ENABLE; - padapter->HalFunc.SetHwRegHandler(padapter, - HW_VAR_AP_WOWLAN, (u8 *)&poidparam); - - DBG_871X_LEVEL(_drv_always_, "%s: wowmode suspending\n", __func__); - - if (rtw_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) { - DBG_871X(FUNC_ADPT_FMT " back to linked/linking union - ch:%u, bw:%u, offset:%u\n", - FUNC_ADPT_ARG(padapter), ch, bw, offset); - set_channel_bwmode(padapter, ch, offset, bw); - } - - rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, 0, "AP-WOWLAN"); - - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); -} -#endif /* ifdef CONFIG_AP_WOWLAN */ - - static void rtw_suspend_normal(struct adapter *padapter) { struct net_device *pnetdev = padapter->pnetdev; - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); if (pnetdev) { netif_carrier_off(pnetdev); rtw_netif_stop_queue(pnetdev); @@ -1384,15 +1141,15 @@ static void rtw_suspend_normal(struct adapter *padapter) rtw_suspend_free_assoc_resource(padapter); if ((rtw_hal_check_ips_status(padapter)) || (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off)) - DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR #### driver in IPS ####ERROR###!!!\n", __func__); + netdev_dbg(padapter->pnetdev, + "%s: ### ERROR #### driver in IPS ####ERROR###!!!\n", + __func__); rtw_dev_unload(padapter); /* sdio_deinit(adapter_to_dvobj(padapter)); */ if (padapter->intf_deinit) padapter->intf_deinit(adapter_to_dvobj(padapter)); - - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); } int rtw_suspend_common(struct adapter *padapter) @@ -1405,8 +1162,7 @@ int rtw_suspend_common(struct adapter *padapter) int ret = 0; unsigned long start_time = jiffies; - DBG_871X_LEVEL(_drv_always_, " suspend start\n"); - DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid); + netdev_dbg(padapter->pnetdev, " suspend start\n"); pdbgpriv->dbg_suspend_cnt++; pwrpriv->bInSuspend = true; @@ -1415,8 +1171,6 @@ int rtw_suspend_common(struct adapter *padapter) msleep(1); if ((!padapter->bup) || (padapter->bDriverStopped) || (padapter->bSurpriseRemoved)) { - DBG_871X("%s bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", __func__ - , padapter->bup, padapter->bDriverStopped, padapter->bSurpriseRemoved); pdbgpriv->dbg_suspend_error_cnt++; goto exit; } @@ -1429,247 +1183,28 @@ int rtw_suspend_common(struct adapter *padapter) rtw_stop_cmd_thread(padapter); /* wait for the latest FW to remove this condition. */ - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) hal_btcoex_SuspendNotify(padapter, 0); - DBG_871X("WIFI_AP_STATE\n"); - } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) hal_btcoex_SuspendNotify(padapter, 1); - DBG_871X("STATION\n"); - } rtw_ps_deny_cancel(padapter, PS_DENY_SUSPEND); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - #ifdef CONFIG_WOWLAN - if (check_fwstate(pmlmepriv, _FW_LINKED)) - pwrpriv->wowlan_mode = true; - else if (pwrpriv->wowlan_pno_enable) - pwrpriv->wowlan_mode |= pwrpriv->wowlan_pno_enable; - - if (pwrpriv->wowlan_mode) - rtw_suspend_wow(padapter); - else - rtw_suspend_normal(padapter); - - #else /* CONFIG_WOWLAN */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) rtw_suspend_normal(padapter); - #endif /* CONFIG_WOWLAN */ - } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - #ifdef CONFIG_AP_WOWLAN - rtw_suspend_ap_wow(padapter); - #else + else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) rtw_suspend_normal(padapter); - #endif /* CONFIG_AP_WOWLAN */ - } else { + else rtw_suspend_normal(padapter); - } - DBG_871X_LEVEL(_drv_always_, "rtw suspend success in %d ms\n", - jiffies_to_msecs(jiffies - start_time)); + netdev_dbg(padapter->pnetdev, "rtw suspend success in %d ms\n", + jiffies_to_msecs(jiffies - start_time)); exit: - DBG_871X("<=== %s return %d.............. in %dms\n", __func__ - , ret, jiffies_to_msecs(jiffies - start_time)); return ret; } -#ifdef CONFIG_WOWLAN -int rtw_resume_process_wow(struct adapter *padapter) -{ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct net_device *pnetdev = padapter->pnetdev; - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - struct dvobj_priv *psdpriv = padapter->dvobj; - struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - struct wowlan_ioctl_param poidparam; - struct sta_info *psta = NULL; - int ret = _SUCCESS; - - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); - - if (padapter) { - pnetdev = padapter->pnetdev; - pwrpriv = adapter_to_pwrctl(padapter); - } else { - pdbgpriv->dbg_resume_error_cnt++; - ret = -1; - goto exit; - } - - if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { - DBG_871X("%s pdapter %p bDriverStopped %d bSurpriseRemoved %d\n", - __func__, padapter, padapter->bDriverStopped, - padapter->bSurpriseRemoved); - goto exit; - } - -#ifdef CONFIG_PNO_SUPPORT - pwrpriv->pno_in_resume = true; -#endif - - if (pwrpriv->wowlan_mode) { - rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "WOWLAN"); - - pwrpriv->bFwCurrentInPSMode = false; - - if (padapter->intf_stop) - padapter->intf_stop(padapter); - - if (padapter->HalFunc.clear_interrupt) - padapter->HalFunc.clear_interrupt(padapter); - - /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { */ - if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) { - ret = -1; - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __func__)); - goto exit; - } - - /* Disable WOW, set H2C command */ - poidparam.subcode = WOWLAN_DISABLE; - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam); - - psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); - if (psta) - set_sta_rate(padapter, psta); - - padapter->bDriverStopped = false; - DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); - rtw_start_drv_threads(padapter); - - if (padapter->intf_start) - padapter->intf_start(padapter); - - /* start netif queue */ - if (pnetdev) { - if (!rtw_netif_queue_stopped(pnetdev)) - rtw_netif_start_queue(pnetdev); - else - rtw_netif_wake_queue(pnetdev); - } - } else { - DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR ### wowlan_mode =%d\n", __func__, pwrpriv->wowlan_mode); - } - - if (padapter->pid[1] != 0) { - DBG_871X("pid[1]:%d\n", padapter->pid[1]); - rtw_signal_process(padapter->pid[1], SIGUSR2); - } - - if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { - if (pwrpriv->wowlan_wake_reason == FWDecisionDisconnect || - pwrpriv->wowlan_wake_reason == Rx_DisAssoc || - pwrpriv->wowlan_wake_reason == Rx_DeAuth) { - DBG_871X("%s: disconnect reason: %02x\n", __func__, - pwrpriv->wowlan_wake_reason); - rtw_indicate_disconnect(padapter); - - rtw_sta_media_status_rpt(padapter, - rtw_get_stainfo(&padapter->stapriv, - get_bssid(&padapter->mlmepriv)), 0); - - rtw_free_assoc_resources(padapter, 1); - pmlmeinfo->state = WIFI_FW_NULL_STATE; - - } else { - DBG_871X("%s: do roaming\n", __func__); - rtw_roaming(padapter, NULL); - } - } - - if (pwrpriv->wowlan_mode) { - pwrpriv->bips_processing = false; - _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); - } else { - DBG_871X_LEVEL(_drv_always_, "do not reset timer\n"); - } - - pwrpriv->wowlan_mode = false; - - /* clean driver side wake up reason. */ - pwrpriv->wowlan_wake_reason = 0; -exit: - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); - return ret; -} -#endif /* ifdef CONFIG_WOWLAN */ - -#ifdef CONFIG_AP_WOWLAN -int rtw_resume_process_ap_wow(struct adapter *padapter) -{ - struct net_device *pnetdev = padapter->pnetdev; - struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); - struct dvobj_priv *psdpriv = padapter->dvobj; - struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - struct wowlan_ioctl_param poidparam; - int ret = _SUCCESS; - - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); - - if (padapter) { - pnetdev = padapter->pnetdev; - pwrpriv = adapter_to_pwrctl(padapter); - } else { - pdbgpriv->dbg_resume_error_cnt++; - ret = -1; - goto exit; - } - - rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "AP-WOWLAN"); - - pwrpriv->bFwCurrentInPSMode = false; - - rtw_hal_disable_interrupt(padapter); - - if (padapter->HalFunc.clear_interrupt) - padapter->HalFunc.clear_interrupt(padapter); - - /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { */ - if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) { - ret = -1; - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __func__)); - goto exit; - } - - /* Disable WOW, set H2C command */ - poidparam.subcode = WOWLAN_AP_DISABLE; - padapter->HalFunc.SetHwRegHandler(padapter, - HW_VAR_AP_WOWLAN, (u8 *)&poidparam); - pwrpriv->wowlan_ap_mode = false; - - padapter->bDriverStopped = false; - DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); - rtw_start_drv_threads(padapter); - - if (padapter->intf_start) - padapter->intf_start(padapter); - - /* start netif queue */ - if (pnetdev) { - if (!rtw_netif_queue_stopped(pnetdev)) - rtw_netif_start_queue(pnetdev); - else - rtw_netif_wake_queue(pnetdev); - } - - if (padapter->pid[1] != 0) { - DBG_871X("pid[1]:%d\n", padapter->pid[1]); - rtw_signal_process(padapter->pid[1], SIGUSR2); - } - - pwrpriv->bips_processing = false; - _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); - - /* clean driver side wake up reason. */ - pwrpriv->wowlan_wake_reason = 0; -exit: - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); - return ret; -} -#endif /* ifdef CONFIG_APWOWLAN */ - static int rtw_resume_process_normal(struct adapter *padapter) { struct net_device *pnetdev; @@ -1690,27 +1225,22 @@ static int rtw_resume_process_normal(struct adapter *padapter) pmlmepriv = &padapter->mlmepriv; psdpriv = padapter->dvobj; pdbgpriv = &psdpriv->drv_dbg; - - DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter)); /* interface init */ /* if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) */ if ((padapter->intf_init) && (padapter->intf_init(adapter_to_dvobj(padapter)) != _SUCCESS)) { ret = -1; - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __func__)); goto exit; } rtw_hal_disable_interrupt(padapter); /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) */ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) { ret = -1; - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __func__)); goto exit; } rtw_reset_drv_sw(padapter); pwrpriv->bkeepfwalive = false; - DBG_871X("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); if (pm_netdev_open(pnetdev, true) != 0) { ret = -1; pdbgpriv->dbg_resume_error_cnt++; @@ -1720,28 +1250,16 @@ static int rtw_resume_process_normal(struct adapter *padapter) netif_device_attach(pnetdev); netif_carrier_on(pnetdev); - if (padapter->pid[1] != 0) { - DBG_871X("pid[1]:%d\n", padapter->pid[1]); + if (padapter->pid[1] != 0) rtw_signal_process(padapter->pid[1], SIGUSR2); - } if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - DBG_871X(FUNC_ADPT_FMT " fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); - if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) rtw_roaming(padapter, NULL); - } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - DBG_871X(FUNC_ADPT_FMT " fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); rtw_ap_restore_network(padapter); - } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - DBG_871X(FUNC_ADPT_FMT " fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); - } else { - DBG_871X(FUNC_ADPT_FMT " fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); } - DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter)); - exit: return ret; } @@ -1753,25 +1271,12 @@ int rtw_resume_common(struct adapter *padapter) struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - DBG_871X_LEVEL(_drv_always_, "resume start\n"); - DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid); + netdev_dbg(padapter->pnetdev, "resume start\n"); if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - #ifdef CONFIG_WOWLAN - if (pwrpriv->wowlan_mode) - rtw_resume_process_wow(padapter); - else - rtw_resume_process_normal(padapter); - #else rtw_resume_process_normal(padapter); - #endif - } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - #ifdef CONFIG_AP_WOWLAN - rtw_resume_process_ap_wow(padapter); - #else rtw_resume_process_normal(padapter); - #endif /* CONFIG_AP_WOWLAN */ } else { rtw_resume_process_normal(padapter); } @@ -1780,12 +1285,9 @@ int rtw_resume_common(struct adapter *padapter) if (pwrpriv) { pwrpriv->bInSuspend = false; - #ifdef CONFIG_PNO_SUPPORT - pwrpriv->pno_in_resume = false; - #endif } - DBG_871X_LEVEL(_drv_always_, "%s:%d in %d ms\n", __func__, ret, - jiffies_to_msecs(jiffies - start_time)); + netdev_dbg(padapter->pnetdev, "%s:%d in %d ms\n", __func__, ret, + jiffies_to_msecs(jiffies - start_time)); return ret; } diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c index 3c71d2fafabff689c3c1fcd763c544bf1bc22d5a..9c6b1666df13966efd1fe83a82fca929091b6565 100644 --- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c +++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c @@ -47,7 +47,7 @@ inline struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb) return skb_copy(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); } -inline int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb) +inline int _rtw_netif_rx(struct net_device *ndev, struct sk_buff *skb) { skb->dev = ndev; return netif_rx(skb); @@ -160,10 +160,8 @@ int rtw_change_ifname(struct adapter *padapter, const char *ifname) else ret = register_netdevice(pnetdev); - if (ret != 0) { - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("register_netdev() failed\n")); + if (ret != 0) goto error; - } return 0; @@ -252,7 +250,6 @@ bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf) if (rtw_cbuf_full(cbuf)) return _FAIL; - DBG_871X("%s on %u\n", __func__, cbuf->write); cbuf->bufs[cbuf->write] = buf; cbuf->write = (cbuf->write + 1) % cbuf->size; @@ -272,7 +269,6 @@ void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) if (rtw_cbuf_empty(cbuf)) return NULL; - DBG_871X("%s on %u\n", __func__, cbuf->read); buf = cbuf->bufs[cbuf->read]; cbuf->read = (cbuf->read + 1) % cbuf->size; diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index ac35277fbacd0fc1bc2c6a81d548cd6e555c5d7b..cd51430d4618fd8b0f9cb0796b6fb6a4b73acec5 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -30,7 +30,7 @@ void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *prec /* free os related resource in union recv_frame */ void rtw_os_recv_resource_free(struct recv_priv *precvpriv) { - sint i; + signed int i; union recv_frame *precvframe; precvframe = (union recv_frame *) precvpriv->precv_frame_buf; @@ -53,19 +53,17 @@ void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *pre } } -_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) +struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) { u16 eth_type; - _pkt *sub_skb; + struct sk_buff *sub_skb; struct rx_pkt_attrib *pattrib; pattrib = &prframe->u.hdr.attrib; sub_skb = rtw_skb_alloc(nSubframe_Length + 12); - if (!sub_skb) { - DBG_871X("%s(): rtw_skb_alloc() Fail!!!\n", __func__); + if (!sub_skb) return NULL; - } skb_reserve(sub_skb, 12); skb_put_data(sub_skb, (pdata + ETH_HLEN), nSubframe_Length); @@ -95,15 +93,14 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 return sub_skb; } -void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib) +void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - int ret; /* Indicate the packets to upper layer */ if (pkt) { if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { - _pkt *pskb2 = NULL; + struct sk_buff *pskb2 = NULL; struct sta_info *psta = NULL; struct sta_priv *pstapriv = &padapter->stapriv; int bmcast = IS_MCAST(pattrib->dst); @@ -124,39 +121,22 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt _rtw_xmit_entry(pkt, pnetdev); - if (bmcast && pskb2) { + if (bmcast && pskb2) pkt = pskb2; - DBG_COUNTER(padapter->rx_logs.os_indicate_ap_mcast); - } else { - DBG_COUNTER(padapter->rx_logs.os_indicate_ap_forward); + else return; - } } } else { /* to APself */ - /* DBG_871X("to APSelf\n"); */ - DBG_COUNTER(padapter->rx_logs.os_indicate_ap_self); } } pkt->protocol = eth_type_trans(pkt, padapter->pnetdev); pkt->dev = padapter->pnetdev; -#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX - if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) - pkt->ip_summed = CHECKSUM_UNNECESSARY; - else - pkt->ip_summed = CHECKSUM_NONE; - -#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */ pkt->ip_summed = CHECKSUM_NONE; -#endif /* CONFIG_TCP_CSUM_OFFLOAD_RX */ - ret = rtw_netif_rx(padapter->pnetdev, pkt); - if (ret == NET_RX_SUCCESS) - DBG_COUNTER(padapter->rx_logs.os_netif_ok); - else - DBG_COUNTER(padapter->rx_logs.os_netif_err); + rtw_netif_rx(padapter->pnetdev, pkt); } } @@ -206,60 +186,19 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) wrqu.data.length = sizeof(ev); } -#ifdef CONFIG_AUTO_AP_MODE -static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *precv_frame) -{ - _pkt *skb = precv_frame->u.hdr.pkt; - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct sta_info *psta = precv_frame->u.hdr.psta; - - DBG_871X("eth rx: got eth_type = 0x%x\n", pattrib->eth_type); - - if (psta && psta->isrc && psta->pid > 0) { - u16 rx_pid; - - rx_pid = *(u16 *)(skb->data+ETH_HLEN); - - DBG_871X("eth rx(pid = 0x%x): sta(%pM) pid = 0x%x\n", - rx_pid, MAC_ARG(psta->hwaddr), psta->pid); - - if (rx_pid == psta->pid) { - int i; - u16 len = *(u16 *)(skb->data+ETH_HLEN+2); - DBG_871X("eth, RC: len = 0x%x\n", len); - - for (i = 0; i < len; i++) - DBG_871X("0x%x\n", *(skb->data+ETH_HLEN+4+i)); - - DBG_871X("eth, RC-end\n"); - } - - } - -} -#endif /* CONFIG_AUTO_AP_MODE */ - int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame) { struct recv_priv *precvpriv; struct __queue *pfree_recv_queue; - _pkt *skb; + struct sk_buff *skb; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - DBG_COUNTER(padapter->rx_logs.os_indicate); - precvpriv = &(padapter->recvpriv); pfree_recv_queue = &(precvpriv->free_recv_queue); skb = precv_frame->u.hdr.pkt; - if (skb == NULL) { - RT_TRACE(_module_recv_osdep_c_, _drv_err_, ("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n")); + if (!skb) goto _recv_indicatepkt_drop; - } - - RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("rtw_recv_indicatepkt():skb != NULL !!!\n")); - RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head =%p precv_frame->hdr.rx_data =%p\n", precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data)); - RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("precv_frame->hdr.rx_tail =%p precv_frame->u.hdr.rx_end =%p precv_frame->hdr.len =%d\n", precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end, precv_frame->u.hdr.len)); skb->data = precv_frame->u.hdr.rx_data; @@ -267,16 +206,6 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame skb->len = precv_frame->u.hdr.len; - RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n", skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len)); - -#ifdef CONFIG_AUTO_AP_MODE - if (0x8899 == pattrib->eth_type) { - rtw_os_ksocket_send(padapter, precv_frame); - - /* goto _recv_indicatepkt_drop; */ - } -#endif /* CONFIG_AUTO_AP_MODE */ - rtw_os_recv_indicate_pkt(padapter, skb, pattrib); /* pointers to NULL before rtw_free_recvframe() */ @@ -284,8 +213,6 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame rtw_free_recvframe(precv_frame, pfree_recv_queue); - RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n rtw_recv_indicatepkt :after rtw_os_recv_indicate_pkt!!!!\n")); - return _SUCCESS; _recv_indicatepkt_drop: @@ -293,7 +220,6 @@ _recv_indicatepkt_drop: /* enqueue back to free_recv_queue */ rtw_free_recvframe(precv_frame, pfree_recv_queue); - DBG_COUNTER(padapter->rx_logs.os_indicate_err); return _FAIL; } diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index 301ffff12e82ba590e74e971d1a8796fb0239df7..d2bf444117b88a33927f823620980de7d81f87e9 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -36,17 +36,12 @@ static const struct dev_pm_ops rtw_sdio_pm_ops = { .resume = rtw_sdio_resume, }; -struct sdio_drv_priv { - struct sdio_driver r871xs_drv; - int drv_registered; -}; - -static struct sdio_drv_priv sdio_drvpriv = { - .r871xs_drv.probe = rtw_drv_init, - .r871xs_drv.remove = rtw_dev_remove, - .r871xs_drv.name = "rtl8723bs", - .r871xs_drv.id_table = sdio_ids, - .r871xs_drv.drv = { +static struct sdio_driver rtl8723bs_sdio_driver = { + .probe = rtw_drv_init, + .remove = rtw_dev_remove, + .name = "rtl8723bs", + .id_table = sdio_ids, + .drv = { .pm = &rtw_sdio_pm_ops, } }; @@ -58,10 +53,8 @@ static void sd_sync_int_hdl(struct sdio_func *func) psdpriv = sdio_get_drvdata(func); - if (!psdpriv->if1) { - DBG_871X("%s if1 == NULL\n", __func__); + if (!psdpriv->if1) return; - } rtw_sdio_set_irq_thd(psdpriv, current); sd_int_hdl(psdpriv->if1); @@ -108,7 +101,9 @@ static void sdio_free_irq(struct dvobj_priv *dvobj) err = sdio_release_irq(func); if (err) { dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++; - DBG_871X_LEVEL(_drv_err_, "%s: sdio_release_irq FAIL(%d)!\n", __func__, err); + netdev_err(dvobj->if1->pnetdev, + "%s: sdio_release_irq FAIL(%d)!\n", + __func__, err); } else dvobj->drv_dbg.dbg_sdio_free_irq_cnt++; sdio_release_host(func); @@ -117,55 +112,6 @@ static void sdio_free_irq(struct dvobj_priv *dvobj) } } -#ifdef CONFIG_GPIO_WAKEUP -extern unsigned int oob_irq; -static irqreturn_t gpio_hostwakeup_irq_thread(int irq, void *data) -{ - struct adapter *padapter = data; - DBG_871X_LEVEL(_drv_always_, "gpio_hostwakeup_irq_thread\n"); - /* Disable interrupt before calling handler */ - /* disable_irq_nosync(oob_irq); */ - rtw_lock_suspend_timeout(HZ/2); - return IRQ_HANDLED; -} - -static u8 gpio_hostwakeup_alloc_irq(struct adapter *padapter) -{ - int err; - - if (oob_irq == 0) { - DBG_871X("oob_irq ZERO!\n"); - return _FAIL; - } - /* dont set it IRQF_TRIGGER_LOW, or wowlan */ - /* power is high after suspend */ - /* and failing can prevent can not sleep issue if */ - /* wifi gpio12 pin is not linked with CPU */ - err = request_threaded_irq(oob_irq, gpio_hostwakeup_irq_thread, NULL, - /* IRQF_TRIGGER_LOW | IRQF_ONESHOT, */ - IRQF_TRIGGER_FALLING, - "rtw_wifi_gpio_wakeup", padapter); - if (err < 0) { - DBG_871X("Oops: can't allocate gpio irq %d err:%d\n", oob_irq, err); - return false; - } else { - DBG_871X("allocate gpio irq %d ok\n", oob_irq); - } - - enable_irq_wake(oob_irq); - return _SUCCESS; -} - -static void gpio_hostwakeup_free_irq(struct adapter *padapter) -{ - if (oob_irq == 0) - return; - - disable_irq_wake(oob_irq); - free_irq(oob_irq, padapter); -} -#endif - static u32 sdio_init(struct dvobj_priv *dvobj) { struct sdio_data *psdio_data; @@ -181,14 +127,12 @@ static u32 sdio_init(struct dvobj_priv *dvobj) err = sdio_enable_func(func); if (err) { dvobj->drv_dbg.dbg_sdio_init_error_cnt++; - DBG_8192C(KERN_CRIT "%s: sdio_enable_func FAIL(%d)!\n", __func__, err); goto release; } err = sdio_set_block_size(func, 512); if (err) { dvobj->drv_dbg.dbg_sdio_init_error_cnt++; - DBG_8192C(KERN_CRIT "%s: sdio_set_block_size FAIL(%d)!\n", __func__, err); goto release; } psdio_data->block_transfer_len = 512; @@ -208,25 +152,19 @@ static void sdio_deinit(struct dvobj_priv *dvobj) struct sdio_func *func; int err; - - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+sdio_deinit\n")); - func = dvobj->intf_data.func; if (func) { sdio_claim_host(func); err = sdio_disable_func(func); - if (err) { + if (err) dvobj->drv_dbg.dbg_sdio_deinit_error_cnt++; - DBG_8192C(KERN_ERR "%s: sdio_disable_func(%d)\n", __func__, err); - } if (dvobj->irq_alloc) { err = sdio_release_irq(func); - if (err) { + if (err) dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++; - DBG_8192C(KERN_ERR "%s: sdio_release_irq(%d)\n", __func__, err); - } else + else dvobj->drv_dbg.dbg_sdio_free_irq_cnt++; } @@ -240,19 +178,17 @@ static struct dvobj_priv *sdio_dvobj_init(struct sdio_func *func) struct sdio_data *psdio; dvobj = devobj_init(); - if (dvobj == NULL) { + if (!dvobj) goto exit; - } sdio_set_drvdata(func, dvobj); psdio = &dvobj->intf_data; psdio->func = func; - if (sdio_init(dvobj) != _SUCCESS) { - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!\n", __func__)); + if (sdio_init(dvobj) != _SUCCESS) goto free_dvobj; - } + rtw_reset_continual_io_error(dvobj); status = _SUCCESS; @@ -289,10 +225,8 @@ void rtw_set_hal_ops(struct adapter *padapter) static void sd_intf_start(struct adapter *padapter) { - if (padapter == NULL) { - DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); + if (!padapter) return; - } /* hal dep */ rtw_hal_enable_interrupt(padapter); @@ -300,10 +234,8 @@ static void sd_intf_start(struct adapter *padapter) static void sd_intf_stop(struct adapter *padapter) { - if (padapter == NULL) { - DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); + if (!padapter) return; - } /* hal dep */ rtw_hal_disable_interrupt(padapter); @@ -318,9 +250,8 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct struct sdio_data *psdio = &dvobj->intf_data; padapter = vzalloc(sizeof(*padapter)); - if (padapter == NULL) { + if (!padapter) goto exit; - } padapter->dvobj = dvobj; dvobj->if1 = padapter; @@ -354,11 +285,8 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct padapter->intf_alloc_irq = &sdio_alloc_irq; padapter->intf_free_irq = &sdio_free_irq; - if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) { - RT_TRACE(_module_hci_intfs_c_, _drv_err_, - ("rtw_drv_init: Can't init io_priv\n")); + if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) goto free_hal_data; - } rtw_hal_read_chip_version(padapter); @@ -370,11 +298,8 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct rtw_hal_read_chip_info(padapter); /* 3 7. init driver common data */ - if (rtw_init_drv_sw(padapter) == _FAIL) { - RT_TRACE(_module_hci_intfs_c_, _drv_err_, - ("rtw_drv_init: Initialize driver software resource Failed!\n")); + if (rtw_init_drv_sw(padapter) == _FAIL) goto free_hal_data; - } rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)); @@ -384,13 +309,6 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct rtw_hal_disable_interrupt(padapter); - DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" - , padapter->bDriverStopped - , padapter->bSurpriseRemoved - , padapter->bup - , padapter->hw_init_completed - ); - status = _SUCCESS; free_hal_data: @@ -424,23 +342,12 @@ static void rtw_sdio_if1_deinit(struct adapter *if1) free_mlme_ap_info(if1); -#ifdef CONFIG_GPIO_WAKEUP - gpio_hostwakeup_free_irq(if1); -#endif - rtw_cancel_all_timer(if1); -#ifdef CONFIG_WOWLAN - adapter_to_pwrctl(if1)->wowlan_mode = false; - DBG_871X_LEVEL(_drv_always_, "%s wowlan_mode:%d\n", __func__, adapter_to_pwrctl(if1)->wowlan_mode); -#endif /* CONFIG_WOWLAN */ - rtw_dev_unload(if1); - DBG_871X("+r871xu_dev_remove, hw_init_completed =%d\n", if1->hw_init_completed); - if (if1->rtw_wdev) { + if (if1->rtw_wdev) rtw_wdev_free(if1->rtw_wdev); - } rtw_free_drv_sw(if1); @@ -459,44 +366,32 @@ static int rtw_drv_init( const struct sdio_device_id *id) { int status = _FAIL; - struct adapter *if1 = NULL, *if2 = NULL; + struct adapter *if1 = NULL; struct dvobj_priv *dvobj; dvobj = sdio_dvobj_init(func); - if (dvobj == NULL) { - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n")); + if (!dvobj) goto exit; - } if1 = rtw_sdio_if1_init(dvobj, id); - if (if1 == NULL) { - DBG_871X("rtw_init_primarystruct adapter Failed!\n"); + if (!if1) goto free_dvobj; - } /* dev_alloc_name && register_netdev */ status = rtw_drv_register_netdev(if1); if (status != _SUCCESS) - goto free_if2; + goto free_if1; if (sdio_alloc_irq(dvobj) != _SUCCESS) - goto free_if2; - -#ifdef CONFIG_GPIO_WAKEUP - gpio_hostwakeup_alloc_irq(if1); -#endif - - RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-871x_drv - drv_init, success!\n")); + goto free_if1; rtw_ndev_notifier_register(); status = _SUCCESS; -free_if2: - if (status != _SUCCESS && if2) { - } - if (status != _SUCCESS && if1) { +free_if1: + if (status != _SUCCESS && if1) rtw_sdio_if1_deinit(if1); - } + free_dvobj: if (status != _SUCCESS) sdio_dvobj_deinit(func); @@ -509,8 +404,6 @@ static void rtw_dev_remove(struct sdio_func *func) struct dvobj_priv *dvobj = sdio_get_drvdata(func); struct adapter *padapter = dvobj->if1; - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n")); - dvobj->processing_dev_remove = true; rtw_unregister_netdevs(dvobj); @@ -522,10 +415,8 @@ static void rtw_dev_remove(struct sdio_func *func) sdio_claim_host(func); sdio_readb(func, 0, &err); sdio_release_host(func); - if (err == -ENOMEDIUM) { + if (err == -ENOMEDIUM) padapter->bSurpriseRemoved = true; - DBG_871X(KERN_NOTICE "%s: device had been removed!\n", __func__); - } } rtw_ps_deny(padapter, PS_DENY_DRV_REMOVE); @@ -540,13 +431,8 @@ static void rtw_dev_remove(struct sdio_func *func) rtw_sdio_if1_deinit(padapter); sdio_dvobj_deinit(func); - - RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n")); } -extern int pm_netdev_open(struct net_device *pnetdev, u8 bnormal); -extern int pm_netdev_close(struct net_device *pnetdev, u8 bnormal); - static int rtw_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); @@ -555,13 +441,10 @@ static int rtw_sdio_suspend(struct device *dev) struct adapter *padapter = psdpriv->if1; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - if (padapter->bDriverStopped) { - DBG_871X("%s bDriverStopped = %d\n", __func__, padapter->bDriverStopped); + if (padapter->bDriverStopped) return 0; - } if (pwrpriv->bInSuspend) { - DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend); pdbgpriv->dbg_suspend_error_cnt++; return 0; } @@ -577,7 +460,6 @@ static int rtw_resume_process(struct adapter *padapter) if (!pwrpriv->bInSuspend) { pdbgpriv->dbg_resume_error_cnt++; - DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend); return -1; } @@ -593,57 +475,30 @@ static int rtw_sdio_resume(struct device *dev) int ret = 0; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; - DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid); - pdbgpriv->dbg_resume_cnt++; ret = rtw_resume_process(padapter); pmlmeext->last_scan_time = jiffies; - DBG_871X("<======== %s return %d\n", __func__, ret); return ret; } static int __init rtw_drv_entry(void) { - int ret = 0; - - DBG_871X_LEVEL(_drv_always_, "module init start\n"); - dump_drv_version(RTW_DBGDUMP); -#ifdef BTCOEXVERSION - DBG_871X_LEVEL(_drv_always_, "rtl8723bs BT-Coex version = %s\n", BTCOEXVERSION); -#endif /* BTCOEXVERSION */ - - sdio_drvpriv.drv_registered = true; + int ret; - ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv); - if (ret != 0) { - sdio_drvpriv.drv_registered = false; + ret = sdio_register_driver(&rtl8723bs_sdio_driver); + if (ret != 0) rtw_ndev_notifier_unregister(); - DBG_871X("%s: register driver failed!!(%d)\n", __func__, ret); - goto exit; - } - goto exit; - -exit: - DBG_871X_LEVEL(_drv_always_, "module init ret =%d\n", ret); return ret; } static void __exit rtw_drv_halt(void) { - DBG_871X_LEVEL(_drv_always_, "module exit start\n"); - - sdio_drvpriv.drv_registered = false; - - sdio_unregister_driver(&sdio_drvpriv.r871xs_drv); + sdio_unregister_driver(&rtl8723bs_sdio_driver); rtw_ndev_notifier_unregister(); - - DBG_871X_LEVEL(_drv_always_, "module exit success\n"); - - rtw_mstat_dump(RTW_DBGDUMP); } diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c index 079da433d811535ac10636d6eb10e009cdc1f994..5cedf775b6ef3c2c1491b3e76247cfec2fa491ca 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c @@ -40,10 +40,8 @@ u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return v; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -53,8 +51,6 @@ u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) v = sdio_f0_readb(func, addr, err); if (claim_needed) sdio_release_host(func); - if (err && *err) - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, *err, addr); return v; } @@ -76,19 +72,15 @@ s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; for (i = 0; i < cnt; i++) { pdata[i] = sdio_readb(func, addr + i, &err); - if (err) { - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, err, addr + i); + if (err) break; - } } return err; } @@ -112,10 +104,8 @@ s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -146,20 +136,15 @@ s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; for (i = 0; i < cnt; i++) { sdio_writeb(func, pdata[i], addr + i, &err); - if (err) { - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, - err, addr + i, pdata[i]); + if (err) break; - } } return err; } @@ -183,10 +168,8 @@ s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -213,10 +196,8 @@ u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return v; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -226,8 +207,6 @@ u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) v = sdio_readb(func, addr, err); if (claim_needed) sdio_release_host(func); - if (err && *err) - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, *err, addr); return v; } @@ -244,10 +223,8 @@ u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return v; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -261,8 +238,6 @@ u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) if (err && *err) { int i; - DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x\n", __func__, *err, addr, v); - *err = 0; for (i = 0; i < SD_IO_TRY_CNT; i++) { if (claim_needed) @@ -275,7 +250,6 @@ u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) rtw_reset_continual_io_error(psdiodev); break; } else { - DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x, try_cnt =%d\n", __func__, *err, addr, v, i); if ((-ESHUTDOWN == *err) || (-ENODEV == *err)) padapter->bSurpriseRemoved = true; @@ -285,12 +259,6 @@ u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) } } } - - if (i == SD_IO_TRY_CNT) - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x, val = 0x%x, try_cnt =%d\n", __func__, *err, addr, v, i); - else - DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x, try_cnt =%d\n", __func__, *err, addr, v, i); - } return v; } @@ -307,10 +275,8 @@ void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -320,8 +286,6 @@ void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err) sdio_writeb(func, v, addr, err); if (claim_needed) sdio_release_host(func); - if (err && *err) - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, *err, addr, v); } void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) @@ -336,10 +300,8 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -353,8 +315,6 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) if (err && *err) { int i; - DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x val = 0x%08x\n", __func__, *err, addr, v); - *err = 0; for (i = 0; i < SD_IO_TRY_CNT; i++) { if (claim_needed) @@ -366,7 +326,6 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) rtw_reset_continual_io_error(psdiodev); break; } else { - DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x, try_cnt =%d\n", __func__, *err, addr, v, i); if ((-ESHUTDOWN == *err) || (-ENODEV == *err)) padapter->bSurpriseRemoved = true; @@ -377,10 +336,6 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) } } - if (i == SD_IO_TRY_CNT) - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%08x, try_cnt =%d\n", __func__, *err, addr, v, i); - else - DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x val = 0x%08x, try_cnt =%d\n", __func__, *err, addr, v, i); } } @@ -412,10 +367,8 @@ s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; @@ -426,17 +379,13 @@ s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) for (i = 0; i < cnt; i++) { *(pbuf + i) = sdio_readb(func, addr + i, &err); - if (err) { - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, err, addr); + if (err) break; - } } return err; } err = sdio_memcpy_fromio(func, pdata, addr, cnt); - if (err) - DBG_871X(KERN_ERR "%s: FAIL(%d)! ADDR =%#x Size =%d\n", __func__, err, addr, cnt); return err; } @@ -468,10 +417,9 @@ s32 sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } + func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); @@ -512,10 +460,8 @@ s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; /* size = sdio_align_size(func, cnt); */ @@ -526,11 +472,8 @@ s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) for (i = 0; i < cnt; i++) { sdio_writeb(func, *(pbuf + i), addr + i, &err); - if (err) { - DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", - __func__, err, addr, *(pbuf + i)); + if (err) break; - } } return err; @@ -538,8 +481,6 @@ s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) size = cnt; err = sdio_memcpy_toio(func, addr, pdata, size); - if (err) - DBG_871X(KERN_ERR "%s: FAIL(%d)! ADDR =%#x Size =%d(%d)\n", __func__, err, addr, cnt, size); return err; } @@ -570,10 +511,8 @@ s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) psdiodev = pintfhdl->pintf_dev; psdio = &psdiodev->intf_data; - if (padapter->bSurpriseRemoved) { - /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ + if (padapter->bSurpriseRemoved) return err; - } func = psdio->func; claim_needed = rtw_sdio_claim_host_needed(func); diff --git a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c index 3f04b7a954ba07b3b151074adb94c6def5868d5d..0084589499b9fd67e39709538e76f5d919d20683 100644 --- a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c +++ b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c @@ -61,7 +61,7 @@ static void _rtw_reg_apply_flags(struct wiphy *wiphy) { struct adapter *padapter = wiphy_to_adapter(wiphy); struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set; + struct rt_channel_info *channel_set = pmlmeext->channel_set; u8 max_chan_nums = pmlmeext->max_chan_nums; struct ieee80211_supported_band *sband; @@ -150,7 +150,5 @@ void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct rtw_regulatory *reg = NULL; - DBG_8192C("%s\n", __func__); - _rtw_reg_notifier_apply(wiphy, request, reg); } diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c index b060a6a2df34e20ed656eb5de5209927152dcc2c..639408eaf4df245eff649df8854968d3f09c8a37 100644 --- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c @@ -15,7 +15,7 @@ uint rtw_remainder_len(struct pkt_file *pfile) return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start))); } -void _rtw_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) +void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile) { pfile->pkt = pktptr; pfile->cur_addr = pfile->buf_start = pktptr->data; @@ -39,7 +39,7 @@ uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) return len; } -sint rtw_endofpktfile(struct pkt_file *pfile) +signed int rtw_endofpktfile(struct pkt_file *pfile) { if (pfile->pkt_len == 0) return true; @@ -67,7 +67,7 @@ void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitb #define WMM_XMIT_THRESHOLD (NR_XMITFRAME * 2 / 5) -void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt) +void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt) { u16 queue; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -104,7 +104,7 @@ void rtw_os_xmit_schedule(struct adapter *padapter) complete(&pri_adapter->xmitpriv.xmit_comp); } -static void rtw_check_xmit_resource(struct adapter *padapter, _pkt *pkt) +static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt) { struct xmit_priv *pxmitpriv = &padapter->xmitpriv; u16 queue; @@ -112,10 +112,8 @@ static void rtw_check_xmit_resource(struct adapter *padapter, _pkt *pkt) queue = skb_get_queue_mapping(pkt); if (padapter->registrypriv.wifi_spec) { /* No free space for Tx, tx_worker is too slow */ - if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) { - /* DBG_871X("%s(): stop netif_subqueue[%d]\n", __func__, queue); */ + if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) netif_stop_subqueue(padapter->pnetdev, queue); - } } else { if (pxmitpriv->free_xmitframe_cnt <= 4) { if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) @@ -139,8 +137,6 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) int i; s32 res; - DBG_COUNTER(padapter->tx_logs.os_tx_m2u); - spin_lock_bh(&pstapriv->asoc_list_lock); phead = &pstapriv->asoc_list; plist = get_next(phead); @@ -160,20 +156,14 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) for (i = 0; i < chk_alive_num; i++) { psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); - if (!(psta->state & _FW_LINKED)) { - DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked); + if (!(psta->state & _FW_LINKED)) continue; - } /* avoid come from STA1 and send back STA1 */ if (!memcmp(psta->hwaddr, &skb->data[6], 6) || !memcmp(psta->hwaddr, null_addr, 6) || - !memcmp(psta->hwaddr, bc_addr, 6)) { - DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self); + !memcmp(psta->hwaddr, bc_addr, 6)) continue; - } - - DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry); newskb = rtw_skb_copy(skb); @@ -181,14 +171,10 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) memcpy(newskb->data, psta->hwaddr, 6); res = rtw_xmit(padapter, &newskb); if (res < 0) { - DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_xmit); - DBG_871X("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__); pxmitpriv->tx_drop++; dev_kfree_skb_any(newskb); } } else { - DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_skb); - DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __func__, __LINE__); pxmitpriv->tx_drop++; /* dev_kfree_skb_any(skb); */ return false; /* Caller shall tx this multicast frame via normal way. */ @@ -199,24 +185,15 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) return true; } -int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) +int _rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev) { struct adapter *padapter = rtw_netdev_priv(pnetdev); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; s32 res = 0; - DBG_COUNTER(padapter->tx_logs.os_tx); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); - - if (rtw_if_up(padapter) == false) { - DBG_COUNTER(padapter->tx_logs.os_tx_err_up); - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n")); - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __func__); - #endif + if (rtw_if_up(padapter) == false) goto drop_packet; - } rtw_check_xmit_resource(padapter, pkt); @@ -224,50 +201,35 @@ int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) && check_fwstate(pmlmepriv, WIFI_AP_STATE) == true && (IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data) - #ifdef CONFIG_TX_BCAST2UNI - || is_broadcast_mac_addr(pkt->data) - #endif ) && padapter->registrypriv.wifi_spec == 0) { if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) { res = rtw_mlcst2unicst(padapter, pkt); if (res) goto exit; - } else { - /* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */ - /* DBG_871X("!m2u); */ - DBG_COUNTER(padapter->tx_logs.os_tx_m2u_stop); } } res = rtw_xmit(padapter, &pkt); - if (res < 0) { - #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __func__); - #endif + if (res < 0) goto drop_packet; - } - RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts =%d\n", (u32)pxmitpriv->tx_pkts)); goto exit; drop_packet: pxmitpriv->tx_drop++; dev_kfree_skb_any(pkt); - RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop =%d\n", (u32)pxmitpriv->tx_drop)); exit: return 0; } -int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) +int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev) { int ret = 0; - if (pkt) { - rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize); + if (pkt) ret = _rtw_xmit_entry(pkt, pnetdev); - } return ret; } diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c index 0f369935fb6ce1d5e6c9aecd089d52bfe2f22da0..a305e15dfb9c3549890c405f7e27b3d7d87ca918 100644 --- a/drivers/staging/rts5208/xd.c +++ b/drivers/staging/rts5208/xd.c @@ -1628,7 +1628,6 @@ static int xd_finish_write(struct rtsx_chip *chip, int retval, zone_no; u16 log_off; - dev_dbg(rtsx_dev(chip), "%s ", __func__); 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); @@ -1806,7 +1805,6 @@ int xd_delay_write(struct rtsx_chip *chip) int retval; if (delay_write->delay_write_flag) { - dev_dbg(rtsx_dev(chip), "%s\n", __func__); retval = xd_switch_clock(chip); if (retval != STATUS_SUCCESS) return STATUS_FAIL; diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 19823c7277a44c0c211f33b1dd911127d83352eb..23eefd019ec91feec7737f1d7a10904f059fb705 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -55,23 +55,27 @@ struct lynx_accel { volatile unsigned char __iomem *dpPortBase; /* function pointers */ - void (*de_init)(struct lynx_accel *); + void (*de_init)(struct lynx_accel *accel); int (*de_wait)(void);/* see if hardware ready to work */ - int (*de_fillrect)(struct lynx_accel *, - u32, u32, u32, u32, - u32, u32, u32, u32, u32); - - int (*de_copyarea)(struct lynx_accel *, - u32, u32, u32, u32, - u32, u32, u32, u32, - u32, u32, u32, u32); - - int (*de_imageblit)(struct lynx_accel *, const char *, - u32, u32, u32, u32, - u32, u32, u32, u32, - u32, u32, u32, u32); + int (*de_fillrect)(struct lynx_accel *accel, + u32 base, u32 pitch, u32 bpp, + u32 x, u32 y, u32 width, u32 height, + u32 color, u32 rop); + + int (*de_copyarea)(struct lynx_accel *accel, + u32 s_base, u32 s_pitch, + u32 sx, u32 sy, + u32 d_base, u32 d_pitch, + u32 bpp, u32 dx, u32 dy, + u32 width, u32 height, + u32 rop2); + + int (*de_imageblit)(struct lynx_accel *accel, const char *p_srcbuf, + u32 src_delta, u32 start_bit, u32 d_base, u32 d_pitch, + u32 byte_per_pixel, u32 dx, u32 dy, u32 width, + u32 height, u32 f_color, u32 b_color, u32 rop2); }; diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 0433536930a981f02b056f07c204422fd9543f6e..a3bc568c660d4d6b69ff9f5ce24af8361c863b5c 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -122,7 +122,6 @@ struct chanstat { * @n_rcv_packets_not_accepted: # bogs rcv packets. * @queuefullmsg_logged: * @struct chstat: - * @struct irq_poll_timer: * @struct napi: * @struct cmdrsp: */ @@ -183,7 +182,6 @@ struct visornic_devdata { int queuefullmsg_logged; struct chanstat chstat; - struct timer_list irq_poll_timer; struct napi_struct napi; struct uiscmdrsp cmdrsp[SIZEOF_CMDRSP]; }; @@ -341,7 +339,7 @@ static void visornic_serverdown_complete(struct visornic_devdata *devdata) struct net_device *netdev = devdata->netdev; /* Stop polling for interrupts */ - del_timer_sync(&devdata->irq_poll_timer); + visorbus_disable_channel_interrupts(devdata->dev); rtnl_lock(); dev_close(netdev); @@ -534,7 +532,7 @@ static int visornic_disable_with_timeout(struct net_device *netdev, return err; /* wait for ack to arrive before we try to free rcv buffers - * NOTE: the other end automatically unposts the rcv buffers when + * NOTE: the other end automatically unposts the rcv buffers * when it gets a disable. */ spin_lock_irqsave(&devdata->priv_lock, flags); @@ -1749,17 +1747,17 @@ static int visornic_poll(struct napi_struct *napi, int budget) return rx_count; } -/* poll_for_irq - checks the status of the response queue - * @t: pointer to the 'struct timer_list' from which we can retrieve the - * the visornic devdata struct. +/* visornic_channel_interrupt - checks the status of the response queue * * Main function of the vnic_incoming thread. Periodically check the response * queue and drain it if needed. */ -static void poll_for_irq(struct timer_list *t) +static void visornic_channel_interrupt(struct visor_device *dev) { - struct visornic_devdata *devdata = from_timer(devdata, t, - irq_poll_timer); + struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); + + if (!devdata) + return; if (!visorchannel_signalempty( devdata->dev->visorchannel, @@ -1768,7 +1766,6 @@ static void poll_for_irq(struct timer_list *t) atomic_set(&devdata->interrupt_rcvd, 0); - mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); } /* visornic_probe - probe function for visornic devices @@ -1890,13 +1887,6 @@ static int visornic_probe(struct visor_device *dev) /* Let's start our threads to get responses */ netif_napi_add(netdev, &devdata->napi, visornic_poll, NAPI_WEIGHT); - timer_setup(&devdata->irq_poll_timer, poll_for_irq, 0); - /* Note: This time has to start running before the while - * loop below because the napi routine is responsible for - * setting enab_dis_acked - */ - mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); - channel_offset = offsetof(struct visor_io_channel, channel_header.features); err = visorbus_read_channel(dev, channel_offset, &features, 8); @@ -1949,7 +1939,7 @@ cleanup_register_netdev: unregister_netdev(netdev); cleanup_napi_add: - del_timer_sync(&devdata->irq_poll_timer); + visorbus_disable_channel_interrupts(dev); netif_napi_del(&devdata->napi); cleanup_xmit_cmdrsp: @@ -2017,7 +2007,7 @@ static void visornic_remove(struct visor_device *dev) /* this will call visornic_close() */ unregister_netdev(netdev); - del_timer_sync(&devdata->irq_poll_timer); + visorbus_disable_channel_interrupts(devdata->dev); netif_napi_del(&devdata->napi); dev_set_drvdata(&dev->device, NULL); @@ -2091,7 +2081,7 @@ static int visornic_resume(struct visor_device *dev, * we can start using the device again. * TODO: State transitions */ - mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); + visorbus_enable_channel_interrupts(dev); rtnl_lock(); dev_open(netdev, NULL); @@ -2113,7 +2103,7 @@ static struct visor_driver visornic_driver = { .remove = visornic_remove, .pause = visornic_pause, .resume = visornic_resume, - .channel_interrupt = NULL, + .channel_interrupt = visornic_channel_interrupt, }; /* visornic_init - init function diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c index 542aff131d0629ac406e781b4b8dfca7ba5b06f0..f2ef1d641e70c627802400c14d8ed42ef29b9353 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c @@ -14,14 +14,14 @@ static const struct snd_pcm_hardware snd_bcm2835_playback_hw = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_APPLPTR | SNDRV_PCM_INFO_BATCH), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = 128 * 1024, + .channels_max = 8, + .buffer_bytes_max = 512 * 1024, .period_bytes_min = 1 * 1024, - .period_bytes_max = 128 * 1024, + .period_bytes_max = 512 * 1024, .periods_min = 1, .periods_max = 128, }; diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO index 0bcb8f158afc42024469daccef85521deff08877..39810ce017cd30412183251cb8121d2232242a6a 100644 --- a/drivers/staging/vc04_services/interface/TODO +++ b/drivers/staging/vc04_services/interface/TODO @@ -27,8 +27,8 @@ unused. 3) Make driver more portable Building this driver with arm/multi_v7_defconfig or arm64/defconfig -leads to data corruption during the following command: - +leads to data corruption during the following command: + vchiq_test -f 1 This should be fixed. @@ -37,7 +37,7 @@ This should be fixed. Even the VPU firmware doesn't support a VCHI re-connect, the driver should properly handle a module unload. This also includes that all -resouces must be freed (kthreads, debugfs entries, ...) and global +resources must be freed (kthreads, debugfs entries, ...) and global variables avoided. 5) Cleanup logging mechanism 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 59e45dc03a977a049dd90aa3bea392c04ce86d7e..e39897c38e6a904aa4cb2fa78261323b78e6e0ba 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -2332,8 +2332,10 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, int *entity_uc; int local_uc; - if (!arm_state) + if (!arm_state) { + ret = VCHIQ_ERROR; goto out; + } vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); @@ -2389,8 +2391,10 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service) char entity[16]; int *entity_uc; - if (!arm_state) + if (!arm_state) { + ret = VCHIQ_ERROR; goto out; + } vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); @@ -2734,7 +2738,7 @@ static int vchiq_probe(struct platform_device *pdev) return -ENOENT; } - drvdata->fw = rpi_firmware_get(fw_node); + drvdata->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!drvdata->fw) return -EPROBE_DEFER; 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 0b0a97bfd01cdb8646e187a86a4dfaf0e8c86cae..517a8c9b41ed046f46f4073d6027609c1520c517 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -28,6 +28,8 @@ ((unsigned int)(info - state->slot_info)) #define SLOT_QUEUE_INDEX_FROM_POS(pos) \ ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE)) +#define SLOT_QUEUE_INDEX_FROM_POS_MASKED(pos) \ + (SLOT_QUEUE_INDEX_FROM_POS(pos) & VCHIQ_SLOT_QUEUE_MASK) #define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1)) @@ -338,7 +340,7 @@ static void mark_service_closing_internal(struct vchiq_service *service, int sh_thread) { struct vchiq_state *state = service->state; - struct vchiq_service_quota *service_quota; + struct vchiq_service_quota *quota; service->closing = 1; @@ -357,8 +359,8 @@ mark_service_closing_internal(struct vchiq_service *service, int sh_thread) } /* Unblock any sending thread. */ - service_quota = &state->service_quotas[service->localport]; - complete(&service_quota->quota_event); + quota = &state->service_quotas[service->localport]; + complete("a->quota_event); } static void @@ -537,22 +539,23 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service, int poll_type) { u32 value; + int index; - if (service) { - do { - value = atomic_read(&service->poll_flags); - } while (atomic_cmpxchg(&service->poll_flags, value, - value | BIT(poll_type)) != value); + if (!service) + goto skip_service; - do { - value = atomic_read(&state->poll_services[ - service->localport>>5]); - } while (atomic_cmpxchg( - &state->poll_services[service->localport>>5], - value, value | BIT(service->localport & 0x1f)) - != value); - } + do { + value = atomic_read(&service->poll_flags); + } while (atomic_cmpxchg(&service->poll_flags, value, + value | BIT(poll_type)) != value); + + index = BITSET_WORD(service->localport); + do { + value = atomic_read(&state->poll_services[index]); + } while (atomic_cmpxchg(&state->poll_services[index], + value, value | BIT(service->localport & 0x1f)) != value); +skip_service: state->poll_needed = 1; wmb(); @@ -612,8 +615,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking) } slot_index = local->slot_queue[ - SLOT_QUEUE_INDEX_FROM_POS(tx_pos) & - VCHIQ_SLOT_QUEUE_MASK]; + SLOT_QUEUE_INDEX_FROM_POS_MASKED(tx_pos)]; state->tx_data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index); } @@ -674,28 +676,28 @@ process_free_queue(struct vchiq_state *state, BITSET_T *service_found, if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA) { int port = VCHIQ_MSG_SRCPORT(msgid); - struct vchiq_service_quota *service_quota = + struct vchiq_service_quota *quota = &state->service_quotas[port]; int count; spin_lock("a_spinlock); - count = service_quota->message_use_count; + count = quota->message_use_count; if (count > 0) - service_quota->message_use_count = + quota->message_use_count = count - 1; spin_unlock("a_spinlock); - if (count == service_quota->message_quota) + if (count == quota->message_quota) /* * Signal the service that it * has dropped below its quota */ - complete(&service_quota->quota_event); + complete("a->quota_event); else if (count == 0) { vchiq_log_error(vchiq_core_log_level, "service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)", port, - service_quota->message_use_count, + quota->message_use_count, header, msgid, header->msgid, header->size); WARN(1, "invalid message use count\n"); @@ -705,9 +707,9 @@ process_free_queue(struct vchiq_state *state, BITSET_T *service_found, BITSET_SET(service_found, port); spin_lock("a_spinlock); - count = service_quota->slot_use_count; + count = quota->slot_use_count; if (count > 0) - service_quota->slot_use_count = + quota->slot_use_count = count - 1; spin_unlock("a_spinlock); @@ -716,7 +718,7 @@ process_free_queue(struct vchiq_state *state, BITSET_T *service_found, * Signal the service in case * it has dropped below its quota */ - complete(&service_quota->quota_event); + complete("a->quota_event); vchiq_log_trace( vchiq_core_log_level, "%d: pfq:%d %x@%pK - slot_use->%d", @@ -822,7 +824,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, void *context, size_t size, int flags) { struct vchiq_shared_state *local; - struct vchiq_service_quota *service_quota = NULL; + struct vchiq_service_quota *quota = NULL; struct vchiq_header *header; int type = VCHIQ_MSG_TYPE(msgid); @@ -856,7 +858,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, return VCHIQ_ERROR; } - service_quota = &state->service_quotas[service->localport]; + quota = &state->service_quotas[service->localport]; spin_lock("a_spinlock); @@ -893,22 +895,21 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, } } - while ((service_quota->message_use_count == - service_quota->message_quota) || - ((tx_end_index != service_quota->previous_tx_index) && - (service_quota->slot_use_count == - service_quota->slot_quota))) { + while ((quota->message_use_count == quota->message_quota) || + ((tx_end_index != quota->previous_tx_index) && + (quota->slot_use_count == + quota->slot_quota))) { spin_unlock("a_spinlock); vchiq_log_trace(vchiq_core_log_level, "%d: qm:%d %s,%zx - quota stall (msg %d, slot %d)", state->id, service->localport, msg_type_str(type), size, - service_quota->message_use_count, - service_quota->slot_use_count); + 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( - &service_quota->quota_event)) + "a->quota_event)) return VCHIQ_RETRY; if (service->closing) return VCHIQ_ERROR; @@ -974,7 +975,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, (size_t)callback_result)); spin_lock("a_spinlock); - service_quota->message_use_count++; + quota->message_use_count++; tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1); @@ -992,9 +993,9 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, * If this isn't the same slot last used by this service, * the service's slot_use_count must be increased. */ - if (tx_end_index != service_quota->previous_tx_index) { - service_quota->previous_tx_index = tx_end_index; - slot_use_count = ++service_quota->slot_use_count; + if (tx_end_index != quota->previous_tx_index) { + quota->previous_tx_index = tx_end_index; + slot_use_count = ++quota->slot_use_count; } else { slot_use_count = 0; } @@ -1567,8 +1568,7 @@ parse_rx_slots(struct vchiq_state *state) WARN_ON(!((state->rx_pos & VCHIQ_SLOT_MASK) == 0)); rx_index = remote->slot_queue[ - SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) & - VCHIQ_SLOT_QUEUE_MASK]; + SLOT_QUEUE_INDEX_FROM_POS_MASKED(state->rx_pos)]; state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state, rx_index); state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index); @@ -1681,8 +1681,7 @@ parse_rx_slots(struct vchiq_state *state) "%d: prs OPENACK@%pK,%x (%d->%d) v:%d", state->id, header, size, remoteport, localport, service->peer_version); - if (service->srvstate == - VCHIQ_SRVSTATE_OPENING) { + if (service->srvstate == VCHIQ_SRVSTATE_OPENING) { service->remoteport = remoteport; vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN); @@ -1716,9 +1715,8 @@ parse_rx_slots(struct vchiq_state *state) "%d: prs DATA@%pK,%x (%d->%d)", state->id, header, size, remoteport, localport); - if ((service->remoteport == remoteport) - && (service->srvstate == - VCHIQ_SRVSTATE_OPEN)) { + if ((service->remoteport == remoteport) && + (service->srvstate == VCHIQ_SRVSTATE_OPEN)) { header->msgid = msgid | VCHIQ_MSGID_CLAIMED; claim_slot(state->rx_info); DEBUG_TRACE(PARSE_LINE); @@ -1753,9 +1751,8 @@ parse_rx_slots(struct vchiq_state *state) break; case VCHIQ_MSG_BULK_RX_DONE: case VCHIQ_MSG_BULK_TX_DONE: - if ((service->remoteport == remoteport) - && (service->srvstate != - VCHIQ_SRVSTATE_FREE)) { + if ((service->remoteport == remoteport) && + (service->srvstate != VCHIQ_SRVSTATE_FREE)) { struct vchiq_bulk_queue *queue; struct vchiq_bulk *bulk; @@ -2209,9 +2206,9 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero) state->slot_queue_available = 0; for (i = 0; i < VCHIQ_MAX_SERVICES; i++) { - struct vchiq_service_quota *service_quota = + struct vchiq_service_quota *quota = &state->service_quotas[i]; - init_completion(&service_quota->quota_event); + init_completion("a->quota_event); } for (i = local->slot_first; i <= local->slot_last; i++) { @@ -2366,7 +2363,7 @@ vchiq_add_service_internal(struct vchiq_state *state, { struct vchiq_service *service; struct vchiq_service __rcu **pservice = NULL; - struct vchiq_service_quota *service_quota; + struct vchiq_service_quota *quota; int ret; int i; @@ -2445,10 +2442,9 @@ vchiq_add_service_internal(struct vchiq_state *state, srv = rcu_dereference(state->services[i]); if (!srv) pservice = &state->services[i]; - else if ((srv->public_fourcc == params->fourcc) - && ((srv->instance != instance) || - (srv->base.callback != - params->callback))) { + else if ((srv->public_fourcc == params->fourcc) && + ((srv->instance != instance) || + (srv->base.callback != params->callback))) { /* * There is another server using this * fourcc which doesn't match. @@ -2481,11 +2477,11 @@ vchiq_add_service_internal(struct vchiq_state *state, return NULL; } - service_quota = &state->service_quotas[service->localport]; - service_quota->slot_quota = state->default_slot_quota; - service_quota->message_quota = state->default_message_quota; - if (service_quota->slot_use_count == 0) - service_quota->previous_tx_index = + quota = &state->service_quotas[service->localport]; + quota->slot_quota = state->default_slot_quota; + quota->message_quota = state->default_message_quota; + if (quota->slot_use_count == 0) + quota->previous_tx_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos) - 1; @@ -2526,24 +2522,27 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id) &payload, sizeof(payload), QMFLAGS_IS_BLOCKING); - if (status == VCHIQ_SUCCESS) { - /* Wait for the ACK/NAK */ - if (wait_for_completion_interruptible(&service->remove_event)) { - status = VCHIQ_RETRY; - vchiq_release_service_internal(service); - } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) && - (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) { - if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) - vchiq_log_error(vchiq_core_log_level, - "%d: osi - srvstate = %s (ref %u)", - service->state->id, - srvstate_names[service->srvstate], - kref_read(&service->ref_count)); - status = VCHIQ_ERROR; - VCHIQ_SERVICE_STATS_INC(service, error_count); - vchiq_release_service_internal(service); - } + + if (status != VCHIQ_SUCCESS) + return status; + + /* Wait for the ACK/NAK */ + if (wait_for_completion_interruptible(&service->remove_event)) { + status = VCHIQ_RETRY; + vchiq_release_service_internal(service); + } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) && + (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) { + if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) + vchiq_log_error(vchiq_core_log_level, + "%d: osi - srvstate = %s (ref %u)", + service->state->id, + srvstate_names[service->srvstate], + kref_read(&service->ref_count)); + status = VCHIQ_ERROR; + VCHIQ_SERVICE_STATS_INC(service, error_count); + vchiq_release_service_internal(service); } + return status; } @@ -2939,8 +2938,8 @@ vchiq_close_service(unsigned int handle) service->state->id, service->localport); if ((service->srvstate == VCHIQ_SRVSTATE_FREE) || - (service->srvstate == VCHIQ_SRVSTATE_LISTENING) || - (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) { + (service->srvstate == VCHIQ_SRVSTATE_LISTENING) || + (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) { unlock_service(service); return VCHIQ_ERROR; } @@ -2963,8 +2962,8 @@ vchiq_close_service(unsigned int handle) } if ((service->srvstate == VCHIQ_SRVSTATE_FREE) || - (service->srvstate == VCHIQ_SRVSTATE_LISTENING) || - (service->srvstate == VCHIQ_SRVSTATE_OPEN)) + (service->srvstate == VCHIQ_SRVSTATE_LISTENING) || + (service->srvstate == VCHIQ_SRVSTATE_OPEN)) break; vchiq_log_warning(vchiq_core_log_level, @@ -2974,8 +2973,8 @@ vchiq_close_service(unsigned int handle) } if ((status == VCHIQ_SUCCESS) && - (service->srvstate != VCHIQ_SRVSTATE_FREE) && - (service->srvstate != VCHIQ_SRVSTATE_LISTENING)) + (service->srvstate != VCHIQ_SRVSTATE_FREE) && + (service->srvstate != VCHIQ_SRVSTATE_LISTENING)) status = VCHIQ_ERROR; unlock_service(service); @@ -3006,7 +3005,7 @@ vchiq_remove_service(unsigned int handle) mark_service_closing(service); if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) || - (current == service->state->slot_handler_thread)) { + (current == service->state->slot_handler_thread)) { /* * Make it look like a client, because it must be removed and * not left in the LISTENING state. @@ -3027,7 +3026,7 @@ vchiq_remove_service(unsigned int handle) } if ((service->srvstate == VCHIQ_SRVSTATE_FREE) || - (service->srvstate == VCHIQ_SRVSTATE_OPEN)) + (service->srvstate == VCHIQ_SRVSTATE_OPEN)) break; vchiq_log_warning(vchiq_core_log_level, @@ -3037,7 +3036,7 @@ vchiq_remove_service(unsigned int handle) } if ((status == VCHIQ_SUCCESS) && - (service->srvstate != VCHIQ_SRVSTATE_FREE)) + (service->srvstate != VCHIQ_SRVSTATE_FREE)) status = VCHIQ_ERROR; unlock_service(service); @@ -3070,9 +3069,16 @@ enum vchiq_status vchiq_bulk_transfer(unsigned int handle, enum vchiq_status status = VCHIQ_ERROR; int payload[2]; - if (!service || service->srvstate != VCHIQ_SRVSTATE_OPEN || - (!offset && !uoffset) || - vchiq_check_service(service) != VCHIQ_SUCCESS) + if (!service) + goto error_exit; + + if (service->srvstate != VCHIQ_SRVSTATE_OPEN) + goto error_exit; + + if (!offset && !uoffset) + goto error_exit; + + if (vchiq_check_service(service) != VCHIQ_SUCCESS) goto error_exit; switch (mode) { @@ -3216,8 +3222,10 @@ vchiq_queue_message(unsigned int handle, struct vchiq_service *service = find_service_by_handle(handle); enum vchiq_status status = VCHIQ_ERROR; - if (!service || - (vchiq_check_service(service) != VCHIQ_SUCCESS)) + if (!service) + goto error_exit; + + if (vchiq_check_service(service) != VCHIQ_SUCCESS) goto error_exit; if (!size) { @@ -3299,7 +3307,7 @@ vchiq_release_message(unsigned int handle, slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header); if ((slot_index >= remote->slot_first) && - (slot_index <= remote->slot_last)) { + (slot_index <= remote->slot_last)) { int msgid = header->msgid; if (msgid & VCHIQ_MSGID_CLAIMED) { @@ -3328,10 +3336,15 @@ vchiq_get_peer_version(unsigned int handle, short *peer_version) enum vchiq_status status = VCHIQ_ERROR; struct vchiq_service *service = find_service_by_handle(handle); - if (!service || - (vchiq_check_service(service) != VCHIQ_SUCCESS) || - !peer_version) + if (!service) + goto exit; + + if (vchiq_check_service(service) != VCHIQ_SUCCESS) goto exit; + + if (!peer_version) + goto exit; + *peer_version = service->peer_version; status = VCHIQ_SUCCESS; @@ -3358,77 +3371,70 @@ vchiq_set_service_option(unsigned int handle, { struct vchiq_service *service = find_service_by_handle(handle); enum vchiq_status status = VCHIQ_ERROR; + struct vchiq_service_quota *quota; - if (service) { - switch (option) { - case VCHIQ_SERVICE_OPTION_AUTOCLOSE: - service->auto_close = value; - status = VCHIQ_SUCCESS; - break; + if (!service) + return VCHIQ_ERROR; - case VCHIQ_SERVICE_OPTION_SLOT_QUOTA: { - struct vchiq_service_quota *service_quota = - &service->state->service_quotas[ - service->localport]; - if (value == 0) - value = service->state->default_slot_quota; - if ((value >= service_quota->slot_use_count) && - (value < (unsigned short)~0)) { - service_quota->slot_quota = value; - if ((value >= service_quota->slot_use_count) && - (service_quota->message_quota >= - service_quota->message_use_count)) { - /* - * Signal the service that it may have - * dropped below its quota - */ - complete(&service_quota->quota_event); - } - status = VCHIQ_SUCCESS; - } - } break; - - case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA: { - struct vchiq_service_quota *service_quota = - &service->state->service_quotas[ - service->localport]; - if (value == 0) - value = service->state->default_message_quota; - if ((value >= service_quota->message_use_count) && - (value < (unsigned short)~0)) { - service_quota->message_quota = value; - if ((value >= - service_quota->message_use_count) && - (service_quota->slot_quota >= - service_quota->slot_use_count)) - /* - * Signal the service that it may have - * dropped below its quota - */ - complete(&service_quota->quota_event); - status = VCHIQ_SUCCESS; - } - } break; + switch (option) { + case VCHIQ_SERVICE_OPTION_AUTOCLOSE: + service->auto_close = value; + status = VCHIQ_SUCCESS; + break; - case VCHIQ_SERVICE_OPTION_SYNCHRONOUS: - if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) || - (service->srvstate == - VCHIQ_SRVSTATE_LISTENING)) { - service->sync = value; - status = VCHIQ_SUCCESS; - } - break; + case VCHIQ_SERVICE_OPTION_SLOT_QUOTA: + quota = &service->state->service_quotas[service->localport]; + if (value == 0) + value = service->state->default_slot_quota; + if ((value >= quota->slot_use_count) && + (value < (unsigned short)~0)) { + quota->slot_quota = value; + if ((value >= quota->slot_use_count) && + (quota->message_quota >= quota->message_use_count)) + /* + * Signal the service that it may have + * dropped below its quota + */ + complete("a->quota_event); + status = VCHIQ_SUCCESS; + } + break; - case VCHIQ_SERVICE_OPTION_TRACE: - service->trace = value; + case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA: + quota = &service->state->service_quotas[service->localport]; + if (value == 0) + value = service->state->default_message_quota; + if ((value >= quota->message_use_count) && + (value < (unsigned short)~0)) { + quota->message_quota = value; + if ((value >= quota->message_use_count) && + (quota->slot_quota >= quota->slot_use_count)) + /* + * Signal the service that it may have + * dropped below its quota + */ + complete("a->quota_event); status = VCHIQ_SUCCESS; - break; + } + break; - default: - break; + case VCHIQ_SERVICE_OPTION_SYNCHRONOUS: + if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) || + (service->srvstate == VCHIQ_SRVSTATE_LISTENING)) { + service->sync = value; + status = VCHIQ_SUCCESS; } - unlock_service(service); + break; + + case VCHIQ_SERVICE_OPTION_TRACE: + service->trace = value; + status = VCHIQ_SUCCESS; + break; + + default: + break; } + unlock_service(service); return status; } @@ -3592,7 +3598,7 @@ int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service) if (service->srvstate != VCHIQ_SRVSTATE_FREE) { char remoteport[30]; - struct vchiq_service_quota *service_quota = + struct vchiq_service_quota *quota = &service->state->service_quotas[service->localport]; int fourcc = service->base.fourcc; int tx_pending, rx_pending; @@ -3612,10 +3618,10 @@ int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service) " '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)", VCHIQ_FOURCC_AS_4CHARS(fourcc), remoteport, - service_quota->message_use_count, - service_quota->message_quota, - service_quota->slot_use_count, - service_quota->slot_quota); + quota->message_use_count, + quota->message_quota, + quota->slot_use_count, + quota->slot_quota); err = vchiq_dump(dump_context, buf, len + 1); if (err) @@ -3702,24 +3708,22 @@ vchiq_loud_error_footer(void) enum vchiq_status vchiq_send_remote_use(struct vchiq_state *state) { - enum vchiq_status status = VCHIQ_RETRY; + if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) + return VCHIQ_RETRY; - if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) - status = queue_message(state, NULL, - VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0), - NULL, NULL, 0, 0); - return status; + return queue_message(state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0), + NULL, NULL, 0, 0); } enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state) { - enum vchiq_status status = VCHIQ_RETRY; + if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) + return VCHIQ_RETRY; - if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) - status = queue_message(state, NULL, - VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0), - NULL, NULL, 0, 0); - return status; + return queue_message(state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0), + NULL, NULL, 0, 0); } void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, 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 ec2f033cdf321364168f976b07e7c642ce4941af..e9bf055a4ca958fff8a131080891dd7fb3425192 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h @@ -7,7 +7,7 @@ #include "vchiq_core.h" struct vchiq_debugfs_node { - struct dentry *dentry; + struct dentry *dentry; }; void vchiq_debugfs_init(void); diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 9097bcbd67d8226bc68315235af1de25e09cf5e4..06bca7be5203ff888e3578596600b5a3c00b34ac 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -432,7 +432,7 @@ buffer_from_host(struct vchiq_mmal_instance *instance, m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; - /* clear buffer type sepecific data */ + /* clear buffer type specific data */ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, sizeof(m.u.buffer_from_host.buffer_header_type_specific)); @@ -927,7 +927,7 @@ release_msg: return ret; } -/* create comonent on vc */ +/* create component on vc */ static int create_component(struct vchiq_mmal_instance *instance, struct vchiq_mmal_component *component, const char *name) diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index 1aa675241599e8ee24f381c88b393802bed0528e..d89163299172c6a37bf0548f507be93248a976f7 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -52,7 +52,7 @@ /*--------------------- Static Variables --------------------------*/ #define CB_VT3253_INIT_FOR_RFMD 446 -static const unsigned char byVT3253InitTab_RFMD[CB_VT3253_INIT_FOR_RFMD][2] = { +static const unsigned char by_vt3253_init_tab_rfmd[CB_VT3253_INIT_FOR_RFMD][2] = { {0x00, 0x30}, {0x01, 0x00}, {0x02, 0x00}, @@ -2002,8 +2002,8 @@ bool bb_vt3253_init(struct vnt_private *priv) if (by_local_id <= REV_ID_VT3253_A1) { for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) result &= bb_write_embedded(priv, - byVT3253InitTab_RFMD[ii][0], - byVT3253InitTab_RFMD[ii][1]); + 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++) diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c index 889fc22f19bd15e38059322786498a0665062cd2..cf46ee63681a5701a5d817ff7ba096f5a60fe579 100644 --- a/drivers/staging/vt6655/channel.c +++ b/drivers/staging/vt6655/channel.c @@ -114,40 +114,38 @@ static struct ieee80211_supported_band vnt_supported_5ghz_band = { .n_bitrates = ARRAY_SIZE(vnt_rates_a), }; -void vnt_init_bands(struct vnt_private *priv) +static void vnt_init_band(struct vnt_private *priv, + struct ieee80211_supported_band *supported_band, + enum nl80211_band band) { - struct ieee80211_channel *ch; 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) +{ switch (priv->byRFType) { case RF_AIROHA7230: case RF_UW2452: case RF_NOTHING: default: - ch = vnt_channels_5ghz; - - for (i = 0; i < ARRAY_SIZE(vnt_channels_5ghz); i++) { - ch[i].max_power = 0x3f; - ch[i].flags = IEEE80211_CHAN_NO_HT40; - } - - priv->hw->wiphy->bands[NL80211_BAND_5GHZ] = - &vnt_supported_5ghz_band; + vnt_init_band(priv, &vnt_supported_5ghz_band, + NL80211_BAND_5GHZ); fallthrough; case RF_RFMD2959: case RF_AIROHA: case RF_AL2230S: case RF_UW2451: case RF_VT3226: - ch = vnt_channels_2ghz; - - for (i = 0; i < ARRAY_SIZE(vnt_channels_2ghz); i++) { - ch[i].max_power = 0x3f; - ch[i].flags = IEEE80211_CHAN_NO_HT40; - } - - priv->hw->wiphy->bands[NL80211_BAND_2GHZ] = - &vnt_supported_2ghz_band; + vnt_init_band(priv, &vnt_supported_2ghz_band, + NL80211_BAND_2GHZ); break; } } @@ -155,8 +153,8 @@ void vnt_init_bands(struct vnt_private *priv) /** * set_channel() - Set NIC media channel * - * @pDeviceHandler: The adapter to be set - * @uConnectionChannel: Channel to be set + * @priv: The adapter to be set + * @ch: Channel to be set * * Return Value: true if succeeded; false if failed. * diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c index 10f3dfda83b54d68f0c4300e4bdc22111fea24b9..396736eee690a0cb7592af8f94f034d4054993cb 100644 --- a/drivers/staging/vt6656/card.c +++ b/drivers/staging/vt6656/card.c @@ -375,7 +375,8 @@ int vnt_radio_power_off(struct vnt_private *priv) case RF_VT3226D0: case RF_VT3342A0: ret = vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL, - (SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3)); + (SOFTPWRCTL_SWPE2 | + SOFTPWRCTL_SWPE3)); break; } diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c index 56a5f891447b0695b0515bbb4ce424c32175e03f..9fca7f26372aa26183c35c5e7bccbc14b7240027 100644 --- a/drivers/staging/wfx/hif_rx.c +++ b/drivers/staging/wfx/hif_rx.c @@ -391,9 +391,9 @@ void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) } // Note: mutex_is_lock cause an implicit memory barrier that protect // buf_send - if (mutex_is_locked(&wdev->hif_cmd.lock) - && wdev->hif_cmd.buf_send - && wdev->hif_cmd.buf_send->id == hif_id) { + if (mutex_is_locked(&wdev->hif_cmd.lock) && + wdev->hif_cmd.buf_send && + wdev->hif_cmd.buf_send->id == hif_id) { hif_generic_confirm(wdev, hif, hif->body); goto free; } diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c index 196779a1b89ac043459d286d0d9233aed4130dc3..cb7e8abdf43cea1137ec5b0ae46204709c05abfa 100644 --- a/drivers/staging/wfx/sta.c +++ b/drivers/staging/wfx/sta.c @@ -199,7 +199,7 @@ int wfx_update_pm(struct wfx_vif *wvif) } int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) + u16 queue, const struct ieee80211_tx_queue_params *params) { struct wfx_dev *wdev = hw->priv; struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/staging/wimax/Documentation/i2400m.rst b/drivers/staging/wimax/Documentation/i2400m.rst deleted file mode 100644 index 194388c0c3513a4e523820a0701a720141ae231c..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/Documentation/i2400m.rst +++ /dev/null @@ -1,283 +0,0 @@ -.. include:: <isonum.txt> - -==================================================== -Driver for the Intel Wireless Wimax Connection 2400m -==================================================== - -:Copyright: |copy| 2008 Intel Corporation < linux-wimax@intel.com > - - This provides a driver for the Intel Wireless WiMAX Connection 2400m - and a basic Linux kernel WiMAX stack. - -1. Requirements -=============== - - * Linux installation with Linux kernel 2.6.22 or newer (if building - from a separate tree) - * Intel i2400m Echo Peak or Baxter Peak; this includes the Intel - Wireless WiMAX/WiFi Link 5x50 series. - * build tools: - - + Linux kernel development package for the target kernel; to - build against your currently running kernel, you need to have - the kernel development package corresponding to the running - image installed (usually if your kernel is named - linux-VERSION, the development package is called - linux-dev-VERSION or linux-headers-VERSION). - + GNU C Compiler, make - -2. Compilation and installation -=============================== - -2.1. Compilation of the drivers included in the kernel ------------------------------------------------------- - - Configure the kernel; to enable the WiMAX drivers select Drivers > - Networking Drivers > WiMAX device support. Enable all of them as - modules (easier). - - If USB or SDIO are not enabled in the kernel configuration, the options - to build the i2400m USB or SDIO drivers will not show. Enable said - subsystems and go back to the WiMAX menu to enable the drivers. - - Compile and install your kernel as usual. - -2.2. Compilation of the drivers distributed as an standalone module -------------------------------------------------------------------- - - To compile:: - - $ cd source/directory - $ make - - Once built you can load and unload using the provided load.sh script; - load.sh will load the modules, load.sh u will unload them. - - To install in the default kernel directories (and enable auto loading - when the device is plugged):: - - $ make install - $ depmod -a - - If your kernel development files are located in a non standard - directory or if you want to build for a kernel that is not the - currently running one, set KDIR to the right location:: - - $ make KDIR=/path/to/kernel/dev/tree - - For more information, please contact linux-wimax@intel.com. - -3. Installing the firmware --------------------------- - - The firmware can be obtained from http://linuxwimax.org or might have - been supplied with your hardware. - - It has to be installed in the target system:: - - $ cp FIRMWAREFILE.sbcf /lib/firmware/i2400m-fw-BUSTYPE-1.3.sbcf - - * NOTE: if your firmware came in an .rpm or .deb file, just install - it as normal, with the rpm (rpm -i FIRMWARE.rpm) or dpkg - (dpkg -i FIRMWARE.deb) commands. No further action is needed. - * BUSTYPE will be usb or sdio, depending on the hardware you have. - Each hardware type comes with its own firmware and will not work - with other types. - -4. Design -========= - - This package contains two major parts: a WiMAX kernel stack and a - driver for the Intel i2400m. - - The WiMAX stack is designed to provide for common WiMAX control - services to current and future WiMAX devices from any vendor; please - see README.wimax for details. - - The i2400m kernel driver is broken up in two main parts: the bus - generic driver and the bus-specific drivers. The bus generic driver - forms the drivercore and contain no knowledge of the actual method we - use to connect to the device. The bus specific drivers are just the - glue to connect the bus-generic driver and the device. Currently only - USB and SDIO are supported. See drivers/net/wimax/i2400m/i2400m.h for - more information. - - The bus generic driver is logically broken up in two parts: OS-glue and - hardware-glue. The OS-glue interfaces with Linux. The hardware-glue - interfaces with the device on using an interface provided by the - bus-specific driver. The reason for this breakup is to be able to - easily reuse the hardware-glue to write drivers for other OSes; note - the hardware glue part is written as a native Linux driver; no - abstraction layers are used, so to port to another OS, the Linux kernel - API calls should be replaced with the target OS's. - -5. Usage -======== - - To load the driver, follow the instructions in the install section; - once the driver is loaded, plug in the device (unless it is permanently - plugged in). The driver will enumerate the device, upload the firmware - and output messages in the kernel log (dmesg, /var/log/messages or - /var/log/kern.log) such as:: - - ... - i2400m_usb 5-4:1.0: firmware interface version 8.0.0 - i2400m_usb 5-4:1.0: WiMAX interface wmx0 (00:1d:e1:01:94:2c) ready - - At this point the device is ready to work. - - Current versions require the Intel WiMAX Network Service in userspace - to make things work. See the network service's README for instructions - on how to scan, connect and disconnect. - -5.1. Module parameters ----------------------- - - Module parameters can be set at kernel or module load time or by - echoing values:: - - $ echo VALUE > /sys/module/MODULENAME/parameters/PARAMETERNAME - - To make changes permanent, for example, for the i2400m module, you can - also create a file named /etc/modprobe.d/i2400m containing:: - - options i2400m idle_mode_disabled=1 - - To find which parameters are supported by a module, run:: - - $ modinfo path/to/module.ko - - During kernel bootup (if the driver is linked in the kernel), specify - the following to the kernel command line:: - - i2400m.PARAMETER=VALUE - -5.1.1. i2400m: idle_mode_disabled -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - The i2400m module supports a parameter to disable idle mode. This - parameter, once set, will take effect only when the device is - reinitialized by the driver (eg: following a reset or a reconnect). - -5.2. Debug operations: debugfs entries --------------------------------------- - - The driver will register debugfs entries that allow the user to tweak - debug settings. There are three main container directories where - entries are placed, which correspond to the three blocks a i2400m WiMAX - driver has: - - * /sys/kernel/debug/wimax:DEVNAME/ for the generic WiMAX stack - controls - * /sys/kernel/debug/wimax:DEVNAME/i2400m for the i2400m generic - driver controls - * /sys/kernel/debug/wimax:DEVNAME/i2400m-usb (or -sdio) for the - bus-specific i2400m-usb or i2400m-sdio controls). - - Of course, if debugfs is mounted in a directory other than - /sys/kernel/debug, those paths will change. - -5.2.1. Increasing debug output -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - The files named *dl_* indicate knobs for controlling the debug output - of different submodules:: - - # find /sys/kernel/debug/wimax\:wmx0 -name \*dl_\* - /sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_tx - /sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_rx - /sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_notif - /sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_fw - /sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_usb - /sys/kernel/debug/wimax:wmx0/i2400m/dl_tx - /sys/kernel/debug/wimax:wmx0/i2400m/dl_rx - /sys/kernel/debug/wimax:wmx0/i2400m/dl_rfkill - /sys/kernel/debug/wimax:wmx0/i2400m/dl_netdev - /sys/kernel/debug/wimax:wmx0/i2400m/dl_fw - /sys/kernel/debug/wimax:wmx0/i2400m/dl_debugfs - /sys/kernel/debug/wimax:wmx0/i2400m/dl_driver - /sys/kernel/debug/wimax:wmx0/i2400m/dl_control - /sys/kernel/debug/wimax:wmx0/wimax_dl_stack - /sys/kernel/debug/wimax:wmx0/wimax_dl_op_rfkill - /sys/kernel/debug/wimax:wmx0/wimax_dl_op_reset - /sys/kernel/debug/wimax:wmx0/wimax_dl_op_msg - /sys/kernel/debug/wimax:wmx0/wimax_dl_id_table - /sys/kernel/debug/wimax:wmx0/wimax_dl_debugfs - - By reading the file you can obtain the current value of said debug - level; by writing to it, you can set it. - - To increase the debug level of, for example, the i2400m's generic TX - engine, just write:: - - $ echo 3 > /sys/kernel/debug/wimax:wmx0/i2400m/dl_tx - - Increasing numbers yield increasing debug information; for details of - what is printed and the available levels, check the source. The code - uses 0 for disabled and increasing values until 8. - -5.2.2. RX and TX statistics -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - The i2400m/rx_stats and i2400m/tx_stats provide statistics about the - data reception/delivery from the device:: - - $ cat /sys/kernel/debug/wimax:wmx0/i2400m/rx_stats - 45 1 3 34 3104 48 480 - - The numbers reported are: - - * packets/RX-buffer: total, min, max - * RX-buffers: total RX buffers received, accumulated RX buffer size - in bytes, min size received, max size received - - Thus, to find the average buffer size received, divide accumulated - RX-buffer / total RX-buffers. - - To clear the statistics back to 0, write anything to the rx_stats file:: - - $ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m_rx_stats - - Likewise for TX. - - Note the packets this debug file refers to are not network packet, but - packets in the sense of the device-specific protocol for communication - to the host. See drivers/net/wimax/i2400m/tx.c. - -5.2.3. Tracing messages received from user space -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - To echo messages received from user space into the trace pipe that the - i2400m driver creates, set the debug file i2400m/trace_msg_from_user to - 1:: - - $ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m/trace_msg_from_user - -5.2.4. Performing a device reset -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - By writing a 0, a 1 or a 2 to the file - /sys/kernel/debug/wimax:wmx0/reset, the driver performs a warm (without - disconnecting from the bus), cold (disconnecting from the bus) or bus - (bus specific) reset on the device. - -5.2.5. Asking the device to enter power saving mode -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - By writing any value to the /sys/kernel/debug/wimax:wmx0 file, the - device will attempt to enter power saving mode. - -6. Troubleshooting -================== - -6.1. Driver complains about ``i2400m-fw-usb-1.2.sbcf: request failed`` ----------------------------------------------------------------------- - - If upon connecting the device, the following is output in the kernel - log:: - - i2400m_usb 5-4:1.0: fw i2400m-fw-usb-1.3.sbcf: request failed: -2 - - This means that the driver cannot locate the firmware file named - /lib/firmware/i2400m-fw-usb-1.2.sbcf. Check that the file is present in - the right location. diff --git a/drivers/staging/wimax/Documentation/index.rst b/drivers/staging/wimax/Documentation/index.rst deleted file mode 100644 index fdf7c1f99ff568da6bb14346c606692a0d9fba1c..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/Documentation/index.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -=============== -WiMAX subsystem -=============== - -.. toctree:: - :maxdepth: 2 - - wimax - - i2400m - -.. only:: subproject and html - - Indices - ======= - - * :ref:`genindex` diff --git a/drivers/staging/wimax/Documentation/wimax.rst b/drivers/staging/wimax/Documentation/wimax.rst deleted file mode 100644 index 817ee8ba2732257ea727f3bdbf1b88a8381bb326..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/Documentation/wimax.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. include:: <isonum.txt> - -======================== -Linux kernel WiMAX stack -======================== - -:Copyright: |copy| 2008 Intel Corporation < linux-wimax@intel.com > - - This provides a basic Linux kernel WiMAX stack to provide a common - control API for WiMAX devices, usable from kernel and user space. - -1. Design -========= - - The WiMAX stack is designed to provide for common WiMAX control - services to current and future WiMAX devices from any vendor. - - Because currently there is only one and we don't know what would be the - common services, the APIs it currently provides are very minimal. - However, it is done in such a way that it is easily extensible to - accommodate future requirements. - - The stack works by embedding a struct wimax_dev in your device's - control structures. This provides a set of callbacks that the WiMAX - stack will call in order to implement control operations requested by - the user. As well, the stack provides API functions that the driver - calls to notify about changes of state in the device. - - The stack exports the API calls needed to control the device to user - space using generic netlink as a marshalling mechanism. You can access - them using your own code or use the wrappers provided for your - convenience in libwimax (in the wimax-tools package). - - For detailed information on the stack, please see - include/linux/wimax.h. - -2. Usage -======== - - For usage in a driver (registration, API, etc) please refer to the - instructions in the header file include/linux/wimax.h. - - When a device is registered with the WiMAX stack, a set of debugfs - files will appear in /sys/kernel/debug/wimax:wmxX can tweak for - control. - -2.1. Obtaining debug information: debugfs entries -------------------------------------------------- - - The WiMAX stack is compiled, by default, with debug messages that can - be used to diagnose issues. By default, said messages are disabled. - - The drivers will register debugfs entries that allow the user to tweak - debug settings. - - Each driver, when registering with the stack, will cause a debugfs - directory named wimax:DEVICENAME to be created; optionally, it might - create more subentries below it. - -2.1.1. Increasing debug output ------------------------------- - - The files named *dl_* indicate knobs for controlling the debug output - of different submodules of the WiMAX stack:: - - # find /sys/kernel/debug/wimax\:wmx0 -name \*dl_\* - /sys/kernel/debug/wimax:wmx0/wimax_dl_stack - /sys/kernel/debug/wimax:wmx0/wimax_dl_op_rfkill - /sys/kernel/debug/wimax:wmx0/wimax_dl_op_reset - /sys/kernel/debug/wimax:wmx0/wimax_dl_op_msg - /sys/kernel/debug/wimax:wmx0/wimax_dl_id_table - /sys/kernel/debug/wimax:wmx0/wimax_dl_debugfs - /sys/kernel/debug/wimax:wmx0/.... # other driver specific files - - NOTE: - Of course, if debugfs is mounted in a directory other than - /sys/kernel/debug, those paths will change. - - By reading the file you can obtain the current value of said debug - level; by writing to it, you can set it. - - To increase the debug level of, for example, the id-table submodule, - just write: - - $ echo 3 > /sys/kernel/debug/wimax:wmx0/wimax_dl_id_table - - Increasing numbers yield increasing debug information; for details of - what is printed and the available levels, check the source. The code - uses 0 for disabled and increasing values until 8. diff --git a/drivers/staging/wimax/Kconfig b/drivers/staging/wimax/Kconfig deleted file mode 100644 index 113c35072e2c7aad020d5433893692af99aae9e5..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# WiMAX LAN device configuration -# - -menuconfig WIMAX - tristate "WiMAX Wireless Broadband support" - depends on NET - depends on RFKILL || !RFKILL - help - - Select to configure support for devices that provide - wireless broadband connectivity using the WiMAX protocol - (IEEE 802.16). - - Please note that most of these devices require signing up - for a service plan with a provider. - - The different WiMAX drivers can be enabled in the menu entry - - Device Drivers > Network device support > WiMAX Wireless - Broadband devices - - If unsure, it is safe to select M (module). - -if WIMAX - -config WIMAX_DEBUG_LEVEL - int "WiMAX debug level" - depends on WIMAX - default 8 - help - - Select the maximum debug verbosity level to be compiled into - the WiMAX stack code. - - By default, debug messages are disabled at runtime and can - be selectively enabled for different parts of the code using - the sysfs debug-levels file. - - If set at zero, this will compile out all the debug code. - - It is recommended that it is left at 8. - -source "drivers/staging/wimax/i2400m/Kconfig" - -endif diff --git a/drivers/staging/wimax/Makefile b/drivers/staging/wimax/Makefile deleted file mode 100644 index 0e3f988656aa12db89a36f8f6349e5669f64b306..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_WIMAX) += wimax.o - -wimax-y := \ - id-table.o \ - op-msg.o \ - op-reset.o \ - op-rfkill.o \ - op-state-get.o \ - stack.o - -wimax-$(CONFIG_DEBUG_FS) += debugfs.o - -obj-$(CONFIG_WIMAX_I2400M) += i2400m/ diff --git a/drivers/staging/wimax/TODO b/drivers/staging/wimax/TODO deleted file mode 100644 index 26e4cb9e95997d575434387db802d8627bea898f..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/TODO +++ /dev/null @@ -1,18 +0,0 @@ -There are no known users of this driver as of October 2020, and it will -be removed unless someone turns out to still need it in future releases. - -According to https://en.wikipedia.org/wiki/List_of_WiMAX_networks, there -have been many public wimax networks, but it appears that many of these -have migrated to LTE or discontinued their service altogether. As most -PCs and phones lack WiMAX hardware support, the remaining networks tend -to use standalone routers. These almost certainly run Linux, but not a -modern kernel or the mainline wimax driver stack. - -NetworkManager appears to have dropped userspace support in 2015 -https://bugzilla.gnome.org/show_bug.cgi?id=747846, the www.linuxwimax.org -site had already shut down earlier. - -WiMax is apparently still being deployed on airport campus networks -("AeroMACS"), but in a frequency band that was not supported by the old -Intel 2400m (used in Sandy Bridge laptops and earlier), which is the -only driver using the kernel's wimax stack. diff --git a/drivers/staging/wimax/debug-levels.h b/drivers/staging/wimax/debug-levels.h deleted file mode 100644 index b854802d1d00611148b0be6651758ce61807e7f9..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/debug-levels.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Linux WiMAX Stack - * Debug levels control file for the wimax module - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ -#ifndef __debug_levels__h__ -#define __debug_levels__h__ - -/* Maximum compile and run time debug level for all submodules */ -#define D_MODULENAME wimax -#define D_MASTER CONFIG_WIMAX_DEBUG_LEVEL - -#include "linux-wimax-debug.h" - -/* List of all the enabled modules */ -enum d_module { - D_SUBMODULE_DECLARE(debugfs), - D_SUBMODULE_DECLARE(id_table), - D_SUBMODULE_DECLARE(op_msg), - D_SUBMODULE_DECLARE(op_reset), - D_SUBMODULE_DECLARE(op_rfkill), - D_SUBMODULE_DECLARE(op_state_get), - D_SUBMODULE_DECLARE(stack), -}; - -#endif /* #ifndef __debug_levels__h__ */ diff --git a/drivers/staging/wimax/debugfs.c b/drivers/staging/wimax/debugfs.c deleted file mode 100644 index e11bff61ffcf2ba0d92a724f954027160d04a7ee..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/debugfs.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * Debugfs support - * - * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ -#include <linux/debugfs.h> -#include "linux-wimax.h" -#include "wimax-internal.h" - -#define D_SUBMODULE debugfs -#include "debug-levels.h" - -void wimax_debugfs_add(struct wimax_dev *wimax_dev) -{ - struct net_device *net_dev = wimax_dev->net_dev; - struct dentry *dentry; - char buf[128]; - - snprintf(buf, sizeof(buf), "wimax:%s", net_dev->name); - dentry = debugfs_create_dir(buf, NULL); - wimax_dev->debugfs_dentry = dentry; - - d_level_register_debugfs("wimax_dl_", debugfs, dentry); - d_level_register_debugfs("wimax_dl_", id_table, dentry); - d_level_register_debugfs("wimax_dl_", op_msg, dentry); - d_level_register_debugfs("wimax_dl_", op_reset, dentry); - d_level_register_debugfs("wimax_dl_", op_rfkill, dentry); - d_level_register_debugfs("wimax_dl_", op_state_get, dentry); - d_level_register_debugfs("wimax_dl_", stack, dentry); -} - -void wimax_debugfs_rm(struct wimax_dev *wimax_dev) -{ - debugfs_remove_recursive(wimax_dev->debugfs_dentry); -} diff --git a/drivers/staging/wimax/i2400m/Kconfig b/drivers/staging/wimax/i2400m/Kconfig deleted file mode 100644 index 843b905a26a37fcf35cf57e169315639261a491e..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -config WIMAX_I2400M - tristate - depends on WIMAX - select FW_LOADER - -comment "Enable USB support to see WiMAX USB drivers" - depends on USB = n - -config WIMAX_I2400M_USB - tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)" - depends on WIMAX && USB - select WIMAX_I2400M - help - Select if you have a device based on the Intel WiMAX - Connection 2400 over USB (like any of the Intel Wireless - WiMAX/WiFi Link 5x50 series). - - If unsure, it is safe to select M (module). - -config WIMAX_I2400M_DEBUG_LEVEL - int "WiMAX i2400m debug level" - depends on WIMAX_I2400M - default 8 - help - - Select the maximum debug verbosity level to be compiled into - the WiMAX i2400m driver code. - - By default, this is disabled at runtime and can be - selectively enabled at runtime for different parts of the - code using the sysfs debug-levels file. - - If set at zero, this will compile out all the debug code. - - It is recommended that it is left at 8. diff --git a/drivers/staging/wimax/i2400m/Makefile b/drivers/staging/wimax/i2400m/Makefile deleted file mode 100644 index b1db1eff0648430619cc7c923111d5284b7f0e96..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_WIMAX_I2400M) += i2400m.o -obj-$(CONFIG_WIMAX_I2400M_USB) += i2400m-usb.o - -i2400m-y := \ - control.o \ - driver.o \ - fw.o \ - op-rfkill.o \ - sysfs.o \ - netdev.o \ - tx.o \ - rx.o - -i2400m-$(CONFIG_DEBUG_FS) += debugfs.o - -i2400m-usb-y := \ - usb-fw.o \ - usb-notif.o \ - usb-tx.o \ - usb-rx.o \ - usb.o diff --git a/drivers/staging/wimax/i2400m/control.c b/drivers/staging/wimax/i2400m/control.c deleted file mode 100644 index 1e270b2101e869fb5e40d06b9dcfc653774c2d57..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/control.c +++ /dev/null @@ -1,1434 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Miscellaneous control functions for managing the device - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * This is a collection of functions used to control the device (plus - * a few helpers). - * - * There are utilities for handling TLV buffers, hooks on the device's - * reports to act on device changes of state [i2400m_report_hook()], - * on acks to commands [i2400m_msg_ack_hook()], a helper for sending - * commands to the device and blocking until a reply arrives - * [i2400m_msg_to_dev()], a few high level commands for manipulating - * the device state, powersving mode and configuration plus the - * routines to setup the device once communication is stablished with - * it [i2400m_dev_initialize()]. - * - * ROADMAP - * - * i2400m_dev_initialize() Called by i2400m_dev_start() - * i2400m_set_init_config() - * i2400m_cmd_get_state() - * i2400m_dev_shutdown() Called by i2400m_dev_stop() - * i2400m_reset() - * - * i2400m_{cmd,get,set}_*() - * i2400m_msg_to_dev() - * i2400m_msg_check_status() - * - * i2400m_report_hook() Called on reception of an event - * i2400m_report_state_hook() - * i2400m_tlv_buffer_walk() - * i2400m_tlv_match() - * i2400m_report_tlv_system_state() - * i2400m_report_tlv_rf_switches_status() - * i2400m_report_tlv_media_status() - * i2400m_cmd_enter_powersave() - * - * i2400m_msg_ack_hook() Called on reception of a reply to a - * command, get or set - */ - -#include <stdarg.h> -#include "i2400m.h" -#include <linux/kernel.h> -#include <linux/slab.h> -#include "linux-wimax-i2400m.h" -#include <linux/export.h> -#include <linux/moduleparam.h> - - -#define D_SUBMODULE control -#include "debug-levels.h" - -static int i2400m_idle_mode_disabled;/* 0 (idle mode enabled) by default */ -module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644); -MODULE_PARM_DESC(idle_mode_disabled, - "If true, the device will not enable idle mode negotiation " - "with the base station (when connected) to save power."); - -/* 0 (power saving enabled) by default */ -static int i2400m_power_save_disabled; -module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); -MODULE_PARM_DESC(power_save_disabled, - "If true, the driver will not tell the device to enter " - "power saving mode when it reports it is ready for it. " - "False by default (so the device is told to do power " - "saving)."); - -static int i2400m_passive_mode; /* 0 (passive mode disabled) by default */ -module_param_named(passive_mode, i2400m_passive_mode, int, 0644); -MODULE_PARM_DESC(passive_mode, - "If true, the driver will not do any device setup " - "and leave it up to user space, who must be properly " - "setup."); - - -/* - * Return if a TLV is of a give type and size - * - * @tlv_hdr: pointer to the TLV - * @tlv_type: type of the TLV we are looking for - * @tlv_size: expected size of the TLV we are looking for (if -1, - * don't check the size). This includes the header - * Returns: 0 if the TLV matches - * < 0 if it doesn't match at all - * > 0 total TLV + payload size, if the type matches, but not - * the size - */ -static -ssize_t i2400m_tlv_match(const struct i2400m_tlv_hdr *tlv, - enum i2400m_tlv tlv_type, ssize_t tlv_size) -{ - if (le16_to_cpu(tlv->type) != tlv_type) /* Not our type? skip */ - return -1; - if (tlv_size != -1 - && le16_to_cpu(tlv->length) + sizeof(*tlv) != tlv_size) { - size_t size = le16_to_cpu(tlv->length) + sizeof(*tlv); - printk(KERN_WARNING "W: tlv type 0x%x mismatched because of " - "size (got %zu vs %zd expected)\n", - tlv_type, size, tlv_size); - return size; - } - return 0; -} - - -/* - * Given a buffer of TLVs, iterate over them - * - * @i2400m: device instance - * @tlv_buf: pointer to the beginning of the TLV buffer - * @buf_size: buffer size in bytes - * @tlv_pos: seek position; this is assumed to be a pointer returned - * by i2400m_tlv_buffer_walk() [and thus, validated]. The - * TLV returned will be the one following this one. - * - * Usage: - * - * tlv_itr = NULL; - * while (tlv_itr = i2400m_tlv_buffer_walk(i2400m, buf, size, tlv_itr)) { - * ... - * // Do stuff with tlv_itr, DON'T MODIFY IT - * ... - * } - */ -static -const struct i2400m_tlv_hdr *i2400m_tlv_buffer_walk( - struct i2400m *i2400m, - const void *tlv_buf, size_t buf_size, - const struct i2400m_tlv_hdr *tlv_pos) -{ - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_tlv_hdr *tlv_top = tlv_buf + buf_size; - size_t offset, length, avail_size; - unsigned type; - - if (tlv_pos == NULL) /* Take the first one? */ - tlv_pos = tlv_buf; - else /* Nope, the next one */ - tlv_pos = (void *) tlv_pos - + le16_to_cpu(tlv_pos->length) + sizeof(*tlv_pos); - if (tlv_pos == tlv_top) { /* buffer done */ - tlv_pos = NULL; - goto error_beyond_end; - } - if (tlv_pos > tlv_top) { - tlv_pos = NULL; - WARN_ON(1); - goto error_beyond_end; - } - offset = (void *) tlv_pos - (void *) tlv_buf; - avail_size = buf_size - offset; - if (avail_size < sizeof(*tlv_pos)) { - dev_err(dev, "HW BUG? tlv_buf %p [%zu bytes], tlv @%zu: " - "short header\n", tlv_buf, buf_size, offset); - goto error_short_header; - } - type = le16_to_cpu(tlv_pos->type); - length = le16_to_cpu(tlv_pos->length); - if (avail_size < sizeof(*tlv_pos) + length) { - dev_err(dev, "HW BUG? tlv_buf %p [%zu bytes], " - "tlv type 0x%04x @%zu: " - "short data (%zu bytes vs %zu needed)\n", - tlv_buf, buf_size, type, offset, avail_size, - sizeof(*tlv_pos) + length); - goto error_short_header; - } -error_short_header: -error_beyond_end: - return tlv_pos; -} - - -/* - * Find a TLV in a buffer of sequential TLVs - * - * @i2400m: device descriptor - * @tlv_hdr: pointer to the first TLV in the sequence - * @size: size of the buffer in bytes; all TLVs are assumed to fit - * fully in the buffer (otherwise we'll complain). - * @tlv_type: type of the TLV we are looking for - * @tlv_size: expected size of the TLV we are looking for (if -1, - * don't check the size). This includes the header - * - * Returns: NULL if the TLV is not found, otherwise a pointer to - * it. If the sizes don't match, an error is printed and NULL - * returned. - */ -static -const struct i2400m_tlv_hdr *i2400m_tlv_find( - struct i2400m *i2400m, - const struct i2400m_tlv_hdr *tlv_hdr, size_t size, - enum i2400m_tlv tlv_type, ssize_t tlv_size) -{ - ssize_t match; - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_tlv_hdr *tlv = NULL; - while ((tlv = i2400m_tlv_buffer_walk(i2400m, tlv_hdr, size, tlv))) { - match = i2400m_tlv_match(tlv, tlv_type, tlv_size); - if (match == 0) /* found it :) */ - break; - if (match > 0) - dev_warn(dev, "TLV type 0x%04x found with size " - "mismatch (%zu vs %zd needed)\n", - tlv_type, match, tlv_size); - } - return tlv; -} - - -static const struct -{ - char *msg; - int errno; -} ms_to_errno[I2400M_MS_MAX] = { - [I2400M_MS_DONE_OK] = { "", 0 }, - [I2400M_MS_DONE_IN_PROGRESS] = { "", 0 }, - [I2400M_MS_INVALID_OP] = { "invalid opcode", -ENOSYS }, - [I2400M_MS_BAD_STATE] = { "invalid state", -EILSEQ }, - [I2400M_MS_ILLEGAL_VALUE] = { "illegal value", -EINVAL }, - [I2400M_MS_MISSING_PARAMS] = { "missing parameters", -ENOMSG }, - [I2400M_MS_VERSION_ERROR] = { "bad version", -EIO }, - [I2400M_MS_ACCESSIBILITY_ERROR] = { "accesibility error", -EIO }, - [I2400M_MS_BUSY] = { "busy", -EBUSY }, - [I2400M_MS_CORRUPTED_TLV] = { "corrupted TLV", -EILSEQ }, - [I2400M_MS_UNINITIALIZED] = { "uninitialized", -EILSEQ }, - [I2400M_MS_UNKNOWN_ERROR] = { "unknown error", -EIO }, - [I2400M_MS_PRODUCTION_ERROR] = { "production error", -EIO }, - [I2400M_MS_NO_RF] = { "no RF", -EIO }, - [I2400M_MS_NOT_READY_FOR_POWERSAVE] = - { "not ready for powersave", -EACCES }, - [I2400M_MS_THERMAL_CRITICAL] = { "thermal critical", -EL3HLT }, -}; - - -/* - * i2400m_msg_check_status - translate a message's status code - * - * @i2400m: device descriptor - * @l3l4_hdr: message header - * @strbuf: buffer to place a formatted error message (unless NULL). - * @strbuf_size: max amount of available space; larger messages will - * be truncated. - * - * Returns: errno code corresponding to the status code in @l3l4_hdr - * and a message in @strbuf describing the error. - */ -int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *l3l4_hdr, - char *strbuf, size_t strbuf_size) -{ - int result; - enum i2400m_ms status = le16_to_cpu(l3l4_hdr->status); - const char *str; - - if (status == 0) - return 0; - if (status >= ARRAY_SIZE(ms_to_errno)) { - str = "unknown status code"; - result = -EBADR; - } else { - str = ms_to_errno[status].msg; - result = ms_to_errno[status].errno; - } - if (strbuf) - snprintf(strbuf, strbuf_size, "%s (%d)", str, status); - return result; -} - - -/* - * Act on a TLV System State reported by the device - * - * @i2400m: device descriptor - * @ss: validated System State TLV - */ -static -void i2400m_report_tlv_system_state(struct i2400m *i2400m, - const struct i2400m_tlv_system_state *ss) -{ - struct device *dev = i2400m_dev(i2400m); - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - enum i2400m_system_state i2400m_state = le32_to_cpu(ss->state); - - d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); - - if (i2400m->state != i2400m_state) { - i2400m->state = i2400m_state; - wake_up_all(&i2400m->state_wq); - } - switch (i2400m_state) { - case I2400M_SS_UNINITIALIZED: - case I2400M_SS_INIT: - case I2400M_SS_CONFIG: - case I2400M_SS_PRODUCTION: - wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED); - break; - - case I2400M_SS_RF_OFF: - case I2400M_SS_RF_SHUTDOWN: - wimax_state_change(wimax_dev, WIMAX_ST_RADIO_OFF); - break; - - case I2400M_SS_READY: - case I2400M_SS_STANDBY: - case I2400M_SS_SLEEPACTIVE: - wimax_state_change(wimax_dev, WIMAX_ST_READY); - break; - - case I2400M_SS_CONNECTING: - case I2400M_SS_WIMAX_CONNECTED: - wimax_state_change(wimax_dev, WIMAX_ST_READY); - break; - - case I2400M_SS_SCAN: - case I2400M_SS_OUT_OF_ZONE: - wimax_state_change(wimax_dev, WIMAX_ST_SCANNING); - break; - - case I2400M_SS_IDLE: - d_printf(1, dev, "entering BS-negotiated idle mode\n"); - fallthrough; - case I2400M_SS_DISCONNECTING: - case I2400M_SS_DATA_PATH_CONNECTED: - wimax_state_change(wimax_dev, WIMAX_ST_CONNECTED); - break; - - default: - /* Huh? just in case, shut it down */ - dev_err(dev, "HW BUG? unknown state %u: shutting down\n", - i2400m_state); - i2400m_reset(i2400m, I2400M_RT_WARM); - break; - } - d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", - i2400m, ss, i2400m_state); -} - - -/* - * Parse and act on a TLV Media Status sent by the device - * - * @i2400m: device descriptor - * @ms: validated Media Status TLV - * - * This will set the carrier up on down based on the device's link - * report. This is done asides of what the WiMAX stack does based on - * the device's state as sometimes we need to do a link-renew (the BS - * wants us to renew a DHCP lease, for example). - * - * In fact, doc says that every time we get a link-up, we should do a - * DHCP negotiation... - */ -static -void i2400m_report_tlv_media_status(struct i2400m *i2400m, - const struct i2400m_tlv_media_status *ms) -{ - struct device *dev = i2400m_dev(i2400m); - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - struct net_device *net_dev = wimax_dev->net_dev; - enum i2400m_media_status status = le32_to_cpu(ms->media_status); - - d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); - - switch (status) { - case I2400M_MEDIA_STATUS_LINK_UP: - netif_carrier_on(net_dev); - break; - case I2400M_MEDIA_STATUS_LINK_DOWN: - netif_carrier_off(net_dev); - break; - /* - * This is the network telling us we need to retrain the DHCP - * lease -- so far, we are trusting the WiMAX Network Service - * in user space to pick this up and poke the DHCP client. - */ - case I2400M_MEDIA_STATUS_LINK_RENEW: - netif_carrier_on(net_dev); - break; - default: - dev_err(dev, "HW BUG? unknown media status %u\n", - status); - } - d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", - i2400m, ms, status); -} - - -/* - * Process a TLV from a 'state report' - * - * @i2400m: device descriptor - * @tlv: pointer to the TLV header; it has been already validated for - * consistent size. - * @tag: for error messages - * - * Act on the TLVs from a 'state report'. - */ -static -void i2400m_report_state_parse_tlv(struct i2400m *i2400m, - const struct i2400m_tlv_hdr *tlv, - const char *tag) -{ - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_tlv_media_status *ms; - const struct i2400m_tlv_system_state *ss; - const struct i2400m_tlv_rf_switches_status *rfss; - - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { - ss = container_of(tlv, typeof(*ss), hdr); - d_printf(2, dev, "%s: system state TLV " - "found (0x%04x), state 0x%08x\n", - tag, I2400M_TLV_SYSTEM_STATE, - le32_to_cpu(ss->state)); - i2400m_report_tlv_system_state(i2400m, ss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { - rfss = container_of(tlv, typeof(*rfss), hdr); - d_printf(2, dev, "%s: RF status TLV " - "found (0x%04x), sw 0x%02x hw 0x%02x\n", - tag, I2400M_TLV_RF_STATUS, - le32_to_cpu(rfss->sw_rf_switch), - le32_to_cpu(rfss->hw_rf_switch)); - i2400m_report_tlv_rf_switches_status(i2400m, rfss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { - ms = container_of(tlv, typeof(*ms), hdr); - d_printf(2, dev, "%s: Media Status TLV: %u\n", - tag, le32_to_cpu(ms->media_status)); - i2400m_report_tlv_media_status(i2400m, ms); - } -} - - -/* - * Parse a 'state report' and extract information - * - * @i2400m: device descriptor - * @l3l4_hdr: pointer to message; it has been already validated for - * consistent size. - * @size: size of the message (header + payload). The header length - * declaration is assumed to be congruent with @size (as in - * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) - * - * Walk over the TLVs in a report state and act on them. - */ -static -void i2400m_report_state_hook(struct i2400m *i2400m, - const struct i2400m_l3l4_hdr *l3l4_hdr, - size_t size, const char *tag) -{ - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_tlv_hdr *tlv; - size_t tlv_size = le16_to_cpu(l3l4_hdr->length); - - d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", - i2400m, l3l4_hdr, size, tag); - tlv = NULL; - - while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, - tlv_size, tlv))) - i2400m_report_state_parse_tlv(i2400m, tlv, tag); - d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", - i2400m, l3l4_hdr, size, tag); -} - - -/* - * i2400m_report_hook - (maybe) act on a report - * - * @i2400m: device descriptor - * @l3l4_hdr: pointer to message; it has been already validated for - * consistent size. - * @size: size of the message (header + payload). The header length - * declaration is assumed to be congruent with @size (as in - * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) - * - * Extract information we might need (like carrien on/off) from a - * device report. - */ -void i2400m_report_hook(struct i2400m *i2400m, - const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size) -{ - struct device *dev = i2400m_dev(i2400m); - unsigned msg_type; - - d_fnstart(3, dev, "(i2400m %p l3l4_hdr %p size %zu)\n", - i2400m, l3l4_hdr, size); - /* Chew on the message, we might need some information from - * here */ - msg_type = le16_to_cpu(l3l4_hdr->type); - switch (msg_type) { - case I2400M_MT_REPORT_STATE: /* carrier detection... */ - i2400m_report_state_hook(i2400m, - l3l4_hdr, size, "REPORT STATE"); - break; - /* If the device is ready for power save, then ask it to do - * it. */ - case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ - if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { - if (i2400m_power_save_disabled) - d_printf(1, dev, "ready for powersave, " - "not requesting (disabled by module " - "parameter)\n"); - else { - d_printf(1, dev, "ready for powersave, " - "requesting\n"); - i2400m_cmd_enter_powersave(i2400m); - } - } - break; - } - d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n", - i2400m, l3l4_hdr, size); -} - - -/* - * i2400m_msg_ack_hook - process cmd/set/get ack for internal status - * - * @i2400m: device descriptor - * @l3l4_hdr: pointer to message; it has been already validated for - * consistent size. - * @size: size of the message - * - * Extract information we might need from acks to commands and act on - * it. This is akin to i2400m_report_hook(). Note most of this - * processing should be done in the function that calls the - * command. This is here for some cases where it can't happen... - */ -static void i2400m_msg_ack_hook(struct i2400m *i2400m, - const struct i2400m_l3l4_hdr *l3l4_hdr, - size_t size) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - unsigned int ack_type; - char strerr[32]; - - /* Chew on the message, we might need some information from - * here */ - ack_type = le16_to_cpu(l3l4_hdr->type); - switch (ack_type) { - case I2400M_MT_CMD_ENTER_POWERSAVE: - /* This is just left here for the sake of example, as - * the processing is done somewhere else. */ - if (0) { - result = i2400m_msg_check_status( - l3l4_hdr, strerr, sizeof(strerr)); - if (result >= 0) - d_printf(1, dev, "ready for power save: %zd\n", - size); - } - break; - } -} - - -/* - * i2400m_msg_size_check() - verify message size and header are congruent - * - * It is ok if the total message size is larger than the expected - * size, as there can be padding. - */ -int i2400m_msg_size_check(struct i2400m *i2400m, - const struct i2400m_l3l4_hdr *l3l4_hdr, - size_t msg_size) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - size_t expected_size; - d_fnstart(4, dev, "(i2400m %p l3l4_hdr %p msg_size %zu)\n", - i2400m, l3l4_hdr, msg_size); - if (msg_size < sizeof(*l3l4_hdr)) { - dev_err(dev, "bad size for message header " - "(expected at least %zu, got %zu)\n", - (size_t) sizeof(*l3l4_hdr), msg_size); - result = -EIO; - goto error_hdr_size; - } - expected_size = le16_to_cpu(l3l4_hdr->length) + sizeof(*l3l4_hdr); - if (msg_size < expected_size) { - dev_err(dev, "bad size for message code 0x%04x (expected %zu, " - "got %zu)\n", le16_to_cpu(l3l4_hdr->type), - expected_size, msg_size); - result = -EIO; - } else - result = 0; -error_hdr_size: - d_fnend(4, dev, - "(i2400m %p l3l4_hdr %p msg_size %zu) = %d\n", - i2400m, l3l4_hdr, msg_size, result); - return result; -} - - - -/* - * Cancel a wait for a command ACK - * - * @i2400m: device descriptor - * @code: [negative] errno code to cancel with (don't use - * -EINPROGRESS) - * - * If there is an ack already filled out, free it. - */ -void i2400m_msg_to_dev_cancel_wait(struct i2400m *i2400m, int code) -{ - struct sk_buff *ack_skb; - unsigned long flags; - - spin_lock_irqsave(&i2400m->rx_lock, flags); - ack_skb = i2400m->ack_skb; - if (ack_skb && !IS_ERR(ack_skb)) - kfree_skb(ack_skb); - i2400m->ack_skb = ERR_PTR(code); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); -} - - -/** - * i2400m_msg_to_dev - Send a control message to the device and get a response - * - * @i2400m: device descriptor - * - * @buf: pointer to the buffer containing the message to be sent; it - * has to start with a &struct i2400M_l3l4_hdr and then - * followed by the payload. Once this function returns, the - * buffer can be reused. - * - * @buf_len: buffer size - * - * Returns: - * - * Pointer to skb containing the ack message. You need to check the - * pointer with IS_ERR(), as it might be an error code. Error codes - * could happen because: - * - * - the message wasn't formatted correctly - * - couldn't send the message - * - failed waiting for a response - * - the ack message wasn't formatted correctly - * - * The returned skb has been allocated with wimax_msg_to_user_alloc(), - * it contains the response in a netlink attribute and is ready to be - * passed up to user space with wimax_msg_to_user_send(). To access - * the payload and its length, use wimax_msg_{data,len}() on the skb. - * - * The skb has to be freed with kfree_skb() once done. - * - * Description: - * - * This function delivers a message/command to the device and waits - * for an ack to be received. The format is described in - * linux/wimax/i2400m.h. In summary, a command/get/set is followed by an - * ack. - * - * This function will not check the ack status, that's left up to the - * caller. Once done with the ack skb, it has to be kfree_skb()ed. - * - * The i2400m handles only one message at the same time, thus we need - * the mutex to exclude other players. - * - * We write the message and then wait for an answer to come back. The - * RX path intercepts control messages and handles them in - * i2400m_rx_ctl(). Reports (notifications) are (maybe) processed - * locally and then forwarded (as needed) to user space on the WiMAX - * stack message pipe. Acks are saved and passed back to us through an - * skb in i2400m->ack_skb which is ready to be given to generic - * netlink if need be. - */ -struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, - const void *buf, size_t buf_len) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_l3l4_hdr *msg_l3l4_hdr; - struct sk_buff *ack_skb; - const struct i2400m_l3l4_hdr *ack_l3l4_hdr; - size_t ack_len; - int ack_timeout; - unsigned msg_type; - unsigned long flags; - - d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", - i2400m, buf, buf_len); - - rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ - if (i2400m->boot_mode) - return ERR_PTR(-EL3RST); - - msg_l3l4_hdr = buf; - /* Check msg & payload consistency */ - result = i2400m_msg_size_check(i2400m, msg_l3l4_hdr, buf_len); - if (result < 0) - goto error_bad_msg; - msg_type = le16_to_cpu(msg_l3l4_hdr->type); - d_printf(1, dev, "CMD/GET/SET 0x%04x %zu bytes\n", - msg_type, buf_len); - d_dump(2, dev, buf, buf_len); - - /* Setup the completion, ack_skb ("we are waiting") and send - * the message to the device */ - mutex_lock(&i2400m->msg_mutex); - spin_lock_irqsave(&i2400m->rx_lock, flags); - i2400m->ack_skb = ERR_PTR(-EINPROGRESS); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - init_completion(&i2400m->msg_completion); - result = i2400m_tx(i2400m, buf, buf_len, I2400M_PT_CTRL); - if (result < 0) { - dev_err(dev, "can't send message 0x%04x: %d\n", - le16_to_cpu(msg_l3l4_hdr->type), result); - goto error_tx; - } - - /* Some commands take longer to execute because of crypto ops, - * so we give them some more leeway on timeout */ - switch (msg_type) { - case I2400M_MT_GET_TLS_OPERATION_RESULT: - case I2400M_MT_CMD_SEND_EAP_RESPONSE: - ack_timeout = 5 * HZ; - break; - default: - ack_timeout = HZ; - } - - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL); - /* The RX path in rx.c will put any response for this message - * in i2400m->ack_skb and wake us up. If we cancel the wait, - * we need to change the value of i2400m->ack_skb to something - * not -EINPROGRESS so RX knows there is no one waiting. */ - result = wait_for_completion_interruptible_timeout( - &i2400m->msg_completion, ack_timeout); - if (result == 0) { - dev_err(dev, "timeout waiting for reply to message 0x%04x\n", - msg_type); - result = -ETIMEDOUT; - i2400m_msg_to_dev_cancel_wait(i2400m, result); - goto error_wait_for_completion; - } else if (result < 0) { - dev_err(dev, "error waiting for reply to message 0x%04x: %d\n", - msg_type, result); - i2400m_msg_to_dev_cancel_wait(i2400m, result); - goto error_wait_for_completion; - } - - /* Pull out the ack data from i2400m->ack_skb -- see if it is - * an error and act accordingly */ - spin_lock_irqsave(&i2400m->rx_lock, flags); - ack_skb = i2400m->ack_skb; - if (IS_ERR(ack_skb)) - result = PTR_ERR(ack_skb); - else - result = 0; - i2400m->ack_skb = NULL; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - if (result < 0) - goto error_ack_status; - ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); - - /* Check the ack and deliver it if it is ok */ - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "echo", - ack_l3l4_hdr, ack_len, GFP_KERNEL); - result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); - if (result < 0) { - dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", - msg_type, result); - goto error_bad_ack_len; - } - if (msg_type != le16_to_cpu(ack_l3l4_hdr->type)) { - dev_err(dev, "HW BUG? bad reply 0x%04x to message 0x%04x\n", - le16_to_cpu(ack_l3l4_hdr->type), msg_type); - result = -EIO; - goto error_bad_ack_type; - } - i2400m_msg_ack_hook(i2400m, ack_l3l4_hdr, ack_len); - mutex_unlock(&i2400m->msg_mutex); - d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %p\n", - i2400m, buf, buf_len, ack_skb); - return ack_skb; - -error_bad_ack_type: -error_bad_ack_len: - kfree_skb(ack_skb); -error_ack_status: -error_wait_for_completion: -error_tx: - mutex_unlock(&i2400m->msg_mutex); -error_bad_msg: - d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %d\n", - i2400m, buf, buf_len, result); - return ERR_PTR(result); -} - - -/* - * Definitions for the Enter Power Save command - * - * The Enter Power Save command requests the device to go into power - * saving mode. The device will ack or nak the command depending on it - * being ready for it. If it acks, we tell the USB subsystem to - * - * As well, the device might request to go into power saving mode by - * sending a report (REPORT_POWERSAVE_READY), in which case, we issue - * this command. The hookups in the RX coder allow - */ -enum { - I2400M_WAKEUP_ENABLED = 0x01, - I2400M_WAKEUP_DISABLED = 0x02, - I2400M_TLV_TYPE_WAKEUP_MODE = 144, -}; - -struct i2400m_cmd_enter_power_save { - struct i2400m_l3l4_hdr hdr; - struct i2400m_tlv_hdr tlv; - __le32 val; -} __packed; - - -/* - * Request entering power save - * - * This command is (mainly) executed when the device indicates that it - * is ready to go into powersave mode via a REPORT_POWERSAVE_READY. - */ -int i2400m_cmd_enter_powersave(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct i2400m_cmd_enter_power_save *cmd; - char strerr[32]; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_ENTER_POWERSAVE); - cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr)); - cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION); - cmd->tlv.type = cpu_to_le16(I2400M_TLV_TYPE_WAKEUP_MODE); - cmd->tlv.length = cpu_to_le16(sizeof(cmd->val)); - cmd->val = cpu_to_le32(I2400M_WAKEUP_ENABLED); - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - result = PTR_ERR(ack_skb); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'Enter power save' command: %d\n", - result); - goto error_msg_to_dev; - } - result = i2400m_msg_check_status(wimax_msg_data(ack_skb), - strerr, sizeof(strerr)); - if (result == -EACCES) - d_printf(1, dev, "Cannot enter power save mode\n"); - else if (result < 0) - dev_err(dev, "'Enter power save' (0x%04x) command failed: " - "%d - %s\n", I2400M_MT_CMD_ENTER_POWERSAVE, - result, strerr); - else - d_printf(1, dev, "device ready to power save\n"); - kfree_skb(ack_skb); -error_msg_to_dev: - kfree(cmd); -error_alloc: - return result; -} -EXPORT_SYMBOL_GPL(i2400m_cmd_enter_powersave); - - -/* - * Definitions for getting device information - */ -enum { - I2400M_TLV_DETAILED_DEVICE_INFO = 140 -}; - -/** - * i2400m_get_device_info - Query the device for detailed device information - * - * @i2400m: device descriptor - * - * Returns: an skb whose skb->data points to a 'struct - * i2400m_tlv_detailed_device_info'. When done, kfree_skb() it. The - * skb is *guaranteed* to contain the whole TLV data structure. - * - * On error, IS_ERR(skb) is true and ERR_PTR(skb) is the error - * code. - */ -struct sk_buff *i2400m_get_device_info(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct i2400m_l3l4_hdr *cmd; - const struct i2400m_l3l4_hdr *ack; - size_t ack_len; - const struct i2400m_tlv_hdr *tlv; - const struct i2400m_tlv_detailed_device_info *ddi; - char strerr[32]; - - ack_skb = ERR_PTR(-ENOMEM); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->type = cpu_to_le16(I2400M_MT_GET_DEVICE_INFO); - cmd->length = 0; - cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'get device info' command: %ld\n", - PTR_ERR(ack_skb)); - goto error_msg_to_dev; - } - ack = wimax_msg_data_len(ack_skb, &ack_len); - result = i2400m_msg_check_status(ack, strerr, sizeof(strerr)); - if (result < 0) { - dev_err(dev, "'get device info' (0x%04x) command failed: " - "%d - %s\n", I2400M_MT_GET_DEVICE_INFO, result, - strerr); - goto error_cmd_failed; - } - tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack), - I2400M_TLV_DETAILED_DEVICE_INFO, sizeof(*ddi)); - if (tlv == NULL) { - dev_err(dev, "GET DEVICE INFO: " - "detailed device info TLV not found (0x%04x)\n", - I2400M_TLV_DETAILED_DEVICE_INFO); - result = -EIO; - goto error_no_tlv; - } - skb_pull(ack_skb, (void *) tlv - (void *) ack_skb->data); -error_msg_to_dev: - kfree(cmd); -error_alloc: - return ack_skb; - -error_no_tlv: -error_cmd_failed: - kfree_skb(ack_skb); - kfree(cmd); - return ERR_PTR(result); -} - - -/* Firmware interface versions we support */ -enum { - I2400M_HDIv_MAJOR = 9, - I2400M_HDIv_MINOR = 1, - I2400M_HDIv_MINOR_2 = 2, -}; - - -/** - * i2400m_firmware_check - check firmware versions are compatible with - * the driver - * - * @i2400m: device descriptor - * - * Returns: 0 if ok, < 0 errno code an error and a message in the - * kernel log. - * - * Long function, but quite simple; first chunk launches the command - * and double checks the reply for the right TLV. Then we process the - * TLV (where the meat is). - * - * Once we process the TLV that gives us the firmware's interface - * version, we encode it and save it in i2400m->fw_version for future - * reference. - */ -int i2400m_firmware_check(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct i2400m_l3l4_hdr *cmd; - const struct i2400m_l3l4_hdr *ack; - size_t ack_len; - const struct i2400m_tlv_hdr *tlv; - const struct i2400m_tlv_l4_message_versions *l4mv; - char strerr[32]; - unsigned major, minor, branch; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->type = cpu_to_le16(I2400M_MT_GET_LM_VERSION); - cmd->length = 0; - cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - if (IS_ERR(ack_skb)) { - result = PTR_ERR(ack_skb); - dev_err(dev, "Failed to issue 'get lm version' command: %-d\n", - result); - goto error_msg_to_dev; - } - ack = wimax_msg_data_len(ack_skb, &ack_len); - result = i2400m_msg_check_status(ack, strerr, sizeof(strerr)); - if (result < 0) { - dev_err(dev, "'get lm version' (0x%04x) command failed: " - "%d - %s\n", I2400M_MT_GET_LM_VERSION, result, - strerr); - goto error_cmd_failed; - } - tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack), - I2400M_TLV_L4_MESSAGE_VERSIONS, sizeof(*l4mv)); - if (tlv == NULL) { - dev_err(dev, "get lm version: TLV not found (0x%04x)\n", - I2400M_TLV_L4_MESSAGE_VERSIONS); - result = -EIO; - goto error_no_tlv; - } - l4mv = container_of(tlv, typeof(*l4mv), hdr); - major = le16_to_cpu(l4mv->major); - minor = le16_to_cpu(l4mv->minor); - branch = le16_to_cpu(l4mv->branch); - result = -EINVAL; - if (major != I2400M_HDIv_MAJOR) { - dev_err(dev, "unsupported major fw version " - "%u.%u.%u\n", major, minor, branch); - goto error_bad_major; - } - result = 0; - if (minor > I2400M_HDIv_MINOR_2 || minor < I2400M_HDIv_MINOR) - dev_warn(dev, "untested minor fw version %u.%u.%u\n", - major, minor, branch); - /* Yes, we ignore the branch -- we don't have to track it */ - i2400m->fw_version = major << 16 | minor; - dev_info(dev, "firmware interface version %u.%u.%u\n", - major, minor, branch); -error_bad_major: -error_no_tlv: -error_cmd_failed: - kfree_skb(ack_skb); -error_msg_to_dev: - kfree(cmd); -error_alloc: - return result; -} - - -/* - * Send an DoExitIdle command to the device to ask it to go out of - * basestation-idle mode. - * - * @i2400m: device descriptor - * - * This starts a renegotiation with the basestation that might involve - * another crypto handshake with user space. - * - * Returns: 0 if ok, < 0 errno code on error. - */ -int i2400m_cmd_exit_idle(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct i2400m_l3l4_hdr *cmd; - char strerr[32]; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->type = cpu_to_le16(I2400M_MT_CMD_EXIT_IDLE); - cmd->length = 0; - cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - result = PTR_ERR(ack_skb); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'exit idle' command: %d\n", - result); - goto error_msg_to_dev; - } - result = i2400m_msg_check_status(wimax_msg_data(ack_skb), - strerr, sizeof(strerr)); - kfree_skb(ack_skb); -error_msg_to_dev: - kfree(cmd); -error_alloc: - return result; - -} - - -/* - * Query the device for its state, update the WiMAX stack's idea of it - * - * @i2400m: device descriptor - * - * Returns: 0 if ok, < 0 errno code on error. - * - * Executes a 'Get State' command and parses the returned - * TLVs. - * - * Because this is almost identical to a 'Report State', we use - * i2400m_report_state_hook() to parse the answer. This will set the - * carrier state, as well as the RF Kill switches state. - */ -static int i2400m_cmd_get_state(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct i2400m_l3l4_hdr *cmd; - const struct i2400m_l3l4_hdr *ack; - size_t ack_len; - char strerr[32]; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->type = cpu_to_le16(I2400M_MT_GET_STATE); - cmd->length = 0; - cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'get state' command: %ld\n", - PTR_ERR(ack_skb)); - result = PTR_ERR(ack_skb); - goto error_msg_to_dev; - } - ack = wimax_msg_data_len(ack_skb, &ack_len); - result = i2400m_msg_check_status(ack, strerr, sizeof(strerr)); - if (result < 0) { - dev_err(dev, "'get state' (0x%04x) command failed: " - "%d - %s\n", I2400M_MT_GET_STATE, result, strerr); - goto error_cmd_failed; - } - i2400m_report_state_hook(i2400m, ack, ack_len - sizeof(*ack), - "GET STATE"); - result = 0; - kfree_skb(ack_skb); -error_cmd_failed: -error_msg_to_dev: - kfree(cmd); -error_alloc: - return result; -} - -/** - * Set basic configuration settings - * - * @i2400m: device descriptor - * @arg: array of pointers to the TLV headers to send for - * configuration (each followed by its payload). - * TLV headers and payloads must be properly initialized, with the - * right endianess (LE). - * @args: number of pointers in the @arg array - */ -static int i2400m_set_init_config(struct i2400m *i2400m, - const struct i2400m_tlv_hdr **arg, - size_t args) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct i2400m_l3l4_hdr *cmd; - char strerr[32]; - unsigned argc, argsize, tlv_size; - const struct i2400m_tlv_hdr *tlv_hdr; - void *buf, *itr; - - d_fnstart(3, dev, "(i2400m %p arg %p args %zu)\n", i2400m, arg, args); - result = 0; - if (args == 0) - goto none; - /* Compute the size of all the TLVs, so we can alloc a - * contiguous command block to copy them. */ - argsize = 0; - for (argc = 0; argc < args; argc++) { - tlv_hdr = arg[argc]; - argsize += sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length); - } - WARN_ON(argc >= 9); /* As per hw spec */ - - /* Alloc the space for the command and TLVs*/ - result = -ENOMEM; - buf = kzalloc(sizeof(*cmd) + argsize, GFP_KERNEL); - if (buf == NULL) - goto error_alloc; - cmd = buf; - cmd->type = cpu_to_le16(I2400M_MT_SET_INIT_CONFIG); - cmd->length = cpu_to_le16(argsize); - cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); - - /* Copy the TLVs */ - itr = buf + sizeof(*cmd); - for (argc = 0; argc < args; argc++) { - tlv_hdr = arg[argc]; - tlv_size = sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length); - memcpy(itr, tlv_hdr, tlv_size); - itr += tlv_size; - } - - /* Send the message! */ - ack_skb = i2400m_msg_to_dev(i2400m, buf, sizeof(*cmd) + argsize); - result = PTR_ERR(ack_skb); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'init config' command: %d\n", - result); - - goto error_msg_to_dev; - } - result = i2400m_msg_check_status(wimax_msg_data(ack_skb), - strerr, sizeof(strerr)); - if (result < 0) - dev_err(dev, "'init config' (0x%04x) command failed: %d - %s\n", - I2400M_MT_SET_INIT_CONFIG, result, strerr); - kfree_skb(ack_skb); -error_msg_to_dev: - kfree(buf); -error_alloc: -none: - d_fnend(3, dev, "(i2400m %p arg %p args %zu) = %d\n", - i2400m, arg, args, result); - return result; - -} - -/** - * i2400m_set_idle_timeout - Set the device's idle mode timeout - * - * @i2400m: i2400m device descriptor - * - * @msecs: milliseconds for the timeout to enter idle mode. Between - * 100 to 300000 (5m); 0 to disable. In increments of 100. - * - * After this @msecs of the link being idle (no data being sent or - * received), the device will negotiate with the basestation entering - * idle mode for saving power. The connection is maintained, but - * getting out of it (done in tx.c) will require some negotiation, - * possible crypto re-handshake and a possible DHCP re-lease. - * - * Only available if fw_version >= 0x00090002. - * - * Returns: 0 if ok, < 0 errno code on error. - */ -int i2400m_set_idle_timeout(struct i2400m *i2400m, unsigned msecs) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct { - struct i2400m_l3l4_hdr hdr; - struct i2400m_tlv_config_idle_timeout cit; - } *cmd; - const struct i2400m_l3l4_hdr *ack; - size_t ack_len; - char strerr[32]; - - result = -ENOSYS; - if (i2400m_le_v1_3(i2400m)) - goto error_alloc; - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->hdr.type = cpu_to_le16(I2400M_MT_GET_STATE); - cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr)); - cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION); - - cmd->cit.hdr.type = - cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT); - cmd->cit.hdr.length = cpu_to_le16(sizeof(cmd->cit.timeout)); - cmd->cit.timeout = cpu_to_le32(msecs); - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'set idle timeout' command: " - "%ld\n", PTR_ERR(ack_skb)); - result = PTR_ERR(ack_skb); - goto error_msg_to_dev; - } - ack = wimax_msg_data_len(ack_skb, &ack_len); - result = i2400m_msg_check_status(ack, strerr, sizeof(strerr)); - if (result < 0) { - dev_err(dev, "'set idle timeout' (0x%04x) command failed: " - "%d - %s\n", I2400M_MT_GET_STATE, result, strerr); - goto error_cmd_failed; - } - result = 0; - kfree_skb(ack_skb); -error_cmd_failed: -error_msg_to_dev: - kfree(cmd); -error_alloc: - return result; -} - - -/** - * i2400m_dev_initialize - Initialize the device once communications are ready - * - * @i2400m: device descriptor - * - * Returns: 0 if ok, < 0 errno code on error. - * - * Configures the device to work the way we like it. - * - * At the point of this call, the device is registered with the WiMAX - * and netdev stacks, firmware is uploaded and we can talk to the - * device normally. - */ -int i2400m_dev_initialize(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct i2400m_tlv_config_idle_parameters idle_params; - struct i2400m_tlv_config_idle_timeout idle_timeout; - struct i2400m_tlv_config_d2h_data_format df; - struct i2400m_tlv_config_dl_host_reorder dlhr; - const struct i2400m_tlv_hdr *args[9]; - unsigned argc = 0; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - if (i2400m_passive_mode) - goto out_passive; - /* Disable idle mode? (enabled by default) */ - if (i2400m_idle_mode_disabled) { - if (i2400m_le_v1_3(i2400m)) { - idle_params.hdr.type = - cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS); - idle_params.hdr.length = cpu_to_le16( - sizeof(idle_params) - sizeof(idle_params.hdr)); - idle_params.idle_timeout = 0; - idle_params.idle_paging_interval = 0; - args[argc++] = &idle_params.hdr; - } else { - idle_timeout.hdr.type = - cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT); - idle_timeout.hdr.length = cpu_to_le16( - sizeof(idle_timeout) - sizeof(idle_timeout.hdr)); - idle_timeout.timeout = 0; - args[argc++] = &idle_timeout.hdr; - } - } - if (i2400m_ge_v1_4(i2400m)) { - /* Enable extended RX data format? */ - df.hdr.type = - cpu_to_le16(I2400M_TLV_CONFIG_D2H_DATA_FORMAT); - df.hdr.length = cpu_to_le16( - sizeof(df) - sizeof(df.hdr)); - df.format = 1; - args[argc++] = &df.hdr; - - /* Enable RX data reordering? - * (switch flipped in rx.c:i2400m_rx_setup() after fw upload) */ - if (i2400m->rx_reorder) { - dlhr.hdr.type = - cpu_to_le16(I2400M_TLV_CONFIG_DL_HOST_REORDER); - dlhr.hdr.length = cpu_to_le16( - sizeof(dlhr) - sizeof(dlhr.hdr)); - dlhr.reorder = 1; - args[argc++] = &dlhr.hdr; - } - } - result = i2400m_set_init_config(i2400m, args, argc); - if (result < 0) - goto error; -out_passive: - /* - * Update state: Here it just calls a get state; parsing the - * result (System State TLV and RF Status TLV [done in the rx - * path hooks]) will set the hardware and software RF-Kill - * status. - */ - result = i2400m_cmd_get_state(i2400m); -error: - if (result < 0) - dev_err(dev, "failed to initialize the device: %d\n", result); - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; -} - - -/** - * i2400m_dev_shutdown - Shutdown a running device - * - * @i2400m: device descriptor - * - * Release resources acquired during the running of the device; in - * theory, should also tell the device to go to sleep, switch off the - * radio, all that, but at this point, in most cases (driver - * disconnection, reset handling) we can't even talk to the device. - */ -void i2400m_dev_shutdown(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} diff --git a/drivers/staging/wimax/i2400m/debug-levels.h b/drivers/staging/wimax/i2400m/debug-levels.h deleted file mode 100644 index a317e9fbb7341d58a773dce98991dc222c125239..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/debug-levels.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Wireless WiMAX Connection 2400m - * Debug levels control file for the i2400m module - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ -#ifndef __debug_levels__h__ -#define __debug_levels__h__ - -/* Maximum compile and run time debug level for all submodules */ -#define D_MODULENAME i2400m -#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL - -#include "../linux-wimax-debug.h" - -/* List of all the enabled modules */ -enum d_module { - D_SUBMODULE_DECLARE(control), - D_SUBMODULE_DECLARE(driver), - D_SUBMODULE_DECLARE(debugfs), - D_SUBMODULE_DECLARE(fw), - D_SUBMODULE_DECLARE(netdev), - D_SUBMODULE_DECLARE(rfkill), - D_SUBMODULE_DECLARE(rx), - D_SUBMODULE_DECLARE(sysfs), - D_SUBMODULE_DECLARE(tx), -}; - - -#endif /* #ifndef __debug_levels__h__ */ diff --git a/drivers/staging/wimax/i2400m/debugfs.c b/drivers/staging/wimax/i2400m/debugfs.c deleted file mode 100644 index 1c640b41ea4c943de4fb6e3a95cdffda7d106c3a..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/debugfs.c +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless WiMAX Connection 2400m - * Debugfs interfaces to manipulate driver and device information - * - * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ - -#include <linux/debugfs.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/spinlock.h> -#include <linux/device.h> -#include <linux/export.h> -#include "i2400m.h" - - -#define D_SUBMODULE debugfs -#include "debug-levels.h" - -static -int debugfs_netdev_queue_stopped_get(void *data, u64 *val) -{ - struct i2400m *i2400m = data; - *val = netif_queue_stopped(i2400m->wimax_dev.net_dev); - return 0; -} -DEFINE_DEBUGFS_ATTRIBUTE(fops_netdev_queue_stopped, - debugfs_netdev_queue_stopped_get, - NULL, "%llu\n"); - -/* - * We don't allow partial reads of this file, as then the reader would - * get weirdly confused data as it is updated. - * - * So or you read it all or nothing; if you try to read with an offset - * != 0, we consider you are done reading. - */ -static -ssize_t i2400m_rx_stats_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct i2400m *i2400m = filp->private_data; - char buf[128]; - unsigned long flags; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - spin_lock_irqsave(&i2400m->rx_lock, flags); - snprintf(buf, sizeof(buf), "%u %u %u %u %u %u %u\n", - i2400m->rx_pl_num, i2400m->rx_pl_min, - i2400m->rx_pl_max, i2400m->rx_num, - i2400m->rx_size_acc, - i2400m->rx_size_min, i2400m->rx_size_max); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); -} - - -/* Any write clears the stats */ -static -ssize_t i2400m_rx_stats_write(struct file *filp, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct i2400m *i2400m = filp->private_data; - unsigned long flags; - - spin_lock_irqsave(&i2400m->rx_lock, flags); - i2400m->rx_pl_num = 0; - i2400m->rx_pl_max = 0; - i2400m->rx_pl_min = UINT_MAX; - i2400m->rx_num = 0; - i2400m->rx_size_acc = 0; - i2400m->rx_size_min = UINT_MAX; - i2400m->rx_size_max = 0; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - return count; -} - -static -const struct file_operations i2400m_rx_stats_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i2400m_rx_stats_read, - .write = i2400m_rx_stats_write, - .llseek = default_llseek, -}; - - -/* See i2400m_rx_stats_read() */ -static -ssize_t i2400m_tx_stats_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct i2400m *i2400m = filp->private_data; - char buf[128]; - unsigned long flags; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - spin_lock_irqsave(&i2400m->tx_lock, flags); - snprintf(buf, sizeof(buf), "%u %u %u %u %u %u %u\n", - i2400m->tx_pl_num, i2400m->tx_pl_min, - i2400m->tx_pl_max, i2400m->tx_num, - i2400m->tx_size_acc, - i2400m->tx_size_min, i2400m->tx_size_max); - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); -} - -/* Any write clears the stats */ -static -ssize_t i2400m_tx_stats_write(struct file *filp, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct i2400m *i2400m = filp->private_data; - unsigned long flags; - - spin_lock_irqsave(&i2400m->tx_lock, flags); - i2400m->tx_pl_num = 0; - i2400m->tx_pl_max = 0; - i2400m->tx_pl_min = UINT_MAX; - i2400m->tx_num = 0; - i2400m->tx_size_acc = 0; - i2400m->tx_size_min = UINT_MAX; - i2400m->tx_size_max = 0; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - return count; -} - -static -const struct file_operations i2400m_tx_stats_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i2400m_tx_stats_read, - .write = i2400m_tx_stats_write, - .llseek = default_llseek, -}; - - -/* Write 1 to ask the device to go into suspend */ -static -int debugfs_i2400m_suspend_set(void *data, u64 val) -{ - int result; - struct i2400m *i2400m = data; - result = i2400m_cmd_enter_powersave(i2400m); - if (result >= 0) - result = 0; - return result; -} -DEFINE_DEBUGFS_ATTRIBUTE(fops_i2400m_suspend, - NULL, debugfs_i2400m_suspend_set, - "%llu\n"); - -/* - * Reset the device - * - * Write 0 to ask the device to soft reset, 1 to cold reset, 2 to bus - * reset (as defined by enum i2400m_reset_type). - */ -static -int debugfs_i2400m_reset_set(void *data, u64 val) -{ - int result; - struct i2400m *i2400m = data; - enum i2400m_reset_type rt = val; - switch(rt) { - case I2400M_RT_WARM: - case I2400M_RT_COLD: - case I2400M_RT_BUS: - result = i2400m_reset(i2400m, rt); - if (result >= 0) - result = 0; - break; - default: - result = -EINVAL; - } - return result; -} -DEFINE_DEBUGFS_ATTRIBUTE(fops_i2400m_reset, - NULL, debugfs_i2400m_reset_set, - "%llu\n"); - -void i2400m_debugfs_add(struct i2400m *i2400m) -{ - struct dentry *dentry = i2400m->wimax_dev.debugfs_dentry; - - dentry = debugfs_create_dir("i2400m", dentry); - i2400m->debugfs_dentry = dentry; - - d_level_register_debugfs("dl_", control, dentry); - d_level_register_debugfs("dl_", driver, dentry); - d_level_register_debugfs("dl_", debugfs, dentry); - d_level_register_debugfs("dl_", fw, dentry); - d_level_register_debugfs("dl_", netdev, dentry); - d_level_register_debugfs("dl_", rfkill, dentry); - d_level_register_debugfs("dl_", rx, dentry); - d_level_register_debugfs("dl_", tx, dentry); - - debugfs_create_size_t("tx_in", 0400, dentry, &i2400m->tx_in); - debugfs_create_size_t("tx_out", 0400, dentry, &i2400m->tx_out); - debugfs_create_u32("state", 0600, dentry, &i2400m->state); - - /* - * Trace received messages from user space - * - * In order to tap the bidirectional message stream in the - * 'msg' pipe, user space can read from the 'msg' pipe; - * however, due to limitations in libnl, we can't know what - * the different applications are sending down to the kernel. - * - * So we have this hack where the driver will echo any message - * received on the msg pipe from user space [through a call to - * wimax_dev->op_msg_from_user() into - * i2400m_op_msg_from_user()] into the 'trace' pipe that this - * driver creates. - * - * So then, reading from both the 'trace' and 'msg' pipes in - * user space will provide a full dump of the traffic. - * - * Write 1 to activate, 0 to clear. - * - * It is not really very atomic, but it is also not too - * critical. - */ - debugfs_create_u8("trace_msg_from_user", 0600, dentry, - &i2400m->trace_msg_from_user); - - debugfs_create_file("netdev_queue_stopped", 0400, dentry, i2400m, - &fops_netdev_queue_stopped); - - debugfs_create_file("rx_stats", 0600, dentry, i2400m, - &i2400m_rx_stats_fops); - - debugfs_create_file("tx_stats", 0600, dentry, i2400m, - &i2400m_tx_stats_fops); - - debugfs_create_file("suspend", 0200, dentry, i2400m, - &fops_i2400m_suspend); - - debugfs_create_file("reset", 0200, dentry, i2400m, &fops_i2400m_reset); -} - -void i2400m_debugfs_rm(struct i2400m *i2400m) -{ - debugfs_remove_recursive(i2400m->debugfs_dentry); -} diff --git a/drivers/staging/wimax/i2400m/driver.c b/drivers/staging/wimax/i2400m/driver.c deleted file mode 100644 index f5186458bb3d4508e7cc9fe75a91089a7f92fa7a..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/driver.c +++ /dev/null @@ -1,1003 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless WiMAX Connection 2400m - * Generic probe/disconnect, reset and message passing - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * See i2400m.h for driver documentation. This contains helpers for - * the driver model glue [_setup()/_release()], handling device resets - * [_dev_reset_handle()], and the backends for the WiMAX stack ops - * reset [_op_reset()] and message from user [_op_msg_from_user()]. - * - * ROADMAP: - * - * i2400m_op_msg_from_user() - * i2400m_msg_to_dev() - * wimax_msg_to_user_send() - * - * i2400m_op_reset() - * i240m->bus_reset() - * - * i2400m_dev_reset_handle() - * __i2400m_dev_reset_handle() - * __i2400m_dev_stop() - * __i2400m_dev_start() - * - * i2400m_setup() - * i2400m->bus_setup() - * i2400m_bootrom_init() - * register_netdev() - * wimax_dev_add() - * i2400m_dev_start() - * __i2400m_dev_start() - * i2400m_dev_bootstrap() - * i2400m_tx_setup() - * i2400m->bus_dev_start() - * i2400m_firmware_check() - * i2400m_check_mac_addr() - * - * i2400m_release() - * i2400m_dev_stop() - * __i2400m_dev_stop() - * i2400m_dev_shutdown() - * i2400m->bus_dev_stop() - * i2400m_tx_release() - * i2400m->bus_release() - * wimax_dev_rm() - * unregister_netdev() - */ -#include "i2400m.h" -#include <linux/etherdevice.h> -#include "linux-wimax-i2400m.h" -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/suspend.h> -#include <linux/slab.h> - -#define D_SUBMODULE driver -#include "debug-levels.h" - - -static char i2400m_debug_params[128]; -module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params), - 0644); -MODULE_PARM_DESC(debug, - "String of space-separated NAME:VALUE pairs, where NAMEs " - "are the different debug submodules and VALUE are the " - "initial debug value to set."); - -static char i2400m_barkers_params[128]; -module_param_string(barkers, i2400m_barkers_params, - sizeof(i2400m_barkers_params), 0644); -MODULE_PARM_DESC(barkers, - "String of comma-separated 32-bit values; each is " - "recognized as the value the device sends as a reboot " - "signal; values are appended to a list--setting one value " - "as zero cleans the existing list and starts a new one."); - -/* - * WiMAX stack operation: relay a message from user space - * - * @wimax_dev: device descriptor - * @pipe_name: named pipe the message is for - * @msg_buf: pointer to the message bytes - * @msg_len: length of the buffer - * @genl_info: passed by the generic netlink layer - * - * The WiMAX stack will call this function when a message was received - * from user space. - * - * For the i2400m, this is an L3L4 message, as specified in - * include/linux/wimax/i2400m.h, and thus prefixed with a 'struct - * i2400m_l3l4_hdr'. Driver (and device) expect the messages to be - * coded in Little Endian. - * - * This function just verifies that the header declaration and the - * payload are consistent and then deals with it, either forwarding it - * to the device or procesing it locally. - * - * In the i2400m, messages are basically commands that will carry an - * ack, so we use i2400m_msg_to_dev() and then deliver the ack back to - * user space. The rx.c code might intercept the response and use it - * to update the driver's state, but then it will pass it on so it can - * be relayed back to user space. - * - * Note that asynchronous events from the device are processed and - * sent to user space in rx.c. - */ -static -int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, - const char *pipe_name, - const void *msg_buf, size_t msg_len, - const struct genl_info *genl_info) -{ - int result; - struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev); - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - - d_fnstart(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p " - "msg_len %zu genl_info %p)\n", wimax_dev, i2400m, - msg_buf, msg_len, genl_info); - ack_skb = i2400m_msg_to_dev(i2400m, msg_buf, msg_len); - result = PTR_ERR(ack_skb); - if (IS_ERR(ack_skb)) - goto error_msg_to_dev; - result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); -error_msg_to_dev: - d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " - "genl_info %p) = %d\n", wimax_dev, i2400m, msg_buf, msg_len, - genl_info, result); - return result; -} - - -/* - * Context to wait for a reset to finalize - */ -struct i2400m_reset_ctx { - struct completion completion; - int result; -}; - - -/* - * WiMAX stack operation: reset a device - * - * @wimax_dev: device descriptor - * - * See the documentation for wimax_reset() and wimax_dev->op_reset for - * the requirements of this function. The WiMAX stack guarantees - * serialization on calls to this function. - * - * Do a warm reset on the device; if it fails, resort to a cold reset - * and return -ENODEV. On successful warm reset, we need to block - * until it is complete. - * - * The bus-driver implementation of reset takes care of falling back - * to cold reset if warm fails. - */ -static -int i2400m_op_reset(struct wimax_dev *wimax_dev) -{ - int result; - struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev); - struct device *dev = i2400m_dev(i2400m); - struct i2400m_reset_ctx ctx = { - .completion = COMPLETION_INITIALIZER_ONSTACK(ctx.completion), - .result = 0, - }; - - d_fnstart(4, dev, "(wimax_dev %p)\n", wimax_dev); - mutex_lock(&i2400m->init_mutex); - i2400m->reset_ctx = &ctx; - mutex_unlock(&i2400m->init_mutex); - result = i2400m_reset(i2400m, I2400M_RT_WARM); - if (result < 0) - goto out; - result = wait_for_completion_timeout(&ctx.completion, 4*HZ); - if (result == 0) - result = -ETIMEDOUT; - else if (result > 0) - result = ctx.result; - /* if result < 0, pass it on */ - mutex_lock(&i2400m->init_mutex); - i2400m->reset_ctx = NULL; - mutex_unlock(&i2400m->init_mutex); -out: - d_fnend(4, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); - return result; -} - - -/* - * Check the MAC address we got from boot mode is ok - * - * @i2400m: device descriptor - * - * Returns: 0 if ok, < 0 errno code on error. - */ -static -int i2400m_check_mac_addr(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb; - const struct i2400m_tlv_detailed_device_info *ddi; - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - skb = i2400m_get_device_info(i2400m); - if (IS_ERR(skb)) { - result = PTR_ERR(skb); - dev_err(dev, "Cannot verify MAC address, error reading: %d\n", - result); - goto error; - } - /* Extract MAC address */ - ddi = (void *) skb->data; - BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address)); - d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n", - ddi->mac_address); - if (!memcmp(net_dev->perm_addr, ddi->mac_address, - sizeof(ddi->mac_address))) - goto ok; - dev_warn(dev, "warning: device reports a different MAC address " - "to that of boot mode's\n"); - dev_warn(dev, "device reports %pM\n", ddi->mac_address); - dev_warn(dev, "boot mode reported %pM\n", net_dev->perm_addr); - if (is_zero_ether_addr(ddi->mac_address)) - dev_err(dev, "device reports an invalid MAC address, " - "not updating\n"); - else { - dev_warn(dev, "updating MAC address\n"); - net_dev->addr_len = ETH_ALEN; - memcpy(net_dev->perm_addr, ddi->mac_address, ETH_ALEN); - memcpy(net_dev->dev_addr, ddi->mac_address, ETH_ALEN); - } -ok: - result = 0; - kfree_skb(skb); -error: - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; -} - - -/** - * __i2400m_dev_start - Bring up driver communication with the device - * - * @i2400m: device descriptor - * @flags: boot mode flags - * - * Returns: 0 if ok, < 0 errno code on error. - * - * Uploads firmware and brings up all the resources needed to be able - * to communicate with the device. - * - * The workqueue has to be setup early, at least before RX handling - * (it's only real user for now) so it can process reports as they - * arrive. We also want to destroy it if we retry, to make sure it is - * flushed...easier like this. - * - * TX needs to be setup before the bus-specific code (otherwise on - * shutdown, the bus-tx code could try to access it). - */ -static -int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) -{ - int result; - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - struct net_device *net_dev = wimax_dev->net_dev; - struct device *dev = i2400m_dev(i2400m); - int times = i2400m->bus_bm_retries; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); -retry: - result = i2400m_dev_bootstrap(i2400m, flags); - if (result < 0) { - dev_err(dev, "cannot bootstrap device: %d\n", result); - goto error_bootstrap; - } - result = i2400m_tx_setup(i2400m); - if (result < 0) - goto error_tx_setup; - result = i2400m_rx_setup(i2400m); - if (result < 0) - goto error_rx_setup; - i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); - if (i2400m->work_queue == NULL) { - result = -ENOMEM; - dev_err(dev, "cannot create workqueue\n"); - goto error_create_workqueue; - } - if (i2400m->bus_dev_start) { - result = i2400m->bus_dev_start(i2400m); - if (result < 0) - goto error_bus_dev_start; - } - i2400m->ready = 1; - wmb(); /* see i2400m->ready's documentation */ - /* process pending reports from the device */ - queue_work(i2400m->work_queue, &i2400m->rx_report_ws); - result = i2400m_firmware_check(i2400m); /* fw versions ok? */ - if (result < 0) - goto error_fw_check; - /* At this point is ok to send commands to the device */ - result = i2400m_check_mac_addr(i2400m); - if (result < 0) - goto error_check_mac_addr; - result = i2400m_dev_initialize(i2400m); - if (result < 0) - goto error_dev_initialize; - - /* We don't want any additional unwanted error recovery triggered - * from any other context so if anything went wrong before we come - * here, let's keep i2400m->error_recovery untouched and leave it to - * dev_reset_handle(). See dev_reset_handle(). */ - - atomic_dec(&i2400m->error_recovery); - /* Every thing works so far, ok, now we are ready to - * take error recovery if it's required. */ - - /* At this point, reports will come for the device and set it - * to the right state if it is different than UNINITIALIZED */ - d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", - net_dev, i2400m, result); - return result; - -error_dev_initialize: -error_check_mac_addr: -error_fw_check: - i2400m->ready = 0; - wmb(); /* see i2400m->ready's documentation */ - flush_workqueue(i2400m->work_queue); - if (i2400m->bus_dev_stop) - i2400m->bus_dev_stop(i2400m); -error_bus_dev_start: - destroy_workqueue(i2400m->work_queue); -error_create_workqueue: - i2400m_rx_release(i2400m); -error_rx_setup: - i2400m_tx_release(i2400m); -error_tx_setup: -error_bootstrap: - if (result == -EL3RST && times-- > 0) { - flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; - goto retry; - } - d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", - net_dev, i2400m, result); - return result; -} - - -static -int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) -{ - int result = 0; - mutex_lock(&i2400m->init_mutex); /* Well, start the device */ - if (i2400m->updown == 0) { - result = __i2400m_dev_start(i2400m, bm_flags); - if (result >= 0) { - i2400m->updown = 1; - i2400m->alive = 1; - wmb();/* see i2400m->updown and i2400m->alive's doc */ - } - } - mutex_unlock(&i2400m->init_mutex); - return result; -} - - -/** - * i2400m_dev_stop - Tear down driver communication with the device - * - * @i2400m: device descriptor - * - * Returns: 0 if ok, < 0 errno code on error. - * - * Releases all the resources allocated to communicate with the - * device. Note we cannot destroy the workqueue earlier as until RX is - * fully destroyed, it could still try to schedule jobs. - */ -static -void __i2400m_dev_stop(struct i2400m *i2400m) -{ - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); - i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); - complete(&i2400m->msg_completion); - i2400m_net_wake_stop(i2400m); - i2400m_dev_shutdown(i2400m); - /* - * Make sure no report hooks are running *before* we stop the - * communication infrastructure with the device. - */ - i2400m->ready = 0; /* nobody can queue work anymore */ - wmb(); /* see i2400m->ready's documentation */ - flush_workqueue(i2400m->work_queue); - - if (i2400m->bus_dev_stop) - i2400m->bus_dev_stop(i2400m); - destroy_workqueue(i2400m->work_queue); - i2400m_rx_release(i2400m); - i2400m_tx_release(i2400m); - wimax_state_change(wimax_dev, WIMAX_ST_DOWN); - d_fnend(3, dev, "(i2400m %p) = 0\n", i2400m); -} - - -/* - * Watch out -- we only need to stop if there is a need for it. The - * device could have reset itself and failed to come up again (see - * _i2400m_dev_reset_handle()). - */ -static -void i2400m_dev_stop(struct i2400m *i2400m) -{ - mutex_lock(&i2400m->init_mutex); - if (i2400m->updown) { - __i2400m_dev_stop(i2400m); - i2400m->updown = 0; - i2400m->alive = 0; - wmb(); /* see i2400m->updown and i2400m->alive's doc */ - } - mutex_unlock(&i2400m->init_mutex); -} - - -/* - * Listen to PM events to cache the firmware before suspend/hibernation - * - * When the device comes out of suspend, it might go into reset and - * firmware has to be uploaded again. At resume, most of the times, we - * can't load firmware images from disk, so we need to cache it. - * - * i2400m_fw_cache() will allocate a kobject and attach the firmware - * to it; that way we don't have to worry too much about the fw loader - * hitting a race condition. - * - * Note: modus operandi stolen from the Orinoco driver; thx. - */ -static -int i2400m_pm_notifier(struct notifier_block *notifier, - unsigned long pm_event, - void *unused) -{ - struct i2400m *i2400m = - container_of(notifier, struct i2400m, pm_notifier); - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p pm_event %lx)\n", i2400m, pm_event); - switch (pm_event) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - i2400m_fw_cache(i2400m); - break; - case PM_POST_RESTORE: - /* Restore from hibernation failed. We need to clean - * up in exactly the same way, so fall through. */ - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - i2400m_fw_uncache(i2400m); - break; - - case PM_RESTORE_PREPARE: - default: - break; - } - d_fnend(3, dev, "(i2400m %p pm_event %lx) = void\n", i2400m, pm_event); - return NOTIFY_DONE; -} - - -/* - * pre-reset is called before a device is going on reset - * - * This has to be followed by a call to i2400m_post_reset(), otherwise - * bad things might happen. - */ -int i2400m_pre_reset(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - d_printf(1, dev, "pre-reset shut down\n"); - - mutex_lock(&i2400m->init_mutex); - if (i2400m->updown) { - netif_tx_disable(i2400m->wimax_dev.net_dev); - __i2400m_dev_stop(i2400m); - /* down't set updown to zero -- this way - * post_reset can restore properly */ - } - mutex_unlock(&i2400m->init_mutex); - if (i2400m->bus_release) - i2400m->bus_release(i2400m); - d_fnend(3, dev, "(i2400m %p) = 0\n", i2400m); - return 0; -} -EXPORT_SYMBOL_GPL(i2400m_pre_reset); - - -/* - * Restore device state after a reset - * - * Do the work needed after a device reset to bring it up to the same - * state as it was before the reset. - * - * NOTE: this requires i2400m->init_mutex taken - */ -int i2400m_post_reset(struct i2400m *i2400m) -{ - int result = 0; - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - d_printf(1, dev, "post-reset start\n"); - if (i2400m->bus_setup) { - result = i2400m->bus_setup(i2400m); - if (result < 0) { - dev_err(dev, "bus-specific setup failed: %d\n", - result); - goto error_bus_setup; - } - } - mutex_lock(&i2400m->init_mutex); - if (i2400m->updown) { - result = __i2400m_dev_start( - i2400m, I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); - if (result < 0) - goto error_dev_start; - } - mutex_unlock(&i2400m->init_mutex); - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; - -error_dev_start: - if (i2400m->bus_release) - i2400m->bus_release(i2400m); - /* even if the device was up, it could not be recovered, so we - * mark it as down. */ - i2400m->updown = 0; - wmb(); /* see i2400m->updown's documentation */ - mutex_unlock(&i2400m->init_mutex); -error_bus_setup: - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; -} -EXPORT_SYMBOL_GPL(i2400m_post_reset); - - -/* - * The device has rebooted; fix up the device and the driver - * - * Tear down the driver communication with the device, reload the - * firmware and reinitialize the communication with the device. - * - * If someone calls a reset when the device's firmware is down, in - * theory we won't see it because we are not listening. However, just - * in case, leave the code to handle it. - * - * If there is a reset context, use it; this means someone is waiting - * for us to tell him when the reset operation is complete and the - * device is ready to rock again. - * - * NOTE: if we are in the process of bringing up or down the - * communication with the device [running i2400m_dev_start() or - * _stop()], don't do anything, let it fail and handle it. - * - * This function is ran always in a thread context - * - * This function gets passed, as payload to i2400m_work() a 'const - * char *' ptr with a "reason" why the reset happened (for messages). - */ -static -void __i2400m_dev_reset_handle(struct work_struct *ws) -{ - struct i2400m *i2400m = container_of(ws, struct i2400m, reset_ws); - const char *reason = i2400m->reset_reason; - struct device *dev = i2400m_dev(i2400m); - struct i2400m_reset_ctx *ctx = i2400m->reset_ctx; - int result; - - d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason); - - i2400m->boot_mode = 1; - wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ - - result = 0; - if (mutex_trylock(&i2400m->init_mutex) == 0) { - /* We are still in i2400m_dev_start() [let it fail] or - * i2400m_dev_stop() [we are shutting down anyway, so - * ignore it] or we are resetting somewhere else. */ - dev_err(dev, "device rebooted somewhere else?\n"); - i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); - complete(&i2400m->msg_completion); - goto out; - } - - dev_err(dev, "%s: reinitializing driver\n", reason); - rmb(); - if (i2400m->updown) { - __i2400m_dev_stop(i2400m); - i2400m->updown = 0; - wmb(); /* see i2400m->updown's documentation */ - } - - if (i2400m->alive) { - result = __i2400m_dev_start(i2400m, - I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); - if (result < 0) { - dev_err(dev, "%s: cannot start the device: %d\n", - reason, result); - result = -EUCLEAN; - if (atomic_read(&i2400m->bus_reset_retries) - >= I2400M_BUS_RESET_RETRIES) { - result = -ENODEV; - dev_err(dev, "tried too many times to " - "reset the device, giving up\n"); - } - } - } - - if (i2400m->reset_ctx) { - ctx->result = result; - complete(&ctx->completion); - } - mutex_unlock(&i2400m->init_mutex); - if (result == -EUCLEAN) { - /* - * We come here because the reset during operational mode - * wasn't successfully done and need to proceed to a bus - * reset. For the dev_reset_handle() to be able to handle - * the reset event later properly, we restore boot_mode back - * to the state before previous reset. ie: just like we are - * issuing the bus reset for the first time - */ - i2400m->boot_mode = 0; - wmb(); - - atomic_inc(&i2400m->bus_reset_retries); - /* ops, need to clean up [w/ init_mutex not held] */ - result = i2400m_reset(i2400m, I2400M_RT_BUS); - if (result >= 0) - result = -ENODEV; - } else { - rmb(); - if (i2400m->alive) { - /* great, we expect the device state up and - * dev_start() actually brings the device state up */ - i2400m->updown = 1; - wmb(); - atomic_set(&i2400m->bus_reset_retries, 0); - } - } -out: - d_fnend(3, dev, "(ws %p i2400m %p reason %s) = void\n", - ws, i2400m, reason); -} - - -/* - * i2400m_dev_reset_handle - Handle a device's reset in a thread context - * - * Schedule a device reset handling out on a thread context, so it - * is safe to call from atomic context. We can't use the i2400m's - * queue as we are going to destroy it and reinitialize it as part of - * the driver bringup/bringup process. - * - * See __i2400m_dev_reset_handle() for details; that takes care of - * reinitializing the driver to handle the reset, calling into the - * bus-specific functions ops as needed. - */ -int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason) -{ - i2400m->reset_reason = reason; - return schedule_work(&i2400m->reset_ws); -} -EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); - - -/* - * The actual work of error recovery. - * - * The current implementation of error recovery is to trigger a bus reset. - */ -static -void __i2400m_error_recovery(struct work_struct *ws) -{ - struct i2400m *i2400m = container_of(ws, struct i2400m, recovery_ws); - - i2400m_reset(i2400m, I2400M_RT_BUS); -} - -/* - * Schedule a work struct for error recovery. - * - * The intention of error recovery is to bring back the device to some - * known state whenever TX sees -110 (-ETIMEOUT) on copying the data to - * the device. The TX failure could mean a device bus stuck, so the current - * error recovery implementation is to trigger a bus reset to the device - * and hopefully it can bring back the device. - * - * The actual work of error recovery has to be in a thread context because - * it is kicked off in the TX thread (i2400ms->tx_workqueue) which is to be - * destroyed by the error recovery mechanism (currently a bus reset). - * - * Also, there may be already a queue of TX works that all hit - * the -ETIMEOUT error condition because the device is stuck already. - * Since bus reset is used as the error recovery mechanism and we don't - * want consecutive bus resets simply because the multiple TX works - * in the queue all hit the same device erratum, the flag "error_recovery" - * is introduced for preventing unwanted consecutive bus resets. - * - * Error recovery shall only be invoked again if previous one was completed. - * The flag error_recovery is set when error recovery mechanism is scheduled, - * and is checked when we need to schedule another error recovery. If it is - * in place already, then we shouldn't schedule another one. - */ -void i2400m_error_recovery(struct i2400m *i2400m) -{ - if (atomic_add_return(1, &i2400m->error_recovery) == 1) - schedule_work(&i2400m->recovery_ws); - else - atomic_dec(&i2400m->error_recovery); -} -EXPORT_SYMBOL_GPL(i2400m_error_recovery); - -/* - * Alloc the command and ack buffers for boot mode - * - * Get the buffers needed to deal with boot mode messages. - */ -static -int i2400m_bm_buf_alloc(struct i2400m *i2400m) -{ - i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL); - if (i2400m->bm_cmd_buf == NULL) - goto error_bm_cmd_kzalloc; - i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL); - if (i2400m->bm_ack_buf == NULL) - goto error_bm_ack_buf_kzalloc; - return 0; - -error_bm_ack_buf_kzalloc: - kfree(i2400m->bm_cmd_buf); -error_bm_cmd_kzalloc: - return -ENOMEM; -} - - -/* - * Free boot mode command and ack buffers. - */ -static -void i2400m_bm_buf_free(struct i2400m *i2400m) -{ - kfree(i2400m->bm_ack_buf); - kfree(i2400m->bm_cmd_buf); -} - - -/* - * i2400m_init - Initialize a 'struct i2400m' from all zeroes - * - * This is a bus-generic API call. - */ -void i2400m_init(struct i2400m *i2400m) -{ - wimax_dev_init(&i2400m->wimax_dev); - - i2400m->boot_mode = 1; - i2400m->rx_reorder = 1; - init_waitqueue_head(&i2400m->state_wq); - - spin_lock_init(&i2400m->tx_lock); - i2400m->tx_pl_min = UINT_MAX; - i2400m->tx_size_min = UINT_MAX; - - spin_lock_init(&i2400m->rx_lock); - i2400m->rx_pl_min = UINT_MAX; - i2400m->rx_size_min = UINT_MAX; - INIT_LIST_HEAD(&i2400m->rx_reports); - INIT_WORK(&i2400m->rx_report_ws, i2400m_report_hook_work); - - mutex_init(&i2400m->msg_mutex); - init_completion(&i2400m->msg_completion); - - mutex_init(&i2400m->init_mutex); - /* wake_tx_ws is initialized in i2400m_tx_setup() */ - - INIT_WORK(&i2400m->reset_ws, __i2400m_dev_reset_handle); - INIT_WORK(&i2400m->recovery_ws, __i2400m_error_recovery); - - atomic_set(&i2400m->bus_reset_retries, 0); - - i2400m->alive = 0; - - /* initialize error_recovery to 1 for denoting we - * are not yet ready to take any error recovery */ - atomic_set(&i2400m->error_recovery, 1); -} -EXPORT_SYMBOL_GPL(i2400m_init); - - -int i2400m_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) -{ - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - - /* - * Make sure we stop TXs and down the carrier before - * resetting; this is needed to avoid things like - * i2400m_wake_tx() scheduling stuff in parallel. - */ - if (net_dev->reg_state == NETREG_REGISTERED) { - netif_tx_disable(net_dev); - netif_carrier_off(net_dev); - } - return i2400m->bus_reset(i2400m, rt); -} -EXPORT_SYMBOL_GPL(i2400m_reset); - - -/** - * i2400m_setup - bus-generic setup function for the i2400m device - * - * @i2400m: device descriptor (bus-specific parts have been initialized) - * @bm_flags: boot mode flags - * - * Returns: 0 if ok, < 0 errno code on error. - * - * Sets up basic device comunication infrastructure, boots the ROM to - * read the MAC address, registers with the WiMAX and network stacks - * and then brings up the device. - */ -int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - - snprintf(wimax_dev->name, sizeof(wimax_dev->name), - "i2400m-%s:%s", dev->bus->name, dev_name(dev)); - - result = i2400m_bm_buf_alloc(i2400m); - if (result < 0) { - dev_err(dev, "cannot allocate bootmode scratch buffers\n"); - goto error_bm_buf_alloc; - } - - if (i2400m->bus_setup) { - result = i2400m->bus_setup(i2400m); - if (result < 0) { - dev_err(dev, "bus-specific setup failed: %d\n", - result); - goto error_bus_setup; - } - } - - result = i2400m_bootrom_init(i2400m, bm_flags); - if (result < 0) { - dev_err(dev, "read mac addr: bootrom init " - "failed: %d\n", result); - goto error_bootrom_init; - } - result = i2400m_read_mac_addr(i2400m); - if (result < 0) - goto error_read_mac_addr; - eth_random_addr(i2400m->src_mac_addr); - - i2400m->pm_notifier.notifier_call = i2400m_pm_notifier; - register_pm_notifier(&i2400m->pm_notifier); - - result = register_netdev(net_dev); /* Okey dokey, bring it up */ - if (result < 0) { - dev_err(dev, "cannot register i2400m network device: %d\n", - result); - goto error_register_netdev; - } - netif_carrier_off(net_dev); - - i2400m->wimax_dev.op_msg_from_user = i2400m_op_msg_from_user; - i2400m->wimax_dev.op_rfkill_sw_toggle = i2400m_op_rfkill_sw_toggle; - i2400m->wimax_dev.op_reset = i2400m_op_reset; - - result = wimax_dev_add(&i2400m->wimax_dev, net_dev); - if (result < 0) - goto error_wimax_dev_add; - - /* Now setup all that requires a registered net and wimax device. */ - result = sysfs_create_group(&net_dev->dev.kobj, &i2400m_dev_attr_group); - if (result < 0) { - dev_err(dev, "cannot setup i2400m's sysfs: %d\n", result); - goto error_sysfs_setup; - } - - i2400m_debugfs_add(i2400m); - - result = i2400m_dev_start(i2400m, bm_flags); - if (result < 0) - goto error_dev_start; - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; - -error_dev_start: - i2400m_debugfs_rm(i2400m); - sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, - &i2400m_dev_attr_group); -error_sysfs_setup: - wimax_dev_rm(&i2400m->wimax_dev); -error_wimax_dev_add: - unregister_netdev(net_dev); -error_register_netdev: - unregister_pm_notifier(&i2400m->pm_notifier); -error_read_mac_addr: -error_bootrom_init: - if (i2400m->bus_release) - i2400m->bus_release(i2400m); -error_bus_setup: - i2400m_bm_buf_free(i2400m); -error_bm_buf_alloc: - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; -} -EXPORT_SYMBOL_GPL(i2400m_setup); - - -/* - * i2400m_release - release the bus-generic driver resources - * - * Sends a disconnect message and undoes any setup done by i2400m_setup() - */ -void i2400m_release(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - netif_stop_queue(i2400m->wimax_dev.net_dev); - - i2400m_dev_stop(i2400m); - - cancel_work_sync(&i2400m->reset_ws); - cancel_work_sync(&i2400m->recovery_ws); - - i2400m_debugfs_rm(i2400m); - sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, - &i2400m_dev_attr_group); - wimax_dev_rm(&i2400m->wimax_dev); - unregister_netdev(i2400m->wimax_dev.net_dev); - unregister_pm_notifier(&i2400m->pm_notifier); - if (i2400m->bus_release) - i2400m->bus_release(i2400m); - i2400m_bm_buf_free(i2400m); - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} -EXPORT_SYMBOL_GPL(i2400m_release); - - -/* - * Debug levels control; see debug.h - */ -struct d_level D_LEVEL[] = { - D_SUBMODULE_DEFINE(control), - D_SUBMODULE_DEFINE(driver), - D_SUBMODULE_DEFINE(debugfs), - D_SUBMODULE_DEFINE(fw), - D_SUBMODULE_DEFINE(netdev), - D_SUBMODULE_DEFINE(rfkill), - D_SUBMODULE_DEFINE(rx), - D_SUBMODULE_DEFINE(sysfs), - D_SUBMODULE_DEFINE(tx), -}; -size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); - - -static -int __init i2400m_driver_init(void) -{ - d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400m_debug_params, - "i2400m.debug"); - return i2400m_barker_db_init(i2400m_barkers_params); -} -module_init(i2400m_driver_init); - -static -void __exit i2400m_driver_exit(void) -{ - i2400m_barker_db_exit(); -} -module_exit(i2400m_driver_exit); - -MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); -MODULE_DESCRIPTION("Intel 2400M WiMAX networking bus-generic driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/wimax/i2400m/fw.c b/drivers/staging/wimax/i2400m/fw.c deleted file mode 100644 index 92ea5c101e765e6c650b300061a9f6427450064c..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/fw.c +++ /dev/null @@ -1,1666 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Firmware uploader - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * - * THE PROCEDURE - * - * The 2400m and derived devices work in two modes: boot-mode or - * normal mode. In boot mode we can execute only a handful of commands - * targeted at uploading the firmware and launching it. - * - * The 2400m enters boot mode when it is first connected to the - * system, when it crashes and when you ask it to reboot. There are - * two submodes of the boot mode: signed and non-signed. Signed takes - * firmwares signed with a certain private key, non-signed takes any - * firmware. Normal hardware takes only signed firmware. - * - * On boot mode, in USB, we write to the device using the bulk out - * endpoint and read from it in the notification endpoint. - * - * Upon entrance to boot mode, the device sends (preceded with a few - * zero length packets (ZLPs) on the notification endpoint in USB) a - * reboot barker (4 le32 words with the same value). We ack it by - * sending the same barker to the device. The device acks with a - * reboot ack barker (4 le32 words with value I2400M_ACK_BARKER) and - * then is fully booted. At this point we can upload the firmware. - * - * Note that different iterations of the device and EEPROM - * configurations will send different [re]boot barkers; these are - * collected in i2400m_barker_db along with the firmware - * characteristics they require. - * - * This process is accomplished by the i2400m_bootrom_init() - * function. All the device interaction happens through the - * i2400m_bm_cmd() [boot mode command]. Special return values will - * indicate if the device did reset during the process. - * - * After this, we read the MAC address and then (if needed) - * reinitialize the device. We need to read it ahead of time because - * in the future, we might not upload the firmware until userspace - * 'ifconfig up's the device. - * - * We can then upload the firmware file. The file is composed of a BCF - * header (basic data, keys and signatures) and a list of write - * commands and payloads. Optionally more BCF headers might follow the - * main payload. We first upload the header [i2400m_dnload_init()] and - * then pass the commands and payloads verbatim to the i2400m_bm_cmd() - * function [i2400m_dnload_bcf()]. Then we tell the device to jump to - * the new firmware [i2400m_dnload_finalize()]. - * - * Once firmware is uploaded, we are good to go :) - * - * When we don't know in which mode we are, we first try by sending a - * warm reset request that will take us to boot-mode. If we time out - * waiting for a reboot barker, that means maybe we are already in - * boot mode, so we send a reboot barker. - * - * COMMAND EXECUTION - * - * This code (and process) is single threaded; for executing commands, - * we post a URB to the notification endpoint, post the command, wait - * for data on the notification buffer. We don't need to worry about - * others as we know we are the only ones in there. - * - * BACKEND IMPLEMENTATION - * - * This code is bus-generic; the bus-specific driver provides back end - * implementations to send a boot mode command to the device and to - * read an acknolwedgement from it (or an asynchronous notification) - * from it. - * - * FIRMWARE LOADING - * - * Note that in some cases, we can't just load a firmware file (for - * example, when resuming). For that, we might cache the firmware - * file. Thus, when doing the bootstrap, if there is a cache firmware - * file, it is used; if not, loading from disk is attempted. - * - * ROADMAP - * - * i2400m_barker_db_init Called by i2400m_driver_init() - * i2400m_barker_db_add - * - * i2400m_barker_db_exit Called by i2400m_driver_exit() - * - * i2400m_dev_bootstrap Called by __i2400m_dev_start() - * request_firmware - * i2400m_fw_bootstrap - * i2400m_fw_check - * i2400m_fw_hdr_check - * i2400m_fw_dnload - * release_firmware - * - * i2400m_fw_dnload - * i2400m_bootrom_init - * i2400m_bm_cmd - * i2400m_reset - * i2400m_dnload_init - * i2400m_dnload_init_signed - * i2400m_dnload_init_nonsigned - * i2400m_download_chunk - * i2400m_bm_cmd - * i2400m_dnload_bcf - * i2400m_bm_cmd - * i2400m_dnload_finalize - * i2400m_bm_cmd - * - * i2400m_bm_cmd - * i2400m->bus_bm_cmd_send() - * i2400m->bus_bm_wait_for_ack - * __i2400m_bm_ack_verify - * i2400m_is_boot_barker - * - * i2400m_bm_cmd_prepare Used by bus-drivers to prep - * commands before sending - * - * i2400m_pm_notifier Called on Power Management events - * i2400m_fw_cache - * i2400m_fw_uncache - */ -#include <linux/firmware.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/export.h> -#include "i2400m.h" - - -#define D_SUBMODULE fw -#include "debug-levels.h" - - -static const __le32 i2400m_ACK_BARKER[4] = { - cpu_to_le32(I2400M_ACK_BARKER), - cpu_to_le32(I2400M_ACK_BARKER), - cpu_to_le32(I2400M_ACK_BARKER), - cpu_to_le32(I2400M_ACK_BARKER) -}; - - -/** - * Prepare a boot-mode command for delivery - * - * @cmd: pointer to bootrom header to prepare - * - * Computes checksum if so needed. After calling this function, DO NOT - * modify the command or header as the checksum won't work anymore. - * - * We do it from here because some times we cannot do it in the - * original context the command was sent (it is a const), so when we - * copy it to our staging buffer, we add the checksum there. - */ -void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *cmd) -{ - if (i2400m_brh_get_use_checksum(cmd)) { - int i; - __le32 checksum = 0; - const u32 *checksum_ptr = (void *) cmd->payload; - - for (i = 0; i < le32_to_cpu(cmd->data_size) / 4; i++) - le32_add_cpu(&checksum, *checksum_ptr++); - - le32_add_cpu(&checksum, le32_to_cpu(cmd->command)); - le32_add_cpu(&checksum, le32_to_cpu(cmd->target_addr)); - le32_add_cpu(&checksum, le32_to_cpu(cmd->data_size)); - - cmd->block_checksum = checksum; - } -} -EXPORT_SYMBOL_GPL(i2400m_bm_cmd_prepare); - - -/* - * Database of known barkers. - * - * A barker is what the device sends indicating he is ready to be - * bootloaded. Different versions of the device will send different - * barkers. Depending on the barker, it might mean the device wants - * some kind of firmware or the other. - */ -static struct i2400m_barker_db { - __le32 data[4]; -} *i2400m_barker_db; -static size_t i2400m_barker_db_used, i2400m_barker_db_size; - - -static -int i2400m_zrealloc_2x(void **ptr, size_t *_count, size_t el_size, - gfp_t gfp_flags) -{ - size_t old_count = *_count, - new_count = old_count ? 2 * old_count : 2, - old_size = el_size * old_count, - new_size = el_size * new_count; - void *nptr = krealloc(*ptr, new_size, gfp_flags); - if (nptr) { - /* zero the other half or the whole thing if old_count - * was zero */ - if (old_size == 0) - memset(nptr, 0, new_size); - else - memset(nptr + old_size, 0, old_size); - *_count = new_count; - *ptr = nptr; - return 0; - } else - return -ENOMEM; -} - - -/* - * Add a barker to the database - * - * This cannot used outside of this module and only at at module_init - * time. This is to avoid the need to do locking. - */ -static -int i2400m_barker_db_add(u32 barker_id) -{ - int result; - - struct i2400m_barker_db *barker; - if (i2400m_barker_db_used >= i2400m_barker_db_size) { - result = i2400m_zrealloc_2x( - (void **) &i2400m_barker_db, &i2400m_barker_db_size, - sizeof(i2400m_barker_db[0]), GFP_KERNEL); - if (result < 0) - return result; - } - barker = i2400m_barker_db + i2400m_barker_db_used++; - barker->data[0] = le32_to_cpu(barker_id); - barker->data[1] = le32_to_cpu(barker_id); - barker->data[2] = le32_to_cpu(barker_id); - barker->data[3] = le32_to_cpu(barker_id); - return 0; -} - - -void i2400m_barker_db_exit(void) -{ - kfree(i2400m_barker_db); - i2400m_barker_db = NULL; - i2400m_barker_db_size = 0; - i2400m_barker_db_used = 0; -} - - -/* - * Helper function to add all the known stable barkers to the barker - * database. - */ -static -int i2400m_barker_db_known_barkers(void) -{ - int result; - - result = i2400m_barker_db_add(I2400M_NBOOT_BARKER); - if (result < 0) - goto error_add; - result = i2400m_barker_db_add(I2400M_SBOOT_BARKER); - if (result < 0) - goto error_add; - result = i2400m_barker_db_add(I2400M_SBOOT_BARKER_6050); - if (result < 0) - goto error_add; -error_add: - return result; -} - - -/* - * Initialize the barker database - * - * This can only be used from the module_init function for this - * module; this is to avoid the need to do locking. - * - * @options: command line argument with extra barkers to - * recognize. This is a comma-separated list of 32-bit hex - * numbers. They are appended to the existing list. Setting 0 - * cleans the existing list and starts a new one. - */ -int i2400m_barker_db_init(const char *_options) -{ - int result; - char *options = NULL, *options_orig, *token; - - i2400m_barker_db = NULL; - i2400m_barker_db_size = 0; - i2400m_barker_db_used = 0; - - result = i2400m_barker_db_known_barkers(); - if (result < 0) - goto error_add; - /* parse command line options from i2400m.barkers */ - if (_options != NULL) { - unsigned barker; - - options_orig = kstrdup(_options, GFP_KERNEL); - if (options_orig == NULL) { - result = -ENOMEM; - goto error_parse; - } - options = options_orig; - - while ((token = strsep(&options, ",")) != NULL) { - if (*token == '\0') /* eat joint commas */ - continue; - if (sscanf(token, "%x", &barker) != 1 - || barker > 0xffffffff) { - printk(KERN_ERR "%s: can't recognize " - "i2400m.barkers value '%s' as " - "a 32-bit number\n", - __func__, token); - result = -EINVAL; - goto error_parse; - } - if (barker == 0) { - /* clean list and start new */ - i2400m_barker_db_exit(); - continue; - } - result = i2400m_barker_db_add(barker); - if (result < 0) - goto error_parse_add; - } - kfree(options_orig); - } - return 0; - -error_parse_add: -error_parse: - kfree(options_orig); -error_add: - kfree(i2400m_barker_db); - return result; -} - - -/* - * Recognize a boot barker - * - * @buf: buffer where the boot barker. - * @buf_size: size of the buffer (has to be 16 bytes). It is passed - * here so the function can check it for the caller. - * - * Note that as a side effect, upon identifying the obtained boot - * barker, this function will set i2400m->barker to point to the right - * barker database entry. Subsequent calls to the function will result - * in verifying that the same type of boot barker is returned when the - * device [re]boots (as long as the same device instance is used). - * - * Return: 0 if @buf matches a known boot barker. -ENOENT if the - * buffer in @buf doesn't match any boot barker in the database or - * -EILSEQ if the buffer doesn't have the right size. - */ -int i2400m_is_boot_barker(struct i2400m *i2400m, - const void *buf, size_t buf_size) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct i2400m_barker_db *barker; - int i; - - result = -ENOENT; - if (buf_size != sizeof(i2400m_barker_db[i].data)) - return result; - - /* Short circuit if we have already discovered the barker - * associated with the device. */ - if (i2400m->barker && - !memcmp(buf, i2400m->barker, sizeof(i2400m->barker->data))) - return 0; - - for (i = 0; i < i2400m_barker_db_used; i++) { - barker = &i2400m_barker_db[i]; - BUILD_BUG_ON(sizeof(barker->data) != 16); - if (memcmp(buf, barker->data, sizeof(barker->data))) - continue; - - if (i2400m->barker == NULL) { - i2400m->barker = barker; - d_printf(1, dev, "boot barker set to #%u/%08x\n", - i, le32_to_cpu(barker->data[0])); - if (barker->data[0] == le32_to_cpu(I2400M_NBOOT_BARKER)) - i2400m->sboot = 0; - else - i2400m->sboot = 1; - } else if (i2400m->barker != barker) { - dev_err(dev, "HW inconsistency: device " - "reports a different boot barker " - "than set (from %08x to %08x)\n", - le32_to_cpu(i2400m->barker->data[0]), - le32_to_cpu(barker->data[0])); - result = -EIO; - } else - d_printf(2, dev, "boot barker confirmed #%u/%08x\n", - i, le32_to_cpu(barker->data[0])); - result = 0; - break; - } - return result; -} -EXPORT_SYMBOL_GPL(i2400m_is_boot_barker); - - -/* - * Verify the ack data received - * - * Given a reply to a boot mode command, chew it and verify everything - * is ok. - * - * @opcode: opcode which generated this ack. For error messages. - * @ack: pointer to ack data we received - * @ack_size: size of that data buffer - * @flags: I2400M_BM_CMD_* flags we called the command with. - * - * Way too long function -- maybe it should be further split - */ -static -ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode, - struct i2400m_bootrom_header *ack, - size_t ack_size, int flags) -{ - ssize_t result = -ENOMEM; - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(8, dev, "(i2400m %p opcode %d ack %p size %zu)\n", - i2400m, opcode, ack, ack_size); - if (ack_size < sizeof(*ack)) { - result = -EIO; - dev_err(dev, "boot-mode cmd %d: HW BUG? notification didn't " - "return enough data (%zu bytes vs %zu expected)\n", - opcode, ack_size, sizeof(*ack)); - goto error_ack_short; - } - result = i2400m_is_boot_barker(i2400m, ack, ack_size); - if (result >= 0) { - result = -ERESTARTSYS; - d_printf(6, dev, "boot-mode cmd %d: HW boot barker\n", opcode); - goto error_reboot; - } - if (ack_size == sizeof(i2400m_ACK_BARKER) - && memcmp(ack, i2400m_ACK_BARKER, sizeof(*ack)) == 0) { - result = -EISCONN; - d_printf(3, dev, "boot-mode cmd %d: HW reboot ack barker\n", - opcode); - goto error_reboot_ack; - } - result = 0; - if (flags & I2400M_BM_CMD_RAW) - goto out_raw; - ack->data_size = le32_to_cpu(ack->data_size); - ack->target_addr = le32_to_cpu(ack->target_addr); - ack->block_checksum = le32_to_cpu(ack->block_checksum); - d_printf(5, dev, "boot-mode cmd %d: notification for opcode %u " - "response %u csum %u rr %u da %u\n", - opcode, i2400m_brh_get_opcode(ack), - i2400m_brh_get_response(ack), - i2400m_brh_get_use_checksum(ack), - i2400m_brh_get_response_required(ack), - i2400m_brh_get_direct_access(ack)); - result = -EIO; - if (i2400m_brh_get_signature(ack) != 0xcbbc) { - dev_err(dev, "boot-mode cmd %d: HW BUG? wrong signature " - "0x%04x\n", opcode, i2400m_brh_get_signature(ack)); - goto error_ack_signature; - } - if (opcode != -1 && opcode != i2400m_brh_get_opcode(ack)) { - dev_err(dev, "boot-mode cmd %d: HW BUG? " - "received response for opcode %u, expected %u\n", - opcode, i2400m_brh_get_opcode(ack), opcode); - goto error_ack_opcode; - } - if (i2400m_brh_get_response(ack) != 0) { /* failed? */ - dev_err(dev, "boot-mode cmd %d: error; hw response %u\n", - opcode, i2400m_brh_get_response(ack)); - goto error_ack_failed; - } - if (ack_size < ack->data_size + sizeof(*ack)) { - dev_err(dev, "boot-mode cmd %d: SW BUG " - "driver provided only %zu bytes for %zu bytes " - "of data\n", opcode, ack_size, - (size_t) le32_to_cpu(ack->data_size) + sizeof(*ack)); - goto error_ack_short_buffer; - } - result = ack_size; - /* Don't you love this stack of empty targets? Well, I don't - * either, but it helps track exactly who comes in here and - * why :) */ -error_ack_short_buffer: -error_ack_failed: -error_ack_opcode: -error_ack_signature: -out_raw: -error_reboot_ack: -error_reboot: -error_ack_short: - d_fnend(8, dev, "(i2400m %p opcode %d ack %p size %zu) = %d\n", - i2400m, opcode, ack, ack_size, (int) result); - return result; -} - - -/** - * i2400m_bm_cmd - Execute a boot mode command - * - * @i2400m: device descriptor - * @cmd: buffer containing the command data (pointing at the header). - * This data can be ANYWHERE (for USB, we will copy it to an - * specific buffer). Make sure everything is in proper little - * endian. - * - * A raw buffer can be also sent, just cast it and set flags to - * I2400M_BM_CMD_RAW. - * - * This function will generate a checksum for you if the - * checksum bit in the command is set (unless I2400M_BM_CMD_RAW - * is set). - * - * You can use the i2400m->bm_cmd_buf to stage your commands and - * send them. - * - * If NULL, no command is sent (we just wait for an ack). - * - * @cmd_size: size of the command. Will be auto padded to the - * bus-specific drivers padding requirements. - * - * @ack: buffer where to place the acknowledgement. If it is a regular - * command response, all fields will be returned with the right, - * native endianess. - * - * You *cannot* use i2400m->bm_ack_buf for this buffer. - * - * @ack_size: size of @ack, 16 aligned; you need to provide at least - * sizeof(*ack) bytes and then enough to contain the return data - * from the command - * - * @flags: see I2400M_BM_CMD_* above. - * - * Returns: bytes received by the notification; if < 0, an errno code - * denoting an error or: - * - * -ERESTARTSYS The device has rebooted - * - * Executes a boot-mode command and waits for a response, doing basic - * validation on it; if a zero length response is received, it retries - * waiting for a response until a non-zero one is received (timing out - * after %I2400M_BOOT_RETRIES retries). - */ -static -ssize_t i2400m_bm_cmd(struct i2400m *i2400m, - const struct i2400m_bootrom_header *cmd, size_t cmd_size, - struct i2400m_bootrom_header *ack, size_t ack_size, - int flags) -{ - ssize_t result, rx_bytes; - struct device *dev = i2400m_dev(i2400m); - int opcode = cmd == NULL ? -1 : i2400m_brh_get_opcode(cmd); - - d_fnstart(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu)\n", - i2400m, cmd, cmd_size, ack, ack_size); - BUG_ON(ack_size < sizeof(*ack)); - BUG_ON(i2400m->boot_mode == 0); - - if (cmd != NULL) { /* send the command */ - result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags); - if (result < 0) - goto error_cmd_send; - if ((flags & I2400M_BM_CMD_RAW) == 0) - d_printf(5, dev, - "boot-mode cmd %d csum %u rr %u da %u: " - "addr 0x%04x size %u block csum 0x%04x\n", - opcode, i2400m_brh_get_use_checksum(cmd), - i2400m_brh_get_response_required(cmd), - i2400m_brh_get_direct_access(cmd), - cmd->target_addr, cmd->data_size, - cmd->block_checksum); - } - result = i2400m->bus_bm_wait_for_ack(i2400m, ack, ack_size); - if (result < 0) { - dev_err(dev, "boot-mode cmd %d: error waiting for an ack: %d\n", - opcode, (int) result); /* bah, %zd doesn't work */ - goto error_wait_for_ack; - } - rx_bytes = result; - /* verify the ack and read more if necessary [result is the - * final amount of bytes we get in the ack] */ - result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags); - if (result < 0) - goto error_bad_ack; - /* Don't you love this stack of empty targets? Well, I don't - * either, but it helps track exactly who comes in here and - * why :) */ - result = rx_bytes; -error_bad_ack: -error_wait_for_ack: -error_cmd_send: - d_fnend(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu) = %d\n", - i2400m, cmd, cmd_size, ack, ack_size, (int) result); - return result; -} - - -/** - * i2400m_download_chunk - write a single chunk of data to the device's memory - * - * @i2400m: device descriptor - * @chunk: the buffer to write - * @__chunk_len: length of the buffer to write - * @addr: address in the device memory space - * @direct: bootrom write mode - * @do_csum: should a checksum validation be performed - */ -static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, - size_t __chunk_len, unsigned long addr, - unsigned int direct, unsigned int do_csum) -{ - int ret; - size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); - struct device *dev = i2400m_dev(i2400m); - struct { - struct i2400m_bootrom_header cmd; - u8 cmd_payload[]; - } __packed *buf; - struct i2400m_bootrom_header ack; - - d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx " - "direct %u do_csum %u)\n", i2400m, chunk, __chunk_len, - addr, direct, do_csum); - buf = i2400m->bm_cmd_buf; - memcpy(buf->cmd_payload, chunk, __chunk_len); - memset(buf->cmd_payload + __chunk_len, 0xad, chunk_len - __chunk_len); - - buf->cmd.command = i2400m_brh_command(I2400M_BRH_WRITE, - __chunk_len & 0x3 ? 0 : do_csum, - __chunk_len & 0xf ? 0 : direct); - buf->cmd.target_addr = cpu_to_le32(addr); - buf->cmd.data_size = cpu_to_le32(__chunk_len); - ret = i2400m_bm_cmd(i2400m, &buf->cmd, sizeof(buf->cmd) + chunk_len, - &ack, sizeof(ack), 0); - if (ret >= 0) - ret = 0; - d_fnend(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx " - "direct %u do_csum %u) = %d\n", i2400m, chunk, __chunk_len, - addr, direct, do_csum, ret); - return ret; -} - - -/* - * Download a BCF file's sections to the device - * - * @i2400m: device descriptor - * @bcf: pointer to firmware data (first header followed by the - * payloads). Assumed verified and consistent. - * @bcf_len: length (in bytes) of the @bcf buffer. - * - * Returns: < 0 errno code on error or the offset to the jump instruction. - * - * Given a BCF file, downloads each section (a command and a payload) - * to the device's address space. Actually, it just executes each - * command i the BCF file. - * - * The section size has to be aligned to 4 bytes AND the padding has - * to be taken from the firmware file, as the signature takes it into - * account. - */ -static -ssize_t i2400m_dnload_bcf(struct i2400m *i2400m, - const struct i2400m_bcf_hdr *bcf, size_t bcf_len) -{ - ssize_t ret; - struct device *dev = i2400m_dev(i2400m); - size_t offset, /* iterator offset */ - data_size, /* Size of the data payload */ - section_size, /* Size of the whole section (cmd + payload) */ - section = 1; - const struct i2400m_bootrom_header *bh; - struct i2400m_bootrom_header ack; - - d_fnstart(3, dev, "(i2400m %p bcf %p bcf_len %zu)\n", - i2400m, bcf, bcf_len); - /* Iterate over the command blocks in the BCF file that start - * after the header */ - offset = le32_to_cpu(bcf->header_len) * sizeof(u32); - while (1) { /* start sending the file */ - bh = (void *) bcf + offset; - data_size = le32_to_cpu(bh->data_size); - section_size = ALIGN(sizeof(*bh) + data_size, 4); - d_printf(7, dev, - "downloading section #%zu (@%zu %zu B) to 0x%08x\n", - section, offset, sizeof(*bh) + data_size, - le32_to_cpu(bh->target_addr)); - /* - * We look for JUMP cmd from the bootmode header, - * either I2400M_BRH_SIGNED_JUMP for secure boot - * or I2400M_BRH_JUMP for unsecure boot, the last chunk - * should be the bootmode header with JUMP cmd. - */ - if (i2400m_brh_get_opcode(bh) == I2400M_BRH_SIGNED_JUMP || - i2400m_brh_get_opcode(bh) == I2400M_BRH_JUMP) { - d_printf(5, dev, "jump found @%zu\n", offset); - break; - } - if (offset + section_size > bcf_len) { - dev_err(dev, "fw %s: bad section #%zu, " - "end (@%zu) beyond EOF (@%zu)\n", - i2400m->fw_name, section, - offset + section_size, bcf_len); - ret = -EINVAL; - goto error_section_beyond_eof; - } - __i2400m_msleep(20); - ret = i2400m_bm_cmd(i2400m, bh, section_size, - &ack, sizeof(ack), I2400M_BM_CMD_RAW); - if (ret < 0) { - dev_err(dev, "fw %s: section #%zu (@%zu %zu B) " - "failed %d\n", i2400m->fw_name, section, - offset, sizeof(*bh) + data_size, (int) ret); - goto error_send; - } - offset += section_size; - section++; - } - ret = offset; -error_section_beyond_eof: -error_send: - d_fnend(3, dev, "(i2400m %p bcf %p bcf_len %zu) = %d\n", - i2400m, bcf, bcf_len, (int) ret); - return ret; -} - - -/* - * Indicate if the device emitted a reboot barker that indicates - * "signed boot" - */ -static -unsigned i2400m_boot_is_signed(struct i2400m *i2400m) -{ - return likely(i2400m->sboot); -} - - -/* - * Do the final steps of uploading firmware - * - * @bcf_hdr: BCF header we are actually using - * @bcf: pointer to the firmware image (which matches the first header - * that is followed by the actual payloads). - * @offset: [byte] offset into @bcf for the command we need to send. - * - * Depending on the boot mode (signed vs non-signed), different - * actions need to be taken. - */ -static -int i2400m_dnload_finalize(struct i2400m *i2400m, - const struct i2400m_bcf_hdr *bcf_hdr, - const struct i2400m_bcf_hdr *bcf, size_t offset) -{ - int ret = 0; - struct device *dev = i2400m_dev(i2400m); - struct i2400m_bootrom_header *cmd, ack; - struct { - struct i2400m_bootrom_header cmd; - u8 cmd_pl[0]; - } __packed *cmd_buf; - size_t signature_block_offset, signature_block_size; - - d_fnstart(3, dev, "offset %zu\n", offset); - cmd = (void *) bcf + offset; - if (i2400m_boot_is_signed(i2400m) == 0) { - struct i2400m_bootrom_header jump_ack; - d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", - le32_to_cpu(cmd->target_addr)); - cmd_buf = i2400m->bm_cmd_buf; - memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); - cmd = &cmd_buf->cmd; - /* now cmd points to the actual bootrom_header in cmd_buf */ - i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); - cmd->data_size = 0; - ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), - &jump_ack, sizeof(jump_ack), 0); - } else { - d_printf(1, dev, "secure boot, jumping to 0x%08x\n", - le32_to_cpu(cmd->target_addr)); - cmd_buf = i2400m->bm_cmd_buf; - memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); - signature_block_offset = - sizeof(*bcf_hdr) - + le32_to_cpu(bcf_hdr->key_size) * sizeof(u32) - + le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32); - signature_block_size = - le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32); - memcpy(cmd_buf->cmd_pl, - (void *) bcf_hdr + signature_block_offset, - signature_block_size); - ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, - sizeof(cmd_buf->cmd) + signature_block_size, - &ack, sizeof(ack), I2400M_BM_CMD_RAW); - } - d_fnend(3, dev, "returning %d\n", ret); - return ret; -} - - -/** - * i2400m_bootrom_init - Reboots a powered device into boot mode - * - * @i2400m: device descriptor - * @flags: - * I2400M_BRI_SOFT: a reboot barker has been seen - * already, so don't wait for it. - * - * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait - * for a reboot barker notification. This is a one shot; if - * the state machine needs to send a reboot command it will. - * - * Returns: - * - * < 0 errno code on error, 0 if ok. - * - * Description: - * - * Tries hard enough to put the device in boot-mode. There are two - * main phases to this: - * - * a. (1) send a reboot command and (2) get a reboot barker - * - * b. (1) echo/ack the reboot sending the reboot barker back and (2) - * getting an ack barker in return - * - * We want to skip (a) in some cases [soft]. The state machine is - * horrible, but it is basically: on each phase, send what has to be - * sent (if any), wait for the answer and act on the answer. We might - * have to backtrack and retry, so we keep a max tries counter for - * that. - * - * It sucks because we don't know ahead of time which is going to be - * the reboot barker (the device might send different ones depending - * on its EEPROM config) and once the device reboots and waits for the - * echo/ack reboot barker being sent back, it doesn't understand - * anything else. So we can be left at the point where we don't know - * what to send to it -- cold reset and bus reset seem to have little - * effect. So the function iterates (in this case) through all the - * known barkers and tries them all until an ACK is - * received. Otherwise, it gives up. - * - * If we get a timeout after sending a warm reset, we do it again. - */ -int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct i2400m_bootrom_header *cmd; - struct i2400m_bootrom_header ack; - int count = i2400m->bus_bm_retries; - int ack_timeout_cnt = 1; - unsigned i; - - BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data)); - BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER)); - - d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags); - result = -ENOMEM; - cmd = i2400m->bm_cmd_buf; - if (flags & I2400M_BRI_SOFT) - goto do_reboot_ack; -do_reboot: - ack_timeout_cnt = 1; - if (--count < 0) - goto error_timeout; - d_printf(4, dev, "device reboot: reboot command [%d # left]\n", - count); - if ((flags & I2400M_BRI_NO_REBOOT) == 0) - i2400m_reset(i2400m, I2400M_RT_WARM); - result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack), - I2400M_BM_CMD_RAW); - flags &= ~I2400M_BRI_NO_REBOOT; - switch (result) { - case -ERESTARTSYS: - /* - * at this point, i2400m_bm_cmd(), through - * __i2400m_bm_ack_process(), has updated - * i2400m->barker and we are good to go. - */ - d_printf(4, dev, "device reboot: got reboot barker\n"); - break; - case -EISCONN: /* we don't know how it got here...but we follow it */ - d_printf(4, dev, "device reboot: got ack barker - whatever\n"); - goto do_reboot; - case -ETIMEDOUT: - /* - * Device has timed out, we might be in boot mode - * already and expecting an ack; if we don't know what - * the barker is, we just send them all. Cold reset - * and bus reset don't work. Beats me. - */ - if (i2400m->barker != NULL) { - dev_err(dev, "device boot: reboot barker timed out, " - "trying (set) %08x echo/ack\n", - le32_to_cpu(i2400m->barker->data[0])); - goto do_reboot_ack; - } - for (i = 0; i < i2400m_barker_db_used; i++) { - struct i2400m_barker_db *barker = &i2400m_barker_db[i]; - memcpy(cmd, barker->data, sizeof(barker->data)); - result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), - &ack, sizeof(ack), - I2400M_BM_CMD_RAW); - if (result == -EISCONN) { - dev_warn(dev, "device boot: got ack barker " - "after sending echo/ack barker " - "#%d/%08x; rebooting j.i.c.\n", - i, le32_to_cpu(barker->data[0])); - flags &= ~I2400M_BRI_NO_REBOOT; - goto do_reboot; - } - } - dev_err(dev, "device boot: tried all the echo/acks, could " - "not get device to respond; giving up"); - result = -ESHUTDOWN; - case -EPROTO: - case -ESHUTDOWN: /* dev is gone */ - case -EINTR: /* user cancelled */ - goto error_dev_gone; - default: - dev_err(dev, "device reboot: error %d while waiting " - "for reboot barker - rebooting\n", result); - d_dump(1, dev, &ack, result); - goto do_reboot; - } - /* At this point we ack back with 4 REBOOT barkers and expect - * 4 ACK barkers. This is ugly, as we send a raw command -- - * hence the cast. _bm_cmd() will catch the reboot ack - * notification and report it as -EISCONN. */ -do_reboot_ack: - d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count); - memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data)); - result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), - &ack, sizeof(ack), I2400M_BM_CMD_RAW); - switch (result) { - case -ERESTARTSYS: - d_printf(4, dev, "reboot ack: got reboot barker - retrying\n"); - if (--count < 0) - goto error_timeout; - goto do_reboot_ack; - case -EISCONN: - d_printf(4, dev, "reboot ack: got ack barker - good\n"); - break; - case -ETIMEDOUT: /* no response, maybe it is the other type? */ - if (ack_timeout_cnt-- < 0) { - d_printf(4, dev, "reboot ack timedout: retrying\n"); - goto do_reboot_ack; - } else { - dev_err(dev, "reboot ack timedout too long: " - "trying reboot\n"); - goto do_reboot; - } - break; - case -EPROTO: - case -ESHUTDOWN: /* dev is gone */ - goto error_dev_gone; - default: - dev_err(dev, "device reboot ack: error %d while waiting for " - "reboot ack barker - rebooting\n", result); - goto do_reboot; - } - d_printf(2, dev, "device reboot ack: got ack barker - boot done\n"); - result = 0; -exit_timeout: -error_dev_gone: - d_fnend(4, dev, "(i2400m %p flags 0x%08x) = %d\n", - i2400m, flags, result); - return result; - -error_timeout: - dev_err(dev, "Timed out waiting for reboot ack\n"); - result = -ETIMEDOUT; - goto exit_timeout; -} - - -/* - * Read the MAC addr - * - * The position this function reads is fixed in device memory and - * always available, even without firmware. - * - * Note we specify we want to read only six bytes, but provide space - * for 16, as we always get it rounded up. - */ -int i2400m_read_mac_addr(struct i2400m *i2400m) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - struct i2400m_bootrom_header *cmd; - struct { - struct i2400m_bootrom_header ack; - u8 ack_pl[16]; - } __packed ack_buf; - - d_fnstart(5, dev, "(i2400m %p)\n", i2400m); - cmd = i2400m->bm_cmd_buf; - cmd->command = i2400m_brh_command(I2400M_BRH_READ, 0, 1); - cmd->target_addr = cpu_to_le32(0x00203fe8); - cmd->data_size = cpu_to_le32(6); - result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), - &ack_buf.ack, sizeof(ack_buf), 0); - if (result < 0) { - dev_err(dev, "BM: read mac addr failed: %d\n", result); - goto error_read_mac; - } - d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl); - if (i2400m->bus_bm_mac_addr_impaired == 1) { - ack_buf.ack_pl[0] = 0x00; - ack_buf.ack_pl[1] = 0x16; - ack_buf.ack_pl[2] = 0xd3; - get_random_bytes(&ack_buf.ack_pl[3], 3); - dev_err(dev, "BM is MAC addr impaired, faking MAC addr to " - "mac addr is %pM\n", ack_buf.ack_pl); - result = 0; - } - net_dev->addr_len = ETH_ALEN; - memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN); -error_read_mac: - d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; -} - - -/* - * Initialize a non signed boot - * - * This implies sending some magic values to the device's memory. Note - * we convert the values to little endian in the same array - * declaration. - */ -static -int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) -{ - unsigned i = 0; - int ret = 0; - struct device *dev = i2400m_dev(i2400m); - d_fnstart(5, dev, "(i2400m %p)\n", i2400m); - if (i2400m->bus_bm_pokes_table) { - while (i2400m->bus_bm_pokes_table[i].address) { - ret = i2400m_download_chunk( - i2400m, - &i2400m->bus_bm_pokes_table[i].data, - sizeof(i2400m->bus_bm_pokes_table[i].data), - i2400m->bus_bm_pokes_table[i].address, 1, 1); - if (ret < 0) - break; - i++; - } - } - d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); - return ret; -} - - -/* - * Initialize the signed boot process - * - * @i2400m: device descriptor - * - * @bcf_hdr: pointer to the firmware header; assumes it is fully in - * memory (it has gone through basic validation). - * - * Returns: 0 if ok, < 0 errno code on error, -ERESTARTSYS if the hw - * rebooted. - * - * This writes the firmware BCF header to the device using the - * HASH_PAYLOAD_ONLY command. - */ -static -int i2400m_dnload_init_signed(struct i2400m *i2400m, - const struct i2400m_bcf_hdr *bcf_hdr) -{ - int ret; - struct device *dev = i2400m_dev(i2400m); - struct { - struct i2400m_bootrom_header cmd; - struct i2400m_bcf_hdr cmd_pl; - } __packed *cmd_buf; - struct i2400m_bootrom_header ack; - - d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr); - cmd_buf = i2400m->bm_cmd_buf; - cmd_buf->cmd.command = - i2400m_brh_command(I2400M_BRH_HASH_PAYLOAD_ONLY, 0, 0); - cmd_buf->cmd.target_addr = 0; - cmd_buf->cmd.data_size = cpu_to_le32(sizeof(cmd_buf->cmd_pl)); - memcpy(&cmd_buf->cmd_pl, bcf_hdr, sizeof(*bcf_hdr)); - ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, sizeof(*cmd_buf), - &ack, sizeof(ack), 0); - if (ret >= 0) - ret = 0; - d_fnend(5, dev, "(i2400m %p bcf_hdr %p) = %d\n", i2400m, bcf_hdr, ret); - return ret; -} - - -/* - * Initialize the firmware download at the device size - * - * Multiplex to the one that matters based on the device's mode - * (signed or non-signed). - */ -static -int i2400m_dnload_init(struct i2400m *i2400m, - const struct i2400m_bcf_hdr *bcf_hdr) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - - if (i2400m_boot_is_signed(i2400m)) { - d_printf(1, dev, "signed boot\n"); - result = i2400m_dnload_init_signed(i2400m, bcf_hdr); - if (result == -ERESTARTSYS) - return result; - if (result < 0) - dev_err(dev, "firmware %s: signed boot download " - "initialization failed: %d\n", - i2400m->fw_name, result); - } else { - /* non-signed boot process without pokes */ - d_printf(1, dev, "non-signed boot\n"); - result = i2400m_dnload_init_nonsigned(i2400m); - if (result == -ERESTARTSYS) - return result; - if (result < 0) - dev_err(dev, "firmware %s: non-signed download " - "initialization failed: %d\n", - i2400m->fw_name, result); - } - return result; -} - - -/* - * Run consistency tests on the firmware file and load up headers - * - * Check for the firmware being made for the i2400m device, - * etc...These checks are mostly informative, as the device will make - * them too; but the driver's response is more informative on what - * went wrong. - * - * This will also look at all the headers present on the firmware - * file, and update i2400m->fw_bcf_hdr to point to them. - */ -static -int i2400m_fw_hdr_check(struct i2400m *i2400m, - const struct i2400m_bcf_hdr *bcf_hdr, - size_t index, size_t offset) -{ - struct device *dev = i2400m_dev(i2400m); - - unsigned module_type, header_len, major_version, minor_version, - module_id, module_vendor, date, size; - - module_type = le32_to_cpu(bcf_hdr->module_type); - header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len); - major_version = (le32_to_cpu(bcf_hdr->header_version) & 0xffff0000) - >> 16; - minor_version = le32_to_cpu(bcf_hdr->header_version) & 0x0000ffff; - module_id = le32_to_cpu(bcf_hdr->module_id); - module_vendor = le32_to_cpu(bcf_hdr->module_vendor); - date = le32_to_cpu(bcf_hdr->date); - size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); - - d_printf(1, dev, "firmware %s #%zd@%08zx: BCF header " - "type:vendor:id 0x%x:%x:%x v%u.%u (%u/%u B) built %08x\n", - i2400m->fw_name, index, offset, - module_type, module_vendor, module_id, - major_version, minor_version, header_len, size, date); - - /* Hard errors */ - if (major_version != 1) { - dev_err(dev, "firmware %s #%zd@%08zx: major header version " - "v%u.%u not supported\n", - i2400m->fw_name, index, offset, - major_version, minor_version); - return -EBADF; - } - - if (module_type != 6) { /* built for the right hardware? */ - dev_err(dev, "firmware %s #%zd@%08zx: unexpected module " - "type 0x%x; aborting\n", - i2400m->fw_name, index, offset, - module_type); - return -EBADF; - } - - if (module_vendor != 0x8086) { - dev_err(dev, "firmware %s #%zd@%08zx: unexpected module " - "vendor 0x%x; aborting\n", - i2400m->fw_name, index, offset, module_vendor); - return -EBADF; - } - - if (date < 0x20080300) - dev_warn(dev, "firmware %s #%zd@%08zx: build date %08x " - "too old; unsupported\n", - i2400m->fw_name, index, offset, date); - return 0; -} - - -/* - * Run consistency tests on the firmware file and load up headers - * - * Check for the firmware being made for the i2400m device, - * etc...These checks are mostly informative, as the device will make - * them too; but the driver's response is more informative on what - * went wrong. - * - * This will also look at all the headers present on the firmware - * file, and update i2400m->fw_hdrs to point to them. - */ -static -int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - size_t headers = 0; - const struct i2400m_bcf_hdr *bcf_hdr; - const void *itr, *next, *top; - size_t slots = 0, used_slots = 0; - - for (itr = bcf, top = itr + bcf_size; - itr < top; - headers++, itr = next) { - size_t leftover, offset, header_len, size; - - leftover = top - itr; - offset = itr - bcf; - if (leftover <= sizeof(*bcf_hdr)) { - dev_err(dev, "firmware %s: %zu B left at @%zx, " - "not enough for BCF header\n", - i2400m->fw_name, leftover, offset); - break; - } - bcf_hdr = itr; - /* Only the first header is supposed to be followed by - * payload */ - header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len); - size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); - if (headers == 0) - next = itr + size; - else - next = itr + header_len; - - result = i2400m_fw_hdr_check(i2400m, bcf_hdr, headers, offset); - if (result < 0) - continue; - if (used_slots + 1 >= slots) { - /* +1 -> we need to account for the one we'll - * occupy and at least an extra one for - * always being NULL */ - result = i2400m_zrealloc_2x( - (void **) &i2400m->fw_hdrs, &slots, - sizeof(i2400m->fw_hdrs[0]), - GFP_KERNEL); - if (result < 0) - goto error_zrealloc; - } - i2400m->fw_hdrs[used_slots] = bcf_hdr; - used_slots++; - } - if (headers == 0) { - dev_err(dev, "firmware %s: no usable headers found\n", - i2400m->fw_name); - result = -EBADF; - } else - result = 0; -error_zrealloc: - return result; -} - - -/* - * Match a barker to a BCF header module ID - * - * The device sends a barker which tells the firmware loader which - * header in the BCF file has to be used. This does the matching. - */ -static -unsigned i2400m_bcf_hdr_match(struct i2400m *i2400m, - const struct i2400m_bcf_hdr *bcf_hdr) -{ - u32 barker = le32_to_cpu(i2400m->barker->data[0]) - & 0x7fffffff; - u32 module_id = le32_to_cpu(bcf_hdr->module_id) - & 0x7fffffff; /* high bit used for something else */ - - /* special case for 5x50 */ - if (barker == I2400M_SBOOT_BARKER && module_id == 0) - return 1; - if (module_id == barker) - return 1; - return 0; -} - -static -const struct i2400m_bcf_hdr *i2400m_bcf_hdr_find(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_bcf_hdr **bcf_itr, *bcf_hdr; - unsigned i = 0; - u32 barker = le32_to_cpu(i2400m->barker->data[0]); - - d_printf(2, dev, "finding BCF header for barker %08x\n", barker); - if (barker == I2400M_NBOOT_BARKER) { - bcf_hdr = i2400m->fw_hdrs[0]; - d_printf(1, dev, "using BCF header #%u/%08x for non-signed " - "barker\n", 0, le32_to_cpu(bcf_hdr->module_id)); - return bcf_hdr; - } - for (bcf_itr = i2400m->fw_hdrs; *bcf_itr != NULL; bcf_itr++, i++) { - bcf_hdr = *bcf_itr; - if (i2400m_bcf_hdr_match(i2400m, bcf_hdr)) { - d_printf(1, dev, "hit on BCF hdr #%u/%08x\n", - i, le32_to_cpu(bcf_hdr->module_id)); - return bcf_hdr; - } else - d_printf(1, dev, "miss on BCF hdr #%u/%08x\n", - i, le32_to_cpu(bcf_hdr->module_id)); - } - dev_err(dev, "cannot find a matching BCF header for barker %08x\n", - barker); - return NULL; -} - - -/* - * Download the firmware to the device - * - * @i2400m: device descriptor - * @bcf: pointer to loaded (and minimally verified for consistency) - * firmware - * @bcf_size: size of the @bcf buffer (header plus payloads) - * - * The process for doing this is described in this file's header. - * - * Note we only reinitialize boot-mode if the flags say so. Some hw - * iterations need it, some don't. In any case, if we loop, we always - * need to reinitialize the boot room, hence the flags modification. - */ -static -int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, - size_t fw_size, enum i2400m_bri flags) -{ - int ret = 0; - struct device *dev = i2400m_dev(i2400m); - int count = i2400m->bus_bm_retries; - const struct i2400m_bcf_hdr *bcf_hdr; - size_t bcf_size; - - d_fnstart(5, dev, "(i2400m %p bcf %p fw size %zu)\n", - i2400m, bcf, fw_size); - i2400m->boot_mode = 1; - wmb(); /* Make sure other readers see it */ -hw_reboot: - if (count-- == 0) { - ret = -ERESTARTSYS; - dev_err(dev, "device rebooted too many times, aborting\n"); - goto error_too_many_reboots; - } - if (flags & I2400M_BRI_MAC_REINIT) { - ret = i2400m_bootrom_init(i2400m, flags); - if (ret < 0) { - dev_err(dev, "bootrom init failed: %d\n", ret); - goto error_bootrom_init; - } - } - flags |= I2400M_BRI_MAC_REINIT; - - /* - * Initialize the download, push the bytes to the device and - * then jump to the new firmware. Note @ret is passed with the - * offset of the jump instruction to _dnload_finalize() - * - * Note we need to use the BCF header in the firmware image - * that matches the barker that the device sent when it - * rebooted, so it has to be passed along. - */ - ret = -EBADF; - bcf_hdr = i2400m_bcf_hdr_find(i2400m); - if (bcf_hdr == NULL) - goto error_bcf_hdr_find; - - ret = i2400m_dnload_init(i2400m, bcf_hdr); - if (ret == -ERESTARTSYS) - goto error_dev_rebooted; - if (ret < 0) - goto error_dnload_init; - - /* - * bcf_size refers to one header size plus the fw sections size - * indicated by the header,ie. if there are other extended headers - * at the tail, they are not counted - */ - bcf_size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); - ret = i2400m_dnload_bcf(i2400m, bcf, bcf_size); - if (ret == -ERESTARTSYS) - goto error_dev_rebooted; - if (ret < 0) { - dev_err(dev, "fw %s: download failed: %d\n", - i2400m->fw_name, ret); - goto error_dnload_bcf; - } - - ret = i2400m_dnload_finalize(i2400m, bcf_hdr, bcf, ret); - if (ret == -ERESTARTSYS) - goto error_dev_rebooted; - if (ret < 0) { - dev_err(dev, "fw %s: " - "download finalization failed: %d\n", - i2400m->fw_name, ret); - goto error_dnload_finalize; - } - - d_printf(2, dev, "fw %s successfully uploaded\n", - i2400m->fw_name); - i2400m->boot_mode = 0; - wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ -error_dnload_finalize: -error_dnload_bcf: -error_dnload_init: -error_bcf_hdr_find: -error_bootrom_init: -error_too_many_reboots: - d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n", - i2400m, bcf, fw_size, ret); - return ret; - -error_dev_rebooted: - dev_err(dev, "device rebooted, %d tries left\n", count); - /* we got the notification already, no need to wait for it again */ - flags |= I2400M_BRI_SOFT; - goto hw_reboot; -} - -static -int i2400m_fw_bootstrap(struct i2400m *i2400m, const struct firmware *fw, - enum i2400m_bri flags) -{ - int ret; - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_bcf_hdr *bcf; /* Firmware data */ - - d_fnstart(5, dev, "(i2400m %p)\n", i2400m); - bcf = (void *) fw->data; - ret = i2400m_fw_check(i2400m, bcf, fw->size); - if (ret >= 0) - ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags); - if (ret < 0) - dev_err(dev, "%s: cannot use: %d, skipping\n", - i2400m->fw_name, ret); - kfree(i2400m->fw_hdrs); - i2400m->fw_hdrs = NULL; - d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); - return ret; -} - - -/* Refcounted container for firmware data */ -struct i2400m_fw { - struct kref kref; - const struct firmware *fw; -}; - - -static -void i2400m_fw_destroy(struct kref *kref) -{ - struct i2400m_fw *i2400m_fw = - container_of(kref, struct i2400m_fw, kref); - release_firmware(i2400m_fw->fw); - kfree(i2400m_fw); -} - - -static -struct i2400m_fw *i2400m_fw_get(struct i2400m_fw *i2400m_fw) -{ - if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) - kref_get(&i2400m_fw->kref); - return i2400m_fw; -} - - -static -void i2400m_fw_put(struct i2400m_fw *i2400m_fw) -{ - kref_put(&i2400m_fw->kref, i2400m_fw_destroy); -} - - -/** - * i2400m_dev_bootstrap - Bring the device to a known state and upload firmware - * - * @i2400m: device descriptor - * @flags: - * I2400M_BRI_SOFT: a reboot barker has been seen - * already, so don't wait for it. - * - * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait - * for a reboot barker notification. This is a one shot; if - * the state machine needs to send a reboot command it will. - * - * Returns: >= 0 if ok, < 0 errno code on error. - * - * This sets up the firmware upload environment, loads the firmware - * file from disk, verifies and then calls the firmware upload process - * per se. - * - * Can be called either from probe, or after a warm reset. Can not be - * called from within an interrupt. All the flow in this code is - * single-threade; all I/Os are synchronous. - */ -int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags) -{ - int ret, itr; - struct device *dev = i2400m_dev(i2400m); - struct i2400m_fw *i2400m_fw; - const struct firmware *fw; - const char *fw_name; - - d_fnstart(5, dev, "(i2400m %p)\n", i2400m); - - ret = -ENODEV; - spin_lock(&i2400m->rx_lock); - i2400m_fw = i2400m_fw_get(i2400m->fw_cached); - spin_unlock(&i2400m->rx_lock); - if (i2400m_fw == (void *) ~0) { - dev_err(dev, "can't load firmware now!"); - goto out; - } else if (i2400m_fw != NULL) { - dev_info(dev, "firmware %s: loading from cache\n", - i2400m->fw_name); - ret = i2400m_fw_bootstrap(i2400m, i2400m_fw->fw, flags); - i2400m_fw_put(i2400m_fw); - goto out; - } - - /* Load firmware files to memory. */ - for (itr = 0, ret = -ENOENT; ; itr++) { - fw_name = i2400m->bus_fw_names[itr]; - if (fw_name == NULL) { - dev_err(dev, "Could not find a usable firmware image\n"); - break; - } - d_printf(1, dev, "trying firmware %s (%d)\n", fw_name, itr); - ret = request_firmware(&fw, fw_name, dev); - if (ret < 0) { - dev_err(dev, "fw %s: cannot load file: %d\n", - fw_name, ret); - continue; - } - i2400m->fw_name = fw_name; - ret = i2400m_fw_bootstrap(i2400m, fw, flags); - release_firmware(fw); - if (ret >= 0) /* firmware loaded successfully */ - break; - i2400m->fw_name = NULL; - } -out: - d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); - return ret; -} -EXPORT_SYMBOL_GPL(i2400m_dev_bootstrap); - - -void i2400m_fw_cache(struct i2400m *i2400m) -{ - int result; - struct i2400m_fw *i2400m_fw; - struct device *dev = i2400m_dev(i2400m); - - /* if there is anything there, free it -- now, this'd be weird */ - spin_lock(&i2400m->rx_lock); - i2400m_fw = i2400m->fw_cached; - spin_unlock(&i2400m->rx_lock); - if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) { - i2400m_fw_put(i2400m_fw); - WARN(1, "%s:%u: still cached fw still present?\n", - __func__, __LINE__); - } - - if (i2400m->fw_name == NULL) { - dev_err(dev, "firmware n/a: can't cache\n"); - i2400m_fw = (void *) ~0; - goto out; - } - - i2400m_fw = kzalloc(sizeof(*i2400m_fw), GFP_ATOMIC); - if (i2400m_fw == NULL) - goto out; - kref_init(&i2400m_fw->kref); - result = request_firmware(&i2400m_fw->fw, i2400m->fw_name, dev); - if (result < 0) { - dev_err(dev, "firmware %s: failed to cache: %d\n", - i2400m->fw_name, result); - kfree(i2400m_fw); - i2400m_fw = (void *) ~0; - } else - dev_info(dev, "firmware %s: cached\n", i2400m->fw_name); -out: - spin_lock(&i2400m->rx_lock); - i2400m->fw_cached = i2400m_fw; - spin_unlock(&i2400m->rx_lock); -} - - -void i2400m_fw_uncache(struct i2400m *i2400m) -{ - struct i2400m_fw *i2400m_fw; - - spin_lock(&i2400m->rx_lock); - i2400m_fw = i2400m->fw_cached; - i2400m->fw_cached = NULL; - spin_unlock(&i2400m->rx_lock); - - if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) - i2400m_fw_put(i2400m_fw); -} - diff --git a/drivers/staging/wimax/i2400m/i2400m-usb.h b/drivers/staging/wimax/i2400m/i2400m-usb.h deleted file mode 100644 index eff4f464a23e14e92a7f57e77c08a6e1e6c8878c..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/i2400m-usb.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * USB-specific i2400m driver definitions - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * - * - * This driver implements the bus-specific part of the i2400m for - * USB. Check i2400m.h for a generic driver description. - * - * ARCHITECTURE - * - * This driver listens to notifications sent from the notification - * endpoint (in usb-notif.c); when data is ready to read, the code in - * there schedules a read from the device (usb-rx.c) and then passes - * the data to the generic RX code (rx.c). - * - * When the generic driver needs to send data (network or control), it - * queues up in the TX FIFO (tx.c) and that will notify the driver - * through the i2400m->bus_tx_kick() callback - * (usb-tx.c:i2400mu_bus_tx_kick) which will send the items in the - * FIFO queue. - * - * This driver, as well, implements the USB-specific ops for the generic - * driver to be able to setup/teardown communication with the device - * [i2400m_bus_dev_start() and i2400m_bus_dev_stop()], reseting the - * device [i2400m_bus_reset()] and performing firmware upload - * [i2400m_bus_bm_cmd() and i2400_bus_bm_wait_for_ack()]. - */ - -#ifndef __I2400M_USB_H__ -#define __I2400M_USB_H__ - -#include "i2400m.h" -#include <linux/kthread.h> - - -/* - * Error Density Count: cheapo error density (over time) counter - * - * Originally by Reinette Chatre <reinette.chatre@intel.com> - * - * Embed an 'struct edc' somewhere. Each time there is a soft or - * retryable error, call edc_inc() and check if the error top - * watermark has been reached. - */ -enum { - EDC_MAX_ERRORS = 10, - EDC_ERROR_TIMEFRAME = HZ, -}; - -/* error density counter */ -struct edc { - unsigned long timestart; - u16 errorcount; -}; - -struct i2400m_endpoint_cfg { - unsigned char bulk_out; - unsigned char notification; - unsigned char reset_cold; - unsigned char bulk_in; -}; - -static inline void edc_init(struct edc *edc) -{ - edc->timestart = jiffies; -} - -/** - * edc_inc - report a soft error and check if we are over the watermark - * - * @edc: pointer to error density counter. - * @max_err: maximum number of errors we can accept over the timeframe - * @timeframe: length of the timeframe (in jiffies). - * - * Returns: !0 1 if maximum acceptable errors per timeframe has been - * exceeded. 0 otherwise. - * - * This is way to determine if the number of acceptable errors per time - * period has been exceeded. It is not accurate as there are cases in which - * this scheme will not work, for example if there are periodic occurrences - * of errors that straddle updates to the start time. This scheme is - * sufficient for our usage. - * - * To use, embed a 'struct edc' somewhere, initialize it with - * edc_init() and when an error hits: - * - * if (do_something_fails_with_a_soft_error) { - * if (edc_inc(&my->edc, MAX_ERRORS, MAX_TIMEFRAME)) - * Ops, hard error, do something about it - * else - * Retry or ignore, depending on whatever - * } - */ -static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe) -{ - unsigned long now; - - now = jiffies; - if (time_after(now, edc->timestart + timeframe)) { - edc->errorcount = 1; - edc->timestart = now; - } else if (++edc->errorcount > max_err) { - edc->errorcount = 0; - edc->timestart = now; - return 1; - } - return 0; -} - -/* Host-Device interface for USB */ -enum { - I2400M_USB_BOOT_RETRIES = 3, - I2400MU_MAX_NOTIFICATION_LEN = 256, - I2400MU_BLK_SIZE = 16, - I2400MU_PL_SIZE_MAX = 0x3EFF, - - /* Device IDs */ - USB_DEVICE_ID_I6050 = 0x0186, - USB_DEVICE_ID_I6050_2 = 0x0188, - USB_DEVICE_ID_I6150 = 0x07d6, - USB_DEVICE_ID_I6150_2 = 0x07d7, - USB_DEVICE_ID_I6150_3 = 0x07d9, - USB_DEVICE_ID_I6250 = 0x0187, -}; - - -/** - * struct i2400mu - descriptor for a USB connected i2400m - * - * @i2400m: bus-generic i2400m implementation; has to be first (see - * it's documentation in i2400m.h). - * - * @usb_dev: pointer to our USB device - * - * @usb_iface: pointer to our USB interface - * - * @urb_edc: error density counter; used to keep a density-on-time tab - * on how many soft (retryable or ignorable) errors we get. If we - * go over the threshold, we consider the bus transport is failing - * too much and reset. - * - * @notif_urb: URB for receiving notifications from the device. - * - * @tx_kthread: thread we use for data TX. We use a thread because in - * order to do deep power saving and put the device to sleep, we - * need to call usb_autopm_*() [blocking functions]. - * - * @tx_wq: waitqueue for the TX kthread to sleep when there is no data - * to be sent; when more data is available, it is woken up by - * i2400mu_bus_tx_kick(). - * - * @rx_kthread: thread we use for data RX. We use a thread because in - * order to do deep power saving and put the device to sleep, we - * need to call usb_autopm_*() [blocking functions]. - * - * @rx_wq: waitqueue for the RX kthread to sleep when there is no data - * to receive. When data is available, it is woken up by - * usb-notif.c:i2400mu_notification_grok(). - * - * @rx_pending_count: number of rx-data-ready notifications that were - * still not handled by the RX kthread. - * - * @rx_size: current RX buffer size that is being used. - * - * @rx_size_acc: accumulator of the sizes of the previous read - * transactions. - * - * @rx_size_cnt: number of read transactions accumulated in - * @rx_size_acc. - * - * @do_autopm: disable(0)/enable(>0) calling the - * usb_autopm_get/put_interface() barriers when executing - * commands. See doc in i2400mu_suspend() for more information. - * - * @rx_size_auto_shrink: if true, the rx_size is shrunk - * automatically based on the average size of the received - * transactions. This allows the receive code to allocate smaller - * chunks of memory and thus reduce pressure on the memory - * allocator by not wasting so much space. By default it is - * enabled. - * - * @debugfs_dentry: hookup for debugfs files. - * These have to be in a separate directory, a child of - * (wimax_dev->debugfs_dentry) so they can be removed when the - * module unloads, as we don't keep each dentry. - */ -struct i2400mu { - struct i2400m i2400m; /* FIRST! See doc */ - - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - struct edc urb_edc; /* Error density counter */ - struct i2400m_endpoint_cfg endpoint_cfg; - - struct urb *notif_urb; - struct task_struct *tx_kthread; - wait_queue_head_t tx_wq; - - struct task_struct *rx_kthread; - wait_queue_head_t rx_wq; - atomic_t rx_pending_count; - size_t rx_size, rx_size_acc, rx_size_cnt; - atomic_t do_autopm; - u8 rx_size_auto_shrink; - - struct dentry *debugfs_dentry; - unsigned i6050:1; /* 1 if this is a 6050 based SKU */ -}; - - -static inline -void i2400mu_init(struct i2400mu *i2400mu) -{ - i2400m_init(&i2400mu->i2400m); - edc_init(&i2400mu->urb_edc); - init_waitqueue_head(&i2400mu->tx_wq); - atomic_set(&i2400mu->rx_pending_count, 0); - init_waitqueue_head(&i2400mu->rx_wq); - i2400mu->rx_size = PAGE_SIZE - sizeof(struct skb_shared_info); - atomic_set(&i2400mu->do_autopm, 1); - i2400mu->rx_size_auto_shrink = 1; -} - -int i2400mu_notification_setup(struct i2400mu *); -void i2400mu_notification_release(struct i2400mu *); - -int i2400mu_rx_setup(struct i2400mu *); -void i2400mu_rx_release(struct i2400mu *); -void i2400mu_rx_kick(struct i2400mu *); - -int i2400mu_tx_setup(struct i2400mu *); -void i2400mu_tx_release(struct i2400mu *); -void i2400mu_bus_tx_kick(struct i2400m *); - -ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *, - const struct i2400m_bootrom_header *, size_t, - int); -ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *, - struct i2400m_bootrom_header *, size_t); -#endif /* #ifndef __I2400M_USB_H__ */ diff --git a/drivers/staging/wimax/i2400m/i2400m.h b/drivers/staging/wimax/i2400m/i2400m.h deleted file mode 100644 index de22cc6f2c5c1b77661d85d36f711b7a2b804c7b..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/i2400m.h +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Declarations for bus-generic internal APIs - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * - * - * GENERAL DRIVER ARCHITECTURE - * - * The i2400m driver is split in the following two major parts: - * - * - bus specific driver - * - bus generic driver (this part) - * - * The bus specific driver sets up stuff specific to the bus the - * device is connected to (USB, PCI, tam-tam...non-authoritative - * nor binding list) which is basically the device-model management - * (probe/disconnect, etc), moving data from device to kernel and - * back, doing the power saving details and reseting the device. - * - * For details on each bus-specific driver, see it's include file, - * i2400m-BUSNAME.h - * - * The bus-generic functionality break up is: - * - * - Firmware upload: fw.c - takes care of uploading firmware to the - * device. bus-specific driver just needs to provides a way to - * execute boot-mode commands and to reset the device. - * - * - RX handling: rx.c - receives data from the bus-specific code and - * feeds it to the network or WiMAX stack or uses it to modify - * the driver state. bus-specific driver only has to receive - * frames and pass them to this module. - * - * - TX handling: tx.c - manages the TX FIFO queue and provides means - * for the bus-specific TX code to pull data from the FIFO - * queue. bus-specific code just pulls frames from this module - * to sends them to the device. - * - * - netdev glue: netdev.c - interface with Linux networking - * stack. Pass around data frames, and configure when the - * device is up and running or shutdown (through ifconfig up / - * down). Bus-generic only. - * - * - control ops: control.c - implements various commands for - * controlling the device. bus-generic only. - * - * - device model glue: driver.c - implements helpers for the - * device-model glue done by the bus-specific layer - * (setup/release the driver resources), turning the device on - * and off, handling the device reboots/resets and a few simple - * WiMAX stack ops. - * - * Code is also broken up in linux-glue / device-glue. - * - * Linux glue contains functions that deal mostly with gluing with the - * rest of the Linux kernel. - * - * Device-glue are functions that deal mostly with the way the device - * does things and talk the device's language. - * - * device-glue code is licensed BSD so other open source OSes can take - * it to implement their drivers. - * - * - * APIs AND HEADER FILES - * - * This bus generic code exports three APIs: - * - * - HDI (host-device interface) definitions common to all busses - * (include/linux/wimax/i2400m.h); these can be also used by user - * space code. - * - internal API for the bus-generic code - * - external API for the bus-specific drivers - * - * - * LIFE CYCLE: - * - * When the bus-specific driver probes, it allocates a network device - * with enough space for it's data structue, that must contain a - * &struct i2400m at the top. - * - * On probe, it needs to fill the i2400m members marked as [fill], as - * well as i2400m->wimax_dev.net_dev and call i2400m_setup(). The - * i2400m driver will only register with the WiMAX and network stacks; - * the only access done to the device is to read the MAC address so we - * can register a network device. - * - * The high-level call flow is: - * - * bus_probe() - * i2400m_setup() - * i2400m->bus_setup() - * boot rom initialization / read mac addr - * network / WiMAX stacks registration - * i2400m_dev_start() - * i2400m->bus_dev_start() - * i2400m_dev_initialize() - * - * The reverse applies for a disconnect() call: - * - * bus_disconnect() - * i2400m_release() - * i2400m_dev_stop() - * i2400m_dev_shutdown() - * i2400m->bus_dev_stop() - * network / WiMAX stack unregistration - * i2400m->bus_release() - * - * At this point, control and data communications are possible. - * - * While the device is up, it might reset. The bus-specific driver has - * to catch that situation and call i2400m_dev_reset_handle() to deal - * with it (reset the internal driver structures and go back to square - * one). - */ - -#ifndef __I2400M_H__ -#define __I2400M_H__ - -#include <linux/usb.h> -#include <linux/netdevice.h> -#include <linux/completion.h> -#include <linux/rwsem.h> -#include <linux/atomic.h> -#include "../net-wimax.h" -#include "linux-wimax-i2400m.h" -#include <asm/byteorder.h> - -enum { -/* netdev interface */ - /* - * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size - * - * The MTU is 1400 or less - */ - I2400M_MAX_MTU = 1400, -}; - -/* Misc constants */ -enum { - /* Size of the Boot Mode Command buffer */ - I2400M_BM_CMD_BUF_SIZE = 16 * 1024, - I2400M_BM_ACK_BUF_SIZE = 256, -}; - -enum { - /* Maximum number of bus reset can be retried */ - I2400M_BUS_RESET_RETRIES = 3, -}; - -/** - * struct i2400m_poke_table - Hardware poke table for the Intel 2400m - * - * This structure will be used to create a device specific poke table - * to put the device in a consistent state at boot time. - * - * @address: The device address to poke - * - * @data: The data value to poke to the device address - * - */ -struct i2400m_poke_table{ - __le32 address; - __le32 data; -}; - -#define I2400M_FW_POKE(a, d) { \ - .address = cpu_to_le32(a), \ - .data = cpu_to_le32(d) \ -} - - -/** - * i2400m_reset_type - methods to reset a device - * - * @I2400M_RT_WARM: Reset without device disconnection, device handles - * are kept valid but state is back to power on, with firmware - * re-uploaded. - * @I2400M_RT_COLD: Tell the device to disconnect itself from the bus - * and reconnect. Renders all device handles invalid. - * @I2400M_RT_BUS: Tells the bus to reset the device; last measure - * used when both types above don't work. - */ -enum i2400m_reset_type { - I2400M_RT_WARM, /* first measure */ - I2400M_RT_COLD, /* second measure */ - I2400M_RT_BUS, /* call in artillery */ -}; - -struct i2400m_reset_ctx; -struct i2400m_roq; -struct i2400m_barker_db; - -/** - * struct i2400m - descriptor for an Intel 2400m - * - * Members marked with [fill] must be filled out/initialized before - * calling i2400m_setup(). - * - * Note the @bus_setup/@bus_release, @bus_dev_start/@bus_dev_release - * call pairs are very much doing almost the same, and depending on - * the underlying bus, some stuff has to be put in one or the - * other. The idea of setup/release is that they setup the minimal - * amount needed for loading firmware, where us dev_start/stop setup - * the rest needed to do full data/control traffic. - * - * @bus_tx_block_size: [fill] USB imposes a 16 block size, but other - * busses will differ. So we have a tx_blk_size variable that the - * bus layer sets to tell the engine how much of that we need. - * - * @bus_tx_room_min: [fill] Minimum room required while allocating - * TX queue's buffer space for message header. USB requires - * 16 bytes. Refer to bus specific driver code for details. - * - * @bus_pl_size_max: [fill] Maximum payload size. - * - * @bus_setup: [optional fill] Function called by the bus-generic code - * [i2400m_setup()] to setup the basic bus-specific communications - * to the the device needed to load firmware. See LIFE CYCLE above. - * - * NOTE: Doesn't need to upload the firmware, as that is taken - * care of by the bus-generic code. - * - * @bus_release: [optional fill] Function called by the bus-generic - * code [i2400m_release()] to shutdown the basic bus-specific - * communications to the the device needed to load firmware. See - * LIFE CYCLE above. - * - * This function does not need to reset the device, just tear down - * all the host resources created to handle communication with - * the device. - * - * @bus_dev_start: [optional fill] Function called by the bus-generic - * code [i2400m_dev_start()] to do things needed to start the - * device. See LIFE CYCLE above. - * - * NOTE: Doesn't need to upload the firmware, as that is taken - * care of by the bus-generic code. - * - * @bus_dev_stop: [optional fill] Function called by the bus-generic - * code [i2400m_dev_stop()] to do things needed for stopping the - * device. See LIFE CYCLE above. - * - * This function does not need to reset the device, just tear down - * all the host resources created to handle communication with - * the device. - * - * @bus_tx_kick: [fill] Function called by the bus-generic code to let - * the bus-specific code know that there is data available in the - * TX FIFO for transmission to the device. - * - * This function cannot sleep. - * - * @bus_reset: [fill] Function called by the bus-generic code to reset - * the device in in various ways. Doesn't need to wait for the - * reset to finish. - * - * If warm or cold reset fail, this function is expected to do a - * bus-specific reset (eg: USB reset) to get the device to a - * working state (even if it implies device disconecction). - * - * Note the warm reset is used by the firmware uploader to - * reinitialize the device. - * - * IMPORTANT: this is called very early in the device setup - * process, so it cannot rely on common infrastructure being laid - * out. - * - * IMPORTANT: don't call reset on RT_BUS with i2400m->init_mutex - * held, as the .pre/.post reset handlers will deadlock. - * - * @bus_bm_retries: [fill] How many times shall a firmware upload / - * device initialization be retried? Different models of the same - * device might need different values, hence it is set by the - * bus-specific driver. Note this value is used in two places, - * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become - * multiplicative (__i2400m_dev_start() calling N times - * i2400m_fw_dnload() and this trying N times to download the - * firmware), as if __i2400m_dev_start() only retries if the - * firmware crashed while initializing the device (not in a - * general case). - * - * @bus_bm_cmd_send: [fill] Function called to send a boot-mode - * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This - * is synchronous and has to return 0 if ok or < 0 errno code in - * any error condition. - * - * @bus_bm_wait_for_ack: [fill] Function called to wait for a - * boot-mode notification (that can be a response to a previously - * issued command or an asynchronous one). Will read until all the - * indicated size is read or timeout. Reading more or less data - * than asked for is an error condition. Return 0 if ok, < 0 errno - * code on error. - * - * The caller to this function will check if the response is a - * barker that indicates the device going into reset mode. - * - * @bus_fw_names: [fill] a NULL-terminated array with the names of the - * firmware images to try loading. This is made a list so we can - * support backward compatibility of firmware releases (eg: if we - * can't find the default v1.4, we try v1.3). In general, the name - * should be i2400m-fw-X-VERSION.sbcf, where X is the bus name. - * The list is tried in order and the first one that loads is - * used. The fw loader will set i2400m->fw_name to point to the - * active firmware image. - * - * @bus_bm_mac_addr_impaired: [fill] Set to true if the device's MAC - * address provided in boot mode is kind of broken and needs to - * be re-read later on. - * - * @bus_bm_pokes_table: [fill/optional] A table of device addresses - * and values that will be poked at device init time to move the - * device to the correct state for the type of boot/firmware being - * used. This table MUST be terminated with (0x000000, - * 0x00000000) or bad things will happen. - * - * - * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX - * stack. Due to the way a net_device is allocated, we need to - * force this to be the first field so that we can get from - * netdev_priv() the right pointer. - * - * @updown: the device is up and ready for transmitting control and - * data packets. This implies @ready (communication infrastructure - * with the device is ready) and the device's firmware has been - * loaded and the device initialized. - * - * Write to it only inside a i2400m->init_mutex protected area - * followed with a wmb(); rmb() before accesing (unless locked - * inside i2400m->init_mutex). Read access can be loose like that - * [just using rmb()] because the paths that use this also do - * other error checks later on. - * - * @ready: Communication infrastructure with the device is ready, data - * frames can start to be passed around (this is lighter than - * using the WiMAX state for certain hot paths). - * - * Write to it only inside a i2400m->init_mutex protected area - * followed with a wmb(); rmb() before accesing (unless locked - * inside i2400m->init_mutex). Read access can be loose like that - * [just using rmb()] because the paths that use this also do - * other error checks later on. - * - * @rx_reorder: 1 if RX reordering is enabled; this can only be - * set at probe time. - * - * @state: device's state (as reported by it) - * - * @state_wq: waitqueue that is woken up whenever the state changes - * - * @tx_lock: spinlock to protect TX members - * - * @tx_buf: FIFO buffer for TX; we queue data here - * - * @tx_in: FIFO index for incoming data. Note this doesn't wrap around - * and it is always greater than @tx_out. - * - * @tx_out: FIFO index for outgoing data - * - * @tx_msg: current TX message that is active in the FIFO for - * appending payloads. - * - * @tx_sequence: current sequence number for TX messages from the - * device to the host. - * - * @tx_msg_size: size of the current message being transmitted by the - * bus-specific code. - * - * @tx_pl_num: total number of payloads sent - * - * @tx_pl_max: maximum number of payloads sent in a TX message - * - * @tx_pl_min: minimum number of payloads sent in a TX message - * - * @tx_num: number of TX messages sent - * - * @tx_size_acc: number of bytes in all TX messages sent - * (this is different to net_dev's statistics as it also counts - * control messages). - * - * @tx_size_min: smallest TX message sent. - * - * @tx_size_max: biggest TX message sent. - * - * @rx_lock: spinlock to protect RX members and rx_roq_refcount. - * - * @rx_pl_num: total number of payloads received - * - * @rx_pl_max: maximum number of payloads received in a RX message - * - * @rx_pl_min: minimum number of payloads received in a RX message - * - * @rx_num: number of RX messages received - * - * @rx_size_acc: number of bytes in all RX messages received - * (this is different to net_dev's statistics as it also counts - * control messages). - * - * @rx_size_min: smallest RX message received. - * - * @rx_size_max: buggest RX message received. - * - * @rx_roq: RX ReOrder queues. (fw >= v1.4) When packets are received - * out of order, the device will ask the driver to hold certain - * packets until the ones that are received out of order can be - * delivered. Then the driver can release them to the host. See - * drivers/net/i2400m/rx.c for details. - * - * @rx_roq_refcount: refcount rx_roq. This refcounts any access to - * rx_roq thus preventing rx_roq being destroyed when rx_roq - * is being accessed. rx_roq_refcount is protected by rx_lock. - * - * @rx_reports: reports received from the device that couldn't be - * processed because the driver wasn't still ready; when ready, - * they are pulled from here and chewed. - * - * @rx_reports_ws: Work struct used to kick a scan of the RX reports - * list and to process each. - * - * @src_mac_addr: MAC address used to make ethernet packets be coming - * from. This is generated at i2400m_setup() time and used during - * the life cycle of the instance. See i2400m_fake_eth_header(). - * - * @init_mutex: Mutex used for serializing the device bringup - * sequence; this way if the device reboots in the middle, we - * don't try to do a bringup again while we are tearing down the - * one that failed. - * - * Can't reuse @msg_mutex because from within the bringup sequence - * we need to send messages to the device and thus use @msg_mutex. - * - * @msg_mutex: mutex used to send control commands to the device (we - * only allow one at a time, per host-device interface design). - * - * @msg_completion: used to wait for an ack to a control command sent - * to the device. - * - * @ack_skb: used to store the actual ack to a control command if the - * reception of the command was successful. Otherwise, a ERR_PTR() - * errno code that indicates what failed with the ack reception. - * - * Only valid after @msg_completion is woken up. Only updateable - * if @msg_completion is armed. Only touched by - * i2400m_msg_to_dev(). - * - * Protected by @rx_lock. In theory the command execution flow is - * sequential, but in case the device sends an out-of-phase or - * very delayed response, we need to avoid it trampling current - * execution. - * - * @bm_cmd_buf: boot mode command buffer for composing firmware upload - * commands. - * - * USB can't r/w to stack, vmalloc, etc...as well, we end up - * having to alloc/free a lot to compose commands, so we use these - * for stagging and not having to realloc all the time. - * - * This assumes the code always runs serialized. Only one thread - * can call i2400m_bm_cmd() at the same time. - * - * @bm_ack_buf: boot mode acknoledge buffer for staging reception of - * responses to commands. - * - * See @bm_cmd_buf. - * - * @work_queue: work queue for processing device reports. This - * workqueue cannot be used for processing TX or RX to the device, - * as from it we'll process device reports, which might require - * further communication with the device. - * - * @debugfs_dentry: hookup for debugfs files. - * These have to be in a separate directory, a child of - * (wimax_dev->debugfs_dentry) so they can be removed when the - * module unloads, as we don't keep each dentry. - * - * @fw_name: name of the firmware image that is currently being used. - * - * @fw_version: version of the firmware interface, Major.minor, - * encoded in the high word and low word (major << 16 | minor). - * - * @fw_hdrs: NULL terminated array of pointers to the firmware - * headers. This is only available during firmware load time. - * - * @fw_cached: Used to cache firmware when the system goes to - * suspend/standby/hibernation (as on resume we can't read it). If - * NULL, no firmware was cached, read it. If ~0, you can't read - * any firmware files (the system still didn't come out of suspend - * and failed to cache one), so abort; otherwise, a valid cached - * firmware to be used. Access to this variable is protected by - * the spinlock i2400m->rx_lock. - * - * @barker: barker type that the device uses; this is initialized by - * i2400m_is_boot_barker() the first time it is called. Then it - * won't change during the life cycle of the device and every time - * a boot barker is received, it is just verified for it being the - * same. - * - * @pm_notifier: used to register for PM events - * - * @bus_reset_retries: counter for the number of bus resets attempted for - * this boot. It's not for tracking the number of bus resets during - * the whole driver life cycle (from insmod to rmmod) but for the - * number of dev_start() executed until dev_start() returns a success - * (ie: a good boot means a dev_stop() followed by a successful - * dev_start()). dev_reset_handler() increments this counter whenever - * it is triggering a bus reset. It checks this counter to decide if a - * subsequent bus reset should be retried. dev_reset_handler() retries - * the bus reset until dev_start() succeeds or the counter reaches - * I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in - * dev_reset_handle() when dev_start() returns a success, - * ie: a successul boot is completed. - * - * @alive: flag to denote if the device *should* be alive. This flag is - * everything like @updown (see doc for @updown) except reflecting - * the device state *we expect* rather than the actual state as denoted - * by @updown. It is set 1 whenever @updown is set 1 in dev_start(). - * Then the device is expected to be alive all the time - * (i2400m->alive remains 1) until the driver is removed. Therefore - * all the device reboot events detected can be still handled properly - * by either dev_reset_handle() or .pre_reset/.post_reset as long as - * the driver presents. It is set 0 along with @updown in dev_stop(). - * - * @error_recovery: flag to denote if we are ready to take an error recovery. - * 0 for ready to take an error recovery; 1 for not ready. It is - * initialized to 1 while probe() since we don't tend to take any error - * recovery during probe(). It is decremented by 1 whenever dev_start() - * succeeds to indicate we are ready to take error recovery from now on. - * It is checked every time we wanna schedule an error recovery. If an - * error recovery is already in place (error_recovery was set 1), we - * should not schedule another one until the last one is done. - */ -struct i2400m { - struct wimax_dev wimax_dev; /* FIRST! See doc */ - - unsigned updown:1; /* Network device is up or down */ - unsigned boot_mode:1; /* is the device in boot mode? */ - unsigned sboot:1; /* signed or unsigned fw boot */ - unsigned ready:1; /* Device comm infrastructure ready */ - unsigned rx_reorder:1; /* RX reorder is enabled */ - u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */ - /* typed u8 so /sys/kernel/debug/u8 can tweak */ - enum i2400m_system_state state; - wait_queue_head_t state_wq; /* Woken up when on state updates */ - - size_t bus_tx_block_size; - size_t bus_tx_room_min; - size_t bus_pl_size_max; - unsigned bus_bm_retries; - - int (*bus_setup)(struct i2400m *); - int (*bus_dev_start)(struct i2400m *); - void (*bus_dev_stop)(struct i2400m *); - void (*bus_release)(struct i2400m *); - void (*bus_tx_kick)(struct i2400m *); - int (*bus_reset)(struct i2400m *, enum i2400m_reset_type); - ssize_t (*bus_bm_cmd_send)(struct i2400m *, - const struct i2400m_bootrom_header *, - size_t, int flags); - ssize_t (*bus_bm_wait_for_ack)(struct i2400m *, - struct i2400m_bootrom_header *, size_t); - const char **bus_fw_names; - unsigned bus_bm_mac_addr_impaired:1; - const struct i2400m_poke_table *bus_bm_pokes_table; - - spinlock_t tx_lock; /* protect TX state */ - void *tx_buf; - size_t tx_in, tx_out; - struct i2400m_msg_hdr *tx_msg; - size_t tx_sequence, tx_msg_size; - /* TX stats */ - unsigned tx_pl_num, tx_pl_max, tx_pl_min, - tx_num, tx_size_acc, tx_size_min, tx_size_max; - - /* RX stuff */ - /* protect RX state and rx_roq_refcount */ - spinlock_t rx_lock; - unsigned rx_pl_num, rx_pl_max, rx_pl_min, - rx_num, rx_size_acc, rx_size_min, rx_size_max; - struct i2400m_roq *rx_roq; /* access is refcounted */ - struct kref rx_roq_refcount; /* refcount access to rx_roq */ - u8 src_mac_addr[ETH_HLEN]; - struct list_head rx_reports; /* under rx_lock! */ - struct work_struct rx_report_ws; - - struct mutex msg_mutex; /* serialize command execution */ - struct completion msg_completion; - struct sk_buff *ack_skb; /* protected by rx_lock */ - - void *bm_ack_buf; /* for receiving acks over USB */ - void *bm_cmd_buf; /* for issuing commands over USB */ - - struct workqueue_struct *work_queue; - - struct mutex init_mutex; /* protect bringup seq */ - struct i2400m_reset_ctx *reset_ctx; /* protected by init_mutex */ - - struct work_struct wake_tx_ws; - struct sk_buff *wake_tx_skb; - - struct work_struct reset_ws; - const char *reset_reason; - - struct work_struct recovery_ws; - - struct dentry *debugfs_dentry; - const char *fw_name; /* name of the current firmware image */ - unsigned long fw_version; /* version of the firmware interface */ - const struct i2400m_bcf_hdr **fw_hdrs; - struct i2400m_fw *fw_cached; /* protected by rx_lock */ - struct i2400m_barker_db *barker; - - struct notifier_block pm_notifier; - - /* counting bus reset retries in this boot */ - atomic_t bus_reset_retries; - - /* if the device is expected to be alive */ - unsigned alive; - - /* 0 if we are ready for error recovery; 1 if not ready */ - atomic_t error_recovery; - -}; - - -/* - * Bus-generic internal APIs - * ------------------------- - */ - -static inline -struct i2400m *wimax_dev_to_i2400m(struct wimax_dev *wimax_dev) -{ - return container_of(wimax_dev, struct i2400m, wimax_dev); -} - -static inline -struct i2400m *net_dev_to_i2400m(struct net_device *net_dev) -{ - return wimax_dev_to_i2400m(netdev_priv(net_dev)); -} - -/* - * Boot mode support - */ - -/** - * i2400m_bm_cmd_flags - flags to i2400m_bm_cmd() - * - * @I2400M_BM_CMD_RAW: send the command block as-is, without doing any - * extra processing for adding CRC. - */ -enum i2400m_bm_cmd_flags { - I2400M_BM_CMD_RAW = 1 << 2, -}; - -/** - * i2400m_bri - Boot-ROM indicators - * - * Flags for i2400m_bootrom_init() and i2400m_dev_bootstrap() [which - * are passed from things like i2400m_setup()]. Can be combined with - * |. - * - * @I2400M_BRI_SOFT: The device rebooted already and a reboot - * barker received, proceed directly to ack the boot sequence. - * @I2400M_BRI_NO_REBOOT: Do not reboot the device and proceed - * directly to wait for a reboot barker from the device. - * @I2400M_BRI_MAC_REINIT: We need to reinitialize the boot - * rom after reading the MAC address. This is quite a dirty hack, - * if you ask me -- the device requires the bootrom to be - * initialized after reading the MAC address. - */ -enum i2400m_bri { - I2400M_BRI_SOFT = 1 << 1, - I2400M_BRI_NO_REBOOT = 1 << 2, - I2400M_BRI_MAC_REINIT = 1 << 3, -}; - -void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *); -int i2400m_dev_bootstrap(struct i2400m *, enum i2400m_bri); -int i2400m_read_mac_addr(struct i2400m *); -int i2400m_bootrom_init(struct i2400m *, enum i2400m_bri); -int i2400m_is_boot_barker(struct i2400m *, const void *, size_t); -static inline -int i2400m_is_d2h_barker(const void *buf) -{ - const __le32 *barker = buf; - return le32_to_cpu(*barker) == I2400M_D2H_MSG_BARKER; -} -void i2400m_unknown_barker(struct i2400m *, const void *, size_t); - -/* Make/grok boot-rom header commands */ - -static inline -__le32 i2400m_brh_command(enum i2400m_brh_opcode opcode, unsigned use_checksum, - unsigned direct_access) -{ - return cpu_to_le32( - I2400M_BRH_SIGNATURE - | (direct_access ? I2400M_BRH_DIRECT_ACCESS : 0) - | I2400M_BRH_RESPONSE_REQUIRED /* response always required */ - | (use_checksum ? I2400M_BRH_USE_CHECKSUM : 0) - | (opcode & I2400M_BRH_OPCODE_MASK)); -} - -static inline -void i2400m_brh_set_opcode(struct i2400m_bootrom_header *hdr, - enum i2400m_brh_opcode opcode) -{ - hdr->command = cpu_to_le32( - (le32_to_cpu(hdr->command) & ~I2400M_BRH_OPCODE_MASK) - | (opcode & I2400M_BRH_OPCODE_MASK)); -} - -static inline -unsigned i2400m_brh_get_opcode(const struct i2400m_bootrom_header *hdr) -{ - return le32_to_cpu(hdr->command) & I2400M_BRH_OPCODE_MASK; -} - -static inline -unsigned i2400m_brh_get_response(const struct i2400m_bootrom_header *hdr) -{ - return (le32_to_cpu(hdr->command) & I2400M_BRH_RESPONSE_MASK) - >> I2400M_BRH_RESPONSE_SHIFT; -} - -static inline -unsigned i2400m_brh_get_use_checksum(const struct i2400m_bootrom_header *hdr) -{ - return le32_to_cpu(hdr->command) & I2400M_BRH_USE_CHECKSUM; -} - -static inline -unsigned i2400m_brh_get_response_required( - const struct i2400m_bootrom_header *hdr) -{ - return le32_to_cpu(hdr->command) & I2400M_BRH_RESPONSE_REQUIRED; -} - -static inline -unsigned i2400m_brh_get_direct_access(const struct i2400m_bootrom_header *hdr) -{ - return le32_to_cpu(hdr->command) & I2400M_BRH_DIRECT_ACCESS; -} - -static inline -unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr) -{ - return (le32_to_cpu(hdr->command) & I2400M_BRH_SIGNATURE_MASK) - >> I2400M_BRH_SIGNATURE_SHIFT; -} - - -/* - * Driver / device setup and internal functions - */ -void i2400m_init(struct i2400m *); -int i2400m_reset(struct i2400m *, enum i2400m_reset_type); -void i2400m_netdev_setup(struct net_device *net_dev); -int i2400m_sysfs_setup(struct device_driver *); -void i2400m_sysfs_release(struct device_driver *); -int i2400m_tx_setup(struct i2400m *); -void i2400m_wake_tx_work(struct work_struct *); -void i2400m_tx_release(struct i2400m *); - -int i2400m_rx_setup(struct i2400m *); -void i2400m_rx_release(struct i2400m *); - -void i2400m_fw_cache(struct i2400m *); -void i2400m_fw_uncache(struct i2400m *); - -void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned, const void *, - int); -void i2400m_net_erx(struct i2400m *, struct sk_buff *, enum i2400m_cs); -void i2400m_net_wake_stop(struct i2400m *); -enum i2400m_pt; -int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt); - -#ifdef CONFIG_DEBUG_FS -void i2400m_debugfs_add(struct i2400m *); -void i2400m_debugfs_rm(struct i2400m *); -#else -static inline void i2400m_debugfs_add(struct i2400m *i2400m) {} -static inline void i2400m_debugfs_rm(struct i2400m *i2400m) {} -#endif - -/* Initialize/shutdown the device */ -int i2400m_dev_initialize(struct i2400m *); -void i2400m_dev_shutdown(struct i2400m *); - -extern struct attribute_group i2400m_dev_attr_group; - - -/* HDI message's payload description handling */ - -static inline -size_t i2400m_pld_size(const struct i2400m_pld *pld) -{ - return I2400M_PLD_SIZE_MASK & le32_to_cpu(pld->val); -} - -static inline -enum i2400m_pt i2400m_pld_type(const struct i2400m_pld *pld) -{ - return (I2400M_PLD_TYPE_MASK & le32_to_cpu(pld->val)) - >> I2400M_PLD_TYPE_SHIFT; -} - -static inline -void i2400m_pld_set(struct i2400m_pld *pld, size_t size, - enum i2400m_pt type) -{ - pld->val = cpu_to_le32( - ((type << I2400M_PLD_TYPE_SHIFT) & I2400M_PLD_TYPE_MASK) - | (size & I2400M_PLD_SIZE_MASK)); -} - - -/* - * API for the bus-specific drivers - * -------------------------------- - */ - -static inline -struct i2400m *i2400m_get(struct i2400m *i2400m) -{ - dev_hold(i2400m->wimax_dev.net_dev); - return i2400m; -} - -static inline -void i2400m_put(struct i2400m *i2400m) -{ - dev_put(i2400m->wimax_dev.net_dev); -} - -int i2400m_dev_reset_handle(struct i2400m *, const char *); -int i2400m_pre_reset(struct i2400m *); -int i2400m_post_reset(struct i2400m *); -void i2400m_error_recovery(struct i2400m *); - -/* - * _setup()/_release() are called by the probe/disconnect functions of - * the bus-specific drivers. - */ -int i2400m_setup(struct i2400m *, enum i2400m_bri bm_flags); -void i2400m_release(struct i2400m *); - -int i2400m_rx(struct i2400m *, struct sk_buff *); -struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *); -void i2400m_tx_msg_sent(struct i2400m *); - - -/* - * Utility functions - */ - -static inline -struct device *i2400m_dev(struct i2400m *i2400m) -{ - return i2400m->wimax_dev.net_dev->dev.parent; -} - -int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *, char *, size_t); -int i2400m_msg_size_check(struct i2400m *, const struct i2400m_l3l4_hdr *, - size_t); -struct sk_buff *i2400m_msg_to_dev(struct i2400m *, const void *, size_t); -void i2400m_msg_to_dev_cancel_wait(struct i2400m *, int); -void i2400m_report_hook(struct i2400m *, const struct i2400m_l3l4_hdr *, - size_t); -void i2400m_report_hook_work(struct work_struct *); -int i2400m_cmd_enter_powersave(struct i2400m *); -int i2400m_cmd_exit_idle(struct i2400m *); -struct sk_buff *i2400m_get_device_info(struct i2400m *); -int i2400m_firmware_check(struct i2400m *); -int i2400m_set_idle_timeout(struct i2400m *, unsigned); - -static inline -struct usb_endpoint_descriptor *usb_get_epd(struct usb_interface *iface, int ep) -{ - return &iface->cur_altsetting->endpoint[ep].desc; -} - -int i2400m_op_rfkill_sw_toggle(struct wimax_dev *, enum wimax_rf_state); -void i2400m_report_tlv_rf_switches_status(struct i2400m *, - const struct i2400m_tlv_rf_switches_status *); - -/* - * Helpers for firmware backwards compatibility - * - * As we aim to support at least the firmware version that was - * released with the previous kernel/driver release, some code will be - * conditionally executed depending on the firmware version. On each - * release, the code to support fw releases past the last two ones - * will be purged. - * - * By making it depend on this macros, it is easier to keep it a tab - * on what has to go and what not. - */ -static inline -unsigned i2400m_le_v1_3(struct i2400m *i2400m) -{ - /* running fw is lower or v1.3 */ - return i2400m->fw_version <= 0x00090001; -} - -static inline -unsigned i2400m_ge_v1_4(struct i2400m *i2400m) -{ - /* running fw is higher or v1.4 */ - return i2400m->fw_version >= 0x00090002; -} - - -/* - * Do a millisecond-sleep for allowing wireshark to dump all the data - * packets. Used only for debugging. - */ -static inline -void __i2400m_msleep(unsigned ms) -{ -#if 1 -#else - msleep(ms); -#endif -} - - -/* module initialization helpers */ -int i2400m_barker_db_init(const char *); -void i2400m_barker_db_exit(void); - - - -#endif /* #ifndef __I2400M_H__ */ diff --git a/drivers/staging/wimax/i2400m/linux-wimax-i2400m.h b/drivers/staging/wimax/i2400m/linux-wimax-i2400m.h deleted file mode 100644 index fd198bc24a3c9d81ed0074fbacce6594cf90ceee..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/linux-wimax-i2400m.h +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Intel Wireless WiMax Connection 2400m - * Host-Device protocol interface definitions - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * - * This header defines the data structures and constants used to - * communicate with the device. - * - * BOOTMODE/BOOTROM/FIRMWARE UPLOAD PROTOCOL - * - * The firmware upload protocol is quite simple and only requires a - * handful of commands. See drivers/net/wimax/i2400m/fw.c for more - * details. - * - * The BCF data structure is for the firmware file header. - * - * - * THE DATA / CONTROL PROTOCOL - * - * This is the normal protocol spoken with the device once the - * firmware is uploaded. It transports data payloads and control - * messages back and forth. - * - * It consists 'messages' that pack one or more payloads each. The - * format is described in detail in drivers/net/wimax/i2400m/rx.c and - * tx.c. - * - * - * THE L3L4 PROTOCOL - * - * The term L3L4 refers to Layer 3 (the device), Layer 4 (the - * driver/host software). - * - * This is the control protocol used by the host to control the i2400m - * device (scan, connect, disconnect...). This is sent to / received - * as control frames. These frames consist of a header and zero or - * more TLVs with information. We call each control frame a "message". - * - * Each message is composed of: - * - * HEADER - * [TLV0 + PAYLOAD0] - * [TLV1 + PAYLOAD1] - * [...] - * [TLVN + PAYLOADN] - * - * The HEADER is defined by 'struct i2400m_l3l4_hdr'. The payloads are - * defined by a TLV structure (Type Length Value) which is a 'header' - * (struct i2400m_tlv_hdr) and then the payload. - * - * All integers are represented as Little Endian. - * - * - REQUESTS AND EVENTS - * - * The requests can be clasified as follows: - * - * COMMAND: implies a request from the host to the device requesting - * an action being performed. The device will reply with a - * message (with the same type as the command), status and - * no (TLV) payload. Execution of a command might cause - * events (of different type) to be sent later on as - * device's state changes. - * - * GET/SET: similar to COMMAND, but will not cause other - * EVENTs. The reply, in the case of GET, will contain - * TLVs with the requested information. - * - * EVENT: asynchronous messages sent from the device, maybe as a - * consequence of previous COMMANDs but disassociated from - * them. - * - * Only one request might be pending at the same time (ie: don't - * parallelize nor post another GET request before the previous - * COMMAND has been acknowledged with it's corresponding reply by the - * device). - * - * The different requests and their formats are described below: - * - * I2400M_MT_* Message types - * I2400M_MS_* Message status (for replies, events) - * i2400m_tlv_* TLVs - * - * data types are named 'struct i2400m_msg_OPNAME', OPNAME matching the - * operation. - */ - -#ifndef __LINUX__WIMAX__I2400M_H__ -#define __LINUX__WIMAX__I2400M_H__ - -#include <linux/types.h> -#include <linux/if_ether.h> - -/* - * Host Device Interface (HDI) common to all busses - */ - -/* Boot-mode (firmware upload mode) commands */ - -/* Header for the firmware file */ -struct i2400m_bcf_hdr { - __le32 module_type; - __le32 header_len; - __le32 header_version; - __le32 module_id; - __le32 module_vendor; - __le32 date; /* BCD YYYMMDD */ - __le32 size; /* in dwords */ - __le32 key_size; /* in dwords */ - __le32 modulus_size; /* in dwords */ - __le32 exponent_size; /* in dwords */ - __u8 reserved[88]; -} __attribute__ ((packed)); - -/* Boot mode opcodes */ -enum i2400m_brh_opcode { - I2400M_BRH_READ = 1, - I2400M_BRH_WRITE = 2, - I2400M_BRH_JUMP = 3, - I2400M_BRH_SIGNED_JUMP = 8, - I2400M_BRH_HASH_PAYLOAD_ONLY = 9, -}; - -/* Boot mode command masks and stuff */ -enum i2400m_brh { - I2400M_BRH_SIGNATURE = 0xcbbc0000, - I2400M_BRH_SIGNATURE_MASK = 0xffff0000, - I2400M_BRH_SIGNATURE_SHIFT = 16, - I2400M_BRH_OPCODE_MASK = 0x0000000f, - I2400M_BRH_RESPONSE_MASK = 0x000000f0, - I2400M_BRH_RESPONSE_SHIFT = 4, - I2400M_BRH_DIRECT_ACCESS = 0x00000400, - I2400M_BRH_RESPONSE_REQUIRED = 0x00000200, - I2400M_BRH_USE_CHECKSUM = 0x00000100, -}; - - -/** - * i2400m_bootrom_header - Header for a boot-mode command - * - * @cmd: the above command descriptor - * @target_addr: where on the device memory should the action be performed. - * @data_size: for read/write, amount of data to be read/written - * @block_checksum: checksum value (if applicable) - * @payload: the beginning of data attached to this header - */ -struct i2400m_bootrom_header { - __le32 command; /* Compose with enum i2400_brh */ - __le32 target_addr; - __le32 data_size; - __le32 block_checksum; - char payload[0]; -} __attribute__ ((packed)); - - -/* - * Data / control protocol - */ - -/* Packet types for the host-device interface */ -enum i2400m_pt { - I2400M_PT_DATA = 0, - I2400M_PT_CTRL, - I2400M_PT_TRACE, /* For device debug */ - I2400M_PT_RESET_WARM, /* device reset */ - I2400M_PT_RESET_COLD, /* USB[transport] reset, like reconnect */ - I2400M_PT_EDATA, /* Extended RX data */ - I2400M_PT_ILLEGAL -}; - - -/* - * Payload for a data packet - * - * This is prefixed to each and every outgoing DATA type. - */ -struct i2400m_pl_data_hdr { - __le32 reserved; -} __attribute__((packed)); - - -/* - * Payload for an extended data packet - * - * New in fw v1.4 - * - * @reorder: if this payload has to be reorder or not (and how) - * @cs: the type of data in the packet, as defined per (802.16e - * T11.13.19.1). Currently only 2 (IPv4 packet) supported. - * - * This is prefixed to each and every INCOMING DATA packet. - */ -struct i2400m_pl_edata_hdr { - __le32 reorder; /* bits defined in i2400m_ro */ - __u8 cs; - __u8 reserved[11]; -} __attribute__((packed)); - -enum i2400m_cs { - I2400M_CS_IPV4_0 = 0, - I2400M_CS_IPV4 = 2, -}; - -enum i2400m_ro { - I2400M_RO_NEEDED = 0x01, - I2400M_RO_TYPE = 0x03, - I2400M_RO_TYPE_SHIFT = 1, - I2400M_RO_CIN = 0x0f, - I2400M_RO_CIN_SHIFT = 4, - I2400M_RO_FBN = 0x07ff, - I2400M_RO_FBN_SHIFT = 8, - I2400M_RO_SN = 0x07ff, - I2400M_RO_SN_SHIFT = 21, -}; - -enum i2400m_ro_type { - I2400M_RO_TYPE_RESET = 0, - I2400M_RO_TYPE_PACKET, - I2400M_RO_TYPE_WS, - I2400M_RO_TYPE_PACKET_WS, -}; - - -/* Misc constants */ -enum { - I2400M_PL_ALIGN = 16, /* Payload data size alignment */ - I2400M_PL_SIZE_MAX = 0x3EFF, - I2400M_MAX_PLS_IN_MSG = 60, - /* protocol barkers: sync sequences; for notifications they - * are sent in groups of four. */ - I2400M_H2D_PREVIEW_BARKER = 0xcafe900d, - I2400M_COLD_RESET_BARKER = 0xc01dc01d, - I2400M_WARM_RESET_BARKER = 0x50f750f7, - I2400M_NBOOT_BARKER = 0xdeadbeef, - I2400M_SBOOT_BARKER = 0x0ff1c1a1, - I2400M_SBOOT_BARKER_6050 = 0x80000001, - I2400M_ACK_BARKER = 0xfeedbabe, - I2400M_D2H_MSG_BARKER = 0xbeefbabe, -}; - - -/* - * Hardware payload descriptor - * - * Bitfields encoded in a struct to enforce typing semantics. - * - * Look in rx.c and tx.c for a full description of the format. - */ -struct i2400m_pld { - __le32 val; -} __attribute__ ((packed)); - -#define I2400M_PLD_SIZE_MASK 0x00003fff -#define I2400M_PLD_TYPE_SHIFT 16 -#define I2400M_PLD_TYPE_MASK 0x000f0000 - -/* - * Header for a TX message or RX message - * - * @barker: preamble - * @size: used for management of the FIFO queue buffer; before - * sending, this is converted to be a real preamble. This - * indicates the real size of the TX message that starts at this - * point. If the highest bit is set, then this message is to be - * skipped. - * @sequence: sequence number of this message - * @offset: offset where the message itself starts -- see the comments - * in the file header about message header and payload descriptor - * alignment. - * @num_pls: number of payloads in this message - * @padding: amount of padding bytes at the end of the message to make - * it be of block-size aligned - * - * Look in rx.c and tx.c for a full description of the format. - */ -struct i2400m_msg_hdr { - union { - __le32 barker; - __u32 size; /* same size type as barker!! */ - }; - union { - __le32 sequence; - __u32 offset; /* same size type as barker!! */ - }; - __le16 num_pls; - __le16 rsv1; - __le16 padding; - __le16 rsv2; - struct i2400m_pld pld[0]; -} __attribute__ ((packed)); - - - -/* - * L3/L4 control protocol - */ - -enum { - /* Interface version */ - I2400M_L3L4_VERSION = 0x0100, -}; - -/* Message types */ -enum i2400m_mt { - I2400M_MT_RESERVED = 0x0000, - I2400M_MT_INVALID = 0xffff, - I2400M_MT_REPORT_MASK = 0x8000, - - I2400M_MT_GET_SCAN_RESULT = 0x4202, - I2400M_MT_SET_SCAN_PARAM = 0x4402, - I2400M_MT_CMD_RF_CONTROL = 0x4602, - I2400M_MT_CMD_SCAN = 0x4603, - I2400M_MT_CMD_CONNECT = 0x4604, - I2400M_MT_CMD_DISCONNECT = 0x4605, - I2400M_MT_CMD_EXIT_IDLE = 0x4606, - I2400M_MT_GET_LM_VERSION = 0x5201, - I2400M_MT_GET_DEVICE_INFO = 0x5202, - I2400M_MT_GET_LINK_STATUS = 0x5203, - I2400M_MT_GET_STATISTICS = 0x5204, - I2400M_MT_GET_STATE = 0x5205, - I2400M_MT_GET_MEDIA_STATUS = 0x5206, - I2400M_MT_SET_INIT_CONFIG = 0x5404, - I2400M_MT_CMD_INIT = 0x5601, - I2400M_MT_CMD_TERMINATE = 0x5602, - I2400M_MT_CMD_MODE_OF_OP = 0x5603, - I2400M_MT_CMD_RESET_DEVICE = 0x5604, - I2400M_MT_CMD_MONITOR_CONTROL = 0x5605, - I2400M_MT_CMD_ENTER_POWERSAVE = 0x5606, - I2400M_MT_GET_TLS_OPERATION_RESULT = 0x6201, - I2400M_MT_SET_EAP_SUCCESS = 0x6402, - I2400M_MT_SET_EAP_FAIL = 0x6403, - I2400M_MT_SET_EAP_KEY = 0x6404, - I2400M_MT_CMD_SEND_EAP_RESPONSE = 0x6602, - I2400M_MT_REPORT_SCAN_RESULT = 0xc002, - I2400M_MT_REPORT_STATE = 0xd002, - I2400M_MT_REPORT_POWERSAVE_READY = 0xd005, - I2400M_MT_REPORT_EAP_REQUEST = 0xe002, - I2400M_MT_REPORT_EAP_RESTART = 0xe003, - I2400M_MT_REPORT_ALT_ACCEPT = 0xe004, - I2400M_MT_REPORT_KEY_REQUEST = 0xe005, -}; - - -/* - * Message Ack Status codes - * - * When a message is replied-to, this status is reported. - */ -enum i2400m_ms { - I2400M_MS_DONE_OK = 0, - I2400M_MS_DONE_IN_PROGRESS = 1, - I2400M_MS_INVALID_OP = 2, - I2400M_MS_BAD_STATE = 3, - I2400M_MS_ILLEGAL_VALUE = 4, - I2400M_MS_MISSING_PARAMS = 5, - I2400M_MS_VERSION_ERROR = 6, - I2400M_MS_ACCESSIBILITY_ERROR = 7, - I2400M_MS_BUSY = 8, - I2400M_MS_CORRUPTED_TLV = 9, - I2400M_MS_UNINITIALIZED = 10, - I2400M_MS_UNKNOWN_ERROR = 11, - I2400M_MS_PRODUCTION_ERROR = 12, - I2400M_MS_NO_RF = 13, - I2400M_MS_NOT_READY_FOR_POWERSAVE = 14, - I2400M_MS_THERMAL_CRITICAL = 15, - I2400M_MS_MAX -}; - - -/** - * i2400m_tlv - enumeration of the different types of TLVs - * - * TLVs stand for type-length-value and are the header for a payload - * composed of almost anything. Each payload has a type assigned - * and a length. - */ -enum i2400m_tlv { - I2400M_TLV_L4_MESSAGE_VERSIONS = 129, - I2400M_TLV_SYSTEM_STATE = 141, - I2400M_TLV_MEDIA_STATUS = 161, - I2400M_TLV_RF_OPERATION = 162, - I2400M_TLV_RF_STATUS = 163, - I2400M_TLV_DEVICE_RESET_TYPE = 132, - I2400M_TLV_CONFIG_IDLE_PARAMETERS = 601, - I2400M_TLV_CONFIG_IDLE_TIMEOUT = 611, - I2400M_TLV_CONFIG_D2H_DATA_FORMAT = 614, - I2400M_TLV_CONFIG_DL_HOST_REORDER = 615, -}; - - -struct i2400m_tlv_hdr { - __le16 type; - __le16 length; /* payload's */ - __u8 pl[0]; -} __attribute__((packed)); - - -struct i2400m_l3l4_hdr { - __le16 type; - __le16 length; /* payload's */ - __le16 version; - __le16 resv1; - __le16 status; - __le16 resv2; - struct i2400m_tlv_hdr pl[0]; -} __attribute__((packed)); - - -/** - * i2400m_system_state - different states of the device - */ -enum i2400m_system_state { - I2400M_SS_UNINITIALIZED = 1, - I2400M_SS_INIT, - I2400M_SS_READY, - I2400M_SS_SCAN, - I2400M_SS_STANDBY, - I2400M_SS_CONNECTING, - I2400M_SS_WIMAX_CONNECTED, - I2400M_SS_DATA_PATH_CONNECTED, - I2400M_SS_IDLE, - I2400M_SS_DISCONNECTING, - I2400M_SS_OUT_OF_ZONE, - I2400M_SS_SLEEPACTIVE, - I2400M_SS_PRODUCTION, - I2400M_SS_CONFIG, - I2400M_SS_RF_OFF, - I2400M_SS_RF_SHUTDOWN, - I2400M_SS_DEVICE_DISCONNECT, - I2400M_SS_MAX, -}; - - -/** - * i2400m_tlv_system_state - report on the state of the system - * - * @state: see enum i2400m_system_state - */ -struct i2400m_tlv_system_state { - struct i2400m_tlv_hdr hdr; - __le32 state; -} __attribute__((packed)); - - -struct i2400m_tlv_l4_message_versions { - struct i2400m_tlv_hdr hdr; - __le16 major; - __le16 minor; - __le16 branch; - __le16 reserved; -} __attribute__((packed)); - - -struct i2400m_tlv_detailed_device_info { - struct i2400m_tlv_hdr hdr; - __u8 reserved1[400]; - __u8 mac_address[ETH_ALEN]; - __u8 reserved2[2]; -} __attribute__((packed)); - - -enum i2400m_rf_switch_status { - I2400M_RF_SWITCH_ON = 1, - I2400M_RF_SWITCH_OFF = 2, -}; - -struct i2400m_tlv_rf_switches_status { - struct i2400m_tlv_hdr hdr; - __u8 sw_rf_switch; /* 1 ON, 2 OFF */ - __u8 hw_rf_switch; /* 1 ON, 2 OFF */ - __u8 reserved[2]; -} __attribute__((packed)); - - -enum { - i2400m_rf_operation_on = 1, - i2400m_rf_operation_off = 2 -}; - -struct i2400m_tlv_rf_operation { - struct i2400m_tlv_hdr hdr; - __le32 status; /* 1 ON, 2 OFF */ -} __attribute__((packed)); - - -enum i2400m_tlv_reset_type { - I2400M_RESET_TYPE_COLD = 1, - I2400M_RESET_TYPE_WARM -}; - -struct i2400m_tlv_device_reset_type { - struct i2400m_tlv_hdr hdr; - __le32 reset_type; -} __attribute__((packed)); - - -struct i2400m_tlv_config_idle_parameters { - struct i2400m_tlv_hdr hdr; - __le32 idle_timeout; /* 100 to 300000 ms [5min], 100 increments - * 0 disabled */ - __le32 idle_paging_interval; /* frames */ -} __attribute__((packed)); - - -enum i2400m_media_status { - I2400M_MEDIA_STATUS_LINK_UP = 1, - I2400M_MEDIA_STATUS_LINK_DOWN, - I2400M_MEDIA_STATUS_LINK_RENEW, -}; - -struct i2400m_tlv_media_status { - struct i2400m_tlv_hdr hdr; - __le32 media_status; -} __attribute__((packed)); - - -/* New in v1.4 */ -struct i2400m_tlv_config_idle_timeout { - struct i2400m_tlv_hdr hdr; - __le32 timeout; /* 100 to 300000 ms [5min], 100 increments - * 0 disabled */ -} __attribute__((packed)); - -/* New in v1.4 -- for backward compat, will be removed */ -struct i2400m_tlv_config_d2h_data_format { - struct i2400m_tlv_hdr hdr; - __u8 format; /* 0 old format, 1 enhanced */ - __u8 reserved[3]; -} __attribute__((packed)); - -/* New in v1.4 */ -struct i2400m_tlv_config_dl_host_reorder { - struct i2400m_tlv_hdr hdr; - __u8 reorder; /* 0 disabled, 1 enabled */ - __u8 reserved[3]; -} __attribute__((packed)); - - -#endif /* #ifndef __LINUX__WIMAX__I2400M_H__ */ diff --git a/drivers/staging/wimax/i2400m/netdev.c b/drivers/staging/wimax/i2400m/netdev.c deleted file mode 100644 index cd06eaf75e8bd0532f9d85dddb0cae5b4beabe84..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/netdev.c +++ /dev/null @@ -1,603 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless WiMAX Connection 2400m - * Glue with the networking stack - * - * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This implements an ethernet device for the i2400m. - * - * We fake being an ethernet device to simplify the support from user - * space and from the other side. The world is (sadly) configured to - * take in only Ethernet devices... - * - * Because of this, when using firmwares <= v1.3, there is an - * copy-each-rxed-packet overhead on the RX path. Each IP packet has - * to be reallocated to add an ethernet header (as there is no space - * in what we get from the device). This is a known drawback and - * firmwares >= 1.4 add header space that can be used to insert the - * ethernet header without having to reallocate and copy. - * - * TX error handling is tricky; because we have to FIFO/queue the - * buffers for transmission (as the hardware likes it aggregated), we - * just give the skb to the TX subsystem and by the time it is - * transmitted, we have long forgotten about it. So we just don't care - * too much about it. - * - * Note that when the device is in idle mode with the basestation, we - * need to negotiate coming back up online. That involves negotiation - * and possible user space interaction. Thus, we defer to a workqueue - * to do all that. By default, we only queue a single packet and drop - * the rest, as potentially the time to go back from idle to normal is - * long. - * - * ROADMAP - * - * i2400m_open Called on ifconfig up - * i2400m_stop Called on ifconfig down - * - * i2400m_hard_start_xmit Called by the network stack to send a packet - * i2400m_net_wake_tx Wake up device from basestation-IDLE & TX - * i2400m_wake_tx_work - * i2400m_cmd_exit_idle - * i2400m_tx - * i2400m_net_tx TX a data frame - * i2400m_tx - * - * i2400m_change_mtu Called on ifconfig mtu XXX - * - * i2400m_tx_timeout Called when the device times out - * - * i2400m_net_rx Called by the RX code when a data frame is - * available (firmware <= 1.3) - * i2400m_net_erx Called by the RX code when a data frame is - * available (firmware >= 1.4). - * i2400m_netdev_setup Called to setup all the netdev stuff from - * alloc_netdev. - */ -#include <linux/if_arp.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/ethtool.h> -#include <linux/export.h> -#include "i2400m.h" - - -#define D_SUBMODULE netdev -#include "debug-levels.h" - -enum { -/* netdev interface */ - /* 20 secs? yep, this is the maximum timeout that the device - * might take to get out of IDLE / negotiate it with the base - * station. We add 1sec for good measure. */ - I2400M_TX_TIMEOUT = 21 * HZ, - /* - * Experimentation has determined that, 20 to be a good value - * for minimizing the jitter in the throughput. - */ - I2400M_TX_QLEN = 20, -}; - - -static -int i2400m_open(struct net_device *net_dev) -{ - int result; - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); - /* Make sure we wait until init is complete... */ - mutex_lock(&i2400m->init_mutex); - if (i2400m->updown) - result = 0; - else - result = -EBUSY; - mutex_unlock(&i2400m->init_mutex); - d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", - net_dev, i2400m, result); - return result; -} - - -static -int i2400m_stop(struct net_device *net_dev) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); - i2400m_net_wake_stop(i2400m); - d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m); - return 0; -} - - -/* - * Wake up the device and transmit a held SKB, then restart the net queue - * - * When the device goes into basestation-idle mode, we need to tell it - * to exit that mode; it will negotiate with the base station, user - * space may have to intervene to rehandshake crypto and then tell us - * when it is ready to transmit the packet we have "queued". Still we - * need to give it sometime after it reports being ok. - * - * On error, there is not much we can do. If the error was on TX, we - * still wake the queue up to see if the next packet will be luckier. - * - * If _cmd_exit_idle() fails...well, it could be many things; most - * commonly it is that something else took the device out of IDLE mode - * (for example, the base station). In that case we get an -EILSEQ and - * we are just going to ignore that one. If the device is back to - * connected, then fine -- if it is someother state, the packet will - * be dropped anyway. - */ -void i2400m_wake_tx_work(struct work_struct *ws) -{ - int result; - struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb; - unsigned long flags; - - spin_lock_irqsave(&i2400m->tx_lock, flags); - skb = i2400m->wake_tx_skb; - i2400m->wake_tx_skb = NULL; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - - d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb); - result = -EINVAL; - if (skb == NULL) { - dev_err(dev, "WAKE&TX: skb disappeared!\n"); - goto out_put; - } - /* If we have, somehow, lost the connection after this was - * queued, don't do anything; this might be the device got - * reset or just disconnected. */ - if (unlikely(!netif_carrier_ok(net_dev))) - goto out_kfree; - result = i2400m_cmd_exit_idle(i2400m); - if (result == -EILSEQ) - result = 0; - if (result < 0) { - dev_err(dev, "WAKE&TX: device didn't get out of idle: " - "%d - resetting\n", result); - i2400m_reset(i2400m, I2400M_RT_BUS); - goto error; - } - result = wait_event_timeout(i2400m->state_wq, - i2400m->state != I2400M_SS_IDLE, - net_dev->watchdog_timeo - HZ/2); - if (result == 0) - result = -ETIMEDOUT; - if (result < 0) { - dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: " - "%d - resetting\n", result); - i2400m_reset(i2400m, I2400M_RT_BUS); - goto error; - } - msleep(20); /* device still needs some time or it drops it */ - result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); -error: - netif_wake_queue(net_dev); -out_kfree: - kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */ -out_put: - i2400m_put(i2400m); - d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n", - ws, i2400m, skb, result); -} - - -/* - * Prepare the data payload TX header - * - * The i2400m expects a 4 byte header in front of a data packet. - * - * Because we pretend to be an ethernet device, this packet comes with - * an ethernet header. Pull it and push our header. - */ -static -void i2400m_tx_prep_header(struct sk_buff *skb) -{ - struct i2400m_pl_data_hdr *pl_hdr; - skb_pull(skb, ETH_HLEN); - pl_hdr = skb_push(skb, sizeof(*pl_hdr)); - pl_hdr->reserved = 0; -} - - - -/* - * Cleanup resources acquired during i2400m_net_wake_tx() - * - * This is called by __i2400m_dev_stop and means we have to make sure - * the workqueue is flushed from any pending work. - */ -void i2400m_net_wake_stop(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *wake_tx_skb; - unsigned long flags; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - /* - * See i2400m_hard_start_xmit(), references are taken there and - * here we release them if the packet was still pending. - */ - cancel_work_sync(&i2400m->wake_tx_ws); - - spin_lock_irqsave(&i2400m->tx_lock, flags); - wake_tx_skb = i2400m->wake_tx_skb; - i2400m->wake_tx_skb = NULL; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - - if (wake_tx_skb) { - i2400m_put(i2400m); - kfree_skb(wake_tx_skb); - } - - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} - - -/* - * TX an skb to an idle device - * - * When the device is in basestation-idle mode, we need to wake it up - * and then TX. So we queue a work_struct for doing so. - * - * We need to get an extra ref for the skb (so it is not dropped), as - * well as be careful not to queue more than one request (won't help - * at all). If more than one request comes or there are errors, we - * just drop the packets (see i2400m_hard_start_xmit()). - */ -static -int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev, - struct sk_buff *skb) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - unsigned long flags; - - d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); - if (net_ratelimit()) { - d_printf(3, dev, "WAKE&NETTX: " - "skb %p sending %d bytes to radio\n", - skb, skb->len); - d_dump(4, dev, skb->data, skb->len); - } - /* We hold a ref count for i2400m and skb, so when - * stopping() the device, we need to cancel that work - * and if pending, release those resources. */ - result = 0; - spin_lock_irqsave(&i2400m->tx_lock, flags); - if (!i2400m->wake_tx_skb) { - netif_stop_queue(net_dev); - i2400m_get(i2400m); - i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */ - i2400m_tx_prep_header(skb); - result = schedule_work(&i2400m->wake_tx_ws); - WARN_ON(result == 0); - } - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - if (result == 0) { - /* Yes, this happens even if we stopped the - * queue -- blame the queue disciplines that - * queue without looking -- I guess there is a reason - * for that. */ - if (net_ratelimit()) - d_printf(1, dev, "NETTX: device exiting idle, " - "dropping skb %p, queue running %d\n", - skb, netif_queue_stopped(net_dev)); - result = -EBUSY; - } - d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); - return result; -} - - -/* - * Transmit a packet to the base station on behalf of the network stack. - * - * Returns: 0 if ok, < 0 errno code on error. - * - * We need to pull the ethernet header and add the hardware header, - * which is currently set to all zeroes and reserved. - */ -static -int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev, - struct sk_buff *skb) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n", - i2400m, net_dev, skb); - /* FIXME: check eth hdr, only IPv4 is routed by the device as of now */ - netif_trans_update(net_dev); - i2400m_tx_prep_header(skb); - d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n", - skb, skb->len); - d_dump(4, dev, skb->data, skb->len); - result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); - d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n", - i2400m, net_dev, skb, result); - return result; -} - - -/* - * Transmit a packet to the base station on behalf of the network stack - * - * - * Returns: NETDEV_TX_OK (always, even in case of error) - * - * In case of error, we just drop it. Reasons: - * - * - we add a hw header to each skb, and if the network stack - * retries, we have no way to know if that skb has it or not. - * - * - network protocols have their own drop-recovery mechanisms - * - * - there is not much else we can do - * - * If the device is idle, we need to wake it up; that is an operation - * that will sleep. See i2400m_net_wake_tx() for details. - */ -static -netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, - struct net_device *net_dev) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct device *dev = i2400m_dev(i2400m); - int result = -1; - - d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); - - if (skb_cow_head(skb, 0)) - goto drop; - - if (i2400m->state == I2400M_SS_IDLE) - result = i2400m_net_wake_tx(i2400m, net_dev, skb); - else - result = i2400m_net_tx(i2400m, net_dev, skb); - if (result < 0) { -drop: - net_dev->stats.tx_dropped++; - } else { - net_dev->stats.tx_packets++; - net_dev->stats.tx_bytes += skb->len; - } - dev_kfree_skb(skb); - d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); - return NETDEV_TX_OK; -} - - -static -void i2400m_tx_timeout(struct net_device *net_dev, unsigned int txqueue) -{ - /* - * We might want to kick the device - * - * There is not much we can do though, as the device requires - * that we send the data aggregated. By the time we receive - * this, there might be data pending to be sent or not... - */ - net_dev->stats.tx_errors++; -} - - -/* - * Create a fake ethernet header - * - * For emulating an ethernet device, every received IP header has to - * be prefixed with an ethernet header. Fake it with the given - * protocol. - */ -static -void i2400m_rx_fake_eth_header(struct net_device *net_dev, - void *_eth_hdr, __be16 protocol) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct ethhdr *eth_hdr = _eth_hdr; - - memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); - memcpy(eth_hdr->h_source, i2400m->src_mac_addr, - sizeof(eth_hdr->h_source)); - eth_hdr->h_proto = protocol; -} - - -/* - * i2400m_net_rx - pass a network packet to the stack - * - * @i2400m: device instance - * @skb_rx: the skb where the buffer pointed to by @buf is - * @i: 1 if payload is the only one - * @buf: pointer to the buffer containing the data - * @len: buffer's length - * - * This is only used now for the v1.3 firmware. It will be deprecated - * in >= 2.6.31. - * - * Note that due to firmware limitations, we don't have space to add - * an ethernet header, so we need to copy each packet. Firmware - * versions >= v1.4 fix this [see i2400m_net_erx()]. - * - * We just clone the skb and set it up so that it's skb->data pointer - * points to "buf" and it's length. - * - * Note that if the payload is the last (or the only one) in a - * multi-payload message, we don't clone the SKB but just reuse it. - * - * This function is normally run from a thread context. However, we - * still use netif_rx() instead of netif_receive_skb() as was - * recommended in the mailing list. Reason is in some stress tests - * when sending/receiving a lot of data we seem to hit a softlock in - * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using - * netif_rx() took care of the issue. - * - * This is, of course, still open to do more research on why running - * with netif_receive_skb() hits this softlock. FIXME. - * - * FIXME: currently we don't do any efforts at distinguishing if what - * we got was an IPv4 or IPv6 header, to setup the protocol field - * correctly. - */ -void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx, - unsigned i, const void *buf, int buf_len) -{ - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb; - - d_fnstart(2, dev, "(i2400m %p buf %p buf_len %d)\n", - i2400m, buf, buf_len); - if (i) { - skb = skb_get(skb_rx); - d_printf(2, dev, "RX: reusing first payload skb %p\n", skb); - skb_pull(skb, buf - (void *) skb->data); - skb_trim(skb, (void *) skb_end_pointer(skb) - buf); - } else { - /* Yes, this is bad -- a lot of overhead -- see - * comments at the top of the file */ - skb = __netdev_alloc_skb(net_dev, buf_len, GFP_KERNEL); - if (skb == NULL) { - dev_err(dev, "NETRX: no memory to realloc skb\n"); - net_dev->stats.rx_dropped++; - goto error_skb_realloc; - } - skb_put_data(skb, buf, buf_len); - } - i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev, - skb->data - ETH_HLEN, - cpu_to_be16(ETH_P_IP)); - skb_set_mac_header(skb, -ETH_HLEN); - skb->dev = i2400m->wimax_dev.net_dev; - skb->protocol = htons(ETH_P_IP); - net_dev->stats.rx_packets++; - net_dev->stats.rx_bytes += buf_len; - d_printf(3, dev, "NETRX: receiving %d bytes to network stack\n", - buf_len); - d_dump(4, dev, buf, buf_len); - netif_rx_ni(skb); /* see notes in function header */ -error_skb_realloc: - d_fnend(2, dev, "(i2400m %p buf %p buf_len %d) = void\n", - i2400m, buf, buf_len); -} - - -/* - * i2400m_net_erx - pass a network packet to the stack (extended version) - * - * @i2400m: device descriptor - * @skb: the skb where the packet is - the skb should be set to point - * at the IP packet; this function will add ethernet headers if - * needed. - * @cs: packet type - * - * This is only used now for firmware >= v1.4. Note it is quite - * similar to i2400m_net_rx() (used only for v1.3 firmware). - * - * This function is normally run from a thread context. However, we - * still use netif_rx() instead of netif_receive_skb() as was - * recommended in the mailing list. Reason is in some stress tests - * when sending/receiving a lot of data we seem to hit a softlock in - * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using - * netif_rx() took care of the issue. - * - * This is, of course, still open to do more research on why running - * with netif_receive_skb() hits this softlock. FIXME. - */ -void i2400m_net_erx(struct i2400m *i2400m, struct sk_buff *skb, - enum i2400m_cs cs) -{ - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(2, dev, "(i2400m %p skb %p [%u] cs %d)\n", - i2400m, skb, skb->len, cs); - switch(cs) { - case I2400M_CS_IPV4_0: - case I2400M_CS_IPV4: - i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev, - skb->data - ETH_HLEN, - cpu_to_be16(ETH_P_IP)); - skb_set_mac_header(skb, -ETH_HLEN); - skb->dev = i2400m->wimax_dev.net_dev; - skb->protocol = htons(ETH_P_IP); - net_dev->stats.rx_packets++; - net_dev->stats.rx_bytes += skb->len; - break; - default: - dev_err(dev, "ERX: BUG? CS type %u unsupported\n", cs); - goto error; - - } - d_printf(3, dev, "ERX: receiving %d bytes to the network stack\n", - skb->len); - d_dump(4, dev, skb->data, skb->len); - netif_rx_ni(skb); /* see notes in function header */ -error: - d_fnend(2, dev, "(i2400m %p skb %p [%u] cs %d) = void\n", - i2400m, skb, skb->len, cs); -} - -static const struct net_device_ops i2400m_netdev_ops = { - .ndo_open = i2400m_open, - .ndo_stop = i2400m_stop, - .ndo_start_xmit = i2400m_hard_start_xmit, - .ndo_tx_timeout = i2400m_tx_timeout, -}; - -static void i2400m_get_drvinfo(struct net_device *net_dev, - struct ethtool_drvinfo *info) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - - strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strscpy(info->fw_version, i2400m->fw_name ? : "", - sizeof(info->fw_version)); - if (net_dev->dev.parent) - strscpy(info->bus_info, dev_name(net_dev->dev.parent), - sizeof(info->bus_info)); -} - -static const struct ethtool_ops i2400m_ethtool_ops = { - .get_drvinfo = i2400m_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - -/* - * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data - * - * Called by alloc_netdev() - */ -void i2400m_netdev_setup(struct net_device *net_dev) -{ - d_fnstart(3, NULL, "(net_dev %p)\n", net_dev); - ether_setup(net_dev); - net_dev->mtu = I2400M_MAX_MTU; - net_dev->min_mtu = 0; - net_dev->max_mtu = I2400M_MAX_MTU; - net_dev->tx_queue_len = I2400M_TX_QLEN; - net_dev->features = - NETIF_F_VLAN_CHALLENGED - | NETIF_F_HIGHDMA; - net_dev->flags = - IFF_NOARP /* i2400m is apure IP device */ - & (~IFF_BROADCAST /* i2400m is P2P */ - & ~IFF_MULTICAST); - net_dev->watchdog_timeo = I2400M_TX_TIMEOUT; - net_dev->netdev_ops = &i2400m_netdev_ops; - net_dev->ethtool_ops = &i2400m_ethtool_ops; - d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev); -} -EXPORT_SYMBOL_GPL(i2400m_netdev_setup); - diff --git a/drivers/staging/wimax/i2400m/op-rfkill.c b/drivers/staging/wimax/i2400m/op-rfkill.c deleted file mode 100644 index fbddf2e18c1429712a7b8655102e190455cde2c0..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/op-rfkill.c +++ /dev/null @@ -1,196 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless WiMAX Connection 2400m - * Implement backend for the WiMAX stack rfkill support - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * The WiMAX kernel stack integrates into RF-Kill and keeps the - * switches's status. We just need to: - * - * - report changes in the HW RF Kill switch [with - * wimax_rfkill_{sw,hw}_report(), which happens when we detect those - * indications coming through hardware reports]. We also do it on - * initialization to let the stack know the initial HW state. - * - * - implement indications from the stack to change the SW RF Kill - * switch (coming from sysfs, the wimax stack or user space). - */ -#include "i2400m.h" -#include "linux-wimax-i2400m.h" -#include <linux/slab.h> - - - -#define D_SUBMODULE rfkill -#include "debug-levels.h" - -/* - * Return true if the i2400m radio is in the requested wimax_rf_state state - * - */ -static -int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state) -{ - if (state == WIMAX_RF_OFF) - return i2400m->state == I2400M_SS_RF_OFF - || i2400m->state == I2400M_SS_RF_SHUTDOWN; - else if (state == WIMAX_RF_ON) - /* state == WIMAX_RF_ON */ - return i2400m->state != I2400M_SS_RF_OFF - && i2400m->state != I2400M_SS_RF_SHUTDOWN; - else { - BUG(); - return -EINVAL; /* shut gcc warnings on certain arches */ - } -} - - -/* - * WiMAX stack operation: implement SW RFKill toggling - * - * @wimax_dev: device descriptor - * @skb: skb where the message has been received; skb->data is - * expected to point to the message payload. - * @genl_info: passed by the generic netlink layer - * - * Generic Netlink will call this function when a message is sent from - * userspace to change the software RF-Kill switch status. - * - * This function will set the device's software RF-Kill switch state to - * match what is requested. - * - * NOTE: the i2400m has a strict state machine; we can only set the - * RF-Kill switch when it is on, the HW RF-Kill is on and the - * device is initialized. So we ignore errors steaming from not - * being in the right state (-EILSEQ). - */ -int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ - int result; - struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev); - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *ack_skb; - struct { - struct i2400m_l3l4_hdr hdr; - struct i2400m_tlv_rf_operation sw_rf; - } __packed *cmd; - char strerr[32]; - - d_fnstart(4, dev, "(wimax_dev %p state %d)\n", wimax_dev, state); - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_alloc; - cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_RF_CONTROL); - cmd->hdr.length = sizeof(cmd->sw_rf); - cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION); - cmd->sw_rf.hdr.type = cpu_to_le16(I2400M_TLV_RF_OPERATION); - cmd->sw_rf.hdr.length = cpu_to_le16(sizeof(cmd->sw_rf.status)); - switch (state) { - case WIMAX_RF_OFF: /* RFKILL ON, radio OFF */ - cmd->sw_rf.status = cpu_to_le32(2); - break; - case WIMAX_RF_ON: /* RFKILL OFF, radio ON */ - cmd->sw_rf.status = cpu_to_le32(1); - break; - default: - BUG(); - } - - ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); - result = PTR_ERR(ack_skb); - if (IS_ERR(ack_skb)) { - dev_err(dev, "Failed to issue 'RF Control' command: %d\n", - result); - goto error_msg_to_dev; - } - result = i2400m_msg_check_status(wimax_msg_data(ack_skb), - strerr, sizeof(strerr)); - if (result < 0) { - dev_err(dev, "'RF Control' (0x%04x) command failed: %d - %s\n", - I2400M_MT_CMD_RF_CONTROL, result, strerr); - goto error_cmd; - } - - /* Now we wait for the state to change to RADIO_OFF or RADIO_ON */ - result = wait_event_timeout( - i2400m->state_wq, i2400m_radio_is(i2400m, state), - 5 * HZ); - if (result == 0) - result = -ETIMEDOUT; - if (result < 0) - dev_err(dev, "Error waiting for device to toggle RF state: " - "%d\n", result); - result = 0; -error_cmd: - kfree_skb(ack_skb); -error_msg_to_dev: -error_alloc: - d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n", - wimax_dev, state, result); - kfree(cmd); - return result; -} - - -/* - * Inform the WiMAX stack of changes in the RF Kill switches reported - * by the device - * - * @i2400m: device descriptor - * @rfss: TLV for RF Switches status; already validated - * - * NOTE: the reports on RF switch status cannot be trusted - * or used until the device is in a state of RADIO_OFF - * or greater. - */ -void i2400m_report_tlv_rf_switches_status( - struct i2400m *i2400m, - const struct i2400m_tlv_rf_switches_status *rfss) -{ - struct device *dev = i2400m_dev(i2400m); - enum i2400m_rf_switch_status hw, sw; - enum wimax_st wimax_state; - - sw = le32_to_cpu(rfss->sw_rf_switch); - hw = le32_to_cpu(rfss->hw_rf_switch); - - d_fnstart(3, dev, "(i2400m %p rfss %p [hw %u sw %u])\n", - i2400m, rfss, hw, sw); - /* We only process rw switch evens when the device has been - * fully initialized */ - wimax_state = wimax_state_get(&i2400m->wimax_dev); - if (wimax_state < WIMAX_ST_RADIO_OFF) { - d_printf(3, dev, "ignoring RF switches report, state %u\n", - wimax_state); - goto out; - } - switch (sw) { - case I2400M_RF_SWITCH_ON: /* RF Kill disabled (radio on) */ - wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_ON); - break; - case I2400M_RF_SWITCH_OFF: /* RF Kill enabled (radio off) */ - wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_OFF); - break; - default: - dev_err(dev, "HW BUG? Unknown RF SW state 0x%x\n", sw); - } - - switch (hw) { - case I2400M_RF_SWITCH_ON: /* RF Kill disabled (radio on) */ - wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_ON); - break; - case I2400M_RF_SWITCH_OFF: /* RF Kill enabled (radio off) */ - wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_OFF); - break; - default: - dev_err(dev, "HW BUG? Unknown RF HW state 0x%x\n", hw); - } -out: - d_fnend(3, dev, "(i2400m %p rfss %p [hw %u sw %u]) = void\n", - i2400m, rfss, hw, sw); -} diff --git a/drivers/staging/wimax/i2400m/rx.c b/drivers/staging/wimax/i2400m/rx.c deleted file mode 100644 index 702a1e2fabcd0520a2eee16af03fc6a7bd36e3d1..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/rx.c +++ /dev/null @@ -1,1394 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Handle incoming traffic and deliver it to the control or data planes - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Use skb_clone(), break up processing in chunks - * - Split transport/device specific - * - Make buffer size dynamic to exert less memory pressure - * - RX reorder support - * - * This handles the RX path. - * - * We receive an RX message from the bus-specific driver, which - * contains one or more payloads that have potentially different - * destinataries (data or control paths). - * - * So we just take that payload from the transport specific code in - * the form of an skb, break it up in chunks (a cloned skb each in the - * case of network packets) and pass it to netdev or to the - * command/ack handler (and from there to the WiMAX stack). - * - * PROTOCOL FORMAT - * - * The format of the buffer is: - * - * HEADER (struct i2400m_msg_hdr) - * PAYLOAD DESCRIPTOR 0 (struct i2400m_pld) - * PAYLOAD DESCRIPTOR 1 - * ... - * PAYLOAD DESCRIPTOR N - * PAYLOAD 0 (raw bytes) - * PAYLOAD 1 - * ... - * PAYLOAD N - * - * See tx.c for a deeper description on alignment requirements and - * other fun facts of it. - * - * DATA PACKETS - * - * In firmwares <= v1.3, data packets have no header for RX, but they - * do for TX (currently unused). - * - * In firmware >= 1.4, RX packets have an extended header (16 - * bytes). This header conveys information for management of host - * reordering of packets (the device offloads storage of the packets - * for reordering to the host). Read below for more information. - * - * The header is used as dummy space to emulate an ethernet header and - * thus be able to act as an ethernet device without having to reallocate. - * - * DATA RX REORDERING - * - * Starting in firmware v1.4, the device can deliver packets for - * delivery with special reordering information; this allows it to - * more effectively do packet management when some frames were lost in - * the radio traffic. - * - * Thus, for RX packets that come out of order, the device gives the - * driver enough information to queue them properly and then at some - * point, the signal to deliver the whole (or part) of the queued - * packets to the networking stack. There are 16 such queues. - * - * This only happens when a packet comes in with the "need reorder" - * flag set in the RX header. When such bit is set, the following - * operations might be indicated: - * - * - reset queue: send all queued packets to the OS - * - * - queue: queue a packet - * - * - update ws: update the queue's window start and deliver queued - * packets that meet the criteria - * - * - queue & update ws: queue a packet, update the window start and - * deliver queued packets that meet the criteria - * - * (delivery criteria: the packet's [normalized] sequence number is - * lower than the new [normalized] window start). - * - * See the i2400m_roq_*() functions for details. - * - * ROADMAP - * - * i2400m_rx - * i2400m_rx_msg_hdr_check - * i2400m_rx_pl_descr_check - * i2400m_rx_payload - * i2400m_net_rx - * i2400m_rx_edata - * i2400m_net_erx - * i2400m_roq_reset - * i2400m_net_erx - * i2400m_roq_queue - * __i2400m_roq_queue - * i2400m_roq_update_ws - * __i2400m_roq_update_ws - * i2400m_net_erx - * i2400m_roq_queue_update_ws - * __i2400m_roq_queue - * __i2400m_roq_update_ws - * i2400m_net_erx - * i2400m_rx_ctl - * i2400m_msg_size_check - * i2400m_report_hook_work [in a workqueue] - * i2400m_report_hook - * wimax_msg_to_user - * i2400m_rx_ctl_ack - * wimax_msg_to_user_alloc - * i2400m_rx_trace - * i2400m_msg_size_check - * wimax_msg - */ -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/if_arp.h> -#include <linux/netdevice.h> -#include <linux/workqueue.h> -#include <linux/export.h> -#include <linux/moduleparam.h> -#include "i2400m.h" - - -#define D_SUBMODULE rx -#include "debug-levels.h" - -static int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */ -module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); -MODULE_PARM_DESC(rx_reorder_disabled, - "If true, RX reordering will be disabled."); - -struct i2400m_report_hook_args { - struct sk_buff *skb_rx; - const struct i2400m_l3l4_hdr *l3l4_hdr; - size_t size; - struct list_head list_node; -}; - - -/* - * Execute i2400m_report_hook in a workqueue - * - * Goes over the list of queued reports in i2400m->rx_reports and - * processes them. - * - * NOTE: refcounts on i2400m are not needed because we flush the - * workqueue this runs on (i2400m->work_queue) before destroying - * i2400m. - */ -void i2400m_report_hook_work(struct work_struct *ws) -{ - struct i2400m *i2400m = container_of(ws, struct i2400m, rx_report_ws); - struct device *dev = i2400m_dev(i2400m); - struct i2400m_report_hook_args *args, *args_next; - LIST_HEAD(list); - unsigned long flags; - - while (1) { - spin_lock_irqsave(&i2400m->rx_lock, flags); - list_splice_init(&i2400m->rx_reports, &list); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - if (list_empty(&list)) - break; - else - d_printf(1, dev, "processing queued reports\n"); - list_for_each_entry_safe(args, args_next, &list, list_node) { - d_printf(2, dev, "processing queued report %p\n", args); - i2400m_report_hook(i2400m, args->l3l4_hdr, args->size); - kfree_skb(args->skb_rx); - list_del(&args->list_node); - kfree(args); - } - } -} - - -/* - * Flush the list of queued reports - */ -static -void i2400m_report_hook_flush(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - struct i2400m_report_hook_args *args, *args_next; - LIST_HEAD(list); - unsigned long flags; - - d_printf(1, dev, "flushing queued reports\n"); - spin_lock_irqsave(&i2400m->rx_lock, flags); - list_splice_init(&i2400m->rx_reports, &list); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - list_for_each_entry_safe(args, args_next, &list, list_node) { - d_printf(2, dev, "flushing queued report %p\n", args); - kfree_skb(args->skb_rx); - list_del(&args->list_node); - kfree(args); - } -} - - -/* - * Queue a report for later processing - * - * @i2400m: device descriptor - * @skb_rx: skb that contains the payload (for reference counting) - * @l3l4_hdr: pointer to the control - * @size: size of the message - */ -static -void i2400m_report_hook_queue(struct i2400m *i2400m, struct sk_buff *skb_rx, - const void *l3l4_hdr, size_t size) -{ - struct device *dev = i2400m_dev(i2400m); - unsigned long flags; - struct i2400m_report_hook_args *args; - - args = kzalloc(sizeof(*args), GFP_NOIO); - if (args) { - args->skb_rx = skb_get(skb_rx); - args->l3l4_hdr = l3l4_hdr; - args->size = size; - spin_lock_irqsave(&i2400m->rx_lock, flags); - list_add_tail(&args->list_node, &i2400m->rx_reports); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - d_printf(2, dev, "queued report %p\n", args); - rmb(); /* see i2400m->ready's documentation */ - if (likely(i2400m->ready)) /* only send if up */ - queue_work(i2400m->work_queue, &i2400m->rx_report_ws); - } else { - if (printk_ratelimit()) - dev_err(dev, "%s:%u: Can't allocate %zu B\n", - __func__, __LINE__, sizeof(*args)); - } -} - - -/* - * Process an ack to a command - * - * @i2400m: device descriptor - * @payload: pointer to message - * @size: size of the message - * - * Pass the acknodledgment (in an skb) to the thread that is waiting - * for it in i2400m->msg_completion. - * - * We need to coordinate properly with the thread waiting for the - * ack. Check if it is waiting or if it is gone. We loose the spinlock - * to avoid allocating on atomic contexts (yeah, could use GFP_ATOMIC, - * but this is not so speed critical). - */ -static -void i2400m_rx_ctl_ack(struct i2400m *i2400m, - const void *payload, size_t size) -{ - struct device *dev = i2400m_dev(i2400m); - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - unsigned long flags; - struct sk_buff *ack_skb; - - /* Anyone waiting for an answer? */ - spin_lock_irqsave(&i2400m->rx_lock, flags); - if (i2400m->ack_skb != ERR_PTR(-EINPROGRESS)) { - dev_err(dev, "Huh? reply to command with no waiters\n"); - goto error_no_waiter; - } - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - - ack_skb = wimax_msg_alloc(wimax_dev, NULL, payload, size, GFP_KERNEL); - - /* Check waiter didn't time out waiting for the answer... */ - spin_lock_irqsave(&i2400m->rx_lock, flags); - if (i2400m->ack_skb != ERR_PTR(-EINPROGRESS)) { - d_printf(1, dev, "Huh? waiter for command reply cancelled\n"); - goto error_waiter_cancelled; - } - if (IS_ERR(ack_skb)) - dev_err(dev, "CMD/GET/SET ack: cannot allocate SKB\n"); - i2400m->ack_skb = ack_skb; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - complete(&i2400m->msg_completion); - return; - -error_waiter_cancelled: - if (!IS_ERR(ack_skb)) - kfree_skb(ack_skb); -error_no_waiter: - spin_unlock_irqrestore(&i2400m->rx_lock, flags); -} - - -/* - * Receive and process a control payload - * - * @i2400m: device descriptor - * @skb_rx: skb that contains the payload (for reference counting) - * @payload: pointer to message - * @size: size of the message - * - * There are two types of control RX messages: reports (asynchronous, - * like your every day interrupts) and 'acks' (reponses to a command, - * get or set request). - * - * If it is a report, we run hooks on it (to extract information for - * things we need to do in the driver) and then pass it over to the - * WiMAX stack to send it to user space. - * - * NOTE: report processing is done in a workqueue specific to the - * generic driver, to avoid deadlocks in the system. - * - * If it is not a report, it is an ack to a previously executed - * command, set or get, so wake up whoever is waiting for it from - * i2400m_msg_to_dev(). i2400m_rx_ctl_ack() takes care of that. - * - * Note that the sizes we pass to other functions from here are the - * sizes of the _l3l4_hdr + payload, not full buffer sizes, as we have - * verified in _msg_size_check() that they are congruent. - * - * For reports: We can't clone the original skb where the data is - * because we need to send this up via netlink; netlink has to add - * headers and we can't overwrite what's preceding the payload...as - * it is another message. So we just dup them. - */ -static -void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, - const void *payload, size_t size) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_l3l4_hdr *l3l4_hdr = payload; - unsigned msg_type; - - result = i2400m_msg_size_check(i2400m, l3l4_hdr, size); - if (result < 0) { - dev_err(dev, "HW BUG? device sent a bad message: %d\n", - result); - goto error_check; - } - msg_type = le16_to_cpu(l3l4_hdr->type); - d_printf(1, dev, "%s 0x%04x: %zu bytes\n", - msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET", - msg_type, size); - d_dump(2, dev, l3l4_hdr, size); - if (msg_type & I2400M_MT_REPORT_MASK) { - /* - * Process each report - * - * - has to be ran serialized as well - * - * - the handling might force the execution of - * commands. That might cause reentrancy issues with - * bus-specific subdrivers and workqueues, so the we - * run it in a separate workqueue. - * - * - when the driver is not yet ready to handle them, - * they are queued and at some point the queue is - * restarted [NOTE: we can't queue SKBs directly, as - * this might be a piece of a SKB, not the whole - * thing, and this is cheaper than cloning the - * SKB]. - * - * Note we don't do refcounting for the device - * structure; this is because before destroying - * 'i2400m', we make sure to flush the - * i2400m->work_queue, so there are no issues. - */ - i2400m_report_hook_queue(i2400m, skb_rx, l3l4_hdr, size); - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "echo", - l3l4_hdr, size, GFP_KERNEL); - result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, - GFP_KERNEL); - if (result < 0) - dev_err(dev, "error sending report to userspace: %d\n", - result); - } else /* an ack to a CMD, GET or SET */ - i2400m_rx_ctl_ack(i2400m, payload, size); -error_check: - return; -} - - -/* - * Receive and send up a trace - * - * @i2400m: device descriptor - * @skb_rx: skb that contains the trace (for reference counting) - * @payload: pointer to trace message inside the skb - * @size: size of the message - * - * THe i2400m might produce trace information (diagnostics) and we - * send them through a different kernel-to-user pipe (to avoid - * clogging it). - * - * As in i2400m_rx_ctl(), we can't clone the original skb where the - * data is because we need to send this up via netlink; netlink has to - * add headers and we can't overwrite what's preceding the - * payload...as it is another message. So we just dup them. - */ -static -void i2400m_rx_trace(struct i2400m *i2400m, - const void *payload, size_t size) -{ - int result; - struct device *dev = i2400m_dev(i2400m); - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - const struct i2400m_l3l4_hdr *l3l4_hdr = payload; - unsigned msg_type; - - result = i2400m_msg_size_check(i2400m, l3l4_hdr, size); - if (result < 0) { - dev_err(dev, "HW BUG? device sent a bad trace message: %d\n", - result); - goto error_check; - } - msg_type = le16_to_cpu(l3l4_hdr->type); - d_printf(1, dev, "Trace %s 0x%04x: %zu bytes\n", - msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET", - msg_type, size); - d_dump(2, dev, l3l4_hdr, size); - result = wimax_msg(wimax_dev, "trace", l3l4_hdr, size, GFP_KERNEL); - if (result < 0) - dev_err(dev, "error sending trace to userspace: %d\n", - result); -error_check: - return; -} - - -/* - * Reorder queue data stored on skb->cb while the skb is queued in the - * reorder queues. - */ -struct i2400m_roq_data { - unsigned sn; /* Serial number for the skb */ - enum i2400m_cs cs; /* packet type for the skb */ -}; - - -/* - * ReOrder Queue - * - * @ws: Window Start; sequence number where the current window start - * is for this queue - * @queue: the skb queue itself - * @log: circular ring buffer used to log information about the - * reorder process in this queue that can be displayed in case of - * error to help diagnose it. - * - * This is the head for a list of skbs. In the skb->cb member of the - * skb when queued here contains a 'struct i2400m_roq_data' were we - * store the sequence number (sn) and the cs (packet type) coming from - * the RX payload header from the device. - */ -struct i2400m_roq { - unsigned ws; - struct sk_buff_head queue; - struct i2400m_roq_log *log; -}; - - -static -void __i2400m_roq_init(struct i2400m_roq *roq) -{ - roq->ws = 0; - skb_queue_head_init(&roq->queue); -} - - -static -unsigned __i2400m_roq_index(struct i2400m *i2400m, struct i2400m_roq *roq) -{ - return ((unsigned long) roq - (unsigned long) i2400m->rx_roq) - / sizeof(*roq); -} - - -/* - * Normalize a sequence number based on the queue's window start - * - * nsn = (sn - ws) % 2048 - * - * Note that if @sn < @roq->ws, we still need a positive number; %'s - * sign is implementation specific, so we normalize it by adding 2048 - * to bring it to be positive. - */ -static -unsigned __i2400m_roq_nsn(struct i2400m_roq *roq, unsigned sn) -{ - int r; - r = ((int) sn - (int) roq->ws) % 2048; - if (r < 0) - r += 2048; - return r; -} - - -/* - * Circular buffer to keep the last N reorder operations - * - * In case something fails, dumb then to try to come up with what - * happened. - */ -enum { - I2400M_ROQ_LOG_LENGTH = 32, -}; - -struct i2400m_roq_log { - struct i2400m_roq_log_entry { - enum i2400m_ro_type type; - unsigned ws, count, sn, nsn, new_ws; - } entry[I2400M_ROQ_LOG_LENGTH]; - unsigned in, out; -}; - - -/* Print a log entry */ -static -void i2400m_roq_log_entry_print(struct i2400m *i2400m, unsigned index, - unsigned e_index, - struct i2400m_roq_log_entry *e) -{ - struct device *dev = i2400m_dev(i2400m); - - switch(e->type) { - case I2400M_RO_TYPE_RESET: - dev_err(dev, "q#%d reset ws %u cnt %u sn %u/%u" - " - new nws %u\n", - index, e->ws, e->count, e->sn, e->nsn, e->new_ws); - break; - case I2400M_RO_TYPE_PACKET: - dev_err(dev, "q#%d queue ws %u cnt %u sn %u/%u\n", - index, e->ws, e->count, e->sn, e->nsn); - break; - case I2400M_RO_TYPE_WS: - dev_err(dev, "q#%d update_ws ws %u cnt %u sn %u/%u" - " - new nws %u\n", - index, e->ws, e->count, e->sn, e->nsn, e->new_ws); - break; - case I2400M_RO_TYPE_PACKET_WS: - dev_err(dev, "q#%d queue_update_ws ws %u cnt %u sn %u/%u" - " - new nws %u\n", - index, e->ws, e->count, e->sn, e->nsn, e->new_ws); - break; - default: - dev_err(dev, "q#%d BUG? entry %u - unknown type %u\n", - index, e_index, e->type); - break; - } -} - - -static -void i2400m_roq_log_add(struct i2400m *i2400m, - struct i2400m_roq *roq, enum i2400m_ro_type type, - unsigned ws, unsigned count, unsigned sn, - unsigned nsn, unsigned new_ws) -{ - struct i2400m_roq_log_entry *e; - unsigned cnt_idx; - int index = __i2400m_roq_index(i2400m, roq); - - /* if we run out of space, we eat from the end */ - if (roq->log->in - roq->log->out == I2400M_ROQ_LOG_LENGTH) - roq->log->out++; - cnt_idx = roq->log->in++ % I2400M_ROQ_LOG_LENGTH; - e = &roq->log->entry[cnt_idx]; - - e->type = type; - e->ws = ws; - e->count = count; - e->sn = sn; - e->nsn = nsn; - e->new_ws = new_ws; - - if (d_test(1)) - i2400m_roq_log_entry_print(i2400m, index, cnt_idx, e); -} - - -/* Dump all the entries in the FIFO and reinitialize it */ -static -void i2400m_roq_log_dump(struct i2400m *i2400m, struct i2400m_roq *roq) -{ - unsigned cnt, cnt_idx; - struct i2400m_roq_log_entry *e; - int index = __i2400m_roq_index(i2400m, roq); - - BUG_ON(roq->log->out > roq->log->in); - for (cnt = roq->log->out; cnt < roq->log->in; cnt++) { - cnt_idx = cnt % I2400M_ROQ_LOG_LENGTH; - e = &roq->log->entry[cnt_idx]; - i2400m_roq_log_entry_print(i2400m, index, cnt_idx, e); - memset(e, 0, sizeof(*e)); - } - roq->log->in = roq->log->out = 0; -} - - -/* - * Backbone for the queuing of an skb (by normalized sequence number) - * - * @i2400m: device descriptor - * @roq: reorder queue where to add - * @skb: the skb to add - * @sn: the sequence number of the skb - * @nsn: the normalized sequence number of the skb (pre-computed by the - * caller from the @sn and @roq->ws). - * - * We try first a couple of quick cases: - * - * - the queue is empty - * - the skb would be appended to the queue - * - * These will be the most common operations. - * - * If these fail, then we have to do a sorted insertion in the queue, - * which is the slowest path. - * - * We don't have to acquire a reference count as we are going to own it. - */ -static -void __i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq, - struct sk_buff *skb, unsigned sn, unsigned nsn) -{ - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb_itr; - struct i2400m_roq_data *roq_data_itr, *roq_data; - unsigned nsn_itr; - - d_fnstart(4, dev, "(i2400m %p roq %p skb %p sn %u nsn %u)\n", - i2400m, roq, skb, sn, nsn); - - roq_data = (struct i2400m_roq_data *) &skb->cb; - BUILD_BUG_ON(sizeof(*roq_data) > sizeof(skb->cb)); - roq_data->sn = sn; - d_printf(3, dev, "ERX: roq %p [ws %u] nsn %d sn %u\n", - roq, roq->ws, nsn, roq_data->sn); - - /* Queues will be empty on not-so-bad environments, so try - * that first */ - if (skb_queue_empty(&roq->queue)) { - d_printf(2, dev, "ERX: roq %p - first one\n", roq); - __skb_queue_head(&roq->queue, skb); - goto out; - } - /* Now try append, as most of the operations will be that */ - skb_itr = skb_peek_tail(&roq->queue); - roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb; - nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn); - /* NSN bounds assumed correct (checked when it was queued) */ - if (nsn >= nsn_itr) { - d_printf(2, dev, "ERX: roq %p - appended after %p (nsn %d sn %u)\n", - roq, skb_itr, nsn_itr, roq_data_itr->sn); - __skb_queue_tail(&roq->queue, skb); - goto out; - } - /* None of the fast paths option worked. Iterate to find the - * right spot where to insert the packet; we know the queue is - * not empty, so we are not the first ones; we also know we - * are not going to be the last ones. The list is sorted, so - * we have to insert before the the first guy with an nsn_itr - * greater that our nsn. */ - skb_queue_walk(&roq->queue, skb_itr) { - roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb; - nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn); - /* NSN bounds assumed correct (checked when it was queued) */ - if (nsn_itr > nsn) { - d_printf(2, dev, "ERX: roq %p - queued before %p " - "(nsn %d sn %u)\n", roq, skb_itr, nsn_itr, - roq_data_itr->sn); - __skb_queue_before(&roq->queue, skb_itr, skb); - goto out; - } - } - /* If we get here, that is VERY bad -- print info to help - * diagnose and crash it */ - dev_err(dev, "SW BUG? failed to insert packet\n"); - dev_err(dev, "ERX: roq %p [ws %u] skb %p nsn %d sn %u\n", - roq, roq->ws, skb, nsn, roq_data->sn); - skb_queue_walk(&roq->queue, skb_itr) { - roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb; - nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn); - /* NSN bounds assumed correct (checked when it was queued) */ - dev_err(dev, "ERX: roq %p skb_itr %p nsn %d sn %u\n", - roq, skb_itr, nsn_itr, roq_data_itr->sn); - } - BUG(); -out: - d_fnend(4, dev, "(i2400m %p roq %p skb %p sn %u nsn %d) = void\n", - i2400m, roq, skb, sn, nsn); -} - - -/* - * Backbone for the update window start operation - * - * @i2400m: device descriptor - * @roq: Reorder queue - * @sn: New sequence number - * - * Updates the window start of a queue; when doing so, it must deliver - * to the networking stack all the queued skb's whose normalized - * sequence number is lower than the new normalized window start. - */ -static -unsigned __i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq, - unsigned sn) -{ - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb_itr, *tmp_itr; - struct i2400m_roq_data *roq_data_itr; - unsigned new_nws, nsn_itr; - - new_nws = __i2400m_roq_nsn(roq, sn); - /* - * For type 2(update_window_start) rx messages, there is no - * need to check if the normalized sequence number is greater 1023. - * Simply insert and deliver all packets to the host up to the - * window start. - */ - skb_queue_walk_safe(&roq->queue, skb_itr, tmp_itr) { - roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb; - nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn); - /* NSN bounds assumed correct (checked when it was queued) */ - if (nsn_itr < new_nws) { - d_printf(2, dev, "ERX: roq %p - release skb %p " - "(nsn %u/%u new nws %u)\n", - roq, skb_itr, nsn_itr, roq_data_itr->sn, - new_nws); - __skb_unlink(skb_itr, &roq->queue); - i2400m_net_erx(i2400m, skb_itr, roq_data_itr->cs); - } - else - break; /* rest of packets all nsn_itr > nws */ - } - roq->ws = sn; - return new_nws; -} - - -/* - * Reset a queue - * - * @i2400m: device descriptor - * @cin: Queue Index - * - * Deliver all the packets and reset the window-start to zero. Name is - * kind of misleading. - */ -static -void i2400m_roq_reset(struct i2400m *i2400m, struct i2400m_roq *roq) -{ - struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb_itr, *tmp_itr; - struct i2400m_roq_data *roq_data_itr; - - d_fnstart(2, dev, "(i2400m %p roq %p)\n", i2400m, roq); - i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_RESET, - roq->ws, skb_queue_len(&roq->queue), - ~0, ~0, 0); - skb_queue_walk_safe(&roq->queue, skb_itr, tmp_itr) { - roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb; - d_printf(2, dev, "ERX: roq %p - release skb %p (sn %u)\n", - roq, skb_itr, roq_data_itr->sn); - __skb_unlink(skb_itr, &roq->queue); - i2400m_net_erx(i2400m, skb_itr, roq_data_itr->cs); - } - roq->ws = 0; - d_fnend(2, dev, "(i2400m %p roq %p) = void\n", i2400m, roq); -} - - -/* - * Queue a packet - * - * @i2400m: device descriptor - * @cin: Queue Index - * @skb: containing the packet data - * @fbn: First block number of the packet in @skb - * @lbn: Last block number of the packet in @skb - * - * The hardware is asking the driver to queue a packet for later - * delivery to the networking stack. - */ -static -void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq, - struct sk_buff *skb, unsigned lbn) -{ - struct device *dev = i2400m_dev(i2400m); - unsigned nsn, len; - - d_fnstart(2, dev, "(i2400m %p roq %p skb %p lbn %u) = void\n", - i2400m, roq, skb, lbn); - len = skb_queue_len(&roq->queue); - nsn = __i2400m_roq_nsn(roq, lbn); - if (unlikely(nsn >= 1024)) { - dev_err(dev, "SW BUG? queue nsn %d (lbn %u ws %u)\n", - nsn, lbn, roq->ws); - i2400m_roq_log_dump(i2400m, roq); - i2400m_reset(i2400m, I2400M_RT_WARM); - } else { - __i2400m_roq_queue(i2400m, roq, skb, lbn, nsn); - i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET, - roq->ws, len, lbn, nsn, ~0); - } - d_fnend(2, dev, "(i2400m %p roq %p skb %p lbn %u) = void\n", - i2400m, roq, skb, lbn); -} - - -/* - * Update the window start in a reorder queue and deliver all skbs - * with a lower window start - * - * @i2400m: device descriptor - * @roq: Reorder queue - * @sn: New sequence number - */ -static -void i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq, - unsigned sn) -{ - struct device *dev = i2400m_dev(i2400m); - unsigned old_ws, nsn, len; - - d_fnstart(2, dev, "(i2400m %p roq %p sn %u)\n", i2400m, roq, sn); - old_ws = roq->ws; - len = skb_queue_len(&roq->queue); - nsn = __i2400m_roq_update_ws(i2400m, roq, sn); - i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_WS, - old_ws, len, sn, nsn, roq->ws); - d_fnstart(2, dev, "(i2400m %p roq %p sn %u) = void\n", i2400m, roq, sn); -} - - -/* - * Queue a packet and update the window start - * - * @i2400m: device descriptor - * @cin: Queue Index - * @skb: containing the packet data - * @fbn: First block number of the packet in @skb - * @sn: Last block number of the packet in @skb - * - * Note that unlike i2400m_roq_update_ws(), which sets the new window - * start to @sn, in here we'll set it to @sn + 1. - */ -static -void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq, - struct sk_buff *skb, unsigned sn) -{ - struct device *dev = i2400m_dev(i2400m); - unsigned nsn, old_ws, len; - - d_fnstart(2, dev, "(i2400m %p roq %p skb %p sn %u)\n", - i2400m, roq, skb, sn); - len = skb_queue_len(&roq->queue); - nsn = __i2400m_roq_nsn(roq, sn); - /* - * For type 3(queue_update_window_start) rx messages, there is no - * need to check if the normalized sequence number is greater 1023. - * Simply insert and deliver all packets to the host up to the - * window start. - */ - old_ws = roq->ws; - /* If the queue is empty, don't bother as we'd queue - * it and immediately unqueue it -- just deliver it. - */ - if (len == 0) { - struct i2400m_roq_data *roq_data; - roq_data = (struct i2400m_roq_data *) &skb->cb; - i2400m_net_erx(i2400m, skb, roq_data->cs); - } else - __i2400m_roq_queue(i2400m, roq, skb, sn, nsn); - - __i2400m_roq_update_ws(i2400m, roq, sn + 1); - i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET_WS, - old_ws, len, sn, nsn, roq->ws); - - d_fnend(2, dev, "(i2400m %p roq %p skb %p sn %u) = void\n", - i2400m, roq, skb, sn); -} - - -/* - * This routine destroys the memory allocated for rx_roq, when no - * other thread is accessing it. Access to rx_roq is refcounted by - * rx_roq_refcount, hence memory allocated must be destroyed when - * rx_roq_refcount becomes zero. This routine gets executed when - * rx_roq_refcount becomes zero. - */ -static void i2400m_rx_roq_destroy(struct kref *ref) -{ - unsigned itr; - struct i2400m *i2400m - = container_of(ref, struct i2400m, rx_roq_refcount); - for (itr = 0; itr < I2400M_RO_CIN + 1; itr++) - __skb_queue_purge(&i2400m->rx_roq[itr].queue); - kfree(i2400m->rx_roq[0].log); - kfree(i2400m->rx_roq); - i2400m->rx_roq = NULL; -} - -/* - * Receive and send up an extended data packet - * - * @i2400m: device descriptor - * @skb_rx: skb that contains the extended data packet - * @single_last: 1 if the payload is the only one or the last one of - * the skb. - * @payload: pointer to the packet's data inside the skb - * @size: size of the payload - * - * Starting in v1.4 of the i2400m's firmware, the device can send data - * packets to the host in an extended format that; this incudes a 16 - * byte header (struct i2400m_pl_edata_hdr). Using this header's space - * we can fake ethernet headers for ethernet device emulation without - * having to copy packets around. - * - * This function handles said path. - * - * - * Receive and send up an extended data packet that requires no reordering - * - * @i2400m: device descriptor - * @skb_rx: skb that contains the extended data packet - * @single_last: 1 if the payload is the only one or the last one of - * the skb. - * @payload: pointer to the packet's data (past the actual extended - * data payload header). - * @size: size of the payload - * - * Pass over to the networking stack a data packet that might have - * reordering requirements. - * - * This needs to the decide if the skb in which the packet is - * contained can be reused or if it needs to be cloned. Then it has to - * be trimmed in the edges so that the beginning is the space for eth - * header and then pass it to i2400m_net_erx() for the stack - * - * Assumes the caller has verified the sanity of the payload (size, - * etc) already. - */ -static -void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx, - unsigned single_last, const void *payload, size_t size) -{ - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_pl_edata_hdr *hdr = payload; - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - struct sk_buff *skb; - enum i2400m_cs cs; - u32 reorder; - unsigned ro_needed, ro_type, ro_cin, ro_sn; - struct i2400m_roq *roq; - struct i2400m_roq_data *roq_data; - unsigned long flags; - - BUILD_BUG_ON(ETH_HLEN > sizeof(*hdr)); - - d_fnstart(2, dev, "(i2400m %p skb_rx %p single %u payload %p " - "size %zu)\n", i2400m, skb_rx, single_last, payload, size); - if (size < sizeof(*hdr)) { - dev_err(dev, "ERX: HW BUG? message with short header (%zu " - "vs %zu bytes expected)\n", size, sizeof(*hdr)); - goto error; - } - - if (single_last) { - skb = skb_get(skb_rx); - d_printf(3, dev, "ERX: skb %p reusing\n", skb); - } else { - skb = skb_clone(skb_rx, GFP_KERNEL); - if (skb == NULL) { - dev_err(dev, "ERX: no memory to clone skb\n"); - net_dev->stats.rx_dropped++; - goto error_skb_clone; - } - d_printf(3, dev, "ERX: skb %p cloned from %p\n", skb, skb_rx); - } - /* now we have to pull and trim so that the skb points to the - * beginning of the IP packet; the netdev part will add the - * ethernet header as needed - we know there is enough space - * because we checked in i2400m_rx_edata(). */ - skb_pull(skb, payload + sizeof(*hdr) - (void *) skb->data); - skb_trim(skb, (void *) skb_end_pointer(skb) - payload - sizeof(*hdr)); - - reorder = le32_to_cpu(hdr->reorder); - ro_needed = reorder & I2400M_RO_NEEDED; - cs = hdr->cs; - if (ro_needed) { - ro_type = (reorder >> I2400M_RO_TYPE_SHIFT) & I2400M_RO_TYPE; - ro_cin = (reorder >> I2400M_RO_CIN_SHIFT) & I2400M_RO_CIN; - ro_sn = (reorder >> I2400M_RO_SN_SHIFT) & I2400M_RO_SN; - - spin_lock_irqsave(&i2400m->rx_lock, flags); - if (i2400m->rx_roq == NULL) { - kfree_skb(skb); /* rx_roq is already destroyed */ - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - goto error; - } - roq = &i2400m->rx_roq[ro_cin]; - kref_get(&i2400m->rx_roq_refcount); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - - roq_data = (struct i2400m_roq_data *) &skb->cb; - roq_data->sn = ro_sn; - roq_data->cs = cs; - d_printf(2, dev, "ERX: reorder needed: " - "type %u cin %u [ws %u] sn %u/%u len %zuB\n", - ro_type, ro_cin, roq->ws, ro_sn, - __i2400m_roq_nsn(roq, ro_sn), size); - d_dump(2, dev, payload, size); - switch(ro_type) { - case I2400M_RO_TYPE_RESET: - i2400m_roq_reset(i2400m, roq); - kfree_skb(skb); /* no data here */ - break; - case I2400M_RO_TYPE_PACKET: - i2400m_roq_queue(i2400m, roq, skb, ro_sn); - break; - case I2400M_RO_TYPE_WS: - i2400m_roq_update_ws(i2400m, roq, ro_sn); - kfree_skb(skb); /* no data here */ - break; - case I2400M_RO_TYPE_PACKET_WS: - i2400m_roq_queue_update_ws(i2400m, roq, skb, ro_sn); - break; - default: - dev_err(dev, "HW BUG? unknown reorder type %u\n", ro_type); - } - - spin_lock_irqsave(&i2400m->rx_lock, flags); - kref_put(&i2400m->rx_roq_refcount, i2400m_rx_roq_destroy); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - } - else - i2400m_net_erx(i2400m, skb, cs); -error_skb_clone: -error: - d_fnend(2, dev, "(i2400m %p skb_rx %p single %u payload %p " - "size %zu) = void\n", i2400m, skb_rx, single_last, payload, size); -} - - -/* - * Act on a received payload - * - * @i2400m: device instance - * @skb_rx: skb where the transaction was received - * @single_last: 1 this is the only payload or the last one (so the - * skb can be reused instead of cloned). - * @pld: payload descriptor - * @payload: payload data - * - * Upon reception of a payload, look at its guts in the payload - * descriptor and decide what to do with it. If it is a single payload - * skb or if the last skb is a data packet, the skb will be referenced - * and modified (so it doesn't have to be cloned). - */ -static -void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx, - unsigned single_last, const struct i2400m_pld *pld, - const void *payload) -{ - struct device *dev = i2400m_dev(i2400m); - size_t pl_size = i2400m_pld_size(pld); - enum i2400m_pt pl_type = i2400m_pld_type(pld); - - d_printf(7, dev, "RX: received payload type %u, %zu bytes\n", - pl_type, pl_size); - d_dump(8, dev, payload, pl_size); - - switch (pl_type) { - case I2400M_PT_DATA: - d_printf(3, dev, "RX: data payload %zu bytes\n", pl_size); - i2400m_net_rx(i2400m, skb_rx, single_last, payload, pl_size); - break; - case I2400M_PT_CTRL: - i2400m_rx_ctl(i2400m, skb_rx, payload, pl_size); - break; - case I2400M_PT_TRACE: - i2400m_rx_trace(i2400m, payload, pl_size); - break; - case I2400M_PT_EDATA: - d_printf(3, dev, "ERX: data payload %zu bytes\n", pl_size); - i2400m_rx_edata(i2400m, skb_rx, single_last, payload, pl_size); - break; - default: /* Anything else shouldn't come to the host */ - if (printk_ratelimit()) - dev_err(dev, "RX: HW BUG? unexpected payload type %u\n", - pl_type); - } -} - - -/* - * Check a received transaction's message header - * - * @i2400m: device descriptor - * @msg_hdr: message header - * @buf_size: size of the received buffer - * - * Check that the declarations done by a RX buffer message header are - * sane and consistent with the amount of data that was received. - */ -static -int i2400m_rx_msg_hdr_check(struct i2400m *i2400m, - const struct i2400m_msg_hdr *msg_hdr, - size_t buf_size) -{ - int result = -EIO; - struct device *dev = i2400m_dev(i2400m); - if (buf_size < sizeof(*msg_hdr)) { - dev_err(dev, "RX: HW BUG? message with short header (%zu " - "vs %zu bytes expected)\n", buf_size, sizeof(*msg_hdr)); - goto error; - } - if (msg_hdr->barker != cpu_to_le32(I2400M_D2H_MSG_BARKER)) { - dev_err(dev, "RX: HW BUG? message received with unknown " - "barker 0x%08x (buf_size %zu bytes)\n", - le32_to_cpu(msg_hdr->barker), buf_size); - goto error; - } - if (msg_hdr->num_pls == 0) { - dev_err(dev, "RX: HW BUG? zero payload packets in message\n"); - goto error; - } - if (le16_to_cpu(msg_hdr->num_pls) > I2400M_MAX_PLS_IN_MSG) { - dev_err(dev, "RX: HW BUG? message contains more payload " - "than maximum; ignoring.\n"); - goto error; - } - result = 0; -error: - return result; -} - - -/* - * Check a payload descriptor against the received data - * - * @i2400m: device descriptor - * @pld: payload descriptor - * @pl_itr: offset (in bytes) in the received buffer the payload is - * located - * @buf_size: size of the received buffer - * - * Given a payload descriptor (part of a RX buffer), check it is sane - * and that the data it declares fits in the buffer. - */ -static -int i2400m_rx_pl_descr_check(struct i2400m *i2400m, - const struct i2400m_pld *pld, - size_t pl_itr, size_t buf_size) -{ - int result = -EIO; - struct device *dev = i2400m_dev(i2400m); - size_t pl_size = i2400m_pld_size(pld); - enum i2400m_pt pl_type = i2400m_pld_type(pld); - - if (pl_size > i2400m->bus_pl_size_max) { - dev_err(dev, "RX: HW BUG? payload @%zu: size %zu is " - "bigger than maximum %zu; ignoring message\n", - pl_itr, pl_size, i2400m->bus_pl_size_max); - goto error; - } - if (pl_itr + pl_size > buf_size) { /* enough? */ - dev_err(dev, "RX: HW BUG? payload @%zu: size %zu " - "goes beyond the received buffer " - "size (%zu bytes); ignoring message\n", - pl_itr, pl_size, buf_size); - goto error; - } - if (pl_type >= I2400M_PT_ILLEGAL) { - dev_err(dev, "RX: HW BUG? illegal payload type %u; " - "ignoring message\n", pl_type); - goto error; - } - result = 0; -error: - return result; -} - - -/** - * i2400m_rx - Receive a buffer of data from the device - * - * @i2400m: device descriptor - * @skb: skbuff where the data has been received - * - * Parse in a buffer of data that contains an RX message sent from the - * device. See the file header for the format. Run all checks on the - * buffer header, then run over each payload's descriptors, verify - * their consistency and act on each payload's contents. If - * everything is successful, update the device's statistics. - * - * Note: You need to set the skb to contain only the length of the - * received buffer; for that, use skb_trim(skb, RECEIVED_SIZE). - * - * Returns: - * - * 0 if ok, < 0 errno on error - * - * If ok, this function owns now the skb and the caller DOESN'T have - * to run kfree_skb() on it. However, on error, the caller still owns - * the skb and it is responsible for releasing it. - */ -int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) -{ - int i, result; - struct device *dev = i2400m_dev(i2400m); - const struct i2400m_msg_hdr *msg_hdr; - size_t pl_itr, pl_size; - unsigned long flags; - unsigned num_pls, single_last, skb_len; - - skb_len = skb->len; - d_fnstart(4, dev, "(i2400m %p skb %p [size %u])\n", - i2400m, skb, skb_len); - msg_hdr = (void *) skb->data; - result = i2400m_rx_msg_hdr_check(i2400m, msg_hdr, skb_len); - if (result < 0) - goto error_msg_hdr_check; - result = -EIO; - num_pls = le16_to_cpu(msg_hdr->num_pls); - /* Check payload descriptor(s) */ - pl_itr = struct_size(msg_hdr, pld, num_pls); - pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN); - if (pl_itr > skb_len) { /* got all the payload descriptors? */ - dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " - "%u payload descriptors (%zu each, total %zu)\n", - skb_len, num_pls, sizeof(msg_hdr->pld[0]), pl_itr); - goto error_pl_descr_short; - } - /* Walk each payload payload--check we really got it */ - for (i = 0; i < num_pls; i++) { - /* work around old gcc warnings */ - pl_size = i2400m_pld_size(&msg_hdr->pld[i]); - result = i2400m_rx_pl_descr_check(i2400m, &msg_hdr->pld[i], - pl_itr, skb_len); - if (result < 0) - goto error_pl_descr_check; - single_last = num_pls == 1 || i == num_pls - 1; - i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i], - skb->data + pl_itr); - pl_itr += ALIGN(pl_size, I2400M_PL_ALIGN); - cond_resched(); /* Don't monopolize */ - } - kfree_skb(skb); - /* Update device statistics */ - spin_lock_irqsave(&i2400m->rx_lock, flags); - i2400m->rx_pl_num += i; - if (i > i2400m->rx_pl_max) - i2400m->rx_pl_max = i; - if (i < i2400m->rx_pl_min) - i2400m->rx_pl_min = i; - i2400m->rx_num++; - i2400m->rx_size_acc += skb_len; - if (skb_len < i2400m->rx_size_min) - i2400m->rx_size_min = skb_len; - if (skb_len > i2400m->rx_size_max) - i2400m->rx_size_max = skb_len; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); -error_pl_descr_check: -error_pl_descr_short: -error_msg_hdr_check: - d_fnend(4, dev, "(i2400m %p skb %p [size %u]) = %d\n", - i2400m, skb, skb_len, result); - return result; -} -EXPORT_SYMBOL_GPL(i2400m_rx); - - -void i2400m_unknown_barker(struct i2400m *i2400m, - const void *buf, size_t size) -{ - struct device *dev = i2400m_dev(i2400m); - char prefix[64]; - const __le32 *barker = buf; - dev_err(dev, "RX: HW BUG? unknown barker %08x, " - "dropping %zu bytes\n", le32_to_cpu(*barker), size); - snprintf(prefix, sizeof(prefix), "%s %s: ", - dev_driver_string(dev), dev_name(dev)); - if (size > 64) { - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, - 8, 4, buf, 64, 0); - printk(KERN_ERR "%s... (only first 64 bytes " - "dumped)\n", prefix); - } else - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, - 8, 4, buf, size, 0); -} -EXPORT_SYMBOL(i2400m_unknown_barker); - - -/* - * Initialize the RX queue and infrastructure - * - * This sets up all the RX reordering infrastructures, which will not - * be used if reordering is not enabled or if the firmware does not - * support it. The device is told to do reordering in - * i2400m_dev_initialize(), where it also looks at the value of the - * i2400m->rx_reorder switch before taking a decission. - * - * Note we allocate the roq queues in one chunk and the actual logging - * support for it (logging) in another one and then we setup the - * pointers from the first to the last. - */ -int i2400m_rx_setup(struct i2400m *i2400m) -{ - int result = 0; - - i2400m->rx_reorder = i2400m_rx_reorder_disabled? 0 : 1; - if (i2400m->rx_reorder) { - unsigned itr; - struct i2400m_roq_log *rd; - - result = -ENOMEM; - - i2400m->rx_roq = kcalloc(I2400M_RO_CIN + 1, - sizeof(i2400m->rx_roq[0]), GFP_KERNEL); - if (i2400m->rx_roq == NULL) - goto error_roq_alloc; - - rd = kcalloc(I2400M_RO_CIN + 1, sizeof(*i2400m->rx_roq[0].log), - GFP_KERNEL); - if (rd == NULL) { - result = -ENOMEM; - goto error_roq_log_alloc; - } - - for(itr = 0; itr < I2400M_RO_CIN + 1; itr++) { - __i2400m_roq_init(&i2400m->rx_roq[itr]); - i2400m->rx_roq[itr].log = &rd[itr]; - } - kref_init(&i2400m->rx_roq_refcount); - } - return 0; - -error_roq_log_alloc: - kfree(i2400m->rx_roq); -error_roq_alloc: - return result; -} - - -/* Tear down the RX queue and infrastructure */ -void i2400m_rx_release(struct i2400m *i2400m) -{ - unsigned long flags; - - if (i2400m->rx_reorder) { - spin_lock_irqsave(&i2400m->rx_lock, flags); - kref_put(&i2400m->rx_roq_refcount, i2400m_rx_roq_destroy); - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - } - /* at this point, nothing can be received... */ - i2400m_report_hook_flush(i2400m); -} diff --git a/drivers/staging/wimax/i2400m/sysfs.c b/drivers/staging/wimax/i2400m/sysfs.c deleted file mode 100644 index 895ee265909be770d9a84f95d974d930fba9dbcb..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/sysfs.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless WiMAX Connection 2400m - * Sysfs interfaces to show driver and device information - * - * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/spinlock.h> -#include <linux/device.h> -#include "i2400m.h" - - -#define D_SUBMODULE sysfs -#include "debug-levels.h" - - -/* - * Set the idle timeout (msecs) - * - * FIXME: eventually this should be a common WiMAX stack method, but - * would like to wait to see how other devices manage it. - */ -static -ssize_t i2400m_idle_timeout_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct i2400m *i2400m = net_dev_to_i2400m(to_net_dev(dev)); - unsigned val; - - result = -EINVAL; - if (sscanf(buf, "%u\n", &val) != 1) - goto error_no_unsigned; - if (val != 0 && (val < 100 || val > 300000 || val % 100 != 0)) { - dev_err(dev, "idle_timeout: %u: invalid msecs specification; " - "valid values are 0, 100-300000 in 100 increments\n", - val); - goto error_bad_value; - } - result = i2400m_set_idle_timeout(i2400m, val); - if (result >= 0) - result = size; -error_no_unsigned: -error_bad_value: - return result; -} - -static -DEVICE_ATTR_WO(i2400m_idle_timeout); - -static -struct attribute *i2400m_dev_attrs[] = { - &dev_attr_i2400m_idle_timeout.attr, - NULL, -}; - -struct attribute_group i2400m_dev_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = i2400m_dev_attrs, -}; diff --git a/drivers/staging/wimax/i2400m/tx.c b/drivers/staging/wimax/i2400m/tx.c deleted file mode 100644 index 8c01f42876ea14eedcb706627da1f54a22f5b0fb..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/tx.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Generic (non-bus specific) TX handling - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * - * Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Rewritten to use a single FIFO to lower the memory allocation - * pressure and optimize cache hits when copying to the queue, as - * well as splitting out bus-specific code. - * - * - * Implements data transmission to the device; this is done through a - * software FIFO, as data/control frames can be coalesced (while the - * device is reading the previous tx transaction, others accumulate). - * - * A FIFO is used because at the end it is resource-cheaper that trying - * to implement scatter/gather over USB. As well, most traffic is going - * to be download (vs upload). - * - * The format for sending/receiving data to/from the i2400m is - * described in detail in rx.c:PROTOCOL FORMAT. In here we implement - * the transmission of that. This is split between a bus-independent - * part that just prepares everything and a bus-specific part that - * does the actual transmission over the bus to the device (in the - * bus-specific driver). - * - * - * The general format of a device-host transaction is MSG-HDR, PLD1, - * PLD2...PLDN, PL1, PL2,...PLN, PADDING. - * - * Because we need the send payload descriptors and then payloads and - * because it is kind of expensive to do scatterlists in USB (one URB - * per node), it becomes cheaper to append all the data to a FIFO - * (copying to a FIFO potentially in cache is cheaper). - * - * Then the bus-specific code takes the parts of that FIFO that are - * written and passes them to the device. - * - * So the concepts to keep in mind there are: - * - * We use a FIFO to queue the data in a linear buffer. We first append - * a MSG-HDR, space for I2400M_TX_PLD_MAX payload descriptors and then - * go appending payloads until we run out of space or of payload - * descriptors. Then we append padding to make the whole transaction a - * multiple of i2400m->bus_tx_block_size (as defined by the bus layer). - * - * - A TX message: a combination of a message header, payload - * descriptors and payloads. - * - * Open: it is marked as active (i2400m->tx_msg is valid) and we - * can keep adding payloads to it. - * - * Closed: we are not appending more payloads to this TX message - * (exahusted space in the queue, too many payloads or - * whichever). We have appended padding so the whole message - * length is aligned to i2400m->bus_tx_block_size (as set by the - * bus/transport layer). - * - * - Most of the time we keep a TX message open to which we append - * payloads. - * - * - If we are going to append and there is no more space (we are at - * the end of the FIFO), we close the message, mark the rest of the - * FIFO space unusable (skip_tail), create a new message at the - * beginning of the FIFO (if there is space) and append the message - * there. - * - * This is because we need to give linear TX messages to the bus - * engine. So we don't write a message to the remaining FIFO space - * until the tail and continue at the head of it. - * - * - We overload one of the fields in the message header to use it as - * 'size' of the TX message, so we can iterate over them. It also - * contains a flag that indicates if we have to skip it or not. - * When we send the buffer, we update that to its real on-the-wire - * value. - * - * - The MSG-HDR PLD1...PLD2 stuff has to be a size multiple of 16. - * - * It follows that if MSG-HDR says we have N messages, the whole - * header + descriptors is 16 + 4*N; for those to be a multiple of - * 16, it follows that N can be 4, 8, 12, ... (32, 48, 64, 80... - * bytes). - * - * So if we have only 1 payload, we have to submit a header that in - * all truth has space for 4. - * - * The implication is that we reserve space for 12 (64 bytes); but - * if we fill up only (eg) 2, our header becomes 32 bytes only. So - * the TX engine has to shift those 32 bytes of msg header and 2 - * payloads and padding so that right after it the payloads start - * and the TX engine has to know about that. - * - * It is cheaper to move the header up than the whole payloads down. - * - * We do this in i2400m_tx_close(). See 'i2400m_msg_hdr->offset'. - * - * - Each payload has to be size-padded to 16 bytes; before appending - * it, we just do it. - * - * - The whole message has to be padded to i2400m->bus_tx_block_size; - * we do this at close time. Thus, when reserving space for the - * payload, we always make sure there is also free space for this - * padding that sooner or later will happen. - * - * When we append a message, we tell the bus specific code to kick in - * TXs. It will TX (in parallel) until the buffer is exhausted--hence - * the lockin we do. The TX code will only send a TX message at the - * time (which remember, might contain more than one payload). Of - * course, when the bus-specific driver attempts to TX a message that - * is still open, it gets closed first. - * - * Gee, this is messy; well a picture. In the example below we have a - * partially full FIFO, with a closed message ready to be delivered - * (with a moved message header to make sure it is size-aligned to - * 16), TAIL room that was unusable (and thus is marked with a message - * header that says 'skip this') and at the head of the buffer, an - * incomplete message with a couple of payloads. - * - * N ___________________________________________________ - * | | - * | TAIL room | - * | | - * | msg_hdr to skip (size |= 0x80000) | - * |---------------------------------------------------|------- - * | | /|\ - * | | | - * | TX message padding | | - * | | | - * | | | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | - * | | | - * | payload 1 | | - * | | N * tx_block_size - * | | | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | - * | | | - * | payload 1 | | - * | | | - * | | | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -|- -|- - - - - * | padding 3 /|\ | | /|\ - * | padding 2 | | | | - * | pld 1 32 bytes (2 * 16) | | | - * | pld 0 | | | | - * | moved msg_hdr \|/ | \|/ | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -|- - - | - * | | _PLD_SIZE - * | unused | | - * | | | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | - * | msg_hdr (size X) [this message is closed] | \|/ - * |===================================================|========== <=== OUT - * | | - * | | - * | | - * | Free rooom | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * |===================================================|========== <=== IN - * | | - * | | - * | | - * | | - * | payload 1 | - * | | - * | | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -| - * | | - * | payload 0 | - * | | - * | | - * |- - - - - - - - - - - - - - - - - - - - - - - - - -| - * | pld 11 /|\ | - * | ... | | - * | pld 1 64 bytes (2 * 16) | - * | pld 0 | | - * | msg_hdr (size X) \|/ [message is open] | - * 0 --------------------------------------------------- - * - * - * ROADMAP - * - * i2400m_tx_setup() Called by i2400m_setup - * i2400m_tx_release() Called by i2400m_release() - * - * i2400m_tx() Called to send data or control frames - * i2400m_tx_fifo_push() Allocates append-space in the FIFO - * i2400m_tx_new() Opens a new message in the FIFO - * i2400m_tx_fits() Checks if a new payload fits in the message - * i2400m_tx_close() Closes an open message in the FIFO - * i2400m_tx_skip_tail() Marks unusable FIFO tail space - * i2400m->bus_tx_kick() - * - * Now i2400m->bus_tx_kick() is the the bus-specific driver backend - * implementation; that would do: - * - * i2400m->bus_tx_kick() - * i2400m_tx_msg_get() Gets first message ready to go - * ...sends it... - * i2400m_tx_msg_sent() Ack the message is sent; repeat from - * _tx_msg_get() until it returns NULL - * (FIFO empty). - */ -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/export.h> -#include "i2400m.h" - - -#define D_SUBMODULE tx -#include "debug-levels.h" - -enum { - /** - * TX Buffer size - * - * Doc says maximum transaction is 16KiB. If we had 16KiB en - * route and 16KiB being queued, it boils down to needing - * 32KiB. - * 32KiB is insufficient for 1400 MTU, hence increasing - * tx buffer size to 64KiB. - */ - I2400M_TX_BUF_SIZE = 65536, - /** - * Message header and payload descriptors have to be 16 - * aligned (16 + 4 * N = 16 * M). If we take that average sent - * packets are MTU size (~1400-~1500) it follows that we could - * fit at most 10-11 payloads in one transaction. To meet the - * alignment requirement, that means we need to leave space - * for 12 (64 bytes). To simplify, we leave space for that. If - * at the end there are less, we pad up to the nearest - * multiple of 16. - */ - /* - * According to Intel Wimax i3200, i5x50 and i6x50 specification - * documents, the maximum number of payloads per message can be - * up to 60. Increasing the number of payloads to 60 per message - * helps to accommodate smaller payloads in a single transaction. - */ - I2400M_TX_PLD_MAX = 60, - I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr) - + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld), - I2400M_TX_SKIP = 0x80000000, - /* - * According to Intel Wimax i3200, i5x50 and i6x50 specification - * documents, the maximum size of each message can be up to 16KiB. - */ - I2400M_TX_MSG_SIZE = 16384, -}; - -#define TAIL_FULL ((void *)~(unsigned long)NULL) - -/* - * Calculate how much tail room is available - * - * Note the trick here. This path is ONLY caleed for Case A (see - * i2400m_tx_fifo_push() below), where we have: - * - * Case A - * N ___________ - * | tail room | - * | | - * |<- IN ->| - * | | - * | data | - * | | - * |<- OUT ->| - * | | - * | head room | - * 0 ----------- - * - * When calculating the tail_room, tx_in might get to be zero if - * i2400m->tx_in is right at the end of the buffer (really full - * buffer) if there is no head room. In this case, tail_room would be - * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final - * mod (%) operation. However, when doing this kind of optimization, - * i2400m->tx_in being zero would fail, so we treat is an a special - * case. - */ -static inline -size_t __i2400m_tx_tail_room(struct i2400m *i2400m) -{ - size_t tail_room; - size_t tx_in; - - if (unlikely(i2400m->tx_in == 0)) - return I2400M_TX_BUF_SIZE; - tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; - tail_room = I2400M_TX_BUF_SIZE - tx_in; - tail_room %= I2400M_TX_BUF_SIZE; - return tail_room; -} - - -/* - * Allocate @size bytes in the TX fifo, return a pointer to it - * - * @i2400m: device descriptor - * @size: size of the buffer we need to allocate - * @padding: ensure that there is at least this many bytes of free - * contiguous space in the fifo. This is needed because later on - * we might need to add padding. - * @try_head: specify either to allocate head room or tail room space - * in the TX FIFO. This boolean is required to avoids a system hang - * due to an infinite loop caused by i2400m_tx_fifo_push(). - * The caller must always try to allocate tail room space first by - * calling this routine with try_head = 0. In case if there - * is not enough tail room space but there is enough head room space, - * (i2400m_tx_fifo_push() returns TAIL_FULL) try to allocate head - * room space, by calling this routine again with try_head = 1. - * - * Returns: - * - * Pointer to the allocated space. NULL if there is no - * space. TAIL_FULL if there is no space at the tail but there is at - * the head (Case B below). - * - * These are the two basic cases we need to keep an eye for -- it is - * much better explained in linux/kernel/kfifo.c, but this code - * basically does the same. No rocket science here. - * - * Case A Case B - * N ___________ ___________ - * | tail room | | data | - * | | | | - * |<- IN ->| |<- OUT ->| - * | | | | - * | data | | room | - * | | | | - * |<- OUT ->| |<- IN ->| - * | | | | - * | head room | | data | - * 0 ----------- ----------- - * - * We allocate only *contiguous* space. - * - * We can allocate only from 'room'. In Case B, it is simple; in case - * A, we only try from the tail room; if it is not enough, we just - * fail and return TAIL_FULL and let the caller figure out if we wants to - * skip the tail room and try to allocate from the head. - * - * There is a corner case, wherein i2400m_tx_new() can get into - * an infinite loop calling i2400m_tx_fifo_push(). - * In certain situations, tx_in would have reached on the top of TX FIFO - * and i2400m_tx_tail_room() returns 0, as described below: - * - * N ___________ tail room is zero - * |<- IN ->| - * | | - * | | - * | | - * | data | - * |<- OUT ->| - * | | - * | | - * | head room | - * 0 ----------- - * During such a time, where tail room is zero in the TX FIFO and if there - * is a request to add a payload to TX FIFO, which calls: - * i2400m_tx() - * ->calls i2400m_tx_close() - * ->calls i2400m_tx_skip_tail() - * goto try_new; - * ->calls i2400m_tx_new() - * |----> [try_head:] - * infinite loop | ->calls i2400m_tx_fifo_push() - * | if (tail_room < needed) - * | if (head_room => needed) - * | return TAIL_FULL; - * |<---- goto try_head; - * - * i2400m_tx() calls i2400m_tx_close() to close the message, since there - * is no tail room to accommodate the payload and calls - * i2400m_tx_skip_tail() to skip the tail space. Now i2400m_tx() calls - * i2400m_tx_new() to allocate space for new message header calling - * i2400m_tx_fifo_push() that returns TAIL_FULL, since there is no tail space - * to accommodate the message header, but there is enough head space. - * The i2400m_tx_new() keeps re-retrying by calling i2400m_tx_fifo_push() - * ending up in a loop causing system freeze. - * - * This corner case is avoided by using a try_head boolean, - * as an argument to i2400m_tx_fifo_push(). - * - * Note: - * - * Assumes i2400m->tx_lock is taken, and we use that as a barrier - * - * The indexes keep increasing and we reset them to zero when we - * pop data off the queue - */ -static -void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, - size_t padding, bool try_head) -{ - struct device *dev = i2400m_dev(i2400m); - size_t room, tail_room, needed_size; - void *ptr; - - needed_size = size + padding; - room = I2400M_TX_BUF_SIZE - (i2400m->tx_in - i2400m->tx_out); - if (room < needed_size) { /* this takes care of Case B */ - d_printf(2, dev, "fifo push %zu/%zu: no space\n", - size, padding); - return NULL; - } - /* Is there space at the tail? */ - tail_room = __i2400m_tx_tail_room(i2400m); - if (!try_head && tail_room < needed_size) { - /* - * If the tail room space is not enough to push the message - * in the TX FIFO, then there are two possibilities: - * 1. There is enough head room space to accommodate - * this message in the TX FIFO. - * 2. There is not enough space in the head room and - * in tail room of the TX FIFO to accommodate the message. - * In the case (1), return TAIL_FULL so that the caller - * can figure out, if the caller wants to push the message - * into the head room space. - * In the case (2), return NULL, indicating that the TX FIFO - * cannot accommodate the message. - */ - if (room - tail_room >= needed_size) { - d_printf(2, dev, "fifo push %zu/%zu: tail full\n", - size, padding); - return TAIL_FULL; /* There might be head space */ - } else { - d_printf(2, dev, "fifo push %zu/%zu: no head space\n", - size, padding); - return NULL; /* There is no space */ - } - } - ptr = i2400m->tx_buf + i2400m->tx_in % I2400M_TX_BUF_SIZE; - d_printf(2, dev, "fifo push %zu/%zu: at @%zu\n", size, padding, - i2400m->tx_in % I2400M_TX_BUF_SIZE); - i2400m->tx_in += size; - return ptr; -} - - -/* - * Mark the tail of the FIFO buffer as 'to-skip' - * - * We should never hit the BUG_ON() because all the sizes we push to - * the FIFO are padded to be a multiple of 16 -- the size of *msg - * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the - * header). - * - * Tail room can get to be zero if a message was opened when there was - * space only for a header. _tx_close() will mark it as to-skip (as it - * will have no payloads) and there will be no more space to flush, so - * nothing has to be done here. This is probably cheaper than ensuring - * in _tx_new() that there is some space for payloads...as we could - * always possibly hit the same problem if the payload wouldn't fit. - * - * Note: - * - * Assumes i2400m->tx_lock is taken, and we use that as a barrier - * - * This path is only taken for Case A FIFO situations [see - * i2400m_tx_fifo_push()] - */ -static -void i2400m_tx_skip_tail(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; - size_t tail_room = __i2400m_tx_tail_room(i2400m); - struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; - if (unlikely(tail_room == 0)) - return; - BUG_ON(tail_room < sizeof(*msg)); - msg->size = tail_room | I2400M_TX_SKIP; - d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", - tail_room, tx_in); - i2400m->tx_in += tail_room; -} - - -/* - * Check if a skb will fit in the TX queue's current active TX - * message (if there are still descriptors left unused). - * - * Returns: - * 0 if the message won't fit, 1 if it will. - * - * Note: - * - * Assumes a TX message is active (i2400m->tx_msg). - * - * Assumes i2400m->tx_lock is taken, and we use that as a barrier - */ -static -unsigned i2400m_tx_fits(struct i2400m *i2400m) -{ - struct i2400m_msg_hdr *msg_hdr = i2400m->tx_msg; - return le16_to_cpu(msg_hdr->num_pls) < I2400M_TX_PLD_MAX; - -} - - -/* - * Start a new TX message header in the queue. - * - * Reserve memory from the base FIFO engine and then just initialize - * the message header. - * - * We allocate the biggest TX message header we might need (one that'd - * fit I2400M_TX_PLD_MAX payloads) -- when it is closed it will be - * 'ironed it out' and the unneeded parts removed. - * - * NOTE: - * - * Assumes that the previous message is CLOSED (eg: either - * there was none or 'i2400m_tx_close()' was called on it). - * - * Assumes i2400m->tx_lock is taken, and we use that as a barrier - */ -static -void i2400m_tx_new(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - struct i2400m_msg_hdr *tx_msg; - bool try_head = false; - BUG_ON(i2400m->tx_msg != NULL); - /* - * In certain situations, TX queue might have enough space to - * accommodate the new message header I2400M_TX_PLD_SIZE, but - * might not have enough space to accommodate the payloads. - * Adding bus_tx_room_min padding while allocating a new TX message - * increases the possibilities of including at least one payload of the - * size <= bus_tx_room_min. - */ -try_head: - tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, - i2400m->bus_tx_room_min, try_head); - if (tx_msg == NULL) - goto out; - else if (tx_msg == TAIL_FULL) { - i2400m_tx_skip_tail(i2400m); - d_printf(2, dev, "new TX message: tail full, trying head\n"); - try_head = true; - goto try_head; - } - memset(tx_msg, 0, I2400M_TX_PLD_SIZE); - tx_msg->size = I2400M_TX_PLD_SIZE; -out: - i2400m->tx_msg = tx_msg; - d_printf(2, dev, "new TX message: %p @%zu\n", - tx_msg, (void *) tx_msg - i2400m->tx_buf); -} - - -/* - * Finalize the current TX message header - * - * Sets the message header to be at the proper location depending on - * how many descriptors we have (check documentation at the file's - * header for more info on that). - * - * Appends padding bytes to make sure the whole TX message (counting - * from the 'relocated' message header) is aligned to - * tx_block_size. We assume the _append() code has left enough space - * in the FIFO for that. If there are no payloads, just pass, as it - * won't be transferred. - * - * The amount of padding bytes depends on how many payloads are in the - * TX message, as the "msg header and payload descriptors" will be - * shifted up in the buffer. - */ -static -void i2400m_tx_close(struct i2400m *i2400m) -{ - struct device *dev = i2400m_dev(i2400m); - struct i2400m_msg_hdr *tx_msg = i2400m->tx_msg; - struct i2400m_msg_hdr *tx_msg_moved; - size_t aligned_size, padding, hdr_size; - void *pad_buf; - unsigned num_pls; - - if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ - goto out; - num_pls = le16_to_cpu(tx_msg->num_pls); - /* We can get this situation when a new message was started - * and there was no space to add payloads before hitting the - tail (and taking padding into consideration). */ - if (num_pls == 0) { - tx_msg->size |= I2400M_TX_SKIP; - goto out; - } - /* Relocate the message header - * - * Find the current header size, align it to 16 and if we need - * to move it so the tail is next to the payloads, move it and - * set the offset. - * - * If it moved, this header is good only for transmission; the - * original one (it is kept if we moved) is still used to - * figure out where the next TX message starts (and where the - * offset to the moved header is). - */ - hdr_size = struct_size(tx_msg, pld, le16_to_cpu(tx_msg->num_pls)); - hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN); - tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; - tx_msg_moved = (void *) tx_msg + tx_msg->offset; - memmove(tx_msg_moved, tx_msg, hdr_size); - tx_msg_moved->size -= tx_msg->offset; - /* - * Now figure out how much we have to add to the (moved!) - * message so the size is a multiple of i2400m->bus_tx_block_size. - */ - aligned_size = ALIGN(tx_msg_moved->size, i2400m->bus_tx_block_size); - padding = aligned_size - tx_msg_moved->size; - if (padding > 0) { - pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0, 0); - if (WARN_ON(pad_buf == NULL || pad_buf == TAIL_FULL)) { - /* This should not happen -- append should verify - * there is always space left at least to append - * tx_block_size */ - dev_err(dev, - "SW BUG! Possible data leakage from memory the " - "device should not read for padding - " - "size %lu aligned_size %zu tx_buf %p in " - "%zu out %zu\n", - (unsigned long) tx_msg_moved->size, - aligned_size, i2400m->tx_buf, i2400m->tx_in, - i2400m->tx_out); - } else - memset(pad_buf, 0xad, padding); - } - tx_msg_moved->padding = cpu_to_le16(padding); - tx_msg_moved->size += padding; - if (tx_msg != tx_msg_moved) - tx_msg->size += padding; -out: - i2400m->tx_msg = NULL; -} - - -/** - * i2400m_tx - send the data in a buffer to the device - * - * @i2400m: device descriptor - * - * @buf: pointer to the buffer to transmit - * - * @buf_len: buffer size - * - * @pl_type: type of the payload we are sending. - * - * Returns: - * 0 if ok, < 0 errno code on error (-ENOSPC, if there is no more - * room for the message in the queue). - * - * Appends the buffer to the TX FIFO and notifies the bus-specific - * part of the driver that there is new data ready to transmit. - * Once this function returns, the buffer has been copied, so it can - * be reused. - * - * The steps followed to append are explained in detail in the file - * header. - * - * Whenever we write to a message, we increase msg->size, so it - * reflects exactly how big the message is. This is needed so that if - * we concatenate two messages before they can be sent, the code that - * sends the messages can find the boundaries (and it will replace the - * size with the real barker before sending). - * - * Note: - * - * Cold and warm reset payloads need to be sent as a single - * payload, so we handle that. - */ -int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, - enum i2400m_pt pl_type) -{ - int result = -ENOSPC; - struct device *dev = i2400m_dev(i2400m); - unsigned long flags; - size_t padded_len; - void *ptr; - bool try_head = false; - unsigned is_singleton = pl_type == I2400M_PT_RESET_WARM - || pl_type == I2400M_PT_RESET_COLD; - - d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", - i2400m, buf, buf_len, pl_type); - padded_len = ALIGN(buf_len, I2400M_PL_ALIGN); - d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); - /* If there is no current TX message, create one; if the - * current one is out of payload slots or we have a singleton, - * close it and start a new one */ - spin_lock_irqsave(&i2400m->tx_lock, flags); - /* If tx_buf is NULL, device is shutdown */ - if (i2400m->tx_buf == NULL) { - result = -ESHUTDOWN; - goto error_tx_new; - } -try_new: - if (unlikely(i2400m->tx_msg == NULL)) - i2400m_tx_new(i2400m); - else if (unlikely(!i2400m_tx_fits(i2400m) - || (is_singleton && i2400m->tx_msg->num_pls != 0))) { - d_printf(2, dev, "closing TX message (fits %u singleton " - "%u num_pls %u)\n", i2400m_tx_fits(i2400m), - is_singleton, i2400m->tx_msg->num_pls); - i2400m_tx_close(i2400m); - i2400m_tx_new(i2400m); - } - if (i2400m->tx_msg == NULL) - goto error_tx_new; - /* - * Check if this skb will fit in the TX queue's current active - * TX message. The total message size must not exceed the maximum - * size of each message I2400M_TX_MSG_SIZE. If it exceeds, - * close the current message and push this skb into the new message. - */ - if (i2400m->tx_msg->size + padded_len > I2400M_TX_MSG_SIZE) { - d_printf(2, dev, "TX: message too big, going new\n"); - i2400m_tx_close(i2400m); - i2400m_tx_new(i2400m); - } - if (i2400m->tx_msg == NULL) - goto error_tx_new; - /* So we have a current message header; now append space for - * the message -- if there is not enough, try the head */ - ptr = i2400m_tx_fifo_push(i2400m, padded_len, - i2400m->bus_tx_block_size, try_head); - if (ptr == TAIL_FULL) { /* Tail is full, try head */ - d_printf(2, dev, "pl append: tail full\n"); - i2400m_tx_close(i2400m); - i2400m_tx_skip_tail(i2400m); - try_head = true; - goto try_new; - } else if (ptr == NULL) { /* All full */ - result = -ENOSPC; - d_printf(2, dev, "pl append: all full\n"); - } else { /* Got space, copy it, set padding */ - struct i2400m_msg_hdr *tx_msg = i2400m->tx_msg; - unsigned num_pls = le16_to_cpu(tx_msg->num_pls); - memcpy(ptr, buf, buf_len); - memset(ptr + buf_len, 0xad, padded_len - buf_len); - i2400m_pld_set(&tx_msg->pld[num_pls], buf_len, pl_type); - d_printf(3, dev, "pld 0x%08x (type 0x%1x len 0x%04zx\n", - le32_to_cpu(tx_msg->pld[num_pls].val), - pl_type, buf_len); - tx_msg->num_pls = cpu_to_le16(num_pls + 1); - tx_msg->size += padded_len; - d_printf(2, dev, "TX: appended %zu b (up to %u b) pl #%u\n", - padded_len, tx_msg->size, num_pls+1); - d_printf(2, dev, - "TX: appended hdr @%zu %zu b pl #%u @%zu %zu/%zu b\n", - (void *)tx_msg - i2400m->tx_buf, (size_t)tx_msg->size, - num_pls+1, ptr - i2400m->tx_buf, buf_len, padded_len); - result = 0; - if (is_singleton) - i2400m_tx_close(i2400m); - } -error_tx_new: - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - /* kick in most cases, except when the TX subsys is down, as - * it might free space */ - if (likely(result != -ESHUTDOWN)) - i2400m->bus_tx_kick(i2400m); - d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n", - i2400m, buf, buf_len, pl_type, result); - return result; -} -EXPORT_SYMBOL_GPL(i2400m_tx); - - -/** - * i2400m_tx_msg_get - Get the first TX message in the FIFO to start sending it - * - * @i2400m: device descriptors - * @bus_size: where to place the size of the TX message - * - * Called by the bus-specific driver to get the first TX message at - * the FIF that is ready for transmission. - * - * It sets the state in @i2400m to indicate the bus-specific driver is - * transferring that message (i2400m->tx_msg_size). - * - * Once the transfer is completed, call i2400m_tx_msg_sent(). - * - * Notes: - * - * The size of the TX message to be transmitted might be smaller than - * that of the TX message in the FIFO (in case the header was - * shorter). Hence, we copy it in @bus_size, for the bus layer to - * use. We keep the message's size in i2400m->tx_msg_size so that - * when the bus later is done transferring we know how much to - * advance the fifo. - * - * We collect statistics here as all the data is available and we - * assume it is going to work [see i2400m_tx_msg_sent()]. - */ -struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m, - size_t *bus_size) -{ - struct device *dev = i2400m_dev(i2400m); - struct i2400m_msg_hdr *tx_msg, *tx_msg_moved; - unsigned long flags, pls; - - d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size); - spin_lock_irqsave(&i2400m->tx_lock, flags); - tx_msg_moved = NULL; - if (i2400m->tx_buf == NULL) - goto out_unlock; -skip: - tx_msg_moved = NULL; - if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */ - i2400m->tx_in = 0; - i2400m->tx_out = 0; - d_printf(2, dev, "TX: FIFO empty: resetting\n"); - goto out_unlock; - } - tx_msg = i2400m->tx_buf + i2400m->tx_out % I2400M_TX_BUF_SIZE; - if (tx_msg->size & I2400M_TX_SKIP) { /* skip? */ - d_printf(2, dev, "TX: skip: msg @%zu (%zu b)\n", - i2400m->tx_out % I2400M_TX_BUF_SIZE, - (size_t) tx_msg->size & ~I2400M_TX_SKIP); - i2400m->tx_out += tx_msg->size & ~I2400M_TX_SKIP; - goto skip; - } - - if (tx_msg->num_pls == 0) { /* No payloads? */ - if (tx_msg == i2400m->tx_msg) { /* open, we are done */ - d_printf(2, dev, - "TX: FIFO empty: open msg w/o payloads @%zu\n", - (void *) tx_msg - i2400m->tx_buf); - tx_msg = NULL; - goto out_unlock; - } else { /* closed, skip it */ - d_printf(2, dev, - "TX: skip msg w/o payloads @%zu (%zu b)\n", - (void *) tx_msg - i2400m->tx_buf, - (size_t) tx_msg->size); - i2400m->tx_out += tx_msg->size & ~I2400M_TX_SKIP; - goto skip; - } - } - if (tx_msg == i2400m->tx_msg) /* open msg? */ - i2400m_tx_close(i2400m); - - /* Now we have a valid TX message (with payloads) to TX */ - tx_msg_moved = (void *) tx_msg + tx_msg->offset; - i2400m->tx_msg_size = tx_msg->size; - *bus_size = tx_msg_moved->size; - d_printf(2, dev, "TX: pid %d msg hdr at @%zu offset +@%zu " - "size %zu bus_size %zu\n", - current->pid, (void *) tx_msg - i2400m->tx_buf, - (size_t) tx_msg->offset, (size_t) tx_msg->size, - (size_t) tx_msg_moved->size); - tx_msg_moved->barker = cpu_to_le32(I2400M_H2D_PREVIEW_BARKER); - tx_msg_moved->sequence = cpu_to_le32(i2400m->tx_sequence++); - - pls = le16_to_cpu(tx_msg_moved->num_pls); - i2400m->tx_pl_num += pls; /* Update stats */ - if (pls > i2400m->tx_pl_max) - i2400m->tx_pl_max = pls; - if (pls < i2400m->tx_pl_min) - i2400m->tx_pl_min = pls; - i2400m->tx_num++; - i2400m->tx_size_acc += *bus_size; - if (*bus_size < i2400m->tx_size_min) - i2400m->tx_size_min = *bus_size; - if (*bus_size > i2400m->tx_size_max) - i2400m->tx_size_max = *bus_size; -out_unlock: - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - d_fnstart(3, dev, "(i2400m %p bus_size %p [%zu]) = %p\n", - i2400m, bus_size, *bus_size, tx_msg_moved); - return tx_msg_moved; -} -EXPORT_SYMBOL_GPL(i2400m_tx_msg_get); - - -/** - * i2400m_tx_msg_sent - indicate the transmission of a TX message - * - * @i2400m: device descriptor - * - * Called by the bus-specific driver when a message has been sent; - * this pops it from the FIFO; and as there is space, start the queue - * in case it was stopped. - * - * Should be called even if the message send failed and we are - * dropping this TX message. - */ -void i2400m_tx_msg_sent(struct i2400m *i2400m) -{ - unsigned n; - unsigned long flags; - struct device *dev = i2400m_dev(i2400m); - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - spin_lock_irqsave(&i2400m->tx_lock, flags); - if (i2400m->tx_buf == NULL) - goto out_unlock; - i2400m->tx_out += i2400m->tx_msg_size; - d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size); - i2400m->tx_msg_size = 0; - BUG_ON(i2400m->tx_out > i2400m->tx_in); - /* level them FIFO markers off */ - n = i2400m->tx_out / I2400M_TX_BUF_SIZE; - i2400m->tx_out %= I2400M_TX_BUF_SIZE; - i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; -out_unlock: - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} -EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent); - - -/** - * i2400m_tx_setup - Initialize the TX queue and infrastructure - * - * @i2400m: device descriptor - * - * Make sure we reset the TX sequence to zero, as when this function - * is called, the firmware has been just restarted. Same rational - * for tx_in, tx_out, tx_msg_size and tx_msg. We reset them since - * the memory for TX queue is reallocated. - */ -int i2400m_tx_setup(struct i2400m *i2400m) -{ - int result = 0; - void *tx_buf; - unsigned long flags; - - /* Do this here only once -- can't do on - * i2400m_hard_start_xmit() as we'll cause race conditions if - * the WS was scheduled on another CPU */ - INIT_WORK(&i2400m->wake_tx_ws, i2400m_wake_tx_work); - - tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_ATOMIC); - if (tx_buf == NULL) { - result = -ENOMEM; - goto error_kmalloc; - } - - /* - * Fail the build if we can't fit at least two maximum size messages - * on the TX FIFO [one being delivered while one is constructed]. - */ - BUILD_BUG_ON(2 * I2400M_TX_MSG_SIZE > I2400M_TX_BUF_SIZE); - spin_lock_irqsave(&i2400m->tx_lock, flags); - i2400m->tx_sequence = 0; - i2400m->tx_in = 0; - i2400m->tx_out = 0; - i2400m->tx_msg_size = 0; - i2400m->tx_msg = NULL; - i2400m->tx_buf = tx_buf; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - /* Huh? the bus layer has to define this... */ - BUG_ON(i2400m->bus_tx_block_size == 0); -error_kmalloc: - return result; - -} - - -/* - * i2400m_tx_release - Tear down the TX queue and infrastructure - */ -void i2400m_tx_release(struct i2400m *i2400m) -{ - unsigned long flags; - spin_lock_irqsave(&i2400m->tx_lock, flags); - kfree(i2400m->tx_buf); - i2400m->tx_buf = NULL; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); -} diff --git a/drivers/staging/wimax/i2400m/usb-debug-levels.h b/drivers/staging/wimax/i2400m/usb-debug-levels.h deleted file mode 100644 index 8fd0111560f6fca99a43444f213713c4c6a425f3..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/usb-debug-levels.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Wireless WiMAX Connection 2400m - * Debug levels control file for the i2400m-usb module - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ -#ifndef __debug_levels__h__ -#define __debug_levels__h__ - -/* Maximum compile and run time debug level for all submodules */ -#define D_MODULENAME i2400m_usb -#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL - -#include "../linux-wimax-debug.h" - -/* List of all the enabled modules */ -enum d_module { - D_SUBMODULE_DECLARE(usb), - D_SUBMODULE_DECLARE(fw), - D_SUBMODULE_DECLARE(notif), - D_SUBMODULE_DECLARE(rx), - D_SUBMODULE_DECLARE(tx), -}; - - -#endif /* #ifndef __debug_levels__h__ */ diff --git a/drivers/staging/wimax/i2400m/usb-fw.c b/drivers/staging/wimax/i2400m/usb-fw.c deleted file mode 100644 index 27ab233650d538c6aff52a7d015c14a99b36a6d9..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/usb-fw.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Firmware uploader's USB specifics - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - bus generic/specific split - * - * THE PROCEDURE - * - * See fw.c for the generic description of this procedure. - * - * This file implements only the USB specifics. It boils down to how - * to send a command and waiting for an acknowledgement from the - * device. - * - * This code (and process) is single threaded. It assumes it is the - * only thread poking around (guaranteed by fw.c). - * - * COMMAND EXECUTION - * - * A write URB is posted with the buffer to the bulk output endpoint. - * - * ACK RECEPTION - * - * We just post a URB to the notification endpoint and wait for - * data. We repeat until we get all the data we expect (as indicated - * by the call from the bus generic code). - * - * The data is not read from the bulk in endpoint for boot mode. - * - * ROADMAP - * - * i2400mu_bus_bm_cmd_send - * i2400m_bm_cmd_prepare... - * i2400mu_tx_bulk_out - * - * i2400mu_bus_bm_wait_for_ack - * i2400m_notif_submit - */ -#include <linux/usb.h> -#include <linux/gfp.h> -#include "i2400m-usb.h" - - -#define D_SUBMODULE fw -#include "usb-debug-levels.h" - - -/* - * Synchronous write to the device - * - * Takes care of updating EDC counts and thus, handle device errors. - */ -static -ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size) -{ - int result; - struct device *dev = &i2400mu->usb_iface->dev; - int len; - struct usb_endpoint_descriptor *epd; - int pipe, do_autopm = 1; - - result = usb_autopm_get_interface(i2400mu->usb_iface); - if (result < 0) { - dev_err(dev, "BM-CMD: can't get autopm: %d\n", result); - do_autopm = 0; - } - epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out); - pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); -retry: - result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, 200); - switch (result) { - case 0: - if (len != buf_size) { - dev_err(dev, "BM-CMD: short write (%u B vs %zu " - "expected)\n", len, buf_size); - result = -EIO; - break; - } - result = len; - break; - case -EPIPE: - /* - * Stall -- maybe the device is choking with our - * requests. Clear it and give it some time. If they - * happen to often, it might be another symptom, so we - * reset. - * - * No error handling for usb_clear_halt(0; if it - * works, the retry works; if it fails, this switch - * does the error handling for us. - */ - if (edc_inc(&i2400mu->urb_edc, - 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "BM-CMD: too many stalls in " - "URB; resetting device\n"); - usb_queue_reset_device(i2400mu->usb_iface); - } else { - usb_clear_halt(i2400mu->usb_dev, pipe); - msleep(10); /* give the device some time */ - goto retry; - } - fallthrough; - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* just ignore it */ - case -ESHUTDOWN: /* and exit */ - case -ECONNRESET: - result = -ESHUTDOWN; - break; - case -ETIMEDOUT: /* bah... */ - break; - default: /* any other? */ - if (edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "BM-CMD: maximum errors in " - "URB exceeded; resetting device\n"); - usb_queue_reset_device(i2400mu->usb_iface); - result = -ENODEV; - break; - } - dev_err(dev, "BM-CMD: URB error %d, retrying\n", - result); - goto retry; - } - if (do_autopm) - usb_autopm_put_interface(i2400mu->usb_iface); - return result; -} - - -/* - * Send a boot-mode command over the bulk-out pipe - * - * Command can be a raw command, which requires no preparation (and - * which might not even be following the command format). Checks that - * the right amount of data was transferred. - * - * To satisfy USB requirements (no onstack, vmalloc or in data segment - * buffers), we copy the command to i2400m->bm_cmd_buf and send it from - * there. - * - * @flags: pass thru from i2400m_bm_cmd() - * @return: cmd_size if ok, < 0 errno code on error. - */ -ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m, - const struct i2400m_bootrom_header *_cmd, - size_t cmd_size, int flags) -{ - ssize_t result; - struct device *dev = i2400m_dev(i2400m); - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd); - struct i2400m_bootrom_header *cmd; - size_t cmd_size_a = ALIGN(cmd_size, 16); /* USB restriction */ - - d_fnstart(8, dev, "(i2400m %p cmd %p size %zu)\n", - i2400m, _cmd, cmd_size); - result = -E2BIG; - if (cmd_size > I2400M_BM_CMD_BUF_SIZE) - goto error_too_big; - if (_cmd != i2400m->bm_cmd_buf) - memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); - cmd = i2400m->bm_cmd_buf; - if (cmd_size_a > cmd_size) /* Zero pad space */ - memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); - if ((flags & I2400M_BM_CMD_RAW) == 0) { - if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0)) - dev_warn(dev, "SW BUG: response_required == 0\n"); - i2400m_bm_cmd_prepare(cmd); - } - result = i2400mu_tx_bulk_out(i2400mu, i2400m->bm_cmd_buf, cmd_size); - if (result < 0) { - dev_err(dev, "boot-mode cmd %d: cannot send: %zd\n", - opcode, result); - goto error_cmd_send; - } - if (result != cmd_size) { /* all was transferred? */ - dev_err(dev, "boot-mode cmd %d: incomplete transfer " - "(%zd vs %zu submitted)\n", opcode, result, cmd_size); - result = -EIO; - goto error_cmd_size; - } -error_cmd_size: -error_cmd_send: -error_too_big: - d_fnend(8, dev, "(i2400m %p cmd %p size %zu) = %zd\n", - i2400m, _cmd, cmd_size, result); - return result; -} - - -static -void __i2400mu_bm_notif_cb(struct urb *urb) -{ - complete(urb->context); -} - - -/* - * submit a read to the notification endpoint - * - * @i2400m: device descriptor - * @urb: urb to use - * @completion: completion variable to complete when done - * - * Data is always read to i2400m->bm_ack_buf - */ -static -int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb, - struct completion *completion) -{ - struct i2400m *i2400m = &i2400mu->i2400m; - struct usb_endpoint_descriptor *epd; - int pipe; - - epd = usb_get_epd(i2400mu->usb_iface, - i2400mu->endpoint_cfg.notification); - pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); - usb_fill_int_urb(urb, i2400mu->usb_dev, pipe, - i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE, - __i2400mu_bm_notif_cb, completion, - epd->bInterval); - return usb_submit_urb(urb, GFP_KERNEL); -} - - -/* - * Read an ack from the notification endpoint - * - * @i2400m: - * @_ack: pointer to where to store the read data - * @ack_size: how many bytes we should read - * - * Returns: < 0 errno code on error; otherwise, amount of received bytes. - * - * Submits a notification read, appends the read data to the given ack - * buffer and then repeats (until @ack_size bytes have been - * received). - */ -ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m, - struct i2400m_bootrom_header *_ack, - size_t ack_size) -{ - ssize_t result = -ENOMEM; - struct device *dev = i2400m_dev(i2400m); - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - struct urb notif_urb; - void *ack = _ack; - size_t offset, len; - long val; - int do_autopm = 1; - DECLARE_COMPLETION_ONSTACK(notif_completion); - - d_fnstart(8, dev, "(i2400m %p ack %p size %zu)\n", - i2400m, ack, ack_size); - BUG_ON(_ack == i2400m->bm_ack_buf); - result = usb_autopm_get_interface(i2400mu->usb_iface); - if (result < 0) { - dev_err(dev, "BM-ACK: can't get autopm: %d\n", (int) result); - do_autopm = 0; - } - usb_init_urb(¬if_urb); /* ready notifications */ - usb_get_urb(¬if_urb); - offset = 0; - while (offset < ack_size) { - init_completion(¬if_completion); - result = i2400mu_notif_submit(i2400mu, ¬if_urb, - ¬if_completion); - if (result < 0) - goto error_notif_urb_submit; - val = wait_for_completion_interruptible_timeout( - ¬if_completion, HZ); - if (val == 0) { - result = -ETIMEDOUT; - usb_kill_urb(¬if_urb); /* Timedout */ - goto error_notif_wait; - } - if (val == -ERESTARTSYS) { - result = -EINTR; /* Interrupted */ - usb_kill_urb(¬if_urb); - goto error_notif_wait; - } - result = notif_urb.status; /* How was the ack? */ - switch (result) { - case 0: - break; - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* just ignore it */ - case -ESHUTDOWN: /* and exit */ - case -ECONNRESET: - result = -ESHUTDOWN; - goto error_dev_gone; - default: /* any other? */ - usb_kill_urb(¬if_urb); /* Timedout */ - if (edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) - goto error_exceeded; - dev_err(dev, "BM-ACK: URB error %d, " - "retrying\n", notif_urb.status); - continue; /* retry */ - } - if (notif_urb.actual_length == 0) { - d_printf(6, dev, "ZLP received, retrying\n"); - continue; - } - /* Got data, append it to the buffer */ - len = min(ack_size - offset, (size_t) notif_urb.actual_length); - memcpy(ack + offset, i2400m->bm_ack_buf, len); - offset += len; - } - result = offset; -error_notif_urb_submit: -error_notif_wait: -error_dev_gone: -out: - if (do_autopm) - usb_autopm_put_interface(i2400mu->usb_iface); - d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n", - i2400m, ack, ack_size, (long) result); - usb_put_urb(¬if_urb); - return result; - -error_exceeded: - dev_err(dev, "bm: maximum errors in notification URB exceeded; " - "resetting device\n"); - usb_queue_reset_device(i2400mu->usb_iface); - goto out; -} diff --git a/drivers/staging/wimax/i2400m/usb-notif.c b/drivers/staging/wimax/i2400m/usb-notif.c deleted file mode 100644 index 5d429f81612546fa44c6c19f6b64c28fc2f6b336..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/usb-notif.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m over USB - * Notification handling - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * - * The notification endpoint is active when the device is not in boot - * mode; in here we just read and get notifications; based on those, - * we act to either reinitialize the device after a reboot or to - * submit a RX request. - * - * ROADMAP - * - * i2400mu_usb_notification_setup() - * - * i2400mu_usb_notification_release() - * - * i2400mu_usb_notification_cb() Called when a URB is ready - * i2400mu_notif_grok() - * i2400m_is_boot_barker() - * i2400m_dev_reset_handle() - * i2400mu_rx_kick() - */ -#include <linux/usb.h> -#include <linux/slab.h> -#include "i2400m-usb.h" - - -#define D_SUBMODULE notif -#include "usb-debug-levels.h" - - -static const -__le32 i2400m_ZERO_BARKER[4] = { 0, 0, 0, 0 }; - - -/* - * Process a received notification - * - * In normal operation mode, we can only receive two types of payloads - * on the notification endpoint: - * - * - a reboot barker, we do a bootstrap (the device has reseted). - * - * - a block of zeroes: there is pending data in the IN endpoint - */ -static -int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf, - size_t buf_len) -{ - int ret; - struct device *dev = &i2400mu->usb_iface->dev; - struct i2400m *i2400m = &i2400mu->i2400m; - - d_fnstart(4, dev, "(i2400m %p buf %p buf_len %zu)\n", - i2400mu, buf, buf_len); - ret = -EIO; - if (buf_len < sizeof(i2400m_ZERO_BARKER)) - /* Not a bug, just ignore */ - goto error_bad_size; - ret = 0; - if (!memcmp(i2400m_ZERO_BARKER, buf, sizeof(i2400m_ZERO_BARKER))) { - i2400mu_rx_kick(i2400mu); - goto out; - } - ret = i2400m_is_boot_barker(i2400m, buf, buf_len); - if (unlikely(ret >= 0)) - ret = i2400m_dev_reset_handle(i2400m, "device rebooted"); - else /* Unknown or unexpected data in the notif message */ - i2400m_unknown_barker(i2400m, buf, buf_len); -error_bad_size: -out: - d_fnend(4, dev, "(i2400m %p buf %p buf_len %zu) = %d\n", - i2400mu, buf, buf_len, ret); - return ret; -} - - -/* - * URB callback for the notification endpoint - * - * @urb: the urb received from the notification endpoint - * - * This function will just process the USB side of the transaction, - * checking everything is fine, pass the processing to - * i2400m_notification_grok() and resubmit the URB. - */ -static -void i2400mu_notification_cb(struct urb *urb) -{ - int ret; - struct i2400mu *i2400mu = urb->context; - struct device *dev = &i2400mu->usb_iface->dev; - - d_fnstart(4, dev, "(urb %p status %d actual_length %d)\n", - urb, urb->status, urb->actual_length); - ret = urb->status; - switch (ret) { - case 0: - ret = i2400mu_notification_grok(i2400mu, urb->transfer_buffer, - urb->actual_length); - if (ret == -EIO && edc_inc(&i2400mu->urb_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) - goto error_exceeded; - if (ret == -ENOMEM) /* uff...power cycle? shutdown? */ - goto error_exceeded; - break; - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* ditto */ - case -ESHUTDOWN: /* URB killed */ - case -ECONNRESET: /* disconnection */ - goto out; /* Notify around */ - default: /* Some error? */ - if (edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) - goto error_exceeded; - dev_err(dev, "notification: URB error %d, retrying\n", - urb->status); - } - usb_mark_last_busy(i2400mu->usb_dev); - ret = usb_submit_urb(i2400mu->notif_urb, GFP_ATOMIC); - switch (ret) { - case 0: - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* ditto */ - case -ESHUTDOWN: /* URB killed */ - case -ECONNRESET: /* disconnection */ - break; /* just ignore */ - default: /* Some error? */ - dev_err(dev, "notification: cannot submit URB: %d\n", ret); - goto error_submit; - } - d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n", - urb, urb->status, urb->actual_length); - return; - -error_exceeded: - dev_err(dev, "maximum errors in notification URB exceeded; " - "resetting device\n"); -error_submit: - usb_queue_reset_device(i2400mu->usb_iface); -out: - d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n", - urb, urb->status, urb->actual_length); -} - - -/* - * setup the notification endpoint - * - * @i2400m: device descriptor - * - * This procedure prepares the notification urb and handler for receiving - * unsolicited barkers from the device. - */ -int i2400mu_notification_setup(struct i2400mu *i2400mu) -{ - struct device *dev = &i2400mu->usb_iface->dev; - int usb_pipe, ret = 0; - struct usb_endpoint_descriptor *epd; - char *buf; - - d_fnstart(4, dev, "(i2400m %p)\n", i2400mu); - buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA); - if (buf == NULL) { - ret = -ENOMEM; - goto error_buf_alloc; - } - - i2400mu->notif_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!i2400mu->notif_urb) { - ret = -ENOMEM; - goto error_alloc_urb; - } - epd = usb_get_epd(i2400mu->usb_iface, - i2400mu->endpoint_cfg.notification); - usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); - usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe, - buf, I2400MU_MAX_NOTIFICATION_LEN, - i2400mu_notification_cb, i2400mu, epd->bInterval); - ret = usb_submit_urb(i2400mu->notif_urb, GFP_KERNEL); - if (ret != 0) { - dev_err(dev, "notification: cannot submit URB: %d\n", ret); - goto error_submit; - } - d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret); - return ret; - -error_submit: - usb_free_urb(i2400mu->notif_urb); -error_alloc_urb: - kfree(buf); -error_buf_alloc: - d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret); - return ret; -} - - -/* - * Tear down of the notification mechanism - * - * @i2400m: device descriptor - * - * Kill the interrupt endpoint urb, free any allocated resources. - * - * We need to check if we have done it before as for example, - * _suspend() call this; if after a suspend() we get a _disconnect() - * (as the case is when hibernating), nothing bad happens. - */ -void i2400mu_notification_release(struct i2400mu *i2400mu) -{ - struct device *dev = &i2400mu->usb_iface->dev; - - d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); - if (i2400mu->notif_urb != NULL) { - usb_kill_urb(i2400mu->notif_urb); - kfree(i2400mu->notif_urb->transfer_buffer); - usb_free_urb(i2400mu->notif_urb); - i2400mu->notif_urb = NULL; - } - d_fnend(4, dev, "(i2400mu %p)\n", i2400mu); -} diff --git a/drivers/staging/wimax/i2400m/usb-rx.c b/drivers/staging/wimax/i2400m/usb-rx.c deleted file mode 100644 index 5b64bda7d9e71969c535b93d983235e7f5530ceb..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/usb-rx.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * USB RX handling - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Use skb_clone(), break up processing in chunks - * - Split transport/device specific - * - Make buffer size dynamic to exert less memory pressure - * - * - * This handles the RX path on USB. - * - * When a notification is received that says 'there is RX data ready', - * we call i2400mu_rx_kick(); that wakes up the RX kthread, which - * reads a buffer from USB and passes it to i2400m_rx() in the generic - * handling code. The RX buffer has an specific format that is - * described in rx.c. - * - * We use a kernel thread in a loop because: - * - * - we want to be able to call the USB power management get/put - * functions (blocking) before each transaction. - * - * - We might get a lot of notifications and we don't want to submit - * a zillion reads; by serializing, we are throttling. - * - * - RX data processing can get heavy enough so that it is not - * appropriate for doing it in the USB callback; thus we run it in a - * process context. - * - * We provide a read buffer of an arbitrary size (short of a page); if - * the callback reports -EOVERFLOW, it means it was too small, so we - * just double the size and retry (being careful to append, as - * sometimes the device provided some data). Every now and then we - * check if the average packet size is smaller than the current packet - * size and if so, we halve it. At the end, the size of the - * preallocated buffer should be following the average received - * transaction size, adapting dynamically to it. - * - * ROADMAP - * - * i2400mu_rx_kick() Called from notif.c when we get a - * 'data ready' notification - * i2400mu_rxd() Kernel RX daemon - * i2400mu_rx() Receive USB data - * i2400m_rx() Send data to generic i2400m RX handling - * - * i2400mu_rx_setup() called from i2400mu_bus_dev_start() - * - * i2400mu_rx_release() called from i2400mu_bus_dev_stop() - */ -#include <linux/workqueue.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include "i2400m-usb.h" - - -#define D_SUBMODULE rx -#include "usb-debug-levels.h" - -/* - * Dynamic RX size - * - * We can't let the rx_size be a multiple of 512 bytes (the RX - * endpoint's max packet size). On some USB host controllers (we - * haven't been able to fully characterize which), if the device is - * about to send (for example) X bytes and we only post a buffer to - * receive n*512, it will fail to mark that as babble (so that - * i2400mu_rx() [case -EOVERFLOW] can resize the buffer and get the - * rest). - * - * So on growing or shrinking, if it is a multiple of the - * maxpacketsize, we remove some (instead of incresing some, so in a - * buddy allocator we try to waste less space). - * - * Note we also need a hook for this on i2400mu_rx() -- when we do the - * first read, we are sure we won't hit this spot because - * i240mm->rx_size has been set properly. However, if we have to - * double because of -EOVERFLOW, when we launch the read to get the - * rest of the data, we *have* to make sure that also is not a - * multiple of the max_pkt_size. - */ - -static -size_t i2400mu_rx_size_grow(struct i2400mu *i2400mu) -{ - struct device *dev = &i2400mu->usb_iface->dev; - size_t rx_size; - const size_t max_pkt_size = 512; - - rx_size = 2 * i2400mu->rx_size; - if (rx_size % max_pkt_size == 0) { - rx_size -= 8; - d_printf(1, dev, - "RX: expected size grew to %zu [adjusted -8] " - "from %zu\n", - rx_size, i2400mu->rx_size); - } else - d_printf(1, dev, - "RX: expected size grew to %zu from %zu\n", - rx_size, i2400mu->rx_size); - return rx_size; -} - - -static -void i2400mu_rx_size_maybe_shrink(struct i2400mu *i2400mu) -{ - const size_t max_pkt_size = 512; - struct device *dev = &i2400mu->usb_iface->dev; - - if (unlikely(i2400mu->rx_size_cnt >= 100 - && i2400mu->rx_size_auto_shrink)) { - size_t avg_rx_size = - i2400mu->rx_size_acc / i2400mu->rx_size_cnt; - size_t new_rx_size = i2400mu->rx_size / 2; - if (avg_rx_size < new_rx_size) { - if (new_rx_size % max_pkt_size == 0) { - new_rx_size -= 8; - d_printf(1, dev, - "RX: expected size shrank to %zu " - "[adjusted -8] from %zu\n", - new_rx_size, i2400mu->rx_size); - } else - d_printf(1, dev, - "RX: expected size shrank to %zu " - "from %zu\n", - new_rx_size, i2400mu->rx_size); - i2400mu->rx_size = new_rx_size; - i2400mu->rx_size_cnt = 0; - i2400mu->rx_size_acc = i2400mu->rx_size; - } - } -} - -/* - * Receive a message with payloads from the USB bus into an skb - * - * @i2400mu: USB device descriptor - * @rx_skb: skb where to place the received message - * - * Deals with all the USB-specifics of receiving, dynamically - * increasing the buffer size if so needed. Returns the payload in the - * skb, ready to process. On a zero-length packet, we retry. - * - * On soft USB errors, we retry (until they become too frequent and - * then are promoted to hard); on hard USB errors, we reset the - * device. On other errors (skb realloacation, we just drop it and - * hope for the next invocation to solve it). - * - * Returns: pointer to the skb if ok, ERR_PTR on error. - * NOTE: this function might realloc the skb (if it is too small), - * so always update with the one returned. - * ERR_PTR() is < 0 on error. - * Will return NULL if it cannot reallocate -- this can be - * considered a transient retryable error. - */ -static -struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb) -{ - int result = 0; - struct device *dev = &i2400mu->usb_iface->dev; - int usb_pipe, read_size, rx_size, do_autopm; - struct usb_endpoint_descriptor *epd; - const size_t max_pkt_size = 512; - - d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); - do_autopm = atomic_read(&i2400mu->do_autopm); - result = do_autopm ? - usb_autopm_get_interface(i2400mu->usb_iface) : 0; - if (result < 0) { - dev_err(dev, "RX: can't get autopm: %d\n", result); - do_autopm = 0; - } - epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_in); - usb_pipe = usb_rcvbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); -retry: - rx_size = skb_end_pointer(rx_skb) - rx_skb->data - rx_skb->len; - if (unlikely(rx_size % max_pkt_size == 0)) { - rx_size -= 8; - d_printf(1, dev, "RX: rx_size adapted to %d [-8]\n", rx_size); - } - result = usb_bulk_msg( - i2400mu->usb_dev, usb_pipe, rx_skb->data + rx_skb->len, - rx_size, &read_size, 200); - usb_mark_last_busy(i2400mu->usb_dev); - switch (result) { - case 0: - if (read_size == 0) - goto retry; /* ZLP, just resubmit */ - skb_put(rx_skb, read_size); - break; - case -EPIPE: - /* - * Stall -- maybe the device is choking with our - * requests. Clear it and give it some time. If they - * happen to often, it might be another symptom, so we - * reset. - * - * No error handling for usb_clear_halt(0; if it - * works, the retry works; if it fails, this switch - * does the error handling for us. - */ - if (edc_inc(&i2400mu->urb_edc, - 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "BM-CMD: too many stalls in " - "URB; resetting device\n"); - goto do_reset; - } - usb_clear_halt(i2400mu->usb_dev, usb_pipe); - msleep(10); /* give the device some time */ - goto retry; - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* just ignore it */ - case -ESHUTDOWN: - case -ECONNRESET: - break; - case -EOVERFLOW: { /* too small, reallocate */ - struct sk_buff *new_skb; - rx_size = i2400mu_rx_size_grow(i2400mu); - if (rx_size <= (1 << 16)) /* cap it */ - i2400mu->rx_size = rx_size; - else if (printk_ratelimit()) { - dev_err(dev, "BUG? rx_size up to %d\n", rx_size); - result = -EINVAL; - goto out; - } - skb_put(rx_skb, read_size); - new_skb = skb_copy_expand(rx_skb, 0, rx_size - rx_skb->len, - GFP_KERNEL); - if (new_skb == NULL) { - kfree_skb(rx_skb); - rx_skb = NULL; - goto out; /* drop it...*/ - } - kfree_skb(rx_skb); - rx_skb = new_skb; - i2400mu->rx_size_cnt = 0; - i2400mu->rx_size_acc = i2400mu->rx_size; - d_printf(1, dev, "RX: size changed to %d, received %d, " - "copied %d, capacity %ld\n", - rx_size, read_size, rx_skb->len, - (long) skb_end_offset(new_skb)); - goto retry; - } - /* In most cases, it happens due to the hardware scheduling a - * read when there was no data - unfortunately, we have no way - * to tell this timeout from a USB timeout. So we just ignore - * it. */ - case -ETIMEDOUT: - dev_err(dev, "RX: timeout: %d\n", result); - result = 0; - break; - default: /* Any error */ - if (edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) - goto error_reset; - dev_err(dev, "RX: error receiving URB: %d, retrying\n", result); - goto retry; - } -out: - if (do_autopm) - usb_autopm_put_interface(i2400mu->usb_iface); - d_fnend(4, dev, "(i2400mu %p) = %p\n", i2400mu, rx_skb); - return rx_skb; - -error_reset: - dev_err(dev, "RX: maximum errors in URB exceeded; " - "resetting device\n"); -do_reset: - usb_queue_reset_device(i2400mu->usb_iface); - rx_skb = ERR_PTR(result); - goto out; -} - - -/* - * Kernel thread for USB reception of data - * - * This thread waits for a kick; once kicked, it will allocate an skb - * and receive a single message to it from USB (using - * i2400mu_rx()). Once received, it is passed to the generic i2400m RX - * code for processing. - * - * When done processing, it runs some dirty statistics to verify if - * the last 100 messages received were smaller than half of the - * current RX buffer size. In that case, the RX buffer size is - * halved. This will helps lowering the pressure on the memory - * allocator. - * - * Hard errors force the thread to exit. - */ -static -int i2400mu_rxd(void *_i2400mu) -{ - int result = 0; - struct i2400mu *i2400mu = _i2400mu; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = &i2400mu->usb_iface->dev; - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - size_t pending; - int rx_size; - struct sk_buff *rx_skb; - unsigned long flags; - - d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); - spin_lock_irqsave(&i2400m->rx_lock, flags); - BUG_ON(i2400mu->rx_kthread != NULL); - i2400mu->rx_kthread = current; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - while (1) { - d_printf(2, dev, "RX: waiting for messages\n"); - pending = 0; - wait_event_interruptible( - i2400mu->rx_wq, - (kthread_should_stop() /* check this first! */ - || (pending = atomic_read(&i2400mu->rx_pending_count))) - ); - if (kthread_should_stop()) - break; - if (pending == 0) - continue; - rx_size = i2400mu->rx_size; - d_printf(2, dev, "RX: reading up to %d bytes\n", rx_size); - rx_skb = __netdev_alloc_skb(net_dev, rx_size, GFP_KERNEL); - if (rx_skb == NULL) { - dev_err(dev, "RX: can't allocate skb [%d bytes]\n", - rx_size); - msleep(50); /* give it some time? */ - continue; - } - - /* Receive the message with the payloads */ - rx_skb = i2400mu_rx(i2400mu, rx_skb); - result = PTR_ERR(rx_skb); - if (IS_ERR(rx_skb)) - goto out; - atomic_dec(&i2400mu->rx_pending_count); - if (rx_skb == NULL || rx_skb->len == 0) { - /* some "ignorable" condition */ - kfree_skb(rx_skb); - continue; - } - - /* Deliver the message to the generic i2400m code */ - i2400mu->rx_size_cnt++; - i2400mu->rx_size_acc += rx_skb->len; - result = i2400m_rx(i2400m, rx_skb); - if (result == -EIO - && edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - goto error_reset; - } - - /* Maybe adjust RX buffer size */ - i2400mu_rx_size_maybe_shrink(i2400mu); - } - result = 0; -out: - spin_lock_irqsave(&i2400m->rx_lock, flags); - i2400mu->rx_kthread = NULL; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result); - return result; - -error_reset: - dev_err(dev, "RX: maximum errors in received buffer exceeded; " - "resetting device\n"); - usb_queue_reset_device(i2400mu->usb_iface); - goto out; -} - - -/* - * Start reading from the device - * - * @i2400m: device instance - * - * Notify the RX thread that there is data pending. - */ -void i2400mu_rx_kick(struct i2400mu *i2400mu) -{ - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = &i2400mu->usb_iface->dev; - - d_fnstart(3, dev, "(i2400mu %p)\n", i2400m); - atomic_inc(&i2400mu->rx_pending_count); - wake_up_all(&i2400mu->rx_wq); - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} - - -int i2400mu_rx_setup(struct i2400mu *i2400mu) -{ - int result = 0; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = &i2400mu->usb_iface->dev; - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - struct task_struct *kthread; - - kthread = kthread_run(i2400mu_rxd, i2400mu, "%s-rx", - wimax_dev->name); - /* the kthread function sets i2400mu->rx_thread */ - if (IS_ERR(kthread)) { - result = PTR_ERR(kthread); - dev_err(dev, "RX: cannot start thread: %d\n", result); - } - return result; -} - - -void i2400mu_rx_release(struct i2400mu *i2400mu) -{ - unsigned long flags; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = i2400m_dev(i2400m); - struct task_struct *kthread; - - spin_lock_irqsave(&i2400m->rx_lock, flags); - kthread = i2400mu->rx_kthread; - i2400mu->rx_kthread = NULL; - spin_unlock_irqrestore(&i2400m->rx_lock, flags); - if (kthread) - kthread_stop(kthread); - else - d_printf(1, dev, "RX: kthread had already exited\n"); -} - diff --git a/drivers/staging/wimax/i2400m/usb-tx.c b/drivers/staging/wimax/i2400m/usb-tx.c deleted file mode 100644 index 3ba9d70cca1b439bd530f1b04f8ea13debda3b5d..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/usb-tx.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * USB specific TX handling - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Split transport/device specific - * - * - * Takes the TX messages in the i2400m's driver TX FIFO and sends them - * to the device until there are no more. - * - * If we fail sending the message, we just drop it. There isn't much - * we can do at this point. We could also retry, but the USB stack has - * already retried and still failed, so there is not much of a - * point. As well, most of the traffic is network, which has recovery - * methods for dropped packets. - * - * For sending we just obtain a FIFO buffer to send, send it to the - * USB bulk out, tell the TX FIFO code we have sent it; query for - * another one, etc... until done. - * - * We use a thread so we can call usb_autopm_enable() and - * usb_autopm_disable() for each transaction; this way when the device - * goes idle, it will suspend. It also has less overhead than a - * dedicated workqueue, as it is being used for a single task. - * - * ROADMAP - * - * i2400mu_tx_setup() - * i2400mu_tx_release() - * - * i2400mu_bus_tx_kick() - Called by the tx.c code when there - * is new data in the FIFO. - * i2400mu_txd() - * i2400m_tx_msg_get() - * i2400m_tx_msg_sent() - */ -#include "i2400m-usb.h" - - -#define D_SUBMODULE tx -#include "usb-debug-levels.h" - - -/* - * Get the next TX message in the TX FIFO and send it to the device - * - * Note that any iteration consumes a message to be sent, no matter if - * it succeeds or fails (we have no real way to retry or complain). - * - * Return: 0 if ok, < 0 errno code on hard error. - */ -static -int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg, - size_t tx_msg_size) -{ - int result = 0; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = &i2400mu->usb_iface->dev; - int usb_pipe, sent_size, do_autopm; - struct usb_endpoint_descriptor *epd; - - d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); - do_autopm = atomic_read(&i2400mu->do_autopm); - result = do_autopm ? - usb_autopm_get_interface(i2400mu->usb_iface) : 0; - if (result < 0) { - dev_err(dev, "TX: can't get autopm: %d\n", result); - do_autopm = 0; - } - epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out); - usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); -retry: - result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe, - tx_msg, tx_msg_size, &sent_size, 200); - usb_mark_last_busy(i2400mu->usb_dev); - switch (result) { - case 0: - if (sent_size != tx_msg_size) { /* Too short? drop it */ - dev_err(dev, "TX: short write (%d B vs %zu " - "expected)\n", sent_size, tx_msg_size); - result = -EIO; - } - break; - case -EPIPE: - /* - * Stall -- maybe the device is choking with our - * requests. Clear it and give it some time. If they - * happen to often, it might be another symptom, so we - * reset. - * - * No error handling for usb_clear_halt(0; if it - * works, the retry works; if it fails, this switch - * does the error handling for us. - */ - if (edc_inc(&i2400mu->urb_edc, - 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "BM-CMD: too many stalls in " - "URB; resetting device\n"); - usb_queue_reset_device(i2400mu->usb_iface); - } else { - usb_clear_halt(i2400mu->usb_dev, usb_pipe); - msleep(10); /* give the device some time */ - goto retry; - } - fallthrough; - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* just ignore it */ - case -ESHUTDOWN: /* and exit */ - case -ECONNRESET: - result = -ESHUTDOWN; - break; - default: /* Some error? */ - if (edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "TX: maximum errors in URB " - "exceeded; resetting device\n"); - usb_queue_reset_device(i2400mu->usb_iface); - } else { - dev_err(dev, "TX: cannot send URB; retrying. " - "tx_msg @%zu %zu B [%d sent]: %d\n", - (void *) tx_msg - i2400m->tx_buf, - tx_msg_size, sent_size, result); - goto retry; - } - } - if (do_autopm) - usb_autopm_put_interface(i2400mu->usb_iface); - d_fnend(4, dev, "(i2400mu %p) = result\n", i2400mu); - return result; -} - - -/* - * Get the next TX message in the TX FIFO and send it to the device - * - * Note we exit the loop if i2400mu_tx() fails; that function only - * fails on hard error (failing to tx a buffer not being one of them, - * see its doc). - * - * Return: 0 - */ -static -int i2400mu_txd(void *_i2400mu) -{ - struct i2400mu *i2400mu = _i2400mu; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = &i2400mu->usb_iface->dev; - struct i2400m_msg_hdr *tx_msg; - size_t tx_msg_size; - unsigned long flags; - - d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); - - spin_lock_irqsave(&i2400m->tx_lock, flags); - BUG_ON(i2400mu->tx_kthread != NULL); - i2400mu->tx_kthread = current; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - - while (1) { - d_printf(2, dev, "TX: waiting for messages\n"); - tx_msg = NULL; - wait_event_interruptible( - i2400mu->tx_wq, - (kthread_should_stop() /* check this first! */ - || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) - ); - if (kthread_should_stop()) - break; - WARN_ON(tx_msg == NULL); /* should not happen...*/ - d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size); - d_dump(5, dev, tx_msg, tx_msg_size); - /* Yeah, we ignore errors ... not much we can do */ - i2400mu_tx(i2400mu, tx_msg, tx_msg_size); - i2400m_tx_msg_sent(i2400m); /* ack it, advance the FIFO */ - } - - spin_lock_irqsave(&i2400m->tx_lock, flags); - i2400mu->tx_kthread = NULL; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - - d_fnend(4, dev, "(i2400mu %p)\n", i2400mu); - return 0; -} - - -/* - * i2400m TX engine notifies us that there is data in the FIFO ready - * for TX - * - * If there is a URB in flight, don't do anything; when it finishes, - * it will see there is data in the FIFO and send it. Else, just - * submit a write. - */ -void i2400mu_bus_tx_kick(struct i2400m *i2400m) -{ - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - struct device *dev = &i2400mu->usb_iface->dev; - - d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m); - wake_up_all(&i2400mu->tx_wq); - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} - - -int i2400mu_tx_setup(struct i2400mu *i2400mu) -{ - int result = 0; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = &i2400mu->usb_iface->dev; - struct wimax_dev *wimax_dev = &i2400m->wimax_dev; - struct task_struct *kthread; - - kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx", - wimax_dev->name); - /* the kthread function sets i2400mu->tx_thread */ - if (IS_ERR(kthread)) { - result = PTR_ERR(kthread); - dev_err(dev, "TX: cannot start thread: %d\n", result); - } - return result; -} - -void i2400mu_tx_release(struct i2400mu *i2400mu) -{ - unsigned long flags; - struct i2400m *i2400m = &i2400mu->i2400m; - struct device *dev = i2400m_dev(i2400m); - struct task_struct *kthread; - - spin_lock_irqsave(&i2400m->tx_lock, flags); - kthread = i2400mu->tx_kthread; - i2400mu->tx_kthread = NULL; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - if (kthread) - kthread_stop(kthread); - else - d_printf(1, dev, "TX: kthread had already exited\n"); -} diff --git a/drivers/staging/wimax/i2400m/usb.c b/drivers/staging/wimax/i2400m/usb.c deleted file mode 100644 index 481b1ccde9830a78c87d63a53dd184735c7eb294..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/i2400m/usb.c +++ /dev/null @@ -1,765 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless WiMAX Connection 2400m - * Linux driver model glue for USB device, reset & fw upload - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - * See i2400m-usb.h for a general description of this driver. - * - * This file implements driver model glue, and hook ups for the - * generic driver to implement the bus-specific functions (device - * communication setup/tear down, firmware upload and resetting). - * - * ROADMAP - * - * i2400mu_probe() - * alloc_netdev()... - * i2400mu_netdev_setup() - * i2400mu_init() - * i2400m_netdev_setup() - * i2400m_setup()... - * - * i2400mu_disconnect - * i2400m_release() - * free_netdev() - * - * i2400mu_suspend() - * i2400m_cmd_enter_powersave() - * i2400mu_notification_release() - * - * i2400mu_resume() - * i2400mu_notification_setup() - * - * i2400mu_bus_dev_start() Called by i2400m_dev_start() [who is - * i2400mu_tx_setup() called by i2400m_setup()] - * i2400mu_rx_setup() - * i2400mu_notification_setup() - * - * i2400mu_bus_dev_stop() Called by i2400m_dev_stop() [who is - * i2400mu_notification_release() called by i2400m_release()] - * i2400mu_rx_release() - * i2400mu_tx_release() - * - * i2400mu_bus_reset() Called by i2400m_reset - * __i2400mu_reset() - * __i2400mu_send_barker() - * usb_reset_device() - */ -#include "i2400m-usb.h" -#include "linux-wimax-i2400m.h" -#include <linux/debugfs.h> -#include <linux/ethtool.h> -#include <linux/slab.h> -#include <linux/module.h> - - -#define D_SUBMODULE usb -#include "usb-debug-levels.h" - -static char i2400mu_debug_params[128]; -module_param_string(debug, i2400mu_debug_params, sizeof(i2400mu_debug_params), - 0644); -MODULE_PARM_DESC(debug, - "String of space-separated NAME:VALUE pairs, where NAMEs " - "are the different debug submodules and VALUE are the " - "initial debug value to set."); - -/* Our firmware file name */ -static const char *i2400mu_bus_fw_names_5x50[] = { -#define I2400MU_FW_FILE_NAME_v1_5 "i2400m-fw-usb-1.5.sbcf" - I2400MU_FW_FILE_NAME_v1_5, -#define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf" - I2400MU_FW_FILE_NAME_v1_4, - NULL, -}; - - -static const char *i2400mu_bus_fw_names_6050[] = { -#define I6050U_FW_FILE_NAME_v1_5 "i6050-fw-usb-1.5.sbcf" - I6050U_FW_FILE_NAME_v1_5, - NULL, -}; - - -static -int i2400mu_bus_dev_start(struct i2400m *i2400m) -{ - int result; - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - struct device *dev = &i2400mu->usb_iface->dev; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - result = i2400mu_tx_setup(i2400mu); - if (result < 0) - goto error_usb_tx_setup; - result = i2400mu_rx_setup(i2400mu); - if (result < 0) - goto error_usb_rx_setup; - result = i2400mu_notification_setup(i2400mu); - if (result < 0) - goto error_notif_setup; - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); - return result; - -error_notif_setup: - i2400mu_rx_release(i2400mu); -error_usb_rx_setup: - i2400mu_tx_release(i2400mu); -error_usb_tx_setup: - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); - return result; -} - - -static -void i2400mu_bus_dev_stop(struct i2400m *i2400m) -{ - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - struct device *dev = &i2400mu->usb_iface->dev; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - i2400mu_notification_release(i2400mu); - i2400mu_rx_release(i2400mu); - i2400mu_tx_release(i2400mu); - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} - - -/* - * Sends a barker buffer to the device - * - * This helper will allocate a kmalloced buffer and use it to transmit - * (then free it). Reason for this is that other arches cannot use - * stack/vmalloc/text areas for DMA transfers. - * - * Error recovery here is simpler: anything is considered a hard error - * and will move the reset code to use a last-resort bus-based reset. - */ -static -int __i2400mu_send_barker(struct i2400mu *i2400mu, - const __le32 *barker, - size_t barker_size, - unsigned endpoint) -{ - struct usb_endpoint_descriptor *epd = NULL; - int pipe, actual_len, ret; - struct device *dev = &i2400mu->usb_iface->dev; - void *buffer; - int do_autopm = 1; - - ret = usb_autopm_get_interface(i2400mu->usb_iface); - if (ret < 0) { - dev_err(dev, "RESET: can't get autopm: %d\n", ret); - do_autopm = 0; - } - ret = -ENOMEM; - buffer = kmalloc(barker_size, GFP_KERNEL); - if (buffer == NULL) - goto error_kzalloc; - epd = usb_get_epd(i2400mu->usb_iface, endpoint); - pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); - memcpy(buffer, barker, barker_size); -retry: - ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size, - &actual_len, 200); - switch (ret) { - case 0: - if (actual_len != barker_size) { /* Too short? drop it */ - dev_err(dev, "E: %s: short write (%d B vs %zu " - "expected)\n", - __func__, actual_len, barker_size); - ret = -EIO; - } - break; - case -EPIPE: - /* - * Stall -- maybe the device is choking with our - * requests. Clear it and give it some time. If they - * happen to often, it might be another symptom, so we - * reset. - * - * No error handling for usb_clear_halt(0; if it - * works, the retry works; if it fails, this switch - * does the error handling for us. - */ - if (edc_inc(&i2400mu->urb_edc, - 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "E: %s: too many stalls in " - "URB; resetting device\n", __func__); - usb_queue_reset_device(i2400mu->usb_iface); - /* fallthrough */ - } else { - usb_clear_halt(i2400mu->usb_dev, pipe); - msleep(10); /* give the device some time */ - goto retry; - } - fallthrough; - case -EINVAL: /* while removing driver */ - case -ENODEV: /* dev disconnect ... */ - case -ENOENT: /* just ignore it */ - case -ESHUTDOWN: /* and exit */ - case -ECONNRESET: - ret = -ESHUTDOWN; - break; - default: /* Some error? */ - if (edc_inc(&i2400mu->urb_edc, - EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "E: %s: maximum errors in URB " - "exceeded; resetting device\n", - __func__); - usb_queue_reset_device(i2400mu->usb_iface); - } else { - dev_warn(dev, "W: %s: cannot send URB: %d\n", - __func__, ret); - goto retry; - } - } - kfree(buffer); -error_kzalloc: - if (do_autopm) - usb_autopm_put_interface(i2400mu->usb_iface); - return ret; -} - - -/* - * Reset a device at different levels (warm, cold or bus) - * - * @i2400m: device descriptor - * @reset_type: soft, warm or bus reset (I2400M_RT_WARM/SOFT/BUS) - * - * Warm and cold resets get a USB reset if they fail. - * - * Warm reset: - * - * The device will be fully reset internally, but won't be - * disconnected from the USB bus (so no reenumeration will - * happen). Firmware upload will be necessary. - * - * The device will send a reboot barker in the notification endpoint - * that will trigger the driver to reinitialize the state - * automatically from notif.c:i2400m_notification_grok() into - * i2400m_dev_bootstrap_delayed(). - * - * Cold and bus (USB) reset: - * - * The device will be fully reset internally, disconnected from the - * USB bus an a reenumeration will happen. Firmware upload will be - * necessary. Thus, we don't do any locking or struct - * reinitialization, as we are going to be fully disconnected and - * reenumerated. - * - * Note we need to return -ENODEV if a warm reset was requested and we - * had to resort to a bus reset. See i2400m_op_reset(), wimax_reset() - * and wimax_dev->op_reset. - * - * WARNING: no driver state saved/fixed - */ -static -int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) -{ - int result; - struct i2400mu *i2400mu = - container_of(i2400m, struct i2400mu, i2400m); - struct device *dev = i2400m_dev(i2400m); - static const __le32 i2400m_WARM_BOOT_BARKER[4] = { - cpu_to_le32(I2400M_WARM_RESET_BARKER), - cpu_to_le32(I2400M_WARM_RESET_BARKER), - cpu_to_le32(I2400M_WARM_RESET_BARKER), - cpu_to_le32(I2400M_WARM_RESET_BARKER), - }; - static const __le32 i2400m_COLD_BOOT_BARKER[4] = { - cpu_to_le32(I2400M_COLD_RESET_BARKER), - cpu_to_le32(I2400M_COLD_RESET_BARKER), - cpu_to_le32(I2400M_COLD_RESET_BARKER), - cpu_to_le32(I2400M_COLD_RESET_BARKER), - }; - - d_fnstart(3, dev, "(i2400m %p rt %u)\n", i2400m, rt); - if (rt == I2400M_RT_WARM) - result = __i2400mu_send_barker( - i2400mu, i2400m_WARM_BOOT_BARKER, - sizeof(i2400m_WARM_BOOT_BARKER), - i2400mu->endpoint_cfg.bulk_out); - else if (rt == I2400M_RT_COLD) - result = __i2400mu_send_barker( - i2400mu, i2400m_COLD_BOOT_BARKER, - sizeof(i2400m_COLD_BOOT_BARKER), - i2400mu->endpoint_cfg.reset_cold); - else if (rt == I2400M_RT_BUS) { - result = usb_reset_device(i2400mu->usb_dev); - switch (result) { - case 0: - case -EINVAL: /* device is gone */ - case -ENODEV: - case -ENOENT: - case -ESHUTDOWN: - result = 0; - break; /* We assume the device is disconnected */ - default: - dev_err(dev, "USB reset failed (%d), giving up!\n", - result); - } - } else { - result = -EINVAL; /* shut gcc up in certain arches */ - BUG(); - } - if (result < 0 - && result != -EINVAL /* device is gone */ - && rt != I2400M_RT_BUS) { - /* - * Things failed -- resort to lower level reset, that - * we queue in another context; the reason for this is - * that the pre and post reset functionality requires - * the i2400m->init_mutex; RT_WARM and RT_COLD can - * come from areas where i2400m->init_mutex is taken. - */ - dev_err(dev, "%s reset failed (%d); trying USB reset\n", - rt == I2400M_RT_WARM ? "warm" : "cold", result); - usb_queue_reset_device(i2400mu->usb_iface); - result = -ENODEV; - } - d_fnend(3, dev, "(i2400m %p rt %u) = %d\n", i2400m, rt, result); - return result; -} - -static void i2400mu_get_drvinfo(struct net_device *net_dev, - struct ethtool_drvinfo *info) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - struct usb_device *udev = i2400mu->usb_dev; - - strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strscpy(info->fw_version, i2400m->fw_name ? : "", - sizeof(info->fw_version)); - usb_make_path(udev, info->bus_info, sizeof(info->bus_info)); -} - -static const struct ethtool_ops i2400mu_ethtool_ops = { - .get_drvinfo = i2400mu_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - -static -void i2400mu_netdev_setup(struct net_device *net_dev) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); - i2400mu_init(i2400mu); - i2400m_netdev_setup(net_dev); - net_dev->ethtool_ops = &i2400mu_ethtool_ops; -} - - -/* - * Debug levels control; see debug.h - */ -struct d_level D_LEVEL[] = { - D_SUBMODULE_DEFINE(usb), - D_SUBMODULE_DEFINE(fw), - D_SUBMODULE_DEFINE(notif), - D_SUBMODULE_DEFINE(rx), - D_SUBMODULE_DEFINE(tx), -}; -size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); - -static -void i2400mu_debugfs_add(struct i2400mu *i2400mu) -{ - struct dentry *dentry = i2400mu->i2400m.wimax_dev.debugfs_dentry; - - dentry = debugfs_create_dir("i2400m-usb", dentry); - i2400mu->debugfs_dentry = dentry; - - d_level_register_debugfs("dl_", usb, dentry); - d_level_register_debugfs("dl_", fw, dentry); - d_level_register_debugfs("dl_", notif, dentry); - d_level_register_debugfs("dl_", rx, dentry); - d_level_register_debugfs("dl_", tx, dentry); - - /* Don't touch these if you don't know what you are doing */ - debugfs_create_u8("rx_size_auto_shrink", 0600, dentry, - &i2400mu->rx_size_auto_shrink); - - debugfs_create_size_t("rx_size", 0600, dentry, &i2400mu->rx_size); -} - - -static struct device_type i2400mu_type = { - .name = "wimax", -}; - -/* - * Probe a i2400m interface and register it - * - * @iface: USB interface to link to - * @id: USB class/subclass/protocol id - * @returns: 0 if ok, < 0 errno code on error. - * - * Alloc a net device, initialize the bus-specific details and then - * calls the bus-generic initialization routine. That will register - * the wimax and netdev devices, upload the firmware [using - * _bus_bm_*()], call _bus_dev_start() to finalize the setup of the - * communication with the device and then will start to talk to it to - * finnish setting it up. - */ -static -int i2400mu_probe(struct usb_interface *iface, - const struct usb_device_id *id) -{ - int result; - struct net_device *net_dev; - struct device *dev = &iface->dev; - struct i2400m *i2400m; - struct i2400mu *i2400mu; - struct usb_device *usb_dev = interface_to_usbdev(iface); - - if (iface->cur_altsetting->desc.bNumEndpoints < 4) - return -ENODEV; - - if (usb_dev->speed != USB_SPEED_HIGH) - dev_err(dev, "device not connected as high speed\n"); - - /* Allocate instance [calls i2400m_netdev_setup() on it]. */ - result = -ENOMEM; - net_dev = alloc_netdev(sizeof(*i2400mu), "wmx%d", NET_NAME_UNKNOWN, - i2400mu_netdev_setup); - if (net_dev == NULL) { - dev_err(dev, "no memory for network device instance\n"); - goto error_alloc_netdev; - } - SET_NETDEV_DEV(net_dev, dev); - SET_NETDEV_DEVTYPE(net_dev, &i2400mu_type); - i2400m = net_dev_to_i2400m(net_dev); - i2400mu = container_of(i2400m, struct i2400mu, i2400m); - i2400m->wimax_dev.net_dev = net_dev; - i2400mu->usb_dev = usb_get_dev(usb_dev); - i2400mu->usb_iface = iface; - usb_set_intfdata(iface, i2400mu); - - i2400m->bus_tx_block_size = I2400MU_BLK_SIZE; - /* - * Room required in the Tx queue for USB message to accommodate - * a smallest payload while allocating header space is 16 bytes. - * Adding this room for the new tx message increases the - * possibilities of including any payload with size <= 16 bytes. - */ - i2400m->bus_tx_room_min = I2400MU_BLK_SIZE; - i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX; - i2400m->bus_setup = NULL; - i2400m->bus_dev_start = i2400mu_bus_dev_start; - i2400m->bus_dev_stop = i2400mu_bus_dev_stop; - i2400m->bus_release = NULL; - i2400m->bus_tx_kick = i2400mu_bus_tx_kick; - i2400m->bus_reset = i2400mu_bus_reset; - i2400m->bus_bm_retries = I2400M_USB_BOOT_RETRIES; - i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; - i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; - i2400m->bus_bm_mac_addr_impaired = 0; - - switch (id->idProduct) { - case USB_DEVICE_ID_I6050: - case USB_DEVICE_ID_I6050_2: - case USB_DEVICE_ID_I6150: - case USB_DEVICE_ID_I6150_2: - case USB_DEVICE_ID_I6150_3: - case USB_DEVICE_ID_I6250: - i2400mu->i6050 = 1; - break; - default: - break; - } - - if (i2400mu->i6050) { - i2400m->bus_fw_names = i2400mu_bus_fw_names_6050; - i2400mu->endpoint_cfg.bulk_out = 0; - i2400mu->endpoint_cfg.notification = 3; - i2400mu->endpoint_cfg.reset_cold = 2; - i2400mu->endpoint_cfg.bulk_in = 1; - } else { - i2400m->bus_fw_names = i2400mu_bus_fw_names_5x50; - i2400mu->endpoint_cfg.bulk_out = 0; - i2400mu->endpoint_cfg.notification = 1; - i2400mu->endpoint_cfg.reset_cold = 2; - i2400mu->endpoint_cfg.bulk_in = 3; - } -#ifdef CONFIG_PM - iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */ - device_init_wakeup(dev, 1); - pm_runtime_set_autosuspend_delay(&usb_dev->dev, 15000); - usb_enable_autosuspend(usb_dev); -#endif - - result = i2400m_setup(i2400m, I2400M_BRI_MAC_REINIT); - if (result < 0) { - dev_err(dev, "cannot setup device: %d\n", result); - goto error_setup; - } - i2400mu_debugfs_add(i2400mu); - return 0; - -error_setup: - usb_set_intfdata(iface, NULL); - usb_put_dev(i2400mu->usb_dev); - free_netdev(net_dev); -error_alloc_netdev: - return result; -} - - -/* - * Disconnect a i2400m from the system. - * - * i2400m_stop() has been called before, so al the rx and tx contexts - * have been taken down already. Make sure the queue is stopped, - * unregister netdev and i2400m, free and kill. - */ -static -void i2400mu_disconnect(struct usb_interface *iface) -{ - struct i2400mu *i2400mu = usb_get_intfdata(iface); - struct i2400m *i2400m = &i2400mu->i2400m; - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - struct device *dev = &iface->dev; - - d_fnstart(3, dev, "(iface %p i2400m %p)\n", iface, i2400m); - - debugfs_remove_recursive(i2400mu->debugfs_dentry); - i2400m_release(i2400m); - usb_set_intfdata(iface, NULL); - usb_put_dev(i2400mu->usb_dev); - free_netdev(net_dev); - d_fnend(3, dev, "(iface %p i2400m %p) = void\n", iface, i2400m); -} - - -/* - * Get the device ready for USB port or system standby and hibernation - * - * USB port and system standby are handled the same. - * - * When the system hibernates, the USB device is powered down and then - * up, so we don't really have to do much here, as it will be seen as - * a reconnect. Still for simplicity we consider this case the same as - * suspend, so that the device has a chance to do notify the base - * station (if connected). - * - * So at the end, the three cases require common handling. - * - * If at the time of this call the device's firmware is not loaded, - * nothing has to be done. Note we can be "loose" about not reading - * i2400m->updown under i2400m->init_mutex. If it happens to change - * inmediately, other parts of the call flow will fail and effectively - * catch it. - * - * If the firmware is loaded, we need to: - * - * - tell the device to go into host interface power save mode, wait - * for it to ack - * - * This is quite more interesting than it is; we need to execute a - * command, but this time, we don't want the code in usb-{tx,rx}.c - * to call the usb_autopm_get/put_interface() barriers as it'd - * deadlock, so we need to decrement i2400mu->do_autopm, that acts - * as a poor man's semaphore. Ugly, but it works. - * - * As well, the device might refuse going to sleep for whichever - * reason. In this case we just fail. For system suspend/hibernate, - * we *can't* fail. We check PMSG_IS_AUTO to see if the - * suspend call comes from the USB stack or from the system and act - * in consequence. - * - * - stop the notification endpoint polling - */ -static -int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) -{ - int result = 0; - struct device *dev = &iface->dev; - struct i2400mu *i2400mu = usb_get_intfdata(iface); - unsigned is_autosuspend = 0; - struct i2400m *i2400m = &i2400mu->i2400m; - -#ifdef CONFIG_PM - if (PMSG_IS_AUTO(pm_msg)) - is_autosuspend = 1; -#endif - - d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); - rmb(); /* see i2400m->updown's documentation */ - if (i2400m->updown == 0) - goto no_firmware; - if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { - /* ugh -- the device is connected and this suspend - * request is an autosuspend one (not a system standby - * / hibernate). - * - * The only way the device can go to standby is if the - * link with the base station is in IDLE mode; that - * were the case, we'd be in status - * I2400M_SS_CONNECTED_IDLE. But we are not. - * - * If we *tell* him to go power save now, it'll reset - * as a precautionary measure, so if this is an - * autosuspend thing, say no and it'll come back - * later, when the link is IDLE - */ - result = -EBADF; - d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " - "not entering powersave\n"); - goto error_not_now; - } - d_printf(1, dev, "fw up: entering powersave\n"); - atomic_dec(&i2400mu->do_autopm); - result = i2400m_cmd_enter_powersave(i2400m); - atomic_inc(&i2400mu->do_autopm); - if (result < 0 && !is_autosuspend) { - /* System suspend, can't fail */ - dev_err(dev, "failed to suspend, will reset on resume\n"); - result = 0; - } - if (result < 0) - goto error_enter_powersave; - i2400mu_notification_release(i2400mu); - d_printf(1, dev, "powersave requested\n"); -error_enter_powersave: -error_not_now: -no_firmware: - d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", - iface, pm_msg.event, result); - return result; -} - - -static -int i2400mu_resume(struct usb_interface *iface) -{ - int ret = 0; - struct device *dev = &iface->dev; - struct i2400mu *i2400mu = usb_get_intfdata(iface); - struct i2400m *i2400m = &i2400mu->i2400m; - - d_fnstart(3, dev, "(iface %p)\n", iface); - rmb(); /* see i2400m->updown's documentation */ - if (i2400m->updown == 0) { - d_printf(1, dev, "fw was down, no resume needed\n"); - goto out; - } - d_printf(1, dev, "fw was up, resuming\n"); - i2400mu_notification_setup(i2400mu); - /* USB has flow control, so we don't need to give it time to - * come back; otherwise, we'd use something like a get-state - * command... */ -out: - d_fnend(3, dev, "(iface %p) = %d\n", iface, ret); - return ret; -} - - -static -int i2400mu_reset_resume(struct usb_interface *iface) -{ - int result; - struct device *dev = &iface->dev; - struct i2400mu *i2400mu = usb_get_intfdata(iface); - struct i2400m *i2400m = &i2400mu->i2400m; - - d_fnstart(3, dev, "(iface %p)\n", iface); - result = i2400m_dev_reset_handle(i2400m, "device reset on resume"); - d_fnend(3, dev, "(iface %p) = %d\n", iface, result); - return result < 0 ? result : 0; -} - - -/* - * Another driver or user space is triggering a reset on the device - * which contains the interface passed as an argument. Cease IO and - * save any device state you need to restore. - * - * If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if - * you are in atomic context. - */ -static -int i2400mu_pre_reset(struct usb_interface *iface) -{ - struct i2400mu *i2400mu = usb_get_intfdata(iface); - return i2400m_pre_reset(&i2400mu->i2400m); -} - - -/* - * The reset has completed. Restore any saved device state and begin - * using the device again. - * - * If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if - * you are in atomic context. - */ -static -int i2400mu_post_reset(struct usb_interface *iface) -{ - struct i2400mu *i2400mu = usb_get_intfdata(iface); - return i2400m_post_reset(&i2400mu->i2400m); -} - - -static -struct usb_device_id i2400mu_id_table[] = { - { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) }, - { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) }, - { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150) }, - { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_2) }, - { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_3) }, - { USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) }, - { USB_DEVICE(0x8086, 0x0181) }, - { USB_DEVICE(0x8086, 0x1403) }, - { USB_DEVICE(0x8086, 0x1405) }, - { USB_DEVICE(0x8086, 0x0180) }, - { USB_DEVICE(0x8086, 0x0182) }, - { USB_DEVICE(0x8086, 0x1406) }, - { USB_DEVICE(0x8086, 0x1403) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, i2400mu_id_table); - - -static -struct usb_driver i2400mu_driver = { - .name = KBUILD_MODNAME, - .suspend = i2400mu_suspend, - .resume = i2400mu_resume, - .reset_resume = i2400mu_reset_resume, - .probe = i2400mu_probe, - .disconnect = i2400mu_disconnect, - .pre_reset = i2400mu_pre_reset, - .post_reset = i2400mu_post_reset, - .id_table = i2400mu_id_table, - .supports_autosuspend = 1, -}; - -static -int __init i2400mu_driver_init(void) -{ - d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400mu_debug_params, - "i2400m_usb.debug"); - return usb_register(&i2400mu_driver); -} -module_init(i2400mu_driver_init); - - -static -void __exit i2400mu_driver_exit(void) -{ - usb_deregister(&i2400mu_driver); -} -module_exit(i2400mu_driver_exit); - -MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); -MODULE_DESCRIPTION("Driver for USB based Intel Wireless WiMAX Connection 2400M " - "(5x50 & 6050)"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_5); -MODULE_FIRMWARE(I6050U_FW_FILE_NAME_v1_5); diff --git a/drivers/staging/wimax/id-table.c b/drivers/staging/wimax/id-table.c deleted file mode 100644 index 0e6f4aa87bc91f268dbb0961118563a50ee3ed43..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/id-table.c +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * Mappping of generic netlink family IDs to net devices - * - * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * We assign a single generic netlink family ID to each device (to - * simplify lookup). - * - * We need a way to map family ID to a wimax_dev pointer. - * - * The idea is to use a very simple lookup. Using a netlink attribute - * with (for example) the interface name implies a heavier search over - * all the network devices; seemed kind of a waste given that we know - * we are looking for a WiMAX device and that most systems will have - * just a single WiMAX adapter. - * - * We put all the WiMAX devices in the system in a linked list and - * match the generic link family ID against the list. - * - * By using a linked list, the case of a single adapter in the system - * becomes (almost) no overhead, while still working for many more. If - * it ever goes beyond two, I'll be surprised. - */ -#include <linux/device.h> -#include <net/genetlink.h> -#include <linux/netdevice.h> -#include <linux/list.h> -#include "linux-wimax.h" -#include "wimax-internal.h" - - -#define D_SUBMODULE id_table -#include "debug-levels.h" - - -static DEFINE_SPINLOCK(wimax_id_table_lock); -static struct list_head wimax_id_table = LIST_HEAD_INIT(wimax_id_table); - - -/* - * wimax_id_table_add - add a gennetlink familiy ID / wimax_dev mapping - * - * @wimax_dev: WiMAX device descriptor to associate to the Generic - * Netlink family ID. - * - * Look for an empty spot in the ID table; if none found, double the - * table's size and get the first spot. - */ -void wimax_id_table_add(struct wimax_dev *wimax_dev) -{ - d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev); - spin_lock(&wimax_id_table_lock); - list_add(&wimax_dev->id_table_node, &wimax_id_table); - spin_unlock(&wimax_id_table_lock); - d_fnend(3, NULL, "(wimax_dev %p)\n", wimax_dev); -} - - -/* - * wimax_get_netdev_by_info - lookup a wimax_dev from the gennetlink info - * - * The generic netlink family ID has been filled out in the - * nlmsghdr->nlmsg_type field, so we pull it from there, look it up in - * the mapping table and reference the wimax_dev. - * - * When done, the reference should be dropped with - * 'dev_put(wimax_dev->net_dev)'. - */ -struct wimax_dev *wimax_dev_get_by_genl_info( - struct genl_info *info, int ifindex) -{ - struct wimax_dev *wimax_dev = NULL; - - d_fnstart(3, NULL, "(info %p ifindex %d)\n", info, ifindex); - spin_lock(&wimax_id_table_lock); - list_for_each_entry(wimax_dev, &wimax_id_table, id_table_node) { - if (wimax_dev->net_dev->ifindex == ifindex) { - dev_hold(wimax_dev->net_dev); - goto found; - } - } - wimax_dev = NULL; - d_printf(1, NULL, "wimax: no devices found with ifindex %d\n", - ifindex); -found: - spin_unlock(&wimax_id_table_lock); - d_fnend(3, NULL, "(info %p ifindex %d) = %p\n", - info, ifindex, wimax_dev); - return wimax_dev; -} - - -/* - * wimax_id_table_rm - Remove a gennetlink familiy ID / wimax_dev mapping - * - * @id: family ID to remove from the table - */ -void wimax_id_table_rm(struct wimax_dev *wimax_dev) -{ - spin_lock(&wimax_id_table_lock); - list_del_init(&wimax_dev->id_table_node); - spin_unlock(&wimax_id_table_lock); -} - - -/* - * Release the gennetlink family id / mapping table - * - * On debug, verify that the table is empty upon removal. We want the - * code always compiled, to ensure it doesn't bit rot. It will be - * compiled out if CONFIG_BUG is disabled. - */ -void wimax_id_table_release(void) -{ - struct wimax_dev *wimax_dev; - -#ifndef CONFIG_BUG - return; -#endif - spin_lock(&wimax_id_table_lock); - list_for_each_entry(wimax_dev, &wimax_id_table, id_table_node) { - pr_err("BUG: %s wimax_dev %p ifindex %d not cleared\n", - __func__, wimax_dev, wimax_dev->net_dev->ifindex); - WARN_ON(1); - } - spin_unlock(&wimax_id_table_lock); -} diff --git a/drivers/staging/wimax/linux-wimax-debug.h b/drivers/staging/wimax/linux-wimax-debug.h deleted file mode 100644 index 5b5ec405143b87a061f7073bccb15160d5a5b8b8..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/linux-wimax-debug.h +++ /dev/null @@ -1,491 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Linux WiMAX - * Collection of tools to manage debug operations. - * - * Copyright (C) 2005-2007 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * Don't #include this file directly, read on! - * - * EXECUTING DEBUGGING ACTIONS OR NOT - * - * The main thing this framework provides is decission power to take a - * debug action (like printing a message) if the current debug level - * allows it. - * - * The decission power is at two levels: at compile-time (what does - * not make it is compiled out) and at run-time. The run-time - * selection is done per-submodule (as they are declared by the user - * of the framework). - * - * A call to d_test(L) (L being the target debug level) returns true - * if the action should be taken because the current debug levels - * allow it (both compile and run time). - * - * It follows that a call to d_test() that can be determined to be - * always false at compile time will get the code depending on it - * compiled out by optimization. - * - * DEBUG LEVELS - * - * It is up to the caller to define how much a debugging level is. - * - * Convention sets 0 as "no debug" (so an action marked as debug level 0 - * will always be taken). The increasing debug levels are used for - * increased verbosity. - * - * USAGE - * - * Group the code in modules and submodules inside each module [which - * in most cases maps to Linux modules and .c files that compose - * those]. - * - * For each module, there is: - * - * - a MODULENAME (single word, legal C identifier) - * - * - a debug-levels.h header file that declares the list of - * submodules and that is included by all .c files that use - * the debugging tools. The file name can be anything. - * - * - some (optional) .c code to manipulate the runtime debug levels - * through debugfs. - * - * The debug-levels.h file would look like: - * - * #ifndef __debug_levels__h__ - * #define __debug_levels__h__ - * - * #define D_MODULENAME modulename - * #define D_MASTER 10 - * - * #include "linux-wimax-debug.h" - * - * enum d_module { - * D_SUBMODULE_DECLARE(submodule_1), - * D_SUBMODULE_DECLARE(submodule_2), - * ... - * D_SUBMODULE_DECLARE(submodule_N) - * }; - * - * #endif - * - * D_MASTER is the maximum compile-time debug level; any debug actions - * above this will be out. D_MODULENAME is the module name (legal C - * identifier), which has to be unique for each module (to avoid - * namespace collisions during linkage). Note those #defines need to - * be done before #including debug.h - * - * We declare N different submodules whose debug level can be - * independently controlled during runtime. - * - * In a .c file of the module (and only in one of them), define the - * following code: - * - * struct d_level D_LEVEL[] = { - * D_SUBMODULE_DEFINE(submodule_1), - * D_SUBMODULE_DEFINE(submodule_2), - * ... - * D_SUBMODULE_DEFINE(submodule_N), - * }; - * size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); - * - * Externs for d_level_MODULENAME and d_level_size_MODULENAME are used - * and declared in this file using the D_LEVEL and D_LEVEL_SIZE macros - * #defined also in this file. - * - * To manipulate from user space the levels, create a debugfs dentry - * and then register each submodule with: - * - * d_level_register_debugfs("PREFIX_", submodule_X, parent); - * - * Where PREFIX_ is a name of your chosing. This will create debugfs - * file with a single numeric value that can be use to tweak it. To - * remove the entires, just use debugfs_remove_recursive() on 'parent'. - * - * NOTE: remember that even if this will show attached to some - * particular instance of a device, the settings are *global*. - * - * On each submodule (for example, .c files), the debug infrastructure - * should be included like this: - * - * #define D_SUBMODULE submodule_x // matches one in debug-levels.h - * #include "debug-levels.h" - * - * after #including all your include files. - * - * Now you can use the d_*() macros below [d_test(), d_fnstart(), - * d_fnend(), d_printf(), d_dump()]. - * - * If their debug level is greater than D_MASTER, they will be - * compiled out. - * - * If their debug level is lower or equal than D_MASTER but greater - * than the current debug level of their submodule, they'll be - * ignored. - * - * Otherwise, the action will be performed. - */ -#ifndef __debug__h__ -#define __debug__h__ - -#include <linux/types.h> -#include <linux/slab.h> - -struct device; - -/* Backend stuff */ - -/* - * Debug backend: generate a message header from a 'struct device' - * - * @head: buffer where to place the header - * @head_size: length of @head - * @dev: pointer to device used to generate a header from. If NULL, - * an empty ("") header is generated. - */ -static inline -void __d_head(char *head, size_t head_size, - struct device *dev) -{ - if (dev == NULL) - head[0] = 0; - else if ((unsigned long)dev < 4096) { - printk(KERN_ERR "E: Corrupt dev %p\n", dev); - WARN_ON(1); - } else - snprintf(head, head_size, "%s %s: ", - dev_driver_string(dev), dev_name(dev)); -} - - -/* - * Debug backend: log some message if debugging is enabled - * - * @l: intended debug level - * @tag: tag to prefix the message with - * @dev: 'struct device' associated to this message - * @f: printf-like format and arguments - * - * Note this is optimized out if it doesn't pass the compile-time - * check; however, it is *always* compiled. This is useful to make - * sure the printf-like formats and variables are always checked and - * they don't get bit rot if you have all the debugging disabled. - */ -#define _d_printf(l, tag, dev, f, a...) \ -do { \ - char head[64]; \ - if (!d_test(l)) \ - break; \ - __d_head(head, sizeof(head), dev); \ - printk(KERN_ERR "%s%s%s: " f, head, __func__, tag, ##a); \ -} while (0) - - -/* - * CPP syntactic sugar to generate A_B like symbol names when one of - * the arguments is a preprocessor #define. - */ -#define __D_PASTE__(varname, modulename) varname##_##modulename -#define __D_PASTE(varname, modulename) (__D_PASTE__(varname, modulename)) -#define _D_SUBMODULE_INDEX(_name) (D_SUBMODULE_DECLARE(_name)) - - -/* - * Store a submodule's runtime debug level and name - */ -struct d_level { - u8 level; - const char *name; -}; - - -/* - * List of available submodules and their debug levels - * - * We call them d_level_MODULENAME and d_level_size_MODULENAME; the - * macros D_LEVEL and D_LEVEL_SIZE contain the name already for - * convenience. - * - * This array and the size are defined on some .c file that is part of - * the current module. - */ -#define D_LEVEL __D_PASTE(d_level, D_MODULENAME) -#define D_LEVEL_SIZE __D_PASTE(d_level_size, D_MODULENAME) - -extern struct d_level D_LEVEL[]; -extern size_t D_LEVEL_SIZE; - - -/* - * Frontend stuff - * - * - * Stuff you need to declare prior to using the actual "debug" actions - * (defined below). - */ - -#ifndef D_MODULENAME -#error D_MODULENAME is not defined in your debug-levels.h file -/** - * D_MODULE - Name of the current module - * - * #define in your module's debug-levels.h, making sure it is - * unique. This has to be a legal C identifier. - */ -#define D_MODULENAME undefined_modulename -#endif - - -#ifndef D_MASTER -#warning D_MASTER not defined, but debug.h included! [see docs] -/** - * D_MASTER - Compile time maximum debug level - * - * #define in your debug-levels.h file to the maximum debug level the - * runtime code will be allowed to have. This allows you to provide a - * main knob. - * - * Anything above that level will be optimized out of the compile. - * - * Defaults to zero (no debug code compiled in). - * - * Maximum one definition per module (at the debug-levels.h file). - */ -#define D_MASTER 0 -#endif - -#ifndef D_SUBMODULE -#error D_SUBMODULE not defined, but debug.h included! [see docs] -/** - * D_SUBMODULE - Name of the current submodule - * - * #define in your submodule .c file before #including debug-levels.h - * to the name of the current submodule as previously declared and - * defined with D_SUBMODULE_DECLARE() (in your module's - * debug-levels.h) and D_SUBMODULE_DEFINE(). - * - * This is used to provide runtime-control over the debug levels. - * - * Maximum one per .c file! Can be shared among different .c files - * (meaning they belong to the same submodule categorization). - */ -#define D_SUBMODULE undefined_module -#endif - - -/** - * D_SUBMODULE_DECLARE - Declare a submodule for runtime debug level control - * - * @_name: name of the submodule, restricted to the chars that make up a - * valid C identifier ([a-zA-Z0-9_]). - * - * Declare in the module's debug-levels.h header file as: - * - * enum d_module { - * D_SUBMODULE_DECLARE(submodule_1), - * D_SUBMODULE_DECLARE(submodule_2), - * D_SUBMODULE_DECLARE(submodule_3), - * }; - * - * Some corresponding .c file needs to have a matching - * D_SUBMODULE_DEFINE(). - */ -#define D_SUBMODULE_DECLARE(_name) __D_SUBMODULE_##_name - - -/** - * D_SUBMODULE_DEFINE - Define a submodule for runtime debug level control - * - * @_name: name of the submodule, restricted to the chars that make up a - * valid C identifier ([a-zA-Z0-9_]). - * - * Use once per module (in some .c file) as: - * - * static - * struct d_level d_level_SUBMODULENAME[] = { - * D_SUBMODULE_DEFINE(submodule_1), - * D_SUBMODULE_DEFINE(submodule_2), - * D_SUBMODULE_DEFINE(submodule_3), - * }; - * size_t d_level_size_SUBDMODULENAME = ARRAY_SIZE(d_level_SUBDMODULENAME); - * - * Matching D_SUBMODULE_DECLARE()s have to be present in a - * debug-levels.h header file. - */ -#define D_SUBMODULE_DEFINE(_name) \ -[__D_SUBMODULE_##_name] = { \ - .level = 0, \ - .name = #_name \ -} - - - -/* The actual "debug" operations */ - - -/** - * d_test - Returns true if debugging should be enabled - * - * @l: intended debug level (unsigned) - * - * If the master debug switch is enabled and the current settings are - * higher or equal to the requested level, then debugging - * output/actions should be enabled. - * - * NOTE: - * - * This needs to be coded so that it can be evaluated in compile - * time; this is why the ugly BUG_ON() is placed in there, so the - * D_MASTER evaluation compiles all out if it is compile-time false. - */ -#define d_test(l) \ -({ \ - unsigned __l = l; /* type enforcer */ \ - (D_MASTER) >= __l \ - && ({ \ - BUG_ON(_D_SUBMODULE_INDEX(D_SUBMODULE) >= D_LEVEL_SIZE);\ - D_LEVEL[_D_SUBMODULE_INDEX(D_SUBMODULE)].level >= __l; \ - }); \ -}) - - -/** - * d_fnstart - log message at function start if debugging enabled - * - * @l: intended debug level - * @_dev: 'struct device' pointer, NULL if none (for context) - * @f: printf-like format and arguments - */ -#define d_fnstart(l, _dev, f, a...) _d_printf(l, " FNSTART", _dev, f, ## a) - - -/** - * d_fnend - log message at function end if debugging enabled - * - * @l: intended debug level - * @_dev: 'struct device' pointer, NULL if none (for context) - * @f: printf-like format and arguments - */ -#define d_fnend(l, _dev, f, a...) _d_printf(l, " FNEND", _dev, f, ## a) - - -/** - * d_printf - log message if debugging enabled - * - * @l: intended debug level - * @_dev: 'struct device' pointer, NULL if none (for context) - * @f: printf-like format and arguments - */ -#define d_printf(l, _dev, f, a...) _d_printf(l, "", _dev, f, ## a) - - -/** - * d_dump - log buffer hex dump if debugging enabled - * - * @l: intended debug level - * @_dev: 'struct device' pointer, NULL if none (for context) - * @f: printf-like format and arguments - */ -#define d_dump(l, dev, ptr, size) \ -do { \ - char head[64]; \ - if (!d_test(l)) \ - break; \ - __d_head(head, sizeof(head), dev); \ - print_hex_dump(KERN_ERR, head, 0, 16, 1, \ - ((void *) ptr), (size), 0); \ -} while (0) - - -/** - * Export a submodule's debug level over debugfs as PREFIXSUBMODULE - * - * @prefix: string to prefix the name with - * @submodule: name of submodule (not a string, just the name) - * @dentry: debugfs parent dentry - * - * For removing, just use debugfs_remove_recursive() on the parent. - */ -#define d_level_register_debugfs(prefix, name, parent) \ -({ \ - debugfs_create_u8( \ - prefix #name, 0600, parent, \ - &(D_LEVEL[__D_SUBMODULE_ ## name].level)); \ -}) - - -static inline -void d_submodule_set(struct d_level *d_level, size_t d_level_size, - const char *submodule, u8 level, const char *tag) -{ - struct d_level *itr, *top; - int index = -1; - - for (itr = d_level, top = itr + d_level_size; itr < top; itr++) { - index++; - if (itr->name == NULL) { - printk(KERN_ERR "%s: itr->name NULL?? (%p, #%d)\n", - tag, itr, index); - continue; - } - if (!strcmp(itr->name, submodule)) { - itr->level = level; - return; - } - } - printk(KERN_ERR "%s: unknown submodule %s\n", tag, submodule); -} - - -/** - * d_parse_params - Parse a string with debug parameters from the - * command line - * - * @d_level: level structure (D_LEVEL) - * @d_level_size: number of items in the level structure - * (D_LEVEL_SIZE). - * @_params: string with the parameters; this is a space (not tab!) - * separated list of NAME:VALUE, where value is the debug level - * and NAME is the name of the submodule. - * @tag: string for error messages (example: MODULE.ARGNAME). - */ -static inline -void d_parse_params(struct d_level *d_level, size_t d_level_size, - const char *_params, const char *tag) -{ - char submodule[130], *params, *params_orig, *token, *colon; - unsigned level, tokens; - - if (_params == NULL) - return; - params_orig = kstrdup(_params, GFP_KERNEL); - params = params_orig; - while (1) { - token = strsep(¶ms, " "); - if (token == NULL) - break; - if (*token == '\0') /* eat joint spaces */ - continue; - /* kernel's sscanf %s eats until whitespace, so we - * replace : by \n so it doesn't get eaten later by - * strsep */ - colon = strchr(token, ':'); - if (colon != NULL) - *colon = '\n'; - tokens = sscanf(token, "%s\n%u", submodule, &level); - if (colon != NULL) - *colon = ':'; /* set back, for error messages */ - if (tokens == 2) - d_submodule_set(d_level, d_level_size, - submodule, level, tag); - else - printk(KERN_ERR "%s: can't parse '%s' as a " - "SUBMODULE:LEVEL (%d tokens)\n", - tag, token, tokens); - } - kfree(params_orig); -} - -#endif /* #ifndef __debug__h__ */ diff --git a/drivers/staging/wimax/linux-wimax.h b/drivers/staging/wimax/linux-wimax.h deleted file mode 100644 index 9f6b77af2f6ddf547cb133ca8994aab9d63c0034..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/linux-wimax.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Linux WiMax - * API for user space - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * - * This file declares the user/kernel protocol that is spoken over - * Generic Netlink, as well as any type declaration that is to be used - * by kernel and user space. - * - * It is intended for user space to clone it verbatim to use it as a - * primary reference for definitions. - * - * Stuff intended for kernel usage as well as full protocol and stack - * documentation is rooted in include/net/wimax.h. - */ - -#ifndef __LINUX__WIMAX_H__ -#define __LINUX__WIMAX_H__ - -#include <linux/types.h> - -enum { - /** - * Version of the interface (unsigned decimal, MMm, max 25.5) - * M - Major: change if removing or modifying an existing call. - * m - minor: change when adding a new call - */ - WIMAX_GNL_VERSION = 01, - /* Generic NetLink attributes */ - WIMAX_GNL_ATTR_INVALID = 0x00, - WIMAX_GNL_ATTR_MAX = 10, -}; - - -/* - * Generic NetLink operations - * - * Most of these map to an API call; _OP_ stands for operation, _RP_ - * for reply and _RE_ for report (aka: signal). - */ -enum { - WIMAX_GNL_OP_MSG_FROM_USER, /* User to kernel message */ - WIMAX_GNL_OP_MSG_TO_USER, /* Kernel to user message */ - WIMAX_GNL_OP_RFKILL, /* Run wimax_rfkill() */ - WIMAX_GNL_OP_RESET, /* Run wimax_rfkill() */ - WIMAX_GNL_RE_STATE_CHANGE, /* Report: status change */ - WIMAX_GNL_OP_STATE_GET, /* Request for current state */ -}; - - -/* Message from user / to user */ -enum { - WIMAX_GNL_MSG_IFIDX = 1, - WIMAX_GNL_MSG_PIPE_NAME, - WIMAX_GNL_MSG_DATA, -}; - - -/* - * wimax_rfkill() - * - * The state of the radio (ON/OFF) is mapped to the rfkill subsystem's - * switch state (DISABLED/ENABLED). - */ -enum wimax_rf_state { - WIMAX_RF_OFF = 0, /* Radio is off, rfkill on/enabled */ - WIMAX_RF_ON = 1, /* Radio is on, rfkill off/disabled */ - WIMAX_RF_QUERY = 2, -}; - -/* Attributes */ -enum { - WIMAX_GNL_RFKILL_IFIDX = 1, - WIMAX_GNL_RFKILL_STATE, -}; - - -/* Attributes for wimax_reset() */ -enum { - WIMAX_GNL_RESET_IFIDX = 1, -}; - -/* Attributes for wimax_state_get() */ -enum { - WIMAX_GNL_STGET_IFIDX = 1, -}; - -/* - * Attributes for the Report State Change - * - * For now we just have the old and new states; new attributes might - * be added later on. - */ -enum { - WIMAX_GNL_STCH_IFIDX = 1, - WIMAX_GNL_STCH_STATE_OLD, - WIMAX_GNL_STCH_STATE_NEW, -}; - - -/** - * enum wimax_st - The different states of a WiMAX device - * @__WIMAX_ST_NULL: The device structure has been allocated and zeroed, - * but still wimax_dev_add() hasn't been called. There is no state. - * - * @WIMAX_ST_DOWN: The device has been registered with the WiMAX and - * networking stacks, but it is not initialized (normally that is - * done with 'ifconfig DEV up' [or equivalent], which can upload - * firmware and enable communications with the device). - * In this state, the device is powered down and using as less - * power as possible. - * This state is the default after a call to wimax_dev_add(). It - * is ok to have drivers move directly to %WIMAX_ST_UNINITIALIZED - * or %WIMAX_ST_RADIO_OFF in _probe() after the call to - * wimax_dev_add(). - * It is recommended that the driver leaves this state when - * calling 'ifconfig DEV up' and enters it back on 'ifconfig DEV - * down'. - * - * @__WIMAX_ST_QUIESCING: The device is being torn down, so no API - * operations are allowed to proceed except the ones needed to - * complete the device clean up process. - * - * @WIMAX_ST_UNINITIALIZED: [optional] Communication with the device - * is setup, but the device still requires some configuration - * before being operational. - * Some WiMAX API calls might work. - * - * @WIMAX_ST_RADIO_OFF: The device is fully up; radio is off (wether - * by hardware or software switches). - * It is recommended to always leave the device in this state - * after initialization. - * - * @WIMAX_ST_READY: The device is fully up and radio is on. - * - * @WIMAX_ST_SCANNING: [optional] The device has been instructed to - * scan. In this state, the device cannot be actively connected to - * a network. - * - * @WIMAX_ST_CONNECTING: The device is connecting to a network. This - * state exists because in some devices, the connect process can - * include a number of negotiations between user space, kernel - * space and the device. User space needs to know what the device - * is doing. If the connect sequence in a device is atomic and - * fast, the device can transition directly to CONNECTED - * - * @WIMAX_ST_CONNECTED: The device is connected to a network. - * - * @__WIMAX_ST_INVALID: This is an invalid state used to mark the - * maximum numeric value of states. - * - * Description: - * - * Transitions from one state to another one are atomic and can only - * be caused in kernel space with wimax_state_change(). To read the - * state, use wimax_state_get(). - * - * States starting with __ are internal and shall not be used or - * referred to by drivers or userspace. They look ugly, but that's the - * point -- if any use is made non-internal to the stack, it is easier - * to catch on review. - * - * All API operations [with well defined exceptions] will take the - * device mutex before starting and then check the state. If the state - * is %__WIMAX_ST_NULL, %WIMAX_ST_DOWN, %WIMAX_ST_UNINITIALIZED or - * %__WIMAX_ST_QUIESCING, it will drop the lock and quit with - * -%EINVAL, -%ENOMEDIUM, -%ENOTCONN or -%ESHUTDOWN. - * - * The order of the definitions is important, so we can do numerical - * comparisons (eg: < %WIMAX_ST_RADIO_OFF means the device is not ready - * to operate). - */ -/* - * The allowed state transitions are described in the table below - * (states in rows can go to states in columns where there is an X): - * - * UNINI RADIO READY SCAN CONNEC CONNEC - * NULL DOWN QUIESCING TIALIZED OFF NING TING TED - * NULL - x - * DOWN - x x x - * QUIESCING x - - * UNINITIALIZED x - x - * RADIO_OFF x - x - * READY x x - x x x - * SCANNING x x x - x x - * CONNECTING x x x x - x - * CONNECTED x x x - - * - * This table not available in kernel-doc because the formatting messes it up. - */ - enum wimax_st { - __WIMAX_ST_NULL = 0, - WIMAX_ST_DOWN, - __WIMAX_ST_QUIESCING, - WIMAX_ST_UNINITIALIZED, - WIMAX_ST_RADIO_OFF, - WIMAX_ST_READY, - WIMAX_ST_SCANNING, - WIMAX_ST_CONNECTING, - WIMAX_ST_CONNECTED, - __WIMAX_ST_INVALID /* Always keep last */ -}; - - -#endif /* #ifndef __LINUX__WIMAX_H__ */ diff --git a/drivers/staging/wimax/net-wimax.h b/drivers/staging/wimax/net-wimax.h deleted file mode 100644 index f578e345e2bda86d9c1f487a9c36aad4585d82bc..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/net-wimax.h +++ /dev/null @@ -1,503 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Linux WiMAX - * Kernel space API for accessing WiMAX devices - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * The WiMAX stack provides an API for controlling and managing the - * system's WiMAX devices. This API affects the control plane; the - * data plane is accessed via the network stack (netdev). - * - * Parts of the WiMAX stack API and notifications are exported to - * user space via Generic Netlink. In user space, libwimax (part of - * the wimax-tools package) provides a shim layer for accessing those - * calls. - * - * The API is standarized for all WiMAX devices and different drivers - * implement the backend support for it. However, device-specific - * messaging pipes are provided that can be used to issue commands and - * receive notifications in free form. - * - * Currently the messaging pipes are the only means of control as it - * is not known (due to the lack of more devices in the market) what - * will be a good abstraction layer. Expect this to change as more - * devices show in the market. This API is designed to be growable in - * order to address this problem. - * - * USAGE - * - * Embed a `struct wimax_dev` at the beginning of the device's - * private structure, initialize and register it. For details, see - * `struct wimax_dev`s documentation. - * - * Once this is done, wimax-tools's libwimaxll can be used to - * communicate with the driver from user space. You user space - * application does not have to forcibily use libwimaxll and can talk - * the generic netlink protocol directly if desired. - * - * Remember this is a very low level API that will to provide all of - * WiMAX features. Other daemons and services running in user space - * are the expected clients of it. They offer a higher level API that - * applications should use (an example of this is the Intel's WiMAX - * Network Service for the i2400m). - * - * DESIGN - * - * Although not set on final stone, this very basic interface is - * mostly completed. Remember this is meant to grow as new common - * operations are decided upon. New operations will be added to the - * interface, intent being on keeping backwards compatibility as much - * as possible. - * - * This layer implements a set of calls to control a WiMAX device, - * exposing a frontend to the rest of the kernel and user space (via - * generic netlink) and a backend implementation in the driver through - * function pointers. - * - * WiMAX devices have a state, and a kernel-only API allows the - * drivers to manipulate that state. State transitions are atomic, and - * only some of them are allowed (see `enum wimax_st`). - * - * Most API calls will set the state automatically; in most cases - * drivers have to only report state changes due to external - * conditions. - * - * All API operations are 'atomic', serialized through a mutex in the - * `struct wimax_dev`. - * - * EXPORTING TO USER SPACE THROUGH GENERIC NETLINK - * - * The API is exported to user space using generic netlink (other - * methods can be added as needed). - * - * There is a Generic Netlink Family named "WiMAX", where interfaces - * supporting the WiMAX interface receive commands and broadcast their - * signals over a multicast group named "msg". - * - * Mapping to the source/destination interface is done by an interface - * index attribute. - * - * For user-to-kernel traffic (commands) we use a function call - * marshalling mechanism, where a message X with attributes A, B, C - * sent from user space to kernel space means executing the WiMAX API - * call wimax_X(A, B, C), sending the results back as a message. - * - * Kernel-to-user (notifications or signals) communication is sent - * over multicast groups. This allows to have multiple applications - * monitoring them. - * - * Each command/signal gets assigned it's own attribute policy. This - * way the validator will verify that all the attributes in there are - * only the ones that should be for each command/signal. Thing of an - * attribute mapping to a type+argumentname for each command/signal. - * - * If we had a single policy for *all* commands/signals, after running - * the validator we'd have to check "does this attribute belong in - * here"? for each one. It can be done manually, but it's just easier - * to have the validator do that job with multiple policies. As well, - * it makes it easier to later expand each command/signal signature - * without affecting others and keeping the namespace more or less - * sane. Not that it is too complicated, but it makes it even easier. - * - * No state information is maintained in the kernel for each user - * space connection (the connection is stateless). - * - * TESTING FOR THE INTERFACE AND VERSIONING - * - * If network interface X is a WiMAX device, there will be a Generic - * Netlink family named "WiMAX X" and the device will present a - * "wimax" directory in it's network sysfs directory - * (/sys/class/net/DEVICE/wimax) [used by HAL]. - * - * The inexistence of any of these means the device does not support - * this WiMAX API. - * - * By querying the generic netlink controller, versioning information - * and the multicast groups available can be found. Applications using - * the interface can either rely on that or use the generic netlink - * controller to figure out which generic netlink commands/signals are - * supported. - * - * NOTE: this versioning is a last resort to avoid hard - * incompatibilities. It is the intention of the design of this - * stack not to introduce backward incompatible changes. - * - * The version code has to fit in one byte (restrictions imposed by - * generic netlink); we use `version / 10` for the major version and - * `version % 10` for the minor. This gives 9 minors for each major - * and 25 majors. - * - * The version change protocol is as follow: - * - * - Major versions: needs to be increased if an existing message/API - * call is changed or removed. Doesn't need to be changed if a new - * message is added. - * - * - Minor version: needs to be increased if new messages/API calls are - * being added or some other consideration that doesn't impact the - * user-kernel interface too much (like some kind of bug fix) and - * that is kind of left up in the air to common sense. - * - * User space code should not try to work if the major version it was - * compiled for differs from what the kernel offers. As well, if the - * minor version of the kernel interface is lower than the one user - * space is expecting (the one it was compiled for), the kernel - * might be missing API calls; user space shall be ready to handle - * said condition. Use the generic netlink controller operations to - * find which ones are supported and which not. - * - * libwimaxll:wimaxll_open() takes care of checking versions. - * - * THE OPERATIONS: - * - * Each operation is defined in its on file (drivers/net/wimax/op-*.c) - * for clarity. The parts needed for an operation are: - * - * - a function pointer in `struct wimax_dev`: optional, as the - * operation might be implemented by the stack and not by the - * driver. - * - * All function pointers are named wimax_dev->op_*(), and drivers - * must implement them except where noted otherwise. - * - * - When exported to user space, a `struct nla_policy` to define the - * attributes of the generic netlink command and a `struct genl_ops` - * to define the operation. - * - * All the declarations for the operation codes (WIMAX_GNL_OP_<NAME>) - * and generic netlink attributes (WIMAX_GNL_<NAME>_*) are declared in - * include/linux/wimax.h; this file is intended to be cloned by user - * space to gain access to those declarations. - * - * A few caveats to remember: - * - * - Need to define attribute numbers starting in 1; otherwise it - * fails. - * - * - the `struct genl_family` requires a maximum attribute id; when - * defining the `struct nla_policy` for each message, it has to have - * an array size of WIMAX_GNL_ATTR_MAX+1. - * - * The op_*() function pointers will not be called if the wimax_dev is - * in a state <= %WIMAX_ST_UNINITIALIZED. The exception is: - * - * - op_reset: can be called at any time after wimax_dev_add() has - * been called. - * - * THE PIPE INTERFACE: - * - * This interface is kept intentionally simple. The driver can send - * and receive free-form messages to/from user space through a - * pipe. See drivers/net/wimax/op-msg.c for details. - * - * The kernel-to-user messages are sent with - * wimax_msg(). user-to-kernel messages are delivered via - * wimax_dev->op_msg_from_user(). - * - * RFKILL: - * - * RFKILL support is built into the wimax_dev layer; the driver just - * needs to call wimax_report_rfkill_{hw,sw}() to inform of changes in - * the hardware or software RF kill switches. When the stack wants to - * turn the radio off, it will call wimax_dev->op_rfkill_sw_toggle(), - * which the driver implements. - * - * User space can set the software RF Kill switch by calling - * wimax_rfkill(). - * - * The code for now only supports devices that don't require polling; - * If the device needs to be polled, create a self-rearming delayed - * work struct for polling or look into adding polled support to the - * WiMAX stack. - * - * When initializing the hardware (_probe), after calling - * wimax_dev_add(), query the device for it's RF Kill switches status - * and feed it back to the WiMAX stack using - * wimax_report_rfkill_{hw,sw}(). If any switch is missing, always - * report it as ON. - * - * NOTE: the wimax stack uses an inverted terminology to that of the - * RFKILL subsystem: - * - * - ON: radio is ON, RFKILL is DISABLED or OFF. - * - OFF: radio is OFF, RFKILL is ENABLED or ON. - * - * MISCELLANEOUS OPS: - * - * wimax_reset() can be used to reset the device to power on state; by - * default it issues a warm reset that maintains the same device - * node. If that is not possible, it falls back to a cold reset - * (device reconnect). The driver implements the backend to this - * through wimax_dev->op_reset(). - */ - -#ifndef __NET__WIMAX_H__ -#define __NET__WIMAX_H__ - -#include "linux-wimax.h" -#include <net/genetlink.h> -#include <linux/netdevice.h> - -struct net_device; -struct genl_info; -struct wimax_dev; - -/** - * struct wimax_dev - Generic WiMAX device - * - * @net_dev: [fill] Pointer to the &struct net_device this WiMAX - * device implements. - * - * @op_msg_from_user: [fill] Driver-specific operation to - * handle a raw message from user space to the driver. The - * driver can send messages to user space using with - * wimax_msg_to_user(). - * - * @op_rfkill_sw_toggle: [fill] Driver-specific operation to act on - * userspace (or any other agent) requesting the WiMAX device to - * change the RF Kill software switch (WIMAX_RF_ON or - * WIMAX_RF_OFF). - * If such hardware support is not present, it is assumed the - * radio cannot be switched off and it is always on (and the stack - * will error out when trying to switch it off). In such case, - * this function pointer can be left as NULL. - * - * @op_reset: [fill] Driver specific operation to reset the - * device. - * This operation should always attempt first a warm reset that - * does not disconnect the device from the bus and return 0. - * If that fails, it should resort to some sort of cold or bus - * reset (even if it implies a bus disconnection and device - * disappearance). In that case, -ENODEV should be returned to - * indicate the device is gone. - * This operation has to be synchronous, and return only when the - * reset is complete. In case of having had to resort to bus/cold - * reset implying a device disconnection, the call is allowed to - * return immediately. - * NOTE: wimax_dev->mutex is NOT locked when this op is being - * called; however, wimax_dev->mutex_reset IS locked to ensure - * serialization of calls to wimax_reset(). - * See wimax_reset()'s documentation. - * - * @name: [fill] A way to identify this device. We need to register a - * name with many subsystems (rfkill, workqueue creation, etc). - * We can't use the network device name as that - * might change and in some instances we don't know it yet (until - * we don't call register_netdev()). So we generate an unique one - * using the driver name and device bus id, place it here and use - * it across the board. Recommended naming: - * DRIVERNAME-BUSNAME:BUSID (dev->bus->name, dev->bus_id). - * - * @id_table_node: [private] link to the list of wimax devices kept by - * id-table.c. Protected by it's own spinlock. - * - * @mutex: [private] Serializes all concurrent access and execution of - * operations. - * - * @mutex_reset: [private] Serializes reset operations. Needs to be a - * different mutex because as part of the reset operation, the - * driver has to call back into the stack to do things such as - * state change, that require wimax_dev->mutex. - * - * @state: [private] Current state of the WiMAX device. - * - * @rfkill: [private] integration into the RF-Kill infrastructure. - * - * @rf_sw: [private] State of the software radio switch (OFF/ON) - * - * @rf_hw: [private] State of the hardware radio switch (OFF/ON) - * - * @debugfs_dentry: [private] Used to hook up a debugfs entry. This - * shows up in the debugfs root as wimax\:DEVICENAME. - * - * Description: - * This structure defines a common interface to access all WiMAX - * devices from different vendors and provides a common API as well as - * a free-form device-specific messaging channel. - * - * Usage: - * 1. Embed a &struct wimax_dev at *the beginning* the network - * device structure so that netdev_priv() points to it. - * - * 2. memset() it to zero - * - * 3. Initialize with wimax_dev_init(). This will leave the WiMAX - * device in the %__WIMAX_ST_NULL state. - * - * 4. Fill all the fields marked with [fill]; once called - * wimax_dev_add(), those fields CANNOT be modified. - * - * 5. Call wimax_dev_add() *after* registering the network - * device. This will leave the WiMAX device in the %WIMAX_ST_DOWN - * state. - * Protect the driver's net_device->open() against succeeding if - * the wimax device state is lower than %WIMAX_ST_DOWN. - * - * 6. Select when the device is going to be turned on/initialized; - * for example, it could be initialized on 'ifconfig up' (when the - * netdev op 'open()' is called on the driver). - * - * When the device is initialized (at `ifconfig up` time, or right - * after calling wimax_dev_add() from _probe(), make sure the - * following steps are taken - * - * a. Move the device to %WIMAX_ST_UNINITIALIZED. This is needed so - * some API calls that shouldn't work until the device is ready - * can be blocked. - * - * b. Initialize the device. Make sure to turn the SW radio switch - * off and move the device to state %WIMAX_ST_RADIO_OFF when - * done. When just initialized, a device should be left in RADIO - * OFF state until user space devices to turn it on. - * - * c. Query the device for the state of the hardware rfkill switch - * and call wimax_rfkill_report_hw() and wimax_rfkill_report_sw() - * as needed. See below. - * - * wimax_dev_rm() undoes before unregistering the network device. Once - * wimax_dev_add() is called, the driver can get called on the - * wimax_dev->op_* function pointers - * - * CONCURRENCY: - * - * The stack provides a mutex for each device that will disallow API - * calls happening concurrently; thus, op calls into the driver - * through the wimax_dev->op*() function pointers will always be - * serialized and *never* concurrent. - * - * For locking, take wimax_dev->mutex is taken; (most) operations in - * the API have to check for wimax_dev_is_ready() to return 0 before - * continuing (this is done internally). - * - * REFERENCE COUNTING: - * - * The WiMAX device is reference counted by the associated network - * device. The only operation that can be used to reference the device - * is wimax_dev_get_by_genl_info(), and the reference it acquires has - * to be released with dev_put(wimax_dev->net_dev). - * - * RFKILL: - * - * At startup, both HW and SW radio switchess are assumed to be off. - * - * At initialization time [after calling wimax_dev_add()], have the - * driver query the device for the status of the software and hardware - * RF kill switches and call wimax_report_rfkill_hw() and - * wimax_rfkill_report_sw() to indicate their state. If any is - * missing, just call it to indicate it is ON (radio always on). - * - * Whenever the driver detects a change in the state of the RF kill - * switches, it should call wimax_report_rfkill_hw() or - * wimax_report_rfkill_sw() to report it to the stack. - */ -struct wimax_dev { - struct net_device *net_dev; - struct list_head id_table_node; - struct mutex mutex; /* Protects all members and API calls */ - struct mutex mutex_reset; - enum wimax_st state; - - int (*op_msg_from_user)(struct wimax_dev *wimax_dev, - const char *, - const void *, size_t, - const struct genl_info *info); - int (*op_rfkill_sw_toggle)(struct wimax_dev *wimax_dev, - enum wimax_rf_state); - int (*op_reset)(struct wimax_dev *wimax_dev); - - struct rfkill *rfkill; - unsigned int rf_hw; - unsigned int rf_sw; - char name[32]; - - struct dentry *debugfs_dentry; -}; - - - -/* - * WiMAX stack public API for device drivers - * ----------------------------------------- - * - * These functions are not exported to user space. - */ -void wimax_dev_init(struct wimax_dev *); -int wimax_dev_add(struct wimax_dev *, struct net_device *); -void wimax_dev_rm(struct wimax_dev *); - -static inline -struct wimax_dev *net_dev_to_wimax(struct net_device *net_dev) -{ - return netdev_priv(net_dev); -} - -static inline -struct device *wimax_dev_to_dev(struct wimax_dev *wimax_dev) -{ - return wimax_dev->net_dev->dev.parent; -} - -void wimax_state_change(struct wimax_dev *, enum wimax_st); -enum wimax_st wimax_state_get(struct wimax_dev *); - -/* - * Radio Switch state reporting. - * - * enum wimax_rf_state is declared in linux/wimax.h so the exports - * to user space can use it. - */ -void wimax_report_rfkill_hw(struct wimax_dev *, enum wimax_rf_state); -void wimax_report_rfkill_sw(struct wimax_dev *, enum wimax_rf_state); - - -/* - * Free-form messaging to/from user space - * - * Sending a message: - * - * wimax_msg(wimax_dev, pipe_name, buf, buf_size, GFP_KERNEL); - * - * Broken up: - * - * skb = wimax_msg_alloc(wimax_dev, pipe_name, buf_size, GFP_KERNEL); - * ...fill up skb... - * wimax_msg_send(wimax_dev, pipe_name, skb); - * - * Be sure not to modify skb->data in the middle (ie: don't use - * skb_push()/skb_pull()/skb_reserve() on the skb). - * - * "pipe_name" is any string, that can be interpreted as the name of - * the pipe or recipient; the interpretation of it is driver - * specific, so the recipient can multiplex it as wished. It can be - * NULL, it won't be used - an example is using a "diagnostics" tag to - * send diagnostics information that a device-specific diagnostics - * tool would be interested in. - */ -struct sk_buff *wimax_msg_alloc(struct wimax_dev *, const char *, const void *, - size_t, gfp_t); -int wimax_msg_send(struct wimax_dev *, struct sk_buff *); -int wimax_msg(struct wimax_dev *, const char *, const void *, size_t, gfp_t); - -const void *wimax_msg_data_len(struct sk_buff *, size_t *); -const void *wimax_msg_data(struct sk_buff *); -ssize_t wimax_msg_len(struct sk_buff *); - - -/* - * WiMAX stack user space API - * -------------------------- - * - * This API is what gets exported to user space for general - * operations. As well, they can be called from within the kernel, - * (with a properly referenced `struct wimax_dev`). - * - * Properly referenced means: the 'struct net_device' that embeds the - * device's control structure and (as such) the 'struct wimax_dev' is - * referenced by the caller. - */ -int wimax_rfkill(struct wimax_dev *, enum wimax_rf_state); -int wimax_reset(struct wimax_dev *); - -#endif /* #ifndef __NET__WIMAX_H__ */ diff --git a/drivers/staging/wimax/op-msg.c b/drivers/staging/wimax/op-msg.c deleted file mode 100644 index e20ac7d84e82ad1ff4fdcb6b08b9a4ed4b67cce7..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/op-msg.c +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * Generic messaging interface between userspace and driver/device - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This implements a direct communication channel between user space and - * the driver/device, by which free form messages can be sent back and - * forth. - * - * This is intended for device-specific features, vendor quirks, etc. - * - * See include/net/wimax.h - * - * GENERIC NETLINK ENCODING AND CAPACITY - * - * A destination "pipe name" is added to each message; it is up to the - * drivers to assign or use those names (if using them at all). - * - * Messages are encoded as a binary netlink attribute using nla_put() - * using type NLA_UNSPEC (as some versions of libnl still in - * deployment don't yet understand NLA_BINARY). - * - * The maximum capacity of this transport is PAGESIZE per message (so - * the actual payload will be bit smaller depending on the - * netlink/generic netlink attributes and headers). - * - * RECEPTION OF MESSAGES - * - * When a message is received from user space, it is passed verbatim - * to the driver calling wimax_dev->op_msg_from_user(). The return - * value from this function is passed back to user space as an ack - * over the generic netlink protocol. - * - * The stack doesn't do any processing or interpretation of these - * messages. - * - * SENDING MESSAGES - * - * Messages can be sent with wimax_msg(). - * - * If the message delivery needs to happen on a different context to - * that of its creation, wimax_msg_alloc() can be used to get a - * pointer to the message that can be delivered later on with - * wimax_msg_send(). - * - * ROADMAP - * - * wimax_gnl_doit_msg_from_user() Process a message from user space - * wimax_dev_get_by_genl_info() - * wimax_dev->op_msg_from_user() Delivery of message to the driver - * - * wimax_msg() Send a message to user space - * wimax_msg_alloc() - * wimax_msg_send() - */ -#include <linux/device.h> -#include <linux/slab.h> -#include <net/genetlink.h> -#include <linux/netdevice.h> -#include "linux-wimax.h" -#include <linux/security.h> -#include <linux/export.h> -#include "wimax-internal.h" - - -#define D_SUBMODULE op_msg -#include "debug-levels.h" - - -/** - * wimax_msg_alloc - Create a new skb for sending a message to userspace - * - * @wimax_dev: WiMAX device descriptor - * @pipe_name: "named pipe" the message will be sent to - * @msg: pointer to the message data to send - * @size: size of the message to send (in bytes), including the header. - * @gfp_flags: flags for memory allocation. - * - * Returns: %0 if ok, negative errno code on error - * - * Description: - * - * Allocates an skb that will contain the message to send to user - * space over the messaging pipe and initializes it, copying the - * payload. - * - * Once this call is done, you can deliver it with - * wimax_msg_send(). - * - * IMPORTANT: - * - * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as - * wimax_msg_send() depends on skb->data being placed at the - * beginning of the user message. - * - * Unlike other WiMAX stack calls, this call can be used way early, - * even before wimax_dev_add() is called, as long as the - * wimax_dev->net_dev pointer is set to point to a proper - * net_dev. This is so that drivers can use it early in case they need - * to send stuff around or communicate with user space. - */ -struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, - const char *pipe_name, - const void *msg, size_t size, - gfp_t gfp_flags) -{ - int result; - struct device *dev = wimax_dev_to_dev(wimax_dev); - size_t msg_size; - void *genl_msg; - struct sk_buff *skb; - - msg_size = nla_total_size(size) - + nla_total_size(sizeof(u32)) - + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0); - result = -ENOMEM; - skb = genlmsg_new(msg_size, gfp_flags); - if (skb == NULL) - goto error_new; - genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family, - 0, WIMAX_GNL_OP_MSG_TO_USER); - if (genl_msg == NULL) { - dev_err(dev, "no memory to create generic netlink message\n"); - goto error_genlmsg_put; - } - result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX, - wimax_dev->net_dev->ifindex); - if (result < 0) { - dev_err(dev, "no memory to add ifindex attribute\n"); - goto error_nla_put; - } - if (pipe_name) { - result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME, - pipe_name); - if (result < 0) { - dev_err(dev, "no memory to add pipe_name attribute\n"); - goto error_nla_put; - } - } - result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg); - if (result < 0) { - dev_err(dev, "no memory to add payload (msg %p size %zu) in " - "attribute: %d\n", msg, size, result); - goto error_nla_put; - } - genlmsg_end(skb, genl_msg); - return skb; - -error_nla_put: -error_genlmsg_put: -error_new: - nlmsg_free(skb); - return ERR_PTR(result); -} -EXPORT_SYMBOL_GPL(wimax_msg_alloc); - - -/** - * wimax_msg_data_len - Return a pointer and size of a message's payload - * - * @msg: Pointer to a message created with wimax_msg_alloc() - * @size: Pointer to where to store the message's size - * - * Returns the pointer to the message data. - */ -const void *wimax_msg_data_len(struct sk_buff *msg, size_t *size) -{ - struct nlmsghdr *nlh = (void *) msg->head; - struct nlattr *nla; - - nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), - WIMAX_GNL_MSG_DATA); - if (nla == NULL) { - pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); - return NULL; - } - *size = nla_len(nla); - return nla_data(nla); -} -EXPORT_SYMBOL_GPL(wimax_msg_data_len); - - -/** - * wimax_msg_data - Return a pointer to a message's payload - * - * @msg: Pointer to a message created with wimax_msg_alloc() - */ -const void *wimax_msg_data(struct sk_buff *msg) -{ - struct nlmsghdr *nlh = (void *) msg->head; - struct nlattr *nla; - - nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), - WIMAX_GNL_MSG_DATA); - if (nla == NULL) { - pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); - return NULL; - } - return nla_data(nla); -} -EXPORT_SYMBOL_GPL(wimax_msg_data); - - -/** - * wimax_msg_len - Return a message's payload length - * - * @msg: Pointer to a message created with wimax_msg_alloc() - */ -ssize_t wimax_msg_len(struct sk_buff *msg) -{ - struct nlmsghdr *nlh = (void *) msg->head; - struct nlattr *nla; - - nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), - WIMAX_GNL_MSG_DATA); - if (nla == NULL) { - pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); - return -EINVAL; - } - return nla_len(nla); -} -EXPORT_SYMBOL_GPL(wimax_msg_len); - - -/** - * wimax_msg_send - Send a pre-allocated message to user space - * - * @wimax_dev: WiMAX device descriptor - * - * @skb: &struct sk_buff returned by wimax_msg_alloc(). Note the - * ownership of @skb is transferred to this function. - * - * Returns: 0 if ok, < 0 errno code on error - * - * Description: - * - * Sends a free-form message that was preallocated with - * wimax_msg_alloc() and filled up. - * - * Assumes that once you pass an skb to this function for sending, it - * owns it and will release it when done (on success). - * - * IMPORTANT: - * - * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as - * wimax_msg_send() depends on skb->data being placed at the - * beginning of the user message. - * - * Unlike other WiMAX stack calls, this call can be used way early, - * even before wimax_dev_add() is called, as long as the - * wimax_dev->net_dev pointer is set to point to a proper - * net_dev. This is so that drivers can use it early in case they need - * to send stuff around or communicate with user space. - */ -int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) -{ - struct device *dev = wimax_dev_to_dev(wimax_dev); - void *msg = skb->data; - size_t size = skb->len; - might_sleep(); - - d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); - d_dump(2, dev, msg, size); - genlmsg_multicast(&wimax_gnl_family, skb, 0, 0, GFP_KERNEL); - d_printf(1, dev, "CTX: genl multicast done\n"); - return 0; -} -EXPORT_SYMBOL_GPL(wimax_msg_send); - - -/** - * wimax_msg - Send a message to user space - * - * @wimax_dev: WiMAX device descriptor (properly referenced) - * @pipe_name: "named pipe" the message will be sent to - * @buf: pointer to the message to send. - * @size: size of the buffer pointed to by @buf (in bytes). - * @gfp_flags: flags for memory allocation. - * - * Returns: %0 if ok, negative errno code on error. - * - * Description: - * - * Sends a free-form message to user space on the device @wimax_dev. - * - * NOTES: - * - * Once the @skb is given to this function, who will own it and will - * release it when done (unless it returns error). - */ -int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name, - const void *buf, size_t size, gfp_t gfp_flags) -{ - int result = -ENOMEM; - struct sk_buff *skb; - - skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags); - if (IS_ERR(skb)) - result = PTR_ERR(skb); - else - result = wimax_msg_send(wimax_dev, skb); - return result; -} -EXPORT_SYMBOL_GPL(wimax_msg); - -/* - * Relays a message from user space to the driver - * - * The skb is passed to the driver-specific function with the netlink - * and generic netlink headers already stripped. - * - * This call will block while handling/relaying the message. - */ -int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info) -{ - int result, ifindex; - struct wimax_dev *wimax_dev; - struct device *dev; - struct nlmsghdr *nlh = info->nlhdr; - char *pipe_name; - void *msg_buf; - size_t msg_len; - - might_sleep(); - d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); - result = -ENODEV; - if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) { - pr_err("WIMAX_GNL_MSG_FROM_USER: can't find IFIDX attribute\n"); - goto error_no_wimax_dev; - } - ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]); - wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); - if (wimax_dev == NULL) - goto error_no_wimax_dev; - dev = wimax_dev_to_dev(wimax_dev); - - /* Unpack arguments */ - result = -EINVAL; - if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) { - dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA " - "attribute\n"); - goto error_no_data; - } - msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]); - msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]); - - if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL) - pipe_name = NULL; - else { - struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME]; - size_t attr_len = nla_len(attr); - /* libnl-1.1 does not yet support NLA_NUL_STRING */ - result = -ENOMEM; - pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL); - if (pipe_name == NULL) - goto error_alloc; - pipe_name[attr_len] = 0; - } - mutex_lock(&wimax_dev->mutex); - result = wimax_dev_is_ready(wimax_dev); - if (result == -ENOMEDIUM) - result = 0; - if (result < 0) - goto error_not_ready; - result = -ENOSYS; - if (wimax_dev->op_msg_from_user == NULL) - goto error_noop; - - d_printf(1, dev, - "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, - nlh->nlmsg_seq, nlh->nlmsg_pid); - d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len); - d_dump(2, dev, msg_buf, msg_len); - - result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name, - msg_buf, msg_len, info); -error_noop: -error_not_ready: - mutex_unlock(&wimax_dev->mutex); -error_alloc: - kfree(pipe_name); -error_no_data: - dev_put(wimax_dev->net_dev); -error_no_wimax_dev: - d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); - return result; -} diff --git a/drivers/staging/wimax/op-reset.c b/drivers/staging/wimax/op-reset.c deleted file mode 100644 index b3f000cbe112e12e279e6dc46a7ed56545cc4a29..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/op-reset.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * Implement and export a method for resetting a WiMAX device - * - * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This implements a simple synchronous call to reset a WiMAX device. - * - * Resets aim at being warm, keeping the device handles active; - * however, when that fails, it falls back to a cold reset (that will - * disconnect and reconnect the device). - */ - -#include "net-wimax.h" -#include <net/genetlink.h> -#include "linux-wimax.h" -#include <linux/security.h> -#include <linux/export.h> -#include "wimax-internal.h" - -#define D_SUBMODULE op_reset -#include "debug-levels.h" - - -/** - * wimax_reset - Reset a WiMAX device - * - * @wimax_dev: WiMAX device descriptor - * - * Returns: - * - * %0 if ok and a warm reset was done (the device still exists in - * the system). - * - * -%ENODEV if a cold/bus reset had to be done (device has - * disconnected and reconnected, so current handle is not valid - * any more). - * - * -%EINVAL if the device is not even registered. - * - * Any other negative error code shall be considered as - * non-recoverable. - * - * Description: - * - * Called when wanting to reset the device for any reason. Device is - * taken back to power on status. - * - * This call blocks; on successful return, the device has completed the - * reset process and is ready to operate. - */ -int wimax_reset(struct wimax_dev *wimax_dev) -{ - int result = -EINVAL; - struct device *dev = wimax_dev_to_dev(wimax_dev); - enum wimax_st state; - - might_sleep(); - d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); - mutex_lock(&wimax_dev->mutex); - dev_hold(wimax_dev->net_dev); - state = wimax_dev->state; - mutex_unlock(&wimax_dev->mutex); - - if (state >= WIMAX_ST_DOWN) { - mutex_lock(&wimax_dev->mutex_reset); - result = wimax_dev->op_reset(wimax_dev); - mutex_unlock(&wimax_dev->mutex_reset); - } - dev_put(wimax_dev->net_dev); - - d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); - return result; -} -EXPORT_SYMBOL(wimax_reset); - - -/* - * Exporting to user space over generic netlink - * - * Parse the reset command from user space, return error code. - * - * No attributes. - */ -int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info) -{ - int result, ifindex; - struct wimax_dev *wimax_dev; - - d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); - result = -ENODEV; - if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) { - pr_err("WIMAX_GNL_OP_RFKILL: can't find IFIDX attribute\n"); - goto error_no_wimax_dev; - } - ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]); - wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); - if (wimax_dev == NULL) - goto error_no_wimax_dev; - /* Execute the operation and send the result back to user space */ - result = wimax_reset(wimax_dev); - dev_put(wimax_dev->net_dev); -error_no_wimax_dev: - d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); - return result; -} diff --git a/drivers/staging/wimax/op-rfkill.c b/drivers/staging/wimax/op-rfkill.c deleted file mode 100644 index 78b294481a59ac40f77bbc4afc029977d53a27ec..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/op-rfkill.c +++ /dev/null @@ -1,431 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * RF-kill framework integration - * - * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This integrates into the Linux Kernel rfkill susbystem so that the - * drivers just have to do the bare minimal work, which is providing a - * method to set the software RF-Kill switch and to report changes in - * the software and hardware switch status. - * - * A non-polled generic rfkill device is embedded into the WiMAX - * subsystem's representation of a device. - * - * FIXME: Need polled support? Let drivers provide a poll routine - * and hand it to rfkill ops then? - * - * All device drivers have to do is after wimax_dev_init(), call - * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update - * initial state and then every time it changes. See wimax.h:struct - * wimax_dev for more information. - * - * ROADMAP - * - * wimax_gnl_doit_rfkill() User space calling wimax_rfkill() - * wimax_rfkill() Kernel calling wimax_rfkill() - * __wimax_rf_toggle_radio() - * - * wimax_rfkill_set_radio_block() RF-Kill subsystem calling - * __wimax_rf_toggle_radio() - * - * __wimax_rf_toggle_radio() - * wimax_dev->op_rfkill_sw_toggle() Driver backend - * __wimax_state_change() - * - * wimax_report_rfkill_sw() Driver reports state change - * __wimax_state_change() - * - * wimax_report_rfkill_hw() Driver reports state change - * __wimax_state_change() - * - * wimax_rfkill_add() Initialize/shutdown rfkill support - * wimax_rfkill_rm() [called by wimax_dev_add/rm()] - */ - -#include "net-wimax.h" -#include <net/genetlink.h> -#include "linux-wimax.h" -#include <linux/security.h> -#include <linux/rfkill.h> -#include <linux/export.h> -#include "wimax-internal.h" - -#define D_SUBMODULE op_rfkill -#include "debug-levels.h" - -/** - * wimax_report_rfkill_hw - Reports changes in the hardware RF switch - * - * @wimax_dev: WiMAX device descriptor - * - * @state: New state of the RF Kill switch. %WIMAX_RF_ON radio on, - * %WIMAX_RF_OFF radio off. - * - * When the device detects a change in the state of thehardware RF - * switch, it must call this function to let the WiMAX kernel stack - * know that the state has changed so it can be properly propagated. - * - * The WiMAX stack caches the state (the driver doesn't need to). As - * well, as the change is propagated it will come back as a request to - * change the software state to mirror the hardware state. - * - * If the device doesn't have a hardware kill switch, just report - * it on initialization as always on (%WIMAX_RF_ON, radio on). - */ -void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ - int result; - struct device *dev = wimax_dev_to_dev(wimax_dev); - enum wimax_st wimax_state; - - d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); - BUG_ON(state == WIMAX_RF_QUERY); - BUG_ON(state != WIMAX_RF_ON && state != WIMAX_RF_OFF); - - mutex_lock(&wimax_dev->mutex); - result = wimax_dev_is_ready(wimax_dev); - if (result < 0) - goto error_not_ready; - - if (state != wimax_dev->rf_hw) { - wimax_dev->rf_hw = state; - if (wimax_dev->rf_hw == WIMAX_RF_ON && - wimax_dev->rf_sw == WIMAX_RF_ON) - wimax_state = WIMAX_ST_READY; - else - wimax_state = WIMAX_ST_RADIO_OFF; - - result = rfkill_set_hw_state(wimax_dev->rfkill, - state == WIMAX_RF_OFF); - - __wimax_state_change(wimax_dev, wimax_state); - } -error_not_ready: - mutex_unlock(&wimax_dev->mutex); - d_fnend(3, dev, "(wimax_dev %p state %u) = void [%d]\n", - wimax_dev, state, result); -} -EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw); - - -/** - * wimax_report_rfkill_sw - Reports changes in the software RF switch - * - * @wimax_dev: WiMAX device descriptor - * - * @state: New state of the RF kill switch. %WIMAX_RF_ON radio on, - * %WIMAX_RF_OFF radio off. - * - * Reports changes in the software RF switch state to the WiMAX stack. - * - * The main use is during initialization, so the driver can query the - * device for its current software radio kill switch state and feed it - * to the system. - * - * On the side, the device does not change the software state by - * itself. In practice, this can happen, as the device might decide to - * switch (in software) the radio off for different reasons. - */ -void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ - int result; - struct device *dev = wimax_dev_to_dev(wimax_dev); - enum wimax_st wimax_state; - - d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); - BUG_ON(state == WIMAX_RF_QUERY); - BUG_ON(state != WIMAX_RF_ON && state != WIMAX_RF_OFF); - - mutex_lock(&wimax_dev->mutex); - result = wimax_dev_is_ready(wimax_dev); - if (result < 0) - goto error_not_ready; - - if (state != wimax_dev->rf_sw) { - wimax_dev->rf_sw = state; - if (wimax_dev->rf_hw == WIMAX_RF_ON && - wimax_dev->rf_sw == WIMAX_RF_ON) - wimax_state = WIMAX_ST_READY; - else - wimax_state = WIMAX_ST_RADIO_OFF; - __wimax_state_change(wimax_dev, wimax_state); - rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); - } -error_not_ready: - mutex_unlock(&wimax_dev->mutex); - d_fnend(3, dev, "(wimax_dev %p state %u) = void [%d]\n", - wimax_dev, state, result); -} -EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw); - - -/* - * Callback for the RF Kill toggle operation - * - * This function is called by: - * - * - The rfkill subsystem when the RF-Kill key is pressed in the - * hardware and the driver notifies through - * wimax_report_rfkill_hw(). The rfkill subsystem ends up calling back - * here so the software RF Kill switch state is changed to reflect - * the hardware switch state. - * - * - When the user sets the state through sysfs' rfkill/state file - * - * - When the user calls wimax_rfkill(). - * - * This call blocks! - * - * WARNING! When we call rfkill_unregister(), this will be called with - * state 0! - * - * WARNING: wimax_dev must be locked - */ -static -int __wimax_rf_toggle_radio(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ - int result = 0; - struct device *dev = wimax_dev_to_dev(wimax_dev); - enum wimax_st wimax_state; - - might_sleep(); - d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); - if (wimax_dev->rf_sw == state) - goto out_no_change; - if (wimax_dev->op_rfkill_sw_toggle != NULL) - result = wimax_dev->op_rfkill_sw_toggle(wimax_dev, state); - else if (state == WIMAX_RF_OFF) /* No op? can't turn off */ - result = -ENXIO; - else /* No op? can turn on */ - result = 0; /* should never happen tho */ - if (result >= 0) { - result = 0; - wimax_dev->rf_sw = state; - wimax_state = state == WIMAX_RF_ON ? - WIMAX_ST_READY : WIMAX_ST_RADIO_OFF; - __wimax_state_change(wimax_dev, wimax_state); - } -out_no_change: - d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", - wimax_dev, state, result); - return result; -} - - -/* - * Translate from rfkill state to wimax state - * - * NOTE: Special state handling rules here - * - * Just pretend the call didn't happen if we are in a state where - * we know for sure it cannot be handled (WIMAX_ST_DOWN or - * __WIMAX_ST_QUIESCING). rfkill() needs it to register and - * unregister, as it will run this path. - * - * NOTE: This call will block until the operation is completed. - */ -static int wimax_rfkill_set_radio_block(void *data, bool blocked) -{ - int result; - struct wimax_dev *wimax_dev = data; - struct device *dev = wimax_dev_to_dev(wimax_dev); - enum wimax_rf_state rf_state; - - d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked); - rf_state = WIMAX_RF_ON; - if (blocked) - rf_state = WIMAX_RF_OFF; - mutex_lock(&wimax_dev->mutex); - if (wimax_dev->state <= __WIMAX_ST_QUIESCING) - result = 0; - else - result = __wimax_rf_toggle_radio(wimax_dev, rf_state); - mutex_unlock(&wimax_dev->mutex); - d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n", - wimax_dev, blocked, result); - return result; -} - -static const struct rfkill_ops wimax_rfkill_ops = { - .set_block = wimax_rfkill_set_radio_block, -}; - -/** - * wimax_rfkill - Set the software RF switch state for a WiMAX device - * - * @wimax_dev: WiMAX device descriptor - * - * @state: New RF state. - * - * Returns: - * - * >= 0 toggle state if ok, < 0 errno code on error. The toggle state - * is returned as a bitmap, bit 0 being the hardware RF state, bit 1 - * the software RF state. - * - * 0 means disabled (%WIMAX_RF_ON, radio on), 1 means enabled radio - * off (%WIMAX_RF_OFF). - * - * Description: - * - * Called by the user when he wants to request the WiMAX radio to be - * switched on (%WIMAX_RF_ON) or off (%WIMAX_RF_OFF). With - * %WIMAX_RF_QUERY, just the current state is returned. - * - * NOTE: - * - * This call will block until the operation is complete. - */ -int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) -{ - int result; - struct device *dev = wimax_dev_to_dev(wimax_dev); - - d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); - mutex_lock(&wimax_dev->mutex); - result = wimax_dev_is_ready(wimax_dev); - if (result < 0) { - /* While initializing, < 1.4.3 wimax-tools versions use - * this call to check if the device is a valid WiMAX - * device; so we allow it to proceed always, - * considering the radios are all off. */ - if (result == -ENOMEDIUM && state == WIMAX_RF_QUERY) - result = WIMAX_RF_OFF << 1 | WIMAX_RF_OFF; - goto error_not_ready; - } - switch (state) { - case WIMAX_RF_ON: - case WIMAX_RF_OFF: - result = __wimax_rf_toggle_radio(wimax_dev, state); - if (result < 0) - goto error; - rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); - break; - case WIMAX_RF_QUERY: - break; - default: - result = -EINVAL; - goto error; - } - result = wimax_dev->rf_sw << 1 | wimax_dev->rf_hw; -error: -error_not_ready: - mutex_unlock(&wimax_dev->mutex); - d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", - wimax_dev, state, result); - return result; -} -EXPORT_SYMBOL(wimax_rfkill); - - -/* - * Register a new WiMAX device's RF Kill support - * - * WARNING: wimax_dev->mutex must be unlocked - */ -int wimax_rfkill_add(struct wimax_dev *wimax_dev) -{ - int result; - struct rfkill *rfkill; - struct device *dev = wimax_dev_to_dev(wimax_dev); - - d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); - /* Initialize RF Kill */ - result = -ENOMEM; - rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX, - &wimax_rfkill_ops, wimax_dev); - if (rfkill == NULL) - goto error_rfkill_allocate; - - d_printf(1, dev, "rfkill %p\n", rfkill); - - wimax_dev->rfkill = rfkill; - - rfkill_init_sw_state(rfkill, 1); - result = rfkill_register(wimax_dev->rfkill); - if (result < 0) - goto error_rfkill_register; - - /* If there is no SW toggle op, SW RFKill is always on */ - if (wimax_dev->op_rfkill_sw_toggle == NULL) - wimax_dev->rf_sw = WIMAX_RF_ON; - - d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); - return 0; - -error_rfkill_register: - rfkill_destroy(wimax_dev->rfkill); -error_rfkill_allocate: - d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); - return result; -} - - -/* - * Deregister a WiMAX device's RF Kill support - * - * Ick, we can't call rfkill_free() after rfkill_unregister()...oh - * well. - * - * WARNING: wimax_dev->mutex must be unlocked - */ -void wimax_rfkill_rm(struct wimax_dev *wimax_dev) -{ - struct device *dev = wimax_dev_to_dev(wimax_dev); - d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); - rfkill_unregister(wimax_dev->rfkill); - rfkill_destroy(wimax_dev->rfkill); - d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); -} - - -/* - * Exporting to user space over generic netlink - * - * Parse the rfkill command from user space, return a combination - * value that describe the states of the different toggles. - * - * Only one attribute: the new state requested (on, off or no change, - * just query). - */ - -int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info) -{ - int result, ifindex; - struct wimax_dev *wimax_dev; - struct device *dev; - enum wimax_rf_state new_state; - - d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); - result = -ENODEV; - if (info->attrs[WIMAX_GNL_RFKILL_IFIDX] == NULL) { - pr_err("WIMAX_GNL_OP_RFKILL: can't find IFIDX attribute\n"); - goto error_no_wimax_dev; - } - ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RFKILL_IFIDX]); - wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); - if (wimax_dev == NULL) - goto error_no_wimax_dev; - dev = wimax_dev_to_dev(wimax_dev); - result = -EINVAL; - if (info->attrs[WIMAX_GNL_RFKILL_STATE] == NULL) { - dev_err(dev, "WIMAX_GNL_RFKILL: can't find RFKILL_STATE " - "attribute\n"); - goto error_no_pid; - } - new_state = nla_get_u32(info->attrs[WIMAX_GNL_RFKILL_STATE]); - - /* Execute the operation and send the result back to user space */ - result = wimax_rfkill(wimax_dev, new_state); -error_no_pid: - dev_put(wimax_dev->net_dev); -error_no_wimax_dev: - d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); - return result; -} diff --git a/drivers/staging/wimax/op-state-get.c b/drivers/staging/wimax/op-state-get.c deleted file mode 100644 index c5bfbed505f5d9674d6fed5bd5996324155edc6c..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/op-state-get.c +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * Implement and export a method for getting a WiMAX device current state - * - * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * Based on previous WiMAX core work by: - * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - */ - -#include "net-wimax.h" -#include <net/genetlink.h> -#include "linux-wimax.h" -#include <linux/security.h> -#include "wimax-internal.h" - -#define D_SUBMODULE op_state_get -#include "debug-levels.h" - - -/* - * Exporting to user space over generic netlink - * - * Parse the state get command from user space, return a combination - * value that describe the current state. - * - * No attributes. - */ -int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info) -{ - int result, ifindex; - struct wimax_dev *wimax_dev; - - d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); - result = -ENODEV; - if (info->attrs[WIMAX_GNL_STGET_IFIDX] == NULL) { - pr_err("WIMAX_GNL_OP_STATE_GET: can't find IFIDX attribute\n"); - goto error_no_wimax_dev; - } - ifindex = nla_get_u32(info->attrs[WIMAX_GNL_STGET_IFIDX]); - wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); - if (wimax_dev == NULL) - goto error_no_wimax_dev; - /* Execute the operation and send the result back to user space */ - result = wimax_state_get(wimax_dev); - dev_put(wimax_dev->net_dev); -error_no_wimax_dev: - d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); - return result; -} diff --git a/drivers/staging/wimax/stack.c b/drivers/staging/wimax/stack.c deleted file mode 100644 index ace24a6dfd2d9af46fcae09c5b25f43729e80fb5..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/stack.c +++ /dev/null @@ -1,616 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Linux WiMAX - * Initialization, addition and removal of wimax devices - * - * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This implements: - * - * - basic life cycle of 'struct wimax_dev' [wimax_dev_*()]; on - * addition/registration initialize all subfields and allocate - * generic netlink resources for user space communication. On - * removal/unregistration, undo all that. - * - * - device state machine [wimax_state_change()] and support to send - * reports to user space when the state changes - * [wimax_gnl_re_state_change*()]. - * - * See include/net/wimax.h for rationales and design. - * - * ROADMAP - * - * [__]wimax_state_change() Called by drivers to update device's state - * wimax_gnl_re_state_change_alloc() - * wimax_gnl_re_state_change_send() - * - * wimax_dev_init() Init a device - * wimax_dev_add() Register - * wimax_rfkill_add() - * wimax_gnl_add() Register all the generic netlink resources. - * wimax_id_table_add() - * wimax_dev_rm() Unregister - * wimax_id_table_rm() - * wimax_gnl_rm() - * wimax_rfkill_rm() - */ -#include <linux/device.h> -#include <linux/gfp.h> -#include <net/genetlink.h> -#include <linux/netdevice.h> -#include "linux-wimax.h" -#include <linux/module.h> -#include "wimax-internal.h" - - -#define D_SUBMODULE stack -#include "debug-levels.h" - -static char wimax_debug_params[128]; -module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params), - 0644); -MODULE_PARM_DESC(debug, - "String of space-separated NAME:VALUE pairs, where NAMEs " - "are the different debug submodules and VALUE are the " - "initial debug value to set."); - -/* - * Authoritative source for the RE_STATE_CHANGE attribute policy - * - * We don't really use it here, but /me likes to keep the definition - * close to where the data is generated. - */ -/* -static const struct nla_policy wimax_gnl_re_status_change[WIMAX_GNL_ATTR_MAX + 1] = { - [WIMAX_GNL_STCH_STATE_OLD] = { .type = NLA_U8 }, - [WIMAX_GNL_STCH_STATE_NEW] = { .type = NLA_U8 }, -}; -*/ - - -/* - * Allocate a Report State Change message - * - * @header: save it, you need it for _send() - * - * Creates and fills a basic state change message; different code - * paths can then add more attributes to the message as needed. - * - * Use wimax_gnl_re_state_change_send() to send the returned skb. - * - * Returns: skb with the genl message if ok, IS_ERR() ptr on error - * with an errno code. - */ -static -struct sk_buff *wimax_gnl_re_state_change_alloc( - struct wimax_dev *wimax_dev, - enum wimax_st new_state, enum wimax_st old_state, - void **header) -{ - int result; - struct device *dev = wimax_dev_to_dev(wimax_dev); - void *data; - struct sk_buff *report_skb; - - d_fnstart(3, dev, "(wimax_dev %p new_state %u old_state %u)\n", - wimax_dev, new_state, old_state); - result = -ENOMEM; - report_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (report_skb == NULL) { - dev_err(dev, "RE_STCH: can't create message\n"); - goto error_new; - } - /* FIXME: sending a group ID as the seq is wrong */ - data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset, - &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE); - if (data == NULL) { - dev_err(dev, "RE_STCH: can't put data into message\n"); - goto error_put; - } - *header = data; - - result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_OLD, old_state); - if (result < 0) { - dev_err(dev, "RE_STCH: Error adding OLD attr: %d\n", result); - goto error_put; - } - result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_NEW, new_state); - if (result < 0) { - dev_err(dev, "RE_STCH: Error adding NEW attr: %d\n", result); - goto error_put; - } - result = nla_put_u32(report_skb, WIMAX_GNL_STCH_IFIDX, - wimax_dev->net_dev->ifindex); - if (result < 0) { - dev_err(dev, "RE_STCH: Error adding IFINDEX attribute\n"); - goto error_put; - } - d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %p\n", - wimax_dev, new_state, old_state, report_skb); - return report_skb; - -error_put: - nlmsg_free(report_skb); -error_new: - d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %d\n", - wimax_dev, new_state, old_state, result); - return ERR_PTR(result); -} - - -/* - * Send a Report State Change message (as created with _alloc). - * - * @report_skb: as returned by wimax_gnl_re_state_change_alloc() - * @header: as returned by wimax_gnl_re_state_change_alloc() - * - * Returns: 0 if ok, < 0 errno code on error. - * - * If the message is NULL, pretend it didn't happen. - */ -static -int wimax_gnl_re_state_change_send( - struct wimax_dev *wimax_dev, struct sk_buff *report_skb, - void *header) -{ - int result = 0; - struct device *dev = wimax_dev_to_dev(wimax_dev); - d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n", - wimax_dev, report_skb); - if (report_skb == NULL) { - result = -ENOMEM; - goto out; - } - genlmsg_end(report_skb, header); - genlmsg_multicast(&wimax_gnl_family, report_skb, 0, 0, GFP_KERNEL); -out: - d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n", - wimax_dev, report_skb, result); - return result; -} - - -static -void __check_new_state(enum wimax_st old_state, enum wimax_st new_state, - unsigned int allowed_states_bm) -{ - if (WARN_ON(((1 << new_state) & allowed_states_bm) == 0)) { - pr_err("SW BUG! Forbidden state change %u -> %u\n", - old_state, new_state); - } -} - - -/* - * Set the current state of a WiMAX device [unlocking version of - * wimax_state_change(). - */ -void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state) -{ - struct device *dev = wimax_dev_to_dev(wimax_dev); - enum wimax_st old_state = wimax_dev->state; - struct sk_buff *stch_skb; - void *header; - - d_fnstart(3, dev, "(wimax_dev %p new_state %u [old %u])\n", - wimax_dev, new_state, old_state); - - if (WARN_ON(new_state >= __WIMAX_ST_INVALID)) { - dev_err(dev, "SW BUG: requesting invalid state %u\n", - new_state); - goto out; - } - if (old_state == new_state) - goto out; - header = NULL; /* gcc complains? can't grok why */ - stch_skb = wimax_gnl_re_state_change_alloc( - wimax_dev, new_state, old_state, &header); - - /* Verify the state transition and do exit-from-state actions */ - switch (old_state) { - case __WIMAX_ST_NULL: - __check_new_state(old_state, new_state, - 1 << WIMAX_ST_DOWN); - break; - case WIMAX_ST_DOWN: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_UNINITIALIZED - | 1 << WIMAX_ST_RADIO_OFF); - break; - case __WIMAX_ST_QUIESCING: - __check_new_state(old_state, new_state, 1 << WIMAX_ST_DOWN); - break; - case WIMAX_ST_UNINITIALIZED: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_RADIO_OFF); - break; - case WIMAX_ST_RADIO_OFF: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_READY); - break; - case WIMAX_ST_READY: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_RADIO_OFF - | 1 << WIMAX_ST_SCANNING - | 1 << WIMAX_ST_CONNECTING - | 1 << WIMAX_ST_CONNECTED); - break; - case WIMAX_ST_SCANNING: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_RADIO_OFF - | 1 << WIMAX_ST_READY - | 1 << WIMAX_ST_CONNECTING - | 1 << WIMAX_ST_CONNECTED); - break; - case WIMAX_ST_CONNECTING: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_RADIO_OFF - | 1 << WIMAX_ST_READY - | 1 << WIMAX_ST_SCANNING - | 1 << WIMAX_ST_CONNECTED); - break; - case WIMAX_ST_CONNECTED: - __check_new_state(old_state, new_state, - 1 << __WIMAX_ST_QUIESCING - | 1 << WIMAX_ST_RADIO_OFF - | 1 << WIMAX_ST_READY); - netif_tx_disable(wimax_dev->net_dev); - netif_carrier_off(wimax_dev->net_dev); - break; - case __WIMAX_ST_INVALID: - default: - dev_err(dev, "SW BUG: wimax_dev %p is in unknown state %u\n", - wimax_dev, wimax_dev->state); - WARN_ON(1); - goto out; - } - - /* Execute the actions of entry to the new state */ - switch (new_state) { - case __WIMAX_ST_NULL: - dev_err(dev, "SW BUG: wimax_dev %p entering NULL state " - "from %u\n", wimax_dev, wimax_dev->state); - WARN_ON(1); /* Nobody can enter this state */ - break; - case WIMAX_ST_DOWN: - break; - case __WIMAX_ST_QUIESCING: - break; - case WIMAX_ST_UNINITIALIZED: - break; - case WIMAX_ST_RADIO_OFF: - break; - case WIMAX_ST_READY: - break; - case WIMAX_ST_SCANNING: - break; - case WIMAX_ST_CONNECTING: - break; - case WIMAX_ST_CONNECTED: - netif_carrier_on(wimax_dev->net_dev); - netif_wake_queue(wimax_dev->net_dev); - break; - case __WIMAX_ST_INVALID: - default: - BUG(); - } - __wimax_state_set(wimax_dev, new_state); - if (!IS_ERR(stch_skb)) - wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header); -out: - d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n", - wimax_dev, new_state, old_state); -} - - -/** - * wimax_state_change - Set the current state of a WiMAX device - * - * @wimax_dev: WiMAX device descriptor (properly referenced) - * @new_state: New state to switch to - * - * This implements the state changes for the wimax devices. It will - * - * - verify that the state transition is legal (for now it'll just - * print a warning if not) according to the table in - * linux/wimax.h's documentation for 'enum wimax_st'. - * - * - perform the actions needed for leaving the current state and - * whichever are needed for entering the new state. - * - * - issue a report to user space indicating the new state (and an - * optional payload with information about the new state). - * - * NOTE: @wimax_dev must be locked - */ -void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state) -{ - /* - * A driver cannot take the wimax_dev out of the - * __WIMAX_ST_NULL state unless by calling wimax_dev_add(). If - * the wimax_dev's state is still NULL, we ignore any request - * to change its state because it means it hasn't been yet - * registered. - * - * There is no need to complain about it, as routines that - * call this might be shared from different code paths that - * are called before or after wimax_dev_add() has done its - * job. - */ - mutex_lock(&wimax_dev->mutex); - if (wimax_dev->state > __WIMAX_ST_NULL) - __wimax_state_change(wimax_dev, new_state); - mutex_unlock(&wimax_dev->mutex); -} -EXPORT_SYMBOL_GPL(wimax_state_change); - - -/** - * wimax_state_get() - Return the current state of a WiMAX device - * - * @wimax_dev: WiMAX device descriptor - * - * Returns: Current state of the device according to its driver. - */ -enum wimax_st wimax_state_get(struct wimax_dev *wimax_dev) -{ - enum wimax_st state; - mutex_lock(&wimax_dev->mutex); - state = wimax_dev->state; - mutex_unlock(&wimax_dev->mutex); - return state; -} -EXPORT_SYMBOL_GPL(wimax_state_get); - - -/** - * wimax_dev_init - initialize a newly allocated instance - * - * @wimax_dev: WiMAX device descriptor to initialize. - * - * Initializes fields of a freshly allocated @wimax_dev instance. This - * function assumes that after allocation, the memory occupied by - * @wimax_dev was zeroed. - */ -void wimax_dev_init(struct wimax_dev *wimax_dev) -{ - INIT_LIST_HEAD(&wimax_dev->id_table_node); - __wimax_state_set(wimax_dev, __WIMAX_ST_NULL); - mutex_init(&wimax_dev->mutex); - mutex_init(&wimax_dev->mutex_reset); -} -EXPORT_SYMBOL_GPL(wimax_dev_init); - -/* - * There are multiple enums reusing the same values, adding - * others is only possible if they use a compatible policy. - */ -static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = { - /* - * WIMAX_GNL_RESET_IFIDX, WIMAX_GNL_RFKILL_IFIDX, - * WIMAX_GNL_STGET_IFIDX, WIMAX_GNL_MSG_IFIDX - */ - [1] = { .type = NLA_U32, }, - /* - * WIMAX_GNL_RFKILL_STATE, WIMAX_GNL_MSG_PIPE_NAME - */ - [2] = { .type = NLA_U32, }, /* enum wimax_rf_state */ - /* - * WIMAX_GNL_MSG_DATA - */ - [3] = { .type = NLA_UNSPEC, }, /* libnl doesn't grok BINARY yet */ -}; - -static const struct genl_small_ops wimax_gnl_ops[] = { - { - .cmd = WIMAX_GNL_OP_MSG_FROM_USER, - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .flags = GENL_ADMIN_PERM, - .doit = wimax_gnl_doit_msg_from_user, - }, - { - .cmd = WIMAX_GNL_OP_RESET, - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .flags = GENL_ADMIN_PERM, - .doit = wimax_gnl_doit_reset, - }, - { - .cmd = WIMAX_GNL_OP_RFKILL, - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .flags = GENL_ADMIN_PERM, - .doit = wimax_gnl_doit_rfkill, - }, - { - .cmd = WIMAX_GNL_OP_STATE_GET, - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .flags = GENL_ADMIN_PERM, - .doit = wimax_gnl_doit_state_get, - }, -}; - - -static -size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size, - unsigned char *addr, size_t addr_len) -{ - unsigned int cnt, total; - - for (total = cnt = 0; cnt < addr_len; cnt++) - total += scnprintf(addr_str + total, addr_str_size - total, - "%02x%c", addr[cnt], - cnt == addr_len - 1 ? '\0' : ':'); - return total; -} - - -/** - * wimax_dev_add - Register a new WiMAX device - * - * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's - * priv data). You must have called wimax_dev_init() on it before. - * - * @net_dev: net device the @wimax_dev is associated with. The - * function expects SET_NETDEV_DEV() and register_netdev() were - * already called on it. - * - * Registers the new WiMAX device, sets up the user-kernel control - * interface (generic netlink) and common WiMAX infrastructure. - * - * Note that the parts that will allow interaction with user space are - * setup at the very end, when the rest is in place, as once that - * happens, the driver might get user space control requests via - * netlink or from debugfs that might translate into calls into - * wimax_dev->op_*(). - */ -int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev) -{ - int result; - struct device *dev = net_dev->dev.parent; - char addr_str[32]; - - d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev); - - /* Do the RFKILL setup before locking, as RFKILL will call - * into our functions. - */ - wimax_dev->net_dev = net_dev; - result = wimax_rfkill_add(wimax_dev); - if (result < 0) - goto error_rfkill_add; - - /* Set up user-space interaction */ - mutex_lock(&wimax_dev->mutex); - wimax_id_table_add(wimax_dev); - wimax_debugfs_add(wimax_dev); - - __wimax_state_set(wimax_dev, WIMAX_ST_DOWN); - mutex_unlock(&wimax_dev->mutex); - - wimax_addr_scnprint(addr_str, sizeof(addr_str), - net_dev->dev_addr, net_dev->addr_len); - dev_err(dev, "WiMAX interface %s (%s) ready\n", - net_dev->name, addr_str); - d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev); - return 0; - -error_rfkill_add: - d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n", - wimax_dev, net_dev, result); - return result; -} -EXPORT_SYMBOL_GPL(wimax_dev_add); - - -/** - * wimax_dev_rm - Unregister an existing WiMAX device - * - * @wimax_dev: WiMAX device descriptor - * - * Unregisters a WiMAX device previously registered for use with - * wimax_add_rm(). - * - * IMPORTANT! Must call before calling unregister_netdev(). - * - * After this function returns, you will not get any more user space - * control requests (via netlink or debugfs) and thus to wimax_dev->ops. - * - * Reentrancy control is ensured by setting the state to - * %__WIMAX_ST_QUIESCING. rfkill operations coming through - * wimax_*rfkill*() will be stopped by the quiescing state; ops coming - * from the rfkill subsystem will be stopped by the support being - * removed by wimax_rfkill_rm(). - */ -void wimax_dev_rm(struct wimax_dev *wimax_dev) -{ - d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev); - - mutex_lock(&wimax_dev->mutex); - __wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); - wimax_debugfs_rm(wimax_dev); - wimax_id_table_rm(wimax_dev); - __wimax_state_change(wimax_dev, WIMAX_ST_DOWN); - mutex_unlock(&wimax_dev->mutex); - wimax_rfkill_rm(wimax_dev); - d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev); -} -EXPORT_SYMBOL_GPL(wimax_dev_rm); - - -/* Debug framework control of debug levels */ -struct d_level D_LEVEL[] = { - D_SUBMODULE_DEFINE(debugfs), - D_SUBMODULE_DEFINE(id_table), - D_SUBMODULE_DEFINE(op_msg), - D_SUBMODULE_DEFINE(op_reset), - D_SUBMODULE_DEFINE(op_rfkill), - D_SUBMODULE_DEFINE(op_state_get), - D_SUBMODULE_DEFINE(stack), -}; -size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); - - -static const struct genl_multicast_group wimax_gnl_mcgrps[] = { - { .name = "msg", }, -}; - -struct genl_family wimax_gnl_family __ro_after_init = { - .name = "WiMAX", - .version = WIMAX_GNL_VERSION, - .hdrsize = 0, - .maxattr = WIMAX_GNL_ATTR_MAX, - .policy = wimax_gnl_policy, - .module = THIS_MODULE, - .small_ops = wimax_gnl_ops, - .n_small_ops = ARRAY_SIZE(wimax_gnl_ops), - .mcgrps = wimax_gnl_mcgrps, - .n_mcgrps = ARRAY_SIZE(wimax_gnl_mcgrps), -}; - - - -/* Shutdown the wimax stack */ -static -int __init wimax_subsys_init(void) -{ - int result; - - d_fnstart(4, NULL, "()\n"); - d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params, - "wimax.debug"); - - result = genl_register_family(&wimax_gnl_family); - if (unlikely(result < 0)) { - pr_err("cannot register generic netlink family: %d\n", result); - goto error_register_family; - } - - d_fnend(4, NULL, "() = 0\n"); - return 0; - -error_register_family: - d_fnend(4, NULL, "() = %d\n", result); - return result; - -} -module_init(wimax_subsys_init); - - -/* Shutdown the wimax stack */ -static -void __exit wimax_subsys_exit(void) -{ - wimax_id_table_release(); - genl_unregister_family(&wimax_gnl_family); -} -module_exit(wimax_subsys_exit); - -MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); -MODULE_DESCRIPTION("Linux WiMAX stack"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/wimax/wimax-internal.h b/drivers/staging/wimax/wimax-internal.h deleted file mode 100644 index a6b6990642a1cfcb85f7456dd461aceedb5b8ab9..0000000000000000000000000000000000000000 --- a/drivers/staging/wimax/wimax-internal.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Linux WiMAX - * Internal API for kernel space WiMAX stack - * - * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This header file is for declarations and definitions internal to - * the WiMAX stack. For public APIs and documentation, see - * include/net/wimax.h and include/linux/wimax.h. - */ - -#ifndef __WIMAX_INTERNAL_H__ -#define __WIMAX_INTERNAL_H__ -#ifdef __KERNEL__ - -#ifdef pr_fmt -#undef pr_fmt -#endif - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/device.h> -#include "net-wimax.h" - - -/* - * Decide if a (locked) device is ready for use - * - * Before using the device structure, it must be locked - * (wimax_dev->mutex). As well, most operations need to call this - * function to check if the state is the right one. - * - * An error value will be returned if the state is not the right - * one. In that case, the caller should not attempt to use the device - * and just unlock it. - */ -static inline __must_check -int wimax_dev_is_ready(struct wimax_dev *wimax_dev) -{ - if (wimax_dev->state == __WIMAX_ST_NULL) - return -EINVAL; /* Device is not even registered! */ - if (wimax_dev->state == WIMAX_ST_DOWN) - return -ENOMEDIUM; - if (wimax_dev->state == __WIMAX_ST_QUIESCING) - return -ESHUTDOWN; - return 0; -} - - -static inline -void __wimax_state_set(struct wimax_dev *wimax_dev, enum wimax_st state) -{ - wimax_dev->state = state; -} -void __wimax_state_change(struct wimax_dev *, enum wimax_st); - -#ifdef CONFIG_DEBUG_FS -void wimax_debugfs_add(struct wimax_dev *); -void wimax_debugfs_rm(struct wimax_dev *); -#else -static inline void wimax_debugfs_add(struct wimax_dev *wimax_dev) {} -static inline void wimax_debugfs_rm(struct wimax_dev *wimax_dev) {} -#endif - -void wimax_id_table_add(struct wimax_dev *); -struct wimax_dev *wimax_dev_get_by_genl_info(struct genl_info *, int); -void wimax_id_table_rm(struct wimax_dev *); -void wimax_id_table_release(void); - -int wimax_rfkill_add(struct wimax_dev *); -void wimax_rfkill_rm(struct wimax_dev *); - -/* generic netlink */ -extern struct genl_family wimax_gnl_family; - -/* ops */ -int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info); -int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info); -int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info); -int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info); - -#endif /* #ifdef __KERNEL__ */ -#endif /* #ifndef __WIMAX_INTERNAL_H__ */ diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h index 827002ca9930caaa6b58f96b1fe15aad6c424b20..15fd635d97701ce99bcd0ca27a76f6ac55febc79 100644 --- a/drivers/staging/wlan-ng/p80211conv.h +++ b/drivers/staging/wlan-ng/p80211conv.h @@ -122,9 +122,6 @@ struct p80211_caphdr { __be32 encoding; }; -/* buffer free method pointer type */ -typedef void (*freebuf_method_t) (void *buf, int size); - struct p80211_metawep { void *data; u8 iv[4]; diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 6f9666dc027795a55435b97b0a50da32c34be3a3..70570e8a5ad27818822dfd293ce4c8a5ab5da040 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -569,7 +569,7 @@ static int p80211knetdev_do_ioctl(struct net_device *dev, goto bail; } - msgbuf = memdup_user(req->data, req->len); + msgbuf = memdup_user((void __user *)req->data, req->len); if (IS_ERR(msgbuf)) { result = PTR_ERR(msgbuf); goto bail; diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile index 56263ae3b1d7a3b6e8c92da85ec0f2c233442874..3aa33ea9e6a6b7e92c5bdab0fefda81b0d129595 100644 --- a/drivers/tee/optee/Makefile +++ b/drivers/tee/optee/Makefile @@ -6,3 +6,6 @@ optee-objs += rpc.o optee-objs += supp.o optee-objs += shm_pool.o optee-objs += device.o + +# for tracing framework to find optee_trace.h +CFLAGS_call.o := -I$(src) diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 7a77e375b503cd2512496ba6d321326d7b776676..6132cc8d014c08512b487a31041844f65dbd6830 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -14,6 +14,8 @@ #include <linux/uaccess.h> #include "optee_private.h" #include "optee_smc.h" +#define CREATE_TRACE_POINTS +#include "optee_trace.h" struct optee_call_waiter { struct list_head list_node; @@ -138,9 +140,11 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg) while (true) { struct arm_smccc_res res; + trace_optee_invoke_fn_begin(¶m); optee->invoke_fn(param.a0, param.a1, param.a2, param.a3, param.a4, param.a5, param.a6, param.a7, &res); + trace_optee_invoke_fn_end(¶m, &res); if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) { /* diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 319a1e701163b6c419e3e3ca6f14a69c0ee1c1c0..ddb8f9ecf3078f42708523ec26ae88174031d8a8 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -79,16 +79,6 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params, return rc; p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa; p->u.memref.shm = shm; - - /* Check that the memref is covered by the shm object */ - if (p->u.memref.size) { - size_t o = p->u.memref.shm_offs + - p->u.memref.size - 1; - - rc = tee_shm_get_pa(shm, o, NULL); - if (rc) - return rc; - } break; case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT: case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT: diff --git a/drivers/tee/optee/optee_trace.h b/drivers/tee/optee/optee_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..7c954eefa4bfa3517e7db22ce42534e0f5b58752 --- /dev/null +++ b/drivers/tee/optee/optee_trace.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * optee trace points + * + * Copyright (C) 2021 Synaptics Incorporated + * Author: Jisheng Zhang <jszhang@kernel.org> + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM optee + +#if !defined(_TRACE_OPTEE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_OPTEE_H + +#include <linux/arm-smccc.h> +#include <linux/tracepoint.h> +#include "optee_private.h" + +TRACE_EVENT(optee_invoke_fn_begin, + TP_PROTO(struct optee_rpc_param *param), + TP_ARGS(param), + + TP_STRUCT__entry( + __field(void *, param) + __array(u32, args, 8) + ), + + TP_fast_assign( + __entry->param = param; + BUILD_BUG_ON(sizeof(*param) < sizeof(__entry->args)); + memcpy(__entry->args, param, sizeof(__entry->args)); + ), + + TP_printk("param=%p (%x, %x, %x, %x, %x, %x, %x, %x)", __entry->param, + __entry->args[0], __entry->args[1], __entry->args[2], + __entry->args[3], __entry->args[4], __entry->args[5], + __entry->args[6], __entry->args[7]) +); + +TRACE_EVENT(optee_invoke_fn_end, + TP_PROTO(struct optee_rpc_param *param, struct arm_smccc_res *res), + TP_ARGS(param, res), + + TP_STRUCT__entry( + __field(void *, param) + __array(unsigned long, rets, 4) + ), + + TP_fast_assign( + __entry->param = param; + BUILD_BUG_ON(sizeof(*res) < sizeof(__entry->rets)); + memcpy(__entry->rets, res, sizeof(__entry->rets)); + ), + + TP_printk("param=%p ret (%lx, %lx, %lx, %lx)", __entry->param, + __entry->rets[0], __entry->rets[1], __entry->rets[2], + __entry->rets[3]) +); +#endif /* _TRACE_OPTEE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE optee_trace + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index f1aeaff9f3684a565201ecc7d0f9dcb73403cc8e..0fb5e04191e24e81a636fbfbcb8762c2c8a70777 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -17,7 +17,7 @@ #define TB_CTL_RX_PKG_COUNT 10 -#define TB_CTL_RETRIES 4 +#define TB_CTL_RETRIES 1 /** * struct tb_ctl - Thunderbolt control channel @@ -29,6 +29,7 @@ * @request_queue_lock: Lock protecting @request_queue * @request_queue: List of outstanding requests * @running: Is the control channel running at the moment + * @timeout_msec: Default timeout for non-raw control messages * @callback: Callback called when hotplug message is received * @callback_data: Data passed to @callback */ @@ -43,6 +44,7 @@ struct tb_ctl { struct list_head request_queue; bool running; + int timeout_msec; event_cb callback; void *callback_data; }; @@ -613,6 +615,7 @@ struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl, /** * tb_ctl_alloc() - allocate a control channel * @nhi: Pointer to NHI + * @timeout_msec: Default timeout used with non-raw control messages * @cb: Callback called for plug events * @cb_data: Data passed to @cb * @@ -620,13 +623,15 @@ struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl, * * Return: Returns a pointer on success or NULL on failure. */ -struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data) +struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int timeout_msec, event_cb cb, + void *cb_data) { int i; struct tb_ctl *ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); if (!ctl) return NULL; ctl->nhi = nhi; + ctl->timeout_msec = timeout_msec; ctl->callback = cb; ctl->callback_data = cb_data; @@ -802,14 +807,12 @@ static bool tb_cfg_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg) * tb_cfg_reset() - send a reset packet and wait for a response * @ctl: Control channel pointer * @route: Router string for the router to send reset - * @timeout_msec: Timeout in ms how long to wait for the response * * If the switch at route is incorrectly configured then we will not receive a * reply (even though the switch will reset). The caller should check for * -ETIMEDOUT and attempt to reconfigure the switch. */ -struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route, - int timeout_msec) +struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route) { struct cfg_reset_pkg request = { .header = tb_cfg_make_header(route) }; struct tb_cfg_result res = { 0 }; @@ -831,7 +834,7 @@ struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route, req->response_size = sizeof(reply); req->response_type = TB_CFG_PKG_RESET; - res = tb_cfg_request_sync(ctl, req, timeout_msec); + res = tb_cfg_request_sync(ctl, req, ctl->timeout_msec); tb_cfg_request_put(req); @@ -1007,7 +1010,7 @@ int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port, enum tb_cfg_space space, u32 offset, u32 length) { struct tb_cfg_result res = tb_cfg_read_raw(ctl, buffer, route, port, - space, offset, length, TB_CFG_DEFAULT_TIMEOUT); + space, offset, length, ctl->timeout_msec); switch (res.err) { case 0: /* Success */ @@ -1033,7 +1036,7 @@ int tb_cfg_write(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port, enum tb_cfg_space space, u32 offset, u32 length) { struct tb_cfg_result res = tb_cfg_write_raw(ctl, buffer, route, port, - space, offset, length, TB_CFG_DEFAULT_TIMEOUT); + space, offset, length, ctl->timeout_msec); switch (res.err) { case 0: /* Success */ @@ -1071,7 +1074,7 @@ int tb_cfg_get_upstream_port(struct tb_ctl *ctl, u64 route) u32 dummy; struct tb_cfg_result res = tb_cfg_read_raw(ctl, &dummy, route, 0, TB_CFG_SWITCH, 0, 1, - TB_CFG_DEFAULT_TIMEOUT); + ctl->timeout_msec); if (res.err == 1) return -EIO; if (res.err) diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h index 97cb03b38953112cbe6aa6112ee1b3d60aa3f89e..e8c64898dfce6e3442a001b46156d854a1e035ac 100644 --- a/drivers/thunderbolt/ctl.h +++ b/drivers/thunderbolt/ctl.h @@ -21,15 +21,14 @@ struct tb_ctl; typedef bool (*event_cb)(void *data, enum tb_cfg_pkg_type type, const void *buf, size_t size); -struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data); +struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int timeout_msec, event_cb cb, + void *cb_data); void tb_ctl_start(struct tb_ctl *ctl); void tb_ctl_stop(struct tb_ctl *ctl); void tb_ctl_free(struct tb_ctl *ctl); /* configuration commands */ -#define TB_CFG_DEFAULT_TIMEOUT 5000 /* msec */ - struct tb_cfg_result { u64 response_route; u32 response_port; /* @@ -124,8 +123,7 @@ static inline struct tb_cfg_header tb_cfg_make_header(u64 route) } int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug); -struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route, - int timeout_msec); +struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route); struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer, u64 route, u32 port, enum tb_cfg_space space, u32 offset, diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c index 9541d7409ab101b8c38f0f7067c4ae64b4097c27..c850b0ac098c7171309ccf7680b80e77433bc686 100644 --- a/drivers/thunderbolt/debugfs.c +++ b/drivers/thunderbolt/debugfs.c @@ -251,6 +251,29 @@ out: return ret < 0 ? ret : count; } +static void cap_show_by_dw(struct seq_file *s, struct tb_switch *sw, + struct tb_port *port, unsigned int cap, + unsigned int offset, u8 cap_id, u8 vsec_id, + int dwords) +{ + int i, ret; + u32 data; + + for (i = 0; i < dwords; i++) { + if (port) + ret = tb_port_read(port, &data, TB_CFG_PORT, cap + offset + i, 1); + else + ret = tb_sw_read(sw, &data, TB_CFG_SWITCH, cap + offset + i, 1); + if (ret) { + seq_printf(s, "0x%04x <not accessible>\n", cap + offset + i); + continue; + } + + seq_printf(s, "0x%04x %4d 0x%02x 0x%02x 0x%08x\n", cap + offset + i, + offset + i, cap_id, vsec_id, data); + } +} + static void cap_show(struct seq_file *s, struct tb_switch *sw, struct tb_port *port, unsigned int cap, u8 cap_id, u8 vsec_id, int length) @@ -267,10 +290,7 @@ static void cap_show(struct seq_file *s, struct tb_switch *sw, else ret = tb_sw_read(sw, data, TB_CFG_SWITCH, cap + offset, dwords); if (ret) { - seq_printf(s, "0x%04x <not accessible>\n", - cap + offset); - if (dwords > 1) - seq_printf(s, "0x%04x ...\n", cap + offset + 1); + cap_show_by_dw(s, sw, port, cap, offset, cap_id, vsec_id, length); return; } @@ -341,15 +361,6 @@ static void port_cap_show(struct tb_port *port, struct seq_file *s, } else { length = header.extended_short.length; vsec_id = header.extended_short.vsec_id; - /* - * Ice Lake and Tiger Lake do not implement the - * full length of the capability, only first 32 - * dwords so hard-code it here. - */ - if (!vsec_id && - (tb_switch_is_ice_lake(port->sw) || - tb_switch_is_tiger_lake(port->sw))) - length = 32; } break; diff --git a/drivers/thunderbolt/dma_test.c b/drivers/thunderbolt/dma_test.c index 6debaf5a660490f652e63e6274524850979500f0..3bedecb236e0d15f67e9c09586eddb008276c87a 100644 --- a/drivers/thunderbolt/dma_test.c +++ b/drivers/thunderbolt/dma_test.c @@ -13,7 +13,6 @@ #include <linux/sizes.h> #include <linux/thunderbolt.h> -#define DMA_TEST_HOPID 8 #define DMA_TEST_TX_RING_SIZE 64 #define DMA_TEST_RX_RING_SIZE 256 #define DMA_TEST_FRAME_SIZE SZ_4K @@ -72,7 +71,9 @@ static const char * const dma_test_result_names[] = { * @svc: XDomain service the driver is bound to * @xd: XDomain the service belongs to * @rx_ring: Software ring holding RX frames + * @rx_hopid: HopID used for receiving frames * @tx_ring: Software ring holding TX frames + * @tx_hopid: HopID used for sending fames * @packets_to_send: Number of packets to send * @packets_to_receive: Number of packets to receive * @packets_sent: Actual number of packets sent @@ -92,7 +93,9 @@ struct dma_test { const struct tb_service *svc; struct tb_xdomain *xd; struct tb_ring *rx_ring; + int rx_hopid; struct tb_ring *tx_ring; + int tx_hopid; unsigned int packets_to_send; unsigned int packets_to_receive; unsigned int packets_sent; @@ -119,10 +122,12 @@ static void *dma_test_pattern; static void dma_test_free_rings(struct dma_test *dt) { if (dt->rx_ring) { + tb_xdomain_release_in_hopid(dt->xd, dt->rx_hopid); tb_ring_free(dt->rx_ring); dt->rx_ring = NULL; } if (dt->tx_ring) { + tb_xdomain_release_out_hopid(dt->xd, dt->tx_hopid); tb_ring_free(dt->tx_ring); dt->tx_ring = NULL; } @@ -151,6 +156,14 @@ static int dma_test_start_rings(struct dma_test *dt) dt->tx_ring = ring; e2e_tx_hop = ring->hop; + + ret = tb_xdomain_alloc_out_hopid(xd, -1); + if (ret < 0) { + dma_test_free_rings(dt); + return ret; + } + + dt->tx_hopid = ret; } if (dt->packets_to_receive) { @@ -168,11 +181,19 @@ static int dma_test_start_rings(struct dma_test *dt) } dt->rx_ring = ring; + + ret = tb_xdomain_alloc_in_hopid(xd, -1); + if (ret < 0) { + dma_test_free_rings(dt); + return ret; + } + + dt->rx_hopid = ret; } - ret = tb_xdomain_enable_paths(dt->xd, DMA_TEST_HOPID, + ret = tb_xdomain_enable_paths(dt->xd, dt->tx_hopid, dt->tx_ring ? dt->tx_ring->hop : 0, - DMA_TEST_HOPID, + dt->rx_hopid, dt->rx_ring ? dt->rx_ring->hop : 0); if (ret) { dma_test_free_rings(dt); @@ -189,12 +210,18 @@ static int dma_test_start_rings(struct dma_test *dt) static void dma_test_stop_rings(struct dma_test *dt) { + int ret; + if (dt->rx_ring) tb_ring_stop(dt->rx_ring); if (dt->tx_ring) tb_ring_stop(dt->tx_ring); - if (tb_xdomain_disable_paths(dt->xd)) + ret = tb_xdomain_disable_paths(dt->xd, dt->tx_hopid, + dt->tx_ring ? dt->tx_ring->hop : 0, + dt->rx_hopid, + dt->rx_ring ? dt->rx_ring->hop : 0); + if (ret) dev_warn(&dt->svc->dev, "failed to disable DMA paths\n"); dma_test_free_rings(dt); diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 89ae614eaba240465cd03dcd9a64d226a2c2f606..98f4056f89ffe7b6f6d544eb9a25feb806f157e8 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -341,9 +341,34 @@ struct device_type tb_domain_type = { .release = tb_domain_release, }; +static bool tb_domain_event_cb(void *data, enum tb_cfg_pkg_type type, + const void *buf, size_t size) +{ + struct tb *tb = data; + + if (!tb->cm_ops->handle_event) { + tb_warn(tb, "domain does not have event handler\n"); + return true; + } + + switch (type) { + case TB_CFG_PKG_XDOMAIN_REQ: + case TB_CFG_PKG_XDOMAIN_RESP: + if (tb_is_xdomain_enabled()) + return tb_xdomain_handle_request(tb, type, buf, size); + break; + + default: + tb->cm_ops->handle_event(tb, type, buf, size); + } + + return true; +} + /** * tb_domain_alloc() - Allocate a domain * @nhi: Pointer to the host controller + * @timeout_msec: Control channel timeout for non-raw messages * @privsize: Size of the connection manager private data * * Allocates and initializes a new Thunderbolt domain. Connection @@ -355,7 +380,7 @@ struct device_type tb_domain_type = { * * Return: allocated domain structure on %NULL in case of error */ -struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize) +struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize) { struct tb *tb; @@ -382,6 +407,10 @@ struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize) if (!tb->wq) goto err_remove_ida; + tb->ctl = tb_ctl_alloc(nhi, timeout_msec, tb_domain_event_cb, tb); + if (!tb->ctl) + goto err_destroy_wq; + tb->dev.parent = &nhi->pdev->dev; tb->dev.bus = &tb_bus_type; tb->dev.type = &tb_domain_type; @@ -391,6 +420,8 @@ struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize) return tb; +err_destroy_wq: + destroy_workqueue(tb->wq); err_remove_ida: ida_simple_remove(&tb_domain_ida, tb->index); err_free: @@ -399,30 +430,6 @@ err_free: return NULL; } -static bool tb_domain_event_cb(void *data, enum tb_cfg_pkg_type type, - const void *buf, size_t size) -{ - struct tb *tb = data; - - if (!tb->cm_ops->handle_event) { - tb_warn(tb, "domain does not have event handler\n"); - return true; - } - - switch (type) { - case TB_CFG_PKG_XDOMAIN_REQ: - case TB_CFG_PKG_XDOMAIN_RESP: - if (tb_is_xdomain_enabled()) - return tb_xdomain_handle_request(tb, type, buf, size); - break; - - default: - tb->cm_ops->handle_event(tb, type, buf, size); - } - - return true; -} - /** * tb_domain_add() - Add domain to the system * @tb: Domain to add @@ -442,13 +449,6 @@ int tb_domain_add(struct tb *tb) return -EINVAL; mutex_lock(&tb->lock); - - tb->ctl = tb_ctl_alloc(tb->nhi, tb_domain_event_cb, tb); - if (!tb->ctl) { - ret = -ENOMEM; - goto err_unlock; - } - /* * tb_schedule_hotplug_handler may be called as soon as the config * channel is started. Thats why we have to hold the lock here. @@ -493,7 +493,6 @@ err_domain_del: device_del(&tb->dev); err_ctl_stop: tb_ctl_stop(tb->ctl); -err_unlock: mutex_unlock(&tb->lock); return ret; @@ -793,6 +792,10 @@ int tb_domain_disconnect_pcie_paths(struct tb *tb) * tb_domain_approve_xdomain_paths() - Enable DMA paths for XDomain * @tb: Domain enabling the DMA paths * @xd: XDomain DMA paths are created to + * @transmit_path: HopID we are using to send out packets + * @transmit_ring: DMA ring used to send out packets + * @receive_path: HopID the other end is using to send packets to us + * @receive_ring: DMA ring used to receive packets from @receive_path * * Calls connection manager specific method to enable DMA paths to the * XDomain in question. @@ -801,18 +804,25 @@ int tb_domain_disconnect_pcie_paths(struct tb *tb) * particular returns %-ENOTSUPP if the connection manager * implementation does not support XDomains. */ -int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { if (!tb->cm_ops->approve_xdomain_paths) return -ENOTSUPP; - return tb->cm_ops->approve_xdomain_paths(tb, xd); + return tb->cm_ops->approve_xdomain_paths(tb, xd, transmit_path, + transmit_ring, receive_path, receive_ring); } /** * tb_domain_disconnect_xdomain_paths() - Disable DMA paths for XDomain * @tb: Domain disabling the DMA paths * @xd: XDomain whose DMA paths are disconnected + * @transmit_path: HopID we are using to send out packets + * @transmit_ring: DMA ring used to send out packets + * @receive_path: HopID the other end is using to send packets to us + * @receive_ring: DMA ring used to receive packets from @receive_path * * Calls connection manager specific method to disconnect DMA paths to * the XDomain in question. @@ -821,12 +831,15 @@ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) * particular returns %-ENOTSUPP if the connection manager * implementation does not support XDomains. */ -int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { if (!tb->cm_ops->disconnect_xdomain_paths) return -ENOTSUPP; - return tb->cm_ops->disconnect_xdomain_paths(tb, xd); + return tb->cm_ops->disconnect_xdomain_paths(tb, xd, transmit_path, + transmit_ring, receive_path, receive_ring); } static int disconnect_xdomain(struct device *dev, void *data) @@ -837,7 +850,7 @@ static int disconnect_xdomain(struct device *dev, void *data) xd = tb_to_xdomain(dev); if (xd && xd->tb == tb) - ret = tb_xdomain_disable_paths(xd); + ret = tb_xdomain_disable_all_paths(xd); return ret; } diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index dd03d309665313d4901e2dd38990483304bd96c2..46d0906a30707447af395e8ad700dfbd302ad6d6 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -277,6 +277,16 @@ struct tb_drom_entry_port { u8 unknown4:2; } __packed; +/* USB4 product descriptor */ +struct tb_drom_entry_desc { + struct tb_drom_entry_header header; + u16 bcdUSBSpec; + u16 idVendor; + u16 idProduct; + u16 bcdProductFWRevision; + u32 TID; + u8 productHWRevision; +}; /** * tb_drom_read_uid_only() - Read UID directly from DROM @@ -329,6 +339,16 @@ static int tb_drom_parse_entry_generic(struct tb_switch *sw, if (!sw->device_name) return -ENOMEM; break; + case 9: { + const struct tb_drom_entry_desc *desc = + (const struct tb_drom_entry_desc *)entry; + + if (!sw->vendor && !sw->device) { + sw->vendor = desc->idVendor; + sw->device = desc->idProduct; + } + break; + } } return 0; @@ -521,6 +541,51 @@ static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val, return tb_eeprom_read_n(sw, offset, val, count); } +static int tb_drom_parse(struct tb_switch *sw) +{ + const struct tb_drom_header *header = + (const struct tb_drom_header *)sw->drom; + u32 crc; + + crc = tb_crc8((u8 *) &header->uid, 8); + if (crc != header->uid_crc8) { + tb_sw_warn(sw, + "DROM UID CRC8 mismatch (expected: %#x, got: %#x), aborting\n", + header->uid_crc8, crc); + return -EINVAL; + } + if (!sw->uid) + sw->uid = header->uid; + sw->vendor = header->vendor_id; + sw->device = header->model_id; + + crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); + if (crc != header->data_crc32) { + tb_sw_warn(sw, + "DROM data CRC32 mismatch (expected: %#x, got: %#x), continuing\n", + header->data_crc32, crc); + } + + return tb_drom_parse_entries(sw); +} + +static int usb4_drom_parse(struct tb_switch *sw) +{ + const struct tb_drom_header *header = + (const struct tb_drom_header *)sw->drom; + u32 crc; + + crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); + if (crc != header->data_crc32) { + tb_sw_warn(sw, + "DROM data CRC32 mismatch (expected: %#x, got: %#x), aborting\n", + header->data_crc32, crc); + return -EINVAL; + } + + return tb_drom_parse_entries(sw); +} + /** * tb_drom_read() - Copy DROM to sw->drom and parse it * @sw: Router whose DROM to read and parse @@ -534,7 +599,6 @@ static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val, int tb_drom_read(struct tb_switch *sw) { u16 size; - u32 crc; struct tb_drom_header *header; int res, retries = 1; @@ -599,31 +663,21 @@ parse: goto err; } - crc = tb_crc8((u8 *) &header->uid, 8); - if (crc != header->uid_crc8) { - tb_sw_warn(sw, - "drom uid crc8 mismatch (expected: %#x, got: %#x), aborting\n", - header->uid_crc8, crc); - goto err; - } - if (!sw->uid) - sw->uid = header->uid; - sw->vendor = header->vendor_id; - sw->device = header->model_id; - tb_check_quirks(sw); + tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision); - crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); - if (crc != header->data_crc32) { - tb_sw_warn(sw, - "drom data crc32 mismatch (expected: %#x, got: %#x), continuing\n", - header->data_crc32, crc); + switch (header->device_rom_revision) { + case 3: + res = usb4_drom_parse(sw); + break; + default: + tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n", + header->device_rom_revision); + fallthrough; + case 1: + res = tb_drom_parse(sw); + break; } - if (header->device_rom_revision > 2) - tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n", - header->device_rom_revision); - - res = tb_drom_parse_entries(sw); /* If the DROM parsing fails, wait a moment and retry once */ if (res == -EILSEQ && retries--) { tb_sw_warn(sw, "parsing DROM failed, retrying\n"); @@ -633,10 +687,11 @@ parse: goto parse; } - return res; + if (!res) + return 0; + err: kfree(sw->drom); sw->drom = NULL; return -EIO; - } diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index f6f605d48371208efe8cca5f4ee5eefa4a0835db..2f30b816705a28ba1ab2853ca04ffd6a711ae8a7 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -557,7 +557,9 @@ static int icm_fr_challenge_switch_key(struct tb *tb, struct tb_switch *sw, return 0; } -static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { struct icm_fr_pkg_approve_xdomain_response reply; struct icm_fr_pkg_approve_xdomain request; @@ -568,10 +570,10 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) request.link_info = xd->depth << ICM_LINK_INFO_DEPTH_SHIFT | xd->link; memcpy(&request.remote_uuid, xd->remote_uuid, sizeof(*xd->remote_uuid)); - request.transmit_path = xd->transmit_path; - request.transmit_ring = xd->transmit_ring; - request.receive_path = xd->receive_path; - request.receive_ring = xd->receive_ring; + request.transmit_path = transmit_path; + request.transmit_ring = transmit_ring; + request.receive_path = receive_path; + request.receive_ring = receive_ring; memset(&reply, 0, sizeof(reply)); ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply), @@ -585,7 +587,9 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) return 0; } -static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { u8 phy_port; u8 cmd; @@ -1122,7 +1126,9 @@ static int icm_tr_challenge_switch_key(struct tb *tb, struct tb_switch *sw, return 0; } -static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { struct icm_tr_pkg_approve_xdomain_response reply; struct icm_tr_pkg_approve_xdomain request; @@ -1132,10 +1138,10 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) request.hdr.code = ICM_APPROVE_XDOMAIN; request.route_hi = upper_32_bits(xd->route); request.route_lo = lower_32_bits(xd->route); - request.transmit_path = xd->transmit_path; - request.transmit_ring = xd->transmit_ring; - request.receive_path = xd->receive_path; - request.receive_ring = xd->receive_ring; + request.transmit_path = transmit_path; + request.transmit_ring = transmit_ring; + request.receive_path = receive_path; + request.receive_ring = receive_ring; memcpy(&request.remote_uuid, xd->remote_uuid, sizeof(*xd->remote_uuid)); memset(&reply, 0, sizeof(reply)); @@ -1176,7 +1182,9 @@ static int icm_tr_xdomain_tear_down(struct tb *tb, struct tb_xdomain *xd, return 0; } -static int icm_tr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static int icm_tr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { int ret; @@ -2416,7 +2424,7 @@ struct tb *icm_probe(struct tb_nhi *nhi) struct icm *icm; struct tb *tb; - tb = tb_domain_alloc(nhi, sizeof(struct icm)); + tb = tb_domain_alloc(nhi, ICM_TIMEOUT, sizeof(struct icm)); if (!tb) return NULL; diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c index d5b0cdb8f0b1e838c76eedbf05189df07546e815..dc555cda98e680d251175f14e967a9ea270f473c 100644 --- a/drivers/thunderbolt/property.c +++ b/drivers/thunderbolt/property.c @@ -501,6 +501,77 @@ ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, return ret < 0 ? ret : 0; } +/** + * tb_property_copy_dir() - Take a deep copy of directory + * @dir: Directory to copy + * + * This function takes a deep copy of @dir and returns back the copy. In + * case of error returns %NULL. The resulting directory needs to be + * released by calling tb_property_free_dir(). + */ +struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir) +{ + struct tb_property *property, *p = NULL; + struct tb_property_dir *d; + + if (!dir) + return NULL; + + d = tb_property_create_dir(dir->uuid); + if (!d) + return NULL; + + list_for_each_entry(property, &dir->properties, list) { + struct tb_property *p; + + p = tb_property_alloc(property->key, property->type); + if (!p) + goto err_free; + + p->length = property->length; + + switch (property->type) { + case TB_PROPERTY_TYPE_DIRECTORY: + p->value.dir = tb_property_copy_dir(property->value.dir); + if (!p->value.dir) + goto err_free; + break; + + case TB_PROPERTY_TYPE_DATA: + p->value.data = kmemdup(property->value.data, + property->length * 4, + GFP_KERNEL); + if (!p->value.data) + goto err_free; + break; + + case TB_PROPERTY_TYPE_TEXT: + p->value.text = kzalloc(p->length * 4, GFP_KERNEL); + if (!p->value.text) + goto err_free; + strcpy(p->value.text, property->value.text); + break; + + case TB_PROPERTY_TYPE_VALUE: + p->value.immediate = property->value.immediate; + break; + + default: + break; + } + + list_add_tail(&p->list, &d->properties); + } + + return d; + +err_free: + kfree(p); + tb_property_free_dir(d); + + return NULL; +} + /** * tb_property_add_immediate() - Add immediate property to directory * @parent: Directory to add the property diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 2a95b4ce06c0b9c765e0d39475c5ba0b09991a70..e73cd296db7ef5497368b71935c147c09d3a0701 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -626,28 +626,6 @@ int tb_port_add_nfc_credits(struct tb_port *port, int credits) TB_CFG_PORT, ADP_CS_4, 1); } -/** - * tb_port_set_initial_credits() - Set initial port link credits allocated - * @port: Port to set the initial credits - * @credits: Number of credits to to allocate - * - * Set initial credits value to be used for ingress shared buffering. - */ -int tb_port_set_initial_credits(struct tb_port *port, u32 credits) -{ - u32 data; - int ret; - - ret = tb_port_read(port, &data, TB_CFG_PORT, ADP_CS_5, 1); - if (ret) - return ret; - - data &= ~ADP_CS_5_LCA_MASK; - data |= (credits << ADP_CS_5_LCA_SHIFT) & ADP_CS_5_LCA_MASK; - - return tb_port_write(port, &data, TB_CFG_PORT, ADP_CS_5, 1); -} - /** * tb_port_clear_counter() - clear a counter in TB_CFG_COUNTER * @port: Port whose counters to clear @@ -1331,7 +1309,7 @@ int tb_switch_reset(struct tb_switch *sw) TB_CFG_SWITCH, 2, 2); if (res.err) return res.err; - res = tb_cfg_reset(sw->tb->ctl, tb_route(sw), TB_CFG_DEFAULT_TIMEOUT); + res = tb_cfg_reset(sw->tb->ctl, tb_route(sw)); if (res.err > 0) return -EIO; return res.err; @@ -1762,6 +1740,18 @@ static struct attribute *switch_attrs[] = { NULL, }; +static bool has_port(const struct tb_switch *sw, enum tb_port_type type) +{ + const struct tb_port *port; + + tb_switch_for_each_port(sw, port) { + if (!port->disabled && port->config.type == type) + return true; + } + + return false; +} + static umode_t switch_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { @@ -1770,7 +1760,8 @@ static umode_t switch_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_authorized.attr) { if (sw->tb->security_level == TB_SECURITY_NOPCIE || - sw->tb->security_level == TB_SECURITY_DPONLY) + sw->tb->security_level == TB_SECURITY_DPONLY || + !has_port(sw, TB_TYPE_PCIE_UP)) return 0; } else if (attr == &dev_attr_device.attr) { if (!sw->device) @@ -1849,6 +1840,39 @@ static void tb_switch_release(struct device *dev) kfree(sw); } +static int tb_switch_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct tb_switch *sw = tb_to_switch(dev); + const char *type; + + if (sw->config.thunderbolt_version == USB4_VERSION_1_0) { + if (add_uevent_var(env, "USB4_VERSION=1.0")) + return -ENOMEM; + } + + if (!tb_route(sw)) { + type = "host"; + } else { + const struct tb_port *port; + bool hub = false; + + /* Device is hub if it has any downstream ports */ + tb_switch_for_each_port(sw, port) { + if (!port->disabled && !tb_is_upstream_port(port) && + tb_port_is_null(port)) { + hub = true; + break; + } + } + + type = hub ? "hub" : "device"; + } + + if (add_uevent_var(env, "USB4_TYPE=%s", type)) + return -ENOMEM; + return 0; +} + /* * Currently only need to provide the callbacks. Everything else is handled * in the connection manager. @@ -1882,6 +1906,7 @@ static const struct dev_pm_ops tb_switch_pm_ops = { struct device_type tb_switch_type = { .name = "thunderbolt_device", .release = tb_switch_release, + .uevent = tb_switch_uevent, .pm = &tb_switch_pm_ops, }; @@ -2542,6 +2567,8 @@ int tb_switch_add(struct tb_switch *sw) } tb_sw_dbg(sw, "uid: %#llx\n", sw->uid); + tb_check_quirks(sw); + ret = tb_switch_set_uuid(sw); if (ret) { dev_err(&sw->dev, "failed to set UUID\n"); diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index c348b1fc0efc3f84477f1a02921118e274cf300f..7e6dc2b03bedc578244e74e9c5985e9b8777121c 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -15,6 +15,8 @@ #include "tb_regs.h" #include "tunnel.h" +#define TB_TIMEOUT 100 /* ms */ + /** * struct tb_cm - Simple Thunderbolt connection manager * @tunnel_list: List of active tunnels @@ -1077,7 +1079,9 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw) return 0; } -static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { struct tb_cm *tcm = tb_priv(tb); struct tb_port *nhi_port, *dst_port; @@ -1089,9 +1093,8 @@ static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) nhi_port = tb_switch_find_port(tb->root_switch, TB_TYPE_NHI); mutex_lock(&tb->lock); - tunnel = tb_tunnel_alloc_dma(tb, nhi_port, dst_port, xd->transmit_ring, - xd->transmit_path, xd->receive_ring, - xd->receive_path); + tunnel = tb_tunnel_alloc_dma(tb, nhi_port, dst_port, transmit_path, + transmit_ring, receive_path, receive_ring); if (!tunnel) { mutex_unlock(&tb->lock); return -ENOMEM; @@ -1110,29 +1113,40 @@ static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) return 0; } -static void __tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static void __tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { - struct tb_port *dst_port; - struct tb_tunnel *tunnel; + struct tb_cm *tcm = tb_priv(tb); + struct tb_port *nhi_port, *dst_port; + struct tb_tunnel *tunnel, *n; struct tb_switch *sw; sw = tb_to_switch(xd->dev.parent); dst_port = tb_port_at(xd->route, sw); + nhi_port = tb_switch_find_port(tb->root_switch, TB_TYPE_NHI); - /* - * It is possible that the tunnel was already teared down (in - * case of cable disconnect) so it is fine if we cannot find it - * here anymore. - */ - tunnel = tb_find_tunnel(tb, TB_TUNNEL_DMA, NULL, dst_port); - tb_deactivate_and_free_tunnel(tunnel); + list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { + if (!tb_tunnel_is_dma(tunnel)) + continue; + if (tunnel->src_port != nhi_port || tunnel->dst_port != dst_port) + continue; + + if (tb_tunnel_match_dma(tunnel, transmit_path, transmit_ring, + receive_path, receive_ring)) + tb_deactivate_and_free_tunnel(tunnel); + } } -static int tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) +static int tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring) { if (!xd->is_unplugged) { mutex_lock(&tb->lock); - __tb_disconnect_xdomain_paths(tb, xd); + __tb_disconnect_xdomain_paths(tb, xd, transmit_path, + transmit_ring, receive_path, + receive_ring); mutex_unlock(&tb->lock); } return 0; @@ -1208,12 +1222,12 @@ static void tb_handle_hotplug(struct work_struct *work) * tb_xdomain_remove() so setting XDomain as * unplugged here prevents deadlock if they call * tb_xdomain_disable_paths(). We will tear down - * the path below. + * all the tunnels below. */ xd->is_unplugged = true; tb_xdomain_remove(xd); port->xdomain = NULL; - __tb_disconnect_xdomain_paths(tb, xd); + __tb_disconnect_xdomain_paths(tb, xd, -1, -1, -1, -1); tb_xdomain_put(xd); tb_port_unconfigure_xdomain(port); } else if (tb_port_is_dpout(port) || tb_port_is_dpin(port)) { @@ -1562,7 +1576,7 @@ struct tb *tb_probe(struct tb_nhi *nhi) struct tb_cm *tcm; struct tb *tb; - tb = tb_domain_alloc(nhi, sizeof(*tcm)); + tb = tb_domain_alloc(nhi, TB_TIMEOUT, sizeof(*tcm)); if (!tb) return NULL; diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index beea88c34c0f30b296f4fd91f74e347c2c4daf41..9790e9f13d2be8b32a221a2372517b79bcec4f58 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -406,8 +406,12 @@ struct tb_cm_ops { int (*challenge_switch_key)(struct tb *tb, struct tb_switch *sw, const u8 *challenge, u8 *response); int (*disconnect_pcie_paths)(struct tb *tb); - int (*approve_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd); - int (*disconnect_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd); + int (*approve_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring); + int (*disconnect_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring); int (*usb4_switch_op)(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_data_len, void *rx_data, size_t rx_data_len); @@ -625,7 +629,7 @@ void tb_domain_exit(void); int tb_xdomain_init(void); void tb_xdomain_exit(void); -struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize); +struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize); int tb_domain_add(struct tb *tb); void tb_domain_remove(struct tb *tb); int tb_domain_suspend_noirq(struct tb *tb); @@ -641,8 +645,12 @@ int tb_domain_approve_switch(struct tb *tb, struct tb_switch *sw); int tb_domain_approve_switch_key(struct tb *tb, struct tb_switch *sw); int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw); int tb_domain_disconnect_pcie_paths(struct tb *tb); -int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd); -int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd); +int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring); +int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, + int transmit_path, int transmit_ring, + int receive_path, int receive_ring); int tb_domain_disconnect_all_paths(struct tb *tb); static inline struct tb *tb_domain_get(struct tb *tb) @@ -787,32 +795,6 @@ static inline bool tb_switch_is_titan_ridge(const struct tb_switch *sw) return false; } -static inline bool tb_switch_is_ice_lake(const struct tb_switch *sw) -{ - if (sw->config.vendor_id == PCI_VENDOR_ID_INTEL) { - switch (sw->config.device_id) { - case PCI_DEVICE_ID_INTEL_ICL_NHI0: - case PCI_DEVICE_ID_INTEL_ICL_NHI1: - return true; - } - } - return false; -} - -static inline bool tb_switch_is_tiger_lake(const struct tb_switch *sw) -{ - if (sw->config.vendor_id == PCI_VENDOR_ID_INTEL) { - switch (sw->config.device_id) { - case PCI_DEVICE_ID_INTEL_TGL_NHI0: - case PCI_DEVICE_ID_INTEL_TGL_NHI1: - case PCI_DEVICE_ID_INTEL_TGL_H_NHI0: - case PCI_DEVICE_ID_INTEL_TGL_H_NHI1: - return true; - } - } - return false; -} - /** * tb_switch_is_usb4() - Is the switch USB4 compliant * @sw: Switch to check @@ -860,7 +842,6 @@ static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw) int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged); int tb_port_add_nfc_credits(struct tb_port *port, int credits); -int tb_port_set_initial_credits(struct tb_port *port, u32 credits); int tb_port_clear_counter(struct tb_port *port, int counter); int tb_port_unlock(struct tb_port *port); int tb_port_enable(struct tb_port *port); diff --git a/drivers/thunderbolt/test.c b/drivers/thunderbolt/test.c index 464c2d37b992e507b0ca76a907ac8d1e4a46c8a0..5ff5a03bc9ceffed7f6c38ab7d3786cc727f6a30 100644 --- a/drivers/thunderbolt/test.c +++ b/drivers/thunderbolt/test.c @@ -119,6 +119,7 @@ static struct tb_switch *alloc_host(struct kunit *test) sw->ports[7].config.type = TB_TYPE_NHI; sw->ports[7].config.max_in_hop_id = 11; sw->ports[7].config.max_out_hop_id = 11; + sw->ports[7].config.nfc_credits = 0x41800000; sw->ports[8].config.type = TB_TYPE_PCIE_DOWN; sw->ports[8].config.max_in_hop_id = 8; @@ -1594,6 +1595,489 @@ static void tb_test_tunnel_port_on_path(struct kunit *test) tb_tunnel_free(dp_tunnel); } +static void tb_test_tunnel_dma(struct kunit *test) +{ + struct tb_port *nhi, *port; + struct tb_tunnel *tunnel; + struct tb_switch *host; + + /* + * Create DMA tunnel from NHI to port 1 and back. + * + * [Host 1] + * 1 ^ In HopID 1 -> Out HopID 8 + * | + * v In HopID 8 -> Out HopID 1 + * ............ Domain border + * | + * [Host 2] + */ + host = alloc_host(test); + nhi = &host->ports[7]; + port = &host->ports[1]; + + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2); + /* RX path */ + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 8); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, nhi); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].next_hop_index, 1); + /* TX path */ + KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 1); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, nhi); + KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[0].in_hop_index, 1); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].out_port, port); + KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[0].next_hop_index, 8); + + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dma_rx(struct kunit *test) +{ + struct tb_port *nhi, *port; + struct tb_tunnel *tunnel; + struct tb_switch *host; + + /* + * Create DMA RX tunnel from port 1 to NHI. + * + * [Host 1] + * 1 ^ + * | + * | In HopID 15 -> Out HopID 2 + * ............ Domain border + * | + * [Host 2] + */ + host = alloc_host(test); + nhi = &host->ports[7]; + port = &host->ports[1]; + + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, -1, -1, 15, 2); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)1); + /* RX path */ + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 15); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, nhi); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].next_hop_index, 2); + + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dma_tx(struct kunit *test) +{ + struct tb_port *nhi, *port; + struct tb_tunnel *tunnel; + struct tb_switch *host; + + /* + * Create DMA TX tunnel from NHI to port 1. + * + * [Host 1] + * 1 | In HopID 2 -> Out HopID 15 + * | + * v + * ............ Domain border + * | + * [Host 2] + */ + host = alloc_host(test); + nhi = &host->ports[7]; + port = &host->ports[1]; + + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 2, -1, -1); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)1); + /* TX path */ + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, nhi); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, port); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].next_hop_index, 15); + + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dma_chain(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2; + struct tb_port *nhi, *port; + struct tb_tunnel *tunnel; + + /* + * Create DMA tunnel from NHI to Device #2 port 3 and back. + * + * [Host 1] + * 1 ^ In HopID 1 -> Out HopID x + * | + * 1 | In HopID x -> Out HopID 1 + * [Device #1] + * 7 \ + * 1 \ + * [Device #2] + * 3 | In HopID x -> Out HopID 8 + * | + * v In HopID 8 -> Out HopID x + * ............ Domain border + * | + * [Host 2] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x701, true); + + nhi = &host->ports[7]; + port = &dev2->ports[3]; + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2); + /* RX path */ + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 3); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 8); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, + &dev2->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].in_port, + &dev1->ports[7]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].out_port, + &dev1->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].in_port, + &host->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].out_port, nhi); + KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[2].next_hop_index, 1); + /* TX path */ + KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 3); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, nhi); + KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[0].in_hop_index, 1); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[1].in_port, + &dev1->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[1].out_port, + &dev1->ports[7]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[2].in_port, + &dev2->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[2].out_port, port); + KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[2].next_hop_index, 8); + + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dma_match(struct kunit *test) +{ + struct tb_port *nhi, *port; + struct tb_tunnel *tunnel; + struct tb_switch *host; + + host = alloc_host(test); + nhi = &host->ports[7]; + port = &host->ports[1]; + + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 1, 15, 1); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, 1, 15, 1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 8, 1, 15, 1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, 1, -1, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, -1, -1, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, 1, -1, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, 1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, -1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 8, -1, 8, -1)); + + tb_tunnel_free(tunnel); + + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 1, -1, -1); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, 1, -1, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, -1, -1, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, 1, -1, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, -1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 15, 1, 15, 1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 15, 11, -1, -1)); + + tb_tunnel_free(tunnel); + + tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, -1, -1, 15, 11); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 11)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, -1)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, 11)); + KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, -1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 1)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, -1, -1, 10, 11)); + KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 15, 11, -1, -1)); + + tb_tunnel_free(tunnel); +} + +static const u32 root_directory[] = { + 0x55584401, /* "UXD" v1 */ + 0x00000018, /* Root directory length */ + 0x76656e64, /* "vend" */ + 0x6f726964, /* "orid" */ + 0x76000001, /* "v" R 1 */ + 0x00000a27, /* Immediate value, ! Vendor ID */ + 0x76656e64, /* "vend" */ + 0x6f726964, /* "orid" */ + 0x74000003, /* "t" R 3 */ + 0x0000001a, /* Text leaf offset, (“Apple Inc.”) */ + 0x64657669, /* "devi" */ + 0x63656964, /* "ceid" */ + 0x76000001, /* "v" R 1 */ + 0x0000000a, /* Immediate value, ! Device ID */ + 0x64657669, /* "devi" */ + 0x63656964, /* "ceid" */ + 0x74000003, /* "t" R 3 */ + 0x0000001d, /* Text leaf offset, (“Macintosh”) */ + 0x64657669, /* "devi" */ + 0x63657276, /* "cerv" */ + 0x76000001, /* "v" R 1 */ + 0x80000100, /* Immediate value, Device Revision */ + 0x6e657477, /* "netw" */ + 0x6f726b00, /* "ork" */ + 0x44000014, /* "D" R 20 */ + 0x00000021, /* Directory data offset, (Network Directory) */ + 0x4170706c, /* "Appl" */ + 0x6520496e, /* "e In" */ + 0x632e0000, /* "c." ! */ + 0x4d616369, /* "Maci" */ + 0x6e746f73, /* "ntos" */ + 0x68000000, /* "h" */ + 0x00000000, /* padding */ + 0xca8961c6, /* Directory UUID, Network Directory */ + 0x9541ce1c, /* Directory UUID, Network Directory */ + 0x5949b8bd, /* Directory UUID, Network Directory */ + 0x4f5a5f2e, /* Directory UUID, Network Directory */ + 0x70727463, /* "prtc" */ + 0x69640000, /* "id" */ + 0x76000001, /* "v" R 1 */ + 0x00000001, /* Immediate value, Network Protocol ID */ + 0x70727463, /* "prtc" */ + 0x76657273, /* "vers" */ + 0x76000001, /* "v" R 1 */ + 0x00000001, /* Immediate value, Network Protocol Version */ + 0x70727463, /* "prtc" */ + 0x72657673, /* "revs" */ + 0x76000001, /* "v" R 1 */ + 0x00000001, /* Immediate value, Network Protocol Revision */ + 0x70727463, /* "prtc" */ + 0x73746e73, /* "stns" */ + 0x76000001, /* "v" R 1 */ + 0x00000000, /* Immediate value, Network Protocol Settings */ +}; + +static const uuid_t network_dir_uuid = + UUID_INIT(0xc66189ca, 0x1cce, 0x4195, + 0xbd, 0xb8, 0x49, 0x59, 0x2e, 0x5f, 0x5a, 0x4f); + +static void tb_test_property_parse(struct kunit *test) +{ + struct tb_property_dir *dir, *network_dir; + struct tb_property *p; + + dir = tb_property_parse_dir(root_directory, ARRAY_SIZE(root_directory)); + KUNIT_ASSERT_TRUE(test, dir != NULL); + + p = tb_property_find(dir, "foo", TB_PROPERTY_TYPE_TEXT); + KUNIT_ASSERT_TRUE(test, !p); + + p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_TEXT); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_STREQ(test, p->value.text, "Apple Inc."); + + p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_VALUE); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0xa27); + + p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_TEXT); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_STREQ(test, p->value.text, "Macintosh"); + + p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_VALUE); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0xa); + + p = tb_property_find(dir, "missing", TB_PROPERTY_TYPE_DIRECTORY); + KUNIT_ASSERT_TRUE(test, !p); + + p = tb_property_find(dir, "network", TB_PROPERTY_TYPE_DIRECTORY); + KUNIT_ASSERT_TRUE(test, p != NULL); + + network_dir = p->value.dir; + KUNIT_EXPECT_TRUE(test, uuid_equal(network_dir->uuid, &network_dir_uuid)); + + p = tb_property_find(network_dir, "prtcid", TB_PROPERTY_TYPE_VALUE); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x1); + + p = tb_property_find(network_dir, "prtcvers", TB_PROPERTY_TYPE_VALUE); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x1); + + p = tb_property_find(network_dir, "prtcrevs", TB_PROPERTY_TYPE_VALUE); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x1); + + p = tb_property_find(network_dir, "prtcstns", TB_PROPERTY_TYPE_VALUE); + KUNIT_ASSERT_TRUE(test, p != NULL); + KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x0); + + p = tb_property_find(network_dir, "deviceid", TB_PROPERTY_TYPE_VALUE); + KUNIT_EXPECT_TRUE(test, !p); + p = tb_property_find(network_dir, "deviceid", TB_PROPERTY_TYPE_TEXT); + KUNIT_EXPECT_TRUE(test, !p); + + tb_property_free_dir(dir); +} + +static void tb_test_property_format(struct kunit *test) +{ + struct tb_property_dir *dir; + ssize_t block_len; + u32 *block; + int ret, i; + + dir = tb_property_parse_dir(root_directory, ARRAY_SIZE(root_directory)); + KUNIT_ASSERT_TRUE(test, dir != NULL); + + ret = tb_property_format_dir(dir, NULL, 0); + KUNIT_ASSERT_EQ(test, ret, (int)ARRAY_SIZE(root_directory)); + + block_len = ret; + + block = kunit_kzalloc(test, block_len * sizeof(u32), GFP_KERNEL); + KUNIT_ASSERT_TRUE(test, block != NULL); + + ret = tb_property_format_dir(dir, block, block_len); + KUNIT_EXPECT_EQ(test, ret, 0); + + for (i = 0; i < ARRAY_SIZE(root_directory); i++) + KUNIT_EXPECT_EQ(test, root_directory[i], block[i]); + + tb_property_free_dir(dir); +} + +static void compare_dirs(struct kunit *test, struct tb_property_dir *d1, + struct tb_property_dir *d2) +{ + struct tb_property *p1, *p2, *tmp; + int n1, n2, i; + + if (d1->uuid) { + KUNIT_ASSERT_TRUE(test, d2->uuid != NULL); + KUNIT_ASSERT_TRUE(test, uuid_equal(d1->uuid, d2->uuid)); + } else { + KUNIT_ASSERT_TRUE(test, d2->uuid == NULL); + } + + n1 = 0; + tb_property_for_each(d1, tmp) + n1++; + KUNIT_ASSERT_NE(test, n1, 0); + + n2 = 0; + tb_property_for_each(d2, tmp) + n2++; + KUNIT_ASSERT_NE(test, n2, 0); + + KUNIT_ASSERT_EQ(test, n1, n2); + + p1 = NULL; + p2 = NULL; + for (i = 0; i < n1; i++) { + p1 = tb_property_get_next(d1, p1); + KUNIT_ASSERT_TRUE(test, p1 != NULL); + p2 = tb_property_get_next(d2, p2); + KUNIT_ASSERT_TRUE(test, p2 != NULL); + + KUNIT_ASSERT_STREQ(test, &p1->key[0], &p2->key[0]); + KUNIT_ASSERT_EQ(test, p1->type, p2->type); + KUNIT_ASSERT_EQ(test, p1->length, p2->length); + + switch (p1->type) { + case TB_PROPERTY_TYPE_DIRECTORY: + KUNIT_ASSERT_TRUE(test, p1->value.dir != NULL); + KUNIT_ASSERT_TRUE(test, p2->value.dir != NULL); + compare_dirs(test, p1->value.dir, p2->value.dir); + break; + + case TB_PROPERTY_TYPE_DATA: + KUNIT_ASSERT_TRUE(test, p1->value.data != NULL); + KUNIT_ASSERT_TRUE(test, p2->value.data != NULL); + KUNIT_ASSERT_TRUE(test, + !memcmp(p1->value.data, p2->value.data, + p1->length * 4) + ); + break; + + case TB_PROPERTY_TYPE_TEXT: + KUNIT_ASSERT_TRUE(test, p1->value.text != NULL); + KUNIT_ASSERT_TRUE(test, p2->value.text != NULL); + KUNIT_ASSERT_STREQ(test, p1->value.text, p2->value.text); + break; + + case TB_PROPERTY_TYPE_VALUE: + KUNIT_ASSERT_EQ(test, p1->value.immediate, + p2->value.immediate); + break; + default: + KUNIT_FAIL(test, "unexpected property type"); + break; + } + } +} + +static void tb_test_property_copy(struct kunit *test) +{ + struct tb_property_dir *src, *dst; + u32 *block; + int ret, i; + + src = tb_property_parse_dir(root_directory, ARRAY_SIZE(root_directory)); + KUNIT_ASSERT_TRUE(test, src != NULL); + + dst = tb_property_copy_dir(src); + KUNIT_ASSERT_TRUE(test, dst != NULL); + + /* Compare the structures */ + compare_dirs(test, src, dst); + + /* Compare the resulting property block */ + ret = tb_property_format_dir(dst, NULL, 0); + KUNIT_ASSERT_EQ(test, ret, (int)ARRAY_SIZE(root_directory)); + + block = kunit_kzalloc(test, sizeof(root_directory), GFP_KERNEL); + KUNIT_ASSERT_TRUE(test, block != NULL); + + ret = tb_property_format_dir(dst, block, ARRAY_SIZE(root_directory)); + KUNIT_EXPECT_TRUE(test, !ret); + + for (i = 0; i < ARRAY_SIZE(root_directory); i++) + KUNIT_EXPECT_EQ(test, root_directory[i], block[i]); + + tb_property_free_dir(dst); + tb_property_free_dir(src); +} + static struct kunit_case tb_test_cases[] = { KUNIT_CASE(tb_test_path_basic), KUNIT_CASE(tb_test_path_not_connected_walk), @@ -1616,6 +2100,14 @@ static struct kunit_case tb_test_cases[] = { KUNIT_CASE(tb_test_tunnel_dp_max_length), KUNIT_CASE(tb_test_tunnel_port_on_path), KUNIT_CASE(tb_test_tunnel_usb3), + KUNIT_CASE(tb_test_tunnel_dma), + KUNIT_CASE(tb_test_tunnel_dma_rx), + KUNIT_CASE(tb_test_tunnel_dma_tx), + KUNIT_CASE(tb_test_tunnel_dma_chain), + KUNIT_CASE(tb_test_tunnel_dma_match), + KUNIT_CASE(tb_test_property_parse), + KUNIT_CASE(tb_test_property_format), + KUNIT_CASE(tb_test_property_copy), { } }; diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 6557b6e070098ae40aa862369f7c3d0539be0a1c..e1979bed7146f14829bf97223b4b7ca77508aae9 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -794,24 +794,14 @@ static u32 tb_dma_credits(struct tb_port *nhi) return min(max_credits, 13U); } -static int tb_dma_activate(struct tb_tunnel *tunnel, bool active) -{ - struct tb_port *nhi = tunnel->src_port; - u32 credits; - - credits = active ? tb_dma_credits(nhi) : 0; - return tb_port_set_initial_credits(nhi, credits); -} - -static void tb_dma_init_path(struct tb_path *path, unsigned int isb, - unsigned int efc, u32 credits) +static void tb_dma_init_path(struct tb_path *path, unsigned int efc, u32 credits) { int i; path->egress_fc_enable = efc; path->ingress_fc_enable = TB_PATH_ALL; path->egress_shared_buffer = TB_PATH_NONE; - path->ingress_shared_buffer = isb; + path->ingress_shared_buffer = TB_PATH_NONE; path->priority = 5; path->weight = 1; path->clear_fc = true; @@ -825,28 +815,28 @@ static void tb_dma_init_path(struct tb_path *path, unsigned int isb, * @tb: Pointer to the domain structure * @nhi: Host controller port * @dst: Destination null port which the other domain is connected to - * @transmit_ring: NHI ring number used to send packets towards the - * other domain. Set to %0 if TX path is not needed. * @transmit_path: HopID used for transmitting packets - * @receive_ring: NHI ring number used to receive packets from the - * other domain. Set to %0 if RX path is not needed. + * @transmit_ring: NHI ring number used to send packets towards the + * other domain. Set to %-1 if TX path is not needed. * @receive_path: HopID used for receiving packets + * @receive_ring: NHI ring number used to receive packets from the + * other domain. Set to %-1 if RX path is not needed. * * Return: Returns a tb_tunnel on success or NULL on failure. */ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, - struct tb_port *dst, int transmit_ring, - int transmit_path, int receive_ring, - int receive_path) + struct tb_port *dst, int transmit_path, + int transmit_ring, int receive_path, + int receive_ring) { struct tb_tunnel *tunnel; size_t npaths = 0, i = 0; struct tb_path *path; u32 credits; - if (receive_ring) + if (receive_ring > 0) npaths++; - if (transmit_ring) + if (transmit_ring > 0) npaths++; if (WARN_ON(!npaths)) @@ -856,38 +846,96 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, if (!tunnel) return NULL; - tunnel->activate = tb_dma_activate; tunnel->src_port = nhi; tunnel->dst_port = dst; credits = tb_dma_credits(nhi); - if (receive_ring) { + if (receive_ring > 0) { path = tb_path_alloc(tb, dst, receive_path, nhi, receive_ring, 0, "DMA RX"); if (!path) { tb_tunnel_free(tunnel); return NULL; } - tb_dma_init_path(path, TB_PATH_NONE, TB_PATH_SOURCE | TB_PATH_INTERNAL, - credits); + tb_dma_init_path(path, TB_PATH_SOURCE | TB_PATH_INTERNAL, credits); tunnel->paths[i++] = path; } - if (transmit_ring) { + if (transmit_ring > 0) { path = tb_path_alloc(tb, nhi, transmit_ring, dst, transmit_path, 0, "DMA TX"); if (!path) { tb_tunnel_free(tunnel); return NULL; } - tb_dma_init_path(path, TB_PATH_SOURCE, TB_PATH_ALL, credits); + tb_dma_init_path(path, TB_PATH_ALL, credits); tunnel->paths[i++] = path; } return tunnel; } +/** + * tb_tunnel_match_dma() - Match DMA tunnel + * @tunnel: Tunnel to match + * @transmit_path: HopID used for transmitting packets. Pass %-1 to ignore. + * @transmit_ring: NHI ring number used to send packets towards the + * other domain. Pass %-1 to ignore. + * @receive_path: HopID used for receiving packets. Pass %-1 to ignore. + * @receive_ring: NHI ring number used to receive packets from the + * other domain. Pass %-1 to ignore. + * + * This function can be used to match specific DMA tunnel, if there are + * multiple DMA tunnels going through the same XDomain connection. + * Returns true if there is match and false otherwise. + */ +bool tb_tunnel_match_dma(const struct tb_tunnel *tunnel, int transmit_path, + int transmit_ring, int receive_path, int receive_ring) +{ + const struct tb_path *tx_path = NULL, *rx_path = NULL; + int i; + + if (!receive_ring || !transmit_ring) + return false; + + for (i = 0; i < tunnel->npaths; i++) { + const struct tb_path *path = tunnel->paths[i]; + + if (!path) + continue; + + if (tb_port_is_nhi(path->hops[0].in_port)) + tx_path = path; + else if (tb_port_is_nhi(path->hops[path->path_length - 1].out_port)) + rx_path = path; + } + + if (transmit_ring > 0 || transmit_path > 0) { + if (!tx_path) + return false; + if (transmit_ring > 0 && + (tx_path->hops[0].in_hop_index != transmit_ring)) + return false; + if (transmit_path > 0 && + (tx_path->hops[tx_path->path_length - 1].next_hop_index != transmit_path)) + return false; + } + + if (receive_ring > 0 || receive_path > 0) { + if (!rx_path) + return false; + if (receive_path > 0 && + (rx_path->hops[0].in_hop_index != receive_path)) + return false; + if (receive_ring > 0 && + (rx_path->hops[rx_path->path_length - 1].next_hop_index != receive_ring)) + return false; + } + + return true; +} + static int tb_usb3_max_link_rate(struct tb_port *up, struct tb_port *down) { int ret, up_max_rate, down_max_rate; diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h index 1d2a64eb060d54409b088984a8e801247f205e3f..a66994fb4e600d05553257c46bec4556833f6743 100644 --- a/drivers/thunderbolt/tunnel.h +++ b/drivers/thunderbolt/tunnel.h @@ -70,9 +70,11 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, struct tb_port *out, int max_up, int max_down); struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, - struct tb_port *dst, int transmit_ring, - int transmit_path, int receive_ring, - int receive_path); + struct tb_port *dst, int transmit_path, + int transmit_ring, int receive_path, + int receive_ring); +bool tb_tunnel_match_dma(const struct tb_tunnel *tunnel, int transmit_path, + int transmit_ring, int receive_path, int receive_ring); struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down); struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, struct tb_port *down, int max_up, diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index 7cf8b9c85ab7df97cf94a09ed9a0f79a3df6a4bd..b21d99d59412510a5d6d12aa579f587f026a26b2 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -12,17 +12,19 @@ #include <linux/kmod.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/prandom.h> #include <linux/utsname.h> #include <linux/uuid.h> #include <linux/workqueue.h> #include "tb.h" -#define XDOMAIN_DEFAULT_TIMEOUT 5000 /* ms */ +#define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */ #define XDOMAIN_UUID_RETRIES 10 -#define XDOMAIN_PROPERTIES_RETRIES 60 +#define XDOMAIN_PROPERTIES_RETRIES 10 #define XDOMAIN_PROPERTIES_CHANGED_RETRIES 10 #define XDOMAIN_BONDING_WAIT 100 /* ms */ +#define XDOMAIN_DEFAULT_MAX_HOPID 15 struct xdomain_request_work { struct work_struct work; @@ -34,13 +36,15 @@ static bool tb_xdomain_enabled = true; module_param_named(xdomain, tb_xdomain_enabled, bool, 0444); MODULE_PARM_DESC(xdomain, "allow XDomain protocol (default: true)"); -/* Serializes access to the properties and protocol handlers below */ +/* + * Serializes access to the properties and protocol handlers below. If + * you need to take both this lock and the struct tb_xdomain lock, take + * this one first. + */ static DEFINE_MUTEX(xdomain_lock); /* Properties exposed to the remote domains */ static struct tb_property_dir *xdomain_property_dir; -static u32 *xdomain_property_block; -static u32 xdomain_property_block_len; static u32 xdomain_property_block_gen; /* Additional protocol handlers */ @@ -385,8 +389,7 @@ err: } static int tb_xdp_properties_response(struct tb *tb, struct tb_ctl *ctl, - u64 route, u8 sequence, const uuid_t *src_uuid, - const struct tb_xdp_properties *req) + struct tb_xdomain *xd, u8 sequence, const struct tb_xdp_properties *req) { struct tb_xdp_properties_response *res; size_t total_size; @@ -398,39 +401,39 @@ static int tb_xdp_properties_response(struct tb *tb, struct tb_ctl *ctl, * protocol supports forwarding, though which we might add * support later on. */ - if (!uuid_equal(src_uuid, &req->dst_uuid)) { - tb_xdp_error_response(ctl, route, sequence, + if (!uuid_equal(xd->local_uuid, &req->dst_uuid)) { + tb_xdp_error_response(ctl, xd->route, sequence, ERROR_UNKNOWN_DOMAIN); return 0; } - mutex_lock(&xdomain_lock); + mutex_lock(&xd->lock); - if (req->offset >= xdomain_property_block_len) { - mutex_unlock(&xdomain_lock); + if (req->offset >= xd->local_property_block_len) { + mutex_unlock(&xd->lock); return -EINVAL; } - len = xdomain_property_block_len - req->offset; + len = xd->local_property_block_len - req->offset; len = min_t(u16, len, TB_XDP_PROPERTIES_MAX_DATA_LENGTH); total_size = sizeof(*res) + len * 4; res = kzalloc(total_size, GFP_KERNEL); if (!res) { - mutex_unlock(&xdomain_lock); + mutex_unlock(&xd->lock); return -ENOMEM; } - tb_xdp_fill_header(&res->hdr, route, sequence, PROPERTIES_RESPONSE, + tb_xdp_fill_header(&res->hdr, xd->route, sequence, PROPERTIES_RESPONSE, total_size); - res->generation = xdomain_property_block_gen; - res->data_length = xdomain_property_block_len; + res->generation = xd->local_property_block_gen; + res->data_length = xd->local_property_block_len; res->offset = req->offset; - uuid_copy(&res->src_uuid, src_uuid); + uuid_copy(&res->src_uuid, xd->local_uuid); uuid_copy(&res->dst_uuid, &req->src_uuid); - memcpy(res->data, &xdomain_property_block[req->offset], len * 4); + memcpy(res->data, &xd->local_property_block[req->offset], len * 4); - mutex_unlock(&xdomain_lock); + mutex_unlock(&xd->lock); ret = __tb_xdomain_response(ctl, res, total_size, TB_CFG_PKG_XDOMAIN_RESP); @@ -512,52 +515,63 @@ void tb_unregister_protocol_handler(struct tb_protocol_handler *handler) } EXPORT_SYMBOL_GPL(tb_unregister_protocol_handler); -static int rebuild_property_block(void) +static void update_property_block(struct tb_xdomain *xd) { - u32 *block, len; - int ret; - - ret = tb_property_format_dir(xdomain_property_dir, NULL, 0); - if (ret < 0) - return ret; - - len = ret; - - block = kcalloc(len, sizeof(u32), GFP_KERNEL); - if (!block) - return -ENOMEM; + mutex_lock(&xdomain_lock); + mutex_lock(&xd->lock); + /* + * If the local property block is not up-to-date, rebuild it now + * based on the global property template. + */ + if (!xd->local_property_block || + xd->local_property_block_gen < xdomain_property_block_gen) { + struct tb_property_dir *dir; + int ret, block_len; + u32 *block; + + dir = tb_property_copy_dir(xdomain_property_dir); + if (!dir) { + dev_warn(&xd->dev, "failed to copy properties\n"); + goto out_unlock; + } - ret = tb_property_format_dir(xdomain_property_dir, block, len); - if (ret) { - kfree(block); - return ret; - } + /* Fill in non-static properties now */ + tb_property_add_text(dir, "deviceid", utsname()->nodename); + tb_property_add_immediate(dir, "maxhopid", xd->local_max_hopid); - kfree(xdomain_property_block); - xdomain_property_block = block; - xdomain_property_block_len = len; - xdomain_property_block_gen++; + ret = tb_property_format_dir(dir, NULL, 0); + if (ret < 0) { + dev_warn(&xd->dev, "local property block creation failed\n"); + tb_property_free_dir(dir); + goto out_unlock; + } - return 0; -} + block_len = ret; + block = kcalloc(block_len, sizeof(*block), GFP_KERNEL); + if (!block) { + tb_property_free_dir(dir); + goto out_unlock; + } -static void finalize_property_block(void) -{ - const struct tb_property *nodename; + ret = tb_property_format_dir(dir, block, block_len); + if (ret) { + dev_warn(&xd->dev, "property block generation failed\n"); + tb_property_free_dir(dir); + kfree(block); + goto out_unlock; + } - /* - * On first XDomain connection we set up the the system - * nodename. This delayed here because userspace may not have it - * set when the driver is first probed. - */ - mutex_lock(&xdomain_lock); - nodename = tb_property_find(xdomain_property_dir, "deviceid", - TB_PROPERTY_TYPE_TEXT); - if (!nodename) { - tb_property_add_text(xdomain_property_dir, "deviceid", - utsname()->nodename); - rebuild_property_block(); + tb_property_free_dir(dir); + /* Release the previous block */ + kfree(xd->local_property_block); + /* Assign new one */ + xd->local_property_block = block; + xd->local_property_block_len = block_len; + xd->local_property_block_gen = xdomain_property_block_gen; } + +out_unlock: + mutex_unlock(&xd->lock); mutex_unlock(&xdomain_lock); } @@ -568,6 +582,7 @@ static void tb_xdp_handle_request(struct work_struct *work) const struct tb_xdomain_header *xhdr = &pkg->xd_hdr; struct tb *tb = xw->tb; struct tb_ctl *ctl = tb->ctl; + struct tb_xdomain *xd; const uuid_t *uuid; int ret = 0; u32 sequence; @@ -589,17 +604,21 @@ static void tb_xdp_handle_request(struct work_struct *work) goto out; } - finalize_property_block(); + tb_dbg(tb, "%llx: received XDomain request %#x\n", route, pkg->type); + + xd = tb_xdomain_find_by_route_locked(tb, route); + if (xd) + update_property_block(xd); switch (pkg->type) { case PROPERTIES_REQUEST: - ret = tb_xdp_properties_response(tb, ctl, route, sequence, uuid, - (const struct tb_xdp_properties *)pkg); + if (xd) { + ret = tb_xdp_properties_response(tb, ctl, xd, sequence, + (const struct tb_xdp_properties *)pkg); + } break; - case PROPERTIES_CHANGED_REQUEST: { - struct tb_xdomain *xd; - + case PROPERTIES_CHANGED_REQUEST: ret = tb_xdp_properties_changed_response(ctl, route, sequence); /* @@ -607,17 +626,11 @@ static void tb_xdp_handle_request(struct work_struct *work) * the xdomain related to this connection as well in * case there is a change in services it offers. */ - xd = tb_xdomain_find_by_route_locked(tb, route); - if (xd) { - if (device_is_registered(&xd->dev)) { - queue_delayed_work(tb->wq, &xd->get_properties_work, - msecs_to_jiffies(50)); - } - tb_xdomain_put(xd); + if (xd && device_is_registered(&xd->dev)) { + queue_delayed_work(tb->wq, &xd->get_properties_work, + msecs_to_jiffies(50)); } - break; - } case UUID_REQUEST_OLD: case UUID_REQUEST: @@ -630,6 +643,8 @@ static void tb_xdp_handle_request(struct work_struct *work) break; } + tb_xdomain_put(xd); + if (ret) { tb_warn(tb, "failed to send XDomain response for %#x\n", pkg->type); @@ -811,7 +826,7 @@ static int remove_missing_service(struct device *dev, void *data) if (!svc) return 0; - if (!tb_property_find(xd->properties, svc->key, + if (!tb_property_find(xd->remote_properties, svc->key, TB_PROPERTY_TYPE_DIRECTORY)) device_unregister(dev); @@ -871,7 +886,7 @@ static void enumerate_services(struct tb_xdomain *xd) device_for_each_child_reverse(&xd->dev, xd, remove_missing_service); /* Then re-enumerate properties creating new services as we go */ - tb_property_for_each(xd->properties, p) { + tb_property_for_each(xd->remote_properties, p) { if (p->type != TB_PROPERTY_TYPE_DIRECTORY) continue; @@ -928,6 +943,14 @@ static int populate_properties(struct tb_xdomain *xd, return -EINVAL; xd->vendor = p->value.immediate; + p = tb_property_find(dir, "maxhopid", TB_PROPERTY_TYPE_VALUE); + /* + * USB4 inter-domain spec suggests using 15 as HopID if the + * other end does not announce it in a property. This is for + * TBT3 compatibility. + */ + xd->remote_max_hopid = p ? p->value.immediate : XDOMAIN_DEFAULT_MAX_HOPID; + kfree(xd->device_name); xd->device_name = NULL; kfree(xd->vendor_name); @@ -944,19 +967,6 @@ static int populate_properties(struct tb_xdomain *xd, return 0; } -/* Called with @xd->lock held */ -static void tb_xdomain_restore_paths(struct tb_xdomain *xd) -{ - if (!xd->resume) - return; - - xd->resume = false; - if (xd->transmit_path) { - dev_dbg(&xd->dev, "re-establishing DMA path\n"); - tb_domain_approve_xdomain_paths(xd->tb, xd); - } -} - static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd) { return tb_to_switch(xd->dev.parent); @@ -1002,9 +1012,12 @@ static void tb_xdomain_get_uuid(struct work_struct *work) uuid_t uuid; int ret; + dev_dbg(&xd->dev, "requesting remote UUID\n"); + ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->uuid_retries, &uuid); if (ret < 0) { if (xd->uuid_retries-- > 0) { + dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); queue_delayed_work(xd->tb->wq, &xd->get_uuid_work, msecs_to_jiffies(100)); } else { @@ -1013,6 +1026,8 @@ static void tb_xdomain_get_uuid(struct work_struct *work) return; } + dev_dbg(&xd->dev, "got remote UUID %pUb\n", &uuid); + if (uuid_equal(&uuid, xd->local_uuid)) dev_dbg(&xd->dev, "intra-domain loop detected\n"); @@ -1052,11 +1067,15 @@ static void tb_xdomain_get_properties(struct work_struct *work) u32 gen = 0; int ret; + dev_dbg(&xd->dev, "requesting remote properties\n"); + ret = tb_xdp_properties_request(tb->ctl, xd->route, xd->local_uuid, xd->remote_uuid, xd->properties_retries, &block, &gen); if (ret < 0) { if (xd->properties_retries-- > 0) { + dev_dbg(&xd->dev, + "failed to request remote properties, retrying\n"); queue_delayed_work(xd->tb->wq, &xd->get_properties_work, msecs_to_jiffies(1000)); } else { @@ -1073,16 +1092,8 @@ static void tb_xdomain_get_properties(struct work_struct *work) mutex_lock(&xd->lock); /* Only accept newer generation properties */ - if (xd->properties && gen <= xd->property_block_gen) { - /* - * On resume it is likely that the properties block is - * not changed (unless the other end added or removed - * services). However, we need to make sure the existing - * DMA paths are restored properly. - */ - tb_xdomain_restore_paths(xd); + if (xd->remote_properties && gen <= xd->remote_property_block_gen) goto err_free_block; - } dir = tb_property_parse_dir(block, ret); if (!dir) { @@ -1097,18 +1108,16 @@ static void tb_xdomain_get_properties(struct work_struct *work) } /* Release the existing one */ - if (xd->properties) { - tb_property_free_dir(xd->properties); + if (xd->remote_properties) { + tb_property_free_dir(xd->remote_properties); update = true; } - xd->properties = dir; - xd->property_block_gen = gen; + xd->remote_properties = dir; + xd->remote_property_block_gen = gen; tb_xdomain_update_link_attributes(xd); - tb_xdomain_restore_paths(xd); - mutex_unlock(&xd->lock); kfree(block); @@ -1123,6 +1132,11 @@ static void tb_xdomain_get_properties(struct work_struct *work) dev_err(&xd->dev, "failed to add XDomain device\n"); return; } + dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n", + xd->vendor, xd->device); + if (xd->vendor_name && xd->device_name) + dev_info(&xd->dev, "%s %s\n", xd->vendor_name, + xd->device_name); } else { kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE); } @@ -1143,13 +1157,19 @@ static void tb_xdomain_properties_changed(struct work_struct *work) properties_changed_work.work); int ret; + dev_dbg(&xd->dev, "sending properties changed notification\n"); + ret = tb_xdp_properties_changed_request(xd->tb->ctl, xd->route, xd->properties_changed_retries, xd->local_uuid); if (ret) { - if (xd->properties_changed_retries-- > 0) + if (xd->properties_changed_retries-- > 0) { + dev_dbg(&xd->dev, + "failed to send properties changed notification, retrying\n"); queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, msecs_to_jiffies(1000)); + } + dev_err(&xd->dev, "failed to send properties changed notification\n"); return; } @@ -1180,6 +1200,15 @@ device_name_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(device_name); +static ssize_t maxhopid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); + + return sprintf(buf, "%d\n", xd->remote_max_hopid); +} +static DEVICE_ATTR_RO(maxhopid); + static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1238,6 +1267,7 @@ static DEVICE_ATTR(tx_lanes, 0444, lanes_show, NULL); static struct attribute *xdomain_attrs[] = { &dev_attr_device.attr, &dev_attr_device_name.attr, + &dev_attr_maxhopid.attr, &dev_attr_rx_lanes.attr, &dev_attr_rx_speed.attr, &dev_attr_tx_lanes.attr, @@ -1263,7 +1293,10 @@ static void tb_xdomain_release(struct device *dev) put_device(xd->dev.parent); - tb_property_free_dir(xd->properties); + kfree(xd->local_property_block); + tb_property_free_dir(xd->remote_properties); + ida_destroy(&xd->out_hopids); + ida_destroy(&xd->in_hopids); ida_destroy(&xd->service_ids); kfree(xd->local_uuid); @@ -1310,15 +1343,7 @@ static int __maybe_unused tb_xdomain_suspend(struct device *dev) static int __maybe_unused tb_xdomain_resume(struct device *dev) { - struct tb_xdomain *xd = tb_to_xdomain(dev); - - /* - * Ask tb_xdomain_get_properties() restore any existing DMA - * paths after properties are re-read. - */ - xd->resume = true; - start_handshake(xd); - + start_handshake(tb_to_xdomain(dev)); return 0; } @@ -1363,7 +1388,10 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, xd->tb = tb; xd->route = route; + xd->local_max_hopid = down->config.max_in_hop_id; ida_init(&xd->service_ids); + ida_init(&xd->in_hopids); + ida_init(&xd->out_hopids); mutex_init(&xd->lock); INIT_DELAYED_WORK(&xd->get_uuid_work, tb_xdomain_get_uuid); INIT_DELAYED_WORK(&xd->get_properties_work, tb_xdomain_get_properties); @@ -1390,6 +1418,10 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, xd->dev.groups = xdomain_attr_groups; dev_set_name(&xd->dev, "%u-%llx", tb->index, route); + dev_dbg(&xd->dev, "local UUID %pUb\n", local_uuid); + if (remote_uuid) + dev_dbg(&xd->dev, "remote UUID %pUb\n", remote_uuid); + /* * This keeps the DMA powered on as long as we have active * connection to another host. @@ -1452,10 +1484,12 @@ void tb_xdomain_remove(struct tb_xdomain *xd) pm_runtime_put_noidle(&xd->dev); pm_runtime_set_suspended(&xd->dev); - if (!device_is_registered(&xd->dev)) + if (!device_is_registered(&xd->dev)) { put_device(&xd->dev); - else + } else { + dev_info(&xd->dev, "host disconnected\n"); device_unregister(&xd->dev); + } } /** @@ -1523,73 +1557,118 @@ void tb_xdomain_lane_bonding_disable(struct tb_xdomain *xd) EXPORT_SYMBOL_GPL(tb_xdomain_lane_bonding_disable); /** - * tb_xdomain_enable_paths() - Enable DMA paths for XDomain connection + * tb_xdomain_alloc_in_hopid() - Allocate input HopID for tunneling * @xd: XDomain connection - * @transmit_path: HopID of the transmit path the other end is using to - * send packets - * @transmit_ring: DMA ring used to receive packets from the other end - * @receive_path: HopID of the receive path the other end is using to - * receive packets - * @receive_ring: DMA ring used to send packets to the other end + * @hopid: Preferred HopID or %-1 for next available * - * The function enables DMA paths accordingly so that after successful - * return the caller can send and receive packets using high-speed DMA - * path. - * - * Return: %0 in case of success and negative errno in case of error + * Returns allocated HopID or negative errno. Specifically returns + * %-ENOSPC if there are no more available HopIDs. Returned HopID is + * guaranteed to be within range supported by the input lane adapter. + * Call tb_xdomain_release_in_hopid() to release the allocated HopID. */ -int tb_xdomain_enable_paths(struct tb_xdomain *xd, u16 transmit_path, - u16 transmit_ring, u16 receive_path, - u16 receive_ring) +int tb_xdomain_alloc_in_hopid(struct tb_xdomain *xd, int hopid) { - int ret; + if (hopid < 0) + hopid = TB_PATH_MIN_HOPID; + if (hopid < TB_PATH_MIN_HOPID || hopid > xd->local_max_hopid) + return -EINVAL; - mutex_lock(&xd->lock); + return ida_alloc_range(&xd->in_hopids, hopid, xd->local_max_hopid, + GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(tb_xdomain_alloc_in_hopid); - if (xd->transmit_path) { - ret = xd->transmit_path == transmit_path ? 0 : -EBUSY; - goto exit_unlock; - } +/** + * tb_xdomain_alloc_out_hopid() - Allocate output HopID for tunneling + * @xd: XDomain connection + * @hopid: Preferred HopID or %-1 for next available + * + * Returns allocated HopID or negative errno. Specifically returns + * %-ENOSPC if there are no more available HopIDs. Returned HopID is + * guaranteed to be within range supported by the output lane adapter. + * Call tb_xdomain_release_in_hopid() to release the allocated HopID. + */ +int tb_xdomain_alloc_out_hopid(struct tb_xdomain *xd, int hopid) +{ + if (hopid < 0) + hopid = TB_PATH_MIN_HOPID; + if (hopid < TB_PATH_MIN_HOPID || hopid > xd->remote_max_hopid) + return -EINVAL; - xd->transmit_path = transmit_path; - xd->transmit_ring = transmit_ring; - xd->receive_path = receive_path; - xd->receive_ring = receive_ring; + return ida_alloc_range(&xd->out_hopids, hopid, xd->remote_max_hopid, + GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(tb_xdomain_alloc_out_hopid); - ret = tb_domain_approve_xdomain_paths(xd->tb, xd); +/** + * tb_xdomain_release_in_hopid() - Release input HopID + * @xd: XDomain connection + * @hopid: HopID to release + */ +void tb_xdomain_release_in_hopid(struct tb_xdomain *xd, int hopid) +{ + ida_free(&xd->in_hopids, hopid); +} +EXPORT_SYMBOL_GPL(tb_xdomain_release_in_hopid); -exit_unlock: - mutex_unlock(&xd->lock); +/** + * tb_xdomain_release_out_hopid() - Release output HopID + * @xd: XDomain connection + * @hopid: HopID to release + */ +void tb_xdomain_release_out_hopid(struct tb_xdomain *xd, int hopid) +{ + ida_free(&xd->out_hopids, hopid); +} +EXPORT_SYMBOL_GPL(tb_xdomain_release_out_hopid); - return ret; +/** + * tb_xdomain_enable_paths() - Enable DMA paths for XDomain connection + * @xd: XDomain connection + * @transmit_path: HopID we are using to send out packets + * @transmit_ring: DMA ring used to send out packets + * @receive_path: HopID the other end is using to send packets to us + * @receive_ring: DMA ring used to receive packets from @receive_path + * + * The function enables DMA paths accordingly so that after successful + * return the caller can send and receive packets using high-speed DMA + * path. If a transmit or receive path is not needed, pass %-1 for those + * parameters. + * + * Return: %0 in case of success and negative errno in case of error + */ +int tb_xdomain_enable_paths(struct tb_xdomain *xd, int transmit_path, + int transmit_ring, int receive_path, + int receive_ring) +{ + return tb_domain_approve_xdomain_paths(xd->tb, xd, transmit_path, + transmit_ring, receive_path, + receive_ring); } EXPORT_SYMBOL_GPL(tb_xdomain_enable_paths); /** * tb_xdomain_disable_paths() - Disable DMA paths for XDomain connection * @xd: XDomain connection + * @transmit_path: HopID we are using to send out packets + * @transmit_ring: DMA ring used to send out packets + * @receive_path: HopID the other end is using to send packets to us + * @receive_ring: DMA ring used to receive packets from @receive_path * * This does the opposite of tb_xdomain_enable_paths(). After call to - * this the caller is not expected to use the rings anymore. + * this the caller is not expected to use the rings anymore. Passing %-1 + * as path/ring parameter means don't care. Normally the callers should + * pass the same values here as they do when paths are enabled. * * Return: %0 in case of success and negative errno in case of error */ -int tb_xdomain_disable_paths(struct tb_xdomain *xd) +int tb_xdomain_disable_paths(struct tb_xdomain *xd, int transmit_path, + int transmit_ring, int receive_path, + int receive_ring) { - int ret = 0; - - mutex_lock(&xd->lock); - if (xd->transmit_path) { - xd->transmit_path = 0; - xd->transmit_ring = 0; - xd->receive_path = 0; - xd->receive_ring = 0; - - ret = tb_domain_disconnect_xdomain_paths(xd->tb, xd); - } - mutex_unlock(&xd->lock); - - return ret; + return tb_domain_disconnect_xdomain_paths(xd->tb, xd, transmit_path, + transmit_ring, receive_path, + receive_ring); } EXPORT_SYMBOL_GPL(tb_xdomain_disable_paths); @@ -1826,11 +1905,7 @@ int tb_register_property_dir(const char *key, struct tb_property_dir *dir) if (ret) goto err_unlock; - ret = rebuild_property_block(); - if (ret) { - remove_directory(key, dir); - goto err_unlock; - } + xdomain_property_block_gen++; mutex_unlock(&xdomain_lock); update_all_xdomains(); @@ -1856,7 +1931,7 @@ void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir) mutex_lock(&xdomain_lock); if (remove_directory(key, dir)) - ret = rebuild_property_block(); + xdomain_property_block_gen++; mutex_unlock(&xdomain_lock); if (!ret) @@ -1875,7 +1950,8 @@ int tb_xdomain_init(void) * directories. Those will be added by service drivers * themselves when they are loaded. * - * We also add node name later when first connection is made. + * Rest of the properties are filled dynamically based on these + * when the P2P connection is made. */ tb_property_add_immediate(xdomain_property_dir, "vendorid", PCI_VENDOR_ID_INTEL); @@ -1883,11 +1959,11 @@ int tb_xdomain_init(void) tb_property_add_immediate(xdomain_property_dir, "deviceid", 0x1); tb_property_add_immediate(xdomain_property_dir, "devicerv", 0x80000100); + xdomain_property_block_gen = prandom_u32(); return 0; } void tb_xdomain_exit(void) { - kfree(xdomain_property_block); tb_property_free_dir(xdomain_property_dir); } diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index e15cd6b5bb99a896b21d98506a900d1ab6686cb6..f6a7fd6d3bb6f54359ee5aba97f142c3151aeec0 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -181,7 +181,7 @@ config SERIAL_NONSTANDARD help Say Y here if you have any non-standard serial boards -- boards which aren't supported using the standard "dumb" serial driver. - This includes intelligent serial boards such as Cyclades, + This includes intelligent serial boards such as Digiboards, etc. These are usually used for systems that need many serial ports because they serve many terminals or dial-in connections. @@ -192,50 +192,6 @@ config SERIAL_NONSTANDARD Most people can say N here. -config ROCKETPORT - tristate "Comtrol RocketPort support" - depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) - help - This driver supports Comtrol RocketPort and RocketModem PCI boards. - These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or - modems. For information about the RocketPort/RocketModem boards - and this driver read <file:Documentation/driver-api/serial/rocket.rst>. - - To compile this driver as a module, choose M here: the - module will be called rocket. - - If you want to compile this driver into the kernel, say Y here. If - you don't have a Comtrol RocketPort/RocketModem card installed, say N. - -config CYCLADES - tristate "Cyclades async mux support" - depends on SERIAL_NONSTANDARD && (PCI || ISA) - select FW_LOADER - help - This driver supports Cyclades Z and Y multiserial boards. - You would need something like this to connect more than two modems to - your Linux box, for instance in order to become a dial-in server. - - For information about the Cyclades-Z card, read - <file:Documentation/driver-api/serial/cyclades_z.rst>. - - To compile this driver as a module, choose M here: the - module will be called cyclades. - - If you haven't heard about it, it's safe to say N. - -config CYZ_INTR - bool "Cyclades-Z interrupt mode operation" - depends on CYCLADES && PCI - help - The Cyclades-Z family of multiport cards allows 2 (two) driver op - modes: polling and interrupt. In polling mode, the driver will check - the status of the Cyclades-Z ports every certain amount of time - (which is called polling cycle and is configurable). In interrupt - mode, it will use an interrupt line (IRQ) in order to check the - status of the Cyclades-Z ports. The default op mode is polling. If - unsure, say N. - config MOXA_INTELLIO tristate "Moxa Intellio support" depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) @@ -267,16 +223,6 @@ config SYNCLINK_GT synchronous and asynchronous serial adapters manufactured by Microgate Systems, Ltd. (www.microgate.com) -config ISI - tristate "Multi-Tech multiport card support" - depends on SERIAL_NONSTANDARD && PCI - select FW_LOADER - help - This is a driver for the Multi-Tech cards which provide several - serial ports. The driver is experimental and can currently only be - built as a module. The module will be called isicom. - If you want to do that, choose M here. - config N_HDLC tristate "HDLC line discipline support" depends on SERIAL_NONSTANDARD @@ -415,36 +361,6 @@ config NULL_TTY If unsure, say N. -config TRACE_ROUTER - tristate "Trace data router for MIPI P1149.7 cJTAG standard" - depends on TRACE_SINK - help - The trace router uses the Linux tty line discipline framework to - route trace data coming from a tty port (say UART for example) to - the trace sink line discipline driver and to another tty port (say - USB). This is part of a solution for the MIPI P1149.7, compact JTAG, - standard, which is for debugging mobile devices. The PTI driver in - drivers/misc/pti.c defines the majority of this MIPI solution. - - You should select this driver if the target kernel is meant for - a mobile device containing a modem. Then you will need to select - "Trace data sink for MIPI P1149.7 cJTAG standard" line discipline - driver. - -config TRACE_SINK - tristate "Trace data sink for MIPI P1149.7 cJTAG standard" - help - The trace sink uses the Linux line discipline framework to receive - trace data coming from the trace router line discipline driver - to a user-defined tty port target, like USB. - This is to provide a way to extract modem trace data on - devices that do not have a PTI HW module, or just need modem - trace data to come out of a different HW output port. - This is part of a solution for the P1149.7, compact JTAG, standard. - - If you select this option, you need to select - "Trace data router for MIPI P1149.7 cJTAG standard". - config VCC tristate "Sun Virtual Console Concentrator" depends on SUN_LDOMS diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 730de6bf048bb7f1e1a7d3a131dc7f22f21cb89c..c7054f5117c38f7a3418abf8efd040762d6e063a 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -18,13 +18,10 @@ obj-$(CONFIG_SERIAL_DEV_BUS) += serdev/ # tty drivers obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -obj-$(CONFIG_CYCLADES) += cyclades.o -obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_NULL_TTY) += ttynull.o -obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 18b78ea110ef47ad00a59cd854b7e8e1feebf44c..ca48ce5a0862a128081aaf145bf57f2463dd5f95 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -937,15 +937,21 @@ static void rs_unthrottle(struct tty_struct * tty) static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct serial_state *state = tty->driver_data; + unsigned int close_delay, closing_wait; tty_lock(tty); + close_delay = jiffies_to_msecs(state->tport.close_delay) / 10; + closing_wait = state->tport.closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = jiffies_to_msecs(closing_wait) / 10; + ss->line = tty->index; ss->port = state->port; ss->flags = state->tport.flags; ss->xmit_fifo_size = state->xmit_fifo_size; ss->baud_base = state->baud_base; - ss->close_delay = state->tport.close_delay; - ss->closing_wait = state->tport.closing_wait; + ss->close_delay = close_delay; + ss->closing_wait = closing_wait; ss->custom_divisor = state->custom_divisor; tty_unlock(tty); return 0; @@ -957,6 +963,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) struct tty_port *port = &state->tport; bool change_spd; int retval = 0; + unsigned int close_delay, closing_wait; tty_lock(tty); change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) || @@ -966,10 +973,16 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) tty_unlock(tty); return -EINVAL; } - + + close_delay = msecs_to_jiffies(ss->close_delay * 10); + closing_wait = ss->closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = msecs_to_jiffies(closing_wait * 10); + if (!serial_isroot()) { if ((ss->baud_base != state->baud_base) || - (ss->close_delay != port->close_delay) || + (close_delay != port->close_delay) || + (closing_wait != port->closing_wait) || (ss->xmit_fifo_size != state->xmit_fifo_size) || ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { @@ -996,8 +1009,8 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) port->flags = ((port->flags & ~ASYNC_FLAGS) | (ss->flags & ASYNC_FLAGS)); state->custom_divisor = ss->custom_divisor; - port->close_delay = ss->close_delay * HZ/100; - port->closing_wait = ss->closing_wait * HZ/100; + port->close_delay = close_delay; + port->closing_wait = closing_wait; check_and_exit: if (tty_port_initialized(port)) { @@ -1622,21 +1635,17 @@ fail_put_tty_driver: static int __exit amiga_serial_remove(struct platform_device *pdev) { - int error; struct serial_state *state = platform_get_drvdata(pdev); /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - error = tty_unregister_driver(serial_driver); - if (error) - printk("SERIAL: failed to unregister serial driver (%d)\n", - error); + tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); tty_port_destroy(&state->tport); free_irq(IRQ_AMIGA_TBE, state); free_irq(IRQ_AMIGA_RBF, state); - return error; + return 0; } static struct platform_driver amiga_serial_driver = { diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c deleted file mode 100644 index 097266342e5e3086f158f964a0b9c87021f73884..0000000000000000000000000000000000000000 --- a/drivers/tty/cyclades.c +++ /dev/null @@ -1,4119 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#undef BLOCKMOVE -#define Z_WAKE -#undef Z_EXT_CHARS_IN_BUFFER - -/* - * This file contains the driver for the Cyclades async multiport - * serial boards. - * - * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>. - * Modified and maintained by Marcio Saito <marcio@cyclades.com>. - * - * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com> - * - * Much of the design and some of the code came from serial.c - * which was copyright (C) 1991, 1992 Linus Torvalds. It was - * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, - * and then fixed as suggested by Michael K. Johnson 12/12/92. - * Converted to pci probing and cleaned up by Jiri Slaby. - * - */ - -#define CY_VERSION "2.6" - -/* If you need to install more boards than NR_CARDS, change the constant - in the definition below. No other change is necessary to support up to - eight boards. Beyond that you'll have to extend cy_isa_addresses. */ - -#define NR_CARDS 4 - -/* - If the total number of ports is larger than NR_PORTS, change this - constant in the definition below. No other change is necessary to - support more boards/ports. */ - -#define NR_PORTS 256 - -#define ZO_V1 0 -#define ZO_V2 1 -#define ZE_V1 2 - -#define SERIAL_PARANOIA_CHECK -#undef CY_DEBUG_OPEN -#undef CY_DEBUG_THROTTLE -#undef CY_DEBUG_OTHER -#undef CY_DEBUG_IO -#undef CY_DEBUG_COUNT -#undef CY_DEBUG_DTR -#undef CY_DEBUG_INTERRUPTS -#undef CY_16Y_HACK -#undef CY_ENABLE_MONITORING -#undef CY_PCI_DEBUG - -/* - * Include section - */ -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/cyclades.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/bitops.h> -#include <linux/firmware.h> -#include <linux/device.h> -#include <linux/slab.h> - -#include <linux/io.h> -#include <linux/uaccess.h> - -#include <linux/kernel.h> -#include <linux/pci.h> - -#include <linux/stat.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - -static void cy_send_xchar(struct tty_struct *tty, char ch); - -#ifndef SERIAL_XMIT_SIZE -#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) -#endif - -/* firmware stuff */ -#define ZL_MAX_BLOCKS 16 -#define DRIVER_VERSION 0x02010203 -#define RAM_SIZE 0x80000 - -enum zblock_type { - ZBLOCK_PRG = 0, - ZBLOCK_FPGA = 1 -}; - -struct zfile_header { - char name[64]; - char date[32]; - char aux[32]; - u32 n_config; - u32 config_offset; - u32 n_blocks; - u32 block_offset; - u32 reserved[9]; -} __attribute__ ((packed)); - -struct zfile_config { - char name[64]; - u32 mailbox; - u32 function; - u32 n_blocks; - u32 block_list[ZL_MAX_BLOCKS]; -} __attribute__ ((packed)); - -struct zfile_block { - u32 type; - u32 file_offset; - u32 ram_offset; - u32 size; -} __attribute__ ((packed)); - -static struct tty_driver *cy_serial_driver; - -#ifdef CONFIG_ISA -/* This is the address lookup table. The driver will probe for - Cyclom-Y/ISA boards at all addresses in here. If you want the - driver to probe addresses at a different address, add it to - this table. If the driver is probing some other board and - causing problems, remove the offending address from this table. -*/ - -static unsigned int cy_isa_addresses[] = { - 0xD0000, - 0xD2000, - 0xD4000, - 0xD6000, - 0xD8000, - 0xDA000, - 0xDC000, - 0xDE000, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses) - -static long maddr[NR_CARDS]; -static int irq[NR_CARDS]; - -module_param_hw_array(maddr, long, iomem, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); - -#endif /* CONFIG_ISA */ - -/* This is the per-card data structure containing address, irq, number of - channels, etc. This driver supports a maximum of NR_CARDS cards. -*/ -static struct cyclades_card cy_card[NR_CARDS]; - -static int cy_next_channel; /* next minor available */ - -/* - * This is used to look up the divisor speeds and the timeouts - * We're normally limited to 15 distinct baud rates. The extra - * are accessed via settings in info->port.flags. - * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - * HI VHI - * 20 - */ -static const int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, - 230400, 0 -}; - -static const char baud_co_25[] = { /* 25 MHz clock option table */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, - 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */ - 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, - 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15 -}; - -static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, - 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 -}; - -static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ - 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62, - 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32, - 0x21 -}; - -static const char baud_cor3[] = { /* receive threshold */ - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, - 0x07 -}; - -/* - * The Cyclades driver implements HW flow control as any serial driver. - * The cyclades_port structure member rflow and the vector rflow_thr - * allows us to take advantage of a special feature in the CD1400 to avoid - * data loss even when the system interrupt latency is too high. These flags - * are to be used only with very special applications. Setting these flags - * requires the use of a special cable (DTR and RTS reversed). In the new - * CD1400-based boards (rev. 6.00 or later), there is no need for special - * cables. - */ - -static const char rflow_thr[] = { /* rflow threshold */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a -}; - -/* The Cyclom-Ye has placed the sequential chips in non-sequential - * address order. This look-up table overcomes that problem. - */ -static const unsigned int cy_chip_offset[] = { 0x0000, - 0x0400, - 0x0800, - 0x0C00, - 0x0200, - 0x0600, - 0x0A00, - 0x0E00 -}; - -/* PCI related definitions */ - -#ifdef CONFIG_PCI -static const struct pci_device_id cy_pci_dev_id[] = { - /* PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, - /* PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, - /* 4Y PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, - /* 4Y PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, - /* 8Y PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, - /* 8Y PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, - /* Z PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, - /* Z PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, - { } /* end of table */ -}; -MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); -#endif - -static void cy_start(struct tty_struct *); -static void cy_set_line_char(struct cyclades_port *, struct tty_struct *); -static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); -#ifdef CONFIG_ISA -static unsigned detect_isa_irq(void __iomem *); -#endif /* CONFIG_ISA */ - -#ifndef CONFIG_CYZ_INTR -static void cyz_poll(struct timer_list *); - -/* The Cyclades-Z polling cycle is defined by this variable */ -static long cyz_polling_cycle = CZ_DEF_POLL; - -static DEFINE_TIMER(cyz_timerlist, cyz_poll); - -#else /* CONFIG_CYZ_INTR */ -static void cyz_rx_restart(struct timer_list *); -#endif /* CONFIG_CYZ_INTR */ - -static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val) -{ - struct cyclades_card *card = port->card; - - cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val); -} - -static u8 cyy_readb(struct cyclades_port *port, u32 reg) -{ - struct cyclades_card *card = port->card; - - return readb(port->u.cyy.base_addr + (reg << card->bus_index)); -} - -static inline bool cy_is_Z(struct cyclades_card *card) -{ - return card->num_chips == (unsigned int)-1; -} - -static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr) -{ - return readl(&ctl_addr->init_ctrl) & (1 << 17); -} - -static inline bool cyz_fpga_loaded(struct cyclades_card *card) -{ - return __cyz_fpga_loaded(card->ctl_addr.p9060); -} - -static bool cyz_is_loaded(struct cyclades_card *card) -{ - struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS; - - return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) && - readl(&fw_id->signature) == ZFIRM_ID; -} - -static int serial_paranoia_check(struct cyclades_port *info, - const char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - if (!info) { - printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) " - "in %s\n", name, routine); - return 1; - } - - if (info->magic != CYCLADES_MAGIC) { - printk(KERN_WARNING "cyc Warning: bad magic number for serial " - "struct (%s) in %s\n", name, routine); - return 1; - } -#endif - return 0; -} - -/***********************************************************/ -/********* Start of block of Cyclom-Y specific code ********/ - -/* This routine waits up to 1000 micro-seconds for the previous - command to the Cirrus chip to complete and then issues the - new command. An error is returned if the previous command - didn't finish within the time limit. - - This function is only called from inside spinlock-protected code. - */ -static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index) -{ - void __iomem *ccr = base_addr + (CyCCR << index); - unsigned int i; - - /* Check to see that the previous command has completed */ - for (i = 0; i < 100; i++) { - if (readb(ccr) == 0) - break; - udelay(10L); - } - /* if the CCR never cleared, the previous command - didn't finish within the "reasonable time" */ - if (i == 100) - return -1; - - /* Issue the new command */ - cy_writeb(ccr, cmd); - - return 0; -} - -static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd) -{ - return __cyy_issue_cmd(port->u.cyy.base_addr, cmd, - port->card->bus_index); -} - -#ifdef CONFIG_ISA -/* ISA interrupt detection code */ -static unsigned detect_isa_irq(void __iomem *address) -{ - int irq; - unsigned long irqs, flags; - int save_xir, save_car; - int index = 0; /* IRQ probing is only for ISA */ - - /* forget possible initially masked and pending IRQ */ - irq = probe_irq_off(probe_irq_on()); - - /* Clear interrupts on the board first */ - cy_writeb(address + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - - irqs = probe_irq_on(); - /* Wait ... */ - msleep(5); - - /* Enable the Tx interrupts on the CD1400 */ - local_irq_save(flags); - cy_writeb(address + (CyCAR << index), 0); - __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index); - - cy_writeb(address + (CyCAR << index), 0); - cy_writeb(address + (CySRER << index), - readb(address + (CySRER << index)) | CyTxRdy); - local_irq_restore(flags); - - /* Wait ... */ - msleep(5); - - /* Check which interrupt is in use */ - irq = probe_irq_off(irqs); - - /* Clean up */ - save_xir = (u_char) readb(address + (CyTIR << index)); - save_car = readb(address + (CyCAR << index)); - cy_writeb(address + (CyCAR << index), (save_xir & 0x3)); - cy_writeb(address + (CySRER << index), - readb(address + (CySRER << index)) & ~CyTxRdy); - cy_writeb(address + (CyTIR << index), (save_xir & 0x3f)); - cy_writeb(address + (CyCAR << index), (save_car)); - cy_writeb(address + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - - return (irq > 0) ? irq : 0; -} -#endif /* CONFIG_ISA */ - -static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, - void __iomem *base_addr) -{ - struct cyclades_port *info; - struct tty_port *port; - int len, index = cinfo->bus_index; - u8 ivr, save_xir, channel, save_car, data, char_count; - -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); -#endif - /* determine the channel & change to that context */ - save_xir = readb(base_addr + (CyRIR << index)); - channel = save_xir & CyIRChannel; - info = &cinfo->ports[channel + chip * 4]; - port = &info->port; - save_car = cyy_readb(info, CyCAR); - cyy_writeb(info, CyCAR, save_xir); - ivr = cyy_readb(info, CyRIVR) & CyIVRMask; - - /* there is an open port for this data */ - if (ivr == CyIVRRxEx) { /* exception */ - data = cyy_readb(info, CyRDSR); - - /* For statistics only */ - if (data & CyBREAK) - info->icount.brk++; - else if (data & CyFRAME) - info->icount.frame++; - else if (data & CyPARITY) - info->icount.parity++; - else if (data & CyOVERRUN) - info->icount.overrun++; - - if (data & info->ignore_status_mask) { - info->icount.rx++; - return; - } - if (tty_buffer_request_room(port, 1)) { - if (data & info->read_status_mask) { - if (data & CyBREAK) { - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_BREAK); - info->icount.rx++; - if (port->flags & ASYNC_SAK) { - struct tty_struct *tty = - tty_port_tty_get(port); - if (tty) { - do_SAK(tty); - tty_kref_put(tty); - } - } - } else if (data & CyFRAME) { - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_FRAME); - info->icount.rx++; - info->idle_stats.frame_errs++; - } else if (data & CyPARITY) { - /* Pieces of seven... */ - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_PARITY); - info->icount.rx++; - info->idle_stats.parity_errs++; - } else if (data & CyOVERRUN) { - tty_insert_flip_char(port, 0, - TTY_OVERRUN); - info->icount.rx++; - /* If the flip buffer itself is - overflowing, we still lose - the next incoming character. - */ - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_FRAME); - info->icount.rx++; - info->idle_stats.overruns++; - /* These two conditions may imply */ - /* a normal read should be done. */ - /* } else if(data & CyTIMEOUT) { */ - /* } else if(data & CySPECHAR) { */ - } else { - tty_insert_flip_char(port, 0, - TTY_NORMAL); - info->icount.rx++; - } - } else { - tty_insert_flip_char(port, 0, TTY_NORMAL); - info->icount.rx++; - } - } else { - /* there was a software buffer overrun and nothing - * could be done about it!!! */ - info->icount.buf_overrun++; - info->idle_stats.overruns++; - } - } else { /* normal character reception */ - /* load # chars available from the chip */ - char_count = cyy_readb(info, CyRDCR); - -#ifdef CY_ENABLE_MONITORING - ++info->mon.int_count; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; -#endif - len = tty_buffer_request_room(port, char_count); - while (len--) { - data = cyy_readb(info, CyRDSR); - tty_insert_flip_char(port, data, TTY_NORMAL); - info->idle_stats.recv_bytes++; - info->icount.rx++; -#ifdef CY_16Y_HACK - udelay(10L); -#endif - } - info->idle_stats.recv_idle = jiffies; - } - tty_schedule_flip(port); - - /* end of service */ - cyy_writeb(info, CyRIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); -} - -static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, - void __iomem *base_addr) -{ - struct cyclades_port *info; - struct tty_struct *tty; - int char_count, index = cinfo->bus_index; - u8 save_xir, channel, save_car, outch; - - /* Since we only get here when the transmit buffer - is empty, we know we can always stuff a dozen - characters. */ -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); -#endif - - /* determine the channel & change to that context */ - save_xir = readb(base_addr + (CyTIR << index)); - channel = save_xir & CyIRChannel; - save_car = readb(base_addr + (CyCAR << index)); - cy_writeb(base_addr + (CyCAR << index), save_xir); - - info = &cinfo->ports[channel + chip * 4]; - tty = tty_port_tty_get(&info->port); - if (tty == NULL) { - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); - goto end; - } - - /* load the on-chip space for outbound data */ - char_count = info->xmit_fifo_size; - - if (info->x_char) { /* send special char */ - outch = info->x_char; - cyy_writeb(info, CyTDR, outch); - char_count--; - info->icount.tx++; - info->x_char = 0; - } - - if (info->breakon || info->breakoff) { - if (info->breakon) { - cyy_writeb(info, CyTDR, 0); - cyy_writeb(info, CyTDR, 0x81); - info->breakon = 0; - char_count -= 2; - } - if (info->breakoff) { - cyy_writeb(info, CyTDR, 0); - cyy_writeb(info, CyTDR, 0x83); - info->breakoff = 0; - char_count -= 2; - } - } - - while (char_count-- > 0) { - if (!info->xmit_cnt) { - if (cyy_readb(info, CySRER) & CyTxMpty) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxMpty); - } else { - cyy_writeb(info, CySRER, CyTxMpty | - (cyy_readb(info, CySRER) & ~CyTxRdy)); - } - goto done; - } - if (info->port.xmit_buf == NULL) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); - goto done; - } - if (tty->stopped || tty->hw_stopped) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); - goto done; - } - /* Because the Embedded Transmit Commands have been enabled, - * we must check to see if the escape character, NULL, is being - * sent. If it is, we must ensure that there is room for it to - * be doubled in the output stream. Therefore we no longer - * advance the pointer when the character is fetched, but - * rather wait until after the check for a NULL output - * character. This is necessary because there may not be room - * for the two chars needed to send a NULL.) - */ - outch = info->port.xmit_buf[info->xmit_tail]; - if (outch) { - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - cyy_writeb(info, CyTDR, outch); - info->icount.tx++; - } else { - if (char_count > 1) { - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - cyy_writeb(info, CyTDR, outch); - cyy_writeb(info, CyTDR, 0); - info->icount.tx++; - char_count--; - } - } - } - -done: - tty_wakeup(tty); - tty_kref_put(tty); -end: - /* end of service */ - cyy_writeb(info, CyTIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); -} - -static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, - void __iomem *base_addr) -{ - struct cyclades_port *info; - struct tty_struct *tty; - int index = cinfo->bus_index; - u8 save_xir, channel, save_car, mdm_change, mdm_status; - - /* determine the channel & change to that context */ - save_xir = readb(base_addr + (CyMIR << index)); - channel = save_xir & CyIRChannel; - info = &cinfo->ports[channel + chip * 4]; - save_car = cyy_readb(info, CyCAR); - cyy_writeb(info, CyCAR, save_xir); - - mdm_change = cyy_readb(info, CyMISR); - mdm_status = cyy_readb(info, CyMSVR1); - - tty = tty_port_tty_get(&info->port); - if (!tty) - goto end; - - if (mdm_change & CyANY_DELTA) { - /* For statistics only */ - if (mdm_change & CyDCD) - info->icount.dcd++; - if (mdm_change & CyCTS) - info->icount.cts++; - if (mdm_change & CyDSR) - info->icount.dsr++; - if (mdm_change & CyRI) - info->icount.rng++; - - wake_up_interruptible(&info->port.delta_msr_wait); - } - - if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) { - if (mdm_status & CyDCD) - wake_up_interruptible(&info->port.open_wait); - else - tty_hangup(tty); - } - if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) { - if (tty->hw_stopped) { - if (mdm_status & CyCTS) { - /* cy_start isn't used - because... !!! */ - tty->hw_stopped = 0; - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) | CyTxRdy); - tty_wakeup(tty); - } - } else { - if (!(mdm_status & CyCTS)) { - /* cy_stop isn't used - because ... !!! */ - tty->hw_stopped = 1; - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); - } - } - } -/* if (mdm_change & CyDSR) { - } - if (mdm_change & CyRI) { - }*/ - tty_kref_put(tty); -end: - /* end of service */ - cyy_writeb(info, CyMIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); -} - -/* The real interrupt service routine is called - whenever the card wants its hand held--chars - received, out buffer empty, modem change, etc. - */ -static irqreturn_t cyy_interrupt(int irq, void *dev_id) -{ - int status; - struct cyclades_card *cinfo = dev_id; - void __iomem *base_addr, *card_base_addr; - unsigned int chip, too_many, had_work; - int index; - - if (unlikely(cinfo == NULL)) { -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n", - irq); -#endif - return IRQ_NONE; /* spurious interrupt */ - } - - card_base_addr = cinfo->base_addr; - index = cinfo->bus_index; - - /* card was not initialized yet (e.g. DEBUG_SHIRQ) */ - if (unlikely(card_base_addr == NULL)) - return IRQ_HANDLED; - - /* This loop checks all chips in the card. Make a note whenever - _any_ chip had some work to do, as this is considered an - indication that there will be more to do. Only when no chip - has any work does this outermost loop exit. - */ - do { - had_work = 0; - for (chip = 0; chip < cinfo->num_chips; chip++) { - base_addr = cinfo->base_addr + - (cy_chip_offset[chip] << index); - too_many = 0; - while ((status = readb(base_addr + - (CySVRR << index))) != 0x00) { - had_work++; - /* The purpose of the following test is to ensure that - no chip can monopolize the driver. This forces the - chips to be checked in a round-robin fashion (after - draining each of a bunch (1000) of characters). - */ - if (1000 < too_many++) - break; - spin_lock(&cinfo->card_lock); - if (status & CySRReceive) /* rx intr */ - cyy_chip_rx(cinfo, chip, base_addr); - if (status & CySRTransmit) /* tx intr */ - cyy_chip_tx(cinfo, chip, base_addr); - if (status & CySRModem) /* modem intr */ - cyy_chip_modem(cinfo, chip, base_addr); - spin_unlock(&cinfo->card_lock); - } - } - } while (had_work); - - /* clear interrupts */ - spin_lock(&cinfo->card_lock); - cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - spin_unlock(&cinfo->card_lock); - return IRQ_HANDLED; -} /* cyy_interrupt */ - -static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set, - unsigned int clear) -{ - struct cyclades_card *card = info->card; - int channel = info->line - card->first_line; - u32 rts, dtr, msvrr, msvrd; - - channel &= 0x03; - - if (info->rtsdtr_inv) { - msvrr = CyMSVR2; - msvrd = CyMSVR1; - rts = CyDTR; - dtr = CyRTS; - } else { - msvrr = CyMSVR1; - msvrd = CyMSVR2; - rts = CyRTS; - dtr = CyDTR; - } - if (set & TIOCM_RTS) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrr, rts); - } - if (clear & TIOCM_RTS) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrr, ~rts); - } - if (set & TIOCM_DTR) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrd, dtr); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); - printk(KERN_DEBUG " status: 0x%x, 0x%x\n", - cyy_readb(info, CyMSVR1), - cyy_readb(info, CyMSVR2)); -#endif - } - if (clear & TIOCM_DTR) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrd, ~dtr); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); - printk(KERN_DEBUG " status: 0x%x, 0x%x\n", - cyy_readb(info, CyMSVR1), - cyy_readb(info, CyMSVR2)); -#endif - } -} - -/***********************************************************/ -/********* End of block of Cyclom-Y specific code **********/ -/******** Start of block of Cyclades-Z specific code *******/ -/***********************************************************/ - -static int -cyz_fetch_msg(struct cyclades_card *cinfo, - __u32 *channel, __u8 *cmd, __u32 *param) -{ - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - unsigned long loc_doorbell; - - loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell); - if (loc_doorbell) { - *cmd = (char)(0xff & loc_doorbell); - *channel = readl(&board_ctrl->fwcmd_channel); - *param = (__u32) readl(&board_ctrl->fwcmd_param); - cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff); - return 1; - } - return 0; -} /* cyz_fetch_msg */ - -static int -cyz_issue_cmd(struct cyclades_card *cinfo, - __u32 channel, __u8 cmd, __u32 param) -{ - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - __u32 __iomem *pci_doorbell; - unsigned int index; - - if (!cyz_is_loaded(cinfo)) - return -1; - - index = 0; - pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell; - while ((readl(pci_doorbell) & 0xff) != 0) { - if (index++ == 1000) - return (int)(readl(pci_doorbell) & 0xff); - udelay(50L); - } - cy_writel(&board_ctrl->hcmd_channel, channel); - cy_writel(&board_ctrl->hcmd_param, param); - cy_writel(pci_doorbell, (long)cmd); - - return 0; -} /* cyz_issue_cmd */ - -static void cyz_handle_rx(struct cyclades_port *info) -{ - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; - struct cyclades_card *cinfo = info->card; - struct tty_port *port = &info->port; - unsigned int char_count; - int len; -#ifdef BLOCKMOVE - unsigned char *buf; -#else - char data; -#endif - __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; - - rx_get = new_rx_get = readl(&buf_ctrl->rx_get); - rx_put = readl(&buf_ctrl->rx_put); - rx_bufsize = readl(&buf_ctrl->rx_bufsize); - rx_bufaddr = readl(&buf_ctrl->rx_bufaddr); - if (rx_put >= rx_get) - char_count = rx_put - rx_get; - else - char_count = rx_put - rx_get + rx_bufsize; - - if (!char_count) - return; - -#ifdef CY_ENABLE_MONITORING - info->mon.int_count++; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; -#endif - -#ifdef BLOCKMOVE - /* we'd like to use memcpy(t, f, n) and memset(s, c, count) - for performance, but because of buffer boundaries, there - may be several steps to the operation */ - while (1) { - len = tty_prepare_flip_string(port, &buf, - char_count); - if (!len) - break; - - len = min_t(unsigned int, min(len, char_count), - rx_bufsize - new_rx_get); - - memcpy_fromio(buf, cinfo->base_addr + - rx_bufaddr + new_rx_get, len); - - new_rx_get = (new_rx_get + len) & - (rx_bufsize - 1); - char_count -= len; - info->icount.rx += len; - info->idle_stats.recv_bytes += len; - } -#else - len = tty_buffer_request_room(port, char_count); - while (len--) { - data = readb(cinfo->base_addr + rx_bufaddr + - new_rx_get); - new_rx_get = (new_rx_get + 1) & - (rx_bufsize - 1); - tty_insert_flip_char(port, data, TTY_NORMAL); - info->idle_stats.recv_bytes++; - info->icount.rx++; - } -#endif -#ifdef CONFIG_CYZ_INTR - /* Recalculate the number of chars in the RX buffer and issue - a cmd in case it's higher than the RX high water mark */ - rx_put = readl(&buf_ctrl->rx_put); - if (rx_put >= rx_get) - char_count = rx_put - rx_get; - else - char_count = rx_put - rx_get + rx_bufsize; - if (char_count >= readl(&buf_ctrl->rx_threshold) && - !timer_pending(&info->rx_full_timer)) - mod_timer(&info->rx_full_timer, jiffies + 1); -#endif - info->idle_stats.recv_idle = jiffies; - tty_schedule_flip(&info->port); - - /* Update rx_get */ - cy_writel(&buf_ctrl->rx_get, new_rx_get); -} - -static void cyz_handle_tx(struct cyclades_port *info) -{ - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; - struct cyclades_card *cinfo = info->card; - struct tty_struct *tty; - u8 data; - unsigned int char_count; -#ifdef BLOCKMOVE - int small_count; -#endif - __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr; - - if (info->xmit_cnt <= 0) /* Nothing to transmit */ - return; - - tx_get = readl(&buf_ctrl->tx_get); - tx_put = readl(&buf_ctrl->tx_put); - tx_bufsize = readl(&buf_ctrl->tx_bufsize); - tx_bufaddr = readl(&buf_ctrl->tx_bufaddr); - if (tx_put >= tx_get) - char_count = tx_get - tx_put - 1 + tx_bufsize; - else - char_count = tx_get - tx_put - 1; - - if (!char_count) - return; - - tty = tty_port_tty_get(&info->port); - if (tty == NULL) - goto ztxdone; - - if (info->x_char) { /* send special char */ - data = info->x_char; - - cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); - tx_put = (tx_put + 1) & (tx_bufsize - 1); - info->x_char = 0; - char_count--; - info->icount.tx++; - } -#ifdef BLOCKMOVE - while (0 < (small_count = min_t(unsigned int, - tx_bufsize - tx_put, min_t(unsigned int, - (SERIAL_XMIT_SIZE - info->xmit_tail), - min_t(unsigned int, info->xmit_cnt, - char_count))))) { - - memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put), - &info->port.xmit_buf[info->xmit_tail], - small_count); - - tx_put = (tx_put + small_count) & (tx_bufsize - 1); - char_count -= small_count; - info->icount.tx += small_count; - info->xmit_cnt -= small_count; - info->xmit_tail = (info->xmit_tail + small_count) & - (SERIAL_XMIT_SIZE - 1); - } -#else - while (info->xmit_cnt && char_count) { - data = info->port.xmit_buf[info->xmit_tail]; - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - - cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); - tx_put = (tx_put + 1) & (tx_bufsize - 1); - char_count--; - info->icount.tx++; - } -#endif - tty_wakeup(tty); - tty_kref_put(tty); -ztxdone: - /* Update tx_put */ - cy_writel(&buf_ctrl->tx_put, tx_put); -} - -static void cyz_handle_cmd(struct cyclades_card *cinfo) -{ - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - struct cyclades_port *info; - __u32 channel, param, fw_ver; - __u8 cmd; - int special_count; - int delta_count; - - fw_ver = readl(&board_ctrl->fw_version); - - while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { - special_count = 0; - delta_count = 0; - info = &cinfo->ports[channel]; - - switch (cmd) { - case C_CM_PR_ERROR: - tty_insert_flip_char(&info->port, 0, TTY_PARITY); - info->icount.rx++; - special_count++; - break; - case C_CM_FR_ERROR: - tty_insert_flip_char(&info->port, 0, TTY_FRAME); - info->icount.rx++; - special_count++; - break; - case C_CM_RXBRK: - tty_insert_flip_char(&info->port, 0, TTY_BREAK); - info->icount.rx++; - special_count++; - break; - case C_CM_MDCD: - info->icount.dcd++; - delta_count++; - if (tty_port_check_carrier(&info->port)) { - u32 dcd = fw_ver > 241 ? param : - readl(&info->u.cyz.ch_ctrl->rs_status); - if (dcd & C_RS_DCD) - wake_up_interruptible(&info->port.open_wait); - else - tty_port_tty_hangup(&info->port, false); - } - break; - case C_CM_MCTS: - info->icount.cts++; - delta_count++; - break; - case C_CM_MRI: - info->icount.rng++; - delta_count++; - break; - case C_CM_MDSR: - info->icount.dsr++; - delta_count++; - break; -#ifdef Z_WAKE - case C_CM_IOCTLW: - complete(&info->shutdown_wait); - break; -#endif -#ifdef CONFIG_CYZ_INTR - case C_CM_RXHIWM: - case C_CM_RXNNDT: - case C_CM_INTBACK2: - /* Reception Interrupt */ -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " - "port %ld\n", info->card, channel); -#endif - cyz_handle_rx(info); - break; - case C_CM_TXBEMPTY: - case C_CM_TXLOWWM: - case C_CM_INTBACK: - /* Transmission Interrupt */ -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " - "port %ld\n", info->card, channel); -#endif - cyz_handle_tx(info); - break; -#endif /* CONFIG_CYZ_INTR */ - case C_CM_FATAL: - /* should do something with this !!! */ - break; - default: - break; - } - if (delta_count) - wake_up_interruptible(&info->port.delta_msr_wait); - if (special_count) - tty_schedule_flip(&info->port); - } -} - -#ifdef CONFIG_CYZ_INTR -static irqreturn_t cyz_interrupt(int irq, void *dev_id) -{ - struct cyclades_card *cinfo = dev_id; - - if (unlikely(!cyz_is_loaded(cinfo))) { -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " - "(IRQ%d).\n", irq); -#endif - return IRQ_NONE; - } - - /* Handle the interrupts */ - cyz_handle_cmd(cinfo); - - return IRQ_HANDLED; -} /* cyz_interrupt */ - -static void cyz_rx_restart(struct timer_list *t) -{ - struct cyclades_port *info = from_timer(info, t, rx_full_timer); - struct cyclades_card *card = info->card; - int retval; - __u32 channel = info->line - card->first_line; - unsigned long flags; - - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n", - info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); -} - -#else /* CONFIG_CYZ_INTR */ - -static void cyz_poll(struct timer_list *unused) -{ - struct cyclades_card *cinfo; - struct cyclades_port *info; - unsigned long expires = jiffies + HZ; - unsigned int port, card; - - for (card = 0; card < NR_CARDS; card++) { - cinfo = &cy_card[card]; - - if (!cy_is_Z(cinfo)) - continue; - if (!cyz_is_loaded(cinfo)) - continue; - - /* Skip first polling cycle to avoid racing conditions with the FW */ - if (!cinfo->intr_enabled) { - cinfo->intr_enabled = 1; - continue; - } - - cyz_handle_cmd(cinfo); - - for (port = 0; port < cinfo->nports; port++) { - info = &cinfo->ports[port]; - - if (!info->throttle) - cyz_handle_rx(info); - cyz_handle_tx(info); - } - /* poll every 'cyz_polling_cycle' period */ - expires = jiffies + cyz_polling_cycle; - } - mod_timer(&cyz_timerlist, expires); -} /* cyz_poll */ - -#endif /* CONFIG_CYZ_INTR */ - -/********** End of block of Cyclades-Z specific code *********/ -/***********************************************************/ - -/* This is called whenever a port becomes active; - interrupts are enabled and DTR & RTS are turned on. - */ -static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) -{ - struct cyclades_card *card; - unsigned long flags; - int retval = 0; - int channel; - unsigned long page; - - card = info->card; - channel = info->line - card->first_line; - - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - spin_lock_irqsave(&card->card_lock, flags); - - if (tty_port_initialized(&info->port)) - goto errout; - - if (!info->type) { - set_bit(TTY_IO_ERROR, &tty->flags); - goto errout; - } - - if (info->port.xmit_buf) - free_page(page); - else - info->port.xmit_buf = (unsigned char *)page; - - spin_unlock_irqrestore(&card->card_lock, flags); - - cy_set_line_char(info, tty); - - if (!cy_is_Z(card)) { - channel &= 0x03; - - spin_lock_irqsave(&card->card_lock, flags); - - cyy_writeb(info, CyCAR, channel); - - cyy_writeb(info, CyRTPR, - (info->default_timeout ? info->default_timeout : 0x02)); - /* 10ms rx timeout */ - - cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR); - - cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0); - - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData); - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - - if (!cyz_is_loaded(card)) - return -ENODEV; - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " - "base_addr %p\n", card, channel, card->base_addr); -#endif - spin_lock_irqsave(&card->card_lock, flags); - - cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE); -#ifdef Z_WAKE -#ifdef CONFIG_CYZ_INTR - cy_writel(&ch_ctrl->intr_enable, - C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | - C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD); -#else - cy_writel(&ch_ctrl->intr_enable, - C_IN_IOCTLW | C_IN_MDCD); -#endif /* CONFIG_CYZ_INTR */ -#else -#ifdef CONFIG_CYZ_INTR - cy_writel(&ch_ctrl->intr_enable, - C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | - C_IN_RXNNDT | C_IN_MDCD); -#else - cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD); -#endif /* CONFIG_CYZ_INTR */ -#endif /* Z_WAKE */ - - retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was " - "%x\n", info->line, retval); - } - - /* Flush RX buffers before raising DTR and RTS */ - retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was " - "%x\n", info->line, retval); - } - - /* set timeout !!! */ - /* set RTS and DTR !!! */ - tty_port_raise_dtr_rts(&info->port); - - /* enable send, recv, modem !!! */ - } - - tty_port_set_initialized(&info->port, 1); - - clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - info->breakon = info->breakoff = 0; - memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); - info->idle_stats.in_use = - info->idle_stats.recv_idle = - info->idle_stats.xmit_idle = jiffies; - - spin_unlock_irqrestore(&card->card_lock, flags); - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc startup done\n"); -#endif - return 0; - -errout: - spin_unlock_irqrestore(&card->card_lock, flags); - free_page(page); - return retval; -} /* startup */ - -static void start_xmit(struct cyclades_port *info) -{ - struct cyclades_card *card = info->card; - unsigned long flags; - int channel = info->line - card->first_line; - - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { -#ifdef CONFIG_CYZ_INTR - int retval; - - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was " - "%x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); -#else /* CONFIG_CYZ_INTR */ - /* Don't have to do anything at this time */ -#endif /* CONFIG_CYZ_INTR */ - } -} /* start_xmit */ - -/* - * This routine shuts down a serial port; interrupts are disabled, - * and DTR is dropped if the hangup on close termio flag is on. - */ -static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) -{ - struct cyclades_card *card; - unsigned long flags; - - if (!tty_port_initialized(&info->port)) - return; - - card = info->card; - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - - /* Clear delta_msr_wait queue to avoid mem leaks. */ - wake_up_interruptible(&info->port.delta_msr_wait); - - if (info->port.xmit_buf) { - unsigned char *temp; - temp = info->port.xmit_buf; - info->port.xmit_buf = NULL; - free_page((unsigned long)temp); - } - if (C_HUPCL(tty)) - cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); - - cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); - /* it may be appropriate to clear _XMIT at - some later date (after testing)!!! */ - - set_bit(TTY_IO_ERROR, &tty->flags); - tty_port_set_initialized(&info->port, 0); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { -#ifdef CY_DEBUG_OPEN - int channel = info->line - card->first_line; - printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, " - "base_addr %p\n", card, channel, card->base_addr); -#endif - - if (!cyz_is_loaded(card)) - return; - - spin_lock_irqsave(&card->card_lock, flags); - - if (info->port.xmit_buf) { - unsigned char *temp; - temp = info->port.xmit_buf; - info->port.xmit_buf = NULL; - free_page((unsigned long)temp); - } - - if (C_HUPCL(tty)) - tty_port_lower_dtr_rts(&info->port); - - set_bit(TTY_IO_ERROR, &tty->flags); - tty_port_set_initialized(&info->port, 0); - - spin_unlock_irqrestore(&card->card_lock, flags); - } - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc shutdown done\n"); -#endif -} /* shutdown */ - -/* - * ------------------------------------------------------------ - * cy_open() and friends - * ------------------------------------------------------------ - */ - -/* - * This routine is called whenever a serial port is opened. It - * performs the serial-specific initialization for the tty structure. - */ -static int cy_open(struct tty_struct *tty, struct file *filp) -{ - struct cyclades_port *info; - unsigned int i, line = tty->index; - int retval; - - for (i = 0; i < NR_CARDS; i++) - if (line < cy_card[i].first_line + cy_card[i].nports && - line >= cy_card[i].first_line) - break; - if (i >= NR_CARDS) - return -ENODEV; - info = &cy_card[i].ports[line - cy_card[i].first_line]; - if (info->line < 0) - return -ENODEV; - - /* If the card's firmware hasn't been loaded, - treat it as absent from the system. This - will make the user pay attention. - */ - if (cy_is_Z(info->card)) { - struct cyclades_card *cinfo = info->card; - struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; - - if (!cyz_is_loaded(cinfo)) { - if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) && - readl(&firm_id->signature) == - ZFIRM_HLT) { - printk(KERN_ERR "cyc:Cyclades-Z Error: you " - "need an external power supply for " - "this number of ports.\nFirmware " - "halted.\n"); - } else { - printk(KERN_ERR "cyc:Cyclades-Z firmware not " - "yet loaded\n"); - } - return -ENODEV; - } -#ifdef CONFIG_CYZ_INTR - else { - /* In case this Z board is operating in interrupt mode, its - interrupts should be enabled as soon as the first open - happens to one of its ports. */ - if (!cinfo->intr_enabled) { - u16 intr; - - /* Enable interrupts on the PLX chip */ - intr = readw(&cinfo->ctl_addr.p9060-> - intr_ctrl_stat) | 0x0900; - cy_writew(&cinfo->ctl_addr.p9060-> - intr_ctrl_stat, intr); - /* Enable interrupts on the FW */ - retval = cyz_issue_cmd(cinfo, 0, - C_CM_IRQ_ENBL, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:IRQ enable retval " - "was %x\n", retval); - } - cinfo->intr_enabled = 1; - } - } -#endif /* CONFIG_CYZ_INTR */ - /* Make sure this Z port really exists in hardware */ - if (info->line > (cinfo->first_line + cinfo->nports - 1)) - return -ENODEV; - } -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); -#endif - tty->driver_data = info; - if (serial_paranoia_check(info, tty->name, "cy_open")) - return -ENODEV; - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, - info->port.count); -#endif - info->port.count++; -#ifdef CY_DEBUG_COUNT - printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", - current->pid, info->port.count); -#endif - - /* - * Start up serial port - */ - retval = cy_startup(info, tty); - if (retval) - return retval; - - retval = tty_port_block_til_ready(&info->port, tty, filp); - if (retval) { -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " - "with %d\n", retval); -#endif - return retval; - } - - info->throttle = 0; - tty_port_tty_set(&info->port, tty); - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc:cy_open done\n"); -#endif - return 0; -} /* cy_open */ - -/* - * cy_wait_until_sent() --- wait until the transmitter is empty - */ -static void cy_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct cyclades_card *card; - struct cyclades_port *info = tty->driver_data; - unsigned long orig_jiffies; - int char_time; - - if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent")) - return; - - if (info->xmit_fifo_size == 0) - return; /* Just in case.... */ - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size; - char_time = char_time / 5; - if (char_time <= 0) - char_time = 1; - if (timeout < 0) - timeout = 0; - if (timeout) - char_time = min(char_time, timeout); - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than info->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*info->timeout. - */ - if (!timeout || timeout > 2 * info->timeout) - timeout = 2 * info->timeout; - - card = info->card; - if (!cy_is_Z(card)) { - while (cyy_readb(info, CySRER) & CyTxRdy) { - if (msleep_interruptible(jiffies_to_msecs(char_time))) - break; - if (timeout && time_after(jiffies, orig_jiffies + - timeout)) - break; - } - } - /* Run one more char cycle */ - msleep_interruptible(jiffies_to_msecs(char_time * 5)); -} - -static void cy_flush_buffer(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int channel, retval; - unsigned long flags; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) - return; - - card = info->card; - channel = info->line - card->first_line; - - spin_lock_irqsave(&card->card_lock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - spin_unlock_irqrestore(&card->card_lock, flags); - - if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board - buffers as well */ - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " - "was %x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); - } - tty_wakeup(tty); -} /* cy_flush_buffer */ - - -static void cy_do_close(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *card; - unsigned long flags; - int channel; - - card = info->card; - channel = info->line - card->first_line; - spin_lock_irqsave(&card->card_lock, flags); - - if (!cy_is_Z(card)) { - /* Stop accepting input */ - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData); - if (tty_port_initialized(&info->port)) { - /* Waiting for on-board buffers to be empty before - closing the port */ - spin_unlock_irqrestore(&card->card_lock, flags); - cy_wait_until_sent(port->tty, info->timeout); - spin_lock_irqsave(&card->card_lock, flags); - } - } else { -#ifdef Z_WAKE - /* Waiting for on-board buffers to be empty before closing - the port */ - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int retval; - - if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) { - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L); - if (retval != 0) { - printk(KERN_DEBUG "cyc:cy_close retval on " - "ttyC%d was %x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); - wait_for_completion_interruptible(&info->shutdown_wait); - spin_lock_irqsave(&card->card_lock, flags); - } -#endif - } - spin_unlock_irqrestore(&card->card_lock, flags); - cy_shutdown(info, port->tty); -} - -/* - * This routine is called when a particular tty device is closed. - */ -static void cy_close(struct tty_struct *tty, struct file *filp) -{ - struct cyclades_port *info = tty->driver_data; - if (!info || serial_paranoia_check(info, tty->name, "cy_close")) - return; - tty_port_close(&info->port, tty, filp); -} /* cy_close */ - -/* This routine gets called when tty_write has put something into - * the write_queue. The characters may come from user space or - * kernel space. - * - * This routine will return the number of characters actually - * accepted for writing. - * - * If the port is not already transmitting stuff, start it off by - * enabling interrupts. The interrupt service routine will then - * ensure that the characters are sent. - * If the port is already active, there is no need to kick it. - * - */ -static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct cyclades_port *info = tty->driver_data; - unsigned long flags; - int c, ret = 0; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_write")) - return 0; - - if (!info->port.xmit_buf) - return 0; - - spin_lock_irqsave(&info->card->card_lock, flags); - while (1) { - c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1)); - c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head)); - - if (c <= 0) - break; - - memcpy(info->port.xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & - (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - buf += c; - count -= c; - ret += c; - } - spin_unlock_irqrestore(&info->card->card_lock, flags); - - info->idle_stats.xmit_bytes += ret; - info->idle_stats.xmit_idle = jiffies; - - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) - start_xmit(info); - - return ret; -} /* cy_write */ - -/* - * This routine is called by the kernel to write a single - * character to the tty device. If the kernel uses this routine, - * it must call the flush_chars() routine (if defined) when it is - * done stuffing characters into the driver. If there is no room - * in the queue, the character is ignored. - */ -static int cy_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct cyclades_port *info = tty->driver_data; - unsigned long flags; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_put_char")) - return 0; - - if (!info->port.xmit_buf) - return 0; - - spin_lock_irqsave(&info->card->card_lock, flags); - if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) { - spin_unlock_irqrestore(&info->card->card_lock, flags); - return 0; - } - - info->port.xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE - 1; - info->xmit_cnt++; - info->idle_stats.xmit_bytes++; - info->idle_stats.xmit_idle = jiffies; - spin_unlock_irqrestore(&info->card->card_lock, flags); - return 1; -} /* cy_put_char */ - -/* - * This routine is called by the kernel after it has written a - * series of characters to the tty device using put_char(). - */ -static void cy_flush_chars(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) - return; - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->port.xmit_buf) - return; - - start_xmit(info); -} /* cy_flush_chars */ - -/* - * This routine returns the numbers of characters the tty driver - * will accept for queuing to be written. This number is subject - * to change as output buffers get emptied, or if the output flow - * control is activated. - */ -static int cy_write_room(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - int ret; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} /* cy_write_room */ - -static int cy_chars_in_buffer(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) - return 0; - -#ifdef Z_EXT_CHARS_IN_BUFFER - if (!cy_is_Z(info->card)) { -#endif /* Z_EXT_CHARS_IN_BUFFER */ -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", - info->line, info->xmit_cnt); -#endif - return info->xmit_cnt; -#ifdef Z_EXT_CHARS_IN_BUFFER - } else { - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; - int char_count; - __u32 tx_put, tx_get, tx_bufsize; - - tx_get = readl(&buf_ctrl->tx_get); - tx_put = readl(&buf_ctrl->tx_put); - tx_bufsize = readl(&buf_ctrl->tx_bufsize); - if (tx_put >= tx_get) - char_count = tx_put - tx_get; - else - char_count = tx_put - tx_get + tx_bufsize; -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", - info->line, info->xmit_cnt + char_count); -#endif - return info->xmit_cnt + char_count; - } -#endif /* Z_EXT_CHARS_IN_BUFFER */ -} /* cy_chars_in_buffer */ - -/* - * ------------------------------------------------------------ - * cy_ioctl() and friends - * ------------------------------------------------------------ - */ - -static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) -{ - int co, co_val, bpr; - __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : - 25000000); - - if (baud == 0) { - info->tbpr = info->tco = info->rbpr = info->rco = 0; - return; - } - - /* determine which prescaler to use */ - for (co = 4, co_val = 2048; co; co--, co_val >>= 2) { - if (cy_clock / co_val / baud > 63) - break; - } - - bpr = (cy_clock / co_val * 2 / baud + 1) / 2; - if (bpr > 255) - bpr = 255; - - info->tbpr = info->rbpr = bpr; - info->tco = info->rco = co; -} - -/* - * This routine finds or computes the various line characteristics. - * It used to be called config_setup - */ -static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) -{ - struct cyclades_card *card; - unsigned long flags; - int channel; - unsigned cflag, iflag; - int baud, baud_rate = 0; - int i; - - if (info->line == -1) - return; - - cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; - - card = info->card; - channel = info->line - card->first_line; - - if (!cy_is_Z(card)) { - u32 cflags; - - /* baud rate */ - baud = tty_get_baud_rate(tty); - if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - if (info->custom_divisor) - baud_rate = info->baud / info->custom_divisor; - else - baud_rate = info->baud; - } else if (baud > CD1400_MAX_SPEED) { - baud = CD1400_MAX_SPEED; - } - /* find the baud index */ - for (i = 0; i < 20; i++) { - if (baud == baud_table[i]) - break; - } - if (i == 20) - i = 19; /* CD1400_MAX_SPEED */ - - if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - cyy_baud_calc(info, baud_rate); - } else { - if (info->chip_rev >= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[i]; /* Tx BPR */ - info->tco = baud_co_60[i]; /* Tx CO */ - info->rbpr = baud_bpr_60[i]; /* Rx BPR */ - info->rco = baud_co_60[i]; /* Rx CO */ - } else { - info->tbpr = baud_bpr_25[i]; /* Tx BPR */ - info->tco = baud_co_25[i]; /* Tx CO */ - info->rbpr = baud_bpr_25[i]; /* Rx BPR */ - info->rco = baud_co_25[i]; /* Rx CO */ - } - } - if (baud_table[i] == 134) { - /* get it right for 134.5 baud */ - info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + - 2; - } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud_rate) + 2; - } else if (baud_table[i]) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud_table[i]) + 2; - /* this needs to be propagated into the card info */ - } else { - info->timeout = 0; - } - /* By tradition (is it a standard?) a baud rate of zero - implies the line should be/has been closed. A bit - later in this routine such a test is performed. */ - - /* byte size and parity */ - info->cor5 = 0; - info->cor4 = 0; - /* receive threshold */ - info->cor3 = (info->default_threshold ? - info->default_threshold : baud_cor3[i]); - info->cor2 = CyETC; - switch (cflag & CSIZE) { - case CS5: - info->cor1 = Cy_5_BITS; - break; - case CS6: - info->cor1 = Cy_6_BITS; - break; - case CS7: - info->cor1 = Cy_7_BITS; - break; - case CS8: - info->cor1 = Cy_8_BITS; - break; - } - if (cflag & CSTOPB) - info->cor1 |= Cy_2_STOP; - - if (cflag & PARENB) { - if (cflag & PARODD) - info->cor1 |= CyPARITY_O; - else - info->cor1 |= CyPARITY_E; - } else - info->cor1 |= CyPARITY_NONE; - - /* CTS flow control flag */ - tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - if (cflag & CRTSCTS) - info->cor2 |= CyCtsAE; - else - info->cor2 &= ~CyCtsAE; - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); - - /*********************************************** - The hardware option, CyRtsAO, presents RTS when - the chip has characters to send. Since most modems - use RTS as reverse (inbound) flow control, this - option is not used. If inbound flow control is - necessary, DTR can be programmed to provide the - appropriate signals for use with a non-standard - cable. Contact Marcio Saito for details. - ***********************************************/ - - channel &= 0x03; - - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel); - - /* tx and rx baud rate */ - - cyy_writeb(info, CyTCOR, info->tco); - cyy_writeb(info, CyTBPR, info->tbpr); - cyy_writeb(info, CyRCOR, info->rco); - cyy_writeb(info, CyRBPR, info->rbpr); - - /* set line characteristics according configuration */ - - cyy_writeb(info, CySCHR1, START_CHAR(tty)); - cyy_writeb(info, CySCHR2, STOP_CHAR(tty)); - cyy_writeb(info, CyCOR1, info->cor1); - cyy_writeb(info, CyCOR2, info->cor2); - cyy_writeb(info, CyCOR3, info->cor3); - cyy_writeb(info, CyCOR4, info->cor4); - cyy_writeb(info, CyCOR5, info->cor5); - - cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch | - CyCOR3ch); - - /* !!! Is this needed? */ - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, CyRTPR, - (info->default_timeout ? info->default_timeout : 0x02)); - /* 10ms rx timeout */ - - cflags = CyCTS; - if (!C_CLOCAL(tty)) - cflags |= CyDSR | CyRI | CyDCD; - /* without modem intr */ - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh); - /* act on 1->0 modem transitions */ - if ((cflag & CRTSCTS) && info->rflow) - cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]); - else - cyy_writeb(info, CyMCOR1, cflags); - /* act on 0->1 modem transitions */ - cyy_writeb(info, CyMCOR2, cflags); - - if (i == 0) /* baud rate is zero, turn off line */ - cyy_change_rts_dtr(info, 0, TIOCM_DTR); - else - cyy_change_rts_dtr(info, TIOCM_DTR, 0); - - clear_bit(TTY_IO_ERROR, &tty->flags); - spin_unlock_irqrestore(&card->card_lock, flags); - - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - __u32 sw_flow; - int retval; - - if (!cyz_is_loaded(card)) - return; - - /* baud rate */ - baud = tty_get_baud_rate(tty); - if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - if (info->custom_divisor) - baud_rate = info->baud / info->custom_divisor; - else - baud_rate = info->baud; - } else if (baud > CYZ_MAX_SPEED) { - baud = CYZ_MAX_SPEED; - } - cy_writel(&ch_ctrl->comm_baud, baud); - - if (baud == 134) { - /* get it right for 134.5 baud */ - info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + - 2; - } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud_rate) + 2; - } else if (baud) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud) + 2; - /* this needs to be propagated into the card info */ - } else { - info->timeout = 0; - } - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5); - break; - case CS6: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6); - break; - case CS7: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7); - break; - case CS8: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8); - break; - } - if (cflag & CSTOPB) { - cy_writel(&ch_ctrl->comm_data_l, - readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); - } else { - cy_writel(&ch_ctrl->comm_data_l, - readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); - } - if (cflag & PARENB) { - if (cflag & PARODD) - cy_writel(&ch_ctrl->comm_parity, C_PR_ODD); - else - cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN); - } else - cy_writel(&ch_ctrl->comm_parity, C_PR_NONE); - - /* CTS flow control flag */ - if (cflag & CRTSCTS) { - cy_writel(&ch_ctrl->hw_flow, - readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS); - } else { - cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) & - ~(C_RS_CTS | C_RS_RTS)); - } - /* As the HW flow control is done in firmware, the driver - doesn't need to care about it */ - tty_port_set_cts_flow(&info->port, 0); - - /* XON/XOFF/XANY flow control flags */ - sw_flow = 0; - if (iflag & IXON) { - sw_flow |= C_FL_OXX; - if (iflag & IXANY) - sw_flow |= C_FL_OIXANY; - } - cy_writel(&ch_ctrl->sw_flow, sw_flow); - - retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:set_line_char retval on ttyC%d " - "was %x\n", info->line, retval); - } - - /* CD sensitivity */ - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); - - if (baud == 0) { /* baud rate is zero, turn off line */ - cy_writel(&ch_ctrl->rs_control, - readl(&ch_ctrl->rs_control) & ~C_RS_DTR); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n"); -#endif - } else { - cy_writel(&ch_ctrl->rs_control, - readl(&ch_ctrl->rs_control) | C_RS_DTR); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n"); -#endif - } - - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d " - "was %x\n", info->line, retval); - } - - clear_bit(TTY_IO_ERROR, &tty->flags); - } -} /* set_line_char */ - -static int cy_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *cinfo = info->card; - - if (serial_paranoia_check(info, tty->name, "cy_ioctl")) - return -ENODEV; - ss->type = info->type; - ss->line = info->line; - ss->port = (info->card - cy_card) * 0x100 + info->line - - cinfo->first_line; - ss->irq = cinfo->irq; - ss->flags = info->port.flags; - ss->close_delay = info->port.close_delay; - ss->closing_wait = info->port.closing_wait; - ss->baud_base = info->baud; - ss->custom_divisor = info->custom_divisor; - return 0; -} - -static int cy_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct cyclades_port *info = tty->driver_data; - int old_flags; - int ret; - - if (serial_paranoia_check(info, tty->name, "cy_ioctl")) - return -ENODEV; - - mutex_lock(&info->port.mutex); - - old_flags = info->port.flags; - - if (!capable(CAP_SYS_ADMIN)) { - if (ss->close_delay != info->port.close_delay || - ss->baud_base != info->baud || - (ss->flags & ASYNC_FLAGS & - ~ASYNC_USR_MASK) != - (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) - { - mutex_unlock(&info->port.mutex); - return -EPERM; - } - info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK); - info->baud = ss->baud_base; - info->custom_divisor = ss->custom_divisor; - goto check_and_exit; - } - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud = ss->baud_base; - info->custom_divisor = ss->custom_divisor; - info->port.flags = (info->port.flags & ~ASYNC_FLAGS) | - (ss->flags & ASYNC_FLAGS); - info->port.close_delay = ss->close_delay * HZ / 100; - info->port.closing_wait = ss->closing_wait * HZ / 100; - -check_and_exit: - if (tty_port_initialized(&info->port)) { - if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) { - /* warn about deprecation unless clearing */ - if (ss->flags & ASYNC_SPD_MASK) - dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); - } - cy_set_line_char(info, tty); - ret = 0; - } else { - ret = cy_startup(info, tty); - } - mutex_unlock(&info->port.mutex); - return ret; -} /* set_serial_info */ - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) -{ - struct cyclades_card *card = info->card; - unsigned int result; - unsigned long flags; - u8 status; - - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty); - spin_unlock_irqrestore(&card->card_lock, flags); - result = (status ? 0 : TIOCSER_TEMT); - } else { - /* Not supported yet */ - return -EINVAL; - } - return put_user(result, value); -} - -static int cy_tiocmget(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int result; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - card = info->card; - - if (!cy_is_Z(card)) { - unsigned long flags; - int channel = info->line - card->first_line; - u8 status; - - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - status = cyy_readb(info, CyMSVR1); - status |= cyy_readb(info, CyMSVR2); - spin_unlock_irqrestore(&card->card_lock, flags); - - if (info->rtsdtr_inv) { - result = ((status & CyRTS) ? TIOCM_DTR : 0) | - ((status & CyDTR) ? TIOCM_RTS : 0); - } else { - result = ((status & CyRTS) ? TIOCM_RTS : 0) | - ((status & CyDTR) ? TIOCM_DTR : 0); - } - result |= ((status & CyDCD) ? TIOCM_CAR : 0) | - ((status & CyRI) ? TIOCM_RNG : 0) | - ((status & CyDSR) ? TIOCM_DSR : 0) | - ((status & CyCTS) ? TIOCM_CTS : 0); - } else { - u32 lstatus; - - if (!cyz_is_loaded(card)) { - result = -ENODEV; - goto end; - } - - lstatus = readl(&info->u.cyz.ch_ctrl->rs_status); - result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | - ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | - ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | - ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) | - ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) | - ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); - } -end: - return result; -} /* cy_tiomget */ - -static int -cy_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - card = info->card; - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, set, clear); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int retval, channel = info->line - card->first_line; - u32 rs; - - if (!cyz_is_loaded(card)) - return -ENODEV; - - spin_lock_irqsave(&card->card_lock, flags); - rs = readl(&ch_ctrl->rs_control); - if (set & TIOCM_RTS) - rs |= C_RS_RTS; - if (clear & TIOCM_RTS) - rs &= ~C_RS_RTS; - if (set & TIOCM_DTR) { - rs |= C_RS_DTR; -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n"); -#endif - } - if (clear & TIOCM_DTR) { - rs &= ~C_RS_DTR; -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info clearing " - "Z DTR\n"); -#endif - } - cy_writel(&ch_ctrl->rs_control, rs); - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); - spin_unlock_irqrestore(&card->card_lock, flags); - if (retval != 0) { - printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d " - "was %x\n", info->line, retval); - } - } - return 0; -} - -/* - * cy_break() --- routine which turns the break handling on or off - */ -static int cy_break(struct tty_struct *tty, int break_state) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - int retval = 0; - - if (serial_paranoia_check(info, tty->name, "cy_break")) - return -EINVAL; - - card = info->card; - - spin_lock_irqsave(&card->card_lock, flags); - if (!cy_is_Z(card)) { - /* Let the transmit ISR take care of this (since it - requires stuffing characters into the output stream). - */ - if (break_state == -1) { - if (!info->breakon) { - info->breakon = 1; - if (!info->xmit_cnt) { - spin_unlock_irqrestore(&card->card_lock, flags); - start_xmit(info); - spin_lock_irqsave(&card->card_lock, flags); - } - } - } else { - if (!info->breakoff) { - info->breakoff = 1; - if (!info->xmit_cnt) { - spin_unlock_irqrestore(&card->card_lock, flags); - start_xmit(info); - spin_lock_irqsave(&card->card_lock, flags); - } - } - } - } else { - if (break_state == -1) { - retval = cyz_issue_cmd(card, - info->line - card->first_line, - C_CM_SET_BREAK, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:cy_break (set) retval on " - "ttyC%d was %x\n", info->line, retval); - } - } else { - retval = cyz_issue_cmd(card, - info->line - card->first_line, - C_CM_CLR_BREAK, 0L); - if (retval != 0) { - printk(KERN_DEBUG "cyc:cy_break (clr) retval " - "on ttyC%d was %x\n", info->line, - retval); - } - } - } - spin_unlock_irqrestore(&card->card_lock, flags); - return retval; -} /* cy_break */ - -static int set_threshold(struct cyclades_port *info, unsigned long value) -{ - struct cyclades_card *card = info->card; - unsigned long flags; - - if (!cy_is_Z(card)) { - info->cor3 &= ~CyREC_FIFO; - info->cor3 |= value & CyREC_FIFO; - - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCOR3, info->cor3); - cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch); - spin_unlock_irqrestore(&card->card_lock, flags); - } - return 0; -} /* set_threshold */ - -static int get_threshold(struct cyclades_port *info, - unsigned long __user *value) -{ - struct cyclades_card *card = info->card; - - if (!cy_is_Z(card)) { - u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO; - return put_user(tmp, value); - } - return 0; -} /* get_threshold */ - -static int set_timeout(struct cyclades_port *info, unsigned long value) -{ - struct cyclades_card *card = info->card; - unsigned long flags; - - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyRTPR, value & 0xff); - spin_unlock_irqrestore(&card->card_lock, flags); - } - return 0; -} /* set_timeout */ - -static int get_timeout(struct cyclades_port *info, - unsigned long __user *value) -{ - struct cyclades_card *card = info->card; - - if (!cy_is_Z(card)) { - u8 tmp = cyy_readb(info, CyRTPR); - return put_user(tmp, value); - } - return 0; -} /* get_timeout */ - -static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg, - struct cyclades_icount *cprev) -{ - struct cyclades_icount cnow; - unsigned long flags; - int ret; - - spin_lock_irqsave(&info->card->card_lock, flags); - cnow = info->icount; /* atomic copy */ - spin_unlock_irqrestore(&info->card->card_lock, flags); - - ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); - - *cprev = cnow; - - return ret; -} - -/* - * This routine allows the tty driver to implement device- - * specific ioctl's. If the ioctl number passed in cmd is - * not recognized by the driver, it should return ENOIOCTLCMD. - */ -static int -cy_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_icount cnow; /* kernel counter temps */ - int ret_val = 0; - unsigned long flags; - void __user *argp = (void __user *)arg; - - if (serial_paranoia_check(info, tty->name, "cy_ioctl")) - return -ENODEV; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", - info->line, cmd, arg); -#endif - - switch (cmd) { - case CYGETMON: - if (copy_to_user(argp, &info->mon, sizeof(info->mon))) { - ret_val = -EFAULT; - break; - } - memset(&info->mon, 0, sizeof(info->mon)); - break; - case CYGETTHRESH: - ret_val = get_threshold(info, argp); - break; - case CYSETTHRESH: - ret_val = set_threshold(info, arg); - break; - case CYGETDEFTHRESH: - ret_val = put_user(info->default_threshold, - (unsigned long __user *)argp); - break; - case CYSETDEFTHRESH: - info->default_threshold = arg & 0x0f; - break; - case CYGETTIMEOUT: - ret_val = get_timeout(info, argp); - break; - case CYSETTIMEOUT: - ret_val = set_timeout(info, arg); - break; - case CYGETDEFTIMEOUT: - ret_val = put_user(info->default_timeout, - (unsigned long __user *)argp); - break; - case CYSETDEFTIMEOUT: - info->default_timeout = arg & 0xff; - break; - case CYSETRFLOW: - info->rflow = (int)arg; - break; - case CYGETRFLOW: - ret_val = info->rflow; - break; - case CYSETRTSDTR_INV: - info->rtsdtr_inv = (int)arg; - break; - case CYGETRTSDTR_INV: - ret_val = info->rtsdtr_inv; - break; - case CYGETCD1400VER: - ret_val = info->chip_rev; - break; -#ifndef CONFIG_CYZ_INTR - case CYZSETPOLLCYCLE: - if (arg > LONG_MAX / HZ) - return -ENODEV; - cyz_polling_cycle = (arg * HZ) / 1000; - break; - case CYZGETPOLLCYCLE: - ret_val = (cyz_polling_cycle * 1000) / HZ; - break; -#endif /* CONFIG_CYZ_INTR */ - case CYSETWAIT: - info->port.closing_wait = (unsigned short)arg * HZ / 100; - break; - case CYGETWAIT: - ret_val = info->port.closing_wait / (HZ / 100); - break; - case TIOCSERGETLSR: /* Get line status register */ - ret_val = get_lsr_info(info, argp); - break; - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: - spin_lock_irqsave(&info->card->card_lock, flags); - /* note the counters on entry */ - cnow = info->icount; - spin_unlock_irqrestore(&info->card->card_lock, flags); - ret_val = wait_event_interruptible(info->port.delta_msr_wait, - cy_cflags_changed(info, arg, &cnow)); - break; - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - default: - ret_val = -ENOIOCTLCMD; - } - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_ioctl done\n"); -#endif - return ret_val; -} /* cy_ioctl */ - -static int cy_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *sic) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_icount cnow; /* Used to snapshot */ - unsigned long flags; - - spin_lock_irqsave(&info->card->card_lock, flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->card->card_lock, flags); - - sic->cts = cnow.cts; - sic->dsr = cnow.dsr; - sic->rng = cnow.rng; - sic->dcd = cnow.dcd; - sic->rx = cnow.rx; - sic->tx = cnow.tx; - sic->frame = cnow.frame; - sic->overrun = cnow.overrun; - sic->parity = cnow.parity; - sic->brk = cnow.brk; - sic->buf_overrun = cnow.buf_overrun; - return 0; -} - -/* - * This routine allows the tty driver to be notified when - * device's termios settings have changed. Note that a - * well-designed tty driver should be prepared to accept the case - * where old == NULL, and try to do something rational. - */ -static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct cyclades_port *info = tty->driver_data; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); -#endif - - cy_set_line_char(info, tty); - - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - cy_start(tty); - } -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) - wake_up_interruptible(&info->port.open_wait); -#endif -} /* cy_set_termios */ - -/* This function is used to send a high-priority XON/XOFF character to - the device. -*/ -static void cy_send_xchar(struct tty_struct *tty, char ch) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int channel; - - if (serial_paranoia_check(info, tty->name, "cy_send_xchar")) - return; - - info->x_char = ch; - - if (ch) - cy_start(tty); - - card = info->card; - channel = info->line - card->first_line; - - if (cy_is_Z(card)) { - if (ch == STOP_CHAR(tty)) - cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L); - else if (ch == START_CHAR(tty)) - cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L); - } -} - -/* This routine is called by the upper-layer tty layer to signal - that incoming characters should be throttled because the input - buffers are close to full. - */ -static void cy_throttle(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - -#ifdef CY_DEBUG_THROTTLE - printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty), - info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_throttle")) - return; - - card = info->card; - - if (I_IXOFF(tty)) { - if (!cy_is_Z(card)) - cy_send_xchar(tty, STOP_CHAR(tty)); - else - info->throttle = 1; - } - - if (C_CRTSCTS(tty)) { - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, 0, TIOCM_RTS); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - info->throttle = 1; - } - } -} /* cy_throttle */ - -/* - * This routine notifies the tty driver that it should signal - * that characters can now be sent to the tty without fear of - * overrunning the input buffers of the line disciplines. - */ -static void cy_unthrottle(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - -#ifdef CY_DEBUG_THROTTLE - printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n", - tty_name(tty), info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - cy_send_xchar(tty, START_CHAR(tty)); - } - - if (C_CRTSCTS(tty)) { - card = info->card; - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, TIOCM_RTS, 0); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - info->throttle = 0; - } - } -} /* cy_unthrottle */ - -/* cy_start and cy_stop provide software output flow control as a - function of XON/XOFF, software CTS, and other such stuff. -*/ -static void cy_stop(struct tty_struct *tty) -{ - struct cyclades_card *cinfo; - struct cyclades_port *info = tty->driver_data; - int channel; - unsigned long flags; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_stop")) - return; - - cinfo = info->card; - channel = info->line - cinfo->first_line; - if (!cy_is_Z(cinfo)) { - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); - spin_unlock_irqrestore(&cinfo->card_lock, flags); - } -} /* cy_stop */ - -static void cy_start(struct tty_struct *tty) -{ - struct cyclades_card *cinfo; - struct cyclades_port *info = tty->driver_data; - int channel; - unsigned long flags; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_start")) - return; - - cinfo = info->card; - channel = info->line - cinfo->first_line; - if (!cy_is_Z(cinfo)) { - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); - spin_unlock_irqrestore(&cinfo->card_lock, flags); - } -} /* cy_start */ - -/* - * cy_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void cy_hangup(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_hangup")) - return; - - cy_flush_buffer(tty); - cy_shutdown(info, tty); - tty_port_hangup(&info->port); -} /* cy_hangup */ - -static int cyy_carrier_raised(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - unsigned long flags; - int channel = info->line - cinfo->first_line; - u32 cd; - - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cd = cyy_readb(info, CyMSVR1) & CyDCD; - spin_unlock_irqrestore(&cinfo->card_lock, flags); - - return cd; -} - -static void cyy_dtr_rts(struct tty_port *port, int raise) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - unsigned long flags; - - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0, - raise ? 0 : TIOCM_RTS | TIOCM_DTR); - spin_unlock_irqrestore(&cinfo->card_lock, flags); -} - -static int cyz_carrier_raised(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - - return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD; -} - -static void cyz_dtr_rts(struct tty_port *port, int raise) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int ret, channel = info->line - cinfo->first_line; - u32 rs; - - rs = readl(&ch_ctrl->rs_control); - if (raise) - rs |= C_RS_RTS | C_RS_DTR; - else - rs &= ~(C_RS_RTS | C_RS_DTR); - cy_writel(&ch_ctrl->rs_control, rs); - ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L); - if (ret != 0) - printk(KERN_ERR "%s: retval on ttyC%d was %x\n", - __func__, info->line, ret); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "%s: raising Z DTR\n", __func__); -#endif -} - -static const struct tty_port_operations cyy_port_ops = { - .carrier_raised = cyy_carrier_raised, - .dtr_rts = cyy_dtr_rts, - .shutdown = cy_do_close, -}; - -static const struct tty_port_operations cyz_port_ops = { - .carrier_raised = cyz_carrier_raised, - .dtr_rts = cyz_dtr_rts, - .shutdown = cy_do_close, -}; - -/* - * --------------------------------------------------------------------- - * cy_init() and friends - * - * cy_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -static int cy_init_card(struct cyclades_card *cinfo) -{ - struct cyclades_port *info; - unsigned int channel, port; - - spin_lock_init(&cinfo->card_lock); - cinfo->intr_enabled = 0; - - cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports), - GFP_KERNEL); - if (cinfo->ports == NULL) { - printk(KERN_ERR "Cyclades: cannot allocate ports\n"); - return -ENOMEM; - } - - for (channel = 0, port = cinfo->first_line; channel < cinfo->nports; - channel++, port++) { - info = &cinfo->ports[channel]; - tty_port_init(&info->port); - info->magic = CYCLADES_MAGIC; - info->card = cinfo; - info->line = port; - - info->port.closing_wait = CLOSING_WAIT_DELAY; - info->port.close_delay = 5 * HZ / 10; - init_completion(&info->shutdown_wait); - - if (cy_is_Z(cinfo)) { - struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS; - struct ZFW_CTRL *zfw_ctrl; - - info->port.ops = &cyz_port_ops; - info->type = PORT_STARTECH; - - zfw_ctrl = cinfo->base_addr + - (readl(&firm_id->zfwctrl_addr) & 0xfffff); - info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel]; - info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; - - if (cinfo->hw_ver == ZO_V1) - info->xmit_fifo_size = CYZ_FIFO_SIZE; - else - info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE; -#ifdef CONFIG_CYZ_INTR - timer_setup(&info->rx_full_timer, cyz_rx_restart, 0); -#endif - } else { - unsigned short chip_number; - int index = cinfo->bus_index; - - info->port.ops = &cyy_port_ops; - info->type = PORT_CIRRUS; - info->xmit_fifo_size = CyMAX_CHAR_FIFO; - info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; - info->cor2 = CyETC; - info->cor3 = 0x08; /* _very_ small rcv threshold */ - - chip_number = channel / CyPORTS_PER_CHIP; - info->u.cyy.base_addr = cinfo->base_addr + - (cy_chip_offset[chip_number] << index); - info->chip_rev = cyy_readb(info, CyGFRCR); - - if (info->chip_rev >= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[13]; /* Tx BPR */ - info->tco = baud_co_60[13]; /* Tx CO */ - info->rbpr = baud_bpr_60[13]; /* Rx BPR */ - info->rco = baud_co_60[13]; /* Rx CO */ - info->rtsdtr_inv = 1; - } else { - info->tbpr = baud_bpr_25[13]; /* Tx BPR */ - info->tco = baud_co_25[13]; /* Tx CO */ - info->rbpr = baud_bpr_25[13]; /* Rx BPR */ - info->rco = baud_co_25[13]; /* Rx CO */ - info->rtsdtr_inv = 0; - } - info->read_status_mask = CyTIMEOUT | CySPECHAR | - CyBREAK | CyPARITY | CyFRAME | CyOVERRUN; - } - - } - -#ifndef CONFIG_CYZ_INTR - if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) { - mod_timer(&cyz_timerlist, jiffies + 1); -#ifdef CY_PCI_DEBUG - printk(KERN_DEBUG "Cyclades-Z polling initialized\n"); -#endif - } -#endif - return 0; -} - -/* initialize chips on Cyclom-Y card -- return number of valid - chips (which is number of ports/4) */ -static unsigned short cyy_init_card(void __iomem *true_base_addr, - int index) -{ - unsigned int chip_number; - void __iomem *base_addr; - - cy_writeb(true_base_addr + (Cy_HwReset << index), 0); - /* Cy_HwReset is 0x1400 */ - cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - udelay(500L); - - for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; - chip_number++) { - base_addr = - true_base_addr + (cy_chip_offset[chip_number] << index); - mdelay(1); - if (readb(base_addr + (CyCCR << index)) != 0x00) { - /************* - printk(" chip #%d at %#6lx is never idle (CCR != 0)\n", - chip_number, (unsigned long)base_addr); - *************/ - return chip_number; - } - - cy_writeb(base_addr + (CyGFRCR << index), 0); - udelay(10L); - - /* The Cyclom-16Y does not decode address bit 9 and therefore - cannot distinguish between references to chip 0 and a non- - existent chip 4. If the preceding clearing of the supposed - chip 4 GFRCR register appears at chip 0, there is no chip 4 - and this must be a Cyclom-16Y, not a Cyclom-32Ye. - */ - if (chip_number == 4 && readb(true_base_addr + - (cy_chip_offset[0] << index) + - (CyGFRCR << index)) == 0) { - return chip_number; - } - - cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET); - mdelay(1); - - if (readb(base_addr + (CyGFRCR << index)) == 0x00) { - /* - printk(" chip #%d at %#6lx is not responding ", - chip_number, (unsigned long)base_addr); - printk("(GFRCR stayed 0)\n", - */ - return chip_number; - } - if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) != - 0x40) { - /* - printk(" chip #%d at %#6lx is not valid (GFRCR == " - "%#2x)\n", - chip_number, (unsigned long)base_addr, - base_addr[CyGFRCR<<index]); - */ - return chip_number; - } - cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL); - if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - /* Impossible to reach 5ms with this chip. - Changed to 2ms instead (f = 500 Hz). */ - cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS); - } else { - /* f = 200 Hz */ - cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS); - } - - /* - printk(" chip #%d at %#6lx is rev 0x%2x\n", - chip_number, (unsigned long)base_addr, - readb(base_addr+(CyGFRCR<<index))); - */ - } - return chip_number; -} /* cyy_init_card */ - -/* - * --------------------------------------------------------------------- - * cy_detect_isa() - Probe for Cyclom-Y/ISA boards. - * sets global variables and return the number of ISA boards found. - * --------------------------------------------------------------------- - */ -static int __init cy_detect_isa(void) -{ -#ifdef CONFIG_ISA - struct cyclades_card *card; - unsigned short cy_isa_irq, nboard; - void __iomem *cy_isa_address; - unsigned short i, j, k, cy_isa_nchan; - int isparam = 0; - - nboard = 0; - - /* Check for module parameters */ - for (i = 0; i < NR_CARDS; i++) { - if (maddr[i] || i) { - isparam = 1; - cy_isa_addresses[i] = maddr[i]; - } - if (!maddr[i]) - break; - } - - /* scan the address table probing for Cyclom-Y/ISA boards */ - for (i = 0; i < NR_ISA_ADDRS; i++) { - unsigned int isa_address = cy_isa_addresses[i]; - if (isa_address == 0x0000) - return nboard; - - /* probe for CD1400... */ - cy_isa_address = ioremap(isa_address, CyISA_Ywin); - if (cy_isa_address == NULL) { - printk(KERN_ERR "Cyclom-Y/ISA: can't remap base " - "address\n"); - continue; - } - cy_isa_nchan = CyPORTS_PER_CHIP * - cyy_init_card(cy_isa_address, 0); - if (cy_isa_nchan == 0) { - iounmap(cy_isa_address); - continue; - } - - if (isparam && i < NR_CARDS && irq[i]) - cy_isa_irq = irq[i]; - else - /* find out the board's irq by probing */ - cy_isa_irq = detect_isa_irq(cy_isa_address); - if (cy_isa_irq == 0) { - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the " - "IRQ could not be detected.\n", - (unsigned long)cy_isa_address); - iounmap(cy_isa_address); - continue; - } - - if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) { - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " - "more channels are available. Change NR_PORTS " - "in cyclades.c and recompile kernel.\n", - (unsigned long)cy_isa_address); - iounmap(cy_isa_address); - return nboard; - } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - card = &cy_card[j]; - if (card->base_addr == NULL) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " - "more cards can be used. Change NR_CARDS in " - "cyclades.c and recompile kernel.\n", - (unsigned long)cy_isa_address); - iounmap(cy_isa_address); - return nboard; - } - - /* allocate IRQ */ - if (request_irq(cy_isa_irq, cyy_interrupt, - 0, "Cyclom-Y", card)) { - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " - "could not allocate IRQ#%d.\n", - (unsigned long)cy_isa_address, cy_isa_irq); - iounmap(cy_isa_address); - return nboard; - } - - /* set cy_card */ - card->base_addr = cy_isa_address; - card->ctl_addr.p9050 = NULL; - card->irq = (int)cy_isa_irq; - card->bus_index = 0; - card->first_line = cy_next_channel; - card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; - card->nports = cy_isa_nchan; - if (cy_init_card(card)) { - card->base_addr = NULL; - free_irq(cy_isa_irq, card); - iounmap(cy_isa_address); - continue; - } - nboard++; - - printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " - "%d channels starting from port %d\n", - j + 1, (unsigned long)cy_isa_address, - (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), - cy_isa_irq, cy_isa_nchan, cy_next_channel); - - for (k = 0, j = cy_next_channel; - j < cy_next_channel + cy_isa_nchan; j++, k++) - tty_port_register_device(&card->ports[k].port, - cy_serial_driver, j, NULL); - cy_next_channel += cy_isa_nchan; - } - return nboard; -#else - return 0; -#endif /* CONFIG_ISA */ -} /* cy_detect_isa */ - -#ifdef CONFIG_PCI -static inline int cyc_isfwstr(const char *str, unsigned int size) -{ - unsigned int a; - - for (a = 0; a < size && *str; a++, str++) - if (*str & 0x80) - return -EINVAL; - - for (; a < size; a++, str++) - if (*str) - return -EINVAL; - - return 0; -} - -static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data, - unsigned int size) -{ - for (; size > 0; size--) { - cy_writel(fpga, *data++); - udelay(10); - } -} - -static void plx_init(struct pci_dev *pdev, int irq, - struct RUNTIME_9060 __iomem *addr) -{ - /* Reset PLX */ - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000); - udelay(100L); - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000); - - /* Reload Config. Registers from EEPROM */ - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000); - udelay(100L); - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000); - - /* For some yet unknown reason, once the PLX9060 reloads the EEPROM, - * the IRQ is lost and, thus, we have to re-write it to the PCI config. - * registers. This will remain here until we find a permanent fix. - */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); -} - -static int __cyz_load_fw(const struct firmware *fw, - const char *name, const u32 mailbox, void __iomem *base, - void __iomem *fpga) -{ - const void *ptr = fw->data; - const struct zfile_header *h = ptr; - const struct zfile_config *c, *cs; - const struct zfile_block *b, *bs; - unsigned int a, tmp, len = fw->size; -#define BAD_FW KERN_ERR "Bad firmware: " - if (len < sizeof(*h)) { - printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h)); - return -EINVAL; - } - - cs = ptr + h->config_offset; - bs = ptr + h->block_offset; - - if ((void *)(cs + h->n_config) > ptr + len || - (void *)(bs + h->n_blocks) > ptr + len) { - printk(BAD_FW "too short"); - return -EINVAL; - } - - if (cyc_isfwstr(h->name, sizeof(h->name)) || - cyc_isfwstr(h->date, sizeof(h->date))) { - printk(BAD_FW "bad formatted header string\n"); - return -EINVAL; - } - - if (strncmp(name, h->name, sizeof(h->name))) { - printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name); - return -EINVAL; - } - - tmp = 0; - for (c = cs; c < cs + h->n_config; c++) { - for (a = 0; a < c->n_blocks; a++) - if (c->block_list[a] > h->n_blocks) { - printk(BAD_FW "bad block ref number in cfgs\n"); - return -EINVAL; - } - if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */ - tmp++; - } - if (!tmp) { - printk(BAD_FW "nothing appropriate\n"); - return -EINVAL; - } - - for (b = bs; b < bs + h->n_blocks; b++) - if (b->file_offset + b->size > len) { - printk(BAD_FW "bad block data offset\n"); - return -EINVAL; - } - - /* everything is OK, let's seek'n'load it */ - for (c = cs; c < cs + h->n_config; c++) - if (c->mailbox == mailbox && c->function == 0) - break; - - for (a = 0; a < c->n_blocks; a++) { - b = &bs[c->block_list[a]]; - if (b->type == ZBLOCK_FPGA) { - if (fpga != NULL) - cyz_fpga_copy(fpga, ptr + b->file_offset, - b->size); - } else { - if (base != NULL) - memcpy_toio(base + b->ram_offset, - ptr + b->file_offset, b->size); - } - } -#undef BAD_FW - return 0; -} - -static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, - struct RUNTIME_9060 __iomem *ctl_addr, int irq) -{ - const struct firmware *fw; - struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS; - struct CUSTOM_REG __iomem *cust = base_addr; - struct ZFW_CTRL __iomem *pt_zfwctrl; - void __iomem *tmp; - u32 mailbox, status, nchan; - unsigned int i; - int retval; - - retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev); - if (retval) { - dev_err(&pdev->dev, "can't get firmware\n"); - goto err; - } - - /* Check whether the firmware is already loaded and running. If - positive, skip this board */ - if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) { - u32 cntval = readl(base_addr + 0x190); - - udelay(100); - if (cntval != readl(base_addr + 0x190)) { - /* FW counter is working, FW is running */ - dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. " - "Skipping board.\n"); - retval = 0; - goto err_rel; - } - } - - /* start boot */ - cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) & - ~0x00030800UL); - - mailbox = readl(&ctl_addr->mail_box_0); - - if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) { - /* stops CPU and set window to beginning of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - cy_writel(&cust->cpu_stop, 0); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - udelay(100); - } - - plx_init(pdev, irq, ctl_addr); - - if (mailbox != 0) { - /* load FPGA */ - retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL, - base_addr); - if (retval) - goto err_rel; - if (!__cyz_fpga_loaded(ctl_addr)) { - dev_err(&pdev->dev, "fw upload successful, but fw is " - "not loaded\n"); - goto err_rel; - } - } - - /* stops CPU and set window to beginning of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - cy_writel(&cust->cpu_stop, 0); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - udelay(100); - - /* clear memory */ - for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) - cy_writeb(tmp, 255); - if (mailbox != 0) { - /* set window to last 512K of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE); - for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) - cy_writeb(tmp, 255); - /* set window to beginning of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - } - - retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL); - release_firmware(fw); - if (retval) - goto err; - - /* finish boot and start boards */ - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - cy_writel(&cust->cpu_start, 0); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - i = 0; - while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40) - msleep(100); - if (status != ZFIRM_ID) { - if (status == ZFIRM_HLT) { - dev_err(&pdev->dev, "you need an external power supply " - "for this number of ports. Firmware halted and " - "board reset.\n"); - retval = -EIO; - goto err; - } - dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting " - "some more time\n", status); - while ((status = readl(&fid->signature)) != ZFIRM_ID && - i++ < 200) - msleep(100); - if (status != ZFIRM_ID) { - dev_err(&pdev->dev, "Board not started in 20 seconds! " - "Giving up. (fid->signature = 0x%x)\n", - status); - dev_info(&pdev->dev, "*** Warning ***: if you are " - "upgrading the FW, please power cycle the " - "system before loading the new FW to the " - "Cyclades-Z.\n"); - - if (__cyz_fpga_loaded(ctl_addr)) - plx_init(pdev, irq, ctl_addr); - - retval = -EIO; - goto err; - } - dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n", - i / 10); - } - pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr); - - dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n", - base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr), - base_addr + readl(&fid->zfwctrl_addr)); - - nchan = readl(&pt_zfwctrl->board_ctrl.n_channel); - dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n", - readl(&pt_zfwctrl->board_ctrl.fw_version), nchan); - - if (nchan == 0) { - dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please " - "check the connection between the Z host card and the " - "serial expanders.\n"); - - if (__cyz_fpga_loaded(ctl_addr)) - plx_init(pdev, irq, ctl_addr); - - dev_info(&pdev->dev, "Null number of ports detected. Board " - "reset.\n"); - retval = 0; - goto err; - } - - cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX); - cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION); - - /* - Early firmware failed to start looking for commands. - This enables firmware interrupts for those commands. - */ - cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | - (1 << 17)); - cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | - 0x00030800UL); - - return nchan; -err_rel: - release_firmware(fw); -err: - return retval; -} - -static int cy_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct cyclades_card *card; - void __iomem *addr0 = NULL, *addr2 = NULL; - char *card_name = NULL; - u32 mailbox; - unsigned int device_id, nchan = 0, card_no, i, j; - unsigned char plx_ver; - int retval, irq; - - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "cannot enable device\n"); - goto err; - } - - /* read PCI configuration area */ - irq = pdev->irq; - device_id = pdev->device & ~PCI_DEVICE_ID_MASK; - -#if defined(__alpha__) - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ - dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low " - "addresses on Alpha systems.\n"); - retval = -EIO; - goto err_dis; - } -#endif - if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { - dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low " - "addresses\n"); - retval = -EIO; - goto err_dis; - } - - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring " - "it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } - - retval = pci_request_regions(pdev, "cyclades"); - if (retval) { - dev_err(&pdev->dev, "failed to reserve resources\n"); - goto err_dis; - } - - retval = -EIO; - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - card_name = "Cyclom-Y"; - - addr0 = ioremap(pci_resource_start(pdev, 0), - CyPCI_Yctl); - if (addr0 == NULL) { - dev_err(&pdev->dev, "can't remap ctl region\n"); - goto err_reg; - } - addr2 = ioremap(pci_resource_start(pdev, 2), - CyPCI_Ywin); - if (addr2 == NULL) { - dev_err(&pdev->dev, "can't remap base region\n"); - goto err_unmap; - } - - nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1); - if (nchan == 0) { - dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " - "Serial-Modules\n"); - goto err_unmap; - } - } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { - struct RUNTIME_9060 __iomem *ctl_addr; - - ctl_addr = addr0 = ioremap(pci_resource_start(pdev, 0), - CyPCI_Zctl); - if (addr0 == NULL) { - dev_err(&pdev->dev, "can't remap ctl region\n"); - goto err_reg; - } - - /* Disable interrupts on the PLX before resetting it */ - cy_writew(&ctl_addr->intr_ctrl_stat, - readw(&ctl_addr->intr_ctrl_stat) & ~0x0900); - - plx_init(pdev, irq, addr0); - - mailbox = readl(&ctl_addr->mail_box_0); - - addr2 = ioremap(pci_resource_start(pdev, 2), - mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); - if (addr2 == NULL) { - dev_err(&pdev->dev, "can't remap base region\n"); - goto err_unmap; - } - - if (mailbox == ZE_V1) { - card_name = "Cyclades-Ze"; - } else { - card_name = "Cyclades-8Zo"; -#ifdef CY_PCI_DEBUG - if (mailbox == ZO_V1) { - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA " - "id %lx, ver %lx\n", (ulong)(0xff & - readl(&((struct CUSTOM_REG *)addr2)-> - fpga_id)), (ulong)(0xff & - readl(&((struct CUSTOM_REG *)addr2)-> - fpga_version))); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - } else { - dev_info(&pdev->dev, "Cyclades-Z/PCI: New " - "Cyclades-Z board. FPGA not loaded\n"); - } -#endif - /* The following clears the firmware id word. This - ensures that the driver will not attempt to talk to - the board until it has been properly initialized. - */ - if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel(addr2 + ID_ADDRESS, 0L); - } - - retval = cyz_load_fw(pdev, addr2, addr0, irq); - if (retval <= 0) - goto err_unmap; - nchan = retval; - } - - if ((cy_next_channel + nchan) > NR_PORTS) { - dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " - "channels are available. Change NR_PORTS in " - "cyclades.c and recompile kernel.\n"); - goto err_unmap; - } - /* fill the next cy_card structure available */ - for (card_no = 0; card_no < NR_CARDS; card_no++) { - card = &cy_card[card_no]; - if (card->base_addr == NULL) - break; - } - if (card_no == NR_CARDS) { /* no more cy_cards available */ - dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " - "more cards can be used. Change NR_CARDS in " - "cyclades.c and recompile kernel.\n"); - goto err_unmap; - } - - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - /* allocate IRQ */ - retval = request_irq(irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", card); - if (retval) { - dev_err(&pdev->dev, "could not allocate IRQ\n"); - goto err_unmap; - } - card->num_chips = nchan / CyPORTS_PER_CHIP; - } else { - struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS; - struct ZFW_CTRL __iomem *zfw_ctrl; - - zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - - card->hw_ver = mailbox; - card->num_chips = (unsigned int)-1; - card->board_ctrl = &zfw_ctrl->board_ctrl; -#ifdef CONFIG_CYZ_INTR - /* allocate IRQ only if board has an IRQ */ - if (irq != 0 && irq != 255) { - retval = request_irq(irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", card); - if (retval) { - dev_err(&pdev->dev, "could not allocate IRQ\n"); - goto err_unmap; - } - } -#endif /* CONFIG_CYZ_INTR */ - } - - /* set cy_card */ - card->base_addr = addr2; - card->ctl_addr.p9050 = addr0; - card->irq = irq; - card->bus_index = 1; - card->first_line = cy_next_channel; - card->nports = nchan; - retval = cy_init_card(card); - if (retval) - goto err_null; - - pci_set_drvdata(pdev, card); - - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - /* enable interrupts in the PCI interface */ - plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - cy_writeb(addr0 + 0x4c, 0x43); - break; - - case PLX_9060: - case PLX_9080: - default: /* Old boards, use PLX_9060 */ - { - struct RUNTIME_9060 __iomem *ctl_addr = addr0; - plx_init(pdev, irq, ctl_addr); - cy_writew(&ctl_addr->intr_ctrl_stat, - readw(&ctl_addr->intr_ctrl_stat) | 0x0900); - break; - } - } - } - - dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " - "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); - for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++) - tty_port_register_device(&card->ports[j].port, - cy_serial_driver, i, &pdev->dev); - cy_next_channel += nchan; - - return 0; -err_null: - card->base_addr = NULL; - free_irq(irq, card); -err_unmap: - iounmap(addr0); - if (addr2) - iounmap(addr2); -err_reg: - pci_release_regions(pdev); -err_dis: - pci_disable_device(pdev); -err: - return retval; -} - -static void cy_pci_remove(struct pci_dev *pdev) -{ - struct cyclades_card *cinfo = pci_get_drvdata(pdev); - unsigned int i, channel; - - /* non-Z with old PLX */ - if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == - PLX_9050) - cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0); - else -#ifndef CONFIG_CYZ_INTR - if (!cy_is_Z(cinfo)) -#endif - cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat, - readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) & - ~0x0900); - - iounmap(cinfo->base_addr); - if (cinfo->ctl_addr.p9050) - iounmap(cinfo->ctl_addr.p9050); - if (cinfo->irq -#ifndef CONFIG_CYZ_INTR - && !cy_is_Z(cinfo) -#endif /* CONFIG_CYZ_INTR */ - ) - free_irq(cinfo->irq, cinfo); - pci_release_regions(pdev); - - cinfo->base_addr = NULL; - for (channel = 0, i = cinfo->first_line; i < cinfo->first_line + - cinfo->nports; i++, channel++) { - tty_unregister_device(cy_serial_driver, i); - tty_port_destroy(&cinfo->ports[channel].port); - } - cinfo->nports = 0; - kfree(cinfo->ports); -} - -static struct pci_driver cy_pci_driver = { - .name = "cyclades", - .id_table = cy_pci_dev_id, - .probe = cy_pci_probe, - .remove = cy_pci_remove -}; -#endif - -static int cyclades_proc_show(struct seq_file *m, void *v) -{ - struct cyclades_port *info; - unsigned int i, j; - __u32 cur_jifs = jiffies; - - seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn " - "IdleIn Overruns Ldisc\n"); - - /* Output one line for each known port */ - for (i = 0; i < NR_CARDS; i++) - for (j = 0; j < cy_card[i].nports; j++) { - info = &cy_card[i].ports[j]; - - if (info->port.count) { - /* XXX is the ldisc num worth this? */ - struct tty_struct *tty; - struct tty_ldisc *ld; - int num = 0; - tty = tty_port_tty_get(&info->port); - if (tty) { - ld = tty_ldisc_ref(tty); - if (ld) { - num = ld->ops->num; - tty_ldisc_deref(ld); - } - tty_kref_put(tty); - } - seq_printf(m, "%3d %8lu %10lu %8lu " - "%10lu %8lu %9lu %6d\n", info->line, - (cur_jifs - info->idle_stats.in_use) / - HZ, info->idle_stats.xmit_bytes, - (cur_jifs - info->idle_stats.xmit_idle)/ - HZ, info->idle_stats.recv_bytes, - (cur_jifs - info->idle_stats.recv_idle)/ - HZ, info->idle_stats.overruns, - num); - } else - seq_printf(m, "%3d %8lu %10lu %8lu " - "%10lu %8lu %9lu %6ld\n", - info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); - } - return 0; -} - -/* The serial driver boot-time initialization code! - Hardware I/O ports are mapped to character special devices on a - first found, first allocated manner. That is, this code searches - for Cyclom cards in the system. As each is found, it is probed - to discover how many chips (and thus how many ports) are present. - These ports are mapped to the tty ports 32 and upward in monotonic - fashion. If an 8-port card is replaced with a 16-port card, the - port mapping on a following card will shift. - - This approach is different from what is used in the other serial - device driver because the Cyclom is more properly a multiplexer, - not just an aggregation of serial ports on one card. - - If there are more cards with more ports than have been - statically allocated above, a warning is printed and the - extra ports are ignored. - */ - -static const struct tty_operations cy_ops = { - .open = cy_open, - .close = cy_close, - .write = cy_write, - .put_char = cy_put_char, - .flush_chars = cy_flush_chars, - .write_room = cy_write_room, - .chars_in_buffer = cy_chars_in_buffer, - .flush_buffer = cy_flush_buffer, - .ioctl = cy_ioctl, - .throttle = cy_throttle, - .unthrottle = cy_unthrottle, - .set_termios = cy_set_termios, - .stop = cy_stop, - .start = cy_start, - .hangup = cy_hangup, - .break_ctl = cy_break, - .wait_until_sent = cy_wait_until_sent, - .tiocmget = cy_tiocmget, - .tiocmset = cy_tiocmset, - .get_icount = cy_get_icount, - .set_serial = cy_set_serial_info, - .get_serial = cy_get_serial_info, - .proc_show = cyclades_proc_show, -}; - -static int __init cy_init(void) -{ - unsigned int nboards; - int retval = -ENOMEM; - - cy_serial_driver = alloc_tty_driver(NR_PORTS); - if (!cy_serial_driver) - goto err; - - printk(KERN_INFO "Cyclades driver " CY_VERSION "\n"); - - /* Initialize the tty_driver structure */ - - cy_serial_driver->driver_name = "cyclades"; - cy_serial_driver->name = "ttyC"; - cy_serial_driver->major = CYCLADES_MAJOR; - cy_serial_driver->minor_start = 0; - cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - cy_serial_driver->subtype = SERIAL_TYPE_NORMAL; - cy_serial_driver->init_termios = tty_std_termios; - cy_serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(cy_serial_driver, &cy_ops); - - retval = tty_register_driver(cy_serial_driver); - if (retval) { - printk(KERN_ERR "Couldn't register Cyclades serial driver\n"); - goto err_frtty; - } - - /* the code below is responsible to find the boards. Each different - type of board has its own detection routine. If a board is found, - the next cy_card structure available is set by the detection - routine. These functions are responsible for checking the - availability of cy_card and cy_port data structures and updating - the cy_next_channel. */ - - /* look for isa boards */ - nboards = cy_detect_isa(); - -#ifdef CONFIG_PCI - /* look for pci boards */ - retval = pci_register_driver(&cy_pci_driver); - if (retval && !nboards) { - tty_unregister_driver(cy_serial_driver); - goto err_frtty; - } -#endif - - return 0; -err_frtty: - put_tty_driver(cy_serial_driver); -err: - return retval; -} /* cy_init */ - -static void __exit cy_cleanup_module(void) -{ - struct cyclades_card *card; - unsigned int i, e1; - -#ifndef CONFIG_CYZ_INTR - del_timer_sync(&cyz_timerlist); -#endif /* CONFIG_CYZ_INTR */ - - e1 = tty_unregister_driver(cy_serial_driver); - if (e1) - printk(KERN_ERR "failed to unregister Cyclades serial " - "driver(%d)\n", e1); - -#ifdef CONFIG_PCI - pci_unregister_driver(&cy_pci_driver); -#endif - - for (i = 0; i < NR_CARDS; i++) { - card = &cy_card[i]; - if (card->base_addr) { - /* clear interrupt */ - cy_writeb(card->base_addr + Cy_ClrIntr, 0); - iounmap(card->base_addr); - if (card->ctl_addr.p9050) - iounmap(card->ctl_addr.p9050); - if (card->irq -#ifndef CONFIG_CYZ_INTR - && !cy_is_Z(card) -#endif /* CONFIG_CYZ_INTR */ - ) - free_irq(card->irq, card); - for (e1 = card->first_line; e1 < card->first_line + - card->nports; e1++) - tty_unregister_device(cy_serial_driver, e1); - kfree(card->ports); - } - } - - put_tty_driver(cy_serial_driver); -} /* cy_cleanup_module */ - -module_init(cy_init); -module_exit(cy_cleanup_module); - -MODULE_LICENSE("GPL"); -MODULE_VERSION(CY_VERSION); -MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR); -MODULE_FIRMWARE("cyzfirm.bin"); diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index a4c9913f76a0672bf8cb7b69d28ce1a42447cb4b..ff0dcc56413c4c98b339ac99306b4adca7a480fa 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c @@ -17,7 +17,7 @@ #include "hvc_console.h" -struct hvc_struct *hvc_udbg_dev; +static struct hvc_struct *hvc_udbg_dev; static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) { diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 9afa1dcef2c2f247fceb509a3153f59808078d5f..197988c55e0cf25ed6965279116ad793cf728a9a 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -290,35 +290,11 @@ static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static DEFINE_MUTEX(hvcs_init_mutex); -static void hvcs_unthrottle(struct tty_struct *tty); -static void hvcs_throttle(struct tty_struct *tty); -static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance); - -static int hvcs_write(struct tty_struct *tty, - const unsigned char *buf, int count); -static int hvcs_write_room(struct tty_struct *tty); -static int hvcs_chars_in_buffer(struct tty_struct *tty); - -static int hvcs_has_pi(struct hvcs_struct *hvcsd); -static void hvcs_set_pi(struct hvcs_partner_info *pi, - struct hvcs_struct *hvcsd); static int hvcs_get_pi(struct hvcs_struct *hvcsd); static int hvcs_rescan_devices_list(void); -static int hvcs_partner_connect(struct hvcs_struct *hvcsd); static void hvcs_partner_free(struct hvcs_struct *hvcsd); -static int hvcs_enable_device(struct hvcs_struct *hvcsd, - uint32_t unit_address, unsigned int irq, struct vio_dev *dev); - -static int hvcs_open(struct tty_struct *tty, struct file *filp); -static void hvcs_close(struct tty_struct *tty, struct file *filp); -static void hvcs_hangup(struct tty_struct * tty); - -static int hvcs_probe(struct vio_dev *dev, - const struct vio_device_id *id); -static int __init hvcs_module_init(void); -static void __exit hvcs_module_exit(void); static int hvcs_initialize(void); #define HVCS_SCHED_READ 0x00000001 diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 6dacbc5e286c1092b5a4a0c92149355ae2360c5d..99bb2f149ff5c22d09e43397392f17a528f866ae 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -235,10 +235,10 @@ static int ipw_write_room(struct tty_struct *linux_tty) /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) - return -ENODEV; + return 0; if (!tty->port.count) - return -EINVAL; + return 0; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; if (room < 0) @@ -596,13 +596,8 @@ int ipwireless_tty_init(void) void ipwireless_tty_release(void) { - int ret; - - ret = tty_unregister_driver(ipw_tty_driver); + tty_unregister_driver(ipw_tty_driver); put_tty_driver(ipw_tty_driver); - if (ret != 0) - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": tty_unregister_driver failed with code %d\n", ret); } int ipwireless_tty_is_modem(struct ipw_tty *tty) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c deleted file mode 100644 index 3b2f9fb01aa0a987940fff519712169c7647d4a6..0000000000000000000000000000000000000000 --- a/drivers/tty/isicom.c +++ /dev/null @@ -1,1699 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Original driver code supplied by Multi-Tech - * - * Changes - * 1/9/98 alan@lxorguk.ukuu.org.uk - * Merge to 2.0.x kernel tree - * Obtain and use official major/minors - * Loader switched to a misc device - * (fixed range check bug as a side effect) - * Printk clean up - * 9/12/98 alan@lxorguk.ukuu.org.uk - * Rough port to 2.1.x - * - * 10/6/99 sameer Merged the ISA and PCI drivers to - * a new unified driver. - * - * 3/9/99 sameer Added support for ISI4616 cards. - * - * 16/9/99 sameer We do not force RTS low anymore. - * This is to prevent the firmware - * from getting confused. - * - * 26/10/99 sameer Cosmetic changes:The driver now - * dumps the Port Count information - * along with I/O address and IRQ. - * - * 13/12/99 sameer Fixed the problem with IRQ sharing. - * - * 10/5/00 sameer Fixed isicom_shutdown_board() - * to not lower DTR on all the ports - * when the last port on the card is - * closed. - * - * 10/5/00 sameer Signal mask setup command added - * to isicom_setup_port and - * isicom_shutdown_port. - * - * 24/5/00 sameer The driver is now SMP aware. - * - * - * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem - * - * - * 03/01/01 anil .s Added support for resetting the - * internal modems on ISI cards. - * - * 08/02/01 anil .s Upgraded the driver for kernel - * 2.4.x - * - * 11/04/01 Kevin Fixed firmware load problem with - * ISIHP-4X card - * - * 30/04/01 anil .s Fixed the remote login through - * ISI port problem. Now the link - * does not go down before password - * prompt. - * - * 03/05/01 anil .s Fixed the problem with IRQ sharing - * among ISI-PCI cards. - * - * 03/05/01 anil .s Added support to display the version - * info during insmod as well as module - * listing by lsmod. - * - * 10/05/01 anil .s Done the modifications to the source - * file and Install script so that the - * same installation can be used for - * 2.2.x and 2.4.x kernel. - * - * 06/06/01 anil .s Now we drop both dtr and rts during - * shutdown_port as well as raise them - * during isicom_config_port. - * - * 09/06/01 acme@conectiva.com.br use capable, not suser, do - * restore_flags on failure in - * isicom_send_break, verify put_user - * result - * - * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps - * Baud index extended to 21 - * - * 20/03/03 ranjeeth Made to work for Linux Advanced server. - * Taken care of license warning. - * - * 10/12/03 Ravindra Made to work for Fedora Core 1 of - * Red Hat Distribution - * - * 06/01/05 Alan Cox Merged the ISI and base kernel strands - * into a single 2.6 driver - * - * *********************************************************** - * - * To use this driver you also need the support package. You - * can find this in RPM format on - * ftp://ftp.linux.org.uk/pub/linux/alan - * - * You can find the original tools for this direct from Multitech - * ftp://ftp.multitech.com/ISI-Cards/ - * - * Having installed the cards the module options (/etc/modprobe.d/) - * - * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4 - * - * Omit those entries for boards you don't have installed. - * - * TODO - * Merge testing - * 64-bit verification - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/firmware.h> -#include <linux/kernel.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/termios.h> -#include <linux/fs.h> -#include <linux/sched.h> -#include <linux/serial.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> - -#include <linux/uaccess.h> -#include <linux/io.h> - -#include <linux/pci.h> - -#include <linux/isicom.h> - -#define InterruptTheCard(base) outw(0, (base) + 0xc) -#define ClearInterrupt(base) inw((base) + 0x0a) - -#ifdef DEBUG -#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) -#else -#define isicom_paranoia_check(a, b, c) 0 -#endif - -static int isicom_probe(struct pci_dev *, const struct pci_device_id *); -static void isicom_remove(struct pci_dev *); - -static const struct pci_device_id isicom_pci_tbl[] = { - { PCI_DEVICE(VENDOR_ID, 0x2028) }, - { PCI_DEVICE(VENDOR_ID, 0x2051) }, - { PCI_DEVICE(VENDOR_ID, 0x2052) }, - { PCI_DEVICE(VENDOR_ID, 0x2053) }, - { PCI_DEVICE(VENDOR_ID, 0x2054) }, - { PCI_DEVICE(VENDOR_ID, 0x2055) }, - { PCI_DEVICE(VENDOR_ID, 0x2056) }, - { PCI_DEVICE(VENDOR_ID, 0x2057) }, - { PCI_DEVICE(VENDOR_ID, 0x2058) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, isicom_pci_tbl); - -static struct pci_driver isicom_driver = { - .name = "isicom", - .id_table = isicom_pci_tbl, - .probe = isicom_probe, - .remove = isicom_remove -}; - -static int prev_card = 3; /* start servicing isi_card[0] */ -static struct tty_driver *isicom_normal; - -static void isicom_tx(struct timer_list *unused); -static void isicom_start(struct tty_struct *tty); - -static DEFINE_TIMER(tx, isicom_tx); - -/* baud index mappings from linux defns to isi */ - -static signed char linuxb_to_isib[] = { - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21 -}; - -struct isi_board { - unsigned long base; - int irq; - unsigned char port_count; - unsigned short status; - unsigned short port_status; /* each bit for each port */ - unsigned short shift_count; - struct isi_port *ports; - signed char count; - spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ - unsigned long flags; - unsigned int index; -}; - -struct isi_port { - unsigned short magic; - struct tty_port port; - u16 channel; - u16 status; - struct isi_board *card; - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; -}; - -static struct isi_board isi_card[BOARD_COUNT]; -static struct isi_port isi_ports[PORT_COUNT]; - -/* - * Locking functions for card level locking. We need to own both - * the kernel lock for the card and have the card in a position that - * it wants to talk. - */ - -static int WaitTillCardIsFree(unsigned long base) -{ - unsigned int count = 0; - - while (!(inw(base + 0xe) & 0x1) && count++ < 100) - mdelay(1); - - return !(inw(base + 0xe) & 0x1); -} - -static int lock_card(struct isi_board *card) -{ - unsigned long base = card->base; - unsigned int retries, a; - - for (retries = 0; retries < 10; retries++) { - spin_lock_irqsave(&card->card_lock, card->flags); - for (a = 0; a < 10; a++) { - if (inw(base + 0xe) & 0x1) - return 1; - udelay(10); - } - spin_unlock_irqrestore(&card->card_lock, card->flags); - msleep(10); - } - pr_warn("Failed to lock Card (0x%lx)\n", card->base); - - return 0; /* Failed to acquire the card! */ -} - -static void unlock_card(struct isi_board *card) -{ - spin_unlock_irqrestore(&card->card_lock, card->flags); -} - -/* - * ISI Card specific ops ... - */ - -/* card->lock HAS to be held */ -static void raise_dtr(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0504, base); - InterruptTheCard(base); - port->status |= ISI_DTR; -} - -/* card->lock HAS to be held */ -static void drop_dtr(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0404, base); - InterruptTheCard(base); - port->status &= ~ISI_DTR; -} - -/* card->lock HAS to be held */ -static inline void raise_rts(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0a04, base); - InterruptTheCard(base); - port->status |= ISI_RTS; -} - -/* card->lock HAS to be held */ -static inline void drop_rts(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0804, base); - InterruptTheCard(base); - port->status &= ~ISI_RTS; -} - -/* card->lock MUST NOT be held */ - -static void isicom_dtr_rts(struct tty_port *port, int on) -{ - struct isi_port *ip = container_of(port, struct isi_port, port); - struct isi_board *card = ip->card; - unsigned long base = card->base; - u16 channel = ip->channel; - - if (!lock_card(card)) - return; - - if (on) { - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0f04, base); - InterruptTheCard(base); - ip->status |= (ISI_DTR | ISI_RTS); - } else { - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0C04, base); - InterruptTheCard(base); - ip->status &= ~(ISI_DTR | ISI_RTS); - } - unlock_card(card); -} - -/* card->lock HAS to be held */ -static void drop_dtr_rts(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0c04, base); - InterruptTheCard(base); - port->status &= ~(ISI_RTS | ISI_DTR); -} - -/* - * ISICOM Driver specific routines ... - * - */ - -static inline int __isicom_paranoia_check(struct isi_port const *port, - char *name, const char *routine) -{ - if (!port) { - pr_warn("Warning: bad isicom magic for dev %s in %s\n", - name, routine); - return 1; - } - if (port->magic != ISICOM_MAGIC) { - pr_warn("Warning: NULL isicom port for dev %s in %s\n", - name, routine); - return 1; - } - - return 0; -} - -/* - * Transmitter. - * - * We shovel data into the card buffers on a regular basis. The card - * will do the rest of the work for us. - */ - -static void isicom_tx(struct timer_list *unused) -{ - unsigned long flags, base; - unsigned int retries; - short count = (BOARD_COUNT-1), card; - short txcount, wrd, residue, word_count, cnt; - struct isi_port *port; - struct tty_struct *tty; - - /* find next active board */ - card = (prev_card + 1) & 0x0003; - while (count-- > 0) { - if (isi_card[card].status & BOARD_ACTIVE) - break; - card = (card + 1) & 0x0003; - } - if (!(isi_card[card].status & BOARD_ACTIVE)) - goto sched_again; - - prev_card = card; - - count = isi_card[card].port_count; - port = isi_card[card].ports; - base = isi_card[card].base; - - spin_lock_irqsave(&isi_card[card].card_lock, flags); - for (retries = 0; retries < 100; retries++) { - if (inw(base + 0xe) & 0x1) - break; - udelay(2); - } - if (retries >= 100) - goto unlock; - - tty = tty_port_tty_get(&port->port); - if (tty == NULL) - goto put_unlock; - - for (; count > 0; count--, port++) { - /* port not active or tx disabled to force flow control */ - if (!tty_port_initialized(&port->port) || - !(port->status & ISI_TXOK)) - continue; - - txcount = min_t(short, TX_SIZE, port->xmit_cnt); - if (txcount <= 0 || tty->stopped || tty->hw_stopped) - continue; - - if (!(inw(base + 0x02) & (1 << port->channel))) - continue; - - pr_debug("txing %d bytes, port%d.\n", - txcount, port->channel + 1); - outw((port->channel << isi_card[card].shift_count) | txcount, - base); - residue = NO; - wrd = 0; - while (1) { - cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - - port->xmit_tail)); - if (residue == YES) { - residue = NO; - if (cnt > 0) { - wrd |= (port->port.xmit_buf[port->xmit_tail] - << 8); - port->xmit_tail = (port->xmit_tail + 1) - & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - txcount--; - cnt--; - outw(wrd, base); - } else { - outw(wrd, base); - break; - } - } - if (cnt <= 0) - break; - word_count = cnt >> 1; - outsw(base, port->port.xmit_buf+port->xmit_tail, word_count); - port->xmit_tail = (port->xmit_tail - + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); - txcount -= (word_count << 1); - port->xmit_cnt -= (word_count << 1); - if (cnt & 0x0001) { - residue = YES; - wrd = port->port.xmit_buf[port->xmit_tail]; - port->xmit_tail = (port->xmit_tail + 1) - & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - txcount--; - } - } - - InterruptTheCard(base); - if (port->xmit_cnt <= 0) - port->status &= ~ISI_TXOK; - if (port->xmit_cnt <= WAKEUP_CHARS) - tty_wakeup(tty); - } - -put_unlock: - tty_kref_put(tty); -unlock: - spin_unlock_irqrestore(&isi_card[card].card_lock, flags); - /* schedule another tx for hopefully in about 10ms */ -sched_again: - mod_timer(&tx, jiffies + msecs_to_jiffies(10)); -} - -/* - * Main interrupt handler routine - */ - -static irqreturn_t isicom_interrupt(int irq, void *dev_id) -{ - struct isi_board *card = dev_id; - struct isi_port *port; - struct tty_struct *tty; - unsigned long base; - u16 header, word_count, count, channel; - short byte_count; - unsigned char *rp; - - if (!card || !(card->status & FIRMWARE_LOADED)) - return IRQ_NONE; - - base = card->base; - - /* did the card interrupt us? */ - if (!(inw(base + 0x0e) & 0x02)) - return IRQ_NONE; - - spin_lock(&card->card_lock); - - /* - * disable any interrupts from the PCI card and lower the - * interrupt line - */ - outw(0x8000, base+0x04); - ClearInterrupt(base); - - inw(base); /* get the dummy word out */ - header = inw(base); - channel = (header & 0x7800) >> card->shift_count; - byte_count = header & 0xff; - - if (channel + 1 > card->port_count) { - pr_warn("%s(0x%lx): %d(channel) > port_count\n", - __func__, base, channel + 1); - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - return IRQ_HANDLED; - } - port = card->ports + channel; - if (!tty_port_initialized(&port->port)) { - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - return IRQ_HANDLED; - } - - tty = tty_port_tty_get(&port->port); - if (tty == NULL) { - while (byte_count > 1) { - inw(base); - byte_count -= 2; - } - if (byte_count & 0x01) - inw(base); - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - return IRQ_HANDLED; - } - - if (header & 0x8000) { /* Status Packet */ - header = inw(base); - switch (header & 0xff) { - case 0: /* Change in EIA signals */ - if (tty_port_check_carrier(&port->port)) { - if (port->status & ISI_DCD) { - if (!(header & ISI_DCD)) { - /* Carrier has been lost */ - pr_debug("%s: DCD->low.\n", - __func__); - port->status &= ~ISI_DCD; - tty_hangup(tty); - } - } else if (header & ISI_DCD) { - /* Carrier has been detected */ - pr_debug("%s: DCD->high.\n", - __func__); - port->status |= ISI_DCD; - wake_up_interruptible(&port->port.open_wait); - } - } else { - if (header & ISI_DCD) - port->status |= ISI_DCD; - else - port->status &= ~ISI_DCD; - } - - if (tty_port_cts_enabled(&port->port)) { - if (tty->hw_stopped) { - if (header & ISI_CTS) { - tty->hw_stopped = 0; - /* start tx ing */ - port->status |= (ISI_TXOK - | ISI_CTS); - tty_wakeup(tty); - } - } else if (!(header & ISI_CTS)) { - tty->hw_stopped = 1; - /* stop tx ing */ - port->status &= ~(ISI_TXOK | ISI_CTS); - } - } else { - if (header & ISI_CTS) - port->status |= ISI_CTS; - else - port->status &= ~ISI_CTS; - } - - if (header & ISI_DSR) - port->status |= ISI_DSR; - else - port->status &= ~ISI_DSR; - - if (header & ISI_RI) - port->status |= ISI_RI; - else - port->status &= ~ISI_RI; - - break; - - case 1: /* Received Break !!! */ - tty_insert_flip_char(&port->port, 0, TTY_BREAK); - if (port->port.flags & ASYNC_SAK) - do_SAK(tty); - tty_flip_buffer_push(&port->port); - break; - - case 2: /* Statistics */ - pr_debug("%s: stats!!!\n", __func__); - break; - - default: - pr_debug("%s: Unknown code in status packet.\n", - __func__); - break; - } - } else { /* Data Packet */ - count = tty_prepare_flip_string(&port->port, &rp, - byte_count & ~1); - pr_debug("%s: Can rx %d of %d bytes.\n", - __func__, count, byte_count); - word_count = count >> 1; - insw(base, rp, word_count); - byte_count -= (word_count << 1); - if (count & 0x0001) { - tty_insert_flip_char(&port->port, inw(base) & 0xff, - TTY_NORMAL); - byte_count -= 2; - } - if (byte_count > 0) { - pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n", - __func__, base, channel + 1); - /* drain out unread xtra data */ - while (byte_count > 0) { - inw(base); - byte_count -= 2; - } - } - tty_flip_buffer_push(&port->port); - } - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - tty_kref_put(tty); - - return IRQ_HANDLED; -} - -static void isicom_config_port(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long baud; - unsigned long base = card->base; - u16 channel_setup, channel = port->channel, - shift_count = card->shift_count; - unsigned char flow_ctrl; - - /* FIXME: Switch to new tty baud API */ - baud = C_BAUD(tty); - if (baud & CBAUDEX) { - baud &= ~CBAUDEX; - - /* if CBAUDEX bit is on and the baud is set to either 50 or 75 - * then the card is programmed for 57.6Kbps or 115Kbps - * respectively. - */ - - /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ - if (baud < 1 || baud > 4) - tty->termios.c_cflag &= ~CBAUDEX; - else - baud += 15; - } - if (baud == 15) { - - /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set - * by the set_serial_info ioctl ... this is done by - * the 'setserial' utility. - */ - - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baud++; /* 57.6 Kbps */ - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baud += 2; /* 115 Kbps */ - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - baud += 3; /* 230 kbps*/ - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - baud += 4; /* 460 kbps*/ - } - if (linuxb_to_isib[baud] == -1) { - /* hang up */ - drop_dtr(port); - return; - } else - raise_dtr(port); - - if (WaitTillCardIsFree(base) == 0) { - outw(0x8000 | (channel << shift_count) | 0x03, base); - outw(linuxb_to_isib[baud] << 8 | 0x03, base); - channel_setup = 0; - switch (C_CSIZE(tty)) { - case CS5: - channel_setup |= ISICOM_CS5; - break; - case CS6: - channel_setup |= ISICOM_CS6; - break; - case CS7: - channel_setup |= ISICOM_CS7; - break; - case CS8: - channel_setup |= ISICOM_CS8; - break; - } - - if (C_CSTOPB(tty)) - channel_setup |= ISICOM_2SB; - if (C_PARENB(tty)) { - channel_setup |= ISICOM_EVPAR; - if (C_PARODD(tty)) - channel_setup |= ISICOM_ODPAR; - } - outw(channel_setup, base); - InterruptTheCard(base); - } - tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty)); - - /* flow control settings ...*/ - flow_ctrl = 0; - tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty)); - if (C_CRTSCTS(tty)) - flow_ctrl |= ISICOM_CTSRTS; - if (I_IXON(tty)) - flow_ctrl |= ISICOM_RESPOND_XONXOFF; - if (I_IXOFF(tty)) - flow_ctrl |= ISICOM_INITIATE_XONXOFF; - - if (WaitTillCardIsFree(base) == 0) { - outw(0x8000 | (channel << shift_count) | 0x04, base); - outw(flow_ctrl << 8 | 0x05, base); - outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); - InterruptTheCard(base); - } - - /* rx enabled -> enable port for rx on the card */ - if (C_CREAD(tty)) { - card->port_status |= (1 << channel); - outw(card->port_status, base + 0x02); - } -} - -/* open et all */ - -static inline void isicom_setup_board(struct isi_board *bp) -{ - int channel; - struct isi_port *port; - - bp->count++; - if (!(bp->status & BOARD_INIT)) { - port = bp->ports; - for (channel = 0; channel < bp->port_count; channel++, port++) - drop_dtr_rts(port); - } - bp->status |= BOARD_ACTIVE | BOARD_INIT; -} - -/* Activate and thus setup board are protected from races against shutdown - by the tty_port mutex */ - -static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) -{ - struct isi_port *port = container_of(tport, struct isi_port, port); - struct isi_board *card = port->card; - unsigned long flags; - - if (tty_port_alloc_xmit_buf(tport) < 0) - return -ENOMEM; - - spin_lock_irqsave(&card->card_lock, flags); - isicom_setup_board(card); - - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - - /* discard any residual data */ - if (WaitTillCardIsFree(card->base) == 0) { - outw(0x8000 | (port->channel << card->shift_count) | 0x02, - card->base); - outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); - InterruptTheCard(card->base); - } - isicom_config_port(tty); - spin_unlock_irqrestore(&card->card_lock, flags); - - return 0; -} - -static int isicom_carrier_raised(struct tty_port *port) -{ - struct isi_port *ip = container_of(port, struct isi_port, port); - return (ip->status & ISI_DCD)?1 : 0; -} - -static struct tty_port *isicom_find_port(struct tty_struct *tty) -{ - struct isi_port *port; - struct isi_board *card; - unsigned int board; - int line = tty->index; - - board = BOARD(line); - card = &isi_card[board]; - - if (!(card->status & FIRMWARE_LOADED)) - return NULL; - - /* open on a port greater than the port count for the card !!! */ - if (line > ((board * 16) + card->port_count - 1)) - return NULL; - - port = &isi_ports[line]; - if (isicom_paranoia_check(port, tty->name, "isicom_open")) - return NULL; - - return &port->port; -} - -static int isicom_open(struct tty_struct *tty, struct file *filp) -{ - struct isi_port *port; - struct tty_port *tport; - - tport = isicom_find_port(tty); - if (tport == NULL) - return -ENODEV; - port = container_of(tport, struct isi_port, port); - - tty->driver_data = port; - return tty_port_open(tport, tty, filp); -} - -/* close et all */ - -/* card->lock HAS to be held */ -static void isicom_shutdown_port(struct isi_port *port) -{ - struct isi_board *card = port->card; - - if (--card->count < 0) { - pr_debug("%s: bad board(0x%lx) count %d.\n", - __func__, card->base, card->count); - card->count = 0; - } - /* last port was closed, shutdown that board too */ - if (!card->count) - card->status &= BOARD_ACTIVE; -} - -static void isicom_flush_buffer(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer")) - return; - - spin_lock_irqsave(&card->card_lock, flags); - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - spin_unlock_irqrestore(&card->card_lock, flags); - - tty_wakeup(tty); -} - -static void isicom_shutdown(struct tty_port *port) -{ - struct isi_port *ip = container_of(port, struct isi_port, port); - struct isi_board *card = ip->card; - unsigned long flags; - - /* indicate to the card that no more data can be received - on this port */ - spin_lock_irqsave(&card->card_lock, flags); - card->port_status &= ~(1 << ip->channel); - outw(card->port_status, card->base + 0x02); - isicom_shutdown_port(ip); - spin_unlock_irqrestore(&card->card_lock, flags); - tty_port_free_xmit_buf(port); -} - -static void isicom_close(struct tty_struct *tty, struct file *filp) -{ - struct isi_port *ip = tty->driver_data; - struct tty_port *port; - - if (ip == NULL) - return; - - port = &ip->port; - if (isicom_paranoia_check(ip, tty->name, "isicom_close")) - return; - tty_port_close(port, tty, filp); -} - -/* write et all */ -static int isicom_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - int cnt, total = 0; - - if (isicom_paranoia_check(port, tty->name, "isicom_write")) - return 0; - - spin_lock_irqsave(&card->card_lock, flags); - - while (1) { - cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - - 1, SERIAL_XMIT_SIZE - port->xmit_head)); - if (cnt <= 0) - break; - - memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt); - port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - - 1); - port->xmit_cnt += cnt; - buf += cnt; - count -= cnt; - total += cnt; - } - if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) - port->status |= ISI_TXOK; - spin_unlock_irqrestore(&card->card_lock, flags); - return total; -} - -/* put_char et all */ -static int isicom_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) - return 0; - - spin_lock_irqsave(&card->card_lock, flags); - if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { - spin_unlock_irqrestore(&card->card_lock, flags); - return 0; - } - - port->port.xmit_buf[port->xmit_head++] = ch; - port->xmit_head &= (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt++; - spin_unlock_irqrestore(&card->card_lock, flags); - return 1; -} - -/* flush_chars et all */ -static void isicom_flush_chars(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars")) - return; - - if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !port->port.xmit_buf) - return; - - /* this tells the transmitter to consider this port for - data output to the card ... that's the best we can do. */ - port->status |= ISI_TXOK; -} - -/* write_room et all */ -static int isicom_write_room(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - int free; - - if (isicom_paranoia_check(port, tty->name, "isicom_write_room")) - return 0; - - free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; - if (free < 0) - free = 0; - return free; -} - -/* chars_in_buffer et all */ -static int isicom_chars_in_buffer(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer")) - return 0; - return port->xmit_cnt; -} - -/* ioctl et all */ -static int isicom_send_break(struct tty_struct *tty, int length) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long base = card->base; - - if (length == -1) - return -EOPNOTSUPP; - - if (!lock_card(card)) - return -EINVAL; - - outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); - outw((length & 0xff) << 8 | 0x00, base); - outw((length & 0xff00u), base); - InterruptTheCard(base); - - unlock_card(card); - return 0; -} - -static int isicom_tiocmget(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - /* just send the port status */ - u16 status = port->status; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - return ((status & ISI_RTS) ? TIOCM_RTS : 0) | - ((status & ISI_DTR) ? TIOCM_DTR : 0) | - ((status & ISI_DCD) ? TIOCM_CAR : 0) | - ((status & ISI_DSR) ? TIOCM_DSR : 0) | - ((status & ISI_CTS) ? TIOCM_CTS : 0) | - ((status & ISI_RI ) ? TIOCM_RI : 0); -} - -static int isicom_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct isi_port *port = tty->driver_data; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - spin_lock_irqsave(&port->card->card_lock, flags); - if (set & TIOCM_RTS) - raise_rts(port); - if (set & TIOCM_DTR) - raise_dtr(port); - - if (clear & TIOCM_RTS) - drop_rts(port); - if (clear & TIOCM_DTR) - drop_dtr(port); - spin_unlock_irqrestore(&port->card->card_lock, flags); - - return 0; -} - -static int isicom_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct isi_port *port = tty->driver_data; - int reconfig_port; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - mutex_lock(&port->port.mutex); - reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != - (ss->flags & ASYNC_SPD_MASK)); - - if (!capable(CAP_SYS_ADMIN)) { - if ((ss->close_delay != port->port.close_delay) || - (ss->closing_wait != port->port.closing_wait) || - ((ss->flags & ~ASYNC_USR_MASK) != - (port->port.flags & ~ASYNC_USR_MASK))) { - mutex_unlock(&port->port.mutex); - return -EPERM; - } - port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK)); - } else { - port->port.close_delay = ss->close_delay; - port->port.closing_wait = ss->closing_wait; - port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | - (ss->flags & ASYNC_FLAGS)); - } - if (reconfig_port) { - unsigned long flags; - spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); - spin_unlock_irqrestore(&port->card->card_lock, flags); - } - mutex_unlock(&port->port.mutex); - return 0; -} - -static int isicom_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - mutex_lock(&port->port.mutex); -/* ss->type = ? */ - ss->line = port - isi_ports; - ss->port = port->card->base; - ss->irq = port->card->irq; - ss->flags = port->port.flags; -/* ss->baud_base = ? */ - ss->close_delay = port->port.close_delay; - ss->closing_wait = port->port.closing_wait; - mutex_unlock(&port->port.mutex); - return 0; -} - -/* set_termios et all */ -static void isicom_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct isi_port *port = tty->driver_data; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) - return; - - if (tty->termios.c_cflag == old_termios->c_cflag && - tty->termios.c_iflag == old_termios->c_iflag) - return; - - spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); - spin_unlock_irqrestore(&port->card->card_lock, flags); - - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - isicom_start(tty); - } -} - -/* throttle et all */ -static void isicom_throttle(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - - if (isicom_paranoia_check(port, tty->name, "isicom_throttle")) - return; - - /* tell the card that this port cannot handle any more data for now */ - card->port_status &= ~(1 << port->channel); - outw(card->port_status, card->base + 0x02); -} - -/* unthrottle et all */ -static void isicom_unthrottle(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - - if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle")) - return; - - /* tell the card that this port is ready to accept more data */ - card->port_status |= (1 << port->channel); - outw(card->port_status, card->base + 0x02); -} - -/* stop et all */ -static void isicom_stop(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_stop")) - return; - - /* this tells the transmitter not to consider this port for - data output to the card. */ - port->status &= ~ISI_TXOK; -} - -/* start et all */ -static void isicom_start(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_start")) - return; - - /* this tells the transmitter to consider this port for - data output to the card. */ - port->status |= ISI_TXOK; -} - -static void isicom_hangup(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) - return; - tty_port_hangup(&port->port); -} - - -/* - * Driver init and deinit functions - */ - -static const struct tty_operations isicom_ops = { - .open = isicom_open, - .close = isicom_close, - .write = isicom_write, - .put_char = isicom_put_char, - .flush_chars = isicom_flush_chars, - .write_room = isicom_write_room, - .chars_in_buffer = isicom_chars_in_buffer, - .set_termios = isicom_set_termios, - .throttle = isicom_throttle, - .unthrottle = isicom_unthrottle, - .stop = isicom_stop, - .start = isicom_start, - .hangup = isicom_hangup, - .flush_buffer = isicom_flush_buffer, - .tiocmget = isicom_tiocmget, - .tiocmset = isicom_tiocmset, - .break_ctl = isicom_send_break, - .get_serial = isicom_get_serial_info, - .set_serial = isicom_set_serial_info, -}; - -static const struct tty_port_operations isicom_port_ops = { - .carrier_raised = isicom_carrier_raised, - .dtr_rts = isicom_dtr_rts, - .activate = isicom_activate, - .shutdown = isicom_shutdown, -}; - -static int reset_card(struct pci_dev *pdev, - const unsigned int card, unsigned int *signature) -{ - struct isi_board *board = pci_get_drvdata(pdev); - unsigned long base = board->base; - unsigned int sig, portcount = 0; - int retval = 0; - - dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1, - base); - - inw(base + 0x8); - - msleep(10); - - outw(0, base + 0x8); /* Reset */ - - msleep(1000); - - sig = inw(base + 0x4) & 0xff; - - if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd && - sig != 0xee) { - dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible " - "bad I/O Port Address 0x%lx).\n", card + 1, base); - dev_dbg(&pdev->dev, "Sig=0x%x\n", sig); - retval = -EIO; - goto end; - } - - msleep(10); - - portcount = inw(base + 0x2); - if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 && - portcount != 8 && portcount != 16)) { - dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n", - card + 1); - retval = -EIO; - goto end; - } - - switch (sig) { - case 0xa5: - case 0xbb: - case 0xdd: - board->port_count = (portcount == 4) ? 4 : 8; - board->shift_count = 12; - break; - case 0xcc: - case 0xee: - board->port_count = 16; - board->shift_count = 11; - break; - } - dev_info(&pdev->dev, "-Done\n"); - *signature = sig; - -end: - return retval; -} - -static int load_firmware(struct pci_dev *pdev, - const unsigned int index, const unsigned int signature) -{ - struct isi_board *board = pci_get_drvdata(pdev); - const struct firmware *fw; - unsigned long base = board->base; - unsigned int a; - u16 word_count, status; - int retval = -EIO; - char *name; - u8 *data; - - struct stframe { - u16 addr; - u16 count; - u8 data[0]; - } *frame; - - switch (signature) { - case 0xa5: - name = "isi608.bin"; - break; - case 0xbb: - name = "isi608em.bin"; - break; - case 0xcc: - name = "isi616em.bin"; - break; - case 0xdd: - name = "isi4608.bin"; - break; - case 0xee: - name = "isi4616.bin"; - break; - default: - dev_err(&pdev->dev, "Unknown signature.\n"); - goto end; - } - - retval = request_firmware(&fw, name, &pdev->dev); - if (retval) - goto end; - - retval = -EIO; - - for (frame = (struct stframe *)fw->data; - frame < (struct stframe *)(fw->data + fw->size); - frame = (struct stframe *)((u8 *)(frame + 1) + - frame->count)) { - if (WaitTillCardIsFree(base)) - goto errrelfw; - - outw(0xf0, base); /* start upload sequence */ - outw(0x00, base); - outw(frame->addr, base); /* lsb of address */ - - word_count = frame->count / 2 + frame->count % 2; - outw(word_count, base); - InterruptTheCard(base); - - udelay(100); /* 0x2f */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_warn(&pdev->dev, "Card%d rejected load header:\n" - "Address:0x%x\n" - "Count:0x%x\n" - "Status:0x%x\n", - index + 1, frame->addr, frame->count, status); - goto errrelfw; - } - outsw(base, frame->data, word_count); - - InterruptTheCard(base); - - udelay(50); /* 0x0f */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_err(&pdev->dev, "Card%d got out of sync.Card " - "Status:0x%x\n", index + 1, status); - goto errrelfw; - } - } - -/* XXX: should we test it by reading it back and comparing with original like - * in load firmware package? */ - for (frame = (struct stframe *)fw->data; - frame < (struct stframe *)(fw->data + fw->size); - frame = (struct stframe *)((u8 *)(frame + 1) + - frame->count)) { - if (WaitTillCardIsFree(base)) - goto errrelfw; - - outw(0xf1, base); /* start download sequence */ - outw(0x00, base); - outw(frame->addr, base); /* lsb of address */ - - word_count = (frame->count >> 1) + frame->count % 2; - outw(word_count + 1, base); - InterruptTheCard(base); - - udelay(50); /* 0xf */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_warn(&pdev->dev, "Card%d rejected verify header:\n" - "Address:0x%x\n" - "Count:0x%x\n" - "Status: 0x%x\n", - index + 1, frame->addr, frame->count, status); - goto errrelfw; - } - - data = kmalloc_array(word_count, 2, GFP_KERNEL); - if (data == NULL) { - dev_err(&pdev->dev, "Card%d, firmware upload " - "failed, not enough memory\n", index + 1); - goto errrelfw; - } - inw(base); - insw(base, data, word_count); - InterruptTheCard(base); - - for (a = 0; a < frame->count; a++) - if (data[a] != frame->data[a]) { - kfree(data); - dev_err(&pdev->dev, "Card%d, firmware upload " - "failed\n", index + 1); - goto errrelfw; - } - kfree(data); - - udelay(50); /* 0xf */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_err(&pdev->dev, "Card%d verify got out of sync. " - "Card Status:0x%x\n", index + 1, status); - goto errrelfw; - } - } - - /* xfer ctrl */ - if (WaitTillCardIsFree(base)) - goto errrelfw; - - outw(0xf2, base); - outw(0x800, base); - outw(0x0, base); - outw(0x0, base); - InterruptTheCard(base); - outw(0x0, base + 0x4); /* for ISI4608 cards */ - - board->status |= FIRMWARE_LOADED; - retval = 0; - -errrelfw: - release_firmware(fw); -end: - return retval; -} - -/* - * Insmod can set static symbols so keep these static - */ -static unsigned int card_count; - -static int isicom_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - unsigned int signature, index; - int retval = -EPERM; - struct isi_board *board = NULL; - - if (card_count >= BOARD_COUNT) - goto err; - - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "failed to enable\n"); - goto err; - } - - dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device); - - /* allot the first empty slot in the array */ - for (index = 0; index < BOARD_COUNT; index++) { - if (isi_card[index].base == 0) { - board = &isi_card[index]; - break; - } - } - if (index == BOARD_COUNT) { - retval = -ENODEV; - goto err_disable; - } - - board->index = index; - board->base = pci_resource_start(pdev, 3); - board->irq = pdev->irq; - card_count++; - - pci_set_drvdata(pdev, board); - - retval = pci_request_region(pdev, 3, ISICOM_NAME); - if (retval) { - dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d " - "will be disabled.\n", board->base, board->base + 15, - index + 1); - retval = -EBUSY; - goto errdec; - } - - retval = request_irq(board->irq, isicom_interrupt, - IRQF_SHARED, ISICOM_NAME, board); - if (retval < 0) { - dev_err(&pdev->dev, "Could not install handler at Irq %d. " - "Card%d will be disabled.\n", board->irq, index + 1); - goto errunrr; - } - - retval = reset_card(pdev, index, &signature); - if (retval < 0) - goto errunri; - - retval = load_firmware(pdev, index, signature); - if (retval < 0) - goto errunri; - - for (index = 0; index < board->port_count; index++) { - struct tty_port *tport = &board->ports[index].port; - tty_port_init(tport); - tport->ops = &isicom_port_ops; - tport->close_delay = 50 * HZ/100; - tport->closing_wait = 3000 * HZ/100; - tty_port_register_device(tport, isicom_normal, - board->index * 16 + index, &pdev->dev); - } - - return 0; - -errunri: - free_irq(board->irq, board); -errunrr: - pci_release_region(pdev, 3); -errdec: - board->base = 0; - card_count--; -err_disable: - pci_disable_device(pdev); -err: - return retval; -} - -static void isicom_remove(struct pci_dev *pdev) -{ - struct isi_board *board = pci_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < board->port_count; i++) { - tty_unregister_device(isicom_normal, board->index * 16 + i); - tty_port_destroy(&board->ports[i].port); - } - - free_irq(board->irq, board); - pci_release_region(pdev, 3); - board->base = 0; - card_count--; - pci_disable_device(pdev); -} - -static int __init isicom_init(void) -{ - int retval, idx, channel; - struct isi_port *port; - - for (idx = 0; idx < BOARD_COUNT; idx++) { - port = &isi_ports[idx * 16]; - isi_card[idx].ports = port; - spin_lock_init(&isi_card[idx].card_lock); - for (channel = 0; channel < 16; channel++, port++) { - port->magic = ISICOM_MAGIC; - port->card = &isi_card[idx]; - port->channel = channel; - port->status = 0; - /* . . . */ - } - isi_card[idx].base = 0; - isi_card[idx].irq = 0; - } - - /* tty driver structure initialization */ - isicom_normal = alloc_tty_driver(PORT_COUNT); - if (!isicom_normal) { - retval = -ENOMEM; - goto error; - } - - isicom_normal->name = "ttyM"; - isicom_normal->major = ISICOM_NMAJOR; - isicom_normal->minor_start = 0; - isicom_normal->type = TTY_DRIVER_TYPE_SERIAL; - isicom_normal->subtype = SERIAL_TYPE_NORMAL; - isicom_normal->init_termios = tty_std_termios; - isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | - CLOCAL; - isicom_normal->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK; - tty_set_operations(isicom_normal, &isicom_ops); - - retval = tty_register_driver(isicom_normal); - if (retval) { - pr_debug("Couldn't register the dialin driver\n"); - goto err_puttty; - } - - retval = pci_register_driver(&isicom_driver); - if (retval < 0) { - pr_err("Unable to register pci driver.\n"); - goto err_unrtty; - } - - mod_timer(&tx, jiffies + 1); - - return 0; -err_unrtty: - tty_unregister_driver(isicom_normal); -err_puttty: - put_tty_driver(isicom_normal); -error: - return retval; -} - -static void __exit isicom_exit(void) -{ - del_timer_sync(&tx); - - pci_unregister_driver(&isicom_driver); - tty_unregister_driver(isicom_normal); - put_tty_driver(isicom_normal); -} - -module_init(isicom_init); -module_exit(isicom_exit); - -MODULE_AUTHOR("MultiTech"); -MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("isi608.bin"); -MODULE_FIRMWARE("isi608em.bin"); -MODULE_FIRMWARE("isi616em.bin"); -MODULE_FIRMWARE("isi4608.bin"); -MODULE_FIRMWARE("isi4616.bin"); diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 9f13f7d49dd78874283efbb3a0286a776b882dc3..4d4f15b5cd29819a0ced008d1069a364202317f7 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1118,9 +1118,7 @@ static void __exit moxa_exit(void) del_timer_sync(&moxaTimer); - if (tty_unregister_driver(moxaDriver)) - printk(KERN_ERR "Couldn't unregister MOXA Intellio family " - "serial driver\n"); + tty_unregister_driver(moxaDriver); put_tty_driver(moxaDriver); } @@ -2040,7 +2038,7 @@ static int moxa_get_serial_info(struct tty_struct *tty, ss->line = info->port.tty->index, ss->flags = info->port.flags, ss->baud_base = 921600, - ss->close_delay = info->port.close_delay; + ss->close_delay = jiffies_to_msecs(info->port.close_delay) / 10; mutex_unlock(&info->port.mutex); return 0; } @@ -2050,30 +2048,31 @@ static int moxa_set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct moxa_port *info = tty->driver_data; + unsigned int close_delay; if (tty->index == MAX_PORTS) return -EINVAL; if (!info) return -ENODEV; - if (ss->irq != 0 || ss->port != 0 || - ss->custom_divisor != 0 || - ss->baud_base != 921600) - return -EPERM; + close_delay = msecs_to_jiffies(ss->close_delay * 10); mutex_lock(&info->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if (((ss->flags & ~ASYNC_USR_MASK) != + if (close_delay != info->port.close_delay || + ss->type != info->type || + ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) { mutex_unlock(&info->port.mutex); return -EPERM; } - } - info->port.close_delay = ss->close_delay * HZ / 100; + } else { + info->port.close_delay = close_delay; - MoxaSetFifo(info, ss->type == PORT_16550A); + MoxaSetFifo(info, ss->type == PORT_16550A); - info->type = ss->type; + info->type = ss->type; + } mutex_unlock(&info->port.mutex); return 0; } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 4203b64bccdb1b6c89c29aaf9ee2ca868465062e..16a852ecbe8a6a4e3ce2ff610dfd6cfd29d03405 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1208,19 +1208,26 @@ static int mxser_get_serial_info(struct tty_struct *tty, { struct mxser_port *info = tty->driver_data; struct tty_port *port = &info->port; + unsigned int closing_wait, close_delay; if (tty->index == MXSER_PORTS) return -ENOTTY; mutex_lock(&port->mutex); + + close_delay = jiffies_to_msecs(info->port.close_delay) / 10; + closing_wait = info->port.closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = jiffies_to_msecs(closing_wait) / 10; + ss->type = info->type, ss->line = tty->index, ss->port = info->ioaddr, ss->irq = info->board->irq, ss->flags = info->port.flags, ss->baud_base = info->baud_base, - ss->close_delay = info->port.close_delay, - ss->closing_wait = info->port.closing_wait, + ss->close_delay = close_delay; + ss->closing_wait = closing_wait; ss->custom_divisor = info->custom_divisor, mutex_unlock(&port->mutex); return 0; @@ -1233,7 +1240,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, struct tty_port *port = &info->port; speed_t baud; unsigned long sl_flags; - unsigned int flags; + unsigned int flags, close_delay, closing_wait; int retval = 0; if (tty->index == MXSER_PORTS) @@ -1255,9 +1262,15 @@ static int mxser_set_serial_info(struct tty_struct *tty, flags = port->flags & ASYNC_SPD_MASK; + close_delay = msecs_to_jiffies(ss->close_delay * 10); + closing_wait = ss->closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = msecs_to_jiffies(closing_wait * 10); + if (!capable(CAP_SYS_ADMIN)) { if ((ss->baud_base != info->baud_base) || - (ss->close_delay != info->port.close_delay) || + (close_delay != info->port.close_delay) || + (closing_wait != info->port.closing_wait) || ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) { mutex_unlock(&port->mutex); return -EPERM; @@ -1271,8 +1284,8 @@ static int mxser_set_serial_info(struct tty_struct *tty, */ port->flags = ((port->flags & ~ASYNC_FLAGS) | (ss->flags & ASYNC_FLAGS)); - port->close_delay = ss->close_delay * HZ / 100; - port->closing_wait = ss->closing_wait * HZ / 100; + port->close_delay = close_delay; + port->closing_wait = closing_wait; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && (ss->baud_base != info->baud_base || ss->custom_divisor != @@ -1284,11 +1297,11 @@ static int mxser_set_serial_info(struct tty_struct *tty, baud = ss->baud_base / ss->custom_divisor; tty_encode_baud_rate(tty, baud, baud); } - } - info->type = ss->type; + info->type = ss->type; - process_txrx_fifo(info); + process_txrx_fifo(info); + } if (tty_port_initialized(port)) { if (flags != (port->flags & ASYNC_SPD_MASK)) { @@ -2142,14 +2155,7 @@ end_intr: port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; - /* - * We are called from an interrupt context with &port->slock - * being held. Drop it temporarily in order to prevent - * recursive locking. - */ - spin_unlock(&port->slock); tty_flip_buffer_push(&port->port); - spin_lock(&port->slock); } static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 51dafc06f5414d9e59f2b68400715b5b8afdbc88..5fea02cfb0ccf73e06e135ce54457a9c0b329637 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -50,6 +50,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/gsmmux.h> +#include "tty.h" static int debug; module_param(debug, int, 0600); @@ -266,7 +267,7 @@ struct gsm_mux { #define MAX_MUX 4 /* 256 minors */ static struct gsm_mux *gsm_mux[MAX_MUX]; /* GSM muxes */ -static spinlock_t gsm_mux_lock; +static DEFINE_SPINLOCK(gsm_mux_lock); static struct tty_driver *gsm_tty_driver; @@ -2384,8 +2385,18 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) /* Don't register device 0 - this is the control channel and not a usable tty interface */ base = mux_num_to_base(gsm); /* Base for this MUX */ - for (i = 1; i < NUM_DLCI; i++) - tty_register_device(gsm_tty_driver, base + i, NULL); + for (i = 1; i < NUM_DLCI; i++) { + struct device *dev; + + dev = tty_register_device(gsm_tty_driver, + base + i, NULL); + if (IS_ERR(dev)) { + for (i--; i >= 1; i--) + tty_unregister_device(gsm_tty_driver, + base + i); + return PTR_ERR(dev); + } + } } return ret; } @@ -2416,27 +2427,24 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct gsm_mux *gsm = tty->disc_data; - const unsigned char *dp; - char *f; - int i; char flags = TTY_NORMAL; if (debug & 4) print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET, cp, count); - for (i = count, dp = cp, f = fp; i; i--, dp++) { - if (f) - flags = *f++; + for (; count; count--, cp++) { + if (fp) + flags = *fp++; switch (flags) { case TTY_NORMAL: - gsm->receive(gsm, *dp); + gsm->receive(gsm, *cp); break; case TTY_OVERRUN: case TTY_BREAK: case TTY_PARITY: case TTY_FRAME: - gsm_error(gsm, *dp, flags); + gsm_error(gsm, *cp, flags); break; default: WARN_ONCE(1, "%s: unknown flag %d\n", @@ -2849,7 +2857,6 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) /* Line discipline for real tty */ static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_gsm", .open = gsmld_open, .close = gsmld_close, @@ -3052,7 +3059,7 @@ static int gsmtty_write_room(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) - return -EINVAL; + return 0; return TX_SIZE - kfifo_len(&dlci->fifo); } @@ -3060,7 +3067,7 @@ static int gsmtty_chars_in_buffer(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) - return -EINVAL; + return 0; return kfifo_len(&dlci->fifo); } @@ -3261,8 +3268,6 @@ static int __init gsm_init(void) gsm_tty_driver->init_termios.c_lflag &= ~ECHO; tty_set_operations(gsm_tty_driver, &gsmtty_ops); - spin_lock_init(&gsm_mux_lock); - if (tty_register_driver(gsm_tty_driver)) { put_tty_driver(gsm_tty_driver); tty_unregister_ldisc(N_GSM0710); diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 1363e659dc1dbce8f08983e0f1c439555640006b..b0f33e8ac819ac1ad33af23cd753fad53dbc48fb 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -100,6 +100,7 @@ #include <asm/termios.h> #include <linux/uaccess.h> +#include "tty.h" /* * Buffers for individual HDLC frames @@ -787,7 +788,6 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) static struct tty_ldisc_ops n_hdlc_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "hdlc", .open = n_hdlc_tty_open, .close = n_hdlc_tty_close, diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c index ce03ae78f5c6ac40a6fe2e1278b049fbc1d7edbe..b8f67b5f1ef88023c511d61aefd4f81b31923683 100644 --- a/drivers/tty/n_null.c +++ b/drivers/tty/n_null.c @@ -40,7 +40,6 @@ static void n_null_receivebuf(struct tty_struct *tty, static struct tty_ldisc_ops null_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_null", .open = n_null_open, .close = n_null_close, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 3161f0a535e3714d1aad14cb8ffc39b606f05fd9..2eb76ea1d88dd7fb00250b6f2ae11fa784baa4d8 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -146,7 +146,6 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "R3964", .open = r3964_open, .close = r3964_close, diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 87ec15dbe10db355dbe1b760fe65eeddb4ce99fc..9686c5d1057155cc605671c8660545e0321487fc 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -49,6 +49,7 @@ #include <linux/module.h> #include <linux/ratelimit.h> #include <linux/vmalloc.h> +#include "tty.h" /* * Until this number of characters is queued in the xmit buffer, select will @@ -2488,7 +2489,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, } static struct tty_ldisc_ops n_tty_ops = { - .magic = TTY_LDISC_MAGIC, + .owner = THIS_MODULE, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 861e9504319193b4f1dc25d02203e530ccd27ca7..9a2d78ace49be6d2ef65b40ff4128b7a709a96a4 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -47,9 +47,6 @@ #include <linux/delay.h> - -#define VERSION_STRING DRIVER_DESC " 2.1d" - /* Default debug printout level */ #define NOZOMI_DEBUG_LEVEL 0x00 static int debug = NOZOMI_DEBUG_LEVEL; @@ -89,7 +86,6 @@ do { \ /* Defines */ #define NOZOMI_NAME "nozomi" #define NOZOMI_NAME_TTY "nozomi_tty" -#define DRIVER_DESC "Nozomi driver" #define NTTY_TTY_MAXMINORS 256 #define NTTY_FIFO_BUFFER_SIZE 8192 @@ -359,12 +355,6 @@ struct nozomi { u32 open_ttys; }; -/* This is a data packet that is read or written to/from card */ -struct buffer { - u32 size; /* size is the length of the data buffer */ - u8 *data; -} __attribute__ ((packed)); - /* Global variables */ static const struct pci_device_id nozomi_pci_tbl[] = { {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ @@ -787,7 +777,6 @@ static int receive_data(enum port_type index, struct nozomi *dc) int i, ret; size = __le32_to_cpu(readl(addr)); - /* DBG1( "%d bytes port: %d", size, index); */ if (tty && tty_throttled(tty)) { DBG1("No room in tty, don't read data, don't ack interrupt, " @@ -1318,8 +1307,6 @@ static int nozomi_card_init(struct pci_dev *pdev, int ndev_idx; int i; - dev_dbg(&pdev->dev, "Init, new card found\n"); - for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) if (!ndevs[ndev_idx]) break; @@ -1453,8 +1440,6 @@ static void tty_exit(struct nozomi *dc) { unsigned int i; - DBG1(" "); - for (i = 0; i < MAX_PORT; ++i) tty_port_tty_hangup(&dc->port[i].port, false); @@ -1619,8 +1604,6 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, struct port *port = tty->driver_data; unsigned long flags; - /* DBG1( "WRITEx: %d, index = %d", count, index); */ - if (!dc || !port) return -ENODEV; @@ -1746,8 +1729,6 @@ static int ntty_ioctl(struct tty_struct *tty, struct port *port = tty->driver_data; int rval = -ENOIOCTLCMD; - DBG1("******** IOCTL, cmd: %d", cmd); - switch (cmd) { case TIOCMIWAIT: { struct async_icount cprev = port->tty_icount; @@ -1773,7 +1754,6 @@ static void ntty_unthrottle(struct tty_struct *tty) struct nozomi *dc = get_dc_by_tty(tty); unsigned long flags; - DBG1("UNTHROTTLE"); spin_lock_irqsave(&dc->spin_mutex, flags); enable_transmit_dl(tty->index % MAX_PORT, dc); set_rts(tty, 1); @@ -1790,7 +1770,6 @@ static void ntty_throttle(struct tty_struct *tty) struct nozomi *dc = get_dc_by_tty(tty); unsigned long flags; - DBG1("THROTTLE"); spin_lock_irqsave(&dc->spin_mutex, flags); set_rts(tty, 0); spin_unlock_irqrestore(&dc->spin_mutex, flags); @@ -1847,8 +1826,6 @@ static __init int nozomi_init(void) { int ret; - printk(KERN_INFO "Initializing %s\n", VERSION_STRING); - ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); if (!ntty_driver) return -ENOMEM; @@ -1888,7 +1865,6 @@ free_tty: static __exit void nozomi_exit(void) { - printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); pci_unregister_driver(&nozomi_driver); tty_unregister_driver(ntty_driver); put_tty_driver(ntty_driver); @@ -1898,4 +1874,4 @@ module_init(nozomi_init); module_exit(nozomi_exit); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION("Nozomi driver"); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 5e2374580e271395151039b96fd3fbf1d177e884..9b5d4ae5d8f2bc1270447a7d060d9f07151eb8db 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -29,6 +29,7 @@ #include <linux/file.h> #include <linux/ioctl.h> #include <linux/compat.h> +#include "tty.h" #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP @@ -159,6 +160,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty) static int pty_set_lock(struct tty_struct *tty, int __user *arg) { int val; + if (get_user(val, arg)) return -EFAULT; if (val) @@ -171,6 +173,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg) static int pty_get_lock(struct tty_struct *tty, int __user *arg) { int locked = test_bit(TTY_PTY_LOCK, &tty->flags); + return put_user(locked, arg); } @@ -200,6 +203,7 @@ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg) static int pty_get_pktmode(struct tty_struct *tty, int __user *arg) { int pktmode = tty->packet; + return put_user(pktmode, arg); } @@ -463,6 +467,7 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty) static void pty_remove(struct tty_driver *driver, struct tty_struct *tty) { struct tty_struct *pair = tty->link; + driver->ttys[tty->index] = NULL; if (pair) pair->driver->ttys[pair->index] = NULL; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c deleted file mode 100644 index 2540b2e4c8e819551b4512f456e0d8f6ba4a34a9..0000000000000000000000000000000000000000 --- a/drivers/tty/rocket.c +++ /dev/null @@ -1,3127 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -/* - * RocketPort device driver for Linux - * - * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000. - * - * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc. - */ - -/* - * Kernel Synchronization: - * - * This driver has 2 kernel control paths - exception handlers (calls into the driver - * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts - * are not used. - * - * Critical data: - * - rp_table[], accessed through passed "info" pointers, is a global (static) array of - * serial port state information and the xmit_buf circular buffer. Protected by - * a per port spinlock. - * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there - * is data to be transmitted. Protected by atomic bit operations. - * - rp_num_ports, int indicating number of open ports, protected by atomic operations. - * - * rp_write() and rp_write_char() functions use a per port semaphore to protect against - * simultaneous access to the same port by more than one process. - */ - -/****** Defines ******/ -#define ROCKET_PARANOIA_CHECK -#define ROCKET_DISABLE_SIMUSAGE - -#undef ROCKET_SOFT_FLOW -#undef ROCKET_DEBUG_OPEN -#undef ROCKET_DEBUG_INTR -#undef ROCKET_DEBUG_WRITE -#undef ROCKET_DEBUG_FLOW -#undef ROCKET_DEBUG_THROTTLE -#undef ROCKET_DEBUG_WAIT_UNTIL_SENT -#undef ROCKET_DEBUG_RECEIVE -#undef ROCKET_DEBUG_HANGUP -#undef REV_PCI_ORDER -#undef ROCKET_DEBUG_IO - -#define POLL_PERIOD (HZ/100) /* Polling period .01 seconds (10ms) */ - -/****** Kernel includes ******/ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/major.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/mutex.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/completion.h> -#include <linux/wait.h> -#include <linux/pci.h> -#include <linux/uaccess.h> -#include <linux/atomic.h> -#include <asm/unaligned.h> -#include <linux/bitops.h> -#include <linux/spinlock.h> -#include <linux/init.h> - -/****** RocketPort includes ******/ - -#include "rocket_int.h" -#include "rocket.h" - -#define ROCKET_VERSION "2.09" -#define ROCKET_DATE "12-June-2003" - -/****** RocketPort Local Variables ******/ - -static void rp_do_poll(struct timer_list *unused); - -static struct tty_driver *rocket_driver; - -static struct rocket_version driver_version = { - ROCKET_VERSION, ROCKET_DATE -}; - -static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */ -static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ - /* eg. Bit 0 indicates port 0 has xmit data, ... */ -static atomic_t rp_num_ports_open; /* Number of serial ports open */ -static DEFINE_TIMER(rocket_timer, rp_do_poll); - -static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ -static unsigned long board2; -static unsigned long board3; -static unsigned long board4; -static unsigned long controller; -static bool support_low_speed; -static unsigned long modem1; -static unsigned long modem2; -static unsigned long modem3; -static unsigned long modem4; -static unsigned long pc104_1[8]; -static unsigned long pc104_2[8]; -static unsigned long pc104_3[8]; -static unsigned long pc104_4[8]; -static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 }; - -static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */ -static unsigned long rcktpt_io_addr[NUM_BOARDS]; -static int rcktpt_type[NUM_BOARDS]; -static int is_PCI[NUM_BOARDS]; -static rocketModel_t rocketModel[NUM_BOARDS]; -static int max_board; -static const struct tty_port_operations rocket_port_ops; - -/* - * The following arrays define the interrupt bits corresponding to each AIOP. - * These bits are different between the ISA and regular PCI boards and the - * Universal PCI boards. - */ - -static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { - AIOP_INTR_BIT_0, - AIOP_INTR_BIT_1, - AIOP_INTR_BIT_2, - AIOP_INTR_BIT_3 -}; - -#ifdef CONFIG_PCI -static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { - UPCI_AIOP_INTR_BIT_0, - UPCI_AIOP_INTR_BIT_1, - UPCI_AIOP_INTR_BIT_2, - UPCI_AIOP_INTR_BIT_3 -}; -#endif - -static Byte_t RData[RDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ -}; - -static CONTROLLER_T sController[CTL_SIZE] = { - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} -}; - -static Byte_t sBitMapClrTbl[8] = { - 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f -}; - -static Byte_t sBitMapSetTbl[8] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 -}; - -static int sClockPrescale = 0x14; - -/* - * Line number is the ttySIx number (x), the Minor number. We - * assign them sequentially, starting at zero. The following - * array keeps track of the line number assigned to a given board/aiop/channel. - */ -static unsigned char lineNumbers[MAX_RP_PORTS]; -static unsigned long nextLineNumber; - -/***** RocketPort Static Prototypes *********/ -static int __init init_ISA(int i); -static void rp_wait_until_sent(struct tty_struct *tty, int timeout); -static void rp_flush_buffer(struct tty_struct *tty); -static unsigned char GetLineNumber(int ctrl, int aiop, int ch); -static unsigned char SetLineNumber(int ctrl, int aiop, int ch); -static void rp_start(struct tty_struct *tty); -static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, - int ChanNum); -static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); -static void sFlushRxFIFO(CHANNEL_T * ChP); -static void sFlushTxFIFO(CHANNEL_T * ChP); -static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); -static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); -static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); -static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); -static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); -static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, int AiopIOListSize, - int IRQNum, Byte_t Frequency, int PeriodicOnly); -static int sReadAiopID(ByteIO_t io); -static int sReadAiopNumChan(WordIO_t io); - -MODULE_AUTHOR("Theodore Ts'o"); -MODULE_DESCRIPTION("Comtrol RocketPort driver"); -module_param_hw(board1, ulong, ioport, 0); -MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); -module_param_hw(board2, ulong, ioport, 0); -MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); -module_param_hw(board3, ulong, ioport, 0); -MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); -module_param_hw(board4, ulong, ioport, 0); -MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); -module_param_hw(controller, ulong, ioport, 0); -MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); -module_param(support_low_speed, bool, 0); -MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud"); -module_param(modem1, ulong, 0); -MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem"); -module_param(modem2, ulong, 0); -MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem"); -module_param(modem3, ulong, 0); -MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem"); -module_param(modem4, ulong, 0); -MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem"); -module_param_array(pc104_1, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,..."); -module_param_array(pc104_2, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,..."); -module_param_array(pc104_3, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,..."); -module_param_array(pc104_4, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); - -static int __init rp_init(void); -static void rp_cleanup_module(void); - -module_init(rp_init); -module_exit(rp_cleanup_module); - - -MODULE_LICENSE("Dual BSD/GPL"); - -/*************************************************************************/ -/* Module code starts here */ - -static inline int rocket_paranoia_check(struct r_port *info, - const char *routine) -{ -#ifdef ROCKET_PARANOIA_CHECK - if (!info) - return 1; - if (info->magic != RPORT_MAGIC) { - printk(KERN_WARNING "Warning: bad magic number for rocketport " - "struct in %s\n", routine); - return 1; - } -#endif - return 0; -} - - -/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals - * that receive data is present on a serial port. Pulls data from FIFO, moves it into the - * tty layer. - */ -static void rp_do_receive(struct r_port *info, CHANNEL_t *cp, - unsigned int ChanStatus) -{ - unsigned int CharNStat; - int ToRecv, wRecv, space; - unsigned char *cbuf; - - ToRecv = sGetRxCnt(cp); -#ifdef ROCKET_DEBUG_INTR - printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv); -#endif - if (ToRecv == 0) - return; - - /* - * if status indicates there are errored characters in the - * FIFO, then enter status mode (a word in FIFO holds - * character and status). - */ - if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { - if (!(ChanStatus & STATMODE)) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "Entering STATMODE...\n"); -#endif - ChanStatus |= STATMODE; - sEnRxStatusMode(cp); - } - } - - /* - * if we previously entered status mode, then read down the - * FIFO one word at a time, pulling apart the character and - * the status. Update error counters depending on status - */ - if (ChanStatus & STATMODE) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "Ignore %x, read %x...\n", - info->ignore_status_mask, info->read_status_mask); -#endif - while (ToRecv) { - char flag; - - CharNStat = sInW(sGetTxRxDataIO(cp)); -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "%x...\n", CharNStat); -#endif - if (CharNStat & STMBREAKH) - CharNStat &= ~(STMFRAMEH | STMPARITYH); - if (CharNStat & info->ignore_status_mask) { - ToRecv--; - continue; - } - CharNStat &= info->read_status_mask; - if (CharNStat & STMBREAKH) - flag = TTY_BREAK; - else if (CharNStat & STMPARITYH) - flag = TTY_PARITY; - else if (CharNStat & STMFRAMEH) - flag = TTY_FRAME; - else if (CharNStat & STMRCVROVRH) - flag = TTY_OVERRUN; - else - flag = TTY_NORMAL; - tty_insert_flip_char(&info->port, CharNStat & 0xff, - flag); - ToRecv--; - } - - /* - * after we've emptied the FIFO in status mode, turn - * status mode back off - */ - if (sGetRxCnt(cp) == 0) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "Status mode off.\n"); -#endif - sDisRxStatusMode(cp); - } - } else { - /* - * we aren't in status mode, so read down the FIFO two - * characters at time by doing repeated word IO - * transfer. - */ - space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv); - if (space < ToRecv) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space); -#endif - if (space <= 0) - return; - ToRecv = space; - } - wRecv = ToRecv >> 1; - if (wRecv) - sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); - if (ToRecv & 1) - cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); - } - /* Push the data up to the tty layer */ - tty_flip_buffer_push(&info->port); -} - -/* - * Serial port transmit data function. Called from the timer polling loop as a - * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready - * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is - * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks. - */ -static void rp_do_transmit(struct r_port *info) -{ - int c; - CHANNEL_t *cp = &info->channel; - struct tty_struct *tty; - unsigned long flags; - -#ifdef ROCKET_DEBUG_INTR - printk(KERN_DEBUG "%s\n", __func__); -#endif - if (!info) - return; - tty = tty_port_tty_get(&info->port); - - if (tty == NULL) { - printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__); - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - return; - } - - spin_lock_irqsave(&info->slock, flags); - info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - - /* Loop sending data to FIFO until done or FIFO full */ - while (1) { - if (tty->stopped) - break; - c = min(info->xmit_fifo_room, info->xmit_cnt); - c = min(c, XMIT_BUF_SIZE - info->xmit_tail); - if (c <= 0 || info->xmit_fifo_room <= 0) - break; - sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); - if (c & 1) - sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]); - info->xmit_tail += c; - info->xmit_tail &= XMIT_BUF_SIZE - 1; - info->xmit_cnt -= c; - info->xmit_fifo_room -= c; -#ifdef ROCKET_DEBUG_INTR - printk(KERN_INFO "tx %d chars...\n", c); -#endif - } - - if (info->xmit_cnt == 0) - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - - if (info->xmit_cnt < WAKEUP_CHARS) { - tty_wakeup(tty); -#ifdef ROCKETPORT_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - } - - spin_unlock_irqrestore(&info->slock, flags); - tty_kref_put(tty); - -#ifdef ROCKET_DEBUG_INTR - printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head, - info->xmit_tail, info->xmit_fifo_room); -#endif -} - -/* - * Called when a serial port signals it has read data in it's RX FIFO. - * It checks what interrupts are pending and services them, including - * receiving serial data. - */ -static void rp_handle_port(struct r_port *info) -{ - CHANNEL_t *cp; - unsigned int IntMask, ChanStatus; - - if (!info) - return; - - if (!tty_port_initialized(&info->port)) { - printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " - "info->flags & NOT_INIT\n"); - return; - } - - cp = &info->channel; - - IntMask = sGetChanIntID(cp) & info->intmask; -#ifdef ROCKET_DEBUG_INTR - printk(KERN_INFO "rp_interrupt %02x...\n", IntMask); -#endif - ChanStatus = sGetChanStatus(cp); - if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ - rp_do_receive(info, cp, ChanStatus); - } - if (IntMask & DELTA_CD) { /* CD change */ -#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) - printk(KERN_INFO "ttyR%d CD now %s...\n", info->line, - (ChanStatus & CD_ACT) ? "on" : "off"); -#endif - if (!(ChanStatus & CD_ACT) && info->cd_status) { -#ifdef ROCKET_DEBUG_HANGUP - printk(KERN_INFO "CD drop, calling hangup.\n"); -#endif - tty_port_tty_hangup(&info->port, false); - } - info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; - wake_up_interruptible(&info->port.open_wait); - } -#ifdef ROCKET_DEBUG_INTR - if (IntMask & DELTA_CTS) { /* CTS change */ - printk(KERN_INFO "CTS change...\n"); - } - if (IntMask & DELTA_DSR) { /* DSR change */ - printk(KERN_INFO "DSR change...\n"); - } -#endif -} - -/* - * The top level polling routine. Repeats every 1/100 HZ (10ms). - */ -static void rp_do_poll(struct timer_list *unused) -{ - CONTROLLER_t *ctlp; - int ctrl, aiop, ch, line; - unsigned int xmitmask, i; - unsigned int CtlMask; - unsigned char AiopMask; - Word_t bit; - - /* Walk through all the boards (ctrl's) */ - for (ctrl = 0; ctrl < max_board; ctrl++) { - if (rcktpt_io_addr[ctrl] <= 0) - continue; - - /* Get a ptr to the board's control struct */ - ctlp = sCtlNumToCtlPtr(ctrl); - - /* Get the interrupt status from the board */ -#ifdef CONFIG_PCI - if (ctlp->BusType == isPCI) - CtlMask = sPCIGetControllerIntStatus(ctlp); - else -#endif - CtlMask = sGetControllerIntStatus(ctlp); - - /* Check if any AIOP read bits are set */ - for (aiop = 0; CtlMask; aiop++) { - bit = ctlp->AiopIntrBits[aiop]; - if (CtlMask & bit) { - CtlMask &= ~bit; - AiopMask = sGetAiopIntStatus(ctlp, aiop); - - /* Check if any port read bits are set */ - for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { - if (AiopMask & 1) { - - /* Get the line number (/dev/ttyRx number). */ - /* Read the data from the port. */ - line = GetLineNumber(ctrl, aiop, ch); - rp_handle_port(rp_table[line]); - } - } - } - } - - xmitmask = xmit_flags[ctrl]; - - /* - * xmit_flags contains bit-significant flags, indicating there is data - * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port - * 1, ... (32 total possible). The variable i has the aiop and ch - * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). - */ - if (xmitmask) { - for (i = 0; i < rocketModel[ctrl].numPorts; i++) { - if (xmitmask & (1 << i)) { - aiop = (i & 0x18) >> 3; - ch = i & 0x07; - line = GetLineNumber(ctrl, aiop, ch); - rp_do_transmit(rp_table[line]); - } - } - } - } - - /* - * Reset the timer so we get called at the next clock tick (10ms). - */ - if (atomic_read(&rp_num_ports_open)) - mod_timer(&rocket_timer, jiffies + POLL_PERIOD); -} - -/* - * Initializes the r_port structure for a port, as well as enabling the port on - * the board. - * Inputs: board, aiop, chan numbers - */ -static void __init -init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) -{ - unsigned rocketMode; - struct r_port *info; - int line; - CONTROLLER_T *ctlp; - - /* Get the next available line number */ - line = SetLineNumber(board, aiop, chan); - - ctlp = sCtlNumToCtlPtr(board); - - /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ - info = kzalloc(sizeof (struct r_port), GFP_KERNEL); - if (!info) { - printk(KERN_ERR "Couldn't allocate info struct for line #%d\n", - line); - return; - } - - info->magic = RPORT_MAGIC; - info->line = line; - info->ctlp = ctlp; - info->board = board; - info->aiop = aiop; - info->chan = chan; - tty_port_init(&info->port); - info->port.ops = &rocket_port_ops; - info->flags &= ~ROCKET_MODE_MASK; - if (board < ARRAY_SIZE(pc104) && line < ARRAY_SIZE(pc104_1)) - switch (pc104[board][line]) { - case 422: - info->flags |= ROCKET_MODE_RS422; - break; - case 485: - info->flags |= ROCKET_MODE_RS485; - break; - case 232: - default: - info->flags |= ROCKET_MODE_RS232; - break; - } - else - info->flags |= ROCKET_MODE_RS232; - - info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; - if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { - printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n", - board, aiop, chan); - tty_port_destroy(&info->port); - kfree(info); - return; - } - - rocketMode = info->flags & ROCKET_MODE_MASK; - - if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) - sEnRTSToggle(&info->channel); - else - sDisRTSToggle(&info->channel); - - if (ctlp->boardType == ROCKET_TYPE_PC104) { - switch (rocketMode) { - case ROCKET_MODE_RS485: - sSetInterfaceMode(&info->channel, InterfaceModeRS485); - break; - case ROCKET_MODE_RS422: - sSetInterfaceMode(&info->channel, InterfaceModeRS422); - break; - case ROCKET_MODE_RS232: - default: - if (info->flags & ROCKET_RTS_TOGGLE) - sSetInterfaceMode(&info->channel, InterfaceModeRS232T); - else - sSetInterfaceMode(&info->channel, InterfaceModeRS232); - break; - } - } - spin_lock_init(&info->slock); - mutex_init(&info->write_mtx); - rp_table[line] = info; - tty_port_register_device(&info->port, rocket_driver, line, - pci_dev ? &pci_dev->dev : NULL); -} - -/* - * Configures a rocketport port according to its termio settings. Called from - * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. - */ -static void configure_r_port(struct tty_struct *tty, struct r_port *info, - struct ktermios *old_termios) -{ - unsigned cflag; - unsigned long flags; - unsigned rocketMode; - int bits, baud, divisor; - CHANNEL_t *cp; - struct ktermios *t = &tty->termios; - - cp = &info->channel; - cflag = t->c_cflag; - - /* Byte size and parity */ - if ((cflag & CSIZE) == CS8) { - sSetData8(cp); - bits = 10; - } else { - sSetData7(cp); - bits = 9; - } - if (cflag & CSTOPB) { - sSetStop2(cp); - bits++; - } else { - sSetStop1(cp); - } - - if (cflag & PARENB) { - sEnParity(cp); - bits++; - if (cflag & PARODD) { - sSetOddParity(cp); - } else { - sSetEvenParity(cp); - } - } else { - sDisParity(cp); - } - - /* baud rate */ - baud = tty_get_baud_rate(tty); - if (!baud) - baud = 9600; - divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; - if ((divisor >= 8192 || divisor < 0) && old_termios) { - baud = tty_termios_baud_rate(old_termios); - if (!baud) - baud = 9600; - divisor = (rp_baud_base[info->board] / baud) - 1; - } - if (divisor >= 8192 || divisor < 0) { - baud = 9600; - divisor = (rp_baud_base[info->board] / baud) - 1; - } - info->cps = baud / bits; - sSetBaud(cp, divisor); - - /* FIXME: Should really back compute a baud rate from the divisor */ - tty_encode_baud_rate(tty, baud, baud); - - if (cflag & CRTSCTS) { - info->intmask |= DELTA_CTS; - sEnCTSFlowCtl(cp); - } else { - info->intmask &= ~DELTA_CTS; - sDisCTSFlowCtl(cp); - } - if (cflag & CLOCAL) { - info->intmask &= ~DELTA_CD; - } else { - spin_lock_irqsave(&info->slock, flags); - if (sGetChanStatus(cp) & CD_ACT) - info->cd_status = 1; - else - info->cd_status = 0; - info->intmask |= DELTA_CD; - spin_unlock_irqrestore(&info->slock, flags); - } - - /* - * Handle software flow control in the board - */ -#ifdef ROCKET_SOFT_FLOW - if (I_IXON(tty)) { - sEnTxSoftFlowCtl(cp); - if (I_IXANY(tty)) { - sEnIXANY(cp); - } else { - sDisIXANY(cp); - } - sSetTxXONChar(cp, START_CHAR(tty)); - sSetTxXOFFChar(cp, STOP_CHAR(tty)); - } else { - sDisTxSoftFlowCtl(cp); - sDisIXANY(cp); - sClrTxXOFF(cp); - } -#endif - - /* - * Set up ignore/read mask words - */ - info->read_status_mask = STMRCVROVRH | 0xFF; - if (I_INPCK(tty)) - info->read_status_mask |= STMFRAMEH | STMPARITYH; - if (I_BRKINT(tty) || I_PARMRK(tty)) - info->read_status_mask |= STMBREAKH; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(tty)) - info->ignore_status_mask |= STMFRAMEH | STMPARITYH; - if (I_IGNBRK(tty)) { - info->ignore_status_mask |= STMBREAKH; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too. (For real raw support). - */ - if (I_IGNPAR(tty)) - info->ignore_status_mask |= STMRCVROVRH; - } - - rocketMode = info->flags & ROCKET_MODE_MASK; - - if ((info->flags & ROCKET_RTS_TOGGLE) - || (rocketMode == ROCKET_MODE_RS485)) - sEnRTSToggle(cp); - else - sDisRTSToggle(cp); - - sSetRTS(&info->channel); - - if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { - switch (rocketMode) { - case ROCKET_MODE_RS485: - sSetInterfaceMode(cp, InterfaceModeRS485); - break; - case ROCKET_MODE_RS422: - sSetInterfaceMode(cp, InterfaceModeRS422); - break; - case ROCKET_MODE_RS232: - default: - if (info->flags & ROCKET_RTS_TOGGLE) - sSetInterfaceMode(cp, InterfaceModeRS232T); - else - sSetInterfaceMode(cp, InterfaceModeRS232); - break; - } - } -} - -static int carrier_raised(struct tty_port *port) -{ - struct r_port *info = container_of(port, struct r_port, port); - return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; -} - -static void dtr_rts(struct tty_port *port, int on) -{ - struct r_port *info = container_of(port, struct r_port, port); - if (on) { - sSetDTR(&info->channel); - sSetRTS(&info->channel); - } else { - sClrDTR(&info->channel); - sClrRTS(&info->channel); - } -} - -/* - * Exception handler that opens a serial port. Creates xmit_buf storage, fills in - * port's r_port struct. Initializes the port hardware. - */ -static int rp_open(struct tty_struct *tty, struct file *filp) -{ - struct r_port *info; - struct tty_port *port; - int retval; - CHANNEL_t *cp; - unsigned long page; - - info = rp_table[tty->index]; - if (info == NULL) - return -ENXIO; - port = &info->port; - - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - /* - * We must not sleep from here until the port is marked fully in use. - */ - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *) page; - - tty->driver_data = info; - tty_port_tty_set(port, tty); - - if (port->count++ == 0) { - atomic_inc(&rp_num_ports_open); - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rocket mod++ = %d...\n", - atomic_read(&rp_num_ports_open)); -#endif - } -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count); -#endif - - /* - * Info->count is now 1; so it's safe to sleep now. - */ - if (!tty_port_initialized(port)) { - cp = &info->channel; - sSetRxTrigger(cp, TRIG_1); - if (sGetChanStatus(cp) & CD_ACT) - info->cd_status = 1; - else - info->cd_status = 0; - sDisRxStatusMode(cp); - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - - sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); - sSetRxTrigger(cp, TRIG_1); - - sGetChanStatus(cp); - sDisRxStatusMode(cp); - sClrTxXOFF(cp); - - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - - sEnRxFIFO(cp); - sEnTransmit(cp); - - tty_port_set_initialized(&info->port, 1); - - configure_r_port(tty, info, NULL); - if (C_BAUD(tty)) { - sSetDTR(cp); - sSetRTS(cp); - } - } - /* Starts (or resets) the maint polling loop */ - mod_timer(&rocket_timer, jiffies + POLL_PERIOD); - - retval = tty_port_block_til_ready(port, tty, filp); - if (retval) { -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); -#endif - return retval; - } - return 0; -} - -/* - * Exception handler that closes a serial port. info->port.count is considered critical. - */ -static void rp_close(struct tty_struct *tty, struct file *filp) -{ - struct r_port *info = tty->driver_data; - struct tty_port *port = &info->port; - int timeout; - CHANNEL_t *cp; - - if (rocket_paranoia_check(info, "rp_close")) - return; - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count); -#endif - - if (tty_port_close_start(port, tty, filp) == 0) - return; - - mutex_lock(&port->mutex); - cp = &info->channel; - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps; - if (timeout == 0) - timeout = 1; - rp_wait_until_sent(tty, timeout); - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - - sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - sClrTxXOFF(cp); - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - sClrRTS(cp); - if (C_HUPCL(tty)) - sClrDTR(cp); - - rp_flush_buffer(tty); - - tty_ldisc_flush(tty); - - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - - /* We can't yet use tty_port_close_end as the buffer handling in this - driver is a bit different to the usual */ - - if (port->blocked_open) { - if (port->close_delay) { - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - } - wake_up_interruptible(&port->open_wait); - } else { - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = NULL; - } - } - spin_lock_irq(&port->lock); - tty->closing = 0; - spin_unlock_irq(&port->lock); - tty_port_set_initialized(port, 0); - tty_port_set_active(port, 0); - mutex_unlock(&port->mutex); - tty_port_tty_set(port, NULL); - - atomic_dec(&rp_num_ports_open); - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rocket mod-- = %d...\n", - atomic_read(&rp_num_ports_open)); - printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line); -#endif - -} - -static void rp_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned cflag; - - if (rocket_paranoia_check(info, "rp_set_termios")) - return; - - cflag = tty->termios.c_cflag; - - /* - * This driver doesn't support CS5 or CS6 - */ - if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) - tty->termios.c_cflag = - ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); - /* Or CMSPAR */ - tty->termios.c_cflag &= ~CMSPAR; - - configure_r_port(tty, info, old_termios); - - cp = &info->channel; - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { - sClrDTR(cp); - sClrRTS(cp); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { - sSetRTS(cp); - sSetDTR(cp); - } - - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) - rp_start(tty); -} - -static int rp_break(struct tty_struct *tty, int break_state) -{ - struct r_port *info = tty->driver_data; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_break")) - return -EINVAL; - - spin_lock_irqsave(&info->slock, flags); - if (break_state == -1) - sSendBreak(&info->channel); - else - sClrBreak(&info->channel); - spin_unlock_irqrestore(&info->slock, flags); - return 0; -} - -/* - * sGetChanRI used to be a macro in rocket_int.h. When the functionality for - * the UPCI boards was added, it was decided to make this a function because - * the macro was getting too complicated. All cases except the first one - * (UPCIRingInd) are taken directly from the original macro. - */ -static int sGetChanRI(CHANNEL_T * ChP) -{ - CONTROLLER_t *CtlP = ChP->CtlP; - int ChanNum = ChP->ChanNum; - int RingInd = 0; - - if (CtlP->UPCIRingInd) - RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); - else if (CtlP->AltChanRingIndicator) - RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; - else if (CtlP->boardType == ROCKET_TYPE_PC104) - RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); - - return RingInd; -} - -/********************************************************************************************/ -/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */ - -/* - * Returns the state of the serial modem control lines. These next 2 functions - * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. - */ -static int rp_tiocmget(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - unsigned int control, result, ChanStatus; - - ChanStatus = sGetChanStatusLo(&info->channel); - control = info->channel.TxControl[3]; - result = ((control & SET_RTS) ? TIOCM_RTS : 0) | - ((control & SET_DTR) ? TIOCM_DTR : 0) | - ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | - (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | - ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | - ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); - - return result; -} - -/* - * Sets the modem control lines - */ -static int rp_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct r_port *info = tty->driver_data; - - if (set & TIOCM_RTS) - info->channel.TxControl[3] |= SET_RTS; - if (set & TIOCM_DTR) - info->channel.TxControl[3] |= SET_DTR; - if (clear & TIOCM_RTS) - info->channel.TxControl[3] &= ~SET_RTS; - if (clear & TIOCM_DTR) - info->channel.TxControl[3] &= ~SET_DTR; - - out32(info->channel.IndexAddr, info->channel.TxControl); - return 0; -} - -static int get_config(struct r_port *info, struct rocket_config __user *retinfo) -{ - struct rocket_config tmp; - - memset(&tmp, 0, sizeof (tmp)); - mutex_lock(&info->port.mutex); - tmp.line = info->line; - tmp.flags = info->flags; - tmp.close_delay = info->port.close_delay; - tmp.closing_wait = info->port.closing_wait; - tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; - mutex_unlock(&info->port.mutex); - - if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) - return -EFAULT; - return 0; -} - -static int set_config(struct tty_struct *tty, struct r_port *info, - struct rocket_config __user *new_info) -{ - struct rocket_config new_serial; - - if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) - return -EFAULT; - - mutex_lock(&info->port.mutex); - if (!capable(CAP_SYS_ADMIN)) - { - if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) { - mutex_unlock(&info->port.mutex); - return -EPERM; - } - info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); - mutex_unlock(&info->port.mutex); - return 0; - } - - if ((new_serial.flags ^ info->flags) & ROCKET_SPD_MASK) { - /* warn about deprecation, unless clearing */ - if (new_serial.flags & ROCKET_SPD_MASK) - dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); - } - - info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); - info->port.close_delay = new_serial.close_delay; - info->port.closing_wait = new_serial.closing_wait; - - mutex_unlock(&info->port.mutex); - - configure_r_port(tty, info, NULL); - return 0; -} - -/* - * This function fills in a rocket_ports struct with information - * about what boards/ports are in the system. This info is passed - * to user space. See setrocket.c where the info is used to create - * the /dev/ttyRx ports. - */ -static int get_ports(struct r_port *info, struct rocket_ports __user *retports) -{ - struct rocket_ports *tmp; - int board, ret = 0; - - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - tmp->tty_major = rocket_driver->major; - - for (board = 0; board < 4; board++) { - tmp->rocketModel[board].model = rocketModel[board].model; - strcpy(tmp->rocketModel[board].modelString, - rocketModel[board].modelString); - tmp->rocketModel[board].numPorts = rocketModel[board].numPorts; - tmp->rocketModel[board].loadrm2 = rocketModel[board].loadrm2; - tmp->rocketModel[board].startingPortNumber = - rocketModel[board].startingPortNumber; - } - if (copy_to_user(retports, tmp, sizeof(*retports))) - ret = -EFAULT; - kfree(tmp); - return ret; -} - -static int reset_rm2(struct r_port *info, void __user *arg) -{ - int reset; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&reset, arg, sizeof (int))) - return -EFAULT; - if (reset) - reset = 1; - - if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && - rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) - return -EINVAL; - - if (info->ctlp->BusType == isISA) - sModemReset(info->ctlp, info->chan, reset); - else - sPCIModemReset(info->ctlp, info->chan, reset); - - return 0; -} - -static int get_version(struct r_port *info, struct rocket_version __user *retvers) -{ - if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) - return -EFAULT; - return 0; -} - -/* IOCTL call handler into the driver */ -static int rp_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct r_port *info = tty->driver_data; - void __user *argp = (void __user *)arg; - int ret = 0; - - if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) - return -ENXIO; - - switch (cmd) { - case RCKP_GET_CONFIG: - dev_warn_ratelimited(tty->dev, - "RCKP_GET_CONFIG option is deprecated\n"); - ret = get_config(info, argp); - break; - case RCKP_SET_CONFIG: - dev_warn_ratelimited(tty->dev, - "RCKP_SET_CONFIG option is deprecated\n"); - ret = set_config(tty, info, argp); - break; - case RCKP_GET_PORTS: - dev_warn_ratelimited(tty->dev, - "RCKP_GET_PORTS option is deprecated\n"); - ret = get_ports(info, argp); - break; - case RCKP_RESET_RM2: - dev_warn_ratelimited(tty->dev, - "RCKP_RESET_RM2 option is deprecated\n"); - ret = reset_rm2(info, argp); - break; - case RCKP_GET_VERSION: - dev_warn_ratelimited(tty->dev, - "RCKP_GET_VERSION option is deprecated\n"); - ret = get_version(info, argp); - break; - default: - ret = -ENOIOCTLCMD; - } - return ret; -} - -static void rp_send_xchar(struct tty_struct *tty, char ch) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - - if (rocket_paranoia_check(info, "rp_send_xchar")) - return; - - cp = &info->channel; - if (sGetTxCnt(cp)) - sWriteTxPrioByte(cp, ch); - else - sWriteTxByte(sGetTxRxDataIO(cp), ch); -} - -static void rp_throttle(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - -#ifdef ROCKET_DEBUG_THROTTLE - printk(KERN_INFO "throttle %s ....\n", tty->name); -#endif - - if (rocket_paranoia_check(info, "rp_throttle")) - return; - - if (I_IXOFF(tty)) - rp_send_xchar(tty, STOP_CHAR(tty)); - - sClrRTS(&info->channel); -} - -static void rp_unthrottle(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; -#ifdef ROCKET_DEBUG_THROTTLE - printk(KERN_INFO "unthrottle %s ....\n", tty->name); -#endif - - if (rocket_paranoia_check(info, "rp_unthrottle")) - return; - - if (I_IXOFF(tty)) - rp_send_xchar(tty, START_CHAR(tty)); - - sSetRTS(&info->channel); -} - -/* - * ------------------------------------------------------------ - * rp_stop() and rp_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rp_stop(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - -#ifdef ROCKET_DEBUG_FLOW - printk(KERN_INFO "stop %s: %d %d....\n", tty->name, - info->xmit_cnt, info->xmit_fifo_room); -#endif - - if (rocket_paranoia_check(info, "rp_stop")) - return; - - if (sGetTxCnt(&info->channel)) - sDisTransmit(&info->channel); -} - -static void rp_start(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - -#ifdef ROCKET_DEBUG_FLOW - printk(KERN_INFO "start %s: %d %d....\n", tty->name, - info->xmit_cnt, info->xmit_fifo_room); -#endif - - if (rocket_paranoia_check(info, "rp_stop")) - return; - - sEnTransmit(&info->channel); - set_bit((info->aiop * 8) + info->chan, - (void *) &xmit_flags[info->board]); -} - -/* - * rp_wait_until_sent() --- wait until the transmitter is empty - */ -static void rp_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned long orig_jiffies; - int check_time, exit_time; - int txcnt; - - if (rocket_paranoia_check(info, "rp_wait_until_sent")) - return; - - cp = &info->channel; - - orig_jiffies = jiffies; -#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout, - jiffies); - printk(KERN_INFO "cps=%d...\n", info->cps); -#endif - while (1) { - txcnt = sGetTxCnt(cp); - if (!txcnt) { - if (sGetChanStatusLo(cp) & TXSHRMT) - break; - check_time = (HZ / info->cps) / 5; - } else { - check_time = HZ * txcnt / info->cps; - } - if (timeout) { - exit_time = orig_jiffies + timeout - jiffies; - if (exit_time <= 0) - break; - if (exit_time < check_time) - check_time = exit_time; - } - if (check_time == 0) - check_time = 1; -#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt, - jiffies, check_time); -#endif - msleep_interruptible(jiffies_to_msecs(check_time)); - if (signal_pending(current)) - break; - } - __set_current_state(TASK_RUNNING); -#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); -#endif -} - -/* - * rp_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rp_hangup(struct tty_struct *tty) -{ - CHANNEL_t *cp; - struct r_port *info = tty->driver_data; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_hangup")) - return; - -#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) - printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line); -#endif - rp_flush_buffer(tty); - spin_lock_irqsave(&info->port.lock, flags); - if (info->port.count) - atomic_dec(&rp_num_ports_open); - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - spin_unlock_irqrestore(&info->port.lock, flags); - - tty_port_hangup(&info->port); - - cp = &info->channel; - sDisRxFIFO(cp); - sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - sClrTxXOFF(cp); - tty_port_set_initialized(&info->port, 0); - - wake_up_interruptible(&info->port.open_wait); -} - -/* - * Exception handler - write char routine. The RocketPort driver uses a - * double-buffering strategy, with the twist that if the in-memory CPU - * buffer is empty, and there's space in the transmit FIFO, the - * writing routines will write directly to transmit FIFO. - * Write buffer and counters protected by spinlocks - */ -static int rp_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_put_char")) - return 0; - - /* - * Grab the port write mutex, locking out other processes that try to - * write to this port - */ - mutex_lock(&info->write_mtx); - -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_put_char %c...\n", ch); -#endif - - spin_lock_irqsave(&info->slock, flags); - cp = &info->channel; - - if (!tty->stopped && info->xmit_fifo_room == 0) - info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - - if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= XMIT_BUF_SIZE - 1; - info->xmit_cnt++; - set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - } else { - sOutB(sGetTxRxDataIO(cp), ch); - info->xmit_fifo_room--; - } - spin_unlock_irqrestore(&info->slock, flags); - mutex_unlock(&info->write_mtx); - return 1; -} - -/* - * Exception handler - write routine, called when user app writes to the device. - * A per port write mutex is used to protect from another process writing to - * this port at the same time. This other process could be running on the other CPU - * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). - * Spinlocks protect the info xmit members. - */ -static int rp_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - const unsigned char *b; - int c, retval = 0; - unsigned long flags; - - if (count <= 0 || rocket_paranoia_check(info, "rp_write")) - return 0; - - if (mutex_lock_interruptible(&info->write_mtx)) - return -ERESTARTSYS; - -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_write %d chars...\n", count); -#endif - cp = &info->channel; - - if (!tty->stopped && info->xmit_fifo_room < count) - info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - - /* - * If the write queue for the port is empty, and there is FIFO space, stuff bytes - * into FIFO. Use the write queue for temp storage. - */ - if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { - c = min(count, info->xmit_fifo_room); - b = buf; - - /* Push data into FIFO, 2 bytes at a time */ - sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); - - /* If there is a byte remaining, write it */ - if (c & 1) - sOutB(sGetTxRxDataIO(cp), b[c - 1]); - - retval += c; - buf += c; - count -= c; - - spin_lock_irqsave(&info->slock, flags); - info->xmit_fifo_room -= c; - spin_unlock_irqrestore(&info->slock, flags); - } - - /* If count is zero, we wrote it all and are done */ - if (!count) - goto end; - - /* Write remaining data into the port's xmit_buf */ - while (1) { - /* Hung up ? */ - if (!tty_port_active(&info->port)) - goto end; - c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); - c = min(c, XMIT_BUF_SIZE - info->xmit_head); - if (c <= 0) - break; - - b = buf; - memcpy(info->xmit_buf + info->xmit_head, b, c); - - spin_lock_irqsave(&info->slock, flags); - info->xmit_head = - (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->slock, flags); - - buf += c; - count -= c; - retval += c; - } - - if ((retval > 0) && !tty->stopped) - set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - -end: - if (info->xmit_cnt < WAKEUP_CHARS) { - tty_wakeup(tty); -#ifdef ROCKETPORT_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - } - mutex_unlock(&info->write_mtx); - return retval; -} - -/* - * Return the number of characters that can be sent. We estimate - * only using the in-memory transmit buffer only, and ignore the - * potential space in the transmit FIFO. - */ -static int rp_write_room(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - int ret; - - if (rocket_paranoia_check(info, "rp_write_room")) - return 0; - - ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_write_room returns %d...\n", ret); -#endif - return ret; -} - -/* - * Return the number of characters in the buffer. Again, this only - * counts those characters in the in-memory transmit buffer. - */ -static int rp_chars_in_buffer(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - - if (rocket_paranoia_check(info, "rp_chars_in_buffer")) - return 0; - -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt); -#endif - return info->xmit_cnt; -} - -/* - * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the - * r_port struct for the port. Note that spinlock are used to protect info members, - * do not call this function if the spinlock is already held. - */ -static void rp_flush_buffer(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_flush_buffer")) - return; - - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - spin_unlock_irqrestore(&info->slock, flags); - -#ifdef ROCKETPORT_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - tty_wakeup(tty); - - cp = &info->channel; - sFlushTxFIFO(cp); -} - -#ifdef CONFIG_PCI - -static const struct pci_device_id rocket_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8J) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4J) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8SNI) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16SNI) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP16INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_CRP16INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP32INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP4) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP8) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_232) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_422) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP6M) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4M) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_8PORT) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_4PORT) }, - { } -}; -MODULE_DEVICE_TABLE(pci, rocket_pci_ids); - -/* Resets the speaker controller on RocketModem II and III devices */ -static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) -{ - ByteIO_t addr; - - /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ - if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { - addr = CtlP->AiopIO[0] + 0x4F; - sOutB(addr, 0); - } - - /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ - if ((model == MODEL_UPCI_RM3_8PORT) - || (model == MODEL_UPCI_RM3_4PORT)) { - addr = CtlP->AiopIO[0] + 0x88; - sOutB(addr, 0); - } -} - -/*************************************************************************** -Function: sPCIInitController -Purpose: Initialization of controller global registers and controller - structure. -Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, - IRQNum,Frequency,PeriodicOnly) - CONTROLLER_T *CtlP; Ptr to controller structure - int CtlNum; Controller number - ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. - This list must be in the order the AIOPs will be found on the - controller. Once an AIOP in the list is not found, it is - assumed that there are no more AIOPs on the controller. - int AiopIOListSize; Number of addresses in AiopIOList - int IRQNum; Interrupt Request number. Can be any of the following: - 0: Disable global interrupts - 3: IRQ 3 - 4: IRQ 4 - 5: IRQ 5 - 9: IRQ 9 - 10: IRQ 10 - 11: IRQ 11 - 12: IRQ 12 - 15: IRQ 15 - Byte_t Frequency: A flag identifying the frequency - of the periodic interrupt, can be any one of the following: - FREQ_DIS - periodic interrupt disabled - FREQ_137HZ - 137 Hertz - FREQ_69HZ - 69 Hertz - FREQ_34HZ - 34 Hertz - FREQ_17HZ - 17 Hertz - FREQ_9HZ - 9 Hertz - FREQ_4HZ - 4 Hertz - If IRQNum is set to 0 the Frequency parameter is - overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: 1 if all interrupts except the periodic - interrupt are to be blocked. - 0 is both the periodic interrupt and - other channel interrupts are allowed. - If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of 0. -Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller - initialization failed. - -Comments: - If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. - - If interrupts are to be completely disabled set IRQNum to 0. - - Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an - invalid combination. - - This function performs initialization of global interrupt modes, - but it does not actually enable global interrupts. To enable - and disable global interrupts use functions sEnGlobalInt() and - sDisGlobalInt(). Enabling of global interrupts is normally not - done until all other initializations are complete. - - Even if interrupts are globally enabled, they must also be - individually enabled for each channel that is to generate - interrupts. - -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. - - After this function all AIOPs on the controller are disabled, - they can be enabled with sEnAiop(). -*/ -static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, - ByteIO_t * AiopIOList, int AiopIOListSize, - WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, - int PeriodicOnly, int altChanRingIndicator, - int UPCIRingInd) -{ - int i; - ByteIO_t io; - - CtlP->AltChanRingIndicator = altChanRingIndicator; - CtlP->UPCIRingInd = UPCIRingInd; - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isPCI; /* controller release 1 */ - - if (ConfigIO) { - CtlP->isUPCI = 1; - CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; - CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; - CtlP->AiopIntrBits = upci_aiop_intr_bits; - } else { - CtlP->isUPCI = 0; - CtlP->PCIIO = - (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); - CtlP->AiopIntrBits = aiop_intr_bits; - } - - sPCIControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for (i = 0; i < AiopIOListSize; i++) { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t) io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - break; /* done looking for AIOPs */ - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ - sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA, sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - - if (CtlP->NumAiop == 0) - return (-1); - else - return (CtlP->NumAiop); -} - -/* - * Called when a PCI card is found. Retrieves and stores model information, - * init's aiopic and serial port hardware. - * Inputs: i is the board number (0-n) - */ -static __init int register_PCI(int i, struct pci_dev *dev) -{ - int num_aiops, aiop, max_num_aiops, chan; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - CONTROLLER_t *ctlp; - - int fast_clock = 0; - int altChanRingIndicator = 0; - int ports_per_aiop = 8; - WordIO_t ConfigIO = 0; - ByteIO_t UPCIRingInd = 0; - - if (!dev || !pci_match_id(rocket_pci_ids, dev) || - pci_enable_device(dev) || i >= NUM_BOARDS) - return 0; - - rcktpt_io_addr[i] = pci_resource_start(dev, 0); - - rcktpt_type[i] = ROCKET_TYPE_NORMAL; - rocketModel[i].loadrm2 = 0; - rocketModel[i].startingPortNumber = nextLineNumber; - - /* Depending on the model, set up some config variables */ - switch (dev->device) { - case PCI_DEVICE_ID_RP4QUAD: - max_num_aiops = 1; - ports_per_aiop = 4; - rocketModel[i].model = MODEL_RP4QUAD; - strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); - rocketModel[i].numPorts = 4; - break; - case PCI_DEVICE_ID_RP8OCTA: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8OCTA; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_URP8OCTA: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RP8OCTA; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP8INTF: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8INTF; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_URP8INTF: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RP8INTF; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP8J: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8J; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP4J: - max_num_aiops = 1; - ports_per_aiop = 4; - rocketModel[i].model = MODEL_RP4J; - strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors"); - rocketModel[i].numPorts = 4; - break; - case PCI_DEVICE_ID_RP8SNI: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8SNI; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP16SNI: - max_num_aiops = 2; - rocketModel[i].model = MODEL_RP16SNI; - strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_RP16INTF: - max_num_aiops = 2; - rocketModel[i].model = MODEL_RP16INTF; - strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_URP16INTF: - max_num_aiops = 2; - rocketModel[i].model = MODEL_UPCI_RP16INTF; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_CRP16INTF: - max_num_aiops = 2; - rocketModel[i].model = MODEL_CPCI_RP16INTF; - strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_RP32INTF: - max_num_aiops = 4; - rocketModel[i].model = MODEL_RP32INTF; - strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F"); - rocketModel[i].numPorts = 32; - break; - case PCI_DEVICE_ID_URP32INTF: - max_num_aiops = 4; - rocketModel[i].model = MODEL_UPCI_RP32INTF; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F"); - rocketModel[i].numPorts = 32; - break; - case PCI_DEVICE_ID_RPP4: - max_num_aiops = 1; - ports_per_aiop = 4; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RPP4; - strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port"); - rocketModel[i].numPorts = 4; - break; - case PCI_DEVICE_ID_RPP8: - max_num_aiops = 2; - ports_per_aiop = 4; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RPP8; - strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP2_232: - max_num_aiops = 1; - ports_per_aiop = 2; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RP2_232; - strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232"); - rocketModel[i].numPorts = 2; - break; - case PCI_DEVICE_ID_RP2_422: - max_num_aiops = 1; - ports_per_aiop = 2; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RP2_422; - strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422"); - rocketModel[i].numPorts = 2; - break; - case PCI_DEVICE_ID_RP6M: - - max_num_aiops = 1; - ports_per_aiop = 6; - - /* If revision is 1, the rocketmodem flash must be loaded. - * If it is 2 it is a "socketed" version. */ - if (dev->revision == 1) { - rcktpt_type[i] = ROCKET_TYPE_MODEMII; - rocketModel[i].loadrm2 = 1; - } else { - rcktpt_type[i] = ROCKET_TYPE_MODEM; - } - - rocketModel[i].model = MODEL_RP6M; - strcpy(rocketModel[i].modelString, "RocketModem 6 port"); - rocketModel[i].numPorts = 6; - break; - case PCI_DEVICE_ID_RP4M: - max_num_aiops = 1; - ports_per_aiop = 4; - if (dev->revision == 1) { - rcktpt_type[i] = ROCKET_TYPE_MODEMII; - rocketModel[i].loadrm2 = 1; - } else { - rcktpt_type[i] = ROCKET_TYPE_MODEM; - } - - rocketModel[i].model = MODEL_RP4M; - strcpy(rocketModel[i].modelString, "RocketModem 4 port"); - rocketModel[i].numPorts = 4; - break; - default: - max_num_aiops = 0; - break; - } - - /* - * Check for UPCI boards. - */ - - switch (dev->device) { - case PCI_DEVICE_ID_URP32INTF: - case PCI_DEVICE_ID_URP8INTF: - case PCI_DEVICE_ID_URP16INTF: - case PCI_DEVICE_ID_CRP16INTF: - case PCI_DEVICE_ID_URP8OCTA: - rcktpt_io_addr[i] = pci_resource_start(dev, 2); - ConfigIO = pci_resource_start(dev, 1); - if (dev->device == PCI_DEVICE_ID_URP8OCTA) { - UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; - - /* - * Check for octa or quad cable. - */ - if (! - (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) & - PCI_GPIO_CTRL_8PORT)) { - ports_per_aiop = 4; - rocketModel[i].numPorts = 4; - } - } - break; - case PCI_DEVICE_ID_UPCI_RM3_8PORT: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RM3_8PORT; - strcpy(rocketModel[i].modelString, "RocketModem III 8 port"); - rocketModel[i].numPorts = 8; - rcktpt_io_addr[i] = pci_resource_start(dev, 2); - UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; - ConfigIO = pci_resource_start(dev, 1); - rcktpt_type[i] = ROCKET_TYPE_MODEMIII; - break; - case PCI_DEVICE_ID_UPCI_RM3_4PORT: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RM3_4PORT; - strcpy(rocketModel[i].modelString, "RocketModem III 4 port"); - rocketModel[i].numPorts = 4; - rcktpt_io_addr[i] = pci_resource_start(dev, 2); - UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; - ConfigIO = pci_resource_start(dev, 1); - rcktpt_type[i] = ROCKET_TYPE_MODEMIII; - break; - default: - break; - } - - if (fast_clock) { - sClockPrescale = 0x12; /* mod 2 (divide by 3) */ - rp_baud_base[i] = 921600; - } else { - /* - * If support_low_speed is set, use the slow clock - * prescale, which supports 50 bps - */ - if (support_low_speed) { - /* mod 9 (divide by 10) prescale */ - sClockPrescale = 0x19; - rp_baud_base[i] = 230400; - } else { - /* mod 4 (divide by 5) prescale */ - sClockPrescale = 0x14; - rp_baud_base[i] = 460800; - } - } - - for (aiop = 0; aiop < max_num_aiops; aiop++) - aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); - ctlp = sCtlNumToCtlPtr(i); - num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd); - for (aiop = 0; aiop < max_num_aiops; aiop++) - ctlp->AiopNumChan[aiop] = ports_per_aiop; - - dev_info(&dev->dev, "comtrol PCI controller #%d found at " - "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n", - i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString, - rocketModel[i].startingPortNumber, - rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1); - - if (num_aiops <= 0) { - rcktpt_io_addr[i] = 0; - return (0); - } - is_PCI[i] = 1; - - /* Reset the AIOPIC, init the serial ports */ - for (aiop = 0; aiop < num_aiops; aiop++) { - sResetAiopByNum(ctlp, aiop); - for (chan = 0; chan < ports_per_aiop; chan++) - init_r_port(i, aiop, chan, dev); - } - - /* Rocket modems must be reset */ - if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || - (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || - (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { - for (chan = 0; chan < ports_per_aiop; chan++) - sPCIModemReset(ctlp, chan, 1); - msleep(500); - for (chan = 0; chan < ports_per_aiop; chan++) - sPCIModemReset(ctlp, chan, 0); - msleep(500); - rmSpeakerReset(ctlp, rocketModel[i].model); - } - return (1); -} - -/* - * Probes for PCI cards, inits them if found - * Input: board_found = number of ISA boards already found, or the - * starting board number - * Returns: Number of PCI boards found - */ -static int __init init_PCI(int boards_found) -{ - struct pci_dev *dev = NULL; - int count = 0; - - /* Work through the PCI device list, pulling out ours */ - while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { - if (register_PCI(count + boards_found, dev)) - count++; - } - return (count); -} - -#endif /* CONFIG_PCI */ - -/* - * Probes for ISA cards - * Input: i = the board number to look for - * Returns: 1 if board found, 0 else - */ -static int __init init_ISA(int i) -{ - int num_aiops, num_chan = 0, total_num_chan = 0; - int aiop, chan; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - CONTROLLER_t *ctlp; - char *type_string; - - /* If io_addr is zero, no board configured */ - if (rcktpt_io_addr[i] == 0) - return (0); - - /* Reserve the IO region */ - if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) { - printk(KERN_ERR "Unable to reserve IO region for configured " - "ISA RocketPort at address 0x%lx, board not " - "installed...\n", rcktpt_io_addr[i]); - rcktpt_io_addr[i] = 0; - return (0); - } - - ctlp = sCtlNumToCtlPtr(i); - - ctlp->boardType = rcktpt_type[i]; - - switch (rcktpt_type[i]) { - case ROCKET_TYPE_PC104: - type_string = "(PC104)"; - break; - case ROCKET_TYPE_MODEM: - type_string = "(RocketModem)"; - break; - case ROCKET_TYPE_MODEMII: - type_string = "(RocketModem II)"; - break; - default: - type_string = ""; - break; - } - - /* - * If support_low_speed is set, use the slow clock prescale, - * which supports 50 bps - */ - if (support_low_speed) { - sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ - rp_baud_base[i] = 230400; - } else { - sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */ - rp_baud_base[i] = 460800; - } - - for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++) - aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400); - - num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0); - - if (ctlp->boardType == ROCKET_TYPE_PC104) { - sEnAiop(ctlp, 2); /* only one AIOPIC, but these */ - sEnAiop(ctlp, 3); /* CSels used for other stuff */ - } - - /* If something went wrong initing the AIOP's release the ISA IO memory */ - if (num_aiops <= 0) { - release_region(rcktpt_io_addr[i], 64); - rcktpt_io_addr[i] = 0; - return (0); - } - - rocketModel[i].startingPortNumber = nextLineNumber; - - for (aiop = 0; aiop < num_aiops; aiop++) { - sResetAiopByNum(ctlp, aiop); - sEnAiop(ctlp, aiop); - num_chan = sGetAiopNumChan(ctlp, aiop); - total_num_chan += num_chan; - for (chan = 0; chan < num_chan; chan++) - init_r_port(i, aiop, chan, NULL); - } - is_PCI[i] = 0; - if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) { - num_chan = sGetAiopNumChan(ctlp, 0); - total_num_chan = num_chan; - for (chan = 0; chan < num_chan; chan++) - sModemReset(ctlp, chan, 1); - msleep(500); - for (chan = 0; chan < num_chan; chan++) - sModemReset(ctlp, chan, 0); - msleep(500); - strcpy(rocketModel[i].modelString, "RocketModem ISA"); - } else { - strcpy(rocketModel[i].modelString, "RocketPort ISA"); - } - rocketModel[i].numPorts = total_num_chan; - rocketModel[i].model = MODEL_ISA; - - printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n", - i, rcktpt_io_addr[i], num_aiops, type_string); - - printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", - rocketModel[i].modelString, - rocketModel[i].startingPortNumber, - rocketModel[i].startingPortNumber + - rocketModel[i].numPorts - 1); - - return (1); -} - -static const struct tty_operations rocket_ops = { - .open = rp_open, - .close = rp_close, - .write = rp_write, - .put_char = rp_put_char, - .write_room = rp_write_room, - .chars_in_buffer = rp_chars_in_buffer, - .flush_buffer = rp_flush_buffer, - .ioctl = rp_ioctl, - .throttle = rp_throttle, - .unthrottle = rp_unthrottle, - .set_termios = rp_set_termios, - .stop = rp_stop, - .start = rp_start, - .hangup = rp_hangup, - .break_ctl = rp_break, - .send_xchar = rp_send_xchar, - .wait_until_sent = rp_wait_until_sent, - .tiocmget = rp_tiocmget, - .tiocmset = rp_tiocmset, -}; - -static const struct tty_port_operations rocket_port_ops = { - .carrier_raised = carrier_raised, - .dtr_rts = dtr_rts, -}; - -/* - * The module "startup" routine; it's run when the module is loaded. - */ -static int __init rp_init(void) -{ - int ret = -ENOMEM, pci_boards_found, isa_boards_found, i; - - printk(KERN_INFO "RocketPort device driver module, version %s, %s\n", - ROCKET_VERSION, ROCKET_DATE); - - rocket_driver = alloc_tty_driver(MAX_RP_PORTS); - if (!rocket_driver) - goto err; - - /* - * If board 1 is non-zero, there is at least one ISA configured. If controller is - * zero, use the default controller IO address of board1 + 0x40. - */ - if (board1) { - if (controller == 0) - controller = board1 + 0x40; - } else { - controller = 0; /* Used as a flag, meaning no ISA boards */ - } - - /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */ - if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) { - printk(KERN_ERR "Unable to reserve IO region for first " - "configured ISA RocketPort controller 0x%lx. " - "Driver exiting\n", controller); - ret = -EBUSY; - goto err_tty; - } - - /* Store ISA variable retrieved from command line or .conf file. */ - rcktpt_io_addr[0] = board1; - rcktpt_io_addr[1] = board2; - rcktpt_io_addr[2] = board3; - rcktpt_io_addr[3] = board4; - - rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0]; - rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1]; - rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2]; - rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3]; - - /* - * Set up the tty driver structure and then register this - * driver with the tty layer. - */ - - rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; - rocket_driver->name = "ttyR"; - rocket_driver->driver_name = "Comtrol RocketPort"; - rocket_driver->major = TTY_ROCKET_MAJOR; - rocket_driver->minor_start = 0; - rocket_driver->type = TTY_DRIVER_TYPE_SERIAL; - rocket_driver->subtype = SERIAL_TYPE_NORMAL; - rocket_driver->init_termios = tty_std_termios; - rocket_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - rocket_driver->init_termios.c_ispeed = 9600; - rocket_driver->init_termios.c_ospeed = 9600; -#ifdef ROCKET_SOFT_FLOW - rocket_driver->flags |= TTY_DRIVER_REAL_RAW; -#endif - tty_set_operations(rocket_driver, &rocket_ops); - - ret = tty_register_driver(rocket_driver); - if (ret < 0) { - printk(KERN_ERR "Couldn't install tty RocketPort driver\n"); - goto err_controller; - } - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major); -#endif - - /* - * OK, let's probe each of the controllers looking for boards. Any boards found - * will be initialized here. - */ - isa_boards_found = 0; - pci_boards_found = 0; - - for (i = 0; i < NUM_BOARDS; i++) { - if (init_ISA(i)) - isa_boards_found++; - } - -#ifdef CONFIG_PCI - if (isa_boards_found < NUM_BOARDS) - pci_boards_found = init_PCI(isa_boards_found); -#endif - - max_board = pci_boards_found + isa_boards_found; - - if (max_board == 0) { - printk(KERN_ERR "No rocketport ports found; unloading driver\n"); - ret = -ENXIO; - goto err_ttyu; - } - - return 0; -err_ttyu: - tty_unregister_driver(rocket_driver); -err_controller: - if (controller) - release_region(controller, 4); -err_tty: - put_tty_driver(rocket_driver); -err: - return ret; -} - - -static void rp_cleanup_module(void) -{ - int retval; - int i; - - del_timer_sync(&rocket_timer); - - retval = tty_unregister_driver(rocket_driver); - if (retval) - printk(KERN_ERR "Error %d while trying to unregister " - "rocketport driver\n", -retval); - - for (i = 0; i < MAX_RP_PORTS; i++) - if (rp_table[i]) { - tty_unregister_device(rocket_driver, i); - tty_port_destroy(&rp_table[i]->port); - kfree(rp_table[i]); - } - - put_tty_driver(rocket_driver); - - for (i = 0; i < NUM_BOARDS; i++) { - if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) - continue; - release_region(rcktpt_io_addr[i], 64); - } - if (controller) - release_region(controller, 4); -} - -/*************************************************************************** -Function: sInitController -Purpose: Initialization of controller global registers and controller - structure. -Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, - IRQNum,Frequency,PeriodicOnly) - CONTROLLER_T *CtlP; Ptr to controller structure - int CtlNum; Controller number - ByteIO_t MudbacIO; Mudbac base I/O address. - ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. - This list must be in the order the AIOPs will be found on the - controller. Once an AIOP in the list is not found, it is - assumed that there are no more AIOPs on the controller. - int AiopIOListSize; Number of addresses in AiopIOList - int IRQNum; Interrupt Request number. Can be any of the following: - 0: Disable global interrupts - 3: IRQ 3 - 4: IRQ 4 - 5: IRQ 5 - 9: IRQ 9 - 10: IRQ 10 - 11: IRQ 11 - 12: IRQ 12 - 15: IRQ 15 - Byte_t Frequency: A flag identifying the frequency - of the periodic interrupt, can be any one of the following: - FREQ_DIS - periodic interrupt disabled - FREQ_137HZ - 137 Hertz - FREQ_69HZ - 69 Hertz - FREQ_34HZ - 34 Hertz - FREQ_17HZ - 17 Hertz - FREQ_9HZ - 9 Hertz - FREQ_4HZ - 4 Hertz - If IRQNum is set to 0 the Frequency parameter is - overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: 1 if all interrupts except the periodic - interrupt are to be blocked. - 0 is both the periodic interrupt and - other channel interrupts are allowed. - If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of 0. -Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller - initialization failed. - -Comments: - If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. - - If interrupts are to be completely disabled set IRQNum to 0. - - Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an - invalid combination. - - This function performs initialization of global interrupt modes, - but it does not actually enable global interrupts. To enable - and disable global interrupts use functions sEnGlobalInt() and - sDisGlobalInt(). Enabling of global interrupts is normally not - done until all other initializations are complete. - - Even if interrupts are globally enabled, they must also be - individually enabled for each channel that is to generate - interrupts. - -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. - - After this function all AIOPs on the controller are disabled, - they can be enabled with sEnAiop(). -*/ -static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, int AiopIOListSize, - int IRQNum, Byte_t Frequency, int PeriodicOnly) -{ - int i; - ByteIO_t io; - int done; - - CtlP->AiopIntrBits = aiop_intr_bits; - CtlP->AltChanRingIndicator = 0; - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isISA; - CtlP->MBaseIO = MudbacIO; - CtlP->MReg1IO = MudbacIO + 1; - CtlP->MReg2IO = MudbacIO + 2; - CtlP->MReg3IO = MudbacIO + 3; -#if 1 - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ -#else - if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */ - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ - } else { - CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ - CtlP->MReg3 = Frequency; /* set frequency */ - if (PeriodicOnly) { /* periodic interrupt only */ - CtlP->MReg3 |= PERIODIC_ONLY; - } - } -#endif - sOutB(CtlP->MReg2IO, CtlP->MReg2); - sOutB(CtlP->MReg3IO, CtlP->MReg3); - sControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for (i = done = 0; i < AiopIOListSize; i++) { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t) io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */ - sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */ - if (done) - continue; - sEnAiop(CtlP, i); /* enable the AIOP */ - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - done = 1; /* done looking for AIOPs */ - else { - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ - sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA, sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - sDisAiop(CtlP, i); /* disable AIOP */ - } - - if (CtlP->NumAiop == 0) - return (-1); - else - return (CtlP->NumAiop); -} - -/*************************************************************************** -Function: sReadAiopID -Purpose: Read the AIOP idenfication number directly from an AIOP. -Call: sReadAiopID(io) - ByteIO_t io: AIOP base I/O address -Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X - is replace by an identifying number. - Flag AIOPID_NULL if no valid AIOP is found -Warnings: No context switches are allowed while executing this function. - -*/ -static int sReadAiopID(ByteIO_t io) -{ - Byte_t AiopID; /* ID byte from AIOP */ - - sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */ - sOutB(io + _CMD_REG, 0x0); - AiopID = sInW(io + _CHN_STAT0) & 0x07; - if (AiopID == 0x06) - return (1); - else /* AIOP does not exist */ - return (-1); -} - -/*************************************************************************** -Function: sReadAiopNumChan -Purpose: Read the number of channels available in an AIOP directly from - an AIOP. -Call: sReadAiopNumChan(io) - WordIO_t io: AIOP base I/O address -Return: int: The number of channels available -Comments: The number of channels is determined by write/reads from identical - offsets within the SRAM address spaces for channels 0 and 4. - If the channel 4 space is mirrored to channel 0 it is a 4 channel - AIOP, otherwise it is an 8 channel. -Warnings: No context switches are allowed while executing this function. -*/ -static int sReadAiopNumChan(WordIO_t io) -{ - Word_t x; - static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; - - /* write to chan 0 SRAM */ - out32((DWordIO_t) io + _INDX_ADDR, R); - sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ - x = sInW(io + _INDX_DATA); - sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ - if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ - return (8); - else - return (4); -} - -/*************************************************************************** -Function: sInitChan -Purpose: Initialization of a channel and channel structure -Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) - CONTROLLER_T *CtlP; Ptr to controller structure - CHANNEL_T *ChP; Ptr to channel structure - int AiopNum; AIOP number within controller - int ChanNum; Channel number within AIOP -Return: int: 1 if initialization succeeded, 0 if it fails because channel - number exceeds number of channels available in AIOP. -Comments: This function must be called before a channel can be used. -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. -*/ -static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, - int ChanNum) -{ - int i; - WordIO_t AiopIO; - WordIO_t ChIOOff; - Byte_t *ChR; - Word_t ChOff; - static Byte_t R[4]; - int brd9600; - - if (ChanNum >= CtlP->AiopNumChan[AiopNum]) - return 0; /* exceeds num chans in AIOP */ - - /* Channel, AIOP, and controller identifiers */ - ChP->CtlP = CtlP; - ChP->ChanID = CtlP->AiopID[AiopNum]; - ChP->AiopNum = AiopNum; - ChP->ChanNum = ChanNum; - - /* Global direct addresses */ - AiopIO = CtlP->AiopIO[AiopNum]; - ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG; - ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN; - ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK; - ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR; - ChP->IndexData = AiopIO + _INDX_DATA; - - /* Channel direct addresses */ - ChIOOff = AiopIO + ChP->ChanNum * 2; - ChP->TxRxData = ChIOOff + _TD0; - ChP->ChanStat = ChIOOff + _CHN_STAT0; - ChP->TxRxCount = ChIOOff + _FIFO_CNT0; - ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0; - - /* Initialize the channel from the RData array */ - for (i = 0; i < RDATASIZE; i += 4) { - R[0] = RData[i]; - R[1] = RData[i + 1] + 0x10 * ChanNum; - R[2] = RData[i + 2]; - R[3] = RData[i + 3]; - out32(ChP->IndexAddr, R); - } - - ChR = ChP->R; - for (i = 0; i < RREGDATASIZE; i += 4) { - ChR[i] = RRegData[i]; - ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum; - ChR[i + 2] = RRegData[i + 2]; - ChR[i + 3] = RRegData[i + 3]; - } - - /* Indexed registers */ - ChOff = (Word_t) ChanNum *0x1000; - - if (sClockPrescale == 0x14) - brd9600 = 47; - else - brd9600 = 23; - - ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD); - ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); - ChP->BaudDiv[2] = (Byte_t) brd9600; - ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); - out32(ChP->IndexAddr, ChP->BaudDiv); - - ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); - ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); - ChP->TxControl[2] = 0; - ChP->TxControl[3] = 0; - out32(ChP->IndexAddr, ChP->TxControl); - - ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); - ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); - ChP->RxControl[2] = 0; - ChP->RxControl[3] = 0; - out32(ChP->IndexAddr, ChP->RxControl); - - ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); - ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); - ChP->TxEnables[2] = 0; - ChP->TxEnables[3] = 0; - out32(ChP->IndexAddr, ChP->TxEnables); - - ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); - ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); - ChP->TxCompare[2] = 0; - ChP->TxCompare[3] = 0; - out32(ChP->IndexAddr, ChP->TxCompare); - - ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); - ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); - ChP->TxReplace1[2] = 0; - ChP->TxReplace1[3] = 0; - out32(ChP->IndexAddr, ChP->TxReplace1); - - ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); - ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); - ChP->TxReplace2[2] = 0; - ChP->TxReplace2[3] = 0; - out32(ChP->IndexAddr, ChP->TxReplace2); - - ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; - ChP->TxFIFO = ChOff + _TX_FIFO; - - sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData, 0); - ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; - ChP->RxFIFO = ChOff + _RX_FIFO; - - sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData, 0); - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData, 0); - ChP->TxPrioCnt = ChOff + _TXP_CNT; - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt); - sOutB(ChP->IndexData, 0); - ChP->TxPrioPtr = ChOff + _TXP_PNTR; - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr); - sOutB(ChP->IndexData, 0); - ChP->TxPrioBuf = ChOff + _TXP_BUF; - sEnRxProcessor(ChP); /* start the Rx processor */ - - return 1; -} - -/*************************************************************************** -Function: sStopRxProcessor -Purpose: Stop the receive processor from processing a channel. -Call: sStopRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure - -Comments: The receive processor can be started again with sStartRxProcessor(). - This function causes the receive processor to skip over the - stopped channel. It does not stop it from processing other channels. - -Warnings: No context switches are allowed while executing this function. - - Do not leave the receive processor stopped for more than one - character time. - - After calling this function a delay of 4 uS is required to ensure - that the receive processor is no longer processing this channel. -*/ -static void sStopRxProcessor(CHANNEL_T * ChP) -{ - Byte_t R[4]; - - R[0] = ChP->R[0]; - R[1] = ChP->R[1]; - R[2] = 0x0a; - R[3] = ChP->R[3]; - out32(ChP->IndexAddr, R); -} - -/*************************************************************************** -Function: sFlushRxFIFO -Purpose: Flush the Rx FIFO -Call: sFlushRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: void -Comments: To prevent data from being enqueued or dequeued in the Tx FIFO - while it is being flushed the receive processor is stopped - and the transmitter is disabled. After these operations a - 4 uS delay is done before clearing the pointers to allow - the receive processor to stop. These items are handled inside - this function. -Warnings: No context switches are allowed while executing this function. -*/ -static void sFlushRxFIFO(CHANNEL_T * ChP) -{ - int i; - Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ - - if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ - return; /* don't need to flush */ - - RxFIFOEnabled = 0; - if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ - RxFIFOEnabled = 1; - sDisRxFIFO(ChP); /* disable it */ - for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - } - sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ - Ch = (Byte_t) sGetChanNum(ChP); - sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData, 0); - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData, 0); - if (RxFIFOEnabled) - sEnRxFIFO(ChP); /* enable Rx FIFO */ -} - -/*************************************************************************** -Function: sFlushTxFIFO -Purpose: Flush the Tx FIFO -Call: sFlushTxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: void -Comments: To prevent data from being enqueued or dequeued in the Tx FIFO - while it is being flushed the receive processor is stopped - and the transmitter is disabled. After these operations a - 4 uS delay is done before clearing the pointers to allow - the receive processor to stop. These items are handled inside - this function. -Warnings: No context switches are allowed while executing this function. -*/ -static void sFlushTxFIFO(CHANNEL_T * ChP) -{ - int i; - Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* 1 if transmitter enabled */ - - if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ - return; /* don't need to flush */ - - TxEnabled = 0; - if (ChP->TxControl[3] & TX_ENABLE) { - TxEnabled = 1; - sDisTransmit(ChP); /* disable transmitter */ - } - sStopRxProcessor(ChP); /* stop Rx processor */ - for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - Ch = (Byte_t) sGetChanNum(ChP); - sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData, 0); - if (TxEnabled) - sEnTransmit(ChP); /* enable transmitter */ - sStartRxProcessor(ChP); /* restart Rx processor */ -} - -/*************************************************************************** -Function: sWriteTxPrioByte -Purpose: Write a byte of priority transmit data to a channel -Call: sWriteTxPrioByte(ChP,Data) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Data; The transmit data byte - -Return: int: 1 if the bytes is successfully written, otherwise 0. - -Comments: The priority byte is transmitted before any data in the Tx FIFO. - -Warnings: No context switches are allowed while executing this function. -*/ -static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) -{ - Byte_t DWBuf[4]; /* buffer for double word writes */ - Word_t *WordPtr; /* must be far because Win SS != DS */ - register DWordIO_t IndexAddr; - - if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */ - IndexAddr = ChP->IndexAddr; - sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */ - if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */ - return (0); /* nothing sent */ - - WordPtr = (Word_t *) (&DWBuf[0]); - *WordPtr = ChP->TxPrioBuf; /* data byte address */ - - DWBuf[2] = Data; /* data byte value */ - out32(IndexAddr, DWBuf); /* write it out */ - - *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ - - DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ - DWBuf[3] = 0; /* priority buffer pointer */ - out32(IndexAddr, DWBuf); /* write it out */ - } else { /* write it to Tx FIFO */ - - sWriteTxByte(sGetTxRxDataIO(ChP), Data); - } - return (1); /* 1 byte sent */ -} - -/*************************************************************************** -Function: sEnInterrupts -Purpose: Enable one or more interrupts for a channel -Call: sEnInterrupts(ChP,Flags) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Flags: Interrupt enable flags, can be any combination - of the following flags: - TXINT_EN: Interrupt on Tx FIFO empty - RXINT_EN: Interrupt on Rx FIFO at trigger level (see - sSetRxTrigger()) - SRCINT_EN: Interrupt on SRC (Special Rx Condition) - MCINT_EN: Interrupt on modem input change - CHANINT_EN: Allow channel interrupt signal to the AIOP's - Interrupt Channel Register. -Return: void -Comments: If an interrupt enable flag is set in Flags, that interrupt will be - enabled. If an interrupt enable flag is not set in Flags, that - interrupt will not be changed. Interrupts can be disabled with - function sDisInterrupts(). - - This function sets the appropriate bit for the channel in the AIOP's - Interrupt Mask Register if the CHANINT_EN flag is set. This allows - this channel's bit to be set in the AIOP's Interrupt Channel Register. - - Interrupts must also be globally enabled before channel interrupts - will be passed on to the host. This is done with function - sEnGlobalInt(). - - In some cases it may be desirable to disable interrupts globally but - enable channel interrupts. This would allow the global interrupt - status register to be used to determine which AIOPs need service. -*/ -static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) -{ - Byte_t Mask; /* Interrupt Mask Register */ - - ChP->RxControl[2] |= - ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - - out32(ChP->IndexAddr, ChP->RxControl); - - ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); - - out32(ChP->IndexAddr, ChP->TxControl); - - if (Flags & CHANINT_EN) { - Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; - sOutB(ChP->IntMask, Mask); - } -} - -/*************************************************************************** -Function: sDisInterrupts -Purpose: Disable one or more interrupts for a channel -Call: sDisInterrupts(ChP,Flags) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Flags: Interrupt flags, can be any combination - of the following flags: - TXINT_EN: Interrupt on Tx FIFO empty - RXINT_EN: Interrupt on Rx FIFO at trigger level (see - sSetRxTrigger()) - SRCINT_EN: Interrupt on SRC (Special Rx Condition) - MCINT_EN: Interrupt on modem input change - CHANINT_EN: Disable channel interrupt signal to the - AIOP's Interrupt Channel Register. -Return: void -Comments: If an interrupt flag is set in Flags, that interrupt will be - disabled. If an interrupt flag is not set in Flags, that - interrupt will not be changed. Interrupts can be enabled with - function sEnInterrupts(). - - This function clears the appropriate bit for the channel in the AIOP's - Interrupt Mask Register if the CHANINT_EN flag is set. This blocks - this channel's bit from being set in the AIOP's Interrupt Channel - Register. -*/ -static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) -{ - Byte_t Mask; /* Interrupt Mask Register */ - - ChP->RxControl[2] &= - ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - out32(ChP->IndexAddr, ChP->RxControl); - ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); - out32(ChP->IndexAddr, ChP->TxControl); - - if (Flags & CHANINT_EN) { - Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; - sOutB(ChP->IntMask, Mask); - } -} - -static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) -{ - sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); -} - -/* - * Not an official SSCI function, but how to reset RocketModems. - * ISA bus version - */ -static void sModemReset(CONTROLLER_T * CtlP, int chan, int on) -{ - ByteIO_t addr; - Byte_t val; - - addr = CtlP->AiopIO[0] + 0x400; - val = sInB(CtlP->MReg3IO); - /* if AIOP[1] is not enabled, enable it */ - if ((val & 2) == 0) { - val = sInB(CtlP->MReg2IO); - sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03)); - sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6)); - } - - sEnAiop(CtlP, 1); - if (!on) - addr += 8; - sOutB(addr + chan, 0); /* apply or remove reset */ - sDisAiop(CtlP, 1); -} - -/* - * Not an official SSCI function, but how to reset RocketModems. - * PCI bus version - */ -static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) -{ - ByteIO_t addr; - - addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */ - if (!on) - addr += 8; - sOutB(addr + chan, 0); /* apply or remove reset */ -} - -/* Returns the line number given the controller (board), aiop and channel number */ -static unsigned char GetLineNumber(int ctrl, int aiop, int ch) -{ - return lineNumbers[(ctrl << 5) | (aiop << 3) | ch]; -} - -/* - * Stores the line number associated with a given controller (board), aiop - * and channel number. - * Returns: The line number assigned - */ -static unsigned char SetLineNumber(int ctrl, int aiop, int ch) -{ - lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++; - return (nextLineNumber - 1); -} diff --git a/drivers/tty/rocket.h b/drivers/tty/rocket.h deleted file mode 100644 index d62ed6587f32ec62d98d77574053ca2c1a1af3cc..0000000000000000000000000000000000000000 --- a/drivers/tty/rocket.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * rocket.h --- the exported interface of the rocket driver to its configuration program. - * - * Written by Theodore Ts'o, Copyright 1997. - * Copyright 1997 Comtrol Corporation. - * - */ - -/* Model Information Struct */ -typedef struct { - unsigned long model; - char modelString[80]; - unsigned long numPorts; - int loadrm2; - int startingPortNumber; -} rocketModel_t; - -struct rocket_config { - int line; - int flags; - int closing_wait; - int close_delay; - int port; - int reserved[32]; -}; - -struct rocket_ports { - int tty_major; - int callout_major; - rocketModel_t rocketModel[8]; -}; - -struct rocket_version { - char rocket_version[32]; - char rocket_date[32]; - char reserved[64]; -}; - -/* - * Rocketport flags - */ -/*#define ROCKET_CALLOUT_NOHUP 0x00000001 */ -#define ROCKET_FORCE_CD 0x00000002 -#define ROCKET_HUP_NOTIFY 0x00000004 -#define ROCKET_SPLIT_TERMIOS 0x00000008 -#define ROCKET_SPD_MASK 0x00000070 -#define ROCKET_SPD_HI 0x00000010 /* Use 57600 instead of 38400 bps */ -#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ -#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ -#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ -#define ROCKET_SAK 0x00000080 -#define ROCKET_SESSION_LOCKOUT 0x00000100 -#define ROCKET_PGRP_LOCKOUT 0x00000200 -#define ROCKET_RTS_TOGGLE 0x00000400 -#define ROCKET_MODE_MASK 0x00003000 -#define ROCKET_MODE_RS232 0x00000000 -#define ROCKET_MODE_RS485 0x00001000 -#define ROCKET_MODE_RS422 0x00002000 -#define ROCKET_FLAGS 0x00003FFF - -#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged - * users can set or reset */ - -/* - * For closing_wait and closing_wait2 - */ -#define ROCKET_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE -#define ROCKET_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF - -/* - * Rocketport ioctls -- "RP" - */ -#define RCKP_GET_CONFIG 0x00525002 -#define RCKP_SET_CONFIG 0x00525003 -#define RCKP_GET_PORTS 0x00525004 -#define RCKP_RESET_RM2 0x00525005 -#define RCKP_GET_VERSION 0x00525006 - -/* Rocketport Models */ -#define MODEL_RP32INTF 0x0001 /* RP 32 port w/external I/F */ -#define MODEL_RP8INTF 0x0002 /* RP 8 port w/external I/F */ -#define MODEL_RP16INTF 0x0003 /* RP 16 port w/external I/F */ -#define MODEL_RP8OCTA 0x0005 /* RP 8 port w/octa cable */ -#define MODEL_RP4QUAD 0x0004 /* RP 4 port w/quad cable */ -#define MODEL_RP8J 0x0006 /* RP 8 port w/RJ11 connectors */ -#define MODEL_RP4J 0x0007 /* RP 4 port w/RJ45 connectors */ -#define MODEL_RP8SNI 0x0008 /* RP 8 port w/ DB78 SNI connector */ -#define MODEL_RP16SNI 0x0009 /* RP 16 port w/ DB78 SNI connector */ -#define MODEL_RPP4 0x000A /* RP Plus 4 port */ -#define MODEL_RPP8 0x000B /* RP Plus 8 port */ -#define MODEL_RP2_232 0x000E /* RP Plus 2 port RS232 */ -#define MODEL_RP2_422 0x000F /* RP Plus 2 port RS232 */ - -/* Rocketmodem II Models */ -#define MODEL_RP6M 0x000C /* RM 6 port */ -#define MODEL_RP4M 0x000D /* RM 4 port */ - -/* Universal PCI boards */ -#define MODEL_UPCI_RP32INTF 0x0801 /* RP UPCI 32 port w/external I/F */ -#define MODEL_UPCI_RP8INTF 0x0802 /* RP UPCI 8 port w/external I/F */ -#define MODEL_UPCI_RP16INTF 0x0803 /* RP UPCI 16 port w/external I/F */ -#define MODEL_UPCI_RP8OCTA 0x0805 /* RP UPCI 8 port w/octa cable */ -#define MODEL_UPCI_RM3_8PORT 0x080C /* RP UPCI Rocketmodem III 8 port */ -#define MODEL_UPCI_RM3_4PORT 0x080C /* RP UPCI Rocketmodem III 4 port */ - -/* Compact PCI 16 port */ -#define MODEL_CPCI_RP16INTF 0x0903 /* RP Compact PCI 16 port w/external I/F */ - -/* All ISA boards */ -#define MODEL_ISA 0x1000 diff --git a/drivers/tty/rocket_int.h b/drivers/tty/rocket_int.h deleted file mode 100644 index 727e50dbb92f72aaf56c449d5ecb9cb362c6cd1e..0000000000000000000000000000000000000000 --- a/drivers/tty/rocket_int.h +++ /dev/null @@ -1,1214 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * rocket_int.h --- internal header file for rocket.c - * - * Written by Theodore Ts'o, Copyright 1997. - * Copyright 1997 Comtrol Corporation. - * - */ - -/* - * Definition of the types in rcktpt_type - */ -#define ROCKET_TYPE_NORMAL 0 -#define ROCKET_TYPE_MODEM 1 -#define ROCKET_TYPE_MODEMII 2 -#define ROCKET_TYPE_MODEMIII 3 -#define ROCKET_TYPE_PC104 4 - -#include <linux/mutex.h> - -#include <asm/io.h> -#include <asm/byteorder.h> - -typedef unsigned char Byte_t; -typedef unsigned int ByteIO_t; - -typedef unsigned int Word_t; -typedef unsigned int WordIO_t; - -typedef unsigned int DWordIO_t; - -/* - * Note! Normally the Linux I/O macros already take care of - * byte-swapping the I/O instructions. However, all accesses using - * sOutDW aren't really 32-bit accesses, but should be handled in byte - * order. Hence the use of the cpu_to_le32() macro to byte-swap - * things to no-op the byte swapping done by the big-endian outl() - * instruction. - */ - -static inline void sOutB(unsigned short port, unsigned char value) -{ -#ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "sOutB(%x, %x)...\n", port, value); -#endif - outb_p(value, port); -} - -static inline void sOutW(unsigned short port, unsigned short value) -{ -#ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "sOutW(%x, %x)...\n", port, value); -#endif - outw_p(value, port); -} - -static inline void out32(unsigned short port, Byte_t *p) -{ - u32 value = get_unaligned_le32(p); -#ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); -#endif - outl_p(value, port); -} - -static inline unsigned char sInB(unsigned short port) -{ - return inb_p(port); -} - -static inline unsigned short sInW(unsigned short port) -{ - return inw_p(port); -} - -/* This is used to move arrays of bytes so byte swapping isn't appropriate. */ -#define sOutStrW(port, addr, count) if (count) outsw(port, addr, count) -#define sInStrW(port, addr, count) if (count) insw(port, addr, count) - -#define CTL_SIZE 8 -#define AIOP_CTL_SIZE 4 -#define CHAN_AIOP_SIZE 8 -#define MAX_PORTS_PER_AIOP 8 -#define MAX_AIOPS_PER_BOARD 4 -#define MAX_PORTS_PER_BOARD 32 - -/* Bus type ID */ -#define isISA 0 -#define isPCI 1 -#define isMC 2 - -/* Controller ID numbers */ -#define CTLID_NULL -1 /* no controller exists */ -#define CTLID_0001 0x0001 /* controller release 1 */ - -/* AIOP ID numbers, identifies AIOP type implementing channel */ -#define AIOPID_NULL -1 /* no AIOP or channel exists */ -#define AIOPID_0001 0x0001 /* AIOP release 1 */ - -/************************************************************************ - Global Register Offsets - Direct Access - Fixed values -************************************************************************/ - -#define _CMD_REG 0x38 /* Command Register 8 Write */ -#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ -#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ -#define _UNUSED 0x3B /* Unused 8 */ -#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ -#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ - -/************************************************************************ - Channel Register Offsets for 1st channel in AIOP - Direct Access -************************************************************************/ -#define _TD0 0x00 /* Transmit Data 16 Write */ -#define _RD0 0x00 /* Receive Data 16 Read */ -#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ -#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ -#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ - -/************************************************************************ - Tx Control Register Offsets - Indexed - External - Fixed -************************************************************************/ -#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ -#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ -#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ -#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ -#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ -#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ - -/************************************************************************ -Memory Controller Register Offsets - Indexed - External - Fixed -************************************************************************/ -#define _RX_FIFO 0x000 /* Rx FIFO */ -#define _TX_FIFO 0x800 /* Tx FIFO */ -#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ -#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ -#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ -#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ -#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ -#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ - -#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ -#define TXFIFO_SIZE 255 /* size of Tx FIFO */ -#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ - -/************************************************************************ -Tx Priority Buffer - Indexed - External - Fixed -************************************************************************/ -#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ -#define TXP_SIZE 0x20 /* 32 bytes */ - -/************************************************************************ -Channel Register Offsets - Indexed - Internal - Fixed -************************************************************************/ - -#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ -#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ -#define _BAUD 0xFF4 /* Baud Rate 16 Write */ -#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ - -#define STMBREAK 0x08 /* BREAK */ -#define STMFRAME 0x04 /* framing error */ -#define STMRCVROVR 0x02 /* receiver over run error */ -#define STMPARITY 0x01 /* parity error */ -#define STMERROR (STMBREAK | STMFRAME | STMPARITY) -#define STMBREAKH 0x800 /* BREAK */ -#define STMFRAMEH 0x400 /* framing error */ -#define STMRCVROVRH 0x200 /* receiver over run error */ -#define STMPARITYH 0x100 /* parity error */ -#define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH) - -#define CTS_ACT 0x20 /* CTS input asserted */ -#define DSR_ACT 0x10 /* DSR input asserted */ -#define CD_ACT 0x08 /* CD input asserted */ -#define TXFIFOMT 0x04 /* Tx FIFO is empty */ -#define TXSHRMT 0x02 /* Tx shift register is empty */ -#define RDA 0x01 /* Rx data available */ -#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ - -#define STATMODE 0x8000 /* status mode enable bit */ -#define RXFOVERFL 0x2000 /* receive FIFO overflow */ -#define RX2MATCH 0x1000 /* receive compare byte 2 match */ -#define RX1MATCH 0x0800 /* receive compare byte 1 match */ -#define RXBREAK 0x0400 /* received BREAK */ -#define RXFRAME 0x0200 /* received framing error */ -#define RXPARITY 0x0100 /* received parity error */ -#define STATERROR (RXBREAK | RXFRAME | RXPARITY) - -#define CTSFC_EN 0x80 /* CTS flow control enable bit */ -#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ -#define TXINT_EN 0x10 /* transmit interrupt enable */ -#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ -#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ -#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ -#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ - -#define SETBREAK 0x10 /* send break condition (must clear) */ -#define LOCALLOOP 0x08 /* local loopback set for test */ -#define SET_DTR 0x04 /* assert DTR */ -#define SET_RTS 0x02 /* assert RTS */ -#define TX_ENABLE 0x01 /* enable transmitter */ - -#define RTSFC_EN 0x40 /* RTS flow control enable */ -#define RXPROC_EN 0x20 /* receive processor enable */ -#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ -#define TRIG_1 0x08 /* trigger level 1 char */ -#define TRIG_1_2 0x10 /* trigger level 1/2 */ -#define TRIG_7_8 0x18 /* trigger level 7/8 */ -#define TRIG_MASK 0x18 /* trigger level mask */ -#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ -#define RXINT_EN 0x02 /* Rx interrupt enable */ -#define MCINT_EN 0x01 /* modem change interrupt enable */ - -#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ -#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ -#define SRC_INT 0x08 /* special receive condition interrupt */ -#define DELTA_CD 0x04 /* CD change interrupt */ -#define DELTA_CTS 0x02 /* CTS change interrupt */ -#define DELTA_DSR 0x01 /* DSR change interrupt */ - -#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ -#define IGN2_EN 0x08 /* ignore byte 2 enable */ -#define IGN1_EN 0x04 /* ignore byte 1 enable */ -#define COMP2_EN 0x02 /* compare byte 2 enable */ -#define COMP1_EN 0x01 /* compare byte 1 enable */ - -#define RESET_ALL 0x80 /* reset AIOP (all channels) */ -#define TXOVERIDE 0x40 /* Transmit software off override */ -#define RESETUART 0x20 /* reset channel's UART */ -#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ -#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ - -#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ -#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ -#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ -#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ - -#define INTR_EN 0x08 /* allow interrupts to host */ -#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ - -/************************************************************************** - MUDBAC remapped for PCI -**************************************************************************/ - -#define _CFG_INT_PCI 0x40 -#define _PCI_INT_FUNC 0x3A - -#define PCI_STROB 0x2000 /* bit 13 of int aiop register */ -#define INTR_EN_PCI 0x0010 /* allow interrupts to host */ - -/* - * Definitions for Universal PCI board registers - */ -#define _PCI_9030_INT_CTRL 0x4c /* Offsets from BAR1 */ -#define _PCI_9030_GPIO_CTRL 0x54 -#define PCI_INT_CTRL_AIOP 0x0001 -#define PCI_GPIO_CTRL_8PORT 0x4000 -#define _PCI_9030_RING_IND 0xc0 /* Offsets from BAR1 */ - -#define CHAN3_EN 0x08 /* enable AIOP 3 */ -#define CHAN2_EN 0x04 /* enable AIOP 2 */ -#define CHAN1_EN 0x02 /* enable AIOP 1 */ -#define CHAN0_EN 0x01 /* enable AIOP 0 */ -#define FREQ_DIS 0x00 -#define FREQ_274HZ 0x60 -#define FREQ_137HZ 0x50 -#define FREQ_69HZ 0x40 -#define FREQ_34HZ 0x30 -#define FREQ_17HZ 0x20 -#define FREQ_9HZ 0x10 -#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ - -#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ - -#define RDATASIZE 72 -#define RREGDATASIZE 52 - -/* - * AIOP interrupt bits for ISA/PCI boards and UPCI boards. - */ -#define AIOP_INTR_BIT_0 0x0001 -#define AIOP_INTR_BIT_1 0x0002 -#define AIOP_INTR_BIT_2 0x0004 -#define AIOP_INTR_BIT_3 0x0008 - -#define AIOP_INTR_BITS ( \ - AIOP_INTR_BIT_0 \ - | AIOP_INTR_BIT_1 \ - | AIOP_INTR_BIT_2 \ - | AIOP_INTR_BIT_3) - -#define UPCI_AIOP_INTR_BIT_0 0x0004 -#define UPCI_AIOP_INTR_BIT_1 0x0020 -#define UPCI_AIOP_INTR_BIT_2 0x0100 -#define UPCI_AIOP_INTR_BIT_3 0x0800 - -#define UPCI_AIOP_INTR_BITS ( \ - UPCI_AIOP_INTR_BIT_0 \ - | UPCI_AIOP_INTR_BIT_1 \ - | UPCI_AIOP_INTR_BIT_2 \ - | UPCI_AIOP_INTR_BIT_3) - -/* Controller level information structure */ -typedef struct { - int CtlID; - int CtlNum; - int BusType; - int boardType; - int isUPCI; - WordIO_t PCIIO; - WordIO_t PCIIO2; - ByteIO_t MBaseIO; - ByteIO_t MReg1IO; - ByteIO_t MReg2IO; - ByteIO_t MReg3IO; - Byte_t MReg2; - Byte_t MReg3; - int NumAiop; - int AltChanRingIndicator; - ByteIO_t UPCIRingInd; - WordIO_t AiopIO[AIOP_CTL_SIZE]; - ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; - int AiopID[AIOP_CTL_SIZE]; - int AiopNumChan[AIOP_CTL_SIZE]; - Word_t *AiopIntrBits; -} CONTROLLER_T; - -typedef CONTROLLER_T CONTROLLER_t; - -/* Channel level information structure */ -typedef struct { - CONTROLLER_T *CtlP; - int AiopNum; - int ChanID; - int ChanNum; - int rtsToggle; - - ByteIO_t Cmd; - ByteIO_t IntChan; - ByteIO_t IntMask; - DWordIO_t IndexAddr; - WordIO_t IndexData; - - WordIO_t TxRxData; - WordIO_t ChanStat; - WordIO_t TxRxCount; - ByteIO_t IntID; - - Word_t TxFIFO; - Word_t TxFIFOPtrs; - Word_t RxFIFO; - Word_t RxFIFOPtrs; - Word_t TxPrioCnt; - Word_t TxPrioPtr; - Word_t TxPrioBuf; - - Byte_t R[RREGDATASIZE]; - - Byte_t BaudDiv[4]; - Byte_t TxControl[4]; - Byte_t RxControl[4]; - Byte_t TxEnables[4]; - Byte_t TxCompare[4]; - Byte_t TxReplace1[4]; - Byte_t TxReplace2[4]; -} CHANNEL_T; - -typedef CHANNEL_T CHANNEL_t; -typedef CHANNEL_T *CHANPTR_T; - -#define InterfaceModeRS232 0x00 -#define InterfaceModeRS422 0x08 -#define InterfaceModeRS485 0x10 -#define InterfaceModeRS232T 0x18 - -/*************************************************************************** -Function: sClrBreak -Purpose: Stop sending a transmit BREAK signal -Call: sClrBreak(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrBreak(ChP) \ -do { \ - (ChP)->TxControl[3] &= ~SETBREAK; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sClrDTR -Purpose: Clr the DTR output -Call: sClrDTR(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrDTR(ChP) \ -do { \ - (ChP)->TxControl[3] &= ~SET_DTR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sClrRTS -Purpose: Clr the RTS output -Call: sClrRTS(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrRTS(ChP) \ -do { \ - if ((ChP)->rtsToggle) break; \ - (ChP)->TxControl[3] &= ~SET_RTS; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sClrTxXOFF -Purpose: Clear any existing transmit software flow control off condition -Call: sClrTxXOFF(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrTxXOFF(ChP) \ -do { \ - sOutB((ChP)->Cmd,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \ - sOutB((ChP)->Cmd,(Byte_t)(ChP)->ChanNum); \ -} while (0) - -/*************************************************************************** -Function: sCtlNumToCtlPtr -Purpose: Convert a controller number to controller structure pointer -Call: sCtlNumToCtlPtr(CtlNum) - int CtlNum; Controller number -Return: CONTROLLER_T *: Ptr to controller structure -*/ -#define sCtlNumToCtlPtr(CTLNUM) &sController[CTLNUM] - -/*************************************************************************** -Function: sControllerEOI -Purpose: Strobe the MUDBAC's End Of Interrupt bit. -Call: sControllerEOI(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -*/ -#define sControllerEOI(CTLP) sOutB((CTLP)->MReg2IO,(CTLP)->MReg2 | INT_STROB) - -/*************************************************************************** -Function: sPCIControllerEOI -Purpose: Strobe the PCI End Of Interrupt bit. - For the UPCI boards, toggle the AIOP interrupt enable bit - (this was taken from the Windows driver). -Call: sPCIControllerEOI(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -*/ -#define sPCIControllerEOI(CTLP) \ -do { \ - if ((CTLP)->isUPCI) { \ - Word_t w = sInW((CTLP)->PCIIO); \ - sOutW((CTLP)->PCIIO, (w ^ PCI_INT_CTRL_AIOP)); \ - sOutW((CTLP)->PCIIO, w); \ - } \ - else { \ - sOutW((CTLP)->PCIIO, PCI_STROB); \ - } \ -} while (0) - -/*************************************************************************** -Function: sDisAiop -Purpose: Disable I/O access to an AIOP -Call: sDisAiop(CltP) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; Number of AIOP on controller -*/ -#define sDisAiop(CTLP,AIOPNUM) \ -do { \ - (CTLP)->MReg3 &= sBitMapClrTbl[AIOPNUM]; \ - sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} while (0) - -/*************************************************************************** -Function: sDisCTSFlowCtl -Purpose: Disable output flow control using CTS -Call: sDisCTSFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisCTSFlowCtl(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~CTSFC_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sDisIXANY -Purpose: Disable IXANY Software Flow Control -Call: sDisIXANY(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisIXANY(ChP) \ -do { \ - (ChP)->R[0x0e] = 0x86; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ -} while (0) - -/*************************************************************************** -Function: DisParity -Purpose: Disable parity -Call: sDisParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). -*/ -#define sDisParity(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~PARITY_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sDisRTSToggle -Purpose: Disable RTS toggle -Call: sDisRTSToggle(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisRTSToggle(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~RTSTOG_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ - (ChP)->rtsToggle = 0; \ -} while (0) - -/*************************************************************************** -Function: sDisRxFIFO -Purpose: Disable Rx FIFO -Call: sDisRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisRxFIFO(ChP) \ -do { \ - (ChP)->R[0x32] = 0x0a; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ -} while (0) - -/*************************************************************************** -Function: sDisRxStatusMode -Purpose: Disable the Rx status mode -Call: sDisRxStatusMode(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This takes the channel out of the receive status mode. All - subsequent reads of receive data using sReadRxWord() will return - two data bytes. -*/ -#define sDisRxStatusMode(ChP) sOutW((ChP)->ChanStat,0) - -/*************************************************************************** -Function: sDisTransmit -Purpose: Disable transmit -Call: sDisTransmit(ChP) - CHANNEL_T *ChP; Ptr to channel structure - This disables movement of Tx data from the Tx FIFO into the 1 byte - Tx buffer. Therefore there could be up to a 2 byte latency - between the time sDisTransmit() is called and the transmit buffer - and transmit shift register going completely empty. -*/ -#define sDisTransmit(ChP) \ -do { \ - (ChP)->TxControl[3] &= ~TX_ENABLE; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sDisTxSoftFlowCtl -Purpose: Disable Tx Software Flow Control -Call: sDisTxSoftFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisTxSoftFlowCtl(ChP) \ -do { \ - (ChP)->R[0x06] = 0x8a; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ -} while (0) - -/*************************************************************************** -Function: sEnAiop -Purpose: Enable I/O access to an AIOP -Call: sEnAiop(CltP) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; Number of AIOP on controller -*/ -#define sEnAiop(CTLP,AIOPNUM) \ -do { \ - (CTLP)->MReg3 |= sBitMapSetTbl[AIOPNUM]; \ - sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} while (0) - -/*************************************************************************** -Function: sEnCTSFlowCtl -Purpose: Enable output flow control using CTS -Call: sEnCTSFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnCTSFlowCtl(ChP) \ -do { \ - (ChP)->TxControl[2] |= CTSFC_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnIXANY -Purpose: Enable IXANY Software Flow Control -Call: sEnIXANY(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnIXANY(ChP) \ -do { \ - (ChP)->R[0x0e] = 0x21; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ -} while (0) - -/*************************************************************************** -Function: EnParity -Purpose: Enable parity -Call: sEnParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: Before enabling parity odd or even parity should be chosen using - functions sSetOddParity() or sSetEvenParity(). -*/ -#define sEnParity(ChP) \ -do { \ - (ChP)->TxControl[2] |= PARITY_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnRTSToggle -Purpose: Enable RTS toggle -Call: sEnRTSToggle(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function will disable RTS flow control and clear the RTS - line to allow operation of RTS toggle. -*/ -#define sEnRTSToggle(ChP) \ -do { \ - (ChP)->RxControl[2] &= ~RTSFC_EN; \ - out32((ChP)->IndexAddr,(ChP)->RxControl); \ - (ChP)->TxControl[2] |= RTSTOG_EN; \ - (ChP)->TxControl[3] &= ~SET_RTS; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ - (ChP)->rtsToggle = 1; \ -} while (0) - -/*************************************************************************** -Function: sEnRxFIFO -Purpose: Enable Rx FIFO -Call: sEnRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnRxFIFO(ChP) \ -do { \ - (ChP)->R[0x32] = 0x08; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ -} while (0) - -/*************************************************************************** -Function: sEnRxProcessor -Purpose: Enable the receive processor -Call: sEnRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function is used to start the receive processor. When - the channel is in the reset state the receive processor is not - running. This is done to prevent the receive processor from - executing invalid microcode instructions prior to the - downloading of the microcode. - -Warnings: This function must be called after valid microcode has been - downloaded to the AIOP, and it must not be called before the - microcode has been downloaded. -*/ -#define sEnRxProcessor(ChP) \ -do { \ - (ChP)->RxControl[2] |= RXPROC_EN; \ - out32((ChP)->IndexAddr,(ChP)->RxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnRxStatusMode -Purpose: Enable the Rx status mode -Call: sEnRxStatusMode(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This places the channel in the receive status mode. All subsequent - reads of receive data using sReadRxWord() will return a data byte - in the low word and a status byte in the high word. - -*/ -#define sEnRxStatusMode(ChP) sOutW((ChP)->ChanStat,STATMODE) - -/*************************************************************************** -Function: sEnTransmit -Purpose: Enable transmit -Call: sEnTransmit(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnTransmit(ChP) \ -do { \ - (ChP)->TxControl[3] |= TX_ENABLE; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnTxSoftFlowCtl -Purpose: Enable Tx Software Flow Control -Call: sEnTxSoftFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnTxSoftFlowCtl(ChP) \ -do { \ - (ChP)->R[0x06] = 0xc5; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ -} while (0) - -/*************************************************************************** -Function: sGetAiopIntStatus -Purpose: Get the AIOP interrupt status -Call: sGetAiopIntStatus(CtlP,AiopNum) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; AIOP number -Return: Byte_t: The AIOP interrupt status. Bits 0 through 7 - represent channels 0 through 7 respectively. If a - bit is set that channel is interrupting. -*/ -#define sGetAiopIntStatus(CTLP,AIOPNUM) sInB((CTLP)->AiopIntChanIO[AIOPNUM]) - -/*************************************************************************** -Function: sGetAiopNumChan -Purpose: Get the number of channels supported by an AIOP -Call: sGetAiopNumChan(CtlP,AiopNum) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; AIOP number -Return: int: The number of channels supported by the AIOP -*/ -#define sGetAiopNumChan(CTLP,AIOPNUM) (CTLP)->AiopNumChan[AIOPNUM] - -/*************************************************************************** -Function: sGetChanIntID -Purpose: Get a channel's interrupt identification byte -Call: sGetChanIntID(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The channel interrupt ID. Can be any - combination of the following flags: - RXF_TRIG: Rx FIFO trigger level interrupt - TXFIFO_MT: Tx FIFO empty interrupt - SRC_INT: Special receive condition interrupt - DELTA_CD: CD change interrupt - DELTA_CTS: CTS change interrupt - DELTA_DSR: DSR change interrupt -*/ -#define sGetChanIntID(ChP) (sInB((ChP)->IntID) & (RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR)) - -/*************************************************************************** -Function: sGetChanNum -Purpose: Get the number of a channel within an AIOP -Call: sGetChanNum(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: int: Channel number within AIOP, or NULLCHAN if channel does - not exist. -*/ -#define sGetChanNum(ChP) (ChP)->ChanNum - -/*************************************************************************** -Function: sGetChanStatus -Purpose: Get the channel status -Call: sGetChanStatus(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Word_t: The channel status. Can be any combination of - the following flags: - LOW BYTE FLAGS - CTS_ACT: CTS input asserted - DSR_ACT: DSR input asserted - CD_ACT: CD input asserted - TXFIFOMT: Tx FIFO is empty - TXSHRMT: Tx shift register is empty - RDA: Rx data available - - HIGH BYTE FLAGS - STATMODE: status mode enable bit - RXFOVERFL: receive FIFO overflow - RX2MATCH: receive compare byte 2 match - RX1MATCH: receive compare byte 1 match - RXBREAK: received BREAK - RXFRAME: received framing error - RXPARITY: received parity error -Warnings: This function will clear the high byte flags in the Channel - Status Register. -*/ -#define sGetChanStatus(ChP) sInW((ChP)->ChanStat) - -/*************************************************************************** -Function: sGetChanStatusLo -Purpose: Get the low byte only of the channel status -Call: sGetChanStatusLo(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The channel status low byte. Can be any combination - of the following flags: - CTS_ACT: CTS input asserted - DSR_ACT: DSR input asserted - CD_ACT: CD input asserted - TXFIFOMT: Tx FIFO is empty - TXSHRMT: Tx shift register is empty - RDA: Rx data available -*/ -#define sGetChanStatusLo(ChP) sInB((ByteIO_t)(ChP)->ChanStat) - -/********************************************************************** - * Get RI status of channel - * Defined as a function in rocket.c -aes - */ -#if 0 -#define sGetChanRI(ChP) ((ChP)->CtlP->AltChanRingIndicator ? \ - (sInB((ByteIO_t)((ChP)->ChanStat+8)) & DSR_ACT) : \ - (((ChP)->CtlP->boardType == ROCKET_TYPE_PC104) ? \ - (!(sInB((ChP)->CtlP->AiopIO[3]) & sBitMapSetTbl[(ChP)->ChanNum])) : \ - 0)) -#endif - -/*************************************************************************** -Function: sGetControllerIntStatus -Purpose: Get the controller interrupt status -Call: sGetControllerIntStatus(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -Return: Byte_t: The controller interrupt status in the lower 4 - bits. Bits 0 through 3 represent AIOP's 0 - through 3 respectively. If a bit is set that - AIOP is interrupting. Bits 4 through 7 will - always be cleared. -*/ -#define sGetControllerIntStatus(CTLP) (sInB((CTLP)->MReg1IO) & 0x0f) - -/*************************************************************************** -Function: sPCIGetControllerIntStatus -Purpose: Get the controller interrupt status -Call: sPCIGetControllerIntStatus(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -Return: unsigned char: The controller interrupt status in the lower 4 - bits and bit 4. Bits 0 through 3 represent AIOP's 0 - through 3 respectively. Bit 4 is set if the int - was generated from periodic. If a bit is set the - AIOP is interrupting. -*/ -#define sPCIGetControllerIntStatus(CTLP) \ - ((CTLP)->isUPCI ? \ - (sInW((CTLP)->PCIIO2) & UPCI_AIOP_INTR_BITS) : \ - ((sInW((CTLP)->PCIIO) >> 8) & AIOP_INTR_BITS)) - -/*************************************************************************** - -Function: sGetRxCnt -Purpose: Get the number of data bytes in the Rx FIFO -Call: sGetRxCnt(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: int: The number of data bytes in the Rx FIFO. -Comments: Byte read of count register is required to obtain Rx count. - -*/ -#define sGetRxCnt(ChP) sInW((ChP)->TxRxCount) - -/*************************************************************************** -Function: sGetTxCnt -Purpose: Get the number of data bytes in the Tx FIFO -Call: sGetTxCnt(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The number of data bytes in the Tx FIFO. -Comments: Byte read of count register is required to obtain Tx count. - -*/ -#define sGetTxCnt(ChP) sInB((ByteIO_t)(ChP)->TxRxCount) - -/***************************************************************************** -Function: sGetTxRxDataIO -Purpose: Get the I/O address of a channel's TxRx Data register -Call: sGetTxRxDataIO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: WordIO_t: I/O address of a channel's TxRx Data register -*/ -#define sGetTxRxDataIO(ChP) (ChP)->TxRxData - -/*************************************************************************** -Function: sInitChanDefaults -Purpose: Initialize a channel structure to it's default state. -Call: sInitChanDefaults(ChP) - CHANNEL_T *ChP; Ptr to the channel structure -Comments: This function must be called once for every channel structure - that exists before any other SSCI calls can be made. - -*/ -#define sInitChanDefaults(ChP) \ -do { \ - (ChP)->CtlP = NULLCTLPTR; \ - (ChP)->AiopNum = NULLAIOP; \ - (ChP)->ChanID = AIOPID_NULL; \ - (ChP)->ChanNum = NULLCHAN; \ -} while (0) - -/*************************************************************************** -Function: sResetAiopByNum -Purpose: Reset the AIOP by number -Call: sResetAiopByNum(CTLP,AIOPNUM) - CONTROLLER_T CTLP; Ptr to controller structure - AIOPNUM; AIOP index -*/ -#define sResetAiopByNum(CTLP,AIOPNUM) \ -do { \ - sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,RESET_ALL); \ - sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,0x0); \ -} while (0) - -/*************************************************************************** -Function: sSendBreak -Purpose: Send a transmit BREAK signal -Call: sSendBreak(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSendBreak(ChP) \ -do { \ - (ChP)->TxControl[3] |= SETBREAK; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetBaud -Purpose: Set baud rate -Call: sSetBaud(ChP,Divisor) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Divisor; 16 bit baud rate divisor for channel -*/ -#define sSetBaud(ChP,DIVISOR) \ -do { \ - (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ - (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ - out32((ChP)->IndexAddr,(ChP)->BaudDiv); \ -} while (0) - -/*************************************************************************** -Function: sSetData7 -Purpose: Set data bits to 7 -Call: sSetData7(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetData7(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~DATA8BIT; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetData8 -Purpose: Set data bits to 8 -Call: sSetData8(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetData8(ChP) \ -do { \ - (ChP)->TxControl[2] |= DATA8BIT; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetDTR -Purpose: Set the DTR output -Call: sSetDTR(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetDTR(ChP) \ -do { \ - (ChP)->TxControl[3] |= SET_DTR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetEvenParity -Purpose: Set even parity -Call: sSetEvenParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: This function has no effect unless parity is enabled with function - sEnParity(). -*/ -#define sSetEvenParity(ChP) \ -do { \ - (ChP)->TxControl[2] |= EVEN_PAR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetOddParity -Purpose: Set odd parity -Call: sSetOddParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: This function has no effect unless parity is enabled with function - sEnParity(). -*/ -#define sSetOddParity(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~EVEN_PAR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetRTS -Purpose: Set the RTS output -Call: sSetRTS(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetRTS(ChP) \ -do { \ - if ((ChP)->rtsToggle) break; \ - (ChP)->TxControl[3] |= SET_RTS; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetRxTrigger -Purpose: Set the Rx FIFO trigger level -Call: sSetRxProcessor(ChP,Level) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Level; Number of characters in Rx FIFO at which the - interrupt will be generated. Can be any of the following flags: - - TRIG_NO: no trigger - TRIG_1: 1 character in FIFO - TRIG_1_2: FIFO 1/2 full - TRIG_7_8: FIFO 7/8 full -Comments: An interrupt will be generated when the trigger level is reached - only if function sEnInterrupt() has been called with flag - RXINT_EN set. The RXF_TRIG flag in the Interrupt Idenfification - register will be set whenever the trigger level is reached - regardless of the setting of RXINT_EN. - -*/ -#define sSetRxTrigger(ChP,LEVEL) \ -do { \ - (ChP)->RxControl[2] &= ~TRIG_MASK; \ - (ChP)->RxControl[2] |= LEVEL; \ - out32((ChP)->IndexAddr,(ChP)->RxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetStop1 -Purpose: Set stop bits to 1 -Call: sSetStop1(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetStop1(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~STOP2; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetStop2 -Purpose: Set stop bits to 2 -Call: sSetStop2(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetStop2(ChP) \ -do { \ - (ChP)->TxControl[2] |= STOP2; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetTxXOFFChar -Purpose: Set the Tx XOFF flow control character -Call: sSetTxXOFFChar(ChP,Ch) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Ch; The value to set the Tx XOFF character to -*/ -#define sSetTxXOFFChar(ChP,CH) \ -do { \ - (ChP)->R[0x07] = (CH); \ - out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ -} while (0) - -/*************************************************************************** -Function: sSetTxXONChar -Purpose: Set the Tx XON flow control character -Call: sSetTxXONChar(ChP,Ch) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Ch; The value to set the Tx XON character to -*/ -#define sSetTxXONChar(ChP,CH) \ -do { \ - (ChP)->R[0x0b] = (CH); \ - out32((ChP)->IndexAddr,&(ChP)->R[0x08]); \ -} while (0) - -/*************************************************************************** -Function: sStartRxProcessor -Purpose: Start a channel's receive processor -Call: sStartRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function is used to start a Rx processor after it was - stopped with sStopRxProcessor() or sStopSWInFlowCtl(). It - will restart both the Rx processor and software input flow control. - -*/ -#define sStartRxProcessor(ChP) out32((ChP)->IndexAddr,&(ChP)->R[0]) - -/*************************************************************************** -Function: sWriteTxByte -Purpose: Write a transmit data byte to a channel. - ByteIO_t io: Channel transmit register I/O address. This can - be obtained with sGetTxRxDataIO(). - Byte_t Data; The transmit data byte. -Warnings: This function writes the data byte without checking to see if - sMaxTxSize is exceeded in the Tx FIFO. -*/ -#define sWriteTxByte(IO,DATA) sOutB(IO,DATA) - -/* - * Begin Linux specific definitions for the Rocketport driver - * - * This code is Copyright Theodore Ts'o, 1995-1997 - */ - -struct r_port { - int magic; - struct tty_port port; - int line; - int flags; /* Don't yet match the ASY_ flags!! */ - unsigned int board:3; - unsigned int aiop:2; - unsigned int chan:3; - CONTROLLER_t *ctlp; - CHANNEL_t channel; - int intmask; - int xmit_fifo_room; /* room in xmit fifo */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int cd_status; - int ignore_status_mask; - int read_status_mask; - int cps; - - spinlock_t slock; - struct mutex write_mtx; -}; - -#define RPORT_MAGIC 0x525001 - -#define NUM_BOARDS 8 -#define MAX_RP_PORTS (32*NUM_BOARDS) - -/* - * The size of the xmit buffer is 1 page, or 4096 bytes - */ -#define XMIT_BUF_SIZE 4096 - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* - * Assigned major numbers for the Comtrol Rocketport - */ -#define TTY_ROCKET_MAJOR 46 -#define CUA_ROCKET_MAJOR 47 - -#ifdef PCI_VENDOR_ID_RP -#undef PCI_VENDOR_ID_RP -#undef PCI_DEVICE_ID_RP8OCTA -#undef PCI_DEVICE_ID_RP8INTF -#undef PCI_DEVICE_ID_RP16INTF -#undef PCI_DEVICE_ID_RP32INTF -#undef PCI_DEVICE_ID_URP8OCTA -#undef PCI_DEVICE_ID_URP8INTF -#undef PCI_DEVICE_ID_URP16INTF -#undef PCI_DEVICE_ID_CRP16INTF -#undef PCI_DEVICE_ID_URP32INTF -#endif - -/* Comtrol PCI Vendor ID */ -#define PCI_VENDOR_ID_RP 0x11fe - -/* Comtrol Device ID's */ -#define PCI_DEVICE_ID_RP32INTF 0x0001 /* Rocketport 32 port w/external I/F */ -#define PCI_DEVICE_ID_RP8INTF 0x0002 /* Rocketport 8 port w/external I/F */ -#define PCI_DEVICE_ID_RP16INTF 0x0003 /* Rocketport 16 port w/external I/F */ -#define PCI_DEVICE_ID_RP4QUAD 0x0004 /* Rocketport 4 port w/quad cable */ -#define PCI_DEVICE_ID_RP8OCTA 0x0005 /* Rocketport 8 port w/octa cable */ -#define PCI_DEVICE_ID_RP8J 0x0006 /* Rocketport 8 port w/RJ11 connectors */ -#define PCI_DEVICE_ID_RP4J 0x0007 /* Rocketport 4 port w/RJ11 connectors */ -#define PCI_DEVICE_ID_RP8SNI 0x0008 /* Rocketport 8 port w/ DB78 SNI (Siemens) connector */ -#define PCI_DEVICE_ID_RP16SNI 0x0009 /* Rocketport 16 port w/ DB78 SNI (Siemens) connector */ -#define PCI_DEVICE_ID_RPP4 0x000A /* Rocketport Plus 4 port */ -#define PCI_DEVICE_ID_RPP8 0x000B /* Rocketport Plus 8 port */ -#define PCI_DEVICE_ID_RP6M 0x000C /* RocketModem 6 port */ -#define PCI_DEVICE_ID_RP4M 0x000D /* RocketModem 4 port */ -#define PCI_DEVICE_ID_RP2_232 0x000E /* Rocketport Plus 2 port RS232 */ -#define PCI_DEVICE_ID_RP2_422 0x000F /* Rocketport Plus 2 port RS422 */ - -/* Universal PCI boards */ -#define PCI_DEVICE_ID_URP32INTF 0x0801 /* Rocketport UPCI 32 port w/external I/F */ -#define PCI_DEVICE_ID_URP8INTF 0x0802 /* Rocketport UPCI 8 port w/external I/F */ -#define PCI_DEVICE_ID_URP16INTF 0x0803 /* Rocketport UPCI 16 port w/external I/F */ -#define PCI_DEVICE_ID_URP8OCTA 0x0805 /* Rocketport UPCI 8 port w/octa cable */ -#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C /* Rocketmodem III 8 port */ -#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D /* Rocketmodem III 4 port */ - -/* Compact PCI device */ -#define PCI_DEVICE_ID_CRP16INTF 0x0903 /* Rocketport Compact PCI 16 port w/external I/F */ - diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index c33e02cbde9303110a094f8d63523197e22f9d5d..61550f24a2d377e45e0a2a718c659b43eab9384c 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -28,6 +28,10 @@ #define ASPEED_VUART_ADDRL 0x28 #define ASPEED_VUART_ADDRH 0x2c +#define ASPEED_VUART_DEFAULT_LPC_ADDR 0x3f8 +#define ASPEED_VUART_DEFAULT_SIRQ 4 +#define ASPEED_VUART_DEFAULT_SIRQ_POLARITY IRQ_TYPE_LEVEL_LOW + struct aspeed_vuart { struct device *dev; void __iomem *regs; @@ -72,22 +76,31 @@ static ssize_t lpc_address_show(struct device *dev, return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr); } +static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr) +{ + if (addr > U16_MAX) + return -EINVAL; + + writeb(addr >> 8, vuart->regs + ASPEED_VUART_ADDRH); + writeb(addr >> 0, vuart->regs + ASPEED_VUART_ADDRL); + + return 0; +} + static ssize_t lpc_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aspeed_vuart *vuart = dev_get_drvdata(dev); - unsigned long val; + u32 val; int err; - err = kstrtoul(buf, 0, &val); + err = kstrtou32(buf, 0, &val); if (err) return err; - writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH); - writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL); - - return count; + err = aspeed_vuart_set_lpc_address(vuart, val); + return err ? : count; } static DEVICE_ATTR_RW(lpc_address); @@ -105,27 +118,37 @@ static ssize_t sirq_show(struct device *dev, return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg); } +static int aspeed_vuart_set_sirq(struct aspeed_vuart *vuart, u32 sirq) +{ + u8 reg; + + if (sirq > (ASPEED_VUART_GCRB_HOST_SIRQ_MASK >> ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT)) + return -EINVAL; + + sirq <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; + sirq &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; + + reg = readb(vuart->regs + ASPEED_VUART_GCRB); + reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK; + reg |= sirq; + writeb(reg, vuart->regs + ASPEED_VUART_GCRB); + + return 0; +} + static ssize_t sirq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aspeed_vuart *vuart = dev_get_drvdata(dev); unsigned long val; int err; - u8 reg; err = kstrtoul(buf, 0, &val); if (err) return err; - val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; - val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; - - reg = readb(vuart->regs + ASPEED_VUART_GCRB); - reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK; - reg |= val; - writeb(reg, vuart->regs + ASPEED_VUART_GCRB); - - return count; + err = aspeed_vuart_set_sirq(vuart, val); + return err ? : count; } static DEVICE_ATTR_RW(sirq); @@ -297,7 +320,6 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir, lsr; - unsigned long flags; int space, count; iir = serial_port_in(port, UART_IIR); @@ -305,7 +327,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) if (iir & UART_IIR_NO_INT) return 0; - spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->lock); lsr = serial_port_in(port, UART_LSR); @@ -341,7 +363,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); - uart_unlock_and_check_sysrq(port, flags); + uart_unlock_and_check_sysrq(port); return 1; } @@ -367,6 +389,18 @@ static void aspeed_vuart_auto_configure_sirq_polarity( aspeed_vuart_set_sirq_polarity(vuart, (value & reg_mask) == 0); } +static int aspeed_vuart_map_irq_polarity(u32 dt) +{ + switch (dt) { + case IRQ_TYPE_LEVEL_LOW: + return 0; + case IRQ_TYPE_LEVEL_HIGH: + return 1; + default: + return -EINVAL; + } +} + static int aspeed_vuart_probe(struct platform_device *pdev) { struct of_phandle_args sirq_polarity_sense_args; @@ -374,8 +408,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev) struct aspeed_vuart *vuart; struct device_node *np; struct resource *res; - u32 clk, prop; - int rc; + u32 clk, prop, sirq[2]; + int rc, sirq_polarity; np = pdev->dev.of_node; @@ -482,6 +516,37 @@ static int aspeed_vuart_probe(struct platform_device *pdev) of_node_put(sirq_polarity_sense_args.np); } + rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &prop); + if (rc < 0) + prop = ASPEED_VUART_DEFAULT_LPC_ADDR; + + rc = aspeed_vuart_set_lpc_address(vuart, prop); + if (rc < 0) { + dev_err(&pdev->dev, "invalid value in aspeed,lpc-io-reg property\n"); + goto err_clk_disable; + } + + rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2); + if (rc < 0) { + sirq[0] = ASPEED_VUART_DEFAULT_SIRQ; + sirq[1] = ASPEED_VUART_DEFAULT_SIRQ_POLARITY; + } + + rc = aspeed_vuart_set_sirq(vuart, sirq[0]); + if (rc < 0) { + dev_err(&pdev->dev, "invalid sirq number in aspeed,lpc-interrupts property\n"); + goto err_clk_disable; + } + + sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]); + if (sirq_polarity < 0) { + dev_err(&pdev->dev, "invalid sirq polarity in aspeed,lpc-interrupts property\n"); + rc = sirq_polarity; + goto err_clk_disable; + } + + aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity); + aspeed_vuart_set_enabled(vuart, true); aspeed_vuart_set_host_tx_discard(vuart, true); platform_set_drvdata(pdev, vuart); diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c new file mode 100644 index 0000000000000000000000000000000000000000..725a450058f88d56a22f1189877ede39cccfb239 --- /dev/null +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -0,0 +1,1202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2020, Broadcom */ +/* + * 8250-core based driver for Broadcom ns16550a UARTs + * + * This driver uses the standard 8250 driver core but adds additional + * optional features including the ability to use a baud rate clock + * mux for more accurate high speed baud rate selection and also + * an optional DMA engine. + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/dma-mapping.h> +#include <linux/tty_flip.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/debugfs.h> + +#include "8250.h" + +/* Register definitions for UART DMA block. Version 1.1 or later. */ +#define UDMA_ARB_RX 0x00 +#define UDMA_ARB_TX 0x04 +#define UDMA_ARB_REQ 0x00000001 +#define UDMA_ARB_GRANT 0x00000002 + +#define UDMA_RX_REVISION 0x00 +#define UDMA_RX_REVISION_REQUIRED 0x00000101 +#define UDMA_RX_CTRL 0x04 +#define UDMA_RX_CTRL_BUF_CLOSE_MODE 0x00010000 +#define UDMA_RX_CTRL_MASK_WR_DONE 0x00008000 +#define UDMA_RX_CTRL_ENDIAN_OVERRIDE 0x00004000 +#define UDMA_RX_CTRL_ENDIAN 0x00002000 +#define UDMA_RX_CTRL_OE_IS_ERR 0x00001000 +#define UDMA_RX_CTRL_PE_IS_ERR 0x00000800 +#define UDMA_RX_CTRL_FE_IS_ERR 0x00000400 +#define UDMA_RX_CTRL_NUM_BUF_USED_MASK 0x000003c0 +#define UDMA_RX_CTRL_NUM_BUF_USED_SHIFT 6 +#define UDMA_RX_CTRL_BUF_CLOSE_CLK_SEL_SYS 0x00000020 +#define UDMA_RX_CTRL_BUF_CLOSE_ENA 0x00000010 +#define UDMA_RX_CTRL_TIMEOUT_CLK_SEL_SYS 0x00000008 +#define UDMA_RX_CTRL_TIMEOUT_ENA 0x00000004 +#define UDMA_RX_CTRL_ABORT 0x00000002 +#define UDMA_RX_CTRL_ENA 0x00000001 +#define UDMA_RX_STATUS 0x08 +#define UDMA_RX_STATUS_ACTIVE_BUF_MASK 0x0000000f +#define UDMA_RX_TRANSFER_LEN 0x0c +#define UDMA_RX_TRANSFER_TOTAL 0x10 +#define UDMA_RX_BUFFER_SIZE 0x14 +#define UDMA_RX_SRC_ADDR 0x18 +#define UDMA_RX_TIMEOUT 0x1c +#define UDMA_RX_BUFFER_CLOSE 0x20 +#define UDMA_RX_BLOCKOUT_COUNTER 0x24 +#define UDMA_RX_BUF0_PTR_LO 0x28 +#define UDMA_RX_BUF0_PTR_HI 0x2c +#define UDMA_RX_BUF0_STATUS 0x30 +#define UDMA_RX_BUFX_STATUS_OVERRUN_ERR 0x00000010 +#define UDMA_RX_BUFX_STATUS_FRAME_ERR 0x00000008 +#define UDMA_RX_BUFX_STATUS_PARITY_ERR 0x00000004 +#define UDMA_RX_BUFX_STATUS_CLOSE_EXPIRED 0x00000002 +#define UDMA_RX_BUFX_STATUS_DATA_RDY 0x00000001 +#define UDMA_RX_BUF0_DATA_LEN 0x34 +#define UDMA_RX_BUF1_PTR_LO 0x38 +#define UDMA_RX_BUF1_PTR_HI 0x3c +#define UDMA_RX_BUF1_STATUS 0x40 +#define UDMA_RX_BUF1_DATA_LEN 0x44 + +#define UDMA_TX_REVISION 0x00 +#define UDMA_TX_REVISION_REQUIRED 0x00000101 +#define UDMA_TX_CTRL 0x04 +#define UDMA_TX_CTRL_ENDIAN_OVERRIDE 0x00000080 +#define UDMA_TX_CTRL_ENDIAN 0x00000040 +#define UDMA_TX_CTRL_NUM_BUF_USED_MASK 0x00000030 +#define UDMA_TX_CTRL_NUM_BUF_USED_1 0x00000010 +#define UDMA_TX_CTRL_ABORT 0x00000002 +#define UDMA_TX_CTRL_ENA 0x00000001 +#define UDMA_TX_DST_ADDR 0x08 +#define UDMA_TX_BLOCKOUT_COUNTER 0x10 +#define UDMA_TX_TRANSFER_LEN 0x14 +#define UDMA_TX_TRANSFER_TOTAL 0x18 +#define UDMA_TX_STATUS 0x20 +#define UDMA_TX_BUF0_PTR_LO 0x24 +#define UDMA_TX_BUF0_PTR_HI 0x28 +#define UDMA_TX_BUF0_STATUS 0x2c +#define UDMA_TX_BUFX_LAST 0x00000002 +#define UDMA_TX_BUFX_EMPTY 0x00000001 +#define UDMA_TX_BUF0_DATA_LEN 0x30 +#define UDMA_TX_BUF0_DATA_SENT 0x34 +#define UDMA_TX_BUF1_PTR_LO 0x38 + +#define UDMA_INTR_STATUS 0x00 +#define UDMA_INTR_ARB_TX_GRANT 0x00040000 +#define UDMA_INTR_ARB_RX_GRANT 0x00020000 +#define UDMA_INTR_TX_ALL_EMPTY 0x00010000 +#define UDMA_INTR_TX_EMPTY_BUF1 0x00008000 +#define UDMA_INTR_TX_EMPTY_BUF0 0x00004000 +#define UDMA_INTR_TX_ABORT 0x00002000 +#define UDMA_INTR_TX_DONE 0x00001000 +#define UDMA_INTR_RX_ERROR 0x00000800 +#define UDMA_INTR_RX_TIMEOUT 0x00000400 +#define UDMA_INTR_RX_READY_BUF7 0x00000200 +#define UDMA_INTR_RX_READY_BUF6 0x00000100 +#define UDMA_INTR_RX_READY_BUF5 0x00000080 +#define UDMA_INTR_RX_READY_BUF4 0x00000040 +#define UDMA_INTR_RX_READY_BUF3 0x00000020 +#define UDMA_INTR_RX_READY_BUF2 0x00000010 +#define UDMA_INTR_RX_READY_BUF1 0x00000008 +#define UDMA_INTR_RX_READY_BUF0 0x00000004 +#define UDMA_INTR_RX_READY_MASK 0x000003fc +#define UDMA_INTR_RX_READY_SHIFT 2 +#define UDMA_INTR_RX_ABORT 0x00000002 +#define UDMA_INTR_RX_DONE 0x00000001 +#define UDMA_INTR_SET 0x04 +#define UDMA_INTR_CLEAR 0x08 +#define UDMA_INTR_MASK_STATUS 0x0c +#define UDMA_INTR_MASK_SET 0x10 +#define UDMA_INTR_MASK_CLEAR 0x14 + + +#define UDMA_RX_INTERRUPTS ( \ + UDMA_INTR_RX_ERROR | \ + UDMA_INTR_RX_TIMEOUT | \ + UDMA_INTR_RX_READY_BUF0 | \ + UDMA_INTR_RX_READY_BUF1 | \ + UDMA_INTR_RX_READY_BUF2 | \ + UDMA_INTR_RX_READY_BUF3 | \ + UDMA_INTR_RX_READY_BUF4 | \ + UDMA_INTR_RX_READY_BUF5 | \ + UDMA_INTR_RX_READY_BUF6 | \ + UDMA_INTR_RX_READY_BUF7 | \ + UDMA_INTR_RX_ABORT | \ + UDMA_INTR_RX_DONE) + +#define UDMA_RX_ERR_INTERRUPTS ( \ + UDMA_INTR_RX_ERROR | \ + UDMA_INTR_RX_TIMEOUT | \ + UDMA_INTR_RX_ABORT | \ + UDMA_INTR_RX_DONE) + +#define UDMA_TX_INTERRUPTS ( \ + UDMA_INTR_TX_ABORT | \ + UDMA_INTR_TX_DONE) + +#define UDMA_IS_RX_INTERRUPT(status) ((status) & UDMA_RX_INTERRUPTS) +#define UDMA_IS_TX_INTERRUPT(status) ((status) & UDMA_TX_INTERRUPTS) + + +/* Current devices have 8 sets of RX buffer registers */ +#define UDMA_RX_BUFS_COUNT 8 +#define UDMA_RX_BUFS_REG_OFFSET (UDMA_RX_BUF1_PTR_LO - UDMA_RX_BUF0_PTR_LO) +#define UDMA_RX_BUFx_PTR_LO(x) (UDMA_RX_BUF0_PTR_LO + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_PTR_HI(x) (UDMA_RX_BUF0_PTR_HI + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_STATUS(x) (UDMA_RX_BUF0_STATUS + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_DATA_LEN(x) (UDMA_RX_BUF0_DATA_LEN + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) + +/* Current devices have 2 sets of TX buffer registers */ +#define UDMA_TX_BUFS_COUNT 2 +#define UDMA_TX_BUFS_REG_OFFSET (UDMA_TX_BUF1_PTR_LO - UDMA_TX_BUF0_PTR_LO) +#define UDMA_TX_BUFx_PTR_LO(x) (UDMA_TX_BUF0_PTR_LO + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_PTR_HI(x) (UDMA_TX_BUF0_PTR_HI + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_STATUS(x) (UDMA_TX_BUF0_STATUS + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_DATA_LEN(x) (UDMA_TX_BUF0_DATA_LEN + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_DATA_SENT(x) (UDMA_TX_BUF0_DATA_SENT + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define REGS_8250 0 +#define REGS_DMA_RX 1 +#define REGS_DMA_TX 2 +#define REGS_DMA_ISR 3 +#define REGS_DMA_ARB 4 +#define REGS_MAX 5 + +#define TX_BUF_SIZE 4096 +#define RX_BUF_SIZE 4096 +#define RX_BUFS_COUNT 2 +#define KHZ 1000 +#define MHZ(x) ((x) * KHZ * KHZ) + +static const u32 brcmstb_rate_table[] = { + MHZ(81), + MHZ(108), + MHZ(64), /* Actually 64285715 for some chips */ + MHZ(48), +}; + +static const u32 brcmstb_rate_table_7278[] = { + MHZ(81), + MHZ(108), + 0, + MHZ(48), +}; + +struct brcmuart_priv { + int line; + struct clk *baud_mux_clk; + unsigned long default_mux_rate; + u32 real_rates[ARRAY_SIZE(brcmstb_rate_table)]; + const u32 *rate_table; + ktime_t char_wait; + struct uart_port *up; + struct hrtimer hrt; + bool shutdown; + bool dma_enabled; + struct uart_8250_dma dma; + void __iomem *regs[REGS_MAX]; + dma_addr_t rx_addr; + void *rx_bufs; + size_t rx_size; + int rx_next_buf; + dma_addr_t tx_addr; + void *tx_buf; + size_t tx_size; + bool tx_running; + bool rx_running; + struct dentry *debugfs_dir; + + /* stats exposed through debugfs */ + u64 dma_rx_partial_buf; + u64 dma_rx_full_buf; + u32 rx_bad_timeout_late_char; + u32 rx_bad_timeout_no_char; + u32 rx_missing_close_timeout; + u32 rx_err; + u32 rx_timeout; + u32 rx_abort; +}; + +static struct dentry *brcmuart_debugfs_root; + +/* + * Register access routines + */ +static u32 udma_readl(struct brcmuart_priv *priv, + int reg_type, int offset) +{ + return readl(priv->regs[reg_type] + offset); +} + +static void udma_writel(struct brcmuart_priv *priv, + int reg_type, int offset, u32 value) +{ + writel(value, priv->regs[reg_type] + offset); +} + +static void udma_set(struct brcmuart_priv *priv, + int reg_type, int offset, u32 bits) +{ + void __iomem *reg = priv->regs[reg_type] + offset; + u32 value; + + value = readl(reg); + value |= bits; + writel(value, reg); +} + +static void udma_unset(struct brcmuart_priv *priv, + int reg_type, int offset, u32 bits) +{ + void __iomem *reg = priv->regs[reg_type] + offset; + u32 value; + + value = readl(reg); + value &= ~bits; + writel(value, reg); +} + +/* + * The UART DMA engine hardware can be used by multiple UARTS, but + * only one at a time. Sharing is not currently supported so + * the first UART to request the DMA engine will get it and any + * subsequent requests by other UARTS will fail. + */ +static int brcmuart_arbitration(struct brcmuart_priv *priv, bool acquire) +{ + u32 rx_grant; + u32 tx_grant; + int waits; + int ret = 0; + + if (acquire) { + udma_set(priv, REGS_DMA_ARB, UDMA_ARB_RX, UDMA_ARB_REQ); + udma_set(priv, REGS_DMA_ARB, UDMA_ARB_TX, UDMA_ARB_REQ); + + waits = 1; + while (1) { + rx_grant = udma_readl(priv, REGS_DMA_ARB, UDMA_ARB_RX); + tx_grant = udma_readl(priv, REGS_DMA_ARB, UDMA_ARB_TX); + if (rx_grant & tx_grant & UDMA_ARB_GRANT) + return 0; + if (waits-- == 0) + break; + msleep(1); + } + ret = 1; + } + + udma_unset(priv, REGS_DMA_ARB, UDMA_ARB_RX, UDMA_ARB_REQ); + udma_unset(priv, REGS_DMA_ARB, UDMA_ARB_TX, UDMA_ARB_REQ); + return ret; +} + +static void brcmuart_init_dma_hardware(struct brcmuart_priv *priv) +{ + u32 daddr; + u32 value; + int x; + + /* Start with all interrupts disabled */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_SET, 0xffffffff); + + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFFER_SIZE, RX_BUF_SIZE); + + /* + * Setup buffer close to happen when 32 character times have + * elapsed since the last character was received. + */ + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFFER_CLOSE, 16*10*32); + value = (RX_BUFS_COUNT << UDMA_RX_CTRL_NUM_BUF_USED_SHIFT) + | UDMA_RX_CTRL_BUF_CLOSE_MODE + | UDMA_RX_CTRL_BUF_CLOSE_ENA; + udma_writel(priv, REGS_DMA_RX, UDMA_RX_CTRL, value); + + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BLOCKOUT_COUNTER, 0); + daddr = priv->rx_addr; + for (x = 0; x < RX_BUFS_COUNT; x++) { + + /* Set RX transfer length to 0 for unknown */ + udma_writel(priv, REGS_DMA_RX, UDMA_RX_TRANSFER_LEN, 0); + + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFx_PTR_LO(x), + lower_32_bits(daddr)); + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFx_PTR_HI(x), + upper_32_bits(daddr)); + daddr += RX_BUF_SIZE; + } + + daddr = priv->tx_addr; + udma_writel(priv, REGS_DMA_TX, UDMA_TX_BUFx_PTR_LO(0), + lower_32_bits(daddr)); + udma_writel(priv, REGS_DMA_TX, UDMA_TX_BUFx_PTR_HI(0), + upper_32_bits(daddr)); + udma_writel(priv, REGS_DMA_TX, UDMA_TX_CTRL, + UDMA_TX_CTRL_NUM_BUF_USED_1); + + /* clear all interrupts then enable them */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_CLEAR, 0xffffffff); + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_CLEAR, + UDMA_RX_INTERRUPTS | UDMA_TX_INTERRUPTS); + +} + +static void start_rx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + int x; + + udma_unset(priv, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ENA); + + /* Clear the RX ready bit for all buffers */ + for (x = 0; x < RX_BUFS_COUNT; x++) + udma_unset(priv, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(x), + UDMA_RX_BUFX_STATUS_DATA_RDY); + + /* always start with buffer 0 */ + udma_unset(priv, REGS_DMA_RX, UDMA_RX_STATUS, + UDMA_RX_STATUS_ACTIVE_BUF_MASK); + priv->rx_next_buf = 0; + + udma_set(priv, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ENA); + priv->rx_running = true; +} + +static void stop_rx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + + /* If RX is running, set the RX ABORT */ + if (priv->rx_running) + udma_set(priv, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ABORT); +} + +static int stop_tx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + u32 value; + + /* If TX is running, set the TX ABORT */ + value = udma_readl(priv, REGS_DMA_TX, UDMA_TX_CTRL); + if (value & UDMA_TX_CTRL_ENA) + udma_set(priv, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ABORT); + priv->tx_running = false; + return 0; +} + +/* + * NOTE: printk's in this routine will hang the system if this is + * the console tty + */ +static int brcmuart_tx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + struct circ_buf *xmit = &p->port.state->xmit; + u32 tx_size; + + if (uart_tx_stopped(&p->port) || priv->tx_running || + uart_circ_empty(xmit)) { + return 0; + } + tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + + priv->dma.tx_err = 0; + memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size); + xmit->tail += tx_size; + xmit->tail &= UART_XMIT_SIZE - 1; + p->port.icount.tx += tx_size; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&p->port); + + udma_writel(priv, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, tx_size); + udma_writel(priv, REGS_DMA_TX, UDMA_TX_BUF0_DATA_LEN, tx_size); + udma_unset(priv, REGS_DMA_TX, UDMA_TX_BUF0_STATUS, UDMA_TX_BUFX_EMPTY); + udma_set(priv, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ENA); + priv->tx_running = true; + + return 0; +} + +static void brcmuart_rx_buf_done_isr(struct uart_port *up, int index) +{ + struct brcmuart_priv *priv = up->private_data; + struct tty_port *tty_port = &up->state->port; + u32 status; + u32 length; + u32 copied; + + /* Make sure we're still in sync with the hardware */ + status = udma_readl(priv, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(index)); + length = udma_readl(priv, REGS_DMA_RX, UDMA_RX_BUFx_DATA_LEN(index)); + + if ((status & UDMA_RX_BUFX_STATUS_DATA_RDY) == 0) { + dev_err(up->dev, "RX done interrupt but DATA_RDY not found\n"); + return; + } + if (status & (UDMA_RX_BUFX_STATUS_OVERRUN_ERR | + UDMA_RX_BUFX_STATUS_FRAME_ERR | + UDMA_RX_BUFX_STATUS_PARITY_ERR)) { + if (status & UDMA_RX_BUFX_STATUS_OVERRUN_ERR) { + up->icount.overrun++; + dev_warn(up->dev, "RX OVERRUN Error\n"); + } + if (status & UDMA_RX_BUFX_STATUS_FRAME_ERR) { + up->icount.frame++; + dev_warn(up->dev, "RX FRAMING Error\n"); + } + if (status & UDMA_RX_BUFX_STATUS_PARITY_ERR) { + up->icount.parity++; + dev_warn(up->dev, "RX PARITY Error\n"); + } + } + copied = (u32)tty_insert_flip_string( + tty_port, + priv->rx_bufs + (index * RX_BUF_SIZE), + length); + if (copied != length) { + dev_warn(up->dev, "Flip buffer overrun of %d bytes\n", + length - copied); + up->icount.overrun += length - copied; + } + up->icount.rx += length; + if (status & UDMA_RX_BUFX_STATUS_CLOSE_EXPIRED) + priv->dma_rx_partial_buf++; + else if (length != RX_BUF_SIZE) + /* + * This is a bug in the controller that doesn't cause + * any problems but will be fixed in the future. + */ + priv->rx_missing_close_timeout++; + else + priv->dma_rx_full_buf++; + + tty_flip_buffer_push(tty_port); +} + +static void brcmuart_rx_isr(struct uart_port *up, u32 rx_isr) +{ + struct brcmuart_priv *priv = up->private_data; + struct device *dev = up->dev; + u32 rx_done_isr; + u32 check_isr; + + rx_done_isr = (rx_isr & UDMA_INTR_RX_READY_MASK); + while (rx_done_isr) { + check_isr = UDMA_INTR_RX_READY_BUF0 << priv->rx_next_buf; + if (check_isr & rx_done_isr) { + brcmuart_rx_buf_done_isr(up, priv->rx_next_buf); + } else { + dev_err(dev, + "RX buffer ready out of sequence, restarting RX DMA\n"); + start_rx_dma(up_to_u8250p(up)); + break; + } + if (rx_isr & UDMA_RX_ERR_INTERRUPTS) { + if (rx_isr & UDMA_INTR_RX_ERROR) + priv->rx_err++; + if (rx_isr & UDMA_INTR_RX_TIMEOUT) { + priv->rx_timeout++; + dev_err(dev, "RX TIMEOUT Error\n"); + } + if (rx_isr & UDMA_INTR_RX_ABORT) + priv->rx_abort++; + priv->rx_running = false; + } + /* If not ABORT, re-enable RX buffer */ + if (!(rx_isr & UDMA_INTR_RX_ABORT)) + udma_unset(priv, REGS_DMA_RX, + UDMA_RX_BUFx_STATUS(priv->rx_next_buf), + UDMA_RX_BUFX_STATUS_DATA_RDY); + rx_done_isr &= ~check_isr; + priv->rx_next_buf++; + if (priv->rx_next_buf == RX_BUFS_COUNT) + priv->rx_next_buf = 0; + } +} + +static void brcmuart_tx_isr(struct uart_port *up, u32 isr) +{ + struct brcmuart_priv *priv = up->private_data; + struct device *dev = up->dev; + struct uart_8250_port *port_8250 = up_to_u8250p(up); + struct circ_buf *xmit = &port_8250->port.state->xmit; + + if (isr & UDMA_INTR_TX_ABORT) { + if (priv->tx_running) + dev_err(dev, "Unexpected TX_ABORT interrupt\n"); + return; + } + priv->tx_running = false; + if (!uart_circ_empty(xmit) && !uart_tx_stopped(up)) + brcmuart_tx_dma(port_8250); +} + +static irqreturn_t brcmuart_isr(int irq, void *dev_id) +{ + struct uart_port *up = dev_id; + struct device *dev = up->dev; + struct brcmuart_priv *priv = up->private_data; + unsigned long flags; + u32 interrupts; + u32 rval; + u32 tval; + + interrupts = udma_readl(priv, REGS_DMA_ISR, UDMA_INTR_STATUS); + if (interrupts == 0) + return IRQ_NONE; + + spin_lock_irqsave(&up->lock, flags); + + /* Clear all interrupts */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_CLEAR, interrupts); + + rval = UDMA_IS_RX_INTERRUPT(interrupts); + if (rval) + brcmuart_rx_isr(up, rval); + tval = UDMA_IS_TX_INTERRUPT(interrupts); + if (tval) + brcmuart_tx_isr(up, tval); + if ((rval | tval) == 0) + dev_warn(dev, "Spurious interrupt: 0x%x\n", interrupts); + + spin_unlock_irqrestore(&up->lock, flags); + return IRQ_HANDLED; +} + +static int brcmuart_startup(struct uart_port *port) +{ + int res; + struct uart_8250_port *up = up_to_u8250p(port); + struct brcmuart_priv *priv = up->port.private_data; + + priv->shutdown = false; + + /* + * prevent serial8250_do_startup() from allocating non-existent + * DMA resources + */ + up->dma = NULL; + + res = serial8250_do_startup(port); + if (!priv->dma_enabled) + return res; + /* + * Disable the Receive Data Interrupt because the DMA engine + * will handle this. + */ + up->ier &= ~UART_IER_RDI; + serial_port_out(port, UART_IER, up->ier); + + priv->tx_running = false; + priv->dma.rx_dma = NULL; + priv->dma.tx_dma = brcmuart_tx_dma; + up->dma = &priv->dma; + + brcmuart_init_dma_hardware(priv); + start_rx_dma(up); + return res; +} + +static void brcmuart_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + struct brcmuart_priv *priv = up->port.private_data; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + priv->shutdown = true; + if (priv->dma_enabled) { + stop_rx_dma(up); + stop_tx_dma(up); + /* disable all interrupts */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_SET, + UDMA_RX_INTERRUPTS | UDMA_TX_INTERRUPTS); + } + + /* + * prevent serial8250_do_shutdown() from trying to free + * DMA resources that we never alloc'd for this driver. + */ + up->dma = NULL; + + spin_unlock_irqrestore(&port->lock, flags); + serial8250_do_shutdown(port); +} + +/* + * Not all clocks run at the exact specified rate, so set each requested + * rate and then get the actual rate. + */ +static void init_real_clk_rates(struct device *dev, struct brcmuart_priv *priv) +{ + int x; + int rc; + + priv->default_mux_rate = clk_get_rate(priv->baud_mux_clk); + for (x = 0; x < ARRAY_SIZE(priv->real_rates); x++) { + if (priv->rate_table[x] == 0) { + priv->real_rates[x] = 0; + continue; + } + rc = clk_set_rate(priv->baud_mux_clk, priv->rate_table[x]); + if (rc) { + dev_err(dev, "Error selecting BAUD MUX clock for %u\n", + priv->rate_table[x]); + priv->real_rates[x] = priv->rate_table[x]; + } else { + priv->real_rates[x] = clk_get_rate(priv->baud_mux_clk); + } + } + clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate); +} + +static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, + u32 baud) +{ + u32 percent; + u32 best_percent = UINT_MAX; + u32 quot; + u32 best_quot = 1; + u32 rate; + int best_index = -1; + u64 hires_rate; + u64 hires_baud; + u64 hires_err; + int rc; + int i; + int real_baud; + + /* If the Baud Mux Clock was not specified, just return */ + if (priv->baud_mux_clk == NULL) + return; + + /* Find the closest match for specified baud */ + for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) { + if (priv->real_rates[i] == 0) + continue; + rate = priv->real_rates[i] / 16; + quot = DIV_ROUND_CLOSEST(rate, baud); + if (!quot) + continue; + + /* increase resolution to get xx.xx percent */ + hires_rate = (u64)rate * 10000; + hires_baud = (u64)baud * 10000; + + hires_err = div_u64(hires_rate, (u64)quot); + + /* get the delta */ + if (hires_err > hires_baud) + hires_err = (hires_err - hires_baud); + else + hires_err = (hires_baud - hires_err); + + percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud); + dev_dbg(up->dev, + "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n", + baud, priv->real_rates[i], percent / 100, + percent % 100); + if (percent < best_percent) { + best_percent = percent; + best_index = i; + best_quot = quot; + } + } + if (best_index == -1) { + dev_err(up->dev, "Error, %d BAUD rate is too fast.\n", baud); + return; + } + rate = priv->real_rates[best_index]; + rc = clk_set_rate(priv->baud_mux_clk, rate); + if (rc) + dev_err(up->dev, "Error selecting BAUD MUX clock\n"); + + /* Error over 3 percent will cause data errors */ + if (best_percent > 300) + dev_err(up->dev, "Error, baud: %d has %u.%u%% error\n", + baud, percent / 100, percent % 100); + + real_baud = rate / 16 / best_quot; + dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", rate); + dev_dbg(up->dev, "Requested baud: %u, Actual baud: %u\n", + baud, real_baud); + + /* calc nanoseconds for 1.5 characters time at the given baud rate */ + i = NSEC_PER_SEC / real_baud / 10; + i += (i / 2); + priv->char_wait = ns_to_ktime(i); + + up->uartclk = rate; +} + +static void brcmstb_set_termios(struct uart_port *up, + struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *p8250 = up_to_u8250p(up); + struct brcmuart_priv *priv = up->private_data; + + if (priv->dma_enabled) + stop_rx_dma(p8250); + set_clock_mux(up, priv, tty_termios_baud_rate(termios)); + serial8250_do_set_termios(up, termios, old); + if (p8250->mcr & UART_MCR_AFE) + p8250->port.status |= UPSTAT_AUTOCTS; + if (priv->dma_enabled) + start_rx_dma(p8250); +} + +static int brcmuart_handle_irq(struct uart_port *p) +{ + unsigned int iir = serial_port_in(p, UART_IIR); + struct brcmuart_priv *priv = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); + unsigned int status; + unsigned long flags; + unsigned int ier; + unsigned int mcr; + int handled = 0; + + /* + * There's a bug in some 8250 cores where we get a timeout + * interrupt but there is no data ready. + */ + if (((iir & UART_IIR_ID) == UART_IIR_RX_TIMEOUT) && !(priv->shutdown)) { + spin_lock_irqsave(&p->lock, flags); + status = serial_port_in(p, UART_LSR); + if ((status & UART_LSR_DR) == 0) { + + ier = serial_port_in(p, UART_IER); + /* + * if Receive Data Interrupt is enabled and + * we're uing hardware flow control, deassert + * RTS and wait for any chars in the pipline to + * arrive and then check for DR again. + */ + if ((ier & UART_IER_RDI) && (up->mcr & UART_MCR_AFE)) { + ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_port_out(p, UART_IER, ier); + mcr = serial_port_in(p, UART_MCR); + mcr &= ~UART_MCR_RTS; + serial_port_out(p, UART_MCR, mcr); + hrtimer_start(&priv->hrt, priv->char_wait, + HRTIMER_MODE_REL); + } else { + serial_port_in(p, UART_RX); + } + + handled = 1; + } + spin_unlock_irqrestore(&p->lock, flags); + if (handled) + return 1; + } + return serial8250_handle_irq(p, iir); +} + +static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) +{ + struct brcmuart_priv *priv = container_of(t, struct brcmuart_priv, hrt); + struct uart_port *p = priv->up; + struct uart_8250_port *up = up_to_u8250p(p); + unsigned int status; + unsigned long flags; + + if (priv->shutdown) + return HRTIMER_NORESTART; + + spin_lock_irqsave(&p->lock, flags); + status = serial_port_in(p, UART_LSR); + + /* + * If a character did not arrive after the timeout, clear the false + * receive timeout. + */ + if ((status & UART_LSR_DR) == 0) { + serial_port_in(p, UART_RX); + priv->rx_bad_timeout_no_char++; + } else { + priv->rx_bad_timeout_late_char++; + } + + /* re-enable receive unless upper layer has disabled it */ + if ((up->ier & (UART_IER_RLSI | UART_IER_RDI)) == + (UART_IER_RLSI | UART_IER_RDI)) { + status = serial_port_in(p, UART_IER); + status |= (UART_IER_RLSI | UART_IER_RDI); + serial_port_out(p, UART_IER, status); + status = serial_port_in(p, UART_MCR); + status |= UART_MCR_RTS; + serial_port_out(p, UART_MCR, status); + } + spin_unlock_irqrestore(&p->lock, flags); + return HRTIMER_NORESTART; +} + +static const struct of_device_id brcmuart_dt_ids[] = { + { + .compatible = "brcm,bcm7278-uart", + .data = brcmstb_rate_table_7278, + }, + { + .compatible = "brcm,bcm7271-uart", + .data = brcmstb_rate_table, + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, brcmuart_dt_ids); + +static void brcmuart_free_bufs(struct device *dev, struct brcmuart_priv *priv) +{ + if (priv->rx_bufs) + dma_free_coherent(dev, priv->rx_size, priv->rx_bufs, + priv->rx_addr); + if (priv->tx_buf) + dma_free_coherent(dev, priv->tx_size, priv->tx_buf, + priv->tx_addr); +} + +static void brcmuart_throttle(struct uart_port *port) +{ + struct brcmuart_priv *priv = port->private_data; + + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_SET, UDMA_RX_INTERRUPTS); +} + +static void brcmuart_unthrottle(struct uart_port *port) +{ + struct brcmuart_priv *priv = port->private_data; + + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_CLEAR, + UDMA_RX_INTERRUPTS); +} + +static int debugfs_stats_show(struct seq_file *s, void *unused) +{ + struct brcmuart_priv *priv = s->private; + + seq_printf(s, "rx_err:\t\t\t\t%u\n", + priv->rx_err); + seq_printf(s, "rx_timeout:\t\t\t%u\n", + priv->rx_timeout); + seq_printf(s, "rx_abort:\t\t\t%u\n", + priv->rx_abort); + seq_printf(s, "rx_bad_timeout_late_char:\t%u\n", + priv->rx_bad_timeout_late_char); + seq_printf(s, "rx_bad_timeout_no_char:\t\t%u\n", + priv->rx_bad_timeout_no_char); + seq_printf(s, "rx_missing_close_timeout:\t%u\n", + priv->rx_missing_close_timeout); + if (priv->dma_enabled) { + seq_printf(s, "dma_rx_partial_buf:\t\t%llu\n", + priv->dma_rx_partial_buf); + seq_printf(s, "dma_rx_full_buf:\t\t%llu\n", + priv->dma_rx_full_buf); + } + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_stats); + +static void brcmuart_init_debugfs(struct brcmuart_priv *priv, + const char *device) +{ + priv->debugfs_dir = debugfs_create_dir(device, brcmuart_debugfs_root); + debugfs_create_file("stats", 0444, priv->debugfs_dir, priv, + &debugfs_stats_fops); +} + + +static int brcmuart_probe(struct platform_device *pdev) +{ + struct resource *regs; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = NULL; + struct uart_8250_port *new_port; + struct device *dev = &pdev->dev; + struct brcmuart_priv *priv; + struct clk *baud_mux_clk; + struct uart_8250_port up; + struct resource *irq; + void __iomem *membase = 0; + resource_size_t mapbase = 0; + u32 clk_rate = 0; + int ret; + int x; + int dma_irq; + static const char * const reg_names[REGS_MAX] = { + "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb" + }; + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(dev, "missing irq\n"); + return -EINVAL; + } + priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + of_id = of_match_node(brcmuart_dt_ids, np); + if (!of_id || !of_id->data) + priv->rate_table = brcmstb_rate_table; + else + priv->rate_table = of_id->data; + + for (x = 0; x < REGS_MAX; x++) { + regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, + reg_names[x]); + if (!regs) + break; + priv->regs[x] = devm_ioremap(dev, regs->start, + resource_size(regs)); + if (!priv->regs[x]) + return -ENOMEM; + if (x == REGS_8250) { + mapbase = regs->start; + membase = priv->regs[x]; + } + } + + /* We should have just the uart base registers or all the registers */ + if (x != 1 && x != REGS_MAX) { + dev_warn(dev, "%s registers not specified\n", reg_names[x]); + return -EINVAL; + } + + /* if the DMA registers were specified, try to enable DMA */ + if (x > REGS_DMA_RX) { + if (brcmuart_arbitration(priv, 1) == 0) { + u32 txrev = 0; + u32 rxrev = 0; + + txrev = udma_readl(priv, REGS_DMA_RX, UDMA_RX_REVISION); + rxrev = udma_readl(priv, REGS_DMA_TX, UDMA_TX_REVISION); + if ((txrev >= UDMA_TX_REVISION_REQUIRED) && + (rxrev >= UDMA_RX_REVISION_REQUIRED)) { + + /* Enable the use of the DMA hardware */ + priv->dma_enabled = true; + } else { + brcmuart_arbitration(priv, 0); + dev_err(dev, + "Unsupported DMA Hardware Revision\n"); + } + } else { + dev_err(dev, + "Timeout arbitrating for UART DMA hardware\n"); + } + } + + of_property_read_u32(np, "clock-frequency", &clk_rate); + + /* See if a Baud clock has been specified */ + baud_mux_clk = of_clk_get_by_name(np, "sw_baud"); + if (IS_ERR(baud_mux_clk)) { + if (PTR_ERR(baud_mux_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "BAUD MUX clock not specified\n"); + } else { + dev_dbg(dev, "BAUD MUX clock found\n"); + ret = clk_prepare_enable(baud_mux_clk); + if (ret) + return ret; + priv->baud_mux_clk = baud_mux_clk; + init_real_clk_rates(dev, priv); + clk_rate = priv->default_mux_rate; + } + + if (clk_rate == 0) { + dev_err(dev, "clock-frequency or clk not defined\n"); + return -EINVAL; + } + + dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not "); + + memset(&up, 0, sizeof(up)); + up.port.type = PORT_16550A; + up.port.uartclk = clk_rate; + up.port.dev = dev; + up.port.mapbase = mapbase; + up.port.membase = membase; + up.port.irq = irq->start; + up.port.handle_irq = brcmuart_handle_irq; + up.port.regshift = 2; + up.port.iotype = of_device_is_big_endian(np) ? + UPIO_MEM32BE : UPIO_MEM32; + up.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF + | UPF_FIXED_PORT | UPF_FIXED_TYPE; + up.port.dev = dev; + up.port.private_data = priv; + up.capabilities = UART_CAP_FIFO | UART_CAP_AFE; + up.port.fifosize = 32; + + /* Check for a fixed line number */ + ret = of_alias_get_id(np, "serial"); + if (ret >= 0) + up.port.line = ret; + + /* setup HR timer */ + hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + priv->hrt.function = brcmuart_hrtimer_func; + + up.port.shutdown = brcmuart_shutdown; + up.port.startup = brcmuart_startup; + up.port.throttle = brcmuart_throttle; + up.port.unthrottle = brcmuart_unthrottle; + up.port.set_termios = brcmstb_set_termios; + + if (priv->dma_enabled) { + priv->rx_size = RX_BUF_SIZE * RX_BUFS_COUNT; + priv->rx_bufs = dma_alloc_coherent(dev, + priv->rx_size, + &priv->rx_addr, GFP_KERNEL); + if (!priv->rx_bufs) + goto err; + priv->tx_size = UART_XMIT_SIZE; + priv->tx_buf = dma_alloc_coherent(dev, + priv->tx_size, + &priv->tx_addr, GFP_KERNEL); + if (!priv->tx_buf) + goto err; + } + + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err(dev, "unable to register 8250 port\n"); + goto err; + } + priv->line = ret; + new_port = serial8250_get_port(ret); + priv->up = &new_port->port; + if (priv->dma_enabled) { + dma_irq = platform_get_irq_byname(pdev, "dma"); + if (dma_irq < 0) { + dev_err(dev, "no IRQ resource info\n"); + goto err1; + } + ret = devm_request_irq(dev, dma_irq, brcmuart_isr, + IRQF_SHARED, "uart DMA irq", &new_port->port); + if (ret) { + dev_err(dev, "unable to register IRQ handler\n"); + goto err1; + } + } + platform_set_drvdata(pdev, priv); + brcmuart_init_debugfs(priv, dev_name(&pdev->dev)); + return 0; + +err1: + serial8250_unregister_port(priv->line); +err: + brcmuart_free_bufs(dev, priv); + brcmuart_arbitration(priv, 0); + return -ENODEV; +} + +static int brcmuart_remove(struct platform_device *pdev) +{ + struct brcmuart_priv *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debugfs_dir); + hrtimer_cancel(&priv->hrt); + serial8250_unregister_port(priv->line); + brcmuart_free_bufs(&pdev->dev, priv); + brcmuart_arbitration(priv, 0); + return 0; +} + +static int __maybe_unused brcmuart_suspend(struct device *dev) +{ + struct brcmuart_priv *priv = dev_get_drvdata(dev); + + serial8250_suspend_port(priv->line); + clk_disable_unprepare(priv->baud_mux_clk); + + return 0; +} + +static int __maybe_unused brcmuart_resume(struct device *dev) +{ + struct brcmuart_priv *priv = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(priv->baud_mux_clk); + if (ret) + dev_err(dev, "Error enabling BAUD MUX clock\n"); + + /* + * The hardware goes back to it's default after suspend + * so get the "clk" back in sync. + */ + ret = clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate); + if (ret) + dev_err(dev, "Error restoring default BAUD MUX clock\n"); + if (priv->dma_enabled) { + if (brcmuart_arbitration(priv, 1)) { + dev_err(dev, "Timeout arbitrating for DMA hardware on resume\n"); + return(-EBUSY); + } + brcmuart_init_dma_hardware(priv); + start_rx_dma(serial8250_get_port(priv->line)); + } + serial8250_resume_port(priv->line); + return 0; +} + +static const struct dev_pm_ops brcmuart_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(brcmuart_suspend, brcmuart_resume) +}; + +static struct platform_driver brcmuart_platform_driver = { + .driver = { + .name = "bcm7271-uart", + .pm = &brcmuart_dev_pm_ops, + .of_match_table = brcmuart_dt_ids, + }, + .probe = brcmuart_probe, + .remove = brcmuart_remove, +}; + +static int __init brcmuart_init(void) +{ + brcmuart_debugfs_root = debugfs_create_dir( + brcmuart_platform_driver.driver.name, NULL); + return platform_driver_register(&brcmuart_platform_driver); +} +module_init(brcmuart_init); + +static void __exit brcmuart_deinit(void) +{ + platform_driver_unregister(&brcmuart_platform_driver); + debugfs_remove_recursive(brcmuart_debugfs_root); +} +module_exit(brcmuart_deinit); + +MODULE_AUTHOR("Al Cooper"); +MODULE_DESCRIPTION("Broadcom NS16550A compatible serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 2d0e7c7e408dc9722181d51ee6415daa3e2e7d52..2f49c580139b86276952cb31443e17d9eac7e00c 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -354,7 +354,7 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p) static void * __xr17v35x_register_gpio(struct pci_dev *pcidev, - const struct property_entry *properties) + const struct software_node *node) { struct platform_device *pdev; @@ -365,7 +365,7 @@ __xr17v35x_register_gpio(struct pci_dev *pcidev, pdev->dev.parent = &pcidev->dev; ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev)); - if (platform_device_add_properties(pdev, properties) < 0 || + if (device_add_software_node(&pdev->dev, node) < 0 || platform_device_add(pdev) < 0) { platform_device_put(pdev); return NULL; @@ -380,12 +380,16 @@ static const struct property_entry exar_gpio_properties[] = { { } }; +static const struct software_node exar_gpio_node = { + .properties = exar_gpio_properties, +}; + static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { if (pcidev->vendor == PCI_VENDOR_ID_EXAR) port->port.private_data = - __xr17v35x_register_gpio(pcidev, exar_gpio_properties); + __xr17v35x_register_gpio(pcidev, &exar_gpio_node); return 0; } @@ -457,6 +461,10 @@ static const struct property_entry iot2040_gpio_properties[] = { { } }; +static const struct software_node iot2040_gpio_node = { + .properties = iot2040_gpio_properties, +}; + static int iot2040_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { @@ -468,7 +476,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev, writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8); port->port.private_data = - __xr17v35x_register_gpio(pcidev, iot2040_gpio_properties); + __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node); return 0; } @@ -547,6 +555,7 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) struct uart_8250_port *port = serial8250_get_port(priv->line[0]); struct platform_device *pdev = port->port.private_data; + device_remove_software_node(&pdev->dev); platform_device_unregister(pdev); port->port.private_data = NULL; } diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index fbcc90c31ca11e5814fecc05b36b982159df1275..4e75d2e4f87cb8108ad8ded99b14f2df19cc578e 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -30,15 +30,14 @@ struct fsl8250_data { int fsl8250_handle_irq(struct uart_port *port) { unsigned char lsr, orig_lsr; - unsigned long flags; unsigned int iir; struct uart_8250_port *up = up_to_u8250p(port); - spin_lock_irqsave(&up->port.lock, flags); + spin_lock(&up->port.lock); iir = port->serial_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock(&up->port.lock); return 0; } @@ -46,7 +45,7 @@ int fsl8250_handle_irq(struct uart_port *port) if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) { up->lsr_saved_flags &= ~UART_LSR_BI; port->serial_in(port, UART_RX); - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock(&up->port.lock); return 1; } @@ -82,7 +81,9 @@ int fsl8250_handle_irq(struct uart_port *port) serial8250_tx_chars(up); up->lsr_saved_flags = orig_lsr; - uart_unlock_and_check_sysrq(&up->port, flags); + + uart_unlock_and_check_sysrq(&up->port); + return 1; } EXPORT_SYMBOL_GPL(fsl8250_handle_irq); @@ -104,11 +105,8 @@ static int fsl8250_acpi_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(dev, "cannot get irq\n"); + if (irq < 0) return irq; - } memset(&port8250, 0, sizeof(port8250)); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 65e9045dafe6d16a38260a4ee4dc23dc1026ab28..0b077b45d6a949b886e2ebe25b0624857d86bae1 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -318,6 +318,7 @@ static const struct of_device_id of_platform_serial_table[] = { { .compatible = "mrvl,mmp-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, }, + { .compatible = "nuvoton,wpcm450-uart", .data = (void *)PORT_NPCM, }, { .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, }, { /* end of list */ }, }; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 23e0decde33eb40e42cceb508cad9c4e93fc0700..8ac11eaeca51bdfb048aff9d79a0aa7651de9479 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1143,7 +1143,6 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = up->port.private_data; unsigned char status; - unsigned long flags; u8 iir; serial8250_rpm_get(up); @@ -1154,7 +1153,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) return IRQ_HANDLED; } - spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->lock); status = serial_port_in(port, UART_LSR); @@ -1179,7 +1178,8 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) } } - uart_unlock_and_check_sysrq(port, flags); + uart_unlock_and_check_sysrq(port); + serial8250_rpm_put(up); return 1; } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index b0af13074cd36d877ee7f1177af8cbc1ff07eab6..d45dab1ab316473d9e9af8138db33a4ec02b2316 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1466,13 +1466,11 @@ EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) { - struct uart_8250_em485 *em485; - struct uart_8250_port *p; + struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, + stop_tx_timer); + struct uart_8250_port *p = em485->port; unsigned long flags; - em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); - p = em485->port; - serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->stop_tx_timer) { @@ -1482,16 +1480,13 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) } spin_unlock_irqrestore(&p->port.lock, flags); serial8250_rpm_put(p); + return HRTIMER_NORESTART; } static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) { - long sec = msec / 1000; - long nsec = (msec % 1000) * 1000000; - ktime_t t = ktime_set(sec, nsec); - - hrtimer_start(hrt, t, HRTIMER_MODE_REL); + hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL); } static void __stop_tx_rs485(struct uart_8250_port *p) @@ -1633,19 +1628,18 @@ static inline void start_tx_rs485(struct uart_port *port) static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) { - struct uart_8250_em485 *em485; - struct uart_8250_port *p; + struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, + start_tx_timer); + struct uart_8250_port *p = em485->port; unsigned long flags; - em485 = container_of(t, struct uart_8250_em485, start_tx_timer); - p = em485->port; - spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->start_tx_timer) { __start_tx(&p->port); em485->active_timer = NULL; } spin_unlock_irqrestore(&p->port.lock, flags); + return HRTIMER_NORESTART; } @@ -1885,14 +1879,13 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) int serial8250_handle_irq(struct uart_port *port, unsigned int iir) { unsigned char status; - unsigned long flags; struct uart_8250_port *up = up_to_u8250p(port); bool skip_rx = false; if (iir & UART_IIR_NO_INT) return 0; - spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->lock); status = serial_port_in(port, UART_LSR); @@ -1918,7 +1911,8 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) (up->ier & UART_IER_THRI)) serial8250_tx_chars(up); - uart_unlock_and_check_sysrq(port, flags); + uart_unlock_and_check_sysrq(port); + return 1; } EXPORT_SYMBOL_GPL(serial8250_handle_irq); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 603137da47363bda89a2778badeb38b84be81374..d1b3c2373fa42be5d3cb0353409c272f0bd06063 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -15,8 +15,7 @@ config SERIAL_8250 here are those that are setting up dedicated Ethernet WWW/FTP servers, or users that have one of the various bus mice instead of a serial mouse and don't intend to use their machine's standard serial - port for anything. (Note that the Cyclades multi serial port driver - does not need this driver built in for it to work.) + port for anything. To compile this driver as a module, choose M here: the module will be called 8250. @@ -226,7 +225,7 @@ config SERIAL_8250_MANY_PORTS serial port hardware which acts similar to standard serial port hardware. If you only use the standard COM 1/2/3/4 ports, you can say N here to save some memory. You can also say Y if you have an - "intelligent" multiport card such as Cyclades, Digiboards, etc. + "intelligent" multiport card such as Digiboards, etc. # # Multi-port serial cards @@ -404,7 +403,8 @@ config SERIAL_8250_RT288X config SERIAL_8250_OMAP tristate "Support for OMAP internal UART (8250 based driver)" - depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3) + depends on SERIAL_8250 + depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST help If you have a machine based on an Texas Instruments OMAP CPU you can enable its onboard serial ports by enabling this option. @@ -440,7 +440,8 @@ config SERIAL_8250_LPC18XX config SERIAL_8250_MT6577 tristate "Mediatek serial port support" - depends on SERIAL_8250 && ARCH_MEDIATEK + depends on SERIAL_8250 + depends on ARCH_MEDIATEK || COMPILE_TEST help If you have a Mediatek based board and want to use the serial port, say Y to this option. If unsure, say N. @@ -510,6 +511,16 @@ config SERIAL_8250_TEGRA Select this option if you have machine with an NVIDIA Tegra SoC and wish to enable 8250 serial driver for the Tegra serial interfaces. +config SERIAL_8250_BCM7271 + tristate "Broadcom 8250 based serial port" + depends on SERIAL_8250 && (ARCH_BRCMSTB || COMPILE_TEST) + default ARCH_BRCMSTB + help + If you have a Broadcom STB based board and want to use the + enhanced features of the Broadcom 8250 based serial port, + including DMA support and high accuracy BAUD rates, say + Y to this option. If unsure, say N. + config SERIAL_OF_PLATFORM tristate "Devicetree based probing for 8250 ports" depends on SERIAL_8250 && OF diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index a8bfb654d4908859b2c57d11a13a2ef5cb9a9cf8..b9bcd73c8997540789985c849376b8bf3d1a0e03 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o +obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 35ff6627c61be45a0507de9d958e605cf21d38b5..63ea9c4da3d5a0dfca485a34399aed27daa2a1d7 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -456,11 +456,11 @@ static int simple_config(struct pcmcia_device *link) * its base address, then try to grab any standard serial port * address, and finally try to get any free port. */ - if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) - goto found_port; - - dev_warn(&link->dev, "no usable port range found, giving up\n"); - return -1; + ret = pcmcia_loop_config(link, simple_config_check_notpicky, NULL); + if (ret) { + dev_warn(&link->dev, "no usable port range found, giving up\n"); + return ret; + } found_port: if (info->multi && (info->manfid == MANFID_3COM)) @@ -474,7 +474,7 @@ found_port: ret = pcmcia_enable_device(link); if (ret != 0) - return -1; + return ret; return setup_serial(link, info, link->resource[0]->start, link->irq); } diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 5311c33d27d1d89764239a2e679c1c129901eac1..be2c03d19aa6a9372a75abb76d6b09e45c67221c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -20,7 +20,7 @@ comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA + depends on ARM_AMBA || COMPILE_TEST select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have @@ -198,7 +198,7 @@ config SERIAL_KGDB_NMI config SERIAL_MESON tristate "Meson serial port support" - depends on ARCH_MESON + depends on ARCH_MESON || COMPILE_TEST select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Amlogic @@ -277,7 +277,7 @@ config SERIAL_SAMSUNG_CONSOLE config SERIAL_TEGRA tristate "NVIDIA Tegra20/30 SoC serial controller" - depends on ARCH_TEGRA && TEGRA20_APB_DMA + depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the NVIDIA Tegra series SOCs @@ -288,7 +288,8 @@ config SERIAL_TEGRA config SERIAL_TEGRA_TCU tristate "NVIDIA Tegra Combined UART" - depends on ARCH_TEGRA && TEGRA_HSP_MBOX + depends on MAILBOX + depends on (ARCH_TEGRA && TEGRA_HSP_MBOX) || COMPILE_TEST select SERIAL_CORE help Support for the mailbox-based TCU (Tegra Combined UART) serial port. @@ -497,6 +498,7 @@ config SERIAL_IMX_EARLYCON bool "Earlycon on IMX serial port" depends on ARCH_MXC || COMPILE_TEST depends on OF + select SERIAL_CORE select SERIAL_EARLYCON select SERIAL_CORE_CONSOLE default y if SERIAL_IMX_CONSOLE @@ -850,7 +852,8 @@ config SERIAL_MPC52xx_CONSOLE_BAUD config SERIAL_ICOM tristate "IBM Multiport Serial Adapter" - depends on PCI && PPC_PSERIES + depends on PCI + depends on PPC_PSERIES || COMPILE_TEST select SERIAL_CORE select FW_LOADER help @@ -919,7 +922,7 @@ config SERIAL_JSM config SERIAL_MSM tristate "MSM on-chip serial port support" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -945,7 +948,7 @@ config SERIAL_QCOM_GENI_CONSOLE config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" - depends on ARCH_VT8500 + depends on ARCH_VT8500 || COMPILE_TEST select SERIAL_CORE config SERIAL_VT8500_CONSOLE @@ -955,7 +958,7 @@ config SERIAL_VT8500_CONSOLE config SERIAL_OMAP tristate "OMAP serial port support" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || COMPILE_TEST select SERIAL_CORE help If you have a machine based on an Texas Instruments OMAP CPU you diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index d0ca9cf29b62ff24566c43e6e04eb6f5d1d0ab75..23c4e0e796944eca07e31ad002f349445cd57b0c 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -131,9 +131,7 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) uart_insert_char(port, 0, 0, ch, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 0e487ce091ac99a0c2ac3243b233706f946c47a7..7c5f4e966b594b42ac02671470fa5f21bec1130c 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -243,9 +243,7 @@ static void altera_uart_rx_chars(struct altera_uart *pp) flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void altera_uart_tx_chars(struct altera_uart *pp) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 3f96edfe569c5d1045f53fd4ebb830b52d6fc4d5..e744b953ca3467460856534bcb3f76169b4f8611 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -159,9 +159,7 @@ static void pl010_rx_chars(struct uart_amba_port *uap) ignore_char: status = readb(uap->port.membase + UART01x_FR); } - spin_unlock(&uap->port.lock); tty_flip_buffer_push(&uap->port.state->port); - spin_lock(&uap->port.lock); } static void pl010_tx_chars(struct uart_amba_port *uap) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 4ead0c9048a892cb4ee3393518cccc656aed777a..78682c12156a662c68a69145d0e00d5a81175f77 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -937,12 +937,10 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, fifotaken = pl011_fifo_to_tty(uap); } - spin_unlock(&uap->port.lock); dev_vdbg(uap->port.dev, "Took %d chars from DMA buffer and %d chars from the FIFO\n", dma_count, fifotaken); tty_flip_buffer_push(port); - spin_lock(&uap->port.lock); } static void pl011_dma_rx_irq(struct uart_amba_port *uap) diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index e8d56e899ec74691a59ff64e4ef7dc8d8ad151a9..d8c937bdf3f9e9c49a69a97e7136bcef465b714b 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -117,9 +117,7 @@ static void apbuart_rx_chars(struct uart_port *port) status = UART_GET_STATUS(port); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void apbuart_tx_chars(struct uart_port *port) diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index c2be7cf91399295b6be57734253d9a67b0c092da..4379ca4842ae75c21db9d96a77958baa68e8bebb 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -385,9 +385,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) tty_insert_flip_char(port, ch, TTY_NORMAL); } while (max_count-- > 0); - spin_unlock(&up->port.lock); tty_flip_buffer_push(port); - spin_lock(&up->port.lock); } static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 17c3fc398fc650ff7d372368e53e9f64f44cff76..1a9444b6b57e953f43953cbc52d86a791c83a825 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -236,9 +236,7 @@ static void arc_serial_rx_chars(struct uart_port *port, unsigned int status) if (!(uart_handle_sysrq_char(port, ch))) uart_insert_char(port, status, RXOERR, ch, flg); - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } while (!((status = UART_GET_STATUS(port)) & RXEMPTY)); } diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index a24e5c2b30bc956ab1f828b8fb702125e3259cd5..058886d9045b94d8caeb2d74d8819aaf19ee647b 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1178,13 +1178,7 @@ static void atmel_rx_from_dma(struct uart_port *port) 1, DMA_FROM_DEVICE); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); } @@ -1576,13 +1570,7 @@ static void atmel_rx_from_ring(struct uart_port *port) uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); } - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void atmel_release_rx_pdc(struct uart_port *port) @@ -1667,13 +1655,7 @@ static void atmel_rx_from_pdc(struct uart_port *port) } } while (head >= pdc->dma_size); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 5674da2b76f0f23b4681f181aed82aab347abc98..5fb0e84f7fd1926651b8cbc2753d553f81f5c566 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -294,9 +294,7 @@ static void bcm_uart_do_rx(struct uart_port *port) } while (--max_count); - spin_unlock(&port->lock); tty_flip_buffer_push(tty_port); - spin_lock(&port->lock); } /* diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 94af7a5ea4975c5a213fee40d3609c657420ca4d..9e9abfc4824a920a564f6e364e50bc1e66618316 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -829,9 +829,7 @@ ignore_char: } icom_port->next_rcv = rcv_buff; - spin_unlock(&icom_port->uart_port.lock); tty_flip_buffer_push(port); - spin_lock(&icom_port->uart_port.lock); } static void process_interrupt(u16 port_int_reg, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8257597d034dd75ba7396d0c659b84672cdadcf9..7d5a8dfa3e91e28d2e2ee6debf1f51f7b52e8712 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -394,11 +394,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) { - long sec = msec / MSEC_PER_SEC; - long nsec = (msec % MSEC_PER_SEC) * 1000000; - ktime_t t = ktime_set(sec, nsec); - - hrtimer_start(hrt, t, HRTIMER_MODE_REL); + hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL); } /* called with port.lock taken and irqs off */ @@ -922,14 +918,8 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; - unsigned long flags = 0; - /* - * IRQs might not be disabled upon entering this interrupt handler, - * e.g. when interrupt handlers are forced to be threaded. To support - * this scenario as well, disable IRQs when acquiring the spinlock. - */ - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); usr1 = imx_uart_readl(sport, USR1); usr2 = imx_uart_readl(sport, USR2); @@ -999,7 +989,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); return ret; } diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 512b77195e9f8e3c65b03d68539760e04c781cfd..8e42a7682c63d83a8827f68f3abf4a70b7d795c2 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -603,18 +603,22 @@ void jsm_input(struct jsm_channel *ch) if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { for (i = 0; i < s; i++) { + u8 chr = ch->ch_rqueue[tail + i]; + u8 error = ch->ch_equeue[tail + i]; + char flag = TTY_NORMAL; + /* - * Give the Linux ld the flags in the - * format it likes. + * Give the Linux ld the flags in the format it + * likes. */ - if (*(ch->ch_equeue + tail + i) & UART_LSR_BI) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_BREAK); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_PARITY); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_FRAME); - else - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_NORMAL); + if (error & UART_LSR_BI) + flag = TTY_BREAK; + else if (error & UART_LSR_PE) + flag = TTY_PARITY; + else if (error & UART_LSR_FE) + flag = TTY_FRAME; + + tty_insert_flip_char(port, chr, flag); } } else { tty_insert_flip_string(port, ch->ch_rqueue + tail, s); diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 6004c0c1d173e6b4f9e5ba2f3be5ebbc76ffdbaa..db059b66438e1de6ad090a5cffca799c85567e61 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -373,9 +373,7 @@ int kgdb_unregister_nmi_console(void) if (ret) return ret; - ret = tty_unregister_driver(kgdb_nmi_tty_driver); - if (ret) - return ret; + tty_unregister_driver(kgdb_nmi_tty_driver); put_tty_driver(kgdb_nmi_tty_driver); return 0; diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 64842f3539e199f7d3ce79738a82714ec9e65c79..0b06770642cb3d0719b7d9e337f781441bef159a 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -270,8 +270,8 @@ static int liteuart_probe(struct platform_device *pdev) /* get membase */ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (!port->membase) - return -ENXIO; + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); /* values not from device tree */ port->dev = &pdev->dev; diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 1fa098d7aec4b230301c5df15b7cb239e27af9ea..b199d7859961183c476cb20ebcc667931426a2db 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -273,9 +273,7 @@ static void __serial_lpc32xx_rx(struct uart_port *port) tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static void __serial_lpc32xx_tx(struct uart_port *port) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 1b61d26bb7afe48ce862f884420d31a72f549c71..8534d6e45a1d7b65c149a130526aa5314203b66b 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -273,7 +273,7 @@ struct max310x_port { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif - struct max310x_one p[0]; + struct max310x_one p[]; }; static struct uart_driver max310x_uart = { diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 09c88c48fb7b3e8cc8a380ae2cb5429fb4b1c91c..c7cec7d03620308cab5e22e174ec71b8d3935283 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -319,9 +319,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } /****************************************************************************/ diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 69eeef9edfa509729e6efb4edac2a446098fe93a..529cd02890560f4c9706205744150cefd6ba738a 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -226,9 +226,7 @@ static void meson_receive_chars(struct uart_port *port) } while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)); - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index af17004452516346d38f3087517421c060f2e11a..2704dc988e4a4de0bab2af2716ebf14ab3a3d5ae 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1421,9 +1421,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) } } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); return psc_ops->raw_rx_rdy(port); } diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 770c182e2208cb2094b1d5d645d04ec4b715bce1..fcef7a961430b37aa5a4b0f7940912f575f52fb6 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -757,9 +757,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) count -= r_count; } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); if (misr & (UART_IMR_RXSTALE)) msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); @@ -819,9 +817,7 @@ static void msm_handle_rx(struct uart_port *port) tty_insert_flip_char(tport, c, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 76b94d0ff58659472f286a2ed526c96e9d1ab8a6..84e8158088cd2fd8410b7a16ae4b5868270f6e7d 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -159,6 +159,8 @@ struct uart_omap_port { u32 calc_latency; struct work_struct qos_work; bool is_suspending; + + unsigned int rs485_tx_filter_count; }; #define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) @@ -302,7 +304,8 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_OMAP_SCR, up->scr); res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; - if (gpiod_get_value(up->rts_gpiod) != res) { + if (up->rts_gpiod && + gpiod_get_value(up->rts_gpiod) != res) { if (port->rs485.delay_rts_after_send > 0) mdelay( port->rs485.delay_rts_after_send); @@ -328,19 +331,6 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } - if ((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { - /* - * Empty the RX FIFO, we are not interested in anything - * received during the half-duplex transmission. - */ - serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR); - /* Re-enable RX interrupts */ - up->ier |= UART_IER_RLSI | UART_IER_RDI; - up->port.read_status_mask |= UART_LSR_DR; - serial_out(up, UART_IER, up->ier); - } - pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); } @@ -366,6 +356,10 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; up->port.x_char = 0; + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + up->rs485_tx_filter_count++; + return; } if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { @@ -377,6 +371,10 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) serial_out(up, UART_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); up->port.icount.tx++; + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + up->rs485_tx_filter_count++; + if (uart_circ_empty(xmit)) break; } while (--count > 0); @@ -411,7 +409,7 @@ static void serial_omap_start_tx(struct uart_port *port) /* if rts not already enabled */ res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; - if (gpiod_get_value(up->rts_gpiod) != res) { + if (up->rts_gpiod && gpiod_get_value(up->rts_gpiod) != res) { gpiod_set_value(up->rts_gpiod, res); if (port->rs485.delay_rts_before_send > 0) mdelay(port->rs485.delay_rts_before_send); @@ -420,7 +418,7 @@ static void serial_omap_start_tx(struct uart_port *port) if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) - serial_omap_stop_rx(port); + up->rs485_tx_filter_count = 0; serial_omap_enable_ier_thri(up); pm_runtime_mark_last_busy(up->dev); @@ -491,8 +489,13 @@ static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) * Read one data character out to avoid stalling the receiver according * to the table 23-246 of the omap4 TRM. */ - if (likely(lsr & UART_LSR_DR)) + if (likely(lsr & UART_LSR_DR)) { serial_in(up, UART_RX); + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && + up->rs485_tx_filter_count) + up->rs485_tx_filter_count--; + } up->port.icount.rx++; flag = TTY_NORMAL; @@ -543,6 +546,13 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) return; ch = serial_in(up, UART_RX); + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && + up->rs485_tx_filter_count) { + up->rs485_tx_filter_count--; + return; + } + flag = TTY_NORMAL; up->port.icount.rx++; @@ -1407,18 +1417,13 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) /* store new config */ port->rs485 = *rs485; - /* - * Just as a precaution, only allow rs485 - * to be enabled if the gpio pin is valid - */ if (up->rts_gpiod) { /* enable / disable rts */ val = (port->rs485.flags & SER_RS485_ENABLED) ? SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; val = (port->rs485.flags & val) ? 1 : 0; gpiod_set_value(up->rts_gpiod, val); - } else - port->rs485.flags &= ~SER_RS485_ENABLED; + } /* Enable interrupts */ up->ier = mode; diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index abc6042f03788b54b880f5d6d431ebc37c7995bd..91f1eb0058d7ec025f0f07fd5c50d05e91c915cd 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -247,9 +247,7 @@ static void owl_uart_receive_chars(struct uart_port *port) stat = owl_uart_read(port, OWL_UART_STAT); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static irqreturn_t owl_uart_irq(int irq, void *dev_id) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index a7363bc66c11a4190f19499ca03bffb7fd66b64c..f0351e6f0ef6d44ba6d6615ad5e99abcf7abd1ef 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -236,7 +236,6 @@ struct eg20t_port { void *rx_buf_virt; dma_addr_t rx_buf_dma; - struct dentry *debugfs; #define IRQ_NAME_SIZE 17 char irq_name[IRQ_NAME_SIZE]; @@ -292,8 +291,6 @@ static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 }; static const int trigger_level_1[4] = { 1, 1, 1, 1 }; -#ifdef CONFIG_DEBUG_FS - #define PCH_REGS_BUFSIZE 1024 @@ -353,7 +350,6 @@ static const struct file_operations port_regs_ops = { .read = port_show_regs, .llseek = default_llseek, }; -#endif /* CONFIG_DEBUG_FS */ static const struct dmi_system_id pch_uart_dmi_table[] = { { @@ -1735,9 +1731,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int fifosize; int port_type; struct pch_uart_driver_data *board; -#ifdef CONFIG_DEBUG_FS - char name[32]; /* for debugfs file name */ -#endif + char name[32]; board = &drv_dat[id->driver_data]; port_type = board->port_type; @@ -1813,11 +1807,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (ret < 0) goto init_port_hal_free; -#ifdef CONFIG_DEBUG_FS - snprintf(name, sizeof(name), "uart%d_regs", board->line_no); - priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO, - NULL, priv, &port_regs_ops); -#endif + snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); + debugfs_create_file(name, S_IFREG | S_IRUGO, NULL, priv, + &port_regs_ops); return priv; @@ -1835,10 +1827,10 @@ init_port_alloc_err: static void pch_uart_exit_port(struct eg20t_port *priv) { + char name[32]; -#ifdef CONFIG_DEBUG_FS - debugfs_remove(priv->debugfs); -#endif + snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); + debugfs_remove(debugfs_lookup(name, NULL)); uart_remove_one_port(&pch_uart_driver, &priv->port); free_page((unsigned long)priv->rxbuf.buf); } diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 0d85b55ea8233a2761551d6535c436628bcf60f7..23d729ed3bf667d468f7b059d75cbd9ef080f7d0 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -818,7 +818,6 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) u32 s_irq_status; u32 geni_status; struct uart_port *uport = dev; - unsigned long flags; bool drop_rx = false; struct tty_port *tport = &uport->state->port; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); @@ -826,7 +825,8 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) if (uport->suspended) return IRQ_NONE; - spin_lock_irqsave(&uport->lock, flags); + spin_lock(&uport->lock); + m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); geni_status = readl(uport->membase + SE_GENI_STATUS); @@ -861,7 +861,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) qcom_geni_serial_handle_rx(uport, drop_rx); out_unlock: - uart_unlock_and_check_sysrq(uport, flags); + uart_unlock_and_check_sysrq(uport); return IRQ_HANDLED; } @@ -1426,14 +1426,14 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap")) port->cts_rts_swap = true; - port->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se"); - if (IS_ERR(port->se.opp_table)) - return PTR_ERR(port->se.opp_table); + ret = devm_pm_opp_set_clkname(&pdev->dev, "se"); + if (ret) + return ret; /* OPP table is optional */ - ret = dev_pm_opp_of_add_table(&pdev->dev); + ret = devm_pm_opp_of_add_table(&pdev->dev); if (ret && ret != -ENODEV) { dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - goto put_clkname; + return ret; } port->private_data.drv = drv; @@ -1443,7 +1443,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) ret = uart_add_one_port(drv, uport); if (ret) - goto err; + return ret; irq_set_status_flags(uport->irq, IRQ_NOAUTOEN); ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr, @@ -1451,7 +1451,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) { dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); uart_remove_one_port(drv, uport); - goto err; + return ret; } /* @@ -1468,16 +1468,11 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) { device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, uport); - goto err; + return ret; } } return 0; -err: - dev_pm_opp_of_remove_table(&pdev->dev); -put_clkname: - dev_pm_opp_put_clkname(port->se.opp_table); - return ret; } static int qcom_geni_serial_remove(struct platform_device *pdev) @@ -1485,8 +1480,6 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); struct uart_driver *drv = port->private_data.drv; - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(port->se.opp_table); dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, &port->uport); diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index 85366e05925850dbd8d2c603893a0433a19ccf29..d550d8fa2fabf3289c90ebab28207b34ea5e67d1 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -398,9 +398,7 @@ static void rda_uart_receive_chars(struct uart_port *port) status = rda_uart_read(port, RDA_UART_STATUS); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static irqreturn_t rda_interrupt(int irq, void *dev_id) diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 5690c09cc0417f3a34d005b804b08e6808ff1d28..d60abffab70eca80e450174378c50a25d8fe0861 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -424,9 +424,7 @@ static void rp2_rx_chars(struct rp2_uart_port *up) up->port.icount.rx++; } - spin_unlock(&up->port.lock); tty_flip_buffer_push(port); - spin_lock(&up->port.lock); } static void rp2_tx_chars(struct rp2_uart_port *up) diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index f5fab1dd96bcdef3e9de16d168069f90c8a5c520..697b6a002a16e6886f8fac902364c6c5f230c9bf 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -223,9 +223,7 @@ sa1100_rx_chars(struct sa1100_port *sport) UTSR0_TO_SM(UART_GET_UTSR0(sport)); } - spin_unlock(&sport->port.lock); tty_flip_buffer_push(&sport->port.state->port); - spin_lock(&sport->port.lock); } static void sa1100_tx_chars(struct sa1100_port *sport) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 8ae3e03fbd8ce625742782950af00eebbf698c64..d9e4b67a12a002ef624e8f9b6e9ad59bd2270523 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -56,9 +56,16 @@ /* flag to ignore all characters coming in */ #define RXSTAT_DUMMY_READ (0x10000000) +enum s3c24xx_port_type { + TYPE_S3C24XX, + TYPE_S3C6400, + TYPE_APPLE_S5L, +}; + struct s3c24xx_uart_info { char *name; - unsigned int type; + enum s3c24xx_port_type type; + unsigned int port_type; unsigned int fifosize; unsigned long rx_fifomask; unsigned long rx_fifoshift; @@ -70,6 +77,7 @@ struct s3c24xx_uart_info { unsigned long num_clks; unsigned long clksel_mask; unsigned long clksel_shift; + unsigned long ucon_mask; /* uart port features */ @@ -144,6 +152,8 @@ struct s3c24xx_uart_port { #endif }; +static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport); + /* conversion functions */ #define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev) @@ -228,16 +238,6 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } -/* - * s3c64xx and later SoC's include the interrupt mask and status registers in - * the controller itself, unlike the s3c24xx SoC's which have these registers - * in the interrupt controller. Check if the port type is s3c64xx or higher. - */ -static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port) -{ - return to_ourport(port)->info->type == PORT_S3C6400; -} - static void s3c24xx_serial_rx_enable(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -289,10 +289,17 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) if (!ourport->tx_enabled) return; - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + s3c24xx_clear_bit(port, APPLE_S5L_UCON_TXTHRESH_ENA, S3C2410_UCON); + break; + default: disable_irq_nosync(ourport->tx_irq); + break; + } if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) { dmaengine_pause(dma->tx_chan); @@ -353,10 +360,17 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) u32 ucon; /* Mask Tx interrupt */ - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + WARN_ON(1); // No DMA + break; + default: disable_irq_nosync(ourport->tx_irq); + break; + } /* Enable tx dma mode */ ucon = rd_regl(port, S3C2410_UCON); @@ -386,13 +400,28 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport) wr_regl(port, S3C2410_UCON, ucon); /* Unmask Tx interrupt */ - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK; + wr_regl(port, S3C2410_UCON, ucon); + break; + default: enable_irq(ourport->tx_irq); + break; + } ourport->tx_mode = S3C24XX_TX_PIO; + + /* + * The Apple version only has edge triggered TX IRQs, so we need + * to kick off the process by sending some characters here. + */ + if (ourport->info->type == TYPE_APPLE_S5L) + s3c24xx_serial_tx_chars(ourport); } static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport) @@ -513,11 +542,19 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (ourport->rx_enabled) { dev_dbg(port->dev, "stopping rx\n"); - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON); + break; + default: disable_irq_nosync(ourport->rx_irq); + break; + } ourport->rx_enabled = 0; } if (dma && dma->rx_chan) { @@ -651,14 +688,18 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport) /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); - ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | - S3C64XX_UCON_EMPTYINT_EN | - S3C64XX_UCON_DMASUS_EN | - S3C64XX_UCON_TIMEOUT_EN | - S3C64XX_UCON_RXMODE_MASK); - ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | - S3C64XX_UCON_TIMEOUT_EN | - S3C64XX_UCON_RXMODE_CPU; + ucon &= ~S3C64XX_UCON_RXMODE_MASK; + ucon |= S3C64XX_UCON_RXMODE_CPU; + + /* Apple types use these bits for IRQ masks */ + if (ourport->info->type != TYPE_APPLE_S5L) { + ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | + S3C64XX_UCON_EMPTYINT_EN | + S3C64XX_UCON_DMASUS_EN | + S3C64XX_UCON_TIMEOUT_EN); + ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | + S3C64XX_UCON_TIMEOUT_EN; + } wr_regl(port, S3C2410_UCON, ucon); ourport->rx_mode = S3C24XX_RX_PIO; @@ -674,13 +715,12 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) struct s3c24xx_uart_dma *dma = ourport->dma; struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port); struct tty_port *t = &port->state->port; - unsigned long flags; struct dma_tx_state state; utrstat = rd_regl(port, S3C2410_UTRSTAT); rd_regl(port, S3C2410_UFSTAT); - spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->lock); if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) { s3c64xx_start_rx_dma(ourport); @@ -709,7 +749,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT); finish: - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock(&port->lock); return IRQ_HANDLED; } @@ -805,16 +845,15 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->lock); s3c24xx_serial_rx_drain_fifo(ourport); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock(&port->lock); return IRQ_HANDLED; } -static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) +static irqreturn_t s3c24xx_serial_rx_irq(int irq, void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; @@ -823,16 +862,12 @@ static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) return s3c24xx_serial_rx_chars_pio(dev_id); } -static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) +static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) { - struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; struct circ_buf *xmit = &port->state->xmit; - unsigned long flags; int count, dma_count = 0; - spin_lock_irqsave(&port->lock, flags); - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (ourport->dma && ourport->dma->tx_chan && @@ -849,7 +884,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) wr_reg(port, S3C2410_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; - goto out; + return; } /* if there isn't anything more to transmit, or the uart is now @@ -858,7 +893,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { s3c24xx_serial_stop_tx(port); - goto out; + return; } /* try and drain the buffer... */ @@ -880,7 +915,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (!count && dma_count) { s3c24xx_serial_start_tx_dma(ourport, dma_count); - goto out; + return; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { @@ -891,9 +926,18 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (uart_circ_empty(xmit)) s3c24xx_serial_stop_tx(port); +} -out: - spin_unlock_irqrestore(&port->lock, flags); +static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + + spin_lock(&port->lock); + + s3c24xx_serial_tx_chars(ourport); + + spin_unlock(&port->lock); return IRQ_HANDLED; } @@ -906,16 +950,37 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) irqreturn_t ret = IRQ_HANDLED; if (pend & S3C64XX_UINTM_RXD_MSK) { - ret = s3c24xx_serial_rx_chars(irq, id); + ret = s3c24xx_serial_rx_irq(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); } if (pend & S3C64XX_UINTM_TXD_MSK) { - ret = s3c24xx_serial_tx_chars(irq, id); + ret = s3c24xx_serial_tx_irq(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); } return ret; } +/* interrupt handler for Apple SoC's.*/ +static irqreturn_t apple_serial_handle_irq(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); + irqreturn_t ret = IRQ_NONE; + + if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) { + wr_regl(port, S3C2410_UTRSTAT, + APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO); + ret = s3c24xx_serial_rx_irq(irq, id); + } + if (pend & APPLE_S5L_UTRSTAT_TXTHRESH) { + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_TXTHRESH); + ret = s3c24xx_serial_tx_irq(irq, id); + } + + return ret; +} + static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); @@ -1098,27 +1163,62 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); if (ourport->tx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->tx_irq, ourport); + free_irq(ourport->tx_irq, ourport); ourport->tx_enabled = 0; ourport->tx_claimed = 0; ourport->tx_mode = 0; } if (ourport->rx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->rx_irq, ourport); + free_irq(ourport->rx_irq, ourport); ourport->rx_claimed = 0; ourport->rx_enabled = 0; } - /* Clear pending interrupts and mask all interrupts */ - if (s3c24xx_serial_has_interrupt_mask(port)) { - free_irq(port->irq, ourport); + if (ourport->dma) + s3c24xx_serial_release_dma(ourport); - wr_regl(port, S3C64XX_UINTP, 0xf); - wr_regl(port, S3C64XX_UINTM, 0xf); - } + ourport->tx_in_progress = 0; +} + +static void s3c64xx_serial_shutdown(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + ourport->tx_enabled = 0; + ourport->tx_mode = 0; + ourport->rx_enabled = 0; + + free_irq(port->irq, ourport); + + wr_regl(port, S3C64XX_UINTP, 0xf); + wr_regl(port, S3C64XX_UINTM, 0xf); + + if (ourport->dma) + s3c24xx_serial_release_dma(ourport); + + ourport->tx_in_progress = 0; +} + +static void apple_s5l_serial_shutdown(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + unsigned int ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + wr_regl(port, S3C2410_UCON, ucon); + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + + free_irq(port->irq, ourport); + + ourport->tx_enabled = 0; + ourport->tx_mode = 0; + ourport->rx_enabled = 0; if (ourport->dma) s3c24xx_serial_release_dma(ourport); @@ -1133,7 +1233,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) ourport->rx_enabled = 1; - ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, + ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_irq, 0, s3c24xx_serial_portname(port), ourport); if (ret != 0) { @@ -1147,7 +1247,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) ourport->tx_enabled = 1; - ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, + ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_irq, 0, s3c24xx_serial_portname(port), ourport); if (ret) { @@ -1193,9 +1293,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) /* For compatibility with s3c24xx Soc's */ ourport->rx_enabled = 1; - ourport->rx_claimed = 1; ourport->tx_enabled = 0; - ourport->tx_claimed = 1; spin_lock_irqsave(&port->lock, flags); @@ -1215,6 +1313,45 @@ static int s3c64xx_serial_startup(struct uart_port *port) return ret; } +static int apple_s5l_serial_startup(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; + unsigned int ufcon; + int ret; + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + + ret = request_irq(port->irq, apple_serial_handle_irq, 0, + s3c24xx_serial_portname(port), ourport); + if (ret) { + dev_err(port->dev, "cannot get irq %d\n", port->irq); + return ret; + } + + /* For compatibility with s3c24xx Soc's */ + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + + spin_lock_irqsave(&port->lock, flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; + if (!uart_console(port)) + ufcon |= S3C2410_UFCON_RESETTX; + wr_regl(port, S3C2410_UFCON, ufcon); + + enable_rx_pio(ourport); + + spin_unlock_irqrestore(&port->lock, flags); + + /* Enable Rx Interrupt */ + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON); + + return ret; +} + /* power power management control */ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, @@ -1535,41 +1672,26 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, static const char *s3c24xx_serial_type(struct uart_port *port) { - switch (port->type) { - case PORT_S3C2410: - return "S3C2410"; - case PORT_S3C2440: - return "S3C2440"; - case PORT_S3C2412: - return "S3C2412"; - case PORT_S3C6400: + struct s3c24xx_uart_port *ourport = to_ourport(port); + + switch (ourport->info->type) { + case TYPE_S3C24XX: + return "S3C24XX"; + case TYPE_S3C6400: return "S3C6400/10"; + case TYPE_APPLE_S5L: + return "APPLE S5L"; default: return NULL; } } -#define MAP_SIZE (0x100) - -static void s3c24xx_serial_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, MAP_SIZE); -} - -static int s3c24xx_serial_request_port(struct uart_port *port) -{ - const char *name = s3c24xx_serial_portname(port); - - return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY; -} - static void s3c24xx_serial_config_port(struct uart_port *port, int flags) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - if (flags & UART_CONFIG_TYPE && - s3c24xx_serial_request_port(port) == 0) - port->type = info->type; + if (flags & UART_CONFIG_TYPE) + port->type = info->port_type; } /* @@ -1580,7 +1702,7 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - if (ser->type != PORT_UNKNOWN && ser->type != info->type) + if (ser->type != PORT_UNKNOWN && ser->type != info->port_type) return -EINVAL; return 0; @@ -1608,7 +1730,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, unsigned char c); #endif -static struct uart_ops s3c24xx_serial_ops = { +static const struct uart_ops s3c24xx_serial_ops = { .pm = s3c24xx_serial_pm, .tx_empty = s3c24xx_serial_tx_empty, .get_mctrl = s3c24xx_serial_get_mctrl, @@ -1621,8 +1743,48 @@ static struct uart_ops s3c24xx_serial_ops = { .shutdown = s3c24xx_serial_shutdown, .set_termios = s3c24xx_serial_set_termios, .type = s3c24xx_serial_type, - .release_port = s3c24xx_serial_release_port, - .request_port = s3c24xx_serial_request_port, + .config_port = s3c24xx_serial_config_port, + .verify_port = s3c24xx_serial_verify_port, +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) + .poll_get_char = s3c24xx_serial_get_poll_char, + .poll_put_char = s3c24xx_serial_put_poll_char, +#endif +}; + +static const struct uart_ops s3c64xx_serial_ops = { + .pm = s3c24xx_serial_pm, + .tx_empty = s3c24xx_serial_tx_empty, + .get_mctrl = s3c24xx_serial_get_mctrl, + .set_mctrl = s3c24xx_serial_set_mctrl, + .stop_tx = s3c24xx_serial_stop_tx, + .start_tx = s3c24xx_serial_start_tx, + .stop_rx = s3c24xx_serial_stop_rx, + .break_ctl = s3c24xx_serial_break_ctl, + .startup = s3c64xx_serial_startup, + .shutdown = s3c64xx_serial_shutdown, + .set_termios = s3c24xx_serial_set_termios, + .type = s3c24xx_serial_type, + .config_port = s3c24xx_serial_config_port, + .verify_port = s3c24xx_serial_verify_port, +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) + .poll_get_char = s3c24xx_serial_get_poll_char, + .poll_put_char = s3c24xx_serial_put_poll_char, +#endif +}; + +static const struct uart_ops apple_s5l_serial_ops = { + .pm = s3c24xx_serial_pm, + .tx_empty = s3c24xx_serial_tx_empty, + .get_mctrl = s3c24xx_serial_get_mctrl, + .set_mctrl = s3c24xx_serial_set_mctrl, + .stop_tx = s3c24xx_serial_stop_tx, + .start_tx = s3c24xx_serial_start_tx, + .stop_rx = s3c24xx_serial_stop_rx, + .break_ctl = s3c24xx_serial_break_ctl, + .startup = apple_s5l_serial_startup, + .shutdown = apple_s5l_serial_shutdown, + .set_termios = s3c24xx_serial_set_termios, + .type = s3c24xx_serial_type, .config_port = s3c24xx_serial_config_port, .verify_port = s3c24xx_serial_verify_port, #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) @@ -1706,14 +1868,9 @@ static void s3c24xx_serial_resetport(struct uart_port *port, { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned long ucon = rd_regl(port, S3C2410_UCON); - unsigned int ucon_mask; - ucon_mask = info->clksel_mask; - if (info->type == PORT_S3C2440) - ucon_mask |= S3C2440_UCON0_DIVMASK; - - ucon &= ucon_mask; - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + ucon &= (info->clksel_mask | info->ucon_mask); + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); @@ -1868,10 +2025,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* setup info for port */ port->dev = &platdev->dev; - /* Startup sequence is different for s3c64xx and higher SoC's */ - if (s3c24xx_serial_has_interrupt_mask(port)) - s3c24xx_serial_ops.startup = s3c64xx_serial_startup; - port->uartclk = 1; if (cfg->uart_flags & UPF_CONS_FLOW) { @@ -1889,8 +2042,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, dev_dbg(port->dev, "resource %pR)\n", res); - port->membase = devm_ioremap(port->dev, res->start, resource_size(res)); - if (!port->membase) { + port->membase = devm_ioremap_resource(port->dev, res); + if (IS_ERR(port->membase)) { dev_err(port->dev, "failed to remap controller address\n"); return -EBUSY; } @@ -1905,11 +2058,16 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->tx_irq = ret + 1; } - if (!s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C24XX: ret = platform_get_irq(platdev, 1); if (ret > 0) ourport->tx_irq = ret; + break; + default: + break; } + /* * DMA is currently supported only on DT platforms, if DMA properties * are specified. @@ -1945,10 +2103,26 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, pr_warn("uart: failed to enable baudclk\n"); /* Keep all interrupts masked and cleared */ - if (s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C6400: wr_regl(port, S3C64XX_UINTM, 0xf); wr_regl(port, S3C64XX_UINTP, 0xf); wr_regl(port, S3C64XX_UINTSP, 0xf); + break; + case TYPE_APPLE_S5L: { + unsigned int ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + wr_regl(port, S3C2410_UCON, ucon); + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + break; + } + default: + break; } dev_dbg(port->dev, "port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n", @@ -2019,6 +2193,18 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; + switch (ourport->info->type) { + case TYPE_S3C24XX: + ourport->port.ops = &s3c24xx_serial_ops; + break; + case TYPE_S3C6400: + ourport->port.ops = &s3c64xx_serial_ops; + break; + case TYPE_APPLE_S5L: + ourport->port.ops = &apple_s5l_serial_ops; + break; + } + if (np) { of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); @@ -2142,7 +2328,8 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (port) { /* restore IRQ mask */ - if (s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C6400: { unsigned int uintm = 0xf; if (ourport->tx_enabled) @@ -2156,6 +2343,47 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); clk_disable_unprepare(ourport->clk); + break; + } + case TYPE_APPLE_S5L: { + unsigned int ucon; + int ret; + + ret = clk_prepare_enable(ourport->clk); + if (ret) { + dev_err(dev, "clk_enable clk failed: %d\n", ret); + return ret; + } + if (!IS_ERR(ourport->baudclk)) { + ret = clk_prepare_enable(ourport->baudclk); + if (ret) { + dev_err(dev, "clk_enable baudclk failed: %d\n", ret); + clk_disable_unprepare(ourport->clk); + return ret; + } + } + + ucon = rd_regl(port, S3C2410_UCON); + + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + + if (ourport->tx_enabled) + ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK; + if (ourport->rx_enabled) + ucon |= APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK; + + wr_regl(port, S3C2410_UCON, ucon); + + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); + clk_disable_unprepare(ourport->clk); + break; + } + default: + break; } } @@ -2380,7 +2608,8 @@ static struct console s3c24xx_serial_console = { static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2410 UART", - .type = PORT_S3C2410, + .type = TYPE_S3C24XX, + .port_type = PORT_S3C2410, .fifosize = 16, .rx_fifomask = S3C2410_UFSTAT_RXMASK, .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, @@ -2407,7 +2636,8 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2412 UART", - .type = PORT_S3C2412, + .type = TYPE_S3C24XX, + .port_type = PORT_S3C2412, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2436,7 +2666,8 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2440 UART", - .type = PORT_S3C2440, + .type = TYPE_S3C24XX, + .port_type = PORT_S3C2440, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2449,6 +2680,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .num_clks = 4, .clksel_mask = S3C2412_UCON_CLKMASK, .clksel_shift = S3C2412_UCON_CLKSHIFT, + .ucon_mask = S3C2440_UCON0_DIVMASK, }, .def_cfg = &(struct s3c2410_uartcfg) { .ucon = S3C2410_UCON_DEFAULT, @@ -2464,7 +2696,8 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C6400 UART", - .type = PORT_S3C6400, + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2492,7 +2725,8 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S5PV210 UART", - .type = PORT_S3C6400, + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, .has_divslot = 1, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, @@ -2520,7 +2754,8 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #define EXYNOS_COMMON_SERIAL_DRV_DATA \ .info = &(struct s3c24xx_uart_info) { \ .name = "Samsung Exynos UART", \ - .type = PORT_S3C6400, \ + .type = TYPE_S3C6400, \ + .port_type = PORT_S3C6400, \ .has_divslot = 1, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ @@ -2556,6 +2791,34 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL #endif +#ifdef CONFIG_ARCH_APPLE +static struct s3c24xx_serial_drv_data s5l_serial_drv_data = { + .info = &(struct s3c24xx_uart_info) { + .name = "Apple S5L UART", + .type = TYPE_APPLE_S5L, + .port_type = PORT_8250, + .fifosize = 16, + .rx_fifomask = S3C2410_UFSTAT_RXMASK, + .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2410_UFSTAT_RXFULL, + .tx_fifofull = S3C2410_UFSTAT_TXFULL, + .tx_fifomask = S3C2410_UFSTAT_TXMASK, + .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, + .def_clk_sel = S3C2410_UCON_CLKSEL0, + .num_clks = 1, + .clksel_mask = 0, + .clksel_shift = 0, + }, + .def_cfg = &(struct s3c2410_uartcfg) { + .ucon = APPLE_S5L_UCON_DEFAULT, + .ufcon = S3C2410_UFCON_DEFAULT, + }, +}; +#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)&s5l_serial_drv_data) +#else +#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) +#endif + static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { .name = "s3c2410-uart", @@ -2578,6 +2841,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = { }, { .name = "exynos5433-uart", .driver_data = EXYNOS5433_SERIAL_DRV_DATA, + }, { + .name = "s5l-uart", + .driver_data = S5L_SERIAL_DRV_DATA, }, { }, }; @@ -2599,6 +2865,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = { .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos5433-uart", .data = (void *)EXYNOS5433_SERIAL_DRV_DATA }, + { .compatible = "apple,s5l-uart", + .data = (void *)S5L_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); @@ -2730,6 +2998,23 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart", s5pv210_early_console_setup); OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart", s5pv210_early_console_setup); + +/* Apple S5L */ +static int __init apple_s5l_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + /* Close enough to S3C2410 for earlycon... */ + device->port.private_data = &s3c2410_early_console_data; + +#ifdef CONFIG_ARM64 + /* ... but we need to override the existing fixmap entry as nGnRnE */ + __set_fixmap(FIX_EARLYCON_MEM_BASE, device->port.mapbase, + __pgprot(PROT_DEVICE_nGnRnE)); +#endif + return samsung_early_console_setup(device, opt); +} + +OF_EARLYCON_DECLARE(s5l, "apple,s5l-uart", apple_s5l_early_console_setup); #endif MODULE_ALIAS("platform:samsung-uart"); diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index f86ec2d2635b7c76121914c12b40d564711742da..9adb8362578c5d8c54a5c1a34061e5688eaf727d 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1196,7 +1196,7 @@ static int sc16is7xx_probe(struct device *dev, ret = regmap_read(regmap, SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val); if (ret < 0) - return ret; + return -EPROBE_DEFER; /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ba31e97d3d96b8ee45351c918f86f03ff342a105..87f7127b57e6b1ca5d64414ab76bab5bb3ed9c15 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -759,8 +759,6 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo) struct uart_port *uport; int ret = -ENODEV; - memset(retinfo, 0, sizeof(*retinfo)); - /* * Ensure the state we copy is consistent and no hardware changes * occur as we go @@ -1305,7 +1303,7 @@ static int uart_set_rs485_config(struct uart_port *port, unsigned long flags; if (!port->rs485_config) - return -ENOIOCTLCMD; + return -ENOTTY; if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT; @@ -1329,7 +1327,7 @@ static int uart_get_iso7816_config(struct uart_port *port, struct serial_iso7816 aux; if (!port->iso7816_config) - return -ENOIOCTLCMD; + return -ENOTTY; spin_lock_irqsave(&port->lock, flags); aux = port->iso7816; @@ -1349,7 +1347,7 @@ static int uart_set_iso7816_config(struct uart_port *port, unsigned long flags; if (!port->iso7816_config) - return -ENOIOCTLCMD; + return -ENOTTY; if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user))) return -EFAULT; diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 7a07e7272de1258d2bf48066ccd7d0e467a3244e..0a7e5b74bc1dc8f2225f46a4166d62b1512af576 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -330,9 +330,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) up->port.ignore_status_mask = next_ignore_status_mask; disr = sio_in(up, TXX9_SIDISR); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); - spin_unlock(&up->port.lock); + tty_flip_buffer_push(&up->port.state->port); - spin_lock(&up->port.lock); + *status = disr; } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e1179e74a2b89d892f4c8e0edceb3378c6755e5a..ef37fdf37612f82f1ce280d885775f3178820fe1 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2124,7 +2124,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state) unsigned short scscr, scsptr; unsigned long flags; - /* check wheter the port has SCSPTR */ + /* check whether the port has SCSPTR */ if (!sci_getreg(port, SCSPTR)->size) { /* * Not supported by hardware. Most parts couple break and rx @@ -2609,21 +2609,10 @@ done: udelay(DIV_ROUND_UP(10 * 1000000, baud)); } - /* - * Calculate delay for 2 DMA buffers (4 FIFO). - * See serial_core.c::uart_update_timeout(). - * With 10 bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above - * function calculates 1 jiffie for the data plus 5 jiffies for the - * "slop(e)." Then below we calculate 5 jiffies (20ms) for 2 DMA - * buffers (4 FIFO sizes), but when performing a faster transfer, the - * value obtained by this formula is too small. Therefore, if the value - * is smaller than 20ms, use 20ms as the timeout value for DMA. - */ + /* Calculate delay for 2 DMA buffers (4 FIFO). */ s->rx_frame = (10000 * bits) / (baud / 100); #ifdef CONFIG_SERIAL_SH_SCI_DMA s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; - if (s->rx_timeout < 20) - s->rx_timeout = 20; #endif if ((termios->c_cflag & CREAD) != 0) diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 328d5a78792fe78c19400fb78373fcee440c3a99..0ac0371f943b688113612e943db6812d3df177a4 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -448,9 +448,7 @@ static void __ssp_receive_chars(struct sifive_serial_port *ssp) uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); } - spin_unlock(&ssp->port.lock); tty_flip_buffer_push(&ssp->port.state->port); - spin_lock(&ssp->port.lock); } /** diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index b3675cf25a692cb1762bb8162f9fb83dcb770b31..c2ae7b392b86b4761085beaf0e197b73f7d43d79 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -218,8 +218,7 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) u32 sr; char flag; - if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) - pm_wakeup_event(tport->tty->dev, 0); + spin_lock(&port->lock); while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { @@ -271,14 +270,14 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) } } - if (uart_handle_sysrq_char(port, c)) + if (uart_prepare_sysrq_char(port, c)) continue; uart_insert_char(port, sr, USART_SR_ORE, c, flag); } - spin_unlock(&port->lock); + uart_unlock_and_check_sysrq(port); + tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static void stm32_usart_tx_dma_complete(void *arg) @@ -286,12 +285,16 @@ static void stm32_usart_tx_dma_complete(void *arg) struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + unsigned long flags; + dmaengine_terminate_async(stm32port->tx_ch); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); stm32port->tx_dma_busy = false; /* Let's see if we have pending data to send */ + spin_lock_irqsave(&port->lock, flags); stm32_usart_transmit_chars(port); + spin_unlock_irqrestore(&port->lock, flags); } static void stm32_usart_tx_interrupt_enable(struct uart_port *port) @@ -303,7 +306,7 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port) * Enables TX FIFO threashold irq when FIFO is enabled, * or TX empty irq when FIFO is disabled */ - if (stm32_port->fifoen) + if (stm32_port->fifoen && stm32_port->txftcfg >= 0) stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); else stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); @@ -314,7 +317,7 @@ static void stm32_usart_tx_interrupt_disable(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - if (stm32_port->fifoen) + if (stm32_port->fifoen && stm32_port->txftcfg >= 0) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); else stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); @@ -455,29 +458,34 @@ static void stm32_usart_transmit_chars(struct uart_port *port) static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; - spin_lock(&port->lock); - sr = readl_relaxed(port->membase + ofs->isr); if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG) writel_relaxed(USART_ICR_RTOCF, port->membase + ofs->icr); - if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) + if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) { + /* Clear wake up flag and disable wake up interrupt */ writel_relaxed(USART_ICR_WUCF, port->membase + ofs->icr); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); + if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) + pm_wakeup_event(tport->tty->dev, 0); + } if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) stm32_usart_receive_chars(port, false); - if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) + if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { + spin_lock(&port->lock); stm32_usart_transmit_chars(port); - - spin_unlock(&port->lock); + spin_unlock(&port->lock); + } if (stm32_port->rx_ch) return IRQ_WAKE_THREAD; @@ -490,13 +498,9 @@ static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) struct uart_port *port = ptr; struct stm32_port *stm32_port = to_stm32_port(port); - spin_lock(&port->lock); - if (stm32_port->rx_ch) stm32_usart_receive_chars(port, true); - spin_unlock(&port->lock); - return IRQ_HANDLED; } @@ -505,7 +509,10 @@ static unsigned int stm32_usart_tx_empty(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; + if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) + return TIOCSER_TEMT; + + return 0; } static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -584,6 +591,19 @@ static void stm32_usart_start_tx(struct uart_port *port) stm32_usart_transmit_chars(port); } +/* Flush the transmit buffer. */ +static void stm32_usart_flush_buffer(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (stm32_port->tx_ch) { + dmaengine_terminate_async(stm32_port->tx_ch); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_port->tx_dma_busy = false; + } +} + /* Throttle the remote when input buffer is about to overflow. */ static void stm32_usart_throttle(struct uart_port *port) { @@ -634,33 +654,30 @@ static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; ret = request_threaded_irq(port->irq, stm32_usart_interrupt, stm32_usart_threaded_interrupt, - IRQF_NO_SUSPEND, name, port); + IRQF_ONESHOT | IRQF_NO_SUSPEND, + name, port); if (ret) return ret; + if (stm32_port->swap) { + val = readl_relaxed(port->membase + ofs->cr2); + val |= USART_CR2_SWAP; + writel_relaxed(val, port->membase + ofs->cr2); + } + /* RX FIFO Flush */ if (ofs->rqr != UNDEF_REG) - stm32_usart_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); + writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); - /* Tx and RX FIFO configuration */ - if (stm32_port->fifoen) { - val = readl_relaxed(port->membase + ofs->cr3); - val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK); - val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; - val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; - writel_relaxed(val, port->membase + ofs->cr3); - } - - /* RX FIFO enabling */ - val = stm32_port->cr1_irq | USART_CR1_RE; - if (stm32_port->fifoen) - val |= USART_CR1_FIFOEN; + /* RX enabling */ + val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); stm32_usart_set_bits(port, ofs->cr1, val); return 0; @@ -691,6 +708,11 @@ static void stm32_usart_shutdown(struct uart_port *port) if (ret) dev_err(port->dev, "Transmission is not complete\n"); + /* flush RX & TX FIFO */ + if (ofs->rqr != UNDEF_REG) + writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, + port->membase + ofs->rqr); + stm32_usart_clr_bits(port, ofs->cr1, val); free_irq(port->irq, port); @@ -737,8 +759,9 @@ static void stm32_usart_set_termios(struct uart_port *port, unsigned int baud, bits; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; - u32 cr1, cr2, cr3; + u32 cr1, cr2, cr3, isr; unsigned long flags; + int ret; if (!stm32_port->hw_flow_control) cflag &= ~CRTSCTS; @@ -747,21 +770,37 @@ static void stm32_usart_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TC), + 10, 100000); + + /* Send the TC error message only when ISR_TC is not set. */ + if (ret) + dev_err(port->dev, "Transmission is not complete\n"); + /* Stop serial port and reset value */ writel_relaxed(0, port->membase + ofs->cr1); /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) - stm32_usart_set_bits(port, ofs->rqr, - USART_RQR_TXFRQ | USART_RQR_RXFRQ); + writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, + port->membase + ofs->rqr); cr1 = USART_CR1_TE | USART_CR1_RE; if (stm32_port->fifoen) cr1 |= USART_CR1_FIFOEN; - cr2 = 0; + cr2 = stm32_port->swap ? USART_CR2_SWAP : 0; + + /* Tx and RX FIFO configuration */ cr3 = readl_relaxed(port->membase + ofs->cr3); - cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE - | USART_CR3_TXFTCFG_MASK; + cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; + if (stm32_port->fifoen) { + if (stm32_port->txftcfg >= 0) + cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT; + if (stm32_port->rxftcfg >= 0) + cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT; + } if (cflag & CSTOPB) cr2 |= USART_CR2_STOP_2B; @@ -790,7 +829,8 @@ static void stm32_usart_set_termios(struct uart_port *port, , bits); if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || - stm32_port->fifoen)) { + (stm32_port->fifoen && + stm32_port->rxftcfg >= 0))) { if (cflag & CSTOPB) bits = bits + 3; /* 1 start bit + 2 stop bits */ else @@ -817,12 +857,6 @@ static void stm32_usart_set_termios(struct uart_port *port, cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } - /* Handle modem control interrupts */ - if (UART_ENABLE_MS(port, termios->c_cflag)) - stm32_usart_enable_ms(port); - else - stm32_usart_disable_ms(port); - usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); /* @@ -892,12 +926,24 @@ static void stm32_usart_set_termios(struct uart_port *port, cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); } + /* Configure wake up from low power on start bit detection */ + if (stm32_port->wakeup_src) { + cr3 &= ~USART_CR3_WUS_MASK; + cr3 |= USART_CR3_WUS_START_BIT; + } + writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr2, port->membase + ofs->cr2); writel_relaxed(cr1, port->membase + ofs->cr1); stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); + + /* Handle modem control interrupts */ + if (UART_ENABLE_MS(port, termios->c_cflag)) + stm32_usart_enable_ms(port); + else + stm32_usart_disable_ms(port); } static const char *stm32_usart_type(struct uart_port *port) @@ -962,6 +1008,7 @@ static const struct uart_ops stm32_uart_ops = { .break_ctl = stm32_usart_break_ctl, .startup = stm32_usart_startup, .shutdown = stm32_usart_shutdown, + .flush_buffer = stm32_usart_flush_buffer, .set_termios = stm32_usart_set_termios, .pm = stm32_usart_pm, .type = stm32_usart_type, @@ -971,6 +1018,39 @@ static const struct uart_ops stm32_uart_ops = { .verify_port = stm32_usart_verify_port, }; +/* + * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG) + * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case, + * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE. + * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1. + */ +static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 }; + +static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p, + int *ftcfg) +{ + u32 bytes, i; + + /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */ + if (of_property_read_u32(pdev->dev.of_node, p, &bytes)) + bytes = 8; + + for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) + if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes) + break; + if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg)) + i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1; + + dev_dbg(&pdev->dev, "%s set to %d bytes\n", p, + stm32h7_usart_fifo_thresh_cfg[i]); + + /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */ + if (i) + *ftcfg = i - 1; + else + *ftcfg = -EINVAL; +} + static void stm32_usart_deinit_port(struct stm32_port *stm32port) { clk_disable_unprepare(stm32port->clk); @@ -1000,13 +1080,19 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, if (ret) return ret; - if (stm32port->info->cfg.has_wakeup) { - stm32port->wakeirq = platform_get_irq_optional(pdev, 1); - if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) - return stm32port->wakeirq ? : -ENODEV; - } + stm32port->wakeup_src = stm32port->info->cfg.has_wakeup && + of_property_read_bool(pdev->dev.of_node, "wakeup-source"); + + stm32port->swap = stm32port->info->cfg.has_swap && + of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"); stm32port->fifoen = stm32port->info->cfg.has_fifo; + if (stm32port->fifoen) { + stm32_usart_get_ftcfg(pdev, "rx-threshold", + &stm32port->rxftcfg); + stm32_usart_get_ftcfg(pdev, "tx-threshold", + &stm32port->txftcfg); + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->membase = devm_ioremap_resource(&pdev->dev, res); @@ -1106,6 +1192,13 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct dma_async_tx_descriptor *desc = NULL; int ret; + /* + * Using DMA and threaded handler for the console could lead to + * deadlocks. + */ + if (uart_console(port)) + return -ENODEV; + /* Request DMA RX channel */ stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); if (!stm32port->rx_ch) { @@ -1239,23 +1332,13 @@ static int stm32_usart_serial_probe(struct platform_device *pdev) if (ret) return ret; - if (stm32port->wakeirq > 0) { - ret = device_init_wakeup(&pdev->dev, true); - if (ret) - goto err_uninit; - - ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, - stm32port->wakeirq); + if (stm32port->wakeup_src) { + device_set_wakeup_capable(&pdev->dev, true); + ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq); if (ret) goto err_nowup; - - device_set_wakeup_enable(&pdev->dev, false); } - ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); - if (ret) - goto err_wirq; - ret = stm32_usart_of_dma_rx_probe(stm32port, pdev); if (ret) dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n"); @@ -1269,19 +1352,47 @@ static int stm32_usart_serial_probe(struct platform_device *pdev) pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); + if (ret) + goto err_port; + pm_runtime_put_sync(&pdev->dev); return 0; -err_wirq: - if (stm32port->wakeirq > 0) +err_port: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + if (stm32port->rx_ch) { + dmaengine_terminate_async(stm32port->rx_ch); + dma_release_channel(stm32port->rx_ch); + } + + if (stm32port->rx_dma_buf) + dma_free_coherent(&pdev->dev, + RX_BUF_L, stm32port->rx_buf, + stm32port->rx_dma_buf); + + if (stm32port->tx_ch) { + dmaengine_terminate_async(stm32port->tx_ch); + dma_release_channel(stm32port->tx_ch); + } + + if (stm32port->tx_dma_buf) + dma_free_coherent(&pdev->dev, + TX_BUF_L, stm32port->tx_buf, + stm32port->tx_dma_buf); + + if (stm32port->wakeup_src) dev_pm_clear_wake_irq(&pdev->dev); err_nowup: - if (stm32port->wakeirq > 0) - device_init_wakeup(&pdev->dev, false); + if (stm32port->wakeup_src) + device_set_wakeup_capable(&pdev->dev, false); -err_uninit: stm32_usart_deinit_port(stm32port); return ret; @@ -1295,11 +1406,20 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) int err; pm_runtime_get_sync(&pdev->dev); + err = uart_remove_one_port(&stm32_usart_driver, port); + if (err) + return(err); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + dmaengine_terminate_async(stm32_port->rx_ch); dma_release_channel(stm32_port->rx_ch); + } if (stm32_port->rx_dma_buf) dma_free_coherent(&pdev->dev, @@ -1308,27 +1428,24 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - if (stm32_port->tx_ch) + if (stm32_port->tx_ch) { + dmaengine_terminate_async(stm32_port->tx_ch); dma_release_channel(stm32_port->tx_ch); + } if (stm32_port->tx_dma_buf) dma_free_coherent(&pdev->dev, TX_BUF_L, stm32_port->tx_buf, stm32_port->tx_dma_buf); - if (stm32_port->wakeirq > 0) { + if (stm32_port->wakeup_src) { dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); } stm32_usart_deinit_port(stm32_port); - err = uart_remove_one_port(&stm32_usart_driver, port); - - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - - return err; + return 0; } #ifdef CONFIG_SERIAL_STM32_CONSOLE @@ -1354,13 +1471,10 @@ static void stm32_usart_console_write(struct console *co, const char *s, u32 old_cr1, new_cr1; int locked = 1; - local_irq_save(flags); - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&port->lock); + if (oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); else - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); /* Save and disable interrupts, enable the transmitter */ old_cr1 = readl_relaxed(port->membase + ofs->cr1); @@ -1374,8 +1488,7 @@ static void stm32_usart_console_write(struct console *co, const char *s, writel_relaxed(old_cr1, port->membase + ofs->cr1); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static int stm32_usart_console_setup(struct console *co, char *options) @@ -1436,23 +1549,20 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - const struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; - if (stm32_port->wakeirq <= 0) + if (!stm32_port->wakeup_src) return; + /* + * Enable low-power wake-up and wake-up irq if argument is set to + * "enable", disable low-power wake-up and wake-up irq otherwise + */ if (enable) { - stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); - val = readl_relaxed(port->membase + ofs->cr3); - val &= ~USART_CR3_WUS_MASK; - /* Enable Wake up interrupt from low power on start bit */ - val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; - writel_relaxed(val, port->membase + ofs->cr3); - stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); } else { stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } } @@ -1462,10 +1572,8 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev) || device_wakeup_path(dev)) stm32_usart_serial_en_wakeup(port, true); - else - stm32_usart_serial_en_wakeup(port, false); /* * When "no_console_suspend" is enabled, keep the pinctrl default state @@ -1474,7 +1582,7 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) * capabilities. */ if (console_suspend_enabled || !uart_console(port)) { - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev) || device_wakeup_path(dev)) pinctrl_pm_select_idle_state(dev); else pinctrl_pm_select_sleep_state(dev); @@ -1489,7 +1597,7 @@ static int __maybe_unused stm32_usart_serial_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev) || device_wakeup_path(dev)) stm32_usart_serial_en_wakeup(port, false); return uart_resume_port(&stm32_usart_driver, port); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index cb4f327c46db992140ecf13e2f4b4e4f8958304d..07ac291328cda85359dd9a78441ffb553368ff44 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -25,6 +25,7 @@ struct stm32_usart_offsets { struct stm32_usart_config { u8 uart_enable_bit; /* USART_CR1_UE */ bool has_7bits_data; + bool has_swap; bool has_wakeup; bool has_fifo; int fifosize; @@ -76,6 +77,7 @@ struct stm32_usart_info stm32f7_info = { .cfg = { .uart_enable_bit = 0, .has_7bits_data = true, + .has_swap = true, .fifosize = 1, } }; @@ -97,6 +99,7 @@ struct stm32_usart_info stm32h7_info = { .cfg = { .uart_enable_bit = 0, .has_7bits_data = true, + .has_swap = true, .has_wakeup = true, .has_fifo = true, .fifosize = 16, @@ -127,9 +130,6 @@ struct stm32_usart_info stm32h7_info = { /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) -/* USART_ICR (F7) */ -#define USART_CR_TC BIT(6) - /* USART_DR */ #define USART_DR_MASK GENMASK(8, 0) @@ -216,12 +216,6 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */ #define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */ -/* TX FIFO threashold set to half of its depth */ -#define USART_CR3_TXFTCFG_HALF 0x2 - -/* RX FIFO threashold set to half of its depth */ -#define USART_CR3_RXFTCFG_HALF 0x2 - /* USART_GTPR */ #define USART_GTPR_PSC_MASK GENMASK(7, 0) #define USART_GTPR_GT_MASK GENMASK(15, 8) @@ -271,8 +265,11 @@ struct stm32_port { int last_res; bool tx_dma_busy; /* dma tx busy */ bool hw_flow_control; + bool swap; /* swap RX & TX pins */ bool fifoen; - int wakeirq; + int rxftcfg; /* RX FIFO threshold CFG */ + int txftcfg; /* TX FIFO threshold CFG */ + bool wakeup_src; int rdr_mask; /* receive data register mask */ struct mctrl_gpios *gpios; /* modem control gpios */ }; diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 319e5ceb6130e2bee8a1ccc60e6a590c83a68ef9..12c2468f2b0e22b565f80a2d6b73e68e6ce148ff 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -466,12 +466,8 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) if (status & UART_LSR_THRE) transmit_chars(up); - spin_unlock_irqrestore(&up->port.lock, flags); - tty_flip_buffer_push(&up->port.state->port); - spin_lock_irqsave(&up->port.lock, flags); - } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); spin_unlock_irqrestore(&up->port.lock, flags); diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index aaf8748a614791650b9a830cc5ae2d86dd523a59..52687c65ad7455e18c0795001e3c5e945a42bda9 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -282,6 +282,7 @@ static const struct of_device_id tegra_tcu_match[] = { { .compatible = "nvidia,tegra194-tcu" }, { } }; +MODULE_DEVICE_TABLE(of, tegra_tcu_match); static struct platform_driver tegra_tcu_driver = { .driver = { diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 2126e6e6dfd162fd8b7c2f5e699bb98ed88dcde5..08941eabe7b14c21cc3c8fa5a7bd5f7de2608273 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -87,9 +87,7 @@ static void timbuart_rx_chars(struct uart_port *port) tty_insert_flip_char(tport, ch, TTY_NORMAL); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); dev_dbg(port->dev, "%s - total read %d bytes\n", __func__, port->icount.rx); diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index d6a8604157aba00a2182eb98e4fc81bbfd9182ac..f81261cb52b8c283dc46d96149dbfb55b52ff3dd 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -261,11 +261,11 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) struct qe_bd *bdp = qe_port->tx_bd_base; while (1) { - if (qe_ioread16be(&bdp->status) & BD_SC_READY) + if (ioread16be(&bdp->status) & BD_SC_READY) /* This BD is not done, so return "not done" */ return 0; - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) /* * This BD is done and it's the last one, so return * "done" @@ -344,10 +344,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); *p++ = port->x_char; - qe_iowrite16be(1, &bdp->length); + iowrite16be(1, &bdp->length); qe_setbits_be16(&bdp->status, BD_SC_READY); /* Get next BD. */ - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) bdp = qe_port->tx_bd_base; else bdp++; @@ -366,7 +366,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) /* Pick next descriptor and fill from buffer */ bdp = qe_port->tx_cur; - while (!(qe_ioread16be(&bdp->status) & BD_SC_READY) && + while (!(ioread16be(&bdp->status) & BD_SC_READY) && (xmit->tail != xmit->head)) { count = 0; p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); @@ -379,11 +379,11 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) break; } - qe_iowrite16be(count, &bdp->length); + iowrite16be(count, &bdp->length); qe_setbits_be16(&bdp->status, BD_SC_READY); /* Get next BD. */ - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) bdp = qe_port->tx_bd_base; else bdp++; @@ -416,7 +416,7 @@ static void qe_uart_start_tx(struct uart_port *port) container_of(port, struct uart_qe_port, port); /* If we currently are transmitting, then just return */ - if (qe_ioread16be(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) + if (ioread16be(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) return; /* Otherwise, pump the port and start transmission */ @@ -471,14 +471,14 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) */ bdp = qe_port->rx_cur; while (1) { - status = qe_ioread16be(&bdp->status); + status = ioread16be(&bdp->status); /* If this one is empty, then we assume we've read them all */ if (status & BD_SC_EMPTY) break; /* get number of characters, and check space in RX buffer */ - i = qe_ioread16be(&bdp->length); + i = ioread16be(&bdp->length); /* If we don't have enough room in RX buffer for the entire BD, * then we try later, which will be the next RX interrupt. @@ -512,7 +512,7 @@ error_return: qe_clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID, BD_SC_EMPTY); - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) bdp = qe_port->rx_bd_base; else bdp++; @@ -569,8 +569,8 @@ static irqreturn_t qe_uart_int(int irq, void *data) u16 events; /* Clear the interrupts */ - events = qe_ioread16be(&uccp->ucce); - qe_iowrite16be(events, &uccp->ucce); + events = ioread16be(&uccp->ucce); + iowrite16be(events, &uccp->ucce); if (events & UCC_UART_UCCE_BRKE) uart_handle_break(&qe_port->port); @@ -601,17 +601,17 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) bdp = qe_port->rx_bd_base; qe_port->rx_cur = qe_port->rx_bd_base; for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) { - qe_iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); bd_virt += qe_port->rx_fifosize; bdp++; } /* */ - qe_iowrite16be(BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -622,9 +622,9 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) qe_port->tx_cur = qe_port->tx_bd_base; bdp = qe_port->tx_bd_base; for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) { - qe_iowrite16be(BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); bd_virt += qe_port->tx_fifosize; bdp++; } @@ -634,9 +634,9 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) qe_setbits_be16(&qe_port->tx_cur->status, BD_SC_P); #endif - qe_iowrite16be(BD_SC_WRAP | BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_WRAP | BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); } /* @@ -658,21 +658,21 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); /* Program the UCC UART parameter RAM */ - qe_iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.rbmr); - qe_iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.tbmr); - qe_iowrite16be(qe_port->rx_fifosize, &uccup->common.mrblr); - qe_iowrite16be(0x10, &uccup->maxidl); - qe_iowrite16be(1, &uccup->brkcr); - qe_iowrite16be(0, &uccup->parec); - qe_iowrite16be(0, &uccup->frmec); - qe_iowrite16be(0, &uccup->nosec); - qe_iowrite16be(0, &uccup->brkec); - qe_iowrite16be(0, &uccup->uaddr[0]); - qe_iowrite16be(0, &uccup->uaddr[1]); - qe_iowrite16be(0, &uccup->toseq); + iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.rbmr); + iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.tbmr); + iowrite16be(qe_port->rx_fifosize, &uccup->common.mrblr); + iowrite16be(0x10, &uccup->maxidl); + iowrite16be(1, &uccup->brkcr); + iowrite16be(0, &uccup->parec); + iowrite16be(0, &uccup->frmec); + iowrite16be(0, &uccup->nosec); + iowrite16be(0, &uccup->brkec); + iowrite16be(0, &uccup->uaddr[0]); + iowrite16be(0, &uccup->uaddr[1]); + iowrite16be(0, &uccup->toseq); for (i = 0; i < 8; i++) - qe_iowrite16be(0xC000, &uccup->cchars[i]); - qe_iowrite16be(0xc0ff, &uccup->rccm); + iowrite16be(0xC000, &uccup->cchars[i]); + iowrite16be(0xc0ff, &uccup->rccm); /* Configure the GUMR registers for UART */ if (soft_uart) { @@ -702,30 +702,30 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) #endif /* Disable rx interrupts and clear all pending events. */ - qe_iowrite16be(0, &uccp->uccm); - qe_iowrite16be(0xffff, &uccp->ucce); - qe_iowrite16be(0x7e7e, &uccp->udsr); + iowrite16be(0, &uccp->uccm); + iowrite16be(0xffff, &uccp->ucce); + iowrite16be(0x7e7e, &uccp->udsr); /* Initialize UPSMR */ - qe_iowrite16be(0, &uccp->upsmr); + iowrite16be(0, &uccp->upsmr); if (soft_uart) { - qe_iowrite16be(0x30, &uccup->supsmr); - qe_iowrite16be(0, &uccup->res92); - qe_iowrite32be(0, &uccup->rx_state); - qe_iowrite32be(0, &uccup->rx_cnt); - qe_iowrite8(0, &uccup->rx_bitmark); - qe_iowrite8(10, &uccup->rx_length); - qe_iowrite32be(0x4000, &uccup->dump_ptr); - qe_iowrite8(0, &uccup->rx_temp_dlst_qe); - qe_iowrite32be(0, &uccup->rx_frame_rem); - qe_iowrite8(0, &uccup->rx_frame_rem_size); + iowrite16be(0x30, &uccup->supsmr); + iowrite16be(0, &uccup->res92); + iowrite32be(0, &uccup->rx_state); + iowrite32be(0, &uccup->rx_cnt); + iowrite8(0, &uccup->rx_bitmark); + iowrite8(10, &uccup->rx_length); + iowrite32be(0x4000, &uccup->dump_ptr); + iowrite8(0, &uccup->rx_temp_dlst_qe); + iowrite32be(0, &uccup->rx_frame_rem); + iowrite8(0, &uccup->rx_frame_rem_size); /* Soft-UART requires TX to be 1X */ - qe_iowrite8(UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1, + iowrite8(UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1, &uccup->tx_mode); - qe_iowrite16be(0, &uccup->tx_state); - qe_iowrite8(0, &uccup->resD4); - qe_iowrite16be(0, &uccup->resD5); + iowrite16be(0, &uccup->tx_state); + iowrite8(0, &uccup->resD4); + iowrite16be(0, &uccup->resD5); /* Set UART mode. * Enable receive and transmit. @@ -850,9 +850,9 @@ static void qe_uart_set_termios(struct uart_port *port, struct ucc_slow __iomem *uccp = qe_port->uccp; unsigned int baud; unsigned long flags; - u16 upsmr = qe_ioread16be(&uccp->upsmr); + u16 upsmr = ioread16be(&uccp->upsmr); struct ucc_uart_pram __iomem *uccup = qe_port->uccup; - u16 supsmr = qe_ioread16be(&uccup->supsmr); + u16 supsmr = ioread16be(&uccup->supsmr); u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */ /* Character length programmed into the mode register is the @@ -950,10 +950,10 @@ static void qe_uart_set_termios(struct uart_port *port, /* Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); - qe_iowrite16be(upsmr, &uccp->upsmr); + iowrite16be(upsmr, &uccp->upsmr); if (soft_uart) { - qe_iowrite16be(supsmr, &uccup->supsmr); - qe_iowrite8(char_length, &uccup->rx_length); + iowrite16be(supsmr, &uccup->supsmr); + iowrite8(char_length, &uccup->rx_length); /* Soft-UART requires a 1X multiplier for TX */ qe_setbrg(qe_port->us_info.rx_clock, baud, 16); diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 764e992438b2042419fe89e55ca92f567b28dc05..c5edd56ff83019f6d608a360d39af87396e272f2 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -184,9 +184,7 @@ static void handle_rx(struct uart_port *port) tty_insert_flip_char(tport, c, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static void handle_tx(struct uart_port *port) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index a14c5d9964739c9ade73bdbdd1d68391a13f1eab..67a2db621e2b7669e007bdc7e3d4ab0731b7c9d2 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -301,9 +301,8 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) tty_insert_flip_char(&port->state->port, data, status); isrstatus = 0; } - spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } /** diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 644173786bf0decb29e472390129aeb240d21833..5523cf7bd1c27490a392da141c138ec71df28d1a 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -137,37 +137,14 @@ MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); */ static struct tty_driver *serial_driver; -static int open(struct tty_struct *tty, struct file * filp); -static void close(struct tty_struct *tty, struct file * filp); -static void hangup(struct tty_struct *tty); -static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); - -static int write(struct tty_struct *tty, const unsigned char *buf, int count); -static int put_char(struct tty_struct *tty, unsigned char ch); -static void send_xchar(struct tty_struct *tty, char ch); static void wait_until_sent(struct tty_struct *tty, int timeout); -static int write_room(struct tty_struct *tty); -static void flush_chars(struct tty_struct *tty); static void flush_buffer(struct tty_struct *tty); -static void tx_hold(struct tty_struct *tty); static void tx_release(struct tty_struct *tty); -static int ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int chars_in_buffer(struct tty_struct *tty); -static void throttle(struct tty_struct * tty); -static void unthrottle(struct tty_struct * tty); -static int set_break(struct tty_struct *tty, int break_state); - /* - * generic HDLC support and callbacks + * generic HDLC support */ -#if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) -static void hdlcdev_tx_done(struct slgt_info *info); -static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); -static int hdlcdev_init(struct slgt_info *info); -static void hdlcdev_exit(struct slgt_info *info); -#endif /* @@ -186,9 +163,6 @@ struct cond_wait { wait_queue_entry_t wait; unsigned int data; }; -static void init_cond_wait(struct cond_wait *w, unsigned int data); -static void add_cond_wait(struct cond_wait **head, struct cond_wait *w); -static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w); static void flush_cond_wait(struct cond_wait **head); /* @@ -443,12 +417,8 @@ static void shutdown(struct slgt_info *info); static void program_hw(struct slgt_info *info); static void change_params(struct slgt_info *info); -static int register_test(struct slgt_info *info); -static int irq_test(struct slgt_info *info); -static int loopback_test(struct slgt_info *info); static int adapter_test(struct slgt_info *info); -static void reset_adapter(struct slgt_info *info); static void reset_port(struct slgt_info *info); static void async_mode(struct slgt_info *info); static void sync_mode(struct slgt_info *info); @@ -457,14 +427,12 @@ static void rx_stop(struct slgt_info *info); static void rx_start(struct slgt_info *info); static void reset_rbufs(struct slgt_info *info); static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); -static void rdma_reset(struct slgt_info *info); static bool rx_get_frame(struct slgt_info *info); static bool rx_get_buf(struct slgt_info *info); static void tx_start(struct slgt_info *info); static void tx_stop(struct slgt_info *info); static void tx_set_idle(struct slgt_info *info); -static unsigned int free_tbuf_count(struct slgt_info *info); static unsigned int tbuf_bytes(struct slgt_info *info); static void reset_tbufs(struct slgt_info *info); static void tdma_reset(struct slgt_info *info); @@ -472,26 +440,10 @@ static bool tx_load(struct slgt_info *info, const char *buf, unsigned int count) static void get_signals(struct slgt_info *info); static void set_signals(struct slgt_info *info); -static void enable_loopback(struct slgt_info *info); static void set_rate(struct slgt_info *info, u32 data_rate); -static int bh_action(struct slgt_info *info); -static void bh_handler(struct work_struct *work); static void bh_transmit(struct slgt_info *info); -static void isr_serial(struct slgt_info *info); -static void isr_rdma(struct slgt_info *info); static void isr_txeom(struct slgt_info *info, unsigned short status); -static void isr_tdma(struct slgt_info *info); - -static int alloc_dma_bufs(struct slgt_info *info); -static void free_dma_bufs(struct slgt_info *info); -static int alloc_desc(struct slgt_info *info); -static void free_desc(struct slgt_info *info); -static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); -static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); - -static int alloc_tmp_rbuf(struct slgt_info *info); -static void free_tmp_rbuf(struct slgt_info *info); static void tx_timeout(struct timer_list *t); static void rx_timeout(struct timer_list *t); @@ -509,10 +461,6 @@ static int tx_abort(struct slgt_info *info); static int rx_enable(struct slgt_info *info, int enable); static int modem_input_wait(struct slgt_info *info,int arg); static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr); -static int tiocmget(struct tty_struct *tty); -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int set_break(struct tty_struct *tty, int break_state); static int get_interface(struct slgt_info *info, int __user *if_mode); static int set_interface(struct slgt_info *info, int if_mode); static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); @@ -526,9 +474,6 @@ static int set_xctrl(struct slgt_info *info, int if_mode); /* * driver functions */ -static void add_device(struct slgt_info *info); -static void device_init(int adapter_num, struct pci_dev *pdev); -static int claim_resources(struct slgt_info *info); static void release_resources(struct slgt_info *info); /* @@ -3566,8 +3511,6 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev info->max_frame_size = 4096; info->base_clock = 14745600; info->rbuf_fill_level = DMABUFSIZE; - info->port.close_delay = 5*HZ/10; - info->port.closing_wait = 30*HZ; init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->netlock); @@ -3705,7 +3648,6 @@ static const struct tty_operations ops = { static void slgt_cleanup(void) { - int rc; struct slgt_info *info; struct slgt_info *tmp; @@ -3714,9 +3656,7 @@ static void slgt_cleanup(void) if (serial_driver) { for (info=slgt_device_list ; info != NULL ; info=info->next_device) tty_unregister_device(serial_driver, info->line); - rc = tty_unregister_driver(serial_driver); - if (rc) - DBGERR(("tty_unregister_driver error=%d\n", rc)); + tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); } @@ -5018,7 +4958,7 @@ static int loopback_test(struct slgt_info *info) #define TESTFRAMESIZE 20 unsigned long timeout; - u16 count = TESTFRAMESIZE; + u16 count; unsigned char buf[TESTFRAMESIZE]; int rc = -ENODEV; unsigned long flags; diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 8f01cde61d20a29591cbd22b9daf85f3b5adf77d..193e6c3391251252965237f74fa70251a59c7d55 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -120,6 +120,7 @@ static const struct sysrq_key_op sysrq_loglevel_op = { static void sysrq_handle_SAK(int key) { struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; + schedule_work(SAK_work); } static const struct sysrq_key_op sysrq_SAK_op = { @@ -551,22 +552,22 @@ static int sysrq_key_table_key2index(int key) */ static const struct sysrq_key_op *__sysrq_get_key_op(int key) { - const struct sysrq_key_op *op_p = NULL; - int i; + const struct sysrq_key_op *op_p = NULL; + int i; i = sysrq_key_table_key2index(key); if (i != -1) - op_p = sysrq_key_table[i]; + op_p = sysrq_key_table[i]; - return op_p; + return op_p; } static void __sysrq_put_key_op(int key, const struct sysrq_key_op *op_p) { - int i = sysrq_key_table_key2index(key); + int i = sysrq_key_table_key2index(key); - if (i != -1) - sysrq_key_table[i] = op_p; + if (i != -1) + sysrq_key_table[i] = op_p; } void __handle_sysrq(int key, bool check_mask) @@ -590,8 +591,8 @@ void __handle_sysrq(int key, bool check_mask) orig_log_level = console_loglevel; console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; - op_p = __sysrq_get_key_op(key); - if (op_p) { + op_p = __sysrq_get_key_op(key); + if (op_p) { /* * Should we check for enabled operations (/proc/sysrq-trigger * should not) and is the invoked operation enabled? @@ -640,13 +641,13 @@ static int sysrq_reset_downtime_ms; /* Simple translation table for the SysRq keys */ static const unsigned char sysrq_xlate[KEY_CNT] = - "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ - "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ - "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ - "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ - "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ - "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ - "\r\000/"; /* 0x60 - 0x6f */ + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ struct sysrq_state { struct input_handle handle; @@ -1111,7 +1112,7 @@ int sysrq_toggle_support(int enable_mask) EXPORT_SYMBOL_GPL(sysrq_toggle_support); static int __sysrq_swap_key_ops(int key, const struct sysrq_key_op *insert_op_p, - const struct sysrq_key_op *remove_op_p) + const struct sysrq_key_op *remove_op_p) { int retval; diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h new file mode 100644 index 0000000000000000000000000000000000000000..b710c5ef89ab2f5939869dacaa73f383628d60e1 --- /dev/null +++ b/drivers/tty/tty.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * TTY core internal functions + */ + +#ifndef _TTY_INTERNAL_H +#define _TTY_INTERNAL_H + +#define tty_msg(fn, tty, f, ...) \ + fn("%s %s: " f, tty_driver_name(tty), tty_name(tty), ##__VA_ARGS__) + +#define tty_debug(tty, f, ...) tty_msg(pr_debug, tty, f, ##__VA_ARGS__) +#define tty_notice(tty, f, ...) tty_msg(pr_notice, tty, f, ##__VA_ARGS__) +#define tty_warn(tty, f, ...) tty_msg(pr_warn, tty, f, ##__VA_ARGS__) +#define tty_err(tty, f, ...) tty_msg(pr_err, tty, f, ##__VA_ARGS__) + +#define tty_info_ratelimited(tty, f, ...) \ + tty_msg(pr_info_ratelimited, tty, f, ##__VA_ARGS__) + +/* + * Lock subclasses for tty locks + * + * TTY_LOCK_NORMAL is for normal ttys and master ptys. + * TTY_LOCK_SLAVE is for slave ptys only. + * + * Lock subclasses are necessary for handling nested locking with pty pairs. + * tty locks which use nested locking: + * + * legacy_mutex - Nested tty locks are necessary for releasing pty pairs. + * The stable lock order is master pty first, then slave pty. + * termios_rwsem - The stable lock order is tty_buffer lock->termios_rwsem. + * Subclassing this lock enables the slave pty to hold its + * termios_rwsem when claiming the master tty_buffer lock. + * tty_buffer lock - slave ptys can claim nested buffer lock when handling + * signal chars. The stable lock order is slave pty, then + * master. + */ +enum { + TTY_LOCK_NORMAL = 0, + TTY_LOCK_SLAVE, +}; + +/* Values for tty->flow_change */ +#define TTY_THROTTLE_SAFE 1 +#define TTY_UNTHROTTLE_SAFE 2 + +static inline void __tty_set_flow_change(struct tty_struct *tty, int val) +{ + tty->flow_change = val; +} + +static inline void tty_set_flow_change(struct tty_struct *tty, int val) +{ + tty->flow_change = val; + smp_mb(); +} + +int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout); +void tty_ldisc_unlock(struct tty_struct *tty); + +int __tty_check_change(struct tty_struct *tty, int sig); +int tty_check_change(struct tty_struct *tty); +void __stop_tty(struct tty_struct *tty); +void __start_tty(struct tty_struct *tty); +void tty_vhangup_session(struct tty_struct *tty); +void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty); +int tty_signal_session_leader(struct tty_struct *tty, int exit_session); +void session_clear_tty(struct pid *session); +void tty_buffer_free_all(struct tty_port *port); +void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); +void tty_buffer_init(struct tty_port *port); +void tty_buffer_set_lock_subclass(struct tty_port *port); +bool tty_buffer_restart_work(struct tty_port *port); +bool tty_buffer_cancel_work(struct tty_port *port); +void tty_buffer_flush_work(struct tty_port *port); +speed_t tty_termios_input_baud_rate(struct ktermios *termios); +void tty_ldisc_hangup(struct tty_struct *tty, bool reset); +int tty_ldisc_reinit(struct tty_struct *tty, int disc); +long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +long tty_jobctrl_ioctl(struct tty_struct *tty, struct tty_struct *real_tty, + struct file *file, unsigned int cmd, unsigned long arg); +void tty_default_fops(struct file_operations *fops); +struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx); +int tty_alloc_file(struct file *file); +void tty_add_file(struct tty_struct *tty, struct file *file); +void tty_free_file(struct file *file); +int tty_release(struct inode *inode, struct file *filp); + +#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) + +int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); +void tty_ldisc_release(struct tty_struct *tty); +int __must_check tty_ldisc_init(struct tty_struct *tty); +void tty_ldisc_deinit(struct tty_struct *tty); + +void tty_sysctl_init(void); + +/* tty_audit.c */ +#ifdef CONFIG_AUDIT +void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size); +void tty_audit_tiocsti(struct tty_struct *tty, char ch); +#else +static inline void tty_audit_add_data(struct tty_struct *tty, const void *data, + size_t size) +{ +} +static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch) +{ +} +#endif + +ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *); + +#endif diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index 32898aabcd068a124397a10f22b0b553355c7387..ca7afd7b27165d27384b2d799a1f417b77f810a4 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -10,6 +10,7 @@ #include <linux/audit.h> #include <linux/slab.h> #include <linux/tty.h> +#include "tty.h" struct tty_audit_buf { struct mutex mutex; /* Protects all data below */ diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 6551b188b736b888fb69def69d9f2682e8264285..48b5de659c77f2f9775de9da0222d0f68300c97e 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -8,6 +8,7 @@ #include <linux/termios.h> #include <linux/tty.h> #include <linux/export.h> +#include "tty.h" /* diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6d4995a5f3187cf083e22dfaa4aa58f856fbeacd..9733469a14b2ccacdbc2401ac6de5cf16529edb5 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -17,7 +17,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/ratelimit.h> - +#include "tty.h" #define MIN_TTYB_SIZE 256 #define TTYB_ALIGN_MASK 255 diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 391bada4cedb62f765af58a8e38c2440a02b9ff4..5b5e99604989d485f02118a6c9e0746e26bb5e82 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -108,6 +108,7 @@ #include <linux/kmod.h> #include <linux/nsproxy.h> +#include "tty.h" #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP @@ -546,7 +547,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); * This is available to the pty code so if the master closes, if the * slave is a redirect it can release the redirect. */ -struct file *tty_release_redirect(struct tty_struct *tty) +static struct file *tty_release_redirect(struct tty_struct *tty) { struct file *f = NULL; @@ -559,7 +560,6 @@ struct file *tty_release_redirect(struct tty_struct *tty) return f; } -EXPORT_SYMBOL_GPL(tty_release_redirect); /** * __tty_hangup - actual handler for hangup events @@ -1195,8 +1195,6 @@ int tty_send_xchar(struct tty_struct *tty, char ch) return 0; } -static char ptychar[] = "pqrstuvwxyzabcde"; - /** * pty_line_name - generate name for a pty * @driver: the tty driver in use @@ -1210,6 +1208,7 @@ static char ptychar[] = "pqrstuvwxyzabcde"; */ static void pty_line_name(struct tty_driver *driver, int index, char *p) { + static const char ptychar[] = "pqrstuvwxyzabcde"; int i = index + driver->name_base; /* ->name is initialized to "ttyp", but "tty" is expected */ sprintf(p, "%s%c%x", @@ -2530,14 +2529,14 @@ out: * @p: pointer to result * * Obtain the modem status bits from the tty driver if the feature - * is supported. Return -EINVAL if it is not available. + * is supported. Return -ENOTTY if it is not available. * * Locking: none (up to the driver) */ static int tty_tiocmget(struct tty_struct *tty, int __user *p) { - int retval = -EINVAL; + int retval = -ENOTTY; if (tty->ops->tiocmget) { retval = tty->ops->tiocmget(tty); @@ -2555,7 +2554,7 @@ static int tty_tiocmget(struct tty_struct *tty, int __user *p) * @p: pointer to desired bits * * Set the modem status bits from the tty driver if the feature - * is supported. Return -EINVAL if it is not available. + * is supported. Return -ENOTTY if it is not available. * * Locking: none (up to the driver) */ @@ -2567,7 +2566,7 @@ static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, unsigned int set, clear, val; if (tty->ops->tiocmset == NULL) - return -EINVAL; + return -ENOTTY; retval = get_user(val, p); if (retval) @@ -2607,7 +2606,7 @@ int tty_get_icount(struct tty_struct *tty, if (tty->ops->get_icount) return tty->ops->get_icount(tty, icount); else - return -EINVAL; + return -ENOTTY; } EXPORT_SYMBOL_GPL(tty_get_icount); @@ -2625,26 +2624,31 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) return 0; } -static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss) +static int tty_set_serial(struct tty_struct *tty, struct serial_struct *ss) { - static DEFINE_RATELIMIT_STATE(depr_flags, - DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); char comm[TASK_COMM_LEN]; - struct serial_struct v; int flags; - if (copy_from_user(&v, ss, sizeof(*ss))) - return -EFAULT; + flags = ss->flags & ASYNC_DEPRECATED; - flags = v.flags & ASYNC_DEPRECATED; + if (flags) + pr_warn_ratelimited("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", + __func__, get_task_comm(comm, current), flags); - if (flags && __ratelimit(&depr_flags)) - pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", - __func__, get_task_comm(comm, current), flags); if (!tty->ops->set_serial) return -ENOTTY; - return tty->ops->set_serial(tty, &v); + + return tty->ops->set_serial(tty, ss); +} + +static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss) +{ + struct serial_struct v; + + if (copy_from_user(&v, ss, sizeof(*ss))) + return -EFAULT; + + return tty_set_serial(tty, &v); } static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *ss) @@ -2842,13 +2846,8 @@ struct serial_struct32 { static int compat_tty_tiocsserial(struct tty_struct *tty, struct serial_struct32 __user *ss) { - static DEFINE_RATELIMIT_STATE(depr_flags, - DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - char comm[TASK_COMM_LEN]; struct serial_struct32 v32; struct serial_struct v; - int flags; if (copy_from_user(&v32, ss, sizeof(*ss))) return -EFAULT; @@ -2859,14 +2858,7 @@ static int compat_tty_tiocsserial(struct tty_struct *tty, v.port_high = v32.port_high; v.iomap_base = 0; - flags = v.flags & ASYNC_DEPRECATED; - - if (flags && __ratelimit(&depr_flags)) - pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", - __func__, get_task_comm(comm, current), flags); - if (!tty->ops->set_serial) - return -ENOTTY; - return tty->ops->set_serial(tty, &v); + return tty_set_serial(tty, &v); } static int compat_tty_tiocgserial(struct tty_struct *tty, @@ -3524,21 +3516,14 @@ EXPORT_SYMBOL(tty_register_driver); /* * Called by a tty driver to unregister itself. */ -int tty_unregister_driver(struct tty_driver *driver) +void tty_unregister_driver(struct tty_driver *driver) { -#if 0 - /* FIXME */ - if (driver->refcount) - return -EBUSY; -#endif unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); - return 0; } - EXPORT_SYMBOL(tty_unregister_driver); dev_t tty_devnum(struct tty_struct *tty) diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 4de1c6ddb8ffb24a428f22c1fc133b71763f8f5c..41f7449d04642ee9426181f922b8ce340c08dc45 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -21,6 +21,7 @@ #include <linux/bitops.h> #include <linux/mutex.h> #include <linux/compat.h> +#include "tty.h" #include <asm/io.h> #include <linux/uaccess.h> @@ -57,8 +58,7 @@ int tty_chars_in_buffer(struct tty_struct *tty) { if (tty->ops->chars_in_buffer) return tty->ops->chars_in_buffer(tty); - else - return 0; + return 0; } EXPORT_SYMBOL(tty_chars_in_buffer); @@ -774,8 +774,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, case TCSETX: case TCSETXW: case TCSETXF: - return -EINVAL; -#endif + return -ENOTTY; +#endif case TIOCGSOFTCAR: copy_termios(real_tty, &kterm); ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0, diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index 4b751b9285add6fe370153dac1e4c8c352242143..7813dc910a19a84d1539a6428f34a1d83b21838f 100644 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -11,6 +11,7 @@ #include <linux/tty.h> #include <linux/fcntl.h> #include <linux/uaccess.h> +#include "tty.h" static int is_ignored(int sig) { @@ -75,6 +76,7 @@ void proc_clear_tty(struct task_struct *p) { unsigned long flags; struct tty_struct *tty; + spin_lock_irqsave(&p->sighand->siglock, flags); tty = p->signal->tty; p->signal->tty = NULL; @@ -173,6 +175,7 @@ EXPORT_SYMBOL_GPL(get_current_tty); void session_clear_tty(struct pid *session) { struct task_struct *p; + do_each_pid_task(session, PIDTYPE_SID, p) { proc_clear_tty(p); } while_each_pid_task(session, PIDTYPE_SID, p); @@ -202,8 +205,10 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session) spin_lock_irq(&p->sighand->siglock); if (p->signal->tty == tty) { p->signal->tty = NULL; - /* We defer the dereferences outside fo - the tasklist lock */ + /* + * We defer the dereferences outside of + * the tasklist lock. + */ refs++; } if (!p->signal->leader) { @@ -240,10 +245,10 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session) * it wants to disassociate itself from its controlling tty. * * It performs the following functions: - * (1) Sends a SIGHUP and SIGCONT to the foreground process group - * (2) Clears the tty from being controlling the session - * (3) Clears the controlling tty for all processes in the - * session group. + * (1) Sends a SIGHUP and SIGCONT to the foreground process group + * (2) Clears the tty from being controlling the session + * (3) Clears the controlling tty for all processes in the + * session group. * * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. @@ -269,6 +274,7 @@ void disassociate_ctty(int on_exit) tty_vhangup_session(tty); } else { struct pid *tty_pgrp = tty_get_pgrp(tty); + if (tty_pgrp) { kill_pgrp(tty_pgrp, SIGHUP, on_exit); if (!on_exit) @@ -280,6 +286,7 @@ void disassociate_ctty(int on_exit) } else if (on_exit) { struct pid *old_pgrp; + spin_lock_irq(¤t->sighand->siglock); old_pgrp = current->signal->tty_old_pgrp; current->signal->tty_old_pgrp = NULL; @@ -324,10 +331,13 @@ void disassociate_ctty(int on_exit) */ void no_tty(void) { - /* FIXME: Review locking here. The tty_lock never covered any race - between a new association and proc_clear_tty but possible we need - to protect against this anyway */ + /* + * FIXME: Review locking here. The tty_lock never covered any race + * between a new association and proc_clear_tty but possibly we need + * to protect against this anyway. + */ struct task_struct *tsk = current; + disassociate_ctty(0); proc_clear_tty(tsk); } @@ -531,7 +541,7 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. - */ + */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 1ba74d6f5e5cdf8770f62a8f4786bef88ee4c8c5..03f414172f34d85d9a7b35bd687d2a2c1fcc5b62 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -19,6 +19,7 @@ #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/ratelimit.h> +#include "tty.h" #undef LDISC_DEBUG_HANGUP @@ -147,7 +148,7 @@ static int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD); * Returns: -EINVAL if the discipline index is not [N_TTY..NR_LDISCS] or * if the discipline is not registered * -EAGAIN if request_module() failed to load or register the - * the discipline + * discipline * -ENOMEM if allocation failure * * Otherwise, returns a pointer to the discipline and bumps the @@ -459,7 +460,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); if (ld->ops->open) { int ret; - /* BTM here locks versus a hangup event */ + /* BTM here locks versus a hangup event */ ret = ld->ops->open(tty); if (ret) clear_bit(TTY_LDISC_OPEN, &tty->flags); @@ -508,7 +509,8 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld) return PTR_ERR(disc); tty->ldisc = disc; tty_set_termios_ldisc(tty, ld); - if ((r = tty_ldisc_open(tty, disc)) < 0) + r = tty_ldisc_open(tty, disc); + if (r < 0) tty_ldisc_put(disc); return r; } @@ -529,9 +531,11 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) const char *name = tty_name(tty); pr_warn("Falling back ldisc for %s.\n", name); - /* The traditional behaviour is to fall back to N_TTY, we - want to avoid falling back to N_NULL unless we have no - choice to avoid the risk of breaking anything */ + /* + * The traditional behaviour is to fall back to N_TTY, we + * want to avoid falling back to N_NULL unless we have no + * choice to avoid the risk of breaking anything + */ if (tty_ldisc_failto(tty, N_TTY) < 0 && tty_ldisc_failto(tty, N_NULL) < 0) panic("Couldn't open N_NULL ldisc for %s.", name); @@ -600,17 +604,21 @@ int tty_set_ldisc(struct tty_struct *tty, int disc) up_read(&tty->termios_rwsem); } - /* At this point we hold a reference to the new ldisc and a - reference to the old ldisc, or we hold two references to - the old ldisc (if it was restored as part of error cleanup - above). In either case, releasing a single reference from - the old ldisc is correct. */ + /* + * At this point we hold a reference to the new ldisc and a + * reference to the old ldisc, or we hold two references to + * the old ldisc (if it was restored as part of error cleanup + * above). In either case, releasing a single reference from + * the old ldisc is correct. + */ new_ldisc = old_ldisc; out: tty_ldisc_unlock(tty); - /* Restart the work queue in case no characters kick it off. Safe if - already running */ + /* + * Restart the work queue in case no characters kick it off. Safe if + * already running + */ tty_buffer_restart_work(tty->port); err: tty_ldisc_put(new_ldisc); /* drop the extra reference */ @@ -771,6 +779,7 @@ void tty_ldisc_hangup(struct tty_struct *tty, bool reinit) int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) { int retval = tty_ldisc_open(tty, tty->ldisc); + if (retval) return retval; @@ -811,8 +820,10 @@ void tty_ldisc_release(struct tty_struct *tty) tty_ldisc_kill(o_tty); tty_ldisc_unlock_pair(tty, o_tty); - /* And the memory resources remaining (buffers, termios) will be - disposed of when the kref hits zero */ + /* + * And the memory resources remaining (buffers, termios) will be + * disposed of when the kref hits zero + */ tty_ldisc_debug(tty, "released\n"); } @@ -829,6 +840,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_release); int tty_ldisc_init(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY); + if (IS_ERR(ld)) return PTR_ERR(ld); tty->ldisc = ld; diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 2640635ee177d1ad027ee7bc3443bfb2880ae17c..393518a24cfe230e55e623697a5fe10dcd703665 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,6 +4,7 @@ #include <linux/kallsyms.h> #include <linux/semaphore.h> #include <linux/sched.h> +#include "tty.h" /* Legacy tty mutex glue */ diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 346d20f4a4862e62a8fe27e45d147852b5a70b99..303c198fbf5c10ab22e8c33b9e91bf5df496af70 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/serdev.h> +#include "tty.h" static int tty_port_default_receive_buf(struct tty_port *port, const unsigned char *p, diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index e2d6205f83ce1794aeb7fea4c0f4b844ea7ae20a..0a3a71e14df48a49ad643da44f518daa3ad4aac7 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -14,16 +14,9 @@ #include <asm/vio.h> #include <asm/ldc.h> -#define DRV_MODULE_NAME "vcc" -#define DRV_MODULE_VERSION "1.1" -#define DRV_MODULE_RELDATE "July 1, 2017" - -static char version[] = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")"; - MODULE_DESCRIPTION("Sun LDOM virtual console concentrator driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_VERSION("1.1"); struct vcc_port { struct vio_driver_state vio; @@ -59,16 +52,14 @@ struct vcc_port { #define VCC_CTL_BREAK -1 #define VCC_CTL_HUP -2 -static const char vcc_driver_name[] = "vcc"; -static const char vcc_device_node[] = "vcc"; static struct tty_driver *vcc_tty_driver; static struct vcc_port *vcc_table[VCC_MAX_PORTS]; static DEFINE_SPINLOCK(vcc_table_lock); -int vcc_dbg; -int vcc_dbg_ldc; -int vcc_dbg_vio; +static unsigned int vcc_dbg; +static unsigned int vcc_dbg_ldc; +static unsigned int vcc_dbg_vio; module_param(vcc_dbg, uint, 0664); module_param(vcc_dbg_ldc, uint, 0664); @@ -735,11 +726,6 @@ static int vcc_open(struct tty_struct *tty, struct file *vcc_file) { struct vcc_port *port; - if (unlikely(!tty)) { - pr_err("VCC: open: Invalid TTY handle\n"); - return -ENXIO; - } - if (tty->count > 1) return -EBUSY; @@ -773,11 +759,6 @@ static int vcc_open(struct tty_struct *tty, struct file *vcc_file) static void vcc_close(struct tty_struct *tty, struct file *vcc_file) { - if (unlikely(!tty)) { - pr_err("VCC: close: Invalid TTY handle\n"); - return; - } - if (unlikely(tty->count > 1)) return; @@ -805,11 +786,6 @@ static void vcc_hangup(struct tty_struct *tty) { struct vcc_port *port; - if (unlikely(!tty)) { - pr_err("VCC: hangup: Invalid TTY handle\n"); - return; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: hangup: Failed to find VCC port\n"); @@ -839,11 +815,6 @@ static int vcc_write(struct tty_struct *tty, const unsigned char *buf, int tosend = 0; int rv = -EINVAL; - if (unlikely(!tty)) { - pr_err("VCC: write: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: write: Failed to find VCC port"); @@ -904,15 +875,10 @@ static int vcc_write_room(struct tty_struct *tty) struct vcc_port *port; u64 num; - if (unlikely(!tty)) { - pr_err("VCC: write_room: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: write_room: Failed to find VCC port\n"); - return -ENODEV; + return 0; } num = VCC_BUFF_LEN - port->chars_in_buffer; @@ -927,15 +893,10 @@ static int vcc_chars_in_buffer(struct tty_struct *tty) struct vcc_port *port; u64 num; - if (unlikely(!tty)) { - pr_err("VCC: chars_in_buffer: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: chars_in_buffer: Failed to find VCC port\n"); - return -ENODEV; + return 0; } num = port->chars_in_buffer; @@ -950,11 +911,6 @@ static int vcc_break_ctl(struct tty_struct *tty, int state) struct vcc_port *port; unsigned long flags; - if (unlikely(!tty)) { - pr_err("VCC: break_ctl: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: break_ctl: Failed to find VCC port\n"); @@ -985,11 +941,6 @@ static int vcc_install(struct tty_driver *driver, struct tty_struct *tty) struct tty_port *port_tty; int ret; - if (unlikely(!tty)) { - pr_err("VCC: install: Invalid TTY handle\n"); - return -ENXIO; - } - if (tty->index >= VCC_MAX_PORTS) return -EINVAL; @@ -1024,11 +975,6 @@ static void vcc_cleanup(struct tty_struct *tty) { struct vcc_port *port; - if (unlikely(!tty)) { - pr_err("VCC: cleanup: Invalid TTY handle\n"); - return; - } - port = vcc_get(tty->index, true); if (port) { port->tty = NULL; @@ -1066,16 +1012,14 @@ static int vcc_tty_init(void) { int rv; - pr_info("VCC: %s\n", version); - vcc_tty_driver = tty_alloc_driver(VCC_MAX_PORTS, VCC_TTY_FLAGS); if (IS_ERR(vcc_tty_driver)) { pr_err("VCC: TTY driver alloc failed\n"); return PTR_ERR(vcc_tty_driver); } - vcc_tty_driver->driver_name = vcc_driver_name; - vcc_tty_driver->name = vcc_device_node; + vcc_tty_driver->driver_name = "vcc"; + vcc_tty_driver->name = "vcc"; vcc_tty_driver->minor_start = VCC_MINOR_START; vcc_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 77638629c562fcf711e2d87ff5a933676eb226ac..5d23097427188eba6e8cb4201c47fdae34de81c6 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -2186,7 +2186,7 @@ void vt_reset_unicode(int console) } /** - * vt_get_shiftstate - shift bit state + * vt_get_shift_state - shift bit state * * Report the shift bits from the keyboard state. We have to export * this to support some oddities in the vt layer. diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 284b07224c55541b9d9663d130042ab62adba237..01645e87b3d5c3bb8fb961965eaeba7f3fe6a00d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1381,6 +1381,7 @@ struct vc_data *vc_deallocate(unsigned int currcons) atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); vcs_remove_sysfs(currcons); visual_deinit(vc); + con_free_unimap(vc); put_pid(vc->vt_pid); vc_uniscr_set(vc, NULL); kfree(vc->vc_screenbuf); @@ -4448,7 +4449,7 @@ void poke_blanked_console(void) might_sleep(); /* This isn't perfectly race free, but a race here would be mostly harmless, - * at worse, we'll do a spurrious blank and it's unlikely + * at worst, we'll do a spurious blank and it's unlikely */ del_timer(&console_timer); blank_timer_expired = 0; diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 202ee81cfc2ba4de6f37ceaa74cecf0a29f0406e..5531f3afeb2130a958ae2d398c9a58eb36c7d9c1 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -165,4 +165,21 @@ config UIO_HV_GENERIC to network and storage devices from userspace. If you compile this as a module, it will be called uio_hv_generic. + +config UIO_DFL + tristate "Generic driver for DFL (Device Feature List) bus" + depends on FPGA_DFL + help + Generic DFL (Device Feature List) driver for Userspace I/O devices. + It is useful to provide direct access to DFL devices from userspace. + A sample userspace application using this driver is available for + download in a git repository: + + git clone https://github.com/OPAE/opae-sdk.git + + It could be found at: + + opae-sdk/tools/libopaeuio/ + + If you compile this as a module, it will be called uio_dfl. endif diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index c285dd2a4539b80fd9b957f5dc5f947d0ac2e04d..f2f416a142286b791be31dc0f0e234b2124e75df 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o obj-$(CONFIG_UIO_MF624) += uio_mf624.o obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o +obj-$(CONFIG_UIO_DFL) += uio_dfl.o diff --git a/drivers/uio/uio_dfl.c b/drivers/uio/uio_dfl.c new file mode 100644 index 0000000000000000000000000000000000000000..89c0fc7b0cbcff64723ef06569d588a67a0e011f --- /dev/null +++ b/drivers/uio/uio_dfl.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic DFL driver for Userspace I/O devicess + * + * Copyright (C) 2021 Intel Corporation, Inc. + */ +#include <linux/dfl.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/uio_driver.h> + +#define DRIVER_NAME "uio_dfl" + +static int uio_dfl_probe(struct dfl_device *ddev) +{ + struct resource *r = &ddev->mmio_res; + struct device *dev = &ddev->dev; + struct uio_info *uioinfo; + struct uio_mem *uiomem; + int ret; + + uioinfo = devm_kzalloc(dev, sizeof(struct uio_info), GFP_KERNEL); + if (!uioinfo) + return -ENOMEM; + + uioinfo->name = DRIVER_NAME; + uioinfo->version = "0"; + + uiomem = &uioinfo->mem[0]; + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = r->start & PAGE_MASK; + uiomem->offs = r->start & ~PAGE_MASK; + uiomem->size = (uiomem->offs + resource_size(r) + + PAGE_SIZE - 1) & PAGE_MASK; + uiomem->name = r->name; + + /* Irq is yet to be supported */ + uioinfo->irq = UIO_IRQ_NONE; + + ret = devm_uio_register_device(dev, uioinfo); + if (ret) + dev_err(dev, "unable to register uio device\n"); + + return ret; +} + +#define FME_FEATURE_ID_ETH_GROUP 0x10 + +static const struct dfl_device_id uio_dfl_ids[] = { + { FME_ID, FME_FEATURE_ID_ETH_GROUP }, + { } +}; +MODULE_DEVICE_TABLE(dfl, uio_dfl_ids); + +static struct dfl_driver uio_dfl_driver = { + .drv = { + .name = DRIVER_NAME, + }, + .id_table = uio_dfl_ids, + .probe = uio_dfl_probe, +}; +module_dfl_driver(uio_dfl_driver); + +MODULE_DESCRIPTION("Generic DFL driver for Userspace I/O devices"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 582bfeceedb47f523342359fc28985129f8ff6ff..9b1bd417cec0393c1097f96800abd9e8f5ad8f28 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -59,6 +59,7 @@ #include <linux/dma-mapping.h> #include <linux/usb/gadget.h> #include <linux/module.h> +#include <linux/dmapool.h> #include <linux/iopoll.h> #include "core.h" @@ -190,29 +191,13 @@ dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep, return priv_ep->trb_pool_dma + offset; } -static int cdns3_ring_size(struct cdns3_endpoint *priv_ep) -{ - switch (priv_ep->type) { - case USB_ENDPOINT_XFER_ISOC: - return TRB_ISO_RING_SIZE; - case USB_ENDPOINT_XFER_CONTROL: - return TRB_CTRL_RING_SIZE; - default: - if (priv_ep->use_streams) - return TRB_STREAM_RING_SIZE; - else - return TRB_RING_SIZE; - } -} - static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) { struct cdns3_device *priv_dev = priv_ep->cdns3_dev; if (priv_ep->trb_pool) { - dma_free_coherent(priv_dev->sysdev, - cdns3_ring_size(priv_ep), - priv_ep->trb_pool, priv_ep->trb_pool_dma); + dma_pool_free(priv_dev->eps_dma_pool, + priv_ep->trb_pool, priv_ep->trb_pool_dma); priv_ep->trb_pool = NULL; } } @@ -226,7 +211,7 @@ static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) { struct cdns3_device *priv_dev = priv_ep->cdns3_dev; - int ring_size = cdns3_ring_size(priv_ep); + int ring_size = TRB_RING_SIZE; int num_trbs = ring_size / TRB_SIZE; struct cdns3_trb *link_trb; @@ -234,10 +219,10 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) cdns3_free_trb_pool(priv_ep); if (!priv_ep->trb_pool) { - priv_ep->trb_pool = dma_alloc_coherent(priv_dev->sysdev, - ring_size, - &priv_ep->trb_pool_dma, - GFP_DMA32 | GFP_ATOMIC); + priv_ep->trb_pool = dma_pool_alloc(priv_dev->eps_dma_pool, + GFP_DMA32 | GFP_ATOMIC, + &priv_ep->trb_pool_dma); + if (!priv_ep->trb_pool) return -ENOMEM; @@ -834,9 +819,15 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, priv_ep->dir); if ((priv_req->flags & REQUEST_UNALIGNED) && - priv_ep->dir == USB_DIR_OUT && !request->status) + priv_ep->dir == USB_DIR_OUT && !request->status) { + /* Make DMA buffer CPU accessible */ + dma_sync_single_for_cpu(priv_dev->sysdev, + priv_req->aligned_buf->dma, + priv_req->aligned_buf->size, + priv_req->aligned_buf->dir); memcpy(request->buf, priv_req->aligned_buf->buf, request->length); + } priv_req->flags &= ~(REQUEST_PENDING | REQUEST_UNALIGNED); /* All TRBs have finished, clear the counter */ @@ -898,8 +889,8 @@ static void cdns3_free_aligned_request_buf(struct work_struct *work) * interrupts. */ spin_unlock_irqrestore(&priv_dev->lock, flags); - dma_free_coherent(priv_dev->sysdev, buf->size, - buf->buf, buf->dma); + dma_free_noncoherent(priv_dev->sysdev, buf->size, + buf->buf, buf->dma, buf->dir); kfree(buf); spin_lock_irqsave(&priv_dev->lock, flags); } @@ -926,10 +917,13 @@ static int cdns3_prepare_aligned_request_buf(struct cdns3_request *priv_req) return -ENOMEM; buf->size = priv_req->request.length; + buf->dir = usb_endpoint_dir_in(priv_ep->endpoint.desc) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE; - buf->buf = dma_alloc_coherent(priv_dev->sysdev, + buf->buf = dma_alloc_noncoherent(priv_dev->sysdev, buf->size, &buf->dma, + buf->dir, GFP_ATOMIC); if (!buf->buf) { kfree(buf); @@ -951,10 +945,17 @@ static int cdns3_prepare_aligned_request_buf(struct cdns3_request *priv_req) } if (priv_ep->dir == USB_DIR_IN) { + /* Make DMA buffer CPU accessible */ + dma_sync_single_for_cpu(priv_dev->sysdev, + buf->dma, buf->size, buf->dir); memcpy(buf->buf, priv_req->request.buf, priv_req->request.length); } + /* Transfer DMA buffer ownership back to device */ + dma_sync_single_for_device(priv_dev->sysdev, + buf->dma, buf->size, buf->dir); + priv_req->flags |= REQUEST_UNALIGNED; trace_cdns3_prepare_aligned_request(priv_req); @@ -3103,9 +3104,10 @@ static void cdns3_gadget_exit(struct cdns *cdns) struct cdns3_aligned_buf *buf; buf = cdns3_next_align_buf(&priv_dev->aligned_buf_list); - dma_free_coherent(priv_dev->sysdev, buf->size, + dma_free_noncoherent(priv_dev->sysdev, buf->size, buf->buf, - buf->dma); + buf->dma, + buf->dir); list_del(&buf->list); kfree(buf); @@ -3113,6 +3115,7 @@ static void cdns3_gadget_exit(struct cdns *cdns) dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, priv_dev->setup_dma); + dma_pool_destroy(priv_dev->eps_dma_pool); kfree(priv_dev->zlp_buf); usb_put_gadget(&priv_dev->gadget); @@ -3185,6 +3188,14 @@ static int cdns3_gadget_start(struct cdns *cdns) /* initialize endpoint container */ INIT_LIST_HEAD(&priv_dev->gadget.ep_list); INIT_LIST_HEAD(&priv_dev->aligned_buf_list); + priv_dev->eps_dma_pool = dma_pool_create("cdns3_eps_dma_pool", + priv_dev->sysdev, + TRB_RING_SIZE, 8, 0); + if (!priv_dev->eps_dma_pool) { + dev_err(priv_dev->dev, "Failed to create TRB dma pool\n"); + ret = -ENOMEM; + goto err1; + } ret = cdns3_init_eps(priv_dev); if (ret) { @@ -3235,6 +3246,8 @@ err3: err2: cdns3_free_all_eps(priv_dev); err1: + dma_pool_destroy(priv_dev->eps_dma_pool); + usb_put_gadget(&priv_dev->gadget); cdns->gadget_dev = NULL; return ret; @@ -3304,6 +3317,8 @@ static int cdns3_gadget_resume(struct cdns *cdns, bool hibernated) return 0; cdns3_gadget_config(priv_dev); + if (hibernated) + writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf); return 0; } diff --git a/drivers/usb/cdns3/cdns3-gadget.h b/drivers/usb/cdns3/cdns3-gadget.h index 21fa461c518ec269258012ff5ba6e35e79a18906..c5660f2c4293ff2a34f81a57ac0b17f447564611 100644 --- a/drivers/usb/cdns3/cdns3-gadget.h +++ b/drivers/usb/cdns3/cdns3-gadget.h @@ -12,6 +12,7 @@ #ifndef __LINUX_CDNS3_GADGET #define __LINUX_CDNS3_GADGET #include <linux/usb/gadget.h> +#include <linux/dma-direction.h> /* * USBSS-DEV register interface. @@ -1205,6 +1206,7 @@ struct cdns3_aligned_buf { void *buf; dma_addr_t dma; u32 size; + enum dma_data_direction dir; unsigned in_use:1; struct list_head list; }; @@ -1298,6 +1300,7 @@ struct cdns3_device { struct cdns3_usb_regs __iomem *regs; + struct dma_pool *eps_dma_pool; struct usb_ctrlrequest *setup_buf; dma_addr_t setup_dma; void *zlp_buf; diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c index 8f88eec0b0ea20f5f928567e53fe814b5c63558f..74e758dc089555df6e9c0ef55249b07b81b6d857 100644 --- a/drivers/usb/cdns3/cdns3-imx.c +++ b/drivers/usb/cdns3/cdns3-imx.c @@ -361,6 +361,39 @@ static int cdns_imx_suspend(struct device *dev) return 0; } + + +/* Indicate if the controller was power lost before */ +static inline bool cdns_imx_is_power_lost(struct cdns_imx *data) +{ + u32 value; + + value = cdns_imx_readl(data, USB3_CORE_CTRL1); + if ((value & SW_RESET_MASK) == ALL_SW_RESET) + return true; + else + return false; +} + +static int __maybe_unused cdns_imx_system_resume(struct device *dev) +{ + struct cdns_imx *data = dev_get_drvdata(dev); + int ret; + + ret = cdns_imx_resume(dev); + if (ret) + return ret; + + if (cdns_imx_is_power_lost(data)) { + dev_dbg(dev, "resume from power lost\n"); + ret = cdns_imx_noncore_init(data); + if (ret) + cdns_imx_suspend(dev); + } + + return ret; +} + #else static int cdns_imx_platform_suspend(struct device *dev, bool suspend, bool wakeup) @@ -372,6 +405,7 @@ static int cdns_imx_platform_suspend(struct device *dev, static const struct dev_pm_ops cdns_imx_pm_ops = { SET_RUNTIME_PM_OPS(cdns_imx_suspend, cdns_imx_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(cdns_imx_suspend, cdns_imx_system_resume) }; static const struct of_device_id cdns_imx_of_match[] = { diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c index 4b18e1c6a4bb1ab837e56de0e8710b8286b8e4df..e1deeada425cd5b0cd9f14b60dd440814f50cca7 100644 --- a/drivers/usb/cdns3/cdns3-plat.c +++ b/drivers/usb/cdns3/cdns3-plat.c @@ -19,6 +19,7 @@ #include "core.h" #include "gadget-export.h" +#include "drd.h" static int set_phy_power_on(struct cdns *cdns) { @@ -236,6 +237,18 @@ static int cdns3_controller_resume(struct device *dev, pm_message_t msg) if (!cdns->in_lpm) return 0; + if (cdns_power_is_lost(cdns)) { + phy_exit(cdns->usb2_phy); + ret = phy_init(cdns->usb2_phy); + if (ret) + return ret; + + phy_exit(cdns->usb3_phy); + ret = phy_init(cdns->usb3_phy); + if (ret) + return ret; + } + ret = set_phy_power_on(cdns); if (ret) return ret; @@ -270,10 +283,18 @@ static int cdns3_plat_runtime_resume(struct device *dev) static int cdns3_plat_suspend(struct device *dev) { struct cdns *cdns = dev_get_drvdata(dev); + int ret; cdns_suspend(cdns); - return cdns3_controller_suspend(dev, PMSG_SUSPEND); + ret = cdns3_controller_suspend(dev, PMSG_SUSPEND); + if (ret) + return ret; + + if (device_may_wakeup(dev) && cdns->wakeup_irq) + enable_irq_wake(cdns->wakeup_irq); + + return ret; } static int cdns3_plat_resume(struct device *dev) diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h index 8648c7a7a9dd792070ce813a0a595bc16cb4e313..7574b4a6281320f635fa9156de6220d85bd5820a 100644 --- a/drivers/usb/cdns3/cdns3-trace.h +++ b/drivers/usb/cdns3/cdns3-trace.h @@ -214,7 +214,6 @@ DECLARE_EVENT_CLASS(cdns3_log_request, __field(int, no_interrupt) __field(int, start_trb) __field(int, end_trb) - __field(struct cdns3_trb *, start_trb_addr) __field(int, flags) __field(unsigned int, stream_id) ), @@ -230,12 +229,11 @@ DECLARE_EVENT_CLASS(cdns3_log_request, __entry->no_interrupt = req->request.no_interrupt; __entry->start_trb = req->start_trb; __entry->end_trb = req->end_trb; - __entry->start_trb_addr = req->trb; __entry->flags = req->flags; __entry->stream_id = req->request.stream_id; ), TP_printk("%s: req: %p, req buff %p, length: %u/%u %s%s%s, status: %d," - " trb: [start:%d, end:%d: virt addr %pa], flags:%x SID: %u", + " trb: [start:%d, end:%d], flags:%x SID: %u", __get_str(name), __entry->req, __entry->buf, __entry->actual, __entry->length, __entry->zero ? "Z" : "z", @@ -244,7 +242,6 @@ DECLARE_EVENT_CLASS(cdns3_log_request, __entry->status, __entry->start_trb, __entry->end_trb, - __entry->start_trb_addr, __entry->flags, __entry->stream_id ) diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c index d7d4bdd57f46fbe4c47c9e99a6b67d8bb7cddc5a..56707b6b0f57ca2c5ac6ebff23e62fe5459aeb56 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -727,7 +727,7 @@ int cdnsp_reset_device(struct cdnsp_device *pdev) * are in Disabled state. */ for (i = 1; i < CDNSP_ENDPOINTS_NUM; ++i) - pdev->eps[i].ep_state |= EP_STOPPED; + pdev->eps[i].ep_state |= EP_STOPPED | EP_UNCONFIGURED; trace_cdnsp_handle_cmd_reset_dev(slot_ctx); @@ -942,6 +942,7 @@ static int cdnsp_gadget_ep_enable(struct usb_ep *ep, pep = to_cdnsp_ep(ep); pdev = pep->pdev; + pep->ep_state &= ~EP_UNCONFIGURED; if (dev_WARN_ONCE(pdev->dev, pep->ep_state & EP_ENABLED, "%s is already enabled\n", pep->name)) @@ -1023,9 +1024,13 @@ static int cdnsp_gadget_ep_disable(struct usb_ep *ep) goto finish; } - cdnsp_cmd_stop_ep(pdev, pep); pep->ep_state |= EP_DIS_IN_RROGRESS; - cdnsp_cmd_flush_ep(pdev, pep); + + /* Endpoint was unconfigured by Reset Device command. */ + if (!(pep->ep_state & EP_UNCONFIGURED)) { + cdnsp_cmd_stop_ep(pdev, pep); + cdnsp_cmd_flush_ep(pdev, pep); + } /* Remove all queued USB requests. */ while (!list_empty(&pep->pending_list)) { @@ -1043,10 +1048,12 @@ static int cdnsp_gadget_ep_disable(struct usb_ep *ep) cdnsp_endpoint_zero(pdev, pep); - ret = cdnsp_update_eps_configuration(pdev, pep); + if (!(pep->ep_state & EP_UNCONFIGURED)) + ret = cdnsp_update_eps_configuration(pdev, pep); + cdnsp_free_endpoint_rings(pdev, pep); - pep->ep_state &= ~EP_ENABLED; + pep->ep_state &= ~(EP_ENABLED | EP_UNCONFIGURED); pep->ep_state |= EP_STOPPED; finish: diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h index 6bbb26548c049046124ba1e52e2ab35af0888a06..783ca8ffde007eff783ba5268697121356e5dca5 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.h +++ b/drivers/usb/cdns3/cdnsp-gadget.h @@ -835,6 +835,7 @@ struct cdnsp_ep { #define EP_WEDGE BIT(4) #define EP0_HALTED_STATUS BIT(5) #define EP_HAS_STREAMS BIT(6) +#define EP_UNCONFIGURED BIT(7) bool skip; }; diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c index 7a84e928710e41d5d6af21178d5a999ff1297218..5d4c4bfe15b705d258494db45cb577d14c3cf813 100644 --- a/drivers/usb/cdns3/cdnsp-mem.c +++ b/drivers/usb/cdns3/cdnsp-mem.c @@ -686,7 +686,7 @@ static void cdnsp_free_priv_device(struct cdnsp_device *pdev) static int cdnsp_alloc_priv_device(struct cdnsp_device *pdev) { - int ret = -ENOMEM; + int ret; ret = cdnsp_init_device_ctx(pdev); if (ret) @@ -1231,7 +1231,6 @@ int cdnsp_mem_init(struct cdnsp_device *pdev) if (!pdev->dcbaa) return -ENOMEM; - memset(pdev->dcbaa, 0, sizeof(*pdev->dcbaa)); pdev->dcbaa->dma = dma; cdnsp_write_64(dma, &pdev->op_regs->dcbaa_ptr); diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 199713769289c1a42a6fe44a51375a5fa65d0be3..bb739d88179ff167c38b87d403483a07a49e985d 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -525,9 +525,36 @@ EXPORT_SYMBOL_GPL(cdns_suspend); int cdns_resume(struct cdns *cdns, u8 set_active) { struct device *dev = cdns->dev; + enum usb_role real_role; + bool role_changed = false; + int ret = 0; + + if (cdns_power_is_lost(cdns)) { + if (cdns->role_sw) { + cdns->role = cdns_role_get(cdns->role_sw); + } else { + real_role = cdns_hw_role_state_machine(cdns); + if (real_role != cdns->role) { + ret = cdns_hw_role_switch(cdns); + if (ret) + return ret; + role_changed = true; + } + } + + if (!role_changed) { + if (cdns->role == USB_ROLE_HOST) + ret = cdns_drd_host_on(cdns); + else if (cdns->role == USB_ROLE_DEVICE) + ret = cdns_drd_gadget_on(cdns); + + if (ret) + return ret; + } + } if (cdns->roles[cdns->role]->resume) - cdns->roles[cdns->role]->resume(cdns, false); + cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns)); if (set_active) { pm_runtime_disable(dev); diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c index fa5318ade3e14aff91fbb220e6757499fe8da7ba..55c73b1d870471bff520b619fa27b6a94ee752d8 100644 --- a/drivers/usb/cdns3/drd.c +++ b/drivers/usb/cdns3/drd.c @@ -478,3 +478,18 @@ int cdns_drd_exit(struct cdns *cdns) return 0; } + + +/* Indicate the cdns3 core was power lost before */ +bool cdns_power_is_lost(struct cdns *cdns) +{ + if (cdns->version == CDNS3_CONTROLLER_V1) { + if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0))) + return true; + } else { + if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0))) + return true; + } + return false; +} +EXPORT_SYMBOL_GPL(cdns_power_is_lost); diff --git a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h index 9724acdecbbb0fbe8bde1df2d6276a75e2206659..cbdf94f73ed917bb14baf23a9087b10aca2f7015 100644 --- a/drivers/usb/cdns3/drd.h +++ b/drivers/usb/cdns3/drd.h @@ -215,5 +215,5 @@ int cdns_drd_gadget_on(struct cdns *cdns); void cdns_drd_gadget_off(struct cdns *cdns); int cdns_drd_host_on(struct cdns *cdns); void cdns_drd_host_off(struct cdns *cdns); - +bool cdns_power_is_lost(struct cdns *cdns); #endif /* __LINUX_CDNS3_DRD */ diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 90f2a8b786be6ba7015676e99b239bfbf188b10d..60361141ac04fc2a94463cf8a85736daee45a207 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -285,11 +285,9 @@ static int tegra_usb_probe(struct platform_device *pdev) } usb->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); - if (IS_ERR(usb->phy)) { - err = PTR_ERR(usb->phy); - dev_err(&pdev->dev, "failed to get PHY: %d\n", err); - return err; - } + if (IS_ERR(usb->phy)) + return dev_err_probe(&pdev->dev, PTR_ERR(usb->phy), + "failed to get PHY\n"); usb->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usb->clk)) { diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 67247d2ac07a8f7309082f91e8ef4389513e178c..e86d13c04bdbe5b7e3f18797fbbacfd230d9f8c9 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -32,7 +32,7 @@ struct ehci_ci_priv { struct ci_hdrc_dma_aligned_buffer { void *kmalloc_ptr; void *old_xfer_buffer; - u8 data[0]; + u8 data[]; }; static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3fda1ec961d7d417f78a45a5ce595db0796cd453..ca7a61190dd937ed04787fd3a51c8ca081322475 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -929,8 +929,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct acm *acm = tty->driver_data; - ss->xmit_fifo_size = acm->writesize; - ss->baud_base = le32_to_cpu(acm->line.dwDTERate); + ss->line = acm->minor; ss->close_delay = jiffies_to_msecs(acm->port.close_delay) / 10; ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : @@ -942,7 +941,6 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct acm *acm = tty->driver_data; unsigned int closing_wait, close_delay; - unsigned int old_closing_wait, old_close_delay; int retval = 0; close_delay = msecs_to_jiffies(ss->close_delay * 10); @@ -950,20 +948,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) ASYNC_CLOSING_WAIT_NONE : msecs_to_jiffies(ss->closing_wait * 10); - /* we must redo the rounding here, so that the values match */ - old_close_delay = jiffies_to_msecs(acm->port.close_delay) / 10; - old_closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - jiffies_to_msecs(acm->port.closing_wait) / 10; - mutex_lock(&acm->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if ((ss->close_delay != old_close_delay) || - (ss->closing_wait != old_closing_wait)) + if ((close_delay != acm->port.close_delay) || + (closing_wait != acm->port.closing_wait)) retval = -EPERM; - else - retval = -EOPNOTSUPP; } else { acm->port.close_delay = close_delay; acm->port.closing_wait = closing_wait; @@ -1634,12 +1624,13 @@ static int acm_resume(struct usb_interface *intf) struct urb *urb; int rv = 0; - acm_unpoison_urbs(acm); spin_lock_irq(&acm->write_lock); if (--acm->susp_count) goto out; + acm_unpoison_urbs(acm); + if (tty_port_initialized(&acm->port)) { rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); @@ -1922,9 +1913,17 @@ static const struct usb_device_id acm_ids[] = { #endif #if IS_ENABLED(CONFIG_USB_SERIAL_XR) - { USB_DEVICE(0x04e2, 0x1410), /* Ignore XR21V141X USB to Serial converter */ - .driver_info = IGNORE_DEVICE, - }, + { USB_DEVICE(0x04e2, 0x1400), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1401), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1402), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1403), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1410), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1411), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1412), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1414), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1420), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1422), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1424), .driver_info = IGNORE_DEVICE }, #endif /*Samsung phone in firmware update mode */ diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index fc21cf2d36f65ed86a9578930f6f9c269e6273c8..347fb3d3894a5c746ab15f1280aa345b352bfbec 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -25,6 +25,12 @@ static const char *const ep_type_names[] = { [USB_ENDPOINT_XFER_INT] = "intr", }; +/** + * usb_ep_type_string() - Returns human readable-name of the endpoint type. + * @ep_type: The endpoint type to return human-readable name for. If it's not + * any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}, + * usually got by usb_endpoint_type(), the string 'unknown' will be returned. + */ const char *usb_ep_type_string(int ep_type) { if (ep_type < 0 || ep_type >= ARRAY_SIZE(ep_type_names)) @@ -76,6 +82,12 @@ static const char *const ssp_rate[] = { [USB_SSP_GEN_2x2] = "super-speed-plus-gen2x2", }; +/** + * usb_speed_string() - Returns human readable-name of the speed. + * @speed: The speed to return human-readable name for. If it's not + * any of the speeds defined in usb_device_speed enum, string for + * USB_SPEED_UNKNOWN will be returned. + */ const char *usb_speed_string(enum usb_device_speed speed) { if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) @@ -84,6 +96,14 @@ const char *usb_speed_string(enum usb_device_speed speed) } EXPORT_SYMBOL_GPL(usb_speed_string); +/** + * usb_get_maximum_speed - Get maximum requested speed for a given USB + * controller. + * @dev: Pointer to the given USB controller device + * + * The function gets the maximum speed string from property "maximum-speed", + * and returns the corresponding enum usb_device_speed. + */ enum usb_device_speed usb_get_maximum_speed(struct device *dev) { const char *maximum_speed; @@ -102,6 +122,15 @@ enum usb_device_speed usb_get_maximum_speed(struct device *dev) } EXPORT_SYMBOL_GPL(usb_get_maximum_speed); +/** + * usb_get_maximum_ssp_rate - Get the signaling rate generation and lane count + * of a SuperSpeed Plus capable device. + * @dev: Pointer to the given USB controller device + * + * If the string from "maximum-speed" property is super-speed-plus-genXxY where + * 'X' is the generation number and 'Y' is the number of lanes, then this + * function returns the corresponding enum usb_ssp_rate. + */ enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev) { const char *maximum_speed; @@ -116,6 +145,12 @@ enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev) } EXPORT_SYMBOL_GPL(usb_get_maximum_ssp_rate); +/** + * usb_state_string - Returns human readable name for the state. + * @state: The state to return a human-readable name for. If it's not + * any of the states devices in usb_device_state_string enum, + * the string UNKNOWN will be returned. + */ const char *usb_state_string(enum usb_device_state state) { static const char *const names[] = { @@ -165,6 +200,47 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev) } EXPORT_SYMBOL_GPL(usb_get_dr_mode); +/** + * usb_decode_interval - Decode bInterval into the time expressed in 1us unit + * @epd: The descriptor of the endpoint + * @speed: The speed that the endpoint works as + * + * Function returns the interval expressed in 1us unit for servicing + * endpoint for data transfers. + */ +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd, + enum usb_device_speed speed) +{ + unsigned int interval = 0; + + switch (usb_endpoint_type(epd)) { + case USB_ENDPOINT_XFER_CONTROL: + /* uframes per NAK */ + if (speed == USB_SPEED_HIGH) + interval = epd->bInterval; + break; + case USB_ENDPOINT_XFER_ISOC: + interval = 1 << (epd->bInterval - 1); + break; + case USB_ENDPOINT_XFER_BULK: + /* uframes per NAK */ + if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd)) + interval = epd->bInterval; + break; + case USB_ENDPOINT_XFER_INT: + if (speed >= USB_SPEED_HIGH) + interval = 1 << (epd->bInterval - 1); + else + interval = epd->bInterval; + break; + } + + interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000; + + return interval; +} +EXPORT_SYMBOL_GPL(usb_decode_interval); + #ifdef CONFIG_OF /** * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c index ba849c7bc5c7f155ee3420be2d556052f2aaa733..a76a086b9c548e4295b1eddf96fef4c73d0ee656 100644 --- a/drivers/usb/common/debug.c +++ b/drivers/usb/common/debug.c @@ -207,8 +207,26 @@ static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size) snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue); } -/* - * usb_decode_ctrl - returns a string representation of ctrl request +/** + * usb_decode_ctrl - Returns human readable representation of control request. + * @str: buffer to return a human-readable representation of control request. + * This buffer should have about 200 bytes. + * @size: size of str buffer. + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (CPU byte order) + * @wIndex: matches the USB wIndex field (CPU byte order) + * @wLength: matches the USB wLength field (CPU byte order) + * + * Function returns decoded, formatted and human-readable description of + * control request packet. + * + * The usage scenario for this is for tracepoints, so function as a return + * use the same value as in parameters. This approach allows to use this + * function in TP_printk + * + * Important: wValue, wIndex, wLength parameters before invoking this function + * should be processed by le16_to_cpu macro. */ const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex, diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 1ef2de6e375ac84b80aa31540069088a8257983a..d8b0041de612ffc30a41aa5f09d4701f88b109b3 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -157,38 +157,25 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: type = "Ctrl"; - if (speed == USB_SPEED_HIGH) /* uframes per NAK */ - interval = desc->bInterval; - else - interval = 0; dir = 'B'; /* ctrl is bidirectional */ break; case USB_ENDPOINT_XFER_ISOC: type = "Isoc"; - interval = 1 << (desc->bInterval - 1); break; case USB_ENDPOINT_XFER_BULK: type = "Bulk"; - if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */ - interval = desc->bInterval; - else - interval = 0; break; case USB_ENDPOINT_XFER_INT: type = "Int."; - if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER) - interval = 1 << (desc->bInterval - 1); - else - interval = desc->bInterval; break; default: /* "can't happen" */ return start; } - interval *= (speed == USB_SPEED_HIGH || - speed >= USB_SPEED_SUPER) ? 125 : 1000; - if (interval % 1000) + + interval = usb_decode_interval(desc, speed); + if (interval % 1000) { unit = 'u'; - else { + } else { unit = 'm'; interval /= 1000; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 4dfa44d6cc3cf0666329b5c2b2a88680eee0503f..072968c40adeaaf204a68589c0ca2d8660adb5b7 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -519,17 +519,13 @@ static int usb_unbind_interface(struct device *dev) * @driver: the driver to be bound * @iface: the interface to which it will be bound; must be in the * usb device's active configuration - * @priv: driver data associated with that interface + * @data: driver data associated with that interface * * This is used by usb device drivers that need to claim more than one * interface on a device when probing (audio and acm are current examples). * No device driver should directly modify internal usb_interface or * usb_device structure members. * - * Few drivers should need to use this routine, since the most natural - * way to bind to an interface is to return the private data from - * the driver's probe() method. - * * Callers must own the device lock, so driver probe() entries don't need * extra locking, but other call contexts may need to explicitly claim that * lock. @@ -537,7 +533,7 @@ static int usb_unbind_interface(struct device *dev) * Return: 0 on success. */ int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void *priv) + struct usb_interface *iface, void *data) { struct device *dev; int retval = 0; @@ -554,7 +550,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, return -ENODEV; dev->driver = &driver->drvwrap.driver; - usb_set_intfdata(iface, priv); + usb_set_intfdata(iface, data); iface->needs_binding = 0; iface->condition = USB_INTERFACE_BOUND; diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 903426b6d305c8f8fcb0eee03440f354570d3589..a2530811cf7ded0656556d35abcc43b302409ce8 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -84,40 +84,13 @@ static ssize_t interval_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ep_device *ep = to_ep_device(dev); + unsigned int interval; char unit; - unsigned interval = 0; - unsigned in; - in = (ep->desc->bEndpointAddress & USB_DIR_IN); - - switch (usb_endpoint_type(ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - if (ep->udev->speed == USB_SPEED_HIGH) - /* uframes per NAK */ - interval = ep->desc->bInterval; - break; - - case USB_ENDPOINT_XFER_ISOC: - interval = 1 << (ep->desc->bInterval - 1); - break; - - case USB_ENDPOINT_XFER_BULK: - if (ep->udev->speed == USB_SPEED_HIGH && !in) - /* uframes per NAK */ - interval = ep->desc->bInterval; - break; - - case USB_ENDPOINT_XFER_INT: - if (ep->udev->speed == USB_SPEED_HIGH) - interval = 1 << (ep->desc->bInterval - 1); - else - interval = ep->desc->bInterval; - break; - } - interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000; - if (interval % 1000) + interval = usb_decode_interval(ep->desc, ep->udev->speed); + if (interval % 1000) { unit = 'u'; - else { + } else { unit = 'm'; interval /= 1000; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 3f0381344221e20980dea3adad15a3d7c4933319..6119fb41d73653848c067952f6bbafe031356b6b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2721,6 +2721,7 @@ int usb_add_hcd(struct usb_hcd *hcd, rhdev->rx_lanes = 1; rhdev->tx_lanes = 1; + rhdev->ssp_rate = USB_SSP_GEN_UNKNOWN; switch (hcd->speed) { case HCD_USB11: @@ -2738,8 +2739,11 @@ int usb_add_hcd(struct usb_hcd *hcd, case HCD_USB32: rhdev->rx_lanes = 2; rhdev->tx_lanes = 2; - fallthrough; + rhdev->ssp_rate = USB_SSP_GEN_2x2; + rhdev->speed = USB_SPEED_SUPER_PLUS; + break; case HCD_USB31: + rhdev->ssp_rate = USB_SSP_GEN_2x1; rhdev->speed = USB_SPEED_SUPER_PLUS; break; default: diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7f71218cc1e54b0d577eb9bee233ebc2ac75ba6c..b2bc4b7c428953b8e7dca0e9c872d3d31619e1f9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -31,6 +31,7 @@ #include <linux/pm_qos.h> #include <linux/kobject.h> +#include <linux/bitfield.h> #include <linux/uaccess.h> #include <asm/byteorder.h> @@ -2668,31 +2669,79 @@ out_authorized: return result; } -/* - * Return 1 if port speed is SuperSpeedPlus, 0 otherwise - * check it from the link protocol field of the current speed ID attribute. - * current speed ID is got from ext port status request. Sublink speed attribute - * table is returned with the hub BOS SSP device capability descriptor +/** + * get_port_ssp_rate - Match the extended port status to SSP rate + * @hdev: The hub device + * @ext_portstatus: extended port status + * + * Match the extended port status speed id to the SuperSpeed Plus sublink speed + * capability attributes. Base on the number of connected lanes and speed, + * return the corresponding enum usb_ssp_rate. */ -static int port_speed_is_ssp(struct usb_device *hdev, int speed_id) +static enum usb_ssp_rate get_port_ssp_rate(struct usb_device *hdev, + u32 ext_portstatus) { - int ssa_count; - u32 ss_attr; - int i; struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap; + u32 attr; + u8 speed_id; + u8 ssac; + u8 lanes; + int i; if (!ssp_cap) - return 0; + goto out; - ssa_count = le32_to_cpu(ssp_cap->bmAttributes) & + speed_id = ext_portstatus & USB_EXT_PORT_STAT_RX_SPEED_ID; + lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1; + + ssac = le32_to_cpu(ssp_cap->bmAttributes) & USB_SSP_SUBLINK_SPEED_ATTRIBS; - for (i = 0; i <= ssa_count; i++) { - ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]); - if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID)) - return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP); + for (i = 0; i <= ssac; i++) { + u8 ssid; + + attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]); + ssid = FIELD_GET(USB_SSP_SUBLINK_SPEED_SSID, attr); + if (speed_id == ssid) { + u16 mantissa; + u8 lse; + u8 type; + + /* + * Note: currently asymmetric lane types are only + * applicable for SSIC operate in SuperSpeed protocol + */ + type = FIELD_GET(USB_SSP_SUBLINK_SPEED_ST, attr); + if (type == USB_SSP_SUBLINK_SPEED_ST_ASYM_RX || + type == USB_SSP_SUBLINK_SPEED_ST_ASYM_TX) + goto out; + + if (FIELD_GET(USB_SSP_SUBLINK_SPEED_LP, attr) != + USB_SSP_SUBLINK_SPEED_LP_SSP) + goto out; + + lse = FIELD_GET(USB_SSP_SUBLINK_SPEED_LSE, attr); + mantissa = FIELD_GET(USB_SSP_SUBLINK_SPEED_LSM, attr); + + /* Convert to Gbps */ + for (; lse < USB_SSP_SUBLINK_SPEED_LSE_GBPS; lse++) + mantissa /= 1000; + + if (mantissa >= 10 && lanes == 1) + return USB_SSP_GEN_2x1; + + if (mantissa >= 10 && lanes == 2) + return USB_SSP_GEN_2x2; + + if (mantissa >= 5 && lanes == 2) + return USB_SSP_GEN_1x2; + + goto out; + } } - return 0; + +out: + return USB_SSP_GEN_UNKNOWN; } /* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ @@ -2850,15 +2899,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, /* extended portstatus Rx and Tx lane count are zero based */ udev->rx_lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1; udev->tx_lanes = USB_EXT_PORT_TX_LANES(ext_portstatus) + 1; + udev->ssp_rate = get_port_ssp_rate(hub->hdev, ext_portstatus); } else { udev->rx_lanes = 1; udev->tx_lanes = 1; + udev->ssp_rate = USB_SSP_GEN_UNKNOWN; } if (hub_is_wusb(hub)) udev->speed = USB_SPEED_WIRELESS; - else if (hub_is_superspeedplus(hub->hdev) && - port_speed_is_ssp(hub->hdev, ext_portstatus & - USB_EXT_PORT_STAT_RX_SPEED_ID)) + else if (udev->ssp_rate != USB_SSP_GEN_UNKNOWN) udev->speed = USB_SPEED_SUPER_PLUS; else if (hub_is_superspeed(hub->hdev)) udev->speed = USB_SPEED_SUPER; @@ -3556,7 +3605,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) u16 portchange, portstatus; if (!test_and_set_bit(port1, hub->child_usage_bits)) { - status = pm_runtime_get_sync(&port_dev->dev); + status = pm_runtime_resume_and_get(&port_dev->dev); if (status < 0) { dev_dbg(&udev->dev, "can't resume usb port, status %d\n", status); @@ -4781,9 +4830,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, "%s SuperSpeed%s%s USB device number %d using %s\n", (udev->config) ? "reset" : "new", (udev->speed == USB_SPEED_SUPER_PLUS) ? - "Plus Gen 2" : " Gen 1", - (udev->rx_lanes == 2 && udev->tx_lanes == 2) ? - "x2" : "", + " Plus" : "", + (udev->ssp_rate == USB_SSP_GEN_2x2) ? + " Gen 2x2" : + (udev->ssp_rate == USB_SSP_GEN_2x1) ? + " Gen 2x1" : + (udev->ssp_rate == USB_SSP_GEN_1x2) ? + " Gen 1x2" : "", devnum, driver_name); } diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 73f4482d833a7017cd4b91ea083c12fd1647046a..22ea1f4f2d66d79ee78772ea75bbd333163f979a 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -148,8 +148,10 @@ static inline unsigned hub_power_on_good_delay(struct usb_hub *hub) { unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2; - /* Wait at least 100 msec for power to become stable */ - return max(delay, 100U); + if (!hub->hdev->parent) /* root hub */ + return delay; + else /* Wait at least 100 msec for power to become stable */ + return max(delay, 100U); } static inline int hub_port_debounce_be_connected(struct usb_hub *hub, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 76ac5d6555ae4d001389233192fd2bf0740be550..21e7522655ac90bdc444721d029d9dc6c512286e 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -406,6 +406,7 @@ static const struct usb_device_id usb_quirk_list[] = { /* Realtek hub in Dell WD19 (Type-C) */ { USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM }, + { USB_DEVICE(0x0bda, 0x5487), .driver_info = USB_QUIRK_RESET_RESUME }, /* Generic RTL8153 based ethernet adapters */ { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM }, @@ -438,6 +439,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x17ef, 0xa012), .driver_info = USB_QUIRK_DISCONNECT_SUSPEND }, + /* Lenovo ThinkPad USB-C Dock Gen2 Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x17ef, 0xa387), .driver_info = USB_QUIRK_NO_LPM }, + /* BUILDWIN Photo Frame */ { USB_DEVICE(0x1908, 0x1315), .driver_info = USB_QUIRK_HONOR_BNUMINTERFACES }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d85699bee671f791bd95c2f95abc2881914419b4..5a168ba9fc518f0b51c1a111854fe4576dd6e585 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -167,7 +167,10 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, speed = "5000"; break; case USB_SPEED_SUPER_PLUS: - speed = "10000"; + if (udev->ssp_rate == USB_SSP_GEN_2x2) + speed = "20000"; + else + speed = "10000"; break; default: speed = "unknown"; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a566bb494e246b852578130522539d577f06d256..62368c4ed37afb840dc180f42b92565b674d5043 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -398,6 +398,52 @@ int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *)) } EXPORT_SYMBOL_GPL(usb_for_each_dev); +struct each_hub_arg { + void *data; + int (*fn)(struct device *, void *); +}; + +static int __each_hub(struct usb_device *hdev, void *data) +{ + struct each_hub_arg *arg = (struct each_hub_arg *)data; + struct usb_hub *hub; + int ret = 0; + int i; + + hub = usb_hub_to_struct_hub(hdev); + if (!hub) + return 0; + + mutex_lock(&usb_port_peer_mutex); + + for (i = 0; i < hdev->maxchild; i++) { + ret = arg->fn(&hub->ports[i]->dev, arg->data); + if (ret) + break; + } + + mutex_unlock(&usb_port_peer_mutex); + + return ret; +} + +/** + * usb_for_each_port - interate over all USB ports in the system + * @data: data pointer that will be handed to the callback function + * @fn: callback function to be called for each USB port + * + * Iterate over all USB ports and call @fn for each, passing it @data. If it + * returns anything other than 0, we break the iteration prematurely and return + * that value. + */ +int usb_for_each_port(void *data, int (*fn)(struct device *, void *)) +{ + struct each_hub_arg arg = {data, fn}; + + return usb_for_each_dev(&arg, __each_hub); +} +EXPORT_SYMBOL_GPL(usb_for_each_port); + /** * usb_release_dev - free a usb device structure when all users of it are finished. * @dev: device that's been disconnected @@ -982,17 +1028,15 @@ static struct notifier_block usb_bus_nb = { .notifier_call = usb_bus_notify, }; -static struct dentry *usb_devices_root; - static void usb_debugfs_init(void) { - usb_devices_root = debugfs_create_file("devices", 0444, usb_debug_root, - NULL, &usbfs_devices_fops); + debugfs_create_file("devices", 0444, usb_debug_root, NULL, + &usbfs_devices_fops); } static void usb_debugfs_cleanup(void) { - debugfs_remove(usb_devices_root); + debugfs_remove(debugfs_lookup("devices", usb_debug_root)); } /* diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index fec17a2d2447dd5a863bf37fc940832737501c0c..6f70ab9577b4e4537302ddef1865e3b2e68e5332 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -131,54 +131,26 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. * * @hsotg: Programming view of the DWC_otg controller + * @rem_wakeup: indicates whether resume is initiated by Reset. * @restore: Controller registers need to be restored */ -int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) +int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup, + bool restore) { - u32 pcgcctl; - int ret = 0; - - if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) - return -ENOTSUPP; - - pcgcctl = dwc2_readl(hsotg, PCGCTL); - pcgcctl &= ~PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - - pcgcctl = dwc2_readl(hsotg, PCGCTL); - pcgcctl &= ~PCGCTL_PWRCLMP; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - - pcgcctl = dwc2_readl(hsotg, PCGCTL); - pcgcctl &= ~PCGCTL_RSTPDWNMODULE; - dwc2_writel(hsotg, pcgcctl, PCGCTL); + struct dwc2_gregs_backup *gr; - udelay(100); - if (restore) { - ret = dwc2_restore_global_registers(hsotg); - if (ret) { - dev_err(hsotg->dev, "%s: failed to restore registers\n", - __func__); - return ret; - } - if (dwc2_is_host_mode(hsotg)) { - ret = dwc2_restore_host_registers(hsotg); - if (ret) { - dev_err(hsotg->dev, "%s: failed to restore host registers\n", - __func__); - return ret; - } - } else { - ret = dwc2_restore_device_registers(hsotg, 0); - if (ret) { - dev_err(hsotg->dev, "%s: failed to restore device registers\n", - __func__); - return ret; - } - } - } + gr = &hsotg->gr_backup; - return ret; + /* + * Restore host or device regisers with the same mode core enterted + * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup + * value of the "gotgctl" register. + */ + if (gr->gotgctl & GOTGCTL_CURMODE_HOST) + return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup, + restore); + else + return dwc2_gadget_exit_partial_power_down(hsotg, restore); } /** @@ -188,57 +160,10 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) */ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) { - u32 pcgcctl; - int ret = 0; - - if (!hsotg->params.power_down) - return -ENOTSUPP; - - /* Backup all registers */ - ret = dwc2_backup_global_registers(hsotg); - if (ret) { - dev_err(hsotg->dev, "%s: failed to backup global registers\n", - __func__); - return ret; - } - - if (dwc2_is_host_mode(hsotg)) { - ret = dwc2_backup_host_registers(hsotg); - if (ret) { - dev_err(hsotg->dev, "%s: failed to backup host registers\n", - __func__); - return ret; - } - } else { - ret = dwc2_backup_device_registers(hsotg); - if (ret) { - dev_err(hsotg->dev, "%s: failed to backup device registers\n", - __func__); - return ret; - } - } - - /* - * Clear any pending interrupts since dwc2 will not be able to - * clear them after entering partial_power_down. - */ - dwc2_writel(hsotg, 0xffffffff, GINTSTS); - - /* Put the controller in low power state */ - pcgcctl = dwc2_readl(hsotg, PCGCTL); - - pcgcctl |= PCGCTL_PWRCLMP; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - ndelay(20); - - pcgcctl |= PCGCTL_RSTPDWNMODULE; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - ndelay(20); - - pcgcctl |= PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - - return ret; + if (dwc2_is_host_mode(hsotg)) + return dwc2_host_enter_partial_power_down(hsotg); + else + return dwc2_gadget_enter_partial_power_down(hsotg); } /** @@ -374,6 +299,12 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, __func__); } else { dev_dbg(hsotg->dev, "restore done generated here\n"); + + /* + * To avoid restore done interrupt storm after restore is + * generated clear GINTSTS_RESTOREDONE bit. + */ + dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS); } } @@ -460,9 +391,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) */ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host) { - if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION) - return -ENOTSUPP; - if (is_host) return dwc2_host_enter_hibernation(hsotg); else @@ -545,6 +473,22 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) dwc2_writel(hsotg, greset, GRSTCTL); } + /* + * Switching from device mode to host mode by disconnecting + * device cable core enters and exits form hibernation. + * However, the fifo map remains not cleared. It results + * to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ + * gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) + * if in host mode we disconnect the micro a to b host + * cable. Because core reset occurs. + * To avoid the WARNING, fifo_map should be cleared + * in dwc2_core_reset() function by taking into account configs. + * fifo_map must be cleared only if driver is configured in + * "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" + * mode. + */ + dwc2_clear_fifo_map(hsotg); + /* Wait for AHB master IDLE state */ if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) { dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n", diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 7161344c65221be089a07b808b627cfe0be5717b..da5ac4a4595b6c7b2133d12b62885adefcdc7c1f 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -38,6 +38,7 @@ #ifndef __DWC2_CORE_H__ #define __DWC2_CORE_H__ +#include <linux/acpi.h> #include <linux/phy/phy.h> #include <linux/regulator/consumer.h> #include <linux/usb/gadget.h> @@ -426,7 +427,7 @@ enum dwc2_ep0_state { * @g_tx_fifo_size: An array of TX fifo sizes in dedicated fifo * mode. Each value corresponds to one EP * starting from EP1 (max 15 values). Sizes are - * in DWORDS with possible values from from + * in DWORDS with possible values from * 16-32768 (default: 256, 256, 256, 256, 768, * 768, 768, 768, 0, 0, 0, 0, 0, 0, 0). * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL @@ -865,6 +866,8 @@ struct dwc2_hregs_backup { * @gadget_enabled: Peripheral mode sub-driver initialization indicator. * @ll_hw_enabled: Status of low-level hardware resources. * @hibernated: True if core is hibernated + * @in_ppd: True if core is partial power down mode. + * @bus_suspended: True if bus is suspended * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a * remote wakeup. * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend. @@ -1022,7 +1025,6 @@ struct dwc2_hregs_backup { * a pointer to an array of register definitions, the * array size and the base address where the register bank * is to be found. - * @bus_suspended: True if bus is suspended * @last_frame_num: Number of last frame. Range from 0 to 32768 * @frame_num_array: Used only if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is * defined, for missed SOFs tracking. Array holds that @@ -1060,6 +1062,8 @@ struct dwc2_hsotg { unsigned int gadget_enabled:1; unsigned int ll_hw_enabled:1; unsigned int hibernated:1; + unsigned int in_ppd:1; + bool bus_suspended; unsigned int reset_phy_on_wake:1; unsigned int need_phy_for_wake:1; unsigned int phy_off_for_suspend:1; @@ -1143,7 +1147,6 @@ struct dwc2_hsotg { unsigned long hs_periodic_bitmap[ DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)]; u16 periodic_qh_count; - bool bus_suspended; bool new_connection; u16 last_frame_num; @@ -1301,7 +1304,8 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg) */ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait); int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg); -int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore); +int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup, + bool restore); int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host); int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset, int is_host); @@ -1339,6 +1343,7 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev); /* The device ID match table */ extern const struct of_device_id dwc2_of_match_table[]; +extern const struct acpi_device_id dwc2_acpi_match[]; int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); @@ -1409,11 +1414,19 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup); int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg); int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset); +int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg); +int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, + bool restore); +void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg); +void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, + int rem_wakeup); int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg); +static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) +{ hsotg->fifo_map = 0; } #else static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -1442,6 +1455,14 @@ static inline int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) static inline int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset) { return 0; } +static inline int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, + bool restore) +{ return 0; } +static inline void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) {} +static inline void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, + int rem_wakeup) {} static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) @@ -1450,6 +1471,7 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) { return 0; } static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {} +static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) {} #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) @@ -1459,11 +1481,18 @@ void dwc2_hcd_connect(struct dwc2_hsotg *hsotg); void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force); void dwc2_hcd_start(struct dwc2_hsotg *hsotg); int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup); +int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex); +int dwc2_port_resume(struct dwc2_hsotg *hsotg); int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg); int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset); +int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg); +int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg, + int rem_wakeup, bool restore); +void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg); +void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup); bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2); static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) { schedule_work(&hsotg->phy_reset_work); } @@ -1479,6 +1508,10 @@ static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {} static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) { return 0; } +static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) +{ return 0; } +static inline int dwc2_port_resume(struct dwc2_hsotg *hsotg) +{ return 0; } static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) @@ -1490,6 +1523,14 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset) { return 0; } +static inline int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg, + int rem_wakeup, bool restore) +{ return 0; } +static inline void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg) {} +static inline void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, + int rem_wakeup) {} static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2) { return false; } static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {} diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 55f1d14fc4148f0ffe25207aa0f0e90b5396a88e..a5ab03808da69fec436b2a1c1fa74d459a334295 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -307,6 +307,7 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg) static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) { int ret; + u32 hprt0; /* Clear interrupt */ dwc2_writel(hsotg, GINTSTS_SESSREQINT, GINTSTS); @@ -316,10 +317,18 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) if (dwc2_is_device_mode(hsotg)) { if (hsotg->lx_state == DWC2_L2) { - ret = dwc2_exit_partial_power_down(hsotg, true); - if (ret && (ret != -ENOTSUPP)) - dev_err(hsotg->dev, - "exit power_down failed\n"); + if (hsotg->in_ppd) { + ret = dwc2_exit_partial_power_down(hsotg, 0, + true); + if (ret) + dev_err(hsotg->dev, + "exit power_down failed\n"); + } + + /* Exit gadget mode clock gating. */ + if (hsotg->params.power_down == + DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) + dwc2_gadget_exit_clock_gating(hsotg, 0); } /* @@ -327,6 +336,13 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) * established */ dwc2_hsotg_disconnect(hsotg); + } else { + /* Turn on the port power bit. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_PWR; + dwc2_writel(hsotg, hprt0, HPRT0); + /* Connect hcd after port power is set. */ + dwc2_hcd_connect(hsotg); } } @@ -407,32 +423,40 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dwc2_readl(hsotg, DSTS)); if (hsotg->lx_state == DWC2_L2) { - u32 dctl = dwc2_readl(hsotg, DCTL); - - /* Clear Remote Wakeup Signaling */ - dctl &= ~DCTL_RMTWKUPSIG; - dwc2_writel(hsotg, dctl, DCTL); - ret = dwc2_exit_partial_power_down(hsotg, true); - if (ret && (ret != -ENOTSUPP)) - dev_err(hsotg->dev, "exit power_down failed\n"); + if (hsotg->in_ppd) { + u32 dctl = dwc2_readl(hsotg, DCTL); + /* Clear Remote Wakeup Signaling */ + dctl &= ~DCTL_RMTWKUPSIG; + dwc2_writel(hsotg, dctl, DCTL); + ret = dwc2_exit_partial_power_down(hsotg, 1, + true); + if (ret) + dev_err(hsotg->dev, + "exit partial_power_down failed\n"); + call_gadget(hsotg, resume); + } - /* Change to L0 state */ - hsotg->lx_state = DWC2_L0; - call_gadget(hsotg, resume); + /* Exit gadget mode clock gating. */ + if (hsotg->params.power_down == + DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) + dwc2_gadget_exit_clock_gating(hsotg, 0); } else { /* Change to L0 state */ hsotg->lx_state = DWC2_L0; } } else { - if (hsotg->params.power_down) - return; - - if (hsotg->lx_state != DWC2_L1) { - u32 pcgcctl = dwc2_readl(hsotg, PCGCTL); + if (hsotg->lx_state == DWC2_L2) { + if (hsotg->in_ppd) { + ret = dwc2_exit_partial_power_down(hsotg, 1, + true); + if (ret) + dev_err(hsotg->dev, + "exit partial_power_down failed\n"); + } - /* Restart the Phy Clock */ - pcgcctl &= ~PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgcctl, PCGCTL); + if (hsotg->params.power_down == + DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) + dwc2_host_exit_clock_gating(hsotg, 1); /* * If we've got this quirk then the PHY is stuck upon @@ -508,31 +532,33 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) return; } if (dsts & DSTS_SUSPSTS) { - if (hsotg->hw_params.power_optimized) { + switch (hsotg->params.power_down) { + case DWC2_POWER_DOWN_PARAM_PARTIAL: ret = dwc2_enter_partial_power_down(hsotg); - if (ret) { - if (ret != -ENOTSUPP) - dev_err(hsotg->dev, - "%s: enter partial_power_down failed\n", - __func__); - goto skip_power_saving; - } + if (ret) + dev_err(hsotg->dev, + "enter partial_power_down failed\n"); udelay(100); /* Ask phy to be suspended */ if (!IS_ERR_OR_NULL(hsotg->uphy)) usb_phy_set_suspend(hsotg->uphy, true); - } - - if (hsotg->hw_params.hibernation) { + break; + case DWC2_POWER_DOWN_PARAM_HIBERNATION: ret = dwc2_enter_hibernation(hsotg, 0); - if (ret && ret != -ENOTSUPP) + if (ret) dev_err(hsotg->dev, - "%s: enter hibernation failed\n", - __func__); + "enter hibernation failed\n"); + break; + case DWC2_POWER_DOWN_PARAM_NONE: + /* + * If neither hibernation nor partial power down are supported, + * clock gating is used to save power. + */ + dwc2_gadget_enter_clock_gating(hsotg); } -skip_power_saving: + /* * Change to L2 (suspend) state before releasing * spinlock @@ -652,16 +678,82 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg) return 0; } +/** + * dwc_handle_gpwrdn_disc_det() - Handles the gpwrdn disconnect detect. + * Exits hibernation without restoring registers. + * + * @hsotg: Programming view of DWC_otg controller + * @gpwrdn: GPWRDN register + */ +static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg, + u32 gpwrdn) +{ + u32 gpwrdn_tmp; + + /* Switch-on voltage to the core */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Reset core */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Disable Power Down Clamp */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Deassert reset core */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp |= GPWRDN_PWRDNRSTN; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Disable PMU interrupt */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PMUINTSEL; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + + /* De-assert Wakeup Logic */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PMUACTV; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + + hsotg->hibernated = 0; + hsotg->bus_suspended = 0; + + if (gpwrdn & GPWRDN_IDSTS) { + hsotg->op_state = OTG_STATE_B_PERIPHERAL; + dwc2_core_init(hsotg, false); + dwc2_enable_global_interrupts(hsotg); + dwc2_hsotg_core_init_disconnected(hsotg, false); + dwc2_hsotg_core_connect(hsotg); + } else { + hsotg->op_state = OTG_STATE_A_HOST; + + /* Initialize the Core for Host mode */ + dwc2_core_init(hsotg, false); + dwc2_enable_global_interrupts(hsotg); + dwc2_hcd_start(hsotg); + } +} + /* * GPWRDN interrupt handler. * * The GPWRDN interrupts are those that occur in both Host and * Device mode while core is in hibernated state. */ -static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) +static int dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) { u32 gpwrdn; int linestate; + int ret = 0; gpwrdn = dwc2_readl(hsotg, GPWRDN); /* clear all interrupt */ @@ -673,93 +765,52 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) if ((gpwrdn & GPWRDN_DISCONN_DET) && (gpwrdn & GPWRDN_DISCONN_DET_MSK) && !linestate) { - u32 gpwrdn_tmp; - dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__); - - /* Switch-on voltage to the core */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Reset core */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Disable Power Down Clamp */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Deassert reset core */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp |= GPWRDN_PWRDNRSTN; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Disable PMU interrupt */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PMUINTSEL; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - - /* De-assert Wakeup Logic */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PMUACTV; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - - hsotg->hibernated = 0; - - if (gpwrdn & GPWRDN_IDSTS) { - hsotg->op_state = OTG_STATE_B_PERIPHERAL; - dwc2_core_init(hsotg, false); - dwc2_enable_global_interrupts(hsotg); - dwc2_hsotg_core_init_disconnected(hsotg, false); - dwc2_hsotg_core_connect(hsotg); - } else { - hsotg->op_state = OTG_STATE_A_HOST; - - /* Initialize the Core for Host mode */ - dwc2_core_init(hsotg, false); - dwc2_enable_global_interrupts(hsotg); - dwc2_hcd_start(hsotg); - } - } - - if ((gpwrdn & GPWRDN_LNSTSCHG) && - (gpwrdn & GPWRDN_LNSTSCHG_MSK) && linestate) { + /* + * Call disconnect detect function to exit from + * hibernation + */ + dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn); + } else if ((gpwrdn & GPWRDN_LNSTSCHG) && + (gpwrdn & GPWRDN_LNSTSCHG_MSK) && linestate) { dev_dbg(hsotg->dev, "%s: GPWRDN_LNSTSCHG\n", __func__); if (hsotg->hw_params.hibernation && hsotg->hibernated) { if (gpwrdn & GPWRDN_IDSTS) { - dwc2_exit_hibernation(hsotg, 0, 0, 0); + ret = dwc2_exit_hibernation(hsotg, 0, 0, 0); + if (ret) + dev_err(hsotg->dev, + "exit hibernation failed.\n"); call_gadget(hsotg, resume); } else { - dwc2_exit_hibernation(hsotg, 1, 0, 1); + ret = dwc2_exit_hibernation(hsotg, 1, 0, 1); + if (ret) + dev_err(hsotg->dev, + "exit hibernation failed.\n"); } } - } - if ((gpwrdn & GPWRDN_RST_DET) && (gpwrdn & GPWRDN_RST_DET_MSK)) { + } else if ((gpwrdn & GPWRDN_RST_DET) && + (gpwrdn & GPWRDN_RST_DET_MSK)) { dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__); - if (!linestate && (gpwrdn & GPWRDN_BSESSVLD)) - dwc2_exit_hibernation(hsotg, 0, 1, 0); - } - if ((gpwrdn & GPWRDN_STS_CHGINT) && - (gpwrdn & GPWRDN_STS_CHGINT_MSK) && linestate) { - dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__); - if (hsotg->hw_params.hibernation && - hsotg->hibernated) { - if (gpwrdn & GPWRDN_IDSTS) { - dwc2_exit_hibernation(hsotg, 0, 0, 0); - call_gadget(hsotg, resume); - } else { - dwc2_exit_hibernation(hsotg, 1, 0, 1); - } + if (!linestate) { + ret = dwc2_exit_hibernation(hsotg, 0, 1, 0); + if (ret) + dev_err(hsotg->dev, + "exit hibernation failed.\n"); } + } else if ((gpwrdn & GPWRDN_STS_CHGINT) && + (gpwrdn & GPWRDN_STS_CHGINT_MSK)) { + dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__); + /* + * As GPWRDN_STS_CHGINT exit from hibernation flow is + * the same as in GPWRDN_DISCONN_DET flow. Call + * disconnect detect helper function to exit from + * hibernation. + */ + dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn); } + + return ret; } /* diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index aaafd463d72a3befb9978fdc424166a27c8d8d61..f13eed4231e1842daca0d9a4d73fb5a0dc1de992 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -691,6 +691,8 @@ static int params_show(struct seq_file *seq, void *v) print_param(seq, p, ulpi_fs_ls); print_param(seq, p, host_support_fs_ls_low_power); print_param(seq, p, host_ls_low_power_phy_clk); + print_param(seq, p, activate_stm_fs_transceiver); + print_param(seq, p, activate_stm_id_vb_detection); print_param(seq, p, ts_dline); print_param(seq, p, reload_ctl); print_param_hex(seq, p, ahbcfg); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index ad4c94366dadfd4051c8459f4db0bd566fd18b04..e6bb1bdb2760390592a42cd7423b19b3395e06ee 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3689,10 +3689,10 @@ irq_retry: dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS); /* This event must be used only if controller is suspended */ - if (hsotg->lx_state == DWC2_L2) { - dwc2_exit_partial_power_down(hsotg, true); - hsotg->lx_state = DWC2_L0; - } + if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2) + dwc2_exit_partial_power_down(hsotg, 0, true); + + hsotg->lx_state = DWC2_L0; } if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { @@ -4615,11 +4615,15 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) spin_lock_irqsave(&hsotg->lock, flags); /* - * If controller is hibernated, it must exit from power_down - * before being initialized / de-initialized + * If controller is in partial power down state, it must exit from + * that state before being initialized / de-initialized */ - if (hsotg->lx_state == DWC2_L2) - dwc2_exit_partial_power_down(hsotg, false); + if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) + /* + * No need to check the return value as + * registers are not being restored. + */ + dwc2_exit_partial_power_down(hsotg, 0, false); if (is_active) { hsotg->op_state = OTG_STATE_B_PERIPHERAL; @@ -5301,6 +5305,10 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, dwc2_writel(hsotg, dr->dcfg, DCFG); dwc2_writel(hsotg, dr->dctl, DCTL); + /* On USB Reset, reset device address to zero */ + if (reset) + dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); + /* De-assert Wakeup Logic */ gpwrdn = dwc2_readl(hsotg, GPWRDN); gpwrdn &= ~GPWRDN_PMUACTV; @@ -5351,3 +5359,202 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, return ret; } + +/** + * dwc2_gadget_enter_partial_power_down() - Put controller in partial + * power down. + * + * @hsotg: Programming view of the DWC_otg controller + * + * Return: non-zero if failed to enter device partial power down. + * + * This function is for entering device mode partial power down. + */ +int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg) +{ + u32 pcgcctl; + int ret = 0; + + dev_dbg(hsotg->dev, "Entering device partial power down started.\n"); + + /* Backup all registers */ + ret = dwc2_backup_global_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to backup global registers\n", + __func__); + return ret; + } + + ret = dwc2_backup_device_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to backup device registers\n", + __func__); + return ret; + } + + /* + * Clear any pending interrupts since dwc2 will not be able to + * clear them after entering partial_power_down. + */ + dwc2_writel(hsotg, 0xffffffff, GINTSTS); + + /* Put the controller in low power state */ + pcgcctl = dwc2_readl(hsotg, PCGCTL); + + pcgcctl |= PCGCTL_PWRCLMP; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(5); + + pcgcctl |= PCGCTL_RSTPDWNMODULE; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(5); + + pcgcctl |= PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + /* Set in_ppd flag to 1 as here core enters suspend. */ + hsotg->in_ppd = 1; + hsotg->lx_state = DWC2_L2; + + dev_dbg(hsotg->dev, "Entering device partial power down completed.\n"); + + return ret; +} + +/* + * dwc2_gadget_exit_partial_power_down() - Exit controller from device partial + * power down. + * + * @hsotg: Programming view of the DWC_otg controller + * @restore: indicates whether need to restore the registers or not. + * + * Return: non-zero if failed to exit device partial power down. + * + * This function is for exiting from device mode partial power down. + */ +int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, + bool restore) +{ + u32 pcgcctl; + u32 dctl; + struct dwc2_dregs_backup *dr; + int ret = 0; + + dr = &hsotg->dr_backup; + + dev_dbg(hsotg->dev, "Exiting device partial Power Down started.\n"); + + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl &= ~PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl &= ~PCGCTL_PWRCLMP; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl &= ~PCGCTL_RSTPDWNMODULE; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + udelay(100); + if (restore) { + ret = dwc2_restore_global_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to restore registers\n", + __func__); + return ret; + } + /* Restore DCFG */ + dwc2_writel(hsotg, dr->dcfg, DCFG); + + ret = dwc2_restore_device_registers(hsotg, 0); + if (ret) { + dev_err(hsotg->dev, "%s: failed to restore device registers\n", + __func__); + return ret; + } + } + + /* Set the Power-On Programming done bit */ + dctl = dwc2_readl(hsotg, DCTL); + dctl |= DCTL_PWRONPRGDONE; + dwc2_writel(hsotg, dctl, DCTL); + + /* Set in_ppd flag to 0 as here core exits from suspend. */ + hsotg->in_ppd = 0; + hsotg->lx_state = DWC2_L0; + + dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n"); + return ret; +} + +/** + * dwc2_gadget_enter_clock_gating() - Put controller in clock gating. + * + * @hsotg: Programming view of the DWC_otg controller + * + * Return: non-zero if failed to enter device partial power down. + * + * This function is for entering device mode clock gating. + */ +void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) +{ + u32 pcgctl; + + dev_dbg(hsotg->dev, "Entering device clock gating.\n"); + + /* Set the Phy Clock bit as suspend is received. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl |= PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + /* Set the Gate hclk as suspend is received. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl |= PCGCTL_GATEHCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + hsotg->lx_state = DWC2_L2; + hsotg->bus_suspended = true; +} + +/* + * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating. + * + * @hsotg: Programming view of the DWC_otg controller + * @rem_wakeup: indicates whether remote wake up is enabled. + * + * This function is for exiting from device mode clock gating. + */ +void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup) +{ + u32 pcgctl; + u32 dctl; + + dev_dbg(hsotg->dev, "Exiting device clock gating.\n"); + + /* Clear the Gate hclk. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl &= ~PCGCTL_GATEHCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + /* Phy Clock bit. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl &= ~PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + if (rem_wakeup) { + /* Set Remote Wakeup Signaling */ + dctl = dwc2_readl(hsotg, DCTL); + dctl |= DCTL_RMTWKUPSIG; + dwc2_writel(hsotg, dctl, DCTL); + } + + /* Change to L0 state */ + call_gadget(hsotg, resume); + hsotg->lx_state = DWC2_L0; + hsotg->bus_suspended = false; +} diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 1a9789ec5847f642d3e313b42ffb2889d7f99540..035d4911a3c324d81d742dc91c775444fde42164 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -56,8 +56,6 @@ #include "core.h" #include "hcd.h" -static void dwc2_port_resume(struct dwc2_hsotg *hsotg); - /* * ========================================================================= * Host Core Layer Functions @@ -3208,6 +3206,15 @@ static void dwc2_conn_id_status_change(struct work_struct *work) if (count > 250) dev_err(hsotg->dev, "Connection id status change timed out\n"); + + /* + * Exit Partial Power Down without restoring registers. + * No need to check the return value as registers + * are not being restored. + */ + if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2) + dwc2_exit_partial_power_down(hsotg, 0, false); + hsotg->op_state = OTG_STATE_B_PERIPHERAL; dwc2_core_init(hsotg, false); dwc2_enable_global_interrupts(hsotg); @@ -3277,13 +3284,23 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg) return hcd->self.b_hnp_enable; } -/* Must NOT be called with interrupt disabled or spinlock held */ -static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) +/** + * dwc2_port_suspend() - Put controller in suspend mode for host. + * + * @hsotg: Programming view of the DWC_otg controller + * @windex: The control request wIndex field + * + * Return: non-zero if failed to enter suspend mode for host. + * + * This function is for entering Host mode suspend. + * Must NOT be called with interrupt disabled or spinlock held. + */ +int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) { unsigned long flags; - u32 hprt0; u32 pcgctl; u32 gotgctl; + int ret = 0; dev_dbg(hsotg->dev, "%s()\n", __func__); @@ -3296,22 +3313,33 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) hsotg->op_state = OTG_STATE_A_SUSPEND; } - hprt0 = dwc2_read_hprt0(hsotg); - hprt0 |= HPRT0_SUSP; - dwc2_writel(hsotg, hprt0, HPRT0); - - hsotg->bus_suspended = true; - - /* - * If power_down is supported, Phy clock will be suspended - * after registers are backuped. - */ - if (!hsotg->params.power_down) { - /* Suspend the Phy Clock */ - pcgctl = dwc2_readl(hsotg, PCGCTL); - pcgctl |= PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgctl, PCGCTL); - udelay(10); + switch (hsotg->params.power_down) { + case DWC2_POWER_DOWN_PARAM_PARTIAL: + ret = dwc2_enter_partial_power_down(hsotg); + if (ret) + dev_err(hsotg->dev, + "enter partial_power_down failed.\n"); + break; + case DWC2_POWER_DOWN_PARAM_HIBERNATION: + /* + * Perform spin unlock and lock because in + * "dwc2_host_enter_hibernation()" function there is a spinlock + * logic which prevents servicing of any IRQ during entering + * hibernation. + */ + spin_unlock_irqrestore(&hsotg->lock, flags); + ret = dwc2_enter_hibernation(hsotg, 1); + if (ret) + dev_err(hsotg->dev, "enter hibernation failed.\n"); + spin_lock_irqsave(&hsotg->lock, flags); + break; + case DWC2_POWER_DOWN_PARAM_NONE: + /* + * If not hibernation nor partial power down are supported, + * clock gating is used to save power. + */ + dwc2_host_enter_clock_gating(hsotg); + break; } /* For HNP the bus must be suspended for at least 200ms */ @@ -3326,44 +3354,54 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) } else { spin_unlock_irqrestore(&hsotg->lock, flags); } + + return ret; } -/* Must NOT be called with interrupt disabled or spinlock held */ -static void dwc2_port_resume(struct dwc2_hsotg *hsotg) +/** + * dwc2_port_resume() - Exit controller from suspend mode for host. + * + * @hsotg: Programming view of the DWC_otg controller + * + * Return: non-zero if failed to exit suspend mode for host. + * + * This function is for exiting Host mode suspend. + * Must NOT be called with interrupt disabled or spinlock held. + */ +int dwc2_port_resume(struct dwc2_hsotg *hsotg) { unsigned long flags; - u32 hprt0; - u32 pcgctl; + int ret = 0; spin_lock_irqsave(&hsotg->lock, flags); - /* - * If power_down is supported, Phy clock is already resumed - * after registers restore. - */ - if (!hsotg->params.power_down) { - pcgctl = dwc2_readl(hsotg, PCGCTL); - pcgctl &= ~PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgctl, PCGCTL); + switch (hsotg->params.power_down) { + case DWC2_POWER_DOWN_PARAM_PARTIAL: + ret = dwc2_exit_partial_power_down(hsotg, 0, true); + if (ret) + dev_err(hsotg->dev, + "exit partial_power_down failed.\n"); + break; + case DWC2_POWER_DOWN_PARAM_HIBERNATION: + /* Exit host hibernation. */ + ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); + if (ret) + dev_err(hsotg->dev, "exit hibernation failed.\n"); + break; + case DWC2_POWER_DOWN_PARAM_NONE: + /* + * If not hibernation nor partial power down are supported, + * port resume is done using the clock gating programming flow. + */ spin_unlock_irqrestore(&hsotg->lock, flags); - msleep(20); + dwc2_host_exit_clock_gating(hsotg, 0); spin_lock_irqsave(&hsotg->lock, flags); + break; } - hprt0 = dwc2_read_hprt0(hsotg); - hprt0 |= HPRT0_RES; - hprt0 &= ~HPRT0_SUSP; - dwc2_writel(hsotg, hprt0, HPRT0); spin_unlock_irqrestore(&hsotg->lock, flags); - msleep(USB_RESUME_TIMEOUT); - - spin_lock_irqsave(&hsotg->lock, flags); - hprt0 = dwc2_read_hprt0(hsotg); - hprt0 &= ~(HPRT0_RES | HPRT0_SUSP); - dwc2_writel(hsotg, hprt0, HPRT0); - hsotg->bus_suspended = false; - spin_unlock_irqrestore(&hsotg->lock, flags); + return ret; } /* Handles hub class-specific requests */ @@ -3413,12 +3451,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, dev_dbg(hsotg->dev, "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); - if (hsotg->bus_suspended) { - if (hsotg->hibernated) - dwc2_exit_hibernation(hsotg, 0, 0, 1); - else - dwc2_port_resume(hsotg); - } + if (hsotg->bus_suspended) + retval = dwc2_port_resume(hsotg); break; case USB_PORT_FEAT_POWER: @@ -3629,10 +3663,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); if (windex != hsotg->otg_port) goto error; - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_HIBERNATION) - dwc2_enter_hibernation(hsotg, 1); - else - dwc2_port_suspend(hsotg, windex); + if (!hsotg->bus_suspended) + retval = dwc2_port_suspend(hsotg, windex); break; case USB_PORT_FEAT_POWER: @@ -3647,12 +3679,30 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, break; case USB_PORT_FEAT_RESET: - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_HIBERNATION && - hsotg->hibernated) - dwc2_exit_hibernation(hsotg, 0, 1, 1); - hprt0 = dwc2_read_hprt0(hsotg); dev_dbg(hsotg->dev, "SetPortFeature - USB_PORT_FEAT_RESET\n"); + + hprt0 = dwc2_read_hprt0(hsotg); + + if (hsotg->hibernated) { + retval = dwc2_exit_hibernation(hsotg, 0, 1, 1); + if (retval) + dev_err(hsotg->dev, + "exit hibernation failed\n"); + } + + if (hsotg->in_ppd) { + retval = dwc2_exit_partial_power_down(hsotg, 1, + true); + if (retval) + dev_err(hsotg->dev, + "exit partial_power_down failed\n"); + } + + if (hsotg->params.power_down == + DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) + dwc2_host_exit_clock_gating(hsotg, 0); + pcgctl = dwc2_readl(hsotg, PCGCTL); pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK); dwc2_writel(hsotg, pcgctl, PCGCTL); @@ -4305,8 +4355,6 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); unsigned long flags; int ret = 0; - u32 hprt0; - u32 pcgctl; spin_lock_irqsave(&hsotg->lock, flags); @@ -4322,47 +4370,51 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) if (hsotg->op_state == OTG_STATE_B_PERIPHERAL) goto unlock; - if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL || - hsotg->flags.b.port_connect_status == 0) + if (hsotg->bus_suspended) goto skip_power_saving; - /* - * Drive USB suspend and disable port Power - * if usb bus is not suspended. - */ - if (!hsotg->bus_suspended) { - hprt0 = dwc2_read_hprt0(hsotg); - if (hprt0 & HPRT0_CONNSTS) { - hprt0 |= HPRT0_SUSP; - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) - hprt0 &= ~HPRT0_PWR; - dwc2_writel(hsotg, hprt0, HPRT0); - } - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { - spin_unlock_irqrestore(&hsotg->lock, flags); - dwc2_vbus_supply_exit(hsotg); - spin_lock_irqsave(&hsotg->lock, flags); - } else { - pcgctl = readl(hsotg->regs + PCGCTL); - pcgctl |= PCGCTL_STOPPCLK; - writel(pcgctl, hsotg->regs + PCGCTL); - } - } + if (hsotg->flags.b.port_connect_status == 0) + goto skip_power_saving; - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { + switch (hsotg->params.power_down) { + case DWC2_POWER_DOWN_PARAM_PARTIAL: /* Enter partial_power_down */ ret = dwc2_enter_partial_power_down(hsotg); - if (ret) { - if (ret != -ENOTSUPP) - dev_err(hsotg->dev, - "enter partial_power_down failed\n"); - goto skip_power_saving; - } + if (ret) + dev_err(hsotg->dev, + "enter partial_power_down failed\n"); + /* After entering suspend, hardware is not accessible */ + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + break; + case DWC2_POWER_DOWN_PARAM_HIBERNATION: + /* Enter hibernation */ + spin_unlock_irqrestore(&hsotg->lock, flags); + ret = dwc2_enter_hibernation(hsotg, 1); + if (ret) + dev_err(hsotg->dev, "enter hibernation failed\n"); + spin_lock_irqsave(&hsotg->lock, flags); + + /* After entering suspend, hardware is not accessible */ + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + break; + case DWC2_POWER_DOWN_PARAM_NONE: + /* + * If not hibernation nor partial power down are supported, + * clock gating is used to save power. + */ + dwc2_host_enter_clock_gating(hsotg); - /* After entering partial_power_down, hardware is no more accessible */ + /* After entering suspend, hardware is not accessible */ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + break; + default: + goto skip_power_saving; } + spin_unlock_irqrestore(&hsotg->lock, flags); + dwc2_vbus_supply_exit(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); + /* Ask phy to be suspended */ if (!IS_ERR_OR_NULL(hsotg->uphy)) { spin_unlock_irqrestore(&hsotg->lock, flags); @@ -4382,7 +4434,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) { struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); unsigned long flags; - u32 pcgctl; + u32 hprt0; int ret = 0; spin_lock_irqsave(&hsotg->lock, flags); @@ -4393,68 +4445,102 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) if (hsotg->lx_state != DWC2_L2) goto unlock; - if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) { + hprt0 = dwc2_read_hprt0(hsotg); + + /* + * Added port connection status checking which prevents exiting from + * Partial Power Down mode from _dwc2_hcd_resume() if not in Partial + * Power Down mode. + */ + if (hprt0 & HPRT0_CONNSTS) { hsotg->lx_state = DWC2_L0; goto unlock; } - /* - * Enable power if not already done. - * This must not be spinlocked since duration - * of this call is unknown. - */ - if (!IS_ERR_OR_NULL(hsotg->uphy)) { + switch (hsotg->params.power_down) { + case DWC2_POWER_DOWN_PARAM_PARTIAL: + ret = dwc2_exit_partial_power_down(hsotg, 0, true); + if (ret) + dev_err(hsotg->dev, + "exit partial_power_down failed\n"); + /* + * Set HW accessible bit before powering on the controller + * since an interrupt may rise. + */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + break; + case DWC2_POWER_DOWN_PARAM_HIBERNATION: + ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); + if (ret) + dev_err(hsotg->dev, "exit hibernation failed.\n"); + + /* + * Set HW accessible bit before powering on the controller + * since an interrupt may rise. + */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + break; + case DWC2_POWER_DOWN_PARAM_NONE: + /* + * If not hibernation nor partial power down are supported, + * port resume is done using the clock gating programming flow. + */ spin_unlock_irqrestore(&hsotg->lock, flags); - usb_phy_set_suspend(hsotg->uphy, false); + dwc2_host_exit_clock_gating(hsotg, 0); + + /* + * Initialize the Core for Host mode, as after system resume + * the global interrupts are disabled. + */ + dwc2_core_init(hsotg, false); + dwc2_enable_global_interrupts(hsotg); + dwc2_hcd_reinit(hsotg); spin_lock_irqsave(&hsotg->lock, flags); - } - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { /* * Set HW accessible bit before powering on the controller * since an interrupt may rise. */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + break; + default: + hsotg->lx_state = DWC2_L0; + goto unlock; + } + /* Change Root port status, as port status change occurred after resume.*/ + hsotg->flags.b.port_suspend_change = 1; - /* Exit partial_power_down */ - ret = dwc2_exit_partial_power_down(hsotg, true); - if (ret && (ret != -ENOTSUPP)) - dev_err(hsotg->dev, "exit partial_power_down failed\n"); - } else { - pcgctl = readl(hsotg->regs + PCGCTL); - pcgctl &= ~PCGCTL_STOPPCLK; - writel(pcgctl, hsotg->regs + PCGCTL); + /* + * Enable power if not already done. + * This must not be spinlocked since duration + * of this call is unknown. + */ + if (!IS_ERR_OR_NULL(hsotg->uphy)) { + spin_unlock_irqrestore(&hsotg->lock, flags); + usb_phy_set_suspend(hsotg->uphy, false); + spin_lock_irqsave(&hsotg->lock, flags); } - hsotg->lx_state = DWC2_L0; - + /* Enable external vbus supply after resuming the port. */ spin_unlock_irqrestore(&hsotg->lock, flags); + dwc2_vbus_supply_init(hsotg); - if (hsotg->bus_suspended) { - spin_lock_irqsave(&hsotg->lock, flags); - hsotg->flags.b.port_suspend_change = 1; - spin_unlock_irqrestore(&hsotg->lock, flags); - dwc2_port_resume(hsotg); - } else { - if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { - dwc2_vbus_supply_init(hsotg); - - /* Wait for controller to correctly update D+/D- level */ - usleep_range(3000, 5000); - } + /* Wait for controller to correctly update D+/D- level */ + usleep_range(3000, 5000); + spin_lock_irqsave(&hsotg->lock, flags); - /* - * Clear Port Enable and Port Status changes. - * Enable Port Power. - */ - dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET | - HPRT0_ENACHG, HPRT0); - /* Wait for controller to detect Port Connect */ - usleep_range(5000, 7000); - } + /* + * Clear Port Enable and Port Status changes. + * Enable Port Power. + */ + dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET | + HPRT0_ENACHG, HPRT0); - return ret; + /* Wait for controller to detect Port Connect */ + spin_unlock_irqrestore(&hsotg->lock, flags); + usleep_range(5000, 7000); + spin_lock_irqsave(&hsotg->lock, flags); unlock: spin_unlock_irqrestore(&hsotg->lock, flags); @@ -4565,12 +4651,41 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, struct dwc2_qh *qh; bool qh_allocated = false; struct dwc2_qtd *qtd; + struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup; if (dbg_urb(urb)) { dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n"); dwc2_dump_urb_info(hcd, urb, "urb_enqueue"); } + if (hsotg->hibernated) { + if (gr->gotgctl & GOTGCTL_CURMODE_HOST) + retval = dwc2_exit_hibernation(hsotg, 0, 0, 1); + else + retval = dwc2_exit_hibernation(hsotg, 0, 0, 0); + + if (retval) + dev_err(hsotg->dev, + "exit hibernation failed.\n"); + } + + if (hsotg->in_ppd) { + retval = dwc2_exit_partial_power_down(hsotg, 0, true); + if (retval) + dev_err(hsotg->dev, + "exit partial_power_down failed\n"); + } + + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && + hsotg->bus_suspended) { + if (dwc2_is_device_mode(hsotg)) + dwc2_gadget_exit_clock_gating(hsotg, 0); + else + dwc2_host_exit_clock_gating(hsotg, 0); + } + if (!ep) return -EINVAL; @@ -5580,7 +5695,15 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, return ret; } - dwc2_hcd_rem_wakeup(hsotg); + if (rem_wakeup) { + dwc2_hcd_rem_wakeup(hsotg); + /* + * Change "port_connect_status_change" flag to re-enumerate, + * because after exit from hibernation port connection status + * is not detected. + */ + hsotg->flags.b.port_connect_status_change = 1; + } hsotg->hibernated = 0; hsotg->bus_suspended = 0; @@ -5607,3 +5730,249 @@ bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2) /* No reason to keep the PHY powered, so allow poweroff */ return true; } + +/** + * dwc2_host_enter_partial_power_down() - Put controller in partial + * power down. + * + * @hsotg: Programming view of the DWC_otg controller + * + * Return: non-zero if failed to enter host partial power down. + * + * This function is for entering Host mode partial power down. + */ +int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg) +{ + u32 pcgcctl; + u32 hprt0; + int ret = 0; + + dev_dbg(hsotg->dev, "Entering host partial power down started.\n"); + + /* Put this port in suspend mode. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_SUSP; + dwc2_writel(hsotg, hprt0, HPRT0); + udelay(5); + + /* Wait for the HPRT0.PrtSusp register field to be set */ + if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000)) + dev_warn(hsotg->dev, "Suspend wasn't generated\n"); + + /* Backup all registers */ + ret = dwc2_backup_global_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to backup global registers\n", + __func__); + return ret; + } + + ret = dwc2_backup_host_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to backup host registers\n", + __func__); + return ret; + } + + /* + * Clear any pending interrupts since dwc2 will not be able to + * clear them after entering partial_power_down. + */ + dwc2_writel(hsotg, 0xffffffff, GINTSTS); + + /* Put the controller in low power state */ + pcgcctl = dwc2_readl(hsotg, PCGCTL); + + pcgcctl |= PCGCTL_PWRCLMP; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(5); + + pcgcctl |= PCGCTL_RSTPDWNMODULE; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(5); + + pcgcctl |= PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + /* Set in_ppd flag to 1 as here core enters suspend. */ + hsotg->in_ppd = 1; + hsotg->lx_state = DWC2_L2; + hsotg->bus_suspended = true; + + dev_dbg(hsotg->dev, "Entering host partial power down completed.\n"); + + return ret; +} + +/* + * dwc2_host_exit_partial_power_down() - Exit controller from host partial + * power down. + * + * @hsotg: Programming view of the DWC_otg controller + * @rem_wakeup: indicates whether resume is initiated by Reset. + * @restore: indicates whether need to restore the registers or not. + * + * Return: non-zero if failed to exit host partial power down. + * + * This function is for exiting from Host mode partial power down. + */ +int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg, + int rem_wakeup, bool restore) +{ + u32 pcgcctl; + int ret = 0; + u32 hprt0; + + dev_dbg(hsotg->dev, "Exiting host partial power down started.\n"); + + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl &= ~PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(5); + + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl &= ~PCGCTL_PWRCLMP; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(5); + + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl &= ~PCGCTL_RSTPDWNMODULE; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + udelay(100); + if (restore) { + ret = dwc2_restore_global_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to restore registers\n", + __func__); + return ret; + } + + ret = dwc2_restore_host_registers(hsotg); + if (ret) { + dev_err(hsotg->dev, "%s: failed to restore host registers\n", + __func__); + return ret; + } + } + + /* Drive resume signaling and exit suspend mode on the port. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_RES; + hprt0 &= ~HPRT0_SUSP; + dwc2_writel(hsotg, hprt0, HPRT0); + udelay(5); + + if (!rem_wakeup) { + /* Stop driveing resume signaling on the port. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 &= ~HPRT0_RES; + dwc2_writel(hsotg, hprt0, HPRT0); + + hsotg->bus_suspended = false; + } else { + /* Turn on the port power bit. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_PWR; + dwc2_writel(hsotg, hprt0, HPRT0); + + /* Connect hcd. */ + dwc2_hcd_connect(hsotg); + + mod_timer(&hsotg->wkp_timer, + jiffies + msecs_to_jiffies(71)); + } + + /* Set lx_state to and in_ppd to 0 as here core exits from suspend. */ + hsotg->in_ppd = 0; + hsotg->lx_state = DWC2_L0; + + dev_dbg(hsotg->dev, "Exiting host partial power down completed.\n"); + return ret; +} + +/** + * dwc2_host_enter_clock_gating() - Put controller in clock gating. + * + * @hsotg: Programming view of the DWC_otg controller + * + * This function is for entering Host mode clock gating. + */ +void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg) +{ + u32 hprt0; + u32 pcgctl; + + dev_dbg(hsotg->dev, "Entering host clock gating.\n"); + + /* Put this port in suspend mode. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_SUSP; + dwc2_writel(hsotg, hprt0, HPRT0); + + /* Set the Phy Clock bit as suspend is received. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl |= PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + /* Set the Gate hclk as suspend is received. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl |= PCGCTL_GATEHCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + hsotg->bus_suspended = true; + hsotg->lx_state = DWC2_L2; +} + +/** + * dwc2_host_exit_clock_gating() - Exit controller from clock gating. + * + * @hsotg: Programming view of the DWC_otg controller + * @rem_wakeup: indicates whether resume is initiated by remote wakeup + * + * This function is for exiting Host mode clock gating. + */ +void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup) +{ + u32 hprt0; + u32 pcgctl; + + dev_dbg(hsotg->dev, "Exiting host clock gating.\n"); + + /* Clear the Gate hclk. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl &= ~PCGCTL_GATEHCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + /* Phy Clock bit. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl &= ~PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + /* Drive resume signaling and exit suspend mode on the port. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_RES; + hprt0 &= ~HPRT0_SUSP; + dwc2_writel(hsotg, hprt0, HPRT0); + udelay(5); + + if (!rem_wakeup) { + /* In case of port resume need to wait for 40 ms */ + msleep(USB_RESUME_TIMEOUT); + + /* Stop driveing resume signaling on the port. */ + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 &= ~HPRT0_RES; + dwc2_writel(hsotg, hprt0, HPRT0); + + hsotg->bus_suspended = false; + hsotg->lx_state = DWC2_L0; + } else { + mod_timer(&hsotg->wkp_timer, + jiffies + msecs_to_jiffies(71)); + } +} diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 68bbac64b7536aec43574d543be8ff758b718fa9..621a4846bd05ae18539ed34f3dfc61369c18b068 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -59,7 +59,7 @@ #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5)) /* If we get a NAK, wait this long before retrying */ -#define DWC2_RETRY_WAIT_DELAY 1*1E6L +#define DWC2_RETRY_WAIT_DELAY (1 * 1E6L) /** * dwc2_periodic_channel_available() - Checks that a channel is available for a diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index c3d6dde2aca45cd28ae5a67b3a358e9a8e5fa05b..6b16fbf98bc6ec0183147c1325450c018776f634 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -44,6 +44,7 @@ #define GOTGCTL_CHIRPEN BIT(27) #define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) #define GOTGCTL_MULT_VALID_BC_SHIFT 22 +#define GOTGCTL_CURMODE_HOST BIT(21) #define GOTGCTL_OTGVER BIT(20) #define GOTGCTL_BSESVLD BIT(19) #define GOTGCTL_ASESVLD BIT(18) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 92df3d620f7d2c95a24138fa5e242bf0775208fd..7a6089fa81e1d11e45fc540dceb4f48c1788a10e 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -232,6 +232,12 @@ const struct of_device_id dwc2_of_match_table[] = { }; MODULE_DEVICE_TABLE(of, dwc2_of_match_table); +const struct acpi_device_id dwc2_acpi_match[] = { + { "BCM2848", (kernel_ulong_t)dwc2_set_bcm_params }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, dwc2_acpi_match); + static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg) { u8 val; @@ -866,10 +872,12 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) return 0; } +typedef void (*set_params_cb)(struct dwc2_hsotg *data); + int dwc2_init_params(struct dwc2_hsotg *hsotg) { const struct of_device_id *match; - void (*set_params)(struct dwc2_hsotg *data); + set_params_cb set_params; dwc2_set_default_params(hsotg); dwc2_get_device_properties(hsotg); @@ -878,6 +886,14 @@ int dwc2_init_params(struct dwc2_hsotg *hsotg) if (match && match->data) { set_params = match->data; set_params(hsotg); + } else { + const struct acpi_device_id *amatch; + + amatch = acpi_match_device(dwc2_acpi_match, hsotg->dev); + if (amatch && amatch->driver_data) { + set_params = (set_params_cb)amatch->driver_data; + set_params(hsotg); + } } dwc2_check_params(hsotg); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 5f18acac7406885927b4d473045aaae94d474470..3024785d84cb8284454ea3ab3d20c49644f73d90 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -316,6 +316,39 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) static int dwc2_driver_remove(struct platform_device *dev) { struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); + struct dwc2_gregs_backup *gr; + int ret = 0; + + gr = &hsotg->gr_backup; + + /* Exit Hibernation when driver is removed. */ + if (hsotg->hibernated) { + if (gr->gotgctl & GOTGCTL_CURMODE_HOST) + ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); + else + ret = dwc2_exit_hibernation(hsotg, 0, 0, 0); + + if (ret) + dev_err(hsotg->dev, + "exit hibernation failed.\n"); + } + + /* Exit Partial Power Down when driver is removed. */ + if (hsotg->in_ppd) { + ret = dwc2_exit_partial_power_down(hsotg, 0, true); + if (ret) + dev_err(hsotg->dev, + "exit partial_power_down failed\n"); + } + + /* Exit clock gating when driver is removed. */ + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && + hsotg->bus_suspended) { + if (dwc2_is_device_mode(hsotg)) + dwc2_gadget_exit_clock_gating(hsotg, 0); + else + dwc2_host_exit_clock_gating(hsotg, 0); + } dwc2_debugfs_exit(hsotg); if (hsotg->hcd_enabled) @@ -334,7 +367,7 @@ static int dwc2_driver_remove(struct platform_device *dev) reset_control_assert(hsotg->reset); reset_control_assert(hsotg->reset_ecc); - return 0; + return ret; } /** @@ -734,6 +767,7 @@ static struct platform_driver dwc2_platform_driver = { .driver = { .name = dwc2_driver_name, .of_match_table = dwc2_of_match_table, + .acpi_match_table = ACPI_PTR(dwc2_acpi_match), .pm = &dwc2_dev_pm_ops, }, .probe = dwc2_driver_probe, diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 2133acf8ee6958c90b7072a8a6e79ff6b7e81b99..66b1454c4db2c77b115ad7166e41ee912930438b 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -149,4 +149,13 @@ config USB_DWC3_IMX8MP functionality. Say 'Y' or 'M' if you have one such device. +config USB_DWC3_XILINX + tristate "Xilinx Platforms" + depends on (ARCH_ZYNQMP || ARCH_VERSAL) && OF + default USB_DWC3 + help + Support Xilinx SoCs with DesignWare Core USB3 IP. + This driver handles both ZynqMP and Versal SoC operations. + Say 'Y' or 'M' if you have one such device. + endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 2259f8876fb2f2679ddf5c6914724d86f2bb09df..2d499de6f66a53ad55a26fe5ec830a73fb8637de 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -52,3 +52,4 @@ obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o +obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index f2448d0a9d393a0d986d614abc2bc16f1bee43a9..b6e53d8212cd874788785c425ba8f27b8069f46c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -114,6 +114,8 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } +static int dwc3_core_soft_reset(struct dwc3 *dwc); + static void __dwc3_set_mode(struct work_struct *work) { struct dwc3 *dwc = work_to_dwc(work); @@ -121,6 +123,8 @@ static void __dwc3_set_mode(struct work_struct *work) int ret; u32 reg; + mutex_lock(&dwc->mutex); + pm_runtime_get_sync(dwc->dev); if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) @@ -154,6 +158,25 @@ static void __dwc3_set_mode(struct work_struct *work) break; } + /* For DRD host or device mode only */ + if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + reg |= DWC3_GCTL_CORESOFTRESET; + dwc3_writel(dwc->regs, DWC3_GCTL, reg); + + /* + * Wait for internal clocks to synchronized. DWC_usb31 and + * DWC_usb32 may need at least 50ms (less for DWC_usb3). To + * keep it consistent across different IPs, let's wait up to + * 100ms before clearing GCTL.CORESOFTRESET. + */ + msleep(100); + + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + reg &= ~DWC3_GCTL_CORESOFTRESET; + dwc3_writel(dwc->regs, DWC3_GCTL, reg); + } + spin_lock_irqsave(&dwc->lock, flags); dwc3_set_prtcap(dwc, dwc->desired_dr_role); @@ -178,6 +201,8 @@ static void __dwc3_set_mode(struct work_struct *work) } break; case DWC3_GCTL_PRTCAP_DEVICE: + dwc3_core_soft_reset(dwc); + dwc3_event_buffers_setup(dwc); if (dwc->usb2_phy) @@ -200,6 +225,7 @@ static void __dwc3_set_mode(struct work_struct *work) out: pm_runtime_mark_last_busy(dwc->dev); pm_runtime_put_autosuspend(dwc->dev); + mutex_unlock(&dwc->mutex); } void dwc3_set_mode(struct dwc3 *dwc, u32 mode) @@ -544,6 +570,9 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); + + if (DWC3_IP_IS(DWC32)) + parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9); } static int dwc3_core_ulpi_init(struct dwc3 *dwc) @@ -1238,6 +1267,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) u8 rx_max_burst_prd; u8 tx_thr_num_pkt_prd; u8 tx_max_burst_prd; + const char *usb_psy_name; + int ret; /* default to highest possible threshold */ lpm_nyet_threshold = 0xf; @@ -1263,6 +1294,13 @@ static void dwc3_get_properties(struct dwc3 *dwc) else dwc->sysdev = dwc->dev; + ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name); + if (ret >= 0) { + dwc->usb_psy = power_supply_get_by_name(usb_psy_name); + if (!dwc->usb_psy) + dev_err(dev, "couldn't get usb power supply\n"); + } + dwc->has_lpm_erratum = device_property_read_bool(dev, "snps,has-lpm-erratum"); device_property_read_u8(dev, "snps,lpm-nyet-threshold", @@ -1277,6 +1315,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,usb3_lpm_capable"); dwc->usb2_lpm_disable = device_property_read_bool(dev, "snps,usb2-lpm-disable"); + dwc->usb2_gadget_lpm_disable = device_property_read_bool(dev, + "snps,usb2-gadget-lpm-disable"); device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd", &rx_thr_num_pkt_prd); device_property_read_u8(dev, "snps,rx-max-burst-prd", @@ -1385,7 +1425,6 @@ static void dwc3_check_params(struct dwc3 *dwc) /* Check the maximum_speed parameter */ switch (dwc->maximum_speed) { - case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: break; @@ -1543,6 +1582,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_cache_hwparams(dwc); spin_lock_init(&dwc->lock); + mutex_init(&dwc->mutex); pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); @@ -1619,6 +1659,9 @@ disable_clks: assert_reset: reset_control_assert(dwc->reset); + if (dwc->usb_psy) + power_supply_put(dwc->usb_psy); + return ret; } @@ -1641,9 +1684,17 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_free_event_buffers(dwc); dwc3_free_scratch_buffers(dwc); + if (dwc->usb_psy) + power_supply_put(dwc->usb_psy); + return 0; } +static void dwc3_shutdown(struct platform_device *pdev) +{ + dwc3_remove(pdev); +} + #ifdef CONFIG_PM static int dwc3_core_init_for_resume(struct dwc3 *dwc) { @@ -1961,6 +2012,7 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); static struct platform_driver dwc3_driver = { .probe = dwc3_probe, .remove = dwc3_remove, + .shutdown = dwc3_shutdown, .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 052b20d526510aa77efd4b6293a0eaec90e20c8d..b1e875c58f20f69813f206a117f738743a0fa366 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/ioport.h> #include <linux/list.h> #include <linux/bitops.h> @@ -30,6 +31,8 @@ #include <linux/phy/phy.h> +#include <linux/power_supply.h> + #define DWC3_MSG_MAX 500 /* Global constants */ @@ -140,6 +143,7 @@ #define DWC3_GHWPARAMS8 0xc600 #define DWC3_GUCTL3 0xc60c #define DWC3_GFLADJ 0xc630 +#define DWC3_GHWPARAMS9 0xc680 /* Device Registers */ #define DWC3_DCFG 0xc700 @@ -375,6 +379,9 @@ #define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff) #define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff) +/* Global HWPARAMS9 Register */ +#define DWC3_GHWPARAMS9_DEV_TXF_FLUSH_BYPASS BIT(0) + /* Global Frame Length Adjustment Register */ #define DWC3_GFLADJ_30MHZ_SDBND_SEL BIT(7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f @@ -396,12 +403,12 @@ #define DWC3_DCFG_SUPERSPEED (4 << 0) #define DWC3_DCFG_HIGHSPEED (0 << 0) #define DWC3_DCFG_FULLSPEED BIT(0) -#define DWC3_DCFG_LOWSPEED (2 << 0) #define DWC3_DCFG_NUMP_SHIFT 17 #define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f) #define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT) #define DWC3_DCFG_LPM_CAP BIT(22) +#define DWC3_DCFG_IGNSTRMPP BIT(23) /* Device Control Register */ #define DWC3_DCTL_RUN_STOP BIT(31) @@ -490,7 +497,6 @@ #define DWC3_DSTS_SUPERSPEED (4 << 0) #define DWC3_DSTS_HIGHSPEED (0 << 0) #define DWC3_DSTS_FULLSPEED BIT(0) -#define DWC3_DSTS_LOWSPEED (2 << 0) /* Device Generic Command Register */ #define DWC3_DGCMD_SET_LMP 0x01 @@ -855,13 +861,12 @@ struct dwc3_hwparams { u32 hwparams6; u32 hwparams7; u32 hwparams8; + u32 hwparams9; }; /* HWPARAMS0 */ #define DWC3_MODE(n) ((n) & 0x7) -#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8) - /* HWPARAMS1 */ #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) @@ -908,11 +913,13 @@ struct dwc3_request { unsigned int remaining; unsigned int status; -#define DWC3_REQUEST_STATUS_QUEUED 0 -#define DWC3_REQUEST_STATUS_STARTED 1 -#define DWC3_REQUEST_STATUS_CANCELLED 2 -#define DWC3_REQUEST_STATUS_COMPLETED 3 -#define DWC3_REQUEST_STATUS_UNKNOWN -1 +#define DWC3_REQUEST_STATUS_QUEUED 0 +#define DWC3_REQUEST_STATUS_STARTED 1 +#define DWC3_REQUEST_STATUS_DISCONNECTED 2 +#define DWC3_REQUEST_STATUS_DEQUEUED 3 +#define DWC3_REQUEST_STATUS_STALLED 4 +#define DWC3_REQUEST_STATUS_COMPLETED 5 +#define DWC3_REQUEST_STATUS_UNKNOWN -1 u8 epnum; struct dwc3_trb *trb; @@ -946,6 +953,7 @@ struct dwc3_scratchpad_array { * @scratch_addr: dma address of scratchbuf * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing + * @mutex: for mode switching * @dev: pointer to our struct device * @sysdev: pointer to the DMA-capable device * @xhci: pointer to our xHCI child @@ -986,6 +994,7 @@ struct dwc3_scratchpad_array { * @role_sw: usb_role_switch handle * @role_switch_default_mode: default operation mode of controller while * usb role is USB_ROLE_NONE. + * @usb_psy: pointer to power supply interface. * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY @@ -1034,7 +1043,8 @@ struct dwc3_scratchpad_array { * @dis_start_transfer_quirk: set if start_transfer failure SW workaround is * not needed for DWC_usb31 version 1.70a-ea06 and below * @usb3_lpm_capable: set if hadrware supports Link Power Management - * @usb2_lpm_disable: set to disable usb2 lpm + * @usb2_lpm_disable: set to disable usb2 lpm for host + * @usb2_gadget_lpm_disable: set to disable usb2 lpm for gadget * @disable_scramble_quirk: set if we enable the disable scramble quirk * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk @@ -1085,6 +1095,9 @@ struct dwc3 { /* device lock */ spinlock_t lock; + /* mode switching lock */ + struct mutex mutex; + struct device *dev; struct device *sysdev; @@ -1125,6 +1138,8 @@ struct dwc3 { struct usb_role_switch *role_sw; enum usb_dr_mode role_switch_default_mode; + struct power_supply *usb_psy; + u32 fladj; u32 irq_gadget; u32 otg_irq; @@ -1238,6 +1253,7 @@ struct dwc3 { unsigned dis_start_transfer_quirk:1; unsigned usb3_lpm_capable:1; unsigned usb2_lpm_disable:1; + unsigned usb2_gadget_lpm_disable:1; unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; @@ -1455,6 +1471,23 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); (!(_ip##_VERSIONTYPE_##_to) || \ dwc->version_type <= _ip##_VERSIONTYPE_##_to)) +/** + * dwc3_mdwidth - get MDWIDTH value in bits + * @dwc: pointer to our context structure + * + * Return MDWIDTH configuration value in bits. + */ +static inline u32 dwc3_mdwidth(struct dwc3 *dwc) +{ + u32 mdwidth; + + mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0); + if (DWC3_IP_IS(DWC32)) + mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + + return mdwidth; +} + bool dwc3_has_imod(struct dwc3 *dwc); int dwc3_event_buffers_setup(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 8ab3949423604d1c37c38e05cdab5c6dfa718644..db231de46bb3592410f6adc83bad13a4487ebf79 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* * debug.h - DesignWare USB3 DRD Controller Debug Header * * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 5da4f6082d930486bb9fa30a1f1bc47128c1a794..7146ee2ac05765fd052d0cb5d6525abc52a51760 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * debugfs.c - DesignWare USB3 DRD Controller DebugFS file * * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com @@ -638,16 +638,14 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) struct dwc3_ep *dep = s->private; struct dwc3 *dwc = dep->dwc; unsigned long flags; - int mdwidth; + u32 mdwidth; u32 val; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_TXFIFO); /* Convert to bytes */ - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - if (DWC3_IP_IS(DWC32)) - mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + mdwidth = dwc3_mdwidth(dwc); val *= mdwidth; val >>= 3; @@ -662,16 +660,14 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) struct dwc3_ep *dep = s->private; struct dwc3 *dwc = dep->dwc; unsigned long flags; - int mdwidth; + u32 mdwidth; u32 val; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXFIFO); /* Convert to bytes */ - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - if (DWC3_IP_IS(DWC32)) - mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + mdwidth = dwc3_mdwidth(dwc); val *= mdwidth; val >>= 3; diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 90bb022737da8ef4e540ee1a713ed3ac3acdd8e2..0ecf20eeceee9ddb1bb0c26317062f743539fd80 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-exynos.c - Samsung Exynos DWC3 Specific Glue layer * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index 75f0042b998b11ffbb1cf932624b12c729914454..b13cfab89d532da8fba2aa17d8f2747b1ea01f69 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-imx8mp.c - NXP imx8mp Specific Glue layer * * Copyright (c) 2020 NXP. diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 057056c0975e4a7a935b710c557d971f218d8123..1317959294e6ef7a44de1ed53d7b4deee51427ff 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-keystone.c - Keystone Specific Glue layer * * Copyright (C) 2010-2013 Texas Instruments Incorporated - https://www.ti.com diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index e62ecd22b3ed48d427accb2ba68521185ba2acf0..71fd620c5161931746411d44e0a944d981b0d3e5 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -172,7 +172,6 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = { static const struct of_device_id of_dwc3_simple_match[] = { { .compatible = "rockchip,rk3399-dwc3" }, - { .compatible = "xlnx,zynqmp-dwc3" }, { .compatible = "cavium,octeon-7130-usb-uctl" }, { .compatible = "sprd,sc9860-dwc3" }, { .compatible = "allwinner,sun50i-h6-dwc3" }, diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 4c5c6972124a4806eec893184e70410c405eea39..e7b932dcbf820d7c6b7307cf615ccccc54f6d8cf 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-pci.c - PCI Specific glue layer * * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com @@ -41,6 +41,7 @@ #define PCI_DEVICE_ID_INTEL_TGPH 0x43ee #define PCI_DEVICE_ID_INTEL_JSP 0x4dee #define PCI_DEVICE_ID_INTEL_ADLP 0x51ee +#define PCI_DEVICE_ID_INTEL_ADLM 0x54ee #define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1 #define PCI_DEVICE_ID_INTEL_TGL 0x9a15 @@ -388,6 +389,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLP), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLM), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 3de291ab951a72eb9a709959b674a34904c1509f..49e6ca94486ddb6d1562f3d887f9ad67866c8239 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -235,7 +235,7 @@ static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom) /** * dwc3_qcom_interconnect_init() - Get interconnect path handles - * and set bandwidhth. + * and set bandwidth. * @qcom: Pointer to the concerned usb core. * */ @@ -647,7 +647,7 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret; - dwc3_np = of_get_child_by_name(np, "dwc3"); + dwc3_np = of_get_compatible_child(np, "snps,dwc3"); if (!dwc3_np) { dev_err(dev, "failed to find dwc3 core child\n"); return -ENODEV; @@ -774,7 +774,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev) qcom->qscratch_base = devm_ioremap_resource(dev, parent_res); if (IS_ERR(qcom->qscratch_base)) { - dev_err(dev, "failed to map qscratch, err=%d\n", ret); ret = PTR_ERR(qcom->qscratch_base); goto clk_disable; } diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index b06b7092b1a2d3fbbaac0b9ef57310df5dea9fd6..166b5bde45cbc8b2ee40e8fc502c3a32e8ba3109 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ -/** +/* * dwc3-st.c Support for dwc3 platform devices on ST Microelectronics platforms * * This is a small driver for the dwc3 to provide the glue logic diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c new file mode 100644 index 0000000000000000000000000000000000000000..9cc3ad701a295297d4d0c72c01bf4020444440cf --- /dev/null +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dwc3-xilinx.c - Xilinx DWC3 controller specific glue driver + * + * Authors: Manish Narani <manish.narani@xilinx.com> + * Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/firmware/xlnx-zynqmp.h> +#include <linux/io.h> + +#include <linux/phy/phy.h> + +/* USB phy reset mask register */ +#define XLNX_USB_PHY_RST_EN 0x001C +#define XLNX_PHY_RST_MASK 0x1 + +/* Xilinx USB 3.0 IP Register */ +#define XLNX_USB_TRAFFIC_ROUTE_CONFIG 0x005C +#define XLNX_USB_TRAFFIC_ROUTE_FPD 0x1 + +/* Versal USB Reset ID */ +#define VERSAL_USB_RESET_ID 0xC104036 + +#define XLNX_USB_FPD_PIPE_CLK 0x7c +#define PIPE_CLK_DESELECT 1 +#define PIPE_CLK_SELECT 0 +#define XLNX_USB_FPD_POWER_PRSNT 0x80 +#define FPD_POWER_PRSNT_OPTION BIT(0) + +struct dwc3_xlnx { + int num_clocks; + struct clk_bulk_data *clks; + struct device *dev; + void __iomem *regs; + int (*pltfm_init)(struct dwc3_xlnx *data); +}; + +static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool mask) +{ + u32 reg; + + /* + * Enable or disable ULPI PHY reset from USB Controller. + * This does not actually reset the phy, but just controls + * whether USB controller can or cannot reset ULPI PHY. + */ + reg = readl(priv_data->regs + XLNX_USB_PHY_RST_EN); + + if (mask) + reg &= ~XLNX_PHY_RST_MASK; + else + reg |= XLNX_PHY_RST_MASK; + + writel(reg, priv_data->regs + XLNX_USB_PHY_RST_EN); +} + +static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data) +{ + struct device *dev = priv_data->dev; + int ret; + + dwc3_xlnx_mask_phy_rst(priv_data, false); + + /* Assert and De-assert reset */ + ret = zynqmp_pm_reset_assert(VERSAL_USB_RESET_ID, + PM_RESET_ACTION_ASSERT); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to assert Reset\n"); + return ret; + } + + ret = zynqmp_pm_reset_assert(VERSAL_USB_RESET_ID, + PM_RESET_ACTION_RELEASE); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to De-assert Reset\n"); + return ret; + } + + dwc3_xlnx_mask_phy_rst(priv_data, true); + + return 0; +} + +static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) +{ + struct device *dev = priv_data->dev; + struct reset_control *crst, *hibrst, *apbrst; + struct phy *usb3_phy; + int ret; + u32 reg; + + usb3_phy = devm_phy_get(dev, "usb3-phy"); + if (PTR_ERR(usb3_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err; + } else if (IS_ERR(usb3_phy)) { + usb3_phy = NULL; + } + + crst = devm_reset_control_get_exclusive(dev, "usb_crst"); + if (IS_ERR(crst)) { + ret = PTR_ERR(crst); + dev_err_probe(dev, ret, + "failed to get core reset signal\n"); + goto err; + } + + hibrst = devm_reset_control_get_exclusive(dev, "usb_hibrst"); + if (IS_ERR(hibrst)) { + ret = PTR_ERR(hibrst); + dev_err_probe(dev, ret, + "failed to get hibernation reset signal\n"); + goto err; + } + + apbrst = devm_reset_control_get_exclusive(dev, "usb_apbrst"); + if (IS_ERR(apbrst)) { + ret = PTR_ERR(apbrst); + dev_err_probe(dev, ret, + "failed to get APB reset signal\n"); + goto err; + } + + ret = reset_control_assert(crst); + if (ret < 0) { + dev_err(dev, "Failed to assert core reset\n"); + goto err; + } + + ret = reset_control_assert(hibrst); + if (ret < 0) { + dev_err(dev, "Failed to assert hibernation reset\n"); + goto err; + } + + ret = reset_control_assert(apbrst); + if (ret < 0) { + dev_err(dev, "Failed to assert APB reset\n"); + goto err; + } + + ret = phy_init(usb3_phy); + if (ret < 0) { + phy_exit(usb3_phy); + goto err; + } + + ret = reset_control_deassert(apbrst); + if (ret < 0) { + dev_err(dev, "Failed to release APB reset\n"); + goto err; + } + + /* Set PIPE Power Present signal in FPD Power Present Register*/ + writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT); + + /* Set the PIPE Clock Select bit in FPD PIPE Clock register */ + writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK); + + ret = reset_control_deassert(crst); + if (ret < 0) { + dev_err(dev, "Failed to release core reset\n"); + goto err; + } + + ret = reset_control_deassert(hibrst); + if (ret < 0) { + dev_err(dev, "Failed to release hibernation reset\n"); + goto err; + } + + ret = phy_power_on(usb3_phy); + if (ret < 0) { + phy_exit(usb3_phy); + goto err; + } + + /* + * This routes the USB DMA traffic to go through FPD path instead + * of reaching DDR directly. This traffic routing is needed to + * make SMMU and CCI work with USB DMA. + */ + if (of_dma_is_coherent(dev->of_node) || device_iommu_mapped(dev)) { + reg = readl(priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG); + reg |= XLNX_USB_TRAFFIC_ROUTE_FPD; + writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG); + } + +err: + return ret; +} + +static const struct of_device_id dwc3_xlnx_of_match[] = { + { + .compatible = "xlnx,zynqmp-dwc3", + .data = &dwc3_xlnx_init_zynqmp, + }, + { + .compatible = "xlnx,versal-dwc3", + .data = &dwc3_xlnx_init_versal, + }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwc3_xlnx_of_match); + +static int dwc3_xlnx_probe(struct platform_device *pdev) +{ + struct dwc3_xlnx *priv_data; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct of_device_id *match; + void __iomem *regs; + int ret; + + priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + dev_err_probe(dev, ret, "failed to map registers\n"); + return ret; + } + + match = of_match_node(dwc3_xlnx_of_match, pdev->dev.of_node); + + priv_data->pltfm_init = match->data; + priv_data->regs = regs; + priv_data->dev = dev; + + platform_set_drvdata(pdev, priv_data); + + ret = devm_clk_bulk_get_all(priv_data->dev, &priv_data->clks); + if (ret < 0) + return ret; + + priv_data->num_clocks = ret; + + ret = clk_bulk_prepare_enable(priv_data->num_clocks, priv_data->clks); + if (ret) + return ret; + + ret = priv_data->pltfm_init(priv_data); + if (ret) + goto err_clk_put; + + ret = of_platform_populate(np, NULL, NULL, dev); + if (ret) + goto err_clk_put; + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_suspend_ignore_children(dev, false); + pm_runtime_get_sync(dev); + + return 0; + +err_clk_put: + clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks); + + return ret; +} + +static int dwc3_xlnx_remove(struct platform_device *pdev) +{ + struct dwc3_xlnx *priv_data = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + of_platform_depopulate(dev); + + clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks); + priv_data->num_clocks = 0; + + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); + + return 0; +} + +static int __maybe_unused dwc3_xlnx_suspend_common(struct device *dev) +{ + struct dwc3_xlnx *priv_data = dev_get_drvdata(dev); + + clk_bulk_disable(priv_data->num_clocks, priv_data->clks); + + return 0; +} + +static int __maybe_unused dwc3_xlnx_resume_common(struct device *dev) +{ + struct dwc3_xlnx *priv_data = dev_get_drvdata(dev); + + return clk_bulk_enable(priv_data->num_clocks, priv_data->clks); +} + +static int __maybe_unused dwc3_xlnx_runtime_idle(struct device *dev) +{ + pm_runtime_mark_last_busy(dev); + pm_runtime_autosuspend(dev); + + return 0; +} + +static UNIVERSAL_DEV_PM_OPS(dwc3_xlnx_dev_pm_ops, dwc3_xlnx_suspend_common, + dwc3_xlnx_resume_common, dwc3_xlnx_runtime_idle); + +static struct platform_driver dwc3_xlnx_driver = { + .probe = dwc3_xlnx_probe, + .remove = dwc3_xlnx_remove, + .driver = { + .name = "dwc3-xilinx", + .of_match_table = dwc3_xlnx_of_match, + .pm = &dwc3_xlnx_dev_pm_ops, + }, +}; + +module_platform_driver(dwc3_xlnx_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Xilinx DWC3 controller specific glue driver"); +MODULE_AUTHOR("Manish Narani <manish.narani@xilinx.com>"); +MODULE_AUTHOR("Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>"); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c7ef218e7a8cfec04dc9e740534779aa69e1bdf0..dd80e5ca8c78b6e402864a00b8e314a7a09e175f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -308,13 +308,12 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, } if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { - int needs_wakeup; + int link_state; - needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 || - dwc->link_state == DWC3_LINK_STATE_U2 || - dwc->link_state == DWC3_LINK_STATE_U3); - - if (unlikely(needs_wakeup)) { + link_state = dwc3_gadget_get_link_state(dwc); + if (link_state == DWC3_LINK_STATE_U1 || + link_state == DWC3_LINK_STATE_U2 || + link_state == DWC3_LINK_STATE_U3) { ret = __dwc3_gadget_wakeup(dwc); dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", ret); @@ -608,12 +607,14 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) u8 bInterval_m1; /* - * Valid range for DEPCFG.bInterval_m1 is from 0 to 13, and it - * must be set to 0 when the controller operates in full-speed. + * Valid range for DEPCFG.bInterval_m1 is from 0 to 13. + * + * NOTE: The programming guide incorrectly stated bInterval_m1 + * must be set to 0 when operating in fullspeed. Internally the + * controller does not have this limitation. See DWC_usb3x + * programming guide section 3.2.2.1. */ bInterval_m1 = min_t(u8, desc->bInterval - 1, 13); - if (dwc->gadget->speed == USB_SPEED_FULL) - bInterval_m1 = 0; if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT && dwc->gadget->speed == USB_SPEED_FULL) @@ -729,8 +730,16 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) * All stream eps will reinitiate stream on NoStream * rejection until we can determine that the host can * prime after the first transfer. + * + * However, if the controller is capable of + * TXF_FLUSH_BYPASS, then IN direction endpoints will + * automatically restart the stream without the driver + * initiation. */ - dep->flags |= DWC3_EP_FORCE_RESTART_STREAM; + if (!dep->direction || + !(dwc->hwparams.hwparams9 & + DWC3_GHWPARAMS9_DEV_TXF_FLUSH_BYPASS)) + dep->flags |= DWC3_EP_FORCE_RESTART_STREAM; } } @@ -1402,7 +1411,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) dwc3_stop_active_transfer(dep, true, true); list_for_each_entry_safe(req, tmp, &dep->started_list, list) - dwc3_gadget_move_cancelled_request(req); + dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_DEQUEUED); /* If ep isn't started, then there's no end transfer pending */ if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) @@ -1729,10 +1738,25 @@ static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep) { struct dwc3_request *req; struct dwc3_request *tmp; + struct dwc3 *dwc = dep->dwc; list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) { dwc3_gadget_ep_skip_trbs(dep, req); - dwc3_gadget_giveback(dep, req, -ECONNRESET); + switch (req->status) { + case DWC3_REQUEST_STATUS_DISCONNECTED: + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + break; + case DWC3_REQUEST_STATUS_DEQUEUED: + dwc3_gadget_giveback(dep, req, -ECONNRESET); + break; + case DWC3_REQUEST_STATUS_STALLED: + dwc3_gadget_giveback(dep, req, -EPIPE); + break; + default: + dev_err(dwc->dev, "request cancelled with wrong reason:%d\n", req->status); + dwc3_gadget_giveback(dep, req, -ECONNRESET); + break; + } } } @@ -1776,7 +1800,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, * cancelled. */ list_for_each_entry_safe(r, t, &dep->started_list, list) - dwc3_gadget_move_cancelled_request(r); + dwc3_gadget_move_cancelled_request(r, + DWC3_REQUEST_STATUS_DEQUEUED); dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE; @@ -1848,7 +1873,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) dwc3_stop_active_transfer(dep, true, true); list_for_each_entry_safe(req, tmp, &dep->started_list, list) - dwc3_gadget_move_cancelled_request(req); + dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_STALLED); if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) { dep->flags |= DWC3_EP_PENDING_CLEAR_STALL; @@ -1973,6 +1998,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) case DWC3_LINK_STATE_RESET: case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ + case DWC3_LINK_STATE_U2: /* in HS, means Sleep (L1) */ + case DWC3_LINK_STATE_U1: case DWC3_LINK_STATE_RESUME: break; default: @@ -2113,9 +2140,6 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc) reg |= DWC3_DCFG_SUPERSPEED; } else { switch (speed) { - case USB_SPEED_LOW: - reg |= DWC3_DCFG_LOWSPEED; - break; case USB_SPEED_FULL: reg |= DWC3_DCFG_FULLSPEED; break; @@ -2340,9 +2364,7 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc) u32 reg; ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7); - mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0); - if (DWC3_IP_IS(DWC32)) - mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + mdwidth = dwc3_mdwidth(dwc); nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024; nump = min_t(u32, nump, 16); @@ -2388,6 +2410,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) dwc3_gadget_setup_nump(dwc); + /* + * Currently the controller handles single stream only. So, Ignore + * Packet Pending bit for stream selection and don't search for another + * stream if the host sends Data Packet with PP=0 (for OUT direction) or + * ACK with NumP=0 and PP=0 (for IN direction). This slightly improves + * the stream performance. + */ + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg |= DWC3_DCFG_IGNSTRMPP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); @@ -2531,11 +2564,19 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g, static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) { struct dwc3 *dwc = gadget_to_dwc(g); + union power_supply_propval val = {0}; + int ret; if (dwc->usb2_phy) return usb_phy_set_power(dwc->usb2_phy, mA); - return 0; + if (!dwc->usb_psy) + return -EOPNOTSUPP; + + val.intval = 1000 * mA; + ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); + + return ret; } static const struct usb_gadget_ops dwc3_gadget_ops = { @@ -2571,12 +2612,10 @@ static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep) static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; - int mdwidth; + u32 mdwidth; int size; - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - if (DWC3_IP_IS(DWC32)) - mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + mdwidth = dwc3_mdwidth(dwc); /* MDWIDTH is represented in bits, we need it in bytes */ mdwidth /= 8; @@ -2618,12 +2657,10 @@ static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep) static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; - int mdwidth; + u32 mdwidth; int size; - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - if (DWC3_IP_IS(DWC32)) - mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + mdwidth = dwc3_mdwidth(dwc); /* MDWIDTH is represented in bits, convert to bytes */ mdwidth /= 8; @@ -2913,6 +2950,11 @@ static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep, static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep) { struct dwc3_request *req; + struct dwc3 *dwc = dep->dwc; + + if (!dep->endpoint.desc || !dwc->pullups_connected || + !dwc->connected) + return false; if (!list_empty(&dep->pending_list)) return true; @@ -3322,6 +3364,15 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; + /* + * Ideally, dwc3_reset_gadget() would trigger the function + * drivers to stop any active transfers through ep disable. + * However, for functions which defer ep disable, such as mass + * storage, we will need to rely on the call to stop active + * transfers here, and avoid allowing of request queuing. + */ + dwc->connected = false; + /* * WORKAROUND: DWC3 revisions <1.88a have an issue which * would cause a missing Disconnect Event if there's a @@ -3448,11 +3499,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc->gadget->ep0->maxpacket = 64; dwc->gadget->speed = USB_SPEED_FULL; break; - case DWC3_DSTS_LOWSPEED: - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); - dwc->gadget->ep0->maxpacket = 8; - dwc->gadget->speed = USB_SPEED_LOW; - break; } dwc->eps[1]->endpoint.maxpacket = dwc->gadget->ep0->maxpacket; @@ -3460,6 +3506,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) /* Enable USB2 LPM Capability */ if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A) && + !dwc->usb2_gadget_lpm_disable && (speed != DWC3_DSTS_SUPERSPEED) && (speed != DWC3_DSTS_SUPERSPEED_PLUS)) { reg = dwc3_readl(dwc->regs, DWC3_DCFG); @@ -3486,6 +3533,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc3_gadget_dctl_write_safe(dwc, reg); } else { + if (dwc->usb2_gadget_lpm_disable) { + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~DWC3_DCFG_LPM_CAP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + } + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_HIRD_THRES_MASK; dwc3_gadget_dctl_write_safe(dwc, reg); @@ -3934,7 +3987,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN; dwc->gadget->sg_supported = true; dwc->gadget->name = "dwc3-gadget"; - dwc->gadget->lpm_capable = true; + dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable; /* * FIXME We might be setting max_speed to <SUPER, however versions diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 0cd28194997017a98cd00fe16bae54713cc0f186..77df4b6d6c13d68b5ccbeadc633608836b46cfb0 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -90,15 +90,17 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) /** * dwc3_gadget_move_cancelled_request - move @req to the cancelled_list * @req: the request to be moved + * @reason: cancelled reason for the dwc3 request * * Caller should take care of locking. This function will move @req from its * current list to the endpoint's cancelled_list. */ -static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req) +static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req, + unsigned int reason) { struct dwc3_ep *dep = req->dep; - req->status = DWC3_REQUEST_STATUS_CANCELLED; + req->status = reason; list_move_tail(&req->list, &dep->cancelled_list); } diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 76b73b116862625839c24ea078b901608d308b8c..1e96ea339d48d03036391c8c04a74898b66f8ace 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* * io.h - DesignWare USB3 DRD IO Header * * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com diff --git a/drivers/usb/dwc3/trace.c b/drivers/usb/dwc3/trace.c index 1b45a9723eeb7f3ff305f2466066a5da3f8657d6..088995885678b5d025001de65e09a067d7ac6937 100644 --- a/drivers/usb/dwc3/trace.c +++ b/drivers/usb/dwc3/trace.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * trace.c - DesignWare USB3 DRD Controller Trace Support * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 97f4f1125a416315da9951bdde697ee9ab8abcd0..51d18e8d1602895b287d99e59173ce77b74ccd28 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* * trace.h - DesignWare USB3 DRD Controller Trace Support * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com @@ -32,8 +32,10 @@ DECLARE_EVENT_CLASS(dwc3_log_io, __entry->offset = offset; __entry->value = value; ), - TP_printk("addr %p value %08x", __entry->base + __entry->offset, - __entry->value) + TP_printk("addr %p offset %04x value %08x", + __entry->base + __entry->offset, + __entry->offset, + __entry->value) ); DEFINE_EVENT(dwc3_log_io, dwc3_readl, diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 2d115353424c2cb073d07251f67a574a4407188e..8bb25773b61e91e83ee5a48fefe25a1566418640 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -194,9 +194,13 @@ EXPORT_SYMBOL_GPL(usb_assign_descriptors); void usb_free_all_descriptors(struct usb_function *f) { usb_free_descriptors(f->fs_descriptors); + f->fs_descriptors = NULL; usb_free_descriptors(f->hs_descriptors); + f->hs_descriptors = NULL; usb_free_descriptors(f->ss_descriptors); + f->ss_descriptors = NULL; usb_free_descriptors(f->ssp_descriptors); + f->ssp_descriptors = NULL; } EXPORT_SYMBOL_GPL(usb_free_all_descriptors); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 38e330b3ed9d689b2cceddf82e491cc90a2b778b..034c25a77da409866d628daf61795d5f5adcdd26 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2640,6 +2640,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, do { /* lang_count > 0 so we can use do-while */ unsigned needed = needed_count; + u32 str_per_lang = str_count; if (len < 3) goto error_free; @@ -2675,7 +2676,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, data += length + 1; len -= length + 1; - } while (--str_count); + } while (--str_per_lang); s->id = 0; /* terminator */ s->s = NULL; @@ -3830,14 +3831,9 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len) if (!len) return NULL; - data = kmalloc(len, GFP_KERNEL); - if (!data) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(data, buf, len)) { - kfree(data); - return ERR_PTR(-EFAULT); - } + data = memdup_user(buf, len); + if (IS_ERR(data)) + return ERR_PTR(PTR_ERR(data)); pr_vdebug("Buffer from user space:\n"); ffs_dump_mem("", data, len); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 950c9435beec376d7ca81c5e110af83d47ada626..4a4703634a2abf8bd7d88e47b3e689b3a492e39e 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -351,8 +351,6 @@ static inline struct fsg_dev *fsg_from_func(struct usb_function *f) return container_of(f, struct fsg_dev, function); } -typedef void (*fsg_routine_t)(struct fsg_dev *); - static int exception_in_progress(struct fsg_common *common) { return common->state > FSG_STATE_NORMAL; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 61ce8e68f7a304842a452daa7a5644473cac8f33..f47fdc1fa7f138b9cd297697bb310a992d3c8e50 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -825,7 +825,7 @@ set_printer_interface(struct printer_dev *dev) result = usb_ep_enable(dev->out_ep); if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + DBG(dev, "enable %s --> %d\n", dev->out_ep->name, result); goto done; } diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 560382e0a8f38d2b79502c9211b69a7cf1281a40..d04707580068883bfe29940d41f976e3cb53ee5b 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -19,6 +19,12 @@ #include "u_audio.h" #include "u_uac1.h" +/* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */ +#define UAC1_CHANNEL_MASK 0x0FFF + +#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) +#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) + struct f_uac1 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; @@ -30,6 +36,11 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) return container_of(f, struct f_uac1, g_audio.func); } +static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) +{ + return container_of(audio->func.fi, struct f_uac1_opts, func_inst); +} + /* * DESCRIPTORS ... most are static, but strings and full * configuration descriptors are built on demand. @@ -42,11 +53,6 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN */ -#define F_AUDIO_AC_INTERFACE 0 -#define F_AUDIO_AS_OUT_INTERFACE 1 -#define F_AUDIO_AS_IN_INTERFACE 2 -/* Number of streaming interfaces */ -#define F_AUDIO_NUM_INTERFACES 2 /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc = { @@ -57,73 +63,47 @@ static struct usb_interface_descriptor ac_interface_desc = { .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, }; -/* - * The number of AudioStreaming and MIDIStreaming interfaces - * in the Audio Interface Collection - */ -DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); - -#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) -/* 2 input terminals and 2 output terminals */ -#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ - + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE) /* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_2 ac_header_desc = { - .bLength = UAC_DT_AC_HEADER_LENGTH, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_HEADER, - .bcdADC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH), - .bInCollection = F_AUDIO_NUM_INTERFACES, - .baInterfaceNr = { - /* Interface number of the AudioStream interfaces */ - [0] = 1, - [1] = 2, - } -}; +static struct uac1_ac_header_descriptor *ac_header_desc; -#define USB_OUT_IT_ID 1 static struct uac_input_terminal_descriptor usb_out_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = USB_OUT_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, .wChannelConfig = cpu_to_le16(0x3), }; -#define IO_OUT_OT_ID 2 static struct uac1_output_terminal_descriptor io_out_ot_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = IO_OUT_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), .bAssocTerminal = 0, - .bSourceID = USB_OUT_IT_ID, + /* .bSourceID = DYNAMIC */ }; -#define IO_IN_IT_ID 3 static struct uac_input_terminal_descriptor io_in_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = IO_IN_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), .bAssocTerminal = 0, .wChannelConfig = cpu_to_le16(0x3), }; -#define USB_IN_OT_ID 4 static struct uac1_output_terminal_descriptor usb_in_ot_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = USB_IN_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .bSourceID = IO_IN_IT_ID, + /* .bSourceID = DYNAMIC */ }; /* B.4.1 Standard AS Interface Descriptor */ @@ -168,7 +148,7 @@ static struct uac1_as_header_descriptor as_out_header_desc = { .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_OUT_IT_ID, + /* .bTerminalLink = DYNAMIC */ .bDelay = 1, .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; @@ -177,7 +157,7 @@ static struct uac1_as_header_descriptor as_in_header_desc = { .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_IN_OT_ID, + /* .bTerminalLink = DYNAMIC */ .bDelay = 1, .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; @@ -505,11 +485,144 @@ static void f_audio_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ +static struct +uac1_ac_header_descriptor *build_ac_header_desc(struct f_uac1_opts *opts) +{ + struct uac1_ac_header_descriptor *ac_desc; + int ac_header_desc_size; + int num_ifaces = 0; + + if (EPOUT_EN(opts)) + num_ifaces++; + if (EPIN_EN(opts)) + num_ifaces++; + + ac_header_desc_size = UAC_DT_AC_HEADER_SIZE(num_ifaces); + + ac_desc = kzalloc(ac_header_desc_size, GFP_KERNEL); + if (!ac_desc) + return NULL; + + ac_desc->bLength = ac_header_desc_size; + ac_desc->bDescriptorType = USB_DT_CS_INTERFACE; + ac_desc->bDescriptorSubtype = UAC_HEADER; + ac_desc->bcdADC = cpu_to_le16(0x0100); + ac_desc->bInCollection = num_ifaces; + + /* wTotalLength and baInterfaceNr will be defined later */ + + return ac_desc; +} + +/* Use macro to overcome line length limitation */ +#define USBDHDR(p) (struct usb_descriptor_header *)(p) + +static void setup_descriptor(struct f_uac1_opts *opts) +{ + /* patch descriptors */ + int i = 1; /* ID's start with 1 */ + + if (EPOUT_EN(opts)) + usb_out_it_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + io_in_it_desc.bTerminalID = i++; + if (EPOUT_EN(opts)) + io_out_ot_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + usb_in_ot_desc.bTerminalID = i++; + + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + + as_out_header_desc.bTerminalLink = usb_out_it_desc.bTerminalID; + as_in_header_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; + + ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc->bLength); + + if (EPIN_EN(opts)) { + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); + + len += sizeof(usb_in_ot_desc); + len += sizeof(io_in_it_desc); + ac_header_desc->wTotalLength = cpu_to_le16(len); + } + if (EPOUT_EN(opts)) { + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); + + len += sizeof(usb_out_it_desc); + len += sizeof(io_out_ot_desc); + ac_header_desc->wTotalLength = cpu_to_le16(len); + } + + i = 0; + f_audio_desc[i++] = USBDHDR(&ac_interface_desc); + f_audio_desc[i++] = USBDHDR(ac_header_desc); + + if (EPOUT_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + f_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + } + + if (EPIN_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&io_in_it_desc); + f_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + } + + if (EPOUT_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_0_desc); + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_1_desc); + f_audio_desc[i++] = USBDHDR(&as_out_header_desc); + f_audio_desc[i++] = USBDHDR(&as_out_type_i_desc); + f_audio_desc[i++] = USBDHDR(&as_out_ep_desc); + f_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_0_desc); + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_1_desc); + f_audio_desc[i++] = USBDHDR(&as_in_header_desc); + f_audio_desc[i++] = USBDHDR(&as_in_type_i_desc); + f_audio_desc[i++] = USBDHDR(&as_in_ep_desc); + f_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + f_audio_desc[i] = NULL; +} + +static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) +{ + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + + if (!opts->p_chmask && !opts->c_chmask) { + dev_err(dev, "Error: no playback and capture channels\n"); + return -EINVAL; + } else if (opts->p_chmask & ~UAC1_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported playback channels mask\n"); + return -EINVAL; + } else if (opts->c_chmask & ~UAC1_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported capture channels mask\n"); + return -EINVAL; + } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) { + dev_err(dev, "Error: incorrect playback sample size\n"); + return -EINVAL; + } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) { + dev_err(dev, "Error: incorrect capture sample size\n"); + return -EINVAL; + } else if (!opts->p_srate) { + dev_err(dev, "Error: incorrect playback sampling rate\n"); + return -EINVAL; + } else if (!opts->c_srate) { + dev_err(dev, "Error: incorrect capture sampling rate\n"); + return -EINVAL; + } + + return 0; +} + /* audio function driver setup/binding */ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct usb_gadget *gadget = cdev->gadget; + struct device *dev = &gadget->dev; struct f_uac1 *uac1 = func_to_uac1(f); struct g_audio *audio = func_to_g_audio(f); struct f_uac1_opts *audio_opts; @@ -517,13 +630,23 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) struct usb_string *us; u8 *sam_freq; int rate; + int ba_iface_id; int status; + status = f_audio_validate_opts(audio, dev); + if (status) + return status; + audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst); us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); if (IS_ERR(us)) return PTR_ERR(us); + + ac_header_desc = build_ac_header_desc(audio_opts); + if (!ac_header_desc) + return -ENOMEM; + ac_interface_desc.iInterface = us[STR_AC_IF].id; usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id; usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id; @@ -564,40 +687,52 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) uac1->ac_intf = status; uac1->ac_alt = 0; - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - as_out_interface_alt_0_desc.bInterfaceNumber = status; - as_out_interface_alt_1_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[0] = status; - uac1->as_out_intf = status; - uac1->as_out_alt = 0; + ba_iface_id = 0; + + if (EPOUT_EN(audio_opts)) { + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + as_out_interface_alt_0_desc.bInterfaceNumber = status; + as_out_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; + uac1->as_out_intf = status; + uac1->as_out_alt = 0; + } - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - as_in_interface_alt_0_desc.bInterfaceNumber = status; - as_in_interface_alt_1_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[1] = status; - uac1->as_in_intf = status; - uac1->as_in_alt = 0; + if (EPIN_EN(audio_opts)) { + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + as_in_interface_alt_0_desc.bInterfaceNumber = status; + as_in_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; + uac1->as_in_intf = status; + uac1->as_in_alt = 0; + } audio->gadget = gadget; status = -ENODEV; /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); - if (!ep) - goto fail; - audio->out_ep = ep; - audio->out_ep->desc = &as_out_ep_desc; + if (EPOUT_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); + if (!ep) + goto fail; + audio->out_ep = ep; + audio->out_ep->desc = &as_out_ep_desc; + } - ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); - if (!ep) - goto fail; - audio->in_ep = ep; - audio->in_ep->desc = &as_in_ep_desc; + if (EPIN_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); + if (!ep) + goto fail; + audio->in_ep = ep; + audio->in_ep->desc = &as_in_ep_desc; + } + + setup_descriptor(audio_opts); /* copy descriptors, and track endpoint copies */ status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, @@ -624,6 +759,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) err_card_register: usb_free_all_descriptors(f); fail: + kfree(ac_header_desc); + ac_header_desc = NULL; return status; } @@ -766,6 +903,9 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) g_audio_cleanup(audio); usb_free_all_descriptors(f); + kfree(ac_header_desc); + ac_header_desc = NULL; + audio->gadget = NULL; } diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 6f03e944e0e31e8a7b6ac230daa9602046cd8923..7aa4c8bc5a1aeaf6ee5a22633bdd37c03910f192 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -14,6 +14,9 @@ #include "u_audio.h" #include "u_uac2.h" +/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ +#define UAC2_CHANNEL_MASK 0x07FFFFFF + /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -284,6 +287,24 @@ static struct usb_endpoint_descriptor hs_epout_desc = { .bInterval = 4, }; +static struct usb_endpoint_descriptor ss_epout_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, + /* .wMaxPacketSize = DYNAMIC */ + .bInterval = 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = { + .bLength = sizeof(ss_epout_desc_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + /* wBytesPerInterval = DYNAMIC */ +}; + /* CS AS ISO OUT Endpoint */ static struct uac2_iso_endpoint_descriptor as_iso_out_desc = { .bLength = sizeof as_iso_out_desc, @@ -361,6 +382,24 @@ static struct usb_endpoint_descriptor hs_epin_desc = { .bInterval = 4, }; +static struct usb_endpoint_descriptor ss_epin_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, + /* .wMaxPacketSize = DYNAMIC */ + .bInterval = 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = { + .bLength = sizeof(ss_epin_desc_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + /* wBytesPerInterval = DYNAMIC */ +}; + /* CS AS ISO IN Endpoint */ static struct uac2_iso_endpoint_descriptor as_iso_in_desc = { .bLength = sizeof as_iso_in_desc, @@ -433,6 +472,38 @@ static struct usb_descriptor_header *hs_audio_desc[] = { NULL, }; +static struct usb_descriptor_header *ss_audio_desc[] = { + (struct usb_descriptor_header *)&iad_desc, + (struct usb_descriptor_header *)&std_ac_if_desc, + + (struct usb_descriptor_header *)&ac_hdr_desc, + (struct usb_descriptor_header *)&in_clk_src_desc, + (struct usb_descriptor_header *)&out_clk_src_desc, + (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&io_in_it_desc, + (struct usb_descriptor_header *)&usb_in_ot_desc, + (struct usb_descriptor_header *)&io_out_ot_desc, + + (struct usb_descriptor_header *)&std_as_out_if0_desc, + (struct usb_descriptor_header *)&std_as_out_if1_desc, + + (struct usb_descriptor_header *)&as_out_hdr_desc, + (struct usb_descriptor_header *)&as_out_fmt1_desc, + (struct usb_descriptor_header *)&ss_epout_desc, + (struct usb_descriptor_header *)&ss_epout_desc_comp, + (struct usb_descriptor_header *)&as_iso_out_desc, + + (struct usb_descriptor_header *)&std_as_in_if0_desc, + (struct usb_descriptor_header *)&std_as_in_if1_desc, + + (struct usb_descriptor_header *)&as_in_hdr_desc, + (struct usb_descriptor_header *)&as_in_fmt1_desc, + (struct usb_descriptor_header *)&ss_epin_desc, + (struct usb_descriptor_header *)&ss_epin_desc_comp, + (struct usb_descriptor_header *)&as_iso_in_desc, + NULL, +}; + struct cntrl_cur_lay3 { __le32 dCUR; }; @@ -459,6 +530,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, break; case USB_SPEED_HIGH: + case USB_SPEED_SUPER: max_size_ep = 1024; factor = 8000; break; @@ -488,6 +560,72 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, /* Use macro to overcome line length limitation */ #define USBDHDR(p) (struct usb_descriptor_header *)(p) +static void setup_headers(struct f_uac2_opts *opts, + struct usb_descriptor_header **headers, + enum usb_device_speed speed) +{ + struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL; + struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL; + struct usb_endpoint_descriptor *epout_desc; + struct usb_endpoint_descriptor *epin_desc; + int i; + + switch (speed) { + case USB_SPEED_FULL: + epout_desc = &fs_epout_desc; + epin_desc = &fs_epin_desc; + break; + case USB_SPEED_HIGH: + epout_desc = &hs_epout_desc; + epin_desc = &hs_epin_desc; + break; + default: + epout_desc = &ss_epout_desc; + epin_desc = &ss_epin_desc; + epout_desc_comp = &ss_epout_desc_comp; + epin_desc_comp = &ss_epin_desc_comp; + } + + i = 0; + headers[i++] = USBDHDR(&iad_desc); + headers[i++] = USBDHDR(&std_ac_if_desc); + headers[i++] = USBDHDR(&ac_hdr_desc); + if (EPIN_EN(opts)) + headers[i++] = USBDHDR(&in_clk_src_desc); + if (EPOUT_EN(opts)) { + headers[i++] = USBDHDR(&out_clk_src_desc); + headers[i++] = USBDHDR(&usb_out_it_desc); + } + if (EPIN_EN(opts)) { + headers[i++] = USBDHDR(&io_in_it_desc); + headers[i++] = USBDHDR(&usb_in_ot_desc); + } + if (EPOUT_EN(opts)) { + headers[i++] = USBDHDR(&io_out_ot_desc); + headers[i++] = USBDHDR(&std_as_out_if0_desc); + headers[i++] = USBDHDR(&std_as_out_if1_desc); + headers[i++] = USBDHDR(&as_out_hdr_desc); + headers[i++] = USBDHDR(&as_out_fmt1_desc); + headers[i++] = USBDHDR(epout_desc); + if (epout_desc_comp) + headers[i++] = USBDHDR(epout_desc_comp); + + headers[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + headers[i++] = USBDHDR(&std_as_in_if0_desc); + headers[i++] = USBDHDR(&std_as_in_if1_desc); + headers[i++] = USBDHDR(&as_in_hdr_desc); + headers[i++] = USBDHDR(&as_in_fmt1_desc); + headers[i++] = USBDHDR(epin_desc); + if (epin_desc_comp) + headers[i++] = USBDHDR(epin_desc_comp); + + headers[i++] = USBDHDR(&as_iso_in_desc); + } + headers[i] = NULL; +} + static void setup_descriptor(struct f_uac2_opts *opts) { /* patch descriptors */ @@ -537,71 +675,39 @@ static void setup_descriptor(struct f_uac2_opts *opts) iad_desc.bInterfaceCount++; } - i = 0; - fs_audio_desc[i++] = USBDHDR(&iad_desc); - fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); - fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); - if (EPIN_EN(opts)) - fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); - if (EPOUT_EN(opts)) { - fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); - fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); - } - if (EPIN_EN(opts)) { - fs_audio_desc[i++] = USBDHDR(&io_in_it_desc); - fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); - } - if (EPOUT_EN(opts)) { - fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); - fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); - fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); - fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); - fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); - fs_audio_desc[i++] = USBDHDR(&fs_epout_desc); - fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); - } - if (EPIN_EN(opts)) { - fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); - fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); - fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); - fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); - fs_audio_desc[i++] = USBDHDR(&fs_epin_desc); - fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); - } - fs_audio_desc[i] = NULL; + setup_headers(opts, fs_audio_desc, USB_SPEED_FULL); + setup_headers(opts, hs_audio_desc, USB_SPEED_HIGH); + setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER); +} - i = 0; - hs_audio_desc[i++] = USBDHDR(&iad_desc); - hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); - hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); - if (EPIN_EN(opts)) - hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); - if (EPOUT_EN(opts)) { - hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); - hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); - } - if (EPIN_EN(opts)) { - hs_audio_desc[i++] = USBDHDR(&io_in_it_desc); - hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); - } - if (EPOUT_EN(opts)) { - hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); - hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); - hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); - hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); - hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); - hs_audio_desc[i++] = USBDHDR(&hs_epout_desc); - hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); - } - if (EPIN_EN(opts)) { - hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); - hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); - hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); - hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); - hs_audio_desc[i++] = USBDHDR(&hs_epin_desc); - hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); +static int afunc_validate_opts(struct g_audio *agdev, struct device *dev) +{ + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + + if (!opts->p_chmask && !opts->c_chmask) { + dev_err(dev, "Error: no playback and capture channels\n"); + return -EINVAL; + } else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported playback channels mask\n"); + return -EINVAL; + } else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported capture channels mask\n"); + return -EINVAL; + } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) { + dev_err(dev, "Error: incorrect playback sample size\n"); + return -EINVAL; + } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) { + dev_err(dev, "Error: incorrect capture sample size\n"); + return -EINVAL; + } else if (!opts->p_srate) { + dev_err(dev, "Error: incorrect playback sampling rate\n"); + return -EINVAL; + } else if (!opts->c_srate) { + dev_err(dev, "Error: incorrect capture sampling rate\n"); + return -EINVAL; } - hs_audio_desc[i] = NULL; + + return 0; } static int @@ -612,11 +718,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) struct usb_composite_dev *cdev = cfg->cdev; struct usb_gadget *gadget = cdev->gadget; struct device *dev = &gadget->dev; - struct f_uac2_opts *uac2_opts; + struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev); struct usb_string *us; int ret; - uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst); + ret = afunc_validate_opts(agdev, dev); + if (ret) + return ret; us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); if (IS_ERR(us)) @@ -716,6 +824,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) return ret; } + ret = set_ep_max_packet_size(uac2_opts, &ss_epin_desc, USB_SPEED_SUPER, + true); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } + + ret = set_ep_max_packet_size(uac2_opts, &ss_epout_desc, USB_SPEED_SUPER, + false); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } + if (EPOUT_EN(uac2_opts)) { agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); if (!agdev->out_ep) { @@ -739,13 +861,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) le16_to_cpu(fs_epout_desc.wMaxPacketSize), le16_to_cpu(hs_epout_desc.wMaxPacketSize)); + agdev->in_ep_maxpsize = max_t(u16, agdev->in_ep_maxpsize, + le16_to_cpu(ss_epin_desc.wMaxPacketSize)); + agdev->out_ep_maxpsize = max_t(u16, agdev->out_ep_maxpsize, + le16_to_cpu(ss_epout_desc.wMaxPacketSize)); + hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; + ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; + ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; setup_descriptor(uac2_opts); - ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, - NULL); + ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc, + ss_audio_desc); if (ret) return ret; diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 44b4352a26765d01ca7005cf5915bf5a46e5262d..f48a00e4979455a7fc1bba0f1e8a091deeaf56c4 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -633,7 +633,12 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc_hs_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11)); - uvc_hs_streaming_ep.bInterval = opts->streaming_interval; + + /* A high-bandwidth endpoint must specify a bInterval value of 1 */ + if (max_packet_mult > 1) + uvc_hs_streaming_ep.bInterval = 1; + else + uvc_hs_streaming_ep.bInterval = opts->streaming_interval; uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size); uvc_ss_streaming_ep.bInterval = opts->streaming_interval; @@ -817,6 +822,7 @@ static struct usb_function_instance *uvc_alloc_inst(void) pd->bmControls[0] = 1; pd->bmControls[1] = 0; pd->iProcessing = 0; + pd->bmVideoStandards = 0; od = &opts->uvc_output_terminal; od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE; diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 265c4d805f810049c0eabb67495a15434959ac76..5fbceee897a3f2bfa0a17fb05bf7a1b90a5d0a39 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -549,15 +549,15 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, if (err < 0) goto snd_fail; - strlcpy(pcm->name, pcm_name, sizeof(pcm->name)); + strscpy(pcm->name, pcm_name, sizeof(pcm->name)); pcm->private_data = uac; uac->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops); - strlcpy(card->driver, card_name, sizeof(card->driver)); - strlcpy(card->shortname, card_name, sizeof(card->shortname)); + strscpy(card->driver, card_name, sizeof(card->driver)); + strscpy(card->shortname, card_name, sizeof(card->shortname)); sprintf(card->longname, "%s %i", card_name, card->dev->id); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 00fb58e50a1554ec2e7a53e4d65a071553245b71..cd28dec837dd8236827ce859006d4b4d4690b98b 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -231,7 +231,7 @@ static struct config_item *uvcg_control_header_make(struct config_group *group, h->desc.bLength = UVC_DT_HEADER_SIZE(1); h->desc.bDescriptorType = USB_DT_CS_INTERFACE; h->desc.bDescriptorSubType = UVC_VC_HEADER; - h->desc.bcdUVC = cpu_to_le16(0x0100); + h->desc.bcdUVC = cpu_to_le16(0x0110); h->desc.dwClockFrequency = cpu_to_le32(48000000); config_item_init_type_name(&h->item, name, &uvcg_control_header_type); diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 71e7d10dd76b90b458582d69334662a9446005ff..cd8e2737947bad780e3f11388e7ed14f882510ee 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -498,7 +498,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ - iocb->ki_complete(iocb, req->actual ? req->actual : req->status, + iocb->ki_complete(iocb, + req->actual ? req->actual : (long)req->status, req->status); } else { /* ep_copy_to_user() won't report both; we hide some faults */ diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index 9ed22c5fb7fe27f20df25edeabd19500414a3928..ac1741126619ba2affba837891e511a9a0079cef 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -175,8 +175,10 @@ static int msg_bind(struct usb_composite_dev *cdev) struct usb_descriptor_header *usb_desc; usb_desc = usb_otg_descriptor_alloc(cdev->gadget); - if (!usb_desc) + if (!usb_desc) { + status = -ENOMEM; goto fail_string_ids; + } usb_otg_descriptor_init(cdev->gadget, usb_desc); otg_desc[0] = usb_desc; otg_desc[1] = NULL; diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index ec974984566095a54cbae210b384ff600c2dfdd4..8db5c91ae47de9d29b718f7834ee80d41cdcafd8 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -182,7 +182,7 @@ err_func_rndis: return ret; } -static __ref int rndis_config_register(struct usb_composite_dev *cdev) +static int rndis_config_register(struct usb_composite_dev *cdev) { static struct usb_configuration config = { .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM, @@ -197,7 +197,7 @@ static __ref int rndis_config_register(struct usb_composite_dev *cdev) #else -static __ref int rndis_config_register(struct usb_composite_dev *cdev) +static int rndis_config_register(struct usb_composite_dev *cdev) { return 0; } @@ -265,7 +265,7 @@ err_func_ecm: return ret; } -static __ref int cdc_config_register(struct usb_composite_dev *cdev) +static int cdc_config_register(struct usb_composite_dev *cdev) { static struct usb_configuration config = { .bConfigurationValue = MULTI_CDC_CONFIG_NUM, @@ -280,7 +280,7 @@ static __ref int cdc_config_register(struct usb_composite_dev *cdev) #else -static __ref int cdc_config_register(struct usb_composite_dev *cdev) +static int cdc_config_register(struct usb_composite_dev *cdev) { return 0; } @@ -291,7 +291,7 @@ static __ref int cdc_config_register(struct usb_composite_dev *cdev) /****************************** Gadget Bind ******************************/ -static int __ref multi_bind(struct usb_composite_dev *cdev) +static int multi_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; #ifdef CONFIG_USB_G_MULTI_CDC @@ -399,8 +399,10 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) struct usb_descriptor_header *usb_desc; usb_desc = usb_otg_descriptor_alloc(gadget); - if (!usb_desc) + if (!usb_desc) { + status = -ENOMEM; goto fail_string_ids; + } usb_otg_descriptor_init(gadget, usb_desc); otg_desc[0] = usb_desc; otg_desc[1] = NULL; diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index a9f8eb8e1c767ce961762e8fcf22112bcf41d221..94e22867da1d0351dbcf1ff0062d3fbe1598eb73 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c @@ -90,7 +90,7 @@ static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { .bLength = UVC_DT_HEADER_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = UVC_VC_HEADER, - .bcdUVC = cpu_to_le16(0x0100), + .bcdUVC = cpu_to_le16(0x0110), .wTotalLength = 0, /* dynamic */ .dwClockFrequency = cpu_to_le32(48000000), .bInCollection = 0, /* dynamic */ @@ -125,6 +125,7 @@ static const struct uvc_processing_unit_descriptor uvc_processing = { .bmControls[0] = 1, .bmControls[1] = 0, .iProcessing = 0, + .bmVideoStandards = 0, }; static const struct uvc_output_terminal_descriptor uvc_output_terminal = { diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index be7bb64e3594d36fbe76f58a7d22e361d73ec548..d11d3d14313f9286f8a2c494b7c9d2dc0aae5bb8 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -36,6 +36,7 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, int status) { bool internal = req->internal; + struct ast_vhub *vhub = ep->vhub; EPVDBG(ep, "completing request @%p, status %d\n", req, status); @@ -46,7 +47,7 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, if (req->req.dma) { if (!WARN_ON(!ep->dev)) - usb_gadget_unmap_request(&ep->dev->gadget, + usb_gadget_unmap_request_by_dev(&vhub->pdev->dev, &req->req, ep->epn.is_in); req->req.dma = 0; } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 02d8bfae58fb141dfe4aac8720df258fdb0ab44b..cb164c615e6fce12f781fa6b91a5962e5dd69ebd 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -376,7 +376,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req, if (ep->epn.desc_mode || ((((unsigned long)u_req->buf & 7) == 0) && (ep->epn.is_in || !(u_req->length & (u_ep->maxpacket - 1))))) { - rc = usb_gadget_map_request(&ep->dev->gadget, u_req, + rc = usb_gadget_map_request_by_dev(&vhub->pdev->dev, u_req, ep->epn.is_in); if (rc) { dev_warn(&vhub->pdev->dev, diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 57067763b1005f7fcd021b5012cb7d1b11b97639..7db773c87379c03b7ae65f5e9427618060584a9c 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -903,6 +903,21 @@ static int dummy_pullup(struct usb_gadget *_gadget, int value) spin_lock_irqsave(&dum->lock, flags); dum->pullup = (value != 0); set_link_state(dum_hcd); + if (value == 0) { + /* + * Emulate synchronize_irq(): wait for callbacks to finish. + * This seems to be the best place to emulate the call to + * synchronize_irq() that's in usb_gadget_remove_driver(). + * Doing it in dummy_udc_stop() would be too late since it + * is called after the unbind callback and unbind shouldn't + * be invoked until all the other callbacks are finished. + */ + while (dum->callback_usage > 0) { + spin_unlock_irqrestore(&dum->lock, flags); + usleep_range(1000, 2000); + spin_lock_irqsave(&dum->lock, flags); + } + } spin_unlock_irqrestore(&dum->lock, flags); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); @@ -1004,14 +1019,6 @@ static int dummy_udc_stop(struct usb_gadget *g) spin_lock_irq(&dum->lock); dum->ints_enabled = 0; stop_activity(dum); - - /* emulate synchronize_irq(): wait for callbacks to finish */ - while (dum->callback_usage > 0) { - spin_unlock_irq(&dum->lock); - usleep_range(1000, 2000); - spin_lock_irq(&dum->lock); - } - dum->driver = NULL; spin_unlock_irq(&dum->lock); @@ -1866,7 +1873,7 @@ restart: /* handle control requests */ if (ep == &dum->ep[0] && ep->setup_stage) { struct usb_ctrlrequest setup; - int value = 1; + int value; setup = *(struct usb_ctrlrequest *) urb->setup_packet; /* paranoia, in case of stale queued data */ diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index d6ca50f019853675b865bc8e60423fe73d54744a..fdca28e72a3b4d1441afa7044e418bb00994abfa 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -338,15 +338,16 @@ static void fotg210_start_dma(struct fotg210_ep *ep, } else { buffer = req->req.buf + req->req.actual; length = ioread32(ep->fotg210->reg + - FOTG210_FIBCR(ep->epnum - 1)); - length &= FIBCR_BCFX; + FOTG210_FIBCR(ep->epnum - 1)) & FIBCR_BCFX; + if (length > req->req.length - req->req.actual) + length = req->req.length - req->req.actual; } } else { buffer = req->req.buf + req->req.actual; if (req->req.length - req->req.actual > ep->ep.maxpacket) length = ep->ep.maxpacket; else - length = req->req.length; + length = req->req.length - req->req.actual; } d = dma_map_single(dev, buffer, length, @@ -379,8 +380,7 @@ static void fotg210_ep0_queue(struct fotg210_ep *ep, } if (ep->dir_in) { /* if IN */ fotg210_start_dma(ep, req); - if ((req->req.length == req->req.actual) || - (req->req.actual < ep->ep.maxpacket)) + if (req->req.length == req->req.actual) fotg210_done(ep, req, 0); } else { /* OUT */ u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0); @@ -820,7 +820,7 @@ static void fotg210_ep0in(struct fotg210_udc *fotg210) if (req->req.length) fotg210_start_dma(ep, req); - if ((req->req.length - req->req.actual) < ep->ep.maxpacket) + if (req->req.actual == req->req.length) fotg210_done(ep, req, 0); } else { fotg210_set_cxdone(fotg210); @@ -849,12 +849,16 @@ static void fotg210_out_fifo_handler(struct fotg210_ep *ep) { struct fotg210_request *req = list_entry(ep->queue.next, struct fotg210_request, queue); + int disgr1 = ioread32(ep->fotg210->reg + FOTG210_DISGR1); fotg210_start_dma(ep, req); - /* finish out transfer */ + /* Complete the request when it's full or a short packet arrived. + * Like other drivers, short_not_ok isn't handled. + */ + if (req->req.length == req->req.actual || - req->req.actual < ep->ep.maxpacket) + (disgr1 & DISGR1_SPK_INT(ep->epnum - 1))) fotg210_done(ep, req, 0); } @@ -877,6 +881,8 @@ static irqreturn_t fotg210_irq(int irq, void *_fotg210) int_grp2 &= ~int_msk2; if (int_grp2 & DISGR2_USBRST_INT) { + usb_gadget_udc_reset(&fotg210->gadget, + fotg210->driver); value = ioread32(reg); value &= ~DISGR2_USBRST_INT; iowrite32(value, reg); @@ -1027,6 +1033,12 @@ static void fotg210_init(struct fotg210_udc *fotg210) value &= ~DMCR_GLINT_EN; iowrite32(value, fotg210->reg + FOTG210_DMCR); + /* enable only grp2 irqs we handle */ + iowrite32(~(DISGR2_DMA_ERROR | DISGR2_RX0BYTE_INT | DISGR2_TX0BYTE_INT + | DISGR2_ISO_SEQ_ABORT_INT | DISGR2_ISO_SEQ_ERR_INT + | DISGR2_RESM_INT | DISGR2_SUSP_INT | DISGR2_USBRST_INT), + fotg210->reg + FOTG210_DMISGR2); + /* disable all fifo interrupt */ iowrite32(~(u32)0, fotg210->reg + FOTG210_DMISGR1); diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 23a735641c3df4882981d950115377ca1144cd59..89f479b78d80ef97d82d6b4e515818d1d9921c71 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -539,7 +539,6 @@ net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) int count; int tmp; int cleanup = 0; - int status = -1; dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n", ep->ep.name, req->req.actual, req->req.length); @@ -591,6 +590,8 @@ net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) } if (!list_empty(&ep->queue)) { + int status; + req = list_entry(ep->queue.next, struct net2272_request, queue); status = net2272_kick_dma(ep, req); diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index a3c1fc9242686c06bd3e0b90543cbf5f2cd47c2c..9bb7a9d7a2fb245e6039e6254db4077dff4fd998 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -8,11 +8,12 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/errno.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/list.h> #include <linux/interrupt.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#include <linux/gpio/consumer.h> #include <linux/irq.h> #define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */ @@ -331,6 +332,7 @@ struct pch_vbus_gpio_data { * @dma_addr: DMA pool for received * @setup_data: Received setup data * @base_addr: for mapped device memory + * @bar: PCI BAR used for mapped device memory * @cfg_data: current cfg, intf, and alt in use * @vbus_gpio: GPIO informaton for detecting VBUS */ @@ -353,6 +355,7 @@ struct pch_udc_dev { dma_addr_t dma_addr; struct usb_ctrlrequest setup_data; void __iomem *base_addr; + unsigned short bar; struct pch_udc_cfg_data cfg_data; struct pch_vbus_gpio_data vbus_gpio; }; @@ -381,11 +384,8 @@ MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); * @td_data_last: last dma desc. of chain * @queue: associated queue * @dma_going: DMA in progress for request - * @dma_mapped: DMA memory mapped for request * @dma_done: DMA completed for request * @chain_len: chain length - * @buf: Buffer memory for align adjustment - * @dma: DMA memory for align adjustment */ struct pch_udc_request { struct usb_request req; @@ -394,11 +394,8 @@ struct pch_udc_request { struct pch_udc_data_dma_desc *td_data_last; struct list_head queue; unsigned dma_going:1, - dma_mapped:1, dma_done:1; unsigned chain_len; - void *buf; - dma_addr_t dma; }; static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg) @@ -563,12 +560,13 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev) pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); } +static void pch_udc_init(struct pch_udc_dev *dev); + /** * pch_udc_reconnect() - This API initializes usb device controller, * and clear the disconnect status. * @dev: Reference to pch_udc_regs structure */ -static void pch_udc_init(struct pch_udc_dev *dev); static void pch_udc_reconnect(struct pch_udc_dev *dev) { pch_udc_init(dev); @@ -596,18 +594,22 @@ static void pch_udc_reconnect(struct pch_udc_dev *dev) static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, int is_active) { + unsigned long iflags; + + spin_lock_irqsave(&dev->lock, iflags); if (is_active) { pch_udc_reconnect(dev); dev->vbus_session = 1; } else { if (dev->driver && dev->driver->disconnect) { - spin_lock(&dev->lock); + spin_unlock_irqrestore(&dev->lock, iflags); dev->driver->disconnect(&dev->gadget); - spin_unlock(&dev->lock); + spin_lock_irqsave(&dev->lock, iflags); } pch_udc_set_disconnect(dev); dev->vbus_session = 0; } + spin_unlock_irqrestore(&dev->lock, iflags); } /** @@ -1166,20 +1168,25 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value) static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on) { struct pch_udc_dev *dev; + unsigned long iflags; if (!gadget) return -EINVAL; + dev = container_of(gadget, struct pch_udc_dev, gadget); + + spin_lock_irqsave(&dev->lock, iflags); if (is_on) { pch_udc_reconnect(dev); } else { if (dev->driver && dev->driver->disconnect) { - spin_lock(&dev->lock); + spin_unlock_irqrestore(&dev->lock, iflags); dev->driver->disconnect(&dev->gadget); - spin_unlock(&dev->lock); + spin_lock_irqsave(&dev->lock, iflags); } pch_udc_set_disconnect(dev); } + spin_unlock_irqrestore(&dev->lock, iflags); return 0; } @@ -1360,6 +1367,7 @@ static irqreturn_t pch_vbus_gpio_irq(int irq, void *data) */ static int pch_vbus_gpio_init(struct pch_udc_dev *dev) { + struct device *d = &dev->pdev->dev; int err; int irq_num = 0; struct gpio_desc *gpiod; @@ -1368,7 +1376,7 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev) dev->vbus_gpio.intr = 0; /* Retrieve the GPIO line from the USB gadget device */ - gpiod = devm_gpiod_get(dev->gadget.dev.parent, NULL, GPIOD_IN); + gpiod = devm_gpiod_get_optional(d, NULL, GPIOD_IN); if (IS_ERR(gpiod)) return PTR_ERR(gpiod); gpiod_set_consumer_name(gpiod, "pch_vbus"); @@ -1428,33 +1436,7 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, status = req->req.status; dev = ep->dev; - if (req->dma_mapped) { - if (req->dma == DMA_ADDR_INVALID) { - if (ep->in) - dma_unmap_single(&dev->pdev->dev, req->req.dma, - req->req.length, - DMA_TO_DEVICE); - else - dma_unmap_single(&dev->pdev->dev, req->req.dma, - req->req.length, - DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - } else { - if (ep->in) - dma_unmap_single(&dev->pdev->dev, req->dma, - req->req.length, - DMA_TO_DEVICE); - else { - dma_unmap_single(&dev->pdev->dev, req->dma, - req->req.length, - DMA_FROM_DEVICE); - memcpy(req->req.buf, req->buf, req->req.length); - } - kfree(req->buf); - req->dma = DMA_ADDR_INVALID; - } - req->dma_mapped = 0; - } + usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in); ep->halted = 1; spin_unlock(&dev->lock); if (!ep->in) @@ -1532,12 +1514,9 @@ static int pch_udc_create_dma_chain(struct pch_udc_ep *ep, if (req->chain_len > 1) pch_udc_free_dma_chain(ep->dev, req); - if (req->dma == DMA_ADDR_INVALID) - td->dataptr = req->req.dma; - else - td->dataptr = req->dma; - + td->dataptr = req->req.dma; td->status = PCH_UDC_BS_HST_BSY; + for (; ; bytes -= buf_len, ++len) { td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes); if (bytes <= buf_len) @@ -1743,7 +1722,6 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, if (!req) return NULL; req->req.dma = DMA_ADDR_INVALID; - req->dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&req->queue); if (!ep->dev->dma_addr) return &req->req; @@ -1756,7 +1734,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, } /* prevent from using desc. - set HOST BUSY */ dma_desc->status |= PCH_UDC_BS_HST_BSY; - dma_desc->dataptr = cpu_to_le32(DMA_ADDR_INVALID); + dma_desc->dataptr = lower_32_bits(DMA_ADDR_INVALID); req->td_data = dma_desc; req->td_data_last = dma_desc; req->chain_len = 1; @@ -1826,39 +1804,9 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, return -ESHUTDOWN; spin_lock_irqsave(&dev->lock, iflags); /* map the buffer for dma */ - if (usbreq->length && - ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) { - if (!((unsigned long)(usbreq->buf) & 0x03)) { - if (ep->in) - usbreq->dma = dma_map_single(&dev->pdev->dev, - usbreq->buf, - usbreq->length, - DMA_TO_DEVICE); - else - usbreq->dma = dma_map_single(&dev->pdev->dev, - usbreq->buf, - usbreq->length, - DMA_FROM_DEVICE); - } else { - req->buf = kzalloc(usbreq->length, GFP_ATOMIC); - if (!req->buf) { - retval = -ENOMEM; - goto probe_end; - } - if (ep->in) { - memcpy(req->buf, usbreq->buf, usbreq->length); - req->dma = dma_map_single(&dev->pdev->dev, - req->buf, - usbreq->length, - DMA_TO_DEVICE); - } else - req->dma = dma_map_single(&dev->pdev->dev, - req->buf, - usbreq->length, - DMA_FROM_DEVICE); - } - req->dma_mapped = 1; - } + retval = usb_gadget_map_request(&dev->gadget, usbreq, ep->in); + if (retval) + goto probe_end; if (usbreq->length > 0) { retval = prepare_dma(ep, req, GFP_ATOMIC); if (retval) @@ -2298,6 +2246,21 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num) pch_udc_set_dma(dev, DMA_DIR_RX); } +static int pch_udc_gadget_setup(struct pch_udc_dev *dev) + __must_hold(&dev->lock) +{ + int rc; + + /* In some cases we can get an interrupt before driver gets setup */ + if (!dev->driver) + return -ESHUTDOWN; + + spin_unlock(&dev->lock); + rc = dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_lock(&dev->lock); + return rc; +} + /** * pch_udc_svc_control_in() - Handle Control IN endpoint interrupts * @dev: Reference to the device structure @@ -2369,15 +2332,12 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; else /* OUT */ dev->gadget.ep0 = &ep->ep; - spin_lock(&dev->lock); /* If Mass storage Reset */ if ((dev->setup_data.bRequestType == 0x21) && (dev->setup_data.bRequest == 0xFF)) dev->prot_stall = 0; /* call gadget with setup data received */ - setup_supported = dev->driver->setup(&dev->gadget, - &dev->setup_data); - spin_unlock(&dev->lock); + setup_supported = pch_udc_gadget_setup(dev); if (dev->setup_data.bRequestType & USB_DIR_IN) { ep->td_data->status = (ep->td_data->status & @@ -2625,9 +2585,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) dev->ep[i].halted = 0; } dev->stall = 0; - spin_unlock(&dev->lock); - dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); + pch_udc_gadget_setup(dev); } /** @@ -2662,9 +2620,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) dev->stall = 0; /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); + pch_udc_gadget_setup(dev); } /** @@ -2870,14 +2826,20 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) * @dev: Reference to the driver structure * * Return codes: - * 0: Success + * 0: Success + * -ERRNO: All kind of errors when retrieving VBUS GPIO */ static int pch_udc_pcd_init(struct pch_udc_dev *dev) { + int ret; + pch_udc_init(dev); pch_udc_pcd_reinit(dev); - pch_vbus_gpio_init(dev); - return 0; + + ret = pch_vbus_gpio_init(dev); + if (ret) + pch_udc_exit(dev); + return ret; } /** @@ -2938,7 +2900,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); - return 0; + return dma_mapping_error(&dev->pdev->dev, dev->dma_addr); } static int pch_udc_start(struct usb_gadget *g, @@ -2976,6 +2938,38 @@ static int pch_udc_stop(struct usb_gadget *g) return 0; } +static void pch_vbus_gpio_remove_table(void *table) +{ + gpiod_remove_lookup_table(table); +} + +static int pch_vbus_gpio_add_table(struct device *d, void *table) +{ + gpiod_add_lookup_table(table); + return devm_add_action_or_reset(d, pch_vbus_gpio_remove_table, table); +} + +static struct gpiod_lookup_table pch_udc_minnow_vbus_gpio_table = { + .dev_id = "0000:02:02.4", + .table = { + GPIO_LOOKUP("sch_gpio.33158", 12, NULL, GPIO_ACTIVE_HIGH), + {} + }, +}; + +static int pch_udc_minnow_platform_init(struct device *d) +{ + return pch_vbus_gpio_add_table(d, &pch_udc_minnow_vbus_gpio_table); +} + +static int pch_udc_quark_platform_init(struct device *d) +{ + struct pch_udc_dev *dev = dev_get_drvdata(d); + + dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000; + return 0; +} + static void pch_udc_shutdown(struct pci_dev *pdev) { struct pch_udc_dev *dev = pci_get_drvdata(pdev); @@ -3024,8 +3018,7 @@ static void pch_udc_remove(struct pci_dev *pdev) pch_udc_exit(dev); } -#ifdef CONFIG_PM_SLEEP -static int pch_udc_suspend(struct device *d) +static int __maybe_unused pch_udc_suspend(struct device *d) { struct pch_udc_dev *dev = dev_get_drvdata(d); @@ -3035,21 +3028,18 @@ static int pch_udc_suspend(struct device *d) return 0; } -static int pch_udc_resume(struct device *d) +static int __maybe_unused pch_udc_resume(struct device *d) { return 0; } static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume); -#define PCH_UDC_PM_OPS (&pch_udc_pm) -#else -#define PCH_UDC_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ -static int pch_udc_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +typedef int (*platform_init_fn)(struct device *); + +static int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int bar; + platform_init_fn platform_init = (platform_init_fn)id->driver_data; int retval; struct pch_udc_dev *dev; @@ -3063,31 +3053,28 @@ static int pch_udc_probe(struct pci_dev *pdev, if (retval) return retval; + dev->bar = PCH_UDC_PCI_BAR; + dev->pdev = pdev; pci_set_drvdata(pdev, dev); - /* Determine BAR based on PCI ID */ - if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC) - bar = PCH_UDC_PCI_BAR_QUARK_X1000; - else - bar = PCH_UDC_PCI_BAR; + /* Platform specific hook */ + if (platform_init) { + retval = platform_init(&pdev->dev); + if (retval) + return retval; + } /* PCI resource allocation */ - retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev)); + retval = pcim_iomap_regions(pdev, BIT(dev->bar), pci_name(pdev)); if (retval) return retval; - dev->base_addr = pcim_iomap_table(pdev)[bar]; - - /* - * FIXME: add a GPIO descriptor table to pdev.dev using - * gpiod_add_descriptor_table() from <linux/gpio/machine.h> based on - * the PCI subsystem ID. The system-dependent GPIO is necessary for - * VBUS operation. - */ + dev->base_addr = pcim_iomap_table(pdev)[dev->bar]; /* initialize the hardware */ - if (pch_udc_pcd_init(dev)) - return -ENODEV; + retval = pch_udc_pcd_init(dev); + if (retval) + return retval; pci_enable_msi(pdev); @@ -3104,7 +3091,6 @@ static int pch_udc_probe(struct pci_dev *pdev, /* device struct setup */ spin_lock_init(&dev->lock); - dev->pdev = pdev; dev->gadget.ops = &pch_udc_ops; retval = init_dma_pools(dev); @@ -3128,10 +3114,17 @@ finished: static const struct pci_device_id pch_udc_pcidev_id[] = { { - PCI_DEVICE(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC), + .class = PCI_CLASS_SERIAL_USB_DEVICE, + .class_mask = 0xffffffff, + .driver_data = (kernel_ulong_t)&pch_udc_quark_platform_init, + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC, + PCI_VENDOR_ID_CIRCUITCO, PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD), .class = PCI_CLASS_SERIAL_USB_DEVICE, .class_mask = 0xffffffff, + .driver_data = (kernel_ulong_t)&pch_udc_minnow_platform_init, }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC), @@ -3160,7 +3153,7 @@ static struct pci_driver pch_udc_driver = { .remove = pch_udc_remove, .shutdown = pch_udc_shutdown, .driver = { - .pm = PCH_UDC_PM_OPS, + .pm = &pch_udc_pm, }, }; diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 896c1a016d550e0482ab9bb7cff75fc00d37de7c..65cae4883454504aff68079a06b9dcd022bee397 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1849,6 +1849,8 @@ static int r8a66597_probe(struct platform_device *pdev) return PTR_ERR(reg); ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!ires) + return -EINVAL; irq = ires->start; irq_trigger = ires->flags & IRQF_TRIGGER_MASK; diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 1d3ebb07ccd4d8cfb9173c66e200f428eacf30c0..b154b62abefa192ea8aefa4e760b83b11740b5e7 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -54,8 +54,6 @@ static struct clk *udc_clock; static struct clk *usb_bus_clock; static void __iomem *base_addr; static int irq_usbd; -static u64 rsrc_start; -static u64 rsrc_len; static struct dentry *s3c2410_udc_debugfs_root; static inline u32 udc_read(u32 reg) @@ -1752,7 +1750,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev) udc_clock = clk_get(NULL, "usb-device"); if (IS_ERR(udc_clock)) { dev_err(dev, "failed to get udc clock source\n"); - return PTR_ERR(udc_clock); + retval = PTR_ERR(udc_clock); + goto err_usb_bus_clk; } clk_prepare_enable(udc_clock); @@ -1775,7 +1774,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base_addr)) { retval = PTR_ERR(base_addr); - goto err_mem; + goto err_udc_clk; } the_controller = udc; @@ -1793,7 +1792,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) if (retval != 0) { dev_err(dev, "cannot get irq %i, err %d\n", irq_usbd, retval); retval = -EBUSY; - goto err_map; + goto err_udc_clk; } dev_dbg(dev, "got irq %i\n", irq_usbd); @@ -1864,10 +1863,14 @@ err_gpio_claim: gpio_free(udc_info->vbus_pin); err_int: free_irq(irq_usbd, udc); -err_map: - iounmap(base_addr); -err_mem: - release_mem_region(rsrc_start, rsrc_len); +err_udc_clk: + clk_disable_unprepare(udc_clock); + clk_put(udc_clock); + udc_clock = NULL; +err_usb_bus_clk: + clk_disable_unprepare(usb_bus_clock); + clk_put(usb_bus_clock); + usb_bus_clock = NULL; return retval; } @@ -1899,9 +1902,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev) free_irq(irq_usbd, udc); - iounmap(base_addr); - release_mem_region(rsrc_start, rsrc_len); - if (!IS_ERR(udc_clock) && udc_clock != NULL) { clk_disable_unprepare(udc_clock); clk_put(udc_clock); diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index 32f1d3e90c26438c12b5bb0a5a46ca219f071842..99805d60a7ab3aa46b00892737c9d43b50a92a90 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -114,8 +114,8 @@ static int udc_plat_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); udc->virt_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(udc->regs)) - return PTR_ERR(udc->regs); + if (IS_ERR(udc->virt_addr)) + return PTR_ERR(udc->virt_addr); /* udc csr registers base */ udc->csr = udc->virt_addr + UDC_CSR_ADDR; diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 580bef8eb4cbcc5403c7a5660b33eccf1772da74..2319c9737c2bd3d220b0b857a38b4282a8c96d14 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -3883,7 +3883,7 @@ static int tegra_xudc_remove(struct platform_device *pdev) pm_runtime_get_sync(xudc->dev); - cancel_delayed_work(&xudc->plc_reset_work); + cancel_delayed_work_sync(&xudc->plc_reset_work); cancel_work_sync(&xudc->usb_role_sw_work); usb_del_gadget_udc(&xudc->gadget); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b94f2a070c056e1c71c3bb56cb328b06b8350147..df9428f1dc5ed53547e3f7b9347cac1c81e835e8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -272,6 +272,7 @@ config USB_EHCI_TEGRA select USB_CHIPIDEA select USB_CHIPIDEA_HOST select USB_CHIPIDEA_TEGRA + select USB_GADGET help This option is deprecated now and the driver was removed, use USB_CHIPIDEA_TEGRA instead. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 3e4d298d851f0cd0b46689b41ec97615251e7694..171de4df50bdc7694b52c4781418987e5e504190 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -19,9 +19,7 @@ ifneq ($(CONFIG_USB_XHCI_DBGCAP), ) xhci-hcd-y += xhci-dbgcap.o xhci-dbgtty.o endif -ifneq ($(CONFIG_USB_XHCI_MTK), ) - xhci-hcd-y += xhci-mtk-sch.o -endif +xhci-mtk-hcd-y := xhci-mtk.o xhci-mtk-sch.o xhci-plat-hcd-y := xhci-plat.o ifneq ($(CONFIG_USB_XHCI_MVEBU), ) @@ -73,7 +71,7 @@ obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o -obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o +obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1926b328b6aa7a2e5a7726561cd44ae111f40d76..94b5e64ae9a254a3df4a1dbc13fe435588061a87 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -651,7 +651,7 @@ static int ehci_run (struct usb_hcd *hcd) "USB %x.%x started, EHCI %x.%02x%s\n", ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), temp >> 8, temp & 0xff, - ignore_oc ? ", overcurrent ignored" : ""); + (ignore_oc || ehci->spurious_oc) ? ", overcurrent ignored" : ""); ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ @@ -705,15 +705,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status, masked_status, pcd_status = 0, cmd; int bh; - unsigned long flags; - /* - * For threadirqs option we use spin_lock_irqsave() variant to prevent - * deadlock with ehci hrtimer callback, because hrtimer callbacks run - * in interrupt context even when threadirqs is specified. We can go - * back to spin_lock() variant when hrtimer callbacks become threaded. - */ - spin_lock_irqsave(&ehci->lock, flags); + spin_lock(&ehci->lock); status = ehci_readl(ehci, &ehci->regs->status); @@ -731,7 +724,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* Shared IRQ? */ if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { - spin_unlock_irqrestore(&ehci->lock, flags); + spin_unlock(&ehci->lock); return IRQ_NONE; } @@ -842,7 +835,7 @@ dead: if (bh) ehci_work (ehci); - spin_unlock_irqrestore(&ehci->lock, flags); + spin_unlock(&ehci->lock); if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 9f9ab5ccea889df6e8aebf630d941a1c82c392c8..159cc27b1a362beeecb35ba3755bea8bc427b963 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -643,7 +643,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) * always set, seem to clear PORT_OCC and PORT_CSC when writing to * PORT_POWER; that's surprising, but maybe within-spec. */ - if (!ignore_oc) + if (!ignore_oc && !ehci->spurious_oc) mask = PORT_CSC | PORT_PEC | PORT_OCC; else mask = PORT_CSC | PORT_PEC; @@ -1013,7 +1013,7 @@ int ehci_hub_control( if (temp & PORT_PEC) status |= USB_PORT_STAT_C_ENABLE << 16; - if ((temp & PORT_OCC) && !ignore_oc){ + if ((temp & PORT_OCC) && (!ignore_oc && !ehci->spurious_oc)){ status |= USB_PORT_STAT_C_OVERCURRENT << 16; /* diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 71ec3025686fe13aafba203369dd5d3698fa2162..e87cf3a00fa4b237dbbe929cba91b8ea3fafe589 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -297,6 +297,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd) if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST) ; /* ConneXT has no sbrn register */ + else if (pdev->vendor == PCI_VENDOR_ID_HUAWEI + && pdev->device == 0xa239) + ; /* HUAWEI Kunpeng920 USB EHCI has no sbrn register */ else pci_read_config_byte(pdev, 0x60, &ehci->sbrn); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index a48dd3fac15373e6287242bc43c26a7fade3f7cf..c70f2d0b4aaf07f69e272f94ac19fc601e54bd2c 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -286,6 +286,9 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "big-endian")) ehci->big_endian_mmio = ehci->big_endian_desc = 1; + if (of_property_read_bool(dev->dev.of_node, "spurious-oc")) + ehci->spurious_oc = 1; + if (of_property_read_bool(dev->dev.of_node, "needs-reset-on-resume")) priv->reset_on_resume = true; @@ -327,6 +330,8 @@ static int ehci_platform_probe(struct platform_device *dev) hcd->has_tt = 1; if (pdata->reset_on_resume) priv->reset_on_resume = true; + if (pdata->spurious_oc) + ehci->spurious_oc = 1; #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO if (ehci->big_endian_mmio) { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index eabf22a78eae037ca51d7041d7d8ea42b2e07e42..80bb823aa9fe8fe3fb49c4d6e6ffe5c7fd744e7f 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -218,6 +218,7 @@ struct ehci_hcd { /* one per controller */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ unsigned need_oc_pp_cycle:1; /* MPC834X port power */ unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ + unsigned spurious_oc:1; /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 5617ef30530a65628703e0203846969de5036ce6..6cac642520fc8464ed3abce097cd4fd53c7fd271 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -408,17 +408,17 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, temp = snprintf(next, size, "\n\t%p%c%s len=%d %08x urb %p", td, mark, ({ char *tmp; - switch ((scratch>>8)&0x03) { - case 0: + switch ((scratch>>8)&0x03) { + case 0: tmp = "out"; break; - case 1: + case 1: tmp = "in"; break; - case 2: + case 2: tmp = "setup"; break; - default: + default: tmp = "?"; break; } tmp; }), @@ -2699,7 +2699,7 @@ cleanup: * any previous qh and cancel its urbs first; endpoints are * implicitly reset then (data toggle too). * That'd mean updating how usbcore talks to HCDs. (2.7?) -*/ + */ /* Each QH holds a qtd list; a QH is used for everything except iso. diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 8544a2a2c1e6a0c42d4ae8dde24a4e40553126f0..8835f6bd528e10fb5933c7397a6f5b4743639411 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1200,14 +1200,13 @@ DEFINE_SHOW_ATTRIBUTE(isp116x_debug); static void create_debug_file(struct isp116x *isp116x) { - isp116x->dentry = debugfs_create_file(hcd_name, - S_IRUGO, NULL, isp116x, - &isp116x_debug_fops); + debugfs_create_file(hcd_name, S_IRUGO, usb_debug_root, isp116x, + &isp116x_debug_fops); } static void remove_debug_file(struct isp116x *isp116x) { - debugfs_remove(isp116x->dentry); + debugfs_remove(debugfs_lookup(hcd_name, usb_debug_root)); } #else diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index a5e929c10d535bf83a715342c376d25374926ace..84904025fe7ff0cd85bfd44cc1b9bbaa4caef48f 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -260,7 +260,6 @@ struct isp116x { struct isp116x_platform_data *board; - struct dentry *dentry; unsigned long stat1, stat2, stat4, stat8, stat16; /* HC registers */ diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 2cecb36d241b4911550410e6ce3e4daea0d8ad3f..d8610ce8f2ecd4f87eb3034b8ee6681806c6941f 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2164,15 +2164,13 @@ DEFINE_SHOW_ATTRIBUTE(isp1362); /* expect just one isp1362_hcd per system */ static void create_debug_file(struct isp1362_hcd *isp1362_hcd) { - isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO, - usb_debug_root, - isp1362_hcd, - &isp1362_fops); + debugfs_create_file("isp1362", S_IRUGO, usb_debug_root, isp1362_hcd, + &isp1362_fops); } static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) { - debugfs_remove(isp1362_hcd->debug_file); + debugfs_remove(debugfs_lookup("isp1362", usb_debug_root)); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index 208705b08d37574db12bdfbe3df8a3bdf03ccf97..74ca4be24723ea68bcbae6c986f24a11959b0f42 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -435,7 +435,6 @@ struct isp1362_hcd { struct isp1362_platform_data *board; - struct dentry *debug_file; unsigned long stat1, stat2, stat4, stat8, stat16; /* HC registers */ diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 115ced0d93e101854e259e73cb7dc5608ad53869..85623731a51626daa004eed6f2830abb77ddbfa3 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1287,11 +1287,10 @@ sl811h_hub_control( goto error; put_unaligned_le32(sl811->port1, buf); -#ifndef VERBOSE - if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ -#endif - dev_dbg(hcd->self.controller, "GetPortStatus %08x\n", - sl811->port1); + if (__is_defined(VERBOSE) || + *(u16*)(buf+2)) /* only if wPortChange is interesting */ + dev_dbg(hcd->self.controller, "GetPortStatus %08x\n", + sl811->port1); break; case SetPortFeature: if (wIndex != 1 || wLength != 0) @@ -1496,14 +1495,13 @@ DEFINE_SHOW_ATTRIBUTE(sl811h_debug); /* expect just one sl811 per system */ static void create_debug_file(struct sl811 *sl811) { - sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO, - usb_debug_root, sl811, - &sl811h_debug_fops); + debugfs_create_file("sl811h", S_IRUGO, usb_debug_root, sl811, + &sl811h_debug_fops); } static void remove_debug_file(struct sl811 *sl811) { - debugfs_remove(sl811->debug_file); + debugfs_remove(debugfs_lookup("sl811h", usb_debug_root)); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h index 2abe51a5db4452517ae328f64c7f5dae28eb728a..ba8c9aa7dee852586aac7270b19359b36b9786da 100644 --- a/drivers/usb/host/sl811.h +++ b/drivers/usb/host/sl811.h @@ -123,7 +123,6 @@ struct sl811 { void __iomem *addr_reg; void __iomem *data_reg; struct sl811_platform_data *board; - struct dentry *debug_file; unsigned long stat_insrmv; unsigned long stat_wake; diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 72136373ffab0872e6568b8d369d716d781c5fc4..16d15701301831b08761e27154a51d73eef59bfa 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -94,7 +94,7 @@ static int sl811_hc_init(struct device *parent, resource_size_t base_addr, return -EBUSY; platform_dev.dev.parent = parent; - /* finish seting up the platform device */ + /* finish setting up the platform device */ resources[0].start = irq; resources[1].start = base_addr; diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index eb96e1e15b711b4dc58eebda20d8eb3f8b4c16cd..5a783c423d8e7e48298fb384880d36ad264bf480 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -78,7 +78,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); * u132_module_lock exists to protect access to global variables * */ -static struct mutex u132_module_lock; +static DEFINE_MUTEX(u132_module_lock); static int u132_exiting; static int u132_instances; /* @@ -3190,7 +3190,6 @@ static int __init u132_hcd_init(void) int retval; u132_instances = 0; u132_exiting = 0; - mutex_init(&u132_module_lock); if (usb_disabled()) return -ENODEV; printk(KERN_INFO "driver %s\n", hcd_name); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 03bc59755123fda5177c29a3a66a02d450fcc114..d90b869f5f409a801e3cab39304fd09219aaa6e8 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -536,7 +536,8 @@ static void release_uhci(struct uhci_hcd *uhci) uhci->is_initialized = 0; spin_unlock_irq(&uhci->lock); - debugfs_remove(uhci->dentry); + debugfs_remove(debugfs_lookup(uhci_to_hcd(uhci)->self.bus_name, + uhci_debugfs_root)); for (i = 0; i < UHCI_NUM_SKELQH; i++) uhci_free_qh(uhci, uhci->skelqh[i]); @@ -577,7 +578,6 @@ static int uhci_start(struct usb_hcd *hcd) struct uhci_hcd *uhci = hcd_to_uhci(hcd); int retval = -EBUSY; int i; - struct dentry __maybe_unused *dentry; hcd->uses_new_polling = 1; /* Accept arbitrarily long scatter-gather lists */ @@ -590,10 +590,8 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); #ifdef UHCI_DEBUG_OPS - uhci->dentry = debugfs_create_file(hcd->self.bus_name, - S_IFREG|S_IRUGO|S_IWUSR, - uhci_debugfs_root, uhci, - &uhci_debug_operations); + debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, + uhci_debugfs_root, uhci, &uhci_debug_operations); #endif uhci->frame = dma_alloc_coherent(uhci_dev(uhci), @@ -702,7 +700,7 @@ err_alloc_frame_cpu: uhci->frame, uhci->frame_dma_handle); err_alloc_frame: - debugfs_remove(uhci->dentry); + debugfs_remove(debugfs_lookup(hcd->self.bus_name, uhci_debugfs_root)); return retval; } diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 7f9f33c8c232413d5e85a01e29b3de4ec5151b9a..8ae5ccd26753b34d3c38823cc45840a4e8b9897b 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -381,10 +381,6 @@ enum uhci_rh_state { * The full UHCI controller information: */ struct uhci_hcd { - - /* debugfs */ - struct dentry *dentry; - /* Grabbed from PCI */ unsigned long io_addr; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 74c497fd34762066bc7057f4a64366d01cfefb42..e9b18fc176172312f512ac7b110564185261eeeb 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <asm/unaligned.h> +#include <linux/bitfield.h> #include "xhci.h" #include "xhci-trace.h" @@ -19,151 +20,236 @@ #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ PORT_RC | PORT_PLC | PORT_PE) -/* USB 3 BOS descriptor and a capability descriptors, combined. - * Fields will be adjusted and added later in xhci_create_usb3_bos_desc() - */ -static u8 usb_bos_descriptor [] = { - USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */ - USB_DT_BOS, /* __u8 bDescriptorType */ - 0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */ - 0x1, /* __u8 bNumDeviceCaps */ - /* First device capability, SuperSpeed */ - USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */ - USB_DT_DEVICE_CAPABILITY, /* Device Capability */ - USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */ - 0x00, /* bmAttributes, LTM off by default */ - USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */ - 0x03, /* bFunctionalitySupport, - USB 3.0 speed only */ - 0x00, /* bU1DevExitLat, set later. */ - 0x00, 0x00, /* __le16 bU2DevExitLat, set later. */ - /* Second device capability, SuperSpeedPlus */ - 0x1c, /* bLength 28, will be adjusted later */ - USB_DT_DEVICE_CAPABILITY, /* Device Capability */ - USB_SSP_CAP_TYPE, /* bDevCapabilityType SUPERSPEED_PLUS */ - 0x00, /* bReserved 0 */ - 0x23, 0x00, 0x00, 0x00, /* bmAttributes, SSAC=3 SSIC=1 */ - 0x01, 0x00, /* wFunctionalitySupport */ - 0x00, 0x00, /* wReserved 0 */ - /* Default Sublink Speed Attributes, overwrite if custom PSI exists */ - 0x34, 0x00, 0x05, 0x00, /* 5Gbps, symmetric, rx, ID = 4 */ - 0xb4, 0x00, 0x05, 0x00, /* 5Gbps, symmetric, tx, ID = 4 */ - 0x35, 0x40, 0x0a, 0x00, /* 10Gbps, SSP, symmetric, rx, ID = 5 */ - 0xb5, 0x40, 0x0a, 0x00, /* 10Gbps, SSP, symmetric, tx, ID = 5 */ +/* Default sublink speed attribute of each lane */ +static u32 ssp_cap_default_ssa[] = { + 0x00050034, /* USB 3.0 SS Gen1x1 id:4 symmetric rx 5Gbps */ + 0x000500b4, /* USB 3.0 SS Gen1x1 id:4 symmetric tx 5Gbps */ + 0x000a4035, /* USB 3.1 SSP Gen2x1 id:5 symmetric rx 10Gbps */ + 0x000a40b5, /* USB 3.1 SSP Gen2x1 id:5 symmetric tx 10Gbps */ + 0x00054036, /* USB 3.2 SSP Gen1x2 id:6 symmetric rx 5Gbps */ + 0x000540b6, /* USB 3.2 SSP Gen1x2 id:6 symmetric tx 5Gbps */ + 0x000a4037, /* USB 3.2 SSP Gen2x2 id:7 symmetric rx 10Gbps */ + 0x000a40b7, /* USB 3.2 SSP Gen2x2 id:7 symmetric tx 10Gbps */ }; -static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf, - u16 wLength) +static int xhci_create_usb3x_bos_desc(struct xhci_hcd *xhci, char *buf, + u16 wLength) { - struct xhci_port_cap *port_cap = NULL; - int i, ssa_count; - u32 temp; - u16 desc_size, ssp_cap_size, ssa_size = 0; - bool usb3_1 = false; - - desc_size = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; - ssp_cap_size = sizeof(usb_bos_descriptor) - desc_size; - - /* does xhci support USB 3.1 Enhanced SuperSpeed */ + struct usb_bos_descriptor *bos; + struct usb_ss_cap_descriptor *ss_cap; + struct usb_ssp_cap_descriptor *ssp_cap; + struct xhci_port_cap *port_cap = NULL; + u16 bcdUSB; + u32 reg; + u32 min_rate = 0; + u8 min_ssid; + u8 ssac; + u8 ssic; + int offset; + int i; + + /* BOS descriptor */ + bos = (struct usb_bos_descriptor *)buf; + bos->bLength = USB_DT_BOS_SIZE; + bos->bDescriptorType = USB_DT_BOS; + bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE + + USB_DT_USB_SS_CAP_SIZE); + bos->bNumDeviceCaps = 1; + + /* Create the descriptor for port with the highest revision */ for (i = 0; i < xhci->num_port_caps; i++) { - if (xhci->port_caps[i].maj_rev == 0x03 && - xhci->port_caps[i].min_rev >= 0x01) { - usb3_1 = true; + u8 major = xhci->port_caps[i].maj_rev; + u8 minor = xhci->port_caps[i].min_rev; + u16 rev = (major << 8) | minor; + + if (i == 0 || bcdUSB < rev) { + bcdUSB = rev; port_cap = &xhci->port_caps[i]; - break; } } - if (usb3_1) { - /* does xhci provide a PSI table for SSA speed attributes? */ + if (bcdUSB >= 0x0310) { if (port_cap->psi_count) { - /* two SSA entries for each unique PSI ID, RX and TX */ - ssa_count = port_cap->psi_uid_count * 2; - ssa_size = ssa_count * sizeof(u32); - ssp_cap_size -= 16; /* skip copying the default SSA */ + u8 num_sym_ssa = 0; + + for (i = 0; i < port_cap->psi_count; i++) { + if ((port_cap->psi[i] & PLT_MASK) == PLT_SYM) + num_sym_ssa++; + } + + ssac = port_cap->psi_count + num_sym_ssa - 1; + ssic = port_cap->psi_uid_count - 1; + } else { + if (bcdUSB >= 0x0320) + ssac = 7; + else + ssac = 3; + + ssic = (ssac + 1) / 2 - 1; } - desc_size += ssp_cap_size; - } - memcpy(buf, &usb_bos_descriptor, min(desc_size, wLength)); - if (usb3_1) { - /* modify bos descriptor bNumDeviceCaps and wTotalLength */ - buf[4] += 1; - put_unaligned_le16(desc_size + ssa_size, &buf[2]); + bos->bNumDeviceCaps++; + bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE + + USB_DT_USB_SS_CAP_SIZE + + USB_DT_USB_SSP_CAP_SIZE(ssac)); } if (wLength < USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE) return wLength; - /* Indicate whether the host has LTM support. */ - temp = readl(&xhci->cap_regs->hcc_params); - if (HCC_LTC(temp)) - buf[8] |= USB_LTM_SUPPORT; + /* SuperSpeed USB Device Capability */ + ss_cap = (struct usb_ss_cap_descriptor *)&buf[USB_DT_BOS_SIZE]; + ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; + ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; + ss_cap->bmAttributes = 0; /* set later */ + ss_cap->wSpeedSupported = cpu_to_le16(USB_5GBPS_OPERATION); + ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; + ss_cap->bU1devExitLat = 0; /* set later */ + ss_cap->bU2DevExitLat = 0; /* set later */ + + reg = readl(&xhci->cap_regs->hcc_params); + if (HCC_LTC(reg)) + ss_cap->bmAttributes |= USB_LTM_SUPPORT; - /* Set the U1 and U2 exit latencies. */ if ((xhci->quirks & XHCI_LPM_SUPPORT)) { - temp = readl(&xhci->cap_regs->hcs_params3); - buf[12] = HCS_U1_LATENCY(temp); - put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); + reg = readl(&xhci->cap_regs->hcs_params3); + ss_cap->bU1devExitLat = HCS_U1_LATENCY(reg); + ss_cap->bU2DevExitLat = cpu_to_le16(HCS_U2_LATENCY(reg)); } - /* If PSI table exists, add the custom speed attributes from it */ - if (usb3_1 && port_cap->psi_count) { - u32 ssp_cap_base, bm_attrib, psi, psi_mant, psi_exp; - int offset; + if (wLength < le16_to_cpu(bos->wTotalLength)) + return wLength; - ssp_cap_base = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; + if (bcdUSB < 0x0310) + return le16_to_cpu(bos->wTotalLength); + + ssp_cap = (struct usb_ssp_cap_descriptor *)&buf[USB_DT_BOS_SIZE + + USB_DT_USB_SS_CAP_SIZE]; + ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(ssac); + ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE; + ssp_cap->bReserved = 0; + ssp_cap->wReserved = 0; + ssp_cap->bmAttributes = + cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, ssac) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, ssic)); + + if (!port_cap->psi_count) { + for (i = 0; i < ssac + 1; i++) + ssp_cap->bmSublinkSpeedAttr[i] = + cpu_to_le32(ssp_cap_default_ssa[i]); + + min_ssid = 4; + goto out; + } - if (wLength < desc_size) - return wLength; - buf[ssp_cap_base] = ssp_cap_size + ssa_size; + offset = 0; + for (i = 0; i < port_cap->psi_count; i++) { + u32 psi; + u32 attr; + u8 ssid; + u8 lp; + u8 lse; + u8 psie; + u16 lane_mantissa; + u16 psim; + u16 plt; + + psi = port_cap->psi[i]; + ssid = XHCI_EXT_PORT_PSIV(psi); + lp = XHCI_EXT_PORT_LP(psi); + psie = XHCI_EXT_PORT_PSIE(psi); + psim = XHCI_EXT_PORT_PSIM(psi); + plt = psi & PLT_MASK; + + lse = psie; + lane_mantissa = psim; + + /* Shift to Gbps and set SSP Link Protocol if 10Gpbs */ + for (; psie < USB_SSP_SUBLINK_SPEED_LSE_GBPS; psie++) + psim /= 1000; + + if (!min_rate || psim < min_rate) { + min_ssid = ssid; + min_rate = psim; + } - /* attribute count SSAC bits 4:0 and ID count SSIC bits 8:5 */ - bm_attrib = (ssa_count - 1) & 0x1f; - bm_attrib |= (port_cap->psi_uid_count - 1) << 5; - put_unaligned_le32(bm_attrib, &buf[ssp_cap_base + 4]); + /* Some host controllers don't set the link protocol for SSP */ + if (psim >= 10) + lp = USB_SSP_SUBLINK_SPEED_LP_SSP; - if (wLength < desc_size + ssa_size) - return wLength; /* - * Create the Sublink Speed Attributes (SSA) array. - * The xhci PSI field and USB 3.1 SSA fields are very similar, - * but link type bits 7:6 differ for values 01b and 10b. - * xhci has also only one PSI entry for a symmetric link when - * USB 3.1 requires two SSA entries (RX and TX) for every link + * PSIM and PSIE represent the total speed of PSI. The BOS + * descriptor SSP sublink speed attribute lane mantissa + * describes the lane speed. E.g. PSIM and PSIE for gen2x2 + * is 20Gbps, but the BOS descriptor lane speed mantissa is + * 10Gbps. Check and modify the mantissa value to match the + * lane speed. */ - offset = desc_size; - for (i = 0; i < port_cap->psi_count; i++) { - psi = port_cap->psi[i]; - psi &= ~USB_SSP_SUBLINK_SPEED_RSVD; - psi_exp = XHCI_EXT_PORT_PSIE(psi); - psi_mant = XHCI_EXT_PORT_PSIM(psi); - - /* Shift to Gbps and set SSP Link BIT(14) if 10Gpbs */ - for (; psi_exp < 3; psi_exp++) - psi_mant /= 1000; - if (psi_mant >= 10) - psi |= BIT(14); - - if ((psi & PLT_MASK) == PLT_SYM) { - /* Symmetric, create SSA RX and TX from one PSI entry */ - put_unaligned_le32(psi, &buf[offset]); - psi |= 1 << 7; /* turn entry to TX */ - offset += 4; - if (offset >= desc_size + ssa_size) - return desc_size + ssa_size; - } else if ((psi & PLT_MASK) == PLT_ASYM_RX) { - /* Asymetric RX, flip bits 7:6 for SSA */ - psi ^= PLT_MASK; + if (bcdUSB == 0x0320 && plt == PLT_SYM) { + /* + * The PSI dword for gen1x2 and gen2x1 share the same + * values. But the lane speed for gen1x2 is 5Gbps while + * gen2x1 is 10Gbps. If the previous PSI dword SSID is + * 5 and the PSIE and PSIM match with SSID 6, let's + * assume that the controller follows the default speed + * id with SSID 6 for gen1x2. + */ + if (ssid == 6 && psie == 3 && psim == 10 && i) { + u32 prev = port_cap->psi[i - 1]; + + if ((prev & PLT_MASK) == PLT_SYM && + XHCI_EXT_PORT_PSIV(prev) == 5 && + XHCI_EXT_PORT_PSIE(prev) == 3 && + XHCI_EXT_PORT_PSIM(prev) == 10) { + lse = USB_SSP_SUBLINK_SPEED_LSE_GBPS; + lane_mantissa = 5; + } + } + + if (psie == 3 && psim > 10) { + lse = USB_SSP_SUBLINK_SPEED_LSE_GBPS; + lane_mantissa = 10; } - put_unaligned_le32(psi, &buf[offset]); - offset += 4; - if (offset >= desc_size + ssa_size) - return desc_size + ssa_size; + } + + attr = (FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, ssid) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP, lp) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE, lse) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, lane_mantissa)); + + switch (plt) { + case PLT_SYM: + attr |= FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, + USB_SSP_SUBLINK_SPEED_ST_SYM_RX); + ssp_cap->bmSublinkSpeedAttr[offset++] = cpu_to_le32(attr); + + attr &= ~USB_SSP_SUBLINK_SPEED_ST; + attr |= FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, + USB_SSP_SUBLINK_SPEED_ST_SYM_TX); + ssp_cap->bmSublinkSpeedAttr[offset++] = cpu_to_le32(attr); + break; + case PLT_ASYM_RX: + attr |= FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, + USB_SSP_SUBLINK_SPEED_ST_ASYM_RX); + ssp_cap->bmSublinkSpeedAttr[offset++] = cpu_to_le32(attr); + break; + case PLT_ASYM_TX: + attr |= FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, + USB_SSP_SUBLINK_SPEED_ST_ASYM_TX); + ssp_cap->bmSublinkSpeedAttr[offset++] = cpu_to_le32(attr); + break; } } - /* ssa_size is 0 for other than usb 3.1 hosts */ - return desc_size + ssa_size; +out: + ssp_cap->wFunctionalitySupport = + cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, + min_ssid) | + FIELD_PREP(USB_SSP_MIN_RX_LANE_COUNT, 1) | + FIELD_PREP(USB_SSP_MIN_TX_LANE_COUNT, 1)); + + return le16_to_cpu(bos->wTotalLength); } static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, @@ -1137,7 +1223,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if (hcd->speed < HCD_USB3) goto error; - retval = xhci_create_usb3_bos_desc(xhci, buf, wLength); + retval = xhci_create_usb3x_bos_desc(xhci, buf, wLength); spin_unlock_irqrestore(&xhci->lock, flags); return retval; case GetPortStatus: diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index f2c4ee7c4786eb4f8f782b3c00b2d5e3a6615de2..f66815fe84822c08bc8c77287a31aa5b7e1c4d8e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -532,7 +532,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, return (struct xhci_ep_ctx *) (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); } - +EXPORT_SYMBOL_GPL(xhci_get_ep_ctx); /***************** Streams structures manipulation *************************/ @@ -2129,6 +2129,15 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, if (major_revision == 0x03) { rhub = &xhci->usb3_rhub; + /* + * Some hosts incorrectly use sub-minor version for minor + * version (i.e. 0x02 instead of 0x20 for bcdUSB 0x320 and 0x01 + * for bcdUSB 0x310). Since there is no USB release with sub + * minor version 0x301 to 0x309, we can assume that they are + * incorrect and fix it here. + */ + if (minor_revision > 0x00 && minor_revision < 0x10) + minor_revision <<= 4; } else if (major_revision <= 0x02) { rhub = &xhci->usb2_rhub; } else { @@ -2240,6 +2249,9 @@ static void xhci_create_rhub_port_array(struct xhci_hcd *xhci, return; rhub->ports = kcalloc_node(rhub->num_ports, sizeof(*rhub->ports), flags, dev_to_node(dev)); + if (!rhub->ports) + return; + for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { if (xhci->hw_ports[i].rhub != rhub || xhci->hw_ports[i].hcd_portnum == DUPLICATE_ENTRY) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index b45e5bf0899798efbda164feab120da4c424fd30..8b90da5a6ed1958cde3d6fc521ed9cc32eb7f47d 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -25,6 +25,15 @@ */ #define TT_MICROFRAMES_MAX 9 +#define DBG_BUF_EN 64 + +/* schedule error type */ +#define ESCH_SS_Y6 1001 +#define ESCH_SS_OVERLAP 1002 +#define ESCH_CS_OVERFLOW 1003 +#define ESCH_BW_OVERFLOW 1004 +#define ESCH_FIXME 1005 + /* mtk scheduler bitmasks */ #define EP_BPKTS(p) ((p) & 0x7f) #define EP_BCSCOUNT(p) (((p) & 0x7) << 8) @@ -32,13 +41,75 @@ #define EP_BOFFSET(p) ((p) & 0x3fff) #define EP_BREPEAT(p) (((p) & 0x7fff) << 16) +static char *sch_error_string(int err_num) +{ + switch (err_num) { + case ESCH_SS_Y6: + return "Can't schedule Start-Split in Y6"; + case ESCH_SS_OVERLAP: + return "Can't find a suitable Start-Split location"; + case ESCH_CS_OVERFLOW: + return "The last Complete-Split is greater than 7"; + case ESCH_BW_OVERFLOW: + return "Bandwidth exceeds the maximum limit"; + case ESCH_FIXME: + return "FIXME, to be resolved"; + default: + return "Unknown"; + } +} + static int is_fs_or_ls(enum usb_device_speed speed) { return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW; } +static const char * +decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed) +{ + static char buf[DBG_BUF_EN]; + struct usb_endpoint_descriptor *epd = &ep->desc; + unsigned int interval; + const char *unit; + + interval = usb_decode_interval(epd, speed); + if (interval % 1000) { + unit = "us"; + } else { + unit = "ms"; + interval /= 1000; + } + + snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s\n", + usb_speed_string(speed), usb_endpoint_num(epd), + usb_endpoint_dir_in(epd) ? "in" : "out", + usb_ep_type_string(usb_endpoint_type(epd)), + usb_endpoint_maxp(epd), epd->bInterval, interval, unit); + + return buf; +} + +static u32 get_bw_boundary(enum usb_device_speed speed) +{ + u32 boundary; + + switch (speed) { + case USB_SPEED_SUPER_PLUS: + boundary = SSP_BW_BOUNDARY; + break; + case USB_SPEED_SUPER: + boundary = SS_BW_BOUNDARY; + break; + default: + boundary = HS_BW_BOUNDARY; + break; + } + + return boundary; +} + /* -* get the index of bandwidth domains array which @ep belongs to. +* get the bandwidth domain which @ep belongs to. * * the bandwidth domain array is saved to @sch_array of struct xhci_hcd_mtk, * each HS root port is treated as a single bandwidth domain, @@ -49,9 +120,11 @@ static int is_fs_or_ls(enum usb_device_speed speed) * so the bandwidth domain array is organized as follow for simplification: * SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY */ -static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, - struct usb_host_endpoint *ep) +static struct mu3h_sch_bw_info * +get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev, + struct usb_host_endpoint *ep) { + struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); struct xhci_virt_device *virt_dev; int bw_index; @@ -67,7 +140,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1; } - return bw_index; + return &mtk->sch_array[bw_index]; } static u32 get_esit(struct xhci_ep_ctx *ep_ctx) @@ -85,7 +158,6 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev) { struct usb_tt *utt = udev->tt; struct mu3h_sch_tt *tt, **tt_index, **ptt; - unsigned int port; bool allocated_index = false; if (!utt) @@ -107,10 +179,8 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev) utt->hcpriv = tt_index; allocated_index = true; } - port = udev->ttport - 1; - ptt = &tt_index[port]; + ptt = &tt_index[udev->ttport - 1]; } else { - port = 0; ptt = (struct mu3h_sch_tt **) &utt->hcpriv; } @@ -125,8 +195,6 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev) return ERR_PTR(-ENOMEM); } INIT_LIST_HEAD(&tt->ep_list); - tt->usb_tt = utt; - tt->tt_port = port; *ptt = tt; } @@ -200,14 +268,15 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, sch_ep->sch_tt = tt; sch_ep->ep = ep; + sch_ep->speed = udev->speed; INIT_LIST_HEAD(&sch_ep->endpoint); INIT_LIST_HEAD(&sch_ep->tt_endpoint); return sch_ep; } -static void setup_sch_info(struct usb_device *udev, - struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep) +static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, + struct mu3h_sch_ep_info *sch_ep) { u32 ep_type; u32 maxpkt; @@ -234,7 +303,7 @@ static void setup_sch_info(struct usb_device *udev, sch_ep->burst_mode = 0; sch_ep->repeat = 0; - if (udev->speed == USB_SPEED_HIGH) { + if (sch_ep->speed == USB_SPEED_HIGH) { sch_ep->cs_count = 0; /* @@ -252,7 +321,7 @@ static void setup_sch_info(struct usb_device *udev, sch_ep->pkts = max_burst + 1; sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; bwb_table[0] = sch_ep->bw_cost_per_microframe; - } else if (udev->speed >= USB_SPEED_SUPER) { + } else if (sch_ep->speed >= USB_SPEED_SUPER) { /* usb3_r1 spec section4.4.7 & 4.4.8 */ sch_ep->cs_count = 0; sch_ep->burst_mode = 1; @@ -272,7 +341,6 @@ static void setup_sch_info(struct usb_device *udev, } if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { - u32 remainder; if (sch_ep->esit == 1) sch_ep->pkts = esit_pkts; @@ -288,16 +356,14 @@ static void setup_sch_info(struct usb_device *udev, sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1); sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; - remainder = sch_ep->bw_cost_per_microframe; - remainder *= sch_ep->num_budget_microframes; - remainder -= (maxpkt * esit_pkts); for (i = 0; i < sch_ep->num_budget_microframes - 1; i++) bwb_table[i] = sch_ep->bw_cost_per_microframe; /* last one <= bw_cost_per_microframe */ - bwb_table[i] = remainder; + bwb_table[i] = maxpkt * esit_pkts + - i * sch_ep->bw_cost_per_microframe; } - } else if (is_fs_or_ls(udev->speed)) { + } else if (is_fs_or_ls(sch_ep->speed)) { sch_ep->pkts = 1; /* at most one packet for each microframe */ /* @@ -375,21 +441,42 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, sch_ep->bw_budget_table[j]; } } - sch_ep->allocated = used; } -static int check_sch_tt(struct usb_device *udev, - struct mu3h_sch_ep_info *sch_ep, u32 offset) +static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) +{ + struct mu3h_sch_tt *tt = sch_ep->sch_tt; + u32 num_esit, tmp; + int base; + int i, j; + + num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; + for (i = 0; i < num_esit; i++) { + base = offset + i * sch_ep->esit; + + /* + * Compared with hs bus, no matter what ep type, + * the hub will always delay one uframe to send data + */ + for (j = 0; j < sch_ep->cs_count; j++) { + tmp = tt->fs_bus_bw[base + j] + sch_ep->bw_cost_per_microframe; + if (tmp > FS_PAYLOAD_MAX) + return -ESCH_BW_OVERFLOW; + } + } + + return 0; +} + +static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) { struct mu3h_sch_tt *tt = sch_ep->sch_tt; u32 extra_cs_count; - u32 fs_budget_start; u32 start_ss, last_ss; u32 start_cs, last_cs; int i; start_ss = offset % 8; - fs_budget_start = (start_ss + 1) % 8; if (sch_ep->ep_type == ISOC_OUT_EP) { last_ss = start_ss + sch_ep->cs_count - 1; @@ -399,11 +486,11 @@ static int check_sch_tt(struct usb_device *udev, * must never schedule Start-Split in Y6 */ if (!(start_ss == 7 || last_ss < 6)) - return -ERANGE; + return -ESCH_SS_Y6; for (i = 0; i < sch_ep->cs_count; i++) - if (test_bit(offset + i, tt->split_bit_map)) - return -ERANGE; + if (test_bit(offset + i, tt->ss_bit_map)) + return -ESCH_SS_OVERLAP; } else { u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); @@ -413,28 +500,26 @@ static int check_sch_tt(struct usb_device *udev, * must never schedule Start-Split in Y6 */ if (start_ss == 6) - return -ERANGE; + return -ESCH_SS_Y6; /* one uframe for ss + one uframe for idle */ start_cs = (start_ss + 2) % 8; last_cs = start_cs + cs_count - 1; if (last_cs > 7) - return -ERANGE; + return -ESCH_CS_OVERFLOW; if (sch_ep->ep_type == ISOC_IN_EP) extra_cs_count = (last_cs == 7) ? 1 : 2; else /* ep_type : INTR IN / INTR OUT */ - extra_cs_count = (fs_budget_start == 6) ? 1 : 2; + extra_cs_count = 1; cs_count += extra_cs_count; if (cs_count > 7) cs_count = 7; /* HW limit */ - for (i = 0; i < cs_count + 2; i++) { - if (test_bit(offset + i, tt->split_bit_map)) - return -ERANGE; - } + if (test_bit(offset, tt->ss_bit_map)) + return -ESCH_SS_OVERLAP; sch_ep->cs_count = cs_count; /* one for ss, the other for idle */ @@ -448,41 +533,85 @@ static int check_sch_tt(struct usb_device *udev, sch_ep->num_budget_microframes = sch_ep->esit; } - return 0; + return check_fs_bus_bw(sch_ep, offset); } -static void update_sch_tt(struct usb_device *udev, - struct mu3h_sch_ep_info *sch_ep) +static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) { struct mu3h_sch_tt *tt = sch_ep->sch_tt; u32 base, num_esit; + int bw_updated; + int bits; int i, j; num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; + bits = (sch_ep->ep_type == ISOC_OUT_EP) ? sch_ep->cs_count : 1; + + if (used) + bw_updated = sch_ep->bw_cost_per_microframe; + else + bw_updated = -sch_ep->bw_cost_per_microframe; + for (i = 0; i < num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; - for (j = 0; j < sch_ep->num_budget_microframes; j++) - set_bit(base + j, tt->split_bit_map); + + for (j = 0; j < bits; j++) { + if (used) + set_bit(base + j, tt->ss_bit_map); + else + clear_bit(base + j, tt->ss_bit_map); + } + + for (j = 0; j < sch_ep->cs_count; j++) + tt->fs_bus_bw[base + j] += bw_updated; } - list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list); + if (used) + list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list); + else + list_del(&sch_ep->tt_endpoint); } -static int check_sch_bw(struct usb_device *udev, - struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) +static int load_ep_bw(struct mu3h_sch_bw_info *sch_bw, + struct mu3h_sch_ep_info *sch_ep, bool loaded) +{ + if (sch_ep->sch_tt) + update_sch_tt(sch_ep, loaded); + + /* update bus bandwidth info */ + update_bus_bw(sch_bw, sch_ep, loaded); + sch_ep->allocated = loaded; + + return 0; +} + +static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep) +{ + u32 boundary = sch_ep->esit; + + if (sch_ep->sch_tt) { /* LS/FS with TT */ + /* tune for CS */ + if (sch_ep->ep_type != ISOC_OUT_EP) + boundary++; + else if (boundary > 1) /* normally esit >= 8 for FS/LS */ + boundary--; + } + + return boundary; +} + +static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw, + struct mu3h_sch_ep_info *sch_ep) { u32 offset; - u32 esit; u32 min_bw; u32 min_index; u32 worst_bw; u32 bw_boundary; + u32 esit_boundary; u32 min_num_budget; u32 min_cs_count; - bool tt_offset_ok = false; - int ret; - - esit = sch_ep->esit; + int ret = 0; /* * Search through all possible schedule microframes. @@ -492,16 +621,15 @@ static int check_sch_bw(struct usb_device *udev, min_index = 0; min_cs_count = sch_ep->cs_count; min_num_budget = sch_ep->num_budget_microframes; - for (offset = 0; offset < esit; offset++) { - if (is_fs_or_ls(udev->speed)) { - ret = check_sch_tt(udev, sch_ep, offset); + esit_boundary = get_esit_boundary(sch_ep); + for (offset = 0; offset < sch_ep->esit; offset++) { + if (sch_ep->sch_tt) { + ret = check_sch_tt(sch_ep, offset); if (ret) continue; - else - tt_offset_ok = true; } - if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit) + if ((offset + sch_ep->num_budget_microframes) > esit_boundary) break; worst_bw = get_max_bw(sch_bw, sch_ep, offset); @@ -515,33 +643,16 @@ static int check_sch_bw(struct usb_device *udev, break; } - if (udev->speed == USB_SPEED_SUPER_PLUS) - bw_boundary = SSP_BW_BOUNDARY; - else if (udev->speed == USB_SPEED_SUPER) - bw_boundary = SS_BW_BOUNDARY; - else - bw_boundary = HS_BW_BOUNDARY; - + bw_boundary = get_bw_boundary(sch_ep->speed); /* check bandwidth */ if (min_bw > bw_boundary) - return -ERANGE; + return ret ? ret : -ESCH_BW_OVERFLOW; sch_ep->offset = min_index; sch_ep->cs_count = min_cs_count; sch_ep->num_budget_microframes = min_num_budget; - if (is_fs_or_ls(udev->speed)) { - /* all offset for tt is not ok*/ - if (!tt_offset_ok) - return -ERANGE; - - update_sch_tt(udev, sch_ep); - } - - /* update bus bandwidth info */ - update_bus_bw(sch_bw, sch_ep, 1); - - return 0; + return load_ep_bw(sch_bw, sch_ep, true); } static void destroy_sch_ep(struct usb_device *udev, @@ -549,14 +660,12 @@ static void destroy_sch_ep(struct usb_device *udev, { /* only release ep bw check passed by check_sch_bw() */ if (sch_ep->allocated) - update_bus_bw(sch_bw, sch_ep, 0); + load_ep_bw(sch_bw, sch_ep, false); - list_del(&sch_ep->endpoint); - - if (sch_ep->sch_tt) { - list_del(&sch_ep->tt_endpoint); + if (sch_ep->sch_tt) drop_tt(udev); - } + + list_del(&sch_ep->endpoint); kfree(sch_ep); } @@ -606,44 +715,36 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) return 0; } -EXPORT_SYMBOL_GPL(xhci_mtk_sch_init); void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk) { kfree(mtk->sch_array); } -EXPORT_SYMBOL_GPL(xhci_mtk_sch_exit); -int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep) +static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) { struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); - struct xhci_hcd *xhci; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_ep_ctx *ep_ctx; - struct xhci_slot_ctx *slot_ctx; struct xhci_virt_device *virt_dev; struct mu3h_sch_ep_info *sch_ep; unsigned int ep_index; - xhci = hcd_to_xhci(hcd); virt_dev = xhci->devs[udev->slot_id]; ep_index = xhci_get_endpoint_index(&ep->desc); - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); - xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n", - __func__, usb_endpoint_type(&ep->desc), udev->speed, - usb_endpoint_maxp(&ep->desc), - usb_endpoint_dir_in(&ep->desc), ep); + xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); - if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) { + if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) { /* * set @bpkts to 1 if it is LS or FS periodic endpoint, and its * device does not connected through an external HS hub */ if (usb_endpoint_xfer_int(&ep->desc) || usb_endpoint_xfer_isoc(&ep->desc)) - ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(1)); + ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(1)); return 0; } @@ -652,41 +753,30 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, if (IS_ERR_OR_NULL(sch_ep)) return -ENOMEM; - setup_sch_info(udev, ep_ctx, sch_ep); + setup_sch_info(ep_ctx, sch_ep); list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list); return 0; } -EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk); -void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep) +static void drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) { struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); - struct xhci_hcd *xhci; - struct xhci_slot_ctx *slot_ctx; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_virt_device *virt_dev; - struct mu3h_sch_bw_info *sch_array; struct mu3h_sch_bw_info *sch_bw; struct mu3h_sch_ep_info *sch_ep, *tmp; - int bw_index; - xhci = hcd_to_xhci(hcd); virt_dev = xhci->devs[udev->slot_id]; - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); - sch_array = mtk->sch_array; - xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n", - __func__, usb_endpoint_type(&ep->desc), udev->speed, - usb_endpoint_maxp(&ep->desc), - usb_endpoint_dir_in(&ep->desc), ep); + xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); - if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) + if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) return; - bw_index = get_bw_index(xhci, udev, ep); - sch_bw = &sch_array[bw_index]; + sch_bw = get_bw_info(mtk, udev, ep); list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) { if (sch_ep->ep == ep) { @@ -695,7 +785,6 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, } } } -EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk); int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) { @@ -704,17 +793,17 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; struct mu3h_sch_bw_info *sch_bw; struct mu3h_sch_ep_info *sch_ep, *tmp; - int bw_index, ret; + int ret; xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) { - bw_index = get_bw_index(xhci, udev, sch_ep->ep); - sch_bw = &mtk->sch_array[bw_index]; + sch_bw = get_bw_info(mtk, udev, sch_ep->ep); - ret = check_sch_bw(udev, sch_bw, sch_ep); + ret = check_sch_bw(sch_bw, sch_ep); if (ret) { - xhci_err(xhci, "Not enough bandwidth!\n"); + xhci_err(xhci, "Not enough bandwidth! (%s)\n", + sch_error_string(-ret)); return -ENOSPC; } } @@ -724,16 +813,14 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) struct usb_host_endpoint *ep = sch_ep->ep; unsigned int ep_index = xhci_get_endpoint_index(&ep->desc); - bw_index = get_bw_index(xhci, udev, ep); - sch_bw = &mtk->sch_array[bw_index]; - + sch_bw = get_bw_info(mtk, udev, ep); list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); - ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) + ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(sch_ep->pkts) | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode)); - ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset) + ep_ctx->reserved[1] = cpu_to_le32(EP_BOFFSET(sch_ep->offset) | EP_BREPEAT(sch_ep->repeat)); xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n", @@ -743,7 +830,6 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) return xhci_check_bandwidth(hcd, udev); } -EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwidth); void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) { @@ -751,16 +837,43 @@ void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct mu3h_sch_bw_info *sch_bw; struct mu3h_sch_ep_info *sch_ep, *tmp; - int bw_index; xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { - bw_index = get_bw_index(xhci, udev, sch_ep->ep); - sch_bw = &mtk->sch_array[bw_index]; + sch_bw = get_bw_info(mtk, udev, sch_ep->ep); destroy_sch_ep(udev, sch_bw, sch_ep); } xhci_reset_bandwidth(hcd, udev); } -EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth); + +int xhci_mtk_add_ep(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + int ret; + + ret = xhci_add_endpoint(hcd, udev, ep); + if (ret) + return ret; + + if (ep->hcpriv) + ret = add_ep_quirk(hcd, udev, ep); + + return ret; +} + +int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + int ret; + + ret = xhci_drop_endpoint(hcd, udev, ep); + if (ret) + return ret; + + if (ep->hcpriv) + drop_ep_quirk(hcd, udev, ep); + + return 0; +} diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 2f27dc0d9c6bd30611d1b81b499f8358b5760134..b2058b3bc834ceffcb2eb030b26fd3f165b17eb1 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -7,7 +7,6 @@ * Chunfeng Yun <chunfeng.yun@mediatek.com> */ -#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/iopoll.h> #include <linux/kernel.h> @@ -16,6 +15,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/pm_wakeirq.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -57,12 +57,23 @@ #define CTRL_U2_FORCE_PLL_STB BIT(28) /* usb remote wakeup registers in syscon */ + /* mt8173 etc */ #define PERI_WK_CTRL1 0x4 #define WC1_IS_C(x) (((x) & 0xf) << 26) /* cycle debounce */ #define WC1_IS_EN BIT(25) #define WC1_IS_P BIT(6) /* polarity for ip sleep */ +/* mt8183 */ +#define PERI_WK_CTRL0 0x0 +#define WC0_IS_C(x) ((u32)(((x) & 0xf) << 28)) /* cycle debounce */ +#define WC0_IS_P BIT(12) /* polarity */ +#define WC0_IS_EN BIT(6) + +/* mt8192 */ +#define WC0_SSUSB0_CDEN BIT(6) +#define WC0_IS_SPM_EN BIT(1) + /* mt2712 etc */ #define PERI_SSUSB_SPM_CTRL 0x0 #define SSC_IP_SLEEP_EN BIT(4) @@ -71,6 +82,8 @@ enum ssusb_uwk_vers { SSUSB_UWK_V1 = 1, SSUSB_UWK_V2, + SSUSB_UWK_V1_1 = 101, /* specific revision 1.01 */ + SSUSB_UWK_V1_2, /* specific revision 1.2 */ }; static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) @@ -206,89 +219,6 @@ static int xhci_mtk_ssusb_config(struct xhci_hcd_mtk *mtk) return xhci_mtk_host_enable(mtk); } -static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) -{ - struct device *dev = mtk->dev; - - mtk->sys_clk = devm_clk_get(dev, "sys_ck"); - if (IS_ERR(mtk->sys_clk)) { - dev_err(dev, "fail to get sys_ck\n"); - return PTR_ERR(mtk->sys_clk); - } - - mtk->xhci_clk = devm_clk_get_optional(dev, "xhci_ck"); - if (IS_ERR(mtk->xhci_clk)) - return PTR_ERR(mtk->xhci_clk); - - mtk->ref_clk = devm_clk_get_optional(dev, "ref_ck"); - if (IS_ERR(mtk->ref_clk)) - return PTR_ERR(mtk->ref_clk); - - mtk->mcu_clk = devm_clk_get_optional(dev, "mcu_ck"); - if (IS_ERR(mtk->mcu_clk)) - return PTR_ERR(mtk->mcu_clk); - - mtk->dma_clk = devm_clk_get_optional(dev, "dma_ck"); - return PTR_ERR_OR_ZERO(mtk->dma_clk); -} - -static int xhci_mtk_clks_enable(struct xhci_hcd_mtk *mtk) -{ - int ret; - - ret = clk_prepare_enable(mtk->ref_clk); - if (ret) { - dev_err(mtk->dev, "failed to enable ref_clk\n"); - goto ref_clk_err; - } - - ret = clk_prepare_enable(mtk->sys_clk); - if (ret) { - dev_err(mtk->dev, "failed to enable sys_clk\n"); - goto sys_clk_err; - } - - ret = clk_prepare_enable(mtk->xhci_clk); - if (ret) { - dev_err(mtk->dev, "failed to enable xhci_clk\n"); - goto xhci_clk_err; - } - - ret = clk_prepare_enable(mtk->mcu_clk); - if (ret) { - dev_err(mtk->dev, "failed to enable mcu_clk\n"); - goto mcu_clk_err; - } - - ret = clk_prepare_enable(mtk->dma_clk); - if (ret) { - dev_err(mtk->dev, "failed to enable dma_clk\n"); - goto dma_clk_err; - } - - return 0; - -dma_clk_err: - clk_disable_unprepare(mtk->mcu_clk); -mcu_clk_err: - clk_disable_unprepare(mtk->xhci_clk); -xhci_clk_err: - clk_disable_unprepare(mtk->sys_clk); -sys_clk_err: - clk_disable_unprepare(mtk->ref_clk); -ref_clk_err: - return ret; -} - -static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk) -{ - clk_disable_unprepare(mtk->dma_clk); - clk_disable_unprepare(mtk->mcu_clk); - clk_disable_unprepare(mtk->xhci_clk); - clk_disable_unprepare(mtk->sys_clk); - clk_disable_unprepare(mtk->ref_clk); -} - /* only clocks can be turn off for ip-sleep wakeup mode */ static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable) { @@ -300,6 +230,16 @@ static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable) msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P; val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0; break; + case SSUSB_UWK_V1_1: + reg = mtk->uwk_reg_base + PERI_WK_CTRL0; + msk = WC0_IS_EN | WC0_IS_C(0xf) | WC0_IS_P; + val = enable ? (WC0_IS_EN | WC0_IS_C(0x8)) : 0; + break; + case SSUSB_UWK_V1_2: + reg = mtk->uwk_reg_base + PERI_WK_CTRL0; + msk = WC0_SSUSB0_CDEN | WC0_IS_SPM_EN; + val = enable ? msk : 0; + break; case SSUSB_UWK_V2: reg = mtk->uwk_reg_base + PERI_SSUSB_SPM_CTRL; msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN; @@ -335,7 +275,6 @@ static int usb_wakeup_of_property_parse(struct xhci_hcd_mtk *mtk, mtk->uwk_reg_base, mtk->uwk_vers); return PTR_ERR_OR_ZERO(mtk->uwk); - } static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable) @@ -344,14 +283,18 @@ static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable) usb_wakeup_ip_sleep_set(mtk, enable); } -static int xhci_mtk_setup(struct usb_hcd *hcd); -static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = { - .reset = xhci_mtk_setup, - .check_bandwidth = xhci_mtk_check_bandwidth, - .reset_bandwidth = xhci_mtk_reset_bandwidth, -}; +static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) +{ + struct clk_bulk_data *clks = mtk->clks; -static struct hc_driver __read_mostly xhci_mtk_hc_driver; + clks[0].id = "sys_ck"; + clks[1].id = "xhci_ck"; + clks[2].id = "ref_ck"; + clks[3].id = "mcu_ck"; + clks[4].id = "dma_ck"; + + return devm_clk_bulk_get_optional(mtk->dev, BULK_CLKS_NUM, clks); +} static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk) { @@ -397,6 +340,8 @@ static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SPURIOUS_SUCCESS; if (mtk->lpm_support) xhci->quirks |= XHCI_LPM_SUPPORT; + if (mtk->u2_lpm_disable) + xhci->quirks |= XHCI_HW_LPM_DISABLE; /* * MTK xHCI 0.96: PSA is 1 by default even if doesn't support stream, @@ -431,6 +376,16 @@ static int xhci_mtk_setup(struct usb_hcd *hcd) return ret; } +static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = { + .reset = xhci_mtk_setup, + .add_endpoint = xhci_mtk_add_ep, + .drop_endpoint = xhci_mtk_drop_ep, + .check_bandwidth = xhci_mtk_check_bandwidth, + .reset_bandwidth = xhci_mtk_reset_bandwidth, +}; + +static struct hc_driver __read_mostly xhci_mtk_hc_driver; + static int xhci_mtk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -441,6 +396,7 @@ static int xhci_mtk_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; int ret = -ENODEV; + int wakeup_irq; int irq; if (usb_disabled()) @@ -468,7 +424,23 @@ static int xhci_mtk_probe(struct platform_device *pdev) if (ret) return ret; + irq = platform_get_irq_byname_optional(pdev, "host"); + if (irq < 0) { + if (irq == -EPROBE_DEFER) + return irq; + + /* for backward compatibility */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + } + + wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup"); + if (wakeup_irq == -EPROBE_DEFER) + return wakeup_irq; + mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable"); + mtk->u2_lpm_disable = of_property_read_bool(node, "usb2-lpm-disable"); /* optional property, ignore the error if it does not exist */ of_property_read_u32(node, "mediatek,u3p-dis-msk", &mtk->u3p_dis_msk); @@ -479,24 +451,20 @@ static int xhci_mtk_probe(struct platform_device *pdev) return ret; } + pm_runtime_set_active(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, 4000); pm_runtime_enable(dev); pm_runtime_get_sync(dev); - device_enable_async_suspend(dev); ret = xhci_mtk_ldos_enable(mtk); if (ret) goto disable_pm; - ret = xhci_mtk_clks_enable(mtk); + ret = clk_bulk_prepare_enable(BULK_CLKS_NUM, mtk->clks); if (ret) goto disable_ldos; - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto disable_clk; - } - hcd = usb_create_hcd(driver, dev, dev_name(dev)); if (!hcd) { ret = -ENOMEM; @@ -563,8 +531,26 @@ static int xhci_mtk_probe(struct platform_device *pdev) if (ret) goto dealloc_usb2_hcd; + if (wakeup_irq > 0) { + ret = dev_pm_set_dedicated_wake_irq(dev, wakeup_irq); + if (ret) { + dev_err(dev, "set wakeup irq %d failed\n", wakeup_irq); + goto dealloc_usb3_hcd; + } + dev_info(dev, "wakeup irq %d\n", wakeup_irq); + } + + device_enable_async_suspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + pm_runtime_forbid(dev); + return 0; +dealloc_usb3_hcd: + usb_remove_hcd(xhci->shared_hcd); + xhci->shared_hcd = NULL; + dealloc_usb2_hcd: usb_remove_hcd(hcd); @@ -579,53 +565,52 @@ put_usb2_hcd: usb_put_hcd(hcd); disable_clk: - xhci_mtk_clks_disable(mtk); + clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks); disable_ldos: xhci_mtk_ldos_disable(mtk); disable_pm: - pm_runtime_put_sync(dev); + pm_runtime_put_sync_autosuspend(dev); pm_runtime_disable(dev); return ret; } -static int xhci_mtk_remove(struct platform_device *dev) +static int xhci_mtk_remove(struct platform_device *pdev) { - struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev); + struct xhci_hcd_mtk *mtk = platform_get_drvdata(pdev); struct usb_hcd *hcd = mtk->hcd; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct usb_hcd *shared_hcd = xhci->shared_hcd; + struct device *dev = &pdev->dev; - pm_runtime_put_noidle(&dev->dev); - pm_runtime_disable(&dev->dev); + pm_runtime_get_sync(dev); + xhci->xhc_state |= XHCI_STATE_REMOVING; + dev_pm_clear_wake_irq(dev); + device_init_wakeup(dev, false); usb_remove_hcd(shared_hcd); xhci->shared_hcd = NULL; - device_init_wakeup(&dev->dev, false); - usb_remove_hcd(hcd); usb_put_hcd(shared_hcd); usb_put_hcd(hcd); xhci_mtk_sch_exit(mtk); - xhci_mtk_clks_disable(mtk); + clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks); xhci_mtk_ldos_disable(mtk); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); + return 0; } -/* - * if ip sleep fails, and all clocks are disabled, access register will hang - * AHB bus, so stop polling roothubs to avoid regs access on bus suspend. - * and no need to check whether ip sleep failed or not; this will cause SPM - * to wake up system immediately after system suspend complete if ip sleep - * fails, it is what we wanted. - */ static int __maybe_unused xhci_mtk_suspend(struct device *dev) { struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev); struct usb_hcd *hcd = mtk->hcd; struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; xhci_dbg(xhci, "%s: stop port polling\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); @@ -633,10 +618,21 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev) clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); del_timer_sync(&xhci->shared_hcd->rh_timer); - xhci_mtk_host_disable(mtk); - xhci_mtk_clks_disable(mtk); + ret = xhci_mtk_host_disable(mtk); + if (ret) + goto restart_poll_rh; + + clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks); usb_wakeup_set(mtk, true); return 0; + +restart_poll_rh: + xhci_dbg(xhci, "%s: restart port polling\n", __func__); + set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + usb_hcd_poll_rh_status(xhci->shared_hcd); + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); + usb_hcd_poll_rh_status(hcd); + return ret; } static int __maybe_unused xhci_mtk_resume(struct device *dev) @@ -644,10 +640,16 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev) struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev); struct usb_hcd *hcd = mtk->hcd; struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; usb_wakeup_set(mtk, false); - xhci_mtk_clks_enable(mtk); - xhci_mtk_host_enable(mtk); + ret = clk_bulk_prepare_enable(BULK_CLKS_NUM, mtk->clks); + if (ret) + goto enable_wakeup; + + ret = xhci_mtk_host_enable(mtk); + if (ret) + goto disable_clks; xhci_dbg(xhci, "%s: restart port polling\n", __func__); set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); @@ -655,21 +657,59 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev) set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); return 0; + +disable_clks: + clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks); +enable_wakeup: + usb_wakeup_set(mtk, true); + return ret; +} + +static int __maybe_unused xhci_mtk_runtime_suspend(struct device *dev) +{ + struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); + int ret = 0; + + if (xhci->xhc_state) + return -ESHUTDOWN; + + if (device_may_wakeup(dev)) + ret = xhci_mtk_suspend(dev); + + /* -EBUSY: let PM automatically reschedule another autosuspend */ + return ret ? -EBUSY : 0; +} + +static int __maybe_unused xhci_mtk_runtime_resume(struct device *dev) +{ + struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); + int ret = 0; + + if (xhci->xhc_state) + return -ESHUTDOWN; + + if (device_may_wakeup(dev)) + ret = xhci_mtk_resume(dev); + + return ret; } static const struct dev_pm_ops xhci_mtk_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(xhci_mtk_suspend, xhci_mtk_resume) + SET_RUNTIME_PM_OPS(xhci_mtk_runtime_suspend, + xhci_mtk_runtime_resume, NULL) }; -#define DEV_PM_OPS IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL -#ifdef CONFIG_OF +#define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL) + static const struct of_device_id mtk_xhci_of_match[] = { { .compatible = "mediatek,mt8173-xhci"}, { .compatible = "mediatek,mtk-xhci"}, { }, }; MODULE_DEVICE_TABLE(of, mtk_xhci_of_match); -#endif static struct platform_driver mtk_xhci_driver = { .probe = xhci_mtk_probe, @@ -677,10 +717,9 @@ static struct platform_driver mtk_xhci_driver = { .driver = { .name = "xhci-mtk", .pm = DEV_PM_OPS, - .of_match_table = of_match_ptr(mtk_xhci_of_match), + .of_match_table = mtk_xhci_of_match, }, }; -MODULE_ALIAS("platform:xhci-mtk"); static int __init xhci_mtk_init(void) { diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index cbb09dfea62e0f8be63a5ac4eac18c972c85ed7a..cd3a37bb73e631bb14bc1488a0d76a687ed5e4fd 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -9,8 +9,12 @@ #ifndef _XHCI_MTK_H_ #define _XHCI_MTK_H_ +#include <linux/clk.h> + #include "xhci.h" +#define BULK_CLKS_NUM 5 + /** * To simplify scheduler algorithm, set a upper limit for ESIT, * if a synchromous ep's ESIT is larger than @XHCI_MTK_MAX_ESIT, @@ -20,16 +24,14 @@ #define XHCI_MTK_MAX_ESIT 64 /** - * @split_bit_map: used to avoid split microframes overlay + * @ss_bit_map: used to avoid start split microframes overlay + * @fs_bus_bw: array to keep track of bandwidth already used for FS * @ep_list: Endpoints using this TT - * @usb_tt: usb TT related - * @tt_port: TT port number */ struct mu3h_sch_tt { - DECLARE_BITMAP(split_bit_map, XHCI_MTK_MAX_ESIT); + DECLARE_BITMAP(ss_bit_map, XHCI_MTK_MAX_ESIT); + u32 fs_bus_bw[XHCI_MTK_MAX_ESIT]; struct list_head ep_list; - struct usb_tt *usb_tt; - int tt_port; }; /** @@ -86,7 +88,8 @@ struct mu3h_sch_ep_info { struct mu3h_sch_tt *sch_tt; u32 ep_type; u32 maxpkt; - void *ep; + struct usb_host_endpoint *ep; + enum usb_device_speed speed; bool allocated; /* * mtk xHCI scheduling information put into reserved DWs @@ -141,15 +144,9 @@ struct xhci_hcd_mtk { int u3p_dis_msk; struct regulator *vusb33; struct regulator *vbus; - struct clk *sys_clk; /* sys and mac clock */ - struct clk *xhci_clk; - struct clk *ref_clk; - struct clk *mcu_clk; - struct clk *dma_clk; - struct regmap *pericfg; - struct phy **phys; - int num_phys; + struct clk_bulk_data clks[BULK_CLKS_NUM]; bool lpm_support; + bool u2_lpm_disable; /* usb remote wakeup */ bool uwk_en; struct regmap *uwk; @@ -162,38 +159,13 @@ static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd) return dev_get_drvdata(hcd->self.controller); } -#if IS_ENABLED(CONFIG_USB_XHCI_MTK) int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk); void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk); -int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep); -void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep); +int xhci_mtk_add_ep(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); +int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); -#else -static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, - struct usb_device *udev, struct usb_host_endpoint *ep) -{ - return 0; -} - -static inline void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, - struct usb_device *udev, struct usb_host_endpoint *ep) -{ -} - -static inline int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, - struct usb_device *udev) -{ - return 0; -} - -static inline void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, - struct usb_device *udev) -{ -} -#endif - #endif /* _XHCI_MTK_H_ */ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ce38076901e25036a9b480b81e65fe0ec7466b62..05c38dd3ee361a6e1fc5e002e8e1a3d2a68c8cae 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -57,7 +57,6 @@ #include <linux/dma-mapping.h> #include "xhci.h" #include "xhci-trace.h" -#include "xhci-mtk.h" static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 field1, u32 field2, @@ -2129,16 +2128,13 @@ 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_td *td, - struct xhci_transfer_event *event, struct xhci_virt_ep *ep) +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) { struct xhci_ep_ctx *ep_ctx; - struct xhci_ring *ep_ring; - u32 trb_comp_code; - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); switch (trb_comp_code) { case COMP_STOPPED_LENGTH_INVALID: @@ -2234,9 +2230,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_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep) +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) { struct xhci_ep_ctx *ep_ctx; u32 trb_comp_code; @@ -2324,15 +2320,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length = requested; finish_td: - return finish_td(xhci, td, event, ep); + return 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_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep) +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) { struct urb_priv *urb_priv; int idx; @@ -2409,7 +2405,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length += frame->actual_length; - return finish_td(xhci, td, event, ep); + return finish_td(xhci, ep, ep_ring, td, trb_comp_code); } static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, @@ -2441,17 +2437,15 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* * Process bulk and interrupt tds, update urb status and actual_length. */ -static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep) +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) { struct xhci_slot_ctx *slot_ctx; - struct xhci_ring *ep_ring; u32 trb_comp_code; u32 remaining, requested, ep_trb_len; slot_ctx = xhci_get_slot_ctx(xhci, ep->vdev->out_ctx); - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); ep_trb_len = TRB_LEN(le32_to_cpu(ep_trb->generic.field[2])); @@ -2511,7 +2505,8 @@ finish_td: remaining); td->urb->actual_length = 0; } - return finish_td(xhci, td, event, ep); + + return finish_td(xhci, ep, ep_ring, td, trb_comp_code); } /* @@ -2854,11 +2849,11 @@ static int handle_tx_event(struct xhci_hcd *xhci, /* update the urb's actual_length and give back to the core */ if (usb_endpoint_xfer_control(&td->urb->ep->desc)) - process_ctrl_td(xhci, td, ep_trb, event, ep); + process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event); else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc)) - process_isoc_td(xhci, td, ep_trb, event, ep); + process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event); else - process_bulk_intr_td(xhci, td, ep_trb, event, ep); + process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event); cleanup: handling_skipped_tds = ep->skip && trb_comp_code != COMP_MISSED_SERVICE_ERROR && @@ -3015,12 +3010,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) struct xhci_hcd *xhci = hcd_to_xhci(hcd); union xhci_trb *event_ring_deq; irqreturn_t ret = IRQ_NONE; - unsigned long flags; u64 temp_64; u32 status; int event_loop = 0; - spin_lock_irqsave(&xhci->lock, flags); + spin_lock(&xhci->lock); /* Check if the xHC generated the interrupt, or the irq is shared */ status = readl(&xhci->op_regs->status); if (status == ~(u32)0) { @@ -3083,7 +3077,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) ret = IRQ_HANDLED; out: - spin_unlock_irqrestore(&xhci->lock, flags); + spin_unlock(&xhci->lock); return ret; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1975016f46bff6fc6a75419994726181d2baf7d3..ca9385d22f68d424f7b31f1176e9683b740fe3c9 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -20,7 +20,6 @@ #include "xhci.h" #include "xhci-trace.h" -#include "xhci-mtk.h" #include "xhci-debugfs.h" #include "xhci-dbgcap.h" @@ -228,6 +227,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) struct device *dev = xhci_to_hcd(xhci)->self.sysdev; int err, i; u64 val; + u32 intrs; /* * Some Renesas controllers get into a weird state if they are @@ -266,7 +266,10 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) if (upper_32_bits(val)) xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring); - for (i = 0; i < HCS_MAX_INTRS(xhci->hcs_params1); i++) { + intrs = min_t(u32, HCS_MAX_INTRS(xhci->hcs_params1), + ARRAY_SIZE(xhci->run_regs->ir_set)); + + for (i = 0; i < intrs; i++) { struct xhci_intr_reg __iomem *ir; ir = &xhci->run_regs->ir_set[i]; @@ -1428,6 +1431,7 @@ unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc) (usb_endpoint_dir_in(desc) ? 1 : 0) - 1; return index; } +EXPORT_SYMBOL_GPL(xhci_get_endpoint_index); /* The reverse operation to xhci_get_endpoint_index. Calculate the USB endpoint * address from the XHCI endpoint index. @@ -1860,8 +1864,8 @@ err_giveback: * disabled, so there's no need for mutual exclusion to protect * the xhci->devs[slot_id] structure. */ -static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep) +int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx, *out_ctx; @@ -1921,9 +1925,6 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); - if (xhci->quirks & XHCI_MTK_HOST) - xhci_mtk_drop_ep_quirk(hcd, udev, ep); - xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, @@ -1931,6 +1932,7 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, (unsigned int) new_add_flags); return 0; } +EXPORT_SYMBOL_GPL(xhci_drop_endpoint); /* Add an endpoint to a new possible bandwidth configuration for this device. * Only one call to this function is allowed per endpoint before @@ -1945,8 +1947,8 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, * configuration or alt setting is installed in the device, so there's no need * for mutual exclusion to protect the xhci->devs[slot_id] structure. */ -static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep) +int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx; @@ -2020,15 +2022,6 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return -ENOMEM; } - if (xhci->quirks & XHCI_MTK_HOST) { - ret = xhci_mtk_add_ep_quirk(hcd, udev, ep); - if (ret < 0) { - xhci_ring_free(xhci, virt_dev->eps[ep_index].new_ring); - virt_dev->eps[ep_index].new_ring = NULL; - return ret; - } - } - ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs); new_add_flags = le32_to_cpu(ctrl_ctx->add_flags); @@ -2053,6 +2046,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, (unsigned int) new_add_flags); return 0; } +EXPORT_SYMBOL_GPL(xhci_add_endpoint); static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev) { @@ -3086,6 +3080,7 @@ command_cleanup: return ret; } +EXPORT_SYMBOL_GPL(xhci_check_bandwidth); void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) { @@ -3110,6 +3105,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) } xhci_zero_in_ctx(xhci, virt_dev); } +EXPORT_SYMBOL_GPL(xhci_reset_bandwidth); static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci, struct xhci_container_ctx *in_ctx, @@ -3269,6 +3265,14 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, /* config ep command clears toggle if add and drop ep flags are set */ ctrl_ctx = xhci_get_input_control_ctx(cfg_cmd->in_ctx); + if (!ctrl_ctx) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_free_command(xhci, cfg_cmd); + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + goto cleanup; + } + xhci_setup_input_ctx_for_config_ep(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ctrl_ctx, ep_flag, ep_flag); xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index); @@ -5234,10 +5238,12 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; hcd->self.root_hub->rx_lanes = 2; hcd->self.root_hub->tx_lanes = 2; + hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x2; break; case 1: hcd->speed = HCD_USB31; hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; + hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x1; break; } xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n", @@ -5436,6 +5442,10 @@ void xhci_init_driver(struct hc_driver *drv, drv->reset = over->reset; if (over->start) drv->start = over->start; + if (over->add_endpoint) + drv->add_endpoint = over->add_endpoint; + if (over->drop_endpoint) + drv->drop_endpoint = over->drop_endpoint; if (over->check_bandwidth) drv->check_bandwidth = over->check_bandwidth; if (over->reset_bandwidth) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ca822ad3b65b0f6383b11edd2aedfdf27f2768cd..2595a8f057c43e8d5683ba8d130ff2ed6bcf73fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1929,6 +1929,10 @@ struct xhci_driver_overrides { size_t extra_priv_size; int (*reset)(struct usb_hcd *hcd); int (*start)(struct usb_hcd *hcd); + int (*add_endpoint)(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); + int (*drop_endpoint)(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); }; @@ -2081,6 +2085,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); void xhci_init_driver(struct hc_driver *drv, const struct xhci_driver_overrides *over); +int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); +int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 45a3879799352dccf7ed1afdabceb11103aba648..6d15a097b007014ec37aba4737f602cc103c9ebb 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -183,10 +183,10 @@ static void adu_interrupt_in_callback(struct urb *urb) dev->interrupt_in_buffer, urb->actual_length); dev->read_buffer_length += urb->actual_length; - dev_dbg(&dev->udev->dev,"%s reading %d\n", __func__, + dev_dbg(&dev->udev->dev, "%s reading %d\n", __func__, urb->actual_length); } else { - dev_dbg(&dev->udev->dev,"%s : read_buffer overflow\n", + dev_dbg(&dev->udev->dev, "%s : read_buffer overflow\n", __func__); } } @@ -726,7 +726,7 @@ static int adu_probe(struct usb_interface *interface, retval = -EIO; goto error; } - dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number); + dev_dbg(&interface->dev, "serial_number=%s", dev->serial_number); /* we can register the device now, as it is ready */ usb_set_intfdata(interface, dev); diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c index 2752e1f4f4d0774aeab07c1987bc0743e603f5c7..f87890f9cd2625c87cc08557407fc3be5b95387d 100644 --- a/drivers/usb/misc/ehset.c +++ b/drivers/usb/misc/ehset.c @@ -24,68 +24,57 @@ static int ehset_probe(struct usb_interface *intf, int ret = -EINVAL; struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *hub_udev = dev->parent; - struct usb_device_descriptor *buf; + struct usb_device_descriptor buf; u8 portnum = dev->portnum; u16 test_pid = le16_to_cpu(dev->descriptor.idProduct); switch (test_pid) { case TEST_SE0_NAK_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (USB_TEST_SE0_NAK << 8) | portnum, - NULL, 0, 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_TEST, + (USB_TEST_SE0_NAK << 8) | portnum, + NULL, 0, 1000, GFP_KERNEL); break; case TEST_J_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (USB_TEST_J << 8) | portnum, - NULL, 0, 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_TEST, + (USB_TEST_J << 8) | portnum, NULL, 0, + 1000, GFP_KERNEL); break; case TEST_K_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (USB_TEST_K << 8) | portnum, - NULL, 0, 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_TEST, + (USB_TEST_K << 8) | portnum, NULL, 0, + 1000, GFP_KERNEL); break; case TEST_PACKET_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (USB_TEST_PACKET << 8) | portnum, - NULL, 0, 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_TEST, + (USB_TEST_PACKET << 8) | portnum, + NULL, 0, 1000, GFP_KERNEL); break; case TEST_HS_HOST_PORT_SUSPEND_RESUME: /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */ msleep(15 * 1000); - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_SUSPEND, portnum, - NULL, 0, 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_SUSPEND, + portnum, NULL, 0, 1000, GFP_KERNEL); if (ret < 0) break; msleep(15 * 1000); - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_SUSPEND, portnum, - NULL, 0, 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_SUSPEND, + portnum, NULL, 0, 1000, GFP_KERNEL); break; case TEST_SINGLE_STEP_GET_DEV_DESC: /* Test: wait for 15secs -> GetDescriptor request */ msleep(15 * 1000); - buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - USB_DT_DEVICE << 8, 0, - buf, USB_DT_DEVICE_SIZE, - USB_CTRL_GET_TIMEOUT); - kfree(buf); + ret = usb_control_msg_recv(dev, 0, USB_REQ_GET_DESCRIPTOR, + USB_DIR_IN, USB_DT_DEVICE << 8, 0, + &buf, USB_DT_DEVICE_SIZE, + USB_CTRL_GET_TIMEOUT, GFP_KERNEL); break; case TEST_SINGLE_STEP_SET_FEATURE: /* @@ -100,11 +89,10 @@ static int ehset_probe(struct usb_interface *intf, break; } - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (6 << 8) | portnum, - NULL, 0, 60 * 1000); + ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE, + USB_RT_PORT, USB_PORT_FEAT_TEST, + (6 << 8) | portnum, NULL, 0, + 60 * 1000, GFP_KERNEL); break; default: @@ -112,7 +100,7 @@ static int ehset_probe(struct usb_interface *intf, __func__, test_pid); } - return (ret < 0) ? ret : 0; + return ret; } static void ehset_disconnect(struct usb_interface *intf) diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c index f058d80297616889a38813d05d4ed478a5e060ef..78aaee56c2b78335c6121051196dc79aa199ad44 100644 --- a/drivers/usb/misc/ezusb.c +++ b/drivers/usb/misc/ezusb.c @@ -31,24 +31,12 @@ static const struct ezusb_fx_type ezusb_fx1 = { static int ezusb_writememory(struct usb_device *dev, int address, unsigned char *data, int length, __u8 request) { - int result; - unsigned char *transfer_buffer; - if (!dev) return -ENODEV; - transfer_buffer = kmemdup(data, length, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, length); - return -ENOMEM; - } - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + return usb_control_msg_send(dev, 0, request, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - address, 0, transfer_buffer, length, 3000); - - kfree(transfer_buffer); - return result; + address, 0, data, length, 3000, GFP_KERNEL); } static int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg, diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index 551074f5b7ad958dda5dfdaaf2bcf9488d3e6d1f..4bc816bb09bbd18661cfbfdf389e6c7334cdbed8 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -74,15 +74,10 @@ static void update_display_powered(struct usb_sevsegdev *mydev) if (mydev->shadow_power != 1) return; - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (80 * 0x100) + 10, /* (power mode) */ - (0x00 * 0x100) + (mydev->powered ? 1 : 0), - NULL, - 0, - 2000); + rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48, + (80 * 0x100) + 10, /* (power mode) */ + (0x00 * 0x100) + (mydev->powered ? 1 : 0), + NULL, 0, 2000, GFP_KERNEL); if (rc < 0) dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); @@ -99,15 +94,10 @@ static void update_display_mode(struct usb_sevsegdev *mydev) if(mydev->shadow_power != 1) return; - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (82 * 0x100) + 10, /* (set mode) */ - (mydev->mode_msb * 0x100) + mydev->mode_lsb, - NULL, - 0, - 2000); + rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48, + (82 * 0x100) + 10, /* (set mode) */ + (mydev->mode_msb * 0x100) + mydev->mode_lsb, + NULL, 0, 2000, GFP_NOIO); if (rc < 0) dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); @@ -117,48 +107,32 @@ static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf) { int rc; int i; - unsigned char *buffer; + unsigned char buffer[MAXLEN] = {0}; u8 decimals = 0; if(mydev->shadow_power != 1) return; - buffer = kzalloc(MAXLEN, mf); - if (!buffer) - return; - /* The device is right to left, where as you write left to right */ for (i = 0; i < mydev->textlength; i++) buffer[i] = mydev->text[mydev->textlength-1-i]; - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (85 * 0x100) + 10, /* (write text) */ - (0 * 0x100) + mydev->textmode, /* mode */ - buffer, - mydev->textlength, - 2000); + rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48, + (85 * 0x100) + 10, /* (write text) */ + (0 * 0x100) + mydev->textmode, /* mode */ + &buffer, mydev->textlength, 2000, mf); if (rc < 0) dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc); - kfree(buffer); - /* The device is right to left, where as you write left to right */ for (i = 0; i < sizeof(mydev->decimals); i++) decimals |= mydev->decimals[i] << i; - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (86 * 0x100) + 10, /* (set decimal) */ - (0 * 0x100) + decimals, /* decimals */ - NULL, - 0, - 2000); + rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48, + (86 * 0x100) + 10, /* (set decimal) */ + (0 * 0x100) + decimals, /* decimals */ + NULL, 0, 2000, mf); if (rc < 0) dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc); diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c index c871b94f3e6f7fbbf5ed3e4d0fe0f9b66bdd2d75..0a8cd446cf1b9e5c6c6af909bdbfcf955ea48403 100644 --- a/drivers/usb/mtu3/mtu3_host.c +++ b/drivers/usb/mtu3/mtu3_host.c @@ -24,6 +24,16 @@ #define WC1_IS_EN BIT(25) #define WC1_IS_P BIT(6) /* polarity for ip sleep */ +/* mt8183 */ +#define PERI_WK_CTRL0 0x0 +#define WC0_IS_C(x) ((u32)(((x) & 0xf) << 28)) /* cycle debounce */ +#define WC0_IS_P BIT(12) /* polarity */ +#define WC0_IS_EN BIT(6) + +/* mt8192 */ +#define WC0_SSUSB0_CDEN BIT(6) +#define WC0_IS_SPM_EN BIT(1) + /* mt2712 etc */ #define PERI_SSUSB_SPM_CTRL 0x0 #define SSC_IP_SLEEP_EN BIT(4) @@ -32,6 +42,8 @@ enum ssusb_uwk_vers { SSUSB_UWK_V1 = 1, SSUSB_UWK_V2, + SSUSB_UWK_V1_1 = 101, /* specific revision 1.01 */ + SSUSB_UWK_V1_2, /* specific revision 1.02 */ }; /* @@ -48,6 +60,16 @@ static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable) msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P; val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0; break; + case SSUSB_UWK_V1_1: + reg = ssusb->uwk_reg_base + PERI_WK_CTRL0; + msk = WC0_IS_EN | WC0_IS_C(0xf) | WC0_IS_P; + val = enable ? (WC0_IS_EN | WC0_IS_C(0x8)) : 0; + break; + case SSUSB_UWK_V1_2: + reg = ssusb->uwk_reg_base + PERI_WK_CTRL0; + msk = WC0_SSUSB0_CDEN | WC0_IS_SPM_EN; + val = enable ? msk : 0; + break; case SSUSB_UWK_V2: reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL; msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN; @@ -109,7 +131,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) void __iomem *ibase = ssusb->ippc_base; int num_u3p = ssusb->u3_ports; int num_u2p = ssusb->u2_ports; - int u3_ports_disabed; + int u3_ports_disabled; u32 check_clk; u32 value; int i; @@ -118,10 +140,10 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN); /* power on and enable u3 ports except skipped ones */ - u3_ports_disabed = 0; + u3_ports_disabled = 0; for (i = 0; i < num_u3p; i++) { if ((0x1 << i) & ssusb->u3p_dis_msk) { - u3_ports_disabed++; + u3_ports_disabled++; continue; } @@ -140,7 +162,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) } check_clk = SSUSB_XHCI_RST_B_STS; - if (num_u3p > u3_ports_disabed) + if (num_u3p > u3_ports_disabled) check_clk = SSUSB_U3_MAC_RST_B_STS; return ssusb_check_clocks(ssusb, check_clk); diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index d44d5417438dc15db796ae545d24213c9611b05c..7786a95a874e82f72f45e27e7b21eeb58001e79c 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -502,25 +502,20 @@ static const struct dev_pm_ops mtu3_pm_ops = { #define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &mtu3_pm_ops : NULL) -#ifdef CONFIG_OF - static const struct of_device_id mtu3_of_match[] = { {.compatible = "mediatek,mt8173-mtu3",}, {.compatible = "mediatek,mtu3",}, {}, }; - MODULE_DEVICE_TABLE(of, mtu3_of_match); -#endif - static struct platform_driver mtu3_driver = { .probe = mtu3_probe, .remove = mtu3_remove, .driver = { .name = MTU3_DRIVER_NAME, .pm = DEV_PM_OPS, - .of_match_table = of_match_ptr(mtu3_of_match), + .of_match_table = mtu3_of_match, }, }; module_platform_driver(mtu3_driver); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index fc0457db62e1a52a07d56675fa7bf6a6ab07f782..8f09a387b77385a7c3606f8bbcc8940e72a2cbdd 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2070,7 +2070,7 @@ static void musb_irq_work(struct work_struct *data) struct musb *musb = container_of(data, struct musb, irq_work.work); int error; - error = pm_runtime_get_sync(musb->controller); + error = pm_runtime_resume_and_get(musb->controller); if (error < 0) { dev_err(musb->controller, "Could not enable: %i\n", error); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index dbe5623db1e03f635d21759343f60338bd2a2958..a8a65effe68b56db5c86fe952957e68a54a07341 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -375,11 +375,11 @@ struct musb { unsigned dyn_fifo:1; /* dynamic FIFO supported? */ unsigned bulk_split:1; -#define can_bulk_split(musb,type) \ +#define can_bulk_split(musb, type) \ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split) unsigned bulk_combine:1; -#define can_bulk_combine(musb,type) \ +#define can_bulk_combine(musb, type) \ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine) /* is_suspended means USB B_PERIPHERAL suspend */ diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index e6fa13701808247542ea6905a0659b194f466fd8..b5e7991dc7d9e537fac334464afb4a518577f522 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -160,8 +160,10 @@ static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) usbhs_lock(priv, flags); pkt = __usbhsf_pkt_get(pipe); - if (!pkt) + if (!pkt) { + ret = -EINVAL; goto __usbhs_pkt_handler_end; + } switch (type) { case USBHSF_PKT_PREPARE: diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 97f37077b7f97502bec556acbeb712fb2cc47910..33b637d0d8d99594199fc8b034fd4374a790518a 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -189,6 +189,8 @@ usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode) return NULL; dev = class_find_device_by_fwnode(role_class, fwnode); + if (dev) + WARN_ON(!try_module_get(dev->parent->driver->owner)); return dev ? to_role_switch(dev) : NULL; } diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index b9bedfe9bd098da3fe1f35ea4522beab7d125f39..5dd710e9fe7d4f2246d601beaa7c373b1ce8d065 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -385,18 +385,6 @@ err_free: return result; } -static int ark3116_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->type = PORT_16654; - ss->line = port->minor; - ss->port = port->port_number; - ss->baud_base = 460800; - return 0; -} - static int ark3116_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -633,7 +621,6 @@ static struct usb_serial_driver ark3116_device = { .port_probe = ark3116_port_probe, .port_remove = ark3116_port_remove, .set_termios = ark3116_set_termios, - .get_serial = ark3116_get_serial_info, .tiocmget = ark3116_tiocmget, .tiocmset = ark3116_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index a373cd63b3a44f7d5cb2f7646d3d51a6149b7137..ee595d1bea0a9f61bb5914be8834294d9a82b4ea 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -1410,17 +1410,6 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state) } #ifdef CONFIG_GPIOLIB -static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset) -{ - struct usb_serial *serial = gpiochip_get_data(gc); - struct cp210x_serial_private *priv = usb_get_serial_data(serial); - - if (priv->gpio_altfunc & BIT(offset)) - return -ENODEV; - - return 0; -} - static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) { struct usb_serial *serial = gpiochip_get_data(gc); @@ -1549,6 +1538,24 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio, return -ENOTSUPP; } +static int cp210x_gpio_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, unsigned int ngpios) +{ + struct usb_serial *serial = gpiochip_get_data(gc); + struct cp210x_serial_private *priv = usb_get_serial_data(serial); + struct device *dev = &serial->interface->dev; + unsigned long altfunc_mask = priv->gpio_altfunc; + + bitmap_complement(valid_mask, &altfunc_mask, ngpios); + + if (bitmap_empty(valid_mask, ngpios)) + dev_dbg(dev, "no pin configured for GPIO\n"); + else + dev_dbg(dev, "GPIO.%*pbl configured for GPIO\n", ngpios, + valid_mask); + return 0; +} + /* * This function is for configuring GPIO using shared pins, where other signals * are made unavailable by configuring the use of GPIO. This is believed to be @@ -1786,13 +1793,13 @@ static int cp210x_gpio_init(struct usb_serial *serial) return result; priv->gc.label = "cp210x"; - priv->gc.request = cp210x_gpio_request; priv->gc.get_direction = cp210x_gpio_direction_get; priv->gc.direction_input = cp210x_gpio_direction_input; priv->gc.direction_output = cp210x_gpio_direction_output; priv->gc.get = cp210x_gpio_get; priv->gc.set = cp210x_gpio_set; priv->gc.set_config = cp210x_gpio_set_config; + priv->gc.init_valid_mask = cp210x_gpio_init_valid_mask; priv->gc.owner = THIS_MODULE; priv->gc.parent = &serial->interface->dev; priv->gc.base = -1; diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 6a8f39147d8ec393dfc40038468366eb4103916f..a7a7af8d05bffb30a7bb0cbbca7bbde31deba37a 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -820,17 +820,12 @@ static int f81232_carrier_raised(struct usb_serial_port *port) return 0; } -static int f81232_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void f81232_get_serial(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct f81232_private *priv = usb_get_serial_port_data(port); - ss->type = PORT_16550A; - ss->line = port->minor; - ss->port = port->port_number; ss->baud_base = priv->baud_base; - return 0; } static void f81232_interrupt_work(struct work_struct *work) @@ -953,7 +948,6 @@ static int f81232_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); - port->port.drain_delay = 256; priv->port = port; return 0; @@ -1021,7 +1015,7 @@ static struct usb_serial_driver f81232_device = { .close = f81232_close, .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, - .get_serial = f81232_get_serial_info, + .get_serial = f81232_get_serial, .break_ctl = f81232_break_ctl, .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, @@ -1046,7 +1040,7 @@ static struct usb_serial_driver f81534a_device = { .close = f81232_close, .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, - .get_serial = f81232_get_serial_info, + .get_serial = f81232_get_serial, .break_ctl = f81232_break_ctl, .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index a763b362f08192351f56d3aeb2587309a0448c2a..c0bca52ef92aa905b5302779e416b6cb235d4504 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1140,19 +1140,14 @@ static void f81534_close(struct usb_serial_port *port) mutex_unlock(&serial_priv->urb_mutex); } -static int f81534_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void f81534_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct f81534_port_private *port_priv; port_priv = usb_get_serial_port_data(port); - ss->type = PORT_16550A; - ss->port = port->port_number; - ss->line = port->minor; ss->baud_base = port_priv->baud_base; - return 0; } static void f81534_process_per_serial_block(struct usb_serial_port *port, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c867592477c9cc7b5ee6f3fa82c720c6e4a44b91..6f2659e59b2ee7bdfc7c16da88d3d20e25acd696 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1082,8 +1082,7 @@ static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss); +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss); static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); @@ -1477,8 +1476,7 @@ static int read_latency_timer(struct usb_serial_port *port) return 0; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +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); @@ -1486,49 +1484,34 @@ static int get_serial_info(struct tty_struct *tty, ss->flags = priv->flags; ss->baud_base = priv->baud_base; ss->custom_divisor = priv->custom_divisor; - return 0; } -static int set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static int set_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); - struct ftdi_private old_priv; + int old_flags, old_divisor; mutex_lock(&priv->cfg_lock); - old_priv = *priv; - - /* Do error checking and permission checking */ if (!capable(CAP_SYS_ADMIN)) { if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) { mutex_unlock(&priv->cfg_lock); return -EPERM; } - priv->flags = ((priv->flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK)); - priv->custom_divisor = ss->custom_divisor; - goto check_and_exit; - } - - if (ss->baud_base != priv->baud_base) { - mutex_unlock(&priv->cfg_lock); - return -EINVAL; } - /* Make the changes - these are privileged changes! */ + old_flags = priv->flags; + old_divisor = priv->custom_divisor; - priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (ss->flags & ASYNC_FLAGS)); + priv->flags = ss->flags & ASYNC_FLAGS; priv->custom_divisor = ss->custom_divisor; -check_and_exit: write_latency_timer(port); - if ((priv->flags ^ old_priv.flags) & ASYNC_SPD_MASK || + if ((priv->flags ^ old_flags) & ASYNC_SPD_MASK || ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && - priv->custom_divisor != old_priv.custom_divisor)) { + priv->custom_divisor != old_divisor)) { /* warn about deprecation unless clearing */ if (priv->flags & ASYNC_SPD_MASK) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 68401adcffde590b8f9daefe343b9b688bb07c09..e6fe3882bf691d3913a12352eed9f712cda0a9cb 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -263,39 +263,9 @@ static const struct divisor_table_entry divisor_table[] = { static atomic_t CmdUrbs = ATOMIC_INIT(0); -/* local function prototypes */ +/* function prototypes */ -/* function prototypes for all URB callbacks */ -static void edge_interrupt_callback(struct urb *urb); -static void edge_bulk_in_callback(struct urb *urb); -static void edge_bulk_out_data_callback(struct urb *urb); -static void edge_bulk_out_cmd_callback(struct urb *urb); - -/* function prototypes for the usbserial callbacks */ -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port); static void edge_close(struct usb_serial_port *port); -static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int edge_write_room(struct tty_struct *tty); -static int edge_chars_in_buffer(struct tty_struct *tty); -static void edge_throttle(struct tty_struct *tty); -static void edge_unthrottle(struct tty_struct *tty); -static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios); -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void edge_break(struct tty_struct *tty, int break_state); -static int edge_tiocmget(struct tty_struct *tty); -static int edge_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int edge_startup(struct usb_serial *serial); -static void edge_disconnect(struct usb_serial *serial); -static void edge_release(struct usb_serial *serial); -static int edge_port_probe(struct usb_serial_port *port); -static void edge_port_remove(struct usb_serial_port *port); - -/* function prototypes for all of our local functions */ static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); @@ -309,8 +279,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, __u8 param); static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor); -static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, - int baudRate); static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, struct ktermios *old_termios); @@ -321,19 +289,8 @@ static int write_cmd_usb(struct edgeport_port *edge_port, static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); -static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, const __u8 *data); -static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, __u8 *data); static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, const __u8 *data); -static void get_manufacturing_desc(struct edgeport_serial *edge_serial); -static void get_boot_desc(struct edgeport_serial *edge_serial); -static void load_application_firmware(struct edgeport_serial *edge_serial); - -static void unicode_to_ascii(char *string, int buflen, - __le16 *unicode, int unicode_size); - /* ************************************************************************ */ /* ************************************************************************ */ @@ -1637,24 +1594,6 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - - ss->type = PORT_16550A; - ss->line = edge_port->port->minor; - ss->port = edge_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = edge_port->maxTxCredits; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; - return 0; -} - - /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver @@ -3116,7 +3055,6 @@ static struct usb_serial_driver edgeport_2port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3152,7 +3090,6 @@ static struct usb_serial_driver edgeport_4port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3188,7 +3125,6 @@ static struct usb_serial_driver edgeport_8port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3224,7 +3160,6 @@ static struct usb_serial_driver epic_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 43ba53a3a6fade6351939a4eb11133c973422b45..7c9f62af5ed6bd586671a4bc573d7b607885da9e 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -10,7 +10,6 @@ #if !defined(_IO_EDGEPORT_H_) #define _IO_EDGEPORT_H_ - #define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */ /* typedefs that the insideout headers need */ @@ -21,57 +20,8 @@ #define HIGH8(a) ((unsigned char)((a & 0xff00) >> 8)) #endif -#ifndef __KERNEL__ -#define __KERNEL__ -#endif - #include "io_usbvend.h" - - -/* The following table is used to map the USBx port number to - * the device serial number (or physical USB path), */ -#define MAX_EDGEPORTS 64 - -struct comMapper { - char SerialNumber[MAX_SERIALNUMBER_LEN+1]; /* Serial number/usb path */ - int numPorts; /* Number of ports */ - int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */ - int Port[MAX_RS232_PORTS]; /* Actual used port numbers */ -}; - - -#define EDGEPORT_CONFIG_DEVICE "/proc/edgeport" - -/* /proc/edgeport Interface - * This interface uses read/write/lseek interface to talk to the edgeport driver - * the following read functions are supported: */ -#define PROC_GET_MAPPING_TO_PATH 1 -#define PROC_GET_COM_ENTRY 2 -#define PROC_GET_EDGE_MANUF_DESCRIPTOR 3 -#define PROC_GET_BOOT_DESCRIPTOR 4 -#define PROC_GET_PRODUCT_INFO 5 -#define PROC_GET_STRINGS 6 -#define PROC_GET_CURRENT_COM_MAPPING 7 - -/* The parameters to the lseek() for the read is: */ -#define PROC_READ_SETUP(Command, Argument) ((Command) + ((Argument)<<8)) - - -/* the following write functions are supported: */ -#define PROC_SET_COM_MAPPING 1 -#define PROC_SET_COM_ENTRY 2 - - -/* The following structure is passed to the write */ -struct procWrite { - int Command; - union { - struct comMapper Entry; - int ComMappingBasedOnUSBPort; /* Boolean value */ - } u; -}; - /* * Product information read from the Edgeport */ @@ -108,22 +58,4 @@ struct edgeport_product_info { struct edge_compatibility_bits Epic; }; -/* - * Edgeport Stringblock String locations - */ -#define EDGESTRING_MANUFNAME 1 /* Manufacture Name */ -#define EDGESTRING_PRODNAME 2 /* Product Name */ -#define EDGESTRING_SERIALNUM 3 /* Serial Number */ -#define EDGESTRING_ASSEMNUM 4 /* Assembly Number */ -#define EDGESTRING_OEMASSEMNUM 5 /* OEM Assembly Number */ -#define EDGESTRING_MANUFDATE 6 /* Manufacture Date */ -#define EDGESTRING_ORIGSERIALNUM 7 /* Serial Number */ - -struct string_block { - __u16 NumStrings; /* Number of strings in block */ - __u16 Strings[1]; /* Start of string block */ -}; - - - #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index e800547be9e0105a44bba6b9e9b9331d6f3db333..39503fdccebfb9438309eeabaa99d4d7484b07b3 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -60,14 +60,12 @@ #define EDGE_READ_URB_STOPPING 1 #define EDGE_READ_URB_STOPPED 2 -#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ - /* Product information read from the Edgeport */ struct product_info { int TiMode; /* Current TI Mode */ - __u8 hardware_type; /* Type of hardware */ -} __attribute__((packed)); + u8 hardware_type; /* Type of hardware */ +} __packed; /* * Edgeport firmware header @@ -89,13 +87,13 @@ struct edgeport_fw_hdr { } __packed; struct edgeport_port { - __u16 uart_base; - __u16 dma_address; - __u8 shadow_msr; - __u8 shadow_mcr; - __u8 shadow_lsr; - __u8 lsr_mask; - __u32 ump_read_timeout; /* + u16 uart_base; + u16 dma_address; + u8 shadow_msr; + u8 shadow_mcr; + u8 shadow_lsr; + u8 lsr_mask; + u32 ump_read_timeout; /* * Number of milliseconds the UMP will * wait without data before completing * a read short @@ -106,7 +104,7 @@ struct edgeport_port { struct edgeport_serial *edge_serial; struct usb_serial_port *port; - __u8 bUartMode; /* Port type, 0: RS232, etc. */ + u8 bUartMode; /* Port type, 0: RS232, etc. */ spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use; @@ -211,7 +209,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -255,8 +252,8 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port); #define TI_VSEND_TIMEOUT_DEFAULT 1000 #define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000 -static int ti_vread_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) +static int ti_vread_sync(struct usb_device *dev, u8 request, u16 value, + u16 index, void *data, int size) { int status; @@ -274,7 +271,7 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, } static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, - u16 index, u8 *data, int size, int timeout) + u16 index, void *data, int size, int timeout) { int status; @@ -287,27 +284,30 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, return 0; } -static int send_cmd(struct usb_device *dev, __u8 command, - __u8 moduleid, __u16 value, u8 *data, - int size) +static int read_port_cmd(struct usb_serial_port *port, u8 command, u16 value, + void *data, int size) +{ + return ti_vread_sync(port->serial->dev, command, value, + UMPM_UART1_PORT + port->port_number, + data, size); +} + +static int send_port_cmd(struct usb_serial_port *port, u8 command, u16 value, + void *data, int size) { - return ti_vsend_sync(dev, command, value, moduleid, data, size, - TI_VSEND_TIMEOUT_DEFAULT); + return ti_vsend_sync(port->serial->dev, command, value, + UMPM_UART1_PORT + port->port_number, + data, size, TI_VSEND_TIMEOUT_DEFAULT); } /* clear tx/rx buffers and fifo in TI UMP */ -static int purge_port(struct usb_serial_port *port, __u16 mask) +static int purge_port(struct usb_serial_port *port, u16 mask) { int port_number = port->port_number; dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask); - return send_cmd(port->serial->dev, - UMPC_PURGE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - mask, - NULL, - 0); + return send_port_cmd(port, UMPC_PURGE_PORT, mask, NULL, 0); } /** @@ -319,10 +319,10 @@ static int purge_port(struct usb_serial_port *port, __u16 mask) * @buffer: pointer to input data buffer */ static int read_download_mem(struct usb_device *dev, int start_address, - int length, __u8 address_type, __u8 *buffer) + int length, u8 address_type, u8 *buffer) { int status = 0; - __u8 read_length; + u8 read_length; u16 be_start_address; dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); @@ -335,7 +335,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, if (length > 64) read_length = 64; else - read_length = (__u8)length; + read_length = (u8)length; if (read_length > 1) { dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); @@ -346,7 +346,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, */ be_start_address = swab16((u16)start_address); status = ti_vread_sync(dev, UMPC_MEMORY_READ, - (__u16)address_type, + (u16)address_type, be_start_address, buffer, read_length); @@ -368,7 +368,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, } static int read_ram(struct usb_device *dev, int start_address, - int length, __u8 *buffer) + int length, u8 *buffer) { return read_download_mem(dev, start_address, length, DTK_ADDR_SPACE_XDATA, buffer); @@ -376,7 +376,7 @@ static int read_ram(struct usb_device *dev, int start_address, /* Read edgeport memory to a given block */ static int read_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status = 0; int i; @@ -384,7 +384,7 @@ static int read_boot_mem(struct edgeport_serial *serial, for (i = 0; i < length; i++) { status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, serial->TI_I2C_Type, - (__u16)(start_address+i), &buffer[i], 0x01); + (u16)(start_address+i), &buffer[i], 0x01); if (status) { dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status); return status; @@ -402,7 +402,7 @@ static int read_boot_mem(struct edgeport_serial *serial, /* Write given block to TI EPROM memory */ static int write_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status = 0; int i; @@ -436,7 +436,7 @@ static int write_boot_mem(struct edgeport_serial *serial, /* Write edgeport I2C memory to TI chip */ static int write_i2c_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 address_type, __u8 *buffer) + int start_address, int length, u8 address_type, u8 *buffer) { struct device *dev = &serial->serial->dev->dev; int status = 0; @@ -522,7 +522,7 @@ static int tx_active(struct edgeport_port *port) { int status; struct out_endpoint_desc_block *oedb; - __u8 *lsr; + u8 *lsr; int bytes_left = 0; oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); @@ -593,7 +593,7 @@ static int choose_config(struct usb_device *dev) } static int read_rom(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status; @@ -611,7 +611,7 @@ static int read_rom(struct edgeport_serial *serial, } static int write_rom(struct edgeport_serial *serial, int start_address, - int length, __u8 *buffer) + int length, u8 *buffer) { if (serial->product_info.TiMode == TI_MODE_BOOT) return write_boot_mem(serial, start_address, length, @@ -636,7 +636,7 @@ static int get_descriptor_addr(struct edgeport_serial *serial, status = read_rom(serial, start_address, sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); + (u8 *)rom_desc); if (status) return 0; @@ -652,13 +652,13 @@ static int get_descriptor_addr(struct edgeport_serial *serial, } /* Validate descriptor checksum */ -static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) +static int valid_csum(struct ti_i2c_desc *rom_desc, u8 *buffer) { - __u16 i; - __u8 cs = 0; + u16 i; + u8 cs = 0; for (i = 0; i < le16_to_cpu(rom_desc->Size); i++) - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); if (cs != rom_desc->CheckSum) { pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); @@ -674,8 +674,8 @@ static int check_i2c_image(struct edgeport_serial *serial) int status = 0; struct ti_i2c_desc *rom_desc; int start_address = 2; - __u8 *buffer; - __u16 ttype; + u8 *buffer; + u16 ttype; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); if (!rom_desc) @@ -703,7 +703,7 @@ static int check_i2c_image(struct edgeport_serial *serial) status = read_rom(serial, start_address, sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); + (u8 *)rom_desc); if (status) break; @@ -748,7 +748,7 @@ out: return status; } -static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) +static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer) { int status; int start_address; @@ -793,10 +793,10 @@ exit: /* Build firmware header used for firmware update */ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) { - __u8 *buffer; + u8 *buffer; int buffer_size; int i; - __u8 cs = 0; + u8 cs = 0; struct ti_i2c_desc *i2c_header; struct ti_i2c_image_header *img_header; struct ti_i2c_firmware_rec *firmware_rec; @@ -840,7 +840,7 @@ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) le16_to_cpu(img_header->Length)); for (i=0; i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); } kfree(buffer); @@ -916,7 +916,7 @@ static int bulk_xfer(struct usb_serial *serial, void *buffer, } /* Download given firmware image to the device (IN BOOT MODE) */ -static int download_code(struct edgeport_serial *serial, __u8 *image, +static int download_code(struct edgeport_serial *serial, u8 *image, int image_length) { int status = 0; @@ -1090,7 +1090,7 @@ static int do_download_mode(struct edgeport_serial *serial, if (!ti_manuf_desc) return -ENOMEM; - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); return status; @@ -1135,7 +1135,7 @@ static int do_download_mode(struct edgeport_serial *serial, status = read_rom(serial, start_address + sizeof(struct ti_i2c_desc), sizeof(struct ti_i2c_firmware_rec), - (__u8 *)firmware_version); + (u8 *)firmware_version); if (status) { kfree(firmware_version); kfree(rom_desc); @@ -1261,8 +1261,8 @@ static int do_download_mode(struct edgeport_serial *serial, if (start_address != 0) { #define HEADER_SIZE (sizeof(struct ti_i2c_desc) + \ sizeof(struct ti_i2c_firmware_rec)) - __u8 *header; - __u8 *vheader; + u8 *header; + u8 *vheader; header = kmalloc(HEADER_SIZE, GFP_KERNEL); if (!header) { @@ -1408,8 +1408,8 @@ static int do_boot_mode(struct edgeport_serial *serial, if (!check_i2c_image(serial)) { struct ti_i2c_image_header *header; int i; - __u8 cs = 0; - __u8 *buffer; + u8 cs = 0; + u8 *buffer; int buffer_size; /* @@ -1420,7 +1420,7 @@ static int do_boot_mode(struct edgeport_serial *serial, if (!ti_manuf_desc) return -ENOMEM; - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); goto stayinbootmode; @@ -1463,13 +1463,13 @@ static int do_boot_mode(struct edgeport_serial *serial, for (i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); } header = (struct ti_i2c_image_header *)buffer; /* update length and checksum after padding */ - header->Length = cpu_to_le16((__u16)(buffer_size - + header->Length = cpu_to_le16((u16)(buffer_size - sizeof(struct ti_i2c_image_header))); header->CheckSum = cs; @@ -1504,15 +1504,12 @@ stayinbootmode: static int ti_do_config(struct edgeport_port *port, int feature, int on) { - int port_number = port->port->port_number; - on = !!on; /* 1 or 0 not bitmask */ - return send_cmd(port->port->serial->dev, - feature, (__u8)(UMPM_UART1_PORT + port_number), - on, NULL, 0); + + return send_port_cmd(port->port, feature, on, NULL, 0); } -static int restore_mcr(struct edgeport_port *port, __u8 mcr) +static int restore_mcr(struct edgeport_port *port, u8 mcr) { int status = 0; @@ -1528,9 +1525,9 @@ static int restore_mcr(struct edgeport_port *port, __u8 mcr) } /* Convert TI LSR to standard UART flags */ -static __u8 map_line_status(__u8 ti_lsr) +static u8 map_line_status(u8 ti_lsr) { - __u8 lsr = 0; + u8 lsr = 0; #define MAP_FLAG(flagUmp, flagUart) \ if (ti_lsr & flagUmp) \ @@ -1548,7 +1545,7 @@ static __u8 map_line_status(__u8 ti_lsr) return lsr; } -static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) +static void handle_new_msr(struct edgeport_port *edge_port, u8 msr) { struct async_icount *icount; struct tty_struct *tty; @@ -1584,10 +1581,10 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) } static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, - __u8 lsr, __u8 data) + u8 lsr, u8 data) { struct async_icount *icount; - __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | + u8 new_lsr = (u8)(lsr & (u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr); @@ -1599,7 +1596,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, * Parity and Framing errors only count if they * occur exclusive of a break being received. */ - new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); + new_lsr &= (u8)(LSR_OVER_ERR | LSR_BREAK); /* Place LSR data byte into Rx buffer */ if (lsr_data) @@ -1628,8 +1625,8 @@ static void edge_interrupt_callback(struct urb *urb) int port_number; int function; int retval; - __u8 lsr; - __u8 msr; + u8 lsr; + u8 msr; int status = urb->status; switch (status) { @@ -1837,7 +1834,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) struct edgeport_serial *edge_serial; struct usb_device *dev; struct urb *urb; - int port_number; int status; u16 open_settings; u8 transaction_timeout; @@ -1845,8 +1841,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (edge_port == NULL) return -ENODEV; - port_number = port->port_number; - dev = port->serial->dev; /* turn off loopback */ @@ -1878,8 +1872,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__); /* Tell TI to open and start the port */ - status = send_cmd(dev, UMPC_OPEN_PORT, - (u8)(UMPM_UART1_PORT + port_number), open_settings, NULL, 0); + status = send_port_cmd(port, UMPC_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", __func__, status); @@ -1887,8 +1880,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) } /* Start the DMA? */ - status = send_cmd(dev, UMPC_START_PORT, - (u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + status = send_port_cmd(port, UMPC_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start DMA command, %d\n", __func__, status); @@ -1905,9 +1897,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) } /* Read Initial MSR */ - status = ti_vread_sync(dev, UMPC_READ_MSR, 0, - (__u16)(UMPM_UART1_PORT + port_number), - &edge_port->shadow_msr, 1); + status = read_port_cmd(port, UMPC_READ_MSR, 0, &edge_port->shadow_msr, 1); if (status) { dev_err(&port->dev, "%s - cannot send read MSR command, %d\n", __func__, status); @@ -1971,9 +1961,7 @@ static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; - struct usb_serial *serial = port->serial; unsigned long flags; - int port_number; edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); @@ -1994,9 +1982,7 @@ static void edge_close(struct usb_serial_port *port) spin_unlock_irqrestore(&edge_port->ep_lock, flags); dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); - port_number = port->port_number; - send_cmd(serial->dev, UMPC_CLOSE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + send_port_cmd(port, UMPC_CLOSE_PORT, 0, NULL, 0); mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; @@ -2229,7 +2215,6 @@ static void change_port_settings(struct tty_struct *tty, int baud; unsigned cflag; int status; - int port_number = edge_port->port->port_number; config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { @@ -2244,7 +2229,7 @@ static void change_port_settings(struct tty_struct *tty, /* These flags must be set */ config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT; config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR; - config->bUartMode = (__u8)(edge_port->bUartMode); + config->bUartMode = (u8)(edge_port->bUartMode); switch (cflag & CSIZE) { case CS5: @@ -2336,7 +2321,7 @@ static void change_port_settings(struct tty_struct *tty, } edge_port->baud_rate = baud; - config->wBaudRate = (__u16)((461550L + baud/2) / baud); + config->wBaudRate = (u16)((461550L + baud/2) / baud); /* FIXME: Recompute actual baud from divisor here */ @@ -2355,9 +2340,8 @@ static void change_port_settings(struct tty_struct *tty, cpu_to_be16s(&config->wFlags); cpu_to_be16s(&config->wBaudRate); - status = send_cmd(edge_port->port->serial->dev, UMPC_SET_CONFIG, - (__u8)(UMPM_UART1_PORT + port_number), - 0, (__u8 *)config, sizeof(*config)); + status = send_port_cmd(edge_port->port, UMPC_SET_CONFIG, 0, config, + sizeof(*config)); if (status) dev_dbg(dev, "%s - error %d when trying to write config to device\n", __func__, status); @@ -2433,28 +2417,6 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned cwait; - - cwait = edge_port->port->port.closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = jiffies_to_msecs(cwait) / 10; - - ss->type = PORT_16550A; - ss->line = edge_port->port->minor; - ss->port = edge_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = edge_port->port->bulk_out_size; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = cwait; - return 0; -} - static void edge_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2615,7 +2577,10 @@ static int edge_port_probe(struct usb_serial_port *port) if (ret) goto err; - port->port.closing_wait = msecs_to_jiffies(closing_wait * 10); + /* + * The LSR does not tell when the transmitter shift register has + * emptied so add a one-character drain delay. + */ port->port.drain_delay = 1; return 0; @@ -2713,7 +2678,6 @@ static struct usb_serial_driver edgeport_1port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2752,7 +2716,6 @@ static struct usb_serial_driver edgeport_2port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2783,9 +2746,6 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("edgeport/down3.bin"); -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); - module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device"); diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index 50b899d55ed0053ed799149e291e88a831d78a2e..24fe1312c84dbc0df668ecd90028201b86e55888 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -133,15 +133,15 @@ #define UMPD_OEDB2_ADDRESS 0xFF10 struct out_endpoint_desc_block { - __u8 Configuration; - __u8 XBufAddr; - __u8 XByteCount; - __u8 Unused1; - __u8 Unused2; - __u8 YBufAddr; - __u8 YByteCount; - __u8 BufferSize; -} __attribute__((packed)); + u8 Configuration; + u8 XBufAddr; + u8 XByteCount; + u8 Unused1; + u8 Unused2; + u8 YBufAddr; + u8 YByteCount; + u8 BufferSize; +}; /* @@ -150,16 +150,16 @@ struct out_endpoint_desc_block { */ /* UART settings */ struct ump_uart_config { - __u16 wBaudRate; /* Baud rate */ - __u16 wFlags; /* Bitmap mask of flags */ - __u8 bDataBits; /* 5..8 - data bits per character */ - __u8 bParity; /* Parity settings */ - __u8 bStopBits; /* Stop bits settings */ + u16 wBaudRate; /* Baud rate */ + u16 wFlags; /* Bitmap mask of flags */ + u8 bDataBits; /* 5..8 - data bits per character */ + u8 bParity; /* Parity settings */ + u8 bStopBits; /* Stop bits settings */ char cXon; /* XON character */ char cXoff; /* XOFF character */ - __u8 bUartMode; /* Will be updated when a user */ + u8 bUartMode; /* Will be updated when a user */ /* interface is defined */ -} __attribute__((packed)); +}; /* @@ -168,9 +168,9 @@ struct ump_uart_config { */ /* Interrupt packet structure */ struct ump_interrupt { - __u8 bICode; /* Interrupt code (interrupt num) */ - __u8 bIInfo; /* Interrupt information */ -} __attribute__((packed)); + u8 bICode; /* Interrupt code (interrupt num) */ + u8 bIInfo; /* Interrupt information */ +}; #define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 6) & 0x01) diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 093afd67a66463ba2ceca94e69c682350ec8c643..19753611e7b08eadd2ff252c86439ed529e9656d 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -643,7 +643,6 @@ static void iuu_uart_read_callback(struct urb *urb) struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; int status = urb->status; - int error = 0; int len = 0; unsigned char *data = urb->transfer_buffer; priv->poll++; @@ -660,12 +659,11 @@ static void iuu_uart_read_callback(struct urb *urb) if (urb->actual_length > 1) { dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__, urb->actual_length); - error = 1; return; } /* if len > 0 call readbuf */ - if (len > 0 && error == 0) { + if (len > 0) { dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n", __func__, len); status = iuu_read_buf(port, len); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 622077dcc344631ca220465a8bf9d447c6e9a87d..b04a029e36571b2e4d63e9683d8b89004417b439 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -41,27 +41,7 @@ #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu" #define DRIVER_DESC "Keyspan USB to Serial Converter Driver" -/* Function prototypes for Keyspan serial converter */ -static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port); -static void keyspan_close(struct usb_serial_port *port); -static void keyspan_dtr_rts(struct usb_serial_port *port, int on); -static int keyspan_startup(struct usb_serial *serial); -static void keyspan_disconnect(struct usb_serial *serial); -static void keyspan_release(struct usb_serial *serial); -static int keyspan_port_probe(struct usb_serial_port *port); -static void keyspan_port_remove(struct usb_serial_port *port); -static int keyspan_write_room(struct tty_struct *tty); -static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); static void keyspan_send_setup(struct usb_serial_port *port, int reset_port); -static void keyspan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -static void keyspan_break_ctl(struct tty_struct *tty, int break_state); -static int keyspan_tiocmget(struct tty_struct *tty); -static int keyspan_tiocmset(struct tty_struct *tty, unsigned int set, - unsigned int clear); -static int keyspan_fake_startup(struct usb_serial *serial); static int keyspan_usa19_calc_baud(struct usb_serial_port *port, u32 baud_rate, u32 baudclk, diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 0bfe4459c37f53d49f23e5fc8e3fc0dc6e8a5916..f9ce9e7b9b807cd4c5928250d7e1f0e52e3783b3 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -299,7 +299,7 @@ static int metrousb_tiocmset(struct tty_struct *tty, unsigned long flags = 0; unsigned long control_state = 0; - dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear); + dev_dbg(&port->dev, "%s - set=%d, clear=%d\n", __func__, set, clear); spin_lock_irqsave(&metro_priv->lock, flags); control_state = metro_priv->control_state; @@ -334,7 +334,7 @@ static void metrousb_unthrottle(struct tty_struct *tty) /* Submit the urb to read from the port. */ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) - dev_err(tty->dev, + dev_err(&port->dev, "failed submitting interrupt in urb error code=%d\n", result); } diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 701dfb32b12936821c12eef61a21a04133556f91..6ee83886e2c9db485f85ac612a574eb74648ea81 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1042,7 +1042,7 @@ static int mos7720_write_room(struct tty_struct *tty) mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) - return -ENODEV; + return 0; /* FIXME: Locking */ for (i = 0; i < NUM_URBS; ++i) { @@ -1634,23 +1634,6 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - - ss->type = PORT_16550A; - ss->line = mos7720_port->port->minor; - ss->port = mos7720_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; - return 0; -} - static int mos7720_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -1790,7 +1773,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .ioctl = mos7720_ioctl, .tiocmget = mos7720_tiocmget, .tiocmset = mos7720_tiocmset, - .get_serial = get_serial_info, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 1bf0d066f55aef896c65859a7347357d8100c308..28e4093794e079eca8b32c7f6d18350b4ac535c8 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1383,28 +1383,6 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, return 0; } -/***************************************************************************** - * mos7840_get_serial_info - * function to get information about serial port - *****************************************************************************/ - -static int mos7840_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port = usb_get_serial_port_data(port); - - ss->type = PORT_16550A; - ss->line = mos7840_port->port->minor; - ss->port = mos7840_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - ss->baud_base = 9600; - ss->close_delay = 5 * HZ; - ss->closing_wait = 30 * HZ; - return 0; -} - /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver @@ -1783,7 +1761,6 @@ static struct usb_serial_driver moschip7840_4port_device = { .probe = mos7840_probe, .attach = mos7840_attach, .ioctl = mos7840_ioctl, - .get_serial = mos7840_get_serial_info, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index eecb72aef83ec7303d17dfdaa1893760b26352dc..40c713fae0c38ff00d0b81916e269f82d383944b 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -352,23 +352,6 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - /* fake emulate a 16550 uart to make userspace code happy */ - ss->type = PORT_16550A; - ss->line = port->minor; - ss->port = 0; - ss->irq = 0; - ss->xmit_fifo_size = 1024; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; - return 0; -} - static int opticon_port_probe(struct usb_serial_port *port) { struct opticon_private *priv; @@ -410,7 +393,6 @@ static struct usb_serial_driver opticon_device = { .chars_in_buffer = opticon_chars_in_buffer, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, - .get_serial = get_serial_info, .tiocmget = opticon_tiocmget, .tiocmset = opticon_tiocmset, .process_read_urb = opticon_process_read_urb, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c6969ca72839083ebac780ee31dc5b6304bbde12..3e79a543d3e771d515bdd502c7df5035becbe617 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2095,8 +2095,6 @@ static struct usb_serial_driver option_1port_device = { .chars_in_buffer = usb_wwan_chars_in_buffer, .tiocmget = usb_wwan_tiocmget, .tiocmset = usb_wwan_tiocmset, - .get_serial = usb_wwan_get_serial_info, - .set_serial = usb_wwan_set_serial_info, .attach = option_attach, .release = option_release, .port_probe = usb_wwan_port_probe, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index eed9acd1ae08920baab9ec8c828dd7f5a299006e..fd773d252691b86a42d4b17da31a2e1a6bc68217 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -173,17 +173,22 @@ MODULE_DEVICE_TABLE(usb, id_table); static void pl2303_set_break(struct usb_serial_port *port, bool enable); enum pl2303_type { - TYPE_01, /* Type 0 and 1 (difference unknown) */ - TYPE_HX, /* HX version of the pl2303 chip */ - TYPE_HXN, /* HXN version of the pl2303 chip */ + TYPE_H, + TYPE_HX, + TYPE_TA, + TYPE_TB, + TYPE_HXD, + TYPE_HXN, TYPE_COUNT }; struct pl2303_type_data { + const char *name; speed_t max_baud_rate; unsigned long quirks; unsigned int no_autoxonxoff:1; unsigned int no_divisors:1; + unsigned int alt_divisors:1; }; struct pl2303_serial_private { @@ -200,15 +205,32 @@ struct pl2303_private { }; static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { - [TYPE_01] = { + [TYPE_H] = { + .name = "H", .max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, .no_autoxonxoff = true, }, [TYPE_HX] = { + .name = "HX", + .max_baud_rate = 6000000, + }, + [TYPE_TA] = { + .name = "TA", + .max_baud_rate = 6000000, + .alt_divisors = true, + }, + [TYPE_TB] = { + .name = "TB", + .max_baud_rate = 12000000, + .alt_divisors = true, + }, + [TYPE_HXD] = { + .name = "HXD", .max_baud_rate = 12000000, }, [TYPE_HXN] = { + .name = "G", .max_baud_rate = 12000000, .no_divisors = true, }, @@ -362,42 +384,82 @@ static int pl2303_calc_num_ports(struct usb_serial *serial, return 1; } +static bool pl2303_supports_hx_status(struct usb_serial *serial) +{ + int ret; + u8 buf; + + ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST, + VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, + 0, &buf, 1, 100, GFP_KERNEL); + + return ret == 0; +} + +static int pl2303_detect_type(struct usb_serial *serial) +{ + struct usb_device_descriptor *desc = &serial->dev->descriptor; + u16 bcdDevice, bcdUSB; + + /* + * Legacy PL2303H, variants 0 and 1 (difference unknown). + */ + if (desc->bDeviceClass == 0x02) + return TYPE_H; /* variant 0 */ + + if (desc->bMaxPacketSize0 != 0x40) { + if (desc->bDeviceClass == 0x00 || desc->bDeviceClass == 0xff) + return TYPE_H; /* variant 1 */ + + return TYPE_H; /* variant 0 */ + } + + bcdDevice = le16_to_cpu(desc->bcdDevice); + bcdUSB = le16_to_cpu(desc->bcdUSB); + + switch (bcdDevice) { + case 0x100: + /* + * Assume it's an HXN-type if the device doesn't support the old read + * request value. + */ + if (bcdUSB == 0x200 && !pl2303_supports_hx_status(serial)) + return TYPE_HXN; + break; + case 0x300: + if (bcdUSB == 0x200) + return TYPE_TA; + + return TYPE_HX; + case 0x400: + return TYPE_HXD; + case 0x500: + return TYPE_TB; + } + + dev_err(&serial->interface->dev, + "unknown device type, please report to linux-usb@vger.kernel.org\n"); + return -ENODEV; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; - enum pl2303_type type = TYPE_01; + enum pl2303_type type; unsigned char *buf; - int res; + int ret; + + ret = pl2303_detect_type(serial); + if (ret < 0) + return ret; + + type = ret; + dev_dbg(&serial->interface->dev, "device type: %s\n", pl2303_type_data[type].name); spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; - buf = kmalloc(1, GFP_KERNEL); - if (!buf) { - kfree(spriv); - return -ENOMEM; - } - - if (serial->dev->descriptor.bDeviceClass == 0x02) - type = TYPE_01; /* type 0 */ - else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) - type = TYPE_HX; - else if (serial->dev->descriptor.bDeviceClass == 0x00) - type = TYPE_01; /* type 1 */ - else if (serial->dev->descriptor.bDeviceClass == 0xFF) - type = TYPE_01; /* type 1 */ - dev_dbg(&serial->interface->dev, "device type: %d\n", type); - - if (type == TYPE_HX) { - res = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, - PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100); - if (res != 1) - type = TYPE_HXN; - } - spriv->type = &pl2303_type_data[type]; spriv->quirks = (unsigned long)usb_get_serial_data(serial); spriv->quirks |= spriv->type->quirks; @@ -405,6 +467,12 @@ static int pl2303_startup(struct usb_serial *serial) usb_set_serial_data(serial, spriv); if (type != TYPE_HXN) { + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + kfree(spriv); + return -ENOMEM; + } + pl2303_vendor_read(serial, 0x8484, buf); pl2303_vendor_write(serial, 0x0404, 0); pl2303_vendor_read(serial, 0x8484, buf); @@ -419,9 +487,9 @@ static int pl2303_startup(struct usb_serial *serial) pl2303_vendor_write(serial, 2, 0x24); else pl2303_vendor_write(serial, 2, 0x44); - } - kfree(buf); + kfree(buf); + } return 0; } @@ -553,6 +621,45 @@ static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], return baud; } +static speed_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4], + speed_t baud) +{ + unsigned int baseline, mantissa, exponent; + + /* + * Apparently, for the TA version the formula is: + * baudrate = 12M * 32 / (mantissa * 2^exponent) + * where + * mantissa = buf[10:0] + * exponent = buf[15:13 16] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ + exponent = 0; + while (mantissa >= 2048) { + if (exponent < 15) { + mantissa >>= 1; /* divide by 2 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 2047; + break; + } + } + + buf[3] = 0x80; + buf[2] = exponent & 0x01; + buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8; + buf[0] = mantissa & 0xff; + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> exponent; + + return baud; +} + static void pl2303_encode_baud_rate(struct tty_struct *tty, struct usb_serial_port *port, u8 buf[4]) @@ -580,6 +687,8 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty, if (baud == baud_sup) baud = pl2303_encode_baud_rate_direct(buf, baud); + else if (spriv->type->alt_divisors) + baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); else baud = pl2303_encode_baud_rate_divisor(buf, baud); @@ -939,18 +1048,6 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) return 0; } -static int pl2303_get_serial(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->type = PORT_16654; - ss->line = port->minor; - ss->port = port->port_number; - ss->baud_base = 460800; - return 0; -} - static void pl2303_set_break(struct usb_serial_port *port, bool enable) { struct usb_serial *serial = port->serial; @@ -1134,7 +1231,6 @@ static struct usb_serial_driver pl2303_device = { .close = pl2303_close, .dtr_rts = pl2303_dtr_rts, .carrier_raised = pl2303_carrier_raised, - .get_serial = pl2303_get_serial, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 599dcb2e374d0c240ef51e356700866c0420cced..5f2e7f668e687953305918df4bfcc8a99dc7572a 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -453,21 +453,6 @@ static void qt2_disconnect(struct usb_serial *serial) usb_kill_urb(serial_priv->read_urb); } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->line = port->minor; - ss->port = 0; - ss->irq = 0; - ss->xmit_fifo_size = port->bulk_out_size; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; - return 0; -} - static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) { switch (*ch) { @@ -978,7 +963,6 @@ static struct usb_serial_driver qt2_device = { .tiocmset = qt2_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .get_serial = get_serial_info, .set_termios = qt2_set_termios, }; diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 89fdc5c19285d09a8234454c2d2091db5c497231..3baf7c0f5a9810c094d378587b60b53a717e1835 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -331,21 +331,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return usb_serial_generic_open(tty, port); } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->line = port->minor; - ss->port = 0; - ss->irq = 0; - ss->xmit_fifo_size = port->bulk_out_size; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; - return 0; -} - static int ssu100_attach(struct usb_serial *serial) { return ssu100_initdevice(serial->dev); @@ -545,7 +530,6 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .get_serial = get_serial_info, .set_termios = ssu100_set_termios, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 7252b0ce75a6ce43068d8cd73220c58b09540aea..caa46ac23db90e8ab953c773aa16453604d9050a 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -121,6 +121,7 @@ #define TI_LSR_ERROR 0x0F #define TI_LSR_RX_FULL 0x10 #define TI_LSR_TX_EMPTY 0x20 +#define TI_LSR_TX_EMPTY_BOTH 0x40 /* Line control */ #define TI_LCR_BREAK 0x40 @@ -183,7 +184,7 @@ struct ti_uart_config { char cXon; char cXoff; u8 bUartMode; -} __packed; +}; /* Get port status */ struct ti_port_status { @@ -192,7 +193,7 @@ struct ti_port_status { u8 bErrorCode; u8 bMSR; u8 bLSR; -} __packed; +}; /* Purge modes */ #define TI_PURGE_OUTPUT 0x00 @@ -223,25 +224,25 @@ struct ti_write_data_bytes { } __packed; struct ti_read_data_request { - __u8 bAddrType; - __u8 bDataType; - __u8 bDataCounter; + u8 bAddrType; + u8 bDataType; + u8 bDataCounter; __be16 wBaseAddrHi; __be16 wBaseAddrLo; } __packed; struct ti_read_data_bytes { - __u8 bCmdCode; - __u8 bModuleId; - __u8 bErrorCode; - __u8 bData[]; -} __packed; + u8 bCmdCode; + u8 bModuleId; + u8 bErrorCode; + u8 bData[]; +}; /* Interrupt struct */ struct ti_interrupt { - __u8 bICode; - __u8 bIInfo; -} __packed; + u8 bICode; + u8 bIInfo; +}; /* Interrupt codes */ #define TI_CODE_HARDWARE_ERROR 0xFF @@ -270,8 +271,6 @@ struct ti_firmware_header { #define TI_TRANSFER_TIMEOUT 2 -#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */ - /* read urb states */ #define TI_READ_URB_RUNNING 0 #define TI_READ_URB_STOPPING 1 @@ -328,27 +327,26 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data, static void ti_send(struct ti_port *tport); static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); static int ti_get_lsr(struct ti_port *tport, u8 *lsr); -static int ti_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss); -static int ti_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss); +static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss); static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); -static int ti_command_out_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size); -static int ti_command_in_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size); +static int ti_command_out_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size); +static int ti_command_in_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size); +static int ti_port_cmd_out(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size); +static int ti_port_cmd_in(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size); static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, unsigned long addr, u8 mask, u8 byte); static int ti_download_firmware(struct ti_device *tdev); -static int closing_wait = TI_DEFAULT_CLOSING_WAIT; - static const struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, @@ -435,7 +433,6 @@ static struct usb_serial_driver ti_1port_device = { .throttle = ti_throttle, .unthrottle = ti_unthrottle, .get_serial = ti_get_serial_info, - .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -469,7 +466,6 @@ static struct usb_serial_driver ti_2port_device = { .throttle = ti_throttle, .unthrottle = ti_unthrottle, .get_serial = ti_get_serial_info, - .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -502,10 +498,6 @@ MODULE_FIRMWARE("moxa/moxa-1131.fw"); MODULE_FIRMWARE("moxa/moxa-1150.fw"); MODULE_FIRMWARE("moxa/moxa-1151.fw"); -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, - "Maximum wait for data to drain in close, in .01 secs, default is 4000"); - MODULE_DEVICE_TABLE(usb, ti_id_table_combined); module_usb_serial_driver(serial_drivers, ti_id_table_combined); @@ -613,7 +605,6 @@ static int ti_port_probe(struct usb_serial_port *port) tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; else tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; - port->port.closing_wait = msecs_to_jiffies(10 * closing_wait); tport->tp_port = port; tport->tp_tdev = usb_get_serial_data(port->serial); @@ -624,7 +615,12 @@ static int ti_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, tport); - port->port.drain_delay = 3; + /* + * The TUSB5052 LSR does not tell when the transmitter shift register + * has emptied so add a one-character drain delay. + */ + if (!tport->tp_tdev->td_is_3410) + port->port.drain_delay = 1; return 0; } @@ -643,7 +639,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) struct ti_device *tdev; struct usb_device *dev; struct urb *urb; - int port_number; int status; u16 open_settings; @@ -658,8 +653,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (mutex_lock_interruptible(&tdev->td_open_close_lock)) return -ERESTARTSYS; - port_number = port->port_number; - tport->tp_msr = 0; tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); @@ -683,31 +676,27 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - status = ti_command_out_sync(tdev, TI_OPEN_PORT, - (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); + status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_START_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); + status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start command, %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_PURGE_PORT, - (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0); + status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_INPUT, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot clear input buffers, %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_PURGE_PORT, - (__u8)(TI_UART1_PORT + port_number), TI_PURGE_OUTPUT, NULL, 0); + status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_OUTPUT, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot clear output buffers, %d\n", __func__, status); @@ -722,16 +711,14 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - status = ti_command_out_sync(tdev, TI_OPEN_PORT, - (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); + status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command (2), %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_START_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); + status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start command (2), %d\n", __func__, status); @@ -772,7 +759,6 @@ static void ti_close(struct usb_serial_port *port) { struct ti_device *tdev; struct ti_port *tport; - int port_number; int status; unsigned long flags; @@ -788,10 +774,7 @@ static void ti_close(struct usb_serial_port *port) kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - port_number = port->port_number; - - status = ti_command_out_sync(tdev, TI_CLOSE_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); + status = ti_port_cmd_out(port, TI_CLOSE_PORT, 0, NULL, 0); if (status) dev_err(&port->dev, "%s - cannot send close port command, %d\n" @@ -861,11 +844,20 @@ static int ti_chars_in_buffer(struct tty_struct *tty) static bool ti_tx_empty(struct usb_serial_port *port) { struct ti_port *tport = usb_get_serial_port_data(port); + u8 lsr, mask; int ret; - u8 lsr; + + /* + * TUSB5052 does not have the TEMT bit to tell if the shift register + * is empty. + */ + if (tport->tp_tdev->td_is_3410) + mask = TI_LSR_TX_EMPTY_BOTH; + else + mask = TI_LSR_TX_EMPTY; ret = ti_get_lsr(tport, &lsr); - if (!ret && !(lsr & TI_LSR_TX_EMPTY)) + if (!ret && !(lsr & mask)) return false; return true; @@ -903,7 +895,6 @@ static void ti_set_termios(struct tty_struct *tty, struct ti_uart_config *config; int baud; int status; - int port_number = port->port_number; unsigned int mcr; u16 wbaudrate; u16 wflags = 0; @@ -919,18 +910,18 @@ static void ti_set_termios(struct tty_struct *tty, switch (C_CSIZE(tty)) { case CS5: - config->bDataBits = TI_UART_5_DATA_BITS; - break; + config->bDataBits = TI_UART_5_DATA_BITS; + break; case CS6: - config->bDataBits = TI_UART_6_DATA_BITS; - break; + config->bDataBits = TI_UART_6_DATA_BITS; + break; case CS7: - config->bDataBits = TI_UART_7_DATA_BITS; - break; + config->bDataBits = TI_UART_7_DATA_BITS; + break; default: case CS8: - config->bDataBits = TI_UART_8_DATA_BITS; - break; + config->bDataBits = TI_UART_8_DATA_BITS; + break; } /* CMSPAR isn't supported by this driver */ @@ -997,12 +988,11 @@ static void ti_set_termios(struct tty_struct *tty, config->wBaudRate = cpu_to_be16(wbaudrate); config->wFlags = cpu_to_be16(wflags); - status = ti_command_out_sync(tport->tp_tdev, TI_SET_CONFIG, - (__u8)(TI_UART1_PORT + port_number), 0, (__u8 *)config, - sizeof(*config)); + status = ti_port_cmd_out(port, TI_SET_CONFIG, 0, config, + sizeof(*config)); if (status) dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", - __func__, port_number, status); + __func__, port->port_number, status); /* SET_CONFIG asserts RTS and DTR, reset them correctly */ mcr = tport->tp_shadow_mcr; @@ -1011,9 +1001,8 @@ static void ti_set_termios(struct tty_struct *tty, mcr &= ~(TI_MCR_DTR | TI_MCR_RTS); status = ti_set_mcr(tport, mcr); if (status) - dev_err(&port->dev, - "%s - cannot set modem control on port %d, %d\n", - __func__, port_number, status); + dev_err(&port->dev, "%s - cannot set modem control on port %d, %d\n", + __func__, port->port_number, status); kfree(config); } @@ -1364,9 +1353,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) static int ti_get_lsr(struct ti_port *tport, u8 *lsr) { int size, status; - struct ti_device *tdev = tport->tp_tdev; struct usb_serial_port *port = tport->tp_port; - int port_number = port->port_number; struct ti_port_status *data; size = sizeof(struct ti_port_status); @@ -1374,8 +1361,7 @@ static int ti_get_lsr(struct ti_port *tport, u8 *lsr) if (!data) return -ENOMEM; - status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS, - (__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size); + status = ti_port_cmd_in(port, TI_GET_PORT_STATUS, 0, data, size); if (status) { dev_err(&port->dev, "%s - get port status command failed, %d\n", @@ -1393,41 +1379,12 @@ free_data: } -static int ti_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - unsigned cwait; - - cwait = port->port.closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = jiffies_to_msecs(cwait) / 10; - ss->type = PORT_16550A; - ss->line = port->minor; - ss->port = port->port_number; - ss->xmit_fifo_size = kfifo_size(&port->write_fifo); ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ss->closing_wait = cwait; - return 0; -} - - -static int ti_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - unsigned cwait; - - cwait = ss->closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = msecs_to_jiffies(10 * ss->closing_wait); - - tport->tp_port->port.closing_wait = cwait; - - return 0; } @@ -1501,34 +1458,28 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) return status; } - -static int ti_command_out_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size) +static int ti_command_out_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size) { int status; - status = usb_control_msg(tdev->td_serial->dev, - usb_sndctrlpipe(tdev->td_serial->dev, 0), command, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, moduleid, data, size, 1000); - + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), command, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, moduleid, data, size, 1000); if (status < 0) return status; return 0; } - -static int ti_command_in_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size) +static int ti_command_in_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size) { int status; - status = usb_control_msg(tdev->td_serial->dev, - usb_rcvctrlpipe(tdev->td_serial->dev, 0), command, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN), - value, moduleid, data, size, 1000); - + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), command, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, moduleid, data, size, 1000); if (status == size) status = 0; else if (status >= 0) @@ -1537,6 +1488,21 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, return status; } +static int ti_port_cmd_out(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size) +{ + return ti_command_out_sync(port->serial->dev, command, + TI_UART1_PORT + port->port_number, + value, data, size); +} + +static int ti_port_cmd_in(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size) +{ + return ti_command_in_sync(port->serial->dev, command, + TI_UART1_PORT + port->port_number, + value, data, size); +} static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, unsigned long addr, @@ -1562,9 +1528,8 @@ static int ti_write_byte(struct usb_serial_port *port, data->bData[0] = mask; data->bData[1] = byte; - status = ti_command_out_sync(tdev, TI_WRITE_DATA, TI_RAM_PORT, 0, - (__u8 *)data, size); - + status = ti_command_out_sync(port->serial->dev, TI_WRITE_DATA, + TI_RAM_PORT, 0, data, size); if (status < 0) dev_err(&port->dev, "%s - failed, %d\n", __func__, status); diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c index 26d7b003b7e3a72a08f10aa9bbdc8bd1740e6c18..63d4a784ae457ccae525ba0cd24089c05a4ab959 100644 --- a/drivers/usb/serial/upd78f0730.c +++ b/drivers/usb/serial/upd78f0730.c @@ -182,7 +182,6 @@ static void upd78f0730_port_remove(struct usb_serial_port *port) static int upd78f0730_tiocmget(struct tty_struct *tty) { - struct device *dev = tty->dev; struct upd78f0730_port_private *private; struct usb_serial_port *port = tty->driver_data; int signals; @@ -197,7 +196,7 @@ static int upd78f0730_tiocmget(struct tty_struct *tty) res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) | ((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0); - dev_dbg(dev, "%s - res = %x\n", __func__, res); + dev_dbg(&port->dev, "%s - res = %x\n", __func__, res); return res; } @@ -205,10 +204,10 @@ static int upd78f0730_tiocmget(struct tty_struct *tty) static int upd78f0730_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { - struct device *dev = tty->dev; struct usb_serial_port *port = tty->driver_data; struct upd78f0730_port_private *private; struct upd78f0730_set_dtr_rts request; + struct device *dev = &port->dev; int res; private = usb_get_serial_port_data(port); @@ -241,10 +240,10 @@ static int upd78f0730_tiocmset(struct tty_struct *tty, static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state) { - struct device *dev = tty->dev; struct upd78f0730_port_private *private; struct usb_serial_port *port = tty->driver_data; struct upd78f0730_set_dtr_rts request; + struct device *dev = &port->dev; private = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 27e3bb58c872eacbd6a2f121571498ae7d10f356..98b33b1b5357c1c89ae4dd54d3282631869ac0a0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -121,6 +121,44 @@ static void release_minors(struct usb_serial *serial) serial->minors_reserved = 0; } +int usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf) +{ + struct usb_driver *driver = serial->type->usb_driver; + int ret; + + if (serial->sibling) + return -EBUSY; + + ret = usb_driver_claim_interface(driver, intf, serial); + if (ret) { + dev_err(&serial->interface->dev, + "failed to claim sibling interface: %d\n", ret); + return ret; + } + + serial->sibling = intf; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_claim_interface); + +static void release_sibling(struct usb_serial *serial, struct usb_interface *intf) +{ + struct usb_driver *driver = serial->type->usb_driver; + struct usb_interface *sibling; + + if (!serial->sibling) + return; + + if (intf == serial->sibling) + sibling = serial->interface; + else + sibling = serial->sibling; + + usb_set_intfdata(sibling, NULL); + usb_driver_release_interface(driver, sibling); +} + static void destroy_serial(struct kref *kref) { struct usb_serial *serial; @@ -243,7 +281,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); return tty_port_open(&port->port, tty, filp); } @@ -272,7 +310,7 @@ static void serial_hangup(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); tty_port_hangup(&port->port); } @@ -281,7 +319,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); tty_port_close(&port->port, tty, filp); } @@ -301,7 +339,7 @@ static void serial_cleanup(struct tty_struct *tty) struct usb_serial *serial; struct module *owner; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); /* The console is magical. Do not hang up the console hardware * or there will be tears. @@ -329,7 +367,7 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf, if (port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; - dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count); + dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count); retval = port->serial->type->write(tty, port, buf, count); if (retval < 0) @@ -342,7 +380,7 @@ static int serial_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); return port->serial->type->write_room(tty); } @@ -352,7 +390,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (serial->disconnected) return 0; @@ -365,7 +403,7 @@ static void serial_wait_until_sent(struct tty_struct *tty, int timeout) struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (!port->serial->type->wait_until_sent) return; @@ -380,7 +418,7 @@ static void serial_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->throttle) port->serial->type->throttle(tty); @@ -390,7 +428,7 @@ static void serial_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->unthrottle) port->serial->type->unthrottle(tty); @@ -399,19 +437,62 @@ static void serial_unthrottle(struct tty_struct *tty) static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + unsigned int close_delay, closing_wait; + + mutex_lock(&tport->mutex); + + close_delay = jiffies_to_msecs(tport->close_delay) / 10; + closing_wait = tport->closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = jiffies_to_msecs(closing_wait) / 10; + + ss->line = port->minor; + ss->close_delay = close_delay; + ss->closing_wait = closing_wait; if (port->serial->type->get_serial) - return port->serial->type->get_serial(tty, ss); - return -ENOTTY; + port->serial->type->get_serial(tty, ss); + + mutex_unlock(&tport->mutex); + + return 0; } static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + unsigned int close_delay, closing_wait; + int ret = 0; + + close_delay = msecs_to_jiffies(ss->close_delay * 10); + closing_wait = ss->closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = msecs_to_jiffies(closing_wait * 10); + + mutex_lock(&tport->mutex); + + if (!capable(CAP_SYS_ADMIN)) { + if (close_delay != tport->close_delay || + closing_wait != tport->closing_wait) { + ret = -EPERM; + goto out_unlock; + } + } - if (port->serial->type->set_serial) - return port->serial->type->set_serial(tty, ss); - return -ENOTTY; + if (port->serial->type->set_serial) { + ret = port->serial->type->set_serial(tty, ss); + if (ret) + goto out_unlock; + } + + tport->close_delay = close_delay; + tport->closing_wait = closing_wait; +out_unlock: + mutex_unlock(&tport->mutex); + + return ret; } static int serial_ioctl(struct tty_struct *tty, @@ -420,7 +501,7 @@ static int serial_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; int retval = -ENOIOCTLCMD; - dev_dbg(tty->dev, "%s - cmd 0x%04x\n", __func__, cmd); + dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd); switch (cmd) { case TIOCMIWAIT: @@ -439,7 +520,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->set_termios) port->serial->type->set_termios(tty, port, old); @@ -451,7 +532,7 @@ static int serial_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->break_ctl) port->serial->type->break_ctl(tty, break_state); @@ -498,11 +579,11 @@ static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->tiocmget) return port->serial->type->tiocmget(tty); - return -EINVAL; + return -ENOTTY; } static int serial_tiocmset(struct tty_struct *tty, @@ -510,11 +591,11 @@ static int serial_tiocmset(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->tiocmset) return port->serial->type->tiocmset(tty, set, clear); - return -EINVAL; + return -ENOTTY; } static int serial_get_icount(struct tty_struct *tty, @@ -522,11 +603,11 @@ static int serial_get_icount(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->get_icount) return port->serial->type->get_icount(tty, icount); - return -EINVAL; + return -ENOTTY; } /* @@ -711,36 +792,48 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_port_shutdown, }; -static void find_endpoints(struct usb_serial *serial, - struct usb_serial_endpoints *epds) +static void store_endpoint(struct usb_serial *serial, + struct usb_serial_endpoints *epds, + struct usb_endpoint_descriptor *epd) { struct device *dev = &serial->interface->dev; + u8 addr = epd->bEndpointAddress; + + if (usb_endpoint_is_bulk_in(epd)) { + if (epds->num_bulk_in == ARRAY_SIZE(epds->bulk_in)) + return; + dev_dbg(dev, "found bulk in endpoint %02x\n", addr); + epds->bulk_in[epds->num_bulk_in++] = epd; + } else if (usb_endpoint_is_bulk_out(epd)) { + if (epds->num_bulk_out == ARRAY_SIZE(epds->bulk_out)) + return; + dev_dbg(dev, "found bulk out endpoint %02x\n", addr); + epds->bulk_out[epds->num_bulk_out++] = epd; + } else if (usb_endpoint_is_int_in(epd)) { + if (epds->num_interrupt_in == ARRAY_SIZE(epds->interrupt_in)) + return; + dev_dbg(dev, "found interrupt in endpoint %02x\n", addr); + epds->interrupt_in[epds->num_interrupt_in++] = epd; + } else if (usb_endpoint_is_int_out(epd)) { + if (epds->num_interrupt_out == ARRAY_SIZE(epds->interrupt_out)) + return; + dev_dbg(dev, "found interrupt out endpoint %02x\n", addr); + epds->interrupt_out[epds->num_interrupt_out++] = epd; + } +} + +static void find_endpoints(struct usb_serial *serial, + struct usb_serial_endpoints *epds, + struct usb_interface *intf) +{ struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *epd; unsigned int i; - BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_in) < USB_MAXENDPOINTS / 2); - BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < USB_MAXENDPOINTS / 2); - BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_in) < USB_MAXENDPOINTS / 2); - BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_out) < USB_MAXENDPOINTS / 2); - - iface_desc = serial->interface->cur_altsetting; + iface_desc = intf->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { epd = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(epd)) { - dev_dbg(dev, "found bulk in on endpoint %u\n", i); - epds->bulk_in[epds->num_bulk_in++] = epd; - } else if (usb_endpoint_is_bulk_out(epd)) { - dev_dbg(dev, "found bulk out on endpoint %u\n", i); - epds->bulk_out[epds->num_bulk_out++] = epd; - } else if (usb_endpoint_is_int_in(epd)) { - dev_dbg(dev, "found interrupt in on endpoint %u\n", i); - epds->interrupt_in[epds->num_interrupt_in++] = epd; - } else if (usb_endpoint_is_int_out(epd)) { - dev_dbg(dev, "found interrupt out on endpoint %u\n", i); - epds->interrupt_out[epds->num_interrupt_out++] = epd; - } + store_endpoint(serial, epds, epd); } } @@ -906,7 +999,7 @@ static int usb_serial_probe(struct usb_interface *interface, if (retval) { dev_dbg(ddev, "sub driver rejected device\n"); - goto err_put_serial; + goto err_release_sibling; } } @@ -914,10 +1007,12 @@ static int usb_serial_probe(struct usb_interface *interface, epds = kzalloc(sizeof(*epds), GFP_KERNEL); if (!epds) { retval = -ENOMEM; - goto err_put_serial; + goto err_release_sibling; } - find_endpoints(serial, epds); + find_endpoints(serial, epds, interface); + if (serial->sibling) + find_endpoints(serial, epds, serial->sibling); if (epds->num_bulk_in < type->num_bulk_in || epds->num_bulk_out < type->num_bulk_out || @@ -1065,7 +1160,8 @@ exit: err_free_epds: kfree(epds); -err_put_serial: +err_release_sibling: + release_sibling(serial, interface); usb_serial_put(serial); err_put_module: module_put(type->driver.owner); @@ -1081,6 +1177,10 @@ static void usb_serial_disconnect(struct usb_interface *interface) struct usb_serial_port *port; struct tty_struct *tty; + /* sibling interface is cleaning up */ + if (!serial) + return; + usb_serial_console_disconnect(serial); mutex_lock(&serial->disc_mutex); @@ -1104,6 +1204,8 @@ static void usb_serial_disconnect(struct usb_interface *interface) if (serial->type->disconnect) serial->type->disconnect(serial); + release_sibling(serial, interface); + /* let the last holder of this object cause it to be cleaned up */ usb_serial_put(serial); dev_info(dev, "device disconnected\n"); @@ -1112,9 +1214,11 @@ static void usb_serial_disconnect(struct usb_interface *interface) int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) { struct usb_serial *serial = usb_get_intfdata(intf); - int i, r = 0; + int i, r; - serial->suspending = 1; + /* suspend when called for first sibling interface */ + if (serial->suspend_count++) + return 0; /* * serial->type->suspend() MUST return 0 in system sleep context, @@ -1124,15 +1228,15 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) if (serial->type->suspend) { r = serial->type->suspend(serial, message); if (r < 0) { - serial->suspending = 0; - goto err_out; + serial->suspend_count--; + return r; } } for (i = 0; i < serial->num_ports; ++i) usb_serial_port_poison_urbs(serial->port[i]); -err_out: - return r; + + return 0; } EXPORT_SYMBOL(usb_serial_suspend); @@ -1149,9 +1253,12 @@ int usb_serial_resume(struct usb_interface *intf) struct usb_serial *serial = usb_get_intfdata(intf); int rv; + /* resume when called for last sibling interface */ + if (--serial->suspend_count) + return 0; + usb_serial_unpoison_port_urbs(serial); - serial->suspending = 0; if (serial->type->resume) rv = serial->type->resume(serial); else @@ -1166,9 +1273,12 @@ static int usb_serial_reset_resume(struct usb_interface *intf) struct usb_serial *serial = usb_get_intfdata(intf); int rv; + /* resume when called for last sibling interface */ + if (--serial->suspend_count) + return 0; + usb_serial_unpoison_port_urbs(serial); - serial->suspending = 0; if (serial->type->reset_resume) { rv = serial->type->reset_resume(serial); } else { diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index 79dafd98e0a1832c2375efa503489d1df7a4cc16..b5331d03092fa42b49acd15267ec7eb82c66f043 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -15,10 +15,6 @@ extern int usb_wwan_write_room(struct tty_struct *tty); extern int usb_wwan_tiocmget(struct tty_struct *tty); extern int usb_wwan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -extern int usb_wwan_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss); -extern int usb_wwan_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss); extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 46d46a4f99c9fb22c8ecec66d2b5ba7bba2d26fc..3eb72c59ede6766551704146983af7992dc7ed24 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -132,51 +132,6 @@ int usb_wwan_tiocmset(struct tty_struct *tty, } EXPORT_SYMBOL(usb_wwan_tiocmset); -int usb_wwan_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->line = port->minor; - ss->port = port->port_number; - ss->baud_base = tty_get_baud_rate(port->port.tty); - ss->close_delay = port->port.close_delay / 10; - ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - port->port.closing_wait / 10; - return 0; -} -EXPORT_SYMBOL(usb_wwan_get_serial_info); - -int usb_wwan_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int closing_wait, close_delay; - int retval = 0; - - close_delay = ss->close_delay * 10; - closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; - - mutex_lock(&port->port.mutex); - - if (!capable(CAP_SYS_ADMIN)) { - if ((close_delay != port->port.close_delay) || - (closing_wait != port->port.closing_wait)) - retval = -EPERM; - else - retval = -EOPNOTSUPP; - } else { - port->port.close_delay = close_delay; - port->port.closing_wait = closing_wait; - } - - mutex_unlock(&port->port.mutex); - return retval; -} -EXPORT_SYMBOL(usb_wwan_set_serial_info); - int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index ccfd5ed652cdff080e2afb15220911f1e6e5dc13..5116ed9db3eb41e0bb1e4570a69b67af00c9392a 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -83,7 +83,7 @@ static void whiteheat_port_remove(struct usb_serial_port *port); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_get_serial(struct tty_struct *tty, +static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss); static void whiteheat_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); @@ -170,7 +170,6 @@ static int firm_report_tx_done(struct usb_serial_port *port); #define COMMAND_PORT 4 #define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ #define COMMAND_TIMEOUT_MS 2000 -#define CLOSING_DELAY (30 * HZ) /***************************************************************************** @@ -440,21 +439,9 @@ static int whiteheat_tiocmset(struct tty_struct *tty, } -static int whiteheat_get_serial(struct tty_struct *tty, - struct serial_struct *ss) +static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - - ss->type = PORT_16654; - ss->line = port->minor; - ss->port = port->port_number; - ss->xmit_fifo_size = kfifo_size(&port->write_fifo); - ss->custom_divisor = 0; ss->baud_base = 460800; - ss->close_delay = CLOSING_DELAY; - ss->closing_wait = CLOSING_DELAY; - - return 0; } diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 0ca04906da4bf2b59f9bf0b2139f1402dfbd14e1..6853cd56d8dce50c8d7377e6806d0eaada759add 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -3,6 +3,7 @@ * MaxLinear/Exar USB to Serial driver * * Copyright (c) 2020 Manivannan Sadhasivam <mani@kernel.org> + * Copyright (c) 2021 Johan Hovold <johan@kernel.org> * * Based on the initial driver written by Patong Yang: * @@ -16,6 +17,7 @@ #include <linux/slab.h> #include <linux/tty.h> #include <linux/usb.h> +#include <linux/usb/cdc.h> #include <linux/usb/serial.h> struct xr_txrx_clk_mask { @@ -28,10 +30,12 @@ struct xr_txrx_clk_mask { #define XR21V141X_MIN_SPEED 46U #define XR21V141X_MAX_SPEED XR_INT_OSC_HZ -/* USB Requests */ -#define XR21V141X_SET_REQ 0 -#define XR21V141X_GET_REQ 1 +/* XR21V141X register blocks */ +#define XR21V141X_UART_REG_BLOCK 0 +#define XR21V141X_UM_REG_BLOCK 4 +#define XR21V141X_UART_CUSTOM_BLOCK 0x66 +/* XR21V141X UART registers */ #define XR21V141X_CLOCK_DIVISOR_0 0x04 #define XR21V141X_CLOCK_DIVISOR_1 0x05 #define XR21V141X_CLOCK_DIVISOR_2 0x06 @@ -39,13 +43,9 @@ struct xr_txrx_clk_mask { #define XR21V141X_TX_CLOCK_MASK_1 0x08 #define XR21V141X_RX_CLOCK_MASK_0 0x09 #define XR21V141X_RX_CLOCK_MASK_1 0x0a +#define XR21V141X_REG_FORMAT 0x0b -/* XR21V141X register blocks */ -#define XR21V141X_UART_REG_BLOCK 0 -#define XR21V141X_UM_REG_BLOCK 4 -#define XR21V141X_UART_CUSTOM_BLOCK 0x66 - -/* XR21V141X UART Manager Registers */ +/* XR21V141X UART Manager registers */ #define XR21V141X_UM_FIFO_ENABLE_REG 0x10 #define XR21V141X_UM_ENABLE_TX_FIFO 0x01 #define XR21V141X_UM_ENABLE_RX_FIFO 0x02 @@ -53,72 +53,203 @@ struct xr_txrx_clk_mask { #define XR21V141X_UM_RX_FIFO_RESET 0x18 #define XR21V141X_UM_TX_FIFO_RESET 0x1c -#define XR21V141X_UART_ENABLE_TX 0x1 -#define XR21V141X_UART_ENABLE_RX 0x2 - -#define XR21V141X_UART_MODE_RI BIT(0) -#define XR21V141X_UART_MODE_CD BIT(1) -#define XR21V141X_UART_MODE_DSR BIT(2) -#define XR21V141X_UART_MODE_DTR BIT(3) -#define XR21V141X_UART_MODE_CTS BIT(4) -#define XR21V141X_UART_MODE_RTS BIT(5) - -#define XR21V141X_UART_BREAK_ON 0xff -#define XR21V141X_UART_BREAK_OFF 0 - -#define XR21V141X_UART_DATA_MASK GENMASK(3, 0) -#define XR21V141X_UART_DATA_7 0x7 -#define XR21V141X_UART_DATA_8 0x8 - -#define XR21V141X_UART_PARITY_MASK GENMASK(6, 4) -#define XR21V141X_UART_PARITY_SHIFT 4 -#define XR21V141X_UART_PARITY_NONE (0x0 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_ODD (0x1 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_EVEN (0x2 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_MARK (0x3 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_SPACE (0x4 << XR21V141X_UART_PARITY_SHIFT) - -#define XR21V141X_UART_STOP_MASK BIT(7) -#define XR21V141X_UART_STOP_SHIFT 7 -#define XR21V141X_UART_STOP_1 (0x0 << XR21V141X_UART_STOP_SHIFT) -#define XR21V141X_UART_STOP_2 (0x1 << XR21V141X_UART_STOP_SHIFT) - -#define XR21V141X_UART_FLOW_MODE_NONE 0x0 -#define XR21V141X_UART_FLOW_MODE_HW 0x1 -#define XR21V141X_UART_FLOW_MODE_SW 0x2 - -#define XR21V141X_UART_MODE_GPIO_MASK GENMASK(2, 0) -#define XR21V141X_UART_MODE_RTS_CTS 0x1 -#define XR21V141X_UART_MODE_DTR_DSR 0x2 -#define XR21V141X_UART_MODE_RS485 0x3 -#define XR21V141X_UART_MODE_RS485_ADDR 0x4 - -#define XR21V141X_REG_ENABLE 0x03 -#define XR21V141X_REG_FORMAT 0x0b -#define XR21V141X_REG_FLOW_CTRL 0x0c -#define XR21V141X_REG_XON_CHAR 0x10 -#define XR21V141X_REG_XOFF_CHAR 0x11 -#define XR21V141X_REG_LOOPBACK 0x12 -#define XR21V141X_REG_TX_BREAK 0x14 -#define XR21V141X_REG_RS845_DELAY 0x15 -#define XR21V141X_REG_GPIO_MODE 0x1a -#define XR21V141X_REG_GPIO_DIR 0x1b -#define XR21V141X_REG_GPIO_INT_MASK 0x1c -#define XR21V141X_REG_GPIO_SET 0x1d -#define XR21V141X_REG_GPIO_CLR 0x1e -#define XR21V141X_REG_GPIO_STATUS 0x1f - -static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val) +#define XR_UART_ENABLE_TX 0x1 +#define XR_UART_ENABLE_RX 0x2 + +#define XR_GPIO_RI BIT(0) +#define XR_GPIO_CD BIT(1) +#define XR_GPIO_DSR BIT(2) +#define XR_GPIO_DTR BIT(3) +#define XR_GPIO_CTS BIT(4) +#define XR_GPIO_RTS BIT(5) +#define XR_GPIO_CLK BIT(6) +#define XR_GPIO_XEN BIT(7) +#define XR_GPIO_TXT BIT(8) +#define XR_GPIO_RXT BIT(9) + +#define XR_UART_DATA_MASK GENMASK(3, 0) +#define XR_UART_DATA_7 0x7 +#define XR_UART_DATA_8 0x8 + +#define XR_UART_PARITY_MASK GENMASK(6, 4) +#define XR_UART_PARITY_SHIFT 4 +#define XR_UART_PARITY_NONE (0x0 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_ODD (0x1 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_EVEN (0x2 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_MARK (0x3 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_SPACE (0x4 << XR_UART_PARITY_SHIFT) + +#define XR_UART_STOP_MASK BIT(7) +#define XR_UART_STOP_SHIFT 7 +#define XR_UART_STOP_1 (0x0 << XR_UART_STOP_SHIFT) +#define XR_UART_STOP_2 (0x1 << XR_UART_STOP_SHIFT) + +#define XR_UART_FLOW_MODE_NONE 0x0 +#define XR_UART_FLOW_MODE_HW 0x1 +#define XR_UART_FLOW_MODE_SW 0x2 + +#define XR_GPIO_MODE_SEL_MASK GENMASK(2, 0) +#define XR_GPIO_MODE_SEL_RTS_CTS 0x1 +#define XR_GPIO_MODE_SEL_DTR_DSR 0x2 +#define XR_GPIO_MODE_SEL_RS485 0x3 +#define XR_GPIO_MODE_SEL_RS485_ADDR 0x4 +#define XR_GPIO_MODE_TX_TOGGLE 0x100 +#define XR_GPIO_MODE_RX_TOGGLE 0x200 + +#define XR_FIFO_RESET 0x1 + +#define XR_CUSTOM_DRIVER_ACTIVE 0x1 + +static int xr21v141x_uart_enable(struct usb_serial_port *port); +static int xr21v141x_uart_disable(struct usb_serial_port *port); +static int xr21v141x_fifo_reset(struct usb_serial_port *port); +static void xr21v141x_set_line_settings(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios); + +struct xr_type { + int reg_width; + u8 reg_recipient; + u8 set_reg; + u8 get_reg; + + u16 uart_enable; + u16 flow_control; + u16 xon_char; + u16 xoff_char; + u16 tx_break; + u16 gpio_mode; + u16 gpio_direction; + u16 gpio_set; + u16 gpio_clear; + u16 gpio_status; + u16 tx_fifo_reset; + u16 rx_fifo_reset; + u16 custom_driver; + + bool have_5_6_bit_mode; + bool have_xmit_toggle; + + int (*enable)(struct usb_serial_port *port); + int (*disable)(struct usb_serial_port *port); + int (*fifo_reset)(struct usb_serial_port *port); + void (*set_line_settings)(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios); +}; + +enum xr_type_id { + XR21V141X, + XR21B142X, + XR21B1411, + XR2280X, + XR_TYPE_COUNT, +}; + +static const struct xr_type xr_types[] = { + [XR21V141X] = { + .reg_width = 8, + .reg_recipient = USB_RECIP_DEVICE, + .set_reg = 0x00, + .get_reg = 0x01, + + .uart_enable = 0x03, + .flow_control = 0x0c, + .xon_char = 0x10, + .xoff_char = 0x11, + .tx_break = 0x14, + .gpio_mode = 0x1a, + .gpio_direction = 0x1b, + .gpio_set = 0x1d, + .gpio_clear = 0x1e, + .gpio_status = 0x1f, + + .enable = xr21v141x_uart_enable, + .disable = xr21v141x_uart_disable, + .fifo_reset = xr21v141x_fifo_reset, + .set_line_settings = xr21v141x_set_line_settings, + }, + [XR21B142X] = { + .reg_width = 16, + .reg_recipient = USB_RECIP_INTERFACE, + .set_reg = 0x00, + .get_reg = 0x00, + + .uart_enable = 0x00, + .flow_control = 0x06, + .xon_char = 0x07, + .xoff_char = 0x08, + .tx_break = 0x0a, + .gpio_mode = 0x0c, + .gpio_direction = 0x0d, + .gpio_set = 0x0e, + .gpio_clear = 0x0f, + .gpio_status = 0x10, + .tx_fifo_reset = 0x40, + .rx_fifo_reset = 0x43, + .custom_driver = 0x60, + + .have_5_6_bit_mode = true, + .have_xmit_toggle = true, + }, + [XR21B1411] = { + .reg_width = 12, + .reg_recipient = USB_RECIP_DEVICE, + .set_reg = 0x00, + .get_reg = 0x01, + + .uart_enable = 0xc00, + .flow_control = 0xc06, + .xon_char = 0xc07, + .xoff_char = 0xc08, + .tx_break = 0xc0a, + .gpio_mode = 0xc0c, + .gpio_direction = 0xc0d, + .gpio_set = 0xc0e, + .gpio_clear = 0xc0f, + .gpio_status = 0xc10, + .tx_fifo_reset = 0xc80, + .rx_fifo_reset = 0xcc0, + .custom_driver = 0x20d, + }, + [XR2280X] = { + .reg_width = 16, + .reg_recipient = USB_RECIP_DEVICE, + .set_reg = 0x05, + .get_reg = 0x05, + + .uart_enable = 0x40, + .flow_control = 0x46, + .xon_char = 0x47, + .xoff_char = 0x48, + .tx_break = 0x4a, + .gpio_mode = 0x4c, + .gpio_direction = 0x4d, + .gpio_set = 0x4e, + .gpio_clear = 0x4f, + .gpio_status = 0x50, + .tx_fifo_reset = 0x60, + .rx_fifo_reset = 0x63, + .custom_driver = 0x81, + }, +}; + +struct xr_data { + const struct xr_type *type; + u8 channel; /* zero-based index or interface number */ +}; + +static int xr_set_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 val) { + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; struct usb_serial *serial = port->serial; int ret; - ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - XR21V141X_SET_REQ, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, reg | (block << 8), NULL, 0, - USB_CTRL_SET_TIMEOUT); + ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + type->set_reg, + USB_DIR_OUT | USB_TYPE_VENDOR | type->reg_recipient, + val, (channel << 8) | reg, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (ret < 0) { dev_err(&port->dev, "Failed to set reg 0x%02x: %d\n", reg, ret); return ret; @@ -127,24 +258,33 @@ static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val) return 0; } -static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val) +static int xr_get_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 *val) { + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; struct usb_serial *serial = port->serial; u8 *dmabuf; - int ret; + int ret, len; + + if (type->reg_width == 8) + len = 1; + else + len = 2; - dmabuf = kmalloc(1, GFP_KERNEL); + dmabuf = kmalloc(len, GFP_KERNEL); if (!dmabuf) return -ENOMEM; - ret = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - XR21V141X_GET_REQ, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg | (block << 8), dmabuf, 1, - USB_CTRL_GET_TIMEOUT); - if (ret == 1) { - *val = *dmabuf; + ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + type->get_reg, + USB_DIR_IN | USB_TYPE_VENDOR | type->reg_recipient, + 0, (channel << 8) | reg, dmabuf, len, + USB_CTRL_GET_TIMEOUT); + if (ret == len) { + if (len == 2) + *val = le16_to_cpup((__le16 *)dmabuf); + else + *val = *dmabuf; ret = 0; } else { dev_err(&port->dev, "Failed to get reg 0x%02x: %d\n", reg, ret); @@ -157,21 +297,45 @@ static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val) return ret; } -static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u8 val) +static int xr_set_reg_uart(struct usb_serial_port *port, u16 reg, u16 val) { - return xr_set_reg(port, XR21V141X_UART_REG_BLOCK, reg, val); + struct xr_data *data = usb_get_serial_port_data(port); + + return xr_set_reg(port, data->channel, reg, val); } -static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u8 *val) +static int xr_get_reg_uart(struct usb_serial_port *port, u16 reg, u16 *val) { - return xr_get_reg(port, XR21V141X_UART_REG_BLOCK, reg, val); + struct xr_data *data = usb_get_serial_port_data(port); + + return xr_get_reg(port, data->channel, reg, val); } -static int xr_set_reg_um(struct usb_serial_port *port, u8 reg, u8 val) +static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) { + struct xr_data *data = usb_get_serial_port_data(port); + u8 reg; + + reg = reg_base + data->channel; + return xr_set_reg(port, XR21V141X_UM_REG_BLOCK, reg, val); } +static int __xr_uart_enable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + return xr_set_reg_uart(port, data->type->uart_enable, + XR_UART_ENABLE_TX | XR_UART_ENABLE_RX); +} + +static int __xr_uart_disable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + return xr_set_reg_uart(port, data->type->uart_enable, 0); +} + /* * According to datasheet, below is the recommended sequence for enabling UART * module in XR21V141X: @@ -180,7 +344,7 @@ static int xr_set_reg_um(struct usb_serial_port *port, u8 reg, u8 val) * Enable Tx and Rx * Enable Rx FIFO */ -static int xr_uart_enable(struct usb_serial_port *port) +static int xr21v141x_uart_enable(struct usb_serial_port *port) { int ret; @@ -189,25 +353,23 @@ static int xr_uart_enable(struct usb_serial_port *port) if (ret) return ret; - ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, - XR21V141X_UART_ENABLE_TX | XR21V141X_UART_ENABLE_RX); + ret = __xr_uart_enable(port); if (ret) return ret; ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO); - if (ret) - xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0); + __xr_uart_disable(port); return ret; } -static int xr_uart_disable(struct usb_serial_port *port) +static int xr21v141x_uart_disable(struct usb_serial_port *port) { int ret; - ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0); + ret = __xr_uart_disable(port); if (ret) return ret; @@ -216,13 +378,68 @@ static int xr_uart_disable(struct usb_serial_port *port) return ret; } +static int xr_uart_enable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + if (data->type->enable) + return data->type->enable(port); + + return __xr_uart_enable(port); +} + +static int xr_uart_disable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + if (data->type->disable) + return data->type->disable(port); + + return __xr_uart_disable(port); +} + +static int xr21v141x_fifo_reset(struct usb_serial_port *port) +{ + int ret; + + ret = xr_set_reg_um(port, XR21V141X_UM_TX_FIFO_RESET, XR_FIFO_RESET); + if (ret) + return ret; + + ret = xr_set_reg_um(port, XR21V141X_UM_RX_FIFO_RESET, XR_FIFO_RESET); + if (ret) + return ret; + + return 0; +} + +static int xr_fifo_reset(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + int ret; + + if (data->type->fifo_reset) + return data->type->fifo_reset(port); + + ret = xr_set_reg_uart(port, data->type->tx_fifo_reset, XR_FIFO_RESET); + if (ret) + return ret; + + ret = xr_set_reg_uart(port, data->type->rx_fifo_reset, XR_FIFO_RESET); + if (ret) + return ret; + + return 0; +} + static int xr_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - u8 status; + struct xr_data *data = usb_get_serial_port_data(port); + u16 status; int ret; - ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_STATUS, &status); + ret = xr_get_reg_uart(port, data->type->gpio_status, &status); if (ret) return ret; @@ -230,12 +447,12 @@ static int xr_tiocmget(struct tty_struct *tty) * Modem control pins are active low, so reading '0' means it is active * and '1' means not active. */ - ret = ((status & XR21V141X_UART_MODE_DTR) ? 0 : TIOCM_DTR) | - ((status & XR21V141X_UART_MODE_RTS) ? 0 : TIOCM_RTS) | - ((status & XR21V141X_UART_MODE_CTS) ? 0 : TIOCM_CTS) | - ((status & XR21V141X_UART_MODE_DSR) ? 0 : TIOCM_DSR) | - ((status & XR21V141X_UART_MODE_RI) ? 0 : TIOCM_RI) | - ((status & XR21V141X_UART_MODE_CD) ? 0 : TIOCM_CD); + ret = ((status & XR_GPIO_DTR) ? 0 : TIOCM_DTR) | + ((status & XR_GPIO_RTS) ? 0 : TIOCM_RTS) | + ((status & XR_GPIO_CTS) ? 0 : TIOCM_CTS) | + ((status & XR_GPIO_DSR) ? 0 : TIOCM_DSR) | + ((status & XR_GPIO_RI) ? 0 : TIOCM_RI) | + ((status & XR_GPIO_CD) ? 0 : TIOCM_CD); return ret; } @@ -243,26 +460,28 @@ static int xr_tiocmget(struct tty_struct *tty) static int xr_tiocmset_port(struct usb_serial_port *port, unsigned int set, unsigned int clear) { - u8 gpio_set = 0; - u8 gpio_clr = 0; + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; + u16 gpio_set = 0; + u16 gpio_clr = 0; int ret = 0; /* Modem control pins are active low, so set & clr are swapped */ if (set & TIOCM_RTS) - gpio_clr |= XR21V141X_UART_MODE_RTS; + gpio_clr |= XR_GPIO_RTS; if (set & TIOCM_DTR) - gpio_clr |= XR21V141X_UART_MODE_DTR; + gpio_clr |= XR_GPIO_DTR; if (clear & TIOCM_RTS) - gpio_set |= XR21V141X_UART_MODE_RTS; + gpio_set |= XR_GPIO_RTS; if (clear & TIOCM_DTR) - gpio_set |= XR21V141X_UART_MODE_DTR; + gpio_set |= XR_GPIO_DTR; /* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */ if (gpio_clr) - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_CLR, gpio_clr); + ret = xr_set_reg_uart(port, type->gpio_clear, gpio_clr); if (gpio_set) - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, gpio_set); + ret = xr_set_reg_uart(port, type->gpio_set, gpio_set); return ret; } @@ -286,16 +505,18 @@ static void xr_dtr_rts(struct usb_serial_port *port, int on) static void xr_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - u8 state; + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; + u16 state; if (break_state == 0) - state = XR21V141X_UART_BREAK_OFF; + state = 0; else - state = XR21V141X_UART_BREAK_ON; + state = GENMASK(type->reg_width - 1, 0); + + dev_dbg(&port->dev, "Turning break %s\n", state == 0 ? "off" : "on"); - dev_dbg(&port->dev, "Turning break %s\n", - state == XR21V141X_UART_BREAK_OFF ? "off" : "on"); - xr_set_reg_uart(port, XR21V141X_REG_TX_BREAK, state); + xr_set_reg_uart(port, type->tx_break, state); } /* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */ @@ -334,8 +555,7 @@ static const struct xr_txrx_clk_mask xr21v141x_txrx_clk_masks[] = { { 0xfff, 0xffe, 0xffd }, }; -static int xr_set_baudrate(struct tty_struct *tty, - struct usb_serial_port *port) +static int xr21v141x_set_baudrate(struct tty_struct *tty, struct usb_serial_port *port) { u32 divisor, baud, idx; u16 tx_mask, rx_mask; @@ -405,43 +625,47 @@ static void xr_set_flow_mode(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - u8 flow, gpio_mode; + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; + u16 flow, gpio_mode; int ret; - ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_MODE, &gpio_mode); + ret = xr_get_reg_uart(port, type->gpio_mode, &gpio_mode); if (ret) return; + /* + * According to the datasheets, the UART needs to be disabled while + * writing to the FLOW_CONTROL register (XR21V141X), or any register + * but GPIO_SET, GPIO_CLEAR, TX_BREAK and ERROR_STATUS (XR21B142X). + */ + xr_uart_disable(port); + /* Set GPIO mode for controlling the pins manually by default. */ - gpio_mode &= ~XR21V141X_UART_MODE_GPIO_MASK; + gpio_mode &= ~XR_GPIO_MODE_SEL_MASK; if (C_CRTSCTS(tty) && C_BAUD(tty) != B0) { dev_dbg(&port->dev, "Enabling hardware flow ctrl\n"); - gpio_mode |= XR21V141X_UART_MODE_RTS_CTS; - flow = XR21V141X_UART_FLOW_MODE_HW; + gpio_mode |= XR_GPIO_MODE_SEL_RTS_CTS; + flow = XR_UART_FLOW_MODE_HW; } else if (I_IXON(tty)) { u8 start_char = START_CHAR(tty); u8 stop_char = STOP_CHAR(tty); dev_dbg(&port->dev, "Enabling sw flow ctrl\n"); - flow = XR21V141X_UART_FLOW_MODE_SW; + flow = XR_UART_FLOW_MODE_SW; - xr_set_reg_uart(port, XR21V141X_REG_XON_CHAR, start_char); - xr_set_reg_uart(port, XR21V141X_REG_XOFF_CHAR, stop_char); + xr_set_reg_uart(port, type->xon_char, start_char); + xr_set_reg_uart(port, type->xoff_char, stop_char); } else { dev_dbg(&port->dev, "Disabling flow ctrl\n"); - flow = XR21V141X_UART_FLOW_MODE_NONE; + flow = XR_UART_FLOW_MODE_NONE; } - /* - * As per the datasheet, UART needs to be disabled while writing to - * FLOW_CONTROL register. - */ - xr_uart_disable(port); - xr_set_reg_uart(port, XR21V141X_REG_FLOW_CTRL, flow); - xr_uart_enable(port); + xr_set_reg_uart(port, type->flow_control, flow); + xr_set_reg_uart(port, type->gpio_mode, gpio_mode); - xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, gpio_mode); + xr_uart_enable(port); if (C_BAUD(tty) == B0) xr_dtr_rts(port, 0); @@ -449,16 +673,15 @@ static void xr_set_flow_mode(struct tty_struct *tty, xr_dtr_rts(port, 1); } -static void xr_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) +static void xr21v141x_set_line_settings(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) { struct ktermios *termios = &tty->termios; u8 bits = 0; int ret; if (!old_termios || (tty->termios.c_ospeed != old_termios->c_ospeed)) - xr_set_baudrate(tty, port); + xr21v141x_set_baudrate(tty, port); switch (C_CSIZE(tty)) { case CS5: @@ -468,61 +691,154 @@ static void xr_set_termios(struct tty_struct *tty, if (old_termios) termios->c_cflag |= old_termios->c_cflag & CSIZE; else - bits |= XR21V141X_UART_DATA_8; + termios->c_cflag |= CS8; + + if (C_CSIZE(tty) == CS7) + bits |= XR_UART_DATA_7; + else + bits |= XR_UART_DATA_8; break; case CS7: - bits |= XR21V141X_UART_DATA_7; + bits |= XR_UART_DATA_7; break; case CS8: default: - bits |= XR21V141X_UART_DATA_8; + bits |= XR_UART_DATA_8; break; } if (C_PARENB(tty)) { if (C_CMSPAR(tty)) { if (C_PARODD(tty)) - bits |= XR21V141X_UART_PARITY_MARK; + bits |= XR_UART_PARITY_MARK; else - bits |= XR21V141X_UART_PARITY_SPACE; + bits |= XR_UART_PARITY_SPACE; } else { if (C_PARODD(tty)) - bits |= XR21V141X_UART_PARITY_ODD; + bits |= XR_UART_PARITY_ODD; else - bits |= XR21V141X_UART_PARITY_EVEN; + bits |= XR_UART_PARITY_EVEN; } } if (C_CSTOPB(tty)) - bits |= XR21V141X_UART_STOP_2; + bits |= XR_UART_STOP_2; else - bits |= XR21V141X_UART_STOP_1; + bits |= XR_UART_STOP_1; ret = xr_set_reg_uart(port, XR21V141X_REG_FORMAT, bits); if (ret) return; +} + +static void xr_cdc_set_line_coding(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + struct xr_data *data = usb_get_serial_port_data(port); + struct usb_host_interface *alt = port->serial->interface->cur_altsetting; + struct usb_device *udev = port->serial->dev; + struct usb_cdc_line_coding *lc; + int ret; + + lc = kzalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) + return; + + if (tty->termios.c_ospeed) + lc->dwDTERate = cpu_to_le32(tty->termios.c_ospeed); + else if (old_termios) + lc->dwDTERate = cpu_to_le32(old_termios->c_ospeed); + else + lc->dwDTERate = cpu_to_le32(9600); + + if (C_CSTOPB(tty)) + lc->bCharFormat = USB_CDC_2_STOP_BITS; + else + lc->bCharFormat = USB_CDC_1_STOP_BITS; + + if (C_PARENB(tty)) { + if (C_CMSPAR(tty)) { + if (C_PARODD(tty)) + lc->bParityType = USB_CDC_MARK_PARITY; + else + lc->bParityType = USB_CDC_SPACE_PARITY; + } else { + if (C_PARODD(tty)) + lc->bParityType = USB_CDC_ODD_PARITY; + else + lc->bParityType = USB_CDC_EVEN_PARITY; + } + } else { + lc->bParityType = USB_CDC_NO_PARITY; + } + + if (!data->type->have_5_6_bit_mode && + (C_CSIZE(tty) == CS5 || C_CSIZE(tty) == CS6)) { + tty->termios.c_cflag &= ~CSIZE; + if (old_termios) + tty->termios.c_cflag |= old_termios->c_cflag & CSIZE; + else + tty->termios.c_cflag |= CS8; + } + + switch (C_CSIZE(tty)) { + case CS5: + lc->bDataBits = 5; + break; + case CS6: + lc->bDataBits = 6; + break; + case CS7: + lc->bDataBits = 7; + break; + case CS8: + default: + lc->bDataBits = 8; + break; + } + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_CDC_REQ_SET_LINE_CODING, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, alt->desc.bInterfaceNumber, + lc, sizeof(*lc), USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_err(&port->dev, "Failed to set line coding: %d\n", ret); + + kfree(lc); +} + +static void xr_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + /* + * XR21V141X does not have a CUSTOM_DRIVER flag and always enters CDC + * mode upon receiving CDC requests. + */ + if (data->type->set_line_settings) + data->type->set_line_settings(tty, port, old_termios); + else + xr_cdc_set_line_coding(tty, port, old_termios); xr_set_flow_mode(tty, port, old_termios); } static int xr_open(struct tty_struct *tty, struct usb_serial_port *port) { - u8 gpio_dir; int ret; + ret = xr_fifo_reset(port); + if (ret) + return ret; + ret = xr_uart_enable(port); if (ret) { dev_err(&port->dev, "Failed to enable UART\n"); return ret; } - /* - * Configure DTR and RTS as outputs and RI, CD, DSR and CTS as - * inputs. - */ - gpio_dir = XR21V141X_UART_MODE_DTR | XR21V141X_UART_MODE_RTS; - xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, gpio_dir); - /* Setup termios */ if (tty) xr_set_termios(tty, port, NULL); @@ -545,15 +861,133 @@ static void xr_close(struct usb_serial_port *port) static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) { - /* Don't bind to control interface */ - if (serial->interface->cur_altsetting->desc.bInterfaceNumber == 0) + struct usb_interface *control = serial->interface; + struct usb_host_interface *alt = control->cur_altsetting; + struct usb_cdc_parsed_header hdrs; + struct usb_cdc_union_desc *desc; + struct usb_interface *data; + int ret; + + ret = cdc_parse_cdc_header(&hdrs, control, alt->extra, alt->extralen); + if (ret < 0) + return -ENODEV; + + desc = hdrs.usb_cdc_union_desc; + if (!desc) + return -ENODEV; + + data = usb_ifnum_to_if(serial->dev, desc->bSlaveInterface0); + if (!data) return -ENODEV; + ret = usb_serial_claim_interface(serial, data); + if (ret) + return ret; + + usb_set_serial_data(serial, (void *)id->driver_info); + + return 0; +} + +static int xr_gpio_init(struct usb_serial_port *port, const struct xr_type *type) +{ + u16 mask, mode; + int ret; + + /* + * Configure all pins as GPIO except for Receive and Transmit Toggle. + */ + mode = 0; + if (type->have_xmit_toggle) + mode |= XR_GPIO_MODE_RX_TOGGLE | XR_GPIO_MODE_TX_TOGGLE; + + ret = xr_set_reg_uart(port, type->gpio_mode, mode); + if (ret) + return ret; + + /* + * Configure DTR and RTS as outputs and make sure they are deasserted + * (active low), and configure RI, CD, DSR and CTS as inputs. + */ + mask = XR_GPIO_DTR | XR_GPIO_RTS; + ret = xr_set_reg_uart(port, type->gpio_direction, mask); + if (ret) + return ret; + + ret = xr_set_reg_uart(port, type->gpio_set, mask); + if (ret) + return ret; + return 0; } +static int xr_port_probe(struct usb_serial_port *port) +{ + struct usb_interface_descriptor *desc; + const struct xr_type *type; + struct xr_data *data; + enum xr_type_id type_id; + int ret; + + type_id = (int)(unsigned long)usb_get_serial_data(port->serial); + type = &xr_types[type_id]; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->type = type; + + desc = &port->serial->interface->cur_altsetting->desc; + if (type_id == XR21V141X) + data->channel = desc->bInterfaceNumber / 2; + else + data->channel = desc->bInterfaceNumber; + + usb_set_serial_port_data(port, data); + + if (type->custom_driver) { + ret = xr_set_reg_uart(port, type->custom_driver, + XR_CUSTOM_DRIVER_ACTIVE); + if (ret) + goto err_free; + } + + ret = xr_gpio_init(port, type); + if (ret) + goto err_free; + + return 0; + +err_free: + kfree(data); + + return ret; +} + +static void xr_port_remove(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + kfree(data); +} + +#define XR_DEVICE(vid, pid, type) \ + USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_COMM), \ + .driver_info = (type) + static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x04e2, 0x1410) }, /* XR21V141X */ + { XR_DEVICE(0x04e2, 0x1400, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1401, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1402, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1403, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1410, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1411, XR21B1411) }, + { XR_DEVICE(0x04e2, 0x1412, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1414, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1420, XR21B142X) }, + { XR_DEVICE(0x04e2, 0x1422, XR21B142X) }, + { XR_DEVICE(0x04e2, 0x1424, XR21B142X) }, { } }; MODULE_DEVICE_TABLE(usb, id_table); @@ -566,6 +1000,8 @@ static struct usb_serial_driver xr_device = { .id_table = id_table, .num_ports = 1, .probe = xr_probe, + .port_probe = xr_port_probe, + .port_remove = xr_port_remove, .open = xr_open, .close = xr_close, .break_ctl = xr_break_ctl, diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 588818483f4bd9950ee344e8b87a119e87e9be82..bcc4a2fad863be881d940926983fa626174e7c99 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -294,7 +294,6 @@ static int datafab_write_data(struct us_data *us, if (reply[0] != 0x50 && reply[1] != 0) { usb_stor_dbg(us, "Gah! write return code: %02x %02x\n", reply[0], reply[1]); - result = USB_STOR_TRANSPORT_ERROR; goto leave; } diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 270e81c087e925cdc968238d3a2f8d9daee59519..a0418f23b4aae298f44a87aa90744b0a82432858 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -50,6 +50,8 @@ source "drivers/usb/typec/tcpm/Kconfig" source "drivers/usb/typec/ucsi/Kconfig" +source "drivers/usb/typec/tipd/Kconfig" + config TYPEC_HD3SS3220 tristate "TI HD3SS3220 Type-C DRP Port controller driver" depends on I2C @@ -61,19 +63,6 @@ config TYPEC_HD3SS3220 If you choose to build this driver as a dynamically linked module, the module will be called hd3ss3220.ko. -config TYPEC_TPS6598X - tristate "TI TPS6598x USB Power Delivery controller driver" - depends on I2C - select POWER_SUPPLY - select REGMAP_I2C - select USB_ROLE_SWITCH - help - Say Y or M here if your system has TI TPS65982 or TPS65983 USB Power - Delivery controller. - - If you choose to build this driver as a dynamically linked module, the - module will be called tps6598x.ko. - config TYPEC_STUSB160X tristate "STMicroelectronics STUSB160x Type-C controller driver" depends on I2C diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index d03b48c4b864ff330edbe628d340424d07713e18..a0adb8947a3014b2a39af804b8f234aacb5d5603 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -1,11 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TYPEC) += typec.o -typec-y := class.o mux.o bus.o +typec-y := class.o mux.o bus.o port-mapper.o obj-$(CONFIG_TYPEC) += altmodes/ obj-$(CONFIG_TYPEC_TCPM) += tcpm/ obj-$(CONFIG_TYPEC_UCSI) += ucsi/ +obj-$(CONFIG_TYPEC_TPS6598X) += tipd/ obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o -obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom-pmic-typec.o obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o obj-$(CONFIG_TYPEC) += mux/ diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c index e8ddb81cb6df4a23d537955acc625b08a2612152..7f3c9a8e2bf0820d1dd8fac59ad47858d9f4fcb5 100644 --- a/drivers/usb/typec/bus.c +++ b/drivers/usb/typec/bus.c @@ -9,6 +9,8 @@ #include <linux/usb/pd_vdo.h> #include "bus.h" +#include "class.h" +#include "mux.h" static inline int typec_altmode_set_mux(struct altmode *alt, unsigned long conf, void *data) diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h index 8ba8112d2740d4a0c2d93bd316215689befdf171..56dec268d4dd90aea0e9c99a55923980344b4c9a 100644 --- a/drivers/usb/typec/bus.h +++ b/drivers/usb/typec/bus.h @@ -4,9 +4,9 @@ #define __USB_TYPEC_ALTMODE_H__ #include <linux/usb/typec_altmode.h> -#include <linux/usb/typec_mux.h> struct bus_type; +struct typec_mux; struct altmode { unsigned int id; @@ -28,24 +28,7 @@ struct altmode { extern struct bus_type typec_bus; extern const struct device_type typec_altmode_dev_type; -extern const struct device_type typec_port_dev_type; #define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type) -#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type) - -extern struct class typec_mux_class; - -struct typec_switch { - struct device dev; - typec_switch_set_fn_t set; -}; - -struct typec_mux { - struct device dev; - typec_mux_set_fn_t set; -}; - -#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev) -#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev) #endif /* __USB_TYPEC_ALTMODE_H__ */ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 45f0bf65e9aba8f700ae93faaf961a4d6293e3a3..b9429c9f65f6c27eb14d671559aa7a913d97c681 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -6,78 +6,23 @@ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> */ -#include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/slab.h> #include <linux/usb/pd_vdo.h> +#include <linux/usb/typec_mux.h> #include "bus.h" +#include "class.h" -struct typec_plug { - struct device dev; - enum typec_plug_index index; - struct ida mode_ids; - int num_altmodes; -}; - -struct typec_cable { - struct device dev; - enum typec_plug_type type; - struct usb_pd_identity *identity; - unsigned int active:1; - u16 pd_revision; /* 0300H = "3.0" */ -}; - -struct typec_partner { - struct device dev; - unsigned int usb_pd:1; - struct usb_pd_identity *identity; - enum typec_accessory accessory; - struct ida mode_ids; - int num_altmodes; - u16 pd_revision; /* 0300H = "3.0" */ - enum usb_pd_svdm_ver svdm_version; -}; +static DEFINE_IDA(typec_index_ida); -struct typec_port { - unsigned int id; - struct device dev; - struct ida mode_ids; - - int prefer_role; - enum typec_data_role data_role; - enum typec_role pwr_role; - enum typec_role vconn_role; - enum typec_pwr_opmode pwr_opmode; - enum typec_port_type port_type; - struct mutex port_type_lock; - - enum typec_orientation orientation; - struct typec_switch *sw; - struct typec_mux *mux; - - const struct typec_capability *cap; - const struct typec_operations *ops; +struct class typec_class = { + .name = "typec", + .owner = THIS_MODULE, }; -#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev) -#define to_typec_plug(_dev_) container_of(_dev_, struct typec_plug, dev) -#define to_typec_cable(_dev_) container_of(_dev_, struct typec_cable, dev) -#define to_typec_partner(_dev_) container_of(_dev_, struct typec_partner, dev) - -static const struct device_type typec_partner_dev_type; -static const struct device_type typec_cable_dev_type; -static const struct device_type typec_plug_dev_type; - -#define is_typec_partner(_dev_) (_dev_->type == &typec_partner_dev_type) -#define is_typec_cable(_dev_) (_dev_->type == &typec_cable_dev_type) -#define is_typec_plug(_dev_) (_dev_->type == &typec_plug_dev_type) - -static DEFINE_IDA(typec_index_ida); -static struct class *typec_class; - /* ------------------------------------------------------------------------- */ /* Common attributes */ @@ -610,7 +555,7 @@ typec_register_altmode(struct device *parent, /* Plug alt modes need a class to generate udev events. */ if (is_typec_plug(parent)) - alt->adev.dev.class = typec_class; + alt->adev.dev.class = &typec_class; ret = device_register(&alt->adev.dev); if (ret) { @@ -726,7 +671,7 @@ static void typec_partner_release(struct device *dev) kfree(partner); } -static const struct device_type typec_partner_dev_type = { +const struct device_type typec_partner_dev_type = { .name = "typec_partner", .groups = typec_partner_groups, .release = typec_partner_release, @@ -874,7 +819,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port, partner->identity = desc->identity; } - partner->dev.class = typec_class; + partner->dev.class = &typec_class; partner->dev.parent = &port->dev; partner->dev.type = &typec_partner_dev_type; dev_set_name(&partner->dev, "%s-partner", dev_name(&port->dev)); @@ -941,7 +886,7 @@ static const struct attribute_group *typec_plug_groups[] = { NULL }; -static const struct device_type typec_plug_dev_type = { +const struct device_type typec_plug_dev_type = { .name = "typec_plug", .groups = typec_plug_groups, .release = typec_plug_release, @@ -1026,7 +971,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable, ida_init(&plug->mode_ids); plug->num_altmodes = -1; plug->index = desc->index; - plug->dev.class = typec_class; + plug->dev.class = &typec_class; plug->dev.parent = &cable->dev; plug->dev.type = &typec_plug_dev_type; dev_set_name(&plug->dev, "%s-%s", dev_name(cable->dev.parent), name); @@ -1089,7 +1034,7 @@ static void typec_cable_release(struct device *dev) kfree(cable); } -static const struct device_type typec_cable_dev_type = { +const struct device_type typec_cable_dev_type = { .name = "typec_cable", .groups = typec_cable_groups, .release = typec_cable_release, @@ -1191,7 +1136,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port, cable->identity = desc->identity; } - cable->dev.class = typec_class; + cable->dev.class = &typec_class; cable->dev.parent = &port->dev; cable->dev.type = &typec_cable_dev_type; dev_set_name(&cable->dev, "%s-cable", dev_name(&port->dev)); @@ -1978,6 +1923,60 @@ typec_port_register_altmode(struct typec_port *port, } EXPORT_SYMBOL_GPL(typec_port_register_altmode); +void typec_port_register_altmodes(struct typec_port *port, + const struct typec_altmode_ops *ops, void *drvdata, + struct typec_altmode **altmodes, size_t n) +{ + struct fwnode_handle *altmodes_node, *child; + struct typec_altmode_desc desc; + struct typec_altmode *alt; + size_t index = 0; + u32 svid, vdo; + int ret; + + altmodes_node = device_get_named_child_node(&port->dev, "altmodes"); + if (!altmodes_node) + return; /* No altmodes specified */ + + fwnode_for_each_child_node(altmodes_node, child) { + ret = fwnode_property_read_u32(child, "svid", &svid); + if (ret) { + dev_err(&port->dev, "Error reading svid for altmode %s\n", + fwnode_get_name(child)); + continue; + } + + ret = fwnode_property_read_u32(child, "vdo", &vdo); + if (ret) { + dev_err(&port->dev, "Error reading vdo for altmode %s\n", + fwnode_get_name(child)); + continue; + } + + if (index >= n) { + dev_err(&port->dev, "Error not enough space for altmode %s\n", + fwnode_get_name(child)); + continue; + } + + desc.svid = svid; + desc.vdo = vdo; + desc.mode = index + 1; + alt = typec_port_register_altmode(port, &desc); + if (IS_ERR(alt)) { + dev_err(&port->dev, "Error registering altmode %s\n", + fwnode_get_name(child)); + continue; + } + + alt->ops = ops; + typec_altmode_set_drvdata(alt, drvdata); + altmodes[index] = alt; + index++; + } +} +EXPORT_SYMBOL_GPL(typec_port_register_altmodes); + /** * typec_register_port - Register a USB Type-C Port * @parent: Parent device @@ -2038,6 +2037,8 @@ struct typec_port *typec_register_port(struct device *parent, ida_init(&port->mode_ids); mutex_init(&port->port_type_lock); + mutex_init(&port->port_list_lock); + INIT_LIST_HEAD(&port->port_list); port->id = id; port->ops = cap->ops; @@ -2045,7 +2046,7 @@ struct typec_port *typec_register_port(struct device *parent, port->prefer_role = cap->prefer_role; device_initialize(&port->dev); - port->dev.class = typec_class; + port->dev.class = &typec_class; port->dev.parent = parent; port->dev.fwnode = cap->fwnode; port->dev.type = &typec_port_dev_type; @@ -2079,6 +2080,10 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_PTR(ret); } + ret = typec_link_ports(port); + if (ret) + dev_warn(&port->dev, "failed to create symlinks (%d)\n", ret); + return port; } EXPORT_SYMBOL_GPL(typec_register_port); @@ -2091,8 +2096,10 @@ EXPORT_SYMBOL_GPL(typec_register_port); */ void typec_unregister_port(struct typec_port *port) { - if (!IS_ERR_OR_NULL(port)) + if (!IS_ERR_OR_NULL(port)) { + typec_unlink_ports(port); device_unregister(&port->dev); + } } EXPORT_SYMBOL_GPL(typec_unregister_port); @@ -2108,11 +2115,9 @@ static int __init typec_init(void) if (ret) goto err_unregister_bus; - typec_class = class_create(THIS_MODULE, "typec"); - if (IS_ERR(typec_class)) { - ret = PTR_ERR(typec_class); + ret = class_register(&typec_class); + if (ret) goto err_unregister_mux_class; - } return 0; @@ -2128,7 +2133,7 @@ subsys_initcall(typec_init); static void __exit typec_exit(void) { - class_destroy(typec_class); + class_unregister(&typec_class); ida_destroy(&typec_index_ida); bus_unregister(&typec_bus); class_unregister(&typec_mux_class); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h new file mode 100644 index 0000000000000000000000000000000000000000..aef03eb7e152316a68475aa9eaf5220247b36e96 --- /dev/null +++ b/drivers/usb/typec/class.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __USB_TYPEC_CLASS__ +#define __USB_TYPEC_CLASS__ + +#include <linux/device.h> +#include <linux/usb/typec.h> + +struct typec_mux; +struct typec_switch; + +struct typec_plug { + struct device dev; + enum typec_plug_index index; + struct ida mode_ids; + int num_altmodes; +}; + +struct typec_cable { + struct device dev; + enum typec_plug_type type; + struct usb_pd_identity *identity; + unsigned int active:1; + u16 pd_revision; /* 0300H = "3.0" */ +}; + +struct typec_partner { + struct device dev; + unsigned int usb_pd:1; + struct usb_pd_identity *identity; + enum typec_accessory accessory; + struct ida mode_ids; + int num_altmodes; + u16 pd_revision; /* 0300H = "3.0" */ + enum usb_pd_svdm_ver svdm_version; +}; + +struct typec_port { + unsigned int id; + struct device dev; + struct ida mode_ids; + + int prefer_role; + enum typec_data_role data_role; + enum typec_role pwr_role; + enum typec_role vconn_role; + enum typec_pwr_opmode pwr_opmode; + enum typec_port_type port_type; + struct mutex port_type_lock; + + enum typec_orientation orientation; + struct typec_switch *sw; + struct typec_mux *mux; + + const struct typec_capability *cap; + const struct typec_operations *ops; + + struct list_head port_list; + struct mutex port_list_lock; /* Port list lock */ + + void *pld; +}; + +#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev) +#define to_typec_plug(_dev_) container_of(_dev_, struct typec_plug, dev) +#define to_typec_cable(_dev_) container_of(_dev_, struct typec_cable, dev) +#define to_typec_partner(_dev_) container_of(_dev_, struct typec_partner, dev) + +extern const struct device_type typec_partner_dev_type; +extern const struct device_type typec_cable_dev_type; +extern const struct device_type typec_plug_dev_type; +extern const struct device_type typec_port_dev_type; + +#define is_typec_partner(dev) ((dev)->type == &typec_partner_dev_type) +#define is_typec_cable(dev) ((dev)->type == &typec_cable_dev_type) +#define is_typec_plug(dev) ((dev)->type == &typec_plug_dev_type) +#define is_typec_port(dev) ((dev)->type == &typec_port_dev_type) + +extern struct class typec_mux_class; +extern struct class typec_class; + +int typec_link_ports(struct typec_port *connector); +void typec_unlink_ports(struct typec_port *connector); + +#endif /* __USB_TYPEC_CLASS__ */ diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index cf720e944aaaa44eba12eb87d06d2e96c4ab9afa..9da22ae3006c970011624262084f4a97a954fc41 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -13,9 +13,9 @@ #include <linux/mutex.h> #include <linux/property.h> #include <linux/slab.h> -#include <linux/usb/typec_mux.h> -#include "bus.h" +#include "class.h" +#include "mux.h" static bool dev_name_ends_with(struct device *dev, const char *suffix) { diff --git a/drivers/usb/typec/mux.h b/drivers/usb/typec/mux.h new file mode 100644 index 0000000000000000000000000000000000000000..4fd9426ee44f6579f1a56e87ee2572bbbbec9f2c --- /dev/null +++ b/drivers/usb/typec/mux.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __USB_TYPEC_MUX__ +#define __USB_TYPEC_MUX__ + +#include <linux/usb/typec_mux.h> + +struct typec_switch { + struct device dev; + typec_switch_set_fn_t set; +}; + +struct typec_mux { + struct device dev; + typec_mux_set_fn_t set; +}; + +#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev) +#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev) + +#endif /* __USB_TYPEC_MUX__ */ diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c new file mode 100644 index 0000000000000000000000000000000000000000..9b0991bdf391a9efd6064a862996730eb52eb0db --- /dev/null +++ b/drivers/usb/typec/port-mapper.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USB Type-C Connector Class Port Mapping Utility + * + * Copyright (C) 2021, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + */ + +#include <linux/acpi.h> +#include <linux/usb.h> +#include <linux/usb/typec.h> + +#include "class.h" + +struct port_node { + struct list_head list; + struct device *dev; + void *pld; +}; + +static int acpi_pld_match(const struct acpi_pld_info *pld1, + const struct acpi_pld_info *pld2) +{ + if (!pld1 || !pld2) + return 0; + + /* + * To speed things up, first checking only the group_position. It seems + * to often have the first unique value in the _PLD. + */ + if (pld1->group_position == pld2->group_position) + return !memcmp(pld1, pld2, sizeof(struct acpi_pld_info)); + + return 0; +} + +static void *get_pld(struct device *dev) +{ +#ifdef CONFIG_ACPI + struct acpi_pld_info *pld; + acpi_status status; + + if (!has_acpi_companion(dev)) + return NULL; + + status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld); + if (ACPI_FAILURE(status)) + return NULL; + + return pld; +#else + return NULL; +#endif +} + +static void free_pld(void *pld) +{ +#ifdef CONFIG_ACPI + ACPI_FREE(pld); +#endif +} + +static int __link_port(struct typec_port *con, struct port_node *node) +{ + int ret; + + ret = sysfs_create_link(&node->dev->kobj, &con->dev.kobj, "connector"); + if (ret) + return ret; + + ret = sysfs_create_link(&con->dev.kobj, &node->dev->kobj, + dev_name(node->dev)); + if (ret) { + sysfs_remove_link(&node->dev->kobj, "connector"); + return ret; + } + + list_add_tail(&node->list, &con->port_list); + + return 0; +} + +static int link_port(struct typec_port *con, struct port_node *node) +{ + int ret; + + mutex_lock(&con->port_list_lock); + ret = __link_port(con, node); + mutex_unlock(&con->port_list_lock); + + return ret; +} + +static void __unlink_port(struct typec_port *con, struct port_node *node) +{ + sysfs_remove_link(&con->dev.kobj, dev_name(node->dev)); + sysfs_remove_link(&node->dev->kobj, "connector"); + list_del(&node->list); +} + +static void unlink_port(struct typec_port *con, struct port_node *node) +{ + mutex_lock(&con->port_list_lock); + __unlink_port(con, node); + mutex_unlock(&con->port_list_lock); +} + +static struct port_node *create_port_node(struct device *port) +{ + struct port_node *node; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return ERR_PTR(-ENOMEM); + + node->dev = get_device(port); + node->pld = get_pld(port); + + return node; +} + +static void remove_port_node(struct port_node *node) +{ + put_device(node->dev); + free_pld(node->pld); + kfree(node); +} + +static int connector_match(struct device *dev, const void *data) +{ + const struct port_node *node = data; + + if (!is_typec_port(dev)) + return 0; + + return acpi_pld_match(to_typec_port(dev)->pld, node->pld); +} + +static struct device *find_connector(struct port_node *node) +{ + if (!node->pld) + return NULL; + + return class_find_device(&typec_class, NULL, node, connector_match); +} + +/** + * typec_link_port - Link a port to its connector + * @port: The port device + * + * Find the connector of @port and create symlink named "connector" for it. + * Returns 0 on success, or errno in case of a failure. + * + * NOTE. The function increments the reference count of @port on success. + */ +int typec_link_port(struct device *port) +{ + struct device *connector; + struct port_node *node; + int ret; + + node = create_port_node(port); + if (IS_ERR(node)) + return PTR_ERR(node); + + connector = find_connector(node); + if (!connector) { + ret = 0; + goto remove_node; + } + + ret = link_port(to_typec_port(connector), node); + if (ret) + goto put_connector; + + return 0; + +put_connector: + put_device(connector); +remove_node: + remove_port_node(node); + + return ret; +} +EXPORT_SYMBOL_GPL(typec_link_port); + +static int port_match_and_unlink(struct device *connector, void *port) +{ + struct port_node *node; + struct port_node *tmp; + int ret = 0; + + if (!is_typec_port(connector)) + return 0; + + mutex_lock(&to_typec_port(connector)->port_list_lock); + list_for_each_entry_safe(node, tmp, &to_typec_port(connector)->port_list, list) { + ret = node->dev == port; + if (ret) { + unlink_port(to_typec_port(connector), node); + remove_port_node(node); + put_device(connector); + break; + } + } + mutex_unlock(&to_typec_port(connector)->port_list_lock); + + return ret; +} + +/** + * typec_unlink_port - Unlink port from its connector + * @port: The port device + * + * Removes the symlink "connector" and decrements the reference count of @port. + */ +void typec_unlink_port(struct device *port) +{ + class_for_each_device(&typec_class, NULL, port, port_match_and_unlink); +} +EXPORT_SYMBOL_GPL(typec_unlink_port); + +static int each_port(struct device *port, void *connector) +{ + struct port_node *node; + int ret; + + node = create_port_node(port); + if (IS_ERR(node)) + return PTR_ERR(node); + + if (!connector_match(connector, node)) { + remove_port_node(node); + return 0; + } + + ret = link_port(to_typec_port(connector), node); + if (ret) { + remove_port_node(node->pld); + return ret; + } + + get_device(connector); + + return 0; +} + +int typec_link_ports(struct typec_port *con) +{ + int ret = 0; + + con->pld = get_pld(&con->dev); + if (!con->pld) + return 0; + + ret = usb_for_each_port(&con->dev, each_port); + if (ret) + typec_unlink_ports(con); + + return ret; +} + +void typec_unlink_ports(struct typec_port *con) +{ + struct port_node *node; + struct port_node *tmp; + + mutex_lock(&con->port_list_lock); + + list_for_each_entry_safe(node, tmp, &con->port_list, list) { + __unlink_port(con, node); + remove_port_node(node); + put_device(&con->dev); + } + + mutex_unlock(&con->port_list_lock); + + free_pld(con->pld); +} diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c index d21750bbbb44d1f54c46d58b38925b2f2cf002fd..6eaeba9b096e140884f041c4072b1775e7ad9518 100644 --- a/drivers/usb/typec/stusb160x.c +++ b/drivers/usb/typec/stusb160x.c @@ -682,8 +682,8 @@ static int stusb160x_probe(struct i2c_client *client) } fwnode = device_get_named_child_node(chip->dev, "connector"); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); + if (!fwnode) + return -ENODEV; /* * When both VDD and VSYS power supplies are present, the low power diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index ebc46b9f776cdb02952e22a4509ff4343255cdbf..7a2a17866a823b36d5e11bce7e31517fd19c1284 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -213,8 +213,9 @@ static void fusb302_debugfs_init(struct fusb302_chip *chip) mutex_init(&chip->logbuffer_lock); snprintf(name, NAME_MAX, "fusb302-%s", dev_name(chip->dev)); - chip->dentry = debugfs_create_file(name, S_IFREG | 0444, usb_debug_root, - chip, &fusb302_debug_fops); + chip->dentry = debugfs_create_dir(name, usb_debug_root); + debugfs_create_file("log", S_IFREG | 0444, chip->dentry, chip, + &fusb302_debug_fops); } static void fusb302_debugfs_exit(struct fusb302_chip *chip) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index a27deb0b5f03c8588b751eed33b468992f4e721a..25b480752266ea08aa83e5bb881254e94224924d 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -24,6 +24,11 @@ #define AUTO_DISCHARGE_PD_HEADROOM_MV 850 #define AUTO_DISCHARGE_PPS_HEADROOM_MV 1250 +#define tcpc_presenting_rd(reg, cc) \ + (!(TCPC_ROLE_CTRL_DRP & (reg)) && \ + (((reg) & (TCPC_ROLE_CTRL_## cc ##_MASK << TCPC_ROLE_CTRL_## cc ##_SHIFT)) == \ + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_## cc ##_SHIFT))) + struct tcpci { struct device *dev; @@ -178,19 +183,25 @@ static int tcpci_get_cc(struct tcpc_dev *tcpc, enum typec_cc_status *cc1, enum typec_cc_status *cc2) { struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg; + unsigned int reg, role_control; int ret; + ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &role_control); + if (ret < 0) + return ret; + ret = regmap_read(tcpci->regmap, TCPC_CC_STATUS, ®); if (ret < 0) return ret; *cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) & TCPC_CC_STATUS_CC1_MASK, - reg & TCPC_CC_STATUS_TERM); + reg & TCPC_CC_STATUS_TERM || + tcpc_presenting_rd(role_control, CC1)); *cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) & TCPC_CC_STATUS_CC2_MASK, - reg & TCPC_CC_STATUS_TERM); + reg & TCPC_CC_STATUS_TERM || + tcpc_presenting_rd(role_control, CC2)); return 0; } diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 57b6e24e0a0c11e88d8cab1b5c801ababdb59181..2be7a77d400ef9da9f0c22b8d4076379d190f1a8 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -47,7 +47,10 @@ #define TCPC_TCPC_CTRL 0x19 #define TCPC_TCPC_CTRL_ORIENTATION BIT(0) +#define PLUG_ORNT_CC1 0 +#define PLUG_ORNT_CC2 1 #define TCPC_TCPC_CTRL_BIST_TM BIT(1) +#define TCPC_TCPC_CTRL_EN_LK4CONN_ALRT BIT(6) #define TCPC_EXTENDED_STATUS 0x20 #define TCPC_EXTENDED_STATUS_VSAFE0V BIT(0) @@ -74,21 +77,28 @@ #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0) #define TCPC_POWER_CTRL_BLEED_DISCHARGE BIT(3) #define TCPC_POWER_CTRL_AUTO_DISCHARGE BIT(4) +#define TCPC_DIS_VOLT_ALRM BIT(5) +#define TCPC_POWER_CTRL_VBUS_VOLT_MON BIT(6) #define TCPC_FAST_ROLE_SWAP_EN BIT(7) #define TCPC_CC_STATUS 0x1d #define TCPC_CC_STATUS_TOGGLING BIT(5) #define TCPC_CC_STATUS_TERM BIT(4) +#define TCPC_CC_STATUS_TERM_RP 0 +#define TCPC_CC_STATUS_TERM_RD 1 +#define TCPC_CC_STATE_SRC_OPEN 0 #define TCPC_CC_STATUS_CC2_SHIFT 2 #define TCPC_CC_STATUS_CC2_MASK 0x3 #define TCPC_CC_STATUS_CC1_SHIFT 0 #define TCPC_CC_STATUS_CC1_MASK 0x3 #define TCPC_POWER_STATUS 0x1e +#define TCPC_POWER_STATUS_DBG_ACC_CON BIT(7) #define TCPC_POWER_STATUS_UNINIT BIT(6) #define TCPC_POWER_STATUS_SOURCING_VBUS BIT(4) #define TCPC_POWER_STATUS_VBUS_DET BIT(3) #define TCPC_POWER_STATUS_VBUS_PRES BIT(2) +#define TCPC_POWER_STATUS_SINKING_VBUS BIT(0) #define TCPC_FAULT_STATUS 0x1f @@ -121,6 +131,10 @@ #define TCPC_RX_DETECT 0x2f #define TCPC_RX_DETECT_HARD_RESET BIT(5) #define TCPC_RX_DETECT_SOP BIT(0) +#define TCPC_RX_DETECT_SOP1 BIT(1) +#define TCPC_RX_DETECT_SOP2 BIT(2) +#define TCPC_RX_DETECT_DBG1 BIT(3) +#define TCPC_RX_DETECT_DBG2 BIT(4) #define TCPC_RX_BYTE_CNT 0x30 #define TCPC_RX_BUF_FRAME_TYPE 0x31 @@ -139,6 +153,8 @@ #define TCPC_TX_DATA 0x54 /* through 0x6f */ #define TCPC_VBUS_VOLTAGE 0x70 +#define TCPC_VBUS_VOLTAGE_MASK 0x3ff +#define TCPC_VBUS_VOLTAGE_LSB_MV 25 #define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72 #define TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV 25 #define TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX 0x3ff diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c index 041a1c39359485857dfb921fc6668d9eb74dfce5..df2505570f07dc4e5802088ec4f667c288725f9f 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c @@ -52,7 +52,7 @@ static const struct regmap_range max_tcpci_tcpci_range[] = { regmap_reg_range(0x00, 0x95) }; -const struct regmap_access_table max_tcpci_tcpci_write_table = { +static const struct regmap_access_table max_tcpci_tcpci_write_table = { .yes_ranges = max_tcpci_tcpci_range, .n_yes_ranges = ARRAY_SIZE(max_tcpci_tcpci_range), }; diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 2b08fbc2723ef8f19f87e2a70bfeca8a80c3187f..f74062a925347b2878b5c3382d6eed662241925d 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -268,12 +268,27 @@ struct pd_mode_data { struct typec_altmode_desc altmode_desc[ALTMODE_DISCOVERY_MAX]; }; +/* + * @min_volt: Actual min voltage at the local port + * @req_min_volt: Requested min voltage to the port partner + * @max_volt: Actual max voltage at the local port + * @req_max_volt: Requested max voltage to the port partner + * @max_curr: Actual max current at the local port + * @req_max_curr: Requested max current of the port partner + * @req_out_volt: Requested output voltage to the port partner + * @req_op_curr: Requested operating current to the port partner + * @supported: Parter has atleast one APDO hence supports PPS + * @active: PPS mode is active + */ struct pd_pps_data { u32 min_volt; + u32 req_min_volt; u32 max_volt; + u32 req_max_volt; u32 max_curr; - u32 out_volt; - u32 op_curr; + u32 req_max_curr; + u32 req_out_volt; + u32 req_op_curr; bool supported; bool active; }; @@ -389,7 +404,10 @@ struct tcpm_port { unsigned int operating_snk_mw; bool update_sink_caps; - /* Requested current / voltage */ + /* Requested current / voltage to the port partner */ + u32 req_current_limit; + u32 req_supply_voltage; + /* Actual current / voltage limit of the local port */ u32 current_limit; u32 supply_voltage; @@ -438,6 +456,16 @@ struct tcpm_port { enum tcpm_ams next_ams; bool in_ams; + /* Auto vbus discharge status */ + bool auto_vbus_discharge_enabled; + + /* + * When set, port requests PD_P_SNK_STDBY_MW upon entering SNK_DISCOVERY and + * the actual currrent limit after RX of PD_CTRL_PSRDY for PD link, + * SNK_READY for non-pd link. + */ + bool slow_charger_loop; + /* Port is still in tCCDebounce */ bool debouncing; @@ -510,6 +538,9 @@ static const char * const pd_rev[] = { (tcpm_port_is_sink(port) && \ ((port)->cc1 == TYPEC_CC_RP_3_0 || (port)->cc2 == TYPEC_CC_RP_3_0)) +#define tcpm_wait_for_discharge(port) \ + (((port)->auto_vbus_discharge_enabled && !(port)->vbus_vsafe0v) ? PD_T_SAFE_0V : 0) + static enum tcpm_state tcpm_default_state(struct tcpm_port *port) { if (port->port_type == TYPEC_PORT_DRP) { @@ -706,8 +737,9 @@ static void tcpm_debugfs_init(struct tcpm_port *port) mutex_init(&port->logbuffer_lock); snprintf(name, NAME_MAX, "tcpm-%s", dev_name(port->dev)); - port->dentry = debugfs_create_file(name, S_IFREG | 0444, usb_debug_root, - port, &tcpm_debug_fops); + port->dentry = debugfs_create_dir(name, usb_debug_root); + debugfs_create_file("log", S_IFREG | 0444, port->dentry, port, + &tcpm_debug_fops); } static void tcpm_debugfs_exit(struct tcpm_port *port) @@ -776,10 +808,8 @@ static enum typec_cc_status tcpm_rp_cc(struct tcpm_port *port) return TYPEC_CC_RP_DEF; } -static int tcpm_ams_finish(struct tcpm_port *port) +static void tcpm_ams_finish(struct tcpm_port *port) { - int ret = 0; - tcpm_log(port, "AMS %s finished", tcpm_ams_str[port->ams]); if (port->pd_capable && port->pwr_role == TYPEC_SOURCE) { @@ -793,8 +823,6 @@ static int tcpm_ams_finish(struct tcpm_port *port) port->in_ams = false; port->ams = NONE_AMS; - - return ret; } static int tcpm_pd_transmit(struct tcpm_port *port, @@ -2450,8 +2478,8 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, case SNK_TRANSITION_SINK: if (port->vbus_present) { tcpm_set_current_limit(port, - port->current_limit, - port->supply_voltage); + port->req_current_limit, + port->req_supply_voltage); port->explicit_contract = true; tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD, @@ -2510,8 +2538,8 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, break; case SNK_NEGOTIATE_PPS_CAPABILITIES: /* Revert data back from any requested PPS updates */ - port->pps_data.out_volt = port->supply_voltage; - port->pps_data.op_curr = port->current_limit; + port->pps_data.req_out_volt = port->supply_voltage; + port->pps_data.req_op_curr = port->current_limit; port->pps_status = (type == PD_CTRL_WAIT ? -EAGAIN : -EOPNOTSUPP); @@ -2560,8 +2588,12 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, break; case SNK_NEGOTIATE_PPS_CAPABILITIES: port->pps_data.active = true; - port->supply_voltage = port->pps_data.out_volt; - port->current_limit = port->pps_data.op_curr; + port->pps_data.min_volt = port->pps_data.req_min_volt; + port->pps_data.max_volt = port->pps_data.req_max_volt; + port->pps_data.max_curr = port->pps_data.req_max_curr; + port->req_supply_voltage = port->pps_data.req_out_volt; + port->req_current_limit = port->pps_data.req_op_curr; + power_supply_changed(port->psy); tcpm_set_state(port, SNK_TRANSITION_SINK, 0); break; case SOFT_RESET_SEND: @@ -3120,17 +3152,16 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) src = port->source_caps[src_pdo]; snk = port->snk_pdo[snk_pdo]; - port->pps_data.min_volt = max(pdo_pps_apdo_min_voltage(src), - pdo_pps_apdo_min_voltage(snk)); - port->pps_data.max_volt = min(pdo_pps_apdo_max_voltage(src), - pdo_pps_apdo_max_voltage(snk)); - port->pps_data.max_curr = min_pps_apdo_current(src, snk); - port->pps_data.out_volt = min(port->pps_data.max_volt, - max(port->pps_data.min_volt, - port->pps_data.out_volt)); - port->pps_data.op_curr = min(port->pps_data.max_curr, - port->pps_data.op_curr); - power_supply_changed(port->psy); + port->pps_data.req_min_volt = max(pdo_pps_apdo_min_voltage(src), + pdo_pps_apdo_min_voltage(snk)); + port->pps_data.req_max_volt = min(pdo_pps_apdo_max_voltage(src), + pdo_pps_apdo_max_voltage(snk)); + port->pps_data.req_max_curr = min_pps_apdo_current(src, snk); + port->pps_data.req_out_volt = min(port->pps_data.req_max_volt, + max(port->pps_data.req_min_volt, + port->pps_data.req_out_volt)); + port->pps_data.req_op_curr = min(port->pps_data.req_max_curr, + port->pps_data.req_op_curr); } return src_pdo; @@ -3210,8 +3241,8 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); } - port->current_limit = ma; - port->supply_voltage = mv; + port->req_current_limit = ma; + port->req_supply_voltage = mv; return 0; } @@ -3257,10 +3288,10 @@ static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) tcpm_log(port, "Invalid APDO selected!"); return -EINVAL; } - max_mv = port->pps_data.max_volt; - max_ma = port->pps_data.max_curr; - out_mv = port->pps_data.out_volt; - op_ma = port->pps_data.op_curr; + max_mv = port->pps_data.req_max_volt; + max_ma = port->pps_data.req_max_curr; + out_mv = port->pps_data.req_out_volt; + op_ma = port->pps_data.req_op_curr; break; default: tcpm_log(port, "Invalid PDO selected!"); @@ -3307,8 +3338,8 @@ static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) tcpm_log(port, "Requesting APDO %d: %u mV, %u mA", src_pdo_index, out_mv, op_ma); - port->pps_data.op_curr = op_ma; - port->pps_data.out_volt = out_mv; + port->pps_data.req_op_curr = op_ma; + port->pps_data.req_out_volt = out_mv; return 0; } @@ -3436,6 +3467,8 @@ static int tcpm_src_attach(struct tcpm_port *port) if (port->tcpc->enable_auto_vbus_discharge) { ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true); tcpm_log_force(port, "enable vbus discharge ret:%d", ret); + if (!ret) + port->auto_vbus_discharge_enabled = true; } ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port)); @@ -3519,6 +3552,8 @@ static void tcpm_reset_port(struct tcpm_port *port) if (port->tcpc->enable_auto_vbus_discharge) { ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false); tcpm_log_force(port, "Disable vbus discharge ret:%d", ret); + if (!ret) + port->auto_vbus_discharge_enabled = false; } port->in_ams = false; port->ams = NONE_AMS; @@ -3552,8 +3587,6 @@ static void tcpm_reset_port(struct tcpm_port *port) port->sink_cap_done = false; if (port->tcpc->enable_frs) port->tcpc->enable_frs(port->tcpc, false); - - power_supply_changed(port->psy); } static void tcpm_detach(struct tcpm_port *port) @@ -3593,6 +3626,8 @@ static int tcpm_snk_attach(struct tcpm_port *port) tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V); ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true); tcpm_log_force(port, "enable vbus discharge ret:%d", ret); + if (!ret) + port->auto_vbus_discharge_enabled = true; } ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port)); @@ -3671,8 +3706,8 @@ static inline enum tcpm_state unattached_state(struct tcpm_port *port) static void tcpm_check_send_discover(struct tcpm_port *port) { - if (port->data_role == TYPEC_HOST && port->send_discover && - port->pd_capable) + if ((port->data_role == TYPEC_HOST || port->negotiated_rev > PD_REV20) && + port->send_discover && port->pd_capable) tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0); port->send_discover = false; } @@ -4064,9 +4099,11 @@ static void run_state_machine(struct tcpm_port *port) break; case SNK_DISCOVERY: if (port->vbus_present) { - tcpm_set_current_limit(port, - tcpm_get_current_limit(port), - 5000); + u32 current_lim = tcpm_get_current_limit(port); + + if (port->slow_charger_loop || (current_lim > PD_P_SNK_STDBY_MW / 5)) + current_lim = PD_P_SNK_STDBY_MW / 5; + tcpm_set_current_limit(port, current_lim, 5000); tcpm_set_charge(port, true); tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0); break; @@ -4148,6 +4185,23 @@ static void run_state_machine(struct tcpm_port *port) } break; case SNK_TRANSITION_SINK: + /* From the USB PD spec: + * "The Sink Shall transition to Sink Standby before a positive or + * negative voltage transition of VBUS. During Sink Standby + * the Sink Shall reduce its power draw to pSnkStdby." + * + * This is not applicable to PPS though as the port can continue + * to draw negotiated power without switching to standby. + */ + if (port->supply_voltage != port->req_supply_voltage && !port->pps_data.active && + port->current_limit * port->supply_voltage / 1000 > PD_P_SNK_STDBY_MW) { + u32 stdby_ma = PD_P_SNK_STDBY_MW * 1000 / port->supply_voltage; + + tcpm_log(port, "Setting standby current %u mV @ %u mA", + port->supply_voltage, stdby_ma); + tcpm_set_current_limit(port, stdby_ma, port->supply_voltage); + } + fallthrough; case SNK_TRANSITION_SINK_VBUS: tcpm_set_state(port, hard_reset_state(port), PD_T_PS_TRANSITION); @@ -4161,6 +4215,8 @@ static void run_state_machine(struct tcpm_port *port) port->pwr_opmode = TYPEC_PWR_MODE_PD; } + if (!port->pd_capable && port->slow_charger_loop) + tcpm_set_current_limit(port, tcpm_get_current_limit(port), 5000); tcpm_swap_complete(port, 0); tcpm_typec_connect(port); mod_enable_frs_delayed_work(port, 0); @@ -4721,9 +4777,9 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, if (tcpm_port_is_disconnected(port) || !tcpm_port_is_source(port)) { if (port->port_type == TYPEC_PORT_SRC) - tcpm_set_state(port, SRC_UNATTACHED, 0); + tcpm_set_state(port, SRC_UNATTACHED, tcpm_wait_for_discharge(port)); else - tcpm_set_state(port, SNK_UNATTACHED, 0); + tcpm_set_state(port, SNK_UNATTACHED, tcpm_wait_for_discharge(port)); } break; case SNK_UNATTACHED: @@ -4754,7 +4810,23 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, tcpm_set_state(port, SNK_DEBOUNCED, 0); break; case SNK_READY: - if (tcpm_port_is_disconnected(port)) + /* + * EXIT condition is based primarily on vbus disconnect and CC is secondary. + * "A port that has entered into USB PD communications with the Source and + * has seen the CC voltage exceed vRd-USB may monitor the CC pin to detect + * cable disconnect in addition to monitoring VBUS. + * + * A port that is monitoring the CC voltage for disconnect (but is not in + * the process of a USB PD PR_Swap or USB PD FR_Swap) shall transition to + * Unattached.SNK within tSinkDisconnect after the CC voltage remains below + * vRd-USB for tPDDebounce." + * + * When set_auto_vbus_discharge_threshold is enabled, CC pins go + * away before vbus decays to disconnect threshold. Allow + * disconnect to be driven by vbus disconnect when auto vbus + * discharge is enabled. + */ + if (!port->auto_vbus_discharge_enabled && tcpm_port_is_disconnected(port)) tcpm_set_state(port, unattached_state(port), 0); else if (!port->pd_capable && (cc1 != old_cc1 || cc2 != old_cc2)) @@ -4853,9 +4925,13 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, * Ignore CC changes here. */ break; - default: - if (tcpm_port_is_disconnected(port)) + /* + * While acting as sink and auto vbus discharge is enabled, Allow disconnect + * to be driven by vbus disconnect. + */ + if (tcpm_port_is_disconnected(port) && !(port->pwr_role == TYPEC_SINK && + port->auto_vbus_discharge_enabled)) tcpm_set_state(port, unattached_state(port), 0); break; } @@ -5020,8 +5096,16 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) case SRC_TRANSITION_SUPPLY: case SRC_READY: case SRC_WAIT_NEW_CAPABILITIES: - /* Force to unattached state to re-initiate connection */ - tcpm_set_state(port, SRC_UNATTACHED, 0); + /* + * Force to unattached state to re-initiate connection. + * DRP port should move to Unattached.SNK instead of Unattached.SRC if + * sink removed. Although sink removal here is due to source's vbus collapse, + * treat it the same way for consistency. + */ + if (port->port_type == TYPEC_PORT_SRC) + tcpm_set_state(port, SRC_UNATTACHED, tcpm_wait_for_discharge(port)); + else + tcpm_set_state(port, SNK_UNATTACHED, tcpm_wait_for_discharge(port)); break; case PORT_RESET: @@ -5040,9 +5124,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) break; default: - if (port->pwr_role == TYPEC_SINK && - port->attached) - tcpm_set_state(port, SNK_UNATTACHED, 0); + if (port->pwr_role == TYPEC_SINK && port->attached) + tcpm_set_state(port, SNK_UNATTACHED, tcpm_wait_for_discharge(port)); break; } } @@ -5064,7 +5147,23 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port) tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED, PD_T_CC_DEBOUNCE); break; + case SRC_STARTUP: + case SRC_SEND_CAPABILITIES: + case SRC_SEND_CAPABILITIES_TIMEOUT: + case SRC_NEGOTIATE_CAPABILITIES: + case SRC_TRANSITION_SUPPLY: + case SRC_READY: + case SRC_WAIT_NEW_CAPABILITIES: + if (port->auto_vbus_discharge_enabled) { + if (port->port_type == TYPEC_PORT_SRC) + tcpm_set_state(port, SRC_UNATTACHED, 0); + else + tcpm_set_state(port, SNK_UNATTACHED, 0); + } + break; default: + if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled) + tcpm_set_state(port, SNK_UNATTACHED, 0); break; } } @@ -5420,7 +5519,7 @@ static int tcpm_try_role(struct typec_port *p, int role) return ret; } -static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr) +static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 req_op_curr) { unsigned int target_mw; int ret; @@ -5438,12 +5537,12 @@ static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr) goto port_unlock; } - if (op_curr > port->pps_data.max_curr) { + if (req_op_curr > port->pps_data.max_curr) { ret = -EINVAL; goto port_unlock; } - target_mw = (op_curr * port->pps_data.out_volt) / 1000; + target_mw = (req_op_curr * port->supply_voltage) / 1000; if (target_mw < port->operating_snk_mw) { ret = -EINVAL; goto port_unlock; @@ -5457,10 +5556,10 @@ static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr) } /* Round down operating current to align with PPS valid steps */ - op_curr = op_curr - (op_curr % RDO_PROG_CURR_MA_STEP); + req_op_curr = req_op_curr - (req_op_curr % RDO_PROG_CURR_MA_STEP); reinit_completion(&port->pps_complete); - port->pps_data.op_curr = op_curr; + port->pps_data.req_op_curr = req_op_curr; port->pps_status = 0; port->pps_pending = true; mutex_unlock(&port->lock); @@ -5481,7 +5580,7 @@ swap_unlock: return ret; } -static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt) +static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 req_out_volt) { unsigned int target_mw; int ret; @@ -5499,13 +5598,13 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt) goto port_unlock; } - if (out_volt < port->pps_data.min_volt || - out_volt > port->pps_data.max_volt) { + if (req_out_volt < port->pps_data.min_volt || + req_out_volt > port->pps_data.max_volt) { ret = -EINVAL; goto port_unlock; } - target_mw = (port->pps_data.op_curr * out_volt) / 1000; + target_mw = (port->current_limit * req_out_volt) / 1000; if (target_mw < port->operating_snk_mw) { ret = -EINVAL; goto port_unlock; @@ -5519,10 +5618,10 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt) } /* Round down output voltage to align with PPS valid steps */ - out_volt = out_volt - (out_volt % RDO_PROG_VOLT_MV_STEP); + req_out_volt = req_out_volt - (req_out_volt % RDO_PROG_VOLT_MV_STEP); reinit_completion(&port->pps_complete); - port->pps_data.out_volt = out_volt; + port->pps_data.req_out_volt = req_out_volt; port->pps_status = 0; port->pps_pending = true; mutex_unlock(&port->lock); @@ -5580,8 +5679,8 @@ static int tcpm_pps_activate(struct tcpm_port *port, bool activate) /* Trigger PPS request or move back to standard PDO contract */ if (activate) { - port->pps_data.out_volt = port->supply_voltage; - port->pps_data.op_curr = port->current_limit; + port->pps_data.req_out_volt = port->supply_voltage; + port->pps_data.req_op_curr = port->current_limit; } mutex_unlock(&port->lock); @@ -5721,6 +5820,7 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, port->typec_caps.type = ret; port->port_type = port->typec_caps.type; + port->slow_charger_loop = fwnode_property_read_bool(fwnode, "slow-charger-loop"); if (port->port_type == TYPEC_PORT_SNK) goto sink; @@ -6161,6 +6261,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) goto out_role_sw_put; } + typec_port_register_altmodes(port->typec_port, + &tcpm_altmode_ops, port, + port->port_altmode, ALTMODE_DISCOVERY_MAX); + mutex_lock(&port->lock); tcpm_init(port); mutex_unlock(&port->lock); diff --git a/drivers/usb/typec/tipd/Kconfig b/drivers/usb/typec/tipd/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..b827152930728623548cbcb148327cc5a58b02bf --- /dev/null +++ b/drivers/usb/typec/tipd/Kconfig @@ -0,0 +1,12 @@ +config TYPEC_TPS6598X + tristate "TI TPS6598x USB Power Delivery controller driver" + depends on I2C + select POWER_SUPPLY + select REGMAP_I2C + select USB_ROLE_SWITCH + help + Say Y or M here if your system has TI TPS65982 or TPS65983 USB Power + Delivery controller. + + If you choose to build this driver as a dynamically linked module, the + module will be called tps6598x.ko. diff --git a/drivers/usb/typec/tipd/Makefile b/drivers/usb/typec/tipd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aa439f80a889ecb6691e5aa27b416db5cb109ca7 --- /dev/null +++ b/drivers/usb/typec/tipd/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +CFLAGS_trace.o := -I$(src) + +obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o +tps6598x-y := core.o +tps6598x-$(CONFIG_TRACING) += trace.o diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tipd/core.c similarity index 91% rename from drivers/usb/typec/tps6598x.c rename to drivers/usb/typec/tipd/core.c index 29bd1c5a283cd966bec7bebdd294fbc5a52f66e6..938219bc1b4beab3c2648f14508656c83d917fd3 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tipd/core.c @@ -15,6 +15,9 @@ #include <linux/usb/typec.h> #include <linux/usb/role.h> +#include "tps6598x.h" +#include "trace.h" + /* Register offsets */ #define TPS_REG_VID 0x00 #define TPS_REG_MODE 0x03 @@ -31,16 +34,7 @@ #define TPS_REG_CTRL_CONF 0x29 #define TPS_REG_POWER_STATUS 0x3f #define TPS_REG_RX_IDENTITY_SOP 0x48 - -/* TPS_REG_INT_* bits */ -#define TPS_REG_INT_PLUG_EVENT BIT(3) - -/* TPS_REG_STATUS bits */ -#define TPS_STATUS_PLUG_PRESENT BIT(0) -#define TPS_STATUS_ORIENTATION BIT(4) -#define TPS_STATUS_PORTROLE(s) (!!((s) & BIT(5))) -#define TPS_STATUS_DATAROLE(s) (!!((s) & BIT(6))) -#define TPS_STATUS_VCONN(s) (!!((s) & BIT(7))) +#define TPS_REG_DATA_STATUS 0x5f /* TPS_REG_SYSTEM_CONF bits */ #define TPS_SYSCONF_PORTINFO(c) ((c) & 7) @@ -55,11 +49,6 @@ enum { TPS_PORTINFO_SOURCE, }; -/* TPS_REG_POWER_STATUS bits */ -#define TPS_POWER_STATUS_CONNECTION BIT(0) -#define TPS_POWER_STATUS_SOURCESINK BIT(1) -#define TPS_POWER_STATUS_PWROPMODE(p) (((p) & GENMASK(3, 2)) >> 2) - /* TPS_REG_RX_IDENTITY_SOP */ struct tps6598x_rx_identity_reg { u8 status; @@ -255,9 +244,9 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) } typec_set_pwr_opmode(tps->port, mode); - typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); - typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); - tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), true); + typec_set_pwr_role(tps->port, TPS_STATUS_TO_TYPEC_PORTROLE(status)); + typec_set_vconn_role(tps->port, TPS_STATUS_TO_TYPEC_VCONN(status)); + tps6598x_set_data_role(tps, TPS_STATUS_TO_TYPEC_DATAROLE(status), true); tps->partner = typec_register_partner(tps->port, &desc); if (IS_ERR(tps->partner)) @@ -277,9 +266,10 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status) typec_unregister_partner(tps->partner); tps->partner = NULL; typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); - typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); - typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); - tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false); + typec_set_pwr_role(tps->port, TPS_STATUS_TO_TYPEC_PORTROLE(status)); + typec_set_vconn_role(tps->port, TPS_STATUS_TO_TYPEC_VCONN(status)); + tps6598x_set_data_role(tps, TPS_STATUS_TO_TYPEC_DATAROLE(status), false); + power_supply_changed(tps->psy); } @@ -363,7 +353,7 @@ static int tps6598x_dr_set(struct typec_port *port, enum typec_data_role role) if (ret) goto out_unlock; - if (role != TPS_STATUS_DATAROLE(status)) { + if (role != TPS_STATUS_TO_TYPEC_DATAROLE(status)) { ret = -EPROTO; goto out_unlock; } @@ -393,7 +383,7 @@ static int tps6598x_pr_set(struct typec_port *port, enum typec_role role) if (ret) goto out_unlock; - if (role != TPS_STATUS_PORTROLE(status)) { + if (role != TPS_STATUS_TO_TYPEC_PORTROLE(status)) { ret = -EPROTO; goto out_unlock; } @@ -416,7 +406,8 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) struct tps6598x *tps = data; u64 event1; u64 event2; - u32 status; + u32 status, data_status; + u16 pwr_status; int ret; mutex_lock(&tps->lock); @@ -427,12 +418,32 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) dev_err(tps->dev, "%s: failed to read events\n", __func__); goto err_unlock; } + trace_tps6598x_irq(event1, event2); ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); if (ret) { dev_err(tps->dev, "%s: failed to read status\n", __func__); goto err_clear_ints; } + trace_tps6598x_status(status); + + if ((event1 | event2) & TPS_REG_INT_POWER_STATUS_UPDATE) { + ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &pwr_status); + if (ret < 0) { + dev_err(tps->dev, "failed to read power status: %d\n", ret); + goto err_clear_ints; + } + trace_tps6598x_power_status(pwr_status); + } + + if ((event1 | event2) & TPS_REG_INT_DATA_STATUS_UPDATE) { + ret = tps6598x_read32(tps, TPS_REG_DATA_STATUS, &data_status); + if (ret < 0) { + dev_err(tps->dev, "failed to read data status: %d\n", ret); + goto err_clear_ints; + } + trace_tps6598x_data_status(data_status); + } /* Handle plug insert or removal */ if ((event1 | event2) & TPS_REG_INT_PLUG_EVENT) { @@ -498,8 +509,8 @@ static int tps6598x_psy_get_online(struct tps6598x *tps, if (ret < 0) return ret; - if ((pwr_status & TPS_POWER_STATUS_CONNECTION) && - (pwr_status & TPS_POWER_STATUS_SOURCESINK)) { + if (TPS_POWER_STATUS_CONNECTION(pwr_status) && + TPS_POWER_STATUS_SOURCESINK(pwr_status)) { val->intval = 1; } else { val->intval = 0; @@ -608,14 +619,15 @@ static int tps6598x_probe(struct i2c_client *client) ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); if (ret < 0) return ret; + trace_tps6598x_status(status); ret = tps6598x_read32(tps, TPS_REG_SYSTEM_CONF, &conf); if (ret < 0) return ret; fwnode = device_get_named_child_node(&client->dev, "connector"); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); + if (!fwnode) + return -ENODEV; tps->role_sw = fwnode_usb_role_switch_get(fwnode); if (IS_ERR(tps->role_sw)) { diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h new file mode 100644 index 0000000000000000000000000000000000000000..003a577be21646cecd478b00e0bdf72a7014ae4a --- /dev/null +++ b/drivers/usb/typec/tipd/tps6598x.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Driver for TI TPS6598x USB Power Delivery controller family + * + * Copyright (C) 2017, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + */ + +#include <linux/bits.h> +#include <linux/bitfield.h> + +#ifndef __TPS6598X_H__ +#define __TPS6598X_H__ + +#define TPS_FIELD_GET(_mask, _reg) ((typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask))) + +/* TPS_REG_STATUS bits */ +#define TPS_STATUS_PLUG_PRESENT BIT(0) +#define TPS_STATUS_PLUG_UPSIDE_DOWN BIT(4) +#define TPS_STATUS_PORTROLE BIT(5) +#define TPS_STATUS_TO_TYPEC_PORTROLE(s) (!!((s) & TPS_STATUS_PORTROLE)) +#define TPS_STATUS_DATAROLE BIT(6) +#define TPS_STATUS_TO_TYPEC_DATAROLE(s) (!!((s) & TPS_STATUS_DATAROLE)) +#define TPS_STATUS_VCONN BIT(7) +#define TPS_STATUS_TO_TYPEC_VCONN(s) (!!((s) & TPS_STATUS_VCONN)) +#define TPS_STATUS_OVERCURRENT BIT(16) +#define TPS_STATUS_GOTO_MIN_ACTIVE BIT(26) +#define TPS_STATUS_BIST BIT(27) +#define TPS_STATUS_HIGH_VOLAGE_WARNING BIT(28) +#define TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING BIT(29) + +#define TPS_STATUS_CONN_STATE_MASK GENMASK(3, 1) +#define TPS_STATUS_CONN_STATE(x) TPS_FIELD_GET(TPS_STATUS_CONN_STATE_MASK, (x)) +#define TPS_STATUS_PP_5V0_SWITCH_MASK GENMASK(9, 8) +#define TPS_STATUS_PP_5V0_SWITCH(x) TPS_FIELD_GET(TPS_STATUS_PP_5V0_SWITCH_MASK, (x)) +#define TPS_STATUS_PP_HV_SWITCH_MASK GENMASK(11, 10) +#define TPS_STATUS_PP_HV_SWITCH(x) TPS_FIELD_GET(TPS_STATUS_PP_HV_SWITCH_MASK, (x)) +#define TPS_STATUS_PP_EXT_SWITCH_MASK GENMASK(13, 12) +#define TPS_STATUS_PP_EXT_SWITCH(x) TPS_FIELD_GET(TPS_STATUS_PP_EXT_SWITCH_MASK, (x)) +#define TPS_STATUS_PP_CABLE_SWITCH_MASK GENMASK(15, 14) +#define TPS_STATUS_PP_CABLE_SWITCH(x) TPS_FIELD_GET(TPS_STATUS_PP_CABLE_SWITCH_MASK, (x)) +#define TPS_STATUS_POWER_SOURCE_MASK GENMASK(19, 18) +#define TPS_STATUS_POWER_SOURCE(x) TPS_FIELD_GET(TPS_STATUS_POWER_SOURCE_MASK, (x)) +#define TPS_STATUS_VBUS_STATUS_MASK GENMASK(21, 20) +#define TPS_STATUS_VBUS_STATUS(x) TPS_FIELD_GET(TPS_STATUS_VBUS_STATUS_MASK, (x)) +#define TPS_STATUS_USB_HOST_PRESENT_MASK GENMASK(23, 22) +#define TPS_STATUS_USB_HOST_PRESENT(x) TPS_FIELD_GET(TPS_STATUS_USB_HOST_PRESENT_MASK, (x)) +#define TPS_STATUS_LEGACY_MASK GENMASK(25, 24) +#define TPS_STATUS_LEGACY(x) TPS_FIELD_GET(TPS_STATUS_LEGACY_MASK, (x)) + +#define TPS_STATUS_CONN_STATE_NO_CONN 0 +#define TPS_STATUS_CONN_STATE_DISABLED 1 +#define TPS_STATUS_CONN_STATE_AUDIO_CONN 2 +#define TPS_STATUS_CONN_STATE_DEBUG_CONN 3 +#define TPS_STATUS_CONN_STATE_NO_CONN_R_A 4 +#define TPS_STATUS_CONN_STATE_RESERVED 5 +#define TPS_STATUS_CONN_STATE_CONN_NO_R_A 6 +#define TPS_STATUS_CONN_STATE_CONN_WITH_R_A 7 + +#define TPS_STATUS_PP_SWITCH_STATE_DISABLED 0 +#define TPS_STATUS_PP_SWITCH_STATE_FAULT 1 +#define TPS_STATUS_PP_SWITCH_STATE_OUT 2 +#define TPS_STATUS_PP_SWITCH_STATE_IN 3 + +#define TPS_STATUS_POWER_SOURCE_UNKNOWN 0 +#define TPS_STATUS_POWER_SOURCE_VIN_3P3 1 +#define TPS_STATUS_POWER_SOURCE_DEAD_BAT 2 +#define TPS_STATUS_POWER_SOURCE_VBUS 3 + +#define TPS_STATUS_VBUS_STATUS_VSAFE0V 0 +#define TPS_STATUS_VBUS_STATUS_VSAFE5V 1 +#define TPS_STATUS_VBUS_STATUS_PD 2 +#define TPS_STATUS_VBUS_STATUS_FAULT 3 + +#define TPS_STATUS_USB_HOST_PRESENT_NO 0 +#define TPS_STATUS_USB_HOST_PRESENT_PD_NO_USB 1 +#define TPS_STATUS_USB_HOST_PRESENT_NO_PD 2 +#define TPS_STATUS_USB_HOST_PRESENT_PD_USB 3 + +#define TPS_STATUS_LEGACY_NO 0 +#define TPS_STATUS_LEGACY_SINK 1 +#define TPS_STATUS_LEGACY_SOURCE 2 + +/* TPS_REG_INT_* bits */ +#define TPS_REG_INT_USER_VID_ALT_MODE_OTHER_VDM BIT_ULL(27+32) +#define TPS_REG_INT_USER_VID_ALT_MODE_ATTN_VDM BIT_ULL(26+32) +#define TPS_REG_INT_USER_VID_ALT_MODE_EXIT BIT_ULL(25+32) +#define TPS_REG_INT_USER_VID_ALT_MODE_ENTERED BIT_ULL(24+32) +#define TPS_REG_INT_EXIT_MODES_COMPLETE BIT_ULL(20+32) +#define TPS_REG_INT_DISCOVER_MODES_COMPLETE BIT_ULL(19+32) +#define TPS_REG_INT_VDM_MSG_SENT BIT_ULL(18+32) +#define TPS_REG_INT_VDM_ENTERED_MODE BIT_ULL(17+32) +#define TPS_REG_INT_ERROR_UNABLE_TO_SOURCE BIT_ULL(14+32) +#define TPS_REG_INT_SRC_TRANSITION BIT_ULL(10+32) +#define TPS_REG_INT_ERROR_DISCHARGE_FAILED BIT_ULL(9+32) +#define TPS_REG_INT_ERROR_MESSAGE_DATA BIT_ULL(7+32) +#define TPS_REG_INT_ERROR_PROTOCOL_ERROR BIT_ULL(6+32) +#define TPS_REG_INT_ERROR_MISSING_GET_CAP_MESSAGE BIT_ULL(4+32) +#define TPS_REG_INT_ERROR_POWER_EVENT_OCCURRED BIT_ULL(3+32) +#define TPS_REG_INT_ERROR_CAN_PROVIDE_PWR_LATER BIT_ULL(2+32) +#define TPS_REG_INT_ERROR_CANNOT_PROVIDE_PWR BIT_ULL(1+32) +#define TPS_REG_INT_ERROR_DEVICE_INCOMPATIBLE BIT_ULL(0+32) +#define TPS_REG_INT_CMD2_COMPLETE BIT(31) +#define TPS_REG_INT_CMD1_COMPLETE BIT(30) +#define TPS_REG_INT_ADC_HIGH_THRESHOLD BIT(29) +#define TPS_REG_INT_ADC_LOW_THRESHOLD BIT(28) +#define TPS_REG_INT_PD_STATUS_UPDATE BIT(27) +#define TPS_REG_INT_STATUS_UPDATE BIT(26) +#define TPS_REG_INT_DATA_STATUS_UPDATE BIT(25) +#define TPS_REG_INT_POWER_STATUS_UPDATE BIT(24) +#define TPS_REG_INT_PP_SWITCH_CHANGED BIT(23) +#define TPS_REG_INT_HIGH_VOLTAGE_WARNING BIT(22) +#define TPS_REG_INT_USB_HOST_PRESENT_NO_LONGER BIT(21) +#define TPS_REG_INT_USB_HOST_PRESENT BIT(20) +#define TPS_REG_INT_GOTO_MIN_RECEIVED BIT(19) +#define TPS_REG_INT_PR_SWAP_REQUESTED BIT(17) +#define TPS_REG_INT_SINK_CAP_MESSAGE_READY BIT(15) +#define TPS_REG_INT_SOURCE_CAP_MESSAGE_READY BIT(14) +#define TPS_REG_INT_NEW_CONTRACT_AS_PROVIDER BIT(13) +#define TPS_REG_INT_NEW_CONTRACT_AS_CONSUMER BIT(12) +#define TPS_REG_INT_VDM_RECEIVED BIT(11) +#define TPS_REG_INT_ATTENTION_RECEIVED BIT(10) +#define TPS_REG_INT_OVERCURRENT BIT(9) +#define TPS_REG_INT_BIST BIT(8) +#define TPS_REG_INT_RDO_RECEIVED_FROM_SINK BIT(7) +#define TPS_REG_INT_DR_SWAP_COMPLETE BIT(5) +#define TPS_REG_INT_PR_SWAP_COMPLETE BIT(4) +#define TPS_REG_INT_PLUG_EVENT BIT(3) +#define TPS_REG_INT_HARD_RESET BIT(1) +#define TPS_REG_INT_PD_SOFT_RESET BIT(0) + +/* TPS_REG_POWER_STATUS bits */ +#define TPS_POWER_STATUS_CONNECTION(x) TPS_FIELD_GET(BIT(0), (x)) +#define TPS_POWER_STATUS_SOURCESINK(x) TPS_FIELD_GET(BIT(1), (x)) +#define TPS_POWER_STATUS_BC12_DET(x) TPS_FIELD_GET(BIT(2), (x)) + +#define TPS_POWER_STATUS_TYPEC_CURRENT_MASK GENMASK(3, 2) +#define TPS_POWER_STATUS_PWROPMODE(p) TPS_FIELD_GET(TPS_POWER_STATUS_TYPEC_CURRENT_MASK, (p)) +#define TPS_POWER_STATUS_BC12_STATUS_MASK GENMASK(6, 5) +#define TPS_POWER_STATUS_BC12_STATUS(p) TPS_FIELD_GET(TPS_POWER_STATUS_BC12_STATUS_MASK, (p)) + +#define TPS_POWER_STATUS_TYPEC_CURRENT_USB 0 +#define TPS_POWER_STATUS_TYPEC_CURRENT_1A5 1 +#define TPS_POWER_STATUS_TYPEC_CURRENT_3A0 2 +#define TPS_POWER_STATUS_TYPEC_CURRENT_PD 3 + +#define TPS_POWER_STATUS_BC12_STATUS_SDP 0 +#define TPS_POWER_STATUS_BC12_STATUS_CDP 2 +#define TPS_POWER_STATUS_BC12_STATUS_DCP 3 + +/* TPS_REG_DATA_STATUS bits */ +#define TPS_DATA_STATUS_DATA_CONNECTION BIT(0) +#define TPS_DATA_STATUS_UPSIDE_DOWN BIT(1) +#define TPS_DATA_STATUS_ACTIVE_CABLE BIT(2) +#define TPS_DATA_STATUS_USB2_CONNECTION BIT(4) +#define TPS_DATA_STATUS_USB3_CONNECTION BIT(5) +#define TPS_DATA_STATUS_USB3_GEN2 BIT(6) +#define TPS_DATA_STATUS_USB_DATA_ROLE BIT(7) +#define TPS_DATA_STATUS_DP_CONNECTION BIT(8) +#define TPS_DATA_STATUS_DP_SINK BIT(9) +#define TPS_DATA_STATUS_TBT_CONNECTION BIT(16) +#define TPS_DATA_STATUS_TBT_TYPE BIT(17) +#define TPS_DATA_STATUS_OPTICAL_CABLE BIT(18) +#define TPS_DATA_STATUS_ACTIVE_LINK_TRAIN BIT(20) +#define TPS_DATA_STATUS_FORCE_LSX BIT(23) +#define TPS_DATA_STATUS_POWER_MISMATCH BIT(24) + +#define TPS_DATA_STATUS_DP_PIN_ASSIGNMENT_MASK GENMASK(11, 10) +#define TPS_DATA_STATUS_DP_PIN_ASSIGNMENT(x) \ + TPS_FIELD_GET(TPS_DATA_STATUS_DP_PIN_ASSIGNMENT_MASK, (x)) +#define TPS_DATA_STATUS_TBT_CABLE_SPEED_MASK GENMASK(27, 25) +#define TPS_DATA_STATUS_TBT_CABLE_SPEED \ + TPS_FIELD_GET(TPS_DATA_STATUS_TBT_CABLE_SPEED_MASK, (x)) +#define TPS_DATA_STATUS_TBT_CABLE_GEN_MASK GENMASK(29, 28) +#define TPS_DATA_STATUS_TBT_CABLE_GEN \ + TPS_FIELD_GET(TPS_DATA_STATUS_TBT_CABLE_GEN_MASK, (x)) + +/* Map data status to DP spec assignments */ +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT(x) \ + ((TPS_DATA_STATUS_DP_PIN_ASSIGNMENT(x) << 1) | \ + TPS_FIELD_GET(TPS_DATA_STATUS_USB3_CONNECTION, (x))) +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_E 0 +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_F BIT(0) +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_C BIT(1) +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_D (BIT(1) | BIT(0)) +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_A BIT(2) +#define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_B (BIT(2) | BIT(1)) + +#endif /* __TPS6598X_H__ */ diff --git a/drivers/usb/typec/tipd/trace.c b/drivers/usb/typec/tipd/trace.c new file mode 100644 index 0000000000000000000000000000000000000000..016e68048dc244976f433b3d57e2dacee284761f --- /dev/null +++ b/drivers/usb/typec/tipd/trace.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TI TPS6598x USB Power Delivery Controller Trace Support + * + * Copyright (C) 2021, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + */ +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/usb/typec/tipd/trace.h b/drivers/usb/typec/tipd/trace.h new file mode 100644 index 0000000000000000000000000000000000000000..5d09d6f7893000d5f7b1670c7ef53112376b9111 --- /dev/null +++ b/drivers/usb/typec/tipd/trace.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Driver for TI TPS6598x USB Power Delivery controller family + * + * Copyright (C) 2020 Purism SPC + * Author: Guido Günther <agx@sigxcpu.org> + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM tps6598x + +#if !defined(_TPS6598X_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _TPS6598X_TRACE_H_ + +#include "tps6598x.h" + +#include <linux/stringify.h> +#include <linux/types.h> +#include <linux/tracepoint.h> + +#define show_irq_flags(flags) \ + __print_flags_u64(flags, "|", \ + { TPS_REG_INT_PD_SOFT_RESET, "PD_SOFT_RESET" }, \ + { TPS_REG_INT_HARD_RESET, "HARD_RESET" }, \ + { TPS_REG_INT_PLUG_EVENT, "PLUG_EVENT" }, \ + { TPS_REG_INT_PR_SWAP_COMPLETE, "PR_SWAP_COMPLETE" }, \ + { TPS_REG_INT_DR_SWAP_COMPLETE, "DR_SWAP_COMPLETE" }, \ + { TPS_REG_INT_RDO_RECEIVED_FROM_SINK, "RDO_RECEIVED_FROM_SINK" }, \ + { TPS_REG_INT_BIST, "BIST" }, \ + { TPS_REG_INT_OVERCURRENT, "OVERCURRENT" }, \ + { TPS_REG_INT_ATTENTION_RECEIVED, "ATTENTION_RECEIVED" }, \ + { TPS_REG_INT_VDM_RECEIVED, "VDM_RECEIVED" }, \ + { TPS_REG_INT_NEW_CONTRACT_AS_CONSUMER, "NEW_CONTRACT_AS_CONSUMER" }, \ + { TPS_REG_INT_NEW_CONTRACT_AS_PROVIDER, "NEW_CONTRACT_AS_PROVIDER" }, \ + { TPS_REG_INT_SOURCE_CAP_MESSAGE_READY, "SOURCE_CAP_MESSAGE_READY" }, \ + { TPS_REG_INT_SINK_CAP_MESSAGE_READY, "SINK_CAP_MESSAGE_READY" }, \ + { TPS_REG_INT_PR_SWAP_REQUESTED, "PR_SWAP_REQUESTED" }, \ + { TPS_REG_INT_GOTO_MIN_RECEIVED, "GOTO_MIN_RECEIVED" }, \ + { TPS_REG_INT_USB_HOST_PRESENT, "USB_HOST_PRESENT" }, \ + { TPS_REG_INT_USB_HOST_PRESENT_NO_LONGER, "USB_HOST_PRESENT_NO_LONGER" }, \ + { TPS_REG_INT_HIGH_VOLTAGE_WARNING, "HIGH_VOLTAGE_WARNING" }, \ + { TPS_REG_INT_PP_SWITCH_CHANGED, "PP_SWITCH_CHANGED" }, \ + { TPS_REG_INT_POWER_STATUS_UPDATE, "POWER_STATUS_UPDATE" }, \ + { TPS_REG_INT_DATA_STATUS_UPDATE, "DATA_STATUS_UPDATE" }, \ + { TPS_REG_INT_STATUS_UPDATE, "STATUS_UPDATE" }, \ + { TPS_REG_INT_PD_STATUS_UPDATE, "PD_STATUS_UPDATE" }, \ + { TPS_REG_INT_ADC_LOW_THRESHOLD, "ADC_LOW_THRESHOLD" }, \ + { TPS_REG_INT_ADC_HIGH_THRESHOLD, "ADC_HIGH_THRESHOLD" }, \ + { TPS_REG_INT_CMD1_COMPLETE, "CMD1_COMPLETE" }, \ + { TPS_REG_INT_CMD2_COMPLETE, "CMD2_COMPLETE" }, \ + { TPS_REG_INT_ERROR_DEVICE_INCOMPATIBLE, "ERROR_DEVICE_INCOMPATIBLE" }, \ + { TPS_REG_INT_ERROR_CANNOT_PROVIDE_PWR, "ERROR_CANNOT_PROVIDE_PWR" }, \ + { TPS_REG_INT_ERROR_CAN_PROVIDE_PWR_LATER, "ERROR_CAN_PROVIDE_PWR_LATER" }, \ + { TPS_REG_INT_ERROR_POWER_EVENT_OCCURRED, "ERROR_POWER_EVENT_OCCURRED" }, \ + { TPS_REG_INT_ERROR_MISSING_GET_CAP_MESSAGE, "ERROR_MISSING_GET_CAP_MESSAGE" }, \ + { TPS_REG_INT_ERROR_PROTOCOL_ERROR, "ERROR_PROTOCOL_ERROR" }, \ + { TPS_REG_INT_ERROR_MESSAGE_DATA, "ERROR_MESSAGE_DATA" }, \ + { TPS_REG_INT_ERROR_DISCHARGE_FAILED, "ERROR_DISCHARGE_FAILED" }, \ + { TPS_REG_INT_SRC_TRANSITION, "SRC_TRANSITION" }, \ + { TPS_REG_INT_ERROR_UNABLE_TO_SOURCE, "ERROR_UNABLE_TO_SOURCE" }, \ + { TPS_REG_INT_VDM_ENTERED_MODE, "VDM_ENTERED_MODE" }, \ + { TPS_REG_INT_VDM_MSG_SENT, "VDM_MSG_SENT" }, \ + { TPS_REG_INT_DISCOVER_MODES_COMPLETE, "DISCOVER_MODES_COMPLETE" }, \ + { TPS_REG_INT_EXIT_MODES_COMPLETE, "EXIT_MODES_COMPLETE" }, \ + { TPS_REG_INT_USER_VID_ALT_MODE_ENTERED, "USER_VID_ALT_MODE_ENTERED" }, \ + { TPS_REG_INT_USER_VID_ALT_MODE_EXIT, "USER_VID_ALT_MODE_EXIT" }, \ + { TPS_REG_INT_USER_VID_ALT_MODE_ATTN_VDM, "USER_VID_ALT_MODE_ATTN_VDM" }, \ + { TPS_REG_INT_USER_VID_ALT_MODE_OTHER_VDM, "USER_VID_ALT_MODE_OTHER_VDM" }) + +#define TPS6598X_STATUS_FLAGS_MASK (GENMASK(31, 0) ^ (TPS_STATUS_CONN_STATE_MASK | \ + TPS_STATUS_PP_5V0_SWITCH_MASK | \ + TPS_STATUS_PP_HV_SWITCH_MASK | \ + TPS_STATUS_PP_EXT_SWITCH_MASK | \ + TPS_STATUS_PP_CABLE_SWITCH_MASK | \ + TPS_STATUS_POWER_SOURCE_MASK | \ + TPS_STATUS_VBUS_STATUS_MASK | \ + TPS_STATUS_USB_HOST_PRESENT_MASK | \ + TPS_STATUS_LEGACY_MASK)) + +#define show_status_conn_state(status) \ + __print_symbolic(TPS_STATUS_CONN_STATE((status)), \ + { TPS_STATUS_CONN_STATE_CONN_WITH_R_A, "conn-Ra" }, \ + { TPS_STATUS_CONN_STATE_CONN_NO_R_A, "conn-no-Ra" }, \ + { TPS_STATUS_CONN_STATE_NO_CONN_R_A, "no-conn-Ra" }, \ + { TPS_STATUS_CONN_STATE_DEBUG_CONN, "debug" }, \ + { TPS_STATUS_CONN_STATE_AUDIO_CONN, "audio" }, \ + { TPS_STATUS_CONN_STATE_DISABLED, "disabled" }, \ + { TPS_STATUS_CONN_STATE_NO_CONN, "no-conn" }) + +#define show_status_pp_switch_state(status) \ + __print_symbolic(status, \ + { TPS_STATUS_PP_SWITCH_STATE_IN, "in" }, \ + { TPS_STATUS_PP_SWITCH_STATE_OUT, "out" }, \ + { TPS_STATUS_PP_SWITCH_STATE_FAULT, "fault" }, \ + { TPS_STATUS_PP_SWITCH_STATE_DISABLED, "off" }) + +#define show_status_power_sources(status) \ + __print_symbolic(TPS_STATUS_POWER_SOURCE(status), \ + { TPS_STATUS_POWER_SOURCE_VBUS, "vbus" }, \ + { TPS_STATUS_POWER_SOURCE_VIN_3P3, "vin-3p3" }, \ + { TPS_STATUS_POWER_SOURCE_DEAD_BAT, "dead-battery" }, \ + { TPS_STATUS_POWER_SOURCE_UNKNOWN, "unknown" }) + +#define show_status_vbus_status(status) \ + __print_symbolic(TPS_STATUS_VBUS_STATUS(status), \ + { TPS_STATUS_VBUS_STATUS_VSAFE0V, "vSafe0V" }, \ + { TPS_STATUS_VBUS_STATUS_VSAFE5V, "vSafe5V" }, \ + { TPS_STATUS_VBUS_STATUS_PD, "pd" }, \ + { TPS_STATUS_VBUS_STATUS_FAULT, "fault" }) + +#define show_status_usb_host_present(status) \ + __print_symbolic(TPS_STATUS_USB_HOST_PRESENT(status), \ + { TPS_STATUS_USB_HOST_PRESENT_PD_USB, "pd-usb" }, \ + { TPS_STATUS_USB_HOST_PRESENT_NO_PD, "no-pd" }, \ + { TPS_STATUS_USB_HOST_PRESENT_PD_NO_USB, "pd-no-usb" }, \ + { TPS_STATUS_USB_HOST_PRESENT_NO, "no" }) + +#define show_status_legacy(status) \ + __print_symbolic(TPS_STATUS_LEGACY(status), \ + { TPS_STATUS_LEGACY_SOURCE, "source" }, \ + { TPS_STATUS_LEGACY_SINK, "sink" }, \ + { TPS_STATUS_LEGACY_NO, "no" }) + +#define show_status_flags(flags) \ + __print_flags((flags & TPS6598X_STATUS_FLAGS_MASK), "|", \ + { TPS_STATUS_PLUG_PRESENT, "PLUG_PRESENT" }, \ + { TPS_STATUS_PLUG_UPSIDE_DOWN, "UPSIDE_DOWN" }, \ + { TPS_STATUS_PORTROLE, "PORTROLE" }, \ + { TPS_STATUS_DATAROLE, "DATAROLE" }, \ + { TPS_STATUS_VCONN, "VCONN" }, \ + { TPS_STATUS_OVERCURRENT, "OVERCURRENT" }, \ + { TPS_STATUS_GOTO_MIN_ACTIVE, "GOTO_MIN_ACTIVE" }, \ + { TPS_STATUS_BIST, "BIST" }, \ + { TPS_STATUS_HIGH_VOLAGE_WARNING, "HIGH_VOLAGE_WARNING" }, \ + { TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING, "HIGH_LOW_VOLTAGE_WARNING" }) + +#define show_power_status_source_sink(power_status) \ + __print_symbolic(TPS_POWER_STATUS_SOURCESINK(power_status), \ + { 1, "sink" }, \ + { 0, "source" }) + +#define show_power_status_typec_status(power_status) \ + __print_symbolic(TPS_POWER_STATUS_PWROPMODE(power_status), \ + { TPS_POWER_STATUS_TYPEC_CURRENT_PD, "pd" }, \ + { TPS_POWER_STATUS_TYPEC_CURRENT_3A0, "3.0A" }, \ + { TPS_POWER_STATUS_TYPEC_CURRENT_1A5, "1.5A" }, \ + { TPS_POWER_STATUS_TYPEC_CURRENT_USB, "usb" }) + +#define show_power_status_bc12_status(power_status) \ + __print_symbolic(TPS_POWER_STATUS_BC12_STATUS(power_status), \ + { TPS_POWER_STATUS_BC12_STATUS_DCP, "dcp" }, \ + { TPS_POWER_STATUS_BC12_STATUS_CDP, "cdp" }, \ + { TPS_POWER_STATUS_BC12_STATUS_SDP, "sdp" }) + +#define TPS_DATA_STATUS_FLAGS_MASK (GENMASK(31, 0) ^ (TPS_DATA_STATUS_DP_PIN_ASSIGNMENT_MASK | \ + TPS_DATA_STATUS_TBT_CABLE_SPEED_MASK | \ + TPS_DATA_STATUS_TBT_CABLE_GEN_MASK)) + +#define show_data_status_flags(data_status) \ + __print_flags(data_status & TPS_DATA_STATUS_FLAGS_MASK, "|", \ + { TPS_DATA_STATUS_DATA_CONNECTION, "DATA_CONNECTION" }, \ + { TPS_DATA_STATUS_UPSIDE_DOWN, "DATA_UPSIDE_DOWN" }, \ + { TPS_DATA_STATUS_ACTIVE_CABLE, "ACTIVE_CABLE" }, \ + { TPS_DATA_STATUS_USB2_CONNECTION, "USB2_CONNECTION" }, \ + { TPS_DATA_STATUS_USB3_CONNECTION, "USB3_CONNECTION" }, \ + { TPS_DATA_STATUS_USB3_GEN2, "USB3_GEN2" }, \ + { TPS_DATA_STATUS_USB_DATA_ROLE, "USB_DATA_ROLE" }, \ + { TPS_DATA_STATUS_DP_CONNECTION, "DP_CONNECTION" }, \ + { TPS_DATA_STATUS_DP_SINK, "DP_SINK" }, \ + { TPS_DATA_STATUS_TBT_CONNECTION, "TBT_CONNECTION" }, \ + { TPS_DATA_STATUS_TBT_TYPE, "TBT_TYPE" }, \ + { TPS_DATA_STATUS_OPTICAL_CABLE, "OPTICAL_CABLE" }, \ + { TPS_DATA_STATUS_ACTIVE_LINK_TRAIN, "ACTIVE_LINK_TRAIN" }, \ + { TPS_DATA_STATUS_FORCE_LSX, "FORCE_LSX" }, \ + { TPS_DATA_STATUS_POWER_MISMATCH, "POWER_MISMATCH" }) + +#define show_data_status_dp_pin_assignment(data_status) \ + __print_symbolic(TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT(data_status), \ + { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_E, "E" }, \ + { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_F, "F" }, \ + { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_C, "C" }, \ + { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_D, "D" }, \ + { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_A, "A" }, \ + { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_B, "B" }) + +#define maybe_show_data_status_dp_pin_assignment(data_status) \ + (data_status & TPS_DATA_STATUS_DP_CONNECTION ? \ + show_data_status_dp_pin_assignment(data_status) : "") + +TRACE_EVENT(tps6598x_irq, + TP_PROTO(u64 event1, + u64 event2), + TP_ARGS(event1, event2), + + TP_STRUCT__entry( + __field(u64, event1) + __field(u64, event2) + ), + + TP_fast_assign( + __entry->event1 = event1; + __entry->event2 = event2; + ), + + TP_printk("event1=%s, event2=%s", + show_irq_flags(__entry->event1), + show_irq_flags(__entry->event2)) +); + +TRACE_EVENT(tps6598x_status, + TP_PROTO(u32 status), + TP_ARGS(status), + + TP_STRUCT__entry( + __field(u32, status) + ), + + TP_fast_assign( + __entry->status = status; + ), + + TP_printk("conn: %s, pp_5v0: %s, pp_hv: %s, pp_ext: %s, pp_cable: %s, " + "pwr-src: %s, vbus: %s, usb-host: %s, legacy: %s, flags: %s", + show_status_conn_state(__entry->status), + show_status_pp_switch_state(TPS_STATUS_PP_5V0_SWITCH(__entry->status)), + show_status_pp_switch_state(TPS_STATUS_PP_HV_SWITCH(__entry->status)), + show_status_pp_switch_state(TPS_STATUS_PP_EXT_SWITCH(__entry->status)), + show_status_pp_switch_state(TPS_STATUS_PP_CABLE_SWITCH(__entry->status)), + show_status_power_sources(__entry->status), + show_status_vbus_status(__entry->status), + show_status_usb_host_present(__entry->status), + show_status_legacy(__entry->status), + show_status_flags(__entry->status) + ) +); + +TRACE_EVENT(tps6598x_power_status, + TP_PROTO(u16 power_status), + TP_ARGS(power_status), + + TP_STRUCT__entry( + __field(u16, power_status) + ), + + TP_fast_assign( + __entry->power_status = power_status; + ), + + TP_printk("conn: %d, pwr-role: %s, typec: %s, bc: %s", + !!TPS_POWER_STATUS_CONNECTION(__entry->power_status), + show_power_status_source_sink(__entry->power_status), + show_power_status_typec_status(__entry->power_status), + show_power_status_bc12_status(__entry->power_status) + ) +); + +TRACE_EVENT(tps6598x_data_status, + TP_PROTO(u32 data_status), + TP_ARGS(data_status), + + TP_STRUCT__entry( + __field(u32, data_status) + ), + + TP_fast_assign( + __entry->data_status = data_status; + ), + + TP_printk("%s%s%s", + show_data_status_flags(__entry->data_status), + __entry->data_status & TPS_DATA_STATUS_DP_CONNECTION ? ", DP pinout " : "", + maybe_show_data_status_dp_pin_assignment(__entry->data_status) + ) +); + +#endif /* _TPS6598X_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 244270755ae61f999d952f281eb8aee8c5fb67cf..282c3c825c136d984487afdba97c339515830335 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -63,7 +63,7 @@ static int ucsi_read_error(struct ucsi *ucsi) u16 error; int ret; - /* Acknowlege the command that failed */ + /* Acknowledge the command that failed */ ret = ucsi_acknowledge_command(ucsi); if (ret) return ret; diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c index f7633ee655a17bed82b5baf9cffefc69b6ffd7f0..d1cf6b51bf85dc7cc6e2ed6105cc5300f67ce9ca 100644 --- a/drivers/usb/usbip/vudc_sysfs.c +++ b/drivers/usb/usbip/vudc_sysfs.c @@ -156,12 +156,14 @@ static ssize_t usbip_sockfd_store(struct device *dev, tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx"); if (IS_ERR(tcp_rx)) { sockfd_put(socket); + mutex_unlock(&udc->ud.sysfs_lock); return -EINVAL; } tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx"); if (IS_ERR(tcp_tx)) { kthread_stop(tcp_rx); sockfd_put(socket); + mutex_unlock(&udc->ud.sysfs_lock); return -EINVAL; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 962c12be9774192fab8bcda7ed75140396ace8e1..39258f9d36a0e44ee01dfbe8ac71e871df923ea4 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -79,7 +79,6 @@ static struct uni_pagedir *vgacon_uni_pagedir; static int vgacon_refcount; /* Description of the hardware situation */ -static bool vga_init_done; static unsigned long vga_vram_base __read_mostly; /* Base of video memory */ static unsigned long vga_vram_end __read_mostly; /* End of video memory */ static unsigned int vga_vram_size __read_mostly; /* Size of video memory */ @@ -96,7 +95,7 @@ static bool vga_is_gfx; static bool vga_512_chars; static int vga_video_font_height; static int vga_scan_lines __read_mostly; -static unsigned int vga_rolled_over; +static unsigned int vga_rolled_over; /* last vc_origin offset before wrap */ static bool vgacon_text_mode_force; static bool vga_hardscroll_enabled; @@ -359,8 +358,6 @@ static const char *vgacon_startup(void) vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH; vgacon_yres = vga_scan_lines; - vga_init_done = true; - return display_desc; } diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c index 757d5c3f620b78bd55d7c7ebdb87849868dfe25c..ff09e57f3c3801eac7832b14fd1704907c0b84f0 100644 --- a/drivers/video/fbdev/core/fbcmap.c +++ b/drivers/video/fbdev/core/fbcmap.c @@ -101,17 +101,17 @@ int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags) if (!len) return 0; - cmap->red = kmalloc(size, flags); + cmap->red = kzalloc(size, flags); if (!cmap->red) goto fail; - cmap->green = kmalloc(size, flags); + cmap->green = kzalloc(size, flags); if (!cmap->green) goto fail; - cmap->blue = kmalloc(size, flags); + cmap->blue = kzalloc(size, flags); if (!cmap->blue) goto fail; if (transp) { - cmap->transp = kmalloc(size, flags); + cmap->transp = kzalloc(size, flags); if (!cmap->transp) goto fail; } else { diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 4dc9077dd2ac04d07401e210b13fcb052b0f6ab1..a7e6eea2c4a1d09ca364f84e6c2961967f514047 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -308,7 +308,7 @@ static inline int synthvid_send(struct hv_device *hdev, VM_PKT_DATA_INBAND, 0); if (ret) - pr_err("Unable to send packet via vmbus\n"); + pr_err_ratelimited("Unable to send packet via vmbus; error %d\n", ret); return ret; } diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c index 7804a2492ad70c775c4a4f9b58bab80b6ae879c2..0d002a355a93627d7eed4f3902ffe690a76cb8ec 100644 --- a/drivers/virt/acrn/vm.c +++ b/drivers/virt/acrn/vm.c @@ -94,7 +94,7 @@ int acrn_vm_destroy(struct acrn_vm *vm) } /** - * acrn_inject_msi() - Inject a MSI interrupt into a User VM + * acrn_msi_inject() - Inject a MSI interrupt into a User VM * @vm: User VM * @msi_addr: The MSI address * @msi_data: The MSI data diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c index c281fe5ed68875eab8bbb1d22fae02650b2d4f31..9dcb5a54f7fc411990de615910c980193b9a7524 100644 --- a/drivers/w1/slaves/w1_ds2780.c +++ b/drivers/w1/slaves/w1_ds2780.c @@ -90,7 +90,7 @@ static ssize_t w1_slave_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 device *dev = kobj_to_dev(kobj); return w1_ds2780_io(dev, buf, off, count, 0); } diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c index f0d393ae070b87a7b3bbd10f5456fb4114793984..2cb7c020b6075eb2135d8eec760cea5d551767d1 100644 --- a/drivers/w1/slaves/w1_ds2781.c +++ b/drivers/w1/slaves/w1_ds2781.c @@ -87,7 +87,7 @@ static ssize_t w1_slave_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 device *dev = kobj_to_dev(kobj); return w1_ds2781_io(dev, buf, off, count, 0); } diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c index 206186db727d4f184ca99cfc538e508cebcdd8d1..6b5d12ba1b6551fdb102338f501e816f26e4275e 100644 --- a/drivers/w1/slaves/w1_ds2805.c +++ b/drivers/w1/slaves/w1_ds2805.c @@ -291,20 +291,7 @@ static struct w1_family w1_family_0d = { .fops = &w1_f0d_fops, }; -static int __init w1_f0d_init(void) -{ - pr_info("%s()\n", __func__); - return w1_register_family(&w1_family_0d); -} - -static void __exit w1_f0d_fini(void) -{ - pr_info("%s()\n", __func__); - w1_unregister_family(&w1_family_0d); -} - -module_init(w1_f0d_init); -module_exit(w1_f0d_fini); +module_w1_family(w1_family_0d); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andrew Worsley amworsley@gmail.com"); diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c index 6b00db7169ab311d3f0c9b707fd0a6422fbbb058..aed10b72fc9988c1e937970762368271acced9f7 100644 --- a/drivers/w1/slaves/w1_ds28e17.c +++ b/drivers/w1/slaves/w1_ds28e17.c @@ -752,18 +752,4 @@ static struct w1_family w1_family_19 = { .fops = &w1_f19_fops, }; - -/* Module init and remove functions. */ -static int __init w1_f19_init(void) -{ - return w1_register_family(&w1_family_19); -} - -static void __exit w1_f19_fini(void) -{ - w1_unregister_family(&w1_family_19); -} - -module_init(w1_f19_init); -module_exit(w1_f19_fini); - +module_w1_family(w1_family_19); diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 976eea28f268a62f3eb8332f971161f3ed4ad44f..9d08a1c9c44564b1ebf28863f1eb04417110ec35 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -63,8 +63,8 @@ static u16 bulk_read_device_counter; /* =0 as per C standard */ #define EEPROM_CMD_READ "restore" /* cmd for read eeprom sysfs */ #define BULK_TRIGGER_CMD "trigger" /* cmd to trigger a bulk read */ -#define MIN_TEMP -55 /* min temperature that can be mesured */ -#define MAX_TEMP 125 /* max temperature that can be mesured */ +#define MIN_TEMP -55 /* min temperature that can be measured */ +#define MAX_TEMP 125 /* max temperature that can be measured */ /* Allowed values for sysfs conv_time attribute */ #define CONV_TIME_DEFAULT 0 @@ -906,8 +906,7 @@ static inline int temperature_from_RAM(struct w1_slave *sl, u8 rom[9]) static inline s8 int_to_short(int i) { /* Prepare to cast to short by eliminating out of range values */ - i = i > MAX_TEMP ? MAX_TEMP : i; - i = i < MIN_TEMP ? MIN_TEMP : i; + i = clamp(i, MIN_TEMP, MAX_TEMP); return (s8) i; } diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c index 765577f11c8db371ff3b8d654a8dc3bc73fb9041..28a24caa2627c924416ef628cc548fa6383d2da2 100644 --- a/drivers/watchdog/npcm_wdt.c +++ b/drivers/watchdog/npcm_wdt.c @@ -229,6 +229,7 @@ static int npcm_wdt_probe(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id npcm_wdt_match[] = { + {.compatible = "nuvoton,wpcm450-wdt"}, {.compatible = "nuvoton,npcm750-wdt"}, {}, }; diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c index 258dfcf9cbdada75e1b4073d1dc818ca9d913c22..2b9017e1cd91f8db5f70d26d0bacf887acac18a6 100644 --- a/drivers/watchdog/retu_wdt.c +++ b/drivers/watchdog/retu_wdt.c @@ -8,6 +8,7 @@ * Rewritten by Aaro Koskinen. */ +#include <linux/devm-helpers.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/device.h> @@ -127,9 +128,12 @@ static int retu_wdt_probe(struct platform_device *pdev) wdev->rdev = rdev; wdev->dev = &pdev->dev; - INIT_DELAYED_WORK(&wdev->ping_work, retu_wdt_ping_work); + ret = devm_delayed_work_autocancel(&pdev->dev, &wdev->ping_work, + retu_wdt_ping_work); + if (ret) + return ret; - ret = watchdog_register_device(retu_wdt); + ret = devm_watchdog_register_device(&pdev->dev, retu_wdt); if (ret < 0) return ret; @@ -138,25 +142,11 @@ static int retu_wdt_probe(struct platform_device *pdev) else retu_wdt_ping_enable(wdev); - platform_set_drvdata(pdev, retu_wdt); - - return 0; -} - -static int retu_wdt_remove(struct platform_device *pdev) -{ - struct watchdog_device *wdog = platform_get_drvdata(pdev); - struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog); - - watchdog_unregister_device(wdog); - cancel_delayed_work_sync(&wdev->ping_work); - return 0; } static struct platform_driver retu_wdt_driver = { .probe = retu_wdt_probe, - .remove = retu_wdt_remove, .driver = { .name = "retu-wdt", }, diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index ea0efd290c3722c34a7f788b724bbbc77493b3fb..5f1ce59b44b95c5bdd4aad5a04dcd61559585eca 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -238,37 +238,6 @@ config XEN_PRIVCMD depends on XEN default m -config XEN_STUB - bool "Xen stub drivers" - depends on XEN && X86_64 && BROKEN - help - Allow kernel to install stub drivers, to reserve space for Xen drivers, - i.e. memory hotplug and cpu hotplug, and to block native drivers loaded, - so that real Xen drivers can be modular. - - To enable Xen features like cpu and memory hotplug, select Y here. - -config XEN_ACPI_HOTPLUG_MEMORY - tristate "Xen ACPI memory hotplug" - depends on XEN_DOM0 && XEN_STUB && ACPI - help - This is Xen ACPI memory hotplug. - - Currently Xen only support ACPI memory hot-add. If you want - to hot-add memory at runtime (the hot-added memory cannot be - removed until machine stop), select Y/M here, otherwise select N. - -config XEN_ACPI_HOTPLUG_CPU - tristate "Xen ACPI cpu hotplug" - depends on XEN_DOM0 && XEN_STUB && ACPI - select ACPI_CONTAINER - help - Xen ACPI cpu enumerating and hotplugging - - For hotplugging, currently Xen only support ACPI cpu hotadd. - If you want to hotadd cpu at runtime (the hotadded cpu cannot - be removed until machine stop), select Y/M here. - config XEN_ACPI_PROCESSOR tristate "Xen ACPI processor" depends on XEN && XEN_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index c3621b9f4012f4128522e88fecb510f0e59c005a..3434593455b2884984004e203d6225bafc0fcc6b 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -26,9 +26,6 @@ obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o -obj-$(CONFIG_XEN_STUB) += xen-stub.o -obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o -obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o obj-$(CONFIG_XEN_EFI) += efi.o obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index cdc6daa7a9f66f9a534e619af244bc8843bcccef..1bcdd52277716edebc9ad4e4807b87a5c181f715 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c @@ -345,41 +345,6 @@ static irqreturn_t xen_pcpu_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* Sync with Xen hypervisor after cpu hotadded */ -void xen_pcpu_hotplug_sync(void) -{ - schedule_work(&xen_pcpu_work); -} -EXPORT_SYMBOL_GPL(xen_pcpu_hotplug_sync); - -/* - * For hypervisor presented cpu, return logic cpu id; - * For hypervisor non-presented cpu, return -ENODEV. - */ -int xen_pcpu_id(uint32_t acpi_id) -{ - int cpu_id = 0, max_id = 0; - struct xen_platform_op op; - - op.cmd = XENPF_get_cpuinfo; - while (cpu_id <= max_id) { - op.u.pcpu_info.xen_cpuid = cpu_id; - if (HYPERVISOR_platform_op(&op)) { - cpu_id++; - continue; - } - - if (acpi_id == op.u.pcpu_info.acpi_id) - return cpu_id; - if (op.u.pcpu_info.max_present > max_id) - max_id = op.u.pcpu_info.max_present; - cpu_id++; - } - - return -ENODEV; -} -EXPORT_SYMBOL_GPL(xen_pcpu_id); - static int __init xen_pcpu_init(void) { int irq, ret; diff --git a/drivers/xen/time.c b/drivers/xen/time.c index 108edbcbc040f753af3ec5df375cf763bbd5eeb1..152dd33bb223673a59e1ff4a74d3bb2bd2bad3bd 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c @@ -7,6 +7,7 @@ #include <linux/math64.h> #include <linux/gfp.h> #include <linux/slab.h> +#include <linux/static_call.h> #include <asm/paravirt.h> #include <asm/xen/hypervisor.h> @@ -175,7 +176,7 @@ void __init xen_time_setup_guest(void) xen_runstate_remote = !HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_runstate_update_flag); - pv_ops.time.steal_clock = xen_steal_clock; + static_call_update(pv_steal_clock, xen_steal_clock); static_key_slow_inc(¶virt_steal_enabled); if (xen_runstate_remote) diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c deleted file mode 100644 index 00ab1ece02e5610e8914e627de7c9fbac47c8ff2..0000000000000000000000000000000000000000 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ /dev/null @@ -1,446 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 Intel Corporation - * Author: Liu Jinsong <jinsong.liu@intel.com> - * Author: Jiang Yunhong <yunhong.jiang@intel.com> - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/cpu.h> -#include <linux/acpi.h> -#include <linux/uaccess.h> -#include <acpi/processor.h> -#include <xen/acpi.h> -#include <xen/interface/platform.h> -#include <asm/xen/hypercall.h> - -#define PREFIX "ACPI:xen_cpu_hotplug:" - -#define INSTALL_NOTIFY_HANDLER 0 -#define UNINSTALL_NOTIFY_HANDLER 1 - -static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr); - -/* -------------------------------------------------------------------------- - Driver Interface --------------------------------------------------------------------------- */ - -static int xen_acpi_processor_enable(struct acpi_device *device) -{ - acpi_status status = 0; - unsigned long long value; - union acpi_object object = { 0 }; - struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; - struct acpi_processor *pr = acpi_driver_data(device); - - if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { - /* Declared with "Processor" statement; match ProcessorID */ - status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) { - pr_err(PREFIX "Evaluating processor object\n"); - return -ENODEV; - } - - pr->acpi_id = object.processor.proc_id; - } else { - /* Declared with "Device" statement; match _UID */ - status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, - NULL, &value); - if (ACPI_FAILURE(status)) { - pr_err(PREFIX "Evaluating processor _UID\n"); - return -ENODEV; - } - - pr->acpi_id = value; - } - - pr->id = xen_pcpu_id(pr->acpi_id); - - if (invalid_logical_cpuid(pr->id)) - /* This cpu is not presented at hypervisor, try to hotadd it */ - if (ACPI_FAILURE(xen_acpi_cpu_hotadd(pr))) { - pr_err(PREFIX "Hotadd CPU (acpi_id = %d) failed.\n", - pr->acpi_id); - return -ENODEV; - } - - return 0; -} - -static int xen_acpi_processor_add(struct acpi_device *device) -{ - int ret; - struct acpi_processor *pr; - - if (!device) - return -EINVAL; - - pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); - if (!pr) - return -ENOMEM; - - pr->handle = device->handle; - strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); - device->driver_data = pr; - - ret = xen_acpi_processor_enable(device); - if (ret) - pr_err(PREFIX "Error when enabling Xen processor\n"); - - return ret; -} - -static int xen_acpi_processor_remove(struct acpi_device *device) -{ - struct acpi_processor *pr; - - if (!device) - return -EINVAL; - - pr = acpi_driver_data(device); - if (!pr) - return -EINVAL; - - kfree(pr); - return 0; -} - -/*-------------------------------------------------------------- - Acpi processor hotplug support ---------------------------------------------------------------*/ - -static int is_processor_present(acpi_handle handle) -{ - acpi_status status; - unsigned long long sta = 0; - - - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - - if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) - return 1; - - /* - * _STA is mandatory for a processor that supports hot plug - */ - if (status == AE_NOT_FOUND) - pr_info(PREFIX "Processor does not support hot plug\n"); - else - pr_info(PREFIX "Processor Device is not present"); - return 0; -} - -static int xen_apic_id(acpi_handle handle) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - struct acpi_madt_local_apic *lapic; - int apic_id; - - if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) - return -EINVAL; - - if (!buffer.length || !buffer.pointer) - return -EINVAL; - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_BUFFER || - obj->buffer.length < sizeof(*lapic)) { - kfree(buffer.pointer); - return -EINVAL; - } - - lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; - - if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || - !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { - kfree(buffer.pointer); - return -EINVAL; - } - - apic_id = (uint32_t)lapic->id; - kfree(buffer.pointer); - buffer.length = ACPI_ALLOCATE_BUFFER; - buffer.pointer = NULL; - - return apic_id; -} - -static int xen_hotadd_cpu(struct acpi_processor *pr) -{ - int cpu_id, apic_id, pxm; - struct xen_platform_op op; - - apic_id = xen_apic_id(pr->handle); - if (apic_id < 0) { - pr_err(PREFIX "Failed to get apic_id for acpi_id %d\n", - pr->acpi_id); - return -ENODEV; - } - - pxm = xen_acpi_get_pxm(pr->handle); - if (pxm < 0) { - pr_err(PREFIX "Failed to get _PXM for acpi_id %d\n", - pr->acpi_id); - return pxm; - } - - op.cmd = XENPF_cpu_hotadd; - op.u.cpu_add.apic_id = apic_id; - op.u.cpu_add.acpi_id = pr->acpi_id; - op.u.cpu_add.pxm = pxm; - - cpu_id = HYPERVISOR_platform_op(&op); - if (cpu_id < 0) - pr_err(PREFIX "Failed to hotadd CPU for acpi_id %d\n", - pr->acpi_id); - - return cpu_id; -} - -static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr) -{ - if (!is_processor_present(pr->handle)) - return AE_ERROR; - - pr->id = xen_hotadd_cpu(pr); - if (invalid_logical_cpuid(pr->id)) - return AE_ERROR; - - /* - * Sync with Xen hypervisor, providing new /sys/.../xen_cpuX - * interface after cpu hotadded. - */ - xen_pcpu_hotplug_sync(); - - return AE_OK; -} - -static int acpi_processor_device_remove(struct acpi_device *device) -{ - pr_debug(PREFIX "Xen does not support CPU hotremove\n"); - - return -ENOSYS; -} - -static void acpi_processor_hotplug_notify(acpi_handle handle, - u32 event, void *data) -{ - struct acpi_processor *pr; - struct acpi_device *device = NULL; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ - int result; - - acpi_scan_lock_acquire(); - - switch (event) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Processor driver received %s event\n", - (event == ACPI_NOTIFY_BUS_CHECK) ? - "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK")); - - if (!is_processor_present(handle)) - break; - - acpi_bus_get_device(handle, &device); - if (acpi_device_enumerated(device)) - break; - - result = acpi_bus_scan(handle); - if (result) { - pr_err(PREFIX "Unable to add the device\n"); - break; - } - device = NULL; - acpi_bus_get_device(handle, &device); - if (!acpi_device_enumerated(device)) { - pr_err(PREFIX "Missing device object\n"); - break; - } - ost_code = ACPI_OST_SC_SUCCESS; - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "received ACPI_NOTIFY_EJECT_REQUEST\n")); - - if (acpi_bus_get_device(handle, &device)) { - pr_err(PREFIX "Device don't exist, dropping EJECT\n"); - break; - } - pr = acpi_driver_data(device); - if (!pr) { - pr_err(PREFIX "Driver data is NULL, dropping EJECT\n"); - break; - } - - /* - * TBD: implement acpi_processor_device_remove if Xen support - * CPU hotremove in the future. - */ - acpi_processor_device_remove(device); - break; - - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); - - /* non-hotplug event; possibly handled by other handler */ - goto out; - } - - (void) acpi_evaluate_ost(handle, event, ost_code, NULL); - -out: - acpi_scan_lock_release(); -} - -static acpi_status is_processor_device(acpi_handle handle) -{ - struct acpi_device_info *info; - char *hid; - acpi_status status; - - status = acpi_get_object_info(handle, &info); - if (ACPI_FAILURE(status)) - return status; - - if (info->type == ACPI_TYPE_PROCESSOR) { - kfree(info); - return AE_OK; /* found a processor object */ - } - - if (!(info->valid & ACPI_VALID_HID)) { - kfree(info); - return AE_ERROR; - } - - hid = info->hardware_id.string; - if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) { - kfree(info); - return AE_ERROR; - } - - kfree(info); - return AE_OK; /* found a processor device object */ -} - -static acpi_status -processor_walk_namespace_cb(acpi_handle handle, - u32 lvl, void *context, void **rv) -{ - acpi_status status; - int *action = context; - - status = is_processor_device(handle); - if (ACPI_FAILURE(status)) - return AE_OK; /* not a processor; continue to walk */ - - switch (*action) { - case INSTALL_NOTIFY_HANDLER: - acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - acpi_processor_hotplug_notify, - NULL); - break; - case UNINSTALL_NOTIFY_HANDLER: - acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - acpi_processor_hotplug_notify); - break; - default: - break; - } - - /* found a processor; skip walking underneath */ - return AE_CTRL_DEPTH; -} - -static -void acpi_processor_install_hotplug_notify(void) -{ - int action = INSTALL_NOTIFY_HANDLER; - acpi_walk_namespace(ACPI_TYPE_ANY, - ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - processor_walk_namespace_cb, NULL, &action, NULL); -} - -static -void acpi_processor_uninstall_hotplug_notify(void) -{ - int action = UNINSTALL_NOTIFY_HANDLER; - acpi_walk_namespace(ACPI_TYPE_ANY, - ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - processor_walk_namespace_cb, NULL, &action, NULL); -} - -static const struct acpi_device_id processor_device_ids[] = { - {ACPI_PROCESSOR_OBJECT_HID, 0}, - {ACPI_PROCESSOR_DEVICE_HID, 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, processor_device_ids); - -static struct acpi_driver xen_acpi_processor_driver = { - .name = "processor", - .class = ACPI_PROCESSOR_CLASS, - .ids = processor_device_ids, - .ops = { - .add = xen_acpi_processor_add, - .remove = xen_acpi_processor_remove, - }, -}; - -static int __init xen_acpi_processor_init(void) -{ - int result = 0; - - if (!xen_initial_domain()) - return -ENODEV; - - /* unregister the stub which only used to reserve driver space */ - xen_stub_processor_exit(); - - result = acpi_bus_register_driver(&xen_acpi_processor_driver); - if (result < 0) { - xen_stub_processor_init(); - return result; - } - - acpi_processor_install_hotplug_notify(); - return 0; -} - -static void __exit xen_acpi_processor_exit(void) -{ - if (!xen_initial_domain()) - return; - - acpi_processor_uninstall_hotplug_notify(); - - acpi_bus_unregister_driver(&xen_acpi_processor_driver); - - /* - * stub reserve space again to prevent any chance of native - * driver loading. - */ - xen_stub_processor_init(); - return; -} - -module_init(xen_acpi_processor_init); -module_exit(xen_acpi_processor_exit); -ACPI_MODULE_NAME("xen-acpi-cpuhotplug"); -MODULE_AUTHOR("Liu Jinsong <jinsong.liu@intel.com>"); -MODULE_DESCRIPTION("Xen Hotplug CPU Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c deleted file mode 100644 index f914b72557efb0379cb208c90a715c2fe3006982..0000000000000000000000000000000000000000 --- a/drivers/xen/xen-acpi-memhotplug.c +++ /dev/null @@ -1,475 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 Intel Corporation - * Author: Liu Jinsong <jinsong.liu@intel.com> - * Author: Jiang Yunhong <yunhong.jiang@intel.com> - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/acpi.h> -#include <xen/acpi.h> -#include <xen/interface/platform.h> -#include <asm/xen/hypercall.h> - -#define PREFIX "ACPI:xen_memory_hotplug:" - -struct acpi_memory_info { - struct list_head list; - u64 start_addr; /* Memory Range start physical addr */ - u64 length; /* Memory Range length */ - unsigned short caching; /* memory cache attribute */ - unsigned short write_protect; /* memory read/write attribute */ - /* copied from buffer getting from _CRS */ - unsigned int enabled:1; -}; - -struct acpi_memory_device { - struct acpi_device *device; - struct list_head res_list; -}; - -static bool acpi_hotmem_initialized __read_mostly; - -static int xen_hotadd_memory(int pxm, struct acpi_memory_info *info) -{ - int rc; - struct xen_platform_op op; - - op.cmd = XENPF_mem_hotadd; - op.u.mem_add.spfn = info->start_addr >> PAGE_SHIFT; - op.u.mem_add.epfn = (info->start_addr + info->length) >> PAGE_SHIFT; - op.u.mem_add.pxm = pxm; - - rc = HYPERVISOR_dom0_op(&op); - if (rc) - pr_err(PREFIX "Xen Hotplug Memory Add failed on " - "0x%lx -> 0x%lx, _PXM: %d, error: %d\n", - (unsigned long)info->start_addr, - (unsigned long)(info->start_addr + info->length), - pxm, rc); - - return rc; -} - -static int xen_acpi_memory_enable_device(struct acpi_memory_device *mem_device) -{ - int pxm, result; - int num_enabled = 0; - struct acpi_memory_info *info; - - if (!mem_device) - return -EINVAL; - - pxm = xen_acpi_get_pxm(mem_device->device->handle); - if (pxm < 0) - return pxm; - - list_for_each_entry(info, &mem_device->res_list, list) { - if (info->enabled) { /* just sanity check...*/ - num_enabled++; - continue; - } - - if (!info->length) - continue; - - result = xen_hotadd_memory(pxm, info); - if (result) - continue; - info->enabled = 1; - num_enabled++; - } - - if (!num_enabled) - return -ENODEV; - - return 0; -} - -static acpi_status -acpi_memory_get_resource(struct acpi_resource *resource, void *context) -{ - struct acpi_memory_device *mem_device = context; - struct acpi_resource_address64 address64; - struct acpi_memory_info *info, *new; - acpi_status status; - - status = acpi_resource_to_address64(resource, &address64); - if (ACPI_FAILURE(status) || - (address64.resource_type != ACPI_MEMORY_RANGE)) - return AE_OK; - - list_for_each_entry(info, &mem_device->res_list, list) { - if ((info->caching == address64.info.mem.caching) && - (info->write_protect == address64.info.mem.write_protect) && - (info->start_addr + info->length == address64.address.minimum)) { - info->length += address64.address.address_length; - return AE_OK; - } - } - - new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL); - if (!new) - return AE_ERROR; - - INIT_LIST_HEAD(&new->list); - new->caching = address64.info.mem.caching; - new->write_protect = address64.info.mem.write_protect; - new->start_addr = address64.address.minimum; - new->length = address64.address.address_length; - list_add_tail(&new->list, &mem_device->res_list); - - return AE_OK; -} - -static int -acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) -{ - acpi_status status; - struct acpi_memory_info *info, *n; - - if (!list_empty(&mem_device->res_list)) - return 0; - - status = acpi_walk_resources(mem_device->device->handle, - METHOD_NAME__CRS, acpi_memory_get_resource, mem_device); - - if (ACPI_FAILURE(status)) { - list_for_each_entry_safe(info, n, &mem_device->res_list, list) - kfree(info); - INIT_LIST_HEAD(&mem_device->res_list); - return -EINVAL; - } - - return 0; -} - -static int acpi_memory_get_device(acpi_handle handle, - struct acpi_memory_device **mem_device) -{ - struct acpi_device *device = NULL; - int result = 0; - - acpi_scan_lock_acquire(); - - acpi_bus_get_device(handle, &device); - if (acpi_device_enumerated(device)) - goto end; - - /* - * Now add the notified device. This creates the acpi_device - * and invokes .add function - */ - result = acpi_bus_scan(handle); - if (result) { - pr_warn(PREFIX "ACPI namespace scan failed\n"); - result = -EINVAL; - goto out; - } - device = NULL; - acpi_bus_get_device(handle, &device); - if (!acpi_device_enumerated(device)) { - pr_warn(PREFIX "Missing device object\n"); - result = -EINVAL; - goto out; - } - -end: - *mem_device = acpi_driver_data(device); - if (!(*mem_device)) { - pr_err(PREFIX "driver data not found\n"); - result = -ENODEV; - goto out; - } - -out: - acpi_scan_lock_release(); - return result; -} - -static int acpi_memory_check_device(struct acpi_memory_device *mem_device) -{ - unsigned long long current_status; - - /* Get device present/absent information from the _STA */ - if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, - "_STA", NULL, ¤t_status))) - return -ENODEV; - /* - * Check for device status. Device should be - * present/enabled/functioning. - */ - if (!((current_status & ACPI_STA_DEVICE_PRESENT) - && (current_status & ACPI_STA_DEVICE_ENABLED) - && (current_status & ACPI_STA_DEVICE_FUNCTIONING))) - return -ENODEV; - - return 0; -} - -static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) -{ - pr_debug(PREFIX "Xen does not support memory hotremove\n"); - - return -ENOSYS; -} - -static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) -{ - struct acpi_memory_device *mem_device; - struct acpi_device *device; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ - - switch (event) { - case ACPI_NOTIFY_BUS_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "\nReceived BUS CHECK notification for device\n")); - fallthrough; - case ACPI_NOTIFY_DEVICE_CHECK: - if (event == ACPI_NOTIFY_DEVICE_CHECK) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "\nReceived DEVICE CHECK notification for device\n")); - - if (acpi_memory_get_device(handle, &mem_device)) { - pr_err(PREFIX "Cannot find driver data\n"); - break; - } - - ost_code = ACPI_OST_SC_SUCCESS; - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "\nReceived EJECT REQUEST notification for device\n")); - - acpi_scan_lock_acquire(); - if (acpi_bus_get_device(handle, &device)) { - acpi_scan_lock_release(); - pr_err(PREFIX "Device doesn't exist\n"); - break; - } - mem_device = acpi_driver_data(device); - if (!mem_device) { - acpi_scan_lock_release(); - pr_err(PREFIX "Driver Data is NULL\n"); - break; - } - - /* - * TBD: implement acpi_memory_disable_device and invoke - * acpi_bus_remove if Xen support hotremove in the future - */ - acpi_memory_disable_device(mem_device); - acpi_scan_lock_release(); - break; - - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); - /* non-hotplug event; possibly handled by other handler */ - return; - } - - (void) acpi_evaluate_ost(handle, event, ost_code, NULL); - return; -} - -static int xen_acpi_memory_device_add(struct acpi_device *device) -{ - int result; - struct acpi_memory_device *mem_device = NULL; - - - if (!device) - return -EINVAL; - - mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL); - if (!mem_device) - return -ENOMEM; - - INIT_LIST_HEAD(&mem_device->res_list); - mem_device->device = device; - sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); - device->driver_data = mem_device; - - /* Get the range from the _CRS */ - result = acpi_memory_get_device_resources(mem_device); - if (result) { - kfree(mem_device); - return result; - } - - /* - * For booting existed memory devices, early boot code has recognized - * memory area by EFI/E820. If DSDT shows these memory devices on boot, - * hotplug is not necessary for them. - * For hot-added memory devices during runtime, it need hypercall to - * Xen hypervisor to add memory. - */ - if (!acpi_hotmem_initialized) - return 0; - - if (!acpi_memory_check_device(mem_device)) - result = xen_acpi_memory_enable_device(mem_device); - - return result; -} - -static int xen_acpi_memory_device_remove(struct acpi_device *device) -{ - struct acpi_memory_device *mem_device = NULL; - - if (!device || !acpi_driver_data(device)) - return -EINVAL; - - mem_device = acpi_driver_data(device); - kfree(mem_device); - - return 0; -} - -/* - * Helper function to check for memory device - */ -static acpi_status is_memory_device(acpi_handle handle) -{ - char *hardware_id; - acpi_status status; - struct acpi_device_info *info; - - status = acpi_get_object_info(handle, &info); - if (ACPI_FAILURE(status)) - return status; - - if (!(info->valid & ACPI_VALID_HID)) { - kfree(info); - return AE_ERROR; - } - - hardware_id = info->hardware_id.string; - if ((hardware_id == NULL) || - (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID))) - status = AE_ERROR; - - kfree(info); - return status; -} - -static acpi_status -acpi_memory_register_notify_handler(acpi_handle handle, - u32 level, void *ctxt, void **retv) -{ - acpi_status status; - - status = is_memory_device(handle); - if (ACPI_FAILURE(status)) - return AE_OK; /* continue */ - - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_memory_device_notify, NULL); - /* continue */ - return AE_OK; -} - -static acpi_status -acpi_memory_deregister_notify_handler(acpi_handle handle, - u32 level, void *ctxt, void **retv) -{ - acpi_status status; - - status = is_memory_device(handle); - if (ACPI_FAILURE(status)) - return AE_OK; /* continue */ - - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - acpi_memory_device_notify); - - return AE_OK; /* continue */ -} - -static const struct acpi_device_id memory_device_ids[] = { - {ACPI_MEMORY_DEVICE_HID, 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, memory_device_ids); - -static struct acpi_driver xen_acpi_memory_device_driver = { - .name = "acpi_memhotplug", - .class = ACPI_MEMORY_DEVICE_CLASS, - .ids = memory_device_ids, - .ops = { - .add = xen_acpi_memory_device_add, - .remove = xen_acpi_memory_device_remove, - }, -}; - -static int __init xen_acpi_memory_device_init(void) -{ - int result; - acpi_status status; - - if (!xen_initial_domain()) - return -ENODEV; - - /* unregister the stub which only used to reserve driver space */ - xen_stub_memory_device_exit(); - - result = acpi_bus_register_driver(&xen_acpi_memory_device_driver); - if (result < 0) { - xen_stub_memory_device_init(); - return -ENODEV; - } - - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - acpi_memory_register_notify_handler, - NULL, NULL, NULL); - - if (ACPI_FAILURE(status)) { - pr_warn(PREFIX "walk_namespace failed\n"); - acpi_bus_unregister_driver(&xen_acpi_memory_device_driver); - xen_stub_memory_device_init(); - return -ENODEV; - } - - acpi_hotmem_initialized = true; - return 0; -} - -static void __exit xen_acpi_memory_device_exit(void) -{ - acpi_status status; - - if (!xen_initial_domain()) - return; - - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - acpi_memory_deregister_notify_handler, - NULL, NULL, NULL); - if (ACPI_FAILURE(status)) - pr_warn(PREFIX "walk_namespace failed\n"); - - acpi_bus_unregister_driver(&xen_acpi_memory_device_driver); - - /* - * stub reserve space again to prevent any chance of native - * driver loading. - */ - xen_stub_memory_device_init(); - return; -} - -module_init(xen_acpi_memory_device_init); -module_exit(xen_acpi_memory_device_exit); -ACPI_MODULE_NAME("xen-acpi-memhotplug"); -MODULE_AUTHOR("Liu Jinsong <jinsong.liu@intel.com>"); -MODULE_DESCRIPTION("Xen Hotplug Mem Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index cb904ac830064672d8125a0bb6f86a79a0bed346..f8e4faa96ad66f1e5178ca0d9cf36b0b45d5b0b4 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -802,7 +802,7 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev) "guest with no AER driver should have been killed\n"); goto end; } - result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result); + result = common_process(psdev, pci_channel_io_normal, XEN_PCI_OP_aer_slotreset, result); if (result == PCI_ERS_RESULT_NONE || result == PCI_ERS_RESULT_DISCONNECT) { @@ -859,7 +859,7 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev) "guest with no AER driver should have been killed\n"); goto end; } - result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result); + result = common_process(psdev, pci_channel_io_normal, XEN_PCI_OP_aer_mmio, result); if (result == PCI_ERS_RESULT_NONE || result == PCI_ERS_RESULT_DISCONNECT) { @@ -970,7 +970,7 @@ static void xen_pcibk_error_resume(struct pci_dev *dev) kill_domain_by_device(psdev); goto end; } - common_process(psdev, 1, XEN_PCI_OP_aer_resume, + common_process(psdev, pci_channel_io_normal, XEN_PCI_OP_aer_resume, PCI_ERS_RESULT_RECOVERED); end: if (psdev) diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c index 5447b5ab7c7666d207b288092fbb90f2783aa71a..4162d0e7e00d7ed5334d20c2ad2ac226fe27837f 100644 --- a/drivers/xen/xen-pciback/vpci.c +++ b/drivers/xen/xen-pciback/vpci.c @@ -233,7 +233,6 @@ static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, unsigned int *devfn) { struct pci_dev_entry *entry; - struct pci_dev *dev = NULL; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; int found = 0, slot; @@ -242,11 +241,7 @@ static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, list_for_each_entry(entry, &vpci_dev->dev_list[slot], list) { - dev = entry->dev; - if (dev && dev->bus->number == pcidev->bus->number - && pci_domain_nr(dev->bus) == - pci_domain_nr(pcidev->bus) - && dev->devfn == pcidev->devfn) { + if (entry->dev == pcidev) { found = 1; *domain = 0; *bus = 0; diff --git a/drivers/xen/xen-stub.c b/drivers/xen/xen-stub.c deleted file mode 100644 index 3be4e74660b5707ab0ce1e0551200983238809f6..0000000000000000000000000000000000000000 --- a/drivers/xen/xen-stub.c +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * xen-stub.c - stub drivers to reserve space for Xen - * - * Copyright (C) 2012 Intel Corporation - * Author: Liu Jinsong <jinsong.liu@intel.com> - * Author: Jiang Yunhong <yunhong.jiang@intel.com> - * - * Copyright (C) 2012 Oracle Inc - * Author: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/export.h> -#include <linux/types.h> -#include <linux/acpi.h> -#include <xen/acpi.h> - -#ifdef CONFIG_ACPI - -/*-------------------------------------------- - stub driver for Xen memory hotplug ---------------------------------------------*/ - -static const struct acpi_device_id memory_device_ids[] = { - {ACPI_MEMORY_DEVICE_HID, 0}, - {"", 0}, -}; - -static struct acpi_driver xen_stub_memory_device_driver = { - /* same name as native memory driver to block native loaded */ - .name = "acpi_memhotplug", - .class = ACPI_MEMORY_DEVICE_CLASS, - .ids = memory_device_ids, -}; - -int xen_stub_memory_device_init(void) -{ - if (!xen_initial_domain()) - return -ENODEV; - - /* just reserve space for Xen, block native driver loaded */ - return acpi_bus_register_driver(&xen_stub_memory_device_driver); -} -EXPORT_SYMBOL_GPL(xen_stub_memory_device_init); -subsys_initcall(xen_stub_memory_device_init); - -void xen_stub_memory_device_exit(void) -{ - acpi_bus_unregister_driver(&xen_stub_memory_device_driver); -} -EXPORT_SYMBOL_GPL(xen_stub_memory_device_exit); - - -/*-------------------------------------------- - stub driver for Xen cpu hotplug ---------------------------------------------*/ - -static const struct acpi_device_id processor_device_ids[] = { - {ACPI_PROCESSOR_OBJECT_HID, 0}, - {ACPI_PROCESSOR_DEVICE_HID, 0}, - {"", 0}, -}; - -static struct acpi_driver xen_stub_processor_driver = { - /* same name as native processor driver to block native loaded */ - .name = "processor", - .class = ACPI_PROCESSOR_CLASS, - .ids = processor_device_ids, -}; - -int xen_stub_processor_init(void) -{ - if (!xen_initial_domain()) - return -ENODEV; - - /* just reserve space for Xen, block native driver loaded */ - return acpi_bus_register_driver(&xen_stub_processor_driver); -} -EXPORT_SYMBOL_GPL(xen_stub_processor_init); -subsys_initcall(xen_stub_processor_init); - -void xen_stub_processor_exit(void) -{ - acpi_bus_unregister_driver(&xen_stub_processor_driver); -} -EXPORT_SYMBOL_GPL(xen_stub_processor_exit); - -#endif diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 8d97f0b45e9c31a3ed16375ab60a17754fb28b49..795706520b5e716783148c029248d84cd9a6eef6 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -399,7 +399,7 @@ static int v9fs_test_inode(struct inode *inode, void *data) umode = p9mode2unixmode(v9ses, st, &rdev); /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) + if (inode_wrong_type(inode, umode)) return 0; /* compare qid details */ @@ -1390,7 +1390,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) * Don't update inode if the file type is different */ umode = p9mode2unixmode(v9ses, st, &rdev); - if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) + if (inode_wrong_type(inode, umode)) goto out; /* diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 1dc7af0466152deb06f039a57717ade541e3e530..e1c0240b51c0350c99605eb502f109f2949337f3 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -59,7 +59,7 @@ static int v9fs_test_inode_dotl(struct inode *inode, void *data) struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) + if (inode_wrong_type(inode, st->st_mode)) return 0; if (inode->i_generation != st->st_gen) @@ -663,14 +663,10 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode, if (stat->st_result_mask & P9_STATS_NLINK) set_nlink(inode, stat->st_nlink); if (stat->st_result_mask & P9_STATS_MODE) { - inode->i_mode = stat->st_mode; - if ((S_ISBLK(inode->i_mode)) || - (S_ISCHR(inode->i_mode))) - init_special_inode(inode, inode->i_mode, - inode->i_rdev); + mode = stat->st_mode & S_IALLUGO; + mode |= inode->i_mode & ~S_IALLUGO; + inode->i_mode = mode; } - if (stat->st_result_mask & P9_STATS_RDEV) - inode->i_rdev = new_decode_dev(stat->st_rdev); if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) && stat->st_result_mask & P9_STATS_SIZE) v9fs_i_size_write(inode, stat->st_size); @@ -959,7 +955,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) /* * Don't update inode if the file type is different */ - if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) + if (inode_wrong_type(inode, st->st_mode)) goto out; /* diff --git a/fs/Kconfig b/fs/Kconfig index 5d452e324b236f088f533477f5f8818ec2892247..242b475178e429fa3a0867c3bbc647c7572980c2 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -126,6 +126,7 @@ source "fs/incfs/Kconfig" menu "Caches" +source "fs/netfs/Kconfig" source "fs/fscache/Kconfig" source "fs/cachefiles/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 3fbeb30bc373d08598bf44cd2dde120e70770d26..bc5a89781d7eaa70e0fa874bfcf472ef3ef13958 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -67,6 +67,7 @@ obj-y += devpts/ obj-$(CONFIG_DLM) += dlm/ # Do not add any filesystems before this line +obj-$(CONFIG_NETFS_SUPPORT) += netfs/ obj-$(CONFIG_FSCACHE) += fscache/ obj-$(CONFIG_REISERFS_FS) += reiserfs/ obj-$(CONFIG_EXT4_FS) += ext4/ diff --git a/fs/afs/Kconfig b/fs/afs/Kconfig index 1ad211d72b3b4f15a5ffde80e55cca7a3639d5a7..fc8ba9142f2f0e92e8fbd3dfcfde2455d5f94eba 100644 --- a/fs/afs/Kconfig +++ b/fs/afs/Kconfig @@ -4,6 +4,7 @@ config AFS_FS depends on INET select AF_RXRPC select DNS_RESOLVER + select NETFS_SUPPORT help If you say Y here, you will get an experimental Andrew File System driver. It currently only supports unsecured read-only AFS access. diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 17548c1faf02999c7c631dd559fcaf2c430af607..117df15e53679b42522ed842707544897f9ed72d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -102,6 +102,35 @@ struct afs_lookup_cookie { struct afs_fid fids[50]; }; +/* + * Drop the refs that we're holding on the pages we were reading into. We've + * got refs on the first nr_pages pages. + */ +static void afs_dir_read_cleanup(struct afs_read *req) +{ + struct address_space *mapping = req->vnode->vfs_inode.i_mapping; + struct page *page; + pgoff_t last = req->nr_pages - 1; + + XA_STATE(xas, &mapping->i_pages, 0); + + if (unlikely(!req->nr_pages)) + return; + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + if (xas_retry(&xas, page)) + continue; + BUG_ON(xa_is_value(page)); + BUG_ON(PageCompound(page)); + ASSERTCMP(page->mapping, ==, mapping); + + put_page(page); + } + + rcu_read_unlock(); +} + /* * check that a directory page is valid */ @@ -127,7 +156,7 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, qty /= sizeof(union afs_xdr_dir_block); /* check them */ - dbuf = kmap(page); + dbuf = kmap_atomic(page); for (tmp = 0; tmp < qty; tmp++) { if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", @@ -146,7 +175,7 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, ((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0; } - kunmap(page); + kunmap_atomic(dbuf); checked: afs_stat_v(dvnode, n_read_dir); @@ -157,35 +186,74 @@ error: } /* - * Check the contents of a directory that we've just read. + * Dump the contents of a directory. */ -static bool afs_dir_check_pages(struct afs_vnode *dvnode, struct afs_read *req) +static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req) { struct afs_xdr_dir_page *dbuf; - unsigned int i, j, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); + struct address_space *mapping = dvnode->vfs_inode.i_mapping; + struct page *page; + unsigned int i, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); + pgoff_t last = req->nr_pages - 1; - for (i = 0; i < req->nr_pages; i++) - if (!afs_dir_check_page(dvnode, req->pages[i], req->actual_len)) - goto bad; - return true; + XA_STATE(xas, &mapping->i_pages, 0); -bad: - pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx r=%llx\n", + pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx\n", dvnode->fid.vid, dvnode->fid.vnode, - req->file_size, req->len, req->actual_len, req->remain); - pr_warn("DIR %llx %x %x %x\n", - req->pos, req->index, req->nr_pages, req->offset); + req->file_size, req->len, req->actual_len); + pr_warn("DIR %llx %x %zx %zx\n", + req->pos, req->nr_pages, + req->iter->iov_offset, iov_iter_count(req->iter)); - for (i = 0; i < req->nr_pages; i++) { - dbuf = kmap(req->pages[i]); - for (j = 0; j < qty; j++) { - union afs_xdr_dir_block *block = &dbuf->blocks[j]; + xas_for_each(&xas, page, last) { + if (xas_retry(&xas, page)) + continue; + + BUG_ON(PageCompound(page)); + BUG_ON(page->mapping != mapping); + + dbuf = kmap_atomic(page); + for (i = 0; i < qty; i++) { + union afs_xdr_dir_block *block = &dbuf->blocks[i]; - pr_warn("[%02x] %32phN\n", i * qty + j, block); + pr_warn("[%02lx] %32phN\n", page->index * qty + i, block); } - kunmap(req->pages[i]); + kunmap_atomic(dbuf); } - return false; +} + +/* + * Check all the pages in a directory. All the pages are held pinned. + */ +static int afs_dir_check(struct afs_vnode *dvnode, struct afs_read *req) +{ + struct address_space *mapping = dvnode->vfs_inode.i_mapping; + struct page *page; + pgoff_t last = req->nr_pages - 1; + int ret = 0; + + XA_STATE(xas, &mapping->i_pages, 0); + + if (unlikely(!req->nr_pages)) + return 0; + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + if (xas_retry(&xas, page)) + continue; + + BUG_ON(PageCompound(page)); + BUG_ON(page->mapping != mapping); + + if (!afs_dir_check_page(dvnode, page, req->file_size)) { + afs_dir_dump(dvnode, req); + ret = -EIO; + break; + } + } + + rcu_read_unlock(); + return ret; } /* @@ -214,57 +282,57 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) { struct afs_read *req; loff_t i_size; - int nr_pages, nr_inline, i, n; - int ret = -ENOMEM; + int nr_pages, i, n; + int ret; + + _enter(""); -retry: + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return ERR_PTR(-ENOMEM); + + refcount_set(&req->usage, 1); + req->vnode = dvnode; + req->key = key_get(key); + req->cleanup = afs_dir_read_cleanup; + +expand: i_size = i_size_read(&dvnode->vfs_inode); - if (i_size < 2048) - return ERR_PTR(afs_bad(dvnode, afs_file_error_dir_small)); + if (i_size < 2048) { + ret = afs_bad(dvnode, afs_file_error_dir_small); + goto error; + } if (i_size > 2048 * 1024) { trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); - return ERR_PTR(-EFBIG); + ret = -EFBIG; + goto error; } _enter("%llu", i_size); - /* Get a request record to hold the page list. We want to hold it - * inline if we can, but we don't want to make an order 1 allocation. - */ nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; - nr_inline = nr_pages; - if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *)) - nr_inline = 0; - req = kzalloc(struct_size(req, array, nr_inline), GFP_KERNEL); - if (!req) - return ERR_PTR(-ENOMEM); - - refcount_set(&req->usage, 1); - req->nr_pages = nr_pages; req->actual_len = i_size; /* May change */ req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ req->data_version = dvnode->status.data_version; /* May change */ - if (nr_inline > 0) { - req->pages = req->array; - } else { - req->pages = kcalloc(nr_pages, sizeof(struct page *), - GFP_KERNEL); - if (!req->pages) - goto error; - } + iov_iter_xarray(&req->def_iter, READ, &dvnode->vfs_inode.i_mapping->i_pages, + 0, i_size); + req->iter = &req->def_iter; - /* Get a list of all the pages that hold or will hold the directory - * content. We need to fill in any gaps that we might find where the - * memory reclaimer has been at work. If there are any gaps, we will + /* Fill in any gaps that we might find where the memory reclaimer has + * been at work and pin all the pages. If there are any gaps, we will * need to reread the entire directory contents. */ - i = 0; - do { + i = req->nr_pages; + while (i < nr_pages) { + struct page *pages[8], *page; + n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i, - req->nr_pages - i, - req->pages + i); - _debug("find %u at %u/%u", n, i, req->nr_pages); + min_t(unsigned int, nr_pages - i, + ARRAY_SIZE(pages)), + pages); + _debug("find %u at %u/%u", n, i, nr_pages); + if (n == 0) { gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask; @@ -272,22 +340,24 @@ retry: afs_stat_v(dvnode, n_inval); ret = -ENOMEM; - req->pages[i] = __page_cache_alloc(gfp); - if (!req->pages[i]) + page = __page_cache_alloc(gfp); + if (!page) goto error; - ret = add_to_page_cache_lru(req->pages[i], + ret = add_to_page_cache_lru(page, dvnode->vfs_inode.i_mapping, i, gfp); if (ret < 0) goto error; - attach_page_private(req->pages[i], (void *)1); - unlock_page(req->pages[i]); + attach_page_private(page, (void *)1); + unlock_page(page); + req->nr_pages++; i++; } else { + req->nr_pages += n; i += n; } - } while (i < req->nr_pages); + } /* If we're going to reload, we need to lock all the pages to prevent * races. @@ -305,18 +375,23 @@ retry: if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { trace_afs_reload_dir(dvnode); - ret = afs_fetch_data(dvnode, key, req); + ret = afs_fetch_data(dvnode, req); if (ret < 0) goto error_unlock; task_io_account_read(PAGE_SIZE * req->nr_pages); - if (req->len < req->file_size) - goto content_has_grown; + if (req->len < req->file_size) { + /* The content has grown, so we need to expand the + * buffer. + */ + up_write(&dvnode->validate_lock); + goto expand; + } /* Validate the data we just read. */ - ret = -EIO; - if (!afs_dir_check_pages(dvnode, req)) + ret = afs_dir_check(dvnode, req); + if (ret < 0) goto error_unlock; // TODO: Trim excess pages @@ -334,11 +409,6 @@ error: afs_put_read(req); _leave(" = %d", ret); return ERR_PTR(ret); - -content_has_grown: - up_write(&dvnode->validate_lock); - afs_put_read(req); - goto retry; } /* @@ -448,6 +518,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, struct afs_read *req; struct page *page; unsigned blkoff, limit; + void __rcu **slot; int ret; _enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos); @@ -472,9 +543,15 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1); /* Fetch the appropriate page from the directory and re-add it - * to the LRU. + * to the LRU. We have all the pages pinned with an extra ref. */ - page = req->pages[blkoff / PAGE_SIZE]; + rcu_read_lock(); + page = NULL; + slot = radix_tree_lookup_slot(&dvnode->vfs_inode.i_mapping->i_pages, + blkoff / PAGE_SIZE); + if (slot) + page = radix_tree_deref_slot(slot); + rcu_read_unlock(); if (!page) { ret = afs_bad(dvnode, afs_file_error_dir_missing_page); break; @@ -2006,6 +2083,6 @@ static void afs_dir_invalidatepage(struct page *page, unsigned int offset, afs_stat_v(dvnode, n_inval); /* we clean up only if the entire page is being invalidated */ - if (offset == 0 && length == PAGE_SIZE) + if (offset == 0 && length == thp_size(page)) detach_page_private(page); } diff --git a/fs/afs/file.c b/fs/afs/file.c index 960b64268623e4cf03f84f6f2587bfe24479ab87..db035ae2a13451dc97fc10e97a6aeb50088898a4 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -14,6 +14,7 @@ #include <linux/gfp.h> #include <linux/task_io_accounting_ops.h> #include <linux/mm.h> +#include <linux/netfs.h> #include "internal.h" static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); @@ -22,8 +23,7 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, unsigned int length); static int afs_releasepage(struct page *page, gfp_t gfp_flags); -static int afs_readpages(struct file *filp, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages); +static void afs_readahead(struct readahead_control *ractl); const struct file_operations afs_file_operations = { .open = afs_open, @@ -47,7 +47,7 @@ const struct inode_operations afs_file_inode_operations = { const struct address_space_operations afs_fs_aops = { .readpage = afs_readpage, - .readpages = afs_readpages, + .readahead = afs_readahead, .set_page_dirty = afs_set_page_dirty, .launder_page = afs_launder_page, .releasepage = afs_releasepage, @@ -183,42 +183,51 @@ int afs_release(struct inode *inode, struct file *file) return ret; } +/* + * Allocate a new read record. + */ +struct afs_read *afs_alloc_read(gfp_t gfp) +{ + struct afs_read *req; + + req = kzalloc(sizeof(struct afs_read), gfp); + if (req) + refcount_set(&req->usage, 1); + + return req; +} + /* * Dispose of a ref to a read record. */ void afs_put_read(struct afs_read *req) { - int i; - if (refcount_dec_and_test(&req->usage)) { - if (req->pages) { - for (i = 0; i < req->nr_pages; i++) - if (req->pages[i]) - put_page(req->pages[i]); - if (req->pages != req->array) - kfree(req->pages); - } + if (req->cleanup) + req->cleanup(req); + key_put(req->key); kfree(req); } } -#ifdef CONFIG_AFS_FSCACHE -/* - * deal with notification that a page was read from the cache - */ -static void afs_file_readpage_read_complete(struct page *page, - void *data, - int error) +static void afs_fetch_data_notify(struct afs_operation *op) { - _enter("%p,%p,%d", page, data, error); - - /* if the read completes with an error, we just unlock the page and let - * the VM reissue the readpage */ - if (!error) - SetPageUptodate(page); - unlock_page(page); + struct afs_read *req = op->fetch.req; + struct netfs_read_subrequest *subreq = req->subreq; + int error = op->error; + + if (error == -ECONNABORTED) + error = afs_abort_to_error(op->ac.abort_code); + req->error = error; + + if (subreq) { + __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); + netfs_subreq_terminated(subreq, error ?: req->actual_len, false); + req->subreq = NULL; + } else if (req->done) { + req->done(req); + } } -#endif static void afs_fetch_data_success(struct afs_operation *op) { @@ -228,10 +237,12 @@ static void afs_fetch_data_success(struct afs_operation *op) afs_vnode_commit_status(op, &op->file[0]); afs_stat_v(vnode, n_fetches); atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes); + afs_fetch_data_notify(op); } static void afs_fetch_data_put(struct afs_operation *op) { + op->fetch.req->error = op->error; afs_put_read(op->fetch.req); } @@ -240,13 +251,14 @@ static const struct afs_operation_ops afs_fetch_data_operation = { .issue_yfs_rpc = yfs_fs_fetch_data, .success = afs_fetch_data_success, .aborted = afs_check_for_remote_deletion, + .failed = afs_fetch_data_notify, .put = afs_fetch_data_put, }; /* * Fetch file data from the volume. */ -int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *req) +int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req) { struct afs_operation *op; @@ -255,11 +267,14 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *re vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, - key_serial(key)); + key_serial(req->key)); - op = afs_alloc_operation(key, vnode->volume); - if (IS_ERR(op)) + op = afs_alloc_operation(req->key, vnode->volume); + if (IS_ERR(op)) { + if (req->subreq) + netfs_subreq_terminated(req->subreq, PTR_ERR(op), false); return PTR_ERR(op); + } afs_op_set_vnode(op, 0, vnode); @@ -268,336 +283,103 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *re return afs_do_sync_operation(op); } -/* - * read page from file, directory or symlink, given a key to use - */ -int afs_page_filler(void *data, struct page *page) +static void afs_req_issue_op(struct netfs_read_subrequest *subreq) { - struct inode *inode = page->mapping->host; - struct afs_vnode *vnode = AFS_FS_I(inode); - struct afs_read *req; - struct key *key = data; - int ret; - - _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); + struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode); + struct afs_read *fsreq; - BUG_ON(!PageLocked(page)); + fsreq = afs_alloc_read(GFP_NOFS); + if (!fsreq) + return netfs_subreq_terminated(subreq, -ENOMEM, false); - ret = -ESTALE; - if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) - goto error; + fsreq->subreq = subreq; + fsreq->pos = subreq->start + subreq->transferred; + fsreq->len = subreq->len - subreq->transferred; + fsreq->key = subreq->rreq->netfs_priv; + fsreq->vnode = vnode; + fsreq->iter = &fsreq->def_iter; - /* is it cached? */ -#ifdef CONFIG_AFS_FSCACHE - ret = fscache_read_or_alloc_page(vnode->cache, - page, - afs_file_readpage_read_complete, - NULL, - GFP_KERNEL); -#else - ret = -ENOBUFS; -#endif - switch (ret) { - /* read BIO submitted (page in cache) */ - case 0: - break; - - /* page not yet cached */ - case -ENODATA: - _debug("cache said ENODATA"); - goto go_on; - - /* page will not be cached */ - case -ENOBUFS: - _debug("cache said ENOBUFS"); - - fallthrough; - default: - go_on: - req = kzalloc(struct_size(req, array, 1), GFP_KERNEL); - if (!req) - goto enomem; - - /* We request a full page. If the page is a partial one at the - * end of the file, the server will return a short read and the - * unmarshalling code will clear the unfilled space. - */ - refcount_set(&req->usage, 1); - req->pos = (loff_t)page->index << PAGE_SHIFT; - req->len = PAGE_SIZE; - req->nr_pages = 1; - req->pages = req->array; - req->pages[0] = page; - get_page(page); - - /* read the contents of the file from the server into the - * page */ - ret = afs_fetch_data(vnode, key, req); - afs_put_read(req); - - if (ret < 0) { - if (ret == -ENOENT) { - _debug("got NOENT from server" - " - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - } + iov_iter_xarray(&fsreq->def_iter, READ, + &fsreq->vnode->vfs_inode.i_mapping->i_pages, + fsreq->pos, fsreq->len); -#ifdef CONFIG_AFS_FSCACHE - fscache_uncache_page(vnode->cache, page); -#endif - BUG_ON(PageFsCache(page)); - - if (ret == -EINTR || - ret == -ENOMEM || - ret == -ERESTARTSYS || - ret == -EAGAIN) - goto error; - goto io_error; - } + afs_fetch_data(fsreq->vnode, fsreq); +} - SetPageUptodate(page); +static int afs_symlink_readpage(struct page *page) +{ + struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); + struct afs_read *fsreq; + int ret; - /* send the page to the cache */ -#ifdef CONFIG_AFS_FSCACHE - if (PageFsCache(page) && - fscache_write_page(vnode->cache, page, vnode->status.size, - GFP_KERNEL) != 0) { - fscache_uncache_page(vnode->cache, page); - BUG_ON(PageFsCache(page)); - } -#endif - unlock_page(page); - } + fsreq = afs_alloc_read(GFP_NOFS); + if (!fsreq) + return -ENOMEM; - _leave(" = 0"); - return 0; + fsreq->pos = page->index * PAGE_SIZE; + fsreq->len = PAGE_SIZE; + fsreq->vnode = vnode; + fsreq->iter = &fsreq->def_iter; + iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages, + fsreq->pos, fsreq->len); -io_error: - SetPageError(page); - goto error; -enomem: - ret = -ENOMEM; -error: - unlock_page(page); - _leave(" = %d", ret); + ret = afs_fetch_data(fsreq->vnode, fsreq); + page_endio(page, false, ret); return ret; } -/* - * read page from file, directory or symlink, given a file to nominate the key - * to be used - */ -static int afs_readpage(struct file *file, struct page *page) +static void afs_init_rreq(struct netfs_read_request *rreq, struct file *file) { - struct key *key; - int ret; - - if (file) { - key = afs_file_key(file); - ASSERT(key != NULL); - ret = afs_page_filler(key, page); - } else { - struct inode *inode = page->mapping->host; - key = afs_request_key(AFS_FS_S(inode->i_sb)->cell); - if (IS_ERR(key)) { - ret = PTR_ERR(key); - } else { - ret = afs_page_filler(key, page); - key_put(key); - } - } - return ret; + rreq->netfs_priv = key_get(afs_file_key(file)); } -/* - * Make pages available as they're filled. - */ -static void afs_readpages_page_done(struct afs_read *req) +static bool afs_is_cache_enabled(struct inode *inode) { -#ifdef CONFIG_AFS_FSCACHE - struct afs_vnode *vnode = req->vnode; -#endif - struct page *page = req->pages[req->index]; + struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode)); - req->pages[req->index] = NULL; - SetPageUptodate(page); - - /* send the page to the cache */ -#ifdef CONFIG_AFS_FSCACHE - if (PageFsCache(page) && - fscache_write_page(vnode->cache, page, vnode->status.size, - GFP_KERNEL) != 0) { - fscache_uncache_page(vnode->cache, page); - BUG_ON(PageFsCache(page)); - } -#endif - unlock_page(page); - put_page(page); + return fscache_cookie_enabled(cookie) && !hlist_empty(&cookie->backing_objects); } -/* - * Read a contiguous set of pages. - */ -static int afs_readpages_one(struct file *file, struct address_space *mapping, - struct list_head *pages) +static int afs_begin_cache_operation(struct netfs_read_request *rreq) { - struct afs_vnode *vnode = AFS_FS_I(mapping->host); - struct afs_read *req; - struct list_head *p; - struct page *first, *page; - struct key *key = afs_file_key(file); - pgoff_t index; - int ret, n, i; - - /* Count the number of contiguous pages at the front of the list. Note - * that the list goes prev-wards rather than next-wards. - */ - first = lru_to_page(pages); - index = first->index + 1; - n = 1; - for (p = first->lru.prev; p != pages; p = p->prev) { - page = list_entry(p, struct page, lru); - if (page->index != index) - break; - index++; - n++; - } - - req = kzalloc(struct_size(req, array, n), GFP_NOFS); - if (!req) - return -ENOMEM; - - refcount_set(&req->usage, 1); - req->vnode = vnode; - req->page_done = afs_readpages_page_done; - req->pos = first->index; - req->pos <<= PAGE_SHIFT; - req->pages = req->array; - - /* Transfer the pages to the request. We add them in until one fails - * to add to the LRU and then we stop (as that'll make a hole in the - * contiguous run. - * - * Note that it's possible for the file size to change whilst we're - * doing this, but we rely on the server returning less than we asked - * for if the file shrank. We also rely on this to deal with a partial - * page at the end of the file. - */ - do { - page = lru_to_page(pages); - list_del(&page->lru); - index = page->index; - if (add_to_page_cache_lru(page, mapping, index, - readahead_gfp_mask(mapping))) { -#ifdef CONFIG_AFS_FSCACHE - fscache_uncache_page(vnode->cache, page); -#endif - put_page(page); - break; - } - - req->pages[req->nr_pages++] = page; - req->len += PAGE_SIZE; - } while (req->nr_pages < n); + struct afs_vnode *vnode = AFS_FS_I(rreq->inode); - if (req->nr_pages == 0) { - kfree(req); - return 0; - } - - ret = afs_fetch_data(vnode, key, req); - if (ret < 0) - goto error; - - task_io_account_read(PAGE_SIZE * req->nr_pages); - afs_put_read(req); - return 0; - -error: - if (ret == -ENOENT) { - _debug("got NOENT from server" - " - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - } - - for (i = 0; i < req->nr_pages; i++) { - page = req->pages[i]; - if (page) { -#ifdef CONFIG_AFS_FSCACHE - fscache_uncache_page(vnode->cache, page); -#endif - SetPageError(page); - unlock_page(page); - } - } - - afs_put_read(req); - return ret; + return fscache_begin_read_operation(rreq, afs_vnode_cache(vnode)); } -/* - * read a set of pages - */ -static int afs_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) +static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len, + struct page *page, void **_fsdata) { - struct key *key = afs_file_key(file); - struct afs_vnode *vnode; - int ret = 0; - - _enter("{%d},{%lu},,%d", - key_serial(key), mapping->host->i_ino, nr_pages); + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); - ASSERT(key != NULL); + return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? -ESTALE : 0; +} - vnode = AFS_FS_I(mapping->host); - if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { - _leave(" = -ESTALE"); - return -ESTALE; - } +static void afs_priv_cleanup(struct address_space *mapping, void *netfs_priv) +{ + key_put(netfs_priv); +} - /* attempt to read as many of the pages as possible */ -#ifdef CONFIG_AFS_FSCACHE - ret = fscache_read_or_alloc_pages(vnode->cache, - mapping, - pages, - &nr_pages, - afs_file_readpage_read_complete, - NULL, - mapping_gfp_mask(mapping)); -#else - ret = -ENOBUFS; -#endif +const struct netfs_read_request_ops afs_req_ops = { + .init_rreq = afs_init_rreq, + .is_cache_enabled = afs_is_cache_enabled, + .begin_cache_operation = afs_begin_cache_operation, + .check_write_begin = afs_check_write_begin, + .issue_op = afs_req_issue_op, + .cleanup = afs_priv_cleanup, +}; - switch (ret) { - /* all pages are being read from the cache */ - case 0: - BUG_ON(!list_empty(pages)); - BUG_ON(nr_pages != 0); - _leave(" = 0 [reading all]"); - return 0; - - /* there were pages that couldn't be read from the cache */ - case -ENODATA: - case -ENOBUFS: - break; - - /* other error */ - default: - _leave(" = %d", ret); - return ret; - } +static int afs_readpage(struct file *file, struct page *page) +{ + if (!file) + return afs_symlink_readpage(page); - while (!list_empty(pages)) { - ret = afs_readpages_one(file, mapping, pages); - if (ret < 0) - break; - } + return netfs_readpage(file, page, &afs_req_ops, NULL); +} - _leave(" = %d [netting]", ret); - return ret; +static void afs_readahead(struct readahead_control *ractl) +{ + netfs_readahead(ractl, &afs_req_ops, NULL); } /* @@ -625,8 +407,8 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset, return; /* We may need to shorten the dirty region */ - f = afs_page_dirty_from(priv); - t = afs_page_dirty_to(priv); + f = afs_page_dirty_from(page, priv); + t = afs_page_dirty_to(page, priv); if (t <= offset || f >= end) return; /* Doesn't overlap */ @@ -644,17 +426,17 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset, if (f == t) goto undirty; - priv = afs_page_dirty(f, t); + priv = afs_page_dirty(page, f, t); set_page_private(page, priv); - trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page); return; undirty: - trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page); clear_page_dirty_for_io(page); full_invalidate: - priv = (unsigned long)detach_page_private(page); - trace_afs_page_dirty(vnode, tracepoint_string("inval"), page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("inval"), page); + detach_page_private(page); } /* @@ -669,20 +451,10 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, BUG_ON(!PageLocked(page)); -#ifdef CONFIG_AFS_FSCACHE - /* we clean up only if the entire page is being invalidated */ - if (offset == 0 && length == PAGE_SIZE) { - if (PageFsCache(page)) { - struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); - fscache_wait_on_page_write(vnode->cache, page); - fscache_uncache_page(vnode->cache, page); - } - } -#endif - if (PagePrivate(page)) afs_invalidate_dirty(page, offset, length); + wait_on_page_fscache(page); _leave(""); } @@ -693,7 +465,6 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, static int afs_releasepage(struct page *page, gfp_t gfp_flags) { struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); - unsigned long priv; _enter("{{%llx:%llu}[%lu],%lx},%x", vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, @@ -702,16 +473,16 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) /* deny if page is being written to the cache and the caller hasn't * elected to wait */ #ifdef CONFIG_AFS_FSCACHE - if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { - _leave(" = F [cache busy]"); - return 0; + if (PageFsCache(page)) { + if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS)) + return false; + wait_on_page_fscache(page); } #endif if (PagePrivate(page)) { - priv = (unsigned long)detach_page_private(page); - trace_afs_page_dirty(vnode, tracepoint_string("rel"), - page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("rel"), page); + detach_page_private(page); } /* indicate that the page can be released */ diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c index 71c58723763d23bf116353c405b5fcd78c8039cd..2cb0951acca605769a2bd5566be78778075c9302 100644 --- a/fs/afs/fs_operation.c +++ b/fs/afs/fs_operation.c @@ -198,8 +198,10 @@ void afs_wait_for_operation(struct afs_operation *op) case -ECONNABORTED: if (op->ops->aborted) op->ops->aborted(op); - break; + fallthrough; default: + if (op->ops->failed) + op->ops->failed(op); break; } diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 1d95ed9dd86e601f6068ec3bf500ebcc08b9d8e9..2f695a260442553dffd102e4cef79a25c91b0c90 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/circ_buf.h> #include <linux/iversion.h> +#include <linux/netfs.h> #include "internal.h" #include "afs_fs.h" #include "xdr_fs.h" @@ -302,17 +303,15 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) struct afs_vnode_param *vp = &op->file[0]; struct afs_read *req = op->fetch.req; const __be32 *bp; - unsigned int size; int ret; - _enter("{%u,%zu/%llu}", - call->unmarshall, iov_iter_count(call->iter), req->actual_len); + _enter("{%u,%zu,%zu/%llu}", + call->unmarshall, call->iov_len, iov_iter_count(call->iter), + req->actual_len); switch (call->unmarshall) { case 0: req->actual_len = 0; - req->index = 0; - req->offset = req->pos & (PAGE_SIZE - 1); call->unmarshall++; if (call->operation_ID == FSFETCHDATA64) { afs_extract_to_tmp64(call); @@ -322,7 +321,10 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) } fallthrough; - /* extract the returned data length */ + /* Extract the returned data length into + * ->actual_len. This may indicate more or less data than was + * requested will be returned. + */ case 1: _debug("extract data length"); ret = afs_extract_data(call, true); @@ -331,44 +333,25 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) req->actual_len = be64_to_cpu(call->tmp64); _debug("DATA length: %llu", req->actual_len); - req->remain = min(req->len, req->actual_len); - if (req->remain == 0) + + if (req->actual_len == 0) goto no_more_data; + call->iter = req->iter; + call->iov_len = min(req->actual_len, req->len); call->unmarshall++; - - begin_page: - ASSERTCMP(req->index, <, req->nr_pages); - if (req->remain > PAGE_SIZE - req->offset) - size = PAGE_SIZE - req->offset; - else - size = req->remain; - call->bvec[0].bv_len = size; - call->bvec[0].bv_offset = req->offset; - call->bvec[0].bv_page = req->pages[req->index]; - iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size); - ASSERTCMP(size, <=, PAGE_SIZE); fallthrough; /* extract the returned data */ case 2: _debug("extract data %zu/%llu", - iov_iter_count(call->iter), req->remain); + iov_iter_count(call->iter), req->actual_len); ret = afs_extract_data(call, true); if (ret < 0) return ret; - req->remain -= call->bvec[0].bv_len; - req->offset += call->bvec[0].bv_len; - ASSERTCMP(req->offset, <=, PAGE_SIZE); - if (req->offset == PAGE_SIZE) { - req->offset = 0; - req->index++; - if (req->remain > 0) - goto begin_page; - } - ASSERTCMP(req->remain, ==, 0); + call->iter = &call->def_iter; if (req->actual_len <= req->len) goto no_more_data; @@ -410,17 +393,6 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) break; } - for (; req->index < req->nr_pages; req->index++) { - if (req->offset < PAGE_SIZE) - zero_user_segment(req->pages[req->index], - req->offset, PAGE_SIZE); - req->offset = 0; - } - - if (req->page_done) - for (req->index = 0; req->index < req->nr_pages; req->index++) - req->page_done(req); - _leave(" = 0 [done]"); return 0; } @@ -494,6 +466,8 @@ void afs_fs_fetch_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); + req->call_debug_id = call->debug_id; + /* marshall the parameters */ bp = call->request; bp[0] = htonl(FSFETCHDATA); @@ -1079,8 +1053,7 @@ static const struct afs_call_type afs_RXFSStoreData64 = { /* * store a set of pages to a very large file */ -static void afs_fs_store_data64(struct afs_operation *op, - loff_t pos, loff_t size, loff_t i_size) +static void afs_fs_store_data64(struct afs_operation *op) { struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; @@ -1095,7 +1068,7 @@ static void afs_fs_store_data64(struct afs_operation *op, if (!call) return afs_op_nomem(op); - call->send_pages = true; + call->write_iter = op->store.write_iter; /* marshall the parameters */ bp = call->request; @@ -1111,47 +1084,38 @@ static void afs_fs_store_data64(struct afs_operation *op, *bp++ = 0; /* unix mode */ *bp++ = 0; /* segment size */ - *bp++ = htonl(upper_32_bits(pos)); - *bp++ = htonl(lower_32_bits(pos)); - *bp++ = htonl(upper_32_bits(size)); - *bp++ = htonl(lower_32_bits(size)); - *bp++ = htonl(upper_32_bits(i_size)); - *bp++ = htonl(lower_32_bits(i_size)); + *bp++ = htonl(upper_32_bits(op->store.pos)); + *bp++ = htonl(lower_32_bits(op->store.pos)); + *bp++ = htonl(upper_32_bits(op->store.size)); + *bp++ = htonl(lower_32_bits(op->store.size)); + *bp++ = htonl(upper_32_bits(op->store.i_size)); + *bp++ = htonl(lower_32_bits(op->store.i_size)); trace_afs_make_fs_call(call, &vp->fid); afs_make_op_call(op, call, GFP_NOFS); } /* - * store a set of pages + * Write data to a file on the server. */ void afs_fs_store_data(struct afs_operation *op) { struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; - loff_t size, pos, i_size; __be32 *bp; _enter(",%x,{%llx:%llu},,", key_serial(op->key), vp->fid.vid, vp->fid.vnode); - size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset; - if (op->store.first != op->store.last) - size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT; - pos = (loff_t)op->store.first << PAGE_SHIFT; - pos += op->store.first_offset; - - i_size = i_size_read(&vp->vnode->vfs_inode); - if (pos + size > i_size) - i_size = size + pos; - _debug("size %llx, at %llx, i_size %llx", - (unsigned long long) size, (unsigned long long) pos, - (unsigned long long) i_size); + (unsigned long long)op->store.size, + (unsigned long long)op->store.pos, + (unsigned long long)op->store.i_size); - if (upper_32_bits(pos) || upper_32_bits(i_size) || upper_32_bits(size) || - upper_32_bits(pos + size)) - return afs_fs_store_data64(op, pos, size, i_size); + if (upper_32_bits(op->store.pos) || + upper_32_bits(op->store.size) || + upper_32_bits(op->store.i_size)) + return afs_fs_store_data64(op); call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData, (4 + 6 + 3) * 4, @@ -1159,7 +1123,7 @@ void afs_fs_store_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); - call->send_pages = true; + call->write_iter = op->store.write_iter; /* marshall the parameters */ bp = call->request; @@ -1175,9 +1139,9 @@ void afs_fs_store_data(struct afs_operation *op) *bp++ = 0; /* unix mode */ *bp++ = 0; /* segment size */ - *bp++ = htonl(lower_32_bits(pos)); - *bp++ = htonl(lower_32_bits(size)); - *bp++ = htonl(lower_32_bits(i_size)); + *bp++ = htonl(lower_32_bits(op->store.pos)); + *bp++ = htonl(lower_32_bits(op->store.size)); + *bp++ = htonl(lower_32_bits(op->store.i_size)); trace_afs_make_fs_call(call, &vp->fid); afs_make_op_call(op, call, GFP_NOFS); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 12be88716e4c9bde3b12d92744f421d01e7e766a..3a129b9fd9b8d0f9e7aac963b8f7f7dc4fea21a7 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -102,13 +102,13 @@ static int afs_inode_init_from_status(struct afs_operation *op, switch (status->type) { case AFS_FTYPE_FILE: - inode->i_mode = S_IFREG | status->mode; + inode->i_mode = S_IFREG | (status->mode & S_IALLUGO); inode->i_op = &afs_file_inode_operations; inode->i_fop = &afs_file_operations; inode->i_mapping->a_ops = &afs_fs_aops; break; case AFS_FTYPE_DIR: - inode->i_mode = S_IFDIR | status->mode; + inode->i_mode = S_IFDIR | (status->mode & S_IALLUGO); inode->i_op = &afs_dir_inode_operations; inode->i_fop = &afs_dir_file_operations; inode->i_mapping->a_ops = &afs_dir_aops; @@ -198,7 +198,7 @@ static void afs_apply_status(struct afs_operation *op, if (status->mode != vnode->status.mode) { mode = inode->i_mode; mode &= ~S_IALLUGO; - mode |= status->mode; + mode |= status->mode & S_IALLUGO; WRITE_ONCE(inode->i_mode, mode); } @@ -214,11 +214,12 @@ static void afs_apply_status(struct afs_operation *op, if (vp->dv_before + vp->dv_delta != status->data_version) { if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) - pr_warn("kAFS: vnode modified {%llx:%llu} %llx->%llx %s\n", + pr_warn("kAFS: vnode modified {%llx:%llu} %llx->%llx %s (op=%x)\n", vnode->fid.vid, vnode->fid.vnode, (unsigned long long)vp->dv_before + vp->dv_delta, (unsigned long long)status->data_version, - op->type ? op->type->name : "???"); + op->type ? op->type->name : "???", + op->debug_id); vnode->invalid_before = status->data_version; if (vnode->status.type == AFS_FTYPE_DIR) { @@ -427,7 +428,7 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) } __packed key; struct afs_vnode_cache_aux aux; - if (vnode->status.type == AFS_FTYPE_DIR) { + if (vnode->status.type != AFS_FTYPE_FILE) { vnode->cache = NULL; return; } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 1627b1872812570da753f85c5fad8059245ad984..52157a05796a7e2e896c066242925780b0b91842 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -14,6 +14,7 @@ #include <linux/key.h> #include <linux/workqueue.h> #include <linux/sched.h> +#define FSCACHE_USE_NEW_IO_API #include <linux/fscache.h> #include <linux/backing-dev.h> #include <linux/uuid.h> @@ -31,6 +32,7 @@ struct pagevec; struct afs_call; +struct afs_vnode; /* * Partial file-locking emulation mode. (The problem being that AFS3 only @@ -104,7 +106,9 @@ struct afs_call { struct afs_server *server; /* The fileserver record if fs op (pins ref) */ struct afs_vlserver *vlserver; /* The vlserver record if vl op */ void *request; /* request data (first part) */ + size_t iov_len; /* Size of *iter to be used */ struct iov_iter def_iter; /* Default buffer/data iterator */ + struct iov_iter *write_iter; /* Iterator defining write to be made */ struct iov_iter *iter; /* Iterator currently in use */ union { /* Convenience for ->def_iter */ struct kvec kvec[1]; @@ -131,7 +135,6 @@ struct afs_call { unsigned char unmarshall; /* unmarshalling phase */ unsigned char addr_ix; /* Address in ->alist */ bool drop_ref; /* T if need to drop ref for incoming call */ - bool send_pages; /* T if data from mapping should be sent */ bool need_attention; /* T if RxRPC poked us */ bool async; /* T if asynchronous */ bool upgrade; /* T to request service upgrade */ @@ -202,17 +205,19 @@ struct afs_read { loff_t pos; /* Where to start reading */ loff_t len; /* How much we're asking for */ loff_t actual_len; /* How much we're actually getting */ - loff_t remain; /* Amount remaining */ loff_t file_size; /* File size returned by server */ + struct key *key; /* The key to use to reissue the read */ + struct afs_vnode *vnode; /* The file being read into. */ + struct netfs_read_subrequest *subreq; /* Fscache helper read request this belongs to */ afs_dataversion_t data_version; /* Version number returned by server */ refcount_t usage; - unsigned int index; /* Which page we're reading into */ + unsigned int call_debug_id; unsigned int nr_pages; - unsigned int offset; /* offset into current page */ - struct afs_vnode *vnode; - void (*page_done)(struct afs_read *); - struct page **pages; - struct page *array[]; + int error; + void (*done)(struct afs_read *); + void (*cleanup)(struct afs_read *); + struct iov_iter *iter; /* Iterator representing the buffer */ + struct iov_iter def_iter; /* Default iterator */ }; /* @@ -739,6 +744,7 @@ struct afs_operation_ops { void (*issue_yfs_rpc)(struct afs_operation *op); void (*success)(struct afs_operation *op); void (*aborted)(struct afs_operation *op); + void (*failed)(struct afs_operation *op); void (*edit_dir)(struct afs_operation *op); void (*put)(struct afs_operation *op); }; @@ -808,12 +814,11 @@ struct afs_operation { afs_lock_type_t type; } lock; struct { - struct address_space *mapping; /* Pages being written from */ - pgoff_t first; /* first page in mapping to deal with */ - pgoff_t last; /* last page in mapping to deal with */ - unsigned first_offset; /* offset into mapping[first] */ - unsigned last_to; /* amount of mapping[last] */ - bool laundering; /* Laundering page, PG_writeback not set */ + struct iov_iter *write_iter; + loff_t pos; + loff_t size; + loff_t i_size; + bool laundering; /* Laundering page, PG_writeback not set */ } store; struct { struct iattr *attr; @@ -875,31 +880,31 @@ struct afs_vnode_cache_aux { #define __AFS_PAGE_PRIV_MMAPPED 0x8000UL #endif -static inline unsigned int afs_page_dirty_resolution(void) +static inline unsigned int afs_page_dirty_resolution(struct page *page) { - int shift = PAGE_SHIFT - (__AFS_PAGE_PRIV_SHIFT - 1); + int shift = thp_order(page) + PAGE_SHIFT - (__AFS_PAGE_PRIV_SHIFT - 1); return (shift > 0) ? shift : 0; } -static inline size_t afs_page_dirty_from(unsigned long priv) +static inline size_t afs_page_dirty_from(struct page *page, unsigned long priv) { unsigned long x = priv & __AFS_PAGE_PRIV_MASK; /* The lower bound is inclusive */ - return x << afs_page_dirty_resolution(); + return x << afs_page_dirty_resolution(page); } -static inline size_t afs_page_dirty_to(unsigned long priv) +static inline size_t afs_page_dirty_to(struct page *page, unsigned long priv) { unsigned long x = (priv >> __AFS_PAGE_PRIV_SHIFT) & __AFS_PAGE_PRIV_MASK; /* The upper bound is immediately beyond the region */ - return (x + 1) << afs_page_dirty_resolution(); + return (x + 1) << afs_page_dirty_resolution(page); } -static inline unsigned long afs_page_dirty(size_t from, size_t to) +static inline unsigned long afs_page_dirty(struct page *page, size_t from, size_t to) { - unsigned int res = afs_page_dirty_resolution(); + unsigned int res = afs_page_dirty_resolution(page); from >>= res; to = (to - 1) >> res; return (to << __AFS_PAGE_PRIV_SHIFT) | from; @@ -1040,13 +1045,14 @@ extern void afs_dynroot_depopulate(struct super_block *); extern const struct address_space_operations afs_fs_aops; extern const struct inode_operations afs_file_inode_operations; extern const struct file_operations afs_file_operations; +extern const struct netfs_read_request_ops afs_req_ops; extern int afs_cache_wb_key(struct afs_vnode *, struct afs_file *); extern void afs_put_wb_key(struct afs_wb_key *); extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); -extern int afs_fetch_data(struct afs_vnode *, struct key *, struct afs_read *); -extern int afs_page_filler(void *, struct page *); +extern int afs_fetch_data(struct afs_vnode *, struct afs_read *); +extern struct afs_read *afs_alloc_read(gfp_t); extern void afs_put_read(struct afs_read *); static inline struct afs_read *afs_get_read(struct afs_read *req) @@ -1270,6 +1276,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size) { + call->iov_len = size; call->kvec[0].iov_base = buf; call->kvec[0].iov_len = size; iov_iter_kvec(&call->def_iter, READ, call->kvec, 1, size); @@ -1277,21 +1284,25 @@ static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t si static inline void afs_extract_to_tmp(struct afs_call *call) { + call->iov_len = sizeof(call->tmp); afs_extract_begin(call, &call->tmp, sizeof(call->tmp)); } static inline void afs_extract_to_tmp64(struct afs_call *call) { + call->iov_len = sizeof(call->tmp64); afs_extract_begin(call, &call->tmp64, sizeof(call->tmp64)); } static inline void afs_extract_discard(struct afs_call *call, size_t size) { + call->iov_len = size; iov_iter_discard(&call->def_iter, READ, size); } static inline void afs_extract_to_buf(struct afs_call *call, size_t size) { + call->iov_len = size; afs_extract_begin(call, call->buffer, size); } diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 8be709cb8542aab247fb390063a51bef8eb8849c..23a1a92d64bb5c4adfe4ce11ee34385917393e9e 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -271,40 +271,6 @@ void afs_flat_call_destructor(struct afs_call *call) call->buffer = NULL; } -#define AFS_BVEC_MAX 8 - -/* - * Load the given bvec with the next few pages. - */ -static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, - struct bio_vec *bv, pgoff_t first, pgoff_t last, - unsigned offset) -{ - struct afs_operation *op = call->op; - struct page *pages[AFS_BVEC_MAX]; - unsigned int nr, n, i, to, bytes = 0; - - nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); - n = find_get_pages_contig(op->store.mapping, first, nr, pages); - ASSERTCMP(n, ==, nr); - - msg->msg_flags |= MSG_MORE; - for (i = 0; i < nr; i++) { - to = PAGE_SIZE; - if (first + i >= last) { - to = op->store.last_to; - msg->msg_flags &= ~MSG_MORE; - } - bv[i].bv_page = pages[i]; - bv[i].bv_len = to - offset; - bv[i].bv_offset = offset; - bytes += to - offset; - offset = 0; - } - - iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes); -} - /* * Advance the AFS call state when the RxRPC call ends the transmit phase. */ @@ -317,42 +283,6 @@ static void afs_notify_end_request_tx(struct sock *sock, afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY); } -/* - * attach the data from a bunch of pages on an inode to a call - */ -static int afs_send_pages(struct afs_call *call, struct msghdr *msg) -{ - struct afs_operation *op = call->op; - struct bio_vec bv[AFS_BVEC_MAX]; - unsigned int bytes, nr, loop, offset; - pgoff_t first = op->store.first, last = op->store.last; - int ret; - - offset = op->store.first_offset; - op->store.first_offset = 0; - - do { - afs_load_bvec(call, msg, bv, first, last, offset); - trace_afs_send_pages(call, msg, first, last, offset); - - offset = 0; - bytes = msg->msg_iter.count; - nr = msg->msg_iter.nr_segs; - - ret = rxrpc_kernel_send_data(op->net->socket, call->rxcall, msg, - bytes, afs_notify_end_request_tx); - for (loop = 0; loop < nr; loop++) - put_page(bv[loop].bv_page); - if (ret < 0) - break; - - first += nr; - } while (first <= last); - - trace_afs_sent_pages(call, op->store.first, last, first, ret); - return ret; -} - /* * Initiate a call and synchronously queue up the parameters for dispatch. Any * error is stored into the call struct, which the caller must check for. @@ -363,6 +293,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) struct rxrpc_call *rxcall; struct msghdr msg; struct kvec iov[1]; + size_t len; s64 tx_total_len; int ret; @@ -383,21 +314,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) * after the initial fixed part. */ tx_total_len = call->request_size; - if (call->send_pages) { - struct afs_operation *op = call->op; - - if (op->store.last == op->store.first) { - tx_total_len += op->store.last_to - op->store.first_offset; - } else { - /* It looks mathematically like you should be able to - * combine the following lines with the ones above, but - * unsigned arithmetic is fun when it wraps... - */ - tx_total_len += PAGE_SIZE - op->store.first_offset; - tx_total_len += op->store.last_to; - tx_total_len += (op->store.last - op->store.first - 1) * PAGE_SIZE; - } - } + if (call->write_iter) + tx_total_len += iov_iter_count(call->write_iter); /* If the call is going to be asynchronous, we need an extra ref for * the call to hold itself so the caller need not hang on to its ref. @@ -439,7 +357,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size); msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); + msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0); ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg, call->request_size, @@ -447,8 +365,18 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) if (ret < 0) goto error_do_abort; - if (call->send_pages) { - ret = afs_send_pages(call, &msg); + if (call->write_iter) { + msg.msg_iter = *call->write_iter; + msg.msg_flags &= ~MSG_MORE; + trace_afs_send_data(call, &msg); + + ret = rxrpc_kernel_send_data(call->net->socket, + call->rxcall, &msg, + iov_iter_count(&msg.msg_iter), + afs_notify_end_request_tx); + *call->write_iter = msg.msg_iter; + + trace_afs_sent_data(call, &msg, ret); if (ret < 0) goto error_do_abort; } @@ -466,9 +394,10 @@ error_do_abort: rxrpc_kernel_abort_call(call->net->socket, rxcall, RX_USER_ABORT, ret, "KSD"); } else { + len = 0; iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0); rxrpc_kernel_recv_data(call->net->socket, rxcall, - &msg.msg_iter, false, + &msg.msg_iter, &len, false, &call->abort_code, &call->service_id); ac->abort_code = call->abort_code; ac->responded = true; @@ -498,12 +427,46 @@ error_kill_call: _leave(" = %d", ret); } +/* + * Log remote abort codes that indicate that we have a protocol disagreement + * with the server. + */ +static void afs_log_error(struct afs_call *call, s32 remote_abort) +{ + static int max = 0; + const char *msg; + int m; + + switch (remote_abort) { + case RX_EOF: msg = "unexpected EOF"; break; + case RXGEN_CC_MARSHAL: msg = "client marshalling"; break; + case RXGEN_CC_UNMARSHAL: msg = "client unmarshalling"; break; + case RXGEN_SS_MARSHAL: msg = "server marshalling"; break; + case RXGEN_SS_UNMARSHAL: msg = "server unmarshalling"; break; + case RXGEN_DECODE: msg = "opcode decode"; break; + case RXGEN_SS_XDRFREE: msg = "server XDR cleanup"; break; + case RXGEN_CC_XDRFREE: msg = "client XDR cleanup"; break; + case -32: msg = "insufficient data"; break; + default: + return; + } + + m = max; + if (m < 3) { + max = m + 1; + pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n", + msg, call->type->name, + &call->alist->addrs[call->addr_ix].transport); + } +} + /* * deliver messages to a call */ static void afs_deliver_to_call(struct afs_call *call) { enum afs_call_state state; + size_t len; u32 abort_code, remote_abort = 0; int ret; @@ -516,10 +479,11 @@ static void afs_deliver_to_call(struct afs_call *call) state == AFS_CALL_SV_AWAIT_ACK ) { if (state == AFS_CALL_SV_AWAIT_ACK) { + len = 0; iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0); ret = rxrpc_kernel_recv_data(call->net->socket, call->rxcall, &call->def_iter, - false, &remote_abort, + &len, false, &remote_abort, &call->service_id); trace_afs_receive_data(call, &call->def_iter, false, ret); @@ -559,6 +523,7 @@ static void afs_deliver_to_call(struct afs_call *call) goto out; case -ECONNABORTED: ASSERTCMP(state, ==, AFS_CALL_COMPLETE); + afs_log_error(call, call->abort_code); goto done; case -ENOTSUPP: abort_code = RXGEN_OPCODE; @@ -929,10 +894,11 @@ int afs_extract_data(struct afs_call *call, bool want_more) u32 remote_abort = 0; int ret; - _enter("{%s,%zu},%d", call->type->name, iov_iter_count(iter), want_more); + _enter("{%s,%zu,%zu},%d", + call->type->name, call->iov_len, iov_iter_count(iter), want_more); ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter, - want_more, &remote_abort, + &call->iov_len, want_more, &remote_abort, &call->service_id); if (ret == 0 || ret == -EAGAIN) return ret; diff --git a/fs/afs/write.c b/fs/afs/write.c index eb737ed63afb6041f26207171b95960e5ec6e7a9..dc66ff15dd16e40d6c6d086e72e12b8c38105d19 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -11,6 +11,8 @@ #include <linux/pagemap.h> #include <linux/writeback.h> #include <linux/pagevec.h> +#include <linux/netfs.h> +#include <linux/fscache.h> #include "internal.h" /* @@ -22,55 +24,6 @@ int afs_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } -/* - * partly or wholly fill a page that's under preparation for writing - */ -static int afs_fill_page(struct afs_vnode *vnode, struct key *key, - loff_t pos, unsigned int len, struct page *page) -{ - struct afs_read *req; - size_t p; - void *data; - int ret; - - _enter(",,%llu", (unsigned long long)pos); - - if (pos >= vnode->vfs_inode.i_size) { - p = pos & ~PAGE_MASK; - ASSERTCMP(p + len, <=, PAGE_SIZE); - data = kmap(page); - memset(data + p, 0, len); - kunmap(page); - return 0; - } - - req = kzalloc(struct_size(req, array, 1), GFP_KERNEL); - if (!req) - return -ENOMEM; - - refcount_set(&req->usage, 1); - req->pos = pos; - req->len = len; - req->nr_pages = 1; - req->pages = req->array; - req->pages[0] = page; - get_page(page); - - ret = afs_fetch_data(vnode, key, req); - afs_put_read(req); - if (ret < 0) { - if (ret == -ENOENT) { - _debug("got NOENT from server" - " - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - } - } - - _leave(" = %d", ret); - return ret; -} - /* * prepare to perform part of a write to a page */ @@ -80,47 +33,40 @@ int afs_write_begin(struct file *file, struct address_space *mapping, { struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); struct page *page; - struct key *key = afs_file_key(file); unsigned long priv; - unsigned f, from = pos & (PAGE_SIZE - 1); - unsigned t, to = from + len; - pgoff_t index = pos >> PAGE_SHIFT; + unsigned f, from; + unsigned t, to; + pgoff_t index; int ret; - _enter("{%llx:%llu},{%lx},%u,%u", - vnode->fid.vid, vnode->fid.vnode, index, from, to); + _enter("{%llx:%llu},%llx,%x", + vnode->fid.vid, vnode->fid.vnode, pos, len); - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; + /* Prefetch area to be written into the cache if we're caching this + * file. We need to do this before we get a lock on the page in case + * there's more than one writer competing for the same cache block. + */ + ret = netfs_write_begin(file, mapping, pos, len, flags, &page, fsdata, + &afs_req_ops, NULL); + if (ret < 0) + return ret; - if (!PageUptodate(page) && len != PAGE_SIZE) { - ret = afs_fill_page(vnode, key, pos & PAGE_MASK, PAGE_SIZE, page); - if (ret < 0) { - unlock_page(page); - put_page(page); - _leave(" = %d [prep]", ret); - return ret; - } - SetPageUptodate(page); - } + index = page->index; + from = pos - index * PAGE_SIZE; + to = from + len; try_again: /* See if this page is already partially written in a way that we can * merge the new write with. */ - t = f = 0; if (PagePrivate(page)) { priv = page_private(page); - f = afs_page_dirty_from(priv); - t = afs_page_dirty_to(priv); + f = afs_page_dirty_from(page, priv); + t = afs_page_dirty_to(page, priv); ASSERTCMP(f, <=, t); - } - if (f != t) { if (PageWriteback(page)) { - trace_afs_page_dirty(vnode, tracepoint_string("alrdy"), - page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("alrdy"), page); goto flush_conflicting_write; } /* If the file is being filled locally, allow inter-write @@ -164,12 +110,10 @@ int afs_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); - struct key *key = afs_file_key(file); unsigned long priv; - unsigned int f, from = pos & (PAGE_SIZE - 1); + unsigned int f, from = pos & (thp_size(page) - 1); unsigned int t, to = from + copied; loff_t i_size, maybe_i_size; - int ret = 0; _enter("{%llx:%llu},{%lx}", vnode->fid.vid, vnode->fid.vnode, page->index); @@ -188,88 +132,75 @@ int afs_write_end(struct file *file, struct address_space *mapping, write_sequnlock(&vnode->cb_lock); } - if (!PageUptodate(page)) { - if (copied < len) { - /* Try and load any missing data from the server. The - * unmarshalling routine will take care of clearing any - * bits that are beyond the EOF. - */ - ret = afs_fill_page(vnode, key, pos + copied, - len - copied, page); - if (ret < 0) - goto out; - } - SetPageUptodate(page); - } + ASSERT(PageUptodate(page)); if (PagePrivate(page)) { priv = page_private(page); - f = afs_page_dirty_from(priv); - t = afs_page_dirty_to(priv); + f = afs_page_dirty_from(page, priv); + t = afs_page_dirty_to(page, priv); if (from < f) f = from; if (to > t) t = to; - priv = afs_page_dirty(f, t); + priv = afs_page_dirty(page, f, t); set_page_private(page, priv); - trace_afs_page_dirty(vnode, tracepoint_string("dirty+"), - page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("dirty+"), page); } else { - priv = afs_page_dirty(from, to); + priv = afs_page_dirty(page, from, to); attach_page_private(page, (void *)priv); - trace_afs_page_dirty(vnode, tracepoint_string("dirty"), - page->index, priv); + trace_afs_page_dirty(vnode, tracepoint_string("dirty"), page); } - set_page_dirty(page); - if (PageDirty(page)) - _debug("dirtied"); - ret = copied; + if (set_page_dirty(page)) + _debug("dirtied %lx", page->index); out: unlock_page(page); put_page(page); - return ret; + return copied; } /* * kill all the pages in the given range */ static void afs_kill_pages(struct address_space *mapping, - pgoff_t first, pgoff_t last) + loff_t start, loff_t len) { struct afs_vnode *vnode = AFS_FS_I(mapping->host); struct pagevec pv; - unsigned count, loop; + unsigned int loop, psize; - _enter("{%llx:%llu},%lx-%lx", - vnode->fid.vid, vnode->fid.vnode, first, last); + _enter("{%llx:%llu},%llx @%llx", + vnode->fid.vid, vnode->fid.vnode, len, start); pagevec_init(&pv); do { - _debug("kill %lx-%lx", first, last); + _debug("kill %llx @%llx", len, start); - count = last - first + 1; - if (count > PAGEVEC_SIZE) - count = PAGEVEC_SIZE; - pv.nr = find_get_pages_contig(mapping, first, count, pv.pages); - ASSERTCMP(pv.nr, ==, count); + pv.nr = find_get_pages_contig(mapping, start / PAGE_SIZE, + PAGEVEC_SIZE, pv.pages); + if (pv.nr == 0) + break; - for (loop = 0; loop < count; loop++) { + for (loop = 0; loop < pv.nr; loop++) { struct page *page = pv.pages[loop]; + + if (page->index * PAGE_SIZE >= start + len) + break; + + psize = thp_size(page); + start += psize; + len -= psize; ClearPageUptodate(page); - SetPageError(page); end_page_writeback(page); - if (page->index >= first) - first = page->index + 1; lock_page(page); generic_error_remove_page(mapping, page); unlock_page(page); } __pagevec_release(&pv); - } while (first <= last); + } while (len > 0); _leave(""); } @@ -279,37 +210,40 @@ static void afs_kill_pages(struct address_space *mapping, */ static void afs_redirty_pages(struct writeback_control *wbc, struct address_space *mapping, - pgoff_t first, pgoff_t last) + loff_t start, loff_t len) { struct afs_vnode *vnode = AFS_FS_I(mapping->host); struct pagevec pv; - unsigned count, loop; + unsigned int loop, psize; - _enter("{%llx:%llu},%lx-%lx", - vnode->fid.vid, vnode->fid.vnode, first, last); + _enter("{%llx:%llu},%llx @%llx", + vnode->fid.vid, vnode->fid.vnode, len, start); pagevec_init(&pv); do { - _debug("redirty %lx-%lx", first, last); + _debug("redirty %llx @%llx", len, start); - count = last - first + 1; - if (count > PAGEVEC_SIZE) - count = PAGEVEC_SIZE; - pv.nr = find_get_pages_contig(mapping, first, count, pv.pages); - ASSERTCMP(pv.nr, ==, count); + pv.nr = find_get_pages_contig(mapping, start / PAGE_SIZE, + PAGEVEC_SIZE, pv.pages); + if (pv.nr == 0) + break; - for (loop = 0; loop < count; loop++) { + for (loop = 0; loop < pv.nr; loop++) { struct page *page = pv.pages[loop]; + if (page->index * PAGE_SIZE >= start + len) + break; + + psize = thp_size(page); + start += psize; + len -= psize; redirty_page_for_writepage(wbc, page); end_page_writeback(page); - if (page->index >= first) - first = page->index + 1; } __pagevec_release(&pv); - } while (first <= last); + } while (len > 0); _leave(""); } @@ -317,37 +251,32 @@ static void afs_redirty_pages(struct writeback_control *wbc, /* * completion of write to server */ -static void afs_pages_written_back(struct afs_vnode *vnode, - pgoff_t first, pgoff_t last) +static void afs_pages_written_back(struct afs_vnode *vnode, loff_t start, unsigned int len) { - struct pagevec pv; - unsigned long priv; - unsigned count, loop; + struct address_space *mapping = vnode->vfs_inode.i_mapping; + struct page *page; + pgoff_t end; - _enter("{%llx:%llu},{%lx-%lx}", - vnode->fid.vid, vnode->fid.vnode, first, last); + XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE); - pagevec_init(&pv); + _enter("{%llx:%llu},{%x @%llx}", + vnode->fid.vid, vnode->fid.vnode, len, start); - do { - _debug("done %lx-%lx", first, last); - - count = last - first + 1; - if (count > PAGEVEC_SIZE) - count = PAGEVEC_SIZE; - pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, - first, count, pv.pages); - ASSERTCMP(pv.nr, ==, count); - - for (loop = 0; loop < count; loop++) { - priv = (unsigned long)detach_page_private(pv.pages[loop]); - trace_afs_page_dirty(vnode, tracepoint_string("clear"), - pv.pages[loop]->index, priv); - end_page_writeback(pv.pages[loop]); + rcu_read_lock(); + + end = (start + len - 1) / PAGE_SIZE; + xas_for_each(&xas, page, end) { + if (!PageWriteback(page)) { + kdebug("bad %x @%llx page %lx %lx", len, start, page->index, end); + ASSERT(PageWriteback(page)); } - first += count; - __pagevec_release(&pv); - } while (first <= last); + + trace_afs_page_dirty(vnode, tracepoint_string("clear"), page); + detach_page_private(page); + page_endio(page, true, 0); + } + + rcu_read_unlock(); afs_prune_wb_keys(vnode); _leave(""); @@ -402,11 +331,9 @@ static void afs_store_data_success(struct afs_operation *op) afs_vnode_commit_status(op, &op->file[0]); if (op->error == 0) { if (!op->store.laundering) - afs_pages_written_back(vnode, op->store.first, op->store.last); + afs_pages_written_back(vnode, op->store.pos, op->store.size); afs_stat_v(vnode, n_stores); - atomic_long_add((op->store.last * PAGE_SIZE + op->store.last_to) - - (op->store.first * PAGE_SIZE + op->store.first_offset), - &afs_v2net(vnode)->n_store_bytes); + atomic_long_add(op->store.size, &afs_v2net(vnode)->n_store_bytes); } } @@ -419,21 +346,20 @@ static const struct afs_operation_ops afs_store_data_operation = { /* * write to a file */ -static int afs_store_data(struct address_space *mapping, - pgoff_t first, pgoff_t last, - unsigned offset, unsigned to, bool laundering) +static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_t pos, + bool laundering) { - struct afs_vnode *vnode = AFS_FS_I(mapping->host); struct afs_operation *op; struct afs_wb_key *wbk = NULL; - int ret; + loff_t size = iov_iter_count(iter), i_size; + int ret = -ENOKEY; - _enter("%s{%llx:%llu.%u},%lx,%lx,%x,%x", + _enter("%s{%llx:%llu.%u},%llx,%llx", vnode->volume->name, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, - first, last, offset, to); + size, pos); ret = afs_get_writeback_key(vnode, &wbk); if (ret) { @@ -447,13 +373,14 @@ static int afs_store_data(struct address_space *mapping, return -ENOMEM; } + i_size = i_size_read(&vnode->vfs_inode); + afs_op_set_vnode(op, 0, vnode); op->file[0].dv_delta = 1; - op->store.mapping = mapping; - op->store.first = first; - op->store.last = last; - op->store.first_offset = offset; - op->store.last_to = to; + op->store.write_iter = iter; + op->store.pos = pos; + op->store.size = size; + op->store.i_size = max(pos + size, i_size); op->store.laundering = laundering; op->mtime = vnode->vfs_inode.i_mtime; op->flags |= AFS_OPERATION_UNINTR; @@ -487,73 +414,58 @@ try_next_key: } /* - * Synchronously write back the locked page and any subsequent non-locked dirty - * pages. + * Extend the region to be written back to include subsequent contiguously + * dirty pages if possible, but don't sleep while doing so. + * + * If this page holds new content, then we can include filler zeros in the + * writeback. */ -static int afs_write_back_from_locked_page(struct address_space *mapping, - struct writeback_control *wbc, - struct page *primary_page, - pgoff_t final_page) +static void afs_extend_writeback(struct address_space *mapping, + struct afs_vnode *vnode, + long *_count, + loff_t start, + loff_t max_len, + bool new_content, + unsigned int *_len) { - struct afs_vnode *vnode = AFS_FS_I(mapping->host); - struct page *pages[8], *page; - unsigned long count, priv; - unsigned n, offset, to, f, t; - pgoff_t start, first, last; - loff_t i_size, end; - int loop, ret; - - _enter(",%lx", primary_page->index); + struct pagevec pvec; + struct page *page; + unsigned long priv; + unsigned int psize, filler = 0; + unsigned int f, t; + loff_t len = *_len; + pgoff_t index = (start + len) / PAGE_SIZE; + bool stop = true; + unsigned int i; - count = 1; - if (test_set_page_writeback(primary_page)) - BUG(); + XA_STATE(xas, &mapping->i_pages, index); + pagevec_init(&pvec); - /* Find all consecutive lockable dirty pages that have contiguous - * written regions, stopping when we find a page that is not - * immediately lockable, is not dirty or is missing, or we reach the - * end of the range. - */ - start = primary_page->index; - priv = page_private(primary_page); - offset = afs_page_dirty_from(priv); - to = afs_page_dirty_to(priv); - trace_afs_page_dirty(vnode, tracepoint_string("store"), - primary_page->index, priv); - - WARN_ON(offset == to); - if (offset == to) - trace_afs_page_dirty(vnode, tracepoint_string("WARN"), - primary_page->index, priv); - - if (start >= final_page || - (to < PAGE_SIZE && !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags))) - goto no_more; - - start++; do { - _debug("more %lx [%lx]", start, count); - n = final_page - start + 1; - if (n > ARRAY_SIZE(pages)) - n = ARRAY_SIZE(pages); - n = find_get_pages_contig(mapping, start, ARRAY_SIZE(pages), pages); - _debug("fgpc %u", n); - if (n == 0) - goto no_more; - if (pages[0]->index != start) { - do { - put_page(pages[--n]); - } while (n > 0); - goto no_more; - } + /* Firstly, we gather up a batch of contiguous dirty pages + * under the RCU read lock - but we can't clear the dirty flags + * there if any of those pages are mapped. + */ + rcu_read_lock(); - for (loop = 0; loop < n; loop++) { - page = pages[loop]; - if (to != PAGE_SIZE && - !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) + xas_for_each(&xas, page, ULONG_MAX) { + stop = true; + if (xas_retry(&xas, page)) + continue; + if (xa_is_value(page)) break; - if (page->index > final_page) + if (page->index != index) break; + + if (!page_cache_get_speculative(page)) { + xas_reset(&xas); + continue; + } + + /* Has the page moved or been split? */ + if (unlikely(page != xas_reload(&xas))) + break; + if (!trylock_page(page)) break; if (!PageDirty(page) || PageWriteback(page)) { @@ -561,57 +473,134 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, break; } + psize = thp_size(page); priv = page_private(page); - f = afs_page_dirty_from(priv); - t = afs_page_dirty_to(priv); - if (f != 0 && - !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) { + f = afs_page_dirty_from(page, priv); + t = afs_page_dirty_to(page, priv); + if (f != 0 && !new_content) { unlock_page(page); break; } - to = t; - trace_afs_page_dirty(vnode, tracepoint_string("store+"), - page->index, priv); + len += filler + t; + filler = psize - t; + if (len >= max_len || *_count <= 0) + stop = true; + else if (t == psize || new_content) + stop = false; + + index += thp_nr_pages(page); + if (!pagevec_add(&pvec, page)) + break; + if (stop) + break; + } + + if (!stop) + xas_pause(&xas); + rcu_read_unlock(); + + /* Now, if we obtained any pages, we can shift them to being + * writable and mark them for caching. + */ + if (!pagevec_count(&pvec)) + break; + + for (i = 0; i < pagevec_count(&pvec); i++) { + page = pvec.pages[i]; + trace_afs_page_dirty(vnode, tracepoint_string("store+"), page); if (!clear_page_dirty_for_io(page)) BUG(); if (test_set_page_writeback(page)) BUG(); + + *_count -= thp_nr_pages(page); unlock_page(page); - put_page(page); - } - count += loop; - if (loop < n) { - for (; loop < n; loop++) - put_page(pages[loop]); - goto no_more; } - start += loop; - } while (start <= final_page && count < 65536); + pagevec_release(&pvec); + cond_resched(); + } while (!stop); + + *_len = len; +} + +/* + * Synchronously write back the locked page and any subsequent non-locked dirty + * pages. + */ +static ssize_t afs_write_back_from_locked_page(struct address_space *mapping, + struct writeback_control *wbc, + struct page *page, + loff_t start, loff_t end) +{ + struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct iov_iter iter; + unsigned long priv; + unsigned int offset, to, len, max_len; + loff_t i_size = i_size_read(&vnode->vfs_inode); + bool new_content = test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); + long count = wbc->nr_to_write; + int ret; + + _enter(",%lx,%llx-%llx", page->index, start, end); + + if (test_set_page_writeback(page)) + BUG(); + + count -= thp_nr_pages(page); + + /* Find all consecutive lockable dirty pages that have contiguous + * written regions, stopping when we find a page that is not + * immediately lockable, is not dirty or is missing, or we reach the + * end of the range. + */ + priv = page_private(page); + offset = afs_page_dirty_from(page, priv); + to = afs_page_dirty_to(page, priv); + trace_afs_page_dirty(vnode, tracepoint_string("store"), page); + + len = to - offset; + start += offset; + if (start < i_size) { + /* Trim the write to the EOF; the extra data is ignored. Also + * put an upper limit on the size of a single storedata op. + */ + max_len = 65536 * 4096; + max_len = min_t(unsigned long long, max_len, end - start + 1); + max_len = min_t(unsigned long long, max_len, i_size - start); + + if (len < max_len && + (to == thp_size(page) || new_content)) + afs_extend_writeback(mapping, vnode, &count, + start, max_len, new_content, &len); + len = min_t(loff_t, len, max_len); + } -no_more: /* We now have a contiguous set of dirty pages, each with writeback * set; the first page is still locked at this point, but all the rest * have been unlocked. */ - unlock_page(primary_page); + unlock_page(page); - first = primary_page->index; - last = first + count - 1; + if (start < i_size) { + _debug("write back %x @%llx [%llx]", len, start, i_size); - end = (loff_t)last * PAGE_SIZE + to; - i_size = i_size_read(&vnode->vfs_inode); + iov_iter_xarray(&iter, WRITE, &mapping->i_pages, start, len); + ret = afs_store_data(vnode, &iter, start, false); + } else { + _debug("write discard %x @%llx [%llx]", len, start, i_size); - _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to); - if (end > i_size) - to = i_size & ~PAGE_MASK; + /* The dirty region was entirely beyond the EOF. */ + afs_pages_written_back(vnode, start, len); + ret = 0; + } - ret = afs_store_data(mapping, first, last, offset, to, false); switch (ret) { case 0: - ret = count; + wbc->nr_to_write = count; + ret = len; break; default: @@ -623,13 +612,13 @@ no_more: case -EKEYEXPIRED: case -EKEYREJECTED: case -EKEYREVOKED: - afs_redirty_pages(wbc, mapping, first, last); + afs_redirty_pages(wbc, mapping, start, len); mapping_set_error(mapping, ret); break; case -EDQUOT: case -ENOSPC: - afs_redirty_pages(wbc, mapping, first, last); + afs_redirty_pages(wbc, mapping, start, len); mapping_set_error(mapping, -ENOSPC); break; @@ -641,7 +630,7 @@ no_more: case -ENOMEDIUM: case -ENXIO: trace_afs_file_error(vnode, ret, afs_file_error_writeback_fail); - afs_kill_pages(mapping, first, last); + afs_kill_pages(mapping, start, len); mapping_set_error(mapping, ret); break; } @@ -656,19 +645,19 @@ no_more: */ int afs_writepage(struct page *page, struct writeback_control *wbc) { - int ret; + ssize_t ret; + loff_t start; _enter("{%lx},", page->index); + start = page->index * PAGE_SIZE; ret = afs_write_back_from_locked_page(page->mapping, wbc, page, - wbc->range_end >> PAGE_SHIFT); + start, LLONG_MAX - start); if (ret < 0) { - _leave(" = %d", ret); - return 0; + _leave(" = %zd", ret); + return ret; } - wbc->nr_to_write -= ret; - _leave(" = 0"); return 0; } @@ -678,35 +667,46 @@ int afs_writepage(struct page *page, struct writeback_control *wbc) */ static int afs_writepages_region(struct address_space *mapping, struct writeback_control *wbc, - pgoff_t index, pgoff_t end, pgoff_t *_next) + loff_t start, loff_t end, loff_t *_next) { struct page *page; - int ret, n; + ssize_t ret; + int n; - _enter(",,%lx,%lx,", index, end); + _enter("%llx,%llx,", start, end); do { - n = find_get_pages_range_tag(mapping, &index, end, - PAGECACHE_TAG_DIRTY, 1, &page); + pgoff_t index = start / PAGE_SIZE; + + n = find_get_pages_range_tag(mapping, &index, end / PAGE_SIZE, + PAGECACHE_TAG_DIRTY, 1, &page); if (!n) break; + start = (loff_t)page->index * PAGE_SIZE; /* May regress with THPs */ + _debug("wback %lx", page->index); - /* - * at this point we hold neither the i_pages lock nor the + /* At this point we hold neither the i_pages lock nor the * page lock: the page may be truncated or invalidated * (changing page->mapping to NULL), or even swizzled * back from swapper_space to tmpfs file mapping */ - ret = lock_page_killable(page); - if (ret < 0) { - put_page(page); - _leave(" = %d", ret); - return ret; + if (wbc->sync_mode != WB_SYNC_NONE) { + ret = lock_page_killable(page); + if (ret < 0) { + put_page(page); + return ret; + } + } else { + if (!trylock_page(page)) { + put_page(page); + return 0; + } } if (page->mapping != mapping || !PageDirty(page)) { + start += thp_size(page); unlock_page(page); put_page(page); continue; @@ -722,20 +722,20 @@ static int afs_writepages_region(struct address_space *mapping, if (!clear_page_dirty_for_io(page)) BUG(); - ret = afs_write_back_from_locked_page(mapping, wbc, page, end); + ret = afs_write_back_from_locked_page(mapping, wbc, page, start, end); put_page(page); if (ret < 0) { - _leave(" = %d", ret); + _leave(" = %zd", ret); return ret; } - wbc->nr_to_write -= ret; + start += ret * PAGE_SIZE; cond_resched(); - } while (index < end && wbc->nr_to_write > 0); + } while (wbc->nr_to_write > 0); - *_next = index; - _leave(" = 0 [%lx]", *_next); + *_next = start; + _leave(" = 0 [%llx]", *_next); return 0; } @@ -746,7 +746,7 @@ int afs_writepages(struct address_space *mapping, struct writeback_control *wbc) { struct afs_vnode *vnode = AFS_FS_I(mapping->host); - pgoff_t start, end, next; + loff_t start, next; int ret; _enter(""); @@ -761,22 +761,19 @@ int afs_writepages(struct address_space *mapping, return 0; if (wbc->range_cyclic) { - start = mapping->writeback_index; - end = -1; - ret = afs_writepages_region(mapping, wbc, start, end, &next); + start = mapping->writeback_index * PAGE_SIZE; + ret = afs_writepages_region(mapping, wbc, start, LLONG_MAX, &next); if (start > 0 && wbc->nr_to_write > 0 && ret == 0) ret = afs_writepages_region(mapping, wbc, 0, start, &next); - mapping->writeback_index = next; + mapping->writeback_index = next / PAGE_SIZE; } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) { - end = (pgoff_t)(LLONG_MAX >> PAGE_SHIFT); - ret = afs_writepages_region(mapping, wbc, 0, end, &next); + ret = afs_writepages_region(mapping, wbc, 0, LLONG_MAX, &next); if (wbc->nr_to_write > 0) mapping->writeback_index = next; } else { - start = wbc->range_start >> PAGE_SHIFT; - end = wbc->range_end >> PAGE_SHIFT; - ret = afs_writepages_region(mapping, wbc, start, end, &next); + ret = afs_writepages_region(mapping, wbc, + wbc->range_start, wbc->range_end, &next); } up_read(&vnode->validate_lock); @@ -834,13 +831,13 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) */ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) { + struct page *page = thp_head(vmf->page); struct file *file = vmf->vma->vm_file; struct inode *inode = file_inode(file); struct afs_vnode *vnode = AFS_FS_I(inode); unsigned long priv; - _enter("{{%llx:%llu}},{%lx}", - vnode->fid.vid, vnode->fid.vnode, vmf->page->index); + _enter("{{%llx:%llu}},{%lx}", vnode->fid.vid, vnode->fid.vnode, page->index); sb_start_pagefault(inode->i_sb); @@ -848,29 +845,35 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) * be modified. We then assume the entire page will need writing back. */ #ifdef CONFIG_AFS_FSCACHE - fscache_wait_on_page_write(vnode->cache, vmf->page); + if (PageFsCache(page) && + wait_on_page_fscache_killable(page) < 0) + return VM_FAULT_RETRY; #endif - if (wait_on_page_writeback_killable(vmf->page)) + if (wait_on_page_writeback_killable(page)) return VM_FAULT_RETRY; - if (lock_page_killable(vmf->page) < 0) + if (lock_page_killable(page) < 0) return VM_FAULT_RETRY; /* We mustn't change page->private until writeback is complete as that * details the portion of the page we need to write back and we might * need to redirty the page if there's a problem. */ - wait_on_page_writeback(vmf->page); + if (wait_on_page_writeback_killable(page) < 0) { + unlock_page(page); + return VM_FAULT_RETRY; + } - priv = afs_page_dirty(0, PAGE_SIZE); + priv = afs_page_dirty(page, 0, thp_size(page)); priv = afs_page_dirty_mmapped(priv); - trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"), - vmf->page->index, priv); - if (PagePrivate(vmf->page)) - set_page_private(vmf->page, priv); - else - attach_page_private(vmf->page, (void *)priv); + if (PagePrivate(page)) { + set_page_private(page, priv); + trace_afs_page_dirty(vnode, tracepoint_string("mkwrite+"), page); + } else { + attach_page_private(page, (void *)priv); + trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"), page); + } file_update_time(file); sb_end_pagefault(inode->i_sb); @@ -912,6 +915,8 @@ int afs_launder_page(struct page *page) { struct address_space *mapping = page->mapping; struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct iov_iter iter; + struct bio_vec bv[1]; unsigned long priv; unsigned int f, t; int ret = 0; @@ -921,26 +926,24 @@ int afs_launder_page(struct page *page) priv = page_private(page); if (clear_page_dirty_for_io(page)) { f = 0; - t = PAGE_SIZE; + t = thp_size(page); if (PagePrivate(page)) { - f = afs_page_dirty_from(priv); - t = afs_page_dirty_to(priv); + f = afs_page_dirty_from(page, priv); + t = afs_page_dirty_to(page, priv); } - trace_afs_page_dirty(vnode, tracepoint_string("launder"), - page->index, priv); - ret = afs_store_data(mapping, page->index, page->index, t, f, true); - } - - priv = (unsigned long)detach_page_private(page); - trace_afs_page_dirty(vnode, tracepoint_string("laundered"), - page->index, priv); + bv[0].bv_page = page; + bv[0].bv_offset = f; + bv[0].bv_len = t - f; + iov_iter_bvec(&iter, WRITE, bv, 1, bv[0].bv_len); -#ifdef CONFIG_AFS_FSCACHE - if (PageFsCache(page)) { - fscache_wait_on_page_write(vnode->cache, page); - fscache_uncache_page(vnode->cache, page); + trace_afs_page_dirty(vnode, tracepoint_string("launder"), page); + ret = afs_store_data(vnode, &iter, (loff_t)page->index * PAGE_SIZE, + true); } -#endif + + trace_afs_page_dirty(vnode, tracepoint_string("laundered"), page); + detach_page_private(page); + wait_on_page_fscache(page); return ret; } diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index bd787e71a657f9b683922eeb7cd2ac5b655eb620..2b35cba8ad62b7f801405643ba1657b654062c2e 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -360,22 +360,23 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) struct afs_vnode_param *vp = &op->file[0]; struct afs_read *req = op->fetch.req; const __be32 *bp; - unsigned int size; int ret; - _enter("{%u,%zu/%llu}", - call->unmarshall, iov_iter_count(call->iter), req->actual_len); + _enter("{%u,%zu, %zu/%llu}", + call->unmarshall, call->iov_len, iov_iter_count(call->iter), + req->actual_len); switch (call->unmarshall) { case 0: req->actual_len = 0; - req->index = 0; - req->offset = req->pos & (PAGE_SIZE - 1); afs_extract_to_tmp64(call); call->unmarshall++; fallthrough; - /* extract the returned data length */ + /* Extract the returned data length into ->actual_len. This + * may indicate more or less data than was requested will be + * returned. + */ case 1: _debug("extract data length"); ret = afs_extract_data(call, true); @@ -384,44 +385,25 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) req->actual_len = be64_to_cpu(call->tmp64); _debug("DATA length: %llu", req->actual_len); - req->remain = min(req->len, req->actual_len); - if (req->remain == 0) + + if (req->actual_len == 0) goto no_more_data; + call->iter = req->iter; + call->iov_len = min(req->actual_len, req->len); call->unmarshall++; - - begin_page: - ASSERTCMP(req->index, <, req->nr_pages); - if (req->remain > PAGE_SIZE - req->offset) - size = PAGE_SIZE - req->offset; - else - size = req->remain; - call->bvec[0].bv_len = size; - call->bvec[0].bv_offset = req->offset; - call->bvec[0].bv_page = req->pages[req->index]; - iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size); - ASSERTCMP(size, <=, PAGE_SIZE); fallthrough; /* extract the returned data */ case 2: _debug("extract data %zu/%llu", - iov_iter_count(call->iter), req->remain); + iov_iter_count(call->iter), req->actual_len); ret = afs_extract_data(call, true); if (ret < 0) return ret; - req->remain -= call->bvec[0].bv_len; - req->offset += call->bvec[0].bv_len; - ASSERTCMP(req->offset, <=, PAGE_SIZE); - if (req->offset == PAGE_SIZE) { - req->offset = 0; - req->index++; - if (req->remain > 0) - goto begin_page; - } - ASSERTCMP(req->remain, ==, 0); + call->iter = &call->def_iter; if (req->actual_len <= req->len) goto no_more_data; @@ -467,17 +449,6 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) break; } - for (; req->index < req->nr_pages; req->index++) { - if (req->offset < PAGE_SIZE) - zero_user_segment(req->pages[req->index], - req->offset, PAGE_SIZE); - req->offset = 0; - } - - if (req->page_done) - for (req->index = 0; req->index < req->nr_pages; req->index++) - req->page_done(req); - _leave(" = 0 [done]"); return 0; } @@ -516,6 +487,8 @@ void yfs_fs_fetch_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); + req->call_debug_id = call->debug_id; + /* marshall the parameters */ bp = call->request; bp = xdr_encode_u32(bp, YFSFETCHDATA64); @@ -1102,25 +1075,15 @@ void yfs_fs_store_data(struct afs_operation *op) { struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; - loff_t size, pos, i_size; __be32 *bp; _enter(",%x,{%llx:%llu},,", key_serial(op->key), vp->fid.vid, vp->fid.vnode); - size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset; - if (op->store.first != op->store.last) - size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT; - pos = (loff_t)op->store.first << PAGE_SHIFT; - pos += op->store.first_offset; - - i_size = i_size_read(&vp->vnode->vfs_inode); - if (pos + size > i_size) - i_size = size + pos; - _debug("size %llx, at %llx, i_size %llx", - (unsigned long long)size, (unsigned long long)pos, - (unsigned long long)i_size); + (unsigned long long)op->store.size, + (unsigned long long)op->store.pos, + (unsigned long long)op->store.i_size); call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64, sizeof(__be32) + @@ -1133,8 +1096,7 @@ void yfs_fs_store_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); - call->key = op->key; - call->send_pages = true; + call->write_iter = op->store.write_iter; /* marshall the parameters */ bp = call->request; @@ -1142,9 +1104,9 @@ void yfs_fs_store_data(struct afs_operation *op) bp = xdr_encode_u32(bp, 0); /* RPC flags */ bp = xdr_encode_YFSFid(bp, &vp->fid); bp = xdr_encode_YFSStoreStatus_mtime(bp, &op->mtime); - bp = xdr_encode_u64(bp, pos); - bp = xdr_encode_u64(bp, size); - bp = xdr_encode_u64(bp, i_size); + bp = xdr_encode_u64(bp, op->store.pos); + bp = xdr_encode_u64(bp, op->store.size); + bp = xdr_encode_u64(bp, op->store.i_size); yfs_check_req(call, bp); trace_afs_make_fs_call(call, &vp->fid); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b12ba98ae9f557c83788e5435ffd7dae0ced09df..187b3f2b9202a6145e57916cfa50d950579f4752 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -2267,8 +2267,7 @@ static int elf_core_dump(struct coredump_params *cprm) goto end_coredump; /* Align to page */ - if (!dump_skip(cprm, dataoff - cprm->pos)) - goto end_coredump; + dump_skip_to(cprm, dataoff); for (i = 0; i < vma_count; i++) { struct core_vma_metadata *meta = vma_meta + i; @@ -2276,7 +2275,6 @@ static int elf_core_dump(struct coredump_params *cprm) if (!dump_user_range(cprm, meta->start, meta->dump_size)) goto end_coredump; } - dump_truncate(cprm); if (!elf_core_write_extra_data(cprm)) goto end_coredump; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 3cfd6cd46f262f0a6381dde51464f1fc38223ea1..2c99b102c8600ab0fa041f84c49b000b5dcda04d 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1631,8 +1631,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; } - if (!dump_skip(cprm, dataoff - cprm->pos)) - goto end_coredump; + dump_skip_to(cprm, dataoff); if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count)) goto end_coredump; diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index b4fb997eda16257bf1bb126b51e0383aa36fa64f..cec88a66bd6c19d643eff8327ef581a87808c037 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -30,7 +30,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \ block-rsv.o delalloc-space.o block-group.o discard.o reflink.o \ - subpage.o + subpage.o tree-mod-log.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index f47c1528eb9a69aeba5f2cd0740333a05aa9238d..117d423fdb930b8792d5e602797951abcc55c7ee 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -14,6 +14,7 @@ #include "delayed-ref.h" #include "locking.h" #include "misc.h" +#include "tree-mod-log.h" /* Just an arbitrary number so we can be sure this happened */ #define BACKREF_FOUND_SHARED 6 @@ -452,7 +453,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, if (path->slots[0] >= btrfs_header_nritems(eb) || is_shared_data_backref(preftrees, eb->start) || ref->root_id != btrfs_header_owner(eb)) { - if (time_seq == SEQ_LAST) + if (time_seq == BTRFS_SEQ_LAST) ret = btrfs_next_leaf(root, path); else ret = btrfs_next_old_leaf(root, path, time_seq); @@ -476,7 +477,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, if (slot == 0 && (is_shared_data_backref(preftrees, eb->start) || ref->root_id != btrfs_header_owner(eb))) { - if (time_seq == SEQ_LAST) + if (time_seq == BTRFS_SEQ_LAST) ret = btrfs_next_leaf(root, path); else ret = btrfs_next_old_leaf(root, path, time_seq); @@ -514,7 +515,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, eie = NULL; } next: - if (time_seq == SEQ_LAST) + if (time_seq == BTRFS_SEQ_LAST) ret = btrfs_next_item(root, path); else ret = btrfs_next_old_item(root, path, time_seq); @@ -574,7 +575,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info, if (path->search_commit_root) root_level = btrfs_header_level(root->commit_root); - else if (time_seq == SEQ_LAST) + else if (time_seq == BTRFS_SEQ_LAST) root_level = btrfs_header_level(root->node); else root_level = btrfs_old_root_level(root, time_seq); @@ -605,7 +606,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info, search_key.offset >= LLONG_MAX) search_key.offset = 0; path->lowest_level = level; - if (time_seq == SEQ_LAST) + if (time_seq == BTRFS_SEQ_LAST) ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); else ret = btrfs_search_old_slot(root, &search_key, path, time_seq); @@ -1147,8 +1148,8 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, * indirect refs to their parent bytenr. * When roots are found, they're added to the roots list * - * If time_seq is set to SEQ_LAST, it will not search delayed_refs, and behave - * much like trans == NULL case, the difference only lies in it will not + * If time_seq is set to BTRFS_SEQ_LAST, it will not search delayed_refs, and + * behave much like trans == NULL case, the difference only lies in it will not * commit root. * The special case is for qgroup to search roots in commit_transaction(). * @@ -1199,7 +1200,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, path->skip_locking = 1; } - if (time_seq == SEQ_LAST) + if (time_seq == BTRFS_SEQ_LAST) path->skip_locking = 1; /* @@ -1217,9 +1218,9 @@ again: #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS if (trans && likely(trans->type != __TRANS_DUMMY) && - time_seq != SEQ_LAST) { + time_seq != BTRFS_SEQ_LAST) { #else - if (trans && time_seq != SEQ_LAST) { + if (trans && time_seq != BTRFS_SEQ_LAST) { #endif /* * look if there are updates for this ref queued and lock the @@ -1527,7 +1528,7 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr, struct btrfs_trans_handle *trans; struct ulist_iterator uiter; struct ulist_node *node; - struct seq_list elem = SEQ_LIST_INIT(elem); + struct btrfs_seq_list elem = BTRFS_SEQ_LIST_INIT(elem); int ret = 0; struct share_check shared = { .root_objectid = root->root_key.objectid, @@ -1953,7 +1954,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, struct ulist *roots = NULL; struct ulist_node *ref_node = NULL; struct ulist_node *root_node = NULL; - struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); + struct btrfs_seq_list seq_elem = BTRFS_SEQ_LIST_INIT(seq_elem); struct ulist_iterator ref_uiter; struct ulist_iterator root_uiter; @@ -1971,12 +1972,12 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, } if (trans) - btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); + btrfs_get_tree_mod_seq(fs_info, &seq_elem); else down_read(&fs_info->commit_root_sem); ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, - tree_mod_seq_elem.seq, &refs, + seq_elem.seq, &refs, &extent_item_pos, ignore_offset); if (ret) goto out; @@ -1984,7 +1985,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, ULIST_ITER_INIT(&ref_uiter); while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { ret = btrfs_find_all_roots_safe(trans, fs_info, ref_node->val, - tree_mod_seq_elem.seq, &roots, + seq_elem.seq, &roots, ignore_offset); if (ret) break; @@ -2007,7 +2008,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, free_leaf_list(refs); out: if (trans) { - btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); + btrfs_put_tree_mod_seq(fs_info, &seq_elem); btrfs_end_transaction(trans); } else { up_read(&fs_info->commit_root_sem); diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 744b99ddc28cab7139f34ca2672812ef09bee3bd..aa57bdc8fc89dd375b4949a4285fd3bc4bfffafb 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -1289,7 +1289,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) * Long running balances can keep us blocked here for eternity, so * simply skip deletion if we're unable to get the mutex. */ - if (!mutex_trylock(&fs_info->delete_unused_bgs_mutex)) + if (!mutex_trylock(&fs_info->reclaim_bgs_lock)) return; spin_lock(&fs_info->unused_bgs_lock); @@ -1462,12 +1462,12 @@ next: spin_lock(&fs_info->unused_bgs_lock); } spin_unlock(&fs_info->unused_bgs_lock); - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); return; flip_async: btrfs_end_transaction(trans); - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_put_block_group(block_group); btrfs_discard_punt_unused_bgs_list(fs_info); } @@ -1485,6 +1485,97 @@ void btrfs_mark_bg_unused(struct btrfs_block_group *bg) spin_unlock(&fs_info->unused_bgs_lock); } +void btrfs_reclaim_bgs_work(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info = + container_of(work, struct btrfs_fs_info, reclaim_bgs_work); + struct btrfs_block_group *bg; + struct btrfs_space_info *space_info; + int ret; + + if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags)) + return; + + if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) + return; + + mutex_lock(&fs_info->reclaim_bgs_lock); + spin_lock(&fs_info->unused_bgs_lock); + while (!list_empty(&fs_info->reclaim_bgs)) { + bg = list_first_entry(&fs_info->reclaim_bgs, + struct btrfs_block_group, + bg_list); + list_del_init(&bg->bg_list); + + space_info = bg->space_info; + spin_unlock(&fs_info->unused_bgs_lock); + + /* Don't race with allocators so take the groups_sem */ + down_write(&space_info->groups_sem); + + spin_lock(&bg->lock); + if (bg->reserved || bg->pinned || bg->ro) { + /* + * We want to bail if we made new allocations or have + * outstanding allocations in this block group. We do + * the ro check in case balance is currently acting on + * this block group. + */ + spin_unlock(&bg->lock); + up_write(&space_info->groups_sem); + goto next; + } + spin_unlock(&bg->lock); + + /* Get out fast, in case we're unmounting the filesystem */ + if (btrfs_fs_closing(fs_info)) { + up_write(&space_info->groups_sem); + goto next; + } + + ret = inc_block_group_ro(bg, 0); + up_write(&space_info->groups_sem); + if (ret < 0) + goto next; + + btrfs_info(fs_info, "reclaiming chunk %llu with %llu%% used", + bg->start, div_u64(bg->used * 100, bg->length)); + trace_btrfs_reclaim_block_group(bg); + ret = btrfs_relocate_chunk(fs_info, bg->start); + if (ret) + btrfs_err(fs_info, "error relocating chunk %llu", + bg->start); + +next: + btrfs_put_block_group(bg); + spin_lock(&fs_info->unused_bgs_lock); + } + spin_unlock(&fs_info->unused_bgs_lock); + mutex_unlock(&fs_info->reclaim_bgs_lock); + btrfs_exclop_finish(fs_info); +} + +void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info) +{ + spin_lock(&fs_info->unused_bgs_lock); + if (!list_empty(&fs_info->reclaim_bgs)) + queue_work(system_unbound_wq, &fs_info->reclaim_bgs_work); + spin_unlock(&fs_info->unused_bgs_lock); +} + +void btrfs_mark_bg_to_reclaim(struct btrfs_block_group *bg) +{ + struct btrfs_fs_info *fs_info = bg->fs_info; + + spin_lock(&fs_info->unused_bgs_lock); + if (list_empty(&bg->bg_list)) { + btrfs_get_block_group(bg); + trace_btrfs_add_reclaim_block_group(bg); + list_add_tail(&bg->bg_list, &fs_info->reclaim_bgs); + } + spin_unlock(&fs_info->unused_bgs_lock); +} + static int read_bg_from_eb(struct btrfs_fs_info *fs_info, struct btrfs_key *key, struct btrfs_path *path) { @@ -2267,29 +2358,33 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache, struct btrfs_trans_handle *trans; u64 alloc_flags; int ret; + bool dirty_bg_running; -again: - trans = btrfs_join_transaction(fs_info->extent_root); - if (IS_ERR(trans)) - return PTR_ERR(trans); + do { + trans = btrfs_join_transaction(fs_info->extent_root); + if (IS_ERR(trans)) + return PTR_ERR(trans); - /* - * we're not allowed to set block groups readonly after the dirty - * block groups cache has started writing. If it already started, - * back off and let this transaction commit - */ - mutex_lock(&fs_info->ro_block_group_mutex); - if (test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &trans->transaction->flags)) { - u64 transid = trans->transid; + dirty_bg_running = false; - mutex_unlock(&fs_info->ro_block_group_mutex); - btrfs_end_transaction(trans); + /* + * We're not allowed to set block groups readonly after the dirty + * block group cache has started writing. If it already started, + * back off and let this transaction commit. + */ + mutex_lock(&fs_info->ro_block_group_mutex); + if (test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &trans->transaction->flags)) { + u64 transid = trans->transid; - ret = btrfs_wait_for_commit(fs_info, transid); - if (ret) - return ret; - goto again; - } + mutex_unlock(&fs_info->ro_block_group_mutex); + btrfs_end_transaction(trans); + + ret = btrfs_wait_for_commit(fs_info, transid); + if (ret) + return ret; + dirty_bg_running = true; + } + } while (dirty_bg_running); if (do_chunk_alloc) { /* @@ -3269,6 +3364,7 @@ static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type) */ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) { + struct btrfs_transaction *cur_trans = trans->transaction; struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_space_info *info; u64 left; @@ -3283,6 +3379,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) lockdep_assert_held(&fs_info->chunk_mutex); info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM); +again: spin_lock(&info->lock); left = info->total_bytes - btrfs_space_info_used(info, true); spin_unlock(&info->lock); @@ -3301,6 +3398,58 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) if (left < thresh) { u64 flags = btrfs_system_alloc_profile(fs_info); + u64 reserved = atomic64_read(&cur_trans->chunk_bytes_reserved); + + /* + * If there's not available space for the chunk tree (system + * space) and there are other tasks that reserved space for + * creating a new system block group, wait for them to complete + * the creation of their system block group and release excess + * reserved space. We do this because: + * + * *) We can end up allocating more system chunks than necessary + * when there are multiple tasks that are concurrently + * allocating block groups, which can lead to exhaustion of + * the system array in the superblock; + * + * *) If we allocate extra and unnecessary system block groups, + * despite being empty for a long time, and possibly forever, + * they end not being added to the list of unused block groups + * because that typically happens only when deallocating the + * last extent from a block group - which never happens since + * we never allocate from them in the first place. The few + * exceptions are when mounting a filesystem or running scrub, + * which add unused block groups to the list of unused block + * groups, to be deleted by the cleaner kthread. + * And even when they are added to the list of unused block + * groups, it can take a long time until they get deleted, + * since the cleaner kthread might be sleeping or busy with + * other work (deleting subvolumes, running delayed iputs, + * defrag scheduling, etc); + * + * This is rare in practice, but can happen when too many tasks + * are allocating blocks groups in parallel (via fallocate()) + * and before the one that reserved space for a new system block + * group finishes the block group creation and releases the space + * reserved in excess (at btrfs_create_pending_block_groups()), + * other tasks end up here and see free system space temporarily + * not enough for updating the chunk tree. + * + * We unlock the chunk mutex before waiting for such tasks and + * lock it again after the wait, otherwise we would deadlock. + * It is safe to do so because allocating a system chunk is the + * first thing done while allocating a new block group. + */ + if (reserved > trans->chunk_bytes_reserved) { + const u64 min_needed = reserved - thresh; + + mutex_unlock(&fs_info->chunk_mutex); + wait_event(cur_trans->chunk_reserve_wait, + atomic64_read(&cur_trans->chunk_bytes_reserved) <= + min_needed); + mutex_lock(&fs_info->chunk_mutex); + goto again; + } /* * Ignore failure to create system chunk. We might end up not @@ -3315,8 +3464,10 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) ret = btrfs_block_rsv_add(fs_info->chunk_root, &fs_info->chunk_block_rsv, thresh, BTRFS_RESERVE_NO_FLUSH); - if (!ret) + if (!ret) { + atomic64_add(thresh, &cur_trans->chunk_bytes_reserved); trans->chunk_bytes_reserved += thresh; + } } } @@ -3386,6 +3537,16 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) } spin_unlock(&info->unused_bgs_lock); + spin_lock(&info->unused_bgs_lock); + while (!list_empty(&info->reclaim_bgs)) { + block_group = list_first_entry(&info->reclaim_bgs, + struct btrfs_block_group, + bg_list); + list_del_init(&block_group->bg_list); + btrfs_put_block_group(block_group); + } + spin_unlock(&info->unused_bgs_lock); + spin_lock(&info->block_group_cache_lock); while ((n = rb_last(&info->block_group_cache_tree)) != NULL) { block_group = rb_entry(n, struct btrfs_block_group, diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index 3ecc3372a5cea5a2c20a450ae8e4fedc8b3822fd..7b927425dc7156f70d11627787188dbea3d0ec9f 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -264,6 +264,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, u64 group_start, struct extent_map *em); void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info); void btrfs_mark_bg_unused(struct btrfs_block_group *bg); +void btrfs_reclaim_bgs_work(struct work_struct *work); +void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info); +void btrfs_mark_bg_to_reclaim(struct btrfs_block_group *bg); int btrfs_read_block_groups(struct btrfs_fs_info *info); int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used, u64 type, u64 chunk_offset, u64 size); diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 28e202e89660f9fdc216f50c6ba30d2a792c9402..c652e19ad74e211ec4b1fac865ead6f7c258da3c 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -220,6 +220,7 @@ struct btrfs_inode { /* Hook into fs_info->delayed_iputs */ struct list_head delayed_iput; + struct rw_semaphore i_mmap_lock; struct inode vfs_inode; }; @@ -299,24 +300,30 @@ static inline void btrfs_mod_outstanding_extents(struct btrfs_inode *inode, mod); } -static inline int btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation) +/* + * Called every time after doing a buffered, direct IO or memory mapped write. + * + * This is to ensure that if we write to a file that was previously fsynced in + * the current transaction, then try to fsync it again in the same transaction, + * we will know that there were changes in the file and that it needs to be + * logged. + */ +static inline void btrfs_set_inode_last_sub_trans(struct btrfs_inode *inode) +{ + spin_lock(&inode->lock); + inode->last_sub_trans = inode->root->log_transid; + spin_unlock(&inode->lock); +} + +static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation) { - int ret = 0; + bool ret = false; spin_lock(&inode->lock); if (inode->logged_trans == generation && inode->last_sub_trans <= inode->last_log_commit && - inode->last_sub_trans <= inode->root->last_log_commit) { - /* - * After a ranged fsync we might have left some extent maps - * (that fall outside the fsync's range). So return false - * here if the list isn't empty, to make sure btrfs_log_inode() - * will be called and process those extent maps. - */ - smp_mb(); - if (list_empty(&inode->extent_tree.modified_extents)) - ret = 1; - } + inode->last_sub_trans <= inode->root->last_log_commit) + ret = true; spin_unlock(&inode->lock); return ret; } diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 113cb85c1fd448a5cfd366301636a60cffacabad..1695086093249bdb0cafe6321fd2059dac536a4a 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1555,10 +1555,11 @@ static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx) BUG_ON(!block_ctx->pagev); num_pages = (block_ctx->len + (u64)PAGE_SIZE - 1) >> PAGE_SHIFT; + /* Pages must be unmapped in reverse order */ while (num_pages > 0) { num_pages--; if (block_ctx->datav[num_pages]) { - kunmap(block_ctx->pagev[num_pages]); + kunmap_local(block_ctx->datav[num_pages]); block_ctx->datav[num_pages] = NULL; } if (block_ctx->pagev[num_pages]) { @@ -1637,7 +1638,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, i = j; } for (i = 0; i < num_pages; i++) - block_ctx->datav[i] = kmap(block_ctx->pagev[i]); + block_ctx->datav[i] = kmap_local_page(block_ctx->pagev[i]); return block_ctx->len; } @@ -2677,7 +2678,7 @@ static void __btrfsic_submit_bio(struct bio *bio) dev_state = btrfsic_dev_state_lookup(bio->bi_bdev->bd_dev); if (NULL != dev_state && (bio_op(bio) == REQ_OP_WRITE) && bio_has_data(bio)) { - unsigned int i = 0; + int i = 0; u64 dev_bytenr; u64 cur_bytenr; struct bio_vec bvec; @@ -2702,7 +2703,7 @@ static void __btrfsic_submit_bio(struct bio *bio) bio_for_each_segment(bvec, bio, iter) { BUG_ON(bvec.bv_len != PAGE_SIZE); - mapped_datav[i] = kmap(bvec.bv_page); + mapped_datav[i] = kmap_local_page(bvec.bv_page); i++; if (dev_state->state->print_mask & @@ -2715,8 +2716,9 @@ static void __btrfsic_submit_bio(struct bio *bio) mapped_datav, segs, bio, &bio_is_patched, bio->bi_opf); - bio_for_each_segment(bvec, bio, iter) - kunmap(bvec.bv_page); + /* Unmap in reverse order */ + for (--i; i >= 0; i--) + kunmap_local(mapped_datav[i]); kfree(mapped_datav); } else if (NULL != dev_state && (bio->bi_opf & REQ_PREFLUSH)) { if (dev_state->state->print_mask & diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 3f4c832abfed6229963a3a78d4708af743fdd078..17f93fd28f7e3be99b42bd8dbce22c39d51ea4cc 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -80,10 +80,15 @@ static int compression_compress_pages(int type, struct list_head *ws, case BTRFS_COMPRESS_NONE: default: /* - * This can't happen, the type is validated several times - * before we get here. As a sane fallback, return what the - * callers will understand as 'no compression happened'. + * This can happen when compression races with remount setting + * it to 'no compress', while caller doesn't call + * inode_need_compress() to check if we really need to + * compress. + * + * Not a big deal, just need to inform caller that we + * haven't allocated any pages yet. */ + *out_pages = 0; return -E2BIG; } } @@ -1611,7 +1616,7 @@ static void heuristic_collect_sample(struct inode *inode, u64 start, u64 end, curr_sample_pos = 0; while (index < index_end) { page = find_get_page(inode->i_mapping, index); - in_data = kmap(page); + in_data = kmap_local_page(page); /* Handle case where the start is not aligned to PAGE_SIZE */ i = start % PAGE_SIZE; while (i < PAGE_SIZE - SAMPLING_READ_SIZE) { @@ -1624,7 +1629,7 @@ static void heuristic_collect_sample(struct inode *inode, u64 start, u64 end, start += SAMPLING_INTERVAL; curr_sample_pos += SAMPLING_READ_SIZE; } - kunmap(page); + kunmap_local(in_data); put_page(page); index++; diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 34b929bd5c1af5a57a258d69e1142fdf46fc9ee6..a484fb72a01f0b620627331522e805a28b7101c0 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -14,6 +14,7 @@ #include "locking.h" #include "volumes.h" #include "qgroup.h" +#include "tree-mod-log.h" static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level); @@ -233,597 +234,6 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, return 0; } -enum mod_log_op { - MOD_LOG_KEY_REPLACE, - MOD_LOG_KEY_ADD, - MOD_LOG_KEY_REMOVE, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, - MOD_LOG_KEY_REMOVE_WHILE_MOVING, - MOD_LOG_MOVE_KEYS, - MOD_LOG_ROOT_REPLACE, -}; - -struct tree_mod_root { - u64 logical; - u8 level; -}; - -struct tree_mod_elem { - struct rb_node node; - u64 logical; - u64 seq; - enum mod_log_op op; - - /* this is used for MOD_LOG_KEY_* and MOD_LOG_MOVE_KEYS operations */ - int slot; - - /* this is used for MOD_LOG_KEY* and MOD_LOG_ROOT_REPLACE */ - u64 generation; - - /* those are used for op == MOD_LOG_KEY_{REPLACE,REMOVE} */ - struct btrfs_disk_key key; - u64 blockptr; - - /* this is used for op == MOD_LOG_MOVE_KEYS */ - struct { - int dst_slot; - int nr_items; - } move; - - /* this is used for op == MOD_LOG_ROOT_REPLACE */ - struct tree_mod_root old_root; -}; - -/* - * Pull a new tree mod seq number for our operation. - */ -static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) -{ - return atomic64_inc_return(&fs_info->tree_mod_seq); -} - -/* - * This adds a new blocker to the tree mod log's blocker list if the @elem - * passed does not already have a sequence number set. So when a caller expects - * to record tree modifications, it should ensure to set elem->seq to zero - * before calling btrfs_get_tree_mod_seq. - * Returns a fresh, unused tree log modification sequence number, even if no new - * blocker was added. - */ -u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem) -{ - write_lock(&fs_info->tree_mod_log_lock); - if (!elem->seq) { - elem->seq = btrfs_inc_tree_mod_seq(fs_info); - list_add_tail(&elem->list, &fs_info->tree_mod_seq_list); - } - write_unlock(&fs_info->tree_mod_log_lock); - - return elem->seq; -} - -void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem) -{ - struct rb_root *tm_root; - struct rb_node *node; - struct rb_node *next; - struct tree_mod_elem *tm; - u64 min_seq = (u64)-1; - u64 seq_putting = elem->seq; - - if (!seq_putting) - return; - - write_lock(&fs_info->tree_mod_log_lock); - list_del(&elem->list); - elem->seq = 0; - - if (!list_empty(&fs_info->tree_mod_seq_list)) { - struct seq_list *first; - - first = list_first_entry(&fs_info->tree_mod_seq_list, - struct seq_list, list); - if (seq_putting > first->seq) { - /* - * Blocker with lower sequence number exists, we - * cannot remove anything from the log. - */ - write_unlock(&fs_info->tree_mod_log_lock); - return; - } - min_seq = first->seq; - } - - /* - * anything that's lower than the lowest existing (read: blocked) - * sequence number can be removed from the tree. - */ - tm_root = &fs_info->tree_mod_log; - for (node = rb_first(tm_root); node; node = next) { - next = rb_next(node); - tm = rb_entry(node, struct tree_mod_elem, node); - if (tm->seq >= min_seq) - continue; - rb_erase(node, tm_root); - kfree(tm); - } - write_unlock(&fs_info->tree_mod_log_lock); -} - -/* - * key order of the log: - * node/leaf start address -> sequence - * - * The 'start address' is the logical address of the *new* root node - * for root replace operations, or the logical address of the affected - * block for all other operations. - */ -static noinline int -__tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) -{ - struct rb_root *tm_root; - struct rb_node **new; - struct rb_node *parent = NULL; - struct tree_mod_elem *cur; - - lockdep_assert_held_write(&fs_info->tree_mod_log_lock); - - tm->seq = btrfs_inc_tree_mod_seq(fs_info); - - tm_root = &fs_info->tree_mod_log; - new = &tm_root->rb_node; - while (*new) { - cur = rb_entry(*new, struct tree_mod_elem, node); - parent = *new; - if (cur->logical < tm->logical) - new = &((*new)->rb_left); - else if (cur->logical > tm->logical) - new = &((*new)->rb_right); - else if (cur->seq < tm->seq) - new = &((*new)->rb_left); - else if (cur->seq > tm->seq) - new = &((*new)->rb_right); - else - return -EEXIST; - } - - rb_link_node(&tm->node, parent, new); - rb_insert_color(&tm->node, tm_root); - return 0; -} - -/* - * Determines if logging can be omitted. Returns 1 if it can. Otherwise, it - * returns zero with the tree_mod_log_lock acquired. The caller must hold - * this until all tree mod log insertions are recorded in the rb tree and then - * write unlock fs_info::tree_mod_log_lock. - */ -static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb) { - smp_mb(); - if (list_empty(&(fs_info)->tree_mod_seq_list)) - return 1; - if (eb && btrfs_header_level(eb) == 0) - return 1; - - write_lock(&fs_info->tree_mod_log_lock); - if (list_empty(&(fs_info)->tree_mod_seq_list)) { - write_unlock(&fs_info->tree_mod_log_lock); - return 1; - } - - return 0; -} - -/* Similar to tree_mod_dont_log, but doesn't acquire any locks. */ -static inline int tree_mod_need_log(const struct btrfs_fs_info *fs_info, - struct extent_buffer *eb) -{ - smp_mb(); - if (list_empty(&(fs_info)->tree_mod_seq_list)) - return 0; - if (eb && btrfs_header_level(eb) == 0) - return 0; - - return 1; -} - -static struct tree_mod_elem * -alloc_tree_mod_elem(struct extent_buffer *eb, int slot, - enum mod_log_op op, gfp_t flags) -{ - struct tree_mod_elem *tm; - - tm = kzalloc(sizeof(*tm), flags); - if (!tm) - return NULL; - - tm->logical = eb->start; - if (op != MOD_LOG_KEY_ADD) { - btrfs_node_key(eb, &tm->key, slot); - tm->blockptr = btrfs_node_blockptr(eb, slot); - } - tm->op = op; - tm->slot = slot; - tm->generation = btrfs_node_ptr_generation(eb, slot); - RB_CLEAR_NODE(&tm->node); - - return tm; -} - -static noinline int tree_mod_log_insert_key(struct extent_buffer *eb, int slot, - enum mod_log_op op, gfp_t flags) -{ - struct tree_mod_elem *tm; - int ret; - - if (!tree_mod_need_log(eb->fs_info, eb)) - return 0; - - tm = alloc_tree_mod_elem(eb, slot, op, flags); - if (!tm) - return -ENOMEM; - - if (tree_mod_dont_log(eb->fs_info, eb)) { - kfree(tm); - return 0; - } - - ret = __tree_mod_log_insert(eb->fs_info, tm); - write_unlock(&eb->fs_info->tree_mod_log_lock); - if (ret) - kfree(tm); - - return ret; -} - -static noinline int tree_mod_log_insert_move(struct extent_buffer *eb, - int dst_slot, int src_slot, int nr_items) -{ - struct tree_mod_elem *tm = NULL; - struct tree_mod_elem **tm_list = NULL; - int ret = 0; - int i; - int locked = 0; - - if (!tree_mod_need_log(eb->fs_info, eb)) - return 0; - - tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), GFP_NOFS); - if (!tm_list) - return -ENOMEM; - - tm = kzalloc(sizeof(*tm), GFP_NOFS); - if (!tm) { - ret = -ENOMEM; - goto free_tms; - } - - tm->logical = eb->start; - tm->slot = src_slot; - tm->move.dst_slot = dst_slot; - tm->move.nr_items = nr_items; - tm->op = MOD_LOG_MOVE_KEYS; - - for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { - tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot, - MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS); - if (!tm_list[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - - if (tree_mod_dont_log(eb->fs_info, eb)) - goto free_tms; - locked = 1; - - /* - * When we override something during the move, we log these removals. - * This can only happen when we move towards the beginning of the - * buffer, i.e. dst_slot < src_slot. - */ - for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { - ret = __tree_mod_log_insert(eb->fs_info, tm_list[i]); - if (ret) - goto free_tms; - } - - ret = __tree_mod_log_insert(eb->fs_info, tm); - if (ret) - goto free_tms; - write_unlock(&eb->fs_info->tree_mod_log_lock); - kfree(tm_list); - - return 0; -free_tms: - for (i = 0; i < nr_items; i++) { - if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) - rb_erase(&tm_list[i]->node, &eb->fs_info->tree_mod_log); - kfree(tm_list[i]); - } - if (locked) - write_unlock(&eb->fs_info->tree_mod_log_lock); - kfree(tm_list); - kfree(tm); - - return ret; -} - -static inline int -__tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, - struct tree_mod_elem **tm_list, - int nritems) -{ - int i, j; - int ret; - - for (i = nritems - 1; i >= 0; i--) { - ret = __tree_mod_log_insert(fs_info, tm_list[i]); - if (ret) { - for (j = nritems - 1; j > i; j--) - rb_erase(&tm_list[j]->node, - &fs_info->tree_mod_log); - return ret; - } - } - - return 0; -} - -static noinline int tree_mod_log_insert_root(struct extent_buffer *old_root, - struct extent_buffer *new_root, int log_removal) -{ - struct btrfs_fs_info *fs_info = old_root->fs_info; - struct tree_mod_elem *tm = NULL; - struct tree_mod_elem **tm_list = NULL; - int nritems = 0; - int ret = 0; - int i; - - if (!tree_mod_need_log(fs_info, NULL)) - return 0; - - if (log_removal && btrfs_header_level(old_root) > 0) { - nritems = btrfs_header_nritems(old_root); - tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), - GFP_NOFS); - if (!tm_list) { - ret = -ENOMEM; - goto free_tms; - } - for (i = 0; i < nritems; i++) { - tm_list[i] = alloc_tree_mod_elem(old_root, i, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); - if (!tm_list[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - } - - tm = kzalloc(sizeof(*tm), GFP_NOFS); - if (!tm) { - ret = -ENOMEM; - goto free_tms; - } - - tm->logical = new_root->start; - tm->old_root.logical = old_root->start; - tm->old_root.level = btrfs_header_level(old_root); - tm->generation = btrfs_header_generation(old_root); - tm->op = MOD_LOG_ROOT_REPLACE; - - if (tree_mod_dont_log(fs_info, NULL)) - goto free_tms; - - if (tm_list) - ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems); - if (!ret) - ret = __tree_mod_log_insert(fs_info, tm); - - write_unlock(&fs_info->tree_mod_log_lock); - if (ret) - goto free_tms; - kfree(tm_list); - - return ret; - -free_tms: - if (tm_list) { - for (i = 0; i < nritems; i++) - kfree(tm_list[i]); - kfree(tm_list); - } - kfree(tm); - - return ret; -} - -static struct tree_mod_elem * -__tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq, - int smallest) -{ - struct rb_root *tm_root; - struct rb_node *node; - struct tree_mod_elem *cur = NULL; - struct tree_mod_elem *found = NULL; - - read_lock(&fs_info->tree_mod_log_lock); - tm_root = &fs_info->tree_mod_log; - node = tm_root->rb_node; - while (node) { - cur = rb_entry(node, struct tree_mod_elem, node); - if (cur->logical < start) { - node = node->rb_left; - } else if (cur->logical > start) { - node = node->rb_right; - } else if (cur->seq < min_seq) { - node = node->rb_left; - } else if (!smallest) { - /* we want the node with the highest seq */ - if (found) - BUG_ON(found->seq > cur->seq); - found = cur; - node = node->rb_left; - } else if (cur->seq > min_seq) { - /* we want the node with the smallest seq */ - if (found) - BUG_ON(found->seq < cur->seq); - found = cur; - node = node->rb_right; - } else { - found = cur; - break; - } - } - read_unlock(&fs_info->tree_mod_log_lock); - - return found; -} - -/* - * this returns the element from the log with the smallest time sequence - * value that's in the log (the oldest log item). any element with a time - * sequence lower than min_seq will be ignored. - */ -static struct tree_mod_elem * -tree_mod_log_search_oldest(struct btrfs_fs_info *fs_info, u64 start, - u64 min_seq) -{ - return __tree_mod_log_search(fs_info, start, min_seq, 1); -} - -/* - * this returns the element from the log with the largest time sequence - * value that's in the log (the most recent log item). any element with - * a time sequence lower than min_seq will be ignored. - */ -static struct tree_mod_elem * -tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq) -{ - return __tree_mod_log_search(fs_info, start, min_seq, 0); -} - -static noinline int tree_mod_log_eb_copy(struct extent_buffer *dst, - struct extent_buffer *src, unsigned long dst_offset, - unsigned long src_offset, int nr_items) -{ - struct btrfs_fs_info *fs_info = dst->fs_info; - int ret = 0; - struct tree_mod_elem **tm_list = NULL; - struct tree_mod_elem **tm_list_add, **tm_list_rem; - int i; - int locked = 0; - - if (!tree_mod_need_log(fs_info, NULL)) - return 0; - - if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) - return 0; - - tm_list = kcalloc(nr_items * 2, sizeof(struct tree_mod_elem *), - GFP_NOFS); - if (!tm_list) - return -ENOMEM; - - tm_list_add = tm_list; - tm_list_rem = tm_list + nr_items; - for (i = 0; i < nr_items; i++) { - tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset, - MOD_LOG_KEY_REMOVE, GFP_NOFS); - if (!tm_list_rem[i]) { - ret = -ENOMEM; - goto free_tms; - } - - tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset, - MOD_LOG_KEY_ADD, GFP_NOFS); - if (!tm_list_add[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - - if (tree_mod_dont_log(fs_info, NULL)) - goto free_tms; - locked = 1; - - for (i = 0; i < nr_items; i++) { - ret = __tree_mod_log_insert(fs_info, tm_list_rem[i]); - if (ret) - goto free_tms; - ret = __tree_mod_log_insert(fs_info, tm_list_add[i]); - if (ret) - goto free_tms; - } - - write_unlock(&fs_info->tree_mod_log_lock); - kfree(tm_list); - - return 0; - -free_tms: - for (i = 0; i < nr_items * 2; i++) { - if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) - rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log); - kfree(tm_list[i]); - } - if (locked) - write_unlock(&fs_info->tree_mod_log_lock); - kfree(tm_list); - - return ret; -} - -static noinline int tree_mod_log_free_eb(struct extent_buffer *eb) -{ - struct tree_mod_elem **tm_list = NULL; - int nritems = 0; - int i; - int ret = 0; - - if (btrfs_header_level(eb) == 0) - return 0; - - if (!tree_mod_need_log(eb->fs_info, NULL)) - return 0; - - nritems = btrfs_header_nritems(eb); - tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), GFP_NOFS); - if (!tm_list) - return -ENOMEM; - - for (i = 0; i < nritems; i++) { - tm_list[i] = alloc_tree_mod_elem(eb, i, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); - if (!tm_list[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - - if (tree_mod_dont_log(eb->fs_info, eb)) - goto free_tms; - - ret = __tree_mod_log_free_eb(eb->fs_info, tm_list, nritems); - write_unlock(&eb->fs_info->tree_mod_log_lock); - if (ret) - goto free_tms; - kfree(tm_list); - - return 0; - -free_tms: - for (i = 0; i < nritems; i++) - kfree(tm_list[i]); - kfree(tm_list); - - return ret; -} - /* * check if the tree block can be shared by multiple trees */ @@ -1090,7 +500,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, parent_start = buf->start; atomic_inc(&cow->refs); - ret = tree_mod_log_insert_root(root->node, cow, 1); + ret = btrfs_tree_mod_log_insert_root(root->node, cow, true); BUG_ON(ret < 0); rcu_assign_pointer(root->node, cow); @@ -1100,15 +510,15 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, add_root_to_dirty_list(root); } else { WARN_ON(trans->transid != btrfs_header_generation(parent)); - tree_mod_log_insert_key(parent, parent_slot, - MOD_LOG_KEY_REPLACE, GFP_NOFS); + btrfs_tree_mod_log_insert_key(parent, parent_slot, + BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); btrfs_set_node_blockptr(parent, parent_slot, cow->start); btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); btrfs_mark_buffer_dirty(parent); if (last_ref) { - ret = tree_mod_log_free_eb(buf); + ret = btrfs_tree_mod_log_free_eb(buf); if (ret) { btrfs_tree_unlock(cow); free_extent_buffer(cow); @@ -1127,298 +537,6 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, return 0; } -/* - * returns the logical address of the oldest predecessor of the given root. - * entries older than time_seq are ignored. - */ -static struct tree_mod_elem *__tree_mod_log_oldest_root( - struct extent_buffer *eb_root, u64 time_seq) -{ - struct tree_mod_elem *tm; - struct tree_mod_elem *found = NULL; - u64 root_logical = eb_root->start; - int looped = 0; - - if (!time_seq) - return NULL; - - /* - * the very last operation that's logged for a root is the - * replacement operation (if it is replaced at all). this has - * the logical address of the *new* root, making it the very - * first operation that's logged for this root. - */ - while (1) { - tm = tree_mod_log_search_oldest(eb_root->fs_info, root_logical, - time_seq); - if (!looped && !tm) - return NULL; - /* - * if there are no tree operation for the oldest root, we simply - * return it. this should only happen if that (old) root is at - * level 0. - */ - if (!tm) - break; - - /* - * if there's an operation that's not a root replacement, we - * found the oldest version of our root. normally, we'll find a - * MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here. - */ - if (tm->op != MOD_LOG_ROOT_REPLACE) - break; - - found = tm; - root_logical = tm->old_root.logical; - looped = 1; - } - - /* if there's no old root to return, return what we found instead */ - if (!found) - found = tm; - - return found; -} - -/* - * tm is a pointer to the first operation to rewind within eb. then, all - * previous operations will be rewound (until we reach something older than - * time_seq). - */ -static void -__tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, - u64 time_seq, struct tree_mod_elem *first_tm) -{ - u32 n; - struct rb_node *next; - struct tree_mod_elem *tm = first_tm; - unsigned long o_dst; - unsigned long o_src; - unsigned long p_size = sizeof(struct btrfs_key_ptr); - - n = btrfs_header_nritems(eb); - read_lock(&fs_info->tree_mod_log_lock); - while (tm && tm->seq >= time_seq) { - /* - * all the operations are recorded with the operator used for - * the modification. as we're going backwards, we do the - * opposite of each operation here. - */ - switch (tm->op) { - case MOD_LOG_KEY_REMOVE_WHILE_FREEING: - BUG_ON(tm->slot < n); - fallthrough; - case MOD_LOG_KEY_REMOVE_WHILE_MOVING: - case MOD_LOG_KEY_REMOVE: - btrfs_set_node_key(eb, &tm->key, tm->slot); - btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); - btrfs_set_node_ptr_generation(eb, tm->slot, - tm->generation); - n++; - break; - case MOD_LOG_KEY_REPLACE: - BUG_ON(tm->slot >= n); - btrfs_set_node_key(eb, &tm->key, tm->slot); - btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); - btrfs_set_node_ptr_generation(eb, tm->slot, - tm->generation); - break; - case MOD_LOG_KEY_ADD: - /* if a move operation is needed it's in the log */ - n--; - break; - case MOD_LOG_MOVE_KEYS: - o_dst = btrfs_node_key_ptr_offset(tm->slot); - o_src = btrfs_node_key_ptr_offset(tm->move.dst_slot); - memmove_extent_buffer(eb, o_dst, o_src, - tm->move.nr_items * p_size); - break; - case MOD_LOG_ROOT_REPLACE: - /* - * this operation is special. for roots, this must be - * handled explicitly before rewinding. - * for non-roots, this operation may exist if the node - * was a root: root A -> child B; then A gets empty and - * B is promoted to the new root. in the mod log, we'll - * have a root-replace operation for B, a tree block - * that is no root. we simply ignore that operation. - */ - break; - } - next = rb_next(&tm->node); - if (!next) - break; - tm = rb_entry(next, struct tree_mod_elem, node); - if (tm->logical != first_tm->logical) - break; - } - read_unlock(&fs_info->tree_mod_log_lock); - btrfs_set_header_nritems(eb, n); -} - -/* - * Called with eb read locked. If the buffer cannot be rewound, the same buffer - * is returned. If rewind operations happen, a fresh buffer is returned. The - * returned buffer is always read-locked. If the returned buffer is not the - * input buffer, the lock on the input buffer is released and the input buffer - * is freed (its refcount is decremented). - */ -static struct extent_buffer * -tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - struct extent_buffer *eb, u64 time_seq) -{ - struct extent_buffer *eb_rewin; - struct tree_mod_elem *tm; - - if (!time_seq) - return eb; - - if (btrfs_header_level(eb) == 0) - return eb; - - tm = tree_mod_log_search(fs_info, eb->start, time_seq); - if (!tm) - return eb; - - if (tm->op == MOD_LOG_KEY_REMOVE_WHILE_FREEING) { - BUG_ON(tm->slot != 0); - eb_rewin = alloc_dummy_extent_buffer(fs_info, eb->start); - if (!eb_rewin) { - btrfs_tree_read_unlock(eb); - free_extent_buffer(eb); - return NULL; - } - btrfs_set_header_bytenr(eb_rewin, eb->start); - btrfs_set_header_backref_rev(eb_rewin, - btrfs_header_backref_rev(eb)); - btrfs_set_header_owner(eb_rewin, btrfs_header_owner(eb)); - btrfs_set_header_level(eb_rewin, btrfs_header_level(eb)); - } else { - eb_rewin = btrfs_clone_extent_buffer(eb); - if (!eb_rewin) { - btrfs_tree_read_unlock(eb); - free_extent_buffer(eb); - return NULL; - } - } - - btrfs_tree_read_unlock(eb); - free_extent_buffer(eb); - - btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb_rewin), - eb_rewin, btrfs_header_level(eb_rewin)); - btrfs_tree_read_lock(eb_rewin); - __tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm); - WARN_ON(btrfs_header_nritems(eb_rewin) > - BTRFS_NODEPTRS_PER_BLOCK(fs_info)); - - return eb_rewin; -} - -/* - * get_old_root() rewinds the state of @root's root node to the given @time_seq - * value. If there are no changes, the current root->root_node is returned. If - * anything changed in between, there's a fresh buffer allocated on which the - * rewind operations are done. In any case, the returned buffer is read locked. - * Returns NULL on error (with no locks held). - */ -static inline struct extent_buffer * -get_old_root(struct btrfs_root *root, u64 time_seq) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct tree_mod_elem *tm; - struct extent_buffer *eb = NULL; - struct extent_buffer *eb_root; - u64 eb_root_owner = 0; - struct extent_buffer *old; - struct tree_mod_root *old_root = NULL; - u64 old_generation = 0; - u64 logical; - int level; - - eb_root = btrfs_read_lock_root_node(root); - tm = __tree_mod_log_oldest_root(eb_root, time_seq); - if (!tm) - return eb_root; - - if (tm->op == MOD_LOG_ROOT_REPLACE) { - old_root = &tm->old_root; - old_generation = tm->generation; - logical = old_root->logical; - level = old_root->level; - } else { - logical = eb_root->start; - level = btrfs_header_level(eb_root); - } - - tm = tree_mod_log_search(fs_info, logical, time_seq); - if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) { - btrfs_tree_read_unlock(eb_root); - free_extent_buffer(eb_root); - old = read_tree_block(fs_info, logical, root->root_key.objectid, - 0, level, NULL); - if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) { - if (!IS_ERR(old)) - free_extent_buffer(old); - btrfs_warn(fs_info, - "failed to read tree block %llu from get_old_root", - logical); - } else { - btrfs_tree_read_lock(old); - eb = btrfs_clone_extent_buffer(old); - btrfs_tree_read_unlock(old); - free_extent_buffer(old); - } - } else if (old_root) { - eb_root_owner = btrfs_header_owner(eb_root); - btrfs_tree_read_unlock(eb_root); - free_extent_buffer(eb_root); - eb = alloc_dummy_extent_buffer(fs_info, logical); - } else { - eb = btrfs_clone_extent_buffer(eb_root); - btrfs_tree_read_unlock(eb_root); - free_extent_buffer(eb_root); - } - - if (!eb) - return NULL; - if (old_root) { - btrfs_set_header_bytenr(eb, eb->start); - btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(eb, eb_root_owner); - btrfs_set_header_level(eb, old_root->level); - btrfs_set_header_generation(eb, old_generation); - } - btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), eb, - btrfs_header_level(eb)); - btrfs_tree_read_lock(eb); - if (tm) - __tree_mod_log_rewind(fs_info, eb, time_seq, tm); - else - WARN_ON(btrfs_header_level(eb) != 0); - WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(fs_info)); - - return eb; -} - -int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq) -{ - struct tree_mod_elem *tm; - int level; - struct extent_buffer *eb_root = btrfs_root_node(root); - - tm = __tree_mod_log_oldest_root(eb_root, time_seq); - if (tm && tm->op == MOD_LOG_ROOT_REPLACE) { - level = tm->old_root.level; - } else { - level = btrfs_header_level(eb_root); - } - free_extent_buffer(eb_root); - - return level; -} - static inline int should_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf) @@ -1840,7 +958,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, goto enospc; } - ret = tree_mod_log_insert_root(root->node, child, 1); + ret = btrfs_tree_mod_log_insert_root(root->node, child, true); BUG_ON(ret < 0); rcu_assign_pointer(root->node, child); @@ -1920,8 +1038,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, } else { struct btrfs_disk_key right_key; btrfs_node_key(right, &right_key, 0); - ret = tree_mod_log_insert_key(parent, pslot + 1, - MOD_LOG_KEY_REPLACE, GFP_NOFS); + ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1, + BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); BUG_ON(ret < 0); btrfs_set_node_key(parent, &right_key, pslot + 1); btrfs_mark_buffer_dirty(parent); @@ -1966,8 +1084,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, /* update the parent key to reflect our changes */ struct btrfs_disk_key mid_key; btrfs_node_key(mid, &mid_key, 0); - ret = tree_mod_log_insert_key(parent, pslot, - MOD_LOG_KEY_REPLACE, GFP_NOFS); + ret = btrfs_tree_mod_log_insert_key(parent, pslot, + BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); BUG_ON(ret < 0); btrfs_set_node_key(parent, &mid_key, pslot); btrfs_mark_buffer_dirty(parent); @@ -2068,8 +1186,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, struct btrfs_disk_key disk_key; orig_slot += left_nr; btrfs_node_key(mid, &disk_key, 0); - ret = tree_mod_log_insert_key(parent, pslot, - MOD_LOG_KEY_REPLACE, GFP_NOFS); + ret = btrfs_tree_mod_log_insert_key(parent, pslot, + BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); BUG_ON(ret < 0); btrfs_set_node_key(parent, &disk_key, pslot); btrfs_mark_buffer_dirty(parent); @@ -2122,8 +1240,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, struct btrfs_disk_key disk_key; btrfs_node_key(right, &disk_key, 0); - ret = tree_mod_log_insert_key(parent, pslot + 1, - MOD_LOG_KEY_REPLACE, GFP_NOFS); + ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1, + BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); BUG_ON(ret < 0); btrfs_set_node_key(parent, &disk_key, pslot + 1); btrfs_mark_buffer_dirty(parent); @@ -2161,12 +1279,13 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, u64 search; u64 target; u64 nread = 0; + u64 nread_max; struct extent_buffer *eb; u32 nr; u32 blocksize; u32 nscan = 0; - if (level != 1) + if (level != 1 && path->reada != READA_FORWARD_ALWAYS) return; if (!path->nodes[level]) @@ -2174,6 +1293,20 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, node = path->nodes[level]; + /* + * Since the time between visiting leaves is much shorter than the time + * between visiting nodes, limit read ahead of nodes to 1, to avoid too + * much IO at once (possibly random). + */ + if (path->reada == READA_FORWARD_ALWAYS) { + if (level > 1) + nread_max = node->fs_info->nodesize; + else + nread_max = SZ_128K; + } else { + nread_max = SZ_64K; + } + search = btrfs_node_blockptr(node, slot); blocksize = fs_info->nodesize; eb = find_extent_buffer(fs_info, search); @@ -2192,7 +1325,8 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, if (nr == 0) break; nr--; - } else if (path->reada == READA_FORWARD) { + } else if (path->reada == READA_FORWARD || + path->reada == READA_FORWARD_ALWAYS) { nr++; if (nr >= nritems) break; @@ -2203,13 +1337,14 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, break; } search = btrfs_node_blockptr(node, nr); - if ((search <= target && target - search <= 65536) || + if (path->reada == READA_FORWARD_ALWAYS || + (search <= target && target - search <= 65536) || (search > target && search - target <= 65536)) { btrfs_readahead_node_child(node, nr); nread += blocksize; } nscan++; - if ((nread > 65536 || nscan > 32)) + if (nread > nread_max || nscan > 32) break; } } @@ -2318,6 +1453,9 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p, tmp = find_extent_buffer(fs_info, blocknr); if (tmp) { + if (p->reada == READA_FORWARD_ALWAYS) + reada_for_search(fs_info, p, level, slot, key->objectid); + /* first we do an atomic uptodate check */ if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) { /* @@ -2861,7 +1999,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, } again: - b = get_old_root(root, time_seq); + b = btrfs_get_old_root(root, time_seq); if (!b) { ret = -EIO; goto done; @@ -2916,7 +2054,7 @@ again: level = btrfs_header_level(b); btrfs_tree_read_lock(b); - b = tree_mod_log_rewind(fs_info, p, b, time_seq); + b = btrfs_tree_mod_log_rewind(fs_info, p, b, time_seq); if (!b) { ret = -ENOMEM; goto done; @@ -3030,8 +2168,8 @@ static void fixup_low_keys(struct btrfs_path *path, if (!path->nodes[i]) break; t = path->nodes[i]; - ret = tree_mod_log_insert_key(t, tslot, MOD_LOG_KEY_REPLACE, - GFP_ATOMIC); + ret = btrfs_tree_mod_log_insert_key(t, tslot, + BTRFS_MOD_LOG_KEY_REPLACE, GFP_ATOMIC); BUG_ON(ret < 0); btrfs_set_node_key(t, key, tslot); btrfs_mark_buffer_dirty(path->nodes[i]); @@ -3194,7 +2332,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, btrfs_abort_transaction(trans, ret); return ret; } - ret = tree_mod_log_eb_copy(dst, src, dst_nritems, 0, push_items); + ret = btrfs_tree_mod_log_eb_copy(dst, src, dst_nritems, 0, push_items); if (ret) { btrfs_abort_transaction(trans, ret); return ret; @@ -3206,8 +2344,8 @@ static int push_node_left(struct btrfs_trans_handle *trans, if (push_items < src_nritems) { /* - * Don't call tree_mod_log_insert_move here, key removal was - * already fully logged by tree_mod_log_eb_copy above. + * Don't call btrfs_tree_mod_log_insert_move() here, key removal + * was already fully logged by btrfs_tree_mod_log_eb_copy() above. */ memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(push_items), @@ -3268,15 +2406,15 @@ static int balance_node_right(struct btrfs_trans_handle *trans, btrfs_abort_transaction(trans, ret); return ret; } - ret = tree_mod_log_insert_move(dst, push_items, 0, dst_nritems); + ret = btrfs_tree_mod_log_insert_move(dst, push_items, 0, dst_nritems); BUG_ON(ret < 0); memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), btrfs_node_key_ptr_offset(0), (dst_nritems) * sizeof(struct btrfs_key_ptr)); - ret = tree_mod_log_eb_copy(dst, src, 0, src_nritems - push_items, - push_items); + ret = btrfs_tree_mod_log_eb_copy(dst, src, 0, src_nritems - push_items, + push_items); if (ret) { btrfs_abort_transaction(trans, ret); return ret; @@ -3342,7 +2480,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(c); old = root->node; - ret = tree_mod_log_insert_root(root->node, c, 0); + ret = btrfs_tree_mod_log_insert_root(root->node, c, false); BUG_ON(ret < 0); rcu_assign_pointer(root->node, c); @@ -3381,8 +2519,8 @@ static void insert_ptr(struct btrfs_trans_handle *trans, BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(trans->fs_info)); if (slot != nritems) { if (level) { - ret = tree_mod_log_insert_move(lower, slot + 1, slot, - nritems - slot); + ret = btrfs_tree_mod_log_insert_move(lower, slot + 1, + slot, nritems - slot); BUG_ON(ret < 0); } memmove_extent_buffer(lower, @@ -3391,8 +2529,8 @@ static void insert_ptr(struct btrfs_trans_handle *trans, (nritems - slot) * sizeof(struct btrfs_key_ptr)); } if (level) { - ret = tree_mod_log_insert_key(lower, slot, MOD_LOG_KEY_ADD, - GFP_NOFS); + ret = btrfs_tree_mod_log_insert_key(lower, slot, + BTRFS_MOD_LOG_KEY_ADD, GFP_NOFS); BUG_ON(ret < 0); } btrfs_set_node_key(lower, key, slot); @@ -3433,9 +2571,9 @@ static noinline int split_node(struct btrfs_trans_handle *trans, * tree mod log: We don't log_removal old root in * insert_new_root, because that root buffer will be kept as a * normal node. We are going to log removal of half of the - * elements below with tree_mod_log_eb_copy. We're holding a - * tree lock on the buffer, which is why we cannot race with - * other tree_mod_log users. + * elements below with btrfs_tree_mod_log_eb_copy(). We're + * holding a tree lock on the buffer, which is why we cannot + * race with other tree_mod_log users. */ ret = insert_new_root(trans, root, path, level + 1); if (ret) @@ -3462,7 +2600,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, root_add_used(root, fs_info->nodesize); ASSERT(btrfs_header_level(c) == level); - ret = tree_mod_log_eb_copy(split, c, 0, mid, c_nritems - mid); + ret = btrfs_tree_mod_log_eb_copy(split, c, 0, mid, c_nritems - mid); if (ret) { btrfs_abort_transaction(trans, ret); return ret; @@ -4844,8 +3982,8 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, nritems = btrfs_header_nritems(parent); if (slot != nritems - 1) { if (level) { - ret = tree_mod_log_insert_move(parent, slot, slot + 1, - nritems - slot - 1); + ret = btrfs_tree_mod_log_insert_move(parent, slot, + slot + 1, nritems - slot - 1); BUG_ON(ret < 0); } memmove_extent_buffer(parent, @@ -4854,8 +3992,8 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, sizeof(struct btrfs_key_ptr) * (nritems - slot - 1)); } else if (level) { - ret = tree_mod_log_insert_key(parent, slot, MOD_LOG_KEY_REMOVE, - GFP_NOFS); + ret = btrfs_tree_mod_log_insert_key(parent, slot, + BTRFS_MOD_LOG_KEY_REMOVE, GFP_NOFS); BUG_ON(ret < 0); } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9ae776ab39676f0f28876da556487765e80370cb..f83fd3cbf2439b9856285725bcf7d9b069dfca37 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -342,6 +342,27 @@ struct btrfs_node { struct btrfs_key_ptr ptrs[]; } __attribute__ ((__packed__)); +/* Read ahead values for struct btrfs_path.reada */ +enum { + READA_NONE, + READA_BACK, + READA_FORWARD, + /* + * Similar to READA_FORWARD but unlike it: + * + * 1) It will trigger readahead even for leaves that are not close to + * each other on disk; + * 2) It also triggers readahead for nodes; + * 3) During a search, even when a node or leaf is already in memory, it + * will still trigger readahead for other nodes and leaves that follow + * it. + * + * This is meant to be used only when we know we are iterating over the + * entire tree or a very large part of it. + */ + READA_FORWARD_ALWAYS, +}; + /* * btrfs_paths remember the path taken from the root down to the leaf. * level 0 is always the leaf, and nodes[1...BTRFS_MAX_LEVEL] will point @@ -350,7 +371,6 @@ struct btrfs_node { * The slots array records the index of the item or block pointer * used while walking the tree. */ -enum { READA_NONE, READA_BACK, READA_FORWARD }; struct btrfs_path { struct extent_buffer *nodes[BTRFS_MAX_LEVEL]; int slots[BTRFS_MAX_LEVEL]; @@ -482,16 +502,6 @@ struct btrfs_discard_ctl { atomic64_t discard_bytes_saved; }; -/* delayed seq elem */ -struct seq_list { - struct list_head list; - u64 seq; -}; - -#define SEQ_LIST_INIT(name) { .list = LIST_HEAD_INIT((name).list), .seq = 0 } - -#define SEQ_LAST ((u64)-1) - enum btrfs_orphan_cleanup_state { ORPHAN_CLEANUP_STARTED = 1, ORPHAN_CLEANUP_DONE = 2, @@ -572,6 +582,15 @@ enum { /* Indicate that we can't trust the free space tree for caching yet */ BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, + + /* Indicate whether there are any tree modification log users */ + BTRFS_FS_TREE_MOD_LOG_USERS, + +#if BITS_PER_LONG == 32 + /* Indicate if we have error/warn message printed on 32bit systems */ + BTRFS_FS_32BIT_ERROR, + BTRFS_FS_32BIT_WARN, +#endif }; /* @@ -941,10 +960,16 @@ struct btrfs_fs_info { struct work_struct async_data_reclaim_work; struct work_struct preempt_reclaim_work; + /* Reclaim partially filled block groups in the background */ + struct work_struct reclaim_bgs_work; + struct list_head reclaim_bgs; + int bg_reclaim_threshold; + spinlock_t unused_bgs_lock; struct list_head unused_bgs; struct mutex unused_bg_unpin_mutex; - struct mutex delete_unused_bgs_mutex; + /* Protect block groups that are going to be deleted */ + struct mutex reclaim_bgs_lock; /* Cached block sizes */ u32 nodesize; @@ -2691,7 +2716,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans); int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_ref *generic_ref); -int btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr); void btrfs_clear_space_info_full(struct btrfs_fs_info *info); /* @@ -2929,13 +2953,6 @@ static inline void btrfs_clear_sb_rdonly(struct super_block *sb) clear_bit(BTRFS_FS_STATE_RO, &btrfs_sb(sb)->fs_state); } -/* tree mod log functions from ctree.c */ -u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem); -void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem); -int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq); - /* root-item.c */ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, u64 ref_id, u64 dirid, u64 sequence, const char *name, @@ -3084,7 +3101,7 @@ u64 btrfs_file_extent_end(const struct btrfs_path *path); blk_status_t btrfs_submit_data_bio(struct inode *inode, struct bio *bio, int mirror_num, unsigned long bio_flags); int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset, - struct page *page, u64 start, u64 end, int mirror); + struct page *page, u64 start, u64 end); struct extent_map *btrfs_get_extent_fiemap(struct btrfs_inode *inode, u64 start, u64 len); noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, @@ -3179,6 +3196,7 @@ extern const struct iomap_dio_ops btrfs_dio_ops; /* Inode locking type flags, by default the exclusive lock is taken */ #define BTRFS_ILOCK_SHARED (1U << 0) #define BTRFS_ILOCK_TRY (1U << 1) +#define BTRFS_ILOCK_MMAP (1U << 2) int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags); void btrfs_inode_unlock(struct inode *inode, unsigned int ilock_flags); @@ -3189,6 +3207,9 @@ void btrfs_update_inode_bytes(struct btrfs_inode *inode, /* ioctl.c */ long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int btrfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); int btrfs_ioctl_get_supported_features(void __user *arg); void btrfs_sync_inode_flags_to_i_flags(struct inode *inode); int __pure btrfs_is_empty_uuid(u8 *uuid); @@ -3217,8 +3238,9 @@ extern const struct file_operations btrfs_file_operations; int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_inode *inode, struct btrfs_drop_extents_args *args); -int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, - const u64 start, const u64 end, +int btrfs_replace_file_extents(struct btrfs_inode *inode, + struct btrfs_path *path, const u64 start, + const u64 end, struct btrfs_replace_extent_info *extent_info, struct btrfs_trans_handle **trans_out); int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, @@ -3405,6 +3427,19 @@ static inline void assertfail(const char *expr, const char* file, int line) { } #define ASSERT(expr) (void)(expr) #endif +#if BITS_PER_LONG == 32 +#define BTRFS_32BIT_MAX_FILE_SIZE (((u64)ULONG_MAX + 1) << PAGE_SHIFT) +/* + * The warning threshold is 5/8th of the MAX_LFS_FILESIZE that limits the logical + * addresses of extents. + * + * For 4K page size it's about 10T, for 64K it's 160T. + */ +#define BTRFS_32BIT_EARLY_WARN_THRESHOLD (BTRFS_32BIT_MAX_FILE_SIZE * 5 / 8) +void btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info); +void btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info); +#endif + /* * Get the correct offset inside the page of extent buffer. * @@ -3732,8 +3767,6 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info) return signal_pending(current); } -#define in_range(b, first, len) ((b) >= (first) && (b) < (first) + (len)) - /* Sanity test specific functions */ #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS void btrfs_test_destroy_inode(struct inode *inode); diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index bf25401c97681eb0f58cae19502021e7704ff985..1a88f6214ebc013e6d84e01c33f6648b457c7df3 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -602,7 +602,6 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root, static int btrfs_delayed_inode_reserve_metadata( struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_inode *inode, struct btrfs_delayed_node *node) { struct btrfs_fs_info *fs_info = root->fs_info; @@ -633,32 +632,17 @@ static int btrfs_delayed_inode_reserve_metadata( return ret; ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes, BTRFS_RESERVE_NO_FLUSH); - /* - * Since we're under a transaction reserve_metadata_bytes could - * try to commit the transaction which will make it return - * EAGAIN to make us stop the transaction we have, so return - * ENOSPC instead so that btrfs_dirty_inode knows what to do. - */ - if (ret == -EAGAIN) { - ret = -ENOSPC; - btrfs_qgroup_free_meta_prealloc(root, num_bytes); - } - if (!ret) { - node->bytes_reserved = num_bytes; - trace_btrfs_space_reservation(fs_info, - "delayed_inode", - btrfs_ino(inode), - num_bytes, 1); - } else { + /* NO_FLUSH could only fail with -ENOSPC */ + ASSERT(ret == 0 || ret == -ENOSPC); + if (ret) btrfs_qgroup_free_meta_prealloc(root, num_bytes); - } - return ret; + } else { + ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, true); } - ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, true); if (!ret) { trace_btrfs_space_reservation(fs_info, "delayed_inode", - btrfs_ino(inode), num_bytes, 1); + node->inode_id, num_bytes, 1); node->bytes_reserved = num_bytes; } @@ -1589,8 +1573,8 @@ bool btrfs_readdir_get_delayed_items(struct inode *inode, * We can only do one readdir with delayed items at a time because of * item->readdir_list. */ - inode_unlock_shared(inode); - inode_lock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED); + btrfs_inode_lock(inode, 0); mutex_lock(&delayed_node->mutex); item = __btrfs_first_delayed_insertion_item(delayed_node); @@ -1833,8 +1817,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, goto release_node; } - ret = btrfs_delayed_inode_reserve_metadata(trans, root, inode, - delayed_node); + ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node); if (ret) goto release_node; diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 63be7d01a9a3d88bcc2b4cd0e4ce71dcc3dbafd4..c92d9d4f5f46cf41b22886554a43ecafa8b0f266 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -11,6 +11,7 @@ #include "transaction.h" #include "qgroup.h" #include "space-info.h" +#include "tree-mod-log.h" struct kmem_cache *btrfs_delayed_ref_head_cachep; struct kmem_cache *btrfs_delayed_tree_ref_cachep; @@ -494,16 +495,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, if (head->is_data) return; - read_lock(&fs_info->tree_mod_log_lock); - if (!list_empty(&fs_info->tree_mod_seq_list)) { - struct seq_list *elem; - - elem = list_first_entry(&fs_info->tree_mod_seq_list, - struct seq_list, list); - seq = elem->seq; - } - read_unlock(&fs_info->tree_mod_log_lock); - + seq = btrfs_tree_mod_log_lowest_seq(fs_info); again: for (node = rb_first_cached(&head->ref_tree); node; node = rb_next(node)) { @@ -517,23 +509,16 @@ again: int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, u64 seq) { - struct seq_list *elem; int ret = 0; + u64 min_seq = btrfs_tree_mod_log_lowest_seq(fs_info); - read_lock(&fs_info->tree_mod_log_lock); - if (!list_empty(&fs_info->tree_mod_seq_list)) { - elem = list_first_entry(&fs_info->tree_mod_seq_list, - struct seq_list, list); - if (seq >= elem->seq) { - btrfs_debug(fs_info, - "holding back delayed_ref %#x.%x, lowest is %#x.%x", - (u32)(seq >> 32), (u32)seq, - (u32)(elem->seq >> 32), (u32)elem->seq); - ret = 1; - } + if (min_seq != 0 && seq >= min_seq) { + btrfs_debug(fs_info, + "holding back delayed_ref %llu, lowest is %llu", + seq, min_seq); + ret = 1; } - read_unlock(&fs_info->tree_mod_log_lock); return ret; } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 289f1f09481d7923872466e520cd08647d1c65c2..c9a3036c23bfcd10e040fb12e806e1f8fde4575f 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -42,6 +42,7 @@ #include "discard.h" #include "space-info.h" #include "zoned.h" +#include "subpage.h" #define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\ BTRFS_HEADER_FLAG_RELOC |\ @@ -440,6 +441,74 @@ static int btree_read_extent_buffer_pages(struct extent_buffer *eb, return ret; } +static int csum_one_extent_buffer(struct extent_buffer *eb) +{ + struct btrfs_fs_info *fs_info = eb->fs_info; + u8 result[BTRFS_CSUM_SIZE]; + int ret; + + ASSERT(memcmp_extent_buffer(eb, fs_info->fs_devices->metadata_uuid, + offsetof(struct btrfs_header, fsid), + BTRFS_FSID_SIZE) == 0); + csum_tree_block(eb, result); + + if (btrfs_header_level(eb)) + ret = btrfs_check_node(eb); + else + ret = btrfs_check_leaf_full(eb); + + if (ret < 0) { + btrfs_print_tree(eb, 0); + btrfs_err(fs_info, + "block=%llu write time tree block corruption detected", + eb->start); + WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); + return ret; + } + write_extent_buffer(eb, result, 0, fs_info->csum_size); + + return 0; +} + +/* Checksum all dirty extent buffers in one bio_vec */ +static int csum_dirty_subpage_buffers(struct btrfs_fs_info *fs_info, + struct bio_vec *bvec) +{ + struct page *page = bvec->bv_page; + u64 bvec_start = page_offset(page) + bvec->bv_offset; + u64 cur; + int ret = 0; + + for (cur = bvec_start; cur < bvec_start + bvec->bv_len; + cur += fs_info->nodesize) { + struct extent_buffer *eb; + bool uptodate; + + eb = find_extent_buffer(fs_info, cur); + uptodate = btrfs_subpage_test_uptodate(fs_info, page, cur, + fs_info->nodesize); + + /* A dirty eb shouldn't disappear from buffer_radix */ + if (WARN_ON(!eb)) + return -EUCLEAN; + + if (WARN_ON(cur != btrfs_header_bytenr(eb))) { + free_extent_buffer(eb); + return -EUCLEAN; + } + if (WARN_ON(!uptodate)) { + free_extent_buffer(eb); + return -EUCLEAN; + } + + ret = csum_one_extent_buffer(eb); + free_extent_buffer(eb); + if (ret < 0) + return ret; + } + return ret; +} + /* * Checksum a dirty tree block before IO. This has extra checks to make sure * we only fill in the checksum field in the first page of a multi-page block. @@ -450,9 +519,10 @@ static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct bio_vec *bvec struct page *page = bvec->bv_page; u64 start = page_offset(page); u64 found_start; - u8 result[BTRFS_CSUM_SIZE]; struct extent_buffer *eb; - int ret; + + if (fs_info->sectorsize < PAGE_SIZE) + return csum_dirty_subpage_buffers(fs_info, bvec); eb = (struct extent_buffer *)page->private; if (page != eb->pages[0]) @@ -474,28 +544,7 @@ static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct bio_vec *bvec if (WARN_ON(!PageUptodate(page))) return -EUCLEAN; - ASSERT(memcmp_extent_buffer(eb, fs_info->fs_devices->metadata_uuid, - offsetof(struct btrfs_header, fsid), - BTRFS_FSID_SIZE) == 0); - - csum_tree_block(eb, result); - - if (btrfs_header_level(eb)) - ret = btrfs_check_node(eb); - else - ret = btrfs_check_leaf_full(eb); - - if (ret < 0) { - btrfs_print_tree(eb, 0); - btrfs_err(fs_info, - "block=%llu write time tree block corruption detected", - eb->start); - WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); - return ret; - } - write_extent_buffer(eb, result, 0, fs_info->csum_size); - - return 0; + return csum_one_extent_buffer(eb); } static int check_tree_block_fsid(struct extent_buffer *eb) @@ -992,14 +1041,48 @@ static void btree_invalidatepage(struct page *page, unsigned int offset, static int btree_set_page_dirty(struct page *page) { #ifdef DEBUG + struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb); + struct btrfs_subpage *subpage; struct extent_buffer *eb; + int cur_bit = 0; + u64 page_start = page_offset(page); + + if (fs_info->sectorsize == PAGE_SIZE) { + BUG_ON(!PagePrivate(page)); + eb = (struct extent_buffer *)page->private; + BUG_ON(!eb); + BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); + BUG_ON(!atomic_read(&eb->refs)); + btrfs_assert_tree_locked(eb); + return __set_page_dirty_nobuffers(page); + } + ASSERT(PagePrivate(page) && page->private); + subpage = (struct btrfs_subpage *)page->private; + + ASSERT(subpage->dirty_bitmap); + while (cur_bit < BTRFS_SUBPAGE_BITMAP_SIZE) { + unsigned long flags; + u64 cur; + u16 tmp = (1 << cur_bit); + + spin_lock_irqsave(&subpage->lock, flags); + if (!(tmp & subpage->dirty_bitmap)) { + spin_unlock_irqrestore(&subpage->lock, flags); + cur_bit++; + continue; + } + spin_unlock_irqrestore(&subpage->lock, flags); + cur = page_start + cur_bit * fs_info->sectorsize; - BUG_ON(!PagePrivate(page)); - eb = (struct extent_buffer *)page->private; - BUG_ON(!eb); - BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); - BUG_ON(!atomic_read(&eb->refs)); - btrfs_assert_tree_locked(eb); + eb = find_extent_buffer(fs_info, cur); + ASSERT(eb); + ASSERT(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); + ASSERT(atomic_read(&eb->refs)); + btrfs_assert_tree_locked(eb); + free_extent_buffer(eb); + + cur_bit += (fs_info->nodesize >> fs_info->sectorsize_bits); + } #endif return __set_page_dirty_nobuffers(page); } @@ -1807,14 +1890,21 @@ static int cleaner_kthread(void *arg) btrfs_run_defrag_inodes(fs_info); /* - * Acquires fs_info->delete_unused_bgs_mutex to avoid racing + * Acquires fs_info->reclaim_bgs_lock to avoid racing * with relocation (btrfs_relocate_chunk) and relocation * acquires fs_info->cleaner_mutex (btrfs_relocate_block_group) - * after acquiring fs_info->delete_unused_bgs_mutex. So we + * after acquiring fs_info->reclaim_bgs_lock. So we * can't hold, nor need to, fs_info->cleaner_mutex when deleting * unused block groups. */ btrfs_delete_unused_bgs(fs_info); + + /* + * Reclaim block groups in the reclaim_bgs list after we deleted + * all unused block_groups. This possibly gives us some more free + * space. + */ + btrfs_reclaim_bgs(fs_info); sleep: clear_and_wake_up_bit(BTRFS_FS_CLEANER_RUNNING, &fs_info->flags); if (kthread_should_park()) @@ -2793,7 +2883,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) spin_lock_init(&fs_info->treelog_bg_lock); rwlock_init(&fs_info->tree_mod_log_lock); mutex_init(&fs_info->unused_bg_unpin_mutex); - mutex_init(&fs_info->delete_unused_bgs_mutex); + mutex_init(&fs_info->reclaim_bgs_lock); mutex_init(&fs_info->reloc_mutex); mutex_init(&fs_info->delalloc_root_mutex); mutex_init(&fs_info->zoned_meta_io_lock); @@ -2803,6 +2893,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) INIT_LIST_HEAD(&fs_info->space_info); INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); INIT_LIST_HEAD(&fs_info->unused_bgs); + INIT_LIST_HEAD(&fs_info->reclaim_bgs); #ifdef CONFIG_BTRFS_DEBUG INIT_LIST_HEAD(&fs_info->allocated_roots); INIT_LIST_HEAD(&fs_info->allocated_ebs); @@ -2891,6 +2982,9 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) fs_info->swapfile_pins = RB_ROOT; fs_info->send_in_progress = 0; + + fs_info->bg_reclaim_threshold = BTRFS_DEFAULT_RECLAIM_THRESH; + INIT_WORK(&fs_info->reclaim_bgs_work, btrfs_reclaim_bgs_work); } static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block *sb) @@ -4249,6 +4343,8 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) cancel_work_sync(&fs_info->async_data_reclaim_work); cancel_work_sync(&fs_info->preempt_reclaim_work); + cancel_work_sync(&fs_info->reclaim_bgs_work); + /* Cancel or finish ongoing discard work */ btrfs_discard_cleanup(fs_info); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 36a3c973fda1029529f8cdaebca0e0be99539020..7a28314189b4a3c0e05aeb14990adcbc33c3d686 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2490,19 +2490,6 @@ int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, return __btrfs_mod_ref(trans, root, buf, full_backref, 0); } -int btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr) -{ - struct btrfs_block_group *block_group; - int readonly = 0; - - block_group = btrfs_lookup_block_group(fs_info, bytenr); - if (!block_group || block_group->ro) - readonly = 1; - if (block_group) - btrfs_put_block_group(block_group); - return readonly; -} - static u64 get_alloc_profile_by_root(struct btrfs_root *root, int data) { struct btrfs_fs_info *fs_info = root->fs_info; @@ -3355,11 +3342,9 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, * find a node pointing to this leaf and record operations that * point to this leaf. */ - if (btrfs_header_level(buf) == 0) { - read_lock(&fs_info->tree_mod_log_lock); - must_pin = !list_empty(&fs_info->tree_mod_seq_list); - read_unlock(&fs_info->tree_mod_log_lock); - } + if (btrfs_header_level(buf) == 0 && + test_bit(BTRFS_FS_TREE_MOD_LOG_USERS, &fs_info->flags)) + must_pin = true; if (must_pin || btrfs_is_zoned(fs_info)) { btrfs_redirty_list_add(trans->transaction, buf); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 910769d5fcdb4998ca5ba004087cf7537bfff132..f2d1bb2343779fa3998792f76477dfe3b7281588 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -13,6 +13,7 @@ #include <linux/pagevec.h> #include <linux/prefetch.h> #include <linux/cleancache.h> +#include "misc.h" #include "extent_io.h" #include "extent-io-tree.h" #include "extent_map.h" @@ -2983,8 +2984,7 @@ static void end_bio_extent_readpage(struct bio *bio) if (likely(uptodate)) { if (is_data_inode(inode)) ret = btrfs_verify_data_csum(io_bio, - bio_offset, page, start, end, - mirror); + bio_offset, page, start, end); else ret = btrfs_validate_metadata_buffer(io_bio, page, start, end, mirror); @@ -3967,7 +3967,13 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb btrfs_tree_unlock(eb); - if (!ret) + /* + * Either we don't need to submit any tree block, or we're submitting + * subpage eb. + * Subpage metadata doesn't use page locking at all, so we can skip + * the page locking. + */ + if (!ret || fs_info->sectorsize < PAGE_SIZE) return ret; num_pages = num_extent_pages(eb); @@ -4012,12 +4018,11 @@ err_unlock: return ret; } -static void set_btree_ioerr(struct page *page) +static void set_btree_ioerr(struct page *page, struct extent_buffer *eb) { - struct extent_buffer *eb = (struct extent_buffer *)page->private; - struct btrfs_fs_info *fs_info; + struct btrfs_fs_info *fs_info = eb->fs_info; - SetPageError(page); + btrfs_page_set_error(fs_info, page, eb->start, eb->len); if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) return; @@ -4025,7 +4030,6 @@ static void set_btree_ioerr(struct page *page) * If we error out, we should add back the dirty_metadata_bytes * to make it consistent. */ - fs_info = eb->fs_info; percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, eb->len, fs_info->dirty_metadata_batch); @@ -4069,26 +4073,111 @@ static void set_btree_ioerr(struct page *page) */ switch (eb->log_index) { case -1: - set_bit(BTRFS_FS_BTREE_ERR, &eb->fs_info->flags); + set_bit(BTRFS_FS_BTREE_ERR, &fs_info->flags); break; case 0: - set_bit(BTRFS_FS_LOG1_ERR, &eb->fs_info->flags); + set_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags); break; case 1: - set_bit(BTRFS_FS_LOG2_ERR, &eb->fs_info->flags); + set_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags); break; default: BUG(); /* unexpected, logic error */ } } +/* + * The endio specific version which won't touch any unsafe spinlock in endio + * context. + */ +static struct extent_buffer *find_extent_buffer_nolock( + struct btrfs_fs_info *fs_info, u64 start) +{ + struct extent_buffer *eb; + + rcu_read_lock(); + eb = radix_tree_lookup(&fs_info->buffer_radix, + start >> fs_info->sectorsize_bits); + if (eb && atomic_inc_not_zero(&eb->refs)) { + rcu_read_unlock(); + return eb; + } + rcu_read_unlock(); + return NULL; +} + +/* + * The endio function for subpage extent buffer write. + * + * Unlike end_bio_extent_buffer_writepage(), we only call end_page_writeback() + * after all extent buffers in the page has finished their writeback. + */ +static void end_bio_subpage_eb_writepage(struct btrfs_fs_info *fs_info, + struct bio *bio) +{ + struct bio_vec *bvec; + struct bvec_iter_all iter_all; + + ASSERT(!bio_flagged(bio, BIO_CLONED)); + bio_for_each_segment_all(bvec, bio, iter_all) { + struct page *page = bvec->bv_page; + u64 bvec_start = page_offset(page) + bvec->bv_offset; + u64 bvec_end = bvec_start + bvec->bv_len - 1; + u64 cur_bytenr = bvec_start; + + ASSERT(IS_ALIGNED(bvec->bv_len, fs_info->nodesize)); + + /* Iterate through all extent buffers in the range */ + while (cur_bytenr <= bvec_end) { + struct extent_buffer *eb; + int done; + + /* + * Here we can't use find_extent_buffer(), as it may + * try to lock eb->refs_lock, which is not safe in endio + * context. + */ + eb = find_extent_buffer_nolock(fs_info, cur_bytenr); + ASSERT(eb); + + cur_bytenr = eb->start + eb->len; + + ASSERT(test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags)); + done = atomic_dec_and_test(&eb->io_pages); + ASSERT(done); + + if (bio->bi_status || + test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { + ClearPageUptodate(page); + set_btree_ioerr(page, eb); + } + + btrfs_subpage_clear_writeback(fs_info, page, eb->start, + eb->len); + end_extent_buffer_writeback(eb); + /* + * free_extent_buffer() will grab spinlock which is not + * safe in endio context. Thus here we manually dec + * the ref. + */ + atomic_dec(&eb->refs); + } + } + bio_put(bio); +} + static void end_bio_extent_buffer_writepage(struct bio *bio) { + struct btrfs_fs_info *fs_info; struct bio_vec *bvec; struct extent_buffer *eb; int done; struct bvec_iter_all iter_all; + fs_info = btrfs_sb(bio_first_page_all(bio)->mapping->host->i_sb); + if (fs_info->sectorsize < PAGE_SIZE) + return end_bio_subpage_eb_writepage(fs_info, bio); + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, iter_all) { struct page *page = bvec->bv_page; @@ -4100,7 +4189,7 @@ static void end_bio_extent_buffer_writepage(struct bio *bio) if (bio->bi_status || test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { ClearPageUptodate(page); - set_btree_ioerr(page); + set_btree_ioerr(page, eb); } end_page_writeback(page); @@ -4114,6 +4203,56 @@ static void end_bio_extent_buffer_writepage(struct bio *bio) bio_put(bio); } +/* + * Unlike the work in write_one_eb(), we rely completely on extent locking. + * Page locking is only utilized at minimum to keep the VMM code happy. + * + * Caller should still call write_one_eb() other than this function directly. + * As write_one_eb() has extra preparation before submitting the extent buffer. + */ +static int write_one_subpage_eb(struct extent_buffer *eb, + struct writeback_control *wbc, + struct extent_page_data *epd) +{ + struct btrfs_fs_info *fs_info = eb->fs_info; + struct page *page = eb->pages[0]; + unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META; + bool no_dirty_ebs = false; + int ret; + + /* clear_page_dirty_for_io() in subpage helper needs page locked */ + lock_page(page); + btrfs_subpage_set_writeback(fs_info, page, eb->start, eb->len); + + /* Check if this is the last dirty bit to update nr_written */ + no_dirty_ebs = btrfs_subpage_clear_and_test_dirty(fs_info, page, + eb->start, eb->len); + if (no_dirty_ebs) + clear_page_dirty_for_io(page); + + ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc, page, + eb->start, eb->len, eb->start - page_offset(page), + &epd->bio, end_bio_extent_buffer_writepage, 0, 0, 0, + false); + if (ret) { + btrfs_subpage_clear_writeback(fs_info, page, eb->start, eb->len); + set_btree_ioerr(page, eb); + unlock_page(page); + + if (atomic_dec_and_test(&eb->io_pages)) + end_extent_buffer_writeback(eb); + return -EIO; + } + unlock_page(page); + /* + * Submission finished without problem, if no range of the page is + * dirty anymore, we have submitted a page. Update nr_written in wbc. + */ + if (no_dirty_ebs) + update_nr_written(wbc, 1); + return ret; +} + static noinline_for_stack int write_one_eb(struct extent_buffer *eb, struct writeback_control *wbc, struct extent_page_data *epd) @@ -4145,6 +4284,9 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, memzero_extent_buffer(eb, start, end - start); } + if (eb->fs_info->sectorsize < PAGE_SIZE) + return write_one_subpage_eb(eb, wbc, epd); + for (i = 0; i < num_pages; i++) { struct page *p = eb->pages[i]; @@ -4156,7 +4298,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, end_bio_extent_buffer_writepage, 0, 0, 0, false); if (ret) { - set_btree_ioerr(p); + set_btree_ioerr(p, eb); if (PageWriteback(p)) end_page_writeback(p); if (atomic_sub_and_test(num_pages - i, &eb->io_pages)) @@ -4180,6 +4322,98 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, return ret; } +/* + * Submit one subpage btree page. + * + * The main difference to submit_eb_page() is: + * - Page locking + * For subpage, we don't rely on page locking at all. + * + * - Flush write bio + * We only flush bio if we may be unable to fit current extent buffers into + * current bio. + * + * Return >=0 for the number of submitted extent buffers. + * Return <0 for fatal error. + */ +static int submit_eb_subpage(struct page *page, + struct writeback_control *wbc, + struct extent_page_data *epd) +{ + struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb); + int submitted = 0; + u64 page_start = page_offset(page); + int bit_start = 0; + const int nbits = BTRFS_SUBPAGE_BITMAP_SIZE; + int sectors_per_node = fs_info->nodesize >> fs_info->sectorsize_bits; + int ret; + + /* Lock and write each dirty extent buffers in the range */ + while (bit_start < nbits) { + struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; + struct extent_buffer *eb; + unsigned long flags; + u64 start; + + /* + * Take private lock to ensure the subpage won't be detached + * in the meantime. + */ + spin_lock(&page->mapping->private_lock); + if (!PagePrivate(page)) { + spin_unlock(&page->mapping->private_lock); + break; + } + spin_lock_irqsave(&subpage->lock, flags); + if (!((1 << bit_start) & subpage->dirty_bitmap)) { + spin_unlock_irqrestore(&subpage->lock, flags); + spin_unlock(&page->mapping->private_lock); + bit_start++; + continue; + } + + start = page_start + bit_start * fs_info->sectorsize; + bit_start += sectors_per_node; + + /* + * Here we just want to grab the eb without touching extra + * spin locks, so call find_extent_buffer_nolock(). + */ + eb = find_extent_buffer_nolock(fs_info, start); + spin_unlock_irqrestore(&subpage->lock, flags); + spin_unlock(&page->mapping->private_lock); + + /* + * The eb has already reached 0 refs thus find_extent_buffer() + * doesn't return it. We don't need to write back such eb + * anyway. + */ + if (!eb) + continue; + + ret = lock_extent_buffer_for_io(eb, epd); + if (ret == 0) { + free_extent_buffer(eb); + continue; + } + if (ret < 0) { + free_extent_buffer(eb); + goto cleanup; + } + ret = write_one_eb(eb, wbc, epd); + free_extent_buffer(eb); + if (ret < 0) + goto cleanup; + submitted++; + } + return submitted; + +cleanup: + /* We hit error, end bio for the submitted extent buffers */ + end_write_bio(epd, ret); + return ret; +} + /* * Submit all page(s) of one extent buffer. * @@ -4212,6 +4446,9 @@ static int submit_eb_page(struct page *page, struct writeback_control *wbc, if (!PagePrivate(page)) return 0; + if (btrfs_sb(page->mapping->host->i_sb)->sectorsize < PAGE_SIZE) + return submit_eb_subpage(page, wbc, epd); + spin_lock(&mapping->private_lock); if (!PagePrivate(page)) { spin_unlock(&mapping->private_lock); @@ -4652,10 +4889,8 @@ void extent_readahead(struct readahead_control *rac) int nr; while ((nr = readahead_page_batch(rac, pagepool))) { - u64 contig_start = page_offset(pagepool[0]); - u64 contig_end = page_offset(pagepool[nr - 1]) + PAGE_SIZE - 1; - - ASSERT(contig_start + nr * PAGE_SIZE - 1 == contig_end); + u64 contig_start = readahead_pos(rac); + u64 contig_end = contig_start + readahead_batch_length(rac) - 1; contiguous_readpages(pagepool, nr, contig_start, contig_end, &em_cached, &bio, &bio_flags, &prev_em_start); @@ -5469,36 +5704,28 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, { struct extent_buffer *eb; - rcu_read_lock(); - eb = radix_tree_lookup(&fs_info->buffer_radix, - start >> fs_info->sectorsize_bits); - if (eb && atomic_inc_not_zero(&eb->refs)) { - rcu_read_unlock(); - /* - * Lock our eb's refs_lock to avoid races with - * free_extent_buffer. When we get our eb it might be flagged - * with EXTENT_BUFFER_STALE and another task running - * free_extent_buffer might have seen that flag set, - * eb->refs == 2, that the buffer isn't under IO (dirty and - * writeback flags not set) and it's still in the tree (flag - * EXTENT_BUFFER_TREE_REF set), therefore being in the process - * of decrementing the extent buffer's reference count twice. - * So here we could race and increment the eb's reference count, - * clear its stale flag, mark it as dirty and drop our reference - * before the other task finishes executing free_extent_buffer, - * which would later result in an attempt to free an extent - * buffer that is dirty. - */ - if (test_bit(EXTENT_BUFFER_STALE, &eb->bflags)) { - spin_lock(&eb->refs_lock); - spin_unlock(&eb->refs_lock); - } - mark_extent_buffer_accessed(eb, NULL); - return eb; + eb = find_extent_buffer_nolock(fs_info, start); + if (!eb) + return NULL; + /* + * Lock our eb's refs_lock to avoid races with free_extent_buffer(). + * When we get our eb it might be flagged with EXTENT_BUFFER_STALE and + * another task running free_extent_buffer() might have seen that flag + * set, eb->refs == 2, that the buffer isn't under IO (dirty and + * writeback flags not set) and it's still in the tree (flag + * EXTENT_BUFFER_TREE_REF set), therefore being in the process of + * decrementing the extent buffer's reference count twice. So here we + * could race and increment the eb's reference count, clear its stale + * flag, mark it as dirty and drop our reference before the other task + * finishes executing free_extent_buffer, which would later result in + * an attempt to free an extent buffer that is dirty. + */ + if (test_bit(EXTENT_BUFFER_STALE, &eb->bflags)) { + spin_lock(&eb->refs_lock); + spin_unlock(&eb->refs_lock); } - rcu_read_unlock(); - - return NULL; + mark_extent_buffer_accessed(eb, NULL); + return eb; } #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS @@ -5594,6 +5821,17 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, return ERR_PTR(-EINVAL); } +#if BITS_PER_LONG == 32 + if (start >= MAX_LFS_FILESIZE) { + btrfs_err_rl(fs_info, + "extent buffer %llu is beyond 32bit page cache limit", start); + btrfs_err_32bit_limit(fs_info); + return ERR_PTR(-EOVERFLOW); + } + if (start >= BTRFS_32BIT_EARLY_WARN_THRESHOLD) + btrfs_warn_32bit_limit(fs_info); +#endif + if (fs_info->sectorsize < PAGE_SIZE && offset_in_page(start) + len > PAGE_SIZE) { btrfs_err(fs_info, @@ -5665,7 +5903,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, btrfs_page_inc_eb_refs(fs_info, p); spin_unlock(&mapping->private_lock); - WARN_ON(PageDirty(p)); + WARN_ON(btrfs_page_test_dirty(fs_info, p, eb->start, eb->len)); eb->pages[i] = p; if (!PageUptodate(p)) uptodate = 0; @@ -5814,28 +6052,51 @@ void free_extent_buffer_stale(struct extent_buffer *eb) release_extent_buffer(eb); } +static void btree_clear_page_dirty(struct page *page) +{ + ASSERT(PageDirty(page)); + ASSERT(PageLocked(page)); + clear_page_dirty_for_io(page); + xa_lock_irq(&page->mapping->i_pages); + if (!PageDirty(page)) + __xa_clear_mark(&page->mapping->i_pages, + page_index(page), PAGECACHE_TAG_DIRTY); + xa_unlock_irq(&page->mapping->i_pages); +} + +static void clear_subpage_extent_buffer_dirty(const struct extent_buffer *eb) +{ + struct btrfs_fs_info *fs_info = eb->fs_info; + struct page *page = eb->pages[0]; + bool last; + + /* btree_clear_page_dirty() needs page locked */ + lock_page(page); + last = btrfs_subpage_clear_and_test_dirty(fs_info, page, eb->start, + eb->len); + if (last) + btree_clear_page_dirty(page); + unlock_page(page); + WARN_ON(atomic_read(&eb->refs) == 0); +} + void clear_extent_buffer_dirty(const struct extent_buffer *eb) { int i; int num_pages; struct page *page; + if (eb->fs_info->sectorsize < PAGE_SIZE) + return clear_subpage_extent_buffer_dirty(eb); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { page = eb->pages[i]; if (!PageDirty(page)) continue; - lock_page(page); - WARN_ON(!PagePrivate(page)); - - clear_page_dirty_for_io(page); - xa_lock_irq(&page->mapping->i_pages); - if (!PageDirty(page)) - __xa_clear_mark(&page->mapping->i_pages, - page_index(page), PAGECACHE_TAG_DIRTY); - xa_unlock_irq(&page->mapping->i_pages); + btree_clear_page_dirty(page); ClearPageError(page); unlock_page(page); } @@ -5856,10 +6117,28 @@ bool set_extent_buffer_dirty(struct extent_buffer *eb) WARN_ON(atomic_read(&eb->refs) == 0); WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)); - if (!was_dirty) - for (i = 0; i < num_pages; i++) - set_page_dirty(eb->pages[i]); + if (!was_dirty) { + bool subpage = eb->fs_info->sectorsize < PAGE_SIZE; + /* + * For subpage case, we can have other extent buffers in the + * same page, and in clear_subpage_extent_buffer_dirty() we + * have to clear page dirty without subpage lock held. + * This can cause race where our page gets dirty cleared after + * we just set it. + * + * Thankfully, clear_subpage_extent_buffer_dirty() has locked + * its page for other reasons, we can use page lock to prevent + * the above race. + */ + if (subpage) + lock_page(eb->pages[0]); + for (i = 0; i < num_pages; i++) + btrfs_page_set_dirty(eb->fs_info, eb->pages[i], + eb->start, eb->len); + if (subpage) + unlock_page(eb->pages[0]); + } #ifdef CONFIG_BTRFS_DEBUG for (i = 0; i < num_pages; i++) ASSERT(PageDirty(eb->pages[i])); @@ -6217,12 +6496,34 @@ int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, return ret; } +/* + * Check that the extent buffer is uptodate. + * + * For regular sector size == PAGE_SIZE case, check if @page is uptodate. + * For subpage case, check if the range covered by the eb has EXTENT_UPTODATE. + */ +static void assert_eb_page_uptodate(const struct extent_buffer *eb, + struct page *page) +{ + struct btrfs_fs_info *fs_info = eb->fs_info; + + if (fs_info->sectorsize < PAGE_SIZE) { + bool uptodate; + + uptodate = btrfs_subpage_test_uptodate(fs_info, page, + eb->start, eb->len); + WARN_ON(!uptodate); + } else { + WARN_ON(!PageUptodate(page)); + } +} + void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb, const void *srcv) { char *kaddr; - WARN_ON(!PageUptodate(eb->pages[0])); + assert_eb_page_uptodate(eb, eb->pages[0]); kaddr = page_address(eb->pages[0]) + get_eb_offset_in_page(eb, 0); memcpy(kaddr + offsetof(struct btrfs_header, chunk_tree_uuid), srcv, BTRFS_FSID_SIZE); @@ -6232,7 +6533,7 @@ void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *srcv) { char *kaddr; - WARN_ON(!PageUptodate(eb->pages[0])); + assert_eb_page_uptodate(eb, eb->pages[0]); kaddr = page_address(eb->pages[0]) + get_eb_offset_in_page(eb, 0); memcpy(kaddr + offsetof(struct btrfs_header, fsid), srcv, BTRFS_FSID_SIZE); @@ -6257,7 +6558,7 @@ void write_extent_buffer(const struct extent_buffer *eb, const void *srcv, while (len > 0) { page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); cur = min(len, PAGE_SIZE - offset); kaddr = page_address(page); @@ -6286,7 +6587,7 @@ void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start, while (len > 0) { page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); cur = min(len, PAGE_SIZE - offset); kaddr = page_address(page); @@ -6344,7 +6645,7 @@ void copy_extent_buffer(const struct extent_buffer *dst, while (len > 0) { page = dst->pages[i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(dst, page); cur = min(len, (unsigned long)(PAGE_SIZE - offset)); @@ -6406,7 +6707,7 @@ int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start, eb_bitmap_offset(eb, start, nr, &i, &offset); page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); kaddr = page_address(page); return 1U & (kaddr[offset] >> (nr & (BITS_PER_BYTE - 1))); } @@ -6431,7 +6732,7 @@ void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long star eb_bitmap_offset(eb, start, pos, &i, &offset); page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); kaddr = page_address(page); while (len >= bits_to_set) { @@ -6442,7 +6743,7 @@ void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long star if (++offset >= PAGE_SIZE && len > 0) { offset = 0; page = eb->pages[++i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); kaddr = page_address(page); } } @@ -6474,7 +6775,7 @@ void extent_buffer_bitmap_clear(const struct extent_buffer *eb, eb_bitmap_offset(eb, start, pos, &i, &offset); page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); kaddr = page_address(page); while (len >= bits_to_clear) { @@ -6485,7 +6786,7 @@ void extent_buffer_bitmap_clear(const struct extent_buffer *eb, if (++offset >= PAGE_SIZE && len > 0) { offset = 0; page = eb->pages[++i]; - WARN_ON(!PageUptodate(page)); + assert_eb_page_uptodate(eb, page); kaddr = page_address(page); } } diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 824640cb0ace657959c744a074e50161b7ffe90a..227215a5722cb6d70683a5b74625964a6e6b9028 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -66,6 +66,7 @@ enum { struct btrfs_root; struct btrfs_inode; struct btrfs_io_bio; +struct btrfs_fs_info; struct io_failure_record; struct extent_io_tree; @@ -270,9 +271,6 @@ struct bio *btrfs_io_bio_alloc(unsigned int nr_iovecs); struct bio *btrfs_bio_clone(struct bio *bio); struct bio *btrfs_bio_clone_partial(struct bio *orig, int offset, int size); -struct btrfs_fs_info; -struct btrfs_inode; - int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, u64 length, u64 logical, struct page *page, unsigned int pg_offset, int mirror_num); diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 47cd3a6dc6351b4bf692e1819fc6f812e1773306..294602f139efa624dec02be6d06448ce1865ece9 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -9,6 +9,7 @@ #include <linux/highmem.h> #include <linux/sched/mm.h> #include <crypto/hash.h> +#include "misc.h" #include "ctree.h" #include "disk-io.h" #include "transaction.h" diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 0e155f01383918dafc9ad869edff1b780f8e0095..864c08d08a353452edc957e75932cb91b2c19538 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2014,14 +2014,8 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, else num_written = btrfs_buffered_write(iocb, from); - /* - * We also have to set last_sub_trans to the current log transid, - * otherwise subsequent syncs to a file that's been synced in this - * transaction will appear to have already occurred. - */ - spin_lock(&inode->lock); - inode->last_sub_trans = inode->root->log_transid; - spin_unlock(&inode->lock); + btrfs_set_inode_last_sub_trans(inode); + if (num_written > 0) num_written = generic_write_sync(iocb, num_written); @@ -2122,7 +2116,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (ret) goto out; - inode_lock(inode); + btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP); atomic_inc(&root->log_batch); @@ -2135,11 +2129,11 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) &BTRFS_I(inode)->runtime_flags); /* - * Before we acquired the inode's lock, someone may have dirtied more - * pages in the target range. We need to make sure that writeback for - * any such pages does not start while we are logging the inode, because - * if it does, any of the following might happen when we are not doing a - * full inode sync: + * Before we acquired the inode's lock and the mmap lock, someone may + * have dirtied more pages in the target range. We need to make sure + * that writeback for any such pages does not start while we are logging + * the inode, because if it does, any of the following might happen when + * we are not doing a full inode sync: * * 1) We log an extent after its writeback finishes but before its * checksums are added to the csum tree, leading to -EIO errors @@ -2154,7 +2148,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) */ ret = start_ordered_ops(inode, start, end); if (ret) { - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); goto out; } @@ -2255,7 +2249,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * file again, but that will end up using the synchronization * inside btrfs_sync_log to keep things safe. */ - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); if (ret != BTRFS_NO_LOG_SYNC) { if (!ret) { @@ -2285,7 +2279,7 @@ out: out_release_extents: btrfs_release_log_ctx_extents(&ctx); - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); goto out; } @@ -2605,16 +2599,17 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, * extents without inserting a new one, so we must abort the transaction to avoid * a corruption. */ -int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, - const u64 start, const u64 end, - struct btrfs_replace_extent_info *extent_info, - struct btrfs_trans_handle **trans_out) +int btrfs_replace_file_extents(struct btrfs_inode *inode, + struct btrfs_path *path, const u64 start, + const u64 end, + struct btrfs_replace_extent_info *extent_info, + struct btrfs_trans_handle **trans_out) { struct btrfs_drop_extents_args drop_args = { 0 }; - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_root *root = inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; u64 min_size = btrfs_calc_insert_metadata_size(fs_info, 1); - u64 ino_size = round_up(inode->i_size, fs_info->sectorsize); - struct btrfs_root *root = BTRFS_I(inode)->root; + u64 ino_size = round_up(inode->vfs_inode.i_size, fs_info->sectorsize); struct btrfs_trans_handle *trans = NULL; struct btrfs_block_rsv *rsv; unsigned int rsv_count; @@ -2662,10 +2657,10 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, drop_args.drop_cache = true; while (cur_offset < end) { drop_args.start = cur_offset; - ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args); + ret = btrfs_drop_extents(trans, root, inode, &drop_args); /* If we are punching a hole decrement the inode's byte count */ if (!extent_info) - btrfs_update_inode_bytes(BTRFS_I(inode), 0, + btrfs_update_inode_bytes(inode, 0, drop_args.bytes_found); if (ret != -ENOSPC) { /* @@ -2685,8 +2680,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, if (!extent_info && cur_offset < drop_args.drop_end && cur_offset < ino_size) { - ret = fill_holes(trans, BTRFS_I(inode), path, - cur_offset, drop_args.drop_end); + ret = fill_holes(trans, inode, path, cur_offset, + drop_args.drop_end); if (ret) { /* * If we failed then we didn't insert our hole @@ -2704,7 +2699,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, * know to not set disk_i_size in this area until a new * file extent is inserted here. */ - ret = btrfs_inode_clear_file_extent_range(BTRFS_I(inode), + ret = btrfs_inode_clear_file_extent_range(inode, cur_offset, drop_args.drop_end - cur_offset); if (ret) { @@ -2723,8 +2718,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, u64 replace_len = drop_args.drop_end - extent_info->file_offset; - ret = btrfs_insert_replace_extent(trans, BTRFS_I(inode), - path, extent_info, replace_len, + ret = btrfs_insert_replace_extent(trans, inode, path, + extent_info, replace_len, drop_args.bytes_found); if (ret) { btrfs_abort_transaction(trans, ret); @@ -2735,9 +2730,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, extent_info->file_offset += replace_len; } - cur_offset = drop_args.drop_end; - - ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); + ret = btrfs_update_inode(trans, root, inode); if (ret) break; @@ -2756,9 +2749,10 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, BUG_ON(ret); /* shouldn't happen */ trans->block_rsv = rsv; - if (!extent_info) { - ret = find_first_non_hole(BTRFS_I(inode), &cur_offset, - &len); + cur_offset = drop_args.drop_end; + len = end - cur_offset; + if (!extent_info && len) { + ret = find_first_non_hole(inode, &cur_offset, &len); if (unlikely(ret < 0)) break; if (ret && !len) { @@ -2771,14 +2765,11 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, /* * If we were cloning, force the next fsync to be a full one since we * we replaced (or just dropped in the case of cloning holes when - * NO_HOLES is enabled) extents and extent maps. - * This is for the sake of simplicity, and cloning into files larger - * than 16Mb would force the full fsync any way (when - * try_release_extent_mapping() is invoked during page cache truncation. + * NO_HOLES is enabled) file extent items and did not setup new extent + * maps for the replacement extents (or holes). */ if (extent_info && !extent_info->is_new_extent) - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); + set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags); if (ret) goto out_trans; @@ -2804,8 +2795,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, */ if (!extent_info && cur_offset < ino_size && cur_offset < drop_args.drop_end) { - ret = fill_holes(trans, BTRFS_I(inode), path, - cur_offset, drop_args.drop_end); + ret = fill_holes(trans, inode, path, cur_offset, + drop_args.drop_end); if (ret) { /* Same comment as above. */ btrfs_abort_transaction(trans, ret); @@ -2813,8 +2804,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, } } else if (!extent_info && cur_offset < drop_args.drop_end) { /* See the comment in the loop above for the reasoning here. */ - ret = btrfs_inode_clear_file_extent_range(BTRFS_I(inode), - cur_offset, drop_args.drop_end - cur_offset); + ret = btrfs_inode_clear_file_extent_range(inode, cur_offset, + drop_args.drop_end - cur_offset); if (ret) { btrfs_abort_transaction(trans, ret); goto out_trans; @@ -2822,7 +2813,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, } if (extent_info) { - ret = btrfs_insert_replace_extent(trans, BTRFS_I(inode), path, + ret = btrfs_insert_replace_extent(trans, inode, path, extent_info, extent_info->data_len, drop_args.bytes_found); if (ret) { @@ -2868,7 +2859,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) if (ret) return ret; - inode_lock(inode); + btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP); ino_size = round_up(inode->i_size, fs_info->sectorsize); ret = find_first_non_hole(BTRFS_I(inode), &offset, &len); if (ret < 0) @@ -2908,7 +2899,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) truncated_block = true; ret = btrfs_truncate_block(BTRFS_I(inode), offset, 0, 0); if (ret) { - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); return ret; } } @@ -2967,8 +2958,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) goto out; } - ret = btrfs_replace_file_extents(inode, path, lockstart, lockend, NULL, - &trans); + ret = btrfs_replace_file_extents(BTRFS_I(inode), path, lockstart, + lockend, NULL, &trans); btrfs_free_path(path); if (ret) goto out; @@ -3009,7 +3000,7 @@ out_only_mutex: ret = ret2; } } - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); return ret; } @@ -3335,7 +3326,7 @@ static long btrfs_fallocate(struct file *file, int mode, return ret; } - btrfs_inode_lock(inode, 0); + btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP); if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) { ret = inode_newsize_ok(inode, offset + len); @@ -3377,7 +3368,7 @@ static long btrfs_fallocate(struct file *file, int mode, if (mode & FALLOC_FL_ZERO_RANGE) { ret = btrfs_zero_range(inode, offset, len, mode); - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); return ret; } @@ -3487,7 +3478,7 @@ out_unlock: unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, &cached_state); out: - inode_unlock(inode); + btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP); /* Let go of our reservation. */ if (ret != 0 && !(mode & FALLOC_FL_ZERO_RANGE)) btrfs_free_reserved_data_space(BTRFS_I(inode), data_reserved, @@ -3496,13 +3487,13 @@ out: return ret; } -static loff_t find_desired_extent(struct inode *inode, loff_t offset, +static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset, int whence) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct extent_map *em = NULL; struct extent_state *cached_state = NULL; - loff_t i_size = inode->i_size; + loff_t i_size = inode->vfs_inode.i_size; u64 lockstart; u64 lockend; u64 start; @@ -3525,11 +3516,10 @@ static loff_t find_desired_extent(struct inode *inode, loff_t offset, lockend--; len = lockend - lockstart + 1; - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state); + lock_extent_bits(&inode->io_tree, lockstart, lockend, &cached_state); while (start < i_size) { - em = btrfs_get_extent_fiemap(BTRFS_I(inode), start, len); + em = btrfs_get_extent_fiemap(inode, start, len); if (IS_ERR(em)) { ret = PTR_ERR(em); em = NULL; @@ -3551,7 +3541,7 @@ static loff_t find_desired_extent(struct inode *inode, loff_t offset, cond_resched(); } free_extent_map(em); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, + unlock_extent_cached(&inode->io_tree, lockstart, lockend, &cached_state); if (ret) { offset = ret; @@ -3575,7 +3565,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) case SEEK_DATA: case SEEK_HOLE: btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED); - offset = find_desired_extent(inode, offset, whence); + offset = find_desired_extent(BTRFS_I(inode), offset, whence); btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED); break; } diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 9988decd5717bd4ca73dcdd9d02fb6c1bda9903a..e54466fc101f775a46c04dca21c559ee00986b1c 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -11,6 +11,7 @@ #include <linux/ratelimit.h> #include <linux/error-injection.h> #include <linux/sched/mm.h> +#include "misc.h" #include "ctree.h" #include "free-space-cache.h" #include "transaction.h" @@ -2539,6 +2540,7 @@ out: static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group, u64 bytenr, u64 size, bool used) { + struct btrfs_fs_info *fs_info = block_group->fs_info; struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; u64 offset = bytenr - block_group->start; u64 to_free, to_unusable; @@ -2569,8 +2571,13 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group, } /* All the region is now unusable. Mark it as unused and reclaim */ - if (block_group->zone_unusable == block_group->length) + if (block_group->zone_unusable == block_group->length) { btrfs_mark_bg_unused(block_group); + } else if (block_group->zone_unusable >= + div_factor_fine(block_group->length, + fs_info->bg_reclaim_threshold)) { + btrfs_mark_bg_to_reclaim(block_group); + } return 0; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a520775949a0715d0e433d0545ecc5c4c201fbb8..b21d491b3adc8e672d3a033b9314c44f7621dcfd 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -102,6 +102,7 @@ static void __endio_write_update_ordered(struct btrfs_inode *inode, * BTRFS_ILOCK_SHARED - acquire a shared lock on the inode * BTRFS_ILOCK_TRY - try to acquire the lock, if fails on first attempt * return -EAGAIN + * BTRFS_ILOCK_MMAP - acquire a write lock on the i_mmap_lock */ int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags) { @@ -122,6 +123,8 @@ int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags) } inode_lock(inode); } + if (ilock_flags & BTRFS_ILOCK_MMAP) + down_write(&BTRFS_I(inode)->i_mmap_lock); return 0; } @@ -133,6 +136,8 @@ int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags) */ void btrfs_inode_unlock(struct inode *inode, unsigned int ilock_flags) { + if (ilock_flags & BTRFS_ILOCK_MMAP) + up_write(&BTRFS_I(inode)->i_mmap_lock); if (ilock_flags & BTRFS_ILOCK_SHARED) inode_unlock_shared(inode); else @@ -1516,7 +1521,7 @@ static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page, static noinline int run_delalloc_nocow(struct btrfs_inode *inode, struct page *locked_page, const u64 start, const u64 end, - int *page_started, int force, + int *page_started, unsigned long *nr_written) { struct btrfs_fs_info *fs_info = inode->root->fs_info; @@ -1530,6 +1535,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, u64 ino = btrfs_ino(inode); bool nocow = false; u64 disk_bytenr = 0; + const bool force = inode->flags & BTRFS_INODE_NODATACOW; path = btrfs_alloc_path(); if (!path) { @@ -1863,23 +1869,16 @@ error: return ret; } -static inline int need_force_cow(struct btrfs_inode *inode, u64 start, u64 end) +static bool should_nocow(struct btrfs_inode *inode, u64 start, u64 end) { - - if (!(inode->flags & BTRFS_INODE_NODATACOW) && - !(inode->flags & BTRFS_INODE_PREALLOC)) - return 0; - - /* - * @defrag_bytes is a hint value, no spinlock held here, - * if is not zero, it means the file is defragging. - * Force cow if given extent needs to be defragged. - */ - if (inode->defrag_bytes && - test_range_bit(&inode->io_tree, start, end, EXTENT_DEFRAG, 0, NULL)) - return 1; - - return 0; + if (inode->flags & (BTRFS_INODE_NODATACOW | BTRFS_INODE_PREALLOC)) { + if (inode->defrag_bytes && + test_range_bit(&inode->io_tree, start, end, EXTENT_DEFRAG, + 0, NULL)) + return false; + return true; + } + return false; } /* @@ -1891,17 +1890,12 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page struct writeback_control *wbc) { int ret; - int force_cow = need_force_cow(inode, start, end); const bool zoned = btrfs_is_zoned(inode->root->fs_info); - if (inode->flags & BTRFS_INODE_NODATACOW && !force_cow) { - ASSERT(!zoned); - ret = run_delalloc_nocow(inode, locked_page, start, end, - page_started, 1, nr_written); - } else if (inode->flags & BTRFS_INODE_PREALLOC && !force_cow) { + if (should_nocow(inode, start, end)) { ASSERT(!zoned); ret = run_delalloc_nocow(inode, locked_page, start, end, - page_started, 0, nr_written); + page_started, nr_written); } else if (!inode_can_compress(inode) || !inode_need_compress(inode, start, end)) { if (zoned) @@ -3151,10 +3145,9 @@ zeroit: * @bio_offset: offset to the beginning of the bio (in bytes) * @start: file offset of the range start * @end: file offset of the range end (inclusive) - * @mirror: mirror number */ int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset, - struct page *page, u64 start, u64 end, int mirror) + struct page *page, u64 start, u64 end) { struct inode *inode = page->mapping->host; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; @@ -3393,15 +3386,19 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) int is_dead_root = 0; /* - * this is an orphan in the tree root. Currently these + * This is an orphan in the tree root. Currently these * could come from 2 sources: - * a) a snapshot deletion in progress + * a) a root (snapshot/subvolume) deletion in progress * b) a free space cache inode - * We need to distinguish those two, as the snapshot - * orphan must not get deleted. - * find_dead_roots already ran before us, so if this - * is a snapshot deletion, we should find the root - * in the fs_roots radix tree. + * We need to distinguish those two, as the orphan item + * for a root must not get deleted before the deletion + * of the snapshot/subvolume's tree completes. + * + * btrfs_find_orphan_roots() ran before us, which has + * found all deleted roots and loaded them into + * fs_info->fs_roots_radix. So here we can find if an + * orphan item corresponds to a deleted root by looking + * up the root from that radix tree. */ spin_lock(&fs_info->fs_roots_radix_lock); @@ -4332,7 +4329,11 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) goto out_end_trans; } - btrfs_record_root_in_trans(trans, dest); + ret = btrfs_record_root_in_trans(trans, dest); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out_end_trans; + } memset(&dest->root_item.drop_progress, 0, sizeof(dest->root_item.drop_progress)); @@ -7026,7 +7027,7 @@ next: if (ret) goto out; } else { - map = kmap(page); + map = kmap_local_page(page); read_extent_buffer(leaf, map + pg_offset, ptr, copy_size); if (pg_offset + copy_size < PAGE_SIZE) { @@ -7034,7 +7035,7 @@ next: PAGE_SIZE - pg_offset - copy_size); } - kunmap(page); + kunmap_local(map); } flush_dcache_page(page); } @@ -7262,6 +7263,19 @@ static struct extent_map *btrfs_new_extent_direct(struct btrfs_inode *inode, return em; } +static bool btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr) +{ + struct btrfs_block_group *block_group; + bool readonly = false; + + block_group = btrfs_lookup_block_group(fs_info, bytenr); + if (!block_group || block_group->ro) + readonly = true; + if (block_group) + btrfs_put_block_group(block_group); + return readonly; +} + /* * Check if we can do nocow write into the range [@offset, @offset + @len) * @@ -8403,17 +8417,11 @@ again: * for the finish_ordered_io */ if (TestClearPagePrivate2(page)) { - struct btrfs_ordered_inode_tree *tree; - u64 new_len; - - tree = &inode->ordered_tree; - - spin_lock_irq(&tree->lock); + spin_lock_irq(&inode->ordered_tree.lock); set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags); - new_len = start - ordered->file_offset; - if (new_len < ordered->truncated_len) - ordered->truncated_len = new_len; - spin_unlock_irq(&tree->lock); + ordered->truncated_len = min(ordered->truncated_len, + start - ordered->file_offset); + spin_unlock_irq(&inode->ordered_tree.lock); if (btrfs_dec_test_ordered_pending(inode, &ordered, start, @@ -8539,6 +8547,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */ again: + down_read(&BTRFS_I(inode)->i_mmap_lock); lock_page(page); size = i_size_read(inode); @@ -8567,6 +8576,7 @@ again: unlock_extent_cached(io_tree, page_start, page_end, &cached_state); unlock_page(page); + up_read(&BTRFS_I(inode)->i_mmap_lock); btrfs_start_ordered_extent(ordered, 1); btrfs_put_ordered_extent(ordered); goto again; @@ -8619,11 +8629,10 @@ again: set_page_dirty(page); SetPageUptodate(page); - BTRFS_I(inode)->last_trans = fs_info->generation; - BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid; - BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->root->last_log_commit; + btrfs_set_inode_last_sub_trans(BTRFS_I(inode)); unlock_extent_cached(io_tree, page_start, page_end, &cached_state); + up_read(&BTRFS_I(inode)->i_mmap_lock); btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE); sb_end_pagefault(inode->i_sb); @@ -8632,6 +8641,7 @@ again: out_unlock: unlock_page(page); + up_read(&BTRFS_I(inode)->i_mmap_lock); out: btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE); btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved, page_start, @@ -8883,6 +8893,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) INIT_LIST_HEAD(&ei->delalloc_inodes); INIT_LIST_HEAD(&ei->delayed_iput); RB_CLEAR_NODE(&ei->rb_node); + init_rwsem(&ei->i_mmap_lock); return inode; } @@ -9101,8 +9112,11 @@ static int btrfs_rename_exchange(struct inode *old_dir, goto out_notrans; } - if (dest != root) - btrfs_record_root_in_trans(trans, dest); + if (dest != root) { + ret = btrfs_record_root_in_trans(trans, dest); + if (ret) + goto out_fail; + } /* * We need to find a free sequence number both in the source and @@ -9406,8 +9420,11 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_notrans; } - if (dest != root) - btrfs_record_root_in_trans(trans, dest); + if (dest != root) { + ret = btrfs_record_root_in_trans(trans, dest); + if (ret) + goto out_fail; + } ret = btrfs_set_inode_index(BTRFS_I(new_dir), &index); if (ret) @@ -9919,7 +9936,7 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( goto free_qgroup; } - ret = btrfs_replace_file_extents(&inode->vfs_inode, path, file_offset, + ret = btrfs_replace_file_extents(inode, path, file_offset, file_offset + len - 1, &extent_info, &trans); btrfs_free_path(path); @@ -10603,6 +10620,8 @@ static const struct inode_operations btrfs_dir_inode_operations = { .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, .tmpfile = btrfs_tmpfile, + .fileattr_get = btrfs_fileattr_get, + .fileattr_set = btrfs_fileattr_set, }; static const struct file_operations btrfs_dir_file_operations = { @@ -10656,6 +10675,8 @@ static const struct inode_operations btrfs_file_inode_operations = { .get_acl = btrfs_get_acl, .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, + .fileattr_get = btrfs_fileattr_get, + .fileattr_set = btrfs_fileattr_set, }; static const struct inode_operations btrfs_special_inode_operations = { .getattr = btrfs_getattr, diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index e8d53fea4c61a19fc29f05a6fe5b06fcf95b9a26..ee1dbabb5d3c42d35e4be395120729de5383a3d5 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -26,6 +26,7 @@ #include <linux/btrfs.h> #include <linux/uaccess.h> #include <linux/iversion.h> +#include <linux/fileattr.h> #include "ctree.h" #include "disk-io.h" #include "export.h" @@ -153,16 +154,6 @@ void btrfs_sync_inode_flags_to_i_flags(struct inode *inode) new_fl); } -static int btrfs_ioctl_getflags(struct file *file, void __user *arg) -{ - struct btrfs_inode *binode = BTRFS_I(file_inode(file)); - unsigned int flags = btrfs_inode_flags_to_fsflags(binode->flags); - - if (copy_to_user(arg, &flags, sizeof(flags))) - return -EFAULT; - return 0; -} - /* * Check if @flags are a supported and valid set of FS_*_FL flags and that * the old and new flags are not conflicting @@ -201,9 +192,22 @@ static int check_fsflags_compatible(struct btrfs_fs_info *fs_info, return 0; } -static int btrfs_ioctl_setflags(struct file *file, void __user *arg) +/* + * Set flags/xflags from the internal inode flags. The remaining items of + * fsxattr are zeroed. + */ +int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct btrfs_inode *binode = BTRFS_I(d_inode(dentry)); + + fileattr_fill_flags(fa, btrfs_inode_flags_to_fsflags(binode->flags)); + return 0; +} + +int btrfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { - struct inode *inode = file_inode(file); + struct inode *inode = d_inode(dentry); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_inode *binode = BTRFS_I(inode); struct btrfs_root *root = binode->root; @@ -213,34 +217,21 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) const char *comp = NULL; u32 binode_flags; - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EPERM; - if (btrfs_root_readonly(root)) return -EROFS; - if (copy_from_user(&fsflags, arg, sizeof(fsflags))) - return -EFAULT; - - ret = mnt_want_write_file(file); - if (ret) - return ret; + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; - inode_lock(inode); - fsflags = btrfs_mask_fsflags_for_type(inode, fsflags); + fsflags = btrfs_mask_fsflags_for_type(inode, fa->flags); old_fsflags = btrfs_inode_flags_to_fsflags(binode->flags); - - ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags); - if (ret) - goto out_unlock; - ret = check_fsflags(old_fsflags, fsflags); if (ret) - goto out_unlock; + return ret; ret = check_fsflags_compatible(fs_info, fsflags); if (ret) - goto out_unlock; + return ret; binode_flags = binode->flags; if (fsflags & FS_SYNC_FL) @@ -263,6 +254,14 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) binode_flags |= BTRFS_INODE_NOATIME; else binode_flags &= ~BTRFS_INODE_NOATIME; + + /* If coming from FS_IOC_FSSETXATTR then skip unconverted flags */ + if (!fa->flags_valid) { + /* 1 item for the inode */ + trans = btrfs_start_transaction(root, 1); + goto update_flags; + } + if (fsflags & FS_DIRSYNC_FL) binode_flags |= BTRFS_INODE_DIRSYNC; else @@ -303,10 +302,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) binode_flags |= BTRFS_INODE_NOCOMPRESS; } else if (fsflags & FS_COMPR_FL) { - if (IS_SWAPFILE(inode)) { - ret = -ETXTBSY; - goto out_unlock; - } + if (IS_SWAPFILE(inode)) + return -ETXTBSY; binode_flags |= BTRFS_INODE_COMPRESS; binode_flags &= ~BTRFS_INODE_NOCOMPRESS; @@ -323,10 +320,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) * 2 for properties */ trans = btrfs_start_transaction(root, 3); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_unlock; - } + if (IS_ERR(trans)) + return PTR_ERR(trans); if (comp) { ret = btrfs_set_prop(trans, inode, "btrfs.compression", comp, @@ -344,6 +339,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) } } +update_flags: binode->flags = binode_flags; btrfs_sync_inode_flags_to_i_flags(inode); inode_inc_iversion(inode); @@ -352,44 +348,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) out_end_trans: btrfs_end_transaction(trans); - out_unlock: - inode_unlock(inode); - mnt_drop_write_file(file); return ret; } -/* - * Translate btrfs internal inode flags to xflags as expected by the - * FS_IOC_FSGETXATT ioctl. Filter only the supported ones, unknown flags are - * silently dropped. - */ -static unsigned int btrfs_inode_flags_to_xflags(unsigned int flags) -{ - unsigned int xflags = 0; - - if (flags & BTRFS_INODE_APPEND) - xflags |= FS_XFLAG_APPEND; - if (flags & BTRFS_INODE_IMMUTABLE) - xflags |= FS_XFLAG_IMMUTABLE; - if (flags & BTRFS_INODE_NOATIME) - xflags |= FS_XFLAG_NOATIME; - if (flags & BTRFS_INODE_NODUMP) - xflags |= FS_XFLAG_NODUMP; - if (flags & BTRFS_INODE_SYNC) - xflags |= FS_XFLAG_SYNC; - - return xflags; -} - -/* Check if @flags are a supported and valid set of FS_XFLAGS_* flags */ -static int check_xflags(unsigned int flags) -{ - if (flags & ~(FS_XFLAG_APPEND | FS_XFLAG_IMMUTABLE | FS_XFLAG_NOATIME | - FS_XFLAG_NODUMP | FS_XFLAG_SYNC)) - return -EOPNOTSUPP; - return 0; -} - bool btrfs_exclop_start(struct btrfs_fs_info *fs_info, enum btrfs_exclusive_operation type) { @@ -402,111 +363,6 @@ void btrfs_exclop_finish(struct btrfs_fs_info *fs_info) sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation"); } -/* - * Set the xflags from the internal inode flags. The remaining items of fsxattr - * are zeroed. - */ -static int btrfs_ioctl_fsgetxattr(struct file *file, void __user *arg) -{ - struct btrfs_inode *binode = BTRFS_I(file_inode(file)); - struct fsxattr fa; - - simple_fill_fsxattr(&fa, btrfs_inode_flags_to_xflags(binode->flags)); - if (copy_to_user(arg, &fa, sizeof(fa))) - return -EFAULT; - - return 0; -} - -static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg) -{ - struct inode *inode = file_inode(file); - struct btrfs_inode *binode = BTRFS_I(inode); - struct btrfs_root *root = binode->root; - struct btrfs_trans_handle *trans; - struct fsxattr fa, old_fa; - unsigned old_flags; - unsigned old_i_flags; - int ret = 0; - - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EPERM; - - if (btrfs_root_readonly(root)) - return -EROFS; - - if (copy_from_user(&fa, arg, sizeof(fa))) - return -EFAULT; - - ret = check_xflags(fa.fsx_xflags); - if (ret) - return ret; - - if (fa.fsx_extsize != 0 || fa.fsx_projid != 0 || fa.fsx_cowextsize != 0) - return -EOPNOTSUPP; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - inode_lock(inode); - - old_flags = binode->flags; - old_i_flags = inode->i_flags; - - simple_fill_fsxattr(&old_fa, - btrfs_inode_flags_to_xflags(binode->flags)); - ret = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa); - if (ret) - goto out_unlock; - - if (fa.fsx_xflags & FS_XFLAG_SYNC) - binode->flags |= BTRFS_INODE_SYNC; - else - binode->flags &= ~BTRFS_INODE_SYNC; - if (fa.fsx_xflags & FS_XFLAG_IMMUTABLE) - binode->flags |= BTRFS_INODE_IMMUTABLE; - else - binode->flags &= ~BTRFS_INODE_IMMUTABLE; - if (fa.fsx_xflags & FS_XFLAG_APPEND) - binode->flags |= BTRFS_INODE_APPEND; - else - binode->flags &= ~BTRFS_INODE_APPEND; - if (fa.fsx_xflags & FS_XFLAG_NODUMP) - binode->flags |= BTRFS_INODE_NODUMP; - else - binode->flags &= ~BTRFS_INODE_NODUMP; - if (fa.fsx_xflags & FS_XFLAG_NOATIME) - binode->flags |= BTRFS_INODE_NOATIME; - else - binode->flags &= ~BTRFS_INODE_NOATIME; - - /* 1 item for the inode */ - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_unlock; - } - - btrfs_sync_inode_flags_to_i_flags(inode); - inode_inc_iversion(inode); - inode->i_ctime = current_time(inode); - ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); - - btrfs_end_transaction(trans); - -out_unlock: - if (ret) { - binode->flags = old_flags; - inode->i_flags = old_i_flags; - } - - inode_unlock(inode); - mnt_drop_write_file(file); - - return ret; -} - static int btrfs_ioctl_getversion(struct file *file, int __user *arg) { struct inode *inode = file_inode(file); @@ -697,8 +553,6 @@ static noinline int create_subvol(struct inode *dir, btrfs_set_root_otransid(root_item, trans->transid); btrfs_tree_unlock(leaf); - free_extent_buffer(leaf); - leaf = NULL; btrfs_set_root_dirid(root_item, BTRFS_FIRST_FREE_OBJECTID); @@ -707,8 +561,22 @@ static noinline int create_subvol(struct inode *dir, key.type = BTRFS_ROOT_ITEM_KEY; ret = btrfs_insert_root(trans, fs_info->tree_root, &key, root_item); - if (ret) + if (ret) { + /* + * Since we don't abort the transaction in this case, free the + * tree block so that we don't leak space and leave the + * filesystem in an inconsistent state (an extent item in the + * extent tree without backreferences). Also no need to have + * the tree block locked since it is not in any tree at this + * point, so no other task can find it and use it. + */ + btrfs_free_tree_block(trans, root, leaf, 0, 1); + free_extent_buffer(leaf); goto fail; + } + + free_extent_buffer(leaf); + leaf = NULL; key.offset = (u64)-1; new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev); @@ -721,7 +589,12 @@ static noinline int create_subvol(struct inode *dir, /* Freeing will be done in btrfs_put_root() of new_root */ anon_dev = 0; - btrfs_record_root_in_trans(trans, new_root); + ret = btrfs_record_root_in_trans(trans, new_root); + if (ret) { + btrfs_put_root(new_root); + btrfs_abort_transaction(trans, ret); + goto fail; + } ret = btrfs_create_subvol_root(trans, new_root, root); btrfs_put_root(new_root); @@ -1014,7 +887,7 @@ out_up_read: out_dput: dput(dentry); out_unlock: - inode_unlock(dir); + btrfs_inode_unlock(dir, 0); return error; } @@ -1612,7 +1485,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, ra_index += cluster; } - inode_lock(inode); + btrfs_inode_lock(inode, 0); if (IS_SWAPFILE(inode)) { ret = -ETXTBSY; } else { @@ -1621,13 +1494,13 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, ret = cluster_pages_for_defrag(inode, pages, i, cluster); } if (ret < 0) { - inode_unlock(inode); + btrfs_inode_unlock(inode, 0); goto out_ra; } defrag_count += ret; balance_dirty_pages_ratelimited(inode->i_mapping); - inode_unlock(inode); + btrfs_inode_unlock(inode, 0); if (newer_than) { if (newer_off == (u64)-1) @@ -1675,9 +1548,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, out_ra: if (do_compress) { - inode_lock(inode); + btrfs_inode_lock(inode, 0); BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE; - inode_unlock(inode); + btrfs_inode_unlock(inode, 0); } if (!file) kfree(ra); @@ -3112,9 +2985,9 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, goto out_dput; } - inode_lock(inode); + btrfs_inode_lock(inode, 0); err = btrfs_delete_subvolume(dir, dentry); - inode_unlock(inode); + btrfs_inode_unlock(inode, 0); if (!err) { fsnotify_rmdir(dir, dentry); d_delete(dentry); @@ -3123,7 +2996,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, out_dput: dput(dentry); out_unlock_dir: - inode_unlock(dir); + btrfs_inode_unlock(dir, 0); free_subvol_name: kfree(subvol_name_ptr); free_parent: @@ -4915,10 +4788,6 @@ long btrfs_ioctl(struct file *file, unsigned int void __user *argp = (void __user *)arg; switch (cmd) { - case FS_IOC_GETFLAGS: - return btrfs_ioctl_getflags(file, argp); - case FS_IOC_SETFLAGS: - return btrfs_ioctl_setflags(file, argp); case FS_IOC_GETVERSION: return btrfs_ioctl_getversion(file, argp); case FS_IOC_GETFSLABEL: @@ -5044,10 +4913,6 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_get_features(fs_info, argp); case BTRFS_IOC_SET_FEATURES: return btrfs_ioctl_set_features(file, argp); - case FS_IOC_FSGETXATTR: - return btrfs_ioctl_fsgetxattr(file, argp); - case FS_IOC_FSSETXATTR: - return btrfs_ioctl_fssetxattr(file, argp); case BTRFS_IOC_GET_SUBVOL_INFO: return btrfs_ioctl_get_subvol_info(file, argp); case BTRFS_IOC_GET_SUBVOL_ROOTREF: @@ -5067,12 +4932,6 @@ long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * handling is necessary. */ switch (cmd) { - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; case FS_IOC32_GETVERSION: cmd = FS_IOC_GETVERSION; break; diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c index 9084a950dc091c0bef974613108d8b5c3988b202..cd042c7567a4752f2103cb2d1d5a23fc578ff5b2 100644 --- a/fs/btrfs/lzo.c +++ b/fs/btrfs/lzo.c @@ -118,7 +118,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping, struct workspace *workspace = list_entry(ws, struct workspace, list); int ret = 0; char *data_in; - char *cpage_out; + char *cpage_out, *sizes_ptr; int nr_pages = 0; struct page *in_page = NULL; struct page *out_page = NULL; @@ -258,10 +258,9 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping, } /* store the size of all chunks of compressed data */ - cpage_out = kmap(pages[0]); - write_compress_length(cpage_out, tot_out); - - kunmap(pages[0]); + sizes_ptr = kmap_local_page(pages[0]); + write_compress_length(sizes_ptr, tot_out); + kunmap_local(sizes_ptr); ret = 0; *total_out = tot_out; diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 985a215584370efd95388dd41e8e150999d184bb..07b0b42187913ce4ae2263d33c6d43cbb1b461ae 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -107,17 +107,6 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 file_offset, return NULL; } -/* - * helper to check if a given offset is inside a given entry - */ -static int offset_in_entry(struct btrfs_ordered_extent *entry, u64 file_offset) -{ - if (file_offset < entry->file_offset || - entry->file_offset + entry->num_bytes <= file_offset) - return 0; - return 1; -} - static int range_overlaps(struct btrfs_ordered_extent *entry, u64 file_offset, u64 len) { @@ -142,7 +131,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, if (tree->last) { entry = rb_entry(tree->last, struct btrfs_ordered_extent, rb_node); - if (offset_in_entry(entry, file_offset)) + if (in_range(file_offset, entry->file_offset, entry->num_bytes)) return tree->last; } ret = __tree_search(root, file_offset, &prev); @@ -349,7 +338,7 @@ bool btrfs_dec_test_first_ordered_pending(struct btrfs_inode *inode, goto out; entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - if (!offset_in_entry(entry, *file_offset)) + if (!in_range(*file_offset, entry->file_offset, entry->num_bytes)) goto out; dec_start = max(*file_offset, entry->file_offset); @@ -428,7 +417,7 @@ bool btrfs_dec_test_ordered_pending(struct btrfs_inode *inode, entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); have_entry: - if (!offset_in_entry(entry, file_offset)) + if (!in_range(file_offset, entry->file_offset, entry->num_bytes)) goto out; if (io_size > entry->bytes_left) @@ -779,7 +768,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct btrfs_inode *ino goto out; entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - if (!offset_in_entry(entry, file_offset)) + if (!in_range(file_offset, entry->file_offset, entry->num_bytes)) entry = NULL; if (entry) refcount_inc(&entry->refs); diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 99e0853e4d3bcb0c8f18196ef0844684663ed26f..e60c07f364276deadc9cc554e2a5bed1d2b849f4 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -39,8 +39,8 @@ struct btrfs_ordered_sum { */ enum { /* - * Different types for direct io, one and only one of the 4 type can - * be set when creating ordered extent. + * Different types for ordered extents, one and only one of the 4 types + * need to be set when creating ordered extent. * * REGULAR: For regular non-compressed COW write * NOCOW: For NOCOW write into existing non-hole extent diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index f0b9ef13153adbbd42323e7ad7ebdaee971bec19..2319c923c9e6993019f88ad9fff8686690373232 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -23,6 +23,7 @@ #include "qgroup.h" #include "block-group.h" #include "sysfs.h" +#include "tree-mod-log.h" /* TODO XXX FIXME * - subvol delete -> delete when ref goes to 0? delete limits also? @@ -2639,12 +2640,12 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) record->data_rsv, BTRFS_QGROUP_RSV_DATA); /* - * Use SEQ_LAST as time_seq to do special search, which - * doesn't lock tree or delayed_refs and search current - * root. It's safe inside commit_transaction(). + * Use BTRFS_SEQ_LAST as time_seq to do special search, + * which doesn't lock tree or delayed_refs and search + * current root. It's safe inside commit_transaction(). */ ret = btrfs_find_all_roots(trans, fs_info, - record->bytenr, SEQ_LAST, &new_roots, false); + record->bytenr, BTRFS_SEQ_LAST, &new_roots, false); if (ret < 0) goto cleanup; if (qgroup_to_skip) { @@ -3543,37 +3544,19 @@ static int try_flush_qgroup(struct btrfs_root *root) { struct btrfs_trans_handle *trans; int ret; - bool can_commit = true; - /* - * If current process holds a transaction, we shouldn't flush, as we - * assume all space reservation happens before a transaction handle is - * held. - * - * But there are cases like btrfs_delayed_item_reserve_metadata() where - * we try to reserve space with one transction handle already held. - * In that case we can't commit transaction, but at least try to end it - * and hope the started data writes can free some space. - */ - if (current->journal_info && - current->journal_info != BTRFS_SEND_TRANS_STUB) - can_commit = false; + /* Can't hold an open transaction or we run the risk of deadlocking */ + ASSERT(current->journal_info == NULL || + current->journal_info == BTRFS_SEND_TRANS_STUB); + if (WARN_ON(current->journal_info && + current->journal_info != BTRFS_SEND_TRANS_STUB)) + return 0; /* * We don't want to run flush again and again, so if there is a running * one, we won't try to start a new flush, but exit directly. */ if (test_and_set_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state)) { - /* - * We are already holding a transaction, thus we can block other - * threads from flushing. So exit right now. This increases - * the chance of EDQUOT for heavy load and near limit cases. - * But we can argue that if we're already near limit, EDQUOT is - * unavoidable anyway. - */ - if (!can_commit) - return 0; - wait_event(root->qgroup_flush_wait, !test_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state)); return 0; @@ -3590,10 +3573,7 @@ static int try_flush_qgroup(struct btrfs_root *root) goto out; } - if (can_commit) - ret = btrfs_commit_transaction(trans); - else - ret = btrfs_end_transaction(trans); + ret = btrfs_commit_transaction(trans); out: clear_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state); wake_up(&root->qgroup_flush_wait); @@ -3646,8 +3626,7 @@ cleanup: qgroup_unreserve_range(inode, reserved, start, len); out: if (new_reserved) { - extent_changeset_release(reserved); - kfree(reserved); + extent_changeset_free(reserved); *reserved_ret = NULL; } return ret; diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 8c31357f08ed9eb91784db8e468b3b5f49037e34..244d499ebc72ca112ced4571e5ae5dc6a032169b 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -13,6 +13,7 @@ #include <linux/list_sort.h> #include <linux/raid/xor.h> #include <linux/mm.h> +#include "misc.h" #include "ctree.h" #include "disk-io.h" #include "volumes.h" @@ -1231,13 +1232,13 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio) /* first collect one page from each data stripe */ for (stripe = 0; stripe < nr_data; stripe++) { p = page_in_rbio(rbio, stripe, pagenr, 0); - pointers[stripe] = kmap(p); + pointers[stripe] = kmap_local_page(p); } /* then add the parity stripe */ p = rbio_pstripe_page(rbio, pagenr); SetPageUptodate(p); - pointers[stripe++] = kmap(p); + pointers[stripe++] = kmap_local_page(p); if (has_qstripe) { @@ -1247,7 +1248,7 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio) */ p = rbio_qstripe_page(rbio, pagenr); SetPageUptodate(p); - pointers[stripe++] = kmap(p); + pointers[stripe++] = kmap_local_page(p); raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE, pointers); @@ -1256,10 +1257,8 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio) copy_page(pointers[nr_data], pointers[0]); run_xor(pointers + 1, nr_data - 1, PAGE_SIZE); } - - - for (stripe = 0; stripe < rbio->real_stripes; stripe++) - kunmap(page_in_rbio(rbio, stripe, pagenr, 0)); + for (stripe = stripe - 1; stripe >= 0; stripe--) + kunmap_local(pointers[stripe]); } /* @@ -1634,7 +1633,8 @@ struct btrfs_plug_cb { /* * rbios on the plug list are sorted for easier merging. */ -static int plug_cmp(void *priv, struct list_head *a, struct list_head *b) +static int plug_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct btrfs_raid_bio *ra = container_of(a, struct btrfs_raid_bio, plug_list); @@ -1776,6 +1776,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) { int pagenr, stripe; void **pointers; + void **unmap_array; int faila = -1, failb = -1; struct page *page; blk_status_t err; @@ -1787,6 +1788,16 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) goto cleanup_io; } + /* + * Store copy of pointers that does not get reordered during + * reconstruction so that kunmap_local works. + */ + unmap_array = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS); + if (!unmap_array) { + err = BLK_STS_RESOURCE; + goto cleanup_pointers; + } + faila = rbio->faila; failb = rbio->failb; @@ -1808,8 +1819,11 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) !test_bit(pagenr, rbio->dbitmap)) continue; - /* setup our array of pointers with pages - * from each stripe + /* + * Setup our array of pointers with pages from each stripe + * + * NOTE: store a duplicate array of pointers to preserve the + * pointer order */ for (stripe = 0; stripe < rbio->real_stripes; stripe++) { /* @@ -1823,7 +1837,8 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) } else { page = rbio_stripe_page(rbio, stripe, pagenr); } - pointers[stripe] = kmap(page); + pointers[stripe] = kmap_local_page(page); + unmap_array[stripe] = pointers[stripe]; } /* all raid6 handling here */ @@ -1916,24 +1931,14 @@ pstripe: } } } - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - /* - * if we're rebuilding a read, we have to use - * pages from the bio list - */ - if ((rbio->operation == BTRFS_RBIO_READ_REBUILD || - rbio->operation == BTRFS_RBIO_REBUILD_MISSING) && - (stripe == faila || stripe == failb)) { - page = page_in_rbio(rbio, stripe, pagenr, 0); - } else { - page = rbio_stripe_page(rbio, stripe, pagenr); - } - kunmap(page); - } + for (stripe = rbio->real_stripes - 1; stripe >= 0; stripe--) + kunmap_local(unmap_array[stripe]); } err = BLK_STS_OK; cleanup: + kfree(unmap_array); +cleanup_pointers: kfree(pointers); cleanup_io: @@ -2358,13 +2363,13 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, goto cleanup; } SetPageUptodate(q_page); - pointers[rbio->real_stripes - 1] = kmap(q_page); + pointers[rbio->real_stripes - 1] = kmap_local_page(q_page); } atomic_set(&rbio->error, 0); /* Map the parity stripe just once */ - pointers[nr_data] = kmap(p_page); + pointers[nr_data] = kmap_local_page(p_page); for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) { struct page *p; @@ -2372,7 +2377,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, /* first collect one page from each data stripe */ for (stripe = 0; stripe < nr_data; stripe++) { p = page_in_rbio(rbio, stripe, pagenr, 0); - pointers[stripe] = kmap(p); + pointers[stripe] = kmap_local_page(p); } if (has_qstripe) { @@ -2387,22 +2392,22 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, /* Check scrubbing parity and repair it */ p = rbio_stripe_page(rbio, rbio->scrubp, pagenr); - parity = kmap(p); + parity = kmap_local_page(p); if (memcmp(parity, pointers[rbio->scrubp], PAGE_SIZE)) copy_page(parity, pointers[rbio->scrubp]); else /* Parity is right, needn't writeback */ bitmap_clear(rbio->dbitmap, pagenr, 1); - kunmap(p); + kunmap_local(parity); - for (stripe = 0; stripe < nr_data; stripe++) - kunmap(page_in_rbio(rbio, stripe, pagenr, 0)); + for (stripe = nr_data - 1; stripe >= 0; stripe--) + kunmap_local(pointers[stripe]); } - kunmap(p_page); + kunmap_local(pointers[nr_data]); __free_page(p_page); if (q_page) { - kunmap(q_page); + kunmap_local(pointers[rbio->real_stripes - 1]); __free_page(q_page); } diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 762881b777b3bed7175c4edec8e6f13095ade6a9..f4ec06b53aa039ff434ffb14161d190909c104da 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -478,9 +478,9 @@ process_slot: clone_info.file_offset = new_key.offset; clone_info.extent_buf = buf; clone_info.is_new_extent = false; - ret = btrfs_replace_file_extents(inode, path, drop_start, - new_key.offset + datal - 1, &clone_info, - &trans); + ret = btrfs_replace_file_extents(BTRFS_I(inode), path, + drop_start, new_key.offset + datal - 1, + &clone_info, &trans); if (ret) goto out; } else if (type == BTRFS_FILE_EXTENT_INLINE) { @@ -567,8 +567,8 @@ process_slot: set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); - ret = btrfs_replace_file_extents(inode, path, last_dest_end, - destoff + len - 1, NULL, &trans); + ret = btrfs_replace_file_extents(BTRFS_I(inode), path, + last_dest_end, destoff + len - 1, NULL, &trans); if (ret) goto out; @@ -604,6 +604,20 @@ static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1, lock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1); } +static void btrfs_double_mmap_lock(struct inode *inode1, struct inode *inode2) +{ + if (inode1 < inode2) + swap(inode1, inode2); + down_write(&BTRFS_I(inode1)->i_mmap_lock); + down_write_nested(&BTRFS_I(inode2)->i_mmap_lock, SINGLE_DEPTH_NESTING); +} + +static void btrfs_double_mmap_unlock(struct inode *inode1, struct inode *inode2) +{ + up_write(&BTRFS_I(inode1)->i_mmap_lock); + up_write(&BTRFS_I(inode2)->i_mmap_lock); +} + static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len, struct inode *dst, u64 dst_loff) { @@ -820,6 +834,16 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, len, remap_flags); } +static bool file_sync_write(const struct file *file) +{ + if (file->f_flags & (__O_SYNC | O_DSYNC)) + return true; + if (IS_SYNC(file_inode(file))) + return true; + + return false; +} + loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, struct file *dst_file, loff_t destoff, loff_t len, unsigned int remap_flags) @@ -832,10 +856,12 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) return -EINVAL; - if (same_inode) - inode_lock(src_inode); - else + if (same_inode) { + btrfs_inode_lock(src_inode, BTRFS_ILOCK_MMAP); + } else { lock_two_nondirectories(src_inode, dst_inode); + btrfs_double_mmap_lock(src_inode, dst_inode); + } ret = btrfs_remap_file_range_prep(src_file, off, dst_file, destoff, &len, remap_flags); @@ -848,10 +874,27 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, ret = btrfs_clone_files(dst_file, src_file, off, len, destoff); out_unlock: - if (same_inode) - inode_unlock(src_inode); - else + if (same_inode) { + btrfs_inode_unlock(src_inode, BTRFS_ILOCK_MMAP); + } else { + btrfs_double_mmap_unlock(src_inode, dst_inode); unlock_two_nondirectories(src_inode, dst_inode); + } + + /* + * If either the source or the destination file was opened with O_SYNC, + * O_DSYNC or has the S_SYNC attribute, fsync both the destination and + * source files/ranges, so that after a successful return (0) followed + * by a power failure results in the reflinked data to be readable from + * both files/ranges. + */ + if (ret == 0 && len > 0 && + (file_sync_write(src_file) || file_sync_write(dst_file))) { + ret = btrfs_sync_file(src_file, off, off + len - 1, 0); + if (ret == 0) + ret = btrfs_sync_file(dst_file, destoff, + destoff + len - 1, 0); + } return ret < 0 ? ret : len; } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 232d5da7b7bef334c5595f14b6d357d9a39da9b0..b70be2ac2e9e61a37865f058f9a368752fe4337c 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -638,9 +638,10 @@ static int __must_check __add_reloc_root(struct btrfs_root *root) node->bytenr, &node->rb_node); spin_unlock(&rc->reloc_root_tree.lock); if (rb_node) { - btrfs_panic(fs_info, -EEXIST, + btrfs_err(fs_info, "Duplicate root found for start=%llu while inserting into relocation tree", node->bytenr); + return -EEXIST; } list_add_tail(&root->root_list, &rc->reloc_roots); @@ -733,10 +734,12 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, struct extent_buffer *eb; struct btrfs_root_item *root_item; struct btrfs_key root_key; - int ret; + int ret = 0; + bool must_abort = false; root_item = kmalloc(sizeof(*root_item), GFP_NOFS); - BUG_ON(!root_item); + if (!root_item) + return ERR_PTR(-ENOMEM); root_key.objectid = BTRFS_TREE_RELOC_OBJECTID; root_key.type = BTRFS_ROOT_ITEM_KEY; @@ -748,7 +751,9 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, /* called by btrfs_init_reloc_root */ ret = btrfs_copy_root(trans, root, root->commit_root, &eb, BTRFS_TREE_RELOC_OBJECTID); - BUG_ON(ret); + if (ret) + goto fail; + /* * Set the last_snapshot field to the generation of the commit * root - like this ctree.c:btrfs_block_can_be_shared() behaves @@ -769,9 +774,16 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, */ ret = btrfs_copy_root(trans, root, root->node, &eb, BTRFS_TREE_RELOC_OBJECTID); - BUG_ON(ret); + if (ret) + goto fail; } + /* + * We have changed references at this point, we must abort the + * transaction if anything fails. + */ + must_abort = true; + memcpy(root_item, &root->root_item, sizeof(*root_item)); btrfs_set_root_bytenr(root_item, eb->start); btrfs_set_root_level(root_item, btrfs_header_level(eb)); @@ -789,14 +801,25 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, ret = btrfs_insert_root(trans, fs_info->tree_root, &root_key, root_item); - BUG_ON(ret); + if (ret) + goto fail; + kfree(root_item); reloc_root = btrfs_read_tree_root(fs_info->tree_root, &root_key); - BUG_ON(IS_ERR(reloc_root)); + if (IS_ERR(reloc_root)) { + ret = PTR_ERR(reloc_root); + goto abort; + } set_bit(BTRFS_ROOT_SHAREABLE, &reloc_root->state); reloc_root->last_trans = trans->transid; return reloc_root; +fail: + kfree(root_item); +abort: + if (must_abort) + btrfs_abort_transaction(trans, ret); + return ERR_PTR(ret); } /* @@ -856,9 +879,16 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, reloc_root = create_reloc_root(trans, root, root->root_key.objectid); if (clear_rsv) trans->block_rsv = rsv; + if (IS_ERR(reloc_root)) + return PTR_ERR(reloc_root); ret = __add_reloc_root(reloc_root); - BUG_ON(ret < 0); + ASSERT(ret != -EEXIST); + if (ret) { + /* Pairs with create_reloc_root */ + btrfs_put_root(reloc_root); + return ret; + } root->reloc_root = btrfs_grab_root(reloc_root); return 0; } @@ -875,7 +905,7 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, int ret; if (!have_reloc_root(root)) - goto out; + return 0; reloc_root = root->reloc_root; root_item = &reloc_root->root_item; @@ -908,10 +938,8 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, ret = btrfs_update_root(trans, fs_info->tree_root, &reloc_root->root_key, root_item); - BUG_ON(ret); btrfs_put_root(reloc_root); -out: - return 0; + return ret; } /* @@ -1185,8 +1213,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc, int ret; int slot; - BUG_ON(src->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); - BUG_ON(dest->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID); + ASSERT(src->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID); + ASSERT(dest->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); last_snapshot = btrfs_root_last_snapshot(&src->root_item); again: @@ -1205,7 +1233,11 @@ again: if (cow) { ret = btrfs_cow_block(trans, dest, eb, NULL, 0, &eb, BTRFS_NESTING_COW); - BUG_ON(ret); + if (ret) { + btrfs_tree_unlock(eb); + free_extent_buffer(eb); + return ret; + } } if (next_key) { @@ -1217,7 +1249,7 @@ again: parent = eb; while (1) { level = btrfs_header_level(parent); - BUG_ON(level < lowest_level); + ASSERT(level >= lowest_level); ret = btrfs_bin_search(parent, &key, &slot); if (ret < 0) @@ -1265,7 +1297,11 @@ again: ret = btrfs_cow_block(trans, dest, eb, parent, slot, &eb, BTRFS_NESTING_COW); - BUG_ON(ret); + if (ret) { + btrfs_tree_unlock(eb); + free_extent_buffer(eb); + break; + } } btrfs_tree_unlock(parent); @@ -1289,7 +1325,11 @@ again: path->lowest_level = level; ret = btrfs_search_slot(trans, src, &key, path, 0, 1); path->lowest_level = 0; - BUG_ON(ret); + if (ret) { + if (ret > 0) + ret = -ENOENT; + break; + } /* * Info qgroup to trace both subtrees. @@ -1329,27 +1369,39 @@ again: ref.skip_qgroup = true; btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid); ret = btrfs_inc_extent_ref(trans, &ref); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, ret); + break; + } btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr, blocksize, 0); ref.skip_qgroup = true; btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid); ret = btrfs_inc_extent_ref(trans, &ref); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, ret); + break; + } btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, new_bytenr, blocksize, path->nodes[level]->start); btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid); ref.skip_qgroup = true; ret = btrfs_free_extent(trans, &ref); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, ret); + break; + } btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, old_bytenr, blocksize, 0); btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid); ref.skip_qgroup = true; ret = btrfs_free_extent(trans, &ref); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, ret); + break; + } btrfs_unlock_up_safe(path, 0); @@ -1537,12 +1589,13 @@ static int find_next_key(struct btrfs_path *path, int level, /* * Insert current subvolume into reloc_control::dirty_subvol_roots */ -static void insert_dirty_subvol(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct btrfs_root *root) +static int insert_dirty_subvol(struct btrfs_trans_handle *trans, + struct reloc_control *rc, + struct btrfs_root *root) { struct btrfs_root *reloc_root = root->reloc_root; struct btrfs_root_item *reloc_root_item; + int ret; /* @root must be a subvolume tree root with a valid reloc tree */ ASSERT(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); @@ -1553,12 +1606,16 @@ static void insert_dirty_subvol(struct btrfs_trans_handle *trans, sizeof(reloc_root_item->drop_progress)); btrfs_set_root_drop_level(reloc_root_item, 0); btrfs_set_root_refs(reloc_root_item, 0); - btrfs_update_reloc_root(trans, root); + ret = btrfs_update_reloc_root(trans, root); + if (ret) + return ret; if (list_empty(&root->reloc_dirty_list)) { btrfs_grab_root(root); list_add_tail(&root->reloc_dirty_list, &rc->dirty_subvol_roots); } + + return 0; } static int clean_dirty_subvols(struct reloc_control *rc) @@ -1760,8 +1817,11 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, out: btrfs_free_path(path); - if (ret == 0) - insert_dirty_subvol(trans, rc, root); + if (ret == 0) { + ret = insert_dirty_subvol(trans, rc, root); + if (ret) + btrfs_abort_transaction(trans, ret); + } if (trans) btrfs_end_transaction_throttle(trans); @@ -1825,8 +1885,18 @@ again: root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset, false); - BUG_ON(IS_ERR(root)); - BUG_ON(root->reloc_root != reloc_root); + if (IS_ERR(root)) { + /* + * Even if we have an error we need this reloc root + * back on our list so we can clean up properly. + */ + list_add(&reloc_root->root_list, &reloc_roots); + btrfs_abort_transaction(trans, (int)PTR_ERR(root)); + if (!err) + err = PTR_ERR(root); + break; + } + ASSERT(root->reloc_root == reloc_root); /* * set reference count to 1, so btrfs_recover_relocation @@ -1834,16 +1904,27 @@ again: */ if (!err) btrfs_set_root_refs(&reloc_root->root_item, 1); - btrfs_update_reloc_root(trans, root); + ret = btrfs_update_reloc_root(trans, root); + /* + * Even if we have an error we need this reloc root back on our + * list so we can clean up properly. + */ list_add(&reloc_root->root_list, &reloc_roots); btrfs_put_root(root); + + if (ret) { + btrfs_abort_transaction(trans, ret); + if (!err) + err = ret; + break; + } } list_splice(&reloc_roots, &rc->reloc_roots); if (!err) - btrfs_commit_transaction(trans); + err = btrfs_commit_transaction(trans); else btrfs_end_transaction(trans); return err; @@ -1888,8 +1969,29 @@ again: root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset, false); if (btrfs_root_refs(&reloc_root->root_item) > 0) { - BUG_ON(IS_ERR(root)); - BUG_ON(root->reloc_root != reloc_root); + if (IS_ERR(root)) { + /* + * For recovery we read the fs roots on mount, + * and if we didn't find the root then we marked + * the reloc root as a garbage root. For normal + * relocation obviously the root should exist in + * memory. However there's no reason we can't + * handle the error properly here just in case. + */ + ASSERT(0); + ret = PTR_ERR(root); + goto out; + } + if (root->reloc_root != reloc_root) { + /* + * This is actually impossible without something + * going really wrong (like weird race condition + * or cosmic rays). + */ + ASSERT(0); + ret = -EINVAL; + goto out; + } ret = merge_reloc_root(rc, root); btrfs_put_root(root); if (ret) { @@ -1971,8 +2073,27 @@ static int record_reloc_root_in_trans(struct btrfs_trans_handle *trans, return 0; root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset, false); - BUG_ON(IS_ERR(root)); - BUG_ON(root->reloc_root != reloc_root); + + /* + * This should succeed, since we can't have a reloc root without having + * already looked up the actual root and created the reloc root for this + * root. + * + * However if there's some sort of corruption where we have a ref to a + * reloc root without a corresponding root this could return ENOENT. + */ + if (IS_ERR(root)) { + ASSERT(0); + return PTR_ERR(root); + } + if (root->reloc_root != reloc_root) { + ASSERT(0); + btrfs_err(fs_info, + "root %llu has two reloc roots associated with it", + reloc_root->root_key.offset); + btrfs_put_root(root); + return -EUCLEAN; + } ret = btrfs_record_root_in_trans(trans, root); btrfs_put_root(root); @@ -1988,26 +2109,77 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans, struct btrfs_backref_node *next; struct btrfs_root *root; int index = 0; + int ret; next = node; while (1) { cond_resched(); next = walk_up_backref(next, edges, &index); root = next->root; - BUG_ON(!root); - BUG_ON(!test_bit(BTRFS_ROOT_SHAREABLE, &root->state)); + + /* + * If there is no root, then our references for this block are + * incomplete, as we should be able to walk all the way up to a + * block that is owned by a root. + * + * This path is only for SHAREABLE roots, so if we come upon a + * non-SHAREABLE root then we have backrefs that resolve + * improperly. + * + * Both of these cases indicate file system corruption, or a bug + * in the backref walking code. + */ + if (!root) { + ASSERT(0); + btrfs_err(trans->fs_info, + "bytenr %llu doesn't have a backref path ending in a root", + node->bytenr); + return ERR_PTR(-EUCLEAN); + } + if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) { + ASSERT(0); + btrfs_err(trans->fs_info, + "bytenr %llu has multiple refs with one ending in a non-shareable root", + node->bytenr); + return ERR_PTR(-EUCLEAN); + } if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { - record_reloc_root_in_trans(trans, root); + ret = record_reloc_root_in_trans(trans, root); + if (ret) + return ERR_PTR(ret); break; } - btrfs_record_root_in_trans(trans, root); + ret = btrfs_record_root_in_trans(trans, root); + if (ret) + return ERR_PTR(ret); root = root->reloc_root; + /* + * We could have raced with another thread which failed, so + * root->reloc_root may not be set, return ENOENT in this case. + */ + if (!root) + return ERR_PTR(-ENOENT); + if (next->new_bytenr != root->node->start) { - BUG_ON(next->new_bytenr); - BUG_ON(!list_empty(&next->list)); + /* + * We just created the reloc root, so we shouldn't have + * ->new_bytenr set and this shouldn't be in the changed + * list. If it is then we have multiple roots pointing + * at the same bytenr which indicates corruption, or + * we've made a mistake in the backref walking code. + */ + ASSERT(next->new_bytenr == 0); + ASSERT(list_empty(&next->list)); + if (next->new_bytenr || !list_empty(&next->list)) { + btrfs_err(trans->fs_info, + "bytenr %llu possibly has multiple roots pointing at the same bytenr %llu", + node->bytenr, next->bytenr); + return ERR_PTR(-EUCLEAN); + } + next->new_bytenr = root->node->start; btrfs_put_root(next->root); next->root = btrfs_grab_root(root); @@ -2024,8 +2196,14 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans, if (!next || next->level <= node->level) break; } - if (!root) - return NULL; + if (!root) { + /* + * This can happen if there's fs corruption or if there's a bug + * in the backref lookup code. + */ + ASSERT(0); + return ERR_PTR(-ENOENT); + } next = node; /* setup backref node path for btrfs_reloc_cow_block */ @@ -2061,7 +2239,13 @@ struct btrfs_root *select_one_root(struct btrfs_backref_node *node) cond_resched(); next = walk_up_backref(next, edges, &index); root = next->root; - BUG_ON(!root); + + /* + * This can occur if we have incomplete extent refs leading all + * the way up a particular path, in this case return -EUCLEAN. + */ + if (!root) + return ERR_PTR(-EUCLEAN); /* No other choice for non-shareable tree */ if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) @@ -2181,7 +2365,11 @@ static int do_relocation(struct btrfs_trans_handle *trans, int slot; int ret = 0; - BUG_ON(lowest && node->eb); + /* + * If we are lowest then this is the first time we're processing this + * block, and thus shouldn't have an eb associated with it yet. + */ + ASSERT(!lowest || !node->eb); path->lowest_level = node->level + 1; rc->backref_cache.path[node->level] = node; @@ -2192,7 +2380,10 @@ static int do_relocation(struct btrfs_trans_handle *trans, upper = edge->node[UPPER]; root = select_reloc_root(trans, rc, upper, edges); - BUG_ON(!root); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto next; + } if (upper->eb && !upper->locked) { if (!lowest) { @@ -2266,7 +2457,11 @@ static int do_relocation(struct btrfs_trans_handle *trans, free_extent_buffer(eb); if (ret < 0) goto next; - BUG_ON(node->eb != eb); + /* + * We've just COWed this block, it should have updated + * the correct backref node entry. + */ + ASSERT(node->eb == eb); } else { btrfs_set_node_blockptr(upper->eb, slot, node->eb->start); @@ -2281,10 +2476,11 @@ static int do_relocation(struct btrfs_trans_handle *trans, btrfs_init_tree_ref(&ref, node->level, btrfs_header_owner(upper->eb)); ret = btrfs_inc_extent_ref(trans, &ref); - BUG_ON(ret); - - ret = btrfs_drop_subtree(trans, root, eb, upper->eb); - BUG_ON(ret); + if (!ret) + ret = btrfs_drop_subtree(trans, root, eb, + upper->eb); + if (ret) + btrfs_abort_transaction(trans, ret); } next: if (!upper->pending) @@ -2302,7 +2498,12 @@ next: } path->lowest_level = 0; - BUG_ON(ret == -ENOSPC); + + /* + * We should have allocated all of our space in the block rsv and thus + * shouldn't ENOSPC. + */ + ASSERT(ret != -ENOSPC); return ret; } @@ -2434,16 +2635,53 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans, BUG_ON(node->processed); root = select_one_root(node); - if (root == ERR_PTR(-ENOENT)) { - update_processed_blocks(rc, node); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + + /* See explanation in select_one_root for the -EUCLEAN case. */ + ASSERT(ret == -ENOENT); + if (ret == -ENOENT) { + ret = 0; + update_processed_blocks(rc, node); + } goto out; } if (root) { if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) { - BUG_ON(node->new_bytenr); - BUG_ON(!list_empty(&node->list)); - btrfs_record_root_in_trans(trans, root); + /* + * This block was the root block of a root, and this is + * the first time we're processing the block and thus it + * should not have had the ->new_bytenr modified and + * should have not been included on the changed list. + * + * However in the case of corruption we could have + * multiple refs pointing to the same block improperly, + * and thus we would trip over these checks. ASSERT() + * for the developer case, because it could indicate a + * bug in the backref code, however error out for a + * normal user in the case of corruption. + */ + ASSERT(node->new_bytenr == 0); + ASSERT(list_empty(&node->list)); + if (node->new_bytenr || !list_empty(&node->list)) { + btrfs_err(root->fs_info, + "bytenr %llu has improper references to it", + node->bytenr); + ret = -EUCLEAN; + goto out; + } + ret = btrfs_record_root_in_trans(trans, root); + if (ret) + goto out; + /* + * Another thread could have failed, need to check if we + * have reloc_root actually set. + */ + if (!root->reloc_root) { + ret = -ENOENT; + goto out; + } root = root->reloc_root; node->new_bytenr = root->node->start; btrfs_put_root(node->root); @@ -2578,7 +2816,7 @@ static noinline_for_stack int prealloc_file_extent_cluster( return btrfs_end_transaction(trans); } - inode_lock(&inode->vfs_inode); + btrfs_inode_lock(&inode->vfs_inode, 0); for (nr = 0; nr < cluster->nr; nr++) { start = cluster->boundary[nr] - offset; if (nr + 1 < cluster->nr) @@ -2596,7 +2834,7 @@ static noinline_for_stack int prealloc_file_extent_cluster( if (ret) break; } - inode_unlock(&inode->vfs_inode); + btrfs_inode_unlock(&inode->vfs_inode, 0); if (cur_offset < prealloc_end) btrfs_free_reserved_data_space_noquota(inode->root->fs_info, @@ -3220,20 +3458,6 @@ static void unset_reloc_control(struct reloc_control *rc) mutex_unlock(&fs_info->reloc_mutex); } -static int check_extent_flags(u64 flags) -{ - if ((flags & BTRFS_EXTENT_FLAG_DATA) && - (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) - return 1; - if (!(flags & BTRFS_EXTENT_FLAG_DATA) && - !(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) - return 1; - if ((flags & BTRFS_EXTENT_FLAG_DATA) && - (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) - return 1; - return 0; -} - static noinline_for_stack int prepare_to_relocate(struct reloc_control *rc) { @@ -3272,8 +3496,7 @@ int prepare_to_relocate(struct reloc_control *rc) */ return PTR_ERR(trans); } - btrfs_commit_transaction(trans); - return 0; + return btrfs_commit_transaction(trans); } static noinline_for_stack int relocate_block_group(struct reloc_control *rc) @@ -3285,7 +3508,6 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) struct btrfs_path *path; struct btrfs_extent_item *ei; u64 flags; - u32 item_size; int ret; int err = 0; int progress = 0; @@ -3334,19 +3556,7 @@ restart: ei = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_extent_item); - item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); - if (item_size >= sizeof(*ei)) { - flags = btrfs_extent_flags(path->nodes[0], ei); - ret = check_extent_flags(flags); - BUG_ON(ret); - } else if (unlikely(item_size == sizeof(struct btrfs_extent_item_v0))) { - err = -EINVAL; - btrfs_print_v0_err(trans->fs_info); - btrfs_abort_transaction(trans, err); - break; - } else { - BUG(); - } + flags = btrfs_extent_flags(path->nodes[0], ei); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { ret = add_tree_block(rc, &key, path, &blocks); @@ -3445,7 +3655,9 @@ restart: err = PTR_ERR(trans); goto out_free; } - btrfs_commit_transaction(trans); + ret = btrfs_commit_transaction(trans); + if (ret && !err) + err = ret; out_free: ret = clean_dirty_subvols(rc); if (ret < 0 && !err) @@ -3488,6 +3700,35 @@ out: return ret; } +static void delete_orphan_inode(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 objectid) +{ + struct btrfs_path *path; + struct btrfs_key key; + int ret = 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = objectid; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret) { + if (ret > 0) + ret = -ENOENT; + goto out; + } + ret = btrfs_del_item(trans, root, path); +out: + if (ret) + btrfs_abort_transaction(trans, ret); + btrfs_free_path(path); +} + /* * helper to create inode for data relocation. * the inode is in data relocation tree and its link count is 0 @@ -3514,10 +3755,16 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, goto out; err = __insert_orphan_inode(trans, root, objectid); - BUG_ON(err); + if (err) + goto out; inode = btrfs_iget(fs_info->sb, objectid, root); - BUG_ON(IS_ERR(inode)); + if (IS_ERR(inode)) { + delete_orphan_inode(trans, root, objectid); + err = PTR_ERR(inode); + inode = NULL; + goto out; + } BTRFS_I(inode)->index_cnt = group->start; err = btrfs_orphan_add(trans, BTRFS_I(inode)); @@ -3859,7 +4106,13 @@ int btrfs_recover_relocation(struct btrfs_root *root) } err = __add_reloc_root(reloc_root); - BUG_ON(err < 0); /* -ENOMEM or logic error */ + ASSERT(err != -EEXIST); + if (err) { + list_add_tail(&reloc_root->root_list, &reloc_roots); + btrfs_put_root(fs_root); + btrfs_end_transaction(trans); + goto out_unset; + } fs_root->reloc_root = btrfs_grab_root(reloc_root); btrfs_put_root(fs_root); } @@ -4074,7 +4327,12 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, return PTR_ERR(reloc_root); ret = __add_reloc_root(reloc_root); - BUG_ON(ret < 0); + ASSERT(ret != -EEXIST); + if (ret) { + /* Pairs with create_reloc_root */ + btrfs_put_root(reloc_root); + return ret; + } new_root->reloc_root = btrfs_grab_root(reloc_root); if (rc->create_reloc_tree) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 3d9088eab2fca3492762ae9f370e13d25baa9f3b..485cda3eb8d763e9b782fae56a1e8e38ad7a4487 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -206,9 +206,6 @@ struct full_stripe_lock { struct mutex mutex; }; -static void scrub_pending_bio_inc(struct scrub_ctx *sctx); -static void scrub_pending_bio_dec(struct scrub_ctx *sctx); -static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); static int scrub_setup_recheck_block(struct scrub_block *original_sblock, struct scrub_block *sblocks_for_recheck); static void scrub_recheck_block(struct btrfs_fs_info *fs_info, @@ -226,14 +223,11 @@ static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, static int scrub_checksum_data(struct scrub_block *sblock); static int scrub_checksum_tree_block(struct scrub_block *sblock); static int scrub_checksum_super(struct scrub_block *sblock); -static void scrub_block_get(struct scrub_block *sblock); static void scrub_block_put(struct scrub_block *sblock); static void scrub_page_get(struct scrub_page *spage); static void scrub_page_put(struct scrub_page *spage); static void scrub_parity_get(struct scrub_parity *sparity); static void scrub_parity_put(struct scrub_parity *sparity); -static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx, - struct scrub_page *spage); static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u32 len, u64 physical, struct btrfs_device *dev, u64 flags, u64 gen, int mirror_num, u8 *csum, @@ -251,8 +245,6 @@ static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, static void scrub_wr_submit(struct scrub_ctx *sctx); static void scrub_wr_bio_end_io(struct bio *bio); static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); -static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); -static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_put_ctx(struct scrub_ctx *sctx); static inline int scrub_is_page_on_raid56(struct scrub_page *spage) @@ -3682,8 +3674,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, spin_lock(&cache->lock); if (!cache->to_copy) { spin_unlock(&cache->lock); - ro_set = 0; - goto done; + btrfs_put_block_group(cache); + goto skip; } spin_unlock(&cache->lock); } @@ -3841,7 +3833,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, cache, found_key.offset)) ro_set = 0; -done: down_write(&dev_replace->rwsem); dev_replace->cursor_left = dev_replace->cursor_right; dev_replace->item_needs_writeback = 1; diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 8f323859156b52ac0edb2a1ee82c4d929a3859eb..55741adf90712c4127c9e82ee6f8fe2756dafd6a 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -6650,6 +6650,7 @@ static int full_send_tree(struct send_ctx *sctx) path = alloc_path_for_send(); if (!path) return -ENOMEM; + path->reada = READA_FORWARD_ALWAYS; key.objectid = BTRFS_FIRST_FREE_OBJECTID; key.type = BTRFS_INODE_ITEM_KEY; @@ -6688,15 +6689,35 @@ out: return ret; } -static int tree_move_down(struct btrfs_path *path, int *level) +static int tree_move_down(struct btrfs_path *path, int *level, u64 reada_min_gen) { struct extent_buffer *eb; + struct extent_buffer *parent = path->nodes[*level]; + int slot = path->slots[*level]; + const int nritems = btrfs_header_nritems(parent); + u64 reada_max; + u64 reada_done = 0; BUG_ON(*level == 0); - eb = btrfs_read_node_slot(path->nodes[*level], path->slots[*level]); + eb = btrfs_read_node_slot(parent, slot); if (IS_ERR(eb)) return PTR_ERR(eb); + /* + * Trigger readahead for the next leaves we will process, so that it is + * very likely that when we need them they are already in memory and we + * will not block on disk IO. For nodes we only do readahead for one, + * since the time window between processing nodes is typically larger. + */ + reada_max = (*level == 1 ? SZ_128K : eb->fs_info->nodesize); + + for (slot++; slot < nritems && reada_done < reada_max; slot++) { + if (btrfs_node_ptr_generation(parent, slot) > reada_min_gen) { + btrfs_readahead_node_child(parent, slot); + reada_done += eb->fs_info->nodesize; + } + } + path->nodes[*level - 1] = eb; path->slots[*level - 1] = 0; (*level)--; @@ -6736,14 +6757,15 @@ static int tree_move_next_or_upnext(struct btrfs_path *path, static int tree_advance(struct btrfs_path *path, int *level, int root_level, int allow_down, - struct btrfs_key *key) + struct btrfs_key *key, + u64 reada_min_gen) { int ret; if (*level == 0 || !allow_down) { ret = tree_move_next_or_upnext(path, level, root_level); } else { - ret = tree_move_down(path, level); + ret = tree_move_down(path, level, reada_min_gen); } if (ret >= 0) { if (*level == 0) @@ -6817,6 +6839,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, u64 right_blockptr; u64 left_gen; u64 right_gen; + u64 reada_min_gen; left_path = btrfs_alloc_path(); if (!left_path) { @@ -6896,6 +6919,14 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, ret = -ENOMEM; goto out; } + /* + * Our right root is the parent root, while the left root is the "send" + * root. We know that all new nodes/leaves in the left root must have + * a generation greater than the right root's generation, so we trigger + * readahead for those nodes and leaves of the left root, as we know we + * will need to read them at some point. + */ + reada_min_gen = btrfs_header_generation(right_root->commit_root); up_read(&fs_info->commit_root_sem); if (left_level == 0) @@ -6920,7 +6951,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, ret = tree_advance(left_path, &left_level, left_root_level, advance_left != ADVANCE_ONLY_NEXT, - &left_key); + &left_key, reada_min_gen); if (ret == -1) left_end_reached = ADVANCE; else if (ret < 0) @@ -6931,7 +6962,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, ret = tree_advance(right_path, &right_level, right_root_level, advance_right != ADVANCE_ONLY_NEXT, - &right_key); + &right_key, reada_min_gen); if (ret == -1) right_end_reached = ADVANCE; else if (ret < 0) diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 2da6177f4b0b85cec43fc0e4496106e9a3716a88..2dc674b7c3b14fd6ba306f7d16699c0659753b9f 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -861,8 +861,8 @@ static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info, * of heavy DIO or ordered reservations, preemptive flushing will just * waste time and cause us to slow down. */ - ordered = percpu_counter_sum_positive(&fs_info->ordered_bytes); - delalloc = percpu_counter_sum_positive(&fs_info->delalloc_bytes); + ordered = percpu_counter_read_positive(&fs_info->ordered_bytes); + delalloc = percpu_counter_read_positive(&fs_info->delalloc_bytes); if (ordered >= delalloc) used += fs_info->delayed_refs_rsv.reserved + fs_info->delayed_block_rsv.reserved; diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c index c69049e7daa9f6903b285a47522cd10ab243beee..2d19089ab625562f8ccc50aa4c91aa3d2e72ea48 100644 --- a/fs/btrfs/subpage.c +++ b/fs/btrfs/subpage.c @@ -4,6 +4,64 @@ #include "ctree.h" #include "subpage.h" +/* + * Subpage (sectorsize < PAGE_SIZE) support overview: + * + * Limitations: + * + * - Only support 64K page size for now + * This is to make metadata handling easier, as 64K page would ensure + * all nodesize would fit inside one page, thus we don't need to handle + * cases where a tree block crosses several pages. + * + * - Only metadata read-write for now + * The data read-write part is in development. + * + * - Metadata can't cross 64K page boundary + * btrfs-progs and kernel have done that for a while, thus only ancient + * filesystems could have such problem. For such case, do a graceful + * rejection. + * + * Special behavior: + * + * - Metadata + * Metadata read is fully supported. + * Meaning when reading one tree block will only trigger the read for the + * needed range, other unrelated range in the same page will not be touched. + * + * Metadata write support is partial. + * The writeback is still for the full page, but we will only submit + * the dirty extent buffers in the page. + * + * This means, if we have a metadata page like this: + * + * Page offset + * 0 16K 32K 48K 64K + * |/////////| |///////////| + * \- Tree block A \- Tree block B + * + * Even if we just want to writeback tree block A, we will also writeback + * tree block B if it's also dirty. + * + * This may cause extra metadata writeback which results more COW. + * + * Implementation: + * + * - Common + * Both metadata and data will use a new structure, btrfs_subpage, to + * record the status of each sector inside a page. This provides the extra + * granularity needed. + * + * - Metadata + * Since we have multiple tree blocks inside one page, we can't rely on page + * locking anymore, or we will have greatly reduced concurrency or even + * deadlocks (hold one tree lock while trying to lock another tree lock in + * the same page). + * + * Thus for metadata locking, subpage support relies on io_tree locking only. + * This means a slightly higher tree locking latency. + */ + int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info, struct page *page, enum btrfs_subpage_type type) { @@ -220,6 +278,82 @@ void btrfs_subpage_clear_error(const struct btrfs_fs_info *fs_info, spin_unlock_irqrestore(&subpage->lock, flags); } +void btrfs_subpage_set_dirty(const struct btrfs_fs_info *fs_info, + struct page *page, u64 start, u32 len) +{ + struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; + u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len); + unsigned long flags; + + spin_lock_irqsave(&subpage->lock, flags); + subpage->dirty_bitmap |= tmp; + spin_unlock_irqrestore(&subpage->lock, flags); + set_page_dirty(page); +} + +/* + * Extra clear_and_test function for subpage dirty bitmap. + * + * Return true if we're the last bits in the dirty_bitmap and clear the + * dirty_bitmap. + * Return false otherwise. + * + * NOTE: Callers should manually clear page dirty for true case, as we have + * extra handling for tree blocks. + */ +bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info, + struct page *page, u64 start, u32 len) +{ + struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; + u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len); + unsigned long flags; + bool last = false; + + spin_lock_irqsave(&subpage->lock, flags); + subpage->dirty_bitmap &= ~tmp; + if (subpage->dirty_bitmap == 0) + last = true; + spin_unlock_irqrestore(&subpage->lock, flags); + return last; +} + +void btrfs_subpage_clear_dirty(const struct btrfs_fs_info *fs_info, + struct page *page, u64 start, u32 len) +{ + bool last; + + last = btrfs_subpage_clear_and_test_dirty(fs_info, page, start, len); + if (last) + clear_page_dirty_for_io(page); +} + +void btrfs_subpage_set_writeback(const struct btrfs_fs_info *fs_info, + struct page *page, u64 start, u32 len) +{ + struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; + u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len); + unsigned long flags; + + spin_lock_irqsave(&subpage->lock, flags); + subpage->writeback_bitmap |= tmp; + set_page_writeback(page); + spin_unlock_irqrestore(&subpage->lock, flags); +} + +void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info, + struct page *page, u64 start, u32 len) +{ + struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; + u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len); + unsigned long flags; + + spin_lock_irqsave(&subpage->lock, flags); + subpage->writeback_bitmap &= ~tmp; + if (subpage->writeback_bitmap == 0) + end_page_writeback(page); + spin_unlock_irqrestore(&subpage->lock, flags); +} + /* * Unlike set/clear which is dependent on each page status, for test all bits * are tested in the same way. @@ -240,6 +374,8 @@ bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \ } IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(uptodate); IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(error); +IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(dirty); +IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(writeback); /* * Note that, in selftests (extent-io-tests), we can have empty fs_info passed @@ -276,3 +412,7 @@ bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info, \ IMPLEMENT_BTRFS_PAGE_OPS(uptodate, SetPageUptodate, ClearPageUptodate, PageUptodate); IMPLEMENT_BTRFS_PAGE_OPS(error, SetPageError, ClearPageError, PageError); +IMPLEMENT_BTRFS_PAGE_OPS(dirty, set_page_dirty, clear_page_dirty_for_io, + PageDirty); +IMPLEMENT_BTRFS_PAGE_OPS(writeback, set_page_writeback, end_page_writeback, + PageWriteback); diff --git a/fs/btrfs/subpage.h b/fs/btrfs/subpage.h index b86a4881475d138cceef0837738655fc8953a2f0..bfd626e955be338ae650097d3910d2b0dea55d54 100644 --- a/fs/btrfs/subpage.h +++ b/fs/btrfs/subpage.h @@ -20,6 +20,8 @@ struct btrfs_subpage { spinlock_t lock; u16 uptodate_bitmap; u16 error_bitmap; + u16 dirty_bitmap; + u16 writeback_bitmap; union { /* * Structures only used by metadata @@ -87,5 +89,10 @@ bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info, \ DECLARE_BTRFS_SUBPAGE_OPS(uptodate); DECLARE_BTRFS_SUBPAGE_OPS(error); +DECLARE_BTRFS_SUBPAGE_OPS(dirty); +DECLARE_BTRFS_SUBPAGE_OPS(writeback); + +bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info, + struct page *page, u64 start, u32 len); #endif diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f7a4ad86adee61610c686f7321d23f5676a983e3..4a396c1147f177c159909390806a153f22fe9f55 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -252,6 +252,32 @@ void __cold btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, . } #endif +#if BITS_PER_LONG == 32 +void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info) +{ + if (!test_and_set_bit(BTRFS_FS_32BIT_WARN, &fs_info->flags)) { + btrfs_warn(fs_info, "reaching 32bit limit for logical addresses"); + btrfs_warn(fs_info, +"due to page cache limit on 32bit systems, btrfs can't access metadata at or beyond %lluT", + BTRFS_32BIT_MAX_FILE_SIZE >> 40); + btrfs_warn(fs_info, + "please consider upgrading to 64bit kernel/hardware"); + } +} + +void __cold btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info) +{ + if (!test_and_set_bit(BTRFS_FS_32BIT_ERROR, &fs_info->flags)) { + btrfs_err(fs_info, "reached 32bit limit for logical addresses"); + btrfs_err(fs_info, +"due to page cache limit on 32bit systems, metadata beyond %lluT can't be accessed", + BTRFS_32BIT_MAX_FILE_SIZE >> 40); + btrfs_err(fs_info, + "please consider upgrading to 64bit kernel/hardware"); + } +} +#endif + /* * We only mark the transaction aborted and then set the file system read-only. * This will prevent new transactions from starting or trying to join this diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 6eb1c50fa98c1ac9c1c69cd01f121fdca77f1746..436ac7b4b3346f5ef3e38072f9934ca8a1d3551c 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -360,11 +360,26 @@ static ssize_t supported_rescue_options_show(struct kobject *kobj, BTRFS_ATTR(static_feature, supported_rescue_options, supported_rescue_options_show); +static ssize_t supported_sectorsizes_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + ssize_t ret = 0; + + /* Only sectorsize == PAGE_SIZE is now supported */ + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%lu\n", PAGE_SIZE); + + return ret; +} +BTRFS_ATTR(static_feature, supported_sectorsizes, + supported_sectorsizes_show); + static struct attribute *btrfs_supported_static_feature_attrs[] = { BTRFS_ATTR_PTR(static_feature, rmdir_subvol), BTRFS_ATTR_PTR(static_feature, supported_checksums), BTRFS_ATTR_PTR(static_feature, send_stream_version), BTRFS_ATTR_PTR(static_feature, supported_rescue_options), + BTRFS_ATTR_PTR(static_feature, supported_sectorsizes), NULL }; @@ -965,6 +980,40 @@ static ssize_t btrfs_read_policy_store(struct kobject *kobj, } BTRFS_ATTR_RW(, read_policy, btrfs_read_policy_show, btrfs_read_policy_store); +static ssize_t btrfs_bg_reclaim_threshold_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + ssize_t ret; + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", fs_info->bg_reclaim_threshold); + + return ret; +} + +static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + int thresh; + int ret; + + ret = kstrtoint(buf, 10, &thresh); + if (ret) + return ret; + + if (thresh <= 50 || thresh > 100) + return -EINVAL; + + fs_info->bg_reclaim_threshold = thresh; + + return len; +} +BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show, + btrfs_bg_reclaim_threshold_store); + static const struct attribute *btrfs_attrs[] = { BTRFS_ATTR_PTR(, label), BTRFS_ATTR_PTR(, nodesize), @@ -976,6 +1025,7 @@ static const struct attribute *btrfs_attrs[] = { BTRFS_ATTR_PTR(, exclusive_operation), BTRFS_ATTR_PTR(, generation), BTRFS_ATTR_PTR(, read_policy), + BTRFS_ATTR_PTR(, bg_reclaim_threshold), NULL, }; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index acff6bb49a97b324cce8666c61b1f19b9432e4ca..f75de9f6c0ada5a4600f93b55513f05c29567e47 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -260,6 +260,7 @@ static inline int extwriter_counter_read(struct btrfs_transaction *trans) void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans) { struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_transaction *cur_trans = trans->transaction; if (!trans->chunk_bytes_reserved) return; @@ -268,6 +269,8 @@ void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans) btrfs_block_rsv_release(fs_info, &fs_info->chunk_block_rsv, trans->chunk_bytes_reserved, NULL); + atomic64_sub(trans->chunk_bytes_reserved, &cur_trans->chunk_bytes_reserved); + cond_wake_up(&cur_trans->chunk_reserve_wait); trans->chunk_bytes_reserved = 0; } @@ -383,6 +386,8 @@ loop: spin_lock_init(&cur_trans->dropped_roots_lock); INIT_LIST_HEAD(&cur_trans->releasing_ebs); spin_lock_init(&cur_trans->releasing_ebs_lock); + atomic64_set(&cur_trans->chunk_bytes_reserved, 0); + init_waitqueue_head(&cur_trans->chunk_reserve_wait); list_add_tail(&cur_trans->list, &fs_info->trans_list); extent_io_tree_init(fs_info, &cur_trans->dirty_pages, IO_TREE_TRANS_DIRTY_PAGES, fs_info->btree_inode); @@ -408,6 +413,7 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans, int force) { struct btrfs_fs_info *fs_info = root->fs_info; + int ret = 0; if ((test_bit(BTRFS_ROOT_SHAREABLE, &root->state) && root->last_trans < trans->transid) || force) { @@ -456,11 +462,11 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans, * lock. smp_wmb() makes sure that all the writes above are * done before we pop in the zero below */ - btrfs_init_reloc_root(trans, root); + ret = btrfs_init_reloc_root(trans, root); smp_mb__before_atomic(); clear_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state); } - return 0; + return ret; } @@ -487,6 +493,7 @@ int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, struct btrfs_root *root) { struct btrfs_fs_info *fs_info = root->fs_info; + int ret; if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) return 0; @@ -501,10 +508,10 @@ int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, return 0; mutex_lock(&fs_info->reloc_mutex); - record_root_in_trans(trans, root, 0); + ret = record_root_in_trans(trans, root, 0); mutex_unlock(&fs_info->reloc_mutex); - return 0; + return ret; } static inline int is_transaction_blocked(struct btrfs_transaction *trans) @@ -741,7 +748,16 @@ got_it: * Thus it need to be called after current->journal_info initialized, * or we can deadlock. */ - btrfs_record_root_in_trans(h, root); + ret = btrfs_record_root_in_trans(h, root); + if (ret) { + /* + * The transaction handle is fully initialized and linked with + * other structures so it needs to be ended in case of errors, + * not just freed. + */ + btrfs_end_transaction(h); + return ERR_PTR(ret); + } return h; @@ -1347,7 +1363,9 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans) spin_unlock(&fs_info->fs_roots_radix_lock); btrfs_free_log(trans, root); - btrfs_update_reloc_root(trans, root); + ret2 = btrfs_update_reloc_root(trans, root); + if (ret2) + return ret2; /* see comments in should_cow_block() */ clear_bit(BTRFS_ROOT_FORCE_COW, &root->state); @@ -1440,7 +1458,9 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, * recorded root will never be updated again, causing an outdated root * item. */ - record_root_in_trans(trans, src, 1); + ret = record_root_in_trans(trans, src, 1); + if (ret) + return ret; /* * btrfs_qgroup_inherit relies on a consistent view of the usage for the @@ -1509,7 +1529,7 @@ out: * insert_dir_item() */ if (!ret) - record_root_in_trans(trans, parent, 1); + ret = record_root_in_trans(trans, parent, 1); return ret; } @@ -1586,8 +1606,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, dentry = pending->dentry; parent_inode = pending->dir; parent_root = BTRFS_I(parent_inode)->root; - record_root_in_trans(trans, parent_root, 0); - + ret = record_root_in_trans(trans, parent_root, 0); + if (ret) + goto fail; cur_time = current_time(parent_inode); /* @@ -1623,7 +1644,11 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, goto fail; } - record_root_in_trans(trans, root, 0); + ret = record_root_in_trans(trans, root, 0); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto fail; + } btrfs_set_root_last_snapshot(&root->root_item, trans->transid); memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); btrfs_check_and_init_root_item(new_root_item); @@ -1961,7 +1986,6 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, int err) */ BUG_ON(list_empty(&cur_trans->list)); - list_del_init(&cur_trans->list); if (cur_trans == fs_info->running_transaction) { cur_trans->state = TRANS_STATE_COMMIT_DOING; spin_unlock(&fs_info->trans_lock); @@ -1970,6 +1994,17 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, int err) spin_lock(&fs_info->trans_lock); } + + /* + * Now that we know no one else is still using the transaction we can + * remove the transaction from the list of transactions. This avoids + * the transaction kthread from cleaning up the transaction while some + * other task is still using it, which could result in a use-after-free + * on things like log trees, as it forces the transaction kthread to + * wait for this transaction to be cleaned up by us. + */ + list_del_init(&cur_trans->list); + spin_unlock(&fs_info->trans_lock); btrfs_cleanup_one_transaction(trans->transaction, fs_info); diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 6335716e513ff81743274ca7df78c07951667135..364cfbb4c5c596c71dc2f02f838590a9edabcc44 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -96,6 +96,13 @@ struct btrfs_transaction { spinlock_t releasing_ebs_lock; struct list_head releasing_ebs; + + /* + * The number of bytes currently reserved, by all transaction handles + * attached to this transaction, for metadata extents of the chunk tree. + */ + atomic64_t chunk_bytes_reserved; + wait_queue_head_t chunk_reserve_wait; }; #define __TRANS_FREEZABLE (1U << 0) @@ -175,7 +182,7 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans, spin_lock(&inode->lock); inode->last_trans = trans->transaction->transid; inode->last_sub_trans = inode->root->log_transid; - inode->last_log_commit = inode->root->last_log_commit; + inode->last_log_commit = inode->last_sub_trans - 1; spin_unlock(&inode->lock); } diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index f4ade821307d7abb6f8239871b89a83c592321ac..a8b2e0d2c02576cf0a69b19c7b819b12f28bcfa8 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -1290,6 +1290,11 @@ static int check_extent_item(struct extent_buffer *leaf, key->offset, fs_info->sectorsize); return -EUCLEAN; } + if (unlikely(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { + extent_err(leaf, slot, + "invalid extent flag, data has full backref set"); + return -EUCLEAN; + } } ptr = (unsigned long)(struct btrfs_extent_item *)(ei + 1); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 92a3686277918a67e22cdda63575344138830f30..f67721d82e5d220e8f5e322378cd60c977e610ad 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3165,20 +3165,22 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, */ mutex_unlock(&root->log_mutex); - btrfs_init_log_ctx(&root_log_ctx, NULL); - - mutex_lock(&log_root_tree->log_mutex); - if (btrfs_is_zoned(fs_info)) { + mutex_lock(&fs_info->tree_root->log_mutex); if (!log_root_tree->node) { ret = btrfs_alloc_log_tree_node(trans, log_root_tree); if (ret) { - mutex_unlock(&log_root_tree->log_mutex); + mutex_unlock(&fs_info->tree_log_mutex); goto out; } } + mutex_unlock(&fs_info->tree_root->log_mutex); } + btrfs_init_log_ctx(&root_log_ctx, NULL); + + mutex_lock(&log_root_tree->log_mutex); + index2 = log_root_tree->log_transid % 2; list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); root_log_ctx.log_transid = log_root_tree->log_transid; @@ -4136,7 +4138,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, return ret; } -static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) +static int extent_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct extent_map *em1, *em2; @@ -6278,8 +6281,13 @@ again: } wc.replay_dest->log_root = log; - btrfs_record_root_in_trans(trans, wc.replay_dest); - ret = walk_log_tree(trans, log, &wc); + ret = btrfs_record_root_in_trans(trans, wc.replay_dest); + if (ret) + /* The loop needs to continue due to the root refs */ + btrfs_handle_fs_error(fs_info, ret, + "failed to record the log root in transaction"); + else + ret = walk_log_tree(trans, log, &wc); if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) { ret = fixup_inode_link_counts(trans, wc.replay_dest, diff --git a/fs/btrfs/tree-mod-log.c b/fs/btrfs/tree-mod-log.c new file mode 100644 index 0000000000000000000000000000000000000000..8a3a14686d3e7e09d41cde0390c3f8fa090a8f55 --- /dev/null +++ b/fs/btrfs/tree-mod-log.c @@ -0,0 +1,929 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "tree-mod-log.h" +#include "disk-io.h" + +struct tree_mod_root { + u64 logical; + u8 level; +}; + +struct tree_mod_elem { + struct rb_node node; + u64 logical; + u64 seq; + enum btrfs_mod_log_op op; + + /* + * This is used for BTRFS_MOD_LOG_KEY_* and BTRFS_MOD_LOG_MOVE_KEYS + * operations. + */ + int slot; + + /* This is used for BTRFS_MOD_LOG_KEY* and BTRFS_MOD_LOG_ROOT_REPLACE. */ + u64 generation; + + /* Those are used for op == BTRFS_MOD_LOG_KEY_{REPLACE,REMOVE}. */ + struct btrfs_disk_key key; + u64 blockptr; + + /* This is used for op == BTRFS_MOD_LOG_MOVE_KEYS. */ + struct { + int dst_slot; + int nr_items; + } move; + + /* This is used for op == BTRFS_MOD_LOG_ROOT_REPLACE. */ + struct tree_mod_root old_root; +}; + +/* + * Pull a new tree mod seq number for our operation. + */ +static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) +{ + return atomic64_inc_return(&fs_info->tree_mod_seq); +} + +/* + * This adds a new blocker to the tree mod log's blocker list if the @elem + * passed does not already have a sequence number set. So when a caller expects + * to record tree modifications, it should ensure to set elem->seq to zero + * before calling btrfs_get_tree_mod_seq. + * Returns a fresh, unused tree log modification sequence number, even if no new + * blocker was added. + */ +u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, + struct btrfs_seq_list *elem) +{ + write_lock(&fs_info->tree_mod_log_lock); + if (!elem->seq) { + elem->seq = btrfs_inc_tree_mod_seq(fs_info); + list_add_tail(&elem->list, &fs_info->tree_mod_seq_list); + set_bit(BTRFS_FS_TREE_MOD_LOG_USERS, &fs_info->flags); + } + write_unlock(&fs_info->tree_mod_log_lock); + + return elem->seq; +} + +void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, + struct btrfs_seq_list *elem) +{ + struct rb_root *tm_root; + struct rb_node *node; + struct rb_node *next; + struct tree_mod_elem *tm; + u64 min_seq = BTRFS_SEQ_LAST; + u64 seq_putting = elem->seq; + + if (!seq_putting) + return; + + write_lock(&fs_info->tree_mod_log_lock); + list_del(&elem->list); + elem->seq = 0; + + if (list_empty(&fs_info->tree_mod_seq_list)) { + clear_bit(BTRFS_FS_TREE_MOD_LOG_USERS, &fs_info->flags); + } else { + struct btrfs_seq_list *first; + + first = list_first_entry(&fs_info->tree_mod_seq_list, + struct btrfs_seq_list, list); + if (seq_putting > first->seq) { + /* + * Blocker with lower sequence number exists, we cannot + * remove anything from the log. + */ + write_unlock(&fs_info->tree_mod_log_lock); + return; + } + min_seq = first->seq; + } + + /* + * Anything that's lower than the lowest existing (read: blocked) + * sequence number can be removed from the tree. + */ + tm_root = &fs_info->tree_mod_log; + for (node = rb_first(tm_root); node; node = next) { + next = rb_next(node); + tm = rb_entry(node, struct tree_mod_elem, node); + if (tm->seq >= min_seq) + continue; + rb_erase(node, tm_root); + kfree(tm); + } + write_unlock(&fs_info->tree_mod_log_lock); +} + +/* + * Key order of the log: + * node/leaf start address -> sequence + * + * The 'start address' is the logical address of the *new* root node for root + * replace operations, or the logical address of the affected block for all + * other operations. + */ +static noinline int tree_mod_log_insert(struct btrfs_fs_info *fs_info, + struct tree_mod_elem *tm) +{ + struct rb_root *tm_root; + struct rb_node **new; + struct rb_node *parent = NULL; + struct tree_mod_elem *cur; + + lockdep_assert_held_write(&fs_info->tree_mod_log_lock); + + tm->seq = btrfs_inc_tree_mod_seq(fs_info); + + tm_root = &fs_info->tree_mod_log; + new = &tm_root->rb_node; + while (*new) { + cur = rb_entry(*new, struct tree_mod_elem, node); + parent = *new; + if (cur->logical < tm->logical) + new = &((*new)->rb_left); + else if (cur->logical > tm->logical) + new = &((*new)->rb_right); + else if (cur->seq < tm->seq) + new = &((*new)->rb_left); + else if (cur->seq > tm->seq) + new = &((*new)->rb_right); + else + return -EEXIST; + } + + rb_link_node(&tm->node, parent, new); + rb_insert_color(&tm->node, tm_root); + return 0; +} + +/* + * Determines if logging can be omitted. Returns true if it can. Otherwise, it + * returns false with the tree_mod_log_lock acquired. The caller must hold + * this until all tree mod log insertions are recorded in the rb tree and then + * write unlock fs_info::tree_mod_log_lock. + */ +static inline bool tree_mod_dont_log(struct btrfs_fs_info *fs_info, + struct extent_buffer *eb) +{ + if (!test_bit(BTRFS_FS_TREE_MOD_LOG_USERS, &fs_info->flags)) + return true; + if (eb && btrfs_header_level(eb) == 0) + return true; + + write_lock(&fs_info->tree_mod_log_lock); + if (list_empty(&(fs_info)->tree_mod_seq_list)) { + write_unlock(&fs_info->tree_mod_log_lock); + return true; + } + + return false; +} + +/* Similar to tree_mod_dont_log, but doesn't acquire any locks. */ +static inline bool tree_mod_need_log(const struct btrfs_fs_info *fs_info, + struct extent_buffer *eb) +{ + if (!test_bit(BTRFS_FS_TREE_MOD_LOG_USERS, &fs_info->flags)) + return false; + if (eb && btrfs_header_level(eb) == 0) + return false; + + return true; +} + +static struct tree_mod_elem *alloc_tree_mod_elem(struct extent_buffer *eb, + int slot, + enum btrfs_mod_log_op op, + gfp_t flags) +{ + struct tree_mod_elem *tm; + + tm = kzalloc(sizeof(*tm), flags); + if (!tm) + return NULL; + + tm->logical = eb->start; + if (op != BTRFS_MOD_LOG_KEY_ADD) { + btrfs_node_key(eb, &tm->key, slot); + tm->blockptr = btrfs_node_blockptr(eb, slot); + } + tm->op = op; + tm->slot = slot; + tm->generation = btrfs_node_ptr_generation(eb, slot); + RB_CLEAR_NODE(&tm->node); + + return tm; +} + +int btrfs_tree_mod_log_insert_key(struct extent_buffer *eb, int slot, + enum btrfs_mod_log_op op, gfp_t flags) +{ + struct tree_mod_elem *tm; + int ret; + + if (!tree_mod_need_log(eb->fs_info, eb)) + return 0; + + tm = alloc_tree_mod_elem(eb, slot, op, flags); + if (!tm) + return -ENOMEM; + + if (tree_mod_dont_log(eb->fs_info, eb)) { + kfree(tm); + return 0; + } + + ret = tree_mod_log_insert(eb->fs_info, tm); + write_unlock(&eb->fs_info->tree_mod_log_lock); + if (ret) + kfree(tm); + + return ret; +} + +int btrfs_tree_mod_log_insert_move(struct extent_buffer *eb, + int dst_slot, int src_slot, + int nr_items) +{ + struct tree_mod_elem *tm = NULL; + struct tree_mod_elem **tm_list = NULL; + int ret = 0; + int i; + bool locked = false; + + if (!tree_mod_need_log(eb->fs_info, eb)) + return 0; + + tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), GFP_NOFS); + if (!tm_list) + return -ENOMEM; + + tm = kzalloc(sizeof(*tm), GFP_NOFS); + if (!tm) { + ret = -ENOMEM; + goto free_tms; + } + + tm->logical = eb->start; + tm->slot = src_slot; + tm->move.dst_slot = dst_slot; + tm->move.nr_items = nr_items; + tm->op = BTRFS_MOD_LOG_MOVE_KEYS; + + for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { + tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot, + BTRFS_MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS); + if (!tm_list[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + + if (tree_mod_dont_log(eb->fs_info, eb)) + goto free_tms; + locked = true; + + /* + * When we override something during the move, we log these removals. + * This can only happen when we move towards the beginning of the + * buffer, i.e. dst_slot < src_slot. + */ + for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { + ret = tree_mod_log_insert(eb->fs_info, tm_list[i]); + if (ret) + goto free_tms; + } + + ret = tree_mod_log_insert(eb->fs_info, tm); + if (ret) + goto free_tms; + write_unlock(&eb->fs_info->tree_mod_log_lock); + kfree(tm_list); + + return 0; + +free_tms: + for (i = 0; i < nr_items; i++) { + if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) + rb_erase(&tm_list[i]->node, &eb->fs_info->tree_mod_log); + kfree(tm_list[i]); + } + if (locked) + write_unlock(&eb->fs_info->tree_mod_log_lock); + kfree(tm_list); + kfree(tm); + + return ret; +} + +static inline int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, + struct tree_mod_elem **tm_list, + int nritems) +{ + int i, j; + int ret; + + for (i = nritems - 1; i >= 0; i--) { + ret = tree_mod_log_insert(fs_info, tm_list[i]); + if (ret) { + for (j = nritems - 1; j > i; j--) + rb_erase(&tm_list[j]->node, + &fs_info->tree_mod_log); + return ret; + } + } + + return 0; +} + +int btrfs_tree_mod_log_insert_root(struct extent_buffer *old_root, + struct extent_buffer *new_root, + bool log_removal) +{ + struct btrfs_fs_info *fs_info = old_root->fs_info; + struct tree_mod_elem *tm = NULL; + struct tree_mod_elem **tm_list = NULL; + int nritems = 0; + int ret = 0; + int i; + + if (!tree_mod_need_log(fs_info, NULL)) + return 0; + + if (log_removal && btrfs_header_level(old_root) > 0) { + nritems = btrfs_header_nritems(old_root); + tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), + GFP_NOFS); + if (!tm_list) { + ret = -ENOMEM; + goto free_tms; + } + for (i = 0; i < nritems; i++) { + tm_list[i] = alloc_tree_mod_elem(old_root, i, + BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); + if (!tm_list[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + } + + tm = kzalloc(sizeof(*tm), GFP_NOFS); + if (!tm) { + ret = -ENOMEM; + goto free_tms; + } + + tm->logical = new_root->start; + tm->old_root.logical = old_root->start; + tm->old_root.level = btrfs_header_level(old_root); + tm->generation = btrfs_header_generation(old_root); + tm->op = BTRFS_MOD_LOG_ROOT_REPLACE; + + if (tree_mod_dont_log(fs_info, NULL)) + goto free_tms; + + if (tm_list) + ret = tree_mod_log_free_eb(fs_info, tm_list, nritems); + if (!ret) + ret = tree_mod_log_insert(fs_info, tm); + + write_unlock(&fs_info->tree_mod_log_lock); + if (ret) + goto free_tms; + kfree(tm_list); + + return ret; + +free_tms: + if (tm_list) { + for (i = 0; i < nritems; i++) + kfree(tm_list[i]); + kfree(tm_list); + } + kfree(tm); + + return ret; +} + +static struct tree_mod_elem *__tree_mod_log_search(struct btrfs_fs_info *fs_info, + u64 start, u64 min_seq, + bool smallest) +{ + struct rb_root *tm_root; + struct rb_node *node; + struct tree_mod_elem *cur = NULL; + struct tree_mod_elem *found = NULL; + + read_lock(&fs_info->tree_mod_log_lock); + tm_root = &fs_info->tree_mod_log; + node = tm_root->rb_node; + while (node) { + cur = rb_entry(node, struct tree_mod_elem, node); + if (cur->logical < start) { + node = node->rb_left; + } else if (cur->logical > start) { + node = node->rb_right; + } else if (cur->seq < min_seq) { + node = node->rb_left; + } else if (!smallest) { + /* We want the node with the highest seq */ + if (found) + BUG_ON(found->seq > cur->seq); + found = cur; + node = node->rb_left; + } else if (cur->seq > min_seq) { + /* We want the node with the smallest seq */ + if (found) + BUG_ON(found->seq < cur->seq); + found = cur; + node = node->rb_right; + } else { + found = cur; + break; + } + } + read_unlock(&fs_info->tree_mod_log_lock); + + return found; +} + +/* + * This returns the element from the log with the smallest time sequence + * value that's in the log (the oldest log item). Any element with a time + * sequence lower than min_seq will be ignored. + */ +static struct tree_mod_elem *tree_mod_log_search_oldest(struct btrfs_fs_info *fs_info, + u64 start, u64 min_seq) +{ + return __tree_mod_log_search(fs_info, start, min_seq, true); +} + +/* + * This returns the element from the log with the largest time sequence + * value that's in the log (the most recent log item). Any element with + * a time sequence lower than min_seq will be ignored. + */ +static struct tree_mod_elem *tree_mod_log_search(struct btrfs_fs_info *fs_info, + u64 start, u64 min_seq) +{ + return __tree_mod_log_search(fs_info, start, min_seq, false); +} + +int btrfs_tree_mod_log_eb_copy(struct extent_buffer *dst, + struct extent_buffer *src, + unsigned long dst_offset, + unsigned long src_offset, + int nr_items) +{ + struct btrfs_fs_info *fs_info = dst->fs_info; + int ret = 0; + struct tree_mod_elem **tm_list = NULL; + struct tree_mod_elem **tm_list_add, **tm_list_rem; + int i; + bool locked = false; + + if (!tree_mod_need_log(fs_info, NULL)) + return 0; + + if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) + return 0; + + tm_list = kcalloc(nr_items * 2, sizeof(struct tree_mod_elem *), + GFP_NOFS); + if (!tm_list) + return -ENOMEM; + + tm_list_add = tm_list; + tm_list_rem = tm_list + nr_items; + for (i = 0; i < nr_items; i++) { + tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset, + BTRFS_MOD_LOG_KEY_REMOVE, GFP_NOFS); + if (!tm_list_rem[i]) { + ret = -ENOMEM; + goto free_tms; + } + + tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset, + BTRFS_MOD_LOG_KEY_ADD, GFP_NOFS); + if (!tm_list_add[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + + if (tree_mod_dont_log(fs_info, NULL)) + goto free_tms; + locked = true; + + for (i = 0; i < nr_items; i++) { + ret = tree_mod_log_insert(fs_info, tm_list_rem[i]); + if (ret) + goto free_tms; + ret = tree_mod_log_insert(fs_info, tm_list_add[i]); + if (ret) + goto free_tms; + } + + write_unlock(&fs_info->tree_mod_log_lock); + kfree(tm_list); + + return 0; + +free_tms: + for (i = 0; i < nr_items * 2; i++) { + if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) + rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log); + kfree(tm_list[i]); + } + if (locked) + write_unlock(&fs_info->tree_mod_log_lock); + kfree(tm_list); + + return ret; +} + +int btrfs_tree_mod_log_free_eb(struct extent_buffer *eb) +{ + struct tree_mod_elem **tm_list = NULL; + int nritems = 0; + int i; + int ret = 0; + + if (!tree_mod_need_log(eb->fs_info, eb)) + return 0; + + nritems = btrfs_header_nritems(eb); + tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), GFP_NOFS); + if (!tm_list) + return -ENOMEM; + + for (i = 0; i < nritems; i++) { + tm_list[i] = alloc_tree_mod_elem(eb, i, + BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); + if (!tm_list[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + + if (tree_mod_dont_log(eb->fs_info, eb)) + goto free_tms; + + ret = tree_mod_log_free_eb(eb->fs_info, tm_list, nritems); + write_unlock(&eb->fs_info->tree_mod_log_lock); + if (ret) + goto free_tms; + kfree(tm_list); + + return 0; + +free_tms: + for (i = 0; i < nritems; i++) + kfree(tm_list[i]); + kfree(tm_list); + + return ret; +} + +/* + * Returns the logical address of the oldest predecessor of the given root. + * Entries older than time_seq are ignored. + */ +static struct tree_mod_elem *tree_mod_log_oldest_root(struct extent_buffer *eb_root, + u64 time_seq) +{ + struct tree_mod_elem *tm; + struct tree_mod_elem *found = NULL; + u64 root_logical = eb_root->start; + bool looped = false; + + if (!time_seq) + return NULL; + + /* + * The very last operation that's logged for a root is the replacement + * operation (if it is replaced at all). This has the logical address + * of the *new* root, making it the very first operation that's logged + * for this root. + */ + while (1) { + tm = tree_mod_log_search_oldest(eb_root->fs_info, root_logical, + time_seq); + if (!looped && !tm) + return NULL; + /* + * If there are no tree operation for the oldest root, we simply + * return it. This should only happen if that (old) root is at + * level 0. + */ + if (!tm) + break; + + /* + * If there's an operation that's not a root replacement, we + * found the oldest version of our root. Normally, we'll find a + * BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here. + */ + if (tm->op != BTRFS_MOD_LOG_ROOT_REPLACE) + break; + + found = tm; + root_logical = tm->old_root.logical; + looped = true; + } + + /* If there's no old root to return, return what we found instead */ + if (!found) + found = tm; + + return found; +} + + +/* + * tm is a pointer to the first operation to rewind within eb. Then, all + * previous operations will be rewound (until we reach something older than + * time_seq). + */ +static void tree_mod_log_rewind(struct btrfs_fs_info *fs_info, + struct extent_buffer *eb, + u64 time_seq, + struct tree_mod_elem *first_tm) +{ + u32 n; + struct rb_node *next; + struct tree_mod_elem *tm = first_tm; + unsigned long o_dst; + unsigned long o_src; + unsigned long p_size = sizeof(struct btrfs_key_ptr); + + n = btrfs_header_nritems(eb); + read_lock(&fs_info->tree_mod_log_lock); + while (tm && tm->seq >= time_seq) { + /* + * All the operations are recorded with the operator used for + * the modification. As we're going backwards, we do the + * opposite of each operation here. + */ + switch (tm->op) { + case BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING: + BUG_ON(tm->slot < n); + fallthrough; + case BTRFS_MOD_LOG_KEY_REMOVE_WHILE_MOVING: + case BTRFS_MOD_LOG_KEY_REMOVE: + btrfs_set_node_key(eb, &tm->key, tm->slot); + btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); + btrfs_set_node_ptr_generation(eb, tm->slot, + tm->generation); + n++; + break; + case BTRFS_MOD_LOG_KEY_REPLACE: + BUG_ON(tm->slot >= n); + btrfs_set_node_key(eb, &tm->key, tm->slot); + btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); + btrfs_set_node_ptr_generation(eb, tm->slot, + tm->generation); + break; + case BTRFS_MOD_LOG_KEY_ADD: + /* if a move operation is needed it's in the log */ + n--; + break; + case BTRFS_MOD_LOG_MOVE_KEYS: + o_dst = btrfs_node_key_ptr_offset(tm->slot); + o_src = btrfs_node_key_ptr_offset(tm->move.dst_slot); + memmove_extent_buffer(eb, o_dst, o_src, + tm->move.nr_items * p_size); + break; + case BTRFS_MOD_LOG_ROOT_REPLACE: + /* + * This operation is special. For roots, this must be + * handled explicitly before rewinding. + * For non-roots, this operation may exist if the node + * was a root: root A -> child B; then A gets empty and + * B is promoted to the new root. In the mod log, we'll + * have a root-replace operation for B, a tree block + * that is no root. We simply ignore that operation. + */ + break; + } + next = rb_next(&tm->node); + if (!next) + break; + tm = rb_entry(next, struct tree_mod_elem, node); + if (tm->logical != first_tm->logical) + break; + } + read_unlock(&fs_info->tree_mod_log_lock); + btrfs_set_header_nritems(eb, n); +} + +/* + * Called with eb read locked. If the buffer cannot be rewound, the same buffer + * is returned. If rewind operations happen, a fresh buffer is returned. The + * returned buffer is always read-locked. If the returned buffer is not the + * input buffer, the lock on the input buffer is released and the input buffer + * is freed (its refcount is decremented). + */ +struct extent_buffer *btrfs_tree_mod_log_rewind(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + struct extent_buffer *eb, + u64 time_seq) +{ + struct extent_buffer *eb_rewin; + struct tree_mod_elem *tm; + + if (!time_seq) + return eb; + + if (btrfs_header_level(eb) == 0) + return eb; + + tm = tree_mod_log_search(fs_info, eb->start, time_seq); + if (!tm) + return eb; + + if (tm->op == BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING) { + BUG_ON(tm->slot != 0); + eb_rewin = alloc_dummy_extent_buffer(fs_info, eb->start); + if (!eb_rewin) { + btrfs_tree_read_unlock(eb); + free_extent_buffer(eb); + return NULL; + } + btrfs_set_header_bytenr(eb_rewin, eb->start); + btrfs_set_header_backref_rev(eb_rewin, + btrfs_header_backref_rev(eb)); + btrfs_set_header_owner(eb_rewin, btrfs_header_owner(eb)); + btrfs_set_header_level(eb_rewin, btrfs_header_level(eb)); + } else { + eb_rewin = btrfs_clone_extent_buffer(eb); + if (!eb_rewin) { + btrfs_tree_read_unlock(eb); + free_extent_buffer(eb); + return NULL; + } + } + + btrfs_tree_read_unlock(eb); + free_extent_buffer(eb); + + btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb_rewin), + eb_rewin, btrfs_header_level(eb_rewin)); + btrfs_tree_read_lock(eb_rewin); + tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm); + WARN_ON(btrfs_header_nritems(eb_rewin) > + BTRFS_NODEPTRS_PER_BLOCK(fs_info)); + + return eb_rewin; +} + +/* + * Rewind the state of @root's root node to the given @time_seq value. + * If there are no changes, the current root->root_node is returned. If anything + * changed in between, there's a fresh buffer allocated on which the rewind + * operations are done. In any case, the returned buffer is read locked. + * Returns NULL on error (with no locks held). + */ +struct extent_buffer *btrfs_get_old_root(struct btrfs_root *root, u64 time_seq) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct tree_mod_elem *tm; + struct extent_buffer *eb = NULL; + struct extent_buffer *eb_root; + u64 eb_root_owner = 0; + struct extent_buffer *old; + struct tree_mod_root *old_root = NULL; + u64 old_generation = 0; + u64 logical; + int level; + + eb_root = btrfs_read_lock_root_node(root); + tm = tree_mod_log_oldest_root(eb_root, time_seq); + if (!tm) + return eb_root; + + if (tm->op == BTRFS_MOD_LOG_ROOT_REPLACE) { + old_root = &tm->old_root; + old_generation = tm->generation; + logical = old_root->logical; + level = old_root->level; + } else { + logical = eb_root->start; + level = btrfs_header_level(eb_root); + } + + tm = tree_mod_log_search(fs_info, logical, time_seq); + if (old_root && tm && tm->op != BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING) { + btrfs_tree_read_unlock(eb_root); + free_extent_buffer(eb_root); + old = read_tree_block(fs_info, logical, root->root_key.objectid, + 0, level, NULL); + if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) { + if (!IS_ERR(old)) + free_extent_buffer(old); + btrfs_warn(fs_info, + "failed to read tree block %llu from get_old_root", + logical); + } else { + struct tree_mod_elem *tm2; + + btrfs_tree_read_lock(old); + eb = btrfs_clone_extent_buffer(old); + /* + * After the lookup for the most recent tree mod operation + * above and before we locked and cloned the extent buffer + * 'old', a new tree mod log operation may have been added. + * So lookup for a more recent one to make sure the number + * of mod log operations we replay is consistent with the + * number of items we have in the cloned extent buffer, + * otherwise we can hit a BUG_ON when rewinding the extent + * buffer. + */ + tm2 = tree_mod_log_search(fs_info, logical, time_seq); + btrfs_tree_read_unlock(old); + free_extent_buffer(old); + ASSERT(tm2); + ASSERT(tm2 == tm || tm2->seq > tm->seq); + if (!tm2 || tm2->seq < tm->seq) { + free_extent_buffer(eb); + return NULL; + } + tm = tm2; + } + } else if (old_root) { + eb_root_owner = btrfs_header_owner(eb_root); + btrfs_tree_read_unlock(eb_root); + free_extent_buffer(eb_root); + eb = alloc_dummy_extent_buffer(fs_info, logical); + } else { + eb = btrfs_clone_extent_buffer(eb_root); + btrfs_tree_read_unlock(eb_root); + free_extent_buffer(eb_root); + } + + if (!eb) + return NULL; + if (old_root) { + btrfs_set_header_bytenr(eb, eb->start); + btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); + btrfs_set_header_owner(eb, eb_root_owner); + btrfs_set_header_level(eb, old_root->level); + btrfs_set_header_generation(eb, old_generation); + } + btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), eb, + btrfs_header_level(eb)); + btrfs_tree_read_lock(eb); + if (tm) + tree_mod_log_rewind(fs_info, eb, time_seq, tm); + else + WARN_ON(btrfs_header_level(eb) != 0); + WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(fs_info)); + + return eb; +} + +int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq) +{ + struct tree_mod_elem *tm; + int level; + struct extent_buffer *eb_root = btrfs_root_node(root); + + tm = tree_mod_log_oldest_root(eb_root, time_seq); + if (tm && tm->op == BTRFS_MOD_LOG_ROOT_REPLACE) + level = tm->old_root.level; + else + level = btrfs_header_level(eb_root); + + free_extent_buffer(eb_root); + + return level; +} + +/* + * Return the lowest sequence number in the tree modification log. + * + * Return the sequence number of the oldest tree modification log user, which + * corresponds to the lowest sequence number of all existing users. If there are + * no users it returns 0. + */ +u64 btrfs_tree_mod_log_lowest_seq(struct btrfs_fs_info *fs_info) +{ + u64 ret = 0; + + read_lock(&fs_info->tree_mod_log_lock); + if (!list_empty(&fs_info->tree_mod_seq_list)) { + struct btrfs_seq_list *elem; + + elem = list_first_entry(&fs_info->tree_mod_seq_list, + struct btrfs_seq_list, list); + ret = elem->seq; + } + read_unlock(&fs_info->tree_mod_log_lock); + + return ret; +} diff --git a/fs/btrfs/tree-mod-log.h b/fs/btrfs/tree-mod-log.h new file mode 100644 index 0000000000000000000000000000000000000000..12605d19621b6e5cabda66a2fe299f9c75f1daba --- /dev/null +++ b/fs/btrfs/tree-mod-log.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef BTRFS_TREE_MOD_LOG_H +#define BTRFS_TREE_MOD_LOG_H + +#include "ctree.h" + +/* Represents a tree mod log user. */ +struct btrfs_seq_list { + struct list_head list; + u64 seq; +}; + +#define BTRFS_SEQ_LIST_INIT(name) { .list = LIST_HEAD_INIT((name).list), .seq = 0 } +#define BTRFS_SEQ_LAST ((u64)-1) + +enum btrfs_mod_log_op { + BTRFS_MOD_LOG_KEY_REPLACE, + BTRFS_MOD_LOG_KEY_ADD, + BTRFS_MOD_LOG_KEY_REMOVE, + BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING, + BTRFS_MOD_LOG_KEY_REMOVE_WHILE_MOVING, + BTRFS_MOD_LOG_MOVE_KEYS, + BTRFS_MOD_LOG_ROOT_REPLACE, +}; + +u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, + struct btrfs_seq_list *elem); +void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, + struct btrfs_seq_list *elem); +int btrfs_tree_mod_log_insert_root(struct extent_buffer *old_root, + struct extent_buffer *new_root, + bool log_removal); +int btrfs_tree_mod_log_insert_key(struct extent_buffer *eb, int slot, + enum btrfs_mod_log_op op, gfp_t flags); +int btrfs_tree_mod_log_free_eb(struct extent_buffer *eb); +struct extent_buffer *btrfs_tree_mod_log_rewind(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + struct extent_buffer *eb, + u64 time_seq); +struct extent_buffer *btrfs_get_old_root(struct btrfs_root *root, u64 time_seq); +int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq); +int btrfs_tree_mod_log_eb_copy(struct extent_buffer *dst, + struct extent_buffer *src, + unsigned long dst_offset, + unsigned long src_offset, + int nr_items); +int btrfs_tree_mod_log_insert_move(struct extent_buffer *eb, + int dst_slot, int src_slot, + int nr_items); +u64 btrfs_tree_mod_log_lowest_seq(struct btrfs_fs_info *fs_info); + +#endif diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1c6810bbaf8b5445c74913af2f5cd23387be0e5c..9a1ead0c4a3113b24b0a7a658cf20cd84778e7af 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1224,7 +1224,8 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices, return 0; } -static int devid_cmp(void *priv, struct list_head *a, struct list_head *b) +static int devid_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct btrfs_device *dev1, *dev2; @@ -1458,8 +1459,8 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device, /* Given hole range was invalid (outside of device) */ if (ret == -ERANGE) { *hole_start += *hole_size; - *hole_size = 0; - return 1; + *hole_size = false; + return true; } *hole_start += zone_size; @@ -3098,11 +3099,12 @@ out: return ret; } -static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset) +int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset) { struct btrfs_root *root = fs_info->chunk_root; struct btrfs_trans_handle *trans; struct btrfs_block_group *block_group; + u64 length; int ret; /* @@ -3117,7 +3119,7 @@ static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset) * we release the path used to search the chunk/dev tree and before * the current task acquires this mutex and calls us. */ - lockdep_assert_held(&fs_info->delete_unused_bgs_mutex); + lockdep_assert_held(&fs_info->reclaim_bgs_lock); /* step one, relocate all the extents inside this chunk */ btrfs_scrub_pause(fs_info); @@ -3130,8 +3132,23 @@ static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset) if (!block_group) return -ENOENT; btrfs_discard_cancel_work(&fs_info->discard_ctl, block_group); + length = block_group->length; btrfs_put_block_group(block_group); + /* + * On a zoned file system, discard the whole block group, this will + * trigger a REQ_OP_ZONE_RESET operation on the device zone. If + * resetting the zone fails, don't treat it as a fatal problem from the + * filesystem's point of view. + */ + if (btrfs_is_zoned(fs_info)) { + ret = btrfs_discard_extent(fs_info, chunk_offset, length, NULL); + if (ret) + btrfs_info(fs_info, + "failed to reset zone %llu after relocation", + chunk_offset); + } + trans = btrfs_start_trans_remove_block_group(root->fs_info, chunk_offset); if (IS_ERR(trans)) { @@ -3172,10 +3189,10 @@ again: key.type = BTRFS_CHUNK_ITEM_KEY; while (1) { - mutex_lock(&fs_info->delete_unused_bgs_mutex); + mutex_lock(&fs_info->reclaim_bgs_lock); ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto error; } BUG_ON(ret == 0); /* Corruption */ @@ -3183,7 +3200,7 @@ again: ret = btrfs_previous_item(chunk_root, path, key.objectid, key.type); if (ret) - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); if (ret < 0) goto error; if (ret > 0) @@ -3204,7 +3221,7 @@ again: else BUG_ON(ret); } - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); if (found_key.offset == 0) break; @@ -3744,10 +3761,10 @@ again: goto error; } - mutex_lock(&fs_info->delete_unused_bgs_mutex); + mutex_lock(&fs_info->reclaim_bgs_lock); ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto error; } @@ -3761,7 +3778,7 @@ again: ret = btrfs_previous_item(chunk_root, path, 0, BTRFS_CHUNK_ITEM_KEY); if (ret) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); ret = 0; break; } @@ -3771,7 +3788,7 @@ again: btrfs_item_key_to_cpu(leaf, &found_key, slot); if (found_key.objectid != key.objectid) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); break; } @@ -3788,12 +3805,12 @@ again: btrfs_release_path(path); if (!ret) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto loop; } if (counting) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); spin_lock(&fs_info->balance_lock); bctl->stat.expected++; spin_unlock(&fs_info->balance_lock); @@ -3818,7 +3835,7 @@ again: count_meta < bctl->meta.limit_min) || ((chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) && count_sys < bctl->sys.limit_min)) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto loop; } @@ -3832,7 +3849,7 @@ again: ret = btrfs_may_alloc_data_chunk(fs_info, found_key.offset); if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto error; } else if (ret == 1) { chunk_reserved = 1; @@ -3840,7 +3857,7 @@ again: } ret = btrfs_relocate_chunk(fs_info, found_key.offset); - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); if (ret == -ENOSPC) { enospc_errors++; } else if (ret == -ETXTBSY) { @@ -4725,16 +4742,16 @@ again: key.type = BTRFS_DEV_EXTENT_KEY; do { - mutex_lock(&fs_info->delete_unused_bgs_mutex); + mutex_lock(&fs_info->reclaim_bgs_lock); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto done; } ret = btrfs_previous_item(root, path, 0, key.type); if (ret) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); if (ret < 0) goto done; ret = 0; @@ -4747,7 +4764,7 @@ again: btrfs_item_key_to_cpu(l, &key, path->slots[0]); if (key.objectid != device->devid) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_release_path(path); break; } @@ -4756,7 +4773,7 @@ again: length = btrfs_dev_extent_length(l, dev_extent); if (key.offset + length <= new_size) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_release_path(path); break; } @@ -4772,12 +4789,12 @@ again: */ ret = btrfs_may_alloc_data_chunk(fs_info, chunk_offset); if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); goto done; } ret = btrfs_relocate_chunk(fs_info, chunk_offset); - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); if (ret == -ENOSPC) { failed++; } else if (ret) { @@ -4989,6 +5006,8 @@ static void init_alloc_chunk_ctl_policy_zoned( ctl->max_chunk_size = 2 * ctl->max_stripe_size; ctl->devs_max = min_t(int, ctl->devs_max, BTRFS_MAX_DEVS_SYS_CHUNK); + } else { + BUG(); } /* We don't want a chunk larger than 10% of writable space */ @@ -6787,6 +6806,46 @@ static u64 calc_stripe_length(u64 type, u64 chunk_len, int num_stripes) return div_u64(chunk_len, data_stripes); } +#if BITS_PER_LONG == 32 +/* + * Due to page cache limit, metadata beyond BTRFS_32BIT_MAX_FILE_SIZE + * can't be accessed on 32bit systems. + * + * This function do mount time check to reject the fs if it already has + * metadata chunk beyond that limit. + */ +static int check_32bit_meta_chunk(struct btrfs_fs_info *fs_info, + u64 logical, u64 length, u64 type) +{ + if (!(type & BTRFS_BLOCK_GROUP_METADATA)) + return 0; + + if (logical + length < MAX_LFS_FILESIZE) + return 0; + + btrfs_err_32bit_limit(fs_info); + return -EOVERFLOW; +} + +/* + * This is to give early warning for any metadata chunk reaching + * BTRFS_32BIT_EARLY_WARN_THRESHOLD. + * Although we can still access the metadata, it's not going to be possible + * once the limit is reached. + */ +static void warn_32bit_meta_chunk(struct btrfs_fs_info *fs_info, + u64 logical, u64 length, u64 type) +{ + if (!(type & BTRFS_BLOCK_GROUP_METADATA)) + return; + + if (logical + length < BTRFS_32BIT_EARLY_WARN_THRESHOLD) + return; + + btrfs_warn_32bit_limit(fs_info); +} +#endif + static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, struct btrfs_chunk *chunk) { @@ -6797,6 +6856,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, u64 logical; u64 length; u64 devid; + u64 type; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; @@ -6804,8 +6864,16 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, logical = key->offset; length = btrfs_chunk_length(leaf, chunk); + type = btrfs_chunk_type(leaf, chunk); num_stripes = btrfs_chunk_num_stripes(leaf, chunk); +#if BITS_PER_LONG == 32 + ret = check_32bit_meta_chunk(fs_info, logical, length, type); + if (ret < 0) + return ret; + warn_32bit_meta_chunk(fs_info, logical, length, type); +#endif + /* * Only need to verify chunk item if we're reading from sys chunk array, * as chunk item in tree block is already verified by tree-checker. @@ -6849,10 +6917,10 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, map->io_width = btrfs_chunk_io_width(leaf, chunk); map->io_align = btrfs_chunk_io_align(leaf, chunk); map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); - map->type = btrfs_chunk_type(leaf, chunk); + map->type = type; map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); map->verified_stripes = 0; - em->orig_block_len = calc_stripe_length(map->type, em->len, + em->orig_block_len = calc_stripe_length(type, em->len, map->num_stripes); for (i = 0; i < num_stripes; i++) { map->stripes[i].physical = @@ -8001,7 +8069,7 @@ static int relocating_repair_kthread(void *data) return -EBUSY; } - mutex_lock(&fs_info->delete_unused_bgs_mutex); + mutex_lock(&fs_info->reclaim_bgs_lock); /* Ensure block group still exists */ cache = btrfs_lookup_block_group(fs_info, target); @@ -8023,7 +8091,7 @@ static int relocating_repair_kthread(void *data) out: if (cache) btrfs_put_block_group(cache); - mutex_unlock(&fs_info->delete_unused_bgs_mutex); + mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_exclop_finish(fs_info); return ret; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index d4c3e0dd32b87e31992c9baf775d13dbcf93d39e..9c0d84e5ec066113bb4c072742cdf0833ac217ae 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -484,6 +484,7 @@ void btrfs_describe_block_groups(u64 flags, char *buf, u32 size_buf); int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info); int btrfs_recover_balance(struct btrfs_fs_info *fs_info); int btrfs_pause_balance(struct btrfs_fs_info *fs_info); +int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset); int btrfs_cancel_balance(struct btrfs_fs_info *fs_info); int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info); int btrfs_uuid_scan_kthread(void *data); diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index eeb3ebe11d7ae4c19c157239d1cc37fc1af63a60..70b23a0d03b1043df7b81c7fcc0a0d1343ef4ec7 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -342,6 +342,13 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device) if (!IS_ALIGNED(nr_sectors, zone_sectors)) zone_info->nr_zones++; + if (bdev_is_zoned(bdev) && zone_info->max_zone_append_size == 0) { + btrfs_err(fs_info, "zoned: device %pg does not support zone append", + bdev); + ret = -EINVAL; + goto out; + } + zone_info->seq_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL); if (!zone_info->seq_zones) { ret = -ENOMEM; diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h index 61e969652fe14abe7634f5f4ad6cbc430aead5de..5e41a74a9cb24d22c30f92f2b21e1d87467dceee 100644 --- a/fs/btrfs/zoned.h +++ b/fs/btrfs/zoned.h @@ -9,6 +9,12 @@ #include "disk-io.h" #include "block-group.h" +/* + * Block groups with more than this value (percents) of unusable space will be + * scheduled for background reclaim. + */ +#define BTRFS_DEFAULT_RECLAIM_THRESH 75 + struct btrfs_zoned_device_info { /* * Number of zones, zone size and types of zones if bdev is a diff --git a/fs/cachefiles/Makefile b/fs/cachefiles/Makefile index 891dedda59054ef42f64ee622a04e20c8f5715f2..2227dc2d549865cdaed58f6535e844fcf0b3f9e7 100644 --- a/fs/cachefiles/Makefile +++ b/fs/cachefiles/Makefile @@ -7,6 +7,7 @@ cachefiles-y := \ bind.o \ daemon.o \ interface.o \ + io.o \ key.o \ main.o \ namei.o \ diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 5efa6a3702c060feea6d3ef6b6297d76905355fa..da3948fdb61523e3051c6849c3cecaa09cbcc37e 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c @@ -319,8 +319,8 @@ static void cachefiles_drop_object(struct fscache_object *_object) /* * dispose of a reference to an object */ -static void cachefiles_put_object(struct fscache_object *_object, - enum fscache_obj_ref_trace why) +void cachefiles_put_object(struct fscache_object *_object, + enum fscache_obj_ref_trace why) { struct cachefiles_object *object; struct fscache_cache *cache; @@ -568,4 +568,5 @@ const struct fscache_cache_ops cachefiles_cache_ops = { .uncache_page = cachefiles_uncache_page, .dissociate_pages = cachefiles_dissociate_pages, .check_consistency = cachefiles_check_consistency, + .begin_read_operation = cachefiles_begin_read_operation, }; diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index cf9bd6401c2d0c5b71c247c87da40bd41fe825fe..4ed83aa5253b17eb3fbea187c7bae679ea172f0c 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -150,6 +150,9 @@ extern int cachefiles_has_space(struct cachefiles_cache *cache, */ extern const struct fscache_cache_ops cachefiles_cache_ops; +void cachefiles_put_object(struct fscache_object *_object, + enum fscache_obj_ref_trace why); + /* * key.c */ @@ -217,6 +220,12 @@ extern int cachefiles_allocate_pages(struct fscache_retrieval *, extern int cachefiles_write_page(struct fscache_storage *, struct page *); extern void cachefiles_uncache_page(struct fscache_object *, struct page *); +/* + * rdwr2.c + */ +extern int cachefiles_begin_read_operation(struct netfs_read_request *, + struct fscache_retrieval *); + /* * security.c */ diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c new file mode 100644 index 0000000000000000000000000000000000000000..b13fb45fc3f331a7dba98ca1e62872b676f6b047 --- /dev/null +++ b/fs/cachefiles/io.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* kiocb-using read/write + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include <linux/mount.h> +#include <linux/slab.h> +#include <linux/file.h> +#include <linux/uio.h> +#include <linux/sched/mm.h> +#include <linux/netfs.h> +#include "internal.h" + +struct cachefiles_kiocb { + struct kiocb iocb; + refcount_t ki_refcnt; + loff_t start; + union { + size_t skipped; + size_t len; + }; + netfs_io_terminated_t term_func; + void *term_func_priv; + bool was_async; +}; + +static inline void cachefiles_put_kiocb(struct cachefiles_kiocb *ki) +{ + if (refcount_dec_and_test(&ki->ki_refcnt)) { + fput(ki->iocb.ki_filp); + kfree(ki); + } +} + +/* + * Handle completion of a read from the cache. + */ +static void cachefiles_read_complete(struct kiocb *iocb, long ret, long ret2) +{ + struct cachefiles_kiocb *ki = container_of(iocb, struct cachefiles_kiocb, iocb); + + _enter("%ld,%ld", ret, ret2); + + if (ki->term_func) { + if (ret >= 0) + ret += ki->skipped; + ki->term_func(ki->term_func_priv, ret, ki->was_async); + } + + cachefiles_put_kiocb(ki); +} + +/* + * Initiate a read from the cache. + */ +static int cachefiles_read(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + bool seek_data, + netfs_io_terminated_t term_func, + void *term_func_priv) +{ + struct cachefiles_kiocb *ki; + struct file *file = cres->cache_priv2; + unsigned int old_nofs; + ssize_t ret = -ENOBUFS; + size_t len = iov_iter_count(iter), skipped = 0; + + _enter("%pD,%li,%llx,%zx/%llx", + file, file_inode(file)->i_ino, start_pos, len, + i_size_read(file->f_inode)); + + /* If the caller asked us to seek for data before doing the read, then + * we should do that now. If we find a gap, we fill it with zeros. + */ + if (seek_data) { + loff_t off = start_pos, off2; + + off2 = vfs_llseek(file, off, SEEK_DATA); + if (off2 < 0 && off2 >= (loff_t)-MAX_ERRNO && off2 != -ENXIO) { + skipped = 0; + ret = off2; + goto presubmission_error; + } + + if (off2 == -ENXIO || off2 >= start_pos + len) { + /* The region is beyond the EOF or there's no more data + * in the region, so clear the rest of the buffer and + * return success. + */ + iov_iter_zero(len, iter); + skipped = len; + ret = 0; + goto presubmission_error; + } + + skipped = off2 - off; + iov_iter_zero(skipped, iter); + } + + ret = -ENOBUFS; + ki = kzalloc(sizeof(struct cachefiles_kiocb), GFP_KERNEL); + if (!ki) + goto presubmission_error; + + refcount_set(&ki->ki_refcnt, 2); + ki->iocb.ki_filp = file; + ki->iocb.ki_pos = start_pos + skipped; + ki->iocb.ki_flags = IOCB_DIRECT; + ki->iocb.ki_hint = ki_hint_validate(file_write_hint(file)); + ki->iocb.ki_ioprio = get_current_ioprio(); + ki->skipped = skipped; + ki->term_func = term_func; + ki->term_func_priv = term_func_priv; + ki->was_async = true; + + if (ki->term_func) + ki->iocb.ki_complete = cachefiles_read_complete; + + get_file(ki->iocb.ki_filp); + + old_nofs = memalloc_nofs_save(); + ret = vfs_iocb_iter_read(file, &ki->iocb, iter); + memalloc_nofs_restore(old_nofs); + switch (ret) { + case -EIOCBQUEUED: + goto in_progress; + + case -ERESTARTSYS: + case -ERESTARTNOINTR: + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: + /* There's no easy way to restart the syscall since other AIO's + * may be already running. Just fail this IO with EINTR. + */ + ret = -EINTR; + fallthrough; + default: + ki->was_async = false; + cachefiles_read_complete(&ki->iocb, ret, 0); + if (ret > 0) + ret = 0; + break; + } + +in_progress: + cachefiles_put_kiocb(ki); + _leave(" = %zd", ret); + return ret; + +presubmission_error: + if (term_func) + term_func(term_func_priv, ret < 0 ? ret : skipped, false); + return ret; +} + +/* + * Handle completion of a write to the cache. + */ +static void cachefiles_write_complete(struct kiocb *iocb, long ret, long ret2) +{ + struct cachefiles_kiocb *ki = container_of(iocb, struct cachefiles_kiocb, iocb); + struct inode *inode = file_inode(ki->iocb.ki_filp); + + _enter("%ld,%ld", ret, ret2); + + /* Tell lockdep we inherited freeze protection from submission thread */ + __sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE); + __sb_end_write(inode->i_sb, SB_FREEZE_WRITE); + + if (ki->term_func) + ki->term_func(ki->term_func_priv, ret, ki->was_async); + + cachefiles_put_kiocb(ki); +} + +/* + * Initiate a write to the cache. + */ +static int cachefiles_write(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + netfs_io_terminated_t term_func, + void *term_func_priv) +{ + struct cachefiles_kiocb *ki; + struct inode *inode; + struct file *file = cres->cache_priv2; + unsigned int old_nofs; + ssize_t ret = -ENOBUFS; + size_t len = iov_iter_count(iter); + + _enter("%pD,%li,%llx,%zx/%llx", + file, file_inode(file)->i_ino, start_pos, len, + i_size_read(file->f_inode)); + + ki = kzalloc(sizeof(struct cachefiles_kiocb), GFP_KERNEL); + if (!ki) + goto presubmission_error; + + refcount_set(&ki->ki_refcnt, 2); + ki->iocb.ki_filp = file; + ki->iocb.ki_pos = start_pos; + ki->iocb.ki_flags = IOCB_DIRECT | IOCB_WRITE; + ki->iocb.ki_hint = ki_hint_validate(file_write_hint(file)); + ki->iocb.ki_ioprio = get_current_ioprio(); + ki->start = start_pos; + ki->len = len; + ki->term_func = term_func; + ki->term_func_priv = term_func_priv; + ki->was_async = true; + + if (ki->term_func) + ki->iocb.ki_complete = cachefiles_write_complete; + + /* Open-code file_start_write here to grab freeze protection, which + * will be released by another thread in aio_complete_rw(). Fool + * lockdep by telling it the lock got released so that it doesn't + * complain about the held lock when we return to userspace. + */ + inode = file_inode(file); + __sb_start_write(inode->i_sb, SB_FREEZE_WRITE); + __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE); + + get_file(ki->iocb.ki_filp); + + old_nofs = memalloc_nofs_save(); + ret = vfs_iocb_iter_write(file, &ki->iocb, iter); + memalloc_nofs_restore(old_nofs); + switch (ret) { + case -EIOCBQUEUED: + goto in_progress; + + case -ERESTARTSYS: + case -ERESTARTNOINTR: + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: + /* There's no easy way to restart the syscall since other AIO's + * may be already running. Just fail this IO with EINTR. + */ + ret = -EINTR; + fallthrough; + default: + ki->was_async = false; + cachefiles_write_complete(&ki->iocb, ret, 0); + if (ret > 0) + ret = 0; + break; + } + +in_progress: + cachefiles_put_kiocb(ki); + _leave(" = %zd", ret); + return ret; + +presubmission_error: + if (term_func) + term_func(term_func_priv, -ENOMEM, false); + return -ENOMEM; +} + +/* + * Prepare a read operation, shortening it to a cached/uncached + * boundary as appropriate. + */ +static enum netfs_read_source cachefiles_prepare_read(struct netfs_read_subrequest *subreq, + loff_t i_size) +{ + struct fscache_retrieval *op = subreq->rreq->cache_resources.cache_priv; + struct cachefiles_object *object; + struct cachefiles_cache *cache; + const struct cred *saved_cred; + struct file *file = subreq->rreq->cache_resources.cache_priv2; + loff_t off, to; + + _enter("%zx @%llx/%llx", subreq->len, subreq->start, i_size); + + object = container_of(op->op.object, + struct cachefiles_object, fscache); + cache = container_of(object->fscache.cache, + struct cachefiles_cache, cache); + + if (!file) + goto cache_fail_nosec; + + if (subreq->start >= i_size) + return NETFS_FILL_WITH_ZEROES; + + cachefiles_begin_secure(cache, &saved_cred); + + off = vfs_llseek(file, subreq->start, SEEK_DATA); + if (off < 0 && off >= (loff_t)-MAX_ERRNO) { + if (off == (loff_t)-ENXIO) + goto download_and_store; + goto cache_fail; + } + + if (off >= subreq->start + subreq->len) + goto download_and_store; + + if (off > subreq->start) { + off = round_up(off, cache->bsize); + subreq->len = off - subreq->start; + goto download_and_store; + } + + to = vfs_llseek(file, subreq->start, SEEK_HOLE); + if (to < 0 && to >= (loff_t)-MAX_ERRNO) + goto cache_fail; + + if (to < subreq->start + subreq->len) { + if (subreq->start + subreq->len >= i_size) + to = round_up(to, cache->bsize); + else + to = round_down(to, cache->bsize); + subreq->len = to - subreq->start; + } + + cachefiles_end_secure(cache, saved_cred); + return NETFS_READ_FROM_CACHE; + +download_and_store: + if (cachefiles_has_space(cache, 0, (subreq->len + PAGE_SIZE - 1) / PAGE_SIZE) == 0) + __set_bit(NETFS_SREQ_WRITE_TO_CACHE, &subreq->flags); +cache_fail: + cachefiles_end_secure(cache, saved_cred); +cache_fail_nosec: + return NETFS_DOWNLOAD_FROM_SERVER; +} + +/* + * Prepare for a write to occur. + */ +static int cachefiles_prepare_write(struct netfs_cache_resources *cres, + loff_t *_start, size_t *_len, loff_t i_size) +{ + loff_t start = *_start; + size_t len = *_len, down; + + /* Round to DIO size */ + down = start - round_down(start, PAGE_SIZE); + *_start = start - down; + *_len = round_up(down + len, PAGE_SIZE); + return 0; +} + +/* + * Clean up an operation. + */ +static void cachefiles_end_operation(struct netfs_cache_resources *cres) +{ + struct fscache_retrieval *op = cres->cache_priv; + struct file *file = cres->cache_priv2; + + _enter(""); + + if (file) + fput(file); + if (op) { + fscache_op_complete(&op->op, false); + fscache_put_retrieval(op); + } + + _leave(""); +} + +static const struct netfs_cache_ops cachefiles_netfs_cache_ops = { + .end_operation = cachefiles_end_operation, + .read = cachefiles_read, + .write = cachefiles_write, + .prepare_read = cachefiles_prepare_read, + .prepare_write = cachefiles_prepare_write, +}; + +/* + * Open the cache file when beginning a cache operation. + */ +int cachefiles_begin_read_operation(struct netfs_read_request *rreq, + struct fscache_retrieval *op) +{ + struct cachefiles_object *object; + struct cachefiles_cache *cache; + struct path path; + struct file *file; + + _enter(""); + + object = container_of(op->op.object, + struct cachefiles_object, fscache); + cache = container_of(object->fscache.cache, + struct cachefiles_cache, cache); + + path.mnt = cache->mnt; + path.dentry = object->backer; + file = open_with_fake_path(&path, O_RDWR | O_LARGEFILE | O_DIRECT, + d_inode(object->backer), cache->cache_cred); + if (IS_ERR(file)) + return PTR_ERR(file); + if (!S_ISREG(file_inode(file)->i_mode)) + goto error_file; + if (unlikely(!file->f_op->read_iter) || + unlikely(!file->f_op->write_iter)) { + pr_notice("Cache does not support read_iter and write_iter\n"); + goto error_file; + } + + fscache_get_retrieval(op); + rreq->cache_resources.cache_priv = op; + rreq->cache_resources.cache_priv2 = file; + rreq->cache_resources.ops = &cachefiles_netfs_cache_ops; + rreq->cookie_debug_id = object->fscache.debug_id; + _leave(""); + return 0; + +error_file: + fput(file); + return -EIO; +} diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 570731c4d019d406b9ce90fafe00cb54f02c55c2..3c03fa37cac46b08ff54d3de445fcaaffcede7ba 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -3358,7 +3358,13 @@ static void handle_cap_grant(struct inode *inode, if ((newcaps & CEPH_CAP_AUTH_SHARED) && (extra_info->issued & CEPH_CAP_AUTH_EXCL) == 0) { - inode->i_mode = le32_to_cpu(grant->mode); + umode_t mode = le32_to_cpu(grant->mode); + + if (inode_wrong_type(inode, mode)) + pr_warn_once("inode type changed! (ino %llx.%llx is 0%o, mds says 0%o)\n", + ceph_vinop(inode), inode->i_mode, mode); + else + inode->i_mode = mode; inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid)); ci->i_btime = extra_info->btime; diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 83d9358854fb55a651c210807dfb352e44351a7d..f7a790ed62c48226380953ea5809f3886cbbc269 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -677,6 +677,8 @@ int ceph_handle_snapdir(struct ceph_mds_request *req, strcmp(dentry->d_name.name, fsc->mount_options->snapdir_name) == 0) { struct inode *inode = ceph_get_snapdir(parent); + if (IS_ERR(inode)) + return PTR_ERR(inode); dout("ENOENT on snapdir %p '%pd', linking to snapdir %p\n", dentry, dentry, inode); BUG_ON(!d_unhashed(dentry)); diff --git a/fs/ceph/export.c b/fs/ceph/export.c index e088843a7734c03592adfe0ec962ed1c71d85a5a..f22156ee73064ecafb2a769c0dcedbcc58de2da5 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -248,9 +248,10 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb, ihold(inode); } else { /* mds does not support lookup snapped inode */ - err = -EOPNOTSUPP; - inode = NULL; + inode = ERR_PTR(-EOPNOTSUPP); } + } else { + inode = ERR_PTR(-ESTALE); } ceph_mdsc_put_request(req); @@ -261,8 +262,8 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb, dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d", vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err); } - if (!inode) - return ERR_PTR(-ESTALE); + if (IS_ERR(inode)) + return ERR_CAST(inode); /* see comments in ceph_get_parent() */ return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode); } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 156f849f5385674804246f3ccee2ccd0fcdf4d28..689e3ffd29d74d1b3ccc0a0fbb6fdc33cfc6514f 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -78,9 +78,21 @@ struct inode *ceph_get_snapdir(struct inode *parent) struct inode *inode = ceph_get_inode(parent->i_sb, vino); struct ceph_inode_info *ci = ceph_inode(inode); - BUG_ON(!S_ISDIR(parent->i_mode)); if (IS_ERR(inode)) return inode; + + if (!S_ISDIR(parent->i_mode)) { + pr_warn_once("bad snapdir parent type (mode=0%o)\n", + parent->i_mode); + return ERR_PTR(-ENOTDIR); + } + + if (!(inode->i_state & I_NEW) && !S_ISDIR(inode->i_mode)) { + pr_warn_once("bad snapdir inode type (mode=0%o)\n", + inode->i_mode); + return ERR_PTR(-ENOTDIR); + } + inode->i_mode = parent->i_mode; inode->i_uid = parent->i_uid; inode->i_gid = parent->i_gid; @@ -757,11 +769,32 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, bool queue_trunc = false; bool new_version = false; bool fill_inline = false; + umode_t mode = le32_to_cpu(info->mode); + dev_t rdev = le32_to_cpu(info->rdev); dout("%s %p ino %llx.%llx v %llu had %llu\n", __func__, inode, ceph_vinop(inode), le64_to_cpu(info->version), ci->i_version); + /* Once I_NEW is cleared, we can't change type or dev numbers */ + if (inode->i_state & I_NEW) { + inode->i_mode = mode; + } else { + if (inode_wrong_type(inode, mode)) { + pr_warn_once("inode type changed! (ino %llx.%llx is 0%o, mds says 0%o)\n", + ceph_vinop(inode), inode->i_mode, mode); + return -ESTALE; + } + + if ((S_ISCHR(mode) || S_ISBLK(mode)) && inode->i_rdev != rdev) { + pr_warn_once("dev inode rdev changed! (ino %llx.%llx is %u:%u, mds says %u:%u)\n", + ceph_vinop(inode), MAJOR(inode->i_rdev), + MINOR(inode->i_rdev), MAJOR(rdev), + MINOR(rdev)); + return -ESTALE; + } + } + info_caps = le32_to_cpu(info->cap.caps); /* prealloc new cap struct */ @@ -815,8 +848,6 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, issued |= __ceph_caps_dirty(ci); new_issued = ~issued & info_caps; - /* update inode */ - inode->i_rdev = le32_to_cpu(info->rdev); /* directories have fl_stripe_unit set to zero */ if (le32_to_cpu(info->layout.fl_stripe_unit)) inode->i_blkbits = @@ -828,7 +859,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) && (issued & CEPH_CAP_AUTH_EXCL) == 0) { - inode->i_mode = le32_to_cpu(info->mode); + inode->i_mode = mode; inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(info->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(info->gid)); dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, @@ -926,7 +957,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, case S_IFCHR: case S_IFSOCK: inode->i_blkbits = PAGE_SHIFT; - init_special_inode(inode, inode->i_mode, inode->i_rdev); + init_special_inode(inode, inode->i_mode, rdev); inode->i_op = &ceph_file_iops; break; case S_IFREG: diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 88a7958170ee0f7612e94f576f7da965e3c235ba..68e8e5b2784196270ce65acf7cfcf89defdae897 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -17,15 +17,14 @@ #include "cifsproto.h" #include "cifs_debug.h" #include "cifsfs.h" +#include "fs_context.h" #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif #ifdef CONFIG_CIFS_SMB_DIRECT #include "smbdirect.h" #endif -#ifdef CONFIG_CIFS_SWN_UPCALL #include "cifs_swn.h" -#endif void cifs_dump_mem(char *label, void *data, int length) @@ -118,10 +117,8 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon) seq_printf(m, " POSIX Extensions"); if (tcon->ses->server->ops->dump_share_caps) tcon->ses->server->ops->dump_share_caps(m, tcon); -#ifdef CONFIG_CIFS_SWN_UPCALL if (tcon->use_witness) seq_puts(m, " Witness"); -#endif if (tcon->need_reconnect) seq_puts(m, "\tDISCONNECTED "); @@ -490,10 +487,8 @@ skip_rdma: spin_unlock(&cifs_tcp_ses_lock); seq_putc(m, '\n'); - -#ifdef CONFIG_CIFS_SWN_UPCALL cifs_swn_dump(m); -#endif + /* BB add code to dump additional info such as TCP session info now */ return 0; } @@ -702,6 +697,7 @@ static const struct proc_ops cifs_lookup_cache_proc_ops; static const struct proc_ops traceSMB_proc_ops; static const struct proc_ops cifs_security_flags_proc_ops; static const struct proc_ops cifs_linux_ext_proc_ops; +static const struct proc_ops cifs_mount_params_proc_ops; void cifs_proc_init(void) @@ -726,6 +722,8 @@ cifs_proc_init(void) proc_create("LookupCacheEnabled", 0644, proc_fs_cifs, &cifs_lookup_cache_proc_ops); + proc_create("mount_params", 0444, proc_fs_cifs, &cifs_mount_params_proc_ops); + #ifdef CONFIG_CIFS_DFS_UPCALL proc_create("dfscache", 0644, proc_fs_cifs, &dfscache_proc_ops); #endif @@ -764,6 +762,7 @@ cifs_proc_clean(void) remove_proc_entry("SecurityFlags", proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); + remove_proc_entry("mount_params", proc_fs_cifs); #ifdef CONFIG_CIFS_DFS_UPCALL remove_proc_entry("dfscache", proc_fs_cifs); @@ -1023,6 +1022,51 @@ static const struct proc_ops cifs_security_flags_proc_ops = { .proc_release = single_release, .proc_write = cifs_security_flags_proc_write, }; + +/* To make it easier to debug, can help to show mount params */ +static int cifs_mount_params_proc_show(struct seq_file *m, void *v) +{ + const struct fs_parameter_spec *p; + const char *type; + + for (p = smb3_fs_parameters; p->name; p++) { + /* cannot use switch with pointers... */ + if (!p->type) { + if (p->flags == fs_param_neg_with_no) + type = "noflag"; + else + type = "flag"; + } else if (p->type == fs_param_is_bool) + type = "bool"; + else if (p->type == fs_param_is_u32) + type = "u32"; + else if (p->type == fs_param_is_u64) + type = "u64"; + else if (p->type == fs_param_is_string) + type = "string"; + else + type = "unknown"; + + seq_printf(m, "%s:%s\n", p->name, type); + } + + return 0; +} + +static int cifs_mount_params_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, cifs_mount_params_proc_show, NULL); +} + +static const struct proc_ops cifs_mount_params_proc_ops = { + .proc_open = cifs_mount_params_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, + /* No need for write for now */ + /* .proc_write = cifs_mount_params_proc_write, */ +}; + #else inline void cifs_proc_init(void) { diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 6b1ce4efb591c04e932611574eabfd15bd0de3c1..c87c37cf291434576ae5cbe1940421882b91c949 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -270,7 +270,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt, char *mountdata; char *devname; - devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL); + devname = kstrdup(fullpath, GFP_KERNEL); if (!devname) return ERR_PTR(-ENOMEM); @@ -302,6 +302,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) struct cifs_sb_info *cifs_sb; struct cifs_ses *ses; struct cifs_tcon *tcon; + void *page; char *full_path, *root_path; unsigned int xid; int rc; @@ -324,10 +325,13 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) goto cdda_exit; } + page = alloc_dentry_path(); /* always use tree name prefix */ - full_path = build_path_from_dentry_optional_prefix(mntpt, true); - if (full_path == NULL) - goto cdda_exit; + full_path = build_path_from_dentry_optional_prefix(mntpt, page, true); + if (IS_ERR(full_path)) { + mnt = ERR_CAST(full_path); + goto free_full_path; + } convert_delimiter(full_path, '\\'); @@ -385,7 +389,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) free_root_path: kfree(root_path); free_full_path: - kfree(full_path); + free_dentry_path(page); cdda_exit: cifs_dbg(FYI, "leaving %s\n" , __func__); return mnt; diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index aa77edc12212680e53291806c0e98769d95031b8..2a5325a7ae49e3171ee95b6416b639d6b338de7b 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -81,5 +81,9 @@ struct cifs_sb_info { * (cifs_autodisable_serverino) in order to match new mounts. */ bool mnt_cifs_serverino_autodisabled; + /* + * Available once the mount has completed. + */ + struct dentry *root; }; #endif /* _CIFS_FS_SB_H */ diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 236ecd4959d5d98e1fdc5962ae11d1e2643c22d3..8a9d2a5c9077e851d3e52d148d4c458b3e2105f2 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -7,11 +7,13 @@ #ifndef _CIFS_SWN_H #define _CIFS_SWN_H +#include "cifsglob.h" struct cifs_tcon; struct sk_buff; struct genl_info; +#ifdef CONFIG_CIFS_SWN_UPCALL extern int cifs_swn_register(struct cifs_tcon *tcon); extern int cifs_swn_unregister(struct cifs_tcon *tcon); @@ -22,4 +24,29 @@ extern void cifs_swn_dump(struct seq_file *m); extern void cifs_swn_check(void); +static inline bool cifs_swn_set_server_dstaddr(struct TCP_Server_Info *server) +{ + if (server->use_swn_dstaddr) { + server->dstaddr = server->swn_dstaddr; + return true; + } + return false; +} + +static inline void cifs_swn_reset_server_dstaddr(struct TCP_Server_Info *server) +{ + server->use_swn_dstaddr = false; +} + +#else + +static inline int cifs_swn_register(struct cifs_tcon *tcon) { return 0; } +static inline int cifs_swn_unregister(struct cifs_tcon *tcon) { return 0; } +static inline int cifs_swn_notify(struct sk_buff *s, struct genl_info *i) { return 0; } +static inline void cifs_swn_dump(struct seq_file *m) {} +static inline void cifs_swn_check(void) {} +static inline bool cifs_swn_set_server_dstaddr(struct TCP_Server_Info *server) { return false; } +static inline void cifs_swn_reset_server_dstaddr(struct TCP_Server_Info *server) {} + +#endif /* CONFIG_CIFS_SWN_UPCALL */ #endif /* _CIFS_SWN_H */ diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index d178cf85e926d479d9169c9bba772a4054d11001..784407f9280fd20e465fbdb99a545ca9bc194b61 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -1094,11 +1094,9 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl, struct cifs_ace *pnntace = NULL; char *nacl_base = NULL; u32 num_aces = 0; - __u64 nmode; bool new_aces_set = false; /* Assuming that pndacl and pnmode are never NULL */ - nmode = *pnmode; nacl_base = (char *)pndacl; nsize = sizeof(struct cifs_acl); @@ -1651,7 +1649,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, * Add three ACEs for owner, group, everyone getting rid of other ACEs * as chmod disables ACEs and set the security descriptor. Allocate * memory for the smb header, set security descriptor request security - * descriptor parameters, and secuirty descriptor itself + * descriptor parameters, and security descriptor itself */ nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN); pnntsd = kmalloc(nsecdesclen, GFP_KERNEL); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5ddd20b62484de389a5ee67654b4375559bf874e..5f2c139143a74f48d50eb1fb11ec201720a15964 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -217,8 +217,11 @@ cifs_read_super(struct super_block *sb) rc = super_setup_bdi(sb); if (rc) goto out_no_root; - /* tune readahead according to rsize */ - sb->s_bdi->ra_pages = cifs_sb->ctx->rsize / PAGE_SIZE; + /* tune readahead according to rsize if readahead size not set on mount */ + if (cifs_sb->ctx->rasize) + sb->s_bdi->ra_pages = cifs_sb->ctx->rasize / PAGE_SIZE; + else + sb->s_bdi->ra_pages = cifs_sb->ctx->rsize / PAGE_SIZE; sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ @@ -257,6 +260,29 @@ out_no_root: static void cifs_kill_sb(struct super_block *sb) { struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifs_tcon *tcon; + struct cached_fid *cfid; + + /* + * We ned to release all dentries for the cached directories + * before we kill the sb. + */ + if (cifs_sb->root) { + dput(cifs_sb->root); + cifs_sb->root = NULL; + } + tcon = cifs_sb_master_tcon(cifs_sb); + if (tcon) { + cfid = &tcon->crfid; + mutex_lock(&cfid->fid_mutex); + if (cfid->dentry) { + + dput(cfid->dentry); + cfid->dentry = NULL; + } + mutex_unlock(&cfid->fid_mutex); + } + kill_anon_super(sb); cifs_umount(cifs_sb); } @@ -626,6 +652,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize); seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize); seq_printf(s, ",bsize=%u", cifs_sb->ctx->bsize); + if (cifs_sb->ctx->rasize) + seq_printf(s, ",rasize=%u", cifs_sb->ctx->rasize); if (tcon->ses->server->min_offload) seq_printf(s, ",esize=%u", tcon->ses->server->min_offload); seq_printf(s, ",echo_interval=%lu", @@ -656,10 +684,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",multichannel,max_channels=%zu", tcon->ses->chan_max); -#ifdef CONFIG_CIFS_SWN_UPCALL if (tcon->use_witness) seq_puts(s, ",witness"); -#endif return 0; } @@ -834,6 +860,12 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out; } + /* cifs_setup_volume_info->smb3_parse_devname() redups UNC & prepath */ + kfree(cifs_sb->ctx->UNC); + cifs_sb->ctx->UNC = NULL; + kfree(cifs_sb->ctx->prepath); + cifs_sb->ctx->prepath = NULL; + rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, old_ctx->UNC); if (rc) { root = ERR_PTR(rc); @@ -888,6 +920,9 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, if (IS_ERR(root)) goto out_super; + if (cifs_sb) + cifs_sb->root = dget(root); + cifs_dbg(FYI, "dentry root is: %p\n", root); return root; @@ -1528,10 +1563,6 @@ init_cifs(void) int rc = 0; cifs_proc_init(); INIT_LIST_HEAD(&cifs_tcp_ses_list); -#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ - INIT_LIST_HEAD(&GlobalDnotifyReqList); - INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); -#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ /* * Initialize Global counters */ diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 0d7ef150dbb2935489d9ac9665d8b4f224494414..6beddb108ba0ebf18860f15ec00c5007640901eb 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -165,5 +165,5 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "2.31" +#define CIFS_VERSION "2.32" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ec824ab8c5ca38a916484e6ddb1586ba3d673c4b..b23a0ee8c6f8264e4d739691adffd7b1e8f3742a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -495,7 +495,7 @@ struct smb_version_operations { struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, - char *full_path, + const char *full_path, umode_t mode, dev_t device_number); /* version specific fiemap implementation */ @@ -988,10 +988,12 @@ struct cached_fid { bool is_valid:1; /* Do we have a useable root fid */ bool file_all_info_is_valid:1; bool has_lease:1; + unsigned long time; /* jiffies of when lease was taken */ struct kref refcount; struct cifs_fid *fid; struct mutex fid_mutex; struct cifs_tcon *tcon; + struct dentry *dentry; struct work_struct lease_break; struct smb2_file_all_info file_all_info; }; @@ -1070,6 +1072,7 @@ struct cifs_tcon { bool use_resilient:1; /* use resilient instead of durable handles */ bool use_persistent:1; /* use persistent instead of durable handles */ bool no_lease:1; /* Do not request leases on files or directories */ + bool use_witness:1; /* use witness protocol */ __le32 capabilities; __u32 share_flags; __u32 maximal_access; @@ -1094,9 +1097,6 @@ struct cifs_tcon { int remap:2; struct list_head ulist; /* cache update list */ #endif -#ifdef CONFIG_CIFS_SWN_UPCALL - bool use_witness:1; /* use witness protocol */ -#endif }; /* @@ -1316,8 +1316,6 @@ struct cifs_readdata { struct page **pages; }; -struct cifs_writedata; - /* asynchronous write support */ struct cifs_writedata { struct kref refcount; @@ -1796,9 +1794,8 @@ require use of the stronger protocol */ * * Semaphores * ---------- - * sesSem operations on smb session - * tconSem operations on tree connection - * fh_sem file handle reconnection operations + * cifsInodeInfo->lock_sem protects: + * the list of locks held by the inode * ****************************************************************************/ @@ -1829,13 +1826,6 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; */ GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; -#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ -/* Outstanding dir notify requests */ -GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; -/* DirNotify response queue */ -GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; -#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ - /* * Global transaction id (XID) information */ @@ -1879,19 +1869,9 @@ extern unsigned int cifs_min_small; /* min size of small buf pool */ extern unsigned int cifs_max_pending; /* MAX requests at once to server*/ extern bool disable_legacy_dialects; /* forbid vers=1.0 and vers=2.0 mounts */ -GLOBAL_EXTERN struct rb_root uidtree; -GLOBAL_EXTERN struct rb_root gidtree; -GLOBAL_EXTERN spinlock_t siduidlock; -GLOBAL_EXTERN spinlock_t sidgidlock; -GLOBAL_EXTERN struct rb_root siduidtree; -GLOBAL_EXTERN struct rb_root sidgidtree; -GLOBAL_EXTERN spinlock_t uidsidlock; -GLOBAL_EXTERN spinlock_t gidsidlock; - void cifs_oplock_break(struct work_struct *work); void cifs_queue_oplock_break(struct cifsFileInfo *cfile); -extern const struct slow_work_ops cifs_oplock_break_ops; extern struct workqueue_struct *cifsiod_wq; extern struct workqueue_struct *decrypt_wq; extern struct workqueue_struct *fileinfo_put_wq; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 9adc74bd9f8fafb57f8c0390c541da25ed030b48..b53a87db282f928f28757b4aee53808573af11c4 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1903,7 +1903,7 @@ typedef struct smb_com_transaction2_fnext_req { __le16 InformationLevel; __u32 ResumeKey; __le16 SearchFlags; - char ResumeFileName[1]; + char ResumeFileName[]; } __attribute__((packed)) TRANSACTION2_FNEXT_REQ; typedef struct smb_com_transaction2_fnext_rsp { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 75ce6f742b8d76203f2e6d9f9179bf2c113a108b..a79d50001fbfb417bec46ba78d49d1a72e3ffbd4 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -69,9 +69,20 @@ extern int init_cifs_idmap(void); extern void exit_cifs_idmap(void); extern int init_cifs_spnego(void); extern void exit_cifs_spnego(void); -extern char *build_path_from_dentry(struct dentry *); +extern const char *build_path_from_dentry(struct dentry *, void *); extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry, - bool prefix); + void *page, bool prefix); +static inline void *alloc_dentry_path(void) +{ + return __getname(); +} + +static inline void free_dentry_path(void *page) +{ + if (page) + __putname(page); +} + extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, @@ -184,7 +195,7 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, struct tcon_link *tlink, __u32 oplock); -extern int cifs_posix_open(char *full_path, struct inode **inode, +extern int cifs_posix_open(const char *full_path, struct inode **inode, struct super_block *sb, int mode, unsigned int f_flags, __u32 *oplock, __u16 *netfid, unsigned int xid); @@ -194,7 +205,7 @@ extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb); extern void cifs_dir_info_to_fattr(struct cifs_fattr *, FILE_DIRECTORY_INFO *, struct cifs_sb_info *); -extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); +extern int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); extern struct inode *cifs_iget(struct super_block *sb, struct cifs_fattr *fattr); @@ -207,7 +218,7 @@ extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, struct super_block *sb, unsigned int xid); extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs, - unsigned int xid, char *full_path, __u32 dosattr); + unsigned int xid, const char *full_path, __u32 dosattr); extern int cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, const unsigned int xid); @@ -358,11 +369,6 @@ extern int CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, bool delete_file, __u16 fid, __u32 pid_of_opener); -#if 0 -extern int CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, - char *fileName, __u16 dos_attributes, - const struct nls_table *nls_codepage); -#endif /* possibly unneeded function */ extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb, bool set_allocation); @@ -504,12 +510,6 @@ extern int generate_smb311signingkey(struct cifs_ses *); extern int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ -#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ -extern int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, struct file *file, int multishot, - const struct nls_table *nls_codepage); -#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ extern int CIFSSMBCopy(unsigned int xid, struct cifs_tcon *source_tcon, const char *fromName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index c279527aae92d382af7ac5aa1c3a718e2d7f8306..41f74163cc1c9a6db25043e23b764cc69d6cc41c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -114,7 +114,7 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) mutex_lock(&tcon->crfid.fid_mutex); tcon->crfid.is_valid = false; /* cached handle is not valid, so SMB2_CLOSE won't be sent below */ - close_shroot_lease_locked(&tcon->crfid); + close_cached_dir_lease_locked(&tcon->crfid); memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid)); mutex_unlock(&tcon->crfid.fid_mutex); @@ -5917,56 +5917,6 @@ SetTimesRetry: return rc; } -/* Can not be used to set time stamps yet (due to old DOS time format) */ -/* Can be used to set attributes */ -#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug - handling it anyway and NT4 was what we thought it would be needed for - Do not delete it until we prove whether needed for Win9x though */ -int -CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName, - __u16 dos_attrs, const struct nls_table *nls_codepage) -{ - SETATTR_REQ *pSMB = NULL; - SETATTR_RSP *pSMBr = NULL; - int rc = 0; - int bytes_returned; - int name_len; - - cifs_dbg(FYI, "In SetAttrLegacy\n"); - -SetAttrLgcyRetry: - rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = - ConvertToUTF16((__le16 *) pSMB->fileName, fileName, - PATH_MAX, nls_codepage); - name_len++; /* trailing null */ - name_len *= 2; - } else { - name_len = copy_path_name(pSMB->fileName, fileName); - } - pSMB->attr = cpu_to_le16(dos_attrs); - pSMB->BufferFormat = 0x04; - inc_rfc1001_len(pSMB, name_len + 1); - pSMB->ByteCount = cpu_to_le16(name_len + 1); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); - if (rc) - cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc); - - cifs_buf_release(pSMB); - - if (rc == -EAGAIN) - goto SetAttrLgcyRetry; - - return rc; -} -#endif /* temporarily unneeded SetAttr legacy function */ - static void cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, const struct cifs_unix_set_info_args *args) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 24668eb006c63f9d09a40ad6518213353915f85f..121d8b4535b0ed6a253ba39757d52afcc8169aca 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -62,9 +62,7 @@ #include "dfs_cache.h" #endif #include "fs_context.h" -#ifdef CONFIG_CIFS_SWN_UPCALL #include "cifs_swn.h" -#endif extern mempool_t *cifs_req_poolp; extern bool disable_legacy_dialects; @@ -314,12 +312,8 @@ cifs_reconnect(struct TCP_Server_Info *server) mutex_lock(&server->srv_mutex); -#ifdef CONFIG_CIFS_SWN_UPCALL - if (server->use_swn_dstaddr) { - server->dstaddr = server->swn_dstaddr; - } else { -#endif + if (!cifs_swn_set_server_dstaddr(server)) { #ifdef CONFIG_CIFS_DFS_UPCALL if (cifs_sb && cifs_sb->origin_fullpath) /* @@ -344,9 +338,7 @@ cifs_reconnect(struct TCP_Server_Info *server) #endif -#ifdef CONFIG_CIFS_SWN_UPCALL } -#endif if (cifs_rdma_enabled(server)) rc = smbd_reconnect(server); @@ -363,9 +355,7 @@ cifs_reconnect(struct TCP_Server_Info *server) if (server->tcpStatus != CifsExiting) server->tcpStatus = CifsNeedNegotiate; spin_unlock(&GlobalMid_Lock); -#ifdef CONFIG_CIFS_SWN_UPCALL - server->use_swn_dstaddr = false; -#endif + cifs_swn_reset_server_dstaddr(server); mutex_unlock(&server->srv_mutex); } } while (server->tcpStatus == CifsNeedReconnect); @@ -430,10 +420,8 @@ cifs_echo_request(struct work_struct *work) cifs_dbg(FYI, "Unable to send echo request to server: %s\n", server->hostname); -#ifdef CONFIG_CIFS_SWN_UPCALL /* Check witness registrations */ cifs_swn_check(); -#endif requeue_echo: queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval); @@ -1790,9 +1778,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses) * for the request. */ if (is_domain && ses->domainName) { - ctx->domainname = kstrndup(ses->domainName, - strlen(ses->domainName), - GFP_KERNEL); + ctx->domainname = kstrdup(ses->domainName, GFP_KERNEL); if (!ctx->domainname) { cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n", len); @@ -2009,7 +1995,6 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; } -#ifdef CONFIG_CIFS_SWN_UPCALL if (tcon->use_witness) { int rc; @@ -2019,7 +2004,6 @@ cifs_put_tcon(struct cifs_tcon *tcon) __func__, rc); } } -#endif list_del_init(&tcon->tcon_list); spin_unlock(&cifs_tcp_ses_lock); @@ -2181,9 +2165,9 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) } tcon->use_resilient = true; } -#ifdef CONFIG_CIFS_SWN_UPCALL + tcon->use_witness = false; - if (ctx->witness) { + if (IS_ENABLED(CONFIG_CIFS_SWN_UPCALL) && ctx->witness) { if (ses->server->vals->protocol_id >= SMB30_PROT_ID) { if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) { /* @@ -2209,7 +2193,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) goto out_fail; } } -#endif /* If the user really knows what they are doing they can override */ if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { @@ -3426,8 +3409,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) goto error; } /* Save mount options */ - mntdata = kstrndup(cifs_sb->ctx->mount_options, - strlen(cifs_sb->ctx->mount_options), GFP_KERNEL); + mntdata = kstrdup(cifs_sb->ctx->mount_options, GFP_KERNEL); if (!mntdata) { rc = -ENOMEM; goto error; @@ -3500,7 +3482,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) * links, the prefix path is included in both and may be changed during reconnect. See * cifs_tree_connect(). */ - cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL); + cifs_sb->origin_fullpath = kstrdup(full_path, GFP_KERNEL); if (!cifs_sb->origin_fullpath) { rc = -ENOMEM; goto error; @@ -3877,9 +3859,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) ctx->sectype = master_tcon->ses->sectype; ctx->sign = master_tcon->ses->sign; ctx->seal = master_tcon->seal; -#ifdef CONFIG_CIFS_SWN_UPCALL ctx->witness = master_tcon->use_witness; -#endif rc = cifs_set_vol_auth(ctx, master_tcon->ses); if (rc) { diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 098b4bc8da59abeb23e8a3df95bf808ff07165d6..b1fa30fefe1f6c263b14e6ce3d59048290c092cf 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -81,23 +81,24 @@ static void refresh_cache_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker); -static int get_normalized_path(const char *path, char **npath) +static int get_normalized_path(const char *path, const char **npath) { if (!path || strlen(path) < 3 || (*path != '\\' && *path != '/')) return -EINVAL; if (*path == '\\') { - *npath = (char *)path; + *npath = path; } else { - *npath = kstrndup(path, strlen(path), GFP_KERNEL); - if (!*npath) + char *s = kstrdup(path, GFP_KERNEL); + if (!s) return -ENOMEM; - convert_delimiter(*npath, '\\'); + convert_delimiter(s, '\\'); + *npath = s; } return 0; } -static inline void free_normalized_path(const char *path, char *npath) +static inline void free_normalized_path(const char *path, const char *npath) { if (path != npath) kfree(npath); @@ -358,7 +359,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed) t = kmalloc(sizeof(*t), GFP_ATOMIC); if (!t) return ERR_PTR(-ENOMEM); - t->name = kstrndup(name, strlen(name), GFP_ATOMIC); + t->name = kstrdup(name, GFP_ATOMIC); if (!t->name) { kfree(t); return ERR_PTR(-ENOMEM); @@ -419,7 +420,7 @@ static struct cache_entry *alloc_cache_entry(const char *path, if (!ce) return ERR_PTR(-ENOMEM); - ce->path = kstrndup(path, strlen(path), GFP_KERNEL); + ce->path = kstrdup(path, GFP_KERNEL); if (!ce->path) { kmem_cache_free(cache_slab, ce); return ERR_PTR(-ENOMEM); @@ -531,7 +532,7 @@ static struct cache_entry *lookup_cache_entry(const char *path, unsigned int *ha char *s, *e; char sep; - npath = kstrndup(path, strlen(path), GFP_KERNEL); + npath = kstrdup(path, GFP_KERNEL); if (!npath) return ERR_PTR(-ENOMEM); @@ -641,7 +642,7 @@ static int __update_cache_entry(const char *path, if (ce->tgthint) { s = ce->tgthint->name; - th = kstrndup(s, strlen(s), GFP_ATOMIC); + th = kstrdup(s, GFP_ATOMIC); if (!th) return -ENOMEM; } @@ -786,11 +787,11 @@ static int setup_referral(const char *path, struct cache_entry *ce, memset(ref, 0, sizeof(*ref)); - ref->path_name = kstrndup(path, strlen(path), GFP_ATOMIC); + ref->path_name = kstrdup(path, GFP_ATOMIC); if (!ref->path_name) return -ENOMEM; - ref->node_name = kstrndup(target, strlen(target), GFP_ATOMIC); + ref->node_name = kstrdup(target, GFP_ATOMIC); if (!ref->node_name) { rc = -ENOMEM; goto err_free_path; @@ -828,7 +829,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl) goto err_free_it; } - it->it_name = kstrndup(t->name, strlen(t->name), GFP_ATOMIC); + it->it_name = kstrdup(t->name, GFP_ATOMIC); if (!it->it_name) { kfree(it); rc = -ENOMEM; @@ -882,7 +883,7 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, struct dfs_cache_tgt_list *tgt_list) { int rc; - char *npath; + const char *npath; struct cache_entry *ce; rc = get_normalized_path(path, &npath); @@ -936,7 +937,7 @@ int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tgt_list) { int rc; - char *npath; + const char *npath; struct cache_entry *ce; rc = get_normalized_path(path, &npath); @@ -991,7 +992,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses, const struct dfs_cache_tgt_iterator *it) { int rc; - char *npath; + const char *npath; struct cache_entry *ce; struct cache_dfs_tgt *t; @@ -1053,7 +1054,7 @@ int dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it) { int rc; - char *npath; + const char *npath; struct cache_entry *ce; struct cache_dfs_tgt *t; @@ -1111,7 +1112,7 @@ int dfs_cache_get_tgt_referral(const char *path, struct dfs_info3_param *ref) { int rc; - char *npath; + const char *npath; struct cache_entry *ce; if (!it || !ref) @@ -1166,7 +1167,7 @@ int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fu if (!vi) return -ENOMEM; - vi->fullpath = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL); + vi->fullpath = kstrdup(fullpath, GFP_KERNEL); if (!vi->fullpath) { rc = -ENOMEM; goto err_free_vi; @@ -1484,7 +1485,7 @@ static int refresh_tcon(struct vol_info *vi, struct cifs_tcon *tcon) { int rc = 0; unsigned int xid; - char *path, *npath; + const char *path, *npath; struct cache_entry *ce; struct cifs_ses *root_ses = NULL, *ses; struct dfs_info3_param *refs = NULL; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index a3fb81e0ba17d1d618ffad73cd87656cdc5c59bd..c85aff838305338d410908036c423e3a9a55aef9 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -78,31 +78,31 @@ cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_s } /* Note: caller must free return buffer */ -char * -build_path_from_dentry(struct dentry *direntry) +const char * +build_path_from_dentry(struct dentry *direntry, void *page) { struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); bool prefix = tcon->Flags & SMB_SHARE_IS_IN_DFS; - return build_path_from_dentry_optional_prefix(direntry, + return build_path_from_dentry_optional_prefix(direntry, page, prefix); } char * -build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix) +build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page, + bool prefix) { - struct dentry *temp; - int namelen; int dfsplen; int pplen = 0; - char *full_path; - char dirsep; struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); - unsigned seq; + char dirsep = CIFS_DIR_SEP(cifs_sb); + char *s; + + if (unlikely(!page)) + return ERR_PTR(-ENOMEM); - dirsep = CIFS_DIR_SEP(cifs_sb); if (prefix) dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); else @@ -111,86 +111,39 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0; -cifs_bp_rename_retry: - namelen = dfsplen + pplen; - seq = read_seqbegin(&rename_lock); - rcu_read_lock(); - for (temp = direntry; !IS_ROOT(temp);) { - namelen += (1 + temp->d_name.len); - temp = temp->d_parent; - if (temp == NULL) { - cifs_dbg(VFS, "corrupt dentry\n"); - rcu_read_unlock(); - return NULL; - } - } - rcu_read_unlock(); - - full_path = kmalloc(namelen+1, GFP_ATOMIC); - if (full_path == NULL) - return full_path; - full_path[namelen] = 0; /* trailing null */ - rcu_read_lock(); - for (temp = direntry; !IS_ROOT(temp);) { - spin_lock(&temp->d_lock); - namelen -= 1 + temp->d_name.len; - if (namelen < 0) { - spin_unlock(&temp->d_lock); - break; - } else { - full_path[namelen] = dirsep; - strncpy(full_path + namelen + 1, temp->d_name.name, - temp->d_name.len); - cifs_dbg(FYI, "name: %s\n", full_path + namelen); - } - spin_unlock(&temp->d_lock); - temp = temp->d_parent; - if (temp == NULL) { - cifs_dbg(VFS, "corrupt dentry\n"); - rcu_read_unlock(); - kfree(full_path); - return NULL; - } - } - rcu_read_unlock(); - if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) { - cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n", - namelen, dfsplen); - /* presumably this is only possible if racing with a rename - of one of the parent directories (we can not lock the dentries - above us to prevent this, but retrying should be harmless) */ - kfree(full_path); - goto cifs_bp_rename_retry; - } - /* DIR_SEP already set for byte 0 / vs \ but not for - subsequent slashes in prepath which currently must - be entered the right way - not sure if there is an alternative - since the '\' is a valid posix character so we can not switch - those safely to '/' if any are found in the middle of the prepath */ - /* BB test paths to Windows with '/' in the midst of prepath */ - + s = dentry_path_raw(direntry, page, PAGE_SIZE); + if (IS_ERR(s)) + return s; + if (!s[1]) // for root we want "", not "/" + s++; + if (s < (char *)page + pplen + dfsplen) + return ERR_PTR(-ENAMETOOLONG); if (pplen) { - int i; - cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath); - memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1); - full_path[dfsplen] = dirsep; - for (i = 0; i < pplen-1; i++) - if (full_path[dfsplen+1+i] == '/') - full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb); + s -= pplen; + memcpy(s + 1, cifs_sb->prepath, pplen - 1); + *s = '/'; } + if (dirsep != '/') { + /* BB test paths to Windows with '/' in the midst of prepath */ + char *p; + for (p = s; *p; p++) + if (*p == '/') + *p = dirsep; + } if (dfsplen) { - strncpy(full_path, tcon->treeName, dfsplen); + s -= dfsplen; + memcpy(s, tcon->treeName, dfsplen); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { int i; for (i = 0; i < dfsplen; i++) { - if (full_path[i] == '\\') - full_path[i] = '/'; + if (s[i] == '\\') + s[i] = '/'; } } } - return full_path; + return s; } /* @@ -233,7 +186,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, int desired_access; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_tcon *tcon = tlink_tcon(tlink); - char *full_path = NULL; + const char *full_path; + void *page = alloc_dentry_path(); FILE_ALL_INFO *buf = NULL; struct inode *newinode = NULL; int disposition; @@ -244,9 +198,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, if (tcon->ses->server->oplocks) *oplock = REQ_OPLOCK; - full_path = build_path_from_dentry(direntry); - if (!full_path) - return -ENOMEM; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + free_dentry_path(page); + return PTR_ERR(full_path); + } if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open && (CIFS_UNIX_POSIX_PATH_OPS_CAP & @@ -418,15 +374,16 @@ cifs_create_get_file_info: if (newinode) { if (server->ops->set_lease_key) server->ops->set_lease_key(newinode, fid); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) - newinode->i_mode = mode; - if ((*oplock & CIFS_CREATE_ACTION) && - (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { - newinode->i_uid = current_fsuid(); - if (inode->i_mode & S_ISGID) - newinode->i_gid = inode->i_gid; - else - newinode->i_gid = current_fsgid(); + if ((*oplock & CIFS_CREATE_ACTION) && S_ISREG(newinode->i_mode)) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) + newinode->i_mode = mode; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + newinode->i_uid = current_fsuid(); + if (inode->i_mode & S_ISGID) + newinode->i_gid = inode->i_gid; + else + newinode->i_gid = current_fsgid(); + } } } } @@ -448,7 +405,7 @@ cifs_create_set_dentry: out: kfree(buf); - kfree(full_path); + free_dentry_path(page); return rc; out_err: @@ -619,7 +576,8 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode, struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *tcon; - char *full_path = NULL; + const char *full_path; + void *page; if (!old_valid_dev(device_number)) return -EINVAL; @@ -629,13 +587,13 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode, if (IS_ERR(tlink)) return PTR_ERR(tlink); + page = alloc_dentry_path(); tcon = tlink_tcon(tlink); - xid = get_xid(); - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto mknod_out; } @@ -644,7 +602,7 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode, device_number); mknod_out: - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); return rc; @@ -660,7 +618,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct tcon_link *tlink; struct cifs_tcon *pTcon; struct inode *newInode = NULL; - char *full_path = NULL; + const char *full_path; + void *page; xid = get_xid(); @@ -687,11 +646,13 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, /* can not grab the rename sem here since it would deadlock in the cases (beginning of sys_rename itself) in which we already have the sb rename sem */ - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { + page = alloc_dentry_path(); + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { cifs_put_tlink(tlink); free_xid(xid); - return ERR_PTR(-ENOMEM); + free_dentry_path(page); + return ERR_CAST(full_path); } if (d_really_is_positive(direntry)) { @@ -727,7 +688,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } newInode = ERR_PTR(rc); } - kfree(full_path); + free_dentry_path(page); cifs_put_tlink(tlink); free_xid(xid); return d_splice_alias(newInode, direntry); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 042e24aad41098ac29c92c7d837deb5b6c806e19..639c59596d4f3665dfafd057298c421b7e2b407f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -112,7 +112,7 @@ static inline int cifs_get_disposition(unsigned int flags) return FILE_OPEN; } -int cifs_posix_open(char *full_path, struct inode **pinode, +int cifs_posix_open(const char *full_path, struct inode **pinode, struct super_block *sb, int mode, unsigned int f_flags, __u32 *poplock, __u16 *pnetfid, unsigned int xid) { @@ -166,7 +166,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, } } else { cifs_revalidate_mapping(*pinode); - cifs_fattr_to_inode(*pinode, &fattr); + rc = cifs_fattr_to_inode(*pinode, &fattr); } posix_open_ret: @@ -175,7 +175,7 @@ posix_open_ret: } static int -cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, +cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock, struct cifs_fid *fid, unsigned int xid) { @@ -530,7 +530,8 @@ int cifs_open(struct inode *inode, struct file *file) struct cifs_tcon *tcon; struct tcon_link *tlink; struct cifsFileInfo *cfile = NULL; - char *full_path = NULL; + void *page; + const char *full_path; bool posix_open_ok = false; struct cifs_fid fid; struct cifs_pending_open open; @@ -546,9 +547,10 @@ int cifs_open(struct inode *inode, struct file *file) tcon = tlink_tcon(tlink); server = tcon->ses->server; - full_path = build_path_from_dentry(file_dentry(file)); - if (full_path == NULL) { - rc = -ENOMEM; + page = alloc_dentry_path(); + full_path = build_path_from_dentry(file_dentry(file), page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto out; } @@ -640,7 +642,7 @@ int cifs_open(struct inode *inode, struct file *file) } out: - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); return rc; @@ -689,7 +691,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) struct TCP_Server_Info *server; struct cifsInodeInfo *cinode; struct inode *inode; - char *full_path = NULL; + void *page; + const char *full_path; int desired_access; int disposition = FILE_OPEN; int create_options = CREATE_NOT_DIR; @@ -699,9 +702,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) mutex_lock(&cfile->fh_mutex); if (!cfile->invalidHandle) { mutex_unlock(&cfile->fh_mutex); - rc = 0; free_xid(xid); - return rc; + return 0; } inode = d_inode(cfile->dentry); @@ -715,12 +717,13 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) * called and if the server was down that means we end up here, and we * can never tell if the caller already has the rename_sem. */ - full_path = build_path_from_dentry(cfile->dentry); - if (full_path == NULL) { - rc = -ENOMEM; + page = alloc_dentry_path(); + full_path = build_path_from_dentry(cfile->dentry, page); + if (IS_ERR(full_path)) { mutex_unlock(&cfile->fh_mutex); + free_dentry_path(page); free_xid(xid); - return rc; + return PTR_ERR(full_path); } cifs_dbg(FYI, "inode = 0x%p file flags 0x%x for %s\n", @@ -838,7 +841,7 @@ reopen_success: cifs_relock_file(cfile); reopen_error_exit: - kfree(full_path); + free_dentry_path(page); free_xid(xid); return rc; } @@ -2069,34 +2072,31 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, int flags, struct cifsFileInfo **ret_file) { - struct list_head *tmp; struct cifsFileInfo *cfile; - struct cifsInodeInfo *cinode; - char *full_path; + void *page = alloc_dentry_path(); *ret_file = NULL; spin_lock(&tcon->open_file_lock); - list_for_each(tmp, &tcon->openFileList) { - cfile = list_entry(tmp, struct cifsFileInfo, - tlist); - full_path = build_path_from_dentry(cfile->dentry); - if (full_path == NULL) { + list_for_each_entry(cfile, &tcon->openFileList, tlist) { + struct cifsInodeInfo *cinode; + const char *full_path = build_path_from_dentry(cfile->dentry, page); + if (IS_ERR(full_path)) { spin_unlock(&tcon->open_file_lock); - return -ENOMEM; + free_dentry_path(page); + return PTR_ERR(full_path); } - if (strcmp(full_path, name)) { - kfree(full_path); + if (strcmp(full_path, name)) continue; - } - kfree(full_path); cinode = CIFS_I(d_inode(cfile->dentry)); spin_unlock(&tcon->open_file_lock); + free_dentry_path(page); return cifs_get_writable_file(cinode, flags, ret_file); } spin_unlock(&tcon->open_file_lock); + free_dentry_path(page); return -ENOENT; } @@ -2104,35 +2104,32 @@ int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, struct cifsFileInfo **ret_file) { - struct list_head *tmp; struct cifsFileInfo *cfile; - struct cifsInodeInfo *cinode; - char *full_path; + void *page = alloc_dentry_path(); *ret_file = NULL; spin_lock(&tcon->open_file_lock); - list_for_each(tmp, &tcon->openFileList) { - cfile = list_entry(tmp, struct cifsFileInfo, - tlist); - full_path = build_path_from_dentry(cfile->dentry); - if (full_path == NULL) { + list_for_each_entry(cfile, &tcon->openFileList, tlist) { + struct cifsInodeInfo *cinode; + const char *full_path = build_path_from_dentry(cfile->dentry, page); + if (IS_ERR(full_path)) { spin_unlock(&tcon->open_file_lock); - return -ENOMEM; + free_dentry_path(page); + return PTR_ERR(full_path); } - if (strcmp(full_path, name)) { - kfree(full_path); + if (strcmp(full_path, name)) continue; - } - kfree(full_path); cinode = CIFS_I(d_inode(cfile->dentry)); spin_unlock(&tcon->open_file_lock); + free_dentry_path(page); *ret_file = find_readable_file(cinode, 0); return *ret_file ? 0 : -ENOENT; } spin_unlock(&tcon->open_file_lock); + free_dentry_path(page); return -ENOENT; } diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 78889024a7ed04cabf5eb7b99e52b5b17fb9e931..3e0d016849e302d2060c749cbbedadab6875f5e9 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -137,6 +137,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_u32("min_enc_offload", Opt_min_enc_offload), fsparam_u32("esize", Opt_min_enc_offload), fsparam_u32("bsize", Opt_blocksize), + fsparam_u32("rasize", Opt_rasize), fsparam_u32("rsize", Opt_rsize), fsparam_u32("wsize", Opt_wsize), fsparam_u32("actimeo", Opt_actimeo), @@ -188,8 +189,8 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { {} }; -int -cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx) +static int +cifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_context *ctx) { substring_t args[MAX_OPT_ARGS]; @@ -203,7 +204,7 @@ cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx) switch (match_token(value, cifs_secflavor_tokens, args)) { case Opt_sec_krb5p: - cifs_dbg(VFS, "sec=krb5p is not supported!\n"); + cifs_errorf(fc, "sec=krb5p is not supported!\n"); return 1; case Opt_sec_krb5i: ctx->sign = true; @@ -238,7 +239,7 @@ cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx) ctx->nullauth = 1; break; default: - cifs_dbg(VFS, "bad security option: %s\n", value); + cifs_errorf(fc, "bad security option: %s\n", value); return 1; } @@ -254,8 +255,8 @@ static const match_table_t cifs_cacheflavor_tokens = { { Opt_cache_err, NULL } }; -int -cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx) +static int +cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_context *ctx) { substring_t args[MAX_OPT_ARGS]; @@ -291,7 +292,7 @@ cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx) ctx->cache_rw = true; break; default: - cifs_dbg(VFS, "bad cache= option: %s\n", value); + cifs_errorf(fc, "bad cache= option: %s\n", value); return 1; } return 0; @@ -339,7 +340,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx } static int -cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) +cifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_context *ctx, bool is_smb3) { substring_t args[MAX_OPT_ARGS]; @@ -347,24 +348,24 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY case Smb_1: if (disable_legacy_dialects) { - cifs_dbg(VFS, "mount with legacy dialect disabled\n"); + cifs_errorf(fc, "mount with legacy dialect disabled\n"); return 1; } if (is_smb3) { - cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); + cifs_errorf(fc, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); return 1; } - cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n"); + cifs_errorf(fc, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n"); ctx->ops = &smb1_operations; ctx->vals = &smb1_values; break; case Smb_20: if (disable_legacy_dialects) { - cifs_dbg(VFS, "mount with legacy dialect disabled\n"); + cifs_errorf(fc, "mount with legacy dialect disabled\n"); return 1; } if (is_smb3) { - cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); + cifs_errorf(fc, "vers=2.0 not permitted when mounting with smb3\n"); return 1; } ctx->ops = &smb20_operations; @@ -372,10 +373,10 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) break; #else case Smb_1: - cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); + cifs_errorf(fc, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); return 1; case Smb_20: - cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); + cifs_errorf(fc, "vers=2.0 mount not permitted when legacy dialects disabled\n"); return 1; #endif /* CIFS_ALLOW_INSECURE_LEGACY */ case Smb_21: @@ -403,7 +404,7 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) ctx->vals = &smbdefault_values; break; default: - cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value); + cifs_errorf(fc, "Unknown vers= option specified: %s\n", value); return 1; } return 0; @@ -430,7 +431,7 @@ int smb3_parse_opt(const char *options, const char *key, char **val) if (nval == p) continue; *nval++ = 0; - *val = kstrndup(nval, strlen(nval), GFP_KERNEL); + *val = kstrdup(nval, GFP_KERNEL); rc = !*val ? -ENOMEM : 0; goto out; } @@ -588,14 +589,14 @@ static int smb3_fs_context_validate(struct fs_context *fc) struct smb3_fs_context *ctx = smb3_fc2context(fc); if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) { - cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n"); + cifs_errorf(fc, "SMB Direct requires Version >=3.0\n"); return -EOPNOTSUPP; } #ifndef CONFIG_KEYS /* Muliuser mounts require CONFIG_KEYS support */ if (ctx->multiuser) { - cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n"); + cifs_errorf(fc, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n"); return -1; } #endif @@ -605,13 +606,13 @@ static int smb3_fs_context_validate(struct fs_context *fc) if (!ctx->UNC) { - cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n"); + cifs_errorf(fc, "CIFS mount error: No usable UNC path provided in device string!\n"); return -1; } /* make sure UNC has a share name */ if (strlen(ctx->UNC) < 3 || !strchr(ctx->UNC + 3, '\\')) { - cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n"); + cifs_errorf(fc, "Malformed UNC. Unable to find share name.\n"); return -ENOENT; } @@ -684,49 +685,50 @@ static void smb3_fs_context_free(struct fs_context *fc) * Compare the old and new proposed context during reconfigure * and check if the changes are compatible. */ -static int smb3_verify_reconfigure_ctx(struct smb3_fs_context *new_ctx, +static int smb3_verify_reconfigure_ctx(struct fs_context *fc, + struct smb3_fs_context *new_ctx, struct smb3_fs_context *old_ctx) { if (new_ctx->posix_paths != old_ctx->posix_paths) { - cifs_dbg(VFS, "can not change posixpaths during remount\n"); + cifs_errorf(fc, "can not change posixpaths during remount\n"); return -EINVAL; } if (new_ctx->sectype != old_ctx->sectype) { - cifs_dbg(VFS, "can not change sec during remount\n"); + cifs_errorf(fc, "can not change sec during remount\n"); return -EINVAL; } if (new_ctx->multiuser != old_ctx->multiuser) { - cifs_dbg(VFS, "can not change multiuser during remount\n"); + cifs_errorf(fc, "can not change multiuser during remount\n"); return -EINVAL; } if (new_ctx->UNC && (!old_ctx->UNC || strcmp(new_ctx->UNC, old_ctx->UNC))) { - cifs_dbg(VFS, "can not change UNC during remount\n"); + cifs_errorf(fc, "can not change UNC during remount\n"); return -EINVAL; } if (new_ctx->username && (!old_ctx->username || strcmp(new_ctx->username, old_ctx->username))) { - cifs_dbg(VFS, "can not change username during remount\n"); + cifs_errorf(fc, "can not change username during remount\n"); return -EINVAL; } if (new_ctx->password && (!old_ctx->password || strcmp(new_ctx->password, old_ctx->password))) { - cifs_dbg(VFS, "can not change password during remount\n"); + cifs_errorf(fc, "can not change password during remount\n"); return -EINVAL; } if (new_ctx->domainname && (!old_ctx->domainname || strcmp(new_ctx->domainname, old_ctx->domainname))) { - cifs_dbg(VFS, "can not change domainname during remount\n"); + cifs_errorf(fc, "can not change domainname during remount\n"); return -EINVAL; } if (new_ctx->nodename && (!old_ctx->nodename || strcmp(new_ctx->nodename, old_ctx->nodename))) { - cifs_dbg(VFS, "can not change nodename during remount\n"); + cifs_errorf(fc, "can not change nodename during remount\n"); return -EINVAL; } if (new_ctx->iocharset && (!old_ctx->iocharset || strcmp(new_ctx->iocharset, old_ctx->iocharset))) { - cifs_dbg(VFS, "can not change iocharset during remount\n"); + cifs_errorf(fc, "can not change iocharset during remount\n"); return -EINVAL; } @@ -747,7 +749,7 @@ static int smb3_reconfigure(struct fs_context *fc) struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); int rc; - rc = smb3_verify_reconfigure_ctx(ctx, cifs_sb->ctx); + rc = smb3_verify_reconfigure_ctx(fc, ctx, cifs_sb->ctx); if (rc) return rc; @@ -933,13 +935,33 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, */ if ((result.uint_32 < CIFS_MAX_MSGSIZE) || (result.uint_32 > (4 * SMB3_DEFAULT_IOSIZE))) { - cifs_dbg(VFS, "%s: Invalid blocksize\n", + cifs_errorf(fc, "%s: Invalid blocksize\n", __func__); goto cifs_parse_mount_err; } ctx->bsize = result.uint_32; ctx->got_bsize = true; break; + case Opt_rasize: + /* + * readahead size realistically should never need to be + * less than 1M (CIFS_DEFAULT_IOSIZE) or greater than 32M + * (perhaps an exception should be considered in the + * for the case of a large number of channels + * when multichannel is negotiated) since that would lead + * to plenty of parallel I/O in flight to the server. + * Note that smaller read ahead sizes would + * hurt performance of common tools like cp and scp + * which often trigger sequential i/o with read ahead + */ + if ((result.uint_32 > (8 * SMB3_DEFAULT_IOSIZE)) || + (result.uint_32 < CIFS_DEFAULT_IOSIZE)) { + cifs_errorf(fc, "%s: Invalid rasize %d vs. %d\n", + __func__, result.uint_32, SMB3_DEFAULT_IOSIZE); + goto cifs_parse_mount_err; + } + ctx->rasize = result.uint_32; + break; case Opt_rsize: ctx->rsize = result.uint_32; ctx->got_rsize = true; @@ -951,25 +973,25 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, case Opt_acregmax: ctx->acregmax = HZ * result.uint_32; if (ctx->acregmax > CIFS_MAX_ACTIMEO) { - cifs_dbg(VFS, "acregmax too large\n"); + cifs_errorf(fc, "acregmax too large\n"); goto cifs_parse_mount_err; } break; case Opt_acdirmax: ctx->acdirmax = HZ * result.uint_32; if (ctx->acdirmax > CIFS_MAX_ACTIMEO) { - cifs_dbg(VFS, "acdirmax too large\n"); + cifs_errorf(fc, "acdirmax too large\n"); goto cifs_parse_mount_err; } break; case Opt_actimeo: if (HZ * result.uint_32 > CIFS_MAX_ACTIMEO) { - cifs_dbg(VFS, "timeout too large\n"); + cifs_errorf(fc, "timeout too large\n"); goto cifs_parse_mount_err; } if ((ctx->acdirmax != CIFS_DEF_ACTIMEO) || (ctx->acregmax != CIFS_DEF_ACTIMEO)) { - cifs_dbg(VFS, "actimeo ignored since acregmax or acdirmax specified\n"); + cifs_errorf(fc, "actimeo ignored since acregmax or acdirmax specified\n"); break; } ctx->acdirmax = ctx->acregmax = HZ * result.uint_32; @@ -982,7 +1004,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, break; case Opt_max_credits: if (result.uint_32 < 20 || result.uint_32 > 60000) { - cifs_dbg(VFS, "%s: Invalid max_credits value\n", + cifs_errorf(fc, "%s: Invalid max_credits value\n", __func__); goto cifs_parse_mount_err; } @@ -990,7 +1012,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, break; case Opt_max_channels: if (result.uint_32 < 1 || result.uint_32 > CIFS_MAX_CHANNELS) { - cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n", + cifs_errorf(fc, "%s: Invalid max_channels value, needs to be 1-%d\n", __func__, CIFS_MAX_CHANNELS); goto cifs_parse_mount_err; } @@ -999,7 +1021,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, case Opt_handletimeout: ctx->handle_timeout = result.uint_32; if (ctx->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { - cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); + cifs_errorf(fc, "Invalid handle cache timeout, longer than 16 minutes\n"); goto cifs_parse_mount_err; } break; @@ -1010,23 +1032,23 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, case 0: break; case -ENOMEM: - cifs_dbg(VFS, "Unable to allocate memory for devname\n"); + cifs_errorf(fc, "Unable to allocate memory for devname\n"); goto cifs_parse_mount_err; case -EINVAL: - cifs_dbg(VFS, "Malformed UNC in devname\n"); + cifs_errorf(fc, "Malformed UNC in devname\n"); goto cifs_parse_mount_err; default: - cifs_dbg(VFS, "Unknown error parsing devname\n"); + cifs_errorf(fc, "Unknown error parsing devname\n"); goto cifs_parse_mount_err; } ctx->source = kstrdup(param->string, GFP_KERNEL); if (ctx->source == NULL) { - cifs_dbg(VFS, "OOM when copying UNC string\n"); + cifs_errorf(fc, "OOM when copying UNC string\n"); goto cifs_parse_mount_err; } fc->source = kstrdup(param->string, GFP_KERNEL); if (fc->source == NULL) { - cifs_dbg(VFS, "OOM when copying UNC string\n"); + cifs_errorf(fc, "OOM when copying UNC string\n"); goto cifs_parse_mount_err; } break; @@ -1046,7 +1068,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, } ctx->username = kstrdup(param->string, GFP_KERNEL); if (ctx->username == NULL) { - cifs_dbg(VFS, "OOM when copying username string\n"); + cifs_errorf(fc, "OOM when copying username string\n"); goto cifs_parse_mount_err; } break; @@ -1058,7 +1080,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ctx->password = kstrdup(param->string, GFP_KERNEL); if (ctx->password == NULL) { - cifs_dbg(VFS, "OOM when copying password string\n"); + cifs_errorf(fc, "OOM when copying password string\n"); goto cifs_parse_mount_err; } break; @@ -1085,7 +1107,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, kfree(ctx->domainname); ctx->domainname = kstrdup(param->string, GFP_KERNEL); if (ctx->domainname == NULL) { - cifs_dbg(VFS, "OOM when copying domainname string\n"); + cifs_errorf(fc, "OOM when copying domainname string\n"); goto cifs_parse_mount_err; } cifs_dbg(FYI, "Domain name set\n"); @@ -1109,7 +1131,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, kfree(ctx->iocharset); ctx->iocharset = kstrdup(param->string, GFP_KERNEL); if (ctx->iocharset == NULL) { - cifs_dbg(VFS, "OOM when copying iocharset string\n"); + cifs_errorf(fc, "OOM when copying iocharset string\n"); goto cifs_parse_mount_err; } } @@ -1175,21 +1197,21 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, goto cifs_parse_mount_err; case Opt_vers: /* protocol version (dialect) */ - if (cifs_parse_smb_version(param->string, ctx, is_smb3) != 0) + if (cifs_parse_smb_version(fc, param->string, ctx, is_smb3) != 0) goto cifs_parse_mount_err; ctx->got_version = true; break; case Opt_sec: - if (cifs_parse_security_flavors(param->string, ctx) != 0) + if (cifs_parse_security_flavors(fc, param->string, ctx) != 0) goto cifs_parse_mount_err; break; case Opt_cache: - if (cifs_parse_cache_flavor(param->string, ctx) != 0) + if (cifs_parse_cache_flavor(fc, param->string, ctx) != 0) goto cifs_parse_mount_err; break; case Opt_witness: #ifndef CONFIG_CIFS_SWN_UPCALL - cifs_dbg(VFS, "Witness support needs CONFIG_CIFS_SWN_UPCALL config option\n"); + cifs_errorf(fc, "Witness support needs CONFIG_CIFS_SWN_UPCALL config option\n"); goto cifs_parse_mount_err; #endif ctx->witness = true; @@ -1290,7 +1312,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, break; case Opt_fsc: #ifndef CONFIG_CIFS_FSCACHE - cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); + cifs_errorf(fc, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); goto cifs_parse_mount_err; #endif ctx->fsc = true; @@ -1311,15 +1333,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, if (result.negated) { ctx->nopersistent = true; if (ctx->persistent) { - cifs_dbg(VFS, - "persistenthandles mount options conflict\n"); + cifs_errorf(fc, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } } else { ctx->persistent = true; if ((ctx->nopersistent) || (ctx->resilient)) { - cifs_dbg(VFS, - "persistenthandles mount options conflict\n"); + cifs_errorf(fc, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } } @@ -1330,8 +1350,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, } else { ctx->resilient = true; if (ctx->persistent) { - cifs_dbg(VFS, - "persistenthandles mount options conflict\n"); + cifs_errorf(fc, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } } @@ -1379,7 +1398,9 @@ int smb3_init_fs_context(struct fs_context *fc) ctx->cred_uid = current_uid(); ctx->linux_uid = current_uid(); ctx->linux_gid = current_gid(); - ctx->bsize = 1024 * 1024; /* can improve cp performance significantly */ + /* By default 4MB read ahead size, 1MB block size */ + ctx->bsize = CIFS_DEFAULT_IOSIZE; /* can improve cp performance significantly */ + ctx->rasize = 0; /* 0 = use default (ie negotiated rsize) for read ahead pages */ /* * default to SFM style remapping of seven reserved characters diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 87dd1f7168f26f8d111e6562636e9cfd06feacff..2a71c8e411ac1b6acdc6b39f10021e278e2ccbf4 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -13,7 +13,12 @@ #include <linux/parser.h> #include <linux/fs_parser.h> -#define cifs_invalf(fc, fmt, ...) invalf(fc, fmt, ## __VA_ARGS__) +/* Log errors in fs_context (new mount api) but also in dmesg (old style) */ +#define cifs_errorf(fc, fmt, ...) \ + do { \ + errorf(fc, fmt, ## __VA_ARGS__); \ + cifs_dbg(VFS, fmt, ## __VA_ARGS__); \ + } while (0) enum smb_version { Smb_1 = 1, @@ -115,6 +120,7 @@ enum cifs_param { Opt_dirmode, Opt_min_enc_offload, Opt_blocksize, + Opt_rasize, Opt_rsize, Opt_wsize, Opt_actimeo, @@ -230,6 +236,7 @@ struct smb3_fs_context { /* reuse existing guid for multichannel */ u8 client_guid[SMB2_CLIENT_GUID_SIZE]; unsigned int bsize; + unsigned int rasize; unsigned int rsize; unsigned int wsize; unsigned int min_offload; @@ -257,10 +264,6 @@ struct smb3_fs_context { extern const struct fs_parameter_spec smb3_fs_parameters[]; -extern int cifs_parse_cache_flavor(char *value, - struct smb3_fs_context *ctx); -extern int cifs_parse_security_flavors(char *value, - struct smb3_fs_context *ctx); extern int smb3_init_fs_context(struct fs_context *fc); extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx); extern void smb3_cleanup_fs_context(struct smb3_fs_context *ctx); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f2df4422e54ae0c8262860165a93a8d96df229e2..002d864b8f7b5bd6e562c7acbaa792394cbc86ff 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -157,12 +157,18 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) } /* populate an inode with info from a cifs_fattr struct */ -void +int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + if (!(inode->i_state & I_NEW) && + unlikely(inode_wrong_type(inode, fattr->cf_mode))) { + CIFS_I(inode)->time = 0; /* force reval */ + return -ESTALE; + } + cifs_revalidate_cache(inode, fattr); spin_lock(&inode->i_lock); @@ -219,6 +225,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) inode->i_flags |= S_AUTOMOUNT; if (inode->i_state & I_NEW) cifs_set_ops(inode); + return 0; } void @@ -363,7 +370,7 @@ cifs_get_file_info_unix(struct file *filp) rc = 0; } - cifs_fattr_to_inode(inode, &fattr); + rc = cifs_fattr_to_inode(inode, &fattr); free_xid(xid); return rc; } @@ -426,14 +433,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, } /* if filetype is different, return error */ - if (unlikely(((*pinode)->i_mode & S_IFMT) != - (fattr.cf_mode & S_IFMT))) { - CIFS_I(*pinode)->time = 0; /* force reval */ - rc = -ESTALE; - goto cgiiu_exit; - } - - cifs_fattr_to_inode(*pinode, &fattr); + rc = cifs_fattr_to_inode(*pinode, &fattr); } cgiiu_exit: @@ -783,7 +783,8 @@ cifs_get_file_info(struct file *filp) */ fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; - cifs_fattr_to_inode(inode, &fattr); + /* if filetype is different, return error */ + rc = cifs_fattr_to_inode(inode, &fattr); cgfi_exit: free_xid(xid); return rc; @@ -1100,16 +1101,8 @@ handle_mnt_opt: rc = -ESTALE; goto out; } - /* if filetype is different, return error */ - if (unlikely(((*inode)->i_mode & S_IFMT) != - (fattr.cf_mode & S_IFMT))) { - CIFS_I(*inode)->time = 0; /* force reval */ - rc = -ESTALE; - goto out; - } - - cifs_fattr_to_inode(*inode, &fattr); + rc = cifs_fattr_to_inode(*inode, &fattr); } out: cifs_buf_release(smb1_backup_rsp_buf); @@ -1215,14 +1208,7 @@ smb311_posix_get_inode_info(struct inode **inode, } /* if filetype is different, return error */ - if (unlikely(((*inode)->i_mode & S_IFMT) != - (fattr.cf_mode & S_IFMT))) { - CIFS_I(*inode)->time = 0; /* force reval */ - rc = -ESTALE; - goto out; - } - - cifs_fattr_to_inode(*inode, &fattr); + rc = cifs_fattr_to_inode(*inode, &fattr); } out: cifs_put_tlink(tlink); @@ -1249,7 +1235,7 @@ cifs_find_inode(struct inode *inode, void *opaque) return 0; /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) + if (inode_wrong_type(inode, fattr->cf_mode)) return 0; /* if it's not a directory or has no dentries, then flag it */ @@ -1317,6 +1303,7 @@ retry_iget5_locked: } } + /* can't fail - see cifs_find_inode() */ cifs_fattr_to_inode(inode, fattr); if (sb->s_flags & SB_NOATIME) inode->i_flags |= S_NOATIME | S_NOCMTIME; @@ -1408,7 +1395,7 @@ out: int cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, - char *full_path, __u32 dosattr) + const char *full_path, __u32 dosattr) { bool set_time = false; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -1609,7 +1596,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) { int rc = 0; unsigned int xid; - char *full_path = NULL; + const char *full_path; + void *page; struct inode *inode = d_inode(dentry); struct cifsInodeInfo *cifs_inode; struct super_block *sb = dir->i_sb; @@ -1629,6 +1617,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) server = tcon->ses->server; xid = get_xid(); + page = alloc_dentry_path(); if (tcon->nodelete) { rc = -EACCES; @@ -1637,9 +1626,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) /* Unlink can be called from rename so we can not take the * sb->s_vfs_rename_mutex here */ - full_path = build_path_from_dentry(dentry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(dentry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto unlink_out; } @@ -1713,7 +1702,7 @@ out_reval: cifs_inode = CIFS_I(dir); CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ unlink_out: - kfree(full_path); + free_dentry_path(page); kfree(attrs); free_xid(xid); cifs_put_tlink(tlink); @@ -1740,6 +1729,16 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, if (rc) return rc; + if (!S_ISDIR(inode->i_mode)) { + /* + * mkdir succeeded, but another client has managed to remove the + * sucker and replace it with non-directory. Return success, + * but don't leave the child in dcache. + */ + iput(inode); + d_drop(dentry); + return 0; + } /* * setting nlink not necessary except in cases where we failed to get it * from the server or was set bogus. Also, since this is a brand new @@ -1791,7 +1790,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, } } d_instantiate(dentry, inode); - return rc; + return 0; } static int @@ -1866,7 +1865,8 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode, struct tcon_link *tlink; struct cifs_tcon *tcon; struct TCP_Server_Info *server; - char *full_path; + const char *full_path; + void *page; cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n", mode, inode); @@ -1879,9 +1879,10 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode, xid = get_xid(); - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; + page = alloc_dentry_path(); + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto mkdir_out; } @@ -1924,7 +1925,7 @@ mkdir_out: * attributes are invalid now. */ CIFS_I(inode)->time = 0; - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); return rc; @@ -1938,16 +1939,17 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) struct tcon_link *tlink; struct cifs_tcon *tcon; struct TCP_Server_Info *server; - char *full_path = NULL; + const char *full_path; + void *page = alloc_dentry_path(); struct cifsInodeInfo *cifsInode; cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode); xid = get_xid(); - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto rmdir_exit; } @@ -1997,7 +1999,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) current_time(inode); rmdir_exit: - kfree(full_path); + free_dentry_path(page); free_xid(xid); return rc; } @@ -2072,8 +2074,8 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir, struct dentry *source_dentry, struct inode *target_dir, struct dentry *target_dentry, unsigned int flags) { - char *from_name = NULL; - char *to_name = NULL; + const char *from_name, *to_name; + void *page1, *page2; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *tcon; @@ -2091,21 +2093,19 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir, return PTR_ERR(tlink); tcon = tlink_tcon(tlink); + page1 = alloc_dentry_path(); + page2 = alloc_dentry_path(); xid = get_xid(); - /* - * we already have the rename sem so we do not need to - * grab it again here to protect the path integrity - */ - from_name = build_path_from_dentry(source_dentry); - if (from_name == NULL) { - rc = -ENOMEM; + from_name = build_path_from_dentry(source_dentry, page1); + if (IS_ERR(from_name)) { + rc = PTR_ERR(from_name); goto cifs_rename_exit; } - to_name = build_path_from_dentry(target_dentry); - if (to_name == NULL) { - rc = -ENOMEM; + to_name = build_path_from_dentry(target_dentry, page2); + if (IS_ERR(to_name)) { + rc = PTR_ERR(to_name); goto cifs_rename_exit; } @@ -2177,18 +2177,21 @@ unlink_target: cifs_rename_exit: kfree(info_buf_source); - kfree(from_name); - kfree(to_name); + free_dentry_path(page2); + free_dentry_path(page1); free_xid(xid); cifs_put_tlink(tlink); return rc; } static bool -cifs_inode_needs_reval(struct inode *inode) +cifs_dentry_needs_reval(struct dentry *dentry) { + struct inode *inode = d_inode(dentry); struct cifsInodeInfo *cifs_i = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + struct cached_fid *cfid = NULL; if (cifs_i->time == 0) return true; @@ -2199,6 +2202,16 @@ cifs_inode_needs_reval(struct inode *inode) if (!lookupCacheEnabled) return true; + if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) { + mutex_lock(&cfid->fid_mutex); + if (cfid->time && cifs_i->time > cfid->time) { + mutex_unlock(&cfid->fid_mutex); + close_cached_dir(cfid); + return false; + } + mutex_unlock(&cfid->fid_mutex); + close_cached_dir(cfid); + } /* * depending on inode type, check if attribute caching disabled for * files or directories @@ -2297,10 +2310,10 @@ cifs_zap_mapping(struct inode *inode) int cifs_revalidate_file_attr(struct file *filp) { int rc = 0; - struct inode *inode = file_inode(filp); + struct dentry *dentry = file_dentry(filp); struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; - if (!cifs_inode_needs_reval(inode)) + if (!cifs_dentry_needs_reval(dentry)) return rc; if (tlink_tcon(cfile->tlink)->unix_ext) @@ -2317,22 +2330,22 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) int rc = 0; struct inode *inode = d_inode(dentry); struct super_block *sb = dentry->d_sb; - char *full_path = NULL; + const char *full_path; + void *page; int count = 0; if (inode == NULL) return -ENOENT; - if (!cifs_inode_needs_reval(inode)) + if (!cifs_dentry_needs_reval(dentry)) return rc; xid = get_xid(); - /* can not safely grab the rename sem here if rename calls revalidate - since that would deadlock */ - full_path = build_path_from_dentry(dentry); - if (full_path == NULL) { - rc = -ENOMEM; + page = alloc_dentry_path(); + full_path = build_path_from_dentry(dentry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto out; } @@ -2351,7 +2364,7 @@ again: if (rc == -EAGAIN && count++ < 10) goto again; out: - kfree(full_path); + free_dentry_path(page); free_xid(xid); return rc; @@ -2522,7 +2535,7 @@ void cifs_setsize(struct inode *inode, loff_t offset) static int cifs_set_file_size(struct inode *inode, struct iattr *attrs, - unsigned int xid, char *full_path) + unsigned int xid, const char *full_path) { int rc; struct cifsFileInfo *open_file; @@ -2613,7 +2626,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) { int rc; unsigned int xid; - char *full_path = NULL; + const char *full_path; + void *page = alloc_dentry_path(); struct inode *inode = d_inode(direntry); struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -2634,9 +2648,9 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) if (rc < 0) goto out; - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto out; } @@ -2748,7 +2762,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) cifsInode->time = 0; out: kfree(args); - kfree(full_path); + free_dentry_path(page); free_xid(xid); return rc; } @@ -2764,7 +2778,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifsFileInfo *wfile; struct cifs_tcon *tcon; - char *full_path = NULL; + const char *full_path; + void *page = alloc_dentry_path(); int rc = -EACCES; __u32 dosattr = 0; __u64 mode = NO_CHANGE_64; @@ -2778,16 +2793,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid |= ATTR_FORCE; rc = setattr_prepare(&init_user_ns, direntry, attrs); - if (rc < 0) { - free_xid(xid); - return rc; - } + if (rc < 0) + goto cifs_setattr_exit; - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; - free_xid(xid); - return rc; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); + goto cifs_setattr_exit; } /* @@ -2937,8 +2949,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) mark_inode_dirty(inode); cifs_setattr_exit: - kfree(full_path); free_xid(xid); + free_dentry_path(page); return rc; } @@ -2961,12 +2973,3 @@ cifs_setattr(struct user_namespace *mnt_userns, struct dentry *direntry, /* BB: add cifs_setattr_legacy for really old servers */ return rc; } - -#if 0 -void cifs_delete_inode(struct inode *inode) -{ - cifs_dbg(FYI, "In cifs_delete_inode, inode = 0x%p\n", inode); - /* may have to add back in if and when safe distributed caching of - directories added e.g. via FindNotify */ -} -#endif diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index dcde44ff6cf9f3192e1fbb6fc63ecca8d142b5ef..08d99fec593e5194dc483781e055c17dc3809df4 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -42,13 +42,16 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct dentry *dentry = filep->f_path.dentry; - unsigned char *path; + const unsigned char *path; + void *page = alloc_dentry_path(); __le16 *utf16_path = NULL, root_path; int rc = 0; - path = build_path_from_dentry(dentry); - if (path == NULL) - return -ENOMEM; + path = build_path_from_dentry(dentry, page); + if (IS_ERR(path)) { + free_dentry_path(page); + return PTR_ERR(path); + } cifs_dbg(FYI, "%s %s\n", __func__, path); @@ -73,7 +76,7 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, ici_exit: if (utf16_path != &root_path) kfree(utf16_path); - kfree(path); + free_dentry_path(page); return rc; } diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 7c5878a645d93701c01976d6930a10e3a8c54c4c..616e1bc0cc0a05f29c470924c7505959d7d116e2 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, { int rc = -EACCES; unsigned int xid; - char *from_name = NULL; - char *to_name = NULL; + const char *from_name, *to_name; + void *page1, *page2; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifs_tcon *tcon; @@ -524,11 +524,17 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, tcon = tlink_tcon(tlink); xid = get_xid(); + page1 = alloc_dentry_path(); + page2 = alloc_dentry_path(); - from_name = build_path_from_dentry(old_file); - to_name = build_path_from_dentry(direntry); - if ((from_name == NULL) || (to_name == NULL)) { - rc = -ENOMEM; + from_name = build_path_from_dentry(old_file, page1); + if (IS_ERR(from_name)) { + rc = PTR_ERR(from_name); + goto cifs_hl_exit; + } + to_name = build_path_from_dentry(direntry, page2); + if (IS_ERR(to_name)) { + rc = PTR_ERR(to_name); goto cifs_hl_exit; } @@ -587,8 +593,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, } cifs_hl_exit: - kfree(from_name); - kfree(to_name); + free_dentry_path(page1); + free_dentry_path(page2); free_xid(xid); cifs_put_tlink(tlink); return rc; @@ -600,7 +606,8 @@ cifs_get_link(struct dentry *direntry, struct inode *inode, { int rc = -ENOMEM; unsigned int xid; - char *full_path = NULL; + const char *full_path; + void *page; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = NULL; @@ -620,11 +627,13 @@ cifs_get_link(struct dentry *direntry, struct inode *inode, tcon = tlink_tcon(tlink); server = tcon->ses->server; - full_path = build_path_from_dentry(direntry); - if (!full_path) { + page = alloc_dentry_path(); + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { free_xid(xid); cifs_put_tlink(tlink); - return ERR_PTR(-ENOMEM); + free_dentry_path(page); + return ERR_CAST(full_path); } cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); @@ -649,7 +658,7 @@ cifs_get_link(struct dentry *direntry, struct inode *inode, &target_path, reparse_point); } - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); if (rc != 0) { @@ -669,7 +678,8 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode, struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifs_tcon *pTcon; - char *full_path = NULL; + const char *full_path; + void *page = alloc_dentry_path(); struct inode *newinode = NULL; xid = get_xid(); @@ -681,9 +691,9 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode, } pTcon = tlink_tcon(tlink); - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto symlink_exit; } @@ -719,7 +729,7 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode, } } symlink_exit: - kfree(full_path); + free_dentry_path(page); cifs_put_tlink(tlink); free_xid(xid); return rc; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 82e176720ca6a0b3d7babe65b54a8a9c33accb10..c15a90e422be79493e5f848b40756afa129e507e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1180,7 +1180,7 @@ int update_super_prepath(struct cifs_tcon *tcon, char *prefix) kfree(cifs_sb->prepath); if (prefix && *prefix) { - cifs_sb->prepath = kstrndup(prefix, strlen(prefix), GFP_ATOMIC); + cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC); if (!cifs_sb->prepath) { rc = -ENOMEM; goto out; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 80bf4c6f4c7bc7d209e95898b8ec43cb29104424..63bfc533c9fb642237c01d385e5222c2600c95c0 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -119,9 +119,7 @@ retry: /* update inode in place * if both i_ino and i_mode didn't change */ if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid && - (inode->i_mode & S_IFMT) == - (fattr->cf_mode & S_IFMT)) { - cifs_fattr_to_inode(inode, fattr); + cifs_fattr_to_inode(inode, fattr) == 0) { dput(dentry); return; } @@ -384,7 +382,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, static int initiate_cifs_search(const unsigned int xid, struct file *file, - char *full_path) + const char *full_path) { __u16 search_flags; int rc = 0; @@ -704,7 +702,7 @@ static int cifs_save_resume_key(const char *current_entry, */ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, - struct file *file, char *full_path, + struct file *file, const char *full_path, char **current_entry, int *num_to_ret) { __u16 search_flags; @@ -942,13 +940,14 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) char *tmp_buf = NULL; char *end_of_smb; unsigned int max_len; - char *full_path = NULL; + const char *full_path; + void *page = alloc_dentry_path(); xid = get_xid(); - full_path = build_path_from_dentry(file_dentry(file)); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(file_dentry(file), page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto rddir2_exit; } @@ -1043,7 +1042,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) kfree(tmp_buf); rddir2_exit: - kfree(full_path); + free_dentry_path(page); free_xid(xid); return rc; } diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index e31b939e628cc4f8c0d195290f6ed6bdae037a47..3b83839fc2c276d02a5e9e52fdf5f839c2b9465f 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -926,9 +926,7 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon, 0); if (!rc) { - *symlinkinfo = kstrndup(referral.node_name, - strlen(referral.node_name), - GFP_KERNEL); + *symlinkinfo = kstrdup(referral.node_name, GFP_KERNEL); free_dfs_info_param(&referral); if (!*symlinkinfo) rc = -ENOMEM; @@ -1027,7 +1025,7 @@ cifs_can_echo(struct TCP_Server_Info *server) static int cifs_make_node(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, - char *full_path, umode_t mode, dev_t dev) + const char *full_path, umode_t mode, dev_t dev) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct inode *newinode = NULL; diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index a718dc77e604edfe0c91933a435c18a7cd816316..9a61209a283ed572fc7fc06d1ea7e7cc75102cbd 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -512,7 +512,6 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, int rc; struct smb2_file_all_info *smb2_data; __u32 create_options = 0; - bool no_cached_open = tcon->nohandlecache; struct cifsFileInfo *cfile; struct cached_fid *cfid = NULL; @@ -525,11 +524,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, return -ENOMEM; /* If it is a root and its handle is cached then use it */ - if (!strlen(full_path) && !no_cached_open) { - rc = open_shroot(xid, tcon, cifs_sb, &cfid); - if (rc) - goto out; - + rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); + if (!rc) { if (tcon->crfid.file_all_info_is_valid) { move_smb2_info_to_cifs(data, &tcon->crfid.file_all_info); @@ -540,7 +536,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, if (!rc) move_smb2_info_to_cifs(data, smb2_data); } - close_shroot(cfid); + close_cached_dir(cfid); goto out; } diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index aac384f69f74b684900144f2dab1e2d5f7d6156f..06d555d4da9a8c31beb9d848722f1d82fe4dc645 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -667,6 +667,7 @@ smb2_is_valid_lease_break(char *buffer) !memcmp(rsp->LeaseKey, tcon->crfid.fid->lease_key, SMB2_LEASE_KEY_SIZE)) { + tcon->crfid.time = 0; INIT_WORK(&tcon->crfid.lease_break, smb2_cached_lease_break); queue_work(cifsiod_wq, diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index f703204fb185dc584023b2674fdea826d4a6f679..dd0eb665b680c86549418e9044b130ea25ec3261 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -690,17 +690,21 @@ smb2_close_cached_fid(struct kref *ref) cfid->is_valid = false; cfid->file_all_info_is_valid = false; cfid->has_lease = false; + if (cfid->dentry) { + dput(cfid->dentry); + cfid->dentry = NULL; + } } } -void close_shroot(struct cached_fid *cfid) +void close_cached_dir(struct cached_fid *cfid) { mutex_lock(&cfid->fid_mutex); kref_put(&cfid->refcount, smb2_close_cached_fid); mutex_unlock(&cfid->fid_mutex); } -void close_shroot_lease_locked(struct cached_fid *cfid) +void close_cached_dir_lease_locked(struct cached_fid *cfid) { if (cfid->has_lease) { cfid->has_lease = false; @@ -708,10 +712,10 @@ void close_shroot_lease_locked(struct cached_fid *cfid) } } -void close_shroot_lease(struct cached_fid *cfid) +void close_cached_dir_lease(struct cached_fid *cfid) { mutex_lock(&cfid->fid_mutex); - close_shroot_lease_locked(cfid); + close_cached_dir_lease_locked(cfid); mutex_unlock(&cfid->fid_mutex); } @@ -721,13 +725,15 @@ smb2_cached_lease_break(struct work_struct *work) struct cached_fid *cfid = container_of(work, struct cached_fid, lease_break); - close_shroot_lease(cfid); + close_cached_dir_lease(cfid); } /* - * Open the directory at the root of a share + * Open the and cache a directory handle. + * Only supported for the root handle. */ -int open_shroot(unsigned int xid, struct cifs_tcon *tcon, +int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + const char *path, struct cifs_sb_info *cifs_sb, struct cached_fid **cfid) { @@ -745,6 +751,18 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, __le16 utf16_path = 0; /* Null - since an open of top of share */ u8 oplock = SMB2_OPLOCK_LEVEL_II; struct cifs_fid *pfid; + struct dentry *dentry; + + if (tcon->nohandlecache) + return -ENOTSUPP; + + if (cifs_sb->root == NULL) + return -ENOENT; + + if (strlen(path)) + return -ENOENT; + + dentry = cifs_sb->root; mutex_lock(&tcon->crfid.fid_mutex); if (tcon->crfid.is_valid) { @@ -830,11 +848,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, }; /* - * caller expects this func to set pfid to a valid - * cached root, so we copy the existing one and get a - * reference. + * caller expects this func to set the fid in crfid to valid + * cached root, so increment the refcount. */ - memcpy(pfid, tcon->crfid.fid, sizeof(*pfid)); kref_get(&tcon->crfid.refcount); mutex_unlock(&tcon->crfid.fid_mutex); @@ -867,13 +883,18 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId); #endif /* CIFS_DEBUG2 */ - memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); tcon->crfid.tcon = tcon; tcon->crfid.is_valid = true; + tcon->crfid.dentry = dentry; + dget(dentry); kref_init(&tcon->crfid.refcount); /* BB TBD check to see if oplock level check can be removed below */ if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { + /* + * See commit 2f94a3125b87. Increment the refcount when we + * get a lease for root, release it if lease break occurs + */ kref_get(&tcon->crfid.refcount); tcon->crfid.has_lease = true; smb2_parse_contexts(server, o_rsp, @@ -892,6 +913,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, &rsp_iov[1], sizeof(struct smb2_file_all_info), (char *)&tcon->crfid.file_all_info)) tcon->crfid.file_all_info_is_valid = true; + tcon->crfid.time = jiffies; + oshr_exit: mutex_unlock(&tcon->crfid.fid_mutex); @@ -905,6 +928,22 @@ oshr_free: return rc; } +int open_cached_dir_by_dentry(struct cifs_tcon *tcon, + struct dentry *dentry, + struct cached_fid **cfid) +{ + mutex_lock(&tcon->crfid.fid_mutex); + if (tcon->crfid.dentry == dentry) { + cifs_dbg(FYI, "found a cached root file handle by dentry\n"); + *cfid = &tcon->crfid; + kref_get(&tcon->crfid.refcount); + mutex_unlock(&tcon->crfid.fid_mutex); + return 0; + } + mutex_unlock(&tcon->crfid.fid_mutex); + return -ENOENT; +} + static void smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb) @@ -914,7 +953,6 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; - bool no_cached_open = tcon->nohandlecache; struct cached_fid *cfid = NULL; oparms.tcon = tcon; @@ -924,14 +962,12 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - if (no_cached_open) { + rc = open_cached_dir(xid, tcon, "", cifs_sb, &cfid); + if (rc == 0) + memcpy(&fid, cfid->fid, sizeof(struct cifs_fid)); + else rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL, NULL); - } else { - rc = open_shroot(xid, tcon, cifs_sb, &cfid); - if (rc == 0) - memcpy(&fid, cfid->fid, sizeof(struct cifs_fid)); - } if (rc) return; @@ -945,10 +981,10 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, FS_VOLUME_INFORMATION); SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */ - if (no_cached_open) + if (cfid == NULL) SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); else - close_shroot(cfid); + close_cached_dir(cfid); } static void @@ -1531,7 +1567,10 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, NULL, 0 /* no input */, CIFSMaxBufSize, (char **)&res_key, &ret_data_len); - if (rc) { + if (rc == -EOPNOTSUPP) { + pr_warn_once("Server share %s does not support copy range\n", tcon->treeName); + goto req_res_key_exit; + } else if (rc) { cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc); goto req_res_key_exit; } @@ -1763,18 +1802,14 @@ smb2_ioctl_query_info(const unsigned int xid, } iqinf_exit: - kfree(vars); - kfree(buffer); - SMB2_open_free(&rqst[0]); - if (qi.flags & PASSTHRU_FSCTL) - SMB2_ioctl_free(&rqst[1]); - else - SMB2_query_info_free(&rqst[1]); - - SMB2_close_free(&rqst[2]); + cifs_small_buf_release(rqst[0].rq_iov[0].iov_base); + cifs_small_buf_release(rqst[1].rq_iov[0].iov_base); + cifs_small_buf_release(rqst[2].rq_iov[0].iov_base); free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); + kfree(vars); + kfree(buffer); return rc; e_fault: @@ -2217,22 +2252,23 @@ smb3_notify(const unsigned int xid, struct file *pfile, struct smb3_notify notify; struct dentry *dentry = pfile->f_path.dentry; struct inode *inode = file_inode(pfile); - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_open_parms oparms; struct cifs_fid fid; struct cifs_tcon *tcon; - unsigned char *path = NULL; + const unsigned char *path; + void *page = alloc_dentry_path(); __le16 *utf16_path = NULL; u8 oplock = SMB2_OPLOCK_LEVEL_NONE; int rc = 0; - path = build_path_from_dentry(dentry); - if (path == NULL) - return -ENOMEM; - - cifs_sb = CIFS_SB(inode->i_sb); + path = build_path_from_dentry(dentry, page); + if (IS_ERR(path)) { + rc = PTR_ERR(path); + goto notify_exit; + } - utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb); + utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); if (utf16_path == NULL) { rc = -ENOMEM; goto notify_exit; @@ -2264,7 +2300,7 @@ smb3_notify(const unsigned int xid, struct file *pfile, cifs_dbg(FYI, "change notify for path %s rc %d\n", path, rc); notify_exit: - kfree(path); + free_dentry_path(page); kfree(utf16_path); return rc; } @@ -3652,6 +3688,77 @@ out: return rc; } +static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + loff_t off, loff_t len) +{ + int rc; + unsigned int xid; + struct cifsFileInfo *cfile = file->private_data; + __le64 eof; + + xid = get_xid(); + + if (off >= i_size_read(file->f_inode) || + off + len >= i_size_read(file->f_inode)) { + rc = -EINVAL; + goto out; + } + + rc = smb2_copychunk_range(xid, cfile, cfile, off + len, + i_size_read(file->f_inode) - off - len, off); + if (rc < 0) + goto out; + + eof = cpu_to_le64(i_size_read(file->f_inode) - len); + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, cfile->pid, &eof); + if (rc < 0) + goto out; + + rc = 0; + out: + free_xid(xid); + return rc; +} + +static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, + loff_t off, loff_t len) +{ + int rc; + unsigned int xid; + struct cifsFileInfo *cfile = file->private_data; + __le64 eof; + __u64 count; + + xid = get_xid(); + + if (off >= i_size_read(file->f_inode)) { + rc = -EINVAL; + goto out; + } + + count = i_size_read(file->f_inode) - off; + eof = cpu_to_le64(i_size_read(file->f_inode) + len); + + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, cfile->pid, &eof); + if (rc < 0) + goto out; + + rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len); + if (rc < 0) + goto out; + + rc = smb3_zero_range(file, tcon, off, len, 1); + if (rc < 0) + goto out; + + rc = 0; + out: + free_xid(xid); + return rc; +} + static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offset, int whence) { struct cifsFileInfo *wrcfile, *cfile = file->private_data; @@ -3823,6 +3930,10 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, return smb3_zero_range(file, tcon, off, len, false); } else if (mode == FALLOC_FL_KEEP_SIZE) return smb3_simple_falloc(file, tcon, off, len, true); + else if (mode == FALLOC_FL_COLLAPSE_RANGE) + return smb3_collapse_range(file, tcon, off, len); + else if (mode == FALLOC_FL_INSERT_RANGE) + return smb3_insert_range(file, tcon, off, len); else if (mode == 0) return smb3_simple_falloc(file, tcon, off, len, false); @@ -4178,7 +4289,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) } spin_unlock(&cifs_tcp_ses_lock); - return 1; + return -EAGAIN; } /* * Encrypt or decrypt @rqst message. @rqst[0] has the following format: @@ -4968,7 +5079,7 @@ smb2_next_header(char *buf) static int smb2_make_node(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, - char *full_path, umode_t mode, dev_t dev) + const char *full_path, umode_t mode, dev_t dev) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); int rc = -EPERM; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 2199a9bfae8f79b60b35f53e9ea3dc696beb4665..e36c2a8677836ad85c8aa34a76e89a7253e44ae5 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1857,7 +1857,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) return 0; - close_shroot_lease(&tcon->crfid); + close_cached_dir_lease(&tcon->crfid); rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server, (void **) &req, diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index a5a9e33c0d739dbe1c80c97c12e9e4a4b4c1d390..6442dc1c292b4a5be4f71389d65a37962cabf10e 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -144,7 +144,7 @@ struct smb2_transform_hdr { } __packed; /* See MS-SMB2 2.2.42 */ -struct smb2_compression_transform_hdr { +struct smb2_compression_transform_hdr_unchained { __le32 ProtocolId; /* 0xFC 'S' 'M' 'B' */ __le32 OriginalCompressedSegmentSize; __le16 CompressionAlgorithm; @@ -160,10 +160,17 @@ struct compression_payload_header { __le16 CompressionAlgorithm; __le16 Flags; __le32 Length; /* length of compressed playload including field below if present */ - /* __le32 OriginalPayloadSize; */ /* optional */ + /* __le32 OriginalPayloadSize; */ /* optional, present when LZNT1, LZ77, LZ77+Huffman */ } __packed; /* See MS-SMB2 2.2.42.2 */ +struct smb2_compression_transform_hdr_chained { + __le32 ProtocolId; /* 0xFC 'S' 'M' 'B' */ + __le32 OriginalCompressedSegmentSize; + /* struct compression_payload_header[] */ +} __packed; + +/* See MS-SMB2 2.2.42.2.2 */ struct compression_pattern_payload_v1 { __le16 Pattern; __le16 Reserved1; @@ -181,7 +188,11 @@ struct smb2_rdma_transform { __le32 Reserved2; } __packed; -struct smb2_rdma_encryption_transform { +/* TransformType */ +#define SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION 0x0001 +#define SMB2_RDMA_TRANSFORM_TYPE_SIGNING 0x0002 + +struct smb2_rdma_crypto_transform { __le16 TransformType; __le16 SignatureLength; __le16 NonceLength; @@ -409,13 +420,29 @@ struct smb2_netname_neg_context { } __packed; /* - * For rdma transform capabilities context see MS-SMB2 2.2.3.1.6 + * For smb2_transport_capabilities context see MS-SMB2 2.2.3.1.5 * and 2.2.4.1.5 */ +/* Flags */ +#define SMB2_ACCEPT_TRANSFORM_LEVEL_SECURITY 0x00000001 + +struct smb2_transport_capabilities_context { + __le16 ContextType; /* 6 */ + __le16 DataLength; + __u32 Reserved; + __le32 Flags; +} __packed; + +/* + * For rdma transform capabilities context see MS-SMB2 2.2.3.1.6 + * and 2.2.4.1.6 + */ + /* RDMA Transform IDs */ #define SMB2_RDMA_TRANSFORM_NONE 0x0000 #define SMB2_RDMA_TRANSFORM_ENCRYPTION 0x0001 +#define SMB2_RDMA_TRANSFORM_SIGNING 0x0002 struct smb2_rdma_transform_capabilities_context { __le16 ContextType; /* 7 */ @@ -427,6 +454,11 @@ struct smb2_rdma_transform_capabilities_context { __le16 RDMATransformIds[]; } __packed; +/* + * For signing capabilities context see MS-SMB2 2.2.3.1.7 + * and 2.2.4.1.7 + */ + /* Signing algorithms */ #define SIGNING_ALG_HMAC_SHA256 0 #define SIGNING_ALG_AES_CMAC 1 @@ -634,7 +666,8 @@ struct smb2_tree_connect_rsp { #define SHI1005_FLAGS_ENABLE_HASH_V2 0x00004000 #define SHI1005_FLAGS_ENCRYPT_DATA 0x00008000 #define SMB2_SHAREFLAG_IDENTITY_REMOTING 0x00040000 /* 3.1.1 */ -#define SHI1005_FLAGS_ALL 0x0004FF33 +#define SMB2_SHAREFLAG_COMPRESS_DATA 0x00100000 /* 3.1.1 */ +#define SHI1005_FLAGS_ALL 0x0014FF33 /* Possible share capabilities */ #define SMB2_SHARE_CAP_DFS cpu_to_le32(0x00000008) /* all dialects */ @@ -1390,7 +1423,11 @@ struct smb2_lock_req { struct smb2_sync_hdr sync_hdr; __le16 StructureSize; /* Must be 48 */ __le16 LockCount; - __le32 Reserved; + /* + * The least significant four bits are the index, the other 28 bits are + * the lock sequence number (0 to 64). See MS-SMB2 2.2.26 + */ + __le32 LockSequenceNumber; __u64 PersistentFileId; /* opaque endianness */ __u64 VolatileFileId; /* opaque endianness */ /* Followed by at least one */ diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index a2eb34a8d9c910b2aa616ba3cc6c5d145cb54566..a5f87b02cfafac19c40860b9ead20b3b2fc91da3 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -69,12 +69,16 @@ extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, extern int smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid); -extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, - struct cached_fid **cfid); -extern void close_shroot(struct cached_fid *cfid); -extern void close_shroot_lease(struct cached_fid *cfid); -extern void close_shroot_lease_locked(struct cached_fid *cfid); +extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + const char *path, + struct cifs_sb_info *cifs_sb, + struct cached_fid **cfid); +extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon, + struct dentry *dentry, + struct cached_fid **cfid); +extern void close_cached_dir(struct cached_fid *cfid); +extern void close_cached_dir_lease(struct cached_fid *cfid); +extern void close_cached_dir_lease_locked(struct cached_fid *cfid); extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src); extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, diff --git a/fs/cifs/unc.c b/fs/cifs/unc.c index 394aa00cea40e77427be39320652b0b4197a5399..f6fc5e343ea42b1e7e9b7ed4a504c0cc0db9cb6a 100644 --- a/fs/cifs/unc.c +++ b/fs/cifs/unc.c @@ -50,7 +50,6 @@ char *extract_sharename(const char *unc) { const char *src; char *delim, *dst; - int len; /* skip double chars at the beginning */ src = unc + 2; @@ -60,10 +59,9 @@ char *extract_sharename(const char *unc) if (!delim) return ERR_PTR(-EINVAL); delim++; - len = strlen(delim); /* caller has to free the memory */ - dst = kstrndup(delim, len, GFP_KERNEL); + dst = kstrdup(delim, GFP_KERNEL); if (!dst) return ERR_PTR(-ENOMEM); diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 41a611e76bb73f468c00e6cb53a384546954f574..e351b945135bb4e938aff6671804f78e292d2ab1 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -53,7 +53,7 @@ enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT, XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL }; static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon, - struct inode *inode, char *full_path, + struct inode *inode, const char *full_path, const void *value, size_t size) { ssize_t rc = -EOPNOTSUPP; @@ -77,7 +77,7 @@ static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon, } static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon, - struct inode *inode, char *full_path, + struct inode *inode, const char *full_path, const void *value, size_t size) { ssize_t rc = -EOPNOTSUPP; @@ -112,7 +112,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct tcon_link *tlink; struct cifs_tcon *pTcon; - char *full_path; + const char *full_path; + void *page; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) @@ -120,10 +121,11 @@ static int cifs_xattr_set(const struct xattr_handler *handler, pTcon = tlink_tcon(tlink); xid = get_xid(); + page = alloc_dentry_path(); - full_path = build_path_from_dentry(dentry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(dentry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto out; } /* return dos attributes as pseudo xattr */ @@ -235,7 +237,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler, } out: - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); return rc; @@ -297,7 +299,8 @@ static int cifs_xattr_get(const struct xattr_handler *handler, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct tcon_link *tlink; struct cifs_tcon *pTcon; - char *full_path; + const char *full_path; + void *page; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) @@ -305,10 +308,11 @@ static int cifs_xattr_get(const struct xattr_handler *handler, pTcon = tlink_tcon(tlink); xid = get_xid(); + page = alloc_dentry_path(); - full_path = build_path_from_dentry(dentry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(dentry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto out; } @@ -401,7 +405,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler, rc = -EOPNOTSUPP; out: - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); return rc; @@ -414,7 +418,8 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct tcon_link *tlink; struct cifs_tcon *pTcon; - char *full_path; + const char *full_path; + void *page; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) return -EOPNOTSUPP; @@ -425,10 +430,11 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) pTcon = tlink_tcon(tlink); xid = get_xid(); + page = alloc_dentry_path(); - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; + full_path = build_path_from_dentry(direntry, page); + if (IS_ERR(full_path)) { + rc = PTR_ERR(full_path); goto list_ea_exit; } /* return dos attributes as pseudo xattr */ @@ -442,7 +448,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, full_path, NULL, data, buf_size, cifs_sb); list_ea_exit: - kfree(full_path); + free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); return rc; diff --git a/fs/coredump.c b/fs/coredump.c index 1c0fdc1aa70b4a6db13d27f44ac6437f2e158e4f..2868e3e171ae615f9c065ec242e150c6eb5e30aa 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -809,6 +809,16 @@ void do_coredump(const kernel_siginfo_t *siginfo) } file_start_write(cprm.file); core_dumped = binfmt->core_dump(&cprm); + /* + * Ensures that file size is big enough to contain the current + * file postion. This prevents gdb from complaining about + * a truncated file if the last "write" to the file was + * dump_skip. + */ + if (cprm.to_skip) { + cprm.to_skip--; + dump_emit(&cprm, "", 1); + } file_end_write(cprm.file); } if (ispipe && core_pipe_limit) @@ -835,7 +845,7 @@ fail: * do on a core-file: use only these functions to write out all the * necessary info. */ -int dump_emit(struct coredump_params *cprm, const void *addr, int nr) +static int __dump_emit(struct coredump_params *cprm, const void *addr, int nr) { struct file *file = cprm->file; loff_t pos = file->f_pos; @@ -855,9 +865,8 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) return 1; } -EXPORT_SYMBOL(dump_emit); -int dump_skip(struct coredump_params *cprm, size_t nr) +static int __dump_skip(struct coredump_params *cprm, size_t nr) { static char zeroes[PAGE_SIZE]; struct file *file = cprm->file; @@ -869,13 +878,35 @@ int dump_skip(struct coredump_params *cprm, size_t nr) return 1; } else { while (nr > PAGE_SIZE) { - if (!dump_emit(cprm, zeroes, PAGE_SIZE)) + if (!__dump_emit(cprm, zeroes, PAGE_SIZE)) return 0; nr -= PAGE_SIZE; } - return dump_emit(cprm, zeroes, nr); + return __dump_emit(cprm, zeroes, nr); } } + +int dump_emit(struct coredump_params *cprm, const void *addr, int nr) +{ + if (cprm->to_skip) { + if (!__dump_skip(cprm, cprm->to_skip)) + return 0; + cprm->to_skip = 0; + } + return __dump_emit(cprm, addr, nr); +} +EXPORT_SYMBOL(dump_emit); + +void dump_skip_to(struct coredump_params *cprm, unsigned long pos) +{ + cprm->to_skip = pos - cprm->pos; +} +EXPORT_SYMBOL(dump_skip_to); + +void dump_skip(struct coredump_params *cprm, size_t nr) +{ + cprm->to_skip += nr; +} EXPORT_SYMBOL(dump_skip); #ifdef CONFIG_ELF_CORE @@ -902,11 +933,11 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start, stop = !dump_emit(cprm, kaddr, PAGE_SIZE); kunmap_local(kaddr); put_page(page); + if (stop) + return 0; } else { - stop = !dump_skip(cprm, PAGE_SIZE); + dump_skip(cprm, PAGE_SIZE); } - if (stop) - return 0; } return 1; } @@ -914,32 +945,15 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start, int dump_align(struct coredump_params *cprm, int align) { - unsigned mod = cprm->pos & (align - 1); + unsigned mod = (cprm->pos + cprm->to_skip) & (align - 1); if (align & (align - 1)) return 0; - return mod ? dump_skip(cprm, align - mod) : 1; + if (mod) + cprm->to_skip += align - mod; + return 1; } EXPORT_SYMBOL(dump_align); -/* - * Ensures that file size is big enough to contain the current file - * postion. This prevents gdb from complaining about a truncated file - * if the last "write" to the file was dump_skip. - */ -void dump_truncate(struct coredump_params *cprm) -{ - struct file *file = cprm->file; - loff_t offset; - - if (file->f_op->llseek && file->f_op->llseek != no_llseek) { - offset = file->f_op->llseek(file, 0, SEEK_CUR); - if (i_size_read(file->f_mapping->host) < offset) - do_truncate(file_mnt_user_ns(file), file->f_path.dentry, - offset, 0, file); - } -} -EXPORT_SYMBOL(dump_truncate); - /* * The purpose of always_dump_vma() is to make sure that special kernel mappings * that are useful for post-mortem analysis are included in every core dump. diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig index a5f5c30368a203d5c1f901ac00cdf1093ba4834f..2d0c8922f63506ce99f4813cc1c0bd314adeba0f 100644 --- a/fs/crypto/Kconfig +++ b/fs/crypto/Kconfig @@ -14,16 +14,30 @@ config FS_ENCRYPTION F2FS and UBIFS make use of this feature. # Filesystems supporting encryption must select this if FS_ENCRYPTION. This -# allows the algorithms to be built as modules when all the filesystems are. +# allows the algorithms to be built as modules when all the filesystems are, +# whereas selecting them from FS_ENCRYPTION would force them to be built-in. +# +# Note: this option only pulls in the algorithms that filesystem encryption +# needs "by default". If userspace will use "non-default" encryption modes such +# as Adiantum encryption, then those other modes need to be explicitly enabled +# in the crypto API; see Documentation/filesystems/fscrypt.rst for details. +# +# Also note that this option only pulls in the generic implementations of the +# algorithms, not any per-architecture optimized implementations. It is +# strongly recommended to enable optimized implementations too. It is safe to +# disable these generic implementations if corresponding optimized +# implementations will always be available too; for this reason, these are soft +# dependencies ('imply' rather than 'select'). Only disable these generic +# implementations if you're sure they will never be needed, though. config FS_ENCRYPTION_ALGS tristate - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_CTS - select CRYPTO_ECB - select CRYPTO_HMAC - select CRYPTO_SHA512 - select CRYPTO_XTS + imply CRYPTO_AES + imply CRYPTO_CBC + imply CRYPTO_CTS + imply CRYPTO_ECB + imply CRYPTO_HMAC + imply CRYPTO_SHA512 + imply CRYPTO_XTS config FS_ENCRYPTION_INLINE_CRYPT bool "Enable fscrypt to use inline crypto" diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 686e0ad287880c15406a479a3acc209a8fa1396f..9979d981e9beb8f8ad8b84e6a08feaee43c0e786 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -773,7 +773,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - char buf[3]; + char buf[2]; bool val; int r; struct dentry *dentry = F_DENTRY(file); @@ -789,7 +789,6 @@ ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, else buf[0] = 'N'; buf[1] = '\n'; - buf[2] = 0x00; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } EXPORT_SYMBOL_GPL(debugfs_read_file_bool); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 22e86ae4dd5a829ebbef4fbdf346d18315446601..1d252164d97b6f989f1836dc27e69e3dc698abdf 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -35,7 +35,7 @@ static struct vfsmount *debugfs_mount; static int debugfs_mount_count; static bool debugfs_registered; -static unsigned int debugfs_allow = DEFAULT_DEBUGFS_ALLOW_BITS; +static unsigned int debugfs_allow __ro_after_init = DEFAULT_DEBUGFS_ALLOW_BITS; /* * Don't allow access attributes to be changed whilst the kernel is locked down diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 18e9285fbb4c8dc339bd6f9b3d7472621497a31f..7169ea8733472d767e640739f744c0af24bd80c5 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -18,6 +18,7 @@ #include <linux/fs_stack.h> #include <linux/slab.h> #include <linux/xattr.h> +#include <linux/fileattr.h> #include <asm/unaligned.h> #include "ecryptfs_kernel.h" @@ -1118,6 +1119,23 @@ out: return rc; } +static int ecryptfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + return vfs_fileattr_get(ecryptfs_dentry_to_lower(dentry), fa); +} + +static int ecryptfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + int rc; + + rc = vfs_fileattr_set(&init_user_ns, lower_dentry, fa); + fsstack_copy_attr_all(d_inode(dentry), d_inode(lower_dentry)); + + return rc; +} + const struct inode_operations ecryptfs_symlink_iops = { .get_link = ecryptfs_get_link, .permission = ecryptfs_permission, @@ -1139,6 +1157,8 @@ const struct inode_operations ecryptfs_dir_iops = { .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .listxattr = ecryptfs_listxattr, + .fileattr_get = ecryptfs_fileattr_get, + .fileattr_set = ecryptfs_fileattr_set, }; const struct inode_operations ecryptfs_main_iops = { @@ -1146,6 +1166,8 @@ const struct inode_operations ecryptfs_main_iops = { .setattr = ecryptfs_setattr, .getattr = ecryptfs_getattr, .listxattr = ecryptfs_listxattr, + .fileattr_get = ecryptfs_fileattr_get, + .fileattr_set = ecryptfs_fileattr_set, }; static int ecryptfs_xattr_get(const struct xattr_handler *handler, diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index e6bc0302643bb8c6dac0c5975a1e6f99ccf97033..d57ee15874f9d7f894f37ecca7c25d6855477d5d 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@ -106,86 +106,9 @@ out_free: return size; } -static inline unsigned int efivarfs_getflags(struct inode *inode) -{ - unsigned int i_flags; - unsigned int flags = 0; - - i_flags = inode->i_flags; - if (i_flags & S_IMMUTABLE) - flags |= FS_IMMUTABLE_FL; - return flags; -} - -static int -efivarfs_ioc_getxflags(struct file *file, void __user *arg) -{ - struct inode *inode = file->f_mapping->host; - unsigned int flags = efivarfs_getflags(inode); - - if (copy_to_user(arg, &flags, sizeof(flags))) - return -EFAULT; - return 0; -} - -static int -efivarfs_ioc_setxflags(struct file *file, void __user *arg) -{ - struct inode *inode = file->f_mapping->host; - unsigned int flags; - unsigned int i_flags = 0; - unsigned int oldflags = efivarfs_getflags(inode); - int error; - - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; - - if (copy_from_user(&flags, arg, sizeof(flags))) - return -EFAULT; - - if (flags & ~FS_IMMUTABLE_FL) - return -EOPNOTSUPP; - - if (flags & FS_IMMUTABLE_FL) - i_flags |= S_IMMUTABLE; - - - error = mnt_want_write_file(file); - if (error) - return error; - - inode_lock(inode); - - error = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (error) - goto out; - - inode_set_flags(inode, i_flags, S_IMMUTABLE); -out: - inode_unlock(inode); - mnt_drop_write_file(file); - return error; -} - -static long -efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) -{ - void __user *arg = (void __user *)p; - - switch (cmd) { - case FS_IOC_GETFLAGS: - return efivarfs_ioc_getxflags(file, arg); - case FS_IOC_SETFLAGS: - return efivarfs_ioc_setxflags(file, arg); - } - - return -ENOTTY; -} - const struct file_operations efivarfs_file_operations = { .open = simple_open, .read = efivarfs_file_read, .write = efivarfs_file_write, .llseek = no_llseek, - .unlocked_ioctl = efivarfs_file_ioctl, }; diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index 14e2947975fddedb23fab35e64452c4bd4ac99cc..939e5e242b985bd8aa6024bc716c70afb549e492 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -10,9 +10,12 @@ #include <linux/kmemleak.h> #include <linux/slab.h> #include <linux/uuid.h> +#include <linux/fileattr.h> #include "internal.h" +static const struct inode_operations efivarfs_file_inode_operations; + struct inode *efivarfs_get_inode(struct super_block *sb, const struct inode *dir, int mode, dev_t dev, bool is_removable) @@ -26,6 +29,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb, inode->i_flags = is_removable ? 0 : S_IMMUTABLE; switch (mode & S_IFMT) { case S_IFREG: + inode->i_op = &efivarfs_file_inode_operations; inode->i_fop = &efivarfs_file_operations; break; case S_IFDIR: @@ -138,3 +142,43 @@ const struct inode_operations efivarfs_dir_inode_operations = { .unlink = efivarfs_unlink, .create = efivarfs_create, }; + +static int +efivarfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + unsigned int i_flags; + unsigned int flags = 0; + + i_flags = d_inode(dentry)->i_flags; + if (i_flags & S_IMMUTABLE) + flags |= FS_IMMUTABLE_FL; + + fileattr_fill_flags(fa, flags); + + return 0; +} + +static int +efivarfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + unsigned int i_flags = 0; + + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; + + if (fa->flags & ~FS_IMMUTABLE_FL) + return -EOPNOTSUPP; + + if (fa->flags & FS_IMMUTABLE_FL) + i_flags |= S_IMMUTABLE; + + inode_set_flags(d_inode(dentry), i_flags, S_IMMUTABLE); + + return 0; +} + +static const struct inode_operations efivarfs_file_inode_operations = { + .fileattr_get = efivarfs_fileattr_get, + .fileattr_set = efivarfs_fileattr_set, +}; diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig index 74b0aaa7114c238788d9e78ad9a0c9439b368f79..858b3339f381f2347977e414022030d979769f8e 100644 --- a/fs/erofs/Kconfig +++ b/fs/erofs/Kconfig @@ -76,17 +76,3 @@ config EROFS_FS_ZIP If you don't want to enable compression feature, say N. -config EROFS_FS_CLUSTER_PAGE_LIMIT - int "EROFS Cluster Pages Hard Limit" - depends on EROFS_FS_ZIP - range 1 256 - default "1" - help - Indicates maximum # of pages of a compressed - physical cluster. - - For example, if files in a image were compressed - into 8k-unit, hard limit should not be configured - less than 2. Otherwise, the image will be refused - to mount on this kernel. - diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index af159539fc1b221b15d93987aef45c593b80791b..1f9aced49070ac77c2a1907adc5c51bea898c6ee 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_EROFS_FS) += erofs.o -erofs-objs := super.o inode.o data.o namei.o dir.o utils.o +erofs-objs := super.o inode.o data.o namei.o dir.o utils.o pcpubuf.o erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o erofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 1249e74b3bf04267cf2f67dfd5af4596e0e9bdcf..ebac756cb2a38eae0fe6450dc90b3aa4ddb2809d 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -109,21 +109,6 @@ err_out: return err; } -int erofs_map_blocks(struct inode *inode, - struct erofs_map_blocks *map, int flags) -{ - if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) { - int err = z_erofs_map_blocks_iter(inode, map, flags); - - if (map->mpage) { - put_page(map->mpage); - map->mpage = NULL; - } - return err; - } - return erofs_map_blocks_flatmode(inode, map, flags); -} - static inline struct bio *erofs_read_raw_page(struct bio *bio, struct address_space *mapping, struct page *page, @@ -159,7 +144,7 @@ submit_bio_retry: erofs_blk_t blknr; unsigned int blkoff; - err = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW); + err = erofs_map_blocks_flatmode(inode, &map, EROFS_GET_BLOCKS_RAW); if (err) goto err_out; @@ -318,7 +303,7 @@ static sector_t erofs_bmap(struct address_space *mapping, sector_t block) return 0; } - if (!erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW)) + if (!erofs_map_blocks_flatmode(inode, &map, EROFS_GET_BLOCKS_RAW)) return erofs_blknr(map.m_pa); return 0; diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index 1cb1ffd105698594a6b5e1d41f4ae56756e85fb5..88e33addf2298e21903dbab7b8621994479ffbe0 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -28,6 +28,42 @@ struct z_erofs_decompressor { char *name; }; +int z_erofs_load_lz4_config(struct super_block *sb, + struct erofs_super_block *dsb, + struct z_erofs_lz4_cfgs *lz4, int size) +{ + struct erofs_sb_info *sbi = EROFS_SB(sb); + u16 distance; + + if (lz4) { + if (size < sizeof(struct z_erofs_lz4_cfgs)) { + erofs_err(sb, "invalid lz4 cfgs, size=%u", size); + return -EINVAL; + } + distance = le16_to_cpu(lz4->max_distance); + + sbi->lz4.max_pclusterblks = le16_to_cpu(lz4->max_pclusterblks); + if (!sbi->lz4.max_pclusterblks) { + sbi->lz4.max_pclusterblks = 1; /* reserved case */ + } else if (sbi->lz4.max_pclusterblks > + Z_EROFS_PCLUSTER_MAX_SIZE / EROFS_BLKSIZ) { + erofs_err(sb, "too large lz4 pclusterblks %u", + sbi->lz4.max_pclusterblks); + return -EINVAL; + } else if (sbi->lz4.max_pclusterblks >= 2) { + erofs_info(sb, "EXPERIMENTAL big pcluster feature in use. Use at your own risk!"); + } + } else { + distance = le16_to_cpu(dsb->u1.lz4_max_distance); + sbi->lz4.max_pclusterblks = 1; + } + + sbi->lz4.max_distance_pages = distance ? + DIV_ROUND_UP(distance, PAGE_SIZE) + 1 : + LZ4_MAX_DISTANCE_PAGES; + return erofs_pcpubuf_growsize(sbi->lz4.max_pclusterblks); +} + static int z_erofs_lz4_prepare_destpages(struct z_erofs_decompress_req *rq, struct list_head *pagepool) { @@ -36,6 +72,8 @@ static int z_erofs_lz4_prepare_destpages(struct z_erofs_decompress_req *rq, struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL }; unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES, BITS_PER_LONG)] = { 0 }; + unsigned int lz4_max_distance_pages = + EROFS_SB(rq->sb)->lz4.max_distance_pages; void *kaddr = NULL; unsigned int i, j, top; @@ -44,14 +82,14 @@ static int z_erofs_lz4_prepare_destpages(struct z_erofs_decompress_req *rq, struct page *const page = rq->out[i]; struct page *victim; - if (j >= LZ4_MAX_DISTANCE_PAGES) + if (j >= lz4_max_distance_pages) j = 0; /* 'valid' bounced can only be tested after a complete round */ if (test_bit(j, bounced)) { - DBG_BUGON(i < LZ4_MAX_DISTANCE_PAGES); - DBG_BUGON(top >= LZ4_MAX_DISTANCE_PAGES); - availables[top++] = rq->out[i - LZ4_MAX_DISTANCE_PAGES]; + DBG_BUGON(i < lz4_max_distance_pages); + DBG_BUGON(top >= lz4_max_distance_pages); + availables[top++] = rq->out[i - lz4_max_distance_pages]; } if (page) { @@ -73,9 +111,8 @@ static int z_erofs_lz4_prepare_destpages(struct z_erofs_decompress_req *rq, victim = availables[--top]; get_page(victim); } else { - victim = erofs_allocpage(pagepool, GFP_KERNEL); - if (!victim) - return -ENOMEM; + victim = erofs_allocpage(pagepool, + GFP_KERNEL | __GFP_NOFAIL); set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE); } rq->out[i] = victim; @@ -83,96 +120,123 @@ static int z_erofs_lz4_prepare_destpages(struct z_erofs_decompress_req *rq, return kaddr ? 1 : 0; } -static void *generic_copy_inplace_data(struct z_erofs_decompress_req *rq, - u8 *src, unsigned int pageofs_in) +static void *z_erofs_handle_inplace_io(struct z_erofs_decompress_req *rq, + void *inpage, unsigned int *inputmargin, int *maptype, + bool support_0padding) { - /* - * if in-place decompression is ongoing, those decompressed - * pages should be copied in order to avoid being overlapped. - */ - struct page **in = rq->in; - u8 *const tmp = erofs_get_pcpubuf(0); - u8 *tmpp = tmp; - unsigned int inlen = rq->inputsize - pageofs_in; - unsigned int count = min_t(uint, inlen, PAGE_SIZE - pageofs_in); - - while (tmpp < tmp + inlen) { - if (!src) - src = kmap_atomic(*in); - memcpy(tmpp, src + pageofs_in, count); - kunmap_atomic(src); - src = NULL; - tmpp += count; - pageofs_in = 0; - count = PAGE_SIZE; + unsigned int nrpages_in, nrpages_out; + unsigned int ofull, oend, inputsize, total, i, j; + struct page **in; + void *src, *tmp; + + inputsize = rq->inputsize; + nrpages_in = PAGE_ALIGN(inputsize) >> PAGE_SHIFT; + oend = rq->pageofs_out + rq->outputsize; + ofull = PAGE_ALIGN(oend); + nrpages_out = ofull >> PAGE_SHIFT; + + if (rq->inplace_io) { + if (rq->partial_decoding || !support_0padding || + ofull - oend < LZ4_DECOMPRESS_INPLACE_MARGIN(inputsize)) + goto docopy; + + for (i = 0; i < nrpages_in; ++i) { + DBG_BUGON(rq->in[i] == NULL); + for (j = 0; j < nrpages_out - nrpages_in + i; ++j) + if (rq->out[j] == rq->in[i]) + goto docopy; + } + } + + if (nrpages_in <= 1) { + *maptype = 0; + return inpage; + } + kunmap_atomic(inpage); + might_sleep(); + src = erofs_vm_map_ram(rq->in, nrpages_in); + if (!src) + return ERR_PTR(-ENOMEM); + *maptype = 1; + return src; + +docopy: + /* Or copy compressed data which can be overlapped to per-CPU buffer */ + in = rq->in; + src = erofs_get_pcpubuf(nrpages_in); + if (!src) { + DBG_BUGON(1); + kunmap_atomic(inpage); + return ERR_PTR(-EFAULT); + } + + tmp = src; + total = rq->inputsize; + while (total) { + unsigned int page_copycnt = + min_t(unsigned int, total, PAGE_SIZE - *inputmargin); + + if (!inpage) + inpage = kmap_atomic(*in); + memcpy(tmp, inpage + *inputmargin, page_copycnt); + kunmap_atomic(inpage); + inpage = NULL; + tmp += page_copycnt; + total -= page_copycnt; ++in; + *inputmargin = 0; } - return tmp; + *maptype = 2; + return src; } static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out) { - unsigned int inputmargin, inlen; - u8 *src; - bool copied, support_0padding; - int ret; - - if (rq->inputsize > PAGE_SIZE) - return -EOPNOTSUPP; + unsigned int inputmargin; + u8 *headpage, *src; + bool support_0padding; + int ret, maptype; - src = kmap_atomic(*rq->in); + DBG_BUGON(*rq->in == NULL); + headpage = kmap_atomic(*rq->in); inputmargin = 0; support_0padding = false; /* decompression inplace is only safe when 0padding is enabled */ - if (EROFS_SB(rq->sb)->feature_incompat & - EROFS_FEATURE_INCOMPAT_LZ4_0PADDING) { + if (erofs_sb_has_lz4_0padding(EROFS_SB(rq->sb))) { support_0padding = true; - while (!src[inputmargin & ~PAGE_MASK]) + while (!headpage[inputmargin & ~PAGE_MASK]) if (!(++inputmargin & ~PAGE_MASK)) break; if (inputmargin >= rq->inputsize) { - kunmap_atomic(src); + kunmap_atomic(headpage); return -EIO; } } - copied = false; - inlen = rq->inputsize - inputmargin; - if (rq->inplace_io) { - const uint oend = (rq->pageofs_out + - rq->outputsize) & ~PAGE_MASK; - const uint nr = PAGE_ALIGN(rq->pageofs_out + - rq->outputsize) >> PAGE_SHIFT; - - if (rq->partial_decoding || !support_0padding || - rq->out[nr - 1] != rq->in[0] || - rq->inputsize - oend < - LZ4_DECOMPRESS_INPLACE_MARGIN(inlen)) { - src = generic_copy_inplace_data(rq, src, inputmargin); - inputmargin = 0; - copied = true; - } - } + rq->inputsize -= inputmargin; + src = z_erofs_handle_inplace_io(rq, headpage, &inputmargin, &maptype, + support_0padding); + if (IS_ERR(src)) + return PTR_ERR(src); /* legacy format could compress extra data in a pcluster. */ if (rq->partial_decoding || !support_0padding) ret = LZ4_decompress_safe_partial(src + inputmargin, out, - inlen, rq->outputsize, - rq->outputsize); + rq->inputsize, rq->outputsize, rq->outputsize); else ret = LZ4_decompress_safe(src + inputmargin, out, - inlen, rq->outputsize); + rq->inputsize, rq->outputsize); if (ret != rq->outputsize) { erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]", - ret, inlen, inputmargin, rq->outputsize); + ret, rq->inputsize, inputmargin, rq->outputsize); WARN_ON(1); print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET, - 16, 1, src + inputmargin, inlen, true); + 16, 1, src + inputmargin, rq->inputsize, true); print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET, 16, 1, out, rq->outputsize, true); @@ -181,10 +245,16 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out) ret = -EIO; } - if (copied) - erofs_put_pcpubuf(src); - else + if (maptype == 0) { kunmap_atomic(src); + } else if (maptype == 1) { + vm_unmap_ram(src, PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT); + } else if (maptype == 2) { + erofs_put_pcpubuf(src); + } else { + DBG_BUGON(1); + return -EFAULT; + } return ret; } @@ -234,57 +304,51 @@ static int z_erofs_decompress_generic(struct z_erofs_decompress_req *rq, const struct z_erofs_decompressor *alg = decompressors + rq->alg; unsigned int dst_maptype; void *dst; - int ret, i; + int ret; - if (nrpages_out == 1 && !rq->inplace_io) { - DBG_BUGON(!*rq->out); - dst = kmap_atomic(*rq->out); - dst_maptype = 0; - goto dstmap_out; - } + /* two optimized fast paths only for non bigpcluster cases yet */ + if (rq->inputsize <= PAGE_SIZE) { + if (nrpages_out == 1 && !rq->inplace_io) { + DBG_BUGON(!*rq->out); + dst = kmap_atomic(*rq->out); + dst_maptype = 0; + goto dstmap_out; + } - /* - * For the case of small output size (especially much less - * than PAGE_SIZE), memcpy the decompressed data rather than - * compressed data is preferred. - */ - if (rq->outputsize <= PAGE_SIZE * 7 / 8) { - dst = erofs_get_pcpubuf(0); - if (IS_ERR(dst)) - return PTR_ERR(dst); - - rq->inplace_io = false; - ret = alg->decompress(rq, dst); - if (!ret) - copy_from_pcpubuf(rq->out, dst, rq->pageofs_out, - rq->outputsize); - - erofs_put_pcpubuf(dst); - return ret; + /* + * For the case of small output size (especially much less + * than PAGE_SIZE), memcpy the decompressed data rather than + * compressed data is preferred. + */ + if (rq->outputsize <= PAGE_SIZE * 7 / 8) { + dst = erofs_get_pcpubuf(1); + if (IS_ERR(dst)) + return PTR_ERR(dst); + + rq->inplace_io = false; + ret = alg->decompress(rq, dst); + if (!ret) + copy_from_pcpubuf(rq->out, dst, rq->pageofs_out, + rq->outputsize); + + erofs_put_pcpubuf(dst); + return ret; + } } + /* general decoding path which can be used for all cases */ ret = alg->prepare_destpages(rq, pagepool); - if (ret < 0) { + if (ret < 0) return ret; - } else if (ret) { + if (ret) { dst = page_address(*rq->out); dst_maptype = 1; goto dstmap_out; } - i = 0; - while (1) { - dst = vm_map_ram(rq->out, nrpages_out, -1); - - /* retry two more times (totally 3 times) */ - if (dst || ++i >= 3) - break; - vm_unmap_aliases(); - } - + dst = erofs_vm_map_ram(rq->out, nrpages_out); if (!dst) return -ENOMEM; - dst_maptype = 2; dstmap_out: diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index 9ad1615f447437209dd5c7e4a5af00c5b5232907..8739d3adf51f1f9626fd357718cc0e8080877d33 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -18,15 +18,22 @@ * be incompatible with this kernel version. */ #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001 -#define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002 +#define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER 0x00000002 +#define EROFS_ALL_FEATURE_INCOMPAT \ + (EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \ + EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \ + EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER) -/* 128-byte erofs on-disk super block */ +#define EROFS_SB_EXTSLOT_SIZE 16 + +/* erofs on-disk super block (currently 128 bytes) */ struct erofs_super_block { __le32 magic; /* file system magic number */ __le32 checksum; /* crc32c(super_block) */ __le32 feature_compat; __u8 blkszbits; /* support block_size == PAGE_SIZE only */ - __u8 reserved; + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */ __le16 root_nid; /* nid of root directory */ __le64 inos; /* total valid ino # (== f_files - f_favail) */ @@ -39,7 +46,13 @@ struct erofs_super_block { __u8 uuid[16]; /* 128-bit uuid for volume */ __u8 volume_name[16]; /* volume name */ __le32 feature_incompat; - __u8 reserved2[44]; + union { + /* bitmap for available compression algorithms */ + __le16 available_compr_algs; + /* customized sliding window size instead of 64k by default */ + __le16 lz4_max_distance; + } __packed u1; + __u8 reserved2[42]; }; /* @@ -75,6 +88,9 @@ static inline bool erofs_inode_is_data_compressed(unsigned int datamode) #define EROFS_I_VERSION_BIT 0 #define EROFS_I_DATALAYOUT_BIT 1 +#define EROFS_I_ALL \ + ((1 << (EROFS_I_DATALAYOUT_BIT + EROFS_I_DATALAYOUT_BITS)) - 1) + /* 32-byte reduced form of an ondisk inode */ struct erofs_inode_compact { __le16 i_format; /* inode format hints */ @@ -189,20 +205,33 @@ static inline unsigned int erofs_xattr_entry_size(struct erofs_xattr_entry *e) e->e_name_len + le16_to_cpu(e->e_value_size)); } +/* maximum supported size of a physical compression cluster */ +#define Z_EROFS_PCLUSTER_MAX_SIZE (1024 * 1024) + /* available compression algorithm types (for h_algorithmtype) */ enum { Z_EROFS_COMPRESSION_LZ4 = 0, Z_EROFS_COMPRESSION_MAX }; +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1)) + +/* 14 bytes (+ length field = 16 bytes) */ +struct z_erofs_lz4_cfgs { + __le16 max_distance; + __le16 max_pclusterblks; + u8 reserved[10]; +} __packed; /* * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on) * e.g. for 4k logical cluster size, 4B if compacted 2B is off; * (4B) + 2B + (4B) if compacted 2B is on. + * bit 1 : HEAD1 big pcluster (0 - off; 1 - on) + * bit 2 : HEAD2 big pcluster (0 - off; 1 - on) */ -#define Z_EROFS_ADVISE_COMPACTED_2B_BIT 0 - -#define Z_EROFS_ADVISE_COMPACTED_2B (1 << Z_EROFS_ADVISE_COMPACTED_2B_BIT) +#define Z_EROFS_ADVISE_COMPACTED_2B 0x0001 +#define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002 +#define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004 struct z_erofs_map_header { __le32 h_reserved1; @@ -214,9 +243,7 @@ struct z_erofs_map_header { __u8 h_algorithmtype; /* * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096; - * bit 3-4 : (physical - logical) cluster bits of head 1: - * For example, if logical clustersize = 4096, 1 for 8192. - * bit 5-7 : (physical - logical) cluster bits of head 2. + * bit 3-7 : reserved. */ __u8 h_clusterbits; }; @@ -259,6 +286,13 @@ enum { #define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS 2 #define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT 0 +/* + * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the + * compressed block count of a compressed extent (in logical clusters, aka. + * block count of a pcluster). + */ +#define Z_EROFS_VLE_DI_D0_CBLKCNT (1 << 11) + struct z_erofs_vle_decompressed_index { __le16 di_advise; /* where to decompress in the head cluster */ diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c index 119fdce1b5207605286b00e0b9a36dd35042414d..7ed2d73916928445ac9f3d842f7f36f0574529ce 100644 --- a/fs/erofs/inode.c +++ b/fs/erofs/inode.c @@ -44,6 +44,13 @@ static struct page *erofs_read_inode(struct inode *inode, dic = page_address(page) + *ofs; ifmt = le16_to_cpu(dic->i_format); + if (ifmt & ~EROFS_I_ALL) { + erofs_err(inode->i_sb, "unsupported i_format %u of nid %llu", + ifmt, vi->nid); + err = -EOPNOTSUPP; + goto err_out; + } + vi->datalayout = erofs_inode_datalayout(ifmt); if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) { erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu", diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 351dae524a0c9542d4afae678d9e4a54c331423f..f92e3e32b9f484dcf70b0c7705bc7aad561622f2 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -50,6 +50,8 @@ struct erofs_fs_context { #ifdef CONFIG_EROFS_FS_ZIP /* current strategy of how to use managed cache */ unsigned char cache_strategy; + /* strategy of sync decompression (false - auto, true - force on) */ + bool readahead_sync_decompress; /* threshold for decompression synchronously */ unsigned int max_sync_decompress_pages; @@ -57,6 +59,14 @@ struct erofs_fs_context { unsigned int mount_opt; }; +/* all filesystem-wide lz4 configurations */ +struct erofs_sb_lz4_info { + /* # of pages needed for EROFS lz4 rolling decompression */ + u16 max_distance_pages; + /* maximum possible blocks for pclusters in the filesystem */ + u16 max_pclusterblks; +}; + struct erofs_sb_info { #ifdef CONFIG_EROFS_FS_ZIP /* list for all registered superblocks, mainly for shrinker */ @@ -67,9 +77,12 @@ struct erofs_sb_info { struct xarray managed_pslots; unsigned int shrinker_run_no; + u16 available_compr_algs; /* pseudo inode to manage cached pages */ struct inode *managed_cache; + + struct erofs_sb_lz4_info lz4; #endif /* CONFIG_EROFS_FS_ZIP */ u32 blocks; u32 meta_blkaddr; @@ -80,6 +93,7 @@ struct erofs_sb_info { /* inode slot unit size in bit shift */ unsigned char islotbits; + u32 sb_size; /* total superblock size */ u32 build_time_nsec; u64 build_time; @@ -182,12 +196,6 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp) return v; } #endif /* !CONFIG_SMP */ - -/* hard limit of pages per compressed cluster */ -#define Z_EROFS_CLUSTER_MAX_PAGES (CONFIG_EROFS_FS_CLUSTER_PAGE_LIMIT) -#define EROFS_PCPUBUF_NR_PAGES Z_EROFS_CLUSTER_MAX_PAGES -#else -#define EROFS_PCPUBUF_NR_PAGES 0 #endif /* !CONFIG_EROFS_FS_ZIP */ /* we strictly follow PAGE_SIZE and no buffer head yet */ @@ -216,6 +224,17 @@ static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid) return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits); } +#define EROFS_FEATURE_FUNCS(name, compat, feature) \ +static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ +{ \ + return sbi->feature_##compat & EROFS_FEATURE_##feature; \ +} + +EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) +EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) +EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) + /* atomic flag definitions */ #define EROFS_I_EA_INITED_BIT 0 #define EROFS_I_Z_INITED_BIT 1 @@ -244,7 +263,6 @@ struct erofs_inode { unsigned short z_advise; unsigned char z_algorithmtype[2]; unsigned char z_logical_clusterbits; - unsigned char z_physical_clusterbits[2]; }; #endif /* CONFIG_EROFS_FS_ZIP */ }; @@ -287,7 +305,7 @@ extern const struct address_space_operations erofs_raw_access_aops; extern const struct address_space_operations z_erofs_aops; /* - * Logical to physical block mapping, used by erofs_map_blocks() + * Logical to physical block mapping * * Different with other file systems, it is used for 2 access modes: * @@ -334,7 +352,7 @@ struct erofs_map_blocks { struct page *mpage; }; -/* Flags used by erofs_map_blocks() */ +/* Flags used by erofs_map_blocks_flatmode() */ #define EROFS_GET_BLOCKS_RAW 0x0001 /* zmap.c */ @@ -356,8 +374,6 @@ static inline int z_erofs_map_blocks_iter(struct inode *inode, /* data.c */ struct page *erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr); -int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int); - /* inode.c */ static inline unsigned long erofs_inode_hash(erofs_nid_t nid) { @@ -386,23 +402,30 @@ int erofs_namei(struct inode *dir, struct qstr *name, /* dir.c */ extern const struct file_operations erofs_dir_fops; -/* utils.c / zdata.c */ -struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp); - -#if (EROFS_PCPUBUF_NR_PAGES > 0) -void *erofs_get_pcpubuf(unsigned int pagenr); -#define erofs_put_pcpubuf(buf) do { \ - (void)&(buf); \ - preempt_enable(); \ -} while (0) -#else -static inline void *erofs_get_pcpubuf(unsigned int pagenr) +static inline void *erofs_vm_map_ram(struct page **pages, unsigned int count) { - return ERR_PTR(-EOPNOTSUPP); + int retried = 0; + + while (1) { + void *p = vm_map_ram(pages, count, -1); + + /* retry two more times (totally 3 times) */ + if (p || ++retried >= 3) + return p; + vm_unmap_aliases(); + } + return NULL; } -#define erofs_put_pcpubuf(buf) do {} while (0) -#endif +/* pcpubuf.c */ +void *erofs_get_pcpubuf(unsigned int requiredpages); +void erofs_put_pcpubuf(void *ptr); +int erofs_pcpubuf_growsize(unsigned int nrpages); +void erofs_pcpubuf_init(void); +void erofs_pcpubuf_exit(void); + +/* utils.c / zdata.c */ +struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp); #ifdef CONFIG_EROFS_FS_ZIP int erofs_workgroup_put(struct erofs_workgroup *grp); @@ -421,6 +444,9 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, struct erofs_workgroup *egrp); int erofs_try_to_free_cached_page(struct address_space *mapping, struct page *page); +int z_erofs_load_lz4_config(struct super_block *sb, + struct erofs_super_block *dsb, + struct z_erofs_lz4_cfgs *lz4, int len); #else static inline void erofs_shrinker_register(struct super_block *sb) {} static inline void erofs_shrinker_unregister(struct super_block *sb) {} @@ -428,6 +454,16 @@ static inline int erofs_init_shrinker(void) { return 0; } static inline void erofs_exit_shrinker(void) {} static inline int z_erofs_init_zip_subsystem(void) { return 0; } static inline void z_erofs_exit_zip_subsystem(void) {} +static inline int z_erofs_load_lz4_config(struct super_block *sb, + struct erofs_super_block *dsb, + struct z_erofs_lz4_cfgs *lz4, int len) +{ + if (lz4 || dsb->u1.lz4_max_distance) { + erofs_err(sb, "lz4 algorithm isn't enabled"); + return -EINVAL; + } + return 0; +} #endif /* !CONFIG_EROFS_FS_ZIP */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ diff --git a/fs/erofs/pcpubuf.c b/fs/erofs/pcpubuf.c new file mode 100644 index 0000000000000000000000000000000000000000..6c885575128ac1a4d9512832771815f4c0ccb847 --- /dev/null +++ b/fs/erofs/pcpubuf.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) Gao Xiang <xiang@kernel.org> + * + * For low-latency decompression algorithms (e.g. lz4), reserve consecutive + * per-CPU virtual memory (in pages) in advance to store such inplace I/O + * data if inplace decompression is failed (due to unmet inplace margin for + * example). + */ +#include "internal.h" + +struct erofs_pcpubuf { + raw_spinlock_t lock; + void *ptr; + struct page **pages; + unsigned int nrpages; +}; + +static DEFINE_PER_CPU(struct erofs_pcpubuf, erofs_pcb); + +void *erofs_get_pcpubuf(unsigned int requiredpages) + __acquires(pcb->lock) +{ + struct erofs_pcpubuf *pcb = &get_cpu_var(erofs_pcb); + + raw_spin_lock(&pcb->lock); + /* check if the per-CPU buffer is too small */ + if (requiredpages > pcb->nrpages) { + raw_spin_unlock(&pcb->lock); + put_cpu_var(erofs_pcb); + /* (for sparse checker) pretend pcb->lock is still taken */ + __acquire(pcb->lock); + return NULL; + } + return pcb->ptr; +} + +void erofs_put_pcpubuf(void *ptr) __releases(pcb->lock) +{ + struct erofs_pcpubuf *pcb = &per_cpu(erofs_pcb, smp_processor_id()); + + DBG_BUGON(pcb->ptr != ptr); + raw_spin_unlock(&pcb->lock); + put_cpu_var(erofs_pcb); +} + +/* the next step: support per-CPU page buffers hotplug */ +int erofs_pcpubuf_growsize(unsigned int nrpages) +{ + static DEFINE_MUTEX(pcb_resize_mutex); + static unsigned int pcb_nrpages; + LIST_HEAD(pagepool); + int delta, cpu, ret, i; + + mutex_lock(&pcb_resize_mutex); + delta = nrpages - pcb_nrpages; + ret = 0; + /* avoid shrinking pcpubuf, since no idea how many fses rely on */ + if (delta <= 0) + goto out; + + for_each_possible_cpu(cpu) { + struct erofs_pcpubuf *pcb = &per_cpu(erofs_pcb, cpu); + struct page **pages, **oldpages; + void *ptr, *old_ptr; + + pages = kmalloc_array(nrpages, sizeof(*pages), GFP_KERNEL); + if (!pages) { + ret = -ENOMEM; + break; + } + + for (i = 0; i < nrpages; ++i) { + pages[i] = erofs_allocpage(&pagepool, GFP_KERNEL); + if (!pages[i]) { + ret = -ENOMEM; + oldpages = pages; + goto free_pagearray; + } + } + ptr = vmap(pages, nrpages, VM_MAP, PAGE_KERNEL); + if (!ptr) { + ret = -ENOMEM; + oldpages = pages; + goto free_pagearray; + } + raw_spin_lock(&pcb->lock); + old_ptr = pcb->ptr; + pcb->ptr = ptr; + oldpages = pcb->pages; + pcb->pages = pages; + i = pcb->nrpages; + pcb->nrpages = nrpages; + raw_spin_unlock(&pcb->lock); + + if (!oldpages) { + DBG_BUGON(old_ptr); + continue; + } + + if (old_ptr) + vunmap(old_ptr); +free_pagearray: + while (i) + list_add(&oldpages[--i]->lru, &pagepool); + kfree(oldpages); + if (ret) + break; + } + pcb_nrpages = nrpages; + put_pages_list(&pagepool); +out: + mutex_unlock(&pcb_resize_mutex); + return ret; +} + +void erofs_pcpubuf_init(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct erofs_pcpubuf *pcb = &per_cpu(erofs_pcb, cpu); + + raw_spin_lock_init(&pcb->lock); + } +} + +void erofs_pcpubuf_exit(void) +{ + int cpu, i; + + for_each_possible_cpu(cpu) { + struct erofs_pcpubuf *pcb = &per_cpu(erofs_pcb, cpu); + + if (pcb->ptr) { + vunmap(pcb->ptr); + pcb->ptr = NULL; + } + if (!pcb->pages) + continue; + + for (i = 0; i < pcb->nrpages; ++i) + if (pcb->pages[i]) + put_page(pcb->pages[i]); + kfree(pcb->pages); + pcb->pages = NULL; + } +} diff --git a/fs/erofs/super.c b/fs/erofs/super.c index d5a6b9b888a562bae6b30e80162be2bea7f7fc55..bbf3bbd908e0816e4d4d894a69431c58f0c95b3f 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -122,6 +122,136 @@ static bool check_layout_compatibility(struct super_block *sb, return true; } +#ifdef CONFIG_EROFS_FS_ZIP +/* read variable-sized metadata, offset will be aligned by 4-byte */ +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep, + erofs_off_t *offset, int *lengthp) +{ + struct page *page = *pagep; + u8 *buffer, *ptr; + int len, i, cnt; + erofs_blk_t blk; + + *offset = round_up(*offset, 4); + blk = erofs_blknr(*offset); + + if (!page || page->index != blk) { + if (page) { + unlock_page(page); + put_page(page); + } + page = erofs_get_meta_page(sb, blk); + if (IS_ERR(page)) + goto err_nullpage; + } + + ptr = kmap(page); + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]); + if (!len) + len = U16_MAX + 1; + buffer = kmalloc(len, GFP_KERNEL); + if (!buffer) { + buffer = ERR_PTR(-ENOMEM); + goto out; + } + *offset += sizeof(__le16); + *lengthp = len; + + for (i = 0; i < len; i += cnt) { + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i); + blk = erofs_blknr(*offset); + + if (!page || page->index != blk) { + if (page) { + kunmap(page); + unlock_page(page); + put_page(page); + } + page = erofs_get_meta_page(sb, blk); + if (IS_ERR(page)) { + kfree(buffer); + goto err_nullpage; + } + ptr = kmap(page); + } + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt); + *offset += cnt; + } +out: + kunmap(page); + *pagep = page; + return buffer; +err_nullpage: + *pagep = NULL; + return page; +} + +static int erofs_load_compr_cfgs(struct super_block *sb, + struct erofs_super_block *dsb) +{ + struct erofs_sb_info *sbi; + struct page *page; + unsigned int algs, alg; + erofs_off_t offset; + int size, ret; + + sbi = EROFS_SB(sb); + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs); + + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) { + erofs_err(sb, "try to load compressed fs with unsupported algorithms %x", + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS); + return -EINVAL; + } + + offset = EROFS_SUPER_OFFSET + sbi->sb_size; + page = NULL; + alg = 0; + ret = 0; + + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) { + void *data; + + if (!(algs & 1)) + continue; + + data = erofs_read_metadata(sb, &page, &offset, &size); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + goto err; + } + + switch (alg) { + case Z_EROFS_COMPRESSION_LZ4: + ret = z_erofs_load_lz4_config(sb, dsb, data, size); + break; + default: + DBG_BUGON(1); + ret = -EFAULT; + } + kfree(data); + if (ret) + goto err; + } +err: + if (page) { + unlock_page(page); + put_page(page); + } + return ret; +} +#else +static int erofs_load_compr_cfgs(struct super_block *sb, + struct erofs_super_block *dsb) +{ + if (dsb->u1.available_compr_algs) { + erofs_err(sb, "try to load compressed fs when compression is disabled"); + return -EINVAL; + } + return 0; +} +#endif + static int erofs_read_superblock(struct super_block *sb) { struct erofs_sb_info *sbi; @@ -149,7 +279,7 @@ static int erofs_read_superblock(struct super_block *sb) } sbi->feature_compat = le32_to_cpu(dsb->feature_compat); - if (sbi->feature_compat & EROFS_FEATURE_COMPAT_SB_CHKSUM) { + if (erofs_sb_has_sb_chksum(sbi)) { ret = erofs_superblock_csum_verify(sb, data); if (ret) goto out; @@ -166,6 +296,12 @@ static int erofs_read_superblock(struct super_block *sb) if (!check_layout_compatibility(sb, dsb)) goto out; + sbi->sb_size = 128 + dsb->sb_extslots * EROFS_SB_EXTSLOT_SIZE; + if (sbi->sb_size > EROFS_BLKSIZ) { + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)", + sbi->sb_size); + goto out; + } sbi->blocks = le32_to_cpu(dsb->blocks); sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr); #ifdef CONFIG_EROFS_FS_XATTR @@ -187,7 +323,12 @@ static int erofs_read_superblock(struct super_block *sb) ret = -EFSCORRUPTED; goto out; } - ret = 0; + + /* parse on-disk compression configurations */ + if (erofs_sb_has_compr_cfgs(sbi)) + ret = erofs_load_compr_cfgs(sb, dsb); + else + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0); out: kunmap(page); put_page(page); @@ -200,6 +341,7 @@ static void erofs_default_options(struct erofs_fs_context *ctx) #ifdef CONFIG_EROFS_FS_ZIP ctx->cache_strategy = EROFS_ZIP_CACHE_READAROUND; ctx->max_sync_decompress_pages = 3; + ctx->readahead_sync_decompress = false; #endif #ifdef CONFIG_EROFS_FS_XATTR set_opt(ctx, XATTR_USER); @@ -513,6 +655,7 @@ static int __init erofs_module_init(void) if (err) goto shrinker_err; + erofs_pcpubuf_init(); err = z_erofs_init_zip_subsystem(); if (err) goto zip_err; @@ -542,6 +685,7 @@ static void __exit erofs_module_exit(void) /* Ensure all RCU free inodes are safe before cache is destroyed. */ rcu_barrier(); kmem_cache_destroy(erofs_inode_cachep); + erofs_pcpubuf_exit(); } /* get filesystem statistics */ diff --git a/fs/erofs/utils.c b/fs/erofs/utils.c index de9986d2f82fd5f46b16c90e14fbb4024569e9fa..6758c5b19f7cf8f05dec69b9e2e05edd453df535 100644 --- a/fs/erofs/utils.c +++ b/fs/erofs/utils.c @@ -21,18 +21,6 @@ struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp) return page; } -#if (EROFS_PCPUBUF_NR_PAGES > 0) -static struct { - u8 data[PAGE_SIZE * EROFS_PCPUBUF_NR_PAGES]; -} ____cacheline_aligned_in_smp erofs_pcpubuf[NR_CPUS]; - -void *erofs_get_pcpubuf(unsigned int pagenr) -{ - preempt_disable(); - return &erofs_pcpubuf[smp_processor_id()].data[pagenr * PAGE_SIZE]; -} -#endif - #ifdef CONFIG_EROFS_FS_ZIP /* global shrink count (for all mounted EROFS instances) */ static atomic_long_t erofs_global_shrink_cnt; diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 3851e1a64f730d115d57682699d7ab5f77674e60..78e4b598eccafc490d05b3887f6ee8c2db16d646 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -10,6 +10,93 @@ #include <trace/events/erofs.h> +/* + * since pclustersize is variable for big pcluster feature, introduce slab + * pools implementation for different pcluster sizes. + */ +struct z_erofs_pcluster_slab { + struct kmem_cache *slab; + unsigned int maxpages; + char name[48]; +}; + +#define _PCLP(n) { .maxpages = n } + +static struct z_erofs_pcluster_slab pcluster_pool[] __read_mostly = { + _PCLP(1), _PCLP(4), _PCLP(16), _PCLP(64), _PCLP(128), + _PCLP(Z_EROFS_PCLUSTER_MAX_PAGES) +}; + +static void z_erofs_destroy_pcluster_pool(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) { + if (!pcluster_pool[i].slab) + continue; + kmem_cache_destroy(pcluster_pool[i].slab); + pcluster_pool[i].slab = NULL; + } +} + +static int z_erofs_create_pcluster_pool(void) +{ + struct z_erofs_pcluster_slab *pcs; + struct z_erofs_pcluster *a; + unsigned int size; + + for (pcs = pcluster_pool; + pcs < pcluster_pool + ARRAY_SIZE(pcluster_pool); ++pcs) { + size = struct_size(a, compressed_pages, pcs->maxpages); + + sprintf(pcs->name, "erofs_pcluster-%u", pcs->maxpages); + pcs->slab = kmem_cache_create(pcs->name, size, 0, + SLAB_RECLAIM_ACCOUNT, NULL); + if (pcs->slab) + continue; + + z_erofs_destroy_pcluster_pool(); + return -ENOMEM; + } + return 0; +} + +static struct z_erofs_pcluster *z_erofs_alloc_pcluster(unsigned int nrpages) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) { + struct z_erofs_pcluster_slab *pcs = pcluster_pool + i; + struct z_erofs_pcluster *pcl; + + if (nrpages > pcs->maxpages) + continue; + + pcl = kmem_cache_zalloc(pcs->slab, GFP_NOFS); + if (!pcl) + return ERR_PTR(-ENOMEM); + pcl->pclusterpages = nrpages; + return pcl; + } + return ERR_PTR(-EINVAL); +} + +static void z_erofs_free_pcluster(struct z_erofs_pcluster *pcl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) { + struct z_erofs_pcluster_slab *pcs = pcluster_pool + i; + + if (pcl->pclusterpages > pcs->maxpages) + continue; + + kmem_cache_free(pcs->slab, pcl); + return; + } + DBG_BUGON(1); +} + /* * a compressed_pages[] placeholder in order to avoid * being filled with file pages for in-place decompression. @@ -37,12 +124,11 @@ typedef tagptr1_t compressed_page_t; tagptr_fold(compressed_page_t, page, 1) static struct workqueue_struct *z_erofs_workqueue __read_mostly; -static struct kmem_cache *pcluster_cachep __read_mostly; void z_erofs_exit_zip_subsystem(void) { destroy_workqueue(z_erofs_workqueue); - kmem_cache_destroy(pcluster_cachep); + z_erofs_destroy_pcluster_pool(); } static inline int z_erofs_init_workqueue(void) @@ -59,32 +145,16 @@ static inline int z_erofs_init_workqueue(void) return z_erofs_workqueue ? 0 : -ENOMEM; } -static void z_erofs_pcluster_init_once(void *ptr) -{ - struct z_erofs_pcluster *pcl = ptr; - struct z_erofs_collection *cl = z_erofs_primarycollection(pcl); - unsigned int i; - - mutex_init(&cl->lock); - cl->nr_pages = 0; - cl->vcnt = 0; - for (i = 0; i < Z_EROFS_CLUSTER_MAX_PAGES; ++i) - pcl->compressed_pages[i] = NULL; -} - int __init z_erofs_init_zip_subsystem(void) { - pcluster_cachep = kmem_cache_create("erofs_compress", - Z_EROFS_WORKGROUP_SIZE, 0, - SLAB_RECLAIM_ACCOUNT, - z_erofs_pcluster_init_once); - if (pcluster_cachep) { - if (!z_erofs_init_workqueue()) - return 0; - - kmem_cache_destroy(pcluster_cachep); - } - return -ENOMEM; + int err = z_erofs_create_pcluster_pool(); + + if (err) + return err; + err = z_erofs_init_workqueue(); + if (err) + z_erofs_destroy_pcluster_pool(); + return err; } enum z_erofs_collectmode { @@ -104,6 +174,12 @@ enum z_erofs_collectmode { * |_______PRIMARY_FOLLOWED_______|________PRIMARY_HOOKED___________| */ COLLECT_PRIMARY_HOOKED, + /* + * a weak form of COLLECT_PRIMARY_FOLLOWED, the difference is that it + * could be dispatched into bypass queue later due to uptodated managed + * pages. All related online pages cannot be reused for inplace I/O (or + * pagevec) since it can be directly decoded without I/O submission. + */ COLLECT_PRIMARY_FOLLOWED_NOINPLACE, /* * The current collection has been linked with the owned chain, and @@ -128,7 +204,8 @@ struct z_erofs_collector { struct z_erofs_pcluster *pcl, *tailpcl; struct z_erofs_collection *cl; - struct page **compressedpages; + /* a pointer used to pick up inplace I/O pages */ + struct page **icpage_ptr; z_erofs_next_pcluster_t owned_head; enum z_erofs_collectmode mode; @@ -162,18 +239,19 @@ static void preload_compressed_pages(struct z_erofs_collector *clt, enum z_erofs_cache_alloctype type, struct list_head *pagepool) { - const struct z_erofs_pcluster *pcl = clt->pcl; - const unsigned int clusterpages = BIT(pcl->clusterbits); - struct page **pages = clt->compressedpages; - pgoff_t index = pcl->obj.index + (pages - pcl->compressed_pages); + struct z_erofs_pcluster *pcl = clt->pcl; bool standalone = true; gfp_t gfp = (mapping_gfp_mask(mc) & ~__GFP_DIRECT_RECLAIM) | __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN; + struct page **pages; + pgoff_t index; if (clt->mode < COLLECT_PRIMARY_FOLLOWED) return; - for (; pages < pcl->compressed_pages + clusterpages; ++pages) { + pages = pcl->compressed_pages; + index = pcl->obj.index; + for (; index < pcl->obj.index + pcl->pclusterpages; ++index, ++pages) { struct page *page; compressed_page_t t; struct page *newpage = NULL; @@ -186,21 +264,25 @@ static void preload_compressed_pages(struct z_erofs_collector *clt, if (page) { t = tag_compressed_page_justfound(page); - } else if (type == DELAYEDALLOC) { - t = tagptr_init(compressed_page_t, PAGE_UNALLOCATED); - } else if (type == TRYALLOC) { - newpage = erofs_allocpage(pagepool, gfp); - if (!newpage) - goto dontalloc; - - set_page_private(newpage, Z_EROFS_PREALLOCATED_PAGE); - t = tag_compressed_page_justfound(newpage); - } else { /* DONTALLOC */ -dontalloc: - if (standalone) - clt->compressedpages = pages; + } else { + /* I/O is needed, no possible to decompress directly */ standalone = false; - continue; + switch (type) { + case DELAYEDALLOC: + t = tagptr_init(compressed_page_t, + PAGE_UNALLOCATED); + break; + case TRYALLOC: + newpage = erofs_allocpage(pagepool, gfp); + if (!newpage) + continue; + set_page_private(newpage, + Z_EROFS_PREALLOCATED_PAGE); + t = tag_compressed_page_justfound(newpage); + break; + default: /* DONTALLOC */ + continue; + } } if (!cmpxchg_relaxed(pages, NULL, tagptr_cast_ptr(t))) @@ -214,7 +296,11 @@ dontalloc: } } - if (standalone) /* downgrade to PRIMARY_FOLLOWED_NOINPLACE */ + /* + * don't do inplace I/O if all compressed pages are available in + * managed cache since it can be moved to the bypass queue instead. + */ + if (standalone) clt->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE; } @@ -225,14 +311,13 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, struct z_erofs_pcluster *const pcl = container_of(grp, struct z_erofs_pcluster, obj); struct address_space *const mapping = MNGD_MAPPING(sbi); - const unsigned int clusterpages = BIT(pcl->clusterbits); int i; /* * refcount of workgroup is now freezed as 1, * therefore no need to worry about available decompression users. */ - for (i = 0; i < clusterpages; ++i) { + for (i = 0; i < pcl->pclusterpages; ++i) { struct page *page = pcl->compressed_pages[i]; if (!page) @@ -257,13 +342,12 @@ int erofs_try_to_free_cached_page(struct address_space *mapping, struct page *page) { struct z_erofs_pcluster *const pcl = (void *)page_private(page); - const unsigned int clusterpages = BIT(pcl->clusterbits); int ret = 0; /* 0 - busy */ if (erofs_workgroup_try_to_freeze(&pcl->obj, 1)) { unsigned int i; - for (i = 0; i < clusterpages; ++i) { + for (i = 0; i < pcl->pclusterpages; ++i) { if (pcl->compressed_pages[i] == page) { WRITE_ONCE(pcl->compressed_pages[i], NULL); ret = 1; @@ -279,16 +363,14 @@ int erofs_try_to_free_cached_page(struct address_space *mapping, } /* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */ -static inline bool z_erofs_try_inplace_io(struct z_erofs_collector *clt, - struct page *page) +static bool z_erofs_try_inplace_io(struct z_erofs_collector *clt, + struct page *page) { struct z_erofs_pcluster *const pcl = clt->pcl; - const unsigned int clusterpages = BIT(pcl->clusterbits); - while (clt->compressedpages < pcl->compressed_pages + clusterpages) { - if (!cmpxchg(clt->compressedpages++, NULL, page)) + while (clt->icpage_ptr > pcl->compressed_pages) + if (!cmpxchg(--clt->icpage_ptr, NULL, page)) return true; - } return false; } @@ -399,10 +481,10 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, struct erofs_workgroup *grp; int err; - /* no available workgroup, let's allocate one */ - pcl = kmem_cache_alloc(pcluster_cachep, GFP_NOFS); - if (!pcl) - return -ENOMEM; + /* no available pcluster, let's allocate one */ + pcl = z_erofs_alloc_pcluster(map->m_plen >> PAGE_SHIFT); + if (IS_ERR(pcl)) + return PTR_ERR(pcl); atomic_set(&pcl->obj.refcount, 1); pcl->obj.index = map->m_pa >> PAGE_SHIFT; @@ -416,25 +498,18 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, else pcl->algorithmformat = Z_EROFS_COMPRESSION_SHIFTED; - pcl->clusterbits = EROFS_I(inode)->z_physical_clusterbits[0]; - pcl->clusterbits -= PAGE_SHIFT; - /* new pclusters should be claimed as type 1, primary and followed */ pcl->next = clt->owned_head; clt->mode = COLLECT_PRIMARY_FOLLOWED; cl = z_erofs_primarycollection(pcl); - - /* must be cleaned before freeing to slab */ - DBG_BUGON(cl->nr_pages); - DBG_BUGON(cl->vcnt); - cl->pageofs = map->m_la & ~PAGE_MASK; /* * lock all primary followed works before visible to others * and mutex_trylock *never* fails for a new pcluster. */ + mutex_init(&cl->lock); DBG_BUGON(!mutex_trylock(&cl->lock)); grp = erofs_insert_workgroup(inode->i_sb, &pcl->obj); @@ -458,7 +533,7 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, err_out: mutex_unlock(&cl->lock); - kmem_cache_free(pcluster_cachep, pcl); + z_erofs_free_pcluster(pcl); return err; } @@ -502,9 +577,8 @@ out: z_erofs_pagevec_ctor_init(&clt->vector, Z_EROFS_NR_INLINE_PAGEVECS, clt->cl->pagevec, clt->cl->vcnt); - clt->compressedpages = clt->pcl->compressed_pages; - if (clt->mode <= COLLECT_PRIMARY) /* cannot do in-place I/O */ - clt->compressedpages += Z_EROFS_CLUSTER_MAX_PAGES; + /* since file-backed online pages are traversed in reverse order */ + clt->icpage_ptr = clt->pcl->compressed_pages + clt->pcl->pclusterpages; return 0; } @@ -517,9 +591,8 @@ static void z_erofs_rcu_callback(struct rcu_head *head) struct z_erofs_collection *const cl = container_of(head, struct z_erofs_collection, rcu); - kmem_cache_free(pcluster_cachep, - container_of(cl, struct z_erofs_pcluster, - primary_collection)); + z_erofs_free_pcluster(container_of(cl, struct z_erofs_pcluster, + primary_collection)); } void erofs_workgroup_free_rcu(struct erofs_workgroup *grp) @@ -706,9 +779,12 @@ err_out: goto out; } +static void z_erofs_decompressqueue_work(struct work_struct *work); static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, bool sync, int bios) { + struct erofs_sb_info *const sbi = EROFS_SB(io->sb); + /* wake up the caller thread for sync decompression */ if (sync) { unsigned long flags; @@ -720,8 +796,15 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, return; } - if (!atomic_add_return(bios, &io->pending_bios)) + if (atomic_add_return(bios, &io->pending_bios)) + return; + /* Use workqueue and sync decompression for atomic contexts only */ + if (in_atomic() || irqs_disabled()) { queue_work(z_erofs_workqueue, &io->u.work); + sbi->ctx.readahead_sync_decompress = true; + return; + } + z_erofs_decompressqueue_work(&io->u.work); } static bool z_erofs_page_is_invalidated(struct page *page) @@ -761,9 +844,8 @@ static int z_erofs_decompress_pcluster(struct super_block *sb, struct list_head *pagepool) { struct erofs_sb_info *const sbi = EROFS_SB(sb); - const unsigned int clusterpages = BIT(pcl->clusterbits); struct z_erofs_pagevec_ctor ctor; - unsigned int i, outputsize, llen, nr_pages; + unsigned int i, inputsize, outputsize, llen, nr_pages; struct page *pages_onstack[Z_EROFS_VMAP_ONSTACK_PAGES]; struct page **pages, **compressed_pages, *page; @@ -843,7 +925,7 @@ static int z_erofs_decompress_pcluster(struct super_block *sb, overlapped = false; compressed_pages = pcl->compressed_pages; - for (i = 0; i < clusterpages; ++i) { + for (i = 0; i < pcl->pclusterpages; ++i) { unsigned int pagenr; page = compressed_pages[i]; @@ -896,12 +978,13 @@ static int z_erofs_decompress_pcluster(struct super_block *sb, partial = true; } + inputsize = pcl->pclusterpages * PAGE_SIZE; err = z_erofs_decompress(&(struct z_erofs_decompress_req) { .sb = sb, .in = compressed_pages, .out = pages, .pageofs_out = cl->pageofs, - .inputsize = PAGE_SIZE, + .inputsize = inputsize, .outputsize = outputsize, .alg = pcl->algorithmformat, .inplace_io = overlapped, @@ -909,8 +992,8 @@ static int z_erofs_decompress_pcluster(struct super_block *sb, }, pagepool); out: - /* must handle all compressed pages before endding pages */ - for (i = 0; i < clusterpages; ++i) { + /* must handle all compressed pages before ending pages */ + for (i = 0; i < pcl->pclusterpages; ++i) { page = compressed_pages[i]; if (erofs_page_is_managed(sbi, page)) @@ -1213,7 +1296,7 @@ static void z_erofs_submit_queue(struct super_block *sb, pcl = container_of(owned_head, struct z_erofs_pcluster, next); cur = pcl->obj.index; - end = cur + BIT(pcl->clusterbits); + end = cur + pcl->pclusterpages; /* close the main owned chain at first */ owned_head = cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL, @@ -1333,7 +1416,8 @@ static void z_erofs_readahead(struct readahead_control *rac) struct erofs_sb_info *const sbi = EROFS_I_SB(inode); unsigned int nr_pages = readahead_count(rac); - bool sync = (nr_pages <= sbi->ctx.max_sync_decompress_pages); + bool sync = (sbi->ctx.readahead_sync_decompress && + nr_pages <= sbi->ctx.max_sync_decompress_pages); struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode); struct page *page, *head = NULL; LIST_HEAD(pagepool); diff --git a/fs/erofs/zdata.h b/fs/erofs/zdata.h index b503b353d4abc3e5603cf3899ce04a5c45613363..942ee69dff6af134c33282763decddbb0ecf2804 100644 --- a/fs/erofs/zdata.h +++ b/fs/erofs/zdata.h @@ -10,6 +10,7 @@ #include "internal.h" #include "zpvec.h" +#define Z_EROFS_PCLUSTER_MAX_PAGES (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE) #define Z_EROFS_NR_INLINE_PAGEVECS 3 /* @@ -59,16 +60,17 @@ struct z_erofs_pcluster { /* A: point to next chained pcluster or TAILs */ z_erofs_next_pcluster_t next; - /* A: compressed pages (including multi-usage pages) */ - struct page *compressed_pages[Z_EROFS_CLUSTER_MAX_PAGES]; - /* A: lower limit of decompressed length and if full length or not */ unsigned int length; + /* I: physical cluster size in pages */ + unsigned short pclusterpages; + /* I: compression algorithm format */ unsigned char algorithmformat; - /* I: bit shift of physical cluster size */ - unsigned char clusterbits; + + /* A: compressed pages (can be cached or inplaced pages) */ + struct page *compressed_pages[]; }; #define z_erofs_primarycollection(pcluster) (&(pcluster)->primary_collection) @@ -82,8 +84,6 @@ struct z_erofs_pcluster { #define Z_EROFS_PCLUSTER_NIL (NULL) -#define Z_EROFS_WORKGROUP_SIZE sizeof(struct z_erofs_pcluster) - struct z_erofs_decompressqueue { struct super_block *sb; atomic_t pending_bios; diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c index 14d2de35110ccd25c005ac96865c660c06d43f44..e62d813756f28b07926423ed039b5202ae17f87c 100644 --- a/fs/erofs/zmap.c +++ b/fs/erofs/zmap.c @@ -11,17 +11,16 @@ int z_erofs_fill_inode(struct inode *inode) { struct erofs_inode *const vi = EROFS_I(inode); + struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb); - if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) { + if (!erofs_sb_has_big_pcluster(sbi) && + vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) { vi->z_advise = 0; vi->z_algorithmtype[0] = 0; vi->z_algorithmtype[1] = 0; vi->z_logical_clusterbits = LOG_BLOCK_SIZE; - vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits; - vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits; set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); } - inode->i_mapping->a_ops = &z_erofs_aops; return 0; } @@ -52,7 +51,8 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) goto out_unlock; - DBG_BUGON(vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY); + DBG_BUGON(!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && + vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY); pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize + vi->xattr_isize, 8); @@ -77,18 +77,22 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) } vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7); - vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits + - ((h->h_clusterbits >> 3) & 3); - - if (vi->z_physical_clusterbits[0] != LOG_BLOCK_SIZE) { - erofs_err(sb, "unsupported physical clusterbits %u for nid %llu, please upgrade kernel", - vi->z_physical_clusterbits[0], vi->nid); - err = -EOPNOTSUPP; + if (!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && + vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | + Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { + erofs_err(sb, "per-inode big pcluster without sb feature for nid %llu", + vi->nid); + err = -EFSCORRUPTED; + goto unmap_done; + } + if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION && + !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^ + !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { + erofs_err(sb, "big pcluster head1/2 of compact indexes should be consistent for nid %llu", + vi->nid); + err = -EFSCORRUPTED; goto unmap_done; } - - vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits + - ((h->h_clusterbits >> 5) & 7); /* paired with smp_mb() at the beginning of the function */ smp_mb(); set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); @@ -111,7 +115,7 @@ struct z_erofs_maprecorder { u8 type; u16 clusterofs; u16 delta[2]; - erofs_blk_t pblk; + erofs_blk_t pblk, compressedlcs; }; static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m, @@ -174,6 +178,15 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: m->clusterofs = 1 << vi->z_logical_clusterbits; m->delta[0] = le16_to_cpu(di->di_u.delta[0]); + if (m->delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) { + if (!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) { + DBG_BUGON(1); + return -EFSCORRUPTED; + } + m->compressedlcs = m->delta[0] & + ~Z_EROFS_VLE_DI_D0_CBLKCNT; + m->delta[0] = 1; + } m->delta[1] = le16_to_cpu(di->di_u.delta[1]); break; case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: @@ -210,6 +223,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, unsigned int vcnt, base, lo, encodebits, nblk; int i; u8 *in, type; + bool big_pcluster; if (1 << amortizedshift == 4) vcnt = 2; @@ -218,6 +232,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, else return -EOPNOTSUPP; + big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt; base = round_down(eofs, vcnt << amortizedshift); in = m->kaddr + base; @@ -229,7 +244,15 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, m->type = type; if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { m->clusterofs = 1 << lclusterbits; - if (i + 1 != vcnt) { + if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) { + if (!big_pcluster) { + DBG_BUGON(1); + return -EFSCORRUPTED; + } + m->compressedlcs = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT; + m->delta[0] = 1; + return 0; + } else if (i + 1 != (int)vcnt) { m->delta[0] = lo; return 0; } @@ -242,22 +265,48 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, in, encodebits * (i - 1), &type); if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) lo = 0; + else if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) + lo = 1; m->delta[0] = lo + 1; return 0; } m->clusterofs = lo; m->delta[0] = 0; /* figout out blkaddr (pblk) for HEAD lclusters */ - nblk = 1; - while (i > 0) { - --i; - lo = decode_compactedbits(lclusterbits, lomask, - in, encodebits * i, &type); - if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) - i -= lo; - - if (i >= 0) + if (!big_pcluster) { + nblk = 1; + while (i > 0) { + --i; + lo = decode_compactedbits(lclusterbits, lomask, + in, encodebits * i, &type); + if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) + i -= lo; + + if (i >= 0) + ++nblk; + } + } else { + nblk = 0; + while (i > 0) { + --i; + lo = decode_compactedbits(lclusterbits, lomask, + in, encodebits * i, &type); + if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { + if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) { + --i; + nblk += lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT; + continue; + } + /* bigpcluster shouldn't have plain d0 == 1 */ + if (lo <= 1) { + DBG_BUGON(1); + return -EFSCORRUPTED; + } + i -= lo - 2; + continue; + } ++nblk; + } } in += (vcnt << amortizedshift) - sizeof(__le32); m->pblk = le32_to_cpu(*(__le32 *)in) + nblk; @@ -381,6 +430,58 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, return 0; } +static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + unsigned int initial_lcn) +{ + struct erofs_inode *const vi = EROFS_I(m->inode); + struct erofs_map_blocks *const map = m->map; + const unsigned int lclusterbits = vi->z_logical_clusterbits; + unsigned long lcn; + int err; + + DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN && + m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD); + if (!(map->m_flags & EROFS_MAP_ZIPPED) || + !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) { + map->m_plen = 1 << lclusterbits; + return 0; + } + + lcn = m->lcn + 1; + if (m->compressedlcs) + goto out; + if (lcn == initial_lcn) + goto err_bonus_cblkcnt; + + err = z_erofs_load_cluster_from_disk(m, lcn); + if (err) + return err; + + switch (m->type) { + case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: + if (m->delta[0] != 1) + goto err_bonus_cblkcnt; + if (m->compressedlcs) + break; + fallthrough; + default: + erofs_err(m->inode->i_sb, + "cannot found CBLKCNT @ lcn %lu of nid %llu", + lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; + } +out: + map->m_plen = m->compressedlcs << lclusterbits; + return 0; +err_bonus_cblkcnt: + erofs_err(m->inode->i_sb, + "bogus CBLKCNT @ lcn %lu of nid %llu", + lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; +} + int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, int flags) @@ -392,6 +493,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, }; int err = 0; unsigned int lclusterbits, endoff; + unsigned long initial_lcn; unsigned long long ofs, end; trace_z_erofs_map_blocks_iter_enter(inode, map, flags); @@ -410,10 +512,10 @@ int z_erofs_map_blocks_iter(struct inode *inode, lclusterbits = vi->z_logical_clusterbits; ofs = map->m_la; - m.lcn = ofs >> lclusterbits; + initial_lcn = ofs >> lclusterbits; endoff = ofs & ((1 << lclusterbits) - 1); - err = z_erofs_load_cluster_from_disk(&m, m.lcn); + err = z_erofs_load_cluster_from_disk(&m, initial_lcn); if (err) goto unmap_out; @@ -443,7 +545,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, m.delta[0] = 1; fallthrough; case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: - /* get the correspoinding first chunk */ + /* get the corresponding first chunk */ err = z_erofs_extent_lookback(&m, m.delta[0]); if (err) goto unmap_out; @@ -457,10 +559,12 @@ int z_erofs_map_blocks_iter(struct inode *inode, } map->m_llen = end - map->m_la; - map->m_plen = 1 << lclusterbits; map->m_pa = blknr_to_addr(m.pblk); map->m_flags |= EROFS_MAP_MAPPED; + err = z_erofs_get_extent_compressedlen(&m, initial_lcn); + if (err) + goto out; unmap_out: if (m.kaddr) kunmap_atomic(m.kaddr); diff --git a/fs/eventpoll.c b/fs/eventpoll.c index f081d6634acb190c5a3f47c1b8ad9dccb30ef660..7e5b7cb2ed7f6ddb08e10f5edd263c84e0d50cb8 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -367,8 +367,8 @@ static inline struct epitem *ep_item_from_wait(wait_queue_entry_t *p) * * @ep: Pointer to the eventpoll context. * - * Returns: Returns a value different than zero if ready events are available, - * or zero otherwise. + * Return: a value different than %zero if ready events are available, + * or %zero otherwise. */ static inline int ep_events_available(struct eventpoll *ep) { @@ -1024,7 +1024,7 @@ struct file *get_epoll_tfile_raw_ptr(struct file *file, int tfd, } #endif /* CONFIG_KCMP */ -/** +/* * Adds a new entry to the tail of the list in a lockless way, i.e. * multiple CPUs are allowed to call this function concurrently. * @@ -1036,10 +1036,10 @@ struct file *get_epoll_tfile_raw_ptr(struct file *file, int tfd, * completed. * * Also an element can be locklessly added to the list only in one - * direction i.e. either to the tail either to the head, otherwise + * direction i.e. either to the tail or to the head, otherwise * concurrent access will corrupt the list. * - * Returns %false if element has been already added to the list, %true + * Return: %false if element has been already added to the list, %true * otherwise. */ static inline bool list_add_tail_lockless(struct list_head *new, @@ -1077,11 +1077,11 @@ static inline bool list_add_tail_lockless(struct list_head *new, return true; } -/** +/* * Chains a new epi entry to the tail of the ep->ovflist in a lockless way, * i.e. multiple CPUs are allowed to call this function concurrently. * - * Returns %false if epi element has been already chained, %true otherwise. + * Return: %false if epi element has been already chained, %true otherwise. */ static inline bool chain_epi_lockless(struct epitem *epi) { @@ -1106,8 +1106,8 @@ static inline bool chain_epi_lockless(struct epitem *epi) * mechanism. It is called by the stored file descriptors when they * have events to report. * - * This callback takes a read lock in order not to content with concurrent - * events from another file descriptors, thus all modifications to ->rdllist + * This callback takes a read lock in order not to contend with concurrent + * events from another file descriptor, thus all modifications to ->rdllist * or ->ovflist are lockless. Read lock is paired with the write lock from * ep_scan_ready_list(), which stops all list modifications and guarantees * that lists state is seen correctly. @@ -1336,8 +1336,8 @@ static int reverse_path_check_proc(struct hlist_head *refs, int depth) * paths such that we will spend all our time waking up * eventpoll objects. * - * Returns: Returns zero if the proposed links don't create too many paths, - * -1 otherwise. + * Return: %zero if the proposed links don't create too many paths, + * %-1 otherwise. */ static int reverse_path_check(void) { @@ -1735,7 +1735,7 @@ static struct timespec64 *ep_timeout_to_timespec(struct timespec64 *to, long ms) } /** - * ep_poll - Retrieves ready events, and delivers them to the caller supplied + * ep_poll - Retrieves ready events, and delivers them to the caller-supplied * event buffer. * * @ep: Pointer to the eventpoll context. @@ -1748,7 +1748,7 @@ static struct timespec64 *ep_timeout_to_timespec(struct timespec64 *to, long ms) * until at least one event has been retrieved (or an error * occurred). * - * Returns: Returns the number of ready events which have been fetched, or an + * Return: the number of ready events which have been fetched, or an * error code, in case of error. */ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, @@ -1775,9 +1775,9 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, /* * This call is racy: We may or may not see events that are being added - * to the ready list under the lock (e.g., in IRQ callbacks). For, cases + * to the ready list under the lock (e.g., in IRQ callbacks). For cases * with a non-zero timeout, this thread will check the ready list under - * lock and will added to the wait queue. For, cases with a zero + * lock and will add to the wait queue. For cases with a zero * timeout, the user by definition should not care and will have to * recheck again. */ @@ -1870,15 +1870,15 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, /** * ep_loop_check_proc - verify that adding an epoll file inside another - * epoll structure, does not violate the constraints, in + * epoll structure does not violate the constraints, in * terms of closed loops, or too deep chains (which can * result in excessive stack usage). * - * @priv: Pointer to the epoll file to be currently checked. + * @ep: the &struct eventpoll to be currently checked. * @depth: Current depth of the path being checked. * - * Returns: Returns zero if adding the epoll @file inside current epoll - * structure @ep does not violate the constraints, or -1 otherwise. + * Return: %zero if adding the epoll @file inside current epoll + * structure @ep does not violate the constraints, or %-1 otherwise. */ static int ep_loop_check_proc(struct eventpoll *ep, int depth) { @@ -1920,14 +1920,14 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth) /** * ep_loop_check - Performs a check to verify that adding an epoll file (@to) - * into another epoll file (represented by @from) does not create + * into another epoll file (represented by @ep) does not create * closed loops or too deep chains. * - * @from: Pointer to the epoll we are inserting into. + * @ep: Pointer to the epoll we are inserting into. * @to: Pointer to the epoll to be inserted. * - * Returns: Returns zero if adding the epoll @to inside the epoll @from - * does not violate the constraints, or -1 otherwise. + * Return: %zero if adding the epoll @to inside the epoll @from + * does not violate the constraints, or %-1 otherwise. */ static int ep_loop_check(struct eventpoll *ep, struct eventpoll *to) { @@ -2075,8 +2075,8 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, ep = f.file->private_data; /* - * When we insert an epoll file descriptor, inside another epoll file - * descriptor, there is the change of creating closed loops, which are + * When we insert an epoll file descriptor inside another epoll file + * descriptor, there is the chance of creating closed loops, which are * better be handled here, than in more critical paths. While we are * checking for loops we also determine the list of files reachable * and hang them on the tfile_check_list, so we can check that we @@ -2114,7 +2114,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, } /* - * Try to lookup the file inside our RB tree, Since we grabbed "mtx" + * Try to lookup the file inside our RB tree. Since we grabbed "mtx" * above, we can be sure to be able to use the item looked up by * ep_find() till we release the mutex. */ diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 3309fb2d327a8d53868c883dcda87744f2a742eb..23ffe5b9601081b9602db2e672e7d6e5787537fe 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -283,8 +283,6 @@ static inline __u32 ext2_mask_flags(umode_t mode, __u32 flags) /* * ioctl commands */ -#define EXT2_IOC_GETFLAGS FS_IOC_GETFLAGS -#define EXT2_IOC_SETFLAGS FS_IOC_SETFLAGS #define EXT2_IOC_GETVERSION FS_IOC_GETVERSION #define EXT2_IOC_SETVERSION FS_IOC_SETVERSION #define EXT2_IOC_GETRSVSZ _IOR('f', 5, long) @@ -293,8 +291,6 @@ static inline __u32 ext2_mask_flags(umode_t mode, __u32 flags) /* * ioctl commands in 32 bit emulation */ -#define EXT2_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define EXT2_IOC32_SETFLAGS FS_IOC32_SETFLAGS #define EXT2_IOC32_GETVERSION FS_IOC32_GETVERSION #define EXT2_IOC32_SETVERSION FS_IOC32_SETVERSION @@ -772,6 +768,9 @@ extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); /* ioctl.c */ +extern int ext2_fileattr_get(struct dentry *dentry, struct fileattr *fa); +extern int ext2_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); extern long ext2_ioctl(struct file *, unsigned int, unsigned long); extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long); diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 96044f5dbc0e0232386e9bd489dc20ae6ecdf066..f98466acc672a4dc7fb7ddf5a62642bcc3e09ab2 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -204,4 +204,6 @@ const struct inode_operations ext2_file_inode_operations = { .get_acl = ext2_get_acl, .set_acl = ext2_set_acl, .fiemap = ext2_fiemap, + .fileattr_get = ext2_fileattr_get, + .fileattr_set = ext2_fileattr_set, }; diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index b399cbb7022df5075717109cc5c425b4d9a44eba..e8340bf09b102cd6b9cb07ce1eab03f67b8398ba 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -16,69 +16,51 @@ #include <linux/mount.h> #include <asm/current.h> #include <linux/uaccess.h> +#include <linux/fileattr.h> - -long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +int ext2_fileattr_get(struct dentry *dentry, struct fileattr *fa) { - struct inode *inode = file_inode(filp); - struct ext2_inode_info *ei = EXT2_I(inode); - unsigned int flags; - unsigned short rsv_window_size; - int ret; + struct ext2_inode_info *ei = EXT2_I(d_inode(dentry)); - ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); + fileattr_fill_flags(fa, ei->i_flags & EXT2_FL_USER_VISIBLE); - switch (cmd) { - case EXT2_IOC_GETFLAGS: - flags = ei->i_flags & EXT2_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); - case EXT2_IOC_SETFLAGS: { - unsigned int oldflags; + return 0; +} - ret = mnt_want_write_file(filp); - if (ret) - return ret; +int ext2_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct ext2_inode_info *ei = EXT2_I(inode); - if (!inode_owner_or_capable(&init_user_ns, inode)) { - ret = -EACCES; - goto setflags_out; - } + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; - if (get_user(flags, (int __user *) arg)) { - ret = -EFAULT; - goto setflags_out; - } + /* Is it quota file? Do not allow user to mess with it */ + if (IS_NOQUOTA(inode)) + return -EPERM; - flags = ext2_mask_flags(inode->i_mode, flags); + ei->i_flags = (ei->i_flags & ~EXT2_FL_USER_MODIFIABLE) | + (fa->flags & EXT2_FL_USER_MODIFIABLE); - inode_lock(inode); - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) { - inode_unlock(inode); - ret = -EPERM; - goto setflags_out; - } - oldflags = ei->i_flags; + ext2_set_inode_flags(inode); + inode->i_ctime = current_time(inode); + mark_inode_dirty(inode); - ret = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (ret) { - inode_unlock(inode); - goto setflags_out; - } + return 0; +} - flags = flags & EXT2_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; - ei->i_flags = flags; - ext2_set_inode_flags(inode); - inode->i_ctime = current_time(inode); - inode_unlock(inode); +long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct ext2_inode_info *ei = EXT2_I(inode); + unsigned short rsv_window_size; + int ret; - mark_inode_dirty(inode); -setflags_out: - mnt_drop_write_file(filp); - return ret; - } + ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { case EXT2_IOC_GETVERSION: return put_user(inode->i_generation, (int __user *) arg); case EXT2_IOC_SETVERSION: { @@ -163,12 +145,6 @@ long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { - case EXT2_IOC32_GETFLAGS: - cmd = EXT2_IOC_GETFLAGS; - break; - case EXT2_IOC32_SETFLAGS: - cmd = EXT2_IOC_SETFLAGS; - break; case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 3367384d344d0b7dcfdd3cb92a1ee33b6997f2b6..c03fc3c1533ef92296dc8fceef860c855c060eb6 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -427,6 +427,8 @@ const struct inode_operations ext2_dir_inode_operations = { .get_acl = ext2_get_acl, .set_acl = ext2_set_acl, .tmpfile = ext2_tmpfile, + .fileattr_get = ext2_fileattr_get, + .fileattr_set = ext2_fileattr_set, }; const struct inode_operations ext2_special_inode_operations = { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index d7fdbaea64b536639abfda321bda13a0cc946132..f632a4ac577cab967851c4fa4141acbc7595a35a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -472,15 +472,6 @@ struct flex_groups { EXT4_VERITY_FL | \ EXT4_INLINE_DATA_FL) -/* Flags we can manipulate with through FS_IOC_FSSETXATTR */ -#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \ - EXT4_IMMUTABLE_FL | \ - EXT4_APPEND_FL | \ - EXT4_NODUMP_FL | \ - EXT4_NOATIME_FL | \ - EXT4_PROJINHERIT_FL | \ - EXT4_DAX_FL) - /* Flags that should be inherited by new inodes from their parent. */ #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ @@ -2973,6 +2964,9 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode, /* ioctl.c */ extern long ext4_ioctl(struct file *, unsigned int, unsigned long); extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); +int ext4_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); +int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa); extern void ext4_reset_inode_seed(struct inode *inode); /* migrate.c */ diff --git a/fs/ext4/file.c b/fs/ext4/file.c index fcd097cef319fe58690b55cca39b7e38bf3f677e..d1e7482bf2e8ba1779f2e8cde39f7c377ab32794 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -921,5 +921,7 @@ const struct inode_operations ext4_file_inode_operations = { .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, .fiemap = ext4_fiemap, + .fileattr_get = ext4_fileattr_get, + .fileattr_set = ext4_fileattr_set, }; diff --git a/fs/ext4/fsmap.c b/fs/ext4/fsmap.c index 4c2a9fe3006723f4ee1fc84e461d1782322ec054..4493ef0c715e9d1a1e8166feefc0a532339f6dd0 100644 --- a/fs/ext4/fsmap.c +++ b/fs/ext4/fsmap.c @@ -354,8 +354,8 @@ static unsigned int ext4_getfsmap_find_sb(struct super_block *sb, /* Compare two fsmap items. */ static int ext4_getfsmap_compare(void *priv, - struct list_head *a, - struct list_head *b) + const struct list_head *a, + const struct list_head *b) { struct ext4_fsmap *fa; struct ext4_fsmap *fb; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 594bfd7122b352c43a261ee532dd476f43e49592..5aefa85012d44132b41d1eb3ea37278d432a1975 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -973,7 +973,7 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns, i_gid_write(inode, owner[1]); } else if (test_opt(sb, GRPID)) { inode->i_mode = mode; - inode->i_uid = fsuid_into_mnt(mnt_userns); + inode_fsuid_set(inode, mnt_userns); inode->i_gid = dir->i_gid; } else inode_init_owner(mnt_userns, inode, dir, mode); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a2cf35066f46be5059d8f3d9b2000f845bd5aa85..e9b0a1fa2ba895d82f8b7585bd909828188d5e79 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -20,6 +20,7 @@ #include <linux/uaccess.h> #include <linux/delay.h> #include <linux/iversion.h> +#include <linux/fileattr.h> #include "ext4_jbd2.h" #include "ext4.h" #include <linux/fsmap.h> @@ -344,11 +345,6 @@ static int ext4_ioctl_setflags(struct inode *inode, goto flags_out; oldflags = ei->i_flags; - - err = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (err) - goto flags_out; - /* * The JOURNAL_DATA flag can only be changed by * the relevant capability. @@ -459,9 +455,8 @@ flags_out: } #ifdef CONFIG_QUOTA -static int ext4_ioctl_setproject(struct file *filp, __u32 projid) +static int ext4_ioctl_setproject(struct inode *inode, __u32 projid) { - struct inode *inode = file_inode(filp); struct super_block *sb = inode->i_sb; struct ext4_inode_info *ei = EXT4_I(inode); int err, rc; @@ -545,7 +540,7 @@ out_stop: return err; } #else -static int ext4_ioctl_setproject(struct file *filp, __u32 projid) +static int ext4_ioctl_setproject(struct inode *inode, __u32 projid) { if (projid != EXT4_DEF_PROJID) return -EOPNOTSUPP; @@ -553,56 +548,6 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid) } #endif -/* Transfer internal flags to xflags */ -static inline __u32 ext4_iflags_to_xflags(unsigned long iflags) -{ - __u32 xflags = 0; - - if (iflags & EXT4_SYNC_FL) - xflags |= FS_XFLAG_SYNC; - if (iflags & EXT4_IMMUTABLE_FL) - xflags |= FS_XFLAG_IMMUTABLE; - if (iflags & EXT4_APPEND_FL) - xflags |= FS_XFLAG_APPEND; - if (iflags & EXT4_NODUMP_FL) - xflags |= FS_XFLAG_NODUMP; - if (iflags & EXT4_NOATIME_FL) - xflags |= FS_XFLAG_NOATIME; - if (iflags & EXT4_PROJINHERIT_FL) - xflags |= FS_XFLAG_PROJINHERIT; - if (iflags & EXT4_DAX_FL) - xflags |= FS_XFLAG_DAX; - return xflags; -} - -#define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \ - FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \ - FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT | \ - FS_XFLAG_DAX) - -/* Transfer xflags flags to internal */ -static inline unsigned long ext4_xflags_to_iflags(__u32 xflags) -{ - unsigned long iflags = 0; - - if (xflags & FS_XFLAG_SYNC) - iflags |= EXT4_SYNC_FL; - if (xflags & FS_XFLAG_IMMUTABLE) - iflags |= EXT4_IMMUTABLE_FL; - if (xflags & FS_XFLAG_APPEND) - iflags |= EXT4_APPEND_FL; - if (xflags & FS_XFLAG_NODUMP) - iflags |= EXT4_NODUMP_FL; - if (xflags & FS_XFLAG_NOATIME) - iflags |= EXT4_NOATIME_FL; - if (xflags & FS_XFLAG_PROJINHERIT) - iflags |= EXT4_PROJINHERIT_FL; - if (xflags & FS_XFLAG_DAX) - iflags |= EXT4_DAX_FL; - - return iflags; -} - static int ext4_shutdown(struct super_block *sb, unsigned long arg) { struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -770,15 +715,52 @@ group_add_out: return err; } -static void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa) +int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa) { + struct inode *inode = d_inode(dentry); struct ext4_inode_info *ei = EXT4_I(inode); + u32 flags = ei->i_flags & EXT4_FL_USER_VISIBLE; - simple_fill_fsxattr(fa, ext4_iflags_to_xflags(ei->i_flags & - EXT4_FL_USER_VISIBLE)); + if (S_ISREG(inode->i_mode)) + flags &= ~FS_PROJINHERIT_FL; + fileattr_fill_flags(fa, flags); if (ext4_has_feature_project(inode->i_sb)) fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid); + + return 0; +} + +int ext4_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + u32 flags = fa->flags; + int err = -EOPNOTSUPP; + + ext4_fc_start_update(inode); + if (flags & ~EXT4_FL_USER_VISIBLE) + goto out; + + /* + * chattr(1) grabs flags via GETFLAGS, modifies the result and + * passes that to SETFLAGS. So we cannot easily make SETFLAGS + * more restrictive than just silently masking off visible but + * not settable flags as we always did. + */ + flags &= EXT4_FL_USER_MODIFIABLE; + if (ext4_mask_flags(inode->i_mode, flags) != flags) + goto out; + err = ext4_ioctl_check_immutable(inode, fa->fsx_projid, flags); + if (err) + goto out; + err = ext4_ioctl_setflags(inode, flags); + if (err) + goto out; + err = ext4_ioctl_setproject(inode, fa->fsx_projid); +out: + ext4_fc_stop_update(inode); + return err; } /* So that the fiemap access checks can't overflow on 32 bit machines. */ @@ -816,55 +798,13 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); struct super_block *sb = inode->i_sb; - struct ext4_inode_info *ei = EXT4_I(inode); struct user_namespace *mnt_userns = file_mnt_user_ns(filp); - unsigned int flags; ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { case FS_IOC_GETFSMAP: return ext4_ioc_getfsmap(sb, (void __user *)arg); - case FS_IOC_GETFLAGS: - flags = ei->i_flags & EXT4_FL_USER_VISIBLE; - if (S_ISREG(inode->i_mode)) - flags &= ~EXT4_PROJINHERIT_FL; - return put_user(flags, (int __user *) arg); - case FS_IOC_SETFLAGS: { - int err; - - if (!inode_owner_or_capable(mnt_userns, inode)) - return -EACCES; - - if (get_user(flags, (int __user *) arg)) - return -EFAULT; - - if (flags & ~EXT4_FL_USER_VISIBLE) - return -EOPNOTSUPP; - /* - * chattr(1) grabs flags via GETFLAGS, modifies the result and - * passes that to SETFLAGS. So we cannot easily make SETFLAGS - * more restrictive than just silently masking off visible but - * not settable flags as we always did. - */ - flags &= EXT4_FL_USER_MODIFIABLE; - if (ext4_mask_flags(inode->i_mode, flags) != flags) - return -EOPNOTSUPP; - - err = mnt_want_write_file(filp); - if (err) - return err; - - inode_lock(inode); - err = ext4_ioctl_check_immutable(inode, - from_kprojid(&init_user_ns, ei->i_projid), - flags); - if (!err) - err = ext4_ioctl_setflags(inode, flags); - inode_unlock(inode); - mnt_drop_write_file(filp); - return err; - } case EXT4_IOC_GETVERSION: case EXT4_IOC_GETVERSION_OLD: return put_user(inode->i_generation, (int __user *) arg); @@ -1246,60 +1186,6 @@ resizefs_out: case EXT4_IOC_GET_ES_CACHE: return ext4_ioctl_get_es_cache(filp, arg); - case FS_IOC_FSGETXATTR: - { - struct fsxattr fa; - - ext4_fill_fsxattr(inode, &fa); - - if (copy_to_user((struct fsxattr __user *)arg, - &fa, sizeof(fa))) - return -EFAULT; - return 0; - } - case FS_IOC_FSSETXATTR: - { - struct fsxattr fa, old_fa; - int err; - - if (copy_from_user(&fa, (struct fsxattr __user *)arg, - sizeof(fa))) - return -EFAULT; - - /* Make sure caller has proper permission */ - if (!inode_owner_or_capable(mnt_userns, inode)) - return -EACCES; - - if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS) - return -EOPNOTSUPP; - - flags = ext4_xflags_to_iflags(fa.fsx_xflags); - if (ext4_mask_flags(inode->i_mode, flags) != flags) - return -EOPNOTSUPP; - - err = mnt_want_write_file(filp); - if (err) - return err; - - inode_lock(inode); - ext4_fill_fsxattr(inode, &old_fa); - err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa); - if (err) - goto out; - flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) | - (flags & EXT4_FL_XFLAG_VISIBLE); - err = ext4_ioctl_check_immutable(inode, fa.fsx_projid, flags); - if (err) - goto out; - err = ext4_ioctl_setflags(inode, flags); - if (err) - goto out; - err = ext4_ioctl_setproject(filp, fa.fsx_projid); -out: - inode_unlock(inode); - mnt_drop_write_file(filp); - return err; - } case EXT4_IOC_SHUTDOWN: return ext4_shutdown(sb, arg); @@ -1340,12 +1226,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; case EXT4_IOC32_GETVERSION: cmd = EXT4_IOC_GETVERSION; break; @@ -1405,8 +1285,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case EXT4_IOC_CLEAR_ES_CACHE: case EXT4_IOC_GETSTATE: case EXT4_IOC_GET_ES_CACHE: - case FS_IOC_FSGETXATTR: - case FS_IOC_FSSETXATTR: break; default: return -ENOIOCTLCMD; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index b253c2f34cfb6af1c9191583da367808063c60de..b69e853f991ad9b6d22a3da6b338f9fc2c36ad5d 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -4291,6 +4291,8 @@ const struct inode_operations ext4_dir_inode_operations = { .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, .fiemap = ext4_fiemap, + .fileattr_get = ext4_fileattr_get, + .fileattr_set = ext4_fileattr_set, }; const struct inode_operations ext4_special_inode_operations = { diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c index 00e3cbde472e45135f95c12d6615e4356caf67c3..07438f46b5582d19eb7fd4f5a7699c1616e3ae44 100644 --- a/fs/ext4/verity.c +++ b/fs/ext4/verity.c @@ -370,7 +370,7 @@ static struct page *ext4_read_merkle_tree_page(struct inode *inode, pgoff_t index, unsigned long num_ra_pages) { - DEFINE_READAHEAD(ractl, NULL, inode->i_mapping, index); + DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index); struct page *page; index += ext4_verity_metadata_pos(inode) >> PAGE_SHIFT; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 68396d8f2ab68bce6b383ef0729606442b143864..a3ea80c5c99b60b42cb8b0ee462cb01ff88210a6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3194,6 +3194,9 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end); void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count); int f2fs_precache_extents(struct inode *inode); +int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int f2fs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index d26ff2ae3f5ebbbaada71b040666d5710b7872e8..8a56acbcee4c24756a05fd68ea02a75417103ded 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -22,6 +22,7 @@ #include <linux/file.h> #include <linux/nls.h> #include <linux/sched/signal.h> +#include <linux/fileattr.h> #include "f2fs.h" #include "node.h" @@ -990,6 +991,8 @@ const struct inode_operations f2fs_file_inode_operations = { .set_acl = f2fs_set_acl, .listxattr = f2fs_listxattr, .fiemap = f2fs_fiemap, + .fileattr_get = f2fs_fileattr_get, + .fileattr_set = f2fs_fileattr_set, }; static int fill_zero(struct inode *inode, pgoff_t index, @@ -1871,13 +1874,16 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) return 0; } -/* FS_IOC_GETFLAGS and FS_IOC_SETFLAGS support */ +/* FS_IOC_[GS]ETFLAGS and FS_IOC_FS[GS]ETXATTR support */ /* * To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry * for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to * F2FS_GETTABLE_FS_FL. To also make it settable via FS_IOC_SETFLAGS, also add * its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL. + * + * Translating flags to fsx_flags value used by FS_IOC_FSGETXATTR and + * FS_IOC_FSSETXATTR is done by the VFS. */ static const struct { @@ -1952,67 +1958,6 @@ static inline u32 f2fs_fsflags_to_iflags(u32 fsflags) return iflags; } -static int f2fs_ioc_getflags(struct file *filp, unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct f2fs_inode_info *fi = F2FS_I(inode); - u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags); - - if (IS_ENCRYPTED(inode)) - fsflags |= FS_ENCRYPT_FL; - if (IS_VERITY(inode)) - fsflags |= FS_VERITY_FL; - if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) - fsflags |= FS_INLINE_DATA_FL; - if (is_inode_flag_set(inode, FI_PIN_FILE)) - fsflags |= FS_NOCOW_FL; - - fsflags &= F2FS_GETTABLE_FS_FL; - - return put_user(fsflags, (int __user *)arg); -} - -static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct f2fs_inode_info *fi = F2FS_I(inode); - u32 fsflags, old_fsflags; - u32 iflags; - int ret; - - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; - - if (get_user(fsflags, (int __user *)arg)) - return -EFAULT; - - if (fsflags & ~F2FS_GETTABLE_FS_FL) - return -EOPNOTSUPP; - fsflags &= F2FS_SETTABLE_FS_FL; - - iflags = f2fs_fsflags_to_iflags(fsflags); - if (f2fs_mask_flags(inode->i_mode, iflags) != iflags) - return -EOPNOTSUPP; - - ret = mnt_want_write_file(filp); - if (ret) - return ret; - - inode_lock(inode); - - old_fsflags = f2fs_iflags_to_fsflags(fi->i_flags); - ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags); - if (ret) - goto out; - - ret = f2fs_setflags_common(inode, iflags, - f2fs_fsflags_to_iflags(F2FS_SETTABLE_FS_FL)); -out: - inode_unlock(inode); - mnt_drop_write_file(filp); - return ret; -} - static int f2fs_ioc_getversion(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); @@ -3019,9 +2964,8 @@ int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) return err; } -static int f2fs_ioc_setproject(struct file *filp, __u32 projid) +static int f2fs_ioc_setproject(struct inode *inode, __u32 projid) { - struct inode *inode = file_inode(filp); struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *ipage; @@ -3082,7 +3026,7 @@ int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) return 0; } -static int f2fs_ioc_setproject(struct file *filp, __u32 projid) +static int f2fs_ioc_setproject(struct inode *inode, __u32 projid) { if (projid != F2FS_DEF_PROJID) return -EOPNOTSUPP; @@ -3090,123 +3034,55 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) } #endif -/* FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR support */ - -/* - * To make a new on-disk f2fs i_flag gettable via FS_IOC_FSGETXATTR and settable - * via FS_IOC_FSSETXATTR, add an entry for it to f2fs_xflags_map[], and add its - * FS_XFLAG_* equivalent to F2FS_SUPPORTED_XFLAGS. - */ - -static const struct { - u32 iflag; - u32 xflag; -} f2fs_xflags_map[] = { - { F2FS_SYNC_FL, FS_XFLAG_SYNC }, - { F2FS_IMMUTABLE_FL, FS_XFLAG_IMMUTABLE }, - { F2FS_APPEND_FL, FS_XFLAG_APPEND }, - { F2FS_NODUMP_FL, FS_XFLAG_NODUMP }, - { F2FS_NOATIME_FL, FS_XFLAG_NOATIME }, - { F2FS_PROJINHERIT_FL, FS_XFLAG_PROJINHERIT }, -}; - -#define F2FS_SUPPORTED_XFLAGS ( \ - FS_XFLAG_SYNC | \ - FS_XFLAG_IMMUTABLE | \ - FS_XFLAG_APPEND | \ - FS_XFLAG_NODUMP | \ - FS_XFLAG_NOATIME | \ - FS_XFLAG_PROJINHERIT) - -/* Convert f2fs on-disk i_flags to FS_IOC_FS{GET,SET}XATTR flags */ -static inline u32 f2fs_iflags_to_xflags(u32 iflags) -{ - u32 xflags = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(f2fs_xflags_map); i++) - if (iflags & f2fs_xflags_map[i].iflag) - xflags |= f2fs_xflags_map[i].xflag; - - return xflags; -} - -/* Convert FS_IOC_FS{GET,SET}XATTR flags to f2fs on-disk i_flags */ -static inline u32 f2fs_xflags_to_iflags(u32 xflags) -{ - u32 iflags = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(f2fs_xflags_map); i++) - if (xflags & f2fs_xflags_map[i].xflag) - iflags |= f2fs_xflags_map[i].iflag; - - return iflags; -} - -static void f2fs_fill_fsxattr(struct inode *inode, struct fsxattr *fa) +int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa) { + struct inode *inode = d_inode(dentry); struct f2fs_inode_info *fi = F2FS_I(inode); + u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags); - simple_fill_fsxattr(fa, f2fs_iflags_to_xflags(fi->i_flags)); + if (IS_ENCRYPTED(inode)) + fsflags |= FS_ENCRYPT_FL; + if (IS_VERITY(inode)) + fsflags |= FS_VERITY_FL; + if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) + fsflags |= FS_INLINE_DATA_FL; + if (is_inode_flag_set(inode, FI_PIN_FILE)) + fsflags |= FS_NOCOW_FL; + + fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL); if (f2fs_sb_has_project_quota(F2FS_I_SB(inode))) fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid); -} -static int f2fs_ioc_fsgetxattr(struct file *filp, unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct fsxattr fa; - - f2fs_fill_fsxattr(inode, &fa); - - if (copy_to_user((struct fsxattr __user *)arg, &fa, sizeof(fa))) - return -EFAULT; return 0; } -static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) +int f2fs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { - struct inode *inode = file_inode(filp); - struct fsxattr fa, old_fa; + struct inode *inode = d_inode(dentry); + u32 fsflags = fa->flags, mask = F2FS_SETTABLE_FS_FL; u32 iflags; int err; - if (copy_from_user(&fa, (struct fsxattr __user *)arg, sizeof(fa))) - return -EFAULT; - - /* Make sure caller has proper permission */ - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; - - if (fa.fsx_xflags & ~F2FS_SUPPORTED_XFLAGS) + if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) + return -EIO; + if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode))) + return -ENOSPC; + if (fsflags & ~F2FS_GETTABLE_FS_FL) return -EOPNOTSUPP; + fsflags &= F2FS_SETTABLE_FS_FL; + if (!fa->flags_valid) + mask &= FS_COMMON_FL; - iflags = f2fs_xflags_to_iflags(fa.fsx_xflags); + iflags = f2fs_fsflags_to_iflags(fsflags); if (f2fs_mask_flags(inode->i_mode, iflags) != iflags) return -EOPNOTSUPP; - err = mnt_want_write_file(filp); - if (err) - return err; - - inode_lock(inode); - - f2fs_fill_fsxattr(inode, &old_fa); - err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa); - if (err) - goto out; - - err = f2fs_setflags_common(inode, iflags, - f2fs_xflags_to_iflags(F2FS_SUPPORTED_XFLAGS)); - if (err) - goto out; + err = f2fs_setflags_common(inode, iflags, f2fs_fsflags_to_iflags(mask)); + if (!err) + err = f2fs_ioc_setproject(inode, fa->fsx_projid); - err = f2fs_ioc_setproject(filp, fa.fsx_projid); -out: - inode_unlock(inode); - mnt_drop_write_file(filp); return err; } @@ -4051,7 +3927,7 @@ out: static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len) { - DEFINE_READAHEAD(ractl, NULL, inode->i_mapping, page_idx); + DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, page_idx); struct address_space *mapping = inode->i_mapping; struct page *page; pgoff_t redirty_idx = page_idx; @@ -4233,10 +4109,6 @@ out: static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { - case FS_IOC_GETFLAGS: - return f2fs_ioc_getflags(filp, arg); - case FS_IOC_SETFLAGS: - return f2fs_ioc_setflags(filp, arg); case FS_IOC_GETVERSION: return f2fs_ioc_getversion(filp, arg); case F2FS_IOC_START_ATOMIC_WRITE: @@ -4285,10 +4157,6 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return f2fs_ioc_flush_device(filp, arg); case F2FS_IOC_GET_FEATURES: return f2fs_ioc_get_features(filp, arg); - case FS_IOC_FSGETXATTR: - return f2fs_ioc_fsgetxattr(filp, arg); - case FS_IOC_FSSETXATTR: - return f2fs_ioc_fssetxattr(filp, arg); case F2FS_IOC_GET_PIN_FILE: return f2fs_ioc_get_pin_file(filp, arg); case F2FS_IOC_SET_PIN_FILE: @@ -4518,12 +4386,6 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -ENOSPC; switch (cmd) { - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; case FS_IOC32_GETVERSION: cmd = FS_IOC_GETVERSION; break; @@ -4552,8 +4414,6 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case F2FS_IOC_DEFRAGMENT: case F2FS_IOC_FLUSH_DEVICE: case F2FS_IOC_GET_FEATURES: - case FS_IOC_FSGETXATTR: - case FS_IOC_FSSETXATTR: case F2FS_IOC_GET_PIN_FILE: case F2FS_IOC_SET_PIN_FILE: case F2FS_IOC_PRECACHE_EXTENTS: diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 17bd072a5d393f9880d543f735db0d58d834d215..14bf4f65bcb33ae72f8aa620d47434e5d8dc6047 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1327,6 +1327,8 @@ const struct inode_operations f2fs_dir_inode_operations = { .set_acl = f2fs_set_acl, .listxattr = f2fs_listxattr, .fiemap = f2fs_fiemap, + .fileattr_get = f2fs_fileattr_get, + .fileattr_set = f2fs_fileattr_set, }; const struct inode_operations f2fs_symlink_inode_operations = { diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index 054ec852b5ea40ec4f3f1750c79e7480ac498e5a..a7beff28a3c598d3086f9be2e321417bc7d0c3c4 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -228,7 +228,7 @@ static struct page *f2fs_read_merkle_tree_page(struct inode *inode, pgoff_t index, unsigned long num_ra_pages) { - DEFINE_READAHEAD(ractl, NULL, inode->i_mapping, index); + DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index); struct page *page; index += f2fs_verity_metadata_pos(inode) >> PAGE_SHIFT; diff --git a/fs/fscache/Kconfig b/fs/fscache/Kconfig index 5e796e6c38e56146a87cf9c0fabc892f7506e5d3..427efa73b9bdff5f146fdac59b720b8100c61bc9 100644 --- a/fs/fscache/Kconfig +++ b/fs/fscache/Kconfig @@ -2,6 +2,7 @@ config FSCACHE tristate "General filesystem local caching manager" + select NETFS_SUPPORT help This option enables a generic filesystem caching manager that can be used by various network and other filesystems to cache data locally. diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile index 79e08e05ef84803437a4d1af3fa6589eba62a62b..3b2ffa93ac184ff8c11451545f3243e6af5ecdd0 100644 --- a/fs/fscache/Makefile +++ b/fs/fscache/Makefile @@ -7,6 +7,7 @@ fscache-y := \ cache.o \ cookie.o \ fsdef.o \ + io.o \ main.o \ netfs.o \ object.o \ diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 08e91efbce538c15ff3b69634634055c78fdeb87..c483863b740adee564f9df12022fa13c9848050a 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h @@ -142,6 +142,10 @@ extern int fscache_wait_for_operation_activation(struct fscache_object *, atomic_t *, atomic_t *); extern void fscache_invalidate_writes(struct fscache_cookie *); +struct fscache_retrieval *fscache_alloc_retrieval(struct fscache_cookie *cookie, + struct address_space *mapping, + fscache_rw_complete_t end_io_func, + void *context); /* * proc.c diff --git a/fs/fscache/io.c b/fs/fscache/io.c new file mode 100644 index 0000000000000000000000000000000000000000..8ecc1141802f4e8e93146fd7ea3c9859dccacb1e --- /dev/null +++ b/fs/fscache/io.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Cache data I/O routines + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#define FSCACHE_DEBUG_LEVEL PAGE +#include <linux/module.h> +#define FSCACHE_USE_NEW_IO_API +#include <linux/fscache-cache.h> +#include <linux/slab.h> +#include <linux/netfs.h> +#include "internal.h" + +/* + * Start a cache read operation. + * - we return: + * -ENOMEM - out of memory, some pages may be being read + * -ERESTARTSYS - interrupted, some pages may be being read + * -ENOBUFS - no backing object or space available in which to cache any + * pages not being read + * -ENODATA - no data available in the backing object for some or all of + * the pages + * 0 - dispatched a read on all pages + */ +int __fscache_begin_read_operation(struct netfs_read_request *rreq, + struct fscache_cookie *cookie) +{ + struct fscache_retrieval *op; + struct fscache_object *object; + bool wake_cookie = false; + int ret; + + _enter("rr=%08x", rreq->debug_id); + + fscache_stat(&fscache_n_retrievals); + + if (hlist_empty(&cookie->backing_objects)) + goto nobufs; + + if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { + _leave(" = -ENOBUFS [invalidating]"); + return -ENOBUFS; + } + + ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); + + if (fscache_wait_for_deferred_lookup(cookie) < 0) + return -ERESTARTSYS; + + op = fscache_alloc_retrieval(cookie, NULL, NULL, NULL); + if (!op) + return -ENOMEM; + trace_fscache_page_op(cookie, NULL, &op->op, fscache_page_op_retr_multi); + + spin_lock(&cookie->lock); + + if (!fscache_cookie_enabled(cookie) || + hlist_empty(&cookie->backing_objects)) + goto nobufs_unlock; + object = hlist_entry(cookie->backing_objects.first, + struct fscache_object, cookie_link); + + __fscache_use_cookie(cookie); + atomic_inc(&object->n_reads); + __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); + + if (fscache_submit_op(object, &op->op) < 0) + goto nobufs_unlock_dec; + spin_unlock(&cookie->lock); + + fscache_stat(&fscache_n_retrieval_ops); + + /* we wait for the operation to become active, and then process it + * *here*, in this thread, and not in the thread pool */ + ret = fscache_wait_for_operation_activation( + object, &op->op, + __fscache_stat(&fscache_n_retrieval_op_waits), + __fscache_stat(&fscache_n_retrievals_object_dead)); + if (ret < 0) + goto error; + + /* ask the cache to honour the operation */ + ret = object->cache->ops->begin_read_operation(rreq, op); + +error: + if (ret == -ENOMEM) + fscache_stat(&fscache_n_retrievals_nomem); + else if (ret == -ERESTARTSYS) + fscache_stat(&fscache_n_retrievals_intr); + else if (ret == -ENODATA) + fscache_stat(&fscache_n_retrievals_nodata); + else if (ret < 0) + fscache_stat(&fscache_n_retrievals_nobufs); + else + fscache_stat(&fscache_n_retrievals_ok); + + fscache_put_retrieval(op); + _leave(" = %d", ret); + return ret; + +nobufs_unlock_dec: + atomic_dec(&object->n_reads); + wake_cookie = __fscache_unuse_cookie(cookie); +nobufs_unlock: + spin_unlock(&cookie->lock); + fscache_put_retrieval(op); + if (wake_cookie) + __fscache_wake_unused_cookie(cookie); +nobufs: + fscache_stat(&fscache_n_retrievals_nobufs); + _leave(" = -ENOBUFS"); + return -ENOBUFS; +} +EXPORT_SYMBOL(__fscache_begin_read_operation); diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 26af6fdf15387fa3e39442b7df2c62706a1afff0..991b0a871744e13f736eec4a0e48504dc225e652 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -299,7 +299,7 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) /* * allocate a retrieval op */ -static struct fscache_retrieval *fscache_alloc_retrieval( +struct fscache_retrieval *fscache_alloc_retrieval( struct fscache_cookie *cookie, struct address_space *mapping, fscache_rw_complete_t end_io_func, diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index a5aa93ece8c50e4cebcdc05067d801e2d200c991..a7c3ed89a3e0396eca98202245d485bb6093417f 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c @@ -278,5 +278,6 @@ int fscache_stats_show(struct seq_file *m, void *v) atomic_read(&fscache_n_cache_stale_objects), atomic_read(&fscache_n_cache_retired_objects), atomic_read(&fscache_n_cache_culled_objects)); + netfs_stats_show(m); return 0; } diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 20ed23aa16fa6a10e82cce28ba432a4a34771617..d9e1b47382f3a767a5e1c3b10a1c7089df08dffe 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_FUSE_FS) += fuse.o obj-$(CONFIG_CUSE) += cuse.o obj-$(CONFIG_VIRTIO_FS) += virtiofs.o -fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o +fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o fuse-y += passthrough.o fuse-$(CONFIG_FUSE_DAX) += dax.o diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 5f4a4c0df091080c373b04c625be9216c2623a1d..228215f5413119c3507a3190c1f0f0fd5bb7e74a 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -252,7 +252,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) if (ret == -ENOMEM) goto out; if (ret || fuse_invalid_attr(&outarg.attr) || - (outarg.attr.mode ^ inode->i_mode) & S_IFMT) + inode_wrong_type(inode, outarg.attr.mode)) goto invalid; forget_all_cached_acls(inode); @@ -548,7 +548,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, * 'mknod' + 'open' requests. */ static int fuse_create_open(struct inode *dir, struct dentry *entry, - struct file *file, unsigned flags, + struct file *file, unsigned int flags, umode_t mode) { int err; @@ -1096,7 +1096,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, err = fuse_simple_request(fm, &args); if (!err) { if (fuse_invalid_attr(&outarg.attr) || - (inode->i_mode ^ outarg.attr.mode) & S_IFMT) { + inode_wrong_type(inode, outarg.attr.mode)) { fuse_make_bad(inode); err = -EIO; } else { @@ -1745,7 +1745,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, } if (fuse_invalid_attr(&outarg.attr) || - (inode->i_mode ^ outarg.attr.mode) & S_IFMT) { + inode_wrong_type(inode, outarg.attr.mode)) { fuse_make_bad(inode); err = -EIO; goto error; @@ -1908,6 +1908,8 @@ static const struct inode_operations fuse_dir_inode_operations = { .listxattr = fuse_listxattr, .get_acl = fuse_get_acl, .set_acl = fuse_set_acl, + .fileattr_get = fuse_fileattr_get, + .fileattr_set = fuse_fileattr_set, }; static const struct file_operations fuse_dir_operations = { @@ -1928,6 +1930,8 @@ static const struct inode_operations fuse_common_inode_operations = { .listxattr = fuse_listxattr, .get_acl = fuse_get_acl, .set_acl = fuse_set_acl, + .fileattr_get = fuse_fileattr_get, + .fileattr_set = fuse_fileattr_set, }; static const struct inode_operations fuse_symlink_inode_operations = { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e3741a94c1f9df3c238f4a2765e51c8430cae9c1..dce23741a0bfcea9aab7d776a4a2abaded101381 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -14,32 +14,20 @@ #include <linux/sched.h> #include <linux/sched/signal.h> #include <linux/module.h> -#include <linux/compat.h> #include <linux/swap.h> #include <linux/falloc.h> #include <linux/uio.h> #include <linux/fs.h> -static struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, - struct fuse_page_desc **desc) -{ - struct page **pages; - - pages = kzalloc(npages * (sizeof(struct page *) + - sizeof(struct fuse_page_desc)), flags); - *desc = (void *) (pages + npages); - - return pages; -} - -static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, struct file *file, - int opcode, struct fuse_open_out *outargp) +static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, + unsigned int open_flags, int opcode, + struct fuse_open_out *outargp) { struct fuse_open_in inarg; FUSE_ARGS(args); memset(&inarg, 0, sizeof(inarg)); - inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); + inarg.flags = open_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); if (!fm->fc->atomic_o_trunc) inarg.flags &= ~O_TRUNC; @@ -136,8 +124,8 @@ static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) } } -int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, - bool isdir) +struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, + unsigned int open_flags, bool isdir) { struct fuse_conn *fc = fm->fc; struct fuse_file *ff; @@ -145,7 +133,7 @@ int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, ff = fuse_file_alloc(fm); if (!ff) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ff->fh = 0; /* Default for no-open */ @@ -154,14 +142,14 @@ int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, struct fuse_open_out outarg; int err; - err = fuse_send_open(fm, nodeid, file, opcode, &outarg); + err = fuse_send_open(fm, nodeid, open_flags, opcode, &outarg); if (!err) { ff->fh = outarg.fh; ff->open_flags = outarg.open_flags; fuse_passthrough_setup(fc, ff, &outarg); } else if (err != -ENOSYS) { fuse_file_free(ff); - return err; + return ERR_PTR(err); } else { if (isdir) fc->no_opendir = 1; @@ -174,9 +162,19 @@ int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, ff->open_flags &= ~FOPEN_DIRECT_IO; ff->nodeid = nodeid; - file->private_data = ff; - return 0; + return ff; +} + +int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, + bool isdir) +{ + struct fuse_file *ff = fuse_file_open(fm, nodeid, file->f_flags, isdir); + + if (!IS_ERR(ff)) + file->private_data = ff; + + return PTR_ERR_OR_ZERO(ff); } EXPORT_SYMBOL_GPL(fuse_do_open); @@ -268,7 +266,7 @@ out: } static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff, - int flags, int opcode) + unsigned int flags, int opcode) { struct fuse_conn *fc = ff->fm->fc; struct fuse_release_args *ra = ff->release_args; @@ -297,24 +295,23 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff, ra->args.nocreds = true; } -void fuse_release_common(struct file *file, bool isdir) +void fuse_file_release(struct inode *inode, struct fuse_file *ff, + unsigned int open_flags, fl_owner_t id, bool isdir) { - struct fuse_inode *fi = get_fuse_inode(file_inode(file)); - struct fuse_file *ff = file->private_data; + struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_release_args *ra = ff->release_args; int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; fuse_passthrough_release(&ff->passthrough); - fuse_prepare_release(fi, ff, file->f_flags, opcode); + fuse_prepare_release(fi, ff, open_flags, opcode); if (ff->flock) { ra->inarg.release_flags |= FUSE_RELEASE_FLOCK_UNLOCK; - ra->inarg.lock_owner = fuse_lock_owner_id(ff->fm->fc, - (fl_owner_t) file); + ra->inarg.lock_owner = fuse_lock_owner_id(ff->fm->fc, id); } /* Hold inode until release is finished */ - ra->inode = igrab(file_inode(file)); + ra->inode = igrab(inode); /* * Normally this will send the RELEASE request, however if @@ -328,6 +325,12 @@ void fuse_release_common(struct file *file, bool isdir) fuse_file_put(ff, ff->fm->fc->destroy, isdir); } +void fuse_release_common(struct file *file, bool isdir) +{ + fuse_file_release(file_inode(file), file->private_data, file->f_flags, + (fl_owner_t) file, isdir); +} + static int fuse_open(struct inode *inode, struct file *file) { return fuse_open_common(inode, file, false); @@ -347,7 +350,8 @@ static int fuse_release(struct inode *inode, struct file *file) return 0; } -void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, int flags) +void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, + unsigned int flags) { WARN_ON(refcount_read(&ff->count) > 1); fuse_prepare_release(fi, ff, flags, FUSE_RELEASE); @@ -1348,16 +1352,6 @@ out: return written ? written : err; } -static inline void fuse_page_descs_length_init(struct fuse_page_desc *descs, - unsigned int index, - unsigned int nr_pages) -{ - int i; - - for (i = index; i < index + nr_pages; i++) - descs[i].length = PAGE_SIZE - descs[i].offset; -} - static inline unsigned long fuse_get_user_addr(const struct iov_iter *ii) { return (unsigned long)ii->iov->iov_base + ii->iov_offset; @@ -2645,363 +2639,6 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) return retval; } -/* - * CUSE servers compiled on 32bit broke on 64bit kernels because the - * ABI was defined to be 'struct iovec' which is different on 32bit - * and 64bit. Fortunately we can determine which structure the server - * used from the size of the reply. - */ -static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src, - size_t transferred, unsigned count, - bool is_compat) -{ -#ifdef CONFIG_COMPAT - if (count * sizeof(struct compat_iovec) == transferred) { - struct compat_iovec *ciov = src; - unsigned i; - - /* - * With this interface a 32bit server cannot support - * non-compat (i.e. ones coming from 64bit apps) ioctl - * requests - */ - if (!is_compat) - return -EINVAL; - - for (i = 0; i < count; i++) { - dst[i].iov_base = compat_ptr(ciov[i].iov_base); - dst[i].iov_len = ciov[i].iov_len; - } - return 0; - } -#endif - - if (count * sizeof(struct iovec) != transferred) - return -EIO; - - memcpy(dst, src, transferred); - return 0; -} - -/* Make sure iov_length() won't overflow */ -static int fuse_verify_ioctl_iov(struct fuse_conn *fc, struct iovec *iov, - size_t count) -{ - size_t n; - u32 max = fc->max_pages << PAGE_SHIFT; - - for (n = 0; n < count; n++, iov++) { - if (iov->iov_len > (size_t) max) - return -ENOMEM; - max -= iov->iov_len; - } - return 0; -} - -static int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst, - void *src, size_t transferred, unsigned count, - bool is_compat) -{ - unsigned i; - struct fuse_ioctl_iovec *fiov = src; - - if (fc->minor < 16) { - return fuse_copy_ioctl_iovec_old(dst, src, transferred, - count, is_compat); - } - - if (count * sizeof(struct fuse_ioctl_iovec) != transferred) - return -EIO; - - for (i = 0; i < count; i++) { - /* Did the server supply an inappropriate value? */ - if (fiov[i].base != (unsigned long) fiov[i].base || - fiov[i].len != (unsigned long) fiov[i].len) - return -EIO; - - dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base; - dst[i].iov_len = (size_t) fiov[i].len; - -#ifdef CONFIG_COMPAT - if (is_compat && - (ptr_to_compat(dst[i].iov_base) != fiov[i].base || - (compat_size_t) dst[i].iov_len != fiov[i].len)) - return -EIO; -#endif - } - - return 0; -} - - -/* - * For ioctls, there is no generic way to determine how much memory - * needs to be read and/or written. Furthermore, ioctls are allowed - * to dereference the passed pointer, so the parameter requires deep - * copying but FUSE has no idea whatsoever about what to copy in or - * out. - * - * This is solved by allowing FUSE server to retry ioctl with - * necessary in/out iovecs. Let's assume the ioctl implementation - * needs to read in the following structure. - * - * struct a { - * char *buf; - * size_t buflen; - * } - * - * On the first callout to FUSE server, inarg->in_size and - * inarg->out_size will be NULL; then, the server completes the ioctl - * with FUSE_IOCTL_RETRY set in out->flags, out->in_iovs set to 1 and - * the actual iov array to - * - * { { .iov_base = inarg.arg, .iov_len = sizeof(struct a) } } - * - * which tells FUSE to copy in the requested area and retry the ioctl. - * On the second round, the server has access to the structure and - * from that it can tell what to look for next, so on the invocation, - * it sets FUSE_IOCTL_RETRY, out->in_iovs to 2 and iov array to - * - * { { .iov_base = inarg.arg, .iov_len = sizeof(struct a) }, - * { .iov_base = a.buf, .iov_len = a.buflen } } - * - * FUSE will copy both struct a and the pointed buffer from the - * process doing the ioctl and retry ioctl with both struct a and the - * buffer. - * - * This time, FUSE server has everything it needs and completes ioctl - * without FUSE_IOCTL_RETRY which finishes the ioctl call. - * - * Copying data out works the same way. - * - * Note that if FUSE_IOCTL_UNRESTRICTED is clear, the kernel - * automatically initializes in and out iovs by decoding @cmd with - * _IOC_* macros and the server is not allowed to request RETRY. This - * limits ioctl data transfers to well-formed ioctls and is the forced - * behavior for all FUSE servers. - */ -long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, - unsigned int flags) -{ - struct fuse_file *ff = file->private_data; - struct fuse_mount *fm = ff->fm; - struct fuse_ioctl_in inarg = { - .fh = ff->fh, - .cmd = cmd, - .arg = arg, - .flags = flags - }; - struct fuse_ioctl_out outarg; - struct iovec *iov_page = NULL; - struct iovec *in_iov = NULL, *out_iov = NULL; - unsigned int in_iovs = 0, out_iovs = 0, max_pages; - size_t in_size, out_size, c; - ssize_t transferred; - int err, i; - struct iov_iter ii; - struct fuse_args_pages ap = {}; - -#if BITS_PER_LONG == 32 - inarg.flags |= FUSE_IOCTL_32BIT; -#else - if (flags & FUSE_IOCTL_COMPAT) { - inarg.flags |= FUSE_IOCTL_32BIT; -#ifdef CONFIG_X86_X32 - if (in_x32_syscall()) - inarg.flags |= FUSE_IOCTL_COMPAT_X32; -#endif - } -#endif - - /* assume all the iovs returned by client always fits in a page */ - BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); - - err = -ENOMEM; - ap.pages = fuse_pages_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.descs); - iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); - if (!ap.pages || !iov_page) - goto out; - - fuse_page_descs_length_init(ap.descs, 0, fm->fc->max_pages); - - /* - * If restricted, initialize IO parameters as encoded in @cmd. - * RETRY from server is not allowed. - */ - if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { - struct iovec *iov = iov_page; - - iov->iov_base = (void __user *)arg; - - switch (cmd) { - case FS_IOC_GETFLAGS: - case FS_IOC_SETFLAGS: - iov->iov_len = sizeof(int); - break; - default: - iov->iov_len = _IOC_SIZE(cmd); - break; - } - - if (_IOC_DIR(cmd) & _IOC_WRITE) { - in_iov = iov; - in_iovs = 1; - } - - if (_IOC_DIR(cmd) & _IOC_READ) { - out_iov = iov; - out_iovs = 1; - } - } - - retry: - inarg.in_size = in_size = iov_length(in_iov, in_iovs); - inarg.out_size = out_size = iov_length(out_iov, out_iovs); - - /* - * Out data can be used either for actual out data or iovs, - * make sure there always is at least one page. - */ - out_size = max_t(size_t, out_size, PAGE_SIZE); - max_pages = DIV_ROUND_UP(max(in_size, out_size), PAGE_SIZE); - - /* make sure there are enough buffer pages and init request with them */ - err = -ENOMEM; - if (max_pages > fm->fc->max_pages) - goto out; - while (ap.num_pages < max_pages) { - ap.pages[ap.num_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!ap.pages[ap.num_pages]) - goto out; - ap.num_pages++; - } - - - /* okay, let's send it to the client */ - ap.args.opcode = FUSE_IOCTL; - ap.args.nodeid = ff->nodeid; - ap.args.in_numargs = 1; - ap.args.in_args[0].size = sizeof(inarg); - ap.args.in_args[0].value = &inarg; - if (in_size) { - ap.args.in_numargs++; - ap.args.in_args[1].size = in_size; - ap.args.in_pages = true; - - err = -EFAULT; - iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size); - for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) { - c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii); - if (c != PAGE_SIZE && iov_iter_count(&ii)) - goto out; - } - } - - ap.args.out_numargs = 2; - ap.args.out_args[0].size = sizeof(outarg); - ap.args.out_args[0].value = &outarg; - ap.args.out_args[1].size = out_size; - ap.args.out_pages = true; - ap.args.out_argvar = true; - - transferred = fuse_simple_request(fm, &ap.args); - err = transferred; - if (transferred < 0) - goto out; - - /* did it ask for retry? */ - if (outarg.flags & FUSE_IOCTL_RETRY) { - void *vaddr; - - /* no retry if in restricted mode */ - err = -EIO; - if (!(flags & FUSE_IOCTL_UNRESTRICTED)) - goto out; - - in_iovs = outarg.in_iovs; - out_iovs = outarg.out_iovs; - - /* - * Make sure things are in boundary, separate checks - * are to protect against overflow. - */ - err = -ENOMEM; - if (in_iovs > FUSE_IOCTL_MAX_IOV || - out_iovs > FUSE_IOCTL_MAX_IOV || - in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) - goto out; - - vaddr = kmap_atomic(ap.pages[0]); - err = fuse_copy_ioctl_iovec(fm->fc, iov_page, vaddr, - transferred, in_iovs + out_iovs, - (flags & FUSE_IOCTL_COMPAT) != 0); - kunmap_atomic(vaddr); - if (err) - goto out; - - in_iov = iov_page; - out_iov = in_iov + in_iovs; - - err = fuse_verify_ioctl_iov(fm->fc, in_iov, in_iovs); - if (err) - goto out; - - err = fuse_verify_ioctl_iov(fm->fc, out_iov, out_iovs); - if (err) - goto out; - - goto retry; - } - - err = -EIO; - if (transferred > inarg.out_size) - goto out; - - err = -EFAULT; - iov_iter_init(&ii, READ, out_iov, out_iovs, transferred); - for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) { - c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii); - if (c != PAGE_SIZE && iov_iter_count(&ii)) - goto out; - } - err = 0; - out: - free_page((unsigned long) iov_page); - while (ap.num_pages) - __free_page(ap.pages[--ap.num_pages]); - kfree(ap.pages); - - return err ? err : outarg.result; -} -EXPORT_SYMBOL_GPL(fuse_do_ioctl); - -long fuse_ioctl_common(struct file *file, unsigned int cmd, - unsigned long arg, unsigned int flags) -{ - struct inode *inode = file_inode(file); - struct fuse_conn *fc = get_fuse_conn(inode); - - if (!fuse_allow_current_process(fc)) - return -EACCES; - - if (fuse_is_bad(inode)) - return -EIO; - - return fuse_do_ioctl(file, cmd, arg, flags); -} - -static long fuse_file_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return fuse_ioctl_common(file, cmd, arg, 0); -} - -static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT); -} - /* * All files which have been polled are linked to RB tree * fuse_conn->polled_files which is indexed by kh. Walk the tree and diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 318a5d712c4e1ec22bda85b4710493338dc1fb43..3b9c8842f9aea15f0b1f0a33405a95470860eba1 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -896,6 +896,28 @@ static inline bool fuse_is_bad(struct inode *inode) return unlikely(test_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state)); } +static inline struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, + struct fuse_page_desc **desc) +{ + struct page **pages; + + pages = kzalloc(npages * (sizeof(struct page *) + + sizeof(struct fuse_page_desc)), flags); + *desc = (void *) (pages + npages); + + return pages; +} + +static inline void fuse_page_descs_length_init(struct fuse_page_desc *descs, + unsigned int index, + unsigned int nr_pages) +{ + int i; + + for (i = index; i < index + nr_pages; i++) + descs[i].length = PAGE_SIZE - descs[i].offset; +} + /** Device operations */ extern const struct file_operations fuse_dev_operations; @@ -956,7 +978,8 @@ struct fuse_file *fuse_file_alloc(struct fuse_mount *fm); void fuse_file_free(struct fuse_file *ff); void fuse_finish_open(struct inode *inode, struct file *file); -void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, int flags); +void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, + unsigned int flags); /** * Send RELEASE or RELEASEDIR request @@ -1238,6 +1261,21 @@ void fuse_dax_inode_cleanup(struct inode *inode); bool fuse_dax_check_alignment(struct fuse_conn *fc, unsigned int map_alignment); void fuse_dax_cancel_work(struct fuse_conn *fc); +/* ioctl.c */ +long fuse_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int fuse_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); + +/* file.c */ + +struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, + unsigned int open_flags, bool isdir); +void fuse_file_release(struct inode *inode, struct fuse_file *ff, + unsigned int open_flags, fl_owner_t id, bool isdir); + /* passthrough.c */ int fuse_passthrough_open(struct fuse_dev *fud, struct fuse_passthrough_out *pto); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7ebc398fbacbc9a9a53c1846db53bcc905b2948d..7b620d9522a9267ee1d2b1359b6a4b8a055f09bb 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -350,7 +350,7 @@ retry: inode->i_generation = generation; fuse_init_inode(inode, attr); unlock_new_inode(inode); - } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { + } else if (inode_wrong_type(inode, attr->mode)) { /* Inode has changed type, any I/O on the old should fail */ fuse_make_bad(inode); iput(inode); diff --git a/fs/fuse/ioctl.c b/fs/fuse/ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..546ea3d58fb475dca6831dd87cd196bf3a912692 --- /dev/null +++ b/fs/fuse/ioctl.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "fuse_i.h" + +#include <linux/uio.h> +#include <linux/compat.h> +#include <linux/fileattr.h> + +/* + * CUSE servers compiled on 32bit broke on 64bit kernels because the + * ABI was defined to be 'struct iovec' which is different on 32bit + * and 64bit. Fortunately we can determine which structure the server + * used from the size of the reply. + */ +static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src, + size_t transferred, unsigned count, + bool is_compat) +{ +#ifdef CONFIG_COMPAT + if (count * sizeof(struct compat_iovec) == transferred) { + struct compat_iovec *ciov = src; + unsigned i; + + /* + * With this interface a 32bit server cannot support + * non-compat (i.e. ones coming from 64bit apps) ioctl + * requests + */ + if (!is_compat) + return -EINVAL; + + for (i = 0; i < count; i++) { + dst[i].iov_base = compat_ptr(ciov[i].iov_base); + dst[i].iov_len = ciov[i].iov_len; + } + return 0; + } +#endif + + if (count * sizeof(struct iovec) != transferred) + return -EIO; + + memcpy(dst, src, transferred); + return 0; +} + +/* Make sure iov_length() won't overflow */ +static int fuse_verify_ioctl_iov(struct fuse_conn *fc, struct iovec *iov, + size_t count) +{ + size_t n; + u32 max = fc->max_pages << PAGE_SHIFT; + + for (n = 0; n < count; n++, iov++) { + if (iov->iov_len > (size_t) max) + return -ENOMEM; + max -= iov->iov_len; + } + return 0; +} + +static int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst, + void *src, size_t transferred, unsigned count, + bool is_compat) +{ + unsigned i; + struct fuse_ioctl_iovec *fiov = src; + + if (fc->minor < 16) { + return fuse_copy_ioctl_iovec_old(dst, src, transferred, + count, is_compat); + } + + if (count * sizeof(struct fuse_ioctl_iovec) != transferred) + return -EIO; + + for (i = 0; i < count; i++) { + /* Did the server supply an inappropriate value? */ + if (fiov[i].base != (unsigned long) fiov[i].base || + fiov[i].len != (unsigned long) fiov[i].len) + return -EIO; + + dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base; + dst[i].iov_len = (size_t) fiov[i].len; + +#ifdef CONFIG_COMPAT + if (is_compat && + (ptr_to_compat(dst[i].iov_base) != fiov[i].base || + (compat_size_t) dst[i].iov_len != fiov[i].len)) + return -EIO; +#endif + } + + return 0; +} + + +/* + * For ioctls, there is no generic way to determine how much memory + * needs to be read and/or written. Furthermore, ioctls are allowed + * to dereference the passed pointer, so the parameter requires deep + * copying but FUSE has no idea whatsoever about what to copy in or + * out. + * + * This is solved by allowing FUSE server to retry ioctl with + * necessary in/out iovecs. Let's assume the ioctl implementation + * needs to read in the following structure. + * + * struct a { + * char *buf; + * size_t buflen; + * } + * + * On the first callout to FUSE server, inarg->in_size and + * inarg->out_size will be NULL; then, the server completes the ioctl + * with FUSE_IOCTL_RETRY set in out->flags, out->in_iovs set to 1 and + * the actual iov array to + * + * { { .iov_base = inarg.arg, .iov_len = sizeof(struct a) } } + * + * which tells FUSE to copy in the requested area and retry the ioctl. + * On the second round, the server has access to the structure and + * from that it can tell what to look for next, so on the invocation, + * it sets FUSE_IOCTL_RETRY, out->in_iovs to 2 and iov array to + * + * { { .iov_base = inarg.arg, .iov_len = sizeof(struct a) }, + * { .iov_base = a.buf, .iov_len = a.buflen } } + * + * FUSE will copy both struct a and the pointed buffer from the + * process doing the ioctl and retry ioctl with both struct a and the + * buffer. + * + * This time, FUSE server has everything it needs and completes ioctl + * without FUSE_IOCTL_RETRY which finishes the ioctl call. + * + * Copying data out works the same way. + * + * Note that if FUSE_IOCTL_UNRESTRICTED is clear, the kernel + * automatically initializes in and out iovs by decoding @cmd with + * _IOC_* macros and the server is not allowed to request RETRY. This + * limits ioctl data transfers to well-formed ioctls and is the forced + * behavior for all FUSE servers. + */ +long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, + unsigned int flags) +{ + struct fuse_file *ff = file->private_data; + struct fuse_mount *fm = ff->fm; + struct fuse_ioctl_in inarg = { + .fh = ff->fh, + .cmd = cmd, + .arg = arg, + .flags = flags + }; + struct fuse_ioctl_out outarg; + struct iovec *iov_page = NULL; + struct iovec *in_iov = NULL, *out_iov = NULL; + unsigned int in_iovs = 0, out_iovs = 0, max_pages; + size_t in_size, out_size, c; + ssize_t transferred; + int err, i; + struct iov_iter ii; + struct fuse_args_pages ap = {}; + +#if BITS_PER_LONG == 32 + inarg.flags |= FUSE_IOCTL_32BIT; +#else + if (flags & FUSE_IOCTL_COMPAT) { + inarg.flags |= FUSE_IOCTL_32BIT; +#ifdef CONFIG_X86_X32 + if (in_x32_syscall()) + inarg.flags |= FUSE_IOCTL_COMPAT_X32; +#endif + } +#endif + + /* assume all the iovs returned by client always fits in a page */ + BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); + + err = -ENOMEM; + ap.pages = fuse_pages_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.descs); + iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); + if (!ap.pages || !iov_page) + goto out; + + fuse_page_descs_length_init(ap.descs, 0, fm->fc->max_pages); + + /* + * If restricted, initialize IO parameters as encoded in @cmd. + * RETRY from server is not allowed. + */ + if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { + struct iovec *iov = iov_page; + + iov->iov_base = (void __user *)arg; + iov->iov_len = _IOC_SIZE(cmd); + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + in_iov = iov; + in_iovs = 1; + } + + if (_IOC_DIR(cmd) & _IOC_READ) { + out_iov = iov; + out_iovs = 1; + } + } + + retry: + inarg.in_size = in_size = iov_length(in_iov, in_iovs); + inarg.out_size = out_size = iov_length(out_iov, out_iovs); + + /* + * Out data can be used either for actual out data or iovs, + * make sure there always is at least one page. + */ + out_size = max_t(size_t, out_size, PAGE_SIZE); + max_pages = DIV_ROUND_UP(max(in_size, out_size), PAGE_SIZE); + + /* make sure there are enough buffer pages and init request with them */ + err = -ENOMEM; + if (max_pages > fm->fc->max_pages) + goto out; + while (ap.num_pages < max_pages) { + ap.pages[ap.num_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + if (!ap.pages[ap.num_pages]) + goto out; + ap.num_pages++; + } + + + /* okay, let's send it to the client */ + ap.args.opcode = FUSE_IOCTL; + ap.args.nodeid = ff->nodeid; + ap.args.in_numargs = 1; + ap.args.in_args[0].size = sizeof(inarg); + ap.args.in_args[0].value = &inarg; + if (in_size) { + ap.args.in_numargs++; + ap.args.in_args[1].size = in_size; + ap.args.in_pages = true; + + err = -EFAULT; + iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size); + for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) { + c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii); + if (c != PAGE_SIZE && iov_iter_count(&ii)) + goto out; + } + } + + ap.args.out_numargs = 2; + ap.args.out_args[0].size = sizeof(outarg); + ap.args.out_args[0].value = &outarg; + ap.args.out_args[1].size = out_size; + ap.args.out_pages = true; + ap.args.out_argvar = true; + + transferred = fuse_simple_request(fm, &ap.args); + err = transferred; + if (transferred < 0) + goto out; + + /* did it ask for retry? */ + if (outarg.flags & FUSE_IOCTL_RETRY) { + void *vaddr; + + /* no retry if in restricted mode */ + err = -EIO; + if (!(flags & FUSE_IOCTL_UNRESTRICTED)) + goto out; + + in_iovs = outarg.in_iovs; + out_iovs = outarg.out_iovs; + + /* + * Make sure things are in boundary, separate checks + * are to protect against overflow. + */ + err = -ENOMEM; + if (in_iovs > FUSE_IOCTL_MAX_IOV || + out_iovs > FUSE_IOCTL_MAX_IOV || + in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) + goto out; + + vaddr = kmap_atomic(ap.pages[0]); + err = fuse_copy_ioctl_iovec(fm->fc, iov_page, vaddr, + transferred, in_iovs + out_iovs, + (flags & FUSE_IOCTL_COMPAT) != 0); + kunmap_atomic(vaddr); + if (err) + goto out; + + in_iov = iov_page; + out_iov = in_iov + in_iovs; + + err = fuse_verify_ioctl_iov(fm->fc, in_iov, in_iovs); + if (err) + goto out; + + err = fuse_verify_ioctl_iov(fm->fc, out_iov, out_iovs); + if (err) + goto out; + + goto retry; + } + + err = -EIO; + if (transferred > inarg.out_size) + goto out; + + err = -EFAULT; + iov_iter_init(&ii, READ, out_iov, out_iovs, transferred); + for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) { + c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii); + if (c != PAGE_SIZE && iov_iter_count(&ii)) + goto out; + } + err = 0; + out: + free_page((unsigned long) iov_page); + while (ap.num_pages) + __free_page(ap.pages[--ap.num_pages]); + kfree(ap.pages); + + return err ? err : outarg.result; +} +EXPORT_SYMBOL_GPL(fuse_do_ioctl); + +long fuse_ioctl_common(struct file *file, unsigned int cmd, + unsigned long arg, unsigned int flags) +{ + struct inode *inode = file_inode(file); + struct fuse_conn *fc = get_fuse_conn(inode); + + if (!fuse_allow_current_process(fc)) + return -EACCES; + + if (fuse_is_bad(inode)) + return -EIO; + + return fuse_do_ioctl(file, cmd, arg, flags); +} + +long fuse_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return fuse_ioctl_common(file, cmd, arg, 0); +} + +long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT); +} + +static int fuse_priv_ioctl(struct inode *inode, struct fuse_file *ff, + unsigned int cmd, void *ptr, size_t size) +{ + struct fuse_mount *fm = ff->fm; + struct fuse_ioctl_in inarg; + struct fuse_ioctl_out outarg; + FUSE_ARGS(args); + int err; + + memset(&inarg, 0, sizeof(inarg)); + inarg.fh = ff->fh; + inarg.cmd = cmd; + +#if BITS_PER_LONG == 32 + inarg.flags |= FUSE_IOCTL_32BIT; +#endif + if (S_ISDIR(inode->i_mode)) + inarg.flags |= FUSE_IOCTL_DIR; + + if (_IOC_DIR(cmd) & _IOC_READ) + inarg.out_size = size; + if (_IOC_DIR(cmd) & _IOC_WRITE) + inarg.in_size = size; + + args.opcode = FUSE_IOCTL; + args.nodeid = ff->nodeid; + args.in_numargs = 2; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + args.in_args[1].size = inarg.in_size; + args.in_args[1].value = ptr; + args.out_numargs = 2; + args.out_args[0].size = sizeof(outarg); + args.out_args[0].value = &outarg; + args.out_args[1].size = inarg.out_size; + args.out_args[1].value = ptr; + + err = fuse_simple_request(fm, &args); + if (!err && outarg.flags & FUSE_IOCTL_RETRY) + err = -EIO; + + return err; +} + +static struct fuse_file *fuse_priv_ioctl_prepare(struct inode *inode) +{ + struct fuse_mount *fm = get_fuse_mount(inode); + bool isdir = S_ISDIR(inode->i_mode); + + if (!S_ISREG(inode->i_mode) && !isdir) + return ERR_PTR(-ENOTTY); + + return fuse_file_open(fm, get_node_id(inode), O_RDONLY, isdir); +} + +static void fuse_priv_ioctl_cleanup(struct inode *inode, struct fuse_file *ff) +{ + fuse_file_release(inode, ff, O_RDONLY, NULL, S_ISDIR(inode->i_mode)); +} + +int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct fuse_file *ff; + unsigned int flags; + struct fsxattr xfa; + int err; + + ff = fuse_priv_ioctl_prepare(inode); + if (IS_ERR(ff)) + return PTR_ERR(ff); + + if (fa->flags_valid) { + err = fuse_priv_ioctl(inode, ff, FS_IOC_GETFLAGS, + &flags, sizeof(flags)); + if (err) + goto cleanup; + + fileattr_fill_flags(fa, flags); + } else { + err = fuse_priv_ioctl(inode, ff, FS_IOC_FSGETXATTR, + &xfa, sizeof(xfa)); + if (err) + goto cleanup; + + fileattr_fill_xflags(fa, xfa.fsx_xflags); + fa->fsx_extsize = xfa.fsx_extsize; + fa->fsx_nextents = xfa.fsx_nextents; + fa->fsx_projid = xfa.fsx_projid; + fa->fsx_cowextsize = xfa.fsx_cowextsize; + } +cleanup: + fuse_priv_ioctl_cleanup(inode, ff); + + return err; +} + +int fuse_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct fuse_file *ff; + unsigned int flags = fa->flags; + struct fsxattr xfa; + int err; + + ff = fuse_priv_ioctl_prepare(inode); + if (IS_ERR(ff)) + return PTR_ERR(ff); + + if (fa->flags_valid) { + err = fuse_priv_ioctl(inode, ff, FS_IOC_SETFLAGS, + &flags, sizeof(flags)); + if (err) + goto cleanup; + } else { + memset(&xfa, 0, sizeof(xfa)); + xfa.fsx_xflags = fa->fsx_xflags; + xfa.fsx_extsize = fa->fsx_extsize; + xfa.fsx_nextents = fa->fsx_nextents; + xfa.fsx_projid = fa->fsx_projid; + xfa.fsx_cowextsize = fa->fsx_cowextsize; + + err = fuse_priv_ioctl(inode, ff, FS_IOC_FSSETXATTR, + &xfa, sizeof(xfa)); + } + +cleanup: + fuse_priv_ioctl_cleanup(inode, ff); + + return err; +} diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index 3441ffa740f3d71b15021c058bdad82bbde25577..277f7041d55aacd1285e674f4f46f746cdf08ad1 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -202,7 +202,7 @@ retry: inode = d_inode(dentry); if (!inode || get_node_id(inode) != o->nodeid || - ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { + inode_wrong_type(inode, o->attr.mode)) { d_invalidate(dentry); dput(dentry); goto retry; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 2d500f90cdacf3ae539ad7ab1905be79def0491d..b46714d4810793a4b0a33b4a87b909fa9d9241cf 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -25,6 +25,7 @@ #include <linux/dlm_plock.h> #include <linux/delay.h> #include <linux/backing-dev.h> +#include <linux/fileattr.h> #include "gfs2.h" #include "incore.h" @@ -153,14 +154,17 @@ static inline u32 gfs2_gfsflags_to_fsflags(struct inode *inode, u32 gfsflags) return fsflags; } -static int gfs2_get_flags(struct file *filp, u32 __user *ptr) +int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa) { - struct inode *inode = file_inode(filp); + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; u32 fsflags; + if (d_is_special(dentry)) + return -ENOTTY; + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh); error = gfs2_glock_nq(&gh); if (error) @@ -168,8 +172,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) fsflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags); - if (put_user(fsflags, ptr)) - error = -EFAULT; + fileattr_fill_flags(fa, fsflags); gfs2_glock_dq(&gh); out_uninit: @@ -213,33 +216,19 @@ void gfs2_set_inode_flags(struct inode *inode) * @fsflags: The FS_* inode flags passed in * */ -static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask, +static int do_gfs2_set_flags(struct inode *inode, u32 reqflags, u32 mask, const u32 fsflags) { - struct inode *inode = file_inode(filp); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *bh; struct gfs2_holder gh; int error; - u32 new_flags, flags, oldflags; - - error = mnt_want_write_file(filp); - if (error) - return error; + u32 new_flags, flags; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); if (error) - goto out_drop_write; - - oldflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags); - error = vfs_ioc_setflags_prepare(inode, oldflags, fsflags); - if (error) - goto out; - - error = -EACCES; - if (!inode_owner_or_capable(&init_user_ns, inode)) - goto out; + return error; error = 0; flags = ip->i_diskflags; @@ -252,9 +241,6 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask, goto out; if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY)) goto out; - if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) && - !capable(CAP_LINUX_IMMUTABLE)) - goto out; if (!IS_IMMUTABLE(inode)) { error = gfs2_permission(&init_user_ns, inode, MAY_WRITE); if (error) @@ -291,20 +277,22 @@ out_trans_end: gfs2_trans_end(sdp); out: gfs2_glock_dq_uninit(&gh); -out_drop_write: - mnt_drop_write_file(filp); return error; } -static int gfs2_set_flags(struct file *filp, u32 __user *ptr) +int gfs2_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { - struct inode *inode = file_inode(filp); - u32 fsflags, gfsflags = 0; + struct inode *inode = d_inode(dentry); + u32 fsflags = fa->flags, gfsflags = 0; u32 mask; int i; - if (get_user(fsflags, ptr)) - return -EFAULT; + if (d_is_special(dentry)) + return -ENOTTY; + + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++) { if (fsflags & fsflag_gfs2flag[i].fsflag) { @@ -325,7 +313,7 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr) mask &= ~(GFS2_DIF_TOPDIR | GFS2_DIF_INHERIT_JDATA); } - return do_gfs2_set_flags(filp, gfsflags, mask, fsflags); + return do_gfs2_set_flags(inode, gfsflags, mask, fsflags); } static int gfs2_getlabel(struct file *filp, char __user *label) @@ -342,10 +330,6 @@ static int gfs2_getlabel(struct file *filp, char __user *label) static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { - case FS_IOC_GETFLAGS: - return gfs2_get_flags(filp, (u32 __user *)arg); - case FS_IOC_SETFLAGS: - return gfs2_set_flags(filp, (u32 __user *)arg); case FITRIM: return gfs2_fitrim(filp, (void __user *)arg); case FS_IOC_GETFSLABEL: @@ -359,13 +343,6 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static long gfs2_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { - /* These are just misnamed, they actually get/put from/to user an int */ - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; /* Keep this list in sync with gfs2_ioctl */ case FITRIM: case FS_IOC_GETFSLABEL: diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 9567520d79f798b0d6fb1b180328241158acf6ff..c06a6cdf05de607327444ec75e5f4d4bafb98b9a 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1732,7 +1732,8 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) spin_unlock(&gl->gl_lockref.lock); } -static int glock_cmp(void *priv, struct list_head *a, struct list_head *b) +static int glock_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct gfs2_glock *gla, *glb; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 8e32d569c8bf0607ba461e8bbf2b36b11a91aa57..ef0b583c3417cbd73f4d650a68b6c8617ec86e2d 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -394,18 +394,24 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) const struct gfs2_dinode *str = buf; struct timespec64 atime; u16 height, depth; + umode_t mode = be32_to_cpu(str->di_mode); + bool is_new = ip->i_inode.i_flags & I_NEW; if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) goto corrupt; + if (unlikely(!is_new && inode_wrong_type(&ip->i_inode, mode))) + goto corrupt; ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); - ip->i_inode.i_mode = be32_to_cpu(str->di_mode); - ip->i_inode.i_rdev = 0; - switch (ip->i_inode.i_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), - be32_to_cpu(str->di_minor)); - break; + ip->i_inode.i_mode = mode; + if (is_new) { + ip->i_inode.i_rdev = 0; + switch (mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), + be32_to_cpu(str->di_minor)); + break; + } } i_uid_write(&ip->i_inode, be32_to_cpu(str->di_uid)); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c9775d5c659497a0209dbc621faf2ce5bc901201..6a63607ac52678c81f6295c75d73242a1ea6ba2b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -2157,6 +2157,8 @@ static const struct inode_operations gfs2_file_iops = { .get_acl = gfs2_get_acl, .set_acl = gfs2_set_acl, .update_time = gfs2_update_time, + .fileattr_get = gfs2_fileattr_get, + .fileattr_set = gfs2_fileattr_set, }; static const struct inode_operations gfs2_dir_iops = { @@ -2178,6 +2180,8 @@ static const struct inode_operations gfs2_dir_iops = { .set_acl = gfs2_set_acl, .update_time = gfs2_update_time, .atomic_open = gfs2_atomic_open, + .fileattr_get = gfs2_fileattr_get, + .fileattr_set = gfs2_fileattr_set, }; static const struct inode_operations gfs2_symlink_iops = { diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index c447bd5b3017ea7334a6cd9a6f970fce2434bb90..9e898660eae06bca8c4f00d80ccbb83e3ece7271 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -111,6 +111,9 @@ extern loff_t gfs2_seek_hole(struct file *file, loff_t offset); extern const struct file_operations gfs2_file_fops_nolock; extern const struct file_operations gfs2_dir_fops_nolock; +extern int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa); +extern int gfs2_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); extern void gfs2_set_inode_flags(struct inode *inode); #ifdef CONFIG_GFS2_FS_LOCKING_DLM diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 6410281546f924942dd6a3f734a357e8eadd300a..88649b43fcffbd7b93d187759fd6258393fac83a 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -695,7 +695,7 @@ void log_flush_wait(struct gfs2_sbd *sdp) } } -static int ip_cmp(void *priv, struct list_head *a, struct list_head *b) +static int ip_cmp(void *priv, const struct list_head *a, const struct list_head *b) { struct gfs2_inode *ipa, *ipb; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index a82f4747aa8d5eaa05038e9ae324eabad53b48c3..b4809967efc675966d36f2346194368ad4a98168 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -634,7 +634,8 @@ static void gfs2_check_magic(struct buffer_head *bh) kunmap_atomic(kaddr); } -static int blocknr_cmp(void *priv, struct list_head *a, struct list_head *b) +static int blocknr_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct gfs2_bufdata *bda, *bdb; diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 03e6c046faf4153d8330d56a444ea00658d5fed0..84714bbccc1238a28a841faffe2ea53cd5930d4f 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -569,6 +569,8 @@ const struct inode_operations hfsplus_dir_inode_operations = { .rename = hfsplus_rename, .getattr = hfsplus_getattr, .listxattr = hfsplus_listxattr, + .fileattr_get = hfsplus_fileattr_get, + .fileattr_set = hfsplus_fileattr_set, }; const struct file_operations hfsplus_dir_operations = { diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 12b20479ed2be0c673c9bd6c1015579dc94bbe6f..1798949f269bb89d40ddafc1172508e817856089 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -344,17 +344,6 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) #define hfs_brec_goto hfsplus_brec_goto #define hfs_part_find hfsplus_part_find -/* - * definitions for ext2 flag ioctls (linux really needs a generic - * interface for this). - */ - -/* ext2 ioctls (EXT2_IOC_GETFLAGS and EXT2_IOC_SETFLAGS) to support - * chattr/lsattr */ -#define HFSPLUS_IOC_EXT2_GETFLAGS FS_IOC_GETFLAGS -#define HFSPLUS_IOC_EXT2_SETFLAGS FS_IOC_SETFLAGS - - /* * hfs+-specific ioctl for making the filesystem bootable */ @@ -493,6 +482,9 @@ int hfsplus_getattr(struct user_namespace *mnt_userns, const struct path *path, unsigned int query_flags); int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); +int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int hfsplus_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); /* ioctl.c */ long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 078c5c8a5156880d9d9ff0f53597d0f24ff7f293..8ea447e5c4708a3d4dbf1b55e6b484b437a00c6e 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -17,6 +17,7 @@ #include <linux/sched.h> #include <linux/cred.h> #include <linux/uio.h> +#include <linux/fileattr.h> #include "hfsplus_fs.h" #include "hfsplus_raw.h" @@ -353,6 +354,8 @@ static const struct inode_operations hfsplus_file_inode_operations = { .setattr = hfsplus_setattr, .getattr = hfsplus_getattr, .listxattr = hfsplus_listxattr, + .fileattr_get = hfsplus_fileattr_get, + .fileattr_set = hfsplus_fileattr_set, }; static const struct file_operations hfsplus_file_operations = { @@ -628,3 +631,54 @@ out: hfs_find_exit(&fd); return 0; } + +int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct hfsplus_inode_info *hip = HFSPLUS_I(inode); + unsigned int flags = 0; + + if (inode->i_flags & S_IMMUTABLE) + flags |= FS_IMMUTABLE_FL; + if (inode->i_flags & S_APPEND) + flags |= FS_APPEND_FL; + if (hip->userflags & HFSPLUS_FLG_NODUMP) + flags |= FS_NODUMP_FL; + + fileattr_fill_flags(fa, flags); + + return 0; +} + +int hfsplus_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct hfsplus_inode_info *hip = HFSPLUS_I(inode); + unsigned int new_fl = 0; + + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; + + /* don't silently ignore unsupported ext2 flags */ + if (fa->flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) + return -EOPNOTSUPP; + + if (fa->flags & FS_IMMUTABLE_FL) + new_fl |= S_IMMUTABLE; + + if (fa->flags & FS_APPEND_FL) + new_fl |= S_APPEND; + + inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); + + if (fa->flags & FS_NODUMP_FL) + hip->userflags |= HFSPLUS_FLG_NODUMP; + else + hip->userflags &= ~HFSPLUS_FLG_NODUMP; + + inode->i_ctime = current_time(inode); + mark_inode_dirty(inode); + + return 0; +} diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index 3edb1926d1272335584707963e7780a6b27ea2e9..5661a2e24d036ff19290b5a016a3f8a952fbfda7 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -57,95 +57,11 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags) return 0; } -static inline unsigned int hfsplus_getflags(struct inode *inode) -{ - struct hfsplus_inode_info *hip = HFSPLUS_I(inode); - unsigned int flags = 0; - - if (inode->i_flags & S_IMMUTABLE) - flags |= FS_IMMUTABLE_FL; - if (inode->i_flags & S_APPEND) - flags |= FS_APPEND_FL; - if (hip->userflags & HFSPLUS_FLG_NODUMP) - flags |= FS_NODUMP_FL; - return flags; -} - -static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags) -{ - struct inode *inode = file_inode(file); - unsigned int flags = hfsplus_getflags(inode); - - return put_user(flags, user_flags); -} - -static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) -{ - struct inode *inode = file_inode(file); - struct hfsplus_inode_info *hip = HFSPLUS_I(inode); - unsigned int flags, new_fl = 0; - unsigned int oldflags = hfsplus_getflags(inode); - int err = 0; - - err = mnt_want_write_file(file); - if (err) - goto out; - - if (!inode_owner_or_capable(&init_user_ns, inode)) { - err = -EACCES; - goto out_drop_write; - } - - if (get_user(flags, user_flags)) { - err = -EFAULT; - goto out_drop_write; - } - - inode_lock(inode); - - err = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (err) - goto out_unlock_inode; - - /* don't silently ignore unsupported ext2 flags */ - if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) { - err = -EOPNOTSUPP; - goto out_unlock_inode; - } - - if (flags & FS_IMMUTABLE_FL) - new_fl |= S_IMMUTABLE; - - if (flags & FS_APPEND_FL) - new_fl |= S_APPEND; - - inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); - - if (flags & FS_NODUMP_FL) - hip->userflags |= HFSPLUS_FLG_NODUMP; - else - hip->userflags &= ~HFSPLUS_FLG_NODUMP; - - inode->i_ctime = current_time(inode); - mark_inode_dirty(inode); - -out_unlock_inode: - inode_unlock(inode); -out_drop_write: - mnt_drop_write_file(file); -out: - return err; -} - long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; switch (cmd) { - case HFSPLUS_IOC_EXT2_GETFLAGS: - return hfsplus_ioctl_getflags(file, argp); - case HFSPLUS_IOC_EXT2_SETFLAGS: - return hfsplus_ioctl_setflags(file, argp); case HFSPLUS_IOC_BLESS: return hfsplus_ioctl_bless(file, argp); default: diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 743a005a5c64cca77d941392402ffb7c71cc8d51..7b5e984ff02a79a12ef40e4e56e231760b58d730 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -711,7 +711,6 @@ static int hostfs_mknod(struct user_namespace *mnt_userns, struct inode *dir, if (name == NULL) goto out_put; - init_special_inode(inode, mode, dev); err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); if (err) goto out_free; diff --git a/fs/inode.c b/fs/inode.c index a047ab306f9a86aa60b28fed5bd786839f888236..9e192bea063096142c6f13ae3313ac2d0a4df6cd 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -12,7 +12,6 @@ #include <linux/security.h> #include <linux/cdev.h> #include <linux/memblock.h> -#include <linux/fscrypt.h> #include <linux/fsnotify.h> #include <linux/mount.h> #include <linux/posix_acl.h> @@ -2148,7 +2147,7 @@ EXPORT_SYMBOL(init_special_inode); void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode, const struct inode *dir, umode_t mode) { - inode->i_uid = fsuid_into_mnt(mnt_userns); + inode_fsuid_set(inode, mnt_userns); if (dir && dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; @@ -2160,7 +2159,7 @@ void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode, !capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID)) mode &= ~S_ISGID; } else - inode->i_gid = fsgid_into_mnt(mnt_userns); + inode_fsgid_set(inode, mnt_userns); inode->i_mode = mode; } EXPORT_SYMBOL(inode_init_owner); @@ -2314,89 +2313,3 @@ struct timespec64 current_time(struct inode *inode) return timestamp_truncate(now, inode); } EXPORT_SYMBOL(current_time); - -/* - * Generic function to check FS_IOC_SETFLAGS values and reject any invalid - * configurations. - * - * Note: the caller should be holding i_mutex, or else be sure that they have - * exclusive access to the inode structure. - */ -int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags, - unsigned int flags) -{ - /* - * The IMMUTABLE and APPEND_ONLY flags can only be changed by - * the relevant capability. - * - * This test looks nicer. Thanks to Pauline Middelink - */ - if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && - !capable(CAP_LINUX_IMMUTABLE)) - return -EPERM; - - return fscrypt_prepare_setflags(inode, oldflags, flags); -} -EXPORT_SYMBOL(vfs_ioc_setflags_prepare); - -/* - * Generic function to check FS_IOC_FSSETXATTR values and reject any invalid - * configurations. - * - * Note: the caller should be holding i_mutex, or else be sure that they have - * exclusive access to the inode structure. - */ -int vfs_ioc_fssetxattr_check(struct inode *inode, const struct fsxattr *old_fa, - struct fsxattr *fa) -{ - /* - * Can't modify an immutable/append-only file unless we have - * appropriate permission. - */ - if ((old_fa->fsx_xflags ^ fa->fsx_xflags) & - (FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND) && - !capable(CAP_LINUX_IMMUTABLE)) - return -EPERM; - - /* - * Project Quota ID state is only allowed to change from within the init - * namespace. Enforce that restriction only if we are trying to change - * the quota ID state. Everything else is allowed in user namespaces. - */ - if (current_user_ns() != &init_user_ns) { - if (old_fa->fsx_projid != fa->fsx_projid) - return -EINVAL; - if ((old_fa->fsx_xflags ^ fa->fsx_xflags) & - FS_XFLAG_PROJINHERIT) - return -EINVAL; - } - - /* Check extent size hints. */ - if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode)) - return -EINVAL; - - if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && - !S_ISDIR(inode->i_mode)) - return -EINVAL; - - if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) && - !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) - return -EINVAL; - - /* - * It is only valid to set the DAX flag on regular files and - * directories on filesystems. - */ - if ((fa->fsx_xflags & FS_XFLAG_DAX) && - !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) - return -EINVAL; - - /* Extent size hints of zero turn off the flags. */ - if (fa->fsx_extsize == 0) - fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); - if (fa->fsx_cowextsize == 0) - fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; - - return 0; -} -EXPORT_SYMBOL(vfs_ioc_fssetxattr_check); diff --git a/fs/ioctl.c b/fs/ioctl.c index 4e6cc0a7d69c9f27e3b900b2dad72f7904cc90c4..1e2204fa9963e30102f801a39f1aa2137c5f86e8 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -19,6 +19,9 @@ #include <linux/falloc.h> #include <linux/sched/signal.h> #include <linux/fiemap.h> +#include <linux/mount.h> +#include <linux/fscrypt.h> +#include <linux/fileattr.h> #include "internal.h" @@ -657,6 +660,307 @@ out: return ret; } +/** + * fileattr_fill_xflags - initialize fileattr with xflags + * @fa: fileattr pointer + * @xflags: FS_XFLAG_* flags + * + * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All + * other fields are zeroed. + */ +void fileattr_fill_xflags(struct fileattr *fa, u32 xflags) +{ + memset(fa, 0, sizeof(*fa)); + fa->fsx_valid = true; + fa->fsx_xflags = xflags; + if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE) + fa->flags |= FS_IMMUTABLE_FL; + if (fa->fsx_xflags & FS_XFLAG_APPEND) + fa->flags |= FS_APPEND_FL; + if (fa->fsx_xflags & FS_XFLAG_SYNC) + fa->flags |= FS_SYNC_FL; + if (fa->fsx_xflags & FS_XFLAG_NOATIME) + fa->flags |= FS_NOATIME_FL; + if (fa->fsx_xflags & FS_XFLAG_NODUMP) + fa->flags |= FS_NODUMP_FL; + if (fa->fsx_xflags & FS_XFLAG_DAX) + fa->flags |= FS_DAX_FL; + if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) + fa->flags |= FS_PROJINHERIT_FL; +} +EXPORT_SYMBOL(fileattr_fill_xflags); + +/** + * fileattr_fill_flags - initialize fileattr with flags + * @fa: fileattr pointer + * @flags: FS_*_FL flags + * + * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags). + * All other fields are zeroed. + */ +void fileattr_fill_flags(struct fileattr *fa, u32 flags) +{ + memset(fa, 0, sizeof(*fa)); + fa->flags_valid = true; + fa->flags = flags; + if (fa->flags & FS_SYNC_FL) + fa->fsx_xflags |= FS_XFLAG_SYNC; + if (fa->flags & FS_IMMUTABLE_FL) + fa->fsx_xflags |= FS_XFLAG_IMMUTABLE; + if (fa->flags & FS_APPEND_FL) + fa->fsx_xflags |= FS_XFLAG_APPEND; + if (fa->flags & FS_NODUMP_FL) + fa->fsx_xflags |= FS_XFLAG_NODUMP; + if (fa->flags & FS_NOATIME_FL) + fa->fsx_xflags |= FS_XFLAG_NOATIME; + if (fa->flags & FS_DAX_FL) + fa->fsx_xflags |= FS_XFLAG_DAX; + if (fa->flags & FS_PROJINHERIT_FL) + fa->fsx_xflags |= FS_XFLAG_PROJINHERIT; +} +EXPORT_SYMBOL(fileattr_fill_flags); + +/** + * vfs_fileattr_get - retrieve miscellaneous file attributes + * @dentry: the object to retrieve from + * @fa: fileattr pointer + * + * Call i_op->fileattr_get() callback, if exists. + * + * Return: 0 on success, or a negative error on failure. + */ +int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + + if (!inode->i_op->fileattr_get) + return -ENOIOCTLCMD; + + return inode->i_op->fileattr_get(dentry, fa); +} +EXPORT_SYMBOL(vfs_fileattr_get); + +/** + * copy_fsxattr_to_user - copy fsxattr to userspace. + * @fa: fileattr pointer + * @ufa: fsxattr user pointer + * + * Return: 0 on success, or -EFAULT on failure. + */ +int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) +{ + struct fsxattr xfa; + + memset(&xfa, 0, sizeof(xfa)); + xfa.fsx_xflags = fa->fsx_xflags; + xfa.fsx_extsize = fa->fsx_extsize; + xfa.fsx_nextents = fa->fsx_nextents; + xfa.fsx_projid = fa->fsx_projid; + xfa.fsx_cowextsize = fa->fsx_cowextsize; + + if (copy_to_user(ufa, &xfa, sizeof(xfa))) + return -EFAULT; + + return 0; +} +EXPORT_SYMBOL(copy_fsxattr_to_user); + +static int copy_fsxattr_from_user(struct fileattr *fa, + struct fsxattr __user *ufa) +{ + struct fsxattr xfa; + + if (copy_from_user(&xfa, ufa, sizeof(xfa))) + return -EFAULT; + + fileattr_fill_xflags(fa, xfa.fsx_xflags); + fa->fsx_extsize = xfa.fsx_extsize; + fa->fsx_nextents = xfa.fsx_nextents; + fa->fsx_projid = xfa.fsx_projid; + fa->fsx_cowextsize = xfa.fsx_cowextsize; + + return 0; +} + +/* + * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject + * any invalid configurations. + * + * Note: must be called with inode lock held. + */ +static int fileattr_set_prepare(struct inode *inode, + const struct fileattr *old_ma, + struct fileattr *fa) +{ + int err; + + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + */ + if ((fa->flags ^ old_ma->flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && + !capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + + err = fscrypt_prepare_setflags(inode, old_ma->flags, fa->flags); + if (err) + return err; + + /* + * Project Quota ID state is only allowed to change from within the init + * namespace. Enforce that restriction only if we are trying to change + * the quota ID state. Everything else is allowed in user namespaces. + */ + if (current_user_ns() != &init_user_ns) { + if (old_ma->fsx_projid != fa->fsx_projid) + return -EINVAL; + if ((old_ma->fsx_xflags ^ fa->fsx_xflags) & + FS_XFLAG_PROJINHERIT) + return -EINVAL; + } + + /* Check extent size hints. */ + if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode)) + return -EINVAL; + + if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && + !S_ISDIR(inode->i_mode)) + return -EINVAL; + + if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) && + !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) + return -EINVAL; + + /* + * It is only valid to set the DAX flag on regular files and + * directories on filesystems. + */ + if ((fa->fsx_xflags & FS_XFLAG_DAX) && + !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) + return -EINVAL; + + /* Extent size hints of zero turn off the flags. */ + if (fa->fsx_extsize == 0) + fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); + if (fa->fsx_cowextsize == 0) + fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; + + return 0; +} + +/** + * vfs_fileattr_set - change miscellaneous file attributes + * @mnt_userns: user namespace of the mount + * @dentry: the object to change + * @fa: fileattr pointer + * + * After verifying permissions, call i_op->fileattr_set() callback, if + * exists. + * + * Verifying attributes involves retrieving current attributes with + * i_op->fileattr_get(), this also allows initializing attributes that have + * not been set by the caller to current values. Inode lock is held + * thoughout to prevent racing with another instance. + * + * Return: 0 on success, or a negative error on failure. + */ +int vfs_fileattr_set(struct user_namespace *mnt_userns, struct dentry *dentry, + struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct fileattr old_ma = {}; + int err; + + if (!inode->i_op->fileattr_set) + return -ENOIOCTLCMD; + + if (!inode_owner_or_capable(mnt_userns, inode)) + return -EPERM; + + inode_lock(inode); + err = vfs_fileattr_get(dentry, &old_ma); + if (!err) { + /* initialize missing bits from old_ma */ + if (fa->flags_valid) { + fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON; + fa->fsx_extsize = old_ma.fsx_extsize; + fa->fsx_nextents = old_ma.fsx_nextents; + fa->fsx_projid = old_ma.fsx_projid; + fa->fsx_cowextsize = old_ma.fsx_cowextsize; + } else { + fa->flags |= old_ma.flags & ~FS_COMMON_FL; + } + err = fileattr_set_prepare(inode, &old_ma, fa); + if (!err) + err = inode->i_op->fileattr_set(mnt_userns, dentry, fa); + } + inode_unlock(inode); + + return err; +} +EXPORT_SYMBOL(vfs_fileattr_set); + +static int ioctl_getflags(struct file *file, unsigned int __user *argp) +{ + struct fileattr fa = { .flags_valid = true }; /* hint only */ + int err; + + err = vfs_fileattr_get(file->f_path.dentry, &fa); + if (!err) + err = put_user(fa.flags, argp); + return err; +} + +static int ioctl_setflags(struct file *file, unsigned int __user *argp) +{ + struct user_namespace *mnt_userns = file_mnt_user_ns(file); + struct dentry *dentry = file->f_path.dentry; + struct fileattr fa; + unsigned int flags; + int err; + + err = get_user(flags, argp); + if (!err) { + err = mnt_want_write_file(file); + if (!err) { + fileattr_fill_flags(&fa, flags); + err = vfs_fileattr_set(mnt_userns, dentry, &fa); + mnt_drop_write_file(file); + } + } + return err; +} + +static int ioctl_fsgetxattr(struct file *file, void __user *argp) +{ + struct fileattr fa = { .fsx_valid = true }; /* hint only */ + int err; + + err = vfs_fileattr_get(file->f_path.dentry, &fa); + if (!err) + err = copy_fsxattr_to_user(&fa, argp); + + return err; +} + +static int ioctl_fssetxattr(struct file *file, void __user *argp) +{ + struct user_namespace *mnt_userns = file_mnt_user_ns(file); + struct dentry *dentry = file->f_path.dentry; + struct fileattr fa; + int err; + + err = copy_fsxattr_from_user(&fa, argp); + if (!err) { + err = mnt_want_write_file(file); + if (!err) { + err = vfs_fileattr_set(mnt_userns, dentry, &fa); + mnt_drop_write_file(file); + } + } + return err; +} + /* * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. * It's just a simple helper for sys_ioctl and compat_sys_ioctl. @@ -727,6 +1031,18 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, return put_user(i_size_read(inode) - filp->f_pos, (int __user *)argp); + case FS_IOC_GETFLAGS: + return ioctl_getflags(filp, argp); + + case FS_IOC_SETFLAGS: + return ioctl_setflags(filp, argp); + + case FS_IOC_FSGETXATTR: + return ioctl_fsgetxattr(filp, argp); + + case FS_IOC_FSSETXATTR: + return ioctl_fssetxattr(filp, argp); + default: if (S_ISREG(inode->i_mode)) return file_ioctl(filp, cmd, argp); @@ -827,6 +1143,15 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, break; #endif + /* + * These access 32-bit values anyway so no further handling is + * necessary. + */ + case FS_IOC32_GETFLAGS: + case FS_IOC32_SETFLAGS: + cmd = (cmd == FS_IOC32_GETFLAGS) ? + FS_IOC_GETFLAGS : FS_IOC_SETFLAGS; + fallthrough; /* * everything else in do_vfs_ioctl() takes either a compatible * pointer argument or no argument -- call it with a modified diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 414769a6ad113af77a363e12518d8cfc711a164e..0129e6bab98570a1a68b1392b23e788066567a32 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -1155,7 +1155,8 @@ iomap_ioend_try_merge(struct iomap_ioend *ioend, struct list_head *more_ioends, EXPORT_SYMBOL_GPL(iomap_ioend_try_merge); static int -iomap_ioend_compare(void *priv, struct list_head *a, struct list_head *b) +iomap_ioend_compare(void *priv, const struct list_head *a, + const struct list_head *b) { struct iomap_ioend *ia = container_of(a, struct iomap_ioend, io_list); struct iomap_ioend *ib = container_of(b, struct iomap_ioend, io_list); diff --git a/fs/iomap/swapfile.c b/fs/iomap/swapfile.c index a5e478de141744cd7fef9276b26e5dc0b55638f0..6250ca6a1f851d4be8d12f39e86f0d03508f6627 100644 --- a/fs/iomap/swapfile.c +++ b/fs/iomap/swapfile.c @@ -18,6 +18,7 @@ struct iomap_swapfile_info { uint64_t highest_ppage; /* highest physical addr seen (pages) */ unsigned long nr_pages; /* number of pages collected */ int nr_extents; /* extent count */ + struct file *file; }; /* @@ -70,6 +71,18 @@ static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi) return 0; } +static int iomap_swapfile_fail(struct iomap_swapfile_info *isi, const char *str) +{ + char *buf, *p = ERR_PTR(-ENOMEM); + + buf = kmalloc(PATH_MAX, GFP_KERNEL); + if (buf) + p = file_path(isi->file, buf, PATH_MAX); + pr_err("swapon: file %s %s\n", IS_ERR(p) ? "<unknown>" : p, str); + kfree(buf); + return -EINVAL; +} + /* * Accumulate iomaps for this swap file. We have to accumulate iomaps because * swap only cares about contiguous page-aligned physical extents and makes no @@ -89,28 +102,20 @@ static loff_t iomap_swapfile_activate_actor(struct inode *inode, loff_t pos, break; case IOMAP_INLINE: /* No inline data. */ - pr_err("swapon: file is inline\n"); - return -EINVAL; + return iomap_swapfile_fail(isi, "is inline"); default: - pr_err("swapon: file has unallocated extents\n"); - return -EINVAL; + return iomap_swapfile_fail(isi, "has unallocated extents"); } /* No uncommitted metadata or shared blocks. */ - if (iomap->flags & IOMAP_F_DIRTY) { - pr_err("swapon: file is not committed\n"); - return -EINVAL; - } - if (iomap->flags & IOMAP_F_SHARED) { - pr_err("swapon: file has shared extents\n"); - return -EINVAL; - } + if (iomap->flags & IOMAP_F_DIRTY) + return iomap_swapfile_fail(isi, "is not committed"); + if (iomap->flags & IOMAP_F_SHARED) + return iomap_swapfile_fail(isi, "has shared extents"); /* Only one bdev per swap file. */ - if (iomap->bdev != isi->sis->bdev) { - pr_err("swapon: file is on multiple devices\n"); - return -EINVAL; - } + if (iomap->bdev != isi->sis->bdev) + return iomap_swapfile_fail(isi, "outside the main device"); if (isi->iomap.length == 0) { /* No accumulated extent, so just store it. */ @@ -139,6 +144,7 @@ int iomap_swapfile_activate(struct swap_info_struct *sis, struct iomap_swapfile_info isi = { .sis = sis, .lowest_ppage = (sector_t)-1ULL, + .file = swap_file, }; struct address_space *mapping = swap_file->f_mapping; struct inode *inode = mapping->host; diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 28b70e7c7dd4722b0573bf5614e820706a436028..1d732fd223d4a900a280f3615a5f6e600bf5b8f0 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -130,6 +130,8 @@ int jfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, const struct inode_operations jfs_file_inode_operations = { .listxattr = jfs_listxattr, .setattr = jfs_setattr, + .fileattr_get = jfs_fileattr_get, + .fileattr_set = jfs_fileattr_set, #ifdef CONFIG_JFS_POSIX_ACL .get_acl = jfs_get_acl, .set_acl = jfs_set_acl, @@ -147,7 +149,5 @@ const struct file_operations jfs_file_operations = { .fsync = jfs_fsync, .release = jfs_release, .unlocked_ioctl = jfs_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = jfs_compat_ioctl, -#endif + .compat_ioctl = compat_ptr_ioctl, }; diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index 2581d4db58fff2b258377c3a8ec18de15072cf4f..03a845ab4f009c30e6fc2a941bb2196f21a65200 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -15,6 +15,7 @@ #include <linux/blkdev.h> #include <asm/current.h> #include <linux/uaccess.h> +#include <linux/fileattr.h> #include "jfs_filsys.h" #include "jfs_debug.h" @@ -56,69 +57,56 @@ static long jfs_map_ext2(unsigned long flags, int from) return mapped; } +int jfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct jfs_inode_info *jfs_inode = JFS_IP(d_inode(dentry)); + unsigned int flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; -long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + if (d_is_special(dentry)) + return -ENOTTY; + + fileattr_fill_flags(fa, jfs_map_ext2(flags, 0)); + + return 0; +} + +int jfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { - struct inode *inode = file_inode(filp); + struct inode *inode = d_inode(dentry); struct jfs_inode_info *jfs_inode = JFS_IP(inode); unsigned int flags; - switch (cmd) { - case JFS_IOC_GETFLAGS: - flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; - flags = jfs_map_ext2(flags, 0); - return put_user(flags, (int __user *) arg); - case JFS_IOC_SETFLAGS: { - unsigned int oldflags; - int err; - - err = mnt_want_write_file(filp); - if (err) - return err; - - if (!inode_owner_or_capable(&init_user_ns, inode)) { - err = -EACCES; - goto setflags_out; - } - if (get_user(flags, (int __user *) arg)) { - err = -EFAULT; - goto setflags_out; - } + if (d_is_special(dentry)) + return -ENOTTY; - flags = jfs_map_ext2(flags, 1); - if (!S_ISDIR(inode->i_mode)) - flags &= ~JFS_DIRSYNC_FL; + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) { - err = -EPERM; - goto setflags_out; - } + flags = jfs_map_ext2(fa->flags, 1); + if (!S_ISDIR(inode->i_mode)) + flags &= ~JFS_DIRSYNC_FL; - /* Lock against other parallel changes of flags */ - inode_lock(inode); + /* Is it quota file? Do not allow user to mess with it */ + if (IS_NOQUOTA(inode)) + return -EPERM; - oldflags = jfs_map_ext2(jfs_inode->mode2 & JFS_FL_USER_VISIBLE, - 0); - err = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (err) { - inode_unlock(inode); - goto setflags_out; - } + flags = flags & JFS_FL_USER_MODIFIABLE; + flags |= jfs_inode->mode2 & ~JFS_FL_USER_MODIFIABLE; + jfs_inode->mode2 = flags; - flags = flags & JFS_FL_USER_MODIFIABLE; - flags |= jfs_inode->mode2 & ~JFS_FL_USER_MODIFIABLE; - jfs_inode->mode2 = flags; - - jfs_set_inode_flags(inode); - inode_unlock(inode); - inode->i_ctime = current_time(inode); - mark_inode_dirty(inode); -setflags_out: - mnt_drop_write_file(filp); - return err; - } + jfs_set_inode_flags(inode); + inode->i_ctime = current_time(inode); + mark_inode_dirty(inode); + + return 0; +} + +long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + switch (cmd) { case FITRIM: { struct super_block *sb = inode->i_sb; @@ -156,22 +144,3 @@ setflags_out: return -ENOTTY; } } - -#ifdef CONFIG_COMPAT -long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - /* While these ioctl numbers defined with 'long' and have different - * numbers than the 64bit ABI, - * the actual implementation only deals with ints and is compatible. - */ - switch (cmd) { - case JFS_IOC_GETFLAGS32: - cmd = JFS_IOC_GETFLAGS; - break; - case JFS_IOC_SETFLAGS32: - cmd = JFS_IOC_SETFLAGS; - break; - } - return jfs_ioctl(filp, cmd, arg); -} -#endif diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h index 5fa9fd594115aa158abfee58c12f797f4830c548..d6af79e94263237d1fe205d290943a1fa0f2d28c 100644 --- a/fs/jfs/jfs_dinode.h +++ b/fs/jfs/jfs_dinode.h @@ -160,11 +160,4 @@ struct dinode { #define JFS_FL_USER_MODIFIABLE 0x03F80000 #define JFS_FL_INHERIT 0x03C80000 -/* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */ -#define JFS_IOC_GETFLAGS _IOR('f', 1, long) -#define JFS_IOC_SETFLAGS _IOW('f', 2, long) - -#define JFS_IOC_GETFLAGS32 _IOR('f', 1, int) -#define JFS_IOC_SETFLAGS32 _IOW('f', 2, int) - #endif /*_H_JFS_DINODE */ diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 01daa0cb0ae58f7dabb0d66a3d2b4f6f70e53750..7de961a818623cb77586ebc558b1986fcff73b87 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -9,8 +9,10 @@ struct fid; extern struct inode *ialloc(struct inode *, umode_t); extern int jfs_fsync(struct file *, loff_t, loff_t, int); +extern int jfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); +extern int jfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); extern long jfs_ioctl(struct file *, unsigned int, unsigned long); -extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); extern struct inode *jfs_iget(struct super_block *, unsigned long); extern int jfs_commit_inode(struct inode *, int); extern int jfs_write_inode(struct inode *, struct writeback_control *); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 9abed0d750e5a86ed4bc3f6c989c2aae024f3781..9db4f5789c0eca4ae8dc32a62e126a2aa2d073c2 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1522,6 +1522,8 @@ const struct inode_operations jfs_dir_inode_operations = { .rename = jfs_rename, .listxattr = jfs_listxattr, .setattr = jfs_setattr, + .fileattr_get = jfs_fileattr_get, + .fileattr_set = jfs_fileattr_set, #ifdef CONFIG_JFS_POSIX_ACL .get_acl = jfs_get_acl, .set_acl = jfs_set_acl, @@ -1533,9 +1535,7 @@ const struct file_operations jfs_dir_operations = { .iterate = jfs_readdir, .fsync = jfs_fsync, .unlocked_ioctl = jfs_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = jfs_compat_ioctl, -#endif + .compat_ioctl = compat_ptr_ioctl, .llseek = generic_file_llseek, }; diff --git a/fs/libfs.c b/fs/libfs.c index e2de5401abca5a18d2db6c6fae10afb7f152c218..e9b29c6ffccbddf0e9fc8c4a71cf2c6ff62ca412 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -481,6 +481,7 @@ EXPORT_SYMBOL(simple_rename); /** * simple_setattr - setattr for simple filesystem + * @mnt_userns: user namespace of the target mount * @dentry: dentry * @iattr: iattr structure * diff --git a/fs/locks.c b/fs/locks.c index 6125d2de39b8b8bd18ef8678d9228fdf61eada16..5c42363aa811c13930b1722709560bcb5b68e883 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2369,7 +2369,6 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock) if (flock->l_pid != 0) goto out; - cmd = F_GETLK; fl->fl_flags |= FL_OFDLCK; fl->fl_owner = filp; } @@ -2825,7 +2824,7 @@ struct locks_iterator { }; static void lock_get_status(struct seq_file *f, struct file_lock *fl, - loff_t id, char *pfx) + loff_t id, char *pfx, int repeat) { struct inode *inode = NULL; unsigned int fl_pid; @@ -2841,7 +2840,11 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, if (fl->fl_file != NULL) inode = locks_inode(fl->fl_file); - seq_printf(f, "%lld:%s ", id, pfx); + seq_printf(f, "%lld: ", id); + + if (repeat) + seq_printf(f, "%*s", repeat - 1 + (int)strlen(pfx), pfx); + if (IS_POSIX(fl)) { if (fl->fl_flags & FL_ACCESS) seq_puts(f, "ACCESS"); @@ -2903,21 +2906,64 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, } } +static struct file_lock *get_next_blocked_member(struct file_lock *node) +{ + struct file_lock *tmp; + + /* NULL node or root node */ + if (node == NULL || node->fl_blocker == NULL) + return NULL; + + /* Next member in the linked list could be itself */ + tmp = list_next_entry(node, fl_blocked_member); + if (list_entry_is_head(tmp, &node->fl_blocker->fl_blocked_requests, fl_blocked_member) + || tmp == node) { + return NULL; + } + + return tmp; +} + static int locks_show(struct seq_file *f, void *v) { struct locks_iterator *iter = f->private; - struct file_lock *fl, *bfl; + struct file_lock *cur, *tmp; struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb); + int level = 0; - fl = hlist_entry(v, struct file_lock, fl_link); + cur = hlist_entry(v, struct file_lock, fl_link); - if (locks_translate_pid(fl, proc_pidns) == 0) + if (locks_translate_pid(cur, proc_pidns) == 0) return 0; - lock_get_status(f, fl, iter->li_pos, ""); + /* View this crossed linked list as a binary tree, the first member of fl_blocked_requests + * is the left child of current node, the next silibing in fl_blocked_member is the + * right child, we can alse get the parent of current node from fl_blocker, so this + * question becomes traversal of a binary tree + */ + while (cur != NULL) { + if (level) + lock_get_status(f, cur, iter->li_pos, "-> ", level); + else + lock_get_status(f, cur, iter->li_pos, "", level); - list_for_each_entry(bfl, &fl->fl_blocked_requests, fl_blocked_member) - lock_get_status(f, bfl, iter->li_pos, " ->"); + if (!list_empty(&cur->fl_blocked_requests)) { + /* Turn left */ + cur = list_first_entry_or_null(&cur->fl_blocked_requests, + struct file_lock, fl_blocked_member); + level++; + } else { + /* Turn right */ + tmp = get_next_blocked_member(cur); + /* Fall back to parent node */ + while (tmp == NULL && cur->fl_blocker != NULL) { + cur = cur->fl_blocker; + level--; + tmp = get_next_blocked_member(cur); + } + cur = tmp; + } + } return 0; } @@ -2938,7 +2984,7 @@ static void __show_fd_locks(struct seq_file *f, (*id)++; seq_puts(f, "lock:\t"); - lock_get_status(f, fl, *id, ""); + lock_get_status(f, fl, *id, "", 0); } } diff --git a/fs/namei.c b/fs/namei.c index 5379c704462a6692f077a6f33e4bab3581a5a1ac..7a19d3c13b26f82e0434ec8ef951449db7035176 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1210,8 +1210,7 @@ int may_linkat(struct user_namespace *mnt_userns, struct path *link) * should be allowed, or not, on files that already * exist. * @mnt_userns: user namespace of the mount the inode was found from - * @dir_mode: mode bits of directory - * @dir_uid: owner of directory + * @nd: nameidata pathwalk data * @inode: the inode of the file to open * * Block an O_CREAT open of a FIFO (or a regular file) when: @@ -2909,16 +2908,14 @@ static int may_delete(struct user_namespace *mnt_userns, struct inode *dir, static inline int may_create(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *child) { - struct user_namespace *s_user_ns; audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - s_user_ns = dir->i_sb->s_user_ns; - if (!kuid_has_mapping(s_user_ns, fsuid_into_mnt(mnt_userns)) || - !kgid_has_mapping(s_user_ns, fsgid_into_mnt(mnt_userns))) + if (!fsuidgid_has_mapping(dir->i_sb, mnt_userns)) return -EOVERFLOW; + return inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC); } @@ -3120,14 +3117,11 @@ static int may_o_create(struct user_namespace *mnt_userns, const struct path *dir, struct dentry *dentry, umode_t mode) { - struct user_namespace *s_user_ns; int error = security_path_mknod(dir, dentry, mode, 0); if (error) return error; - s_user_ns = dir->dentry->d_sb->s_user_ns; - if (!kuid_has_mapping(s_user_ns, fsuid_into_mnt(mnt_userns)) || - !kgid_has_mapping(s_user_ns, fsgid_into_mnt(mnt_userns))) + if (!fsuidgid_has_mapping(dir->dentry->d_sb, mnt_userns)) return -EOVERFLOW; error = inode_permission(mnt_userns, dir->dentry->d_inode, @@ -3467,7 +3461,7 @@ static int do_open(struct nameidata *nd, * @mnt_userns: user namespace of the mount the inode was found from * @dentry: pointer to dentry of the base directory * @mode: mode of the new tmpfile - * @open_flags: flags + * @open_flag: flags * * Create a temporary file. * @@ -4492,14 +4486,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname /** * vfs_rename - rename a filesystem object - * @old_mnt_userns: old user namespace of the mount the inode was found from - * @old_dir: parent of source - * @old_dentry: source - * @new_mnt_userns: new user namespace of the mount the inode was found from - * @new_dir: parent of destination - * @new_dentry: destination - * @delegated_inode: returns an inode needing a delegation break - * @flags: rename flags + * @rd: pointer to &struct renamedata info * * The caller must hold multiple mutexes--see lock_rename()). * diff --git a/fs/namespace.c b/fs/namespace.c index 56bb5a5fdc0d099c3c150c7d3d1c20d2165e3e95..f63337828e1c474daa4ac8f13ebb99fc180e5eae 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1242,8 +1242,9 @@ struct vfsmount *mntget(struct vfsmount *mnt) } EXPORT_SYMBOL(mntget); -/* path_is_mountpoint() - Check if path is a mount in the current - * namespace. +/** + * path_is_mountpoint() - Check if path is a mount in the current namespace. + * @path: path to check * * d_mountpoint() can only be used reliably to establish if a dentry is * not mounted in any namespace and that common case is handled inline. @@ -1369,7 +1370,7 @@ void mnt_cursor_del(struct mnt_namespace *ns, struct mount *cursor) /** * may_umount_tree - check if a mount tree is busy - * @mnt: root of mount tree + * @m: root of mount tree * * This is called to check if a tree of mounts has any * open files, pwds, chroots or sub mounts that are @@ -1939,10 +1940,11 @@ void drop_collected_mounts(struct vfsmount *mnt) /** * clone_private_mount - create a private clone of a path + * @path: path to clone * - * This creates a new vfsmount, which will be the clone of @path. The new will - * not be attached anywhere in the namespace and will be private (i.e. changes - * to the originating mount won't be propagated into this). + * This creates a new vfsmount, which will be the clone of @path. The new mount + * will not be attached anywhere in the namespace and will be private (i.e. + * changes to the originating mount won't be propagated into this). * * Release with mntput(). */ diff --git a/fs/netfs/Kconfig b/fs/netfs/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..578112713703b92b7cbfe578bdac9c4a374ec4ed --- /dev/null +++ b/fs/netfs/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config NETFS_SUPPORT + tristate "Support for network filesystem high-level I/O" + help + This option enables support for network filesystems, including + helpers for high-level buffered I/O, abstracting out read + segmentation, local caching and transparent huge page support. + +config NETFS_STATS + bool "Gather statistical information on local caching" + depends on NETFS_SUPPORT && PROC_FS + help + This option causes statistical information to be gathered on local + caching and exported through file: + + /proc/fs/fscache/stats + + The gathering of statistics adds a certain amount of overhead to + execution as there are a quite a few stats gathered, and on a + multi-CPU system these may be on cachelines that keep bouncing + between CPUs. On the other hand, the stats are very useful for + debugging purposes. Saying 'Y' here is recommended. diff --git a/fs/netfs/Makefile b/fs/netfs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c15bfc966d96db7494783d374113544ca7fc7d37 --- /dev/null +++ b/fs/netfs/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +netfs-y := read_helper.o stats.o + +obj-$(CONFIG_NETFS_SUPPORT) := netfs.o diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h new file mode 100644 index 0000000000000000000000000000000000000000..b7f2c4459f33683cf80a1591ca9b586fb9bcb37f --- /dev/null +++ b/fs/netfs/internal.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Internal definitions for network filesystem support + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#ifdef pr_fmt +#undef pr_fmt +#endif + +#define pr_fmt(fmt) "netfs: " fmt + +/* + * read_helper.c + */ +extern unsigned int netfs_debug; + +/* + * stats.c + */ +#ifdef CONFIG_NETFS_STATS +extern atomic_t netfs_n_rh_readahead; +extern atomic_t netfs_n_rh_readpage; +extern atomic_t netfs_n_rh_rreq; +extern atomic_t netfs_n_rh_sreq; +extern atomic_t netfs_n_rh_download; +extern atomic_t netfs_n_rh_download_done; +extern atomic_t netfs_n_rh_download_failed; +extern atomic_t netfs_n_rh_download_instead; +extern atomic_t netfs_n_rh_read; +extern atomic_t netfs_n_rh_read_done; +extern atomic_t netfs_n_rh_read_failed; +extern atomic_t netfs_n_rh_zero; +extern atomic_t netfs_n_rh_short_read; +extern atomic_t netfs_n_rh_write; +extern atomic_t netfs_n_rh_write_begin; +extern atomic_t netfs_n_rh_write_done; +extern atomic_t netfs_n_rh_write_failed; +extern atomic_t netfs_n_rh_write_zskip; + + +static inline void netfs_stat(atomic_t *stat) +{ + atomic_inc(stat); +} + +static inline void netfs_stat_d(atomic_t *stat) +{ + atomic_dec(stat); +} + +#else +#define netfs_stat(x) do {} while(0) +#define netfs_stat_d(x) do {} while(0) +#endif + +/*****************************************************************************/ +/* + * debug tracing + */ +#define dbgprintk(FMT, ...) \ + printk("[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) + +#define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) +#define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) +#define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) + +#ifdef __KDEBUG +#define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__) +#define _leave(FMT, ...) kleave(FMT, ##__VA_ARGS__) +#define _debug(FMT, ...) kdebug(FMT, ##__VA_ARGS__) + +#elif defined(CONFIG_NETFS_DEBUG) +#define _enter(FMT, ...) \ +do { \ + if (netfs_debug) \ + kenter(FMT, ##__VA_ARGS__); \ +} while (0) + +#define _leave(FMT, ...) \ +do { \ + if (netfs_debug) \ + kleave(FMT, ##__VA_ARGS__); \ +} while (0) + +#define _debug(FMT, ...) \ +do { \ + if (netfs_debug) \ + kdebug(FMT, ##__VA_ARGS__); \ +} while (0) + +#else +#define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__) +#define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__) +#define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__) +#endif diff --git a/fs/netfs/read_helper.c b/fs/netfs/read_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..193841d03de09b515b821ab67b50fcfc1b0b89a6 --- /dev/null +++ b/fs/netfs/read_helper.c @@ -0,0 +1,1185 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Network filesystem high-level read support. + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include <linux/module.h> +#include <linux/export.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/slab.h> +#include <linux/uio.h> +#include <linux/sched/mm.h> +#include <linux/task_io_accounting_ops.h> +#include <linux/netfs.h> +#include "internal.h" +#define CREATE_TRACE_POINTS +#include <trace/events/netfs.h> + +MODULE_DESCRIPTION("Network fs support"); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + +unsigned netfs_debug; +module_param_named(debug, netfs_debug, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(netfs_debug, "Netfs support debugging mask"); + +static void netfs_rreq_work(struct work_struct *); +static void __netfs_put_subrequest(struct netfs_read_subrequest *, bool); + +static void netfs_put_subrequest(struct netfs_read_subrequest *subreq, + bool was_async) +{ + if (refcount_dec_and_test(&subreq->usage)) + __netfs_put_subrequest(subreq, was_async); +} + +static struct netfs_read_request *netfs_alloc_read_request( + const struct netfs_read_request_ops *ops, void *netfs_priv, + struct file *file) +{ + static atomic_t debug_ids; + struct netfs_read_request *rreq; + + rreq = kzalloc(sizeof(struct netfs_read_request), GFP_KERNEL); + if (rreq) { + rreq->netfs_ops = ops; + rreq->netfs_priv = netfs_priv; + rreq->inode = file_inode(file); + rreq->i_size = i_size_read(rreq->inode); + rreq->debug_id = atomic_inc_return(&debug_ids); + INIT_LIST_HEAD(&rreq->subrequests); + INIT_WORK(&rreq->work, netfs_rreq_work); + refcount_set(&rreq->usage, 1); + __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags); + ops->init_rreq(rreq, file); + netfs_stat(&netfs_n_rh_rreq); + } + + return rreq; +} + +static void netfs_get_read_request(struct netfs_read_request *rreq) +{ + refcount_inc(&rreq->usage); +} + +static void netfs_rreq_clear_subreqs(struct netfs_read_request *rreq, + bool was_async) +{ + struct netfs_read_subrequest *subreq; + + while (!list_empty(&rreq->subrequests)) { + subreq = list_first_entry(&rreq->subrequests, + struct netfs_read_subrequest, rreq_link); + list_del(&subreq->rreq_link); + netfs_put_subrequest(subreq, was_async); + } +} + +static void netfs_free_read_request(struct work_struct *work) +{ + struct netfs_read_request *rreq = + container_of(work, struct netfs_read_request, work); + netfs_rreq_clear_subreqs(rreq, false); + if (rreq->netfs_priv) + rreq->netfs_ops->cleanup(rreq->mapping, rreq->netfs_priv); + trace_netfs_rreq(rreq, netfs_rreq_trace_free); + if (rreq->cache_resources.ops) + rreq->cache_resources.ops->end_operation(&rreq->cache_resources); + kfree(rreq); + netfs_stat_d(&netfs_n_rh_rreq); +} + +static void netfs_put_read_request(struct netfs_read_request *rreq, bool was_async) +{ + if (refcount_dec_and_test(&rreq->usage)) { + if (was_async) { + rreq->work.func = netfs_free_read_request; + if (!queue_work(system_unbound_wq, &rreq->work)) + BUG(); + } else { + netfs_free_read_request(&rreq->work); + } + } +} + +/* + * Allocate and partially initialise an I/O request structure. + */ +static struct netfs_read_subrequest *netfs_alloc_subrequest( + struct netfs_read_request *rreq) +{ + struct netfs_read_subrequest *subreq; + + subreq = kzalloc(sizeof(struct netfs_read_subrequest), GFP_KERNEL); + if (subreq) { + INIT_LIST_HEAD(&subreq->rreq_link); + refcount_set(&subreq->usage, 2); + subreq->rreq = rreq; + netfs_get_read_request(rreq); + netfs_stat(&netfs_n_rh_sreq); + } + + return subreq; +} + +static void netfs_get_read_subrequest(struct netfs_read_subrequest *subreq) +{ + refcount_inc(&subreq->usage); +} + +static void __netfs_put_subrequest(struct netfs_read_subrequest *subreq, + bool was_async) +{ + struct netfs_read_request *rreq = subreq->rreq; + + trace_netfs_sreq(subreq, netfs_sreq_trace_free); + kfree(subreq); + netfs_stat_d(&netfs_n_rh_sreq); + netfs_put_read_request(rreq, was_async); +} + +/* + * Clear the unread part of an I/O request. + */ +static void netfs_clear_unread(struct netfs_read_subrequest *subreq) +{ + struct iov_iter iter; + + iov_iter_xarray(&iter, WRITE, &subreq->rreq->mapping->i_pages, + subreq->start + subreq->transferred, + subreq->len - subreq->transferred); + iov_iter_zero(iov_iter_count(&iter), &iter); +} + +static void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error, + bool was_async) +{ + struct netfs_read_subrequest *subreq = priv; + + netfs_subreq_terminated(subreq, transferred_or_error, was_async); +} + +/* + * Issue a read against the cache. + * - Eats the caller's ref on subreq. + */ +static void netfs_read_from_cache(struct netfs_read_request *rreq, + struct netfs_read_subrequest *subreq, + bool seek_data) +{ + struct netfs_cache_resources *cres = &rreq->cache_resources; + struct iov_iter iter; + + netfs_stat(&netfs_n_rh_read); + iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages, + subreq->start + subreq->transferred, + subreq->len - subreq->transferred); + + cres->ops->read(cres, subreq->start, &iter, seek_data, + netfs_cache_read_terminated, subreq); +} + +/* + * Fill a subrequest region with zeroes. + */ +static void netfs_fill_with_zeroes(struct netfs_read_request *rreq, + struct netfs_read_subrequest *subreq) +{ + netfs_stat(&netfs_n_rh_zero); + __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); + netfs_subreq_terminated(subreq, 0, false); +} + +/* + * Ask the netfs to issue a read request to the server for us. + * + * The netfs is expected to read from subreq->pos + subreq->transferred to + * subreq->pos + subreq->len - 1. It may not backtrack and write data into the + * buffer prior to the transferred point as it might clobber dirty data + * obtained from the cache. + * + * Alternatively, the netfs is allowed to indicate one of two things: + * + * - NETFS_SREQ_SHORT_READ: A short read - it will get called again to try and + * make progress. + * + * - NETFS_SREQ_CLEAR_TAIL: A short read - the rest of the buffer will be + * cleared. + */ +static void netfs_read_from_server(struct netfs_read_request *rreq, + struct netfs_read_subrequest *subreq) +{ + netfs_stat(&netfs_n_rh_download); + rreq->netfs_ops->issue_op(subreq); +} + +/* + * Release those waiting. + */ +static void netfs_rreq_completed(struct netfs_read_request *rreq, bool was_async) +{ + trace_netfs_rreq(rreq, netfs_rreq_trace_done); + netfs_rreq_clear_subreqs(rreq, was_async); + netfs_put_read_request(rreq, was_async); +} + +/* + * Deal with the completion of writing the data to the cache. We have to clear + * the PG_fscache bits on the pages involved and release the caller's ref. + * + * May be called in softirq mode and we inherit a ref from the caller. + */ +static void netfs_rreq_unmark_after_write(struct netfs_read_request *rreq, + bool was_async) +{ + struct netfs_read_subrequest *subreq; + struct page *page; + pgoff_t unlocked = 0; + bool have_unlocked = false; + + rcu_read_lock(); + + list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + XA_STATE(xas, &rreq->mapping->i_pages, subreq->start / PAGE_SIZE); + + xas_for_each(&xas, page, (subreq->start + subreq->len - 1) / PAGE_SIZE) { + /* We might have multiple writes from the same huge + * page, but we mustn't unlock a page more than once. + */ + if (have_unlocked && page->index <= unlocked) + continue; + unlocked = page->index; + end_page_fscache(page); + have_unlocked = true; + } + } + + rcu_read_unlock(); + netfs_rreq_completed(rreq, was_async); +} + +static void netfs_rreq_copy_terminated(void *priv, ssize_t transferred_or_error, + bool was_async) +{ + struct netfs_read_subrequest *subreq = priv; + struct netfs_read_request *rreq = subreq->rreq; + + if (IS_ERR_VALUE(transferred_or_error)) { + netfs_stat(&netfs_n_rh_write_failed); + trace_netfs_failure(rreq, subreq, transferred_or_error, + netfs_fail_copy_to_cache); + } else { + netfs_stat(&netfs_n_rh_write_done); + } + + trace_netfs_sreq(subreq, netfs_sreq_trace_write_term); + + /* If we decrement nr_wr_ops to 0, the ref belongs to us. */ + if (atomic_dec_and_test(&rreq->nr_wr_ops)) + netfs_rreq_unmark_after_write(rreq, was_async); + + netfs_put_subrequest(subreq, was_async); +} + +/* + * Perform any outstanding writes to the cache. We inherit a ref from the + * caller. + */ +static void netfs_rreq_do_write_to_cache(struct netfs_read_request *rreq) +{ + struct netfs_cache_resources *cres = &rreq->cache_resources; + struct netfs_read_subrequest *subreq, *next, *p; + struct iov_iter iter; + int ret; + + trace_netfs_rreq(rreq, netfs_rreq_trace_write); + + /* We don't want terminating writes trying to wake us up whilst we're + * still going through the list. + */ + atomic_inc(&rreq->nr_wr_ops); + + list_for_each_entry_safe(subreq, p, &rreq->subrequests, rreq_link) { + if (!test_bit(NETFS_SREQ_WRITE_TO_CACHE, &subreq->flags)) { + list_del_init(&subreq->rreq_link); + netfs_put_subrequest(subreq, false); + } + } + + list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + /* Amalgamate adjacent writes */ + while (!list_is_last(&subreq->rreq_link, &rreq->subrequests)) { + next = list_next_entry(subreq, rreq_link); + if (next->start != subreq->start + subreq->len) + break; + subreq->len += next->len; + list_del_init(&next->rreq_link); + netfs_put_subrequest(next, false); + } + + ret = cres->ops->prepare_write(cres, &subreq->start, &subreq->len, + rreq->i_size); + if (ret < 0) { + trace_netfs_failure(rreq, subreq, ret, netfs_fail_prepare_write); + trace_netfs_sreq(subreq, netfs_sreq_trace_write_skip); + continue; + } + + iov_iter_xarray(&iter, WRITE, &rreq->mapping->i_pages, + subreq->start, subreq->len); + + atomic_inc(&rreq->nr_wr_ops); + netfs_stat(&netfs_n_rh_write); + netfs_get_read_subrequest(subreq); + trace_netfs_sreq(subreq, netfs_sreq_trace_write); + cres->ops->write(cres, subreq->start, &iter, + netfs_rreq_copy_terminated, subreq); + } + + /* If we decrement nr_wr_ops to 0, the usage ref belongs to us. */ + if (atomic_dec_and_test(&rreq->nr_wr_ops)) + netfs_rreq_unmark_after_write(rreq, false); +} + +static void netfs_rreq_write_to_cache_work(struct work_struct *work) +{ + struct netfs_read_request *rreq = + container_of(work, struct netfs_read_request, work); + + netfs_rreq_do_write_to_cache(rreq); +} + +static void netfs_rreq_write_to_cache(struct netfs_read_request *rreq, + bool was_async) +{ + if (was_async) { + rreq->work.func = netfs_rreq_write_to_cache_work; + if (!queue_work(system_unbound_wq, &rreq->work)) + BUG(); + } else { + netfs_rreq_do_write_to_cache(rreq); + } +} + +/* + * Unlock the pages in a read operation. We need to set PG_fscache on any + * pages we're going to write back before we unlock them. + */ +static void netfs_rreq_unlock(struct netfs_read_request *rreq) +{ + struct netfs_read_subrequest *subreq; + struct page *page; + unsigned int iopos, account = 0; + pgoff_t start_page = rreq->start / PAGE_SIZE; + pgoff_t last_page = ((rreq->start + rreq->len) / PAGE_SIZE) - 1; + bool subreq_failed = false; + int i; + + XA_STATE(xas, &rreq->mapping->i_pages, start_page); + + if (test_bit(NETFS_RREQ_FAILED, &rreq->flags)) { + __clear_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags); + list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + __clear_bit(NETFS_SREQ_WRITE_TO_CACHE, &subreq->flags); + } + } + + /* Walk through the pagecache and the I/O request lists simultaneously. + * We may have a mixture of cached and uncached sections and we only + * really want to write out the uncached sections. This is slightly + * complicated by the possibility that we might have huge pages with a + * mixture inside. + */ + subreq = list_first_entry(&rreq->subrequests, + struct netfs_read_subrequest, rreq_link); + iopos = 0; + subreq_failed = (subreq->error < 0); + + trace_netfs_rreq(rreq, netfs_rreq_trace_unlock); + + rcu_read_lock(); + xas_for_each(&xas, page, last_page) { + unsigned int pgpos = (page->index - start_page) * PAGE_SIZE; + unsigned int pgend = pgpos + thp_size(page); + bool pg_failed = false; + + for (;;) { + if (!subreq) { + pg_failed = true; + break; + } + if (test_bit(NETFS_SREQ_WRITE_TO_CACHE, &subreq->flags)) + set_page_fscache(page); + pg_failed |= subreq_failed; + if (pgend < iopos + subreq->len) + break; + + account += subreq->transferred; + iopos += subreq->len; + if (!list_is_last(&subreq->rreq_link, &rreq->subrequests)) { + subreq = list_next_entry(subreq, rreq_link); + subreq_failed = (subreq->error < 0); + } else { + subreq = NULL; + subreq_failed = false; + } + if (pgend == iopos) + break; + } + + if (!pg_failed) { + for (i = 0; i < thp_nr_pages(page); i++) + flush_dcache_page(page); + SetPageUptodate(page); + } + + if (!test_bit(NETFS_RREQ_DONT_UNLOCK_PAGES, &rreq->flags)) { + if (page->index == rreq->no_unlock_page && + test_bit(NETFS_RREQ_NO_UNLOCK_PAGE, &rreq->flags)) + _debug("no unlock"); + else + unlock_page(page); + } + } + rcu_read_unlock(); + + task_io_account_read(account); + if (rreq->netfs_ops->done) + rreq->netfs_ops->done(rreq); +} + +/* + * Handle a short read. + */ +static void netfs_rreq_short_read(struct netfs_read_request *rreq, + struct netfs_read_subrequest *subreq) +{ + __clear_bit(NETFS_SREQ_SHORT_READ, &subreq->flags); + __set_bit(NETFS_SREQ_SEEK_DATA_READ, &subreq->flags); + + netfs_stat(&netfs_n_rh_short_read); + trace_netfs_sreq(subreq, netfs_sreq_trace_resubmit_short); + + netfs_get_read_subrequest(subreq); + atomic_inc(&rreq->nr_rd_ops); + if (subreq->source == NETFS_READ_FROM_CACHE) + netfs_read_from_cache(rreq, subreq, true); + else + netfs_read_from_server(rreq, subreq); +} + +/* + * Resubmit any short or failed operations. Returns true if we got the rreq + * ref back. + */ +static bool netfs_rreq_perform_resubmissions(struct netfs_read_request *rreq) +{ + struct netfs_read_subrequest *subreq; + + WARN_ON(in_interrupt()); + + trace_netfs_rreq(rreq, netfs_rreq_trace_resubmit); + + /* We don't want terminating submissions trying to wake us up whilst + * we're still going through the list. + */ + atomic_inc(&rreq->nr_rd_ops); + + __clear_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags); + list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + if (subreq->error) { + if (subreq->source != NETFS_READ_FROM_CACHE) + break; + subreq->source = NETFS_DOWNLOAD_FROM_SERVER; + subreq->error = 0; + netfs_stat(&netfs_n_rh_download_instead); + trace_netfs_sreq(subreq, netfs_sreq_trace_download_instead); + netfs_get_read_subrequest(subreq); + atomic_inc(&rreq->nr_rd_ops); + netfs_read_from_server(rreq, subreq); + } else if (test_bit(NETFS_SREQ_SHORT_READ, &subreq->flags)) { + netfs_rreq_short_read(rreq, subreq); + } + } + + /* If we decrement nr_rd_ops to 0, the usage ref belongs to us. */ + if (atomic_dec_and_test(&rreq->nr_rd_ops)) + return true; + + wake_up_var(&rreq->nr_rd_ops); + return false; +} + +/* + * Check to see if the data read is still valid. + */ +static void netfs_rreq_is_still_valid(struct netfs_read_request *rreq) +{ + struct netfs_read_subrequest *subreq; + + if (!rreq->netfs_ops->is_still_valid || + rreq->netfs_ops->is_still_valid(rreq)) + return; + + list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + if (subreq->source == NETFS_READ_FROM_CACHE) { + subreq->error = -ESTALE; + __set_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags); + } + } +} + +/* + * Assess the state of a read request and decide what to do next. + * + * Note that we could be in an ordinary kernel thread, on a workqueue or in + * softirq context at this point. We inherit a ref from the caller. + */ +static void netfs_rreq_assess(struct netfs_read_request *rreq, bool was_async) +{ + trace_netfs_rreq(rreq, netfs_rreq_trace_assess); + +again: + netfs_rreq_is_still_valid(rreq); + + if (!test_bit(NETFS_RREQ_FAILED, &rreq->flags) && + test_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags)) { + if (netfs_rreq_perform_resubmissions(rreq)) + goto again; + return; + } + + netfs_rreq_unlock(rreq); + + clear_bit_unlock(NETFS_RREQ_IN_PROGRESS, &rreq->flags); + wake_up_bit(&rreq->flags, NETFS_RREQ_IN_PROGRESS); + + if (test_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags)) + return netfs_rreq_write_to_cache(rreq, was_async); + + netfs_rreq_completed(rreq, was_async); +} + +static void netfs_rreq_work(struct work_struct *work) +{ + struct netfs_read_request *rreq = + container_of(work, struct netfs_read_request, work); + netfs_rreq_assess(rreq, false); +} + +/* + * Handle the completion of all outstanding I/O operations on a read request. + * We inherit a ref from the caller. + */ +static void netfs_rreq_terminated(struct netfs_read_request *rreq, + bool was_async) +{ + if (test_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags) && + was_async) { + if (!queue_work(system_unbound_wq, &rreq->work)) + BUG(); + } else { + netfs_rreq_assess(rreq, was_async); + } +} + +/** + * netfs_subreq_terminated - Note the termination of an I/O operation. + * @subreq: The I/O request that has terminated. + * @transferred_or_error: The amount of data transferred or an error code. + * @was_async: The termination was asynchronous + * + * This tells the read helper that a contributory I/O operation has terminated, + * one way or another, and that it should integrate the results. + * + * The caller indicates in @transferred_or_error the outcome of the operation, + * supplying a positive value to indicate the number of bytes transferred, 0 to + * indicate a failure to transfer anything that should be retried or a negative + * error code. The helper will look after reissuing I/O operations as + * appropriate and writing downloaded data to the cache. + * + * If @was_async is true, the caller might be running in softirq or interrupt + * context and we can't sleep. + */ +void netfs_subreq_terminated(struct netfs_read_subrequest *subreq, + ssize_t transferred_or_error, + bool was_async) +{ + struct netfs_read_request *rreq = subreq->rreq; + int u; + + _enter("[%u]{%llx,%lx},%zd", + subreq->debug_index, subreq->start, subreq->flags, + transferred_or_error); + + switch (subreq->source) { + case NETFS_READ_FROM_CACHE: + netfs_stat(&netfs_n_rh_read_done); + break; + case NETFS_DOWNLOAD_FROM_SERVER: + netfs_stat(&netfs_n_rh_download_done); + break; + default: + break; + } + + if (IS_ERR_VALUE(transferred_or_error)) { + subreq->error = transferred_or_error; + trace_netfs_failure(rreq, subreq, transferred_or_error, + netfs_fail_read); + goto failed; + } + + if (WARN(transferred_or_error > subreq->len - subreq->transferred, + "Subreq overread: R%x[%x] %zd > %zu - %zu", + rreq->debug_id, subreq->debug_index, + transferred_or_error, subreq->len, subreq->transferred)) + transferred_or_error = subreq->len - subreq->transferred; + + subreq->error = 0; + subreq->transferred += transferred_or_error; + if (subreq->transferred < subreq->len) + goto incomplete; + +complete: + __clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags); + if (test_bit(NETFS_SREQ_WRITE_TO_CACHE, &subreq->flags)) + set_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags); + +out: + trace_netfs_sreq(subreq, netfs_sreq_trace_terminated); + + /* If we decrement nr_rd_ops to 0, the ref belongs to us. */ + u = atomic_dec_return(&rreq->nr_rd_ops); + if (u == 0) + netfs_rreq_terminated(rreq, was_async); + else if (u == 1) + wake_up_var(&rreq->nr_rd_ops); + + netfs_put_subrequest(subreq, was_async); + return; + +incomplete: + if (test_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags)) { + netfs_clear_unread(subreq); + subreq->transferred = subreq->len; + goto complete; + } + + if (transferred_or_error == 0) { + if (__test_and_set_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags)) { + subreq->error = -ENODATA; + goto failed; + } + } else { + __clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags); + } + + __set_bit(NETFS_SREQ_SHORT_READ, &subreq->flags); + set_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags); + goto out; + +failed: + if (subreq->source == NETFS_READ_FROM_CACHE) { + netfs_stat(&netfs_n_rh_read_failed); + set_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags); + } else { + netfs_stat(&netfs_n_rh_download_failed); + set_bit(NETFS_RREQ_FAILED, &rreq->flags); + rreq->error = subreq->error; + } + goto out; +} +EXPORT_SYMBOL(netfs_subreq_terminated); + +static enum netfs_read_source netfs_cache_prepare_read(struct netfs_read_subrequest *subreq, + loff_t i_size) +{ + struct netfs_read_request *rreq = subreq->rreq; + struct netfs_cache_resources *cres = &rreq->cache_resources; + + if (cres->ops) + return cres->ops->prepare_read(subreq, i_size); + if (subreq->start >= rreq->i_size) + return NETFS_FILL_WITH_ZEROES; + return NETFS_DOWNLOAD_FROM_SERVER; +} + +/* + * Work out what sort of subrequest the next one will be. + */ +static enum netfs_read_source +netfs_rreq_prepare_read(struct netfs_read_request *rreq, + struct netfs_read_subrequest *subreq) +{ + enum netfs_read_source source; + + _enter("%llx-%llx,%llx", subreq->start, subreq->start + subreq->len, rreq->i_size); + + source = netfs_cache_prepare_read(subreq, rreq->i_size); + if (source == NETFS_INVALID_READ) + goto out; + + if (source == NETFS_DOWNLOAD_FROM_SERVER) { + /* Call out to the netfs to let it shrink the request to fit + * its own I/O sizes and boundaries. If it shinks it here, it + * will be called again to make simultaneous calls; if it wants + * to make serial calls, it can indicate a short read and then + * we will call it again. + */ + if (subreq->len > rreq->i_size - subreq->start) + subreq->len = rreq->i_size - subreq->start; + + if (rreq->netfs_ops->clamp_length && + !rreq->netfs_ops->clamp_length(subreq)) { + source = NETFS_INVALID_READ; + goto out; + } + } + + if (WARN_ON(subreq->len == 0)) + source = NETFS_INVALID_READ; + +out: + subreq->source = source; + trace_netfs_sreq(subreq, netfs_sreq_trace_prepare); + return source; +} + +/* + * Slice off a piece of a read request and submit an I/O request for it. + */ +static bool netfs_rreq_submit_slice(struct netfs_read_request *rreq, + unsigned int *_debug_index) +{ + struct netfs_read_subrequest *subreq; + enum netfs_read_source source; + + subreq = netfs_alloc_subrequest(rreq); + if (!subreq) + return false; + + subreq->debug_index = (*_debug_index)++; + subreq->start = rreq->start + rreq->submitted; + subreq->len = rreq->len - rreq->submitted; + + _debug("slice %llx,%zx,%zx", subreq->start, subreq->len, rreq->submitted); + list_add_tail(&subreq->rreq_link, &rreq->subrequests); + + /* Call out to the cache to find out what it can do with the remaining + * subset. It tells us in subreq->flags what it decided should be done + * and adjusts subreq->len down if the subset crosses a cache boundary. + * + * Then when we hand the subset, it can choose to take a subset of that + * (the starts must coincide), in which case, we go around the loop + * again and ask it to download the next piece. + */ + source = netfs_rreq_prepare_read(rreq, subreq); + if (source == NETFS_INVALID_READ) + goto subreq_failed; + + atomic_inc(&rreq->nr_rd_ops); + + rreq->submitted += subreq->len; + + trace_netfs_sreq(subreq, netfs_sreq_trace_submit); + switch (source) { + case NETFS_FILL_WITH_ZEROES: + netfs_fill_with_zeroes(rreq, subreq); + break; + case NETFS_DOWNLOAD_FROM_SERVER: + netfs_read_from_server(rreq, subreq); + break; + case NETFS_READ_FROM_CACHE: + netfs_read_from_cache(rreq, subreq, false); + break; + default: + BUG(); + } + + return true; + +subreq_failed: + rreq->error = subreq->error; + netfs_put_subrequest(subreq, false); + return false; +} + +static void netfs_cache_expand_readahead(struct netfs_read_request *rreq, + loff_t *_start, size_t *_len, loff_t i_size) +{ + struct netfs_cache_resources *cres = &rreq->cache_resources; + + if (cres->ops && cres->ops->expand_readahead) + cres->ops->expand_readahead(cres, _start, _len, i_size); +} + +static void netfs_rreq_expand(struct netfs_read_request *rreq, + struct readahead_control *ractl) +{ + /* Give the cache a chance to change the request parameters. The + * resultant request must contain the original region. + */ + netfs_cache_expand_readahead(rreq, &rreq->start, &rreq->len, rreq->i_size); + + /* Give the netfs a chance to change the request parameters. The + * resultant request must contain the original region. + */ + if (rreq->netfs_ops->expand_readahead) + rreq->netfs_ops->expand_readahead(rreq); + + /* Expand the request if the cache wants it to start earlier. Note + * that the expansion may get further extended if the VM wishes to + * insert THPs and the preferred start and/or end wind up in the middle + * of THPs. + * + * If this is the case, however, the THP size should be an integer + * multiple of the cache granule size, so we get a whole number of + * granules to deal with. + */ + if (rreq->start != readahead_pos(ractl) || + rreq->len != readahead_length(ractl)) { + readahead_expand(ractl, rreq->start, rreq->len); + rreq->start = readahead_pos(ractl); + rreq->len = readahead_length(ractl); + + trace_netfs_read(rreq, readahead_pos(ractl), readahead_length(ractl), + netfs_read_trace_expanded); + } +} + +/** + * netfs_readahead - Helper to manage a read request + * @ractl: The description of the readahead request + * @ops: The network filesystem's operations for the helper to use + * @netfs_priv: Private netfs data to be retained in the request + * + * Fulfil a readahead request by drawing data from the cache if possible, or + * the netfs if not. Space beyond the EOF is zero-filled. Multiple I/O + * requests from different sources will get munged together. If necessary, the + * readahead window can be expanded in either direction to a more convenient + * alighment for RPC efficiency or to make storage in the cache feasible. + * + * The calling netfs must provide a table of operations, only one of which, + * issue_op, is mandatory. It may also be passed a private token, which will + * be retained in rreq->netfs_priv and will be cleaned up by ops->cleanup(). + * + * This is usable whether or not caching is enabled. + */ +void netfs_readahead(struct readahead_control *ractl, + const struct netfs_read_request_ops *ops, + void *netfs_priv) +{ + struct netfs_read_request *rreq; + struct page *page; + unsigned int debug_index = 0; + int ret; + + _enter("%lx,%x", readahead_index(ractl), readahead_count(ractl)); + + if (readahead_count(ractl) == 0) + goto cleanup; + + rreq = netfs_alloc_read_request(ops, netfs_priv, ractl->file); + if (!rreq) + goto cleanup; + rreq->mapping = ractl->mapping; + rreq->start = readahead_pos(ractl); + rreq->len = readahead_length(ractl); + + if (ops->begin_cache_operation) { + ret = ops->begin_cache_operation(rreq); + if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) + goto cleanup_free; + } + + netfs_stat(&netfs_n_rh_readahead); + trace_netfs_read(rreq, readahead_pos(ractl), readahead_length(ractl), + netfs_read_trace_readahead); + + netfs_rreq_expand(rreq, ractl); + + atomic_set(&rreq->nr_rd_ops, 1); + do { + if (!netfs_rreq_submit_slice(rreq, &debug_index)) + break; + + } while (rreq->submitted < rreq->len); + + /* Drop the refs on the pages here rather than in the cache or + * filesystem. The locks will be dropped in netfs_rreq_unlock(). + */ + while ((page = readahead_page(ractl))) + put_page(page); + + /* If we decrement nr_rd_ops to 0, the ref belongs to us. */ + if (atomic_dec_and_test(&rreq->nr_rd_ops)) + netfs_rreq_assess(rreq, false); + return; + +cleanup_free: + netfs_put_read_request(rreq, false); + return; +cleanup: + if (netfs_priv) + ops->cleanup(ractl->mapping, netfs_priv); + return; +} +EXPORT_SYMBOL(netfs_readahead); + +/** + * netfs_readpage - Helper to manage a readpage request + * @file: The file to read from + * @page: The page to read + * @ops: The network filesystem's operations for the helper to use + * @netfs_priv: Private netfs data to be retained in the request + * + * Fulfil a readpage request by drawing data from the cache if possible, or the + * netfs if not. Space beyond the EOF is zero-filled. Multiple I/O requests + * from different sources will get munged together. + * + * The calling netfs must provide a table of operations, only one of which, + * issue_op, is mandatory. It may also be passed a private token, which will + * be retained in rreq->netfs_priv and will be cleaned up by ops->cleanup(). + * + * This is usable whether or not caching is enabled. + */ +int netfs_readpage(struct file *file, + struct page *page, + const struct netfs_read_request_ops *ops, + void *netfs_priv) +{ + struct netfs_read_request *rreq; + unsigned int debug_index = 0; + int ret; + + _enter("%lx", page_index(page)); + + rreq = netfs_alloc_read_request(ops, netfs_priv, file); + if (!rreq) { + if (netfs_priv) + ops->cleanup(netfs_priv, page_file_mapping(page)); + unlock_page(page); + return -ENOMEM; + } + rreq->mapping = page_file_mapping(page); + rreq->start = page_file_offset(page); + rreq->len = thp_size(page); + + if (ops->begin_cache_operation) { + ret = ops->begin_cache_operation(rreq); + if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) { + unlock_page(page); + goto out; + } + } + + netfs_stat(&netfs_n_rh_readpage); + trace_netfs_read(rreq, rreq->start, rreq->len, netfs_read_trace_readpage); + + netfs_get_read_request(rreq); + + atomic_set(&rreq->nr_rd_ops, 1); + do { + if (!netfs_rreq_submit_slice(rreq, &debug_index)) + break; + + } while (rreq->submitted < rreq->len); + + /* Keep nr_rd_ops incremented so that the ref always belongs to us, and + * the service code isn't punted off to a random thread pool to + * process. + */ + do { + wait_var_event(&rreq->nr_rd_ops, atomic_read(&rreq->nr_rd_ops) == 1); + netfs_rreq_assess(rreq, false); + } while (test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags)); + + ret = rreq->error; + if (ret == 0 && rreq->submitted < rreq->len) { + trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_readpage); + ret = -EIO; + } +out: + netfs_put_read_request(rreq, false); + return ret; +} +EXPORT_SYMBOL(netfs_readpage); + +static void netfs_clear_thp(struct page *page) +{ + unsigned int i; + + for (i = 0; i < thp_nr_pages(page); i++) + clear_highpage(page + i); +} + +/** + * netfs_write_begin - Helper to prepare for writing + * @file: The file to read from + * @mapping: The mapping to read from + * @pos: File position at which the write will begin + * @len: The length of the write in this page + * @flags: AOP_* flags + * @_page: Where to put the resultant page + * @_fsdata: Place for the netfs to store a cookie + * @ops: The network filesystem's operations for the helper to use + * @netfs_priv: Private netfs data to be retained in the request + * + * Pre-read data for a write-begin request by drawing data from the cache if + * possible, or the netfs if not. Space beyond the EOF is zero-filled. + * Multiple I/O requests from different sources will get munged together. If + * necessary, the readahead window can be expanded in either direction to a + * more convenient alighment for RPC efficiency or to make storage in the cache + * feasible. + * + * The calling netfs must provide a table of operations, only one of which, + * issue_op, is mandatory. + * + * The check_write_begin() operation can be provided to check for and flush + * conflicting writes once the page is grabbed and locked. It is passed a + * pointer to the fsdata cookie that gets returned to the VM to be passed to + * write_end. It is permitted to sleep. It should return 0 if the request + * should go ahead; unlock the page and return -EAGAIN to cause the page to be + * regot; or return an error. + * + * This is usable whether or not caching is enabled. + */ +int netfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned int len, unsigned int flags, + struct page **_page, void **_fsdata, + const struct netfs_read_request_ops *ops, + void *netfs_priv) +{ + struct netfs_read_request *rreq; + struct page *page, *xpage; + struct inode *inode = file_inode(file); + unsigned int debug_index = 0; + pgoff_t index = pos >> PAGE_SHIFT; + int pos_in_page = pos & ~PAGE_MASK; + loff_t size; + int ret; + + DEFINE_READAHEAD(ractl, file, NULL, mapping, index); + +retry: + page = grab_cache_page_write_begin(mapping, index, 0); + if (!page) + return -ENOMEM; + + if (ops->check_write_begin) { + /* Allow the netfs (eg. ceph) to flush conflicts. */ + ret = ops->check_write_begin(file, pos, len, page, _fsdata); + if (ret < 0) { + trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin); + if (ret == -EAGAIN) + goto retry; + goto error; + } + } + + if (PageUptodate(page)) + goto have_page; + + /* If the page is beyond the EOF, we want to clear it - unless it's + * within the cache granule containing the EOF, in which case we need + * to preload the granule. + */ + size = i_size_read(inode); + if (!ops->is_cache_enabled(inode) && + ((pos_in_page == 0 && len == thp_size(page)) || + (pos >= size) || + (pos_in_page == 0 && (pos + len) >= size))) { + netfs_clear_thp(page); + SetPageUptodate(page); + netfs_stat(&netfs_n_rh_write_zskip); + goto have_page_no_wait; + } + + ret = -ENOMEM; + rreq = netfs_alloc_read_request(ops, netfs_priv, file); + if (!rreq) + goto error; + rreq->mapping = page->mapping; + rreq->start = page_offset(page); + rreq->len = thp_size(page); + rreq->no_unlock_page = page->index; + __set_bit(NETFS_RREQ_NO_UNLOCK_PAGE, &rreq->flags); + netfs_priv = NULL; + + if (ops->begin_cache_operation) { + ret = ops->begin_cache_operation(rreq); + if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) + goto error_put; + } + + netfs_stat(&netfs_n_rh_write_begin); + trace_netfs_read(rreq, pos, len, netfs_read_trace_write_begin); + + /* Expand the request to meet caching requirements and download + * preferences. + */ + ractl._nr_pages = thp_nr_pages(page); + netfs_rreq_expand(rreq, &ractl); + netfs_get_read_request(rreq); + + /* We hold the page locks, so we can drop the references */ + while ((xpage = readahead_page(&ractl))) + if (xpage != page) + put_page(xpage); + + atomic_set(&rreq->nr_rd_ops, 1); + do { + if (!netfs_rreq_submit_slice(rreq, &debug_index)) + break; + + } while (rreq->submitted < rreq->len); + + /* Keep nr_rd_ops incremented so that the ref always belongs to us, and + * the service code isn't punted off to a random thread pool to + * process. + */ + for (;;) { + wait_var_event(&rreq->nr_rd_ops, atomic_read(&rreq->nr_rd_ops) == 1); + netfs_rreq_assess(rreq, false); + if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags)) + break; + cond_resched(); + } + + ret = rreq->error; + if (ret == 0 && rreq->submitted < rreq->len) { + trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_write_begin); + ret = -EIO; + } + netfs_put_read_request(rreq, false); + if (ret < 0) + goto error; + +have_page: + ret = wait_on_page_fscache_killable(page); + if (ret < 0) + goto error; +have_page_no_wait: + if (netfs_priv) + ops->cleanup(netfs_priv, mapping); + *_page = page; + _leave(" = 0"); + return 0; + +error_put: + netfs_put_read_request(rreq, false); +error: + unlock_page(page); + put_page(page); + if (netfs_priv) + ops->cleanup(netfs_priv, mapping); + _leave(" = %d", ret); + return ret; +} +EXPORT_SYMBOL(netfs_write_begin); diff --git a/fs/netfs/stats.c b/fs/netfs/stats.c new file mode 100644 index 0000000000000000000000000000000000000000..9ae538c853787ee4284bbfaab6e9328885a2f564 --- /dev/null +++ b/fs/netfs/stats.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Netfs support statistics + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include <linux/export.h> +#include <linux/seq_file.h> +#include <linux/netfs.h> +#include "internal.h" + +atomic_t netfs_n_rh_readahead; +atomic_t netfs_n_rh_readpage; +atomic_t netfs_n_rh_rreq; +atomic_t netfs_n_rh_sreq; +atomic_t netfs_n_rh_download; +atomic_t netfs_n_rh_download_done; +atomic_t netfs_n_rh_download_failed; +atomic_t netfs_n_rh_download_instead; +atomic_t netfs_n_rh_read; +atomic_t netfs_n_rh_read_done; +atomic_t netfs_n_rh_read_failed; +atomic_t netfs_n_rh_zero; +atomic_t netfs_n_rh_short_read; +atomic_t netfs_n_rh_write; +atomic_t netfs_n_rh_write_begin; +atomic_t netfs_n_rh_write_done; +atomic_t netfs_n_rh_write_failed; +atomic_t netfs_n_rh_write_zskip; + +void netfs_stats_show(struct seq_file *m) +{ + seq_printf(m, "RdHelp : RA=%u RP=%u WB=%u WBZ=%u rr=%u sr=%u\n", + atomic_read(&netfs_n_rh_readahead), + atomic_read(&netfs_n_rh_readpage), + atomic_read(&netfs_n_rh_write_begin), + atomic_read(&netfs_n_rh_write_zskip), + atomic_read(&netfs_n_rh_rreq), + atomic_read(&netfs_n_rh_sreq)); + seq_printf(m, "RdHelp : ZR=%u sh=%u sk=%u\n", + atomic_read(&netfs_n_rh_zero), + atomic_read(&netfs_n_rh_short_read), + atomic_read(&netfs_n_rh_write_zskip)); + seq_printf(m, "RdHelp : DL=%u ds=%u df=%u di=%u\n", + atomic_read(&netfs_n_rh_download), + atomic_read(&netfs_n_rh_download_done), + atomic_read(&netfs_n_rh_download_failed), + atomic_read(&netfs_n_rh_download_instead)); + seq_printf(m, "RdHelp : RD=%u rs=%u rf=%u\n", + atomic_read(&netfs_n_rh_read), + atomic_read(&netfs_n_rh_read_done), + atomic_read(&netfs_n_rh_read_failed)); + seq_printf(m, "RdHelp : WR=%u ws=%u wf=%u\n", + atomic_read(&netfs_n_rh_write), + atomic_read(&netfs_n_rh_write_done), + atomic_read(&netfs_n_rh_write_failed)); +} +EXPORT_SYMBOL(netfs_stats_show); diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c index 971a9251c1d97c2c7bda911cead74d5a26654def..a06d213d76895f4c76699f728fea36a2919f9e98 100644 --- a/fs/nfs/fs_context.c +++ b/fs/nfs/fs_context.c @@ -463,6 +463,9 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, if (opt < 0) return ctx->sloppy ? 1 : opt; + if (fc->security) + ctx->has_sec_mnt_opts = 1; + switch (opt) { case Opt_source: if (fc->source) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a7fb076a5f44bcb8311e7bbb76c8ae778e158823..5a8854de0c19c25659c0aa97c94bc19d4cc848ab 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -335,7 +335,7 @@ nfs_find_actor(struct inode *inode, void *opaque) if (NFS_FILEID(inode) != fattr->fileid) return 0; - if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode)) + if (inode_wrong_type(inode, fattr->mode)) return 0; if (nfs_compare_fh(NFS_FH(inode), fh)) return 0; @@ -1461,7 +1461,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat return 0; return -ESTALE; } - if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) + if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) return -ESTALE; @@ -1876,7 +1876,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) /* * Make sure the inode's type hasn't changed. */ - if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { + if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) { /* * Big trouble! The inode has become a different object. */ diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7b644d6c09e4b27d8e0e5a25d75f91202ea72049..7395d0977b7daa3c90bb69603979c8d746103ed9 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -96,6 +96,7 @@ struct nfs_fs_context { char *fscache_uniq; unsigned short protofamily; unsigned short mountfamily; + bool has_sec_mnt_opts; struct { union { diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 94885c6f8f5410e388566828a80a64104effbb87..4aaa1f5dd381efa10c347745ac8abd71acfd7569 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1045,7 +1045,7 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx) sb->s_blocksize = 0; sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr; sb->s_op = server->nfs_client->cl_nfs_mod->sops; - if (ctx && ctx->bsize) + if (ctx->bsize) sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits); if (server->nfs_client->rpc_ops->version != 2) { @@ -1077,6 +1077,7 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx) &sb->s_blocksize_bits); nfs_super_set_maxbytes(sb, server->maxfilesize); + server->has_sec_mnt_opts = ctx->has_sec_mnt_opts; } static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, @@ -1193,6 +1194,9 @@ static int nfs_compare_super(struct super_block *sb, struct fs_context *fc) return 0; if (!nfs_compare_userns(old, server)) return 0; + if ((old->has_sec_mnt_opts || fc->security) && + security_sb_mnt_opts_compat(sb, fc->security)) + return 0; return nfs_compare_mount_options(sb, server, fc); } diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index 79c563c1a5e84b5aa962612614704115cc00941d..5a5bd85d08f8ca983d8a6e9fe4c2e5020137972d 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c @@ -136,6 +136,77 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, } EXPORT_SYMBOL_GPL(nfsacl_encode); +/** + * nfs_stream_encode_acl - Encode an NFSv3 ACL + * + * @xdr: an xdr_stream positioned to receive an encoded ACL + * @inode: inode of file whose ACL this is + * @acl: posix_acl to encode + * @encode_entries: whether to encode ACEs as well + * @typeflag: ACL type: NFS_ACL_DEFAULT or zero + * + * Return values: + * %false: The ACL could not be encoded + * %true: @xdr is advanced to the next available position + */ +bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode, + struct posix_acl *acl, int encode_entries, + int typeflag) +{ + const size_t elem_size = XDR_UNIT * 3; + u32 entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; + struct nfsacl_encode_desc nfsacl_desc = { + .desc = { + .elem_size = elem_size, + .array_len = encode_entries ? entries : 0, + .xcode = xdr_nfsace_encode, + }, + .acl = acl, + .typeflag = typeflag, + .uid = inode->i_uid, + .gid = inode->i_gid, + }; + struct nfsacl_simple_acl aclbuf; + unsigned int base; + int err; + + if (entries > NFS_ACL_MAX_ENTRIES) + return false; + if (xdr_stream_encode_u32(xdr, entries) < 0) + return false; + + if (encode_entries && acl && acl->a_count == 3) { + struct posix_acl *acl2 = &aclbuf.acl; + + /* Avoid the use of posix_acl_alloc(). nfsacl_encode() is + * invoked in contexts where a memory allocation failure is + * fatal. Fortunately this fake ACL is small enough to + * construct on the stack. */ + posix_acl_init(acl2, 4); + + /* Insert entries in canonical order: other orders seem + to confuse Solaris VxFS. */ + acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ + acl2->a_entries[1] = acl->a_entries[1]; /* ACL_GROUP_OBJ */ + acl2->a_entries[2] = acl->a_entries[1]; /* ACL_MASK */ + acl2->a_entries[2].e_tag = ACL_MASK; + acl2->a_entries[3] = acl->a_entries[2]; /* ACL_OTHER */ + nfsacl_desc.acl = acl2; + } + + base = xdr_stream_pos(xdr); + if (!xdr_reserve_space(xdr, XDR_UNIT + + elem_size * nfsacl_desc.desc.array_len)) + return false; + err = xdr_encode_array2(xdr->buf, base, &nfsacl_desc.desc); + if (err) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(nfs_stream_encode_acl); + + struct nfsacl_decode_desc { struct xdr_array2_desc desc; unsigned int count; diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index d6cff5fbe705b4f64e215507d504a5081ab5b002..5fa38ad9e7e3f241a25864551923f95e12c49c00 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -99,7 +99,7 @@ config NFSD_BLOCKLAYOUT help This option enables support for the exporting pNFS block layouts in the kernel's NFS server. The pNFS block layout enables NFS - clients to directly perform I/O to block devices accesible to both + clients to directly perform I/O to block devices accessible to both the server and the clients. See RFC 5663 for more details. If unsure, say N. @@ -113,7 +113,7 @@ config NFSD_SCSILAYOUT help This option enables support for the exporting pNFS SCSI layouts in the kernel's NFS server. The pNFS SCSI layout enables NFS - clients to directly perform I/O to SCSI devices accesible to both + clients to directly perform I/O to SCSI devices accessible to both the server and the clients. See draft-ietf-nfsv4-scsi-layout for more details. @@ -127,7 +127,7 @@ config NFSD_FLEXFILELAYOUT This option enables support for the exporting pNFS Flex File layouts in the kernel's NFS server. The pNFS Flex File layout enables NFS clients to directly perform I/O to NFSv3 devices - accesible to both the server and the clients. See + accessible to both the server and the clients. See draft-ietf-nfsv4-flex-files for more details. Warning, this server implements the bare minimum functionality diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index c330f5bd0cf329f9b762deb1e36ab340c7a3daca..a75abeb1e69881295e93aa54f7e27f58d33bdfef 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -51,9 +51,6 @@ struct nfsd_net { bool grace_ended; time64_t boot_time; - /* internal mount of the "nfsd" pseudofilesystem: */ - struct vfsmount *nfsd_mnt; - struct dentry *nfsd_client_dir; /* @@ -130,6 +127,9 @@ struct nfsd_net { wait_queue_head_t ntf_wq; atomic_t ntf_refcnt; + /* Allow umount to wait for nfsd state cleanup */ + struct completion nfsd_shutdown_complete; + /* * clientid and stateid data for construction of net unique COPY * stateids. diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 855e17772eba44173803ff5b5a95aa7261661e13..4b43929c1f25530fdd2e89945f536b1a4a6708a9 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -242,79 +242,61 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) /* GETACL */ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_getaclres *resp = rqstp->rq_resp; struct dentry *dentry = resp->fh.fh_dentry; struct inode *inode; - struct kvec *head = rqstp->rq_res.head; - unsigned int base; - int n; int w; - *p++ = resp->status; - if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; - /* - * Since this is version 2, the check for nfserr in - * nfsd_dispatch actually ensures the following cannot happen. - * However, it seems fragile to depend on that. - */ if (dentry == NULL || d_really_is_negative(dentry)) - return 0; + return 1; inode = d_inode(dentry); - p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); - *p++ = htonl(resp->mask); - if (!xdr_ressize_check(rqstp, p)) + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) return 0; - base = (char *)p - (char *)head->iov_base; rqstp->rq_res.page_len = w = nfsacl_size( (resp->mask & NFS_ACL) ? resp->acl_access : NULL, (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); while (w > 0) { if (!*(rqstp->rq_next_page++)) - return 0; + return 1; w -= PAGE_SIZE; } - n = nfsacl_encode(&rqstp->rq_res, base, inode, - resp->acl_access, - resp->mask & NFS_ACL, 0); - if (n > 0) - n = nfsacl_encode(&rqstp->rq_res, base + n, inode, - resp->acl_default, - resp->mask & NFS_DFACL, - NFS_ACL_DEFAULT); - return (n > 0); -} - -static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) -{ - struct nfsd_attrstat *resp = rqstp->rq_resp; - - *p++ = resp->status; - if (resp->status != nfs_ok) - goto out; + if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access, + resp->mask & NFS_ACL, 0)) + return 0; + if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default, + resp->mask & NFS_DFACL, NFS_ACL_DEFAULT)) + return 0; - p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); -out: - return xdr_ressize_check(rqstp, p); + return 1; } /* ACCESS */ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_accessres *resp = rqstp->rq_resp; - *p++ = resp->status; - if (resp->status != nfs_ok) - goto out; + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->access) < 0) + return 0; + break; + } - p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); - *p++ = htonl(resp->access); -out: - return xdr_ressize_check(rqstp, p); + return 1; } /* @@ -329,13 +311,6 @@ static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp) posix_acl_release(resp->acl_default); } -static void nfsaclsvc_release_attrstat(struct svc_rqst *rqstp) -{ - struct nfsd_attrstat *resp = rqstp->rq_resp; - - fh_put(&resp->fh); -} - static void nfsaclsvc_release_access(struct svc_rqst *rqstp) { struct nfsd3_accessres *resp = rqstp->rq_resp; @@ -375,8 +350,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { [ACLPROC2_SETACL] = { .pc_func = nfsacld_proc_setacl, .pc_decode = nfsaclsvc_decode_setaclargs, - .pc_encode = nfsaclsvc_encode_attrstatres, - .pc_release = nfsaclsvc_release_attrstat, + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd3_setaclargs), .pc_ressize = sizeof(struct nfsd_attrstat), .pc_cachetype = RC_NOCACHE, @@ -386,8 +361,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { [ACLPROC2_GETATTR] = { .pc_func = nfsacld_proc_getattr, .pc_decode = nfssvc_decode_fhandleargs, - .pc_encode = nfsaclsvc_encode_attrstatres, - .pc_release = nfsaclsvc_release_attrstat, + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_fhandle), .pc_ressize = sizeof(struct nfsd_attrstat), .pc_cachetype = RC_NOCACHE, diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 9a6f18d74d1485bda0629e6dc845d56e23b2e2ef..a1591feeea22ce9b087959d738af534f79e7a58a 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -168,22 +168,25 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) /* GETACL */ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_getaclres *resp = rqstp->rq_resp; struct dentry *dentry = resp->fh.fh_dentry; + struct kvec *head = rqstp->rq_res.head; + struct inode *inode = d_inode(dentry); + unsigned int base; + int n; + int w; - *p++ = resp->status; - p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); - if (resp->status == 0 && dentry && d_really_is_positive(dentry)) { - struct inode *inode = d_inode(dentry); - struct kvec *head = rqstp->rq_res.head; - unsigned int base; - int n; - int w; - - *p++ = htonl(resp->mask); - if (!xdr_ressize_check(rqstp, p)) + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) return 0; - base = (char *)p - (char *)head->iov_base; + + base = (char *)xdr->p - (char *)head->iov_base; rqstp->rq_res.page_len = w = nfsacl_size( (resp->mask & NFS_ACL) ? resp->acl_access : NULL, @@ -204,9 +207,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) NFS_ACL_DEFAULT); if (n <= 0) return 0; - } else - if (!xdr_ressize_check(rqstp, p)) + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) return 0; + } return 1; } @@ -214,11 +219,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) /* SETACL */ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_attrstat *resp = rqstp->rq_resp; - *p++ = resp->status; - p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_nfsstat3(xdr, resp->status) && + svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh); } /* diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 8675851199f8dde167394d3f3d524b8f13244acf..17715a6c7a4090f2bb7ac3f4dd66659137ee5e8a 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -126,14 +126,15 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd3_readlinkres *resp = rqstp->rq_resp; - char *buffer = page_address(*(rqstp->rq_next_page++)); dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); /* Read the symlink. */ fh_copy(&resp->fh, &argp->fh); resp->len = NFS3_MAXPATHLEN; - resp->status = nfsd_readlink(rqstp, &resp->fh, buffer, &resp->len); + resp->pages = rqstp->rq_next_page++; + resp->status = nfsd_readlink(rqstp, &resp->fh, + page_address(*resp->pages), &resp->len); return rpc_success; } @@ -158,6 +159,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp) v = 0; len = argp->count; + resp->pages = rqstp->rq_next_page; while (len > 0) { struct page *page = *(rqstp->rq_next_page++); @@ -439,17 +441,30 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, struct nfsd3_readdirres *resp, int count) { + struct xdr_buf *buf = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; + count = min_t(u32, count, svc_max_payload(rqstp)); - /* Convert byte count to number of words (i.e. >> 2), - * and reserve room for the NULL ptr & eof flag (-2 words) */ - resp->buflen = (count >> 2) - 2; + memset(buf, 0, sizeof(*buf)); - resp->buffer = page_address(*rqstp->rq_next_page); + /* Reserve room for the NULL ptr & eof flag (-2 words) */ + buf->buflen = count - XDR_UNIT * 2; + buf->pages = rqstp->rq_next_page; while (count > 0) { rqstp->rq_next_page++; count -= PAGE_SIZE; } + + /* This is xdr_init_encode(), but it assumes that + * the head kvec has already been consumed. */ + xdr_set_scratch_buffer(xdr, NULL, 0); + xdr->buf = buf; + xdr->page_ptr = buf->pages; + xdr->iov = NULL; + xdr->p = page_address(*buf->pages); + xdr->end = xdr->p + (PAGE_SIZE >> 2); + xdr->rqst = NULL; } /* @@ -460,10 +475,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) { struct nfsd3_readdirargs *argp = rqstp->rq_argp; struct nfsd3_readdirres *resp = rqstp->rq_resp; - int count = 0; loff_t offset; - struct page **p; - caddr_t page_addr = NULL; dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), @@ -471,39 +483,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) nfsd3_init_dirlist_pages(rqstp, resp, argp->count); - /* Read directory and encode entries on the fly */ fh_copy(&resp->fh, &argp->fh); - resp->common.err = nfs_ok; + resp->cookie_offset = 0; resp->rqstp = rqstp; offset = argp->cookie; - resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, - &resp->common, nfs3svc_encode_entry); + &resp->common, nfs3svc_encode_entry3); memcpy(resp->verf, argp->verf, 8); - count = 0; - for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { - page_addr = page_address(*p); + nfs3svc_encode_cookie3(resp, offset); - if (((caddr_t)resp->buffer >= page_addr) && - ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { - count += (caddr_t)resp->buffer - page_addr; - break; - } - count += PAGE_SIZE; - } - resp->count = count >> 2; - if (resp->offset) { - if (unlikely(resp->offset1)) { - /* we ended up with offset on a page boundary */ - *resp->offset = htonl(offset >> 32); - *resp->offset1 = htonl(offset & 0xffffffff); - resp->offset1 = NULL; - } else { - xdr_encode_hyper(resp->offset, offset); - } - resp->offset = NULL; - } + /* Recycle only pages that were part of the reply */ + rqstp->rq_next_page = resp->xdr.page_ptr + 1; return rpc_success; } @@ -517,10 +508,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) { struct nfsd3_readdirargs *argp = rqstp->rq_argp; struct nfsd3_readdirres *resp = rqstp->rq_resp; - int count = 0; loff_t offset; - struct page **p; - caddr_t page_addr = NULL; dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), @@ -528,10 +516,9 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) nfsd3_init_dirlist_pages(rqstp, resp, argp->count); - /* Read directory and encode entries on the fly */ fh_copy(&resp->fh, &argp->fh); - resp->common.err = nfs_ok; + resp->cookie_offset = 0; resp->rqstp = rqstp; offset = argp->cookie; @@ -545,30 +532,12 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) } resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, - &resp->common, nfs3svc_encode_entry_plus); + &resp->common, nfs3svc_encode_entryplus3); memcpy(resp->verf, argp->verf, 8); - for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { - page_addr = page_address(*p); + nfs3svc_encode_cookie3(resp, offset); - if (((caddr_t)resp->buffer >= page_addr) && - ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { - count += (caddr_t)resp->buffer - page_addr; - break; - } - count += PAGE_SIZE; - } - resp->count = count >> 2; - if (resp->offset) { - if (unlikely(resp->offset1)) { - /* we ended up with offset on a page boundary */ - *resp->offset = htonl(offset >> 32); - *resp->offset1 = htonl(offset & 0xffffffff); - resp->offset1 = NULL; - } else { - xdr_encode_hyper(resp->offset, offset); - } - resp->offset = NULL; - } + /* Recycle only pages that were part of the reply */ + rqstp->rq_next_page = resp->xdr.page_ptr + 1; out: return rpc_success; @@ -736,7 +705,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { [NFS3PROC_GETATTR] = { .pc_func = nfsd3_proc_getattr, .pc_decode = nfs3svc_decode_fhandleargs, - .pc_encode = nfs3svc_encode_attrstatres, + .pc_encode = nfs3svc_encode_getattrres, .pc_release = nfs3svc_release_fhandle, .pc_argsize = sizeof(struct nfsd_fhandle), .pc_ressize = sizeof(struct nfsd3_attrstatres), @@ -758,7 +727,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { [NFS3PROC_LOOKUP] = { .pc_func = nfsd3_proc_lookup, .pc_decode = nfs3svc_decode_diropargs, - .pc_encode = nfs3svc_encode_diropres, + .pc_encode = nfs3svc_encode_lookupres, .pc_release = nfs3svc_release_fhandle2, .pc_argsize = sizeof(struct nfsd3_diropargs), .pc_ressize = sizeof(struct nfsd3_diropres), diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 9d9a01ce0b270835129cfc90d40f6cbb54b0c3c0..0a5ebc52e6a9ccdc5aaf0beffab7ced35cb3adac 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -14,13 +14,26 @@ #include "netns.h" #include "vfs.h" -#define NFSDDBG_FACILITY NFSDDBG_XDR +/* + * Force construction of an empty post-op attr + */ +static const struct svc_fh nfs3svc_null_fh = { + .fh_no_wcc = true, +}; +/* + * time_delta. {1, 0} means the server is accurate only + * to the nearest second. + */ +static const struct timespec64 nfs3svc_time_delta = { + .tv_sec = 1, + .tv_nsec = 0, +}; /* * Mapping of S_IF* types to NFS file types */ -static u32 nfs3_ftypes[] = { +static const u32 nfs3_ftypes[] = { NF3NON, NF3FIFO, NF3CHR, NF3BAD, NF3DIR, NF3BAD, NF3BLK, NF3BAD, NF3REG, NF3BAD, NF3LNK, NF3BAD, @@ -33,9 +46,11 @@ static u32 nfs3_ftypes[] = { */ static __be32 * -encode_time3(__be32 *p, struct timespec64 *time) +encode_nfstime3(__be32 *p, const struct timespec64 *time) { - *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); + *p++ = cpu_to_be32((u32)time->tv_sec); + *p++ = cpu_to_be32(time->tv_nsec); + return p; } @@ -82,14 +97,80 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) return true; } -static __be32 * -encode_fh(__be32 *p, struct svc_fh *fhp) +/** + * svcxdr_encode_nfsstat3 - Encode an NFSv3 status code + * @xdr: XDR stream + * @status: status value to encode + * + * Return values: + * %false: Send buffer space was exhausted + * %true: Success + */ +bool +svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, sizeof(status)); + if (!p) + return false; + *p = status; + + return true; +} + +static bool +svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) { - unsigned int size = fhp->fh_handle.fh_size; - *p++ = htonl(size); - if (size) p[XDR_QUADLEN(size)-1]=0; + u32 size = fhp->fh_handle.fh_size; + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT + size); + if (!p) + return false; + *p++ = cpu_to_be32(size); + if (size) + p[XDR_QUADLEN(size) - 1] = 0; memcpy(p, &fhp->fh_handle.fh_base, size); - return p + XDR_QUADLEN(size); + + return true; +} + +static bool +svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) +{ + if (xdr_stream_encode_item_present(xdr) < 0) + return false; + if (!svcxdr_encode_nfs_fh3(xdr, fhp)) + return false; + + return true; +} + +static bool +svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, NFS3_COOKIEVERFSIZE); + if (!p) + return false; + memcpy(p, verf, NFS3_COOKIEVERFSIZE); + + return true; +} + +static bool +svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, NFS3_WRITEVERFSIZE); + if (!p) + return false; + memcpy(p, verf, NFS3_WRITEVERFSIZE); + + return true; } static bool @@ -253,115 +334,157 @@ svcxdr_decode_devicedata3(struct svc_rqst *rqstp, struct xdr_stream *xdr, svcxdr_decode_specdata3(xdr, args); } -static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) +static bool +svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp, const struct kstat *stat) { - u64 f; + struct user_namespace *userns = nfsd_user_namespace(rqstp); + __be32 *p; + u64 fsid; + + p = xdr_reserve_space(xdr, XDR_UNIT * 21); + if (!p) + return false; + + *p++ = cpu_to_be32(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); + *p++ = cpu_to_be32((u32)(stat->mode & S_IALLUGO)); + *p++ = cpu_to_be32((u32)stat->nlink); + *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid)); + *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid)); + if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) + p = xdr_encode_hyper(p, (u64)NFS3_MAXPATHLEN); + else + p = xdr_encode_hyper(p, (u64)stat->size); + + /* used */ + p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); + + /* rdev */ + *p++ = cpu_to_be32((u32)MAJOR(stat->rdev)); + *p++ = cpu_to_be32((u32)MINOR(stat->rdev)); + switch(fsid_source(fhp)) { - default: - case FSIDSOURCE_DEV: - p = xdr_encode_hyper(p, (u64)huge_encode_dev - (fhp->fh_dentry->d_sb->s_dev)); - break; case FSIDSOURCE_FSID: - p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); + fsid = (u64)fhp->fh_export->ex_fsid; break; case FSIDSOURCE_UUID: - f = ((u64*)fhp->fh_export->ex_uuid)[0]; - f ^= ((u64*)fhp->fh_export->ex_uuid)[1]; - p = xdr_encode_hyper(p, f); + fsid = ((u64 *)fhp->fh_export->ex_uuid)[0]; + fsid ^= ((u64 *)fhp->fh_export->ex_uuid)[1]; break; + default: + fsid = (u64)huge_encode_dev(fhp->fh_dentry->d_sb->s_dev); } - return p; -} + p = xdr_encode_hyper(p, fsid); -static __be32 * -encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, - struct kstat *stat) -{ - struct user_namespace *userns = nfsd_user_namespace(rqstp); - *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); - *p++ = htonl((u32) (stat->mode & S_IALLUGO)); - *p++ = htonl((u32) stat->nlink); - *p++ = htonl((u32) from_kuid_munged(userns, stat->uid)); - *p++ = htonl((u32) from_kgid_munged(userns, stat->gid)); - if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { - p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); - } else { - p = xdr_encode_hyper(p, (u64) stat->size); - } - p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); - *p++ = htonl((u32) MAJOR(stat->rdev)); - *p++ = htonl((u32) MINOR(stat->rdev)); - p = encode_fsid(p, fhp); + /* fileid */ p = xdr_encode_hyper(p, stat->ino); - p = encode_time3(p, &stat->atime); - p = encode_time3(p, &stat->mtime); - p = encode_time3(p, &stat->ctime); - return p; + p = encode_nfstime3(p, &stat->atime); + p = encode_nfstime3(p, &stat->mtime); + encode_nfstime3(p, &stat->ctime); + + return true; } -static __be32 * -encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +static bool +svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) { - /* Attributes to follow */ - *p++ = xdr_one; - return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT * 6); + if (!p) + return false; + p = xdr_encode_hyper(p, (u64)fhp->fh_pre_size); + p = encode_nfstime3(p, &fhp->fh_pre_mtime); + encode_nfstime3(p, &fhp->fh_pre_ctime); + + return true; } -/* - * Encode post-operation attributes. - * The inode may be NULL if the call failed because of a stale file - * handle. In this case, no attributes are returned. - */ -static __be32 * -encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +static bool +svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) { - struct dentry *dentry = fhp->fh_dentry; - if (!fhp->fh_no_wcc && dentry && d_really_is_positive(dentry)) { - __be32 err; - struct kstat stat; - - err = fh_getattr(fhp, &stat); - if (!err) { - *p++ = xdr_one; /* attributes follow */ - lease_get_mtime(d_inode(dentry), &stat.mtime); - return encode_fattr3(rqstp, p, fhp, &stat); - } + if (!fhp->fh_pre_saved) { + if (xdr_stream_encode_item_absent(xdr) < 0) + return false; + return true; } - *p++ = xdr_zero; - return p; + + if (xdr_stream_encode_item_present(xdr) < 0) + return false; + return svcxdr_encode_wcc_attr(xdr, fhp); } -/* Helper for NFSv3 ACLs */ -__be32 * -nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +/** + * svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes + * @rqstp: Context of a completed RPC transaction + * @xdr: XDR stream + * @fhp: File handle to encode + * + * Return values: + * %false: Send buffer space was exhausted + * %true: Success + */ +bool +svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp) { - return encode_post_op_attr(rqstp, p, fhp); + struct dentry *dentry = fhp->fh_dentry; + struct kstat stat; + + /* + * The inode may be NULL if the call failed because of a + * stale file handle. In this case, no attributes are + * returned. + */ + if (fhp->fh_no_wcc || !dentry || !d_really_is_positive(dentry)) + goto no_post_op_attrs; + if (fh_getattr(fhp, &stat) != nfs_ok) + goto no_post_op_attrs; + + if (xdr_stream_encode_item_present(xdr) < 0) + return false; + lease_get_mtime(d_inode(dentry), &stat.mtime); + if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &stat)) + return false; + + return true; + +no_post_op_attrs: + return xdr_stream_encode_item_absent(xdr) > 0; } /* - * Enocde weak cache consistency data + * Encode weak cache consistency data */ -static __be32 * -encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +static bool +svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp) { - struct dentry *dentry = fhp->fh_dentry; - - if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) { - if (fhp->fh_pre_saved) { - *p++ = xdr_one; - p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); - p = encode_time3(p, &fhp->fh_pre_mtime); - p = encode_time3(p, &fhp->fh_pre_ctime); - } else { - *p++ = xdr_zero; - } - return encode_saved_post_attr(rqstp, p, fhp); - } - /* no pre- or post-attrs */ - *p++ = xdr_zero; - return encode_post_op_attr(rqstp, p, fhp); + struct dentry *dentry = fhp->fh_dentry; + + if (!dentry || !d_really_is_positive(dentry) || !fhp->fh_post_saved) + goto neither; + + /* before */ + if (!svcxdr_encode_pre_op_attr(xdr, fhp)) + return false; + + /* after */ + if (xdr_stream_encode_item_present(xdr) < 0) + return false; + if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &fhp->fh_post_attr)) + return false; + + return true; + +neither: + if (xdr_stream_encode_item_absent(xdr) < 0) + return false; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, fhp)) + return false; + + return true; } static bool fs_supports_change_attribute(struct super_block *sb) @@ -713,210 +836,252 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) /* GETATTR */ int -nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) +nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_attrstat *resp = rqstp->rq_resp; - *p++ = resp->status; - if (resp->status == 0) { - lease_get_mtime(d_inode(resp->fh.fh_dentry), - &resp->stat.mtime); - p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime); + if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat)) + return 0; + break; } - return xdr_ressize_check(rqstp, p); + + return 1; } /* SETATTR, REMOVE, RMDIR */ int nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_attrstat *resp = rqstp->rq_resp; - *p++ = resp->status; - p = encode_wcc_data(rqstp, p, &resp->fh); - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_nfsstat3(xdr, resp->status) && + svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh); } /* LOOKUP */ -int -nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) +int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_diropres *resp = rqstp->rq_resp; - *p++ = resp->status; - if (resp->status == 0) { - p = encode_fh(p, &resp->fh); - p = encode_post_op_attr(rqstp, p, &resp->fh); + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) + return 0; } - p = encode_post_op_attr(rqstp, p, &resp->dirfh); - return xdr_ressize_check(rqstp, p); + + return 1; } /* ACCESS */ int nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_accessres *resp = rqstp->rq_resp; - *p++ = resp->status; - p = encode_post_op_attr(rqstp, p, &resp->fh); - if (resp->status == 0) - *p++ = htonl(resp->access); - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->access) < 0) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + } + + return 1; } /* READLINK */ int nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_readlinkres *resp = rqstp->rq_resp; struct kvec *head = rqstp->rq_res.head; - *p++ = resp->status; - p = encode_post_op_attr(rqstp, p, &resp->fh); - if (resp->status == 0) { - *p++ = htonl(resp->len); - xdr_ressize_check(rqstp, p); - rqstp->rq_res.page_len = resp->len; - if (resp->len & 3) { - /* need to pad the tail */ - rqstp->rq_res.tail[0].iov_base = p; - *p = 0; - rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); - } - if (svc_encode_result_payload(rqstp, head->iov_len, resp->len)) + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) return 0; - return 1; - } else - return xdr_ressize_check(rqstp, p); + if (xdr_stream_encode_u32(xdr, resp->len) < 0) + return 0; + xdr_write_pages(xdr, resp->pages, 0, resp->len); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + } + + return 1; } /* READ */ int nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_readres *resp = rqstp->rq_resp; struct kvec *head = rqstp->rq_res.head; - *p++ = resp->status; - p = encode_post_op_attr(rqstp, p, &resp->fh); - if (resp->status == 0) { - *p++ = htonl(resp->count); - *p++ = htonl(resp->eof); - *p++ = htonl(resp->count); /* xdr opaque count */ - xdr_ressize_check(rqstp, p); - /* now update rqstp->rq_res to reflect data as well */ - rqstp->rq_res.page_len = resp->count; - if (resp->count & 3) { - /* need to pad the tail */ - rqstp->rq_res.tail[0].iov_base = p; - *p = 0; - rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); - } - if (svc_encode_result_payload(rqstp, head->iov_len, - resp->count)) + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) return 0; - return 1; - } else - return xdr_ressize_check(rqstp, p); + if (xdr_stream_encode_u32(xdr, resp->count) < 0) + return 0; + if (xdr_stream_encode_bool(xdr, resp->eof) < 0) + return 0; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) + return 0; + xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, + resp->count); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + } + + return 1; } /* WRITE */ int nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_writeres *resp = rqstp->rq_resp; - *p++ = resp->status; - p = encode_wcc_data(rqstp, p, &resp->fh); - if (resp->status == 0) { - *p++ = htonl(resp->count); - *p++ = htonl(resp->committed); - *p++ = resp->verf[0]; - *p++ = resp->verf[1]; + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) + return 0; + if (xdr_stream_encode_u32(xdr, resp->committed) < 0) + return 0; + if (!svcxdr_encode_writeverf3(xdr, resp->verf)) + return 0; + break; + default: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) + return 0; } - return xdr_ressize_check(rqstp, p); + + return 1; } /* CREATE, MKDIR, SYMLINK, MKNOD */ int nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_diropres *resp = rqstp->rq_resp; - *p++ = resp->status; - if (resp->status == 0) { - *p++ = xdr_one; - p = encode_fh(p, &resp->fh); - p = encode_post_op_attr(rqstp, p, &resp->fh); + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_fh3(xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) + return 0; + break; + default: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) + return 0; } - p = encode_wcc_data(rqstp, p, &resp->dirfh); - return xdr_ressize_check(rqstp, p); + + return 1; } /* RENAME */ int nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_renameres *resp = rqstp->rq_resp; - *p++ = resp->status; - p = encode_wcc_data(rqstp, p, &resp->ffh); - p = encode_wcc_data(rqstp, p, &resp->tfh); - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_nfsstat3(xdr, resp->status) && + svcxdr_encode_wcc_data(rqstp, xdr, &resp->ffh) && + svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh); } /* LINK */ int nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_linkres *resp = rqstp->rq_resp; - *p++ = resp->status; - p = encode_post_op_attr(rqstp, p, &resp->fh); - p = encode_wcc_data(rqstp, p, &resp->tfh); - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_nfsstat3(xdr, resp->status) && + svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh) && + svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh); } /* READDIR */ int nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_readdirres *resp = rqstp->rq_resp; + struct xdr_buf *dirlist = &resp->dirlist; - *p++ = resp->status; - p = encode_post_op_attr(rqstp, p, &resp->fh); - - if (resp->status == 0) { - /* stupid readdir cookie */ - memcpy(p, resp->verf, 8); p += 2; - xdr_ressize_check(rqstp, p); - if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE) - return 1; /*No room for trailer */ - rqstp->rq_res.page_len = (resp->count) << 2; - - /* add the 'tail' to the end of the 'head' page - page 0. */ - rqstp->rq_res.tail[0].iov_base = p; - *p++ = 0; /* no more entries */ - *p++ = htonl(resp->common.err == nfserr_eof); - rqstp->rq_res.tail[0].iov_len = 2<<2; - return 1; - } else - return xdr_ressize_check(rqstp, p); -} - -static __be32 * -encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, - int namlen, u64 ino) -{ - *p++ = xdr_one; /* mark entry present */ - p = xdr_encode_hyper(p, ino); /* file id */ - p = xdr_encode_array(p, name, namlen);/* name length & name */ - - cd->offset = p; /* remember pointer */ - p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */ + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_cookieverf3(xdr, resp->verf)) + return 0; + xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); + /* no more entries */ + if (xdr_stream_encode_item_absent(xdr) < 0) + return 0; + if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + } - return p; + return 1; } static __be32 @@ -957,267 +1122,327 @@ out: return rv; } -static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino) +/** + * nfs3svc_encode_cookie3 - Encode a directory offset cookie + * @resp: readdir result context + * @offset: offset cookie to encode + * + * The buffer space for the offset cookie has already been reserved + * by svcxdr_encode_entry3_common(). + */ +void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset) { - struct svc_fh *fh = &cd->scratch; - __be32 err; - - fh_init(fh, NFS3_FHSIZE); - err = compose_entry_fh(cd, fh, name, namlen, ino); - if (err) { - *p++ = 0; - *p++ = 0; - goto out; - } - p = encode_post_op_attr(cd->rqstp, p, fh); - *p++ = xdr_one; /* yes, a file handle follows */ - p = encode_fh(p, fh); -out: - fh_put(fh); - return p; -} + __be64 cookie = cpu_to_be64(offset); -/* - * Encode a directory entry. This one works for both normal readdir - * and readdirplus. - * The normal readdir reply requires 2 (fileid) + 1 (stringlen) - * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen. - * - * The readdirplus baggage is 1+21 words for post_op_attr, plus the - * file handle. - */ + if (!resp->cookie_offset) + return; + write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie, + sizeof(cookie)); + resp->cookie_offset = 0; +} -#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1) -#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) -static int -encode_entry(struct readdir_cd *ccd, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type, int plus) +static bool +svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name, + int namlen, loff_t offset, u64 ino) { - struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, - common); - __be32 *p = cd->buffer; - caddr_t curr_page_addr = NULL; - struct page ** page; - int slen; /* string (name) length */ - int elen; /* estimated entry length in words */ - int num_entry_words = 0; /* actual number of words */ - - if (cd->offset) { - u64 offset64 = offset; - - if (unlikely(cd->offset1)) { - /* we ended up with offset on a page boundary */ - *cd->offset = htonl(offset64 >> 32); - *cd->offset1 = htonl(offset64 & 0xffffffff); - cd->offset1 = NULL; - } else { - xdr_encode_hyper(cd->offset, offset64); - } - cd->offset = NULL; - } + struct xdr_buf *dirlist = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; - /* - dprintk("encode_entry(%.*s @%ld%s)\n", - namlen, name, (long) offset, plus? " plus" : ""); - */ - - /* truncate filename if too long */ - namlen = min(namlen, NFS3_MAXNAMLEN); + if (xdr_stream_encode_item_present(xdr) < 0) + return false; + /* fileid */ + if (xdr_stream_encode_u64(xdr, ino) < 0) + return false; + /* name */ + if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS3_MAXNAMLEN)) < 0) + return false; + /* cookie */ + resp->cookie_offset = dirlist->len; + if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0) + return false; - slen = XDR_QUADLEN(namlen); - elen = slen + NFS3_ENTRY_BAGGAGE - + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0); + return true; +} - if (cd->buflen < elen) { - cd->common.err = nfserr_toosmall; - return -EINVAL; - } +/** + * nfs3svc_encode_entry3 - encode one NFSv3 READDIR entry + * @data: directory context + * @name: name of the object to be encoded + * @namlen: length of that name, in bytes + * @offset: the offset of the previous entry + * @ino: the fileid of this entry + * @d_type: unused + * + * Return values: + * %0: Entry was successfully encoded. + * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err + * + * On exit, the following fields are updated: + * - resp->xdr + * - resp->common.err + * - resp->cookie_offset + */ +int nfs3svc_encode_entry3(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct readdir_cd *ccd = data; + struct nfsd3_readdirres *resp = container_of(ccd, + struct nfsd3_readdirres, + common); + unsigned int starting_length = resp->dirlist.len; - /* determine which page in rq_respages[] we are currently filling */ - for (page = cd->rqstp->rq_respages + 1; - page < cd->rqstp->rq_next_page; page++) { - curr_page_addr = page_address(*page); + /* The offset cookie for the previous entry */ + nfs3svc_encode_cookie3(resp, offset); - if (((caddr_t)cd->buffer >= curr_page_addr) && - ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE)) - break; - } + if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino)) + goto out_toosmall; - if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) { - /* encode entry in current page */ + xdr_commit_encode(&resp->xdr); + resp->common.err = nfs_ok; + return 0; - p = encode_entry_baggage(cd, p, name, namlen, ino); +out_toosmall: + resp->cookie_offset = 0; + resp->common.err = nfserr_toosmall; + resp->dirlist.len = starting_length; + return -EINVAL; +} - if (plus) - p = encode_entryplus_baggage(cd, p, name, namlen, ino); - num_entry_words = p - cd->buffer; - } else if (*(page+1) != NULL) { - /* temporarily encode entry into next page, then move back to - * current and next page in rq_respages[] */ - __be32 *p1, *tmp; - int len1, len2; +static bool +svcxdr_encode_entry3_plus(struct nfsd3_readdirres *resp, const char *name, + int namlen, u64 ino) +{ + struct xdr_stream *xdr = &resp->xdr; + struct svc_fh *fhp = &resp->scratch; + bool result; - /* grab next page for temporary storage of entry */ - p1 = tmp = page_address(*(page+1)); + result = false; + fh_init(fhp, NFS3_FHSIZE); + if (compose_entry_fh(resp, fhp, name, namlen, ino) != nfs_ok) + goto out_noattrs; - p1 = encode_entry_baggage(cd, p1, name, namlen, ino); + if (!svcxdr_encode_post_op_attr(resp->rqstp, xdr, fhp)) + goto out; + if (!svcxdr_encode_post_op_fh3(xdr, fhp)) + goto out; + result = true; - if (plus) - p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino); +out: + fh_put(fhp); + return result; - /* determine entry word length and lengths to go in pages */ - num_entry_words = p1 - tmp; - len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer; - if ((num_entry_words << 2) < len1) { - /* the actual number of words in the entry is less - * than elen and can still fit in the current page - */ - memmove(p, tmp, num_entry_words << 2); - p += num_entry_words; - - /* update offset */ - cd->offset = cd->buffer + (cd->offset - tmp); - } else { - unsigned int offset_r = (cd->offset - tmp) << 2; - - /* update pointer to offset location. - * This is a 64bit quantity, so we need to - * deal with 3 cases: - * - entirely in first page - * - entirely in second page - * - 4 bytes in each page - */ - if (offset_r + 8 <= len1) { - cd->offset = p + (cd->offset - tmp); - } else if (offset_r >= len1) { - cd->offset -= len1 >> 2; - } else { - /* sitting on the fence */ - BUG_ON(offset_r != len1 - 4); - cd->offset = p + (cd->offset - tmp); - cd->offset1 = tmp; - } - - len2 = (num_entry_words << 2) - len1; - - /* move from temp page to current and next pages */ - memmove(p, tmp, len1); - memmove(tmp, (caddr_t)tmp+len1, len2); - - p = tmp + (len2 >> 2); - } - } - else { - cd->common.err = nfserr_toosmall; - return -EINVAL; - } +out_noattrs: + if (xdr_stream_encode_item_absent(xdr) < 0) + return false; + if (xdr_stream_encode_item_absent(xdr) < 0) + return false; + return true; +} - cd->buflen -= num_entry_words; - cd->buffer = p; - cd->common.err = nfs_ok; +/** + * nfs3svc_encode_entryplus3 - encode one NFSv3 READDIRPLUS entry + * @data: directory context + * @name: name of the object to be encoded + * @namlen: length of that name, in bytes + * @offset: the offset of the previous entry + * @ino: the fileid of this entry + * @d_type: unused + * + * Return values: + * %0: Entry was successfully encoded. + * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err + * + * On exit, the following fields are updated: + * - resp->xdr + * - resp->common.err + * - resp->cookie_offset + */ +int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct readdir_cd *ccd = data; + struct nfsd3_readdirres *resp = container_of(ccd, + struct nfsd3_readdirres, + common); + unsigned int starting_length = resp->dirlist.len; + + /* The offset cookie for the previous entry */ + nfs3svc_encode_cookie3(resp, offset); + + if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino)) + goto out_toosmall; + if (!svcxdr_encode_entry3_plus(resp, name, namlen, ino)) + goto out_toosmall; + + xdr_commit_encode(&resp->xdr); + resp->common.err = nfs_ok; return 0; +out_toosmall: + resp->cookie_offset = 0; + resp->common.err = nfserr_toosmall; + resp->dirlist.len = starting_length; + return -EINVAL; } -int -nfs3svc_encode_entry(void *cd, const char *name, - int namlen, loff_t offset, u64 ino, unsigned int d_type) +static bool +svcxdr_encode_fsstat3resok(struct xdr_stream *xdr, + const struct nfsd3_fsstatres *resp) { - return encode_entry(cd, name, namlen, offset, ino, d_type, 0); -} + const struct kstatfs *s = &resp->stats; + u64 bs = s->f_bsize; + __be32 *p; -int -nfs3svc_encode_entry_plus(void *cd, const char *name, - int namlen, loff_t offset, u64 ino, - unsigned int d_type) -{ - return encode_entry(cd, name, namlen, offset, ino, d_type, 1); + p = xdr_reserve_space(xdr, XDR_UNIT * 13); + if (!p) + return false; + p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ + p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ + p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ + p = xdr_encode_hyper(p, s->f_files); /* total inodes */ + p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ + p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ + *p = cpu_to_be32(resp->invarsec); /* mean unchanged time */ + + return true; } /* FSSTAT */ int nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_fsstatres *resp = rqstp->rq_resp; - struct kstatfs *s = &resp->stats; - u64 bs = s->f_bsize; - - *p++ = resp->status; - *p++ = xdr_zero; /* no post_op_attr */ - - if (resp->status == 0) { - p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ - p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ - p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ - p = xdr_encode_hyper(p, s->f_files); /* total inodes */ - p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ - p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ - *p++ = htonl(resp->invarsec); /* mean unchanged time */ + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) + return 0; + if (!svcxdr_encode_fsstat3resok(xdr, resp)) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) + return 0; } - return xdr_ressize_check(rqstp, p); + + return 1; +} + +static bool +svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr, + const struct nfsd3_fsinfores *resp) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT * 12); + if (!p) + return false; + *p++ = cpu_to_be32(resp->f_rtmax); + *p++ = cpu_to_be32(resp->f_rtpref); + *p++ = cpu_to_be32(resp->f_rtmult); + *p++ = cpu_to_be32(resp->f_wtmax); + *p++ = cpu_to_be32(resp->f_wtpref); + *p++ = cpu_to_be32(resp->f_wtmult); + *p++ = cpu_to_be32(resp->f_dtpref); + p = xdr_encode_hyper(p, resp->f_maxfilesize); + p = encode_nfstime3(p, &nfs3svc_time_delta); + *p = cpu_to_be32(resp->f_properties); + + return true; } /* FSINFO */ int nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_fsinfores *resp = rqstp->rq_resp; - *p++ = resp->status; - *p++ = xdr_zero; /* no post_op_attr */ - - if (resp->status == 0) { - *p++ = htonl(resp->f_rtmax); - *p++ = htonl(resp->f_rtpref); - *p++ = htonl(resp->f_rtmult); - *p++ = htonl(resp->f_wtmax); - *p++ = htonl(resp->f_wtpref); - *p++ = htonl(resp->f_wtmult); - *p++ = htonl(resp->f_dtpref); - p = xdr_encode_hyper(p, resp->f_maxfilesize); - *p++ = xdr_one; - *p++ = xdr_zero; - *p++ = htonl(resp->f_properties); + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) + return 0; + if (!svcxdr_encode_fsinfo3resok(xdr, resp)) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) + return 0; } - return xdr_ressize_check(rqstp, p); + return 1; +} + +static bool +svcxdr_encode_pathconf3resok(struct xdr_stream *xdr, + const struct nfsd3_pathconfres *resp) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT * 6); + if (!p) + return false; + *p++ = cpu_to_be32(resp->p_link_max); + *p++ = cpu_to_be32(resp->p_name_max); + p = xdr_encode_bool(p, resp->p_no_trunc); + p = xdr_encode_bool(p, resp->p_chown_restricted); + p = xdr_encode_bool(p, resp->p_case_insensitive); + xdr_encode_bool(p, resp->p_case_preserving); + + return true; } /* PATHCONF */ int nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_pathconfres *resp = rqstp->rq_resp; - *p++ = resp->status; - *p++ = xdr_zero; /* no post_op_attr */ - - if (resp->status == 0) { - *p++ = htonl(resp->p_link_max); - *p++ = htonl(resp->p_name_max); - *p++ = htonl(resp->p_no_trunc); - *p++ = htonl(resp->p_chown_restricted); - *p++ = htonl(resp->p_case_insensitive); - *p++ = htonl(resp->p_case_preserving); + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) + return 0; + if (!svcxdr_encode_pathconf3resok(xdr, resp)) + return 0; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) + return 0; } - return xdr_ressize_check(rqstp, p); + return 1; } /* COMMIT */ int nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd3_commitres *resp = rqstp->rq_resp; - *p++ = resp->status; - p = encode_wcc_data(rqstp, p, &resp->fh); - /* Write verifier */ - if (resp->status == 0) { - *p++ = resp->verf[0]; - *p++ = resp->verf[1]; + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_writeverf3(xdr, resp->verf)) + return 0; + break; + default: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) + return 0; } - return xdr_ressize_check(rqstp, p); + + return 1; } /* diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index dd9f38d072dd6ecd04fe7aa92e24290e45dab1db..daf43b980d4b90a999534f0f50a4e3a055a5d538 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1383,10 +1383,13 @@ static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) { ssize_t bytes_copied = 0; - size_t bytes_total = copy->cp_count; + u64 bytes_total = copy->cp_count; u64 src_pos = copy->cp_src_pos; u64 dst_pos = copy->cp_dst_pos; + /* See RFC 7862 p.67: */ + if (bytes_total == 0) + bytes_total = ULLONG_MAX; do { if (kthread_should_stop()) break; @@ -1538,8 +1541,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!nfs4_init_copy_state(nn, copy)) goto out_err; refcount_set(&async_copy->refcount, 1); - memcpy(©->cp_res.cb_stateid, ©->cp_stateid, - sizeof(copy->cp_stateid)); + memcpy(©->cp_res.cb_stateid, ©->cp_stateid.stid, + sizeof(copy->cp_res.cb_stateid)); dup_copy_fields(copy, async_copy); async_copy->copy_task = kthread_create(nfsd4_do_async_copy, async_copy, "%s", "copy thread"); @@ -2262,25 +2265,6 @@ static bool need_wrongsec_check(struct svc_rqst *rqstp) return !(nextd->op_flags & OP_HANDLES_WRONGSEC); } -static void svcxdr_init_encode(struct svc_rqst *rqstp, - struct nfsd4_compoundres *resp) -{ - struct xdr_stream *xdr = &resp->xdr; - struct xdr_buf *buf = &rqstp->rq_res; - struct kvec *head = buf->head; - - xdr->buf = buf; - xdr->iov = head; - xdr->p = head->iov_base + head->iov_len; - xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack; - /* Tail and page_len should be zero at this point: */ - buf->len = buf->head[0].iov_len; - xdr_reset_scratch_buffer(xdr); - xdr->page_ptr = buf->pages - 1; - buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages) - - rqstp->rq_auth_slack; -} - #ifdef CONFIG_NFSD_V4_2_INTER_SSC static void check_if_stalefh_allowed(struct nfsd4_compoundargs *args) @@ -2335,10 +2319,14 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); __be32 status; - svcxdr_init_encode(rqstp, resp); - resp->tagp = resp->xdr.p; + resp->xdr = &rqstp->rq_res_stream; + + /* reserve space for: NFS status code */ + xdr_reserve_space(resp->xdr, XDR_UNIT); + + resp->tagp = resp->xdr->p; /* reserve space for: taglen, tag, and opcnt */ - xdr_reserve_space(&resp->xdr, 8 + args->taglen); + xdr_reserve_space(resp->xdr, XDR_UNIT * 2 + args->taglen); resp->taglen = args->taglen; resp->tag = args->tag; resp->rqstp = rqstp; @@ -2444,7 +2432,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) encode_op: if (op->status == nfserr_replay_me) { op->replay = &cstate->replay_owner->so_replay; - nfsd4_encode_replay(&resp->xdr, op); + nfsd4_encode_replay(resp->xdr, op); status = op->status = op->replay->rp_status; } else { nfsd4_encode_operation(resp, op); diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 891395c6c7d3dd62c2f38ca4b0ef53b7693a6a9f..6fedc49726bf7c7b1d27ff692c3913fefbb1ccc9 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -626,7 +626,7 @@ nfsd4_legacy_tracking_init(struct net *net) status = nfsd4_load_reboot_recovery_data(net); if (status) goto err; - printk("NFSD: Using legacy client tracking operations.\n"); + pr_info("NFSD: Using legacy client tracking operations.\n"); return 0; err: @@ -1028,7 +1028,7 @@ nfsd4_init_cld_pipe(struct net *net) status = __nfsd4_init_cld_pipe(net); if (!status) - printk("NFSD: Using old nfsdcld client tracking operations.\n"); + pr_info("NFSD: Using old nfsdcld client tracking operations.\n"); return status; } @@ -1605,7 +1605,7 @@ nfsd4_cld_tracking_init(struct net *net) nfs4_release_reclaim(nn); goto err_remove; } else - printk("NFSD: Using nfsdcld client tracking operations.\n"); + pr_info("NFSD: Using nfsdcld client tracking operations.\n"); return 0; err_remove: @@ -1864,7 +1864,7 @@ nfsd4_umh_cltrack_init(struct net *net) ret = nfsd4_umh_cltrack_upcall("init", NULL, grace_start, NULL); kfree(grace_start); if (!ret) - printk("NFSD: Using UMH upcall client tracking operations.\n"); + pr_info("NFSD: Using UMH upcall client tracking operations.\n"); return ret; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 97447a64bad0bf6d423403774f48ccf84dcd12fc..7698172ac0c7619319393ed03c56b511f453d14e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -43,6 +43,7 @@ #include <linux/sunrpc/addr.h> #include <linux/jhash.h> #include <linux/string_helpers.h> +#include <linux/fsnotify.h> #include "xdr4.h" #include "xdr4cb.h" #include "vfs.h" @@ -2352,6 +2353,10 @@ static int client_info_show(struct seq_file *m, void *v) memcpy(&clid, &clp->cl_clientid, sizeof(clid)); seq_printf(m, "clientid: 0x%llx\n", clid); seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); + if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) + seq_puts(m, "status: confirmed\n"); + else + seq_puts(m, "status: unconfirmed\n"); seq_printf(m, "name: "); seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); @@ -2702,6 +2707,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, int ret; struct net *net = SVC_NET(rqstp); struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct dentry *dentries[ARRAY_SIZE(client_files)]; clp = alloc_client(name); if (clp == NULL) @@ -2721,9 +2727,11 @@ static struct nfs4_client *create_client(struct xdr_netobj name, memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); clp->cl_cb_session = NULL; clp->net = net; - clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs, - clp->cl_clientid.cl_id - nn->clientid_base, - client_files); + clp->cl_nfsd_dentry = nfsd_client_mkdir( + nn, &clp->cl_nfsdfs, + clp->cl_clientid.cl_id - nn->clientid_base, + client_files, dentries); + clp->cl_nfsd_info_dentry = dentries[0]; if (!clp->cl_nfsd_dentry) { free_client(clp); return NULL; @@ -2798,7 +2806,10 @@ move_to_confirmed(struct nfs4_client *clp) list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); add_clp_to_name_tree(clp, &nn->conf_name_tree); - set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); + if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags) && + clp->cl_nfsd_dentry && + clp->cl_nfsd_info_dentry) + fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); renew_client_locked(clp); } @@ -2903,7 +2914,7 @@ out_err: static void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) { - struct xdr_buf *buf = resp->xdr.buf; + struct xdr_buf *buf = resp->xdr->buf; struct nfsd4_slot *slot = resp->cstate.slot; unsigned int base; @@ -2973,7 +2984,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, struct nfsd4_sequence *seq) { struct nfsd4_slot *slot = resp->cstate.slot; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; __be32 status; @@ -3708,7 +3719,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct nfsd4_sequence *seq = &u->sequence; struct nfsd4_compoundres *resp = rqstp->rq_resp; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct nfsd4_session *session; struct nfs4_client *clp; struct nfsd4_slot *slot; @@ -5338,6 +5349,22 @@ static bool clients_still_reclaiming(struct nfsd_net *nn) return true; } +struct laundry_time { + time64_t cutoff; + time64_t new_timeo; +}; + +static bool state_expired(struct laundry_time *lt, time64_t last_refresh) +{ + time64_t time_remaining; + + if (last_refresh < lt->cutoff) + return true; + time_remaining = last_refresh - lt->cutoff; + lt->new_timeo = min(lt->new_timeo, time_remaining); + return false; +} + static time64_t nfs4_laundromat(struct nfsd_net *nn) { @@ -5347,14 +5374,16 @@ nfs4_laundromat(struct nfsd_net *nn) struct nfs4_ol_stateid *stp; struct nfsd4_blocked_lock *nbl; struct list_head *pos, *next, reaplist; - time64_t cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease; - time64_t t, new_timeo = nn->nfsd4_lease; + struct laundry_time lt = { + .cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease, + .new_timeo = nn->nfsd4_lease + }; struct nfs4_cpntf_state *cps; copy_stateid_t *cps_t; int i; if (clients_still_reclaiming(nn)) { - new_timeo = 0; + lt.new_timeo = 0; goto out; } nfsd4_end_grace(nn); @@ -5364,7 +5393,7 @@ nfs4_laundromat(struct nfsd_net *nn) idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && - cps->cpntf_time < cutoff) + state_expired(<, cps->cpntf_time)) _free_cpntf_state_locked(nn, cps); } spin_unlock(&nn->s2s_cp_lock); @@ -5372,11 +5401,8 @@ nfs4_laundromat(struct nfsd_net *nn) spin_lock(&nn->client_lock); list_for_each_safe(pos, next, &nn->client_lru) { clp = list_entry(pos, struct nfs4_client, cl_lru); - if (clp->cl_time > cutoff) { - t = clp->cl_time - cutoff; - new_timeo = min(new_timeo, t); + if (!state_expired(<, clp->cl_time)) break; - } if (mark_client_expired_locked(clp)) { trace_nfsd_clid_expired(&clp->cl_clientid); continue; @@ -5393,11 +5419,8 @@ nfs4_laundromat(struct nfsd_net *nn) spin_lock(&state_lock); list_for_each_safe(pos, next, &nn->del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); - if (dp->dl_time > cutoff) { - t = dp->dl_time - cutoff; - new_timeo = min(new_timeo, t); + if (!state_expired(<, dp->dl_time)) break; - } WARN_ON(!unhash_delegation_locked(dp)); list_add(&dp->dl_recall_lru, &reaplist); } @@ -5413,11 +5436,8 @@ nfs4_laundromat(struct nfsd_net *nn) while (!list_empty(&nn->close_lru)) { oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, oo_close_lru); - if (oo->oo_time > cutoff) { - t = oo->oo_time - cutoff; - new_timeo = min(new_timeo, t); + if (!state_expired(<, oo->oo_time)) break; - } list_del_init(&oo->oo_close_lru); stp = oo->oo_last_closed_stid; oo->oo_last_closed_stid = NULL; @@ -5443,11 +5463,8 @@ nfs4_laundromat(struct nfsd_net *nn) while (!list_empty(&nn->blocked_locks_lru)) { nbl = list_first_entry(&nn->blocked_locks_lru, struct nfsd4_blocked_lock, nbl_lru); - if (nbl->nbl_time > cutoff) { - t = nbl->nbl_time - cutoff; - new_timeo = min(new_timeo, t); + if (!state_expired(<, nbl->nbl_time)) break; - } list_move(&nbl->nbl_lru, &reaplist); list_del_init(&nbl->nbl_list); } @@ -5460,8 +5477,7 @@ nfs4_laundromat(struct nfsd_net *nn) free_blocked_lock(nbl); } out: - new_timeo = max_t(time64_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); - return new_timeo; + return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); } static struct workqueue_struct *laundry_wq; @@ -7321,14 +7337,9 @@ nfs4_state_start_net(struct net *net) struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; - ret = get_nfsdfs(net); - if (ret) - return ret; ret = nfs4_state_create_net(net); - if (ret) { - mntput(nn->nfsd_mnt); + if (ret) return ret; - } locks_start_grace(net, &nn->nfsd4_manager); nfsd4_client_tracking_init(net); if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) @@ -7398,7 +7409,6 @@ nfs4_state_shutdown_net(struct net *net) nfsd4_client_tracking_exit(net); nfs4_state_destroy_net(net); - mntput(nn->nfsd_mnt); } void diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index eaaa1605b5b5f38a51065a8bcc21ebc76d5a0190..e0f06d3cbd44d0b96fb6176207d643006200af40 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3581,7 +3581,7 @@ nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid) static __be32 nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 8); @@ -3594,7 +3594,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8); @@ -3611,7 +3611,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, static __be32 nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_encode_stateid(xdr, &close->cl_stateid); } @@ -3620,7 +3620,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c static __be32 nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); @@ -3634,7 +3634,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ static __be32 nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 20); @@ -3649,7 +3649,7 @@ static __be32 nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) { struct svc_fh *fhp = getattr->ga_fhp; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry, getattr->ga_bmval, resp->rqstp, 0); @@ -3658,7 +3658,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 static __be32 nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct svc_fh *fhp = *fhpp; unsigned int len; __be32 *p; @@ -3713,7 +3713,7 @@ again: static __be32 nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; if (!nfserr) nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); @@ -3726,7 +3726,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo static __be32 nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; if (nfserr == nfserr_denied) nfsd4_encode_lock_denied(xdr, &lockt->lt_denied); @@ -3736,7 +3736,7 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l static __be32 nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_encode_stateid(xdr, &locku->lu_stateid); } @@ -3745,7 +3745,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l static __be32 nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 20); @@ -3759,7 +3759,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li static __be32 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid); @@ -3853,7 +3853,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op static __be32 nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid); } @@ -3861,7 +3861,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct static __be32 nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_encode_stateid(xdr, &od->od_stateid); } @@ -3871,7 +3871,7 @@ static __be32 nfsd4_encode_splice_read( struct nfsd4_read *read, struct file *file, unsigned long maxcount) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct xdr_buf *buf = xdr->buf; int status, space_left; u32 eof; @@ -3937,7 +3937,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, struct nfsd4_read *read, struct file *file, unsigned long maxcount) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; u32 eof; int starting_len = xdr->buf->len - 8; __be32 nfserr; @@ -3976,7 +3976,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read) { unsigned long maxcount; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct file *file; int starting_len = xdr->buf->len; __be32 *p; @@ -3990,7 +3990,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)); return nfserr_resource; } - if (resp->xdr.buf->page_len && + if (resp->xdr->buf->page_len && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) { WARN_ON_ONCE(1); return nfserr_resource; @@ -4020,7 +4020,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd int maxcount; __be32 wire_count; int zero = 0; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; int length_offset = xdr->buf->len; int status; __be32 *p; @@ -4072,7 +4072,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 int bytes_left; loff_t offset; __be64 wire_offset; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; int starting_len = xdr->buf->len; __be32 *p; @@ -4083,8 +4083,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ *p++ = cpu_to_be32(0); *p++ = cpu_to_be32(0); - resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p) - - (char *)resp->xdr.buf->head[0].iov_base; + xdr->buf->head[0].iov_len = (char *)xdr->p - + (char *)xdr->buf->head[0].iov_base; /* * Number of bytes left for directory entries allowing for the @@ -4159,7 +4159,7 @@ err_no_verf: static __be32 nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 20); @@ -4172,7 +4172,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ static __be32 nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 40); @@ -4255,7 +4255,7 @@ static __be32 nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_secinfo *secinfo) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp); } @@ -4264,7 +4264,7 @@ static __be32 nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_secinfo_no_name *secinfo) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp); } @@ -4276,7 +4276,7 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, static __be32 nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 16); @@ -4300,7 +4300,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 static __be32 nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; if (!nfserr) { @@ -4324,7 +4324,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n static __be32 nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 16); @@ -4341,7 +4341,7 @@ static __be32 nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_exchange_id *exid) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; char *major_id; char *server_scope; @@ -4419,7 +4419,7 @@ static __be32 nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create_session *sess) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 24); @@ -4472,7 +4472,7 @@ static __be32 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_sequence *seq) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20); @@ -4495,7 +4495,7 @@ static __be32 nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_test_stateid *test_stateid) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct nfsd4_test_stateid_id *stateid, *next; __be32 *p; @@ -4516,7 +4516,7 @@ static __be32 nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getdeviceinfo *gdev) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; const struct nfsd4_layout_ops *ops; u32 starting_len = xdr->buf->len, needed_len; __be32 *p; @@ -4572,7 +4572,7 @@ static __be32 nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_layoutget *lgp) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; const struct nfsd4_layout_ops *ops; __be32 *p; @@ -4599,7 +4599,7 @@ static __be32 nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_layoutcommit *lcp) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 4); @@ -4620,7 +4620,7 @@ static __be32 nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_layoutreturn *lrp) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 4); @@ -4638,7 +4638,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, struct nfsd42_write_res *write, bool sync) { __be32 *p; - p = xdr_reserve_space(&resp->xdr, 4); + p = xdr_reserve_space(resp->xdr, 4); if (!p) return nfserr_resource; @@ -4647,11 +4647,11 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, else { __be32 nfserr; *p++ = cpu_to_be32(1); - nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid); + nfserr = nfsd4_encode_stateid(resp->xdr, &write->cb_stateid); if (nfserr) return nfserr; } - p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE); + p = xdr_reserve_space(resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE); if (!p) return nfserr_resource; @@ -4665,7 +4665,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, static __be32 nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct nfs42_netaddr *addr; __be32 *p; @@ -4713,7 +4713,7 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, if (nfserr) return nfserr; - p = xdr_reserve_space(&resp->xdr, 4 + 4); + p = xdr_reserve_space(resp->xdr, 4 + 4); *p++ = xdr_one; /* cr_consecutive */ *p++ = cpu_to_be32(copy->cp_synchronous); return 0; @@ -4723,7 +4723,7 @@ static __be32 nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_offload_status *os) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 8 + 4); @@ -4740,7 +4740,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, unsigned long *maxcount, u32 *eof, loff_t *pos) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct file *file = read->rd_nf->nf_file; int starting_len = xdr->buf->len; loff_t hole_pos; @@ -4799,7 +4799,7 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, count = data_pos - read->rd_offset; /* Content type, offset, byte count */ - p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); + p = xdr_reserve_space(resp->xdr, 4 + 8 + 8); if (!p) return nfserr_resource; @@ -4817,7 +4817,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read) { unsigned long maxcount, count; - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct file *file; int starting_len = xdr->buf->len; int last_segment = xdr->buf->len; @@ -4888,7 +4888,7 @@ static __be32 nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_copy_notify *cn) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; if (nfserr) @@ -4924,7 +4924,7 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, { __be32 *p; - p = xdr_reserve_space(&resp->xdr, 4 + 8); + p = xdr_reserve_space(resp->xdr, 4 + 8); *p++ = cpu_to_be32(seek->seek_eof); p = xdr_encode_hyper(p, seek->seek_pos); @@ -4985,7 +4985,7 @@ static __be32 nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getxattr *getxattr) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p, err; p = xdr_reserve_space(xdr, 4); @@ -5009,7 +5009,7 @@ static __be32 nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setxattr *setxattr) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 20); @@ -5050,7 +5050,7 @@ static __be32 nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_listxattrs *listxattrs) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; u32 cookie_offset, count_offset, eof; u32 left, xdrleft, slen, count; u32 xdrlen, offset; @@ -5161,7 +5161,7 @@ static __be32 nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_removexattr *removexattr) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; __be32 *p; p = xdr_reserve_space(xdr, 20); @@ -5301,7 +5301,7 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) void nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) { - struct xdr_stream *xdr = &resp->xdr; + struct xdr_stream *xdr = resp->xdr; struct nfs4_stateowner *so = resp->cstate.replay_owner; struct svc_rqst *rqstp = resp->rqstp; const struct nfsd4_operation *opdesc = op->opdesc; @@ -5430,14 +5430,14 @@ int nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd4_compoundres *resp = rqstp->rq_resp; - struct xdr_buf *buf = resp->xdr.buf; + struct xdr_buf *buf = resp->xdr->buf; WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len); *p = resp->cstate.status; - rqstp->rq_next_page = resp->xdr.page_ptr + 1; + rqstp->rq_next_page = resp->xdr->page_ptr + 1; p = resp->tagp; *p++ = htonl(resp->taglen); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index ef86ed23af8281e48f5b3219436a65836935fca0..853bf50a2a9bba548fd3bd9736514a38e02bdfaa 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1266,7 +1266,8 @@ static void nfsdfs_remove_files(struct dentry *root) /* XXX: cut'n'paste from simple_fill_super; figure out if we could share * code instead. */ static int nfsdfs_create_files(struct dentry *root, - const struct tree_descr *files) + const struct tree_descr *files, + struct dentry **fdentries) { struct inode *dir = d_inode(root); struct inode *inode; @@ -1275,8 +1276,6 @@ static int nfsdfs_create_files(struct dentry *root, inode_lock(dir); for (i = 0; files->name && files->name[0]; i++, files++) { - if (!files->name) - continue; dentry = d_alloc_name(root, files->name); if (!dentry) goto out; @@ -1290,6 +1289,8 @@ static int nfsdfs_create_files(struct dentry *root, inode->i_private = __get_nfsdfs_client(dir); d_add(dentry, inode); fsnotify_create(dir, dentry); + if (fdentries) + fdentries[i] = dentry; } inode_unlock(dir); return 0; @@ -1301,8 +1302,9 @@ out: /* on success, returns positive number unique to that client. */ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, - struct nfsdfs_client *ncl, u32 id, - const struct tree_descr *files) + struct nfsdfs_client *ncl, u32 id, + const struct tree_descr *files, + struct dentry **fdentries) { struct dentry *dentry; char name[11]; @@ -1313,7 +1315,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); if (IS_ERR(dentry)) /* XXX: tossing errors? */ return NULL; - ret = nfsdfs_create_files(dentry, files); + ret = nfsdfs_create_files(dentry, files, fdentries); if (ret) { nfsd_client_rmdir(dentry); return NULL; @@ -1416,6 +1418,8 @@ static void nfsd_umount(struct super_block *sb) { struct net *net = sb->s_fs_info; + nfsd_shutdown_threads(net); + kill_litter_super(sb); put_net(net); } @@ -1428,18 +1432,6 @@ static struct file_system_type nfsd_fs_type = { }; MODULE_ALIAS_FS("nfsd"); -int get_nfsdfs(struct net *net) -{ - struct nfsd_net *nn = net_generic(net, nfsd_net_id); - struct vfsmount *mnt; - - mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL); - if (IS_ERR(mnt)) - return PTR_ERR(mnt); - nn->nfsd_mnt = mnt; - return 0; -} - #ifdef CONFIG_PROC_FS static int create_proc_exports_entry(void) { diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 8bdc37aa2c2e4c80b4d2bba65dc4dad8b0be6488..14dbfa75059d53a27c7dd7d91b23480bf6d7ea3d 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -93,13 +93,12 @@ int nfsd_get_nrthreads(int n, int *, struct net *); int nfsd_set_nrthreads(int n, int *, struct net *); int nfsd_pool_stats_open(struct inode *, struct file *); int nfsd_pool_stats_release(struct inode *, struct file *); +void nfsd_shutdown_threads(struct net *net); void nfsd_destroy(struct net *net); bool i_am_nfsd(void); -int get_nfsdfs(struct net *); - struct nfsdfs_client { struct kref cl_ref; void (*cl_release)(struct kref *kref); @@ -107,7 +106,9 @@ struct nfsdfs_client { struct nfsdfs_client *get_nfsdfs_client(struct inode *); struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, - struct nfsdfs_client *ncl, u32 id, const struct tree_descr *); + struct nfsdfs_client *ncl, u32 id, + const struct tree_descr *, + struct dentry **fdentries); void nfsd_client_rmdir(struct dentry *dentry); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 10b44421eacec3172d6e79d84769406be8b122bf..c475d2271f9c503bb05e4073ba6661ebb8371e38 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -711,7 +711,7 @@ char * SVCFH_fmt(struct svc_fh *fhp) return buf; } -enum fsid_source fsid_source(struct svc_fh *fhp) +enum fsid_source fsid_source(const struct svc_fh *fhp) { if (fhp->fh_handle.fh_version != 1) return FSIDSOURCE_DEV; diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index f58933519f3806d159939d0295f3f9601aa38625..aff2cda5c6c3372b616bead9e5a90cd7e40b5197 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -82,7 +82,7 @@ enum fsid_source { FSIDSOURCE_FSID, FSIDSOURCE_UUID, }; -extern enum fsid_source fsid_source(struct svc_fh *fhp); +extern enum fsid_source fsid_source(const struct svc_fh *fhp); /* diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index a8d5449dd0e922d9a8a5b55ec1cdcbdb37dc76e3..60d7c59e7935cc7424be1e6efb8f0360b2e669a8 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -151,13 +151,14 @@ nfsd_proc_readlink(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_readlinkres *resp = rqstp->rq_resp; - char *buffer = page_address(*(rqstp->rq_next_page++)); dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); /* Read the symlink. */ resp->len = NFS_MAXPATHLEN; - resp->status = nfsd_readlink(rqstp, &argp->fh, buffer, &resp->len); + resp->page = *(rqstp->rq_next_page++); + resp->status = nfsd_readlink(rqstp, &argp->fh, + page_address(resp->page), &resp->len); fh_put(&argp->fh); return rpc_success; @@ -184,6 +185,7 @@ nfsd_proc_read(struct svc_rqst *rqstp) v = 0; len = argp->count; + resp->pages = rqstp->rq_next_page; while (len > 0) { struct page *page = *(rqstp->rq_next_page++); @@ -381,7 +383,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) /* Make sure the type and device matches */ resp->status = nfserr_exist; - if (inode && type != (inode->i_mode & S_IFMT)) + if (inode && inode_wrong_type(inode, type)) goto out_unlock; } @@ -557,14 +559,27 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, struct nfsd_readdirres *resp, int count) { + struct xdr_buf *buf = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; + count = min_t(u32, count, PAGE_SIZE); - /* Convert byte count to number of words (i.e. >> 2), - * and reserve room for the NULL ptr & eof flag (-2 words) */ - resp->buflen = (count >> 2) - 2; + memset(buf, 0, sizeof(*buf)); - resp->buffer = page_address(*rqstp->rq_next_page); + /* Reserve room for the NULL ptr & eof flag (-2 words) */ + buf->buflen = count - sizeof(__be32) * 2; + buf->pages = rqstp->rq_next_page; rqstp->rq_next_page++; + + /* This is xdr_init_encode(), but it assumes that + * the head kvec has already been consumed. */ + xdr_set_scratch_buffer(xdr, NULL, 0); + xdr->buf = buf; + xdr->page_ptr = buf->pages; + xdr->iov = NULL; + xdr->p = page_address(*buf->pages); + xdr->end = xdr->p + (PAGE_SIZE >> 2); + xdr->rqst = NULL; } /* @@ -576,25 +591,19 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) struct nfsd_readdirargs *argp = rqstp->rq_argp; struct nfsd_readdirres *resp = rqstp->rq_resp; loff_t offset; - __be32 *buffer; dprintk("nfsd: READDIR %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), argp->count, argp->cookie); nfsd_init_dirlist_pages(rqstp, resp, argp->count); - buffer = resp->buffer; - resp->offset = NULL; resp->common.err = nfs_ok; - /* Read directory and encode entries on the fly */ + resp->cookie_offset = 0; offset = argp->cookie; resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, &resp->common, nfssvc_encode_entry); - - resp->count = resp->buffer - buffer; - if (resp->offset) - *resp->offset = htonl(offset); + nfssvc_encode_nfscookie(resp, offset); fh_put(&argp->fh); return rpc_success; @@ -640,7 +649,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_GETATTR] = { .pc_func = nfsd_proc_getattr, .pc_decode = nfssvc_decode_fhandleargs, - .pc_encode = nfssvc_encode_attrstat, + .pc_encode = nfssvc_encode_attrstatres, .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_fhandle), .pc_ressize = sizeof(struct nfsd_attrstat), @@ -651,7 +660,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_SETATTR] = { .pc_func = nfsd_proc_setattr, .pc_decode = nfssvc_decode_sattrargs, - .pc_encode = nfssvc_encode_attrstat, + .pc_encode = nfssvc_encode_attrstatres, .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_sattrargs), .pc_ressize = sizeof(struct nfsd_attrstat), @@ -714,7 +723,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_WRITE] = { .pc_func = nfsd_proc_write, .pc_decode = nfssvc_decode_writeargs, - .pc_encode = nfssvc_encode_attrstat, + .pc_encode = nfssvc_encode_attrstatres, .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_writeargs), .pc_ressize = sizeof(struct nfsd_attrstat), @@ -736,7 +745,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_REMOVE] = { .pc_func = nfsd_proc_remove, .pc_decode = nfssvc_decode_diropargs, - .pc_encode = nfssvc_encode_stat, + .pc_encode = nfssvc_encode_statres, .pc_argsize = sizeof(struct nfsd_diropargs), .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, @@ -746,7 +755,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_RENAME] = { .pc_func = nfsd_proc_rename, .pc_decode = nfssvc_decode_renameargs, - .pc_encode = nfssvc_encode_stat, + .pc_encode = nfssvc_encode_statres, .pc_argsize = sizeof(struct nfsd_renameargs), .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, @@ -756,7 +765,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_LINK] = { .pc_func = nfsd_proc_link, .pc_decode = nfssvc_decode_linkargs, - .pc_encode = nfssvc_encode_stat, + .pc_encode = nfssvc_encode_statres, .pc_argsize = sizeof(struct nfsd_linkargs), .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, @@ -766,7 +775,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_SYMLINK] = { .pc_func = nfsd_proc_symlink, .pc_decode = nfssvc_decode_symlinkargs, - .pc_encode = nfssvc_encode_stat, + .pc_encode = nfssvc_encode_statres, .pc_argsize = sizeof(struct nfsd_symlinkargs), .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, @@ -787,7 +796,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_RMDIR] = { .pc_func = nfsd_proc_rmdir, .pc_decode = nfssvc_decode_diropargs, - .pc_encode = nfssvc_encode_stat, + .pc_encode = nfssvc_encode_statres, .pc_argsize = sizeof(struct nfsd_diropargs), .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 6de406322106f195ad6d32cf8705bd7661a400f2..82ba034fa5791313234f5a62e93bd996800f7f93 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -84,7 +84,7 @@ DEFINE_MUTEX(nfsd_mutex); * version 4.1 DRC caches. * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage. */ -spinlock_t nfsd_drc_lock; +DEFINE_SPINLOCK(nfsd_drc_lock); unsigned long nfsd_drc_max_mem; unsigned long nfsd_drc_mem_used; @@ -563,7 +563,6 @@ static void set_max_drc(void) nfsd_drc_max_mem = (nr_free_buffer_pages() >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; nfsd_drc_mem_used = 0; - spin_lock_init(&nfsd_drc_lock); dprintk("%s nfsd_drc_max_mem %lu \n", __func__, nfsd_drc_max_mem); } @@ -596,6 +595,37 @@ static const struct svc_serv_ops nfsd_thread_sv_ops = { .svo_module = THIS_MODULE, }; +static void nfsd_complete_shutdown(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + WARN_ON(!mutex_is_locked(&nfsd_mutex)); + + nn->nfsd_serv = NULL; + complete(&nn->nfsd_shutdown_complete); +} + +void nfsd_shutdown_threads(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct svc_serv *serv; + + mutex_lock(&nfsd_mutex); + serv = nn->nfsd_serv; + if (serv == NULL) { + mutex_unlock(&nfsd_mutex); + return; + } + + svc_get(serv); + /* Kill outstanding nfsd threads */ + serv->sv_ops->svo_setup(serv, NULL, 0); + nfsd_destroy(net); + mutex_unlock(&nfsd_mutex); + /* Wait for shutdown of nfsd_serv to complete */ + wait_for_completion(&nn->nfsd_shutdown_complete); +} + bool i_am_nfsd(void) { return kthread_func(current) == nfsd; @@ -618,11 +648,13 @@ int nfsd_create_serv(struct net *net) &nfsd_thread_sv_ops); if (nn->nfsd_serv == NULL) return -ENOMEM; + init_completion(&nn->nfsd_shutdown_complete); nn->nfsd_serv->sv_maxconn = nn->max_connections; error = svc_bind(nn->nfsd_serv, net); if (error < 0) { svc_destroy(nn->nfsd_serv); + nfsd_complete_shutdown(net); return error; } @@ -671,7 +703,7 @@ void nfsd_destroy(struct net *net) svc_shutdown_net(nn->nfsd_serv, net); svc_destroy(nn->nfsd_serv); if (destroy) - nn->nfsd_serv = NULL; + nfsd_complete_shutdown(net); } int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) @@ -997,7 +1029,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) * NFSv4 does some encoding while processing */ p = resv->iov_base + resv->iov_len; - resv->iov_len += sizeof(__be32); + svcxdr_init_encode(rqstp); *statp = proc->pc_func(rqstp); if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) @@ -1052,7 +1084,7 @@ int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) */ int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) { - return xdr_ressize_check(rqstp, p); + return 1; } int nfsd_pool_stats_open(struct inode *inode, struct file *file) diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 5d79ef6a0c7fc216431f97be166fdd1a95c72ef3..a06c05fe3b421895a13d2ed1c7ac11794c1ba67d 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -9,12 +9,10 @@ #include "xdr.h" #include "auth.h" -#define NFSDDBG_FACILITY NFSDDBG_XDR - /* * Mapping of S_IF* types to NFS file types */ -static u32 nfs_ftypes[] = { +static const u32 nfs_ftypes[] = { NFNON, NFCHR, NFCHR, NFBAD, NFDIR, NFBAD, NFBLK, NFBAD, NFREG, NFBAD, NFLNK, NFBAD, @@ -26,6 +24,28 @@ static u32 nfs_ftypes[] = { * Basic NFSv2 data types (RFC 1094 Section 2.3) */ +/** + * svcxdr_encode_stat - Encode an NFSv2 status code + * @xdr: XDR stream + * @status: status value to encode + * + * Return values: + * %false: Send buffer space was exhausted + * %true: Success + */ +bool +svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, sizeof(status)); + if (!p) + return false; + *p = status; + + return true; +} + /** * svcxdr_decode_fhandle - Decode an NFSv2 file handle * @xdr: XDR stream positioned at an encoded NFSv2 FH @@ -50,11 +70,28 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) return true; } -static __be32 * -encode_fh(__be32 *p, struct svc_fh *fhp) +static bool +svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp) { + __be32 *p; + + p = xdr_reserve_space(xdr, NFS_FHSIZE); + if (!p) + return false; memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE); - return p + (NFS_FHSIZE>> 2); + + return true; +} + +static __be32 * +encode_timeval(__be32 *p, const struct timespec64 *time) +{ + *p++ = cpu_to_be32((u32)time->tv_sec); + if (time->tv_nsec) + *p++ = cpu_to_be32(time->tv_nsec / NSEC_PER_USEC); + else + *p++ = xdr_zero; + return p; } static bool @@ -162,68 +199,73 @@ svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, return true; } -static __be32 * -encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, - struct kstat *stat) +/** + * svcxdr_encode_fattr - Encode NFSv2 file attributes + * @rqstp: Context of a completed RPC transaction + * @xdr: XDR stream + * @fhp: File handle to encode + * @stat: Attributes to encode + * + * Return values: + * %false: Send buffer space was exhausted + * %true: Success + */ +bool +svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp, const struct kstat *stat) { struct user_namespace *userns = nfsd_user_namespace(rqstp); - struct dentry *dentry = fhp->fh_dentry; - int type; + struct dentry *dentry = fhp->fh_dentry; + int type = stat->mode & S_IFMT; struct timespec64 time; - u32 f; + __be32 *p; + u32 fsid; - type = (stat->mode & S_IFMT); + p = xdr_reserve_space(xdr, XDR_UNIT * 17); + if (!p) + return false; - *p++ = htonl(nfs_ftypes[type >> 12]); - *p++ = htonl((u32) stat->mode); - *p++ = htonl((u32) stat->nlink); - *p++ = htonl((u32) from_kuid_munged(userns, stat->uid)); - *p++ = htonl((u32) from_kgid_munged(userns, stat->gid)); + *p++ = cpu_to_be32(nfs_ftypes[type >> 12]); + *p++ = cpu_to_be32((u32)stat->mode); + *p++ = cpu_to_be32((u32)stat->nlink); + *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid)); + *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid)); - if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) { - *p++ = htonl(NFS_MAXPATHLEN); - } else { - *p++ = htonl((u32) stat->size); - } - *p++ = htonl((u32) stat->blksize); + if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) + *p++ = cpu_to_be32(NFS_MAXPATHLEN); + else + *p++ = cpu_to_be32((u32) stat->size); + *p++ = cpu_to_be32((u32) stat->blksize); if (S_ISCHR(type) || S_ISBLK(type)) - *p++ = htonl(new_encode_dev(stat->rdev)); + *p++ = cpu_to_be32(new_encode_dev(stat->rdev)); else - *p++ = htonl(0xffffffff); - *p++ = htonl((u32) stat->blocks); + *p++ = cpu_to_be32(0xffffffff); + *p++ = cpu_to_be32((u32)stat->blocks); + switch (fsid_source(fhp)) { - default: - case FSIDSOURCE_DEV: - *p++ = htonl(new_encode_dev(stat->dev)); - break; case FSIDSOURCE_FSID: - *p++ = htonl((u32) fhp->fh_export->ex_fsid); + fsid = (u32)fhp->fh_export->ex_fsid; break; case FSIDSOURCE_UUID: - f = ((u32*)fhp->fh_export->ex_uuid)[0]; - f ^= ((u32*)fhp->fh_export->ex_uuid)[1]; - f ^= ((u32*)fhp->fh_export->ex_uuid)[2]; - f ^= ((u32*)fhp->fh_export->ex_uuid)[3]; - *p++ = htonl(f); + fsid = ((u32 *)fhp->fh_export->ex_uuid)[0]; + fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[1]; + fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[2]; + fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[3]; + break; + default: + fsid = new_encode_dev(stat->dev); break; } - *p++ = htonl((u32) stat->ino); - *p++ = htonl((u32) stat->atime.tv_sec); - *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); - time = stat->mtime; - lease_get_mtime(d_inode(dentry), &time); - *p++ = htonl((u32) time.tv_sec); - *p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0); - *p++ = htonl((u32) stat->ctime.tv_sec); - *p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0); + *p++ = cpu_to_be32(fsid); - return p; -} + *p++ = cpu_to_be32((u32)stat->ino); + p = encode_timeval(p, &stat->atime); + time = stat->mtime; + lease_get_mtime(d_inode(dentry), &time); + p = encode_timeval(p, &time); + encode_timeval(p, &stat->ctime); -/* Helper function for NFSv2 ACL code */ -__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) -{ - return encode_fattr(rqstp, p, fhp, stat); + return true; } /* @@ -390,106 +432,118 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) */ int -nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p) +nfssvc_encode_statres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_stat *resp = rqstp->rq_resp; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_stat(xdr, resp->status); } int -nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) +nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_attrstat *resp = rqstp->rq_resp; - *p++ = resp->status; - if (resp->status != nfs_ok) - goto out; - p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); -out: - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) + return 0; + break; + } + + return 1; } int nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_diropres *resp = rqstp->rq_resp; - *p++ = resp->status; - if (resp->status != nfs_ok) - goto out; - p = encode_fh(p, &resp->fh); - p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); -out: - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fhandle(xdr, &resp->fh)) + return 0; + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) + return 0; + break; + } + + return 1; } int nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_readlinkres *resp = rqstp->rq_resp; struct kvec *head = rqstp->rq_res.head; - *p++ = resp->status; - if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); - - *p++ = htonl(resp->len); - xdr_ressize_check(rqstp, p); - rqstp->rq_res.page_len = resp->len; - if (resp->len & 3) { - /* need to pad the tail */ - rqstp->rq_res.tail[0].iov_base = p; - *p = 0; - rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); - } - if (svc_encode_result_payload(rqstp, head->iov_len, resp->len)) + if (!svcxdr_encode_stat(xdr, resp->status)) return 0; + switch (resp->status) { + case nfs_ok: + if (xdr_stream_encode_u32(xdr, resp->len) < 0) + return 0; + xdr_write_pages(xdr, &resp->page, 0, resp->len); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) + return 0; + break; + } + return 1; } int nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_readres *resp = rqstp->rq_resp; struct kvec *head = rqstp->rq_res.head; - *p++ = resp->status; - if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); - - p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); - *p++ = htonl(resp->count); - xdr_ressize_check(rqstp, p); - - /* now update rqstp->rq_res to reflect data as well */ - rqstp->rq_res.page_len = resp->count; - if (resp->count & 3) { - /* need to pad the tail */ - rqstp->rq_res.tail[0].iov_base = p; - *p = 0; - rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3); - } - if (svc_encode_result_payload(rqstp, head->iov_len, resp->count)) + if (!svcxdr_encode_stat(xdr, resp->status)) return 0; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) + return 0; + xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, + resp->count); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) + return 0; + break; + } + return 1; } int nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_readdirres *resp = rqstp->rq_resp; + struct xdr_buf *dirlist = &resp->dirlist; - *p++ = resp->status; - if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); - - xdr_ressize_check(rqstp, p); - p = resp->buffer; - *p++ = 0; /* no more entries */ - *p++ = htonl((resp->common.err == nfserr_eof)); - rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1; + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); + /* no more entries */ + if (xdr_stream_encode_item_absent(xdr) < 0) + return 0; + if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) + return 0; + break; + } return 1; } @@ -497,64 +551,113 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) int nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nfsd_statfsres *resp = rqstp->rq_resp; struct kstatfs *stat = &resp->stats; - *p++ = resp->status; - if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: + p = xdr_reserve_space(xdr, XDR_UNIT * 5); + if (!p) + return 0; + *p++ = cpu_to_be32(NFSSVC_MAXBLKSIZE_V2); + *p++ = cpu_to_be32(stat->f_bsize); + *p++ = cpu_to_be32(stat->f_blocks); + *p++ = cpu_to_be32(stat->f_bfree); + *p = cpu_to_be32(stat->f_bavail); + break; + } - *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */ - *p++ = htonl(stat->f_bsize); - *p++ = htonl(stat->f_blocks); - *p++ = htonl(stat->f_bfree); - *p++ = htonl(stat->f_bavail); - return xdr_ressize_check(rqstp, p); + return 1; } -int -nfssvc_encode_entry(void *ccdv, const char *name, - int namlen, loff_t offset, u64 ino, unsigned int d_type) +/** + * nfssvc_encode_nfscookie - Encode a directory offset cookie + * @resp: readdir result context + * @offset: offset cookie to encode + * + * The buffer space for the offset cookie has already been reserved + * by svcxdr_encode_entry_common(). + */ +void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset) { - struct readdir_cd *ccd = ccdv; - struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common); - __be32 *p = cd->buffer; - int buflen, slen; + __be32 cookie = cpu_to_be32(offset); - /* - dprintk("nfsd: entry(%.*s off %ld ino %ld)\n", - namlen, name, offset, ino); - */ + if (!resp->cookie_offset) + return; - if (offset > ~((u32) 0)) { - cd->common.err = nfserr_fbig; - return -EINVAL; - } - if (cd->offset) - *cd->offset = htonl(offset); + write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie, + sizeof(cookie)); + resp->cookie_offset = 0; +} - /* truncate filename */ - namlen = min(namlen, NFS2_MAXNAMLEN); - slen = XDR_QUADLEN(namlen); +static bool +svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name, + int namlen, loff_t offset, u64 ino) +{ + struct xdr_buf *dirlist = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; - if ((buflen = cd->buflen - slen - 4) < 0) { - cd->common.err = nfserr_toosmall; - return -EINVAL; - } - if (ino > ~((u32) 0)) { - cd->common.err = nfserr_fbig; - return -EINVAL; - } - *p++ = xdr_one; /* mark entry present */ - *p++ = htonl((u32) ino); /* file id */ - p = xdr_encode_array(p, name, namlen);/* name length & name */ - cd->offset = p; /* remember pointer */ - *p++ = htonl(~0U); /* offset of next entry */ - - cd->buflen = buflen; - cd->buffer = p; - cd->common.err = nfs_ok; + if (xdr_stream_encode_item_present(xdr) < 0) + return false; + /* fileid */ + if (xdr_stream_encode_u32(xdr, (u32)ino) < 0) + return false; + /* name */ + if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS2_MAXNAMLEN)) < 0) + return false; + /* cookie */ + resp->cookie_offset = dirlist->len; + if (xdr_stream_encode_u32(xdr, ~0U) < 0) + return false; + + return true; +} + +/** + * nfssvc_encode_entry - encode one NFSv2 READDIR entry + * @data: directory context + * @name: name of the object to be encoded + * @namlen: length of that name, in bytes + * @offset: the offset of the previous entry + * @ino: the fileid of this entry + * @d_type: unused + * + * Return values: + * %0: Entry was successfully encoded. + * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err + * + * On exit, the following fields are updated: + * - resp->xdr + * - resp->common.err + * - resp->cookie_offset + */ +int nfssvc_encode_entry(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct readdir_cd *ccd = data; + struct nfsd_readdirres *resp = container_of(ccd, + struct nfsd_readdirres, + common); + unsigned int starting_length = resp->dirlist.len; + + /* The offset cookie for the previous entry */ + nfssvc_encode_nfscookie(resp, offset); + + if (!svcxdr_encode_entry_common(resp, name, namlen, offset, ino)) + goto out_toosmall; + + xdr_commit_encode(&resp->xdr); + resp->common.err = nfs_ok; return 0; + +out_toosmall: + resp->cookie_offset = 0; + resp->common.err = nfserr_toosmall; + resp->dirlist.len = starting_length; + return -EINVAL; } /* diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 73deea35316994fae5473dd2c14138ad5811405b..54cab651ac1d009ed69a315733a24c8ea2311c2f 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -371,6 +371,10 @@ struct nfs4_client { /* debugging info directory under nfsd/clients/ : */ struct dentry *cl_nfsd_dentry; + /* 'info' file within that directory. Ref is not counted, + * but will remain valid iff cl_nfsd_dentry != NULL + */ + struct dentry *cl_nfsd_info_dentry; /* for nfs41 callbacks */ /* We currently support a single back channel with a single slot */ diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 92a0973dd67136547f9eba231a711e7849820efd..27a93ebd1d80906276086b61c32c9a5ba49c6683 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -391,6 +391,30 @@ DEFINE_EVENT(nfsd_err_class, nfsd_##name, \ DEFINE_NFSD_ERR_EVENT(read_err); DEFINE_NFSD_ERR_EVENT(write_err); +TRACE_EVENT(nfsd_dirent, + TP_PROTO(struct svc_fh *fhp, + u64 ino, + const char *name, + int namlen), + TP_ARGS(fhp, ino, name, namlen), + TP_STRUCT__entry( + __field(u32, fh_hash) + __field(u64, ino) + __field(int, len) + __dynamic_array(unsigned char, name, namlen) + ), + TP_fast_assign( + __entry->fh_hash = fhp ? knfsd_fh_hash(&fhp->fh_handle) : 0; + __entry->ino = ino; + __entry->len = namlen; + memcpy(__get_str(name), name, namlen); + __assign_str(name, name); + ), + TP_printk("fh_hash=0x%08x ino=%llu name=%.*s", + __entry->fh_hash, __entry->ino, + __entry->len, __get_str(name)) +) + #include "state.h" #include "filecache.h" #include "vfs.h" diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index fd6be35a1642cc165f7db3961a2b92a122e57ad1..15adf1f6ab21fc7d258227046f76cef1aad20687 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1968,8 +1968,9 @@ static int nfsd_buffered_filldir(struct dir_context *ctx, const char *name, return 0; } -static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, - struct readdir_cd *cdp, loff_t *offsetp) +static __be32 nfsd_buffered_readdir(struct file *file, struct svc_fh *fhp, + nfsd_filldir_t func, struct readdir_cd *cdp, + loff_t *offsetp) { struct buffered_dirent *de; int host_err; @@ -2015,6 +2016,8 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, if (cdp->err != nfs_ok) break; + trace_nfsd_dirent(fhp, de->ino, de->name, de->namlen); + reclen = ALIGN(sizeof(*de) + de->namlen, sizeof(u64)); size -= reclen; @@ -2062,7 +2065,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, goto out_close; } - err = nfsd_buffered_readdir(file, func, cdp, offsetp); + err = nfsd_buffered_readdir(file, fhp, func, cdp, offsetp); if (err == nfserr_eof || err == nfserr_toosmall) err = nfs_ok; /* can still be found in ->err */ diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index a2442ebe5acf68e79aa47c48679d98f5486a2d80..b21b76e6b9a876e20e784b3a9051e8b649af93ef 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -152,7 +152,7 @@ static inline void fh_drop_write(struct svc_fh *fh) } } -static inline __be32 fh_getattr(struct svc_fh *fh, struct kstat *stat) +static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat) { struct path p = {.mnt = fh->fh_export->ex_path.mnt, .dentry = fh->fh_dentry}; diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index 3018b52b6d5edf39609c96a36cf0214af37b16c1..f45b4bc93f527da80d01d26616275d953e7ea18d 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -94,6 +94,7 @@ struct nfsd_diropres { struct nfsd_readlinkres { __be32 status; int len; + struct page *page; }; struct nfsd_readres { @@ -101,17 +102,20 @@ struct nfsd_readres { struct svc_fh fh; unsigned long count; struct kstat stat; + struct page **pages; }; struct nfsd_readdirres { + /* Components of the reply */ __be32 status; int count; + /* Used to encode the reply's entry list */ + struct xdr_stream xdr; + struct xdr_buf dirlist; struct readdir_cd common; - __be32 * buffer; - int buflen; - __be32 * offset; + unsigned int cookie_offset; }; struct nfsd_statfsres { @@ -147,23 +151,26 @@ int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *); int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); -int nfssvc_encode_stat(struct svc_rqst *, __be32 *); -int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *); +int nfssvc_encode_statres(struct svc_rqst *, __be32 *); +int nfssvc_encode_attrstatres(struct svc_rqst *, __be32 *); int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *); int nfssvc_encode_readres(struct svc_rqst *, __be32 *); int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *); int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); -int nfssvc_encode_entry(void *, const char *name, - int namlen, loff_t offset, u64 ino, unsigned int); +void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); +int nfssvc_encode_entry(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type); void nfssvc_release_attrstat(struct svc_rqst *rqstp); void nfssvc_release_diropres(struct svc_rqst *rqstp); void nfssvc_release_readres(struct svc_rqst *rqstp); /* Helper functions for NFSv2 ACL code */ -__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat); bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp); +bool svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status); +bool svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp, const struct kstat *stat); #endif /* LINUX_NFSD_H */ diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h index 3e1578953f544c6257f3a26d4e70bff3d781937b..933008382bbeb09348bcdb6ac20c493cdf4c951e 100644 --- a/fs/nfsd/xdr3.h +++ b/fs/nfsd/xdr3.h @@ -137,6 +137,7 @@ struct nfsd3_readlinkres { __be32 status; struct svc_fh fh; __u32 len; + struct page **pages; }; struct nfsd3_readres { @@ -144,6 +145,7 @@ struct nfsd3_readres { struct svc_fh fh; unsigned long count; __u32 eof; + struct page **pages; }; struct nfsd3_writeres { @@ -167,19 +169,17 @@ struct nfsd3_linkres { }; struct nfsd3_readdirres { + /* Components of the reply */ __be32 status; struct svc_fh fh; - /* Just to save kmalloc on every readdirplus entry (svc_fh is a - * little large for the stack): */ - struct svc_fh scratch; - int count; __be32 verf[2]; + /* Used to encode the reply's entry list */ + struct xdr_stream xdr; + struct xdr_buf dirlist; + struct svc_fh scratch; struct readdir_cd common; - __be32 * buffer; - int buflen; - __be32 * offset; - __be32 * offset1; + unsigned int cookie_offset; struct svc_rqst * rqstp; }; @@ -280,9 +280,9 @@ int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *); int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *); int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *); int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *); -int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *); +int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *); int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); -int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *); +int nfs3svc_encode_lookupres(struct svc_rqst *, __be32 *); int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *); int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *); int nfs3svc_encode_readres(struct svc_rqst *, __be32 *); @@ -298,15 +298,16 @@ int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *); void nfs3svc_release_fhandle(struct svc_rqst *); void nfs3svc_release_fhandle2(struct svc_rqst *); -int nfs3svc_encode_entry(void *, const char *name, - int namlen, loff_t offset, u64 ino, - unsigned int); -int nfs3svc_encode_entry_plus(void *, const char *name, - int namlen, loff_t offset, u64 ino, - unsigned int); + +void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset); +int nfs3svc_encode_entry3(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type); +int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type); /* Helper functions for NFSv3 ACL code */ -__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, - struct svc_fh *fhp); bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp); +bool svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status); +bool svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp); #endif /* _LINUX_NFSD_XDR3_H */ diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index c300885ae75ddee7866e519c0d71cebadfa5d6da..fe540a3415c6ae515d0bfdfa4aa868ace70cac94 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -698,7 +698,7 @@ struct nfsd4_compoundargs { struct nfsd4_compoundres { /* scratch variables for XDR encode */ - struct xdr_stream xdr; + struct xdr_stream *xdr; struct svc_rqst * rqstp; u32 taglen; diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index e1bd592ce7001a28a2c18fdb7335e4d0d0b8a8ed..7cf765258fdad020b23163a98f77d9bcee34ba34 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c @@ -148,6 +148,8 @@ const struct inode_operations nilfs_file_inode_operations = { .setattr = nilfs_setattr, .permission = nilfs_permission, .fiemap = nilfs_fiemap, + .fileattr_get = nilfs_fileattr_get, + .fileattr_set = nilfs_fileattr_set, }; /* end of file */ diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index b053b40315bf2b2264ab7a08e5166af517869aa9..3fcb9357bbfd1170df643442820e309afd9d22c4 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -16,6 +16,7 @@ #include <linux/compat.h> /* compat_ptr() */ #include <linux/mount.h> /* mnt_want_write_file(), mnt_drop_write_file() */ #include <linux/buffer_head.h> +#include <linux/fileattr.h> #include "nilfs.h" #include "segment.h" #include "bmap.h" @@ -113,51 +114,39 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, } /** - * nilfs_ioctl_getflags - ioctl to support lsattr + * nilfs_fileattr_get - ioctl to support lsattr */ -static int nilfs_ioctl_getflags(struct inode *inode, void __user *argp) +int nilfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) { - unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE; + struct inode *inode = d_inode(dentry); - return put_user(flags, (int __user *)argp); + fileattr_fill_flags(fa, NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE); + + return 0; } /** - * nilfs_ioctl_setflags - ioctl to support chattr + * nilfs_fileattr_set - ioctl to support chattr */ -static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp, - void __user *argp) +int nilfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { + struct inode *inode = d_inode(dentry); struct nilfs_transaction_info ti; unsigned int flags, oldflags; int ret; - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; - - if (get_user(flags, (int __user *)argp)) - return -EFAULT; - - ret = mnt_want_write_file(filp); - if (ret) - return ret; - - flags = nilfs_mask_flags(inode->i_mode, flags); - - inode_lock(inode); - - oldflags = NILFS_I(inode)->i_flags; + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; - ret = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (ret) - goto out; + flags = nilfs_mask_flags(inode->i_mode, fa->flags); ret = nilfs_transaction_begin(inode->i_sb, &ti, 0); if (ret) - goto out; + return ret; - NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) | - (flags & FS_FL_USER_MODIFIABLE); + oldflags = NILFS_I(inode)->i_flags & ~FS_FL_USER_MODIFIABLE; + NILFS_I(inode)->i_flags = oldflags | (flags & FS_FL_USER_MODIFIABLE); nilfs_set_inode_flags(inode); inode->i_ctime = current_time(inode); @@ -165,11 +154,7 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp, nilfs_set_transaction_flag(NILFS_TI_SYNC); nilfs_mark_inode_dirty(inode); - ret = nilfs_transaction_commit(inode->i_sb); -out: - inode_unlock(inode); - mnt_drop_write_file(filp); - return ret; + return nilfs_transaction_commit(inode->i_sb); } /** @@ -1282,10 +1267,6 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) void __user *argp = (void __user *)arg; switch (cmd) { - case FS_IOC_GETFLAGS: - return nilfs_ioctl_getflags(inode, argp); - case FS_IOC_SETFLAGS: - return nilfs_ioctl_setflags(inode, filp, argp); case FS_IOC_GETVERSION: return nilfs_ioctl_getversion(inode, argp); case NILFS_IOCTL_CHANGE_CPMODE: @@ -1331,12 +1312,6 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; case FS_IOC32_GETVERSION: cmd = FS_IOC_GETVERSION; break; diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index ecace5f96a95623d8409ef9de8c800a1745af8aa..189bd1007a2f6e7cd667878d85263a37dd3b3d75 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -552,6 +552,8 @@ const struct inode_operations nilfs_dir_inode_operations = { .setattr = nilfs_setattr, .permission = nilfs_permission, .fiemap = nilfs_fiemap, + .fileattr_get = nilfs_fileattr_get, + .fileattr_set = nilfs_fileattr_set, }; const struct inode_operations nilfs_special_inode_operations = { diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index c4a45a081ade690c8ffea8cbfb46e2c78e5e1597..60b21b6eeac0670d0c0057854cc16f8a7ff34514 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -243,6 +243,9 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, extern int nilfs_sync_file(struct file *, loff_t, loff_t, int); /* ioctl.c */ +int nilfs_fileattr_get(struct dentry *dentry, struct fileattr *m); +int nilfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); long nilfs_ioctl(struct file *, unsigned int, unsigned long); long nilfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, struct nilfs_argv *, diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 8e3a369086dbd56126e050b5ab0daf1035d0ff04..0fbe8bf7190fa48fa5879a0a78afe8e90f5cb9fd 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -2204,7 +2204,7 @@ static void ocfs2_unpack_timespec(struct timespec64 *spec, spec->tv_nsec = packed_time & OCFS2_NSEC_MASK; } -static void ocfs2_refresh_inode_from_lvb(struct inode *inode) +static int ocfs2_refresh_inode_from_lvb(struct inode *inode) { struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres; @@ -2213,6 +2213,8 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode) mlog_meta_lvb(0, lockres); lvb = ocfs2_dlm_lvb(&lockres->l_lksb); + if (inode_wrong_type(inode, be16_to_cpu(lvb->lvb_imode))) + return -ESTALE; /* We're safe here without the lockres lock... */ spin_lock(&oi->ip_lock); @@ -2240,6 +2242,7 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode) ocfs2_unpack_timespec(&inode->i_ctime, be64_to_cpu(lvb->lvb_ictime_packed)); spin_unlock(&oi->ip_lock); + return 0; } static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode, @@ -2342,7 +2345,8 @@ static int ocfs2_inode_lock_update(struct inode *inode, if (ocfs2_meta_lvb_is_trustable(inode, lockres)) { mlog(0, "Trusting LVB on inode %llu\n", (unsigned long long)oi->ip_blkno); - ocfs2_refresh_inode_from_lvb(inode); + status = ocfs2_refresh_inode_from_lvb(inode); + goto bail_refresh; } else { /* Boo, we have to go to disk. */ /* read bh, cast, ocfs2_refresh_inode */ @@ -2352,6 +2356,10 @@ static int ocfs2_inode_lock_update(struct inode *inode, goto bail_refresh; } fe = (struct ocfs2_dinode *) (*bh)->b_data; + if (inode_wrong_type(inode, le16_to_cpu(fe->i_mode))) { + status = -ESTALE; + goto bail_refresh; + } /* This is a good chance to make sure we're not * locking an invalid object. ocfs2_read_inode_block() diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 5edc1d0cf115fb6750dd230c4e6351d36f2ee4cf..db8a6265b749234fc473a2d94c081fb95d43a2a3 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2649,6 +2649,8 @@ const struct inode_operations ocfs2_file_iops = { .fiemap = ocfs2_fiemap, .get_acl = ocfs2_iop_get_acl, .set_acl = ocfs2_iop_set_acl, + .fileattr_get = ocfs2_fileattr_get, + .fileattr_set = ocfs2_fileattr_set, }; const struct inode_operations ocfs2_special_file_iops = { diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 50c9b30ee9f6f02466f1ec28c5cb3011e3a92287..f59461d85da4595dafd9119f9df09a77fefa8ead 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c @@ -10,6 +10,7 @@ #include <linux/mount.h> #include <linux/blkdev.h> #include <linux/compat.h> +#include <linux/fileattr.h> #include <cluster/masklog.h> @@ -61,8 +62,10 @@ static inline int o2info_coherent(struct ocfs2_info_request *req) return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); } -static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) +int ocfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa) { + struct inode *inode = d_inode(dentry); + unsigned int flags; int status; status = ocfs2_inode_lock(inode, NULL, 0); @@ -71,15 +74,19 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) return status; } ocfs2_get_inode_flags(OCFS2_I(inode)); - *flags = OCFS2_I(inode)->ip_attr; + flags = OCFS2_I(inode)->ip_attr; ocfs2_inode_unlock(inode, 0); + fileattr_fill_flags(fa, flags & OCFS2_FL_VISIBLE); + return status; } -static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, - unsigned mask) +int ocfs2_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { + struct inode *inode = d_inode(dentry); + unsigned int flags = fa->flags; struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); handle_t *handle = NULL; @@ -87,7 +94,8 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, unsigned oldflags; int status; - inode_lock(inode); + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; status = ocfs2_inode_lock(inode, &bh, 1); if (status < 0) { @@ -95,19 +103,17 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, goto bail; } - status = -EACCES; - if (!inode_owner_or_capable(&init_user_ns, inode)) - goto bail_unlock; - if (!S_ISDIR(inode->i_mode)) flags &= ~OCFS2_DIRSYNC_FL; oldflags = ocfs2_inode->ip_attr; - flags = flags & mask; - flags |= oldflags & ~mask; + flags = flags & OCFS2_FL_MODIFIABLE; + flags |= oldflags & ~OCFS2_FL_MODIFIABLE; - status = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (status) + /* Check already done by VFS, but repeat with ocfs lock */ + status = -EPERM; + if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && + !capable(CAP_LINUX_IMMUTABLE)) goto bail_unlock; handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); @@ -129,8 +135,6 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, bail_unlock: ocfs2_inode_unlock(inode, 1); bail: - inode_unlock(inode); - brelse(bh); return status; @@ -836,7 +840,6 @@ bail: long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); - unsigned int flags; int new_clusters; int status; struct ocfs2_space_resv sr; @@ -849,24 +852,6 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) void __user *argp = (void __user *)arg; switch (cmd) { - case OCFS2_IOC_GETFLAGS: - status = ocfs2_get_inode_attr(inode, &flags); - if (status < 0) - return status; - - flags &= OCFS2_FL_VISIBLE; - return put_user(flags, (int __user *) arg); - case OCFS2_IOC_SETFLAGS: - if (get_user(flags, (int __user *) arg)) - return -EFAULT; - - status = mnt_want_write_file(filp); - if (status) - return status; - status = ocfs2_set_inode_attr(inode, flags, - OCFS2_FL_MODIFIABLE); - mnt_drop_write_file(filp); - return status; case OCFS2_IOC_RESVSP: case OCFS2_IOC_RESVSP64: case OCFS2_IOC_UNRESVSP: @@ -959,12 +944,6 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) void __user *argp = (void __user *)arg; switch (cmd) { - case OCFS2_IOC32_GETFLAGS: - cmd = OCFS2_IOC_GETFLAGS; - break; - case OCFS2_IOC32_SETFLAGS: - cmd = OCFS2_IOC_SETFLAGS; - break; case OCFS2_IOC_RESVSP: case OCFS2_IOC_RESVSP64: case OCFS2_IOC_UNRESVSP: diff --git a/fs/ocfs2/ioctl.h b/fs/ocfs2/ioctl.h index 9f5e4d95e37f84588bc61dec2b07116069ce9bd7..0297c8846945ab34ffd0d8297dd9bafe5bec4cf0 100644 --- a/fs/ocfs2/ioctl.h +++ b/fs/ocfs2/ioctl.h @@ -11,6 +11,9 @@ #ifndef OCFS2_IOCTL_PROTO_H #define OCFS2_IOCTL_PROTO_H +int ocfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int ocfs2_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg); diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 3abdd36da2e26e1afb366e6cf8df4d983d56e287..05ced86580d1d25e4a38985b8b36421bf093a352 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -50,6 +50,7 @@ #include "xattr.h" #include "acl.h" #include "ocfs2_trace.h" +#include "ioctl.h" #include "buffer_head_io.h" @@ -2918,4 +2919,6 @@ const struct inode_operations ocfs2_dir_iops = { .fiemap = ocfs2_fiemap, .get_acl = ocfs2_iop_get_acl, .set_acl = ocfs2_iop_set_acl, + .fileattr_get = ocfs2_fileattr_get, + .fileattr_set = ocfs2_fileattr_set, }; diff --git a/fs/ocfs2/ocfs2_ioctl.h b/fs/ocfs2/ocfs2_ioctl.h index d7b31734f6be4ebc0219eba26fcadc35e2d77426..273616bd4f19328a8fcb800506e5b21522ac0113 100644 --- a/fs/ocfs2/ocfs2_ioctl.h +++ b/fs/ocfs2/ocfs2_ioctl.h @@ -12,14 +12,6 @@ #ifndef OCFS2_IOCTL_H #define OCFS2_IOCTL_H -/* - * ioctl commands - */ -#define OCFS2_IOC_GETFLAGS FS_IOC_GETFLAGS -#define OCFS2_IOC_SETFLAGS FS_IOC_SETFLAGS -#define OCFS2_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define OCFS2_IOC32_SETFLAGS FS_IOC32_SETFLAGS - /* * Space reservation / allocation / free ioctls and argument structure * are designed to be compatible with XFS. diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 40c8c2e32fa3e5617c818e782eed34ea61670d29..f825176ff4ed7c6ed2270639332438c40dee1f56 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -236,27 +236,31 @@ found: mutex_unlock(&op_mutex); if (IS_ERR(inode)) return ERR_CAST(inode); - ent_oi = OP_I(inode); - ent_oi->type = ent_type; - ent_oi->u = ent_data; - - switch (ent_type) { - case op_inode_node: - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - inode->i_op = &openprom_inode_operations; - inode->i_fop = &openprom_operations; - set_nlink(inode, 2); - break; - case op_inode_prop: - if (of_node_name_eq(dp, "options") && (len == 17) && - !strncmp (name, "security-password", 17)) - inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; - else - inode->i_mode = S_IFREG | S_IRUGO; - inode->i_fop = &openpromfs_prop_ops; - set_nlink(inode, 1); - inode->i_size = ent_oi->u.prop->length; - break; + if (inode->i_state & I_NEW) { + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + ent_oi = OP_I(inode); + ent_oi->type = ent_type; + ent_oi->u = ent_data; + + switch (ent_type) { + case op_inode_node: + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_op = &openprom_inode_operations; + inode->i_fop = &openprom_operations; + set_nlink(inode, 2); + break; + case op_inode_prop: + if (of_node_name_eq(dp, "options") && (len == 17) && + !strncmp (name, "security-password", 17)) + inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; + else + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_fop = &openpromfs_prop_ops; + set_nlink(inode, 1); + inode->i_size = ent_oi->u.prop->length; + break; + } + unlock_new_inode(inode); } return d_splice_alias(inode, dentry); @@ -345,20 +349,9 @@ static void openprom_free_inode(struct inode *inode) static struct inode *openprom_iget(struct super_block *sb, ino_t ino) { - struct inode *inode; - - inode = iget_locked(sb, ino); + struct inode *inode = iget_locked(sb, ino); if (!inode) - return ERR_PTR(-ENOMEM); - if (inode->i_state & I_NEW) { - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - if (inode->i_ino == OPENPROM_ROOT_INO) { - inode->i_op = &openprom_inode_operations; - inode->i_fop = &openprom_operations; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - } - unlock_new_inode(inode); - } + inode = ERR_PTR(-ENOMEM); return inode; } @@ -394,9 +387,15 @@ static int openprom_fill_super(struct super_block *s, struct fs_context *fc) goto out_no_root; } + root_inode->i_mtime = root_inode->i_atime = + root_inode->i_ctime = current_time(root_inode); + root_inode->i_op = &openprom_inode_operations; + root_inode->i_fop = &openprom_operations; + root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; oi = OP_I(root_inode); oi->type = op_inode_node; oi->u.node = of_find_node_by_path("/"); + unlock_new_inode(root_inode); s->s_root = d_make_root(root_inode); if (!s->s_root) diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 9b28a7132466a9d2944131fce33384bcbc16cea0..ccef8c9dd51629c6d1b3ac18494852e072c6ef37 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -375,84 +375,6 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb, return ret; } -static int orangefs_getflags(struct inode *inode, unsigned long *uval) -{ - __u64 val = 0; - int ret; - - ret = orangefs_inode_getxattr(inode, - "user.pvfs2.meta_hint", - &val, sizeof(val)); - if (ret < 0 && ret != -ENODATA) - return ret; - else if (ret == -ENODATA) - val = 0; - *uval = val; - return 0; -} - -/* - * Perform a miscellaneous operation on a file. - */ -static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file_inode(file); - int ret = -ENOTTY; - __u64 val = 0; - unsigned long uval; - - gossip_debug(GOSSIP_FILE_DEBUG, - "orangefs_ioctl: called with cmd %d\n", - cmd); - - /* - * we understand some general ioctls on files, such as the immutable - * and append flags - */ - if (cmd == FS_IOC_GETFLAGS) { - ret = orangefs_getflags(inode, &uval); - if (ret) - return ret; - gossip_debug(GOSSIP_FILE_DEBUG, - "orangefs_ioctl: FS_IOC_GETFLAGS: %llu\n", - (unsigned long long)uval); - return put_user(uval, (int __user *)arg); - } else if (cmd == FS_IOC_SETFLAGS) { - unsigned long old_uval; - - ret = 0; - if (get_user(uval, (int __user *)arg)) - return -EFAULT; - /* - * ORANGEFS_MIRROR_FL is set internally when the mirroring mode - * is turned on for a file. The user is not allowed to turn - * on this bit, but the bit is present if the user first gets - * the flags and then updates the flags with some new - * settings. So, we ignore it in the following edit. bligon. - */ - if ((uval & ~ORANGEFS_MIRROR_FL) & - (~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NOATIME_FL))) { - gossip_err("orangefs_ioctl: the FS_IOC_SETFLAGS only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL\n"); - return -EINVAL; - } - ret = orangefs_getflags(inode, &old_uval); - if (ret) - return ret; - ret = vfs_ioc_setflags_prepare(inode, old_uval, uval); - if (ret) - return ret; - val = uval; - gossip_debug(GOSSIP_FILE_DEBUG, - "orangefs_ioctl: FS_IOC_SETFLAGS: %llu\n", - (unsigned long long)val); - ret = orangefs_inode_setxattr(inode, - "user.pvfs2.meta_hint", - &val, sizeof(val), 0); - } - - return ret; -} - static vm_fault_t orangefs_fault(struct vm_fault *vmf) { struct file *file = vmf->vma->vm_file; @@ -657,7 +579,6 @@ const struct file_operations orangefs_file_operations = { .read_iter = orangefs_file_read_iter, .write_iter = orangefs_file_write_iter, .lock = orangefs_lock, - .unlocked_ioctl = orangefs_ioctl, .mmap = orangefs_file_mmap, .open = generic_file_open, .splice_read = generic_file_splice_read, diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index 5079cfafa8d7a938859348d157a8b366f605ac4c..85b3dd2d769d26717b578beaab7e1e5f0a146d10 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -11,6 +11,7 @@ */ #include <linux/bvec.h> +#include <linux/fileattr.h> #include "protocol.h" #include "orangefs-kernel.h" #include "orangefs-bufmap.h" @@ -954,6 +955,53 @@ int orangefs_update_time(struct inode *inode, struct timespec64 *time, int flags return __orangefs_setattr(inode, &iattr); } +static int orangefs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + u64 val = 0; + int ret; + + gossip_debug(GOSSIP_FILE_DEBUG, "%s: called on %pd\n", __func__, + dentry); + + ret = orangefs_inode_getxattr(d_inode(dentry), + "user.pvfs2.meta_hint", + &val, sizeof(val)); + if (ret < 0 && ret != -ENODATA) + return ret; + + gossip_debug(GOSSIP_FILE_DEBUG, "%s: flags=%u\n", __func__, (u32) val); + + fileattr_fill_flags(fa, val); + return 0; +} + +static int orangefs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + u64 val = 0; + + gossip_debug(GOSSIP_FILE_DEBUG, "%s: called on %pd\n", __func__, + dentry); + /* + * ORANGEFS_MIRROR_FL is set internally when the mirroring mode is + * turned on for a file. The user is not allowed to turn on this bit, + * but the bit is present if the user first gets the flags and then + * updates the flags with some new settings. So, we ignore it in the + * following edit. bligon. + */ + if (fileattr_has_fsx(fa) || + (fa->flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NOATIME_FL | ORANGEFS_MIRROR_FL))) { + gossip_err("%s: only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL\n", + __func__); + return -EOPNOTSUPP; + } + val = fa->flags; + gossip_debug(GOSSIP_FILE_DEBUG, "%s: flags=%u\n", __func__, (u32) val); + return orangefs_inode_setxattr(d_inode(dentry), + "user.pvfs2.meta_hint", + &val, sizeof(val), 0); +} + /* ORANGEFS2 implementation of VFS inode operations for files */ static const struct inode_operations orangefs_file_inode_operations = { .get_acl = orangefs_get_acl, @@ -963,6 +1011,8 @@ static const struct inode_operations orangefs_file_inode_operations = { .listxattr = orangefs_listxattr, .permission = orangefs_permission, .update_time = orangefs_update_time, + .fileattr_get = orangefs_fileattr_get, + .fileattr_set = orangefs_fileattr_set, }; static int orangefs_init_iops(struct inode *inode) diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c index d4b7ae763186ce5da4606b33251386e5fb7318a2..46b7dcff18acedaa3b9ca07ac8ad812b3a90748c 100644 --- a/fs/orangefs/orangefs-utils.c +++ b/fs/orangefs/orangefs-utils.c @@ -221,7 +221,7 @@ static int orangefs_inode_is_stale(struct inode *inode, * If the inode type or symlink target have changed then this * inode is stale. */ - if (type == -1 || !(inode->i_mode & type)) { + if (type == -1 || inode_wrong_type(inode, type)) { orangefs_make_bad_inode(inode); return 1; } diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 836f14b9d3a65e179ff9a4f3ecd68e4017cee035..93efe7048a77173ac73410126e3224a9ec21f716 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -1301,4 +1301,6 @@ const struct inode_operations ovl_dir_inode_operations = { .listxattr = ovl_listxattr, .get_acl = ovl_get_acl, .update_time = ovl_update_time, + .fileattr_get = ovl_fileattr_get, + .fileattr_set = ovl_fileattr_set, }; diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 5c5fc305f212b822823b7c0a734cc1ddae1317b1..c7ea1962fc59fff11beecd0d5de4b4115ca5460d 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -469,112 +469,6 @@ static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice) return ret; } -static long ovl_real_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct fd real; - long ret; - - ret = ovl_real_fdget(file, &real); - if (ret) - return ret; - - ret = security_file_ioctl(real.file, cmd, arg); - if (!ret) { - /* - * Don't override creds, since we currently can't safely check - * permissions before doing so. - */ - ret = vfs_ioctl(real.file, cmd, arg); - } - - fdput(real); - - return ret; -} - -static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, - unsigned long arg) -{ - long ret; - struct inode *inode = file_inode(file); - - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - inode_lock(inode); - - /* - * Prevent copy up if immutable and has no CAP_LINUX_IMMUTABLE - * capability. - */ - ret = -EPERM; - if (!ovl_has_upperdata(inode) && IS_IMMUTABLE(inode) && - !capable(CAP_LINUX_IMMUTABLE)) - goto unlock; - - ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY); - if (ret) - goto unlock; - - ret = ovl_real_ioctl(file, cmd, arg); - - ovl_copyflags(ovl_inode_real(inode), inode); -unlock: - inode_unlock(inode); - - mnt_drop_write_file(file); - - return ret; - -} - -long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret; - - switch (cmd) { - case FS_IOC_GETFLAGS: - case FS_IOC_FSGETXATTR: - ret = ovl_real_ioctl(file, cmd, arg); - break; - - case FS_IOC_FSSETXATTR: - case FS_IOC_SETFLAGS: - ret = ovl_ioctl_set_flags(file, cmd, arg); - break; - - default: - ret = -ENOTTY; - } - - return ret; -} - -#ifdef CONFIG_COMPAT -long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; - - default: - return -ENOIOCTLCMD; - } - - return ovl_ioctl(file, cmd, arg); -} -#endif - enum ovl_copyop { OVL_COPY, OVL_CLONE, @@ -674,10 +568,6 @@ const struct file_operations ovl_file_operations = { .mmap = ovl_mmap, .fallocate = ovl_fallocate, .fadvise = ovl_fadvise, - .unlocked_ioctl = ovl_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ovl_compat_ioctl, -#endif .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 003cf83bf78a4520ec9257d00664a9c457e3b97c..c3c96b4b3b337b339c04195d4a500d2dfe89c7de 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -11,6 +11,8 @@ #include <linux/posix_acl.h> #include <linux/ratelimit.h> #include <linux/fiemap.h> +#include <linux/fileattr.h> +#include <linux/security.h> #include "overlayfs.h" @@ -500,6 +502,79 @@ static int ovl_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, return err; } +/* + * Work around the fact that security_file_ioctl() takes a file argument. + * Introducing security_inode_fileattr_get/set() hooks would solve this issue + * properly. + */ +static int ovl_security_fileattr(struct dentry *dentry, struct fileattr *fa, + bool set) +{ + struct path realpath; + struct file *file; + unsigned int cmd; + int err; + + ovl_path_real(dentry, &realpath); + file = dentry_open(&realpath, O_RDONLY, current_cred()); + if (IS_ERR(file)) + return PTR_ERR(file); + + if (set) + cmd = fa->fsx_valid ? FS_IOC_FSSETXATTR : FS_IOC_SETFLAGS; + else + cmd = fa->fsx_valid ? FS_IOC_FSGETXATTR : FS_IOC_GETFLAGS; + + err = security_file_ioctl(file, cmd, 0); + fput(file); + + return err; +} + +int ovl_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct dentry *upperdentry; + const struct cred *old_cred; + int err; + + err = ovl_want_write(dentry); + if (err) + goto out; + + err = ovl_copy_up(dentry); + if (!err) { + upperdentry = ovl_dentry_upper(dentry); + + old_cred = ovl_override_creds(inode->i_sb); + err = ovl_security_fileattr(dentry, fa, true); + if (!err) + err = vfs_fileattr_set(&init_user_ns, upperdentry, fa); + revert_creds(old_cred); + ovl_copyflags(ovl_inode_real(inode), inode); + } + ovl_drop_write(dentry); +out: + return err; +} + +int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct dentry *realdentry = ovl_dentry_real(dentry); + const struct cred *old_cred; + int err; + + old_cred = ovl_override_creds(inode->i_sb); + err = ovl_security_fileattr(dentry, fa, false); + if (!err) + err = vfs_fileattr_get(realdentry, fa); + revert_creds(old_cred); + + return err; +} + static const struct inode_operations ovl_file_inode_operations = { .setattr = ovl_setattr, .permission = ovl_permission, @@ -508,6 +583,8 @@ static const struct inode_operations ovl_file_inode_operations = { .get_acl = ovl_get_acl, .update_time = ovl_update_time, .fiemap = ovl_fiemap, + .fileattr_get = ovl_fileattr_get, + .fileattr_set = ovl_fileattr_set, }; static const struct inode_operations ovl_symlink_inode_operations = { diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index c7216c025999d9b3324a7f1b3c53e438f2783cb9..328d2329142139482315d919d4c6636fbba95446 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -372,7 +372,7 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected, return PTR_ERR(origin); if (upperdentry && !ovl_is_whiteout(upperdentry) && - ((d_inode(origin)->i_mode ^ d_inode(upperdentry)->i_mode) & S_IFMT)) + inode_wrong_type(d_inode(upperdentry), d_inode(origin)->i_mode)) goto invalid; if (!*stackp) @@ -731,7 +731,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper, index = ERR_PTR(-ESTALE); goto out; } else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) || - ((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) { + inode_wrong_type(inode, d_inode(origin)->i_mode)) { /* * Index should always be of the same file type as origin * except for the case of a whiteout index. A whiteout diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 95cff83786a5523d875350cdc72d1b89cbcd59b4..f38cb5e07eff82f43f1c27d57ddf53be36355633 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -519,8 +519,9 @@ struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr); extern const struct file_operations ovl_file_operations; int __init ovl_aio_request_cache_init(void); void ovl_aio_request_cache_destroy(void); -long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int ovl_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); /* copy_up.c */ int ovl_copy_up(struct dentry *dentry); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index f404a78e6b607bf1d2b854506ebb3f72cd8af8d2..1ddad09672559e95b5127a69361707bb6009afd7 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -963,10 +963,6 @@ const struct file_operations ovl_dir_operations = { .llseek = ovl_dir_llseek, .fsync = ovl_dir_fsync, .release = ovl_dir_release, - .unlocked_ioctl = ovl_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ovl_compat_ioctl, -#endif }; int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) diff --git a/fs/proc/array.c b/fs/proc/array.c index bb87e4d89cd8fc4e95c6bc277933ea2edddd3cf1..7ec59171f197fcc5cca96bed68ca7c74d5887a84 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -342,8 +342,10 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) seq_put_decimal_ull(m, "NoNewPrivs:\t", task_no_new_privs(p)); #ifdef CONFIG_SECCOMP seq_put_decimal_ull(m, "\nSeccomp:\t", p->seccomp.mode); +#ifdef CONFIG_SECCOMP_FILTER seq_put_decimal_ull(m, "\nSeccomp_filters:\t", atomic_read(&p->seccomp.filter_count)); +#endif #endif seq_puts(m, "\nSpeculation_Store_Bypass:\t"); switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) { diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index ca6d8a86728566520c896cda6b7b7986c3e35e36..fefe3d391d3af69b2205c95f9120ca4df9b0e46b 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -56,7 +56,7 @@ MODULE_PARM_DESC(mem_size, static unsigned int mem_type; module_param(mem_type, uint, 0400); MODULE_PARM_DESC(mem_type, - "set to 1 to try to use unbuffered memory (default 0)"); + "memory type: 0=write-combined (default), 1=unbuffered, 2=cached"); static int ramoops_max_reason = -1; module_param_named(max_reason, ramoops_max_reason, int, 0400); @@ -648,6 +648,10 @@ static int ramoops_parse_dt(struct platform_device *pdev, pdata->mem_size = resource_size(res); pdata->mem_address = res->start; + /* + * Setting "unbuffered" is deprecated and will be ignored if + * "mem_type" is also specified. + */ pdata->mem_type = of_property_read_bool(of_node, "unbuffered"); /* * Setting "no-dump-oops" is deprecated and will be ignored if @@ -666,6 +670,7 @@ static int ramoops_parse_dt(struct platform_device *pdev, field = value; \ } + parse_u32("mem-type", pdata->record_size, pdata->mem_type); parse_u32("record-size", pdata->record_size, 0); parse_u32("console-size", pdata->console_size, 0); parse_u32("ftrace-size", pdata->ftrace_size, 0); diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index fff363bfd4845abb0d86abcf272c21cad54c9b4e..fe5305028c6e2701a4c7d21062ac16c8b351fad5 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -396,6 +396,10 @@ void persistent_ram_zap(struct persistent_ram_zone *prz) persistent_ram_update_header_ecc(prz); } +#define MEM_TYPE_WCOMBINE 0 +#define MEM_TYPE_NONCACHED 1 +#define MEM_TYPE_NORMAL 2 + static void *persistent_ram_vmap(phys_addr_t start, size_t size, unsigned int memtype) { @@ -409,10 +413,20 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size, page_start = start - offset_in_page(start); page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); - if (memtype) + switch (memtype) { + case MEM_TYPE_NORMAL: + prot = PAGE_KERNEL; + break; + case MEM_TYPE_NONCACHED: prot = pgprot_noncached(PAGE_KERNEL); - else + break; + case MEM_TYPE_WCOMBINE: prot = pgprot_writecombine(PAGE_KERNEL); + break; + default: + pr_err("invalid mem_type=%d\n", memtype); + return NULL; + } pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL); if (!pages) { diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 1db0254bc38b26f68472f5752d97873d42451629..203a47232707c50c6a10664b2f3ae33cad3a65a6 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -258,4 +258,6 @@ const struct inode_operations reiserfs_file_inode_operations = { .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, .set_acl = reiserfs_set_acl, + .fileattr_get = reiserfs_fileattr_get, + .fileattr_set = reiserfs_fileattr_set, }; diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 4f1cbd9301792fb1ecb4884e925bc7854da5bbde..4b86ecf5817e3a227cee7cf82529211587df75db 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -10,6 +10,59 @@ #include <linux/uaccess.h> #include <linux/pagemap.h> #include <linux/compat.h> +#include <linux/fileattr.h> + +int reiserfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + + if (!reiserfs_attrs(inode->i_sb)) + return -ENOTTY; + + fileattr_fill_flags(fa, REISERFS_I(inode)->i_attrs); + + return 0; +} + +int reiserfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + unsigned int flags = fa->flags; + int err; + + reiserfs_write_lock(inode->i_sb); + + err = -ENOTTY; + if (!reiserfs_attrs(inode->i_sb)) + goto unlock; + + err = -EOPNOTSUPP; + if (fileattr_has_fsx(fa)) + goto unlock; + + /* + * Is it quota file? Do not allow user to mess with it + */ + err = -EPERM; + if (IS_NOQUOTA(inode)) + goto unlock; + + if ((flags & REISERFS_NOTAIL_FL) && S_ISREG(inode->i_mode)) { + err = reiserfs_unpack(inode); + if (err) + goto unlock; + } + sd_attrs_to_i_attrs(flags, inode); + REISERFS_I(inode)->i_attrs = flags; + inode->i_ctime = current_time(inode); + mark_inode_dirty(inode); + err = 0; +unlock: + reiserfs_write_unlock(inode->i_sb); + + return err; +} /* * reiserfs_ioctl - handler for ioctl for inode @@ -23,7 +76,6 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); - unsigned int flags; int err = 0; reiserfs_write_lock(inode->i_sb); @@ -32,7 +84,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case REISERFS_IOC_UNPACK: if (S_ISREG(inode->i_mode)) { if (arg) - err = reiserfs_unpack(inode, filp); + err = reiserfs_unpack(inode); } else err = -ENOTTY; break; @@ -40,63 +92,6 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * following two cases are taken from fs/ext2/ioctl.c by Remy * Card (card@masi.ibp.fr) */ - case REISERFS_IOC_GETFLAGS: - if (!reiserfs_attrs(inode->i_sb)) { - err = -ENOTTY; - break; - } - - flags = REISERFS_I(inode)->i_attrs; - err = put_user(flags, (int __user *)arg); - break; - case REISERFS_IOC_SETFLAGS:{ - if (!reiserfs_attrs(inode->i_sb)) { - err = -ENOTTY; - break; - } - - err = mnt_want_write_file(filp); - if (err) - break; - - if (!inode_owner_or_capable(&init_user_ns, inode)) { - err = -EPERM; - goto setflags_out; - } - if (get_user(flags, (int __user *)arg)) { - err = -EFAULT; - goto setflags_out; - } - /* - * Is it quota file? Do not allow user to mess with it - */ - if (IS_NOQUOTA(inode)) { - err = -EPERM; - goto setflags_out; - } - err = vfs_ioc_setflags_prepare(inode, - REISERFS_I(inode)->i_attrs, - flags); - if (err) - goto setflags_out; - if ((flags & REISERFS_NOTAIL_FL) && - S_ISREG(inode->i_mode)) { - int result; - - result = reiserfs_unpack(inode, filp); - if (result) { - err = result; - goto setflags_out; - } - } - sd_attrs_to_i_attrs(flags, inode); - REISERFS_I(inode)->i_attrs = flags; - inode->i_ctime = current_time(inode); - mark_inode_dirty(inode); -setflags_out: - mnt_drop_write_file(filp); - break; - } case REISERFS_IOC_GETVERSION: err = put_user(inode->i_generation, (int __user *)arg); break; @@ -138,12 +133,6 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, case REISERFS_IOC32_UNPACK: cmd = REISERFS_IOC_UNPACK; break; - case REISERFS_IOC32_GETFLAGS: - cmd = REISERFS_IOC_GETFLAGS; - break; - case REISERFS_IOC32_SETFLAGS: - cmd = REISERFS_IOC_SETFLAGS; - break; case REISERFS_IOC32_GETVERSION: cmd = REISERFS_IOC_GETVERSION; break; @@ -165,7 +154,7 @@ int reiserfs_commit_write(struct file *f, struct page *page, * Function try to convert tail from direct item into indirect. * It set up nopack attribute in the REISERFS_I(inode)->nopack */ -int reiserfs_unpack(struct inode *inode, struct file *filp) +int reiserfs_unpack(struct inode *inode) { int retval = 0; int index; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index e6eb05e2b2f1b95e887552fbf8f7ed03c5a16899..017db70d0f4864b17478c16878dbbed9b891dc12 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1660,6 +1660,8 @@ const struct inode_operations reiserfs_dir_inode_operations = { .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, .set_acl = reiserfs_set_acl, + .fileattr_get = reiserfs_fileattr_get, + .fileattr_set = reiserfs_fileattr_set, }; /* diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index 0ca2ac62e53424a55873cca4c429ae738313b506..3aa928ec527a88d402e6ec122e24ab968c717e12 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -18,8 +18,6 @@ /* the 32 bit compat definitions with int argument */ #define REISERFS_IOC32_UNPACK _IOW(0xCD, 1, int) -#define REISERFS_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define REISERFS_IOC32_SETFLAGS FS_IOC32_SETFLAGS #define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION #define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION @@ -3408,7 +3406,10 @@ __u32 r5_hash(const signed char *msg, int len); #define SPARE_SPACE 500 /* prototypes from ioctl.c */ +int reiserfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int reiserfs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); long reiserfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -int reiserfs_unpack(struct inode *inode, struct file *filp); +int reiserfs_unpack(struct inode *inode); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 1b9c7a387dc7101dc30011d943019893ce027143..3ffafc73acf028730e43c67b720dad467d519d84 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2408,7 +2408,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, * IO to work */ if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { - err = reiserfs_unpack(inode, NULL); + err = reiserfs_unpack(inode); if (err) { reiserfs_warning(sb, "super-6520", "Unpacking tail of quota file failed" diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index d9d8d7794eff265cf0a056e60fe12b4c14e62a4e..5bd8482e660aa798514f1cf11928aeaa3e67f9b2 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1637,6 +1637,8 @@ const struct inode_operations ubifs_dir_inode_operations = { .listxattr = ubifs_listxattr, .update_time = ubifs_update_time, .tmpfile = ubifs_tmpfile, + .fileattr_get = ubifs_fileattr_get, + .fileattr_set = ubifs_fileattr_set, }; const struct file_operations ubifs_dir_operations = { diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 0e4b4be3aa26ebe0314d2374b39e3b94adea7511..2e4e1d15996931c47132901b807615c2f554a464 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1648,6 +1648,8 @@ const struct inode_operations ubifs_file_inode_operations = { .getattr = ubifs_getattr, .listxattr = ubifs_listxattr, .update_time = ubifs_update_time, + .fileattr_get = ubifs_fileattr_get, + .fileattr_set = ubifs_fileattr_set, }; const struct inode_operations ubifs_symlink_inode_operations = { diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c index a4aaeea63893e2939303a4aead1dcf92f4519eca..dc3e26e9ed7b2b905f97f46d7f2b68f542ba8024 100644 --- a/fs/ubifs/gc.c +++ b/fs/ubifs/gc.c @@ -102,7 +102,8 @@ static int switch_gc_head(struct ubifs_info *c) * This function compares data nodes @a and @b. Returns %1 if @a has greater * inode or block number, and %-1 otherwise. */ -static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) +static int data_nodes_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { ino_t inuma, inumb; struct ubifs_info *c = priv; @@ -145,8 +146,8 @@ static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) * first and sorted by length in descending order. Directory entry nodes go * after inode nodes and are sorted in ascending hash valuer order. */ -static int nondata_nodes_cmp(void *priv, struct list_head *a, - struct list_head *b) +static int nondata_nodes_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { ino_t inuma, inumb; struct ubifs_info *c = priv; diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 2326d5122beb7e498922bd04ad75c45bef44267a..c6a86348778037fd0d06e0b10fe835f841988f93 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -14,6 +14,7 @@ #include <linux/compat.h> #include <linux/mount.h> +#include <linux/fileattr.h> #include "ubifs.h" /* Need to be kept consistent with checked flags in ioctl2ubifs() */ @@ -103,7 +104,7 @@ static int ubifs2ioctl(int ubifs_flags) static int setflags(struct inode *inode, int flags) { - int oldflags, err, release; + int err, release; struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_budget_req req = { .dirtied_ino = 1, @@ -114,11 +115,6 @@ static int setflags(struct inode *inode, int flags) return err; mutex_lock(&ui->ui_mutex); - oldflags = ubifs2ioctl(ui->flags); - err = vfs_ioc_setflags_prepare(inode, oldflags, flags); - if (err) - goto out_unlock; - ui->flags &= ~ioctl2ubifs(UBIFS_SETTABLE_IOCTL_FLAGS); ui->flags |= ioctl2ubifs(flags); ubifs_set_inode_flags(inode); @@ -132,54 +128,52 @@ static int setflags(struct inode *inode, int flags) if (IS_SYNC(inode)) err = write_inode_now(inode, 1); return err; +} -out_unlock: - mutex_unlock(&ui->ui_mutex); - ubifs_release_budget(c, &req); - return err; +int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa) +{ + struct inode *inode = d_inode(dentry); + int flags = ubifs2ioctl(ubifs_inode(inode)->flags); + + if (d_is_special(dentry)) + return -ENOTTY; + + dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags); + fileattr_fill_flags(fa, flags); + + return 0; } -long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +int ubifs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa) { - int flags, err; - struct inode *inode = file_inode(file); + struct inode *inode = d_inode(dentry); + int flags = fa->flags; - switch (cmd) { - case FS_IOC_GETFLAGS: - flags = ubifs2ioctl(ubifs_inode(inode)->flags); + if (d_is_special(dentry)) + return -ENOTTY; - dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags); - return put_user(flags, (int __user *) arg); + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; - case FS_IOC_SETFLAGS: { - if (IS_RDONLY(inode)) - return -EROFS; + if (flags & ~UBIFS_GETTABLE_IOCTL_FLAGS) + return -EOPNOTSUPP; - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; + flags &= UBIFS_SETTABLE_IOCTL_FLAGS; - if (get_user(flags, (int __user *) arg)) - return -EFAULT; + if (!S_ISDIR(inode->i_mode)) + flags &= ~FS_DIRSYNC_FL; - if (flags & ~UBIFS_GETTABLE_IOCTL_FLAGS) - return -EOPNOTSUPP; - flags &= UBIFS_SETTABLE_IOCTL_FLAGS; + dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags); + return setflags(inode, flags); +} - if (!S_ISDIR(inode->i_mode)) - flags &= ~FS_DIRSYNC_FL; +long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err; + struct inode *inode = file_inode(file); - /* - * Make sure the file-system is read-write and make sure it - * will not become read-only while we are changing the flags. - */ - err = mnt_want_write_file(file); - if (err) - return err; - dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags); - err = setflags(inode, flags); - mnt_drop_write_file(file); - return err; - } + switch (cmd) { case FS_IOC_SET_ENCRYPTION_POLICY: { struct ubifs_info *c = inode->i_sb->s_fs_info; diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 0f8a6a16421b4a7db2ec84bd979f94cf75923eae..4d17e5382b7410e6886c6337dd6eac9221fdf7d5 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -298,8 +298,8 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) * entries @a and @b by comparing their sequence numer. Returns %1 if @a has * greater sequence number and %-1 otherwise. */ -static int replay_entries_cmp(void *priv, struct list_head *a, - struct list_head *b) +static int replay_entries_cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct ubifs_info *c = priv; struct replay_entry *ra, *rb; diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 7fdfdbda4b8ae93b9365c7c8dd932fa10a1634ec..b65c599a386a490ea60db658268918969eaf3329 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -2053,6 +2053,9 @@ int ubifs_recover_size(struct ubifs_info *c, bool in_place); void ubifs_destroy_size_tree(struct ubifs_info *c); /* ioctl.c */ +int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int ubifs_fileattr_set(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); void ubifs_set_inode_flags(struct inode *inode); #ifdef CONFIG_COMPAT diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c index 7aee0ec63ade181131977072802f4802ffedb855..eac6788fc6cffc03c406419a92ffe35a16f121eb 100644 --- a/fs/vboxsf/dir.c +++ b/fs/vboxsf/dir.c @@ -225,7 +225,7 @@ static struct dentry *vboxsf_dir_lookup(struct inode *parent, } else { inode = vboxsf_new_inode(parent->i_sb); if (!IS_ERR(inode)) - vboxsf_init_inode(sbi, inode, &fsinfo); + vboxsf_init_inode(sbi, inode, &fsinfo, false); } return d_splice_alias(inode, dentry); @@ -245,7 +245,7 @@ static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry, sf_i = VBOXSF_I(inode); /* The host may have given us different attr then requested */ sf_i->force_restat = 1; - vboxsf_init_inode(sbi, inode, info); + vboxsf_init_inode(sbi, inode, info, false); d_instantiate(dentry, inode); diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c index d7816c01a4f62885f505001a752a80b2700dd82a..4f5e59f062846afb243333a08b6751616e8d03d0 100644 --- a/fs/vboxsf/super.c +++ b/fs/vboxsf/super.c @@ -207,7 +207,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc) err = -ENOMEM; goto fail_unmap; } - vboxsf_init_inode(sbi, iroot, &sbi->root_info); + vboxsf_init_inode(sbi, iroot, &sbi->root_info, false); unlock_new_inode(iroot); droot = d_make_root(iroot); @@ -418,7 +418,7 @@ static int vboxsf_reconfigure(struct fs_context *fc) /* Apply changed options to the root inode */ sbi->o = ctx->o; - vboxsf_init_inode(sbi, iroot, &sbi->root_info); + vboxsf_init_inode(sbi, iroot, &sbi->root_info, true); return 0; } diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c index 3b847e3fba24e5e3ea8580fc2263d64ae7312cf4..aec2ebf7d25ae8e0dd656a24d7d6fec677fda78d 100644 --- a/fs/vboxsf/utils.c +++ b/fs/vboxsf/utils.c @@ -45,12 +45,12 @@ struct inode *vboxsf_new_inode(struct super_block *sb) } /* set [inode] attributes based on [info], uid/gid based on [sbi] */ -void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, - const struct shfl_fsobjinfo *info) +int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, + const struct shfl_fsobjinfo *info, bool reinit) { const struct shfl_fsobjattr *attr; s64 allocated; - int mode; + umode_t mode; attr = &info->attr; @@ -75,29 +75,44 @@ void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, inode->i_mapping->a_ops = &vboxsf_reg_aops; if (SHFL_IS_DIRECTORY(attr->mode)) { - inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode; - inode->i_mode &= ~sbi->o.dmask; - inode->i_mode |= S_IFDIR; - inode->i_op = &vboxsf_dir_iops; - inode->i_fop = &vboxsf_dir_fops; - /* - * XXX: this probably should be set to the number of entries - * in the directory plus two (. ..) - */ - set_nlink(inode, 1); + if (sbi->o.dmode_set) + mode = sbi->o.dmode; + mode &= ~sbi->o.dmask; + mode |= S_IFDIR; + if (!reinit) { + inode->i_op = &vboxsf_dir_iops; + inode->i_fop = &vboxsf_dir_fops; + /* + * XXX: this probably should be set to the number of entries + * in the directory plus two (. ..) + */ + set_nlink(inode, 1); + } else if (!S_ISDIR(inode->i_mode)) + return -ESTALE; + inode->i_mode = mode; } else if (SHFL_IS_SYMLINK(attr->mode)) { - inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; - inode->i_mode &= ~sbi->o.fmask; - inode->i_mode |= S_IFLNK; - inode->i_op = &vboxsf_lnk_iops; - set_nlink(inode, 1); + if (sbi->o.fmode_set) + mode = sbi->o.fmode; + mode &= ~sbi->o.fmask; + mode |= S_IFLNK; + if (!reinit) { + inode->i_op = &vboxsf_lnk_iops; + set_nlink(inode, 1); + } else if (!S_ISLNK(inode->i_mode)) + return -ESTALE; + inode->i_mode = mode; } else { - inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; - inode->i_mode &= ~sbi->o.fmask; - inode->i_mode |= S_IFREG; - inode->i_op = &vboxsf_reg_iops; - inode->i_fop = &vboxsf_reg_fops; - set_nlink(inode, 1); + if (sbi->o.fmode_set) + mode = sbi->o.fmode; + mode &= ~sbi->o.fmask; + mode |= S_IFREG; + if (!reinit) { + inode->i_op = &vboxsf_reg_iops; + inode->i_fop = &vboxsf_reg_fops; + set_nlink(inode, 1); + } else if (!S_ISREG(inode->i_mode)) + return -ESTALE; + inode->i_mode = mode; } inode->i_uid = sbi->o.uid; @@ -116,6 +131,7 @@ void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, info->change_time.ns_relative_to_unix_epoch); inode->i_mtime = ns_to_timespec64( info->modification_time.ns_relative_to_unix_epoch); + return 0; } int vboxsf_create_at_dentry(struct dentry *dentry, @@ -199,7 +215,9 @@ int vboxsf_inode_revalidate(struct dentry *dentry) dentry->d_time = jiffies; sf_i->force_restat = 0; - vboxsf_init_inode(sbi, inode, &info); + err = vboxsf_init_inode(sbi, inode, &info, true); + if (err) + return err; /* * If the file was changed on the host side we need to invalidate the diff --git a/fs/vboxsf/vfsmod.h b/fs/vboxsf/vfsmod.h index 760524e78c886bb7b99f8775fb220a1385603557..6a7a9cedebc6e1708f6e593b3110a66e37c05740 100644 --- a/fs/vboxsf/vfsmod.h +++ b/fs/vboxsf/vfsmod.h @@ -82,8 +82,8 @@ extern const struct dentry_operations vboxsf_dentry_ops; /* from utils.c */ struct inode *vboxsf_new_inode(struct super_block *sb); -void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, - const struct shfl_fsobjinfo *info); +int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, + const struct shfl_fsobjinfo *info, bool reinit); int vboxsf_create_at_dentry(struct dentry *dentry, struct shfl_createparms *params); int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, diff --git a/fs/verity/Kconfig b/fs/verity/Kconfig index 88fb25119899d3fac6dc40fa1f64b1c9178f98b9..24d1b54de8079f8df6ff26924468685449b033e7 100644 --- a/fs/verity/Kconfig +++ b/fs/verity/Kconfig @@ -3,9 +3,13 @@ config FS_VERITY bool "FS Verity (read-only file-based authenticity protection)" select CRYPTO - # SHA-256 is selected as it's intended to be the default hash algorithm. + # SHA-256 is implied as it's intended to be the default hash algorithm. # To avoid bloat, other wanted algorithms must be selected explicitly. - select CRYPTO_SHA256 + # Note that CRYPTO_SHA256 denotes the generic C implementation, but + # some architectures provided optimized implementations of the same + # algorithm that may be used instead. In this case, CRYPTO_SHA256 may + # be omitted even if SHA-256 is being used. + imply CRYPTO_SHA256 help This option enables fs-verity. fs-verity is the dm-verity mechanism implemented at the file level. On supported diff --git a/fs/xattr.c b/fs/xattr.c index b3444e06cded4dfadd6501b96ce2ed1c61748e4e..5c8c5175b385c274eaac9a239ba0749b9372ff98 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -186,12 +186,12 @@ EXPORT_SYMBOL(__vfs_setxattr); * __vfs_setxattr_noperm - perform setxattr operation without performing * permission checks. * - * @mnt_userns - user namespace of the mount the inode was found from - * @dentry - object to perform setxattr on - * @name - xattr name to set - * @value - value to set @name to - * @size - size of @value - * @flags - flags to pass into filesystem operations + * @mnt_userns: user namespace of the mount the inode was found from + * @dentry: object to perform setxattr on + * @name: xattr name to set + * @value: value to set @name to + * @size: size of @value + * @flags: flags to pass into filesystem operations * * returns the result of the internal setxattr or setsecurity operations. * @@ -242,6 +242,7 @@ int __vfs_setxattr_noperm(struct user_namespace *mnt_userns, * __vfs_setxattr_locked - set an extended attribute while holding the inode * lock * + * @mnt_userns: user namespace of the mount of the target inode * @dentry: object to perform setxattr on * @name: xattr name to set * @value: value to set @name to @@ -473,6 +474,7 @@ EXPORT_SYMBOL(__vfs_removexattr); * __vfs_removexattr_locked - set an extended attribute while holding the inode * lock * + * @mnt_userns: user namespace of the mount of the target inode * @dentry: object to perform setxattr on * @name: name of xattr to remove * @delegated_inode: on return, will contain an inode pointer that diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 6fad140d4c8e57b113f1c39204e61eb57d4b4491..6bf7d8b7d7435258e894c2e22720aa508feaeca1 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -770,8 +770,6 @@ struct xfs_scrub_metadata { /* * ioctl commands that are used by Linux filesystems */ -#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS -#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS #define XFS_IOC_GETVERSION FS_IOC_GETVERSION /* @@ -782,8 +780,6 @@ struct xfs_scrub_metadata { #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) #define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) -#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR -#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) #define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) diff --git a/fs/xfs/scrub/bitmap.c b/fs/xfs/scrub/bitmap.c index f88694f22d059ac5a99286aa8e74c272b788e2e4..813b5f21911387e32045ba65daadafd9a51e1389 100644 --- a/fs/xfs/scrub/bitmap.c +++ b/fs/xfs/scrub/bitmap.c @@ -63,8 +63,8 @@ xbitmap_init( static int xbitmap_range_cmp( void *priv, - struct list_head *a, - struct list_head *b) + const struct list_head *a, + const struct list_head *b) { struct xbitmap_range *ap; struct xbitmap_range *bp; diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 2344757ede63c0dfa5ce1d15d11bd380d8d2ce8e..e3a691937e92f08258b2a4dfc20ce9d145356735 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -265,8 +265,8 @@ xfs_trans_log_finish_bmap_update( static int xfs_bmap_update_diff_items( void *priv, - struct list_head *a, - struct list_head *b) + const struct list_head *a, + const struct list_head *b) { struct xfs_bmap_intent *ba; struct xfs_bmap_intent *bb; diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 37a1d12762d8f54c3c438bf1f30eaf5086b8ccd3..592800c8852f45f8794405e7b738ec2afb938c22 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -2124,9 +2124,9 @@ xfs_buf_delwri_queue( */ static int xfs_buf_cmp( - void *priv, - struct list_head *a, - struct list_head *b) + void *priv, + const struct list_head *a, + const struct list_head *b) { struct xfs_buf *ap = container_of(a, struct xfs_buf, b_list); struct xfs_buf *bp = container_of(b, struct xfs_buf, b_list); diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c index ef17c1f6db32242bfbafc5e5f36fbfe661f306fc..a4075685d9ebaf25f407163313438b601e7b739b 100644 --- a/fs/xfs/xfs_extent_busy.c +++ b/fs/xfs/xfs_extent_busy.c @@ -629,8 +629,8 @@ xfs_extent_busy_wait_all( int xfs_extent_busy_ag_cmp( void *priv, - struct list_head *l1, - struct list_head *l2) + const struct list_head *l1, + const struct list_head *l2) { struct xfs_extent_busy *b1 = container_of(l1, struct xfs_extent_busy, list); diff --git a/fs/xfs/xfs_extent_busy.h b/fs/xfs/xfs_extent_busy.h index 990ab3891971730d3bfe2e060191d4e14ecaa9f0..8aea07100092397f4e1f5754c9b806ce5138cb9c 100644 --- a/fs/xfs/xfs_extent_busy.h +++ b/fs/xfs/xfs_extent_busy.h @@ -58,7 +58,8 @@ void xfs_extent_busy_wait_all(struct xfs_mount *mp); int -xfs_extent_busy_ag_cmp(void *priv, struct list_head *a, struct list_head *b); +xfs_extent_busy_ag_cmp(void *priv, const struct list_head *a, + const struct list_head *b); static inline void xfs_extent_busy_sort(struct list_head *list) { diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 93223ebb33721ed3fb8429d7e3f34e92935484c3..2424230ca2c3f6db7dae99b991532022bbfa1f36 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -397,8 +397,8 @@ xfs_trans_free_extent( static int xfs_extent_free_diff_items( void *priv, - struct list_head *a, - struct list_head *b) + const struct list_head *a, + const struct list_head *b) { struct xfs_mount *mp = priv; struct xfs_extent_free_item *ra; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index f93370bd7b1e387f35fc16b32bf058cc83002e5d..2a8bdf33e6c46bad9ae37352023a1fdda7a6c6f0 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -812,7 +812,7 @@ xfs_init_new_inode( if (dir && !(dir->i_mode & S_ISGID) && (mp->m_flags & XFS_MOUNT_GRPID)) { - inode->i_uid = fsuid_into_mnt(mnt_userns); + inode_fsuid_set(inode, mnt_userns); inode->i_gid = dir->i_gid; inode->i_mode = mode; } else { @@ -1007,8 +1007,8 @@ xfs_create( /* * Make sure that we have allocated dquot(s) on disk. */ - error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns), - fsgid_into_mnt(mnt_userns), prid, + error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), + mapped_fsgid(mnt_userns), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp); if (error) @@ -1158,8 +1158,8 @@ xfs_create_tmpfile( /* * Make sure that we have allocated dquot(s) on disk. */ - error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns), - fsgid_into_mnt(mnt_userns), prid, + error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), + mapped_fsgid(mnt_userns), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp); if (error) diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 99dfe89a8d08b82d966d9f833eb7761c62a1d3e6..bbda105a2ce504b4c3e46137ecb329bf9871abe9 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -40,6 +40,7 @@ #include <linux/mount.h> #include <linux/namei.h> +#include <linux/fileattr.h> /* * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to @@ -1053,73 +1054,15 @@ xfs_ioc_ag_geometry( * Linux extended inode flags interface. */ -STATIC unsigned int -xfs_merge_ioc_xflags( - unsigned int flags, - unsigned int start) -{ - unsigned int xflags = start; - - if (flags & FS_IMMUTABLE_FL) - xflags |= FS_XFLAG_IMMUTABLE; - else - xflags &= ~FS_XFLAG_IMMUTABLE; - if (flags & FS_APPEND_FL) - xflags |= FS_XFLAG_APPEND; - else - xflags &= ~FS_XFLAG_APPEND; - if (flags & FS_SYNC_FL) - xflags |= FS_XFLAG_SYNC; - else - xflags &= ~FS_XFLAG_SYNC; - if (flags & FS_NOATIME_FL) - xflags |= FS_XFLAG_NOATIME; - else - xflags &= ~FS_XFLAG_NOATIME; - if (flags & FS_NODUMP_FL) - xflags |= FS_XFLAG_NODUMP; - else - xflags &= ~FS_XFLAG_NODUMP; - if (flags & FS_DAX_FL) - xflags |= FS_XFLAG_DAX; - else - xflags &= ~FS_XFLAG_DAX; - - return xflags; -} - -STATIC unsigned int -xfs_di2lxflags( - uint16_t di_flags, - uint64_t di_flags2) -{ - unsigned int flags = 0; - - if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= FS_IMMUTABLE_FL; - if (di_flags & XFS_DIFLAG_APPEND) - flags |= FS_APPEND_FL; - if (di_flags & XFS_DIFLAG_SYNC) - flags |= FS_SYNC_FL; - if (di_flags & XFS_DIFLAG_NOATIME) - flags |= FS_NOATIME_FL; - if (di_flags & XFS_DIFLAG_NODUMP) - flags |= FS_NODUMP_FL; - if (di_flags2 & XFS_DIFLAG2_DAX) { - flags |= FS_DAX_FL; - } - return flags; -} - static void xfs_fill_fsxattr( struct xfs_inode *ip, - bool attr, - struct fsxattr *fa) + int whichfork, + struct fileattr *fa) { - struct xfs_ifork *ifp = attr ? ip->i_afp : &ip->i_df; + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - simple_fill_fsxattr(fa, xfs_ip2xflags(ip)); + fileattr_fill_xflags(fa, xfs_ip2xflags(ip)); fa->fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; fa->fsx_cowextsize = ip->i_d.di_cowextsize << ip->i_mount->m_sb.sb_blocklog; @@ -1131,19 +1074,33 @@ xfs_fill_fsxattr( } STATIC int -xfs_ioc_fsgetxattr( +xfs_ioc_fsgetxattra( xfs_inode_t *ip, - int attr, void __user *arg) { - struct fsxattr fa; + struct fileattr fa; xfs_ilock(ip, XFS_ILOCK_SHARED); - xfs_fill_fsxattr(ip, attr, &fa); + xfs_fill_fsxattr(ip, XFS_ATTR_FORK, &fa); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return copy_fsxattr_to_user(&fa, arg); +} + +int +xfs_fileattr_get( + struct dentry *dentry, + struct fileattr *fa) +{ + struct xfs_inode *ip = XFS_I(d_inode(dentry)); + + if (d_is_special(dentry)) + return -ENOTTY; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + xfs_fill_fsxattr(ip, XFS_DATA_FORK, fa); xfs_iunlock(ip, XFS_ILOCK_SHARED); - if (copy_to_user(arg, &fa, sizeof(fa))) - return -EFAULT; return 0; } @@ -1210,7 +1167,7 @@ static int xfs_ioctl_setattr_xflags( struct xfs_trans *tp, struct xfs_inode *ip, - struct fsxattr *fa) + struct fileattr *fa) { struct xfs_mount *mp = ip->i_mount; uint64_t di_flags2; @@ -1253,7 +1210,7 @@ xfs_ioctl_setattr_xflags( static void xfs_ioctl_setattr_prepare_dax( struct xfs_inode *ip, - struct fsxattr *fa) + struct fileattr *fa) { struct xfs_mount *mp = ip->i_mount; struct inode *inode = VFS_I(ip); @@ -1280,10 +1237,9 @@ xfs_ioctl_setattr_prepare_dax( */ static struct xfs_trans * xfs_ioctl_setattr_get_trans( - struct file *file, + struct xfs_inode *ip, struct xfs_dquot *pdqp) { - struct xfs_inode *ip = XFS_I(file_inode(file)); struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error = -EROFS; @@ -1299,24 +1255,11 @@ xfs_ioctl_setattr_get_trans( if (error) goto out_error; - /* - * CAP_FOWNER overrides the following restrictions: - * - * The user ID of the calling process must be equal to the file owner - * ID, except in cases where the CAP_FSETID capability is applicable. - */ - if (!inode_owner_or_capable(file_mnt_user_ns(file), VFS_I(ip))) { - error = -EPERM; - goto out_cancel; - } - if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(tp); return tp; -out_cancel: - xfs_trans_cancel(tp); out_error: return ERR_PTR(error); } @@ -1340,12 +1283,15 @@ out_error: static int xfs_ioctl_setattr_check_extsize( struct xfs_inode *ip, - struct fsxattr *fa) + struct fileattr *fa) { struct xfs_mount *mp = ip->i_mount; xfs_extlen_t size; xfs_fsblock_t extsize_fsb; + if (!fa->fsx_valid) + return 0; + if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents && ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize)) return -EINVAL; @@ -1390,12 +1336,15 @@ xfs_ioctl_setattr_check_extsize( static int xfs_ioctl_setattr_check_cowextsize( struct xfs_inode *ip, - struct fsxattr *fa) + struct fileattr *fa) { struct xfs_mount *mp = ip->i_mount; xfs_extlen_t size; xfs_fsblock_t cowextsize_fsb; + if (!fa->fsx_valid) + return 0; + if (!(fa->fsx_xflags & FS_XFLAG_COWEXTSIZE)) return 0; @@ -1422,8 +1371,11 @@ xfs_ioctl_setattr_check_cowextsize( static int xfs_ioctl_setattr_check_projid( struct xfs_inode *ip, - struct fsxattr *fa) + struct fileattr *fa) { + if (!fa->fsx_valid) + return 0; + /* Disallow 32bit project ids if projid32bit feature is not enabled. */ if (fa->fsx_projid > (uint16_t)-1 && !xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb)) @@ -1431,14 +1383,13 @@ xfs_ioctl_setattr_check_projid( return 0; } -STATIC int -xfs_ioctl_setattr( - struct file *file, - struct fsxattr *fa) +int +xfs_fileattr_set( + struct user_namespace *mnt_userns, + struct dentry *dentry, + struct fileattr *fa) { - struct user_namespace *mnt_userns = file_mnt_user_ns(file); - struct xfs_inode *ip = XFS_I(file_inode(file)); - struct fsxattr old_fa; + struct xfs_inode *ip = XFS_I(d_inode(dentry)); struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; struct xfs_dquot *pdqp = NULL; @@ -1447,6 +1398,16 @@ xfs_ioctl_setattr( trace_xfs_ioctl_setattr(ip); + if (d_is_special(dentry)) + return -ENOTTY; + + if (!fa->fsx_valid) { + if (fa->flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | + FS_NOATIME_FL | FS_NODUMP_FL | + FS_SYNC_FL | FS_DAX_FL | FS_PROJINHERIT_FL)) + return -EOPNOTSUPP; + } + error = xfs_ioctl_setattr_check_projid(ip, fa); if (error) return error; @@ -1459,7 +1420,7 @@ xfs_ioctl_setattr( * If the IDs do change before we take the ilock, we're covered * because the i_*dquot fields will get updated anyway. */ - if (XFS_IS_QUOTA_ON(mp)) { + if (fa->fsx_valid && XFS_IS_QUOTA_ON(mp)) { error = xfs_qm_vop_dqalloc(ip, VFS_I(ip)->i_uid, VFS_I(ip)->i_gid, fa->fsx_projid, XFS_QMOPT_PQUOTA, NULL, NULL, &pdqp); @@ -1469,17 +1430,12 @@ xfs_ioctl_setattr( xfs_ioctl_setattr_prepare_dax(ip, fa); - tp = xfs_ioctl_setattr_get_trans(file, pdqp); + tp = xfs_ioctl_setattr_get_trans(ip, pdqp); if (IS_ERR(tp)) { error = PTR_ERR(tp); goto error_free_dquots; } - xfs_fill_fsxattr(ip, false, &old_fa); - error = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, fa); - if (error) - goto error_trans_cancel; - error = xfs_ioctl_setattr_check_extsize(ip, fa); if (error) goto error_trans_cancel; @@ -1492,6 +1448,8 @@ xfs_ioctl_setattr( if (error) goto error_trans_cancel; + if (!fa->fsx_valid) + goto skip_xattr; /* * Change file ownership. Must be the owner or privileged. CAP_FSETID * overrides the following restrictions: @@ -1529,6 +1487,7 @@ xfs_ioctl_setattr( else ip->i_d.di_cowextsize = 0; +skip_xattr: error = xfs_trans_commit(tp); /* @@ -1546,91 +1505,6 @@ error_free_dquots: return error; } -STATIC int -xfs_ioc_fssetxattr( - struct file *filp, - void __user *arg) -{ - struct fsxattr fa; - int error; - - if (copy_from_user(&fa, arg, sizeof(fa))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - error = xfs_ioctl_setattr(filp, &fa); - mnt_drop_write_file(filp); - return error; -} - -STATIC int -xfs_ioc_getxflags( - xfs_inode_t *ip, - void __user *arg) -{ - unsigned int flags; - - flags = xfs_di2lxflags(ip->i_d.di_flags, ip->i_d.di_flags2); - if (copy_to_user(arg, &flags, sizeof(flags))) - return -EFAULT; - return 0; -} - -STATIC int -xfs_ioc_setxflags( - struct xfs_inode *ip, - struct file *filp, - void __user *arg) -{ - struct xfs_trans *tp; - struct fsxattr fa; - struct fsxattr old_fa; - unsigned int flags; - int error; - - if (copy_from_user(&flags, arg, sizeof(flags))) - return -EFAULT; - - if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ - FS_NOATIME_FL | FS_NODUMP_FL | \ - FS_SYNC_FL | FS_DAX_FL)) - return -EOPNOTSUPP; - - fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); - - error = mnt_want_write_file(filp); - if (error) - return error; - - xfs_ioctl_setattr_prepare_dax(ip, &fa); - - tp = xfs_ioctl_setattr_get_trans(filp, NULL); - if (IS_ERR(tp)) { - error = PTR_ERR(tp); - goto out_drop_write; - } - - xfs_fill_fsxattr(ip, false, &old_fa); - error = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, &fa); - if (error) { - xfs_trans_cancel(tp); - goto out_drop_write; - } - - error = xfs_ioctl_setattr_xflags(tp, ip, &fa); - if (error) { - xfs_trans_cancel(tp); - goto out_drop_write; - } - - error = xfs_trans_commit(tp); -out_drop_write: - mnt_drop_write_file(filp); - return error; -} - static bool xfs_getbmap_format( struct kgetbmap *p, @@ -2137,16 +2011,8 @@ xfs_file_ioctl( case XFS_IOC_GETVERSION: return put_user(inode->i_generation, (int __user *)arg); - case XFS_IOC_FSGETXATTR: - return xfs_ioc_fsgetxattr(ip, 0, arg); case XFS_IOC_FSGETXATTRA: - return xfs_ioc_fsgetxattr(ip, 1, arg); - case XFS_IOC_FSSETXATTR: - return xfs_ioc_fssetxattr(filp, arg); - case XFS_IOC_GETXFLAGS: - return xfs_ioc_getxflags(ip, arg); - case XFS_IOC_SETXFLAGS: - return xfs_ioc_setxflags(ip, filp, arg); + return xfs_ioc_fsgetxattra(ip, arg); case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: diff --git a/fs/xfs/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h index bab6a5a924077fff1a4631bb905602a7be4a8c33..28453a6d446185bed95f2e8b324e6e5f6a98f421 100644 --- a/fs/xfs/xfs_ioctl.h +++ b/fs/xfs/xfs_ioctl.h @@ -47,6 +47,17 @@ xfs_handle_to_dentry( void __user *uhandle, u32 hlen); +extern int +xfs_fileattr_get( + struct dentry *dentry, + struct fileattr *fa); + +extern int +xfs_fileattr_set( + struct user_namespace *mnt_userns, + struct dentry *dentry, + struct fileattr *fa); + extern long xfs_file_ioctl( struct file *filp, diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index 33c09ec8e6c02a913761ea23092013031d126cdb..e6506773ba5579a6f49222878ca66d3183853dc5 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c @@ -484,8 +484,6 @@ xfs_file_compat_ioctl( } #endif /* long changes size, but xfs only copiese out 32 bits */ - case XFS_IOC_GETXFLAGS_32: - case XFS_IOC_SETXFLAGS_32: case XFS_IOC_GETVERSION_32: cmd = _NATIVE_IOC(cmd, long); return xfs_file_ioctl(filp, cmd, p); diff --git a/fs/xfs/xfs_ioctl32.h b/fs/xfs/xfs_ioctl32.h index 053de7d894cd31427eaba31272096c75ea2e72ad..9929482bf35846bde3ace59e233dfb6aa2aa9d8e 100644 --- a/fs/xfs/xfs_ioctl32.h +++ b/fs/xfs/xfs_ioctl32.h @@ -17,8 +17,6 @@ */ /* stock kernel-level ioctls we support */ -#define XFS_IOC_GETXFLAGS_32 FS_IOC32_GETFLAGS -#define XFS_IOC_SETXFLAGS_32 FS_IOC32_SETFLAGS #define XFS_IOC_GETVERSION_32 FS_IOC32_GETVERSION /* diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 66ebccb5a6fffb64d10e6e15a99757d48c5f4799..e1f749b711f86bf1a45b69e6ae74d072dcd3bb16 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -21,6 +21,7 @@ #include "xfs_dir2.h" #include "xfs_iomap.h" #include "xfs_error.h" +#include "xfs_ioctl.h" #include <linux/posix_acl.h> #include <linux/security.h> @@ -1152,6 +1153,8 @@ static const struct inode_operations xfs_inode_operations = { .listxattr = xfs_vn_listxattr, .fiemap = xfs_vn_fiemap, .update_time = xfs_vn_update_time, + .fileattr_get = xfs_fileattr_get, + .fileattr_set = xfs_fileattr_set, }; static const struct inode_operations xfs_dir_inode_operations = { @@ -1177,6 +1180,8 @@ static const struct inode_operations xfs_dir_inode_operations = { .listxattr = xfs_vn_listxattr, .update_time = xfs_vn_update_time, .tmpfile = xfs_vn_tmpfile, + .fileattr_get = xfs_fileattr_get, + .fileattr_set = xfs_fileattr_set, }; static const struct inode_operations xfs_dir_ci_inode_operations = { @@ -1202,6 +1207,8 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .listxattr = xfs_vn_listxattr, .update_time = xfs_vn_update_time, .tmpfile = xfs_vn_tmpfile, + .fileattr_get = xfs_fileattr_get, + .fileattr_set = xfs_fileattr_set, }; static const struct inode_operations xfs_symlink_inode_operations = { diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 07ebccbbf4dfab8e270b9c4aca46800d1fceff2f..746f4eda724ce35d1d6adc50c399b3ba14cefb38 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -269,8 +269,8 @@ xfs_trans_log_finish_refcount_update( static int xfs_refcount_update_diff_items( void *priv, - struct list_head *a, - struct list_head *b) + const struct list_head *a, + const struct list_head *b) { struct xfs_mount *mp = priv; struct xfs_refcount_intent *ra; diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 49cebd68b6727b7eb378e7c8c6111308a78771ee..dc4f0c9f0897af385abfe02bf851a6422eb6bd97 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -337,8 +337,8 @@ xfs_trans_log_finish_rmap_update( static int xfs_rmap_update_diff_items( void *priv, - struct list_head *a, - struct list_head *b) + const struct list_head *a, + const struct list_head *b) { struct xfs_mount *mp = priv; struct xfs_rmap_intent *ra; diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 7f368b10ded1bf1673167c5fefa7be03be983b22..63edb4dbed4abbc123084f4c629d6dedc3965c43 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -182,8 +182,8 @@ xfs_symlink( /* * Make sure that we have allocated dquot(s) on disk. */ - error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns), - fsgid_into_mnt(mnt_userns), prid, + error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), + mapped_fsgid(mnt_userns), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp); if (error) diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 1538a6853822c930a6a5b8ed874e7dfaffa0ed80..1b4c458156959ef4754b82201ab3e6620e001534 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -362,7 +362,7 @@ * * A less-safe version of the macros is provided for optional use if the * compiler uses excessive CPU stack (for example, this may happen in the - * debug case if code optimzation is disabled.) + * debug case if code optimization is disabled.) */ /* Exit trace helper macro */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f28b097c658f474c89c071d80de7391809afdc67..3a82faac5767362b12401b0dd0a66c2cbe060319 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -78,6 +78,7 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev, bool acpi_dev_found(const char *hid); bool acpi_dev_present(const char *hid, const char *uid, s64 hrv); +bool acpi_reduced_hardware(void); #ifdef CONFIG_ACPI @@ -689,11 +690,30 @@ acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const cha struct acpi_device * acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv); +/** + * for_each_acpi_dev_match - iterate over ACPI devices that matching the criteria + * @adev: pointer to the matching ACPI device, NULL at the end of the loop + * @hid: Hardware ID of the device. + * @uid: Unique ID of the device, pass NULL to not check _UID + * @hrv: Hardware Revision of the device, pass -1 to not check _HRV + * + * The caller is responsible for invoking acpi_dev_put() on the returned device. + * + * FIXME: Due to above requirement there is a window that may invalidate @adev + * and next iteration will use a dangling pointer, e.g. in the case of a + * hotplug event. That said, the caller should ensure that this will never + * happen. + */ #define for_each_acpi_dev_match(adev, hid, uid, hrv) \ for (adev = acpi_dev_get_first_match_dev(hid, uid, hrv); \ adev; \ adev = acpi_dev_get_next_match_dev(adev, hid, uid, hrv)) +static inline struct acpi_device *acpi_dev_get(struct acpi_device *adev) +{ + return adev ? to_acpi_device(get_device(&adev->dev)) : NULL; +} + static inline void acpi_dev_put(struct acpi_device *adev) { put_device(&adev->dev); diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 94d356fcc4839169994bc96093d8f2c94bedce6d..8372b0e7fd156d5b6ce9270a8d54cfa86e971b56 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -11,18 +11,6 @@ #define ACPI_MAX_STRING 80 -/* - * Please update drivers/acpi/debug.c and Documentation/firmware-guide/acpi/debug.rst - * if you add to this list. - */ -#define ACPI_SBS_COMPONENT 0x00100000 -#define ACPI_FAN_COMPONENT 0x00200000 -#define ACPI_PCI_COMPONENT 0x00400000 -#define ACPI_CONTAINER_COMPONENT 0x01000000 -#define ACPI_SYSTEM_COMPONENT 0x02000000 -#define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000 -#define ACPI_PROCESSOR_COMPONENT 0x20000000 - /* * _HID definitions * HIDs must conform to ACPI spec(6.1.4) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 370293ee839909eb16225611bea3f732ff98739b..f8d44b06f3e3a41245c4d9a24e5f11e392fc4aef 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -12,7 +12,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20210105 +#define ACPI_CA_VERSION 0x20210331 #include <acpi/acconfig.h> #include <acpi/actypes.h> diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index 9bccac9becd798c6ddfe5f47c6d331c72e823c9e..8e2319bbd0a22a7d273eb8bbeb9f49c0126d3eed 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -381,7 +381,7 @@ struct acpi_resource_gpio { #define ACPI_IO_RESTRICT_OUTPUT 2 #define ACPI_IO_RESTRICT_NONE_PRESERVE 3 -/* Common structure for I2C, SPI, and UART serial descriptors */ +/* Common structure for I2C, SPI, UART, CSI2 serial descriptors */ #define ACPI_RESOURCE_SERIAL_COMMON \ u8 revision_id; \ @@ -403,6 +403,7 @@ ACPI_RESOURCE_SERIAL_COMMON}; #define ACPI_RESOURCE_SERIAL_TYPE_I2C 1 #define ACPI_RESOURCE_SERIAL_TYPE_SPI 2 #define ACPI_RESOURCE_SERIAL_TYPE_UART 3 +#define ACPI_RESOURCE_SERIAL_TYPE_CSI2 4 /* Values for slave_mode field above */ @@ -505,6 +506,11 @@ struct acpi_resource_uart_serialbus { #define ACPI_UART_CLEAR_TO_SEND (1<<6) #define ACPI_UART_REQUEST_TO_SEND (1<<7) +struct acpi_resource_csi2_serialbus { + ACPI_RESOURCE_SERIAL_COMMON u8 local_port_instance; + u8 phy_type; +}; + struct acpi_resource_pin_function { u8 revision_id; u8 pin_config; @@ -634,6 +640,7 @@ union acpi_resource_data { struct acpi_resource_i2c_serialbus i2c_serial_bus; struct acpi_resource_spi_serialbus spi_serial_bus; struct acpi_resource_uart_serialbus uart_serial_bus; + struct acpi_resource_csi2_serialbus csi2_serial_bus; struct acpi_resource_common_serialbus common_serial_bus; struct acpi_resource_pin_function pin_function; struct acpi_resource_pin_config pin_config; diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index af0a8c3b87b7e75e1fc84d46f0c04f4dee860cf0..ce59903c2695e61d1db245d27743887885878e4b 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -28,6 +28,7 @@ #define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */ #define ACPI_SIG_BGRT "BGRT" /* Boot Graphics Resource Table */ #define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */ +#define ACPI_SIG_CEDT "CEDT" /* CXL Early Discovery Table */ #define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */ #define ACPI_SIG_CSRT "CSRT" /* Core System Resource Table */ #define ACPI_SIG_DBG2 "DBG2" /* Debug Port table type 2 */ @@ -301,6 +302,49 @@ struct acpi_table_boot { u8 reserved[3]; }; +/******************************************************************************* + * + * CEDT - CXL Early Discovery Table + * Version 1 + * + * Conforms to the "CXL Early Discovery Table" (CXL 2.0) + * + ******************************************************************************/ + +struct acpi_table_cedt { + struct acpi_table_header header; /* Common ACPI table header */ +}; + +/* CEDT subtable header (Performance Record Structure) */ + +struct acpi_cedt_header { + u8 type; + u8 reserved; + u16 length; +}; + +/* Values for Type field above */ + +enum acpi_cedt_type { + ACPI_CEDT_TYPE_CHBS = 0, + ACPI_CEDT_TYPE_RESERVED = 1 +}; + +/* + * CEDT subtables + */ + +/* 0: CXL Host Bridge Structure */ + +struct acpi_cedt_chbs { + struct acpi_cedt_header header; + u32 uid; + u32 cxl_version; + u32 reserved; + u64 base; + u64 length; +}; + /******************************************************************************* * * CPEP - Corrected Platform Error Polling table (ACPI 4.0) @@ -1445,7 +1489,8 @@ struct acpi_hmat_locality { struct acpi_hmat_structure header; u8 flags; u8 data_type; - u16 reserved1; + u8 min_transfer_size; + u8 reserved1; u32 number_of_initiator_Pds; u32 number_of_target_Pds; u32 reserved2; @@ -1454,15 +1499,18 @@ struct acpi_hmat_locality { /* Masks for Flags field above */ -#define ACPI_HMAT_MEMORY_HIERARCHY (0x0F) +#define ACPI_HMAT_MEMORY_HIERARCHY (0x0F) /* Bits 0-3 */ -/* Values for Memory Hierarchy flag */ +/* Values for Memory Hierarchy flags */ #define ACPI_HMAT_MEMORY 0 #define ACPI_HMAT_LAST_LEVEL_CACHE 1 #define ACPI_HMAT_1ST_LEVEL_CACHE 2 #define ACPI_HMAT_2ND_LEVEL_CACHE 3 #define ACPI_HMAT_3RD_LEVEL_CACHE 4 +#define ACPI_HMAT_MINIMUM_XFER_SIZE 0x10 /* Bit 4: ACPI 6.4 */ +#define ACPI_HMAT_NON_SEQUENTIAL_XFERS 0x20 /* Bit 5: ACPI 6.4 */ + /* Values for data_type field above */ diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index d6478c430c99afeea2e3fce9f01ba531ea4c436c..18cafe3ebddc22926154d12f5c68a9e37162e6b9 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -36,6 +36,7 @@ #define ACPI_SIG_NFIT "NFIT" /* NVDIMM Firmware Interface Table */ #define ACPI_SIG_PCCT "PCCT" /* Platform Communications Channel Table */ #define ACPI_SIG_PDTT "PDTT" /* Platform Debug Trigger Table */ +#define ACPI_SIG_PHAT "PHAT" /* Platform Health Assessment Table */ #define ACPI_SIG_PMTT "PMTT" /* Platform Memory Topology Table */ #define ACPI_SIG_PPTT "PPTT" /* Processor Properties Topology Table */ #define ACPI_SIG_RASF "RASF" /* RAS Feature table */ @@ -67,7 +68,7 @@ * IORT - IO Remapping Table * * Conforms to "IO Remapping Table System Software on ARM Platforms", - * Document number: ARM DEN 0049D, March 2018 + * Document number: ARM DEN 0049E.b, Feb 2021 * ******************************************************************************/ @@ -85,7 +86,7 @@ struct acpi_iort_node { u8 type; u16 length; u8 revision; - u32 reserved; + u32 identifier; u32 mapping_count; u32 mapping_offset; char node_data[1]; @@ -99,7 +100,8 @@ enum acpi_iort_node_type { ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02, ACPI_IORT_NODE_SMMU = 0x03, ACPI_IORT_NODE_SMMU_V3 = 0x04, - ACPI_IORT_NODE_PMCG = 0x05 + ACPI_IORT_NODE_PMCG = 0x05, + ACPI_IORT_NODE_RMR = 0x06, }; struct acpi_iort_id_mapping { @@ -166,10 +168,11 @@ struct acpi_iort_root_complex { u8 reserved[3]; /* Reserved, must be zero */ }; -/* Values for ats_attribute field above */ +/* Masks for ats_attribute field above */ -#define ACPI_IORT_ATS_SUPPORTED 0x00000001 /* The root complex supports ATS */ -#define ACPI_IORT_ATS_UNSUPPORTED 0x00000000 /* The root complex doesn't support ATS */ +#define ACPI_IORT_ATS_SUPPORTED (1) /* The root complex ATS support */ +#define ACPI_IORT_PRI_SUPPORTED (1<<1) /* The root complex PRI support */ +#define ACPI_IORT_PASID_FWD_SUPPORTED (1<<2) /* The root complex PASID forward support */ struct acpi_iort_smmu { u64 base_address; /* SMMU base address */ @@ -240,6 +243,18 @@ struct acpi_iort_pmcg { u64 page1_base_address; }; +struct acpi_iort_rmr { + u32 flags; + u32 rmr_count; + u32 rmr_offset; +}; + +struct acpi_iort_rmr_desc { + u64 base_address; + u64 length; + u32 reserved; +}; + /******************************************************************************* * * IVRS - I/O Virtualization Reporting Structure @@ -276,6 +291,7 @@ struct acpi_ivrs_header { enum acpi_ivrs_type { ACPI_IVRS_TYPE_HARDWARE1 = 0x10, ACPI_IVRS_TYPE_HARDWARE2 = 0x11, + ACPI_IVRS_TYPE_HARDWARE3 = 0x40, ACPI_IVRS_TYPE_MEMORY1 = 0x20, ACPI_IVRS_TYPE_MEMORY2 = 0x21, ACPI_IVRS_TYPE_MEMORY3 = 0x22 @@ -364,7 +380,11 @@ enum acpi_ivrs_device_entry_type { ACPI_IVRS_TYPE_ALIAS_START = 67, /* Uses struct acpi_ivrs_device8a */ ACPI_IVRS_TYPE_EXT_SELECT = 70, /* Uses struct acpi_ivrs_device8b */ ACPI_IVRS_TYPE_EXT_START = 71, /* Uses struct acpi_ivrs_device8b */ - ACPI_IVRS_TYPE_SPECIAL = 72 /* Uses struct acpi_ivrs_device8c */ + ACPI_IVRS_TYPE_SPECIAL = 72, /* Uses struct acpi_ivrs_device8c */ + + /* Variable-length device entries */ + + ACPI_IVRS_TYPE_HID = 240 /* Uses ACPI_IVRS_DEVICE_HID */ }; /* Values for Data field above */ @@ -416,6 +436,16 @@ struct acpi_ivrs_device8c { #define ACPI_IVHD_IOAPIC 1 #define ACPI_IVHD_HPET 2 +/* Type 240: variable-length device entry */ + +struct acpi_ivrs_device_hid { + struct acpi_ivrs_de_header header; + u64 acpi_hid; + u64 acpi_cid; + u8 uid_type; + u8 uid_length; +}; + /* 0x20, 0x21, 0x22: I/O Virtualization Memory Definition Block (IVMD) */ struct acpi_ivrs_memory { @@ -516,7 +546,8 @@ enum acpi_madt_type { ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, - ACPI_MADT_TYPE_RESERVED = 16 /* 16 and greater are reserved */ + ACPI_MADT_TYPE_MULTIPROC_WAKEUP = 16, + ACPI_MADT_TYPE_RESERVED = 17 /* 17 and greater are reserved */ }; /* @@ -723,6 +754,15 @@ struct acpi_madt_generic_translator { u32 reserved2; }; +/* 16: Multiprocessor wakeup (ACPI 6.4) */ + +struct acpi_madt_multiproc_wakeup { + struct acpi_subtable_header header; + u16 mailbox_version; + u32 reserved; /* reserved - must be zero */ + u64 base_address; +}; + /* * Common flags fields for MADT subtables */ @@ -983,12 +1023,14 @@ struct acpi_nfit_system_address { u64 address; u64 length; u64 memory_mapping; + u64 location_cookie; /* ACPI 6.4 */ }; /* Flags */ #define ACPI_NFIT_ADD_ONLINE_ONLY (1) /* 00: Add/Online Operation Only */ #define ACPI_NFIT_PROXIMITY_VALID (1<<1) /* 01: Proximity Domain Valid */ +#define ACPI_NFIT_LOCATION_COOKIE_VALID (1<<2) /* 02: SPA location cookie valid (ACPI 6.4) */ /* Range Type GUIDs appear in the include/acuuid.h file */ @@ -1184,7 +1226,8 @@ enum acpi_pcct_type { ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 = 2, /* ACPI 6.1 */ ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE = 3, /* ACPI 6.2 */ ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE = 4, /* ACPI 6.2 */ - ACPI_PCCT_TYPE_RESERVED = 5 /* 5 and greater are reserved */ + ACPI_PCCT_TYPE_HW_REG_COMM_SUBSPACE = 5, /* ACPI 6.4 */ + ACPI_PCCT_TYPE_RESERVED = 6 /* 6 and greater are reserved */ }; /* @@ -1299,6 +1342,24 @@ struct acpi_pcct_ext_pcc_slave { u64 error_status_mask; }; +/* 5: HW Registers based Communications Subspace */ + +struct acpi_pcct_hw_reg { + struct acpi_subtable_header header; + u16 version; + u64 base_address; + u64 length; + struct acpi_generic_address doorbell_register; + u64 doorbell_preserve; + u64 doorbell_write; + struct acpi_generic_address cmd_complete_register; + u64 cmd_complete_mask; + struct acpi_generic_address error_status_register; + u64 error_status_mask; + u32 nominal_latency; + u32 min_turnaround_time; +}; + /* Values for doorbell flags above */ #define ACPI_PCCT_INTERRUPT_POLARITY (1) @@ -1355,6 +1416,66 @@ struct acpi_pdtt_channel { #define ACPI_PDTT_WAIT_COMPLETION (1<<1) #define ACPI_PDTT_TRIGGER_ORDER (1<<2) +/******************************************************************************* + * + * PHAT - Platform Health Assessment Table (ACPI 6.4) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_phat { + struct acpi_table_header header; /* Common ACPI table header */ +}; + +/* Common header for PHAT subtables that follow main table */ + +struct acpi_phat_header { + u16 type; + u16 length; + u8 revision; +}; + +/* Values for Type field above */ + +#define ACPI_PHAT_TYPE_FW_VERSION_DATA 0 +#define ACPI_PHAT_TYPE_FW_HEALTH_DATA 1 +#define ACPI_PHAT_TYPE_RESERVED 2 /* 0x02-0xFFFF are reserved */ + +/* + * PHAT subtables, correspond to Type in struct acpi_phat_header + */ + +/* 0: Firmware Version Data Record */ + +struct acpi_phat_version_data { + struct acpi_phat_header header; + u8 reserved[3]; + u32 element_count; +}; + +struct acpi_phat_version_element { + u8 guid[16]; + u64 version_value; + u32 producer_id; +}; + +/* 1: Firmware Health Data Record */ + +struct acpi_phat_health_data { + struct acpi_phat_header header; + u8 reserved[2]; + u8 health; + u8 device_guid[16]; + u32 device_specific_offset; /* Zero if no Device-specific data */ +}; + +/* Values for Health field above */ + +#define ACPI_PHAT_ERRORS_FOUND 0 +#define ACPI_PHAT_NO_ERRORS 1 +#define ACPI_PHAT_UNKNOWN_ERRORS 2 +#define ACPI_PHAT_ADVISORY 3 + /******************************************************************************* * * PMTT - Platform Memory Topology Table (ACPI 5.0) @@ -1364,7 +1485,11 @@ struct acpi_pdtt_channel { struct acpi_table_pmtt { struct acpi_table_header header; /* Common ACPI table header */ - u32 reserved; + u32 memory_device_count; + /* + * Immediately followed by: + * MEMORY_DEVICE memory_device_struct[memory_device_count]; + */ }; /* Common header for PMTT subtables that follow main table */ @@ -1375,6 +1500,12 @@ struct acpi_pmtt_header { u16 length; u16 flags; u16 reserved2; + u32 memory_device_count; /* Zero means no memory device structs follow */ + /* + * Immediately followed by: + * u8 type_specific_data[] + * MEMORY_DEVICE memory_device_struct[memory_device_count]; + */ }; /* Values for Type field above */ @@ -1382,7 +1513,8 @@ struct acpi_pmtt_header { #define ACPI_PMTT_TYPE_SOCKET 0 #define ACPI_PMTT_TYPE_CONTROLLER 1 #define ACPI_PMTT_TYPE_DIMM 2 -#define ACPI_PMTT_TYPE_RESERVED 3 /* 0x03-0xFF are reserved */ +#define ACPI_PMTT_TYPE_RESERVED 3 /* 0x03-0xFE are reserved */ +#define ACPI_PMTT_TYPE_VENDOR 0xFF /* Values for Flags field above */ @@ -1401,37 +1533,43 @@ struct acpi_pmtt_socket { u16 socket_id; u16 reserved; }; + /* + * Immediately followed by: + * MEMORY_DEVICE memory_device_struct[memory_device_count]; + */ /* 1: Memory Controller subtable */ struct acpi_pmtt_controller { struct acpi_pmtt_header header; - u32 read_latency; - u32 write_latency; - u32 read_bandwidth; - u32 write_bandwidth; - u16 access_width; - u16 alignment; + u16 controller_id; u16 reserved; - u16 domain_count; -}; - -/* 1a: Proximity Domain substructure */ - -struct acpi_pmtt_domain { - u32 proximity_domain; }; + /* + * Immediately followed by: + * MEMORY_DEVICE memory_device_struct[memory_device_count]; + */ /* 2: Physical Component Identifier (DIMM) */ struct acpi_pmtt_physical_component { struct acpi_pmtt_header header; - u16 component_id; - u16 reserved; - u32 memory_size; u32 bios_handle; }; +/* 0xFF: Vendor Specific Data */ + +struct acpi_pmtt_vendor_specific { + struct acpi_pmtt_header header; + u8 type_uuid[16]; + u8 specific[]; + /* + * Immediately followed by: + * u8 vendor_specific_data[]; + * MEMORY_DEVICE memory_device_struct[memory_device_count]; + */ +}; + /******************************************************************************* * * PPTT - Processor Properties Topology Table (ACPI 6.2) @@ -1485,6 +1623,12 @@ struct acpi_pptt_cache { u16 line_size; }; +/* 1: Cache Type Structure for PPTT version 3 */ + +struct acpi_pptt_cache_v1 { + u32 cache_id; +}; + /* Flags */ #define ACPI_PPTT_SIZE_PROPERTY_VALID (1) /* Physical property valid */ @@ -1494,6 +1638,7 @@ struct acpi_pptt_cache { #define ACPI_PPTT_CACHE_TYPE_VALID (1<<4) /* Cache type valid */ #define ACPI_PPTT_WRITE_POLICY_VALID (1<<5) /* Write policy valid */ #define ACPI_PPTT_LINE_SIZE_VALID (1<<6) /* Line size valid */ +#define ACPI_PPTT_CACHE_ID_VALID (1<<7) /* Cache ID valid */ /* Masks for Attributes */ @@ -1679,6 +1824,7 @@ enum acpi_sdev_type { /* Values for flags above */ #define ACPI_SDEV_HANDOFF_TO_UNSECURE_OS (1) +#define ACPI_SDEV_SECURE_COMPONENTS_PRESENT (1<<1) /* * SDEV subtables @@ -1694,6 +1840,46 @@ struct acpi_sdev_namespace { u16 vendor_data_length; }; +struct acpi_sdev_secure_component { + u16 secure_component_offset; + u16 secure_component_length; +}; + +/* + * SDEV sub-subtables ("Components") for above + */ +struct acpi_sdev_component { + struct acpi_sdev_header header; +}; + +/* Values for sub-subtable type above */ + +enum acpi_sac_type { + ACPI_SDEV_TYPE_ID_COMPONENT = 0, + ACPI_SDEV_TYPE_MEM_COMPONENT = 1 +}; + +struct acpi_sdev_id_component { + struct acpi_sdev_header header; + u16 hardware_id_offset; + u16 hardware_id_length; + u16 subsystem_id_offset; + u16 subsystem_id_length; + u16 hardware_revision; + u8 hardware_rev_present; + u8 class_code_present; + u8 pci_base_class; + u8 pci_sub_class; + u8 pci_programming_xface; +}; + +struct acpi_sdev_mem_component { + struct acpi_sdev_header header; + u32 reserved; + u64 memory_base_address; + u64 memory_length; +}; + /* 1: PCIe Endpoint Device Based Device Structure */ struct acpi_sdev_pcie { diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index df5f4b27f3aae2f056a4ea2932629fb3652196a0..86903ac5bbc52b61660ba4f26dfb475373da757e 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -33,6 +33,7 @@ #define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ #define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ #define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */ +#define ACPI_SIG_VIOT "VIOT" /* Virtual I/O Translation Table */ #define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */ #define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */ #define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */ @@ -285,7 +286,8 @@ struct acpi_srat_generic_affinity { /* Flags for struct acpi_srat_generic_affinity */ -#define ACPI_SRAT_GENERIC_AFFINITY_ENABLED (1) /* 00: Use affinity structure */ +#define ACPI_SRAT_GENERIC_AFFINITY_ENABLED (1) /* 00: Use affinity structure */ +#define ACPI_SRAT_ARCHITECTURAL_TRANSACTIONS (1<<1) /* ACPI 6.4 */ /******************************************************************************* * @@ -483,6 +485,72 @@ struct acpi_table_uefi { u16 data_offset; /* Offset of remaining data in table */ }; +/******************************************************************************* + * + * VIOT - Virtual I/O Translation Table + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_viot { + struct acpi_table_header header; /* Common ACPI table header */ + u16 node_count; + u16 node_offset; + u8 reserved[8]; +}; + +/* VIOT subtable header */ + +struct acpi_viot_header { + u8 type; + u8 reserved; + u16 length; +}; + +/* Values for Type field above */ + +enum acpi_viot_node_type { + ACPI_VIOT_NODE_PCI_RANGE = 0x01, + ACPI_VIOT_NODE_MMIO = 0x02, + ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI = 0x03, + ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO = 0x04, + ACPI_VIOT_RESERVED = 0x05 +}; + +/* VIOT subtables */ + +struct acpi_viot_pci_range { + struct acpi_viot_header header; + u32 endpoint_start; + u16 segment_start; + u16 segment_end; + u16 bdf_start; + u16 bdf_end; + u16 output_node; + u8 reserved[6]; +}; + +struct acpi_viot_mmio { + struct acpi_viot_header header; + u32 endpoint; + u64 base_address; + u16 output_node; + u8 reserved[6]; +}; + +struct acpi_viot_virtio_iommu_pci { + struct acpi_viot_header header; + u16 segment; + u16 bdf; + u8 reserved[8]; +}; + +struct acpi_viot_virtio_iommu_mmio { + struct acpi_viot_header header; + u8 reserved[4]; + u64 base_address; +}; + /******************************************************************************* * * WAET - Windows ACPI Emulated devices Table diff --git a/include/acpi/acuuid.h b/include/acpi/acuuid.h index a5c2ca019a12c62d677b13ad1c350a69ef09b131..bc24388ce94e246649ea5d644817c17250764591 100644 --- a/include/acpi/acuuid.h +++ b/include/acpi/acuuid.h @@ -68,5 +68,6 @@ #define UUID_DEVICE_GRAPHS "ab02a46b-74c7-45a2-bd68-f7d344ef2153" #define UUID_HIERARCHICAL_DATA_EXTENSION "dbb8e3e6-5886-4ba6-8795-1319f52a966b" #define UUID_CORESIGHT_GRAPH "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd" +#define UUID_USB4_CAPABILITIES "23a0d13a-26ab-486c-9c5f-0ffa525a575a" #endif /* __ACUUID_H__ */ diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index c7fc4524e1514a6eb17597954730157884776808..9f4985b4d64dedef391b46a7b7189e2aeccbf8a9 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h @@ -11,6 +11,7 @@ #define _CPPC_ACPI_H #include <linux/acpi.h> +#include <linux/cpufreq.h> #include <linux/types.h> #include <acpi/pcc.h> @@ -132,6 +133,7 @@ struct cppc_cpudata { cpumask_var_t shared_cpu_map; }; +#ifdef CONFIG_ACPI_CPPC_LIB extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); @@ -142,5 +144,43 @@ extern unsigned int cppc_get_transition_latency(int cpu); extern bool cpc_ffh_supported(void); extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val); extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val); +#else /* !CONFIG_ACPI_CPPC_LIB */ +static inline int cppc_get_desired_perf(int cpunum, u64 *desired_perf) +{ + return -ENOTSUPP; +} +static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs) +{ + return -ENOTSUPP; +} +static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) +{ + return -ENOTSUPP; +} +static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps) +{ + return -ENOTSUPP; +} +static inline bool acpi_cpc_valid(void) +{ + return false; +} +static inline unsigned int cppc_get_transition_latency(int cpu) +{ + return CPUFREQ_ETERNAL; +} +static inline bool cpc_ffh_supported(void) +{ + return false; +} +static inline int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val) +{ + return -ENOTSUPP; +} +static inline int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val) +{ + return -ENOTSUPP; +} +#endif /* !CONFIG_ACPI_CPPC_LIB */ #endif /* _CPPC_ACPI_H*/ diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 0cd4f61d4248d5668adc88b6d973c2cb9cedf6c9..f6656be81760e17ceba1a1189abb0a67ddcc18f4 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -61,7 +61,7 @@ typedef __builtin_va_list va_list; #endif /* - * Explictly mark intentional explicit fallthrough to silence + * Explicitly mark intentional explicit fallthrough to silence * -Wimplicit-fallthrough in GCC 7.1+. */ diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index 76a10e0dca9fc7559ad57268c155fbf665583f73..b402494883b682e8d0fdea0a702a37ee93078632 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -241,6 +241,22 @@ void __warn(const char *file, int line, void *caller, unsigned taint, # define WARN_ON_SMP(x) ({0;}) #endif +/* + * WARN_ON_FUNCTION_MISMATCH() warns if a value doesn't match a + * function address, and can be useful for catching issues with + * callback functions, for example. + * + * With CONFIG_CFI_CLANG, the warning is disabled because the + * compiler replaces function addresses taken in C code with + * local jump table addresses, which breaks cross-module function + * address equality. + */ +#if defined(CONFIG_CFI_CLANG) && defined(CONFIG_MODULES) +# define WARN_ON_FUNCTION_MISMATCH(x, fn) ({ 0; }) +#else +# define WARN_ON_FUNCTION_MISMATCH(x, fn) WARN_ON_ONCE((x) != (fn)) +#endif + #endif /* __ASSEMBLY__ */ #endif diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h index 83448e837dedb82fac90f8d52d26620605d01ff1..515c3fb06ab3fc3dba39a3d6ba0de030359db795 100644 --- a/include/asm-generic/hyperv-tlfs.h +++ b/include/asm-generic/hyperv-tlfs.h @@ -89,9 +89,9 @@ #define HV_ACCESS_STATS BIT(8) #define HV_DEBUGGING BIT(11) #define HV_CPU_MANAGEMENT BIT(12) +#define HV_ENABLE_EXTENDED_HYPERCALLS BIT(20) #define HV_ISOLATION BIT(22) - /* * TSC page layout. */ @@ -159,11 +159,18 @@ struct ms_hyperv_tsc_page { #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 +/* Extended hypercalls */ +#define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001 +#define HV_EXT_CALL_MEMORY_HEAT_HINT 0x8003 + #define HV_FLUSH_ALL_PROCESSORS BIT(0) #define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1) #define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2) #define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3) +/* Extended capability bits */ +#define HV_EXT_CAPABILITY_MEMORY_COLD_DISCARD_HINT BIT(8) + enum HV_GENERIC_SET_FORMAT { HV_GENERIC_SET_SPARSE_4K, HV_GENERIC_SET_ALL, @@ -220,6 +227,41 @@ enum HV_GENERIC_SET_FORMAT { #define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) #define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) +/* + * Define hypervisor message types. Some of the message types + * are x86/x64 specific, but there's no good way to separate + * them out into the arch-specific version of hyperv-tlfs.h + * because C doesn't provide a way to extend enum types. + * Keeping them all in the arch neutral hyperv-tlfs.h seems + * the least messy compromise. + */ +enum hv_message_type { + HVMSG_NONE = 0x00000000, + + /* Memory access messages. */ + HVMSG_UNMAPPED_GPA = 0x80000000, + HVMSG_GPA_INTERCEPT = 0x80000001, + + /* Timer notification messages. */ + HVMSG_TIMER_EXPIRED = 0x80000010, + + /* Error messages. */ + HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020, + HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021, + HVMSG_UNSUPPORTED_FEATURE = 0x80000022, + + /* Trace buffer complete messages. */ + HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040, + + /* Platform-specific processor intercept messages. */ + HVMSG_X64_IOPORT_INTERCEPT = 0x80010000, + HVMSG_X64_MSR_INTERCEPT = 0x80010001, + HVMSG_X64_CPUID_INTERCEPT = 0x80010002, + HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, + HVMSG_X64_APIC_EOI = 0x80010004, + HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 +}; + /* Define synthetic interrupt controller message flags. */ union hv_message_flags { __u8 asu8; @@ -373,8 +415,10 @@ struct hv_guest_mapping_flush { * by the bitwidth of "additional_pages" in union hv_gpa_page_range. */ #define HV_MAX_FLUSH_PAGES (2048) +#define HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB 0 +#define HV_GPA_PAGE_RANGE_PAGE_SIZE_1GB 1 -/* HvFlushGuestPhysicalAddressList hypercall */ +/* HvFlushGuestPhysicalAddressList, HvExtCallMemoryHeatHint hypercall */ union hv_gpa_page_range { u64 address_space; struct { @@ -382,6 +426,12 @@ union hv_gpa_page_range { u64 largepage:1; u64 basepfn:52; } page; + struct { + u64 reserved:12; + u64 page_size:1; + u64 reserved1:8; + u64 base_large_pfn:43; + }; }; /* @@ -739,4 +789,20 @@ struct hv_input_unmap_device_interrupt { #define HV_SOURCE_SHADOW_NONE 0x0 #define HV_SOURCE_SHADOW_BRIDGE_BUS_RANGE 0x1 +/* + * The whole argument should fit in a page to be able to pass to the hypervisor + * in one hypercall. + */ +#define HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES \ + ((HV_HYP_PAGE_SIZE - sizeof(struct hv_memory_hint)) / \ + sizeof(union hv_gpa_page_range)) + +/* HvExtCallMemoryHeatHint hypercall */ +#define HV_EXT_MEMORY_HEAT_HINT_TYPE_COLD_DISCARD 2 +struct hv_memory_hint { + u64 type:2; + u64 reserved:62; + union hv_gpa_page_range ranges[]; +} __packed; + #endif diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index c6af40ce03befec1740fd9ab705648e1eba2bf81..76d456c516a137d225357b7fdea978a0826cd2c8 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -942,7 +942,9 @@ static inline void *phys_to_virt(unsigned long address) * * ioremap_wc() and ioremap_wt() can provide more relaxed caching attributes * for specific drivers if the architecture choses to implement them. If they - * are not implemented we fall back to plain ioremap. + * are not implemented we fall back to plain ioremap. Conversely, ioremap_np() + * can provide stricter non-posted write semantics if the architecture + * implements them. */ #ifndef CONFIG_MMU #ifndef ioremap @@ -995,6 +997,23 @@ static inline void __iomem *ioremap_uc(phys_addr_t offset, size_t size) } #endif +/* + * ioremap_np needs an explicit architecture implementation, as it + * requests stronger semantics than regular ioremap(). Portable drivers + * should instead use one of the higher-level abstractions, like + * devm_ioremap_resource(), to choose the correct variant for any given + * device and bus. Portable drivers with a good reason to want non-posted + * write semantics should always provide an ioremap() fallback in case + * ioremap_np() is not available. + */ +#ifndef ioremap_np +#define ioremap_np ioremap_np +static inline void __iomem *ioremap_np(phys_addr_t offset, size_t size) +{ + return NULL; +} +#endif + #ifdef CONFIG_HAS_IOPORT_MAP #ifndef CONFIG_GENERIC_IOMAP #ifndef ioport_map diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h index 6492246649693bdfce927be48bdf700890588121..9b3eb6d86200180d1fe6ff40687c807bb6107bc4 100644 --- a/include/asm-generic/iomap.h +++ b/include/asm-generic/iomap.h @@ -101,6 +101,15 @@ extern void ioport_unmap(void __iomem *); #define ioremap_wt ioremap #endif +#ifndef ARCH_HAS_IOREMAP_NP +/* See the comment in asm-generic/io.h about ioremap_np(). */ +#define ioremap_np ioremap_np +static inline void __iomem *ioremap_np(phys_addr_t offset, size_t size) +{ + return NULL; +} +#endif + #ifdef CONFIG_PCI /* Destroy a virtual mapping cookie for a PCI BAR (memory or IO) */ struct pci_dev; diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index dff58a3db5d5c9f3e5a6b20337ea826c3759f7aa..9a000ba2bb754bbcd4b61381b951c1bb8e17bacf 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -27,7 +27,7 @@ struct ms_hyperv_info { u32 features; - u32 features_b; + u32 priv_high; u32 misc_features; u32 hints; u32 nested_features; @@ -41,6 +41,53 @@ extern struct ms_hyperv_info ms_hyperv; extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); +/* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ +static inline int hv_result(u64 status) +{ + return status & HV_HYPERCALL_RESULT_MASK; +} + +static inline bool hv_result_success(u64 status) +{ + return hv_result(status) == HV_STATUS_SUCCESS; +} + +static inline unsigned int hv_repcomp(u64 status) +{ + /* Bits [43:32] of status have 'Reps completed' data. */ + return (status & HV_HYPERCALL_REP_COMP_MASK) >> + HV_HYPERCALL_REP_COMP_OFFSET; +} + +/* + * Rep hypercalls. Callers of this functions are supposed to ensure that + * rep_count and varhead_size comply with Hyper-V hypercall definition. + */ +static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, + void *input, void *output) +{ + u64 control = code; + u64 status; + u16 rep_comp; + + control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; + control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; + + do { + status = hv_do_hypercall(control, input, output); + if (!hv_result_success(status)) + return status; + + rep_comp = hv_repcomp(status); + + control &= ~HV_HYPERCALL_REP_START_MASK; + control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; + + touch_nmi_watchdog(); + } while (rep_comp < rep_count); + + return status; +} /* Generate the guest OS identifier as described in the Hyper-V TLFS */ static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, @@ -56,7 +103,6 @@ static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, return guest_id; } - /* Free the message slot and signal end-of-message if required */ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) { @@ -88,14 +134,14 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) * possibly deliver another msg from the * hypervisor */ - hv_signal_eom(); + hv_set_register(HV_REGISTER_EOM, 0); } } -int hv_setup_vmbus_irq(int irq, void (*handler)(void)); -void hv_remove_vmbus_irq(void); -void hv_enable_vmbus_irq(void); -void hv_disable_vmbus_irq(void); +void hv_setup_vmbus_handler(void (*handler)(void)); +void hv_remove_vmbus_handler(void); +void hv_setup_stimer0_handler(void (*handler)(void)); +void hv_remove_stimer0_handler(void); void hv_setup_kexec_handler(void (*handler)(void)); void hv_remove_kexec_handler(void); @@ -103,6 +149,7 @@ void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); void hv_remove_crash_handler(void); extern int vmbus_interrupt; +extern int vmbus_irq; #if IS_ENABLED(CONFIG_HYPERV) /* @@ -117,6 +164,10 @@ extern u32 hv_max_vp_index; /* Sentinel value for an uninitialized entry in hv_vp_index array */ #define VP_INVAL U32_MAX +void *hv_alloc_hyperv_page(void); +void *hv_alloc_hyperv_zeroed_page(void); +void hv_free_hyperv_page(unsigned long addr); + /** * hv_cpu_number_to_vp_number() - Map CPU to VP. * @cpu_number: CPU number in Linux terms @@ -169,21 +220,16 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset, } void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); -void hyperv_report_panic_msg(phys_addr_t pa, size_t size); bool hv_is_hyperv_initialized(void); bool hv_is_hibernation_supported(void); enum hv_isolation_type hv_get_isolation_type(void); bool hv_is_isolation_supported(void); void hyperv_cleanup(void); +bool hv_query_ext_cap(u64 cap_query); #else /* CONFIG_HYPERV */ static inline bool hv_is_hyperv_initialized(void) { return false; } static inline bool hv_is_hibernation_supported(void) { return false; } static inline void hyperv_cleanup(void) {} #endif /* CONFIG_HYPERV */ -#if IS_ENABLED(CONFIG_HYPERV) -extern int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void)); -extern void hv_remove_stimer0_irq(int irq); -#endif - #endif diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 0331d5d49551a305b92a628f4e20e8f5a7cd72a3..40a9c101565ebe120e537eb0e12b471f25a6612a 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -544,6 +544,22 @@ . = ALIGN((align)); \ __end_rodata = .; + +/* + * .text..L.cfi.jumptable.* contain Control-Flow Integrity (CFI) + * jump table entries. + */ +#ifdef CONFIG_CFI_CLANG +#define TEXT_CFI_JT \ + . = ALIGN(PMD_SIZE); \ + __cfi_jt_start = .; \ + *(.text..L.cfi.jumptable .text..L.cfi.jumptable.*) \ + . = ALIGN(PMD_SIZE); \ + __cfi_jt_end = .; +#else +#define TEXT_CFI_JT +#endif + /* * Non-instrumentable text section */ @@ -570,6 +586,7 @@ NOINSTR_TEXT \ *(.text..refcount) \ *(.ref.text) \ + TEXT_CFI_JT \ MEM_KEEP(init.text*) \ MEM_KEEP(exit.text*) \ @@ -974,7 +991,8 @@ * keep any .init_array.* sections. * https://bugs.llvm.org/show_bug.cgi?id=46478 */ -#if defined(CONFIG_GCOV_KERNEL) || defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN) +#if defined(CONFIG_GCOV_KERNEL) || defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN) || \ + defined(CONFIG_CFI_CLANG) # ifdef CONFIG_CONSTRUCTORS # define SANITIZER_DISCARDS \ *(.eh_frame) diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 1d68d5613daebf59779d277877d49fd58064e043..73c7139c866fadccbd0aec9dbceafe5c325b2206 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -32,6 +32,7 @@ enum arch_timer_ppi_nr { ARCH_TIMER_PHYS_NONSECURE_PPI, ARCH_TIMER_VIRT_PPI, ARCH_TIMER_HYP_PPI, + ARCH_TIMER_HYP_VIRT_PPI, ARCH_TIMER_MAX_TIMER_PPI }; diff --git a/include/clocksource/hyperv_timer.h b/include/clocksource/hyperv_timer.h index 34eef083c9882fafbd3bf5cc25a0dd5fdb38b06d..b6774aa5a4b865fa4b0b32c20d7315bf3cf96ea4 100644 --- a/include/clocksource/hyperv_timer.h +++ b/include/clocksource/hyperv_timer.h @@ -21,8 +21,7 @@ #define HV_MIN_DELTA_TICKS 1 /* Routines called by the VMbus driver */ -extern int hv_stimer_alloc(void); -extern void hv_stimer_free(void); +extern int hv_stimer_alloc(bool have_percpu_irqs); extern int hv_stimer_cleanup(unsigned int cpu); extern void hv_stimer_legacy_init(unsigned int cpu, int sint); extern void hv_stimer_legacy_cleanup(unsigned int cpu); diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h index fcde59c65a81b2a9ff6204ae79416a520ee1f057..cb3d6b1c655decb8bf092c7a97b73897fe1a79b8 100644 --- a/include/crypto/acompress.h +++ b/include/crypto/acompress.h @@ -165,6 +165,8 @@ static inline struct crypto_acomp *crypto_acomp_reqtfm(struct acomp_req *req) * crypto_free_acomp() -- free ACOMPRESS tfm handle * * @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp() + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_acomp(struct crypto_acomp *tfm) { diff --git a/include/crypto/aead.h b/include/crypto/aead.h index fcc12c593ef8b4a59ca9e20e6e88588e84a62bc2..e728469c4cccb3aa56835b042ee83373377acf24 100644 --- a/include/crypto/aead.h +++ b/include/crypto/aead.h @@ -185,6 +185,8 @@ static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm) /** * crypto_free_aead() - zeroize and free aead handle * @tfm: cipher handle to be freed + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_aead(struct crypto_aead *tfm) { diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index 1d3aa252cabafba10df19f4128d3718c9a106cc2..5764b46bd1ec18165b70e7b88003145e34da0dac 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -174,6 +174,8 @@ static inline struct crypto_akcipher *crypto_akcipher_reqtfm( * crypto_free_akcipher() - free AKCIPHER tfm handle * * @tfm: AKCIPHER tfm handle allocated with crypto_alloc_akcipher() + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_akcipher(struct crypto_akcipher *tfm) { diff --git a/include/crypto/chacha.h b/include/crypto/chacha.h index 3a1c72fdb7cf5b468c881a1c2149c0afcdf282e2..dabaee6987186b9890deb81c721cecbc171708a3 100644 --- a/include/crypto/chacha.h +++ b/include/crypto/chacha.h @@ -47,13 +47,18 @@ static inline void hchacha_block(const u32 *state, u32 *out, int nrounds) hchacha_block_generic(state, out, nrounds); } -void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv); -static inline void chacha_init_generic(u32 *state, const u32 *key, const u8 *iv) +static inline void chacha_init_consts(u32 *state) { state[0] = 0x61707865; /* "expa" */ state[1] = 0x3320646e; /* "nd 3" */ state[2] = 0x79622d32; /* "2-by" */ state[3] = 0x6b206574; /* "te k" */ +} + +void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv); +static inline void chacha_init_generic(u32 *state, const u32 *key, const u8 *iv) +{ + chacha_init_consts(state); state[4] = key[0]; state[5] = key[1]; state[6] = key[2]; diff --git a/include/crypto/ecc_curve.h b/include/crypto/ecc_curve.h new file mode 100644 index 0000000000000000000000000000000000000000..70964781eb683d5af2f1e6a9fabf109bc61746fd --- /dev/null +++ b/include/crypto/ecc_curve.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2021 HiSilicon */ + +#ifndef _CRYTO_ECC_CURVE_H +#define _CRYTO_ECC_CURVE_H + +#include <linux/types.h> + +/** + * struct ecc_point - elliptic curve point in affine coordinates + * + * @x: X coordinate in vli form. + * @y: Y coordinate in vli form. + * @ndigits: Length of vlis in u64 qwords. + */ +struct ecc_point { + u64 *x; + u64 *y; + u8 ndigits; +}; + +/** + * struct ecc_curve - definition of elliptic curve + * + * @name: Short name of the curve. + * @g: Generator point of the curve. + * @p: Prime number, if Barrett's reduction is used for this curve + * pre-calculated value 'mu' is appended to the @p after ndigits. + * Use of Barrett's reduction is heuristically determined in + * vli_mmod_fast(). + * @n: Order of the curve group. + * @a: Curve parameter a. + * @b: Curve parameter b. + */ +struct ecc_curve { + char *name; + struct ecc_point g; + u64 *p; + u64 *n; + u64 *a; + u64 *b; +}; + +/** + * ecc_get_curve() - get elliptic curve; + * @curve_id: Curves IDs: + * defined in 'include/crypto/ecdh.h'; + * + * Returns curve if get curve succssful, NULL otherwise + */ +const struct ecc_curve *ecc_get_curve(unsigned int curve_id); + +/** + * ecc_get_curve25519() - get curve25519 curve; + * + * Returns curve25519 + */ +const struct ecc_curve *ecc_get_curve25519(void); + +#endif diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h index a5b805b5526d2c6a5304b0ddb10c4fba1fe22a3b..a9f98078d29cf61a081f5a6c05ab2447b095b83b 100644 --- a/include/crypto/ecdh.h +++ b/include/crypto/ecdh.h @@ -25,16 +25,15 @@ /* Curves IDs */ #define ECC_CURVE_NIST_P192 0x0001 #define ECC_CURVE_NIST_P256 0x0002 +#define ECC_CURVE_NIST_P384 0x0003 /** * struct ecdh - define an ECDH private key * - * @curve_id: ECC curve the key is based on. * @key: Private ECDH key * @key_size: Size of the private ECDH key */ struct ecdh { - unsigned short curve_id; char *key; unsigned short key_size; }; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 13f8a6a54ca878f8761d7d95376be283de5698f3..b2bc1e46e86a766cd19de68150c6870a40dcb0de 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -281,6 +281,8 @@ static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm) /** * crypto_free_ahash() - zeroize and free the ahash handle * @tfm: cipher handle to be freed + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_ahash(struct crypto_ahash *tfm) { @@ -724,6 +726,8 @@ static inline struct crypto_tfm *crypto_shash_tfm(struct crypto_shash *tfm) /** * crypto_free_shash() - zeroize and free the message digest handle * @tfm: cipher handle to be freed + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_shash(struct crypto_shash *tfm) { diff --git a/include/crypto/internal/poly1305.h b/include/crypto/internal/poly1305.h index 064e52ca5248019fd1a2b02fd3ab30fcf4f7010f..196aa769f296867df68b245122e86a9364bed73b 100644 --- a/include/crypto/internal/poly1305.h +++ b/include/crypto/internal/poly1305.h @@ -18,7 +18,8 @@ * only the ε-almost-∆-universal hash function (not the full MAC) is computed. */ -void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key); +void poly1305_core_setkey(struct poly1305_core_key *key, + const u8 raw_key[POLY1305_BLOCK_SIZE]); static inline void poly1305_core_init(struct poly1305_state *state) { *state = (struct poly1305_state){}; diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h index 88b591215d5c8f5872374391c7aa34c2838da3db..cccceadc164b9e6041aa8afa07adf13dbe0dbbc0 100644 --- a/include/crypto/kpp.h +++ b/include/crypto/kpp.h @@ -154,6 +154,8 @@ static inline void crypto_kpp_set_flags(struct crypto_kpp *tfm, u32 flags) * crypto_free_kpp() - free KPP tfm handle * * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_kpp(struct crypto_kpp *tfm) { diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h index f1f67fc749cf4edc3e7a5a0c17a2e6bd1cb19ee4..090692ec3bc7342da3bed3a812a4003c5f395ceb 100644 --- a/include/crypto/poly1305.h +++ b/include/crypto/poly1305.h @@ -58,8 +58,10 @@ struct poly1305_desc_ctx { }; }; -void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key); -void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key); +void poly1305_init_arch(struct poly1305_desc_ctx *desc, + const u8 key[POLY1305_KEY_SIZE]); +void poly1305_init_generic(struct poly1305_desc_ctx *desc, + const u8 key[POLY1305_KEY_SIZE]); static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key) { diff --git a/include/crypto/rng.h b/include/crypto/rng.h index 8b4b844b4eef8841b3790c6c2c0e08512e94fdb8..17bb3673d3c1700359515c3d79f7d0da531908f8 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -111,6 +111,8 @@ static inline struct rng_alg *crypto_rng_alg(struct crypto_rng *tfm) /** * crypto_free_rng() - zeroize and free RNG handle * @tfm: cipher handle to be freed + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_rng(struct crypto_rng *tfm) { diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 6a733b171a5d0ae5ca8edd8abfc74addadedc58f..ef0fc9ed4342e6dca5f48efb2e705877c576d7f1 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -196,6 +196,8 @@ static inline struct crypto_tfm *crypto_skcipher_tfm( /** * crypto_free_skcipher() - zeroize and free cipher handle * @tfm: cipher handle to be freed + * + * If @tfm is a NULL or error pointer, this function does nothing. */ static inline void crypto_free_skcipher(struct crypto_skcipher *tfm) { diff --git a/include/dt-bindings/clock/omap5.h b/include/dt-bindings/clock/omap5.h index 41775272fd2754306778da32f2a29127b8f9cef4..90e0d4b00127dd3b86634eeadb07be367acda347 100644 --- a/include/dt-bindings/clock/omap5.h +++ b/include/dt-bindings/clock/omap5.h @@ -32,6 +32,8 @@ /* l3main2 clocks */ #define OMAP5_L3_MAIN_2_CLKCTRL OMAP5_CLKCTRL_INDEX(0x20) +#define OMAP5_L3_MAIN_2_GPMC_CLKCTRL OMAP5_CLKCTRL_INDEX(0x28) +#define OMAP5_L3_MAIN_2_OCMC_RAM_CLKCTRL OMAP5_CLKCTRL_INDEX(0x30) /* ipu clocks */ #define OMAP5_MMU_IPU_CLKCTRL OMAP5_CLKCTRL_INDEX(0x20) diff --git a/include/dt-bindings/interconnect/qcom,sdm660.h b/include/dt-bindings/interconnect/qcom,sdm660.h new file mode 100644 index 0000000000000000000000000000000000000000..62e8d8670d5ea9bdb4d94392b3b1928739c0e4f5 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sdm660.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* SDM660 interconnect IDs */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SDM660_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SDM660_H + +/* A2NOC */ +#define MASTER_IPA 0 +#define MASTER_CNOC_A2NOC 1 +#define MASTER_SDCC_1 2 +#define MASTER_SDCC_2 3 +#define MASTER_BLSP_1 4 +#define MASTER_BLSP_2 5 +#define MASTER_UFS 6 +#define MASTER_USB_HS 7 +#define MASTER_USB3 8 +#define MASTER_CRYPTO_C0 9 +#define SLAVE_A2NOC_SNOC 10 + +/* BIMC */ +#define MASTER_GNOC_BIMC 0 +#define MASTER_OXILI 1 +#define MASTER_MNOC_BIMC 2 +#define MASTER_SNOC_BIMC 3 +#define MASTER_PIMEM 4 +#define SLAVE_EBI 5 +#define SLAVE_HMSS_L3 6 +#define SLAVE_BIMC_SNOC 7 + +/* CNOC */ +#define MASTER_SNOC_CNOC 0 +#define MASTER_QDSS_DAP 1 +#define SLAVE_CNOC_A2NOC 2 +#define SLAVE_MPM 3 +#define SLAVE_PMIC_ARB 4 +#define SLAVE_TLMM_NORTH 5 +#define SLAVE_TCSR 6 +#define SLAVE_PIMEM_CFG 7 +#define SLAVE_IMEM_CFG 8 +#define SLAVE_MESSAGE_RAM 9 +#define SLAVE_GLM 10 +#define SLAVE_BIMC_CFG 11 +#define SLAVE_PRNG 12 +#define SLAVE_SPDM 13 +#define SLAVE_QDSS_CFG 14 +#define SLAVE_CNOC_MNOC_CFG 15 +#define SLAVE_SNOC_CFG 16 +#define SLAVE_QM_CFG 17 +#define SLAVE_CLK_CTL 18 +#define SLAVE_MSS_CFG 19 +#define SLAVE_TLMM_SOUTH 20 +#define SLAVE_UFS_CFG 21 +#define SLAVE_A2NOC_CFG 22 +#define SLAVE_A2NOC_SMMU_CFG 23 +#define SLAVE_GPUSS_CFG 24 +#define SLAVE_AHB2PHY 25 +#define SLAVE_BLSP_1 26 +#define SLAVE_SDCC_1 27 +#define SLAVE_SDCC_2 28 +#define SLAVE_TLMM_CENTER 29 +#define SLAVE_BLSP_2 30 +#define SLAVE_PDM 31 +#define SLAVE_CNOC_MNOC_MMSS_CFG 32 +#define SLAVE_USB_HS 33 +#define SLAVE_USB3_0 34 +#define SLAVE_SRVC_CNOC 35 + +/* GNOC */ +#define MASTER_APSS_PROC 0 +#define SLAVE_GNOC_BIMC 1 +#define SLAVE_GNOC_SNOC 2 + +/* MNOC */ +#define MASTER_CPP 0 +#define MASTER_JPEG 1 +#define MASTER_MDP_P0 2 +#define MASTER_MDP_P1 3 +#define MASTER_VENUS 4 +#define MASTER_VFE 5 +#define SLAVE_MNOC_BIMC 6 +#define MASTER_CNOC_MNOC_MMSS_CFG 7 +#define MASTER_CNOC_MNOC_CFG 8 +#define SLAVE_CAMERA_CFG 9 +#define SLAVE_CAMERA_THROTTLE_CFG 10 +#define SLAVE_MISC_CFG 11 +#define SLAVE_VENUS_THROTTLE_CFG 12 +#define SLAVE_VENUS_CFG 13 +#define SLAVE_MMSS_CLK_XPU_CFG 14 +#define SLAVE_MMSS_CLK_CFG 15 +#define SLAVE_MNOC_MPU_CFG 16 +#define SLAVE_DISPLAY_CFG 17 +#define SLAVE_CSI_PHY_CFG 18 +#define SLAVE_DISPLAY_THROTTLE_CFG 19 +#define SLAVE_SMMU_CFG 20 +#define SLAVE_SRVC_MNOC 21 + +/* SNOC */ +#define MASTER_QDSS_ETR 0 +#define MASTER_QDSS_BAM 1 +#define MASTER_SNOC_CFG 2 +#define MASTER_BIMC_SNOC 3 +#define MASTER_A2NOC_SNOC 4 +#define MASTER_GNOC_SNOC 5 +#define SLAVE_HMSS 6 +#define SLAVE_LPASS 7 +#define SLAVE_WLAN 8 +#define SLAVE_CDSP 9 +#define SLAVE_IPA 10 +#define SLAVE_SNOC_BIMC 11 +#define SLAVE_SNOC_CNOC 12 +#define SLAVE_IMEM 13 +#define SLAVE_PIMEM 14 +#define SLAVE_QDSS_STM 15 +#define SLAVE_SRVC_SNOC 16 + +#endif diff --git a/include/dt-bindings/interconnect/qcom,sm8350.h b/include/dt-bindings/interconnect/qcom,sm8350.h new file mode 100644 index 0000000000000000000000000000000000000000..c7f7ed315aeba25a10110922b27bc911b364f569 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sm8350.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Qualcomm SM8350 interconnect IDs + * + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Limited + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM8350_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SM8350_H + +#define MASTER_QSPI_0 0 +#define MASTER_QUP_1 1 +#define MASTER_A1NOC_CFG 2 +#define MASTER_SDCC_4 3 +#define MASTER_UFS_MEM 4 +#define MASTER_USB3_0 5 +#define MASTER_USB3_1 6 +#define SLAVE_A1NOC_SNOC 7 +#define SLAVE_SERVICE_A1NOC 8 + +#define MASTER_QDSS_BAM 0 +#define MASTER_QUP_0 1 +#define MASTER_QUP_2 2 +#define MASTER_A2NOC_CFG 3 +#define MASTER_CRYPTO 4 +#define MASTER_IPA 5 +#define MASTER_PCIE_0 6 +#define MASTER_PCIE_1 7 +#define MASTER_QDSS_ETR 8 +#define MASTER_SDCC_2 9 +#define MASTER_UFS_CARD 10 +#define SLAVE_A2NOC_SNOC 11 +#define SLAVE_ANOC_PCIE_GEM_NOC 12 +#define SLAVE_SERVICE_A2NOC 13 + +#define MASTER_GEM_NOC_CNOC 0 +#define MASTER_GEM_NOC_PCIE_SNOC 1 +#define MASTER_QDSS_DAP 2 +#define SLAVE_AHB2PHY_SOUTH 3 +#define SLAVE_AHB2PHY_NORTH 4 +#define SLAVE_AOSS 5 +#define SLAVE_APPSS 6 +#define SLAVE_CAMERA_CFG 7 +#define SLAVE_CLK_CTL 8 +#define SLAVE_CDSP_CFG 9 +#define SLAVE_RBCPR_CX_CFG 10 +#define SLAVE_RBCPR_MMCX_CFG 11 +#define SLAVE_RBCPR_MX_CFG 12 +#define SLAVE_CRYPTO_0_CFG 13 +#define SLAVE_CX_RDPM 14 +#define SLAVE_DCC_CFG 15 +#define SLAVE_DISPLAY_CFG 16 +#define SLAVE_GFX3D_CFG 17 +#define SLAVE_HWKM 18 +#define SLAVE_IMEM_CFG 19 +#define SLAVE_IPA_CFG 20 +#define SLAVE_IPC_ROUTER_CFG 21 +#define SLAVE_LPASS 22 +#define SLAVE_CNOC_MSS 23 +#define SLAVE_MX_RDPM 24 +#define SLAVE_PCIE_0_CFG 25 +#define SLAVE_PCIE_1_CFG 26 +#define SLAVE_PDM 27 +#define SLAVE_PIMEM_CFG 28 +#define SLAVE_PKA_WRAPPER_CFG 29 +#define SLAVE_PMU_WRAPPER_CFG 30 +#define SLAVE_QDSS_CFG 31 +#define SLAVE_QSPI_0 32 +#define SLAVE_QUP_0 33 +#define SLAVE_QUP_1 34 +#define SLAVE_QUP_2 35 +#define SLAVE_SDCC_2 36 +#define SLAVE_SDCC_4 37 +#define SLAVE_SECURITY 38 +#define SLAVE_SPSS_CFG 39 +#define SLAVE_TCSR 40 +#define SLAVE_TLMM 41 +#define SLAVE_UFS_CARD_CFG 42 +#define SLAVE_UFS_MEM_CFG 43 +#define SLAVE_USB3_0 44 +#define SLAVE_USB3_1 45 +#define SLAVE_VENUS_CFG 46 +#define SLAVE_VSENSE_CTRL_CFG 47 +#define SLAVE_A1NOC_CFG 48 +#define SLAVE_A2NOC_CFG 49 +#define SLAVE_DDRSS_CFG 50 +#define SLAVE_CNOC_MNOC_CFG 51 +#define SLAVE_SNOC_CFG 52 +#define SLAVE_BOOT_IMEM 53 +#define SLAVE_IMEM 54 +#define SLAVE_PIMEM 55 +#define SLAVE_SERVICE_CNOC 56 +#define SLAVE_PCIE_0 57 +#define SLAVE_PCIE_1 58 +#define SLAVE_QDSS_STM 59 +#define SLAVE_TCU 60 + +#define MASTER_CNOC_DC_NOC 0 +#define SLAVE_LLCC_CFG 1 +#define SLAVE_GEM_NOC_CFG 2 + +#define MASTER_GPU_TCU 0 +#define MASTER_SYS_TCU 1 +#define MASTER_APPSS_PROC 2 +#define MASTER_COMPUTE_NOC 3 +#define MASTER_GEM_NOC_CFG 4 +#define MASTER_GFX3D 5 +#define MASTER_MNOC_HF_MEM_NOC 6 +#define MASTER_MNOC_SF_MEM_NOC 7 +#define MASTER_ANOC_PCIE_GEM_NOC 8 +#define MASTER_SNOC_GC_MEM_NOC 9 +#define MASTER_SNOC_SF_MEM_NOC 10 +#define SLAVE_MSS_PROC_MS_MPU_CFG 11 +#define SLAVE_MCDMA_MS_MPU_CFG 12 +#define SLAVE_GEM_NOC_CNOC 13 +#define SLAVE_LLCC 14 +#define SLAVE_MEM_NOC_PCIE_SNOC 15 +#define SLAVE_SERVICE_GEM_NOC_1 16 +#define SLAVE_SERVICE_GEM_NOC_2 17 +#define SLAVE_SERVICE_GEM_NOC 18 +#define MASTER_MNOC_HF_MEM_NOC_DISP 19 +#define MASTER_MNOC_SF_MEM_NOC_DISP 20 +#define SLAVE_LLCC_DISP 21 + +#define MASTER_CNOC_LPASS_AG_NOC 0 +#define SLAVE_LPASS_CORE_CFG 1 +#define SLAVE_LPASS_LPI_CFG 2 +#define SLAVE_LPASS_MPU_CFG 3 +#define SLAVE_LPASS_TOP_CFG 4 +#define SLAVE_SERVICES_LPASS_AML_NOC 5 +#define SLAVE_SERVICE_LPASS_AG_NOC 6 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 +#define MASTER_LLCC_DISP 2 +#define SLAVE_EBI1_DISP 3 + +#define MASTER_CAMNOC_HF 0 +#define MASTER_CAMNOC_ICP 1 +#define MASTER_CAMNOC_SF 2 +#define MASTER_CNOC_MNOC_CFG 3 +#define MASTER_VIDEO_P0 4 +#define MASTER_VIDEO_P1 5 +#define MASTER_VIDEO_PROC 6 +#define MASTER_MDP0 7 +#define MASTER_MDP1 8 +#define MASTER_ROTATOR 9 +#define SLAVE_MNOC_HF_MEM_NOC 10 +#define SLAVE_MNOC_SF_MEM_NOC 11 +#define SLAVE_SERVICE_MNOC 12 +#define MASTER_MDP0_DISP 13 +#define MASTER_MDP1_DISP 14 +#define MASTER_ROTATOR_DISP 15 +#define SLAVE_MNOC_HF_MEM_NOC_DISP 16 +#define SLAVE_MNOC_SF_MEM_NOC_DISP 17 + +#define MASTER_CDSP_NOC_CFG 0 +#define MASTER_CDSP_PROC 1 +#define SLAVE_CDSP_MEM_NOC 2 +#define SLAVE_SERVICE_NSP_NOC 3 + +#define MASTER_A1NOC_SNOC 0 +#define MASTER_A2NOC_SNOC 1 +#define MASTER_SNOC_CFG 2 +#define MASTER_PIMEM 3 +#define MASTER_GIC 4 +#define SLAVE_SNOC_GEM_NOC_GC 5 +#define SLAVE_SNOC_GEM_NOC_SF 6 +#define SLAVE_SERVICE_SNOC 7 + +#endif diff --git a/include/dt-bindings/interrupt-controller/apple-aic.h b/include/dt-bindings/interrupt-controller/apple-aic.h new file mode 100644 index 0000000000000000000000000000000000000000..604f2bb30ac0d674efaaaa480f52e0cfb890a67c --- /dev/null +++ b/include/dt-bindings/interrupt-controller/apple-aic.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR MIT */ +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_APPLE_AIC_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_APPLE_AIC_H + +#include <dt-bindings/interrupt-controller/irq.h> + +#define AIC_IRQ 0 +#define AIC_FIQ 1 + +#define AIC_TMR_HV_PHYS 0 +#define AIC_TMR_HV_VIRT 1 +#define AIC_TMR_GUEST_PHYS 2 +#define AIC_TMR_GUEST_VIRT 3 + +#endif diff --git a/include/dt-bindings/mux/ti-serdes.h b/include/dt-bindings/mux/ti-serdes.h index 9047ec6bd3cf82dceffd67e3d2d2bfc318e6a55b..d417b9268b162dfc2dfccbc58ca6eb70f7897821 100644 --- a/include/dt-bindings/mux/ti-serdes.h +++ b/include/dt-bindings/mux/ti-serdes.h @@ -90,4 +90,9 @@ #define J7200_SERDES0_LANE3_USB 0x2 #define J7200_SERDES0_LANE3_IP4_UNUSED 0x3 +/* AM64 */ + +#define AM64_SERDES0_LANE0_PCIE0 0x0 +#define AM64_SERDES0_LANE0_USB 0x1 + #endif /* _DT_BINDINGS_MUX_TI_SERDES */ diff --git a/include/dt-bindings/phy/phy-cadence-torrent.h b/include/dt-bindings/phy/phy-cadence-torrent.h deleted file mode 100644 index e387b6a957413657c17ba3107b905813abde01b1..0000000000000000000000000000000000000000 --- a/include/dt-bindings/phy/phy-cadence-torrent.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * This header provides constants for Cadence Torrent SERDES. - */ - -#ifndef _DT_BINDINGS_TORRENT_SERDES_H -#define _DT_BINDINGS_TORRENT_SERDES_H - -#define TORRENT_SERDES_NO_SSC 0 -#define TORRENT_SERDES_EXTERNAL_SSC 1 -#define TORRENT_SERDES_INTERNAL_SSC 2 - -#endif /* _DT_BINDINGS_TORRENT_SERDES_H */ diff --git a/include/dt-bindings/phy/phy-cadence.h b/include/dt-bindings/phy/phy-cadence.h new file mode 100644 index 0000000000000000000000000000000000000000..4652bcb8626521a1f0768222a1a304cd938c29b5 --- /dev/null +++ b/include/dt-bindings/phy/phy-cadence.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for Cadence SERDES. + */ + +#ifndef _DT_BINDINGS_CADENCE_SERDES_H +#define _DT_BINDINGS_CADENCE_SERDES_H + +/* Torrent */ +#define TORRENT_SERDES_NO_SSC 0 +#define TORRENT_SERDES_EXTERNAL_SSC 1 +#define TORRENT_SERDES_INTERNAL_SSC 2 + +#define CDNS_TORRENT_REFCLK_DRIVER 0 + +/* Sierra */ +#define CDNS_SIERRA_PLL_CMNLC 0 +#define CDNS_SIERRA_PLL_CMNLC1 1 + +#endif /* _DT_BINDINGS_CADENCE_SERDES_H */ diff --git a/include/dt-bindings/phy/phy-ti.h b/include/dt-bindings/phy/phy-ti.h new file mode 100644 index 0000000000000000000000000000000000000000..ad955d3a56b4ef89c0c37401d41d6d2958b07019 --- /dev/null +++ b/include/dt-bindings/phy/phy-ti.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for TI SERDES. + */ + +#ifndef _DT_BINDINGS_TI_SERDES +#define _DT_BINDINGS_TI_SERDES + +/* Clock index for output clocks from WIZ */ + +/* MUX Clocks */ +#define TI_WIZ_PLL0_REFCLK 0 +#define TI_WIZ_PLL1_REFCLK 1 +#define TI_WIZ_REFCLK_DIG 2 + +/* Reserve index here for future additions */ + +/* MISC Clocks */ +#define TI_WIZ_PHY_EN_REFCLK 16 + +#endif /* _DT_BINDINGS_TI_SERDES */ diff --git a/include/dt-bindings/pinctrl/k3.h b/include/dt-bindings/pinctrl/k3.h index b0eea7cc6e232972dc0068f552e7d334b4c8158b..e085f102b2839a0c7b45678b1f10bead1ba21a26 100644 --- a/include/dt-bindings/pinctrl/k3.h +++ b/include/dt-bindings/pinctrl/k3.h @@ -3,7 +3,7 @@ * This header provides constants for pinctrl bindings for TI's K3 SoC * family. * - * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2018-2021 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef _DT_BINDINGS_PINCTRL_TI_K3_H #define _DT_BINDINGS_PINCTRL_TI_K3_H @@ -35,4 +35,7 @@ #define J721E_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) #define J721E_WKUP_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) +#define AM64X_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) +#define AM64X_MCU_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) + #endif diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index d711e250cf2c6150795617288d813b0ef607cf78..eedb5d94c0206f4b29a6ece24e86834089607873 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -45,6 +45,21 @@ #define SM8250_MX 8 #define SM8250_MX_AO 9 +/* SM8350 Power Domain Indexes */ +#define SM8350_CX 0 +#define SM8350_CX_AO 1 +#define SM8350_EBI 2 +#define SM8350_GFX 3 +#define SM8350_LCX 4 +#define SM8350_LMX 5 +#define SM8350_MMCX 6 +#define SM8350_MMCX_AO 7 +#define SM8350_MX 8 +#define SM8350_MX_AO 9 +#define SM8350_MXC 10 +#define SM8350_MXC_AO 11 +#define SM8350_MSS 12 + /* SC7180 Power Domain Indexes */ #define SC7180_CX 0 #define SC7180_CX_AO 1 @@ -55,6 +70,17 @@ #define SC7180_LCX 6 #define SC7180_MSS 7 +/* SC7280 Power Domain Indexes */ +#define SC7280_CX 0 +#define SC7280_CX_AO 1 +#define SC7280_EBI 2 +#define SC7280_GFX 3 +#define SC7280_MX 4 +#define SC7280_MX_AO 5 +#define SC7280_LMX 6 +#define SC7280_LCX 7 +#define SC7280_MSS 8 + /* SDM845 Power Domain performance levels */ #define RPMH_REGULATOR_LEVEL_RETENTION 16 #define RPMH_REGULATOR_LEVEL_MIN_SVS 48 diff --git a/include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h b/include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h new file mode 100644 index 0000000000000000000000000000000000000000..27c5ce68847b4be090863d3a87208b37d98dd106 --- /dev/null +++ b/include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Nicolas Saenz Julienne + * Author: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> + */ + +#ifndef _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H +#define _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H + +#define RASPBERRYPI_FIRMWARE_PWM_POE 0 +#define RASPBERRYPI_FIRMWARE_PWM_NUM 1 + +#endif diff --git a/include/dt-bindings/soc/bcm-pmb.h b/include/dt-bindings/soc/bcm-pmb.h index 744dc3af4d415fe4d809a8c0ba7b5fe73bd2126e..3858844680070456a34d14ce1601e7b4bc63b8eb 100644 --- a/include/dt-bindings/soc/bcm-pmb.h +++ b/include/dt-bindings/soc/bcm-pmb.h @@ -7,5 +7,6 @@ #define BCM_PMB_PCIE1 0x02 #define BCM_PMB_PCIE2 0x03 #define BCM_PMB_HOST_USB 0x04 +#define BCM_PMB_SATA 0x05 #endif diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index a29d3ff2e7e8dc59c83ef041179bda0b461a16d7..c432fdb8547f909231a8c69445c55b4b4cc4fb6b 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h @@ -72,6 +72,12 @@ const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key) return key->payload.data[asym_key_ids]; } +static inline +const struct public_key *asymmetric_key_public_key(const struct key *key) +{ + return key->payload.data[asym_crypto]; +} + extern struct key *find_asymmetric_key(struct key *keyring, const struct asymmetric_key_id *id_0, const struct asymmetric_key_id *id_1, diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index fb8b07daa9d15519370e1731b8cf4c726bf83a17..875e002a41804726f712948e5ed9acb1c7402706 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h @@ -31,6 +31,7 @@ extern int restrict_link_by_builtin_and_secondary_trusted( #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted #endif +extern struct pkcs7_message *pkcs7; #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING extern int mark_hash_blacklisted(const char *hash); extern int is_hash_blacklisted(const u8 *hash, size_t hash_len, @@ -49,6 +50,20 @@ static inline int is_binary_blacklisted(const u8 *hash, size_t hash_len) } #endif +#ifdef CONFIG_SYSTEM_REVOCATION_LIST +extern int add_key_to_revocation_list(const char *data, size_t size); +extern int is_key_on_revocation_list(struct pkcs7_message *pkcs7); +#else +static inline int add_key_to_revocation_list(const char *data, size_t size) +{ + return 0; +} +static inline int is_key_on_revocation_list(struct pkcs7_message *pkcs7) +{ + return -ENOKEY; +} +#endif + #ifdef CONFIG_IMA_BLACKLIST_KEYRING extern struct key *ima_blacklist_keyring; diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h index a94c03a61d8f9b3c57cddd158737ed4298d29ffe..d89fa2579ac0569864508ef4d175669f22314d35 100644 --- a/include/keys/trusted-type.h +++ b/include/keys/trusted-type.h @@ -11,6 +11,12 @@ #include <linux/rcupdate.h> #include <linux/tpm.h> +#ifdef pr_fmt +#undef pr_fmt +#endif + +#define pr_fmt(fmt) "trusted_key: " fmt + #define MIN_KEY_SIZE 32 #define MAX_KEY_SIZE 128 #define MAX_BLOB_SIZE 512 @@ -22,6 +28,7 @@ struct trusted_key_payload { unsigned int key_len; unsigned int blob_len; unsigned char migratable; + unsigned char old_format; unsigned char key[MAX_KEY_SIZE + 1]; unsigned char blob[MAX_BLOB_SIZE]; }; @@ -30,6 +37,7 @@ struct trusted_key_options { uint16_t keytype; uint32_t keyhandle; unsigned char keyauth[TPM_DIGEST_SIZE]; + uint32_t blobauth_len; unsigned char blobauth[TPM_DIGEST_SIZE]; uint32_t pcrinfo_len; unsigned char pcrinfo[MAX_PCRINFO_SIZE]; @@ -40,6 +48,53 @@ struct trusted_key_options { uint32_t policyhandle; }; +struct trusted_key_ops { + /* + * flag to indicate if trusted key implementation supports migration + * or not. + */ + unsigned char migratable; + + /* Initialize key interface. */ + int (*init)(void); + + /* Seal a key. */ + int (*seal)(struct trusted_key_payload *p, char *datablob); + + /* Unseal a key. */ + int (*unseal)(struct trusted_key_payload *p, char *datablob); + + /* Get a randomized key. */ + int (*get_random)(unsigned char *key, size_t key_len); + + /* Exit key interface. */ + void (*exit)(void); +}; + +struct trusted_key_source { + char *name; + struct trusted_key_ops *ops; +}; + extern struct key_type key_type_trusted; +#define TRUSTED_DEBUG 0 + +#if TRUSTED_DEBUG +static inline void dump_payload(struct trusted_key_payload *p) +{ + pr_info("key_len %d\n", p->key_len); + print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE, + 16, 1, p->key, p->key_len, 0); + pr_info("bloblen %d\n", p->blob_len); + print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE, + 16, 1, p->blob, p->blob_len, 0); + pr_info("migratable %d\n", p->migratable); +} +#else +static inline void dump_payload(struct trusted_key_payload *p) +{ +} +#endif + #endif /* _KEYS_TRUSTED_TYPE_H */ diff --git a/include/keys/trusted_tee.h b/include/keys/trusted_tee.h new file mode 100644 index 0000000000000000000000000000000000000000..151be25a979e8f3c98122355f6413a5d27530443 --- /dev/null +++ b/include/keys/trusted_tee.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019-2021 Linaro Ltd. + * + * Author: + * Sumit Garg <sumit.garg@linaro.org> + */ + +#ifndef __TEE_TRUSTED_KEY_H +#define __TEE_TRUSTED_KEY_H + +#include <keys/trusted-type.h> + +extern struct trusted_key_ops trusted_key_tee_ops; + +#endif diff --git a/include/keys/trusted_tpm.h b/include/keys/trusted_tpm.h index a56d8e1298f27e76d3c299de8b5d3870b77535d4..7769b726863ab10b5b160366d7fa918784491995 100644 --- a/include/keys/trusted_tpm.h +++ b/include/keys/trusted_tpm.h @@ -16,6 +16,8 @@ #define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) #define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) +extern struct trusted_key_ops trusted_key_tpm_ops; + struct osapsess { uint32_t handle; unsigned char secret[SHA1_DIGEST_SIZE]; @@ -52,30 +54,19 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, #if TPM_DEBUG static inline void dump_options(struct trusted_key_options *o) { - pr_info("trusted_key: sealing key type %d\n", o->keytype); - pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle); - pr_info("trusted_key: pcrlock %d\n", o->pcrlock); - pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len); + pr_info("sealing key type %d\n", o->keytype); + pr_info("sealing key handle %0X\n", o->keyhandle); + pr_info("pcrlock %d\n", o->pcrlock); + pr_info("pcrinfo %d\n", o->pcrinfo_len); print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, 16, 1, o->pcrinfo, o->pcrinfo_len, 0); } -static inline void dump_payload(struct trusted_key_payload *p) -{ - pr_info("trusted_key: key_len %d\n", p->key_len); - print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE, - 16, 1, p->key, p->key_len, 0); - pr_info("trusted_key: bloblen %d\n", p->blob_len); - print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE, - 16, 1, p->blob, p->blob_len, 0); - pr_info("trusted_key: migratable %d\n", p->migratable); -} - static inline void dump_sess(struct osapsess *s) { print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, 16, 1, &s->handle, 4, 0); - pr_info("trusted-key: secret:\n"); + pr_info("secret:\n"); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); pr_info("trusted-key: enonce:\n"); @@ -87,7 +78,7 @@ static inline void dump_tpm_buf(unsigned char *buf) { int len; - pr_info("\ntrusted-key: tpm buffer\n"); + pr_info("\ntpm buffer\n"); len = LOAD32(buf, TPM_SIZE_OFFSET); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); } @@ -96,10 +87,6 @@ static inline void dump_options(struct trusted_key_options *o) { } -static inline void dump_payload(struct trusted_key_payload *p) -{ -} - static inline void dump_sess(struct osapsess *s) { } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3bdcfc4401b7b07980e646f5c8fcd7a37b1d9949..c60745f657e9c9fc10a5276bb90d466652fc9f9f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -748,6 +748,11 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) return NULL; } +static inline bool acpi_reduced_hardware(void) +{ + return false; +} + static inline void acpi_dev_put(struct acpi_device *adev) {} static inline bool is_acpi_node(const struct fwnode_handle *fwnode) @@ -1034,9 +1039,14 @@ static inline void acpi_ec_set_gpe_wake_mask(u8 action) {} __printf(3, 4) void acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...); +void acpi_evaluation_failure_warn(acpi_handle handle, const char *name, + acpi_status status); #else /* !CONFIG_ACPI */ static inline __printf(3, 4) void acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {} +static inline void acpi_evaluation_failure_warn(acpi_handle handle, + const char *name, + acpi_status status) {} #endif /* !CONFIG_ACPI */ #if defined(CONFIG_ACPI) && defined(CONFIG_DYNAMIC_DEBUG) diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h index 131b27c9720931b18cc63000123ff31cdb3a2e82..9bf58aac0df2bbd0142cfe638eeb668bc9ab846f 100644 --- a/include/linux/amba/pl022.h +++ b/include/linux/amba/pl022.h @@ -223,10 +223,6 @@ struct dma_chan; /** * struct pl022_ssp_master - device.platform_data for SPI controller devices. * @bus_id: identifier for this bus - * @num_chipselect: chipselects are used to distinguish individual - * SPI slaves, and are numbered from zero to num_chipselects - 1. - * each slave has a chipselect signal, but it's common that not - * every chipselect is connected to a slave. * @enable_dma: if true enables DMA driven transfers. * @dma_rx_param: parameter to locate an RX DMA channel. * @dma_tx_param: parameter to locate a TX DMA channel. @@ -235,18 +231,15 @@ struct dma_chan; * indicates no delay and the device will be suspended immediately. * @rt: indicates the controller should run the message pump with realtime * priority to minimise the transfer latency on the bus. - * @chipselects: list of <num_chipselects> chip select gpios */ struct pl022_ssp_controller { u16 bus_id; - u8 num_chipselect; u8 enable_dma:1; bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; int autosuspend_delay; bool rt; - int *chipselects; }; /** @@ -265,8 +258,6 @@ struct pl022_ssp_controller { * @duplex: Microwire interface: Full/Half duplex * @clkdelay: on the PL023 variant, the delay in feeback clock cycles * before sampling the incoming line - * @cs_control: function pointer to board-specific function to - * assert/deassert I/O port to control HW generation of devices chip-select. */ struct pl022_config_chip { enum ssp_interface iface; @@ -280,7 +271,6 @@ struct pl022_config_chip { enum ssp_microwire_wait_state wait_state; enum ssp_duplex duplex; enum ssp_clkdelay clkdelay; - void (*cs_control) (u32 control); }; #endif /* _SSP_PL022_H */ diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index 3f33dfe7f8083ef0e37141454ad10e0affb9773f..f99a7fd8b268e1ba4582a4a64fa90636d9d0003f 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -24,18 +24,31 @@ static inline unsigned long topology_get_cpu_scale(int cpu) void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity); -DECLARE_PER_CPU(unsigned long, freq_scale); +DECLARE_PER_CPU(unsigned long, arch_freq_scale); static inline unsigned long topology_get_freq_scale(int cpu) { - return per_cpu(freq_scale, cpu); + return per_cpu(arch_freq_scale, cpu); } void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq, unsigned long max_freq); bool topology_scale_freq_invariant(void); -bool arch_freq_counters_available(const struct cpumask *cpus); +enum scale_freq_source { + SCALE_FREQ_SOURCE_CPUFREQ = 0, + SCALE_FREQ_SOURCE_ARCH, + SCALE_FREQ_SOURCE_CPPC, +}; + +struct scale_freq_data { + enum scale_freq_source source; + void (*set_freq_scale)(void); +}; + +void topology_scale_freq_tick(void); +void topology_set_scale_freq_source(struct scale_freq_data *data, const struct cpumask *cpus); +void topology_clear_scale_freq_source(enum scale_freq_source source, const struct cpumask *cpus); DECLARE_PER_CPU(unsigned long, thermal_pressure); diff --git a/include/linux/asn1_encoder.h b/include/linux/asn1_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..08cd0c2ad34f0e14b863c5a85a25b70565581c7f --- /dev/null +++ b/include/linux/asn1_encoder.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _LINUX_ASN1_ENCODER_H +#define _LINUX_ASN1_ENCODER_H + +#include <linux/types.h> +#include <linux/asn1.h> +#include <linux/asn1_ber_bytecode.h> +#include <linux/bug.h> + +#define asn1_oid_len(oid) (sizeof(oid)/sizeof(u32)) +unsigned char * +asn1_encode_integer(unsigned char *data, const unsigned char *end_data, + s64 integer); +unsigned char * +asn1_encode_oid(unsigned char *data, const unsigned char *end_data, + u32 oid[], int oid_len); +unsigned char * +asn1_encode_tag(unsigned char *data, const unsigned char *end_data, + u32 tag, const unsigned char *string, int len); +unsigned char * +asn1_encode_octet_string(unsigned char *data, + const unsigned char *end_data, + const unsigned char *string, u32 len); +unsigned char * +asn1_encode_sequence(unsigned char *data, const unsigned char *end_data, + const unsigned char *seq, int len); +unsigned char * +asn1_encode_boolean(unsigned char *data, const unsigned char *end_data, + bool val); + +#endif diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 0abd93efc18106437448e94e225de28407ea7880..049cf9421d83141f5cd851ca953f3fcb85932d56 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -86,6 +86,7 @@ struct coredump_params { unsigned long mm_flags; loff_t written; loff_t pos; + loff_t to_skip; }; /* diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h index a19519f4241dce4f18b8c338648a70af75392994..eed86eb0a1dea08a4f813537b198639730e87d45 100644 --- a/include/linux/bottom_half.h +++ b/include/linux/bottom_half.h @@ -4,7 +4,7 @@ #include <linux/preempt.h> -#ifdef CONFIG_TRACE_IRQFLAGS +#if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_TRACE_IRQFLAGS) extern void __local_bh_disable_ip(unsigned long ip, unsigned int cnt); #else static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) @@ -32,4 +32,10 @@ static inline void local_bh_enable(void) __local_bh_enable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); } +#ifdef CONFIG_PREEMPT_RT +extern bool local_bh_blocked(void); +#else +static inline bool local_bh_blocked(void) { return false; } +#endif + #endif /* _LINUX_BH_H */ diff --git a/include/linux/bpf.h b/include/linux/bpf.h index fdac0534ce79d9b69fd0f5aa40452010f0cb24f0..00597b0c719c4a74cf82fef858d5b4472137efcc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -652,7 +652,7 @@ struct bpf_dispatcher { struct bpf_ksym ksym; }; -static __always_inline unsigned int bpf_dispatcher_nop_func( +static __always_inline __nocfi unsigned int bpf_dispatcher_nop_func( const void *ctx, const struct bpf_insn *insnsi, unsigned int (*bpf_func)(const void *, @@ -680,7 +680,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr); } #define DEFINE_BPF_DISPATCHER(name) \ - noinline unsigned int bpf_dispatcher_##name##_func( \ + noinline __nocfi unsigned int bpf_dispatcher_##name##_func( \ const void *ctx, \ const struct bpf_insn *insnsi, \ unsigned int (*bpf_func)(const void *, \ diff --git a/include/linux/cfi.h b/include/linux/cfi.h new file mode 100644 index 0000000000000000000000000000000000000000..879744aaa6e0f667c3e9ca1f4681267247e1cefc --- /dev/null +++ b/include/linux/cfi.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Clang Control Flow Integrity (CFI) support. + * + * Copyright (C) 2021 Google LLC + */ +#ifndef _LINUX_CFI_H +#define _LINUX_CFI_H + +#ifdef CONFIG_CFI_CLANG +typedef void (*cfi_check_fn)(uint64_t id, void *ptr, void *diag); + +/* Compiler-generated function in each module, and the kernel */ +extern void __cfi_check(uint64_t id, void *ptr, void *diag); + +/* + * Force the compiler to generate a CFI jump table entry for a function + * and store the jump table address to __cfi_jt_<function>. + */ +#define __CFI_ADDRESSABLE(fn, __attr) \ + const void *__cfi_jt_ ## fn __visible __attr = (void *)&fn + +#ifdef CONFIG_CFI_CLANG_SHADOW + +extern void cfi_module_add(struct module *mod, unsigned long base_addr); +extern void cfi_module_remove(struct module *mod, unsigned long base_addr); + +#else + +static inline void cfi_module_add(struct module *mod, unsigned long base_addr) {} +static inline void cfi_module_remove(struct module *mod, unsigned long base_addr) {} + +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +#else /* !CONFIG_CFI_CLANG */ + +#define __CFI_ADDRESSABLE(fn, __attr) + +#endif /* CONFIG_CFI_CLANG */ + +#endif /* _LINUX_CFI_H */ diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index eb016fc9cc0b52b571775852a000630de59e1420..f7ff722a03dd5c066bab93b7d112235cd92dcd95 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2020, NVIDIA CORPORATION. All rights reserved. */ #ifndef __LINUX_CLK_TEGRA_H_ @@ -123,6 +123,8 @@ static inline void tegra_cpu_clock_resume(void) } #endif +extern int tegra210_plle_hw_sequence_start(void); +extern bool tegra210_plle_hw_sequence_is_enabled(void); extern void tegra210_xusb_pll_hw_control_enable(void); extern void tegra210_xusb_pll_hw_sequence_start(void); extern void tegra210_sata_pll_hw_control_enable(void); diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 86d143db65231649af215c30dfc24814f0d38349..a247b089ca78d753ba038f0e110361c738adfa8a 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -70,7 +70,7 @@ struct module; * @mark_unstable: Optional function to inform the clocksource driver that * the watchdog marked the clocksource unstable * @tick_stable: Optional function called periodically from the watchdog - * code to provide stable syncrhonization points + * code to provide stable synchronization points * @wd_list: List head to enqueue into the watchdog list (internal) * @cs_last: Last clocksource value for clocksource watchdog * @wd_last: Last watchdog value corresponding to @cs_last diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index d217c382b02deff6cace8b80cc938d65cfed6d0d..adbe76b203e2fd27356d7cb772542c4e22e23ca1 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -61,3 +61,6 @@ #if __has_feature(shadow_call_stack) # define __noscs __attribute__((__no_sanitize__("shadow-call-stack"))) #endif + +#define __nocfi __attribute__((__no_sanitize__("cfi"))) +#define __cficanonical __attribute__((__cfi_canonical_jump_table__)) diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index e5dd5a4ae94608b9b5d0950a81ba272f0dde8997..d29bda7f6ebddf8141443801ceb553b3f57eb934 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -242,6 +242,14 @@ struct ftrace_likely_data { # define __noscs #endif +#ifndef __nocfi +# define __nocfi +#endif + +#ifndef __cficanonical +# define __cficanonical +#endif + #ifndef asm_volatile_goto #define asm_volatile_goto(x...) asm goto(x) #endif diff --git a/include/linux/coredump.h b/include/linux/coredump.h index e58e8c2077828d3d3f7f526f34976fff0062d40b..78fcd776b185a853653e2bbd499e7d2c28675439 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -7,34 +7,34 @@ #include <linux/fs.h> #include <asm/siginfo.h> +#ifdef CONFIG_COREDUMP struct core_vma_metadata { unsigned long start, end; unsigned long flags; unsigned long dump_size; }; +extern int core_uses_pid; +extern char core_pattern[]; +extern unsigned int core_pipe_limit; + /* * These are the only things you should do on a core-file: use only these * functions to write out all the necessary info. */ struct coredump_params; -extern int dump_skip(struct coredump_params *cprm, size_t nr); +extern void dump_skip_to(struct coredump_params *cprm, unsigned long to); +extern void dump_skip(struct coredump_params *cprm, size_t nr); extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr); extern int dump_align(struct coredump_params *cprm, int align); -extern void dump_truncate(struct coredump_params *cprm); int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len); int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, struct core_vma_metadata **vma_meta, size_t *vma_data_size_ptr); -#ifdef CONFIG_COREDUMP extern void do_coredump(const kernel_siginfo_t *siginfo); #else static inline void do_coredump(const kernel_siginfo_t *siginfo) {} #endif -extern int core_uses_pid; -extern char core_pattern[]; -extern unsigned int core_pipe_limit; - #endif /* _LINUX_COREDUMP_H */ diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index f14adb882338194cc7f127f9ba7ad3288c084370..db82ce5304f9661f54c3e96dc281e4de00e90f93 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -100,6 +100,7 @@ enum cpuhp_state { CPUHP_AP_CPU_PM_STARTING, CPUHP_AP_IRQ_GIC_STARTING, CPUHP_AP_IRQ_HIP04_STARTING, + CPUHP_AP_IRQ_APPLE_AIC_STARTING, CPUHP_AP_IRQ_ARMADA_XP_STARTING, CPUHP_AP_IRQ_BCM2836_STARTING, CPUHP_AP_IRQ_MIPS_GIC_STARTING, @@ -135,6 +136,7 @@ enum cpuhp_state { CPUHP_AP_RISCV_TIMER_STARTING, CPUHP_AP_CLINT_TIMER_STARTING, CPUHP_AP_CSKY_TIMER_STARTING, + CPUHP_AP_TI_GP_TIMER_STARTING, CPUHP_AP_HYPERV_TIMER_STARTING, CPUHP_AP_KVM_STARTING, CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, @@ -175,6 +177,8 @@ enum cpuhp_state { CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, + CPUHP_AP_PERF_ARM_HISI_PA_ONLINE, + CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, CPUHP_AP_PERF_ARM_L2X0_ONLINE, CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE, CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE, diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index bd605b5585cf6793d350f74227f150b4f82ca41e..fce476275e16ced61c5fdb105b8112e829996c80 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -49,8 +49,8 @@ struct cpuidle_state { char name[CPUIDLE_NAME_LEN]; char desc[CPUIDLE_DESC_LEN]; - u64 exit_latency_ns; - u64 target_residency_ns; + s64 exit_latency_ns; + s64 target_residency_ns; unsigned int flags; unsigned int exit_latency; /* in US */ int power_usage; /* in mW */ diff --git a/include/linux/cred.h b/include/linux/cred.h index 4c6350503697779149782c170289d9cd2f7a778b..ac0e5f97d7d8d39519f896c780cf26c2f0a73e53 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -140,7 +140,7 @@ struct cred { struct key *request_key_auth; /* assumed request_key authority */ #endif #ifdef CONFIG_SECURITY - void *security; /* subjective LSM security */ + void *security; /* LSM security */ #endif struct user_struct *user; /* real user ID subscription */ struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h deleted file mode 100644 index 05ee0f19448a500d81f7481e6ecce4fa884fc577..0000000000000000000000000000000000000000 --- a/include/linux/cyclades.h +++ /dev/null @@ -1,364 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* $Revision: 3.0 $$Date: 1998/11/02 14:20:59 $ - * linux/include/linux/cyclades.h - * - * This file was initially written by - * Randolph Bentson <bentson@grieg.seaslug.org> and is maintained by - * Ivan Passos <ivan@cyclades.com>. - * - * This file contains the general definitions for the cyclades.c driver - *$Log: cyclades.h,v $ - *Revision 3.1 2002/01/29 11:36:16 henrique - *added throttle field on struct cyclades_port to indicate whether the - *port is throttled or not - * - *Revision 3.1 2000/04/19 18:52:52 ivan - *converted address fields to unsigned long and added fields for physical - *addresses on cyclades_card structure; - * - *Revision 3.0 1998/11/02 14:20:59 ivan - *added nports field on cyclades_card structure; - * - *Revision 2.5 1998/08/03 16:57:01 ivan - *added cyclades_idle_stats structure; - * - *Revision 2.4 1998/06/01 12:09:53 ivan - *removed closing_wait2 from cyclades_port structure; - * - *Revision 2.3 1998/03/16 18:01:12 ivan - *changes in the cyclades_port structure to get it closer to the - *standard serial port structure; - *added constants for new ioctls; - * - *Revision 2.2 1998/02/17 16:50:00 ivan - *changes in the cyclades_port structure (addition of shutdown_wait and - *chip_rev variables); - *added constants for new ioctls and for CD1400 rev. numbers. - * - *Revision 2.1 1997/10/24 16:03:00 ivan - *added rflow (which allows enabling the CD1400 special flow control - *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to - *cyclades_port structure; - *added Alpha support - * - *Revision 2.0 1997/06/30 10:30:00 ivan - *added some new doorbell command constants related to IOCTLW and - *UART error signaling - * - *Revision 1.8 1997/06/03 15:30:00 ivan - *added constant ZFIRM_HLT - *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin) - * - *Revision 1.7 1997/03/26 10:30:00 daniel - *new entries at the end of cyclades_port struct to reallocate - *variables illegally allocated within card memory. - * - *Revision 1.6 1996/09/09 18:35:30 bentson - *fold in changes for Cyclom-Z -- including structures for - *communicating with board as well modest changes to original - *structures to support new features. - * - *Revision 1.5 1995/11/13 21:13:31 bentson - *changes suggested by Michael Chastain <mec@duracef.shout.net> - *to support use of this file in non-kernel applications - * - * - */ -#ifndef _LINUX_CYCLADES_H -#define _LINUX_CYCLADES_H - -#include <uapi/linux/cyclades.h> - - -/* Per card data structure */ -struct cyclades_card { - void __iomem *base_addr; - union { - void __iomem *p9050; - struct RUNTIME_9060 __iomem *p9060; - } ctl_addr; - struct BOARD_CTRL __iomem *board_ctrl; /* cyz specific */ - int irq; - unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */ - unsigned int first_line; /* minor number of first channel on card */ - unsigned int nports; /* Number of ports in the card */ - int bus_index; /* address shift - 0 for ISA, 1 for PCI */ - int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */ - u32 hw_ver; - spinlock_t card_lock; - struct cyclades_port *ports; -}; - -/*************************************** - * Memory access functions/macros * - * (required to support Alpha systems) * - ***************************************/ - -#define cy_writeb(port,val) do { writeb((val), (port)); mb(); } while (0) -#define cy_writew(port,val) do { writew((val), (port)); mb(); } while (0) -#define cy_writel(port,val) do { writel((val), (port)); mb(); } while (0) - -/* - * Statistics counters - */ -struct cyclades_icount { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; -}; - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct cyclades_port { - int magic; - struct tty_port port; - struct cyclades_card *card; - union { - struct { - void __iomem *base_addr; - } cyy; - struct { - struct CH_CTRL __iomem *ch_ctrl; - struct BUF_CTRL __iomem *buf_ctrl; - } cyz; - } u; - int line; - int flags; /* defined in tty.h */ - int type; /* UART type */ - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; - int cor1,cor2,cor3,cor4,cor5; - int tbpr,tco,rbpr,rco; - int baud; - int rflow; - int rtsdtr_inv; - int chip_rev; - int custom_divisor; - u8 x_char; /* to be pushed out ASAP */ - int breakon; - int breakoff; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int default_threshold; - int default_timeout; - unsigned long rflush_count; - struct cyclades_monitor mon; - struct cyclades_idle_stats idle_stats; - struct cyclades_icount icount; - struct completion shutdown_wait; - int throttle; -#ifdef CONFIG_CYZ_INTR - struct timer_list rx_full_timer; -#endif -}; - -#define CLOSING_WAIT_DELAY 30*HZ -#define CY_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE -#define CY_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF - - -#define CyMAX_CHIPS_PER_CARD 8 -#define CyMAX_CHAR_FIFO 12 -#define CyPORTS_PER_CHIP 4 -#define CD1400_MAX_SPEED 115200 - -#define CyISA_Ywin 0x2000 - -#define CyPCI_Ywin 0x4000 -#define CyPCI_Yctl 0x80 -#define CyPCI_Zctl CTRL_WINDOW_SIZE -#define CyPCI_Zwin 0x80000 -#define CyPCI_Ze_win (2 * CyPCI_Zwin) - -#define PCI_DEVICE_ID_MASK 0x06 - -/**** CD1400 registers ****/ - -#define CD1400_REV_G 0x46 -#define CD1400_REV_J 0x48 - -#define CyRegSize 0x0400 -#define Cy_HwReset 0x1400 -#define Cy_ClrIntr 0x1800 -#define Cy_EpldRev 0x1e00 - -/* Global Registers */ - -#define CyGFRCR (0x40*2) -#define CyRevE (44) -#define CyCAR (0x68*2) -#define CyCHAN_0 (0x00) -#define CyCHAN_1 (0x01) -#define CyCHAN_2 (0x02) -#define CyCHAN_3 (0x03) -#define CyGCR (0x4B*2) -#define CyCH0_SERIAL (0x00) -#define CyCH0_PARALLEL (0x80) -#define CySVRR (0x67*2) -#define CySRModem (0x04) -#define CySRTransmit (0x02) -#define CySRReceive (0x01) -#define CyRICR (0x44*2) -#define CyTICR (0x45*2) -#define CyMICR (0x46*2) -#define CyICR0 (0x00) -#define CyICR1 (0x01) -#define CyICR2 (0x02) -#define CyICR3 (0x03) -#define CyRIR (0x6B*2) -#define CyTIR (0x6A*2) -#define CyMIR (0x69*2) -#define CyIRDirEq (0x80) -#define CyIRBusy (0x40) -#define CyIRUnfair (0x20) -#define CyIRContext (0x1C) -#define CyIRChannel (0x03) -#define CyPPR (0x7E*2) -#define CyCLOCK_20_1MS (0x27) -#define CyCLOCK_25_1MS (0x31) -#define CyCLOCK_25_5MS (0xf4) -#define CyCLOCK_60_1MS (0x75) -#define CyCLOCK_60_2MS (0xea) - -/* Virtual Registers */ - -#define CyRIVR (0x43*2) -#define CyTIVR (0x42*2) -#define CyMIVR (0x41*2) -#define CyIVRMask (0x07) -#define CyIVRRxEx (0x07) -#define CyIVRRxOK (0x03) -#define CyIVRTxOK (0x02) -#define CyIVRMdmOK (0x01) -#define CyTDR (0x63*2) -#define CyRDSR (0x62*2) -#define CyTIMEOUT (0x80) -#define CySPECHAR (0x70) -#define CyBREAK (0x08) -#define CyPARITY (0x04) -#define CyFRAME (0x02) -#define CyOVERRUN (0x01) -#define CyMISR (0x4C*2) -/* see CyMCOR_ and CyMSVR_ for bits*/ -#define CyEOSRR (0x60*2) - -/* Channel Registers */ - -#define CyLIVR (0x18*2) -#define CyMscsr (0x01) -#define CyTdsr (0x02) -#define CyRgdsr (0x03) -#define CyRedsr (0x07) -#define CyCCR (0x05*2) -/* Format 1 */ -#define CyCHAN_RESET (0x80) -#define CyCHIP_RESET (0x81) -#define CyFlushTransFIFO (0x82) -/* Format 2 */ -#define CyCOR_CHANGE (0x40) -#define CyCOR1ch (0x02) -#define CyCOR2ch (0x04) -#define CyCOR3ch (0x08) -/* Format 3 */ -#define CySEND_SPEC_1 (0x21) -#define CySEND_SPEC_2 (0x22) -#define CySEND_SPEC_3 (0x23) -#define CySEND_SPEC_4 (0x24) -/* Format 4 */ -#define CyCHAN_CTL (0x10) -#define CyDIS_RCVR (0x01) -#define CyENB_RCVR (0x02) -#define CyDIS_XMTR (0x04) -#define CyENB_XMTR (0x08) -#define CySRER (0x06*2) -#define CyMdmCh (0x80) -#define CyRxData (0x10) -#define CyTxRdy (0x04) -#define CyTxMpty (0x02) -#define CyNNDT (0x01) -#define CyCOR1 (0x08*2) -#define CyPARITY_NONE (0x00) -#define CyPARITY_0 (0x20) -#define CyPARITY_1 (0xA0) -#define CyPARITY_E (0x40) -#define CyPARITY_O (0xC0) -#define Cy_1_STOP (0x00) -#define Cy_1_5_STOP (0x04) -#define Cy_2_STOP (0x08) -#define Cy_5_BITS (0x00) -#define Cy_6_BITS (0x01) -#define Cy_7_BITS (0x02) -#define Cy_8_BITS (0x03) -#define CyCOR2 (0x09*2) -#define CyIXM (0x80) -#define CyTxIBE (0x40) -#define CyETC (0x20) -#define CyAUTO_TXFL (0x60) -#define CyLLM (0x10) -#define CyRLM (0x08) -#define CyRtsAO (0x04) -#define CyCtsAE (0x02) -#define CyDsrAE (0x01) -#define CyCOR3 (0x0A*2) -#define CySPL_CH_DRANGE (0x80) /* special character detect range */ -#define CySPL_CH_DET1 (0x40) /* enable special character detection - on SCHR4-SCHR3 */ -#define CyFL_CTRL_TRNSP (0x20) /* Flow Control Transparency */ -#define CySPL_CH_DET2 (0x10) /* Enable special character detection - on SCHR2-SCHR1 */ -#define CyREC_FIFO (0x0F) /* Receive FIFO threshold */ -#define CyCOR4 (0x1E*2) -#define CyCOR5 (0x1F*2) -#define CyCCSR (0x0B*2) -#define CyRxEN (0x80) -#define CyRxFloff (0x40) -#define CyRxFlon (0x20) -#define CyTxEN (0x08) -#define CyTxFloff (0x04) -#define CyTxFlon (0x02) -#define CyRDCR (0x0E*2) -#define CySCHR1 (0x1A*2) -#define CySCHR2 (0x1B*2) -#define CySCHR3 (0x1C*2) -#define CySCHR4 (0x1D*2) -#define CySCRL (0x22*2) -#define CySCRH (0x23*2) -#define CyLNC (0x24*2) -#define CyMCOR1 (0x15*2) -#define CyMCOR2 (0x16*2) -#define CyRTPR (0x21*2) -#define CyMSVR1 (0x6C*2) -#define CyMSVR2 (0x6D*2) -#define CyANY_DELTA (0xF0) -#define CyDSR (0x80) -#define CyCTS (0x40) -#define CyRI (0x20) -#define CyDCD (0x10) -#define CyDTR (0x02) -#define CyRTS (0x01) -#define CyPVSR (0x6F*2) -#define CyRBPR (0x78*2) -#define CyRCOR (0x7C*2) -#define CyTBPR (0x72*2) -#define CyTCOR (0x76*2) - -/* Custom Registers */ - -#define CyPLX_VER (0x3400) -#define PLX_9050 0x0b -#define PLX_9060 0x0c -#define PLX_9080 0x0d - -/***************************************************************************/ - -#endif /* _LINUX_CYCLADES_H */ diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 26ea0850be9bb0a4aecd2d6c25e1f269e7840ee8..142474b4af9637e75323da69f08dd05ee6e605d1 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -38,6 +38,7 @@ enum devfreq_timer { struct devfreq; struct devfreq_governor; +struct thermal_cooling_device; /** * struct devfreq_dev_status - Data given from devfreq user device to @@ -98,11 +99,15 @@ struct devfreq_dev_status { * @freq_table: Optional list of frequencies to support statistics * and freq_table must be generated in ascending order. * @max_state: The size of freq_table. + * + * @is_cooling_device: A self-explanatory boolean giving the device a + * cooling effect property. */ struct devfreq_dev_profile { unsigned long initial_freq; unsigned int polling_ms; enum devfreq_timer timer; + bool is_cooling_device; int (*target)(struct device *dev, unsigned long *freq, u32 flags); int (*get_dev_status)(struct device *dev, @@ -156,6 +161,7 @@ struct devfreq_stats { * @suspend_count: suspend requests counter for a device. * @stats: Statistics of devfreq device behavior * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier + * @cdev: Cooling device pointer if the devfreq has cooling property * @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY * @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY * @@ -198,6 +204,9 @@ struct devfreq { struct srcu_notifier_head transition_notifier_list; + /* Pointer to the cooling device if used for thermal mitigation */ + struct thermal_cooling_device *cdev; + struct notifier_block nb_min; struct notifier_block nb_max; }; diff --git a/include/linux/device.h b/include/linux/device.h index ba660731bd258279d8c9b5513a90015b22fad3e0..38a2071cf77685a3b8c520f4d4eafb50ee080669 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -49,7 +49,7 @@ struct dev_iommu; /** * struct subsys_interface - interfaces to device functions * @name: name of the device function - * @subsys: subsytem of the devices to attach to + * @subsys: subsystem of the devices to attach to * @node: the list of functions registered at the subsystem * @add_dev: device hookup to device function handler * @remove_dev: device hookup to device function handler @@ -439,6 +439,9 @@ struct dev_links_info { * @state_synced: The hardware state of this device has been synced to match * the software state of this device by calling the driver/bus * sync_state() callback. + * @can_match: The device has matched with a driver at least once or it is in + * a bus (like AMBA) which can't check for matching drivers until + * other devices probe successfully. * @dma_coherent: this particular device is dma coherent, even if the * architecture supports non-coherent devices. * @dma_ops_bypass: If set to %true then the dma_ops are bypassed for the @@ -545,6 +548,7 @@ struct device { bool offline:1; bool of_node_reused:1; bool state_synced:1; + bool can_match:1; #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) diff --git a/include/linux/devm-helpers.h b/include/linux/devm-helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..f40f77717a245881d54bcff12082b147e03934d5 --- /dev/null +++ b/include/linux/devm-helpers.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LINUX_DEVM_HELPERS_H +#define __LINUX_DEVM_HELPERS_H + +/* + * Functions which do automatically cancel operations or release resources upon + * driver detach. + * + * These should be helpful to avoid mixing the manual and devm-based resource + * management which can be source of annoying, rarely occurring, + * hard-to-reproduce bugs. + * + * Please take into account that devm based cancellation may be performed some + * time after the remove() is ran. + * + * Thus mixing devm and manual resource management can easily cause problems + * when unwinding operations with dependencies. IRQ scheduling a work in a queue + * is typical example where IRQs are often devm-managed and WQs are manually + * cleaned at remove(). If IRQs are not manually freed at remove() (and this is + * often the case when we use devm for IRQs) we have a period of time after + * remove() - and before devm managed IRQs are freed - where new IRQ may fire + * and schedule a work item which won't be cancelled because remove() was + * already ran. + */ + +#include <linux/device.h> +#include <linux/workqueue.h> + +static inline void devm_delayed_work_drop(void *res) +{ + cancel_delayed_work_sync(res); +} + +/** + * devm_delayed_work_autocancel - Resource-managed delayed work allocation + * @dev: Device which lifetime work is bound to + * @w: Work item to be queued + * @worker: Worker function + * + * Initialize delayed work which is automatically cancelled when driver is + * detached. A few drivers need delayed work which must be cancelled before + * driver is detached to avoid accessing removed resources. + * devm_delayed_work_autocancel() can be used to omit the explicit + * cancelleation when driver is detached. + */ +static inline int devm_delayed_work_autocancel(struct device *dev, + struct delayed_work *w, + work_func_t worker) +{ + INIT_DELAYED_WORK(w, worker); + return devm_add_action(dev, devm_delayed_work_drop, w); +} + +#endif diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h index 883acef895bc4d222c86075974cc55fc23119e02..2e2b8d6140ed47a743c88d03464b9a4d0fc9bcde 100644 --- a/include/linux/entry-common.h +++ b/include/linux/entry-common.h @@ -360,7 +360,7 @@ void syscall_exit_to_user_mode_work(struct pt_regs *regs); * * This is a combination of syscall_exit_to_user_mode_work() (1,2) and * exit_to_user_mode(). This function is preferred unless there is a - * compelling architectural reason to use the seperate functions. + * compelling architectural reason to use the separate functions. */ void syscall_exit_to_user_mode(struct pt_regs *regs); @@ -381,7 +381,7 @@ void irqentry_enter_from_user_mode(struct pt_regs *regs); * irqentry_exit_to_user_mode - Interrupt exit work * @regs: Pointer to current's pt_regs * - * Invoked with interrupts disbled and fully valid regs. Returns with all + * Invoked with interrupts disabled and fully valid regs. Returns with all * work handled, interrupts disabled such that the caller can immediately * switch to user mode. Called from architecture specific interrupt * handling code. diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h new file mode 100644 index 0000000000000000000000000000000000000000..9e37e063ac6984e7ed58d0a8b8abd06cbfda4834 --- /dev/null +++ b/include/linux/fileattr.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_FILEATTR_H +#define _LINUX_FILEATTR_H + +/* Flags shared betwen flags/xflags */ +#define FS_COMMON_FL \ + (FS_SYNC_FL | FS_IMMUTABLE_FL | FS_APPEND_FL | \ + FS_NODUMP_FL | FS_NOATIME_FL | FS_DAX_FL | \ + FS_PROJINHERIT_FL) + +#define FS_XFLAG_COMMON \ + (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND | \ + FS_XFLAG_NODUMP | FS_XFLAG_NOATIME | FS_XFLAG_DAX | \ + FS_XFLAG_PROJINHERIT) + +/* + * Merged interface for miscellaneous file attributes. 'flags' originates from + * ext* and 'fsx_flags' from xfs. There's some overlap between the two, which + * is handled by the VFS helpers, so filesystems are free to implement just one + * or both of these sub-interfaces. + */ +struct fileattr { + u32 flags; /* flags (FS_IOC_GETFLAGS/FS_IOC_SETFLAGS) */ + /* struct fsxattr: */ + u32 fsx_xflags; /* xflags field value (get/set) */ + u32 fsx_extsize; /* extsize field value (get/set)*/ + u32 fsx_nextents; /* nextents field value (get) */ + u32 fsx_projid; /* project identifier (get/set) */ + u32 fsx_cowextsize; /* CoW extsize field value (get/set)*/ + /* selectors: */ + bool flags_valid:1; + bool fsx_valid:1; +}; + +int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa); + +void fileattr_fill_xflags(struct fileattr *fa, u32 xflags); +void fileattr_fill_flags(struct fileattr *fa, u32 flags); + +/** + * fileattr_has_fsx - check for extended flags/attributes + * @fa: fileattr pointer + * + * Return: true if any attributes are present that are not represented in + * ->flags. + */ +static inline bool fileattr_has_fsx(const struct fileattr *fa) +{ + return fa->fsx_valid && + ((fa->fsx_xflags & ~FS_XFLAG_COMMON) || fa->fsx_extsize != 0 || + fa->fsx_projid != 0 || fa->fsx_cowextsize != 0); +} + +int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); +int vfs_fileattr_set(struct user_namespace *mnt_userns, struct dentry *dentry, + struct fileattr *fa); + +#endif /* _LINUX_FILEATTR_H */ diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 71177b17eee5e58f03bd53d07d654bbe3ae0d1c4..66e2423d9feb73e02693d92647f9dd58b65f2c8a 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -354,11 +354,6 @@ int zynqmp_pm_read_pggs(u32 index, u32 *value); int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype); int zynqmp_pm_set_boot_health_status(u32 value); #else -static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) -{ - return ERR_PTR(-ENODEV); -} - static inline int zynqmp_pm_get_api_version(u32 *version) { return -ENODEV; diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 27828145ca0985d77d37123602ce0ff01a7a7145..0621c5f86c397e62d549051c19d97b4dff626748 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -279,7 +279,6 @@ static inline int freeze_kernel_threads(void) { return -ENOSYS; } static inline void thaw_processes(void) {} static inline void thaw_kernel_threads(void) {} -static inline bool try_to_freeze_nowarn(void) { return false; } static inline bool try_to_freeze(void) { return false; } static inline void freezer_do_not_count(void) {} diff --git a/include/linux/fs.h b/include/linux/fs.h index 7347a82471c29663026fa7affd6d02bb8a5e6bca..d8b91efb7edace61d5a3a528f54789dceff9296b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -70,6 +70,7 @@ struct fsverity_info; struct fsverity_operations; struct fs_context; struct fs_parameter_spec; +struct fileattr; extern void __init inode_init(void); extern void __init inode_init_early(void); @@ -891,18 +892,22 @@ struct fown_struct { int signum; /* posix.1b rt signal to be delivered on IO */ }; -/* - * Track a single file's readahead state +/** + * struct file_ra_state - Track a file's readahead state. + * @start: Where the most recent readahead started. + * @size: Number of pages read in the most recent readahead. + * @async_size: Start next readahead when this many pages are left. + * @ra_pages: Maximum size of a readahead request. + * @mmap_miss: How many mmap accesses missed in the page cache. + * @prev_pos: The last byte in the most recent read request. */ struct file_ra_state { - pgoff_t start; /* where readahead started */ - unsigned int size; /* # of readahead pages */ - unsigned int async_size; /* do asynchronous readahead when - there are only # of pages ahead */ - - unsigned int ra_pages; /* Maximum readahead window */ - unsigned int mmap_miss; /* Cache miss stat for mmap accesses */ - loff_t prev_pos; /* Cache last read() position */ + pgoff_t start; + unsigned int size; + unsigned int async_size; + unsigned int ra_pages; + unsigned int mmap_miss; + loff_t prev_pos; }; /* @@ -1574,52 +1579,172 @@ static inline void i_gid_write(struct inode *inode, gid_t gid) inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid); } +/** + * kuid_into_mnt - map a kuid down into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kuid: kuid to be mapped + * + * Return: @kuid mapped according to @mnt_userns. + * If @kuid has no mapping INVALID_UID is returned. + */ static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, kuid_t kuid) { return make_kuid(mnt_userns, __kuid_val(kuid)); } +/** + * kgid_into_mnt - map a kgid down into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kgid: kgid to be mapped + * + * Return: @kgid mapped according to @mnt_userns. + * If @kgid has no mapping INVALID_GID is returned. + */ static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, kgid_t kgid) { return make_kgid(mnt_userns, __kgid_val(kgid)); } +/** + * i_uid_into_mnt - map an inode's i_uid down into a mnt_userns + * @mnt_userns: user namespace of the mount the inode was found from + * @inode: inode to map + * + * Return: the inode's i_uid mapped down according to @mnt_userns. + * If the inode's i_uid has no mapping INVALID_UID is returned. + */ static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, const struct inode *inode) { return kuid_into_mnt(mnt_userns, inode->i_uid); } +/** + * i_gid_into_mnt - map an inode's i_gid down into a mnt_userns + * @mnt_userns: user namespace of the mount the inode was found from + * @inode: inode to map + * + * Return: the inode's i_gid mapped down according to @mnt_userns. + * If the inode's i_gid has no mapping INVALID_GID is returned. + */ static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, const struct inode *inode) { return kgid_into_mnt(mnt_userns, inode->i_gid); } +/** + * kuid_from_mnt - map a kuid up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kuid: kuid to be mapped + * + * Return: @kuid mapped up according to @mnt_userns. + * If @kuid has no mapping INVALID_UID is returned. + */ static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, kuid_t kuid) { return KUIDT_INIT(from_kuid(mnt_userns, kuid)); } +/** + * kgid_from_mnt - map a kgid up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kgid: kgid to be mapped + * + * Return: @kgid mapped up according to @mnt_userns. + * If @kgid has no mapping INVALID_GID is returned. + */ static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, kgid_t kgid) { return KGIDT_INIT(from_kgid(mnt_userns, kgid)); } -static inline kuid_t fsuid_into_mnt(struct user_namespace *mnt_userns) +/** + * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsuid. A common example is initializing the i_uid field of + * a newly allocated inode triggered by a creation event such as mkdir or + * O_CREAT. Other examples include the allocation of quotas for a specific + * user. + * + * Return: the caller's current fsuid mapped up according to @mnt_userns. + */ +static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) { return kuid_from_mnt(mnt_userns, current_fsuid()); } -static inline kgid_t fsgid_into_mnt(struct user_namespace *mnt_userns) +/** + * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsgid. A common example is initializing the i_gid field of + * a newly allocated inode triggered by a creation event such as mkdir or + * O_CREAT. Other examples include the allocation of quotas for a specific + * user. + * + * Return: the caller's current fsgid mapped up according to @mnt_userns. + */ +static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) { return kgid_from_mnt(mnt_userns, current_fsgid()); } +/** + * inode_fsuid_set - initialize inode's i_uid field with callers fsuid + * @inode: inode to initialize + * @mnt_userns: user namespace of the mount the inode was found from + * + * Initialize the i_uid field of @inode. If the inode was found/created via + * an idmapped mount map the caller's fsuid according to @mnt_users. + */ +static inline void inode_fsuid_set(struct inode *inode, + struct user_namespace *mnt_userns) +{ + inode->i_uid = mapped_fsuid(mnt_userns); +} + +/** + * inode_fsgid_set - initialize inode's i_gid field with callers fsgid + * @inode: inode to initialize + * @mnt_userns: user namespace of the mount the inode was found from + * + * Initialize the i_gid field of @inode. If the inode was found/created via + * an idmapped mount map the caller's fsgid according to @mnt_users. + */ +static inline void inode_fsgid_set(struct inode *inode, + struct user_namespace *mnt_userns) +{ + inode->i_gid = mapped_fsgid(mnt_userns); +} + +/** + * fsuidgid_has_mapping() - check whether caller's fsuid/fsgid is mapped + * @sb: the superblock we want a mapping in + * @mnt_userns: user namespace of the relevant mount + * + * Check whether the caller's fsuid and fsgid have a valid mapping in the + * s_user_ns of the superblock @sb. If the caller is on an idmapped mount map + * the caller's fsuid and fsgid according to the @mnt_userns first. + * + * Return: true if fsuid and fsgid is mapped, false if not. + */ +static inline bool fsuidgid_has_mapping(struct super_block *sb, + struct user_namespace *mnt_userns) +{ + struct user_namespace *s_user_ns = sb->s_user_ns; + + return kuid_has_mapping(s_user_ns, mapped_fsuid(mnt_userns)) && + kgid_has_mapping(s_user_ns, mapped_fsgid(mnt_userns)); +} + extern struct timespec64 current_time(struct inode *inode); /* @@ -1739,7 +1864,7 @@ static inline void sb_start_pagefault(struct super_block *sb) __sb_start_write(sb, SB_FREEZE_PAGEFAULT); } -/* +/** * sb_start_intwrite - get write access to a superblock for internal fs purposes * @sb: the super we write to * @@ -1782,6 +1907,17 @@ int vfs_rmdir(struct user_namespace *, struct inode *, struct dentry *); int vfs_unlink(struct user_namespace *, struct inode *, struct dentry *, struct inode **); +/** + * struct renamedata - contains all information required for renaming + * @old_mnt_userns: old user namespace of the mount the inode was found from + * @old_dir: parent of source + * @old_dentry: source + * @new_mnt_userns: new user namespace of the mount the inode was found from + * @new_dir: parent of destination + * @new_dentry: destination + * @delegated_inode: returns an inode needing a delegation break + * @flags: rename flags + */ struct renamedata { struct user_namespace *old_mnt_userns; struct inode *old_dir; @@ -1963,6 +2099,9 @@ struct inode_operations { struct dentry *, umode_t); int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int); + int (*fileattr_set)(struct user_namespace *mnt_userns, + struct dentry *dentry, struct fileattr *fa); + int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); } ____cacheline_aligned; static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio, @@ -2884,6 +3023,11 @@ static inline bool execute_ok(struct inode *inode) return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); } +static inline bool inode_wrong_type(const struct inode *inode, umode_t mode) +{ + return (inode->i_mode ^ mode) & S_IFMT; +} + static inline void file_start_write(struct file *file) { if (!S_ISREG(file_inode(file)->i_mode)) @@ -3161,7 +3305,7 @@ static inline ssize_t blockdev_direct_IO(struct kiocb *iocb, void inode_dio_wait(struct inode *inode); -/* +/** * inode_dio_begin - signal start of a direct I/O requests * @inode: inode the direct I/O happens on * @@ -3173,7 +3317,7 @@ static inline void inode_dio_begin(struct inode *inode) atomic_inc(&inode->i_dio_count); } -/* +/** * inode_dio_end - signal finish of a direct I/O requests * @inode: inode the direct I/O happens on * @@ -3572,18 +3716,6 @@ extern int vfs_fadvise(struct file *file, loff_t offset, loff_t len, extern int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice); -int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags, - unsigned int flags); - -int vfs_ioc_fssetxattr_check(struct inode *inode, const struct fsxattr *old_fa, - struct fsxattr *fa); - -static inline void simple_fill_fsxattr(struct fsxattr *fa, __u32 xflags) -{ - memset(fa, 0, sizeof(*fa)); - fa->fsx_xflags = xflags; -} - /* * Flush file data before changing attributes. Caller must hold any locks * required to prevent further writes to this file until we're done setting diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 3f0b19dcfae79bd0818ffbc527ae2e4ce7ea4204..3235ddbdcc09c70cb9dbaa7c4ac3f308e79192e2 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -304,6 +304,10 @@ struct fscache_cache_ops { /* dissociate a cache from all the pages it was backing */ void (*dissociate_pages)(struct fscache_cache *cache); + + /* Begin a read operation for the netfs lib */ + int (*begin_read_operation)(struct netfs_read_request *rreq, + struct fscache_retrieval *op); }; extern struct fscache_cookie fscache_fsdef_index; diff --git a/include/linux/fscache.h b/include/linux/fscache.h index a1c928fe98e7cb9f6b0eef78bdbbb134dcdacf4e..abc1c4737fb88740aacd78eed656f223d8eed0da 100644 --- a/include/linux/fscache.h +++ b/include/linux/fscache.h @@ -19,6 +19,7 @@ #include <linux/pagemap.h> #include <linux/pagevec.h> #include <linux/list_bl.h> +#include <linux/netfs.h> #if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE) #define fscache_available() (1) @@ -29,16 +30,6 @@ #endif -/* - * overload PG_private_2 to give us PG_fscache - this is used to indicate that - * a page is currently backed by a local disk cache - */ -#define PageFsCache(page) PagePrivate2((page)) -#define SetPageFsCache(page) SetPagePrivate2((page)) -#define ClearPageFsCache(page) ClearPagePrivate2((page)) -#define TestSetPageFsCache(page) TestSetPagePrivate2((page)) -#define TestClearPageFsCache(page) TestClearPagePrivate2((page)) - /* pattern used to fill dead space in an index entry */ #define FSCACHE_INDEX_DEADFILL_PATTERN 0x79 @@ -46,6 +37,7 @@ struct pagevec; struct fscache_cache_tag; struct fscache_cookie; struct fscache_netfs; +struct netfs_read_request; typedef void (*fscache_rw_complete_t)(struct page *page, void *context, @@ -200,6 +192,10 @@ extern void __fscache_update_cookie(struct fscache_cookie *, const void *); extern int __fscache_attr_changed(struct fscache_cookie *); extern void __fscache_invalidate(struct fscache_cookie *); extern void __fscache_wait_on_invalidate(struct fscache_cookie *); + +#ifdef FSCACHE_USE_NEW_IO_API +extern int __fscache_begin_read_operation(struct netfs_read_request *, struct fscache_cookie *); +#else extern int __fscache_read_or_alloc_page(struct fscache_cookie *, struct page *, fscache_rw_complete_t, @@ -223,6 +219,8 @@ extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *, struct inode *); extern void __fscache_readpages_cancel(struct fscache_cookie *cookie, struct list_head *pages); +#endif /* FSCACHE_USE_NEW_IO_API */ + extern void __fscache_disable_cookie(struct fscache_cookie *, const void *, bool); extern void __fscache_enable_cookie(struct fscache_cookie *, const void *, loff_t, bool (*)(void *), void *); @@ -507,6 +505,36 @@ int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size) return -ENOBUFS; } +#ifdef FSCACHE_USE_NEW_IO_API + +/** + * fscache_begin_read_operation - Begin a read operation for the netfs lib + * @rreq: The read request being undertaken + * @cookie: The cookie representing the cache object + * + * Begin a read operation on behalf of the netfs helper library. @rreq + * indicates the read request to which the operation state should be attached; + * @cookie indicates the cache object that will be accessed. + * + * This is intended to be called from the ->begin_cache_operation() netfs lib + * operation as implemented by the network filesystem. + * + * Returns: + * * 0 - Success + * * -ENOBUFS - No caching available + * * Other error code from the cache, such as -ENOMEM. + */ +static inline +int fscache_begin_read_operation(struct netfs_read_request *rreq, + struct fscache_cookie *cookie) +{ + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) + return __fscache_begin_read_operation(rreq, cookie); + return -ENOBUFS; +} + +#else /* FSCACHE_USE_NEW_IO_API */ + /** * fscache_read_or_alloc_page - Read a page from the cache or allocate a block * in which to store it @@ -786,6 +814,8 @@ void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, __fscache_uncache_all_inode_pages(cookie, inode); } +#endif /* FSCACHE_USE_NEW_IO_API */ + /** * fscache_disable_cookie - Disable a cookie * @cookie: The cookie representing the cache object diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h index 0ac27b233f12c2a429cd02dd4921038d54e508d6..fdb55ca47a4f7eedb2de25a00910b9e168c2bff7 100644 --- a/include/linux/fsl/guts.h +++ b/include/linux/fsl/guts.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/** +/* * Freecale 85xx and 86xx Global Utilties register set * * Authors: Jeff Brown @@ -14,7 +14,7 @@ #include <linux/types.h> #include <linux/io.h> -/** +/* * Global Utility Registers. * * Not all registers defined in this structure are available on all chips, so diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 7c9d6a2d7e90905ffa267df45a2e4ec040c29a76..69bc86ea382c2d9e503831f9e6b5bffe798519e0 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -6,6 +6,7 @@ #include <linux/preempt.h> #include <linux/lockdep.h> #include <linux/ftrace_irq.h> +#include <linux/sched.h> #include <linux/vtime.h> #include <asm/hardirq.h> diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 763802b2b8f99c4ad26427746fe9e63d9cf979cd..c27329e2a5ad57851c55cbdaefc382ae6512a350 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -231,6 +231,7 @@ struct hid_sensor_common { struct hid_sensor_hub_attribute_info report_state; struct hid_sensor_hub_attribute_info power_state; struct hid_sensor_hub_attribute_info sensitivity; + struct hid_sensor_hub_attribute_info sensitivity_rel; struct hid_sensor_hub_attribute_info report_latency; struct work_struct work; }; @@ -248,11 +249,17 @@ static inline int hid_sensor_convert_exponent(int unit_expo) int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, - struct hid_sensor_common *st); + struct hid_sensor_common *st, + const u32 *sensitivity_addresses, + u32 sensitivity_addresses_len); int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, int val1, int val2); +int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, int val1, + int val2); int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, int *val1, int *val2); +int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, + int *val1, int *val2); int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, int val1, int val2); int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 3bbdbccc580562506913f65ba3c283f33510b9f0..ac631159403a748b0d6aa91a8953f531ab87abf3 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -149,6 +149,7 @@ /* Per data field properties */ #define HID_USAGE_SENSOR_DATA_MOD_NONE 0x00 #define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000 +#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT 0xE000 /* Power state enumerations */ #define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x200850 diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index f1d74dcf0353f6e32f1bc8c6b7ed26fcc527120c..9c2373a1cb2d14f14c663005839226ea59a1e448 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -234,6 +234,7 @@ static inline u32 hv_get_avail_to_write_percent( * 5 . 0 (Newer Windows 10) * 5 . 1 (Windows 10 RS4) * 5 . 2 (Windows Server 2019, RS5) + * 5 . 3 (Windows Server 2022) */ #define VERSION_WS2008 ((0 << 16) | (13)) @@ -245,6 +246,7 @@ static inline u32 hv_get_avail_to_write_percent( #define VERSION_WIN10_V5 ((5 << 16) | (0)) #define VERSION_WIN10_V5_1 ((5 << 16) | (1)) #define VERSION_WIN10_V5_2 ((5 << 16) | (2)) +#define VERSION_WIN10_V5_3 ((5 << 16) | (3)) /* Make maximum size of pipe payload of 16K */ #define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384) @@ -284,7 +286,7 @@ struct vmbus_channel_offer { /* * Pipes: - * The following sructure is an integrated pipe protocol, which + * The following structure is an integrated pipe protocol, which * is implemented on top of standard user-defined data. Pipe * clients have MAX_PIPE_USER_DEFINED_BYTES left for their own * use. @@ -475,6 +477,7 @@ enum vmbus_channel_message_type { CHANNELMSG_TL_CONNECT_REQUEST = 21, CHANNELMSG_MODIFYCHANNEL = 22, CHANNELMSG_TL_CONNECT_RESULT = 23, + CHANNELMSG_MODIFYCHANNEL_RESPONSE = 24, CHANNELMSG_COUNT }; @@ -588,6 +591,13 @@ struct vmbus_channel_open_result { u32 status; } __packed; +/* Modify Channel Result parameters */ +struct vmbus_channel_modifychannel_response { + struct vmbus_channel_message_header header; + u32 child_relid; + u32 status; +} __packed; + /* Close channel parameters; */ struct vmbus_channel_close_channel { struct vmbus_channel_message_header header; @@ -720,6 +730,7 @@ struct vmbus_channel_msginfo { struct vmbus_channel_gpadl_torndown gpadl_torndown; struct vmbus_channel_gpadl_created gpadl_created; struct vmbus_channel_version_response version_response; + struct vmbus_channel_modifychannel_response modify_response; } response; u32 msgsize; @@ -883,11 +894,11 @@ struct vmbus_channel { * Support for sub-channels. For high performance devices, * it will be useful to have multiple sub-channels to support * a scalable communication infrastructure with the host. - * The support for sub-channels is implemented as an extention + * The support for sub-channels is implemented as an extension * to the current infrastructure. * The initial offer is considered the primary channel and this * offer message will indicate if the host supports sub-channels. - * The guest is free to ask for sub-channels to be offerred and can + * The guest is free to ask for sub-channels to be offered and can * open these sub-channels as a normal "primary" channel. However, * all sub-channels will have the same type and instance guids as the * primary channel. Requests sent on a given channel will result in a @@ -951,7 +962,7 @@ struct vmbus_channel { * Clearly, these optimizations improve throughput at the expense of * latency. Furthermore, since the channel is shared for both * control and data messages, control messages currently suffer - * unnecessary latency adversley impacting performance and boot + * unnecessary latency adversely impacting performance and boot * time. To fix this issue, permit tagging the channel as being * in "low latency" mode. In this mode, we will bypass the monitor * mechanism. @@ -1594,7 +1605,7 @@ extern __u32 vmbus_proto_version; int vmbus_send_tl_connect_request(const guid_t *shv_guest_servie_id, const guid_t *shv_host_servie_id); -int vmbus_send_modifychannel(u32 child_relid, u32 target_vp); +int vmbus_send_modifychannel(struct vmbus_channel *channel, u32 target_vp); void vmbus_set_event(struct vmbus_channel *channel); /* Get the start of the ring buffer. */ diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h index c5d48e1c2d36159449f1a461b413f50492bd504e..52620e5b80522ee75e5223092bbb4ed2e31c4b45 100644 --- a/include/linux/iio/adc/adi-axi-adc.h +++ b/include/linux/iio/adc/adi-axi-adc.h @@ -15,7 +15,7 @@ struct iio_chan_spec; * struct adi_axi_adc_chip_info - Chip specific information * @name Chip name * @id Chip ID (usually product ID) - * @channels Channel specifications of type @struct axi_adc_chan_spec + * @channels Channel specifications of type @struct iio_chan_spec * @num_channels Number of @channels * @scale_table Supported scales by the chip; tuples of 2 ints * @num_scales Number of scales in the table diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index 5b502291d6a44622747afc3232e304df606ec05d..5c355be8981493bce03fdaa5a16b0cae080dc0e9 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -7,10 +7,11 @@ #ifndef __IIO_DMAENGINE_H__ #define __IIO_DMAENGINE_H__ -struct iio_buffer; +struct iio_dev; struct device; -struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, - const char *channel); +int devm_iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel); #endif diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 8febc23f5f260691ea70857bd20bac07464e89b8..b6928ac5c63d647ac6bce28e655d4aabda6f7b0a 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -41,7 +41,7 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, const unsigned long *mask); -void iio_device_attach_buffer(struct iio_dev *indio_dev, - struct iio_buffer *buffer); +int iio_device_attach_buffer(struct iio_dev *indio_dev, + struct iio_buffer *buffer); #endif /* _IIO_BUFFER_GENERIC_H_ */ diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index a63dc07b73500b71e0e53d5291dd04734e8bffa5..245b32918ae1164046bcb972c8b827912abf26cb 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -6,6 +6,8 @@ #ifdef CONFIG_IIO_BUFFER +#include <uapi/linux/iio/buffer.h> + struct iio_dev; struct iio_buffer; @@ -72,6 +74,9 @@ struct iio_buffer { /** @length: Number of datums in buffer. */ unsigned int length; + /** @flags: File ops flags including busy flag. */ + unsigned long flags; + /** @bytes_per_datum: Size of individual datum including timestamp. */ size_t bytes_per_datum; @@ -97,17 +102,14 @@ struct iio_buffer { /* @scan_timestamp: Does the scan mode include a timestamp. */ bool scan_timestamp; - /* @scan_el_dev_attr_list: List of scan element related attributes. */ - struct list_head scan_el_dev_attr_list; - - /* @buffer_group: Attributes of the buffer group. */ - struct attribute_group buffer_group; + /* @buffer_attr_list: List of buffer attributes. */ + struct list_head buffer_attr_list; /* - * @scan_el_group: Attribute group for those attributes not - * created from the iio_chan_info array. + * @buffer_group: Attributes of the new buffer group. + * Includes scan elements attributes. */ - struct attribute_group scan_el_group; + struct attribute_group buffer_group; /* @attrs: Standard attributes of the buffer. */ const struct attribute **attrs; @@ -115,6 +117,9 @@ struct iio_buffer { /* @demux_bounce: Buffer for doing gather from incoming scan. */ void *demux_bounce; + /* @attached_entry: Entry in the devices list of buffers attached by the driver. */ + struct list_head attached_entry; + /* @buffer_list: Entry in the devices list of current buffers. */ struct list_head buffer_list; diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index c9b80be82440f87b8820fb82fee7db9f0ea83172..7ce8a8adad587e7cab5690a3b52d8a63ad221c6f 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -96,8 +96,7 @@ struct platform_device; int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device, cros_ec_sensors_capture_t trigger_capture, - cros_ec_sensorhub_push_data_cb_t push_data, - bool has_hw_fifo); + cros_ec_sensorhub_push_data_cb_t push_data); irqreturn_t cros_ec_sensors_capture(int irq, void *p); int cros_ec_sensors_push_data(struct iio_dev *indio_dev, diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 0a90ba8fa1bb75403ab911bb8dc2d1546db4602a..5fa5957586cf4ae040959cce9b31587515ca6b13 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -241,6 +241,21 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val); */ int iio_read_channel_processed(struct iio_channel *chan, int *val); +/** + * iio_read_channel_processed_scale() - read and scale a processed value + * @chan: The channel being queried. + * @val: Value read back. + * @scale: Scale factor to apply during the conversion + * + * Returns an error code or 0. + * + * This function will read a processed value from a channel. This will work + * like @iio_read_channel_processed() but also scale with an additional + * scale factor while attempting to minimize any precision loss. + */ +int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, + unsigned int scale); + /** * iio_write_channel_attribute() - Write values to the device attribute. * @chan: The channel being queried. diff --git a/include/linux/iio/dac/mcp4725.h b/include/linux/iio/dac/mcp4725.h index e9801c8d49c00be2cc84e0585f1f249b5ee1fc6d..1f7e53c506b6f2071e8b5d43abbee85b9c7fad76 100644 --- a/include/linux/iio/dac/mcp4725.h +++ b/include/linux/iio/dac/mcp4725.h @@ -15,7 +15,7 @@ * @vref_buffered: Controls buffering of the external reference voltage. * * Vref related settings are available only on MCP4756. See - * Documentation/devicetree/bindings/iio/dac/mcp4725.txt for more information. + * Documentation/devicetree/bindings/iio/dac/microchip,mcp4725.yaml for more information. */ struct mcp4725_platform_data { bool use_vref; diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index 07c5a8e52ca88df86200c6c3a51eb83a4469d088..32addd5e790e9e661e07181a9986e4390e27750d 100644 --- a/include/linux/iio/iio-opaque.h +++ b/include/linux/iio/iio-opaque.h @@ -7,11 +7,18 @@ * struct iio_dev_opaque - industrial I/O device opaque information * @indio_dev: public industrial I/O device information * @event_interface: event chrdevs associated with interrupt lines + * @attached_buffers: array of buffers statically attached by the driver + * @attached_buffers_cnt: number of buffers in the array of statically attached buffers + * @buffer_ioctl_handler: ioctl() handler for this IIO device's buffer interface * @buffer_list: list of all buffers currently attached * @channel_attr_list: keep track of automatically created channel * attributes * @chan_attr_group: group for all attrs in base directory * @ioctl_handlers: ioctl handlers registered with the core handler + * @groups: attribute groups + * @groupcounter: index of next attribute group + * @legacy_scan_el_group: attribute group for legacy scan elements attribute group + * @legacy_buffer_group: attribute group for legacy buffer attributes group * @debugfs_dentry: device specific debugfs dentry * @cached_reg_addr: cached register address for debugfs reads * @read_buf: read buffer to be used for the initial reg read @@ -20,10 +27,17 @@ struct iio_dev_opaque { struct iio_dev indio_dev; struct iio_event_interface *event_interface; + struct iio_buffer **attached_buffers; + unsigned int attached_buffers_cnt; + struct iio_ioctl_handler *buffer_ioctl_handler; struct list_head buffer_list; struct list_head channel_attr_list; struct attribute_group chan_attr_group; struct list_head ioctl_handlers; + const struct attribute_group **groups; + int groupcounter; + struct attribute_group legacy_scan_el_group; + struct attribute_group legacy_buffer_group; #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_dentry; unsigned cached_reg_addr; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e4a9822e6495028af486c7031ab9bb26ab8eca5c..f2d65e2e88b64a7238da59b03bca7faf3e489360 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -518,8 +518,6 @@ struct iio_buffer_setup_ops { * @setup_ops: [DRIVER] callbacks to call before and after buffer * enable/disable * @chrdev: [INTERN] associated character device - * @groups: [INTERN] attribute groups - * @groupcounter: [INTERN] index of next attribute group * @flags: [INTERN] file ops related flags including busy flag. * @priv: [DRIVER] reference to driver's private information * **MUST** be accessed **ONLY** via iio_priv() helper @@ -556,9 +554,6 @@ struct iio_dev { struct mutex info_exist_lock; const struct iio_buffer_setup_ops *setup_ops; struct cdev chrdev; -#define IIO_MAX_GROUPS 6 - const struct attribute_group *groups[IIO_MAX_GROUPS + 1]; - int groupcounter; unsigned long flags; void *priv; @@ -698,7 +693,7 @@ static inline void *iio_priv(const struct iio_dev *indio_dev) void iio_device_free(struct iio_dev *indio_dev); struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv); __printf(2, 3) -struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, +struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fmt, ...); /** * iio_buffer_enabled() - helper function to test if the buffer is enabled diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 04e96d688ba9eeccf9e573217ab9473973010676..f9b728d490b1f97225533a505ae12f7fbd22a922 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -428,6 +428,16 @@ static inline int adis_initial_startup(struct adis *adis) return ret; } +static inline void adis_dev_lock(struct adis *adis) +{ + mutex_lock(&adis->state_lock); +} + +static inline void adis_dev_unlock(struct adis *adis) +{ + mutex_unlock(&adis->state_lock); +} + int adis_single_conversion(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int error_mask, int *val); diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h index 1fc1efa7799df968d9f350b51f04c16cfcc4de25..ccd2ceae7b25c92fb21da4f23479deee3d557254 100644 --- a/include/linux/iio/kfifo_buf.h +++ b/include/linux/iio/kfifo_buf.h @@ -3,11 +3,20 @@ #define __LINUX_IIO_KFIFO_BUF_H__ struct iio_buffer; +struct iio_buffer_setup_ops; +struct iio_dev; struct device; struct iio_buffer *iio_kfifo_allocate(void); void iio_kfifo_free(struct iio_buffer *r); -struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev); +int devm_iio_kfifo_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + int mode_flags, + const struct iio_buffer_setup_ops *setup_ops, + const struct attribute **buffer_attrs); + +#define devm_iio_kfifo_buffer_setup(dev, indio_dev, mode_flags, setup_ops) \ + devm_iio_kfifo_buffer_setup_ext((dev), (indio_dev), (mode_flags), (setup_ops), NULL) #endif diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index b532c875bc241b0b2dfe890f5d8af6337c0d9b0f..e51fba66de4b259766561170a93cc4ef91b44869 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -9,6 +9,7 @@ #ifndef _INDUSTRIAL_IO_SYSFS_H_ #define _INDUSTRIAL_IO_SYSFS_H_ +struct iio_buffer; struct iio_chan_spec; /** @@ -17,12 +18,14 @@ struct iio_chan_spec; * @address: associated register address * @l: list head for maintaining list of dynamically created attrs * @c: specification for the underlying channel + * @buffer: the IIO buffer to which this attribute belongs to (if any) */ struct iio_dev_attr { struct device_attribute dev_attr; u64 address; struct list_head l; struct iio_chan_spec const *c; + struct iio_buffer *buffer; }; #define to_iio_dev_attr(_dev_attr) \ diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 055890b6ffcf0a60b8277b7c037f4bc0871fcb86..096f68dd2e0caaf761ade35cd8b9624fd88fb7da 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -161,7 +161,8 @@ void iio_trigger_poll_chained(struct iio_trigger *trig); irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private); -__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...); +__printf(2, 3) +struct iio_trigger *iio_trigger_alloc(struct device *parent, const char *fmt, ...); void iio_trigger_free(struct iio_trigger *trig); /** diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 1e3ed6f55bca03d7a4ad1aab2679f303873f6475..84b3f8175cc6bb82ebbdbdf959ae880d9e65e8c3 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -16,6 +16,7 @@ enum iio_event_info { IIO_EV_INFO_PERIOD, IIO_EV_INFO_HIGH_PASS_FILTER_3DB, IIO_EV_INFO_LOW_PASS_FILTER_3DB, + IIO_EV_INFO_TIMEOUT, }; #define IIO_VAL_INT 1 @@ -50,6 +51,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_PHASE, IIO_CHAN_INFO_HARDWAREGAIN, IIO_CHAN_INFO_HYSTERESIS, + IIO_CHAN_INFO_HYSTERESIS_RELATIVE, IIO_CHAN_INFO_INT_TIME, IIO_CHAN_INFO_ENABLE, IIO_CHAN_INFO_CALIBHEIGHT, diff --git a/include/linux/init.h b/include/linux/init.h index 31f54de584298546bc92c71717f533a7dbe952be..045ad1650ed16dacf28f3894ef2414f279e20fe1 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -47,7 +47,7 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __section(".init.text") __cold __latent_entropy __noinitretpoline +#define __init __section(".init.text") __cold __latent_entropy __noinitretpoline __nocfi #define __initdata __section(".init.data") #define __initconst __section(".init.rodata") #define __exitdata __section(".exit.data") @@ -220,8 +220,8 @@ extern bool initcall_debug; __initcall_name(initstub, __iid, id) #define __define_initcall_stub(__stub, fn) \ - int __init __stub(void); \ - int __init __stub(void) \ + int __init __cficanonical __stub(void); \ + int __init __cficanonical __stub(void) \ { \ return fn(); \ } \ diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h index 50b8398ffd214f189c1713a453b5595621d1c16d..93780834fc8f0fa4fca70b35123770758b820893 100644 --- a/include/linux/intel_rapl.h +++ b/include/linux/intel_rapl.h @@ -33,7 +33,7 @@ enum rapl_domain_reg_id { RAPL_DOMAIN_REG_MAX, }; -struct rapl_package; +struct rapl_domain; enum rapl_primitives { ENERGY_COUNTER, diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 967e2576715348c5b75c7f1a3d882d9dd14b8276..4777850a6dc7cdafdaabc95dbac8746559e92094 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -61,6 +61,9 @@ * interrupt handler after suspending interrupts. For system * wakeup devices users need to implement wakeup detection in * their interrupt handlers. + * IRQF_NO_AUTOEN - Don't enable IRQ or NMI automatically when users request it. + * Users will enable it explicitly by enable_irq() or enable_nmi() + * later. */ #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 @@ -74,6 +77,7 @@ #define IRQF_NO_THREAD 0x00010000 #define IRQF_EARLY_RESUME 0x00020000 #define IRQF_COND_SUSPEND 0x00040000 +#define IRQF_NO_AUTOEN 0x00080000 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) @@ -654,26 +658,21 @@ enum TASKLET_STATE_RUN /* Tasklet is running (SMP only) */ }; -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) static inline int tasklet_trylock(struct tasklet_struct *t) { return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state); } -static inline void tasklet_unlock(struct tasklet_struct *t) -{ - smp_mb__before_atomic(); - clear_bit(TASKLET_STATE_RUN, &(t)->state); -} +void tasklet_unlock(struct tasklet_struct *t); +void tasklet_unlock_wait(struct tasklet_struct *t); +void tasklet_unlock_spin_wait(struct tasklet_struct *t); -static inline void tasklet_unlock_wait(struct tasklet_struct *t) -{ - while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); } -} #else -#define tasklet_trylock(t) 1 -#define tasklet_unlock_wait(t) do { } while (0) -#define tasklet_unlock(t) do { } while (0) +static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; } +static inline void tasklet_unlock(struct tasklet_struct *t) { } +static inline void tasklet_unlock_wait(struct tasklet_struct *t) { } +static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t) { } #endif extern void __tasklet_schedule(struct tasklet_struct *t); @@ -698,6 +697,17 @@ static inline void tasklet_disable_nosync(struct tasklet_struct *t) smp_mb__after_atomic(); } +/* + * Do not use in new code. Disabling tasklets from atomic contexts is + * error prone and should be avoided. + */ +static inline void tasklet_disable_in_atomic(struct tasklet_struct *t) +{ + tasklet_disable_nosync(t); + tasklet_unlock_spin_wait(t); + smp_mb(); +} + static inline void tasklet_disable(struct tasklet_struct *t) { tasklet_disable_nosync(t); @@ -712,7 +722,6 @@ static inline void tasklet_enable(struct tasklet_struct *t) } extern void tasklet_kill(struct tasklet_struct *t); -extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu); extern void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); extern void tasklet_setup(struct tasklet_struct *t, diff --git a/include/linux/io.h b/include/linux/io.h index 8394c56babc26fa1a4d99cd75126cf6ca2a26b42..61ff7d6278b694e870e46b946c0f79d95d9d9b14 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -68,6 +68,8 @@ void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset, resource_size_t size); void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, resource_size_t size); +void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset, + resource_size_t size); void devm_iounmap(struct device *dev, void __iomem *addr); int check_signature(const volatile void __iomem *io_addr, const unsigned char *signature, int length); @@ -80,20 +82,20 @@ void devm_memunmap(struct device *dev, void *addr); #ifdef CONFIG_PCI /* * The PCI specifications (Rev 3.0, 3.2.5 "Transaction Ordering and - * Posting") mandate non-posted configuration transactions. There is - * no ioremap API in the kernel that can guarantee non-posted write - * semantics across arches so provide a default implementation for - * mapping PCI config space that defaults to ioremap(); arches - * should override it if they have memory mapping implementations that - * guarantee non-posted writes semantics to make the memory mapping - * compliant with the PCI specification. + * Posting") mandate non-posted configuration transactions. This default + * implementation attempts to use the ioremap_np() API to provide this + * on arches that support it, and falls back to ioremap() on those that + * don't. Overriding this function is deprecated; arches that properly + * support non-posted accesses should implement ioremap_np() instead, which + * this default implementation can then use to return mappings compliant with + * the PCI specification. */ #ifndef pci_remap_cfgspace #define pci_remap_cfgspace pci_remap_cfgspace static inline void __iomem *pci_remap_cfgspace(phys_addr_t offset, size_t size) { - return ioremap(offset, size); + return ioremap_np(offset, size) ?: ioremap(offset, size); } #endif #endif diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 55de385c839cf5648bffc689b2b1aa4253c74f08..8359c50f99884248807f1df7d3990a9dd37663cf 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -108,6 +108,7 @@ struct resource { #define IORESOURCE_MEM_32BIT (3<<3) #define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ #define IORESOURCE_MEM_EXPANSIONROM (1<<6) +#define IORESOURCE_MEM_NONPOSTED (1<<7) /* PnP I/O specific bits (IORESOURCE_BITS) */ #define IORESOURCE_IO_16BIT_ADDR (1<<0) @@ -331,7 +332,7 @@ static inline void irqresource_disabled(struct resource *res, u32 irq) { res->start = irq; res->end = irq; - res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; + res->flags |= IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; } extern struct address_space *iomem_get_mapping(void); diff --git a/include/linux/irq.h b/include/linux/irq.h index 2efde6a79b7ee7095aad7d7123e6cf4f61b97189..31b347c9f8dd01300dfd02cd7662d40c514e7e5d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -116,7 +116,7 @@ enum { * IRQ_SET_MASK_NOCPY - OK, chip did update irq_common_data.affinity * IRQ_SET_MASK_OK_DONE - Same as IRQ_SET_MASK_OK for core. Special code to * support stacked irqchips, which indicates skipping - * all descendent irqchips. + * all descendant irqchips. */ enum { IRQ_SET_MASK_OK = 0, @@ -302,7 +302,7 @@ static inline bool irqd_is_level_type(struct irq_data *d) /* * Must only be called of irqchip.irq_set_affinity() or low level - * hieararchy domain allocation functions. + * hierarchy domain allocation functions. */ static inline void irqd_set_single_target(struct irq_data *d) { @@ -1258,11 +1258,13 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)); */ extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init; #else +#ifndef set_handle_irq #define set_handle_irq(handle_irq) \ do { \ (void)handle_irq; \ WARN_ON(1); \ } while (0) #endif +#endif #endif /* _LINUX_IRQ_H */ diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index f6d092fdb93dc8949ab1e25a4c2e5eb2efeda43e..81cbf85f73def5849f7ca3dd14d82bd4f1727ab6 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -575,67 +575,11 @@ #define ICC_SRE_EL1_DFB (1U << 1) #define ICC_SRE_EL1_SRE (1U << 0) -/* - * Hypervisor interface registers (SRE only) - */ -#define ICH_LR_VIRTUAL_ID_MASK ((1ULL << 32) - 1) - -#define ICH_LR_EOI (1ULL << 41) -#define ICH_LR_GROUP (1ULL << 60) -#define ICH_LR_HW (1ULL << 61) -#define ICH_LR_STATE (3ULL << 62) -#define ICH_LR_PENDING_BIT (1ULL << 62) -#define ICH_LR_ACTIVE_BIT (1ULL << 63) -#define ICH_LR_PHYS_ID_SHIFT 32 -#define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT) -#define ICH_LR_PRIORITY_SHIFT 48 -#define ICH_LR_PRIORITY_MASK (0xffULL << ICH_LR_PRIORITY_SHIFT) - /* These are for GICv2 emulation only */ #define GICH_LR_VIRTUALID (0x3ffUL << 0) #define GICH_LR_PHYSID_CPUID_SHIFT (10) #define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT) -#define ICH_MISR_EOI (1 << 0) -#define ICH_MISR_U (1 << 1) - -#define ICH_HCR_EN (1 << 0) -#define ICH_HCR_UIE (1 << 1) -#define ICH_HCR_NPIE (1 << 3) -#define ICH_HCR_TC (1 << 10) -#define ICH_HCR_TALL0 (1 << 11) -#define ICH_HCR_TALL1 (1 << 12) -#define ICH_HCR_EOIcount_SHIFT 27 -#define ICH_HCR_EOIcount_MASK (0x1f << ICH_HCR_EOIcount_SHIFT) - -#define ICH_VMCR_ACK_CTL_SHIFT 2 -#define ICH_VMCR_ACK_CTL_MASK (1 << ICH_VMCR_ACK_CTL_SHIFT) -#define ICH_VMCR_FIQ_EN_SHIFT 3 -#define ICH_VMCR_FIQ_EN_MASK (1 << ICH_VMCR_FIQ_EN_SHIFT) -#define ICH_VMCR_CBPR_SHIFT 4 -#define ICH_VMCR_CBPR_MASK (1 << ICH_VMCR_CBPR_SHIFT) -#define ICH_VMCR_EOIM_SHIFT 9 -#define ICH_VMCR_EOIM_MASK (1 << ICH_VMCR_EOIM_SHIFT) -#define ICH_VMCR_BPR1_SHIFT 18 -#define ICH_VMCR_BPR1_MASK (7 << ICH_VMCR_BPR1_SHIFT) -#define ICH_VMCR_BPR0_SHIFT 21 -#define ICH_VMCR_BPR0_MASK (7 << ICH_VMCR_BPR0_SHIFT) -#define ICH_VMCR_PMR_SHIFT 24 -#define ICH_VMCR_PMR_MASK (0xffUL << ICH_VMCR_PMR_SHIFT) -#define ICH_VMCR_ENG0_SHIFT 0 -#define ICH_VMCR_ENG0_MASK (1 << ICH_VMCR_ENG0_SHIFT) -#define ICH_VMCR_ENG1_SHIFT 1 -#define ICH_VMCR_ENG1_MASK (1 << ICH_VMCR_ENG1_SHIFT) - -#define ICH_VTR_PRI_BITS_SHIFT 29 -#define ICH_VTR_PRI_BITS_MASK (7 << ICH_VTR_PRI_BITS_SHIFT) -#define ICH_VTR_ID_BITS_SHIFT 23 -#define ICH_VTR_ID_BITS_MASK (7 << ICH_VTR_ID_BITS_SHIFT) -#define ICH_VTR_SEIS_SHIFT 22 -#define ICH_VTR_SEIS_MASK (1 << ICH_VTR_SEIS_SHIFT) -#define ICH_VTR_A3V_SHIFT 21 -#define ICH_VTR_A3V_MASK (1 << ICH_VTR_A3V_SHIFT) - #define ICC_IAR1_EL1_SPURIOUS 0x3ff #define ICC_SRE_EL2_SRE (1 << 0) diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index 943c3411ca1012510fec3c22b7c139f2c7dbe05a..2c63375bbd43f41d3c5019ab4f4f3583196b522f 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -145,4 +145,6 @@ int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *vpe_ops, const struct irq_domain_ops *sgi_ops); +bool gic_cpuif_has_vsgi(void); + #endif diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 891b323266dfc0277e1b2a69694871fb830ed6ce..df465125078552b097e38ccf26e9e4b0249e6970 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -32,7 +32,7 @@ struct pt_regs; * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts * @threads_handled: stats field for deferred spurious detection of threaded handlers - * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers + * @threads_handled_last: comparator field for deferred spurious detection of threaded handlers * @lock: locking for SMP * @affinity_hint: hint to user space for preferred irq affinity * @affinity_notify: context for notification of affinity changes diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 33cacc8af26dab4f582d986054c4164d02d73d6c..7a1dd7b969b6eb408bd718044fe3b808038463d6 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -415,15 +415,6 @@ static inline unsigned int irq_linear_revmap(struct irq_domain *domain, extern unsigned int irq_find_mapping(struct irq_domain *host, irq_hw_number_t hwirq); extern unsigned int irq_create_direct_mapping(struct irq_domain *host); -extern int irq_create_strict_mappings(struct irq_domain *domain, - unsigned int irq_base, - irq_hw_number_t hwirq_base, int count); - -static inline int irq_create_identity_mapping(struct irq_domain *host, - irq_hw_number_t hwirq) -{ - return irq_create_strict_mappings(host, hwirq, hwirq, 1); -} extern const struct irq_domain_ops irq_domain_simple_ops; diff --git a/include/linux/isicom.h b/include/linux/isicom.h deleted file mode 100644 index 7de6822d7b1a3c0978c5a2d588b492bdb39308a7..0000000000000000000000000000000000000000 --- a/include/linux/isicom.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_ISICOM_H -#define _LINUX_ISICOM_H - -#define YES 1 -#define NO 0 - -/* - * ISICOM Driver definitions ... - * - */ - -#define ISICOM_NAME "ISICom" - -/* - * PCI definitions - */ - -#define DEVID_COUNT 9 -#define VENDOR_ID 0x10b5 - -/* - * These are now officially allocated numbers - */ - -#define ISICOM_NMAJOR 112 /* normal */ -#define ISICOM_CMAJOR 113 /* callout */ -#define ISICOM_MAGIC (('M' << 8) | 'T') - -#define WAKEUP_CHARS 256 /* hard coded for now */ -#define TX_SIZE 254 - -#define BOARD_COUNT 4 -#define PORT_COUNT (BOARD_COUNT*16) - -/* character sizes */ - -#define ISICOM_CS5 0x0000 -#define ISICOM_CS6 0x0001 -#define ISICOM_CS7 0x0002 -#define ISICOM_CS8 0x0003 - -/* stop bits */ - -#define ISICOM_1SB 0x0000 -#define ISICOM_2SB 0x0004 - -/* parity */ - -#define ISICOM_NOPAR 0x0000 -#define ISICOM_ODPAR 0x0008 -#define ISICOM_EVPAR 0x0018 - -/* flow control */ - -#define ISICOM_CTSRTS 0x03 -#define ISICOM_INITIATE_XONXOFF 0x04 -#define ISICOM_RESPOND_XONXOFF 0x08 - -#define BOARD(line) (((line) >> 4) & 0x3) - - /* isi kill queue bitmap */ - -#define ISICOM_KILLTX 0x01 -#define ISICOM_KILLRX 0x02 - - /* isi_board status bitmap */ - -#define FIRMWARE_LOADED 0x0001 -#define BOARD_ACTIVE 0x0002 -#define BOARD_INIT 0x0004 - - /* isi_port status bitmap */ - -#define ISI_CTS 0x1000 -#define ISI_DSR 0x2000 -#define ISI_RI 0x4000 -#define ISI_DCD 0x8000 -#define ISI_DTR 0x0100 -#define ISI_RTS 0x0200 - - -#define ISI_TXOK 0x0001 - -#endif /* ISICOM_H */ diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index d92691262f51a6ef5c0a2efa4df6ab4668b6f920..05f5554d860f5cd44e80885a084da7dfd60f93fe 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -382,6 +382,21 @@ struct static_key_false { [0 ... (count) - 1] = STATIC_KEY_FALSE_INIT, \ } +#define _DEFINE_STATIC_KEY_1(name) DEFINE_STATIC_KEY_TRUE(name) +#define _DEFINE_STATIC_KEY_0(name) DEFINE_STATIC_KEY_FALSE(name) +#define DEFINE_STATIC_KEY_MAYBE(cfg, name) \ + __PASTE(_DEFINE_STATIC_KEY_, IS_ENABLED(cfg))(name) + +#define _DEFINE_STATIC_KEY_RO_1(name) DEFINE_STATIC_KEY_TRUE_RO(name) +#define _DEFINE_STATIC_KEY_RO_0(name) DEFINE_STATIC_KEY_FALSE_RO(name) +#define DEFINE_STATIC_KEY_MAYBE_RO(cfg, name) \ + __PASTE(_DEFINE_STATIC_KEY_RO_, IS_ENABLED(cfg))(name) + +#define _DECLARE_STATIC_KEY_1(name) DECLARE_STATIC_KEY_TRUE(name) +#define _DECLARE_STATIC_KEY_0(name) DECLARE_STATIC_KEY_FALSE(name) +#define DECLARE_STATIC_KEY_MAYBE(cfg, name) \ + __PASTE(_DECLARE_STATIC_KEY_, IS_ENABLED(cfg))(name) + extern bool ____wrong_branch_error(void); #define static_key_enabled(x) \ @@ -482,6 +497,10 @@ extern bool ____wrong_branch_error(void); #endif /* CONFIG_JUMP_LABEL */ +#define static_branch_maybe(config, x) \ + (IS_ENABLED(config) ? static_branch_likely(x) \ + : static_branch_unlikely(x)) + /* * Advanced usage; refcount, branch is enabled when: count != 0 */ diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 14f72ec964922ca95cc23ec7f3dda5244a61caef..d53ea3c047bcde816c4837616ff410b8217d8e05 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -376,6 +376,12 @@ static inline void *kasan_reset_tag(const void *addr) #endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS*/ +#ifdef CONFIG_KASAN_HW_TAGS + +void kasan_report_async(void); + +#endif /* CONFIG_KASAN_HW_TAGS */ + #ifdef CONFIG_KASAN_SW_TAGS void __init kasan_init_sw_tags(void); #else diff --git a/include/linux/list_sort.h b/include/linux/list_sort.h index 20f178c24e9d13db3ddb4d628f1085831410b30b..453105f74e050451b4c65748218b9fbd03b5db0f 100644 --- a/include/linux/list_sort.h +++ b/include/linux/list_sort.h @@ -6,8 +6,9 @@ struct list_head; +typedef int __attribute__((nonnull(2,3))) (*list_cmp_func_t)(void *, + const struct list_head *, const struct list_head *); + __attribute__((nonnull(2,3))) -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)); +void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp); #endif diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 477a597db0130534b3b1c61b379e84d7e1f24c76..61f04f7dc1a4aeedafaf8684791edee4073855b6 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -62,6 +62,7 @@ LSM_HOOK(int, 0, sb_alloc_security, struct super_block *sb) LSM_HOOK(void, LSM_RET_VOID, sb_free_security, struct super_block *sb) LSM_HOOK(void, LSM_RET_VOID, sb_free_mnt_opts, void *mnt_opts) LSM_HOOK(int, 0, sb_eat_lsm_opts, char *orig, void **mnt_opts) +LSM_HOOK(int, 0, sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts) LSM_HOOK(int, 0, sb_remount, struct super_block *sb, void *mnt_opts) LSM_HOOK(int, 0, sb_kern_mount, struct super_block *sb) LSM_HOOK(int, 0, sb_show_options, struct seq_file *m, struct super_block *sb) @@ -203,7 +204,10 @@ LSM_HOOK(int, 0, task_fix_setgid, struct cred *new, const struct cred * old, LSM_HOOK(int, 0, task_setpgid, struct task_struct *p, pid_t pgid) LSM_HOOK(int, 0, task_getpgid, struct task_struct *p) LSM_HOOK(int, 0, task_getsid, struct task_struct *p) -LSM_HOOK(void, LSM_RET_VOID, task_getsecid, struct task_struct *p, u32 *secid) +LSM_HOOK(void, LSM_RET_VOID, task_getsecid_subj, + struct task_struct *p, u32 *secid) +LSM_HOOK(void, LSM_RET_VOID, task_getsecid_obj, + struct task_struct *p, u32 *secid) LSM_HOOK(int, 0, task_setnice, struct task_struct *p, int nice) LSM_HOOK(int, 0, task_setioprio, struct task_struct *p, int ioprio) LSM_HOOK(int, 0, task_getioprio, struct task_struct *p) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index fb7f3193753d9486d77e1d5def769b3436cea7b1..ba2ccd950833fd377d82b7894aed64f6ddfeadef 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -142,6 +142,12 @@ * @orig the original mount data copied from userspace. * @copy copied data which will be passed to the security module. * Returns 0 if the copy was successful. + * @sb_mnt_opts_compat: + * Determine if the new mount options in @mnt_opts are allowed given + * the existing mounted filesystem at @sb. + * @sb superblock being compared + * @mnt_opts new mount options + * Return 0 if options are compatible. * @sb_remount: * Extracts security system specific mount options and verifies no changes * are being made to those options. @@ -707,9 +713,15 @@ * @p. * @p contains the task_struct for the process. * Return 0 if permission is granted. - * @task_getsecid: - * Retrieve the security identifier of the process @p. - * @p contains the task_struct for the process and place is into @secid. + * @task_getsecid_subj: + * Retrieve the subjective security identifier of the task_struct in @p + * and return it in @secid. Special care must be taken to ensure that @p + * is the either the "current" task, or the caller has exclusive access + * to @p. + * In case of failure, @secid will be set to zero. + * @task_getsecid_obj: + * 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. * * @task_setnice: diff --git a/include/linux/mfd/lpc_ich.h b/include/linux/mfd/lpc_ich.h index 6ddca2bbb3a80c0bb9ac0e33c775e0b1657ba75f..39967a5eca6d6f9754293c3afe2df8ea895fd3db 100644 --- a/include/linux/mfd/lpc_ich.h +++ b/include/linux/mfd/lpc_ich.h @@ -8,7 +8,7 @@ #ifndef LPC_ICH_H #define LPC_ICH_H -#include <linux/platform_data/intel-spi.h> +#include <linux/platform_data/x86/intel-spi.h> /* GPIO resources */ #define ICH_RES_GPIO 0 diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d26acc8b21cd796e2aa8cc278022cb3811509acf..944aa3aa30355fe33fba8133cc8e0a2ad1653c9b 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -117,6 +117,7 @@ struct mhi_link_info { * @MHI_EE_WFW: WLAN firmware mode * @MHI_EE_PTHRU: Passthrough * @MHI_EE_EDL: Embedded downloader + * @MHI_EE_FP: Flash Programmer Environment */ enum mhi_ee_type { MHI_EE_PBL, @@ -126,7 +127,8 @@ enum mhi_ee_type { MHI_EE_WFW, MHI_EE_PTHRU, MHI_EE_EDL, - MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, + MHI_EE_FP, + MHI_EE_MAX_SUPPORTED = MHI_EE_FP, MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ MHI_EE_NOT_SUPPORTED, MHI_EE_MAX, @@ -203,7 +205,7 @@ enum mhi_db_brst_mode { * @num: The number assigned to this channel * @num_elements: The number of elements that can be queued to this channel * @local_elements: The local ring length of the channel - * @event_ring: The event rung index that services this channel + * @event_ring: The event ring index that services this channel * @dir: Direction that data may flow on this channel * @type: Channel type * @ee_mask: Execution Environment mask for this channel @@ -296,7 +298,7 @@ struct mhi_controller_config { * @wake_db: MHI WAKE doorbell register address * @iova_start: IOMMU starting address for data (required) * @iova_stop: IOMMU stop address for data (required) - * @fw_image: Firmware image name for normal booting (required) + * @fw_image: Firmware image name for normal booting (optional) * @edl_image: Firmware image name for emergency download mode (optional) * @rddm_size: RAM dump size that host should allocate for debugging purpose * @sbl_size: SBL image size downloaded through BHIe (optional) @@ -352,7 +354,6 @@ struct mhi_controller_config { * @index: Index of the MHI controller instance * @bounce_buf: Use of bounce buffer * @fbc_download: MHI host needs to do complete image transfer (optional) - * @pre_init: MHI host needs to do pre-initialization before power up * @wake_set: Device wakeup set flag * @irq_flags: irq flags passed to request_irq (optional) * @@ -445,7 +446,6 @@ struct mhi_controller { int index; bool bounce_buf; bool fbc_download; - bool pre_init; bool wake_set; unsigned long irq_flags; }; @@ -712,13 +712,27 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev); void mhi_device_put(struct mhi_device *mhi_dev); /** - * mhi_prepare_for_transfer - Setup channel for data transfer + * mhi_prepare_for_transfer - Setup UL and DL channels for data transfer. + * Allocate and initialize the channel context and + * also issue the START channel command to both + * channels. Channels can be started only if both + * host and device execution environments match and + * channels are in a DISABLED state. * @mhi_dev: Device associated with the channels */ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev); /** - * mhi_unprepare_from_transfer - Unprepare the channels + * mhi_unprepare_from_transfer - Reset UL and DL channels for data transfer. + * Issue the RESET channel command and let the + * device clean-up the context so no incoming + * transfers are seen on the host. Free memory + * associated with the context on host. If device + * is unresponsive, only perform a host side + * clean-up. Channels can be reset only if both + * host and device execution environments match + * and channels are in an ENABLED, STOPPED or + * SUSPENDED state. * @mhi_dev: Device associated with the channels */ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev); diff --git a/include/linux/mm.h b/include/linux/mm.h index e9e222aab00d28794b34acf43058733a888a9943..13286dae062774369008738800d5177240539df6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -124,6 +124,16 @@ extern int mmap_rnd_compat_bits __read_mostly; #define lm_alias(x) __va(__pa_symbol(x)) #endif +/* + * With CONFIG_CFI_CLANG, the compiler replaces function addresses in + * instrumented C code with jump table addresses. Architectures that + * support CFI can define this macro to return the actual function address + * when needed. + */ +#ifndef function_nocfi +#define function_nocfi(x) (x) +#endif + /* * To prevent common memory management code establishing * a zero page mapping on a read fault. @@ -2905,18 +2915,20 @@ static inline void kernel_poison_pages(struct page *page, int numpages) { } static inline void kernel_unpoison_pages(struct page *page, int numpages) { } #endif -DECLARE_STATIC_KEY_FALSE(init_on_alloc); +DECLARE_STATIC_KEY_MAYBE(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, init_on_alloc); static inline bool want_init_on_alloc(gfp_t flags) { - if (static_branch_unlikely(&init_on_alloc)) + if (static_branch_maybe(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, + &init_on_alloc)) return true; return flags & __GFP_ZERO; } -DECLARE_STATIC_KEY_FALSE(init_on_free); +DECLARE_STATIC_KEY_MAYBE(CONFIG_INIT_ON_FREE_DEFAULT_ON, init_on_free); static inline bool want_init_on_free(void) { - return static_branch_unlikely(&init_on_free); + return static_branch_maybe(CONFIG_INIT_ON_FREE_DEFAULT_ON, + &init_on_free); } extern bool _debug_pagealloc_enabled_early; diff --git a/include/linux/module.h b/include/linux/module.h index 8aa124b48926cd3731ddaa10d8fbcd669d93adaf..e3b7bcd11f0144d49e5cf05439d1d894d7535517 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -26,6 +26,7 @@ #include <linux/tracepoint-defs.h> #include <linux/srcu.h> #include <linux/static_call_types.h> +#include <linux/cfi.h> #include <linux/percpu.h> #include <asm/module.h> @@ -128,13 +129,17 @@ extern void cleanup_module(void); #define module_init(initfn) \ static inline initcall_t __maybe_unused __inittest(void) \ { return initfn; } \ - int init_module(void) __copy(initfn) __attribute__((alias(#initfn))); + int init_module(void) __copy(initfn) \ + __attribute__((alias(#initfn))); \ + __CFI_ADDRESSABLE(init_module, __initdata); /* This is only required if you want to be unloadable. */ #define module_exit(exitfn) \ static inline exitcall_t __maybe_unused __exittest(void) \ { return exitfn; } \ - void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn))); + void cleanup_module(void) __copy(exitfn) \ + __attribute__((alias(#exitfn))); \ + __CFI_ADDRESSABLE(cleanup_module, __exitdata); #endif @@ -377,6 +382,10 @@ struct module { const s32 *crcs; unsigned int num_syms; +#ifdef CONFIG_CFI_CLANG + cfi_check_fn cfi_check; +#endif + /* Kernel parameters. */ #ifdef CONFIG_SYSFS struct mutex param_lock; diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index 3c668cb1e3447882a56c440c9905dc3f93ce409f..15cc9b95e32b526f7f914e9ed9016bca5d96574d 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h @@ -77,5 +77,16 @@ extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev); +/** + * module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver + * @__mtd_blktrans: mtd_blktrans_ops struct + * + * Helper macro for mtd blktrans drivers which do not do anything special in + * module init/exit. This eliminates a lot of boilerplate. Each module may only + * use this macro once, and calling it replaces module_init() and module_exit() + */ +#define module_mtd_blktrans(__mtd_blktrans) \ + module_driver(__mtd_blktrans, register_mtd_blktrans, \ + deregister_mtd_blktrans) #endif /* __MTD_TRANS_H__ */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 157357ec14419c56a2accbabf2cdf20f7b338fe4..a89955f3cbc88187b8812cd46ba864789f3a582e 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -229,6 +229,7 @@ struct mtd_part { */ struct mtd_master { struct mutex partitions_lock; + struct mutex chrdev_lock; unsigned int suspended : 1; }; @@ -333,9 +334,12 @@ struct mtd_info { int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, - size_t len, size_t *retlen, u_char *buf); + size_t len, size_t *retlen, + const u_char *buf); int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); + int (*_erase_user_prot_reg) (struct mtd_info *mtd, loff_t from, + size_t len); int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); void (*_sync) (struct mtd_info *mtd); @@ -515,8 +519,9 @@ int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, u_char *buf); + size_t *retlen, const u_char *buf); int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len); +int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len); int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); diff --git a/include/linux/mtd/nand-ecc-sw-bch.h b/include/linux/mtd/nand-ecc-sw-bch.h index 22c92073b3dda027d557f9f72328ab19b0920d2c..9da9969505a817cdbb4f340ae5684ade9ad584e6 100644 --- a/include/linux/mtd/nand-ecc-sw-bch.h +++ b/include/linux/mtd/nand-ecc-sw-bch.h @@ -16,7 +16,6 @@ * @req_ctx: Save request context and tweak the original request to fit the * engine needs * @code_size: Number of bytes needed to store a code (one code per step) - * @nsteps: Number of steps * @calc_buf: Buffer to use when calculating ECC bytes * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip * @bch: BCH control structure @@ -26,7 +25,6 @@ struct nand_ecc_sw_bch_conf { struct nand_ecc_req_tweak_ctx req_ctx; unsigned int code_size; - unsigned int nsteps; u8 *calc_buf; u8 *code_buf; struct bch_control *bch; diff --git a/include/linux/mtd/nand-ecc-sw-hamming.h b/include/linux/mtd/nand-ecc-sw-hamming.h index 9f9073d86ff372342f86dcac0a9bbdb6899e5529..c6c71894c575c1114311e0944bcc717453d61088 100644 --- a/include/linux/mtd/nand-ecc-sw-hamming.h +++ b/include/linux/mtd/nand-ecc-sw-hamming.h @@ -17,7 +17,6 @@ * @req_ctx: Save request context and tweak the original request to fit the * engine needs * @code_size: Number of bytes needed to store a code (one code per step) - * @nsteps: Number of steps * @calc_buf: Buffer to use when calculating ECC bytes * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip * @sm_order: Smart Media special ordering @@ -25,7 +24,6 @@ struct nand_ecc_sw_hamming_conf { struct nand_ecc_req_tweak_ctx req_ctx; unsigned int code_size; - unsigned int nsteps; u8 *calc_buf; u8 *code_buf; unsigned int sm_order; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 414f8a4d28538c04a197977d9d7bb5b9351534df..32fc7edf65b33409e303677823b0529f616f0bf6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -231,12 +231,14 @@ struct nand_ops { /** * struct nand_ecc_context - Context for the ECC engine * @conf: basic ECC engine parameters + * @nsteps: number of ECC steps * @total: total number of bytes used for storing ECC codes, this is used by * generic OOB layouts * @priv: ECC engine driver private data */ struct nand_ecc_context { struct nand_ecc_props conf; + unsigned int nsteps; unsigned int total; void *priv; }; @@ -585,6 +587,26 @@ nanddev_get_ecc_conf(struct nand_device *nand) return &nand->ecc.ctx.conf; } +/** + * nanddev_get_ecc_nsteps() - Extract the number of ECC steps + * @nand: NAND device + */ +static inline unsigned int +nanddev_get_ecc_nsteps(struct nand_device *nand) +{ + return nand->ecc.ctx.nsteps; +} + +/** + * nanddev_get_ecc_bytes_per_step() - Extract the number of ECC bytes per step + * @nand: NAND device + */ +static inline unsigned int +nanddev_get_ecc_bytes_per_step(struct nand_device *nand) +{ + return nand->ecc.ctx.total / nand->ecc.ctx.nsteps; +} + /** * nanddev_get_ecc_requirements() - Extract the ECC requirements from a NAND * device diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 6b3240e44310120881700cd51d8c1960e72947c4..29df2f43dcb5a64523e62dfce95a44538859770f 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -18,7 +18,6 @@ #include <linux/mtd/flashchip.h> #include <linux/mtd/bbm.h> #include <linux/mtd/jedec.h> -#include <linux/mtd/nand.h> #include <linux/mtd/onfi.h> #include <linux/mutex.h> #include <linux/of.h> @@ -1036,6 +1035,16 @@ struct nand_manufacturer { void *priv; }; +/** + * struct nand_secure_region - NAND secure region structure + * @offset: Offset of the start of the secure region + * @size: Size of the secure region + */ +struct nand_secure_region { + u64 offset; + u64 size; +}; + /** * struct nand_chip - NAND Private Flash Chip Data * @base: Inherit from the generic NAND device @@ -1086,6 +1095,8 @@ struct nand_manufacturer { * NAND Controller drivers should not modify this value, but they're * allowed to read it. * @read_retries: The number of read retry modes supported + * @secure_regions: Structure containing the secure regions info + * @nr_secure_regions: Number of secure regions * @controller: The hardware controller structure which is shared among multiple * independent devices * @ecc: The ECC controller structure @@ -1135,6 +1146,8 @@ struct nand_chip { unsigned int suspended : 1; int cur_cs; int read_retries; + struct nand_secure_region *secure_regions; + u8 nr_secure_regions; /* Externals */ struct nand_controller *controller; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index a0d5728554441dce699cda7ad501d6df7c19ab7c..98ed91b529ea441df8dba7b2cead0576e870b741 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -107,6 +107,11 @@ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ #define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */ +/* Used for GigaDevices and Winbond flashes. */ +#define SPINOR_OP_ESECR 0x44 /* Erase Security registers */ +#define SPINOR_OP_PSECR 0x42 /* Program Security registers */ +#define SPINOR_OP_RSECR 0x48 /* Read Security registers */ + /* Status Register bits. */ #define SR_WIP BIT(0) /* Write in progress */ #define SR_WEL BIT(1) /* Write enable latch */ @@ -138,6 +143,9 @@ /* Status Register 2 bits. */ #define SR2_QUAD_EN_BIT1 BIT(1) +#define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */ +#define SR2_LB2 BIT(4) /* Security Register Lock Bit 2 */ +#define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */ #define SR2_QUAD_EN_BIT7 BIT(7) /* Supported SPI protocols */ diff --git a/include/linux/netfs.h b/include/linux/netfs.h new file mode 100644 index 0000000000000000000000000000000000000000..9062adfa2fb9dc940abe42bbd9f3c15825d157b8 --- /dev/null +++ b/include/linux/netfs.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Network filesystem support services. + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * See: + * + * Documentation/filesystems/netfs_library.rst + * + * for a description of the network filesystem interface declared here. + */ + +#ifndef _LINUX_NETFS_H +#define _LINUX_NETFS_H + +#include <linux/workqueue.h> +#include <linux/fs.h> +#include <linux/pagemap.h> + +/* + * Overload PG_private_2 to give us PG_fscache - this is used to indicate that + * a page is currently backed by a local disk cache + */ +#define PageFsCache(page) PagePrivate2((page)) +#define SetPageFsCache(page) SetPagePrivate2((page)) +#define ClearPageFsCache(page) ClearPagePrivate2((page)) +#define TestSetPageFsCache(page) TestSetPagePrivate2((page)) +#define TestClearPageFsCache(page) TestClearPagePrivate2((page)) + +/** + * set_page_fscache - Set PG_fscache on a page and take a ref + * @page: The page. + * + * Set the PG_fscache (PG_private_2) flag on a page and take the reference + * needed for the VM to handle its lifetime correctly. This sets the flag and + * takes the reference unconditionally, so care must be taken not to set the + * flag again if it's already set. + */ +static inline void set_page_fscache(struct page *page) +{ + set_page_private_2(page); +} + +/** + * end_page_fscache - Clear PG_fscache and release any waiters + * @page: The page + * + * Clear the PG_fscache (PG_private_2) bit on a page and wake up any sleepers + * waiting for this. The page ref held for PG_private_2 being set is released. + * + * This is, for example, used when a netfs page is being written to a local + * disk cache, thereby allowing writes to the cache for the same page to be + * serialised. + */ +static inline void end_page_fscache(struct page *page) +{ + end_page_private_2(page); +} + +/** + * wait_on_page_fscache - Wait for PG_fscache to be cleared on a page + * @page: The page to wait on + * + * Wait for PG_fscache (aka PG_private_2) to be cleared on a page. + */ +static inline void wait_on_page_fscache(struct page *page) +{ + wait_on_page_private_2(page); +} + +/** + * wait_on_page_fscache_killable - Wait for PG_fscache to be cleared on a page + * @page: The page to wait on + * + * Wait for PG_fscache (aka PG_private_2) to be cleared on a page or until a + * fatal signal is received by the calling task. + * + * Return: + * - 0 if successful. + * - -EINTR if a fatal signal was encountered. + */ +static inline int wait_on_page_fscache_killable(struct page *page) +{ + return wait_on_page_private_2_killable(page); +} + +enum netfs_read_source { + NETFS_FILL_WITH_ZEROES, + NETFS_DOWNLOAD_FROM_SERVER, + NETFS_READ_FROM_CACHE, + NETFS_INVALID_READ, +} __mode(byte); + +typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error, + bool was_async); + +/* + * Resources required to do operations on a cache. + */ +struct netfs_cache_resources { + const struct netfs_cache_ops *ops; + void *cache_priv; + void *cache_priv2; +}; + +/* + * Descriptor for a single component subrequest. + */ +struct netfs_read_subrequest { + struct netfs_read_request *rreq; /* Supervising read request */ + struct list_head rreq_link; /* Link in rreq->subrequests */ + loff_t start; /* Where to start the I/O */ + size_t len; /* Size of the I/O */ + size_t transferred; /* Amount of data transferred */ + refcount_t usage; + short error; /* 0 or error that occurred */ + unsigned short debug_index; /* Index in list (for debugging output) */ + enum netfs_read_source source; /* Where to read from */ + unsigned long flags; +#define NETFS_SREQ_WRITE_TO_CACHE 0 /* Set if should write to cache */ +#define NETFS_SREQ_CLEAR_TAIL 1 /* Set if the rest of the read should be cleared */ +#define NETFS_SREQ_SHORT_READ 2 /* Set if there was a short read from the cache */ +#define NETFS_SREQ_SEEK_DATA_READ 3 /* Set if ->read() should SEEK_DATA first */ +#define NETFS_SREQ_NO_PROGRESS 4 /* Set if we didn't manage to read any data */ +}; + +/* + * Descriptor for a read helper request. This is used to make multiple I/O + * requests on a variety of sources and then stitch the result together. + */ +struct netfs_read_request { + struct work_struct work; + struct inode *inode; /* The file being accessed */ + struct address_space *mapping; /* The mapping being accessed */ + struct netfs_cache_resources cache_resources; + struct list_head subrequests; /* Requests to fetch I/O from disk or net */ + void *netfs_priv; /* Private data for the netfs */ + unsigned int debug_id; + unsigned int cookie_debug_id; + atomic_t nr_rd_ops; /* Number of read ops in progress */ + atomic_t nr_wr_ops; /* Number of write ops in progress */ + size_t submitted; /* Amount submitted for I/O so far */ + size_t len; /* Length of the request */ + short error; /* 0 or error that occurred */ + loff_t i_size; /* Size of the file */ + loff_t start; /* Start position */ + pgoff_t no_unlock_page; /* Don't unlock this page after read */ + refcount_t usage; + unsigned long flags; +#define NETFS_RREQ_INCOMPLETE_IO 0 /* Some ioreqs terminated short or with error */ +#define NETFS_RREQ_WRITE_TO_CACHE 1 /* Need to write to the cache */ +#define NETFS_RREQ_NO_UNLOCK_PAGE 2 /* Don't unlock no_unlock_page on completion */ +#define NETFS_RREQ_DONT_UNLOCK_PAGES 3 /* Don't unlock the pages on completion */ +#define NETFS_RREQ_FAILED 4 /* The request failed */ +#define NETFS_RREQ_IN_PROGRESS 5 /* Unlocked when the request completes */ + const struct netfs_read_request_ops *netfs_ops; +}; + +/* + * Operations the network filesystem can/must provide to the helpers. + */ +struct netfs_read_request_ops { + bool (*is_cache_enabled)(struct inode *inode); + void (*init_rreq)(struct netfs_read_request *rreq, struct file *file); + int (*begin_cache_operation)(struct netfs_read_request *rreq); + void (*expand_readahead)(struct netfs_read_request *rreq); + bool (*clamp_length)(struct netfs_read_subrequest *subreq); + void (*issue_op)(struct netfs_read_subrequest *subreq); + bool (*is_still_valid)(struct netfs_read_request *rreq); + int (*check_write_begin)(struct file *file, loff_t pos, unsigned len, + struct page *page, void **_fsdata); + void (*done)(struct netfs_read_request *rreq); + void (*cleanup)(struct address_space *mapping, void *netfs_priv); +}; + +/* + * Table of operations for access to a cache. This is obtained by + * rreq->ops->begin_cache_operation(). + */ +struct netfs_cache_ops { + /* End an operation */ + void (*end_operation)(struct netfs_cache_resources *cres); + + /* Read data from the cache */ + int (*read)(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + bool seek_data, + netfs_io_terminated_t term_func, + void *term_func_priv); + + /* Write data to the cache */ + int (*write)(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + netfs_io_terminated_t term_func, + void *term_func_priv); + + /* Expand readahead request */ + void (*expand_readahead)(struct netfs_cache_resources *cres, + loff_t *_start, size_t *_len, loff_t i_size); + + /* Prepare a read operation, shortening it to a cached/uncached + * boundary as appropriate. + */ + enum netfs_read_source (*prepare_read)(struct netfs_read_subrequest *subreq, + loff_t i_size); + + /* Prepare a write operation, working out what part of the write we can + * actually do. + */ + int (*prepare_write)(struct netfs_cache_resources *cres, + loff_t *_start, size_t *_len, loff_t i_size); +}; + +struct readahead_control; +extern void netfs_readahead(struct readahead_control *, + const struct netfs_read_request_ops *, + void *); +extern int netfs_readpage(struct file *, + struct page *, + const struct netfs_read_request_ops *, + void *); +extern int netfs_write_begin(struct file *, struct address_space *, + loff_t, unsigned int, unsigned int, struct page **, + void **, + const struct netfs_read_request_ops *, + void *); + +extern void netfs_subreq_terminated(struct netfs_read_subrequest *, ssize_t, bool); +extern void netfs_stats_show(struct seq_file *); + +#endif /* _LINUX_NETFS_H */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 6f76b32a0238fd06cf2fbbe209a94e0c41bba092..a28d71b45b5f0a5f32e8b213422803d17e771605 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -256,6 +256,7 @@ struct nfs_server { /* User namespace info */ const struct cred *cred; + bool has_sec_mnt_opts; }; /* Server capabilities */ diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h index 0ba99c5136491e6cfb34841566d5d623b513a1d8..8e76a79cdc6ae145fcffb9899f4ed52de6899267 100644 --- a/include/linux/nfsacl.h +++ b/include/linux/nfsacl.h @@ -41,5 +41,8 @@ nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, extern bool nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt, struct posix_acl **pacl); +extern bool +nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode, + struct posix_acl *acl, int encode_entries, int typeflag); #endif /* __LINUX_NFSACL_H */ diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 052293f4cbdb0a64d95884aee645778e9a63c511..923dada24eb4163b2e5fb7f9be88ae78db2c34ca 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -65,6 +65,10 @@ int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val); int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val); int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val); +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, + u32 *val); +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, + u64 *val); /* direct nvmem device read/write interface */ struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 4462ed2c18cddb355ed5579059cadc6ec436b0d2..461b7aa587ba5321332f2e572fe1b623aa504326 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -19,8 +19,14 @@ enum OID { OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */ OID_id_dsa, /* 1.2.840.10040.4.1 */ - OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */ OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */ + OID_id_prime192v1, /* 1.2.840.10045.3.1.1 */ + OID_id_prime256v1, /* 1.2.840.10045.3.1.7 */ + OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */ + OID_id_ecdsa_with_sha224, /* 1.2.840.10045.4.3.1 */ + OID_id_ecdsa_with_sha256, /* 1.2.840.10045.4.3.2 */ + OID_id_ecdsa_with_sha384, /* 1.2.840.10045.4.3.3 */ + OID_id_ecdsa_with_sha512, /* 1.2.840.10045.4.3.4 */ /* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */ OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */ @@ -58,6 +64,7 @@ enum OID { OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ OID_sha1, /* 1.3.14.3.2.26 */ + OID_id_ansip384r1, /* 1.3.132.0.34 */ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ OID_sha384, /* 2.16.840.1.101.3.4.2.2 */ OID_sha512, /* 2.16.840.1.101.3.4.2.3 */ @@ -113,10 +120,16 @@ enum OID { OID_SM2_with_SM3, /* 1.2.156.10197.1.501 */ OID_sm3WithRSAEncryption, /* 1.2.156.10197.1.504 */ + /* TCG defined OIDS for TPM based keys */ + OID_TPMLoadableKey, /* 2.23.133.10.1.3 */ + OID_TPMImportableKey, /* 2.23.133.10.1.4 */ + OID_TPMSealedData, /* 2.23.133.10.1.5 */ + OID__NR }; extern enum OID look_up_OID(const void *data, size_t datasize); +extern int parse_OID(const void *data, size_t datasize, enum OID *oid); extern int sprint_oid(const void *, size_t, char *, size_t); extern int sprint_OID(enum OID, char *, size_t); diff --git a/include/linux/overflow.h b/include/linux/overflow.h index ef74051d5cfed5769d1dcb4786ce6392bf654588..0f12345c21fb58430ea93884c4ad5f4688ad7d18 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -235,7 +235,7 @@ static inline bool __must_check __must_check_overflow(bool overflow) * - 'a << s' sets the sign bit, if any, in '*d'. * * '*d' will hold the results of the attempted shift, but is not - * considered "safe for use" if false is returned. + * considered "safe for use" if true is returned. */ #define check_shl_overflow(a, s, d) __must_check_overflow(({ \ typeof(a) _a = a; \ diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 3f750f55e6f6d7a7b37095ba943d718201f29de4..de6ffaa0b6b91bec73a07015dfc1e1a1949f15c8 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -686,6 +686,26 @@ void wait_for_stable_page(struct page *page); void page_endio(struct page *page, bool is_write, int err); +/** + * set_page_private_2 - Set PG_private_2 on a page and take a ref + * @page: The page. + * + * Set the PG_private_2 flag on a page and take the reference needed for the VM + * to handle its lifetime correctly. This sets the flag and takes the + * reference unconditionally, so care must be taken not to set the flag again + * if it's already set. + */ +static inline void set_page_private_2(struct page *page) +{ + page = compound_head(page); + get_page(page); + SetPagePrivate2(page); +} + +void end_page_private_2(struct page *page); +void wait_on_page_private_2(struct page *page); +int wait_on_page_private_2_killable(struct page *page); + /* * Add an arbitrary waiter to a page's wait queue */ @@ -790,20 +810,23 @@ static inline int add_to_page_cache(struct page *page, * @file: The file, used primarily by network filesystems for authentication. * May be NULL if invoked internally by the filesystem. * @mapping: Readahead this filesystem object. + * @ra: File readahead state. May be NULL. */ struct readahead_control { struct file *file; struct address_space *mapping; + struct file_ra_state *ra; /* private: use the readahead_* accessors instead */ pgoff_t _index; unsigned int _nr_pages; unsigned int _batch_count; }; -#define DEFINE_READAHEAD(rac, f, m, i) \ - struct readahead_control rac = { \ +#define DEFINE_READAHEAD(ractl, f, r, m, i) \ + struct readahead_control ractl = { \ .file = f, \ .mapping = m, \ + .ra = r, \ ._index = i, \ } @@ -811,10 +834,11 @@ struct readahead_control { void page_cache_ra_unbounded(struct readahead_control *, unsigned long nr_to_read, unsigned long lookahead_count); -void page_cache_sync_ra(struct readahead_control *, struct file_ra_state *, +void page_cache_sync_ra(struct readahead_control *, unsigned long req_count); +void page_cache_async_ra(struct readahead_control *, struct page *, unsigned long req_count); -void page_cache_async_ra(struct readahead_control *, struct file_ra_state *, - struct page *, unsigned long req_count); +void readahead_expand(struct readahead_control *ractl, + loff_t new_start, size_t new_len); /** * page_cache_sync_readahead - generic file readahead @@ -834,8 +858,8 @@ void page_cache_sync_readahead(struct address_space *mapping, struct file_ra_state *ra, struct file *file, pgoff_t index, unsigned long req_count) { - DEFINE_READAHEAD(ractl, file, mapping, index); - page_cache_sync_ra(&ractl, ra, req_count); + DEFINE_READAHEAD(ractl, file, ra, mapping, index); + page_cache_sync_ra(&ractl, req_count); } /** @@ -857,8 +881,8 @@ void page_cache_async_readahead(struct address_space *mapping, struct file_ra_state *ra, struct file *file, struct page *page, pgoff_t index, unsigned long req_count) { - DEFINE_READAHEAD(ractl, file, mapping, index); - page_cache_async_ra(&ractl, ra, page, req_count); + DEFINE_READAHEAD(ractl, file, ra, mapping, index); + page_cache_async_ra(&ractl, page, req_count); } /** @@ -979,6 +1003,15 @@ static inline unsigned int readahead_count(struct readahead_control *rac) return rac->_nr_pages; } +/** + * readahead_batch_length - The number of bytes in the current batch. + * @rac: The readahead request. + */ +static inline loff_t readahead_batch_length(struct readahead_control *rac) +{ + return rac->_batch_count * PAGE_SIZE; +} + static inline unsigned long dir_pages(struct inode *inode) { return (unsigned long)(inode->i_size + PAGE_SIZE - 1) >> diff --git a/include/linux/parport.h b/include/linux/parport.h index f981f794c8501e63e6686e306154b8a58f2b8ece..1c16ffb8b908db96b961cdbee3ac6273fd7a0853 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -332,9 +332,19 @@ int __must_check __parport_register_driver(struct parport_driver *, __parport_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) /* Unregister a high-level driver. */ -extern void parport_unregister_driver (struct parport_driver *); void parport_unregister_driver(struct parport_driver *); +/** + * module_parport_driver() - Helper macro for registering a modular parport driver + * @__parport_driver: struct parport_driver to be used + * + * Helper macro for parport drivers which do not do anything special in module + * init and exit. This eliminates a lot of boilerplate. Each module may only + * use this macro once, and calling it replaces module_init() and module_exit(). + */ +#define module_parport_driver(__parport_driver) \ + module_driver(__parport_driver, parport_register_driver, parport_unregister_driver) + /* If parport_register_driver doesn't fit your needs, perhaps * parport_find_xxx does. */ extern struct parport *parport_find_number (int); diff --git a/include/linux/pci.h b/include/linux/pci.h index 86c799c97b7796665524666dc4a73f12ab81cbb3..39684b72db915a1deb00439dce8a82a0a54af064 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1944,8 +1944,8 @@ enum pci_fixup_pass { #ifdef CONFIG_LTO_CLANG #define __DECLARE_PCI_FIXUP_SECTION(sec, name, vendor, device, class, \ class_shift, hook, stub) \ - void stub(struct pci_dev *dev); \ - void stub(struct pci_dev *dev) \ + void __cficanonical stub(struct pci_dev *dev); \ + void __cficanonical stub(struct pci_dev *dev) \ { \ hook(dev); \ } \ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c1af48d4094c4304f966214b2cc64b395e982046..47f443297bd43228555c01263806e4b72651811a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1688,37 +1688,8 @@ #define PCI_VENDOR_ID_MICROSEMI 0x11f8 #define PCI_VENDOR_ID_RP 0x11fe -#define PCI_DEVICE_ID_RP32INTF 0x0001 -#define PCI_DEVICE_ID_RP8INTF 0x0002 -#define PCI_DEVICE_ID_RP16INTF 0x0003 -#define PCI_DEVICE_ID_RP4QUAD 0x0004 -#define PCI_DEVICE_ID_RP8OCTA 0x0005 -#define PCI_DEVICE_ID_RP8J 0x0006 -#define PCI_DEVICE_ID_RP4J 0x0007 -#define PCI_DEVICE_ID_RP8SNI 0x0008 -#define PCI_DEVICE_ID_RP16SNI 0x0009 -#define PCI_DEVICE_ID_RPP4 0x000A -#define PCI_DEVICE_ID_RPP8 0x000B -#define PCI_DEVICE_ID_RP4M 0x000D -#define PCI_DEVICE_ID_RP2_232 0x000E -#define PCI_DEVICE_ID_RP2_422 0x000F -#define PCI_DEVICE_ID_URP32INTF 0x0801 -#define PCI_DEVICE_ID_URP8INTF 0x0802 -#define PCI_DEVICE_ID_URP16INTF 0x0803 -#define PCI_DEVICE_ID_URP8OCTA 0x0805 -#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C -#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D -#define PCI_DEVICE_ID_CRP16INTF 0x0903 #define PCI_VENDOR_ID_CYCLADES 0x120e -#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100 -#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101 -#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102 -#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103 -#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104 -#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105 -#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 -#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 #define PCI_DEVICE_ID_PC300_RX_2 0x0300 #define PCI_DEVICE_ID_PC300_RX_1 0x0301 #define PCI_DEVICE_ID_PC300_TE_2 0x0310 @@ -2065,8 +2036,6 @@ #define PCI_DEVICE_ID_EXAR_XR17V358 0x0358 #define PCI_VENDOR_ID_MICROGATE 0x13c0 -#define PCI_DEVICE_ID_MICROGATE_USC 0x0010 -#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 #define PCI_VENDOR_ID_3WARE 0x13C1 #define PCI_DEVICE_ID_3WARE_1000 0x1000 diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index e435bdb0bab355eabc94def12674bc51a7076bda..0ed434d02196bbec2395d6b227e43a1922016804 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -44,6 +44,12 @@ enum phy_mode { PHY_MODE_DP }; +enum phy_media { + PHY_MEDIA_DEFAULT, + PHY_MEDIA_SR, + PHY_MEDIA_DAC, +}; + /** * union phy_configure_opts - Opaque generic phy configuration * @@ -64,6 +70,8 @@ union phy_configure_opts { * @power_on: powering on the phy * @power_off: powering off the phy * @set_mode: set the mode of the phy + * @set_media: set the media type of the phy (optional) + * @set_speed: set the speed of the phy (optional) * @reset: resetting the phy * @calibrate: calibrate the phy * @release: ops to be performed while the consumer relinquishes the PHY @@ -75,6 +83,8 @@ struct phy_ops { int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); int (*set_mode)(struct phy *phy, enum phy_mode mode, int submode); + int (*set_media)(struct phy *phy, enum phy_media media); + int (*set_speed)(struct phy *phy, int speed); /** * @configure: @@ -215,6 +225,8 @@ int phy_power_off(struct phy *phy); int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode); #define phy_set_mode(phy, mode) \ phy_set_mode_ext(phy, mode, 0) +int phy_set_media(struct phy *phy, enum phy_media media); +int phy_set_speed(struct phy *phy, int speed); int phy_configure(struct phy *phy, union phy_configure_opts *opts); int phy_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts); @@ -344,6 +356,20 @@ static inline int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, #define phy_set_mode(phy, mode) \ phy_set_mode_ext(phy, mode, 0) +static inline int phy_set_media(struct phy *phy, enum phy_media media) +{ + if (!phy) + return 0; + return -ENODEV; +} + +static inline int phy_set_speed(struct phy *phy, int speed) +{ + if (!phy) + return 0; + return -ENODEV; +} + static inline enum phy_mode phy_get_mode(struct phy *phy) { return PHY_MODE_INVALID; diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 5ff8597ceabd83b81647cd58dba2161b4f30f0be..6035d9a98fb891ed1243cbcb5c1a679a4a833aaa 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -3467,6 +3467,7 @@ struct ec_response_get_next_event_v1 { #define EC_MKBP_LID_OPEN 0 #define EC_MKBP_TABLET_MODE 1 #define EC_MKBP_BASE_ATTACHED 2 +#define EC_MKBP_FRONT_PROXIMITY 3 /* Run keyboard factory test scanning */ #define EC_CMD_KEYBOARD_FACTORY_TEST 0x0068 diff --git a/include/linux/platform_data/invensense_mpu6050.h b/include/linux/platform_data/invensense_mpu6050.h index 93974f4cfba1007e601eb450d618a5de72c514fa..f05b37521f678e400d41ed474c09c1bf21c7b16e 100644 --- a/include/linux/platform_data/invensense_mpu6050.h +++ b/include/linux/platform_data/invensense_mpu6050.h @@ -12,7 +12,7 @@ * mounting matrix retrieved from device-tree) * * Contains platform specific information on how to configure the MPU6050 to - * work on this platform. The orientation matricies are 3x3 rotation matricies + * work on this platform. The orientation matrices are 3x3 rotation matrices * that are applied to the data to rotate from the mounting orientation to the * platform orientation. The values must be one of 0, 1, or -1 and each row and * column should have exactly 1 non-zero value. diff --git a/include/linux/platform_data/usb-mx2.h b/include/linux/platform_data/usb-mx2.h deleted file mode 100644 index 97a670f3d8fb7cf361007cf0ab52f047e2b42814..0000000000000000000000000000000000000000 --- a/include/linux/platform_data/usb-mx2.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2009 Martin Fuzzey <mfuzzey@gmail.com> - */ - -#ifndef __ASM_ARCH_MX21_USBH -#define __ASM_ARCH_MX21_USBH - -enum mx21_usbh_xcvr { - /* Values below as used by hardware (HWMODE register) */ - MX21_USBXCVR_TXDIF_RXDIF = 0, - MX21_USBXCVR_TXDIF_RXSE = 1, - MX21_USBXCVR_TXSE_RXDIF = 2, - MX21_USBXCVR_TXSE_RXSE = 3, -}; - -struct mx21_usbh_platform_data { - enum mx21_usbh_xcvr host_xcvr; /* tranceiver mode host 1,2 ports */ - enum mx21_usbh_xcvr otg_xcvr; /* tranceiver mode otg (as host) port */ - u16 enable_host1:1, - enable_host2:1, - enable_otg_host:1, /* enable "OTG" port (as host) */ - host1_xcverless:1, /* traceiverless host1 port */ - host1_txenoe:1, /* output enable host1 transmit enable */ - otg_ext_xcvr:1, /* external tranceiver for OTG port */ - unused:10; -}; - -#endif /* __ASM_ARCH_MX21_USBH */ diff --git a/include/linux/platform_data/intel-spi.h b/include/linux/platform_data/x86/intel-spi.h similarity index 100% rename from include/linux/platform_data/intel-spi.h rename to include/linux/platform_data/x86/intel-spi.h diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 3f23f6e430bfa514d7866a941413ea0d274587f7..cd81e060863c95bbb048468db2020aeb3a312aea 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -359,4 +359,7 @@ static inline int is_sh_early_platform_device(struct platform_device *pdev) } #endif /* CONFIG_SUPERH */ +/* For now only SuperH uses it */ +void early_platform_cleanup(void); + #endif /* _PLATFORM_DEVICE_H_ */ diff --git a/include/linux/pm.h b/include/linux/pm.h index 482313a8ccfc1071d0abf1260beb9f42983f5fe1..c9657408fee1aec7f2a7b215c3699e15845ff05b 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -39,7 +39,6 @@ static inline void pm_vt_switch_unregister(struct device *dev) * Device power management */ -struct device; #ifdef CONFIG_PM extern const char power_group_name[]; /* = "power" */ diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index c0371efa4a0f21f4b6a8623a4f6ef998b58d08fd..84150a22fd7c40bcc19f89d6dfd1ea6083051953 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -144,18 +144,21 @@ int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count); void dev_pm_opp_put_supported_hw(struct opp_table *opp_table); +int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count); struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name); void dev_pm_opp_put_prop_name(struct opp_table *opp_table); struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); void dev_pm_opp_put_regulators(struct opp_table *opp_table); +int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name); void dev_pm_opp_put_clkname(struct opp_table *opp_table); +int devm_pm_opp_set_clkname(struct device *dev, const char *name); struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); -struct opp_table *devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); +int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); void dev_pm_opp_detach_genpd(struct opp_table *opp_table); -struct opp_table *devm_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); +int devm_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp); int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); @@ -319,6 +322,13 @@ static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {} +static inline int devm_pm_opp_set_supported_hw(struct device *dev, + const u32 *versions, + unsigned int count) +{ + return -EOPNOTSUPP; +} + static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)) { @@ -327,11 +337,10 @@ static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {} -static inline struct opp_table * -devm_pm_opp_register_set_opp_helper(struct device *dev, +static inline int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)) { - return ERR_PTR(-EOPNOTSUPP); + return -EOPNOTSUPP; } static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) @@ -348,6 +357,13 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, co static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {} +static inline int devm_pm_opp_set_regulators(struct device *dev, + const char * const names[], + unsigned int count) +{ + return -EOPNOTSUPP; +} + static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name) { return ERR_PTR(-EOPNOTSUPP); @@ -355,6 +371,11 @@ static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {} +static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name) +{ + return -EOPNOTSUPP; +} + static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs) { return ERR_PTR(-EOPNOTSUPP); @@ -362,10 +383,11 @@ static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, cons static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {} -static inline struct opp_table *devm_pm_opp_attach_genpd(struct device *dev, - const char **names, struct device ***virt_devs) +static inline int devm_pm_opp_attach_genpd(struct device *dev, + const char **names, + struct device ***virt_devs) { - return ERR_PTR(-EOPNOTSUPP); + return -EOPNOTSUPP; } static inline struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, @@ -419,6 +441,7 @@ int dev_pm_opp_of_add_table(struct device *dev); int dev_pm_opp_of_add_table_indexed(struct device *dev, int index); int dev_pm_opp_of_add_table_noclk(struct device *dev, int index); void dev_pm_opp_of_remove_table(struct device *dev); +int devm_pm_opp_of_add_table(struct device *dev); int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask); void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask); int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); @@ -451,6 +474,11 @@ static inline void dev_pm_opp_of_remove_table(struct device *dev) { } +static inline int devm_pm_opp_of_add_table(struct device *dev) +{ + return -EOPNOTSUPP; +} + static inline int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) { return -EOPNOTSUPP; diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index b492ae00cc9088e61f61042a0c1b0fa576c6c18b..6c08a085367bf790fe0eecf500c6b3b5f7ca8c9e 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -265,7 +265,7 @@ static inline void pm_runtime_no_callbacks(struct device *dev) {} static inline void pm_runtime_irq_safe(struct device *dev) {} static inline bool pm_runtime_is_irq_safe(struct device *dev) { return false; } -static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; } +static inline bool pm_runtime_has_no_callbacks(struct device *dev) { return false; } static inline void pm_runtime_mark_last_busy(struct device *dev) {} static inline void __pm_runtime_use_autosuspend(struct device *dev, bool use) {} diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 05b05b21a554a838c5cb9c5837bcc7ee58b83ecb..41dbb4176f8e58f584f640c1bf056e29801e4a90 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -442,9 +442,16 @@ static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } extern int power_supply_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val); +#if IS_ENABLED(CONFIG_POWER_SUPPLY) extern int power_supply_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val); +#else +static inline int power_supply_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ return 0; } +#endif extern int power_supply_property_is_writeable(struct power_supply *psy, enum power_supply_property psp); extern void power_supply_external_power_changed(struct power_supply *psy); diff --git a/include/linux/pps-gpio.h b/include/linux/pps-gpio.h deleted file mode 100644 index 7bf49908be061fb1baccda2b32313434fe783197..0000000000000000000000000000000000000000 --- a/include/linux/pps-gpio.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * pps-gpio.h -- PPS client for GPIOs - * - * Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca> - */ - -#ifndef _PPS_GPIO_H -#define _PPS_GPIO_H - -struct pps_gpio_platform_data { - struct gpio_desc *gpio_pin; - struct gpio_desc *echo_pin; - bool assert_falling_edge; - bool capture_clear; - unsigned int echo_active_ms; -}; - -#endif /* _PPS_GPIO_H */ diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 69cc8b64aa3a0e3b957fff471b15adcd1dbaa5fe..9881eac0698fd8eb25044b47071d54c11813aa67 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -79,7 +79,11 @@ #define nmi_count() (preempt_count() & NMI_MASK) #define hardirq_count() (preempt_count() & HARDIRQ_MASK) -#define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#ifdef CONFIG_PREEMPT_RT +# define softirq_count() (current->softirq_disable_cnt & SOFTIRQ_MASK) +#else +# define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#endif #define irq_count() (nmi_count() | hardirq_count() | softirq_count()) /* diff --git a/include/linux/property.h b/include/linux/property.h index dd4687b562393120ebd029ecc2fb977c9535f0c3..0d876316e61d5df0f574e1b007f7f6f5fab42302 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -254,6 +254,13 @@ struct software_node_ref_args { u64 args[NR_FWNODE_REFERENCE_ARGS]; }; +#define SOFTWARE_NODE_REFERENCE(_ref_, ...) \ +(const struct software_node_ref_args) { \ + .node = _ref_, \ + .nargs = ARRAY_SIZE(((u64[]){ 0, ##__VA_ARGS__ })) - 1, \ + .args = { __VA_ARGS__ }, \ +} + /** * struct property_entry - "Built-in" device property representation. * @name: Name of the property. @@ -362,11 +369,7 @@ struct property_entry { .name = _name_, \ .length = sizeof(struct software_node_ref_args), \ .type = DEV_PROP_REF, \ - { .pointer = &(const struct software_node_ref_args) { \ - .node = _ref_, \ - .nargs = ARRAY_SIZE(((u64[]){ 0, ##__VA_ARGS__ })) - 1, \ - .args = { __VA_ARGS__ }, \ - } }, \ + { .pointer = &SOFTWARE_NODE_REFERENCE(_ref_, ##__VA_ARGS__), }, \ } struct property_entry * diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index c4fdb4463f7d5c2c6fd92be4f29750c99a58743d..7c811eebcaab8917f9ded5f1eee02292778ac27a 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -47,7 +47,6 @@ struct geni_icc_path { * @num_clk_levels: Number of valid clock levels in clk_perf_tbl * @clk_perf_tbl: Table of clock frequency input to serial engine clock * @icc_paths: Array of ICC paths for SE - * @opp_table: Pointer to the OPP table */ struct geni_se { void __iomem *base; @@ -57,7 +56,6 @@ struct geni_se { unsigned int num_clk_levels; unsigned long *clk_perf_tbl; struct geni_icc_path icc_paths[3]; - struct opp_table *opp_table; }; /* Common SE registers */ diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h new file mode 100644 index 0000000000000000000000000000000000000000..fd80fab663a96153e06f05e6eb0adfe7e152a97b --- /dev/null +++ b/include/linux/randomize_kstack.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _LINUX_RANDOMIZE_KSTACK_H +#define _LINUX_RANDOMIZE_KSTACK_H + +#include <linux/kernel.h> +#include <linux/jump_label.h> +#include <linux/percpu-defs.h> + +DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, + randomize_kstack_offset); +DECLARE_PER_CPU(u32, kstack_offset); + +/* + * Do not use this anywhere else in the kernel. This is used here because + * it provides an arch-agnostic way to grow the stack with correct + * alignment. Also, since this use is being explicitly masked to a max of + * 10 bits, stack-clash style attacks are unlikely. For more details see + * "VLAs" in Documentation/process/deprecated.rst + */ +void *__builtin_alloca(size_t size); +/* + * Use, at most, 10 bits of entropy. We explicitly cap this to keep the + * "VLA" from being unbounded (see above). 10 bits leaves enough room for + * per-arch offset masks to reduce entropy (by removing higher bits, since + * high entropy may overly constrain usable stack space), and for + * compiler/arch-specific stack alignment to remove the lower bits. + */ +#define KSTACK_OFFSET_MAX(x) ((x) & 0x3FF) + +/* + * These macros must be used during syscall entry when interrupts and + * preempt are disabled, and after user registers have been stored to + * the stack. + */ +#define add_random_kstack_offset() do { \ + if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \ + &randomize_kstack_offset)) { \ + u32 offset = raw_cpu_read(kstack_offset); \ + u8 *ptr = __builtin_alloca(KSTACK_OFFSET_MAX(offset)); \ + /* Keep allocation even after "ptr" loses scope. */ \ + asm volatile("" : "=o"(*ptr) :: "memory"); \ + } \ +} while (0) + +#define choose_random_kstack_offset(rand) do { \ + if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \ + &randomize_kstack_offset)) { \ + u32 offset = raw_cpu_read(kstack_offset); \ + offset ^= (rand); \ + raw_cpu_write(kstack_offset, offset); \ + } \ +} while (0) + +#endif diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index bd04f722714f65dea4791076d3f63feb5e16e3c9..6d855ef091ba55e798457f4099594f8f7ea90289 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -334,7 +334,8 @@ static inline void rcu_preempt_sleep_check(void) { } #define rcu_sleep_check() \ do { \ rcu_preempt_sleep_check(); \ - RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), \ + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) \ + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), \ "Illegal context switch in RCU-bh read-side critical section"); \ RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map), \ "Illegal context switch in RCU-sched read-side critical section"); \ diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 2cc4ecd36298f376a7286c1cdc70318977baec82..f87a11a5cc4a70b403465d30bc5a81f6eb9ec832 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1378,6 +1378,9 @@ struct regmap_irq_sub_irq_map { * status_base. Should contain num_regs arrays. * Can be provided for chips with more complex mapping than * 1.st bit to 1.st sub-reg, 2.nd bit to 2.nd sub-reg, ... + * When used with not_fixed_stride, each one-element array + * member contains offset calculated as address from each + * peripheral to first peripheral. * @num_main_regs: Number of 'main status' irq registers for chips which have * main_status set. * @@ -1390,6 +1393,7 @@ struct regmap_irq_sub_irq_map { * Using zero value is possible with @use_ack bit. * @wake_base: Base address for wake enables. If zero unsupported. * @type_base: Base address for irq type. If zero unsupported. + * @virt_reg_base: Base addresses for extra config regs. * @irq_reg_stride: Stride to use for chips where registers are not contiguous. * @init_ack_masked: Ack all masked interrupts once during initalization. * @mask_invert: Inverted mask register: cleared bits are masked out. @@ -1404,6 +1408,9 @@ struct regmap_irq_sub_irq_map { * @clear_on_unmask: For chips with interrupts cleared on read: read the status * registers before unmasking interrupts to clear any bits * set when they were masked. + * @not_fixed_stride: Used when chip peripherals are not laid out with fixed + * stride. Must be used with sub_reg_offsets containing the + * offsets to each peripheral. * @runtime_pm: Hold a runtime PM lock on the device when accessing it. * * @num_regs: Number of registers in each control bank. @@ -1411,12 +1418,16 @@ struct regmap_irq_sub_irq_map { * assigned based on the index in the array of the interrupt. * @num_irqs: Number of descriptors. * @num_type_reg: Number of type registers. + * @num_virt_regs: Number of non-standard irq configuration registers. + * If zero unsupported. * @type_reg_stride: Stride to use for chips where type registers are not * contiguous. * @handle_pre_irq: Driver specific callback to handle interrupt from device * before regmap_irq_handler process the interrupts. * @handle_post_irq: Driver specific callback to handle interrupt from device * after handling the interrupts in regmap_irq_handler(). + * @set_type_virt: Driver specific callback to extend regmap_irq_set_type() + * and configure virt regs. * @irq_drv_data: Driver specific IRQ data which is passed as parameter when * driver specific pre/post interrupt handler is called. * @@ -1438,6 +1449,7 @@ struct regmap_irq_chip { unsigned int ack_base; unsigned int wake_base; unsigned int type_base; + unsigned int *virt_reg_base; unsigned int irq_reg_stride; bool mask_writeonly:1; bool init_ack_masked:1; @@ -1450,6 +1462,7 @@ struct regmap_irq_chip { bool type_invert:1; bool type_in_mask:1; bool clear_on_unmask:1; + bool not_fixed_stride:1; int num_regs; @@ -1457,10 +1470,13 @@ struct regmap_irq_chip { int num_irqs; int num_type_reg; + int num_virt_regs; unsigned int type_reg_stride; int (*handle_pre_irq)(void *irq_drv_data); int (*handle_post_irq)(void *irq_drv_data); + int (*set_type_virt)(unsigned int **buf, unsigned int type, + unsigned long hwirq, int reg); void *irq_drv_data; }; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d7c77ee370f37c4cf2f8593a6b22591ea37e6b7e..4ea520c248e9e0f92c62c491f173f229ad4043fa 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -373,6 +373,10 @@ struct regulator_desc { unsigned int pull_down_reg; unsigned int pull_down_mask; unsigned int pull_down_val_on; + unsigned int ramp_reg; + unsigned int ramp_mask; + const unsigned int *ramp_delay_table; + unsigned int n_ramp_values; unsigned int enable_time; @@ -472,7 +476,7 @@ struct regulator_dev { unsigned int is_switch:1; /* time when this regulator was disabled last time */ - unsigned long last_off_jiffy; + ktime_t last_off; }; struct regulator_dev * @@ -535,6 +539,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev, int min_uA, int max_uA); int regulator_get_current_limit_regmap(struct regulator_dev *rdev); void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); +int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay); /* * Helper functions intended to be used by regulator drivers prior registering @@ -543,4 +548,6 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc, unsigned int selector); +int regulator_desc_list_voltage_linear(const struct regulator_desc *desc, + unsigned int selector); #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 79fc40a6682839b78fb3e60993e9ab139e678eb1..edad5f93794dd83f10f0cf0145712ca36c416dd3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1050,6 +1050,9 @@ struct task_struct { int softirq_context; int irq_config; #endif +#ifdef CONFIG_PREEMPT_RT + int softirq_disable_cnt; +#endif #ifdef CONFIG_LOCKDEP # define MAX_LOCK_DEPTH 48UL diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index ecb3aad1a9648e22234397886b4c44dba3aeab3f..79d0a1237e6cabef0decff4b43cd7536ad5d9536 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -2,7 +2,7 @@ /* * SCMI Message Protocol driver header * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2021 ARM Ltd. */ #ifndef _LINUX_SCMI_PROTOCOL_H @@ -57,9 +57,11 @@ struct scmi_clock_info { }; struct scmi_handle; +struct scmi_device; +struct scmi_protocol_handle; /** - * struct scmi_clk_ops - represents the various operations provided + * struct scmi_clk_proto_ops - represents the various operations provided * by SCMI Clock Protocol * * @count_get: get the count of clocks provided by SCMI @@ -69,21 +71,21 @@ struct scmi_handle; * @enable: enables the specified clock * @disable: disables the specified clock */ -struct scmi_clk_ops { - int (*count_get)(const struct scmi_handle *handle); +struct scmi_clk_proto_ops { + int (*count_get)(const struct scmi_protocol_handle *ph); const struct scmi_clock_info *(*info_get) - (const struct scmi_handle *handle, u32 clk_id); - int (*rate_get)(const struct scmi_handle *handle, u32 clk_id, + (const struct scmi_protocol_handle *ph, u32 clk_id); + int (*rate_get)(const struct scmi_protocol_handle *ph, u32 clk_id, u64 *rate); - int (*rate_set)(const struct scmi_handle *handle, u32 clk_id, + int (*rate_set)(const struct scmi_protocol_handle *ph, u32 clk_id, u64 rate); - int (*enable)(const struct scmi_handle *handle, u32 clk_id); - int (*disable)(const struct scmi_handle *handle, u32 clk_id); + int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id); + int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id); }; /** - * struct scmi_perf_ops - represents the various operations provided + * struct scmi_perf_proto_ops - represents the various operations provided * by SCMI Performance Protocol * * @limits_set: sets limits on the performance level of a domain @@ -100,33 +102,33 @@ struct scmi_clk_ops { * @est_power_get: gets the estimated power cost for a given performance domain * at a given frequency */ -struct scmi_perf_ops { - int (*limits_set)(const struct scmi_handle *handle, u32 domain, +struct scmi_perf_proto_ops { + int (*limits_set)(const struct scmi_protocol_handle *ph, u32 domain, u32 max_perf, u32 min_perf); - int (*limits_get)(const struct scmi_handle *handle, u32 domain, + int (*limits_get)(const struct scmi_protocol_handle *ph, u32 domain, u32 *max_perf, u32 *min_perf); - int (*level_set)(const struct scmi_handle *handle, u32 domain, + int (*level_set)(const struct scmi_protocol_handle *ph, u32 domain, u32 level, bool poll); - int (*level_get)(const struct scmi_handle *handle, u32 domain, + int (*level_get)(const struct scmi_protocol_handle *ph, u32 domain, u32 *level, bool poll); int (*device_domain_id)(struct device *dev); - int (*transition_latency_get)(const struct scmi_handle *handle, + int (*transition_latency_get)(const struct scmi_protocol_handle *ph, struct device *dev); - int (*device_opps_add)(const struct scmi_handle *handle, + int (*device_opps_add)(const struct scmi_protocol_handle *ph, struct device *dev); - int (*freq_set)(const struct scmi_handle *handle, u32 domain, + int (*freq_set)(const struct scmi_protocol_handle *ph, u32 domain, unsigned long rate, bool poll); - int (*freq_get)(const struct scmi_handle *handle, u32 domain, + int (*freq_get)(const struct scmi_protocol_handle *ph, u32 domain, unsigned long *rate, bool poll); - int (*est_power_get)(const struct scmi_handle *handle, u32 domain, + int (*est_power_get)(const struct scmi_protocol_handle *ph, u32 domain, unsigned long *rate, unsigned long *power); - bool (*fast_switch_possible)(const struct scmi_handle *handle, + bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph, struct device *dev); - bool (*power_scale_mw_get)(const struct scmi_handle *handle); + bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph); }; /** - * struct scmi_power_ops - represents the various operations provided + * struct scmi_power_proto_ops - represents the various operations provided * by SCMI Power Protocol * * @num_domains_get: get the count of power domains provided by SCMI @@ -134,9 +136,9 @@ struct scmi_perf_ops { * @state_set: sets the power state of a power domain * @state_get: gets the power state of a power domain */ -struct scmi_power_ops { - int (*num_domains_get)(const struct scmi_handle *handle); - char *(*name_get)(const struct scmi_handle *handle, u32 domain); +struct scmi_power_proto_ops { + int (*num_domains_get)(const struct scmi_protocol_handle *ph); + char *(*name_get)(const struct scmi_protocol_handle *ph, u32 domain); #define SCMI_POWER_STATE_TYPE_SHIFT 30 #define SCMI_POWER_STATE_ID_MASK (BIT(28) - 1) #define SCMI_POWER_STATE_PARAM(type, id) \ @@ -144,9 +146,9 @@ struct scmi_power_ops { ((id) & SCMI_POWER_STATE_ID_MASK)) #define SCMI_POWER_STATE_GENERIC_ON SCMI_POWER_STATE_PARAM(0, 0) #define SCMI_POWER_STATE_GENERIC_OFF SCMI_POWER_STATE_PARAM(1, 0) - int (*state_set)(const struct scmi_handle *handle, u32 domain, + int (*state_set)(const struct scmi_protocol_handle *ph, u32 domain, u32 state); - int (*state_get)(const struct scmi_handle *handle, u32 domain, + int (*state_get)(const struct scmi_protocol_handle *ph, u32 domain, u32 *state); }; @@ -429,7 +431,7 @@ enum scmi_sensor_class { }; /** - * struct scmi_sensor_ops - represents the various operations provided + * struct scmi_sensor_proto_ops - represents the various operations provided * by SCMI Sensor Protocol * * @count_get: get the count of sensors provided by SCMI @@ -444,25 +446,25 @@ enum scmi_sensor_class { * @config_get: Get sensor current configuration * @config_set: Set sensor current configuration */ -struct scmi_sensor_ops { - int (*count_get)(const struct scmi_handle *handle); +struct scmi_sensor_proto_ops { + int (*count_get)(const struct scmi_protocol_handle *ph); const struct scmi_sensor_info *(*info_get) - (const struct scmi_handle *handle, u32 sensor_id); - int (*trip_point_config)(const struct scmi_handle *handle, + (const struct scmi_protocol_handle *ph, u32 sensor_id); + int (*trip_point_config)(const struct scmi_protocol_handle *ph, u32 sensor_id, u8 trip_id, u64 trip_value); - int (*reading_get)(const struct scmi_handle *handle, u32 sensor_id, + int (*reading_get)(const struct scmi_protocol_handle *ph, u32 sensor_id, u64 *value); - int (*reading_get_timestamped)(const struct scmi_handle *handle, + int (*reading_get_timestamped)(const struct scmi_protocol_handle *ph, u32 sensor_id, u8 count, struct scmi_sensor_reading *readings); - int (*config_get)(const struct scmi_handle *handle, + int (*config_get)(const struct scmi_protocol_handle *ph, u32 sensor_id, u32 *sensor_config); - int (*config_set)(const struct scmi_handle *handle, + int (*config_set)(const struct scmi_protocol_handle *ph, u32 sensor_id, u32 sensor_config); }; /** - * struct scmi_reset_ops - represents the various operations provided + * struct scmi_reset_proto_ops - represents the various operations provided * by SCMI Reset Protocol * * @num_domains_get: get the count of reset domains provided by SCMI @@ -472,13 +474,13 @@ struct scmi_sensor_ops { * @assert: explicitly assert reset signal of the specified reset domain * @deassert: explicitly deassert reset signal of the specified reset domain */ -struct scmi_reset_ops { - int (*num_domains_get)(const struct scmi_handle *handle); - char *(*name_get)(const struct scmi_handle *handle, u32 domain); - int (*latency_get)(const struct scmi_handle *handle, u32 domain); - int (*reset)(const struct scmi_handle *handle, u32 domain); - int (*assert)(const struct scmi_handle *handle, u32 domain); - int (*deassert)(const struct scmi_handle *handle, u32 domain); +struct scmi_reset_proto_ops { + int (*num_domains_get)(const struct scmi_protocol_handle *ph); + char *(*name_get)(const struct scmi_protocol_handle *ph, u32 domain); + int (*latency_get)(const struct scmi_protocol_handle *ph, u32 domain); + int (*reset)(const struct scmi_protocol_handle *ph, u32 domain); + int (*assert)(const struct scmi_protocol_handle *ph, u32 domain); + int (*deassert)(const struct scmi_protocol_handle *ph, u32 domain); }; /** @@ -513,7 +515,7 @@ struct scmi_voltage_info { }; /** - * struct scmi_voltage_ops - represents the various operations provided + * struct scmi_voltage_proto_ops - represents the various operations provided * by SCMI Voltage Protocol * * @num_domains_get: get the count of voltage domains provided by SCMI @@ -523,27 +525,31 @@ struct scmi_voltage_info { * @level_set: set the voltage level for the specified domain * @level_get: get the voltage level of the specified domain */ -struct scmi_voltage_ops { - int (*num_domains_get)(const struct scmi_handle *handle); +struct scmi_voltage_proto_ops { + int (*num_domains_get)(const struct scmi_protocol_handle *ph); const struct scmi_voltage_info __must_check *(*info_get) - (const struct scmi_handle *handle, u32 domain_id); - int (*config_set)(const struct scmi_handle *handle, u32 domain_id, + (const struct scmi_protocol_handle *ph, u32 domain_id); + int (*config_set)(const struct scmi_protocol_handle *ph, u32 domain_id, u32 config); #define SCMI_VOLTAGE_ARCH_STATE_OFF 0x0 #define SCMI_VOLTAGE_ARCH_STATE_ON 0x7 - int (*config_get)(const struct scmi_handle *handle, u32 domain_id, + int (*config_get)(const struct scmi_protocol_handle *ph, u32 domain_id, u32 *config); - int (*level_set)(const struct scmi_handle *handle, u32 domain_id, + int (*level_set)(const struct scmi_protocol_handle *ph, u32 domain_id, u32 flags, s32 volt_uV); - int (*level_get)(const struct scmi_handle *handle, u32 domain_id, + int (*level_get)(const struct scmi_protocol_handle *ph, u32 domain_id, s32 *volt_uV); }; /** * struct scmi_notify_ops - represents notifications' operations provided by * SCMI core - * @register_event_notifier: Register a notifier_block for the requested event - * @unregister_event_notifier: Unregister a notifier_block for the requested + * @devm_event_notifier_register: Managed registration of a notifier_block for + * the requested event + * @devm_event_notifier_unregister: Managed unregistration of a notifier_block + * for the requested event + * @event_notifier_register: Register a notifier_block for the requested event + * @event_notifier_unregister: Unregister a notifier_block for the requested * event * * A user can register/unregister its own notifier_block against the wanted @@ -551,7 +557,9 @@ struct scmi_voltage_ops { * tuple: (proto_id, evt_id, src_id) using the provided register/unregister * interface where: * - * @handle: The handle identifying the platform instance to use + * @sdev: The scmi_device to use when calling the devres managed ops devm_ + * @handle: The handle identifying the platform instance to use, when not + * calling the managed ops devm_ * @proto_id: The protocol ID as in SCMI Specification * @evt_id: The message ID of the desired event as in SCMI Specification * @src_id: A pointer to the desired source ID if different sources are @@ -574,11 +582,21 @@ struct scmi_voltage_ops { * @report: A custom struct describing the specific event delivered */ struct scmi_notify_ops { - int (*register_event_notifier)(const struct scmi_handle *handle, - u8 proto_id, u8 evt_id, u32 *src_id, + int (*devm_event_notifier_register)(struct scmi_device *sdev, + u8 proto_id, u8 evt_id, + const u32 *src_id, + struct notifier_block *nb); + int (*devm_event_notifier_unregister)(struct scmi_device *sdev, + u8 proto_id, u8 evt_id, + const u32 *src_id, + struct notifier_block *nb); + int (*event_notifier_register)(const struct scmi_handle *handle, + u8 proto_id, u8 evt_id, + const u32 *src_id, struct notifier_block *nb); - int (*unregister_event_notifier)(const struct scmi_handle *handle, - u8 proto_id, u8 evt_id, u32 *src_id, + int (*event_notifier_unregister)(const struct scmi_handle *handle, + u8 proto_id, u8 evt_id, + const u32 *src_id, struct notifier_block *nb); }; @@ -587,47 +605,21 @@ struct scmi_notify_ops { * * @dev: pointer to the SCMI device * @version: pointer to the structure containing SCMI version information - * @power_ops: pointer to set of power protocol operations - * @perf_ops: pointer to set of performance protocol operations - * @clk_ops: pointer to set of clock protocol operations - * @sensor_ops: pointer to set of sensor protocol operations - * @reset_ops: pointer to set of reset protocol operations - * @voltage_ops: pointer to set of voltage protocol operations + * @devm_protocol_get: devres managed method to acquire a protocol and get specific + * operations and a dedicated protocol handler + * @devm_protocol_put: devres managed method to release a protocol * @notify_ops: pointer to set of notifications related operations - * @perf_priv: pointer to private data structure specific to performance - * protocol(for internal use only) - * @clk_priv: pointer to private data structure specific to clock - * protocol(for internal use only) - * @power_priv: pointer to private data structure specific to power - * protocol(for internal use only) - * @sensor_priv: pointer to private data structure specific to sensors - * protocol(for internal use only) - * @reset_priv: pointer to private data structure specific to reset - * protocol(for internal use only) - * @voltage_priv: pointer to private data structure specific to voltage - * protocol(for internal use only) - * @notify_priv: pointer to private data structure specific to notifications - * (for internal use only) */ struct scmi_handle { struct device *dev; struct scmi_revision_info *version; - const struct scmi_perf_ops *perf_ops; - const struct scmi_clk_ops *clk_ops; - const struct scmi_power_ops *power_ops; - const struct scmi_sensor_ops *sensor_ops; - const struct scmi_reset_ops *reset_ops; - const struct scmi_voltage_ops *voltage_ops; + + const void __must_check * + (*devm_protocol_get)(struct scmi_device *sdev, u8 proto, + struct scmi_protocol_handle **ph); + void (*devm_protocol_put)(struct scmi_device *sdev, u8 proto); + const struct scmi_notify_ops *notify_ops; - /* for protocol internal use */ - void *perf_priv; - void *clk_priv; - void *power_priv; - void *sensor_priv; - void *reset_priv; - void *voltage_priv; - void *notify_priv; - void *system_priv; }; enum scmi_std_protocol { @@ -712,9 +704,21 @@ static inline void scmi_driver_unregister(struct scmi_driver *driver) {} #define module_scmi_driver(__scmi_driver) \ module_driver(__scmi_driver, scmi_register, scmi_unregister) -typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *); -int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn); -void scmi_protocol_unregister(int protocol_id); +/** + * module_scmi_protocol() - Helper macro for registering a scmi protocol + * @__scmi_protocol: scmi_protocol structure + * + * Helper macro for scmi drivers to set up proper module init / exit + * functions. Replaces module_init() and module_exit() and keeps people from + * printing pointless things to the kernel log when their driver is loaded. + */ +#define module_scmi_protocol(__scmi_protocol) \ + module_driver(__scmi_protocol, \ + scmi_protocol_register, scmi_protocol_unregister) + +struct scmi_protocol; +int scmi_protocol_register(const struct scmi_protocol *proto); +void scmi_protocol_unregister(const struct scmi_protocol *proto); /* SCMI Notification API - Custom Event Reports */ enum scmi_notification_events { diff --git a/include/linux/security.h b/include/linux/security.h index 58aadeb61d55185b488e7c82bda7d8ec2eed610b..036f01242e93e0b97d36c5d2747245b5f005a340 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -292,6 +292,7 @@ int security_sb_alloc(struct super_block *sb); void security_sb_free(struct super_block *sb); void security_free_mnt_opts(void **mnt_opts); int security_sb_eat_lsm_opts(char *options, void **mnt_opts); +int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts); int security_sb_remount(struct super_block *sb, void *mnt_opts); int security_sb_kern_mount(struct super_block *sb); int security_sb_show_options(struct seq_file *m, struct super_block *sb); @@ -412,7 +413,8 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old, int security_task_setpgid(struct task_struct *p, pid_t pgid); int security_task_getpgid(struct task_struct *p); int security_task_getsid(struct task_struct *p); -void security_task_getsecid(struct task_struct *p, u32 *secid); +void security_task_getsecid_subj(struct task_struct *p, u32 *secid); +void security_task_getsecid_obj(struct task_struct *p, u32 *secid); int security_task_setnice(struct task_struct *p, int nice); int security_task_setioprio(struct task_struct *p, int ioprio); int security_task_getioprio(struct task_struct *p); @@ -644,6 +646,13 @@ static inline int security_sb_remount(struct super_block *sb, return 0; } +static inline int security_sb_mnt_opts_compat(struct super_block *sb, + void *mnt_opts) +{ + return 0; +} + + static inline int security_sb_kern_mount(struct super_block *sb) { return 0; @@ -1096,7 +1105,12 @@ static inline int security_task_getsid(struct task_struct *p) return 0; } -static inline void security_task_getsecid(struct task_struct *p, u32 *secid) +static inline void security_task_getsecid_subj(struct task_struct *p, u32 *secid) +{ + *secid = 0; +} + +static inline void security_task_getsecid_obj(struct task_struct *p, u32 *secid) { *secid = 0; } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index e1b684e3384178f963dbd04f5a34d5a393d52d18..d7ed00f1594ef660f9070c164fa61b03002f9be8 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -500,19 +500,19 @@ static inline int uart_prepare_sysrq_char(struct uart_port *port, unsigned int c return 0; } -static inline void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags) +static inline void uart_unlock_and_check_sysrq(struct uart_port *port) { int sysrq_ch; if (!port->has_sysrq) { - spin_unlock_irqrestore(&port->lock, irqflags); + spin_unlock(&port->lock); return; } sysrq_ch = port->sysrq_ch; port->sysrq_ch = 0; - spin_unlock_irqrestore(&port->lock, irqflags); + spin_unlock(&port->lock); if (sysrq_ch) handle_sysrq(sysrq_ch); @@ -526,9 +526,9 @@ static inline int uart_prepare_sysrq_char(struct uart_port *port, unsigned int c { return 0; } -static inline void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags) +static inline void uart_unlock_and_check_sysrq(struct uart_port *port) { - spin_unlock_irqrestore(&port->lock, irqflags); + spin_unlock(&port->lock); } #endif /* CONFIG_MAGIC_SYSRQ_SERIAL */ diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h index ca2c5393dc6befc1b8e9afc6134737471a9b103c..f6c3323fc4c52b923903eb29d12a0de07a92c191 100644 --- a/include/linux/serial_s3c.h +++ b/include/linux/serial_s3c.h @@ -246,6 +246,22 @@ S5PV210_UFCON_TXTRIG4 | \ S5PV210_UFCON_RXTRIG4) +#define APPLE_S5L_UCON_RXTO_ENA 9 +#define APPLE_S5L_UCON_RXTHRESH_ENA 12 +#define APPLE_S5L_UCON_TXTHRESH_ENA 13 +#define APPLE_S5L_UCON_RXTO_ENA_MSK (1 << APPLE_S5L_UCON_RXTO_ENA) +#define APPLE_S5L_UCON_RXTHRESH_ENA_MSK (1 << APPLE_S5L_UCON_RXTHRESH_ENA) +#define APPLE_S5L_UCON_TXTHRESH_ENA_MSK (1 << APPLE_S5L_UCON_TXTHRESH_ENA) + +#define APPLE_S5L_UCON_DEFAULT (S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI) + +#define APPLE_S5L_UTRSTAT_RXTHRESH (1<<4) +#define APPLE_S5L_UTRSTAT_TXTHRESH (1<<5) +#define APPLE_S5L_UTRSTAT_RXTO (1<<9) +#define APPLE_S5L_UTRSTAT_ALL_FLAGS (0x3f0) + #ifndef __ASSEMBLY__ #include <linux/serial_core.h> diff --git a/include/linux/soc/qcom/apr.h b/include/linux/soc/qcom/apr.h index 7f0bc3cf4d610cd06c73b58677f049785aeaa353..137f9f2ac4c3c21ae24e618bd3dcb3d5d74091af 100644 --- a/include/linux/soc/qcom/apr.h +++ b/include/linux/soc/qcom/apr.h @@ -113,7 +113,7 @@ void apr_driver_unregister(struct apr_driver *drv); /** * module_apr_driver() - Helper macro for registering a aprbus driver - * @__aprbus_driver: aprbus_driver struct + * @__apr_driver: apr_driver struct * * Helper macro for aprbus drivers which do not do anything special in * module init/exit. This eliminates a lot of boilerplate. Each module diff --git a/include/linux/soc/qcom/irq.h b/include/linux/soc/qcom/irq.h index 9e1ece58e55b734cfc1ca61131787957347437a0..72b9231e9fdde2fc4d2b7689243d5de2a57e1b00 100644 --- a/include/linux/soc/qcom/irq.h +++ b/include/linux/soc/qcom/irq.h @@ -7,7 +7,7 @@ #define GPIO_NO_WAKE_IRQ ~0U -/** +/* * QCOM specific IRQ domain flags that distinguishes the handling of wakeup * capable interrupts by different interrupt controllers. * diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 64fc582ae41573d9c0fe63011730236884deea95..437c9df132296981a20aee0bccdbe18e92aebd2b 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -35,7 +35,7 @@ #define LLCC_WRCACHE 31 /** - * llcc_slice_desc - Cache slice descriptor + * struct llcc_slice_desc - Cache slice descriptor * @slice_id: llcc slice id * @slice_size: Size allocated for the llcc slice */ @@ -45,7 +45,7 @@ struct llcc_slice_desc { }; /** - * llcc_edac_reg_data - llcc edac registers data for each error type + * struct llcc_edac_reg_data - llcc edac registers data for each error type * @name: Name of the error * @synd_reg: Syndrome register address * @count_status_reg: Status register address to read the error count @@ -69,7 +69,7 @@ struct llcc_edac_reg_data { }; /** - * llcc_drv_data - Data associated with the llcc driver + * struct llcc_drv_data - Data associated with the llcc driver * @regmap: regmap associated with the llcc device * @bcast_regmap: regmap associated with llcc broadcast offset * @cfg: pointer to the data structure for slice configuration diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h index e712f94b89fcc150622d47ca843b0496885cfa4b..b1f80e756d2af55e39a9501f251dea37ba18a4a5 100644 --- a/include/linux/soc/qcom/qmi.h +++ b/include/linux/soc/qcom/qmi.h @@ -16,7 +16,7 @@ struct socket; /** - * qmi_header - wireformat header of QMI messages + * struct qmi_header - wireformat header of QMI messages * @type: type of message * @txn_id: transaction id * @msg_id: message id @@ -93,7 +93,7 @@ struct qmi_elem_info { #define QMI_ERR_NOT_SUPPORTED_V01 94 /** - * qmi_response_type_v01 - common response header (decoded) + * struct qmi_response_type_v01 - common response header (decoded) * @result: result of the transaction * @error: error value, when @result is QMI_RESULT_FAILURE_V01 */ diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index d08039d65825efadd7dd443bbfa0033f1c1d961b..ced07f8fde8701fddbd814b10d8e5eb645744a77 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -125,6 +125,12 @@ enum sdw_dpn_grouping { SDW_BLK_GRP_CNT_4 = 3, }; +/* block packing mode enum */ +enum sdw_dpn_pkg_mode { + SDW_BLK_PKG_PER_PORT = 0, + SDW_BLK_PKG_PER_CHANNEL = 1 +}; + /** * enum sdw_stream_type: data stream type * @@ -405,6 +411,7 @@ struct sdw_slave_prop { * command * @mclk_freq: clock reference passed to SoundWire Master, in Hz. * @hw_disabled: if true, the Master is not functional, typically due to pin-mux + * @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification */ struct sdw_master_prop { u32 revision; @@ -421,8 +428,29 @@ struct sdw_master_prop { u32 err_threshold; u32 mclk_freq; bool hw_disabled; + u64 quirks; }; +/* Definitions for Master quirks */ + +/* + * In a number of platforms bus clashes are reported after a hardware + * reset but without any explanations or evidence of a real problem. + * The following quirk will discard all initial bus clash interrupts + * but will leave the detection on should real bus clashes happen + */ +#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH BIT(0) + +/* + * Some Slave devices have known issues with incorrect parity errors + * reported after a hardware reset. However during integration unexplained + * parity errors can be reported by Slave devices, possibly due to electrical + * issues at the Master level. + * The following quirk will discard all initial parity errors but will leave + * the detection on should real parity errors happen. + */ +#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY BIT(1) + int sdw_master_read_prop(struct sdw_bus *bus); int sdw_slave_read_prop(struct sdw_slave *slave); @@ -614,6 +642,7 @@ struct sdw_slave_ops { * @debugfs: Slave debugfs * @node: node for bus list * @port_ready: Port ready completion flag for each Slave port + * @m_port_map: static Master port map for each Slave port * @dev_num: Current Device Number, values can be 0 or dev_num_sticky * @dev_num_sticky: one-time static Device Number assigned by Bus * @probed: boolean tracking driver state @@ -645,6 +674,7 @@ struct sdw_slave { #endif struct list_head node; struct completion port_ready[SDW_MAX_PORTS]; + unsigned int m_port_map[SDW_MAX_PORTS]; enum sdw_clk_stop_mode curr_clk_stop_mode; u16 dev_num; u16 dev_num_sticky; @@ -804,6 +834,7 @@ struct sdw_defer { /** * struct sdw_master_ops - Master driver ops * @read_prop: Read Master properties + * @override_adr: Override value read from firmware (quirk for buggy firmware) * @xfer_msg: Transfer message callback * @xfer_msg_defer: Defer version of transfer message callback * @reset_page_addr: Reset the SCP page address registers @@ -813,7 +844,8 @@ struct sdw_defer { */ struct sdw_master_ops { int (*read_prop)(struct sdw_bus *bus); - + u64 (*override_adr) + (struct sdw_bus *bus, u64 addr); enum sdw_command_response (*xfer_msg) (struct sdw_bus *bus, struct sdw_msg *msg); enum sdw_command_response (*xfer_msg_defer) @@ -1009,5 +1041,7 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); int sdw_read_no_pm(struct sdw_slave *slave, u32 addr); int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); +int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id); +void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id); #endif /* __SOUNDWIRE_H */ diff --git a/include/linux/spi/altera.h b/include/linux/spi/altera.h index 2d42641499a6e05e9e7ba13b958b6455e8dc48aa..2e2a622e56da97a16957d89fd567446728f29ce2 100644 --- a/include/linux/spi/altera.h +++ b/include/linux/spi/altera.h @@ -5,10 +5,13 @@ #ifndef __LINUX_SPI_ALTERA_H #define __LINUX_SPI_ALTERA_H +#include <linux/interrupt.h> #include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/types.h> +#define ALTERA_SPI_MAX_CS 32 + /** * struct altera_spi_platform_data - Platform data of the Altera SPI driver * @mode_bits: Mode bits of SPI master. @@ -26,4 +29,22 @@ struct altera_spi_platform_data { struct spi_board_info *devices; }; +struct altera_spi { + int irq; + int len; + int count; + int bytes_per_word; + u32 imr; + + /* data buffers */ + const unsigned char *tx; + unsigned char *rx; + + struct regmap *regmap; + u32 regoff; + struct device *dev; +}; + +extern irqreturn_t altera_spi_irq(int irq, void *dev); +extern void altera_spi_init_master(struct spi_master *master); #endif /* __LINUX_SPI_ALTERA_H */ diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 592897fa4f030ed08c07c95ea6af56abfbd4739a..360a3bc767ca0442dd71f7bbfab7174eb942d4df 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -19,7 +19,7 @@ #include <uapi/linux/spi/spi.h> struct dma_chan; -struct property_entry; +struct software_node; struct spi_controller; struct spi_transfer; struct spi_controller_mem_ops; @@ -247,7 +247,6 @@ static inline void *spi_get_drvdata(struct spi_device *spi) } struct spi_message; -struct spi_transfer; /** * struct spi_driver - Host side "protocol" driver @@ -510,6 +509,9 @@ struct spi_controller { #define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ + /* flag indicating this is a non-devres managed controller */ + bool devm_allocated; + /* flag indicating this is an SPI slave controller */ bool slave; @@ -832,9 +834,6 @@ extern void spi_res_release(struct spi_controller *ctlr, * @delay: delay to be introduced after this transfer before * (optionally) changing the chipselect status, then starting * the next transfer or completing this @spi_message. - * @delay_usecs: microseconds to delay after this transfer before - * (optionally) changing the chipselect status, then starting - * the next transfer or completing this @spi_message. * @word_delay: inter word delay to be introduced after each word size * (set by bits_per_word) transmission. * @effective_speed_hz: the effective SCK-speed that was used to @@ -946,7 +945,6 @@ struct spi_transfer { #define SPI_NBITS_DUAL 0x02 /* 2bits transfer */ #define SPI_NBITS_QUAD 0x04 /* 4bits transfer */ u8 bits_per_word; - u16 delay_usecs; struct spi_delay delay; struct spi_delay cs_change_delay; struct spi_delay word_delay; @@ -1060,14 +1058,6 @@ spi_transfer_del(struct spi_transfer *t) static inline int spi_transfer_delay_exec(struct spi_transfer *t) { - struct spi_delay d; - - if (t->delay_usecs) { - d.value = t->delay_usecs; - d.unit = SPI_DELAY_UNIT_USECS; - return spi_delay_exec(&d, NULL); - } - return spi_delay_exec(&t->delay, t); } @@ -1409,7 +1399,7 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd) * @modalias: Initializes spi_device.modalias; identifies the driver. * @platform_data: Initializes spi_device.platform_data; the particular * data stored there is driver-specific. - * @properties: Additional device properties for the device. + * @swnode: Software node for the device. * @controller_data: Initializes spi_device.controller_data; some * controllers need hints about hardware setup, e.g. for DMA. * @irq: Initializes spi_device.irq; depends on how the board is wired. @@ -1442,12 +1432,11 @@ struct spi_board_info { * * platform_data goes to spi_device.dev.platform_data, * controller_data goes to spi_device.controller_data, - * device properties are copied and attached to spi_device, * irq is copied too */ char modalias[SPI_NAME_SIZE]; const void *platform_data; - const struct property_entry *properties; + const struct software_node *swnode; void *controller_data; int irq; diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h index 50e2df30b0aa316d056953710852c2b4d8caed59..9edecb494e9e2d5414367598238f7a5396dfc679 100644 --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h @@ -52,8 +52,27 @@ typedef bool (*stack_trace_consume_fn)(void *cookie, unsigned long addr); */ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, struct task_struct *task, struct pt_regs *regs); + +/** + * arch_stack_walk_reliable - Architecture specific function to walk the + * stack reliably + * + * @consume_entry: Callback which is invoked by the architecture code for + * each entry. + * @cookie: Caller supplied pointer which is handed back to + * @consume_entry + * @task: Pointer to a task struct, can be NULL + * + * This function returns an error if it detects any unreliable + * features of the stack. Otherwise it guarantees that the stack + * trace is reliable. + * + * If the task is not 'current', the caller *must* ensure the task is + * inactive and its stack is pinned. + */ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, void *cookie, struct task_struct *task); + void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, const struct pt_regs *regs); diff --git a/include/linux/static_call.h b/include/linux/static_call.h index 85ecc789f4ffdd8f302849d38594e16748271e47..e01b61ab86b10ffb5a435ae1562b2159cdab8909 100644 --- a/include/linux/static_call.h +++ b/include/linux/static_call.h @@ -20,6 +20,7 @@ * static_call(name)(args...); * static_call_cond(name)(args...); * static_call_update(name, func); + * static_call_query(name); * * Usage example: * @@ -91,6 +92,10 @@ * * which will include the required value tests to avoid NULL-pointer * dereferences. + * + * To query which function is currently set to be called, use: + * + * func = static_call_query(name); */ #include <linux/types.h> @@ -118,6 +123,8 @@ extern void arch_static_call_transform(void *site, void *tramp, void *func, bool STATIC_CALL_TRAMP_ADDR(name), func); \ }) +#define static_call_query(name) (READ_ONCE(STATIC_CALL_KEY(name).func)) + #ifdef CONFIG_HAVE_STATIC_CALL_INLINE extern int __init static_call_init(void); @@ -128,16 +135,6 @@ struct static_call_mod { struct static_call_site *sites; }; -struct static_call_key { - void *func; - union { - /* bit 0: 0 = mods, 1 = sites */ - unsigned long type; - struct static_call_mod *mods; - struct static_call_site *sites; - }; -}; - /* For finding the key associated with a trampoline */ struct static_call_tramp_key { s32 tramp; @@ -187,10 +184,6 @@ extern long __static_call_return0(void); static inline int static_call_init(void) { return 0; } -struct static_call_key { - void *func; -}; - #define __DEFINE_STATIC_CALL(name, _func, _func_init) \ DECLARE_STATIC_CALL(name, _func); \ struct static_call_key STATIC_CALL_KEY(name) = { \ @@ -205,6 +198,7 @@ struct static_call_key { }; \ ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name) + #define static_call_cond(name) (void)__static_call(name) static inline @@ -243,10 +237,6 @@ static inline long __static_call_return0(void) static inline int static_call_init(void) { return 0; } -struct static_call_key { - void *func; -}; - static inline long __static_call_return0(void) { return 0; diff --git a/include/linux/static_call_types.h b/include/linux/static_call_types.h index ae5662d368b98f7bceb3d065e2e832507b32f671..5a00b8b2cf9fcceb1fa247a4da5fe2f330f378ce 100644 --- a/include/linux/static_call_types.h +++ b/include/linux/static_call_types.h @@ -58,11 +58,25 @@ struct static_call_site { __raw_static_call(name); \ }) +struct static_call_key { + void *func; + union { + /* bit 0: 0 = mods, 1 = sites */ + unsigned long type; + struct static_call_mod *mods; + struct static_call_site *sites; + }; +}; + #else /* !CONFIG_HAVE_STATIC_CALL_INLINE */ #define __STATIC_CALL_ADDRESSABLE(name) #define __static_call(name) __raw_static_call(name) +struct static_call_key { + void *func; +}; + #endif /* CONFIG_HAVE_STATIC_CALL_INLINE */ #ifdef MODULE @@ -77,6 +91,10 @@ struct static_call_site { #else +struct static_call_key { + void *func; +}; + #define static_call(name) \ ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func)) diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 31ee3b6047c3003ae9f7f34342c91e6c6b4a6eaf..e91d51ea028bb7c4a772956eed58c567e4c92525 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -248,6 +248,7 @@ struct svc_rqst { size_t rq_xprt_hlen; /* xprt header len */ struct xdr_buf rq_arg; struct xdr_stream rq_arg_stream; + struct xdr_stream rq_res_stream; struct page *rq_scratch_page; struct xdr_buf rq_res; struct page *rq_pages[RPCSVC_MAXPAGES + 1]; @@ -574,4 +575,28 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp) xdr_set_scratch_page(xdr, rqstp->rq_scratch_page); } +/** + * svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding + * @rqstp: controlling server RPC transaction context + * + */ +static inline void svcxdr_init_encode(struct svc_rqst *rqstp) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct xdr_buf *buf = &rqstp->rq_res; + struct kvec *resv = buf->head; + + xdr_reset_scratch_buffer(xdr); + + xdr->buf = buf; + xdr->iov = resv; + xdr->p = resv->iov_base + resv->iov_len; + xdr->end = resv->iov_base + PAGE_SIZE - rqstp->rq_auth_slack; + buf->len = resv->iov_len; + xdr->page_ptr = buf->pages - 1; + buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages); + buf->buflen -= rqstp->rq_auth_slack; + xdr->rqst = NULL; +} + #endif /* SUNRPC_SVC_H */ diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index 1e76ed68804475283ca87ea7a86ac6f4e7610745..3184465de3a0bde38f7d9ebfb7ac1f12da7afbb1 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -94,6 +94,8 @@ struct svcxprt_rdma { spinlock_t sc_rw_ctxt_lock; struct list_head sc_rw_ctxts; + u32 sc_pending_recvs; + u32 sc_recv_batch; struct list_head sc_rq_dto_q; spinlock_t sc_rq_dto_lock; struct ib_qp *sc_qp; @@ -104,7 +106,6 @@ struct svcxprt_rdma { wait_queue_head_t sc_send_wait; /* SQ exhaustion waitlist */ unsigned long sc_flags; - struct list_head sc_read_complete_q; struct work_struct sc_work; struct llist_head sc_recv_ctxts; @@ -133,12 +134,10 @@ struct svc_rdma_recv_ctxt { struct rpc_rdma_cid rc_cid; struct ib_sge rc_recv_sge; void *rc_recv_buf; - struct xdr_buf rc_arg; struct xdr_stream rc_stream; bool rc_temp; u32 rc_byte_len; unsigned int rc_page_count; - unsigned int rc_hdr_count; u32 rc_inv_rkey; __be32 rc_msgtype; @@ -148,8 +147,6 @@ struct svc_rdma_recv_ctxt { struct svc_rdma_chunk *rc_cur_result_payload; struct svc_rdma_pcl rc_write_pcl; struct svc_rdma_pcl rc_reply_pcl; - - struct page *rc_pages[RPCSVC_MAXPAGES]; }; struct svc_rdma_send_ctxt { @@ -158,12 +155,12 @@ struct svc_rdma_send_ctxt { struct ib_send_wr sc_send_wr; struct ib_cqe sc_cqe; + struct completion sc_done; struct xdr_buf sc_hdrbuf; struct xdr_stream sc_stream; void *sc_xprt_buf; - int sc_page_count; int sc_cur_sge_no; - struct page *sc_pages[RPCSVC_MAXPAGES]; + struct ib_sge sc_sges[]; }; diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 92455e0d524459d47ce87ba1bd809e7e1d841e99..571f605bc91ef8fa190e7fd5504efb76ec3fa89e 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -130,6 +130,7 @@ void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, int svc_create_xprt(struct svc_serv *, const char *, struct net *, const int, const unsigned short, int, const struct cred *); +void svc_xprt_received(struct svc_xprt *xprt); void svc_xprt_do_enqueue(struct svc_xprt *xprt); void svc_xprt_enqueue(struct svc_xprt *xprt); void svc_xprt_put(struct svc_xprt *xprt); @@ -143,6 +144,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt); void svc_age_temp_xprts_now(struct svc_serv *, struct sockaddr *); +void svc_xprt_deferred_close(struct svc_xprt *xprt); static inline void svc_xprt_get(struct svc_xprt *xprt) { diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 2bc75c167f00f66d4269a3232cddfdbe650e5cdc..a965cbc136adddc6de0a8aa97c496c9a390de146 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -394,6 +394,40 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr) return len; } +/** + * xdr_encode_bool - Encode a boolean item + * @p: address in a buffer into which to encode + * @n: boolean value to encode + * + * Return value: + * Address of item following the encoded boolean + */ +static inline __be32 *xdr_encode_bool(__be32 *p, u32 n) +{ + *p = n ? xdr_one : xdr_zero; + return p++; +} + +/** + * xdr_stream_encode_bool - Encode a boolean item + * @xdr: pointer to xdr_stream + * @n: boolean value to encode + * + * Return values: + * On success, returns length in bytes of XDR buffer consumed + * %-EMSGSIZE on XDR buffer overflow + */ +static inline int xdr_stream_encode_bool(struct xdr_stream *xdr, __u32 n) +{ + const size_t len = XDR_UNIT; + __be32 *p = xdr_reserve_space(xdr, len); + + if (unlikely(!p)) + return -EMSGSIZE; + xdr_encode_bool(p, n); + return len; +} + /** * xdr_stream_encode_u32 - Encode a 32-bit integer * @xdr: pointer to xdr_stream diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index f4b1ba8873849f8244d3a35c64da39cf28348c14..0806796eabcbff3f3f19fe93934a9deb15371a0e 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -344,16 +344,16 @@ struct ssam_request_spec_md { * request has been fully completed. The required transport buffer will be * allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_controller - * *ctrl)``, returning the status of the request, which is zero on success and - * negative on failure. The ``ctrl`` parameter is the controller via which the - * request is being sent. + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl)``, returning the status of the request, which is + * zero on success and negative on failure. The ``ctrl`` parameter is the + * controller via which the request is being sent. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_N(name, spec...) \ - int name(struct ssam_controller *ctrl) \ + static int name(struct ssam_controller *ctrl) \ { \ struct ssam_request_spec s = (struct ssam_request_spec)spec; \ struct ssam_request rqst; \ @@ -383,17 +383,17 @@ struct ssam_request_spec_md { * returning once the request has been fully completed. The required transport * buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_controller - * *ctrl, const atype *arg)``, returning the status of the request, which is - * zero on success and negative on failure. The ``ctrl`` parameter is the - * controller via which the request is sent. The request argument is specified - * via the ``arg`` pointer. + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, const atype *arg)``, returning the status of the + * request, which is zero on success and negative on failure. The ``ctrl`` + * parameter is the controller via which the request is sent. The request + * argument is specified via the ``arg`` pointer. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_W(name, atype, spec...) \ - int name(struct ssam_controller *ctrl, const atype *arg) \ + static int name(struct ssam_controller *ctrl, const atype *arg) \ { \ struct ssam_request_spec s = (struct ssam_request_spec)spec; \ struct ssam_request rqst; \ @@ -424,17 +424,17 @@ struct ssam_request_spec_md { * request itself, returning once the request has been fully completed. The * required transport buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_controller - * *ctrl, rtype *ret)``, returning the status of the request, which is zero on - * success and negative on failure. The ``ctrl`` parameter is the controller - * via which the request is sent. The request's return value is written to the - * memory pointed to by the ``ret`` parameter. + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, rtype *ret)``, returning the status of the request, + * which is zero on success and negative on failure. The ``ctrl`` parameter is + * the controller via which the request is sent. The request's return value is + * written to the memory pointed to by the ``ret`` parameter. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_R(name, rtype, spec...) \ - int name(struct ssam_controller *ctrl, rtype *ret) \ + static int name(struct ssam_controller *ctrl, rtype *ret) \ { \ struct ssam_request_spec s = (struct ssam_request_spec)spec; \ struct ssam_request rqst; \ @@ -483,17 +483,17 @@ struct ssam_request_spec_md { * returning once the request has been fully completed. The required transport * buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_controller - * *ctrl, u8 tid, u8 iid)``, returning the status of the request, which is - * zero on success and negative on failure. The ``ctrl`` parameter is the - * controller via which the request is sent, ``tid`` the target ID for the - * request, and ``iid`` the instance ID. + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, u8 tid, u8 iid)``, returning the status of the + * request, which is zero on success and negative on failure. The ``ctrl`` + * parameter is the controller via which the request is sent, ``tid`` the + * target ID for the request, and ``iid`` the instance ID. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_N(name, spec...) \ - int name(struct ssam_controller *ctrl, u8 tid, u8 iid) \ + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid) \ { \ struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \ struct ssam_request rqst; \ @@ -524,18 +524,18 @@ struct ssam_request_spec_md { * the request itself, returning once the request has been fully completed. * The required transport buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_controller - * *ctrl, u8 tid, u8 iid, const atype *arg)``, returning the status of the - * request, which is zero on success and negative on failure. The ``ctrl`` - * parameter is the controller via which the request is sent, ``tid`` the - * target ID for the request, and ``iid`` the instance ID. The request argument - * is specified via the ``arg`` pointer. + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg)``, returning the + * status of the request, which is zero on success and negative on failure. + * The ``ctrl`` parameter is the controller via which the request is sent, + * ``tid`` the target ID for the request, and ``iid`` the instance ID. The + * request argument is specified via the ``arg`` pointer. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_W(name, atype, spec...) \ - int name(struct ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg)\ + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg) \ { \ struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \ struct ssam_request rqst; \ @@ -567,18 +567,18 @@ struct ssam_request_spec_md { * execution of the request itself, returning once the request has been fully * completed. The required transport buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_controller - * *ctrl, u8 tid, u8 iid, rtype *ret)``, returning the status of the request, - * which is zero on success and negative on failure. The ``ctrl`` parameter is - * the controller via which the request is sent, ``tid`` the target ID for the - * request, and ``iid`` the instance ID. The request's return value is written - * to the memory pointed to by the ``ret`` parameter. + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret)``, returning the status + * of the request, which is zero on success and negative on failure. The + * ``ctrl`` parameter is the controller via which the request is sent, ``tid`` + * the target ID for the request, and ``iid`` the instance ID. The request's + * return value is written to the memory pointed to by the ``ret`` parameter. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_R(name, rtype, spec...) \ - int name(struct ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret) \ + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret) \ { \ struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \ struct ssam_request rqst; \ diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 02f3e06c0a604739a54635d23ec358af37109c35..4441ad667c3f9426200d7f56fee2f9d9693f6fb2 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -336,17 +336,18 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d); * request has been fully completed. The required transport buffer will be * allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_device *sdev)``, - * returning the status of the request, which is zero on success and negative - * on failure. The ``sdev`` parameter specifies both the target device of the - * request and by association the controller via which the request is sent. + * The generated function is defined as ``static int name(struct ssam_device + * *sdev)``, returning the status of the request, which is zero on success and + * negative on failure. The ``sdev`` parameter specifies both the target + * device of the request and by association the controller via which the + * request is sent. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...) \ SSAM_DEFINE_SYNC_REQUEST_MD_N(__raw_##name, spec) \ - int name(struct ssam_device *sdev) \ + static int name(struct ssam_device *sdev) \ { \ return __raw_##name(sdev->ctrl, sdev->uid.target, \ sdev->uid.instance); \ @@ -368,19 +369,19 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d); * itself, returning once the request has been fully completed. The required * transport buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_device *sdev, - * const atype *arg)``, returning the status of the request, which is zero on - * success and negative on failure. The ``sdev`` parameter specifies both the - * target device of the request and by association the controller via which - * the request is sent. The request's argument is specified via the ``arg`` - * pointer. + * The generated function is defined as ``static int name(struct ssam_device + * *sdev, const atype *arg)``, returning the status of the request, which is + * zero on success and negative on failure. The ``sdev`` parameter specifies + * both the target device of the request and by association the controller via + * which the request is sent. The request's argument is specified via the + * ``arg`` pointer. * * Refer to ssam_request_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...) \ SSAM_DEFINE_SYNC_REQUEST_MD_W(__raw_##name, atype, spec) \ - int name(struct ssam_device *sdev, const atype *arg) \ + static int name(struct ssam_device *sdev, const atype *arg) \ { \ return __raw_##name(sdev->ctrl, sdev->uid.target, \ sdev->uid.instance, arg); \ @@ -402,8 +403,8 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d); * itself, returning once the request has been fully completed. The required * transport buffer will be allocated on the stack. * - * The generated function is defined as ``int name(struct ssam_device *sdev, - * rtype *ret)``, returning the status of the request, which is zero on + * The generated function is defined as ``static int name(struct ssam_device + * *sdev, rtype *ret)``, returning the status of the request, which is zero on * success and negative on failure. The ``sdev`` parameter specifies both the * target device of the request and by association the controller via which * the request is sent. The request's return value is written to the memory @@ -414,7 +415,7 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d); */ #define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \ SSAM_DEFINE_SYNC_REQUEST_MD_R(__raw_##name, rtype, spec) \ - int name(struct ssam_device *sdev, rtype *ret) \ + static int name(struct ssam_device *sdev, rtype *ret) \ { \ return __raw_##name(sdev->ctrl, sdev->uid.target, \ sdev->uid.instance, ret); \ diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 659a0a810fa17f76e54d72b74cec051e706952c7..e7c96c37174f1cfb9e8983382f21f3f3ffa599f0 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -146,6 +146,7 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block, size_t block_len); ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, size_t block_len); +struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir); struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid); void tb_property_free_dir(struct tb_property_dir *dir); int tb_property_add_immediate(struct tb_property_dir *parent, const char *key, @@ -179,23 +180,24 @@ void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir); * @route: Route string the other domain can be reached * @vendor: Vendor ID of the remote domain * @device: Device ID of the demote domain + * @local_max_hopid: Maximum input HopID of this host + * @remote_max_hopid: Maximum input HopID of the remote host * @lock: Lock to serialize access to the following fields of this structure * @vendor_name: Name of the vendor (or %NULL if not known) * @device_name: Name of the device (or %NULL if not known) * @link_speed: Speed of the link in Gb/s * @link_width: Width of the link (1 or 2) * @is_unplugged: The XDomain is unplugged - * @resume: The XDomain is being resumed * @needs_uuid: If the XDomain does not have @remote_uuid it will be * queried first - * @transmit_path: HopID which the remote end expects us to transmit - * @transmit_ring: Local ring (hop) where outgoing packets are pushed - * @receive_path: HopID which we expect the remote end to transmit - * @receive_ring: Local ring (hop) where incoming packets arrive * @service_ids: Used to generate IDs for the services - * @properties: Properties exported by the remote domain - * @property_block_gen: Generation of @properties - * @properties_lock: Lock protecting @properties. + * @in_hopids: Input HopIDs for DMA tunneling + * @out_hopids; Output HopIDs for DMA tunneling + * @local_property_block: Local block of properties + * @local_property_block_gen: Generation of @local_property_block + * @local_property_block_len: Length of the @local_property_block in dwords + * @remote_properties: Properties exported by the remote domain + * @remote_property_block_gen: Generation of @remote_properties * @get_uuid_work: Work used to retrieve @remote_uuid * @uuid_retries: Number of times left @remote_uuid is requested before * giving up @@ -225,21 +227,23 @@ struct tb_xdomain { u64 route; u16 vendor; u16 device; + unsigned int local_max_hopid; + unsigned int remote_max_hopid; struct mutex lock; const char *vendor_name; const char *device_name; unsigned int link_speed; unsigned int link_width; bool is_unplugged; - bool resume; bool needs_uuid; - u16 transmit_path; - u16 transmit_ring; - u16 receive_path; - u16 receive_ring; struct ida service_ids; - struct tb_property_dir *properties; - u32 property_block_gen; + struct ida in_hopids; + struct ida out_hopids; + u32 *local_property_block; + u32 local_property_block_gen; + u32 local_property_block_len; + struct tb_property_dir *remote_properties; + u32 remote_property_block_gen; struct delayed_work get_uuid_work; int uuid_retries; struct delayed_work get_properties_work; @@ -252,10 +256,22 @@ struct tb_xdomain { int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd); void tb_xdomain_lane_bonding_disable(struct tb_xdomain *xd); -int tb_xdomain_enable_paths(struct tb_xdomain *xd, u16 transmit_path, - u16 transmit_ring, u16 receive_path, - u16 receive_ring); -int tb_xdomain_disable_paths(struct tb_xdomain *xd); +int tb_xdomain_alloc_in_hopid(struct tb_xdomain *xd, int hopid); +void tb_xdomain_release_in_hopid(struct tb_xdomain *xd, int hopid); +int tb_xdomain_alloc_out_hopid(struct tb_xdomain *xd, int hopid); +void tb_xdomain_release_out_hopid(struct tb_xdomain *xd, int hopid); +int tb_xdomain_enable_paths(struct tb_xdomain *xd, int transmit_path, + int transmit_ring, int receive_path, + int receive_ring); +int tb_xdomain_disable_paths(struct tb_xdomain *xd, int transmit_path, + int transmit_ring, int receive_path, + int receive_ring); + +static inline int tb_xdomain_disable_all_paths(struct tb_xdomain *xd) +{ + return tb_xdomain_disable_paths(xd, -1, -1, -1, -1); +} + struct tb_xdomain *tb_xdomain_find_by_uuid(struct tb *tb, const uuid_t *uuid); struct tb_xdomain *tb_xdomain_find_by_route(struct tb *tb, u64 route); diff --git a/include/linux/timecounter.h b/include/linux/timecounter.h index 754b74a2167feb7f1b12430882e7ad02faaa198e..c6540ceea14303151317627d3216d9f86a549341 100644 --- a/include/linux/timecounter.h +++ b/include/linux/timecounter.h @@ -124,7 +124,7 @@ extern u64 timecounter_read(struct timecounter *tc); * This allows conversion of cycle counter values which were generated * in the past. */ -extern u64 timecounter_cyc2time(struct timecounter *tc, +extern u64 timecounter_cyc2time(const struct timecounter *tc, u64 cycle_tstamp); #endif diff --git a/include/linux/timex.h b/include/linux/timex.h index 9c2e54faf9b71c677aa3de55bdc11334737f79d1..059b18eb1f1fab1c3af72b9369273a2782ba641d 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -133,7 +133,7 @@ /* * kernel variables - * Note: maximum error = NTP synch distance = dispersion + delay / 2; + * Note: maximum error = NTP sync distance = dispersion + delay / 2; * estimated error = NTP dispersion. */ extern unsigned long tick_usec; /* USER_HZ period (usec) */ diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 543aa3b1dedc0766fe52b956b3149e724f51bdaf..aa11fe323c56b5d86a7d66095a826cf0e4cf1c57 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -305,6 +305,8 @@ struct tpm_buf { }; enum tpm2_object_attributes { + TPM2_OA_FIXED_TPM = BIT(1), + TPM2_OA_FIXED_PARENT = BIT(4), TPM2_OA_USER_WITH_AUTH = BIT(6), }; diff --git a/include/linux/tty.h b/include/linux/tty.h index 95fc2f100f12d591e836ecb778672f4478d39c93..e5d6b1f288235506280bc0c1b0f9cb38321ae906 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -16,30 +16,6 @@ #include <linux/llist.h> -/* - * Lock subclasses for tty locks - * - * TTY_LOCK_NORMAL is for normal ttys and master ptys. - * TTY_LOCK_SLAVE is for slave ptys only. - * - * Lock subclasses are necessary for handling nested locking with pty pairs. - * tty locks which use nested locking: - * - * legacy_mutex - Nested tty locks are necessary for releasing pty pairs. - * The stable lock order is master pty first, then slave pty. - * termios_rwsem - The stable lock order is tty_buffer lock->termios_rwsem. - * Subclassing this lock enables the slave pty to hold its - * termios_rwsem when claiming the master tty_buffer lock. - * tty_buffer lock - slave ptys can claim nested buffer lock when handling - * signal chars. The stable lock order is slave pty, then - * master. - */ - -enum { - TTY_LOCK_NORMAL = 0, - TTY_LOCK_SLAVE, -}; - /* * (Note: the *_driver.minor_start values 1, 64, 128, 192 are * hardcoded at present.) @@ -284,7 +260,7 @@ struct tty_operations; struct tty_struct { int magic; struct kref kref; - struct device *dev; + struct device *dev; /* class device or NULL (e.g. ptys, serdev) */ struct tty_driver *driver; const struct tty_operations *ops; int index; @@ -373,21 +349,6 @@ struct tty_file_private { #define TTY_LDISC_CHANGING 20 /* Change pending - non-block IO */ #define TTY_LDISC_HALTED 22 /* Line discipline is halted */ -/* Values for tty->flow_change */ -#define TTY_THROTTLE_SAFE 1 -#define TTY_UNTHROTTLE_SAFE 2 - -static inline void __tty_set_flow_change(struct tty_struct *tty, int val) -{ - tty->flow_change = val; -} - -static inline void tty_set_flow_change(struct tty_struct *tty, int val) -{ - tty->flow_change = val; - smp_mb(); -} - static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file) { return file->f_flags & O_NONBLOCK || @@ -419,10 +380,6 @@ extern struct tty_struct *tty_kopen_exclusive(dev_t device); extern struct tty_struct *tty_kopen_shared(dev_t device); extern void tty_kclose(struct tty_struct *tty); extern int tty_dev_name_to_number(const char *name, dev_t *number); -extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout); -extern void tty_ldisc_unlock(struct tty_struct *tty); -extern ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *); -extern struct file *tty_release_redirect(struct tty_struct *tty); #else static inline void tty_kref_put(struct tty_struct *tty) { } @@ -475,14 +432,10 @@ static inline struct tty_struct *tty_kref_get(struct tty_struct *tty) extern const char *tty_driver_name(const struct tty_struct *tty); extern void tty_wait_until_sent(struct tty_struct *tty, long timeout); -extern int __tty_check_change(struct tty_struct *tty, int sig); -extern int tty_check_change(struct tty_struct *tty); -extern void __stop_tty(struct tty_struct *tty); extern void stop_tty(struct tty_struct *tty); -extern void __start_tty(struct tty_struct *tty); extern void start_tty(struct tty_struct *tty); extern int tty_register_driver(struct tty_driver *driver); -extern int tty_unregister_driver(struct tty_driver *driver); +extern void tty_unregister_driver(struct tty_driver *driver); extern struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); extern struct device *tty_register_device_attr(struct tty_driver *driver, @@ -506,23 +459,11 @@ extern int tty_get_icount(struct tty_struct *tty, extern int is_current_pgrp_orphaned(void); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); -extern void tty_vhangup_session(struct tty_struct *tty); extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); extern void __do_SAK(struct tty_struct *tty); -extern void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty); -extern int tty_signal_session_leader(struct tty_struct *tty, int exit_session); -extern void session_clear_tty(struct pid *session); extern void no_tty(void); -extern void tty_buffer_free_all(struct tty_port *port); -extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); -extern void tty_buffer_init(struct tty_port *port); -extern void tty_buffer_set_lock_subclass(struct tty_port *port); -extern bool tty_buffer_restart_work(struct tty_port *port); -extern bool tty_buffer_cancel_work(struct tty_port *port); -extern void tty_buffer_flush_work(struct tty_port *port); extern speed_t tty_termios_baud_rate(struct ktermios *termios); -extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); extern void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud); extern void tty_encode_baud_rate(struct tty_struct *tty, @@ -550,27 +491,16 @@ extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); extern void tty_ldisc_deref(struct tty_ldisc *); extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); -extern void tty_ldisc_hangup(struct tty_struct *tty, bool reset); -extern int tty_ldisc_reinit(struct tty_struct *tty, int disc); extern const struct seq_operations tty_ldiscs_seq_ops; extern void tty_wakeup(struct tty_struct *tty); extern void tty_ldisc_flush(struct tty_struct *tty); -extern long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -extern long tty_jobctrl_ioctl(struct tty_struct *tty, struct tty_struct *real_tty, - struct file *file, unsigned int cmd, unsigned long arg); extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); -extern void tty_default_fops(struct file_operations *fops); -extern struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx); -extern int tty_alloc_file(struct file *file); -extern void tty_add_file(struct tty_struct *tty, struct file *file); -extern void tty_free_file(struct file *file); extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern void tty_release_struct(struct tty_struct *tty, int idx); -extern int tty_release(struct inode *inode, struct file *filp); extern void tty_init_termios(struct tty_struct *tty); extern void tty_save_termios(struct tty_struct *tty); extern int tty_standard_install(struct tty_driver *driver, @@ -578,8 +508,6 @@ extern int tty_standard_install(struct tty_driver *driver, extern struct mutex tty_mutex; -#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) - extern void tty_port_init(struct tty_port *port); extern void tty_port_link_device(struct tty_port *port, struct tty_driver *driver, unsigned index); @@ -699,13 +627,8 @@ static inline int tty_port_users(struct tty_port *port) extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_set_ldisc(struct tty_struct *tty, int disc); -extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); -extern void tty_ldisc_release(struct tty_struct *tty); -extern int __must_check tty_ldisc_init(struct tty_struct *tty); -extern void tty_ldisc_deinit(struct tty_struct *tty); extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, char *f, int count); -extern void tty_sysctl_init(void); /* n_tty.c */ extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops); @@ -717,20 +640,10 @@ static inline void n_tty_init(void) { } /* tty_audit.c */ #ifdef CONFIG_AUDIT -extern void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size); extern void tty_audit_exit(void); extern void tty_audit_fork(struct signal_struct *sig); -extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); extern int tty_audit_push(void); #else -static inline void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size) -{ -} -static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch) -{ -} static inline void tty_audit_exit(void) { } @@ -772,16 +685,4 @@ static inline void proc_tty_register_driver(struct tty_driver *d) {} static inline void proc_tty_unregister_driver(struct tty_driver *d) {} #endif -#define tty_msg(fn, tty, f, ...) \ - fn("%s %s: " f, tty_driver_name(tty), tty_name(tty), ##__VA_ARGS__) - -#define tty_debug(tty, f, ...) tty_msg(pr_debug, tty, f, ##__VA_ARGS__) -#define tty_info(tty, f, ...) tty_msg(pr_info, tty, f, ##__VA_ARGS__) -#define tty_notice(tty, f, ...) tty_msg(pr_notice, tty, f, ##__VA_ARGS__) -#define tty_warn(tty, f, ...) tty_msg(pr_warn, tty, f, ##__VA_ARGS__) -#define tty_err(tty, f, ...) tty_msg(pr_err, tty, f, ##__VA_ARGS__) - -#define tty_info_ratelimited(tty, f, ...) \ - tty_msg(pr_info_ratelimited, tty, f, ##__VA_ARGS__) - #endif diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 61c3372d3f32871f9e843933ce3cb775346ac323..2f719b471d5248b90ee390c804156813a2a1fbeb 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -228,7 +228,7 @@ * * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel * structure to complete. This method is optional and will only be called - * if provided (otherwise EINVAL will be returned). + * if provided (otherwise ENOTTY will be returned). */ #include <linux/export.h> diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 572a0797611659d25ebcfe9f5966adc4523b28b2..31284b55bd4f148953c43c243caebb44509d4899 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -173,7 +173,6 @@ extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, struct tty_ldisc_ops { - int magic; char *name; int num; int flags; @@ -218,8 +217,6 @@ struct tty_ldisc { struct tty_struct *tty; }; -#define TTY_LDISC_MAGIC 0x5403 - #define LDISC_FLAG_DEFINED 0x00000001 #define MODULE_ALIAS_LDISC(ldisc) \ diff --git a/include/linux/uio.h b/include/linux/uio.h index 27ff8eb786dc34817ac875f780b478c2b93a758f..d3ec87706d757331dd2db52ba9c8d52d96fb0f02 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -24,6 +24,7 @@ enum iter_type { ITER_BVEC = 16, ITER_PIPE = 32, ITER_DISCARD = 64, + ITER_XARRAY = 128, }; struct iov_iter { @@ -39,6 +40,7 @@ struct iov_iter { const struct iovec *iov; const struct kvec *kvec; const struct bio_vec *bvec; + struct xarray *xarray; struct pipe_inode_info *pipe; }; union { @@ -47,6 +49,7 @@ struct iov_iter { unsigned int head; unsigned int start_head; }; + loff_t xarray_start; }; }; @@ -80,6 +83,11 @@ static inline bool iov_iter_is_discard(const struct iov_iter *i) return iov_iter_type(i) == ITER_DISCARD; } +static inline bool iov_iter_is_xarray(const struct iov_iter *i) +{ + return iov_iter_type(i) == ITER_XARRAY; +} + static inline unsigned char iov_iter_rw(const struct iov_iter *i) { return i->type & (READ | WRITE); @@ -221,6 +229,8 @@ void iov_iter_bvec(struct iov_iter *i, unsigned int direction, const struct bio_ void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode_info *pipe, size_t count); void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count); +void iov_iter_xarray(struct iov_iter *i, unsigned int direction, struct xarray *xarray, + loff_t start, size_t count); ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, size_t maxsize, unsigned maxpages, size_t *start); ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, diff --git a/include/linux/usb.h b/include/linux/usb.h index d6a41841b93e4f92647e938d0bff02712b795f12..eaae24217e8a2ebc7b88bd5a794e7dc30d61f4f0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -560,6 +560,7 @@ struct usb3_lpm_parameters { * @speed: device speed: high/full/low (or error) * @rx_lanes: number of rx lanes in use, USB 3.2 adds dual-lane support * @tx_lanes: number of tx lanes in use, USB 3.2 adds dual-lane support + * @ssp_rate: SuperSpeed Plus phy signaling rate and lane count * @tt: Transaction Translator info; used with low/full speed dev, highspeed hub * @ttport: device port on that tt hub * @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints @@ -636,6 +637,7 @@ struct usb_device { enum usb_device_speed speed; unsigned int rx_lanes; unsigned int tx_lanes; + enum usb_ssp_rate ssp_rate; struct usb_tt *tt; int ttport; @@ -841,7 +843,7 @@ extern int usb_free_streams(struct usb_interface *interface, /* used these for multi-interface device registration */ extern int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void *priv); + struct usb_interface *iface, void *data); /** * usb_interface_claimed - returns true iff an interface is claimed @@ -880,6 +882,15 @@ extern struct usb_host_interface *usb_find_alt_setting( unsigned int iface_num, unsigned int alt_num); +#if IS_REACHABLE(CONFIG_USB) +int usb_for_each_port(void *data, int (*fn)(struct device *, void *)); +#else +static inline int usb_for_each_port(void *data, int (*fn)(struct device *, void *)) +{ + return 0; +} +#endif + /* port claiming functions */ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, struct usb_dev_state *owner); @@ -1259,8 +1270,6 @@ struct usb_device_driver { #define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \ drvwrap.driver) -extern struct bus_type usb_bus_type; - /** * struct usb_class_driver - identifies a USB driver that wants to use the USB major number * @name: the usb class device name for this driver. Will show up in sysfs. diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index abdd310c77f053cd0a8e4143ad126fa591d9927a..1cffa34740b00caba347b2b44fb8b78e081669a4 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -45,73 +45,15 @@ enum usb_ssp_rate { USB_SSP_GEN_2x2, }; -/** - * usb_ep_type_string() - Returns human readable-name of the endpoint type. - * @ep_type: The endpoint type to return human-readable name for. If it's not - * any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}, - * usually got by usb_endpoint_type(), the string 'unknown' will be returned. - */ extern const char *usb_ep_type_string(int ep_type); - -/** - * usb_speed_string() - Returns human readable-name of the speed. - * @speed: The speed to return human-readable name for. If it's not - * any of the speeds defined in usb_device_speed enum, string for - * USB_SPEED_UNKNOWN will be returned. - */ extern const char *usb_speed_string(enum usb_device_speed speed); - -/** - * usb_get_maximum_speed - Get maximum requested speed for a given USB - * controller. - * @dev: Pointer to the given USB controller device - * - * The function gets the maximum speed string from property "maximum-speed", - * and returns the corresponding enum usb_device_speed. - */ extern enum usb_device_speed usb_get_maximum_speed(struct device *dev); - -/** - * usb_get_maximum_ssp_rate - Get the signaling rate generation and lane count - * of a SuperSpeed Plus capable device. - * @dev: Pointer to the given USB controller device - * - * If the string from "maximum-speed" property is super-speed-plus-genXxY where - * 'X' is the generation number and 'Y' is the number of lanes, then this - * function returns the corresponding enum usb_ssp_rate. - */ extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev); - -/** - * usb_state_string - Returns human readable name for the state. - * @state: The state to return a human-readable name for. If it's not - * any of the states devices in usb_device_state_string enum, - * the string UNKNOWN will be returned. - */ extern const char *usb_state_string(enum usb_device_state state); +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd, + enum usb_device_speed speed); #ifdef CONFIG_TRACING -/** - * usb_decode_ctrl - Returns human readable representation of control request. - * @str: buffer to return a human-readable representation of control request. - * This buffer should have about 200 bytes. - * @size: size of str buffer. - * @bRequestType: matches the USB bmRequestType field - * @bRequest: matches the USB bRequest field - * @wValue: matches the USB wValue field (CPU byte order) - * @wIndex: matches the USB wIndex field (CPU byte order) - * @wLength: matches the USB wLength field (CPU byte order) - * - * Function returns decoded, formatted and human-readable description of - * control request packet. - * - * The usage scenario for this is for tracepoints, so function as a return - * use the same value as in parameters. This approach allows to use this - * function in TP_printk - * - * Important: wValue, wIndex, wLength parameters before invoking this function - * should be processed by le16_to_cpu macro. - */ extern const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength); diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h index dd742afdc03fa8a84959fc006020e0aef8b42064..89fc901e778fd8baf22030e1cdb9a6031ab1d3d2 100644 --- a/include/linux/usb/ehci_pdriver.h +++ b/include/linux/usb/ehci_pdriver.h @@ -50,6 +50,7 @@ struct usb_ehci_pdata { unsigned no_io_watchdog:1; unsigned reset_on_resume:1; unsigned dma_mask_64:1; + unsigned spurious_oc:1; /* Turn on all power and clocks */ int (*power_on)(struct platform_device *pdev); diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index 70d681918d013463d5a669a54a57759bce311ed4..bf00259493e077f1198a055cc082fbaa0b23617f 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -493,4 +493,6 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP) #define PD_N_HARD_RESET_COUNT 2 +#define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */ + #endif /* __LINUX_USB_PD_H */ diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 952272002e4870683b4374e13e2e20633be08215..8c63fa9bfc746478e0174ca0b24f76695e07354f 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -130,6 +130,8 @@ static inline void usb_set_serial_port_data(struct usb_serial_port *port, * @dev: pointer to the struct usb_device for this device * @type: pointer to the struct usb_serial_driver for this device * @interface: pointer to the struct usb_interface for this device + * @sibling: pointer to the struct usb_interface of any sibling interface + * @suspend_count: number of suspended (sibling) interfaces * @num_ports: the number of ports this device has * @num_interrupt_in: number of interrupt in endpoints we have * @num_interrupt_out: number of interrupt out endpoints we have @@ -145,8 +147,9 @@ struct usb_serial { struct usb_device *dev; struct usb_serial_driver *type; struct usb_interface *interface; + struct usb_interface *sibling; + unsigned int suspend_count; unsigned char disconnected:1; - unsigned char suspending:1; unsigned char attached:1; unsigned char minors_reserved:1; unsigned char num_ports; @@ -276,7 +279,7 @@ struct usb_serial_driver { int (*write_room)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); - int (*get_serial)(struct tty_struct *tty, struct serial_struct *ss); + void (*get_serial)(struct tty_struct *tty, struct serial_struct *ss); int (*set_serial)(struct tty_struct *tty, struct serial_struct *ss); void (*set_termios)(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); @@ -335,6 +338,9 @@ static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} /* Functions needed by other parts of the usbserial core */ struct usb_serial_port *usb_serial_port_get_by_minor(unsigned int minor); void usb_serial_put(struct usb_serial *serial); + +int usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf); + int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port); int usb_serial_generic_write_start(struct usb_serial_port *port, gfp_t mem_flags); int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index 91b4303ca305ca41187417f84ef7f66ad64e1d38..e2e44bb1dad856789cfd6f6a663f5136afa6ba14 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -17,6 +17,7 @@ struct typec_partner; struct typec_cable; struct typec_plug; struct typec_port; +struct typec_altmode_ops; struct fwnode_handle; struct device; @@ -138,6 +139,11 @@ struct typec_altmode struct typec_altmode *typec_port_register_altmode(struct typec_port *port, const struct typec_altmode_desc *desc); + +void typec_port_register_altmodes(struct typec_port *port, + const struct typec_altmode_ops *ops, void *drvdata, + struct typec_altmode **altmodes, size_t n); + void typec_unregister_altmode(struct typec_altmode *altmode); struct typec_port *typec_altmode2port(struct typec_altmode *alt); @@ -298,4 +304,17 @@ int typec_find_port_data_role(const char *name); void typec_partner_set_svdm_version(struct typec_partner *partner, enum usb_pd_svdm_ver svdm_version); int typec_get_negotiated_svdm_version(struct typec_port *port); + +#if IS_REACHABLE(CONFIG_TYPEC) +int typec_link_port(struct device *port); +void typec_unlink_port(struct device *port); +#else +static inline int typec_link_port(struct device *port) +{ + return 0; +} + +static inline void typec_unlink_port(struct device *port) { } +#endif + #endif /* __LINUX_USB_TYPEC_H */ diff --git a/include/linux/wmi.h b/include/linux/wmi.h index 8ef7e7faea1e2d438dc607051ba1cdefc1fc310a..2cb3913c1f5061bdaa2d2bcca5d9950c23a00a40 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -37,7 +37,7 @@ struct wmi_driver { const struct wmi_device_id *id_table; int (*probe)(struct wmi_device *wdev, const void *context); - int (*remove)(struct wmi_device *wdev); + void (*remove)(struct wmi_device *wdev); void (*notify)(struct wmi_device *device, union acpi_object *data); long (*filter_callback)(struct wmi_device *wdev, unsigned int cmd, struct wmi_ioctl_buffer *arg); diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index f6abcc0bbd6e7686c24d081c72693bc15b359bad..cee5f83c0f11a1c581951cd66ca6e69f8e0fb613 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -53,7 +53,7 @@ int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *, struct msghdr *, size_t, rxrpc_notify_end_tx_t); int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *, - struct iov_iter *, bool, u32 *, u16 *); + struct iov_iter *, size_t *, bool, u32 *, u16 *); bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, u32, int, const char *); void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *); diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 43c9c5d2bedbdaf1d1f593a527781b4cc9d6a480..bd76e8e082c0179b3c27b7393ff678909d62de07 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -430,8 +430,6 @@ struct nci_uart_ops { int (*open)(struct nci_uart *nci_uart); void (*close)(struct nci_uart *nci_uart); int (*recv)(struct nci_uart *nci_uart, struct sk_buff *skb); - int (*recv_buf)(struct nci_uart *nci_uart, const u8 *data, char *flags, - int count); int (*send)(struct nci_uart *nci_uart, struct sk_buff *skb); void (*tx_start)(struct nci_uart *nci_uart); void (*tx_done)(struct nci_uart *nci_uart); diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 2568cb0627ec0b388aa100391179993b603c2784..fac8e89aed81dadf8b16fc058fae71f3b29c9fe4 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -249,7 +249,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *, struct fc_frame *); /* libfcoe funcs */ -u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int); +u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], unsigned int, unsigned int); int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *, const struct libfc_function_template *, int init_fcp); u32 fcoe_fc_crc(struct fc_frame *fp); diff --git a/include/soc/at91/pm.h b/include/soc/at91/pm.h new file mode 100644 index 0000000000000000000000000000000000000000..7a41e53a3ffa3e90c7ddee987db670587ec1284a --- /dev/null +++ b/include/soc/at91/pm.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Atmel Power Management + * + * Copyright (C) 2020 Atmel + * + * Author: Lee Jones <lee.jones@linaro.org> + */ + +#ifndef __SOC_ATMEL_PM_H +#define __SOC_ATMEL_PM_H + +void at91_pinctrl_gpio_suspend(void); +void at91_pinctrl_gpio_resume(void); + +#endif /* __SOC_ATMEL_PM_H */ diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index cc9cdbc66403fbb3a45a4b4d39602d9c7bcdeaa2..73ad784fca9666558e14bcc40d4cb8c4f6257d07 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -140,7 +140,10 @@ int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); +void rpi_firmware_put(struct rpi_firmware *fw); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) @@ -154,10 +157,17 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw, return -ENOSYS; } +static inline void rpi_firmware_put(struct rpi_firmware *fw) { } static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { return NULL; } + +static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + return NULL; +} #endif #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index 4925a1b59dc9ce030a004200b5fd078f0161926f..b02e9fe69146a44a91c44027b998a75b5d382ad5 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -239,37 +239,21 @@ static inline int qe_alive_during_sleep(void) #define qe_muram_dma cpm_muram_dma #define qe_muram_free_addr cpm_muram_free_addr -#ifdef CONFIG_PPC32 -#define qe_iowrite8(val, addr) out_8(addr, val) -#define qe_iowrite16be(val, addr) out_be16(addr, val) -#define qe_iowrite32be(val, addr) out_be32(addr, val) -#define qe_ioread8(addr) in_8(addr) -#define qe_ioread16be(addr) in_be16(addr) -#define qe_ioread32be(addr) in_be32(addr) -#else -#define qe_iowrite8(val, addr) iowrite8(val, addr) -#define qe_iowrite16be(val, addr) iowrite16be(val, addr) -#define qe_iowrite32be(val, addr) iowrite32be(val, addr) -#define qe_ioread8(addr) ioread8(addr) -#define qe_ioread16be(addr) ioread16be(addr) -#define qe_ioread32be(addr) ioread32be(addr) -#endif - -#define qe_setbits_be32(_addr, _v) qe_iowrite32be(qe_ioread32be(_addr) | (_v), (_addr)) -#define qe_clrbits_be32(_addr, _v) qe_iowrite32be(qe_ioread32be(_addr) & ~(_v), (_addr)) +#define qe_setbits_be32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr)) +#define qe_clrbits_be32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr)) -#define qe_setbits_be16(_addr, _v) qe_iowrite16be(qe_ioread16be(_addr) | (_v), (_addr)) -#define qe_clrbits_be16(_addr, _v) qe_iowrite16be(qe_ioread16be(_addr) & ~(_v), (_addr)) +#define qe_setbits_be16(_addr, _v) iowrite16be(ioread16be(_addr) | (_v), (_addr)) +#define qe_clrbits_be16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr)) -#define qe_setbits_8(_addr, _v) qe_iowrite8(qe_ioread8(_addr) | (_v), (_addr)) -#define qe_clrbits_8(_addr, _v) qe_iowrite8(qe_ioread8(_addr) & ~(_v), (_addr)) +#define qe_setbits_8(_addr, _v) iowrite8(ioread8(_addr) | (_v), (_addr)) +#define qe_clrbits_8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr)) #define qe_clrsetbits_be32(addr, clear, set) \ - qe_iowrite32be((qe_ioread32be(addr) & ~(clear)) | (set), (addr)) + iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr)) #define qe_clrsetbits_be16(addr, clear, set) \ - qe_iowrite16be((qe_ioread16be(addr) & ~(clear)) | (set), (addr)) + iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr)) #define qe_clrsetbits_8(addr, clear, set) \ - qe_iowrite8((qe_ioread8(addr) & ~(clear)) | (set), (addr)) + iowrite8((ioread8(addr) & ~(clear)) | (set), (addr)) /* Structure that defines QE firmware binary files. * diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index d731407e23bb4105aaae098c76eb170dcfc9fb93..d2fbe6a8b25bd2788386d54386492e2ef80787f9 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -7,6 +7,7 @@ #define __SOC_TEGRA_MC_H__ #include <linux/bits.h> +#include <linux/debugfs.h> #include <linux/err.h> #include <linux/interconnect-provider.h> #include <linux/reset-controller.h> @@ -175,6 +176,8 @@ struct tegra_mc_soc { unsigned int num_resets; const struct tegra_mc_icc_ops *icc_ops; + + int (*init)(struct tegra_mc *mc); }; struct tegra_mc { @@ -196,6 +199,10 @@ struct tegra_mc { struct icc_provider provider; spinlock_t lock; + + struct { + struct dentry *root; + } debugfs; }; int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate); diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 4a5cc8c64be3470b3ecf18b6d7aec66233089f07..3ccf591b2374064915cea8447dd8d02192e243ff 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -886,65 +886,52 @@ TRACE_EVENT(afs_call_done, __entry->rx_call) ); -TRACE_EVENT(afs_send_pages, - TP_PROTO(struct afs_call *call, struct msghdr *msg, - pgoff_t first, pgoff_t last, unsigned int offset), +TRACE_EVENT(afs_send_data, + TP_PROTO(struct afs_call *call, struct msghdr *msg), - TP_ARGS(call, msg, first, last, offset), + TP_ARGS(call, msg), TP_STRUCT__entry( __field(unsigned int, call ) - __field(pgoff_t, first ) - __field(pgoff_t, last ) - __field(unsigned int, nr ) - __field(unsigned int, bytes ) - __field(unsigned int, offset ) __field(unsigned int, flags ) + __field(loff_t, offset ) + __field(loff_t, count ) ), TP_fast_assign( __entry->call = call->debug_id; - __entry->first = first; - __entry->last = last; - __entry->nr = msg->msg_iter.nr_segs; - __entry->bytes = msg->msg_iter.count; - __entry->offset = offset; __entry->flags = msg->msg_flags; + __entry->offset = msg->msg_iter.xarray_start + msg->msg_iter.iov_offset; + __entry->count = iov_iter_count(&msg->msg_iter); ), - TP_printk(" c=%08x %lx-%lx-%lx b=%x o=%x f=%x", - __entry->call, - __entry->first, __entry->first + __entry->nr - 1, __entry->last, - __entry->bytes, __entry->offset, + TP_printk(" c=%08x o=%llx n=%llx f=%x", + __entry->call, __entry->offset, __entry->count, __entry->flags) ); -TRACE_EVENT(afs_sent_pages, - TP_PROTO(struct afs_call *call, pgoff_t first, pgoff_t last, - pgoff_t cursor, int ret), +TRACE_EVENT(afs_sent_data, + TP_PROTO(struct afs_call *call, struct msghdr *msg, int ret), - TP_ARGS(call, first, last, cursor, ret), + TP_ARGS(call, msg, ret), TP_STRUCT__entry( __field(unsigned int, call ) - __field(pgoff_t, first ) - __field(pgoff_t, last ) - __field(pgoff_t, cursor ) __field(int, ret ) + __field(loff_t, offset ) + __field(loff_t, count ) ), TP_fast_assign( __entry->call = call->debug_id; - __entry->first = first; - __entry->last = last; - __entry->cursor = cursor; __entry->ret = ret; + __entry->offset = msg->msg_iter.xarray_start + msg->msg_iter.iov_offset; + __entry->count = iov_iter_count(&msg->msg_iter); ), - TP_printk(" c=%08x %lx-%lx c=%lx r=%d", - __entry->call, - __entry->first, __entry->last, - __entry->cursor, __entry->ret) + TP_printk(" c=%08x o=%llx n=%llx r=%x", + __entry->call, __entry->offset, __entry->count, + __entry->ret) ); TRACE_EVENT(afs_dir_check_failed, @@ -969,30 +956,33 @@ TRACE_EVENT(afs_dir_check_failed, ); TRACE_EVENT(afs_page_dirty, - TP_PROTO(struct afs_vnode *vnode, const char *where, - pgoff_t page, unsigned long priv), + TP_PROTO(struct afs_vnode *vnode, const char *where, struct page *page), - TP_ARGS(vnode, where, page, priv), + TP_ARGS(vnode, where, page), TP_STRUCT__entry( __field(struct afs_vnode *, vnode ) __field(const char *, where ) __field(pgoff_t, page ) - __field(unsigned long, priv ) + __field(unsigned long, from ) + __field(unsigned long, to ) ), TP_fast_assign( __entry->vnode = vnode; __entry->where = where; - __entry->page = page; - __entry->priv = priv; + __entry->page = page->index; + __entry->from = afs_page_dirty_from(page, page->private); + __entry->to = afs_page_dirty_to(page, page->private); + __entry->to |= (afs_is_page_dirty_mmapped(page->private) ? + (1UL << (BITS_PER_LONG - 1)) : 0); ), - TP_printk("vn=%p %lx %s %zx-%zx%s", + TP_printk("vn=%p %lx %s %lx-%lx%s", __entry->vnode, __entry->page, __entry->where, - afs_page_dirty_from(__entry->priv), - afs_page_dirty_to(__entry->priv), - afs_is_page_dirty_mmapped(__entry->priv) ? " M" : "") + __entry->from, + __entry->to & ~(1UL << (BITS_PER_LONG - 1)), + __entry->to & (1UL << (BITS_PER_LONG - 1)) ? " M" : "") ); TRACE_EVENT(afs_call_state, diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 0551ea65374fd0a1ed93300984e85ccc7b2e0f95..a41dd8a0c7302b08ba42f886dec2a79aae99ac4c 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -1903,6 +1903,18 @@ DEFINE_EVENT(btrfs__block_group, btrfs_add_unused_block_group, TP_ARGS(bg_cache) ); +DEFINE_EVENT(btrfs__block_group, btrfs_add_reclaim_block_group, + TP_PROTO(const struct btrfs_block_group *bg_cache), + + TP_ARGS(bg_cache) +); + +DEFINE_EVENT(btrfs__block_group, btrfs_reclaim_block_group, + TP_PROTO(const struct btrfs_block_group *bg_cache), + + TP_ARGS(bg_cache) +); + DEFINE_EVENT(btrfs__block_group, btrfs_skip_unused_block_group, TP_PROTO(const struct btrfs_block_group *bg_cache), diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h new file mode 100644 index 0000000000000000000000000000000000000000..de1c64635e42b4e9d28f820d306f9cd1158d77ab --- /dev/null +++ b/include/trace/events/netfs.h @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Network filesystem support module tracepoints + * + * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM netfs + +#if !defined(_TRACE_NETFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_NETFS_H + +#include <linux/tracepoint.h> + +/* + * Define enums for tracing information. + */ +#ifndef __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY +#define __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY + +enum netfs_read_trace { + netfs_read_trace_expanded, + netfs_read_trace_readahead, + netfs_read_trace_readpage, + netfs_read_trace_write_begin, +}; + +enum netfs_rreq_trace { + netfs_rreq_trace_assess, + netfs_rreq_trace_done, + netfs_rreq_trace_free, + netfs_rreq_trace_resubmit, + netfs_rreq_trace_unlock, + netfs_rreq_trace_unmark, + netfs_rreq_trace_write, +}; + +enum netfs_sreq_trace { + netfs_sreq_trace_download_instead, + netfs_sreq_trace_free, + netfs_sreq_trace_prepare, + netfs_sreq_trace_resubmit_short, + netfs_sreq_trace_submit, + netfs_sreq_trace_terminated, + netfs_sreq_trace_write, + netfs_sreq_trace_write_skip, + netfs_sreq_trace_write_term, +}; + +enum netfs_failure { + netfs_fail_check_write_begin, + netfs_fail_copy_to_cache, + netfs_fail_read, + netfs_fail_short_readpage, + netfs_fail_short_write_begin, + netfs_fail_prepare_write, +}; + +#endif + +#define netfs_read_traces \ + EM(netfs_read_trace_expanded, "EXPANDED ") \ + EM(netfs_read_trace_readahead, "READAHEAD") \ + EM(netfs_read_trace_readpage, "READPAGE ") \ + E_(netfs_read_trace_write_begin, "WRITEBEGN") + +#define netfs_rreq_traces \ + EM(netfs_rreq_trace_assess, "ASSESS") \ + EM(netfs_rreq_trace_done, "DONE ") \ + EM(netfs_rreq_trace_free, "FREE ") \ + EM(netfs_rreq_trace_resubmit, "RESUBM") \ + EM(netfs_rreq_trace_unlock, "UNLOCK") \ + EM(netfs_rreq_trace_unmark, "UNMARK") \ + E_(netfs_rreq_trace_write, "WRITE ") + +#define netfs_sreq_sources \ + EM(NETFS_FILL_WITH_ZEROES, "ZERO") \ + EM(NETFS_DOWNLOAD_FROM_SERVER, "DOWN") \ + EM(NETFS_READ_FROM_CACHE, "READ") \ + E_(NETFS_INVALID_READ, "INVL") \ + +#define netfs_sreq_traces \ + EM(netfs_sreq_trace_download_instead, "RDOWN") \ + EM(netfs_sreq_trace_free, "FREE ") \ + EM(netfs_sreq_trace_prepare, "PREP ") \ + EM(netfs_sreq_trace_resubmit_short, "SHORT") \ + EM(netfs_sreq_trace_submit, "SUBMT") \ + EM(netfs_sreq_trace_terminated, "TERM ") \ + EM(netfs_sreq_trace_write, "WRITE") \ + EM(netfs_sreq_trace_write_skip, "SKIP ") \ + E_(netfs_sreq_trace_write_term, "WTERM") + +#define netfs_failures \ + EM(netfs_fail_check_write_begin, "check-write-begin") \ + EM(netfs_fail_copy_to_cache, "copy-to-cache") \ + EM(netfs_fail_read, "read") \ + EM(netfs_fail_short_readpage, "short-readpage") \ + EM(netfs_fail_short_write_begin, "short-write-begin") \ + E_(netfs_fail_prepare_write, "prep-write") + + +/* + * Export enum symbols via userspace. + */ +#undef EM +#undef E_ +#define EM(a, b) TRACE_DEFINE_ENUM(a); +#define E_(a, b) TRACE_DEFINE_ENUM(a); + +netfs_read_traces; +netfs_rreq_traces; +netfs_sreq_sources; +netfs_sreq_traces; +netfs_failures; + +/* + * Now redefine the EM() and E_() macros to map the enums to the strings that + * will be printed in the output. + */ +#undef EM +#undef E_ +#define EM(a, b) { a, b }, +#define E_(a, b) { a, b } + +TRACE_EVENT(netfs_read, + TP_PROTO(struct netfs_read_request *rreq, + loff_t start, size_t len, + enum netfs_read_trace what), + + TP_ARGS(rreq, start, len, what), + + TP_STRUCT__entry( + __field(unsigned int, rreq ) + __field(unsigned int, cookie ) + __field(loff_t, start ) + __field(size_t, len ) + __field(enum netfs_read_trace, what ) + ), + + TP_fast_assign( + __entry->rreq = rreq->debug_id; + __entry->cookie = rreq->cookie_debug_id; + __entry->start = start; + __entry->len = len; + __entry->what = what; + ), + + TP_printk("R=%08x %s c=%08x s=%llx %zx", + __entry->rreq, + __print_symbolic(__entry->what, netfs_read_traces), + __entry->cookie, + __entry->start, __entry->len) + ); + +TRACE_EVENT(netfs_rreq, + TP_PROTO(struct netfs_read_request *rreq, + enum netfs_rreq_trace what), + + TP_ARGS(rreq, what), + + TP_STRUCT__entry( + __field(unsigned int, rreq ) + __field(unsigned short, flags ) + __field(enum netfs_rreq_trace, what ) + ), + + TP_fast_assign( + __entry->rreq = rreq->debug_id; + __entry->flags = rreq->flags; + __entry->what = what; + ), + + TP_printk("R=%08x %s f=%02x", + __entry->rreq, + __print_symbolic(__entry->what, netfs_rreq_traces), + __entry->flags) + ); + +TRACE_EVENT(netfs_sreq, + TP_PROTO(struct netfs_read_subrequest *sreq, + enum netfs_sreq_trace what), + + TP_ARGS(sreq, what), + + TP_STRUCT__entry( + __field(unsigned int, rreq ) + __field(unsigned short, index ) + __field(short, error ) + __field(unsigned short, flags ) + __field(enum netfs_read_source, source ) + __field(enum netfs_sreq_trace, what ) + __field(size_t, len ) + __field(size_t, transferred ) + __field(loff_t, start ) + ), + + TP_fast_assign( + __entry->rreq = sreq->rreq->debug_id; + __entry->index = sreq->debug_index; + __entry->error = sreq->error; + __entry->flags = sreq->flags; + __entry->source = sreq->source; + __entry->what = what; + __entry->len = sreq->len; + __entry->transferred = sreq->transferred; + __entry->start = sreq->start; + ), + + TP_printk("R=%08x[%u] %s %s f=%02x s=%llx %zx/%zx e=%d", + __entry->rreq, __entry->index, + __print_symbolic(__entry->what, netfs_sreq_traces), + __print_symbolic(__entry->source, netfs_sreq_sources), + __entry->flags, + __entry->start, __entry->transferred, __entry->len, + __entry->error) + ); + +TRACE_EVENT(netfs_failure, + TP_PROTO(struct netfs_read_request *rreq, + struct netfs_read_subrequest *sreq, + int error, enum netfs_failure what), + + TP_ARGS(rreq, sreq, error, what), + + TP_STRUCT__entry( + __field(unsigned int, rreq ) + __field(unsigned short, index ) + __field(short, error ) + __field(unsigned short, flags ) + __field(enum netfs_read_source, source ) + __field(enum netfs_failure, what ) + __field(size_t, len ) + __field(size_t, transferred ) + __field(loff_t, start ) + ), + + TP_fast_assign( + __entry->rreq = rreq->debug_id; + __entry->index = sreq ? sreq->debug_index : 0; + __entry->error = error; + __entry->flags = sreq ? sreq->flags : 0; + __entry->source = sreq ? sreq->source : NETFS_INVALID_READ; + __entry->what = what; + __entry->len = sreq ? sreq->len : 0; + __entry->transferred = sreq ? sreq->transferred : 0; + __entry->start = sreq ? sreq->start : 0; + ), + + TP_printk("R=%08x[%u] %s f=%02x s=%llx %zx/%zx %s e=%d", + __entry->rreq, __entry->index, + __print_symbolic(__entry->source, netfs_sreq_sources), + __entry->flags, + __entry->start, __entry->transferred, __entry->len, + __print_symbolic(__entry->what, netfs_failures), + __entry->error) + ); + +#endif /* _TRACE_NETFS_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/include/trace/events/random.h b/include/trace/events/random.h index 9570a10cb949b5792c4290ba8e82a077ac655069..3d7b432ca5f311cfb16d30bb9ebb82875ebe3f20 100644 --- a/include/trace/events/random.h +++ b/include/trace/events/random.h @@ -85,28 +85,6 @@ TRACE_EVENT(credit_entropy_bits, __entry->entropy_count, (void *)__entry->IP) ); -TRACE_EVENT(push_to_pool, - TP_PROTO(const char *pool_name, int pool_bits, int input_bits), - - TP_ARGS(pool_name, pool_bits, input_bits), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, pool_bits ) - __field( int, input_bits ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->pool_bits = pool_bits; - __entry->input_bits = input_bits; - ), - - TP_printk("%s: pool_bits %d input_pool_bits %d", - __entry->pool_name, __entry->pool_bits, - __entry->input_bits) -); - TRACE_EVENT(debit_entropy, TP_PROTO(const char *pool_name, int debit_bits), @@ -161,35 +139,6 @@ TRACE_EVENT(add_disk_randomness, MINOR(__entry->dev), __entry->input_bits) ); -TRACE_EVENT(xfer_secondary_pool, - TP_PROTO(const char *pool_name, int xfer_bits, int request_bits, - int pool_entropy, int input_entropy), - - TP_ARGS(pool_name, xfer_bits, request_bits, pool_entropy, - input_entropy), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, xfer_bits ) - __field( int, request_bits ) - __field( int, pool_entropy ) - __field( int, input_entropy ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->xfer_bits = xfer_bits; - __entry->request_bits = request_bits; - __entry->pool_entropy = pool_entropy; - __entry->input_entropy = input_entropy; - ), - - TP_printk("pool %s xfer_bits %d request_bits %d pool_entropy %d " - "input_entropy %d", __entry->pool_name, __entry->xfer_bits, - __entry->request_bits, __entry->pool_entropy, - __entry->input_entropy) -); - DECLARE_EVENT_CLASS(random__get_random_bytes, TP_PROTO(int nbytes, unsigned long IP), @@ -253,38 +202,6 @@ DEFINE_EVENT(random__extract_entropy, extract_entropy, TP_ARGS(pool_name, nbytes, entropy_count, IP) ); -DEFINE_EVENT(random__extract_entropy, extract_entropy_user, - TP_PROTO(const char *pool_name, int nbytes, int entropy_count, - unsigned long IP), - - TP_ARGS(pool_name, nbytes, entropy_count, IP) -); - -TRACE_EVENT(random_read, - TP_PROTO(int got_bits, int need_bits, int pool_left, int input_left), - - TP_ARGS(got_bits, need_bits, pool_left, input_left), - - TP_STRUCT__entry( - __field( int, got_bits ) - __field( int, need_bits ) - __field( int, pool_left ) - __field( int, input_left ) - ), - - TP_fast_assign( - __entry->got_bits = got_bits; - __entry->need_bits = need_bits; - __entry->pool_left = pool_left; - __entry->input_left = input_left; - ), - - TP_printk("got_bits %d still_needed_bits %d " - "blocking_pool_entropy_left %d input_entropy_left %d", - __entry->got_bits, __entry->got_bits, __entry->pool_left, - __entry->input_left) -); - TRACE_EVENT(urandom_read, TP_PROTO(int got_bits, int pool_left, int input_left), diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 036eb1f5c1335474143e6cf45a2685e274e0ed95..bda16e9e6ba7c76c955379fd430807e0ce0a4c13 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -1781,6 +1781,7 @@ DECLARE_EVENT_CLASS(svc_xprt_event, ), \ TP_ARGS(xprt)) +DEFINE_SVC_XPRT_EVENT(received); DEFINE_SVC_XPRT_EVENT(no_write_space); DEFINE_SVC_XPRT_EVENT(close); DEFINE_SVC_XPRT_EVENT(detach); diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 8e5b9290ea37f83d99ec917cbab32dddee206324..74dcd8e92e50d1811a56162d99b906120a1eca70 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -265,6 +265,18 @@ struct binder_node_info_for_ref { __u32 reserved3; }; +struct binder_freeze_info { + __u32 pid; + __u32 enable; + __u32 timeout_ms; +}; + +struct binder_frozen_status_info { + __u32 pid; + __u32 sync_recv; + __u32 async_recv; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -275,6 +287,9 @@ struct binder_node_info_for_ref { #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) +#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) +#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info) +#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32) /* * NOTE: Two special error codes you should check for when calling @@ -456,6 +471,19 @@ enum binder_driver_return_protocol { * The last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. */ + + BR_FROZEN_REPLY = _IO('r', 18), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is frozen. No parameters. + */ + + BR_ONEWAY_SPAM_SUSPECT = _IO('r', 19), + /* + * Current process sent too many oneway calls to target, and the last + * asynchronous transaction makes the allocated async buffer size exceed + * detection threshold. No parameters. + */ }; enum binder_driver_command_protocol { diff --git a/include/uapi/linux/cyclades.h b/include/uapi/linux/cyclades.h deleted file mode 100644 index fc0add2194a98549d69786d5612f2627e4379c0f..0000000000000000000000000000000000000000 --- a/include/uapi/linux/cyclades.h +++ /dev/null @@ -1,494 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Revision: 3.0 $$Date: 1998/11/02 14:20:59 $ - * linux/include/linux/cyclades.h - * - * This file was initially written by - * Randolph Bentson <bentson@grieg.seaslug.org> and is maintained by - * Ivan Passos <ivan@cyclades.com>. - * - * This file contains the general definitions for the cyclades.c driver - *$Log: cyclades.h,v $ - *Revision 3.1 2002/01/29 11:36:16 henrique - *added throttle field on struct cyclades_port to indicate whether the - *port is throttled or not - * - *Revision 3.1 2000/04/19 18:52:52 ivan - *converted address fields to unsigned long and added fields for physical - *addresses on cyclades_card structure; - * - *Revision 3.0 1998/11/02 14:20:59 ivan - *added nports field on cyclades_card structure; - * - *Revision 2.5 1998/08/03 16:57:01 ivan - *added cyclades_idle_stats structure; - * - *Revision 2.4 1998/06/01 12:09:53 ivan - *removed closing_wait2 from cyclades_port structure; - * - *Revision 2.3 1998/03/16 18:01:12 ivan - *changes in the cyclades_port structure to get it closer to the - *standard serial port structure; - *added constants for new ioctls; - * - *Revision 2.2 1998/02/17 16:50:00 ivan - *changes in the cyclades_port structure (addition of shutdown_wait and - *chip_rev variables); - *added constants for new ioctls and for CD1400 rev. numbers. - * - *Revision 2.1 1997/10/24 16:03:00 ivan - *added rflow (which allows enabling the CD1400 special flow control - *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to - *cyclades_port structure; - *added Alpha support - * - *Revision 2.0 1997/06/30 10:30:00 ivan - *added some new doorbell command constants related to IOCTLW and - *UART error signaling - * - *Revision 1.8 1997/06/03 15:30:00 ivan - *added constant ZFIRM_HLT - *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin) - * - *Revision 1.7 1997/03/26 10:30:00 daniel - *new entries at the end of cyclades_port struct to reallocate - *variables illegally allocated within card memory. - * - *Revision 1.6 1996/09/09 18:35:30 bentson - *fold in changes for Cyclom-Z -- including structures for - *communicating with board as well modest changes to original - *structures to support new features. - * - *Revision 1.5 1995/11/13 21:13:31 bentson - *changes suggested by Michael Chastain <mec@duracef.shout.net> - *to support use of this file in non-kernel applications - * - * - */ - -#ifndef _UAPI_LINUX_CYCLADES_H -#define _UAPI_LINUX_CYCLADES_H - -#include <linux/types.h> - -struct cyclades_monitor { - unsigned long int_count; - unsigned long char_count; - unsigned long char_max; - unsigned long char_last; -}; - -/* - * These stats all reflect activity since the device was last initialized. - * (i.e., since the port was opened with no other processes already having it - * open) - */ -struct cyclades_idle_stats { - __kernel_old_time_t in_use; /* Time device has been in use (secs) */ - __kernel_old_time_t recv_idle; /* Time since last char received (secs) */ - __kernel_old_time_t xmit_idle; /* Time since last char transmitted (secs) */ - unsigned long recv_bytes; /* Bytes received */ - unsigned long xmit_bytes; /* Bytes transmitted */ - unsigned long overruns; /* Input overruns */ - unsigned long frame_errs; /* Input framing errors */ - unsigned long parity_errs; /* Input parity errors */ -}; - -#define CYCLADES_MAGIC 0x4359 - -#define CYGETMON 0x435901 -#define CYGETTHRESH 0x435902 -#define CYSETTHRESH 0x435903 -#define CYGETDEFTHRESH 0x435904 -#define CYSETDEFTHRESH 0x435905 -#define CYGETTIMEOUT 0x435906 -#define CYSETTIMEOUT 0x435907 -#define CYGETDEFTIMEOUT 0x435908 -#define CYSETDEFTIMEOUT 0x435909 -#define CYSETRFLOW 0x43590a -#define CYGETRFLOW 0x43590b -#define CYSETRTSDTR_INV 0x43590c -#define CYGETRTSDTR_INV 0x43590d -#define CYZSETPOLLCYCLE 0x43590e -#define CYZGETPOLLCYCLE 0x43590f -#define CYGETCD1400VER 0x435910 -#define CYSETWAIT 0x435912 -#define CYGETWAIT 0x435913 - -/*************** CYCLOM-Z ADDITIONS ***************/ - -#define CZIOC ('M' << 8) -#define CZ_NBOARDS (CZIOC|0xfa) -#define CZ_BOOT_START (CZIOC|0xfb) -#define CZ_BOOT_DATA (CZIOC|0xfc) -#define CZ_BOOT_END (CZIOC|0xfd) -#define CZ_TEST (CZIOC|0xfe) - -#define CZ_DEF_POLL (HZ/25) - -#define MAX_BOARD 4 /* Max number of boards */ -#define MAX_DEV 256 /* Max number of ports total */ -#define CYZ_MAX_SPEED 921600 - -#define CYZ_FIFO_SIZE 16 - -#define CYZ_BOOT_NWORDS 0x100 -struct CYZ_BOOT_CTRL { - unsigned short nboard; - int status[MAX_BOARD]; - int nchannel[MAX_BOARD]; - int fw_rev[MAX_BOARD]; - unsigned long offset; - unsigned long data[CYZ_BOOT_NWORDS]; -}; - - -#ifndef DP_WINDOW_SIZE -/* - * Memory Window Sizes - */ - -#define DP_WINDOW_SIZE (0x00080000) /* window size 512 Kb */ -#define ZE_DP_WINDOW_SIZE (0x00100000) /* window size 1 Mb (Ze and - 8Zo V.2 */ -#define CTRL_WINDOW_SIZE (0x00000080) /* runtime regs 128 bytes */ - -/* - * CUSTOM_REG - Cyclom-Z/PCI Custom Registers Set. The driver - * normally will access only interested on the fpga_id, fpga_version, - * start_cpu and stop_cpu. - */ - -struct CUSTOM_REG { - __u32 fpga_id; /* FPGA Identification Register */ - __u32 fpga_version; /* FPGA Version Number Register */ - __u32 cpu_start; /* CPU start Register (write) */ - __u32 cpu_stop; /* CPU stop Register (write) */ - __u32 misc_reg; /* Miscellaneous Register */ - __u32 idt_mode; /* IDT mode Register */ - __u32 uart_irq_status; /* UART IRQ status Register */ - __u32 clear_timer0_irq; /* Clear timer interrupt Register */ - __u32 clear_timer1_irq; /* Clear timer interrupt Register */ - __u32 clear_timer2_irq; /* Clear timer interrupt Register */ - __u32 test_register; /* Test Register */ - __u32 test_count; /* Test Count Register */ - __u32 timer_select; /* Timer select register */ - __u32 pr_uart_irq_status; /* Prioritized UART IRQ stat Reg */ - __u32 ram_wait_state; /* RAM wait-state Register */ - __u32 uart_wait_state; /* UART wait-state Register */ - __u32 timer_wait_state; /* timer wait-state Register */ - __u32 ack_wait_state; /* ACK wait State Register */ -}; - -/* - * RUNTIME_9060 - PLX PCI9060ES local configuration and shared runtime - * registers. This structure can be used to access the 9060 registers - * (memory mapped). - */ - -struct RUNTIME_9060 { - __u32 loc_addr_range; /* 00h - Local Address Range */ - __u32 loc_addr_base; /* 04h - Local Address Base */ - __u32 loc_arbitr; /* 08h - Local Arbitration */ - __u32 endian_descr; /* 0Ch - Big/Little Endian Descriptor */ - __u32 loc_rom_range; /* 10h - Local ROM Range */ - __u32 loc_rom_base; /* 14h - Local ROM Base */ - __u32 loc_bus_descr; /* 18h - Local Bus descriptor */ - __u32 loc_range_mst; /* 1Ch - Local Range for Master to PCI */ - __u32 loc_base_mst; /* 20h - Local Base for Master PCI */ - __u32 loc_range_io; /* 24h - Local Range for Master IO */ - __u32 pci_base_mst; /* 28h - PCI Base for Master PCI */ - __u32 pci_conf_io; /* 2Ch - PCI configuration for Master IO */ - __u32 filler1; /* 30h */ - __u32 filler2; /* 34h */ - __u32 filler3; /* 38h */ - __u32 filler4; /* 3Ch */ - __u32 mail_box_0; /* 40h - Mail Box 0 */ - __u32 mail_box_1; /* 44h - Mail Box 1 */ - __u32 mail_box_2; /* 48h - Mail Box 2 */ - __u32 mail_box_3; /* 4Ch - Mail Box 3 */ - __u32 filler5; /* 50h */ - __u32 filler6; /* 54h */ - __u32 filler7; /* 58h */ - __u32 filler8; /* 5Ch */ - __u32 pci_doorbell; /* 60h - PCI to Local Doorbell */ - __u32 loc_doorbell; /* 64h - Local to PCI Doorbell */ - __u32 intr_ctrl_stat; /* 68h - Interrupt Control/Status */ - __u32 init_ctrl; /* 6Ch - EEPROM control, Init Control, etc */ -}; - -/* Values for the Local Base Address re-map register */ - -#define WIN_RAM 0x00000001L /* set the sliding window to RAM */ -#define WIN_CREG 0x14000001L /* set the window to custom Registers */ - -/* Values timer select registers */ - -#define TIMER_BY_1M 0x00 /* clock divided by 1M */ -#define TIMER_BY_256K 0x01 /* clock divided by 256k */ -#define TIMER_BY_128K 0x02 /* clock divided by 128k */ -#define TIMER_BY_32K 0x03 /* clock divided by 32k */ - -/****************** ****************** *******************/ -#endif - -#ifndef ZFIRM_ID -/* #include "zfwint.h" */ -/****************** ****************** *******************/ -/* - * This file contains the definitions for interfacing with the - * Cyclom-Z ZFIRM Firmware. - */ - -/* General Constant definitions */ - -#define MAX_CHAN 64 /* max number of channels per board */ - -/* firmware id structure (set after boot) */ - -#define ID_ADDRESS 0x00000180L /* signature/pointer address */ -#define ZFIRM_ID 0x5557465AL /* ZFIRM/U signature */ -#define ZFIRM_HLT 0x59505B5CL /* ZFIRM needs external power supply */ -#define ZFIRM_RST 0x56040674L /* RST signal (due to FW reset) */ - -#define ZF_TINACT_DEF 1000 /* default inactivity timeout - (1000 ms) */ -#define ZF_TINACT ZF_TINACT_DEF - -struct FIRM_ID { - __u32 signature; /* ZFIRM/U signature */ - __u32 zfwctrl_addr; /* pointer to ZFW_CTRL structure */ -}; - -/* Op. System id */ - -#define C_OS_LINUX 0x00000030 /* generic Linux system */ - -/* channel op_mode */ - -#define C_CH_DISABLE 0x00000000 /* channel is disabled */ -#define C_CH_TXENABLE 0x00000001 /* channel Tx enabled */ -#define C_CH_RXENABLE 0x00000002 /* channel Rx enabled */ -#define C_CH_ENABLE 0x00000003 /* channel Tx/Rx enabled */ -#define C_CH_LOOPBACK 0x00000004 /* Loopback mode */ - -/* comm_parity - parity */ - -#define C_PR_NONE 0x00000000 /* None */ -#define C_PR_ODD 0x00000001 /* Odd */ -#define C_PR_EVEN 0x00000002 /* Even */ -#define C_PR_MARK 0x00000004 /* Mark */ -#define C_PR_SPACE 0x00000008 /* Space */ -#define C_PR_PARITY 0x000000ff - -#define C_PR_DISCARD 0x00000100 /* discard char with frame/par error */ -#define C_PR_IGNORE 0x00000200 /* ignore frame/par error */ - -/* comm_data_l - data length and stop bits */ - -#define C_DL_CS5 0x00000001 -#define C_DL_CS6 0x00000002 -#define C_DL_CS7 0x00000004 -#define C_DL_CS8 0x00000008 -#define C_DL_CS 0x0000000f -#define C_DL_1STOP 0x00000010 -#define C_DL_15STOP 0x00000020 -#define C_DL_2STOP 0x00000040 -#define C_DL_STOP 0x000000f0 - -/* interrupt enabling/status */ - -#define C_IN_DISABLE 0x00000000 /* zero, disable interrupts */ -#define C_IN_TXBEMPTY 0x00000001 /* tx buffer empty */ -#define C_IN_TXLOWWM 0x00000002 /* tx buffer below LWM */ -#define C_IN_RXHIWM 0x00000010 /* rx buffer above HWM */ -#define C_IN_RXNNDT 0x00000020 /* rx no new data timeout */ -#define C_IN_MDCD 0x00000100 /* modem DCD change */ -#define C_IN_MDSR 0x00000200 /* modem DSR change */ -#define C_IN_MRI 0x00000400 /* modem RI change */ -#define C_IN_MCTS 0x00000800 /* modem CTS change */ -#define C_IN_RXBRK 0x00001000 /* Break received */ -#define C_IN_PR_ERROR 0x00002000 /* parity error */ -#define C_IN_FR_ERROR 0x00004000 /* frame error */ -#define C_IN_OVR_ERROR 0x00008000 /* overrun error */ -#define C_IN_RXOFL 0x00010000 /* RX buffer overflow */ -#define C_IN_IOCTLW 0x00020000 /* I/O control w/ wait */ -#define C_IN_MRTS 0x00040000 /* modem RTS drop */ -#define C_IN_ICHAR 0x00080000 - -/* flow control */ - -#define C_FL_OXX 0x00000001 /* output Xon/Xoff flow control */ -#define C_FL_IXX 0x00000002 /* output Xon/Xoff flow control */ -#define C_FL_OIXANY 0x00000004 /* output Xon/Xoff (any xon) */ -#define C_FL_SWFLOW 0x0000000f - -/* flow status */ - -#define C_FS_TXIDLE 0x00000000 /* no Tx data in the buffer or UART */ -#define C_FS_SENDING 0x00000001 /* UART is sending data */ -#define C_FS_SWFLOW 0x00000002 /* Tx is stopped by received Xoff */ - -/* rs_control/rs_status RS-232 signals */ - -#define C_RS_PARAM 0x80000000 /* Indicates presence of parameter in - IOCTLM command */ -#define C_RS_RTS 0x00000001 /* RTS */ -#define C_RS_DTR 0x00000004 /* DTR */ -#define C_RS_DCD 0x00000100 /* CD */ -#define C_RS_DSR 0x00000200 /* DSR */ -#define C_RS_RI 0x00000400 /* RI */ -#define C_RS_CTS 0x00000800 /* CTS */ - -/* commands Host <-> Board */ - -#define C_CM_RESET 0x01 /* reset/flush buffers */ -#define C_CM_IOCTL 0x02 /* re-read CH_CTRL */ -#define C_CM_IOCTLW 0x03 /* re-read CH_CTRL, intr when done */ -#define C_CM_IOCTLM 0x04 /* RS-232 outputs change */ -#define C_CM_SENDXOFF 0x10 /* send Xoff */ -#define C_CM_SENDXON 0x11 /* send Xon */ -#define C_CM_CLFLOW 0x12 /* Clear flow control (resume) */ -#define C_CM_SENDBRK 0x41 /* send break */ -#define C_CM_INTBACK 0x42 /* Interrupt back */ -#define C_CM_SET_BREAK 0x43 /* Tx break on */ -#define C_CM_CLR_BREAK 0x44 /* Tx break off */ -#define C_CM_CMD_DONE 0x45 /* Previous command done */ -#define C_CM_INTBACK2 0x46 /* Alternate Interrupt back */ -#define C_CM_TINACT 0x51 /* set inactivity detection */ -#define C_CM_IRQ_ENBL 0x52 /* enable generation of interrupts */ -#define C_CM_IRQ_DSBL 0x53 /* disable generation of interrupts */ -#define C_CM_ACK_ENBL 0x54 /* enable acknowledged interrupt mode */ -#define C_CM_ACK_DSBL 0x55 /* disable acknowledged intr mode */ -#define C_CM_FLUSH_RX 0x56 /* flushes Rx buffer */ -#define C_CM_FLUSH_TX 0x57 /* flushes Tx buffer */ -#define C_CM_Q_ENABLE 0x58 /* enables queue access from the - driver */ -#define C_CM_Q_DISABLE 0x59 /* disables queue access from the - driver */ - -#define C_CM_TXBEMPTY 0x60 /* Tx buffer is empty */ -#define C_CM_TXLOWWM 0x61 /* Tx buffer low water mark */ -#define C_CM_RXHIWM 0x62 /* Rx buffer high water mark */ -#define C_CM_RXNNDT 0x63 /* rx no new data timeout */ -#define C_CM_TXFEMPTY 0x64 -#define C_CM_ICHAR 0x65 -#define C_CM_MDCD 0x70 /* modem DCD change */ -#define C_CM_MDSR 0x71 /* modem DSR change */ -#define C_CM_MRI 0x72 /* modem RI change */ -#define C_CM_MCTS 0x73 /* modem CTS change */ -#define C_CM_MRTS 0x74 /* modem RTS drop */ -#define C_CM_RXBRK 0x84 /* Break received */ -#define C_CM_PR_ERROR 0x85 /* Parity error */ -#define C_CM_FR_ERROR 0x86 /* Frame error */ -#define C_CM_OVR_ERROR 0x87 /* Overrun error */ -#define C_CM_RXOFL 0x88 /* RX buffer overflow */ -#define C_CM_CMDERROR 0x90 /* command error */ -#define C_CM_FATAL 0x91 /* fatal error */ -#define C_CM_HW_RESET 0x92 /* reset board */ - -/* - * CH_CTRL - This per port structure contains all parameters - * that control an specific port. It can be seen as the - * configuration registers of a "super-serial-controller". - */ - -struct CH_CTRL { - __u32 op_mode; /* operation mode */ - __u32 intr_enable; /* interrupt masking */ - __u32 sw_flow; /* SW flow control */ - __u32 flow_status; /* output flow status */ - __u32 comm_baud; /* baud rate - numerically specified */ - __u32 comm_parity; /* parity */ - __u32 comm_data_l; /* data length/stop */ - __u32 comm_flags; /* other flags */ - __u32 hw_flow; /* HW flow control */ - __u32 rs_control; /* RS-232 outputs */ - __u32 rs_status; /* RS-232 inputs */ - __u32 flow_xon; /* xon char */ - __u32 flow_xoff; /* xoff char */ - __u32 hw_overflow; /* hw overflow counter */ - __u32 sw_overflow; /* sw overflow counter */ - __u32 comm_error; /* frame/parity error counter */ - __u32 ichar; - __u32 filler[7]; -}; - - -/* - * BUF_CTRL - This per channel structure contains - * all Tx and Rx buffer control for a given channel. - */ - -struct BUF_CTRL { - __u32 flag_dma; /* buffers are in Host memory */ - __u32 tx_bufaddr; /* address of the tx buffer */ - __u32 tx_bufsize; /* tx buffer size */ - __u32 tx_threshold; /* tx low water mark */ - __u32 tx_get; /* tail index tx buf */ - __u32 tx_put; /* head index tx buf */ - __u32 rx_bufaddr; /* address of the rx buffer */ - __u32 rx_bufsize; /* rx buffer size */ - __u32 rx_threshold; /* rx high water mark */ - __u32 rx_get; /* tail index rx buf */ - __u32 rx_put; /* head index rx buf */ - __u32 filler[5]; /* filler to align structures */ -}; - -/* - * BOARD_CTRL - This per board structure contains all global - * control fields related to the board. - */ - -struct BOARD_CTRL { - - /* static info provided by the on-board CPU */ - __u32 n_channel; /* number of channels */ - __u32 fw_version; /* firmware version */ - - /* static info provided by the driver */ - __u32 op_system; /* op_system id */ - __u32 dr_version; /* driver version */ - - /* board control area */ - __u32 inactivity; /* inactivity control */ - - /* host to FW commands */ - __u32 hcmd_channel; /* channel number */ - __u32 hcmd_param; /* pointer to parameters */ - - /* FW to Host commands */ - __u32 fwcmd_channel; /* channel number */ - __u32 fwcmd_param; /* pointer to parameters */ - __u32 zf_int_queue_addr; /* offset for INT_QUEUE structure */ - - /* filler so the structures are aligned */ - __u32 filler[6]; -}; - -/* Host Interrupt Queue */ - -#define QUEUE_SIZE (10*MAX_CHAN) - -struct INT_QUEUE { - unsigned char intr_code[QUEUE_SIZE]; - unsigned long channel[QUEUE_SIZE]; - unsigned long param[QUEUE_SIZE]; - unsigned long put; - unsigned long get; -}; - -/* - * ZFW_CTRL - This is the data structure that includes all other - * data structures used by the Firmware. - */ - -struct ZFW_CTRL { - struct BOARD_CTRL board_ctrl; - struct CH_CTRL ch_ctrl[MAX_CHAN]; - struct BUF_CTRL buf_ctrl[MAX_CHAN]; -}; - -/****************** ****************** *******************/ -#endif - -#endif /* _UAPI_LINUX_CYCLADES_H */ diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 30f68b42eeb53f58b7140b519f07bc623cf43ba4..61bf4774b8f2a13c6517c8df8f1db7717cfa79f5 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -426,6 +426,7 @@ typedef struct elf64_shdr { #define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */ #define NT_ARM_PACG_KEYS 0x408 /* ARM pointer authentication generic key */ #define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* arm64 tagged address control (prctl()) */ +#define NT_ARM_PAC_ENABLED_KEYS 0x40a /* arm64 ptr auth enabled keys (prctl()) */ #define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ #define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ #define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..13939032b3f60ae470b38300b4febd93d8400a87 --- /dev/null +++ b/include/uapi/linux/iio/buffer.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* industrial I/O buffer definitions needed both in and out of kernel + */ + +#ifndef _UAPI_IIO_BUFFER_H_ +#define _UAPI_IIO_BUFFER_H_ + +#define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int) + +#endif /* _UAPI_IIO_BUFFER_H_ */ diff --git a/include/uapi/linux/major.h b/include/uapi/linux/major.h index 7e5fa8e15c43632ec82dfdca82e07318808c9c62..4e5f2b3a3d5465a8e046e3ff2e02dd5097ce952e 100644 --- a/include/uapi/linux/major.h +++ b/include/uapi/linux/major.h @@ -34,8 +34,6 @@ #define GOLDSTAR_CDROM_MAJOR 16 #define OPTICS_CDROM_MAJOR 17 #define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 #define MITSUMI_X_CDROM_MAJOR 20 #define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ #define SCSI_GENERIC_MAJOR 21 diff --git a/include/uapi/linux/map_to_7segment.h b/include/uapi/linux/map_to_7segment.h index 8b02088f96e3733e3ba08b5f856a6705339ed696..04c8b55812e74733c14106a231d13146f41b4a00 100644 --- a/include/uapi/linux/map_to_7segment.h +++ b/include/uapi/linux/map_to_7segment.h @@ -1,20 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com> - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MAP_TO_7SEGMENT_H diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h index ff0ca88b1c8f64a324ff651e561852d7f0d8bf80..427294dd56a1b83bb90abddc819f9b320ceda683 100644 --- a/include/uapi/linux/nfsd/nfsfh.h +++ b/include/uapi/linux/nfsd/nfsfh.h @@ -64,13 +64,24 @@ struct nfs_fhbase_old { * in include/linux/exportfs.h for currently registered values. */ struct nfs_fhbase_new { - __u8 fb_version; /* == 1, even => nfs_fhbase_old */ - __u8 fb_auth_type; - __u8 fb_fsid_type; - __u8 fb_fileid_type; - __u32 fb_auth[1]; -/* __u32 fb_fsid[0]; floating */ -/* __u32 fb_fileid[0]; floating */ + union { + struct { + __u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ + __u8 fb_auth_type_aux; + __u8 fb_fsid_type_aux; + __u8 fb_fileid_type_aux; + __u32 fb_auth[1]; + /* __u32 fb_fsid[0]; floating */ + /* __u32 fb_fileid[0]; floating */ + }; + struct { + __u8 fb_version; /* == 1, even => nfs_fhbase_old */ + __u8 fb_auth_type; + __u8 fb_fsid_type; + __u8 fb_fileid_type; + __u32 fb_auth_flex[]; /* flexible-array member */ + }; + }; }; struct knfsd_fh { @@ -97,7 +108,7 @@ struct knfsd_fh { #define fh_fsid_type fh_base.fh_new.fb_fsid_type #define fh_auth_type fh_base.fh_new.fb_auth_type #define fh_fileid_type fh_base.fh_new.fb_fileid_type -#define fh_fsid fh_base.fh_new.fb_auth +#define fh_fsid fh_base.fh_new.fb_auth_flex /* Do not use, provided for userspace compatiblity. */ #define fh_auth fh_base.fh_new.fb_auth diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 5d836c99a82cdd325d13daefd785a847ac3be507..b1446d6878113ade1e8bbf663cf23b7cc1b86ee7 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -255,6 +255,10 @@ struct prctl_mm_map { # define SYSCALL_DISPATCH_FILTER_ALLOW 0 # define SYSCALL_DISPATCH_FILTER_BLOCK 1 +/* Set/get enabled arm64 pointer authentication keys */ +#define PR_PAC_SET_ENABLED_KEYS 60 +#define PR_PAC_GET_ENABLED_KEYS 61 + #define PR_SET_VMA 0x53564d41 # define PR_SET_VMA_ANON_NAME 0 diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index 93eb3c496ff1e85a6af59c539596775c4c9bf35e..fa6b16e5fdd837405321f21e347b9f7dbcf81649 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -52,11 +52,11 @@ struct serial_struct { #define PORT_16450 2 #define PORT_16550 3 #define PORT_16550A 4 -#define PORT_CIRRUS 5 /* usurped by cyclades.c */ +#define PORT_CIRRUS 5 #define PORT_16650 6 #define PORT_16650V2 7 #define PORT_16750 8 -#define PORT_STARTECH 9 /* usurped by cyclades.c */ +#define PORT_STARTECH 9 #define PORT_16C950 10 /* Oxford Semiconductor */ #define PORT_16654 11 #define PORT_16850 12 diff --git a/include/uapi/linux/surface_aggregator/dtx.h b/include/uapi/linux/surface_aggregator/dtx.h new file mode 100644 index 0000000000000000000000000000000000000000..0833aab0d819cb52f75a0473e76ae5bf7dd9e656 --- /dev/null +++ b/include/uapi/linux/surface_aggregator/dtx.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Surface DTX (clipboard detachment system driver) user-space interface. + * + * Definitions, structs, and IOCTLs for the /dev/surface/dtx misc device. This + * device allows user-space to control the clipboard detachment process on + * Surface Book series devices. + * + * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> + */ + +#ifndef _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H +#define _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +/* Status/error categories */ +#define SDTX_CATEGORY_STATUS 0x0000 +#define SDTX_CATEGORY_RUNTIME_ERROR 0x1000 +#define SDTX_CATEGORY_HARDWARE_ERROR 0x2000 +#define SDTX_CATEGORY_UNKNOWN 0xf000 + +#define SDTX_CATEGORY_MASK 0xf000 +#define SDTX_CATEGORY(value) ((value) & SDTX_CATEGORY_MASK) + +#define SDTX_STATUS(code) ((code) | SDTX_CATEGORY_STATUS) +#define SDTX_ERR_RT(code) ((code) | SDTX_CATEGORY_RUNTIME_ERROR) +#define SDTX_ERR_HW(code) ((code) | SDTX_CATEGORY_HARDWARE_ERROR) +#define SDTX_UNKNOWN(code) ((code) | SDTX_CATEGORY_UNKNOWN) + +#define SDTX_SUCCESS(value) (SDTX_CATEGORY(value) == SDTX_CATEGORY_STATUS) + +/* Latch status values */ +#define SDTX_LATCH_CLOSED SDTX_STATUS(0x00) +#define SDTX_LATCH_OPENED SDTX_STATUS(0x01) + +/* Base state values */ +#define SDTX_BASE_DETACHED SDTX_STATUS(0x00) +#define SDTX_BASE_ATTACHED SDTX_STATUS(0x01) + +/* Runtime errors (non-critical) */ +#define SDTX_DETACH_NOT_FEASIBLE SDTX_ERR_RT(0x01) +#define SDTX_DETACH_TIMEDOUT SDTX_ERR_RT(0x02) + +/* Hardware errors (critical) */ +#define SDTX_ERR_FAILED_TO_OPEN SDTX_ERR_HW(0x01) +#define SDTX_ERR_FAILED_TO_REMAIN_OPEN SDTX_ERR_HW(0x02) +#define SDTX_ERR_FAILED_TO_CLOSE SDTX_ERR_HW(0x03) + +/* Base types */ +#define SDTX_DEVICE_TYPE_HID 0x0100 +#define SDTX_DEVICE_TYPE_SSH 0x0200 + +#define SDTX_DEVICE_TYPE_MASK 0x0f00 +#define SDTX_DEVICE_TYPE(value) ((value) & SDTX_DEVICE_TYPE_MASK) + +#define SDTX_BASE_TYPE_HID(id) ((id) | SDTX_DEVICE_TYPE_HID) +#define SDTX_BASE_TYPE_SSH(id) ((id) | SDTX_DEVICE_TYPE_SSH) + +/** + * enum sdtx_device_mode - Mode describing how (and if) the clipboard is + * attached to the base of the device. + * @SDTX_DEVICE_MODE_TABLET: The clipboard is detached from the base and the + * device operates as tablet. + * @SDTX_DEVICE_MODE_LAPTOP: The clipboard is attached normally to the base + * and the device operates as laptop. + * @SDTX_DEVICE_MODE_STUDIO: The clipboard is attached to the base in reverse. + * The device operates as tablet with keyboard and + * touchpad deactivated, however, the base battery + * and, if present in the specific device model, dGPU + * are available to the system. + */ +enum sdtx_device_mode { + SDTX_DEVICE_MODE_TABLET = 0x00, + SDTX_DEVICE_MODE_LAPTOP = 0x01, + SDTX_DEVICE_MODE_STUDIO = 0x02, +}; + +/** + * struct sdtx_event - Event provided by reading from the DTX device file. + * @length: Length of the event payload, in bytes. + * @code: Event code, detailing what type of event this is. + * @data: Payload of the event, containing @length bytes. + * + * See &enum sdtx_event_code for currently valid event codes. + */ +struct sdtx_event { + __u16 length; + __u16 code; + __u8 data[]; +} __attribute__((__packed__)); + +/** + * enum sdtx_event_code - Code describing the type of an event. + * @SDTX_EVENT_REQUEST: Detachment request event type. + * @SDTX_EVENT_CANCEL: Cancel detachment process event type. + * @SDTX_EVENT_BASE_CONNECTION: Base/clipboard connection change event type. + * @SDTX_EVENT_LATCH_STATUS: Latch status change event type. + * @SDTX_EVENT_DEVICE_MODE: Device mode change event type. + * + * Used in &struct sdtx_event to describe the type of the event. Further event + * codes are reserved for future use. Any event parser should be able to + * gracefully handle unknown events, i.e. by simply skipping them. + * + * Consult the DTX user-space interface documentation for details regarding + * the individual event types. + */ +enum sdtx_event_code { + SDTX_EVENT_REQUEST = 1, + SDTX_EVENT_CANCEL = 2, + SDTX_EVENT_BASE_CONNECTION = 3, + SDTX_EVENT_LATCH_STATUS = 4, + SDTX_EVENT_DEVICE_MODE = 5, +}; + +/** + * struct sdtx_base_info - Describes if and what type of base is connected. + * @state: The state of the connection. Valid values are %SDTX_BASE_DETACHED, + * %SDTX_BASE_ATTACHED, and %SDTX_DETACH_NOT_FEASIBLE (in case a base + * is attached but low clipboard battery prevents detachment). Other + * values are currently reserved. + * @base_id: The type of base connected. Zero if no base is connected. + */ +struct sdtx_base_info { + __u16 state; + __u16 base_id; +} __attribute__((__packed__)); + +/* IOCTLs */ +#define SDTX_IOCTL_EVENTS_ENABLE _IO(0xa5, 0x21) +#define SDTX_IOCTL_EVENTS_DISABLE _IO(0xa5, 0x22) + +#define SDTX_IOCTL_LATCH_LOCK _IO(0xa5, 0x23) +#define SDTX_IOCTL_LATCH_UNLOCK _IO(0xa5, 0x24) + +#define SDTX_IOCTL_LATCH_REQUEST _IO(0xa5, 0x25) +#define SDTX_IOCTL_LATCH_CONFIRM _IO(0xa5, 0x26) +#define SDTX_IOCTL_LATCH_HEARTBEAT _IO(0xa5, 0x27) +#define SDTX_IOCTL_LATCH_CANCEL _IO(0xa5, 0x28) + +#define SDTX_IOCTL_GET_BASE_INFO _IOR(0xa5, 0x29, struct sdtx_base_info) +#define SDTX_IOCTL_GET_DEVICE_MODE _IOR(0xa5, 0x2a, __u16) +#define SDTX_IOCTL_GET_LATCH_STATUS _IOR(0xa5, 0x2b, __u16) + +#endif /* _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H */ diff --git a/include/uapi/linux/tty_flags.h b/include/uapi/linux/tty_flags.h index 900a32e634247ef8b163d63b1d7fd17b2bb42fd8..cf25056d4b27efd11d141b06f102ed6115a05924 100644 --- a/include/uapi/linux/tty_flags.h +++ b/include/uapi/linux/tty_flags.h @@ -39,7 +39,7 @@ * WARNING: These flags are no longer used and have been superceded by the * TTY_PORT_ flags in the iflags field (and not userspace-visible) */ -#ifndef _KERNEL_ +#ifndef __KERNEL__ #define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ #define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ #define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ @@ -73,15 +73,15 @@ #define ASYNC_MAGIC_MULTIPLIER (1U << ASYNCB_MAGIC_MULTIPLIER) #define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1) -#define ASYNC_DEPRECATED (ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | \ - ASYNC_CALLOUT_NOHUP | ASYNC_AUTOPROBE) +#define ASYNC_DEPRECATED (ASYNC_SPLIT_TERMIOS | ASYNC_SESSION_LOCKOUT | \ + ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP | ASYNC_AUTOPROBE) #define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \ ASYNC_LOW_LATENCY) #define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) #define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) #define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) -#ifndef _KERNEL_ +#ifndef __KERNEL__ /* These flags are no longer used (and were always masked from userspace) */ #define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) #define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h index d854cb19c42c38f536627aaefa08ddb0b61d5ada..bfdae12cdacf89d3bccb0f7381630b8fe516104d 100644 --- a/include/uapi/linux/usb/video.h +++ b/include/uapi/linux/usb/video.h @@ -302,9 +302,10 @@ struct uvc_processing_unit_descriptor { __u8 bControlSize; __u8 bmControls[2]; __u8 iProcessing; + __u8 bmVideoStandards; } __attribute__((__packed__)); -#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) +#define UVC_DT_PROCESSING_UNIT_SIZE(n) (10+(n)) /* 3.7.2.6. Extension Unit Descriptor */ struct uvc_extension_unit_descriptor { diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 5a86b521a4506e6c4dffbbd448b59bee9df4cd95..d3e017b5f0dba52cd767160b34fef7fde7bbf2e6 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -297,6 +297,7 @@ enum hl_device_status { #define HL_INFO_SYNC_MANAGER 14 #define HL_INFO_TOTAL_ENERGY 15 #define HL_INFO_PLL_FREQUENCY 16 +#define HL_INFO_POWER 17 #define HL_INFO_VERSION_MAX_LEN 128 #define HL_INFO_CARD_NAME_MAX_LEN 16 @@ -410,6 +411,14 @@ struct hl_pll_frequency_info { __u16 output[HL_PLL_NUM_OUTPUTS]; }; +/** + * struct hl_power_info - power information + * @power: power consumption + */ +struct hl_power_info { + __u64 power; +}; + /** * struct hl_info_sync_manager - sync manager information * @first_available_sync_object: first available sob @@ -621,6 +630,7 @@ struct hl_cs_chunk { #define HL_CS_FLAGS_STAGED_SUBMISSION 0x40 #define HL_CS_FLAGS_STAGED_SUBMISSION_FIRST 0x80 #define HL_CS_FLAGS_STAGED_SUBMISSION_LAST 0x100 +#define HL_CS_FLAGS_CUSTOM_TIMEOUT 0x200 #define HL_CS_STATUS_SUCCESS 0 @@ -634,17 +644,10 @@ struct hl_cs_in { /* holds address of array of hl_cs_chunk for execution phase */ __u64 chunks_execute; - union { - /* this holds address of array of hl_cs_chunk for store phase - - * Currently not in use - */ - __u64 chunks_store; - - /* Sequence number of a staged submission CS - * valid only if HL_CS_FLAGS_STAGED_SUBMISSION is set - */ - __u64 seq; - }; + /* Sequence number of a staged submission CS + * valid only if HL_CS_FLAGS_STAGED_SUBMISSION is set + */ + __u64 seq; /* Number of chunks in restore phase array. Maximum number is * HL_MAX_JOBS_PER_CS @@ -656,8 +659,10 @@ struct hl_cs_in { */ __u32 num_chunks_execute; - /* Number of chunks in restore phase array - Currently not in use */ - __u32 num_chunks_store; + /* timeout in seconds - valid only if HL_CS_FLAGS_CUSTOM_TIMEOUT + * is set + */ + __u32 timeout; /* HL_CS_FLAGS_* */ __u32 cs_flags; @@ -682,14 +687,46 @@ union hl_cs_args { struct hl_cs_out out; }; +#define HL_WAIT_CS_FLAGS_INTERRUPT 0x2 +#define HL_WAIT_CS_FLAGS_INTERRUPT_MASK 0xFFF00000 + struct hl_wait_cs_in { - /* Command submission sequence number */ - __u64 seq; - /* Absolute timeout to wait in microseconds */ - __u64 timeout_us; + union { + struct { + /* Command submission sequence number */ + __u64 seq; + /* Absolute timeout to wait for command submission + * in microseconds + */ + __u64 timeout_us; + }; + + struct { + /* User address for completion comparison. + * upon interrupt, driver will compare the value pointed + * by this address with the supplied target value. + * in order not to perform any comparison, set address + * to all 1s. + * Relevant only when HL_WAIT_CS_FLAGS_INTERRUPT is set + */ + __u64 addr; + /* Target value for completion comparison */ + __u32 target; + /* Absolute timeout to wait for interrupt + * in microseconds + */ + __u32 interrupt_timeout_us; + }; + }; + /* Context ID - Currently not in use */ __u32 ctx_id; - __u32 pad; + /* HL_WAIT_CS_FLAGS_* + * If HL_WAIT_CS_FLAGS_INTERRUPT is set, this field should include + * interrupt id according to HL_WAIT_CS_FLAGS_INTERRUPT_MASK, in order + * not to specify an interrupt id ,set mask to all 1s. + */ + __u32 flags; }; #define HL_WAIT_CS_STATUS_COMPLETED 0 @@ -999,8 +1036,8 @@ struct hl_debug_args { * Each JOB will be enqueued on a specific queue, according to the user's input. * There can be more then one JOB per queue. * - * The CS IOCTL will receive three sets of JOBS. One set is for "restore" phase, - * a second set is for "execution" phase and a third set is for "store" phase. + * The CS IOCTL will receive two sets of JOBS. One set is for "restore" phase + * and a second set is for "execution" phase. * The JOBS on the "restore" phase are enqueued only after context-switch * (or if its the first CS for this context). The user can also order the * driver to run the "restore" phase explicitly diff --git a/include/uapi/misc/uacce/hisi_qm.h b/include/uapi/misc/uacce/hisi_qm.h index 6435f0bcb556cda8bc801619bfdd15dceed33976..1faef5ff87ef908102468f8f062929752bdd0c07 100644 --- a/include/uapi/misc/uacce/hisi_qm.h +++ b/include/uapi/misc/uacce/hisi_qm.h @@ -16,6 +16,7 @@ struct hisi_qp_ctx { #define HISI_QM_API_VER_BASE "hisi_qm_v1" #define HISI_QM_API_VER2_BASE "hisi_qm_v2" +#define HISI_QM_API_VER3_BASE "hisi_qm_v3" /* UACCE_CMD_QM_SET_QP_CTX: Set qp algorithm type */ #define UACCE_CMD_QM_SET_QP_CTX _IOWR('H', 10, struct hisi_qp_ctx) diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h index 65b9db9365577b278424a4ec48f78dd96ce35367..b869990c2db20d12e24b820b839c97e5b5222518 100644 --- a/include/uapi/mtd/mtd-abi.h +++ b/include/uapi/mtd/mtd-abi.h @@ -205,6 +205,8 @@ struct otp_info { * without OOB, e.g., NOR flash. */ #define MEMWRITE _IOWR('M', 24, struct mtd_write_req) +/* Erase a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ +#define OTPERASE _IOW('M', 25, struct otp_info) /* * Obsolete legacy interface. Keep it in order not to break userspace diff --git a/include/xen/acpi.h b/include/xen/acpi.h index 4ddd7dc4a61e2c9b2470bf58349559dc4196f938..b1e11863144d1580cc9399f719d7e41228fc5805 100644 --- a/include/xen/acpi.h +++ b/include/xen/acpi.h @@ -40,41 +40,6 @@ #include <xen/xen.h> #include <linux/acpi.h> -#define ACPI_MEMORY_DEVICE_CLASS "memory" -#define ACPI_MEMORY_DEVICE_HID "PNP0C80" -#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" - -int xen_stub_memory_device_init(void); -void xen_stub_memory_device_exit(void); - -#define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DEVICE_HID "ACPI0007" -#define ACPI_PROCESSOR_DEVICE_NAME "Processor" - -int xen_stub_processor_init(void); -void xen_stub_processor_exit(void); - -void xen_pcpu_hotplug_sync(void); -int xen_pcpu_id(uint32_t acpi_id); - -static inline int xen_acpi_get_pxm(acpi_handle h) -{ - unsigned long long pxm; - acpi_status status; - acpi_handle handle; - acpi_handle phandle = h; - - do { - handle = phandle; - status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm); - if (ACPI_SUCCESS(status)) - return pxm; - status = acpi_get_parent(handle, &phandle); - } while (ACPI_SUCCESS(status)); - - return -ENXIO; -} - int xen_acpi_notify_hypervisor_sleep(u8 sleep_state, u32 pm1a_cnt, u32 pm1b_cnd); int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state, diff --git a/include/xen/arm/swiotlb-xen.h b/include/xen/arm/swiotlb-xen.h new file mode 100644 index 0000000000000000000000000000000000000000..2994fe6031a0973bddde9d0d6f4d706661ee611b --- /dev/null +++ b/include/xen/arm/swiotlb-xen.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_ARM_SWIOTLB_XEN_H +#define _ASM_ARM_SWIOTLB_XEN_H + +extern int xen_swiotlb_detect(void); + +#endif /* _ASM_ARM_SWIOTLB_XEN_H */ diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h index 6d1384abfbdf96edf21665022b9ef1eb9a5fe7d1..5a7bdefa06a8654919826adcf1637afa7fc8f18d 100644 --- a/include/xen/interface/features.h +++ b/include/xen/interface/features.h @@ -83,6 +83,20 @@ */ #define XENFEAT_linux_rsdp_unrestricted 15 +/* + * A direct-mapped (or 1:1 mapped) domain is a domain for which its + * local pages have gfn == mfn. If a domain is direct-mapped, + * XENFEAT_direct_mapped is set; otherwise XENFEAT_not_direct_mapped + * is set. + * + * If neither flag is set (e.g. older Xen releases) the assumptions are: + * - not auto_translated domains (x86 only) are always direct-mapped + * - on x86, auto_translated domains are not direct-mapped + * - on ARM, Dom0 is direct-mapped, DomUs are not + */ +#define XENFEAT_not_direct_mapped 16 +#define XENFEAT_direct_mapped 17 + #define XENFEAT_NR_SUBMAPS 1 #endif /* __XEN_PUBLIC_FEATURES_H__ */ diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h index d5eaf9d682b804be2d563e2a284ae292436e9980..dbc4a4b785f68d999f977b3f5ddaa6a058297a14 100644 --- a/include/xen/swiotlb-xen.h +++ b/include/xen/swiotlb-xen.h @@ -3,6 +3,7 @@ #define __LINUX_SWIOTLB_XEN_H #include <linux/swiotlb.h> +#include <asm/xen/swiotlb-xen.h> void xen_dma_sync_for_cpu(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir); diff --git a/init/Kconfig b/init/Kconfig index 00b1919b68e3a43edf1cbb1fafcf96b6a59bbeed..3d494e0b3c431b6a0206d8a76d85f1b3ee7ae6ad 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2336,7 +2336,7 @@ endif # MODULES config MODULES_TREE_LOOKUP def_bool y - depends on PERF_EVENTS || TRACING + depends on PERF_EVENTS || TRACING || CFI_CLANG config INIT_ALL_POSSIBLE bool diff --git a/init/init_task.c b/init/init_task.c index 3711cdaafed2fb47ea655f98dd860c588d10fe1e..8b08c2e19cbb5b632df0c4ca4f47e7e194345304 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -210,7 +210,7 @@ struct task_struct init_task #ifdef CONFIG_SECURITY .security = NULL, #endif -#ifdef CONFIG_SECCOMP +#ifdef CONFIG_SECCOMP_FILTER .seccomp = { .filter_count = ATOMIC_INIT(0) }, #endif }; diff --git a/init/main.c b/init/main.c index 53b278845b886e1aacd643f6bd7e8902080f525a..f498aac26e8cbedf1178a39cee3cc043c8409729 100644 --- a/init/main.c +++ b/init/main.c @@ -844,6 +844,29 @@ static void __init mm_init(void) pti_init(); } +#ifdef CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET +DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, + randomize_kstack_offset); +DEFINE_PER_CPU(u32, kstack_offset); + +static int __init early_randomize_kstack_offset(char *buf) +{ + int ret; + bool bool_result; + + ret = kstrtobool(buf, &bool_result); + if (ret) + return ret; + + if (bool_result) + static_branch_enable(&randomize_kstack_offset); + else + static_branch_disable(&randomize_kstack_offset); + return 0; +} +early_param("randomize_kstack_offset", early_randomize_kstack_offset); +#endif + void __init __weak arch_call_rest_init(void) { rest_init(); diff --git a/kernel/Makefile b/kernel/Makefile index 605ec3e70cb78d2103d248277571d64d8847f51c..4df609be42d07cadd1f992b63350cc33bf41e988 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -41,6 +41,9 @@ KCSAN_SANITIZE_kcov.o := n UBSAN_SANITIZE_kcov.o := n CFLAGS_kcov.o := $(call cc-option, -fno-conserve-stack) -fno-stack-protector +# Don't instrument error handlers +CFLAGS_REMOVE_cfi.o := $(CC_FLAGS_CFI) + obj-y += sched/ obj-y += locking/ obj-y += power/ @@ -111,6 +114,7 @@ obj-$(CONFIG_BPF) += bpf/ obj-$(CONFIG_KCSAN) += kcsan/ obj-$(CONFIG_SHADOW_CALL_STACK) += scs.o obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call.o +obj-$(CONFIG_CFI_CLANG) += cfi.o obj-$(CONFIG_PERF_EVENTS) += events/ diff --git a/kernel/audit.c b/kernel/audit.c index 551a394bc8f4277710da2f56525198c97695602b..121d37e700a62b53854c06199d9a89850ec39dd4 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -2132,7 +2132,7 @@ int audit_log_task_context(struct audit_buffer *ab) int error; u32 sid; - security_task_getsecid(current, &sid); + security_task_getsecid_subj(current, &sid); if (!sid) return 0; @@ -2353,7 +2353,7 @@ int audit_signal_info(int sig, struct task_struct *t) audit_sig_uid = auid; else audit_sig_uid = uid; - security_task_getsecid(current, &audit_sig_sid); + security_task_getsecid_subj(current, &audit_sig_sid); } return audit_signal_info_syscall(t); diff --git a/kernel/audit.h b/kernel/audit.h index 3b9c0945225a121e7031cfe29299925bb0b42516..1522e100fd1795316e255e54dedac47d40f710a3 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -292,8 +292,8 @@ extern void audit_filter_inodes(struct task_struct *tsk, extern struct list_head *audit_killed_trees(void); #else /* CONFIG_AUDITSYSCALL */ #define auditsc_get_stamp(c, t, s) 0 -#define audit_put_watch(w) {} -#define audit_get_watch(w) {} +#define audit_put_watch(w) do { } while (0) +#define audit_get_watch(w) do { } while (0) #define audit_to_watch(k, p, l, o) (-EINVAL) #define audit_add_watch(k, l) (-EINVAL) #define audit_remove_watch_rule(k) BUG() @@ -302,8 +302,8 @@ extern struct list_head *audit_killed_trees(void); #define audit_alloc_mark(k, p, l) (ERR_PTR(-EINVAL)) #define audit_mark_path(m) "" -#define audit_remove_mark(m) -#define audit_remove_mark_rule(k) +#define audit_remove_mark(m) do { } while (0) +#define audit_remove_mark_rule(k) do { } while (0) #define audit_mark_compare(m, i, d) 0 #define audit_exe_compare(t, m) (-EINVAL) #define audit_dupe_exe(n, o) (-EINVAL) @@ -311,8 +311,8 @@ extern struct list_head *audit_killed_trees(void); #define audit_remove_tree_rule(rule) BUG() #define audit_add_tree_rule(rule) -EINVAL #define audit_make_tree(rule, str, op) -EINVAL -#define audit_trim_trees() (void)0 -#define audit_put_tree(tree) (void)0 +#define audit_trim_trees() do { } while (0) +#define audit_put_tree(tree) do { } while (0) #define audit_tag_tree(old, new) -EINVAL #define audit_tree_path(rule) "" /* never called */ #define audit_kill_trees(context) BUG() diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 333b3bcfc5458fd4b5e45190c90edce17784c46e..db2c6b59dfc3362bb3cbd2ab25122b67fe913ad6 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1359,7 +1359,8 @@ int audit_filter(int msgtype, unsigned int listtype) case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: if (f->lsm_rule) { - security_task_getsecid(current, &sid); + security_task_getsecid_subj(current, + &sid); result = security_audit_rule_match(sid, f->type, f->op, f->lsm_rule); } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 47fb48f42c93477ebc707af15740d76884cc234e..175ef6f3ea4eafb85bb5582a03f29cee07faac79 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -667,7 +667,7 @@ static int audit_filter_rules(struct task_struct *tsk, logged upon error */ if (f->lsm_rule) { if (need_sid) { - security_task_getsecid(tsk, &sid); + security_task_getsecid_subj(tsk, &sid); need_sid = 0; } result = security_audit_rule_match(sid, f->type, @@ -805,8 +805,7 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val) * (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT). */ static void audit_filter_syscall(struct task_struct *tsk, - struct audit_context *ctx, - struct list_head *list) + struct audit_context *ctx) { struct audit_entry *e; enum audit_state state; @@ -815,7 +814,7 @@ static void audit_filter_syscall(struct task_struct *tsk, return; rcu_read_lock(); - list_for_each_entry_rcu(e, list, list) { + list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_EXIT], list) { if (audit_in_mask(&e->rule, ctx->major) && audit_filter_rules(tsk, &e->rule, ctx, NULL, &state, false)) { @@ -1627,8 +1626,7 @@ void __audit_free(struct task_struct *tsk) context->return_valid = AUDITSC_INVALID; context->return_code = 0; - audit_filter_syscall(tsk, context, - &audit_filter_list[AUDIT_FILTER_EXIT]); + audit_filter_syscall(tsk, context); audit_filter_inodes(tsk, context); if (context->current_state == AUDIT_RECORD_CONTEXT) audit_log_exit(); @@ -1735,8 +1733,7 @@ void __audit_syscall_exit(int success, long return_code) else context->return_code = return_code; - audit_filter_syscall(current, context, - &audit_filter_list[AUDIT_FILTER_EXIT]); + audit_filter_syscall(current, context); audit_filter_inodes(current, context); if (context->current_state == AUDIT_RECORD_CONTEXT) audit_log_exit(); @@ -2400,7 +2397,7 @@ void __audit_ptrace(struct task_struct *t) context->target_auid = audit_get_loginuid(t); context->target_uid = task_uid(t); context->target_sessionid = audit_get_sessionid(t); - security_task_getsecid(t, &context->target_sid); + security_task_getsecid_obj(t, &context->target_sid); memcpy(context->target_comm, t->comm, TASK_COMM_LEN); } @@ -2427,7 +2424,7 @@ int audit_signal_info_syscall(struct task_struct *t) ctx->target_auid = audit_get_loginuid(t); ctx->target_uid = t_uid; ctx->target_sessionid = audit_get_sessionid(t); - security_task_getsecid(t, &ctx->target_sid); + security_task_getsecid_obj(t, &ctx->target_sid); memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN); return 0; } @@ -2448,7 +2445,7 @@ int audit_signal_info_syscall(struct task_struct *t) axp->target_auid[axp->pid_count] = audit_get_loginuid(t); axp->target_uid[axp->pid_count] = t_uid; axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t); - security_task_getsecid(t, &axp->target_sid[axp->pid_count]); + security_task_getsecid_obj(t, &axp->target_sid[axp->pid_count]); memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN); axp->pid_count++; diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 1622a44d1617e16d97a4a2470280696ba7e47812..0ff58259ccf84709a31a8f613dbbdaa417661d98 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -209,7 +209,8 @@ BTF_ID(func, bpf_lsm_socket_socketpair) BTF_ID(func, bpf_lsm_syslog) BTF_ID(func, bpf_lsm_task_alloc) -BTF_ID(func, bpf_lsm_task_getsecid) +BTF_ID(func, bpf_lsm_task_getsecid_subj) +BTF_ID(func, bpf_lsm_task_getsecid_obj) BTF_ID(func, bpf_lsm_task_prctl) BTF_ID(func, bpf_lsm_task_setscheduler) BTF_ID(func, bpf_lsm_task_to_inode) diff --git a/kernel/cfi.c b/kernel/cfi.c new file mode 100644 index 0000000000000000000000000000000000000000..e17a56639766be1b558768c1b410ef9373a0b160 --- /dev/null +++ b/kernel/cfi.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clang Control Flow Integrity (CFI) error and slowpath handling. + * + * Copyright (C) 2021 Google LLC + */ + +#include <linux/hardirq.h> +#include <linux/kallsyms.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/printk.h> +#include <linux/ratelimit.h> +#include <linux/rcupdate.h> +#include <linux/vmalloc.h> +#include <asm/cacheflush.h> +#include <asm/set_memory.h> + +/* Compiler-defined handler names */ +#ifdef CONFIG_CFI_PERMISSIVE +#define cfi_failure_handler __ubsan_handle_cfi_check_fail +#else +#define cfi_failure_handler __ubsan_handle_cfi_check_fail_abort +#endif + +static inline void handle_cfi_failure(void *ptr) +{ + if (IS_ENABLED(CONFIG_CFI_PERMISSIVE)) + WARN_RATELIMIT(1, "CFI failure (target: %pS):\n", ptr); + else + panic("CFI failure (target: %pS)\n", ptr); +} + +#ifdef CONFIG_MODULES +#ifdef CONFIG_CFI_CLANG_SHADOW +/* + * Index type. A 16-bit index can address at most (2^16)-2 pages (taking + * into account SHADOW_INVALID), i.e. ~256M with 4k pages. + */ +typedef u16 shadow_t; +#define SHADOW_INVALID ((shadow_t)~0UL) + +struct cfi_shadow { + /* Page index for the beginning of the shadow */ + unsigned long base; + /* An array of __cfi_check locations (as indices to the shadow) */ + shadow_t shadow[1]; +} __packed; + +/* + * The shadow covers ~128M from the beginning of the module region. If + * the region is larger, we fall back to __module_address for the rest. + */ +#define __SHADOW_RANGE (_UL(SZ_128M) >> PAGE_SHIFT) + +/* The in-memory size of struct cfi_shadow, always at least one page */ +#define __SHADOW_PAGES ((__SHADOW_RANGE * sizeof(shadow_t)) >> PAGE_SHIFT) +#define SHADOW_PAGES max(1UL, __SHADOW_PAGES) +#define SHADOW_SIZE (SHADOW_PAGES << PAGE_SHIFT) + +/* The actual size of the shadow array, minus metadata */ +#define SHADOW_ARR_SIZE (SHADOW_SIZE - offsetof(struct cfi_shadow, shadow)) +#define SHADOW_ARR_SLOTS (SHADOW_ARR_SIZE / sizeof(shadow_t)) + +static DEFINE_MUTEX(shadow_update_lock); +static struct cfi_shadow __rcu *cfi_shadow __read_mostly; + +/* Returns the index in the shadow for the given address */ +static inline int ptr_to_shadow(const struct cfi_shadow *s, unsigned long ptr) +{ + unsigned long index; + unsigned long page = ptr >> PAGE_SHIFT; + + if (unlikely(page < s->base)) + return -1; /* Outside of module area */ + + index = page - s->base; + + if (index >= SHADOW_ARR_SLOTS) + return -1; /* Cannot be addressed with shadow */ + + return (int)index; +} + +/* Returns the page address for an index in the shadow */ +static inline unsigned long shadow_to_ptr(const struct cfi_shadow *s, + int index) +{ + if (unlikely(index < 0 || index >= SHADOW_ARR_SLOTS)) + return 0; + + return (s->base + index) << PAGE_SHIFT; +} + +/* Returns the __cfi_check function address for the given shadow location */ +static inline unsigned long shadow_to_check_fn(const struct cfi_shadow *s, + int index) +{ + if (unlikely(index < 0 || index >= SHADOW_ARR_SLOTS)) + return 0; + + if (unlikely(s->shadow[index] == SHADOW_INVALID)) + return 0; + + /* __cfi_check is always page aligned */ + return (s->base + s->shadow[index]) << PAGE_SHIFT; +} + +static void prepare_next_shadow(const struct cfi_shadow __rcu *prev, + struct cfi_shadow *next) +{ + int i, index, check; + + /* Mark everything invalid */ + memset(next->shadow, 0xFF, SHADOW_ARR_SIZE); + + if (!prev) + return; /* No previous shadow */ + + /* If the base address didn't change, an update is not needed */ + if (prev->base == next->base) { + memcpy(next->shadow, prev->shadow, SHADOW_ARR_SIZE); + return; + } + + /* Convert the previous shadow to the new address range */ + for (i = 0; i < SHADOW_ARR_SLOTS; ++i) { + if (prev->shadow[i] == SHADOW_INVALID) + continue; + + index = ptr_to_shadow(next, shadow_to_ptr(prev, i)); + if (index < 0) + continue; + + check = ptr_to_shadow(next, + shadow_to_check_fn(prev, prev->shadow[i])); + if (check < 0) + continue; + + next->shadow[index] = (shadow_t)check; + } +} + +static void add_module_to_shadow(struct cfi_shadow *s, struct module *mod, + unsigned long min_addr, unsigned long max_addr) +{ + int check_index; + unsigned long check = (unsigned long)mod->cfi_check; + unsigned long ptr; + + if (unlikely(!PAGE_ALIGNED(check))) { + pr_warn("cfi: not using shadow for module %s\n", mod->name); + return; + } + + check_index = ptr_to_shadow(s, check); + if (check_index < 0) + return; /* Module not addressable with shadow */ + + /* For each page, store the check function index in the shadow */ + for (ptr = min_addr; ptr <= max_addr; ptr += PAGE_SIZE) { + int index = ptr_to_shadow(s, ptr); + + if (index >= 0) { + /* Each page must only contain one module */ + WARN_ON_ONCE(s->shadow[index] != SHADOW_INVALID); + s->shadow[index] = (shadow_t)check_index; + } + } +} + +static void remove_module_from_shadow(struct cfi_shadow *s, struct module *mod, + unsigned long min_addr, unsigned long max_addr) +{ + unsigned long ptr; + + for (ptr = min_addr; ptr <= max_addr; ptr += PAGE_SIZE) { + int index = ptr_to_shadow(s, ptr); + + if (index >= 0) + s->shadow[index] = SHADOW_INVALID; + } +} + +typedef void (*update_shadow_fn)(struct cfi_shadow *, struct module *, + unsigned long min_addr, unsigned long max_addr); + +static void update_shadow(struct module *mod, unsigned long base_addr, + update_shadow_fn fn) +{ + struct cfi_shadow *prev; + struct cfi_shadow *next; + unsigned long min_addr, max_addr; + + next = vmalloc(SHADOW_SIZE); + + mutex_lock(&shadow_update_lock); + prev = rcu_dereference_protected(cfi_shadow, + mutex_is_locked(&shadow_update_lock)); + + if (next) { + next->base = base_addr >> PAGE_SHIFT; + prepare_next_shadow(prev, next); + + min_addr = (unsigned long)mod->core_layout.base; + max_addr = min_addr + mod->core_layout.text_size; + fn(next, mod, min_addr & PAGE_MASK, max_addr & PAGE_MASK); + + set_memory_ro((unsigned long)next, SHADOW_PAGES); + } + + rcu_assign_pointer(cfi_shadow, next); + mutex_unlock(&shadow_update_lock); + synchronize_rcu(); + + if (prev) { + set_memory_rw((unsigned long)prev, SHADOW_PAGES); + vfree(prev); + } +} + +void cfi_module_add(struct module *mod, unsigned long base_addr) +{ + update_shadow(mod, base_addr, add_module_to_shadow); +} + +void cfi_module_remove(struct module *mod, unsigned long base_addr) +{ + update_shadow(mod, base_addr, remove_module_from_shadow); +} + +static inline cfi_check_fn ptr_to_check_fn(const struct cfi_shadow __rcu *s, + unsigned long ptr) +{ + int index; + + if (unlikely(!s)) + return NULL; /* No shadow available */ + + index = ptr_to_shadow(s, ptr); + if (index < 0) + return NULL; /* Cannot be addressed with shadow */ + + return (cfi_check_fn)shadow_to_check_fn(s, index); +} + +static inline cfi_check_fn find_shadow_check_fn(unsigned long ptr) +{ + cfi_check_fn fn; + + rcu_read_lock_sched(); + fn = ptr_to_check_fn(rcu_dereference_sched(cfi_shadow), ptr); + rcu_read_unlock_sched(); + + return fn; +} + +#else /* !CONFIG_CFI_CLANG_SHADOW */ + +static inline cfi_check_fn find_shadow_check_fn(unsigned long ptr) +{ + return NULL; +} + +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +static inline cfi_check_fn find_module_check_fn(unsigned long ptr) +{ + cfi_check_fn fn = NULL; + struct module *mod; + + rcu_read_lock_sched(); + mod = __module_address(ptr); + if (mod) + fn = mod->cfi_check; + rcu_read_unlock_sched(); + + return fn; +} + +static inline cfi_check_fn find_check_fn(unsigned long ptr) +{ + cfi_check_fn fn = NULL; + + if (is_kernel_text(ptr)) + return __cfi_check; + + /* + * Indirect call checks can happen when RCU is not watching. Both + * the shadow and __module_address use RCU, so we need to wake it + * up if necessary. + */ + RCU_NONIDLE({ + if (IS_ENABLED(CONFIG_CFI_CLANG_SHADOW)) + fn = find_shadow_check_fn(ptr); + + if (!fn) + fn = find_module_check_fn(ptr); + }); + + return fn; +} + +void __cfi_slowpath_diag(uint64_t id, void *ptr, void *diag) +{ + cfi_check_fn fn = find_check_fn((unsigned long)ptr); + + if (likely(fn)) + fn(id, ptr, diag); + else /* Don't allow unchecked modules */ + handle_cfi_failure(ptr); +} +EXPORT_SYMBOL(__cfi_slowpath_diag); + +#else /* !CONFIG_MODULES */ + +void __cfi_slowpath_diag(uint64_t id, void *ptr, void *diag) +{ + handle_cfi_failure(ptr); /* No modules */ +} +EXPORT_SYMBOL(__cfi_slowpath_diag); + +#endif /* CONFIG_MODULES */ + +void cfi_failure_handler(void *data, void *ptr, void *vtable) +{ + handle_cfi_failure(ptr); +} +EXPORT_SYMBOL(cfi_failure_handler); diff --git a/kernel/entry/common.c b/kernel/entry/common.c index 2003d69bd6d546ea0de777c76bbf1889c7e70775..a0b3b04fb5965995ea991f8aa6e375c62e8d9c2d 100644 --- a/kernel/entry/common.c +++ b/kernel/entry/common.c @@ -341,7 +341,7 @@ noinstr irqentry_state_t irqentry_enter(struct pt_regs *regs) * Checking for rcu_is_watching() here would prevent the nesting * interrupt to invoke rcu_irq_enter(). If that nested interrupt is * the tick then rcu_flavor_sched_clock_irq() would wrongfully - * assume that it is the first interupt and eventually claim + * assume that it is the first interrupt and eventually claim * quiescent state and end grace periods prematurely. * * Unconditionally invoke rcu_irq_enter() so RCU state stays diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index e2726b1f73fa10dc23b4486df23988578229af03..1d48bae8f84ccb6ce6143ac219886436744c29f1 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -776,7 +776,7 @@ EXPORT_SYMBOL_GPL(handle_fasteoi_nmi); * handle_edge_irq - edge type IRQ handler * @desc: the interrupt description structure for this irq * - * Interrupt occures on the falling and/or rising edge of a hardware + * Interrupt occurs on the falling and/or rising edge of a hardware * signal. The occurrence is latched into the irq controller hardware * and must be acked in order to be reenabled. After the ack another * interrupt can happen on the same source even before the first one @@ -823,7 +823,7 @@ void handle_edge_irq(struct irq_desc *desc) /* * When another irq arrived while we were handling * one, we could have masked the irq. - * Renable it, if it was not disabled in meantime. + * Reenable it, if it was not disabled in meantime. */ if (unlikely(desc->istate & IRQS_PENDING)) { if (!irqd_irq_disabled(&desc->irq_data) && @@ -1434,7 +1434,7 @@ EXPORT_SYMBOL_GPL(irq_chip_eoi_parent); * @dest: The affinity mask to set * @force: Flag to enforce setting (disable online checks) * - * Conditinal, as the underlying parent chip might not implement it. + * Conditional, as the underlying parent chip might not implement it. */ int irq_chip_set_affinity_parent(struct irq_data *data, const struct cpumask *dest, bool force) @@ -1546,7 +1546,7 @@ EXPORT_SYMBOL_GPL(irq_chip_release_resources_parent); #endif /** - * irq_chip_compose_msi_msg - Componse msi message for a irq chip + * irq_chip_compose_msi_msg - Compose msi message for a irq chip * @data: Pointer to interrupt specific data * @msg: Pointer to the MSI message * diff --git a/kernel/irq/dummychip.c b/kernel/irq/dummychip.c index 0b0cdf206dc44d7151171934344c6d17af26dea1..7fe6cffe7d0df8b3c336a17528ff041812ee9d26 100644 --- a/kernel/irq/dummychip.c +++ b/kernel/irq/dummychip.c @@ -13,7 +13,7 @@ /* * What should we do if we get a hw irq event on an illegal vector? - * Each architecture has to answer this themself. + * Each architecture has to answer this themselves. */ static void ack_bad(struct irq_data *data) { diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index 43e3d1be622c58afc1265038c66acd5235dc1294..52f11c791bf8a52c909e47b05334c8c0512c18d4 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -107,7 +107,7 @@ free_descs: * @irq: linux irq number to be destroyed * @dest: cpumask of cpus which should have the IPI removed * - * The IPIs allocated with irq_reserve_ipi() are retuerned to the system + * The IPIs allocated with irq_reserve_ipi() are returned to the system * destroying all virqs associated with them. * * Return 0 on success or error code on failure. diff --git a/kernel/irq/irq_sim.c b/kernel/irq/irq_sim.c index 40880c350b95d484c9c30bf3d3b72f1a56667721..0cd02efa3a742ed77fbcafb49869bf45e82520fa 100644 --- a/kernel/irq/irq_sim.c +++ b/kernel/irq/irq_sim.c @@ -24,10 +24,6 @@ struct irq_sim_irq_ctx { struct irq_sim_work_ctx *work_ctx; }; -struct irq_sim_devres { - struct irq_domain *domain; -}; - static void irq_sim_irqmask(struct irq_data *data) { struct irq_sim_irq_ctx *irq_ctx = irq_data_get_irq_chip_data(data); @@ -216,11 +212,11 @@ void irq_domain_remove_sim(struct irq_domain *domain) } EXPORT_SYMBOL_GPL(irq_domain_remove_sim); -static void devm_irq_domain_release_sim(struct device *dev, void *res) +static void devm_irq_domain_remove_sim(void *data) { - struct irq_sim_devres *this = res; + struct irq_domain *domain = data; - irq_domain_remove_sim(this->domain); + irq_domain_remove_sim(domain); } /** @@ -238,20 +234,17 @@ struct irq_domain *devm_irq_domain_create_sim(struct device *dev, struct fwnode_handle *fwnode, unsigned int num_irqs) { - struct irq_sim_devres *dr; + struct irq_domain *domain; + int ret; - dr = devres_alloc(devm_irq_domain_release_sim, - sizeof(*dr), GFP_KERNEL); - if (!dr) - return ERR_PTR(-ENOMEM); + domain = irq_domain_create_sim(fwnode, num_irqs); + if (IS_ERR(domain)) + return domain; - dr->domain = irq_domain_create_sim(fwnode, num_irqs); - if (IS_ERR(dr->domain)) { - devres_free(dr); - return dr->domain; - } + ret = devm_add_action_or_reset(dev, devm_irq_domain_remove_sim, domain); + if (ret) + return ERR_PTR(ret); - devres_add(dev, dr); - return dr->domain; + return domain; } EXPORT_SYMBOL_GPL(devm_irq_domain_create_sim); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 1076b6799ed46f7f1af7247580f7296b3bf08fb5..4383d16e306877269a23ecb3b0a70d93f28cd7fb 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -31,7 +31,7 @@ static int __init irq_affinity_setup(char *str) cpulist_parse(str, irq_default_affinity); /* * Set at least the boot cpu. We don't want to end up with - * bugreports caused by random comandline masks + * bugreports caused by random commandline masks */ cpumask_set_cpu(smp_processor_id(), irq_default_affinity); return 1; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index d10ab1d689d58c39c72b8e615b0e64807f082d7c..f42ef868efd3f229672009486f6443a389f31c18 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops); * @name: Optional user provided domain name * @pa: Optional user-provided physical address * - * Allocate a struct irqchip_fwid, and return a poiner to the embedded + * Allocate a struct irqchip_fwid, and return a pointer to the embedded * fwnode_handle (or NULL on failure). * * Note: The types IRQCHIP_FWNODE_NAMED and IRQCHIP_FWNODE_NAMED_ID are @@ -665,7 +665,7 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain, pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); - /* Look for default domain if nececssary */ + /* Look for default domain if necessary */ if (domain == NULL) domain = irq_default_domain; if (domain == NULL) { @@ -703,41 +703,6 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain, } EXPORT_SYMBOL_GPL(irq_create_mapping_affinity); -/** - * irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs - * @domain: domain owning the interrupt range - * @irq_base: beginning of linux IRQ range - * @hwirq_base: beginning of hardware IRQ range - * @count: Number of interrupts to map - * - * This routine is used for allocating and mapping a range of hardware - * irqs to linux irqs where the linux irq numbers are at pre-defined - * locations. For use by controllers that already have static mappings - * to insert in to the domain. - * - * Non-linear users can use irq_create_identity_mapping() for IRQ-at-a-time - * domain insertion. - * - * 0 is returned upon success, while any failure to establish a static - * mapping is treated as an error. - */ -int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base, - irq_hw_number_t hwirq_base, int count) -{ - struct device_node *of_node; - int ret; - - of_node = irq_domain_get_of_node(domain); - ret = irq_alloc_descs(irq_base, irq_base, count, - of_node_to_nid(of_node)); - if (unlikely(ret < 0)) - return ret; - - irq_domain_associate_many(domain, irq_base, hwirq_base, count); - return 0; -} -EXPORT_SYMBOL_GPL(irq_create_strict_mappings); - static int irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, irq_hw_number_t *hwirq, unsigned int *type) @@ -906,7 +871,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain, { struct irq_data *data; - /* Look for default domain if nececssary */ + /* Look for default domain if necessary */ if (domain == NULL) domain = irq_default_domain; if (domain == NULL) @@ -1436,7 +1401,7 @@ int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain, * The whole process to setup an IRQ has been split into two steps. * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ * descriptor and required hardware resources. The second step, - * irq_domain_activate_irq(), is to program hardwares with preallocated + * irq_domain_activate_irq(), is to program the hardware with preallocated * resources. In this way, it's easier to rollback when failing to * allocate resources. */ @@ -1694,12 +1659,10 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) /** * irq_domain_alloc_irqs_parent - Allocate interrupts from parent domain + * @domain: Domain below which interrupts must be allocated * @irq_base: Base IRQ number * @nr_irqs: Number of IRQs to allocate * @arg: Allocation data (arch/domain specific) - * - * Check whether the domain has been setup recursive. If not allocate - * through the parent domain. */ int irq_domain_alloc_irqs_parent(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs, @@ -1715,11 +1678,9 @@ EXPORT_SYMBOL_GPL(irq_domain_alloc_irqs_parent); /** * irq_domain_free_irqs_parent - Free interrupts from parent domain + * @domain: Domain below which interrupts must be freed * @irq_base: Base IRQ number * @nr_irqs: Number of IRQs to free - * - * Check whether the domain has been setup recursive. If not free - * through the parent domain. */ void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 21ea370fccda704050b2c8abddbb65adf0c7ed8b..4c14356543d93bc394c12fbee9aee4418dafeed8 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -179,7 +179,7 @@ bool irq_can_set_affinity_usr(unsigned int irq) /** * irq_set_thread_affinity - Notify irq threads to adjust affinity - * @desc: irq descriptor which has affitnity changed + * @desc: irq descriptor which has affinity changed * * We just set IRQTF_AFFINITY and delegate the affinity setting * to the interrupt thread itself. We can not call @@ -326,7 +326,7 @@ static bool irq_set_affinity_deactivated(struct irq_data *data, * If the interrupt is not yet activated, just store the affinity * mask and do not call the chip driver at all. On activation the * driver has to make sure anyway that the interrupt is in a - * useable state so startup works. + * usable state so startup works. */ if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) || irqd_is_activated(data) || !irqd_affinity_on_activate(data)) @@ -1054,7 +1054,7 @@ again: * to IRQS_INPROGRESS and the irq line is masked forever. * * This also serializes the state of shared oneshot handlers - * versus "desc->threads_onehsot |= action->thread_mask;" in + * versus "desc->threads_oneshot |= action->thread_mask;" in * irq_wake_thread(). See the comment there which explains the * serialization. */ @@ -1157,7 +1157,7 @@ irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action) /* * Interrupts explicitly requested as threaded interrupts want to be - * preemtible - many of them need to sleep and wait for slow busses to + * preemptible - many of them need to sleep and wait for slow busses to * complete. */ static irqreturn_t irq_thread_fn(struct irq_desc *desc, @@ -1697,7 +1697,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) irqd_set(&desc->irq_data, IRQD_NO_BALANCING); } - if (irq_settings_can_autoenable(desc)) { + if (!(new->flags & IRQF_NO_AUTOEN) && + irq_settings_can_autoenable(desc)) { irq_startup(desc, IRQ_RESEND, IRQ_START_COND); } else { /* @@ -1912,7 +1913,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id) /* Last action releases resources */ if (!desc->action) { /* - * Reaquire bus lock as irq_release_resources() might + * Reacquire bus lock as irq_release_resources() might * require it to deallocate resources over the slow bus. */ chip_bus_lock(desc); @@ -2090,10 +2091,15 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, * which interrupt is which (messes up the interrupt freeing * logic etc). * + * Also shared interrupts do not go well with disabling auto enable. + * The sharing interrupt might request it while it's still disabled + * and then wait for interrupts forever. + * * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and * it cannot be set along with IRQF_NO_SUSPEND. */ if (((irqflags & IRQF_SHARED) && !dev_id) || + ((irqflags & IRQF_SHARED) && (irqflags & IRQF_NO_AUTOEN)) || (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) || ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND))) return -EINVAL; @@ -2249,7 +2255,8 @@ int request_nmi(unsigned int irq, irq_handler_t handler, desc = irq_to_desc(irq); - if (!desc || irq_settings_can_autoenable(desc) || + if (!desc || (irq_settings_can_autoenable(desc) && + !(irqflags & IRQF_NO_AUTOEN)) || !irq_settings_can_request(desc) || WARN_ON(irq_settings_is_per_cpu_devid(desc)) || !irq_supports_nmi(desc)) @@ -2746,7 +2753,7 @@ int __irq_get_irqchip_state(struct irq_data *data, enum irqchip_irq_state which, * irq_get_irqchip_state - returns the irqchip state of a interrupt. * @irq: Interrupt line that is forwarded to a VM * @which: One of IRQCHIP_STATE_* the caller wants to know about - * @state: a pointer to a boolean where the state is to be storeed + * @state: a pointer to a boolean where the state is to be stored * * This call snapshots the internal irqchip state of an * interrupt, returning into @state the bit corresponding to diff --git a/kernel/irq/matrix.c b/kernel/irq/matrix.c index 651a4ad6d711f82d8192d07a6b7616ef9337651f..578596e41cb60731cdae15038e5ad0df03dd647c 100644 --- a/kernel/irq/matrix.c +++ b/kernel/irq/matrix.c @@ -337,15 +337,14 @@ void irq_matrix_assign(struct irq_matrix *m, unsigned int bit) * irq_matrix_reserve - Reserve interrupts * @m: Matrix pointer * - * This is merily a book keeping call. It increments the number of globally + * This is merely a book keeping call. It increments the number of globally * reserved interrupt bits w/o actually allocating them. This allows to * setup interrupt descriptors w/o assigning low level resources to it. * The actual allocation happens when the interrupt gets activated. */ void irq_matrix_reserve(struct irq_matrix *m) { - if (m->global_reserved <= m->global_available && - m->global_reserved + 1 > m->global_available) + if (m->global_reserved == m->global_available) pr_warn("Interrupt reservation exceeds available resources\n"); m->global_reserved++; @@ -356,7 +355,7 @@ void irq_matrix_reserve(struct irq_matrix *m) * irq_matrix_remove_reserved - Remove interrupt reservation * @m: Matrix pointer * - * This is merily a book keeping call. It decrements the number of globally + * This is merely a book keeping call. It decrements the number of globally * reserved interrupt bits. This is used to undo irq_matrix_reserve() when the * interrupt was never in use and a real vector allocated, which undid the * reservation. @@ -423,7 +422,9 @@ void irq_matrix_free(struct irq_matrix *m, unsigned int cpu, if (WARN_ON_ONCE(bit < m->alloc_start || bit >= m->alloc_end)) return; - clear_bit(bit, cm->alloc_map); + if (WARN_ON_ONCE(!test_and_clear_bit(bit, cm->alloc_map))) + return; + cm->allocated--; if(managed) cm->managed_allocated--; diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index def48589ea484d44188b8c574cadacfabf21b827..61ca924ef4b4c2d5fff88ba5b85b8993b69698c0 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -7,7 +7,7 @@ /** * irq_fixup_move_pending - Cleanup irq move pending from a dying CPU - * @desc: Interrupt descpriptor to clean up + * @desc: Interrupt descriptor to clean up * @force_clear: If set clear the move pending bit unconditionally. * If not set, clear it only when the dying CPU is the * last one in the pending mask. diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index b338d622f26e330e0e889c1453fec4b4849eab79..c41965e348b5bbfd737a3de0eb04d462e285cf45 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -5,7 +5,7 @@ * * This file is licensed under GPLv2. * - * This file contains common code to support Message Signalled Interrupt for + * This file contains common code to support Message Signaled Interrupts for * PCI compatible and non PCI compatible devices. */ #include <linux/types.h> diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 98138788cb04df4b1a6956f6c49bb131a7c94388..7c5cd42df3b93e7b5bb15bbd9978864fbe80debc 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -144,7 +144,7 @@ static ssize_t write_irq_affinity(int type, struct file *file, if (!irq_can_set_affinity_usr(irq) || no_irq_affinity) return -EIO; - if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) + if (!zalloc_cpumask_var(&new_value, GFP_KERNEL)) return -ENOMEM; if (type) @@ -238,7 +238,7 @@ static ssize_t default_affinity_write(struct file *file, cpumask_var_t new_value; int err; - if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) + if (!zalloc_cpumask_var(&new_value, GFP_KERNEL)) return -ENOMEM; err = cpumask_parse_user(buffer, count, new_value); diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index bd1d85c610aab9d3eb3ffdfb38b61aa3ce3d500f..0c46e9fe3a89de94dd32366ae93215f755d426b9 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -128,7 +128,7 @@ int check_irq_resend(struct irq_desc *desc, bool inject) if (!try_retrigger(desc)) err = irq_sw_resend(desc); - /* If the retrigger was successfull, mark it with the REPLAY bit */ + /* If the retrigger was successful, mark it with the REPLAY bit */ if (!err) desc->istate |= IRQS_REPLAY; return err; diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index f865e5f4d3825461bc4e1994eb4da80981b7e3fc..c481d845832573e94fbdda078b38972a241368b2 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -403,6 +403,10 @@ void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret) desc->irqs_unhandled -= ok; } + if (likely(!desc->irqs_unhandled)) + return; + + /* Now getting into unhandled irq detection */ desc->irq_count++; if (likely(desc->irq_count < 100000)) return; diff --git a/kernel/irq/timings.c b/kernel/irq/timings.c index 773b6105c4aea2843afb3f49313e4dff768af1c0..d309d6fbf5bddc18293b12dcae2d1757b8609119 100644 --- a/kernel/irq/timings.c +++ b/kernel/irq/timings.c @@ -84,7 +84,7 @@ void irq_timings_disable(void) * 2. Log interval * * We saw the irq timings allow to compute the interval of the - * occurrences for a specific interrupt. We can reasonibly assume the + * occurrences for a specific interrupt. We can reasonably assume the * longer is the interval, the higher is the error for the next event * and we can consider storing those interval values into an array * where each slot in the array correspond to an interval at the power @@ -416,7 +416,7 @@ static u64 __irq_timings_next_event(struct irqt_stat *irqs, int irq, u64 now) * Copy the content of the circular buffer into another buffer * in order to linearize the buffer instead of dealing with * wrapping indexes and shifted array which will be prone to - * error and extremelly difficult to debug. + * error and extremely difficult to debug. */ for (i = 0; i < count; i++) { int index = (start + i) & IRQ_TIMINGS_MASK; @@ -485,7 +485,7 @@ static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts) /* * The interrupt triggered more than one second apart, that - * ends the sequence as predictible for our purpose. In this + * ends the sequence as predictable for our purpose. In this * case, assume we have the beginning of a sequence and the * timestamp is the first value. As it is impossible to * predict anything at this point, return. @@ -514,7 +514,7 @@ static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts) * If more than the array size interrupts happened during the * last busy/idle cycle, the index wrapped up and we have to * begin with the next element in the array which is the last one - * in the sequence, otherwise it is a the index 0. + * in the sequence, otherwise it is at the index 0. * * - have an indication of the interrupts activity on this CPU * (eg. irq/sec) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 8043a90aa50ed30f3d8fb4abf9944373a8771705..c851ca0ed357620f62696674a119b789e3e7dc47 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -161,6 +161,27 @@ static unsigned long kallsyms_sym_address(int idx) return kallsyms_relative_base - 1 - kallsyms_offsets[idx]; } +#if defined(CONFIG_CFI_CLANG) && defined(CONFIG_LTO_CLANG_THIN) +/* + * LLVM appends a hash to static function names when ThinLTO and CFI are + * both enabled, i.e. foo() becomes foo$707af9a22804d33c81801f27dcfe489b. + * This causes confusion and potentially breaks user space tools, so we + * strip the suffix from expanded symbol names. + */ +static inline bool cleanup_symbol_name(char *s) +{ + char *res; + + res = strrchr(s, '$'); + if (res) + *res = '\0'; + + return res != NULL; +} +#else +static inline bool cleanup_symbol_name(char *s) { return false; } +#endif + /* Lookup the address for this symbol. Returns 0 if not found. */ unsigned long kallsyms_lookup_name(const char *name) { @@ -173,6 +194,9 @@ unsigned long kallsyms_lookup_name(const char *name) if (strcmp(namebuf, name) == 0) return kallsyms_sym_address(i); + + if (cleanup_symbol_name(namebuf) && strcmp(namebuf, name) == 0) + return kallsyms_sym_address(i); } return module_kallsyms_lookup_name(name); } @@ -303,7 +327,9 @@ const char *kallsyms_lookup(unsigned long addr, namebuf, KSYM_NAME_LEN); if (modname) *modname = NULL; - return namebuf; + + ret = namebuf; + goto found; } /* See if it's in a module or a BPF JITed image. */ @@ -316,11 +342,16 @@ const char *kallsyms_lookup(unsigned long addr, if (!ret) ret = ftrace_mod_address_lookup(addr, symbolsize, offset, modname, namebuf); + +found: + cleanup_symbol_name(namebuf); return ret; } int lookup_symbol_name(unsigned long addr, char *symname) { + int res; + symname[0] = '\0'; symname[KSYM_NAME_LEN - 1] = '\0'; @@ -331,15 +362,23 @@ int lookup_symbol_name(unsigned long addr, char *symname) /* Grab name */ kallsyms_expand_symbol(get_symbol_offset(pos), symname, KSYM_NAME_LEN); - return 0; + goto found; } /* See if it's in a module. */ - return lookup_module_symbol_name(addr, symname); + res = lookup_module_symbol_name(addr, symname); + if (res) + return res; + +found: + cleanup_symbol_name(symname); + return 0; } int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name) { + int res; + name[0] = '\0'; name[KSYM_NAME_LEN - 1] = '\0'; @@ -351,10 +390,16 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, kallsyms_expand_symbol(get_symbol_offset(pos), name, KSYM_NAME_LEN); modname[0] = '\0'; - return 0; + goto found; } /* See if it's in a module. */ - return lookup_module_symbol_attrs(addr, size, offset, modname, name); + res = lookup_module_symbol_attrs(addr, size, offset, modname, name); + if (res) + return res; + +found: + cleanup_symbol_name(name); + return 0; } /* Look up a kernel symbol and return it in a text buffer. */ diff --git a/kernel/kthread.c b/kernel/kthread.c index 028cff2576ef8cd3d0634aba5fc116f659cd1f62..2e2134a51fd2f50d302eff7bc6135328d19197ba 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -964,7 +964,8 @@ static void __kthread_queue_delayed_work(struct kthread_worker *worker, struct timer_list *timer = &dwork->timer; struct kthread_work *work = &dwork->work; - WARN_ON_ONCE(timer->function != kthread_delayed_work_timer_fn); + WARN_ON_FUNCTION_MISMATCH(timer->function, + kthread_delayed_work_timer_fn); /* * If @delay is 0, queue @dwork->work immediately. This is for diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index f160f1c97ca1ea39f48417ce937720b0d8ac2a39..ef28a0b9cf1efa21807d9aafa0e41cfeb4560ed6 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -1393,7 +1393,7 @@ static int add_lock_to_list(struct lock_class *this, /* * For good efficiency of modular, we use power of 2 */ -#define MAX_CIRCULAR_QUEUE_SIZE 4096UL +#define MAX_CIRCULAR_QUEUE_SIZE (1UL << CONFIG_LOCKDEP_CIRCULAR_QUEUE_BITS) #define CQ_MASK (MAX_CIRCULAR_QUEUE_SIZE-1) /* diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_internals.h index de49f9e1c11ba8be13fffcda9159c9c91db16e85..ecb8662e7a4ed52c7935b19d280e79458af6c30b 100644 --- a/kernel/locking/lockdep_internals.h +++ b/kernel/locking/lockdep_internals.h @@ -99,16 +99,16 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ = #define MAX_STACK_TRACE_ENTRIES 262144UL #define STACK_TRACE_HASH_SIZE 8192 #else -#define MAX_LOCKDEP_ENTRIES 32768UL +#define MAX_LOCKDEP_ENTRIES (1UL << CONFIG_LOCKDEP_BITS) -#define MAX_LOCKDEP_CHAINS_BITS 16 +#define MAX_LOCKDEP_CHAINS_BITS CONFIG_LOCKDEP_CHAINS_BITS /* * Stack-trace: tightly packed array of stack backtrace * addresses. Protected by the hash_lock. */ -#define MAX_STACK_TRACE_ENTRIES 524288UL -#define STACK_TRACE_HASH_SIZE 16384 +#define MAX_STACK_TRACE_ENTRIES (1UL << CONFIG_LOCKDEP_STACK_TRACE_BITS) +#define STACK_TRACE_HASH_SIZE (1 << CONFIG_LOCKDEP_STACK_TRACE_HASH_BITS) #endif /* diff --git a/kernel/module.c b/kernel/module.c index 62822b4a246a109bd8b93892c92fe9e843328918..5b0eaaeaaa1280b070bdf6b10d6be12be7f92e46 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2148,6 +2148,8 @@ void __weak module_arch_freeing_init(struct module *mod) { } +static void cfi_cleanup(struct module *mod); + /* Free a module, remove from lists, etc. */ static void free_module(struct module *mod) { @@ -2189,6 +2191,9 @@ static void free_module(struct module *mod) synchronize_rcu(); mutex_unlock(&module_mutex); + /* Clean up CFI for the module. */ + cfi_cleanup(mod); + /* This may be empty, but that's OK */ module_arch_freeing_init(mod); module_memfree(mod->init_layout.base); @@ -3868,6 +3873,8 @@ static int unknown_module_param_cb(char *param, char *val, const char *modname, return 0; } +static void cfi_init(struct module *mod); + /* * Allocate and load the module: note that size of section 0 is always * zero, and we rely on this for optional sections. @@ -3999,6 +4006,9 @@ static int load_module(struct load_info *info, const char __user *uargs, flush_module_icache(mod); + /* Setup CFI for the module. */ + cfi_init(mod); + /* Now copy in args */ mod->args = strndup_user(uargs, ~0UL >> 1); if (IS_ERR(mod->args)) { @@ -4072,6 +4082,7 @@ static int load_module(struct load_info *info, const char __user *uargs, synchronize_rcu(); kfree(mod->args); free_arch_cleanup: + cfi_cleanup(mod); module_arch_cleanup(mod); free_modinfo: free_modinfo(mod); @@ -4417,6 +4428,38 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, #endif /* CONFIG_LIVEPATCH */ #endif /* CONFIG_KALLSYMS */ +static void cfi_init(struct module *mod) +{ +#ifdef CONFIG_CFI_CLANG + initcall_t *init; + exitcall_t *exit; + + rcu_read_lock_sched(); + mod->cfi_check = (cfi_check_fn) + find_kallsyms_symbol_value(mod, "__cfi_check"); + init = (initcall_t *) + find_kallsyms_symbol_value(mod, "__cfi_jt_init_module"); + exit = (exitcall_t *) + find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module"); + rcu_read_unlock_sched(); + + /* Fix init/exit functions to point to the CFI jump table */ + if (init) + mod->init = *init; + if (exit) + mod->exit = *exit; + + cfi_module_add(mod, module_addr_min); +#endif +} + +static void cfi_cleanup(struct module *mod) +{ +#ifdef CONFIG_CFI_CLANG + cfi_module_remove(mod, module_addr_min); +#endif +} + /* Maximum number of characters written by module_flags() */ #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4) diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c index 9af5a50d348994c001505074c3fa9f5639b9b308..b29c8aca7486cd7761acf34e1996864032777ec8 100644 --- a/kernel/power/autosleep.c +++ b/kernel/power/autosleep.c @@ -54,7 +54,7 @@ static void try_to_suspend(struct work_struct *work) goto out; /* - * If the wakeup occured for an unknown reason, wait to prevent the + * If the wakeup occurred for an unknown reason, wait to prevent the * system from trying to suspend and waking up in a tight loop. */ if (final_count == initial_count) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index d63560e1cf8715d6952b74570c30a1c69b1e7c74..1a221dcb3c01cb107769cc6c3e0475ca710711cc 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -329,7 +329,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size) /** * Data types related to memory bitmaps. * - * Memory bitmap is a structure consiting of many linked lists of + * Memory bitmap is a structure consisting of many linked lists of * objects. The main list's elements are of type struct zone_bitmap * and each of them corresonds to one zone. For each zone bitmap * object there is a list of objects of type struct bm_block that diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 72e33054a2e1b72d7b9c529d59105a51ea9dc9e6..bea3cb8afa11261e6262ba9de30b3d68eae602f8 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -884,7 +884,7 @@ out_clean: * enough_swap - Make sure we have enough swap to save the image. * * Returns TRUE or FALSE after checking the total amount of swap - * space avaiable from the resume partition. + * space available from the resume partition. */ static int enough_swap(unsigned int nr_pages) diff --git a/kernel/profile.c b/kernel/profile.c index 6f69a4195d5630bdd9217bfd183579fd117d3976..c2ebddb5e97466a99612adc40a9672249eee9bfc 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -430,7 +430,7 @@ static ssize_t prof_cpu_mask_proc_write(struct file *file, cpumask_var_t new_value; int err; - if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) + if (!zalloc_cpumask_var(&new_value, GFP_KERNEL)) return -ENOMEM; err = cpumask_parse_user(buffer, count, new_value); diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 8f6c6c153ba27c9c99b1ee2f8f2bbc3dfedf4c6d..0939cd47f722f3ddd3e07163a6bcda4b0bcf0ad2 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -121,19 +121,8 @@ static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time, return true; } -static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time, - unsigned int next_freq) +static void sugov_deferred_update(struct sugov_policy *sg_policy) { - if (sugov_update_next_freq(sg_policy, time, next_freq)) - cpufreq_driver_fast_switch(sg_policy->policy, next_freq); -} - -static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time, - unsigned int next_freq) -{ - if (!sugov_update_next_freq(sg_policy, time, next_freq)) - return; - if (!sg_policy->work_in_progress) { sg_policy->work_in_progress = true; irq_work_queue(&sg_policy->irq_work); @@ -378,16 +367,19 @@ static void sugov_update_single_freq(struct update_util_data *hook, u64 time, sg_policy->cached_raw_freq = cached_freq; } + if (!sugov_update_next_freq(sg_policy, time, next_f)) + return; + /* * This code runs under rq->lock for the target CPU, so it won't run * concurrently on two different CPUs for the same target and it is not * necessary to acquire the lock in the fast switch case. */ if (sg_policy->policy->fast_switch_enabled) { - sugov_fast_switch(sg_policy, time, next_f); + cpufreq_driver_fast_switch(sg_policy->policy, next_f); } else { raw_spin_lock(&sg_policy->update_lock); - sugov_deferred_update(sg_policy, time, next_f); + sugov_deferred_update(sg_policy); raw_spin_unlock(&sg_policy->update_lock); } } @@ -466,12 +458,15 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags) if (sugov_should_update_freq(sg_policy, time)) { next_f = sugov_next_freq_shared(sg_cpu, time); + if (!sugov_update_next_freq(sg_policy, time, next_f)) + goto unlock; + if (sg_policy->policy->fast_switch_enabled) - sugov_fast_switch(sg_policy, time, next_f); + cpufreq_driver_fast_switch(sg_policy->policy, next_f); else - sugov_deferred_update(sg_policy, time, next_f); + sugov_deferred_update(sg_policy); } - +unlock: raw_spin_unlock(&sg_policy->update_lock); } diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 2412a595f183b478079d21769461efef83731a04..e83d8c6ad0e4a815375c236cb3e8ec386280ef8b 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -62,7 +62,7 @@ void irqtime_account_irq(struct task_struct *curr, unsigned int offset) cpu = smp_processor_id(); delta = sched_clock_cpu(cpu) - irqtime->irq_start_time; irqtime->irq_start_time += delta; - pc = preempt_count() - offset; + pc = irq_count() - offset; /* * We do not account for softirq time from ksoftirqd here. @@ -429,7 +429,7 @@ void vtime_task_switch(struct task_struct *prev) void vtime_account_irq(struct task_struct *tsk, unsigned int offset) { - unsigned int pc = preempt_count() - offset; + unsigned int pc = irq_count() - offset; if (pc & HARDIRQ_OFFSET) { vtime_account_hardirq(tsk); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 1d60fc2c99871e83ed69e9558506f503e4cacefc..1e63db4dbd9a8cdaf7c9392a6ab091f2f02e008c 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -817,7 +817,7 @@ static void seccomp_cache_prepare_bitmap(struct seccomp_filter *sfilter, } /** - * seccomp_cache_prepare - emulate the filter to find cachable syscalls + * seccomp_cache_prepare - emulate the filter to find cacheable syscalls * @sfilter: The seccomp filter * * Returns 0 if successful or -errno if error occurred. diff --git a/kernel/softirq.c b/kernel/softirq.c index 6770c277e6c82a7e5d32afb03abd270c1f6db45f..607cf474a3488ff583cd1a64ecbc888fc8c73b65 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -13,6 +13,7 @@ #include <linux/kernel_stat.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/local_lock.h> #include <linux/mm.h> #include <linux/notifier.h> #include <linux/percpu.h> @@ -25,6 +26,7 @@ #include <linux/smpboot.h> #include <linux/tick.h> #include <linux/irq.h> +#include <linux/wait_bit.h> #include <asm/softirq_stack.h> @@ -105,20 +107,204 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context); #endif /* - * preempt_count and SOFTIRQ_OFFSET usage: - * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving - * softirq processing. - * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET) + * SOFTIRQ_OFFSET usage: + * + * On !RT kernels 'count' is the preempt counter, on RT kernels this applies + * to a per CPU counter and to task::softirqs_disabled_cnt. + * + * - count is changed by SOFTIRQ_OFFSET on entering or leaving softirq + * processing. + * + * - count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET) * on local_bh_disable or local_bh_enable. + * * This lets us distinguish between whether we are currently processing * softirq and whether we just have bh disabled. */ +#ifdef CONFIG_PREEMPT_RT + +/* + * RT accounts for BH disabled sections in task::softirqs_disabled_cnt and + * also in per CPU softirq_ctrl::cnt. This is necessary to allow tasks in a + * softirq disabled section to be preempted. + * + * The per task counter is used for softirq_count(), in_softirq() and + * in_serving_softirqs() because these counts are only valid when the task + * holding softirq_ctrl::lock is running. + * + * The per CPU counter prevents pointless wakeups of ksoftirqd in case that + * the task which is in a softirq disabled section is preempted or blocks. + */ +struct softirq_ctrl { + local_lock_t lock; + int cnt; +}; + +static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = { + .lock = INIT_LOCAL_LOCK(softirq_ctrl.lock), +}; + +/** + * local_bh_blocked() - Check for idle whether BH processing is blocked + * + * Returns false if the per CPU softirq::cnt is 0 otherwise true. + * + * This is invoked from the idle task to guard against false positive + * softirq pending warnings, which would happen when the task which holds + * softirq_ctrl::lock was the only running task on the CPU and blocks on + * some other lock. + */ +bool local_bh_blocked(void) +{ + return __this_cpu_read(softirq_ctrl.cnt) != 0; +} + +void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) +{ + unsigned long flags; + int newcnt; + + WARN_ON_ONCE(in_hardirq()); + + /* First entry of a task into a BH disabled section? */ + if (!current->softirq_disable_cnt) { + if (preemptible()) { + local_lock(&softirq_ctrl.lock); + /* Required to meet the RCU bottomhalf requirements. */ + rcu_read_lock(); + } else { + DEBUG_LOCKS_WARN_ON(this_cpu_read(softirq_ctrl.cnt)); + } + } + + /* + * Track the per CPU softirq disabled state. On RT this is per CPU + * state to allow preemption of bottom half disabled sections. + */ + newcnt = __this_cpu_add_return(softirq_ctrl.cnt, cnt); + /* + * Reflect the result in the task state to prevent recursion on the + * local lock and to make softirq_count() & al work. + */ + current->softirq_disable_cnt = newcnt; + + if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && newcnt == cnt) { + raw_local_irq_save(flags); + lockdep_softirqs_off(ip); + raw_local_irq_restore(flags); + } +} +EXPORT_SYMBOL(__local_bh_disable_ip); + +static void __local_bh_enable(unsigned int cnt, bool unlock) +{ + unsigned long flags; + int newcnt; + + DEBUG_LOCKS_WARN_ON(current->softirq_disable_cnt != + this_cpu_read(softirq_ctrl.cnt)); + + if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && softirq_count() == cnt) { + raw_local_irq_save(flags); + lockdep_softirqs_on(_RET_IP_); + raw_local_irq_restore(flags); + } + + newcnt = __this_cpu_sub_return(softirq_ctrl.cnt, cnt); + current->softirq_disable_cnt = newcnt; + + if (!newcnt && unlock) { + rcu_read_unlock(); + local_unlock(&softirq_ctrl.lock); + } +} + +void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) +{ + bool preempt_on = preemptible(); + unsigned long flags; + u32 pending; + int curcnt; + + WARN_ON_ONCE(in_irq()); + lockdep_assert_irqs_enabled(); + + local_irq_save(flags); + curcnt = __this_cpu_read(softirq_ctrl.cnt); + + /* + * If this is not reenabling soft interrupts, no point in trying to + * run pending ones. + */ + if (curcnt != cnt) + goto out; + + pending = local_softirq_pending(); + if (!pending || ksoftirqd_running(pending)) + goto out; + + /* + * If this was called from non preemptible context, wake up the + * softirq daemon. + */ + if (!preempt_on) { + wakeup_softirqd(); + goto out; + } + + /* + * Adjust softirq count to SOFTIRQ_OFFSET which makes + * in_serving_softirq() become true. + */ + cnt = SOFTIRQ_OFFSET; + __local_bh_enable(cnt, false); + __do_softirq(); + +out: + __local_bh_enable(cnt, preempt_on); + local_irq_restore(flags); +} +EXPORT_SYMBOL(__local_bh_enable_ip); + +/* + * Invoked from ksoftirqd_run() outside of the interrupt disabled section + * to acquire the per CPU local lock for reentrancy protection. + */ +static inline void ksoftirqd_run_begin(void) +{ + __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); + local_irq_disable(); +} + +/* Counterpart to ksoftirqd_run_begin() */ +static inline void ksoftirqd_run_end(void) +{ + __local_bh_enable(SOFTIRQ_OFFSET, true); + WARN_ON_ONCE(in_interrupt()); + local_irq_enable(); +} + +static inline void softirq_handle_begin(void) { } +static inline void softirq_handle_end(void) { } + +static inline bool should_wake_ksoftirqd(void) +{ + return !this_cpu_read(softirq_ctrl.cnt); +} + +static inline void invoke_softirq(void) +{ + if (should_wake_ksoftirqd()) + wakeup_softirqd(); +} + +#else /* CONFIG_PREEMPT_RT */ -#ifdef CONFIG_TRACE_IRQFLAGS /* - * This is for softirq.c-internal use, where hardirqs are disabled + * This one is for softirq.c-internal use, where hardirqs are disabled * legitimately: */ +#ifdef CONFIG_TRACE_IRQFLAGS void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) { unsigned long flags; @@ -209,6 +395,32 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) } EXPORT_SYMBOL(__local_bh_enable_ip); +static inline void softirq_handle_begin(void) +{ + __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); +} + +static inline void softirq_handle_end(void) +{ + __local_bh_enable(SOFTIRQ_OFFSET); + WARN_ON_ONCE(in_interrupt()); +} + +static inline void ksoftirqd_run_begin(void) +{ + local_irq_disable(); +} + +static inline void ksoftirqd_run_end(void) +{ + local_irq_enable(); +} + +static inline bool should_wake_ksoftirqd(void) +{ + return true; +} + static inline void invoke_softirq(void) { if (ksoftirqd_running(local_softirq_pending())) @@ -253,6 +465,8 @@ asmlinkage __visible void do_softirq(void) local_irq_restore(flags); } +#endif /* !CONFIG_PREEMPT_RT */ + /* * We restart softirq processing for at most MAX_SOFTIRQ_RESTART times, * but break the loop if need_resched() is set or after 2 ms. @@ -321,7 +535,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) pending = local_softirq_pending(); - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); + softirq_handle_begin(); in_hardirq = lockdep_softirq_start(); account_softirq_enter(current); @@ -357,8 +571,10 @@ restart: pending >>= softirq_bit; } - if (__this_cpu_read(ksoftirqd) == current) + if (!IS_ENABLED(CONFIG_PREEMPT_RT) && + __this_cpu_read(ksoftirqd) == current) rcu_softirq_qs(); + local_irq_disable(); pending = local_softirq_pending(); @@ -372,8 +588,7 @@ restart: account_softirq_exit(current); lockdep_softirq_end(in_hardirq); - __local_bh_enable(SOFTIRQ_OFFSET); - WARN_ON_ONCE(in_interrupt()); + softirq_handle_end(); current_restore_flags(old_flags, PF_MEMALLOC); } @@ -468,7 +683,7 @@ inline void raise_softirq_irqoff(unsigned int nr) * Otherwise we wake up ksoftirqd to make sure we * schedule the softirq soon. */ - if (!in_interrupt()) + if (!in_interrupt() && should_wake_ksoftirqd()) wakeup_softirqd(); } @@ -534,6 +749,20 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) } EXPORT_SYMBOL(__tasklet_hi_schedule); +static bool tasklet_clear_sched(struct tasklet_struct *t) +{ + if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) { + wake_up_var(&t->state); + return true; + } + + WARN_ONCE(1, "tasklet SCHED state not set: %s %pS\n", + t->use_callback ? "callback" : "func", + t->use_callback ? (void *)t->callback : (void *)t->func); + + return false; +} + static void tasklet_action_common(struct softirq_action *a, struct tasklet_head *tl_head, unsigned int softirq_nr) @@ -553,13 +782,12 @@ static void tasklet_action_common(struct softirq_action *a, if (tasklet_trylock(t)) { if (!atomic_read(&t->count)) { - if (!test_and_clear_bit(TASKLET_STATE_SCHED, - &t->state)) - BUG(); - if (t->use_callback) - t->callback(t); - else - t->func(t->data); + if (tasklet_clear_sched(t)) { + if (t->use_callback) + t->callback(t); + else + t->func(t->data); + } tasklet_unlock(t); continue; } @@ -609,21 +837,62 @@ void tasklet_init(struct tasklet_struct *t, } EXPORT_SYMBOL(tasklet_init); +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) +/* + * Do not use in new code. Waiting for tasklets from atomic contexts is + * error prone and should be avoided. + */ +void tasklet_unlock_spin_wait(struct tasklet_struct *t) +{ + while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { + if (IS_ENABLED(CONFIG_PREEMPT_RT)) { + /* + * Prevent a live lock when current preempted soft + * interrupt processing or prevents ksoftirqd from + * running. If the tasklet runs on a different CPU + * then this has no effect other than doing the BH + * disable/enable dance for nothing. + */ + local_bh_disable(); + local_bh_enable(); + } else { + cpu_relax(); + } + } +} +EXPORT_SYMBOL(tasklet_unlock_spin_wait); +#endif + void tasklet_kill(struct tasklet_struct *t) { if (in_interrupt()) pr_notice("Attempt to kill tasklet from interrupt\n"); - while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { - do { - yield(); - } while (test_bit(TASKLET_STATE_SCHED, &t->state)); - } + while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) + wait_var_event(&t->state, !test_bit(TASKLET_STATE_SCHED, &t->state)); + tasklet_unlock_wait(t); - clear_bit(TASKLET_STATE_SCHED, &t->state); + tasklet_clear_sched(t); } EXPORT_SYMBOL(tasklet_kill); +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) +void tasklet_unlock(struct tasklet_struct *t) +{ + smp_mb__before_atomic(); + clear_bit(TASKLET_STATE_RUN, &t->state); + smp_mb__after_atomic(); + wake_up_var(&t->state); +} +EXPORT_SYMBOL_GPL(tasklet_unlock); + +void tasklet_unlock_wait(struct tasklet_struct *t) +{ + wait_var_event(&t->state, !test_bit(TASKLET_STATE_RUN, &t->state)); +} +EXPORT_SYMBOL_GPL(tasklet_unlock_wait); +#endif + void __init softirq_init(void) { int cpu; @@ -646,53 +915,21 @@ static int ksoftirqd_should_run(unsigned int cpu) static void run_ksoftirqd(unsigned int cpu) { - local_irq_disable(); + ksoftirqd_run_begin(); if (local_softirq_pending()) { /* * We can safely run softirq on inline stack, as we are not deep * in the task stack here. */ __do_softirq(); - local_irq_enable(); + ksoftirqd_run_end(); cond_resched(); return; } - local_irq_enable(); + ksoftirqd_run_end(); } #ifdef CONFIG_HOTPLUG_CPU -/* - * tasklet_kill_immediate is called to remove a tasklet which can already be - * scheduled for execution on @cpu. - * - * Unlike tasklet_kill, this function removes the tasklet - * _immediately_, even if the tasklet is in TASKLET_STATE_SCHED state. - * - * When this function is called, @cpu must be in the CPU_DEAD state. - */ -void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu) -{ - struct tasklet_struct **i; - - BUG_ON(cpu_online(cpu)); - BUG_ON(test_bit(TASKLET_STATE_RUN, &t->state)); - - if (!test_bit(TASKLET_STATE_SCHED, &t->state)) - return; - - /* CPU is dead, so no lock needed. */ - for (i = &per_cpu(tasklet_vec, cpu).head; *i; i = &(*i)->next) { - if (*i == t) { - *i = t->next; - /* If this was the tail element, move the tail ptr */ - if (*i == NULL) - per_cpu(tasklet_vec, cpu).tail = i; - return; - } - } - BUG(); -} - static int takeover_tasklets(unsigned int cpu) { /* CPU is dead, so no lock needed. */ diff --git a/kernel/sys.c b/kernel/sys.c index cd4c014bc9abd8b848f310c95e88918ee3584443..5d5d91c37c812efa74607911e1029f274c051cc8 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -123,6 +123,12 @@ #ifndef PAC_RESET_KEYS # define PAC_RESET_KEYS(a, b) (-EINVAL) #endif +#ifndef PAC_SET_ENABLED_KEYS +# define PAC_SET_ENABLED_KEYS(a, b, c) (-EINVAL) +#endif +#ifndef PAC_GET_ENABLED_KEYS +# define PAC_GET_ENABLED_KEYS(a) (-EINVAL) +#endif #ifndef SET_TAGGED_ADDR_CTRL # define SET_TAGGED_ADDR_CTRL(a) (-EINVAL) #endif @@ -2651,6 +2657,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, return -EINVAL; error = PAC_RESET_KEYS(me, arg2); break; + case PR_PAC_SET_ENABLED_KEYS: + if (arg4 || arg5) + return -EINVAL; + error = PAC_SET_ENABLED_KEYS(me, arg2, arg3); + break; + case PR_PAC_GET_ENABLED_KEYS: + if (arg2 || arg3 || arg4 || arg5) + return -EINVAL; + error = PAC_GET_ENABLED_KEYS(me); + break; case PR_SET_TAGGED_ADDR_CTRL: if (arg3 || arg4 || arg5) return -EINVAL; diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 4d94e2b5499d894346cac8a772b7cb25141f0988..bea9d08b16988b33a82b7d911c3a174bd4a0bb16 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -2,13 +2,13 @@ /* * Alarmtimer interface * - * This interface provides a timer which is similarto hrtimers, + * This interface provides a timer which is similar to hrtimers, * but triggers a RTC alarm if the box is suspend. * * This interface is influenced by the Android RTC Alarm timer * interface. * - * Copyright (C) 2010 IBM Corperation + * Copyright (C) 2010 IBM Corporation * * Author: John Stultz <john.stultz@linaro.org> */ @@ -811,7 +811,7 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) /** * alarm_timer_nsleep - alarmtimer nanosleep * @which_clock: clockid - * @flags: determins abstime or relative + * @flags: determines abstime or relative * @tsreq: requested sleep time (abs or rel) * * Handles clock_nanosleep calls against _ALARM clockids diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index cce484a2cc7ca4b710622435c5fb065d0ef2c61d..1d1a61371b5a1f4754df3af10f6ced10f7481942 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -38,7 +38,7 @@ * calculated mult and shift factors. This guarantees that no 64bit * overflow happens when the input value of the conversion is * multiplied with the calculated mult factor. Larger ranges may - * reduce the conversion accuracy by chosing smaller mult and shift + * reduce the conversion accuracy by choosing smaller mult and shift * factors. */ void @@ -518,7 +518,7 @@ static void clocksource_suspend_select(bool fallback) * the suspend time when resuming system. * * This function is called late in the suspend process from timekeeping_suspend(), - * that means processes are freezed, non-boot cpus and interrupts are disabled + * that means processes are frozen, non-boot cpus and interrupts are disabled * now. It is therefore possible to start the suspend timer without taking the * clocksource mutex. */ diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 5c9d968187ae850e7a1151adffb986bf0543bddb..4a66725b1d4ac0ffbce018f404f26fe1f068f7a4 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -683,7 +683,7 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) * T1 is removed, so this code is called and would reprogram * the hardware to 5s from now. Any hrtimer_start after that * will not reprogram the hardware due to hang_detected being - * set. So we'd effectivly block all timers until the T2 event + * set. So we'd effectively block all timers until the T2 event * fires. */ if (!__hrtimer_hres_active(cpu_base) || cpu_base->hang_detected) @@ -1019,7 +1019,7 @@ static void __remove_hrtimer(struct hrtimer *timer, * cpu_base->next_timer. This happens when we remove the first * timer on a remote cpu. No harm as we never dereference * cpu_base->next_timer. So the worst thing what can happen is - * an superflous call to hrtimer_force_reprogram() on the + * an superfluous call to hrtimer_force_reprogram() on the * remote cpu later on if the same timer gets enqueued again. */ if (reprogram && timer == cpu_base->next_timer) @@ -1212,7 +1212,7 @@ static void hrtimer_cpu_base_unlock_expiry(struct hrtimer_cpu_base *base) * The counterpart to hrtimer_cancel_wait_running(). * * If there is a waiter for cpu_base->expiry_lock, then it was waiting for - * the timer callback to finish. Drop expiry_lock and reaquire it. That + * the timer callback to finish. Drop expiry_lock and reacquire it. That * allows the waiter to acquire the lock and make progress. */ static void hrtimer_sync_wait_running(struct hrtimer_cpu_base *cpu_base, @@ -1398,7 +1398,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, int base; /* - * On PREEMPT_RT enabled kernels hrtimers which are not explicitely + * On PREEMPT_RT enabled kernels hrtimers which are not explicitly * marked for hard interrupt expiry mode are moved into soft * interrupt context for latency reasons and because the callbacks * can invoke functions which might sleep on RT, e.g. spin_lock(). @@ -1430,7 +1430,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, * hrtimer_init - initialize a timer to the given clock * @timer: the timer to be initialized * @clock_id: the clock to be used - * @mode: The modes which are relevant for intitialization: + * @mode: The modes which are relevant for initialization: * HRTIMER_MODE_ABS, HRTIMER_MODE_REL, HRTIMER_MODE_ABS_SOFT, * HRTIMER_MODE_REL_SOFT * @@ -1487,7 +1487,7 @@ EXPORT_SYMBOL_GPL(hrtimer_active); * insufficient for that. * * The sequence numbers are required because otherwise we could still observe - * a false negative if the read side got smeared over multiple consequtive + * a false negative if the read side got smeared over multiple consecutive * __run_hrtimer() invocations. */ @@ -1588,7 +1588,7 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now, * minimizing wakeups, not running timers at the * earliest interrupt after their soft expiration. * This allows us to avoid using a Priority Search - * Tree, which can answer a stabbing querry for + * Tree, which can answer a stabbing query for * overlapping intervals and instead use the simple * BST we already have. * We don't add extra wakeups by delaying timers that @@ -1822,7 +1822,7 @@ static void __hrtimer_init_sleeper(struct hrtimer_sleeper *sl, clockid_t clock_id, enum hrtimer_mode mode) { /* - * On PREEMPT_RT enabled kernels hrtimers which are not explicitely + * On PREEMPT_RT enabled kernels hrtimers which are not explicitly * marked for hard interrupt expiry mode are moved into soft * interrupt context either for latency reasons or because the * hrtimer callback takes regular spinlocks or invokes other @@ -1835,7 +1835,7 @@ static void __hrtimer_init_sleeper(struct hrtimer_sleeper *sl, * the same CPU. That causes a latency spike due to the wakeup of * a gazillion threads. * - * OTOH, priviledged real-time user space applications rely on the + * OTOH, privileged real-time user space applications rely on the * low latency of hard interrupt wakeups. If the current task is in * a real-time scheduling class, mark the mode for hard interrupt * expiry. diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index a5cffe2a177038fae41df257349250034e1cbab5..a492e4da69ba2a88ac176d0a19f27252b920ffec 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -44,7 +44,7 @@ static u64 jiffies_read(struct clocksource *cs) * the timer interrupt frequency HZ and it suffers * inaccuracies caused by missed or lost timer * interrupts and the inability for the timer - * interrupt hardware to accuratly tick at the + * interrupt hardware to accurately tick at the * requested HZ value. It is also not recommended * for "tick-less" systems. */ diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 5247afd7f34552b0c4fe0f1421302ad7c1cbc5c1..406dccb79c2b6b5dde3c619e3107afd9925ab7ff 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -544,7 +544,7 @@ static inline bool rtc_tv_nsec_ok(unsigned long set_offset_nsec, struct timespec64 *to_set, const struct timespec64 *now) { - /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */ + /* Allowed error in tv_nsec, arbitrarily set to 5 jiffies in ns. */ const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5; struct timespec64 delay = {.tv_sec = -1, .tv_nsec = set_offset_nsec}; diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 9abe15255bc4ef4a3a01ff548fb119b338651e4a..3bb96a8b49c9bd8888e1aaa1791470fe169f4a8f 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -279,7 +279,7 @@ void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples) * @tsk: Task for which cputime needs to be started * @samples: Storage for time samples * - * The thread group cputime accouting is avoided when there are no posix + * The thread group cputime accounting is avoided when there are no posix * CPU timers armed. Before starting a timer it's required to check whether * the time accounting is active. If not, a full update of the atomic * accounting store needs to be done and the accounting enabled. @@ -390,7 +390,7 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer) /* * If posix timer expiry is handled in task work context then * timer::it_lock can be taken without disabling interrupts as all - * other locking happens in task context. This requires a seperate + * other locking happens in task context. This requires a separate * lock class key otherwise regular posix timer expiry would record * the lock class being taken in interrupt context and generate a * false positive warning. @@ -1216,7 +1216,7 @@ static void handle_posix_cpu_timers(struct task_struct *tsk) check_process_timers(tsk, &firing); /* - * The above timer checks have updated the exipry cache and + * The above timer checks have updated the expiry cache and * because nothing can have queued or modified timers after * sighand lock was taken above it is guaranteed to be * consistent. So the next timer interrupt fastpath check diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index bf540f5a4115a2bff84ee7c2eb9f1af21385e1cd..dd5697d7347b1daaa0e843dd1e23abc8c547ddfc 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -1191,8 +1191,8 @@ SYSCALL_DEFINE2(clock_adjtime32, clockid_t, which_clock, err = do_clock_adjtime(which_clock, &ktx); - if (err >= 0) - err = put_old_timex32(utp, &ktx); + if (err >= 0 && put_old_timex32(utp, &ktx)) + return -EFAULT; return err; } diff --git a/kernel/time/test_udelay.c b/kernel/time/test_udelay.c index 77c63005dc4e03ab22d1f8a5599c8317c9afa5a4..13b11eb62685e451488b6e0da55a131d74d09662 100644 --- a/kernel/time/test_udelay.c +++ b/kernel/time/test_udelay.c @@ -21,7 +21,6 @@ #define DEBUGFS_FILENAME "udelay_test" static DEFINE_MUTEX(udelay_test_lock); -static struct dentry *udelay_test_debugfs_file; static int udelay_test_usecs; static int udelay_test_iterations = DEFAULT_ITERATIONS; @@ -138,8 +137,8 @@ static const struct file_operations udelay_test_debugfs_ops = { static int __init udelay_test_init(void) { mutex_lock(&udelay_test_lock); - udelay_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME, - S_IRUSR, NULL, NULL, &udelay_test_debugfs_ops); + debugfs_create_file(DEBUGFS_FILENAME, S_IRUSR, NULL, NULL, + &udelay_test_debugfs_ops); mutex_unlock(&udelay_test_lock); return 0; @@ -150,7 +149,7 @@ module_init(udelay_test_init); static void __exit udelay_test_exit(void) { mutex_lock(&udelay_test_lock); - debugfs_remove(udelay_test_debugfs_file); + debugfs_remove(debugfs_lookup(DEBUGFS_FILENAME, NULL)); mutex_unlock(&udelay_test_lock); } diff --git a/kernel/time/tick-broadcast-hrtimer.c b/kernel/time/tick-broadcast-hrtimer.c index b5a65e212df2f9a1e4b55df717a7f97652b1ed61..797eb93103ad4d373d2fca50b4baeadf8da10e96 100644 --- a/kernel/time/tick-broadcast-hrtimer.c +++ b/kernel/time/tick-broadcast-hrtimer.c @@ -53,7 +53,7 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) * reasons. * * Each caller tries to arm the hrtimer on its own CPU, but if the - * hrtimer callbback function is currently running, then + * hrtimer callback function is currently running, then * hrtimer_start() cannot move it and the timer stays on the CPU on * which it is assigned at the moment. * diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 5a23829372c7fc2d4b60814b397a1af9e72298ba..a440552287969e7e87d550e22b3307ab00056387 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -107,6 +107,19 @@ void tick_install_broadcast_device(struct clock_event_device *dev) tick_broadcast_device.evtdev = dev; if (!cpumask_empty(tick_broadcast_mask)) tick_broadcast_start_periodic(dev); + + if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) + return; + + /* + * If the system already runs in oneshot mode, switch the newly + * registered broadcast device to oneshot mode explicitly. + */ + if (tick_broadcast_oneshot_active()) { + tick_broadcast_switch_to_oneshot(); + return; + } + /* * Inform all cpus about this. We might be in a situation * where we did not switch to oneshot mode because the per cpu @@ -115,8 +128,7 @@ void tick_install_broadcast_device(struct clock_event_device *dev) * notification the systems stays stuck in periodic mode * forever. */ - if (dev->features & CLOCK_EVT_FEAT_ONESHOT) - tick_clock_notify(); + tick_clock_notify(); } /* @@ -157,7 +169,7 @@ static void tick_device_setup_broadcast_func(struct clock_event_device *dev) } /* - * Check, if the device is disfunctional and a place holder, which + * Check, if the device is dysfunctional and a placeholder, which * needs to be handled by the broadcast device. */ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) @@ -391,7 +403,7 @@ void tick_broadcast_control(enum tick_broadcast_mode mode) * - the broadcast device exists * - the broadcast device is not a hrtimer based one * - the broadcast device is in periodic mode to - * avoid a hickup during switch to oneshot mode + * avoid a hiccup during switch to oneshot mode */ if (bc && !(bc->features & CLOCK_EVT_FEAT_HRTIMER) && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 8b5564abdf284c90d8bad1c771d5a552069b7d6f..aecc371f61fea5cbda2378788b9bc4cddbeebe52 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -350,12 +350,7 @@ void tick_check_new_device(struct clock_event_device *newdev) td = &per_cpu(tick_cpu_device, cpu); curdev = td->evtdev; - /* cpu local device ? */ - if (!tick_check_percpu(curdev, newdev, cpu)) - goto out_bc; - - /* Preference decision */ - if (!tick_check_preferred(curdev, newdev)) + if (!tick_check_replacement(curdev, newdev)) goto out_bc; if (!try_module_get(newdev->owner)) diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index f9745d47425aa452b334165ebc453217af4ed0ec..475ecceda7688cebc11b9afa8f919f70b2cdf23d 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -45,7 +45,7 @@ int tick_program_event(ktime_t expires, int force) } /** - * tick_resume_onshot - resume oneshot mode + * tick_resume_oneshot - resume oneshot mode */ void tick_resume_oneshot(void) { diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 09286d269e567af6cc04379a2fb9d13c40faa158..1ef62195bf0a0858782cb6466297e48772a97486 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -754,7 +754,7 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu) * Aside of that check whether the local timer softirq is * pending. If so its a bad idea to call get_next_timer_interrupt() * because there is an already expired timer, so it will request - * immeditate expiry, which rearms the hardware timer with a + * immediate expiry, which rearms the hardware timer with a * minimal delta which brings us back to this place * immediately. Lather, rinse and repeat... */ @@ -976,7 +976,7 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) if (unlikely(local_softirq_pending())) { static int ratelimit; - if (ratelimit < 10 && + if (ratelimit < 10 && !local_bh_blocked() && (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) { pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n", (unsigned int) local_softirq_pending()); @@ -1127,7 +1127,11 @@ ktime_t tick_nohz_get_next_hrtimer(void) * tick_nohz_get_sleep_length - return the expected length of the current sleep * @delta_next: duration until the next event if the tick cannot be stopped * - * Called from power state control code with interrupts disabled + * Called from power state control code with interrupts disabled. + * + * The return value of this function and/or the value returned by it through the + * @delta_next pointer can be negative which must be taken into account by its + * callers. */ ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next) { diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h index 4fb06527cf64fe72da2ddcf550c8cd6de96aa4bc..d952ae393423632e997cc996fad2eaa932c5fc3a 100644 --- a/kernel/time/tick-sched.h +++ b/kernel/time/tick-sched.h @@ -29,7 +29,7 @@ enum tick_nohz_mode { * @inidle: Indicator that the CPU is in the tick idle mode * @tick_stopped: Indicator that the idle tick has been stopped * @idle_active: Indicator that the CPU is actively in the tick idle mode; - * it is resetted during irq handling phases. + * it is reset during irq handling phases. * @do_timer_lst: CPU was the last one doing do_timer before going idle * @got_idle_tick: Tick timer function has run with @inidle set * @last_tick: Store the last tick expiry time when the tick diff --git a/kernel/time/time.c b/kernel/time/time.c index 5fe2cc0f4f3ba7c848e701ab783554c2f1c2ed6c..ecc59b45f770149b3fbb65c3ee37513dc9111dcc 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -571,7 +571,7 @@ EXPORT_SYMBOL(__usecs_to_jiffies); /* * The TICK_NSEC - 1 rounds up the value to the next resolution. Note * that a remainder subtract here would not do the right thing as the - * resolution values don't fall on second boundries. I.e. the line: + * resolution values don't fall on second boundaries. I.e. the line: * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. * Note that due to the small error in the multiplier here, this * rounding is incorrect for sufficiently large values of tv_nsec, but diff --git a/kernel/time/timecounter.c b/kernel/time/timecounter.c index 85b98e727306f1ecec22076d0a397109dbe60c82..e6285288d76572d192435a1a44babc57bfda8770 100644 --- a/kernel/time/timecounter.c +++ b/kernel/time/timecounter.c @@ -76,7 +76,7 @@ static u64 cc_cyc2ns_backwards(const struct cyclecounter *cc, return ns; } -u64 timecounter_cyc2time(struct timecounter *tc, +u64 timecounter_cyc2time(const struct timecounter *tc, u64 cycle_tstamp) { u64 delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 6aee5768c86ff7dbd4acd58cc96d4fac949f9437..81fe2a33b80c8daa833e298026b883b8a174f976 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -596,14 +596,14 @@ EXPORT_SYMBOL_GPL(ktime_get_real_fast_ns); * careful cache layout of the timekeeper because the sequence count and * struct tk_read_base would then need two cache lines instead of one. * - * Access to the time keeper clock source is disabled accross the innermost + * Access to the time keeper clock source is disabled across the innermost * steps of suspend/resume. The accessors still work, but the timestamps * are frozen until time keeping is resumed which happens very early. * * For regular suspend/resume there is no observable difference vs. sched * clock, but it might affect some of the nasty low level debug printks. * - * OTOH, access to sched clock is not guaranteed accross suspend/resume on + * OTOH, access to sched clock is not guaranteed across suspend/resume on * all systems either so it depends on the hardware in use. * * If that turns out to be a real problem then this could be mitigated by @@ -899,7 +899,7 @@ ktime_t ktime_get_coarse_with_offset(enum tk_offsets offs) EXPORT_SYMBOL_GPL(ktime_get_coarse_with_offset); /** - * ktime_mono_to_any() - convert mononotic time to any other time + * ktime_mono_to_any() - convert monotonic time to any other time * @tmono: time to convert. * @offs: which offset to use */ @@ -1427,35 +1427,45 @@ static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) static int change_clocksource(void *data) { struct timekeeper *tk = &tk_core.timekeeper; - struct clocksource *new, *old; + struct clocksource *new, *old = NULL; unsigned long flags; + bool change = false; new = (struct clocksource *) data; - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - timekeeping_forward_now(tk); /* * If the cs is in module, get a module reference. Succeeds * for built-in code (owner == NULL) as well. */ if (try_module_get(new->owner)) { - if (!new->enable || new->enable(new) == 0) { - old = tk->tkr_mono.clock; - tk_setup_internals(tk, new); - if (old->disable) - old->disable(old); - module_put(old->owner); - } else { + if (!new->enable || new->enable(new) == 0) + change = true; + else module_put(new->owner); - } } + + raw_spin_lock_irqsave(&timekeeper_lock, flags); + write_seqcount_begin(&tk_core.seq); + + timekeeping_forward_now(tk); + + if (change) { + old = tk->tkr_mono.clock; + tk_setup_internals(tk, new); + } + timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + if (old) { + if (old->disable) + old->disable(old); + + module_put(old->owner); + } + return 0; } @@ -1948,7 +1958,7 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk, * xtime_nsec_1 = offset + xtime_nsec_2 * Which gives us: * xtime_nsec_2 = xtime_nsec_1 - offset - * Which simplfies to: + * Which simplifies to: * xtime_nsec -= offset */ if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) { @@ -2336,7 +2346,7 @@ static int timekeeping_validate_timex(const struct __kernel_timex *txc) /* * Validate if a timespec/timeval used to inject a time - * offset is valid. Offsets can be postive or negative, so + * offset is valid. Offsets can be positive or negative, so * we don't check tv_sec. The value of the timeval/timespec * is the sum of its fields,but *NOTE*: * The field tv_usec/tv_nsec must always be non-negative and diff --git a/kernel/time/timer.c b/kernel/time/timer.c index f475f1a027c8b36cf339f959c8031a299ba51d8a..d111adf4a0cb4c304fe9a7cbb3fe7b3c4ae2a69b 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -894,7 +894,7 @@ static inline void forward_timer_base(struct timer_base *base) /* * No need to forward if we are close enough below jiffies. * Also while executing timers, base->clk is 1 offset ahead - * of jiffies to avoid endless requeuing to current jffies. + * of jiffies to avoid endless requeuing to current jiffies. */ if ((long)(jnow - base->clk) < 1) return; @@ -1271,7 +1271,7 @@ static inline void timer_base_unlock_expiry(struct timer_base *base) * The counterpart to del_timer_wait_running(). * * If there is a waiter for base->expiry_lock, then it was waiting for the - * timer callback to finish. Drop expiry_lock and reaquire it. That allows + * timer callback to finish. Drop expiry_lock and reacquire it. That allows * the waiter to acquire the lock and make progress. */ static void timer_sync_wait_running(struct timer_base *base) diff --git a/kernel/time/vsyscall.c b/kernel/time/vsyscall.c index 88e6b8ed6ca5ccd4271b96cc1e5fdb867920e88f..f0d5062d9cbc621a2ab32141b53c2f1f8cba0337 100644 --- a/kernel/time/vsyscall.c +++ b/kernel/time/vsyscall.c @@ -108,7 +108,7 @@ void update_vsyscall(struct timekeeper *tk) /* * If the current clocksource is not VDSO capable, then spare the - * update of the high reolution parts. + * update of the high resolution parts. */ if (clock_mode != VDSO_CLOCKMODE_NONE) update_vdso_data(vdata, tk); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 3564b62c08bed59878edda9f1cc5de3132c26c61..927bbe922fe7d2e77110f401ab82285b08cdd08e 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4833,7 +4833,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, cpumask_var_t tracing_cpumask_new; int err; - if (!alloc_cpumask_var(&tracing_cpumask_new, GFP_KERNEL)) + if (!zalloc_cpumask_var(&tracing_cpumask_new, GFP_KERNEL)) return -ENOMEM; err = cpumask_parse_user(ubuf, count, tracing_cpumask_new); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 823beb6b291aecaff63dc92e48b1c3060e2d330c..d64f0195f4c62ed144f5c30babe029d32020ab65 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1634,7 +1634,7 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, struct work_struct *work = &dwork->work; WARN_ON_ONCE(!wq); - WARN_ON_ONCE(timer->function != delayed_work_timer_fn); + WARN_ON_FUNCTION_MISMATCH(timer->function, delayed_work_timer_fn); WARN_ON_ONCE(timer_pending(timer)); WARN_ON_ONCE(!list_empty(&work->entry)); diff --git a/lib/Kconfig b/lib/Kconfig index a38cc61256f1a44e011e7a9f72042900221f9e4d..ac3b30697b2b392af075f81cc83851a18f33f0d3 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -701,3 +701,6 @@ config GENERIC_LIB_DEVMEM_IS_ALLOWED config PLDMFW bool default n + +config ASN1_ENCODER + tristate diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 417c3d3e521bfc4e069bc167202c8cd71476d55b..2c7f46b366f165f56ff2c0b8ae092600a92132e6 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1370,6 +1370,46 @@ config LOCKDEP config LOCKDEP_SMALL bool +config LOCKDEP_BITS + int "Bitsize for MAX_LOCKDEP_ENTRIES" + depends on LOCKDEP && !LOCKDEP_SMALL + range 10 30 + default 15 + help + Try increasing this value if you hit "BUG: MAX_LOCKDEP_ENTRIES too low!" message. + +config LOCKDEP_CHAINS_BITS + int "Bitsize for MAX_LOCKDEP_CHAINS" + depends on LOCKDEP && !LOCKDEP_SMALL + range 10 30 + default 16 + help + Try increasing this value if you hit "BUG: MAX_LOCKDEP_CHAINS too low!" message. + +config LOCKDEP_STACK_TRACE_BITS + int "Bitsize for MAX_STACK_TRACE_ENTRIES" + depends on LOCKDEP && !LOCKDEP_SMALL + range 10 30 + default 19 + help + Try increasing this value if you hit "BUG: MAX_STACK_TRACE_ENTRIES too low!" message. + +config LOCKDEP_STACK_TRACE_HASH_BITS + int "Bitsize for STACK_TRACE_HASH_SIZE" + depends on LOCKDEP && !LOCKDEP_SMALL + range 10 30 + default 14 + help + Try increasing this value if you need large MAX_STACK_TRACE_ENTRIES. + +config LOCKDEP_CIRCULAR_QUEUE_BITS + int "Bitsize for elements in circular_queue struct" + depends on LOCKDEP + range 10 30 + default 12 + help + Try increasing this value if you hit "lockdep bfs error:-1" warning due to __cq_enqueue() failure. + config DEBUG_LOCKDEP bool "Lock dependency engine debugging" depends on DEBUG_KERNEL && LOCKDEP diff --git a/lib/Makefile b/lib/Makefile index b5307d3eec1aaa6327886e034ad3622f3596ff75..e11cfc18b6c0826ffc8bdcf1329dd1ec1aa2ef2e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -280,6 +280,7 @@ obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o obj-$(CONFIG_PERCPU_TEST) += percpu_test.o obj-$(CONFIG_ASN1) += asn1_decoder.o +obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o obj-$(CONFIG_FONT_SUPPORT) += fonts/ diff --git a/lib/asn1_encoder.c b/lib/asn1_encoder.c new file mode 100644 index 0000000000000000000000000000000000000000..41e71aae3ef6faf055823320ae5e357b09a22e9e --- /dev/null +++ b/lib/asn1_encoder.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Simple encoder primitives for ASN.1 BER/DER/CER + * + * Copyright (C) 2019 James.Bottomley@HansenPartnership.com + */ + +#include <linux/asn1_encoder.h> +#include <linux/bug.h> +#include <linux/string.h> +#include <linux/module.h> + +/** + * asn1_encode_integer() - encode positive integer to ASN.1 + * @data: pointer to the pointer to the data + * @end_data: end of data pointer, points one beyond last usable byte in @data + * @integer: integer to be encoded + * + * This is a simplified encoder: it only currently does + * positive integers, but it should be simple enough to add the + * negative case if a use comes along. + */ +unsigned char * +asn1_encode_integer(unsigned char *data, const unsigned char *end_data, + s64 integer) +{ + int data_len = end_data - data; + unsigned char *d = &data[2]; + bool found = false; + int i; + + if (WARN(integer < 0, + "BUG: integer encode only supports positive integers")) + return ERR_PTR(-EINVAL); + + if (IS_ERR(data)) + return data; + + /* need at least 3 bytes for tag, length and integer encoding */ + if (data_len < 3) + return ERR_PTR(-EINVAL); + + /* remaining length where at d (the start of the integer encoding) */ + data_len -= 2; + + data[0] = _tag(UNIV, PRIM, INT); + if (integer == 0) { + *d++ = 0; + goto out; + } + + for (i = sizeof(integer); i > 0 ; i--) { + int byte = integer >> (8 * (i - 1)); + + if (!found && byte == 0) + continue; + + /* + * for a positive number the first byte must have bit + * 7 clear in two's complement (otherwise it's a + * negative number) so prepend a leading zero if + * that's not the case + */ + if (!found && (byte & 0x80)) { + /* + * no check needed here, we already know we + * have len >= 1 + */ + *d++ = 0; + data_len--; + } + + found = true; + if (data_len == 0) + return ERR_PTR(-EINVAL); + + *d++ = byte; + data_len--; + } + + out: + data[1] = d - data - 2; + + return d; +} +EXPORT_SYMBOL_GPL(asn1_encode_integer); + +/* calculate the base 128 digit values setting the top bit of the first octet */ +static int asn1_encode_oid_digit(unsigned char **_data, int *data_len, u32 oid) +{ + unsigned char *data = *_data; + int start = 7 + 7 + 7 + 7; + int ret = 0; + + if (*data_len < 1) + return -EINVAL; + + /* quick case */ + if (oid == 0) { + *data++ = 0x80; + (*data_len)--; + goto out; + } + + while (oid >> start == 0) + start -= 7; + + while (start > 0 && *data_len > 0) { + u8 byte; + + byte = oid >> start; + oid = oid - (byte << start); + start -= 7; + byte |= 0x80; + *data++ = byte; + (*data_len)--; + } + + if (*data_len > 0) { + *data++ = oid; + (*data_len)--; + } else { + ret = -EINVAL; + } + + out: + *_data = data; + return ret; +} + +/** + * asn1_encode_oid() - encode an oid to ASN.1 + * @data: position to begin encoding at + * @end_data: end of data pointer, points one beyond last usable byte in @data + * @oid: array of oids + * @oid_len: length of oid array + * + * this encodes an OID up to ASN.1 when presented as an array of OID values + */ +unsigned char * +asn1_encode_oid(unsigned char *data, const unsigned char *end_data, + u32 oid[], int oid_len) +{ + int data_len = end_data - data; + unsigned char *d = data + 2; + int i, ret; + + if (WARN(oid_len < 2, "OID must have at least two elements")) + return ERR_PTR(-EINVAL); + + if (WARN(oid_len > 32, "OID is too large")) + return ERR_PTR(-EINVAL); + + if (IS_ERR(data)) + return data; + + + /* need at least 3 bytes for tag, length and OID encoding */ + if (data_len < 3) + return ERR_PTR(-EINVAL); + + data[0] = _tag(UNIV, PRIM, OID); + *d++ = oid[0] * 40 + oid[1]; + + data_len -= 3; + + ret = 0; + + for (i = 2; i < oid_len; i++) { + ret = asn1_encode_oid_digit(&d, &data_len, oid[i]); + if (ret < 0) + return ERR_PTR(ret); + } + + data[1] = d - data - 2; + + return d; +} +EXPORT_SYMBOL_GPL(asn1_encode_oid); + +/** + * asn1_encode_length() - encode a length to follow an ASN.1 tag + * @data: pointer to encode at + * @data_len: pointer to remaning length (adjusted by routine) + * @len: length to encode + * + * This routine can encode lengths up to 65535 using the ASN.1 rules. + * It will accept a negative length and place a zero length tag + * instead (to keep the ASN.1 valid). This convention allows other + * encoder primitives to accept negative lengths as singalling the + * sequence will be re-encoded when the length is known. + */ +static int asn1_encode_length(unsigned char **data, int *data_len, int len) +{ + if (*data_len < 1) + return -EINVAL; + + if (len < 0) { + *((*data)++) = 0; + (*data_len)--; + return 0; + } + + if (len <= 0x7f) { + *((*data)++) = len; + (*data_len)--; + return 0; + } + + if (*data_len < 2) + return -EINVAL; + + if (len <= 0xff) { + *((*data)++) = 0x81; + *((*data)++) = len & 0xff; + *data_len -= 2; + return 0; + } + + if (*data_len < 3) + return -EINVAL; + + if (len <= 0xffff) { + *((*data)++) = 0x82; + *((*data)++) = (len >> 8) & 0xff; + *((*data)++) = len & 0xff; + *data_len -= 3; + return 0; + } + + if (WARN(len > 0xffffff, "ASN.1 length can't be > 0xffffff")) + return -EINVAL; + + if (*data_len < 4) + return -EINVAL; + *((*data)++) = 0x83; + *((*data)++) = (len >> 16) & 0xff; + *((*data)++) = (len >> 8) & 0xff; + *((*data)++) = len & 0xff; + *data_len -= 4; + + return 0; +} + +/** + * asn1_encode_tag() - add a tag for optional or explicit value + * @data: pointer to place tag at + * @end_data: end of data pointer, points one beyond last usable byte in @data + * @tag: tag to be placed + * @string: the data to be tagged + * @len: the length of the data to be tagged + * + * Note this currently only handles short form tags < 31. + * + * Standard usage is to pass in a @tag, @string and @length and the + * @string will be ASN.1 encoded with @tag and placed into @data. If + * the encoding would put data past @end_data then an error is + * returned, otherwise a pointer to a position one beyond the encoding + * is returned. + * + * To encode in place pass a NULL @string and -1 for @len and the + * maximum allowable beginning and end of the data; all this will do + * is add the current maximum length and update the data pointer to + * the place where the tag contents should be placed is returned. The + * data should be copied in by the calling routine which should then + * repeat the prior statement but now with the known length. In order + * to avoid having to keep both before and after pointers, the repeat + * expects to be called with @data pointing to where the first encode + * returned it and still NULL for @string but the real length in @len. + */ +unsigned char * +asn1_encode_tag(unsigned char *data, const unsigned char *end_data, + u32 tag, const unsigned char *string, int len) +{ + int data_len = end_data - data; + int ret; + + if (WARN(tag > 30, "ASN.1 tag can't be > 30")) + return ERR_PTR(-EINVAL); + + if (!string && WARN(len > 127, + "BUG: recode tag is too big (>127)")) + return ERR_PTR(-EINVAL); + + if (IS_ERR(data)) + return data; + + if (!string && len > 0) { + /* + * we're recoding, so move back to the start of the + * tag and install a dummy length because the real + * data_len should be NULL + */ + data -= 2; + data_len = 2; + } + + if (data_len < 2) + return ERR_PTR(-EINVAL); + + *(data++) = _tagn(CONT, CONS, tag); + data_len--; + ret = asn1_encode_length(&data, &data_len, len); + if (ret < 0) + return ERR_PTR(ret); + + if (!string) + return data; + + if (data_len < len) + return ERR_PTR(-EINVAL); + + memcpy(data, string, len); + data += len; + + return data; +} +EXPORT_SYMBOL_GPL(asn1_encode_tag); + +/** + * asn1_encode_octet_string() - encode an ASN.1 OCTET STRING + * @data: pointer to encode at + * @end_data: end of data pointer, points one beyond last usable byte in @data + * @string: string to be encoded + * @len: length of string + * + * Note ASN.1 octet strings may contain zeros, so the length is obligatory. + */ +unsigned char * +asn1_encode_octet_string(unsigned char *data, + const unsigned char *end_data, + const unsigned char *string, u32 len) +{ + int data_len = end_data - data; + int ret; + + if (IS_ERR(data)) + return data; + + /* need minimum of 2 bytes for tag and length of zero length string */ + if (data_len < 2) + return ERR_PTR(-EINVAL); + + *(data++) = _tag(UNIV, PRIM, OTS); + data_len--; + + ret = asn1_encode_length(&data, &data_len, len); + if (ret) + return ERR_PTR(ret); + + if (data_len < len) + return ERR_PTR(-EINVAL); + + memcpy(data, string, len); + data += len; + + return data; +} +EXPORT_SYMBOL_GPL(asn1_encode_octet_string); + +/** + * asn1_encode_sequence() - wrap a byte stream in an ASN.1 SEQUENCE + * @data: pointer to encode at + * @end_data: end of data pointer, points one beyond last usable byte in @data + * @seq: data to be encoded as a sequence + * @len: length of the data to be encoded as a sequence + * + * Fill in a sequence. To encode in place, pass NULL for @seq and -1 + * for @len; then call again once the length is known (still with NULL + * for @seq). In order to avoid having to keep both before and after + * pointers, the repeat expects to be called with @data pointing to + * where the first encode placed it. + */ +unsigned char * +asn1_encode_sequence(unsigned char *data, const unsigned char *end_data, + const unsigned char *seq, int len) +{ + int data_len = end_data - data; + int ret; + + if (!seq && WARN(len > 127, + "BUG: recode sequence is too big (>127)")) + return ERR_PTR(-EINVAL); + + if (IS_ERR(data)) + return data; + + if (!seq && len >= 0) { + /* + * we're recoding, so move back to the start of the + * sequence and install a dummy length because the + * real length should be NULL + */ + data -= 2; + data_len = 2; + } + + if (data_len < 2) + return ERR_PTR(-EINVAL); + + *(data++) = _tag(UNIV, CONS, SEQ); + data_len--; + + ret = asn1_encode_length(&data, &data_len, len); + if (ret) + return ERR_PTR(ret); + + if (!seq) + return data; + + if (data_len < len) + return ERR_PTR(-EINVAL); + + memcpy(data, seq, len); + data += len; + + return data; +} +EXPORT_SYMBOL_GPL(asn1_encode_sequence); + +/** + * asn1_encode_boolean() - encode a boolean value to ASN.1 + * @data: pointer to encode at + * @end_data: end of data pointer, points one beyond last usable byte in @data + * @val: the boolean true/false value + */ +unsigned char * +asn1_encode_boolean(unsigned char *data, const unsigned char *end_data, + bool val) +{ + int data_len = end_data - data; + + if (IS_ERR(data)) + return data; + + /* booleans are 3 bytes: tag, length == 1 and value == 0 or 1 */ + if (data_len < 3) + return ERR_PTR(-EINVAL); + + *(data++) = _tag(UNIV, PRIM, BOOL); + data_len--; + + asn1_encode_length(&data, &data_len, 1); + + if (val) + *(data++) = 1; + else + *(data++) = 0; + + return data; +} +EXPORT_SYMBOL_GPL(asn1_encode_boolean); + +MODULE_LICENSE("GPL"); diff --git a/lib/crypto/chacha.c b/lib/crypto/chacha.c index 4ccbec442469c30a4fed329852fb421e7dd57c20..b748fd3d256e41cb00d9c77fa463d41632769cac 100644 --- a/lib/crypto/chacha.c +++ b/lib/crypto/chacha.c @@ -64,7 +64,7 @@ static void chacha_permute(u32 *x, int nrounds) } /** - * chacha_block - generate one keystream block and increment block counter + * chacha_block_generic - generate one keystream block and increment block counter * @state: input state matrix (16 32-bit words) * @stream: output keystream block (64 bytes) * @nrounds: number of rounds (20 or 12; 20 is recommended) @@ -92,7 +92,7 @@ EXPORT_SYMBOL(chacha_block_generic); /** * hchacha_block_generic - abbreviated ChaCha core, for XChaCha * @state: input state matrix (16 32-bit words) - * @out: output (8 32-bit words) + * @stream: output (8 32-bit words) * @nrounds: number of rounds (20 or 12; 20 is recommended) * * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step diff --git a/lib/crypto/poly1305-donna32.c b/lib/crypto/poly1305-donna32.c index 3cc77d94390b26cdb7b04b5a0a133ec7ab070897..7fb71845cc8464fd8beeb5be2b65b79d1193fcd0 100644 --- a/lib/crypto/poly1305-donna32.c +++ b/lib/crypto/poly1305-donna32.c @@ -10,7 +10,8 @@ #include <asm/unaligned.h> #include <crypto/internal/poly1305.h> -void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) +void poly1305_core_setkey(struct poly1305_core_key *key, + const u8 raw_key[POLY1305_BLOCK_SIZE]) { /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff; diff --git a/lib/crypto/poly1305-donna64.c b/lib/crypto/poly1305-donna64.c index 6ae181bb43450cf940d42425965d40c2b9e7dbcb..d34cf4053668958ee48e176092d92d90c7d3c0f8 100644 --- a/lib/crypto/poly1305-donna64.c +++ b/lib/crypto/poly1305-donna64.c @@ -12,7 +12,8 @@ typedef __uint128_t u128; -void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) +void poly1305_core_setkey(struct poly1305_core_key *key, + const u8 raw_key[POLY1305_BLOCK_SIZE]) { u64 t0, t1; diff --git a/lib/crypto/poly1305.c b/lib/crypto/poly1305.c index 9d2d14df0fee533e2548c44e50573f90d4fa3951..26d87fc3823e83798d052aba09c6a94a59c5fd15 100644 --- a/lib/crypto/poly1305.c +++ b/lib/crypto/poly1305.c @@ -12,7 +12,8 @@ #include <linux/module.h> #include <asm/unaligned.h> -void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key) +void poly1305_init_generic(struct poly1305_desc_ctx *desc, + const u8 key[POLY1305_KEY_SIZE]) { poly1305_core_setkey(&desc->core_r, key); desc->s[0] = get_unaligned_le32(key + 16); diff --git a/lib/devres.c b/lib/devres.c index 2a4ff5d6428860b79ed04001acb87137b6dbc651..4679dbb1bf5f8a82ce3773ad14a5f0e0343aaf8b 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -10,6 +10,7 @@ enum devm_ioremap_type { DEVM_IOREMAP = 0, DEVM_IOREMAP_UC, DEVM_IOREMAP_WC, + DEVM_IOREMAP_NP, }; void devm_ioremap_release(struct device *dev, void *res) @@ -42,6 +43,9 @@ static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset, case DEVM_IOREMAP_WC: addr = ioremap_wc(offset, size); break; + case DEVM_IOREMAP_NP: + addr = ioremap_np(offset, size); + break; } if (addr) { @@ -98,6 +102,21 @@ void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, } EXPORT_SYMBOL(devm_ioremap_wc); +/** + * devm_ioremap_np - Managed ioremap_np() + * @dev: Generic device to remap IO address for + * @offset: Resource address to map + * @size: Size of map + * + * Managed ioremap_np(). Map is automatically unmapped on driver detach. + */ +void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset, + resource_size_t size) +{ + return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NP); +} +EXPORT_SYMBOL(devm_ioremap_np); + /** * devm_iounmap - Managed iounmap() * @dev: Generic device to unmap for @@ -128,6 +147,9 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res, return IOMEM_ERR_PTR(-EINVAL); } + if (type == DEVM_IOREMAP && res->flags & IORESOURCE_MEM_NONPOSTED) + type = DEVM_IOREMAP_NP; + size = resource_size(res); if (res->name) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index f66c62aa7154d824faaae7c3f92e9c533bb9e273..61228a6c69f8ba67f46c206b326ecd553302d9a1 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -76,7 +76,44 @@ } \ } -#define iterate_all_kinds(i, n, v, I, B, K) { \ +#define iterate_xarray(i, n, __v, skip, STEP) { \ + struct page *head = NULL; \ + size_t wanted = n, seg, offset; \ + loff_t start = i->xarray_start + skip; \ + pgoff_t index = start >> PAGE_SHIFT; \ + int j; \ + \ + XA_STATE(xas, i->xarray, index); \ + \ + rcu_read_lock(); \ + xas_for_each(&xas, head, ULONG_MAX) { \ + if (xas_retry(&xas, head)) \ + continue; \ + if (WARN_ON(xa_is_value(head))) \ + break; \ + if (WARN_ON(PageHuge(head))) \ + break; \ + for (j = (head->index < index) ? index - head->index : 0; \ + j < thp_nr_pages(head); j++) { \ + __v.bv_page = head + j; \ + offset = (i->xarray_start + skip) & ~PAGE_MASK; \ + seg = PAGE_SIZE - offset; \ + __v.bv_offset = offset; \ + __v.bv_len = min(n, seg); \ + (void)(STEP); \ + n -= __v.bv_len; \ + skip += __v.bv_len; \ + if (n == 0) \ + break; \ + } \ + if (n == 0) \ + break; \ + } \ + rcu_read_unlock(); \ + n = wanted - n; \ +} + +#define iterate_all_kinds(i, n, v, I, B, K, X) { \ if (likely(n)) { \ size_t skip = i->iov_offset; \ if (unlikely(i->type & ITER_BVEC)) { \ @@ -88,6 +125,9 @@ struct kvec v; \ iterate_kvec(i, n, v, kvec, skip, (K)) \ } else if (unlikely(i->type & ITER_DISCARD)) { \ + } else if (unlikely(i->type & ITER_XARRAY)) { \ + struct bio_vec v; \ + iterate_xarray(i, n, v, skip, (X)); \ } else { \ const struct iovec *iov; \ struct iovec v; \ @@ -96,7 +136,7 @@ } \ } -#define iterate_and_advance(i, n, v, I, B, K) { \ +#define iterate_and_advance(i, n, v, I, B, K, X) { \ if (unlikely(i->count < n)) \ n = i->count; \ if (i->count) { \ @@ -121,6 +161,9 @@ i->kvec = kvec; \ } else if (unlikely(i->type & ITER_DISCARD)) { \ skip += n; \ + } else if (unlikely(i->type & ITER_XARRAY)) { \ + struct bio_vec v; \ + iterate_xarray(i, n, v, skip, (X)) \ } else { \ const struct iovec *iov; \ struct iovec v; \ @@ -622,7 +665,9 @@ size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) copyout(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len), memcpy_to_page(v.bv_page, v.bv_offset, (from += v.bv_len) - v.bv_len, v.bv_len), - memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len) + memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len), + memcpy_to_page(v.bv_page, v.bv_offset, + (from += v.bv_len) - v.bv_len, v.bv_len) ) return bytes; @@ -738,6 +783,18 @@ size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i) bytes = curr_addr - s_addr - rem; return bytes; } + }), + ({ + rem = copy_mc_to_page(v.bv_page, v.bv_offset, + (from += v.bv_len) - v.bv_len, v.bv_len); + if (rem) { + curr_addr = (unsigned long) from; + bytes = curr_addr - s_addr - rem; + rcu_read_unlock(); + i->iov_offset += bytes; + i->count -= bytes; + return bytes; + } }) ) @@ -759,7 +816,9 @@ size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) copyin((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, v.bv_offset, v.bv_len), - memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), + memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len) ) return bytes; @@ -785,7 +844,9 @@ bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) 0;}), memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, v.bv_offset, v.bv_len), - memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), + memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len) ) iov_iter_advance(i, bytes); @@ -805,7 +866,9 @@ size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) v.iov_base, v.iov_len), memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, v.bv_offset, v.bv_len), - memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), + memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len) ) return bytes; @@ -840,7 +903,9 @@ size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i) memcpy_page_flushcache((to += v.bv_len) - v.bv_len, v.bv_page, v.bv_offset, v.bv_len), memcpy_flushcache((to += v.iov_len) - v.iov_len, v.iov_base, - v.iov_len) + v.iov_len), + memcpy_page_flushcache((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len) ) return bytes; @@ -864,7 +929,9 @@ bool _copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) 0;}), memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, v.bv_offset, v.bv_len), - memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), + memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len) ) iov_iter_advance(i, bytes); @@ -901,7 +968,7 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, { if (unlikely(!page_copy_sane(page, offset, bytes))) return 0; - if (i->type & (ITER_BVEC|ITER_KVEC)) { + if (i->type & (ITER_BVEC | ITER_KVEC | ITER_XARRAY)) { void *kaddr = kmap_atomic(page); size_t wanted = copy_to_iter(kaddr + offset, bytes, i); kunmap_atomic(kaddr); @@ -924,7 +991,7 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, WARN_ON(1); return 0; } - if (i->type & (ITER_BVEC|ITER_KVEC)) { + if (i->type & (ITER_BVEC | ITER_KVEC | ITER_XARRAY)) { void *kaddr = kmap_atomic(page); size_t wanted = _copy_from_iter(kaddr + offset, bytes, i); kunmap_atomic(kaddr); @@ -968,7 +1035,8 @@ size_t iov_iter_zero(size_t bytes, struct iov_iter *i) iterate_and_advance(i, bytes, v, clear_user(v.iov_base, v.iov_len), memzero_page(v.bv_page, v.bv_offset, v.bv_len), - memset(v.iov_base, 0, v.iov_len) + memset(v.iov_base, 0, v.iov_len), + memzero_page(v.bv_page, v.bv_offset, v.bv_len) ) return bytes; @@ -992,7 +1060,9 @@ size_t iov_iter_copy_from_user_atomic(struct page *page, copyin((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page, v.bv_offset, v.bv_len), - memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len), + memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len) ) kunmap_atomic(kaddr); return bytes; @@ -1078,11 +1148,17 @@ void iov_iter_advance(struct iov_iter *i, size_t size) i->count -= size; return; } + if (unlikely(iov_iter_is_xarray(i))) { + size = min(size, i->count); + i->iov_offset += size; + i->count -= size; + return; + } if (iov_iter_is_bvec(i)) { iov_iter_bvec_advance(i, size); return; } - iterate_and_advance(i, size, v, 0, 0, 0) + iterate_and_advance(i, size, v, 0, 0, 0, 0) } EXPORT_SYMBOL(iov_iter_advance); @@ -1126,7 +1202,12 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll) return; } unroll -= i->iov_offset; - if (iov_iter_is_bvec(i)) { + if (iov_iter_is_xarray(i)) { + BUG(); /* We should never go beyond the start of the specified + * range since we might then be straying into pages that + * aren't pinned. + */ + } else if (iov_iter_is_bvec(i)) { const struct bio_vec *bvec = i->bvec; while (1) { size_t n = (--bvec)->bv_len; @@ -1163,9 +1244,9 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i) return i->count; // it is a silly place, anyway if (i->nr_segs == 1) return i->count; - if (unlikely(iov_iter_is_discard(i))) + if (unlikely(iov_iter_is_discard(i) || iov_iter_is_xarray(i))) return i->count; - else if (iov_iter_is_bvec(i)) + if (iov_iter_is_bvec(i)) return min(i->count, i->bvec->bv_len - i->iov_offset); else return min(i->count, i->iov->iov_len - i->iov_offset); @@ -1213,6 +1294,31 @@ void iov_iter_pipe(struct iov_iter *i, unsigned int direction, } EXPORT_SYMBOL(iov_iter_pipe); +/** + * iov_iter_xarray - Initialise an I/O iterator to use the pages in an xarray + * @i: The iterator to initialise. + * @direction: The direction of the transfer. + * @xarray: The xarray to access. + * @start: The start file position. + * @count: The size of the I/O buffer in bytes. + * + * Set up an I/O iterator to either draw data out of the pages attached to an + * inode or to inject data into those pages. The pages *must* be prevented + * from evaporation, either by taking a ref on them or locking them by the + * caller. + */ +void iov_iter_xarray(struct iov_iter *i, unsigned int direction, + struct xarray *xarray, loff_t start, size_t count) +{ + BUG_ON(direction & ~1); + i->type = ITER_XARRAY | (direction & (READ | WRITE)); + i->xarray = xarray; + i->xarray_start = start; + i->count = count; + i->iov_offset = 0; +} +EXPORT_SYMBOL(iov_iter_xarray); + /** * iov_iter_discard - Initialise an I/O iterator that discards data * @i: The iterator to initialise. @@ -1243,10 +1349,13 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) return size | i->iov_offset; return size; } + if (unlikely(iov_iter_is_xarray(i))) + return (i->xarray_start + i->iov_offset) | i->count; iterate_all_kinds(i, size, v, (res |= (unsigned long)v.iov_base | v.iov_len, 0), res |= v.bv_offset | v.bv_len, - res |= (unsigned long)v.iov_base | v.iov_len + res |= (unsigned long)v.iov_base | v.iov_len, + res |= v.bv_offset | v.bv_len ) return res; } @@ -1268,7 +1377,9 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i) (res |= (!res ? 0 : (unsigned long)v.bv_offset) | (size != v.bv_len ? size : 0)), (res |= (!res ? 0 : (unsigned long)v.iov_base) | - (size != v.iov_len ? size : 0)) + (size != v.iov_len ? size : 0)), + (res |= (!res ? 0 : (unsigned long)v.bv_offset) | + (size != v.bv_len ? size : 0)) ); return res; } @@ -1318,6 +1429,75 @@ static ssize_t pipe_get_pages(struct iov_iter *i, return __pipe_get_pages(i, min(maxsize, capacity), pages, iter_head, start); } +static ssize_t iter_xarray_populate_pages(struct page **pages, struct xarray *xa, + pgoff_t index, unsigned int nr_pages) +{ + XA_STATE(xas, xa, index); + struct page *page; + unsigned int ret = 0; + + rcu_read_lock(); + for (page = xas_load(&xas); page; page = xas_next(&xas)) { + if (xas_retry(&xas, page)) + continue; + + /* Has the page moved or been split? */ + if (unlikely(page != xas_reload(&xas))) { + xas_reset(&xas); + continue; + } + + pages[ret] = find_subpage(page, xas.xa_index); + get_page(pages[ret]); + if (++ret == nr_pages) + break; + } + rcu_read_unlock(); + return ret; +} + +static ssize_t iter_xarray_get_pages(struct iov_iter *i, + struct page **pages, size_t maxsize, + unsigned maxpages, size_t *_start_offset) +{ + unsigned nr, offset; + pgoff_t index, count; + size_t size = maxsize, actual; + loff_t pos; + + if (!size || !maxpages) + return 0; + + pos = i->xarray_start + i->iov_offset; + index = pos >> PAGE_SHIFT; + offset = pos & ~PAGE_MASK; + *_start_offset = offset; + + count = 1; + if (size > PAGE_SIZE - offset) { + size -= PAGE_SIZE - offset; + count += size >> PAGE_SHIFT; + size &= ~PAGE_MASK; + if (size) + count++; + } + + if (count > maxpages) + count = maxpages; + + nr = iter_xarray_populate_pages(pages, i->xarray, index, count); + if (nr == 0) + return 0; + + actual = PAGE_SIZE * nr; + actual -= offset; + if (nr == count && size > 0) { + unsigned last_offset = (nr > 1) ? 0 : offset; + actual -= PAGE_SIZE - (last_offset + size); + } + return actual; +} + ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) @@ -1327,6 +1507,8 @@ ssize_t iov_iter_get_pages(struct iov_iter *i, if (unlikely(iov_iter_is_pipe(i))) return pipe_get_pages(i, pages, maxsize, maxpages, start); + if (unlikely(iov_iter_is_xarray(i))) + return iter_xarray_get_pages(i, pages, maxsize, maxpages, start); if (unlikely(iov_iter_is_discard(i))) return -EFAULT; @@ -1353,7 +1535,8 @@ ssize_t iov_iter_get_pages(struct iov_iter *i, return v.bv_len; }),({ return -EFAULT; - }) + }), + 0 ) return 0; } @@ -1397,6 +1580,51 @@ static ssize_t pipe_get_pages_alloc(struct iov_iter *i, return n; } +static ssize_t iter_xarray_get_pages_alloc(struct iov_iter *i, + struct page ***pages, size_t maxsize, + size_t *_start_offset) +{ + struct page **p; + unsigned nr, offset; + pgoff_t index, count; + size_t size = maxsize, actual; + loff_t pos; + + if (!size) + return 0; + + pos = i->xarray_start + i->iov_offset; + index = pos >> PAGE_SHIFT; + offset = pos & ~PAGE_MASK; + *_start_offset = offset; + + count = 1; + if (size > PAGE_SIZE - offset) { + size -= PAGE_SIZE - offset; + count += size >> PAGE_SHIFT; + size &= ~PAGE_MASK; + if (size) + count++; + } + + p = get_pages_array(count); + if (!p) + return -ENOMEM; + *pages = p; + + nr = iter_xarray_populate_pages(p, i->xarray, index, count); + if (nr == 0) + return 0; + + actual = PAGE_SIZE * nr; + actual -= offset; + if (nr == count && size > 0) { + unsigned last_offset = (nr > 1) ? 0 : offset; + actual -= PAGE_SIZE - (last_offset + size); + } + return actual; +} + ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, size_t maxsize, size_t *start) @@ -1408,6 +1636,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, if (unlikely(iov_iter_is_pipe(i))) return pipe_get_pages_alloc(i, pages, maxsize, start); + if (unlikely(iov_iter_is_xarray(i))) + return iter_xarray_get_pages_alloc(i, pages, maxsize, start); if (unlikely(iov_iter_is_discard(i))) return -EFAULT; @@ -1440,7 +1670,7 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, return v.bv_len; }),({ return -EFAULT; - }) + }), 0 ) return 0; } @@ -1478,6 +1708,13 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, v.iov_base, v.iov_len, sum, off); off += v.iov_len; + }), ({ + char *p = kmap_atomic(v.bv_page); + sum = csum_and_memcpy((to += v.bv_len) - v.bv_len, + p + v.bv_offset, v.bv_len, + sum, off); + kunmap_atomic(p); + off += v.bv_len; }) ) *csum = sum; @@ -1519,6 +1756,13 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, v.iov_base, v.iov_len, sum, off); off += v.iov_len; + }), ({ + char *p = kmap_atomic(v.bv_page); + sum = csum_and_memcpy((to += v.bv_len) - v.bv_len, + p + v.bv_offset, v.bv_len, + sum, off); + kunmap_atomic(p); + off += v.bv_len; }) ) *csum = sum; @@ -1565,6 +1809,13 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *_csstate, (from += v.iov_len) - v.iov_len, v.iov_len, sum, off); off += v.iov_len; + }), ({ + char *p = kmap_atomic(v.bv_page); + sum = csum_and_memcpy(p + v.bv_offset, + (from += v.bv_len) - v.bv_len, + v.bv_len, sum, off); + kunmap_atomic(p); + off += v.bv_len; }) ) csstate->csum = sum; @@ -1615,6 +1866,21 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages) npages = pipe_space_for_user(iter_head, pipe->tail, pipe); if (npages >= maxpages) return maxpages; + } else if (unlikely(iov_iter_is_xarray(i))) { + unsigned offset; + + offset = (i->xarray_start + i->iov_offset) & ~PAGE_MASK; + + npages = 1; + if (size > PAGE_SIZE - offset) { + size -= PAGE_SIZE - offset; + npages += size >> PAGE_SHIFT; + size &= ~PAGE_MASK; + if (size) + npages++; + } + if (npages >= maxpages) + return maxpages; } else iterate_all_kinds(i, size, v, ({ unsigned long p = (unsigned long)v.iov_base; npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE) @@ -1631,7 +1897,8 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages) - p / PAGE_SIZE; if (npages >= maxpages) return maxpages; - }) + }), + 0 ) return npages; } @@ -1644,7 +1911,7 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) WARN_ON(1); return NULL; } - if (unlikely(iov_iter_is_discard(new))) + if (unlikely(iov_iter_is_discard(new) || iov_iter_is_xarray(new))) return NULL; if (iov_iter_is_bvec(new)) return new->bvec = kmemdup(new->bvec, @@ -1849,7 +2116,12 @@ int iov_iter_for_each_range(struct iov_iter *i, size_t bytes, kunmap(v.bv_page); err;}), ({ w = v; - err = f(&w, context);}) + err = f(&w, context);}), ({ + w.iov_base = kmap(v.bv_page) + v.bv_offset; + w.iov_len = v.bv_len; + err = f(&w, context); + kunmap(v.bv_page); + err;}) ) return err; } diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7998affa45d49a27b8613931ae3eb81499eef926..c87d5b6a8a55a3c02719ebfde3761f948ec2c35b 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -251,12 +251,13 @@ static int kobj_usermode_filter(struct kobject *kobj) static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem) { + int buffer_size = sizeof(env->buf) - env->buflen; int len; - len = strlcpy(&env->buf[env->buflen], subsystem, - sizeof(env->buf) - env->buflen); - if (len >= (sizeof(env->buf) - env->buflen)) { - WARN(1, KERN_ERR "init_uevent_argv: buffer size too small\n"); + len = strlcpy(&env->buf[env->buflen], subsystem, buffer_size); + if (len >= buffer_size) { + pr_warn("init_uevent_argv: buffer size of %d too small, needed %d\n", + buffer_size, len); return -ENOMEM; } diff --git a/lib/list_sort.c b/lib/list_sort.c index 52f0c258c895a0fb62ef1384774a38036648e848..a926d96ffd44d3b6e90b2b5c71bfbae18e9fe19d 100644 --- a/lib/list_sort.c +++ b/lib/list_sort.c @@ -7,16 +7,13 @@ #include <linux/list_sort.h> #include <linux/list.h> -typedef int __attribute__((nonnull(2,3))) (*cmp_func)(void *, - struct list_head const *, struct list_head const *); - /* * Returns a list organized in an intermediate format suited * to chaining of merge() calls: null-terminated, no reserved or * sentinel head node, "prev" links not maintained. */ __attribute__((nonnull(2,3,4))) -static struct list_head *merge(void *priv, cmp_func cmp, +static struct list_head *merge(void *priv, list_cmp_func_t cmp, struct list_head *a, struct list_head *b) { struct list_head *head, **tail = &head; @@ -52,7 +49,7 @@ static struct list_head *merge(void *priv, cmp_func cmp, * throughout. */ __attribute__((nonnull(2,3,4,5))) -static void merge_final(void *priv, cmp_func cmp, struct list_head *head, +static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head, struct list_head *a, struct list_head *b) { struct list_head *tail = head; @@ -185,9 +182,7 @@ static void merge_final(void *priv, cmp_func cmp, struct list_head *head, * 2^(k+1) - 1 (second merge of case 5 when x == 2^(k-1) - 1). */ __attribute__((nonnull(2,3))) -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)) +void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp) { struct list_head *list = head->next, *pending = NULL; size_t count = 0; /* Count of pending */ @@ -227,7 +222,7 @@ void list_sort(void *priv, struct list_head *head, if (likely(bits)) { struct list_head *a = *tail, *b = a->prev; - a = merge(priv, (cmp_func)cmp, b, a); + a = merge(priv, cmp, b, a); /* Install the merged result in place of the inputs */ a->prev = b->prev; *tail = a; @@ -249,10 +244,10 @@ void list_sort(void *priv, struct list_head *head, if (!next) break; - list = merge(priv, (cmp_func)cmp, pending, list); + list = merge(priv, cmp, pending, list); pending = next; } /* The final merge, rebuilding prev links */ - merge_final(priv, (cmp_func)cmp, head, pending, list); + merge_final(priv, cmp, head, pending, list); } EXPORT_SYMBOL(list_sort); diff --git a/lib/oid_registry.c b/lib/oid_registry.c index f7ad43f28579359cf352f51ecf4be580e9e70444..3dfaa836e7c58ab6337829c85daacdc404beff75 100644 --- a/lib/oid_registry.c +++ b/lib/oid_registry.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/bug.h> +#include <linux/asn1.h> #include "oid_registry_data.c" MODULE_DESCRIPTION("OID Registry"); @@ -92,6 +93,29 @@ enum OID look_up_OID(const void *data, size_t datasize) } EXPORT_SYMBOL_GPL(look_up_OID); +/** + * parse_OID - Parse an OID from a bytestream + * @data: Binary representation of the header + OID + * @datasize: Size of the binary representation + * @oid: Pointer to oid to return result + * + * Parse an OID from a bytestream that holds the OID in the format + * ASN1_OID | length | oid. The length indicator must equal to datasize - 2. + * -EBADMSG is returned if the bytestream is too short. + */ +int parse_OID(const void *data, size_t datasize, enum OID *oid) +{ + const unsigned char *v = data; + + /* we need 2 bytes of header and at least 1 byte for oid */ + if (datasize < 3 || v[0] != ASN1_OID || v[1] != datasize - 2) + return -EBADMSG; + + *oid = look_up_OID(data + 2, datasize - 2); + return 0; +} +EXPORT_SYMBOL_GPL(parse_OID); + /* * sprint_OID - Print an Object Identifier into a buffer * @data: The encoded OID to print diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e5647d147b35059d4cb06f41c375fb62b37ea14e..785e724ce0d8881b780ca4602d2b871d90ff9093 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -69,10 +69,10 @@ static void kasan_test_exit(struct kunit *test) * resource named "kasan_data". Do not use this name for KUnit resources * outside of KASAN tests. * - * For hardware tag-based KASAN, when a tag fault happens, tag checking is - * normally auto-disabled. When this happens, this test handler reenables - * tag checking. As tag checking can be only disabled or enabled per CPU, this - * handler disables migration (preemption). + * For hardware tag-based KASAN in sync mode, when a tag fault happens, tag + * checking is auto-disabled. When this happens, this test handler reenables + * tag checking. As tag checking can be only disabled or enabled per CPU, + * this handler disables migration (preemption). * * Since the compiler doesn't see that the expression can change the fail_data * fields, it can reorder or optimize away the accesses to those fields. @@ -80,7 +80,8 @@ static void kasan_test_exit(struct kunit *test) * expression to prevent that. */ #define KUNIT_EXPECT_KASAN_FAIL(test, expression) do { \ - if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) \ + if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ + !kasan_async_mode_enabled()) \ migrate_disable(); \ WRITE_ONCE(fail_data.report_expected, true); \ WRITE_ONCE(fail_data.report_found, false); \ @@ -92,12 +93,16 @@ static void kasan_test_exit(struct kunit *test) barrier(); \ expression; \ barrier(); \ + if (kasan_async_mode_enabled()) \ + kasan_force_async_fault(); \ + barrier(); \ KUNIT_EXPECT_EQ(test, \ READ_ONCE(fail_data.report_expected), \ READ_ONCE(fail_data.report_found)); \ - if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) { \ + if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ + !kasan_async_mode_enabled()) { \ if (READ_ONCE(fail_data.report_found)) \ - kasan_enable_tagging(); \ + kasan_enable_tagging_sync(); \ migrate_enable(); \ } \ } while (0) diff --git a/lib/test_list_sort.c b/lib/test_list_sort.c index 1f017d3b610ee3fbfcee18a73c348d96e3e66a92..00daaf23316f4881f857d7d0aecfa3746f41da4c 100644 --- a/lib/test_list_sort.c +++ b/lib/test_list_sort.c @@ -56,7 +56,8 @@ static int __init check(struct debug_el *ela, struct debug_el *elb) return 0; } -static int __init cmp(void *priv, struct list_head *a, struct list_head *b) +static int __init cmp(void *priv, const struct list_head *a, + const struct list_head *b) { struct debug_el *ela, *elb; diff --git a/mm/filemap.c b/mm/filemap.c index 36969780f87f6f3c939e49012afababe32dffb9d..9d4583e4981542c515b168edcfcd9b2cde469fa8 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1432,6 +1432,67 @@ void unlock_page(struct page *page) } EXPORT_SYMBOL(unlock_page); +/** + * end_page_private_2 - Clear PG_private_2 and release any waiters + * @page: The page + * + * Clear the PG_private_2 bit on a page and wake up any sleepers waiting for + * this. The page ref held for PG_private_2 being set is released. + * + * This is, for example, used when a netfs page is being written to a local + * disk cache, thereby allowing writes to the cache for the same page to be + * serialised. + */ +void end_page_private_2(struct page *page) +{ + page = compound_head(page); + VM_BUG_ON_PAGE(!PagePrivate2(page), page); + clear_bit_unlock(PG_private_2, &page->flags); + wake_up_page_bit(page, PG_private_2); + put_page(page); +} +EXPORT_SYMBOL(end_page_private_2); + +/** + * wait_on_page_private_2 - Wait for PG_private_2 to be cleared on a page + * @page: The page to wait on + * + * Wait for PG_private_2 (aka PG_fscache) to be cleared on a page. + */ +void wait_on_page_private_2(struct page *page) +{ + page = compound_head(page); + while (PagePrivate2(page)) + wait_on_page_bit(page, PG_private_2); +} +EXPORT_SYMBOL(wait_on_page_private_2); + +/** + * wait_on_page_private_2_killable - Wait for PG_private_2 to be cleared on a page + * @page: The page to wait on + * + * Wait for PG_private_2 (aka PG_fscache) to be cleared on a page or until a + * fatal signal is received by the calling task. + * + * Return: + * - 0 if successful. + * - -EINTR if a fatal signal was encountered. + */ +int wait_on_page_private_2_killable(struct page *page) +{ + int ret = 0; + + page = compound_head(page); + while (PagePrivate2(page)) { + ret = wait_on_page_bit_killable(page, PG_private_2); + if (ret < 0) + break; + } + + return ret; +} +EXPORT_SYMBOL(wait_on_page_private_2_killable); + /** * end_page_writeback - end writeback against a page * @page: the page @@ -2778,7 +2839,7 @@ static struct file *do_sync_mmap_readahead(struct vm_fault *vmf) struct file *file = vmf->vma->vm_file; struct file_ra_state *ra = &file->f_ra; struct address_space *mapping = file->f_mapping; - DEFINE_READAHEAD(ractl, file, mapping, vmf->pgoff); + DEFINE_READAHEAD(ractl, file, ra, mapping, vmf->pgoff); struct file *fpin = NULL; unsigned int mmap_miss; @@ -2790,7 +2851,7 @@ static struct file *do_sync_mmap_readahead(struct vm_fault *vmf) if (vmf->vma->vm_flags & VM_SEQ_READ) { fpin = maybe_unlock_mmap_for_io(vmf, fpin); - page_cache_sync_ra(&ractl, ra, ra->ra_pages); + page_cache_sync_ra(&ractl, ra->ra_pages); return fpin; } diff --git a/mm/internal.h b/mm/internal.h index cb3c5e0a7799f50cb7778dc977a5060a4cac7f87..bbe900f9f095ac58b5c4661a5ae26602f48a3497 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -51,13 +51,12 @@ void unmap_page_range(struct mmu_gather *tlb, void do_page_cache_ra(struct readahead_control *, unsigned long nr_to_read, unsigned long lookahead_size); -void force_page_cache_ra(struct readahead_control *, struct file_ra_state *, - unsigned long nr); +void force_page_cache_ra(struct readahead_control *, unsigned long nr); static inline void force_page_cache_readahead(struct address_space *mapping, struct file *file, pgoff_t index, unsigned long nr_to_read) { - DEFINE_READAHEAD(ractl, file, mapping, index); - force_page_cache_ra(&ractl, &file->f_ra, nr_to_read); + DEFINE_READAHEAD(ractl, file, &file->f_ra, mapping, index); + force_page_cache_ra(&ractl, nr_to_read); } unsigned find_lock_entries(struct address_space *mapping, pgoff_t start, diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c index 2aad21fda156e4d79e5198a856b1e5da293de46f..4004388b4e4bc35d471fdf4809d46d3473be8a53 100644 --- a/mm/kasan/hw_tags.c +++ b/mm/kasan/hw_tags.c @@ -25,6 +25,12 @@ enum kasan_arg { KASAN_ARG_ON, }; +enum kasan_arg_mode { + KASAN_ARG_MODE_DEFAULT, + KASAN_ARG_MODE_SYNC, + KASAN_ARG_MODE_ASYNC, +}; + enum kasan_arg_stacktrace { KASAN_ARG_STACKTRACE_DEFAULT, KASAN_ARG_STACKTRACE_OFF, @@ -38,6 +44,7 @@ enum kasan_arg_fault { }; static enum kasan_arg kasan_arg __ro_after_init; +static enum kasan_arg_mode kasan_arg_mode __ro_after_init; static enum kasan_arg_stacktrace kasan_arg_stacktrace __ro_after_init; static enum kasan_arg_fault kasan_arg_fault __ro_after_init; @@ -45,6 +52,10 @@ static enum kasan_arg_fault kasan_arg_fault __ro_after_init; DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled); EXPORT_SYMBOL(kasan_flag_enabled); +/* Whether the asynchronous mode is enabled. */ +bool kasan_flag_async __ro_after_init; +EXPORT_SYMBOL_GPL(kasan_flag_async); + /* Whether to collect alloc/free stack traces. */ DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace); @@ -68,6 +79,23 @@ static int __init early_kasan_flag(char *arg) } early_param("kasan", early_kasan_flag); +/* kasan.mode=sync/async */ +static int __init early_kasan_mode(char *arg) +{ + if (!arg) + return -EINVAL; + + if (!strcmp(arg, "sync")) + kasan_arg_mode = KASAN_ARG_MODE_SYNC; + else if (!strcmp(arg, "async")) + kasan_arg_mode = KASAN_ARG_MODE_ASYNC; + else + return -EINVAL; + + return 0; +} +early_param("kasan.mode", early_kasan_mode); + /* kasan.stacktrace=off/on */ static int __init early_kasan_flag_stacktrace(char *arg) { @@ -115,7 +143,15 @@ void kasan_init_hw_tags_cpu(void) return; hw_init_tags(KASAN_TAG_MAX); - hw_enable_tagging(); + + /* + * Enable async mode only when explicitly requested through + * the command line. + */ + if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC) + hw_enable_tagging_async(); + else + hw_enable_tagging_sync(); } /* kasan_init_hw_tags() is called once on boot CPU. */ @@ -132,6 +168,22 @@ void __init kasan_init_hw_tags(void) /* Enable KASAN. */ static_branch_enable(&kasan_flag_enabled); + switch (kasan_arg_mode) { + case KASAN_ARG_MODE_DEFAULT: + /* + * Default to sync mode. + * Do nothing, kasan_flag_async keeps its default value. + */ + break; + case KASAN_ARG_MODE_SYNC: + /* Do nothing, kasan_flag_async keeps its default value. */ + break; + case KASAN_ARG_MODE_ASYNC: + /* Async mode enabled. */ + kasan_flag_async = true; + break; + } + switch (kasan_arg_stacktrace) { case KASAN_ARG_STACKTRACE_DEFAULT: /* Default to enabling stack trace collection. */ @@ -194,10 +246,16 @@ void kasan_set_tagging_report_once(bool state) } EXPORT_SYMBOL_GPL(kasan_set_tagging_report_once); -void kasan_enable_tagging(void) +void kasan_enable_tagging_sync(void) +{ + hw_enable_tagging_sync(); +} +EXPORT_SYMBOL_GPL(kasan_enable_tagging_sync); + +void kasan_force_async_fault(void) { - hw_enable_tagging(); + hw_force_async_tag_fault(); } -EXPORT_SYMBOL_GPL(kasan_enable_tagging); +EXPORT_SYMBOL_GPL(kasan_force_async_fault); #endif diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 3436c6bf7c0c7c4d0da3b628b35a8bfbba875c96..c1581e8a9b8e0046c2c9fed647505224ce297922 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -7,20 +7,37 @@ #include <linux/stackdepot.h> #ifdef CONFIG_KASAN_HW_TAGS + #include <linux/static_key.h> + DECLARE_STATIC_KEY_FALSE(kasan_flag_stacktrace); +extern bool kasan_flag_async __ro_after_init; + static inline bool kasan_stack_collection_enabled(void) { return static_branch_unlikely(&kasan_flag_stacktrace); } + +static inline bool kasan_async_mode_enabled(void) +{ + return kasan_flag_async; +} #else + static inline bool kasan_stack_collection_enabled(void) { return true; } + +static inline bool kasan_async_mode_enabled(void) +{ + return false; +} + #endif extern bool kasan_flag_panic __ro_after_init; +extern bool kasan_flag_async __ro_after_init; #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) #define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) @@ -275,8 +292,11 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) #ifdef CONFIG_KASAN_HW_TAGS -#ifndef arch_enable_tagging -#define arch_enable_tagging() +#ifndef arch_enable_tagging_sync +#define arch_enable_tagging_sync() +#endif +#ifndef arch_enable_tagging_async +#define arch_enable_tagging_async() #endif #ifndef arch_init_tags #define arch_init_tags(max_tag) @@ -284,6 +304,9 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) #ifndef arch_set_tagging_report_once #define arch_set_tagging_report_once(state) #endif +#ifndef arch_force_async_tag_fault +#define arch_force_async_tag_fault() +#endif #ifndef arch_get_random_tag #define arch_get_random_tag() (0xFF) #endif @@ -294,16 +317,19 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) #define arch_set_mem_tag_range(addr, size, tag) ((void *)(addr)) #endif -#define hw_enable_tagging() arch_enable_tagging() +#define hw_enable_tagging_sync() arch_enable_tagging_sync() +#define hw_enable_tagging_async() arch_enable_tagging_async() #define hw_init_tags(max_tag) arch_init_tags(max_tag) #define hw_set_tagging_report_once(state) arch_set_tagging_report_once(state) +#define hw_force_async_tag_fault() arch_force_async_tag_fault() #define hw_get_random_tag() arch_get_random_tag() #define hw_get_mem_tag(addr) arch_get_mem_tag(addr) #define hw_set_mem_tag_range(addr, size, tag) arch_set_mem_tag_range((addr), (size), (tag)) #else /* CONFIG_KASAN_HW_TAGS */ -#define hw_enable_tagging() +#define hw_enable_tagging_sync() +#define hw_enable_tagging_async() #define hw_set_tagging_report_once(state) #endif /* CONFIG_KASAN_HW_TAGS */ @@ -311,12 +337,14 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) #if defined(CONFIG_KASAN_HW_TAGS) && IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) void kasan_set_tagging_report_once(bool state); -void kasan_enable_tagging(void); +void kasan_enable_tagging_sync(void); +void kasan_force_async_fault(void); #else /* CONFIG_KASAN_HW_TAGS || CONFIG_KASAN_KUNIT_TEST */ static inline void kasan_set_tagging_report_once(bool state) { } -static inline void kasan_enable_tagging(void) { } +static inline void kasan_enable_tagging_sync(void) { } +static inline void kasan_force_async_fault(void) { } #endif /* CONFIG_KASAN_HW_TAGS || CONFIG_KASAN_KUNIT_TEST */ diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 87b271206163b8682f818276158812a1c01fe3eb..14bd51ea234836101bb596044b778a59e0b5171e 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -87,7 +87,8 @@ static void start_report(unsigned long *flags) static void end_report(unsigned long *flags, unsigned long addr) { - trace_error_report_end(ERROR_DETECTOR_KASAN, addr); + if (!kasan_async_mode_enabled()) + trace_error_report_end(ERROR_DETECTOR_KASAN, addr); pr_err("==================================================================\n"); add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); spin_unlock_irqrestore(&report_lock, *flags); @@ -360,6 +361,25 @@ void kasan_report_invalid_free(void *object, unsigned long ip) end_report(&flags, (unsigned long)object); } +#ifdef CONFIG_KASAN_HW_TAGS +void kasan_report_async(void) +{ + unsigned long flags; + +#if IS_ENABLED(CONFIG_KUNIT) + if (current->kunit_test) + kasan_update_kunit_status(current->kunit_test); +#endif /* IS_ENABLED(CONFIG_KUNIT) */ + + start_report(&flags); + pr_err("BUG: KASAN: invalid-access\n"); + pr_err("Asynchronous mode enabled: no access details available\n"); + pr_err("\n"); + dump_stack(); + end_report(&flags, 0); +} +#endif /* CONFIG_KASAN_HW_TAGS */ + static void __kasan_report(unsigned long addr, size_t size, bool is_write, unsigned long ip) { diff --git a/mm/mmap.c b/mm/mmap.c index 340cb04dbc535c62b75703c2d768b86938689345..e40a8f3af74f37b958a1e2682a7aab74d3f82de5 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -93,6 +93,12 @@ static void unmap_region(struct mm_struct *mm, * MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes * w: (no) no w: (no) no w: (copy) copy w: (no) no * x: (no) no x: (no) yes x: (no) yes x: (yes) yes + * + * On arm64, PROT_EXEC has the following behaviour for both MAP_SHARED and + * MAP_PRIVATE (with Enhanced PAN supported): + * r: (no) no + * w: (no) no + * x: (yes) yes */ pgprot_t protection_map[16] __ro_after_init = { __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, diff --git a/mm/page_alloc.c b/mm/page_alloc.c index aded7714034a28f8c2bec7ee5a63fe55aa4e06d7..36a7ad74c0c6455d8143b755583762ceb4941fc9 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -167,10 +167,10 @@ unsigned long totalcma_pages __read_mostly; int percpu_pagelist_fraction; gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; -DEFINE_STATIC_KEY_FALSE(init_on_alloc); +DEFINE_STATIC_KEY_MAYBE(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, init_on_alloc); EXPORT_SYMBOL(init_on_alloc); -DEFINE_STATIC_KEY_FALSE(init_on_free); +DEFINE_STATIC_KEY_MAYBE(CONFIG_INIT_ON_FREE_DEFAULT_ON, init_on_free); EXPORT_SYMBOL(init_on_free); static bool _init_on_alloc_enabled_early __read_mostly diff --git a/mm/readahead.c b/mm/readahead.c index a6bfa987a04aaa06a253c91b4dc691cb39726ede..6f29b73bbe5b8236223bdf725596dcb42987dffa 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -208,8 +208,6 @@ void page_cache_ra_unbounded(struct readahead_control *ractl, for (i = 0; i < nr_to_read; i++) { struct page *page = xa_load(&mapping->i_pages, index + i); - BUG_ON(index + i != ractl->_index + ractl->_nr_pages); - if (page && !xa_is_value(page)) { /* * Page already present? Kick off the current batch @@ -220,6 +218,7 @@ void page_cache_ra_unbounded(struct readahead_control *ractl, * not worth getting one just for that. */ read_pages(ractl, &page_pool, true); + i = ractl->_index + ractl->_nr_pages - index - 1; continue; } @@ -233,6 +232,7 @@ void page_cache_ra_unbounded(struct readahead_control *ractl, gfp_mask) < 0) { put_page(page); read_pages(ractl, &page_pool, true); + i = ractl->_index + ractl->_nr_pages - index - 1; continue; } if (i == nr_to_read - lookahead_size) @@ -282,9 +282,10 @@ void do_page_cache_ra(struct readahead_control *ractl, * memory at once. */ void force_page_cache_ra(struct readahead_control *ractl, - struct file_ra_state *ra, unsigned long nr_to_read) + unsigned long nr_to_read) { struct address_space *mapping = ractl->mapping; + struct file_ra_state *ra = ractl->ra; struct backing_dev_info *bdi = inode_to_bdi(mapping->host); unsigned long max_pages, index; @@ -443,10 +444,10 @@ static int try_context_readahead(struct address_space *mapping, * A minimal readahead algorithm for trivial sequential/random reads. */ static void ondemand_readahead(struct readahead_control *ractl, - struct file_ra_state *ra, bool hit_readahead_marker, - unsigned long req_size) + bool hit_readahead_marker, unsigned long req_size) { struct backing_dev_info *bdi = inode_to_bdi(ractl->mapping->host); + struct file_ra_state *ra = ractl->ra; unsigned long max_pages = ra->ra_pages; unsigned long add_pages; unsigned long index = readahead_index(ractl); @@ -560,7 +561,7 @@ readit: } void page_cache_sync_ra(struct readahead_control *ractl, - struct file_ra_state *ra, unsigned long req_count) + unsigned long req_count) { bool do_forced_ra = ractl->file && (ractl->file->f_mode & FMODE_RANDOM); @@ -570,7 +571,7 @@ void page_cache_sync_ra(struct readahead_control *ractl, * read-ahead will do the right thing and limit the read to just the * requested range, which we'll set to 1 page for this case. */ - if (!ra->ra_pages || blk_cgroup_congested()) { + if (!ractl->ra->ra_pages || blk_cgroup_congested()) { if (!ractl->file) return; req_count = 1; @@ -579,21 +580,20 @@ void page_cache_sync_ra(struct readahead_control *ractl, /* be dumb */ if (do_forced_ra) { - force_page_cache_ra(ractl, ra, req_count); + force_page_cache_ra(ractl, req_count); return; } /* do read-ahead */ - ondemand_readahead(ractl, ra, false, req_count); + ondemand_readahead(ractl, false, req_count); } EXPORT_SYMBOL_GPL(page_cache_sync_ra); void page_cache_async_ra(struct readahead_control *ractl, - struct file_ra_state *ra, struct page *page, - unsigned long req_count) + struct page *page, unsigned long req_count) { /* no read-ahead */ - if (!ra->ra_pages) + if (!ractl->ra->ra_pages) return; /* @@ -614,7 +614,7 @@ void page_cache_async_ra(struct readahead_control *ractl, return; /* do read-ahead */ - ondemand_readahead(ractl, ra, true, req_count); + ondemand_readahead(ractl, true, req_count); } EXPORT_SYMBOL_GPL(page_cache_async_ra); @@ -648,3 +648,78 @@ SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count) { return ksys_readahead(fd, offset, count); } + +/** + * readahead_expand - Expand a readahead request + * @ractl: The request to be expanded + * @new_start: The revised start + * @new_len: The revised size of the request + * + * Attempt to expand a readahead request outwards from the current size to the + * specified size by inserting locked pages before and after the current window + * to increase the size to the new window. This may involve the insertion of + * THPs, in which case the window may get expanded even beyond what was + * requested. + * + * The algorithm will stop if it encounters a conflicting page already in the + * pagecache and leave a smaller expansion than requested. + * + * The caller must check for this by examining the revised @ractl object for a + * different expansion than was requested. + */ +void readahead_expand(struct readahead_control *ractl, + loff_t new_start, size_t new_len) +{ + struct address_space *mapping = ractl->mapping; + struct file_ra_state *ra = ractl->ra; + pgoff_t new_index, new_nr_pages; + gfp_t gfp_mask = readahead_gfp_mask(mapping); + + new_index = new_start / PAGE_SIZE; + + /* Expand the leading edge downwards */ + while (ractl->_index > new_index) { + unsigned long index = ractl->_index - 1; + struct page *page = xa_load(&mapping->i_pages, index); + + if (page && !xa_is_value(page)) + return; /* Page apparently present */ + + page = __page_cache_alloc(gfp_mask); + if (!page) + return; + if (add_to_page_cache_lru(page, mapping, index, gfp_mask) < 0) { + put_page(page); + return; + } + + ractl->_nr_pages++; + ractl->_index = page->index; + } + + new_len += new_start - readahead_pos(ractl); + new_nr_pages = DIV_ROUND_UP(new_len, PAGE_SIZE); + + /* Expand the trailing edge upwards */ + while (ractl->_nr_pages < new_nr_pages) { + unsigned long index = ractl->_index + ractl->_nr_pages; + struct page *page = xa_load(&mapping->i_pages, index); + + if (page && !xa_is_value(page)) + return; /* Page apparently present */ + + page = __page_cache_alloc(gfp_mask); + if (!page) + return; + if (add_to_page_cache_lru(page, mapping, index, gfp_mask) < 0) { + put_page(page); + return; + } + ractl->_nr_pages++; + if (ra) { + ra->size++; + ra->async_size++; + } + } +} +EXPORT_SYMBOL(readahead_expand); diff --git a/mm/slab.h b/mm/slab.h index 89bfef6cb79452329a6ffbfe6066dc66d08d5f7c..dd20077306c9c5d5e2b6c2dcddb5ad1fbb169027 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -632,7 +632,8 @@ static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { } static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) { - if (static_branch_unlikely(&init_on_alloc)) { + if (static_branch_maybe(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, + &init_on_alloc)) { if (c->ctor) return false; if (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) @@ -644,7 +645,8 @@ static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) static inline bool slab_want_init_on_free(struct kmem_cache *c) { - if (static_branch_unlikely(&init_on_free)) + if (static_branch_maybe(CONFIG_INIT_ON_FREE_DEFAULT_ON, + &init_on_free)) return !(c->ctor || (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON))); return false; diff --git a/net/bluetooth/ecdh_helper.c b/net/bluetooth/ecdh_helper.c index 3226fe02e8754c0670838c330ddff343d8894419..989401f116e915ecdc84bb3a0923f4e72ffa1f4c 100644 --- a/net/bluetooth/ecdh_helper.c +++ b/net/bluetooth/ecdh_helper.c @@ -126,8 +126,6 @@ int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32]) int err; struct ecdh p = {0}; - p.curve_id = ECC_CURVE_NIST_P256; - if (private_key) { tmp = kmalloc(32, GFP_KERNEL); if (!tmp) diff --git a/net/bluetooth/ecdh_helper.h b/net/bluetooth/ecdh_helper.h index a6f8d03d4aaf65514da3462eda3594c4795362f5..830723971cf831057816145c19aaeb804de4aef7 100644 --- a/net/bluetooth/ecdh_helper.h +++ b/net/bluetooth/ecdh_helper.h @@ -25,6 +25,6 @@ int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pair_public_key[64], u8 secret[32]); -int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 *private_key); +int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32]); int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]); int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]); diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index e55976db4403e7ad742d2721f6b8d9a3d91160bc..805ce546b8133d5f102d75602ea9a52f1d98f08c 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -272,12 +272,16 @@ int hci_req_sync(struct hci_dev *hdev, int (*req)(struct hci_request *req, { int ret; - if (!test_bit(HCI_UP, &hdev->flags)) - return -ENETDOWN; - /* Serialize all requests */ hci_req_sync_lock(hdev); - ret = __hci_req_sync(hdev, req, opt, timeout, hci_status); + /* check the state after obtaing the lock to protect the HCI_UP + * against any races from hci_dev_do_close when the controller + * gets removed. + */ + if (test_bit(HCI_UP, &hdev->flags)) + ret = __hci_req_sync(hdev, req, opt, timeout, hci_status); + else + ret = -ENETDOWN; hci_req_sync_unlock(hdev); return ret; diff --git a/net/bluetooth/selftest.c b/net/bluetooth/selftest.c index f71c6fa65fb35afabdf99d63bb795670abfe56ee..f49604d44b8778057acaeb2f2424a623f043547d 100644 --- a/net/bluetooth/selftest.c +++ b/net/bluetooth/selftest.c @@ -205,7 +205,7 @@ static int __init test_ecdh(void) calltime = ktime_get(); - tfm = crypto_alloc_kpp("ecdh", 0, 0); + tfm = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(tfm)) { BT_ERR("Unable to create ECDH crypto context"); err = PTR_ERR(tfm); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b0c1ee110eff92195bac6b7003193a887e1ca196..21e445993f39c4e6ef2d208125f9a6020c9b2f48 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1386,7 +1386,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) goto zfree_smp; } - smp->tfm_ecdh = crypto_alloc_kpp("ecdh", 0, 0); + smp->tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(smp->tfm_ecdh)) { BT_ERR("Unable to create ECDH crypto context"); goto free_shash; @@ -3281,7 +3281,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) return ERR_CAST(tfm_cmac); } - tfm_ecdh = crypto_alloc_kpp("ecdh", 0, 0); + tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(tfm_ecdh)) { BT_ERR("Unable to create ECDH crypto context"); crypto_free_shash(tfm_cmac); @@ -3806,7 +3806,7 @@ int __init bt_selftest_smp(void) return PTR_ERR(tfm_cmac); } - tfm_ecdh = crypto_alloc_kpp("ecdh", 0, 0); + tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(tfm_ecdh)) { BT_ERR("Unable to create ECDH crypto context"); crypto_free_shash(tfm_cmac); diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index ccb4916428116de6b81b09247491c3db1efef1b6..3e6ac9b790b15f1cd20c664d71ac21615adf7efa 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1539,7 +1539,7 @@ int __init netlbl_unlabel_defconf(void) /* Only the kernel is allowed to call this function and the only time * it is called is at bootup before the audit subsystem is reporting * messages so don't worry to much about these values. */ - security_task_getsecid(current, &audit_info.secid); + security_task_getsecid_subj(current, &audit_info.secid); audit_info.loginuid = GLOBAL_ROOT_UID; audit_info.sessionid = 0; diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h index 3c67afce64f128c7a6d795275883204270122b46..b9ba8112b3c524fd940c0220772f003c076399fc 100644 --- a/net/netlabel/netlabel_user.h +++ b/net/netlabel/netlabel_user.h @@ -34,7 +34,7 @@ static inline void netlbl_netlink_auditinfo(struct sk_buff *skb, struct netlbl_audit *audit_info) { - security_task_getsecid(current, &audit_info->secid); + security_task_getsecid_subj(current, &audit_info->secid); audit_info->loginuid = audit_get_loginuid(current); audit_info->sessionid = audit_get_sessionid(current); } diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 1204c438e87dc5ce92200f39f9888615923bb96b..9958b37d8f9d7baf5a3db35b5b35c4c75247ab43 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -229,6 +229,72 @@ static void nci_uart_tty_wakeup(struct tty_struct *tty) nci_uart_tx_wakeup(nu); } +/* -- Default recv_buf handler -- + * + * This handler supposes that NCI frames are sent over UART link without any + * framing. It reads NCI header, retrieve the packet size and once all packet + * bytes are received it passes it to nci_uart driver for processing. + */ +static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, + int count) +{ + int chunk_len; + + if (!nu->ndev) { + nfc_err(nu->tty->dev, + "receive data from tty but no NCI dev is attached yet, drop buffer\n"); + return 0; + } + + /* Decode all incoming data in packets + * and enqueue then for processing. + */ + while (count > 0) { + /* If this is the first data of a packet, allocate a buffer */ + if (!nu->rx_skb) { + nu->rx_packet_len = -1; + nu->rx_skb = nci_skb_alloc(nu->ndev, + NCI_MAX_PACKET_SIZE, + GFP_ATOMIC); + if (!nu->rx_skb) + return -ENOMEM; + } + + /* Eat byte after byte till full packet header is received */ + if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) { + skb_put_u8(nu->rx_skb, *data++); + --count; + continue; + } + + /* Header was received but packet len was not read */ + if (nu->rx_packet_len < 0) + nu->rx_packet_len = NCI_CTRL_HDR_SIZE + + nci_plen(nu->rx_skb->data); + + /* Compute how many bytes are missing and how many bytes can + * be consumed. + */ + chunk_len = nu->rx_packet_len - nu->rx_skb->len; + if (count < chunk_len) + chunk_len = count; + skb_put_data(nu->rx_skb, data, chunk_len); + data += chunk_len; + count -= chunk_len; + + /* Chcek if packet is fully received */ + if (nu->rx_packet_len == nu->rx_skb->len) { + /* Pass RX packet to driver */ + if (nu->ops.recv(nu, nu->rx_skb) != 0) + nfc_err(nu->tty->dev, "corrupted RX packet\n"); + /* Next packet will be a new one */ + nu->rx_skb = NULL; + } + } + + return 0; +} + /* nci_uart_tty_receive() * * Called by tty low level driver when receive data is @@ -250,7 +316,7 @@ static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data, return; spin_lock(&nu->rx_lock); - nu->ops.recv_buf(nu, (void *)data, flags, count); + nci_uart_default_recv_buf(nu, data, count); spin_unlock(&nu->rx_lock); tty_unthrottle(tty); @@ -321,78 +387,6 @@ static int nci_uart_send(struct nci_uart *nu, struct sk_buff *skb) return 0; } -/* -- Default recv_buf handler -- - * - * This handler supposes that NCI frames are sent over UART link without any - * framing. It reads NCI header, retrieve the packet size and once all packet - * bytes are received it passes it to nci_uart driver for processing. - */ -static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, - char *flags, int count) -{ - int chunk_len; - - if (!nu->ndev) { - nfc_err(nu->tty->dev, - "receive data from tty but no NCI dev is attached yet, drop buffer\n"); - return 0; - } - - /* Decode all incoming data in packets - * and enqueue then for processing. - */ - while (count > 0) { - /* If this is the first data of a packet, allocate a buffer */ - if (!nu->rx_skb) { - nu->rx_packet_len = -1; - nu->rx_skb = nci_skb_alloc(nu->ndev, - NCI_MAX_PACKET_SIZE, - GFP_ATOMIC); - if (!nu->rx_skb) - return -ENOMEM; - } - - /* Eat byte after byte till full packet header is received */ - if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) { - skb_put_u8(nu->rx_skb, *data++); - --count; - continue; - } - - /* Header was received but packet len was not read */ - if (nu->rx_packet_len < 0) - nu->rx_packet_len = NCI_CTRL_HDR_SIZE + - nci_plen(nu->rx_skb->data); - - /* Compute how many bytes are missing and how many bytes can - * be consumed. - */ - chunk_len = nu->rx_packet_len - nu->rx_skb->len; - if (count < chunk_len) - chunk_len = count; - skb_put_data(nu->rx_skb, data, chunk_len); - data += chunk_len; - count -= chunk_len; - - /* Chcek if packet is fully received */ - if (nu->rx_packet_len == nu->rx_skb->len) { - /* Pass RX packet to driver */ - if (nu->ops.recv(nu, nu->rx_skb) != 0) - nfc_err(nu->tty->dev, "corrupted RX packet\n"); - /* Next packet will be a new one */ - nu->rx_skb = NULL; - } - } - - return 0; -} - -/* -- Default recv handler -- */ -static int nci_uart_default_recv(struct nci_uart *nu, struct sk_buff *skb) -{ - return nci_recv_frame(nu->ndev, skb); -} - int nci_uart_register(struct nci_uart *nu) { if (!nu || !nu->ops.open || @@ -402,12 +396,6 @@ int nci_uart_register(struct nci_uart *nu) /* Set the send callback */ nu->ops.send = nci_uart_send; - /* Install default handlers if not overridden */ - if (!nu->ops.recv_buf) - nu->ops.recv_buf = nci_uart_default_recv_buf; - if (!nu->ops.recv) - nu->ops.recv = nci_uart_default_recv; - /* Add this driver in the driver list */ if (nci_uart_drivers[nu->driver]) { pr_err("driver %d is already registered\n", nu->driver); @@ -453,7 +441,6 @@ void nci_uart_set_config(struct nci_uart *nu, int baudrate, int flow_ctrl) EXPORT_SYMBOL_GPL(nci_uart_set_config); static struct tty_ldisc_ops nci_uart_ldisc = { - .magic = TTY_LDISC_MAGIC, .owner = THIS_MODULE, .name = "n_nci", .open = nci_uart_tty_open, @@ -469,7 +456,6 @@ static struct tty_ldisc_ops nci_uart_ldisc = { static int __init nci_uart_init(void) { - memset(nci_uart_drivers, 0, sizeof(nci_uart_drivers)); return tty_register_ldisc(N_NCI, &nci_uart_ldisc); } diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index fef3573fdc8bc270d15cd37bb74ef12c2acff226..eca6dda26c77eba836b53ee1983d3636340cc918 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -669,6 +669,7 @@ wait_error: * @sock: The socket that the call exists on * @call: The call to send data through * @iter: The buffer to receive into + * @_len: The amount of data we want to receive (decreased on return) * @want_more: True if more data is expected to be read * @_abort: Where the abort code is stored if -ECONNABORTED is returned * @_service: Where to store the actual service ID (may be upgraded) @@ -684,7 +685,7 @@ wait_error: * *_abort should also be initialised to 0. */ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, - struct iov_iter *iter, + struct iov_iter *iter, size_t *_len, bool want_more, u32 *_abort, u16 *_service) { size_t offset = 0; @@ -692,7 +693,7 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, _enter("{%d,%s},%zu,%d", call->debug_id, rxrpc_call_states[call->state], - iov_iter_count(iter), want_more); + *_len, want_more); ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_SECURING); @@ -703,8 +704,8 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, case RXRPC_CALL_SERVER_RECV_REQUEST: case RXRPC_CALL_SERVER_ACK_REQUEST: ret = rxrpc_recvmsg_data(sock, call, NULL, iter, - iov_iter_count(iter), 0, - &offset); + *_len, 0, &offset); + *_len -= offset; if (ret < 0) goto out; diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 3cdd71a8df1e777acf9180db81640776cd07f4d9..42565f0c7d5a7110b338721cb4b4832237aabfac 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -139,6 +139,20 @@ int svc_print_xprts(char *buf, int maxlen) return len; } +/** + * svc_xprt_deferred_close - Close a transport + * @xprt: transport instance + * + * Used in contexts that need to defer the work of shutting down + * the transport to an nfsd thread. + */ +void svc_xprt_deferred_close(struct svc_xprt *xprt) +{ + if (!test_and_set_bit(XPT_CLOSE, &xprt->xpt_flags)) + svc_xprt_enqueue(xprt); +} +EXPORT_SYMBOL_GPL(svc_xprt_deferred_close); + static void svc_xprt_free(struct kref *kref) { struct svc_xprt *xprt = @@ -233,21 +247,25 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, return xprt; } -/* - * svc_xprt_received conditionally queues the transport for processing - * by another thread. The caller must hold the XPT_BUSY bit and must +/** + * svc_xprt_received - start next receiver thread + * @xprt: controlling transport + * + * The caller must hold the XPT_BUSY bit and must * not thereafter touch transport data. * * Note: XPT_DATA only gets cleared when a read-attempt finds no (or * insufficient) data. */ -static void svc_xprt_received(struct svc_xprt *xprt) +void svc_xprt_received(struct svc_xprt *xprt) { if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) { WARN_ONCE(1, "xprt=0x%p already busy!", xprt); return; } + trace_svc_xprt_received(xprt); + /* As soon as we clear busy, the xprt could be closed and * 'put', so we need a reference to call svc_enqueue_xprt with: */ @@ -257,6 +275,7 @@ static void svc_xprt_received(struct svc_xprt *xprt) xprt->xpt_server->sv_ops->svo_enqueue_xprt(xprt); svc_xprt_put(xprt); } +EXPORT_SYMBOL_GPL(svc_xprt_received); void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) { @@ -801,8 +820,10 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) newxpt->xpt_cred = get_cred(xprt->xpt_cred); svc_add_new_temp_xprt(serv, newxpt); trace_svc_xprt_accept(newxpt, serv->sv_name); - } else + } else { module_put(xprt->xpt_class->xcl_owner); + } + svc_xprt_received(xprt); } else if (svc_xprt_reserve_slot(rqstp, xprt)) { /* XPT_DATA|XPT_DEFERRED case: */ dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", @@ -817,8 +838,6 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) rqstp->rq_reserved = serv->sv_max_mesg; atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); } - /* clear XPT_BUSY: */ - svc_xprt_received(xprt); out: trace_svc_handle_xprt(xprt, len); return len; @@ -1229,6 +1248,7 @@ static noinline int svc_deferred_recv(struct svc_rqst *rqstp) rqstp->rq_xprt_hlen = dr->xprt_hlen; rqstp->rq_daddr = dr->daddr; rqstp->rq_respages = rqstp->rq_pages; + svc_xprt_received(rqstp->rq_xprt); return (dr->argslen<<2) - dr->xprt_hlen; } diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 97c0bddba7a305167eabd70be175024ea58fbe6f..35b7966ac3b3bff13e2a87c2af5a36625e34b16a 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -303,15 +303,6 @@ static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, return NULL; } -static inline struct ip_map *ip_map_lookup(struct net *net, char *class, - struct in6_addr *addr) -{ - struct sunrpc_net *sn; - - sn = net_generic(net, sunrpc_net_id); - return __ip_map_lookup(sn->ip_map_cache, class, addr); -} - static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time64_t expiry) { diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 2e2f007dfc9f1ff9d5e367f97bc1d0480e9ab506..9eb5b6b890773e06fa0116f7c0549ae1c677d238 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -519,6 +519,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) if (serv->sv_stats) serv->sv_stats->netudpcnt++; + svc_xprt_received(rqstp->rq_xprt); return len; out_recv_err: @@ -527,7 +528,7 @@ out_recv_err: set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); } trace_svcsock_udp_recv_err(&svsk->sk_xprt, err); - return 0; + goto out_clear_busy; out_cmsg_err: net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram\n", cmh->cmsg_level, cmh->cmsg_type); @@ -536,6 +537,8 @@ out_bh_enable: local_bh_enable(); out_free: kfree_skb(skb); +out_clear_busy: + svc_xprt_received(rqstp->rq_xprt); return 0; } @@ -728,10 +731,8 @@ static void svc_tcp_state_change(struct sock *sk) rmb(); svsk->sk_ostate(sk); trace_svcsock_tcp_state(&svsk->sk_xprt, svsk->sk_sock); - if (sk->sk_state != TCP_ESTABLISHED) { - set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); - svc_xprt_enqueue(&svsk->sk_xprt); - } + if (sk->sk_state != TCP_ESTABLISHED) + svc_xprt_deferred_close(&svsk->sk_xprt); } } @@ -901,7 +902,7 @@ err_too_large: net_notice_ratelimited("svc: %s %s RPC fragment too large: %d\n", __func__, svsk->sk_xprt.xpt_server->sv_name, svc_sock_reclen(svsk)); - set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); + svc_xprt_deferred_close(&svsk->sk_xprt); err_short: return -EAGAIN; } @@ -1035,6 +1036,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (serv->sv_stats) serv->sv_stats->nettcpcnt++; + svc_xprt_received(rqstp->rq_xprt); return rqstp->rq_arg.len; err_incomplete: @@ -1052,13 +1054,14 @@ error: if (len != -EAGAIN) goto err_delete; trace_svcsock_tcp_recv_eagain(&svsk->sk_xprt, 0); - return 0; + goto err_noclose; err_nuts: svsk->sk_datalen = 0; err_delete: trace_svcsock_tcp_recv_err(&svsk->sk_xprt, len); - set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); + svc_xprt_deferred_close(&svsk->sk_xprt); err_noclose: + svc_xprt_received(rqstp->rq_xprt); return 0; /* record not complete */ } @@ -1188,8 +1191,7 @@ out_close: xprt->xpt_server->sv_name, (err < 0) ? "got error" : "sent", (err < 0) ? err : sent, xdr->len); - set_bit(XPT_CLOSE, &xprt->xpt_flags); - svc_xprt_enqueue(xprt); + svc_xprt_deferred_close(xprt); atomic_dec(&svsk->sk_sendqlen); mutex_unlock(&xprt->xpt_mutex); return -EAGAIN; @@ -1268,7 +1270,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) case TCP_ESTABLISHED: break; default: - set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); + svc_xprt_deferred_close(&svsk->sk_xprt); } } } diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 9150df35fb6f2633fb08f1180f8b14ebfcde505b..16897fcb659c19f74d684d77068d7c03c14a2ff2 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -93,7 +93,13 @@ static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma, */ get_page(virt_to_page(rqst->rq_buffer)); sctxt->sc_send_wr.opcode = IB_WR_SEND; - return svc_rdma_send(rdma, sctxt); + ret = svc_rdma_send(rdma, sctxt); + if (ret < 0) + return ret; + + ret = wait_for_completion_killable(&sctxt->sc_done); + svc_rdma_send_ctxt_put(rdma, sctxt); + return ret; } /* Server-side transport endpoint wants a whole page for its send diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 7d34290e2ff8de633f24f5287d85e216e01cede3..6be23ce7a93d216d83cf92d91324a033215b2f32 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -89,8 +89,7 @@ * svc_rdma_recvfrom call returns. * * During the second svc_rdma_recvfrom call, RDMA Read sink pages - * are transferred from the svc_rdma_recv_ctxt to the second svc_rqst - * (see rdma_read_complete() below). + * are transferred from the svc_rdma_recv_ctxt to the second svc_rqst. */ #include <linux/slab.h> @@ -107,8 +106,6 @@ #include "xprt_rdma.h" #include <trace/events/rpcrdma.h> -#define RPCDBG_FACILITY RPCDBG_SVCXPRT - static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc); static inline struct svc_rdma_recv_ctxt * @@ -230,11 +227,6 @@ out_empty: void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma, struct svc_rdma_recv_ctxt *ctxt) { - unsigned int i; - - for (i = 0; i < ctxt->rc_page_count; i++) - put_page(ctxt->rc_pages[i]); - pcl_free(&ctxt->rc_call_pcl); pcl_free(&ctxt->rc_read_pcl); pcl_free(&ctxt->rc_write_pcl); @@ -266,33 +258,48 @@ void svc_rdma_release_rqst(struct svc_rqst *rqstp) svc_rdma_recv_ctxt_put(rdma, ctxt); } -static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma, - struct svc_rdma_recv_ctxt *ctxt) +static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma, + unsigned int wanted, bool temp) { + const struct ib_recv_wr *bad_wr = NULL; + struct svc_rdma_recv_ctxt *ctxt; + struct ib_recv_wr *recv_chain; int ret; - trace_svcrdma_post_recv(ctxt); - ret = ib_post_recv(rdma->sc_qp, &ctxt->rc_recv_wr, NULL); - if (ret) - goto err_post; - return 0; + if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) + return false; -err_post: - trace_svcrdma_rq_post_err(rdma, ret); - svc_rdma_recv_ctxt_put(rdma, ctxt); - return ret; -} + recv_chain = NULL; + while (wanted--) { + ctxt = svc_rdma_recv_ctxt_get(rdma); + if (!ctxt) + break; -static int svc_rdma_post_recv(struct svcxprt_rdma *rdma) -{ - struct svc_rdma_recv_ctxt *ctxt; + trace_svcrdma_post_recv(ctxt); + ctxt->rc_temp = temp; + ctxt->rc_recv_wr.next = recv_chain; + recv_chain = &ctxt->rc_recv_wr; + rdma->sc_pending_recvs++; + } + if (!recv_chain) + return false; - if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) - return 0; - ctxt = svc_rdma_recv_ctxt_get(rdma); - if (!ctxt) - return -ENOMEM; - return __svc_rdma_post_recv(rdma, ctxt); + ret = ib_post_recv(rdma->sc_qp, recv_chain, &bad_wr); + if (ret) + goto err_free; + return true; + +err_free: + trace_svcrdma_rq_post_err(rdma, ret); + while (bad_wr) { + ctxt = container_of(bad_wr, struct svc_rdma_recv_ctxt, + rc_recv_wr); + bad_wr = bad_wr->next; + svc_rdma_recv_ctxt_put(rdma, ctxt); + } + /* Since we're destroying the xprt, no need to reset + * sc_pending_recvs. */ + return false; } /** @@ -303,20 +310,7 @@ static int svc_rdma_post_recv(struct svcxprt_rdma *rdma) */ bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma) { - struct svc_rdma_recv_ctxt *ctxt; - unsigned int i; - int ret; - - for (i = 0; i < rdma->sc_max_requests; i++) { - ctxt = svc_rdma_recv_ctxt_get(rdma); - if (!ctxt) - return false; - ctxt->rc_temp = true; - ret = __svc_rdma_post_recv(rdma, ctxt); - if (ret) - return false; - } - return true; + return svc_rdma_refresh_recvs(rdma, rdma->sc_max_requests, true); } /** @@ -324,8 +318,6 @@ bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma) * @cq: Completion Queue context * @wc: Work Completion object * - * NB: The svc_xprt/svcxprt_rdma is pinned whenever it's possible that - * the Receive completion handler could be running. */ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) { @@ -333,6 +325,8 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) struct ib_cqe *cqe = wc->wr_cqe; struct svc_rdma_recv_ctxt *ctxt; + rdma->sc_pending_recvs--; + /* WARNING: Only wc->wr_cqe and wc->status are reliable */ ctxt = container_of(cqe, struct svc_rdma_recv_ctxt, rc_cqe); @@ -340,8 +334,18 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) if (wc->status != IB_WC_SUCCESS) goto flushed; - if (svc_rdma_post_recv(rdma)) - goto post_err; + /* If receive posting fails, the connection is about to be + * lost anyway. The server will not be able to send a reply + * for this RPC, and the client will retransmit this RPC + * anyway when it reconnects. + * + * Therefore we drop the Receive, even if status was SUCCESS + * to reduce the likelihood of replayed requests once the + * client reconnects. + */ + if (rdma->sc_pending_recvs < rdma->sc_max_requests) + if (!svc_rdma_refresh_recvs(rdma, rdma->sc_recv_batch, false)) + goto flushed; /* All wc fields are now known to be valid */ ctxt->rc_byte_len = wc->byte_len; @@ -356,10 +360,8 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) return; flushed: -post_err: svc_rdma_recv_ctxt_put(rdma, ctxt); - set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags); - svc_xprt_enqueue(&rdma->sc_xprt); + svc_xprt_deferred_close(&rdma->sc_xprt); } /** @@ -371,10 +373,6 @@ void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma) { struct svc_rdma_recv_ctxt *ctxt; - while ((ctxt = svc_rdma_next_recv_ctxt(&rdma->sc_read_complete_q))) { - list_del(&ctxt->rc_list); - svc_rdma_recv_ctxt_put(rdma, ctxt); - } while ((ctxt = svc_rdma_next_recv_ctxt(&rdma->sc_rq_dto_q))) { list_del(&ctxt->rc_list); svc_rdma_recv_ctxt_put(rdma, ctxt); @@ -712,35 +710,6 @@ out_inval: return -EINVAL; } -static void rdma_read_complete(struct svc_rqst *rqstp, - struct svc_rdma_recv_ctxt *head) -{ - int page_no; - - /* Move Read chunk pages to rqstp so that they will be released - * when svc_process is done with them. - */ - for (page_no = 0; page_no < head->rc_page_count; page_no++) { - put_page(rqstp->rq_pages[page_no]); - rqstp->rq_pages[page_no] = head->rc_pages[page_no]; - } - head->rc_page_count = 0; - - /* Point rq_arg.pages past header */ - rqstp->rq_arg.pages = &rqstp->rq_pages[head->rc_hdr_count]; - rqstp->rq_arg.page_len = head->rc_arg.page_len; - - /* rq_respages starts after the last arg page */ - rqstp->rq_respages = &rqstp->rq_pages[page_no]; - rqstp->rq_next_page = rqstp->rq_respages + 1; - - /* Rebuild rq_arg head and tail. */ - rqstp->rq_arg.head[0] = head->rc_arg.head[0]; - rqstp->rq_arg.tail[0] = head->rc_arg.tail[0]; - rqstp->rq_arg.len = head->rc_arg.len; - rqstp->rq_arg.buflen = head->rc_arg.buflen; -} - static void svc_rdma_send_error(struct svcxprt_rdma *rdma, struct svc_rdma_recv_ctxt *rctxt, int status) @@ -825,25 +794,22 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) rqstp->rq_xprt_ctxt = NULL; + ctxt = NULL; spin_lock(&rdma_xprt->sc_rq_dto_lock); - ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_read_complete_q); - if (ctxt) { - list_del(&ctxt->rc_list); - spin_unlock(&rdma_xprt->sc_rq_dto_lock); - rdma_read_complete(rqstp, ctxt); - goto complete; - } ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_rq_dto_q); - if (!ctxt) { + if (ctxt) + list_del(&ctxt->rc_list); + else /* No new incoming requests, terminate the loop */ clear_bit(XPT_DATA, &xprt->xpt_flags); - spin_unlock(&rdma_xprt->sc_rq_dto_lock); - return 0; - } - list_del(&ctxt->rc_list); spin_unlock(&rdma_xprt->sc_rq_dto_lock); - percpu_counter_inc(&svcrdma_stat_recv); + /* Unblock the transport for the next receive */ + svc_xprt_received(xprt); + if (!ctxt) + return 0; + + percpu_counter_inc(&svcrdma_stat_recv); ib_dma_sync_single_for_cpu(rdma_xprt->sc_pd->device, ctxt->rc_recv_sge.addr, ctxt->rc_byte_len, DMA_FROM_DEVICE); @@ -868,21 +834,17 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) svc_rdma_get_inv_rkey(rdma_xprt, ctxt); if (!pcl_is_empty(&ctxt->rc_read_pcl) || - !pcl_is_empty(&ctxt->rc_call_pcl)) - goto out_readlist; + !pcl_is_empty(&ctxt->rc_call_pcl)) { + ret = svc_rdma_process_read_list(rdma_xprt, rqstp, ctxt); + if (ret < 0) + goto out_readfail; + } -complete: rqstp->rq_xprt_ctxt = ctxt; rqstp->rq_prot = IPPROTO_MAX; svc_xprt_copy_addrs(rqstp, xprt); return rqstp->rq_arg.len; -out_readlist: - ret = svc_rdma_process_read_list(rdma_xprt, rqstp, ctxt); - if (ret < 0) - goto out_readfail; - return 0; - out_err: svc_rdma_send_error(rdma_xprt, ctxt, ret); svc_rdma_recv_ctxt_put(rdma_xprt, ctxt); diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 693d139a86332f6aef39be85fcb339e58689d775..5238bc829235b63ee36275e55d987d57df9dbb86 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -150,6 +150,8 @@ struct svc_rdma_chunk_ctxt { struct svcxprt_rdma *cc_rdma; struct list_head cc_rwctxts; int cc_sqecount; + enum ib_wc_status cc_status; + struct completion cc_done; }; static void svc_rdma_cc_cid_init(struct svcxprt_rdma *rdma, @@ -250,7 +252,7 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc) wake_up(&rdma->sc_send_wait); if (unlikely(wc->status != IB_WC_SUCCESS)) - set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags); + svc_xprt_deferred_close(&rdma->sc_xprt); svc_rdma_write_info_free(info); } @@ -299,29 +301,15 @@ static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc) struct svc_rdma_chunk_ctxt *cc = container_of(cqe, struct svc_rdma_chunk_ctxt, cc_cqe); struct svcxprt_rdma *rdma = cc->cc_rdma; - struct svc_rdma_read_info *info = - container_of(cc, struct svc_rdma_read_info, ri_cc); trace_svcrdma_wc_read(wc, &cc->cc_cid); atomic_add(cc->cc_sqecount, &rdma->sc_sq_avail); wake_up(&rdma->sc_send_wait); - if (unlikely(wc->status != IB_WC_SUCCESS)) { - set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags); - svc_rdma_recv_ctxt_put(rdma, info->ri_readctxt); - } else { - spin_lock(&rdma->sc_rq_dto_lock); - list_add_tail(&info->ri_readctxt->rc_list, - &rdma->sc_read_complete_q); - /* Note the unlock pairs with the smp_rmb in svc_xprt_ready: */ - set_bit(XPT_DATA, &rdma->sc_xprt.xpt_flags); - spin_unlock(&rdma->sc_rq_dto_lock); - - svc_xprt_enqueue(&rdma->sc_xprt); - } - - svc_rdma_read_info_free(info); + cc->cc_status = wc->status; + complete(&cc->cc_done); + return; } /* This function sleeps when the transport's Send Queue is congested. @@ -334,7 +322,6 @@ static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc) static int svc_rdma_post_chunk_ctxt(struct svc_rdma_chunk_ctxt *cc) { struct svcxprt_rdma *rdma = cc->cc_rdma; - struct svc_xprt *xprt = &rdma->sc_xprt; struct ib_send_wr *first_wr; const struct ib_send_wr *bad_wr; struct list_head *tmp; @@ -373,7 +360,7 @@ static int svc_rdma_post_chunk_ctxt(struct svc_rdma_chunk_ctxt *cc) } while (1); trace_svcrdma_sq_post_err(rdma, ret); - set_bit(XPT_CLOSE, &xprt->xpt_flags); + svc_xprt_deferred_close(&rdma->sc_xprt); /* If even one was posted, there will be a completion. */ if (bad_wr != first_wr) @@ -677,8 +664,8 @@ static int svc_rdma_build_read_segment(struct svc_rdma_read_info *info, struct svc_rdma_recv_ctxt *head = info->ri_readctxt; struct svc_rdma_chunk_ctxt *cc = &info->ri_cc; struct svc_rqst *rqstp = info->ri_rqst; - struct svc_rdma_rw_ctxt *ctxt; unsigned int sge_no, seg_len, len; + struct svc_rdma_rw_ctxt *ctxt; struct scatterlist *sg; int ret; @@ -694,8 +681,6 @@ static int svc_rdma_build_read_segment(struct svc_rdma_read_info *info, seg_len = min_t(unsigned int, len, PAGE_SIZE - info->ri_pageoff); - head->rc_arg.pages[info->ri_pageno] = - rqstp->rq_pages[info->ri_pageno]; if (!info->ri_pageoff) head->rc_page_count++; @@ -789,12 +774,10 @@ static int svc_rdma_copy_inline_range(struct svc_rdma_read_info *info, page_len = min_t(unsigned int, remaining, PAGE_SIZE - info->ri_pageoff); - head->rc_arg.pages[info->ri_pageno] = - rqstp->rq_pages[info->ri_pageno]; if (!info->ri_pageoff) head->rc_page_count++; - dst = page_address(head->rc_arg.pages[info->ri_pageno]); + dst = page_address(rqstp->rq_pages[info->ri_pageno]); memcpy(dst + info->ri_pageno, src + offset, page_len); info->ri_totalbytes += page_len; @@ -814,7 +797,7 @@ static int svc_rdma_copy_inline_range(struct svc_rdma_read_info *info, * svc_rdma_read_multiple_chunks - Construct RDMA Reads to pull data item Read chunks * @info: context for RDMA Reads * - * The chunk data lands in head->rc_arg as a series of contiguous pages, + * The chunk data lands in rqstp->rq_arg as a series of contiguous pages, * like an incoming TCP call. * * Return values: @@ -828,8 +811,8 @@ static noinline int svc_rdma_read_multiple_chunks(struct svc_rdma_read_info *inf { struct svc_rdma_recv_ctxt *head = info->ri_readctxt; const struct svc_rdma_pcl *pcl = &head->rc_read_pcl; + struct xdr_buf *buf = &info->ri_rqst->rq_arg; struct svc_rdma_chunk *chunk, *next; - struct xdr_buf *buf = &head->rc_arg; unsigned int start, length; int ret; @@ -865,9 +848,9 @@ static noinline int svc_rdma_read_multiple_chunks(struct svc_rdma_read_info *inf buf->len += info->ri_totalbytes; buf->buflen += info->ri_totalbytes; - head->rc_hdr_count = 1; - buf->head[0].iov_base = page_address(head->rc_pages[0]); + buf->head[0].iov_base = page_address(info->ri_rqst->rq_pages[0]); buf->head[0].iov_len = min_t(size_t, PAGE_SIZE, info->ri_totalbytes); + buf->pages = &info->ri_rqst->rq_pages[1]; buf->page_len = info->ri_totalbytes - buf->head[0].iov_len; return 0; } @@ -876,9 +859,9 @@ static noinline int svc_rdma_read_multiple_chunks(struct svc_rdma_read_info *inf * svc_rdma_read_data_item - Construct RDMA Reads to pull data item Read chunks * @info: context for RDMA Reads * - * The chunk data lands in the page list of head->rc_arg.pages. + * The chunk data lands in the page list of rqstp->rq_arg.pages. * - * Currently NFSD does not look at the head->rc_arg.tail[0] iovec. + * Currently NFSD does not look at the rqstp->rq_arg.tail[0] kvec. * Therefore, XDR round-up of the Read chunk and trailing * inline content must both be added at the end of the pagelist. * @@ -892,7 +875,7 @@ static noinline int svc_rdma_read_multiple_chunks(struct svc_rdma_read_info *inf static int svc_rdma_read_data_item(struct svc_rdma_read_info *info) { struct svc_rdma_recv_ctxt *head = info->ri_readctxt; - struct xdr_buf *buf = &head->rc_arg; + struct xdr_buf *buf = &info->ri_rqst->rq_arg; struct svc_rdma_chunk *chunk; unsigned int length; int ret; @@ -902,8 +885,6 @@ static int svc_rdma_read_data_item(struct svc_rdma_read_info *info) if (ret < 0) goto out; - head->rc_hdr_count = 0; - /* Split the Receive buffer between the head and tail * buffers at Read chunk's position. XDR roundup of the * chunk is not included in either the pagelist or in @@ -922,7 +903,8 @@ static int svc_rdma_read_data_item(struct svc_rdma_read_info *info) * Currently these chunks always start at page offset 0, * thus the rounded-up length never crosses a page boundary. */ - length = XDR_QUADLEN(info->ri_totalbytes) << 2; + buf->pages = &info->ri_rqst->rq_pages[0]; + length = xdr_align_size(chunk->ch_length); buf->page_len = length; buf->len += length; buf->buflen += length; @@ -1034,8 +1016,7 @@ static int svc_rdma_read_call_chunk(struct svc_rdma_read_info *info) * @info: context for RDMA Reads * * The start of the data lands in the first page just after the - * Transport header, and the rest lands in the page list of - * head->rc_arg.pages. + * Transport header, and the rest lands in rqstp->rq_arg.pages. * * Assumptions: * - A PZRC is never sent in an RDMA_MSG message, though it's @@ -1050,8 +1031,7 @@ static int svc_rdma_read_call_chunk(struct svc_rdma_read_info *info) */ static noinline int svc_rdma_read_special(struct svc_rdma_read_info *info) { - struct svc_rdma_recv_ctxt *head = info->ri_readctxt; - struct xdr_buf *buf = &head->rc_arg; + struct xdr_buf *buf = &info->ri_rqst->rq_arg; int ret; ret = svc_rdma_read_call_chunk(info); @@ -1061,35 +1041,15 @@ static noinline int svc_rdma_read_special(struct svc_rdma_read_info *info) buf->len += info->ri_totalbytes; buf->buflen += info->ri_totalbytes; - head->rc_hdr_count = 1; - buf->head[0].iov_base = page_address(head->rc_pages[0]); + buf->head[0].iov_base = page_address(info->ri_rqst->rq_pages[0]); buf->head[0].iov_len = min_t(size_t, PAGE_SIZE, info->ri_totalbytes); + buf->pages = &info->ri_rqst->rq_pages[1]; buf->page_len = info->ri_totalbytes - buf->head[0].iov_len; out: return ret; } -/* Pages under I/O have been copied to head->rc_pages. Ensure they - * are not released by svc_xprt_release() until the I/O is complete. - * - * This has to be done after all Read WRs are constructed to properly - * handle a page that is part of I/O on behalf of two different RDMA - * segments. - * - * Do this only if I/O has been posted. Otherwise, we do indeed want - * svc_xprt_release() to clean things up properly. - */ -static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, - const unsigned int start, - const unsigned int num_pages) -{ - unsigned int i; - - for (i = start; i < num_pages + start; i++) - rqstp->rq_pages[i] = NULL; -} - /** * svc_rdma_process_read_list - Pull list of Read chunks from the client * @rdma: controlling RDMA transport @@ -1121,18 +1081,6 @@ int svc_rdma_process_read_list(struct svcxprt_rdma *rdma, struct svc_rdma_chunk_ctxt *cc; int ret; - /* The request (with page list) is constructed in - * head->rc_arg. Pages involved with RDMA Read I/O are - * transferred there. - */ - head->rc_arg.head[0] = rqstp->rq_arg.head[0]; - head->rc_arg.tail[0] = rqstp->rq_arg.tail[0]; - head->rc_arg.pages = head->rc_pages; - head->rc_arg.page_base = 0; - head->rc_arg.page_len = 0; - head->rc_arg.len = rqstp->rq_arg.len; - head->rc_arg.buflen = rqstp->rq_arg.buflen; - info = svc_rdma_read_info_alloc(rdma); if (!info) return -ENOMEM; @@ -1154,11 +1102,22 @@ int svc_rdma_process_read_list(struct svcxprt_rdma *rdma, goto out_err; trace_svcrdma_post_read_chunk(&cc->cc_cid, cc->cc_sqecount); + init_completion(&cc->cc_done); ret = svc_rdma_post_chunk_ctxt(cc); if (ret < 0) goto out_err; - svc_rdma_save_io_pages(rqstp, 0, head->rc_page_count); - return 1; + + ret = 1; + wait_for_completion(&cc->cc_done); + if (cc->cc_status != IB_WC_SUCCESS) + ret = -EIO; + + /* rq_respages starts after the last arg page */ + rqstp->rq_respages = &rqstp->rq_pages[head->rc_page_count]; + rqstp->rq_next_page = rqstp->rq_respages + 1; + + /* Ensure svc_rdma_recv_ctxt_put() does not try to release pages */ + head->rc_page_count = 0; out_err: svc_rdma_read_info_free(info); diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 52c759a8543ec86b96e6ba92d18c4cad6cea61c6..056452cabc9836f6f2cf6e5056eff472e371141b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -111,8 +111,6 @@ #include "xprt_rdma.h" #include <trace/events/rpcrdma.h> -#define RPCDBG_FACILITY RPCDBG_SVCXPRT - static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc); static inline struct svc_rdma_send_ctxt * @@ -157,6 +155,7 @@ svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma) ctxt->sc_send_wr.wr_cqe = &ctxt->sc_cqe; ctxt->sc_send_wr.sg_list = ctxt->sc_sges; ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED; + init_completion(&ctxt->sc_done); ctxt->sc_cqe.done = svc_rdma_wc_send; ctxt->sc_xprt_buf = buffer; xdr_buf_init(&ctxt->sc_hdrbuf, ctxt->sc_xprt_buf, @@ -220,7 +219,6 @@ out: ctxt->sc_send_wr.num_sge = 0; ctxt->sc_cur_sge_no = 0; - ctxt->sc_page_count = 0; return ctxt; out_empty: @@ -235,8 +233,6 @@ out_empty: * svc_rdma_send_ctxt_put - Return send_ctxt to free list * @rdma: controlling svcxprt_rdma * @ctxt: object to return to the free list - * - * Pages left in sc_pages are DMA unmapped and released. */ void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt) @@ -257,9 +253,6 @@ void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma, ctxt->sc_sges[i].length); } - for (i = 0; i < ctxt->sc_page_count; ++i) - put_page(ctxt->sc_pages[i]); - spin_lock(&rdma->sc_send_lock); list_add(&ctxt->sc_list, &rdma->sc_send_ctxts); spin_unlock(&rdma->sc_send_lock); @@ -282,15 +275,13 @@ static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc) trace_svcrdma_wc_send(wc, &ctxt->sc_cid); + complete(&ctxt->sc_done); + atomic_inc(&rdma->sc_sq_avail); wake_up(&rdma->sc_send_wait); - svc_rdma_send_ctxt_put(rdma, ctxt); - - if (unlikely(wc->status != IB_WC_SUCCESS)) { - set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags); - svc_xprt_enqueue(&rdma->sc_xprt); - } + if (unlikely(wc->status != IB_WC_SUCCESS)) + svc_xprt_deferred_close(&rdma->sc_xprt); } /** @@ -298,7 +289,7 @@ static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc) * @rdma: transport on which to post the WR * @ctxt: send ctxt with a Send WR ready to post * - * Returns zero the Send WR was posted successfully. Otherwise, a + * Returns zero if the Send WR was posted successfully. Otherwise, a * negative errno is returned. */ int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt) @@ -306,7 +297,7 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt) struct ib_send_wr *wr = &ctxt->sc_send_wr; int ret; - might_sleep(); + reinit_completion(&ctxt->sc_done); /* Sync the transport header buffer */ ib_dma_sync_single_for_device(rdma->sc_pd->device, @@ -336,7 +327,7 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt) } trace_svcrdma_sq_post_err(rdma, ret); - set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags); + svc_xprt_deferred_close(&rdma->sc_xprt); wake_up(&rdma->sc_send_wait); return ret; } @@ -795,25 +786,6 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, svc_rdma_xb_dma_map, &args); } -/* The svc_rqst and all resources it owns are released as soon as - * svc_rdma_sendto returns. Transfer pages under I/O to the ctxt - * so they are released by the Send completion handler. - */ -static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, - struct svc_rdma_send_ctxt *ctxt) -{ - int i, pages = rqstp->rq_next_page - rqstp->rq_respages; - - ctxt->sc_page_count += pages; - for (i = 0; i < pages; i++) { - ctxt->sc_pages[i] = rqstp->rq_respages[i]; - rqstp->rq_respages[i] = NULL; - } - - /* Prevent svc_xprt_release from releasing pages in rq_pages */ - rqstp->rq_next_page = rqstp->rq_respages; -} - /* Prepare the portion of the RPC Reply that will be transmitted * via RDMA Send. The RPC-over-RDMA transport header is prepared * in sc_sges[0], and the RPC xdr_buf is prepared in following sges. @@ -843,15 +815,20 @@ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, if (ret < 0) return ret; - svc_rdma_save_io_pages(rqstp, sctxt); - if (rctxt->rc_inv_rkey) { sctxt->sc_send_wr.opcode = IB_WR_SEND_WITH_INV; sctxt->sc_send_wr.ex.invalidate_rkey = rctxt->rc_inv_rkey; } else { sctxt->sc_send_wr.opcode = IB_WR_SEND; } - return svc_rdma_send(rdma, sctxt); + + ret = svc_rdma_send(rdma, sctxt); + if (ret < 0) + return ret; + + ret = wait_for_completion_killable(&sctxt->sc_done); + svc_rdma_send_ctxt_put(rdma, sctxt); + return ret; } /** @@ -917,7 +894,8 @@ void svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, sctxt->sc_sges[0].length = sctxt->sc_hdrbuf.len; if (svc_rdma_send(rdma, sctxt)) goto put_ctxt; - return; + + wait_for_completion_killable(&sctxt->sc_done); put_ctxt: svc_rdma_send_ctxt_put(rdma, sctxt); @@ -979,16 +957,17 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp); if (ret < 0) goto err1; + + /* Prevent svc_xprt_release() from releasing the page backing + * rq_res.head[0].iov_base. It's no longer being accessed by + * the I/O device. */ + rqstp->rq_respages++; return 0; err2: if (ret != -E2BIG && ret != -EINVAL) goto err1; - /* Send completion releases payload pages that were part - * of previously posted RDMA Writes. - */ - svc_rdma_save_io_pages(rqstp, sctxt); svc_rdma_send_error_msg(rdma, sctxt, rctxt, ret); return 0; @@ -996,7 +975,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) svc_rdma_send_ctxt_put(rdma, sctxt); err0: trace_svcrdma_send_err(rqstp, ret); - set_bit(XPT_CLOSE, &xprt->xpt_flags); + svc_xprt_deferred_close(&rdma->sc_xprt); return -ENOTCONN; } diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index c895f80df659c39a34880f461b4aac8322763298..d94b7759ada131bd2625613c5b58cde3bb5a8c09 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -119,8 +119,7 @@ static void qp_event_handler(struct ib_event *event, void *context) case IB_EVENT_QP_ACCESS_ERR: case IB_EVENT_DEVICE_FATAL: default: - set_bit(XPT_CLOSE, &xprt->xpt_flags); - svc_xprt_enqueue(xprt); + svc_xprt_deferred_close(xprt); break; } } @@ -137,7 +136,6 @@ static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv, svc_xprt_init(net, &svc_rdma_class, &cma_xprt->sc_xprt, serv); INIT_LIST_HEAD(&cma_xprt->sc_accept_q); INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q); - INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q); INIT_LIST_HEAD(&cma_xprt->sc_send_ctxts); init_llist_head(&cma_xprt->sc_recv_ctxts); INIT_LIST_HEAD(&cma_xprt->sc_rw_ctxts); @@ -279,12 +277,14 @@ static int svc_rdma_cma_handler(struct rdma_cm_id *cma_id, switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: clear_bit(RDMAXPRT_CONN_PENDING, &rdma->sc_flags); + + /* Handle any requests that were received while + * CONN_PENDING was set. */ svc_xprt_enqueue(xprt); break; case RDMA_CM_EVENT_DISCONNECTED: case RDMA_CM_EVENT_DEVICE_REMOVAL: - set_bit(XPT_CLOSE, &xprt->xpt_flags); - svc_xprt_enqueue(xprt); + svc_xprt_deferred_close(xprt); break; default: break; @@ -404,11 +404,14 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) newxprt->sc_max_req_size = svcrdma_max_req_size; newxprt->sc_max_requests = svcrdma_max_requests; newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; - rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests; + newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; if (rq_depth > dev->attrs.max_qp_wr) { pr_warn("svcrdma: reducing receive depth to %d\n", dev->attrs.max_qp_wr); rq_depth = dev->attrs.max_qp_wr; + newxprt->sc_recv_batch = 1; newxprt->sc_max_requests = rq_depth - 2; newxprt->sc_max_bc_requests = 2; } diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index ee5ac40ea2b618d8459497f946e91ee7cc0cf7ab..f8141443f2e21bed29658345969cdf5e3e4a0e9d 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -397,8 +397,8 @@ static struct publication *tipc_service_remove_publ(struct service_range *sr, * Code reused: time_after32() for the same purpose */ #define publication_after(pa, pb) time_after32((pa)->id, (pb)->id) -static int tipc_publ_sort(void *priv, struct list_head *a, - struct list_head *b) +static int tipc_publ_sort(void *priv, const struct list_head *a, + const struct list_head *b) { struct publication *pa, *pb; diff --git a/net/wireless/core.c b/net/wireless/core.c index a2785379df6e58d43d6b642412c5de113e510d24..589ee5a69a2e5cd7ca4680d8c5dfd08838d8ef1f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -332,14 +332,29 @@ static void cfg80211_event_work(struct work_struct *work) void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) { struct wireless_dev *wdev, *tmp; + bool found = false; ASSERT_RTNL(); - lockdep_assert_wiphy(&rdev->wiphy); + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + if (wdev->nl_owner_dead) { + if (wdev->netdev) + dev_close(wdev->netdev); + found = true; + } + } + + if (!found) + return; + + wiphy_lock(&rdev->wiphy); list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { - if (wdev->nl_owner_dead) + if (wdev->nl_owner_dead) { + cfg80211_leave(rdev, wdev); rdev_del_virtual_intf(rdev, wdev); + } } + wiphy_unlock(&rdev->wiphy); } static void cfg80211_destroy_iface_wk(struct work_struct *work) @@ -350,9 +365,7 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) destroy_work); rtnl_lock(); - wiphy_lock(&rdev->wiphy); cfg80211_destroy_ifaces(rdev); - wiphy_unlock(&rdev->wiphy); rtnl_unlock(); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b1df42e4f1eb9ad637e8190d243434430c28e102..a5224da6383285acf915b0eb7bb8c1884a3c28de 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3929,7 +3929,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) return err; } -static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) +static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; @@ -3938,9 +3938,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; - /* to avoid failing a new interface creation due to pending removal */ - cfg80211_destroy_ifaces(rdev); - memset(¶ms, 0, sizeof(params)); if (!info->attrs[NL80211_ATTR_IFNAME]) @@ -4028,6 +4025,21 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } +static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int ret; + + /* to avoid failing a new interface creation due to pending removal */ + cfg80211_destroy_ifaces(rdev); + + wiphy_lock(&rdev->wiphy); + ret = _nl80211_new_interface(skb, info); + wiphy_unlock(&rdev->wiphy); + + return ret; +} + static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -15040,7 +15052,9 @@ static const struct genl_small_ops nl80211_small_ops[] = { .doit = nl80211_new_interface, .flags = GENL_UNS_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_WIPHY | - NL80211_FLAG_NEED_RTNL, + NL80211_FLAG_NEED_RTNL | + /* we take the wiphy mutex later ourselves */ + NL80211_FLAG_NO_WIPHY_MTX, }, { .cmd = NL80211_CMD_DEL_INTERFACE, diff --git a/scripts/Makefile b/scripts/Makefile index c36106bce80ee273342558186ca3399b91eb72f1..9adb6d247818f1355e2e478256022cd10afd05f2 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -14,6 +14,7 @@ hostprogs-always-$(CONFIG_ASN1) += asn1_compiler hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert +hostprogs-always-$(CONFIG_SYSTEM_REVOCATION_LIST) += extract-cert HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 735e11e9041b9d6b8e9c5d7a05aca5b3be24a582..dd87cea9fba7852e7e8b9d3f729205f1dd5945c4 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -23,7 +23,7 @@ modname = $(notdir $(@:.mod.o=)) part-of-module = y quiet_cmd_cc_o_c = CC [M] $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI), $(c_flags)) -c -o $@ $< %.mod.o: %.mod.c FORCE $(call if_changed_dep,cc_o_c) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index df8b23dc1eb0af01280ae720331149086f10a506..f42e5ba16d9b5ea6a22c4f6894c0b9362ebaeb32 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -23,6 +23,9 @@ my $V = '0.32'; use Getopt::Long qw(:config no_auto_abbrev); my $quiet = 0; +my $verbose = 0; +my %verbose_messages = (); +my %verbose_emitted = (); my $tree = 1; my $chk_signoff = 1; my $chk_patch = 1; @@ -61,6 +64,7 @@ my $spelling_file = "$D/spelling.txt"; my $codespell = 0; my $codespellfile = "/usr/share/codespell/dictionary.txt"; my $conststructsfile = "$D/const_structs.checkpatch"; +my $docsfile = "$D/../Documentation/dev-tools/checkpatch.rst"; my $typedefsfile; my $color = "auto"; my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE @@ -78,6 +82,7 @@ Version: $V Options: -q, --quiet quiet + -v, --verbose verbose mode --no-tree run without a kernel tree --no-signoff do not check for 'Signed-off-by' line --patch treat FILE as patchfile (default) @@ -158,15 +163,51 @@ sub list_types { my $text = <$script>; close($script); - my @types = (); + my %types = (); # Also catch when type or level is passed through a variable - for ($text =~ /(?:(?:\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) { - push (@types, $_); + while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) { + if (defined($1)) { + if (exists($types{$2})) { + $types{$2} .= ",$1" if ($types{$2} ne $1); + } else { + $types{$2} = $1; + } + } else { + $types{$2} = "UNDETERMINED"; + } } - @types = sort(uniq(@types)); + print("#\tMessage type\n\n"); - foreach my $type (@types) { + if ($color) { + print(" ( Color coding: "); + print(RED . "ERROR" . RESET); + print(" | "); + print(YELLOW . "WARNING" . RESET); + print(" | "); + print(GREEN . "CHECK" . RESET); + print(" | "); + print("Multiple levels / Undetermined"); + print(" )\n\n"); + } + + foreach my $type (sort keys %types) { + my $orig_type = $type; + if ($color) { + my $level = $types{$type}; + if ($level eq "ERROR") { + $type = RED . $type . RESET; + } elsif ($level eq "WARN") { + $type = YELLOW . $type . RESET; + } elsif ($level eq "CHK") { + $type = GREEN . $type . RESET; + } + } print(++$count . "\t" . $type . "\n"); + if ($verbose && exists($verbose_messages{$orig_type})) { + my $message = $verbose_messages{$orig_type}; + $message =~ s/\n/\n\t/g; + print("\t" . $message . "\n\n"); + } } exit($exitcode); @@ -198,6 +239,46 @@ if (-f $conf) { unshift(@ARGV, @conf_args) if @conf_args; } +sub load_docs { + open(my $docs, '<', "$docsfile") + or warn "$P: Can't read the documentation file $docsfile $!\n"; + + my $type = ''; + my $desc = ''; + my $in_desc = 0; + + while (<$docs>) { + chomp; + my $line = $_; + $line =~ s/\s+$//; + + if ($line =~ /^\s*\*\*(.+)\*\*$/) { + if ($desc ne '') { + $verbose_messages{$type} = trim($desc); + } + $type = $1; + $desc = ''; + $in_desc = 1; + } elsif ($in_desc) { + if ($line =~ /^(?:\s{4,}|$)/) { + $line =~ s/^\s{4}//; + $desc .= $line; + $desc .= "\n"; + } else { + $verbose_messages{$type} = trim($desc); + $type = ''; + $desc = ''; + $in_desc = 0; + } + } + } + + if ($desc ne '') { + $verbose_messages{$type} = trim($desc); + } + close($docs); +} + # Perl's Getopt::Long allows options to take optional arguments after a space. # Prevent --color by itself from consuming other arguments foreach (@ARGV) { @@ -208,6 +289,7 @@ foreach (@ARGV) { GetOptions( 'q|quiet+' => \$quiet, + 'v|verbose!' => \$verbose, 'tree!' => \$tree, 'signoff!' => \$chk_signoff, 'patch!' => \$chk_patch, @@ -247,13 +329,27 @@ GetOptions( help(0) if ($help); +die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix)); +die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse); + +if ($color =~ /^[01]$/) { + $color = !$color; +} elsif ($color =~ /^always$/i) { + $color = 1; +} elsif ($color =~ /^never$/i) { + $color = 0; +} elsif ($color =~ /^auto$/i) { + $color = (-t STDOUT); +} else { + die "$P: Invalid color mode: $color\n"; +} + +load_docs() if ($verbose); list_types(0) if ($list_types); $fix = 1 if ($fix_inplace); $check_orig = $check; -die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix)); - my $exit = 0; my $perl_version_ok = 1; @@ -268,18 +364,6 @@ if ($#ARGV < 0) { push(@ARGV, '-'); } -if ($color =~ /^[01]$/) { - $color = !$color; -} elsif ($color =~ /^always$/i) { - $color = 1; -} elsif ($color =~ /^never$/i) { - $color = 0; -} elsif ($color =~ /^auto$/i) { - $color = (-t STDOUT); -} else { - die "$P: Invalid color mode: $color\n"; -} - # skip TAB size 1 to avoid additional checks on $tabsize - 1 die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2); @@ -2209,7 +2293,16 @@ sub report { splice(@lines, 1, 1); $output = join("\n", @lines); } - $output = (split('\n', $output))[0] . "\n" if ($terse); + + if ($terse) { + $output = (split('\n', $output))[0] . "\n"; + } + + if ($verbose && exists($verbose_messages{$type}) && + !exists($verbose_emitted{$type})) { + $output .= $verbose_messages{$type} . "\n\n"; + $verbose_emitted{$type} = 1; + } push(our @report, $output); diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl index 68dab828a722d1ef670f39fae398947b60701420..d5c58600cf1e3f66b1f3dba8cf4f6c0e5208a30c 100755 --- a/scripts/get_abi.pl +++ b/scripts/get_abi.pl @@ -281,8 +281,12 @@ sub create_labels { # Outputs the book on ReST format # -# \b doesn't work well with paths. So, we need to define something else -my $bondary = qr { (?<![\w\/\`\{])(?=[\w\/\`\{])|(?<=[\w\/\`\{])(?![\w\/\`\{]) }x; +# \b doesn't work well with paths. So, we need to define something else: +# Boundaries are punct characters, spaces and end-of-line +my $start = qr {(^|\s|\() }x; +my $bondary = qr { ([,.:;\)\s]|\z) }x; +my $xref_match = qr { $start(\/(sys|config|proc|dev|kvd)\/[^,.:;\)\s]+)$bondary }x; +my $symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x2f\x3a-\x40\x7b-\xff]) }x; sub output_rest { create_labels(); @@ -305,7 +309,6 @@ sub output_rest { } my $w = $what; - $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g; if ($type ne "File") { my $cur_part = $what; @@ -329,6 +332,7 @@ sub output_rest { my $len = 0; foreach my $name (@names) { + $name =~ s/$symbols/\\$1/g; $name = "**$name**"; $len = length($name) if (length($name) > $len); } @@ -377,32 +381,60 @@ sub output_rest { # Enrich text by creating cross-references - $desc =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g; + my $new_desc = ""; + my $init_indent = -1; + my $literal_indent = -1; + + open(my $fh, "+<", \$desc); + while (my $d = <$fh>) { + my $indent = $d =~ m/^(\s+)/; + my $spaces = length($indent); + $init_indent = $indent if ($init_indent < 0); + if ($literal_indent >= 0) { + if ($spaces > $literal_indent) { + $new_desc .= $d; + next; + } else { + $literal_indent = -1; + } + } else { + if ($d =~ /()::$/ && !($d =~ /^\s*\.\./)) { + $literal_indent = $spaces; + } + } - my @matches = $desc =~ m,Documentation/ABI/([\w\/\-]+),; - foreach my $f (@matches) { - my $xref = $f; - my $path = $f; - $path =~ s,.*/(.*/.*),$1,;; - $path =~ s,[/\-],_,g;; - $xref .= " <abi_file_" . $path . ">"; - $desc =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g; - } + $d =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g; - @matches = $desc =~ m,$bondary(/sys/[^\s\.\,\;\:\*\s\`\'\(\)]+)$bondary,; + my @matches = $d =~ m,Documentation/ABI/([\w\/\-]+),g; + foreach my $f (@matches) { + my $xref = $f; + my $path = $f; + $path =~ s,.*/(.*/.*),$1,;; + $path =~ s,[/\-],_,g;; + $xref .= " <abi_file_" . $path . ">"; + $d =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g; + } + + # Seek for cross reference symbols like /sys/... + @matches = $d =~ m/$xref_match/g; - foreach my $s (@matches) { - if (defined($data{$s}) && defined($data{$s}->{label})) { - my $xref = $s; + foreach my $s (@matches) { + next if (!($s =~ m,/,)); + if (defined($data{$s}) && defined($data{$s}->{label})) { + my $xref = $s; - $xref =~ s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g; - $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`"; + $xref =~ s/$symbols/\\$1/g; + $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`"; - $desc =~ s,$bondary$s$bondary,$xref,g; + $d =~ s,$start$s$bondary,$1$xref$2,g; + } } + $new_desc .= $d; } + close $fh; + - print "$desc\n\n"; + print "$new_desc\n\n"; } else { $desc =~ s/^\s+//; diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 8b5bc7bf4bb87cf2f997380242f00b3672cc3e57..2a85d34fdcd0a8d9da79166cb67f7a44b46815f0 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -391,8 +391,14 @@ my $doc_com = '\s*\*\s*'; my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; # @params and a strictly limited set of supported section names +# Specifically: +# Match @word: +# @...: +# @{section-name}: +# while trying to not match literal block starts like "example::" +# my $doc_sect = $doc_com . - '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:(.*)'; + '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$'; my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; my $doc_inline_start = '^\s*/\*\*\s*$'; @@ -1201,12 +1207,23 @@ sub dump_union($$) { sub dump_struct($$) { my $x = shift; my $file = shift; + my $decl_type; + my $members; + my $type = qr{struct|union}; + # For capturing struct/union definition body, i.e. "{members*}qualifiers*" + my $definition_body = qr{\{(.*)\}(?:\s*(?:__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*}; - if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) { - my $decl_type = $1; + if ($x =~ /($type)\s+(\w+)\s*$definition_body/) { + $decl_type = $1; $declaration_name = $2; - my $members = $3; + $members = $3; + } elsif ($x =~ /typedef\s+($type)\s*$definition_body\s*(\w+)\s*;/) { + $decl_type = $1; + $declaration_name = $3; + $members = $2; + } + if ($members) { if ($identifier ne $declaration_name) { print STDERR "${file}:$.: warning: expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"; return; @@ -1401,9 +1418,14 @@ sub dump_enum($$) { if ($members) { if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"; + if ($identifier eq "") { + print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n"; + } else { + print STDERR "${file}:$.: warning: expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"; + } return; } + $declaration_name = "(anonymous)" if ($declaration_name eq ""); my %_members; @@ -1755,12 +1777,14 @@ sub dump_function($$) { $prototype =~ s/^noinline +//; $prototype =~ s/__init +//; $prototype =~ s/__init_or_module +//; + $prototype =~ s/__flatten +//; $prototype =~ s/__meminit +//; $prototype =~ s/__must_check +//; $prototype =~ s/__weak +//; $prototype =~ s/__sched +//; $prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//; my $define = $prototype =~ s/^#\s*define\s+//; #ak added + $prototype =~ s/__attribute_const__ +//; $prototype =~ s/__attribute__\s*\(\( (?: [\w\s]++ # attribute name @@ -2085,15 +2109,28 @@ sub process_name($$) { } } elsif (/$doc_decl/o) { $identifier = $1; - if (/\s*([\w\s]+?)(\(\))?\s*([-:].*)?$/) { + my $is_kernel_comment = 0; + my $decl_start = qr{\s*\*}; + # test for pointer declaration type, foo * bar() - desc + my $fn_type = qr{\w+\s*\*\s*}; + my $parenthesis = qr{\(\w*\)}; + my $decl_end = qr{[-:].*}; + if (/^$decl_start\s*([\w\s]+?)$parenthesis?\s*$decl_end?$/) { $identifier = $1; } if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) { $decl_type = $1; $identifier = $2; - } else { + $is_kernel_comment = 1; + } + # Look for foo() or static void foo() - description; or misspelt + # identifier + elsif (/^$decl_start\s*$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ || + /^$decl_start\s*$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) { + $identifier = $1; $decl_type = 'function'; $identifier =~ s/^define\s+//; + $is_kernel_comment = 1; } $identifier =~ s/\s+$//; @@ -2115,13 +2152,20 @@ sub process_name($$) { $declaration_purpose = ""; } + if (!$is_kernel_comment) { + print STDERR "${file}:$.: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n"; + print STDERR $_; + ++$warnings; + $state = STATE_NORMAL; + } + if (($declaration_purpose eq "") && $verbose) { print STDERR "${file}:$.: warning: missing initial short description on line:\n"; print STDERR $_; ++$warnings; } - if ($identifier eq "") { + if ($identifier eq "" && $decl_type ne "enum") { print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n"; print STDERR $_; ++$warnings; diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 2c52535f9b566d8a6b3ed0406937e8b392764322..04c5685c25cf34dcfcc34dc995181846380eda66 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -3,10 +3,20 @@ * Archs are free to supply their own linker scripts. ld will * combine them automatically. */ +#ifdef CONFIG_CFI_CLANG +# include <asm/page.h> +# define ALIGN_CFI ALIGN(PAGE_SIZE) +# define SANITIZER_DISCARDS *(.eh_frame) +#else +# define ALIGN_CFI +# define SANITIZER_DISCARDS +#endif + SECTIONS { /DISCARD/ : { *(.discard) *(.discard.*) + SANITIZER_DISCARDS } __ksymtab 0 : { *(SORT(___ksymtab+*)) } @@ -41,7 +51,14 @@ SECTIONS { *(.rodata..L*) } - .text : { *(.text .text.[0-9a-zA-Z_]*) } + /* + * With CONFIG_CFI_CLANG, we assume __cfi_check is at the beginning + * of the .text section, and is aligned to PAGE_SIZE. + */ + .text : ALIGN_CFI { + *(.text.__cfi_check) + *(.text .text.[0-9a-zA-Z_]* .text..L.cfi*) + } #endif } diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py index cbdb5c83c08f9e45975af2a115d324473ea17935..3e784cf9f401fd480db03e03e7f43ee5d5d8e12b 100755 --- a/scripts/spdxcheck.py +++ b/scripts/spdxcheck.py @@ -243,7 +243,7 @@ if __name__ == '__main__': # Initialize SPDX data spdx = read_spdxdata(repo) - # Initilize the parser + # Initialize the parser parser = id_parser(spdx) except SPDXException as se: diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 6632da76fbb0ae71b193112bf5e7bc4141c137ee..d13cc84657aff4da2af184b6ed68003850f73e35 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -259,7 +259,7 @@ sub get_sphinx_version($) open IN, "$cmd --version 2>&1 |"; while (<IN>) { - if (m/^\s*sphinx-build\s+([\d\.]+)(\+\/[\da-f]+)?$/) { + if (m/^\s*sphinx-build\s+([\d\.]+)((\+\/[\da-f]+)|(b\d+))?$/) { $ver=$1; last; } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 240a53387e6b21bf7efc85632f052b54af2e3bb7..f72406fe1bf273e8f0cec947b969e44f776333e1 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1252,7 +1252,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(task_free, apparmor_task_free), LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), - LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid), + LSM_HOOK_INIT(task_getsecid_subj, apparmor_task_getsecid), + LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), LSM_HOOK_INIT(task_kill, apparmor_task_kill), diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index a662024b4c70bc7d10d9b4c8130d822deecf092c..23240d793b074e645047e56169ed7d85f93c12ec 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -84,6 +84,7 @@ int asymmetric_verify(struct key *keyring, const char *sig, { struct public_key_signature pks; struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig; + const struct public_key *pk; struct key *key; int ret; @@ -105,23 +106,20 @@ int asymmetric_verify(struct key *keyring, const char *sig, memset(&pks, 0, sizeof(pks)); pks.hash_algo = hash_algo_name[hdr->hash_algo]; - switch (hdr->hash_algo) { - case HASH_ALGO_STREEBOG_256: - case HASH_ALGO_STREEBOG_512: - /* EC-RDSA and Streebog should go together. */ - pks.pkey_algo = "ecrdsa"; - pks.encoding = "raw"; - break; - case HASH_ALGO_SM3_256: - /* SM2 and SM3 should go together. */ - pks.pkey_algo = "sm2"; - pks.encoding = "raw"; - break; - default: - pks.pkey_algo = "rsa"; + + pk = asymmetric_key_public_key(key); + pks.pkey_algo = pk->pkey_algo; + if (!strcmp(pk->pkey_algo, "rsa")) pks.encoding = "pkcs1"; - break; - } + else if (!strncmp(pk->pkey_algo, "ecdsa-", 6)) + /* edcsa-nist-p192 etc. */ + pks.encoding = "x962"; + else if (!strcmp(pk->pkey_algo, "ecrdsa") || + !strcmp(pk->pkey_algo, "sm2")) + pks.encoding = "raw"; + else + return -ENOPKG; + pks.digest = (u8 *)data; pks.digest_size = datalen; pks.s = hdr->sig; diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 565e33ff19d0dd6e8d228a233898089fe8054d27..4e5eb0236278aa5f6dab20fa4275bb36cd3b7d94 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -76,7 +76,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, if (!ima_appraise) return 0; - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); return ima_match_policy(mnt_userns, inode, current_cred(), secid, func, mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL); } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 9ef748ea829fe2063dc18ff0b1bee3f4f4b0ff89..b85d9e4294267b9523562861d9c4510aa054b4c3 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -391,7 +391,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) u32 secid; if (file && (prot & PROT_EXEC)) { - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); return process_measurement(file, current_cred(), secid, NULL, 0, MAY_EXEC, MMAP_CHECK); } @@ -429,7 +429,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) return 0; - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); inode = file_inode(vma->vm_file); action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode, current_cred(), secid, MAY_EXEC, MMAP_CHECK, @@ -470,7 +470,7 @@ int ima_bprm_check(struct linux_binprm *bprm) int ret; u32 secid; - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0, MAY_EXEC, BPRM_CHECK); if (ret) @@ -495,7 +495,7 @@ int ima_file_check(struct file *file, int mask) { u32 secid; - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); return process_measurement(file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); @@ -686,7 +686,7 @@ 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_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); return process_measurement(file, current_cred(), secid, NULL, 0, MAY_READ, func); } @@ -729,7 +729,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, } func = read_idmap[read_id] ?: FILE_CHECK; - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); return process_measurement(file, current_cred(), secid, buf, size, MAY_READ, func); } @@ -872,7 +872,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns, * buffer measurements. */ if (func) { - security_task_getsecid(current, &secid); + security_task_getsecid_subj(current, &secid); action = ima_get_action(mnt_userns, inode, current_cred(), secid, 0, func, &pcr, &template, func_data); diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c index c5ba695c10e3a5afd1633fc5bd765c0f1bf7a303..5604bd57c99077d8238cde7b5e6335a13cf16dce 100644 --- a/security/integrity/platform_certs/keyring_handler.c +++ b/security/integrity/platform_certs/keyring_handler.c @@ -55,6 +55,15 @@ static __init void uefi_blacklist_binary(const char *source, uefi_blacklist_hash(source, data, len, "bin:", 4); } +/* + * Add an X509 cert to the revocation list. + */ +static __init void uefi_revocation_list_x509(const char *source, + const void *data, size_t len) +{ + add_key_to_revocation_list(data, len); +} + /* * Return the appropriate handler for particular signature list types found in * the UEFI db and MokListRT tables. @@ -76,5 +85,7 @@ __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type) return uefi_blacklist_x509_tbs; if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0) return uefi_blacklist_binary; + if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) + return uefi_revocation_list_x509; return 0; } diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c index ee4b4c666854f6b40f5664acf20a10bc641c7448..f290f78c3f3012976a15d507cd26f195230a7fd0 100644 --- a/security/integrity/platform_certs/load_uefi.c +++ b/security/integrity/platform_certs/load_uefi.c @@ -132,8 +132,9 @@ static int __init load_moklist_certs(void) static int __init load_uefi_certs(void) { efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID; - void *db = NULL, *dbx = NULL; - unsigned long dbsize = 0, dbxsize = 0; + efi_guid_t mok_var = EFI_SHIM_LOCK_GUID; + void *db = NULL, *dbx = NULL, *mokx = NULL; + unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0; efi_status_t status; int rc = 0; @@ -175,6 +176,21 @@ static int __init load_uefi_certs(void) kfree(dbx); } + mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &status); + if (!mokx) { + if (status == EFI_NOT_FOUND) + pr_debug("mokx variable wasn't found\n"); + else + pr_info("Couldn't get mokx list\n"); + } else { + rc = parse_efi_signature_list("UEFI:MokListXRT", + mokx, mokxsize, + get_handler_for_dbx); + if (rc) + pr_err("Couldn't parse mokx signatures %d\n", rc); + kfree(mokx); + } + /* Load the MokListRT certs */ rc = load_moklist_certs(); diff --git a/security/keys/Kconfig b/security/keys/Kconfig index c161642a8484172a9dfb7a2fa9500da523fecfb3..64b81abd087e3d531bd18a82002777caf4d3494b 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -75,6 +75,9 @@ config TRUSTED_KEYS select CRYPTO_HMAC select CRYPTO_SHA1 select CRYPTO_HASH_INFO + select ASN1_ENCODER + select OID_REGISTRY + select ASN1 help This option provides support for creating, sealing, and unsealing keys in the kernel. Trusted keys are random number symmetric keys, diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile index 7b73cebbb378a2f2eadffa083ec9d28b44295ee2..feb8b6c3cc79cb6c2235ff90523b1bf5303d09c1 100644 --- a/security/keys/trusted-keys/Makefile +++ b/security/keys/trusted-keys/Makefile @@ -4,5 +4,11 @@ # obj-$(CONFIG_TRUSTED_KEYS) += trusted.o +trusted-y += trusted_core.o trusted-y += trusted_tpm1.o + +$(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h trusted-y += trusted_tpm2.o +trusted-y += tpm2key.asn1.o + +trusted-$(CONFIG_TEE) += trusted_tee.o diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1 new file mode 100644 index 0000000000000000000000000000000000000000..f57f869ad600687e802e91e6a68e50ddc7c334d6 --- /dev/null +++ b/security/keys/trusted-keys/tpm2key.asn1 @@ -0,0 +1,11 @@ +--- +--- ASN.1 for TPM 2.0 keys +--- + +TPMKey ::= SEQUENCE { + type OBJECT IDENTIFIER ({tpm2_key_type}), + emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL, + parent INTEGER ({tpm2_key_parent}), + pubkey OCTET STRING ({tpm2_key_pub}), + privkey OCTET STRING ({tpm2_key_priv}) + } diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c new file mode 100644 index 0000000000000000000000000000000000000000..d5c891d8d353480f26efe2dce630260ae9e9a6f5 --- /dev/null +++ b/security/keys/trusted-keys/trusted_core.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2010 IBM Corporation + * Copyright (c) 2019-2021, Linaro Limited + * + * See Documentation/security/keys/trusted-encrypted.rst + */ + +#include <keys/user-type.h> +#include <keys/trusted-type.h> +#include <keys/trusted_tee.h> +#include <keys/trusted_tpm.h> +#include <linux/capability.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/key-type.h> +#include <linux/module.h> +#include <linux/parser.h> +#include <linux/rcupdate.h> +#include <linux/slab.h> +#include <linux/static_call.h> +#include <linux/string.h> +#include <linux/uaccess.h> + +static char *trusted_key_source; +module_param_named(source, trusted_key_source, charp, 0); +MODULE_PARM_DESC(source, "Select trusted keys source (tpm or tee)"); + +static const struct trusted_key_source trusted_key_sources[] = { +#if defined(CONFIG_TCG_TPM) + { "tpm", &trusted_key_tpm_ops }, +#endif +#if defined(CONFIG_TEE) + { "tee", &trusted_key_tee_ops }, +#endif +}; + +DEFINE_STATIC_CALL_NULL(trusted_key_init, *trusted_key_sources[0].ops->init); +DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal); +DEFINE_STATIC_CALL_NULL(trusted_key_unseal, + *trusted_key_sources[0].ops->unseal); +DEFINE_STATIC_CALL_NULL(trusted_key_get_random, + *trusted_key_sources[0].ops->get_random); +DEFINE_STATIC_CALL_NULL(trusted_key_exit, *trusted_key_sources[0].ops->exit); +static unsigned char migratable; + +enum { + Opt_err, + Opt_new, Opt_load, Opt_update, +}; + +static const match_table_t key_tokens = { + {Opt_new, "new"}, + {Opt_load, "load"}, + {Opt_update, "update"}, + {Opt_err, NULL} +}; + +/* + * datablob_parse - parse the keyctl data and fill in the + * payload structure + * + * On success returns 0, otherwise -EINVAL. + */ +static int datablob_parse(char **datablob, struct trusted_key_payload *p) +{ + substring_t args[MAX_OPT_ARGS]; + long keylen; + int ret = -EINVAL; + int key_cmd; + char *c; + + /* main command */ + c = strsep(datablob, " \t"); + if (!c) + return -EINVAL; + key_cmd = match_token(c, key_tokens, args); + switch (key_cmd) { + case Opt_new: + /* first argument is key size */ + c = strsep(datablob, " \t"); + if (!c) + return -EINVAL; + ret = kstrtol(c, 10, &keylen); + if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) + return -EINVAL; + p->key_len = keylen; + ret = Opt_new; + break; + case Opt_load: + /* first argument is sealed blob */ + c = strsep(datablob, " \t"); + if (!c) + return -EINVAL; + p->blob_len = strlen(c) / 2; + if (p->blob_len > MAX_BLOB_SIZE) + return -EINVAL; + ret = hex2bin(p->blob, c, p->blob_len); + if (ret < 0) + return -EINVAL; + ret = Opt_load; + break; + case Opt_update: + ret = Opt_update; + break; + case Opt_err: + return -EINVAL; + } + return ret; +} + +static struct trusted_key_payload *trusted_payload_alloc(struct key *key) +{ + struct trusted_key_payload *p = NULL; + int ret; + + ret = key_payload_reserve(key, sizeof(*p)); + if (ret < 0) + goto err; + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto err; + + p->migratable = migratable; +err: + return p; +} + +/* + * trusted_instantiate - create a new trusted key + * + * Unseal an existing trusted blob or, for a new key, get a + * random key, then seal and create a trusted key-type key, + * adding it to the specified keyring. + * + * On success, return 0. Otherwise return errno. + */ +static int trusted_instantiate(struct key *key, + struct key_preparsed_payload *prep) +{ + struct trusted_key_payload *payload = NULL; + size_t datalen = prep->datalen; + char *datablob, *orig_datablob; + int ret = 0; + int key_cmd; + size_t key_len; + + if (datalen <= 0 || datalen > 32767 || !prep->data) + return -EINVAL; + + orig_datablob = datablob = kmalloc(datalen + 1, GFP_KERNEL); + if (!datablob) + return -ENOMEM; + memcpy(datablob, prep->data, datalen); + datablob[datalen] = '\0'; + + payload = trusted_payload_alloc(key); + if (!payload) { + ret = -ENOMEM; + goto out; + } + + key_cmd = datablob_parse(&datablob, payload); + if (key_cmd < 0) { + ret = key_cmd; + goto out; + } + + dump_payload(payload); + + switch (key_cmd) { + case Opt_load: + ret = static_call(trusted_key_unseal)(payload, datablob); + dump_payload(payload); + if (ret < 0) + pr_info("key_unseal failed (%d)\n", ret); + break; + case Opt_new: + key_len = payload->key_len; + ret = static_call(trusted_key_get_random)(payload->key, + key_len); + if (ret < 0) + goto out; + + if (ret != key_len) { + pr_info("key_create failed (%d)\n", ret); + ret = -EIO; + goto out; + } + + ret = static_call(trusted_key_seal)(payload, datablob); + if (ret < 0) + pr_info("key_seal failed (%d)\n", ret); + break; + default: + ret = -EINVAL; + } +out: + kfree_sensitive(orig_datablob); + if (!ret) + rcu_assign_keypointer(key, payload); + else + kfree_sensitive(payload); + return ret; +} + +static void trusted_rcu_free(struct rcu_head *rcu) +{ + struct trusted_key_payload *p; + + p = container_of(rcu, struct trusted_key_payload, rcu); + kfree_sensitive(p); +} + +/* + * trusted_update - reseal an existing key with new PCR values + */ +static int trusted_update(struct key *key, struct key_preparsed_payload *prep) +{ + struct trusted_key_payload *p; + struct trusted_key_payload *new_p; + size_t datalen = prep->datalen; + char *datablob, *orig_datablob; + int ret = 0; + + if (key_is_negative(key)) + return -ENOKEY; + p = key->payload.data[0]; + if (!p->migratable) + return -EPERM; + if (datalen <= 0 || datalen > 32767 || !prep->data) + return -EINVAL; + + orig_datablob = datablob = kmalloc(datalen + 1, GFP_KERNEL); + if (!datablob) + return -ENOMEM; + + new_p = trusted_payload_alloc(key); + if (!new_p) { + ret = -ENOMEM; + goto out; + } + + memcpy(datablob, prep->data, datalen); + datablob[datalen] = '\0'; + ret = datablob_parse(&datablob, new_p); + if (ret != Opt_update) { + ret = -EINVAL; + kfree_sensitive(new_p); + goto out; + } + + /* copy old key values, and reseal with new pcrs */ + new_p->migratable = p->migratable; + new_p->key_len = p->key_len; + memcpy(new_p->key, p->key, p->key_len); + dump_payload(p); + dump_payload(new_p); + + ret = static_call(trusted_key_seal)(new_p, datablob); + if (ret < 0) { + pr_info("key_seal failed (%d)\n", ret); + kfree_sensitive(new_p); + goto out; + } + + rcu_assign_keypointer(key, new_p); + call_rcu(&p->rcu, trusted_rcu_free); +out: + kfree_sensitive(orig_datablob); + return ret; +} + +/* + * trusted_read - copy the sealed blob data to userspace in hex. + * On success, return to userspace the trusted key datablob size. + */ +static long trusted_read(const struct key *key, char *buffer, + size_t buflen) +{ + const struct trusted_key_payload *p; + char *bufp; + int i; + + p = dereference_key_locked(key); + if (!p) + return -EINVAL; + + if (buffer && buflen >= 2 * p->blob_len) { + bufp = buffer; + for (i = 0; i < p->blob_len; i++) + bufp = hex_byte_pack(bufp, p->blob[i]); + } + return 2 * p->blob_len; +} + +/* + * trusted_destroy - clear and free the key's payload + */ +static void trusted_destroy(struct key *key) +{ + kfree_sensitive(key->payload.data[0]); +} + +struct key_type key_type_trusted = { + .name = "trusted", + .instantiate = trusted_instantiate, + .update = trusted_update, + .destroy = trusted_destroy, + .describe = user_describe, + .read = trusted_read, +}; +EXPORT_SYMBOL_GPL(key_type_trusted); + +static int __init init_trusted(void) +{ + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(trusted_key_sources); i++) { + if (trusted_key_source && + strncmp(trusted_key_source, trusted_key_sources[i].name, + strlen(trusted_key_sources[i].name))) + continue; + + static_call_update(trusted_key_init, + trusted_key_sources[i].ops->init); + static_call_update(trusted_key_seal, + trusted_key_sources[i].ops->seal); + static_call_update(trusted_key_unseal, + trusted_key_sources[i].ops->unseal); + static_call_update(trusted_key_get_random, + trusted_key_sources[i].ops->get_random); + static_call_update(trusted_key_exit, + trusted_key_sources[i].ops->exit); + migratable = trusted_key_sources[i].ops->migratable; + + ret = static_call(trusted_key_init)(); + if (!ret) + break; + } + + /* + * encrypted_keys.ko depends on successful load of this module even if + * trusted key implementation is not found. + */ + if (ret == -ENODEV) + return 0; + + return ret; +} + +static void __exit cleanup_trusted(void) +{ + static_call(trusted_key_exit)(); +} + +late_initcall(init_trusted); +module_exit(cleanup_trusted); + +MODULE_LICENSE("GPL"); diff --git a/security/keys/trusted-keys/trusted_tee.c b/security/keys/trusted-keys/trusted_tee.c new file mode 100644 index 0000000000000000000000000000000000000000..2ce66c199e1d773b3e6518132926ceb86bae937c --- /dev/null +++ b/security/keys/trusted-keys/trusted_tee.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2021 Linaro Ltd. + * + * Author: + * Sumit Garg <sumit.garg@linaro.org> + */ + +#include <linux/err.h> +#include <linux/key-type.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/tee_drv.h> +#include <linux/uuid.h> + +#include <keys/trusted_tee.h> + +#define DRIVER_NAME "trusted-key-tee" + +/* + * Get random data for symmetric key + * + * [out] memref[0] Random data + */ +#define TA_CMD_GET_RANDOM 0x0 + +/* + * Seal trusted key using hardware unique key + * + * [in] memref[0] Plain key + * [out] memref[1] Sealed key datablob + */ +#define TA_CMD_SEAL 0x1 + +/* + * Unseal trusted key using hardware unique key + * + * [in] memref[0] Sealed key datablob + * [out] memref[1] Plain key + */ +#define TA_CMD_UNSEAL 0x2 + +/** + * struct trusted_key_tee_private - TEE Trusted key private data + * @dev: TEE based Trusted key device. + * @ctx: TEE context handler. + * @session_id: Trusted key TA session identifier. + * @shm_pool: Memory pool shared with TEE device. + */ +struct trusted_key_tee_private { + struct device *dev; + struct tee_context *ctx; + u32 session_id; + struct tee_shm *shm_pool; +}; + +static struct trusted_key_tee_private pvt_data; + +/* + * Have the TEE seal(encrypt) the symmetric key + */ +static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob) +{ + int ret; + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL; + + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + reg_shm_in = tee_shm_register(pvt_data.ctx, (unsigned long)p->key, + p->key_len, TEE_SHM_DMA_BUF | + TEE_SHM_KERNEL_MAPPED); + if (IS_ERR(reg_shm_in)) { + dev_err(pvt_data.dev, "key shm register failed\n"); + return PTR_ERR(reg_shm_in); + } + + reg_shm_out = tee_shm_register(pvt_data.ctx, (unsigned long)p->blob, + sizeof(p->blob), TEE_SHM_DMA_BUF | + TEE_SHM_KERNEL_MAPPED); + if (IS_ERR(reg_shm_out)) { + dev_err(pvt_data.dev, "blob shm register failed\n"); + ret = PTR_ERR(reg_shm_out); + goto out; + } + + inv_arg.func = TA_CMD_SEAL; + inv_arg.session = pvt_data.session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[0].u.memref.shm = reg_shm_in; + param[0].u.memref.size = p->key_len; + param[0].u.memref.shm_offs = 0; + param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param[1].u.memref.shm = reg_shm_out; + param[1].u.memref.size = sizeof(p->blob); + param[1].u.memref.shm_offs = 0; + + ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(pvt_data.dev, "TA_CMD_SEAL invoke err: %x\n", + inv_arg.ret); + ret = -EFAULT; + } else { + p->blob_len = param[1].u.memref.size; + } + +out: + if (reg_shm_out) + tee_shm_free(reg_shm_out); + if (reg_shm_in) + tee_shm_free(reg_shm_in); + + return ret; +} + +/* + * Have the TEE unseal(decrypt) the symmetric key + */ +static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob) +{ + int ret; + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL; + + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + reg_shm_in = tee_shm_register(pvt_data.ctx, (unsigned long)p->blob, + p->blob_len, TEE_SHM_DMA_BUF | + TEE_SHM_KERNEL_MAPPED); + if (IS_ERR(reg_shm_in)) { + dev_err(pvt_data.dev, "blob shm register failed\n"); + return PTR_ERR(reg_shm_in); + } + + reg_shm_out = tee_shm_register(pvt_data.ctx, (unsigned long)p->key, + sizeof(p->key), TEE_SHM_DMA_BUF | + TEE_SHM_KERNEL_MAPPED); + if (IS_ERR(reg_shm_out)) { + dev_err(pvt_data.dev, "key shm register failed\n"); + ret = PTR_ERR(reg_shm_out); + goto out; + } + + inv_arg.func = TA_CMD_UNSEAL; + inv_arg.session = pvt_data.session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[0].u.memref.shm = reg_shm_in; + param[0].u.memref.size = p->blob_len; + param[0].u.memref.shm_offs = 0; + param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param[1].u.memref.shm = reg_shm_out; + param[1].u.memref.size = sizeof(p->key); + param[1].u.memref.shm_offs = 0; + + ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(pvt_data.dev, "TA_CMD_UNSEAL invoke err: %x\n", + inv_arg.ret); + ret = -EFAULT; + } else { + p->key_len = param[1].u.memref.size; + } + +out: + if (reg_shm_out) + tee_shm_free(reg_shm_out); + if (reg_shm_in) + tee_shm_free(reg_shm_in); + + return ret; +} + +/* + * Have the TEE generate random symmetric key + */ +static int trusted_tee_get_random(unsigned char *key, size_t key_len) +{ + int ret; + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + struct tee_shm *reg_shm = NULL; + + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + reg_shm = tee_shm_register(pvt_data.ctx, (unsigned long)key, key_len, + TEE_SHM_DMA_BUF | TEE_SHM_KERNEL_MAPPED); + if (IS_ERR(reg_shm)) { + dev_err(pvt_data.dev, "key shm register failed\n"); + return PTR_ERR(reg_shm); + } + + inv_arg.func = TA_CMD_GET_RANDOM; + inv_arg.session = pvt_data.session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param[0].u.memref.shm = reg_shm; + param[0].u.memref.size = key_len; + param[0].u.memref.shm_offs = 0; + + ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(pvt_data.dev, "TA_CMD_GET_RANDOM invoke err: %x\n", + inv_arg.ret); + ret = -EFAULT; + } else { + ret = param[0].u.memref.size; + } + + tee_shm_free(reg_shm); + + return ret; +} + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + if (ver->impl_id == TEE_IMPL_ID_OPTEE) + return 1; + else + return 0; +} + +static int trusted_key_probe(struct device *dev) +{ + struct tee_client_device *rng_device = to_tee_client_device(dev); + int ret; + struct tee_ioctl_open_session_arg sess_arg; + + memset(&sess_arg, 0, sizeof(sess_arg)); + + pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, + NULL); + if (IS_ERR(pvt_data.ctx)) + return -ENODEV; + + memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN); + sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; + sess_arg.num_params = 0; + + ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); + if ((ret < 0) || (sess_arg.ret != 0)) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", + sess_arg.ret); + ret = -EINVAL; + goto out_ctx; + } + pvt_data.session_id = sess_arg.session; + + ret = register_key_type(&key_type_trusted); + if (ret < 0) + goto out_sess; + + pvt_data.dev = dev; + + return 0; + +out_sess: + tee_client_close_session(pvt_data.ctx, pvt_data.session_id); +out_ctx: + tee_client_close_context(pvt_data.ctx); + + return ret; +} + +static int trusted_key_remove(struct device *dev) +{ + unregister_key_type(&key_type_trusted); + tee_client_close_session(pvt_data.ctx, pvt_data.session_id); + tee_client_close_context(pvt_data.ctx); + + return 0; +} + +static const struct tee_client_device_id trusted_key_id_table[] = { + {UUID_INIT(0xf04a0fe7, 0x1f5d, 0x4b9b, + 0xab, 0xf7, 0x61, 0x9b, 0x85, 0xb4, 0xce, 0x8c)}, + {} +}; +MODULE_DEVICE_TABLE(tee, trusted_key_id_table); + +static struct tee_client_driver trusted_key_driver = { + .id_table = trusted_key_id_table, + .driver = { + .name = DRIVER_NAME, + .bus = &tee_bus_type, + .probe = trusted_key_probe, + .remove = trusted_key_remove, + }, +}; + +static int trusted_tee_init(void) +{ + return driver_register(&trusted_key_driver.driver); +} + +static void trusted_tee_exit(void) +{ + driver_unregister(&trusted_key_driver.driver); +} + +struct trusted_key_ops trusted_key_tee_ops = { + .migratable = 0, /* non-migratable */ + .init = trusted_tee_init, + .seal = trusted_tee_seal, + .unseal = trusted_tee_unseal, + .get_random = trusted_tee_get_random, + .exit = trusted_tee_exit, +}; diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c index 493eb91ed017ff9da39c9fdd47e2a9014ee078c7..4693945508019c277b6a9cf2628b7bdeff25581f 100644 --- a/security/keys/trusted-keys/trusted_tpm1.c +++ b/security/keys/trusted-keys/trusted_tpm1.c @@ -1,29 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 IBM Corporation - * - * Author: - * David Safford <safford@us.ibm.com> + * Copyright (c) 2019-2021, Linaro Limited * * See Documentation/security/keys/trusted-encrypted.rst */ #include <crypto/hash_info.h> -#include <linux/uaccess.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/parser.h> #include <linux/string.h> #include <linux/err.h> -#include <keys/user-type.h> #include <keys/trusted-type.h> #include <linux/key-type.h> -#include <linux/rcupdate.h> #include <linux/crypto.h> #include <crypto/hash.h> #include <crypto/sha1.h> -#include <linux/capability.h> #include <linux/tpm.h> #include <linux/tpm_command.h> @@ -63,7 +56,7 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen, sdesc = init_sdesc(hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("can't alloc %s\n", hash_alg); return PTR_ERR(sdesc); } @@ -83,7 +76,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, sdesc = init_sdesc(hmacalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hmac_alg); + pr_info("can't alloc %s\n", hmac_alg); return PTR_ERR(sdesc); } @@ -136,7 +129,7 @@ int TSS_authhmac(unsigned char *digest, const unsigned char *key, sdesc = init_sdesc(hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("can't alloc %s\n", hash_alg); return PTR_ERR(sdesc); } @@ -212,7 +205,7 @@ int TSS_checkhmac1(unsigned char *buffer, sdesc = init_sdesc(hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("can't alloc %s\n", hash_alg); return PTR_ERR(sdesc); } ret = crypto_shash_init(&sdesc->shash); @@ -305,7 +298,7 @@ static int TSS_checkhmac2(unsigned char *buffer, sdesc = init_sdesc(hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("can't alloc %s\n", hash_alg); return PTR_ERR(sdesc); } ret = crypto_shash_init(&sdesc->shash); @@ -597,12 +590,12 @@ static int tpm_unseal(struct tpm_buf *tb, /* sessions for unsealing key and data */ ret = oiap(tb, &authhandle1, enonce1); if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); + pr_info("oiap failed (%d)\n", ret); return ret; } ret = oiap(tb, &authhandle2, enonce2); if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); + pr_info("oiap failed (%d)\n", ret); return ret; } @@ -612,7 +605,7 @@ static int tpm_unseal(struct tpm_buf *tb, return ret; if (ret != TPM_NONCE_SIZE) { - pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); + pr_info("tpm_get_random failed (%d)\n", ret); return -EIO; } ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, @@ -641,7 +634,7 @@ static int tpm_unseal(struct tpm_buf *tb, ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); if (ret < 0) { - pr_info("trusted_key: authhmac failed (%d)\n", ret); + pr_info("authhmac failed (%d)\n", ret); return ret; } @@ -653,7 +646,7 @@ static int tpm_unseal(struct tpm_buf *tb, *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, 0); if (ret < 0) { - pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret); + pr_info("TSS_checkhmac2 failed (%d)\n", ret); return ret; } memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); @@ -680,7 +673,7 @@ static int key_seal(struct trusted_key_payload *p, p->key, p->key_len + 1, p->blob, &p->blob_len, o->blobauth, o->pcrinfo, o->pcrinfo_len); if (ret < 0) - pr_info("trusted_key: srkseal failed (%d)\n", ret); + pr_info("srkseal failed (%d)\n", ret); tpm_buf_destroy(&tb); return ret; @@ -702,7 +695,7 @@ static int key_unseal(struct trusted_key_payload *p, ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len, o->blobauth, p->key, &p->key_len); if (ret < 0) - pr_info("trusted_key: srkunseal failed (%d)\n", ret); + pr_info("srkunseal failed (%d)\n", ret); else /* pull migratable flag out of sealed key */ p->migratable = p->key[--p->key_len]; @@ -713,7 +706,6 @@ static int key_unseal(struct trusted_key_payload *p, enum { Opt_err, - Opt_new, Opt_load, Opt_update, Opt_keyhandle, Opt_keyauth, Opt_blobauth, Opt_pcrinfo, Opt_pcrlock, Opt_migratable, Opt_hash, @@ -722,9 +714,6 @@ enum { }; static const match_table_t key_tokens = { - {Opt_new, "new"}, - {Opt_load, "load"}, - {Opt_update, "update"}, {Opt_keyhandle, "keyhandle=%s"}, {Opt_keyauth, "keyauth=%s"}, {Opt_blobauth, "blobauth=%s"}, @@ -758,6 +747,9 @@ static int getoptions(char *c, struct trusted_key_payload *pay, opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1; + if (!c) + return 0; + while ((p = strsep(&c, " \t"))) { if (*p == '\0' || *p == ' ' || *p == '\t') continue; @@ -791,13 +783,33 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; break; case Opt_blobauth: - if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) - return -EINVAL; - res = hex2bin(opt->blobauth, args[0].from, - SHA1_DIGEST_SIZE); - if (res < 0) - return -EINVAL; + /* + * TPM 1.2 authorizations are sha1 hashes passed in as + * hex strings. TPM 2.0 authorizations are simple + * passwords (although it can take a hash as well) + */ + opt->blobauth_len = strlen(args[0].from); + + if (opt->blobauth_len == 2 * TPM_DIGEST_SIZE) { + res = hex2bin(opt->blobauth, args[0].from, + TPM_DIGEST_SIZE); + if (res < 0) + return -EINVAL; + + opt->blobauth_len = TPM_DIGEST_SIZE; + break; + } + + if (tpm2 && opt->blobauth_len <= sizeof(opt->blobauth)) { + memcpy(opt->blobauth, args[0].from, + opt->blobauth_len); + break; + } + + return -EINVAL; + break; + case Opt_migratable: if (*args[0].from == '0') pay->migratable = 0; @@ -822,7 +834,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, if (i == HASH_ALGO__LAST) return -EINVAL; if (!tpm2 && i != HASH_ALGO_SHA1) { - pr_info("trusted_key: TPM 1.x only supports SHA-1.\n"); + pr_info("TPM 1.x only supports SHA-1.\n"); return -EINVAL; } break; @@ -851,71 +863,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return 0; } -/* - * datablob_parse - parse the keyctl data and fill in the - * payload and options structures - * - * On success returns 0, otherwise -EINVAL. - */ -static int datablob_parse(char *datablob, struct trusted_key_payload *p, - struct trusted_key_options *o) -{ - substring_t args[MAX_OPT_ARGS]; - long keylen; - int ret = -EINVAL; - int key_cmd; - char *c; - - /* main command */ - c = strsep(&datablob, " \t"); - if (!c) - return -EINVAL; - key_cmd = match_token(c, key_tokens, args); - switch (key_cmd) { - case Opt_new: - /* first argument is key size */ - c = strsep(&datablob, " \t"); - if (!c) - return -EINVAL; - ret = kstrtol(c, 10, &keylen); - if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) - return -EINVAL; - p->key_len = keylen; - ret = getoptions(datablob, p, o); - if (ret < 0) - return ret; - ret = Opt_new; - break; - case Opt_load: - /* first argument is sealed blob */ - c = strsep(&datablob, " \t"); - if (!c) - return -EINVAL; - p->blob_len = strlen(c) / 2; - if (p->blob_len > MAX_BLOB_SIZE) - return -EINVAL; - ret = hex2bin(p->blob, c, p->blob_len); - if (ret < 0) - return -EINVAL; - ret = getoptions(datablob, p, o); - if (ret < 0) - return ret; - ret = Opt_load; - break; - case Opt_update: - /* all arguments are options */ - ret = getoptions(datablob, p, o); - if (ret < 0) - return ret; - ret = Opt_update; - break; - case Opt_err: - return -EINVAL; - break; - } - return ret; -} - static struct trusted_key_options *trusted_options_alloc(void) { struct trusted_key_options *options; @@ -936,252 +883,99 @@ static struct trusted_key_options *trusted_options_alloc(void) return options; } -static struct trusted_key_payload *trusted_payload_alloc(struct key *key) +static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob) { - struct trusted_key_payload *p = NULL; - int ret; - - ret = key_payload_reserve(key, sizeof *p); - if (ret < 0) - return p; - p = kzalloc(sizeof *p, GFP_KERNEL); - if (p) - p->migratable = 1; /* migratable by default */ - return p; -} - -/* - * trusted_instantiate - create a new trusted key - * - * Unseal an existing trusted blob or, for a new key, get a - * random key, then seal and create a trusted key-type key, - * adding it to the specified keyring. - * - * On success, return 0. Otherwise return errno. - */ -static int trusted_instantiate(struct key *key, - struct key_preparsed_payload *prep) -{ - struct trusted_key_payload *payload = NULL; struct trusted_key_options *options = NULL; - size_t datalen = prep->datalen; - char *datablob; int ret = 0; - int key_cmd; - size_t key_len; int tpm2; tpm2 = tpm_is_tpm2(chip); if (tpm2 < 0) return tpm2; - if (datalen <= 0 || datalen > 32767 || !prep->data) - return -EINVAL; - - datablob = kmalloc(datalen + 1, GFP_KERNEL); - if (!datablob) + options = trusted_options_alloc(); + if (!options) return -ENOMEM; - memcpy(datablob, prep->data, datalen); - datablob[datalen] = '\0'; - options = trusted_options_alloc(); - if (!options) { - ret = -ENOMEM; - goto out; - } - payload = trusted_payload_alloc(key); - if (!payload) { - ret = -ENOMEM; + ret = getoptions(datablob, p, options); + if (ret < 0) goto out; - } + dump_options(options); - key_cmd = datablob_parse(datablob, payload, options); - if (key_cmd < 0) { - ret = key_cmd; + if (!options->keyhandle && !tpm2) { + ret = -EINVAL; goto out; } - if (!options->keyhandle) { - ret = -EINVAL; + if (tpm2) + ret = tpm2_seal_trusted(chip, p, options); + else + ret = key_seal(p, options); + if (ret < 0) { + pr_info("key_seal failed (%d)\n", ret); goto out; } - dump_payload(payload); - dump_options(options); - - switch (key_cmd) { - case Opt_load: - if (tpm2) - ret = tpm2_unseal_trusted(chip, payload, options); - else - ret = key_unseal(payload, options); - dump_payload(payload); - dump_options(options); - if (ret < 0) - pr_info("trusted_key: key_unseal failed (%d)\n", ret); - break; - case Opt_new: - key_len = payload->key_len; - ret = tpm_get_random(chip, payload->key, key_len); - if (ret < 0) - goto out; - - if (ret != key_len) { - pr_info("trusted_key: key_create failed (%d)\n", ret); - ret = -EIO; + if (options->pcrlock) { + ret = pcrlock(options->pcrlock); + if (ret < 0) { + pr_info("pcrlock failed (%d)\n", ret); goto out; } - if (tpm2) - ret = tpm2_seal_trusted(chip, payload, options); - else - ret = key_seal(payload, options); - if (ret < 0) - pr_info("trusted_key: key_seal failed (%d)\n", ret); - break; - default: - ret = -EINVAL; - goto out; } - if (!ret && options->pcrlock) - ret = pcrlock(options->pcrlock); out: - kfree_sensitive(datablob); kfree_sensitive(options); - if (!ret) - rcu_assign_keypointer(key, payload); - else - kfree_sensitive(payload); return ret; } -static void trusted_rcu_free(struct rcu_head *rcu) +static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob) { - struct trusted_key_payload *p; - - p = container_of(rcu, struct trusted_key_payload, rcu); - kfree_sensitive(p); -} - -/* - * trusted_update - reseal an existing key with new PCR values - */ -static int trusted_update(struct key *key, struct key_preparsed_payload *prep) -{ - struct trusted_key_payload *p; - struct trusted_key_payload *new_p; - struct trusted_key_options *new_o; - size_t datalen = prep->datalen; - char *datablob; + struct trusted_key_options *options = NULL; int ret = 0; + int tpm2; - if (key_is_negative(key)) - return -ENOKEY; - p = key->payload.data[0]; - if (!p->migratable) - return -EPERM; - if (datalen <= 0 || datalen > 32767 || !prep->data) - return -EINVAL; + tpm2 = tpm_is_tpm2(chip); + if (tpm2 < 0) + return tpm2; - datablob = kmalloc(datalen + 1, GFP_KERNEL); - if (!datablob) + options = trusted_options_alloc(); + if (!options) return -ENOMEM; - new_o = trusted_options_alloc(); - if (!new_o) { - ret = -ENOMEM; - goto out; - } - new_p = trusted_payload_alloc(key); - if (!new_p) { - ret = -ENOMEM; - goto out; - } - memcpy(datablob, prep->data, datalen); - datablob[datalen] = '\0'; - ret = datablob_parse(datablob, new_p, new_o); - if (ret != Opt_update) { - ret = -EINVAL; - kfree_sensitive(new_p); + ret = getoptions(datablob, p, options); + if (ret < 0) goto out; - } + dump_options(options); - if (!new_o->keyhandle) { + if (!options->keyhandle && !tpm2) { ret = -EINVAL; - kfree_sensitive(new_p); goto out; } - /* copy old key values, and reseal with new pcrs */ - new_p->migratable = p->migratable; - new_p->key_len = p->key_len; - memcpy(new_p->key, p->key, p->key_len); - dump_payload(p); - dump_payload(new_p); + if (tpm2) + ret = tpm2_unseal_trusted(chip, p, options); + else + ret = key_unseal(p, options); + if (ret < 0) + pr_info("key_unseal failed (%d)\n", ret); - ret = key_seal(new_p, new_o); - if (ret < 0) { - pr_info("trusted_key: key_seal failed (%d)\n", ret); - kfree_sensitive(new_p); - goto out; - } - if (new_o->pcrlock) { - ret = pcrlock(new_o->pcrlock); + if (options->pcrlock) { + ret = pcrlock(options->pcrlock); if (ret < 0) { - pr_info("trusted_key: pcrlock failed (%d)\n", ret); - kfree_sensitive(new_p); + pr_info("pcrlock failed (%d)\n", ret); goto out; } } - rcu_assign_keypointer(key, new_p); - call_rcu(&p->rcu, trusted_rcu_free); out: - kfree_sensitive(datablob); - kfree_sensitive(new_o); + kfree_sensitive(options); return ret; } -/* - * trusted_read - copy the sealed blob data to userspace in hex. - * On success, return to userspace the trusted key datablob size. - */ -static long trusted_read(const struct key *key, char *buffer, - size_t buflen) -{ - const struct trusted_key_payload *p; - char *bufp; - int i; - - p = dereference_key_locked(key); - if (!p) - return -EINVAL; - - if (buffer && buflen >= 2 * p->blob_len) { - bufp = buffer; - for (i = 0; i < p->blob_len; i++) - bufp = hex_byte_pack(bufp, p->blob[i]); - } - return 2 * p->blob_len; -} - -/* - * trusted_destroy - clear and free the key's payload - */ -static void trusted_destroy(struct key *key) +static int trusted_tpm_get_random(unsigned char *key, size_t key_len) { - kfree_sensitive(key->payload.data[0]); + return tpm_get_random(chip, key, key_len); } -struct key_type key_type_trusted = { - .name = "trusted", - .instantiate = trusted_instantiate, - .update = trusted_update, - .destroy = trusted_destroy, - .describe = user_describe, - .read = trusted_read, -}; - -EXPORT_SYMBOL_GPL(key_type_trusted); - static void trusted_shash_release(void) { if (hashalg) @@ -1196,14 +990,14 @@ static int __init trusted_shash_alloc(void) hmacalg = crypto_alloc_shash(hmac_alg, 0, 0); if (IS_ERR(hmacalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", + pr_info("could not allocate crypto %s\n", hmac_alg); return PTR_ERR(hmacalg); } hashalg = crypto_alloc_shash(hash_alg, 0, 0); if (IS_ERR(hashalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", + pr_info("could not allocate crypto %s\n", hash_alg); ret = PTR_ERR(hashalg); goto hashalg_fail; @@ -1231,16 +1025,13 @@ static int __init init_digests(void) return 0; } -static int __init init_trusted(void) +static int __init trusted_tpm_init(void) { int ret; - /* encrypted_keys.ko depends on successful load of this module even if - * TPM is not used. - */ chip = tpm_default_chip(); if (!chip) - return 0; + return -ENODEV; ret = init_digests(); if (ret < 0) @@ -1261,7 +1052,7 @@ err_put: return ret; } -static void __exit cleanup_trusted(void) +static void trusted_tpm_exit(void) { if (chip) { put_device(&chip->dev); @@ -1271,7 +1062,11 @@ static void __exit cleanup_trusted(void) } } -late_initcall(init_trusted); -module_exit(cleanup_trusted); - -MODULE_LICENSE("GPL"); +struct trusted_key_ops trusted_key_tpm_ops = { + .migratable = 1, /* migratable by default */ + .init = trusted_tpm_init, + .seal = trusted_tpm_seal, + .unseal = trusted_tpm_unseal, + .get_random = trusted_tpm_get_random, + .exit = trusted_tpm_exit, +}; diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c index c87c4df8703d4ea9426cebab43846ed69fb04ddd..617fabd4d913b81caa5e0537e12477671dbe3a77 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -4,6 +4,8 @@ * Copyright (C) 2014 Intel Corporation */ +#include <linux/asn1_encoder.h> +#include <linux/oid_registry.h> #include <linux/string.h> #include <linux/err.h> #include <linux/tpm.h> @@ -12,6 +14,10 @@ #include <keys/trusted-type.h> #include <keys/trusted_tpm.h> +#include <asm/unaligned.h> + +#include "tpm2key.asn1.h" + static struct tpm2_hash tpm2_hash_map[] = { {HASH_ALGO_SHA1, TPM_ALG_SHA1}, {HASH_ALGO_SHA256, TPM_ALG_SHA256}, @@ -20,6 +26,165 @@ static struct tpm2_hash tpm2_hash_map[] = { {HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, }; +static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 }; + +static int tpm2_key_encode(struct trusted_key_payload *payload, + struct trusted_key_options *options, + u8 *src, u32 len) +{ + const int SCRATCH_SIZE = PAGE_SIZE; + u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL); + u8 *work = scratch, *work1; + u8 *end_work = scratch + SCRATCH_SIZE; + u8 *priv, *pub; + u16 priv_len, pub_len; + + priv_len = get_unaligned_be16(src) + 2; + priv = src; + + src += priv_len; + + pub_len = get_unaligned_be16(src) + 2; + pub = src; + + if (!scratch) + return -ENOMEM; + + work = asn1_encode_oid(work, end_work, tpm2key_oid, + asn1_oid_len(tpm2key_oid)); + + if (options->blobauth_len == 0) { + unsigned char bool[3], *w = bool; + /* tag 0 is emptyAuth */ + w = asn1_encode_boolean(w, w + sizeof(bool), true); + if (WARN(IS_ERR(w), "BUG: Boolean failed to encode")) + return PTR_ERR(w); + work = asn1_encode_tag(work, end_work, 0, bool, w - bool); + } + + /* + * Assume both octet strings will encode to a 2 byte definite length + * + * Note: For a well behaved TPM, this warning should never + * trigger, so if it does there's something nefarious going on + */ + if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE, + "BUG: scratch buffer is too small")) + return -EINVAL; + + work = asn1_encode_integer(work, end_work, options->keyhandle); + work = asn1_encode_octet_string(work, end_work, pub, pub_len); + work = asn1_encode_octet_string(work, end_work, priv, priv_len); + + work1 = payload->blob; + work1 = asn1_encode_sequence(work1, work1 + sizeof(payload->blob), + scratch, work - scratch); + if (WARN(IS_ERR(work1), "BUG: ASN.1 encoder failed")) + return PTR_ERR(work1); + + return work1 - payload->blob; +} + +struct tpm2_key_context { + u32 parent; + const u8 *pub; + u32 pub_len; + const u8 *priv; + u32 priv_len; +}; + +static int tpm2_key_decode(struct trusted_key_payload *payload, + struct trusted_key_options *options, + u8 **buf) +{ + int ret; + struct tpm2_key_context ctx; + u8 *blob; + + memset(&ctx, 0, sizeof(ctx)); + + ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob, + payload->blob_len); + if (ret < 0) + return ret; + + if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE) + return -EINVAL; + + blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL); + if (!blob) + return -ENOMEM; + + *buf = blob; + options->keyhandle = ctx.parent; + + memcpy(blob, ctx.priv, ctx.priv_len); + blob += ctx.priv_len; + + memcpy(blob, ctx.pub, ctx.pub_len); + + return 0; +} + +int tpm2_key_parent(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + struct tpm2_key_context *ctx = context; + const u8 *v = value; + int i; + + ctx->parent = 0; + for (i = 0; i < vlen; i++) { + ctx->parent <<= 8; + ctx->parent |= v[i]; + } + + return 0; +} + +int tpm2_key_type(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + enum OID oid = look_up_OID(value, vlen); + + if (oid != OID_TPMSealedData) { + char buffer[50]; + + sprint_oid(value, vlen, buffer, sizeof(buffer)); + pr_debug("OID is \"%s\" which is not TPMSealedData\n", + buffer); + return -EINVAL; + } + + return 0; +} + +int tpm2_key_pub(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + struct tpm2_key_context *ctx = context; + + ctx->pub = value; + ctx->pub_len = vlen; + + return 0; +} + +int tpm2_key_priv(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + struct tpm2_key_context *ctx = context; + + ctx->priv = value; + ctx->priv_len = vlen; + + return 0; +} + /** * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. * @@ -63,9 +228,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { - unsigned int blob_len; + int blob_len = 0; struct tpm_buf buf; u32 hash; + u32 flags; int i; int rc; @@ -79,6 +245,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip, if (i == ARRAY_SIZE(tpm2_hash_map)) return -EINVAL; + if (!options->keyhandle) + return -EINVAL; + rc = tpm_try_get_ops(chip); if (rc) return rc; @@ -97,29 +266,32 @@ int tpm2_seal_trusted(struct tpm_chip *chip, TPM_DIGEST_SIZE); /* sensitive */ - tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1); + tpm_buf_append_u16(&buf, 4 + options->blobauth_len + payload->key_len); + + tpm_buf_append_u16(&buf, options->blobauth_len); + if (options->blobauth_len) + tpm_buf_append(&buf, options->blobauth, options->blobauth_len); - tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE); - tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE); - tpm_buf_append_u16(&buf, payload->key_len + 1); + tpm_buf_append_u16(&buf, payload->key_len); tpm_buf_append(&buf, payload->key, payload->key_len); - tpm_buf_append_u8(&buf, payload->migratable); /* public */ tpm_buf_append_u16(&buf, 14 + options->policydigest_len); tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH); tpm_buf_append_u16(&buf, hash); + /* key properties */ + flags = 0; + flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH; + flags |= payload->migratable ? (TPM2_OA_FIXED_TPM | + TPM2_OA_FIXED_PARENT) : 0; + tpm_buf_append_u32(&buf, flags); + /* policy */ - if (options->policydigest_len) { - tpm_buf_append_u32(&buf, 0); - tpm_buf_append_u16(&buf, options->policydigest_len); + tpm_buf_append_u16(&buf, options->policydigest_len); + if (options->policydigest_len) tpm_buf_append(&buf, options->policydigest, options->policydigest_len); - } else { - tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH); - tpm_buf_append_u16(&buf, 0); - } /* public parameters */ tpm_buf_append_u16(&buf, TPM_ALG_NULL); @@ -150,8 +322,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } - memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len); - payload->blob_len = blob_len; + blob_len = tpm2_key_encode(payload, options, + &buf.data[TPM_HEADER_SIZE + 4], + blob_len); out: tpm_buf_destroy(&buf); @@ -162,6 +335,10 @@ out: else rc = -EPERM; } + if (blob_len < 0) + return blob_len; + + payload->blob_len = blob_len; tpm_put_ops(chip); return rc; @@ -189,13 +366,45 @@ static int tpm2_load_cmd(struct tpm_chip *chip, unsigned int private_len; unsigned int public_len; unsigned int blob_len; + u8 *blob, *pub; int rc; + u32 attrs; + + rc = tpm2_key_decode(payload, options, &blob); + if (rc) { + /* old form */ + blob = payload->blob; + payload->old_format = 1; + } + + /* new format carries keyhandle but old format doesn't */ + if (!options->keyhandle) + return -EINVAL; - private_len = be16_to_cpup((__be16 *) &payload->blob[0]); - if (private_len > (payload->blob_len - 2)) + /* must be big enough for at least the two be16 size counts */ + if (payload->blob_len < 4) + return -EINVAL; + + private_len = get_unaligned_be16(blob); + + /* must be big enough for following public_len */ + if (private_len + 2 + 2 > (payload->blob_len)) + return -E2BIG; + + public_len = get_unaligned_be16(blob + 2 + private_len); + if (private_len + 2 + public_len + 2 > payload->blob_len) return -E2BIG; - public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]); + pub = blob + 2 + private_len + 2; + /* key attributes are always at offset 4 */ + attrs = get_unaligned_be32(pub + 4); + + if ((attrs & (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT)) == + (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT)) + payload->migratable = 0; + else + payload->migratable = 1; + blob_len = private_len + public_len + 4; if (blob_len > payload->blob_len) return -E2BIG; @@ -211,7 +420,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip, options->keyauth /* hmac */, TPM_DIGEST_SIZE); - tpm_buf_append(&buf, payload->blob, blob_len); + tpm_buf_append(&buf, blob, blob_len); if (buf.flags & TPM_BUF_OVERFLOW) { rc = -E2BIG; @@ -224,6 +433,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip, (__be32 *) &buf.data[TPM_HEADER_SIZE]); out: + if (blob != payload->blob) + kfree(blob); tpm_buf_destroy(&buf); if (rc > 0) @@ -265,7 +476,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, NULL /* nonce */, 0, TPM2_SA_CONTINUE_SESSION, options->blobauth /* hmac */, - TPM_DIGEST_SIZE); + options->blobauth_len); rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); if (rc > 0) @@ -274,7 +485,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, if (!rc) { data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); - if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE + 1) { + if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) { rc = -EFAULT; goto out; } @@ -285,9 +496,19 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, } data = &buf.data[TPM_HEADER_SIZE + 6]; - memcpy(payload->key, data, data_len - 1); - payload->key_len = data_len - 1; - payload->migratable = data[data_len - 1]; + if (payload->old_format) { + /* migratable flag is at the end of the key */ + memcpy(payload->key, data, data_len - 1); + payload->key_len = data_len - 1; + payload->migratable = data[data_len - 1]; + } else { + /* + * migratable flag already collected from key + * attributes + */ + memcpy(payload->key, data, data_len); + payload->key_len = data_len; + } } out: diff --git a/security/security.c b/security/security.c index 5ac96b16f8fab0a76666cec5efc1f1003116e549..94383f83ba42bd23d2ebb8c97d470a62744a9aca 100644 --- a/security/security.c +++ b/security/security.c @@ -890,6 +890,13 @@ int security_sb_eat_lsm_opts(char *options, void **mnt_opts) } EXPORT_SYMBOL(security_sb_eat_lsm_opts); +int security_sb_mnt_opts_compat(struct super_block *sb, + void *mnt_opts) +{ + return call_int_hook(sb_mnt_opts_compat, 0, sb, mnt_opts); +} +EXPORT_SYMBOL(security_sb_mnt_opts_compat); + int security_sb_remount(struct super_block *sb, void *mnt_opts) { @@ -1762,12 +1769,19 @@ int security_task_getsid(struct task_struct *p) return call_int_hook(task_getsid, 0, p); } -void security_task_getsecid(struct task_struct *p, u32 *secid) +void security_task_getsecid_subj(struct task_struct *p, u32 *secid) +{ + *secid = 0; + call_void_hook(task_getsecid_subj, p, secid); +} +EXPORT_SYMBOL(security_task_getsecid_subj); + +void security_task_getsecid_obj(struct task_struct *p, u32 *secid) { *secid = 0; - call_void_hook(task_getsecid, p, secid); + call_void_hook(task_getsecid_obj, p, secid); } -EXPORT_SYMBOL(security_task_getsecid); +EXPORT_SYMBOL(security_task_getsecid_obj); int security_task_setnice(struct task_struct *p, int nice) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 27034c43622263b8c3103337bca13484a0c278bb..51c7eae11f7e2c64c5184877627110824e4f5c1e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -229,10 +229,23 @@ static inline u32 cred_sid(const struct cred *cred) return tsec->sid; } +/* + * get the subjective security ID of a task + */ +static inline u32 task_sid_subj(const struct task_struct *task) +{ + u32 sid; + + rcu_read_lock(); + sid = cred_sid(rcu_dereference(task->cred)); + rcu_read_unlock(); + return sid; +} + /* * get the objective security ID of a task */ -static inline u32 task_sid(const struct task_struct *task) +static inline u32 task_sid_obj(const struct task_struct *task) { u32 sid; @@ -242,6 +255,29 @@ static inline u32 task_sid(const struct task_struct *task) return sid; } +/* + * get the security ID of a task for use with binder + */ +static inline u32 task_sid_binder(const struct task_struct *task) +{ + /* + * In many case where this function is used we should be using the + * task's subjective SID, but we can't reliably access the subjective + * creds of a task other than our own so we must use the objective + * creds/SID, which are safe to access. The downside is that if a task + * is temporarily overriding it's creds it will not be reflected here; + * however, it isn't clear that binder would handle that case well + * anyway. + * + * If this ever changes and we can safely reference the subjective + * creds/SID of another task, this function will make it easier to + * identify the various places where we make use of the task SIDs in + * the binder code. It is also likely that we will need to adjust + * the main drivers/android binder code as well. + */ + return task_sid_obj(task); +} + static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry); /* @@ -760,7 +796,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, if (sb->s_user_ns != &init_user_ns && strcmp(sb->s_type->name, "tmpfs") && strcmp(sb->s_type->name, "ramfs") && - strcmp(sb->s_type->name, "devpts")) { + strcmp(sb->s_type->name, "devpts") && + strcmp(sb->s_type->name, "overlay")) { if (context_sid || fscontext_sid || rootcontext_sid || defcontext_sid) { rc = -EACCES; @@ -2034,11 +2071,8 @@ static inline u32 open_file_to_av(struct file *file) static int selinux_binder_set_context_mgr(struct task_struct *mgr) { - u32 mysid = current_sid(); - u32 mgrsid = task_sid(mgr); - return avc_has_perm(&selinux_state, - mysid, mgrsid, SECCLASS_BINDER, + current_sid(), task_sid_binder(mgr), SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL); } @@ -2046,8 +2080,7 @@ static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to) { u32 mysid = current_sid(); - u32 fromsid = task_sid(from); - u32 tosid = task_sid(to); + u32 fromsid = task_sid_binder(from); int rc; if (mysid != fromsid) { @@ -2058,19 +2091,16 @@ static int selinux_binder_transaction(struct task_struct *from, return rc; } - return avc_has_perm(&selinux_state, - fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, - NULL); + return avc_has_perm(&selinux_state, fromsid, task_sid_binder(to), + SECCLASS_BINDER, BINDER__CALL, NULL); } static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to) { - u32 fromsid = task_sid(from); - u32 tosid = task_sid(to); - return avc_has_perm(&selinux_state, - fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, + task_sid_binder(from), task_sid_binder(to), + SECCLASS_BINDER, BINDER__TRANSFER, NULL); } @@ -2078,7 +2108,7 @@ static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) { - u32 sid = task_sid(to); + u32 sid = task_sid_binder(to); struct file_security_struct *fsec = selinux_file(file); struct dentry *dentry = file->f_path.dentry; struct inode_security_struct *isec; @@ -2114,10 +2144,10 @@ static int selinux_binder_transfer_file(struct task_struct *from, } static int selinux_ptrace_access_check(struct task_struct *child, - unsigned int mode) + unsigned int mode) { u32 sid = current_sid(); - u32 csid = task_sid(child); + u32 csid = task_sid_obj(child); if (mode & PTRACE_MODE_READ) return avc_has_perm(&selinux_state, @@ -2130,15 +2160,15 @@ static int selinux_ptrace_access_check(struct task_struct *child, static int selinux_ptrace_traceme(struct task_struct *parent) { return avc_has_perm(&selinux_state, - task_sid(parent), current_sid(), SECCLASS_PROCESS, - PROCESS__PTRACE, NULL); + task_sid_subj(parent), task_sid_obj(current), + SECCLASS_PROCESS, PROCESS__PTRACE, NULL); } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(target), SECCLASS_PROCESS, + current_sid(), task_sid_obj(target), SECCLASS_PROCESS, PROCESS__GETCAP, NULL); } @@ -2263,7 +2293,7 @@ static u32 ptrace_parent_sid(void) rcu_read_lock(); tracer = ptrace_parent(current); if (tracer) - sid = task_sid(tracer); + sid = task_sid_obj(tracer); rcu_read_unlock(); return sid; @@ -2684,6 +2714,61 @@ free_opt: return rc; } +static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts) +{ + struct selinux_mnt_opts *opts = mnt_opts; + struct superblock_security_struct *sbsec = sb->s_security; + u32 sid; + int rc; + + /* + * Superblock not initialized (i.e. no options) - reject if any + * options specified, otherwise accept. + */ + if (!(sbsec->flags & SE_SBINITIALIZED)) + return opts ? 1 : 0; + + /* + * Superblock initialized and no options specified - reject if + * superblock has any options set, otherwise accept. + */ + if (!opts) + return (sbsec->flags & SE_MNTMASK) ? 1 : 0; + + if (opts->fscontext) { + rc = parse_sid(sb, opts->fscontext, &sid); + if (rc) + return 1; + if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) + return 1; + } + if (opts->context) { + rc = parse_sid(sb, opts->context, &sid); + if (rc) + return 1; + if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) + return 1; + } + if (opts->rootcontext) { + struct inode_security_struct *root_isec; + + root_isec = backing_inode_security(sb->s_root); + rc = parse_sid(sb, opts->rootcontext, &sid); + if (rc) + return 1; + if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) + return 1; + } + if (opts->defcontext) { + rc = parse_sid(sb, opts->defcontext, &sid); + if (rc) + return 1; + if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) + return 1; + } + return 0; +} + static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) { struct selinux_mnt_opts *opts = mnt_opts; @@ -3920,7 +4005,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { struct file *file; - u32 sid = task_sid(tsk); + u32 sid = task_sid_obj(tsk); u32 perm; struct file_security_struct *fsec; @@ -4139,47 +4224,52 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents) static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETPGID, NULL); } static int selinux_task_getpgid(struct task_struct *p) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETPGID, NULL); } static int selinux_task_getsid(struct task_struct *p) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETSESSION, NULL); } -static void selinux_task_getsecid(struct task_struct *p, u32 *secid) +static void selinux_task_getsecid_subj(struct task_struct *p, u32 *secid) +{ + *secid = task_sid_subj(p); +} + +static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid) { - *secid = task_sid(p); + *secid = task_sid_obj(p); } static int selinux_task_setnice(struct task_struct *p, int nice) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } static int selinux_task_setioprio(struct task_struct *p, int ioprio) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } static int selinux_task_getioprio(struct task_struct *p) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETSCHED, NULL); } @@ -4210,7 +4300,7 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, upon context transitions. See selinux_bprm_committing_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); return 0; @@ -4219,21 +4309,21 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, static int selinux_task_setscheduler(struct task_struct *p) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } static int selinux_task_getscheduler(struct task_struct *p) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETSCHED, NULL); } static int selinux_task_movememory(struct task_struct *p) { return avc_has_perm(&selinux_state, - current_sid(), task_sid(p), SECCLASS_PROCESS, + current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } @@ -4252,14 +4342,14 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info, else secid = cred_sid(cred); return avc_has_perm(&selinux_state, - secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); + secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL); } static void selinux_task_to_inode(struct task_struct *p, struct inode *inode) { struct inode_security_struct *isec = selinux_inode(inode); - u32 sid = task_sid(p); + u32 sid = task_sid_obj(p); spin_lock(&isec->lock); isec->sclass = inode_mode_to_security_class(inode->i_mode); @@ -6152,7 +6242,7 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m struct ipc_security_struct *isec; struct msg_security_struct *msec; struct common_audit_data ad; - u32 sid = task_sid(target); + u32 sid = task_sid_subj(target); int rc; isec = selinux_ipc(msq); @@ -7049,6 +7139,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts), + LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat), LSM_HOOK_INIT(sb_remount, selinux_sb_remount), LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount), LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options), @@ -7120,7 +7211,8 @@ static struct security_hook_list selinux_hooks[] __lsm_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(task_getsecid, selinux_task_getsecid), + LSM_HOOK_INIT(task_getsecid_subj, selinux_task_getsecid_subj), + LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_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), diff --git a/security/selinux/ima.c b/security/selinux/ima.c index 03715893ff9716b8a0b56060fd875e72673cf572..34d421861bfc25ea488ac4a0ebead10682043b18 100644 --- a/security/selinux/ima.c +++ b/security/selinux/ima.c @@ -13,18 +13,83 @@ #include "ima.h" /* - * selinux_ima_measure_state - Measure hash of the SELinux policy + * selinux_ima_collect_state - Read selinux configuration settings * - * @state: selinux state struct + * @state: selinux_state * - * NOTE: This function must be called with policy_mutex held. + * On success returns the configuration settings string. + * On error, returns NULL. */ -void selinux_ima_measure_state(struct selinux_state *state) +static char *selinux_ima_collect_state(struct selinux_state *state) { + const char *on = "=1;", *off = "=0;"; + char *buf; + int buf_len, len, i, rc; + + buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1; + + len = strlen(on); + for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) + buf_len += strlen(selinux_policycap_names[i]) + len; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return NULL; + + rc = strscpy(buf, "initialized", buf_len); + WARN_ON(rc < 0); + + rc = strlcat(buf, selinux_initialized(state) ? on : off, buf_len); + WARN_ON(rc >= buf_len); + + rc = strlcat(buf, "enforcing", buf_len); + WARN_ON(rc >= buf_len); + + rc = strlcat(buf, enforcing_enabled(state) ? on : off, buf_len); + WARN_ON(rc >= buf_len); + + rc = strlcat(buf, "checkreqprot", buf_len); + WARN_ON(rc >= buf_len); + + rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len); + WARN_ON(rc >= buf_len); + + for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) { + rc = strlcat(buf, selinux_policycap_names[i], buf_len); + WARN_ON(rc >= buf_len); + + rc = strlcat(buf, state->policycap[i] ? on : off, buf_len); + WARN_ON(rc >= buf_len); + } + + return buf; +} + +/* + * selinux_ima_measure_state_locked - Measure SELinux state and hash of policy + * + * @state: selinux state struct + */ +void selinux_ima_measure_state_locked(struct selinux_state *state) +{ + char *state_str = NULL; void *policy = NULL; size_t policy_len; int rc = 0; + WARN_ON(!mutex_is_locked(&state->policy_mutex)); + + state_str = selinux_ima_collect_state(state); + if (!state_str) { + pr_err("SELinux: %s: failed to read state.\n", __func__); + return; + } + + ima_measure_critical_data("selinux", "selinux-state", + state_str, strlen(state_str), false); + + kfree(state_str); + /* * Measure SELinux policy only after initialization is completed. */ @@ -42,3 +107,17 @@ void selinux_ima_measure_state(struct selinux_state *state) vfree(policy); } + +/* + * selinux_ima_measure_state - Measure SELinux state and hash of policy + * + * @state: selinux state struct + */ +void selinux_ima_measure_state(struct selinux_state *state) +{ + WARN_ON(mutex_is_locked(&state->policy_mutex)); + + mutex_lock(&state->policy_mutex); + selinux_ima_measure_state_locked(state); + mutex_unlock(&state->policy_mutex); +} diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 1605abce6a9444cda33e20dbe99a151e9a81aa5f..f3ad0a7facfa610bbf8e74010d4bb83e2dcdf361 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -242,11 +242,12 @@ struct security_class_mapping secclass_map[] = { { "infiniband_endport", { "manage_subnet", NULL } }, { "bpf", - {"map_create", "map_read", "map_write", "prog_load", "prog_run"} }, + { "map_create", "map_read", "map_write", "prog_load", "prog_run", + NULL } }, { "xdp_socket", { COMMON_SOCK_PERMS, NULL } }, { "perf_event", - {"open", "cpu", "kernel", "tracepoint", "read", "write"} }, + { "open", "cpu", "kernel", "tracepoint", "read", "write", NULL } }, { "anon_inode", { COMMON_FILE_PERMS, NULL } }, { NULL } diff --git a/security/selinux/include/ima.h b/security/selinux/include/ima.h index d69c366114233b05af4f94ebaef85c0d306adf05..75ca92b4a4622c031ab5d7b568773c13011520c1 100644 --- a/security/selinux/include/ima.h +++ b/security/selinux/include/ima.h @@ -15,10 +15,16 @@ #ifdef CONFIG_IMA extern void selinux_ima_measure_state(struct selinux_state *selinux_state); +extern void selinux_ima_measure_state_locked( + struct selinux_state *selinux_state); #else static inline void selinux_ima_measure_state(struct selinux_state *selinux_state) { } +static inline void selinux_ima_measure_state_locked( + struct selinux_state *selinux_state) +{ +} #endif #endif /* _SELINUX_IMA_H_ */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 98e475a3ba4b1dd672c50557afea5d1d590ff9b0..dff5f4accba3ce745163274d2ff9067fbd3bb879 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -434,7 +434,7 @@ extern struct page *selinux_kernel_status_page(struct selinux_state *state); #define SELINUX_KERNEL_STATUS_VERSION 1 struct selinux_kernel_status { - u32 version; /* version number of thie structure */ + u32 version; /* version number of the structure */ u32 sequence; /* sequence number of seqlock logic */ u32 enforcing; /* current setting of enforcing mode */ u32 policyload; /* times of policy reloaded */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fff6babeeae669d6d40a8325d54c921d4c537706..e4cd7cb856f375c8eaab1894f632374510709bf2 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -41,6 +41,7 @@ #include "security.h" #include "objsec.h" #include "conditional.h" +#include "ima.h" enum sel_inos { SEL_ROOT_INO = 2, @@ -182,6 +183,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, selinux_status_update_setenforce(state, new_value); if (!new_value) call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); + + selinux_ima_measure_state(state); } length = count; out: @@ -758,6 +761,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, checkreqprot_set(fsi->state, (new_value ? 1 : 0)); length = count; + + selinux_ima_measure_state(fsi->state); + out: kfree(page); return length; diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 3881787ce492c6693efa55dd20ee6c49204d3037..b8f6b3e0a92191efc24c3743c2e2f195276d7d12 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -13,7 +13,7 @@ static struct kmem_cache *hashtab_node_cachep __ro_after_init; /* * Here we simply round the number of elements up to the nearest power of two. - * I tried also other options like rouding down or rounding to the closest + * I tried also other options like rounding down or rounding to the closest * power of two (up or down based on which is closer), but I was unable to * find any significant difference in lookup/insert performance that would * justify switching to a different (less intuitive) formula. It could be that diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 0e5b17c2ff97a858b7561e86102fd71de82a1fbb..72ef11f277755d2bc36f40d2b46e755797efca5e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2205,7 +2205,7 @@ static void selinux_notify_policy_change(struct selinux_state *state, selinux_status_update_policyload(state, seqno); selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); - selinux_ima_measure_state(state); + selinux_ima_measure_state_locked(state); } void selinux_policy_commit(struct selinux_state *state, diff --git a/security/smack/smack.h b/security/smack/smack.h index a9768b12716bf737f76111a3e4492e9ae14c168f..08f9cb80655ce08d338aeba3b11a895c33c4263a 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -383,7 +383,23 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp) return tsp->smk_task; } -static inline struct smack_known *smk_of_task_struct( +static inline struct smack_known *smk_of_task_struct_subj( + const struct task_struct *t) +{ + struct smack_known *skp; + const struct cred *cred; + + rcu_read_lock(); + + cred = rcu_dereference(t->cred); + skp = smk_of_task(smack_cred(cred)); + + rcu_read_unlock(); + + return skp; +} + +static inline struct smack_known *smk_of_task_struct_obj( const struct task_struct *t) { struct smack_known *skp; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 12a45e61c1a54cb21213bb35bbb9adba03bbd759..cd14bec4ad800c157150cb15b64ca45b55e7573c 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -159,7 +159,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp, static int smk_bu_task(struct task_struct *otp, int mode, int rc) { struct task_smack *tsp = smack_cred(current_cred()); - struct smack_known *smk_task = smk_of_task_struct(otp); + struct smack_known *smk_task = smk_of_task_struct_obj(otp); char acc[SMK_NUM_ACCESS_TYPE + 1]; if (rc <= 0) @@ -479,7 +479,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) { struct smack_known *skp; - skp = smk_of_task_struct(ctp); + skp = smk_of_task_struct_obj(ctp); return smk_ptrace_rule_check(current, skp, mode, __func__); } @@ -2033,7 +2033,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access, const char *caller) { struct smk_audit_info ad; - struct smack_known *skp = smk_of_task_struct(p); + struct smack_known *skp = smk_of_task_struct_subj(p); int rc; smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); @@ -2078,15 +2078,29 @@ static int smack_task_getsid(struct task_struct *p) } /** - * smack_task_getsecid - get the secid of the task - * @p: the object task + * smack_task_getsecid_subj - get the subjective secid of the task + * @p: the task * @secid: where to put the result * - * Sets the secid to contain a u32 version of the smack label. + * Sets the secid to contain a u32 version of the task's subjective smack label. + */ +static void smack_task_getsecid_subj(struct task_struct *p, u32 *secid) +{ + struct smack_known *skp = smk_of_task_struct_subj(p); + + *secid = skp->smk_secid; +} + +/** + * smack_task_getsecid_obj - get the objective secid of the task + * @p: the task + * @secid: 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(struct task_struct *p, u32 *secid) +static void smack_task_getsecid_obj(struct task_struct *p, u32 *secid) { - struct smack_known *skp = smk_of_task_struct(p); + struct smack_known *skp = smk_of_task_struct_obj(p); *secid = skp->smk_secid; } @@ -2174,7 +2188,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, { struct smk_audit_info ad; struct smack_known *skp; - struct smack_known *tkp = smk_of_task_struct(p); + struct smack_known *tkp = smk_of_task_struct_obj(p); int rc; if (!sig) @@ -2212,7 +2226,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, static void smack_task_to_inode(struct task_struct *p, struct inode *inode) { struct inode_smack *isp = smack_inode(inode); - struct smack_known *skp = smk_of_task_struct(p); + struct smack_known *skp = smk_of_task_struct_obj(p); isp->smk_inode = skp; isp->smk_flags |= SMK_INODE_INSTANT; @@ -3483,7 +3497,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ static int smack_getprocattr(struct task_struct *p, char *name, char **value) { - struct smack_known *skp = smk_of_task_struct(p); + struct smack_known *skp = smk_of_task_struct_subj(p); char *cp; int slen; @@ -4759,7 +4773,8 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { 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(task_getsecid, smack_task_getsecid), + LSM_HOOK_INIT(task_getsecid_subj, smack_task_getsecid_subj), + LSM_HOOK_INIT(task_getsecid_obj, smack_task_getsecid_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), diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 161be8b7d1317b0825b61ce18c6f44431f641d06..61dfa86d444d81ee439f8b7311b98b95f28e08ad 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -285,7 +285,6 @@ static void v253_wakeup(struct tty_struct *tty) } struct tty_ldisc_ops v253_ops = { - .magic = TTY_LDISC_MAGIC, .name = "cx20442", .owner = THIS_MODULE, .open = v253_open, diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 57feb473a579caa89a697b90da48d7ba7d426f30..98198c7cc872d32e14f3b03c0c959d2b0fb22fc5 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -395,7 +395,6 @@ static void cx81801_wakeup(struct tty_struct *tty) } static struct tty_ldisc_ops cx81801_ops = { - .magic = TTY_LDISC_MAGIC, .name = "cx81801", .owner = THIS_MODULE, .open = cx81801_open, diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h index 546d6ecf0a35b52a58196f07676058e59c301b62..45029354e0a8b42f94e379ecafdf9ba7d50f24bf 100644 --- a/tools/arch/x86/include/asm/msr-index.h +++ b/tools/arch/x86/include/asm/msr-index.h @@ -628,8 +628,6 @@ #define MSR_IA32_APICBASE_ENABLE (1<<11) #define MSR_IA32_APICBASE_BASE (0xfffff<<12) -#define MSR_IA32_TSCDEADLINE 0x000006e0 - #define MSR_IA32_UCODE_WRITE 0x00000079 #define MSR_IA32_UCODE_REV 0x0000008b diff --git a/tools/arch/x86/kcpuid/Makefile b/tools/arch/x86/kcpuid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..87b554fab14b8555068a79511adc1a8e2db42fff --- /dev/null +++ b/tools/arch/x86/kcpuid/Makefile @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for x86/kcpuid tool + +kcpuid : kcpuid.c + +CFLAGS = -Wextra + +BINDIR ?= /usr/sbin + +HWDATADIR ?= /usr/share/misc/ + +override CFLAGS += -O2 -Wall -I../../../include + +%: %.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +.PHONY : clean +clean : + @rm -f kcpuid + +install : kcpuid + install -d $(DESTDIR)$(BINDIR) + install -m 755 -p kcpuid $(DESTDIR)$(BINDIR)/kcpuid + install -m 444 -p cpuid.csv $(HWDATADIR)/cpuid.csv diff --git a/tools/arch/x86/kcpuid/cpuid.csv b/tools/arch/x86/kcpuid/cpuid.csv new file mode 100644 index 0000000000000000000000000000000000000000..4f1c4b0c29e98a4ee06bb7fa06bc4ca0310eac6a --- /dev/null +++ b/tools/arch/x86/kcpuid/cpuid.csv @@ -0,0 +1,400 @@ +# The basic row format is: +# LEAF, SUBLEAF, register_name, bits, short_name, long_description + +# Leaf 00H + 0, 0, EAX, 31:0, max_basic_leafs, Max input value for supported subleafs + +# Leaf 01H + 1, 0, EAX, 3:0, stepping, Stepping ID + 1, 0, EAX, 7:4, model, Model + 1, 0, EAX, 11:8, family, Family ID + 1, 0, EAX, 13:12, processor, Processor Type + 1, 0, EAX, 19:16, model_ext, Extended Model ID + 1, 0, EAX, 27:20, family_ext, Extended Family ID + + 1, 0, EBX, 7:0, brand, Brand Index + 1, 0, EBX, 15:8, clflush_size, CLFLUSH line size (value * 8) in bytes + 1, 0, EBX, 23:16, max_cpu_id, Maxim number of addressable logic cpu in this package + 1, 0, EBX, 31:24, apic_id, Initial APIC ID + + 1, 0, ECX, 0, sse3, Streaming SIMD Extensions 3(SSE3) + 1, 0, ECX, 1, pclmulqdq, PCLMULQDQ instruction supported + 1, 0, ECX, 2, dtes64, DS area uses 64-bit layout + 1, 0, ECX, 3, mwait, MONITOR/MWAIT supported + 1, 0, ECX, 4, ds_cpl, CPL Qualified Debug Store which allows for branch message storage qualified by CPL + 1, 0, ECX, 5, vmx, Virtual Machine Extensions supported + 1, 0, ECX, 6, smx, Safer Mode Extension supported + 1, 0, ECX, 7, eist, Enhanced Intel SpeedStep Technology + 1, 0, ECX, 8, tm2, Thermal Monitor 2 + 1, 0, ECX, 9, ssse3, Supplemental Streaming SIMD Extensions 3 (SSSE3) + 1, 0, ECX, 10, l1_ctx_id, L1 data cache could be set to either adaptive mode or shared mode (check IA32_MISC_ENABLE bit 24 definition) + 1, 0, ECX, 11, sdbg, IA32_DEBUG_INTERFACE MSR for silicon debug supported + 1, 0, ECX, 12, fma, FMA extensions using YMM state supported + 1, 0, ECX, 13, cmpxchg16b, 'CMPXCHG16B - Compare and Exchange Bytes' supported + 1, 0, ECX, 14, xtpr_update, xTPR Update Control supported + 1, 0, ECX, 15, pdcm, Perfmon and Debug Capability present + 1, 0, ECX, 17, pcid, Process-Context Identifiers feature present + 1, 0, ECX, 18, dca, Prefetching data from a memory mapped device supported + 1, 0, ECX, 19, sse4_1, SSE4.1 feature present + 1, 0, ECX, 20, sse4_2, SSE4.2 feature present + 1, 0, ECX, 21, x2apic, x2APIC supported + 1, 0, ECX, 22, movbe, MOVBE instruction supported + 1, 0, ECX, 23, popcnt, POPCNT instruction supported + 1, 0, ECX, 24, tsc_deadline_timer, LAPIC supports one-shot operation using a TSC deadline value + 1, 0, ECX, 25, aesni, AESNI instruction supported + 1, 0, ECX, 26, xsave, XSAVE/XRSTOR processor extended states (XSETBV/XGETBV/XCR0) + 1, 0, ECX, 27, osxsave, OS has set CR4.OSXSAVE bit to enable XSETBV/XGETBV/XCR0 + 1, 0, ECX, 28, avx, AVX instruction supported + 1, 0, ECX, 29, f16c, 16-bit floating-point conversion instruction supported + 1, 0, ECX, 30, rdrand, RDRAND instruction supported + + 1, 0, EDX, 0, fpu, x87 FPU on chip + 1, 0, EDX, 1, vme, Virtual-8086 Mode Enhancement + 1, 0, EDX, 2, de, Debugging Extensions + 1, 0, EDX, 3, pse, Page Size Extensions + 1, 0, EDX, 4, tsc, Time Stamp Counter + 1, 0, EDX, 5, msr, RDMSR and WRMSR Support + 1, 0, EDX, 6, pae, Physical Address Extensions + 1, 0, EDX, 7, mce, Machine Check Exception + 1, 0, EDX, 8, cx8, CMPXCHG8B instr + 1, 0, EDX, 9, apic, APIC on Chip + 1, 0, EDX, 11, sep, SYSENTER and SYSEXIT instrs + 1, 0, EDX, 12, mtrr, Memory Type Range Registers + 1, 0, EDX, 13, pge, Page Global Bit + 1, 0, EDX, 14, mca, Machine Check Architecture + 1, 0, EDX, 15, cmov, Conditional Move Instrs + 1, 0, EDX, 16, pat, Page Attribute Table + 1, 0, EDX, 17, pse36, 36-Bit Page Size Extension + 1, 0, EDX, 18, psn, Processor Serial Number + 1, 0, EDX, 19, clflush, CLFLUSH instr +# 1, 0, EDX, 20, + 1, 0, EDX, 21, ds, Debug Store + 1, 0, EDX, 22, acpi, Thermal Monitor and Software Controlled Clock Facilities + 1, 0, EDX, 23, mmx, Intel MMX Technology + 1, 0, EDX, 24, fxsr, XSAVE and FXRSTOR Instrs + 1, 0, EDX, 25, sse, SSE + 1, 0, EDX, 26, sse2, SSE2 + 1, 0, EDX, 27, ss, Self Snoop + 1, 0, EDX, 28, hit, Max APIC IDs + 1, 0, EDX, 29, tm, Thermal Monitor +# 1, 0, EDX, 30, + 1, 0, EDX, 31, pbe, Pending Break Enable + +# Leaf 02H +# cache and TLB descriptor info + +# Leaf 03H +# Precessor Serial Number, introduced on Pentium III, not valid for +# latest models + +# Leaf 04H +# thread/core and cache topology + 4, 0, EAX, 4:0, cache_type, Cache type like instr/data or unified + 4, 0, EAX, 7:5, cache_level, Cache Level (starts at 1) + 4, 0, EAX, 8, cache_self_init, Cache Self Initialization + 4, 0, EAX, 9, fully_associate, Fully Associative cache +# 4, 0, EAX, 13:10, resvd, resvd + 4, 0, EAX, 25:14, max_logical_id, Max number of addressable IDs for logical processors sharing the cache + 4, 0, EAX, 31:26, max_phy_id, Max number of addressable IDs for processors in phy package + + 4, 0, EBX, 11:0, cache_linesize, Size of a cache line in bytes + 4, 0, EBX, 21:12, cache_partition, Physical Line partitions + 4, 0, EBX, 31:22, cache_ways, Ways of associativity + 4, 0, ECX, 31:0, cache_sets, Number of Sets - 1 + 4, 0, EDX, 0, c_wbinvd, 1 means WBINVD/INVD is not ganranteed to act upon lower level caches of non-originating threads sharing this cache + 4, 0, EDX, 1, c_incl, Whether cache is inclusive of lower cache level + 4, 0, EDX, 2, c_comp_index, Complex Cache Indexing + +# Leaf 05H +# MONITOR/MWAIT + 5, 0, EAX, 15:0, min_mon_size, Smallest monitor line size in bytes + 5, 0, EBX, 15:0, max_mon_size, Largest monitor line size in bytes + 5, 0, ECX, 0, mwait_ext, Enum of Monitor-Mwait extensions supported + 5, 0, ECX, 1, mwait_irq_break, Largest monitor line size in bytes + 5, 0, EDX, 3:0, c0_sub_stats, Number of C0* sub C-states supported using MWAIT + 5, 0, EDX, 7:4, c1_sub_stats, Number of C1* sub C-states supported using MWAIT + 5, 0, EDX, 11:8, c2_sub_stats, Number of C2* sub C-states supported using MWAIT + 5, 0, EDX, 15:12, c3_sub_stats, Number of C3* sub C-states supported using MWAIT + 5, 0, EDX, 19:16, c4_sub_stats, Number of C4* sub C-states supported using MWAIT + 5, 0, EDX, 23:20, c5_sub_stats, Number of C5* sub C-states supported using MWAIT + 5, 0, EDX, 27:24, c6_sub_stats, Number of C6* sub C-states supported using MWAIT + 5, 0, EDX, 31:28, c7_sub_stats, Number of C7* sub C-states supported using MWAIT + +# Leaf 06H +# Thermal & Power Management + + 6, 0, EAX, 0, dig_temp, Digital temperature sensor supported + 6, 0, EAX, 1, turbo, Intel Turbo Boost + 6, 0, EAX, 2, arat, Always running APIC timer +# 6, 0, EAX, 3, resv, Reserved + 6, 0, EAX, 4, pln, Power limit notifications supported + 6, 0, EAX, 5, ecmd, Clock modulation duty cycle extension supported + 6, 0, EAX, 6, ptm, Package thermal management supported + 6, 0, EAX, 7, hwp, HWP base register + 6, 0, EAX, 8, hwp_notify, HWP notification + 6, 0, EAX, 9, hwp_act_window, HWP activity window + 6, 0, EAX, 10, hwp_energy, HWP energy performance preference + 6, 0, EAX, 11, hwp_pkg_req, HWP package level request +# 6, 0, EAX, 12, resv, Reserved + 6, 0, EAX, 13, hdc, HDC base registers supported + 6, 0, EAX, 14, turbo3, Turbo Boost Max 3.0 + 6, 0, EAX, 15, hwp_cap, Highest Performance change supported + 6, 0, EAX, 16, hwp_peci, HWP PECI override is supported + 6, 0, EAX, 17, hwp_flex, Flexible HWP is supported + 6, 0, EAX, 18, hwp_fast, Fast access mode for the IA32_HWP_REQUEST MSR is supported +# 6, 0, EAX, 19, resv, Reserved + 6, 0, EAX, 20, hwp_ignr, Ignoring Idle Logical Processor HWP request is supported + + 6, 0, EBX, 3:0, therm_irq_thresh, Number of Interrupt Thresholds in Digital Thermal Sensor + 6, 0, ECX, 0, aperfmperf, Presence of IA32_MPERF and IA32_APERF + 6, 0, ECX, 3, energ_bias, Performance-energy bias preference supported + +# Leaf 07H +# ECX == 0 +# AVX512 refers to https://en.wikipedia.org/wiki/AVX-512 +# XXX: Do we really need to enumerate each and every AVX512 sub features + + 7, 0, EBX, 0, fsgsbase, RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE supported + 7, 0, EBX, 1, tsc_adjust, TSC_ADJUST MSR supported + 7, 0, EBX, 2, sgx, Software Guard Extensions + 7, 0, EBX, 3, bmi1, BMI1 + 7, 0, EBX, 4, hle, Hardware Lock Elision + 7, 0, EBX, 5, avx2, AVX2 +# 7, 0, EBX, 6, fdp_excp_only, x87 FPU Data Pointer updated only on x87 exceptions + 7, 0, EBX, 7, smep, Supervisor-Mode Execution Prevention + 7, 0, EBX, 8, bmi2, BMI2 + 7, 0, EBX, 9, rep_movsb, Enhanced REP MOVSB/STOSB + 7, 0, EBX, 10, invpcid, INVPCID instruction + 7, 0, EBX, 11, rtm, Restricted Transactional Memory + 7, 0, EBX, 12, rdt_m, Intel RDT Monitoring capability + 7, 0, EBX, 13, depc_fpu_cs_ds, Deprecates FPU CS and FPU DS + 7, 0, EBX, 14, mpx, Memory Protection Extensions + 7, 0, EBX, 15, rdt_a, Intel RDT Allocation capability + 7, 0, EBX, 16, avx512f, AVX512 Foundation instr + 7, 0, EBX, 17, avx512dq, AVX512 Double and Quadword AVX512 instr + 7, 0, EBX, 18, rdseed, RDSEED instr + 7, 0, EBX, 19, adx, ADX instr + 7, 0, EBX, 20, smap, Supervisor Mode Access Prevention + 7, 0, EBX, 21, avx512ifma, AVX512 Integer Fused Multiply Add +# 7, 0, EBX, 22, resvd, resvd + 7, 0, EBX, 23, clflushopt, CLFLUSHOPT instr + 7, 0, EBX, 24, clwb, CLWB instr + 7, 0, EBX, 25, intel_pt, Intel Processor Trace instr + 7, 0, EBX, 26, avx512pf, Prefetch + 7, 0, EBX, 27, avx512er, AVX512 Exponent Reciproca instr + 7, 0, EBX, 28, avx512cd, AVX512 Conflict Detection instr + 7, 0, EBX, 29, sha, Intel Secure Hash Algorithm Extensions instr + 7, 0, EBX, 26, avx512bw, AVX512 Byte & Word instr + 7, 0, EBX, 28, avx512vl, AVX512 Vector Length Extentions (VL) + 7, 0, ECX, 0, prefetchwt1, X + 7, 0, ECX, 1, avx512vbmi, AVX512 Vector Byte Manipulation Instructions + 7, 0, ECX, 2, umip, User-mode Instruction Prevention + + 7, 0, ECX, 3, pku, Protection Keys for User-mode pages + 7, 0, ECX, 4, ospke, CR4 PKE set to enable protection keys +# 7, 0, ECX, 16:5, resvd, resvd + 7, 0, ECX, 21:17, mawau, The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode + 7, 0, ECX, 22, rdpid, RDPID and IA32_TSC_AUX +# 7, 0, ECX, 29:23, resvd, resvd + 7, 0, ECX, 30, sgx_lc, SGX Launch Configuration +# 7, 0, ECX, 31, resvd, resvd + +# Leaf 08H +# + + +# Leaf 09H +# Direct Cache Access (DCA) information + 9, 0, ECX, 31:0, dca_cap, The value of IA32_PLATFORM_DCA_CAP + +# Leaf 0AH +# Architectural Performance Monitoring +# +# Do we really need to print out the PMU related stuff? +# Does normal user really care about it? +# + 0xA, 0, EAX, 7:0, pmu_ver, Performance Monitoring Unit version + 0xA, 0, EAX, 15:8, pmu_gp_cnt_num, Numer of general-purose PMU counters per logical CPU + 0xA, 0, EAX, 23:16, pmu_cnt_bits, Bit wideth of PMU counter + 0xA, 0, EAX, 31:24, pmu_ebx_bits, Length of EBX bit vector to enumerate PMU events + + 0xA, 0, EBX, 0, pmu_no_core_cycle_evt, Core cycle event not available + 0xA, 0, EBX, 1, pmu_no_instr_ret_evt, Instruction retired event not available + 0xA, 0, EBX, 2, pmu_no_ref_cycle_evt, Reference cycles event not available + 0xA, 0, EBX, 3, pmu_no_llc_ref_evt, Last-level cache reference event not available + 0xA, 0, EBX, 4, pmu_no_llc_mis_evt, Last-level cache misses event not available + 0xA, 0, EBX, 5, pmu_no_br_instr_ret_evt, Branch instruction retired event not available + 0xA, 0, EBX, 6, pmu_no_br_mispredict_evt, Branch mispredict retired event not available + + 0xA, 0, ECX, 4:0, pmu_fixed_cnt_num, Performance Monitoring Unit version + 0xA, 0, ECX, 12:5, pmu_fixed_cnt_bits, Numer of PMU counters per logical CPU + +# Leaf 0BH +# Extended Topology Enumeration Leaf +# + + 0xB, 0, EAX, 4:0, id_shift, Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type + 0xB, 0, EBX, 15:0, cpu_nr, Number of logical processors at this level type + 0xB, 0, ECX, 15:8, lvl_type, 0-Invalid 1-SMT 2-Core + 0xB, 0, EDX, 31:0, x2apic_id, x2APIC ID the current logical processor + + +# Leaf 0DH +# Processor Extended State + + 0xD, 0, EAX, 0, x87, X87 state + 0xD, 0, EAX, 1, sse, SSE state + 0xD, 0, EAX, 2, avx, AVX state + 0xD, 0, EAX, 4:3, mpx, MPX state + 0xD, 0, EAX, 7:5, avx512, AVX-512 state + 0xD, 0, EAX, 9, pkru, PKRU state + + 0xD, 0, EBX, 31:0, max_sz_xcr0, Maximum size (bytes) required by enabled features in XCR0 + 0xD, 0, ECX, 31:0, max_sz_xsave, Maximum size (bytes) of the XSAVE/XRSTOR save area + + 0xD, 1, EAX, 0, xsaveopt, XSAVEOPT available + 0xD, 1, EAX, 1, xsavec, XSAVEC and compacted form supported + 0xD, 1, EAX, 2, xgetbv, XGETBV supported + 0xD, 1, EAX, 3, xsaves, XSAVES/XRSTORS and IA32_XSS supported + + 0xD, 1, EBX, 31:0, max_sz_xcr0, Maximum size (bytes) required by enabled features in XCR0 + 0xD, 1, ECX, 8, pt, PT state + 0xD, 1, ECX, 11, cet_usr, CET user state + 0xD, 1, ECX, 12, cet_supv, CET supervisor state + 0xD, 1, ECX, 13, hdc, HDC state + 0xD, 1, ECX, 16, hwp, HWP state + +# Leaf 0FH +# Intel RDT Monitoring + + 0xF, 0, EBX, 31:0, rmid_range, Maximum range (zero-based) of RMID within this physical processor of all types + 0xF, 0, EDX, 1, l3c_rdt_mon, L3 Cache RDT Monitoring supported + + 0xF, 1, ECX, 31:0, rmid_range, Maximum range (zero-based) of RMID of this types + 0xF, 1, EDX, 0, l3c_ocp_mon, L3 Cache occupancy Monitoring supported + 0xF, 1, EDX, 1, l3c_tbw_mon, L3 Cache Total Bandwidth Monitoring supported + 0xF, 1, EDX, 2, l3c_lbw_mon, L3 Cache Local Bandwidth Monitoring supported + +# Leaf 10H +# Intel RDT Allocation + + 0x10, 0, EBX, 1, l3c_rdt_alloc, L3 Cache Allocation supported + 0x10, 0, EBX, 2, l2c_rdt_alloc, L2 Cache Allocation supported + 0x10, 0, EBX, 3, mem_bw_alloc, Memory Bandwidth Allocation supported + + +# Leaf 12H +# SGX Capability +# +# Some detailed SGX features not added yet + + 0x12, 0, EAX, 0, sgx1, L3 Cache Allocation supported + 0x12, 1, EAX, 0, sgx2, L3 Cache Allocation supported + + +# Leaf 14H +# Intel Processor Tracer +# + +# Leaf 15H +# Time Stamp Counter and Nominal Core Crystal Clock Information + + 0x15, 0, EAX, 31:0, tsc_denominator, The denominator of the TSC/”core crystal clock” ratio + 0x15, 0, EBX, 31:0, tsc_numerator, The numerator of the TSC/”core crystal clock” ratio + 0x15, 0, ECX, 31:0, nom_freq, Nominal frequency of the core crystal clock in Hz + +# Leaf 16H +# Processor Frequency Information + + 0x16, 0, EAX, 15:0, cpu_base_freq, Processor Base Frequency in MHz + 0x16, 0, EBX, 15:0, cpu_max_freq, Maximum Frequency in MHz + 0x16, 0, ECX, 15:0, bus_freq, Bus (Reference) Frequency in MHz + +# Leaf 17H +# System-On-Chip Vendor Attribute + + 0x17, 0, EAX, 31:0, max_socid, Maximum input value of supported sub-leaf + 0x17, 0, EBX, 15:0, soc_vid, SOC Vendor ID + 0x17, 0, EBX, 16, std_vid, SOC Vendor ID is assigned via an industry standard scheme + 0x17, 0, ECX, 31:0, soc_pid, SOC Project ID assigned by vendor + 0x17, 0, EDX, 31:0, soc_sid, SOC Stepping ID + +# Leaf 18H +# Deterministic Address Translation Parameters + + +# Leaf 19H +# Key Locker Leaf + + +# Leaf 1AH +# Hybrid Information + + 0x1A, 0, EAX, 31:24, core_type, 20H-Intel_Atom 40H-Intel_Core + + +# Leaf 1FH +# V2 Extended Topology - A preferred superset to leaf 0BH + + +# According to SDM +# 40000000H - 4FFFFFFFH is invalid range + + +# Leaf 80000001H +# Extended Processor Signature and Feature Bits + +0x80000001, 0, ECX, 0, lahf_lm, LAHF/SAHF available in 64-bit mode +0x80000001, 0, ECX, 5, lzcnt, LZCNT +0x80000001, 0, ECX, 8, prefetchw, PREFETCHW + +0x80000001, 0, EDX, 11, sysret, SYSCALL/SYSRET supported +0x80000001, 0, EDX, 20, exec_dis, Execute Disable Bit available +0x80000001, 0, EDX, 26, 1gb_page, 1GB page supported +0x80000001, 0, EDX, 27, rdtscp, RDTSCP and IA32_TSC_AUX are available +#0x80000001, 0, EDX, 29, 64b, 64b Architecture supported + +# Leaf 80000002H/80000003H/80000004H +# Processor Brand String + +# Leaf 80000005H +# Reserved + +# Leaf 80000006H +# Extended L2 Cache Features + +0x80000006, 0, ECX, 7:0, clsize, Cache Line size in bytes +0x80000006, 0, ECX, 15:12, l2c_assoc, L2 Associativity +0x80000006, 0, ECX, 31:16, csize, Cache size in 1K units + + +# Leaf 80000007H + +0x80000007, 0, EDX, 8, nonstop_tsc, Invariant TSC available + + +# Leaf 80000008H + +0x80000008, 0, EAX, 7:0, phy_adr_bits, Physical Address Bits +0x80000008, 0, EAX, 15:8, lnr_adr_bits, Linear Address Bits +0x80000007, 0, EBX, 9, wbnoinvd, WBNOINVD + +# 0x8000001E +# EAX: Extended APIC ID +0x8000001E, 0, EAX, 31:0, extended_apic_id, Extended APIC ID +# EBX: Core Identifiers +0x8000001E, 0, EBX, 7:0, core_id, Identifies the logical core ID +0x8000001E, 0, EBX, 15:8, threads_per_core, The number of threads per core is threads_per_core + 1 +# ECX: Node Identifiers +0x8000001E, 0, ECX, 7:0, node_id, Node ID +0x8000001E, 0, ECX, 10:8, nodes_per_processor, Nodes per processor { 0: 1 node, else reserved } + +# 8000001F: AMD Secure Encryption +0x8000001F, 0, EAX, 0, sme, Secure Memory Encryption +0x8000001F, 0, EAX, 1, sev, Secure Encrypted Virtualization +0x8000001F, 0, EAX, 2, vmpgflush, VM Page Flush MSR +0x8000001F, 0, EAX, 3, seves, SEV Encrypted State +0x8000001F, 0, EBX, 5:0, c-bit, Page table bit number used to enable memory encryption +0x8000001F, 0, EBX, 11:6, mem_encrypt_physaddr_width, Reduction of physical address space in bits with SME enabled +0x8000001F, 0, ECX, 31:0, num_encrypted_guests, Maximum ASID value that may be used for an SEV-enabled guest +0x8000001F, 0, EDX, 31:0, minimum_sev_asid, Minimum ASID value that must be used for an SEV-enabled, SEV-ES-disabled guest diff --git a/tools/arch/x86/kcpuid/kcpuid.c b/tools/arch/x86/kcpuid/kcpuid.c new file mode 100644 index 0000000000000000000000000000000000000000..dae75511fef71fdc0871b4729c33c2fc7db29aa6 --- /dev/null +++ b/tools/arch/x86/kcpuid/kcpuid.c @@ -0,0 +1,657 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +typedef unsigned int u32; +typedef unsigned long long u64; + +char *def_csv = "/usr/share/misc/cpuid.csv"; +char *user_csv; + + +/* Cover both single-bit flag and multiple-bits fields */ +struct bits_desc { + /* start and end bits */ + int start, end; + /* 0 or 1 for 1-bit flag */ + int value; + char simp[32]; + char detail[256]; +}; + +/* descriptor info for eax/ebx/ecx/edx */ +struct reg_desc { + /* number of valid entries */ + int nr; + struct bits_desc descs[32]; +}; + +enum { + R_EAX = 0, + R_EBX, + R_ECX, + R_EDX, + NR_REGS +}; + +struct subleaf { + u32 index; + u32 sub; + u32 eax, ebx, ecx, edx; + struct reg_desc info[NR_REGS]; +}; + +/* Represent one leaf (basic or extended) */ +struct cpuid_func { + /* + * Array of subleafs for this func, if there is no subleafs + * then the leafs[0] is the main leaf + */ + struct subleaf *leafs; + int nr; +}; + +struct cpuid_range { + /* array of main leafs */ + struct cpuid_func *funcs; + /* number of valid leafs */ + int nr; + bool is_ext; +}; + +/* + * basic: basic functions range: [0... ] + * ext: extended functions range: [0x80000000... ] + */ +struct cpuid_range *leafs_basic, *leafs_ext; + +static int num_leafs; +static bool is_amd; +static bool show_details; +static bool show_raw; +static bool show_flags_only = true; +static u32 user_index = 0xFFFFFFFF; +static u32 user_sub = 0xFFFFFFFF; +static int flines; + +static inline void cpuid(u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +static inline bool has_subleafs(u32 f) +{ + if (f == 0x7 || f == 0xd) + return true; + + if (is_amd) { + if (f == 0x8000001d) + return true; + return false; + } + + switch (f) { + case 0x4: + case 0xb: + case 0xf: + case 0x10: + case 0x14: + case 0x18: + case 0x1f: + return true; + default: + return false; + } +} + +static void leaf_print_raw(struct subleaf *leaf) +{ + if (has_subleafs(leaf->index)) { + if (leaf->sub == 0) + printf("0x%08x: subleafs:\n", leaf->index); + + printf(" %2d: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n", + leaf->sub, leaf->eax, leaf->ebx, leaf->ecx, leaf->edx); + } else { + printf("0x%08x: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n", + leaf->index, leaf->eax, leaf->ebx, leaf->ecx, leaf->edx); + } +} + +/* Return true is the input eax/ebx/ecx/edx are all zero */ +static bool cpuid_store(struct cpuid_range *range, u32 f, int subleaf, + u32 a, u32 b, u32 c, u32 d) +{ + struct cpuid_func *func; + struct subleaf *leaf; + int s = 0; + + if (a == 0 && b == 0 && c == 0 && d == 0) + return true; + + /* + * Cut off vendor-prefix from CPUID function as we're using it as an + * index into ->funcs. + */ + func = &range->funcs[f & 0xffff]; + + if (!func->leafs) { + func->leafs = malloc(sizeof(struct subleaf)); + if (!func->leafs) + perror("malloc func leaf"); + + func->nr = 1; + } else { + s = func->nr; + func->leafs = realloc(func->leafs, (s + 1) * sizeof(*leaf)); + if (!func->leafs) + perror("realloc f->leafs"); + + func->nr++; + } + + leaf = &func->leafs[s]; + + leaf->index = f; + leaf->sub = subleaf; + leaf->eax = a; + leaf->ebx = b; + leaf->ecx = c; + leaf->edx = d; + + return false; +} + +static void raw_dump_range(struct cpuid_range *range) +{ + u32 f; + int i; + + printf("%s Leafs :\n", range->is_ext ? "Extended" : "Basic"); + printf("================\n"); + + for (f = 0; (int)f < range->nr; f++) { + struct cpuid_func *func = &range->funcs[f]; + u32 index = f; + + if (range->is_ext) + index += 0x80000000; + + /* Skip leaf without valid items */ + if (!func->nr) + continue; + + /* First item is the main leaf, followed by all subleafs */ + for (i = 0; i < func->nr; i++) + leaf_print_raw(&func->leafs[i]); + } +} + +#define MAX_SUBLEAF_NUM 32 +struct cpuid_range *setup_cpuid_range(u32 input_eax) +{ + u32 max_func, idx_func; + int subleaf; + struct cpuid_range *range; + u32 eax, ebx, ecx, edx; + u32 f = input_eax; + int max_subleaf; + bool allzero; + + eax = input_eax; + ebx = ecx = edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + max_func = eax; + idx_func = (max_func & 0xffff) + 1; + + range = malloc(sizeof(struct cpuid_range)); + if (!range) + perror("malloc range"); + + if (input_eax & 0x80000000) + range->is_ext = true; + else + range->is_ext = false; + + range->funcs = malloc(sizeof(struct cpuid_func) * idx_func); + if (!range->funcs) + perror("malloc range->funcs"); + + range->nr = idx_func; + memset(range->funcs, 0, sizeof(struct cpuid_func) * idx_func); + + for (; f <= max_func; f++) { + eax = f; + subleaf = ecx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + allzero = cpuid_store(range, f, subleaf, eax, ebx, ecx, edx); + if (allzero) + continue; + num_leafs++; + + if (!has_subleafs(f)) + continue; + + max_subleaf = MAX_SUBLEAF_NUM; + + /* + * Some can provide the exact number of subleafs, + * others have to be tried (0xf) + */ + if (f == 0x7 || f == 0x14 || f == 0x17 || f == 0x18) + max_subleaf = (eax & 0xff) + 1; + + if (f == 0xb) + max_subleaf = 2; + + for (subleaf = 1; subleaf < max_subleaf; subleaf++) { + eax = f; + ecx = subleaf; + + cpuid(&eax, &ebx, &ecx, &edx); + allzero = cpuid_store(range, f, subleaf, + eax, ebx, ecx, edx); + if (allzero) + continue; + num_leafs++; + } + + } + + return range; +} + +/* + * The basic row format for cpuid.csv is + * LEAF,SUBLEAF,register_name,bits,short name,long description + * + * like: + * 0, 0, EAX, 31:0, max_basic_leafs, Max input value for supported subleafs + * 1, 0, ECX, 0, sse3, Streaming SIMD Extensions 3(SSE3) + */ +static int parse_line(char *line) +{ + char *str; + int i; + struct cpuid_range *range; + struct cpuid_func *func; + struct subleaf *leaf; + u32 index; + u32 sub; + char buffer[512]; + char *buf; + /* + * Tokens: + * 1. leaf + * 2. subleaf + * 3. register + * 4. bits + * 5. short name + * 6. long detail + */ + char *tokens[6]; + struct reg_desc *reg; + struct bits_desc *bdesc; + int reg_index; + char *start, *end; + + /* Skip comments and NULL line */ + if (line[0] == '#' || line[0] == '\n') + return 0; + + strncpy(buffer, line, 511); + buffer[511] = 0; + str = buffer; + for (i = 0; i < 5; i++) { + tokens[i] = strtok(str, ","); + if (!tokens[i]) + goto err_exit; + str = NULL; + } + tokens[5] = strtok(str, "\n"); + if (!tokens[5]) + goto err_exit; + + /* index/main-leaf */ + index = strtoull(tokens[0], NULL, 0); + + if (index & 0x80000000) + range = leafs_ext; + else + range = leafs_basic; + + index &= 0x7FFFFFFF; + /* Skip line parsing for non-existing indexes */ + if ((int)index >= range->nr) + return -1; + + func = &range->funcs[index]; + + /* Return if the index has no valid item on this platform */ + if (!func->nr) + return 0; + + /* subleaf */ + sub = strtoul(tokens[1], NULL, 0); + if ((int)sub > func->nr) + return -1; + + leaf = &func->leafs[sub]; + buf = tokens[2]; + + if (strcasestr(buf, "EAX")) + reg_index = R_EAX; + else if (strcasestr(buf, "EBX")) + reg_index = R_EBX; + else if (strcasestr(buf, "ECX")) + reg_index = R_ECX; + else if (strcasestr(buf, "EDX")) + reg_index = R_EDX; + else + goto err_exit; + + reg = &leaf->info[reg_index]; + bdesc = ®->descs[reg->nr++]; + + /* bit flag or bits field */ + buf = tokens[3]; + + end = strtok(buf, ":"); + bdesc->end = strtoul(end, NULL, 0); + bdesc->start = bdesc->end; + + /* start != NULL means it is bit fields */ + start = strtok(NULL, ":"); + if (start) + bdesc->start = strtoul(start, NULL, 0); + + strcpy(bdesc->simp, tokens[4]); + strcpy(bdesc->detail, tokens[5]); + return 0; + +err_exit: + printf("Warning: wrong line format:\n"); + printf("\tline[%d]: %s\n", flines, line); + return -1; +} + +/* Parse csv file, and construct the array of all leafs and subleafs */ +static void parse_text(void) +{ + FILE *file; + char *filename, *line = NULL; + size_t len = 0; + int ret; + + if (show_raw) + return; + + filename = user_csv ? user_csv : def_csv; + file = fopen(filename, "r"); + if (!file) { + /* Fallback to a csv in the same dir */ + file = fopen("./cpuid.csv", "r"); + } + + if (!file) { + printf("Fail to open '%s'\n", filename); + return; + } + + while (1) { + ret = getline(&line, &len, file); + flines++; + if (ret > 0) + parse_line(line); + + if (feof(file)) + break; + } + + fclose(file); +} + + +/* Decode every eax/ebx/ecx/edx */ +static void decode_bits(u32 value, struct reg_desc *rdesc) +{ + struct bits_desc *bdesc; + int start, end, i; + u32 mask; + + for (i = 0; i < rdesc->nr; i++) { + bdesc = &rdesc->descs[i]; + + start = bdesc->start; + end = bdesc->end; + if (start == end) { + /* single bit flag */ + if (value & (1 << start)) + printf("\t%-20s %s%s\n", + bdesc->simp, + show_details ? "-" : "", + show_details ? bdesc->detail : "" + ); + } else { + /* bit fields */ + if (show_flags_only) + continue; + + mask = ((u64)1 << (end - start + 1)) - 1; + printf("\t%-20s\t: 0x%-8x\t%s%s\n", + bdesc->simp, + (value >> start) & mask, + show_details ? "-" : "", + show_details ? bdesc->detail : "" + ); + } + } +} + +static void show_leaf(struct subleaf *leaf) +{ + if (!leaf) + return; + + if (show_raw) + leaf_print_raw(leaf); + + decode_bits(leaf->eax, &leaf->info[R_EAX]); + decode_bits(leaf->ebx, &leaf->info[R_EBX]); + decode_bits(leaf->ecx, &leaf->info[R_ECX]); + decode_bits(leaf->edx, &leaf->info[R_EDX]); +} + +static void show_func(struct cpuid_func *func) +{ + int i; + + if (!func) + return; + + for (i = 0; i < func->nr; i++) + show_leaf(&func->leafs[i]); +} + +static void show_range(struct cpuid_range *range) +{ + int i; + + for (i = 0; i < range->nr; i++) + show_func(&range->funcs[i]); +} + +static inline struct cpuid_func *index_to_func(u32 index) +{ + struct cpuid_range *range; + + range = (index & 0x80000000) ? leafs_ext : leafs_basic; + index &= 0x7FFFFFFF; + + if (((index & 0xFFFF) + 1) > (u32)range->nr) { + printf("ERR: invalid input index (0x%x)\n", index); + return NULL; + } + return &range->funcs[index]; +} + +static void show_info(void) +{ + struct cpuid_func *func; + + if (show_raw) { + /* Show all of the raw output of 'cpuid' instr */ + raw_dump_range(leafs_basic); + raw_dump_range(leafs_ext); + return; + } + + if (user_index != 0xFFFFFFFF) { + /* Only show specific leaf/subleaf info */ + func = index_to_func(user_index); + if (!func) + return; + + /* Dump the raw data also */ + show_raw = true; + + if (user_sub != 0xFFFFFFFF) { + if (user_sub + 1 <= (u32)func->nr) { + show_leaf(&func->leafs[user_sub]); + return; + } + + printf("ERR: invalid input subleaf (0x%x)\n", user_sub); + } + + show_func(func); + return; + } + + printf("CPU features:\n=============\n\n"); + show_range(leafs_basic); + show_range(leafs_ext); +} + +static void setup_platform_cpuid(void) +{ + u32 eax, ebx, ecx, edx; + + /* Check vendor */ + eax = ebx = ecx = edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + + /* "htuA" */ + if (ebx == 0x68747541) + is_amd = true; + + /* Setup leafs for the basic and extended range */ + leafs_basic = setup_cpuid_range(0x0); + leafs_ext = setup_cpuid_range(0x80000000); +} + +static void usage(void) +{ + printf("kcpuid [-abdfhr] [-l leaf] [-s subleaf]\n" + "\t-a|--all Show both bit flags and complex bit fields info\n" + "\t-b|--bitflags Show boolean flags only\n" + "\t-d|--detail Show details of the flag/fields (default)\n" + "\t-f|--flags Specify the cpuid csv file\n" + "\t-h|--help Show usage info\n" + "\t-l|--leaf=index Specify the leaf you want to check\n" + "\t-r|--raw Show raw cpuid data\n" + "\t-s|--subleaf=sub Specify the subleaf you want to check\n" + ); +} + +static struct option opts[] = { + { "all", no_argument, NULL, 'a' }, /* show both bit flags and fields */ + { "bitflags", no_argument, NULL, 'b' }, /* only show bit flags, default on */ + { "detail", no_argument, NULL, 'd' }, /* show detail descriptions */ + { "file", required_argument, NULL, 'f' }, /* use user's cpuid file */ + { "help", no_argument, NULL, 'h'}, /* show usage */ + { "leaf", required_argument, NULL, 'l'}, /* only check a specific leaf */ + { "raw", no_argument, NULL, 'r'}, /* show raw CPUID leaf data */ + { "subleaf", required_argument, NULL, 's'}, /* check a specific subleaf */ + { NULL, 0, NULL, 0 } +}; + +static int parse_options(int argc, char *argv[]) +{ + int c; + + while ((c = getopt_long(argc, argv, "abdf:hl:rs:", + opts, NULL)) != -1) + switch (c) { + case 'a': + show_flags_only = false; + break; + case 'b': + show_flags_only = true; + break; + case 'd': + show_details = true; + break; + case 'f': + user_csv = optarg; + break; + case 'h': + usage(); + exit(1); + break; + case 'l': + /* main leaf */ + user_index = strtoul(optarg, NULL, 0); + break; + case 'r': + show_raw = true; + break; + case 's': + /* subleaf */ + user_sub = strtoul(optarg, NULL, 0); + break; + default: + printf("%s: Invalid option '%c'\n", argv[0], optopt); + return -1; + } + + return 0; +} + +/* + * Do 4 things in turn: + * 1. Parse user options + * 2. Parse and store all the CPUID leaf data supported on this platform + * 2. Parse the csv file, while skipping leafs which are not available + * on this platform + * 3. Print leafs info based on user options + */ +int main(int argc, char *argv[]) +{ + if (parse_options(argc, argv)) + return -1; + + /* Setup the cpuid leafs of current platform */ + setup_platform_cpuid(); + + /* Read and parse the 'cpuid.csv' */ + parse_text(); + + show_info(); + return 0; +} diff --git a/tools/debugging/kernel-chktaint b/tools/debugging/kernel-chktaint index 607b2b280945bc4de744bf70e90fba6f70cafa8d..719f18b1edf0db06b3a9aeaa8800fc79b5a09748 100755 --- a/tools/debugging/kernel-chktaint +++ b/tools/debugging/kernel-chktaint @@ -25,7 +25,7 @@ if [ "$1"x != "x" ]; then elif [ $1 -ge 0 ] 2>/dev/null ; then taint=$1 else - echo "Error: Parameter '$1' not a positive interger. Aborting." >&2 + echo "Error: Parameter '$1' not a positive integer. Aborting." >&2 exit 1 fi else diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 3de763d9ab702134c572a049571179cab6e6fab8..5d12ac4e7f8fe236e20e1e881572263f8792d9e2 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -27,6 +27,7 @@ include $(srctree)/tools/build/Makefile.include # $(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio mkdir -p $(OUTPUT)include/linux/iio 2>&1 || true + ln -sf $(CURDIR)/../../include/uapi/linux/iio/buffer.h $@ ln -sf $(CURDIR)/../../include/uapi/linux/iio/events.h $@ ln -sf $(CURDIR)/../../include/uapi/linux/iio/types.h $@ diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index bb03859db89d84680121997f1bb0f095b67fc32d..0076437f6e3fec5eab4306473143272fe1373778 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -14,6 +14,7 @@ #include <unistd.h> #include <stdlib.h> +#include <dirent.h> #include <stdbool.h> #include <stdio.h> #include <errno.h> @@ -280,22 +281,69 @@ static void print_event(struct iio_event_data *event) printf("\n"); } +/* Enable or disable events in sysfs if the knob is available */ +static void enable_events(char *dev_dir, int enable) +{ + const struct dirent *ent; + char evdir[256]; + int ret; + DIR *dp; + + snprintf(evdir, sizeof(evdir), FORMAT_EVENTS_DIR, dev_dir); + evdir[sizeof(evdir)-1] = '\0'; + + dp = opendir(evdir); + if (!dp) { + fprintf(stderr, "Enabling/disabling events: can't open %s\n", + evdir); + return; + } + + while (ent = readdir(dp), ent) { + if (iioutils_check_suffix(ent->d_name, "_en")) { + printf("%sabling: %s\n", + enable ? "En" : "Dis", + ent->d_name); + ret = write_sysfs_int(ent->d_name, evdir, + enable); + if (ret < 0) + fprintf(stderr, "Failed to enable/disable %s\n", + ent->d_name); + } + } + + if (closedir(dp) == -1) { + perror("Enabling/disabling channels: " + "Failed to close directory"); + return; + } +} + int main(int argc, char **argv) { struct iio_event_data event; const char *device_name; + char *dev_dir_name = NULL; char *chrdev_name; int ret; int dev_num; int fd, event_fd; - - if (argc <= 1) { - fprintf(stderr, "Usage: %s <device_name>\n", argv[0]); + bool all_events = false; + + if (argc == 2) { + device_name = argv[1]; + } else if (argc == 3) { + device_name = argv[2]; + if (!strcmp(argv[1], "-a")) + all_events = true; + } else { + fprintf(stderr, + "Usage: iio_event_monitor [options] <device_name>\n" + "Listen and display events from IIO devices\n" + " -a Auto-activate all available events\n"); return -1; } - device_name = argv[1]; - dev_num = find_type_by_name(device_name, "iio:device"); if (dev_num >= 0) { printf("Found IIO device with name %s with device number %d\n", @@ -303,6 +351,10 @@ int main(int argc, char **argv) ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); if (ret < 0) return -ENOMEM; + /* Look up sysfs dir as well if we can */ + ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); + if (ret < 0) + return -ENOMEM; } else { /* * If we can't find an IIO device by name assume device_name is @@ -313,6 +365,9 @@ int main(int argc, char **argv) return -ENOMEM; } + if (all_events && dev_dir_name) + enable_events(dev_dir_name, 1); + fd = open(chrdev_name, 0); if (fd == -1) { ret = -errno; @@ -365,6 +420,10 @@ int main(int argc, char **argv) perror("Failed to close event file"); error_free_chrdev_name: + /* Disable events after use */ + if (all_events && dev_dir_name) + enable_events(dev_dir_name, 0); + free(chrdev_name); return ret; diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 34d63bcebcd289976fe1d8c7dcfe075a433a0c6f..2491c54a5e4fb5b7ed275586a68a7274aa5cf6cc 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -30,6 +30,8 @@ #include <inttypes.h> #include <stdbool.h> #include <signal.h> +#include <sys/ioctl.h> +#include <linux/iio/buffer.h> #include "iio_utils.h" /** @@ -49,7 +51,7 @@ enum autochan { * Has the side effect of filling the channels[i].location values used * in processing the buffer output. **/ -int size_from_channelarray(struct iio_channel_info *channels, int num_channels) +static int size_from_channelarray(struct iio_channel_info *channels, int num_channels) { int bytes = 0; int i = 0; @@ -68,7 +70,7 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels) return bytes; } -void print1byte(uint8_t input, struct iio_channel_info *info) +static void print1byte(uint8_t input, struct iio_channel_info *info) { /* * Shift before conversion to avoid sign extension @@ -85,7 +87,7 @@ void print1byte(uint8_t input, struct iio_channel_info *info) } } -void print2byte(uint16_t input, struct iio_channel_info *info) +static void print2byte(uint16_t input, struct iio_channel_info *info) { /* First swap if incorrect endian */ if (info->be) @@ -108,7 +110,7 @@ void print2byte(uint16_t input, struct iio_channel_info *info) } } -void print4byte(uint32_t input, struct iio_channel_info *info) +static void print4byte(uint32_t input, struct iio_channel_info *info) { /* First swap if incorrect endian */ if (info->be) @@ -131,7 +133,7 @@ void print4byte(uint32_t input, struct iio_channel_info *info) } } -void print8byte(uint64_t input, struct iio_channel_info *info) +static void print8byte(uint64_t input, struct iio_channel_info *info) { /* First swap if incorrect endian */ if (info->be) @@ -167,9 +169,8 @@ void print8byte(uint64_t input, struct iio_channel_info *info) * to fill the location offsets. * @num_channels: number of channels **/ -void process_scan(char *data, - struct iio_channel_info *channels, - int num_channels) +static void process_scan(char *data, struct iio_channel_info *channels, + int num_channels) { int k; @@ -198,7 +199,7 @@ void process_scan(char *data, printf("\n"); } -static int enable_disable_all_channels(char *dev_dir_name, int enable) +static int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable) { const struct dirent *ent; char scanelemdir[256]; @@ -206,7 +207,7 @@ static int enable_disable_all_channels(char *dev_dir_name, int enable) int ret; snprintf(scanelemdir, sizeof(scanelemdir), - FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); + FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx); scanelemdir[sizeof(scanelemdir)-1] = '\0'; dp = opendir(scanelemdir); @@ -238,12 +239,13 @@ static int enable_disable_all_channels(char *dev_dir_name, int enable) return 0; } -void print_usage(void) +static void print_usage(void) { fprintf(stderr, "Usage: generic_buffer [options]...\n" "Capture, convert and output data from IIO device buffer\n" " -a Auto-activate all available channels\n" " -A Force-activate ALL channels\n" + " -b <n> The buffer which to open (by index), default 0\n" " -c <n> Do n conversions, or loop forever if n < 0\n" " -e Disable wait for event (new data)\n" " -g Use trigger-less mode\n" @@ -257,12 +259,13 @@ void print_usage(void) " -w <n> Set delay between reads in us (event-less mode)\n"); } -enum autochan autochannels = AUTOCHANNELS_DISABLED; -char *dev_dir_name = NULL; -char *buf_dir_name = NULL; -bool current_trigger_set = false; +static enum autochan autochannels = AUTOCHANNELS_DISABLED; +static char *dev_dir_name = NULL; +static char *buf_dir_name = NULL; +static int buffer_idx = 0; +static bool current_trigger_set = false; -void cleanup(void) +static void cleanup(void) { int ret; @@ -287,21 +290,21 @@ void cleanup(void) /* Disable channels if auto-enabled */ if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { - ret = enable_disable_all_channels(dev_dir_name, 0); + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0); if (ret) fprintf(stderr, "Failed to disable all channels\n"); autochannels = AUTOCHANNELS_DISABLED; } } -void sig_handler(int signum) +static void sig_handler(int signum) { fprintf(stderr, "Caught signal %d\n", signum); cleanup(); exit(-signum); } -void register_cleanup(void) +static void register_cleanup(void) { struct sigaction sa = { .sa_handler = sig_handler }; const int signums[] = { SIGINT, SIGTERM, SIGABRT }; @@ -334,7 +337,9 @@ int main(int argc, char **argv) unsigned long long j; unsigned long toread; int ret, c; - int fp = -1; + struct stat st; + int fd = -1; + int buf_fd = -1; int num_channels = 0; char *trigger_name = NULL, *device_name = NULL; @@ -353,7 +358,7 @@ int main(int argc, char **argv) register_cleanup(); - while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, + while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts, NULL)) != -1) { switch (c) { case 'a': @@ -362,7 +367,20 @@ int main(int argc, char **argv) case 'A': autochannels = AUTOCHANNELS_ENABLED; force_autochannels = true; - break; + break; + case 'b': + errno = 0; + buffer_idx = strtoll(optarg, &dummy, 10); + if (errno) { + ret = -errno; + goto error; + } + if (buffer_idx < 0) { + ret = -ERANGE; + goto error; + } + + break; case 'c': errno = 0; num_loops = strtoll(optarg, &dummy, 10); @@ -519,7 +537,7 @@ int main(int argc, char **argv) * Parse the files in scan_elements to identify what channels are * present */ - ret = build_channel_array(dev_dir_name, &channels, &num_channels); + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); if (ret) { fprintf(stderr, "Problem reading scan element information\n" "diag %s\n", dev_dir_name); @@ -536,7 +554,7 @@ int main(int argc, char **argv) (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { fprintf(stderr, "Enabling all channels\n"); - ret = enable_disable_all_channels(dev_dir_name, 1); + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1); if (ret) { fprintf(stderr, "Failed to enable all channels\n"); goto error; @@ -545,7 +563,7 @@ int main(int argc, char **argv) /* This flags that we need to disable the channels again */ autochannels = AUTOCHANNELS_ACTIVE; - ret = build_channel_array(dev_dir_name, &channels, + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); if (ret) { fprintf(stderr, "Problem reading scan element " @@ -566,7 +584,7 @@ int main(int argc, char **argv) fprintf(stderr, "Enable channels manually in " FORMAT_SCAN_ELEMENTS_DIR "/*_en or pass -a to autoenable channels and " - "try again.\n", dev_dir_name); + "try again.\n", dev_dir_name, buffer_idx); ret = -ENOENT; goto error; } @@ -577,12 +595,25 @@ int main(int argc, char **argv) * be built rather than found. */ ret = asprintf(&buf_dir_name, - "%siio:device%d/buffer", iio_dir, dev_num); + "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx); if (ret < 0) { ret = -ENOMEM; goto error; } + if (stat(buf_dir_name, &st)) { + fprintf(stderr, "Could not stat() '%s', got error %d: %s\n", + buf_dir_name, errno, strerror(errno)); + ret = -errno; + goto error; + } + + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name); + ret = -EFAULT; + goto error; + } + if (!notrigger) { printf("%s %s\n", dev_dir_name, trigger_name); /* @@ -599,6 +630,35 @@ int main(int argc, char **argv) } } + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error; + } + + /* Attempt to open non blocking the access dev */ + fd = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fd == -1) { /* TODO: If it isn't there make the node */ + ret = -errno; + fprintf(stderr, "Failed to open %s\n", buffer_access); + goto error; + } + + /* specify for which buffer index we want an FD */ + buf_fd = buffer_idx; + + ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd); + if (ret == -1 || buf_fd == -1) { + ret = -errno; + if (ret == -ENODEV || ret == -EINVAL) + fprintf(stderr, + "Device does not have this many buffers\n"); + else + fprintf(stderr, "Failed to retrieve buffer fd\n"); + + goto error; + } + /* Setup ring buffer parameters */ ret = write_sysfs_int("length", buf_dir_name, buf_len); if (ret < 0) @@ -608,7 +668,8 @@ int main(int argc, char **argv) ret = write_sysfs_int("enable", buf_dir_name, 1); if (ret < 0) { fprintf(stderr, - "Failed to enable buffer: %s\n", strerror(-ret)); + "Failed to enable buffer '%s': %s\n", + buf_dir_name, strerror(-ret)); goto error; } @@ -619,24 +680,30 @@ int main(int argc, char **argv) goto error; } - ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error; + /** + * This check is being done here for sanity reasons, however it + * should be omitted under normal operation. + * If this is buffer0, we check that we get EBUSY after this point. + */ + if (buffer_idx == 0) { + errno = 0; + read_size = read(fd, data, 1); + if (read_size > -1 || errno != EBUSY) { + ret = -EFAULT; + perror("Reading from '%s' should not be possible after ioctl()"); + goto error; + } } - /* Attempt to open non blocking the access dev */ - fp = open(buffer_access, O_RDONLY | O_NONBLOCK); - if (fp == -1) { /* TODO: If it isn't there make the node */ - ret = -errno; - fprintf(stderr, "Failed to open %s\n", buffer_access); - goto error; - } + /* close now the main chardev FD and let the buffer FD work */ + if (close(fd) == -1) + perror("Failed to close character device file"); + fd = -1; for (j = 0; j < num_loops || num_loops < 0; j++) { if (!noevents) { struct pollfd pfd = { - .fd = fp, + .fd = buf_fd, .events = POLLIN, }; @@ -654,7 +721,7 @@ int main(int argc, char **argv) toread = 64; } - read_size = read(fp, data, toread * scan_size); + read_size = read(buf_fd, data, toread * scan_size); if (read_size < 0) { if (errno == EAGAIN) { fprintf(stderr, "nothing available\n"); @@ -671,7 +738,9 @@ int main(int argc, char **argv) error: cleanup(); - if (fp >= 0 && close(fp) == -1) + if (fd >= 0 && close(fd) == -1) + perror("Failed to close character device"); + if (buf_fd >= 0 && close(buf_fd) == -1) perror("Failed to close buffer"); free(buffer_access); free(data); diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 7399eb7f13786f9d2e45d4fb9eef5e6123285ca4..aadee6d34c74c112f84be5977f23135e34ee0d20 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -77,15 +77,17 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) * @mask: output a bit mask for the raw data * @be: output if data in big endian * @device_dir: the IIO device directory + * @buffer_idx: the IIO buffer index * @name: the channel name * @generic_name: the channel type name * * Returns a value >= 0 on success, otherwise a negative error code. **/ -int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, - unsigned *shift, uint64_t *mask, unsigned *be, - const char *device_dir, const char *name, - const char *generic_name) +static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, + unsigned int *bits_used, unsigned int *shift, + uint64_t *mask, unsigned int *be, + const char *device_dir, int buffer_idx, + const char *name, const char *generic_name) { FILE *sysfsfp; int ret; @@ -95,7 +97,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, unsigned padint; const struct dirent *ent; - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); if (ret < 0) return -ENOMEM; @@ -303,12 +305,13 @@ void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) /** * build_channel_array() - function to figure out what channels are present * @device_dir: the IIO device directory in sysfs + * @buffer_idx: the IIO buffer for this channel array * @ci_array: output the resulting array of iio_channel_info * @counter: output the amount of array elements * * Returns 0 on success, otherwise a negative error code. **/ -int build_channel_array(const char *device_dir, +int build_channel_array(const char *device_dir, int buffer_idx, struct iio_channel_info **ci_array, int *counter) { DIR *dp; @@ -321,7 +324,7 @@ int build_channel_array(const char *device_dir, char *filename; *counter = 0; - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); if (ret < 0) return -ENOMEM; @@ -502,6 +505,7 @@ int build_channel_array(const char *device_dir, ¤t->mask, ¤t->be, device_dir, + buffer_idx, current->name, current->generic_name); if (ret < 0) diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index 74bde4fde2c80ed013979d681b7f3d02abe5ed07..663c94a6c7058fda52ce951753fc5e8c8257993c 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h @@ -12,7 +12,8 @@ /* Made up value to limit allocation sizes */ #define IIO_MAX_NAME_LENGTH 64 -#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" +#define FORMAT_SCAN_ELEMENTS_DIR "%s/buffer%d" +#define FORMAT_EVENTS_DIR "%s/events" #define FORMAT_TYPE_FILE "%s_type" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) @@ -57,15 +58,11 @@ static inline int iioutils_check_suffix(const char *str, const char *suffix) } int iioutils_break_up_name(const char *full_name, char **generic_name); -int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, - unsigned *shift, uint64_t *mask, unsigned *be, - const char *device_dir, const char *name, - const char *generic_name); int iioutils_get_param_float(float *output, const char *param_name, const char *device_dir, const char *name, const char *generic_name); void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); -int build_channel_array(const char *device_dir, +int build_channel_array(const char *device_dir, int buffer_idx, struct iio_channel_info **ci_array, int *counter); int find_type_by_name(const char *name, const char *type); int write_sysfs_int(const char *filename, const char *basedir, int val); diff --git a/tools/include/linux/static_call_types.h b/tools/include/linux/static_call_types.h index ae5662d368b98f7bceb3d065e2e832507b32f671..5a00b8b2cf9fcceb1fa247a4da5fe2f330f378ce 100644 --- a/tools/include/linux/static_call_types.h +++ b/tools/include/linux/static_call_types.h @@ -58,11 +58,25 @@ struct static_call_site { __raw_static_call(name); \ }) +struct static_call_key { + void *func; + union { + /* bit 0: 0 = mods, 1 = sites */ + unsigned long type; + struct static_call_mod *mods; + struct static_call_site *sites; + }; +}; + #else /* !CONFIG_HAVE_STATIC_CALL_INLINE */ #define __STATIC_CALL_ADDRESSABLE(name) #define __static_call(name) __raw_static_call(name) +struct static_call_key { + void *func; +}; + #endif /* CONFIG_HAVE_STATIC_CALL_INLINE */ #ifdef MODULE @@ -77,6 +91,10 @@ struct static_call_site { #else +struct static_call_key { + void *func; +}; + #define static_call(name) \ ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func)) diff --git a/tools/perf/trace/beauty/tracepoints/x86_msr.sh b/tools/perf/trace/beauty/tracepoints/x86_msr.sh index 27ee1ea1fe941fed1ec29703e220b69ee4fecbda..9b0614a87831ba13769dc444e1acc398f34d835c 100755 --- a/tools/perf/trace/beauty/tracepoints/x86_msr.sh +++ b/tools/perf/trace/beauty/tracepoints/x86_msr.sh @@ -15,7 +15,7 @@ x86_msr_index=${arch_x86_header_dir}/msr-index.h printf "static const char *x86_MSRs[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MSR_([[:alnum:]][[:alnum:]_]+)[[:space:]]+(0x00000[[:xdigit:]]+)[[:space:]]*.*' -egrep $regex ${x86_msr_index} | egrep -v 'MSR_(ATOM|P[46]|IA32_(TSCDEADLINE|UCODE_REV)|IDT_FCR4)' | \ +egrep $regex ${x86_msr_index} | egrep -v 'MSR_(ATOM|P[46]|IA32_(TSC_DEADLINE|UCODE_REV)|IDT_FCR4)' | \ sed -r "s/$regex/\2 \1/g" | sort -n | \ xargs printf "\t[%s] = \"%s\",\n" printf "};\n\n" diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c index 9ea2c0aeb86c4ed7ff7cfdf1b0d8bbff61de0188..185b8c588e1d7623d5488b8da4d66b57a6710b91 100644 --- a/tools/power/acpi/common/cmfsize.c +++ b/tools/power/acpi/common/cmfsize.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /****************************************************************************** * - * Module Name: cfsize - Common get file size function + * Module Name: cmfsize - Common get file size function * * Copyright (C) 2000 - 2021, Intel Corp. * diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py index 81f4b8abbdf7f2ea70f9a5e3e1fdd6477bfd0191..ffd50953a024fbb3c856e24c90b12530247a23ea 100755 --- a/tools/power/pm-graph/sleepgraph.py +++ b/tools/power/pm-graph/sleepgraph.py @@ -6819,7 +6819,7 @@ if __name__ == '__main__': sysvals.outdir = val sysvals.notestrun = True if(os.path.isdir(val) == False): - doError('%s is not accesible' % val) + doError('%s is not accessible' % val) elif(arg == '-filter'): try: val = next(args) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 582feb88eca34d0d47baaa1bef749d27c485cef7..ab940c508ef0cbfd6bcbc5856f9ea627f5d898ee 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -15,7 +15,7 @@ struct process_cmd_struct { int arg; }; -static const char *version_str = "v1.8"; +static const char *version_str = "v1.9"; static const int supported_api_ver = 1; static struct isst_if_platform_info isst_platform_info; static char *progname; @@ -381,6 +381,18 @@ static void set_cpu_online_offline(int cpu, int state) close(fd); } +static void force_all_cpus_online(void) +{ + int i; + + fprintf(stderr, "Forcing all CPUs online\n"); + + for (i = 0; i < topo_max_cpus; ++i) + set_cpu_online_offline(i, 1); + + unlink("/var/run/isst_cpu_topology.dat"); +} + #define MAX_PACKAGE_COUNT 8 #define MAX_DIE_PER_PACKAGE 2 static void for_each_online_package_in_set(void (*callback)(int, void *, void *, @@ -959,6 +971,10 @@ static void isst_print_extended_platform_info(void) fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n"); ret = isst_read_pm_config(i, &cp_state, &cp_cap); + if (ret) { + fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n"); + return; + } if (cp_cap) fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n"); else @@ -2763,6 +2779,7 @@ static void usage(void) printf("\t[-f|--format] : output format [json|text]. Default: text\n"); printf("\t[-h|--help] : Print help\n"); printf("\t[-i|--info] : Print platform information\n"); + printf("\t[-a|--all-cpus-online] : Force online every CPU in the system\n"); printf("\t[-o|--out] : Output file\n"); printf("\t\t\tDefault : stderr\n"); printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n"); @@ -2791,7 +2808,6 @@ static void usage(void) static void print_version(void) { fprintf(outf, "Version %s\n", version_str); - fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__); exit(0); } @@ -2800,11 +2816,12 @@ static void cmdline(int argc, char **argv) const char *pathname = "/dev/isst_interface"; char *ptr; FILE *fp; - int opt; + int opt, force_cpus_online = 0; int option_index = 0; int ret; static struct option long_options[] = { + { "all-cpus-online", no_argument, 0, 'a' }, { "cpu", required_argument, 0, 'c' }, { "debug", no_argument, 0, 'd' }, { "format", required_argument, 0, 'f' }, @@ -2840,9 +2857,12 @@ static void cmdline(int argc, char **argv) } progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options, + while ((opt = getopt_long_only(argc, argv, "+c:df:hio:va", long_options, &option_index)) != -1) { switch (opt) { + case 'a': + force_cpus_online = 1; + break; case 'c': parse_cpu_command(optarg); break; @@ -2892,6 +2912,8 @@ static void cmdline(int argc, char **argv) exit(0); } set_max_cpu_num(); + if (force_cpus_online) + force_all_cpus_online(); store_cpu_topology(); set_cpu_present_cpu_mask(); set_cpu_target_cpu_mask(); diff --git a/tools/power/x86/intel-speed-select/isst-display.c b/tools/power/x86/intel-speed-select/isst-display.c index 8e54ce47648e28f0ffc0c297e6fd0e7655f77f71..3bf1820c0da1184a2bcaf6df94c30c8725b6a95a 100644 --- a/tools/power/x86/intel-speed-select/isst-display.c +++ b/tools/power/x86/intel-speed-select/isst-display.c @@ -25,10 +25,14 @@ static void printcpulist(int str_len, char *str, int mask_size, index = snprintf(&str[curr_index], str_len - curr_index, ","); curr_index += index; + if (curr_index >= str_len) + break; } index = snprintf(&str[curr_index], str_len - curr_index, "%d", i); curr_index += index; + if (curr_index >= str_len) + break; first = 0; } } @@ -64,10 +68,14 @@ static void printcpumask(int str_len, char *str, int mask_size, index = snprintf(&str[curr_index], str_len - curr_index, "%08x", mask[i]); curr_index += index; + if (curr_index >= str_len) + break; if (i) { strncat(&str[curr_index], ",", str_len - curr_index); curr_index++; } + if (curr_index >= str_len) + break; } free(mask); @@ -185,7 +193,7 @@ static void _isst_pbf_display_information(int cpu, FILE *outf, int level, int disp_level) { char header[256]; - char value[256]; + char value[512]; snprintf(header, sizeof(header), "speed-select-base-freq-properties"); format_and_print(outf, disp_level, header, NULL); @@ -349,7 +357,7 @@ void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level, struct isst_pkg_ctdp *pkg_dev) { char header[256]; - char value[256]; + char value[512]; static int level; int i; diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index a7c4f0772e5342e2b95af302a633cb37e503bfd3..5939615265f1845c7067d2c17422707e98985fdf 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2449,7 +2449,7 @@ dump_knl_turbo_ratio_limits(void) fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr); - /** + /* * Turbo encoding in KNL is as follows: * [0] -- Reserved * [7:1] -- Base value of number of active cores of bucket 1. diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index a402f32a145c0de38bb3325e7fd33080a5e15b48..84dbf61a7eca469f845c12f2456905d39f4795fd 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -86,7 +86,8 @@ endif # in newer systems. # Needed for the __raw_cmpxchg in tools/arch/x86/include/asm/cmpxchg.h # -# See https://lkml.org/lkml/2006/11/28/253 and https://gcc.gnu.org/gcc-4.8/changes.html, +# See https://lore.kernel.org/lkml/9a8748490611281710g78402fbeh8ff7fcc162dbcbca@mail.gmail.com/ +# and https://gcc.gnu.org/gcc-4.8/changes.html, # that takes into account Linus's comments (search for Wshadow) for the reasoning about # -Wshadow not being interesting before gcc 4.8. diff --git a/tools/spi/Makefile b/tools/spi/Makefile index ada881afb489a595c536401378ff58342bcc4bcf..0aa6dbd31fb8d3c17dd1f4b47b2f3a11ff56bdbc 100644 --- a/tools/spi/Makefile +++ b/tools/spi/Makefile @@ -25,11 +25,12 @@ include $(srctree)/tools/build/Makefile.include # # We need the following to be outside of kernel tree # -$(OUTPUT)include/linux/spi/spidev.h: ../../include/uapi/linux/spi/spidev.h +$(OUTPUT)include/linux/spi: ../../include/uapi/linux/spi mkdir -p $(OUTPUT)include/linux/spi 2>&1 || true ln -sf $(CURDIR)/../../include/uapi/linux/spi/spidev.h $@ + ln -sf $(CURDIR)/../../include/uapi/linux/spi/spi.h $@ -prepare: $(OUTPUT)include/linux/spi/spidev.h +prepare: $(OUTPUT)include/linux/spi # # spidev_test diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile index 2c9d012797a7f1e4acb7d7c090e0b59885846d96..ced910fb40198c38abbd85832f3482c77024c35f 100644 --- a/tools/testing/selftests/arm64/Makefile +++ b/tools/testing/selftests/arm64/Makefile @@ -4,7 +4,7 @@ ARCH ?= $(shell uname -m 2>/dev/null || echo not) ifneq (,$(filter $(ARCH),aarch64 arm64)) -ARM64_SUBTARGETS ?= tags signal pauth fp mte +ARM64_SUBTARGETS ?= tags signal pauth fp mte bti else ARM64_SUBTARGETS := endif diff --git a/tools/testing/selftests/arm64/bti/.gitignore b/tools/testing/selftests/arm64/bti/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..73869fabada426c67fd9a3e29f71db37e02bc5b5 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/.gitignore @@ -0,0 +1,2 @@ +btitest +nobtitest diff --git a/tools/testing/selftests/arm64/bti/Makefile b/tools/testing/selftests/arm64/bti/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..73e013c082a6526d8572d29b05259352036caf52 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/Makefile @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0 + +TEST_GEN_PROGS := btitest nobtitest + +PROGS := $(patsubst %,gen/%,$(TEST_GEN_PROGS)) + +# These tests are built as freestanding binaries since otherwise BTI +# support in ld.so is required which is not currently widespread; when +# it is available it will still be useful to test this separately as the +# cases for statically linked and dynamically lined binaries are +# slightly different. + +CFLAGS_NOBTI = -DBTI=0 +CFLAGS_BTI = -mbranch-protection=standard -DBTI=1 + +CFLAGS_COMMON = -ffreestanding -Wall -Wextra $(CFLAGS) + +BTI_CC_COMMAND = $(CC) $(CFLAGS_BTI) $(CFLAGS_COMMON) -c -o $@ $< +NOBTI_CC_COMMAND = $(CC) $(CFLAGS_NOBTI) $(CFLAGS_COMMON) -c -o $@ $< + +%-bti.o: %.c + $(BTI_CC_COMMAND) + +%-bti.o: %.S + $(BTI_CC_COMMAND) + +%-nobti.o: %.c + $(NOBTI_CC_COMMAND) + +%-nobti.o: %.S + $(NOBTI_CC_COMMAND) + +BTI_OBJS = \ + test-bti.o \ + signal-bti.o \ + start-bti.o \ + syscall-bti.o \ + system-bti.o \ + teststubs-bti.o \ + trampoline-bti.o +gen/btitest: $(BTI_OBJS) + $(CC) $(CFLAGS_BTI) $(CFLAGS_COMMON) -nostdlib -o $@ $^ + +NOBTI_OBJS = \ + test-nobti.o \ + signal-nobti.o \ + start-nobti.o \ + syscall-nobti.o \ + system-nobti.o \ + teststubs-nobti.o \ + trampoline-nobti.o +gen/nobtitest: $(NOBTI_OBJS) + $(CC) $(CFLAGS_BTI) $(CFLAGS_COMMON) -nostdlib -o $@ $^ + +# Including KSFT lib.mk here will also mangle the TEST_GEN_PROGS list +# to account for any OUTPUT target-dirs optionally provided by +# the toplevel makefile +include ../../lib.mk + +$(TEST_GEN_PROGS): $(PROGS) + cp $(PROGS) $(OUTPUT)/ diff --git a/tools/testing/selftests/arm64/bti/assembler.h b/tools/testing/selftests/arm64/bti/assembler.h new file mode 100644 index 0000000000000000000000000000000000000000..04e7b72880ef997b5a9c2db35019994081573f5a --- /dev/null +++ b/tools/testing/selftests/arm64/bti/assembler.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#ifndef ASSEMBLER_H +#define ASSEMBLER_H + +#define NT_GNU_PROPERTY_TYPE_0 5 +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 + +/* Bits for GNU_PROPERTY_AARCH64_FEATURE_1_BTI */ +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0) +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1U << 1) + + +.macro startfn name:req + .globl \name +\name: + .macro endfn + .size \name, . - \name + .type \name, @function + .purgem endfn + .endm +.endm + +.macro emit_aarch64_feature_1_and + .pushsection .note.gnu.property, "a" + .align 3 + .long 2f - 1f + .long 6f - 3f + .long NT_GNU_PROPERTY_TYPE_0 +1: .string "GNU" +2: + .align 3 +3: .long GNU_PROPERTY_AARCH64_FEATURE_1_AND + .long 5f - 4f +4: +#if BTI + .long GNU_PROPERTY_AARCH64_FEATURE_1_PAC | \ + GNU_PROPERTY_AARCH64_FEATURE_1_BTI +#else + .long 0 +#endif +5: + .align 3 +6: + .popsection +.endm + +.macro paciasp + hint 0x19 +.endm + +.macro autiasp + hint 0x1d +.endm + +.macro __bti_ + hint 0x20 +.endm + +.macro __bti_c + hint 0x22 +.endm + +.macro __bti_j + hint 0x24 +.endm + +.macro __bti_jc + hint 0x26 +.endm + +.macro bti what= + __bti_\what +.endm + +#endif /* ! ASSEMBLER_H */ diff --git a/tools/testing/selftests/arm64/bti/btitest.h b/tools/testing/selftests/arm64/bti/btitest.h new file mode 100644 index 0000000000000000000000000000000000000000..2aff9b10336ec3a9030c72b458d51289e43e1ff9 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/btitest.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#ifndef BTITEST_H +#define BTITEST_H + +/* Trampolines for calling the test stubs: */ +void call_using_br_x0(void (*)(void)); +void call_using_br_x16(void (*)(void)); +void call_using_blr(void (*)(void)); + +/* Test stubs: */ +void nohint_func(void); +void bti_none_func(void); +void bti_c_func(void); +void bti_j_func(void); +void bti_jc_func(void); +void paciasp_func(void); + +#endif /* !BTITEST_H */ diff --git a/tools/testing/selftests/arm64/bti/compiler.h b/tools/testing/selftests/arm64/bti/compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..ebb6204f447a097baac56b14d85727d3833007bd --- /dev/null +++ b/tools/testing/selftests/arm64/bti/compiler.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#ifndef COMPILER_H +#define COMPILER_H + +#define __always_unused __attribute__((__unused__)) +#define __noreturn __attribute__((__noreturn__)) +#define __unreachable() __builtin_unreachable() + +/* curse(e) has value e, but the compiler cannot assume so */ +#define curse(e) ({ \ + __typeof__(e) __curse_e = (e); \ + asm ("" : "+r" (__curse_e)); \ + __curse_e; \ +}) + +#endif /* ! COMPILER_H */ diff --git a/tools/testing/selftests/arm64/bti/gen/.gitignore b/tools/testing/selftests/arm64/bti/gen/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..73869fabada426c67fd9a3e29f71db37e02bc5b5 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/gen/.gitignore @@ -0,0 +1,2 @@ +btitest +nobtitest diff --git a/tools/testing/selftests/arm64/bti/signal.c b/tools/testing/selftests/arm64/bti/signal.c new file mode 100644 index 0000000000000000000000000000000000000000..f3fd29b91141cd15a06e98857782bfb9769befb3 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/signal.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "system.h" +#include "signal.h" + +int sigemptyset(sigset_t *s) +{ + unsigned int i; + + for (i = 0; i < _NSIG_WORDS; ++i) + s->sig[i] = 0; + + return 0; +} + +int sigaddset(sigset_t *s, int n) +{ + if (n < 1 || n > _NSIG) + return -EINVAL; + + s->sig[(n - 1) / _NSIG_BPW] |= 1UL << (n - 1) % _NSIG_BPW; + return 0; +} + +int sigaction(int n, struct sigaction *sa, const struct sigaction *old) +{ + return syscall(__NR_rt_sigaction, n, sa, old, sizeof(sa->sa_mask)); +} + +int sigprocmask(int how, const sigset_t *mask, sigset_t *old) +{ + return syscall(__NR_rt_sigprocmask, how, mask, old, sizeof(*mask)); +} diff --git a/tools/testing/selftests/arm64/bti/signal.h b/tools/testing/selftests/arm64/bti/signal.h new file mode 100644 index 0000000000000000000000000000000000000000..103457dc880e3c81ae2f1902784db53b3564e197 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/signal.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#ifndef SIGNAL_H +#define SIGNAL_H + +#include <linux/signal.h> + +#include "system.h" + +typedef __sighandler_t sighandler_t; + +int sigemptyset(sigset_t *s); +int sigaddset(sigset_t *s, int n); +int sigaction(int n, struct sigaction *sa, const struct sigaction *old); +int sigprocmask(int how, const sigset_t *mask, sigset_t *old); + +#endif /* ! SIGNAL_H */ diff --git a/tools/testing/selftests/arm64/bti/start.S b/tools/testing/selftests/arm64/bti/start.S new file mode 100644 index 0000000000000000000000000000000000000000..831f952e05721ae99db1bc741d58f94a333bbc14 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/start.S @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "assembler.h" + +startfn _start + mov x0, sp + b start +endfn + +emit_aarch64_feature_1_and diff --git a/tools/testing/selftests/arm64/bti/syscall.S b/tools/testing/selftests/arm64/bti/syscall.S new file mode 100644 index 0000000000000000000000000000000000000000..8dde8b6f3db115acfd0d245650a332c3ce8f9e54 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/syscall.S @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "assembler.h" + +startfn syscall + bti c + mov w8, w0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + mov x5, x6 + mov x6, x7 + svc #0 + ret +endfn + +emit_aarch64_feature_1_and diff --git a/tools/testing/selftests/arm64/bti/system.c b/tools/testing/selftests/arm64/bti/system.c new file mode 100644 index 0000000000000000000000000000000000000000..6385d8d4973b5d9151d1d4462c8f9838bd7dc209 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/system.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "system.h" + +#include <asm/unistd.h> + +#include "compiler.h" + +void __noreturn exit(int n) +{ + syscall(__NR_exit, n); + __unreachable(); +} + +ssize_t write(int fd, const void *buf, size_t size) +{ + return syscall(__NR_write, fd, buf, size); +} diff --git a/tools/testing/selftests/arm64/bti/system.h b/tools/testing/selftests/arm64/bti/system.h new file mode 100644 index 0000000000000000000000000000000000000000..aca118589705ed3276bf61e79c85dc9ca84b2b7c --- /dev/null +++ b/tools/testing/selftests/arm64/bti/system.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#ifndef SYSTEM_H +#define SYSTEM_H + +#include <linux/types.h> +#include <linux/stddef.h> + +typedef __kernel_size_t size_t; +typedef __kernel_ssize_t ssize_t; + +#include <linux/errno.h> +#include <asm/hwcap.h> +#include <asm/ptrace.h> +#include <asm/unistd.h> + +#include "compiler.h" + +long syscall(int nr, ...); + +void __noreturn exit(int n); +ssize_t write(int fd, const void *buf, size_t size); + +#endif /* ! SYSTEM_H */ diff --git a/tools/testing/selftests/arm64/bti/test.c b/tools/testing/selftests/arm64/bti/test.c new file mode 100644 index 0000000000000000000000000000000000000000..656b04976ccc6389e03dd46f6b344c1217c41137 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/test.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019,2021 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "system.h" + +#include <linux/errno.h> +#include <linux/auxvec.h> +#include <linux/signal.h> +#include <asm/sigcontext.h> +#include <asm/ucontext.h> + +typedef struct ucontext ucontext_t; + +#include "btitest.h" +#include "compiler.h" +#include "signal.h" + +#define EXPECTED_TESTS 18 + +static volatile unsigned int test_num = 1; +static unsigned int test_passed; +static unsigned int test_failed; +static unsigned int test_skipped; + +static void fdputs(int fd, const char *str) +{ + size_t len = 0; + const char *p = str; + + while (*p++) + ++len; + + write(fd, str, len); +} + +static void putstr(const char *str) +{ + fdputs(1, str); +} + +static void putnum(unsigned int num) +{ + char c; + + if (num / 10) + putnum(num / 10); + + c = '0' + (num % 10); + write(1, &c, 1); +} + +#define puttestname(test_name, trampoline_name) do { \ + putstr(test_name); \ + putstr("/"); \ + putstr(trampoline_name); \ +} while (0) + +void print_summary(void) +{ + putstr("# Totals: pass:"); + putnum(test_passed); + putstr(" fail:"); + putnum(test_failed); + putstr(" xfail:0 xpass:0 skip:"); + putnum(test_skipped); + putstr(" error:0\n"); +} + +static const char *volatile current_test_name; +static const char *volatile current_trampoline_name; +static volatile int sigill_expected, sigill_received; + +static void handler(int n, siginfo_t *si __always_unused, + void *uc_ __always_unused) +{ + ucontext_t *uc = uc_; + + putstr("# \t[SIGILL in "); + puttestname(current_test_name, current_trampoline_name); + putstr(", BTYPE="); + write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK) + >> PSR_BTYPE_SHIFT) * 2], 2); + if (!sigill_expected) { + putstr("]\n"); + putstr("not ok "); + putnum(test_num); + putstr(" "); + puttestname(current_test_name, current_trampoline_name); + putstr("(unexpected SIGILL)\n"); + print_summary(); + exit(128 + n); + } + + putstr(" (expected)]\n"); + sigill_received = 1; + /* zap BTYPE so that resuming the faulting code will work */ + uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK; +} + +static int skip_all; + +static void __do_test(void (*trampoline)(void (*)(void)), + void (*fn)(void), + const char *trampoline_name, + const char *name, + int expect_sigill) +{ + if (skip_all) { + test_skipped++; + putstr("ok "); + putnum(test_num); + putstr(" "); + puttestname(name, trampoline_name); + putstr(" # SKIP\n"); + + return; + } + + /* Branch Target exceptions should only happen in BTI binaries: */ + if (!BTI) + expect_sigill = 0; + + sigill_expected = expect_sigill; + sigill_received = 0; + current_test_name = name; + current_trampoline_name = trampoline_name; + + trampoline(fn); + + if (expect_sigill && !sigill_received) { + putstr("not ok "); + test_failed++; + } else { + putstr("ok "); + test_passed++; + } + putnum(test_num++); + putstr(" "); + puttestname(name, trampoline_name); + putstr("\n"); +} + +#define do_test(expect_sigill_br_x0, \ + expect_sigill_br_x16, \ + expect_sigill_blr, \ + name) \ +do { \ + __do_test(call_using_br_x0, name, "call_using_br_x0", #name, \ + expect_sigill_br_x0); \ + __do_test(call_using_br_x16, name, "call_using_br_x16", #name, \ + expect_sigill_br_x16); \ + __do_test(call_using_blr, name, "call_using_blr", #name, \ + expect_sigill_blr); \ +} while (0) + +void start(int *argcp) +{ + struct sigaction sa; + void *const *p; + const struct auxv_entry { + unsigned long type; + unsigned long val; + } *auxv; + unsigned long hwcap = 0, hwcap2 = 0; + + putstr("TAP version 13\n"); + putstr("1.."); + putnum(EXPECTED_TESTS); + putstr("\n"); + + /* Gross hack for finding AT_HWCAP2 from the initial process stack: */ + p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */ + /* step over environment */ + while (*p++) + ; + for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) { + switch (auxv->type) { + case AT_HWCAP: + hwcap = auxv->val; + break; + case AT_HWCAP2: + hwcap2 = auxv->val; + break; + default: + break; + } + } + + if (hwcap & HWCAP_PACA) + putstr("# HWCAP_PACA present\n"); + else + putstr("# HWCAP_PACA not present\n"); + + if (hwcap2 & HWCAP2_BTI) { + putstr("# HWCAP2_BTI present\n"); + if (!(hwcap & HWCAP_PACA)) + putstr("# Bad hardware? Expect problems.\n"); + } else { + putstr("# HWCAP2_BTI not present\n"); + skip_all = 1; + } + + putstr("# Test binary"); + if (!BTI) + putstr(" not"); + putstr(" built for BTI\n"); + + sa.sa_handler = (sighandler_t)(void *)handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGILL, &sa, NULL); + sigaddset(&sa.sa_mask, SIGILL); + sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); + + do_test(1, 1, 1, nohint_func); + do_test(1, 1, 1, bti_none_func); + do_test(1, 0, 0, bti_c_func); + do_test(0, 0, 1, bti_j_func); + do_test(0, 0, 0, bti_jc_func); + do_test(1, 0, 0, paciasp_func); + + print_summary(); + + if (test_num - 1 != EXPECTED_TESTS) + putstr("# WARNING - EXPECTED TEST COUNT WRONG\n"); + + if (test_failed) + exit(1); + else + exit(0); +} diff --git a/tools/testing/selftests/arm64/bti/teststubs.S b/tools/testing/selftests/arm64/bti/teststubs.S new file mode 100644 index 0000000000000000000000000000000000000000..b62c8c35f67e78e2fbe05426bc9ca54924616fc2 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/teststubs.S @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "assembler.h" + +startfn bti_none_func + bti + ret +endfn + +startfn bti_c_func + bti c + ret +endfn + +startfn bti_j_func + bti j + ret +endfn + +startfn bti_jc_func + bti jc + ret +endfn + +startfn paciasp_func + paciasp + autiasp + ret +endfn + +startfn nohint_func + ret +endfn + +emit_aarch64_feature_1_and diff --git a/tools/testing/selftests/arm64/bti/trampoline.S b/tools/testing/selftests/arm64/bti/trampoline.S new file mode 100644 index 0000000000000000000000000000000000000000..09beb3f361f15bfc08f1e43625ed3c9b27105bf4 --- /dev/null +++ b/tools/testing/selftests/arm64/bti/trampoline.S @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Arm Limited + * Original author: Dave Martin <Dave.Martin@arm.com> + */ + +#include "assembler.h" + +startfn call_using_br_x0 + bti c + br x0 +endfn + +startfn call_using_br_x16 + bti c + mov x16, x0 + br x16 +endfn + +startfn call_using_blr + paciasp + stp x29, x30, [sp, #-16]! + blr x0 + ldp x29, x30, [sp], #16 + autiasp + ret +endfn + +emit_aarch64_feature_1_and diff --git a/tools/testing/selftests/arm64/mte/Makefile b/tools/testing/selftests/arm64/mte/Makefile index 0b3af552632a62123bada07b2b508478eb9ac762..409e3e53d00af61d1a11b7018e6afdf706476019 100644 --- a/tools/testing/selftests/arm64/mte/Makefile +++ b/tools/testing/selftests/arm64/mte/Makefile @@ -1,14 +1,18 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2020 ARM Limited -CFLAGS += -std=gnu99 -I. -lpthread +# preserve CC value from top level Makefile +ifeq ($(CC),cc) +CC := $(CROSS_COMPILE)gcc +endif + +CFLAGS += -std=gnu99 -I. -pthread +LDFLAGS += -pthread SRCS := $(filter-out mte_common_util.c,$(wildcard *.c)) PROGS := $(patsubst %.c,%,$(SRCS)) #Add mte compiler option -ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep gcc),) CFLAGS += -march=armv8.5-a+memtag -endif #check if the compiler works well mte_cc_support := $(shell if ($(CC) $(CFLAGS) -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi) @@ -19,11 +23,14 @@ TEST_GEN_PROGS := $(PROGS) # Get Kernel headers installed and use them. KSFT_KHDR_INSTALL := 1 +else + $(warning compiler "$(CC)" does not support the ARMv8.5 MTE extension.) + $(warning test program "mte" will not be created.) endif # Include KSFT lib.mk. include ../../lib.mk ifeq ($(mte_cc_support),1) -$(TEST_GEN_PROGS): mte_common_util.c mte_common_util.h mte_helper.S +$(TEST_GEN_PROGS): mte_common_util.c mte_helper.S endif diff --git a/tools/testing/selftests/arm64/mte/check_ksm_options.c b/tools/testing/selftests/arm64/mte/check_ksm_options.c index 3b23c4d61d38885bd8ee98a2c6f7c1a6748cdb4e..88c74bc46d4fce66d6f5c1ba9cdb386bf0d8c6da 100644 --- a/tools/testing/selftests/arm64/mte/check_ksm_options.c +++ b/tools/testing/selftests/arm64/mte/check_ksm_options.c @@ -33,7 +33,10 @@ static unsigned long read_sysfs(char *str) ksft_print_msg("ERR: missing %s\n", str); return 0; } - fscanf(f, "%lu", &val); + if (fscanf(f, "%lu", &val) != 1) { + ksft_print_msg("ERR: parsing %s\n", str); + val = 0; + } fclose(f); return val; } diff --git a/tools/testing/selftests/arm64/mte/check_user_mem.c b/tools/testing/selftests/arm64/mte/check_user_mem.c index 4bfa80f2a8c3e1743bea5e8867e28e432888e040..1de7a0abd0ae391d3d3c117eca425b437be9b01c 100644 --- a/tools/testing/selftests/arm64/mte/check_user_mem.c +++ b/tools/testing/selftests/arm64/mte/check_user_mem.c @@ -33,7 +33,8 @@ static int check_usermem_access_fault(int mem_type, int mode, int mapping) if (fd == -1) return KSFT_FAIL; for (i = 0; i < len; i++) - write(fd, &val, sizeof(val)); + if (write(fd, &val, sizeof(val)) != sizeof(val)) + return KSFT_FAIL; lseek(fd, 0, 0); ptr = mte_allocate_memory(len, mem_type, mapping, true); if (check_allocated_memory(ptr, len, mem_type, true) != KSFT_PASS) { diff --git a/tools/testing/selftests/arm64/mte/mte_common_util.c b/tools/testing/selftests/arm64/mte/mte_common_util.c index 39f8908988eab0d032382bc551df6bf754691a4f..f50ac31920d134bd904ce09b846ff7f3b0eecf24 100644 --- a/tools/testing/selftests/arm64/mte/mte_common_util.c +++ b/tools/testing/selftests/arm64/mte/mte_common_util.c @@ -181,10 +181,17 @@ void *mte_allocate_file_memory(size_t size, int mem_type, int mapping, bool tags } /* Initialize the file for mappable size */ lseek(fd, 0, SEEK_SET); - for (index = INIT_BUFFER_SIZE; index < size; index += INIT_BUFFER_SIZE) - write(fd, buffer, INIT_BUFFER_SIZE); + for (index = INIT_BUFFER_SIZE; index < size; index += INIT_BUFFER_SIZE) { + if (write(fd, buffer, INIT_BUFFER_SIZE) != INIT_BUFFER_SIZE) { + perror("initialising buffer"); + return NULL; + } + } index -= INIT_BUFFER_SIZE; - write(fd, buffer, size - index); + if (write(fd, buffer, size - index) != size - index) { + perror("initialising buffer"); + return NULL; + } return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, fd); } @@ -202,9 +209,15 @@ void *mte_allocate_file_memory_tag_range(size_t size, int mem_type, int mapping, /* Initialize the file for mappable size */ lseek(fd, 0, SEEK_SET); for (index = INIT_BUFFER_SIZE; index < map_size; index += INIT_BUFFER_SIZE) - write(fd, buffer, INIT_BUFFER_SIZE); + if (write(fd, buffer, INIT_BUFFER_SIZE) != INIT_BUFFER_SIZE) { + perror("initialising buffer"); + return NULL; + } index -= INIT_BUFFER_SIZE; - write(fd, buffer, map_size - index); + if (write(fd, buffer, map_size - index) != map_size - index) { + perror("initialising buffer"); + return NULL; + } return __mte_allocate_memory_range(size, mem_type, mapping, range_before, range_after, true, fd); } @@ -271,29 +284,20 @@ int mte_switch_mode(int mte_option, unsigned long incl_mask) en |= (incl_mask << PR_MTE_TAG_SHIFT); /* Enable address tagging ABI, mte error reporting mode and tag inclusion mask. */ - if (!prctl(PR_SET_TAGGED_ADDR_CTRL, en, 0, 0, 0) == 0) { + if (prctl(PR_SET_TAGGED_ADDR_CTRL, en, 0, 0, 0) != 0) { ksft_print_msg("FAIL:prctl PR_SET_TAGGED_ADDR_CTRL for mte mode\n"); return -EINVAL; } return 0; } -#define ID_AA64PFR1_MTE_SHIFT 8 -#define ID_AA64PFR1_MTE 2 - int mte_default_setup(void) { - unsigned long hwcaps = getauxval(AT_HWCAP); + unsigned long hwcaps2 = getauxval(AT_HWCAP2); unsigned long en = 0; int ret; - if (!(hwcaps & HWCAP_CPUID)) { - ksft_print_msg("FAIL: CPUID registers unavailable\n"); - return KSFT_FAIL; - } - /* Read ID_AA64PFR1_EL1 register */ - asm volatile("mrs %0, id_aa64pfr1_el1" : "=r"(hwcaps) : : "memory"); - if (((hwcaps >> ID_AA64PFR1_MTE_SHIFT) & MT_TAG_MASK) != ID_AA64PFR1_MTE) { + if (!(hwcaps2 & HWCAP2_MTE)) { ksft_print_msg("FAIL: MTE features unavailable\n"); return KSFT_SKIP; } @@ -333,6 +337,7 @@ int create_temp_file(void) /* Create a file in the tmpfs filesystem */ fd = mkstemp(&filename[0]); if (fd == -1) { + perror(filename); ksft_print_msg("FAIL: Unable to open temporary file\n"); return 0; } diff --git a/tools/testing/selftests/firmware/fw_namespace.c b/tools/testing/selftests/firmware/fw_namespace.c index 5ebc1aec7923b41b3d8697957883d1c358ffd53d..0e393cb5f42de42d9d93a4b954b32b16881bb7e6 100644 --- a/tools/testing/selftests/firmware/fw_namespace.c +++ b/tools/testing/selftests/firmware/fw_namespace.c @@ -95,7 +95,7 @@ static bool test_fw_in_ns(const char *fw_name, const char *sys_path, bool block_ } if (block_fw_in_parent_ns) umount("/lib/firmware"); - return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false; + return WEXITSTATUS(status) == EXIT_SUCCESS; } if (unshare(CLONE_NEWNS) != 0) { diff --git a/tools/testing/selftests/lkdtm/.gitignore b/tools/testing/selftests/lkdtm/.gitignore index f26212605b6b7592b1b255e11e6e165b9e975705..d4b0be857deba00b2b51ed49e9b2fafed348e698 100644 --- a/tools/testing/selftests/lkdtm/.gitignore +++ b/tools/testing/selftests/lkdtm/.gitignore @@ -1,2 +1,3 @@ *.sh !run.sh +!stack-entropy.sh diff --git a/tools/testing/selftests/lkdtm/Makefile b/tools/testing/selftests/lkdtm/Makefile index 1bcc9ee990eb92db6051f3c28519fe568e25e1f4..c71109ceeb2d2538666f093c23d595c0d26754d0 100644 --- a/tools/testing/selftests/lkdtm/Makefile +++ b/tools/testing/selftests/lkdtm/Makefile @@ -5,6 +5,7 @@ include ../lib.mk # NOTE: $(OUTPUT) won't get default value if used before lib.mk TEST_FILES := tests.txt +TEST_PROGS := stack-entropy.sh TEST_GEN_PROGS = $(patsubst %,$(OUTPUT)/%.sh,$(shell awk '{print $$1}' tests.txt | sed -e 's/\#//')) all: $(TEST_GEN_PROGS) diff --git a/tools/testing/selftests/lkdtm/stack-entropy.sh b/tools/testing/selftests/lkdtm/stack-entropy.sh new file mode 100755 index 0000000000000000000000000000000000000000..b1b8a5097cbb1d9d715ceef180f0b0f5a41ce78b --- /dev/null +++ b/tools/testing/selftests/lkdtm/stack-entropy.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Measure kernel stack entropy by sampling via LKDTM's REPORT_STACK test. +set -e +samples="${1:-1000}" + +# Capture dmesg continuously since it may fill up depending on sample size. +log=$(mktemp -t stack-entropy-XXXXXX) +dmesg --follow >"$log" & pid=$! +report=-1 +for i in $(seq 1 $samples); do + echo "REPORT_STACK" >/sys/kernel/debug/provoke-crash/DIRECT + if [ -t 1 ]; then + percent=$(( 100 * $i / $samples )) + if [ "$percent" -ne "$report" ]; then + /bin/echo -en "$percent%\r" + report="$percent" + fi + fi +done +kill "$pid" + +# Count unique offsets since last run. +seen=$(tac "$log" | grep -m1 -B"$samples"0 'Starting stack offset' | \ + grep 'Stack offset' | awk '{print $NF}' | sort | uniq -c | wc -l) +bits=$(echo "obase=2; $seen" | bc | wc -L) +echo "Bits of stack entropy: $bits" +rm -f "$log" + +# We would expect any functional stack randomization to be at least 5 bits. +if [ "$bits" -lt 5 ]; then + exit 1 +else + exit 0 +fi diff --git a/tools/testing/selftests/sgx/defines.h b/tools/testing/selftests/sgx/defines.h index 592c1ccf4576d316c81b1abc76c7accd0a0e468d..0bd73428d2f3ebb8787130df22627abfbfc07ca7 100644 --- a/tools/testing/selftests/sgx/defines.h +++ b/tools/testing/selftests/sgx/defines.h @@ -14,7 +14,7 @@ #define __aligned(x) __attribute__((__aligned__(x))) #define __packed __attribute__((packed)) -#include "../../../../arch/x86/kernel/cpu/sgx/arch.h" +#include "../../../../arch/x86/include/asm/sgx.h" #include "../../../../arch/x86/include/asm/enclu.h" #include "../../../../arch/x86/include/uapi/asm/sgx.h" diff --git a/tools/testing/selftests/sgx/load.c b/tools/testing/selftests/sgx/load.c index 9d43b75aaa55323428eae29cb02e6588a3d2241f..f441ac34b4d4454f918af8003c659c582036b6e0 100644 --- a/tools/testing/selftests/sgx/load.c +++ b/tools/testing/selftests/sgx/load.c @@ -45,19 +45,19 @@ static bool encl_map_bin(const char *path, struct encl *encl) fd = open(path, O_RDONLY); if (fd == -1) { - perror("open()"); + perror("enclave executable open()"); return false; } ret = stat(path, &sb); if (ret) { - perror("stat()"); + perror("enclave executable stat()"); goto err; } bin = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (bin == MAP_FAILED) { - perror("mmap()"); + perror("enclave executable mmap()"); goto err; } @@ -90,8 +90,7 @@ static bool encl_ioc_create(struct encl *encl) ioc.src = (unsigned long)secs; rc = ioctl(encl->fd, SGX_IOC_ENCLAVE_CREATE, &ioc); if (rc) { - fprintf(stderr, "SGX_IOC_ENCLAVE_CREATE failed: errno=%d\n", - errno); + perror("SGX_IOC_ENCLAVE_CREATE failed"); munmap((void *)secs->base, encl->encl_size); return false; } @@ -116,31 +115,72 @@ static bool encl_ioc_add_pages(struct encl *encl, struct encl_segment *seg) rc = ioctl(encl->fd, SGX_IOC_ENCLAVE_ADD_PAGES, &ioc); if (rc < 0) { - fprintf(stderr, "SGX_IOC_ENCLAVE_ADD_PAGES failed: errno=%d.\n", - errno); + perror("SGX_IOC_ENCLAVE_ADD_PAGES failed"); return false; } return true; } + + bool encl_load(const char *path, struct encl *encl) { + const char device_path[] = "/dev/sgx_enclave"; Elf64_Phdr *phdr_tbl; off_t src_offset; Elf64_Ehdr *ehdr; + struct stat sb; + void *ptr; int i, j; int ret; + int fd = -1; memset(encl, 0, sizeof(*encl)); - ret = open("/dev/sgx_enclave", O_RDWR); - if (ret < 0) { - fprintf(stderr, "Unable to open /dev/sgx_enclave\n"); + fd = open(device_path, O_RDWR); + if (fd < 0) { + perror("Unable to open /dev/sgx_enclave"); + goto err; + } + + ret = stat(device_path, &sb); + if (ret) { + perror("device file stat()"); + goto err; + } + + /* + * This just checks if the /dev file has these permission + * bits set. It does not check that the current user is + * the owner or in the owning group. + */ + if (!(sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { + fprintf(stderr, "no execute permissions on device file %s\n", device_path); + goto err; + } + + ptr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); + if (ptr == (void *)-1) { + perror("mmap for read"); + goto err; + } + munmap(ptr, PAGE_SIZE); + +#define ERR_MSG \ +"mmap() succeeded for PROT_READ, but failed for PROT_EXEC.\n" \ +" Check that current user has execute permissions on %s and \n" \ +" that /dev does not have noexec set: mount | grep \"/dev .*noexec\"\n" \ +" If so, remount it executable: mount -o remount,exec /dev\n\n" + + ptr = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_SHARED, fd, 0); + if (ptr == (void *)-1) { + fprintf(stderr, ERR_MSG, device_path); goto err; } + munmap(ptr, PAGE_SIZE); - encl->fd = ret; + encl->fd = fd; if (!encl_map_bin(path, encl)) goto err; @@ -217,6 +257,8 @@ bool encl_load(const char *path, struct encl *encl) return true; err: + if (fd != -1) + close(fd); encl_delete(encl); return false; } @@ -229,7 +271,7 @@ static bool encl_map_area(struct encl *encl) area = mmap(NULL, encl_size * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (area == MAP_FAILED) { - perror("mmap"); + perror("reservation mmap()"); return false; } @@ -268,8 +310,7 @@ bool encl_build(struct encl *encl) ioc.sigstruct = (uint64_t)&encl->sigstruct; ret = ioctl(encl->fd, SGX_IOC_ENCLAVE_INIT, &ioc); if (ret) { - fprintf(stderr, "SGX_IOC_ENCLAVE_INIT failed: errno=%d\n", - errno); + perror("SGX_IOC_ENCLAVE_INIT failed"); return false; } diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c index 724cec700926b8a7b03f4b81cfdadb0dad24e00d..d304a4044eb9c69b69b3a0865fe26227ef22f5be 100644 --- a/tools/testing/selftests/sgx/main.c +++ b/tools/testing/selftests/sgx/main.c @@ -15,6 +15,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> +#include <sys/auxv.h> #include "defines.h" #include "main.h" #include "../kselftest.h" @@ -28,24 +29,6 @@ struct vdso_symtab { Elf64_Word *elf_hashtab; }; -static void *vdso_get_base_addr(char *envp[]) -{ - Elf64_auxv_t *auxv; - int i; - - for (i = 0; envp[i]; i++) - ; - - auxv = (Elf64_auxv_t *)&envp[i + 1]; - - for (i = 0; auxv[i].a_type != AT_NULL; i++) { - if (auxv[i].a_type == AT_SYSINFO_EHDR) - return (void *)auxv[i].a_un.a_val; - } - - return NULL; -} - static Elf64_Dyn *vdso_get_dyntab(void *addr) { Elf64_Ehdr *ehdr = addr; @@ -162,7 +145,7 @@ static int user_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r return 0; } -int main(int argc, char *argv[], char *envp[]) +int main(int argc, char *argv[]) { struct sgx_enclave_run run; struct vdso_symtab symtab; @@ -195,7 +178,7 @@ int main(int argc, char *argv[], char *envp[]) addr = mmap((void *)encl.encl_base + seg->offset, seg->size, seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0); if (addr == MAP_FAILED) { - fprintf(stderr, "mmap() failed, errno=%d.\n", errno); + perror("mmap() segment failed"); exit(KSFT_FAIL); } } @@ -203,7 +186,8 @@ int main(int argc, char *argv[], char *envp[]) memset(&run, 0, sizeof(run)); run.tcs = encl.encl_base; - addr = vdso_get_base_addr(envp); + /* Get vDSO base address */ + addr = (void *)getauxval(AT_SYSINFO_EHDR); if (!addr) goto err; diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c index bfc974b4572d55eb2c2db684a3307dcb66fbe0b7..ef8eb3604595eb9a2b56e5e48c61673dc2c9d0fd 100644 --- a/tools/testing/selftests/timers/clocksource-switch.c +++ b/tools/testing/selftests/timers/clocksource-switch.c @@ -3,7 +3,7 @@ * (C) Copyright IBM 2012 * Licensed under the GPLv2 * - * NOTE: This is a meta-test which quickly changes the clocksourc and + * NOTE: This is a meta-test which quickly changes the clocksource and * then uses other tests to detect problems. Thus this test requires * that the inconsistency-check and nanosleep tests be present in the * same directory it is run from. @@ -134,7 +134,7 @@ int main(int argv, char **argc) return -1; } - /* Check everything is sane before we start switching asyncrhonously */ + /* Check everything is sane before we start switching asynchronously */ for (i = 0; i < count; i++) { printf("Validating clocksource %s\n", clocksource_list[i]); if (change_clocksource(clocksource_list[i])) { diff --git a/tools/testing/selftests/timers/leap-a-day.c b/tools/testing/selftests/timers/leap-a-day.c index 19e46ed5dfb5915540404e95acabc7430ba08505..23eb398c8140ae0a9efb637fcc8ecaf331f47a23 100644 --- a/tools/testing/selftests/timers/leap-a-day.c +++ b/tools/testing/selftests/timers/leap-a-day.c @@ -5,7 +5,7 @@ * Licensed under the GPLv2 * * This test signals the kernel to insert a leap second - * every day at midnight GMT. This allows for stessing the + * every day at midnight GMT. This allows for stressing the * kernel's leap-second behavior, as well as how well applications * handle the leap-second discontinuity. * diff --git a/tools/testing/selftests/timers/leapcrash.c b/tools/testing/selftests/timers/leapcrash.c index dc80728ed1915551bf83c1ea855450d0ccc31c8a..f70802c5dd0d67e16596db582ffb6850575dd4fa 100644 --- a/tools/testing/selftests/timers/leapcrash.c +++ b/tools/testing/selftests/timers/leapcrash.c @@ -4,10 +4,10 @@ * (C) Copyright 2013, 2015 Linaro Limited * Licensed under the GPL * - * This test demonstrates leapsecond deadlock that is possibe + * This test demonstrates leapsecond deadlock that is possible * on kernels from 2.6.26 to 3.3. * - * WARNING: THIS WILL LIKELY HARDHANG SYSTEMS AND MAY LOSE DATA + * WARNING: THIS WILL LIKELY HARD HANG SYSTEMS AND MAY LOSE DATA * RUN AT YOUR OWN RISK! * To build: * $ gcc leapcrash.c -o leapcrash -lrt diff --git a/tools/testing/selftests/timers/threadtest.c b/tools/testing/selftests/timers/threadtest.c index cf3e48919874b3a1a23f8a10bb1e2fce5f9dfadd..80aed4bf06fba35cf2885eb81d85a3358b1fada9 100644 --- a/tools/testing/selftests/timers/threadtest.c +++ b/tools/testing/selftests/timers/threadtest.c @@ -76,7 +76,7 @@ void checklist(struct timespec *list, int size) /* The shared thread shares a global list * that each thread fills while holding the lock. - * This stresses clock syncronization across cpus. + * This stresses clock synchronization across cpus. */ void *shared_thread(void *arg) { diff --git a/tools/testing/selftests/x86/thunks_32.S b/tools/testing/selftests/x86/thunks_32.S index a71d92da8f46684eefb9ac43550a183ea19460f9..f3f56e681e9fbeaddeda911873c7cfba40363c9b 100644 --- a/tools/testing/selftests/x86/thunks_32.S +++ b/tools/testing/selftests/x86/thunks_32.S @@ -45,3 +45,5 @@ call64_from_32: ret .size call64_from_32, .-call64_from_32 + +.section .note.GNU-stack,"",%progbits diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8 index a15d20063b98f2f07441b0d53272d4b76658178e..1f26e4a006384ac11b0a4f53692d1192a5f9791e 100644 --- a/tools/usb/usbip/doc/usbip.8 +++ b/tools/usb/usbip/doc/usbip.8 @@ -49,10 +49,17 @@ then exit. Attach a remote USB device. .PP +.HP +\fBattach\fR \-\-remote=<\fIhost\fR> \-\-device=<\fIdev_id\fR> +.IP +Attach a remote USB gadget. +Only used when the remote usbipd is in device mode. +.PP + .HP \fBdetach\fR \-\-port=<\fIport\fR> .IP -Detach an imported USB device. +Detach an imported USB device/gadget. .PP .HP @@ -73,12 +80,26 @@ Stop exporting a device so it can be used by a local driver. List USB devices exported by a remote host. .PP +.HP +\fBlist\fR \-\-device +.IP +List USB gadgets of local usbip-vudc. +Only used when the local usbipd is in device mode. +Note that this can not list usbip-vudc USB gadgets of the remote device mode usbipd. +.PP + .HP \fBlist\fR \-\-local .IP List local USB devices. .PP +.HP +\fBport\fR +.IP +List imported devices/gadgets. +.PP + .SH EXAMPLES @@ -90,8 +111,27 @@ List local USB devices. client:# usbip attach --remote=server --busid=1-2 - Connect the remote USB device. + client:# usbip port + - List imported devices/gadgets. + client:# usbip detach --port=0 - Detach the usb device. +The following example shows the usage of device mode + + server:# usbip list --device + - List gadgets exported by local usbipd server. + + client:# modprobe vhci-hcd + + client:# usbip attach --remote=server --device=usbip-vudc.0 + - Connect the remote USB gadget. + + client:# usbip port + - List imported devices/gadgets. + + client:# usbip detach --port=0 + - Detach the usb gadget. + .SH "SEE ALSO" \fBusbipd\fP\fB(8)\fB\fP diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8 index fb62a756893bfa57682aaa0a81063e1b81d17d49..d974394f86a1e1a0b6d7686185f4df7cbbc31549 100644 --- a/tools/usb/usbip/doc/usbipd.8 +++ b/tools/usb/usbip/doc/usbipd.8 @@ -29,6 +29,12 @@ Bind to IPv4. Default is both. Bind to IPv6. Default is both. .PP +.HP +\fB\-e\fR, \fB\-\-device\fR +.IP +Run in device mode. Rather than drive an attached device, create a virtual UDC to bind gadgets to. +.PP + .HP \fB\-D\fR, \fB\-\-daemon\fR .IP @@ -86,6 +92,26 @@ USB/IP client can connect and use exported devices. - A usb device 1-2 is now exportable to other hosts! - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally. +The following example shows the usage of device mode + + server:# modprobe usbip-vudc + - Use /sys/class/udc/ interface. + - usbip-host is independent of this module. + + server:# usbipd -e -D + - Start usbip daemon in device mode. + + server:# modprobe g_mass_storage file=/tmp/tmp.img + - Bind a gadget to usbip-vudc. + - in this example, a mass storage gadget is bound. + + server:# usbip list --device + - List gadgets exported by local usbipd server. + + server:# modprobe -r g_mass_storage + - Unbind a gadget from usbip-vudc. + - in this example, the previous mass storage gadget is unbound. + .SH "SEE ALSO" \fBusbip\fP\fB(8)\fB\fP diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h index a941671e4900d8ab34db78607e221ef600c5ac2e..9cca2425587bd59452f7a2f20941af456bb13248 100644 --- a/tools/usb/usbip/libsrc/list.h +++ b/tools/usb/usbip/libsrc/list.h @@ -77,17 +77,17 @@ static inline void __list_del(struct list_head * prev, struct list_head * next) #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ -static inline void __list_del_entry(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); -} - static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c index 8625b0f514ee22421ed496c6bc10c89d9897963e..3d810bcca02fa90580c359fe141ae2921b6d5191 100644 --- a/tools/usb/usbip/src/usbip_list.c +++ b/tools/usb/usbip/src/usbip_list.c @@ -33,7 +33,8 @@ static const char usbip_list_usage_string[] = "usbip list [-p|--parsable] <args>\n" " -p, --parsable Parsable list format\n" " -r, --remote=<host> List the exportable USB devices on <host>\n" - " -l, --local List the local USB devices\n"; + " -l, --local List the local USB devices\n" + " -d, --device List the local USB gadgets bound to usbip-vudc\n"; void usbip_list_usage(void) {